zkcloudworker 0.4.7 → 0.5.1
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/lib/ts/src/api/api.d.ts +4 -0
- package/lib/ts/src/api/api.js +32 -2
- package/lib/ts/src/cloud/job.d.ts +7 -0
- package/lib/ts/src/config.d.ts +1 -0
- package/lib/ts/src/config.js +1 -0
- package/lib/ts/src/encryption/encryption.d.ts +12 -0
- package/lib/ts/src/encryption/encryption.js +41 -0
- package/lib/ts/src/encryption/messages.d.ts +2 -0
- package/lib/ts/src/encryption/messages.js +38 -0
- package/lib/ts/src/encryption/nats-client.d.ts +1 -0
- package/lib/ts/src/encryption/nats-client.js +85 -0
- package/lib/ts/src/index.d.ts +3 -0
- package/lib/ts/src/index.js +3 -0
- package/lib/ts/tsconfig.tsbuildinfo +1 -1
- package/lib/web/src/api/api.d.ts +4 -0
- package/lib/web/src/api/api.js +34 -4
- package/lib/web/src/api/api.js.map +1 -1
- package/lib/web/src/cloud/job.d.ts +7 -0
- package/lib/web/src/config.d.ts +1 -0
- package/lib/web/src/config.js +1 -0
- package/lib/web/src/config.js.map +1 -1
- package/lib/web/src/encryption/encryption.d.ts +12 -0
- package/lib/web/src/encryption/encryption.js +41 -0
- package/lib/web/src/encryption/encryption.js.map +1 -0
- package/lib/web/src/encryption/messages.d.ts +2 -0
- package/lib/web/src/encryption/messages.js +36 -0
- package/lib/web/src/encryption/messages.js.map +1 -0
- package/lib/web/src/encryption/nats-client.d.ts +1 -0
- package/lib/web/src/encryption/nats-client.js +95 -0
- package/lib/web/src/encryption/nats-client.js.map +1 -0
- package/lib/web/src/index.d.ts +3 -0
- package/lib/web/src/index.js +3 -0
- package/lib/web/src/index.js.map +1 -1
- package/lib/web/tsconfig.web.tsbuildinfo +1 -1
- package/package.json +4 -2
package/lib/ts/src/api/api.d.ts
CHANGED
@@ -108,6 +108,7 @@ export declare class zkCloudWorkerClient {
|
|
108
108
|
* Gets the result of the job using serverless api call
|
109
109
|
* @param data the data for the jobResult call
|
110
110
|
* @param data.jobId the jobId of the job
|
111
|
+
* @param data.includeLogs include logs in the result, default is false
|
111
112
|
* @returns { success: boolean, error?: string, result?: any }
|
112
113
|
* where result is the result of the job
|
113
114
|
* if the job is not finished yet, the result will be undefined
|
@@ -117,6 +118,7 @@ export declare class zkCloudWorkerClient {
|
|
117
118
|
*/
|
118
119
|
jobResult(data: {
|
119
120
|
jobId: string;
|
121
|
+
includeLogs?: boolean;
|
120
122
|
}): Promise<{
|
121
123
|
success: boolean;
|
122
124
|
error?: string;
|
@@ -169,6 +171,7 @@ export declare class zkCloudWorkerClient {
|
|
169
171
|
* @param data.maxAttempts the maximum number of attempts, default is 360 (2 hours)
|
170
172
|
* @param data.interval the interval between attempts, default is 20000 (20 seconds)
|
171
173
|
* @param data.maxErrors the maximum number of network errors, default is 10
|
174
|
+
* @param data.printLogs print logs, default is true
|
172
175
|
* @returns { success: boolean, error?: string, result?: any }
|
173
176
|
* where result is the result of the job
|
174
177
|
*/
|
@@ -177,6 +180,7 @@ export declare class zkCloudWorkerClient {
|
|
177
180
|
maxAttempts?: number;
|
178
181
|
interval?: number;
|
179
182
|
maxErrors?: number;
|
183
|
+
printLogs?: boolean;
|
180
184
|
}): Promise<{
|
181
185
|
success: boolean;
|
182
186
|
error?: string;
|
package/lib/ts/src/api/api.js
CHANGED
@@ -5,6 +5,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
6
6
|
exports.zkCloudWorkerClient = void 0;
|
7
7
|
const axios_1 = __importDefault(require("axios"));
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
8
9
|
const mina_1 = require("../mina");
|
9
10
|
const local_1 = require("../cloud/local");
|
10
11
|
const config_1 = __importDefault(require("../config"));
|
@@ -134,6 +135,7 @@ class zkCloudWorkerClient {
|
|
134
135
|
* Gets the result of the job using serverless api call
|
135
136
|
* @param data the data for the jobResult call
|
136
137
|
* @param data.jobId the jobId of the job
|
138
|
+
* @param data.includeLogs include logs in the result, default is false
|
137
139
|
* @returns { success: boolean, error?: string, result?: any }
|
138
140
|
* where result is the result of the job
|
139
141
|
* if the job is not finished yet, the result will be undefined
|
@@ -235,18 +237,39 @@ class zkCloudWorkerClient {
|
|
235
237
|
* @param data.maxAttempts the maximum number of attempts, default is 360 (2 hours)
|
236
238
|
* @param data.interval the interval between attempts, default is 20000 (20 seconds)
|
237
239
|
* @param data.maxErrors the maximum number of network errors, default is 10
|
240
|
+
* @param data.printLogs print logs, default is true
|
238
241
|
* @returns { success: boolean, error?: string, result?: any }
|
239
242
|
* where result is the result of the job
|
240
243
|
*/
|
241
244
|
async waitForJobResult(data) {
|
242
245
|
const maxAttempts = data?.maxAttempts ?? 360; // 2 hours
|
243
|
-
const interval = data?.interval ??
|
246
|
+
const interval = data?.interval ?? 10000;
|
244
247
|
const maxErrors = data?.maxErrors ?? 10;
|
245
248
|
const errorDelay = 30000; // 30 seconds
|
249
|
+
const printedLogs = [];
|
250
|
+
const printLogs = data.printLogs ?? true;
|
251
|
+
function print(logs) {
|
252
|
+
logs.forEach((log) => {
|
253
|
+
if (printedLogs.includes(log) === false) {
|
254
|
+
printedLogs.push(log);
|
255
|
+
// replace all occurrences of "error" with red color
|
256
|
+
const text = log.replace(/error/gi, (matched) => chalk_1.default.red(matched));
|
257
|
+
console.log(text);
|
258
|
+
}
|
259
|
+
});
|
260
|
+
}
|
246
261
|
let attempts = 0;
|
247
262
|
let errors = 0;
|
248
263
|
while (attempts < maxAttempts) {
|
249
|
-
const result = await this.apiHub("jobResult",
|
264
|
+
const result = await this.apiHub("jobResult", {
|
265
|
+
jobId: data.jobId,
|
266
|
+
includeLogs: printLogs,
|
267
|
+
});
|
268
|
+
if (printLogs === true &&
|
269
|
+
result?.data?.logs !== undefined &&
|
270
|
+
result?.data?.logs !== null &&
|
271
|
+
Array.isArray(result.data.logs) === true)
|
272
|
+
print(result.data.logs);
|
250
273
|
if (result.success === false) {
|
251
274
|
errors++;
|
252
275
|
if (errors > maxErrors) {
|
@@ -272,6 +295,13 @@ class zkCloudWorkerClient {
|
|
272
295
|
result: result.data,
|
273
296
|
};
|
274
297
|
}
|
298
|
+
else if (result.data?.jobStatus === "failed") {
|
299
|
+
return {
|
300
|
+
success: false,
|
301
|
+
error: "Job failed",
|
302
|
+
result: result.data,
|
303
|
+
};
|
304
|
+
}
|
275
305
|
await (0, mina_1.sleep)(interval);
|
276
306
|
}
|
277
307
|
attempts++;
|
@@ -1,5 +1,10 @@
|
|
1
1
|
import { blockchain } from "../networks";
|
2
2
|
export type JobStatus = "created" | "started" | "finished" | "failed" | "used";
|
3
|
+
export interface LogStream {
|
4
|
+
logGroupName: string;
|
5
|
+
logStreamName: string;
|
6
|
+
awsRequestId: string;
|
7
|
+
}
|
3
8
|
export interface JobData {
|
4
9
|
id: string;
|
5
10
|
jobId: string;
|
@@ -29,4 +34,6 @@ export interface JobData {
|
|
29
34
|
jobStatus: JobStatus;
|
30
35
|
maxAttempts: number;
|
31
36
|
result?: string;
|
37
|
+
logStreams?: LogStream[];
|
38
|
+
logs?: string[];
|
32
39
|
}
|
package/lib/ts/src/config.d.ts
CHANGED
package/lib/ts/src/config.js
CHANGED
@@ -4,5 +4,6 @@ const config = {
|
|
4
4
|
MINAFEE: "200000000",
|
5
5
|
ZKCLOUDWORKER_AUTH: "M6t4jtbBAFFXhLERHQWyEB9JA9xi4cWqmYduaCXtbrFjb7yaY7TyaXDunKDJNiUTBEcyUomNXJgC",
|
6
6
|
ZKCLOUDWORKER_API: "https://cuq99yahhi.execute-api.eu-west-1.amazonaws.com/dev/zkcloudworker",
|
7
|
+
NATS_SERVER: "nats.socialcap.dev:4222",
|
7
8
|
};
|
8
9
|
exports.default = config;
|
@@ -0,0 +1,12 @@
|
|
1
|
+
import { Field, Group } from "o1js";
|
2
|
+
export interface CipherTextObject {
|
3
|
+
cipherText: Field[];
|
4
|
+
publicKey: Group;
|
5
|
+
}
|
6
|
+
export declare class CipherText {
|
7
|
+
static stringify(cipherText: CipherTextObject): string;
|
8
|
+
static parse(jsonStr: string): CipherTextObject;
|
9
|
+
static encrypt(message: string, publicId: string): string;
|
10
|
+
static decrypt(cipherText: string, privateKey: string): string;
|
11
|
+
static initialize(): Promise<void>;
|
12
|
+
}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.CipherText = void 0;
|
4
|
+
const o1js_1 = require("o1js");
|
5
|
+
class CipherText {
|
6
|
+
static stringify(cipherText) {
|
7
|
+
return JSON.stringify(cipherText);
|
8
|
+
}
|
9
|
+
static parse(jsonStr) {
|
10
|
+
let obj = JSON.parse(jsonStr);
|
11
|
+
return {
|
12
|
+
publicKey: new o1js_1.Group(obj.publicKey),
|
13
|
+
cipherText: (obj.cipherText || []).map((t) => (0, o1js_1.Field)(t)),
|
14
|
+
};
|
15
|
+
}
|
16
|
+
static encrypt(message, publicId) {
|
17
|
+
try {
|
18
|
+
let fields = o1js_1.Encoding.stringToFields(message);
|
19
|
+
let encrypted = o1js_1.Encryption.encrypt(fields, o1js_1.PublicKey.fromBase58(publicId));
|
20
|
+
return CipherText.stringify(encrypted);
|
21
|
+
}
|
22
|
+
catch (err) {
|
23
|
+
throw Error(`Could not encrypt message='${message}' using key='${publicId}'.` +
|
24
|
+
` Error ${err}`);
|
25
|
+
}
|
26
|
+
}
|
27
|
+
static decrypt(cipherText, privateKey) {
|
28
|
+
try {
|
29
|
+
let fields = o1js_1.Encryption.decrypt(CipherText.parse(cipherText), o1js_1.PrivateKey.fromBase58(privateKey));
|
30
|
+
let decrypted = o1js_1.Encoding.stringFromFields(fields);
|
31
|
+
return decrypted;
|
32
|
+
}
|
33
|
+
catch (err) {
|
34
|
+
throw Error(`Could not decrypt cipher='${cipherText}'.` + ` Error ${err}`);
|
35
|
+
}
|
36
|
+
}
|
37
|
+
static async initialize() {
|
38
|
+
await (0, o1js_1.initializeBindings)();
|
39
|
+
}
|
40
|
+
}
|
41
|
+
exports.CipherText = CipherText;
|
@@ -0,0 +1,38 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.postDoneMessage = exports.postReadyMessage = void 0;
|
7
|
+
const nats_1 = require("nats");
|
8
|
+
const config_1 = __importDefault(require("../config"));
|
9
|
+
const { NATS_SERVER } = config_1.default;
|
10
|
+
const codec = (0, nats_1.JSONCodec)();
|
11
|
+
async function postReadyMessage(clientAddress, workerAddress) {
|
12
|
+
// connect to the NATS server and send a 'ready' request
|
13
|
+
const nc = await (0, nats_1.connect)({ servers: NATS_SERVER });
|
14
|
+
const msg = await nc.request(`zkcw:${clientAddress}`, codec.encode({
|
15
|
+
post: "ready",
|
16
|
+
params: { key: workerAddress },
|
17
|
+
}));
|
18
|
+
const response = codec.decode(msg.data);
|
19
|
+
console.log("Response: ", response);
|
20
|
+
// disconnect and clean all pending
|
21
|
+
await nc.drain();
|
22
|
+
return response;
|
23
|
+
}
|
24
|
+
exports.postReadyMessage = postReadyMessage;
|
25
|
+
async function postDoneMessage(clientAddress, encrypted) {
|
26
|
+
// connect to the NATS server and send a 'ready' request
|
27
|
+
const nc = await (0, nats_1.connect)({ servers: NATS_SERVER });
|
28
|
+
const msg = await nc.request(`zkcw:${clientAddress}`, codec.encode({
|
29
|
+
post: "done",
|
30
|
+
params: { result: encrypted },
|
31
|
+
}));
|
32
|
+
const response = codec.decode(msg.data);
|
33
|
+
console.log("Response: ", response);
|
34
|
+
// disconnect and clean all pending
|
35
|
+
await nc.drain();
|
36
|
+
return response;
|
37
|
+
}
|
38
|
+
exports.postDoneMessage = postDoneMessage;
|
@@ -0,0 +1 @@
|
|
1
|
+
export declare function listen(subject: string): Promise<void>;
|
@@ -0,0 +1,85 @@
|
|
1
|
+
"use strict";
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
4
|
+
};
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
6
|
+
exports.listen = void 0;
|
7
|
+
const nats_1 = require("nats");
|
8
|
+
const o1js_1 = require("o1js");
|
9
|
+
const encryption_1 = require("./encryption");
|
10
|
+
const config_1 = __importDefault(require("../config"));
|
11
|
+
const { NATS_SERVER } = config_1.default;
|
12
|
+
async function listen(subject) {
|
13
|
+
// Create a JSON codec for encoding and decoding messages
|
14
|
+
const codec = (0, nats_1.JSONCodec)();
|
15
|
+
const connection = await (0, nats_1.connect)({ servers: NATS_SERVER });
|
16
|
+
// Subscribe to the subject
|
17
|
+
const subscription = connection.subscribe(subject);
|
18
|
+
console.log(`Subscribed to subject ${subject}`);
|
19
|
+
// Process messages received on the subscribed subject
|
20
|
+
(async () => {
|
21
|
+
// Error decoding message: Error: Could not encrypt message={}
|
22
|
+
// Error: Poseidon.Sponge(): bindings are not initialized, try calling `await initializeBindings()` first.
|
23
|
+
// This shouldn't have happened and indicates an internal bug.
|
24
|
+
await (0, o1js_1.initializeBindings)();
|
25
|
+
for await (const msg of subscription) {
|
26
|
+
try {
|
27
|
+
const data = codec.decode(msg.data);
|
28
|
+
//console.log(`Received message on subject ${subject}:`, data);
|
29
|
+
// Perform processing logic here
|
30
|
+
const { post, params } = data;
|
31
|
+
// console.log(`Post: `, post, params);
|
32
|
+
switch (post) {
|
33
|
+
case "ready":
|
34
|
+
{
|
35
|
+
// the workers announces it is ready
|
36
|
+
// and we receive the worker's publicKey
|
37
|
+
let workerKey = params.key || "";
|
38
|
+
console.log("Received 'ready' message from worker");
|
39
|
+
console.log("Worker publicKey: ", workerKey);
|
40
|
+
// we will use its key to encrypt the message
|
41
|
+
const encryptedPayload = encryption_1.CipherText.encrypt(JSON.stringify({
|
42
|
+
value: Math.ceil(Math.random() * 100).toString(),
|
43
|
+
}), workerKey);
|
44
|
+
console.log("Encrypted payload: ", encryptedPayload);
|
45
|
+
// we reply with the command we want the worker to execute
|
46
|
+
// and with the encrypted payload
|
47
|
+
msg.respond(codec.encode({
|
48
|
+
success: true,
|
49
|
+
data: {
|
50
|
+
command: "execute",
|
51
|
+
encrypted: encryptedPayload,
|
52
|
+
},
|
53
|
+
error: undefined,
|
54
|
+
}));
|
55
|
+
}
|
56
|
+
break;
|
57
|
+
case "done":
|
58
|
+
{
|
59
|
+
let result = params.result || "";
|
60
|
+
console.log("Received 'done' message from worker");
|
61
|
+
msg.respond(codec.encode({
|
62
|
+
success: true,
|
63
|
+
data: { status: "closed" },
|
64
|
+
error: undefined,
|
65
|
+
}));
|
66
|
+
// we want to insure that messages that are in flight
|
67
|
+
// get processed, so we are going to drain the
|
68
|
+
// connection. Drain is the same as close, but makes
|
69
|
+
// sure that all messages in flight get seen
|
70
|
+
// by the iterator. After calling drain on the connection
|
71
|
+
// the connection closes.
|
72
|
+
setTimeout(async () => {
|
73
|
+
await connection.drain();
|
74
|
+
}, 1000);
|
75
|
+
}
|
76
|
+
break;
|
77
|
+
}
|
78
|
+
}
|
79
|
+
catch (err) {
|
80
|
+
console.error("Error decoding message: ", err);
|
81
|
+
}
|
82
|
+
}
|
83
|
+
})();
|
84
|
+
}
|
85
|
+
exports.listen = listen;
|
package/lib/ts/src/index.d.ts
CHANGED
package/lib/ts/src/index.js
CHANGED
@@ -24,3 +24,6 @@ __exportStar(require("./fee"), exports);
|
|
24
24
|
__exportStar(require("./fetch"), exports);
|
25
25
|
__exportStar(require("./networks"), exports);
|
26
26
|
__exportStar(require("./api/client-api"), exports);
|
27
|
+
__exportStar(require("./encryption/encryption"), exports);
|
28
|
+
__exportStar(require("./encryption/nats-client"), exports);
|
29
|
+
__exportStar(require("./encryption/messages"), exports);
|