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 committed 2014-12-12 14:25:12 +01:00
commit d452b7593f
9 files changed
+206 -10

No files matched your search

+7
View File
@@ -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())
+3
View File
@@ -57,6 +57,7 @@
"Introducer": "Introducer",
"Inversion of the given condition (i.e. do not exclude)": "Inversion of the given condition (i.e. do not exclude)",
"Keep Versions": "Keep Versions",
"Last File Synced": "Last File Synced",
"Last seen": "Last seen",
"Latest Release": "Latest Release",
"Legend:": "Legend:",
@@ -90,7 +91,9 @@
"Save": "Save",
"Scanning": "Scanning",
"Select the devices to share this folder with.": "Select the devices to share this folder with.",
"Select the folders to share with this device.": "Select the folders to share with this device.",
"Settings": "Settings",
"Share Folders With Device": "Share Folders With Device",
"Share With Devices": "Share With Devices",
"Shared With": "Shared With",
"Short identifier for the folder. Must be the same on all cluster devices.": "Short identifier for the folder. Must be the same on all cluster devices.",
+10 -2
View File
@@ -153,6 +153,14 @@
<th><span class="glyphicon glyphicon-share-alt"></span>&emsp;<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>&emsp;<span translate>Last File Synced</span></th>
<td class="text-right">
<span title="{{folderStats[folder.ID].LastFile.Filename}} @ {{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>&emsp;<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>&emsp;<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();
+3 -3
View File
@@ -67,7 +67,7 @@ func Assets() map[string][]byte {
bs, _ = ioutil.ReadAll(gr)
assets["assets/lang/lang-de.json"] = bs
bs, _ = base64.StdEncoding.DecodeString("H4sIAAAJbogA/+Qa7W4ct/F/noIwEEACLhc3ifPDfwp/xKnq2FFtq4YBAwVvl3dHaHe5Jbl3vhgq+jQF+hp9lD5J54u73NWdLCvxR9A/EjlfnCGHM8O5ffuFUurWvdMT9djsbt0dhjNGLFwXCUwDAZalemg2tjCEGWYD+pGrSuMTWmY92psQBEfDEcLkKNMjq8pt1b3GNbvadUGdBb0y6plpnY+2Wf2ReN5FI6IOEZCMg8jEvFMlWRtU4ZqlXXXelMo1SjfKNtG7siuMFxq1tVWlFkbpsgSq6FRc25CQOqitqao5r/sB5IrKXXS1jrZQXbvyupQNvgxl8vvdigjoP4MenJ6ps2gr+wswuAaxU5AQVi6QU/BAgK6uTRNnars2jeoCKKwjKGxUiNpH5ZZKq8o2zHht4l54i44COijYAW8KEoC7YhtVuxBVMLFrw1ykX5c6iW8aU6CF6gfvnWchE1gibS3IWXpXK1MFAwZ4MWkf4jKT83ZlG11NeXp4z7IDyDqq//xbfXP7D9+pP+tzt1D3nV+Bs5S0WUuHdwHcVoG20dsFnLYPd0X0zflZhYemMpFsk1ECk/udPGRMmoyRJZyuXdqi96T9iBHTU12bjJSmQmBDwcdhSqLI50Liig5dalhwBEhE26ZyulTPtBg2AoyJZKlhNkZLJMmnTPBDaSmW0v8BlMXSfJoRDNE0nw4EsmIaCqLRi8qos9PmlJDZNBFECCh4AzR4fas9WFqq17dsexdj3utbGF04CIMPAqLcNbq2BSAg4LTGL52vle7jSIl7vzF+h5cUnUjY57z8x1osN86uGueNanWEWRNmEE8NCqMIkun1DjoRmQJAfusfWdjUvxqPIUWOYQrKCEFkbTn8LGwMSsOivHbJAa9y7hxvHVirirVuVibMIRMZTASP7r1QS5ASdiGamrf1A0gd1GVJNWwzpZgSjgyjcN3CfMP2BYybWs1D7AFL8k5e2Ju20gXmMcxcGCpKtdipsGsKSFjNqrfhYyw1Naz1LlKg4DArG6NquNK4MQ68KuVb8AiIgJdI8qSbMnKAyMIJ2YBOISb/LKoONthPLP5EOshW8PZxvB4mI+QTjRwZgQBGRKc6rjMSmuYEYUCmkuLHsxMFJcgagz6HfGALYes8Bder0AcFgEf7A8yEGhh/smBEo0YV5164sJjGeEkM/VhQlVvoSj1M4YhIprD9pOq58RvR+ABqxPg8JhXyOZOclBWh6L+AOKadSkwj7AQ0JuyjyIg2gwp5A1EcowlmRtixGjLS0WN7/+twTHxXoJOAVM0yfT9LaLnfyWtXdgNnAmkd0xuAj+zczFXpVOOiMm/AqUsjS9+Ik5d9bEybojZtwBjARD9pqhAN1RHDJCEj3rVnEHw0V8ETiJCZFVScVIqloSBcMfWkKSgn7N0hnzLBE/3G1l2t7q2IIJ8KQVdFqyqzMRUGjbLQvlRHkFmLNYYWxLaQWEoLFTIUfjsm5QO+MS8v/dSIz/NAgI4grp+qPXl1DzSRR6mfZMTgnx8jCP7KdLlMj4w0FETTw5scDMH256V6DgmEcNm0J1i5wxfhKrQIgA3wFsL4A47pxDWFMSmG1BTRJetR7DeQ2/H04c61HYZ29VJyQOENlVh2qWDh0sHZsNdDiJurF8AJrzdYB/KJ1wUWQUf/OFYFvDaBmd9dkKJUWEN1VoDtS659Pg9Fsk2h19RQIwBZV5WUBCMVQEdw9zZGmbqNOyqAUNfSLDU46r5iwjaZbcfz3uYPvY6YRJFCbTW/FPKpEHhI9WZLSBmOEKO2RUY1hjPLXzpbnKtVh+4GRxq6FpFgS5vljHcTsbBn955MewRTkBCaAIdLeB7lYHWC9fiGH8FTUE+InQAhoOEIoZ4aI0+0CWREJkElmyU0+hyjaMTg53C4CKT/AgLlUmzqx4KCiF9EcQFu6uDerbHko4ItVa42rsnF3o8hLRJR78D8MhYUMb4EYnlNMtFlaEZeEqank2kigDNXVp7ooEdycFZrrp5AYYmXgRo18DynxhXcf6k4k1Fs628mrFduK0VsGg4IbJ4BEzzkoSboexLp9iWJ4AOxC0PM0iVc12gDv0ZGVThFI6gwWnRpCHjpisNr1STzPvaqv9bcri0pREtcR6GZKw56BQzilVlGDnO/0twbr5rM7WIJa7MSMhaUrbEE2VNDHMAktmYF8EOlDd49eoIOpY1rqt0xy70ZqyzsOg8WP3Alx5hsKgRRr1YGL+U+mw4ie2a4b/e928r7aAxIRK5tOe6loSA44Kuv1SPnu5oIJiAhhMpIncJ71hWu2vvCegfFIGbtQf8hj0xBA2HaARkOCHryqzXcmgUU6BBIOyw9ts08kR8mmAqxDb0TwqQvGtwybjGeQvCinwgwt+OVNW55d7zKjSRcUiPQU55z1cSMCW4PK/f493JmqCkjPG5qSkRwW3FzZoojNfaXsCZrvVtUpib3VjvwWs7VjYmq6Jvkcyg6ot+BvP/+81/j1T+AfDYBq0q4FN6sKMJg5AFvs4U0XbpFZYtqp/RG24raojqqt192vvrygjboRvxvgf/iYp6pkH7I4R7E4Gwa21zYzMFCGGpeu8Fl5mrYmRpToJwpblAi4kgJ5dxIdK/zx1twMLLs4z3WQI4y96LSzXmv1RUU+8TA6oa6suQI8hBYuq4pU0Z5zX3w193t298aJUn/9S2Irrpyq/QgyRMomNpqyqMgpdRhLf23PqEeScP0eI/Wn1qhYZNMU/hdiy7ZUTnvqZzHy0ItvxLccTdXJwTppI6I8Ko6p847qNFWOmInPcxSRRnsL6KFbtv+fQNCltI+lHIfcjV27kk09yBLvJJ9zxHuak2a0WXlriRbr1faDi76ezYhP4hIGXdwkv5hi812Bc8VW5IZw0NRqzvfYIC783321g3R4/WD2xUwwsDQYbGDTys2qenqBYxnrFS45DQLQ0ziNtk2f64KDpu4TC3ng5HjCop9Ymp5OEi3IH9jHH3/3WAU/cRUQdVxvN+uWTKq/z20hLWP5sczMkodfXVMGIgAQFRAnaaO/nY8kg/V3R4rPjcFr9rErrF/78wVRiSCS0Ja7Je840j304xESZlk5fnP8RFDwt3hxWg96LLGykCni4+3+9y08FqgTvq3t+HKYwuY4kXOVurdQS4UOaUHScASDvIAcgabEm1FTLV0XTHIHWLZGjPamf8bk4eDznmG68HuTT58yJHen/HyotHW1NU6x17/oPERpHW0e0bZAvC3e6KsjefRoONL+vwmMgdVxSC4+3BxBlLhndGv1Pj7ba/H9Rn2LdLTv9dZ3Jh/UMFzsy+5fs7vmq8arMTtJl9JXLzX4eYCrqEEZE2DP/fcuf6ye1h4obPmvJG+RRomBDX8SsbIOKFSV1JGAm7xXB/KD0HZLKHpyy71wsHrRk7mywsmHTBvBXNxMWKTt/UwScjRdzL5VAgCti7676yIaAIaCP/04sXpcwo6P56dJNIxkImlq4EkaThChP5H6DFgQoTxtP+IRFfVrv9WwFKxuOMinFJUhBLxUlgDpcybwhjOuoMzLfknfYzg/DFZ5hPzkVqfSAXeiJf4qYQu8TzxYsC7jgvEGUci/AjOUkVBH90NXxb0Xk3fG47eM4F/GXBk5QeVf8gELin2L2FU/2HD6EVhUyWCkXFlaKWFiVt8Lqf+Mv44xadR4K8w8D4JlmIIhjLSmPp7cBpQVME5Jn7sVecN79+ZxrzNr7hn96pvzL2ClxKJ4MSWwht+KSUBhIy9DhkLXHa46vTrvD1QJrf4eRJS8OCLiy/+BwAA//8BAAD//36dpRC8LAAA")
bs, _ = base64.StdEncoding.DecodeString("H4sIAAAJbogA/+Qa7W4ct/F/noIwYEACLhc3ifPDfwp/xKnq2FFtq4EBAwVvl3dHaHe5Jbk6XwwVfZoCfY0+Sp+k88Vd7t6dLCvxR9A/EjlfnCGHM8PZe/uFUurW/dMT9cRsb90bhjNGLFwXCUwDAZalemQubGEIM8wG9GNXlcYntMx6tDchCI6GI4TJUaZHVpXbqPuNa7a164I6C3pl1HPTOh9ts/oj8byLRkQdIiAZB5GJeatKsjaowjVLu+q8KZVrlG6UbaJ3ZVcYLzRqY6tKLYzSZQlU0am4tiEhdVAbU1VzXvcDyBWVu+hqHW2hunbldSkbvAtl8gfdigjoP4Menp6ps2gr+wswuAaxU5AQVi6QU/BAgK6uTRNnarM2jeoCKKwjKGxUiNpH5ZZKq8o2zHht4l54i44COijYAW8KEoC7YhtVuxBVMLFrw1ykX5c6iW8aU6CF6nvvnWchE1gibS3IWXpXK1MFAwZ4MWkfYpfJebuyja6mPD28Z9kCZB3Vf/6tvr7zh2/Vn/W5W6gHzq/AWUrarKXDuwBuq0Db6O0CTtuHeyL65vyswiNTmUi2ySiByf1OHjEmTcbIEk7XLm3Re9J+xIjpma5NRkpTIbCh4OMwJVHkcyFxRYcuNSw4AiSiTVM5XarnWgwbAcZEstQwG6MlkuRTJvi+tBRL6f8AymJpPs0IhmiaTwcCWTENBdHoRWXU2WlzSshsmggiBBS8ARq8vtUeLC3V61u2vYcx7/UtjC4chMEHAVFuG13bAhAQcFrjl87XSvdxpMS9vzB+i5cUnUjY57z8x1osN86uGueNanWEWRNmEE8NCqMIkun1DjoRmQJAfusfW9jUvxqPIUWOYQrKCEFkbTn8LGwMSsOivHbJAa9y7hxvHVirirVuVibMIRMZTASP779US5AStiGamrf1A0gd1GVJNWwzpZgSjgyjcN3C/ILtCxg3tZqH2AOW5J28sDdtpQvMY5i5MFSUarFVYdsUkLCaVW/Dx1hqaljrXaRAwWFWNkbVcKVxYxx4Vcq34BEQAXdI8qSbMnKAyMIJ2YBOISb/LKoONthPLP5EOshW8PZxvB4mI+RTjRwZgQBGRKc6rjMSmuYEYUCmkuKHsxMFJcgagz6HfGALYeM8Bder0AcFgEf7A8yEGhh/tGBEo0YV5164sJjGeEkM/VhQlVvoSj1K4YhIprD9pOqF8Rei8QHUiPFFTCrkcyY5KStC0X8BcUw7lZhG2AloTNhHkRFtBhXyBqI4RhPMjLBjNWSkoyf2wVfhmPiuQCcBqZpl+n6W0HK/k9eu7AWcCaR1TG8APrJzM1elU42LyrwBpy6NLH0jTl72iTFtitq0AWMAE/0Izq8o5r6AuMJ1wA4sIw3GND0NTRIy4rV8DnFKc8E8gQiZWUFxSlVbGgrCFVOnm4Jywt5z8ikTPNVvbN3V6v6KCPKpEHRVtKoyF6bC+FIW2pfqCJJwscYohNgWbC8tFNNQI26ZlH3hxry89DMj14MHAnQEcf1U7UnBe6CJPEqpJSMG//QEQfBXpstleo+koSCaHt7kYIjLPy3p/AmXTXuClTt8Z65CiwDYAG8h4j/k8E9cUxiTYvRNwV8SJKUJA2UAnj5cz7bDLKB+lnRReEPVmF0qWLh0cDZ8QSAaztVL4ISHHqwDqcfrAuulo38cqwIepsDMTzTIZiqsoZArwPYll0mfhyLZptDDaygngKyrSsqXkWqlI7h7F0aZuo1bqpVQ19IsNTjqvrrDNpltx/Pe5g+9jphEkUJtND8q8qkQeKgKzIaQMhwhRh2OjGoMZ5a/dLY4V6sO3Q2ONHQtIsGWNksv7yZiYc/vP522E6YgITQBDpfwPMrB6gRL9wt+L09BPSE2DYSAhiOEemaMvOYmkBGZBJVsltDoc4yiEYNfwOEikP4LCJRLsakfCwoifhHFBbj/g3u3xuqQartU5Nq4Jhd7P4adRRib8SBdXkVOF7kGQ1ok4uYE5pexoIhRKkC47iBgePQeRubMGTwMXCNoRl4SpqeTaSIAr1RW+g2wU+kKsqVz9RSqZLyu1HXSNZXZGiKUlM9p23mjfjNhvXIbqcjTcEBgJxCYdIkFTt9gSfEhSQQvjV0YoqouIaBEG/hpNXpSULyEcqnFSwchOQUheHqbZN7HXvXXmtu1JSURyTwoNLssg14B00xllpED8a8098arJnO7WMLarISMBWVrLJL2VDkHMImtWQH8UPGFl5je00Px5Zpqe8xyb8YqC7vOg8UPXcm3O5sKQdSrlcFLuc+mg8ieGe7bA+828tgbAxKRa1uOzGkoCE5J6isIN76riWACEkKo3dQpPM5d4aq9z8V3UAxi1h70HzLdFDQQph2Q4YCg/oVaw61ZwBMConCHxdGmmSfywwRTIbahR0+YNHmDW8YNxlMIXvS9A6sPvLLGLe+NV7mRhB01AvUlOJtOzJjg9rDyB4u9nBlqygjPr5qyGNxW3JyZ4kiNzTKsGlvvFpWpOb1twWu5mmhMVEXf8Z9DWRT9FuT995//Gq/+AeSzCVj3wqXwZkURBiMPeJstpIPULSpbVFulL7StqMero3p7u/PV7UvaoBvxvwX+y8t5pkL6KsUNlcHZNPbssDOFpTpU5fYCl5mrYWdqTIFyprhBiYgjJRScI9G9zh9vwcHIso/3WKU5ytyLSjfnvVZXUOwTA6sbajGTI8hTZem6pkwZ5TU39V93d+58Y5Qk/de3ILrqyq3SkylPoGBqqymPgpRSh7U0E/uEeiTd3+M9Wn9qhYZNMk3hty26ZEcPDk8PDrws1L8swR23c3VCkE7qiAjvvnP6jABqtJWO+FkgzFLNG+wvooVu2/4FBkKW0guVBwnkavwMQaK5oVrilewbqHBXa9Isq3XZer3SdnDR37MJ+UFEyriDk/RPb/xyoOBBZUsyY3jKanX3awxwd7/LXuMherx+cLsCRhgYOix28PHHJjVdvYDxjJUKO06zMMQkbpNt8+eq4LCJy9Q/Pxg5rqDYJ6aWh4P0M/I3xtF33w5G0feyCqqO4/12zZJR/cfdEtY+mh/PyCh19OUxYSACAFEBdZo6+tvxSD5Ud3us+NwUvGoTu8b+vTNXGJEIdoS02NF5x5HupxmJkjLJSoOC4yOGhHvDi9F60GWNlYFOFx9v97lp4bVAnwW+uQNXHvvZFC9ytlJvD3KhyCk9SAKWcJAHkDPYlGgrYqqlL4xB7hDLxpjRzvzfmDwcdM4zXA92b/LhQ470/oy7i0ZbU9/tHD9cDBofQVpHu2eULQB/pyfKGo0eDTre0ec3kTmoKgbB3YeLM5AK74w+uePH6F6P6zPsW6Snf6+zuDH/oILndmRy/ZzfNV82WInbi3wlcfFeh5sLuIYSkDUNfpC6e/1l97DwQmfNeSN9izRMCOoWloyRcUKlvqmMBNziuT6ST1XZLKHpZ2rqpYPXjZzM7UsmHTBvBXN5OWKTt/UwScjRj37yqRAEbF30PxojogloIPzTy5enLyjo/HB2kkjHQCaWrgaSpOEIEfov6mPAhAjjaf+LGF1V2/6HD5aKxS0X4ZSiIpSIO2ENlDJvCmM46w7OtOTfJ2AE51/GZT4xH6n1iVTgjfgZf/ehSzxPvBjwruMCccaRCH/RZ6mioF8QDj+T6L2afjw5es8E/nbhyMoPKv+QCVxS7F8idcmpH5m9KGzepV8ZWmlh4gafy6m/jJ/P+DQK/E4E75NgKYZgKCONqb8HpwFFFZxj4sdedd7w/p1pzNv8int2r/rG3Ct4KZEITmwpvOHPviSAkLHXIWOByw5Xnf7UcA+UyS3+1gopePDF5Rf/AwAA//8BAAD//4y3gJSJLQAA")
gr, _ = gzip.NewReader(bytes.NewBuffer(bs))
bs, _ = ioutil.ReadAll(gr)
assets["assets/lang/lang-en.json"] = bs
@@ -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("H4sIAAAJbogA/+x963bcttbY/zwFPN9JLHVpZuw4cb8qkr7qYidKfFF1OWmapmdhSMwMLA7JEKDkiaLzRn2Kvlj3BkASJMEh5yLZbU7WijwkgQ1gA9h3bOw9OXl/fPnL2SsylbPg4Iu9J/3+F8MhOY7iecInU0m2jrfJ18+ef0Mup4xczENPTnk4IYepnEaJGEBhLH855YLESTRJ6IzAz3HCGBHRWN7ShO2SeZQSj4YkYT4XMuGjVDLCJaGhP4wSMot8Pp7DCwSVhj5LiITWJEtmgkRj9fD9uyvyPQtZQgNylo4C7pE33GOhYIRC0/hGTJlPRnNV/DV0AKFdmD6Q1xEAppJH4Q5hHIok5IYlAp7Ji6wNA3CHQJ+2qMRuJySKsdI2AqPhnARUFlWbhl+M0ic8VLCnUQwjmgJUGPctDwIyYiQVbJwGOwRKkp9PL394f3WJ4A7f/UJ+Pjw/P3x3+ct3UBhQDQXYDdOg+CwOOECGcSU0lHPs/ttX58c/QPnDo9M3p5e/wAgQ0OvTy3evLi7I6/fn5JCcHZ5fnh5fvTk8J2dX52fvL14NyAVjbegda1izCLDoM0l5kE/7LzCvAjoX+GRKbxjMr8f4DXSNEg9WUJe5C6JwgqBwlFC4wOOAnI5JGMkdIqCPe1Mp493h8Pb2djAJ00GUTIaBhiGGB4Mv+n1YvLiGYYLCyX6PhT0STvo0jvd7Ilu16pUXhTKJgoAl+718PR/nL3vEC6gQ+z0sGkT0uoeAGfUPviBkbwbjJ96UJoLJ/V4qx/1/7xUfsI999nvKb/Z7/71/ddg/jmYxrLlRwAAsNMFCqHX6ap/5E2bVC+mM7fduOLuNo0RaRW+5L6f7PruBkfbVww6sJy45DfrCowHbfz54VgPkM+ElXC1bC1atGFVbuFYi4OE1TGQAeIPP0oOVxz2ENE3YGGoJGLoY8tlkOKY3+GUQA2YPvsC6ksuAHRRU4k9yd4dzeqJG8A6a3dq+v98b6nJ5axoyLG8/SoajKJKwe2g89IQongYzHg7gTc/0Tc4DBhueyV4VjunhGIY1hBXHbul8qYrYbAQbPOGAyKaae0O9Jr7YG0X+XEHy+U11fb2CMUlrbR3sDaGUxhVQWnIZxWREE4KrF9+F9CZffvQGv+h/+hIKmp8+G9M0gFUCMJkqxyeKrqnxmH4YINgXykNsWX2DryIGOlxqoz8CKuJD32BOsy9BNIl6RCReacLxbV+yj7L/8hs162TKkEns91583SN6sfaeP//PvSEMFBvKW40rTSIQMuW+z8L+R9E7cC+TOK+fBhaADBPWT8Wr8kGqacW54DCraQzUxGen4TgiX31FrMdByG4t1Kh6QIklsAQ5jwG3+iGnCCMZZu3hT/i/Hyd8RpO5+i1m2R7RdAbI03Xe/NZ2qZ3KREyCeTzFvUTyX31vym4S+DeNexk2v2IzEX/nAAMbJBTImYpf/RsapPBXM6r93t2dPXIsIeT9fe/gSr+FpUjuvjSlv7wvT59qaKixYeEYCHAZ42Y0fhLFfnQbljFLDXL+rVctB6t7MkESCfyZmgcbSjuqIliKNOG0H9ARbtVXPpc51vaGtNSRYi3lHZixMK3ODwwu77M9oSDCyAsmJdA3gbPaqXflGaxM2kEGzupwGbkLO8R9vW86deb3xIt81tafaXRLTk/aupOjkd8AqVTUrXOnxTSViPpOnY7G49Yea3CrYTCBvUAT2akvUBmKT1v6c64hPiQG6QiEwk5dBk6VyD6bxXLe0u1DhLmg03vDNHATgOKLYXH4A4il5msNLEmXR0b4midCAke7Bdk7DOYoVN6GhIMACBKlEEBivyMGpyj2hihcGKZZcF6k9k8A/phPTkMUQnJKA4ALDljqTNCf+f3nX9usw/oOeGABUX/7ptkyUauWRVz7qtTe9IVFlktllPTTy9YIeceYz3wQKF4c5LhrbgDFjSqpiq0pRDVN4yBNlFgAkrkAXQN0B0FRNEddA8RqQj3Jb6CGP7DUulmK02A6JqO8kBLjgV2WQQ8sFl2a+ubuj0Geq/DcDlxXs1f1jxF/QOMLAsP2H3UnV7lgbUkFsNvG/GPPMZnlF6VH66GQEcubg03SACRCWMuVpV9a5Bk8VTEKUJcGzRj0eBQhAzaW20Vt52Z4uWgv9CdJBAIJ4f5+b6ygi8UbwmyeXGiFqUpYzKjM6qN+rH+9gW7WxaTGHVaWFqDzAY1FJkTEoPKjSvNvWScz4UM/9+/u/sZDn30ECYgouR4gpImIkl0SRzysL1FXT5SiylA/gFEhxcrGdCGpTMWWftgm+/vkKeqg0OunWiuVMumbZpXUvAt6EpY4YwmotJJOmKk8OD0BSfhLx2JSXQIa46IslWIdhM2p71f2wd1d3oP7+8UAi61YiPREqQkZkGMsmOEDcY4IA43fm7pR5hhCXdTNYfRvpwwk3DS8DpW8eKV/1GXY7pAEqPjMR1D61+qwBOy7GEFd6B9rQPJoqDnQhfm1Oizu4zq5ipHGn0CBNki1vujl7JynWuvKILCwu4RsLd4A266eNYBzv1f8tUxa6ltK7fGCtpXIRGmjZeSGFHRHMSFV5I6Hu0RXhL2/T57ddyAmDr6uCko6CnL5QT+ov2hn8NH85ZtntDiqheZClcysFK5vifsDfpq2s1GDqihmYQsrNezojMppzk6hhcbG/XzYSEuMip/TJQSjbEl+w7iGTQODEWfi4gyUoeDXfKn9NuAh6M3cjcXOKDGiYl/wSRtOXiVJlKyDjaYRrIyatUY+CaJRm3b5PZShAUGKzzY68okC/JoHTJA/CQ1u6Vy8S2cjltzf12gSl9A50/wO+WcjuKO5VOBGPAQt5P7+6FOgdRrN2rD6JvIeBKkBwt0YThW0TaG0cROHoFHpLh+QZ+ttZS+IUr+PpoUgolUZqTr+96BavR8rdWr1OWgorSxotv0kukXF0WKTufXRNY0FSjYwiwjMMYm0caTrza9p+RwE//dh4OKSS0worMDrbnzqLRWgBzzERFba+4WJRaLRpvB3OgmjhJ2hU3U9FKahN2XeNWvbDrpBgi1ygXZl8f8PMs8ZiuOnqCkCu70gT/bJyzVJTWd7BHrSs5Y3IEhVhgIUQXwKHqcUrT4NZKupFxUy8jNfT4pUzQm91QvNdCOLA5mwsOnlG6AkSHzXWx8KBWNtJV4kCEBjBFtTfChXOB9gz6GxAR1LLaMe4B90OcPK+q+kvfihBLbiw1B2n87hv/7bt33fJz/8sDubPb2vq1L2f937gpyLCtOt5oFumJLAe7ciBh9QiasrrS6rTzejqipqDKsNplQaTjDgwc1m0VnaIllZ8kjmMHfKI+0cJe4iXZkmyPEUOy4WmmTV6N1GKreGvBhTmfnScsO0GPzQwvK0YpoGMlsiOApLm2UMrUhZZaiW57NMMDt0Pmahx4M2LRggt09nk72nm/W9YT8tZaUvNzaOkpkxiLtiCFbxX1DfNxjuhNsgFW0ePSCdGuIC/HbCYPVxmmRVbrjgygI16w0r/gzbG6G91JY3Qo2+7I5QQTEYBKZjntZxVSzwPGjgx+MJOh9+LSJPtrZ/6+jea3I+GC+DidhCyB39Cx1N+XtA/0KploHqgQrysAY00AM5PcHpy8vmJn2/CLDJq2xX+F/VUOp26qGRtDTKxeZRQHSrY8dpAd2E/bPZ+tkos27eNnBiipHzLhaaRrEV2g2Zh85X8etTGUkaPEWT3ygu6eJDgQZ1Z9nTUGnul/hoV9lukmYaZZkN4K4T37+KHwpvUSq7I+59Kj8LzMlWQeDwLbmSPOB/KCf96jgTcyHZbAD/dDHWPcxofSqmo4gmbYvk+Oxqo4P24tT4oioGM3gMQdhLaLD7/P7+yxWwkcnbpiVo/TAMoxR0tfc/oR0BA+DHPATCBhI4NZ8uQDlniVl8zVbNTjgdgegxjZI214Sx059w4aF0P18Vp03aU+ZYRFxUhvmago7hD0BVm8gpitPPiqBBYHvauSxSD2OD2vTUg/c/talxC7927uYTdzeNltWmTcdRjFg2ggWgboIBxFN8l8U0BNRjMxXWMIpAhJuZ93n89t2du38fQOLYevo/w6fbreqza7n1F436/n7orrWGVt389ZEpLW0L3Py7jpddndqYgNtmw5N7ZA12BKcVoaOCUzyjDH7OZpFkRgoXthjuktysoCBTY+WgoJJoHuExHS3Rio1HBmU9rcjsDxUZpMEbQ0EhfHcMDvKiWRww5Gy/1mX93wb/kEYoCRWP2n22iZihh1c1VDPl+JJGRPW6RBuZ4irayG51pXgiHuK8fKooGS2HLj3rywTKtKPAR96vZGFUrE6sp3WCq1KhQ6vw34cM4nHs6JYgnvad/SnDdDIpxFZPHOviER3eyym1HdUz11LvoOG6qi2t7Hb08zzCDGxcNV4D+130ZFe95VXmh3Qw4km/dmspsu11cKnxgIBKHGjNBfekQC+eKcVOFif+VsSHZwC1+vGvgERarXbETu3wg42nd9GaCCnwcYqnK/3UW6BjdbSrABcV9eN2taiGvL1NIEKFK3y+tGhzKtAa5Oc44CBd/r1NVeq6lR4UYWzOuoTCKie9YGz5zVQmCNrR7UIatnABDZxQNN/9SZYqf7BPXrz8tufcuewGV37TFOjuljZpxzb3GpvMiGo7oCxwoFcNHOitvWx0s9qVZisXmfVn7UjD+hEMd1zaBriTYxTKRtTbIb2VeNWjxzU0efb36GpubeP/s9TNh/Bs04O/iA97iQPJHX3YGuJGfdi1I3fa9DUsH7DDVypIX7gPnDL8po+u2aTgE588dVl4qmh9F0kbpescP7UMeIAPNN1ZaMGWZzQIgPzA28ElV9FXmk4jbd4VAsjzLnRElcIgrgQYvh/MM9MfVlNzUM4K4V76GzhyapmYmshIsdzVYtMrpNth9jYlJPdXPO5h09IeyE9p56lJ8PWRcjt0y1iS0QjzCJ1kfLine 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("H4sIAAAJbogA/9R9e3PbtrL4//0UiH75RVKs0EkfmVM7bseNk3N9+0gmbnr+cN07tAhJrClS5cOObuPvfncBvkAsQFB2eno4GUcSFovFYrG7WCxAP14WkZ966yQoIj4ZZ9t4nq/CeOnNk5SPp58xeOBznKdJFPF0Mj6rIF7WP45nbFHAr2ESs8nDbJ5s+Iw9XOX5Bv6LkrmPJTP2A3yK+BlPr8M5n7I/BW58xkXGWZan4TwfH35W/7y/zzZpeO3nfH/Fow1PWcAXYRwitqwBu/ZTgOPXJwDIjtjTQ6Uk9q/DJRAQL49v/C2UL/wo4ypMEkdhzOmylGe5n2L9prwGqHuNVDX8mGDnaiB8lK57fpEnAL0Il/L3yfRQBU/5AtpdnW2znK+xlCiUCMyFMRekneV+nhmgTjiSY4N4nUQBT2sIBUQMsLfk+aRIo0sfhnCPjfeveZpBs+OplxXzOc+ySSMagZ/77XGvMQmR8cqqwGcErL6qdN26UZHyTZLmuxAha4Is+SUdO7VfbJapH/BdCCirnsaLxECBx9M0SVsYnbHFRRT19Cfj+Wmcg6D60aRmiZCFGXv2FJ6WoNx+pk7W4jKc74s69Ewt8c2T9SbiuRzqP28P9XKUbFvZaYxaCCDytOAUTCn8GY1E8A/Lzi+0MlCEPKKrrbenJ1AyHmslgZhIBoybNMmTeRK9XIGy5YGuZijJI5qX5W9B04X8xohlIWasoeMZ5/Er7DzdDZuwKD0VCoFuYtFoDBoA2LEEcapKm+LJTRgHyc3Uu4T/J+NLvgALVMRR4geKgelKu6bhVaFQJLyk4WEST0a1ZZIDcyYn6sjWlKrGwWqV+rtGBRz20/lqMvUiwDm1UxFzHhw3cqq0NE7X4wM2PuHReNYtCMK0LANlEqbTLgTacATAOdIty5NivsLC9xtQLXzcEKgNFJJ3OrcQl/J1cs2N9NHFFXEw0uXQGgj0wfalYXalkEgN5Pj96RthwBUp4dc8zmfMT5fdQQwXbFJa/EeP2IPGwFNqNOV5kXZtkKoxkUVJxL0oWbZo6djTroOgltYOiCq6kgDd/2iXP5yM/1/M85skvRIzG0wOqDBQ3uNVGGhkIHSDsR82WxU5jpQZ0jS9kBOLxcBh6Uzljx/ZA8maexqakiAT9wn2IlU9ImIcgWmXtl6eodrkpZ1wZBv6qIG0GVDq6f4C9qBt286FcyXV9IXFc9CBvSyXLrb4MU8Gd09oy9M44B+k9rm3Pire6qRF83CvFvwYSRxruSnY8SJjYJCYH0WsMvf5ys/ZDSxdVn7K4VuIIIia3YT5yvuM4GppnlW+Sj88g+/pKx+sR8tXFCUvFwbdVPr6FZ0NeIny9GTGzNy4dZnG70CL5/xvMGjtbiKs7Kupf8b+SMachFnpJTr3B2YDB6nQfczzqnteGFwMWWf10PhyIIFCVfWQZ5nvpiqa9a/biy832QF7OiNLkyK3FZ/G321znv2c5H5kBHpT5A5Qx0GA/uRBLWaeD79ooLeH5p5XkuXW8f/JJT2wHOprxUEpVoEAcLyJkaYGWVkKeW82Ysy89++OwYHd5LjCODpiT6mhBuV2umBF5i85k8sJ9CtWfsYuYWXAYg5qC7SXXyGKE4y5zNE8BjrzARsovxs/zlmeMD+7AhXIATtggO9r/4ozn81XCfrK7LtCqMogice5qEOhg2qXxRLRrFlQpEicWEX6Ea5Li82MZYlQuDxH1ElyFXKha0lkQEwerjlLFuLzIkyznF2HWZh77F8r6K/Q3yUW0N0bECNOE+bHQYMPQNeJUPh+DAq/SNkK/mTMXyYzpK7kBIXnjwJcCVwnfKaVor4UJP6CFKKVTebFGujxJIW4/ov8OZ/sT749gH+/ffQeH/6aPZ42leDbr0fwZ3L+2+HF46n3+OH042/wd3/GRg+fjab6DBA6o0FAyQw+HVKAuFFT6WjE9hgG37w4uYEl0x4bHa79D09AyETRF0/ZY/b5l/Dni+dPn+o03DIObpdJyQCBey22vGi39IRVWOE/DE6Y6McH3bTC6JzVxOjk7Tahz/xrZ81dCMMqvKMyqlfpIbdok9QE+2JptUPEqRNTEfqv/dsOXsNJubp7Wy72B/gMWRk6oJ0GGexVIgjtYvTQJmImST8slL5bZnGfSv+DdD3wqVo7L701olW15TDidbvnFj+77jBgVIDPEcUFLZ8yJA06FuNIz4TgZ947+cM+fBSm0lwVRijkwes0Wb9Jw2UYt5C87BYNQvcKpvAN2A5OYmxKHZBuClgit7v3Vv7gWFWulNt18ZeeyqCa/wUKPd2iCUqTAtR9sanRoXXLI+5naHU2PJ2D/KIlEvYDlNJNUkQBmNAW1GUoTc0lrD6Niq3C/4I9w1BE2fE9kq17+tjtVZLw4oh9/bVN97X44qr2RLWO6EvBNPpF+EhRPCgpox02fLrSdqB1z6VuzZ4DimdmDFKiDkqO2+GAbwcVA82QbT8185pvPTVOkpjXFfALDU/oG5NZwofQgp3gKyUswheYNFVqWJNkOSrQCncrrAgDJZsBR7WsZ5Gpsp2foKK9FcJ4S99i5+YFJyuN3uFhn26v+v2gRqDVtFUd1PPquUy5f2UGoae5u8+Djx7Grz4eGmNvo64/MJppEmnwKkQYgV+CSp7DsMFfbeOgdixIeSQ8jCuOuwQjBRwdVVmDiP+p7Z9DfXLQCTB0p8pfe/brBGtJ704E4r6VxB2N4Scez+Gn9+9OMSQCOiPOq84Ocf464ynDfY2Po7texsFVGTkr+SgjM6aZSvx+KzcYZyIIboydGhg9Ubclq481G3QXW3q4lHzAevhltQX5IMxerTf59s3l73yeq0tvzTnvbF/KD4dmmHrt/kOY5TwuAxlnOW7POQB6vych+NozpkXuybr/jJJLPzqOY9y/4qm1nS6s0hTVVrMDqiIsQ5skfcFuYU89aqOHPe8neEOztSI7S9K8ohRo8VNu4E2zJSs//ehvOjEcOXWyTntS5jwQ72yiopoSPDMbMkc73YlQ3zE43Wq4J0BtJKjLfy1XQSjnerZaZOUhX4d5J9Rm3p0xm5YqIafTEq23MwG8y4K8TDQQC3H8bBwr2YRRW5dQfhwLdVnOZeGXVuj5h/y4LH7zPftWkTkdYOpFPF7mK3bAiECO8Dj9UC7ezokFbO2XZoISdImINiyRoAc6+LnEZfXCJFHepshWEwm+Y/THzNTXVb9lWzp6ymJKcRqRlvK2x6CZ5tbM4NEi+ySECA+3JG3HvVXdk2poQW+qbOxv61Y19uNbSarwrWqqx48+mcelbtR0rJhVkEVvTBUNgalm+AZj7LiDLYhDPX5dPSgXYGMxE9O8+MVnHudqumb3qdXFfL1prb+GswwZjjhQ8EfSARj11REUJnEext2MjO5jZiw+yIq9IwuPgTBDrK8mIxYoDKEbOwnGdj3JB8w5AQr3sRHLoFLaqzXdZ0xVPjPLWP1NFgSmRFkn097aKx1k30VCcoLJe80uBj1JcrQlE4R9Uic3T2GYBENo+xgQ49fKiwZcBoscBpUl7re94G29uYlhGb/hab6FqtYYhn0C0VKLQVgzRiTiPAwuPLH7DN360c9X3tr/MAE5mdSl7e1l4CCxxd2FQubmgSW8UuOWO9vGppVNa3PbCpi18Vs29/P5ik3ILCgjYyyKVe+KAXiAP6Qm3dL+KK1F6np3coRE6pXr/JUJwLu45nXqsPRExTe3jkoC7+jsyZR/Vx0FwIP6qAdJDCEcw0BCDXP/nEn+d+xjmnnejr068H20jwHmKlo3ujffcecINjVU2Ce3OJ3SpHFe37owVu5cdvOh3Dx5mtNi03Rf+hWjHeRFzWWnu1b7oOXCoHFDW7WNCw8Nsva+fvCz/AxzbsAw8xvhDkwcwO3DZKt54m8z4VJUrU0b22RtsXQ64L9/PP+SzN9wUg+tMXfQgTP2lThpQknPa+WEwR2lR86BXaRHPejQIz3aRlyrts3p0qHruBwO0OswsjoFDtW945yQwZ4adwifULLRam0X2VCPKWEMxigKjgfrHM7OVf5GizCdpKZjRabQJQuI0CkOer7d8GRBbcxg4FQEt0Htj4tYHLLCUKYxgoNQVzEm8FtjOdhq00IV8S1jfS9g6WlvQeQ/B/1NmHsEXuu1H8FC5AH2zNqhLE82m77WKmAM3lhaFQntDiP4MvKzv3oAMRFdjp2RFWG8SD7BwIqW5Zgam77x0xhPkHzaMQdKxDyzEBLgYYnUTkeVVsbFsbdBIlF1o6wO9cMg4nYBlZZEI8mMEh1ecRzHgnWThms/3Q7BOvfj+D7QGsSNmC3YkbcyPwpTjPUJM2y2DFF0z7quic4aqgVvKXY6xVLcnDdtbkOTs808r9PPyAZDsRaRDe7TIC2aurZH0CECD4soSdIJNGc3QdKfw3N8ynAY9+7UBPM6ZEFssfYsU3r2Zx89ctvIreOUR4Kr5q1GKaPJ1ZjwUG0ZxlXN0q5T1V0szTqMi8w+Oxo3u+MNuAyGhCk3ils1KmXeJ7swizAjz1lh/ycOfhiL0MGOAlBp4YECADaqfZqIFI6gfdzIQUZ0f+OTiogw+Cgd92bu/xOlh7bbop8u4kNbUskmC9NcxKff8MreY16Qm9TI5O04VvJ1bCOme0RYwaJvsNgrE5VcnItvneZF++aIv083W2TtsfH/d3Km7N0Fdyc4KXfrtY7qW/bYzzVuErQzsOr0qjDKefu6EFt/4poX6ENW7ZlX4xWbytYrVfPAvmasPToHTpWYz59eOAjIT/6a4ph9nVbDDHA3R6M+b7ORLiTKgkoFdOCILrdeVlxmeYobUc/t7iAeUj6hWUUe4K1kUKveDYto/BzCzEkZpSirTh2Z68bZYWzdgac8CPMznuNZyszKUdD1P8pTkXhZAB7IgPpbBaTi83pTpmLiSajyji4Epg9/0omKDRLv/btXsX8pM5QmVHF9dvQb9rQXmyJAhLine truncated
gr, _ = gzip.NewReader(bytes.NewBuffer(bs))
bs, _ = ioutil.ReadAll(gr)
assets["scripts/syncthing/core/controllers/syncthingController.js"] = bs
+28
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()
+1
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
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
}
+1
View File
@@ -18,4 +18,5 @@ package stats
// Same key space as files/leveldb.go keyType* constants
const (
keyTypeDeviceStatistic = iota + 30
keyTypeFolderStatistic
)