zkcloudworker 0.4.7 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- 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);
|