@radcliffetech/symbolos-core
Version:
Core symbolic simulation and execution engine for Symbolos
106 lines (105 loc) • 4.94 kB
JavaScript
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}`;
};