Simple live moves

This commit is contained in:
2026-02-08 16:55:39 +01:00
parent 8f7fc0188c
commit f7401fb319
3 changed files with 29 additions and 10 deletions
+23 -5
View File
@@ -9,7 +9,7 @@ import { json } from "@codemirror/lang-json";
import { python } from "@codemirror/lang-python"; import { python } from "@codemirror/lang-python";
import { java } from "@codemirror/lang-java"; import { java } from "@codemirror/lang-java";
import { useEffect, useState } from "react"; import { useEffect, useState } from "react";
import useAction, { useActionOnce } from "@/hook/use-action"; import useAction from "@/hook/use-action";
import { getLiveRunMoves } from "@/modules/live-run/actions"; import { getLiveRunMoves } from "@/modules/live-run/actions";
import { LiveRun, LiveRunMove } from "@/modules/live-run/types"; import { LiveRun, LiveRunMove } from "@/modules/live-run/types";
@@ -43,13 +43,31 @@ function getLanguageExtension(lang: Language) {
export default function Editor({ run }: { run: LiveRun | null | undefined }) { export default function Editor({ run }: { run: LiveRun | null | undefined }) {
const [editorView, setEditorView] = useState<EditorView>(); const [editorView, setEditorView] = useState<EditorView>();
const [moves] = useAction<LiveRunMove[]>( const [rawMoves] = useAction<LiveRunMove[]>(
async () => (run ? await getLiveRunMoves(run.id) : []), async () => (run ? await getLiveRunMoves(run.id) : []),
[run], [run],
); );
const [lastMoveId, setLastMoveId] = useState<number>(-1);
const [moves, setMoves] = useState<LiveRunMove[]>([]);
useEffect(() => { useEffect(() => {
console.log(moves); let moves = rawMoves?.filter((move) => move.moveId > lastMoveId) || [];
if (moves.length === 0) return;
setMoves(moves);
setLastMoveId(lastMoveId + moves.length);
if (rawMoves?.length || 0 > 0) {
console.log("raw", rawMoves);
}
}, [rawMoves]);
useEffect(() => {
if (moves.length > 0) {
console.log("moves", moves);
}
}, [moves]); }, [moves]);
useEffect(() => { useEffect(() => {
@@ -63,7 +81,7 @@ export default function Editor({ run }: { run: LiveRun | null | undefined }) {
if (!editorView || cancelled) return resolve(); if (!editorView || cancelled) return resolve();
editorView.dispatch({ editorView.dispatch({
selection: { anchor: move.cursor }, // selection: { anchor: move.cursor },
scrollIntoView: true, scrollIntoView: true,
changes: move.changes, changes: move.changes,
}); });
@@ -86,7 +104,7 @@ export default function Editor({ run }: { run: LiveRun | null | undefined }) {
return () => { return () => {
cancelled = true; cancelled = true;
}; };
}, [editorView, moves]); }, [moves]);
return ( return (
<CodeMirror <CodeMirror
+3 -3
View File
@@ -4,6 +4,7 @@ import "server-only";
import { LiveRun, LiveRunMove } from "./types"; import { LiveRun, LiveRunMove } from "./types";
import { SupabaseClient } from "@supabase/supabase-js"; import { SupabaseClient } from "@supabase/supabase-js";
import { redis } from "@/lib/redis"; import { redis } from "@/lib/redis";
import { randomInt } from "crypto";
/** -------------------- Live Runs in Redis -------------------- */ /** -------------------- Live Runs in Redis -------------------- */
@@ -55,13 +56,12 @@ export async function addLiveRunMoves(id: string, moves: LiveRunMove[]) {
const pipeline = redis.pipeline(); const pipeline = redis.pipeline();
moves.forEach((move) => { moves.forEach((move) => {
pipeline.rpush(`liveRunMoves:${id}`, JSON.stringify(move)); pipeline.rpush(`liveRunMoves:${id}`, JSON.stringify(move));
});
setTimeout(() => { setTimeout(() => {
redis.del(`liveRunMoves:${id}`); redis.del(`liveRunMoves:${id}`);
}, 3000); }, 3000);
});
// Optional: keep moves ephemeral automatically after 3s
pipeline.expire(`liveRunMoves:${id}`, 3);
await pipeline.exec(); await pipeline.exec();
} }
+1
View File
@@ -11,6 +11,7 @@ export interface LiveRun {
export interface LiveRunMove { export interface LiveRunMove {
latency: number; latency: number;
cursor: number; cursor: number;
moveId: number;
changes?: { changes?: {
from: number; from: number;
to: number; to: number;