lint
parent
3038a8c7d2
commit
2b29b76d66
@ -0,0 +1,209 @@
|
||||
/* 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;
|
Loading…
Reference in New Issue