pull/1174/head
Vincent 5 years ago
parent ef65e47819
commit 80bc3520bd

@ -8,7 +8,7 @@ interface ClosedGroupMessageParams extends MessageParams {
} }
export abstract class ClosedGroupMessage extends DataMessage { export abstract class ClosedGroupMessage extends DataMessage {
protected readonly groupId: string; public readonly groupId: string;
constructor(params: ClosedGroupMessageParams) { constructor(params: ClosedGroupMessageParams) {
super({ super({

@ -2,6 +2,11 @@ import { ContentMessage } from '../ContentMessage';
import { SignalService } from '../../../../../protobuf'; import { SignalService } from '../../../../../protobuf';
export abstract class SyncMessage extends ContentMessage { export abstract class SyncMessage extends ContentMessage {
public static canSync(message: ContentMessage): boolean {
// TODO: implement
return true;
}
public ttl(): number { public ttl(): number {
return this.getDefaultTTL(); return this.getDefaultTTL();
} }

@ -3,19 +3,20 @@
// 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 // 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 { SessionResetMessage } from '../messages/outgoing';
import { PubKey } from '../types';
export function hasSession(device: string): boolean { export function hasSession(device: PubKey): boolean {
return false; // TODO: Implement return false; // TODO: Implement
} }
export function hasSentSessionRequest(device: string): boolean { export function hasSentSessionRequest(device: PubKey): boolean {
// TODO: need a way to keep track of if we've sent a session request // 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 // My idea was to use the timestamp of when it was sent but there might be another better approach
return false; return false;
} }
export async function sendSessionRequestIfNeeded( export async function sendSessionRequestIfNeeded(
device: string device: PubKey
): Promise<void> { ): Promise<void> {
if (hasSession(device) || hasSentSessionRequest(device)) { if (hasSession(device) || hasSentSessionRequest(device)) {
return Promise.resolve(); return Promise.resolve();
@ -34,14 +35,14 @@ export async function sendSessionRequest(
return Promise.resolve(); return Promise.resolve();
} }
export function sessionEstablished(device: string) { export function sessionEstablished(device: PubKey) {
// TODO: this is called when we receive an encrypted message from the other user // TODO: this is called when we receive an encrypted message from the other user
// Maybe it should be renamed to something else // Maybe it should be renamed to something else
// TODO: This should make `hasSentSessionRequest` return `false` // TODO: This should make `hasSentSessionRequest` return `false`
} }
export function shouldProcessSessionRequest( export function shouldProcessSessionRequest(
device: string, device: PubKey,
messageTimestamp: number messageTimestamp: number
): boolean { ): boolean {
// TODO: Need to do the following here // TODO: Need to do the following here
@ -49,7 +50,7 @@ export function shouldProcessSessionRequest(
return false; return false;
} }
export function sessionRequestProcessed(device: string) { export function sessionRequestProcessed(device: PubKey) {
// TODO: this is called when we process the session request // TODO: this is called when we process the session request
// This should store the processed timestamp // This should store the processed timestamp
// Again naming is crap so maybe some other name is better // Again naming is crap so maybe some other name is better

@ -1,14 +1,21 @@
import * as _ from 'lodash';
import * as Data from '../../../js/modules/data';
import { textsecure } from '../../window';
import { EventEmitter } from 'events'; import { EventEmitter } from 'events';
import { import {
MessageQueueInterface, MessageQueueInterface,
MessageQueueInterfaceEvents, MessageQueueInterfaceEvents,
GroupMessageType,
} from './MessageQueueInterface'; } from './MessageQueueInterface';
import { ContentMessage, OpenGroupMessage, SyncMessage, SessionResetMessage } from '../messages/outgoing'; import { ContentMessage, OpenGroupMessage, SyncMessage, SessionResetMessage, ClosedGroupMessage } from '../messages/outgoing';
import { PendingMessageCache } from './PendingMessageCache'; import { PendingMessageCache } from './PendingMessageCache';
import { JobQueue, TypedEventEmitter } from '../utils'; import { JobQueue, TypedEventEmitter, toRawMessage, toSyncMessage } from '../utils';
import { PubKey } from '../types'; import { PubKey } from '../types';
import { ConversationController } from '../../window'; import { ConversationController } from '../../window';
import { MessageSender } from '.'; import { MessageSender } from '.';
import { SessionProtocol } from '../protocols';
export class MessageQueue implements MessageQueueInterface { export class MessageQueue implements MessageQueueInterface {
public readonly events: TypedEventEmitter<MessageQueueInterfaceEvents>; public readonly events: TypedEventEmitter<MessageQueueInterfaceEvents>;
@ -18,37 +25,86 @@ export class MessageQueue implements MessageQueueInterface {
constructor() { constructor() {
this.events = new EventEmitter(); this.events = new EventEmitter();
this.cache = new PendingMessageCache(); this.cache = new PendingMessageCache();
this.processAllPending(); void this.processAllPending();
} }
public sendUsingMultiDevice(user: string, message: ContentMessage) { public async sendUsingMultiDevice(user: PubKey, message: ContentMessage) {
// this.cache const userLinked = await Data.getPairedDevicesFor(user.key);
const userDevices = userLinked.map(d => new PubKey(d));
// throw new Error('Method not implemented.');
await this.sendMessageToDevices(userDevices, message);
} }
public send(device: PubKey, message: ContentMessage) {
throw new Error('Method not implemented.'); public async send(device: PubKey, message: ContentMessage) {
await this.sendMessageToDevices([device], message);
} }
public sendToGroup(message: ContentMessage | OpenGroupMessage) {
throw new Error('Method not implemented.'); public async sendMessageToDevices(devices: Array<PubKey>, message: ContentMessage) {
let currentDevices = [...devices];
if (SyncMessage.canSync(message)) {
// Sync to our devices
const syncMessage = toSyncMessage.from(message);
await this.sendSyncMessage(syncMessage);
// Remove our devices from currentDevices
const ourDevices = await this.getOurDevices();
currentDevices = currentDevices.filter(device => !_.includes(ourDevices, device));
}
currentDevices.forEach(async device => {
await this.queue(device, message);
});
} }
public sendSyncMessage(message: ContentMessage) {
throw new Error('Method not implemented.'); public async sendToGroup(message: OpenGroupMessage | ContentMessage) {
if (!(message instanceof OpenGroupMessage) && !(message instanceof ClosedGroupMessage)) {
return;
}
// Closed groups
if (message instanceof ClosedGroupMessage) {
// Get devices in closed group
const conversation = ConversationController.get(message.groupId);
const recipients = 5;
await this.sendMessageToDevices(recipients, message);
}
// Open groups
if (message instanceof OpenGroupMessage) {
// No queue needed for Open Groups; send directly
}
} }
public processPending(device: PubKey) { public async sendSyncMessage(message: ContentMessage) {
// TODO: implement // Sync with our devices
const SessionManager: any = {}; // TEMP FIX
const syncMessage = toSyncMessage();
if (!syncMessage.canSync()) {
return;
}
const ourDevices = await this.getOurDevices();
ourDevices.forEach(async device => {
await this.queue(device, message);
});
}
public async processPending(device: PubKey) {
const messages = this.cache.getForDevice(device); const messages = this.cache.getForDevice(device);
const hasSession = SessionProtocol.hasSession(device);
const conversation = ConversationController.get(device.key); const conversation = ConversationController.get(device.key);
const isMediumGroup = conversation.isMediumGroup(); const isMediumGroup = conversation.isMediumGroup();
const hasSession = false; // TODO ; = SessionManager.hasSession(device);
if (!isMediumGroup && !hasSession) { if (!isMediumGroup && !hasSession) {
SessionManager.sendSessionRequestIfNeeded(); await SessionProtocol.sendSessionRequestIfNeeded(device);
return; return;
} }
@ -56,7 +112,7 @@ export class MessageQueue implements MessageQueueInterface {
const jobQueue = this.getJobQueue(device); const jobQueue = this.getJobQueue(device);
messages.forEach(message => { messages.forEach(message => {
if (!jobQueue.has(message.identifier)) { if (!jobQueue.has(message.identifier)) {
const promise = jobQueue.add(message.identifier, MessageSender.send(message)); const promise = jobQueue.add(async () => MessageSender.send(message));
promise.then(() => { promise.then(() => {
// Message sent; remove from cache // Message sent; remove from cache
@ -66,32 +122,22 @@ export class MessageQueue implements MessageQueueInterface {
}); });
} }
}); });
} }
private processAllPending() { private async processAllPending() {
// TODO: Get all devices which are pending here const devices = this.cache.getDevices();
const promises = devices.map(async device => this.processPending(device));
return Promise.all(promises);
} }
private queue(device: PubKey, message: ContentMessage) { private async queue(device: PubKey, message: ContentMessage) {
// TODO: implement
if (message instanceof SessionResetMessage) { if (message instanceof SessionResetMessage) {
return; return;
} }
const added = this.cache.add(device, message); await this.cache.add(device, message);
await this.processPending(device);
// if not added?
this.processPending(device);
}
private queueOpenGroupMessage(message: OpenGroupMessage) {
// TODO: Do we need to queue open group messages?
// If so we can get open group job queue and add the send job here
} }
private getJobQueue(device: PubKey): JobQueue { private getJobQueue(device: PubKey): JobQueue {
@ -103,4 +149,11 @@ export class MessageQueue implements MessageQueueInterface {
return queue; return queue;
} }
private async getOurDevices(): Promise<Array<PubKey>> {
const ourKey = await textsecure.storage.user.getNumber();
const ourLinked = await Data.getPairedDevicesFor(ourKey);
return ourLinked.map(d => new PubKey(d));
}
} }

@ -16,7 +16,7 @@ export interface MessageQueueInterfaceEvents {
export interface MessageQueueInterface { export interface MessageQueueInterface {
events: TypedEventEmitter<MessageQueueInterfaceEvents>; events: TypedEventEmitter<MessageQueueInterfaceEvents>;
sendUsingMultiDevice(user: string, message: ContentMessage): void; sendUsingMultiDevice(user: PubKey, message: ContentMessage): void;
send(device: PubKey, message: ContentMessage): void; send(device: PubKey, message: ContentMessage): void;
sendToGroup(message: GroupMessageType): void; sendToGroup(message: GroupMessageType): void;
sendSyncMessage(message: ContentMessage): void; sendSyncMessage(message: ContentMessage): void;

@ -1,5 +1,5 @@
import { RawMessage } from '../types/RawMessage'; import { RawMessage } from '../types/RawMessage';
import { ContentMessage } from '../messages/outgoing'; import { ContentMessage, SyncMessage } from '../messages/outgoing';
import { EncryptionType, PubKey } from '../types'; import { EncryptionType, PubKey } from '../types';
export function toRawMessage( export function toRawMessage(
@ -22,3 +22,8 @@ export function toRawMessage(
return rawMessage; return rawMessage;
} }
export function toSyncMessage(message: ContentMessage): {
return SyncMessage;
}
Loading…
Cancel
Save