diff --git a/cutpaste.go b/cutpaste.go index f99b076d..e2c004e3 100644 --- a/cutpaste.go +++ b/cutpaste.go @@ -168,6 +168,11 @@ func edtrenameAPI(w http.ResponseWriter, r *http.Request, auth *Profile) { Dst string `json:"dst" yaml:"dst" xml:"dst"` Ovw bool `json:"overwrite,omitempty" yaml:"overwrite,omitempty" xml:"overwrite,omitempty,attr"` } + var ret struct { + XMLName xml.Name `json:"-" yaml:"-" xml:"ret"` + + Prop FileKit `json:"prop" yaml:"prop" xml:"prop"` + } // get arguments if err = ParseBody(w, r, &arg); err != nil { @@ -234,9 +239,9 @@ func edtrenameAPI(w http.ResponseWriter, r *http.Request, auth *Profile) { WriteError500(w, r, err, AECedtrenstat) return } - var prop = MakeProp(session, dstpath, fi) + ret.Prop.Setup(session, dstpath, fi) - WriteOK(w, r, prop) + WriteOK(w, r, &ret) } // APIHANDLER diff --git a/fileprop.go b/fileprop.go index 9035bb4b..64994aec 100644 --- a/fileprop.go +++ b/fileprop.go @@ -5,36 +5,6 @@ import ( "path" ) -func GetPropSize(p any) (int64, bool) { - switch v := p.(type) { - case *FileKit: - return v.Size, true - case *DirKit: - return v.Size, true - case *ExifKit: - return v.Size, true - case *TagKit: - return v.Size, true - default: - return 0, false - } -} - -func GetPropType(p any) (FT_t, bool) { - switch v := p.(type) { - case *FileKit: - return v.Type, true - case *DirKit: - return v.Type, true - case *ExifKit: - return v.Type, true - case *TagKit: - return v.Type, true - default: - return 0, false - } -} - // FileProp is common file properties chunk. type FileProp struct { Name string `xorm:"'name'" json:"name" yaml:"name" xml:"name"` @@ -53,7 +23,8 @@ func (fp *FileProp) Setup(fi fs.FileInfo) { // PuidProp encapsulated path unique ID value for some properties kit. type PuidProp struct { - PUID Puid_t `xorm:"'puid'" json:"puid" yaml:"puid" xml:"puid"` + PUID Puid_t `xorm:"'puid'" json:"puid" yaml:"puid" xml:"puid"` + Shared bool `xorm:"'shared'" json:"shared" yaml:"shared" xml:"shared"` } func (pp *PuidProp) Setup(session *Session, syspath string) { @@ -146,27 +117,4 @@ func (dk *DirKit) Setup(session *Session, syspath string, fi fs.FileInfo) { dk.DirProp, _ = DirStoreGet(session, dk.PUID) } -// MakeProp is file properties factory. -func MakeProp(session *Session, syspath string, fi fs.FileInfo) any { - if fi.IsDir() { - var dk DirKit - dk.Setup(session, syspath, fi) - return &dk - } - var ext = GetFileExt(syspath) - if IsTypeID3(ext) { - var tk TagKit - tk.Setup(session, syspath, fi) - return &tk - } else if IsTypeEXIF(ext) { - var ek ExifKit - ek.Setup(session, syspath, fi) - return &ek - } else { - var fk FileKit - fk.Setup(session, syspath, fi) - return &fk - } -} - // The End. diff --git a/folder.go b/folder.go index 57942323..6e477ab9 100644 --- a/folder.go +++ b/folder.go @@ -168,12 +168,13 @@ func folderAPI(w http.ResponseWriter, r *http.Request) { WriteError500(w, r, err, AECfolderhome) return } - go func() { + go SqlSession(func(session *Session) (res any, err error) { DirStoreSet(session, &DirStore{ Puid: puid, Prop: lstp, }) - }() + return + }) case PUIDdrives: if ret.List, err = prf.ScanRoots(session); err != nil { WriteError500(w, r, err, AECfolderdrives) diff --git a/frontend/devmode/cards.js b/frontend/devmode/cards.js index f15d55c1..0eb5ec53 100644 --- a/frontend/devmode/cards.js +++ b/frontend/devmode/cards.js @@ -1781,7 +1781,7 @@ const VueMapCard = { uncached.push(tp) } } - this.addmarkers(gpslist); + self.addmarkers(gpslist); // check cached state loop if (!uncached.length) { return; @@ -1800,7 +1800,7 @@ const VueMapCard = { } } } - this.addmarkers(gpslist); + self.addmarkers(gpslist); return; } } else { diff --git a/frontend/devmode/devmode.js b/frontend/devmode/devmode.js index abf957cd..06affc92 100644 --- a/frontend/devmode/devmode.js +++ b/frontend/devmode/devmode.js @@ -3,7 +3,7 @@ // This file is included only for developer mode linkage const buildvers = "0.9.0"; -const builddate = "2022.12.11"; +const builddate = "2023.01.04"; console.info("version: %s, builton: %s", buildvers, builddate); console.info("starts in developer mode"); diff --git a/frontend/devmode/mainpage.js b/frontend/devmode/mainpage.js index 9aa5f97c..cb685b6c 100644 --- a/frontend/devmode/mainpage.js +++ b/frontend/devmode/mainpage.js @@ -449,8 +449,6 @@ const VueMainApp = { readonly: true, // can't modify content of folder selfile: null, // current selected item - shared: [], // list of shared items - delfile: null, // file to delete delensured: false, // deletion request @@ -743,7 +741,6 @@ const VueMainApp = { // update folder settings this.flist = newlist ?? []; - this.updateshared(); // update page data this.curscan = new Date(Date.now()); @@ -753,18 +750,6 @@ const VueMainApp = { this.$refs.page.scrollTop = 0; }, - async fetchshared() { - const response = await fetchajaxauth("POST", "/api/res/folder", { - aid: this.aid, path: PUID.shares - }); - traceajax(response); - if (!response.ok) { - throw new HttpError(response.status, response.data); - } - this.shared = response.data.list ?? []; - this.updateshared(); - }, - async fetchshareadd(file) { const response = await fetchajaxauth("POST", "/api/share/add", { aid: this.aid, @@ -775,7 +760,6 @@ const VueMainApp = { throw new HttpError(response.status, response.data); } file.shared = true; // Vue.set - this.shared.push(file); }, async fetchsharedel(file) { @@ -791,26 +775,6 @@ const VueMainApp = { // update folder settings if (response.data.deleted) { // on ok file.shared = false; // Vue.set - for (let i = 0; i < this.shared.length;) { - if (this.shared[i].puid === file.puid) { - this.shared.splice(i, 1); - } else { - i++; - } - } - } - }, - - updateshared() { - for (const file of this.flist) { - let sf = false; - for (const shr of this.shared) { - if (shr.puid === file.puid) { - sf = true; - break; - } - } - file.shared = sf; // Vue.set } }, @@ -937,9 +901,6 @@ const VueMainApp = { eventHub.emit('ajax', +1); try { await this.fetchfolder({ aid: this.aid, path: this.curpuid ?? this.curpath }); - if (this.isadmin && this.curpuid !== PUID.shares) { - await this.fetchshared(); // get shares - } } catch (e) { ajaxfail(e); } finally { @@ -1204,9 +1165,6 @@ const VueMainApp = { // open route and push history step await this.fetchfolder(hist); - if (this.isadmin && hist.puid !== PUID.shares) { - await this.fetchshared(); // get shares - } this.pushhist(hist); } catch (e) { ajaxfail(e); diff --git a/frontend/devmode/relmode.js b/frontend/devmode/relmode.js index 501ec18e..35d02fa5 100644 --- a/frontend/devmode/relmode.js +++ b/frontend/devmode/relmode.js @@ -3,7 +3,7 @@ // This file is included for release mode linkage const buildvers = "0.8.4"; -const builddate = "2022.11.26"; +const builddate = "2023.01.04"; const devmode = false; const traceajax = () => undefined; diff --git a/gps.go b/gps.go index bf20d5b3..c83d6edc 100644 --- a/gps.go +++ b/gps.go @@ -5,8 +5,6 @@ import ( "io/fs" "math" "net/http" - - "golang.org/x/sync/errgroup" ) // Haversine uses formula to calculate the great-circle distance between @@ -194,14 +192,8 @@ func gpsscanAPI(w http.ResponseWriter, r *http.Request) { return } - var wg errgroup.Group var session = xormStorage.NewSession() - defer func() { - go func() { - wg.Wait() - session.Close() - }() - }() + defer session.Close() var prf *Profile if prf = prflist.ByID(arg.AID); prf == nil { @@ -213,6 +205,7 @@ func gpsscanAPI(w http.ResponseWriter, r *http.Request) { return } + var ests []ExifStore for _, puid := range arg.List { var puid = puid // localize if syspath, ok := PathStorePath(session, puid); ok { @@ -225,33 +218,50 @@ func gpsscanAPI(w http.ResponseWriter, r *http.Request) { ret.List = append(ret.List, gst) } else { // check memory cache - if ok = exifcache.Has(puid); ok { + if exifcache.Has(puid) { continue // there are tags without GPS } - // try to extract from file - var ep ExifProp - if err := ep.Extract(syspath); err != nil { - continue - } - if ok = !ep.IsZero(); ok { - wg.Go(func() (err error) { - return ExifStoreSet(session, &ExifStore{ // update database - Puid: puid, - Prop: ep, - }) - }) + // try to get from database + var est ExifStore + est.Puid = puid + if ok, _ = session.Get(&est); ok { // skip errors + exifcache.Push(puid, est.Prop) // update cache + if est.Prop.IsZero() { + continue + } + } else { + // try to extract from file + if err := est.Prop.Extract(syspath); err != nil { + continue + } + if est.Prop.IsZero() { + continue + } + // set to memory cache + exifcache.Push(puid, est.Prop) + // prepare to set to database + ests = append(ests, est) } - if ep.Latitude != 0 || ep.Longitude != 0 { + if est.Prop.Latitude != 0 || est.Prop.Longitude != 0 { var gst Store[GpsInfo] gst.Puid = puid - gst.Prop.FromProp(&ep) + gst.Prop.FromProp(&est.Prop) ret.List = append(ret.List, gst) + // set to GPS cache + gpscache.Store(puid, gst.Prop) } } } } } + if len(ests) > 0 { + go SqlSession(func(session *Session) (res any, err error) { + _, err = session.Insert(&ests) + return + }) + } + WriteOK(w, r, &ret) } diff --git a/handlers.go b/handlers.go index 74db8c02..3eef59fa 100644 --- a/handlers.go +++ b/handlers.go @@ -586,9 +586,9 @@ func propAPI(w http.ResponseWriter, r *http.Request) { var ret struct { XMLName xml.Name `json:"-" yaml:"-" xml:"ret"` - Path string `json:"path" yaml:"path" xml:"path"` - Name string `json:"shrname" yaml:"shrname" xml:"shrname"` - Prop any `json:"prop" yaml:"prop" xml:"prop"` + Path string `json:"path" yaml:"path" xml:"path"` + Name string `json:"shrname" yaml:"shrname" xml:"shrname"` + Prop FileKit `json:"prop" yaml:"prop" xml:"prop"` } // get arguments @@ -638,7 +638,8 @@ func propAPI(w http.ResponseWriter, r *http.Request) { WriteError500(w, r, err, AECpropbadstat) return } - ret.Prop = MakeProp(session, syspath, fi) + ret.Prop.Setup(session, syspath, fi) + ret.Prop.Shared = prf.IsShared(syspath) WriteOK(w, r, &ret) } @@ -702,6 +703,7 @@ func ispathAPI(w http.ResponseWriter, r *http.Request, auth *Profile) { var fk FileKit fk.Setup(session, syspath, fi) + fk.Shared = prf.IsShared(syspath) WriteOK(w, r, &fk) } @@ -864,6 +866,7 @@ func drvaddAPI(w http.ResponseWriter, r *http.Request, auth *Profile) { var fk FileKit fk.PUID = puid + fk.Shared = prf.IsShared(syspath) fk.Name = path.Base(syspath) fk.Type = FTdrv fk.Size = fi.Size() diff --git a/profile.go b/profile.go index 2ffdf095..ae65a824 100644 --- a/profile.go +++ b/profile.go @@ -182,36 +182,35 @@ func (prf *Profile) GetPathGroup(fpath string, fi fs.FileInfo) (grp FG_t) { // IsHidden do check up that file path is in hidden list. func (prf *Profile) IsHidden(fpath string) bool { var matched bool - var kpath = strings.ToLower(ToSlash(fpath)) + var kpath = strings.ToLower(fpath) prf.mux.RLock() defer prf.mux.RUnlock() var name = path.Base(kpath) -patterns: for _, pattern := range prf.Hidden { if strings.HasPrefix(pattern, "**/") { if matched, _ = path.Match(pattern[3:], name); matched { - break + return true } } else if strings.HasPrefix(pattern, "?:/") { for _, root := range prf.Roots { if root[len(root)-1] != '/' { root += "/" } - if strings.HasPrefix(kpath, root) { + if strings.HasPrefix(kpath, strings.ToLower(root)) { if matched, _ = path.Match(pattern[3:], kpath[len(root):]); matched { - break patterns + return true } } } } else { if matched, _ = path.Match(pattern, kpath); matched { - break + return true } } } - return matched + return false } // IsRoot checks whether file path is disk root path. @@ -227,15 +226,11 @@ func (prf *Profile) IsRoot(syspath string) bool { } // IsShared checks that syspath is become in any share. -func (prf *Profile) IsShared(syspath string) bool { +func (prf *Profile) IsShared(syspath string) (ok bool) { prf.mux.RLock() - defer prf.mux.RUnlock() - for _, fpath := range prf.Shares { - if fpath == syspath { - return true - } - } - return false + _, ok = prf.sharepuid[syspath] + prf.mux.RUnlock() + return } // RootIndex returns index of given path in roots list or -1 if not found. diff --git a/scandir.go b/scandir.go index b28151e9..bad0f538 100644 --- a/scandir.go +++ b/scandir.go @@ -116,6 +116,7 @@ func ScanFileInfoList(prf *Profile, session *Session, vfiles []fs.FileInfo, vpat if dp, ok := dpmap[puid]; ok || fp.Type != FTfile { var dk DirKit dk.PUID = puid + dk.Shared = prf.IsShared(fpath) dk.FileProp = fp dk.DirProp = dp if vfiles[i] == nil && dk.Type != FTctgr { @@ -125,6 +126,7 @@ func ScanFileInfoList(prf *Profile, session *Session, vfiles []fs.FileInfo, vpat } else { var fk FileKit fk.PUID = puid + fk.Shared = prf.IsShared(fpath) fk.FileProp = fp if tp, ok := tilecache.Peek(puid); ok { fk.TileProp = *tp