@effectstream/npm-midnight-indexer 0.3.99 → 0.100.8
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/binary.js +132 -17
- package/index.js +56 -30
- package/indexer-standalone/config.yaml +40 -20
- package/package.json +5 -3
- package/run_midnight_indexer.js +116 -22
package/binary.js
CHANGED
|
@@ -4,7 +4,8 @@ const axios = require("axios");
|
|
|
4
4
|
const extract = require("extract-zip");
|
|
5
5
|
const path = require("path");
|
|
6
6
|
|
|
7
|
-
const CURRENT_BINARY_VERSION = "
|
|
7
|
+
const CURRENT_BINARY_VERSION = "v4.0.0";
|
|
8
|
+
const FINAL_BINARY_NAME = "indexer-standalone";
|
|
8
9
|
|
|
9
10
|
/*
|
|
10
11
|
@returns {string} The platform and architecture of the current machine. Example: "linux-amd64"
|
|
@@ -39,9 +40,12 @@ function getBinaryUrl() {
|
|
|
39
40
|
if (!supportedPlatforms.includes(platform)) {
|
|
40
41
|
throw new Error(`Unsupported platform: ${platform}`);
|
|
41
42
|
}
|
|
42
|
-
|
|
43
|
+
|
|
44
|
+
return `https://github.com/effectstream/binaries/releases/download/0.3.120/indexer-standalone-${platform}-${CURRENT_BINARY_VERSION}.zip`;
|
|
43
45
|
}
|
|
44
46
|
|
|
47
|
+
const ZIP_FILE_PATH = path.join(__dirname, "indexer-standalone.zip");
|
|
48
|
+
|
|
45
49
|
/*
|
|
46
50
|
@returns {Promise<void>} Downloads and saves the binary for the current platform.
|
|
47
51
|
*/
|
|
@@ -50,9 +54,7 @@ async function downloadAndSaveBinary() {
|
|
|
50
54
|
try {
|
|
51
55
|
console.error(`Downloading... ${url}`);
|
|
52
56
|
const response = await axios.get(url, { responseType: "stream" });
|
|
53
|
-
const writer = fs.createWriteStream(
|
|
54
|
-
path.join(__dirname, "indexer-standalone.zip"),
|
|
55
|
-
);
|
|
57
|
+
const writer = fs.createWriteStream(ZIP_FILE_PATH);
|
|
56
58
|
|
|
57
59
|
response.data.pipe(writer);
|
|
58
60
|
|
|
@@ -74,21 +76,73 @@ async function unzipBinary() {
|
|
|
74
76
|
if (!fs.existsSync(dir)) {
|
|
75
77
|
fs.mkdirSync(dir, { recursive: true });
|
|
76
78
|
}
|
|
77
|
-
await extract(
|
|
78
|
-
|
|
79
|
+
await extract(ZIP_FILE_PATH, { dir });
|
|
80
|
+
const dataDir = path.join(dir, "data");
|
|
81
|
+
if (!fs.existsSync(dataDir)) {
|
|
82
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
83
|
+
}
|
|
79
84
|
|
|
80
85
|
const platform = getPlatform();
|
|
81
|
-
const
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
)
|
|
86
|
+
const possibleBinaryNames = [
|
|
87
|
+
`indexer-standalone-${platform}-${CURRENT_BINARY_VERSION}`,
|
|
88
|
+
`indexer-standalone`,
|
|
89
|
+
`indexer-standalone-${platform}`
|
|
90
|
+
];
|
|
91
|
+
|
|
92
|
+
let extractedBinaryPath = null;
|
|
93
|
+
for (const name of possibleBinaryNames) {
|
|
94
|
+
const p = path.join(dir, name);
|
|
95
|
+
if (fs.existsSync(p) && fs.statSync(p).isFile()) {
|
|
96
|
+
extractedBinaryPath = p;
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const finalBinaryPath = path.join(dir, FINAL_BINARY_NAME);
|
|
102
|
+
|
|
103
|
+
// Rename the extracted file to indexer-standalone
|
|
104
|
+
if (extractedBinaryPath) {
|
|
105
|
+
if (extractedBinaryPath !== finalBinaryPath) {
|
|
106
|
+
if (fs.existsSync(finalBinaryPath)) {
|
|
107
|
+
fs.unlinkSync(finalBinaryPath);
|
|
108
|
+
}
|
|
109
|
+
fs.renameSync(extractedBinaryPath, finalBinaryPath);
|
|
110
|
+
}
|
|
111
|
+
} else {
|
|
112
|
+
throw new Error(`Extracted binary not found in: ${dir}. Expected one of: ${possibleBinaryNames.join(", ")}`);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Clean up any other extracted files (e.g., readme.md)
|
|
116
|
+
const files = fs.readdirSync(dir);
|
|
117
|
+
for (const file of files) {
|
|
118
|
+
const filePath = path.join(dir, file);
|
|
119
|
+
// Explicitly protect config.yaml and other potential config files
|
|
120
|
+
const isConfigFile =
|
|
121
|
+
file === "config.yaml" ||
|
|
122
|
+
file === "config.yml" ||
|
|
123
|
+
file.endsWith(".yaml") ||
|
|
124
|
+
file.endsWith(".yml") ||
|
|
125
|
+
file.endsWith(".toml") ||
|
|
126
|
+
file.endsWith(".json");
|
|
127
|
+
|
|
128
|
+
if (
|
|
129
|
+
filePath !== finalBinaryPath &&
|
|
130
|
+
file !== "data" &&
|
|
131
|
+
!isConfigFile &&
|
|
132
|
+
fs.existsSync(filePath) &&
|
|
133
|
+
fs.statSync(filePath).isFile()
|
|
134
|
+
) {
|
|
135
|
+
console.log(`Cleaning up extracted file: ${file}`);
|
|
136
|
+
fs.unlinkSync(filePath);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (!fs.existsSync(finalBinaryPath)) {
|
|
141
|
+
throw new Error(`Expected binary not found: ${finalBinaryPath}`);
|
|
91
142
|
}
|
|
143
|
+
|
|
144
|
+
fs.chmodSync(finalBinaryPath, 0o755);
|
|
145
|
+
fs.unlinkSync(ZIP_FILE_PATH);
|
|
92
146
|
}
|
|
93
147
|
|
|
94
148
|
async function binary() {
|
|
@@ -96,7 +150,68 @@ async function binary() {
|
|
|
96
150
|
await unzipBinary();
|
|
97
151
|
}
|
|
98
152
|
|
|
153
|
+
async function cleanBinaries() {
|
|
154
|
+
const binaryDir = path.join(__dirname, "indexer-standalone");
|
|
155
|
+
const binaryPath = path.join(binaryDir, FINAL_BINARY_NAME);
|
|
156
|
+
const zipPath = path.join(__dirname, "indexer-standalone.zip");
|
|
157
|
+
|
|
158
|
+
let deletedFiles = [];
|
|
159
|
+
|
|
160
|
+
// Delete the binary executable if it exists
|
|
161
|
+
if (fs.existsSync(binaryPath)) {
|
|
162
|
+
try {
|
|
163
|
+
fs.unlinkSync(binaryPath);
|
|
164
|
+
deletedFiles.push(binaryPath);
|
|
165
|
+
} catch (error) {
|
|
166
|
+
console.error(`Error removing binary ${binaryPath}:`, error.message);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Delete the zip file if it exists
|
|
171
|
+
if (fs.existsSync(zipPath)) {
|
|
172
|
+
try {
|
|
173
|
+
fs.unlinkSync(zipPath);
|
|
174
|
+
deletedFiles.push(zipPath);
|
|
175
|
+
} catch (error) {
|
|
176
|
+
console.error(`Error removing file ${zipPath}:`, error.message);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Delete any other binary-related files from the directory, preserving config files
|
|
181
|
+
if (fs.existsSync(binaryDir)) {
|
|
182
|
+
const files = fs.readdirSync(binaryDir);
|
|
183
|
+
for (const file of files) {
|
|
184
|
+
const filePath = path.join(binaryDir, file);
|
|
185
|
+
const stat = fs.statSync(filePath);
|
|
186
|
+
|
|
187
|
+
// Preserve config files and readme
|
|
188
|
+
const isConfigFile =
|
|
189
|
+
file === "config.yaml" ||
|
|
190
|
+
file === "config.yml" ||
|
|
191
|
+
file.endsWith(".yaml") ||
|
|
192
|
+
file.endsWith(".yml") ||
|
|
193
|
+
file.endsWith(".toml") ||
|
|
194
|
+
file.endsWith(".json") ||
|
|
195
|
+
file.toLowerCase().startsWith("readme") ||
|
|
196
|
+
file.toLowerCase().startsWith("license") ||
|
|
197
|
+
file.toLowerCase().startsWith("changelog");
|
|
198
|
+
|
|
199
|
+
if (!isConfigFile && stat.isFile() && fs.existsSync(filePath)) {
|
|
200
|
+
try {
|
|
201
|
+
fs.unlinkSync(filePath);
|
|
202
|
+
deletedFiles.push(filePath);
|
|
203
|
+
} catch (error) {
|
|
204
|
+
console.error(`Error removing file ${filePath}:`, error.message);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
return deletedFiles;
|
|
211
|
+
}
|
|
212
|
+
|
|
99
213
|
module.exports = {
|
|
100
214
|
binary,
|
|
101
215
|
getPlatform,
|
|
216
|
+
cleanBinaries,
|
|
102
217
|
};
|
package/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const { binary, getPlatform } = require("./binary");
|
|
1
|
+
const { binary, getPlatform, cleanBinaries } = require("./binary");
|
|
2
2
|
const { runMidnightIndexer } = require("./run_midnight_indexer");
|
|
3
3
|
const { checkIfDockerExists, pullDockerImage, runDockerContainer } = require(
|
|
4
4
|
"./docker",
|
|
@@ -8,12 +8,11 @@ const path = require("path");
|
|
|
8
8
|
const readline = require("readline");
|
|
9
9
|
const os = require("os");
|
|
10
10
|
|
|
11
|
+
const FINAL_BINARY_NAME = "indexer-standalone";
|
|
12
|
+
|
|
11
13
|
function checkIfBinaryExists() {
|
|
12
|
-
const platform = getPlatform();
|
|
13
|
-
const parts = platform.split("-");
|
|
14
|
-
const binaryName = `indexer-standalone-${platform}`;
|
|
15
14
|
return fs.existsSync(
|
|
16
|
-
path.join(__dirname, "indexer-standalone",
|
|
15
|
+
path.join(__dirname, "indexer-standalone", FINAL_BINARY_NAME),
|
|
17
16
|
);
|
|
18
17
|
}
|
|
19
18
|
|
|
@@ -22,21 +21,9 @@ function checkIfBinaryExists() {
|
|
|
22
21
|
* @returns {boolean} True if binary execution is supported
|
|
23
22
|
*/
|
|
24
23
|
function isBinarySupported() {
|
|
25
|
-
const
|
|
26
|
-
const arch = os.arch();
|
|
27
|
-
|
|
28
|
-
// Check if the current platform-arch combination is supported
|
|
24
|
+
const platformString = getPlatform();
|
|
29
25
|
const supportedPlatforms = require("./package.json").supportedPlatforms;
|
|
30
26
|
|
|
31
|
-
let platformString;
|
|
32
|
-
if (platform === "darwin") {
|
|
33
|
-
platformString = arch === "x64" ? "macos-amd64" : `macos-${arch}`;
|
|
34
|
-
} else {
|
|
35
|
-
platformString = arch === "x64"
|
|
36
|
-
? `${platform}-amd64`
|
|
37
|
-
: `${platform}-${arch}`;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
27
|
return supportedPlatforms.includes(platformString);
|
|
41
28
|
}
|
|
42
29
|
|
|
@@ -69,9 +56,12 @@ function showUsage() {
|
|
|
69
56
|
Usage: node index.js [options] [args...]
|
|
70
57
|
|
|
71
58
|
Options:
|
|
72
|
-
--docker
|
|
73
|
-
--binary
|
|
74
|
-
--
|
|
59
|
+
--docker Force use of Docker container
|
|
60
|
+
--binary Force use of binary execution (supports Linux and macOS arm64)
|
|
61
|
+
--clean-binaries Delete downloaded binaries and download them again
|
|
62
|
+
--only-clean Only delete downloaded binaries without downloading them again
|
|
63
|
+
--clean Clean the SQLite database (existing flag)
|
|
64
|
+
--help Show this help message
|
|
75
65
|
|
|
76
66
|
Environment Variables:
|
|
77
67
|
APP__INFRA__SECRET Required: Secret key for the application
|
|
@@ -87,10 +77,12 @@ Environment Variables:
|
|
|
87
77
|
Note: macOS Intel users will automatically use Docker. macOS arm64 supports both binary and Docker execution.
|
|
88
78
|
|
|
89
79
|
Examples:
|
|
90
|
-
APP__INFRA__SECRET=mysecret node index.js --docker
|
|
91
|
-
APP__INFRA__SECRET=mysecret node index.js --binary
|
|
92
|
-
APP__INFRA__SECRET=mysecret node index.js
|
|
93
|
-
node index.js --
|
|
80
|
+
APP__INFRA__SECRET=mysecret node index.js --docker # Use Docker
|
|
81
|
+
APP__INFRA__SECRET=mysecret node index.js --binary # Use binary (if supported)
|
|
82
|
+
APP__INFRA__SECRET=mysecret node index.js --clean-binaries # Delete and redownload binaries
|
|
83
|
+
node index.js --only-clean # Only delete downloaded binaries
|
|
84
|
+
APP__INFRA__SECRET=mysecret node index.js --clean # Clean SQLite database
|
|
85
|
+
node index.js --help # Show this help
|
|
94
86
|
`);
|
|
95
87
|
}
|
|
96
88
|
|
|
@@ -103,6 +95,8 @@ function parseFlags(args) {
|
|
|
103
95
|
const flags = {
|
|
104
96
|
useDocker: false,
|
|
105
97
|
useBinary: false,
|
|
98
|
+
cleanBinaries: false,
|
|
99
|
+
onlyClean: false,
|
|
106
100
|
showHelp: false,
|
|
107
101
|
remainingArgs: [],
|
|
108
102
|
};
|
|
@@ -112,6 +106,10 @@ function parseFlags(args) {
|
|
|
112
106
|
flags.useDocker = true;
|
|
113
107
|
} else if (args[i] === "--binary") {
|
|
114
108
|
flags.useBinary = true;
|
|
109
|
+
} else if (args[i] === "--clean-binaries") {
|
|
110
|
+
flags.cleanBinaries = true;
|
|
111
|
+
} else if (args[i] === "--only-clean") {
|
|
112
|
+
flags.onlyClean = true;
|
|
115
113
|
} else if (args[i] === "--help" || args[i] === "-h") {
|
|
116
114
|
flags.showHelp = true;
|
|
117
115
|
} else {
|
|
@@ -166,7 +164,7 @@ function setBinaryDefaults(env) {
|
|
|
166
164
|
return binaryEnv;
|
|
167
165
|
}
|
|
168
166
|
|
|
169
|
-
async function runWithBinary(env, args) {
|
|
167
|
+
async function runWithBinary(env, args, forceClean = false) {
|
|
170
168
|
console.log("Using binary to run midnight indexer...");
|
|
171
169
|
|
|
172
170
|
// Check for required environment variable
|
|
@@ -176,8 +174,12 @@ async function runWithBinary(env, args) {
|
|
|
176
174
|
process.exit(1);
|
|
177
175
|
}
|
|
178
176
|
|
|
179
|
-
if (!checkIfBinaryExists()) {
|
|
180
|
-
|
|
177
|
+
if (forceClean || !checkIfBinaryExists()) {
|
|
178
|
+
if (forceClean) {
|
|
179
|
+
console.log("Cleaning downloaded binaries...");
|
|
180
|
+
await cleanBinaries();
|
|
181
|
+
}
|
|
182
|
+
console.log("Downloading binary...");
|
|
181
183
|
await binary();
|
|
182
184
|
}
|
|
183
185
|
|
|
@@ -197,6 +199,18 @@ async function main(args) {
|
|
|
197
199
|
process.exit(0);
|
|
198
200
|
}
|
|
199
201
|
|
|
202
|
+
// Handle --only-clean flag
|
|
203
|
+
if (flags.onlyClean) {
|
|
204
|
+
console.log("Cleaning downloaded binaries...");
|
|
205
|
+
const deletedFiles = await cleanBinaries();
|
|
206
|
+
if (deletedFiles.length > 0) {
|
|
207
|
+
console.log("Deleted:", deletedFiles.join(", "));
|
|
208
|
+
} else {
|
|
209
|
+
console.log("No downloaded binaries found to delete.");
|
|
210
|
+
}
|
|
211
|
+
process.exit(0);
|
|
212
|
+
}
|
|
213
|
+
|
|
200
214
|
// If both flags are provided, show error
|
|
201
215
|
if (flags.useDocker && flags.useBinary) {
|
|
202
216
|
console.error(
|
|
@@ -205,6 +219,14 @@ async function main(args) {
|
|
|
205
219
|
process.exit(1);
|
|
206
220
|
}
|
|
207
221
|
|
|
222
|
+
// Validate clean flag usage
|
|
223
|
+
if (flags.cleanBinaries && flags.useDocker) {
|
|
224
|
+
console.error(
|
|
225
|
+
"Error: --clean-binaries flag cannot be used with --docker flag",
|
|
226
|
+
);
|
|
227
|
+
process.exit(1);
|
|
228
|
+
}
|
|
229
|
+
|
|
208
230
|
// If --docker flag is explicitly provided
|
|
209
231
|
if (flags.useDocker) {
|
|
210
232
|
const dockerAvailable = await checkIfDockerExists();
|
|
@@ -242,7 +264,7 @@ async function main(args) {
|
|
|
242
264
|
);
|
|
243
265
|
process.exit(1);
|
|
244
266
|
}
|
|
245
|
-
return runWithBinary(env, flags.remainingArgs);
|
|
267
|
+
return runWithBinary(env, flags.remainingArgs, flags.cleanBinaries);
|
|
246
268
|
}
|
|
247
269
|
|
|
248
270
|
// No explicit flag provided - determine best execution method
|
|
@@ -298,7 +320,7 @@ async function main(args) {
|
|
|
298
320
|
}
|
|
299
321
|
|
|
300
322
|
// Default to binary execution (only on supported platforms)
|
|
301
|
-
return runWithBinary(env, flags.remainingArgs);
|
|
323
|
+
return runWithBinary(env, flags.remainingArgs, flags.clean);
|
|
302
324
|
}
|
|
303
325
|
|
|
304
326
|
// Handle unhandled promise rejections
|
|
@@ -313,4 +335,8 @@ process.on("SIGINT", () => {
|
|
|
313
335
|
process.exit(0);
|
|
314
336
|
});
|
|
315
337
|
|
|
338
|
+
module.exports = {
|
|
339
|
+
cleanBinaries,
|
|
340
|
+
};
|
|
341
|
+
|
|
316
342
|
main(process.argv.slice(2));
|
|
@@ -1,37 +1,57 @@
|
|
|
1
|
-
|
|
2
|
-
network_id: &network_id "Undeployed"
|
|
3
|
-
|
|
4
|
-
chain_indexer_application:
|
|
5
|
-
network_id: *network_id
|
|
6
|
-
blocks_buffer: 60
|
|
7
|
-
save_zswap_state_after: 1000
|
|
8
|
-
caught_up_max_distance: 60
|
|
9
|
-
caught_up_leeway: 30
|
|
1
|
+
thread_stack_size: "24MiB"
|
|
10
2
|
|
|
11
|
-
|
|
12
|
-
network_id:
|
|
13
|
-
|
|
3
|
+
application:
|
|
4
|
+
network_id: "undeployed"
|
|
5
|
+
blocks_buffer: 10
|
|
6
|
+
save_ledger_state_after: 1000
|
|
7
|
+
caught_up_max_distance: 10
|
|
8
|
+
caught_up_leeway: 5
|
|
9
|
+
active_wallets_query_delay: "500ms"
|
|
14
10
|
active_wallets_ttl: "30m"
|
|
15
|
-
transaction_batch_size:
|
|
16
|
-
#
|
|
17
|
-
#
|
|
11
|
+
transaction_batch_size: 50
|
|
12
|
+
# 1 by default
|
|
13
|
+
# concurrency_limit:
|
|
14
|
+
|
|
15
|
+
# CHECK: linux binary requires this flag in the root.
|
|
16
|
+
run_migrations: true
|
|
18
17
|
|
|
19
18
|
infra:
|
|
19
|
+
run_migrations: true
|
|
20
|
+
storage:
|
|
21
|
+
cnn_url: "data/indexer.sqlite"
|
|
22
|
+
|
|
23
|
+
ledger_db:
|
|
24
|
+
cache_size: "1kiB"
|
|
25
|
+
cnn_url: "data/ledger-db.sqlite"
|
|
26
|
+
|
|
20
27
|
node:
|
|
21
28
|
url: "ws://localhost:9944"
|
|
22
29
|
reconnect_max_delay: "10s" # 10ms, 100ms, 1s, 10s
|
|
23
30
|
reconnect_max_attempts: 30 # Roughly 5m
|
|
24
|
-
|
|
25
|
-
storage:
|
|
26
|
-
cnn_url: "./data/indexer.sqlite"
|
|
31
|
+
subscription_recovery_timeout: "30s" # Re-subscribe if no block received within this time
|
|
27
32
|
|
|
28
33
|
api:
|
|
29
|
-
address: "
|
|
34
|
+
address: "0.0.0.0"
|
|
30
35
|
port: 8088
|
|
31
36
|
request_body_limit: "1MiB"
|
|
32
37
|
max_complexity: 200
|
|
33
38
|
max_depth: 15
|
|
34
|
-
|
|
39
|
+
subscription:
|
|
40
|
+
blocks:
|
|
41
|
+
batch_size: 20
|
|
42
|
+
contract_actions:
|
|
43
|
+
batch_size: 20
|
|
44
|
+
dust_ledger_events:
|
|
45
|
+
batch_size: 20
|
|
46
|
+
shielded_transactions:
|
|
47
|
+
batch_size: 20
|
|
48
|
+
progress_update_interval: "30s"
|
|
49
|
+
keep_wallet_alive_interval: "1m"
|
|
50
|
+
unshielded_transactions:
|
|
51
|
+
batch_size: 20
|
|
52
|
+
progress_update_interval: "30s"
|
|
53
|
+
zswap_ledger_events:
|
|
54
|
+
batch_size: 20
|
|
35
55
|
|
|
36
56
|
telemetry:
|
|
37
57
|
tracing:
|
package/package.json
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effectstream/npm-midnight-indexer",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.100.8",
|
|
4
4
|
"description": "Downloads and runs the Midnight Indexer. It needs a running Midnight Node",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"scripts": {
|
|
7
|
-
"test": "echo \"Error: no test specified\" && exit 1"
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
8
|
+
"clean": "node index.js --clean-binaries",
|
|
9
|
+
"clean-only": "node index.js --only-clean"
|
|
8
10
|
},
|
|
9
11
|
"bin": {
|
|
10
12
|
"npm-midnight-indexer": "index.js"
|
|
@@ -22,4 +24,4 @@
|
|
|
22
24
|
"extract-zip": "^2.0.1",
|
|
23
25
|
"js-yaml": "^4.1.0"
|
|
24
26
|
}
|
|
25
|
-
}
|
|
27
|
+
}
|
package/run_midnight_indexer.js
CHANGED
|
@@ -2,7 +2,93 @@ const { spawn } = require("child_process");
|
|
|
2
2
|
const path = require("path");
|
|
3
3
|
const fs = require("fs");
|
|
4
4
|
const yaml = require("js-yaml");
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
const BINARY_NAME = "indexer-standalone";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Resolves the configuration file path
|
|
10
|
+
* @param {Object} env - Environment variables
|
|
11
|
+
* @param {string} workingDir - The working directory where the indexer runs
|
|
12
|
+
* @returns {string} The resolved configuration file path
|
|
13
|
+
*/
|
|
14
|
+
function resolveConfigPath(env, workingDir) {
|
|
15
|
+
if (env.CONFIG_FILE) {
|
|
16
|
+
return path.isAbsolute(env.CONFIG_FILE)
|
|
17
|
+
? env.CONFIG_FILE
|
|
18
|
+
: path.resolve(workingDir, env.CONFIG_FILE);
|
|
19
|
+
}
|
|
20
|
+
// Fall back to config.yaml in the current working directory
|
|
21
|
+
return path.join(workingDir, "config.yaml");
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Ensures that a configuration file exists at the given path
|
|
26
|
+
* @param {string} configPath - The path to the configuration file
|
|
27
|
+
* @param {Object} env - Environment variables
|
|
28
|
+
*/
|
|
29
|
+
function ensureConfigExists(configPath, env) {
|
|
30
|
+
if (fs.existsSync(configPath)) {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
console.log(
|
|
35
|
+
`Config file not found. Generating default config at: ${configPath}`,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
const networkId = env.LEDGER_NETWORK_ID || "Undeployed";
|
|
39
|
+
const nodeUrl = env.SUBSTRATE_NODE_WS_URL ||
|
|
40
|
+
env.APP__INFRA__NODE__URL ||
|
|
41
|
+
"ws://localhost:9944";
|
|
42
|
+
const cnnUrl = env.APP__INFRA__STORAGE__CNN_URL || "./data/indexer.sqlite";
|
|
43
|
+
const apiPort = env.APP__INFRA__API__PORT || 8088;
|
|
44
|
+
|
|
45
|
+
const defaultConfig = `
|
|
46
|
+
run_migrations: true
|
|
47
|
+
network_id: &network_id "${networkId}"
|
|
48
|
+
|
|
49
|
+
chain_indexer_application:
|
|
50
|
+
network_id: *network_id
|
|
51
|
+
blocks_buffer: 60
|
|
52
|
+
save_zswap_state_after: 1000
|
|
53
|
+
caught_up_max_distance: 60
|
|
54
|
+
caught_up_leeway: 30
|
|
55
|
+
|
|
56
|
+
wallet_indexer_application:
|
|
57
|
+
network_id: *network_id
|
|
58
|
+
active_wallets_repeat_delay: "100ms"
|
|
59
|
+
active_wallets_ttl: "30m"
|
|
60
|
+
transaction_batch_size: 10
|
|
61
|
+
|
|
62
|
+
infra:
|
|
63
|
+
node:
|
|
64
|
+
url: "${nodeUrl}"
|
|
65
|
+
reconnect_max_delay: "10s"
|
|
66
|
+
reconnect_max_attempts: 30
|
|
67
|
+
|
|
68
|
+
storage:
|
|
69
|
+
cnn_url: "${cnnUrl}"
|
|
70
|
+
|
|
71
|
+
api:
|
|
72
|
+
address: "0.0.0.0"
|
|
73
|
+
port: ${apiPort}
|
|
74
|
+
request_body_limit: "1MiB"
|
|
75
|
+
max_complexity: 200
|
|
76
|
+
max_depth: 15
|
|
77
|
+
network_id: *network_id
|
|
78
|
+
|
|
79
|
+
telemetry:
|
|
80
|
+
tracing:
|
|
81
|
+
enabled: false
|
|
82
|
+
service_name: "indexer"
|
|
83
|
+
metrics:
|
|
84
|
+
enabled: false
|
|
85
|
+
address: "0.0.0.0"
|
|
86
|
+
port: 9000
|
|
87
|
+
`;
|
|
88
|
+
|
|
89
|
+
fs.writeFileSync(configPath, defaultConfig.trim());
|
|
90
|
+
}
|
|
91
|
+
|
|
6
92
|
/**
|
|
7
93
|
* Resolves the SQLite database path using the midnight-indexer configuration rules
|
|
8
94
|
* @param {Object} env - Environment variables
|
|
@@ -17,17 +103,7 @@ function resolveSqlitePath(env, workingDir) {
|
|
|
17
103
|
return envCnnUrl;
|
|
18
104
|
}
|
|
19
105
|
|
|
20
|
-
|
|
21
|
-
let configPath;
|
|
22
|
-
if (env.CONFIG_FILE) {
|
|
23
|
-
configPath = path.isAbsolute(env.CONFIG_FILE)
|
|
24
|
-
? env.CONFIG_FILE
|
|
25
|
-
: path.resolve(workingDir, env.CONFIG_FILE);
|
|
26
|
-
} else {
|
|
27
|
-
// Fall back to config.yaml in the current working directory
|
|
28
|
-
configPath = path.join(workingDir, "config.yaml");
|
|
29
|
-
}
|
|
30
|
-
|
|
106
|
+
const configPath = resolveConfigPath(env, workingDir);
|
|
31
107
|
console.log(`Looking for config file at: ${configPath}`);
|
|
32
108
|
|
|
33
109
|
// Check if config file exists
|
|
@@ -64,6 +140,24 @@ function resolveSqlitePath(env, workingDir) {
|
|
|
64
140
|
}
|
|
65
141
|
}
|
|
66
142
|
|
|
143
|
+
/**
|
|
144
|
+
* Resolves the SQLite database path with a fallback to the default location
|
|
145
|
+
* @param {Object} env - Environment variables
|
|
146
|
+
* @param {string} workingDir - The working directory where the indexer runs
|
|
147
|
+
* @returns {string} The resolved SQLite database path
|
|
148
|
+
*/
|
|
149
|
+
function resolveSqlitePathWithFallback(env, workingDir) {
|
|
150
|
+
const sqlitePath = resolveSqlitePath(env, workingDir);
|
|
151
|
+
if (sqlitePath) {
|
|
152
|
+
return sqlitePath;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
// Fallback to default indexer location: data/indexer.sqlite
|
|
156
|
+
const defaultPath = path.join(workingDir, "data", "indexer.sqlite");
|
|
157
|
+
console.log(`Using default SQLite path: ${defaultPath}`);
|
|
158
|
+
return defaultPath;
|
|
159
|
+
}
|
|
160
|
+
|
|
67
161
|
/**
|
|
68
162
|
* Handles the --clean flag by deleting the SQLite database file
|
|
69
163
|
* @param {Object} env - Environment variables
|
|
@@ -72,12 +166,7 @@ function resolveSqlitePath(env, workingDir) {
|
|
|
72
166
|
function handleCleanFlag(env, workingDir) {
|
|
73
167
|
console.log("Processing --clean flag...");
|
|
74
168
|
|
|
75
|
-
const sqlitePath =
|
|
76
|
-
|
|
77
|
-
if (!sqlitePath) {
|
|
78
|
-
console.warn("Could not resolve SQLite database path. Skipping cleanup.");
|
|
79
|
-
return;
|
|
80
|
-
}
|
|
169
|
+
const sqlitePath = resolveSqlitePathWithFallback(env, workingDir);
|
|
81
170
|
|
|
82
171
|
// Handle sqlite:// URLs and extract the file path
|
|
83
172
|
let filePath = sqlitePath;
|
|
@@ -110,16 +199,16 @@ function handleCleanFlag(env, workingDir) {
|
|
|
110
199
|
* @returns {ChildProcess} The spawned child process
|
|
111
200
|
*/
|
|
112
201
|
function runMidnightIndexer(env = process.env, args = []) {
|
|
113
|
-
const platform = getPlatform();
|
|
114
|
-
const parts = platform.split("-");
|
|
115
|
-
const binaryName = `indexer-standalone-${platform}`;
|
|
116
202
|
const binaryPath = path.join(
|
|
117
203
|
__dirname,
|
|
118
204
|
"indexer-standalone",
|
|
119
|
-
|
|
205
|
+
BINARY_NAME,
|
|
120
206
|
);
|
|
121
207
|
const workingDir = path.join(__dirname, "indexer-standalone");
|
|
122
208
|
|
|
209
|
+
const configPath = resolveConfigPath(env, workingDir);
|
|
210
|
+
ensureConfigExists(configPath, env);
|
|
211
|
+
|
|
123
212
|
// Check for --clean flag and handle it
|
|
124
213
|
const cleanFlagIndex = args.indexOf("--clean");
|
|
125
214
|
if (cleanFlagIndex !== -1) {
|
|
@@ -130,6 +219,11 @@ function runMidnightIndexer(env = process.env, args = []) {
|
|
|
130
219
|
|
|
131
220
|
console.log(`Starting midnight-indexer binary at: ${binaryPath}`);
|
|
132
221
|
|
|
222
|
+
const dataDir = path.join(workingDir, "data");
|
|
223
|
+
if (!fs.existsSync(dataDir)) {
|
|
224
|
+
fs.mkdirSync(dataDir, { recursive: true });
|
|
225
|
+
}
|
|
226
|
+
|
|
133
227
|
const childProcess = spawn(binaryPath, args, {
|
|
134
228
|
env: env,
|
|
135
229
|
stdio: "inherit", // Inherit stdin, stdout, stderr from parent process
|