add request batching and drawing module
parent
cca7ca2cd7
commit
9e638d94f1
100
src/client.ts
100
src/client.ts
|
@ -1,7 +1,15 @@
|
||||||
|
import { MethodCall, TCJSONResponse, TCResponse, TCResponseRaw } from "./types";
|
||||||
import { AskModule } from "./ask";
|
import { AskModule } from "./ask";
|
||||||
import { MessagesModule } from "./messages";
|
import { MessagesModule } from "./messages";
|
||||||
import { ForumModule } from "./forum";
|
import { ForumModule } from "./forum";
|
||||||
import { MethodCall, TCJSONResponse, TCResponse, TCResponseRaw } from "./types";
|
import { DrawingModule } from "./drawing";
|
||||||
|
|
||||||
|
interface QueuedCall {
|
||||||
|
methodCall: MethodCall;
|
||||||
|
creator: new(r: TCResponseRaw) => TCResponse;
|
||||||
|
resolve: (value: any) => void;
|
||||||
|
reject: (reason: any) => void;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Client for Two Cans & String API.
|
* Client for Two Cans & String API.
|
||||||
|
@ -13,6 +21,10 @@ export class Client {
|
||||||
#messages: MessagesModule;
|
#messages: MessagesModule;
|
||||||
#ask: AskModule;
|
#ask: AskModule;
|
||||||
#forum: ForumModule;
|
#forum: ForumModule;
|
||||||
|
#drawing: DrawingModule;
|
||||||
|
|
||||||
|
#requestQueue: QueuedCall[] = [];
|
||||||
|
#isBatching: boolean = false;
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
public _cache: { [key: string]: any; } = { };
|
public _cache: { [key: string]: any; } = { };
|
||||||
|
@ -33,6 +45,22 @@ export class Client {
|
||||||
return this.#forum;
|
return this.#forum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get drawing(): DrawingModule {
|
||||||
|
return this.#drawing;
|
||||||
|
}
|
||||||
|
|
||||||
|
public get isBatching(): boolean {
|
||||||
|
return this.#isBatching;
|
||||||
|
}
|
||||||
|
|
||||||
|
public set isBatching(value: boolean) {
|
||||||
|
if (value) {
|
||||||
|
this.beginBatch();
|
||||||
|
} else {
|
||||||
|
this.endBatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public constructor(auth?: string) {
|
public constructor(auth?: string) {
|
||||||
this.auth = auth;
|
this.auth = auth;
|
||||||
|
|
||||||
|
@ -40,6 +68,7 @@ export class Client {
|
||||||
this.#messages = new MessagesModule(this);
|
this.#messages = new MessagesModule(this);
|
||||||
this.#ask = new AskModule(this);
|
this.#ask = new AskModule(this);
|
||||||
this.#forum = new ForumModule(this);
|
this.#forum = new ForumModule(this);
|
||||||
|
this.#drawing = new DrawingModule(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
//public login(username: string, password: string) {
|
//public login(username: string, password: string) {
|
||||||
|
@ -53,7 +82,7 @@ export class Client {
|
||||||
* @param args The arguments to pass to the API method.
|
* @param args The arguments to pass to the API method.
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
public async _call<T extends TCResponse>(
|
public _call<T extends TCResponse>(
|
||||||
creator: new(r: TCResponseRaw) => T,
|
creator: new(r: TCResponseRaw) => T,
|
||||||
methodName: string,
|
methodName: string,
|
||||||
args: { [key: string]: any }
|
args: { [key: string]: any }
|
||||||
|
@ -64,19 +93,82 @@ export class Client {
|
||||||
payload: args,
|
payload: args,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (this.#isBatching) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.#requestQueue.push({
|
||||||
|
methodCall,
|
||||||
|
creator,
|
||||||
|
resolve,
|
||||||
|
reject,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const body = {
|
const body = {
|
||||||
auth: this.auth,
|
auth: this.auth,
|
||||||
requests: [methodCall],
|
requests: [methodCall],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
this.fetch(body)
|
||||||
|
.then((res) => {
|
||||||
|
const rawResponse: TCResponseRaw = {
|
||||||
|
ok: res?.ok ?? false,
|
||||||
|
...res?.responses[0],
|
||||||
|
};
|
||||||
|
|
||||||
|
resolve(new creator(rawResponse));
|
||||||
|
})
|
||||||
|
.catch((reason) => reject(reason));
|
||||||
|
});
|
||||||
|
/*
|
||||||
const res = await this.fetch(body);
|
const res = await this.fetch(body);
|
||||||
|
|
||||||
const rawResponse: TCResponseRaw = {
|
const rawResponse: TCResponseRaw = {
|
||||||
ok: res?.ok ?? false,
|
ok: res?.ok ?? false,
|
||||||
...res?.responses[0],
|
...res?.responses[0],
|
||||||
} as T;
|
} as T;
|
||||||
|
|
||||||
return new creator(rawResponse);
|
return new creator(rawResponse);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
public beginBatch(): void {
|
||||||
|
this.#isBatching = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public endBatch(process = true): void {
|
||||||
|
this.#isBatching = false;
|
||||||
|
if (process) {
|
||||||
|
this.processBatch();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public processBatch(): void {
|
||||||
|
const methodCalls = this.#requestQueue.map((c) => c.methodCall);
|
||||||
|
|
||||||
|
const body = {
|
||||||
|
auth: this.auth,
|
||||||
|
requests: methodCalls,
|
||||||
|
};
|
||||||
|
|
||||||
|
this.fetch(body)
|
||||||
|
.then((res) => {
|
||||||
|
this.#requestQueue.forEach((c, index) => {
|
||||||
|
const individualResponse: TCResponseRaw = {
|
||||||
|
ok: res?.ok ?? false,
|
||||||
|
...res?.responses[index],
|
||||||
|
};
|
||||||
|
|
||||||
|
c.resolve(new c.creator(individualResponse));
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch((reason) => {
|
||||||
|
this.#requestQueue.forEach((c) => c.reject(reason));
|
||||||
|
})
|
||||||
|
.finally(() => {
|
||||||
|
this.#requestQueue.length = 0;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private async fetch(body: any): Promise<TCJSONResponse | undefined> {
|
private async fetch(body: any): Promise<TCJSONResponse | undefined> {
|
||||||
|
@ -93,7 +185,7 @@ export class Client {
|
||||||
const res = await fetch(Client.BASE_URI, req);
|
const res = await fetch(Client.BASE_URI, req);
|
||||||
|
|
||||||
if (!res.ok) {
|
if (!res.ok) {
|
||||||
return;
|
return Promise.reject();
|
||||||
}
|
}
|
||||||
|
|
||||||
return await res.json() as TCJSONResponse;
|
return await res.json() as TCJSONResponse;
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
import { Module } from "../module";
|
||||||
|
import { TCResponse } from "../types";
|
||||||
|
import { SaveDrawingResponse, ViewDrawingDataResponse } from "./types";
|
||||||
|
|
||||||
|
export class DrawingModule extends Module {
|
||||||
|
public async saveDrawing(data: string, makeActive = false) {
|
||||||
|
this.client._call(
|
||||||
|
// newImageId: string
|
||||||
|
SaveDrawingResponse,
|
||||||
|
"legacy.drawing",
|
||||||
|
{
|
||||||
|
action: "save",
|
||||||
|
data,
|
||||||
|
makeActive,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async viewDrawingData(imageId: string) {
|
||||||
|
// response { ok: boolean , pixelData: string }
|
||||||
|
this.client._call(
|
||||||
|
// newImageId: string
|
||||||
|
ViewDrawingDataResponse,
|
||||||
|
"legacy.drawing",
|
||||||
|
{
|
||||||
|
action: "initial-image-data",
|
||||||
|
imageId,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async sendDrawing(imageId: string, receiver: string) {
|
||||||
|
this.client._call(
|
||||||
|
TCResponse,
|
||||||
|
"drawing.send",
|
||||||
|
{
|
||||||
|
imageId,
|
||||||
|
receiver,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
import { TCResponse, TCResponseRaw } from "../types";
|
||||||
|
|
||||||
|
export class SaveDrawingResponse extends TCResponse {
|
||||||
|
public newImageId: string;
|
||||||
|
|
||||||
|
public constructor(res: TCResponseRaw) {
|
||||||
|
super(res);
|
||||||
|
this.newImageId = res["newImageId"];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ViewDrawingDataResponse extends TCResponse {
|
||||||
|
public data: string;
|
||||||
|
|
||||||
|
public constructor(res: TCResponseRaw) {
|
||||||
|
super(res);
|
||||||
|
this.data = res["data"];
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue