Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Task Queue Utility #1213

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 40 additions & 0 deletions examples/taskqueuer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* This examples show the usage of the task queue class in order to help
* make your code look cleaner when running lots of nested async tasks.
*
* This is helpful to preventing "pyramid of doom"-style callback nesting.
*/
const mineflayer = require('mineflayer')

if (process.argv.length < 4 || process.argv.length > 6) {
console.log('Usage : node taskqueuer.js <host> <port> [<name>] [<password>]')
process.exit(1)
}

const bot = mineflayer.createBot({
host: process.argv[2],
port: parseInt(process.argv[3]),
username: process.argv[4] ? process.argv[4] : 'TaskQueueBot',
password: process.argv[5]
})

bot.on('spawn', () => {
const queue = new mineflayer.TaskQueue()
const entity = bot.player.entity

// Through the use of a task queuer, we can add a lot of nested actions to the queue
// Each task is called inside the callback of the previous task.

queue.add(cb => setTimeout(cb, 5000)) // Works on any async function
queue.addSync(() => bot.chat('Going to mine down 10 blocks')) // Support for sync functions, too.

for (let i = 1; i <= 10; i++) {
queue.add(cb => setTimeout(cb, 1000))
queue.add(cb => bot.dig(bot.blockAt(entity.position.offset(0, -1, 0)), cb)) // Make sure to pass the cb into the callback!
queue.add(cb => setTimeout(cb, 50))
queue.addSync(() => bot.chat(`Mined block ${i}`))
}

// After making the queue, call 'runAll' to execute it. You can add an optional callback when it's done.
queue.runAll(() => bot.chat('All done!'))
})
7 changes: 7 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -768,3 +768,10 @@ export var supportedVersions: Array<string>;
export var testedVersions: Array<string>;

export function supportFeature(feature: string, version: string): boolean;

export class TaskQueue {
stopOnError: boolean;
add(cb: (cb: () => void) => void): void;
addSync(cb: () => void): void;
runAll(cb: (err?: Error) => void): void;
}
1 change: 1 addition & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ module.exports = {
Dispenser: require('./lib/dispenser'),
EnchantmentTable: require('./lib/enchantment_table'),
ScoreBoard: require('./lib/scoreboard'),
TaskQueue: require('./lib/taskqueue'),
BossBar: require('./lib/bossbar'),
supportedVersions,
testedVersions,
Expand Down
74 changes: 74 additions & 0 deletions lib/taskqueue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* A utility class for queuing up a set of actions to preform asynchronously.
*/
class TaskQueue {
constructor () {
this._tasks = []
this.stopOnError = true
}

/**
* Adds a new task to the end of this task queue.
*
* @param task - The async task to run.
*/
add (task) {
this._tasks.push(task)
}

/**
* Adds a new sync task to the end of this task queue.
*
* @param task - The sync task to run.
*/
addSync (task) {
this._tasks.push(cb => {
try {
task()
} catch (err) {
cb(err)
return
}

cb()
})
}

/**
* Runs all tasks currently in this queue and empties the queue.
*
* @param cb - The optional callback to run when all tasks are finished.
*/
runAll (cb) {
const taskList = this._tasks
this._tasks = []

if (!cb) cb = () => {}

let index = -1
const runNext = () => {
index++
if (index >= taskList.length) {
cb()
return
}

try {
taskList[index](err => {
if (err) {
cb(err)
if (this.stopOnError) return
}

runNext()
})
} catch (err) {
cb(err)
}
}

runNext()
}
}

module.exports = TaskQueue