forked from Elara6331/itd
136 lines
2.6 KiB
Go
136 lines
2.6 KiB
Go
|
package infinitime
|
||
|
|
||
|
import (
|
||
|
"archive/zip"
|
||
|
"encoding/json"
|
||
|
"errors"
|
||
|
"io"
|
||
|
"path/filepath"
|
||
|
)
|
||
|
|
||
|
type ResourceOperation int
|
||
|
|
||
|
const (
|
||
|
// ResourceUpload represents the upload phase
|
||
|
// of resource loading
|
||
|
ResourceUpload = iota
|
||
|
// ResourceRemove represents the obsolete
|
||
|
// file removal phase of resource loading
|
||
|
ResourceRemove
|
||
|
)
|
||
|
|
||
|
// resourceManifest is the structure of the resource manifest file
|
||
|
type resourceManifest struct {
|
||
|
Resources []resource `json:"resources"`
|
||
|
Obsolete []obsoleteResource `json:"obsolete_files"`
|
||
|
}
|
||
|
|
||
|
// resource represents a resource entry in the manifest
|
||
|
type resource struct {
|
||
|
Name string `json:"filename"`
|
||
|
Path string `json:"path"`
|
||
|
}
|
||
|
|
||
|
// obsoleteResource represents an obsolete file entry in the manifest
|
||
|
type obsoleteResource struct {
|
||
|
Path string `json:"path"`
|
||
|
Since string `json:"since"`
|
||
|
}
|
||
|
|
||
|
// ResourceLoadProgress contains information on the progress of
|
||
|
// a resource load
|
||
|
type ResourceLoadProgress struct {
|
||
|
Operation ResourceOperation
|
||
|
Name string
|
||
|
Total uint32
|
||
|
Transferred uint32
|
||
|
}
|
||
|
|
||
|
// LoadResources accepts the path of an InfiniTime resource archive and loads its contents to the watch's filesystem.
|
||
|
func LoadResources(archivePath string, fs *FS, progress func(ResourceLoadProgress)) error {
|
||
|
r, err := zip.OpenReader(archivePath)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer r.Close()
|
||
|
|
||
|
manifestFl, err := r.Open("resources.json")
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
var manifest resourceManifest
|
||
|
err = json.NewDecoder(manifestFl).Decode(&manifest)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
err = manifestFl.Close()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
for _, file := range manifest.Obsolete {
|
||
|
err := fs.RemoveAll(file.Path)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
progress(ResourceLoadProgress{
|
||
|
Operation: ResourceRemove,
|
||
|
Name: filepath.Base(file.Path),
|
||
|
})
|
||
|
}
|
||
|
|
||
|
for _, file := range manifest.Resources {
|
||
|
src, err := r.Open(file.Name)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
fi, err := src.Stat()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
err = fs.MkdirAll(filepath.Dir(file.Path))
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
dst, err := fs.Create(file.Path, uint32(fi.Size()))
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
dst.ProgressFunc = func(transferred, total uint32) {
|
||
|
progress(ResourceLoadProgress{
|
||
|
Name: file.Name,
|
||
|
Transferred: transferred,
|
||
|
Total: total,
|
||
|
})
|
||
|
}
|
||
|
|
||
|
_, err = io.Copy(dst, src)
|
||
|
if err != nil {
|
||
|
return errors.Join(
|
||
|
err,
|
||
|
src.Close(),
|
||
|
dst.Close(),
|
||
|
)
|
||
|
}
|
||
|
|
||
|
err = src.Close()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
err = dst.Close()
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|