mirror of
https://github.com/octoleo/syncthing.git
synced 2025-02-02 03:48:26 +00:00
Show current repository state (fixes #89)
This commit is contained in:
parent
5064f846fc
commit
48bfc2d9ed
File diff suppressed because one or more lines are too long
@ -88,6 +88,8 @@ func restGetModel(m *Model, w http.ResponseWriter, params martini.Params) {
|
|||||||
|
|
||||||
res["inSyncFiles"], res["inSyncBytes"] = globalFiles-needFiles, globalBytes-needBytes
|
res["inSyncFiles"], res["inSyncBytes"] = globalFiles-needFiles, globalBytes-needBytes
|
||||||
|
|
||||||
|
res["state"] = m.State(repo)
|
||||||
|
|
||||||
w.Header().Set("Content-Type", "application/json")
|
w.Header().Set("Content-Type", "application/json")
|
||||||
json.NewEncoder(w).Encode(res)
|
json.NewEncoder(w).Encode(res)
|
||||||
}
|
}
|
||||||
|
@ -20,11 +20,21 @@ import (
|
|||||||
"github.com/calmh/syncthing/scanner"
|
"github.com/calmh/syncthing/scanner"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type repoState int
|
||||||
|
|
||||||
|
const (
|
||||||
|
RepoIdle repoState = iota
|
||||||
|
RepoScanning
|
||||||
|
RepoSyncing
|
||||||
|
RepoCleaning
|
||||||
|
)
|
||||||
|
|
||||||
type Model struct {
|
type Model struct {
|
||||||
repoDirs map[string]string // repo -> dir
|
repoDirs map[string]string // repo -> dir
|
||||||
repoFiles map[string]*files.Set // repo -> files
|
repoFiles map[string]*files.Set // repo -> files
|
||||||
repoNodes map[string][]string // repo -> nodeIDs
|
repoNodes map[string][]string // repo -> nodeIDs
|
||||||
nodeRepos map[string][]string // nodeID -> repos
|
nodeRepos map[string][]string // nodeID -> repos
|
||||||
|
repoState map[string]repoState // repo -> state
|
||||||
rmut sync.RWMutex // protects the above
|
rmut sync.RWMutex // protects the above
|
||||||
|
|
||||||
cm *cid.Map
|
cm *cid.Map
|
||||||
@ -54,6 +64,7 @@ func NewModel(maxChangeBw int) *Model {
|
|||||||
repoFiles: make(map[string]*files.Set),
|
repoFiles: make(map[string]*files.Set),
|
||||||
repoNodes: make(map[string][]string),
|
repoNodes: make(map[string][]string),
|
||||||
nodeRepos: make(map[string][]string),
|
nodeRepos: make(map[string][]string),
|
||||||
|
repoState: make(map[string]repoState),
|
||||||
cm: cid.NewMap(),
|
cm: cid.NewMap(),
|
||||||
protoConn: make(map[string]protocol.Connection),
|
protoConn: make(map[string]protocol.Connection),
|
||||||
rawConn: make(map[string]io.Closer),
|
rawConn: make(map[string]io.Closer),
|
||||||
@ -536,14 +547,20 @@ func (m *Model) AddRepo(id, dir string, nodes []NodeConfiguration) {
|
|||||||
|
|
||||||
func (m *Model) ScanRepos() {
|
func (m *Model) ScanRepos() {
|
||||||
m.rmut.RLock()
|
m.rmut.RLock()
|
||||||
|
var repos = make([]string, 0, len(m.repoDirs))
|
||||||
for repo := range m.repoDirs {
|
for repo := range m.repoDirs {
|
||||||
m.ScanRepo(repo)
|
repos = append(repos, repo)
|
||||||
}
|
}
|
||||||
m.rmut.RUnlock()
|
m.rmut.RUnlock()
|
||||||
|
|
||||||
|
for _, repo := range repos {
|
||||||
|
m.ScanRepo(repo)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) ScanRepo(repo string) {
|
func (m *Model) ScanRepo(repo string) {
|
||||||
sup := &suppressor{threshold: int64(cfg.Options.MaxChangeKbps)}
|
sup := &suppressor{threshold: int64(cfg.Options.MaxChangeKbps)}
|
||||||
|
m.rmut.Lock()
|
||||||
w := &scanner.Walker{
|
w := &scanner.Walker{
|
||||||
Dir: m.repoDirs[repo],
|
Dir: m.repoDirs[repo],
|
||||||
IgnoreFile: ".stignore",
|
IgnoreFile: ".stignore",
|
||||||
@ -552,8 +569,11 @@ func (m *Model) ScanRepo(repo string) {
|
|||||||
Suppressor: sup,
|
Suppressor: sup,
|
||||||
CurrentFiler: cFiler{m, repo},
|
CurrentFiler: cFiler{m, repo},
|
||||||
}
|
}
|
||||||
|
m.rmut.Unlock()
|
||||||
|
m.setState(repo, RepoScanning)
|
||||||
fs, _ := w.Walk()
|
fs, _ := w.Walk()
|
||||||
m.ReplaceLocal(repo, fs)
|
m.ReplaceLocal(repo, fs)
|
||||||
|
m.setState(repo, RepoIdle)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (m *Model) SaveIndexes(dir string) {
|
func (m *Model) SaveIndexes(dir string) {
|
||||||
@ -647,3 +667,27 @@ func (m *Model) clusterConfig(node string) protocol.ClusterConfigMessage {
|
|||||||
|
|
||||||
return cm
|
return cm
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (m *Model) setState(repo string, state repoState) {
|
||||||
|
m.rmut.Lock()
|
||||||
|
m.repoState[repo] = state
|
||||||
|
m.rmut.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *Model) State(repo string) string {
|
||||||
|
m.rmut.Lock()
|
||||||
|
state := m.repoState[repo]
|
||||||
|
m.rmut.Unlock()
|
||||||
|
switch state {
|
||||||
|
case RepoIdle:
|
||||||
|
return "idle"
|
||||||
|
case RepoScanning:
|
||||||
|
return "scanning"
|
||||||
|
case RepoCleaning:
|
||||||
|
return "cleaning"
|
||||||
|
case RepoSyncing:
|
||||||
|
return "syncing"
|
||||||
|
default:
|
||||||
|
return "unknown"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -127,11 +127,13 @@ func (p *puller) run() {
|
|||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case res := <-p.requestResults:
|
case res := <-p.requestResults:
|
||||||
|
p.model.setState(p.repo, RepoSyncing)
|
||||||
changed = true
|
changed = true
|
||||||
p.requestSlots <- true
|
p.requestSlots <- true
|
||||||
p.handleRequestResult(res)
|
p.handleRequestResult(res)
|
||||||
|
|
||||||
case b := <-p.blocks:
|
case b := <-p.blocks:
|
||||||
|
p.model.setState(p.repo, RepoSyncing)
|
||||||
changed = true
|
changed = true
|
||||||
p.handleBlock(b)
|
p.handleBlock(b)
|
||||||
|
|
||||||
@ -155,10 +157,13 @@ func (p *puller) run() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if changed {
|
if changed {
|
||||||
|
p.model.setState(p.repo, RepoCleaning)
|
||||||
p.fixupDirectories()
|
p.fixupDirectories()
|
||||||
changed = false
|
changed = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p.model.setState(p.repo, RepoIdle)
|
||||||
|
|
||||||
// Do a rescan if it's time for it
|
// Do a rescan if it's time for it
|
||||||
select {
|
select {
|
||||||
case <-walkTicker:
|
case <-walkTicker:
|
||||||
|
30
gui/app.js
30
gui/app.js
@ -108,6 +108,36 @@ syncthing.controller('SyncthingCtrl', function ($scope, $http) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
$scope.repoStatus = function (repo) {
|
||||||
|
if (typeof $scope.model[repo] === 'undefined') {
|
||||||
|
return 'Unknown';
|
||||||
|
}
|
||||||
|
|
||||||
|
var state = '' + $scope.model[repo].state;
|
||||||
|
state = state[0].toUpperCase() + state.substr(1);
|
||||||
|
|
||||||
|
if (state == "Syncing" || state == "Idle") {
|
||||||
|
state += " (" + $scope.syncPercentage(repo) + "%)";
|
||||||
|
}
|
||||||
|
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
$scope.repoClass = function (repo) {
|
||||||
|
if (typeof $scope.model[repo] === 'undefined') {
|
||||||
|
return 'text-info';
|
||||||
|
}
|
||||||
|
|
||||||
|
var state = '' + $scope.model[repo].state;
|
||||||
|
if (state == 'idle') {
|
||||||
|
return 'text-success';
|
||||||
|
}
|
||||||
|
if (state == 'syncing') {
|
||||||
|
return 'text-primary';
|
||||||
|
}
|
||||||
|
return 'text-info';
|
||||||
|
}
|
||||||
|
|
||||||
$scope.syncPercentage = function (repo) {
|
$scope.syncPercentage = function (repo) {
|
||||||
if (typeof $scope.model[repo] === 'undefined') {
|
if (typeof $scope.model[repo] === 'undefined') {
|
||||||
return 100;
|
return 100;
|
||||||
|
@ -137,9 +137,8 @@
|
|||||||
<span class="data">{{repo.ID}}</span>
|
<span class="data">{{repo.ID}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="li-column">
|
<div class="li-column">
|
||||||
<span class="text-muted glyphicon glyphicon-home"></span>
|
<span class="text-muted glyphicon glyphicon-comment"></span>
|
||||||
<span class="data text-success" ng-show="syncPercentage(repo.ID) == 100">In Sync</span>
|
<span class="data" ng-class="repoClass(repo.ID)">{{repoStatus(repo.ID)}}</span>
|
||||||
<span class="data text-primary" ng-hide="syncPercentage(repo.ID) == 100">Syncing ({{syncPercentage(repo.ID)}}%)</span>
|
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
@ -191,7 +190,7 @@
|
|||||||
<span class="data">{{nodeAddr(nodeCfg)}}</span>
|
<span class="data">{{nodeAddr(nodeCfg)}}</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="li-column">
|
<div class="li-column">
|
||||||
<span class="text-muted glyphicon glyphicon-dashboard"></span>
|
<span class="text-muted glyphicon glyphicon-comment"></span>
|
||||||
<span class="data text-{{nodeClass(nodeCfg)}}">{{nodeStatus(nodeCfg)}}</span>
|
<span class="data text-{{nodeClass(nodeCfg)}}">{{nodeStatus(nodeCfg)}}</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user