initial commit
This commit is contained in:
@@ -0,0 +1,138 @@
|
||||
import WebSocket from "ws";
|
||||
|
||||
import type {
|
||||
GetMessagesParams,
|
||||
ListChatsParams,
|
||||
SearchMessagesParams,
|
||||
SendTextParams,
|
||||
} from "../shared/protocol";
|
||||
import type {
|
||||
ChatDTO,
|
||||
ContactDTO,
|
||||
GroupMetadataDTO,
|
||||
MessageDTO,
|
||||
} from "../shared/dto";
|
||||
|
||||
export class WhatsAppClient {
|
||||
private url: string = "";
|
||||
private isConnected: boolean = false;
|
||||
private socket: WebSocket | null = null;
|
||||
|
||||
private pending = new Map<
|
||||
string,
|
||||
{
|
||||
resolve: (value: any) => void;
|
||||
reject: (error: Error) => void;
|
||||
timer: NodeJS.Timeout;
|
||||
}
|
||||
>();
|
||||
|
||||
constructor(url = "ws://127.0.0.1:8787") {
|
||||
this.url = url;
|
||||
}
|
||||
|
||||
async connect() {
|
||||
return new Promise<void>((resolve, reject) => {
|
||||
if (this.socket) return;
|
||||
|
||||
this.socket = new WebSocket(this.url);
|
||||
|
||||
this.socket.on("open", () => {
|
||||
console.log("Connected to bridge");
|
||||
this.isConnected = true;
|
||||
resolve();
|
||||
});
|
||||
|
||||
this.socket.on("message", (data) => {
|
||||
const message = JSON.parse(data.toString());
|
||||
|
||||
if (message.type !== "response") {
|
||||
return;
|
||||
}
|
||||
|
||||
const pending = this.pending.get(message.id);
|
||||
|
||||
if (!pending) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.pending.delete(message.id);
|
||||
clearTimeout(pending.timer);
|
||||
|
||||
if (message.ok) {
|
||||
pending.resolve(message.result);
|
||||
} else {
|
||||
pending.reject(new Error(message.error?.message ?? "Unknown error"));
|
||||
}
|
||||
});
|
||||
|
||||
this.socket.on("close", () => {
|
||||
this.socket = null;
|
||||
this.isConnected = false;
|
||||
setTimeout(() => this.connect(), 3000);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private request<T>(method: string, params?: unknown): Promise<T> {
|
||||
if (!this.isConnected || !this.socket) {
|
||||
throw new Error("WhatsApp is not connected");
|
||||
}
|
||||
|
||||
const id = crypto.randomUUID();
|
||||
|
||||
return new Promise<T>((resolve, reject) => {
|
||||
const timer = setTimeout(() => {
|
||||
this.pending.delete(id);
|
||||
|
||||
reject(new Error(`Request timeout: ${method}`));
|
||||
}, 30_000);
|
||||
|
||||
this.pending.set(id, {
|
||||
resolve,
|
||||
reject,
|
||||
timer,
|
||||
});
|
||||
|
||||
this.socket!.send(
|
||||
JSON.stringify({
|
||||
type: "request",
|
||||
id,
|
||||
method,
|
||||
params,
|
||||
}),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
status() {
|
||||
return this.request<{
|
||||
authenticated: boolean;
|
||||
ready: boolean;
|
||||
}>("status");
|
||||
}
|
||||
|
||||
listChats(params?: ListChatsParams) {
|
||||
return this.request<ChatDTO[]>("listChats", params);
|
||||
}
|
||||
|
||||
listContacts(params?: { limit?: number }) {
|
||||
return this.request<ContactDTO[]>("listContacts", params);
|
||||
}
|
||||
|
||||
listGroups() {
|
||||
return this.request<GroupMetadataDTO[]>("listGroups");
|
||||
}
|
||||
|
||||
getMessages(params: GetMessagesParams) {
|
||||
return this.request<MessageDTO[]>("getMessages", params);
|
||||
}
|
||||
|
||||
searchMessages(params: SearchMessagesParams) {
|
||||
return this.request<MessageDTO[]>("searchMessages", params);
|
||||
}
|
||||
|
||||
sendText(params: SendTextParams) {
|
||||
return this.request<any>("sendText", params);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user