@airmoney-degn/airmoney-cli 0.12.2 → 0.13.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/dist/cli/serve.js +17 -6
- package/dist/config.json +1 -1
- package/dist/util/cryptoProcess.js +123 -22
- package/dist/util/metadata.js +2 -2
- package/package.json +1 -1
package/dist/cli/serve.js
CHANGED
|
@@ -28,6 +28,17 @@ function getSimulatorDir() {
|
|
|
28
28
|
return path_1.default.join(base, 'public', 'simulator');
|
|
29
29
|
}
|
|
30
30
|
async function serveCommand(noBrowser, locationFolder, appUrl) {
|
|
31
|
+
// Check if simulator and API ports are already in use (crypto service handles its own port)
|
|
32
|
+
const requiredPorts = [4040, 4041, 5050];
|
|
33
|
+
const inUsePorts = await (0, cryptoProcess_1.checkPortsInUse)(requiredPorts);
|
|
34
|
+
if (inUsePorts.length > 0) {
|
|
35
|
+
console.error('\x1b[31m❌ Port conflict detected!\x1b[0m');
|
|
36
|
+
console.error(`\x1b[31mThe following ports are already in use: ${inUsePorts.join(', ')}\x1b[0m`);
|
|
37
|
+
console.error('\x1b[31m\nPlease kill the processes using these ports before running serve:\x1b[0m');
|
|
38
|
+
const killCommand = `lsof -ti:${inUsePorts.join(',')} | xargs kill -9`;
|
|
39
|
+
console.error(`\x1b[31m ${killCommand}\x1b[0m`);
|
|
40
|
+
process.exit(1);
|
|
41
|
+
}
|
|
31
42
|
const simulatorPort = 4041;
|
|
32
43
|
const simulatorExpress = (0, express_ws_1.default)((0, express_1.default)()).app;
|
|
33
44
|
simulatorExpress.use((0, cors_1.default)());
|
|
@@ -38,7 +49,7 @@ async function serveCommand(noBrowser, locationFolder, appUrl) {
|
|
|
38
49
|
ws.on('message', function (msg) {
|
|
39
50
|
console.log(msg);
|
|
40
51
|
});
|
|
41
|
-
console.log('socket', req.body);
|
|
52
|
+
// console.log('socket', req.body);
|
|
42
53
|
});
|
|
43
54
|
const simulatorDir = getSimulatorDir();
|
|
44
55
|
simulatorExpress.use('/simulator', express_1.default.static(simulatorDir));
|
|
@@ -49,7 +60,7 @@ async function serveCommand(noBrowser, locationFolder, appUrl) {
|
|
|
49
60
|
}
|
|
50
61
|
const metadata = (0, metadata_1.loadMetadata)();
|
|
51
62
|
if (!metadata) {
|
|
52
|
-
console.log('[
|
|
63
|
+
console.log('\x1b[33mNo metadata found. Skipping some possible checks.\x1b[0m');
|
|
53
64
|
}
|
|
54
65
|
if (appUrl != undefined) {
|
|
55
66
|
const proxyMiddleware = (0, http_proxy_middleware_1.createProxyMiddleware)({
|
|
@@ -65,14 +76,14 @@ async function serveCommand(noBrowser, locationFolder, appUrl) {
|
|
|
65
76
|
}
|
|
66
77
|
const simulatorServer = simulatorExpress.listen(simulatorPort, () => {
|
|
67
78
|
const url = `http://localhost:${simulatorPort}/simulator`;
|
|
68
|
-
console.log(
|
|
79
|
+
console.log(`\x1b[32mStarting simulator server at ${url}\x1b[0m`);
|
|
69
80
|
if (!noBrowser) {
|
|
70
81
|
(0, open_1.default)(url)
|
|
71
82
|
.then(() => {
|
|
72
83
|
// success opening URL
|
|
73
84
|
})
|
|
74
85
|
.catch(err => {
|
|
75
|
-
console.error('
|
|
86
|
+
console.error('\x1b[31mFailed to open web browser\x1b[0m', err);
|
|
76
87
|
});
|
|
77
88
|
}
|
|
78
89
|
});
|
|
@@ -99,7 +110,7 @@ async function serveCommand(noBrowser, locationFolder, appUrl) {
|
|
|
99
110
|
return;
|
|
100
111
|
}
|
|
101
112
|
else {
|
|
102
|
-
console.log('
|
|
113
|
+
console.log('\x1b[33mNo simulator client connected\x1b[0m');
|
|
103
114
|
res.status(503).json({ error: 'Simulator not connected' });
|
|
104
115
|
return;
|
|
105
116
|
}
|
|
@@ -116,7 +127,7 @@ async function serveCommand(noBrowser, locationFolder, appUrl) {
|
|
|
116
127
|
});
|
|
117
128
|
const airmoneyServiceServer = airmoneyServiceExpress.listen(airmoneyServicePort, () => {
|
|
118
129
|
const url = `http://localhost:${airmoneyServicePort}`;
|
|
119
|
-
console.log(
|
|
130
|
+
console.log(`\x1b[32mStarting airmoney service server at ${url}\x1b[0m`);
|
|
120
131
|
});
|
|
121
132
|
////////////////////////////////////////////////////////////////
|
|
122
133
|
(0, cryptoProcess_1.startCryptoServiceSimple)();
|
package/dist/config.json
CHANGED
|
@@ -3,6 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.isPortInUse = isPortInUse;
|
|
7
|
+
exports.checkPortsInUse = checkPortsInUse;
|
|
8
|
+
exports.isCryptoServiceRunning = isCryptoServiceRunning;
|
|
6
9
|
exports.startCryptoService = startCryptoService;
|
|
7
10
|
exports.getCryptoServicePath = getCryptoServicePath;
|
|
8
11
|
exports.startCryptoServiceSimple = startCryptoServiceSimple;
|
|
@@ -13,15 +16,83 @@ const path_1 = __importDefault(require("path"));
|
|
|
13
16
|
const child_process_1 = require("child_process");
|
|
14
17
|
const env_1 = require("./env");
|
|
15
18
|
const CryptoService_1 = require("../service/crypto/CryptoService");
|
|
19
|
+
// Utility functions for port management
|
|
20
|
+
function isPortInUse(port) {
|
|
21
|
+
return new Promise(resolve => {
|
|
22
|
+
const net = require('net');
|
|
23
|
+
const socket = new net.Socket();
|
|
24
|
+
socket.setTimeout(1000);
|
|
25
|
+
socket.on('connect', () => {
|
|
26
|
+
socket.destroy();
|
|
27
|
+
resolve(true); // Port is in use
|
|
28
|
+
});
|
|
29
|
+
socket.on('timeout', () => {
|
|
30
|
+
socket.destroy();
|
|
31
|
+
resolve(false); // Port is free
|
|
32
|
+
});
|
|
33
|
+
socket.on('error', () => {
|
|
34
|
+
resolve(false); // Port is free
|
|
35
|
+
});
|
|
36
|
+
socket.connect(port, 'localhost');
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
async function checkPortsInUse(ports) {
|
|
40
|
+
const inUsePorts = [];
|
|
41
|
+
for (const port of ports) {
|
|
42
|
+
if (await isPortInUse(port)) {
|
|
43
|
+
inUsePorts.push(port);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return inUsePorts;
|
|
47
|
+
}
|
|
48
|
+
async function isCryptoServiceRunning(port = 5050) {
|
|
49
|
+
try {
|
|
50
|
+
// Check if crypto service is running by making a simple HTTP request
|
|
51
|
+
const response = await fetch(`http://localhost:${port}/`, {
|
|
52
|
+
method: 'GET',
|
|
53
|
+
signal: AbortSignal.timeout(1000), // 1 second timeout
|
|
54
|
+
});
|
|
55
|
+
// Accept any response (200, 404, 405, etc.) as long as we get a response
|
|
56
|
+
// This means the crypto service is running
|
|
57
|
+
return true;
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
16
63
|
function startCryptoService() {
|
|
17
|
-
return new Promise((resolve, reject) => {
|
|
64
|
+
return new Promise(async (resolve, reject) => {
|
|
18
65
|
const bin = getCryptoServicePath();
|
|
19
66
|
if (!(0, fs_1.existsSync)(bin)) {
|
|
20
67
|
reject(new Error(`Crypto service binary not found: ${bin}`));
|
|
21
68
|
return;
|
|
22
69
|
}
|
|
70
|
+
// Check if port 5050 is already in use before starting the binary
|
|
71
|
+
const portInUse = await isPortInUse(5050);
|
|
72
|
+
if (portInUse) {
|
|
73
|
+
// Check if it's our crypto service
|
|
74
|
+
const isCryptoRunning = await isCryptoServiceRunning(5050);
|
|
75
|
+
if (isCryptoRunning) {
|
|
76
|
+
// console.log('Reusing existing crypto service on port 5050');
|
|
77
|
+
// Return a mock process that doesn't need to be killed
|
|
78
|
+
resolve({
|
|
79
|
+
process: null,
|
|
80
|
+
kill: () => {
|
|
81
|
+
// console.log('Crypto service is managed externally, not stopping');
|
|
82
|
+
},
|
|
83
|
+
});
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
reject(new Error('Port 5050 is already in use by another service that is not the crypto service.\n' +
|
|
88
|
+
'Please free up port 5050 or kill the conflicting process:\n' +
|
|
89
|
+
' lsof -ti:5050 | xargs kill -9'));
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
23
93
|
// console.log('Starting crypto service...');
|
|
24
94
|
let isKilled = false;
|
|
95
|
+
let hasResolved = false;
|
|
25
96
|
const cryptoProcess = (0, child_process_1.exec)(bin, {
|
|
26
97
|
env: {
|
|
27
98
|
...process.env,
|
|
@@ -30,29 +101,46 @@ function startCryptoService() {
|
|
|
30
101
|
},
|
|
31
102
|
}, (error, stdout, stderr) => {
|
|
32
103
|
// Ignore errors if the process was intentionally killed
|
|
33
|
-
if (error && !isKilled) {
|
|
34
|
-
console.error('Crypto service
|
|
35
|
-
|
|
104
|
+
if (error && !isKilled && !hasResolved) {
|
|
105
|
+
console.error('\x1b[31m❌ Crypto service failed to start:\x1b[0m');
|
|
106
|
+
console.error('\x1b[31mError details:\x1b[0m', error.message);
|
|
107
|
+
// Check for specific Rust panic errors
|
|
108
|
+
if (stderr &&
|
|
109
|
+
stderr.includes('Cannot drop a runtime in a context where blocking is not allowed')) {
|
|
110
|
+
console.error('\x1b[31m\n🔧 This appears to be a Rust/tokio runtime issue in the crypto service binary.\x1b[0m');
|
|
111
|
+
console.error('\x1b[31mPossible solutions:\x1b[0m');
|
|
112
|
+
console.error('\x1b[31m1. The binary may be corrupted - try rebuilding: npm run build\x1b[0m');
|
|
113
|
+
console.error('\x1b[31m2. There may be a compatibility issue with your system\x1b[0m');
|
|
114
|
+
console.error('\x1b[31m3. Try running the binary directly to see more details:\x1b[0m');
|
|
115
|
+
console.error(`\x1b[31m ${bin}\x1b[0m`);
|
|
116
|
+
}
|
|
117
|
+
else if (stderr) {
|
|
118
|
+
console.error('Stderr:', stderr);
|
|
119
|
+
}
|
|
120
|
+
reject(new Error(`Crypto service failed: ${error.message}`));
|
|
36
121
|
return;
|
|
37
122
|
}
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
if (stderr) {
|
|
42
|
-
console.error('
|
|
123
|
+
if (stdout) {
|
|
124
|
+
// console.log('Crypto service stdout:', stdout);
|
|
125
|
+
}
|
|
126
|
+
if (stderr && !isKilled) {
|
|
127
|
+
console.error('\x1b[31mCrypto service stderr:\x1b[0m', stderr);
|
|
43
128
|
}
|
|
44
129
|
});
|
|
45
130
|
// Wait 2 seconds before resolving to ensure service is ready
|
|
46
131
|
setTimeout(() => {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
132
|
+
if (!hasResolved) {
|
|
133
|
+
hasResolved = true;
|
|
134
|
+
resolve({
|
|
135
|
+
process: cryptoProcess,
|
|
136
|
+
kill: () => {
|
|
137
|
+
isKilled = true;
|
|
138
|
+
if (cryptoProcess && !cryptoProcess.killed) {
|
|
139
|
+
cryptoProcess.kill();
|
|
140
|
+
}
|
|
141
|
+
},
|
|
142
|
+
});
|
|
143
|
+
}
|
|
56
144
|
}, 2000);
|
|
57
145
|
});
|
|
58
146
|
}
|
|
@@ -65,10 +153,10 @@ function getCryptoServicePath() {
|
|
|
65
153
|
function startCryptoServiceSimple() {
|
|
66
154
|
const bin = getCryptoServicePath();
|
|
67
155
|
if (!(0, fs_1.existsSync)(bin)) {
|
|
68
|
-
console.log('
|
|
156
|
+
console.log('\x1b[31mcrypto service not found at ' + bin + '\x1b[0m');
|
|
69
157
|
return;
|
|
70
158
|
}
|
|
71
|
-
console.log('
|
|
159
|
+
console.log('\x1b[32mStarting crypto service at http://localhost:5050\x1b[0m');
|
|
72
160
|
(0, child_process_1.exec)(bin, { env: { SECURE_STORAGE: (0, env_1.configDir)(), RUST_BACKTRACE: '1' } }, (_, stdout, stderr) => {
|
|
73
161
|
// console.log("stdout", stdout);
|
|
74
162
|
// console.log("stderr", stderr);
|
|
@@ -88,8 +176,21 @@ async function withCryptoService(operation) {
|
|
|
88
176
|
let cryptoService = null;
|
|
89
177
|
let startedCryptoService = false;
|
|
90
178
|
try {
|
|
91
|
-
|
|
92
|
-
|
|
179
|
+
// Start crypto service (this will check ports and reuse if available)
|
|
180
|
+
try {
|
|
181
|
+
cryptoService = await startCryptoService();
|
|
182
|
+
startedCryptoService = true;
|
|
183
|
+
}
|
|
184
|
+
catch (error) {
|
|
185
|
+
console.error('\x1b[31m❌ Failed to start crypto service:\x1b[0m');
|
|
186
|
+
console.error('\x1b[31mThis might be due to:\x1b[0m');
|
|
187
|
+
console.error('\x1b[31m- Missing or corrupted binary files\x1b[0m');
|
|
188
|
+
console.error('\x1b[31m- Insufficient permissions\x1b[0m');
|
|
189
|
+
console.error('\x1b[31m- System compatibility issues\x1b[0m');
|
|
190
|
+
console.error('\x1b[31m- Port conflicts\x1b[0m');
|
|
191
|
+
console.error('\x1b[31m\nTry running: npm run build\x1b[0m');
|
|
192
|
+
throw error;
|
|
193
|
+
}
|
|
93
194
|
const cryptoServiceClient = new CryptoService_1.CryptoService();
|
|
94
195
|
// console.log('Crypto service client created');
|
|
95
196
|
return await operation(cryptoServiceClient);
|
package/dist/util/metadata.js
CHANGED
|
@@ -42,7 +42,7 @@ function loadMetadata(projectPath = '.') {
|
|
|
42
42
|
try {
|
|
43
43
|
const filePath = path.join(projectPath, 'metadata.json');
|
|
44
44
|
if (!fs.existsSync(filePath)) {
|
|
45
|
-
console.log('
|
|
45
|
+
console.log('\x1b[33mPlease run this command in Project directory\x1b[0m');
|
|
46
46
|
return null;
|
|
47
47
|
}
|
|
48
48
|
const raw = fs.readFileSync(filePath, 'utf8');
|
|
@@ -50,7 +50,7 @@ function loadMetadata(projectPath = '.') {
|
|
|
50
50
|
return data;
|
|
51
51
|
}
|
|
52
52
|
catch (err) {
|
|
53
|
-
console.log('
|
|
53
|
+
console.log('\x1b[33mPlease run this command in Project directory\x1b[0m');
|
|
54
54
|
return null;
|
|
55
55
|
}
|
|
56
56
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@airmoney-degn/airmoney-cli",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.13.0",
|
|
4
4
|
"description": "airmoney-cli is a command-line interface tool designed to facilitate the development and management of decentralized applications (DApps) for Airmoney.",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|