@jikey/fcazero
Version:
Facebook Messenger bot, and is one of the most advanced next-generation Facebook Chat API (FCA)
2 lines (1 loc) • 6.12 kB
JavaScript
import O from"mqtt";import v,{createWebSocketStream as A}from"ws";import{ProxyAgent as R}from"proxy-agent";import o from"../utils/logger.js";import{Constants as w}from"../utils/constants.js";import{Clients as q}from"../utils/clients.js";import{Formatters as b}from"../utils/formatters.js";import C from"./core/parseDelta.js";import{MessageEmitter as L}from"./core/messageEmitter.js";class E{constructor(c,f,e){this.defaultFuncs=c;this.api=f;this.ctx=e;this.listenMqtt=async(c,f,e,s)=>{try{o.info("listenMQTT: Creating MQTT client...");const t=e.globalOptions.online,r=e.region,i=Math.floor(Math.random()*Number.MAX_SAFE_INTEGER)+1,y=e.clientID,M=new C(c,f,e,s),g={u:e.userID,s:i,chat_on:t,fg:!0,d:y,ct:"websocket",aid:e.mqttAppID,aids:null,mqtt_sid:"",cp:3,ecp:10,st:[],pm:[],p:null,dc:"",no_auto_fg:!0,php_override:"",gas:null,pack:[],a:e.globalOptions.userAgent},d=e.jar.getCookiesSync("https://www.facebook.com").join("; "),m="wss://edge-chat.messenger.com/chat",p=r?`${m}?region=${r.toLowerCase()}&sid=${i}&cid=${y}`:`${m}?sid=${i}&cid=${y}`;o.info(`listenMQTT: Using host ${p}`);const T={clientId:g.d??w.getGUID(),protocolId:"MQIsdp",protocolVersion:3,username:JSON.stringify(g),clean:!0,wsOptions:{headers:{cookie:d,origin:"https://www.messenger.com","user-agent":g.a,referer:"https://www.messenger.com/",host:new URL(p).hostname},origin:"https://www.messenger.com",protocolVersion:13},keepalive:10,reschedulePings:!0,connectTimeout:6e4,reconnectPeriod:1e3};e.globalOptions.proxy&&(T.wsOptions.agent=new R({getProxyForUrl:()=>e.globalOptions.proxy}));const D=()=>{const l=new v(p,T.wsOptions);return A(l)},a=new O.Client(D,T);e.mqttClient=a,a.on("connect",async()=>{await Promise.all(w.topics.map(u=>a.subscribe(u)));const l={sync_api_version:10,max_deltas_able_to_process:1e3,delta_batch_size:500,encoding:"JSON",entity_fbid:e.userID,initial_titan_sequence_id:e.lastSeqId,device_params:null};a.publish("/foreground_state",JSON.stringify({foreground:t}),{qos:1}),a.publish("/set_client_settings",JSON.stringify({make_user_available_when_in_foreground:!0}),{qos:1}),a.publish("/messenger_sync_create_queue",JSON.stringify(l),{qos:1,retain:!1}),o.info("listenMQTT: Connected to MQTT!")});let I;e.globalOptions.updatePresence&&(I=setInterval(()=>{if(a.connected){const l=w.generatePresence(e.userID??"");a.publish("/orca_presence",JSON.stringify({p:l}),u=>{u&&o.error({err:u},"Failed to send presence update:")})}},5e4));const S=()=>{I&&(clearInterval(I),I=void 0)};a.on("message",async(l,u,N)=>{let Q=Buffer.isBuffer(u)?Buffer.from(u).toString():u,n;try{n=JSON.parse(Q)}catch{n={}}if(n.type==="jewel_requests_add")s(null,{type:"friend_request_received",actorFbId:n.from.toString()??"",timestamp:Date.now().toString()});else if(n.type==="jewel_requests_remove_old")s(null,{type:"friend_request_cancel",actorFbId:n.from.toString(),timestamp:Date.now().toString()});else if(l==="/t_ms"){n.firstDeltaSeqId&&n.syncToken&&(e.lastSeqId=n.firstDeltaSeqId,e.syncToken=n.syncToken),n.lastIssuedSeqId&&(e.lastSeqId=String(parseInt(n.lastIssuedSeqId)));for(const h in n.deltas){const _=n.deltas[h];M.parse({delta:_})}}else if(l==="/thread_typing"||l==="/orca_typing_notifications"){const h={type:"typ",isTyping:!!n.state,from:n.sender_fbid.toString(),threadID:b.formatID((n.thread||n.sender_fbid).toString())};(function(){s(null,h)})()}else if(l==="/orca_presence"&&!e.globalOptions.updatePresence)for(const h in n.list){const _=n.list[h],k={type:"presence",userID:_.u.toString(),timestamp:_.l*1e3,statuses:_.p};(function(){s(null,k)})()}}),a.on("close",()=>{S(),o.info("listenMQTT: MQTT connection closed.")}),a.on("reconnect",()=>{o.info("listenMQTT: Reconnecting MQTT client...")}),a.on("end",()=>{S(),o.info("listenMQTT: MQTT connection ended.")}),a.on("error",l=>{S(),a.end(),o.error({err:l},"listenMQTT: MQTT connection error:"),e.globalOptions.autoReconnect?this.listenMqtt(c,f,e,s):q.checkLiveCookie(e,c).then(()=>{s(new Error("Connection refused: Server unavailable"),null)}).catch(()=>{const u=new Error("Maybe your account is blocked by facebook, please login and check at https://facebook.com");u.type="account_inactive",s(u,null)})})}catch(t){o.error({err:t},"listenMqtt"),s&&typeof s=="function"&&s(t instanceof Error?t:new Error(String(t)))}}}async getSeqID(c,f,e,s,t){try{const r={queries:JSON.stringify({o0:{doc_id:"3336396659757871",query_params:{limit:1,before:null,tags:["INBOX"],includeDeliveryReceipts:!1,includeSeqID:!0}}})},i=await c.post("https://www.facebook.com/api/graphqlbatch/",e.jar,r).then(q.parseAndCheckLogin(e,c));if(w.getType(i)!="Array"||i&&i.error==1357001)throw i;if(Array.isArray(i)&&i[0]?.o0?.data?.viewer?.message_threads?.sync_sequence_id)e.lastSeqId=i[0].o0.data.viewer.message_threads.sync_sequence_id;else throw new Error("Unexpected response format when fetching sequence ID");return t(c,f,e,s)}catch(r){return o.error({err:r},"getSeqID"),s(r instanceof Error?r:new Error(String(r)))}}async scheduleReconnect(c,f){o.info("listenMQTT: Scheduling reconnect in 20 minutes...");let e=setTimeout(()=>{o.info("listenMQTT: Reconnecting MQTT with new clientID..."),f.mqttClient&&c.hardRestart()},1e3*60*20);c.on("stop",()=>{e&&(clearTimeout(e),e=null)})}call(c,f){return new Promise((e,s)=>{try{const{ctx:t,api:r,defaultFuncs:i,listenMqtt:y,getSeqID:M}=this;let g=(m,p)=>{if(m)return d.emit("error",m);(p.type==="message"||p.type==="message_reply")&&r.markAsRead.call({threadID:String(p.threadID)},T=>{T&&o.error({err:T},"markAsRead MQTT")}),p&&(d.emit("message",p),f(null,p))};const d=new L(t,y,i,r,g);t.emittery=d,!t.firstListen||!t.lastSeqId?M(i,r,t,g,y):y(i,r,t,g),t.firstListen,t.firstListen=!1,this.scheduleReconnect(d,t),r.stopListeningAsync={call:()=>d.stopListeningAsync()},r.softReconnectAsync={call:()=>d.softReconnect()},r.hardRestartAsync={call:()=>d.hardRestart()},setInterval(()=>{r.refreshConfigRequest.call(null,(m,p)=>{m?o.error({err:m},"Error in refreshConfigRequest"):o.info("refreshConfigRequest: Successfully refreshed config.")})},1e3*60*20),e(d)}catch(t){o.error({err:t},"listenMQTT"),f(t instanceof Error?t:new Error(String(t)),null),s(t)}})}}export{E as default};