/** * remote 模块用来处理远程仓库相关事务 */ const path = require("path") const fs = require("fs") const JSON5 = require('json5') const { pipeline, Transform} = require("stream/promises"); module.exports = class Remote { constructor() { // this.__init() this.func_publish = require("./publish") this.func_install = require("./install") } async init() { this.webdav = await import("webdav"); const uConfig = await $context.get("uConfig"); if ( uConfig.get("remoteServer") ){ let server = uConfig.get("remoteServer"); $logger.info("server " + server) if ( server.startsWith("webdav") ) { server = "http" + server.substring(6) } if ( uConfig.get("remoteAuth") ) { let up = uConfig.get("remoteAuth"); $logger.info("remoteAuth " + up) up = up.split(":", 2) this.client = this.webdav.createClient( server, { username: up[0], password: up[1] } ); } else { this.client = this.webdav.createClient( server ); } } } async check() { if ( ! this.webdav ) { $logger.info("webdav unable") return false } if ( ! this.client ) { $logger.info("client unable") return false } try { // Get directory contents const directoryItems = await this.client.getDirectoryContents("/"); $logger.info("directoryItems", directoryItems) // 是否包含 index.json ? // 不包含尝试创建 // 包含了尝试下载 const indexJsonFile = this.getIndexJson( directoryItems ); $logger.info("indexJsonFile", indexJsonFile) if ( indexJsonFile ) { // 包含了尝试下载 // 下载有缓存 this.download(indexJsonFile) $logger.info("download index") } else { // 不包含尝试创建 await this.affireRemoteStore() $logger.info("affireRemoteStore") } return true }catch ( e ) { $logger.error("remote check 过程中出错", e) console.error(e) return false } } /** * 先对比时间和长度,有不同才会真正下载,否则使用本地缓存。 * 本地缓存路径即本地仓库路径 * @param rFile */ download(rFile){ const lFilePath = path.resolve($sConfig.getLocalStorePath(), rFile.filename); if ( fs.existsSync( lFilePath ) ) { const lFileInfo = fs.statSync(lFilePath); if ( lFileInfo.size === rFile.length && lFileInfo.mtime === rFile.lastmod ) { // 使用缓存 $logger.debug("use cache") return true } } // 下载并覆盖 // 不知道是同步还是异步 this.wDownload( rFile.filename, lFilePath ); } async affireRemoteStore(){ // Get directory contents const directoryItems = await this.client.getDirectoryContents("/"); // 是否包含 index.json ? // 不包含尝试创建 // 包含了尝试下载 const indexJsonFile = this.getIndexJson( directoryItems ); if ( ! indexJsonFile ) { // 创建 index await this.client.putFileContents("/index.json", JSON5.stringify({ modules : [], tmpls : [], lists : [] }, null, 4) , { overwrite: false }); } const modulesFolder = this.getFileInfoByName(directoryItems, "modules") if ( ! modulesFolder ) { // 创建文件夹 await this.client.createDirectory("/modules"); } const tmplsFolder = this.getFileInfoByName(directoryItems, "tmpls") if ( ! tmplsFolder ) { // 创建文件夹 await this.client.createDirectory("/tmpls"); } const listsFolder = this.getFileInfoByName(directoryItems, "lists") if ( ! listsFolder ) { // 创建文件夹 await this.client.createDirectory("/lists"); } } getIndexJson(items){ return this.getFileInfoByName( items, "index.json" ); } getFileInfoByName(items, name){ if ( ! items || items.length < 1 ) { return false; } for ( let item of items ) { if ( item.basename === name ) { return item; } } return false; } async publish(localFile, remotePath){ return await this.func_publish( this , localFile, remotePath ) } async install(id){ return this.func_install( this, id ) } async wUpload(from, to, debug){ const totalSize = fs.statSync(from).size; debug ? console.log("totalSize", totalSize) : null const rs = fs.createReadStream( from ); let wSize = 0; let rSize = 0; rs.on("data", (r)=>{ rSize += r.length; debug ? console.log("r", rSize * 100 / totalSize + "%") : null }) const ws = this.client.createWriteStream(to) ws.on("data", (r)=>{ wSize += r.length; debug ? console.log("w ", wSize * 100 / totalSize + "%") : null }) await pipeline( rs, ws); debug ? console.log("finish") : null } async wDownload(from, to){ $logger.info("download", from, to ) const stat = await this.client.stat(from); const totalSize = stat.size; let wSize = 0; let rSize = 0; const rs = this.client.createReadStream(from); rs.on("data", (r)=>{ rSize += r.length; // console.log("r", rSize * 100 / totalSize) }) const ws = fs.createWriteStream(to); ws.on("data", (r)=>{ wSize += r.length; // console.log("w", wSize * 100 / totalSize) }) return await pipeline( rs, ws ) } async wMkdir(folder){ const folderfather = path.dirname( folder ); if ( ! await this.client.exists( folderfather ) ) { // await remote.client.createDirectory( folderfather ) await this.wMkdir( folderfather ) } if ( await this.client.exists( folder ) ) { return } else { await this.client.createDirectory( folder ) } } async wGetModuleInfo(id){ let meta = await this.client.getFileContents("/modules/" + id + "/meta.json", { format: "text" }); let metaJson = JSON5.parse( meta ); return metaJson } }