move pubkey/name out of annotation into user object, read channel meta data from server, throw alert if delete fails, constant name clean up, store timers, Calls refreshModStatus/pollForChannel in cstr

pull/475/head
Ryan Tharp 6 years ago
parent b3e2a5aba8
commit e25ed0aba3

@ -4,8 +4,9 @@ const nodeFetch = require('node-fetch');
const { URL, URLSearchParams } = require('url'); const { URL, URLSearchParams } = require('url');
// Can't be less than 1200 if we have unauth'd requests // Can't be less than 1200 if we have unauth'd requests
const GROUPCHAT_POLL_EVERY = 1500; // 1.5s const PUBLICCHAT_MSG_POLL_EVERY = 1.5 * 1000; // 1.5s
const DELETION_POLL_EVERY = 5000; // 1 second const PUBLICCHAT_CHAN_POLL_EVERY = 20 * 1000; // 20s
const PUBLICCHAT_DELETION_POLL_EVERY = 5 * 1000; // 1 second
// singleton to relay events to libtextsecure/message_receiver // singleton to relay events to libtextsecure/message_receiver
class LokiPublicChatAPI extends EventEmitter { class LokiPublicChatAPI extends EventEmitter {
@ -203,18 +204,20 @@ class LokiPublicChannelAPI {
this.serverAPI = serverAPI; this.serverAPI = serverAPI;
this.channelId = channelId; this.channelId = channelId;
this.baseChannelUrl = `channels/${this.channelId}`; this.baseChannelUrl = `channels/${this.channelId}`;
this.groupName = 'unknown'; this.conversation = ConversationController.get(conversationId);
this.conversationId = conversationId;
this.lastGot = null; this.lastGot = null;
this.stopPolling = false; this.stopPolling = false;
this.modStatus = false; this.modStatus = false;
this.deleteLastId = 1; this.deleteLastId = 1;
this.timers = {};
// end properties // end properties
log.info(`registered LokiPublicChannel ${channelId}`); log.info(`registered LokiPublicChannel ${channelId}`);
// start polling // start polling
this.pollForMessages(); this.pollForMessages();
this.pollForDeletions(); this.pollForDeletions();
this.pollForChannel();
this.refreshModStatus();
} }
// make a request to the server // make a request to the server
@ -290,14 +293,45 @@ class LokiPublicChannelAPI {
// get moderator status // get moderator status
async refreshModStatus() { async refreshModStatus() {
// get moderator status
const res = await this.serverRequest('loki/v1/user_info'); const res = await this.serverRequest('loki/v1/user_info');
// if no problems and we have data // if no problems and we have data
if (!res.err && res.response && res.response.data) { if (!res.err && res.response && res.response.data) {
this.modStatus = res.response.data.moderator_status; this.modStatus = res.response.data.moderator_status;
} }
// if problems, we won't drop moderator status
const conversation = ConversationController.get(this.conversationId); await this.conversation.setModStatus(this.modStatus);
await conversation.setModStatus(this.modStatus);
// get token info
const tokenRes = await this.serverRequest('token');
// if no problems and we have data
if (
!tokenRes.err &&
tokenRes.response &&
tokenRes.response.data &&
tokenRes.response.data.user
) {
// get our profile name and write it to the network
const ourNumber = textsecure.storage.user.getNumber();
const profileConvo = ConversationController.get(ourNumber);
const profileName = profileConvo.getProfileName();
if (tokenRes.response.data.user.name !== profileName) {
if (profileName) {
await this.serverRequest('users/me', {
method: 'PATCH',
objBody: {
name: profileName,
},
});
// no big deal if it fails...
// } else {
// should we update the local from the server?
// guessing no because there will be multiple servers
}
}
}
} }
// delete a message on the server // delete a message on the server
@ -312,8 +346,11 @@ class LokiPublicChannelAPI {
log.info(`deleted ${serverId} on ${this.baseChannelUrl}`); log.info(`deleted ${serverId} on ${this.baseChannelUrl}`);
return true; return true;
} }
// fire an alert
log.warn(`failed to delete ${serverId} on ${this.baseChannelUrl}`); log.warn(`failed to delete ${serverId} on ${this.baseChannelUrl}`);
return false; throw new textsecure.PublicChatError(
'Failed to delete public chat message'
);
} }
// used for sending messages // used for sending messages
@ -326,41 +363,36 @@ class LokiPublicChannelAPI {
// update room details // update room details
async pollForChannel() { async pollForChannel() {
// groupName will be loaded from server const res = await this.serverRequest(`${this.baseChannelUrl}`, {
const url = new URL(this.baseChannelUrl); params: {
let res; include_annotations: 1,
const token = await this.serverAPI.getOrRefreshServerToken(); },
if (!token) { });
log.error('NO TOKEN'); if (!res.err && res.response) {
return { if (
err: 'noToken', res.response.data.annotations &&
}; res.response.data.annotations.length
} ) {
try { res.response.data.annotations.forEach(note => {
// eslint-disable-next-line no-await-in-loop if (note.type === 'net.patter-app.settings') {
const options = { // note.value.description only needed for directory
headers: new Headers({ // this.conversation.setGroupNameAndAvatar(note.value.name,
Authorization: `Bearer ${token}`, // note.value.avatar);
}), if (note.value && note.value.name) {
}; this.conversation.setProfileName(note.value.name);
res = await nodeFetch(url, options || undefined); }
} catch (e) { if (note.value && note.value.avatar) {
log.info(`e ${e}`); this.conversation.setProfileAvatar(note.value.avatar);
return { }
err: e, // else could set a default in case of server problems...
}; }
} });
// eslint-disable-next-line no-await-in-loop }
const response = await res.json();
if (response.meta.code !== 200) {
return {
err: 'statusCode',
response,
};
} }
return { // set up next poll
response, this.timers.channel = setTimeout(() => {
}; this.pollForChannel();
}, PUBLICCHAT_CHAN_POLL_EVERY);
} }
// get moderation actions // get moderation actions
@ -404,9 +436,9 @@ class LokiPublicChannelAPI {
} }
// set up next poll // set up next poll
setTimeout(() => { this.timers.delete = setTimeout(() => {
this.pollForDeletions(); this.pollForDeletions();
}, DELETION_POLL_EVERY); }, PUBLICCHAT_DELETION_POLL_EVERY);
} }
// get channel messages // get channel messages
@ -416,12 +448,11 @@ class LokiPublicChannelAPI {
count: -20, count: -20,
include_deleted: false, include_deleted: false,
}; };
const conversation = ConversationController.get(this.conversationId); if (!this.conversation) {
if (!conversation) {
log.warn('Trying to poll for non-existing public conversation'); log.warn('Trying to poll for non-existing public conversation');
this.lastGot = 0; this.lastGot = 0;
} else if (!this.lastGot) { } else if (!this.lastGot) {
this.lastGot = conversation.getLastRetrievedMessage(); this.lastGot = this.conversation.getLastRetrievedMessage();
} }
params.since_id = this.lastGot; params.since_id = this.lastGot;
const res = await this.serverRequest(`${this.baseChannelUrl}/messages`, { const res = await this.serverRequest(`${this.baseChannelUrl}/messages`, {
@ -432,21 +463,28 @@ class LokiPublicChannelAPI {
let receivedAt = new Date().getTime(); let receivedAt = new Date().getTime();
res.response.data.reverse().forEach(adnMessage => { res.response.data.reverse().forEach(adnMessage => {
let timestamp = new Date(adnMessage.created_at).getTime(); let timestamp = new Date(adnMessage.created_at).getTime();
let from = adnMessage.user.username; // pubKey lives in the username field
let source; let from = adnMessage.user.name;
if (adnMessage.is_deleted) { if (adnMessage.is_deleted) {
return; return;
} }
if (adnMessage.annotations !== []) { if (adnMessage.annotations && adnMessage.annotations.length) {
const noteValue = adnMessage.annotations[0].value; const noteValue = adnMessage.annotations[0].value;
({ from, timestamp, source } = noteValue); ({ timestamp } = noteValue);
// if user doesn't have a name set, fallback to annotation
// pubkeys are already there in v1 (first release)
if (!from) {
({ from } = noteValue);
}
} }
if ( if (
!from || !from ||
!timestamp || !timestamp ||
!source ||
!adnMessage.id || !adnMessage.id ||
!adnMessage.user ||
!adnMessage.user.username ||
!adnMessage.text !adnMessage.text
) { ) {
return; // Invalid message return; // Invalid message
@ -455,7 +493,7 @@ class LokiPublicChannelAPI {
const messageData = { const messageData = {
serverId: adnMessage.id, serverId: adnMessage.id,
friendRequest: false, friendRequest: false,
source, source: adnMessage.user.username,
sourceDevice: 1, sourceDevice: 1,
timestamp, timestamp,
serverTimestamp: timestamp, serverTimestamp: timestamp,
@ -491,12 +529,12 @@ class LokiPublicChannelAPI {
? adnMessage.id ? adnMessage.id
: Math.max(this.lastGot, adnMessage.id); : Math.max(this.lastGot, adnMessage.id);
}); });
conversation.setLastRetrievedMessage(this.lastGot); this.conversation.setLastRetrievedMessage(this.lastGot);
} }
setTimeout(() => { this.timers.message = setTimeout(() => {
this.pollForMessages(); this.pollForMessages();
}, GROUPCHAT_POLL_EVERY); }, PUBLICCHAT_MSG_POLL_EVERY);
} }
// create a message in the channel // create a message in the channel

Loading…
Cancel
Save