feat(ludic.update): a Velopack game updating itself, a frame at a time
latest.json asked once and polled (the newest version and its notes, in a language or English); then Velopack's releases.<os>.json, the plan (the delta chain when the installed full package is on disk, no delta is missing and the chain weighs less than the full one; the newest full package otherwise, named as the feed names it), each package streamed to the packages folder with its bytes on a bar and an eased pace, its SHA-256 by Get-FileHash or shasum in a child, Update patch per delta and Update apply --waitPid. macOS keeps its packages outside the bundle and names --rootDir and --packageDir; a translocated app is not installed. Ports with the runtime as every default: UpdateWorld (platform, exe, pid, now_ms), UpdateNet (get, download, poll, text, received, free), UpdateProc (spawn, poll, free). Config: feed, app_id, version, root, packages, mac_packages, scratch. It words nothing: states, UPDATE_ERR_* codes and numbers, and UPDATE_STARTED / _STOPPED / _APPLYING facts - the game exits on the last. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
63e29f024c
commit
3514d46954
13 changed files with 1103 additions and 0 deletions
49
packages/ludic.update/chain.ludic
Normal file
49
packages/ludic.update/chain.ludic
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
# chain.ludic - the plan made: the files to fetch, in order, and the base the first delta patches
|
||||
function update__plan_clear() -> void {
|
||||
update__files = new []string
|
||||
update__sha = new []string
|
||||
update__size = new []int
|
||||
update__delta = new []bool
|
||||
update__ver = new []string
|
||||
update__full = new []string
|
||||
update__total_bytes = 0
|
||||
update__done_bytes = 0
|
||||
update__i = 0
|
||||
}
|
||||
|
||||
# the plan from a parsed feed; false when there is nothing newer than this version
|
||||
export function update_plan(feed: Val) -> bool {
|
||||
update__plan_clear()
|
||||
let as = update__assets(feed)
|
||||
let n = update__newest_full(as)
|
||||
if n < 0 or not update_newer(as[n].ver, update__conf().version) { return false }
|
||||
let newest = as[n]
|
||||
update__target = newest.ver
|
||||
let base = update_packages() + update__sep() + update__full_name(as, update__conf().version)
|
||||
let chain = update__chain(as, newest.ver)
|
||||
var chain_bytes = 0
|
||||
for i in 0 .. len(chain) { chain_bytes += chain[i].size }
|
||||
let whole = len(chain) > 0 and len(chain) == update__fulls_after(as)
|
||||
if Fs.exists(base) and whole and chain_bytes < newest.size {
|
||||
for i in 0 .. len(chain) { update__plan_add(chain[i], update__full_name(as, chain[i].ver)) }
|
||||
update__old = base
|
||||
} else {
|
||||
update__plan_add(newest, newest.file)
|
||||
update__old = ""
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
# the plan, for a panel or a test
|
||||
export function update_package_count() -> int {
|
||||
if update__files == null { return 0 }
|
||||
return len(update__files)
|
||||
}
|
||||
|
||||
export function update_plan_file(i: int) -> string { return update__files[i] }
|
||||
export function update_plan_is_delta(i: int) -> bool { return update__delta[i] }
|
||||
export function update_plan_version(i: int) -> string { return update__ver[i] }
|
||||
export function update_target() -> string { return update__target }
|
||||
export function update_total_bytes() -> int { return update__total_bytes }
|
||||
|
||||
function update__path(i: int) -> string { return update_packages() + update__sep() + update__files[i] }
|
||||
Loading…
Add table
Add a link
Reference in a new issue