Appsđź”—
The VisionAppster Engine can be thought of as a platform-independent light-weight operating system that runs on top of a real operating system. In the operating system analogy, apps are platform-independent executables.
Apps are written in QML. The structure of the app is built using QML components while the application logic is written in JavaScript. QML makes it easy to create user interfaces to vision apps, but it is also used to build server apps that run in a displayless environment.
Usually, apps are created with the Builder and
run by the Engine service. To create an app that can be run by
va-run
or the Engine service you just need to export the app from
the Builder as a .vapkg
file.
It is also possible to create apps manually yourself. This document gives an overview of how apps can be built and run.
Main app componentđź”—
At a bare minimum, an app consists of a single qml file (e.g.
app.qml
) with the following contents:
import VisionAppster.Core 1.0
App
{
function start() {}
}
This declares a single QML component of type App
. The component must
contain a start
function, which will be invoked when the app is
started. Unlike the main
function in many programming languages, the
purpose of the start function is not to run until the program ends.
Instead, it is an event handler whose purpose is to prepare the app for
execution.
You can run this app with va-run
:
va-run app.qml
This assumes the “bin” directory under the VisionAppster installation
directory is in your PATH
. If you installed the Flatpak version to
the system scope on Linux, you may want to set up an alias first:
flatpak run --command=va-run com.visionappster.Builder app.qml
This will cause the Engine to start the app and remain listening to events from various sources, which you haven’t defined yet. To stop the Engine and hence the app, you need to press Ctrl+C or kill the process otherwise.
If the app component defines a function called stop
, it will be
called before the app exits. The stop function can return false
to
indicate that it cannot be stopped right now. It is however always
possible to kill an app that refuses to shut down cleanly. When shut
down, the Engine first tries to stop all running apps and then kills
them.
import VisionAppster.Core 1.0
App
{
function start() {}
function stop() {
console.log("Stopping");
}
}
To stop an app, call AppManager.stop(appInfo.pid)
. To abruptly stop
execution, one can call die()
in the app’s context. The function
takes an optional error message as a parameter.
Structure of an appđź”—
In addition to the main component, an app may contain any number of
other components, JavaScript files and resources such as images and text
files. You are free to arrange these in any directory structure as far
as the root directory contains an app description file called
appconfig.json
.
The app description file defines the entry point of the app and any
other meta-data that may be used by the app itself or other apps. For
example, the web management interface uses the appName
meta-data
entry as the user-visible name of an app. A minimal configuration file
could be like this:
{
"appName": "My Application",
"mainComponent": "app.qml",
"appId": "my.test.app/1"
}
At run time, the contents of the app configuration file are accessible
through a global object called appInfo
. The object contains not only
the contents of the configuration file but also information collected at
start-up:
uri : string
The full URI of the app, either an absolute path with a
file://
schema or a HTTP URI. This field will always be set.pid : integer
The process ID of the app.
args : array<string>
Start-up (e.g. command-line) arguments.
appId : string
The unique ID of the app. If this is not given in the configuration file, one will be automatically generated from the URI of the app.
The following code prints out the appName
and pid
of the app.
import VisionAppster.Core 1.0
App
{
function start() {
console.log(appInfo.appName); // from appconfig.json
console.log(appInfo.pid); // generated at start-up
}
}
On threadingđź”—
In the VisionAppster Engine, heavy processing such as image analysis is not done in the main thread. QML and JavaScript are however inherently single-threaded. Therefore, the JavaScript code defining application logic will always be run in a single thread. Furthermore, the design choice has been to execute the application logic JS code of all running apps in the main thread. This makes inter-app communication easier but has the drawback that a poorly behaving app may hang others. If an app runs into an eternal loop, the main thread will be blocked and no events will be delivered to any app.
It should be noted that JS code embedded in a processing graph can be run in parallel threads. This is possible because interactions between other components of the app are limited by the interface of the tool.