FIRST DEMO

This commit is contained in:
Yuzu 2022-06-19 20:26:57 -05:00
parent b35ac8fd5a
commit b1f8b0a5b5
10 changed files with 248 additions and 0 deletions

5
mod.ts
View File

@ -0,0 +1,5 @@
export * from "./session/mod.ts";
export * from "./util/mod.ts";
export * from "./structures/mod.ts";
export * from "./vendor/external.ts";
export * from "./handlers/mod.ts";

6
session/Events.ts Normal file
View File

@ -0,0 +1,6 @@
import type {
DiscordGatewayPayload,
Shard,
} from "../vendor/external.ts";
export type DiscordRawEventHandler = (shard: Shard, data: DiscordGatewayPayload) => unknown;

129
session/Session.ts Normal file
View File

@ -0,0 +1,129 @@
import type {
GatewayIntents,
DiscordGatewayPayload,
DiscordGetGatewayBot,
DiscordReady,
DiscordMessage,
GatewayDispatchEventNames,
GatewayBot,
Shard
} from "../vendor/external.ts";
import {
EventEmitter,
Snowflake,
Routes
} from "../util/mod.ts";
import type {
DiscordRawEventHandler,
} from "./Events.ts";
import {
createRestManager,
createGatewayManager
} from "../vendor/external.ts";
export interface RestOptions {
secretKey?: string;
applicationId?: Snowflake;
}
export interface GatewayOptions {
botId?: Snowflake;
data?: GatewayBot;
}
export interface SessionOptions {
token: string;
rawHandler?: DiscordRawEventHandler;
intents?: GatewayIntents;
rest?: RestOptions;
gateway?: GatewayOptions;
}
/**
* Receives a Token, connects
* */
export class Session extends EventEmitter {
options: SessionOptions;
// TODO: improve this with CreateShardManager etc
rest: ReturnType<typeof createRestManager>;
gateway: ReturnType<typeof createGatewayManager>;
constructor(options: SessionOptions) {
super();
this.options = options;
const defHandler: DiscordRawEventHandler = (shard, data) => {
this.emit("raw", data, shard.id);
if (!data.t) return;
this.emit(data.t as GatewayDispatchEventNames, data, shard.id);
};
this.rest = createRestManager({
token: this.options.token,
debug: (text) => {
// TODO: set this using the event emitter
super.rawListeners("debug")?.forEach((fn) => fn(text));
},
secretKey: this.options.rest?.secretKey ?? undefined
});
this.gateway = createGatewayManager({
gatewayBot: options.gateway?.data ?? {} as GatewayBot, // TODO
gatewayConfig: {
token: options.token,
intents: options.intents
},
handleDiscordPayload: options.rawHandler ?? defHandler
});
// TODO: set botId in Session.botId or something
}
override on(event: "ready", func: (payload: DiscordReady) => unknown): this;
override on(event: "raw", func: (shard: Shard, data: DiscordGatewayPayload) => unknown): this;
override on(event: "message", func: (message: DiscordMessage) => unknown): this;
override on(event: "debug", func: (text: string) => unknown): this;
override on(event: string, func: Function): this {
return super.on(event, func);
}
override off(event: string, func: Function): this {
return super.off(event, func);
}
override once(event: string, func: Function): this {
return super.once(event, func);
}
async start() {
const getGatewayBot = () => this.rest.runMethod<DiscordGetGatewayBot>(this.rest, "GET", Routes.GATEWAY_BOT());
// check if is empty
if (!Object.keys(this.options.gateway?.data ?? {}).length) {
const nonParsed = await getGatewayBot();
this.gateway.gatewayBot = {
url: nonParsed.url,
shards: nonParsed.shards,
sessionStartLimit: {
total: nonParsed.session_start_limit.total,
remaining: nonParsed.session_start_limit.remaining,
resetAfter: nonParsed.session_start_limit.reset_after,
maxConcurrency: nonParsed.session_start_limit.max_concurrency,
},
};
this.gateway.lastShardId = this.gateway.gatewayBot.shards - 1;
this.gateway.manager.totalShards = this.gateway.gatewayBot.shards;
}
this.gateway.spawnShards();
}
}

View File

@ -0,0 +1,2 @@
export * from "./Session.ts";
export * from "./Events.ts";

1
tests/deps.ts Normal file
View File

@ -0,0 +1 @@
export * from "../mod.ts";

11
tests/mod.ts Normal file
View File

@ -0,0 +1,11 @@
import * as Discord from "./deps.ts";
const session = new Discord.Session({
token: Deno.args[0],
});
session.on("ready", (payload) => console.log(payload));
session.on("raw", (shard, data) => console.log(shard, data));
session.on("debug", (text) => console.log(text));
session.start();

77
util/EventEmmiter.ts Normal file
View File

@ -0,0 +1,77 @@
// deno-lint-ignore-file ban-types
/**
* An event emitter (observer pattern)
* */
export class EventEmitter {
listeners = new Map<PropertyKey, Function[]>;
#addListener(event: string, func: Function) {
this.listeners.set(event, this.listeners.get(event) || []);
this.listeners.get(event)?.push(func);
return this;
}
on(event: string, func: Function) {
return this.#addListener(event, func);
}
#removeListener(event: string, func: Function) {
if (this.listeners.has(event)) {
const listener = this.listeners.get(event);
if (listener?.includes(func)) {
listener.splice(listener.indexOf(func), 1);
if (listener.length === 0) {
this.listeners.delete(event);
}
}
}
return this;
}
off(event: string, func: Function) {
return this.#removeListener(event, func);
}
once(event: string, func: Function) {
// it is important for this to be an arrow function
const closure = () => {
func();
this.off(event, func);
}
const listener = this.listeners.get(event) ?? [];
listener.push(closure);
return this;
}
emit(event: string, ...args: unknown[]) {
const listener = this.listeners.get(event);
if (!listener) {
return false;
}
listener.forEach((f) => f(...args));
return true;
}
listenerCount(eventName: string) {
return this.listeners.get(eventName)?.length ?? 0;
}
rawListeners(eventName: string): Function[] | undefined {
return this.listeners.get(eventName);
}
}
export default EventEmitter;

3
util/Routes.ts Normal file
View File

@ -0,0 +1,3 @@
export function GATEWAY_BOT() {
return "/gateway/bot";
}

11
util/Snowflake.ts Normal file
View File

@ -0,0 +1,11 @@
// snowflake type
export type Snowflake = string;
export const DiscordEpoch = 14200704e5;
// utilities for Snowflakes
export const Snowflake = {
snowflakeToTimestamp(id: Snowflake) {
return (Number(id) >> 22) + DiscordEpoch;
}
}

3
util/mod.ts Normal file
View File

@ -0,0 +1,3 @@
export * from "./EventEmmiter.ts";
export * from "./Snowflake.ts";
export * as Routes from "./Routes.ts";