UNPKG

@getanthill/datastore

Version:

Event-Sourced Datastore

138 lines (110 loc) 2.9 kB
import type FullyHomomorphicEncryptionClient from '../services/fhe'; import path from 'node:path'; import { Worker } from 'worker_threads'; import { ModelConfig } from '../typings'; export async function handle( handler: string | Function, state: any, event: any, modelConfig?: ModelConfig, fhe?: FullyHomomorphicEncryptionClient, ) { if ( modelConfig?.with_fully_homomorphic_encryption === true && fhe !== undefined && typeof handler === 'string' ) { return handleFHE(handler, state, event, modelConfig, fhe); } if (typeof handler === 'function') { return handler(state, event); } const res = await thread<any>( `async function handler(state, event) { ${handler} }`, state, event, ); return res; } export async function handleFHE( handler: string | Function, state: any, event: any, modelConfig: ModelConfig, fhe: FullyHomomorphicEncryptionClient, ) { const con = fhe.constructor .toString() .replace(/\/\* istanbul ignore next \*\//gm, '') .replace(/cov_[a-z0-9]+\(\)\.(b|s|f)(\[\d+\])+\+\+/gm, 'null'); const p = path.resolve(__dirname, '../../dist/'); const script = ` const SEAL = require("node-seal"); const _vm = require('vm'); _vm.default = _vm; const _operatorOverload = require("${p}/services/fhe/operator-overload"); const _utils = require("${p}/utils"); let sealPromise = SEAL(); ${con} async function handler(state, event) { const fhe = new FullyHomomorphicEncryptionClient({}); await fhe.connect(); const UploadedPublicKey = fhe.seal.PublicKey(); UploadedPublicKey.load(fhe.context, workerData.publicKey); fhe.keys.public = UploadedPublicKey; const asyncFn = fhe.compile( \`async function handler(state, event) { ${handler} }\`); const res = await fhe.compute(asyncFn, state, event); return res; }`; const publicKey = event?.[modelConfig.fhe_public_key_field!] ?? state?.[modelConfig.fhe_public_key_field!] ?? modelConfig.fhe_public_key_field!; const res = await thread<any>(script, state, event, { publicKey, }); return res; } export async function thread<T>( script: string, state: any, event: any, extra?: any, ) { return new Promise((resolve, reject) => { let result: T; const workerScript = ` const { parentPort, workerData } = require('worker_threads'); ${script} async function main() { const res = await handler(workerData.state, workerData.event); parentPort.postMessage(JSON.stringify(res)); } main().catch((err) => { throw err; }); `; const thread = new Worker(workerScript, { workerData: { ...extra, state, event, }, eval: true, }); thread.on('error', (err) => { reject(err); }); thread.on('exit', () => { resolve(result); }); thread.on('message', (msg) => { result = JSON.parse(msg); }); }); }