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.
Files changed (35) hide show
  1. package/lib/ts/src/api/api.d.ts +4 -0
  2. package/lib/ts/src/api/api.js +32 -2
  3. package/lib/ts/src/cloud/job.d.ts +7 -0
  4. package/lib/ts/src/config.d.ts +1 -0
  5. package/lib/ts/src/config.js +1 -0
  6. package/lib/ts/src/encryption/encryption.d.ts +12 -0
  7. package/lib/ts/src/encryption/encryption.js +41 -0
  8. package/lib/ts/src/encryption/messages.d.ts +2 -0
  9. package/lib/ts/src/encryption/messages.js +38 -0
  10. package/lib/ts/src/encryption/nats-client.d.ts +1 -0
  11. package/lib/ts/src/encryption/nats-client.js +85 -0
  12. package/lib/ts/src/index.d.ts +3 -0
  13. package/lib/ts/src/index.js +3 -0
  14. package/lib/ts/tsconfig.tsbuildinfo +1 -1
  15. package/lib/web/src/api/api.d.ts +4 -0
  16. package/lib/web/src/api/api.js +34 -4
  17. package/lib/web/src/api/api.js.map +1 -1
  18. package/lib/web/src/cloud/job.d.ts +7 -0
  19. package/lib/web/src/config.d.ts +1 -0
  20. package/lib/web/src/config.js +1 -0
  21. package/lib/web/src/config.js.map +1 -1
  22. package/lib/web/src/encryption/encryption.d.ts +12 -0
  23. package/lib/web/src/encryption/encryption.js +41 -0
  24. package/lib/web/src/encryption/encryption.js.map +1 -0
  25. package/lib/web/src/encryption/messages.d.ts +2 -0
  26. package/lib/web/src/encryption/messages.js +36 -0
  27. package/lib/web/src/encryption/messages.js.map +1 -0
  28. package/lib/web/src/encryption/nats-client.d.ts +1 -0
  29. package/lib/web/src/encryption/nats-client.js +95 -0
  30. package/lib/web/src/encryption/nats-client.js.map +1 -0
  31. package/lib/web/src/index.d.ts +3 -0
  32. package/lib/web/src/index.js +3 -0
  33. package/lib/web/src/index.js.map +1 -1
  34. package/lib/web/tsconfig.web.tsbuildinfo +1 -1
  35. package/package.json +4 -2
@@ -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;
@@ -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 ?? 20000;
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", data);
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
  }
@@ -2,5 +2,6 @@ declare const config: {
2
2
  MINAFEE: string;
3
3
  ZKCLOUDWORKER_AUTH: string;
4
4
  ZKCLOUDWORKER_API: string;
5
+ NATS_SERVER: string;
5
6
  };
6
7
  export default config;
@@ -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,2 @@
1
+ export declare function postReadyMessage(clientAddress: string, workerAddress: string): Promise<any>;
2
+ export declare function postDoneMessage(clientAddress: string, encrypted: string): Promise<any>;
@@ -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;
@@ -8,3 +8,6 @@ export * from "./fee";
8
8
  export * from "./fetch";
9
9
  export * from "./networks";
10
10
  export * from "./api/client-api";
11
+ export * from "./encryption/encryption";
12
+ export * from "./encryption/nats-client";
13
+ export * from "./encryption/messages";
@@ -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);