Simplify messageReceiver initialization & reset
Co-authored-by: Scott Nonnenberg <scott@signal.org>
This commit is contained in:
parent
f057bc560f
commit
dfd564e67f
6 changed files with 318 additions and 289 deletions
539
ts/background.ts
539
ts/background.ts
|
@ -254,216 +254,8 @@ export async function startApp(): Promise<void> {
|
||||||
let challengeHandler: ChallengeHandler | undefined;
|
let challengeHandler: ChallengeHandler | undefined;
|
||||||
let routineProfileRefresher: RoutineProfileRefresher | undefined;
|
let routineProfileRefresher: RoutineProfileRefresher | undefined;
|
||||||
|
|
||||||
window.storage.onready(() => {
|
|
||||||
server = window.WebAPI.connect({
|
|
||||||
...window.textsecure.storage.user.getWebAPICredentials(),
|
|
||||||
hasStoriesDisabled: window.storage.get('hasStoriesDisabled', false),
|
|
||||||
});
|
|
||||||
window.textsecure.server = server;
|
|
||||||
window.textsecure.messaging = new window.textsecure.MessageSender(server);
|
|
||||||
|
|
||||||
challengeHandler = new ChallengeHandler({
|
|
||||||
storage: window.storage,
|
|
||||||
|
|
||||||
startQueue(conversationId: string) {
|
|
||||||
conversationJobQueue.resolveVerificationWaiter(conversationId);
|
|
||||||
},
|
|
||||||
|
|
||||||
requestChallenge(request) {
|
|
||||||
if (window.SignalCI) {
|
|
||||||
window.SignalCI.handleEvent('challenge', request);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
window.sendChallengeRequest(request);
|
|
||||||
},
|
|
||||||
|
|
||||||
async sendChallengeResponse(data) {
|
|
||||||
const { messaging } = window.textsecure;
|
|
||||||
if (!messaging) {
|
|
||||||
throw new Error('sendChallengeResponse: messaging is not available!');
|
|
||||||
}
|
|
||||||
await messaging.sendChallengeResponse(data);
|
|
||||||
},
|
|
||||||
|
|
||||||
onChallengeFailed() {
|
|
||||||
// TODO: DESKTOP-1530
|
|
||||||
// Display humanized `retryAfter`
|
|
||||||
window.reduxActions.toast.showToast({
|
|
||||||
toastType: ToastType.CaptchaFailed,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
onChallengeSolved() {
|
|
||||||
window.reduxActions.toast.showToast({
|
|
||||||
toastType: ToastType.CaptchaSolved,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
setChallengeStatus(challengeStatus) {
|
|
||||||
window.reduxActions.network.setChallengeStatus(challengeStatus);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
window.Whisper.events.on('challengeResponse', response => {
|
|
||||||
if (!challengeHandler) {
|
|
||||||
throw new Error('Expected challenge handler to be there');
|
|
||||||
}
|
|
||||||
|
|
||||||
challengeHandler.onResponse(response);
|
|
||||||
});
|
|
||||||
|
|
||||||
window.Signal.challengeHandler = challengeHandler;
|
|
||||||
|
|
||||||
log.info('Initializing MessageReceiver');
|
|
||||||
messageReceiver = new MessageReceiver({
|
|
||||||
server,
|
|
||||||
storage: window.storage,
|
|
||||||
serverTrustRoot: window.getServerTrustRoot(),
|
|
||||||
});
|
|
||||||
|
|
||||||
function queuedEventListener<E extends Event>(
|
|
||||||
handler: (event: E) => Promise<void> | void,
|
|
||||||
track = true
|
|
||||||
): (event: E) => void {
|
|
||||||
return (event: E): void => {
|
|
||||||
drop(
|
|
||||||
eventHandlerQueue.add(
|
|
||||||
createTaskWithTimeout(async () => {
|
|
||||||
try {
|
|
||||||
await handler(event);
|
|
||||||
} finally {
|
|
||||||
// message/sent: Message.handleDataMessage has its own queue and will
|
|
||||||
// trigger this event itself when complete.
|
|
||||||
// error: Error processing (below) also has its own queue and
|
|
||||||
// self-trigger.
|
|
||||||
if (track) {
|
|
||||||
window.Whisper.events.trigger('incrementProgress');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}, `queuedEventListener(${event.type}, ${event.timeStamp})`)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'envelopeUnsealed',
|
|
||||||
queuedEventListener(onEnvelopeUnsealed, false)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'envelopeQueued',
|
|
||||||
queuedEventListener(onEnvelopeQueued, false)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'message',
|
|
||||||
queuedEventListener(onMessageReceived, false)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'delivery',
|
|
||||||
queuedEventListener(onDeliveryReceipt)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'contactSync',
|
|
||||||
queuedEventListener(onContactSync)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'sent',
|
|
||||||
queuedEventListener(onSentMessage, false)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'readSync',
|
|
||||||
queuedEventListener(onReadSync)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'viewSync',
|
|
||||||
queuedEventListener(onViewSync)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'read',
|
|
||||||
queuedEventListener(onReadReceipt)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'view',
|
|
||||||
queuedEventListener(onViewReceipt)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'error',
|
|
||||||
queuedEventListener(onError, false)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'decryption-error',
|
|
||||||
queuedEventListener((event: DecryptionErrorEvent): void => {
|
|
||||||
drop(onDecryptionErrorQueue.add(() => onDecryptionError(event)));
|
|
||||||
})
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'invalid-plaintext',
|
|
||||||
queuedEventListener((event: InvalidPlaintextEvent): void => {
|
|
||||||
drop(
|
|
||||||
onDecryptionErrorQueue.add(() => onInvalidPlaintextMessage(event))
|
|
||||||
);
|
|
||||||
})
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'retry-request',
|
|
||||||
queuedEventListener((event: RetryRequestEvent): void => {
|
|
||||||
drop(onRetryRequestQueue.add(() => onRetryRequest(event)));
|
|
||||||
})
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener('empty', queuedEventListener(onEmpty));
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'configuration',
|
|
||||||
queuedEventListener(onConfiguration)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener('typing', queuedEventListener(onTyping));
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'sticker-pack',
|
|
||||||
queuedEventListener(onStickerPack)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'viewOnceOpenSync',
|
|
||||||
queuedEventListener(onViewOnceOpenSync)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'messageRequestResponse',
|
|
||||||
queuedEventListener(onMessageRequestResponse)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'profileKeyUpdate',
|
|
||||||
queuedEventListener(onProfileKeyUpdate)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'fetchLatest',
|
|
||||||
queuedEventListener(onFetchLatestSync)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener('keys', queuedEventListener(onKeysSync));
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'storyRecipientUpdate',
|
|
||||||
queuedEventListener(onStoryRecipientUpdate, false)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'callEventSync',
|
|
||||||
queuedEventListener(onCallEventSync, false)
|
|
||||||
);
|
|
||||||
messageReceiver.addEventListener(
|
|
||||||
'callLogEventSync',
|
|
||||||
queuedEventListener(onCallLogEventSync, false)
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
ourProfileKeyService.initialize(window.storage);
|
ourProfileKeyService.initialize(window.storage);
|
||||||
|
|
||||||
window.storage.onready(() => {
|
|
||||||
if (!window.storage.get('defaultConversationColor')) {
|
|
||||||
drop(
|
|
||||||
window.storage.put(
|
|
||||||
'defaultConversationColor',
|
|
||||||
DEFAULT_CONVERSATION_COLOR
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
window.SignalContext.activeWindowService.registerForChange(isActive => {
|
window.SignalContext.activeWindowService.registerForChange(isActive => {
|
||||||
if (!isActive) {
|
if (!isActive) {
|
||||||
window.reduxActions?.stories.setHasAllStoriesUnmuted(false);
|
window.reduxActions?.stories.setHasAllStoriesUnmuted(false);
|
||||||
|
@ -477,18 +269,6 @@ export async function startApp(): Promise<void> {
|
||||||
|
|
||||||
const reconnectBackOff = new BackOff(FIBONACCI_TIMEOUTS);
|
const reconnectBackOff = new BackOff(FIBONACCI_TIMEOUTS);
|
||||||
|
|
||||||
window.storage.onready(() => {
|
|
||||||
strictAssert(server, 'WebAPI not ready');
|
|
||||||
|
|
||||||
senderCertificateService.initialize({
|
|
||||||
server,
|
|
||||||
events: window.Whisper.events,
|
|
||||||
storage: window.storage,
|
|
||||||
});
|
|
||||||
|
|
||||||
areWeASubscriberService.update(window.storage, server);
|
|
||||||
});
|
|
||||||
|
|
||||||
const eventHandlerQueue = new PQueue({
|
const eventHandlerQueue = new PQueue({
|
||||||
concurrency: 1,
|
concurrency: 1,
|
||||||
});
|
});
|
||||||
|
@ -700,9 +480,6 @@ export async function startApp(): Promise<void> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
log.info('Storage fetch');
|
|
||||||
drop(window.storage.fetch());
|
|
||||||
|
|
||||||
// We need this 'first' check because we don't want to start the app up any other time
|
// We need this 'first' check because we don't want to start the app up any other time
|
||||||
// than the first time. And window.storage.fetch() will cause onready() to fire.
|
// than the first time. And window.storage.fetch() will cause onready() to fire.
|
||||||
let first = true;
|
let first = true;
|
||||||
|
@ -712,7 +489,217 @@ export async function startApp(): Promise<void> {
|
||||||
}
|
}
|
||||||
first = false;
|
first = false;
|
||||||
|
|
||||||
strictAssert(server !== undefined, 'WebAPI not ready');
|
server = window.WebAPI.connect({
|
||||||
|
...window.textsecure.storage.user.getWebAPICredentials(),
|
||||||
|
hasStoriesDisabled: window.storage.get('hasStoriesDisabled', false),
|
||||||
|
});
|
||||||
|
window.textsecure.server = server;
|
||||||
|
window.textsecure.messaging = new window.textsecure.MessageSender(server);
|
||||||
|
|
||||||
|
challengeHandler = new ChallengeHandler({
|
||||||
|
storage: window.storage,
|
||||||
|
|
||||||
|
startQueue(conversationId: string) {
|
||||||
|
conversationJobQueue.resolveVerificationWaiter(conversationId);
|
||||||
|
},
|
||||||
|
|
||||||
|
requestChallenge(request) {
|
||||||
|
if (window.SignalCI) {
|
||||||
|
window.SignalCI.handleEvent('challenge', request);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
window.sendChallengeRequest(request);
|
||||||
|
},
|
||||||
|
|
||||||
|
async sendChallengeResponse(data) {
|
||||||
|
const { messaging } = window.textsecure;
|
||||||
|
if (!messaging) {
|
||||||
|
throw new Error('sendChallengeResponse: messaging is not available!');
|
||||||
|
}
|
||||||
|
await messaging.sendChallengeResponse(data);
|
||||||
|
},
|
||||||
|
|
||||||
|
onChallengeFailed() {
|
||||||
|
// TODO: DESKTOP-1530
|
||||||
|
// Display humanized `retryAfter`
|
||||||
|
window.reduxActions.toast.showToast({
|
||||||
|
toastType: ToastType.CaptchaFailed,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
onChallengeSolved() {
|
||||||
|
window.reduxActions.toast.showToast({
|
||||||
|
toastType: ToastType.CaptchaSolved,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
setChallengeStatus(challengeStatus) {
|
||||||
|
window.reduxActions.network.setChallengeStatus(challengeStatus);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
window.Whisper.events.on('challengeResponse', response => {
|
||||||
|
if (!challengeHandler) {
|
||||||
|
throw new Error('Expected challenge handler to be there');
|
||||||
|
}
|
||||||
|
|
||||||
|
challengeHandler.onResponse(response);
|
||||||
|
});
|
||||||
|
|
||||||
|
window.Signal.challengeHandler = challengeHandler;
|
||||||
|
|
||||||
|
log.info('Initializing MessageReceiver');
|
||||||
|
messageReceiver = new MessageReceiver({
|
||||||
|
server,
|
||||||
|
storage: window.storage,
|
||||||
|
serverTrustRoot: window.getServerTrustRoot(),
|
||||||
|
});
|
||||||
|
|
||||||
|
function queuedEventListener<E extends Event>(
|
||||||
|
handler: (event: E) => Promise<void> | void,
|
||||||
|
track = true
|
||||||
|
): (event: E) => void {
|
||||||
|
return (event: E): void => {
|
||||||
|
drop(
|
||||||
|
eventHandlerQueue.add(
|
||||||
|
createTaskWithTimeout(async () => {
|
||||||
|
try {
|
||||||
|
await handler(event);
|
||||||
|
} finally {
|
||||||
|
// message/sent: Message.handleDataMessage has its own queue and will
|
||||||
|
// trigger this event itself when complete.
|
||||||
|
// error: Error processing (below) also has its own queue and
|
||||||
|
// self-trigger.
|
||||||
|
if (track) {
|
||||||
|
window.Whisper.events.trigger('incrementProgress');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}, `queuedEventListener(${event.type}, ${event.timeStamp})`)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'envelopeUnsealed',
|
||||||
|
queuedEventListener(onEnvelopeUnsealed, false)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'envelopeQueued',
|
||||||
|
queuedEventListener(onEnvelopeQueued, false)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'message',
|
||||||
|
queuedEventListener(onMessageReceived, false)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'delivery',
|
||||||
|
queuedEventListener(onDeliveryReceipt)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'contactSync',
|
||||||
|
queuedEventListener(onContactSync)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'sent',
|
||||||
|
queuedEventListener(onSentMessage, false)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'readSync',
|
||||||
|
queuedEventListener(onReadSync)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'viewSync',
|
||||||
|
queuedEventListener(onViewSync)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'read',
|
||||||
|
queuedEventListener(onReadReceipt)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'view',
|
||||||
|
queuedEventListener(onViewReceipt)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'error',
|
||||||
|
queuedEventListener(onError, false)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'decryption-error',
|
||||||
|
queuedEventListener((event: DecryptionErrorEvent): void => {
|
||||||
|
drop(onDecryptionErrorQueue.add(() => onDecryptionError(event)));
|
||||||
|
})
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'invalid-plaintext',
|
||||||
|
queuedEventListener((event: InvalidPlaintextEvent): void => {
|
||||||
|
drop(
|
||||||
|
onDecryptionErrorQueue.add(() => onInvalidPlaintextMessage(event))
|
||||||
|
);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'retry-request',
|
||||||
|
queuedEventListener((event: RetryRequestEvent): void => {
|
||||||
|
drop(onRetryRequestQueue.add(() => onRetryRequest(event)));
|
||||||
|
})
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener('empty', queuedEventListener(onEmpty));
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'configuration',
|
||||||
|
queuedEventListener(onConfiguration)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener('typing', queuedEventListener(onTyping));
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'sticker-pack',
|
||||||
|
queuedEventListener(onStickerPack)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'viewOnceOpenSync',
|
||||||
|
queuedEventListener(onViewOnceOpenSync)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'messageRequestResponse',
|
||||||
|
queuedEventListener(onMessageRequestResponse)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'profileKeyUpdate',
|
||||||
|
queuedEventListener(onProfileKeyUpdate)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'fetchLatest',
|
||||||
|
queuedEventListener(onFetchLatestSync)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener('keys', queuedEventListener(onKeysSync));
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'storyRecipientUpdate',
|
||||||
|
queuedEventListener(onStoryRecipientUpdate, false)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'callEventSync',
|
||||||
|
queuedEventListener(onCallEventSync, false)
|
||||||
|
);
|
||||||
|
messageReceiver.addEventListener(
|
||||||
|
'callLogEventSync',
|
||||||
|
queuedEventListener(onCallLogEventSync, false)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!window.storage.get('defaultConversationColor')) {
|
||||||
|
drop(
|
||||||
|
window.storage.put(
|
||||||
|
'defaultConversationColor',
|
||||||
|
DEFAULT_CONVERSATION_COLOR
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
senderCertificateService.initialize({
|
||||||
|
server,
|
||||||
|
events: window.Whisper.events,
|
||||||
|
storage: window.storage,
|
||||||
|
});
|
||||||
|
|
||||||
|
areWeASubscriberService.update(window.storage, server);
|
||||||
|
|
||||||
void cleanupSessionResets();
|
void cleanupSessionResets();
|
||||||
|
|
||||||
|
@ -1149,6 +1136,10 @@ export async function startApp(): Promise<void> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
// end of window.storage.onready() callback
|
||||||
|
|
||||||
|
log.info('Storage fetch');
|
||||||
|
drop(window.storage.fetch());
|
||||||
|
|
||||||
function setupAppState({
|
function setupAppState({
|
||||||
mainWindowStats,
|
mainWindowStats,
|
||||||
|
@ -1442,6 +1433,9 @@ export async function startApp(): Promise<void> {
|
||||||
|
|
||||||
drop(connect(true));
|
drop(connect(true));
|
||||||
|
|
||||||
|
// Connect messageReceiver back to websocket
|
||||||
|
afterStart();
|
||||||
|
|
||||||
// Run storage service after linking
|
// Run storage service after linking
|
||||||
drop(runStorageService());
|
drop(runStorageService());
|
||||||
});
|
});
|
||||||
|
@ -1472,7 +1466,7 @@ export async function startApp(): Promise<void> {
|
||||||
);
|
);
|
||||||
|
|
||||||
if (isCoreDataValid && Registration.everDone()) {
|
if (isCoreDataValid && Registration.everDone()) {
|
||||||
void connect();
|
drop(connect());
|
||||||
window.reduxActions.app.openInbox();
|
window.reduxActions.app.openInbox();
|
||||||
} else {
|
} else {
|
||||||
window.IPC.readyForUpdates();
|
window.IPC.readyForUpdates();
|
||||||
|
@ -1523,6 +1517,58 @@ export async function startApp(): Promise<void> {
|
||||||
resolveOnAppView();
|
resolveOnAppView();
|
||||||
resolveOnAppView = undefined;
|
resolveOnAppView = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
afterStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
function afterStart() {
|
||||||
|
strictAssert(messageReceiver, 'messageReceiver must be initialized');
|
||||||
|
strictAssert(server, 'server must be initialized');
|
||||||
|
|
||||||
|
log.info('afterStart(): emitting app-ready-for-processing');
|
||||||
|
window.Whisper.events.trigger('app-ready-for-processing');
|
||||||
|
|
||||||
|
const onOnline = () => {
|
||||||
|
log.info('background: online');
|
||||||
|
|
||||||
|
if (!remotelyExpired) {
|
||||||
|
drop(connect());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.Whisper.events.on('online', onOnline);
|
||||||
|
|
||||||
|
const onOffline = () => {
|
||||||
|
log.info('background: offline');
|
||||||
|
|
||||||
|
drop(challengeHandler?.onOffline());
|
||||||
|
drop(AttachmentDownloads.stop());
|
||||||
|
drop(messageReceiver?.drain());
|
||||||
|
|
||||||
|
if (connectCount === 0) {
|
||||||
|
log.info('background: offline, never connected, showing inbox');
|
||||||
|
|
||||||
|
drop(onEmpty()); // this ensures that the loading screen is dismissed
|
||||||
|
|
||||||
|
// Switch to inbox view even if contact sync is still running
|
||||||
|
if (
|
||||||
|
window.reduxStore.getState().app.appView === AppViewType.Installer
|
||||||
|
) {
|
||||||
|
log.info('background: offline, opening inbox');
|
||||||
|
window.reduxActions.app.openInbox();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
window.Whisper.events.on('offline', onOffline);
|
||||||
|
|
||||||
|
// Because these events may have already fired, we manually call their handlers.
|
||||||
|
// isOnline() will return undefined if neither of these events have been emitted.
|
||||||
|
if (server.isOnline() === true) {
|
||||||
|
onOnline();
|
||||||
|
} else if (server.isOnline() === false) {
|
||||||
|
onOffline();
|
||||||
|
}
|
||||||
|
|
||||||
|
server.registerRequestHandler(messageReceiver);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.getSyncRequest = (timeoutMillis?: number) => {
|
window.getSyncRequest = (timeoutMillis?: number) => {
|
||||||
|
@ -1558,41 +1604,6 @@ export async function startApp(): Promise<void> {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.Whisper.events.on('online', () => {
|
|
||||||
log.info('background: online');
|
|
||||||
strictAssert(
|
|
||||||
messageReceiver !== undefined,
|
|
||||||
'MessageReceiver not initialized'
|
|
||||||
);
|
|
||||||
messageReceiver.reset();
|
|
||||||
|
|
||||||
// The first call to connect should be done via start(), ensuring that the app is
|
|
||||||
// ready first
|
|
||||||
if (!remotelyExpired && connectCount > 0) {
|
|
||||||
drop(connect());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
window.Whisper.events.on('offline', () => {
|
|
||||||
log.info('background: offline');
|
|
||||||
|
|
||||||
drop(challengeHandler?.onOffline());
|
|
||||||
drop(AttachmentDownloads.stop());
|
|
||||||
drop(messageReceiver?.drain());
|
|
||||||
|
|
||||||
if (connectCount === 0) {
|
|
||||||
log.info('background: offline, never connected, showing inbox');
|
|
||||||
|
|
||||||
drop(onEmpty()); // this ensures that the loading screen is dismissed
|
|
||||||
|
|
||||||
// Switch to inbox view even if contact sync is still running
|
|
||||||
if (window.reduxStore.getState().app.appView === AppViewType.Installer) {
|
|
||||||
log.info('background: offline, opening inbox');
|
|
||||||
window.reduxActions.app.openInbox();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
let connectCount = 0;
|
let connectCount = 0;
|
||||||
let connecting = false;
|
let connecting = false;
|
||||||
let remotelyExpired = false;
|
let remotelyExpired = false;
|
||||||
|
@ -1675,12 +1686,6 @@ export async function startApp(): Promise<void> {
|
||||||
|
|
||||||
void window.Signal.Services.initializeGroupCredentialFetcher();
|
void window.Signal.Services.initializeGroupCredentialFetcher();
|
||||||
|
|
||||||
strictAssert(
|
|
||||||
messageReceiver !== undefined,
|
|
||||||
'MessageReceiver not initialized'
|
|
||||||
);
|
|
||||||
server.registerRequestHandler(messageReceiver);
|
|
||||||
|
|
||||||
drop(
|
drop(
|
||||||
AttachmentDownloads.start({
|
AttachmentDownloads.start({
|
||||||
logger: log,
|
logger: log,
|
||||||
|
@ -1690,7 +1695,7 @@ export async function startApp(): Promise<void> {
|
||||||
if (connectCount === 1) {
|
if (connectCount === 1) {
|
||||||
Stickers.downloadQueuedPacks();
|
Stickers.downloadQueuedPacks();
|
||||||
if (!newVersion) {
|
if (!newVersion) {
|
||||||
void runStorageService();
|
drop(runStorageService());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -305,6 +305,8 @@ export default class MessageReceiver
|
||||||
|
|
||||||
private pniIdentityKeyCheckRequired?: boolean;
|
private pniIdentityKeyCheckRequired?: boolean;
|
||||||
|
|
||||||
|
private isAppReadyForProcessing: boolean = false;
|
||||||
|
|
||||||
constructor({ server, storage, serverTrustRoot }: MessageReceiverOptions) {
|
constructor({ server, storage, serverTrustRoot }: MessageReceiverOptions) {
|
||||||
super();
|
super();
|
||||||
|
|
||||||
|
@ -352,6 +354,15 @@ export default class MessageReceiver
|
||||||
maxSize: 30,
|
maxSize: 30,
|
||||||
processBatch: this.cacheRemoveBatch.bind(this),
|
processBatch: this.cacheRemoveBatch.bind(this),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window.Whisper.events.on('app-ready-for-processing', () => {
|
||||||
|
this.isAppReadyForProcessing = true;
|
||||||
|
this.reset();
|
||||||
|
});
|
||||||
|
|
||||||
|
window.Whisper.events.on('online', () => {
|
||||||
|
this.reset();
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public getAndResetProcessedCount(): number {
|
public getAndResetProcessedCount(): number {
|
||||||
|
@ -467,27 +478,36 @@ export default class MessageReceiver
|
||||||
}
|
}
|
||||||
|
|
||||||
public reset(): void {
|
public reset(): void {
|
||||||
// We always process our cache before processing a new websocket message
|
log.info('MessageReceiver.reset');
|
||||||
drop(
|
|
||||||
this.incomingQueue.add(
|
|
||||||
createTaskWithTimeout(
|
|
||||||
async () => this.queueAllCached(),
|
|
||||||
'incomingQueue/queueAllCached',
|
|
||||||
{
|
|
||||||
timeout: 10 * durations.MINUTE,
|
|
||||||
}
|
|
||||||
)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
this.count = 0;
|
this.count = 0;
|
||||||
this.isEmptied = false;
|
this.isEmptied = false;
|
||||||
this.stoppingProcessing = false;
|
this.stoppingProcessing = false;
|
||||||
|
|
||||||
|
if (!this.isAppReadyForProcessing) {
|
||||||
|
log.info('MessageReceiver.reset: not ready yet, returning early');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
drop(this.addCachedMessagesToQueue());
|
||||||
|
}
|
||||||
|
|
||||||
|
private addCachedMessagesToQueue(): Promise<void> {
|
||||||
|
log.info('MessageReceiver.addCachedMessagesToQueue');
|
||||||
|
return this.incomingQueue.add(
|
||||||
|
createTaskWithTimeout(
|
||||||
|
async () => this.queueAllCached(),
|
||||||
|
'incomingQueue/queueAllCached',
|
||||||
|
{
|
||||||
|
timeout: 10 * durations.MINUTE,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public stopProcessing(): void {
|
public stopProcessing(): void {
|
||||||
log.info('MessageReceiver.stopProcessing');
|
log.info('MessageReceiver.stopProcessing');
|
||||||
this.stoppingProcessing = true;
|
this.stoppingProcessing = true;
|
||||||
|
this.isAppReadyForProcessing = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
public hasEmptied(): boolean {
|
public hasEmptied(): boolean {
|
||||||
|
|
|
@ -499,8 +499,8 @@ export class SocketManager extends EventListener {
|
||||||
this.credentials = undefined;
|
this.credentials = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
public get isOnline(): boolean {
|
public get isOnline(): boolean | undefined {
|
||||||
return this.privIsOnline !== false;
|
return this.privIsOnline;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
|
@ -1157,7 +1157,7 @@ export type WebAPIType = {
|
||||||
unregisterRequestHandler: (handler: IRequestHandler) => void;
|
unregisterRequestHandler: (handler: IRequestHandler) => void;
|
||||||
onHasStoriesDisabledChange: (newValue: boolean) => void;
|
onHasStoriesDisabledChange: (newValue: boolean) => void;
|
||||||
checkSockets: () => void;
|
checkSockets: () => void;
|
||||||
isOnline: () => boolean;
|
isOnline: () => boolean | undefined;
|
||||||
onNavigatorOnline: () => Promise<void>;
|
onNavigatorOnline: () => Promise<void>;
|
||||||
onNavigatorOffline: () => Promise<void>;
|
onNavigatorOffline: () => Promise<void>;
|
||||||
onRemoteExpiration: () => Promise<void>;
|
onRemoteExpiration: () => Promise<void>;
|
||||||
|
@ -1637,7 +1637,7 @@ export function initialize({
|
||||||
void socketManager.check();
|
void socketManager.check();
|
||||||
}
|
}
|
||||||
|
|
||||||
function isOnline(): boolean {
|
function isOnline(): boolean | undefined {
|
||||||
return socketManager.isOnline;
|
return socketManager.isOnline;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,6 +26,7 @@ import { SignalService as Proto } from '../protobuf';
|
||||||
import * as log from '../logging/log';
|
import * as log from '../logging/log';
|
||||||
import type { StickersStateType } from '../state/ducks/stickers';
|
import type { StickersStateType } from '../state/ducks/stickers';
|
||||||
import { MINUTE } from '../util/durations';
|
import { MINUTE } from '../util/durations';
|
||||||
|
import { drop } from '../util/drop';
|
||||||
|
|
||||||
export type StickerType = {
|
export type StickerType = {
|
||||||
packId: string;
|
packId: string;
|
||||||
|
@ -173,6 +174,7 @@ export function getInstalledStickerPacks(): Array<StickerPackType> {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function downloadQueuedPacks(): void {
|
export function downloadQueuedPacks(): void {
|
||||||
|
log.info('downloadQueuedPacks');
|
||||||
strictAssert(packsToDownload, 'Stickers not initialized');
|
strictAssert(packsToDownload, 'Stickers not initialized');
|
||||||
|
|
||||||
const ids = Object.keys(packsToDownload);
|
const ids = Object.keys(packsToDownload);
|
||||||
|
@ -180,10 +182,12 @@ export function downloadQueuedPacks(): void {
|
||||||
const { key, status } = packsToDownload[id];
|
const { key, status } = packsToDownload[id];
|
||||||
|
|
||||||
// The queuing is done inside this function, no need to await here
|
// The queuing is done inside this function, no need to await here
|
||||||
void downloadStickerPack(id, key, {
|
drop(
|
||||||
finalStatus: status,
|
downloadStickerPack(id, key, {
|
||||||
suppressError: true,
|
finalStatus: status,
|
||||||
});
|
suppressError: true,
|
||||||
|
})
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
packsToDownload = {};
|
packsToDownload = {};
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
import { clearTimeoutIfNecessary } from './clearTimeoutIfNecessary';
|
import { clearTimeoutIfNecessary } from './clearTimeoutIfNecessary';
|
||||||
|
|
||||||
export type WaitForOnlineOptionsType = Readonly<{
|
export type WaitForOnlineOptionsType = Readonly<{
|
||||||
server?: Readonly<{ isOnline: () => boolean }>;
|
server?: Readonly<{ isOnline: () => boolean | undefined }>;
|
||||||
events?: {
|
events?: {
|
||||||
on: (event: 'online', fn: () => void) => void;
|
on: (event: 'online', fn: () => void) => void;
|
||||||
off: (event: 'online', fn: () => void) => void;
|
off: (event: 'online', fn: () => void) => void;
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue