diff --git a/.denon.json b/.denon.json deleted file mode 100644 index abdb7af..0000000 --- a/.denon.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "files": [ - "src/index.ts" - ], - "quiet": false, - "debug": true, - "fullscreen": true, - "extensions": [ - ".js", - ".ts", - ".py", - ".json" - ], - "interval": 500, - "watch": [ - "src/" - ], - "deno_args":[ - "--allow-net", - "--unstable", - "--allow-read" - ], - "execute": { - ".js": ["deno", "run"], - ".ts": ["deno", "run"], - ".py": ["python"] - }, - "fmt": false, - "test": true -} \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7dd3e50 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +.env +.denon.json \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..4aad6c7 --- /dev/null +++ b/README.md @@ -0,0 +1,20 @@ +# What is Katana? + +Katana is an unofficial Discord library that allows you to build Discord Bots. + +# Usage + +```TS +import { Client } from 'https://deno.land/x/katana/mod.ts' + +const client = new Client(); + +client.on('ready', () => { + console.log('Bot has logged in!'); +}); +``` + +# Features + +# Contributing + diff --git a/mod.ts b/mod.ts new file mode 100644 index 0000000..6fac3dd --- /dev/null +++ b/mod.ts @@ -0,0 +1,2 @@ +export { Client } from './src/client/Client.ts'; + diff --git a/src/client/Client.ts b/src/client/Client.ts index 9628417..5f55ac5 100644 --- a/src/client/Client.ts +++ b/src/client/Client.ts @@ -1,14 +1,39 @@ import EventEmitter from 'https://deno.land/std@0.51.0/node/events.ts'; import WebSocketManager from '../ws/Websocket.ts'; +import ClientUser from './ClientUser.ts'; +import Guild from '../models/Guild.ts'; -export default class Client extends EventEmitter { +export class Client extends EventEmitter { + + private _user!: ClientUser; + private _token!: string; + private _guilds: Map = new Map(); private socket: WebSocketManager = new WebSocketManager(this); async login(token: string): Promise { try { + this._token = token; await this.socket.connect(token); + console.log(this.token); } catch (err) { console.log(err); } } + + get user() { + return this._user; + } + + set user(user: ClientUser) { + this._user = user; + } + + get token() { + return this._token; + } + + get guilds() { + return this._guilds; + } + } \ No newline at end of file diff --git a/src/client/ClientUser.ts b/src/client/ClientUser.ts index 735c7de..090a60c 100644 --- a/src/client/ClientUser.ts +++ b/src/client/ClientUser.ts @@ -9,6 +9,6 @@ export default class ClientUser { private bot: boolean, private avatar: string, ) { - + } } \ No newline at end of file diff --git a/src/constants/Constants.ts b/src/constants/Constants.ts index 7da06b0..6f0ae04 100644 --- a/src/constants/Constants.ts +++ b/src/constants/Constants.ts @@ -1,5 +1,6 @@ export enum Constants { GATEWAY = 'wss://gateway.discord.gg/?v=6&encoding=json', + API = 'https://discord.com/api/v6', } export enum OPCODE { @@ -17,3 +18,9 @@ export enum OPCODE { ELEVEN = 11, TWELVE = 12, } + +export enum ENDPOINTS { + USERS = 'users', + USER_GUILDS = 'users/@me/guilds', + GUILDS = 'guilds' +} \ No newline at end of file diff --git a/src/constants/Events.ts b/src/constants/Events.ts index f7788c1..30a43ec 100644 --- a/src/constants/Events.ts +++ b/src/constants/Events.ts @@ -1,40 +1,40 @@ export enum Events { - READY = 'READY', - RESUMED = 'RESUMED', - RECONNECT = 'RECONNECT', - INVALID_SESSION = 'INVALID_SESSION', - CHANNEL_CREATE = 'CHANNEL_CREATE', - CHANNEL_UPDATE = 'CHANNEL_UPDATE', - CHANNEL_DELETE = 'CHANNEL_DELETE', - CHANNEL_PINS_UPDATE = 'CHANNEL_PINS_UPDATE', - GUILD_CREATE = 'GUILD_CREATE', - GUILD_UPDATE = 'GUILD_UPDATE', - GUILD_DELETE = 'GUILD_DELETE', - GUILD_BAN_ADD = 'GUILD_BAN_ADD', - GUILD_BAN_REMOVE = 'GUILD_BAN_REMOVE', - GUILD_EMOJIS_UPDATE = 'GUILD_EMOJIS_UPDATE', - GUILD_INTEGRATIONS_UPDATE = 'GUILD_INTEGRATIONS_UPDATE', - GUILD_MEMBER_ADD = 'GUILD_MEMBER_ADD', - GUILD_MEMBER_REMOVE = 'GUILD_MEMBER_REMOVE', - GUILD_MEMBER_UPDATE = 'GUILD_MEMBER_UPDATE', - GUILD_MEMBERS_CHUNK = 'GUILD_MEMBERS_CHUNK', - GUILD_ROLE_CREATE = 'GUILD_ROLE_CREATE', - GUILD_ROLE_UPDATE = 'GUILD_ROLE_UPDATE', - GUILD_ROLE_DELETE = 'GUILD_ROLE_DELETE', - INVITE_CREATE = 'INVITE_CREATE', - INVITE_DELETE = 'INVITE_DELETE', - MESSAGE_CREATE = 'MESSAGE_CREATE', - MESSAGE_UPDATE = 'MESSAGE_UPDATE', - MESSAGE_DELETE = 'MESSAGE_DELETE', - MESSAGE_DELETE_BULK = 'MESSAGE_DELETE_BULK', - MESSAGE_REACTION_ADD = 'MESSAGE_REACTION_ADD', - MESSAGE_REACTION_REMOVE = 'MESSAGE_REACTION_REMOVE', - MESSAGE_REACTION_REMOVE_ALL = 'MESSAGE_REACTION_REMOVE_ALL', - MESSAGE_REACTION_REMOVE_EMOJI = 'MESSAGE_REACTION_REMOVE_EMOJI', - PRESENCE_UPDATE = 'PRESENCE_UPDATE', - TYPING_START = 'TYPING_START', - USER_UPDATE = 'USER_UPDATE', - VOICE_STATE_UPDATE = 'VOICE_STATE_UPDATE', - VOICE_SERVER_UPDATE = 'VOICE_SERVER_UPDATE', - WEBHOOKS_UPDATE = 'WEBHOOKS_UPDATE', + READY = 'ready', + RESUMED = 'resumed', + RECONNECT = 'reconnect', + INVALID_SESSION = 'invalid', + CHANNEL_CREATE = 'channelCreate', + CHANNEL_UPDATE = 'channelUpdate', + CHANNEL_DELETE = 'channelDelete', + CHANNEL_PINS_UPDATE = 'channelPinsUpdate', + GUILD_CREATE = 'guildCreate', + GUILD_UPDATE = 'guildUpdate', + GUILD_DELETE = 'guildDelete', + GUILD_BAN_ADD = 'guildBanAdd', + GUILD_BAN_REMOVE = 'guildBanRemove', + GUILD_EMOJIS_UPDATE = 'guildEmojisUpdate', + GUILD_INTEGRATIONS_UPDATE = 'guildIntegrationsUpdate', + GUILD_MEMBER_ADD = 'guildMemberAdd', + GUILD_MEMBER_REMOVE = 'guildMemberRemove', + GUILD_MEMBER_UPDATE = 'guildMemberUpdate', + GUILD_MEMBERS_CHUNK = 'guildMemberAdd', + GUILD_ROLE_CREATE = 'guildRoleCreate', + GUILD_ROLE_UPDATE = 'guildRoleUpdate', + GUILD_ROLE_DELETE = 'guildRoleDelete', + INVITE_CREATE = 'inviteCreate', + INVITE_DELETE = 'inviteDelete', + MESSAGE_CREATE = 'messageCreate', + MESSAGE_UPDATE = 'messageUpdate', + MESSAGE_DELETE = 'messageDelete', + MESSAGE_DELETE_BULK = 'messageDeleteBulk', + MESSAGE_REACTION_ADD = 'messageReactionAdd', + MESSAGE_REACTION_REMOVE = 'messageReactionRemove', + MESSAGE_REACTION_REMOVE_ALL = 'messageReactionRemoveAll', + MESSAGE_REACTION_REMOVE_EMOJI = 'messageReactionRemoveEmoji', + PRESENCE_UPDATE = 'presenceUpdate', + TYPING_START = 'typingStart', + USER_UPDATE = 'userUpdate', + VOICE_STATE_UPDATE = 'voiceStateUpdate', + VOICE_SERVER_UPDATE = 'voiceStateUpdate', + WEBHOOKS_UPDATE = 'webhooksUpdate', } \ No newline at end of file diff --git a/src/constants/Payloads.ts b/src/constants/Payloads.ts index 9360fdf..9341671 100644 --- a/src/constants/Payloads.ts +++ b/src/constants/Payloads.ts @@ -16,3 +16,8 @@ export const Identify = { } } } + +export const headers = { + 'Content-Type' : 'application/json', + 'Authorization' : '', +} \ No newline at end of file diff --git a/src/handlers/GUILD_CREATE.ts b/src/handlers/GUILD_CREATE.ts index 049c4a3..8764b97 100644 --- a/src/handlers/GUILD_CREATE.ts +++ b/src/handlers/GUILD_CREATE.ts @@ -3,5 +3,6 @@ import { Payload } from "../interfaces/Payload.ts"; import { Events } from '../constants/Events.ts'; export default async function (client: Client, payload: Payload) { + console.log('Guild Created'); client.emit(Events.GUILD_CREATE); } \ No newline at end of file diff --git a/src/handlers/MESSAGE_CREATE.ts b/src/handlers/MESSAGE_CREATE.ts new file mode 100644 index 0000000..361cfaa --- /dev/null +++ b/src/handlers/MESSAGE_CREATE.ts @@ -0,0 +1,7 @@ +import Client from "../client/Client.ts"; +import { Payload } from "../interfaces/Payload.ts"; +import { Events } from '../constants/Events.ts'; + +export default function(client: Client, payload: Payload) { + client.emit(Events.MESSAGE_CREATE); +} \ No newline at end of file diff --git a/src/handlers/READY.ts b/src/handlers/READY.ts index 7f46c0c..b8ef0c6 100644 --- a/src/handlers/READY.ts +++ b/src/handlers/READY.ts @@ -1,7 +1,85 @@ import Client from "../client/Client.ts"; import { Payload } from "../interfaces/Payload.ts"; import { Events } from '../constants/Events.ts'; +import RestAPIHandler from '../rest/RestAPIHandler.ts'; +import ClientUser from "../client/ClientUser.ts"; +import Guild from "../models/Guild.ts"; +import Role from "../models/Role.ts"; export default async function (client: Client, payload: Payload) { + + const { user, guilds } = payload.d; + + client.user = new ClientUser( + user.username, + user.discriminator, + user.verified, + user.id, + user.flags, + user.email, + user.bot, + user.avatar + ); + + const now = performance.now(); + + for (const g of guilds) { + const guild: any = await RestAPIHandler.fetchGuild(client.token, g.id); + const rolesArray = guild.roles; + const roles = new Map(); + for (const role of rolesArray) { + roles.set(role.id, new Role( + role.id, + role.name, + role.color, + role.hoist, + role.position, + role.permissions, + role.managed, + role.mentionable + )); + } + + const newGuild = new Guild( + guild.id, + guild.name, + guild.icon, + guild.description, + guild.splash, + guild.discovery_splash, + guild.features, + guild.emojis, + guild.banner, + guild.owner_id, + guild.application_id, + guild.region, + guild.afk_channel_id, + guild.afk_timeout, + guild.system_channel_id, + guild.widget_enabled, + guild.widget_channel_id, + guild.verification_level, + roles, + guild.default_message_notifications, + guild.mfa_level, + guild.explicit_content_filter, + guild.max_presences, + guild.max_members, + guild.max_video_channel_users, + guild.vanity_url_code, + guild.premium_tier, + guild.premium_subscription_count, + guild.system_channel_flags, + guild.preferred_locale, + guild.rules_channel_id, + guild.public_updates_channel_id, + guild.embed_enabled, + guild.embed_channel_id, + ); + client.guilds.set(newGuild.id, newGuild); + } + const end = performance.now(); + + console.log(`Duration: ${end-now}ms`) client.emit(Events.READY); } \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index 78d1636..2605abd 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,6 +1,9 @@ -import Client from '../src/client/Client.ts'; -import EventQueue from './structures/EventQueue.ts'; +import { Client } from '../src/client/Client.ts'; +import "https://deno.land/x/dotenv/load.ts"; const client = new Client(); +client.login(Deno.env.get('BOT_TOKEN')!.toString()); -client.login('token'); +client.on('ready', () => { + console.log('Bot has logged in.'); +}); diff --git a/src/constants/Identify.ts b/src/models/Emoji.ts similarity index 100% rename from src/constants/Identify.ts rename to src/models/Emoji.ts diff --git a/src/models/Guild.ts b/src/models/Guild.ts new file mode 100644 index 0000000..39442ba --- /dev/null +++ b/src/models/Guild.ts @@ -0,0 +1,51 @@ +import Role from "./Role.ts"; + +export default class Guild { + + constructor( + private _id: string, + private name: string, + private icon: string, + private description: string, + private splash: string, + private discoverySplash: string, + private features: Array, + private emojis: Array, + private banner: string, + private ownerId: string, + private applicationId: string, + private region: string, + private afkChannelId: string, + private afkTimeout: string, + private systemChannelId: string, + private widgetEnabled: boolean, + private widgetChannelId: string, + private verificationLevel: number, + private _roles: Map = new Map(), + private defaultMessageNotifications: number, + private mfaLevel: number, + private explicitContentFilter: number, + private maxPresences: number, + private maxMembers: number, + private maxVideoChannelUsers: number, + private vanityUrl: string, + private premiumTier: number, + private premiumSubscriptionCount: number, + private systemChannelFlags: number, + private preferredLocale: string, + private rulesChannelId: string, + private publicUpdatesChannelId: string, + private embedEnabled: boolean, + private embedChannelId: string + ) { + + } + + public get id(): string { + return this._id; + } + + public get roles(): Map { + return this._roles; + } +} \ No newline at end of file diff --git a/src/models/Role.ts b/src/models/Role.ts new file mode 100644 index 0000000..b671467 --- /dev/null +++ b/src/models/Role.ts @@ -0,0 +1,17 @@ +export default class Role { + + constructor( + private _id: string, + private name: string, + private color: number, + private hoist: boolean, + private position: number, + private permissions: number, + private managed: boolean, + private mentionable: boolean + ) { + + } + + public get id() { return this._id; } +} \ No newline at end of file diff --git a/src/rest/RestAPIHandler.ts b/src/rest/RestAPIHandler.ts new file mode 100644 index 0000000..79edc35 --- /dev/null +++ b/src/rest/RestAPIHandler.ts @@ -0,0 +1,19 @@ +import { Constants, ENDPOINTS } from '../constants/Constants.ts'; +import { headers } from '../constants/Payloads.ts'; + +export default class RestAPIHandler { + + static async fetchGuilds(token: string) { + headers.Authorization = `Bot ${token}`; + const response = await fetch(`${Constants.API}/${ENDPOINTS.USER_GUILDS}`, { + headers, + }); + return response.json(); + } + + static async fetchGuild(token: string, id: string) { + headers.Authorization = `Bot ${token}`; + const response = await fetch(`${Constants.API}/${ENDPOINTS.GUILDS}/${id}`, { headers }); + return response.json(); + } +} \ No newline at end of file diff --git a/src/structures/EventQueue.ts b/src/structures/EventQueue.ts deleted file mode 100644 index e69de29..0000000 diff --git a/src/ws/WebSocket.ts b/src/ws/WebSocket.ts index eb53241..35e1656 100644 --- a/src/ws/WebSocket.ts +++ b/src/ws/WebSocket.ts @@ -5,7 +5,7 @@ import { Constants, OPCODE } from '../constants/Constants.ts'; import { Identify, Heartbeat } from '../constants/Payloads.ts'; import { Payload } from '../interfaces/Payload.ts'; import { Events } from '../constants/Events.ts'; -import Client from "../client/Client.ts"; +import { Client } from "../client/Client.ts"; export default class WebSocketManager extends EventEmitter { @@ -36,9 +36,12 @@ export default class WebSocketManager extends EventEmitter { break; } if (event) { - const { default: module } = await import(`../handlers/${event}.ts`); - console.log(module); - module(this.client, payload); + try { + const { default: module } = await import(`../handlers/${event}.ts`); + module(this.client, payload); + } catch (err) { + console.log(err); + } } } } catch (err) {