From bfade45b002254da4f581e6a0a6b164a7670df00 Mon Sep 17 00:00:00 2001 From: Audric Ackermann Date: Mon, 1 Jun 2020 16:28:52 +1000 Subject: [PATCH] add start of SessionProtocol --- ts/session/protocols/SessionProtocol.ts | 125 ++++++++++++++---- .../session/protocols/SessionProtocol_test.ts | 11 ++ 2 files changed, 111 insertions(+), 25 deletions(-) create mode 100644 ts/test/session/protocols/SessionProtocol_test.ts diff --git a/ts/session/protocols/SessionProtocol.ts b/ts/session/protocols/SessionProtocol.ts index ebeac9f37..c95629c2c 100644 --- a/ts/session/protocols/SessionProtocol.ts +++ b/ts/session/protocols/SessionProtocol.ts @@ -1,17 +1,89 @@ -// TODO: Need to flesh out these functions -// Structure of this can be changed for example sticking this all in a class -// The reason i haven't done it is to avoid having instances of the protocol, rather you should be able to call the functions directly +import { SessionResetMessage } from '../messages/outgoing'; +// import { MessageSender } from '../sending'; -import { OutgoingContentMessage } from '../messages/outgoing'; +// These two Maps should never be accessed directly but only +// through `_update*SessionTimestamp()`, `_get*SessionRequest()` or `_has'SessionRequest()` +let sentSessionsTimestamp: Map; +let processedSessionsTimestamp: Map; + +/** + * We only need to fetch once from the database, because we are the only one writing to it + */ +async function _fetchFromDBIfNeeded(): Promise { + if (!sentSessionsTimestamp) { + // TODO actually fetch from DB + sentSessionsTimestamp = new Map(); + processedSessionsTimestamp = new Map(); + } +} + +async function _writeToDBSentSessions(): Promise { + // TODO actually write to DB +} + +async function _writeToDBProcessedSessions(): Promise { + // TODO actually write to DB +} + + +/** + * This is a utility function to avoid duplicated code of _updateSentSessionTimestamp and _updateProcessedSessionTimestamp + */ +async function _updateSessionTimestamp(device: string, timestamp: number | undefined, map: Map): Promise { + await _fetchFromDBIfNeeded(); + if (!timestamp) { + return map.delete(device); + } + map.set(device, timestamp); + + return true; +} + +/** + * + * @param device the device id + * @param timestamp undefined to remove the key/value pair, otherwise updates the sent timestamp and write to DB + */ +async function _updateSentSessionTimestamp(device: string, timestamp: number|undefined): Promise { + if (_updateSessionTimestamp(device, timestamp, sentSessionsTimestamp)) { + await _writeToDBSentSessions(); + } +} + +/** + * timestamp undefined to remove the key/value pair, otherwise updates the processed timestamp and writes to DB + */ +async function _updateProcessedSessionTimestamp(device: string, timestamp: number|undefined): Promise { + if (_updateSessionTimestamp(device, timestamp, processedSessionsTimestamp)) { + await _writeToDBProcessedSessions(); + } +} export function hasSession(device: string): boolean { return false; // TODO: Implement } -export function hasSentSessionRequest(device: string): boolean { - // TODO: need a way to keep track of if we've sent a session request - // My idea was to use the timestamp of when it was sent but there might be another better approach - return false; +/** + * This is a utility function to avoid duplicate code between `_getProcessedSessionRequest()` and `_getSentSessionRequest()` + */ +async function _getSessionRequest(device: string, map: Map): Promise { + await _fetchFromDBIfNeeded(); + + return map.get(device); +} + +async function _getSentSessionRequest(device: string): Promise { + return _getSessionRequest(device, processedSessionsTimestamp); +} + +async function _getProcessedSessionRequest(device: string): Promise { + return _getSessionRequest(device, sentSessionsTimestamp); +} + +export async function hasSentSessionRequest(device: string): Promise { + const hasSent = await _getSessionRequest(device, sentSessionsTimestamp); + + return !!hasSent; } export async function sendSessionRequestIfNeeded( @@ -25,33 +97,36 @@ export async function sendSessionRequestIfNeeded( return Promise.reject(new Error('Need to implement this function')); } -// TODO: Replace OutgoingContentMessage with SessionReset -export async function sendSessionRequest( - message: OutgoingContentMessage +export async function sendSessionRequests( + message: SessionResetMessage, + device: string ): Promise { - // TODO: Optimistically store timestamp of when session request was sent + + // Optimistically store timestamp of when session request was sent + await _updateSentSessionTimestamp(device, Date.now()); + + // await MessageSender.send() + // TODO: Send out the request via MessageSender // TODO: On failure, unset the timestamp return Promise.resolve(); } -export function sessionEstablished(device: string) { - // TODO: this is called when we receive an encrypted message from the other user - // Maybe it should be renamed to something else - // TODO: This should make `hasSentSessionRequest` return `false` +export async function sessionEstablished(device: string) { + // remove our existing sent timestamp for that device + return _updateSentSessionTimestamp(device, undefined); } -export function shouldProcessSessionRequest( +export async function shouldProcessSessionRequest( device: string, messageTimestamp: number -): boolean { - // TODO: Need to do the following here - // messageTimestamp > session request sent timestamp && messageTimestamp > session request processed timestamp - return false; +): Promise { + const existingSentTimestamp = await _getSentSessionRequest(device) || 0; + const existingProcessedTimestamp = await _getProcessedSessionRequest(device) || 0; + + return messageTimestamp > existingSentTimestamp && messageTimestamp > existingProcessedTimestamp; } -export function sessionRequestProcessed(device: string) { - // TODO: this is called when we process the session request - // This should store the processed timestamp - // Again naming is crap so maybe some other name is better +export async function onSessionRequestProcessed(device: string) { + return _updateProcessedSessionTimestamp(device, Date.now()); } diff --git a/ts/test/session/protocols/SessionProtocol_test.ts b/ts/test/session/protocols/SessionProtocol_test.ts new file mode 100644 index 000000000..89bcec78c --- /dev/null +++ b/ts/test/session/protocols/SessionProtocol_test.ts @@ -0,0 +1,11 @@ +import { expect } from 'chai'; +import { SessionProtocol } from '../../../session/protocols'; + + + +describe('SessionProtocol', () => { + it('has ', () => { + + }); + +});