cubbot/src/modules/Connection.ts

107 lines
3.8 KiB
TypeScript

import md from 'minecraft-data'
import Cubbot from '../Cubbot'
import Data from '../utils/Data'
import Module from '../utils/Module'
import Chat, { IMessage } from './Chat'
import Spawn from './Spawn'
type DisconnectReason = 'authservers_down' | 'banned' | 'banned.reason' | 'banned.expiration' | 'banned_ip.reason' |
'banned_ip.expiration' | 'duplicate_login' | 'flying' | 'generic' | 'idling' | 'illegal_characters' |
'invalid_entity_attacked' | 'invalid_player_movement' | 'invalid_vehicle_movement' | 'ip_banned' | 'kicked' |
'outdated_client' | 'outdated_server' | 'server_shutdown' | 'slow_login' | 'unverified_username' |
'not_whitelisted' | 'server_full' | 'name_taken' | 'unexpected_query_response' | 'genericReason' |
'disconnected' | 'lost' | 'kicked' | 'timeout' | 'closed' | 'loginFailed' | 'loginFailedInfo' |
'loginFailedInfo.serversUnavailable' | 'loginFailedInfo.invalidSession' | 'quitting' | 'endOfStream' |
'overflow' | 'spam'
const REASON_PREFIX = 'disconnect.'
interface IConfig {
/** Game data url */
dataSource: string
/** Game data cache path */
dataDir: string
reconnect: DisconnectReason[] | boolean
reconnectDelay: number
}
/** Connection informations */
export default class Connection extends Module<IConfig> {
private _connected = false
public get connected() {
return this._connected
}
private _oldData = md('1.14')
public get oldData() {
return this._oldData
}
private _data = new Data()
public get data() {
return this._data
}
private _engine?: Cubbot
public setEngine(value: Cubbot) {
this._engine = value
}
protected mount() {
const spawn = this.load<Spawn>(Spawn)
spawn.addCheck('data')
this.client.on('connect', () => {
this._connected = true
this.logger.trace('Connected')
this._data.onReady(() => spawn.validateCheck('data'))
})
this.client.on('disconnect', ({ reason }) => {
this._connected = false
const message: IMessage = JSON.parse(reason)
this.logger.warn({ msg: 'Disconnected', type: 'reason', value: Chat.parse(message, this.oldData.language) })
this.bye(message.translate)
})
this.client.on('kick_disconnect', ({ reason }) => {
this._connected = false
const message: IMessage = JSON.parse(reason)
this.logger.warn({ msg: 'Kicked', type: 'reason', value: Chat.parse(message, this.oldData.language) })
this.bye(message.translate)
})
this.client.on('login', () => {
this.logger.trace('Logged')
this._data.load(this.conf.dataSource, this.conf.dataDir, (this.client as any).version,
this.logger.child({ name: 'Data', level: 'info' }))
// FIXME: use 'minecraft-data' when it include 1.15+
})
this.client.on('error', error => {
this.logger.error({ msg: 'Error', value: error })
})
}
protected getConf() {
return {
dataDir: './data/',
dataSource: 'https://pokechu22.github.io/Burger/',
reconnect: false,
reconnectDelay: 5000,
}
}
private bye(reason?: string) {
if (this.conf.reconnect === true || (this.conf.reconnect !== false && reason !== undefined &&
this.conf.reconnect.some(r => reason.endsWith(REASON_PREFIX + r)))
) {
this._engine?.umount(false)
this.logger.info({ msg: 'Reconnecting', type: 'ms', value: this.conf.reconnectDelay })
// MAYBE: exponental backoff
setTimeout(() => this._engine?.mount(), this.conf.reconnectDelay)
} else {
this.logger.info('Bye')
this._engine?.umount(true)
}
}
}