Typing Indicators

This commit is contained in:
Scott Nonnenberg 2018-11-14 11:10:32 -08:00
parent 99252702e1
commit 79a861a870
23 changed files with 906 additions and 121 deletions

View file

@ -935,6 +935,8 @@ MessageReceiver.prototype.extend({
return this.handleCallMessage(envelope, content.callMessage);
} else if (content.receiptMessage) {
return this.handleReceiptMessage(envelope, content.receiptMessage);
} else if (content.typingMessage) {
return this.handleTypingMessage(envelope, content.typingMessage);
}
this.removeFromCache(envelope);
throw new Error('Unsupported content message');
@ -974,6 +976,43 @@ MessageReceiver.prototype.extend({
}
return Promise.all(results);
},
handleTypingMessage(envelope, typingMessage) {
const ev = new Event('typing');
this.removeFromCache(envelope);
if (envelope.timestamp && typingMessage.timestamp) {
const envelopeTimestamp = envelope.timestamp.toNumber();
const typingTimestamp = typingMessage.timestamp.toNumber();
if (typingTimestamp !== envelopeTimestamp) {
window.log.warn(
`Typing message envelope timestamp (${envelopeTimestamp}) did not match typing timestamp (${typingTimestamp})`
);
return null;
}
}
ev.sender = envelope.source;
ev.senderDevice = envelope.sourceDevice;
ev.typing = {
typingMessage,
timestamp: typingMessage.timestamp
? typingMessage.timestamp.toNumber()
: Date.now(),
groupId: typingMessage.groupId
? typingMessage.groupId.toString('binary')
: null,
started:
typingMessage.action ===
textsecure.protobuf.TypingMessage.Action.STARTED,
stopped:
typingMessage.action ===
textsecure.protobuf.TypingMessage.Action.STOPPED,
};
return this.dispatchEvent(ev);
},
handleNullMessage(envelope) {
window.log.info('null message from', this.getEnvelopeId(envelope));
this.removeFromCache(envelope);

View file

@ -30,9 +30,10 @@ function OutgoingMessage(
this.failoverNumbers = [];
this.unidentifiedDeliveries = [];
const { numberInfo, senderCertificate } = options;
const { numberInfo, senderCertificate, online } = options;
this.numberInfo = numberInfo;
this.senderCertificate = senderCertificate;
this.online = online;
}
OutgoingMessage.prototype = {
@ -192,6 +193,7 @@ OutgoingMessage.prototype = {
jsonData,
timestamp,
this.silent,
this.online,
{ accessKey }
);
} else {
@ -199,7 +201,8 @@ OutgoingMessage.prototype = {
number,
jsonData,
timestamp,
this.silent
this.silent,
this.online
);
}

View file

@ -316,10 +316,31 @@ MessageSender.prototype = {
});
},
sendMessageProtoAndWait(timestamp, numbers, message, silent, options = {}) {
return new Promise((resolve, reject) => {
const callback = result => {
if (result && result.errors && result.errors.length > 0) {
return reject(result);
}
return resolve(result);
};
this.sendMessageProto(
timestamp,
numbers,
message,
callback,
silent,
options
);
});
},
sendIndividualProto(number, proto, timestamp, silent, options = {}) {
return new Promise((resolve, reject) => {
const callback = res => {
if (res.errors.length > 0) {
if (res && res.errors && res.errors.length > 0) {
reject(res);
} else {
resolve(res);
@ -447,6 +468,7 @@ MessageSender.prototype = {
return Promise.resolve();
},
sendRequestGroupSyncMessage(options) {
const myNumber = textsecure.storage.user.getNumber();
const myDevice = textsecure.storage.user.getDeviceId();
@ -494,6 +516,55 @@ MessageSender.prototype = {
return Promise.resolve();
},
async sendTypingMessage(options = {}, sendOptions = {}) {
const ACTION_ENUM = textsecure.protobuf.TypingMessage.Action;
const { recipientId, groupId, isTyping, timestamp } = options;
// We don't want to send typing messages to our other devices, but we will
// in the group case.
const myNumber = textsecure.storage.user.getNumber();
if (recipientId && myNumber === recipientId) {
return null;
}
if (!recipientId && !groupId) {
throw new Error('Need to provide either recipientId or groupId!');
}
const recipients = groupId
? await textsecure.storage.groups.getNumbers(groupId)
: [recipientId];
const groupIdBuffer = groupId
? window.Signal.Crypto.fromEncodedBinaryToArrayBuffer(groupId)
: null;
const action = isTyping ? ACTION_ENUM.STARTED : ACTION_ENUM.STOPPED;
const finalTimestamp = timestamp || Date.now();
const typingMessage = new textsecure.protobuf.TypingMessage();
typingMessage.groupId = groupIdBuffer;
typingMessage.action = action;
typingMessage.timestamp = finalTimestamp;
const contentMessage = new textsecure.protobuf.Content();
contentMessage.typingMessage = typingMessage;
const silent = true;
const online = true;
return this.sendMessageProtoAndWait(
finalTimestamp,
recipients,
contentMessage,
silent,
{
...sendOptions,
online,
}
);
},
sendDeliveryReceipt(recipientId, timestamp, options) {
const myNumber = textsecure.storage.user.getNumber();
const myDevice = textsecure.storage.user.getDeviceId();
@ -517,6 +588,7 @@ MessageSender.prototype = {
options
);
},
sendReadReceipts(sender, timestamps, options) {
const receiptMessage = new textsecure.protobuf.ReceiptMessage();
receiptMessage.type = textsecure.protobuf.ReceiptMessage.Type.READ;
@ -971,6 +1043,7 @@ textsecure.MessageSender = function MessageSenderWrapper(
this.sendMessage = sender.sendMessage.bind(sender);
this.resetSession = sender.resetSession.bind(sender);
this.sendMessageToGroup = sender.sendMessageToGroup.bind(sender);
this.sendTypingMessage = sender.sendTypingMessage.bind(sender);
this.createGroup = sender.createGroup.bind(sender);
this.updateGroup = sender.updateGroup.bind(sender);
this.addNumberToGroup = sender.addNumberToGroup.bind(sender);