encoding util

This commit is contained in:
DjDeveloperr 2021-04-04 10:21:39 +05:30
parent 38b11f4076
commit 2b46b38908
4 changed files with 91 additions and 68 deletions

View file

@ -18,6 +18,7 @@ import { delay } from '../utils/delay.ts'
import { VoiceChannel } from '../structures/guildVoiceChannel.ts'
import { Guild } from '../structures/guild.ts'
import { HarmonyEventEmitter } from '../utils/events.ts'
import { decodeText } from '../utils/encoding.ts'
export interface RequestMembersOptions {
limit?: number
@ -89,7 +90,7 @@ export class Gateway extends HarmonyEventEmitter<GatewayTypedEvents> {
}
if (data instanceof Uint8Array) {
data = unzlib(data)
data = new TextDecoder('utf-8').decode(data)
data = decodeText(data)
}
const { op, d, s, t }: GatewayResponse = JSON.parse(data)
@ -385,8 +386,8 @@ export class Gateway extends HarmonyEventEmitter<GatewayTypedEvents> {
channel === undefined
? null
: typeof channel === 'string'
? channel
: channel?.id,
? channel
: channel?.id,
self_mute: voiceOptions.mute === undefined ? false : voiceOptions.mute,
self_deaf: voiceOptions.deaf === undefined ? false : voiceOptions.deaf
}
@ -427,7 +428,11 @@ export class Gateway extends HarmonyEventEmitter<GatewayTypedEvents> {
}
close(code: number = 1000, reason?: string): void {
this.debug(`Closing with code ${code}${reason !== undefined && reason !== '' ? ` and reason ${reason}` : ''}`)
this.debug(
`Closing with code ${code}${
reason !== undefined && reason !== '' ? ` and reason ${reason}` : ''
}`
)
return this.websocket?.close(code, reason)
}

View file

@ -19,7 +19,8 @@ import { RESTManager } from './rest.ts'
import { SlashModule } from './slashModule.ts'
import { verify as edverify } from 'https://deno.land/x/ed25519@1.0.1/mod.ts'
import { User } from '../structures/user.ts'
import { HarmonyEventEmitter } from "../utils/events.ts"
import { HarmonyEventEmitter } from '../utils/events.ts'
import { encodeText, decodeText } from '../utils/encoding.ts'
export class SlashCommand {
slash: SlashCommandsManager
@ -94,8 +95,8 @@ function createSlashOption(
data.choices === undefined
? undefined
: data.choices.map((e) =>
typeof e === 'string' ? { name: e, value: e } : e
)
typeof e === 'string' ? { name: e, value: e } : e
)
}
}
@ -139,15 +140,15 @@ export type SlashOptionCallable = (o: typeof SlashOption) => SlashCommandOption
export type SlashBuilderOptionsData =
| Array<SlashCommandOption | SlashOptionCallable>
| {
[name: string]:
| {
description: string
type: SlashCommandOptionType
options?: SlashCommandOption[]
choices?: SlashCommandChoice[]
[name: string]:
| {
description: string
type: SlashCommandOptionType
options?: SlashCommandOption[]
choices?: SlashCommandChoice[]
}
| SlashOptionCallable
}
| SlashOptionCallable
}
function buildOptionsArray(
options: SlashBuilderOptionsData
@ -155,10 +156,10 @@ function buildOptionsArray(
return Array.isArray(options)
? options.map((op) => (typeof op === 'function' ? op(SlashOption) : op))
: Object.entries(options).map((entry) =>
typeof entry[1] === 'function'
? entry[1](SlashOption)
: Object.assign(entry[1], { name: entry[0] })
)
typeof entry[1] === 'function'
? entry[1](SlashOption)
: Object.assign(entry[1], { name: entry[0] })
)
}
/** Slash Command Builder */
@ -268,8 +269,8 @@ export class SlashCommandsManager {
guild === undefined
? this.rest.api.applications[this.slash.getID()].commands
: this.rest.api.applications[this.slash.getID()].guilds[
typeof guild === 'string' ? guild : guild.id
].commands
typeof guild === 'string' ? guild : guild.id
].commands
const payload = await route.post(data)
@ -277,8 +278,8 @@ export class SlashCommandsManager {
typeof guild === 'object'
? guild
: guild === undefined
? undefined
: await this.slash.client?.guilds.get(guild)
? undefined
: await this.slash.client?.guilds.get(guild)
const cmd = new SlashCommand(this, payload, _guild)
cmd._guild =
@ -297,8 +298,8 @@ export class SlashCommandsManager {
guild === undefined
? this.rest.api.applications[this.slash.getID()].commands[id]
: this.rest.api.applications[this.slash.getID()].guilds[
typeof guild === 'string' ? guild : guild.id
].commands[id]
typeof guild === 'string' ? guild : guild.id
].commands[id]
await route.patch(data)
return this
@ -313,8 +314,8 @@ export class SlashCommandsManager {
guild === undefined
? this.rest.api.applications[this.slash.getID()].commands[id]
: this.rest.api.applications[this.slash.getID()].guilds[
typeof guild === 'string' ? guild : guild.id
].commands[id]
typeof guild === 'string' ? guild : guild.id
].commands[id]
await route.delete()
return this
@ -326,8 +327,8 @@ export class SlashCommandsManager {
guild === undefined
? this.rest.api.applications[this.slash.getID()].commands[id]
: this.rest.api.applications[this.slash.getID()].guilds[
typeof guild === 'string' ? guild : guild.id
].commands[id]
typeof guild === 'string' ? guild : guild.id
].commands[id]
const data = await route.get()
@ -335,8 +336,8 @@ export class SlashCommandsManager {
typeof guild === 'object'
? guild
: guild === undefined
? undefined
: await this.slash.client?.guilds.get(guild)
? undefined
: await this.slash.client?.guilds.get(guild)
return new SlashCommand(this, data, _guild)
}
@ -350,8 +351,8 @@ export class SlashCommandsManager {
guild === undefined
? this.rest.api.applications[this.slash.getID()].commands
: this.rest.api.applications[this.slash.getID()].guilds[
typeof guild === 'string' ? guild : guild.id
].commands
typeof guild === 'string' ? guild : guild.id
].commands
await route.put(cmds)
@ -378,9 +379,6 @@ export interface SlashOptions {
publicKey?: string
}
const encoder = new TextEncoder()
const decoder = new TextDecoder('utf-8')
// eslint-disable-next-line @typescript-eslint/consistent-type-definitions
export type SlashClientEvents = {
interaction: [Interaction]
@ -439,13 +437,14 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> {
options.client === undefined
? options.rest === undefined
? new RESTManager({
token: this.token
})
token: this.token
})
: options.rest
: options.client.rest
this.client?.on('interactionCreate', async (interaction) =>
await this._process(interaction)
this.client?.on(
'interactionCreate',
async (interaction) => await this._process(interaction)
)
this.commands = new SlashCommandsManager(this)
@ -490,20 +489,20 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> {
const groupMatched =
e.group !== undefined && e.parent !== undefined
? i.options
.find(
(o) =>
o.name === e.group &&
o.type === SlashCommandOptionType.SUB_COMMAND_GROUP
)
?.options?.find((o) => o.name === e.name) !== undefined
.find(
(o) =>
o.name === e.group &&
o.type === SlashCommandOptionType.SUB_COMMAND_GROUP
)
?.options?.find((o) => o.name === e.name) !== undefined
: true
const subMatched =
e.group === undefined && e.parent !== undefined
? i.options.find(
(o) =>
o.name === e.name &&
o.type === SlashCommandOptionType.SUB_COMMAND
) !== undefined
(o) =>
o.name === e.name &&
o.type === SlashCommandOptionType.SUB_COMMAND
) !== undefined
: true
const nameMatched1 = e.name === i.name
const parentMatched = hasGroupOrParent ? e.parent === i.name : true
@ -533,7 +532,9 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> {
if (cmd === undefined) return
await this.emit('interaction', interaction)
try { await cmd.handler(interaction) } catch (e) {
try {
await cmd.handler(interaction)
} catch (e) {
await this.emit('interactionError', e)
}
}
@ -548,10 +549,8 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> {
throw new Error('Public Key is not present')
const fullBody = new Uint8Array([
...(typeof timestamp === 'string'
? encoder.encode(timestamp)
: timestamp),
...(typeof rawBody === 'string' ? encoder.encode(rawBody) : rawBody)
...(typeof timestamp === 'string' ? encodeText(timestamp) : timestamp),
...(typeof rawBody === 'string' ? encodeText(rawBody) : rawBody)
])
return edverify(signature, fullBody, this.publicKey).catch(() => false)
@ -561,7 +560,7 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> {
async verifyServerRequest(req: {
headers: Headers
method: string
body: Deno.Reader | Uint8Array,
body: Deno.Reader | Uint8Array
respond: (options: {
status?: number
headers?: Headers
@ -574,12 +573,13 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> {
const timestamp = req.headers.get('x-signature-timestamp')
if (signature === null || timestamp === null) return false
const rawbody = req.body instanceof Uint8Array ? req.body : await Deno.readAll(req.body)
const rawbody =
req.body instanceof Uint8Array ? req.body : await Deno.readAll(req.body)
const verify = await this.verifyKey(rawbody, signature, timestamp)
if (!verify) return false
try {
const payload: InteractionPayload = JSON.parse(decoder.decode(rawbody))
const payload: InteractionPayload = JSON.parse(decodeText(rawbody))
// TODO: Maybe fix all this hackery going on here?
const res = new Interaction(this as any, payload, {
@ -600,7 +600,8 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> {
await req.respond({
status: 200,
headers: new Headers({
'content-type': d instanceof FormData ? 'multipart/form-data' : 'application/json'
'content-type':
d instanceof FormData ? 'multipart/form-data' : 'application/json'
}),
body: d instanceof FormData ? d : JSON.stringify(d)
})
@ -612,7 +613,13 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> {
}
/** Verify FetchEvent (for Service Worker usage) and return Interaction if valid */
async verifyFetchEvent({ request: req, respondWith }: { respondWith: CallableFunction, request: Request }): Promise<false | Interaction> {
async verifyFetchEvent({
request: req,
respondWith
}: {
respondWith: CallableFunction
request: Request
}): Promise<false | Interaction> {
if (req.bodyUsed === true) throw new Error('Request Body already used')
if (req.body === null) return false
const body = (await req.body.getReader().read()).value
@ -623,11 +630,13 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> {
body,
method: req.method,
respond: async (options) => {
await respondWith(new Response(options.body, {
headers: options.headers,
status: options.status,
}))
},
await respondWith(
new Response(options.body, {
headers: options.headers,
status: options.status
})
)
}
})
}

View file

@ -21,6 +21,7 @@ import { MessageReactionsManager } from '../managers/messageReactions.ts'
import { MessageSticker } from './messageSticker.ts'
import { Emoji } from './emoji.ts'
import { InteractionType } from '../types/slash.ts'
import { encodeText } from '../utils/encoding.ts'
type AllMessageOptions = MessageOptions | Embed
@ -217,8 +218,6 @@ export class Message extends SnowflakeBase {
}
}
const encoder = new TextEncoder()
/** Message Attachment that can be sent while Creating Message */
export class MessageAttachment {
name: string
@ -228,7 +227,7 @@ export class MessageAttachment {
this.name = name
this.blob =
typeof blob === 'string'
? new Blob([encoder.encode(blob)])
? new Blob([encodeText(blob)])
: blob instanceof Uint8Array
? new Blob([blob])
: blob

10
src/utils/encoding.ts Normal file
View file

@ -0,0 +1,10 @@
const encoder = new TextEncoder()
const decoder = new TextDecoder('utf-8')
export function encodeText(str: string): Uint8Array {
return encoder.encode(str)
}
export function decodeText(bytes: Uint8Array): string {
return decoder.decode(bytes)
}