Processor API
Processor is a standalone node module that will be required/loaded by a Drovp thread.
It runs in its own raw Node.js process, and it's responsibility is to accept an operation payload, and return a promise that resolves when the operation has been processed.
The function has to be exported as a default export using CommonJS. ESModules are not supported yet (#2).
Example module
module.exports = async (payload, utils) => {
const {input, options} = payload;
// ... do what needs to be done to the input
// Optionally emit outputs
utils.output.file('/new/file/path.ext');
// Use node's built-in `console.*` methods for debugging/logging
console.time('log time');
console.log('hey');
console.timeEnd('log time');
};
#Debugging
If you want to log some stuff for debugging, use node's built-in console.*
methods, but maybe read up on the non-standard logging environment documented in the log utility below. If you want to prevent the issues described there, you can just use the utils.log()
instead, but this is not necessary in most cases.
These logs can then be seen in the operations Logs section.
#Processor
Type: (operation: Operation, utils: ProcessorUtils) => Promise<void>
Processor is a simple async function that accepts operation payload, some utilities, and resolves when everything is done.
#operation
Type: Operation
The operation payload. See Operation
below for more details.
#utils
Type: ProcessorUtils
The operation utilities. You can use these to report progress, access Drovp dependencies, emit outputs, ...
See ProcessorUtils
API below for more details.
#Return
Promise that resolves when operation is done. Any resolved value is ignored.
If you want to emit an output item, use utils.output
API.
If the promise throws, it's the same as calling utils.output.error(message)
and resolving right afterwards.
#Payload
interface Payload {
id: string;
options?: object;
inputs: Item[];
input: Item; // convenience getter for the 1st item in the `items` array
}
Operation payload with these properties:
#id
Type: string
Operation ID.
#options
Type: object
Processor's options schema generated and user configured options of the profile into which the item(s) were dropped into.
If processor doesn't have an options schema, this is undefined
.
Example
For options schema that looks like this:
[
{name: 'foo', type: 'boolean', default: false},
{name: 'bar', type: 'number', default: 0},
],
And assuming the user has kept all of the profile options on their default values, you'll get this options object:
{foo: false, bar: 0}
#input/inputs
Type: Item | Item[]
If processor config doesn't allow bulking (default behavior), operation will always have a single Item
in it's inputs
array. If bulking is enabled, there will be as many items in this array as user has dropped into the profile.
input
is just a convenience getter for the 1st item in the inputs
array. Useful if you only expect one input per operation.
#{other}
Type: any
Processor can also configure an operation preparator, which can modify the operation payload however it sees fit, in which case the payload will also have other properties you decided to add to it.
#Item
Type: ItemFile | ItemDirectory | ItemBlob | ItemString | ItemUrl
Depending on processor's accepts.*
configuration, Item can be one of:
#ItemFile
interface ItemFile {
kind: 'file';
type: string; // Lowercase extension without the dot
path: string; // Path to the file
size: number; // File size
}
#ItemDirectory
interface ItemDirectory {
kind: 'directory';
path: string; // Path to the directory
}
#ItemBlob
interface ItemBlob {
kind: 'blob';
mime: string; // Blob mime type
contents: Buffer; // BLob contents as a Buffer
}
#ItemString
interface ItemString {
kind: 'string';
type: string; // String type, e.g. 'text/plain'
contents: string; // String contents
}
#ItemURL
interface ItemUrl {
kind: 'url';
url: string; // URL path
}
#ProcessorUtils
interface ProcessorUtils {
dependencies: {[key: string]: any};
output: OutputEmitters;
progress: ProgressUtil;
title: (value: string | undefined | null) => void;
stage: (name: string) => void;
log: (...args: any[]) => void;
dataPath: string;
appVersion: string;
}
#dependencies
Type: {[key: string]: any}
A map of dependency names and their exports. Usually the exports are paths to binaries, but it can be any serializable value. See each dependency's documentation for what is being exported.
Each dependency export can be accessed with its short, and full no-collision name.
Example
If you depend on @drovp/ffmpeg:ffprobe
, your dependencies map will look like this:
{
ffprobe: '/path/to/ffprobe/binary',
'@drovp/ffmpeg:ffprobe': '/path/to/ffprobe/binary',
}
#output
Type: OutputEmitters
Utilities for emitting output items. See OutputEmitters
for details.
Quick example
output.file('/path/to/file');
output.directory('/path/to/directory');
output.url('https://example.com');
output.string('token_nd8S7f7aG87b');
output.warning('Something of interest.');
output.error(new Error('Something went wrong.'));
output.error('Something went wrong.');
// Attaching flair and/or badge
output.file('/path/to/file', {
flair: {variant: 'warning', title: 'foo', description: 'This item food the bad'},
badge: {variant: 'warning', icon: 'warning', title: 'This item food the bad'},
});
#progress
Type: Progress
A progress reporting utility. See Progress
.
Quick example
// using `progress()` method always sets all 3 values
// `total` and `indeterminate` parameters are always optional,
// and set to undefined when omitted
progress(completed, total, indeterminate);
progress(null); // reset all
progress({completed: 1, total: 10, indeterminate: true}); // object format
// using `progress.X` only updates concerned property
progress.completed = 1;
progress.total = 10;
progress.indeterminate = true;
#title
Type: (value: string | undefined | null) => void
Sets or deletes operation title. By default, operation titles are constructed from its payload (file paths, domains, etc), but if you have something more descriptive or relevant, you can use this to overwrite it.
#stage
Type: (name: string) => void
Used to name the stage the operation is currently in. This is just to provide an extra piece of information to the user.
The name should be 20 characters and less.
For example, if the operation downloads something and then extracts it, you'd set it to downloading
, than extracting
.
Setting a stage logs STAGE: ${name}
to the operation log.
#log
Type: (...args: any[]) => void
Logs one or multiple values into the current operations Logs section.
This is the actual utility responsible for sending operation logs. The global console.log
is replaced with it for the duration of the operation. This is necessary because all messaging (utils.output.*
, utils.stage
, ...) is handled through IPC channel, while console.log
outputs to stdout, is batched, and therefore not reliably in sync with other stuff. This would often cause operation logs to be out of sync/order with progress/stage/etc reporting, or even cause debugging issues where stuff that is logged just before the operation resolves is nowhere to be seen.
You can continue using console.log
, as it's definitely more comfortable (you don't have to be passing the log
utility to all dependencies), but just be aware that even thought it's replaced with the immediate IPC version, there is still an issue where if something in your operation reports AFTER the operation resolved (some hanging unresolved async calls you forgot to await for), it'll either be logged in the logs of the operation that came after it, or if the process is idle, logged in the Drovp's developer console as "Thread stdout with no job in progress" error. If preventing this is a high priority, you can of course just use this log()
instead of console.log()
directly, as it's scoped to the current operation.
Note: console.log
is the only replaced console.*
method. Everything else still reports through stdout/err, and has the aforementioned caveats.
#dataPath
A path where plugin can save it's session data that should persist. Intended for config files, credentials, logs, history, and such.
#appVersion
Type: string
Current Drovp app version.