Refactor client connection sequence (#189)
* Refactor client connection sequence Allow connection info to come in after Client construction, emit "connect_allowed" similar to nmp * Fix breaking ping behavior change * fix createClient connect callback * correct behavior * remove comments * refactor impl * fix incorrect use of `this`
This commit is contained in:
parent
0dc586db9c
commit
dfff13867d
3 changed files with 60 additions and 33 deletions
|
|
@ -4,7 +4,7 @@ const { serialize, isDebug } = require('./datatypes/util')
|
|||
const debug = require('debug')('minecraft-protocol')
|
||||
const Options = require('./options')
|
||||
const auth = require('./client/auth')
|
||||
|
||||
const initRaknet = require('./rak')
|
||||
const { KeyExchange } = require('./handshake/keyExchange')
|
||||
const Login = require('./handshake/login')
|
||||
const LoginVerify = require('./handshake/loginVerify')
|
||||
|
|
@ -19,20 +19,6 @@ class Client extends Connection {
|
|||
constructor (options) {
|
||||
super()
|
||||
this.options = { ...Options.defaultOptions, ...options }
|
||||
this.validateOptions()
|
||||
|
||||
const { RakClient } = require('./rak')(this.options.useNativeRaknet)
|
||||
|
||||
this.serializer = createSerializer(this.options.version)
|
||||
this.deserializer = createDeserializer(this.options.version)
|
||||
|
||||
KeyExchange(this, null, this.options)
|
||||
Login(this, null, this.options)
|
||||
LoginVerify(this, null, this.options)
|
||||
|
||||
const host = this.options.host
|
||||
const port = this.options.port
|
||||
this.connection = new RakClient({ useWorkers: this.options.useRaknetWorkers, host, port })
|
||||
|
||||
this.startGameData = {}
|
||||
this.clientRuntimeId = null
|
||||
|
|
@ -42,9 +28,31 @@ class Client extends Connection {
|
|||
this.outLog = (...args) => debug('C <-', ...args)
|
||||
}
|
||||
this.conLog = this.options.conLog === undefined ? console.log : this.options.conLog
|
||||
|
||||
if (!options.delayedInit) {
|
||||
this.init()
|
||||
}
|
||||
}
|
||||
|
||||
init () {
|
||||
this.validateOptions()
|
||||
this.serializer = createSerializer(this.options.version)
|
||||
this.deserializer = createDeserializer(this.options.version)
|
||||
|
||||
KeyExchange(this, null, this.options)
|
||||
Login(this, null, this.options)
|
||||
LoginVerify(this, null, this.options)
|
||||
|
||||
const { RakClient } = initRaknet(this.options.useNativeRaknet)
|
||||
const host = this.options.host
|
||||
const port = this.options.port
|
||||
this.connection = new RakClient({ useWorkers: this.options.useRaknetWorkers, host, port })
|
||||
|
||||
this.emit('connect_allowed')
|
||||
}
|
||||
|
||||
connect () {
|
||||
if (!this.connection) throw new Error('Connect not currently allowed') // must wait for `connect_allowed`, or use `createClient`
|
||||
this.on('session', this._connect)
|
||||
|
||||
if (this.options.offline) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,21 @@ const minecraftFolderPath = require('minecraft-folder-path')
|
|||
const debug = require('debug')('minecraft-protocol')
|
||||
const { uuidFrom } = require('../datatypes/util')
|
||||
|
||||
function validateOptions (options) {
|
||||
if (!options.profilesFolder) {
|
||||
options.profilesFolder = path.join(minecraftFolderPath, 'nmp-cache')
|
||||
}
|
||||
if (options.authTitle === undefined) {
|
||||
options.authTitle = Titles.MinecraftNintendoSwitch
|
||||
options.deviceType = 'Nintendo'
|
||||
}
|
||||
}
|
||||
|
||||
async function realmAuthenticate (options) {
|
||||
validateOptions(options)
|
||||
throw new Error('Not implemented')
|
||||
}
|
||||
|
||||
/**
|
||||
* Authenticates to Minecraft via device code based Microsoft auth,
|
||||
* then connects to the specified server in Client Options
|
||||
|
|
@ -13,16 +28,10 @@ const { uuidFrom } = require('../datatypes/util')
|
|||
* @param {object} options - Client Options
|
||||
*/
|
||||
async function authenticate (client, options) {
|
||||
if (!options.profilesFolder) {
|
||||
options.profilesFolder = path.join(minecraftFolderPath, 'nmp-cache')
|
||||
}
|
||||
if (options.authTitle === undefined) {
|
||||
options.authTitle = Titles.MinecraftNintendoSwitch
|
||||
options.deviceType = 'Nintendo'
|
||||
}
|
||||
validateOptions(options)
|
||||
try {
|
||||
const Authflow = new PrismarineAuth(options.username, options.profilesFolder, options, options.onMsaCode)
|
||||
const chains = await Authflow.getMinecraftBedrockToken(client.clientX509).catch(e => {
|
||||
const authflow = options.authflow || new PrismarineAuth(options.username, options.profilesFolder, options, options.onMsaCode)
|
||||
const chains = await authflow.getMinecraftBedrockToken(client.clientX509).catch(e => {
|
||||
if (options.password) console.warn('Sign in failed, try removing the password field')
|
||||
throw e
|
||||
})
|
||||
|
|
@ -71,5 +80,6 @@ function postAuthenticate (client, profile, chains) {
|
|||
|
||||
module.exports = {
|
||||
createOfflineSession,
|
||||
authenticate
|
||||
authenticate,
|
||||
realmAuthenticate
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,27 +1,36 @@
|
|||
const { Client } = require('./client')
|
||||
const { RakClient } = require('./rak')(true)
|
||||
const { Versions, CURRENT_VERSION } = require('./options')
|
||||
const { sleep } = require('./datatypes/util')
|
||||
const assert = require('assert')
|
||||
const Options = require('./options')
|
||||
const advertisement = require('./server/advertisement')
|
||||
const auth = require('./client/auth')
|
||||
|
||||
/** @param {{ version?: number, host: string, port?: number, connectTimeout?: number, skipPing?: boolean }} options */
|
||||
function createClient (options) {
|
||||
assert(options)
|
||||
const client = new Client({ port: 19132, ...options })
|
||||
const client = new Client({ port: 19132, ...options, delayedInit: true })
|
||||
|
||||
if (options.skipPing) {
|
||||
connect(client)
|
||||
} else { // Try to ping
|
||||
client.ping().then(data => {
|
||||
const ad = advertisement.fromServerName(data)
|
||||
client.options.version = options.version ?? (Versions[ad.version] ? ad.version : CURRENT_VERSION)
|
||||
if (client.conLog) client.conLog(`Connecting to server ${ad.motd} (${ad.name}), version ${ad.version}`, client.options.version !== ad.version ? ` (as ${client.options.version})` : '')
|
||||
client.emit('connect_allowed')
|
||||
connect(client)
|
||||
}, client)
|
||||
function onServerInfo () {
|
||||
if (options.skipPing) {
|
||||
client.init()
|
||||
} else {
|
||||
ping(options).then(ad => {
|
||||
const adVersion = ad.version?.split('.').slice(0, 3).join('.') // Only 3 version units
|
||||
client.options.version = options.version ?? (Options.Versions[adVersion] ? adVersion : Options.CURRENT_VERSION)
|
||||
client.conLog?.(`Connecting to server ${ad.motd} (${ad.name}), version ${ad.version}`, client.options.version !== ad.version ? ` (as ${client.options.version})` : '')
|
||||
client.init()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
if (options.realms) {
|
||||
auth.realmAuthenticate(client.options).then(onServerInfo).catch(e => client.emit('error', e))
|
||||
} else {
|
||||
onServerInfo()
|
||||
}
|
||||
|
||||
client.on('connect_allowed', () => connect(client))
|
||||
return client
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue