wa-automate-socket-client
Version:
Easily connect to remote instances of the EASY API
197 lines (196 loc) • 8.51 kB
JavaScript
;
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SocketClient = void 0;
const eventemitter2_1 = require("eventemitter2");
const socket_io_client_1 = require("socket.io-client");
const uuid_1 = require("uuid");
const MessageCollector_1 = require("./MessageCollector");
/**
* [ALPHA - API will 100% change in the near future. Don't say I didn't warn you.]
*
*
* An easy to use socket implementation that allows users to connect into remote instances of the EASY API.
*
* How to use it:
*
* 1. Make sure you're running an instance of the EASY API and make sure to start it with the `--socket` flag
* ```bash
* > docker run -e PORT=8080 -p 8080:8080 openwa/wa-automate:latest --socket
* ```
* 2. Use this in your code:
*
* ```javascript
* import { SocketClient } from "@open-wa/wa-automate";
*
* SocketClient.connect("http://localhost:8080").then(async client => {
* //now you can use the client similar to how you would use the http express middleware.
*
* //There are two main commands from this client
*
* // 1. client.listen - use this for your listeners
*
* await client.listen("onMessage", message => {
* ...
* })
*
* // 2. client.asj - ask the main host client to get things done
*
* await client.ask("sendText", {
* "to" : "44771234567@c.us",
* "content": "hellow socket"
* })
*
* // or you can send the arguments in order as an array (or tuple, as the cool kids would say)
* await client.ask("sendText", [
* "44771234567@c.us",
* "hellow socket"
* ])
*
* })
* ```
*/
class SocketClient {
constructor(url, apiKey, ev) {
this.listeners = {};
this.url = url;
this.apiKey = apiKey;
const _url = new URL(url);
const _path = _url.pathname.replace(/\/$/, "");
this.socket = (0, socket_io_client_1.io)(_url.origin, {
autoConnect: true,
auth: {
apiKey
},
path: _path ? `${_path}/socket.io/` : undefined
});
if (ev)
this.socket.on("connect", () => {
if (!this.ev)
this.ev = new eventemitter2_1.EventEmitter2({
wildcard: true
});
this.socket.emit("register_ev");
this.socket.onAny((event, value) => this.ev.emit(event, value));
});
this.socket.io.on("reconnect", () => __awaiter(this, void 0, void 0, function* () {
console.log("Reconnected!!");
console.log(Object.keys(this.listeners));
yield Promise.all(Object.keys(this.listeners).map((listener) => __awaiter(this, void 0, void 0, function* () {
yield this.ask(listener);
this.socket.on(listener, (data) => __awaiter(this, void 0, void 0, function* () { return yield Promise.all(Object.entries(this.listeners[listener]).map(([, callback]) => callback(data))); }));
})));
}));
this.socket.io.on("reconnect_attempt", () => console.log("Reconnecting..."));
this.socket.on("disconnect", () => console.log("Disconnected from host!"));
return new Proxy(this, {
get: function get(target, prop) {
const o = Reflect.get(target, prop);
if (o)
return o;
if (prop === 'then') {
return Promise.prototype.then.bind(target);
}
if (prop.startsWith("on")) {
return (callback) => __awaiter(this, void 0, void 0, function* () { return target.listen(prop, callback); });
}
else {
return (...args) => __awaiter(this, void 0, void 0, function* () {
return target.ask(prop, args.length == 1 && typeof args[0] == "object" ? Object.assign({}, args[0]) : [
...args
]);
});
}
}
});
}
/**
* The main way to create the socket baed client.
* @param url URL of the socket server (i.e the EASY API instance address)
* @param apiKey optional api key if set
* @returns SocketClient
*/
static connect(url, apiKey, ev) {
return __awaiter(this, void 0, void 0, function* () {
const client = new this(url, apiKey, ev);
return yield new Promise((resolve, reject) => {
client.socket.on("connect", () => {
console.log("Connected!", client.socket.id);
return resolve(client);
});
client.socket.on("connect_error", reject);
});
});
}
createMessageCollector(c, filter, options) {
var _a, _b, _c;
return __awaiter(this, void 0, void 0, function* () {
const chatId = (((_b = (_a = c) === null || _a === void 0 ? void 0 : _a.chat) === null || _b === void 0 ? void 0 : _b.id) || ((_c = c) === null || _c === void 0 ? void 0 : _c.id) || c);
return new MessageCollector_1.MessageCollector(yield this.ask('getSessionId'), yield this.ask('getInstanceId'), chatId, filter, options, this.ev);
});
}
//awaiting tuple label getter to reimplement this
// // | {
// [K in keyof Parameters<Pick<Client,M>[ M ]>]: Parameters<Pick<Client,M>[ M ]>[K]
// }
ask(method, args) {
return __awaiter(this, void 0, void 0, function* () {
// if (!this.socket.connected) return new Error("Socket not connected!")
return new Promise((resolve, reject) => {
if (typeof args !== "object" && !Array.isArray(args) && (typeof args === "string" || typeof args === "number"))
args = [args];
try {
// @ts-ignore
this.socket.emit(method, {
args
}, resolve);
}
catch (error) {
reject(error);
}
});
});
}
/**
* Set a callback on a simple listener
* @param listener The listener name (e.g onMessage, onAnyMessage, etc.)
* @param callback The callback you need to run on the selected listener
* @returns The id of the callback
*/
listen(listener, callback) {
return __awaiter(this, void 0, void 0, function* () {
// if (!this.socket.connected) throw new Error("Socket not connected!")
const id = (0, uuid_1.v4)();
if (!this.listeners[listener]) {
this.listeners[listener] = {};
yield this.ask(listener);
this.socket.on(listener, (data) => __awaiter(this, void 0, void 0, function* () { return yield Promise.all(Object.entries(this.listeners[listener]).map(([, callback]) => callback(data))); }));
}
this.listeners[listener][id] = callback;
return id;
});
}
/**
* Discard a callback
*
* @param listener The listener name (e.g onMessage, onAnyMessage, etc.)
* @param callbackId The ID from `listen`
* @returns boolean - true if the callback was found and discarded, false if the callback is not found
*/
stopListener(listener, callbackId) {
if (this.listeners[listener][callbackId]) {
delete this.listeners[listener][callbackId];
return true;
}
return false;
}
}
exports.SocketClient = SocketClient;