This commit is contained in:
DjDeveloperr 2021-04-30 18:07:01 +05:30
parent fee3e0cfa0
commit e8371408e2
10 changed files with 250 additions and 49 deletions

View File

@ -38,7 +38,7 @@ export interface ClientOptions {
/** Token of the Bot/User */
token?: string
/** Gateway Intents */
intents?: GatewayIntents[]
intents?: Array<GatewayIntents | keyof typeof GatewayIntents>
/** Cache Adapter to use, defaults to Collections one */
cache?: ICacheAdapter
/** Force New Session and don't use cached Session (by persistent caching) */
@ -77,10 +77,29 @@ export class Client extends HarmonyEventEmitter<ClientEvents> {
rest: RESTManager
/** User which Client logs in to, undefined until logs in */
user?: User
#token?: string
/** Token of the Bot/User */
token?: string
get token(): string | undefined {
return this.#token
}
set token(val: string | undefined) {
this.#token = val
}
/** Cache Adapter */
cache: ICacheAdapter = new DefaultCacheAdapter()
get cache(): ICacheAdapter {
return this.#cache
}
set cache(val: ICacheAdapter) {
this.#cache = val
}
#cache: ICacheAdapter = new DefaultCacheAdapter()
/** Gateway Intents */
intents?: GatewayIntents[]
/** Whether to force new session or not */
@ -91,21 +110,23 @@ export class Client extends HarmonyEventEmitter<ClientEvents> {
reactionCacheLifetime: number = 3600000
/** Whether to fetch Uncached Message of Reaction or not? */
fetchUncachedReactions: boolean = false
/** Client Properties */
clientProperties: ClientProperties
readonly clientProperties!: ClientProperties
/** Slash-Commands Management client */
slash: SlashClient
/** Whether to fetch Gateway info or not */
fetchGatewayInfo: boolean = true
/** Users Manager, containing all Users cached */
users: UsersManager = new UsersManager(this)
readonly users: UsersManager = new UsersManager(this)
/** Guilds Manager, providing cache & API interface to Guilds */
guilds: GuildManager = new GuildManager(this)
readonly guilds: GuildManager = new GuildManager(this)
/** Channels Manager, providing cache interface to Channels */
channels: ChannelsManager = new ChannelsManager(this)
readonly channels: ChannelsManager = new ChannelsManager(this)
/** Channels Manager, providing cache interface to Channels */
emojis: EmojisManager = new EmojisManager(this)
readonly emojis: EmojisManager = new EmojisManager(this)
/** Last READY timestamp */
upSince?: Date
@ -146,7 +167,9 @@ export class Client extends HarmonyEventEmitter<ClientEvents> {
super()
this._id = options.id
this.token = options.token
this.intents = options.intents
this.intents = options.intents?.map((e) =>
typeof e === 'string' ? GatewayIntents[e] : e
)
this.shards = new ShardManager(this)
this.forceNewSession = options.forceNewSession
if (options.cache !== undefined) this.cache = options.cache
@ -172,14 +195,17 @@ export class Client extends HarmonyEventEmitter<ClientEvents> {
;(this as any)._decoratedEvents = undefined
}
this.clientProperties =
options.clientProperties === undefined
? {
os: Deno.build.os,
browser: 'harmony',
device: 'harmony'
}
: options.clientProperties
Object.defineProperty(this, 'clientProperties', {
value:
options.clientProperties === undefined
? {
os: Deno.build.os,
browser: 'harmony',
device: 'harmony'
}
: options.clientProperties,
enumerable: false
})
if (options.shard !== undefined) this.shard = options.shard
if (options.shardCount !== undefined) this.shardCount = options.shardCount

View File

@ -62,7 +62,7 @@ export class Gateway extends HarmonyEventEmitter<GatewayTypedEvents> {
lastPingTimestamp = 0
sessionID?: string
private heartbeatServerResponded = false
client: Client
client!: Client
cache: GatewayCache
private timedIdentify: number | null = null
shards?: number[]
@ -70,7 +70,7 @@ export class Gateway extends HarmonyEventEmitter<GatewayTypedEvents> {
constructor(client: Client, shards?: number[]) {
super()
this.client = client
Object.defineProperty(this, 'client', { value: client, enumerable: false })
this.cache = new GatewayCache(client)
this.shards = shards
}

View File

@ -47,11 +47,21 @@ export type SlashClientEvents = {
export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> {
id: string | (() => string)
client?: Client
token?: string
#token?: string
get token(): string | undefined {
return this.#token
}
set token(val: string | undefined) {
this.#token = val
}
enabled: boolean = true
commands: SlashCommandsManager
handlers: SlashCommandHandler[] = []
rest: RESTManager
readonly rest!: RESTManager
modules: SlashModule[] = []
publicKey?: string
@ -62,7 +72,14 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> {
if (id === undefined)
throw new Error('ID could not be found. Pass at least client or token')
this.id = id
this.client = options.client
if (options.client !== undefined) {
Object.defineProperty(this, 'client', {
value: options.client,
enumerable: false
})
}
this.token = options.token
this.publicKey = options.publicKey
@ -85,14 +102,17 @@ export class SlashClient extends HarmonyEventEmitter<SlashClientEvents> {
})
}
this.rest =
options.client === undefined
? options.rest === undefined
? new RESTManager({
token: this.token
})
: options.rest
: options.client.rest
Object.defineProperty(this, 'rest', {
value:
options.client === undefined
? options.rest === undefined
? new RESTManager({
token: this.token
})
: options.rest
: options.client.rest,
enumerable: false
})
this.client?.on(
'interactionCreate',

View File

@ -198,12 +198,15 @@ export class SlashBuilder {
/** Manages Slash Commands, allows fetching/modifying/deleting/creating Slash Commands. */
export class SlashCommandsManager {
slash: SlashClient
rest: RESTManager
readonly slash!: SlashClient
readonly rest!: RESTManager
constructor(client: SlashClient) {
this.slash = client
this.rest = client.rest
Object.defineProperty(this, 'slash', { value: client, enumerable: false })
Object.defineProperty(this, 'rest', {
enumerable: false,
value: client.rest
})
}
/** Get all Global Slash Commands */

View File

@ -1,4 +1,5 @@
import type { Client } from '../client/mod.ts'
import { Base } from '../structures/base.ts'
import { Collection } from '../utils/collection.ts'
/**
@ -6,15 +7,14 @@ import { Collection } from '../utils/collection.ts'
*
* You should not be making Managers yourself.
*/
export class BaseManager<T, T2> {
client: Client
export class BaseManager<T, T2> extends Base {
/** Caches Name or Key used to differentiate caches */
cacheName: string
/** Which data type does this cache have */
DataType: any
constructor(client: Client, cacheName: string, DataType: any) {
this.client = client
super(client)
this.cacheName = cacheName
this.DataType = DataType
}
@ -87,4 +87,8 @@ export class BaseManager<T, T2> {
flush(): any {
return this.client.cache.deleteCache(this.cacheName)
}
[Deno.customInspect](): string {
return `Manager(${this.cacheName})`
}
}

View File

@ -1,15 +1,15 @@
import type { Client } from '../client/mod.ts'
import { Base } from '../structures/base.ts'
import { Collection } from '../utils/collection.ts'
import { BaseManager } from './base.ts'
/** Child Managers validate data from their parents i.e. from Managers */
export class BaseChildManager<T, T2> {
client: Client
export class BaseChildManager<T, T2> extends Base {
/** Parent Manager */
parent: BaseManager<T, T2>
constructor(client: Client, parent: BaseManager<T, T2>) {
this.client = client
super(client)
this.parent = parent
}
@ -62,4 +62,8 @@ export class BaseChildManager<T, T2> {
if (fetchValue !== undefined) return fetchValue
}
}
[Deno.customInspect](): string {
return `ChildManager(${this.parent.cacheName})`
}
}

View File

@ -103,8 +103,18 @@ export class RESTManager {
* ```
*/
api: APIMap
#token?: string | (() => string | undefined)
/** Token being used for Authorization */
token?: string | (() => string | undefined)
get token(): string | (() => string | undefined) | undefined {
return this.#token
}
set token(val: string | (() => string | undefined) | undefined) {
this.#token = val
}
/** Token Type of the Token if any */
tokenType: TokenType = TokenType.Bot
/** Headers object which patch the current ones */
@ -114,13 +124,13 @@ export class RESTManager {
/** Whether REST Manager is using Canary API */
canary?: boolean
/** Optional Harmony Client object */
client?: Client
readonly client?: Client
endpoints: RESTEndpoints
requestTimeout = 30000
timers: Set<number> = new Set()
readonly timers!: Set<number>
apiURL = Constants.DISCORD_API_URL
handlers = new Collection<string, BucketHandler>()
readonly handlers!: Collection<string, BucketHandler>
globalLimit = Infinity
globalRemaining = this.globalLimit
globalReset: number | null = null
@ -136,11 +146,28 @@ export class RESTManager {
if (options?.tokenType !== undefined) this.tokenType = options.tokenType
if (options?.userAgent !== undefined) this.userAgent = options.userAgent
if (options?.canary !== undefined) this.canary = options.canary
if (options?.client !== undefined) this.client = options.client
if (options?.retryLimit !== undefined) this.retryLimit = options.retryLimit
if (options?.requestTimeout !== undefined)
this.requestTimeout = options.requestTimeout
if (options?.client !== undefined) {
Object.defineProperty(this, 'client', {
value: options.client,
enumerable: false
})
}
this.endpoints = new RESTEndpoints(this)
Object.defineProperty(this, 'timers', {
value: new Set(),
enumerable: false
})
Object.defineProperty(this, 'handlers', {
value: new Collection<string, BucketHandler>(),
enumerable: false
})
}
setTimeout(fn: (...args: any[]) => any, ms: number): number {

30
test/eval.ts Normal file
View File

@ -0,0 +1,30 @@
/* eslint-disable no-eval */
import * as discord from '../mod.ts'
import { TOKEN } from './config.ts'
const client = new discord.Client({
token: TOKEN,
intents: ['GUILD_MESSAGES', 'GUILDS']
})
client.on('messageCreate', async (msg) => {
if (msg.author.id !== '422957901716652033') return
if (msg.content.startsWith('.eval') === true) {
let code = msg.content.slice(5).trim()
if (code.startsWith('```') === true) code = code.slice(3).trim()
if (code.endsWith('```') === true) code = code.substr(0, code.length - 3)
try {
const result = await eval(code)
msg.reply(
`\`\`\`js\n${Deno.inspect(result).substr(0, 2000 - 20)}\n\`\`\``
)
} catch (e) {
msg.reply(`\`\`\`js\n${e}\n\`\`\``, {
allowedMentions: { replied_user: false }
})
}
}
})
client.connect().then(() => console.log('Ready!'))

View File

@ -8,12 +8,12 @@ import {
CommandContext,
Extension,
Collection,
GuildTextChannel
} from '../../mod.ts'
GuildTextChannel,
Interaction,
slash
} from '../mod.ts'
import { LL_IP, LL_PASS, LL_PORT, TOKEN } from './config.ts'
import { Manager, Player } from 'https://deno.land/x/lavadeno/mod.ts'
import { Interaction } from '../structures/slash.ts'
import { slash } from '../client/mod.ts'
// import { SlashCommandOptionType } from '../types/slash.ts'
export const nodes = [

87
test/trigger.ts Normal file
View File

@ -0,0 +1,87 @@
/* eslint-disable @typescript-eslint/strict-boolean-expressions */
/* eslint-disable no-control-regex */
import { Client, Embed } from '../mod.ts'
import { TOKEN } from './config.ts'
const client = new Client({
token: TOKEN,
intents: ['GUILDS', 'GUILD_MESSAGES']
})
const NAME_MATCH = /[^a-zA-Z0-9_]/
const STD_REGEX = /\/?std(@[\x00-\x2e\x30-\xff]+)?\/([a-zA-Z0-9]+)(\/[\S\s]+)?/
const X_REGEX = /\/?x\/([a-zA-Z0-9]+)(@[\x00-\x2e\x30-\xff]+)?(\/[\S\s]+)?/
export async function fetchModule(name: string): Promise<any> {
if (name.match(NAME_MATCH) !== null) return null
return fetch(`https://api.deno.land/modules/${name}`, {
credentials: 'omit',
headers: {
'User-Agent':
'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:83.0) Gecko/20100101 Firefox/83.0',
Accept: 'application/json',
'Accept-Language': 'en-US,en;q=0.5',
Pragma: 'no-cache',
'Cache-Control': 'no-cache'
},
referrer: 'https://deno.land/x',
mode: 'cors'
})
.then((res) => {
if (res.status !== 200) throw new Error('not found')
return res
})
.then((r) => r.json())
.then((json) => {
if (!json.success) throw new Error('failed')
return json
})
.then((data) => data.data)
.catch(() => null)
}
client.on('messageCreate', async (msg) => {
if (msg.author.bot === true) return
let match
if (
(match = msg.content.match(STD_REGEX)) ||
(match = msg.content.match(X_REGEX))
) {
let x = match[0].trim()
if (!x.startsWith('/')) x = `/${x}`
let type
if (x.startsWith('/std')) {
x = x.slice(4)
type = 'std'
} else {
x = x.slice(3)
type = 'x'
}
x = x.trim()
const name = x.split('/')[0].split('@')[0]
const mod = await fetchModule(type === 'std' ? 'std' : name)
if (mod === null) return
msg.channel.send(
new Embed()
.setColor('#7289DA')
.setURL(
`https://deno.land/${type}${
x.startsWith('/') || x.startsWith('@') ? '' : '/'
}${x}`
)
.setTitle(
`${type}${x.startsWith('/') || x.startsWith('@') ? '' : '/'}${x}`
)
.setDescription(mod.description ?? 'No description.')
.setFooter(`${mod.star_count ?? 0}`, 'https://kokoro.pw/colleague.png')
)
}
})
console.log('Connecting...')
client.connect().then(() => console.log('Ready!'))