diff --git a/client.js b/client.js index 162ca7b..43fb9c9 100644 --- a/client.js +++ b/client.js @@ -48,6 +48,7 @@ class Client extends EventEmitter { this.emit('friendsList', friends); } }); + debug('current user id', this.userId); let stop = api.listen((err, data) => { if ( err ) { @@ -68,9 +69,14 @@ class Client extends EventEmitter { } else { this.emit('typing:stop', data.threadId, data.from); } - } else if ( data.type === 'message' && data.messageID !== this.lastMsgId) { + } else if ((data.type === 'message' || data.type === 'message_reply') && data.messageID !== this.lastMsgId) { this.lastMsgId = data.messageID; this.emit('message', data); + } else if (data.type === 'event') { + this.lastMsgId = data.messageID; + this.emit('event', data); + } else { + debug("Unknown type received: ", data.type); } }); @@ -86,6 +92,7 @@ class Client extends EventEmitter { return this; }); } + getUserInfoById(userId) { const getUserInfo = Promise.promisify(this.api.getUserInfo); return getUserInfo([userId]).then(res=>{ @@ -94,6 +101,7 @@ class Client extends EventEmitter { return userInfo; }); } + getThreadName(threadInfo) { // Takes threadInfo as an argument and returns a Promise that resolves to // an array with at least the other participant's name on the name @@ -128,6 +136,7 @@ class Client extends EventEmitter { return Promise.resolve({name: threadInfo['name']}); } } + getThreadInfo(threadId) { const getThreadInfo = Promise.promisify(this.api.getThreadInfo); // I need threadInfo to be in this scope so that it can be called from inside both of the chained .than functions @@ -141,6 +150,7 @@ class Client extends EventEmitter { return threadInfo; }); } + sendMessage(threadId, msg) { const sendMessage = Promise.promisify(this.api.sendMessage); return sendMessage(msg, threadId).then(res=>{ @@ -148,6 +158,7 @@ class Client extends EventEmitter { return res; }); } + markAsRead(threadId) { return new Promise((resolve, reject) => { this.api.markAsRead(threadId, (err) => { diff --git a/index.js b/index.js index 2a42936..00df1d1 100644 --- a/index.js +++ b/index.js @@ -25,23 +25,54 @@ class App extends MatrixPuppetBridgeBase { initThirdPartyClient() { this.threadInfo = {}; this.thirdPartyClient = new FacebookClient(); - this.thirdPartyClient.on('message', (data) => { - const { senderID, body, threadID, isGroup, attachments } = data; + + this.thirdPartyClient.on('event', async (data) => { + const { author, threadID, logMessageBody } = data; + const isMe = (author === this.thirdPartyClient.userId); + debug("ISME? " + isMe); + debug('Event has log'); + + let payload = { + roomId: threadID, + senderId: isMe ? undefined : author, + text: logMessageBody + }; + + debug(payload); + this.handleThirdPartyRoomMessage(payload); + }); + + this.thirdPartyClient.on('message', async (data) => { + const { senderID, body, threadID, isGroup, attachments, messageReply } = data; const isMe = senderID === this.thirdPartyClient.userId; debug("ISME? " + isMe); this.threadInfo[threadID] = { isGroup }; - var payload; + let payload; + if (body) { debug('Message has body'); - payload = { - roomId: threadID, - // senderName: senderID, - senderId: isMe ? undefined : senderID, - text: body - }; + + if (messageReply) { + debug('Message has a reply'); + + let userData = await this.getThirdPartyUserDataById(messageReply.senderID); + let replyHtml = `
${userData.senderName}
${messageReply.body}
${body}`; + + payload = { + roomId: threadID, + senderId: isMe ? undefined : senderID, + html: replyHtml + }; + } else { + payload = { + roomId: threadID, + senderId: isMe ? undefined : senderID, + text: body + }; + } + debug(payload); - // Don't return yet -- there may be attachments, too. this.handleThirdPartyRoomMessage(payload); } @@ -172,13 +203,23 @@ class App extends MatrixPuppetBridgeBase { getThirdPartyUserDataById(id) { return this.thirdPartyClient.getUserInfoById(id).then(userInfo=>{ debug('got user data', userInfo); - // TODO use userInfo.thumbSrc as the avatar - return { senderName: userInfo.name }; + return { + senderName: userInfo.name, + senderAvatar: userInfo.thumbSrc + }; }); } + getThirdPartyRoomDataById(threadId) { debug('getting third party room data by thread id', threadId); - let label = this.threadInfo[threadId].isGroup ? "Group" : "Friend"; + + let label; + if (threadId in this.threadInfo) { + label = this.threadInfo[threadId].isGroup ? "Group" : "Friend"; + } else { + label = "Conversation"; + } + return this.thirdPartyClient.getThreadInfo(threadId).then(data=>{ let roomData = { name: data.name ? data.name : '', @@ -188,6 +229,7 @@ class App extends MatrixPuppetBridgeBase { return roomData; }); } + sendMessageAsPuppetToThirdPartyRoomWithId(id, text) { const url = text.match(/(https?:\/\/[^\s]+)/g); if (url) { @@ -199,6 +241,14 @@ class App extends MatrixPuppetBridgeBase { return this.thirdPartyClient.sendMessage(id, text); } } + + sendReplyMessageAsPuppetToThirdPartyRoomWithId(id, text, replyText) { + return this.thirdPartyClient.sendMessage(id, { + body: text, + reply: replyText, + }); + } + sendImageMessageAsPuppetToThirdPartyRoomWithId(id, data) { return download.getTempfile( data.url, { tagFilename: true }).then(({path}) => { let imgstream = fs.createReadStream(path); @@ -208,6 +258,7 @@ class App extends MatrixPuppetBridgeBase { }); }); } + sendFileMessageAsPuppetToThirdPartyRoomWithId(id, data) { return download.getTempfile( data.url, { tagFilename: true }).then(({path}) => { let imgstream = fs.createReadStream(path); diff --git a/package.json b/package.json index 5035ce0..9a58956 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "dependencies": { "bluebird": "^3.5.5", "debug": "^2.6.0", - "facebook-chat-api": "^1.5.1", + "facebook-chat-api": "github:Schmavery/facebook-chat-api", "matrix-puppet-bridge": "github:matrix-hacks/matrix-puppet-bridge#master" }, "devDependencies": {