Try to remove those anys (NOT TESTED)

This commit is contained in:
Helloyunho 2020-11-25 20:53:40 +09:00
parent ce444630d0
commit be2945c5eb
16 changed files with 206 additions and 149 deletions

View File

@ -1,13 +1,17 @@
import { Gateway, GatewayEventHandler } from '../index.ts'
import getChannelByType from '../../utils/getChannelByType.ts'
import { ChannelPayload } from '../../types/channel.ts'
import { Guild } from "../../structures/guild.ts"
import { ChannelPayload, GuildChannelPayload } from '../../types/channel.ts'
import { Guild } from '../../structures/guild.ts'
export const channelCreate: GatewayEventHandler = async (
gateway: Gateway,
d: ChannelPayload
) => {
const guild: undefined | Guild = (d as any).guild_id !== undefined ? await gateway.client.guilds.get((d as any).guild_id) : undefined
const guild: undefined | Guild =
'guild_id' in d
? // eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
await gateway.client.guilds.get((d as GuildChannelPayload).guild_id)
: undefined
const channel = getChannelByType(gateway.client, d, guild)
if (channel !== undefined) {
await gateway.client.channels.set(d.id, d)

View File

@ -1,9 +1,8 @@
import { Gateway, GatewayEventHandler } from '../index.ts'
import { Guild } from '../../structures/guild.ts'
import { GuildPayload, MemberPayload } from '../../types/guild.ts'
import { GuildPayload } from '../../types/guild.ts'
import { MembersManager } from '../../managers/members.ts'
import { GuildChannelPayload } from '../../types/channel.ts'
import { RolePayload } from '../../types/role.ts'
import { RolesManager } from '../../managers/roles.ts'
export const guildCreate: GatewayEventHandler = async (
@ -17,7 +16,7 @@ export const guildCreate: GatewayEventHandler = async (
if (d.members !== undefined) {
const members = new MembersManager(gateway.client, guild)
await members.fromPayload(d.members as MemberPayload[])
await members.fromPayload(d.members)
guild.members = members
}
@ -30,7 +29,7 @@ export const guildCreate: GatewayEventHandler = async (
if (d.roles !== undefined) {
const roles = new RolesManager(gateway.client, guild)
await roles.fromPayload(d.roles as RolePayload[])
await roles.fromPayload(d.roles)
guild.roles = roles
}
@ -39,15 +38,15 @@ export const guildCreate: GatewayEventHandler = async (
await gateway.client.guilds.set(d.id, d)
guild = new Guild(gateway.client, d)
if ((d as any).members !== undefined) {
if (d.members !== undefined) {
const members = new MembersManager(gateway.client, guild)
await members.fromPayload(d.members as MemberPayload[])
await members.fromPayload(d.members)
guild.members = members
}
if (d.channels !== undefined) {
for (const ch of d.channels as GuildChannelPayload[]) {
;(ch as any).guild_id = d.id
ch.guild_id = d.id
await gateway.client.channels.set(ch.id, ch)
}
}

View File

@ -3,7 +3,7 @@ import { Guild } from '../../structures/guild.ts'
export const guildMemberAdd: GatewayEventHandler = async (
gateway: Gateway,
d: any
d:
) => {
const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id)
// Weird case, shouldn't happen

View File

@ -1,21 +1,22 @@
import { Gateway, GatewayEventHandler } from '../index.ts'
import { Guild } from '../../structures/guild.ts'
import { User } from "../../structures/user.ts"
import { User } from '../../structures/user.ts'
import { GuildMemberRemovePayload } from '../../types/gateway.ts'
export const guildMemberRemove: GatewayEventHandler = async (
gateway: Gateway,
d: any
d: GuildMemberRemovePayload
) => {
const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id)
// Weird case, shouldn't happen
if (guild === undefined) return
const member = await guild.members.get(d.id)
await guild.members.delete(d.id)
const member = await guild.members.get(d.user.id)
await guild.members.delete(d.user.id)
if (member !== undefined) gateway.client.emit('guildMemberRemove', member)
else {
const user = new User(gateway.client, d.user)
gateway.client.emit('guildMemberRemoveUncached', user)
}
}
}

View File

@ -1,20 +1,32 @@
import { Gateway, GatewayEventHandler } from '../index.ts'
import { Guild } from '../../structures/guild.ts'
import { GuildMemberUpdatePayload } from '../../types/gateway.ts'
import { MemberPayload } from '../../types/guild.ts'
export const guildMemberUpdate: GatewayEventHandler = async (
gateway: Gateway,
d: any
d: GuildMemberUpdatePayload
) => {
const guild: Guild | undefined = await gateway.client.guilds.get(d.guild_id)
// Weird case, shouldn't happen
if (guild === undefined) return
const member = await guild.members.get(d.id)
await guild.members.set(d.id, d)
const newMember = await guild.members.get(d.id)
if (member !== undefined) gateway.client.emit('guildMemberRemove', member, newMember)
else {
gateway.client.emit('guildMemberUpdateUncached', newMember)
const member = await guild.members.get(d.user.id)
const newMemberPayload: MemberPayload = {
user: d.user,
roles: d.roles,
joined_at: d.joined_at,
nick: d.nick,
premium_since: d.premium_since,
deaf: member?.deaf ?? false,
mute: member?.mute ?? false
}
}
await guild.members.set(d.user.id, newMemberPayload)
const newMember = await guild.members.get(d.user.id)
if (member !== undefined)
gateway.client.emit('guildMemberRemove', member, newMember)
else {
gateway.client.emit('guildMemberUpdateUncached', newMember)
}
}

View File

@ -26,7 +26,7 @@ export const messageCreate: GatewayEventHandler = async (
await guild.members.set(d.author.id, d.member)
member = await guild.members.get(d.author.id)
}
const message = new Message(gateway.client, d, channel as any, user)
const message = new Message(gateway.client, d, channel, user)
if (guild !== undefined) message.guild = guild
await message.mentions.fromPayload(d)
message.member = member

View File

@ -1,11 +1,12 @@
import { Message } from "../../structures/message.ts"
import { Message } from '../../structures/message.ts'
import { TextChannel } from '../../structures/textChannel.ts'
import { User } from "../../structures/user.ts"
import { User } from '../../structures/user.ts'
import { MessagePayload } from '../../types/channel.ts'
import { Gateway, GatewayEventHandler } from '../index.ts'
export const messageUpdate: GatewayEventHandler = async (
gateway: Gateway,
d: any
d: MessagePayload
) => {
let channel = await gateway.client.channels.get<TextChannel>(d.channel_id)
// Fetch the channel if not cached
@ -14,7 +15,10 @@ export const messageUpdate: GatewayEventHandler = async (
channel = (await gateway.client.channels.fetch(d.channel_id)) as TextChannel
const message = await channel.messages.get(d.id)
const author = message?.author !== undefined ? message.author : new User(gateway.client, d)
const author =
message?.author !== undefined
? message.author
: new User(gateway.client, d.author)
const newMsg = new Message(gateway.client, d, channel, author)
if (message === undefined) {
await channel.messages.set(d.id, d)

View File

@ -1,15 +1,19 @@
import { User } from '../../structures/user.ts'
import { Ready } from "../../types/gateway.ts"
import { GuildPayload } from '../../types/guild.ts'
import { Gateway, GatewayEventHandler } from '../index.ts'
export const ready: GatewayEventHandler = async (gateway: Gateway, d: any) => {
export const ready: GatewayEventHandler = async (gateway: Gateway, d: Ready) => {
await gateway.client.guilds.flush()
gateway.client.user = new User(gateway.client, d.user)
gateway.sessionID = d.session_id
gateway.debug(`Received READY. Session: ${gateway.sessionID}`)
await gateway.cache.set("session_id", gateway.sessionID)
d.guilds.forEach((guild: GuildPayload) => {
gateway.client.guilds.set(guild.id, guild)
})
gateway.client.emit('ready')
}

View File

@ -1,10 +1,18 @@
import { User } from '../../structures/user.ts'
import { CLIENT_USER } from '../../types/endpoint.ts'
import { Resume } from '../../types/gateway.ts'
import { Gateway, GatewayEventHandler } from '../index.ts'
export const resume: GatewayEventHandler = async (gateway: Gateway, d: any) => {
export const resume: GatewayEventHandler = async (
gateway: Gateway,
d: Resume
) => {
gateway.debug(`Session Resumed!`)
gateway.client.emit('resume')
if (gateway.client.user === undefined) gateway.client.user = new User(gateway.client, await gateway.client.rest.get(CLIENT_USER()))
if (gateway.client.user === undefined)
gateway.client.user = new User(
gateway.client,
await gateway.client.rest.get(CLIENT_USER())
)
gateway.client.emit('ready')
}
}

View File

@ -8,13 +8,14 @@ import { GatewayResponse } from '../types/gatewayResponse.ts'
import {
GatewayOpcodes,
GatewayIntents,
GatewayCloseCodes
GatewayCloseCodes,
IdentityPayload,
StatusUpdatePayload
} from '../types/gateway.ts'
import { gatewayHandlers } from './handlers/index.ts'
import { GATEWAY_BOT } from '../types/endpoint.ts'
import { GatewayCache } from '../managers/gatewayCache.ts'
import { ClientActivityPayload } from '../structures/presence.ts'
import { delay } from "../utils/delay.ts"
import { delay } from '../utils/delay.ts'
/**
* Handles Discord gateway connection.
@ -116,7 +117,7 @@ class Gateway {
}
if (t !== null && t !== undefined) {
this.client.emit('raw', t, d)
const handler = gatewayHandlers[t]
if (handler !== undefined) {
@ -181,7 +182,9 @@ class Gateway {
} else if (event.code === GatewayCloseCodes.DISALLOWED_INTENTS) {
throw new Error("Given Intents aren't allowed")
} else {
this.debug('Unknown Close code, probably connection error. Reconnecting in 5s.')
this.debug(
'Unknown Close code, probably connection error. Reconnecting in 5s.'
)
await delay(5000)
// eslint-disable-next-line @typescript-eslint/no-floating-promises
this.reconnect()
@ -217,40 +220,39 @@ class Gateway {
}
}
const payload: any = {
op: GatewayOpcodes.IDENTIFY,
d: {
token: this.token,
properties: {
$os: Deno.build.os,
$browser: 'harmony',
$device: 'harmony'
},
compress: true,
shard: [0, 1], // TODO: Make sharding possible
intents: this.intents.reduce(
(previous, current) => previous | current,
0
),
presence: this.client.presence.create()
}
const payload: IdentityPayload = {
token: this.token,
properties: {
$os: Deno.build.os,
$browser: 'harmony',
$device: 'harmony'
},
compress: true,
shard: [0, 1], // TODO: Make sharding possible
intents: this.intents.reduce(
(previous, current) => previous | current,
0
),
presence: this.client.presence.create()
}
if (this.client.bot === false) {
this.debug('Modify Identify Payload for Self-bot..')
delete payload.d.intents
payload.d.presence = null
payload.d.properties = {
$os: 'Windows',
delete payload.intents
payload.presence = undefined
payload.properties = {
$os: 'windows',
$browser: 'Firefox',
$device: '',
$referrer: '',
$referring_domain: ''
}
payload.d.synced_guilds = []
}
this.send(payload)
this.send({
op: GatewayOpcodes.IDENTIFY,
d: payload
})
}
private async sendResume (): Promise<void> {
@ -313,7 +315,7 @@ class Gateway {
return true
}
sendPresence (data: ClientActivityPayload): void {
sendPresence (data: StatusUpdatePayload): void {
this.send({
op: GatewayOpcodes.PRESENCE_UPDATE,
d: data

View File

@ -33,7 +33,8 @@ export class BaseManager<T, T2> {
}
async array (): Promise<undefined | T2[]> {
const arr = await (this.client.cache.array(this.cacheName) as T[])
let arr = await (this.client.cache.array(this.cacheName) as T[])
if (arr === undefined) arr = []
return arr.map(e => new this.DataType(this.client, e)) as any
}
@ -48,7 +49,7 @@ export class BaseManager<T, T2> {
return collection
}
flush(): any {
flush (): any {
return this.client.cache.deleteCache(this.cacheName)
}
}

View File

@ -1,50 +1,61 @@
import { Client } from '../models/client.ts'
import { Channel } from '../structures/channel.ts'
import { ChannelPayload } from '../types/channel.ts'
import { ChannelPayload, GuildChannelPayload } from '../types/channel.ts'
import { CHANNEL } from '../types/endpoint.ts'
import getChannelByType from '../utils/getChannelByType.ts'
import { BaseManager } from './base.ts'
export class ChannelsManager extends BaseManager<ChannelPayload, Channel> {
constructor(client: Client) {
super(client, "channels", Channel)
constructor (client: Client) {
super(client, 'channels', Channel)
}
// Override get method as Generic
async get<T = Channel>(key: string): Promise<T | undefined> {
async get<T = Channel> (key: string): Promise<T | undefined> {
const data = await this._get(key)
if (data === undefined) return
let guild
if ((data as any).guild_id !== undefined) {
guild = await this.client.guilds.get((data as any).guild_id)
if ('guild_id' in data) {
guild = await this.client.guilds.get(
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
(data as GuildChannelPayload).guild_id
)
}
const res = getChannelByType(this.client, data, guild)
return res as any
}
async array(): Promise<undefined | Channel[]> {
const arr = await (this.client.cache.array(this.cacheName) as ChannelPayload[])
async array (): Promise<undefined | Channel[]> {
const arr = await (this.client.cache.array(
this.cacheName
) as ChannelPayload[])
const result: any[] = []
for (const elem of arr) {
let guild
if ((elem as any).guild_id !== undefined) {
guild = await this.client.guilds.get((elem as any).guild_id)
if ('guild_id' in elem) {
guild = await this.client.guilds.get(
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
(elem as GuildChannelPayload).guild_id
)
}
result.push(getChannelByType(this.client, elem, guild))
}
return result
}
async fetch(id: string): Promise<Channel> {
async fetch (id: string): Promise<Channel> {
return await new Promise((resolve, reject) => {
this.client.rest.get(CHANNEL(id)).then(async data => {
this.set(id, data as ChannelPayload)
let guild
if (data.guild_id !== undefined) {
guild = await this.client.guilds.get(data.guild_id)
}
resolve(getChannelByType(this.client, data as ChannelPayload, guild))
}).catch(e => reject(e))
this.client.rest
.get(CHANNEL(id))
.then(async data => {
this.set(id, data as ChannelPayload)
let guild
if (data.guild_id !== undefined) {
guild = await this.client.guilds.get(data.guild_id)
}
resolve(getChannelByType(this.client, data as ChannelPayload, guild))
})
.catch(e => reject(e))
})
}
}

View File

@ -1,58 +1,37 @@
export type ActivityType = 'PLAYING' | 'STREAMING' | 'LISTENING' | 'WATCHING' | 'CUSTOM_STATUS' | 'COMPETING';
export type StatusType = 'online' | 'invisible' | 'offline' | 'idle' | 'dnd';
import { ActivityGame, ClientActivity, StatusType } from '../types/presence.ts'
import { StatusUpdatePayload } from '../types/gateway.ts'
export enum ActivityTypes {
enum ActivityTypes {
PLAYING = 0,
STREAMING = 1,
LISTENING = 2,
WATCHING = 3,
CUSTOM_STATUS = 4,
COMPETING = 5,
}
export interface ActivityGame {
name: string;
type: 0 | 1 | 2 | 3 | 4 | 5 | ActivityType;
url?: string;
}
export interface ClientActivity {
status?: StatusType
activity?: ActivityGame | ActivityGame[]
since?: number | null
afk?: boolean
}
export interface ClientActivityPayload {
status: StatusType
activities: ActivityGame[] | null
since: number | null
afk: boolean
COMPETING = 5
}
export class ClientPresence {
status: StatusType = 'online'
activity?: ActivityGame | ActivityGame[]
activity?: ActivityGame | ActivityGame[]
since?: number | null
afk?: boolean
constructor(data?: ClientActivity | ClientActivityPayload | ActivityGame) {
constructor (data?: ClientActivity | StatusUpdatePayload | ActivityGame) {
if (data !== undefined) {
if ((data as ClientActivity).activity !== undefined) {
Object.assign(this, data)
} else if ((data as ClientActivityPayload).activities !== undefined) {
} else if ((data as StatusUpdatePayload).activities !== undefined) {
} else if ((data as ActivityGame).name !== undefined) {
if (this.activity === undefined) {
this.activity = data as ActivityGame
} else if (this.activity instanceof Array) {
this.activity.push(data as ActivityGame)
} else this.activity = [ this.activity, data as ActivityGame ]
} else this.activity = [this.activity, data as ActivityGame]
}
}
}
parse(payload: ClientActivityPayload): ClientPresence {
parse (payload: StatusUpdatePayload): ClientPresence {
this.afk = payload.afk
this.activity = payload.activities ?? undefined
this.since = payload.since
@ -60,11 +39,11 @@ export class ClientPresence {
return this
}
static parse(payload: ClientActivityPayload): ClientPresence {
static parse (payload: StatusUpdatePayload): ClientPresence {
return new ClientPresence().parse(payload)
}
create(): ClientActivityPayload {
create (): StatusUpdatePayload {
return {
afk: this.afk === undefined ? false : this.afk,
activities: this.createActivity(),
@ -73,51 +52,56 @@ export class ClientPresence {
}
}
createActivity(): ActivityGame[] | null {
createActivity (): ActivityGame[] | null {
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
const activity = this.activity === undefined ? null : (this.activity instanceof Array ? this.activity : [this.activity]) || null
const activity =
this.activity === undefined
? null
: this.activity instanceof Array
? this.activity
: [this.activity]
if (activity === null) return activity
else {
activity.map(e => {
if (typeof e.type === "string") e.type = ActivityTypes[e.type]
if (typeof e.type === 'string') e.type = ActivityTypes[e.type]
return e
})
return activity
}
}
setStatus(status: StatusType): ClientPresence {
setStatus (status: StatusType): ClientPresence {
this.status = status
return this
}
setActivity(activity: ActivityGame): ClientPresence {
setActivity (activity: ActivityGame): ClientPresence {
this.activity = activity
return this
}
setActivities(activities: ActivityGame[]): ClientPresence {
setActivities (activities: ActivityGame[]): ClientPresence {
this.activity = activities
return this
}
setAFK(afk: boolean): ClientPresence {
setAFK (afk: boolean): ClientPresence {
this.afk = afk
return this
}
removeAFK(): ClientPresence {
removeAFK (): ClientPresence {
this.afk = false
return this
}
toggleAFK(): ClientPresence {
toggleAFK (): ClientPresence {
this.afk = this.afk === undefined ? true : !this.afk
return this
}
setSince(since?: number): ClientPresence {
setSince (since?: number): ClientPresence {
this.since = since
return this
}
}
}

View File

@ -100,10 +100,10 @@ export interface MessagePayload {
export interface MessageOption {
tts?: boolean
embed: Embed
embed?: Embed
file?: Attachment
allowedMention?: {
parse: ['everyone', 'users', 'roles']
parse: 'everyone' | 'users' | 'roles'
roles: string[]
users: string[]
}

View File

@ -1,9 +1,13 @@
// https://discord.com/developers/docs/topics/opcodes-and-status-codes#gateway
// https://discord.com/developers/docs/topics/gateway#commands-and-events-gateway-events
import { StatusType } from '../../mod.ts'
import { EmojiPayload } from './emoji.ts'
import { MemberPayload } from './guild.ts'
import { ActivityPayload } from './presence.ts'
import {
ActivityGame,
ActivityPayload,
StatusType,
ClientStatus
} from './presence.ts'
import { RolePayload } from './role.ts'
import { UserPayload } from './user.ts'
@ -107,23 +111,17 @@ export interface IdentityPayload {
compress?: boolean
large_threshold?: number
shard?: number[]
presence?: UpdateStatus
presence?: StatusUpdatePayload
guildSubscriptions?: boolean
intents: number
}
export enum UpdateStatus {
online = 'online',
dnd = 'dnd',
afk = 'idle',
invisible = 'invisible',
offline = 'offline'
intents?: number
}
export interface IdentityConnection {
$os: 'darwin' | 'windows' | 'linux' | 'custom os'
$browser: 'harmony'
$device: 'harmony'
$browser: 'harmony' | 'Firefox'
$device: 'harmony' | ''
$referrer?: ''
$referring_domain?: ''
}
export interface Resume {
@ -159,7 +157,7 @@ export interface Hello {
heartbeat_interval: number
}
export interface ReadyEvent {
export interface Ready {
v: number
user: UserPayload
privateChannels: []
@ -294,7 +292,14 @@ export interface PresenceUpdatePayload {
guild_id: string
status: StatusType
activities: ActivityPayload[]
client_status: UpdateStatus[]
client_status: ClientStatus
}
export interface StatusUpdatePayload {
status: StatusType
activities: ActivityGame[] | null
since: number | null
afk: boolean
}
export interface TypeStart {

View File

@ -1,7 +1,7 @@
export interface ClientStatus {
desktop?: string
mobile?: string
web?: string
desktop?: StatusType
mobile?: StatusType
web?: StatusType
}
export interface ActivityPayload {
@ -57,4 +57,26 @@ export enum ActivityFlags {
JOIN_REQUEST = 1 << 3,
SYNC = 1 << 4,
PLAY = 1 << 5
}
}
export type ActivityType =
| 'PLAYING'
| 'STREAMING'
| 'LISTENING'
| 'WATCHING'
| 'CUSTOM_STATUS'
| 'COMPETING'
export type StatusType = 'online' | 'invisible' | 'offline' | 'idle' | 'dnd'
export interface ActivityGame {
name: string
type: 0 | 1 | 2 | 3 | 4 | 5 | ActivityType
url?: string
}
export interface ClientActivity {
status?: StatusType
activity?: ActivityGame | ActivityGame[]
since?: number | null
afk?: boolean
}