UNPKG

@radcliffetech/symbolos-core

Version:

Core symbolic simulation and execution engine for Symbolos

106 lines (105 loc) 4.94 kB
import chalk from "chalk"; import { createClient } from "redis"; import { promisify } from "util"; import { ungzip } from "node-gzip"; import { gzip as zlibGzip } from "zlib"; const gzip = promisify(zlibGzip); export async function getRedisClient() { const redisUrl = process.env.REDIS_URL || "redis://localhost:6379"; const redisClient = createClient({ url: redisUrl }); redisClient.on("error", (err) => console.log("Redis Client Error", err)); await redisClient.connect(); return redisClient; } export async function storeWorldInstanceToRedis({ redisClient, world, prefix = "symbolos:worlds", verbose = false, }) { const key = `${prefix}:${world.pipelineId}:${world.runId}:frame:${world.tick}`; const worldData = JSON.stringify(world); if (verbose) { console.log(chalk.blueBright(`[symbolos] 🗄️ Storing world instance to Redis at key: ${key} (Tick: ${world.tick}, Step: ${world.step})`)); } redisClient.set(key, worldData); } export async function getCompressedWorldFrameFromRedis({ redisClient, pipelineId, runId, tick, prefix = "symbolos:worlds", }) { const key = `${prefix}:${pipelineId}:${runId}:frame:${tick}`; const compressed = await redisClient.get(key); const decompressed = await ungzip(Buffer.from(compressed)); return JSON.parse(decompressed.toString()); } export async function storeCompressedWorldFrameToRedis({ redisClient, world, prefix = "symbolos:worlds", verbose = false, }) { const key = `${prefix}:${world.pipelineId}:${world.runId}:frame:${world.tick}`; const compressed = await gzip(Buffer.from(JSON.stringify(world))); await redisClient.set(key, compressed); } export async function getWorldFrameFromRedis({ redisClient, pipelineId, runId, tick, prefix = "symbolos:worlds", }) { const key = `${prefix}:${pipelineId}:${runId}:frame:${tick}`; const json = await redisClient.get(key); return json ? JSON.parse(json) : null; } export async function listFramesForRun(redisClient, pipelineId, runId, prefix = "symbolos:worlds") { const pattern = `${prefix}:${pipelineId}:${runId}:frame:*`; const keys = await redisClient.keys(pattern); return keys.sort((a, b) => { const aTick = parseInt(a.split(":").pop() || "0"); const bTick = parseInt(b.split(":").pop() || "0"); return aTick - bTick; }); } export async function indexWorldRun(redisClient, pipelineId, runId, prefix = "symbolos:index") { const key = `${prefix}:${pipelineId}`; await redisClient.sAdd(key, runId); } export async function listWorldRuns(redisClient, pipelineId, prefix = "symbolos:index") { const key = `${prefix}:${pipelineId}`; const runs = await redisClient.smembers(key); return runs.sort(); } export async function getLatestFrameForRun(redisClient, pipelineId, runId, prefix = "symbolos:worlds") { const keys = await listFramesForRun(redisClient, pipelineId, runId, prefix); const latestKey = keys.at(-1); if (!latestKey) return null; const json = await redisClient.get(latestKey); return json ? JSON.parse(json) : null; } export async function getLatestCompressedFrameForRun(redisClient, pipelineId, runId, prefix = "symbolos:worlds") { const keys = await listFramesForRun(redisClient, pipelineId, runId, prefix); const latestKey = keys.at(-1); if (!latestKey) return null; const compressed = await redisClient.get(latestKey); if (!compressed) return null; const decompressed = await ungzip(compressed); return JSON.parse(decompressed.toString()); } export async function deleteWorldRun(redisClient, pipelineId, runId, prefix = "symbolos:worlds") { const frameKeys = await listFramesForRun(redisClient, pipelineId, runId, prefix); if (frameKeys.length > 0) { await redisClient.del(...frameKeys); } await redisClient.srem(`symbolos:index:${pipelineId}`, runId); } export async function listWorldPipelines(redisClient, prefix = "symbolos:index") { const keys = await redisClient.keys(`${prefix}:*`); return keys.map((key) => key.replace(`${prefix}:`, "")).sort(); } export async function deleteAllRunsForPipeline(redisClient, pipelineId, prefix = "symbolos:worlds") { const runIds = await listWorldRuns(redisClient, pipelineId); for (const runId of runIds) { const frameKeys = await listFramesForRun(redisClient, pipelineId, runId, prefix); if (frameKeys.length > 0) { await redisClient.del(...frameKeys); } } await redisClient.del(`symbolos:index:${pipelineId}`); } export const convertWorldFrameToCSV = (world) => { // Implementation placeholder - adjust as needed // Example: convert world object's properties to CSV string const headers = Object.keys(world).join(","); const values = Object.values(world) .map((value) => JSON.stringify(value)) .join(","); return `${headers}\n${values}`; };