Skip to content

Commit

Permalink
fix(SW): use idb instead of electric
Browse files Browse the repository at this point in the history
  • Loading branch information
ledouxm committed Oct 8, 2024
1 parent a3dd9fb commit d62ee30
Show file tree
Hide file tree
Showing 8 changed files with 85 additions and 131 deletions.
1 change: 1 addition & 0 deletions packages/backend/src/routes/uploadRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ export const uploadPlugin: FastifyPluginAsyncTypebox = async (fastify, _) => {
publicRead: true,
});

// await db.pictures.create({ data: { id, url, reportId, createdAt: new Date() } });
await db.pictures.update({ where: { id }, data: { url } });

reply.send();
Expand Down
4 changes: 3 additions & 1 deletion packages/frontend/src/envVars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ const envSchema = z.object({
VITE_ELECTRIC_URL: z.string(),
});

export const ENV = envSchema.parse(isDev ? import.meta.env : window.ENV);
const isBrowser = typeof window === "undefined";

export const ENV = envSchema.parse(isDev || isBrowser ? import.meta.env : window.ENV);
declare global {
interface Window {
ENV: typeof ENV;
Expand Down
15 changes: 5 additions & 10 deletions packages/frontend/src/features/InfoForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ import { useUser } from "../contexts/AuthContext";
import { db } from "../db";
import { useIsFormDisabled } from "./DisabledContext";
import { ServiceInstructeurSelect } from "./ServiceInstructeurSelect";
import { getPicturesStore, syncImages } from "./idb";
import { getPicturesStore, getToUploadStore, syncImages } from "./idb";

export const InfoForm = () => {
const form = useFormContext<Report>();
Expand Down Expand Up @@ -212,22 +212,17 @@ const UploadImage = ({ reportId }: { reportId: string }) => {

const onChange = async (e: ChangeEvent<HTMLInputElement>) => {
const picturesStore = getPicturesStore();
const toUploadStore = getToUploadStore();

const id = v4();
const file = e.target.files?.[0];
if (!file) return;

const buffer = await getArrayBufferFromBlob(file);
set(id, buffer, picturesStore);

await db.pictures.create({
data: {
id,
reportId,
createdAt: new Date(),
},
});
await set(id, buffer, picturesStore);
await set(id, reportId, toUploadStore);

await db.pictures.create({ data: { id, reportId, createdAt: new Date() } });
syncImages();
};

Expand Down
1 change: 1 addition & 0 deletions packages/frontend/src/features/idb.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { createStore } from "idb-keyval";

export const getPicturesStore = () => createStore("toSync", "images");
export const getToUploadStore = () => createStore("toUpload", "images");

export const syncImages = async () => {
console.log("sync");
Expand Down
1 change: 0 additions & 1 deletion packages/frontend/src/service-worker/electric.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ export const initElectric = async () => {
url: ENV.VITE_ELECTRIC_URL,
} satisfies ElectricConfig;
const conn = await ElectricDatabase.init("crvif.db", "/");

const electric = await electrify(conn, schema, config);
const db = electric.db;

Expand Down
75 changes: 32 additions & 43 deletions packages/frontend/src/service-worker/sw.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import { precacheAndRoute } from "workbox-precaching";
import { api, getTokenFromIdb } from "../api";
import { getPicturesStore } from "../features/idb";
import { del, get, keys } from "idb-keyval";
import { initElectric } from "./electric";
import { Pictures } from "@cr-vif/electric-client/frontend";
import { getPicturesStore, getToUploadStore } from "../features/idb";
import { get, keys, del } from "idb-keyval";

declare let self: ServiceWorkerGlobalScope;

Expand All @@ -15,29 +13,16 @@ self.addEventListener("sync", async (event: any) => {
event.waitUntil(syncMissingPictures());
});

const ref = {
db: null as Awaited<ReturnType<typeof initElectric>>["db"] | null,
};

const getDb = async () => {
if (!ref.db) {
ref.db = (await initElectric()).db;
}

return ref.db;
};

const syncMissingPictures = async (retries = 3) => {
try {
const token = await getTokenFromIdb();
if (!token) return void console.log("no token");

const db = await getDb();
const pictures = await db.pictures.findMany({ where: { url: null } });
const pictureIds = await keys(getToUploadStore());

console.log("syncing", pictures.length, "missing pictures");
console.log("syncing", pictureIds.length, "missing pictures");

await syncPicturesById(pictures, token);
await syncPicturesById(pictureIds as string[], token);
} catch (e) {
if (retries > 0) {
console.log("retrying in 5s", e);
Expand All @@ -47,53 +32,57 @@ const syncMissingPictures = async (retries = 3) => {

throw e;
}

// await cleanupOldCaches();
};

const syncPicturesById = async (ids: Pictures[], token: string) => {
const syncPicturesById = async (ids: string[], token: string) => {
const store = getPicturesStore();
const toUploadStore = getToUploadStore();

const localIds = await keys(store);
const missingIds = ids.filter((pic) => localIds.includes(pic.id));
const missingIds = ids.filter((picId) => localIds.includes(picId));

for (const picId of missingIds) {
const reportId = await get(picId, toUploadStore);

for (const pic of missingIds) {
console.log("syncing picture", pic);
const buffer = await get(pic.id, store);
console.log("syncing picture", picId);
const buffer = await get(picId, store);
if (!buffer) {
console.log("missing buffer for id", pic.id);
console.log("missing buffer for id", picId);
continue;
}

const formData = new FormData();
formData.append("file", new Blob([buffer]), "file");
formData.append("reportId", pic.reportId!);
formData.append("pictureId", pic.id);
formData.append("reportId", reportId);
formData.append("pictureId", picId);

await api.post("/api/upload/image", {
body: formData,
query: { reportId: pic.reportId, id: pic.id },
query: { reportId: reportId, id: picId },
header: { Authorization: `Bearer ${token}` },
} as any);

await del(picId, toUploadStore);

console.log("done");
}
};

const cleanupOldCaches = async () => {
const db = await getDb();
// const cleanupOldCaches = async () => {
// const db = await getDb();

const keysToKeep = await db.pictures.findMany({ where: { url: null } });
// const keysToKeep = await db.pictures.findMany({ where: { url: null } });

const store = getPicturesStore();
const localIds = await keys(store);
// const store = getPicturesStore();
// const localIds = await keys(store);

const keysToDelete = localIds.filter((id) => !keysToKeep.some((pic) => pic.id === id));
// const keysToDelete = localIds.filter((id) => !keysToKeep.some((pic) => pic.id === id));

console.log("deleting", keysToDelete.length, "old pictures");
// console.log("deleting", keysToDelete.length, "old pictures");

for (const key of keysToDelete) {
await del(key, store);
}
// for (const key of keysToDelete) {
// await del(key, store);
// }

console.log("done");
};
// console.log("done");
// };
3 changes: 3 additions & 0 deletions packages/frontend/vite.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { TanStackRouterVite } from "@tanstack/router-vite-plugin";
import wasm from "vite-plugin-wasm";
import { VitePWA } from "vite-plugin-pwa";
import topLevelAwait from "vite-plugin-top-level-await";

// https://vitejs.dev/config/
export default defineConfig({
plugins: [
Expand All @@ -12,6 +13,7 @@ export default defineConfig({
wasm(),
VitePWA({
devOptions: { enabled: true, type: "module" },

registerType: "autoUpdate",
manifest: {
id: "gouv.beta.compte-rendu-vif",
Expand All @@ -25,6 +27,7 @@ export default defineConfig({
injectManifest: {
maximumFileSizeToCacheInBytes: 2097152 * 3,
globPatterns: ["**/*.{svg,woff2,js,wasm,css,html,png}"],
rollupFormat: "es",
},
includeAssets: ["**/*.{svg,woff2,wasm}"],
strategies: "injectManifest",
Expand Down
Loading

0 comments on commit d62ee30

Please sign in to comment.