Skip to content
This repository was archived by the owner on Feb 12, 2025. It is now read-only.

Commit

Permalink
✨ Added simple discord integration
Browse files Browse the repository at this point in the history
  • Loading branch information
ZickZenni committed Aug 28, 2024
1 parent 0c910f8 commit 598a7f5
Show file tree
Hide file tree
Showing 13 changed files with 913 additions and 0 deletions.
163 changes: 163 additions & 0 deletions src/common/discord/channel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import BaseDiscordApi from './client/basediscordapi';
import { IUser, User } from './user';

export interface IconEmoji {
name: string;
id: any;
}

export enum ChannelType {
GuildText = 0,
DirectMessage = 1,
GuildVoice = 2,
GroupDirectMessage = 3,
GuildCategory = 4,
GuildAnnouncement = 5,
AnnouncementThread = 10,
PublicThread = 11,
PrivateThread = 12,
GuildStageVoice = 13,
GuildDirectory = 14,
GuildForum = 15,
GuildMedia = 16,
}

export interface IChannel {
version: number;
type: number;
topic: any;
rate_limit_per_user: number;
position: number;
permission_overwrites: string[][];
parent_id?: string;
nsfw: boolean;
name: string;
last_pin_timestamp: string;
last_message_id: string;
id: string;
icon_emoji: IconEmoji;
flags: number;
}

export interface Attachment {
id: string;
filename: string;
size: number;
url: string;
proxy_url: string;
width: number;
height: number;
content_type: string;
content_scan_version: number;
placeholder: string;
placeholder_version: number;
}

export interface ChannelMessage {
type: number;
content: string;
mentions: User[];
mention_roles: any[];
attachments: Attachment[];
embeds: string[][];
timestamp: string;
edited_timestamp: any;
flags: number;
components: any[];
id: string;
channel_id: string;
author: IUser;
pinned: boolean;
mention_everyone: boolean;
tts: boolean;
}

export default class Channel {
public readonly id: string;

public name: string;

public readonly guildId: string;

public readonly type: ChannelType;

public readonly parentId: string | null;

public position: number;

public lastCheckedMessages: number = 0;

public cachedMessages: ChannelMessage[] = [];

public constructor(data: IChannel, guildId: string) {
this.id = data.id;
this.name = data.name;
this.type = data.type;
this.parentId = data.parent_id ?? null;
this.position = data.position;
this.guildId = guildId;
}

public async getMessages(discord: BaseDiscordApi): Promise<ChannelMessage[]> {
if (this.type !== ChannelType.GuildText) return [];

// Retrieve and cache messages if we were not in the channel for the last 15 minutes
if (Date.now() - this.lastCheckedMessages >= 1000 * 60 * 15) {
console.log(
`[Discord/Channel] Updating messages from channel '${this.id}'`,
);
this.cachedMessages = await this.retrieveMessages(discord);
}

this.lastCheckedMessages = Date.now();
return this.cachedMessages;
}

private async retrieveMessages(
discord: BaseDiscordApi,
): Promise<ChannelMessage[]> {
if (this.type !== ChannelType.GuildText) return [];

try {
const response = await fetch(
`https://discord.com/api/v10/channels/${this.id}/messages?limit=50`,
{
headers: {
Authorization: discord.token,
},
},
);
const json = await response.json();
if (json.message) return [];
return json as ChannelMessage[];
} catch (err) {
console.error(
`[Discord/Channel] Failed to retrieve messages from channel '${this.id}': ${err}`,
);
return [];
}
}

public async sendMessage(content: string, discord: BaseDiscordApi) {
if (this.type !== ChannelType.GuildText) return;

const response = await fetch(
`https://discord.com/api/v10/channels/${this.id}/messages`,
{
method: 'POST',
body: JSON.stringify({
content,
flags: 0,
mobile_network_type: 'unknown',
tts: false,
}),
headers: {
'Content-Type': 'application/json',
Authorization: discord.token,
},
},
);
const json = await response.json();
console.log('Response: ', json);
}
}
10 changes: 10 additions & 0 deletions src/common/discord/client/basediscordapi.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import events from 'events';

export default class BaseDiscordApi extends events.EventEmitter {
public readonly token: string;

protected constructor(token: string) {
super();
this.token = token;
}
}
41 changes: 41 additions & 0 deletions src/common/discord/client/basediscordclient.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import VoiceService from '../service/voiceservice';
import GuildService from '../service/guildservice';
import { PrivateChannel, Relationship, User } from '../user';
import Channel from '../channel';
import UserService from '../service/userservice';
import BaseDiscordApi from './basediscordapi';

export default abstract class BaseDiscordClient extends BaseDiscordApi {
public readonly voice: VoiceService;

public readonly guilds: GuildService;

public readonly users: UserService;

public selfUser: User | null = null;

public relationships: Relationship[] = [];

public privateChannels: PrivateChannel[] = [];

public ready: boolean = false;

protected constructor(token: string) {
super(token);
this.voice = new VoiceService();
this.guilds = new GuildService();
this.users = new UserService();
}

public getChannel(id: string): Channel | null {
const guilds = this.guilds.getGuilds();
for (let i = 0; i < guilds.length; i += 1) {
const guild = guilds[i];
for (let j = 0; j < guild.channels.length; j += 1) {
const channel = guild.channels[j];
if (channel.id === id) return channel;
}
}
return null;
}
}
29 changes: 29 additions & 0 deletions src/common/discord/client/client.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import BaseDiscordClient from './basediscordclient';
import { GatewayClient } from '../gateway/gatewayclient';
import GatewayEvent from '../gateway/event';

export declare interface DiscordClient {
on(event: string, listener: Function): this;

on(event: 'connect', listener: () => void): this;

on(event: 'event', listener: (event: GatewayEvent) => void): this;
}

// eslint-disable-next-line no-redeclare
export class DiscordClient extends BaseDiscordClient {
public readonly gateway: GatewayClient;

public constructor(token: string) {
super(token);
this.gateway = new GatewayClient(this);
this.gateway.on('connect', () => this.emit('connect'));
this.gateway.on('event', (event: GatewayEvent) => {
this.emit('event', event);
});
}

public disconnect() {
this.gateway.disconnect();
}
}
106 changes: 106 additions & 0 deletions src/common/discord/gateway/data/ReadyEventData.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { IGuild } from '../../guild';
import {
ConnectedAccount,
IUser,
Member,
PrivateChannel,
Relationship,
} from '../../user';
import { VoiceState } from '../../voice';

export interface Consents {
personalization: string[];
}

export interface NotificationSettings {
flags: number;
}

export interface UserSettings {
detect_platform_accounts: boolean;
animate_stickers: number;
inline_attachment_media: boolean;
status: string;
message_display_compact: boolean;
view_nsfw_guilds: boolean;
timezone_offset: number;
enable_tts_command: boolean;
disable_games_tab: boolean;
stream_notifications_enabled: boolean;
animate_emoji: boolean;
guild_folders: string[];
activity_joining_restricted_guild_ids: any[];
friend_source_flags: string[];
broadcast_allowed_user_ids: any[];
convert_emoticons: boolean;
afk_timeout: number;
passwordless: boolean;
contact_sync_enabled: boolean;
broadcast_allow_friends: boolean;
gif_auto_play: boolean;
custom_status: any;
native_phone_integration_enabled: boolean;
allow_accessibility_detection: boolean;
broadcast_allowed_guild_ids: any[];
friend_discovery_flags: number;
show_current_game: boolean;
restricted_guilds: any[];
developer_mode: boolean;
view_nsfw_commands: boolean;
render_reactions: boolean;
locale: string;
render_embeds: boolean;
inline_embed_media: boolean;
default_guilds_restricted: boolean;
explicit_content_filter: number;
activity_restricted_guild_ids: any[];
theme: string;
}

export interface ReadyEventData {
v: number;
user_settings_proto: string;
user_settings: UserSettings;
user_guild_settings: string[][];
user: IUser;
users: IUser[];
relationships: Relationship[];
read_state: string[][];
private_channels: PrivateChannel[];
presences: string[][];
notification_settings: NotificationSettings;
guilds: IGuild[];
merged_members: Member[][];
guild_join_requests: any[];
guild_experiments: string[][];
friend_suggestion_count: number;
explicit_content_scan_version: number;
experiments: string[][];
country_code: string;
consents: Consents;
connected_accounts: ConnectedAccount[];
auth_session_id_hash: string;
api_code_version: number;
analytics_token: string;
}

export interface MergedPresences {
guilds: any[];
friends: any[];
}

export interface SupplementalGuild {
voice_states: VoiceState[];
id: string;
embedded_activities: any[];
activity_instances: any[];
}

export interface ReadySupplementalData {
merged_presences: MergedPresences;
merged_members: any[];
lazy_private_channels: any[];
guilds: SupplementalGuild[];
game_invites: any[];
disclose: string[];
}
6 changes: 6 additions & 0 deletions src/common/discord/gateway/event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default interface GatewayEvent {
op: number;
data: any;
sequence?: number;
event?: string;
}
Loading

0 comments on commit 598a7f5

Please sign in to comment.