From 5b528f90fb96d6a5dac9cfa8a5e77317975202bd Mon Sep 17 00:00:00 2001 From: malteish Date: Thu, 20 Jun 2024 14:07:53 +0200 Subject: [PATCH 01/12] fix nginx envsubst --- .github/workflows/deploy.yml | 3 ++- .github/workflows/production-deploy.yml | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 2a3445d95..c5a55e9eb 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -36,6 +36,7 @@ jobs: - name: Create .env file env: TARGET_HOST: ${{ vars.HOST_DOMAIN}} + TARGET_IP: ${{ vars.HOST_IP }} run: | echo "REACT_APP_ADDR_ENS_SUBDOMAIN=${{ secrets.ADDR_ENS_SUBDOMAIN}}" >> ./.env.react echo "REACT_APP_BACKEND=https://${{ vars.HOST_DOMAIN}}/api" >> ./.env.react @@ -66,7 +67,7 @@ jobs: echo "URL=${{ vars.HOST_DOMAIN}}" >> ./.env echo "CERT_MAIL=${{ vars.CERT_MAIL }}" >> ./.env echo "DATABASE_URL=${{ secrets.DATABASE_URL }}" >> ./.env - envsubst '${SSL_CERTIFICATE_BASE_LOC} ${TLS_CERTIFICATE_LOCATION} ${TARGET_HOST}' < ./docker/nginx.conf > ./nginx.conf + envsubst '${TARGET_IP} ${TARGET_HOST}' < ./docker/nginx.conf > ./nginx.conf cat ./.env - name: Prepare docker build environment shell: bash diff --git a/.github/workflows/production-deploy.yml b/.github/workflows/production-deploy.yml index bfe2a08f3..2afb6350f 100644 --- a/.github/workflows/production-deploy.yml +++ b/.github/workflows/production-deploy.yml @@ -60,7 +60,7 @@ jobs: echo "URL=${{ secrets.HOST_DOMAIN}}" >> ./.env echo "CERT_MAIL=${{ secrets.CERT_MAIL }}" >> ./.env echo "DATABASE_URL=${{ secrets.DATABASE_URL }}" >> ./.env - envsubst '${TARGET_HOST}' < ./docker/prod/nginx.conf > ./nginx.conf + envsubst '${TARGET_HOST} ${TARGET_IP}' < ./docker/prod/nginx.conf > ./nginx.conf cat ./.env - name: Prepare docker build environment shell: bash From a0d7eeff2a561b3f540e6db754d9d045f2ed4634 Mon Sep 17 00:00:00 2001 From: malteish Date: Mon, 24 Jun 2024 11:22:43 +0200 Subject: [PATCH 02/12] fix wrong path --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 807daef53..31294f1fd 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -130,7 +130,7 @@ jobs: rsync -avz -e 'ssh -i ./ssh-key' ./.env app@${{ vars.HOST_DOMAIN }}:/home/app/dm3 rsync -avz -e 'ssh -i ./ssh-key' ./dm3-*.tar app@${{ vars.HOST_DOMAIN }}:/home/app/dm3 rsync -avz -e 'ssh -i ./ssh-key' ./nginx.conf app@${{ vars.HOST_DOMAIN }}:/home/app/dm3 - rsync -avz -e 'ssh -i ./ssh-key' ./docker/staging/docker-compose.yml app@${{ vars.HOST_DOMAIN }}:/home/app/dm3 + rsync -avz -e 'ssh -i ./ssh-key' ./docker/docker-compose.yml app@${{ vars.HOST_DOMAIN }}:/home/app/dm3 - name: Stop docker on server run: | ssh -i ./ssh-key app@${{ vars.HOST_DOMAIN }} "\ From 8082d86586c25a0bf52dfdbc2d72f026c950b484 Mon Sep 17 00:00:00 2001 From: malteish Date: Wed, 26 Jun 2024 08:27:46 +0200 Subject: [PATCH 03/12] remove stateful directories --- .github/workflows/deploy.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 402c3691e..a9eb61c77 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -142,6 +142,12 @@ jobs: ssh -i ./ssh-key app@${{ vars.HOST_DOMAIN }} "\ cd dm3 && ls |grep -E 'dm3-.*tar' | xargs --no-run-if-empty -L 1 docker load -i; \ rm dm3-*.tar || true" + - name: Reset state of testing environment + run: | + if [ $environment_name == "testing" ]; then + ssh -i ./ssh-key root@${{ vars.HOST_DOMAIN }} "\ + cd /mnt/dm3_prod_volume/db && rm -r * || true; \" + fi - name: Configure Firewall run: | ssh -i ./ssh-key root@${{ vars.HOST_DOMAIN }} "\ From c26d2a3d126f6bc4db8bf07c24e308e316dd9914 Mon Sep 17 00:00:00 2001 From: malteish Date: Wed, 26 Jun 2024 09:01:51 +0200 Subject: [PATCH 04/12] fix RESOLVER_ADDRESS env variable name --- .github/workflows/deploy.yml | 2 +- docker/docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index a9eb61c77..5ddd55d5d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -57,7 +57,7 @@ jobs: echo "REACT_APP_CHAIN_ID=${{ vars.CHAIN_ID }}" >> ./.env.react echo "REACT_APP_GENOME_REGISTRY_ADDRESS=${{ vars.GENOME_REGISTRY_ADDRESS }}" >> ./.env.react cat ./.env.react >> ./.env - echo "RESOLVER_ADDR=${{ vars.ERC3668_RESOLVER_ADDRESS }}" >> ./.env + echo "RESOLVER_ADDRESS=${{ vars.ERC3668_RESOLVER_ADDRESS }}" >> ./.env echo "SIGNING_PUBLIC_KEY=${{ secrets.SIGNING_PUBLIC_KEY }}" >> ./.env echo "SIGNING_PRIVATE_KEY=${{ secrets.SIGNING_PRIVATE_KEY }}" >> ./.env echo "SIGNER_PRIVATE_KEY=${{ secrets.SIGNER_PRIVATE_KEY }}" >> ./.env diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index b0a9c565d..ccb52f6cc 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -112,7 +112,7 @@ services: REACT_APP_USER_ENS_SUBDOMAIN: ${REACT_APP_USER_ENS_SUBDOMAIN} REACT_APP_WALLET_CONNECT_PROJECT_ID: ${REACT_APP_WALLET_CONNECT_PROJECT_ID} REACT_APP_GENOME_REGISTRY_ADDRESS: ${REACT_APP_GENOME_REGISTRY_ADDRESS} - RESOLVER_ADDR: ${RESOLVER_ADDR} + RESOLVER_ADDRESS: ${RESOLVER_ADDRESS} certbot: image: certbot/certbot From 25581d7b6ddf1bd5b86a82551e48b221ec7fe441 Mon Sep 17 00:00:00 2001 From: malteish Date: Wed, 26 Jun 2024 09:12:46 +0200 Subject: [PATCH 05/12] minor fixes --- .github/workflows/deploy.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 5ddd55d5d..8382c7be9 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -106,10 +106,10 @@ jobs: --tag dm3org/$image_name:$version${{ env.docker_suffix }}.${{ env.unix_now }}.${{ env.sha_short }} . docker save -o ./$image_name.tar $image_name:latest docker push --all-tags dm3org/$image_name - - name: Build offchain-resolver docker image + - name: Build and publish offchain-resolver docker image shell: bash run: | - version=$(NODE_PATH=packages/delivery-service node -p "require('package.json').version") + version=$(NODE_PATH=packages/offchain-resolver node -p "require('package.json').version") image_name=dm3-offchain-resolver docker build --progress=plain -f ./docker/DockerfilePackages --build-arg="PACKAGE=offchain-resolver" \ --tag $image_name:latest \ @@ -151,8 +151,8 @@ jobs: - name: Configure Firewall run: | ssh -i ./ssh-key root@${{ vars.HOST_DOMAIN }} "\ - ufw allow from 172.18.0.1/16 proto tcp to ${{ vars.HOST_IP}} port 80; - ufw allow from 172.18.0.1/16 proto tcp to ${{ secrets.IP_ADDRESS }} port 443; + ufw allow from 172.18.0.1/16 proto tcp to ${{ vars.HOST_IP }} port 80; + ufw allow from 172.18.0.1/16 proto tcp to ${{ vars.HOST_IP }} port 443; ufw enable" - name: Start docker on server run: | From 4bfad1a371797e38994cd1b39c30e310dad640c9 Mon Sep 17 00:00:00 2001 From: malteish Date: Wed, 26 Jun 2024 09:20:46 +0200 Subject: [PATCH 06/12] fix reset of state --- .github/workflows/deploy.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 8382c7be9..2b50a6f2d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -146,7 +146,7 @@ jobs: run: | if [ $environment_name == "testing" ]; then ssh -i ./ssh-key root@${{ vars.HOST_DOMAIN }} "\ - cd /mnt/dm3_prod_volume/db && rm -r * || true; \" + cd /mnt/dm3_prod_volume/db && rm -r * || true" fi - name: Configure Firewall run: | From c5224800241a62d840c5adeec32df993f85cf446 Mon Sep 17 00:00:00 2001 From: malteish Date: Wed, 26 Jun 2024 09:01:51 +0200 Subject: [PATCH 07/12] fix RESOLVER_ADDRESS env variable name --- .github/workflows/deploy.yml | 2 +- docker/docker-compose.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 9ba9f1f78..070606e01 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -57,7 +57,7 @@ jobs: echo "REACT_APP_CHAIN_ID=${{ vars.CHAIN_ID }}" >> ./.env.react echo "REACT_APP_GENOME_REGISTRY_ADDRESS=${{ vars.GENOME_REGISTRY_ADDRESS }}" >> ./.env.react cat ./.env.react >> ./.env - echo "RESOLVER_ADDR=${{ vars.ERC3668_RESOLVER_ADDRESS }}" >> ./.env + echo "RESOLVER_ADDRESS=${{ vars.ERC3668_RESOLVER_ADDRESS }}" >> ./.env echo "SIGNING_PUBLIC_KEY=${{ secrets.SIGNING_PUBLIC_KEY }}" >> ./.env echo "SIGNING_PRIVATE_KEY=${{ secrets.SIGNING_PRIVATE_KEY }}" >> ./.env echo "SIGNER_PRIVATE_KEY=${{ secrets.SIGNER_PRIVATE_KEY }}" >> ./.env diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml index b0a9c565d..ccb52f6cc 100644 --- a/docker/docker-compose.yml +++ b/docker/docker-compose.yml @@ -112,7 +112,7 @@ services: REACT_APP_USER_ENS_SUBDOMAIN: ${REACT_APP_USER_ENS_SUBDOMAIN} REACT_APP_WALLET_CONNECT_PROJECT_ID: ${REACT_APP_WALLET_CONNECT_PROJECT_ID} REACT_APP_GENOME_REGISTRY_ADDRESS: ${REACT_APP_GENOME_REGISTRY_ADDRESS} - RESOLVER_ADDR: ${RESOLVER_ADDR} + RESOLVER_ADDRESS: ${RESOLVER_ADDRESS} certbot: image: certbot/certbot From f55e134c4948b2dd405a48e390ef8afbe2c592fe Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Wed, 26 Jun 2024 12:12:05 +0200 Subject: [PATCH 08/12] use paginated conversations --- packages/lib/shared/src/IBackendConnector.ts | 6 +- .../src/new/cloudStorage/getCloudStorage.ts | 6 +- packages/lib/storage/src/new/types.ts | 2 +- .../src/context/BackendContext.tsx | 6 +- .../src/context/StorageContext.tsx | 8 +- .../testHelper/getMockedStorageContext.ts | 7 +- .../conversation/useConversation.test.tsx | 7 +- .../hooks/conversation/useConversation.tsx | 107 +++++++++++------- .../src/hooks/messages/useMessage.test.tsx | 20 ++-- .../src/hooks/server-side/BackendConnector.ts | 13 ++- .../src/hooks/server-side/useBackend.ts | 8 +- .../src/hooks/storage/useStorage.tsx | 23 ++-- .../messenger-widget/src/interfaces/utils.ts | 4 +- 13 files changed, 130 insertions(+), 87 deletions(-) diff --git a/packages/lib/shared/src/IBackendConnector.ts b/packages/lib/shared/src/IBackendConnector.ts index 1040376d8..e163ce2ff 100644 --- a/packages/lib/shared/src/IBackendConnector.ts +++ b/packages/lib/shared/src/IBackendConnector.ts @@ -1,6 +1,10 @@ export interface IBackendConnector { addConversation(ensName: string, encryptedContactName: string): void; - getConversations(ensName: string): Promise; + getConversations( + ensName: string, + size: number, + offset: number, + ): Promise; toggleHideConversation( ensName: string, encryptedContactName: string, diff --git a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts index fec3658c4..f4f4f7e8a 100644 --- a/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts +++ b/packages/lib/storage/src/new/cloudStorage/getCloudStorage.ts @@ -17,9 +17,11 @@ export const getCloudStorage = ( ); }; - const getConversationList = async (page: number) => { + const getConversations = async (size: number, offset: number) => { const encryptedConversations = await backendConnector.getConversations( ensName, + size, + offset, ); return await Promise.all( @@ -174,7 +176,7 @@ export const getCloudStorage = ( return { addConversation: _addConversation, - getConversationList, + getConversations, getMessages, addMessage: _addMessage, addMessageBatch: _addMessageBatch, diff --git a/packages/lib/storage/src/new/types.ts b/packages/lib/storage/src/new/types.ts index 59f760c2a..0ed77ca0a 100644 --- a/packages/lib/storage/src/new/types.ts +++ b/packages/lib/storage/src/new/types.ts @@ -1,7 +1,7 @@ import { Envelop, MessageState } from '@dm3-org/dm3-lib-messaging'; export interface StorageAPI { - getConversationList: (page: number) => Promise; + getConversations: (size: number, offset: number) => Promise; getMessages: ( contactEnsName: string, page: number, diff --git a/packages/messenger-widget/src/context/BackendContext.tsx b/packages/messenger-widget/src/context/BackendContext.tsx index 6a49c5cdd..e829220e5 100644 --- a/packages/messenger-widget/src/context/BackendContext.tsx +++ b/packages/messenger-widget/src/context/BackendContext.tsx @@ -5,7 +5,11 @@ import { useBackend } from '../hooks/server-side/useBackend'; export type BackendContextType = { isInitialized: boolean; addConversation: (ensName: string, encryptedContactName: string) => void; - getConversations: (ensName: string) => Promise; + getConversations: ( + ensName: string, + size: number, + offset: number, + ) => Promise; toggleHideConversation: ( ensName: string, encryptedContactName: string, diff --git a/packages/messenger-widget/src/context/StorageContext.tsx b/packages/messenger-widget/src/context/StorageContext.tsx index a4f6b65d6..3dd4c6574 100644 --- a/packages/messenger-widget/src/context/StorageContext.tsx +++ b/packages/messenger-widget/src/context/StorageContext.tsx @@ -12,10 +12,7 @@ import { useStorage, } from '../hooks/storage/useStorage'; import { AuthContext } from './AuthContext'; -import { DeliveryServiceContext } from './DeliveryServiceContext'; -import { BackendConnector } from '../hooks/server-side/BackendConnector'; -import { BackendContext, BackendContextProvider } from './BackendContext'; -import { IBackendConnector } from '@dm3-org/dm3-lib-shared'; +import { BackendContext } from './BackendContext'; export type StorageContextType = { storeMessage: StoreMessageAsync; @@ -42,7 +39,8 @@ export const StorageContext = React.createContext({ contact: string, batch: StorageEnvelopContainer[], ) => {}, - getConversations: async (page: number) => Promise.resolve([]), + getConversations: async (size: number, offset: number) => + Promise.resolve([]), addConversationAsync: (contact: string) => {}, getMessages: async (contact: string, page: number) => Promise.resolve([]), getNumberOfMessages: async (contact: string) => Promise.resolve(0), diff --git a/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts b/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts index acf1c0a2e..bf50d0d3e 100644 --- a/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts +++ b/packages/messenger-widget/src/context/testHelper/getMockedStorageContext.ts @@ -9,7 +9,7 @@ import { StorageContextType } from '../StorageContext'; export const getMockedStorageContext = ( override?: Partial, ) => { - const defaultValues = { + const defaultValues: StorageContextType = { initialized: false, storeMessage: function ( contact: string, @@ -29,7 +29,10 @@ export const getMockedStorageContext = ( ): void { throw new Error('Function not implemented.'); }, - getConversations: function (page: number): Promise { + getConversations: function ( + size: number, + offset: number, + ): Promise { return Promise.resolve([ { contactEnsName: 'max.eth', diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx index 7bcf05f46..4a910d109 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.test.tsx @@ -400,6 +400,7 @@ describe('useConversation hook test cases', () => { const storageContext: StorageContextType = getMockedStorageContext({ getConversations: function ( page: number, + offset: number, ): Promise { return Promise.resolve([ { @@ -409,6 +410,7 @@ describe('useConversation hook test cases', () => { }, ]); }, + addConversationAsync: jest.fn(), initialized: true, }); const deliveryServiceContext: DeliveryServiceContextType = @@ -480,6 +482,7 @@ describe('useConversation hook test cases', () => { }, ]); }, + addConversationAsync: jest.fn(), initialized: true, }); const deliveryServiceContext: DeliveryServiceContextType = @@ -568,6 +571,7 @@ describe('useConversation hook test cases', () => { }, ]); }, + addConversationAsync: jest.fn(), initialized: true, }); const deliveryServiceContext: DeliveryServiceContextType = @@ -619,7 +623,7 @@ describe('useConversation hook test cases', () => { 'mydefaultcontract.eth', ); }); - it('hidden contact should not appears as hidden in the conversation list', async () => { + it('hidden contact should appear as hidden in the conversation list', async () => { const configurationContext = getMockedDm3Configuration({ dm3Configuration: { ...DEFAULT_DM3_CONFIGURATION, @@ -661,6 +665,7 @@ describe('useConversation hook test cases', () => { }, ]); }, + addConversationAsync: jest.fn(), initialized: true, }); const deliveryServiceContext: DeliveryServiceContextType = diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx index 1ffc32ff6..d0e661419 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx @@ -12,7 +12,7 @@ import { DeliveryServiceContext } from '../../context/DeliveryServiceContext'; import { StorageContext } from '../../context/StorageContext'; import { TLDContext } from '../../context/TLDContext'; import { DM3Configuration } from '../../interfaces/config'; -import { ContactPreview, getDefaultContract } from '../../interfaces/utils'; +import { ContactPreview, getEmptyContact } from '../../interfaces/utils'; import { useMainnetProvider } from '../mainnetprovider/useMainnetProvider'; import { hydrateContract } from './hydrateContact'; @@ -21,13 +21,12 @@ export const useConversation = (config: DM3Configuration) => { const { dm3Configuration } = useContext(DM3ConfigurationContext); const { account } = useContext(AuthContext); const { - getDeliveryServiceProperties, fetchIncommingMessages, isInitialized: deliveryServiceInitialized, } = useContext(DeliveryServiceContext); const { - getConversations, - addConversationAsync, + getConversations: getConversationsFromStorage, + addConversationAsync: storeConversationAsync, initialized: storageInitialized, toggleHideContactAsync, } = useContext(StorageContext); @@ -71,7 +70,7 @@ export const useConversation = (config: DM3Configuration) => { setConversationsInitialized(false); setSelectedContactName(undefined); setContacts([]); - const init = async (page: number = 0) => { + const init = async () => { if ( !account || !storageInitialized || @@ -79,37 +78,34 @@ export const useConversation = (config: DM3Configuration) => { ) { return; } - const currentConversationsPage = await getConversations(page); - //Hydrate the contacts by fetching their profile and DS profile - const storedContacts = await Promise.all( - currentConversationsPage.map((conversation) => { - const isHidden = conversation.isHidden; - //Hydrating is the most expensive operation. Hence we only hydrate if the contact is not hidden - if (isHidden) { - //If the contact is hidden we only return the contact with the default values. Once its unhidden it will be hydrated - return { - ...getDefaultContract(conversation.contactEnsName), - isHidden: true, - }; - } - return hydrateContract( - mainnetProvider, - conversation, - resolveAliasToTLD, - dm3Configuration.addressEnsSubdomain, - ); - }), - ); + const conversations = await Promise.all([ + //Get the last 5 conversations from the storage + getConversationsFromStorage(5, 0), + //Get the conversations that have been added to the DS in absence of the user + getConversationsFromDeliveryService(), + ]); - /** - * It might be the case that contacts are added via websocket. - * In this case we do not want to add them again - */ - _setContactsSafe(storedContacts); + //Flatten the conversations and remove duplicates + conversations + .flat() + .filter( + (conversation, index, self) => + index === + self.findIndex( + (t) => + t.contactEnsName === + conversation.contactEnsName, + ), + ) + //Add the conversations to the list + .forEach((conversation) => { + _addConversation( + conversation.contactEnsName, + conversation.isHidden, + ); + }); - //Conversation that have been added to the DS in absence of the user will be fetched and added to the conversation list using the handlePendingConversations method - await handlePendingConversations(); initDefaultContact(); setConversationsInitialized(true); }; @@ -153,7 +149,9 @@ export const useConversation = (config: DM3Configuration) => { } }; - const handlePendingConversations = async () => { + const getConversationsFromDeliveryService = async (): Promise< + Conversation[] + > => { //The DS does not exposes an endpoint to fetch pending conversations. Hence we're using the fetchIncommingMessages method. //We can make some optimizations here if we use the messages fetched from incommingMessages in useMessages aswell. //This would require a refactor of the useMessages away from a contact based model. @@ -162,16 +160,39 @@ export const useConversation = (config: DM3Configuration) => { account?.ensName as string, ); //Every pending conversation is going to be added to the conversation list - incommingMessages.forEach((pendingMessage: EncryptionEnvelop) => { - const sender = ( - pendingMessage.metadata - .deliveryInformation as DeliveryInformation - ).from; - addConversation(sender); - }); + return ( + incommingMessages + .map((pendingMessage: EncryptionEnvelop) => { + const contactEnsName = ( + pendingMessage.metadata + .deliveryInformation as DeliveryInformation + ).from; + + return { + contactEnsName, + messageCounter: 0, + isHidden: false, + }; + }) + //filter duplicates + .filter((conversation: Conversation) => { + return !contacts.some( + (current) => + current.contactDetails.account.ensName === + conversation.contactEnsName, + ); + }) + ); }; const addConversation = (_ensName: string) => { + //Adds the conversation to the conversation state + _addConversation(_ensName, false); + //Add the contact to the storage in the background + storeConversationAsync(_ensName); + }; + + const _addConversation = (_ensName: string, isHidden: boolean) => { const ensName = normalizeEnsName(_ensName); //Check if the contact is the user itself const isOwnContact = normalizeEnsName(account!.ensName) === ensName; @@ -192,11 +213,9 @@ export const useConversation = (config: DM3Configuration) => { return alreadyAddedContact; } - const newContact: ContactPreview = getDefaultContract(ensName); + const newContact: ContactPreview = getEmptyContact(ensName, isHidden); //Set the new contact to the list _setContactsSafe([newContact]); - //Add the contact to the storage in the background - addConversationAsync(ensName); //Hydrate the contact in the background hydrateExistingContactAsync(newContact); diff --git a/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx b/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx index 32311c3fe..6300a91fa 100644 --- a/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx +++ b/packages/messenger-widget/src/hooks/messages/useMessage.test.tsx @@ -24,7 +24,7 @@ import { } from '../../context/testHelper/getMockedDm3Configuration'; import { getMockedStorageContext } from '../../context/testHelper/getMockedStorageContext'; import { getMockedTldContext } from '../../context/testHelper/getMockedTldContext'; -import { getDefaultContract } from '../../interfaces/utils'; +import { getEmptyContact } from '../../interfaces/utils'; import { DM3Configuration } from '../../widget'; import { useMessage } from './useMessage'; @@ -106,7 +106,7 @@ describe('useMessage hook test cases', () => { storeMessage: jest.fn(), }); const conversationContext = getMockedConversationContext({ - selectedContact: getDefaultContract('max.eth'), + selectedContact: getEmptyContact('max.eth'), }); const deliveryServiceContext = getMockedDeliveryServiceContext({ //Add websocket mock @@ -163,7 +163,7 @@ describe('useMessage hook test cases', () => { storeMessage: jest.fn(), }); const conversationContext = getMockedConversationContext({ - selectedContact: getDefaultContract('max.eth'), + selectedContact: getEmptyContact('max.eth'), }); const deliveryServiceContext = getMockedDeliveryServiceContext({ //Add websocket mock @@ -220,7 +220,7 @@ describe('useMessage hook test cases', () => { storeMessage: jest.fn(), }); const conversationContext = getMockedConversationContext({ - selectedContact: getDefaultContract('max.eth'), + selectedContact: getEmptyContact('max.eth'), }); const deliveryServiceContext = getMockedDeliveryServiceContext({ //Add websocket mock @@ -287,7 +287,7 @@ describe('useMessage hook test cases', () => { }); const conversationContext = getMockedConversationContext({ - selectedContact: getDefaultContract('max.eth'), + selectedContact: getEmptyContact('max.eth'), contacts: [ { name: '', @@ -390,7 +390,7 @@ describe('useMessage hook test cases', () => { }); const conversationContext = getMockedConversationContext({ - selectedContact: getDefaultContract('max.eth'), + selectedContact: getEmptyContact('max.eth'), contacts: [ { name: '', @@ -520,8 +520,8 @@ describe('useMessage hook test cases', () => { getNumberOfMessages: jest.fn().mockResolvedValue(3), }); const conversationContext = getMockedConversationContext({ - selectedContact: getDefaultContract('max.eth'), - contacts: [getDefaultContract('alice.eth')], + selectedContact: getEmptyContact('max.eth'), + contacts: [getEmptyContact('alice.eth')], }); const deliveryServiceContext = getMockedDeliveryServiceContext({ onNewMessage: (cb: Function) => { @@ -597,8 +597,8 @@ describe('useMessage hook test cases', () => { getNumberOfMessages: jest.fn().mockResolvedValue(0), }); const conversationContext = getMockedConversationContext({ - selectedContact: getDefaultContract('max.eth'), - contacts: [getDefaultContract('alice.eth')], + selectedContact: getEmptyContact('max.eth'), + contacts: [getEmptyContact('alice.eth')], }); const deliveryServiceContext = getMockedDeliveryServiceContext({ onNewMessage: (cb: Function) => { diff --git a/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts b/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts index 075fc223f..7df1b7560 100644 --- a/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts +++ b/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts @@ -15,13 +15,22 @@ export class BackendConnector encryptedContactName, }); } - public async getConversations(ensName: string) { + public async getConversations( + ensName: string, + size: number, + offset: number, + ) { const url = `/storage/new/${normalizeEnsName( ensName, )}/getConversations`; const axios = this.getAuthenticatedAxiosClient(); - const { data } = await axios.get(url); + const { data } = await axios.get(url, { + params: { + size, + offset, + }, + }); return data ?? []; } public async toggleHideConversation( diff --git a/packages/messenger-widget/src/hooks/server-side/useBackend.ts b/packages/messenger-widget/src/hooks/server-side/useBackend.ts index 74da8df88..c61dba118 100644 --- a/packages/messenger-widget/src/hooks/server-side/useBackend.ts +++ b/packages/messenger-widget/src/hooks/server-side/useBackend.ts @@ -55,8 +55,12 @@ export const useBackend = (): IBackendConnector & { addConversation: (ensName: string, encryptedContactName: string) => { beConnector?.addConversation(ensName, encryptedContactName); }, - getConversations: async (ensName: string) => { - return beConnector?.getConversations(ensName); + getConversations: async ( + ensName: string, + size: number, + offset: number, + ) => { + return beConnector?.getConversations(ensName, size, offset); }, toggleHideConversation: ( ensName: string, diff --git a/packages/messenger-widget/src/hooks/storage/useStorage.tsx b/packages/messenger-widget/src/hooks/storage/useStorage.tsx index d8c0d6195..f627ca266 100644 --- a/packages/messenger-widget/src/hooks/storage/useStorage.tsx +++ b/packages/messenger-widget/src/hooks/storage/useStorage.tsx @@ -1,8 +1,6 @@ import { StorageEnvelopContainer as StorageEnvelopContainerNew, getCloudStorage, - load, - migrageStorage, } from '@dm3-org/dm3-lib-storage'; import { @@ -13,14 +11,9 @@ import { encryptAsymmetric, } from '@dm3-org/dm3-lib-crypto'; import { Account, ProfileKeys } from '@dm3-org/dm3-lib-profile'; -import { IBackendConnector, sha256, stringify } from '@dm3-org/dm3-lib-shared'; -import { - Conversation, - StorageAPI, -} from '@dm3-org/dm3-lib-storage/dist/new/types'; -import { useContext, useEffect, useState } from 'react'; -import axios from 'axios'; -import { TLDContext } from '../../context/TLDContext'; +import { sha256, stringify } from '@dm3-org/dm3-lib-shared'; +import { Conversation, StorageAPI } from '@dm3-org/dm3-lib-storage'; +import { useEffect, useState } from 'react'; import { BackendContextType } from '../../context/BackendContext'; //Handels storage sync and offers an interface for other hooks to interact with the storage @@ -29,7 +22,6 @@ export const useStorage = ( backendContext: BackendContextType, profileKeys: ProfileKeys | undefined, ) => { - const { resolveTLDtoAlias } = useContext(TLDContext); const [storageApi, setStorageApi] = useState( undefined, ); @@ -129,11 +121,11 @@ export const useStorage = ( } await storageApi.addMessageBatch(contact, batch); }; - const getConversations = async (page: number) => { + const getConversations = async (size: number, offset: number) => { if (!storageApi) { return Promise.resolve([]); } - return storageApi.getConversationList(page); + return storageApi.getConversations(size, offset); }; const addConversationAsync = (contact: string) => { @@ -188,7 +180,10 @@ export type StoreMessageBatch = ( contact: string, batch: StorageEnvelopContainerNew[], ) => Promise; -export type GetConversations = (page: number) => Promise; +export type GetConversations = ( + size: number, + offset: number, +) => Promise; export type AddConversation = (contact: string) => void; export type GetMessages = ( contact: string, diff --git a/packages/messenger-widget/src/interfaces/utils.ts b/packages/messenger-widget/src/interfaces/utils.ts index aced396eb..527854296 100644 --- a/packages/messenger-widget/src/interfaces/utils.ts +++ b/packages/messenger-widget/src/interfaces/utils.ts @@ -50,7 +50,7 @@ export interface IAttachmentPreview { isImage: boolean; } -export const getDefaultContract = (ensName: string) => { +export const getEmptyContact = (ensName: string, isHidden: boolean) => { const newContact: ContactPreview = { name: getAccountDisplayName(ensName, 25), message: null, @@ -63,7 +63,7 @@ export const getDefaultContract = (ensName: string) => { }, deliveryServiceProfiles: [], }, - isHidden: false, + isHidden, messageSizeLimit: 0, }; From 5b4164652c3139bdfa1ffb32c224bb39b391a83f Mon Sep 17 00:00:00 2001 From: malteish Date: Wed, 26 Jun 2024 12:30:26 +0200 Subject: [PATCH 09/12] add action that resets the state of staging --- .github/workflows/resetStagingState.yml | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 .github/workflows/resetStagingState.yml diff --git a/.github/workflows/resetStagingState.yml b/.github/workflows/resetStagingState.yml new file mode 100644 index 000000000..f7e86f1ea --- /dev/null +++ b/.github/workflows/resetStagingState.yml @@ -0,0 +1,22 @@ +name: deploy +on: workflow_dispatch + +jobs: + reset-staging-state: + environment: 'staging' + runs-on: ubuntu-latest + steps: + - name: Stop docker on server + run: | + ssh -i ./ssh-key app@${{ vars.HOST_DOMAIN }} "\ + cd dm3 && docker compose down" + ssh -i ./ssh-key root@${{ vars.HOST_DOMAIN }} "\ + systemctl restart docker.service" + - name: Reset state of staging environment + run: | + ssh -i ./ssh-key root@${{ vars.HOST_DOMAIN }} "\ + cd /mnt/dm3_prod_volume/db && rm -r * || true" + - name: Start docker on server + run: | + ssh -i ./ssh-key app@${{ vars.HOST_DOMAIN }} "\ + cd dm3 && docker compose --env-file .env up -d && docker system prune -af" From b403f89a690e9b9639a98b14804da696fab94b98 Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Wed, 26 Jun 2024 12:42:55 +0200 Subject: [PATCH 10/12] usr constant for default conversation size --- .../src/hooks/conversation/useConversation.tsx | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx index d0e661419..f9f1d4ca6 100644 --- a/packages/messenger-widget/src/hooks/conversation/useConversation.tsx +++ b/packages/messenger-widget/src/hooks/conversation/useConversation.tsx @@ -16,6 +16,8 @@ import { ContactPreview, getEmptyContact } from '../../interfaces/utils'; import { useMainnetProvider } from '../mainnetprovider/useMainnetProvider'; import { hydrateContract } from './hydrateContact'; +const DEFAULT_CONVERSATION_PAGE_SIZE = 1; + export const useConversation = (config: DM3Configuration) => { const mainnetProvider = useMainnetProvider(); const { dm3Configuration } = useContext(DM3ConfigurationContext); @@ -81,7 +83,7 @@ export const useConversation = (config: DM3Configuration) => { const conversations = await Promise.all([ //Get the last 5 conversations from the storage - getConversationsFromStorage(5, 0), + getConversationsFromStorage(DEFAULT_CONVERSATION_PAGE_SIZE, 0), //Get the conversations that have been added to the DS in absence of the user getConversationsFromDeliveryService(), ]); @@ -187,9 +189,11 @@ export const useConversation = (config: DM3Configuration) => { const addConversation = (_ensName: string) => { //Adds the conversation to the conversation state - _addConversation(_ensName, false); + const conversationPreview = _addConversation(_ensName, false); //Add the contact to the storage in the background storeConversationAsync(_ensName); + + return conversationPreview; }; const _addConversation = (_ensName: string, isHidden: boolean) => { From 05f5186aca1d1f53f0a477465c37ea27662e880e Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Wed, 26 Jun 2024 12:43:09 +0200 Subject: [PATCH 11/12] use pageSize param in BackendConnector --- .../src/hooks/server-side/BackendConnector.ts | 4 ++-- packages/messenger-widget/src/interfaces/utils.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts b/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts index 7df1b7560..90f07c895 100644 --- a/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts +++ b/packages/messenger-widget/src/hooks/server-side/BackendConnector.ts @@ -17,7 +17,7 @@ export class BackendConnector } public async getConversations( ensName: string, - size: number, + pageSize: number, offset: number, ) { const url = `/storage/new/${normalizeEnsName( @@ -27,7 +27,7 @@ export class BackendConnector const { data } = await axios.get(url, { params: { - size, + pageSize, offset, }, }); diff --git a/packages/messenger-widget/src/interfaces/utils.ts b/packages/messenger-widget/src/interfaces/utils.ts index 527854296..2efd79704 100644 --- a/packages/messenger-widget/src/interfaces/utils.ts +++ b/packages/messenger-widget/src/interfaces/utils.ts @@ -50,7 +50,7 @@ export interface IAttachmentPreview { isImage: boolean; } -export const getEmptyContact = (ensName: string, isHidden: boolean) => { +export const getEmptyContact = (ensName: string, isHidden: boolean = false) => { const newContact: ContactPreview = { name: getAccountDisplayName(ensName, 25), message: null, From 70d6fa224d7f644b704263b9c3a8828053b30cba Mon Sep 17 00:00:00 2001 From: AlexNi245 Date: Wed, 26 Jun 2024 12:49:27 +0200 Subject: [PATCH 12/12] add loggin for conversations --- packages/backend/src/storage.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/backend/src/storage.ts b/packages/backend/src/storage.ts index 12e3303ad..52b71815e 100644 --- a/packages/backend/src/storage.ts +++ b/packages/backend/src/storage.ts @@ -216,6 +216,8 @@ export default ( try { const ensName = normalizeEnsName(req.params.ensName); + console.log('getConversations query', req.query); + const pageSize = parseInt(req.query.pageSize as string) || DEFAULT_CONVERSATION_PAGE_SIZE; @@ -231,6 +233,8 @@ export default ( return; } + console.log('fetch conversations', pageSize, offset); + const conversations = await db.getConversationList( ensName, pageSize,