Skip to main content

Script library

The decoder, builder and pattern generator scripts installed on the server. Reached through server.scripts (server.scripts() in Rust; in C, the ss_scripts_* and ss_script_* functions take the server handle).

The library belongs to the server

It is shared by every workspace and every client. Installing a script makes it available to all of them, and deleting or renaming one takes it from all of them, including the ScanaStudio window.

Listing what is installed​

scripts = server.scripts

for script in scripts: # also scripts.all(), len(scripts)
print(script.file_name, script.name, script.version)

scripts.find("pwm.js") # by file name or declared name, or None
scripts.decoders() # the ones that can decode
scripts.generators() # the ones that can drive the pattern generator
scripts.library_dir # the folder, on the SERVER's machine

Fields of each script:

  • file_name: the file, relative to the library folder. This is what decoders.add(), pattern.add() and generation.add_builder() take.
  • name, version, author, description, help_url: from the tags in the script's source.
  • capabilities: decode, trigger, builder, builder_object, demo and pattern, one flag per kind of script the file provides.
  • origin_url: where the server downloaded it from; empty for a script written locally.
  • modified: the file was edited after it was downloaded, so an update would overwrite those edits.
  • file_access: the script may open paths of its own (see set_file_access).

The online catalogue​

report = server.scripts.sync() # timeout 300 s
catalogue = server.scripts.online() # refresh=True to fetch it again
names = server.scripts.install([catalogue[0].url])
  • sync() brings the library up to date with the online catalogue and waits for it to finish. A sync already running is joined rather than started again. It returns the report (how many scripts were downloaded, updated, skipped and failed) in Python and NodeJS.
  • online() reads the catalogue without installing anything. Each entry has name, version, author, url, description, help_url and release_notes.
  • install(urls, overwrite_modified=False) installs or updates catalogue entries, named by their download URL. A local file edited since its download is left alone unless overwrite_modified is set.

Adding and changing scripts​

CallWhat it does
import_file(file_name, source)Installs a script from its source text.
import_url(url)Downloads a script from a URL outside the catalogue.
create(file_name, name=…, …)Writes a new script from the template, with one stub per capability.
rename(file_name, new_file_name)Renames a script.
duplicate(file_name, new_file_name)Copies a script. Updates never overwrite the copy.
set_file_access(file_name, enabled)Lets a script open paths of its own.
delete(file_names)Deletes scripts. There is no recycle bin.
usage()How many instances use each script, across the open workspaces.

Every call in the table except usage() returns the list of file names it touched. When a name is already taken, the server writes the file under another name, so read the returned name rather than assuming the one you asked for.

names = server.scripts.create(
"my_bus.js",
name="My bus",
author="Bench team",
description="Decoder for our test bus",
decode=True, trigger=False, builder=False, pattern=False, demo=False,
)
server.scripts.duplicate("pwm.js", "pwm_bench.js")

for row in server.scripts.usage():
print(row.file_name, row.instances, row.workspaces)
Renaming breaks saved workspaces

A .scana refers to its decoders by file name. After a rename, saved workspaces that use the script no longer find it. Read usage() before you rename or delete a script.

set_file_access​

By default a script can only open the files the user picks through its own file fields. set_file_access(file_name, True) lets it open any path. It is off for every script until you turn it on. A granted script can read and write anything the account running the server can. The grant follows the file name, so a renamed script and a duplicate both start without it.

Errors​

A library operation that fails raises ScriptOpError in Python and NodeJS. It carries the server's message, skipped (files left alone because they were edited since their download) and failed (files the operation could not touch). In Rust it is Error::Io with the message. In C the call returns NULL (or a failing ss_status for ss_scripts_sync) and ss_last_error() says why.

An unreachable catalogue makes sync() and online() fail the same way.

Default timeouts in Python and NodeJS: 300 s for sync(), 120 s for online(), 180 s for the other operations.