cache date on the client

This commit is contained in:
Nikita Galaiko 2023-03-27 17:15:29 +02:00
parent 615f0092a6
commit 3653ae6a31
2 changed files with 136 additions and 66 deletions

View File

@ -9,49 +9,73 @@ export type OperationInsert = { insert: [number, string] };
export type Operation = OperationDelete | OperationInsert;
export namespace Operation {
export const isDelete = (operation: Operation): operation is OperationDelete =>
'delete' in operation;
export const isDelete = (operation: Operation): operation is OperationDelete =>
'delete' in operation;
export const isInsert = (operation: Operation): operation is OperationInsert =>
'insert' in operation;
export const isInsert = (operation: Operation): operation is OperationInsert =>
'insert' in operation;
}
export type Delta = { timestampMs: number; operations: Operation[] };
export type DeltasEvent = {
deltas: Delta[];
filePath: string;
deltas: Delta[];
filePath: string;
};
export const list = (params: { projectId: string; sessionId: string; paths?: string[] }) =>
invoke<Record<string, Delta[]>>('list_deltas', params);
const cache: Record<string, Record<string, Promise<Record<string, Delta[]>>>> = {};
export const list = async (params: { projectId: string; sessionId: string; paths?: string[] }) => {
const sessionCache = cache[params.projectId] || {};
if (params.sessionId in sessionCache) {
return sessionCache[params.sessionId].then((deltas) =>
Object.fromEntries(
Object.entries(deltas).filter(([path]) =>
params.paths ? params.paths.includes(path) : true
)
)
);
}
const promise = invoke<Record<string, Delta[]>>('list_deltas', {
projectId: params.projectId,
sessionId: params.sessionId
});
sessionCache[params.sessionId] = promise;
cache[params.projectId] = sessionCache;
return promise.then((deltas) =>
Object.fromEntries(
Object.entries(deltas).filter(([path]) => (params.paths ? params.paths.includes(path) : true))
)
);
};
export const subscribe = (
params: { projectId: string; sessionId: string },
callback: (filepath: string, deltas: Delta[]) => void
params: { projectId: string; sessionId: string },
callback: (filepath: string, deltas: Delta[]) => void
) => {
log.info(`Subscribing to deltas for ${params.projectId}, ${params.sessionId}`);
return appWindow.listen<DeltasEvent>(
`project://${params.projectId}/sessions/${params.sessionId}/deltas`,
(event) => {
log.info(
`Received deltas for ${params.projectId}, ${params.sessionId}, ${event.payload.filePath}`
);
callback(event.payload.filePath, event.payload.deltas);
}
);
log.info(`Subscribing to deltas for ${params.projectId}, ${params.sessionId}`);
return appWindow.listen<DeltasEvent>(
`project://${params.projectId}/sessions/${params.sessionId}/deltas`,
(event) => {
log.info(
`Received deltas for ${params.projectId}, ${params.sessionId}, ${event.payload.filePath}`
);
callback(event.payload.filePath, event.payload.deltas);
}
);
};
export default async (params: { projectId: string; sessionId: string }) => {
const init = await list(params);
const init = await list(params);
const store = writable<Record<string, Delta[]>>(init);
subscribe(params, (filepath, newDeltas) =>
store.update((deltas) => ({
...deltas,
[filepath]: newDeltas
}))
);
const store = writable<Record<string, Delta[]>>(init);
subscribe(params, (filepath, newDeltas) =>
store.update((deltas) => ({
...deltas,
[filepath]: newDeltas
}))
);
return store as Readable<Record<string, Delta[]>>;
return store as Readable<Record<string, Delta[]>>;
};

View File

@ -4,54 +4,100 @@ import { writable, type Readable } from 'svelte/store';
import { log } from '$lib';
export type Activity = {
type: string;
timestampMs: number;
message: string;
type: string;
timestampMs: number;
message: string;
};
export namespace Session {
export const within = (session: Session | undefined, timestampMs: number) => {
if (!session) return false;
const { startTimestampMs, lastTimestampMs } = session.meta;
return startTimestampMs <= timestampMs && timestampMs <= lastTimestampMs;
};
export const within = (session: Session | undefined, timestampMs: number) => {
if (!session) return false;
const { startTimestampMs, lastTimestampMs } = session.meta;
return startTimestampMs <= timestampMs && timestampMs <= lastTimestampMs;
};
}
export type Session = {
id: string;
hash?: string;
meta: {
startTimestampMs: number;
lastTimestampMs: number;
branch?: string;
commit?: string;
};
activity: Activity[];
id: string;
hash?: string;
meta: {
startTimestampMs: number;
lastTimestampMs: number;
branch?: string;
commit?: string;
};
activity: Activity[];
};
export const listFiles = (params: { projectId: string; sessionId: string; paths?: string[] }) =>
invoke<Record<string, string>>('list_session_files', params);
const filesCache: Record<string, Record<string, Promise<Record<string, string>>>> = {};
const list = (params: { projectId: string }) => invoke<Session[]>('list_sessions', params);
export const listFiles = async (params: {
projectId: string;
sessionId: string;
paths?: string[];
}) => {
const sessionFilesCache = filesCache[params.projectId] || {};
if (params.sessionId in sessionFilesCache) {
return sessionFilesCache[params.sessionId].then((files) => {
return Object.fromEntries(
Object.entries(files).filter(([path]) =>
params.paths ? params.paths.includes(path) : true
)
);
});
}
const promise = invoke<Record<string, string>>('list_session_files', {
sessionId: params.sessionId,
projectId: params.projectId
});
sessionFilesCache[params.sessionId] = promise;
filesCache[params.projectId] = sessionFilesCache;
return promise.then((files) => {
return Object.fromEntries(
Object.entries(files).filter(([path]) => (params.paths ? params.paths.includes(path) : true))
);
});
};
const sessionsCache: Record<string, Promise<Session[]>> = {};
const list = async (params: { projectId: string; earliestTimestampMs?: number }) => {
if (params.projectId in sessionsCache) {
return sessionsCache[params.projectId].then((sessions) =>
sessions.filter((s) =>
params.earliestTimestampMs ? s.meta.startTimestampMs >= params.earliestTimestampMs : true
)
);
}
sessionsCache[params.projectId] = invoke<Session[]>('list_sessions', {
projectId: params.projectId
});
return sessionsCache[params.projectId].then((sessions) =>
sessions.filter((s) =>
params.earliestTimestampMs ? s.meta.startTimestampMs >= params.earliestTimestampMs : true
)
);
};
export default async (params: { projectId: string; earliestTimestampMs?: number }) => {
const store = writable([] as Session[]);
list(params).then((sessions) => {
store.set(sessions);
});
const store = writable([] as Session[]);
list(params).then((sessions) => {
store.set(sessions);
});
appWindow.listen<Session>(`project://${params.projectId}/sessions`, async (event) => {
log.info(`Received sessions event, projectId: ${params.projectId}`);
const session = event.payload;
store.update((sessions) => {
const index = sessions.findIndex((session) => session.id === event.payload.id);
if (index === -1) {
return [...sessions, session];
} else {
return [...sessions.slice(0, index), session, ...sessions.slice(index + 1)];
}
});
});
appWindow.listen<Session>(`project://${params.projectId}/sessions`, async (event) => {
log.info(`Received sessions event, projectId: ${params.projectId}`);
const session = event.payload;
store.update((sessions) => {
const index = sessions.findIndex((session) => session.id === event.payload.id);
if (index === -1) {
return [...sessions, session];
} else {
return [...sessions.slice(0, index), session, ...sessions.slice(index + 1)];
}
});
});
return store as Readable<Session[]>;
return store as Readable<Session[]>;
};