mycomesh-consumer 0.1.31 → 0.1.32
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 +49 -111
- package/package.json +7 -5
- package/src/cli.mjs +1 -1
- package/src/consumer-runtime.mjs +1180 -0
- package/src/consumer.mjs +197 -118
- package/consumer.compose.yml +0 -90
- package/scripts/start-consumer.sh +0 -223
package/src/consumer.mjs
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
import { spawn as defaultSpawn } from "node:child_process";
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
|
-
import {
|
|
3
|
+
import { existsSync, readFileSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
import * as readline from "node:readline/promises";
|
|
4
6
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
import {
|
|
8
|
+
DEFAULT_BASE_URL,
|
|
9
|
+
DEFAULT_MAX_FEE_UNITS,
|
|
10
|
+
DEFAULT_RELAY_URL,
|
|
11
|
+
NativeConsumerState,
|
|
12
|
+
createConsumerServer,
|
|
13
|
+
} from "./consumer-runtime.mjs";
|
|
14
|
+
|
|
15
|
+
export const CONSUMER_RELEASE_VERSION = "0.1.32";
|
|
16
|
+
export const API_COMMANDS = new Set(["health", "models", "responses", "chat"]);
|
|
9
17
|
const API_VALUE_OPTIONS = new Set([
|
|
10
18
|
"--base-url",
|
|
11
19
|
"--api-key",
|
|
@@ -21,35 +29,32 @@ const API_VALUE_OPTIONS = new Set([
|
|
|
21
29
|
"--max-completion-tokens",
|
|
22
30
|
]);
|
|
23
31
|
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
Start the local MycoMesh Consumer. No options are needed.
|
|
32
|
+
export const CONSUMER_HELP = `Usage: mycomesh-consumer [options] [-- codex-options]
|
|
27
33
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
34
|
+
Start the local MycoMesh Consumer without Docker, Python, or a public Gateway.
|
|
35
|
+
The process owns one persisted V8 payment key, selects healthy Relays, and
|
|
36
|
+
exposes an OpenAI-compatible loopback API.
|
|
31
37
|
|
|
32
38
|
Options:
|
|
33
|
-
--no-browser Print the credentials URL without opening it
|
|
34
|
-
--no-codex
|
|
35
|
-
--stop Stop
|
|
36
|
-
--reset-local Confirm and delete the local Consumer
|
|
37
|
-
--codex-command PATH Codex executable (default: codex)
|
|
39
|
+
--no-browser Print the local credentials URL without opening it
|
|
40
|
+
--no-codex Keep only the Consumer API running
|
|
41
|
+
--stop Stop a previously started native Consumer
|
|
42
|
+
--reset-local Confirm and delete the local Consumer data directory
|
|
43
|
+
--codex-command PATH Codex executable (default: bundled Codex or codex)
|
|
38
44
|
--ready-timeout SEC Relay readiness timeout (default: 1800)
|
|
39
|
-
--
|
|
40
|
-
--
|
|
41
|
-
--
|
|
45
|
+
--data-dir DIR Payment key and history directory
|
|
46
|
+
--relay URLS Comma-separated Relay URLs for automatic failover
|
|
47
|
+
--proxy URL Optional outbound HTTP proxy
|
|
48
|
+
--host HOST Listen address (default: 127.0.0.1)
|
|
49
|
+
--port PORT Listen port (default: 8110)
|
|
50
|
+
--max-fee UNITS Maximum fee per request (default: 100000)
|
|
51
|
+
--dry-run Print the native startup plan
|
|
42
52
|
-h, --help Show this help
|
|
43
53
|
-v, --version Show the package version
|
|
44
54
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
mycomesh-consumer responses "hello"
|
|
49
|
-
mycomesh-consumer chat "hello"
|
|
50
|
-
|
|
51
|
-
Docker Desktop/Engine is required. The payment key and Consumer state remain
|
|
52
|
-
in a protected Docker volume; no wallet signature or browser session is used.`;
|
|
55
|
+
The browser page displays only the export URL/key, prepaid balance, key
|
|
56
|
+
operations, and local consumption history. No browser conversation state is
|
|
57
|
+
created.`;
|
|
53
58
|
|
|
54
59
|
class ConsumerCliError extends Error {
|
|
55
60
|
constructor(message, exitCode = 1) {
|
|
@@ -66,33 +71,76 @@ export async function main(argv, dependencies = {}) {
|
|
|
66
71
|
try {
|
|
67
72
|
const parsed = parseArguments(argv, env);
|
|
68
73
|
if (parsed.help) {
|
|
69
|
-
stdout.write(`${
|
|
74
|
+
stdout.write(`${CONSUMER_HELP}\n`);
|
|
70
75
|
return 0;
|
|
71
76
|
}
|
|
72
77
|
if (parsed.version) {
|
|
73
78
|
stdout.write(`${CONSUMER_RELEASE_VERSION}\n`);
|
|
74
79
|
return 0;
|
|
75
80
|
}
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
81
|
+
if (parsed.dryRun) {
|
|
82
|
+
stdout.write(`Native Consumer: ${parsed.host}:${parsed.port}\n`);
|
|
83
|
+
stdout.write(`Data directory: ${parsed.dataDir}\n`);
|
|
84
|
+
stdout.write(`Relays: ${parsed.relayUrls}\n`);
|
|
85
|
+
stdout.write("Docker: disabled\n");
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
88
|
+
if (parsed.stop) return stopConsumer(parsed, stdout, stderr);
|
|
89
|
+
if (parsed.resetLocal) return await resetConsumer(parsed, env, stdout, stderr);
|
|
90
|
+
|
|
91
|
+
const state = dependencies.createState
|
|
92
|
+
? dependencies.createState(parsed, env)
|
|
93
|
+
: new NativeConsumerState({
|
|
94
|
+
env: { ...env, MYCOMESH_CONSUMER_DATA_DIR: parsed.dataDir },
|
|
95
|
+
dataDir: parsed.dataDir,
|
|
96
|
+
relayUrls: parsed.relayUrls,
|
|
97
|
+
proxy: parsed.proxy,
|
|
98
|
+
baseUrl: parsed.baseUrl,
|
|
99
|
+
maxFeeUnits: parsed.maxFeeUnits,
|
|
100
|
+
});
|
|
101
|
+
const runtime = dependencies.createServer
|
|
102
|
+
? dependencies.createServer(state, parsed)
|
|
103
|
+
: createConsumerServer(state, { host: parsed.host, port: parsed.port });
|
|
104
|
+
await runtime.listen();
|
|
105
|
+
const rootUrl = `${parsed.scheme}://${parsed.hostForUrl}:${parsed.port}`;
|
|
106
|
+
const credentialsUrl = `${rootUrl}/`;
|
|
107
|
+
writePid(parsed.dataDir);
|
|
108
|
+
stdout.write(`MycoMesh Consumer credentials: ${credentialsUrl}\n`);
|
|
109
|
+
stdout.write(`OpenAI API: ${state.baseUrl}\n`);
|
|
110
|
+
if (!parsed.noBrowser) openBrowser(credentialsUrl, stderr);
|
|
111
|
+
|
|
112
|
+
const shutdown = async () => {
|
|
113
|
+
clearPid(parsed.dataDir);
|
|
114
|
+
await runtime.close();
|
|
115
|
+
};
|
|
116
|
+
if (parsed.noCodex) {
|
|
117
|
+
await waitForSignal(shutdown);
|
|
118
|
+
return 0;
|
|
119
|
+
}
|
|
120
|
+
await waitUntilReady(state, parsed.readyTimeout, stdout);
|
|
121
|
+
const code = await runCodex(parsed, state, dependencies.spawn ?? defaultSpawn, stdout, stderr);
|
|
122
|
+
await shutdown();
|
|
123
|
+
return code;
|
|
82
124
|
} catch (error) {
|
|
83
125
|
const exitCode = error instanceof ConsumerCliError ? error.exitCode : 1;
|
|
84
|
-
|
|
85
|
-
stderr.write(`mycomesh consumer: ${message}\n`);
|
|
126
|
+
stderr.write(`mycomesh consumer: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
86
127
|
return exitCode;
|
|
87
128
|
}
|
|
88
129
|
}
|
|
89
130
|
|
|
90
131
|
export function parseArguments(argv, env = process.env) {
|
|
91
132
|
const parsed = {
|
|
92
|
-
|
|
133
|
+
baseUrl: env.MYCOMESH_CONSUMER_PUBLIC_BASE_URL || DEFAULT_BASE_URL,
|
|
134
|
+
dataDir: env.MYCOMESH_CONSUMER_DATA_DIR || join(env.HOME || process.cwd(), ".mycomesh", "consumer"),
|
|
135
|
+
relayUrls: env.MYCOMESH_V8_RELAY_URLS || env.MYCOMESH_CONSUMER_RELAY_URL || DEFAULT_RELAY_URL,
|
|
136
|
+
proxy: env.MYCOMESH_CONSUMER_PROXY || "",
|
|
93
137
|
codexCommand: env.MYCOMESH_CODEX_COMMAND || bundledCodexCommand(),
|
|
94
|
-
readyTimeout: env.MYCOMESH_CONSUMER_READY_TIMEOUT_SECONDS ||
|
|
95
|
-
|
|
138
|
+
readyTimeout: parsePositive(env.MYCOMESH_CONSUMER_READY_TIMEOUT_SECONDS || "1800", "ready timeout", 86400),
|
|
139
|
+
maxFeeUnits: parsePositive(env.MYCOMESH_V8_MAX_FEE_UNITS || String(DEFAULT_MAX_FEE_UNITS), "max fee"),
|
|
140
|
+
host: env.MYCOMESH_CONSUMER_HOST || "127.0.0.1",
|
|
141
|
+
hostForUrl: env.MYCOMESH_CONSUMER_HOST || "127.0.0.1",
|
|
142
|
+
port: parsePositive(env.MYCOMESH_CONSUMER_PORT || "8110", "port", 65535),
|
|
143
|
+
scheme: "http",
|
|
96
144
|
noBrowser: false,
|
|
97
145
|
noCodex: false,
|
|
98
146
|
stop: false,
|
|
@@ -102,72 +150,46 @@ export function parseArguments(argv, env = process.env) {
|
|
|
102
150
|
version: false,
|
|
103
151
|
codexArgs: [],
|
|
104
152
|
};
|
|
105
|
-
|
|
106
153
|
for (let index = 0; index < argv.length; index += 1) {
|
|
107
154
|
const token = argv[index];
|
|
108
|
-
if (token === "--") {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
}
|
|
112
|
-
if (token === "-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
}
|
|
116
|
-
if (token === "-v" || token === "--version") {
|
|
117
|
-
parsed.version = true;
|
|
118
|
-
continue;
|
|
119
|
-
}
|
|
120
|
-
if (token === "--no-browser") {
|
|
121
|
-
parsed.noBrowser = true;
|
|
122
|
-
continue;
|
|
123
|
-
}
|
|
124
|
-
if (token === "--no-codex") {
|
|
125
|
-
parsed.noCodex = true;
|
|
126
|
-
continue;
|
|
127
|
-
}
|
|
128
|
-
if (token === "--stop") {
|
|
129
|
-
parsed.stop = true;
|
|
130
|
-
continue;
|
|
131
|
-
}
|
|
132
|
-
if (token === "--reset-local") {
|
|
133
|
-
parsed.resetLocal = true;
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
136
|
-
if (token === "--dry-run") {
|
|
137
|
-
parsed.dryRun = true;
|
|
138
|
-
continue;
|
|
139
|
-
}
|
|
155
|
+
if (token === "--") { parsed.codexArgs = argv.slice(index + 1); break; }
|
|
156
|
+
if (token === "-h" || token === "--help") { parsed.help = true; continue; }
|
|
157
|
+
if (token === "-v" || token === "--version") { parsed.version = true; continue; }
|
|
158
|
+
if (token === "--no-browser") { parsed.noBrowser = true; continue; }
|
|
159
|
+
if (token === "--no-codex") { parsed.noCodex = true; continue; }
|
|
160
|
+
if (token === "--stop") { parsed.stop = true; continue; }
|
|
161
|
+
if (token === "--reset-local") { parsed.resetLocal = true; continue; }
|
|
162
|
+
if (token === "--dry-run") { parsed.dryRun = true; continue; }
|
|
140
163
|
const separator = token.indexOf("=");
|
|
141
164
|
const name = separator === -1 ? token : token.slice(0, separator);
|
|
142
165
|
let value = separator === -1 ? undefined : token.slice(separator + 1);
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
if (value === undefined) {
|
|
147
|
-
index += 1;
|
|
148
|
-
value = argv[index];
|
|
149
|
-
}
|
|
166
|
+
const options = new Set(["--base-url", "--data-dir", "--relay", "--proxy", "--codex-command", "--ready-timeout", "--host", "--port", "--max-fee"]);
|
|
167
|
+
if (!options.has(name)) throw new ConsumerCliError(`unknown option: ${token}`, 2);
|
|
168
|
+
if (value === undefined) { index += 1; value = argv[index]; }
|
|
150
169
|
if (!value) throw new ConsumerCliError(`${name} requires a value`, 2);
|
|
151
|
-
if (name === "--
|
|
152
|
-
if (name === "--
|
|
153
|
-
if (name === "--
|
|
170
|
+
if (name === "--base-url") parsed.baseUrl = value;
|
|
171
|
+
if (name === "--data-dir") parsed.dataDir = value;
|
|
172
|
+
if (name === "--relay") parsed.relayUrls = value;
|
|
154
173
|
if (name === "--proxy") parsed.proxy = value;
|
|
174
|
+
if (name === "--codex-command") parsed.codexCommand = value;
|
|
175
|
+
if (name === "--ready-timeout") parsed.readyTimeout = parsePositive(value, name, 86400);
|
|
176
|
+
if (name === "--host") { parsed.host = value; parsed.hostForUrl = value.includes(":") ? `[${value}]` : value; }
|
|
177
|
+
if (name === "--port") parsed.port = parsePositive(value, name, 65535);
|
|
178
|
+
if (name === "--max-fee") parsed.maxFeeUnits = parsePositive(value, name);
|
|
155
179
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
180
|
+
try { new URL(parsed.baseUrl); } catch { throw new ConsumerCliError("--base-url must be an absolute URL", 2); }
|
|
181
|
+
return parsed;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
function parsePositive(value, label, maximum = Number.MAX_SAFE_INTEGER) {
|
|
185
|
+
if (!/^[1-9][0-9]*$/.test(String(value))) throw new ConsumerCliError(`${label} must be a positive integer`, 2);
|
|
186
|
+
const parsed = Number(value);
|
|
187
|
+
if (!Number.isSafeInteger(parsed) || parsed > maximum) throw new ConsumerCliError(`${label} is too large`, 2);
|
|
162
188
|
return parsed;
|
|
163
189
|
}
|
|
164
190
|
|
|
165
191
|
function bundledCodexCommand() {
|
|
166
|
-
try {
|
|
167
|
-
return createRequire(import.meta.url).resolve("@openai/codex/bin/codex.js");
|
|
168
|
-
} catch {
|
|
169
|
-
return "codex";
|
|
170
|
-
}
|
|
192
|
+
try { return createRequire(import.meta.url).resolve("@openai/codex/bin/codex.js"); } catch { return "codex"; }
|
|
171
193
|
}
|
|
172
194
|
|
|
173
195
|
export function isApiInvocation(argv) {
|
|
@@ -185,34 +207,91 @@ export function isApiInvocation(argv) {
|
|
|
185
207
|
return false;
|
|
186
208
|
}
|
|
187
209
|
|
|
188
|
-
|
|
189
|
-
const
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
if (parsed.dryRun) args.push("--dry-run");
|
|
198
|
-
if (parsed.codexArgs.length) args.push("--", ...parsed.codexArgs);
|
|
199
|
-
return args;
|
|
210
|
+
async function waitUntilReady(state, timeoutSeconds, stdout) {
|
|
211
|
+
const started = Date.now();
|
|
212
|
+
stdout.write("Waiting for a healthy Settlement V8 Relay...\n");
|
|
213
|
+
while (true) {
|
|
214
|
+
try { await state.chooseRelay(); return; } catch (error) {
|
|
215
|
+
if (Date.now() - started >= timeoutSeconds * 1000) throw new ConsumerCliError(`timed out waiting for a healthy Relay: ${error.message}`);
|
|
216
|
+
await new Promise((resolve) => setTimeout(resolve, 2000));
|
|
217
|
+
}
|
|
218
|
+
}
|
|
200
219
|
}
|
|
201
220
|
|
|
202
|
-
function
|
|
203
|
-
return new Promise((resolve
|
|
221
|
+
function runCodex(parsed, state, spawn, stdout, stderr) {
|
|
222
|
+
return new Promise((resolve) => {
|
|
223
|
+
const args = [
|
|
224
|
+
"-c", 'model="gpt-5.5"',
|
|
225
|
+
"-c", 'model_provider="mycomesh"',
|
|
226
|
+
"-c", 'model_providers.mycomesh.name="MycoMesh"',
|
|
227
|
+
"-c", `model_providers.mycomesh.base_url="${state.baseUrl}"`,
|
|
228
|
+
"-c", 'model_providers.mycomesh.env_key="OPENAI_API_KEY"',
|
|
229
|
+
"-c", 'model_providers.mycomesh.wire_api="responses"',
|
|
230
|
+
...parsed.codexArgs,
|
|
231
|
+
];
|
|
232
|
+
const env = { ...process.env, OPENAI_BASE_URL: state.baseUrl, OPENAI_API_KEY: state.paymentKey };
|
|
204
233
|
let child;
|
|
205
|
-
try {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
}
|
|
211
|
-
child.once("error", (error) => reject(new ConsumerCliError(`could not start bash: ${error.message}`)));
|
|
212
|
-
child.once("exit", (code, signal) => {
|
|
213
|
-
resolve(typeof code === "number" ? code : 128 + ({ SIGHUP: 1, SIGINT: 2, SIGTERM: 15 }[signal] ?? 1));
|
|
214
|
-
});
|
|
234
|
+
try { child = spawn(parsed.codexCommand, args, { env, stdio: "inherit" }); }
|
|
235
|
+
catch (error) { stderr.write(`mycomesh consumer: could not start Codex: ${error.message}\n`); resolve(127); return; }
|
|
236
|
+
stdout.write("Opening Codex through the native MycoMesh Consumer.\n");
|
|
237
|
+
child.once("error", (error) => { stderr.write(`mycomesh consumer: Codex failed: ${error.message}\n`); resolve(127); });
|
|
238
|
+
child.once("exit", (code, signal) => resolve(typeof code === "number" ? code : 128 + ({ SIGINT: 2, SIGTERM: 15 }[signal] || 1)));
|
|
215
239
|
});
|
|
216
240
|
}
|
|
217
241
|
|
|
218
|
-
|
|
242
|
+
function writePid(dataDir) {
|
|
243
|
+
try { writeFileSync(join(dataDir, "consumer.pid"), `${process.pid}\n`, { mode: 0o600 }); } catch {}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
function clearPid(dataDir) {
|
|
247
|
+
try { unlinkSync(join(dataDir, "consumer.pid")); } catch {}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
function stopConsumer(parsed, stdout, stderr) {
|
|
251
|
+
const pidPath = join(parsed.dataDir, "consumer.pid");
|
|
252
|
+
if (!existsSync(pidPath)) { stdout.write("No native Consumer is running.\n"); return 0; }
|
|
253
|
+
const pid = Number(readFileSync(pidPath, "utf8").trim());
|
|
254
|
+
if (!Number.isInteger(pid) || pid <= 1) { clearPid(parsed.dataDir); stderr.write("Removed an invalid Consumer pid file.\n"); return 0; }
|
|
255
|
+
try { process.kill(pid, "SIGTERM"); stdout.write(`Stopped native Consumer process ${pid}.\n`); }
|
|
256
|
+
catch (error) { if (error.code !== "ESRCH") throw error; stdout.write("Native Consumer was already stopped.\n"); }
|
|
257
|
+
clearPid(parsed.dataDir);
|
|
258
|
+
return 0;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
async function resetConsumer(parsed, env, stdout, stderr) {
|
|
262
|
+
const confirmed = env.MYCOMESH_CONFIRM_RESET === "RESET";
|
|
263
|
+
if (!confirmed && process.stdin.isTTY) {
|
|
264
|
+
const prompt = readline.createInterface({ input: process.stdin, output: process.stdout });
|
|
265
|
+
const answer = await prompt.question("This removes the local payment key and history. Type RESET to continue: ");
|
|
266
|
+
prompt.close();
|
|
267
|
+
if (answer !== "RESET") throw new ConsumerCliError("local Consumer reset cancelled", 2);
|
|
268
|
+
} else if (!confirmed) {
|
|
269
|
+
throw new ConsumerCliError("set MYCOMESH_CONFIRM_RESET=RESET to reset a non-interactive Consumer", 2);
|
|
270
|
+
}
|
|
271
|
+
clearPid(parsed.dataDir);
|
|
272
|
+
rmSync(parsed.dataDir, { recursive: true, force: true });
|
|
273
|
+
stdout.write("Native Consumer local state removed.\n");
|
|
274
|
+
return 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
function openBrowser(url, stderr) {
|
|
278
|
+
const platform = process.platform;
|
|
279
|
+
let command;
|
|
280
|
+
let args;
|
|
281
|
+
if (platform === "darwin") { command = "open"; args = [url]; }
|
|
282
|
+
else if (platform === "win32") { command = "cmd"; args = ["/c", "start", "", url]; }
|
|
283
|
+
else { command = "xdg-open"; args = [url]; }
|
|
284
|
+
try {
|
|
285
|
+
const child = defaultSpawn(command, args, { stdio: "ignore", detached: true });
|
|
286
|
+
child.unref?.();
|
|
287
|
+
} catch { stderr.write(`Open ${url} in a browser.\n`); }
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
function waitForSignal(shutdown) {
|
|
291
|
+
return new Promise((resolve) => {
|
|
292
|
+
let closed = false;
|
|
293
|
+
const finish = async () => { if (closed) return; closed = true; process.removeListener("SIGINT", finish); process.removeListener("SIGTERM", finish); await shutdown(); resolve(); };
|
|
294
|
+
process.once("SIGINT", finish);
|
|
295
|
+
process.once("SIGTERM", finish);
|
|
296
|
+
});
|
|
297
|
+
}
|
package/consumer.compose.yml
DELETED
|
@@ -1,90 +0,0 @@
|
|
|
1
|
-
services:
|
|
2
|
-
consumer-volume-init:
|
|
3
|
-
image: ${MYCOMESH_NODE_IMAGE:?MYCOMESH_NODE_IMAGE is required}
|
|
4
|
-
user: "0:0"
|
|
5
|
-
network_mode: none
|
|
6
|
-
restart: "no"
|
|
7
|
-
read_only: true
|
|
8
|
-
security_opt:
|
|
9
|
-
- no-new-privileges:true
|
|
10
|
-
cap_drop:
|
|
11
|
-
- ALL
|
|
12
|
-
cap_add:
|
|
13
|
-
- CHOWN
|
|
14
|
-
- DAC_OVERRIDE
|
|
15
|
-
volumes:
|
|
16
|
-
- mycomesh-consumer-data:/volumes/consumer
|
|
17
|
-
entrypoint: ["/bin/sh", "-ec", "chown -R 10001:10001 /volumes/consumer"]
|
|
18
|
-
|
|
19
|
-
consumer:
|
|
20
|
-
image: ${MYCOMESH_NODE_IMAGE:?MYCOMESH_NODE_IMAGE is required}
|
|
21
|
-
user: "10001:10001"
|
|
22
|
-
restart: unless-stopped
|
|
23
|
-
pids_limit: 128
|
|
24
|
-
mem_limit: 256m
|
|
25
|
-
cpus: "1.0"
|
|
26
|
-
logging:
|
|
27
|
-
driver: json-file
|
|
28
|
-
options:
|
|
29
|
-
max-size: 10m
|
|
30
|
-
max-file: "3"
|
|
31
|
-
init: true
|
|
32
|
-
read_only: true
|
|
33
|
-
security_opt:
|
|
34
|
-
- no-new-privileges:true
|
|
35
|
-
cap_drop:
|
|
36
|
-
- ALL
|
|
37
|
-
working_dir: /data
|
|
38
|
-
environment:
|
|
39
|
-
MYCOMESH_CONSUMER_DATA_DIR: /data
|
|
40
|
-
MYCOMESH_CONSUMER_PROTOCOL_VERSION: ${MYCOMESH_CONSUMER_PROTOCOL_VERSION:-8}
|
|
41
|
-
MYCOMESH_CONSUMER_NETWORK_CONFIG: ${MYCOMESH_CONSUMER_NETWORK_CONFIG:-/app/deployments/sepolia-provider-network-v8.json}
|
|
42
|
-
MYCOMESH_CONSUMER_PUBLIC_BASE_URL: http://127.0.0.1:8110/v1
|
|
43
|
-
MYCOMESH_V7_RELAY_URLS: ${MYCOMESH_V7_RELAY_URLS:-https://bridge.mycomesh.xyz}
|
|
44
|
-
MYCOMESH_V7_MAX_FEE_UNITS: ${MYCOMESH_V7_MAX_FEE_UNITS:-100000}
|
|
45
|
-
MYCOMESH_V7_REQUEST_TIMEOUT_SECONDS: ${MYCOMESH_V7_REQUEST_TIMEOUT_SECONDS:-300}
|
|
46
|
-
MYCOMESH_V8_RELAY_URLS: ${MYCOMESH_V8_RELAY_URLS:-https://bridge.mycomesh.xyz}
|
|
47
|
-
MYCOMESH_V8_MAX_FEE_UNITS: ${MYCOMESH_V8_MAX_FEE_UNITS:-100000}
|
|
48
|
-
HTTP_PROXY: ${MYCOMESH_CONSUMER_HTTP_PROXY:-}
|
|
49
|
-
HTTPS_PROXY: ${MYCOMESH_CONSUMER_HTTPS_PROXY:-}
|
|
50
|
-
ALL_PROXY: ${MYCOMESH_CONSUMER_ALL_PROXY:-}
|
|
51
|
-
NO_PROXY: ${MYCOMESH_CONSUMER_NO_PROXY:-127.0.0.1,localhost,::1}
|
|
52
|
-
http_proxy: ${MYCOMESH_CONSUMER_HTTP_PROXY:-}
|
|
53
|
-
https_proxy: ${MYCOMESH_CONSUMER_HTTPS_PROXY:-}
|
|
54
|
-
all_proxy: ${MYCOMESH_CONSUMER_ALL_PROXY:-}
|
|
55
|
-
no_proxy: ${MYCOMESH_CONSUMER_NO_PROXY:-127.0.0.1,localhost,::1}
|
|
56
|
-
extra_hosts:
|
|
57
|
-
- host.docker.internal:host-gateway
|
|
58
|
-
ports:
|
|
59
|
-
- "127.0.0.1:8110:8110"
|
|
60
|
-
volumes:
|
|
61
|
-
- mycomesh-consumer-data:/data
|
|
62
|
-
tmpfs:
|
|
63
|
-
- /tmp:size=32m,mode=1777
|
|
64
|
-
depends_on:
|
|
65
|
-
consumer-volume-init:
|
|
66
|
-
condition: service_completed_successfully
|
|
67
|
-
stop_grace_period: 15s
|
|
68
|
-
healthcheck:
|
|
69
|
-
test:
|
|
70
|
-
- CMD
|
|
71
|
-
- python
|
|
72
|
-
- -c
|
|
73
|
-
- "import json, urllib.request; value=json.load(urllib.request.urlopen('http://127.0.0.1:8110/health', timeout=3)); assert value.get('ok') is True; assert value.get('gateway_dependency') is False; assert value.get('browser_app_ready') is True"
|
|
74
|
-
interval: 15s
|
|
75
|
-
timeout: 5s
|
|
76
|
-
retries: 4
|
|
77
|
-
start_period: 10s
|
|
78
|
-
entrypoint: ["sh", "-ec"]
|
|
79
|
-
command:
|
|
80
|
-
- >-
|
|
81
|
-
if [ "$${MYCOMESH_CONSUMER_PROTOCOL_VERSION:-8}" = "8" ]; then
|
|
82
|
-
exec python -m gateway.consumer_v8 serve --host 0.0.0.0 --port 8110;
|
|
83
|
-
elif [ "$${MYCOMESH_CONSUMER_PROTOCOL_VERSION:-8}" = "7" ]; then
|
|
84
|
-
exec python -m gateway.consumer_v7 serve --host 0.0.0.0 --port 8110;
|
|
85
|
-
else
|
|
86
|
-
exec python -m gateway.local_consumer serve --host 0.0.0.0 --port 8110;
|
|
87
|
-
fi
|
|
88
|
-
|
|
89
|
-
volumes:
|
|
90
|
-
mycomesh-consumer-data:
|