Skip to content

Parameters and context object

args parameter

This is the args parameter. It is an object with the arguments sent to the SSF from the calling side. For example, if the client side OnOpen attribute contains:

OnOpen
    const result = context.call('.mySSF', {name:"myName",value:"myValue"})
The resulting args parameter in SSF can be used like this:
ServerSide JS
    return {
        mySSF: async function(args, callInfo){
            const name = args.name;
            const value = args.value;
            console.log(name, value); // prints myName, myValue
        }
    }

callInfo parameter

The callInfo object contains helper functions, access to services, current context path and the users valid authToken, see table below.

key type Description
context Object Useful for talking with other services, internet, fetching data, get&set state, using the db and so on. The context object needs its own section and is found below
details Object The call details object, as described in the wamp protocol. Progressevents and callbacks for advanced server side functions is found here. See the docs for wamp protocol for more information.
token String The callers token. This can be used to check access control, or sent along to another service as callmeta payload.
path String The path for this function. This can be used to send to other services, to set the domain for the call.

The context object

The context object is tied to the server instance through its path. The path is the id used when the code was registered in [ssf].register call. The path is used to define accesscontrol for calls and to bind the function to a scope.

state.get

Gets a value from the state service for the path. It is a persistent value. The call returns the value or throws an exception.

Optional parameter key:

If provided, return the value for that key, instead of the whole object. The key parameter expects the file data to be JSON and to be of type Object with keys at root object level.

Optional parameter file:

If provided, that file is read/written instead of the default state object path.

async function getStates(kwargs, callInfo){
    let result
    const state = callInfo.context.state

    //read setting from the functions state
    result = await state.get()

    //read setting from a specified file
    result = await state.get({ file: "Shared:/globalsettings.json" })

    //read setting from a key
    result = await state.get({ key: "mySetting" })

    //read setting from  a key in a specified file
    result = await state.get({ key: "mySetting", file: "Shared:/globalsettings.json" })

    return result
}

return { getStates }

state.set

Sets data in the state service for the path. When set, the data is stored persistent. However, if set is called without file argument, the value is bound to the path. if the path is changed (any rename of file or parent files), the state will get lost.

key and file params exactly as for get.

Mandatory parameter data:

When provided, this data is written to target. If used in combination with key , the data is written as value for that key.

async function setStates(kwargs, callInfo){
    const state = callInfo.context.state;

    //set simple data to the state for this path
    await state.set({ data: 23 })

    //set complex data to the state for this path
    await state.set({data: { key1:"value1", key2:[1,2,3,4,5] } })

    //set complex data to the state for this path
    await state.set({data:['a','b','c']})

    //set complex data for a key
    await state.set({data: [1,2,3], key:"key2" })

    //set complex data for a key in a file
    await state.set({data:[1,2,3], key:"key2", file:"Shared:/globalsettings.json" })

    //erase data for a key
    await state.set({data: null, key:"key1" })

    //erase state for the entire state
    await state.set(null)

    //erase state for a file (removes the file as well)
    await state.set({ data:null, file:"Shared:/globalsettings.json" })

    return 0
}

db.query

Uses the attached projects database as default database. The database names is used.

Mandatory parameter sql:

The SQL query as a string. If null, undefined or empty, exception is thrown.

Warning

Do NOT concatenate SQL in where clauses for filtering or selecting data. Use Parameters to avoid risk for SQL injections. Always.

Optional parameter params:

If SQL query contains parameters, they are provided here.

Example

async function getAlarms(kwargs, callInfo){
    const db = callInfo.context.db.analogs;
    const top10rows = await db.query("select top 10 * from [Analog Register]")

    //use named params
    let sql = 'SELECT * FROM AnalogRegister WHERE Name LIKE @name1 OR LIKE @name2'
    let params = [{name1: 'GT31'}, {name2: 'SV21'}])
    const match1 = await db.query(sql, params)

    //or use multiple with same name     
    sql = 'SELECT * FROM AnalogRegister WHERE Name EQUALS @name'
    params = [{key:'name' value: 'GT31'}, {key:'name', value: 'SV21'}])
    const match2 = await db.query(sql, params)

    return match2
}
return { getAlarms }

fetch

Fetches a resource. The port to HTTP requests. Use this when you want to read or write any data from any web service. Any url is valid, as long as it can be fetched from the Arrigo Local server.

As the server side functions runs under node, the npm package https://github.com/node-fetch/node-fetch is used to provide very sophisticated data.

A nice feature here is that the Arrigo Local API can be fetched from the server side function and any data from the API can be returned as a value from the server side function.

async function getFromHttp(kwargs, callInfo){
    const fetch = callInfo.context.fetch;

    //fetch the resource
    const response = await fetch('http://localhost/api/login')
    const json = await response.json();

    return json
}

return { getFromHttp }

legacy

A portal to the legacy (existing EXOscada) domain. Use these functions while you are waiting for the proper datasource interface for advanced read/write to variables.

Warning

Be careful! This is raw read/write. No access control at all.Make sure that your client code (OnManeuver, OnChanged, OnOpen) does NOT send in the variables as strings. Define the variables in the serverside function. Make sure the variable values are within boundaries before write.

request/response Message type definition for variable quality.

const  Request = 0,
        Response = 1,
        Update = 2,
        ErrorNotExist = 3,
        ErrorUnreachable = 4,
        Pending = 5,
        Expired = 6,
        AboutToExpire = 7,
        UnknownError = 8;

legacy.read

call read. The function returns immediately with an response array containing variable responses. Check the type for each response. If this is the first time the variable is read, the value is still pending, and type for object is 5, according to the definition above. You have to manually enumerate and check if you need to read again, to make sure that every variable has its value before proceeding.

If you set upp an interval in the view, which periodically calls the function, the type will update and client side can be updated when variables is read. We strongly recommend that you use these functions with caution, as a last resort. Use expressions and OneShot bindings in OnOpen as long as you can. This is only for variables which you not know during compile time.

async function readFromController(args, callInfo){
    const read = callInfo.context.legacy.read;
    const variables = ["Controller_A1.QSystem.Sec"];
    const readResult = await read(variables);
    console.log(readResult);
    return readResult;
}

variables contains an array of read results. Each entry is the response for corresponding read variable in the array sent in.

[{
    "value": 40,
    "variable": "Controller_A1.QSystem.Sec",
    "type": 1,
    "timestamp": "2021-12-08T14:59:29.777131Z"
}]
legacy.write

Same as read. Only difference is that only one variable is possible to write at a time. The write method has same response object as above, but is not an array.

async function writeToController(args, callInfo){
    const write = callInfo.context.legacy.write;
    const variable = {variable: "Controller.DigOut(7)", value: 1};
    const writeResult = await write(variable);
    console.log(writeResult);
    return writeResult;
}
legacy.execute

This method can execute EXObasic snippets, or oneliners. This can be used for synchronizing controllers, block/unblock alarms e.t.c.

async function blockAlarm(args, callInfo){
    const execute = callInfo.context.legacy.execute;
    const executeResult = await execute("UnreachableAlarms.Controller_A1.Block");
    console.log(executeResult);
    return executeResult;
}