forked from Arsen6331/infinitime
parent
b5d345cdec
commit
3e9957d419
@ -0,0 +1,180 @@
|
||||
package infinitime
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"go.arsenm.dev/infinitime/blefs"
|
||||
)
|
||||
|
||||
// ResourceOperation represents an operation performed during
|
||||
// resource loading
|
||||
type ResourceOperation uint8
|
||||
|
||||
const (
|
||||
// ResourceOperationUpload represents the upload phase
|
||||
// of resource loading
|
||||
ResourceOperationUpload = iota
|
||||
// ResourceOperationRemoveObsolete represents the obsolete
|
||||
// file removal phase of resource loading
|
||||
ResourceOperationRemoveObsolete
|
||||
)
|
||||
|
||||
// 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 int64
|
||||
Sent int64
|
||||
Err error
|
||||
}
|
||||
|
||||
// LoadResources accepts a resources zip file and a BLE FS.
|
||||
// It loads the resources from the zip onto the FS.
|
||||
func LoadResources(file *os.File, fs *blefs.FS) (<-chan ResourceLoadProgress, error) {
|
||||
out := make(chan ResourceLoadProgress, 10)
|
||||
|
||||
fi, err := file.Stat()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
r, err := zip.NewReader(file, fi.Size())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
m, err := r.Open("resources.json")
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var manifest ResourceManifest
|
||||
err = json.NewDecoder(m).Decode(&manifest)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
go func() {
|
||||
defer close(out)
|
||||
|
||||
for _, file := range manifest.Obsolete {
|
||||
name := filepath.Base(file.Path)
|
||||
|
||||
err := fs.RemoveAll(file.Path)
|
||||
if err != nil {
|
||||
out <- ResourceLoadProgress{
|
||||
Name: name,
|
||||
Operation: ResourceOperationRemoveObsolete,
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
out <- ResourceLoadProgress{
|
||||
Name: name,
|
||||
Operation: ResourceOperationRemoveObsolete,
|
||||
}
|
||||
}
|
||||
|
||||
for _, file := range manifest.Resources {
|
||||
src, err := r.Open(file.Name)
|
||||
if err != nil {
|
||||
out <- ResourceLoadProgress{
|
||||
Name: file.Name,
|
||||
Operation: ResourceOperationUpload,
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
srcFi, err := src.Stat()
|
||||
if err != nil {
|
||||
out <- ResourceLoadProgress{
|
||||
Name: file.Name,
|
||||
Operation: ResourceOperationUpload,
|
||||
Total: srcFi.Size(),
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
err = fs.MkdirAll(filepath.Dir(file.Path))
|
||||
if err != nil {
|
||||
out <- ResourceLoadProgress{
|
||||
Name: file.Name,
|
||||
Operation: ResourceOperationUpload,
|
||||
Total: srcFi.Size(),
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
dst, err := fs.Create(file.Path, uint32(srcFi.Size()))
|
||||
if err != nil {
|
||||
out <- ResourceLoadProgress{
|
||||
Name: file.Name,
|
||||
Operation: ResourceOperationUpload,
|
||||
Total: srcFi.Size(),
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
progCh := dst.Progress()
|
||||
go func() {
|
||||
for sent := range progCh {
|
||||
out <- ResourceLoadProgress{
|
||||
Name: file.Name,
|
||||
Operation: ResourceOperationUpload,
|
||||
Total: srcFi.Size(),
|
||||
Sent: int64(sent),
|
||||
}
|
||||
|
||||
if sent == uint32(srcFi.Size()) {
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
n, err := io.Copy(dst, src)
|
||||
if err != nil {
|
||||
out <- ResourceLoadProgress{
|
||||
Name: file.Name,
|
||||
Operation: ResourceOperationUpload,
|
||||
Total: srcFi.Size(),
|
||||
Sent: n,
|
||||
Err: err,
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
src.Close()
|
||||
dst.Close()
|
||||
}
|
||||
}()
|
||||
|
||||
return out, nil
|
||||
}
|
Loading…
Reference in new issue