import { useEffect, useState } from "react"; import { PacketRequestUpdate } from "../providers/ProtocolProvider/protocol/packets/packet.requestupdate"; import { APPLICATION_ARCH, APPLICATION_PLATFROM, CORE_VERSION } from "../constants"; import { PacketKernelUpdate } from "../providers/ProtocolProvider/protocol/packets/packet.kernelupdate"; import { usePacket } from "../providers/ProtocolProvider/usePacket"; import { PacketAppUpdate } from "../providers/ProtocolProvider/protocol/packets/packet.appupdate"; import { compareVersions } from "../utils/update"; import { useSender } from "../providers/ProtocolProvider/useSender"; import { useConsoleLogger } from "./useConsoleLogger"; import { useFileStorage } from "./useFileStorage"; import { APP_VERSION } from "../version"; import { useMemory } from "../providers/MemoryProvider/useMemory"; export enum UpdateStatus { IDLE, DOWNLOADING, COMPILE, READY_FOR_RESTART } export function useUpdater() { const send = useSender(); const [kernelOutdatedForNextAppUpdates, setKernelOutdatedForNextAppUpdates] = useState(false); const [kernelUpdateUrl, setKernelUpdateUrl] = useState(""); const [appUpdateUrl, setAppUpdateUrl] = useState(""); const [appActualVersion, setAppActualVersion] = useState(""); const [kernelActualVersion, setKernelActualVersion] = useState(""); const [downloadProgress, setDownloadProgress] = useMemory("dp", 0, true); const [updateStatus, setUpdateStatus] = useMemory("us", UpdateStatus.IDLE, true); const {error, info} = useConsoleLogger('useUpdater'); const {writeFile} = useFileStorage(); useEffect(() => { let packet = new PacketRequestUpdate(); packet.setAppVersion(APP_VERSION); packet.setKernelVersion(CORE_VERSION); packet.setArch(APPLICATION_ARCH); packet.setPlatform(APPLICATION_PLATFROM); send(packet); }, []); usePacket(0x0D, (packet : PacketKernelUpdate) => { let url = packet.getUrl(); let version = packet.getVersion(); setKernelActualVersion(version); setKernelUpdateUrl(url); console.info("Kernel update available: ", version, url); }, []); usePacket(0x0E, (packet : PacketAppUpdate) => { let url = packet.getUrl(); let version = packet.getVersion(); let kernelVersionRequired = packet.getKernelVersionRequired(); if(compareVersions(CORE_VERSION, kernelVersionRequired) < 0){ error("Kernel version is outdated. Cannot update app."); setKernelOutdatedForNextAppUpdates(true); return; } setAppActualVersion(version); setAppUpdateUrl(url); }, []); const downloadLastApplicationUpdate = () => { if(appUpdateUrl == ""){ return; } if(updateStatus != UpdateStatus.IDLE){ return; } setUpdateStatus(UpdateStatus.DOWNLOADING); const xhr = new XMLHttpRequest(); xhr.open("GET", appUpdateUrl, true); xhr.responseType = "blob"; xhr.onprogress = (event) => { if (event.lengthComputable) { const percentComplete = (event.loaded / event.total) * 100; setDownloadProgress(Math.round(percentComplete)); } }; xhr.onload = async () => { if (xhr.status === 200) { setUpdateStatus(UpdateStatus.COMPILE); const blob : Blob = xhr.response; let bundleName = `bundle ${appActualVersion}.zip`; await writeFile(bundleName, Buffer.from(await blob.arrayBuffer())); info("Update downloaded, starting compiler..."); await window.electron.ipcRenderer.invoke('update:installServiceUpdate', bundleName); info("Update compiled successfully."); setTimeout(() => { setUpdateStatus(UpdateStatus.READY_FOR_RESTART); }, 10000); } } xhr.onerror = () => { error("Error downloading update"); setUpdateStatus(UpdateStatus.IDLE); } xhr.send(); } const restartAppForUpdateApply = () => { if(updateStatus != UpdateStatus.READY_FOR_RESTART){ return; } window.electron.ipcRenderer.invoke('update:restartApp'); } return { appUpdateUrl, kernelUpdateUrl, appActualVersion, kernelActualVersion, kernelOutdatedForNextAppUpdates, downloadProgress, updateStatus, downloadLastApplicationUpdate, restartAppForUpdateApply } }