Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: @discordjs/redis-gateway #9541

Open
wants to merge 12 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Expand Up @@ -20,6 +20,7 @@
/packages/next/ @discordjs/core
/packages/proxy/ @discordjs/proxy
/packages/proxy-container/ @discordjs/proxy
/packages/redis-gateway/ @discordjs/brokers @discordjs/core @discordjs/ws
/packages/rest/ @discordjs/rest
/packages/scripts/ @discordjs/scripts
/packages/ui/ @discordjs/ui
Expand Down
3 changes: 3 additions & 0 deletions .github/issue-labeler.yml
Expand Up @@ -34,6 +34,9 @@ packages:proxy:
packages:proxy-container:
- "### Which (application|package|application or package) is this (bug
report|feature request) for\\?\\n\\nproxy-container\\n"
packages:redis-gateway:
- "### Which (application|package|application or package) is this (bug
report|feature request) for\\?\\n\\nredis-gateway\\n"
packages:rest:
- "### Which (application|package|application or package) is this (bug
report|feature request) for\\?\\n\\nrest\\n"
Expand Down
3 changes: 3 additions & 0 deletions .github/labeler.yml
Expand Up @@ -37,6 +37,9 @@ packages:proxy:
packages:proxy-container:
- packages/proxy-container/*
- packages/proxy-container/**/*
packages:redis-gateway:
- packages/redis-gateway/*
- packages/redis-gateway/**/*
packages:rest:
- packages/rest/*
- packages/rest/**/*
Expand Down
2 changes: 2 additions & 0 deletions .github/labels.yml
Expand Up @@ -74,6 +74,8 @@
color: fbca04
- name: packages:proxy-container
color: fbca04
- name: packages:redis-gateway
color: fbca04
- name: packages:rest
color: fbca04
- name: packages:ui
Expand Down
10 changes: 9 additions & 1 deletion .github/workflows/publish-dev-docker.yml
Expand Up @@ -6,6 +6,14 @@ on:
jobs:
docker-publish:
name: Docker publish
strategy:
fail-fast: false
matrix:
include:
- package: '@discordjs/proxy-container'
image: 'proxy-container'
- package: '@discordjs/redis-gateway'
image: 'redis-gateway'
runs-on: ubuntu-latest
if: github.repository_owner == 'discordjs'
steps:
Expand All @@ -30,4 +38,4 @@ jobs:
run: echo ${{ secrets.DOCKER_ACCESS_TOKEN }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin

- name: Build & push docker image
run: yarn docker build --buildkit @discordjs/proxy-container -t discordjs/proxy:latest --push
run: yarn docker build --buildkit ${{ matrix.package }} -t discordjs/${{ matrix.image }}:latest --push
12 changes: 11 additions & 1 deletion .github/workflows/publish-docker.yml
Expand Up @@ -4,6 +4,16 @@ on:
jobs:
docker-publish:
name: Docker publish
strategy:
fail-fast: false
matrix:
include:
- package: '@discordjs/proxy-container'
folder: 'proxy-container'
image: 'proxy-container'
- package: '@discordjs/redis-gateway'
folder: 'redis-gateway'
image: 'redis-gateway'
runs-on: ubuntu-latest
steps:
- name: Checkout repository
Expand All @@ -27,4 +37,4 @@ jobs:
run: echo ${{ secrets.DOCKER_ACCESS_TOKEN }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin

- name: Build & push docker image
run: yarn docker build --buildkit @discordjs/proxy-container -t discordjs/proxy:$(cut -d '.' -f1 <<< $(jq --raw-output '.version' packages/proxy-container/package.json)) --push
run: yarn docker build --buildkit ${{ matrix.package }} -t discordjs/${{ matrix.image }}:$(cut -d '.' -f1 <<< $(jq --raw-output '.version' packages/${{ matrix.folder }}/package.json)) --push
2 changes: 1 addition & 1 deletion packages/brokers/LICENSE
Expand Up @@ -176,7 +176,7 @@
END OF TERMS AND CONDITIONS

Copyright 2022 Noel Buechler
Copyright 2022 Charlotte Cristea
Copyright 2022 Denis Cristea

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
1 change: 1 addition & 0 deletions packages/core/package.json
Expand Up @@ -54,6 +54,7 @@
},
"homepage": "https://discord.js.org",
"dependencies": {
"@discordjs/brokers": "workspace:^",
"@discordjs/rest": "workspace:^",
"@discordjs/util": "workspace:^",
"@discordjs/ws": "workspace:^",
Expand Down
162 changes: 22 additions & 140 deletions packages/core/src/client.ts
Expand Up @@ -4,75 +4,16 @@ import { calculateShardId } from '@discordjs/util';
import { WebSocketShardEvents } from '@discordjs/ws';
import { DiscordSnowflake } from '@sapphire/snowflake';
import { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';
import {
GatewayDispatchEvents,
GatewayOpcodes,
type APIGuildMember,
type GatewayAutoModerationActionExecutionDispatchData,
type GatewayAutoModerationRuleCreateDispatchData,
type GatewayAutoModerationRuleDeleteDispatchData,
type GatewayAutoModerationRuleUpdateDispatchData,
type GatewayChannelCreateDispatchData,
type GatewayChannelDeleteDispatchData,
type GatewayChannelPinsUpdateDispatchData,
type GatewayChannelUpdateDispatchData,
type GatewayGuildAuditLogEntryCreateDispatchData,
type GatewayGuildBanAddDispatchData,
type GatewayGuildBanRemoveDispatchData,
type GatewayGuildCreateDispatchData,
type GatewayGuildDeleteDispatchData,
type GatewayGuildEmojisUpdateDispatchData,
type GatewayGuildIntegrationsUpdateDispatchData,
type GatewayGuildMemberAddDispatchData,
type GatewayGuildMemberRemoveDispatchData,
type GatewayGuildMemberUpdateDispatchData,
type GatewayGuildMembersChunkDispatchData,
type GatewayGuildRoleCreateDispatchData,
type GatewayGuildRoleDeleteDispatchData,
type GatewayGuildRoleUpdateDispatchData,
type GatewayGuildScheduledEventCreateDispatchData,
type GatewayGuildScheduledEventDeleteDispatchData,
type GatewayGuildScheduledEventUpdateDispatchData,
type GatewayGuildScheduledEventUserAddDispatchData,
type GatewayGuildScheduledEventUserRemoveDispatchData,
type GatewayGuildStickersUpdateDispatchData,
type GatewayGuildUpdateDispatchData,
type GatewayIntegrationCreateDispatchData,
type GatewayIntegrationDeleteDispatchData,
type GatewayIntegrationUpdateDispatchData,
type GatewayInteractionCreateDispatchData,
type GatewayInviteCreateDispatchData,
type GatewayInviteDeleteDispatchData,
type GatewayMessageCreateDispatchData,
type GatewayMessageDeleteBulkDispatchData,
type GatewayMessageDeleteDispatchData,
type GatewayMessageReactionAddDispatchData,
type GatewayMessageReactionRemoveAllDispatchData,
type GatewayMessageReactionRemoveDispatchData,
type GatewayMessageReactionRemoveEmojiDispatchData,
type GatewayMessageUpdateDispatchData,
type GatewayPresenceUpdateData,
type GatewayPresenceUpdateDispatchData,
type GatewayReadyDispatchData,
type GatewayRequestGuildMembersData,
type GatewayStageInstanceCreateDispatchData,
type GatewayStageInstanceDeleteDispatchData,
type GatewayStageInstanceUpdateDispatchData,
type GatewayThreadCreateDispatchData,
type GatewayThreadDeleteDispatchData,
type GatewayThreadListSyncDispatchData,
type GatewayThreadMemberUpdateDispatchData,
type GatewayThreadMembersUpdateDispatchData,
type GatewayThreadUpdateDispatchData,
type GatewayTypingStartDispatchData,
type GatewayUserUpdateDispatchData,
type GatewayVoiceServerUpdateDispatchData,
type GatewayVoiceStateUpdateData,
type GatewayVoiceStateUpdateDispatchData,
type GatewayWebhooksUpdateDispatchData,
import { GatewayDispatchEvents, GatewayOpcodes } from 'discord-api-types/v10';
import type {
GatewayDispatchPayload,
APIGuildMember,
GatewayRequestGuildMembersData,
GatewayPresenceUpdateData,
GatewayVoiceStateUpdateData,
} from 'discord-api-types/v10';
import type { Gateway } from './Gateway.js';
import { API } from './api/index.js';
import type { Gateway } from './gateway/Gateway.js';

export interface IntrinsicProps {
/**
Expand All @@ -89,87 +30,28 @@ export interface WithIntrinsicProps<T> extends IntrinsicProps {
data: T;
}

export interface MappedEvents {
[GatewayDispatchEvents.AutoModerationActionExecution]: [
WithIntrinsicProps<GatewayAutoModerationActionExecutionDispatchData>,
];
[GatewayDispatchEvents.AutoModerationRuleCreate]: [WithIntrinsicProps<GatewayAutoModerationRuleCreateDispatchData>];
[GatewayDispatchEvents.AutoModerationRuleDelete]: [WithIntrinsicProps<GatewayAutoModerationRuleDeleteDispatchData>];
[GatewayDispatchEvents.AutoModerationRuleUpdate]: [WithIntrinsicProps<GatewayAutoModerationRuleUpdateDispatchData>];
[GatewayDispatchEvents.ChannelCreate]: [WithIntrinsicProps<GatewayChannelCreateDispatchData>];
[GatewayDispatchEvents.ChannelDelete]: [WithIntrinsicProps<GatewayChannelDeleteDispatchData>];
[GatewayDispatchEvents.ChannelPinsUpdate]: [WithIntrinsicProps<GatewayChannelPinsUpdateDispatchData>];
[GatewayDispatchEvents.ChannelUpdate]: [WithIntrinsicProps<GatewayChannelUpdateDispatchData>];
[GatewayDispatchEvents.GuildAuditLogEntryCreate]: [WithIntrinsicProps<GatewayGuildAuditLogEntryCreateDispatchData>];
[GatewayDispatchEvents.GuildBanAdd]: [WithIntrinsicProps<GatewayGuildBanAddDispatchData>];
[GatewayDispatchEvents.GuildBanRemove]: [WithIntrinsicProps<GatewayGuildBanRemoveDispatchData>];
[GatewayDispatchEvents.GuildCreate]: [WithIntrinsicProps<GatewayGuildCreateDispatchData>];
[GatewayDispatchEvents.GuildDelete]: [WithIntrinsicProps<GatewayGuildDeleteDispatchData>];
[GatewayDispatchEvents.GuildEmojisUpdate]: [WithIntrinsicProps<GatewayGuildEmojisUpdateDispatchData>];
[GatewayDispatchEvents.GuildIntegrationsUpdate]: [WithIntrinsicProps<GatewayGuildIntegrationsUpdateDispatchData>];
[GatewayDispatchEvents.GuildMemberAdd]: [WithIntrinsicProps<GatewayGuildMemberAddDispatchData>];
[GatewayDispatchEvents.GuildMemberRemove]: [WithIntrinsicProps<GatewayGuildMemberRemoveDispatchData>];
[GatewayDispatchEvents.GuildMemberUpdate]: [WithIntrinsicProps<GatewayGuildMemberUpdateDispatchData>];
[GatewayDispatchEvents.GuildMembersChunk]: [WithIntrinsicProps<GatewayGuildMembersChunkDispatchData>];
[GatewayDispatchEvents.GuildRoleCreate]: [WithIntrinsicProps<GatewayGuildRoleCreateDispatchData>];
[GatewayDispatchEvents.GuildRoleDelete]: [WithIntrinsicProps<GatewayGuildRoleDeleteDispatchData>];
[GatewayDispatchEvents.GuildRoleUpdate]: [WithIntrinsicProps<GatewayGuildRoleUpdateDispatchData>];
[GatewayDispatchEvents.GuildScheduledEventCreate]: [WithIntrinsicProps<GatewayGuildScheduledEventCreateDispatchData>];
[GatewayDispatchEvents.GuildScheduledEventDelete]: [WithIntrinsicProps<GatewayGuildScheduledEventDeleteDispatchData>];
[GatewayDispatchEvents.GuildScheduledEventUpdate]: [WithIntrinsicProps<GatewayGuildScheduledEventUpdateDispatchData>];
[GatewayDispatchEvents.GuildScheduledEventUserAdd]: [
WithIntrinsicProps<GatewayGuildScheduledEventUserAddDispatchData>,
];
[GatewayDispatchEvents.GuildScheduledEventUserRemove]: [
WithIntrinsicProps<GatewayGuildScheduledEventUserRemoveDispatchData>,
];
[GatewayDispatchEvents.GuildStickersUpdate]: [WithIntrinsicProps<GatewayGuildStickersUpdateDispatchData>];
[GatewayDispatchEvents.GuildUpdate]: [WithIntrinsicProps<GatewayGuildUpdateDispatchData>];
[GatewayDispatchEvents.IntegrationCreate]: [WithIntrinsicProps<GatewayIntegrationCreateDispatchData>];
[GatewayDispatchEvents.IntegrationDelete]: [WithIntrinsicProps<GatewayIntegrationDeleteDispatchData>];
[GatewayDispatchEvents.IntegrationUpdate]: [WithIntrinsicProps<GatewayIntegrationUpdateDispatchData>];
[GatewayDispatchEvents.InteractionCreate]: [WithIntrinsicProps<GatewayInteractionCreateDispatchData>];
[GatewayDispatchEvents.InviteCreate]: [WithIntrinsicProps<GatewayInviteCreateDispatchData>];
[GatewayDispatchEvents.InviteDelete]: [WithIntrinsicProps<GatewayInviteDeleteDispatchData>];
[GatewayDispatchEvents.MessageCreate]: [WithIntrinsicProps<GatewayMessageCreateDispatchData>];
[GatewayDispatchEvents.MessageDelete]: [WithIntrinsicProps<GatewayMessageDeleteDispatchData>];
[GatewayDispatchEvents.MessageDeleteBulk]: [WithIntrinsicProps<GatewayMessageDeleteBulkDispatchData>];
[GatewayDispatchEvents.MessageReactionAdd]: [WithIntrinsicProps<GatewayMessageReactionAddDispatchData>];
[GatewayDispatchEvents.MessageReactionRemove]: [WithIntrinsicProps<GatewayMessageReactionRemoveDispatchData>];
[GatewayDispatchEvents.MessageReactionRemoveAll]: [WithIntrinsicProps<GatewayMessageReactionRemoveAllDispatchData>];
[GatewayDispatchEvents.MessageReactionRemoveEmoji]: [
WithIntrinsicProps<GatewayMessageReactionRemoveEmojiDispatchData>,
];
[GatewayDispatchEvents.MessageUpdate]: [WithIntrinsicProps<GatewayMessageUpdateDispatchData>];
[GatewayDispatchEvents.PresenceUpdate]: [WithIntrinsicProps<GatewayPresenceUpdateDispatchData>];
[GatewayDispatchEvents.Ready]: [WithIntrinsicProps<GatewayReadyDispatchData>];
[GatewayDispatchEvents.Resumed]: [WithIntrinsicProps<never>];
[GatewayDispatchEvents.StageInstanceCreate]: [WithIntrinsicProps<GatewayStageInstanceCreateDispatchData>];
[GatewayDispatchEvents.StageInstanceDelete]: [WithIntrinsicProps<GatewayStageInstanceDeleteDispatchData>];
[GatewayDispatchEvents.StageInstanceUpdate]: [WithIntrinsicProps<GatewayStageInstanceUpdateDispatchData>];
[GatewayDispatchEvents.ThreadCreate]: [WithIntrinsicProps<GatewayThreadCreateDispatchData>];
[GatewayDispatchEvents.ThreadDelete]: [WithIntrinsicProps<GatewayThreadDeleteDispatchData>];
[GatewayDispatchEvents.ThreadListSync]: [WithIntrinsicProps<GatewayThreadListSyncDispatchData>];
[GatewayDispatchEvents.ThreadMemberUpdate]: [WithIntrinsicProps<GatewayThreadMemberUpdateDispatchData>];
[GatewayDispatchEvents.ThreadMembersUpdate]: [WithIntrinsicProps<GatewayThreadMembersUpdateDispatchData>];
[GatewayDispatchEvents.ThreadUpdate]: [WithIntrinsicProps<GatewayThreadUpdateDispatchData>];
[GatewayDispatchEvents.TypingStart]: [WithIntrinsicProps<GatewayTypingStartDispatchData>];
[GatewayDispatchEvents.UserUpdate]: [WithIntrinsicProps<GatewayUserUpdateDispatchData>];
[GatewayDispatchEvents.VoiceServerUpdate]: [WithIntrinsicProps<GatewayVoiceServerUpdateDispatchData>];
[GatewayDispatchEvents.VoiceStateUpdate]: [WithIntrinsicProps<GatewayVoiceStateUpdateDispatchData>];
[GatewayDispatchEvents.WebhooksUpdate]: [WithIntrinsicProps<GatewayWebhooksUpdateDispatchData>];
}
// need this to be its own type for some reason, the compiler doesn't behave the same way if we in-line it
type _DiscordEvents = {
[K in GatewayDispatchEvents]: GatewayDispatchPayload & {
t: K;
};
};

export type DiscordEvents = {
// @ts-expect-error - unclear why this is an error, this behaves as expected
[K in keyof _DiscordEvents]: _DiscordEvents[K]['d'];
};

export type ManagerShardEventsMap = {
[K in keyof MappedEvents]: MappedEvents[K];
export type MappedEvents = {
[K in keyof DiscordEvents]: [WithIntrinsicProps<DiscordEvents[K]>];
};

export interface ClientOptions {
gateway: Gateway;
rest: REST;
}

export class Client extends AsyncEventEmitter<ManagerShardEventsMap> {
export class Client extends AsyncEventEmitter<MappedEvents> {
public readonly rest: REST;

public readonly gateway: Gateway;
Expand Down
Expand Up @@ -2,11 +2,17 @@ import type { Awaitable } from '@discordjs/util';
import type { ManagerShardEventsMap, WebSocketShardEvents } from '@discordjs/ws';
import type { GatewaySendPayload } from 'discord-api-types/v10';

/**
* A Discord gateway-like interface that can be used to send & recieve events.
didinele marked this conversation as resolved.
Show resolved Hide resolved
*/
export interface Gateway {
getShardCount(): Awaitable<number>;
on(
event: WebSocketShardEvents.Dispatch,
listener: (...params: ManagerShardEventsMap[WebSocketShardEvents.Dispatch]) => Awaitable<void>,
): this;
/**
* Sends a payload to the specified shard
*/
send(shardId: number, payload: GatewaySendPayload): Awaitable<void>;
}
50 changes: 50 additions & 0 deletions packages/core/src/gateway/RedisGateway.ts
@@ -0,0 +1,50 @@
import type { PubSubRedisBroker } from '@discordjs/brokers';
import type { ManagerShardEventsMap, WebSocketShardEvents } from '@discordjs/ws';
import { AsyncEventEmitter } from '@vladfrangu/async_event_emitter';
import type { GatewaySendPayload, GatewayDispatchEvents } from 'discord-api-types/v10';
import type { DiscordEvents } from '../client.js';
import type { Gateway } from './Gateway.js';

interface BrokerIntrinsicProps {
shardId: number;
}

interface Events extends DiscordEvents {
gateway_send: GatewaySendPayload;
}

export type RedisBrokerDiscordEvents = {
[K in keyof Events]: BrokerIntrinsicProps & { payload: Events[K] };
};

export class RedisGateway
extends AsyncEventEmitter<{ dispatch: ManagerShardEventsMap[WebSocketShardEvents.Dispatch] }>
implements Gateway
{
public constructor(
private readonly broker: PubSubRedisBroker<RedisBrokerDiscordEvents>,
private readonly shardCount: number,
) {
super();
}

public getShardCount(): number {
return this.shardCount;
}

public async send(shardId: number, payload: GatewaySendPayload): Promise<void> {
await this.broker.publish('gateway_send', { payload, shardId });
}

public async init(group: string, events: GatewayDispatchEvents[]) {
for (const event of events) {
this.broker.on(event, ({ data: { payload, shardId }, ack }) => {
// @ts-expect-error - Union shenanigans
this.emit('dispatch', { shardId, data: payload });
void ack();
});
}

await this.broker.subscribe(group, events);
}
}
4 changes: 3 additions & 1 deletion packages/core/src/index.ts
@@ -1,6 +1,8 @@
export * from './api/index.js';
export * from './client.js';
export * from './gateway/Gateway.js';
export * from './gateway/RedisGateway.js';
export * from './util/index.js';
export * from './client.js';

export * from 'discord-api-types/v10';

Expand Down
2 changes: 1 addition & 1 deletion packages/proxy-container/LICENSE
Expand Up @@ -176,7 +176,7 @@
END OF TERMS AND CONDITIONS

Copyright 2022 Noel Buechler
Copyright 2022 Charlotte Cristea
Copyright 2022 Denis Cristea

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down
1 change: 0 additions & 1 deletion packages/proxy-container/README.md
Expand Up @@ -55,7 +55,6 @@ Webhooks with tokens or other requests that don't include the Authorization head
## Links

- [Website][website] ([source][website-source])
- [Documentation][documentation]
- [Guide][guide] ([source][guide-source])
Also see the v13 to v14 [Update Guide][guide-update], which includes updated and removed items from the library.
- [discord.js Discord server][discord]
Expand Down
3 changes: 0 additions & 3 deletions packages/proxy-container/tsconfig.json
@@ -1,7 +1,4 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"skipLibCheck": true
},
"include": ["src/**/*.ts"]
}
2 changes: 1 addition & 1 deletion packages/proxy/LICENSE
Expand Up @@ -176,7 +176,7 @@
END OF TERMS AND CONDITIONS

Copyright 2022 Noel Buechler
Copyright 2022 Charlotte Cristea
Copyright 2022 Denis Cristea

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down