Files

1 line
8.4 KiB
JavaScript
Raw Permalink Normal View History

2025-01-04 00:34:03 +01:00
import fs from"node:fs";import os from"node:os";import path from"node:path";import{spawn}from"node:child_process";import url from"node:url";import License from"./license.mjs";import Files from"../files/files.mjs";import{SOFTWARE_UPDATE_CHANNELS,TIMEOUTS}from"../../common/constants.mjs";import{fetchJsonWithTimeout}from"../../common/utils/http.mjs";import{ReleaseData}from"../../common/config.mjs";import FileDownloader from"../files/downloader.mjs";import ProgressEmitter from"../components/progress-emitter.mjs";export default class Updater{constructor(e){this.appDir=e.root,this.updateDir=path.join(e.root,"_update"),this.platform=this._getPlatform(),this.target=null,this.availability={hasUpdate:!1,couldReachWebsite:!1,slowResponse:!1,version:null,channel:null,willDisableModules:!1},this._throttlePct=null,this._updateCheckTime=0}_getPlatform(){let e=os.platform();return"win32"===e?"win":"darwin"===e?"mac":"linux"}get file(){if(!this.target?.download)throw new Error("No target download URL has yet been identified!");const e=url.parse(this.target.download).pathname;return e?path.parse(e).base:null}get localDest(){return`${this.updateDir}/${this.file}`}async check({updateChannel:e="stable",forceUpdate:t}={}){if(t=["true",!0].includes(t),this.target=null,this.availability.version=null,this.availability.channel=null,this.availability.couldReachWebsite=!0,!((e={alpha:"prototype",beta:"testing",release:"stable"}[e]||e)in SOFTWARE_UPDATE_CHANNELS))throw new Error(`${e} is not a valid software update channel to check.`);e!==config.options.updateChannel&&(config.options.updateSource({updateChannel:e}),config.options.save());const o=await this.#e(),s=!0===config.options.telemetry,i=Date.now();let a;try{a=await this.#t(e,s?o:null)}catch(e){return 403!==e.code&&(logger.warn("The Foundry Virtual Tabletop website could not be reached to check for core software updates"),this.availability.couldReachWebsite=!1),null}finally{this.availability.slowResponse=Date.now()-i>2e3}if(globalThis.game.saveNews(a.news,a.featured_content),globalThis.release.updateSource({maxGeneration:a.max_generation,maxStableGeneration:a.max_stable_generation}),!1===a.valid_key)throw config.license.expire(),new Error("SETUP.UpdateLicenseInvalid");if(config.options.noupdate)throw new Error("SETUP.UpdateNoUpdateMode");if("error"===a.status){const e=new Error(a.message);if(e.messageCode=a.message_code,!("latest_release"in a))throw e}const r=new ReleaseData(a.latest_release);this.availability.hasUpdate=r.isNewer(config.release);const n=t||this.availability.hasUpdate;return n&&(logger.info(`Core software ${r.channel} update ${r.version} is available!`),this.target=r,this.availability.version=r.version,this.availability.channel=r.channel),this.availability.willDisableModules=n&&r.isGenerationalChange(config.release),this.target}async#t(e,t){return fetchJsonWithTimeout(License.SOFTWARE_UPDATE_URL,{headers:{"Content-Type":"application/json",Authorization:config.license.authorizationHeader},method:"POST",body:JSON.stringify({diagnostics:t,updateChannel:e,license:config.license.data,versions:{foundry:config.release.version,node:process.versions.node,electron:process.versions.electron}})},{timeoutMs:TIMEOUTS.PACKAGE_REPOSITORY})}update(){if(config.options.noupdate)throw new Error("You are not allowed to update this instance of Foundry Virtual Tabletop because it was launched in --noupdate mode.");return new Promise((async(e,t)=>{const{ACTIONS:o}=CONST.SETUP_PACKAGE_PROGRESS;this.progress=new ProgressEmitter(o.UPDATE_DOWNLOAD,null,1,{id:o.UPDATE_CORE,type:"core",name:"FoundryVTT"},{operationName:"Core Software Update"});try{await this.download({onFetched:()=>e({})});await this.install()&&this.restart()}catch(e){this.progress.error(e),t(e)}}))}async download({onFetched:e}={}){if(!this.target)throw new Error("No update target has been identified");try{fs.accessSync(paths.root,fs.constants.W_OK),await fs.promises.rm(this.updateDir,{force:!0,recursive:!0}),await fs.promises.mkdir(this.updateDir)}catch(e){throw console.error(e),new Error("You do not have permission to write files in you