all: Add a global change list

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/3694
This commit is contained in:
Nathan Morrison 2016-12-21 16:35:20 +00:00 committed by Audrius Butkevicius
parent dd7bb6c4b8
commit 0725e3af38
13 changed files with 228 additions and 36 deletions

View File

@ -554,8 +554,8 @@ func syncthingMain(runtimeOptions RuntimeOptions) {
// Event subscription for the API; must start early to catch the early // Event subscription for the API; must start early to catch the early
// events. The LocalChangeDetected event might overwhelm the event // events. The LocalChangeDetected event might overwhelm the event
// receiver in some situations so we will not subscribe to it here. // receiver in some situations so we will not subscribe to it here.
apiSub := events.NewBufferedSubscription(events.Default.Subscribe(events.AllEvents&^events.LocalChangeDetected), 1000) apiSub := events.NewBufferedSubscription(events.Default.Subscribe(events.AllEvents&^events.LocalChangeDetected&^events.RemoteChangeDetected), 1000)
diskSub := events.NewBufferedSubscription(events.Default.Subscribe(events.LocalChangeDetected), 1000) diskSub := events.NewBufferedSubscription(events.Default.Subscribe(events.LocalChangeDetected|events.RemoteChangeDetected), 1000)
if len(os.Getenv("GOMAXPROCS")) == 0 { if len(os.Getenv("GOMAXPROCS")) == 0 {
runtime.GOMAXPROCS(runtime.NumCPU()) runtime.GOMAXPROCS(runtime.NumCPU())

View File

@ -94,9 +94,12 @@ func (s *verboseService) formatEvent(ev events.Event) string {
case events.LocalChangeDetected: case events.LocalChangeDetected:
data := ev.Data.(map[string]string) data := ev.Data.(map[string]string)
// Local change detected in folder "foo": modified file /Users/jb/whatever
return fmt.Sprintf("Local change detected in folder %q: %s %s %s", data["folder"], data["action"], data["type"], data["path"]) return fmt.Sprintf("Local change detected in folder %q: %s %s %s", data["folder"], data["action"], data["type"], data["path"])
case events.RemoteChangeDetected:
data := ev.Data.(map[string]string)
return fmt.Sprintf("Remote change detected in folder %q: %s %s %s", data["folder"], data["action"], data["type"], data["path"])
case events.RemoteIndexUpdated: case events.RemoteIndexUpdated:
data := ev.Data.(map[string]interface{}) data := ev.Data.(map[string]interface{})
return fmt.Sprintf("Device %v sent an index update for %q with %d items", data["device"], data["folder"], data["items"]) return fmt.Sprintf("Device %v sent an index update for %q with %d items", data["device"], data["folder"], data["items"])

View File

@ -617,9 +617,14 @@
</div> </div>
</div> </div>
<div class="form-group"> <div class="form-group">
<button type="button" class="btn btn-sm btn-default pull-right" ng-click="addDevice()"> <span class="pull-right">
<span class="fa fa-plus"></span>&nbsp;<span translate>Add Remote Device</span> <button type="button" class="btn btn-sm btn-default" ng-click="globalChanges()">
</button> <span class="fa fa-fw fa-history"></span>&nbsp;<span translate>Global Changes</span>
</button>
<button type="button" class="btn btn-sm btn-default" ng-click="addDevice()">
<span class="fa fa-plus"></span>&nbsp;<span translate>Add Remote Device</span>
</button>
</span>
<div class="clearfix"></div> <div class="clearfix"></div>
</div> </div>
</div> </div>
@ -651,6 +656,7 @@
<ng-include src="'syncthing/core/shutdownDialogView.html'"></ng-include> <ng-include src="'syncthing/core/shutdownDialogView.html'"></ng-include>
<ng-include src="'syncthing/device/idqrModalView.html'"></ng-include> <ng-include src="'syncthing/device/idqrModalView.html'"></ng-include>
<ng-include src="'syncthing/device/editDeviceModalView.html'"></ng-include> <ng-include src="'syncthing/device/editDeviceModalView.html'"></ng-include>
<ng-include src="'syncthing/device/globalChangesModalView.html'"></ng-include>
<ng-include src="'syncthing/folder/editFolderModalView.html'"></ng-include> <ng-include src="'syncthing/folder/editFolderModalView.html'"></ng-include>
<ng-include src="'syncthing/folder/editIgnoresModalView.html'"></ng-include> <ng-include src="'syncthing/folder/editIgnoresModalView.html'"></ng-include>
<ng-include src="'syncthing/settings/settingsModalView.html'"></ng-include> <ng-include src="'syncthing/settings/settingsModalView.html'"></ng-include>

View File

@ -51,6 +51,7 @@ angular.module('syncthing.core')
$scope.failedPageSize = 10; $scope.failedPageSize = 10;
$scope.scanProgress = {}; $scope.scanProgress = {};
$scope.themes = []; $scope.themes = [];
$scope.globalChangeEvents = {};
$scope.localStateTotal = { $scope.localStateTotal = {
bytes: 0, bytes: 0,
@ -186,6 +187,7 @@ angular.module('syncthing.core')
$scope.$on(Events.LOCAL_INDEX_UPDATED, function (event, arg) { $scope.$on(Events.LOCAL_INDEX_UPDATED, function (event, arg) {
refreshFolderStats(); refreshFolderStats();
refreshGlobalChanges();
}); });
$scope.$on(Events.DEVICE_DISCONNECTED, function (event, arg) { $scope.$on(Events.DEVICE_DISCONNECTED, function (event, arg) {
@ -629,6 +631,15 @@ angular.module('syncthing.core')
}).error($scope.emitHTTPError); }).error($scope.emitHTTPError);
}, 2500); }, 2500);
var refreshGlobalChanges = debounce(function () {
$http.get(urlbase + "/events/disk?limit=15").success(function (data) {
data = data.reverse();
$scope.globalChangeEvents = data;
console.log("refreshGlobalChanges", data);
}).error($scope.emitHTTPError);
}, 2500);
$scope.refresh = function () { $scope.refresh = function () {
refreshSystem(); refreshSystem();
refreshDiscoveryCache(); refreshDiscoveryCache();
@ -912,6 +923,16 @@ angular.module('syncthing.core')
return ''; return '';
}; };
$scope.friendlyNameFromShort = function (shortID) {
var matches = $scope.devices.filter(function (n) {
return n.deviceID.substr(0, 7) === shortID;
});
if (matches.length !== 1) {
return shortID;
}
return matches[0].name;
};
$scope.findDevice = function (deviceID) { $scope.findDevice = function (deviceID) {
var matches = $scope.devices.filter(function (n) { var matches = $scope.devices.filter(function (n) {
return n.deviceID === deviceID; return n.deviceID === deviceID;
@ -1268,7 +1289,11 @@ angular.module('syncthing.core')
$scope.folderEditor = form; $scope.folderEditor = form;
break; break;
} }
} };
$scope.globalChanges = function () {
$('#globalChanges').modal();
};
$scope.editFolder = function (folderCfg) { $scope.editFolder = function (folderCfg) {
$scope.currentFolder = angular.copy(folderCfg); $scope.currentFolder = angular.copy(folderCfg);

View File

@ -0,0 +1,27 @@
<style> th, td { padding: 6px; } </style>
<modal id="globalChanges" status="default" icon="{{'history'}}" heading="{{'Global Changes' | translate}}" large="yes" closeable="yes">
<div class="modal-body">
<table>
<tr>
<th translate>Device</th>
<th translate>Action</th>
<th translate>Type</th>
<th translate>Path</th>
<th translate>Time</th>
</tr>
<tr ng-repeat="changeEvent in globalChangeEvents">
<td ng-if="changeEvent.data.modifiedBy">{{friendlyNameFromShort(changeEvent.data.modifiedBy)}}</td>
<td ng-if="!changeEvent.data.modifiedBy"><span translate>Unknown</span></td>
<td>{{changeEvent.data.action}}</td>
<td>{{changeEvent.data.type}}</td>
<td>{{changeEvent.data.path}}</td>
<td>{{changeEvent.time | date:'medium'}}</td>
</tr>
</table>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default btn-sm" data-dismiss="modal">
<span class="fa fa-times"></span>&nbsp;<span translate>Close</span>
</button>
</div>
</model>

View File

@ -58,6 +58,7 @@ type FileInfoTruncated struct {
Permissions uint32 `protobuf:"varint,4,opt,name=permissions,proto3" json:"permissions,omitempty"` Permissions uint32 `protobuf:"varint,4,opt,name=permissions,proto3" json:"permissions,omitempty"`
ModifiedS int64 `protobuf:"varint,5,opt,name=modified_s,json=modifiedS,proto3" json:"modified_s,omitempty"` ModifiedS int64 `protobuf:"varint,5,opt,name=modified_s,json=modifiedS,proto3" json:"modified_s,omitempty"`
ModifiedNs int32 `protobuf:"varint,11,opt,name=modified_ns,json=modifiedNs,proto3" json:"modified_ns,omitempty"` ModifiedNs int32 `protobuf:"varint,11,opt,name=modified_ns,json=modifiedNs,proto3" json:"modified_ns,omitempty"`
ModifiedBy protocol.ShortID `protobuf:"varint,12,opt,name=modified_by,json=modifiedBy,proto3,customtype=protocol.ShortID" json:"modified_by"`
Deleted bool `protobuf:"varint,6,opt,name=deleted,proto3" json:"deleted,omitempty"` Deleted bool `protobuf:"varint,6,opt,name=deleted,proto3" json:"deleted,omitempty"`
Invalid bool `protobuf:"varint,7,opt,name=invalid,proto3" json:"invalid,omitempty"` Invalid bool `protobuf:"varint,7,opt,name=invalid,proto3" json:"invalid,omitempty"`
NoPermissions bool `protobuf:"varint,8,opt,name=no_permissions,json=noPermissions,proto3" json:"no_permissions,omitempty"` NoPermissions bool `protobuf:"varint,8,opt,name=no_permissions,json=noPermissions,proto3" json:"no_permissions,omitempty"`
@ -226,6 +227,11 @@ func (m *FileInfoTruncated) MarshalTo(data []byte) (int, error) {
i++ i++
i = encodeVarintStructs(data, i, uint64(m.ModifiedNs)) i = encodeVarintStructs(data, i, uint64(m.ModifiedNs))
} }
if m.ModifiedBy != 0 {
data[i] = 0x60
i++
i = encodeVarintStructs(data, i, uint64(m.ModifiedBy))
}
if len(m.SymlinkTarget) > 0 { if len(m.SymlinkTarget) > 0 {
data[i] = 0x8a data[i] = 0x8a
i++ i++
@ -324,6 +330,9 @@ func (m *FileInfoTruncated) ProtoSize() (n int) {
if m.ModifiedNs != 0 { if m.ModifiedNs != 0 {
n += 1 + sovStructs(uint64(m.ModifiedNs)) n += 1 + sovStructs(uint64(m.ModifiedNs))
} }
if m.ModifiedBy != 0 {
n += 1 + sovStructs(uint64(m.ModifiedBy))
}
l = len(m.SymlinkTarget) l = len(m.SymlinkTarget)
if l > 0 { if l > 0 {
n += 2 + l + sovStructs(uint64(l)) n += 2 + l + sovStructs(uint64(l))
@ -798,6 +807,25 @@ func (m *FileInfoTruncated) Unmarshal(data []byte) error {
break break
} }
} }
case 12:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ModifiedBy", wireType)
}
m.ModifiedBy = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowStructs
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
m.ModifiedBy |= (protocol.ShortID(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 17: case 17:
if wireType != 2 { if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field SymlinkTarget", wireType) return fmt.Errorf("proto: wrong wireType = %d for field SymlinkTarget", wireType)

View File

@ -28,6 +28,7 @@ message FileInfoTruncated {
uint32 permissions = 4; uint32 permissions = 4;
int64 modified_s = 5; int64 modified_s = 5;
int32 modified_ns = 11; int32 modified_ns = 11;
uint64 modified_by = 12 [(gogoproto.customtype) = "protocol.ShortID", (gogoproto.nullable) = false];
bool deleted = 6; bool deleted = 6;
bool invalid = 7; bool invalid = 7;
bool no_permissions = 8; bool no_permissions = 8;

View File

@ -29,6 +29,7 @@ const (
DevicePaused DevicePaused
DeviceResumed DeviceResumed
LocalChangeDetected LocalChangeDetected
RemoteChangeDetected
LocalIndexUpdated LocalIndexUpdated
RemoteIndexUpdated RemoteIndexUpdated
ItemStarted ItemStarted
@ -68,6 +69,8 @@ func (t EventType) String() string {
return "DeviceRejected" return "DeviceRejected"
case LocalChangeDetected: case LocalChangeDetected:
return "LocalChangeDetected" return "LocalChangeDetected"
case RemoteChangeDetected:
return "RemoteChangeDetected"
case LocalIndexUpdated: case LocalIndexUpdated:
return "LocalIndexUpdated" return "LocalIndexUpdated"
case RemoteIndexUpdated: case RemoteIndexUpdated:

View File

@ -1551,12 +1551,18 @@ func (m *Model) updateLocalsFromScanning(folder string, fs []protocol.FileInfo)
m.fmut.RLock() m.fmut.RLock()
folderCfg := m.folderCfgs[folder] folderCfg := m.folderCfgs[folder]
m.fmut.RUnlock() m.fmut.RUnlock()
// Fire the LocalChangeDetected event to notify listeners about local updates.
m.localChangeDetected(folderCfg, fs) m.diskChangeDetected(folderCfg, fs, events.LocalChangeDetected)
} }
func (m *Model) updateLocalsFromPulling(folder string, fs []protocol.FileInfo) { func (m *Model) updateLocalsFromPulling(folder string, fs []protocol.FileInfo) {
m.updateLocals(folder, fs) m.updateLocals(folder, fs)
m.fmut.RLock()
folderCfg := m.folderCfgs[folder]
m.fmut.RUnlock()
m.diskChangeDetected(folderCfg, fs, events.RemoteChangeDetected)
} }
func (m *Model) updateLocals(folder string, fs []protocol.FileInfo) { func (m *Model) updateLocals(folder string, fs []protocol.FileInfo) {
@ -1582,7 +1588,7 @@ func (m *Model) updateLocals(folder string, fs []protocol.FileInfo) {
}) })
} }
func (m *Model) localChangeDetected(folderCfg config.FolderConfiguration, files []protocol.FileInfo) { func (m *Model) diskChangeDetected(folderCfg config.FolderConfiguration, files []protocol.FileInfo, typeOfEvent events.EventType) {
path := strings.Replace(folderCfg.Path(), `\\?\`, "", 1) path := strings.Replace(folderCfg.Path(), `\\?\`, "", 1)
for _, file := range files { for _, file := range files {
@ -1611,12 +1617,14 @@ func (m *Model) localChangeDetected(folderCfg config.FolderConfiguration, files
// for windows paths, strip unwanted chars from the front. // for windows paths, strip unwanted chars from the front.
path := filepath.Join(path, filepath.FromSlash(file.Name)) path := filepath.Join(path, filepath.FromSlash(file.Name))
events.Default.Log(events.LocalChangeDetected, map[string]string{ // Two different events can be fired here based on what EventType is passed into function
"folderID": folderCfg.ID, events.Default.Log(typeOfEvent, map[string]string{
"label": folderCfg.Label, "folderID": folderCfg.ID,
"action": action, "label": folderCfg.Label,
"type": objType, "action": action,
"path": path, "type": objType,
"path": path,
"modifiedBy": file.ModifiedBy.String(),
}) })
} }
} }
@ -1859,6 +1867,7 @@ func (m *Model) internalScanFolderSubdirs(folder string, subDirs []string) error
Size: f.Size, Size: f.Size,
ModifiedS: f.ModifiedS, ModifiedS: f.ModifiedS,
ModifiedNs: f.ModifiedNs, ModifiedNs: f.ModifiedNs,
ModifiedBy: m.id.Short(),
Permissions: f.Permissions, Permissions: f.Permissions,
NoPermissions: f.NoPermissions, NoPermissions: f.NoPermissions,
Invalid: true, Invalid: true,
@ -1884,6 +1893,7 @@ func (m *Model) internalScanFolderSubdirs(folder string, subDirs []string) error
Size: 0, Size: 0,
ModifiedS: f.ModifiedS, ModifiedS: f.ModifiedS,
ModifiedNs: f.ModifiedNs, ModifiedNs: f.ModifiedNs,
ModifiedBy: m.id.Short(),
Deleted: true, Deleted: true,
Version: f.Version.Update(m.shortID), Version: f.Version.Update(m.shortID),
} }

View File

@ -298,6 +298,7 @@ type FileInfo struct {
Permissions uint32 `protobuf:"varint,4,opt,name=permissions,proto3" json:"permissions,omitempty"` Permissions uint32 `protobuf:"varint,4,opt,name=permissions,proto3" json:"permissions,omitempty"`
ModifiedS int64 `protobuf:"varint,5,opt,name=modified_s,json=modifiedS,proto3" json:"modified_s,omitempty"` ModifiedS int64 `protobuf:"varint,5,opt,name=modified_s,json=modifiedS,proto3" json:"modified_s,omitempty"`
ModifiedNs int32 `protobuf:"varint,11,opt,name=modified_ns,json=modifiedNs,proto3" json:"modified_ns,omitempty"` ModifiedNs int32 `protobuf:"varint,11,opt,name=modified_ns,json=modifiedNs,proto3" json:"modified_ns,omitempty"`
ModifiedBy ShortID `protobuf:"varint,12,opt,name=modified_by,json=modifiedBy,proto3,customtype=ShortID" json:"modified_by"`
Deleted bool `protobuf:"varint,6,opt,name=deleted,proto3" json:"deleted,omitempty"` Deleted bool `protobuf:"varint,6,opt,name=deleted,proto3" json:"deleted,omitempty"`
Invalid bool `protobuf:"varint,7,opt,name=invalid,proto3" json:"invalid,omitempty"` Invalid bool `protobuf:"varint,7,opt,name=invalid,proto3" json:"invalid,omitempty"`
NoPermissions bool `protobuf:"varint,8,opt,name=no_permissions,json=noPermissions,proto3" json:"no_permissions,omitempty"` NoPermissions bool `protobuf:"varint,8,opt,name=no_permissions,json=noPermissions,proto3" json:"no_permissions,omitempty"`
@ -381,7 +382,7 @@ type FileDownloadProgressUpdate struct {
UpdateType FileDownloadProgressUpdateType `protobuf:"varint,1,opt,name=update_type,json=updateType,proto3,enum=protocol.FileDownloadProgressUpdateType" json:"update_type,omitempty"` UpdateType FileDownloadProgressUpdateType `protobuf:"varint,1,opt,name=update_type,json=updateType,proto3,enum=protocol.FileDownloadProgressUpdateType" json:"update_type,omitempty"`
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
Version Vector `protobuf:"bytes,3,opt,name=version" json:"version"` Version Vector `protobuf:"bytes,3,opt,name=version" json:"version"`
BlockIndexes []int32 `protobuf:"varint,4,rep,name=block_indexes,json=blockIndexes" json:"block_indexes,omitempty"` BlockIndexes []int32 `protobuf:"varint,4,rep,packed,name=block_indexes,json=blockIndexes" json:"block_indexes,omitempty"`
} }
func (m *FileDownloadProgressUpdate) Reset() { *m = FileDownloadProgressUpdate{} } func (m *FileDownloadProgressUpdate) Reset() { *m = FileDownloadProgressUpdate{} }
@ -858,6 +859,11 @@ func (m *FileInfo) MarshalTo(data []byte) (int, error) {
i++ i++
i = encodeVarintBep(data, i, uint64(m.ModifiedNs)) i = encodeVarintBep(data, i, uint64(m.ModifiedNs))
} }
if m.ModifiedBy != 0 {
data[i] = 0x60
i++
i = encodeVarintBep(data, i, uint64(m.ModifiedBy))
}
if len(m.Blocks) > 0 { if len(m.Blocks) > 0 {
for _, msg := range m.Blocks { for _, msg := range m.Blocks {
data[i] = 0x82 data[i] = 0x82
@ -1146,11 +1152,22 @@ func (m *FileDownloadProgressUpdate) MarshalTo(data []byte) (int, error) {
} }
i += n3 i += n3
if len(m.BlockIndexes) > 0 { if len(m.BlockIndexes) > 0 {
for _, num := range m.BlockIndexes { data5 := make([]byte, len(m.BlockIndexes)*10)
data[i] = 0x20 var j4 int
i++ for _, num1 := range m.BlockIndexes {
i = encodeVarintBep(data, i, uint64(num)) num := uint64(num1)
for num >= 1<<7 {
data5[j4] = uint8(uint64(num)&0x7f | 0x80)
num >>= 7
j4++
}
data5[j4] = uint8(num)
j4++
} }
data[i] = 0x22
i++
i = encodeVarintBep(data, i, uint64(j4))
i += copy(data[i:], data5[:j4])
} }
return i, nil return i, nil
} }
@ -1403,6 +1420,9 @@ func (m *FileInfo) ProtoSize() (n int) {
if m.ModifiedNs != 0 { if m.ModifiedNs != 0 {
n += 1 + sovBep(uint64(m.ModifiedNs)) n += 1 + sovBep(uint64(m.ModifiedNs))
} }
if m.ModifiedBy != 0 {
n += 1 + sovBep(uint64(m.ModifiedBy))
}
if len(m.Blocks) > 0 { if len(m.Blocks) > 0 {
for _, e := range m.Blocks { for _, e := range m.Blocks {
l = e.ProtoSize() l = e.ProtoSize()
@ -1534,9 +1554,11 @@ func (m *FileDownloadProgressUpdate) ProtoSize() (n int) {
l = m.Version.ProtoSize() l = m.Version.ProtoSize()
n += 1 + l + sovBep(uint64(l)) n += 1 + l + sovBep(uint64(l))
if len(m.BlockIndexes) > 0 { if len(m.BlockIndexes) > 0 {
l = 0
for _, e := range m.BlockIndexes { for _, e := range m.BlockIndexes {
n += 1 + sovBep(uint64(e)) l += sovBep(uint64(e))
} }
n += 1 + sovBep(uint64(l)) + l
} }
return n return n
} }
@ -2841,6 +2863,25 @@ func (m *FileInfo) Unmarshal(data []byte) error {
break break
} }
} }
case 12:
if wireType != 0 {
return fmt.Errorf("proto: wrong wireType = %d for field ModifiedBy", wireType)
}
m.ModifiedBy = 0
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowBep
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
m.ModifiedBy |= (ShortID(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
case 16: case 16:
if wireType != 2 { if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field Blocks", wireType) return fmt.Errorf("proto: wrong wireType = %d for field Blocks", wireType)
@ -3782,25 +3823,67 @@ func (m *FileDownloadProgressUpdate) Unmarshal(data []byte) error {
} }
iNdEx = postIndex iNdEx = postIndex
case 4: case 4:
if wireType != 0 { if wireType == 2 {
return fmt.Errorf("proto: wrong wireType = %d for field BlockIndexes", wireType) var packedLen int
} for shift := uint(0); ; shift += 7 {
var v int32 if shift >= 64 {
for shift := uint(0); ; shift += 7 { return ErrIntOverflowBep
if shift >= 64 { }
return ErrIntOverflowBep if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
packedLen |= (int(b) & 0x7F) << shift
if b < 0x80 {
break
}
} }
if iNdEx >= l { if packedLen < 0 {
return ErrInvalidLengthBep
}
postIndex := iNdEx + packedLen
if postIndex > l {
return io.ErrUnexpectedEOF return io.ErrUnexpectedEOF
} }
b := data[iNdEx] for iNdEx < postIndex {
iNdEx++ var v int32
v |= (int32(b) & 0x7F) << shift for shift := uint(0); ; shift += 7 {
if b < 0x80 { if shift >= 64 {
break return ErrIntOverflowBep
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
v |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.BlockIndexes = append(m.BlockIndexes, v)
} }
} else if wireType == 0 {
var v int32
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowBep
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := data[iNdEx]
iNdEx++
v |= (int32(b) & 0x7F) << shift
if b < 0x80 {
break
}
}
m.BlockIndexes = append(m.BlockIndexes, v)
} else {
return fmt.Errorf("proto: wrong wireType = %d for field BlockIndexes", wireType)
} }
m.BlockIndexes = append(m.BlockIndexes, v)
default: default:
iNdEx = preIndex iNdEx = preIndex
skippy, err := skipBep(data[iNdEx:]) skippy, err := skipBep(data[iNdEx:])

View File

@ -100,6 +100,7 @@ message FileInfo {
uint32 permissions = 4; uint32 permissions = 4;
int64 modified_s = 5; int64 modified_s = 5;
int32 modified_ns = 11; int32 modified_ns = 11;
uint64 modified_by = 12 [(gogoproto.customtype) = "ShortID", (gogoproto.nullable) = false];
bool deleted = 6; bool deleted = 6;
bool invalid = 7; bool invalid = 7;
bool no_permissions = 8; bool no_permissions = 8;

View File

@ -88,6 +88,9 @@ func (n *DeviceID) MarshalText() ([]byte, error) {
} }
func (s ShortID) String() string { func (s ShortID) String() string {
if s == 0 {
return ""
}
var bs [8]byte var bs [8]byte
binary.BigEndian.PutUint64(bs[:], uint64(s)) binary.BigEndian.PutUint64(bs[:], uint64(s))
return base32.StdEncoding.EncodeToString(bs[:])[:7] return base32.StdEncoding.EncodeToString(bs[:])[:7]

View File

@ -326,6 +326,7 @@ func (w *walker) walkRegular(relPath string, info os.FileInfo, fchan chan protoc
NoPermissions: w.IgnorePerms, NoPermissions: w.IgnorePerms,
ModifiedS: info.ModTime().Unix(), ModifiedS: info.ModTime().Unix(),
ModifiedNs: int32(info.ModTime().Nanosecond()), ModifiedNs: int32(info.ModTime().Nanosecond()),
ModifiedBy: w.ShortID,
Size: info.Size(), Size: info.Size(),
} }
l.Debugln("to hash:", relPath, f) l.Debugln("to hash:", relPath, f)
@ -361,6 +362,7 @@ func (w *walker) walkDir(relPath string, info os.FileInfo, dchan chan protocol.F
NoPermissions: w.IgnorePerms, NoPermissions: w.IgnorePerms,
ModifiedS: info.ModTime().Unix(), ModifiedS: info.ModTime().Unix(),
ModifiedNs: int32(info.ModTime().Nanosecond()), ModifiedNs: int32(info.ModTime().Nanosecond()),
ModifiedBy: w.ShortID,
} }
l.Debugln("dir:", relPath, f) l.Debugln("dir:", relPath, f)