Last active
January 26, 2024 03:01
-
-
Save scheibo/a72ff41ce7c454ca428f7ed30a30ce44 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env node | |
'use strict'; | |
// !!!!!!!!!!!!!!!!!!!!! | |
// ! ADD ACCOUNTS HERE ! | |
// !!!!!!!!!!!!!!!!!!!!! | |
const ACCOUNTS = { | |
// 'username': 'password', | |
}; | |
const packages = []; | |
for (const dep of ['@pkmn/login', '@pkmn/protocol', 'ws']) { | |
try { | |
require.resolve(dep); | |
} catch (err) { | |
if (err.code !== 'MODULE_NOT_FOUND') throw err; | |
packages.push(dep); | |
} | |
} | |
if (packages.length) { | |
require('child_process').execSync(`npm install ${packages.join(' ')} --no-audit --no-save `, { | |
stdio: 'inherit', | |
cwd: __dirname, | |
}); | |
} | |
const https = require('https'); | |
const {Actions} = require('@pkmn/login'); | |
const {Protocol} = require('@pkmn/protocol'); | |
const WebSocket = require('ws'); | |
const server = 'sim.smogon.com'; | |
const serverport = 8000; | |
function fetch(action, cookie) { | |
const headers = cookie ? {'Set-Cookie': cookie, ...action.headers} : action.headers; | |
return new Promise((resolve, reject) => { | |
let buf = ''; | |
const req = https.request(action.url, {method: action.method, headers}, res => { | |
if (res.statusCode !== 200) return reject(new Error(`HTTP ${res.statusCode}`)); | |
const sid = res.headers['set-cookie']?.find(c => c.startsWith('sid=')); | |
res.on('data', d => { | |
buf += d; | |
}); | |
res.on('end', () => resolve(buf)); | |
}); | |
req.on('error', reject); | |
req.write(action.data); | |
req.end(); | |
}); | |
} | |
class User { | |
constructor(connection) { | |
this.connection = connection; | |
} | |
async login(details) { | |
const action = Actions.login(details); | |
const cmd = action.onResponse(await fetch(action)); | |
if (cmd) this.connection.send(cmd); | |
} | |
async upkeep(details, cookie) { | |
const action = Actions.upkeep(details); | |
const cmd = action.onResponse(await fetch(action, cookie)); | |
if (cmd) this.connection.send(cmd); | |
} | |
async logout() { | |
if (this.username) { | |
const action = Actions.logout({username: this.username}); | |
const cmd = action.onResponse(await fetch(action)); | |
if (cmd) this.connection.send(cmd); | |
this.username = undefined; | |
} | |
} | |
} | |
class Connection { | |
open(fn) { | |
this.ws = new WebSocket(`ws://${server}:${serverport}/showdown/websocket`); | |
this.ws.onmessage = ({data}) => { | |
fn(data); | |
}; | |
this.ws.onopen = () => { | |
console.log(`Connected to ${this.ws.url}`); | |
}; | |
this.ws.onclose = e => { | |
const clean = e.wasClean ? ' cleanly ' : ' '; | |
const reason = e.reason ? `: ${e.reason}` : ''; | |
console.log(`Disconnected${clean}from ${this.ws.url} with ${e.code}${reason}`); | |
}; | |
this.ws.onerror = e => { | |
const msg = e.message; | |
if (msg === 'TIMEOUT') return; | |
console.error(`Connection error${e.message ? `: ${e.message}` : ''}`); | |
}; | |
} | |
close() { | |
this.ws.close(); | |
} | |
send(message) { | |
this.ws.send(message); | |
} | |
} | |
(async () => { | |
const connection = new Connection(); | |
try { | |
const done = new Promise(end => { | |
connection.open(async data => { | |
for (const username in ACCOUNTS) { | |
const wait = new Promise(async resolve => { | |
const user = new User(connection); | |
for (const {args} of Protocol.parse(data)) { | |
switch (args[0]) { | |
case 'challstr': { | |
const challstr = args[1]; | |
const password = ACCOUNTS[username]; | |
user.login({username, challstr, password}).catch(err => { | |
console.error(err); | |
connection.close(); | |
process.exit(1); | |
}); | |
break; | |
} | |
case 'updateuser': { | |
const name = args[1].trim(); | |
if (name.startsWith('Guest')) continue; | |
console.log(`Logged in to '${name.trim()}'`); | |
try { | |
await user.logout(); | |
console.log(`Logged out of '${username.trim()}'`); | |
} finally { | |
resolve(); | |
} | |
break; | |
} | |
} | |
} | |
}); | |
await wait; | |
} | |
end(); | |
}); | |
}); | |
await done; | |
} finally { | |
connection.close(); | |
} | |
})().catch(err => { | |
console.error(err); | |
process.exit(1); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment