be sure to send open group messages in order

pull/1381/head
Audric Ackermann 5 years ago
parent 220de2cd0a
commit efa45f7cbe

@ -1127,7 +1127,7 @@
async sendMessageJob(message) {
try {
const uploads = await message.uploadData();
const id = message.id;
const { id } = message;
const expireTimer = this.get('expireTimer');
const destination = this.id;
@ -1236,6 +1236,7 @@
throw new TypeError(`Invalid conversation type: '${this.get('type')}'`);
} catch (e) {
await message.saveErrors(e);
return null;
}
},
async sendMessage(
@ -1252,100 +1253,102 @@
const expireTimer = this.get('expireTimer');
const recipients = this.getRecipients();
this.queueJob(async () => {
const now = Date.now();
const now = Date.now();
window.log.info(
'Sending message to conversation',
this.idForLogging(),
'with timestamp',
now
);
// be sure an empty quote is marked as undefined rather than being empty
// otherwise upgradeMessageSchema() will return an object with an empty array
// and this.get('quote') will be true, even if there is no quote.
const editedQuote = _.isEmpty(quote) ? undefined : quote;
window.log.info(
'Sending message to conversation',
this.idForLogging(),
'with timestamp',
now
);
// be sure an empty quote is marked as undefined rather than being empty
// otherwise upgradeMessageSchema() will return an object with an empty array
// and this.get('quote') will be true, even if there is no quote.
const editedQuote = _.isEmpty(quote) ? undefined : quote;
const messageWithSchema = await upgradeMessageSchema({
type: 'outgoing',
body,
conversationId: destination,
quote: editedQuote,
preview,
attachments,
sent_at: now,
received_at: now,
expireTimer,
recipients,
});
const messageWithSchema = await upgradeMessageSchema({
type: 'outgoing',
body,
conversationId: destination,
quote: editedQuote,
preview,
attachments,
sent_at: now,
received_at: now,
expireTimer,
recipients,
});
if (this.isPublic()) {
// Public chats require this data to detect duplicates
messageWithSchema.source = textsecure.storage.user.getNumber();
messageWithSchema.sourceDevice = 1;
} else {
messageWithSchema.destination = destination;
}
if (this.isPublic()) {
// Public chats require this data to detect duplicates
messageWithSchema.source = textsecure.storage.user.getNumber();
messageWithSchema.sourceDevice = 1;
} else {
messageWithSchema.destination = destination;
}
const { sessionRestoration = false } = otherOptions;
const { sessionRestoration = false } = otherOptions;
const attributes = {
...messageWithSchema,
groupInvitation,
sessionRestoration,
id: window.getGuid(),
};
const attributes = {
...messageWithSchema,
groupInvitation,
sessionRestoration,
id: window.getGuid(),
};
const model = this.addSingleMessage(attributes);
const message = MessageController.register(model.id, model);
const model = this.addSingleMessage(attributes);
const message = MessageController.register(model.id, model);
await message.commit(true);
await message.commit(true);
if (this.isPrivate()) {
message.set({ destination });
}
if (this.isPublic()) {
message.setServerTimestamp(new Date().getTime());
}
if (this.isPrivate()) {
message.set({ destination });
}
if (this.isPublic()) {
message.setServerTimestamp(new Date().getTime());
}
const id = await message.commit();
message.set({ id });
const id = await message.commit();
message.set({ id });
window.Whisper.events.trigger('messageAdded', {
conversationKey: this.id,
messageModel: message,
});
window.Whisper.events.trigger('messageAdded', {
conversationKey: this.id,
messageModel: message,
});
this.set({
lastMessage: model.getNotificationText(),
lastMessageStatus: 'sending',
active_at: now,
timestamp: now,
isArchived: false,
});
await this.commit();
this.set({
lastMessage: model.getNotificationText(),
lastMessageStatus: 'sending',
active_at: now,
timestamp: now,
isArchived: false,
});
await this.commit();
// We're offline!
if (!textsecure.messaging) {
let errors;
if (this.contactCollection.length) {
errors = this.contactCollection.map(contact => {
const error = new Error('Network is not available');
error.name = 'SendMessageNetworkError';
error.number = contact.id;
return error;
});
} else {
// We're offline!
if (!textsecure.messaging) {
let errors;
if (this.contactCollection.length) {
errors = this.contactCollection.map(contact => {
const error = new Error('Network is not available');
error.name = 'SendMessageNetworkError';
error.number = this.id;
errors = [error];
}
await message.saveErrors(errors);
return null;
error.number = contact.id;
return error;
});
} else {
const error = new Error('Network is not available');
error.name = 'SendMessageNetworkError';
error.number = this.id;
errors = [error];
}
void this.sendMessageJob(message);
await message.saveErrors(errors);
return null;
}
this.queueJob(async () => {
await this.sendMessageJob(message);
});
return null;
},
async updateAvatarOnPublicChat({ url, profileKey }) {

@ -1723,122 +1723,126 @@ class LokiPublicChannelAPI {
}
const pubKey = adnMessage.user.username;
try {
const messengerData = await this.getMessengerData(adnMessage);
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,
avatar,
profileKey,
} = messengerData;
if (!timestamp) {
return false; // Invalid message
}
const messengerData = await this.getMessengerData(adnMessage);
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,
avatar,
profileKey,
} = messengerData;
if (!timestamp) {
return false; // Invalid message
}
// Duplicate check
const isDuplicate = (message, testedMessage) =>
dataMessage.isDuplicate(
message,
testedMessage,
testedMessage.user.username
);
// Filter out any messages that we got previously
if (this.lastMessagesCache.some(m => isDuplicate(m, adnMessage))) {
return false; // Duplicate message
}
// Duplicate check
const isDuplicate = (message, testedMessage) =>
dataMessage.isDuplicate(
message,
testedMessage,
testedMessage.user.username
);
// Filter out any messages that we got previously
if (this.lastMessagesCache.some(m => isDuplicate(m, adnMessage))) {
return false; // Duplicate message
}
// FIXME: maybe move after the de-multidev-decode
// Add the message to the lastMessage cache and keep the last 5 recent messages
this.lastMessagesCache = [
...this.lastMessagesCache,
{
attributes: {
source: pubKey,
body: adnMessage.text,
sent_at: timestamp,
// FIXME: maybe move after the de-multidev-decode
// Add the message to the lastMessage cache and keep the last 5 recent messages
this.lastMessagesCache = [
...this.lastMessagesCache,
{
attributes: {
source: pubKey,
body: adnMessage.text,
sent_at: timestamp,
},
},
},
].splice(-5);
].splice(-5);
const from = adnMessage.user.name || 'Anonymous'; // profileName
const from = adnMessage.user.name || 'Anonymous'; // profileName
// if us
if (pubKey === ourNumberProfile || pubKey === ourNumberDevice) {
// update the last name we saw from ourself
lastProfileName = from;
}
// if us
if (pubKey === ourNumberProfile || pubKey === ourNumberDevice) {
// update the last name we saw from ourself
lastProfileName = from;
}
// track sources for multidevice support
// sort it by home server
let homeServer = window.getDefaultFileServer();
if (adnMessage.user && adnMessage.user.annotations.length) {
const homeNotes = adnMessage.user.annotations.filter(
note => note.type === HOMESERVER_USER_ANNOTATION_TYPE
);
// FIXME: this annotation should probably be signed and verified...
homeServer = homeNotes.reduce(
(curVal, note) => (note.value ? note.value : curVal),
homeServer
);
}
if (homeServerPubKeys[homeServer] === undefined) {
homeServerPubKeys[homeServer] = [];
}
if (homeServerPubKeys[homeServer].indexOf(`@${pubKey}`) === -1) {
homeServerPubKeys[homeServer].push(`@${pubKey}`);
}
// track sources for multidevice support
// sort it by home server
let homeServer = window.getDefaultFileServer();
if (adnMessage.user && adnMessage.user.annotations.length) {
const homeNotes = adnMessage.user.annotations.filter(
note => note.type === HOMESERVER_USER_ANNOTATION_TYPE
);
// FIXME: this annotation should probably be signed and verified...
homeServer = homeNotes.reduce(
(curVal, note) => (note.value ? note.value : curVal),
homeServer
);
}
if (homeServerPubKeys[homeServer] === undefined) {
homeServerPubKeys[homeServer] = [];
}
if (homeServerPubKeys[homeServer].indexOf(`@${pubKey}`) === -1) {
homeServerPubKeys[homeServer].push(`@${pubKey}`);
}
// generate signal message object
const messageData = {
serverId: adnMessage.id,
clientVerified: true,
isSessionRequest: false,
source: pubKey,
sourceDevice: 1,
timestamp, // sender timestamp
serverTimestamp, // server created_at, used to order messages
receivedAt,
isPublic: true,
message: {
body:
adnMessage.text === timestamp.toString() ? '' : adnMessage.text,
attachments,
group: {
id: this.conversationId,
type: textsecure.protobuf.GroupContext.Type.DELIVER,
// generate signal message object
const messageData = {
serverId: adnMessage.id,
clientVerified: true,
isSessionRequest: false,
source: pubKey,
sourceDevice: 1,
timestamp, // sender timestamp
serverTimestamp, // server created_at, used to order messages
receivedAt,
isPublic: true,
message: {
body:
adnMessage.text === timestamp.toString() ? '' : adnMessage.text,
attachments,
group: {
id: this.conversationId,
type: textsecure.protobuf.GroupContext.Type.DELIVER,
},
flags: 0,
expireTimer: 0,
profileKey,
timestamp,
received_at: receivedAt,
sent_at: timestamp, // sender timestamp inner
quote,
contact: [],
preview,
profile: {
displayName: from,
avatar,
},
},
flags: 0,
expireTimer: 0,
profileKey,
timestamp,
received_at: receivedAt,
sent_at: timestamp, // sender timestamp inner
quote,
contact: [],
preview,
profile: {
displayName: from,
avatar,
},
},
};
receivedAt += 1; // Ensure different arrival times
// now process any user meta data updates
// - update their conversation with a potentially new avatar
return messageData;
};
receivedAt += 1; // Ensure different arrival times
// now process any user meta data updates
// - update their conversation with a potentially new avatar
return messageData;
} catch (e) {
window.log.error('pollOnceForMessages: caught error:', e);
return false;
}
})
);

Loading…
Cancel
Save