You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
session-desktop/js/modules/loki_public_chat_api2.js

210 lines
5.3 KiB
JavaScript

/* global log, textsecure */
const EventEmitter = require('events');
const nodeFetch = require('node-fetch');
const { URL, URLSearchParams } = require('url');
const GROUPCHAT_POLL_EVERY = 1000; // 1 second
// singleton to relay events to libtextsecure/message_receiver
class LokiPublicChatAPI extends EventEmitter {
constructor(ourKey) {
super();
this.ourKey = ourKey;
this.lastGot = {};
this.servers = [];
}
findOrCreateServer(hostport) {
let thisServer = null;
log.info(`LokiPublicChatAPI looking for ${hostport}`);
this.servers.some(server => {
// if we already have this hostport registered
if (server.server === hostport) {
thisServer = server;
return true;
}
return false;
});
if (thisServer === null) {
thisServer = new LokiPublicServerAPI(this, hostport);
this.servers.push(thisServer);
}
return thisServer;
}
}
class LokiPublicServerAPI {
constructor(chatAPI, hostport) {
this.chatAPI = chatAPI;
this.server = hostport;
this.channels = [];
}
findOrCreateChannel(channelId, conversationId) {
let thisChannel = null;
this.channels.forEach(channel => {
if (
channel.channelId === channelId &&
channel.conversationId === conversationId
) {
thisChannel = channel;
}
});
if (thisChannel === null) {
thisChannel = new LokiPublicChannelAPI(this, channelId, conversationId);
this.channels.push(thisChannel);
}
return thisChannel;
}
unregisterChannel(channelId) {
// find it, remove it
// if no channels left, request we deregister server
return channelId || this; // this is just to make eslint happy
}
}
class LokiPublicChannelAPI {
constructor(serverAPI, channelId, conversationId) {
this.serverAPI = serverAPI;
this.channelId = channelId;
this.baseChannelUrl = `${serverAPI.server}/channels/${this.channelId}`;
this.groupName = 'unknown';
this.conversationId = conversationId;
this.lastGot = 0;
log.info(`registered LokiPublicChannel ${channelId}`);
// start polling
this.pollForMessages();
}
async pollForChannel(source, endpoint) {
// groupName will be loaded from server
const url = new URL(this.baseChannelUrl);
/*
const params = {
include_annotations: 1,
};
*/
let res;
let success = true;
try {
res = await nodeFetch(url);
} catch (e) {
success = false;
}
const response = await res.json();
if (response.meta.code !== 200) {
success = false;
}
// update this.groupId
return endpoint || success;
}
async pollForDeletions() {
// let id = 0;
// read all messages from 0 to current
// delete local copies if server state has changed to delete
// run every minute
const url = new URL(this.baseChannelUrl);
/*
const params = {
include_annotations: 1,
};
*/
let res;
let success = true;
try {
res = await nodeFetch(url);
} catch (e) {
success = false;
}
const response = await res.json();
if (response.meta.code !== 200) {
success = false;
}
return success;
}
async pollForMessages() {
const url = new URL(`${this.baseChannelUrl}/messages`);
const params = {
include_annotations: 1,
count: -20,
};
if (this.lastGot) {
params.since_id = this.lastGot;
}
url.search = new URLSearchParams(params);
let res;
let success = true;
try {
res = await nodeFetch(url);
} catch (e) {
success = false;
}
const response = await res.json();
if (response.meta.code !== 200) {
success = false;
}
if (success) {
let receivedAt = new Date().getTime();
response.data.forEach(adnMessage => {
// FIXME: create proper message for this message.DataMessage.body
let timestamp = new Date(adnMessage.created_at).getTime();
let from = adnMessage.user.username;
let source;
if (adnMessage.annotations.length) {
const noteValue = adnMessage.annotations[0].value;
({ from, timestamp, source } = noteValue);
}
const messageData = {
friendRequest: false,
source,
sourceDevice: 1,
timestamp,
serverTimestamp: timestamp,
receivedAt,
isPublic: true,
message: {
body: adnMessage.text,
attachments: [],
group: {
id: this.conversationId,
type: textsecure.protobuf.GroupContext.Type.DELIVER,
},
flags: 0,
expireTimer: 0,
profileKey: null,
timestamp,
received_at: receivedAt,
sent_at: timestamp,
quote: null,
contact: [],
preview: [],
profile: {
displayName: from,
},
},
};
receivedAt += 1; // Ensure different arrival times
this.serverAPI.chatAPI.emit('publicMessage', {
message: messageData,
});
this.lastGot = !this.lastGot
? adnMessage.id
: Math.max(this.lastGot, adnMessage.id);
});
}
setTimeout(() => {
this.pollForMessages();
}, GROUPCHAT_POLL_EVERY);
}
}
module.exports = LokiPublicChatAPI;