Skip to content

Commit

Permalink
feat(typings): new helper functions
Browse files Browse the repository at this point in the history
  • Loading branch information
Fyko committed Nov 20, 2022
1 parent 3e223d6 commit 71cc6e1
Show file tree
Hide file tree
Showing 7 changed files with 1,003 additions and 834 deletions.
785 changes: 0 additions & 785 deletions typings/.yarn/releases/yarn-3.2.0-rc.16.cjs

This file was deleted.

807 changes: 807 additions & 0 deletions typings/.yarn/releases/yarn-3.3.0.cjs

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions typings/.yarnrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ nodeLinker: node-modules

npmScopes:
fyko:
npmAlwaysAuth: true
npmAuthToken: ${NODE_AUTH_TOKEN}
npmRegistryServer: 'https://registry.npmjs.com'
npmAlwaysAuth: false
npmAuthToken: "${NODE_AUTH_TOKEN}"
npmRegistryServer: "https://registry.npmjs.com"

yarnPath: .yarn/releases/yarn-3.2.0-rc.16.cjs
yarnPath: .yarn/releases/yarn-3.3.0.cjs
7 changes: 4 additions & 3 deletions typings/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@fyko/export-api",
"description": "Generated code for interacting with the Export API.",
"version": "0.2.1",
"version": "0.3.0",
"license": "MIT",
"exports": {
"./client": {
Expand Down Expand Up @@ -35,7 +35,8 @@
"@grpc/grpc-js": "^1.2.2",
"google-protobuf": "^3.19.4",
"grpc-tools": "^1.10.0",
"grpc_tools_node_protoc_ts": "^5.0.1"
"grpc_tools_node_protoc_ts": "^5.0.1",
"typed-emitter": "^2.1.0"
},
"devDependencies": {
"gen-esm-wrapper": "^1.1.3",
Expand All @@ -47,5 +48,5 @@
"access": "public",
"registry": "https://registry.npmjs.com"
},
"packageManager": "yarn@3.2.0-rc.16"
"packageManager": "yarn@3.3.0"
}
142 changes: 142 additions & 0 deletions typings/src/client.ts
Original file line number Diff line number Diff line change
@@ -1 +1,143 @@
export * from '../generated/export_grpc_pb';

import { CallOptions, ClientOptions, credentials } from "@grpc/grpc-js";
import { EventEmitter } from 'events';
import type TypedEmitter from "typed-emitter";
import { ExporterClient } from '../generated/export_grpc_pb';
import { CreateExportRequest, CreateExportResponse, ExportFormat } from './types';

export function createExporterClient(
address: string,
creds = credentials.createInsecure(),
options?: ClientOptions
): ExporterClient {
return new ExporterClient(address, creds, options);
}

export type ExportEvents = {
error: (err: Error) => void;
progress: (progress: number) => void;
chunk: (chunk: string | Uint8Array) => void;
done: (messageCount: number, file: Buffer) => void;
}

/**
* Create an EventEmitter
* @param client - The client to use to make the request
* @param data - The data to provide to the request
* @param options - Other gRPC options
* @returns An EventEmitter
* @see [Examples: High Level](https://fyko.github.io/export-api/docs/api-versions/gRPC#high-level)
*/
export function createExport(
client: ExporterClient,
data: CreateExportData,
options?: Partial<CallOptions>
) {
const request = createExportRequest(data);
const stream = client.createExport(request, options);

const chunks: Uint8Array[] = [];

let progress = 0;
let messageCount: number | undefined = 0;
const emitter = new EventEmitter() as TypedEmitter<ExportEvents>;

stream.on('data', (response: CreateExportResponse) => {
// if `response.progress` is present
const p = response.getProgress();
if (p && p > progress) {
progress = p;
emitter.emit('progress', progress);
}

// if finally sending the file itself, push to chunk array
const data = response.getData();
const count = data?.getMessageCount();
if (count) {
messageCount = count;
}

const inner = data?.getData();
const isUint8Array = (x: unknown): x is Uint8Array => x instanceof Uint8Array;
if (isUint8Array(inner)) {
chunks.push(inner)
}
});

stream.on("end", async () => {
stream.destroy();
return emitter.emit("done", messageCount ?? 0, Buffer.concat(chunks));
});

stream.on("error", (err) => {
return emitter.emit('error', err);
});

return emitter;
}

/**
* Turns a stream into a promise that resolves with the message count and file buffer.
* @param emitter - The emitter returned by `createExport`
* @returns - A tuple of the message count and file buffer (in that order)
*/
export function promisifyExportResult(emitter: TypedEmitter<ExportEvents>) {
return new Promise<[number, Buffer]>((resolve, reject) => {
emitter.on("done", (count, file) => resolve([count, file]));
emitter.on("error", (err) => reject(err));
});
}

/**
* The data to provide to the export request
*/
export interface CreateExportData {
/**
* The id of the channel to export
*/
channelId: string;
/**
* The bot token for performing requests
*/
token: string;
/**
* The format to export the channel as, defaults to PlainText
*/
exportFormat?: ExportFormat;
/**
* The [date format](https://docs.microsoft.com/en-us/dotnet/standard/base-types/custom-date-and-time-format-strings) for dates in exported files, defaults to dd-MMM-yy hh:mm tt
*/
dateFormat?: string;
/**
* Only include messages sent after this date
*/
after?: string;
/**
* Only include messages sent before this date
*/
before?: string;
}

/**
*
* @param data - The data to provide to the request
* @returns A fresh `CreateExportRequest`
*/
function createExportRequest(data: CreateExportData) {
const request = new CreateExportRequest();

request.setChannelId(data.channelId);
request.setToken(data.token);

if (data.exportFormat)
request.setExportFormat(data.exportFormat);
if (data.dateFormat)
request.setDateFormat(data.dateFormat);
if (data.after)
request.setAfter(data.after);
if (data.before)
request.setBefore(data.before);

return request;
}
55 changes: 15 additions & 40 deletions typings/test/index.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,23 @@
import { credentials } from "@grpc/grpc-js";
import { ExporterClient } from "../dist/client";
import {
CreateExportRequest,
CreateExportResponse,
ExportFormat,
} from "../dist/types";
import { writeFile } from "fs/promises";
import { createExport, createExporterClient, promisifyExportResult } from "../src/client";
import {
ExportFormat
} from "../src/types";

const client = new ExporterClient(
`localhost:${process.env.PORT}`,
credentials.createInsecure()
);
const client = createExporterClient(`localhost:${process.env.PORT}`);

void (async () => {
const request = new CreateExportRequest();
request.setChannelId(process.env.DISCORD_CHANNEL!);
request.setToken(process.env.DISCORD_TOKEN!);
request.setExportFormat(ExportFormat.HTMLDARK);

return new Promise(async (res, rej) => {
const stream = client.createExport(request);

const chunks: (string | Uint8Array)[] = [];
let progress = 0;
stream.on("data", (response: CreateExportResponse) => {
const p = response.getProgress();
if (p && p > progress) {
progress = p;
console.log((p * 100).toFixed() + "%");
}
const stream = createExport(client, {
channelId: process.env.DISCORD_CHANNEL!,
token: process.env.DISCORD_TOKEN!,
exportFormat: ExportFormat.HTMLDARK,
});

const data = response.getData();
const inner = data?.getData();
if (inner) {
console.log(`Inner exists!`);
chunks.push(inner);
}
});
stream.on("progress", (progress) =>
console.log(`progress: ${progress}`));

stream.on("end", async () => {
await writeFile("./foo.html", chunks);
return res(void 0);
});
const [count, file] = await promisifyExportResult(stream);

stream.on("error", rej);
});
console.log(`export created with ${count} messages (${file.byteLength} bytes)`);
await writeFile("./foo.html", file);
})();
33 changes: 31 additions & 2 deletions typings/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ __metadata:
grpc_tools_node_protoc_ts: ^5.0.1
npm-run-all: ^4.1.5
rimraf: ^3.0.2
typed-emitter: ^2.1.0
typescript: ^4.5.5
languageName: unknown
linkType: soft
Expand Down Expand Up @@ -1196,7 +1197,7 @@ __metadata:

"resolve@patch:resolve@^1.10.0#~builtin<compat/resolve>":
version: 1.22.0
resolution: "resolve@patch:resolve@npm%3A1.22.0#~builtin<compat/resolve>::version=1.22.0&hash=07638b"
resolution: "resolve@patch:resolve@npm%3A1.22.0#~builtin<compat/resolve>::version=1.22.0&hash=c3c19d"
dependencies:
is-core-module: ^2.8.1
path-parse: ^1.0.7
Expand All @@ -1218,6 +1219,15 @@ __metadata:
languageName: node
linkType: hard

"rxjs@npm:*":
version: 7.5.7
resolution: "rxjs@npm:7.5.7"
dependencies:
tslib: ^2.1.0
checksum: edabcdb73b0f7e0f5f6e05c2077aff8c52222ac939069729704357d6406438acca831c24210db320aba269e86dbe1a400f3769c89101791885121a342fb15d9c
languageName: node
linkType: hard

"safe-buffer@npm:~5.2.0":
version: 5.2.1
resolution: "safe-buffer@npm:5.2.1"
Expand Down Expand Up @@ -1447,6 +1457,25 @@ __metadata:
languageName: node
linkType: hard

"tslib@npm:^2.1.0":
version: 2.4.1
resolution: "tslib@npm:2.4.1"
checksum: 19480d6e0313292bd6505d4efe096a6b31c70e21cf08b5febf4da62e95c265c8f571f7b36fcc3d1a17e068032f59c269fab3459d6cd3ed6949eafecf64315fca
languageName: node
linkType: hard

"typed-emitter@npm:^2.1.0":
version: 2.1.0
resolution: "typed-emitter@npm:2.1.0"
dependencies:
rxjs: "*"
dependenciesMeta:
rxjs:
optional: true
checksum: 95821a9e05784b972cc9d152891fd12a56cb4b1a7c57e768c02bea6a8984da7aff8f19404a7b69eea11fae2a3b6c0c510a4c510f575f50162c759ae9059f2520
languageName: node
linkType: hard

"typescript@npm:^4.5.5":
version: 4.5.5
resolution: "typescript@npm:4.5.5"
Expand All @@ -1459,7 +1488,7 @@ __metadata:

"typescript@patch:typescript@^4.5.5#~builtin<compat/typescript>":
version: 4.5.5
resolution: "typescript@patch:typescript@npm%3A4.5.5#~builtin<compat/typescript>::version=4.5.5&hash=bda367"
resolution: "typescript@patch:typescript@npm%3A4.5.5#~builtin<compat/typescript>::version=4.5.5&hash=bcec9a"
bin:
tsc: bin/tsc
tsserver: bin/tsserver
Expand Down

0 comments on commit 71cc6e1

Please sign in to comment.