nep-cli 0.2.5 → 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 +241 -53
- package/nep-cli-0.2.6.tgz +0 -0
- package/package.json +6 -5
package/bin/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
1
|
+
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
const { program } = require('commander');
|
|
4
4
|
const { version } = require('../package.json');
|
|
@@ -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');
|
|
@@ -22,6 +23,39 @@ const PORT_MASTER_INFO = 50001; // Default port for master info
|
|
|
22
23
|
const PORT_SERVER = 50050;
|
|
23
24
|
|
|
24
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
|
+
}
|
|
25
59
|
|
|
26
60
|
program
|
|
27
61
|
.version(version)
|
|
@@ -33,37 +67,76 @@ program
|
|
|
33
67
|
.description('Display current Wi-Fi and Ethernet IP addresses of this computer')
|
|
34
68
|
.action(() => {
|
|
35
69
|
try {
|
|
36
|
-
// subsitude by interfaces = nep.getNetworkInterfaces --> {"wifi":wifiInterfaces, "eth":ethernetInterface}
|
|
37
70
|
const platform = os.platform();
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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))])];
|
|
52
104
|
}
|
|
53
105
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
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
|
+
});
|
|
57
114
|
});
|
|
58
115
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
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);
|
|
62
134
|
}
|
|
63
135
|
});
|
|
64
136
|
|
|
65
137
|
|
|
66
138
|
|
|
139
|
+
|
|
67
140
|
// Node saved here
|
|
68
141
|
var nodes_register = {};
|
|
69
142
|
// ----------- Main variables ---------------
|
|
@@ -784,52 +857,167 @@ program
|
|
|
784
857
|
openSub(master_ip, topic, msg_type, callback);
|
|
785
858
|
});
|
|
786
859
|
|
|
787
|
-
|
|
788
860
|
program
|
|
789
|
-
.command('
|
|
790
|
-
.description(
|
|
791
|
-
|
|
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;
|
|
792
876
|
|
|
793
|
-
|
|
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
|
+
}
|
|
794
881
|
|
|
795
|
-
|
|
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
|
+
}
|
|
796
892
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
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
|
+
}
|
|
801
901
|
|
|
802
|
-
|
|
902
|
+
if (opts.pretty) {
|
|
903
|
+
console.log('Parsed payload:');
|
|
904
|
+
console.log(JSON.stringify(payload, null, 2));
|
|
803
905
|
}
|
|
804
906
|
|
|
907
|
+
const node = new nep.Node('nep-cli-pubj');
|
|
908
|
+
const pub = node.new_pub(topic, 'json');
|
|
805
909
|
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
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);
|
|
809
919
|
}
|
|
920
|
+
});
|
|
810
921
|
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
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";
|
|
814
934
|
|
|
815
|
-
|
|
935
|
+
// 1) Fetch topics from master
|
|
936
|
+
const requester = createRequester(master_ip, PORT_MASTER_INFO);
|
|
937
|
+
const resultsRaw = await sendRequest(requester, { "input": "topics" });
|
|
816
938
|
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
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);
|
|
829
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);
|
|
830
982
|
}
|
|
831
|
-
|
|
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);
|
|
832
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
|
+
});
|
|
833
1021
|
|
|
834
1022
|
|
|
835
1023
|
const { Input } = require('enquirer');
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,20 +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
|
+
"json5": "^2.2.3",
|
|
15
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
|
}
|