There a number of places within a Busby system where it is possible to add scripts. These scripts enable Busby to be customised to work in exactly the way required for a particular operation.
Scripts are written in either JavaScript or TypeScript (as type safe version of JavaScript) or in some cases Python, and are provided with a busby.
helper object that can be used to interact with the rest of the system.
The following is a simple example of a script that checks a condition and sets an alarm.
const alarmId: string = 'my alarm';
for (let i=0; i<5; i++) {
busby.log(`i=${i}`)
if (i === 2) {
busby.setAlarm(alarmId);
}
}
Note here that we are using TypeScript, and so the alarmId
string has been given a type identifier - string
in this case. Also note the use of the busby.log
and busby.setAlarm
of the built-in busby.
object.
Further details of the features provided by the busby.
object are provided busby-object in the Busby reference section.
In order to get access to input data, scripts are provided with a root object. This object contains different fields dependent on how the script is created. For example when running a script in a workflow the root object has a field called job
, which refers to the job which is being transitioned.
const ref = root.job.internalRef;
busby.log("Ref is " + ref);
As well as the busby.
object several other useful libraries are included by default.
_
in the scripts)const jobs = [{internalRef: "ABC100"}, {internalRef: "ABC101"}, {internalRef: "DEF100"}]
const filtered = .filter(jobs, (job) => {
return _.startsWith(job.internalRef, "ABC");
})
Looks for the internalRef
starting with "ABC" and so will return two items form the jobs
array - [{internalRef: "ABC100"}, {internalRef: "ABC101"}]
moment
The moment library provides date and time manipulation routines. Note that there are also routines in busby.time
that can be used when broadcast timecodes are needed.
fs-extra (referred to as fs
in the scripts)
Provides access to file system calls. Note that there are also features in busby.file
that might be easier to use.
The fs-extra library introduces synchronous calls for most file operations, these are the calls to use, see Synchronous operation below.
path
Provides utilities for working with file and directory paths.
Scripts are run by busby services. Depending on the set up of the service, one or other of its providers decides to run the script, this provider in turn is associated with a host where it is running. When a script is run it starts up a node process, passes in the busby.
object, and then waits for the script to end. It is possible for a single provider to run up multiple scripts in this way.
The running script runs in the folder /opt/squaredpaper/busby
, and also has access to the shared node_modules folder in /opt/squaredpaper/busby/node_modules
.
When writing scripts in TypeScript the configuration editor transpiles these scripts into JavaScript before running.
Scripts in JavaScript or TypeScript are designed to work in a single-threaded user interface model. To keep UIs responsive callbacks or promises are used, so as to not tie up the single thread. Inside of Busby this model is not required, and in fact can be confusing. Therefore, all scripts inside Busby are synchronous.
In order to keep scripts as simple as possble all scripts in busby run synchronously.
Neither callbacks nor promises can be used in a Busby script. Everything must be synchronous.
In practise, this means that each line of code is performed procedurally. Once the end of a script is reached or busby.exit
is called, the script finishes and the node process is cleared.
Some of the helper classes in the busby.
object are provided to make this easier. For example to copy a file you should do the following:
Copy a file using
busby.file.copy
const success = busby.file.copy("/source/test.txt", "/destination");
console.log(success);
Normally when using node the following arrow function can be used. However, this will NOT work as expected.
Node arrow function - this will not work in a busby script
fs.copy("/source/test.txt", "/destination", (err) => {
if (!err) {
console.log("success")
}
});
In the above case the fs.copy
command will run, but the script will then immediately complete and exit, and the callback will be lost.
It is possible to import other libraries into a script as long as those libraries are part of the existing node_modules deployed. Currently it is advised to use the require
syntax, as such it is necessary to let the TypeScript compiler to know this is fine with the @ts-ignore option.
// @ts-ignore
const js2xml = require("js2xmlparser");
There are two modes when running node scripts, long running or standalone. When in long running script mode there are a pool of node services running all the time, and the script injects its code into one of these services. Standalone scripts create a new node service for each script that is run.
In general long running scripts are quicker, but it is possible to accidentally leak variables from one running instance to the next. Care should be taken to use variables outside of any functions when using the long running mode.