@acaprojects/ts-composer 中文文档教程

发布于 5年前 浏览 16 项目主页 更新于 3年前

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 对象

PropertyDescriptionOptionalTypeExample
hostHost name and port of the ACAEngine serverYesstring"dev.acaprojects.com:8080"
mockWhether to initialise composer with mock servicesYesbooleantrue
auth_uriURI for authorising users sessionNostring"/auth/oauth/authorize"
token_uriURI for generating new auth tokensNostring"/auth/token"
redirect_uriURI to redirect user to after authorising sessionNostring"/oauth-resp.html"
scopeScope of the user permissions needed by the applicationNostring"admin"
storageBrowser storage to use for storing user credentialsYes"local" | "session"
handle_loginWhether composer should handle user loginYesbooleantrue

一旦初始化,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, systemsuserszones

除了 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();

showquery 方法返回的对象是不可变的, 尽管在重新分配值时,它将保存在该对象的 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)
    }
]

查询参数也可用于回调输入。

GETPOSTPUTPATCHDELETE 请求可以被模拟出来。

如果发出请求但没有处理程序,它将尝试发出实时请求。

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

PropertyDescriptionOptionalTypeExample
hostHost name and port of the ACAEngine serverYesstring"dev.acaprojects.com:8080"
mockWhether to initialise composer with mock servicesYesbooleantrue
auth_uriURI for authorising users sessionNostring"/auth/oauth/authorize"
token_uriURI for generating new auth tokensNostring"/auth/token"
redirect_uriURI to redirect user to after authorising sessionNostring"/oauth-resp.html"
scopeScope of the user permissions needed by the applicationNostring"admin"
storageBrowser storage to use for storing user credentialsYes"local" | "session"
handle_loginWhether composer should handle user loginYesbooleantrue

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.

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文