Merge branch 'pr-1094'

* pr-1094:
  GUI tweaks for last file synced
  Display last received file and time (fixes #292, fixes #801)
This commit is contained in:
Jakob Borg
2014-12-12 14:25:12 +01:00
9 changed files with 206 additions and 10 deletions

File diff suppressed because one or more lines are too long

View File

@@ -98,6 +98,7 @@ type Model struct {
deviceStatRefs map[protocol.DeviceID]*stats.DeviceStatisticsReference // deviceID -> statsRef
folderIgnores map[string]*ignore.Matcher // folder -> matcher object
folderRunners map[string]service // folder -> puller or scanner
folderStatRefs map[string]*stats.FolderStatisticsReference // folder -> statsRef
fmut sync.RWMutex // protects the above
folderState map[string]folderState // folder -> state
@@ -137,6 +138,7 @@ func NewModel(cfg *config.Wrapper, deviceName, clientName, clientVersion string,
deviceStatRefs: make(map[protocol.DeviceID]*stats.DeviceStatisticsReference),
folderIgnores: make(map[string]*ignore.Matcher),
folderRunners: make(map[string]service),
folderStatRefs: make(map[string]*stats.FolderStatisticsReference),
folderState: make(map[string]folderState),
folderStateChanged: make(map[string]time.Time),
protoConn: make(map[protocol.DeviceID]protocol.Connection),
@@ -283,6 +285,15 @@ func (m *Model) DeviceStatistics() map[string]stats.DeviceStatistics {
return res
}
// Returns statistics about each folder
func (m *Model) FolderStatistics() map[string]stats.FolderStatistics {
var res = make(map[string]stats.FolderStatistics)
for id := range m.cfg.Folders() {
res[id] = m.folderStatRef(id).GetStatistics()
}
return res
}
// Returns the completion status, in percent, for the given device and folder.
func (m *Model) Completion(device protocol.DeviceID, folder string) float64 {
defer m.leveldbPanicWorkaround()
@@ -873,6 +884,23 @@ func (m *Model) deviceWasSeen(deviceID protocol.DeviceID) {
m.deviceStatRef(deviceID).WasSeen()
}
func (m *Model) folderStatRef(folder string) *stats.FolderStatisticsReference {
m.fmut.Lock()
defer m.fmut.Unlock()
if sr, ok := m.folderStatRefs[folder]; ok {
return sr
} else {
sr = stats.NewFolderStatisticsReference(m.db, folder)
m.folderStatRefs[folder] = sr
return sr
}
}
func (m *Model) receivedFile(folder, filename string) {
m.folderStatRef(folder).ReceivedFile(filename)
}
func sendIndexes(conn protocol.Connection, folder string, fs *files.Set, ignores *ignore.Matcher) {
deviceID := conn.ID()
name := conn.Name()

View File

@@ -830,6 +830,7 @@ func (p *Puller) finisherRoutine(in <-chan *sharedPullerState) {
}
p.performFinish(state)
p.model.receivedFile(p.folder, state.file.Name)
if p.progressEmitter != nil {
p.progressEmitter.Deregister(state)
}

133
internal/stats/folder.go Normal file
View File

@@ -0,0 +1,133 @@
// Copyright (C) 2014 The Syncthing Authors.
//
// This program is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation, either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see <http://www.gnu.org/licenses/>.
package stats
import (
"encoding/binary"
"time"
"github.com/syndtr/goleveldb/leveldb"
)
const (
folderStatisticTypeLastFile = iota
)
var folderStatisticsTypes = []byte{
folderStatisticTypeLastFile,
}
type FolderStatistics struct {
LastFile *LastFile
}
type FolderStatisticsReference struct {
db *leveldb.DB
folder string
}
func NewFolderStatisticsReference(db *leveldb.DB, folder string) *FolderStatisticsReference {
return &FolderStatisticsReference{
db: db,
folder: folder,
}
}
func (s *FolderStatisticsReference) key(stat byte) []byte {
k := make([]byte, 1+1+64)
k[0] = keyTypeFolderStatistic
k[1] = stat
copy(k[1+1:], s.folder[:])
return k
}
func (s *FolderStatisticsReference) GetLastFile() *LastFile {
value, err := s.db.Get(s.key(folderStatisticTypeLastFile), nil)
if err != nil {
if err != leveldb.ErrNotFound {
l.Warnln("FolderStatisticsReference: Failed loading last file filename value for", s.folder, ":", err)
}
return nil
}
file := LastFile{}
err = file.UnmarshalBinary(value)
if err != nil {
l.Warnln("FolderStatisticsReference: Failed loading last file value for", s.folder, ":", err)
return nil
}
return &file
}
func (s *FolderStatisticsReference) ReceivedFile(filename string) {
f := LastFile{
Filename: filename,
At: time.Now(),
}
if debug {
l.Debugln("stats.FolderStatisticsReference.ReceivedFile:", s.folder)
}
value, err := f.MarshalBinary()
if err != nil {
l.Warnln("FolderStatisticsReference: Failed serializing last file value for", s.folder, ":", err)
return
}
err = s.db.Put(s.key(folderStatisticTypeLastFile), value, nil)
if err != nil {
l.Warnln("Failed update last file value for", s.folder, ":", err)
}
}
// Never called, maybe because it's worth while to keep the data
// or maybe because we have no easy way of knowing that a folder has been removed.
func (s *FolderStatisticsReference) Delete() error {
for _, stype := range folderStatisticsTypes {
err := s.db.Delete(s.key(stype), nil)
if debug && err == nil {
l.Debugln("stats.FolderStatisticsReference.Delete:", s.folder, stype)
}
if err != nil && err != leveldb.ErrNotFound {
return err
}
}
return nil
}
func (s *FolderStatisticsReference) GetStatistics() FolderStatistics {
return FolderStatistics{
LastFile: s.GetLastFile(),
}
}
type LastFile struct {
At time.Time
Filename string
}
func (f *LastFile) MarshalBinary() ([]byte, error) {
buf := make([]byte, 8+len(f.Filename))
binary.BigEndian.PutUint64(buf[:8], uint64(f.At.Unix()))
copy(buf[8:], []byte(f.Filename))
return buf, nil
}
func (f *LastFile) UnmarshalBinary(buf []byte) error {
f.At = time.Unix(int64(binary.BigEndian.Uint64(buf[:8])), 0)
f.Filename = string(buf[8:])
return nil
}

View File

@@ -18,4 +18,5 @@ package stats
// Same key space as files/leveldb.go keyType* constants
const (
keyTypeDeviceStatistic = iota + 30
keyTypeFolderStatistic
)