Skip to content
This repository has been archived by the owner on Jun 6, 2023. It is now read-only.

Commit

Permalink
feat: 支持文件修改时间对比
Browse files Browse the repository at this point in the history
  • Loading branch information
asforest committed Jan 20, 2022
1 parent 08c034f commit 037e2e6
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 108 deletions.
45 changes: 19 additions & 26 deletions src/main/Update.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import { UpdaterApplication } from "./UpdaterApplication"
import { FileObject } from "./utils/FileObject"
import { CommonMode } from "./workmode/CommonMode"
import { ExistMode } from "./workmode/ExistMode"
import { UnknownWorkModeException } from "./exceptions/UnknownWorkModeException"
import { SimpleFileObject } from "./utils/SimpleFileObject"
import { LogSys } from "./logging/LogSys"
import { httpGetFile } from "./utils/httpGetFile"
import { httpFetch } from "./utils/httpFetch"
import { countFiles } from "./utils/utility"
import { OnceMode } from "./workmode/OnceMode"
import { AbstractMode } from "./workmode/AbstractMode"
import { readFile } from "original-fs"
import { NoServerAvailableException } from "./exceptions/NoServerAvailableException"
import { HTTPResponseException } from "./exceptions/HTTPResponseException"
import { NewFile } from "./workmode/Difference"
const yaml = require('js-yaml')
const crypto = require('crypto')

Expand All @@ -29,6 +27,9 @@ export interface DownloadTask

/** 文件的预期长度 */
_length: number

/** 文件修改时间 */
mtime?: number
}

export class Update
Expand Down Expand Up @@ -97,7 +98,7 @@ export class Update
// 检查文件差异
let newFolders: string[] = []
let deleteList: string[] = []
let downloadList: { [key: string]: number } = {}
let downloadList: { [key: string]: NewFile } = {}

let e = async (workMode: AbstractMode) => {
let className = (workMode as any).constructor.name
Expand All @@ -115,10 +116,11 @@ export class Update
}

// 使用所有工作模式更新
let mtimePrioritized = this.updater.readField('modification_time_prioritized', 'boolean', true)
if(firstInfo.common_mode)
await e(new CommonMode(firstInfo.common_mode, this.workdir, remoteFiles))
await e(new CommonMode(firstInfo.common_mode, this.workdir, remoteFiles, mtimePrioritized))
if(firstInfo.once_mode)
await e(new OnceMode(firstInfo.once_mode, this.workdir, remoteFiles))
await e(new OnceMode(firstInfo.once_mode, this.workdir, remoteFiles, mtimePrioritized))

// 创建文件夹
for (const f of newFolders)
Expand All @@ -135,7 +137,7 @@ export class Update
// 触发回调函数
let newfiles = []
for (let k in downloadList)
newfiles.push([k, downloadList[k]])
newfiles.push([k, downloadList[k].len])
this.updater.dispatchEvent('updating_new_files', [...newfiles])
this.updater.dispatchEvent('updating_old_files', [...deleteList])

Expand All @@ -158,19 +160,20 @@ export class Update
this.updater.dispatchEvent('cleanup')
}

async download(dir: FileObject, downloadList: { [key: string]: number }, updateSource: string, http_no_cache: string|undefined = undefined, threads: number): Promise<void>
async download(dir: FileObject, downloadList: { [key: string]: NewFile }, updateSource: string, http_no_cache: string|undefined = undefined, threads: number): Promise<void>
{
// 建立下载任务
let dq = new Array<DownloadTask>()
for (let k in downloadList)
{
let v = downloadList[k]
let path = k
let length = v
let length = v.len
let mtime = v.mtime
let file = dir.append(path)
let url = updateSource + path

dq.push({ path: file.path, url: url, _relative_path: path, _length: length })
dq.push({ path: file.path, url: url, _relative_path: path, _length: length, mtime: mtime })
}

let workers: Array<() => Promise<void>> = []
Expand All @@ -191,35 +194,25 @@ export class Update
let url = task.url
let r_path = task._relative_path
let e_length = task._length
let mtime = task.mtime
let file = new FileObject(path)

LogSys.info('下载: '+r_path)
LogSys.info('下载: '+task)
this.updater.dispatchEvent('updating_downloading', r_path, 0, 0, e_length)

await file.makeParentDirs()
await httpGetFile(url, file, e_length, (bytesReceived: number, totalReceived: number) => {
this.updater.dispatchEvent('updating_downloading', r_path, bytesReceived, totalReceived, e_length)
}, http_no_cache)

// 更新修改时间
if (mtime != undefined)
await file.update_time(undefined, mtime)

LogSys.info("下载完毕: "+r_path)
}
}
}

getWorkMode(workmode: string): typeof CommonMode | typeof ExistMode | typeof OnceMode
{
switch(workmode)
{
case 'common':
return CommonMode
case 'exits':
return ExistMode
case 'once':
return OnceMode
default:
throw new UnknownWorkModeException('Unknown workmode: '+workmode)
}
}

async fetchInfo(config: any, http_no_cache: string|undefined = undefined): Promise<any>
{
Expand Down
6 changes: 0 additions & 6 deletions src/main/exceptions/UnknownWorkModeException.ts

This file was deleted.

25 changes: 24 additions & 1 deletion src/main/utils/FileObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export class FileObject

async length(): Promise<number>
{
if(this.isFile())
if(await this.isFile())
return (await fs.stat(this.filePath)).size
return (await this.files()).length;
}
Expand Down Expand Up @@ -179,6 +179,29 @@ export class FileObject
return hash.digest('hex')
}

async modified(): Promise<number>
{
return (await fs.stat(this.filePath)).mtimeMs
}

async created(): Promise<number>
{
return (await fs.stat(this.filePath)).ctimeMs
}

/**
* 修改文件访问时间和文件修改时间
* @param atime 文件访问时间(秒,不是毫秒),如果不修改请传undefined
* @param mtime 文件修改时间(秒,不是毫秒),如果不修改请传undefined
*/
async update_time(atime: number|undefined, mtime: number|undefined)
{
let stats = await fs.stat(this.filePath)
let at = atime ?? stats.atimeMs / 1000
let mt = mtime ?? stats.mtimeMs / 1000
await fs.utimes(this.filePath, at, mt)
}

get path(): string
{
return this.filePath.replace(/\\/g, "/")
Expand Down
18 changes: 10 additions & 8 deletions src/main/utils/SimpleFileObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ export class SimpleFileObject
length: number|undefined
hash: string|undefined
children: SimpleFileObject[]|undefined
modified: number|undefined

constructor(name: string, length?: number, hash?: string, children?: SimpleFileObject[])
constructor(name: string, length: number|undefined, hash: string|undefined, children: SimpleFileObject[]|undefined, modified: number|undefined)
{
this.name = name
this.length = length
this.hash = hash
this.children = children
this.modified = modified

let isFile = this.isFile()
let isDir = this.isDir()
Expand Down Expand Up @@ -65,14 +67,14 @@ export class SimpleFileObject
return this.getByName(file) != null;
}

static FromFile(name: string, length: number, hash: string): SimpleFileObject
static FromFile(name: string, length: number, hash: string, modified?: number): SimpleFileObject
{
return new SimpleFileObject(name, length, hash)
return new SimpleFileObject(name, length, hash, undefined, modified)
}

static FromDirectory(name: string, children: SimpleFileObject[]): SimpleFileObject
{
return new SimpleFileObject(name, undefined, undefined, children)
return new SimpleFileObject(name, undefined, undefined, children, undefined)
}

/** 不要传数组进来! */
Expand All @@ -83,9 +85,9 @@ export class SimpleFileObject
let children = [] as SimpleFileObject[]
for (const child of obj.children)
children.push(SimpleFileObject.FromObject(child))
return new SimpleFileObject(obj.name, undefined, undefined, children)
return new SimpleFileObject(obj.name, undefined, undefined, children, undefined)
} else {
return new SimpleFileObject(obj.name, obj.length, obj.hash)
return new SimpleFileObject(obj.name, obj.length, obj.hash, undefined, obj.modified)
}
}

Expand All @@ -96,9 +98,9 @@ export class SimpleFileObject
let children = [] as SimpleFileObject[]
for (const child of await file.files())
children.push(await SimpleFileObject.FromFileObject(child))
return new SimpleFileObject(file.name, undefined, undefined, children)
return new SimpleFileObject(file.name, undefined, undefined, children, undefined)
} else {
return new SimpleFileObject(file.name, await file.length(), await file.sha1())
return new SimpleFileObject(file.name, await file.length(), await file.sha1(), undefined, await file.modified())
}
}
}
9 changes: 7 additions & 2 deletions src/main/workmode/AbstractMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,20 @@ export abstract class AbstractMode
protected local: FileObject
protected remote: Array<SimpleFileObject>
protected result: Difference = new Difference()
protected modifiedTimePrioritized: boolean

/**
* @param regexes 要比较的路径
* @param local 要比较的本地文件
* @param remote 要比较的远程文件
*/
constructor(regexes: string[], local: FileObject, remote: Array<SimpleFileObject>)
constructor(regexes: string[], local: FileObject, remote: Array<SimpleFileObject>, modifiedTimePrioritized: boolean)
{
this.regexes = regexes
this.base = local
this.local = local
this.remote = remote
this.modifiedTimePrioritized = modifiedTimePrioritized
}

/**
Expand Down Expand Up @@ -57,7 +59,10 @@ export abstract class AbstractMode
await this.markAsNew(n, dir.append(n.name))
} else {
let rp = await dir.relativePath(this.base)
this.result.newFiles[rp] = node.length as number
this.result.newFiles[rp] = {
len: node.length as number,
mtime: node.modified
}
}
}

Expand Down
30 changes: 22 additions & 8 deletions src/main/workmode/CommonMode.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export class CommonMode extends AbstractMode
{
await this.findOutNews(this.local, this.remote, this.local, onScan)
LogSys.debug('-------------------')
await this.findOutOlds(this.local, this.remote, this.local, onScan)
await this.findOutOlds(this.local, this.remote, this.local, async (file: FileObject) => {})
}

/** 扫描需要下载的文件(不包括被删除的)
Expand All @@ -40,8 +40,6 @@ export class CommonMode extends AbstractMode

let flag = direct? '+' : (indirect? '-' : ' ')
LogSys.debug('N: '+flag+' '+indent+r.name)
if (onScan != null)
await onScan(l)

if(!direct && !indirect)
continue
Expand All @@ -60,12 +58,28 @@ export class CommonMode extends AbstractMode
} else { // 远程文件是一个文件
if(await l.isFile()) // 本地文件和远程文件都是文件,则对比校验
{
let lsha1 = await l.sha1()
if(lsha1 != r.hash)
// 调用回调函数
if (onScan != null)
await onScan(l)

let noModifiedWithinMTime = false

if(this.modifiedTimePrioritized)
noModifiedWithinMTime = r.modified == await l.modified() / 1000

if(!noModifiedWithinMTime)
{
LogSys.debug(' '+indent+'Hash not matched: Local: ' + lsha1 + ' Remote: ' + r.hash)
await this.markAsOld(l)
await this.markAsNew(r, l)
let lsha1 = await l.sha1()
if(lsha1 != r.hash)
{
LogSys.debug(' '+indent+'Hash not matched: Local: ' + lsha1 + ' Remote: ' + r.hash)
await this.markAsOld(l)
await this.markAsNew(r, l)
} else if (this.modifiedTimePrioritized && r.modified != undefined) {
LogSys.info('更新文件mtime: ' + await l.relativePath(base) + ' => ' + r.modified)
// 更新修改时间
await l.update_time(undefined, r.modified)
}
}
} else { // 本地对象是一个目录
await this.markAsOld(l)
Expand Down
7 changes: 6 additions & 1 deletion src/main/workmode/Difference.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,10 @@ export class Difference
public oldFolders: string[] = []
public oldFiles: string[] = []
public newFolders: string[] = []
public newFiles: { [key: string]: number } = {}
public newFiles: { [key: string]: NewFile } = {}
}

export interface NewFile {
len: number,
mtime?: number
}
56 changes: 0 additions & 56 deletions src/main/workmode/ExistMode.ts

This file was deleted.

0 comments on commit 037e2e6

Please sign in to comment.