Repetier-Server Module System

Introduction

The server core is a statically linked C++ program. It is also a critical part as it should not crash on any operation. So it is a good idea to keep that part as small as possible. To allow a extension we have included a scripting language called lua (http://www.lua.org) in version 5.3. This allows it, to add function to communicate with the server and store other data or call external programs. Modules can only be used within the pro version of the server.

Layout of a module

Each module should be as easy to install as possible. For that reason, it is very easy to create a new module. In the server installation directory is a folder called modules which stores all modules. Each module has a folder named like the module. That folder contains the following folders: lua, www, bin with bin being an optional directory. It is where you should store additional binary files. If you have binary files you will of course need a special version for each supported operating system. Key is the lua directory which must contain a file <module name>.lua that gets run when a new lua instance is created. Here you load additional lua files if needed and register all hooks that your module offers. It must NOT execute anything at this moment. The server creates a pool of lua interpreters to run them in parallel. The actions should only be performed, if the right action is called.

Your module might need additional web pages. The files put inside the www directory can be reached with the url http://<server name or ip>:3344/mod/<module name>/

Internal Lua classes

RepetierServer

Functions that are responsible for the complete server, can be accessed by the rs (=RepetierServer) object.

applicationDirectory | property(get)

Returns the application directory where the server is stored.

websiteDirectory | property(get)

Returns the root directory of the website definition.

storageDirectory | property(get)

Returns the root directory for data storage.

firmwareDirectory | property(get)

Returns the root directory where firmware definitions are stored.

modulesDirectory | property(get)

Returns the root directory of module definitions.

printerList | property(get)

Returns an array with all existing printer objects.

printerBySlug(slug) | function

Returns a Printer object for the given slug string.

sendPushMessage(string header, string message, string icon) -> bool | function

Sends a push message if enabled and configured. Returns true on success. icon can be one of the following strings: "ready", "info", "error" and "pause".

runThreaded(func function, table object) | function

Starts the function in a separate thread in a new lua instance. For this reason, you need to provide the name as a string and not directly. The second parameter gets mapped into a json object and gets send as second parameter. Use it for some tasks that are not resource hungry and can be executed quite fast.

dispatchJob(func function,table object,int priority) -> integer | function

Starts the function in a separate thread in a new lua instance as a job. There is always only one of these jobs running to preserve performance and resources. Job with highest priority is started next. Special case is where priorty is 100000 or higher. Here the job ist started immediately, regardless of any other running jobs. Should only be used for jobs without big resource usage. Difference to simply starting a thread is that it protocols the start and in case of a server crash it will restart on next start. For this reason, you need to provide the name as a string and not directly. The second parameter gets mapped into a json object and gets send as first parameter to the callback. The second callback parameter is the WorkDispatcher object you are running. If there is already a job with the same name and parameter that needs to be run, the execution is skipped.

runExecutable(exePath, array_of_parameter) -> int | function

Runs a given executable and returns the exit code. Text to console gets stored in log.

runExecutableWithOutput(string exePath,array array_of_parameter,func outputCallback) -> int | function

Runs a given executable and returns the exit code. For every line received the outputCallback is called with the line as parameter.

fileLength(string filepath) -> int | function

Returns the file length or a given file name.

pathExists(string path) -> bool | function

Returns true if the given path exists.

pathDelete(path) | function

Deletes the specified file.

pathExtension(string path) -> string | function

Extracts the extension from a filename.

pathBasename(string filename) | function

Returns the basename of a filepath.

pathConcat(string path1,string path2) -> string | function

Conatenates two strings to combine it to a longer directory/filename.

pathParent(string path) -> string | function

Returns the parent for the given directory or direcory for a file with directory.

pathIsDirectory(string path) -> bool | function

Returns true if path is a existing directory.

tempFile(string extension) | function

Returns a temporary file name. You should take care of deleting your temporary files. If some do not get deleted, the server will delete them on next startup.

pathRename(string old,string new) | function

Renames file old into file new.

sleep(int milliseconds) | function

Send current thread to sleep for a while. Use only in threads and dispatched jobs!

touchSerialWithBaud(string port,int baudrate) | function

Opens a serial port with given baud rate and closes it directly.

portList -> array | property

Returns the current list of ports.

reducePort(string port) -> string | function

Reduces a port name to the original port name. This may be required for linux where it is more secure to use /dev/serial/by-id/ port names, which are links to /dev/ where port names are not per device different and only order of connection matters.

translate(string text,string lang)->string | function

Alternative versions:

We can not translate text inside lua directly. So translation for lua responses work a bit different. First you need a dummy php file in your modules to contain all translateable text parts like this: <?php _('my text') ?>. If you need a placeholder use $1, $2, $3, $4. Then in lua simply call req:translate("my text","de") and it will return the translated text in german or original text. If you have placeholder to fill use the alternatives with 1-4 placeholder.

WorkDispatcher

sendMessage(string key, string message) | function

Sends a "workerMessage" event with the id of the work dispatcher. This allows the frontend to catch messages from worker.

finish(string message) | function

Sends the "workerFinished" event with the id oth the work dispatcher and message set to given message. Should be called at the end, otherwise the server will send the event with empty message. This allows the frontend to register the completition of a work task.

Printer

slug | property(string, get)

Slug of this printer.

dataDirectory | property(string, get)

Returns the data directory for this printer.

activated | property(boolean, get)

modelPrintjobManager | property(get)

Returns the PrintjobManager for models.

config | property(table)

Returns current printer configuration

settings | property(table)

Returns a table with current settings. If you only need one value use getSetting which also makes sure it exists.

getSetting(string key,string default) -> string | function

Return content of a printer referenced setting or returns default string.

setSetting(string key,string value) | function

Stores a value as printer setting and automatically saves the modified printer configuration.

jobPrintjobManager | property(get)

Returns the PrintjobManager for queued jobs.

injectManualCommand(gcode) | function

Injects the gcode into the printer.

injectManualCommandFirst(gcode) | function

Injects the gcode into the printer at the first possible place postponing all other pile dup manual commands.

printjobManagerFromFile(filename) | function

Returns the PrintjobManager that handles the given file. The manager is extracted from the contained directory.

activate() | function

Activates the printer, if it was not activated before.

deactivate() | function

Deactivates the printer, if it was not deactivated before.

PrintjobManager

Each printer has two managers for it's gcode files. One for the stored models and one for files queued for printing. Each list is stored in a separate directory. Containing files must use a special naming scheme. Each files start with a id followed by underline and filename plus extension. To ensure naming is correct all names have to be generated by encodeName function. You can associate any number of extra files with a gcode file as long as the id part stays the same. If a printjob gets created all associated files get copied. If a job gets deleted all files with sam eid get deleted.

encodeName(id,name,extension) | function

Returns a full file name with the given properties.

decodeNamePart(filename) | function

Returns the name part of a file name.

decodeIdPart(filename) | function

Returns the id contained ina file name.

findById(id) | function

Finds a Printjob object from the id.

findByName(name) | function

Finds a Printjob object form the name part.

findByFilename(filename) | function

Finds a Printjob object from a full filename.

removePrintjob(Printjob) | function

Deletes a Printjob from the queue including all associated files.

deleteAssociatedFilesForId(id) | function

Deletes all associated files for a id. Use this if you create a associated file and when beeing finished, the Printjob does not exist any more.

Printjob

id | property(get)

Model/job id.

name | property(get)

Filename of the gcode.

filesize | property(get)

Size in byte of the gcode file.

percentDone | property(get)

Print progress in percent while printing.

running | property(get)

True if this file is currently beeing printed.

deleted | property(get)

True if this file got deleted.

ServerRequest

pathSegments | property(get)

An array with all segments of the path. The first is always "dyn" and the second is the registered command. You can use this to add parameter in url form.

param(key,default) | function

Returns a request parameter from GET or POST. If not present, default will be returned.

originalFilename | property(get)

Original filename of the uploaded file if present.

ServerResponse

viewStaticFile(filename)

Returns the content of the given file. Mime type is set by file name extension.

returnJson(jsonTable)

Returns a table as json response.

returnText(text,mime)

Returns a text message.

language

Returns 2 char string with selected language file. Can be used to translate text.

translate(string text)->string | function

Alternative versions:

We can not translate text inside lua directly. So translation for lua responses work a bit different. First you need a dummy php file in your modules to contain all translateable text parts like this: <?php _('my text') ?>. If you need a placeholder use $1, $2, $3, $4. Then in lua simply call req:translate("my text") and it will return the translated or original text. If you have placeholder to fill use the alternatives with 1-4 placeholder.

Integrating into the server

Each lua instance has a registry for function that should be called at special events, like startup, events or on requested actions. If we want a function myStartupScript being run on server startup to check some new parameters, we would implement that function and put into our mymodule.lua file

server:registerRunAtStartup(myStartupScript)

Registration Methods

server:registerResponseHandler(callback)

Registrers a callback that gets called for every line a printer returns. Use this if you need to analyse printer responses. The callback needs to accept the paramater (printer,response).

server:registerEventHandler(event, f)

server:registerDynRequest(segment,f)

Sometimes the fast and convenient websocket communication is not what we need. If we for example want to upload a file, we need a dynamic request. This can be a post or get call. The format for this is /dyn/cmd with cmd equal the segment parameter used to register. The callback f gets the parameter (request,response)

server:registerLanguageDetector(f)

server:registerAction(action, f)

Actions are the main method of starting actions from the frontend. Actions get send over the websocket and take a json payload and get a json response back. Make sure your action name is unique, e.g. by prefixing your module name.

server:registerFrontendCSS( css)

Registers a css file to be included into the frontend. Example to load firmware.css in firmware module:

server:registerFrontendCSS("/mod/firmware/firmware.css")

server:registerFrontendJS(js)

Registers a js file to be included into the frontend. Example to load firmware.js in firmware module:

server:registerFrontendCSS("/mod/firmware/firmware.js")

server:registerFrontendModule(module)

We are using AngularJS 1.4.x which needs modules to be registered so they get called. So if you add any new modules needing configuration, you need to tell the server with this. Just send the module name to add and make sure that you have also registered the javascript file adding the module definition.