This commit is contained in:
2024-11-13 18:05:55 +08:00
parent 93d41169e1
commit eeaf9e071e
7 changed files with 421 additions and 11 deletions

View File

@ -11,7 +11,7 @@ export class ExtServer implements IServer {
});
}
onConnect(callback: (eventName: string, con: IConnect) => void) {
onConnect(callback: (con: IConnect) => void) {
this.EE.on("connect", callback);
}
}

View File

@ -2,7 +2,7 @@ import EventEmitter from "eventemitter3";
import { v4 as uuidv4 } from "uuid";
export interface IServer {
onConnect: (callback: (eventName: string, con: IConnect) => void) => void;
onConnect: (callback: (con: IConnect) => void) => void;
}
export interface IConnect {
@ -18,8 +18,8 @@ export class Server {
constructor(private connect: IServer) {
this.EE = new EventEmitter();
this.connect.onConnect((eventName, con) => {
this.EE.emit(eventName, con);
this.connect.onConnect((con) => {
this.EE.emit("connection", con);
});
}
@ -31,20 +31,21 @@ export class Server {
export class Connect {
private EE: EventEmitter;
private con: IConnect;
constructor(
private id: string | IConnect,
private con: IConnect
con?: IConnect
) {
this.EE = new EventEmitter();
if (arguments.length === 1) {
this.con = id as IConnect;
this.con.onMessage((message) => {
const data = message as { eventName: string; data: unknown[]; messageId: string };
data.data.push(this.callbackFunc(data.messageId));
this.EE.emit(data.eventName, ...data.data);
this.messageHandler(message);
});
} else {
// 子连接
this.con = con!;
this.con.onMessage((message) => {
const data = message as { eventName: string; data: unknown; id: string };
if (data.eventName === "subcon") {
@ -60,13 +61,13 @@ export class Connect {
}
private callbackFunc(msgId: string): (...data: unknown[]) => void {
return function (...data: unknown[]) {
return (...data: unknown[]) => {
this.con.postMessage({ eventName: "callback", data, messageId: msgId });
};
}
private messageHandler(data: unknown) {
const subData = data.data as { eventName: string; data: unknown[]; messageId: string };
const subData = data as { eventName: string; data: unknown[]; messageId: string };
subData.data.push(this.callbackFunc(subData.messageId));
this.EE.emit(subData.eventName, ...subData.data);
}

View File

@ -0,0 +1,42 @@
// @vitest-environment jsdom
import { expect, test, vi } from "vitest";
import { Server, Connect } from ".";
import { connect, WindowServer } from "./window";
test("server", async () => {
const myFunc = vi.fn();
const server = new Server(new WindowServer(global.window));
server.on("connection", (con) => {
myFunc();
con.onMessage((message) => {
myFunc(message);
});
});
const client = connect(window, window);
client.postMessage("hello");
await new Promise((resolve) => setTimeout(resolve, 1));
expect(myFunc).toHaveBeenCalledTimes(2);
expect(myFunc).toHaveBeenCalledWith("hello");
});
test("connect", async () => {
const myFunc = vi.fn();
const server = new Server(new WindowServer(global.window));
server.on("connection", (con) => {
myFunc();
const wrapCon = new Connect(con);
wrapCon.on("hello", (message) => {
myFunc(message);
wrapCon.emit("world", "world");
});
});
const client = new Connect(connect(window, window));
client.on("world", (message) => {
myFunc(message);
});
client.emit("hello", "hello");
await new Promise((resolve) => setTimeout(resolve, 1));
expect(myFunc).toHaveBeenCalledTimes(3);
expect(myFunc).toHaveBeenCalledWith("hello");
expect(myFunc).toHaveBeenCalledWith("world");
});

View File

@ -0,0 +1,60 @@
import EventEmitter from "eventemitter3";
import { IConnect, IServer } from ".";
import { v4 as uuidv4 } from "uuid";
export class WindowServer implements IServer {
private EE: EventEmitter;
constructor(win: Window) {
this.EE = new EventEmitter();
win.addEventListener("message", (event) => {
if (event.data.type === "connect") {
this.EE.emit("connection", new WindowConnect(event.data.connectId, event.target as Window, win));
}
});
}
onConnect(callback: (con: IConnect) => void) {
this.EE.on("connection", callback);
}
}
export function connect(source: Window, target: Window) {
const con = new WindowConnect(uuidv4(), source, target);
con.postMessage({ type: "connect" });
return con;
}
export class WindowConnect implements IConnect {
private EE: EventEmitter;
constructor(
private id: string,
private source: Window,
private target: Window
) {
this.EE = new EventEmitter();
this.source.addEventListener("message", (event) => {
if (event.data.id === id) {
this.EE.emit("message", event.data);
}
});
}
postMessage(message: unknown) {
this.target.postMessage(message, "*");
}
onMessage(callback: (message: unknown) => void) {
this.EE.on("message", callback);
}
onDisconnect(callback: () => void) {
this.EE.on("disconnect", callback);
}
disconnect() {
this.EE.emit("disconnect");
this.EE.removeAllListeners();
}
}