pmcf 4.19.2 → 4.21.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +93 -72
- package/package.json +19 -19
- package/src/base.mjs +34 -243
- package/src/cli.mjs +4 -4
- package/src/cluster.mjs +13 -11
- package/src/extra-source-service.mjs +7 -10
- package/src/host.mjs +44 -50
- package/src/initialization-context.mjs +324 -0
- package/src/location.mjs +4 -14
- package/src/module.mjs +1 -0
- package/src/network-interfaces/ethernet.mjs +3 -5
- package/src/network-interfaces/loopback.mjs +2 -4
- package/src/network-interfaces/network-interface.mjs +3 -5
- package/src/network-interfaces/skeleton.mjs +9 -3
- package/src/network-interfaces/tun.mjs +2 -4
- package/src/network-interfaces/wireguard.mjs +3 -5
- package/src/network-interfaces/wlan.mjs +4 -7
- package/src/network.mjs +10 -8
- package/src/owner.mjs +7 -31
- package/src/root.mjs +4 -73
- package/src/service-owner.mjs +20 -19
- package/src/service.mjs +13 -18
- package/src/services/alpm.mjs +4 -9
- package/src/services/bind.mjs +424 -388
- package/src/services/chrony.mjs +3 -5
- package/src/services/headscale.mjs +2 -4
- package/src/services/influxdb.mjs +2 -4
- package/src/services/kea.mjs +6 -10
- package/src/services/mosquitto.mjs +2 -4
- package/src/services/openldap.mjs +2 -4
- package/src/services/postfix.mjs +2 -4
- package/src/services/systemd-journal-remote.mjs +2 -4
- package/src/services/systemd-journal-upload.mjs +9 -10
- package/src/services/systemd-journald.mjs +2 -4
- package/src/services/systemd-resolved.mjs +42 -42
- package/src/services/systemd-timesyncd.mjs +9 -13
- package/src/services/tailscale.mjs +5 -2
- package/src/subnet.mjs +9 -5
- package/types/base.d.mts +0 -180
- package/types/cli.d.mts +0 -10
- package/types/cluster.d.mts +0 -507
- package/types/dns-utils.d.mts +0 -14
- package/types/endpoint.d.mts +0 -79
- package/types/extra-source-service.d.mts +0 -1033
- package/types/hooks.d.mts +0 -2
- package/types/host-utils.d.mts +0 -1
- package/types/host.d.mts +0 -285
- package/types/location.d.mts +0 -379
- package/types/module.d.mts +0 -36
- package/types/network-address.d.mts +0 -41
- package/types/network-interfaces/ethernet.d.mts +0 -1189
- package/types/network-interfaces/loopback.d.mts +0 -1140
- package/types/network-interfaces/network-interface.d.mts +0 -1158
- package/types/network-interfaces/skeleton.d.mts +0 -30
- package/types/network-interfaces/tun.d.mts +0 -1131
- package/types/network-interfaces/wireguard.d.mts +0 -1131
- package/types/network-interfaces/wlan.d.mts +0 -1734
- package/types/network-support.d.mts +0 -193
- package/types/network.d.mts +0 -702
- package/types/owner.d.mts +0 -235
- package/types/root.d.mts +0 -10
- package/types/service-owner.d.mts +0 -14
- package/types/service-types.d.mts +0 -246
- package/types/service.d.mts +0 -689
- package/types/services/alpm.d.mts +0 -805
- package/types/services/bind.d.mts +0 -1574
- package/types/services/chrony.d.mts +0 -1310
- package/types/services/headscale.d.mts +0 -801
- package/types/services/influxdb.d.mts +0 -812
- package/types/services/kea.d.mts +0 -945
- package/types/services/mosquitto.d.mts +0 -876
- package/types/services/openldap.d.mts +0 -793
- package/types/services/postfix.d.mts +0 -784
- package/types/services/systemd-journal-remote.d.mts +0 -1030
- package/types/services/systemd-journal-upload.d.mts +0 -932
- package/types/services/systemd-journald.d.mts +0 -1317
- package/types/services/systemd-resolved.d.mts +0 -1644
- package/types/services/systemd-timesyncd.d.mts +0 -1459
- package/types/services/tailscale.d.mts +0 -781
- package/types/subnet.d.mts +0 -57
- package/types/utils.d.mts +0 -37
package/src/cluster.mjs
CHANGED
|
@@ -14,6 +14,7 @@ import { writeLines } from "./utils.mjs";
|
|
|
14
14
|
|
|
15
15
|
const ClusterTypeDefinition = {
|
|
16
16
|
name: "cluster",
|
|
17
|
+
priority: 1.5,
|
|
17
18
|
owners: [Owner.typeDefinition, "network", "location", "root"],
|
|
18
19
|
extends: Host.typeDefinition,
|
|
19
20
|
key: "name",
|
|
@@ -39,18 +40,16 @@ const ClusterTypeDefinition = {
|
|
|
39
40
|
};
|
|
40
41
|
|
|
41
42
|
export class Cluster extends Host {
|
|
42
|
-
|
|
43
|
-
_backups = [];
|
|
44
|
-
routerId = 100;
|
|
45
|
-
checkInterval = 60;
|
|
43
|
+
static typeDefinition = ClusterTypeDefinition;
|
|
46
44
|
|
|
47
45
|
static {
|
|
48
46
|
addType(this);
|
|
49
47
|
}
|
|
50
48
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
_masters = [];
|
|
50
|
+
_backups = [];
|
|
51
|
+
routerId = 100;
|
|
52
|
+
checkInterval = 60;
|
|
54
53
|
|
|
55
54
|
set masters(value) {
|
|
56
55
|
this._masters.push(value);
|
|
@@ -166,7 +165,7 @@ export class Cluster extends Host {
|
|
|
166
165
|
cfg.push("}", "");
|
|
167
166
|
|
|
168
167
|
for (const endpoint of serviceEndpoints(cluster, {
|
|
169
|
-
services:
|
|
168
|
+
services: "services[types[http]]",
|
|
170
169
|
endpoints: e =>
|
|
171
170
|
e.networkInterface && e.networkInterface.kind !== "loopback"
|
|
172
171
|
})) {
|
|
@@ -177,10 +176,13 @@ export class Cluster extends Host {
|
|
|
177
176
|
cfg.push(` protocol ${endpoint.protocol.toUpperCase()}`);
|
|
178
177
|
|
|
179
178
|
for (const member of this.members) {
|
|
180
|
-
const memberService =
|
|
181
|
-
member.
|
|
182
|
-
|
|
179
|
+
const memberService = Array.from(
|
|
180
|
+
member.expression(
|
|
181
|
+
`aggregatedServices[types[${endpoint.type}]][0]`
|
|
182
|
+
)
|
|
183
|
+
);
|
|
183
184
|
|
|
185
|
+
console.log(member.fullName, endpoint.type, memberService);
|
|
184
186
|
cfg.push(` real_server ${member.address} ${memberService.port} {`);
|
|
185
187
|
cfg.push(` weight ${memberService.weight}`);
|
|
186
188
|
|
|
@@ -17,25 +17,22 @@ export const ExtraSourceServiceTypeDefinition = {
|
|
|
17
17
|
};
|
|
18
18
|
|
|
19
19
|
export class ExtraSourceService extends Service {
|
|
20
|
-
|
|
20
|
+
static typeDefinition = ExtraSourceServiceTypeDefinition;
|
|
21
21
|
|
|
22
22
|
static {
|
|
23
23
|
addType(this);
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
return ExtraSourceServiceTypeDefinition;
|
|
28
|
-
}
|
|
26
|
+
source = [];
|
|
29
27
|
|
|
30
28
|
get type() {
|
|
31
29
|
return ExtraSourceServiceTypeDefinition.name;
|
|
32
30
|
}
|
|
33
31
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
}
|
|
32
|
+
get services() {
|
|
33
|
+
return [
|
|
34
|
+
this.owner.owner.services,
|
|
35
|
+
...this.source.map(s => s.services)
|
|
36
|
+
].flat();
|
|
40
37
|
}
|
|
41
38
|
}
|
package/src/host.mjs
CHANGED
|
@@ -26,6 +26,7 @@ import { NetworkInterfaceTypeDefinition } from "./network-interfaces/network-int
|
|
|
26
26
|
|
|
27
27
|
const HostTypeDefinition = {
|
|
28
28
|
name: "host",
|
|
29
|
+
priority: 1.9,
|
|
29
30
|
owners: ["owner", "network", "root"],
|
|
30
31
|
extends: Base.typeDefinition,
|
|
31
32
|
key: "name",
|
|
@@ -76,7 +77,7 @@ const HostTypeDefinition = {
|
|
|
76
77
|
},
|
|
77
78
|
architecture: {
|
|
78
79
|
...string_attribute_writable,
|
|
79
|
-
values: ["x86", "x86_64", "aarch64", "armv7"]
|
|
80
|
+
values: ["x86", "x86_64", "aarch64", "armv7", "riscv"]
|
|
80
81
|
},
|
|
81
82
|
replaces: string_set_attribute_writable,
|
|
82
83
|
depends: string_set_attribute_writable,
|
|
@@ -88,6 +89,12 @@ const HostTypeDefinition = {
|
|
|
88
89
|
};
|
|
89
90
|
|
|
90
91
|
export class Host extends ServiceOwner {
|
|
92
|
+
static typeDefinition = HostTypeDefinition;
|
|
93
|
+
|
|
94
|
+
static {
|
|
95
|
+
addType(this);
|
|
96
|
+
}
|
|
97
|
+
|
|
91
98
|
_aliases = new Set();
|
|
92
99
|
_networkInterfaces = new Map();
|
|
93
100
|
_provides = new Set();
|
|
@@ -102,29 +109,19 @@ export class Host extends ServiceOwner {
|
|
|
102
109
|
_serial;
|
|
103
110
|
_keymap;
|
|
104
111
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
}
|
|
112
|
+
materializeExtends() {
|
|
113
|
+
super.materializeExtends();
|
|
108
114
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
read(data, type) {
|
|
114
|
-
super.read(data, type);
|
|
115
|
-
|
|
116
|
-
this.extra = data.extra;
|
|
117
|
-
}
|
|
115
|
+
for (const host of this.walkDirections(["extends"])) {
|
|
116
|
+
for (const [name, ni] of host.networkInterfaces) {
|
|
117
|
+
const present = this._networkInterfaces.get(name);
|
|
118
118
|
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
present.extends.push(ni);
|
|
126
|
-
} else {
|
|
127
|
-
this._networkInterfaces.set(name, ni.forOwner(this));
|
|
119
|
+
if (present) {
|
|
120
|
+
//console.log("LINK", present.fullName, ni.fullName,present.extends);
|
|
121
|
+
present.extends.add(ni);
|
|
122
|
+
} else {
|
|
123
|
+
this._networkInterfaces.set(name, ni.forOwner(this));
|
|
124
|
+
}
|
|
128
125
|
}
|
|
129
126
|
}
|
|
130
127
|
}
|
|
@@ -171,6 +168,13 @@ export class Host extends ServiceOwner {
|
|
|
171
168
|
return this.extendedAttribute("_vendor");
|
|
172
169
|
}
|
|
173
170
|
|
|
171
|
+
/**
|
|
172
|
+
* @return {string}
|
|
173
|
+
*/
|
|
174
|
+
get id() {
|
|
175
|
+
return this["machine-id"];
|
|
176
|
+
}
|
|
177
|
+
|
|
174
178
|
set keymap(value) {
|
|
175
179
|
this._keymap = value;
|
|
176
180
|
}
|
|
@@ -188,7 +192,9 @@ export class Host extends ServiceOwner {
|
|
|
188
192
|
}
|
|
189
193
|
|
|
190
194
|
get derivedPackaging() {
|
|
191
|
-
return this.
|
|
195
|
+
return this.expand(
|
|
196
|
+
this.collectFromDirections(["this", "extends"], "_packaging")
|
|
197
|
+
);
|
|
192
198
|
}
|
|
193
199
|
|
|
194
200
|
get isTemplate() {
|
|
@@ -200,7 +206,11 @@ export class Host extends ServiceOwner {
|
|
|
200
206
|
}
|
|
201
207
|
|
|
202
208
|
get model() {
|
|
203
|
-
|
|
209
|
+
for (const node of this.walkDirections(["this", "extends"])) {
|
|
210
|
+
if (node.isModel) {
|
|
211
|
+
return node;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
204
214
|
}
|
|
205
215
|
|
|
206
216
|
set aliases(value) {
|
|
@@ -208,7 +218,9 @@ export class Host extends ServiceOwner {
|
|
|
208
218
|
}
|
|
209
219
|
|
|
210
220
|
get aliases() {
|
|
211
|
-
return this.
|
|
221
|
+
return this.expand(
|
|
222
|
+
this.collectFromDirections(["this", "extends"], "_aliases")
|
|
223
|
+
);
|
|
212
224
|
}
|
|
213
225
|
|
|
214
226
|
set provides(value) {
|
|
@@ -217,7 +229,7 @@ export class Host extends ServiceOwner {
|
|
|
217
229
|
|
|
218
230
|
get provides() {
|
|
219
231
|
return this.expand(
|
|
220
|
-
this.
|
|
232
|
+
this.collectFromDirections(["this", "extends"], "_provides")
|
|
221
233
|
);
|
|
222
234
|
}
|
|
223
235
|
|
|
@@ -227,7 +239,7 @@ export class Host extends ServiceOwner {
|
|
|
227
239
|
|
|
228
240
|
get replaces() {
|
|
229
241
|
return this.expand(
|
|
230
|
-
this.
|
|
242
|
+
this.collectFromDirections(["this", "extends"], "_replaces")
|
|
231
243
|
);
|
|
232
244
|
}
|
|
233
245
|
|
|
@@ -237,7 +249,7 @@ export class Host extends ServiceOwner {
|
|
|
237
249
|
|
|
238
250
|
get depends() {
|
|
239
251
|
return this.expand(
|
|
240
|
-
this.
|
|
252
|
+
this.collectFromDirections(["this", "extends"], "_depends")
|
|
241
253
|
);
|
|
242
254
|
}
|
|
243
255
|
|
|
@@ -445,13 +457,13 @@ export class Host extends ServiceOwner {
|
|
|
445
457
|
await ni.systemdDefinitions(dir, packageData);
|
|
446
458
|
}
|
|
447
459
|
|
|
448
|
-
if (this.keymap) {
|
|
449
|
-
await writeLines(dir, "etc/vconsole.conf", `KEYMAP=${this.keymap}`);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
460
|
await generateKnownHosts(this.owner.hosts, join(dir, "root", ".ssh"));
|
|
453
461
|
|
|
462
|
+
console.log([...this.walkDirections(["extends"])].map(e => e.fullName));
|
|
463
|
+
|
|
454
464
|
for (const service of this.services) {
|
|
465
|
+
//console.log("SERVICE",service.name);
|
|
466
|
+
|
|
455
467
|
if (service.systemdConfigs) {
|
|
456
468
|
for (const { serviceName, configFileName, content } of asArray(
|
|
457
469
|
service.expand(service.systemdConfigs(this.name))
|
|
@@ -468,23 +480,5 @@ export class Host extends ServiceOwner {
|
|
|
468
480
|
}
|
|
469
481
|
|
|
470
482
|
yield packageData;
|
|
471
|
-
|
|
472
|
-
if (this.extra) {
|
|
473
|
-
yield {
|
|
474
|
-
sources: [
|
|
475
|
-
new FileContentProvider({
|
|
476
|
-
dir: join(this.directory, "extra"),
|
|
477
|
-
pattern: "**/*"
|
|
478
|
-
})
|
|
479
|
-
],
|
|
480
|
-
outputs: this.outputs,
|
|
481
|
-
properties: {
|
|
482
|
-
name: `${this.typeName}-extra-${this.owner.name}-${this.name}`,
|
|
483
|
-
description: `additional files for ${this.fullName}`,
|
|
484
|
-
access: "private",
|
|
485
|
-
dependencies: [packageData.properties.name]
|
|
486
|
-
}
|
|
487
|
-
};
|
|
488
|
-
}
|
|
489
483
|
}
|
|
490
484
|
}
|
|
@@ -0,0 +1,324 @@
|
|
|
1
|
+
import { readFile, glob } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { toInternal, attributeIterator, types, resolveTypeLinks } from "pacc";
|
|
4
|
+
import { asArray } from "./utils.mjs";
|
|
5
|
+
import { Base } from "./base.mjs";
|
|
6
|
+
import { Root } from "./root.mjs";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Keeps track of all in flight object creations and loose ends during config initialization.
|
|
10
|
+
*/
|
|
11
|
+
export class InitializationContext {
|
|
12
|
+
outstandingResolves = [];
|
|
13
|
+
|
|
14
|
+
constructor(directory = "/") {
|
|
15
|
+
resolveTypeLinks();
|
|
16
|
+
this.directory = directory;
|
|
17
|
+
this.root = new Root(directory);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
resolveOutstanding() {
|
|
21
|
+
for (let { object, attribute, name, value } of this.outstandingResolves) {
|
|
22
|
+
value = object.expand(value);
|
|
23
|
+
|
|
24
|
+
for (const type of attribute.type.members || [attribute.type]) {
|
|
25
|
+
const o =
|
|
26
|
+
object.typeNamed(type.name, value) ||
|
|
27
|
+
object.owner.typeNamed(type.name, value) ||
|
|
28
|
+
object.root.typeNamed(type.name, value); // TODO
|
|
29
|
+
|
|
30
|
+
if (o) {
|
|
31
|
+
this.assign(object, name, attribute, o);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/*
|
|
36
|
+
this.error(
|
|
37
|
+
`No such object "${value}" (${attribute.type.name}) for attribute ${name}`,
|
|
38
|
+
object.root.named(value)?.toString()
|
|
39
|
+
);*/
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
resolveLater(object, attribute, name, value) {
|
|
44
|
+
this.outstandingResolves.push({ object, attribute, name, value });
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
error(...args) {
|
|
48
|
+
console.error(...args);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
assign(object, name, attribute, value) {
|
|
52
|
+
value = toInternal(value, attribute);
|
|
53
|
+
value ??= attribute.default;
|
|
54
|
+
|
|
55
|
+
if (value !== undefined) {
|
|
56
|
+
if (attribute.values) {
|
|
57
|
+
if (attribute.values.indexOf(value) < 0) {
|
|
58
|
+
this.error(name, "unknown value", value, attribute.values);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
if (attribute.collection) {
|
|
63
|
+
const current = object[name];
|
|
64
|
+
|
|
65
|
+
switch (typeof current) {
|
|
66
|
+
case "undefined":
|
|
67
|
+
if (attribute.constructor === value.constructor) {
|
|
68
|
+
object[name] = value;
|
|
69
|
+
} else {
|
|
70
|
+
object[name] = asArray(value);
|
|
71
|
+
}
|
|
72
|
+
break;
|
|
73
|
+
case "object":
|
|
74
|
+
if (Array.isArray(current)) {
|
|
75
|
+
if (Array.isArray(value)) {
|
|
76
|
+
current.push(...value);
|
|
77
|
+
} else {
|
|
78
|
+
current.push(value);
|
|
79
|
+
}
|
|
80
|
+
} else {
|
|
81
|
+
if (current instanceof Set) {
|
|
82
|
+
if (value instanceof Set) {
|
|
83
|
+
object[name] = current.union(value);
|
|
84
|
+
} else {
|
|
85
|
+
object[name].add(value);
|
|
86
|
+
}
|
|
87
|
+
} else if (current instanceof Map) {
|
|
88
|
+
const keyName = attribute.type.key;
|
|
89
|
+
if (keyName) {
|
|
90
|
+
current.set(value[keyName], value);
|
|
91
|
+
} else {
|
|
92
|
+
// TODO
|
|
93
|
+
object[name] = value;
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
const keyName = attribute.type.key;
|
|
97
|
+
object[name][value[keyName]] = value;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
break;
|
|
101
|
+
case "function":
|
|
102
|
+
if (value instanceof Base) {
|
|
103
|
+
object.addObject(value);
|
|
104
|
+
} else {
|
|
105
|
+
this.error("Unknown collection type", name, current);
|
|
106
|
+
}
|
|
107
|
+
break;
|
|
108
|
+
}
|
|
109
|
+
} else {
|
|
110
|
+
object[name] = value;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
instantiateAndAssign(object, name, attribute, value) {
|
|
116
|
+
if (attribute.type.primitive) {
|
|
117
|
+
this.assign(object, name, attribute, value);
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
switch (typeof value) {
|
|
122
|
+
case "undefined":
|
|
123
|
+
return;
|
|
124
|
+
|
|
125
|
+
case "function":
|
|
126
|
+
this.error("Invalid value", name, value);
|
|
127
|
+
break;
|
|
128
|
+
|
|
129
|
+
case "boolean":
|
|
130
|
+
case "bigint":
|
|
131
|
+
case "number":
|
|
132
|
+
case "string":
|
|
133
|
+
{
|
|
134
|
+
let o;
|
|
135
|
+
|
|
136
|
+
for (const type of attribute.type.members || [attribute.type]) {
|
|
137
|
+
o = object.typeNamed(type.name, value);
|
|
138
|
+
if (o) {
|
|
139
|
+
break;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if (o) {
|
|
144
|
+
this.assign(object, name, attribute, o);
|
|
145
|
+
} else {
|
|
146
|
+
if (attribute.type.constructWithIdentifierOnly) {
|
|
147
|
+
o = new attribute.type.clazz(
|
|
148
|
+
object.ownerFor(attribute, value),
|
|
149
|
+
value
|
|
150
|
+
);
|
|
151
|
+
this.read(o, value);
|
|
152
|
+
object.addObject(o);
|
|
153
|
+
} else {
|
|
154
|
+
this.resolveLater(object, attribute, name, value);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
break;
|
|
160
|
+
|
|
161
|
+
case "object":
|
|
162
|
+
if (attribute.type.clazz && value instanceof attribute.type.clazz) {
|
|
163
|
+
this.assign(object, name, attribute, value);
|
|
164
|
+
} else {
|
|
165
|
+
this.assign(
|
|
166
|
+
object,
|
|
167
|
+
name,
|
|
168
|
+
attribute,
|
|
169
|
+
this.typeFactory(
|
|
170
|
+
attribute.type,
|
|
171
|
+
object.ownerFor(attribute, value),
|
|
172
|
+
value
|
|
173
|
+
)
|
|
174
|
+
);
|
|
175
|
+
}
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
typeFactory(type, owner, data) {
|
|
181
|
+
const factory = type.factoryFor?.(owner, data) || type.clazz;
|
|
182
|
+
const object = new factory(owner);
|
|
183
|
+
|
|
184
|
+
this.read(object, data);
|
|
185
|
+
owner.addObject(object);
|
|
186
|
+
return object;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
read(object, data, type = object.constructor.typeDefinition) {
|
|
190
|
+
if (data?.properties) {
|
|
191
|
+
Object.assign(object._properties, data.properties);
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
for (const [path, attribute] of attributeIterator(type.attributes)) {
|
|
195
|
+
if (attribute.writable) {
|
|
196
|
+
const name = path.join(".");
|
|
197
|
+
const value = object.expand(data[name]);
|
|
198
|
+
|
|
199
|
+
if (attribute.collection) {
|
|
200
|
+
if (typeof value === "object") {
|
|
201
|
+
if (Array.isArray(value)) {
|
|
202
|
+
for (const v of value) {
|
|
203
|
+
this.instantiateAndAssign(object, name, attribute, v);
|
|
204
|
+
}
|
|
205
|
+
} else {
|
|
206
|
+
if (value instanceof Base) {
|
|
207
|
+
this.assign(object, name, attribute, value);
|
|
208
|
+
} else {
|
|
209
|
+
for (const [objectName, objectData] of Object.entries(value)) {
|
|
210
|
+
if (typeof objectData === "object") {
|
|
211
|
+
//console.log("KEY", objectName, type.name, type.key);
|
|
212
|
+
objectData[attribute.type.key] = objectName;
|
|
213
|
+
}
|
|
214
|
+
this.instantiateAndAssign(
|
|
215
|
+
object,
|
|
216
|
+
name,
|
|
217
|
+
attribute,
|
|
218
|
+
objectData
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
this.instantiateAndAssign(object, name, attribute, value);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (object.name === undefined && data.name) {
|
|
231
|
+
// TODO
|
|
232
|
+
object.name = data.name;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
if (type.extends) {
|
|
236
|
+
//console.log("READ EXTENDS",data);
|
|
237
|
+
this.read(object, data, type.extends);
|
|
238
|
+
object.materializeExtends();
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
async loadType(name, type) {
|
|
243
|
+
const data = JSON.parse(
|
|
244
|
+
await readFile(
|
|
245
|
+
join(this.directory, name, type.clazz.typeFileName),
|
|
246
|
+
"utf8"
|
|
247
|
+
)
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
//console.log("LOAD", name);
|
|
251
|
+
let owner;
|
|
252
|
+
if (name[0] === "/") {
|
|
253
|
+
const parentName = name.replace(/\/[^\/]+$/, "");
|
|
254
|
+
owner = await this.load(parentName);
|
|
255
|
+
data.name = name.substring(owner.fullName.length + 1);
|
|
256
|
+
} else {
|
|
257
|
+
owner = this.root;
|
|
258
|
+
data.name = name;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
//console.log("LOAD", [name, owner.fullName, data.name]);
|
|
262
|
+
|
|
263
|
+
const object = this.typeFactory(type, owner, data);
|
|
264
|
+
this.root.addTypeObject(type.clazz.typeName, name, object);
|
|
265
|
+
|
|
266
|
+
/*if(object.name === undefined || object.name.length === 0) {
|
|
267
|
+
throw "NO name";
|
|
268
|
+
}*/
|
|
269
|
+
|
|
270
|
+
return object;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
async load(name, options) {
|
|
274
|
+
name = name.replace(/\/?([^\/]+\.json)?$/, "");
|
|
275
|
+
|
|
276
|
+
const object = this.root.named(name);
|
|
277
|
+
if (object) {
|
|
278
|
+
return object;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
if (options?.type) {
|
|
282
|
+
return this.loadType(name, options.type);
|
|
283
|
+
} else {
|
|
284
|
+
for (const type of Object.values(types).filter(
|
|
285
|
+
type => type?.clazz?.typeFileName
|
|
286
|
+
)) {
|
|
287
|
+
try {
|
|
288
|
+
return await this.loadType(name, type);
|
|
289
|
+
} catch {}
|
|
290
|
+
}
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const parentName = name.replace(/\/[^\/]$/, "");
|
|
294
|
+
return name === parentName ? this.root : this.load(parentName, options);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
async loadAll() {
|
|
298
|
+
for (const type of Object.values(types).sort(
|
|
299
|
+
(a, b) => b.priority - a.priority
|
|
300
|
+
)) {
|
|
301
|
+
//console.log("LIST","**/" + type.clazz.typeFileName);
|
|
302
|
+
if (type.clazz?.typeFileName) {
|
|
303
|
+
for await (const name of glob("**/" + type.clazz.typeFileName, {
|
|
304
|
+
cwd: this.directory
|
|
305
|
+
})) {
|
|
306
|
+
if (type === this.root.constructor) {
|
|
307
|
+
const data = JSON.parse(
|
|
308
|
+
await readFile(join(this.directory, name), "utf8")
|
|
309
|
+
);
|
|
310
|
+
this.root._properties = data.properties;
|
|
311
|
+
} else {
|
|
312
|
+
await this.load("/" + name, { type });
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
this.resolveOutstanding();
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
named(name) {
|
|
322
|
+
return this.root.named(name);
|
|
323
|
+
}
|
|
324
|
+
}
|
package/src/location.mjs
CHANGED
|
@@ -5,34 +5,24 @@ import { loadHooks } from "./hooks.mjs";
|
|
|
5
5
|
|
|
6
6
|
const LocationTypeDefinition = {
|
|
7
7
|
name: "location",
|
|
8
|
+
priority: 2,
|
|
8
9
|
owners: [Owner.typeDefinition, "location", "root"],
|
|
9
10
|
extends: Owner.typeDefinition,
|
|
10
11
|
key: "name",
|
|
11
|
-
attributes: {
|
|
12
|
-
}
|
|
12
|
+
attributes: {}
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
export class Location extends Owner {
|
|
16
|
+
static typeDefinition = LocationTypeDefinition;
|
|
17
|
+
|
|
16
18
|
static {
|
|
17
19
|
addType(this);
|
|
18
20
|
}
|
|
19
21
|
|
|
20
|
-
static get typeDefinition() {
|
|
21
|
-
return LocationTypeDefinition;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
22
|
get location() {
|
|
25
23
|
return this;
|
|
26
24
|
}
|
|
27
25
|
|
|
28
|
-
locationNamed(name) {
|
|
29
|
-
if (this.isNamed(name)) {
|
|
30
|
-
return this;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
return super.locationNamed(name);
|
|
34
|
-
}
|
|
35
|
-
|
|
36
26
|
get network() {
|
|
37
27
|
return [...this.typeList("network")][0] || super.network;
|
|
38
28
|
}
|
package/src/module.mjs
CHANGED
|
@@ -20,20 +20,18 @@ export const EthernetNetworkInterfaceTypeDefinition = {
|
|
|
20
20
|
};
|
|
21
21
|
|
|
22
22
|
export class EthernetNetworkInterface extends NetworkInterface {
|
|
23
|
-
|
|
23
|
+
static typeDefinition = EthernetNetworkInterfaceTypeDefinition;
|
|
24
24
|
|
|
25
25
|
static {
|
|
26
26
|
addType(this);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
static get typeDefinition() {
|
|
30
|
-
return EthernetNetworkInterfaceTypeDefinition;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
29
|
static isCommonName(name) {
|
|
34
30
|
return name.match(/^eth\d+$/);
|
|
35
31
|
}
|
|
36
32
|
|
|
33
|
+
arpbridge;
|
|
34
|
+
|
|
37
35
|
get kind() {
|
|
38
36
|
return EthernetNetworkInterfaceTypeDefinition.name;
|
|
39
37
|
}
|
|
@@ -19,14 +19,12 @@ const _localAddresses = new Map([
|
|
|
19
19
|
const _localDomains = new Set(["localhost"]);
|
|
20
20
|
|
|
21
21
|
export class LoopbackNetworkInterface extends SkeletonNetworkInterface {
|
|
22
|
+
static typeDefinition = LoopbackNetworkInterfaceTypeDefinition;
|
|
23
|
+
|
|
22
24
|
static {
|
|
23
25
|
addType(this);
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
static get typeDefinition() {
|
|
27
|
-
return LoopbackNetworkInterfaceTypeDefinition;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
28
|
static isCommonName(name) {
|
|
31
29
|
return name.match(/^lo\d*$/);
|
|
32
30
|
}
|