nep-cli 0.2.4 → 0.2.6
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/bin/assets/vuetify/json/attributes.json +9157 -9157
- package/bin/assets/vuetify/json/tags.json +3062 -3062
- package/bin/assets/vuetify/json/web-types.json +27670 -27670
- package/bin/assets/vuetify/vuetify.css +24875 -24875
- package/bin/assets/vuetify/vuetify.js +41072 -41072
- package/bin/assets/vuetify/vuetify.min.css +7 -7
- package/bin/assets/vuetify/vuetify.min.js +5 -5
- package/bin/index.js +243 -54
- package/nep-cli-0.2.6.tgz +0 -0
- package/package.json +7 -7
package/bin/index.js
CHANGED
|
@@ -9,6 +9,7 @@ var nep_configuration = { current_port: 50200, IP: "0.0.0.0", brokers: {} }
|
|
|
9
9
|
const { exec } = require('child_process');
|
|
10
10
|
const { AutoComplete } = require('enquirer');
|
|
11
11
|
|
|
12
|
+
|
|
12
13
|
const open = require('open'); // Import the 'open' package
|
|
13
14
|
|
|
14
15
|
const express = require('express');
|
|
@@ -17,10 +18,44 @@ const socketIo = require('socket.io');
|
|
|
17
18
|
const fs = require ('fs');
|
|
18
19
|
const zmqc = require("zeromq/v5-compat");
|
|
19
20
|
|
|
21
|
+
|
|
20
22
|
const PORT_MASTER_INFO = 50001; // Default port for master info
|
|
21
23
|
const PORT_SERVER = 50050;
|
|
22
24
|
|
|
23
25
|
|
|
26
|
+
const JSON5 = require('json5');
|
|
27
|
+
|
|
28
|
+
// --- helpers local to this command (do NOT change selectTopic) ---
|
|
29
|
+
function normalizeResults(results) {
|
|
30
|
+
if (!Array.isArray(results?.input)) return results;
|
|
31
|
+
const normalized = results.input.map(item => {
|
|
32
|
+
if (typeof item === 'string') return item;
|
|
33
|
+
if (item && typeof item === 'object') {
|
|
34
|
+
// prefer common fields; last fallback prints the whole object as JSON
|
|
35
|
+
return item.topic || item.name || item.path || item.id || JSON.stringify(item);
|
|
36
|
+
}
|
|
37
|
+
return String(item);
|
|
38
|
+
});
|
|
39
|
+
return { ...results, input: normalized };
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function inferTypeFromSuffix(topic, allowed) {
|
|
43
|
+
const last = String(topic).split('/').pop().toLowerCase();
|
|
44
|
+
return allowed.includes(last) ? last : null; // infer only; do NOT strip from topic
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
function parseFlexibleJSON(src) { try { return JSON.parse(src); } catch { return JSON5.parse(src); } }
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
async function readAllFromStdin() {
|
|
51
|
+
return await new Promise((resolve, reject) => {
|
|
52
|
+
let data = '';
|
|
53
|
+
process.stdin.setEncoding('utf8');
|
|
54
|
+
process.stdin.on('data', chunk => data += chunk);
|
|
55
|
+
process.stdin.on('end', () => resolve(data.trim()));
|
|
56
|
+
process.stdin.on('error', reject);
|
|
57
|
+
});
|
|
58
|
+
}
|
|
24
59
|
|
|
25
60
|
program
|
|
26
61
|
.version(version)
|
|
@@ -32,37 +67,76 @@ program
|
|
|
32
67
|
.description('Display current Wi-Fi and Ethernet IP addresses of this computer')
|
|
33
68
|
.action(() => {
|
|
34
69
|
try {
|
|
35
|
-
// subsitude by interfaces = nep.getNetworkInterfaces --> {"wifi":wifiInterfaces, "eth":ethernetInterface}
|
|
36
70
|
const platform = os.platform();
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
71
|
+
const names = Object.keys(os.networkInterfaces());
|
|
72
|
+
|
|
73
|
+
// Name patterns (broad & locale-friendly)
|
|
74
|
+
const PATS = {
|
|
75
|
+
wifi: [
|
|
76
|
+
/wi-?fi/i, /wireless/i, /wlan/i,
|
|
77
|
+
/ワイヤレス/i, /無線/i
|
|
78
|
+
],
|
|
79
|
+
eth: [
|
|
80
|
+
/ethernet/i, /イーサネット/i, /有線/i, /lan/i,
|
|
81
|
+
/^eth\d+/i, /^enp\d+/i, /^eno\d+/i, /^en\d+$/i // Linux/mac
|
|
82
|
+
],
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
// Helper: get IPv4 addresses for a given interface name
|
|
86
|
+
const ipv4s = (ifname) =>
|
|
87
|
+
(os.networkInterfaces()[ifname] || [])
|
|
88
|
+
.filter(a => a.family === 'IPv4' && !a.internal)
|
|
89
|
+
.map(a => a.address);
|
|
90
|
+
|
|
91
|
+
// Matchers
|
|
92
|
+
const matchAny = (str, regexes) => regexes.some(r => r.test(str));
|
|
93
|
+
|
|
94
|
+
// Candidate sets
|
|
95
|
+
let wifiIfs = names.filter(n => matchAny(n, PATS.wifi));
|
|
96
|
+
let ethIfs = names.filter(n => matchAny(n, PATS.eth));
|
|
97
|
+
|
|
98
|
+
// Windows special: accept numbered “Ethernet 2 / イーサネット 2”
|
|
99
|
+
if (platform === 'win32') {
|
|
100
|
+
const winEthWide = /^(Ethernet|イーサネット)(\s*\d+)?$/i;
|
|
101
|
+
const winWiFiWide = /^(Wi-?Fi|Wireless|WLAN|ワイヤレス|無線)(\s*\d+)?$/i;
|
|
102
|
+
ethIfs = [...new Set([...ethIfs, ...names.filter(n => winEthWide.test(n))])];
|
|
103
|
+
wifiIfs = [...new Set([...wifiIfs, ...names.filter(n => winWiFiWide.test(n))])];
|
|
51
104
|
}
|
|
52
105
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
106
|
+
// Print Wi-Fi(s)
|
|
107
|
+
let printed = false;
|
|
108
|
+
wifiIfs.forEach(ifn => {
|
|
109
|
+
const addrs = ipv4s(ifn);
|
|
110
|
+
addrs.forEach(ip => {
|
|
111
|
+
printed = true;
|
|
112
|
+
nep.printIPAddress(`Wi-Fi (${ifn})`, ip);
|
|
113
|
+
});
|
|
56
114
|
});
|
|
57
115
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
116
|
+
// Print Ethernet(s)
|
|
117
|
+
ethIfs.forEach(ifn => {
|
|
118
|
+
const addrs = ipv4s(ifn);
|
|
119
|
+
addrs.forEach(ip => {
|
|
120
|
+
printed = true;
|
|
121
|
+
nep.printIPAddress(`Ethernet (${ifn})`, ip);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
// Fallback: if nothing matched, dump all non-internal IPv4s
|
|
126
|
+
if (!printed) {
|
|
127
|
+
names.forEach(ifn => {
|
|
128
|
+
const addrs = ipv4s(ifn);
|
|
129
|
+
addrs.forEach(ip => nep.printIPAddress(`${ifn}`, ip));
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
} catch (err) {
|
|
133
|
+
console.error('An error occurred:', err.message);
|
|
61
134
|
}
|
|
62
135
|
});
|
|
63
136
|
|
|
64
137
|
|
|
65
138
|
|
|
139
|
+
|
|
66
140
|
// Node saved here
|
|
67
141
|
var nodes_register = {};
|
|
68
142
|
// ----------- Main variables ---------------
|
|
@@ -578,7 +652,7 @@ program
|
|
|
578
652
|
.action(async (topic, index) => {
|
|
579
653
|
const ip = "127.0.0.1";
|
|
580
654
|
|
|
581
|
-
const allowedFormats = ["json", "msgpack", "bytes", "images", "dictionary"
|
|
655
|
+
const allowedFormats = ["json", "msgpack", "bytes", "images", "dictionary"];
|
|
582
656
|
const master_ip = "127.0.0.1";
|
|
583
657
|
|
|
584
658
|
const requester = createRequester(master_ip, PORT_MASTER_INFO);
|
|
@@ -599,7 +673,7 @@ program
|
|
|
599
673
|
open(`http://localhost:${port}/?port=${port}&topic=${encodeURIComponent(topicid)}`);
|
|
600
674
|
startShowServer(port, topic, ip);
|
|
601
675
|
}
|
|
602
|
-
else if (msg_type === "json" || msg_type === "dictionary") {
|
|
676
|
+
else if (msg_type === "json" || msg_type === "dictionary" || msg_type === "msgpack") {
|
|
603
677
|
open(`http://localhost:${port}/?port=${port}&topic=${encodeURIComponent(topicid)}`);
|
|
604
678
|
startJsonServer(port, topic, ip, msg_type);
|
|
605
679
|
}
|
|
@@ -783,52 +857,167 @@ program
|
|
|
783
857
|
openSub(master_ip, topic, msg_type, callback);
|
|
784
858
|
});
|
|
785
859
|
|
|
786
|
-
|
|
787
860
|
program
|
|
788
|
-
.command('
|
|
789
|
-
.description(
|
|
790
|
-
|
|
861
|
+
.command('pub <topic>')
|
|
862
|
+
.description(
|
|
863
|
+
'Publish JSON/JSON5 to a NEP+ topic.\n\n' +
|
|
864
|
+
'Input can come from --json, --file, or piped stdin.\n\n' +
|
|
865
|
+
'Examples:\n' +
|
|
866
|
+
' nep pub test/json --json "{value:1, txt:\'hello\'}"\n' +
|
|
867
|
+
' nep pub test/json --file payload.json5\n' +
|
|
868
|
+
' echo {value:1, txt:"hello"} | nep pub test/json\n'
|
|
869
|
+
)
|
|
870
|
+
.option('-j, --json <text>', 'JSON/JSON5 string (allows single quotes, unquoted keys)')
|
|
871
|
+
.option('-f, --file <path>', 'Read payload from a file')
|
|
872
|
+
.option('--pretty', 'Pretty-print parsed JSON before publishing')
|
|
873
|
+
.action(async (topic, opts) => {
|
|
874
|
+
try {
|
|
875
|
+
let text = null;
|
|
791
876
|
|
|
792
|
-
|
|
877
|
+
if (opts.json && opts.file) {
|
|
878
|
+
console.error('Please provide only one of --json or --file (or use stdin).');
|
|
879
|
+
process.exit(2);
|
|
880
|
+
}
|
|
793
881
|
|
|
794
|
-
|
|
882
|
+
if (opts.json) {
|
|
883
|
+
text = opts.json;
|
|
884
|
+
} else if (opts.file) {
|
|
885
|
+
text = fs.readFileSync(opts.file, 'utf8');
|
|
886
|
+
} else if (!process.stdin.isTTY) {
|
|
887
|
+
text = await readAllFromStdin(); // supports: echo {...} | nep pubj test
|
|
888
|
+
} else {
|
|
889
|
+
console.error('No input provided. Use --json, --file, or pipe data via stdin.');
|
|
890
|
+
process.exit(2);
|
|
891
|
+
}
|
|
795
892
|
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
893
|
+
let payload;
|
|
894
|
+
try {
|
|
895
|
+
payload = parseFlexibleJSON(text);
|
|
896
|
+
} catch (err) {
|
|
897
|
+
console.error('Failed to parse input as JSON/JSON5:');
|
|
898
|
+
console.error(err.message);
|
|
899
|
+
process.exit(2);
|
|
900
|
+
}
|
|
800
901
|
|
|
801
|
-
|
|
902
|
+
if (opts.pretty) {
|
|
903
|
+
console.log('Parsed payload:');
|
|
904
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
802
905
|
}
|
|
803
906
|
|
|
907
|
+
const node = new nep.Node('nep-cli-pubj');
|
|
908
|
+
const pub = node.new_pub(topic, 'json');
|
|
804
909
|
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
910
|
+
// give a moment for transport to connect
|
|
911
|
+
setTimeout(() => {
|
|
912
|
+
pub.publish(payload);
|
|
913
|
+
console.log('Message published to', topic);
|
|
914
|
+
process.exit(0);
|
|
915
|
+
}, 500);
|
|
916
|
+
} catch (e) {
|
|
917
|
+
console.error('Error:', e.message);
|
|
918
|
+
process.exit(1);
|
|
808
919
|
}
|
|
920
|
+
});
|
|
809
921
|
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
922
|
+
|
|
923
|
+
program
|
|
924
|
+
.command('publish [topic] [message...]')
|
|
925
|
+
.description(
|
|
926
|
+
'Publish to a registered NEP+ topic.\n\n' +
|
|
927
|
+
'Examples:\n' +
|
|
928
|
+
' nep publish # select topic & type, then enter payload\n' +
|
|
929
|
+
' nep publish test/json "{number:1, txt:\'hello\'}" # publishes TO topic "test/json"\n'
|
|
930
|
+
)
|
|
931
|
+
.action(async (topicArg, messageParts) => {
|
|
932
|
+
const allowedFormats = ["json", "msgpack", "bytes", "images", "dictionary", "string"];
|
|
933
|
+
const master_ip = "127.0.0.1";
|
|
813
934
|
|
|
814
|
-
|
|
935
|
+
// 1) Fetch topics from master
|
|
936
|
+
const requester = createRequester(master_ip, PORT_MASTER_INFO);
|
|
937
|
+
const resultsRaw = await sendRequest(requester, { "input": "topics" });
|
|
815
938
|
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
939
|
+
// 2) Normalize ONLY for this command (leave selectTopic untouched elsewhere)
|
|
940
|
+
const results = normalizeResults(resultsRaw);
|
|
941
|
+
console.log(results);
|
|
942
|
+
|
|
943
|
+
// 3) Let the user select a registered topic (reuses your existing selectTopic)
|
|
944
|
+
const selectedTopic = await selectTopic(results, topicArg);
|
|
945
|
+
|
|
946
|
+
|
|
947
|
+
|
|
948
|
+
// 5) Determine message type
|
|
949
|
+
let msg_type = inferTypeFromSuffix(selectedTopic, allowedFormats);
|
|
950
|
+
if (!msg_type) {
|
|
951
|
+
msg_type = await selectMsgType(allowedFormats, null, selectedTopic);
|
|
952
|
+
}
|
|
953
|
+
|
|
954
|
+
// 6) Acquire payload (CLI arg or prompt)
|
|
955
|
+
let messageText = Array.isArray(messageParts) ? messageParts.join(' ') : (messageParts || '');
|
|
956
|
+
if (!messageText || messageText.trim() === '') {
|
|
957
|
+
const prompt = new Input({
|
|
958
|
+
name: 'payload',
|
|
959
|
+
message:
|
|
960
|
+
msg_type === 'string' ? 'Enter STRING payload:'
|
|
961
|
+
: msg_type === 'bytes' ? 'Enter BYTES payload (base64-encoded):'
|
|
962
|
+
: `Enter ${msg_type.toUpperCase()} payload (JSON/JSON5 allowed):`
|
|
963
|
+
});
|
|
964
|
+
messageText = await prompt.run();
|
|
965
|
+
}
|
|
966
|
+
const src = messageText.trim();
|
|
967
|
+
|
|
968
|
+
// 7) Build payload by type
|
|
969
|
+
let payload;
|
|
970
|
+
try {
|
|
971
|
+
if (msg_type === 'string') {
|
|
972
|
+
payload = src;
|
|
973
|
+
} else if (msg_type === 'bytes') {
|
|
974
|
+
payload = Buffer.from(src, 'base64');
|
|
975
|
+
} else {
|
|
976
|
+
// json / dictionary / msgpack / images → parse as JSON/JSON5
|
|
977
|
+
payload = parseFlexibleJSON(src);
|
|
828
978
|
}
|
|
979
|
+
} catch (e) {
|
|
980
|
+
console.error('Failed to parse payload. Tip: use `nep pubj` for stdin/files.\n', e.message);
|
|
981
|
+
process.exit(2);
|
|
829
982
|
}
|
|
830
|
-
|
|
983
|
+
|
|
984
|
+
// 8) Publish to the EXACT selected topic (no stripping of suffix)
|
|
985
|
+
const node = new nep.Node('nep-cli-pub');
|
|
986
|
+
const conf = node.hybrid(master_ip);
|
|
987
|
+
const pub = node.new_pub(selectedTopic, msg_type, conf);
|
|
988
|
+
|
|
989
|
+
setTimeout(() => {
|
|
990
|
+
pub.publish(payload);
|
|
991
|
+
console.log(`Published to "${selectedTopic}" as ${msg_type}`);
|
|
992
|
+
process.exit(0);
|
|
993
|
+
}, 500);
|
|
831
994
|
});
|
|
995
|
+
|
|
996
|
+
program
|
|
997
|
+
.command('test [master_ip]')
|
|
998
|
+
.description('Publish "hello world" to the specified IP. If no IP is provided, the default is 127.0.0.1')
|
|
999
|
+
.action((master_ip = "127.0.0.1") => {
|
|
1000
|
+
|
|
1001
|
+
var openpub = function (master_ip) {
|
|
1002
|
+
|
|
1003
|
+
var pubFunction = function () {
|
|
1004
|
+
|
|
1005
|
+
var msg = { "message": "hello world" }
|
|
1006
|
+
console.log("Messgae published: " + JSON.stringify(msg) + " to " + master_ip)
|
|
1007
|
+
pub.publish(msg)
|
|
1008
|
+
|
|
1009
|
+
process.exit(1)
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
var node = new nep.Node("nep-cli-test")
|
|
1013
|
+
const conf = node.hybrid(master_ip);
|
|
1014
|
+
var pub = node.new_pub("test", "json", conf)
|
|
1015
|
+
setTimeout(pubFunction, 1000)
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
openpub(master_ip)
|
|
1019
|
+
|
|
1020
|
+
});
|
|
832
1021
|
|
|
833
1022
|
|
|
834
1023
|
const { Input } = require('enquirer');
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nep-cli",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.6",
|
|
4
4
|
"main": "./lib/nep.js",
|
|
5
5
|
"bin": {
|
|
6
|
-
"nep": "
|
|
6
|
+
"nep": "bin/index.js"
|
|
7
7
|
},
|
|
8
8
|
"keywords": [],
|
|
9
9
|
"author": "Enrique Coronado <enriquecoronadozu@gmail.com> (https://enriquecoronadozu.github.io/NEP/)",
|
|
10
10
|
"license": "ISC",
|
|
11
11
|
"dependencies": {
|
|
12
|
-
"commander": "^
|
|
12
|
+
"commander": "^14.0.3",
|
|
13
13
|
"enquirer": "^2.4.1",
|
|
14
14
|
"express": "^4.18.2",
|
|
15
|
-
"
|
|
15
|
+
"json5": "^2.2.3",
|
|
16
|
+
"nep-js": "^0.4.0",
|
|
16
17
|
"open": "7.4.2",
|
|
17
|
-
"socket.io": "
|
|
18
|
-
"zeromq": "6.
|
|
18
|
+
"socket.io": "4.8.3",
|
|
19
|
+
"zeromq": "6.5.0"
|
|
19
20
|
}
|
|
20
21
|
}
|
|
21
|
-
|