Libs
Overview
Libraries or libs are the fundamental unit of modularity in the Haxall architecture. All Haxall libs are proper Haystack libs packaged as Fantom pods.
Libs package one or more of the following features into a named, versioned module:
- Haystack defs for tags
- SkySpark defs for apps, views
- Fantom HxLib class to perform background processing
- Axon functions
Libs which only publish declarative data such as defs and functions are called resource libs. Resource libs cannot contain any Fantom code, but have the ability to be hot reloaded at runtime. Pods which contain one or more Fantom classes are called fantom libs. All Fantom libs must define a HxLib subclass.
Pod
All libs must be packaged into a Fantom pod. Pods are just a zip that contains a "meta.props" file for essential metadata. Any zip file can be made a Fantom pod by adding the following "meta.props" file:
pod.name=acmeFoo pod.version=1.0.9 pod.summary=Summary of pod pod.depends= pod.fcode=false
There are dozens of standardized fields used by "meta.props", but the ones above are the required fields.
Most of the time you will build your pod using Fantom's build system. Your source directory will be structured as follows:
acmeFoo/
build.fan
pod.fandoc
fan/
AcmeFooLib.fan
AcmeFooFuncs.fan
lib/
lib.trio
other-defs.trio
test/
AcmeFooLibTest.fan
Resource pods will only contain the "lib/" directory with the definitions.
It is recommended to use the stub tool to generate the source directory for a new library.
Build File
The build file is a Fantom script used to compile your source into a pod file. Here is a sample build file:
#! /usr/bin/env fan
using build
class Build : BuildPod
{
new make()
{
podName = "acmeFoo"
summary = "Foo is something awesome"
meta = ["org.name": "Acme",
"org.uri": "https://acme.com/",
"proj.name": "Cool Libs",
"proj.uri": "https://acme.com/cool-libs",
"license.name": "MIT",
"vcs.name": "Git",
"vcs.uri": "https://github.com/acme/cool-libs",
]
depends = ["sys 1.0",
"concurrent 1.0",
"haystack 3.1",
"axon 3.1",
"hx 3.1"
]
srcDirs = [`fan/`, `test/`]
resDirs = [`lib/`]
index = ["ph.lib": "acmeFoo"]
}
}
Resource libs should omit the depends and srcDirs fields.
Its important that all libs register the Haystack library name with the indexed prop "ph.lib". By convention a library named "acmeFoo" is packaged into a pod named "acmeFoo". Your library name should be globally unique - we recommend prefixing your library names with your company name.
Defs
All libs must define a "lib/lib.trio" file that registers the library as a Haystack 4 lib:
// lib.trio def: ^lib:acmeFoo depends: [^lib:ph, ^lib:axon, ^lib:hx] typeName:"acmeFoo::AcmeFooLib" doc: "Foo is something awesome"
Fantom libs must register the class qname using typeName; resource libs should omit this line.
You can package additional defs under the "lib/" directory using whatever naming convention you prefer. The special file "lib/skyarc.trio" is used to register SkySpark only defs - it is ignored in non-SkySpark runtimes.
HxLib
Libs which use Fantom must create a subclass of HxLib. An instance of this class is created by the runtime to receive lifecycle callbacks to perform background processing.
Here is a simple example:
using hx
const class AcmeFooLib : HxLib
{
override Void onStart() { log.info("$typeof started!") }
override Void onStop() { log.info("$typeof stopped!") }
}
Lifecycle
The lifecycle of a lib follows the overall runtime lifecycle:
- Instantiation (constructor)
HxLib.onStartHxLib.onReadyHxLib.onSteadyState(see Runtime)
The shutdown lib life cycle is:
In the instantiation phase, only basic information from the runtime is available. You must wait until onStart to access services and lookup other libs.
While your lib is running, you can schedule periodic house keeping. To use this feature override the HxLib.houseKeepingFreq which causes periodic callbacks to to HxLib.onHouseKeeping.
Axon Funcs
Axon functions may be bundled as a trio file under the "lib/" directory:
// funcs.trio def: ^func:acmeFooAxon src: () => "hello world in Axon!"
In Haxall, your function must use the def=^func:name syntax shown above. The name plus func marker tag pattern used by SkySpark is not supported.
Fantom Funcs
You can also implement your Axon functions in Fantom by creating a class named "<libName>Funcs". Axon functions are implemented as public, static methods annotated with the Axon facet:
using haystack
using axon
class AcmeFooFuncs
{
** Fandoc is used for reference docs
@Axon
static Str fooAcmeFantom()
{
"hello world in Fantom!"
}
}
It is critical to consider security when implementing functions in Fantom. Fantom funcs run outside of the Axon security sandbox, so its up your code to enforce any security constraints. Never create functions which would allow unconstrained access to the underlying OS.
Settings
Libs are enabled in a runtime database with a record via the ext tag. This record can store settings data that is accessible via the HxLib.rec method. You can create a statically typed class for your setting that is also used by UI tools:
Here is an example:
const class TaskLib : HxLib
{
** Settings record
override TaskSettings rec() { super.rec }
}
const class TaskSettings : TypedDict
{
** Constructor
new make(Dict d, |This| f) : super(d) { f(this) }
** Max threads for the task actor pool
@TypedTag { restart=true }
const Int maxThreads:= 50
}
The HxLib.onRecUpdate callback is invoked whenever the settings rec is modified.
Web
To add HTTP handling to your lib:
Here is a very simple example:
const class FooLib : HxLib
{
override const FooWeb web := FooWeb(this)
}
const class FooWeb : HxLibWeb
{
new make(FooLib lib) : super(lib) {}
override Void onGet()
{
res.headers["Content-Type"] = "text/plain; charset=utf-8"
res.out.printLine("Foo hello world: $req.modRel")
}
}
Libs plug into the URI namespace as follows:
- Haxall:
/{libName} - SkySpark:
/api/{projName}/ext/{libName}
Management
Libs can be enabled/disabled at runtime. The enabled libs are stored as records in the runtime database with the ext tag. You cannot directly add nor remove an ext record, but rather must instead use dedicated APIs.
Lib management in Fantom:
HxRuntime.libs: access toHxRuntimeLibsHxRuntimeLibs.list: list the enabled libsHxRuntimeLibs.get: lookup a lib by nameHxRuntimeLibs.add: enable an lib by nameHxRuntimeLibs.remove: disable an lib
Lib management in Axon:
libs(): list enabled libs in namespacelibAdd(): enable a lib by namelibRemove(): disable a lib by name
Note that adding/remove libs must be done in the correct order to ensure lib dependencies are met.
Stub
The hx stub tool will generate all the boiler plate code and structure for a new library. Run the following on the command line to see options:
hx help stub