diff --git a/lib/shared/dm-ops/process-dm-ops.js b/lib/shared/dm-ops/process-dm-ops.js new file mode 100644 --- /dev/null +++ b/lib/shared/dm-ops/process-dm-ops.js @@ -0,0 +1,46 @@ +// @flow + +import * as React from 'react'; + +import { dmOpSpecs } from './dm-op-specs.js'; +import { useLoggedInUserInfo } from '../../hooks/account-hooks.js'; +import type { DMOperation } from '../../types/dm-ops.js'; +import { getConfig } from '../../utils/config.js'; +import { translateClientDBMessageInfoToRawMessageInfo } from '../../utils/message-ops-utils.js'; + +function useProcessDMOperation(): (dmOp: DMOperation) => Promise { + const { getLatestMessageEdit } = getConfig().sqliteAPI; + const fetchMessage = React.useCallback( + async (messageID: string) => { + const latestMessageEdit = await getLatestMessageEdit(messageID); + if (!latestMessageEdit) { + return latestMessageEdit; + } + return translateClientDBMessageInfoToRawMessageInfo(latestMessageEdit); + }, + [getLatestMessageEdit], + ); + + const utilities = React.useMemo( + () => ({ + fetchMessage, + }), + [fetchMessage], + ); + + const loggedInUserInfo = useLoggedInUserInfo(); + const viewerID = loggedInUserInfo?.id; + return React.useCallback( + async (dmOp: DMOperation) => { + if (!viewerID) { + console.log('ignored DMOperation because logged out'); + return; + } + await dmOpSpecs[dmOp.type].processDMOperation(dmOp, viewerID, utilities); + // TODO: dispatch Redux action + }, + [viewerID, utilities], + ); +} + +export { useProcessDMOperation }; diff --git a/lib/tunnelbroker/use-peer-to-peer-message-handler.js b/lib/tunnelbroker/use-peer-to-peer-message-handler.js --- a/lib/tunnelbroker/use-peer-to-peer-message-handler.js +++ b/lib/tunnelbroker/use-peer-to-peer-message-handler.js @@ -18,6 +18,7 @@ removeDeviceFromDeviceList, } from '../shared/device-list-utils.js'; import { IdentityClientContext } from '../shared/identity-client-context.js'; +import { useProcessDMOperation } from '../shared/dm-ops/process-dm-ops.js'; import type { DeviceOlmInboundKeys } from '../types/identity-service-types.js'; import { peerToPeerMessageTypes, @@ -53,6 +54,8 @@ const dispatchActionPromise = useDispatchActionPromise(); const primaryDeviceRequestedLogOut = useLogOut(primaryRequestLogoutOptions); + const processDMOperation = useProcessDMOperation(); + return React.useCallback( async (decryptedMessageContent: string, senderInfo: SenderInfo) => { const parsedMessageToDevice = JSON.parse(decryptedMessageContent); @@ -84,6 +87,10 @@ await broadcastDeviceListUpdates( allPeerDevices.filter(deviceID => deviceID !== deviceIDToLogOut), ); + } else if ( + userActionMessage.type === userActionsP2PMessageTypes.DM_OPERATION + ) { + await processDMOperation(userActionMessage.op); } else { console.warn( 'Unsupported P2P user action message:', @@ -97,6 +104,7 @@ dispatchActionPromise, identityClient, primaryDeviceRequestedLogOut, + processDMOperation, ], ); } diff --git a/lib/types/dm-ops.js b/lib/types/dm-ops.js --- a/lib/types/dm-ops.js +++ b/lib/types/dm-ops.js @@ -1,6 +1,6 @@ // @flow -import type { TInterface } from 'tcomb'; +import type { TInterface, TUnion } from 'tcomb'; import t from 'tcomb'; import type { RawMessageInfo } from './message-types.js'; @@ -89,6 +89,11 @@ | DMCreateThreadOperation | DMCreateSidebarOperation | DMSendTextMessageOperation; +export const dmOperationValidator: TUnion = t.union([ + dmCreateThreadOperationValidator, + dmCreateSidebarOperationValidator, + dmSendTextMessageOperationValidator, +]); export type DMOperationResult = { rawMessageInfos: Array, diff --git a/lib/types/tunnelbroker/user-actions-peer-to-peer-message-types.js b/lib/types/tunnelbroker/user-actions-peer-to-peer-message-types.js --- a/lib/types/tunnelbroker/user-actions-peer-to-peer-message-types.js +++ b/lib/types/tunnelbroker/user-actions-peer-to-peer-message-types.js @@ -3,10 +3,12 @@ import t, { type TInterface, type TUnion } from 'tcomb'; import { tShape, tString } from '../../utils/validation-utils.js'; +import { type DMOperation, dmOperationValidator } from '../dm-ops.js'; export const userActionsP2PMessageTypes = Object.freeze({ LOG_OUT_PRIMARY_DEVICE: 'LOG_OUT_PRIMARY_DEVICE', LOG_OUT_SECONDARY_DEVICE: 'LOG_OUT_SECONDARY_DEVICE', + DM_OPERATION: 'DM_OPERATION', }); export type PrimaryDeviceLogoutP2PMessage = { @@ -26,12 +28,24 @@ type: tString(userActionsP2PMessageTypes.LOG_OUT_SECONDARY_DEVICE), }); +export type DMOperationP2PMessage = { + +type: 'DM_OPERATION', + +op: DMOperation, +}; +export const dmOperationP2PMessageValidator: TInterface = + tShape({ + type: tString(userActionsP2PMessageTypes.DM_OPERATION), + op: dmOperationValidator, + }); + export type UserActionP2PMessage = | PrimaryDeviceLogoutP2PMessage - | SecondaryDeviceLogoutP2PMessage; + | SecondaryDeviceLogoutP2PMessage + | DMOperationP2PMessage; export const userActionP2PMessageValidator: TUnion = t.union([ primaryDeviceLogoutP2PMessageValidator, secondaryDeviceLogoutP2PMessageValidator, + dmOperationP2PMessageValidator, ]);