Merge pull request #1321 from Bilb/use-created-at-server-timestamp

Fixes #1249
pull/1330/head
Audric Ackermann 5 years ago committed by GitHub
commit c34edee180
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -110,7 +110,6 @@ module.exports = {
getPublicConversationsByServer,
getPubkeysInPublicConversation,
getAllConversationIds,
getAllPrivateConversations,
getAllGroupsInvolvingId,
removeAllConversations,
removeAllPrivateConversations,
@ -130,6 +129,7 @@ module.exports = {
removeMessage,
getUnreadByConversation,
getMessageBySender,
getMessagesBySender,
getMessageIdsFromServerIds,
getMessageById,
getAllMessages,
@ -811,6 +811,7 @@ const LOKI_SCHEMA_VERSIONS = [
updateToLokiSchemaVersion5,
updateToLokiSchemaVersion6,
updateToLokiSchemaVersion7,
updateToLokiSchemaVersion8,
];
async function updateToLokiSchemaVersion1(currentVersion, instance) {
@ -824,7 +825,6 @@ async function updateToLokiSchemaVersion1(currentVersion, instance) {
`ALTER TABLE messages
ADD COLUMN serverId INTEGER;`
);
await instance.run(
`CREATE TABLE servers(
serverUrl STRING PRIMARY KEY ASC,
@ -1052,6 +1052,29 @@ async function updateToLokiSchemaVersion7(currentVersion, instance) {
console.log('updateToLokiSchemaVersion7: success!');
}
async function updateToLokiSchemaVersion8(currentVersion, instance) {
if (currentVersion >= 8) {
return;
}
console.log('updateToLokiSchemaVersion8: starting...');
await instance.run('BEGIN TRANSACTION;');
await instance.run(
`ALTER TABLE messages
ADD COLUMN serverTimestamp INTEGER;`
);
await instance.run(
`INSERT INTO loki_schema (
version
) values (
8
);`
);
await instance.run('COMMIT TRANSACTION;');
console.log('updateToLokiSchemaVersion8: success!');
}
async function updateLokiSchema(instance) {
const result = await instance.get(
"SELECT name FROM sqlite_master WHERE type = 'table' AND name='loki_schema';"
@ -1948,16 +1971,6 @@ async function getAllConversationIds() {
return map(rows, row => row.id);
}
async function getAllPrivateConversations() {
const rows = await db.all(
`SELECT json FROM ${CONVERSATIONS_TABLE} WHERE
type = 'private'
ORDER BY id ASC;`
);
return map(rows, row => jsonToObject(row.json));
}
async function getAllPublicConversations() {
const rows = await db.all(
`SELECT json FROM conversations WHERE
@ -2103,6 +2116,7 @@ async function saveMessage(data, { forceSave } = {}) {
hasVisualMediaAttachments,
id,
serverId,
serverTimestamp,
// eslint-disable-next-line camelcase
received_at,
schemaVersion,
@ -2122,6 +2136,7 @@ async function saveMessage(data, { forceSave } = {}) {
$json: objectToJSON(data),
$serverId: serverId,
$serverTimestamp: serverTimestamp,
$body: body,
$conversationId: conversationId,
$expirationStartTimestamp: expirationStartTimestamp,
@ -2145,6 +2160,7 @@ async function saveMessage(data, { forceSave } = {}) {
`UPDATE messages SET
json = $json,
serverId = $serverId,
serverTimestamp = $serverTimestamp,
body = $body,
conversationId = $conversationId,
expirationStartTimestamp = $expirationStartTimestamp,
@ -2180,6 +2196,7 @@ async function saveMessage(data, { forceSave } = {}) {
json,
serverId,
serverTimestamp,
body,
conversationId,
expirationStartTimestamp,
@ -2201,6 +2218,7 @@ async function saveMessage(data, { forceSave } = {}) {
$json,
$serverId,
$serverTimestamp,
$body,
$conversationId,
$expirationStartTimestamp,
@ -2394,6 +2412,20 @@ async function getMessageBySender({ source, sourceDevice, sent_at }) {
return map(rows, row => jsonToObject(row.json));
}
async function getMessagesBySender({ source, sourceDevice }) {
const rows = await db.all(
`SELECT json FROM messages WHERE
source = $source AND
sourceDevice = $sourceDevice`,
{
$source: source,
$sourceDevice: sourceDevice,
}
);
return map(rows, row => jsonToObject(row.json));
}
async function getAllUnsentMessages() {
const rows = await db.all(`
SELECT json FROM messages WHERE
@ -2430,7 +2462,7 @@ async function getMessagesByConversation(
conversationId = $conversationId AND
received_at < $received_at AND
type LIKE $type
ORDER BY sent_at DESC
ORDER BY serverTimestamp DESC, serverId DESC, sent_at DESC
LIMIT $limit;
`,
{

@ -359,7 +359,6 @@
<script type='text/javascript' src='js/views/device_pairing_dialog_view.js'></script>
<script type='text/javascript' src='js/views/device_pairing_words_dialog_view.js'></script>
<script type='text/javascript' src='js/views/create_group_dialog_view.js'></script>
<script type='text/javascript' src='js/views/confirm_session_reset_view.js'></script>
<script type='text/javascript' src='js/views/edit_profile_dialog_view.js'></script>
<script type='text/javascript' src='js/views/invite_contacts_dialog_view.js'></script>
<script type='text/javascript' src='js/views/moderators_add_dialog_view.js'></script>

@ -362,7 +362,6 @@
<script type='text/javascript' src='js/views/device_pairing_dialog_view.js'></script>
<script type='text/javascript' src='js/views/device_pairing_words_dialog_view.js'></script>
<script type='text/javascript' src='js/views/create_group_dialog_view.js'></script>
<script type='text/javascript' src='js/views/confirm_session_reset_view.js'></script>
<script type='text/javascript' src='js/views/edit_profile_dialog_view.js'></script>
<script type='text/javascript' src='js/views/invite_contacts_dialog_view.js'></script>
<script type='text/javascript' src='js/views/moderators_add_dialog_view.js'></script>

@ -1121,10 +1121,15 @@
Whisper.events.on(
'publicMessageSent',
({ pubKey, timestamp, serverId }) => {
({ pubKey, timestamp, serverId, serverTimestamp }) => {
try {
const conversation = ConversationController.get(pubKey);
conversation.onPublicMessageSent(pubKey, timestamp, serverId);
conversation.onPublicMessageSent(
pubKey,
timestamp,
serverId,
serverTimestamp
);
} catch (e) {
window.log.error('Error setting public on message');
}
@ -1326,7 +1331,7 @@
messageReceiver = new textsecure.MessageReceiver(mySignalingKey, options);
messageReceiver.addEventListener(
'message',
window.NewReceiver.handleMessageEvent
window.DataMessageReceiver.handleMessageEvent
);
window.textsecure.messaging = new textsecure.MessageSender();
return;
@ -1337,11 +1342,11 @@
messageReceiver = new textsecure.MessageReceiver(mySignalingKey, options);
messageReceiver.addEventListener(
'message',
window.NewReceiver.handleMessageEvent
window.DataMessageReceiver.handleMessageEvent
);
messageReceiver.addEventListener(
'sent',
window.NewReceiver.handleMessageEvent
window.DataMessageReceiver.handleMessageEvent
);
messageReceiver.addEventListener('empty', onEmpty);
messageReceiver.addEventListener('reconnect', onReconnect);

@ -540,14 +540,13 @@
await Promise.all(messages.map(m => m.setCalculatingPoW()));
},
async onPublicMessageSent(pubKey, timestamp, serverId) {
async onPublicMessageSent(pubKey, timestamp, serverId, serverTimestamp) {
const messages = this._getMessagesWithTimestamp(pubKey, timestamp);
await Promise.all(
messages.map(message => [
message.setIsPublic(true),
message.setServerId(serverId),
])
);
if (messages && messages.length === 1) {
await messages[0].setIsPublic(true);
await messages[0].setServerId(serverId);
await messages[0].setServerTimestamp(serverTimestamp);
}
},
async onNewMessage(message) {
@ -1295,6 +1294,9 @@
if (this.isPrivate()) {
message.set({ destination });
}
if (this.isPublic()) {
message.setServerTimestamp(new Date().getTime());
}
const id = await window.Signal.Data.saveMessage(message.attributes, {
Message: Whisper.Message,

@ -596,6 +596,7 @@
id: this.id,
direction: this.isIncoming() ? 'incoming' : 'outgoing',
timestamp: this.get('sent_at'),
serverTimestamp: this.get('serverTimestamp'),
status: this.getMessagePropStatus(),
contact: this.getPropsForEmbeddedContact(),
authorColor,
@ -1440,6 +1441,19 @@
Message: Whisper.Message,
});
},
async setServerTimestamp(serverTimestamp) {
if (_.isEqual(this.get('serverTimestamp'), serverTimestamp)) {
return;
}
this.set({
serverTimestamp,
});
await window.Signal.Data.saveMessage(this.attributes, {
Message: Whisper.Message,
});
},
async setIsPublic(isPublic) {
if (_.isEqual(this.get('isPublic'), isPublic)) {
return;
@ -1669,13 +1683,6 @@
Whisper.MessageCollection = Backbone.Collection.extend({
model: Whisper.Message,
comparator(left, right) {
if (left.get('sent_at') === right.get('sent_at')) {
return (left.get('received_at') || 0) - (right.get('received_at') || 0);
}
return (left.get('sent_at') || 0) - (right.get('sent_at') || 0);
},
initialize(models, options) {
if (options) {
this.conversation = options.conversation;
@ -1726,7 +1733,7 @@
);
}
this.add(models);
this.add(models.reverse());
if (unreadCount <= 0) {
return;

@ -197,7 +197,6 @@ export function getAllConversations({
}): Promise<Array<ConversationCollection>>;
export function getAllConversationIds(): Promise<Array<string>>;
export function getAllPrivateConversations(): Promise<Array<string>>;
export function getAllPublicConversations(): Promise<Array<string>>;
export function getPublicConversationsByServer(
server: string,
@ -224,7 +223,6 @@ export function searchMessagesInConversation(
conversationId: string,
{ limit }?: { limit: any }
): Promise<any>;
export function getMessageCount(): Promise<number>;
export function saveMessage(
data: Mesasge,
{ forceSave, Message }?: { forceSave?: any; Message?: any }
@ -267,6 +265,10 @@ export function getMessageBySender(
}: { source: any; sourceDevice: any; sent_at: any },
{ Message }: { Message: any }
): Promise<any>;
export function getMessagesBySender(
{ source, sourceDevice }: { source: any; sourceDevice: any },
{ Message }: { Message: any }
): Promise<Whisper.MessageCollection>;
export function getMessageIdsFromServerIds(
serverIds: any,
conversationId: any
@ -322,6 +324,7 @@ export function getMessagesByConversation(
type?: string;
}
): Promise<any>;
export function getSeenMessagesByHashList(hashes: any): Promise<any>;
export function getLastHashBySnode(convoId: any, snode: any): Promise<any>;

@ -123,7 +123,6 @@ module.exports = {
getAllConversations,
getAllConversationIds,
getAllPrivateConversations,
getAllPublicConversations,
getPublicConversationsByServer,
getPubkeysInPublicConversation,
@ -135,7 +134,6 @@ module.exports = {
searchMessages,
searchMessagesInConversation,
getMessageCount,
saveMessage,
cleanSeenMessages,
cleanLastHashes,
@ -151,6 +149,7 @@ module.exports = {
removeAllMessagesInConversation,
getMessageBySender,
getMessagesBySender,
getMessageIdsFromServerIds,
getMessageById,
getAllMessages,
@ -818,14 +817,6 @@ async function getAllPublicConversations({ ConversationCollection }) {
return collection;
}
async function getAllPrivateConversations({ ConversationCollection }) {
const conversations = await channels.getAllPrivateConversations();
const collection = new ConversationCollection();
collection.add(conversations);
return collection;
}
async function getPubkeysInPublicConversation(id) {
return channels.getPubkeysInPublicConversation(id);
}
@ -882,9 +873,6 @@ async function searchMessagesInConversation(
}
// Message
async function getMessageCount() {
return channels.getMessageCount();
}
async function cleanSeenMessages() {
await channels.cleanSeenMessages();
@ -1015,6 +1003,22 @@ async function getMessageBySender(
return new Message(messages[0]);
}
async function getMessagesBySender(
// eslint-disable-next-line camelcase
{ source, sourceDevice },
{ Message }
) {
const messages = await channels.getMessagesBySender({
source,
sourceDevice,
});
if (!messages || !messages.length) {
return null;
}
return messages.map(m => new Message(m));
}
async function getUnreadByConversation(conversationId, { MessageCollection }) {
const messages = await channels.getUnreadByConversation(conversationId);
return new MessageCollection(messages);

@ -30,7 +30,7 @@ export interface LokiPublicChannelAPI {
body?: string;
},
timestamp: number
): Promise<number>;
): Promise<{ serverId; serverTimestamp }>;
}
declare class LokiAppDotNetServerAPI implements LokiAppDotNetServerInterface {

@ -6,13 +6,13 @@ const { URL, URLSearchParams } = require('url');
const FormData = require('form-data');
const https = require('https');
const path = require('path');
const dataMessage = require('../../ts/receiver/dataMessage');
// Can't be less than 1200 if we have unauth'd requests
const PUBLICCHAT_MSG_POLL_EVERY = 1.5 * 1000; // 1.5s
const PUBLICCHAT_CHAN_POLL_EVERY = 20 * 1000; // 20s
const PUBLICCHAT_DELETION_POLL_EVERY = 5 * 1000; // 5s
const PUBLICCHAT_MOD_POLL_EVERY = 30 * 1000; // 30s
const PUBLICCHAT_MIN_TIME_BETWEEN_DUPLICATE_MESSAGES = 10 * 1000; // 10s
// FIXME: replace with something on urlPubkeyMap...
const FILESERVER_HOSTS = [
@ -1800,6 +1800,8 @@ class LokiPublicChannelAPI {
return {
timestamp,
serverTimestamp:
new Date(`${adnMessage.created_at}`).getTime() || timestamp,
attachments,
preview,
quote,
@ -1913,9 +1915,13 @@ class LokiPublicChannelAPI {
if (messengerData === false) {
return false;
}
// eslint-disable-next-line no-param-reassign
adnMessage.timestamp = messengerData.timestamp;
// eslint-disable-next-line no-param-reassign
adnMessage.body = messengerData.text;
const {
timestamp,
serverTimestamp,
quote,
attachments,
preview,
@ -1927,20 +1933,15 @@ class LokiPublicChannelAPI {
}
// Duplicate check
const isDuplicate = message => {
// The username in this case is the users pubKey
const sameUsername = message.username === pubKey;
const sameText = message.text === adnMessage.text;
// Don't filter out messages that are too far apart from each other
const timestampsSimilar =
Math.abs(message.timestamp - timestamp) <=
PUBLICCHAT_MIN_TIME_BETWEEN_DUPLICATE_MESSAGES;
return sameUsername && sameText && timestampsSimilar;
};
const isDuplicate = (message, testedMessage) =>
dataMessage.isDuplicate(
message,
testedMessage,
testedMessage.user.username
);
// Filter out any messages that we got previously
if (this.lastMessagesCache.some(isDuplicate)) {
if (this.lastMessagesCache.some(m => isDuplicate(m, adnMessage))) {
return false; // Duplicate message
}
@ -1949,9 +1950,11 @@ class LokiPublicChannelAPI {
this.lastMessagesCache = [
...this.lastMessagesCache,
{
username: pubKey,
text: adnMessage.text,
timestamp,
attributes: {
source: pubKey,
body: adnMessage.text,
sent_at: timestamp,
},
},
].splice(-5);
@ -1990,9 +1993,9 @@ class LokiPublicChannelAPI {
isSessionRequest: false,
source: pubKey,
sourceDevice: 1,
timestamp,
timestamp, // sender timestamp
serverTimestamp: timestamp,
serverTimestamp, // server created_at, used to order messages
receivedAt,
isPublic: true,
message: {
@ -2008,7 +2011,7 @@ class LokiPublicChannelAPI {
profileKey,
timestamp,
received_at: receivedAt,
sent_at: timestamp,
sent_at: timestamp, // sender timestamp inner
quote,
contact: [],
preview,
@ -2342,7 +2345,10 @@ class LokiPublicChannelAPI {
objBody: payload,
});
if (!res.err && res.response) {
return res.response.data.id;
return {
serverId: res.response.data.id,
serverTimestamp: new Date(`${res.response.data.created_at}`).getTime(),
};
}
if (res.err) {
log.error(`POST ${this.baseChannelUrl}/messages failed`);
@ -2354,9 +2360,8 @@ class LokiPublicChannelAPI {
} else {
log.warn(res.response);
}
// there's no retry on desktop
// this is supposed to be after retries
return -1;
return { serverId: -1, serverTimestamp: -1 };
}
}

@ -60,7 +60,8 @@ class LokiMessageAPI {
'Failed to send public chat message'
);
}
messageEventData.serverId = res;
messageEventData.serverId = res.serverId;
messageEventData.serverTimestamp = res.serverTimestamp;
window.Whisper.events.trigger('publicMessageSent', messageEventData);
return;
}

@ -420,6 +420,7 @@ window.addEventListener('contextmenu', e => {
});
window.NewReceiver = require('./ts/receiver/receiver');
window.DataMessageReceiver = require('./ts/receiver/dataMessage');
window.NewSnodeAPI = require('./ts/session/snode_api/serviceNodeAPI');
window.SnodePool = require('./ts/session/snode_api/snodePool');

@ -1200,7 +1200,9 @@
}
.module-message-detail__unix-timestamp {
color: $color-light-10;
@include themify($themes) {
color: subtle(themed('textColor'));
}
}
.module-message-detail__delete-button-container {

@ -370,7 +370,10 @@ $session-element-border-green: 4px solid $session-color-green;
font-size: $session-font-md;
&-text {
@include session-color-subtle($session-color-white);
@include themify($themes) {
@include session-color-subtle(themed('textColor'));
}
font-family: $session-font-default;
font-weight: 300;
font-size: $session-font-xs;

@ -584,10 +584,6 @@
// Module: Message Detail
.module-message-detail__unix-timestamp {
color: $color-dark-55;
}
.module-message-detail__delete-button {
background-color: $session-color-danger;
color: $color-white;

@ -370,7 +370,6 @@
<script type="text/javascript" src="../js/views/device_pairing_dialog_view.js"></script>
<script type="text/javascript" src="../js/views/device_pairing_words_dialog_view.js"></script>
<script type="text/javascript" src="../js/views/create_group_dialog_view.js"></script>
<script type="text/javascript" src="../js/views/confirm_session_reset_view.js"></script>
<script type="text/javascript" src="../js/views/edit_profile_dialog_view.js"></script>
<script type="text/javascript" src="../js/views/invite_contacts_dialog_view.js"></script>
<script type="text/javascript" src="../js/views/moderators_add_dialog_view.js"></script>

@ -65,6 +65,7 @@ export interface Props {
collapseMetadata?: boolean;
direction: 'incoming' | 'outgoing';
timestamp: number;
serverTimestamp?: number;
status?: 'sending' | 'sent' | 'delivered' | 'read' | 'error';
// What if changed this over to a single contact like quote, and put the events on it?
contact?: Contact & {
@ -257,6 +258,7 @@ export class Message extends React.PureComponent<Props, State> {
text,
textPending,
timestamp,
serverTimestamp,
} = this.props;
if (collapseMetadata) {
@ -299,7 +301,7 @@ export class Message extends React.PureComponent<Props, State> {
) : (
<Timestamp
i18n={i18n}
timestamp={timestamp}
timestamp={serverTimestamp || timestamp}
extended={true}
direction={direction}
withImageNoCaption={withImageNoCaption}

@ -356,30 +356,53 @@ interface MessageId {
source: any;
sourceDevice: any;
timestamp: any;
message: any;
}
const PUBLICCHAT_MIN_TIME_BETWEEN_DUPLICATE_MESSAGES = 10 * 1000; // 10s
async function isMessageDuplicate({
source,
sourceDevice,
timestamp,
message,
}: MessageId) {
const { Errors } = window.Signal.Types;
try {
const result = await window.Signal.Data.getMessageBySender(
{ source, sourceDevice, sent_at: timestamp },
const result = await window.Signal.Data.getMessagesBySender(
{ source, sourceDevice },
{
Message: window.Whisper.Message,
}
);
return Boolean(result);
if (!result) {
return false;
}
const filteredResult = result.filter(
(m: any) => m.attributes.body === message.body
);
const isSimilar = filteredResult.some((m: any) =>
isDuplicate(m, message, source)
);
return isSimilar;
} catch (error) {
window.log.error('isMessageDuplicate error:', Errors.toLogFormat(error));
return false;
}
}
export const isDuplicate = (m: any, testedMessage: any, source: string) => {
// The username in this case is the users pubKey
const sameUsername = m.attributes.source === source;
const sameText = m.attributes.body === testedMessage.body;
// Don't filter out messages that are too far apart from each other
const timestampsSimilar =
Math.abs(m.attributes.sent_at - testedMessage.timestamp) <=
PUBLICCHAT_MIN_TIME_BETWEEN_DUPLICATE_MESSAGES;
return sameUsername && sameText && timestampsSimilar;
};
async function handleProfileUpdate(
profileKeyBuffer: Uint8Array,
convoId: string,
@ -427,6 +450,7 @@ interface MessageCreationData {
source: boolean;
serverId: string;
message: any;
serverTimestamp: any;
// Needed for synced outgoing messages
unidentifiedStatus: any; // ???
@ -445,6 +469,7 @@ export function initIncomingMessage(data: MessageCreationData): MessageModel {
source,
serverId,
message,
serverTimestamp,
} = data;
const type = 'incoming';
@ -457,6 +482,7 @@ export function initIncomingMessage(data: MessageCreationData): MessageModel {
sourceDevice,
serverId, // + (not present below in `createSentMessage`)
sent_at: timestamp,
serverTimestamp,
received_at: receivedAt || Date.now(),
conversationId: groupId ?? source,
unidentifiedDeliveryReceived, // +
@ -476,6 +502,7 @@ function createSentMessage(data: MessageCreationData): MessageModel {
const {
timestamp,
serverTimestamp,
isPublic,
receivedAt,
sourceDevice,
@ -508,6 +535,7 @@ function createSentMessage(data: MessageCreationData): MessageModel {
const messageData: any = {
source: window.textsecure.storage.user.getNumber(),
sourceDevice,
serverTimestamp,
sent_at: timestamp,
received_at: isPublic ? receivedAt : now,
conversationId: destination, // conversation ID will might change later (if it is a group)
@ -588,9 +616,7 @@ export async function handleMessageEvent(event: MessageEvent): Promise<void> {
// if the message is `sent` (from secondary device) we have to set the sender manually... (at least for now)
source = source || msg.get('source');
const isDuplicate = await isMessageDuplicate(data);
if (isDuplicate) {
if (await isMessageDuplicate(data)) {
// RSS expects duplicates, so squelch log
if (!source.match(/^rss:/)) {
window.log.warn('Received duplicate message', msg.idForLogging());

@ -4,7 +4,7 @@ import { EnvelopePlus } from './types';
import * as Data from '../../js/modules/data';
import { SignalService } from '../protobuf';
import { updateProfile } from './receiver';
import { updateProfile } from './dataMessage';
import { onVerified } from './syncMessages';
import { StringUtils } from '../session/utils';

@ -19,27 +19,14 @@ import _ from 'lodash';
export { processMessage, onDeliveryReceipt };
import {
handleDataMessage,
handleMessageEvent,
updateProfile,
} from './dataMessage';
import { handleMessageEvent, updateProfile } from './dataMessage';
import { getEnvelopeId } from './common';
import { StringUtils } from '../session/utils';
import { SignalService } from '../protobuf';
import { BlockedNumberController } from '../util/blockedNumberController';
import { MultiDeviceProtocol } from '../session/protocols';
// TODO: check if some of these exports no longer needed
export {
handleEndSession,
handleMediumGroupUpdate,
downloadAttachment,
handleDataMessage,
updateProfile,
handleMessageEvent,
};
interface ReqOptions {
conversationId: string;

@ -11,14 +11,12 @@ import {
handleMessageEvent,
isMessageEmpty,
processDecrypted,
updateProfile,
} from './dataMessage';
import { updateProfile } from './receiver';
import { handleContacts } from './multidevice';
import { updateOrCreateGroupFromSync } from '../session/medium_group';
import { MultiDeviceProtocol } from '../session/protocols';
import { DataMessage } from '../session/messages/outgoing';
import { BlockedNumberController } from '../util';
import { StringUtils } from '../session/utils';
export async function handleSyncMessage(
envelope: EnvelopePlus,

@ -62,13 +62,14 @@ export class MessageQueue implements MessageQueueInterface {
try {
const result = await MessageSender.sendToOpenGroup(message);
// sendToOpenGroup returns -1 if failed or an id if succeeded
if (result < 0) {
if (result.serverId < 0) {
this.events.emit('fail', message, error);
} else {
const messageEventData = {
pubKey: message.group.groupId,
timestamp: message.timestamp,
serverId: result,
serverId: result.serverId,
serverTimestamp: result.serverTimestamp,
};
this.events.emit('success', message);

@ -98,7 +98,7 @@ function wrapEnvelope(envelope: SignalService.Envelope): Uint8Array {
*/
export async function sendToOpenGroup(
message: OpenGroupMessage
): Promise<number> {
): Promise<{ serverId: number; serverTimestamp: number }> {
/*
Note: Retrying wasn't added to this but it can be added in the future if needed.
The only problem is that `channelAPI.sendMessage` returns true/false and doesn't throw any error so we can never be sure why sending failed.
@ -112,7 +112,7 @@ export async function sendToOpenGroup(
);
if (!channelAPI) {
return -1;
return { serverId: -1, serverTimestamp: -1 };
}
// Returns -1 on fail or an id > 0 on success

@ -27,6 +27,7 @@ chai.use(chaiAsPromised);
const { expect } = chai;
// tslint:disable-next-line: max-func-body-length
describe('MessageQueue', () => {
// Initialize new stubbed cache
const sandbox = sinon.createSandbox();
@ -321,12 +322,12 @@ describe('MessageQueue', () => {
describe('open groups', async () => {
let sendToOpenGroupStub: sinon.SinonStub<
[OpenGroupMessage],
Promise<number>
Promise<{ serverId: number; serverTimestamp: number }>
>;
beforeEach(() => {
sendToOpenGroupStub = sandbox
.stub(MessageSender, 'sendToOpenGroup')
.resolves(-1);
.resolves({ serverId: -1, serverTimestamp: -1 });
});
it('can send to open group', async () => {
@ -336,7 +337,7 @@ describe('MessageQueue', () => {
});
it('should emit a success event when send was successful', async () => {
sendToOpenGroupStub.resolves(123456);
sendToOpenGroupStub.resolves({ serverId: 5125, serverTimestamp: 5125 });
const message = TestUtils.generateOpenGroupMessage();
const eventPromise = PromiseUtils.waitForTask(complete => {
@ -348,7 +349,7 @@ describe('MessageQueue', () => {
});
it('should emit a fail event if something went wrong', async () => {
sendToOpenGroupStub.resolves(-1);
sendToOpenGroupStub.resolves({ serverId: -1, serverTimestamp: -1 });
const message = TestUtils.generateOpenGroupMessage();
const eventPromise = PromiseUtils.waitForTask(complete => {
messageQueueStub.events.once('fail', complete);

Loading…
Cancel
Save