Fix server synchronization

This commit is contained in:
wpetit 2020-05-09 18:32:22 +02:00
parent 20d88852b1
commit acde2a7db1
1 changed files with 28 additions and 27 deletions

View File

@ -1,25 +1,28 @@
import { Project } from "../models/project";
import { usePrevious } from "./use-previous";
import { useEffect, useState } from "preact/hooks";
import { useEffect, useState, useRef } from "preact/hooks";
import { generate as diff } from "json-merge-patch";
import useDebounce from "./use-debounce";
export interface ServerSyncOptions {
projectURL: string
refreshInterval: number
syncDelay: number
}
export const defaultOptions = {
refreshInterval: 10000,
refreshInterval: 5000,
projectURL: `//${window.location.host}/api/v1/projects`,
syncDelay: 5000,
}
export function useServerSync(project: Project, applyServerUpdate: (project: Project) => void, options: ServerSyncOptions = defaultOptions) {
options = Object.assign({}, defaultOptions, options);
const [ version, setVersion ] = useState(0);
const [ serverState, setServerState ] = useState({
version: 0,
project: project,
});
console.log('server state', serverState);
const handleAPIResponse = (res: Response) => {
// If the project does not yet exist, create it
@ -27,58 +30,56 @@ export function useServerSync(project: Project, applyServerUpdate: (project: Pro
return createProject(project, options)
.then(res => res.json())
.then(result => {
setVersion(result.version);
setServerState({ version: result.version, project });
})
;
}
// In case of conflict, notify of new server version
if (res.status === 409) {
console.log("server conflict detected");
return res.json().then((result: any) => {
console.log('received response', result);
applyServerUpdate(result.project);
setVersion(result.version);
setServerState({ version: result.version, project: result.project });
});
}
// If the server version is not modified, do nothing
if (res.status === 304) {
console.log("no modification on server");
return;
}
return res.json().then((result: any) => {
console.log('received response', result);
applyServerUpdate(result.project);
setVersion(result.version);
setServerState({ version: result.version, project: result.project });
});
};
// Force refresh periodically
useEffect(() => {
const intervalId = window.setInterval(() => {
refreshProject(project, version, options).then(handleAPIResponse);
console.time("server-sync");
refreshProject(project, serverState.version, options).then(handleAPIResponse)
.then(() => {
console.timeEnd("server-sync");
});
}, options.refreshInterval);
return () => clearInterval(intervalId);
}, [version]);
}, [serverState]);
// Send delayed update
useEffect(() => {
const timeoutId =window.setTimeout(() => {
console.log('executing debounced patch');
let previousProject: Project|any = usePrevious(project);
if (!previousProject) previousProject = {};
// Trigger patch if project has changed
const patch = diff(previousProject, project);
console.log('generated patch', patch);
const timeoutId = window.setTimeout(() => {
const patch = diff(serverState.project, project);
if (!patch) return;
patchProject(project, patch, version, options).then(handleAPIResponse);
}, options.syncDelay);
patchProject(project, patch, serverState.version, options).then(handleAPIResponse);
}, 5000);
return () => clearTimeout(timeoutId);
});
}, [project, serverState]);
}
function refreshProject(project: Project, version: number, options: ServerSyncOptions): Promise<Response> {