Skip to content

Instantly share code, notes, and snippets.

@Alynva
Last active September 15, 2022 16:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Alynva/6803004270a714de99b42ab9941243fa to your computer and use it in GitHub Desktop.
Save Alynva/6803004270a714de99b42ab9941243fa to your computer and use it in GitHub Desktop.
G-Node utility to wait until a packet is intercepted with promise and timeout.
import { EventEmitter } from 'node:events'
import { Extension, HDirection, HMessage } from "gnode-api"
const sleep = ms => new Promise(res => setTimeout(res, ms))
/**
* Usage:
* ```
* const waiter = new Waiter(ext)
* waiter.timeout = 60 * 1000 // optional, defaults to 10.000
* waiter.when(HDirection.TOSERVER, "MoveAvatar")
* .then(hMessage => console.log(hMessage))
* .catch(err => console.error(err))
* ```
*/
export default class Waiter {
/** @type {Extension} */
#ext
#events = new EventEmitter()
timeout = 10 * 1000
/** @param {Extension} ext */
constructor(ext) {
if (!ext) throw new Error("You must pass the extension when creating a new Waiter.")
this.#ext = ext
ext.interceptAll(HDirection.TOCLIENT, this.#interceptHandler.bind(this))
ext.interceptAll(HDirection.TOSERVER, this.#interceptHandler.bind(this))
}
/** @param {HMessage} message */
#interceptHandler(message) {
const packetNames = this.#getPacketNames(message)
if (!packetNames || !packetNames.length) {
console.warn(`Not packet info available or unknown packet.`)
}
for (const name of packetNames) {
this.#events.emit(name, message)
}
}
/** @param {HMessage} message */
#getPacketNames(message) {
const direction = message.getDestination()
const packet = message.getPacket()
const packetInfoManager = this.#ext.getPacketInfoManager()
if (!packetInfoManager) {
return
}
const packetInfos = packetInfoManager.getAllPacketInfoFromHeaderId(direction, packet.headerId())
const packetNames = packetInfos
.filter((x, i, a) => i.name !== null && i === a.indexOf(x))
.map(i => `${i.name}`)
return packetNames
}
/**
* @param {HDirection} direction
* @param {String} packetName
*/
async when(direction, packetName) {
/** @type {Promise<HMessage>} */
const promise = Promise(async (res, rej) => {
let completed = false
/** @param {HMessage} message */
function listener(message) {
if (message.getDestination() === direction) {
completed = true
res(message)
}
}
this.#events.once(packetName, listener)
await sleep(this.timeout)
this.#events.removeListener(packetName, listener)
if (completed) return
rej(new Error(`Waiting for ${packetName} timed out.`))
})
return promise
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment