1 | "use strict";
|
2 | Object.defineProperty(exports, "__esModule", { value: true });
|
3 | const tslib_1 = require("tslib");
|
4 | const fs_1 = tslib_1.__importDefault(require("fs"));
|
5 | const path_1 = tslib_1.__importDefault(require("path"));
|
6 | const FacebookDeviceId_1 = tslib_1.__importDefault(require("./FacebookDeviceId"));
|
7 | const HttpApi_1 = tslib_1.__importDefault(require("./http/HttpApi"));
|
8 | const MqttApi_1 = tslib_1.__importDefault(require("./mqtt/MqttApi"));
|
9 | const Thread_1 = require("./types/Thread");
|
10 | const User_1 = require("./types/User");
|
11 | const debug_1 = tslib_1.__importDefault(require("debug"));
|
12 | const Message_1 = require("./types/Message");
|
13 | const parseDeltaMessage_1 = tslib_1.__importDefault(require("./types/message/parseDeltaMessage"));
|
14 | const parseDeltaEvent_1 = tslib_1.__importDefault(require("./types/events/parseDeltaEvent"));
|
15 | const events_1 = tslib_1.__importDefault(require("events"));
|
16 | const Errors_1 = require("./types/Errors");
|
17 | const debugLog = debug_1.default('fblib');
|
18 |
|
19 |
|
20 |
|
21 |
|
22 | class Client extends events_1.default {
|
23 | constructor(options = { selfListen: false, session: null }) {
|
24 | super();
|
25 | this.seqId = '';
|
26 | this.loggedIn = false;
|
27 | this.getThreadList = (count) => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
28 | const threads = yield this.httpApi.threadListQuery(count);
|
29 | return threads.viewer.message_threads.nodes.map(Thread_1.parseThread);
|
30 | });
|
31 | this.mqttApi = new MqttApi_1.default();
|
32 | this.httpApi = new HttpApi_1.default();
|
33 | let session = options.session;
|
34 | if (!session) {
|
35 | session = { tokens: null, deviceId: null };
|
36 | }
|
37 | if (!session.deviceId) {
|
38 | const deviceId = FacebookDeviceId_1.default();
|
39 | session.deviceId = deviceId;
|
40 | this.httpApi.deviceId = deviceId.deviceId;
|
41 | }
|
42 | if (session.tokens) {
|
43 | this.httpApi.token = session.tokens.access_token;
|
44 | }
|
45 | this.session = session;
|
46 | }
|
47 | login(email, password) {
|
48 | return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
49 |
|
50 | if (this.loggedIn)
|
51 | throw new Error('Already logged in!');
|
52 | if (!email || typeof email !== 'string' || !email.trim() ||
|
53 | !password || typeof password !== 'string' || !password.trim())
|
54 | throw new Error('Wrong username/password!');
|
55 | yield this.doLogin(email, password);
|
56 | this.loggedIn = true;
|
57 | });
|
58 | }
|
59 | doLogin(login, password) {
|
60 | return new Promise((resolve, reject) => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
61 | if (!this.session.tokens) {
|
62 | let tokens;
|
63 | try {
|
64 | tokens = yield this.httpApi.auth(login, password);
|
65 | }
|
66 | catch (err) {
|
67 | return reject(err);
|
68 | }
|
69 | this.httpApi.token = tokens.access_token;
|
70 | this.session.tokens = tokens;
|
71 | }
|
72 | this.mqttApi.on('publish', (publish) => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
73 | debugLog(publish.topic);
|
74 | if (publish.topic === '/send_message_response') {
|
75 | const response = JSON.parse(publish.data.toString('utf8'));
|
76 | debugLog(response);
|
77 | this.mqttApi.emit('sentMessage:' + response.msgid, response);
|
78 | }
|
79 | if (publish.topic === '/t_ms')
|
80 | this.handleMS(publish.data.toString('utf8'));
|
81 | }));
|
82 | this.mqttApi.on('connected', () => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
83 | let viewer;
|
84 | try {
|
85 | ({ viewer } = yield this.httpApi.querySeqId());
|
86 | }
|
87 | catch (err) {
|
88 | return reject(err);
|
89 | }
|
90 | const seqId = viewer.message_threads.sync_sequence_id;
|
91 | this.seqId = seqId;
|
92 | resolve();
|
93 | if (!this.session.tokens.syncToken) {
|
94 | yield this.createQueue(seqId);
|
95 | return;
|
96 | }
|
97 | yield this.createQueue(seqId);
|
98 | }));
|
99 | try {
|
100 | yield this.mqttApi.connect(this.session.tokens, this.session.deviceId);
|
101 | }
|
102 | catch (err) {
|
103 | return reject(err);
|
104 | }
|
105 | }));
|
106 | }
|
107 | getSession() {
|
108 | return this.session;
|
109 | }
|
110 | sendMessage(threadId, message) {
|
111 | return this.mqttApi.sendMessage(threadId, message);
|
112 | }
|
113 | sendAttachmentFile(threadId, attachmentPath, extension) {
|
114 | if (!fs_1.default.existsSync(attachmentPath))
|
115 | throw new Errors_1.AttachmentNotFoundError(attachmentPath);
|
116 | const stream = fs_1.default.createReadStream(attachmentPath);
|
117 | if (!extension)
|
118 | extension = path_1.default.parse(attachmentPath).ext;
|
119 | const length = fs_1.default.statSync(attachmentPath).size.toString();
|
120 | return this.httpApi.sendImage(stream, extension, this.session.tokens.uid, threadId, length);
|
121 | }
|
122 | sendAttachmentStream(threadId, extension, attachment) {
|
123 | return this.httpApi.sendImage(attachment, extension, this.session.tokens.uid, threadId);
|
124 | }
|
125 | getAttachmentURL(messageId, attachmentId) {
|
126 | return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
127 | const attachment = yield this.httpApi.getAttachment(messageId, attachmentId);
|
128 | if (!attachment.redirect_uri)
|
129 | throw new Errors_1.AttachmentURLMissingError(attachment);
|
130 | return attachment.redirect_uri;
|
131 | });
|
132 | }
|
133 | getAttachmentInfo(messageId, attachmentId) {
|
134 | return this.httpApi.getAttachment(messageId, attachmentId);
|
135 | }
|
136 | getStickerURL(stickerId) {
|
137 | return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
138 | const sticker = yield this.httpApi.getSticker(stickerId);
|
139 | return sticker[stickerId.toString()].thread_image.uri;
|
140 | });
|
141 | }
|
142 | getThreadInfo(threadId) {
|
143 | return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
144 | const res = yield this.httpApi.threadQuery(threadId);
|
145 | const thread = res[threadId];
|
146 | if (!thread)
|
147 | return null;
|
148 | return Thread_1.parseThread(thread);
|
149 | });
|
150 | }
|
151 | getUserInfo(userId) {
|
152 | return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
153 | const res = yield this.httpApi.userQuery(userId);
|
154 | const user = res[userId];
|
155 | if (!user)
|
156 | return null;
|
157 | return User_1.parseUser(user);
|
158 | });
|
159 | }
|
160 | getMessages(threadId, count) {
|
161 | return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
162 | const res = yield this.httpApi.threadMessagesQuery(threadId, count);
|
163 | const thread = res[threadId];
|
164 | if (!thread)
|
165 | return null;
|
166 | return thread.messages.nodes.map(message => Message_1.parseThreadMessage(threadId, message));
|
167 | });
|
168 | }
|
169 | createQueue(seqId) {
|
170 | return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
171 | const obj = {
|
172 | delta_batch_size: 125,
|
173 | max_deltas_able_to_process: 1250,
|
174 | sync_api_version: 3,
|
175 | encoding: 'JSON',
|
176 | initial_titan_sequence_id: seqId,
|
177 | device_id: this.session.deviceId.deviceId,
|
178 | entity_fbid: this.session.tokens.uid,
|
179 | queue_params: {
|
180 | buzz_on_deltas_enabled: 'false',
|
181 | graphql_query_hashes: {
|
182 | xma_query_id: '10153919431161729'
|
183 | },
|
184 | graphql_query_params: {
|
185 | '10153919431161729': {
|
186 | xma_id: '<ID>'
|
187 | }
|
188 | }
|
189 | }
|
190 | };
|
191 | yield this.mqttApi.sendPublish('/messenger_sync_create_queue', JSON.stringify(obj));
|
192 | });
|
193 | }
|
194 | connectQueue(seqId) {
|
195 | return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
196 | const obj = {
|
197 | delta_batch_size: 125,
|
198 | max_deltas_able_to_process: 1250,
|
199 | sync_api_version: 3,
|
200 | encoding: 'JSON',
|
201 | last_seq_id: seqId,
|
202 | sync_token: this.session.tokens.syncToken
|
203 | };
|
204 | yield this.mqttApi.sendPublish('/messenger_sync_get_diffs', JSON.stringify(obj));
|
205 | });
|
206 | }
|
207 | handleMS(ms) {
|
208 | return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
209 | let data;
|
210 | try {
|
211 | data = JSON.parse(ms.replace('\u0000', ''));
|
212 | }
|
213 | catch (err) {
|
214 | console.error('Error while parsing the following message:');
|
215 | console.error(ms);
|
216 | return;
|
217 | }
|
218 |
|
219 | if (data.syncToken) {
|
220 | this.session.tokens.syncToken = data.syncToken;
|
221 | yield this.connectQueue(this.seqId);
|
222 | return;
|
223 | }
|
224 | if (!data.deltas || !Array.isArray(data.deltas))
|
225 | return;
|
226 | data.deltas.forEach(delta => {
|
227 | debugLog(delta);
|
228 | this.handleMessage(delta);
|
229 | });
|
230 | });
|
231 | }
|
232 | handleMessage(event) {
|
233 | if (event.deltaNewMessage) {
|
234 | const message = parseDeltaMessage_1.default(event.deltaNewMessage);
|
235 | if (!message || message.authorId === this.session.tokens.uid && !this.options.selfListen)
|
236 | return;
|
237 | this.emit('message', message);
|
238 | }
|
239 | const deltaEvent = parseDeltaEvent_1.default(event);
|
240 | if (!deltaEvent)
|
241 | return;
|
242 | this.emit('event', deltaEvent);
|
243 |
|
244 | this.emit(deltaEvent.type, deltaEvent.event);
|
245 | }
|
246 | }
|
247 | exports.default = Client;
|
248 |
|
\ | No newline at end of file |