Add folder label in addition to ID (fixes #966)

An auto generated ID is suggested on folder creation to reduce conflicts with
folders created on other devices.
This commit is contained in:
Lars K.W. Gohlke 2016-03-11 09:48:46 +00:00 committed by Jakob Borg
parent 1875f7287e
commit 16c3d39fd2
13 changed files with 160 additions and 104 deletions

View File

@ -141,6 +141,10 @@ table.table-condensed td {
white-space: nowrap;
}
table.table-condensed td.no-overflow-ellipse {
white-space: normal;
}
.folder-advanced{
background-color: hsla(0,0%,99%,1);
border: 1px solid hsla(0, 0%, 95%, 1);

View File

@ -165,16 +165,19 @@
</div>
<div class="panel-body">
<p>
<span translate translate-value-device="{{ deviceName(findDevice(event.data.device)) }}" translate-value-folder="{{ event.data.folder }}">
<span ng-if="event.data.folderLabel.length == 0" translate translate-value-device="{{ deviceName(findDevice(event.data.device)) }}" translate-value-folder="{{ event.data.folder }}">
{%device%} wants to share folder "{%folder%}".
</span>
<span ng-if="event.data.folderLabel.length != 0" translate translate-value-device="{{ deviceName(findDevice(event.data.device)) }}" translate-value-folder="{{ event.data.folder }}" translate-value-folderLabel="{{ event.data.folderLabel }}">
{%device%} wants to share folder "{%folderLabel%}" ({%folder%}).
</span>
<span translate ng-if="folders[event.data.folder]">Share this folder?</span>
<span translate ng-if="!folders[event.data.folder]">Add new folder?</span>
</p>
</div>
<div class="panel-footer clearfix">
<div class="pull-right">
<button type="button" class="btn btn-sm btn-success" ng-click="addFolderAndShare(event.data.folder, event.data.device)" ng-if="!folders[event.data.folder]">
<button type="button" class="btn btn-sm btn-success" ng-click="addFolderAndShare(event.data.folder, event.data.folderLabel, event.data.device)" ng-if="!folders[event.data.folder]">
<span class="fa fa-check"></span>&nbsp;<span translate>Add</span>
</button>
<button type="button" class="btn btn-sm btn-success" ng-click="shareFolderWithDevice(event.data.folder, event.data.device)" ng-if="folders[event.data.folder]">
@ -222,7 +225,9 @@
<div class="panel-progress" ng-show="folderStatus(folder) == 'syncing'" ng-attr-style="width: {{syncPercentage(folder.id)}}%"></div>
<div class="panel-progress" ng-show="folderStatus(folder) == 'scanning' && scanProgress[folder.id] != undefined" ng-attr-style="width: {{scanPercentage(folder.id)}}%"></div>
<h3 class="panel-title">
<span class="fa hidden-xs fa-fw" ng-class="[folder.readOnly ? 'fa-lock' : 'fa-folder']"></span>{{folder.id}}
<span class="fa hidden-xs fa-fw" ng-class="[folder.readOnly ? 'fa-lock' : 'fa-folder']"></span>
<span ng-show="folder.label.length == 0">{{folder.id}}</span>
<span title="{{folder.id}}" ng-show="folder.label.length != 0">{{folder.label}}</span>
<span class="pull-right text-{{folderClass(folder)}}" ng-switch="folderStatus(folder)">
<span ng-switch-when="unknown"><span class="hidden-xs" translate>Unknown</span><span class="visible-xs">&#9724;</span></span>
<span ng-switch-when="unshared"><span class="hidden-xs" translate>Unshared</span><span class="visible-xs">&#9724;</span></span>
@ -247,6 +252,10 @@
<div class="panel-body">
<table class="table table-condensed table-striped">
<tbody>
<tr ng-show="folder.label != undefined && folder.label.length > 0">
<th><span class="fa fa-fw fa-folder-open"></span>&nbsp;<span translate>Folder ID</span></th>
<td class="text-right no-overflow-ellipse">{{folder.id}}</td>
</tr>
<tr>
<th><span class="fa fa-fw fa-folder-open"></span>&nbsp;<span translate>Folder Path</span></th>
<td class="text-right" title="{{folder.path}}">{{folder.path}}</td>
@ -583,6 +592,7 @@
<script src="vendor/jquery/jquery-2.0.3.min.js"></script>
<script src="vendor/angular/angular.min.js"></script>
<script src="vendor/angular/angular-translate.min.js"></script>
<script src="vendor/angular/angular-translate-handler-log.min.js"></script>
<script src="vendor/angular/angular-translate-loader.min.js"></script>
<script src="vendor/angular/angular-dirPagination.js"></script>
<script src="vendor/bootstrap/js/bootstrap.min.js"></script>

View File

@ -29,8 +29,6 @@ syncthing.config(function ($httpProvider, $translateProvider, LocaleServiceProvi
return {
response: function onResponse(response) {
var headers = response.headers();
var responseVersion;
var deviceIdShort;
// angular template cache sends no headers
if(Object.keys(headers).length === 0) {
@ -40,7 +38,7 @@ syncthing.config(function ($httpProvider, $translateProvider, LocaleServiceProvi
if (!deviceId) {
deviceId = headers['x-syncthing-id'];
if (deviceId) {
deviceIdShort = deviceId.substring(0, 5);
var deviceIdShort = deviceId.substring(0, 5);
$httpProvider.defaults.xsrfHeaderName = 'X-CSRF-Token-' + deviceIdShort;
$httpProvider.defaults.xsrfCookieName = 'CSRF-Token-' + deviceIdShort;
}
@ -57,6 +55,7 @@ syncthing.config(function ($httpProvider, $translateProvider, LocaleServiceProvi
prefix: 'assets/lang/lang-',
suffix: '.json'
});
$translateProvider.useMissingTranslationHandlerLog();
LocaleServiceProvider.setAvailableLocales(validLangs);
LocaleServiceProvider.setDefaultLocale('en');
@ -114,9 +113,14 @@ function decimals(val, num) {
}
function randomString(len) {
var i, result = '', chars = '01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-';
for (i = 0; i < len; i++) {
result += chars[Math.round(Math.random() * (chars.length - 1))];
var chars = '01234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-';
return randomStringFromCharset(len, chars);
}
function randomStringFromCharset(len, charset) {
var result = '';
for (var i = 0; i < len; i++) {
result += charset[Math.round(Math.random() * (charset.length - 1))];
}
return result;
}
@ -150,7 +154,6 @@ function debounce(func, wait) {
context = this;
args = arguments;
timestamp = Date.now();
var callNow = !timeout;
if (!timeout) {
timeout = setTimeout(later, wait);
result = func.apply(context, args);

View File

@ -90,7 +90,7 @@ angular.module('syncthing.core')
refreshFolderStats();
$http.get(urlbase + '/system/version').success(function (data) {
if ($scope.version.version && $scope.version.version != data.version) {
if ($scope.version.version && $scope.version.version !== data.version) {
// We already have a version response, but it differs from
// the new one. Reload the full GUI in case it's changed.
document.location.reload(true);
@ -271,10 +271,10 @@ angular.module('syncthing.core')
}
for (var folder in $scope.progress) {
if (!(folder in progress)) {
if ($scope.neededFolder == folder) {
if ($scope.neededFolder === folder) {
refreshNeed(folder);
}
} else if ($scope.neededFolder == folder) {
} else if ($scope.neededFolder === folder) {
for (file in $scope.progress[folder]) {
if (!(file in progress[folder])) {
refreshNeed(folder);
@ -322,7 +322,7 @@ angular.module('syncthing.core')
$scope.scanProgress[data.folder] = {
current: data.current,
total: data.total,
rate: data.rate,
rate: data.rate
};
console.log("FolderScanProgress", data);
});
@ -374,8 +374,8 @@ angular.module('syncthing.core')
// authentication configured, and the magic setting to silence the
// warning isn't set, then yell at the user.
var guiCfg = $scope.config.gui;
$scope.openNoAuth = guiCfg.address.substr(0, 4) != "127."
&& guiCfg.address.substr(0, 6) != "[::1]:"
$scope.openNoAuth = guiCfg.address.substr(0, 4) !== "127."
&& guiCfg.address.substr(0, 6) !== "[::1]:"
&& (!guiCfg.user || !guiCfg.password)
&& !guiCfg.insecureAdminAccess;
@ -509,7 +509,7 @@ angular.module('syncthing.core')
url += "&page=" + $scope.neededCurrentPage;
url += "&perpage=" + $scope.neededPageSize;
$http.get(url).success(function (data) {
if ($scope.neededFolder == folder) {
if ($scope.neededFolder === folder) {
console.log("refreshNeed", folder, data);
parseNeeded(data);
}
@ -631,10 +631,10 @@ angular.module('syncthing.core')
$scope.folderClass = function (folderCfg) {
var status = $scope.folderStatus(folderCfg);
if (status == 'idle') {
if (status === 'idle') {
return 'success';
}
if (status == 'syncing' || status == 'scanning') {
if (status === 'syncing' || status === 'scanning') {
return 'primary';
}
if (status === 'unknown') {
@ -668,14 +668,14 @@ angular.module('syncthing.core')
}
var pct = 100 * $scope.scanProgress[folder].current / $scope.scanProgress[folder].total;
return Math.floor(pct);
}
};
$scope.scanRate = function (folder) {
if (!$scope.scanProgress[folder]) {
return 0;
}
return $scope.scanProgress[folder].rate;
}
};
$scope.scanRemaining = function (folder) {
// Formats the remaining scan time as a string. Includes days and
@ -685,23 +685,22 @@ angular.module('syncthing.core')
// 2h 32m
// 4d 2h
var res = [];
if (!$scope.scanProgress[folder]) {
return "";
}
// Calculate remaining bytes and seconds based on our current
// rate.
var remainingBytes = $scope.scanProgress[folder].total - $scope.scanProgress[folder].current;
var seconds = remainingBytes / $scope.scanProgress[folder].rate;
// Round up to closest ten seconds to avoid flapping too much to
// and fro.
seconds = Math.ceil(seconds / 10) * 10;
// Separate out the number of days.
var days = 0;
var res = [];
if (seconds >= 86400) {
days = Math.floor(seconds / 86400);
res.push('' + days + 'd')
@ -718,20 +717,20 @@ angular.module('syncthing.core')
var d = new Date(1970, 0, 1).setSeconds(seconds);
if (days == 0) {
if (days === 0) {
// Format minutes only if we're within a day of completion.
var f = $filter('date')(d, "m'm'");
res.push(f);
}
if (days == 0 && hours == 0) {
if (days === 0 && hours === 0) {
// Format seconds only when we're within an hour of completion.
var f = $filter('date')(d, "ss's'");
res.push(f);
}
return res.join(' ');
}
};
$scope.deviceStatus = function (deviceCfg) {
if ($scope.deviceFolders(deviceCfg).length === 0) {
@ -802,9 +801,9 @@ angular.module('syncthing.core')
$scope.findDevice = function (deviceID) {
var matches = $scope.devices.filter(function (n) {
return n.deviceID == deviceID;
return n.deviceID === deviceID;
});
if (matches.length != 1) {
if (matches.length !== 1) {
return undefined;
}
return matches[0];
@ -1029,17 +1028,15 @@ angular.module('syncthing.core')
};
$scope.saveDeviceConfig = function (deviceCfg) {
var done, i;
deviceCfg.addresses = deviceCfg._addressesStr.split(',').map(function (x) {
return x.trim();
});
done = false;
for (i = 0; i < $scope.devices.length; i++) {
var done = false;
for (var i = 0; i < $scope.devices.length && !done; i++) {
if ($scope.devices[i].deviceID === deviceCfg.deviceID) {
$scope.devices[i] = deviceCfg;
done = true;
break;
}
}
@ -1059,7 +1056,7 @@ angular.module('syncthing.core')
if (deviceCfg.selectedFolders[id]) {
var found = false;
for (i = 0; i < $scope.folders[id].devices.length; i++) {
if ($scope.folders[id].devices[i].deviceID == deviceCfg.deviceID) {
if ($scope.folders[id].devices[i].deviceID === deviceCfg.deviceID) {
found = true;
break;
}
@ -1072,7 +1069,7 @@ angular.module('syncthing.core')
}
} else {
$scope.folders[id].devices = $scope.folders[id].devices.filter(function (n) {
return n.deviceID != deviceCfg.deviceID;
return n.deviceID !== deviceCfg.deviceID;
});
}
}
@ -1097,10 +1094,8 @@ angular.module('syncthing.core')
};
$scope.thisDevice = function () {
var i, n;
for (i = 0; i < $scope.devices.length; i++) {
n = $scope.devices[i];
for (var i = 0; i < $scope.devices.length; i++) {
var n = $scope.devices[i];
if (n.deviceID === $scope.myID) {
return n;
}
@ -1142,7 +1137,7 @@ angular.module('syncthing.core')
$scope.directoryList = [];
$scope.$watch('currentFolder.path', function (newvalue) {
if (newvalue && newvalue.trim().charAt(0) == '~') {
if (newvalue && newvalue.trim().charAt(0) === '~') {
$scope.currentFolder.path = $scope.system.tilde + newvalue.trim().substring(1);
}
$http.get(urlbase + '/system/browse', {
@ -1154,7 +1149,7 @@ angular.module('syncthing.core')
$scope.editFolder = function (folderCfg) {
$scope.currentFolder = angular.copy(folderCfg);
if ($scope.currentFolder.path.slice(-1) == $scope.system.pathSeparator) {
if ($scope.currentFolder.path.slice(-1) === $scope.system.pathSeparator) {
$scope.currentFolder.path = $scope.currentFolder.path.slice(0, -1);
}
$scope.currentFolder.selectedDevices = {};
@ -1202,30 +1197,8 @@ angular.module('syncthing.core')
$scope.addFolder = function () {
$scope.currentFolder = {
selectedDevices: {}
};
$scope.currentFolder.rescanIntervalS = 60;
$scope.currentFolder.minDiskFreePct = 1;
$scope.currentFolder.maxConflicts = 10;
$scope.currentFolder.order = "random";
$scope.currentFolder.fileVersioningSelector = "none";
$scope.currentFolder.trashcanClean = 0;
$scope.currentFolder.simpleKeep = 5;
$scope.currentFolder.staggeredMaxAge = 365;
$scope.currentFolder.staggeredCleanInterval = 3600;
$scope.currentFolder.staggeredVersionsPath = "";
$scope.currentFolder.externalCommand = "";
$scope.currentFolder.autoNormalize = true;
$scope.editingExisting = false;
$scope.folderEditor.$setPristine();
$('#editFolder').modal();
};
$scope.addFolderAndShare = function (folder, device) {
$scope.dismissFolderRejection(folder, device);
$scope.currentFolder = {
id: folder,
selectedDevices: {},
id: $scope.createRandomFolderId(),
rescanIntervalS: 60,
minDiskFreePct: 1,
maxConflicts: 10,
@ -1239,6 +1212,33 @@ angular.module('syncthing.core')
externalCommand: "",
autoNormalize: true
};
$scope.editingExisting = false;
$scope.folderEditor.$setPristine();
$('#editFolder').modal();
};
$scope.addFolderAndShare = function (folder, folderLabel, device) {
$scope.dismissFolderRejection(folder, device);
$scope.currentFolder = {
id: folder,
label: folderLabel,
selectedDevices: {},
rescanIntervalS: 60,
minDiskFreePct: 1,
maxConflicts: 10,
order: "random",
fileVersioningSelector: "none",
trashcanClean: 0,
simpleKeep: 5,
staggeredMaxAge: 365,
staggeredCleanInterval: 3600,
staggeredVersionsPath: "",
externalCommand: "",
autoNormalize: true,
viewFlags: {
importFromOtherDevice: true
}
};
$scope.currentFolder.selectedDevices[device] = true;
$scope.editingExisting = false;
@ -1256,10 +1256,8 @@ angular.module('syncthing.core')
};
$scope.saveFolder = function () {
var folderCfg, done, i;
$('#editFolder').modal('hide');
folderCfg = $scope.currentFolder;
var folderCfg = $scope.currentFolder;
folderCfg.devices = [];
folderCfg.selectedDevices[$scope.myID] = true;
for (var deviceID in folderCfg.selectedDevices) {
@ -1329,7 +1327,7 @@ angular.module('syncthing.core')
$scope.sharesFolder = function (folderCfg) {
var names = [];
folderCfg.devices.forEach(function (device) {
if (device.deviceID != $scope.myID) {
if (device.deviceID !== $scope.myID) {
names.push($scope.deviceName($scope.findDevice(device.deviceID)));
}
});
@ -1342,8 +1340,9 @@ angular.module('syncthing.core')
for (var folderID in $scope.folders) {
var devices = $scope.folders[folderID].devices;
for (var i = 0; i < devices.length; i++) {
if (devices[i].deviceID == deviceCfg.deviceID) {
folders.push(folderID);
if (devices[i].deviceID === deviceCfg.deviceID) {
var label = $scope.folders[folderID].label;
folders.push(label.length > 0 ? label : folderID);
break;
}
}
@ -1445,7 +1444,7 @@ angular.module('syncthing.core')
};
$scope.showFailed = function (folder) {
$scope.failedCurrent = $scope.failed[folder]
$scope.failedCurrent = $scope.failed[folder];
$('#failed').modal().on('hidden.bs.modal', function () {
$scope.failedCurrent = undefined;
});
@ -1455,10 +1454,10 @@ angular.module('syncthing.core')
if (!$scope.failed[folder]) {
return false;
}
if ($scope.failed[folder].length == 0) {
if ($scope.failed[folder].length === 0) {
return false;
}
return true
return true;
};
$scope.override = function (folder) {
@ -1492,7 +1491,7 @@ angular.module('syncthing.core')
url += "&page=" + $scope.neededCurrentPage;
url += "&perpage=" + $scope.neededPageSize;
$http.post(url).success(function (data) {
if ($scope.neededFolder == folder) {
if ($scope.neededFolder === folder) {
console.log("bumpFile", folder, data);
parseNeeded(data);
}
@ -1512,7 +1511,7 @@ angular.module('syncthing.core')
'netbsd': 'NetBSD',
'linux': 'Linux',
'windows': 'Windows',
'solaris': 'Solaris',
'solaris': 'Solaris'
}[$scope.version.os] || $scope.version.os;
var arch ={
@ -1521,7 +1520,7 @@ angular.module('syncthing.core')
'arm': 'ARM',
'arm64': 'AArch64',
'ppc64': 'PowerPC',
'ppc64le': 'PowerPC (LE)',
'ppc64le': 'PowerPC (LE)'
}[$scope.version.arch] || $scope.version.arch;
return $scope.version.version + ', ' + os + ' (' + arch + ')';
@ -1546,6 +1545,11 @@ angular.module('syncthing.core')
return 'text';
};
$scope.createRandomFolderId = function(){
var charset = '2345679abcdefghijkmnopqrstuvwxyzACDEFGHJKLMNPQRSTUVWXYZ';
return randomStringFromCharset(5, charset) + "-" + randomStringFromCharset(5, charset);
};
// pseudo main. called on all definitions assigned
initController();
});

View File

@ -60,8 +60,11 @@
<div class="row">
<div class="col-md-4" ng-repeat="folder in folderList()">
<div class="checkbox">
<label>
<input type="checkbox" ng-model="currentDevice.selectedFolders[folder.id]"> {{folder.id}}
<label ng-if="folder.label.length == 0">
<input type="checkbox" ng-model="currentDevice.selectedFolders[folder.id]">&nbsp;{{folder.id}}
</label>
<label ng-if="folder.label.length != 0">
<input type="checkbox" ng-model="currentDevice.selectedFolders[folder.id]">&nbsp;<span title="{{folder.id}}">{{folder.label}}</span>
</label>
</div>
</div>

View File

@ -11,11 +11,18 @@
<form role="form" name="folderEditor">
<div class="row">
<div class="col-md-12">
<div class="form-group" ng-class="{'has-error': folderEditor.folderLabel.$invalid && folderEditor.folderLabel.$dirty}">
<label for="folderLabel"><span translate>Folder Label</span></label>
<input name="folderLabel" id="folderLabel" class="form-control" type="text" ng-model="currentFolder.label" value="{{currentFolder.label}}"/>
<p class="help-block">
<span translate ng-if="folderEditor.folderLabel.$valid || folderEditor.folderLabel.$pristine">Optional descriptive label for the folder. Can be different on each device.</span>
</p>
</div>
<div class="form-group" ng-class="{'has-error': folderEditor.folderID.$invalid && folderEditor.folderID.$dirty}">
<label for="folderID"><span translate>Folder ID</span></label>
<input name="folderID" ng-readonly="editingExisting" id="folderID" class="form-control" type="text" ng-model="currentFolder.id" required unique-folder>
<input name="folderID" ng-readonly="editingExisting || (!editingExisting && currentFolder.viewFlags.importFromOtherDevice)" id="folderID" class="form-control" type="text" ng-model="currentFolder.id" required unique-folder value="{{currentFolder.id}}"/>
<p class="help-block">
<span translate ng-if="folderEditor.folderID.$valid || folderEditor.folderID.$pristine">Short identifier for the folder. Must be the same on all cluster devices.</span>
<span translate ng-if="folderEditor.folderID.$valid || folderEditor.folderID.$pristine">Required identifier for the folder. Must be the same on all cluster devices.</span>
<span translate ng-if="folderEditor.folderID.$error.uniqueFolder">The folder ID must be unique.</span>
<span translate ng-if="folderEditor.folderID.$error.required && folderEditor.folderID.$dirty">The folder ID cannot be blank.</span>
</p>

View File

@ -51,8 +51,11 @@
<div class="panel panel-default" ng-repeat="folder in advancedConfig.folders">
<div class="panel-heading" role="tab" id="folder{{$index}}Heading" data-toggle="collapse" data-parent="#advancedAccordion" href="#folder{{$index}}Config" aria-expanded="true" aria-controls="folder{{$index}}Config" style="cursor: pointer">
<h4 class="panel-title">
<span translate>Folder</span> "{{folder.id}}"
<h4 ng-if="folder.label.length == 0" class="panel-title">
<span translate>Folder</span> "{{folder.id}}"
</h4>
<h4 ng-if="folder.label.length != 0" class="panel-title">
<span translate>Folder</span> "{{folder.label}}" ({{folder.id}})
</h4>
</div>
<div id="folder{{$index}}Config" class="panel-collapse collapse" role="tabpanel" aria-labelledby="folder{{$index}}Heading">

View File

@ -0,0 +1,6 @@
/*!
* angular-translate - v2.10.0 - 2016-02-28
*
* Copyright (c) 2016 The angular-translate team, Pascal Precht; Licensed MIT
*/
!function(a,b){"function"==typeof define&&define.amd?define([],function(){return b()}):"object"==typeof exports?module.exports=b():b()}(this,function(){function a(a){"use strict";return function(b){a.warn("Translation for "+b+" doesn't exist")}}return angular.module("pascalprecht.translate").factory("$translateMissingTranslationHandlerLog",a),a.$inject=["$log"],a.displayName="$translateMissingTranslationHandlerLog","pascalprecht.translate"});

File diff suppressed because one or more lines are too long

View File

@ -18,6 +18,7 @@ import (
type FolderConfiguration struct {
ID string `xml:"id,attr" json:"id"`
Label string `xml:"label,attr" json:"label"`
RawPath string `xml:"path,attr" json:"path"`
Devices []FolderDeviceConfiguration `xml:"device" json:"devices"`
ReadOnly bool `xml:"ro,attr" json:"readOnly"`

View File

@ -650,8 +650,9 @@ nextFolder:
if !m.folderSharedWithUnlocked(folder.ID, deviceID) {
events.Default.Log(events.FolderRejected, map[string]string{
"folder": folder.ID,
"device": deviceID.String(),
"folder": folder.ID,
"folderLabel": folder.Label,
"device": deviceID.String(),
})
l.Infof("Unexpected folder ID %q sent from device %q; ensure that the folder exists and that this device is selected under \"Share With\" in the folder configuration.", folder.ID, deviceID)
continue
@ -1530,7 +1531,7 @@ func (m *Model) numHashers(folder string) int {
// generateClusterConfig returns a ClusterConfigMessage that is correct for
// the given peer device
func (m *Model) generateClusterConfig(device protocol.DeviceID) protocol.ClusterConfigMessage {
cm := protocol.ClusterConfigMessage{
message := protocol.ClusterConfigMessage{
DeviceName: m.deviceName,
ClientName: m.clientName,
ClientVersion: m.clientVersion,
@ -1539,8 +1540,9 @@ func (m *Model) generateClusterConfig(device protocol.DeviceID) protocol.Cluster
m.fmut.RLock()
for _, folder := range m.deviceFolders[device] {
folderCfg := m.cfg.Folders()[folder]
cr := protocol.Folder{
ID: folder,
protocolFolder := protocol.Folder{
ID: folder,
Label: folderCfg.Label,
}
var flags uint32
if folderCfg.ReadOnly {
@ -1552,7 +1554,7 @@ func (m *Model) generateClusterConfig(device protocol.DeviceID) protocol.Cluster
if folderCfg.IgnoreDelete {
flags |= protocol.FlagFolderIgnoreDelete
}
cr.Flags = flags
protocolFolder.Flags = flags
for _, device := range m.folderDevices[folder] {
// DeviceID is a value type, but with an underlying array. Copy it
// so we don't grab aliases to the same array later on in device[:]
@ -1560,7 +1562,7 @@ func (m *Model) generateClusterConfig(device protocol.DeviceID) protocol.Cluster
// TODO: Set read only bit when relevant, and when we have per device
// access controls.
deviceCfg := m.cfg.Devices()[device]
cn := protocol.Device{
protocolDevice := protocol.Device{
ID: device[:],
Name: deviceCfg.Name,
Addresses: deviceCfg.Addresses,
@ -1570,15 +1572,15 @@ func (m *Model) generateClusterConfig(device protocol.DeviceID) protocol.Cluster
}
if deviceCfg.Introducer {
cn.Flags |= protocol.FlagIntroducer
protocolDevice.Flags |= protocol.FlagIntroducer
}
cr.Devices = append(cr.Devices, cn)
protocolFolder.Devices = append(protocolFolder.Devices, protocolDevice)
}
cm.Folders = append(cm.Folders, cr)
message.Folders = append(message.Folders, protocolFolder)
}
m.fmut.RUnlock()
return cm
return message
}
func (m *Model) State(folder string) (string, time.Time, error) {

View File

@ -143,6 +143,7 @@ func (o *ClusterConfigMessage) GetOption(key string) string {
type Folder struct {
ID string // max:256
Label string // max:256
Devices []Device // max:1000000
Flags uint32
Options []Option // max:64

View File

@ -656,6 +656,10 @@ Folder Structure:
\ ID (length + padded data) \
/ /
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/ /
\ Label (length + padded data) \
/ /
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
| Number of Devices |
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
/ /
@ -674,6 +678,7 @@ Folder Structure:
struct Folder {
string ID<256>;
string Label<256>;
Device Devices<1000000>;
unsigned int Flags;
Option Options<64>;
@ -683,6 +688,7 @@ struct Folder {
func (o Folder) XDRSize() int {
return 4 + len(o.ID) + xdr.Padding(len(o.ID)) +
4 + len(o.Label) + xdr.Padding(len(o.Label)) +
4 + xdr.SizeOfSlice(o.Devices) + 4 +
4 + xdr.SizeOfSlice(o.Options)
}
@ -706,6 +712,10 @@ func (o Folder) MarshalXDRInto(m *xdr.Marshaller) error {
return xdr.ElementSizeExceeded("ID", l, 256)
}
m.MarshalString(o.ID)
if l := len(o.Label); l > 256 {
return xdr.ElementSizeExceeded("Label", l, 256)
}
m.MarshalString(o.Label)
if l := len(o.Devices); l > 1000000 {
return xdr.ElementSizeExceeded("Devices", l, 1000000)
}
@ -734,6 +744,7 @@ func (o *Folder) UnmarshalXDR(bs []byte) error {
}
func (o *Folder) UnmarshalXDRFrom(u *xdr.Unmarshaller) error {
o.ID = u.UnmarshalStringMax(256)
o.Label = u.UnmarshalStringMax(256)
_DevicesSize := int(u.UnmarshalUint32())
if _DevicesSize < 0 {
return xdr.ElementSizeExceeded("Devices", _DevicesSize, 1000000)