Skip to content

Commit

Permalink
Support @amrc-factoryplus/sparkplug-app. (#7)
Browse files Browse the repository at this point in the history
* Fetch device addresses from the Directory.
* Fetch full service records from the Directory.
* Provide a Command Escalation service interface.
  • Loading branch information
amrc-benmorrow authored Jul 11, 2023
2 parents 6eaaff1 + 72b8daa commit cda6fa3
Show file tree
Hide file tree
Showing 6 changed files with 223 additions and 122 deletions.
2 changes: 2 additions & 0 deletions lib/service-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { Debug } from "./debug.js";
import { Service } from "./uuids.js";

import Auth from "./service/auth.js";
import CmdEsc from "./service/cmdesc.js";
import ConfigDB from "./service/configdb.js";
import Directory from "./service/directory.js";
import Discovery from "./service/discovery.js";
Expand Down Expand Up @@ -73,6 +74,7 @@ export class ServiceClient {
* mostly be defined only on the service interface. */
ServiceClient.define_interfaces(
["Auth", Auth, `check_acl fetch_acl resolve_principal`],
["CmdEsc", CmdEsc, ``],
["ConfigDB", ConfigDB, `fetch_configdb:get_config`],
["Directory", Directory, ``],
["Discovery", Discovery,
Expand Down
38 changes: 38 additions & 0 deletions lib/service/cmdesc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Factory+ NodeJS Utilities
* Command Escalation service interface.
* Copyright 2023 AMRC.
*/

import { Address } from "../sparkplug/util.js";
import { Service } from "../uuids.js";

import { ServiceInterface } from "./service-interface.js";

export default class CmdEsc extends ServiceInterface {
constructor (fplus) {
super(fplus);
this.service = Service.Command_Escalation;
this.log = this.debug.log.bind(this.debug, "cmdesc");
}

async request_cmd ({ address, name, type, value }) {
const [st] = await this.fetch({
method: "POST",
url: `v1/address/${address}`,
body: { name, type, value },
});
if (st != 200)
this.throw(`Can't set metric ${name} of ${address}`, st);
}

async rebirth (address) {
const ctrl = address.isDevice() ? "Device Control" : "Node Control";
await this.request_cmd({
address: address,
name: `${ctrl}/Rebirth`,
type: "Boolean",
value: true,
});
}
}
37 changes: 34 additions & 3 deletions lib/service/directory.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
* Copyright 2023 AMRC.
*/

import { Address } from "../sparkplug/util.js";
import { Service, Null as Null_UUID } from "../uuids.js";

import { ServiceInterface } from "./service-interface.js";
Expand All @@ -14,17 +15,33 @@ export default class Directory extends ServiceInterface {
this.service = Service.Directory;
this.log = this.debug.log.bind(this.debug, "directory");
}
async get_service_urls (service) {

async get_service_info (service) {
const [st, specs] = await this.fetch(`/v1/service/${service}`);
if (st == 404) {
this.log("Can't find service %s: %s", service, st);
return;
}
if (st != 200)
this.throw(`Can't get service records for ${service}`, st);
if (!Array.isArray(specs))
this.throw(`Invalid service response for ${service}`);
if (specs.length > 1)
this.throw(`More than one service record for ${service}`);

return specs.map(s => s.url).filter(u => u != null);
return specs[0];
}

async get_service_url (service) {
const spec = await this.get_service_info(service);
return spec?.url;
}

/* XXX Endpoint for compatibility. This will only ever return a
* single result. */
async get_service_urls (service) {
const url = await this.get_service_url(service);
return url ? [url] : undefined;
}

async register_service_url (service, url) {
Expand All @@ -37,4 +54,18 @@ export default class Directory extends ServiceInterface {
this.throw(`Can't register service ${service}`, st);
this.log("Registered %s for %s", url, service);
}

async get_device_info (device) {
const [st, info] = await this.fetch(`v1/device/${device}`);
if (st == 404) return;
if (st != 200)
this.throw(`Can't find device ${device}`, st);
return info;
}

async get_device_address (device) {
const info = await this.get_device_info(device);
if (!info) return;
return new Address(info.group_id, info.node_id, info.device_id);
}
}
5 changes: 2 additions & 3 deletions lib/service/discovery.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ export default class Discovery extends ServiceInterface {
return this.fplus.Directory.get_service_urls(service);
}

/* This interface is deprecated. The concept of 'multiple providers
* for a service' was never properly implemented. */
async service_urls (service) {
this.debug.log("service", `[${service}] Looking for URL...`);
if (this.urls.has(service)) {
Expand All @@ -60,9 +62,6 @@ export default class Discovery extends ServiceInterface {
}
}

/* XXX This interface is deprecated. Services may have multiple
* URLs, and we cannot do liveness testing here as we don't know all
* the protocols. */
async service_url (service) {
const urls = await this.service_urls(service);
return urls?.[0];
Expand Down
Loading

0 comments on commit cda6fa3

Please sign in to comment.