mirror of
https://github.com/tiramisulabs/seyfert.git
synced 2025-07-03 05:26:07 +00:00
2.0.5 - first stable version of gateway
This commit is contained in:
parent
9d4b543c8b
commit
a39c06bab9
1
.gitignore
vendored
1
.gitignore
vendored
@ -22,6 +22,7 @@ packages/core/docs.json
|
|||||||
node_modules
|
node_modules
|
||||||
.pnp
|
.pnp
|
||||||
.pnp.js
|
.pnp.js
|
||||||
|
.vscode
|
||||||
|
|
||||||
# testing
|
# testing
|
||||||
coverage
|
coverage
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# @biscuitland/api-types
|
# @biscuitland/api-types
|
||||||
|
|
||||||
## 2.0.4
|
## 2.0.5
|
||||||
|
|
||||||
### Major Changes
|
### Major Changes
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ import type { DiscordUser } from '@biscuitland/api-types';
|
|||||||
## Example for [Deno](https://deno.land/)
|
## Example for [Deno](https://deno.land/)
|
||||||
|
|
||||||
```ts
|
```ts
|
||||||
import type { DiscordUser } from "https://unpkg.com/@biscuitland/api-types@2.0.4/dist/index.d.ts";
|
import type { DiscordUser } from "https://unpkg.com/@biscuitland/api-types@2.0.5/dist/index.d.ts";
|
||||||
```
|
```
|
||||||
|
|
||||||
We deliver this package through [unpkg](https://unpkg.com/) and it does contain constants and routes too
|
We deliver this package through [unpkg](https://unpkg.com/) and it does contain constants and routes too
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@biscuitland/api-types",
|
"name": "@biscuitland/api-types",
|
||||||
"version": "2.0.4",
|
"version": "2.0.5",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"module": "./dist/index.mjs",
|
"module": "./dist/index.mjs",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
|
@ -5,7 +5,7 @@ export const BASE_URL = 'https://discord.com/api';
|
|||||||
export const API_VERSION = 10;
|
export const API_VERSION = 10;
|
||||||
|
|
||||||
/** https://github.com/oasisjs/biscuit/releases */
|
/** https://github.com/oasisjs/biscuit/releases */
|
||||||
export const BISCUIT_VERSION = '2.0.4';
|
export const BISCUIT_VERSION = '2.0.5';
|
||||||
|
|
||||||
/** https://discord.com/developers/docs/reference#user-agent */
|
/** https://discord.com/developers/docs/reference#user-agent */
|
||||||
export const USER_AGENT = `DiscordBot (https://github.com/oasisjs/biscuit, v${BISCUIT_VERSION})`;
|
export const USER_AGENT = `DiscordBot (https://github.com/oasisjs/biscuit, v${BISCUIT_VERSION})`;
|
||||||
|
4
packages/cache/CHANGELOG.md
vendored
4
packages/cache/CHANGELOG.md
vendored
@ -1,6 +1,6 @@
|
|||||||
# @biscuitland/cache
|
# @biscuitland/cache
|
||||||
|
|
||||||
## 2.0.4
|
## 2.0.5
|
||||||
|
|
||||||
### Major Changes
|
### Major Changes
|
||||||
|
|
||||||
@ -9,4 +9,4 @@
|
|||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|
||||||
- Updated dependencies
|
- Updated dependencies
|
||||||
- @biscuitland/api-types@2.0.4
|
- @biscuitland/api-types@2.0.5
|
||||||
|
4
packages/cache/package.json
vendored
4
packages/cache/package.json
vendored
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@biscuitland/cache",
|
"name": "@biscuitland/cache",
|
||||||
"version": "2.0.4",
|
"version": "2.0.5",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"module": "./dist/index.mjs",
|
"module": "./dist/index.mjs",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
@ -23,7 +23,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@biscuitland/api-types": "^2.0.4",
|
"@biscuitland/api-types": "^2.0.5",
|
||||||
"ioredis": "^5.2.2"
|
"ioredis": "^5.2.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# @biscuitland/core
|
# @biscuitland/core
|
||||||
|
|
||||||
## 2.0.4
|
## 2.0.5
|
||||||
|
|
||||||
### Major Changes
|
### Major Changes
|
||||||
|
|
||||||
@ -9,6 +9,6 @@
|
|||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|
||||||
- Updated dependencies
|
- Updated dependencies
|
||||||
- @biscuitland/api-types@2.0.4
|
- @biscuitland/api-types@2.0.5
|
||||||
- @biscuitland/rest@2.0.4
|
- @biscuitland/rest@2.0.5
|
||||||
- @biscuitland/ws@2.0.4
|
- @biscuitland/ws@2.0.5
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@biscuitland/core",
|
"name": "@biscuitland/core",
|
||||||
"version": "2.0.4",
|
"version": "2.0.5",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"module": "./dist/index.mjs",
|
"module": "./dist/index.mjs",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
@ -23,9 +23,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@biscuitland/api-types": "^2.0.4",
|
"@biscuitland/api-types": "^2.0.5",
|
||||||
"@biscuitland/rest": "^2.0.4",
|
"@biscuitland/rest": "^2.0.5",
|
||||||
"@biscuitland/ws": "^2.0.4"
|
"@biscuitland/ws": "^2.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"tsup": "^6.1.3"
|
"tsup": "^6.1.3"
|
||||||
|
@ -10,13 +10,11 @@ import type {
|
|||||||
Localization,
|
Localization,
|
||||||
Snowflake,
|
Snowflake,
|
||||||
DiscordGetGatewayBot,
|
DiscordGetGatewayBot,
|
||||||
|
DiscordGatewayPayload
|
||||||
} from '@biscuitland/api-types';
|
} from '@biscuitland/api-types';
|
||||||
|
|
||||||
import { ApplicationCommandTypes, GatewayOpcodes } from '@biscuitland/api-types';
|
import { ApplicationCommandTypes, GatewayOpcodes ,
|
||||||
|
|
||||||
// routes
|
|
||||||
|
|
||||||
import {
|
|
||||||
APPLICATION_COMMANDS,
|
APPLICATION_COMMANDS,
|
||||||
GUILD_APPLICATION_COMMANDS,
|
GUILD_APPLICATION_COMMANDS,
|
||||||
GUILD_APPLICATION_COMMANDS_PERMISSIONS,
|
GUILD_APPLICATION_COMMANDS_PERMISSIONS,
|
||||||
@ -24,6 +22,8 @@ import {
|
|||||||
USER
|
USER
|
||||||
} from '@biscuitland/api-types';
|
} from '@biscuitland/api-types';
|
||||||
|
|
||||||
|
// routes
|
||||||
|
|
||||||
import type { PermissionResolvable } from './structures/special/permissions';
|
import type { PermissionResolvable } from './structures/special/permissions';
|
||||||
import type { Activities, StatusTypes } from './structures/presence';
|
import type { Activities, StatusTypes } from './structures/presence';
|
||||||
|
|
||||||
@ -36,14 +36,13 @@ import { User } from './structures/user';
|
|||||||
import type { RestAdapter } from '@biscuitland/rest';
|
import type { RestAdapter } from '@biscuitland/rest';
|
||||||
import { DefaultRestAdapter } from '@biscuitland/rest';
|
import { DefaultRestAdapter } from '@biscuitland/rest';
|
||||||
|
|
||||||
import type { WsAdapter } from '@biscuitland/ws';
|
import type { Shard } from '@biscuitland/ws';
|
||||||
import { DefaultWsAdapter } from '@biscuitland/ws';
|
import { ShardManager } from '@biscuitland/ws';
|
||||||
|
|
||||||
import type { EventAdapter } from './adapters/event-adapter';
|
import type { EventAdapter } from './adapters/event-adapter';
|
||||||
import { DefaultEventAdapter } from './adapters/default-event-adapter';
|
import { DefaultEventAdapter } from './adapters/default-event-adapter';
|
||||||
|
|
||||||
import { Util } from './utils/util';
|
import { Util } from './utils/util';
|
||||||
import { Shard } from '@biscuitland/ws';
|
|
||||||
|
|
||||||
// PRESENCE
|
// PRESENCE
|
||||||
|
|
||||||
@ -146,7 +145,7 @@ export interface BiscuitOptions {
|
|||||||
};
|
};
|
||||||
|
|
||||||
ws: {
|
ws: {
|
||||||
adapter?: { new (...args: any[]): WsAdapter };
|
adapter?: { new (...args: any[]): ShardManager };
|
||||||
options: any;
|
options: any;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -180,9 +179,9 @@ export class Session {
|
|||||||
options: null,
|
options: null,
|
||||||
},
|
},
|
||||||
ws: {
|
ws: {
|
||||||
adapter: DefaultWsAdapter,
|
adapter: ShardManager,
|
||||||
options: null,
|
options: null,
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
options: BiscuitOptions;
|
options: BiscuitOptions;
|
||||||
@ -190,7 +189,7 @@ export class Session {
|
|||||||
readonly events: EventAdapter;
|
readonly events: EventAdapter;
|
||||||
|
|
||||||
readonly rest: RestAdapter;
|
readonly rest: RestAdapter;
|
||||||
readonly ws: WsAdapter;
|
readonly ws: ShardManager;
|
||||||
|
|
||||||
private adapters = new Map<string, any>();
|
private adapters = new Map<string, any>();
|
||||||
|
|
||||||
@ -210,20 +209,17 @@ export class Session {
|
|||||||
|
|
||||||
// makeWs
|
// makeWs
|
||||||
|
|
||||||
const defHandler: DiscordRawEventHandler = (shard, event) => {
|
const defHandler = (shard: Shard, payload: DiscordGatewayPayload) => {
|
||||||
let data = event as any;
|
Actions.raw(this, shard.options.id, payload);
|
||||||
// let data = JSON.parse(message) as DiscordGatewayPayload;
|
|
||||||
|
|
||||||
Actions.raw(this, shard.id, data);
|
if (!payload.t || !payload.d) {
|
||||||
|
|
||||||
if (!data.t || !data.d) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Actions[data.t as keyof typeof Actions]?.(
|
Actions[payload.t as keyof typeof Actions]?.(
|
||||||
this,
|
this,
|
||||||
shard.id,
|
shard.options.id,
|
||||||
data.d as any
|
payload.d as any
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -231,21 +227,28 @@ export class Session {
|
|||||||
this.options.ws.options = {
|
this.options.ws.options = {
|
||||||
handleDiscordPayload: defHandler,
|
handleDiscordPayload: defHandler,
|
||||||
|
|
||||||
gatewayConfig: {
|
gateway: {
|
||||||
|
url: '',
|
||||||
|
shards: '',
|
||||||
|
|
||||||
|
session_start_limit: {
|
||||||
|
total: 1000,
|
||||||
|
remaining: 1000,
|
||||||
|
reset_after: 3600000,
|
||||||
|
|
||||||
|
max_concurrency: 1
|
||||||
|
}
|
||||||
|
},
|
||||||
|
config: {
|
||||||
token: this.options.token,
|
token: this.options.token,
|
||||||
intents: this.options.intents,
|
intents: this.options.intents,
|
||||||
},
|
},
|
||||||
|
|
||||||
intents: this.options.intents,
|
|
||||||
token: this.options.token,
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeEvents
|
// makeEvents
|
||||||
|
|
||||||
this.events = this.options.events?.adapter
|
this.events = this.options.events?.adapter ? new this.options.events.adapter() : new DefaultEventAdapter();
|
||||||
? new this.options.events.adapter()
|
|
||||||
: new DefaultEventAdapter();
|
|
||||||
|
|
||||||
this.ws = this.getWs();
|
this.ws = this.getWs();
|
||||||
this.token = options.token;
|
this.token = options.token;
|
||||||
@ -282,7 +285,7 @@ export class Session {
|
|||||||
* @inheritDoc
|
* @inheritDoc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
private getWs(): WsAdapter {
|
private getWs(): ShardManager {
|
||||||
return this.getAdapter(
|
return this.getAdapter(
|
||||||
this.options.ws.adapter!,
|
this.options.ws.adapter!,
|
||||||
this.options.ws.options
|
this.options.ws.options
|
||||||
@ -294,23 +297,10 @@ export class Session {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
async start(): Promise<void> {
|
async start(): Promise<void> {
|
||||||
const nonParsed = await this.rest.get<DiscordGetGatewayBot>('/gateway/bot');
|
const gateway = await this.rest.get<DiscordGetGatewayBot>('/gateway/bot');
|
||||||
|
this.ws.options.gateway = gateway;
|
||||||
|
|
||||||
this.ws.options.gatewayBot = {
|
this.ws.spawns();
|
||||||
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.ws.options.lastShardId = this.ws.options.gatewayBot.shards - 1;
|
|
||||||
this.ws.agent.options.totalShards = this.ws.options.gatewayBot.shards;
|
|
||||||
|
|
||||||
this.ws.shards();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// USEFUL METHODS
|
// USEFUL METHODS
|
||||||
@ -338,7 +328,7 @@ export class Session {
|
|||||||
* }
|
* }
|
||||||
*/
|
*/
|
||||||
editStatus(shardId: number, status: StatusUpdate, prio = true): void {
|
editStatus(shardId: number, status: StatusUpdate, prio = true): void {
|
||||||
const shard = this.ws.agent.shards.get(shardId);
|
const shard = this.ws.shards.get(shardId);
|
||||||
|
|
||||||
if (!shard) {
|
if (!shard) {
|
||||||
throw new Error(`Unknown shard ${shardId}`);
|
throw new Error(`Unknown shard ${shardId}`);
|
||||||
@ -350,7 +340,7 @@ export class Session {
|
|||||||
status: status.status,
|
status: status.status,
|
||||||
since: null,
|
since: null,
|
||||||
afk: false,
|
afk: false,
|
||||||
activities: status.activities.map((activity) => {
|
activities: status.activities.map(activity => {
|
||||||
return {
|
return {
|
||||||
name: activity.name,
|
name: activity.name,
|
||||||
type: activity.type,
|
type: activity.type,
|
||||||
@ -399,7 +389,7 @@ export class Session {
|
|||||||
permissions: options,
|
permissions: options,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
headers: { 'Authorization': `Bearer ${bearerToken}` },
|
headers: { Authorization: `Bearer ${bearerToken}` },
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -463,7 +453,7 @@ export class Session {
|
|||||||
guildId
|
guildId
|
||||||
? GUILD_APPLICATION_COMMANDS(this.applicationId, guildId)
|
? GUILD_APPLICATION_COMMANDS(this.applicationId, guildId)
|
||||||
: APPLICATION_COMMANDS(this.applicationId),
|
: APPLICATION_COMMANDS(this.applicationId),
|
||||||
options.map((o) =>
|
options.map(o =>
|
||||||
this.isContextApplicationCommand(o)
|
this.isContextApplicationCommand(o)
|
||||||
? {
|
? {
|
||||||
name: o.name,
|
name: o.name,
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
# @biscuitland/helpers
|
# @biscuitland/helpers
|
||||||
|
|
||||||
## 2.0.4
|
## 2.0.5
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|
||||||
- Updated dependencies
|
- Updated dependencies
|
||||||
- @biscuitland/api-types@2.0.4
|
- @biscuitland/api-types@2.0.5
|
||||||
- @biscuitland/core@2.0.4
|
- @biscuitland/core@2.0.5
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@biscuitland/helpers",
|
"name": "@biscuitland/helpers",
|
||||||
"version": "2.0.4",
|
"version": "2.0.5",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"module": "./dist/index.mjs",
|
"module": "./dist/index.mjs",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
@ -23,8 +23,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@biscuitland/api-types": "^2.0.4",
|
"@biscuitland/api-types": "^2.0.5",
|
||||||
"@biscuitland/core": "^2.0.4"
|
"@biscuitland/core": "^2.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"tsup": "^6.1.3"
|
"tsup": "^6.1.3"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# @biscuitland/rest
|
# @biscuitland/rest
|
||||||
|
|
||||||
## 2.0.4
|
## 2.0.5
|
||||||
|
|
||||||
### Major Changes
|
### Major Changes
|
||||||
|
|
||||||
@ -9,4 +9,4 @@
|
|||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|
||||||
- Updated dependencies
|
- Updated dependencies
|
||||||
- @biscuitland/api-types@2.0.4
|
- @biscuitland/api-types@2.0.5
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@biscuitland/rest",
|
"name": "@biscuitland/rest",
|
||||||
"version": "2.0.4",
|
"version": "2.0.5",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"module": "./dist/index.mjs",
|
"module": "./dist/index.mjs",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
@ -23,7 +23,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@biscuitland/api-types": "^2.0.4"
|
"@biscuitland/api-types": "^2.0.5"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"tsup": "^6.1.3"
|
"tsup": "^6.1.3"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
# @biscuitland/ws
|
# @biscuitland/ws
|
||||||
|
|
||||||
## 2.0.4
|
## 2.0.5
|
||||||
|
|
||||||
### Major Changes
|
### Major Changes
|
||||||
|
|
||||||
@ -9,4 +9,4 @@
|
|||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|
||||||
- Updated dependencies
|
- Updated dependencies
|
||||||
- @biscuitland/api-types@2.0.4
|
- @biscuitland/api-types@2.0.5
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@biscuitland/ws",
|
"name": "@biscuitland/ws",
|
||||||
"version": "2.0.4",
|
"version": "2.0.5",
|
||||||
"main": "./dist/index.js",
|
"main": "./dist/index.js",
|
||||||
"module": "./dist/index.mjs",
|
"module": "./dist/index.mjs",
|
||||||
"types": "./dist/index.d.ts",
|
"types": "./dist/index.d.ts",
|
||||||
@ -23,7 +23,8 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@biscuitland/api-types": "^2.0.4",
|
"@biscuitland/api-types": "^2.0.5",
|
||||||
|
"@sapphire/async-queue": "^1.5.0",
|
||||||
"ws": "^8.8.1"
|
"ws": "^8.8.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
@ -1,234 +0,0 @@
|
|||||||
import { createLeakyBucket } from '../utils/bucket-util';
|
|
||||||
|
|
||||||
import type { LeakyBucket } from '../utils/bucket-util';
|
|
||||||
|
|
||||||
import type { GatewayBot, PickPartial } from '@biscuitland/api-types';
|
|
||||||
import type { WsAdapter } from './ws-adapter';
|
|
||||||
|
|
||||||
import type {
|
|
||||||
Shard,
|
|
||||||
ShardGatewayConfig,
|
|
||||||
ShardOptions,
|
|
||||||
} from '../services/shard';
|
|
||||||
|
|
||||||
import { Agent } from '../services/agent';
|
|
||||||
|
|
||||||
export class DefaultWsAdapter implements WsAdapter {
|
|
||||||
static readonly DEFAULTS = {
|
|
||||||
spawnShardDelay: 5300,
|
|
||||||
|
|
||||||
shardsPerWorker: 25,
|
|
||||||
totalWorkers: 4,
|
|
||||||
|
|
||||||
gatewayBot: {
|
|
||||||
url: 'wss://gateway.discord.gg',
|
|
||||||
shards: 1,
|
|
||||||
|
|
||||||
sessionStartLimit: {
|
|
||||||
total: 1000,
|
|
||||||
remaining: 1000,
|
|
||||||
resetAfter: 0,
|
|
||||||
maxConcurrency: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
firstShardId: 0,
|
|
||||||
|
|
||||||
lastShardId: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
buckets = new Map<
|
|
||||||
number,
|
|
||||||
{
|
|
||||||
workers: { id: number; queue: number[] }[];
|
|
||||||
leak: LeakyBucket;
|
|
||||||
}
|
|
||||||
>();
|
|
||||||
|
|
||||||
options: Options;
|
|
||||||
|
|
||||||
agent: Agent;
|
|
||||||
|
|
||||||
constructor(options: DefaultWsOptions) {
|
|
||||||
this.options = Object.assign(Object.create(DefaultWsAdapter.DEFAULTS), options);
|
|
||||||
|
|
||||||
this.options.firstShardId = this.options.firstShardId ?? 0;
|
|
||||||
this.options.lastShardId = this.options.lastShardId ?? this.options.totalShards - 1 ?? 1;
|
|
||||||
|
|
||||||
this.agent = new Agent({
|
|
||||||
totalShards: this.options.totalShards ?? this.options.gatewayBot.shards ?? 1,
|
|
||||||
gatewayConfig: this.options.gatewayConfig,
|
|
||||||
createShardOptions: this.options.createShardOptions,
|
|
||||||
|
|
||||||
handleMessage: (shard: Shard, message: MessageEvent<any>) => {
|
|
||||||
return this.options.handleDiscordPayload(shard, message);
|
|
||||||
},
|
|
||||||
|
|
||||||
handleIdentify: (id: number) => {
|
|
||||||
return this.buckets.get(id % this.options.gatewayBot.sessionStartLimit.maxConcurrency)!.leak.acquire(1);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
prepareBuckets() {
|
|
||||||
for (
|
|
||||||
let i = 0;
|
|
||||||
i < this.options.gatewayBot.sessionStartLimit.maxConcurrency;
|
|
||||||
++i
|
|
||||||
) {
|
|
||||||
this.buckets.set(i, {
|
|
||||||
workers: [],
|
|
||||||
leak: createLeakyBucket({
|
|
||||||
max: 1,
|
|
||||||
refillAmount: 1,
|
|
||||||
refillInterval: this.options.spawnShardDelay,
|
|
||||||
}),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
for (
|
|
||||||
let shardId = this.options.firstShardId;
|
|
||||||
shardId <= this.options.lastShardId;
|
|
||||||
++shardId
|
|
||||||
) {
|
|
||||||
if (shardId >= this.agent.options.totalShards) {
|
|
||||||
throw new Error(
|
|
||||||
`Shard (id: ${shardId}) is bigger or equal to the used amount of used shards which is ${this.agent.options.totalShards}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const bucketId = shardId % this.options.gatewayBot.sessionStartLimit.maxConcurrency;
|
|
||||||
const bucket = this.buckets.get(bucketId);
|
|
||||||
|
|
||||||
if (!bucket) {
|
|
||||||
throw new Error(
|
|
||||||
`Shard (id: ${shardId}) got assigned to an illegal bucket id: ${bucketId}, expected a bucket id between 0 and ${
|
|
||||||
this.options.gatewayBot.sessionStartLimit
|
|
||||||
.maxConcurrency - 1
|
|
||||||
}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const workerId = this.workerId(shardId);
|
|
||||||
const worker = bucket.workers.find(w => w.id === workerId);
|
|
||||||
|
|
||||||
if (worker) {
|
|
||||||
worker.queue.push(shardId);
|
|
||||||
} else {
|
|
||||||
bucket.workers.push({ id: workerId, queue: [shardId] });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
prepareShards() {
|
|
||||||
this.buckets.forEach((bucket, bucketId) => {
|
|
||||||
for (const worker of bucket.workers) {
|
|
||||||
for (const shardId of worker.queue) {
|
|
||||||
this.workerToIdentify(worker.id, shardId, bucketId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
calculateTotalShards(): number {
|
|
||||||
if (this.agent.options.totalShards < 100) {
|
|
||||||
return this.agent.options.totalShards;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
Math.ceil(
|
|
||||||
this.agent.options.totalShards /
|
|
||||||
(this.options.gatewayBot.sessionStartLimit
|
|
||||||
.maxConcurrency === 1
|
|
||||||
? 16
|
|
||||||
: this.options.gatewayBot.sessionStartLimit
|
|
||||||
.maxConcurrency)
|
|
||||||
) * this.options.gatewayBot.sessionStartLimit.maxConcurrency
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
workerToIdentify(_workerId: number, shardId: number, _bucketId: number) {
|
|
||||||
return this.agent.identify(shardId);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
workerId(shardId: number) {
|
|
||||||
let workerId = Math.floor(shardId / this.options.shardsPerWorker);
|
|
||||||
|
|
||||||
if (workerId >= this.options.totalWorkers) {
|
|
||||||
workerId = this.options.totalWorkers - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return workerId;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
shards() {
|
|
||||||
this.prepareBuckets();
|
|
||||||
|
|
||||||
this.prepareShards();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type DefaultWsOptions = Pick<
|
|
||||||
Options,
|
|
||||||
Exclude<keyof Options, keyof typeof DefaultWsAdapter.DEFAULTS>
|
|
||||||
> &
|
|
||||||
Partial<Options>;
|
|
||||||
|
|
||||||
interface Options {
|
|
||||||
/** Delay in milliseconds to wait before spawning next shard. */
|
|
||||||
spawnShardDelay: number;
|
|
||||||
|
|
||||||
/** The amount of shards to load per worker. */
|
|
||||||
shardsPerWorker: number;
|
|
||||||
|
|
||||||
/** The total amount of workers to use for your bot. */
|
|
||||||
totalWorkers: number;
|
|
||||||
|
|
||||||
/** Total amount of shards your bot uses. Useful for zero-downtime updates or resharding. */
|
|
||||||
totalShards: number;
|
|
||||||
|
|
||||||
/** Id of the first Shard which should get controlled by this manager. */
|
|
||||||
firstShardId: number;
|
|
||||||
|
|
||||||
/** Id of the last Shard which should get controlled by this manager. */
|
|
||||||
lastShardId: number;
|
|
||||||
|
|
||||||
createShardOptions?: Omit<
|
|
||||||
ShardOptions,
|
|
||||||
'id' | 'totalShards' | 'requestIdentify' | 'gatewayConfig'
|
|
||||||
>;
|
|
||||||
|
|
||||||
/** Important data which is used by the manager to connect shards to the gateway. */
|
|
||||||
gatewayBot: GatewayBot;
|
|
||||||
|
|
||||||
// REMOVE THIS
|
|
||||||
|
|
||||||
gatewayConfig: PickPartial<ShardGatewayConfig, 'token'>;
|
|
||||||
|
|
||||||
/** Sends the discord payload to another guild. */
|
|
||||||
handleDiscordPayload: (shard: Shard, data: MessageEvent<any>) => any;
|
|
||||||
}
|
|
@ -1,29 +0,0 @@
|
|||||||
import type { Agent } from '../services/agent';
|
|
||||||
import type { GatewayBot } from '@biscuitland/api-types';
|
|
||||||
|
|
||||||
export interface WsAdapter {
|
|
||||||
options: Partial<Options | any>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
agent: Agent;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
shards(): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface Options {
|
|
||||||
/** Id of the first Shard which should get controlled by this manager. */
|
|
||||||
firstShardId: number;
|
|
||||||
|
|
||||||
/** Id of the last Shard which should get controlled by this manager. */
|
|
||||||
lastShardId: number;
|
|
||||||
|
|
||||||
/** Important data which is used by the manager to connect shards to the gateway. */
|
|
||||||
gatewayBot: GatewayBot;
|
|
||||||
}
|
|
@ -1,9 +1,2 @@
|
|||||||
export { WsAdapter } from './adapters/ws-adapter';
|
export { ShardManager } from './services/shard-manager';
|
||||||
|
|
||||||
export {
|
|
||||||
DefaultWsAdapter,
|
|
||||||
DefaultWsOptions,
|
|
||||||
} from './adapters/default-ws-adapter';
|
|
||||||
|
|
||||||
export { AgentOptions, Agent } from './services/agent';
|
|
||||||
export { Shard } from './services/shard';
|
export { Shard } from './services/shard';
|
||||||
|
@ -1,113 +0,0 @@
|
|||||||
import type { ShardGatewayConfig, ShardOptions } from './shard';
|
|
||||||
import type { PickPartial } from '@biscuitland/api-types';
|
|
||||||
|
|
||||||
import { Shard } from './shard';
|
|
||||||
|
|
||||||
export class Agent {
|
|
||||||
static readonly DEFAULTS = {
|
|
||||||
shardIds: [],
|
|
||||||
|
|
||||||
totalShards: 1,
|
|
||||||
};
|
|
||||||
|
|
||||||
options: Options;
|
|
||||||
shards: Map<number, Shard>;
|
|
||||||
|
|
||||||
constructor(options: AgentOptions) {
|
|
||||||
this.options = Object.assign(Agent.DEFAULTS, options);
|
|
||||||
|
|
||||||
const { handleIdentify } = this.options;
|
|
||||||
|
|
||||||
this.shards = new Map(
|
|
||||||
this.options.shardIds.map(id => {
|
|
||||||
const shard = new Shard({
|
|
||||||
id,
|
|
||||||
totalShards: this.options.totalShards,
|
|
||||||
gatewayConfig: this.options.gatewayConfig,
|
|
||||||
|
|
||||||
handleMessage: (shard, message) => {
|
|
||||||
return this.options.handleMessage(shard, message);
|
|
||||||
},
|
|
||||||
|
|
||||||
async handleIdentify() {
|
|
||||||
return await handleIdentify(id);
|
|
||||||
},
|
|
||||||
|
|
||||||
...this.options.createShardOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
return [id, shard] as const;
|
|
||||||
})
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
async identify(id: number) {
|
|
||||||
// @ts-ignore
|
|
||||||
let shard = this.shards.get(id);
|
|
||||||
|
|
||||||
if (!shard) {
|
|
||||||
const { handleIdentify } = this.options;
|
|
||||||
|
|
||||||
shard = new Shard({
|
|
||||||
id,
|
|
||||||
totalShards: this.options.totalShards,
|
|
||||||
gatewayConfig: this.options.gatewayConfig,
|
|
||||||
|
|
||||||
handleMessage: (shard, message) => {
|
|
||||||
return this.options.handleMessage(shard, message);
|
|
||||||
},
|
|
||||||
|
|
||||||
async handleIdentify() {
|
|
||||||
return await handleIdentify(id);
|
|
||||||
},
|
|
||||||
|
|
||||||
...this.options.createShardOptions,
|
|
||||||
});
|
|
||||||
|
|
||||||
this.shards.set(id, shard);
|
|
||||||
}
|
|
||||||
|
|
||||||
return await shard.identify();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @inheritDoc
|
|
||||||
*/
|
|
||||||
|
|
||||||
async scale() {
|
|
||||||
//
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export type AgentOptions = Pick<
|
|
||||||
Options,
|
|
||||||
Exclude<keyof Options, keyof typeof Agent.DEFAULTS>
|
|
||||||
> &
|
|
||||||
Partial<Options>;
|
|
||||||
|
|
||||||
interface Options {
|
|
||||||
/** Ids of the Shards which should be managed. */
|
|
||||||
shardIds: number[];
|
|
||||||
|
|
||||||
/** Total amount of Shard used by the bot. */
|
|
||||||
totalShards: number;
|
|
||||||
|
|
||||||
/** Options which are used to create a new Shard. */
|
|
||||||
createShardOptions?: Omit<
|
|
||||||
ShardOptions,
|
|
||||||
'id' | 'totalShards' | 'requestIdentify' | 'gatewayConfig'
|
|
||||||
>;
|
|
||||||
|
|
||||||
/** Gateway configuration which is used when creating a Shard. */
|
|
||||||
gatewayConfig: PickPartial<ShardGatewayConfig, 'token'>;
|
|
||||||
|
|
||||||
/** Sends the discord payload to another guild. */
|
|
||||||
handleMessage: (shard: Shard, data: MessageEvent<any>) => any;
|
|
||||||
|
|
||||||
/** This function communicates with the parent manager. */
|
|
||||||
handleIdentify(shardId: number): Promise<void>;
|
|
||||||
}
|
|
121
packages/ws/src/services/shard-manager.ts
Normal file
121
packages/ws/src/services/shard-manager.ts
Normal file
@ -0,0 +1,121 @@
|
|||||||
|
import type { ShardManagerOptions, SMO } from '../types';
|
||||||
|
import type { LeakyBucket } from '../utils/bucket';
|
||||||
|
|
||||||
|
import { Shard } from './shard';
|
||||||
|
|
||||||
|
import { createLeakyBucket } from '../utils/bucket';
|
||||||
|
import { Options } from '../utils/options';
|
||||||
|
|
||||||
|
export class ShardManager {
|
||||||
|
static readonly DEFAULTS = {
|
||||||
|
workers: {
|
||||||
|
shards: 25,
|
||||||
|
amount: 5,
|
||||||
|
delay: 5000
|
||||||
|
},
|
||||||
|
|
||||||
|
shards: {
|
||||||
|
timeout: 15000,
|
||||||
|
delay: 5000
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
readonly options: SMO;
|
||||||
|
|
||||||
|
readonly buckets = new Map<
|
||||||
|
number,
|
||||||
|
{
|
||||||
|
workers: { id: number; queue: number[] }[];
|
||||||
|
leak: LeakyBucket;
|
||||||
|
}
|
||||||
|
>();
|
||||||
|
|
||||||
|
readonly shards = new Map<number, Shard>();
|
||||||
|
|
||||||
|
constructor(options: ShardManagerOptions) {
|
||||||
|
this.options = Options({}, ShardManager.DEFAULTS, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Invokes internal processing and respawns shards */
|
||||||
|
async respawns(): Promise<void> {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Invoke internal processing and spawns shards */
|
||||||
|
async spawns(): Promise<void> {
|
||||||
|
const { gateway, workers } = this.options;
|
||||||
|
|
||||||
|
/** Creates the necessary buckets according to concurrency */
|
||||||
|
for (let i = 0; i < gateway.session_start_limit.max_concurrency; i++) {
|
||||||
|
this.buckets.set(i, {
|
||||||
|
workers: [],
|
||||||
|
leak: createLeakyBucket({
|
||||||
|
max: 1,
|
||||||
|
refillAmount: 1,
|
||||||
|
refillInterval: workers.delay,
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Create the start sequence of the shards inside the buckets. */
|
||||||
|
for (let i = 0; i < gateway.shards; i++) {
|
||||||
|
const bucketID = i % gateway.session_start_limit.max_concurrency;
|
||||||
|
const bucket = this.buckets.get(bucketID);
|
||||||
|
|
||||||
|
if (bucket) {
|
||||||
|
const workerID = Math.floor(i / workers.shards);
|
||||||
|
const worker = bucket.workers.find(w => w.id === workerID);
|
||||||
|
|
||||||
|
if (worker) {
|
||||||
|
worker.queue.push(i);
|
||||||
|
} else {
|
||||||
|
bucket.workers.push({ id: workerID, queue: [i] });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Route all shards to workers */
|
||||||
|
this.buckets.forEach(async bucket => {
|
||||||
|
for (const worker of bucket.workers) {
|
||||||
|
|
||||||
|
for (const id of worker.queue) {
|
||||||
|
await this.connect(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Invokes the bucket to prepare the connection to the shard */
|
||||||
|
private async connect(id: number): Promise<Shard> {
|
||||||
|
const { gateway } = this.options;
|
||||||
|
|
||||||
|
let shard = this.shards.get(id);
|
||||||
|
|
||||||
|
if (!shard) {
|
||||||
|
shard = new Shard({
|
||||||
|
id,
|
||||||
|
|
||||||
|
gateway: this.options.gateway,
|
||||||
|
|
||||||
|
shards: this.options.shards,
|
||||||
|
|
||||||
|
config: this.options.config,
|
||||||
|
|
||||||
|
handlePayloads: async (shard, payload) => {
|
||||||
|
await this.options.handleDiscordPayload(shard, payload); // remove await?
|
||||||
|
},
|
||||||
|
|
||||||
|
handleIdentify: async (id: number) => {
|
||||||
|
await this.buckets.get(id % gateway.session_start_limit.max_concurrency)!.leak.acquire(1); // remove await?
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.shards.set(id, shard);
|
||||||
|
}
|
||||||
|
|
||||||
|
await shard.connect();
|
||||||
|
|
||||||
|
return shard;
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
91
packages/ws/src/types.ts
Normal file
91
packages/ws/src/types.ts
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
import type { DiscordGatewayPayload, DiscordGetGatewayBot, GatewayIntents } from '@biscuitland/api-types';
|
||||||
|
|
||||||
|
import type { ShardManager } from './services/shard-manager';
|
||||||
|
import type { Shard } from './services/shard';
|
||||||
|
|
||||||
|
/** ShardManager */
|
||||||
|
|
||||||
|
export type ShardManagerOptions = Pick<SMO, Exclude<keyof SMO, keyof typeof ShardManager.DEFAULTS>> & Partial<SMO>;
|
||||||
|
|
||||||
|
export interface SMO {
|
||||||
|
/** Function for interpretation of messages from discord */
|
||||||
|
handleDiscordPayload: (shard: Shard, payload: DiscordGatewayPayload) => unknown;
|
||||||
|
|
||||||
|
/** Based on the information in Get Gateway */
|
||||||
|
gateway: DiscordGetGatewayBot;
|
||||||
|
|
||||||
|
/** Workers options */
|
||||||
|
workers: ShardManagerWorkersOptions;
|
||||||
|
|
||||||
|
/** Authentication */
|
||||||
|
config: {
|
||||||
|
intents?: GatewayIntents;
|
||||||
|
token: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Options shards */
|
||||||
|
shards: ShardManagerShardsOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ShardManagerWorkersOptions {
|
||||||
|
/**
|
||||||
|
* Number of shards per worker
|
||||||
|
* @default 25
|
||||||
|
*/
|
||||||
|
shards: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Number of workers
|
||||||
|
* @default 5
|
||||||
|
*/
|
||||||
|
amount: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waiting time between workers
|
||||||
|
* @default 5000
|
||||||
|
*/
|
||||||
|
delay: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ShardManagerShardsOptions {
|
||||||
|
/**
|
||||||
|
* Waiting time to receive the ready event.
|
||||||
|
* @default 15000
|
||||||
|
*/
|
||||||
|
timeout: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Waiting time between shards
|
||||||
|
* @default 5000
|
||||||
|
*/
|
||||||
|
delay: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Shard */
|
||||||
|
|
||||||
|
export type ShardOptions = Pick<SO, Exclude<keyof SO, keyof typeof Shard.DEFAULTS>> & Partial<SO>;
|
||||||
|
|
||||||
|
export interface SO {
|
||||||
|
/** Shard Id */
|
||||||
|
id: number;
|
||||||
|
|
||||||
|
/** Based on the information in Get Gateway */
|
||||||
|
gateway: DiscordGetGatewayBot;
|
||||||
|
|
||||||
|
/** Options shards */
|
||||||
|
shards: ShardManagerShardsOptions;
|
||||||
|
|
||||||
|
/** Authentication */
|
||||||
|
config: {
|
||||||
|
intents?: GatewayIntents;
|
||||||
|
token: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Function for interpretation of messages from discord */
|
||||||
|
handlePayloads: (shard: Shard, data: DiscordGatewayPayload) => Promise<void>;
|
||||||
|
|
||||||
|
/** Notify the manager if the shard is ready. */
|
||||||
|
handleIdentify: (id: number) => Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ShardStatus = 'Disconnected' | 'Handshaking' | 'Connecting' | 'Heartbeating' | 'Identifying' | 'Resuming' | 'Ready';
|
@ -1,4 +1,4 @@
|
|||||||
/** unnecessary */
|
/** Create from scratch */
|
||||||
|
|
||||||
import type { PickPartial } from '@biscuitland/api-types';
|
import type { PickPartial } from '@biscuitland/api-types';
|
||||||
|
|
42
packages/ws/src/utils/options.ts
Normal file
42
packages/ws/src/utils/options.ts
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
const isPlainObject = (value: any) => {
|
||||||
|
return (
|
||||||
|
value !== null
|
||||||
|
&& typeof value === 'object'
|
||||||
|
&& typeof value.constructor === 'function'
|
||||||
|
// eslint-disable-next-line no-prototype-builtins
|
||||||
|
&& (value.constructor.prototype.hasOwnProperty('isPrototypeOf') || Object.getPrototypeOf(value.constructor.prototype) === null)
|
||||||
|
)
|
||||||
|
|| (value && Object.getPrototypeOf(value) === null);
|
||||||
|
};
|
||||||
|
|
||||||
|
const isObject = (o: any) => {
|
||||||
|
return !!o && typeof o === 'object' && !Array.isArray(o);
|
||||||
|
};
|
||||||
|
|
||||||
|
export const Options = (defaults: any, ...options: any[]): any => {
|
||||||
|
if (!options.length) {
|
||||||
|
return defaults;
|
||||||
|
}
|
||||||
|
|
||||||
|
const source = options.shift();
|
||||||
|
|
||||||
|
if (isObject(defaults) && isPlainObject(source)) {
|
||||||
|
Object.entries(source).forEach(([key, value]) => {
|
||||||
|
if (typeof value === 'undefined') {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isPlainObject(value)) {
|
||||||
|
if (!(key in defaults)) {
|
||||||
|
Object.assign(defaults, { [key]: {} });
|
||||||
|
}
|
||||||
|
|
||||||
|
Options(defaults[key], value);
|
||||||
|
} else {
|
||||||
|
Object.assign(defaults, { [key]: value });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return Options(defaults, ...options);
|
||||||
|
};
|
@ -1,18 +0,0 @@
|
|||||||
/** unnecessary */
|
|
||||||
|
|
||||||
import type { Shard } from '../services/shard';
|
|
||||||
|
|
||||||
export async function checkOffline(
|
|
||||||
shard: Shard,
|
|
||||||
highPriority: boolean
|
|
||||||
): Promise<void> {
|
|
||||||
if (!shard.isOpen()) {
|
|
||||||
await new Promise(resolve => {
|
|
||||||
if (highPriority) {
|
|
||||||
shard.offlineSendQueue.unshift(resolve);
|
|
||||||
} else {
|
|
||||||
shard.offlineSendQueue.push(resolve);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user