@acaprojects/ts-composer 中文文档教程
TypeScript Composer Library
Composer 是 ACAEngine 的打字稿 API
Compilation
您可以在使用命令
npm run build
Usage
安装依赖项后从源代码构建库,可以找到 API 文档 here
您可以使用 npm 命令安装 Typescript composer
npm install --save-dev @acaprojects/ts-composer
安装包后,您可以导入 Composer
到您的应用程序
import { Composer } from '@acaprojects/ts-composer'
中 在使用 composer 之前,需要对其进行初始化。
Composer.init(config);
init 方法采用具有以下属性的 config
对象
Property | Description | Optional | Type | Example |
---|---|---|---|---|
host | Host name and port of the ACAEngine server | Yes | string | "dev.acaprojects.com:8080" |
mock | Whether to initialise composer with mock services | Yes | boolean | true |
auth_uri | URI for authorising users session | No | string | "/auth/oauth/authorize" |
token_uri | URI for generating new auth tokens | No | string | "/auth/token" |
redirect_uri | URI to redirect user to after authorising session | No | string | "/oauth-resp.html" |
scope | Scope of the user permissions needed by the application | No | string | "admin" |
storage | Browser storage to use for storing user credentials | Yes | "local" | "session" | |
handle_login | Whether composer should handle user login | Yes | boolean | true |
一旦初始化,Composer
对象将向 ACAEngine 的 websocket 和 http API 公开接口
Websocket API
Composer
公开 ACAEngine 的 websocket API 通过 bindings
服务。
bindings
服务用于提供与 ACAEngine 上运行的模块的实时交互。 它提供了一个接口来构建高效、响应迅速的用户界面、监控系统和其他需要实时、双向或异步交互的扩展。
composer 初始化后,您可以监听模块上的值
const my_mod = Composer.bindings.module('sys-death-star', 'TestModule', 3);
const my_variable = my_mod.binding('power');
const unbind = my_variable.bind();
const sub = my_variable.listen((value) => doSomething(value));
这将绑定到系统 sys-death-star
中第 3 个 TestModule
上的 power
状态变量>。 ACAEngine 上 power
值的任何更改都会发送到传递给 listen
的函数。
除了监听值的变化之外,您还可以远程执行模块上的方法。
const my_mod = Composer.bindings.module('sys-death-star', 'DemoModule', 2);
my_mod.exec('power_off').then(
(resp) => handleSuccess(resp)
(err) => handleError(err)
);
这将在系统 sys-death-star
中的第二个 DemoModule
上执行方法 power_off
。 如果该方法不存在或系统已关闭,它将返回错误。 来自 ACAEngine 的响应可以使用 exec
方法返回的承诺来处理。
HTTP API
对于 HTTP API,Composer
为 ACAEngine 的 RESTful API 上可用的每个根端点提供服务。
API 的文档可以在这里找到 https://docs.acaengine.com/api/control
为 drivers
, modules
, systems
、users
和 zones
除了 users
之外的每个服务都提供 CRUD 方法。 users
提供 _RUD。
// Drivers CRUD
Composer.drivers.add(driver_data).then((new_driver) => doSomething(new_driver));
Composer.drivers.show(driver_id).then((driver) => doSomething(driver));
Composer.drivers.update(driver_id, driver_data).then((updated_driver) => doSomething(updated_driver));
Composer.drivers.delete(driver_id).then(() => doSomething());
// Modules CRUD
Composer.modules.add(module_data).then((new_module) => doSomething(new_module));
Composer.modules.show(module_id).then((mod) => doSomething(mod));
Composer.modules.update(module_id, module_data).then((updated_module) => doSomething(updated_module));
Composer.modules.delete(module_id).then(() => doSomething());
// Systems CRUD
Composer.systems.add(system_data).then((new_system) => doSomething(new_system));
Composer.systems.show(system_id).then((system) => doSomething(system));
Composer.systems.update(system_id, system_data).then((updated_system) => doSomething(updated_system));
Composer.systems.delete(system_id).then(() => doSomething());
// Users CRUD
Composer.users.add(user_data).then((new_user) => doSomething(new_user)); // This will error
Composer.users.show(user_id).then((user) => doSomething(user));
Composer.users.update(user_id, user_data).then((updated_user) => doSomething(updated_user));
Composer.users.delete(user_id).then(() => doSomething());
// Zones CRUD
Composer.zones.add(zone_data).then((new_zone) => doSomething(new_zone));
Composer.zones.show(zone_id).then((zone) => doSomething(zone));
Composer.zones.update(zone_id, zone_data).then((updated_zone) => doSomething(updated_zone));
Composer.zones.delete(zone_id).then(() => doSomething());
该服务还为各种项目操作端点提供方法
// Driver Actions
Composer.drivers.reload(driver_id);
// Module Actions
Composer.module.start(module_id);
Composer.module.stop(module_id);
Composer.module.ping(module_id);
Composer.module.lookup(module_id, lookup);
Composer.module.internalState(module_id);
// System Actions
Composer.system.remove(system_id, module_name);
Composer.system.start(system_id);
Composer.system.stop(system_id);
Composer.system.execute(system_id, module_name, index, args);
Composer.system.state(system_id, module_name, index, lookup);
Composer.system.functionList(system_id, module_name, index);
Composer.system.types(system_id, module_name);
Composer.system.count(system_id);
// User Actions
Composer.users.current();
show
和 query
方法返回的对象是不可变的, 尽管在重新分配值时,它将保存在该对象的 changes
属性下。 可以使用 save
方法保存这些更改,该方法将返回对新对象的承诺。
Composer.zones.show(zone_id).then((zone) => {
console.log(zone.description); // Prints the current description
zone.description = 'New description';
console.log(zone.description); // Same a previous print
cosnole.log(zone.changes.description) // New description
zone.save().then((updated_zone) => {
cosnole.log(updated_zone.description) // New description
});
});
您可以在 API 文档上找到有关端点操作的更多详细信息
https://app.swaggerhub.com/apis/ACAprojects/ACAEngine/3.5.0#/
Writing mocks
如果您无权访问 ACAEngine 服务器,您也可以编写模拟,以便您仍然可以为 ACAEngine 开发接口。
要使用模拟服务,您可以将 mock: true
传递到初始化对象中。
Websockets
要为 realtime(websocket) API 编写模拟,您需要在初始化 composer 之前将您的系统添加到 window.control.systems
。
window.control.systems = {
"my-system": {
"MyModule": [
{
power: true,
$power_on: function () { this.power = true },
$power_off: function () { this.power = false }
}
]
}
}
请注意,模拟系统上的可执行方法使用 $
命名空间,因为引擎中的真实系统允许方法与变量同名。
一旦与系统的初始化交互以与实时系统相同的方式执行。
const my_mod = Composer.bindings.module('my-system', 'MyModule', 1);
const my_variable = my_mod.binding('power');
const unbind = my_variable.bind();
const sub = my_variable.listen((value) => doSomething(value)); // Emits true
my_mod.exec('power_off'); // The listen callback will now emit false
某些方法可能需要访问系统内的其他模块,为此,在运行时附加了一个名为 _system
的属性,它允许访问父系统
window.control.systems = {
"my-system": {
"MyModule": [
{
$lights_off: function () { this._system.MyOtherModule[0].lights = false; }
}
]
"MyOtherModule": [
{
lights: true,
}
]
}
}
HTTP Requests
HTTP API 请求可以以类似于实时的方式模拟API 通过将处理程序添加到 window.control.handlers
window.control.handlers = [
{
path: '/api/engine/v2/systems',
metadata: {},
method: 'GET',
callback: (request) => my_mock_systems
}
]
路径允许路由参数并将在回调输入中传递值。
window.control.handlers = [
{
path: '/api/engine/v2/systems/:system_id',
...
callback: (request) =>
my_mock_systems.find(sys => sys.id === request.route_params.system_id)
}
]
查询参数也可用于回调输入。
GET
、POST
、PUT
、PATCH
和 DELETE
请求可以被模拟出来。
如果发出请求但没有处理程序,它将尝试发出实时请求。
TypeScript Composer Library
Composer is a typescript API for ACAEngine
Compilation
You can build the library from source after installing the dependencies with the command
npm run build
Usage
API docs can be found here
You can install Typescript composer with the npm command
npm install --save-dev @acaprojects/ts-composer
After the package is installed you can import Composer
into your application
import { Composer } from '@acaprojects/ts-composer'
Before using composer it will need to be intialised.
Composer.init(config);
The init method takes a config
object with the following properties
Property | Description | Optional | Type | Example |
---|---|---|---|---|
host | Host name and port of the ACAEngine server | Yes | string | "dev.acaprojects.com:8080" |
mock | Whether to initialise composer with mock services | Yes | boolean | true |
auth_uri | URI for authorising users session | No | string | "/auth/oauth/authorize" |
token_uri | URI for generating new auth tokens | No | string | "/auth/token" |
redirect_uri | URI to redirect user to after authorising session | No | string | "/oauth-resp.html" |
scope | Scope of the user permissions needed by the application | No | string | "admin" |
storage | Browser storage to use for storing user credentials | Yes | "local" | "session" | |
handle_login | Whether composer should handle user login | Yes | boolean | true |
Once initialised the Composer
object will expose interfaces to ACAEngine's websocket and http APIs
Websocket API
Composer
exposes ACAEngine's websocket API through the bindings
service.
The bindings
service is used to provide real-time interaction with modules running on ACAEngine. It provides an interface to build efficient, responsive user interfaces, monitoring systems and other extensions which require live, two-way or asynchronous interaction.
Once composer has initialised you can listen to values on modules
const my_mod = Composer.bindings.module('sys-death-star', 'TestModule', 3);
const my_variable = my_mod.binding('power');
const unbind = my_variable.bind();
const sub = my_variable.listen((value) => doSomething(value));
This binds to the power
status variable on the 3rd TestModule
in the system sys-death-star
. Any changes to the value of power
on ACAEngine will then be emitted to the function passed to listen
.
Other than listening to changes of values you can also remotely execute methods on modules.
const my_mod = Composer.bindings.module('sys-death-star', 'DemoModule', 2);
my_mod.exec('power_off').then(
(resp) => handleSuccess(resp)
(err) => handleError(err)
);
This will execute the method power_off
on the 2nd DemoModule
in the system sys-death-star
. If the method doesn't exist or the system is turned off it will return an error. The response from ACAEngine can be handled using the promise returned by the exec
method.
HTTP API
For the HTTP API, Composer
provides a service for each of the root endpoints available on ACAEngine's RESTful API.
Docs for the API can be found here https://docs.acaengine.com/api/control
Services are provided for drivers
, modules
, systems
, users
, and zones
Each service except for users
provides CRUD methods. users
provides _RUD.
// Drivers CRUD
Composer.drivers.add(driver_data).then((new_driver) => doSomething(new_driver));
Composer.drivers.show(driver_id).then((driver) => doSomething(driver));
Composer.drivers.update(driver_id, driver_data).then((updated_driver) => doSomething(updated_driver));
Composer.drivers.delete(driver_id).then(() => doSomething());
// Modules CRUD
Composer.modules.add(module_data).then((new_module) => doSomething(new_module));
Composer.modules.show(module_id).then((mod) => doSomething(mod));
Composer.modules.update(module_id, module_data).then((updated_module) => doSomething(updated_module));
Composer.modules.delete(module_id).then(() => doSomething());
// Systems CRUD
Composer.systems.add(system_data).then((new_system) => doSomething(new_system));
Composer.systems.show(system_id).then((system) => doSomething(system));
Composer.systems.update(system_id, system_data).then((updated_system) => doSomething(updated_system));
Composer.systems.delete(system_id).then(() => doSomething());
// Users CRUD
Composer.users.add(user_data).then((new_user) => doSomething(new_user)); // This will error
Composer.users.show(user_id).then((user) => doSomething(user));
Composer.users.update(user_id, user_data).then((updated_user) => doSomething(updated_user));
Composer.users.delete(user_id).then(() => doSomething());
// Zones CRUD
Composer.zones.add(zone_data).then((new_zone) => doSomething(new_zone));
Composer.zones.show(zone_id).then((zone) => doSomething(zone));
Composer.zones.update(zone_id, zone_data).then((updated_zone) => doSomething(updated_zone));
Composer.zones.delete(zone_id).then(() => doSomething());
The services also provide methods for the various item action endpoints
// Driver Actions
Composer.drivers.reload(driver_id);
// Module Actions
Composer.module.start(module_id);
Composer.module.stop(module_id);
Composer.module.ping(module_id);
Composer.module.lookup(module_id, lookup);
Composer.module.internalState(module_id);
// System Actions
Composer.system.remove(system_id, module_name);
Composer.system.start(system_id);
Composer.system.stop(system_id);
Composer.system.execute(system_id, module_name, index, args);
Composer.system.state(system_id, module_name, index, lookup);
Composer.system.functionList(system_id, module_name, index);
Composer.system.types(system_id, module_name);
Composer.system.count(system_id);
// User Actions
Composer.users.current();
Objects returned by show
and query
methods are immutable, though when reassigning value it will be saved under the changes
property of that object. These changes can be saved using the save
method which will return a promise for the new object.
Composer.zones.show(zone_id).then((zone) => {
console.log(zone.description); // Prints the current description
zone.description = 'New description';
console.log(zone.description); // Same a previous print
cosnole.log(zone.changes.description) // New description
zone.save().then((updated_zone) => {
cosnole.log(updated_zone.description) // New description
});
});
You can find more details about endpoint action on the API docs
https://app.swaggerhub.com/apis/ACAprojects/ACAEngine/3.5.0#/
Writing mocks
If you don't have access to an ACAEngine server you can also write mocks so that you can still develop interfaces for ACAEngine.
To use the mock services you can pass mock: true
into the initialisation object.
Websockets
To write mocks for the the realtime(websocket) API you'll need to add your systems to window.control.systems
before initialising composer.
window.control.systems = {
"my-system": {
"MyModule": [
{
power: true,
$power_on: function () { this.power = true },
$power_off: function () { this.power = false }
}
]
}
}
Note that executable methods on mock systems are namespaced with $
as real systems in engine allow for methods to have the same name as variables.
Once initialised interactions with a system are performed in the same manner as the live system.
const my_mod = Composer.bindings.module('my-system', 'MyModule', 1);
const my_variable = my_mod.binding('power');
const unbind = my_variable.bind();
const sub = my_variable.listen((value) => doSomething(value)); // Emits true
my_mod.exec('power_off'); // The listen callback will now emit false
Some methods may need access to other modules within the system, for this a property is appended on runtime called _system
which allows for access to the parent system
window.control.systems = {
"my-system": {
"MyModule": [
{
$lights_off: function () { this._system.MyOtherModule[0].lights = false; }
}
]
"MyOtherModule": [
{
lights: true,
}
]
}
}
HTTP Requests
HTTP API Requests can be mocked in a similar way to the realtime API by adding handlers to window.control.handlers
window.control.handlers = [
{
path: '/api/engine/v2/systems',
metadata: {},
method: 'GET',
callback: (request) => my_mock_systems
}
]
Paths allow for route parameters and will pass the value in the callback input.
window.control.handlers = [
{
path: '/api/engine/v2/systems/:system_id',
...
callback: (request) =>
my_mock_systems.find(sys => sys.id === request.route_params.system_id)
}
]
Query parameters are also available on the callback input.
GET
, POST
, PUT
, PATCH
and DELETE
requests can be mocked out.
If a request is made and there are no handlers it will attempt to make the live request.