Archived
1 parent
691f0f4845
commit
bde92d5cfe
8 files changed
+202
-9
No files matched your search
@@ -129,6 +129,7 @@ func startGUI(cfg config.GUIConfiguration, assetDir string, m *model.Model) erro
|
||||
getRestMux.HandleFunc("/rest/upgrade", restGetUpgrade)
|
||||
getRestMux.HandleFunc("/rest/version", restGetVersion)
|
||||
getRestMux.HandleFunc("/rest/stats/device", withModel(m, restGetDeviceStats))
|
||||
getRestMux.HandleFunc("/rest/stats/folder", withModel(m, restGetFolderStats))
|
||||
|
||||
// Debug endpoints, not for general use
|
||||
getRestMux.HandleFunc("/rest/debug/peerCompletion", withModel(m, restGetPeerCompletion))
|
||||
@@ -343,6 +344,12 @@ func restGetDeviceStats(m *model.Model, w http.ResponseWriter, r *http.Request)
|
||||
json.NewEncoder(w).Encode(res)
|
||||
}
|
||||
|
||||
func restGetFolderStats(m *model.Model, w http.ResponseWriter, r *http.Request) {
|
||||
var res = m.FolderStatistics()
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
json.NewEncoder(w).Encode(res)
|
||||
}
|
||||
|
||||
func restGetConfig(w http.ResponseWriter, r *http.Request) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
json.NewEncoder(w).Encode(cfg.Raw())
|
||||
|
||||
+10
-2
@@ -153,6 +153,14 @@
|
||||
<th><span class="glyphicon glyphicon-share-alt"></span> <span translate>Shared With</span></th>
|
||||
<td class="text-right">{{sharesFolder(folder)}}</td>
|
||||
</tr>
|
||||
<tr ng-if="folderStats[folder.ID].LastFile">
|
||||
<th><span class="glyphicon glyphicon-transfer"></span> <span translate>Last change received</span></th>
|
||||
<td class="text-right">
|
||||
<span popover data-trigger="hover" data-placement="bottom" data-content="{{folderStats[folder.ID].LastFile.At | date:'yyyy-MM-dd HH:mm'}}">
|
||||
{{folderStats[folder.ID].LastFile.Filename | basename}}
|
||||
</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -276,8 +284,8 @@
|
||||
</tr>
|
||||
<tr ng-if="!connections[deviceCfg.DeviceID]">
|
||||
<th><span class="glyphicon glyphicon-eye-open"></span> <span translate>Last seen</span></th>
|
||||
<td translate ng-if="!stats[deviceCfg.DeviceID].LastSeenDays || stats[deviceCfg.DeviceID].LastSeenDays >= 365" class="text-right">Never</td>
|
||||
<td ng-if="stats[deviceCfg.DeviceID].LastSeenDays < 365" class="text-right">{{stats[deviceCfg.DeviceID].LastSeen | date:"yyyy-MM-dd HH:mm"}}</td>
|
||||
<td translate ng-if="!deviceStats[deviceCfg.DeviceID].LastSeenDays || deviceStats[deviceCfg.DeviceID].LastSeenDays >= 365" class="text-right">Never</td>
|
||||
<td ng-if="deviceStats[deviceCfg.DeviceID].LastSeenDays < 365" class="text-right">{{deviceStats[deviceCfg.DeviceID].LastSeen | date:"yyyy-MM-dd HH:mm"}}</td>
|
||||
</tr>
|
||||
<tr ng-if="deviceFolders(deviceCfg).length > 0">
|
||||
<th><span class="glyphicon glyphicon-hdd"></span> <span translate>Folders</span></th>
|
||||
|
||||
@@ -17,6 +17,7 @@ angular.module('syncthing.core')
|
||||
refreshConfig();
|
||||
refreshConnectionStats();
|
||||
refreshDeviceStats();
|
||||
refreshFolderStats();
|
||||
|
||||
$http.get(urlbase + '/version').success(function (data) {
|
||||
$scope.version = data.version;
|
||||
@@ -52,7 +53,8 @@ angular.module('syncthing.core')
|
||||
$scope.folders = {};
|
||||
$scope.seenError = '';
|
||||
$scope.upgradeInfo = null;
|
||||
$scope.stats = {};
|
||||
$scope.deviceStats = {};
|
||||
$scope.folderStats = {};
|
||||
$scope.progress = {};
|
||||
|
||||
$(window).bind('beforeunload', function () {
|
||||
@@ -112,6 +114,7 @@ angular.module('syncthing.core')
|
||||
$scope.$on('LocalIndexUpdated', function (event, arg) {
|
||||
var data = arg.data;
|
||||
refreshFolder(data.folder);
|
||||
refreshFolderStats();
|
||||
|
||||
// Update completion status for all devices that we share this folder with.
|
||||
$scope.folders[data.folder].Devices.forEach(function (deviceCfg) {
|
||||
@@ -364,15 +367,27 @@ angular.module('syncthing.core')
|
||||
|
||||
var refreshDeviceStats = debounce(function () {
|
||||
$http.get(urlbase + "/stats/device").success(function (data) {
|
||||
$scope.stats = data;
|
||||
for (var device in $scope.stats) {
|
||||
$scope.stats[device].LastSeen = new Date($scope.stats[device].LastSeen);
|
||||
$scope.stats[device].LastSeenDays = (new Date() - $scope.stats[device].LastSeen) / 1000 / 86400;
|
||||
$scope.deviceStats = data;
|
||||
for (var device in $scope.deviceStats) {
|
||||
$scope.deviceStats[device].LastSeen = new Date($scope.deviceStats[device].LastSeen);
|
||||
$scope.deviceStats[device].LastSeenDays = (new Date() - $scope.deviceStats[device].LastSeen) / 1000 / 86400;
|
||||
}
|
||||
console.log("refreshDeviceStats", data);
|
||||
});
|
||||
}, 500);
|
||||
|
||||
var refreshFolderStats = debounce(function () {
|
||||
$http.get(urlbase + "/stats/folder").success(function (data) {
|
||||
$scope.folderStats = data;
|
||||
for (var folder in $scope.folderStats) {
|
||||
if ($scope.folderStats[folder].LastFile) {
|
||||
$scope.folderStats[folder].LastFile.At = new Date($scope.folderStats[folder].LastFile.At);
|
||||
}
|
||||
}
|
||||
console.log("refreshfolderStats", data);
|
||||
});
|
||||
}, 500);
|
||||
|
||||
$scope.refresh = function () {
|
||||
refreshSystem();
|
||||
refreshConnectionStats();
|
||||
|
||||
@@ -142,7 +142,7 @@ func Assets() map[string][]byte {
|
||||
bs, _ = ioutil.ReadAll(gr)
|
||||
assets["assets/lang/valid-langs.js"] = bs
|
||||
|
||||
bs, _ = base64.StdEncoding.DecodeString("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 truncated
|
||||
bs, _ = base64.StdEncoding.DecodeString("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 truncated
|
||||
gr, _ = gzip.NewReader(bytes.NewBuffer(bs))
|
||||
bs, _ = ioutil.ReadAll(gr)
|
||||
assets["index.html"] = bs
|
||||
@@ -162,7 +162,7 @@ func Assets() map[string][]byte {
|
||||
bs, _ = ioutil.ReadAll(gr)
|
||||
assets["scripts/syncthing/core/controllers/eventController.js"] = bs
|
||||
|
||||
bs, _ = base64.StdEncoding.DecodeString("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 truncated
|
||||
bs, _ = base64.StdEncoding.DecodeString("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 truncated
|
||||
gr, _ = gzip.NewReader(bytes.NewBuffer(bs))
|
||||
bs, _ = ioutil.ReadAll(gr)
|
||||
assets["scripts/syncthing/core/controllers/syncthingController.js"] = bs
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -839,6 +839,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)
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
@@ -18,4 +18,5 @@ package stats
|
||||
// Same key space as files/leveldb.go keyType* constants
|
||||
const (
|
||||
keyTypeDeviceStatistic = iota + 30
|
||||
keyTypeFolderStatistic
|
||||
)
|
||||
Reference in new issue
Block a user