refactor: use modern Protobuf encoder (#9817)
At a high level, this is what I've done and why:
- I'm moving the protobuf generation for the `protocol`, `discovery` and
`db` packages to the modern alternatives, and using `buf` to generate
because it's nice and simple.
- After trying various approaches on how to integrate the new types with
the existing code, I opted for splitting off our own data model types
from the on-the-wire generated types. This means we can have a
`FileInfo` type with nicer ergonomics and lots of methods, while the
protobuf generated type stays clean and close to the wire protocol. It
does mean copying between the two when required, which certainly adds a
small amount of inefficiency. If we want to walk this back in the future
and use the raw generated type throughout, that's possible, this however
makes the refactor smaller (!) as it doesn't change everything about the
type for everyone at the same time.
- I have simply removed in cold blood a significant number of old
database migrations. These depended on previous generations of generated
messages of various kinds and were annoying to support in the new
fashion. The oldest supported database version now is the one from
Syncthing 1.9.0 from Sep 7, 2020.
- I changed config structs to be regular manually defined structs.
For the sake of discussion, some things I tried that turned out not to
work...
### Embedding / wrapping
Embedding the protobuf generated structs in our existing types as a data
container and keeping our methods and stuff:
```
package protocol
type FileInfo struct {
*generated.FileInfo
}
```
This generates a lot of problems because the internal shape of the
generated struct is quite different (different names, different types,
more pointers), because initializing it doesn't work like you'd expect
(i.e., you end up with an embedded nil pointer and a panic), and because
the types of child types don't get wrapped. That is, even if we also
have a similar wrapper around a `Vector`, that's not the type you get
when accessing `someFileInfo.Version`, you get the `*generated.Vector`
that doesn't have methods, etc.
### Aliasing
```
package protocol
type FileInfo = generated.FileInfo
```
Doesn't help because you can't attach methods to it, plus all the above.
### Generating the types into the target package like we do now and
attaching methods
This fails because of the different shape of the generated type (as in
the embedding case above) plus the generated struct already has a bunch
of methods that we can't necessarily override properly (like `String()`
and a bunch of getters).
### Methods to functions
I considered just moving all the methods we attach to functions in a
specific package, so that for example
```
package protocol
func (f FileInfo) Equal(other FileInfo) bool
```
would become
```
package fileinfos
func Equal(a, b *generated.FileInfo) bool
```
and this would mostly work, but becomes quite verbose and cumbersome,
and somewhat limits discoverability (you can't see what methods are
available on the type in auto completions, etc). In the end I did this
in some cases, like in the database layer where a lot of things like
`func (fv *FileVersion) IsEmpty() bool` becomes `func fvIsEmpty(fv
*generated.FileVersion)` because they were anyway just internal methods.
Fixes #8247
This commit is contained in:
@@ -0,0 +1,8 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package apiproto;
|
||||
|
||||
message TokenSet {
|
||||
// token -> expiry time (epoch nanoseconds)
|
||||
map<string, int64> tokens = 1;
|
||||
}
|
||||
@@ -0,0 +1,253 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package bep;
|
||||
|
||||
// --- Pre-auth ---
|
||||
|
||||
message Hello {
|
||||
string device_name = 1;
|
||||
string client_name = 2;
|
||||
string client_version = 3;
|
||||
int32 num_connections = 4;
|
||||
int64 timestamp = 5;
|
||||
}
|
||||
|
||||
// --- Header ---
|
||||
|
||||
message Header {
|
||||
MessageType type = 1;
|
||||
MessageCompression compression = 2;
|
||||
}
|
||||
|
||||
enum MessageType {
|
||||
MESSAGE_TYPE_CLUSTER_CONFIG = 0;
|
||||
MESSAGE_TYPE_INDEX = 1;
|
||||
MESSAGE_TYPE_INDEX_UPDATE = 2;
|
||||
MESSAGE_TYPE_REQUEST = 3;
|
||||
MESSAGE_TYPE_RESPONSE = 4;
|
||||
MESSAGE_TYPE_DOWNLOAD_PROGRESS = 5;
|
||||
MESSAGE_TYPE_PING = 6;
|
||||
MESSAGE_TYPE_CLOSE = 7;
|
||||
}
|
||||
|
||||
enum MessageCompression {
|
||||
MESSAGE_COMPRESSION_NONE = 0;
|
||||
MESSAGE_COMPRESSION_LZ4 = 1;
|
||||
}
|
||||
|
||||
// --- Actual messages ---
|
||||
|
||||
// Cluster Config
|
||||
|
||||
message ClusterConfig {
|
||||
repeated Folder folders = 1;
|
||||
bool secondary = 2;
|
||||
}
|
||||
|
||||
message Folder {
|
||||
string id = 1;
|
||||
string label = 2;
|
||||
bool read_only = 3;
|
||||
bool ignore_permissions = 4;
|
||||
bool ignore_delete = 5;
|
||||
bool disable_temp_indexes = 6;
|
||||
bool paused = 7;
|
||||
|
||||
repeated Device devices = 16;
|
||||
}
|
||||
|
||||
message Device {
|
||||
bytes id = 1;
|
||||
string name = 2;
|
||||
repeated string addresses = 3;
|
||||
Compression compression = 4;
|
||||
string cert_name = 5;
|
||||
int64 max_sequence = 6;
|
||||
bool introducer = 7;
|
||||
uint64 index_id = 8;
|
||||
bool skip_introduction_removals = 9;
|
||||
bytes encryption_password_token = 10;
|
||||
}
|
||||
|
||||
enum Compression {
|
||||
COMPRESSION_METADATA = 0;
|
||||
COMPRESSION_NEVER = 1;
|
||||
COMPRESSION_ALWAYS = 2;
|
||||
}
|
||||
|
||||
// Index and Index Update
|
||||
|
||||
message Index {
|
||||
string folder = 1;
|
||||
repeated FileInfo files = 2;
|
||||
int64 last_sequence = 3; // the highest sequence in this batch
|
||||
}
|
||||
|
||||
message IndexUpdate {
|
||||
string folder = 1;
|
||||
repeated FileInfo files = 2;
|
||||
int64 last_sequence = 3; // the highest sequence in this batch
|
||||
int64 prev_sequence = 4; // the highest sequence in the previous batch
|
||||
}
|
||||
|
||||
message FileInfo {
|
||||
// The field ordering here optimizes for struct size / alignment --
|
||||
// large types come before smaller ones.
|
||||
|
||||
string name = 1;
|
||||
int64 size = 3;
|
||||
int64 modified_s = 5;
|
||||
uint64 modified_by = 12;
|
||||
Vector version = 9;
|
||||
int64 sequence = 10;
|
||||
repeated BlockInfo blocks = 16;
|
||||
string symlink_target = 17;
|
||||
bytes blocks_hash = 18;
|
||||
bytes encrypted = 19;
|
||||
FileInfoType type = 2;
|
||||
uint32 permissions = 4;
|
||||
int32 modified_ns = 11;
|
||||
int32 block_size = 13;
|
||||
PlatformData platform = 14;
|
||||
|
||||
// The local_flags fields stores flags that are relevant to the local
|
||||
// host only. It is not part of the protocol, doesn't get sent or
|
||||
// received (we make sure to zero it), nonetheless we need it on our
|
||||
// struct and to be able to serialize it to/from the database.
|
||||
uint32 local_flags = 1000;
|
||||
|
||||
// The version_hash is an implementation detail and not part of the wire
|
||||
// format.
|
||||
bytes version_hash = 1001;
|
||||
|
||||
// The time when the inode was last changed (i.e., permissions, xattrs
|
||||
// etc changed). This is host-local, not sent over the wire.
|
||||
int64 inode_change_ns = 1002;
|
||||
|
||||
// The size of the data appended to the encrypted file on disk. This is
|
||||
// host-local, not sent over the wire.
|
||||
int32 encryption_trailer_size = 1003;
|
||||
|
||||
bool deleted = 6;
|
||||
bool invalid = 7;
|
||||
bool no_permissions = 8;
|
||||
}
|
||||
|
||||
enum FileInfoType {
|
||||
FILE_INFO_TYPE_FILE = 0;
|
||||
FILE_INFO_TYPE_DIRECTORY = 1;
|
||||
FILE_INFO_TYPE_SYMLINK_FILE = 2 [deprecated = true];
|
||||
FILE_INFO_TYPE_SYMLINK_DIRECTORY = 3 [deprecated = true];
|
||||
FILE_INFO_TYPE_SYMLINK = 4;
|
||||
}
|
||||
|
||||
message BlockInfo {
|
||||
bytes hash = 3;
|
||||
int64 offset = 1;
|
||||
int32 size = 2;
|
||||
uint32 weak_hash = 4;
|
||||
}
|
||||
|
||||
message Vector {
|
||||
repeated Counter counters = 1;
|
||||
}
|
||||
|
||||
message Counter {
|
||||
uint64 id = 1;
|
||||
uint64 value = 2;
|
||||
}
|
||||
|
||||
message PlatformData {
|
||||
UnixData unix = 1;
|
||||
WindowsData windows = 2;
|
||||
XattrData linux = 3;
|
||||
XattrData darwin = 4;
|
||||
XattrData freebsd = 5;
|
||||
XattrData netbsd = 6;
|
||||
}
|
||||
|
||||
message UnixData {
|
||||
// The owner name and group name are set when known (i.e., could be
|
||||
// resolved on the source device), while the UID and GID are always set
|
||||
// as they come directly from the stat() call.
|
||||
string owner_name = 1;
|
||||
string group_name = 2;
|
||||
int32 uid = 3;
|
||||
int32 gid = 4;
|
||||
}
|
||||
|
||||
message WindowsData {
|
||||
// Windows file objects have a single owner, which may be a user or a
|
||||
// group. We keep the name of that account, and a flag to indicate what
|
||||
// type it is.
|
||||
string owner_name = 1;
|
||||
bool owner_is_group = 2;
|
||||
}
|
||||
|
||||
message XattrData {
|
||||
repeated Xattr xattrs = 1;
|
||||
}
|
||||
|
||||
message Xattr {
|
||||
string name = 1;
|
||||
bytes value = 2;
|
||||
}
|
||||
|
||||
// Request
|
||||
|
||||
message Request {
|
||||
int32 id = 1;
|
||||
string folder = 2;
|
||||
string name = 3;
|
||||
int64 offset = 4;
|
||||
int32 size = 5;
|
||||
bytes hash = 6;
|
||||
bool from_temporary = 7;
|
||||
uint32 weak_hash = 8;
|
||||
int32 block_no = 9;
|
||||
}
|
||||
|
||||
// Response
|
||||
|
||||
message Response {
|
||||
int32 id = 1;
|
||||
bytes data = 2;
|
||||
ErrorCode code = 3;
|
||||
}
|
||||
|
||||
enum ErrorCode {
|
||||
ERROR_CODE_NO_ERROR = 0;
|
||||
ERROR_CODE_GENERIC = 1;
|
||||
ERROR_CODE_NO_SUCH_FILE = 2;
|
||||
ERROR_CODE_INVALID_FILE = 3;
|
||||
}
|
||||
|
||||
// DownloadProgress
|
||||
|
||||
message DownloadProgress {
|
||||
string folder = 1;
|
||||
repeated FileDownloadProgressUpdate updates = 2;
|
||||
}
|
||||
|
||||
message FileDownloadProgressUpdate {
|
||||
FileDownloadProgressUpdateType update_type = 1;
|
||||
string name = 2;
|
||||
Vector version = 3;
|
||||
repeated int32 block_indexes = 4 [packed = false];
|
||||
int32 block_size = 5;
|
||||
}
|
||||
|
||||
enum FileDownloadProgressUpdateType {
|
||||
FILE_DOWNLOAD_PROGRESS_UPDATE_TYPE_APPEND = 0;
|
||||
FILE_DOWNLOAD_PROGRESS_UPDATE_TYPE_FORGET = 1;
|
||||
}
|
||||
|
||||
// Ping
|
||||
|
||||
message Ping {}
|
||||
|
||||
// Close
|
||||
|
||||
message Close {
|
||||
string reason = 1;
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package dbproto;
|
||||
|
||||
import "bep/bep.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
|
||||
// Same as bep.FileInfo, but without blocks
|
||||
message FileInfoTruncated {
|
||||
string name = 1;
|
||||
int64 size = 3;
|
||||
int64 modified_s = 5;
|
||||
uint64 modified_by = 12;
|
||||
bep.Vector version = 9;
|
||||
int64 sequence = 10;
|
||||
reserved 16; // blocks
|
||||
string symlink_target = 17;
|
||||
bytes blocks_hash = 18;
|
||||
bytes encrypted = 19;
|
||||
bep.FileInfoType type = 2;
|
||||
uint32 permissions = 4;
|
||||
int32 modified_ns = 11;
|
||||
int32 block_size = 13;
|
||||
bep.PlatformData platform = 14;
|
||||
|
||||
// The local_flags fields stores flags that are relevant to the local
|
||||
// host only. It is not part of the protocol, doesn't get sent or
|
||||
// received (we make sure to zero it), nonetheless we need it on our
|
||||
// struct and to be able to serialize it to/from the database.
|
||||
uint32 local_flags = 1000;
|
||||
|
||||
// The version_hash is an implementation detail and not part of the wire
|
||||
// format.
|
||||
bytes version_hash = 1001;
|
||||
|
||||
// The time when the inode was last changed (i.e., permissions, xattrs
|
||||
// etc changed). This is host-local, not sent over the wire.
|
||||
int64 inode_change_ns = 1002;
|
||||
|
||||
// The size of the data appended to the encrypted file on disk. This is
|
||||
// host-local, not sent over the wire.
|
||||
int32 encryption_trailer_size = 1003;
|
||||
|
||||
bool deleted = 6;
|
||||
bool invalid = 7;
|
||||
bool no_permissions = 8;
|
||||
}
|
||||
|
||||
|
||||
message FileVersion {
|
||||
bep.Vector version = 1;
|
||||
bool deleted = 2;
|
||||
repeated bytes devices = 3;
|
||||
repeated bytes invalid_devices = 4;
|
||||
}
|
||||
|
||||
message VersionList {
|
||||
repeated FileVersion versions = 1;
|
||||
}
|
||||
|
||||
// BlockList is the structure used to store block lists
|
||||
message BlockList {
|
||||
repeated bep.BlockInfo blocks = 1;
|
||||
}
|
||||
|
||||
// IndirectionHashesOnly is used to only unmarshal the indirection hashes
|
||||
// from a FileInfo
|
||||
message IndirectionHashesOnly {
|
||||
bytes blocks_hash = 18;
|
||||
bytes version_hash = 1001;
|
||||
}
|
||||
|
||||
// For each folder and device we keep one of these to track the current
|
||||
// counts and sequence. We also keep one for the global state of the folder.
|
||||
message Counts {
|
||||
int32 files = 1;
|
||||
int32 directories = 2;
|
||||
int32 symlinks = 3;
|
||||
int32 deleted = 4;
|
||||
int64 bytes = 5;
|
||||
int64 sequence = 6; // zero for the global state
|
||||
bytes device_id = 17; // device ID for remote devices, or special values for local/global
|
||||
uint32 local_flags = 18; // the local flag for this count bucket
|
||||
}
|
||||
|
||||
message CountsSet {
|
||||
repeated Counts counts = 1;
|
||||
int64 created = 2; // unix nanos
|
||||
}
|
||||
|
||||
message ObservedFolder {
|
||||
google.protobuf.Timestamp time = 1;
|
||||
string label = 2;
|
||||
bool receive_encrypted = 3;
|
||||
bool remote_encrypted = 4;
|
||||
}
|
||||
|
||||
message ObservedDevice {
|
||||
google.protobuf.Timestamp time = 1;
|
||||
string name = 2;
|
||||
string address = 3;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package discoproto;
|
||||
|
||||
message Announce {
|
||||
bytes id = 1;
|
||||
repeated string addresses = 2;
|
||||
int64 instance_id = 3;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package discosrv;
|
||||
|
||||
message DatabaseRecord {
|
||||
repeated DatabaseAddress addresses = 1;
|
||||
int64 seen = 3; // Unix nanos, last device announce
|
||||
}
|
||||
|
||||
message ReplicationRecord {
|
||||
bytes key = 1; // raw 32 byte device ID
|
||||
repeated DatabaseAddress addresses = 2;
|
||||
int64 seen = 3; // Unix nanos, last device announce
|
||||
}
|
||||
|
||||
message DatabaseAddress {
|
||||
string address = 1;
|
||||
int64 expires = 2; // Unix nanos
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
syntax = "proto2";
|
||||
|
||||
package ext;
|
||||
|
||||
import "google/protobuf/descriptor.proto";
|
||||
|
||||
option go_package = "github.com/syncthing/syncthing/proto/ext";
|
||||
|
||||
extend google.protobuf.MessageOptions {
|
||||
optional bool xml_tags = 74001;
|
||||
}
|
||||
|
||||
extend google.protobuf.FieldOptions {
|
||||
optional string xml = 75005;
|
||||
optional string json = 75006;
|
||||
optional string default = 75007;
|
||||
optional bool restart = 75008;
|
||||
optional bool device_id = 75009;
|
||||
optional string goname = 75010;
|
||||
optional string gotype = 75011;
|
||||
optional bool nodefault = 75012;
|
||||
}
|
||||
|
||||
extend google.protobuf.EnumValueOptions {
|
||||
optional string enumgoname = 76010;
|
||||
}
|
||||
@@ -1,152 +0,0 @@
|
||||
// Code generated by protoc-gen-gogo. DO NOT EDIT.
|
||||
// source: ext.proto
|
||||
|
||||
package ext
|
||||
|
||||
import (
|
||||
fmt "fmt"
|
||||
proto "github.com/gogo/protobuf/proto"
|
||||
descriptor "github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
|
||||
math "math"
|
||||
)
|
||||
|
||||
// Reference imports to suppress errors if they are not otherwise used.
|
||||
var _ = proto.Marshal
|
||||
var _ = fmt.Errorf
|
||||
var _ = math.Inf
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the proto package it is being compiled against.
|
||||
// A compilation error at this line likely means your copy of the
|
||||
// proto package needs to be updated.
|
||||
const _ = proto.GoGoProtoPackageIsVersion3 // please upgrade the proto package
|
||||
|
||||
var E_XmlTags = &proto.ExtensionDesc{
|
||||
ExtendedType: (*descriptor.MessageOptions)(nil),
|
||||
ExtensionType: (*bool)(nil),
|
||||
Field: 74001,
|
||||
Name: "ext.xml_tags",
|
||||
Tag: "varint,74001,opt,name=xml_tags",
|
||||
Filename: "ext.proto",
|
||||
}
|
||||
|
||||
var E_Xml = &proto.ExtensionDesc{
|
||||
ExtendedType: (*descriptor.FieldOptions)(nil),
|
||||
ExtensionType: (*string)(nil),
|
||||
Field: 75005,
|
||||
Name: "ext.xml",
|
||||
Tag: "bytes,75005,opt,name=xml",
|
||||
Filename: "ext.proto",
|
||||
}
|
||||
|
||||
var E_Json = &proto.ExtensionDesc{
|
||||
ExtendedType: (*descriptor.FieldOptions)(nil),
|
||||
ExtensionType: (*string)(nil),
|
||||
Field: 75006,
|
||||
Name: "ext.json",
|
||||
Tag: "bytes,75006,opt,name=json",
|
||||
Filename: "ext.proto",
|
||||
}
|
||||
|
||||
var E_Default = &proto.ExtensionDesc{
|
||||
ExtendedType: (*descriptor.FieldOptions)(nil),
|
||||
ExtensionType: (*string)(nil),
|
||||
Field: 75007,
|
||||
Name: "ext.default",
|
||||
Tag: "bytes,75007,opt,name=default",
|
||||
Filename: "ext.proto",
|
||||
}
|
||||
|
||||
var E_Restart = &proto.ExtensionDesc{
|
||||
ExtendedType: (*descriptor.FieldOptions)(nil),
|
||||
ExtensionType: (*bool)(nil),
|
||||
Field: 75008,
|
||||
Name: "ext.restart",
|
||||
Tag: "varint,75008,opt,name=restart",
|
||||
Filename: "ext.proto",
|
||||
}
|
||||
|
||||
var E_DeviceId = &proto.ExtensionDesc{
|
||||
ExtendedType: (*descriptor.FieldOptions)(nil),
|
||||
ExtensionType: (*bool)(nil),
|
||||
Field: 75009,
|
||||
Name: "ext.device_id",
|
||||
Tag: "varint,75009,opt,name=device_id",
|
||||
Filename: "ext.proto",
|
||||
}
|
||||
|
||||
var E_Goname = &proto.ExtensionDesc{
|
||||
ExtendedType: (*descriptor.FieldOptions)(nil),
|
||||
ExtensionType: (*string)(nil),
|
||||
Field: 75010,
|
||||
Name: "ext.goname",
|
||||
Tag: "bytes,75010,opt,name=goname",
|
||||
Filename: "ext.proto",
|
||||
}
|
||||
|
||||
var E_Gotype = &proto.ExtensionDesc{
|
||||
ExtendedType: (*descriptor.FieldOptions)(nil),
|
||||
ExtensionType: (*string)(nil),
|
||||
Field: 75011,
|
||||
Name: "ext.gotype",
|
||||
Tag: "bytes,75011,opt,name=gotype",
|
||||
Filename: "ext.proto",
|
||||
}
|
||||
|
||||
var E_Nodefault = &proto.ExtensionDesc{
|
||||
ExtendedType: (*descriptor.FieldOptions)(nil),
|
||||
ExtensionType: (*bool)(nil),
|
||||
Field: 75012,
|
||||
Name: "ext.nodefault",
|
||||
Tag: "varint,75012,opt,name=nodefault",
|
||||
Filename: "ext.proto",
|
||||
}
|
||||
|
||||
var E_Enumgoname = &proto.ExtensionDesc{
|
||||
ExtendedType: (*descriptor.EnumValueOptions)(nil),
|
||||
ExtensionType: (*string)(nil),
|
||||
Field: 76010,
|
||||
Name: "ext.enumgoname",
|
||||
Tag: "bytes,76010,opt,name=enumgoname",
|
||||
Filename: "ext.proto",
|
||||
}
|
||||
|
||||
func init() {
|
||||
proto.RegisterExtension(E_XmlTags)
|
||||
proto.RegisterExtension(E_Xml)
|
||||
proto.RegisterExtension(E_Json)
|
||||
proto.RegisterExtension(E_Default)
|
||||
proto.RegisterExtension(E_Restart)
|
||||
proto.RegisterExtension(E_DeviceId)
|
||||
proto.RegisterExtension(E_Goname)
|
||||
proto.RegisterExtension(E_Gotype)
|
||||
proto.RegisterExtension(E_Nodefault)
|
||||
proto.RegisterExtension(E_Enumgoname)
|
||||
}
|
||||
|
||||
func init() { proto.RegisterFile("ext.proto", fileDescriptor_95fe6908ffcf64d3) }
|
||||
|
||||
var fileDescriptor_95fe6908ffcf64d3 = []byte{
|
||||
// 332 bytes of a gzipped FileDescriptorProto
|
||||
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x8c, 0xd2, 0x4d, 0x4b, 0xfb, 0x30,
|
||||
0x1c, 0xc0, 0x71, 0xca, 0xc6, 0x7f, 0x6b, 0x8e, 0x3b, 0xfd, 0x11, 0x9c, 0xf3, 0xb6, 0x53, 0x8b,
|
||||
0x08, 0x8a, 0x61, 0x5e, 0x14, 0x05, 0x0f, 0x22, 0x0c, 0xf1, 0xe0, 0x65, 0x64, 0xed, 0x6f, 0x59,
|
||||
0x24, 0x0f, 0xa5, 0x49, 0xa5, 0xbb, 0xf9, 0xf4, 0x06, 0x7c, 0x4b, 0x9e, 0x74, 0x27, 0x7d, 0x07,
|
||||
0xb2, 0xa3, 0xef, 0xc1, 0x07, 0xba, 0xa6, 0x6e, 0xb0, 0x43, 0xbc, 0x95, 0xf2, 0xfd, 0x24, 0xbf,
|
||||
0x84, 0x20, 0x1f, 0x72, 0x13, 0x24, 0xa9, 0x32, 0xaa, 0x55, 0x83, 0xdc, 0xac, 0x75, 0xa8, 0x52,
|
||||
0x94, 0x43, 0x38, 0xff, 0x35, 0xcc, 0x46, 0x61, 0x0c, 0x3a, 0x4a, 0x59, 0x62, 0x54, 0x5a, 0x66,
|
||||
0xb8, 0x87, 0x9a, 0xb9, 0xe0, 0x03, 0x43, 0xa8, 0x6e, 0x6d, 0x04, 0x65, 0x1e, 0x54, 0x79, 0x70,
|
||||
0x0a, 0x5a, 0x13, 0x0a, 0x67, 0x89, 0x61, 0x4a, 0xea, 0xff, 0x8f, 0x4f, 0xf5, 0x8e, 0xd7, 0x6d,
|
||||
0xf6, 0x1b, 0xb9, 0xe0, 0xe7, 0x84, 0x6a, 0xbc, 0x85, 0x6a, 0xb9, 0xe0, 0xad, 0xf5, 0x15, 0x78,
|
||||
0xcc, 0x80, 0xc7, 0x15, 0xfb, 0x7c, 0x29, 0x98, 0xdf, 0x2f, 0x5a, 0xbc, 0x8d, 0xea, 0x57, 0x5a,
|
||||
0x49, 0x97, 0xf9, 0xb2, 0x66, 0x1e, 0xe3, 0x3d, 0xd4, 0x88, 0x61, 0x44, 0x32, 0x6e, 0x5c, 0xee,
|
||||
0xdb, 0xba, 0xaa, 0x2f, 0x68, 0x0a, 0xda, 0x90, 0xd4, 0x49, 0x6f, 0xa6, 0xf6, 0x74, 0xb6, 0xc7,
|
||||
0x3d, 0xe4, 0xc7, 0x70, 0xcd, 0x22, 0x18, 0xb0, 0xd8, 0x85, 0x6f, 0x2d, 0x6e, 0x96, 0xe2, 0x24,
|
||||
0xc6, 0xbb, 0xe8, 0x1f, 0x55, 0x92, 0x08, 0x70, 0xd1, 0xbb, 0x69, 0x39, 0xb2, 0xcd, 0x4b, 0x68,
|
||||
0x26, 0x89, 0x13, 0xde, 0x2f, 0x60, 0x91, 0xe3, 0x7d, 0xe4, 0x4b, 0xf5, 0xc7, 0x7b, 0x7a, 0xb0,
|
||||
0xf3, 0x2e, 0x04, 0x3e, 0x44, 0x08, 0x64, 0x26, 0xec, 0xd0, 0x9b, 0x2b, 0xfe, 0x48, 0x66, 0xe2,
|
||||
0x82, 0xf0, 0xec, 0xf7, 0x39, 0x7c, 0xbc, 0x95, 0xfb, 0x2f, 0xb1, 0x83, 0x9d, 0xe7, 0x59, 0xdb,
|
||||
0x7b, 0x9d, 0xb5, 0xbd, 0xf7, 0x59, 0xdb, 0xbb, 0xec, 0x52, 0x66, 0xc6, 0xd9, 0x30, 0x88, 0x94,
|
||||
0x08, 0xf5, 0x44, 0x46, 0x66, 0xcc, 0x24, 0x5d, 0xfa, 0x9a, 0xaf, 0x1d, 0x42, 0x6e, 0x7e, 0x02,
|
||||
0x00, 0x00, 0xff, 0xff, 0x65, 0x95, 0xf9, 0xeb, 0xba, 0x02, 0x00, 0x00,
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
// Copyright (C) 2020 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path/filepath"
|
||||
)
|
||||
|
||||
//go:generate go run scripts/protofmt.go .
|
||||
|
||||
// First generate extensions using standard proto compiler.
|
||||
//go:generate protoc -I ../ -I . --gogofast_out=Mgoogle/protobuf/descriptor.proto=github.com/gogo/protobuf/protoc-gen-gogo/descriptor,paths=source_relative:ext ext.proto
|
||||
|
||||
// Then build our vanity compiler that uses the new extensions
|
||||
//go:generate go build -o scripts/protoc-gen-gosyncthing scripts/protoc_plugin.go
|
||||
|
||||
// Inception, go generate calls the script itself that then deals with generation.
|
||||
// This is only done because go:generate does not support wildcards in paths.
|
||||
//go:generate go run generate.go lib/protocol lib/config lib/fs lib/db lib/discover lib/api
|
||||
|
||||
func main() {
|
||||
for _, path := range os.Args[1:] {
|
||||
matches, err := filepath.Glob(filepath.Join(path, "*proto"))
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
log.Println(path, "returned:", matches)
|
||||
args := []string{
|
||||
"-I", "..",
|
||||
"-I", ".",
|
||||
"--plugin=protoc-gen-gosyncthing=scripts/protoc-gen-gosyncthing",
|
||||
"--gosyncthing_out=paths=source_relative:..",
|
||||
}
|
||||
args = append(args, matches...)
|
||||
cmd := exec.Command("protoc", args...)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
|
||||
if err := cmd.Run(); err != nil {
|
||||
log.Fatal("Failed generating", path)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package api;
|
||||
|
||||
message TokenSet {
|
||||
// token -> expiry time (epoch nanoseconds)
|
||||
map<string, int64> tokens = 1;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package config;
|
||||
|
||||
import "repos/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
import "ext.proto";
|
||||
|
||||
enum AuthMode {
|
||||
option (gogoproto.goproto_enum_stringer) = false;
|
||||
|
||||
AUTH_MODE_STATIC = 0;
|
||||
AUTH_MODE_LDAP = 1 [(ext.enumgoname) = "AuthModeLDAP"];
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package config;
|
||||
|
||||
import "repos/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
enum BlockPullOrder {
|
||||
option (gogoproto.goproto_enum_stringer) = false;
|
||||
|
||||
BLOCK_PULL_ORDER_STANDARD = 0;
|
||||
BLOCK_PULL_ORDER_RANDOM = 1;
|
||||
BLOCK_PULL_ORDER_IN_ORDER = 2;
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package config;
|
||||
|
||||
import "lib/config/folderconfiguration.proto";
|
||||
import "lib/config/deviceconfiguration.proto";
|
||||
import "lib/config/guiconfiguration.proto";
|
||||
import "lib/config/ldapconfiguration.proto";
|
||||
import "lib/config/optionsconfiguration.proto";
|
||||
import "lib/config/observed.proto";
|
||||
|
||||
import "ext.proto";
|
||||
|
||||
message Configuration {
|
||||
int32 version = 1 [(ext.xml) = "version,attr"];
|
||||
repeated FolderConfiguration folders = 2;
|
||||
repeated DeviceConfiguration devices = 3;
|
||||
GUIConfiguration gui = 4 [(ext.goname) = "GUI"];
|
||||
LDAPConfiguration ldap = 5 [(ext.goname) = "LDAP"];
|
||||
OptionsConfiguration options = 6;
|
||||
repeated ObservedDevice ignored_devices = 7 [(ext.json) = "remoteIgnoredDevices", (ext.xml) = "remoteIgnoredDevice"];
|
||||
repeated ObservedDevice pending_devices = 8 [deprecated=true];
|
||||
Defaults defaults = 9;
|
||||
}
|
||||
|
||||
message Defaults {
|
||||
FolderConfiguration folder = 1;
|
||||
DeviceConfiguration device = 2;
|
||||
Ignores ignores = 3;
|
||||
}
|
||||
|
||||
message Ignores {
|
||||
repeated string lines = 1;
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package config;
|
||||
|
||||
import "lib/protocol/bep.proto";
|
||||
import "lib/config/observed.proto";
|
||||
|
||||
import "ext.proto";
|
||||
|
||||
message DeviceConfiguration {
|
||||
bytes device_id = 1 [(ext.goname) = "DeviceID", (ext.xml) = "id,attr", (ext.json) = "deviceID", (ext.device_id) = true, (ext.nodefault) = true];
|
||||
string name = 2 [(ext.xml) = "name,attr,omitempty"];
|
||||
repeated string addresses = 3 [(ext.xml) = "address,omitempty"];
|
||||
protocol.Compression compression = 4 [(ext.xml) = "compression,attr"];
|
||||
string cert_name = 5 [(ext.xml) = "certName,attr,omitempty"];
|
||||
bool introducer = 6 [(ext.xml) = "introducer,attr"];
|
||||
bool skip_introduction_removals = 7 [(ext.xml) = "skipIntroductionRemovals,attr"];
|
||||
bytes introduced_by = 8 [(ext.xml) = "introducedBy,attr", (ext.device_id) = true, (ext.nodefault) = true];
|
||||
bool paused = 9;
|
||||
repeated string allowed_networks = 10 [(ext.xml) = "allowedNetwork,omitempty"];
|
||||
bool auto_accept_folders = 11;
|
||||
int32 max_send_kbps = 12;
|
||||
int32 max_recv_kbps = 13;
|
||||
repeated ObservedFolder ignored_folders = 14;
|
||||
repeated ObservedFolder pending_folders = 15 [deprecated = true];
|
||||
int32 max_request_kib = 16 [(ext.goname) = "MaxRequestKiB", (ext.xml) = "maxRequestKiB", (ext.json) = "maxRequestKiB"];
|
||||
bool untrusted = 17;
|
||||
int32 remote_gui_port = 18 [(ext.goname) = "RemoteGUIPort", (ext.xml) = "remoteGUIPort", (ext.json) = "remoteGUIPort"];
|
||||
int32 num_connections = 19 [(ext.goname) = "RawNumConnections"]; // attempt to establish this many connections to the device
|
||||
}
|
||||
@@ -1,86 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package config;
|
||||
|
||||
import "lib/config/foldertype.proto";
|
||||
import "lib/config/size.proto";
|
||||
import "lib/config/pullorder.proto";
|
||||
import "lib/config/versioningconfiguration.proto";
|
||||
import "lib/config/blockpullorder.proto";
|
||||
|
||||
import "lib/fs/types.proto";
|
||||
import "lib/fs/copyrangemethod.proto";
|
||||
|
||||
import "ext.proto";
|
||||
|
||||
message FolderDeviceConfiguration {
|
||||
bytes device_id = 1 [(ext.goname) = "DeviceID", (ext.xml) = "id,attr", (ext.json) = "deviceID", (ext.device_id) = true];
|
||||
bytes introduced_by = 2 [(ext.xml) = "introducedBy,attr", (ext.device_id) = true];
|
||||
string encryption_password = 3;
|
||||
}
|
||||
|
||||
message FolderConfiguration {
|
||||
string id = 1 [(ext.goname) = "ID", (ext.xml) = "id,attr", (ext.nodefault) = true];
|
||||
string label = 2 [(ext.xml) = "label,attr", (ext.restart) = false];
|
||||
fs.FilesystemType filesystem_type = 3;
|
||||
string path = 4 [(ext.xml) = "path,attr", (ext.default) = "~"];
|
||||
FolderType type = 5 [(ext.xml) = "type,attr"];
|
||||
repeated FolderDeviceConfiguration devices = 6;
|
||||
int32 rescan_interval_s = 7 [(ext.xml) = "rescanIntervalS,attr", (ext.default) = "3600"];
|
||||
bool fs_watcher_enabled = 8 [(ext.goname) = "FSWatcherEnabled", (ext.xml) = "fsWatcherEnabled,attr", (ext.default) = "true"];
|
||||
double fs_watcher_delay_s = 9 [(ext.goname) = "FSWatcherDelayS", (ext.xml) = "fsWatcherDelayS,attr", (ext.default) = "10"];
|
||||
double fs_watcher_timeout_s = 40 [(ext.goname) = "FSWatcherTimeoutS", (ext.xml) = "fsWatcherTimeoutS,attr"];
|
||||
bool ignore_perms = 10 [(ext.xml) = "ignorePerms,attr"];
|
||||
bool auto_normalize = 11 [(ext.xml) = "autoNormalize,attr", (ext.default) = "true"];
|
||||
Size min_disk_free = 12 [(ext.default) = "1 %"];
|
||||
VersioningConfiguration versioning = 13;
|
||||
int32 copiers = 14;
|
||||
int32 puller_max_pending_kib = 15 [(ext.goname) = "PullerMaxPendingKiB", (ext.xml) = "pullerMaxPendingKiB", (ext.json) = "pullerMaxPendingKiB"];
|
||||
int32 hashers = 16;
|
||||
PullOrder order = 17;
|
||||
bool ignore_delete = 18;
|
||||
int32 scan_progress_interval_s = 19;
|
||||
int32 puller_pause_s = 20;
|
||||
int32 max_conflicts = 21 [(ext.default) = "10"];
|
||||
bool disable_sparse_files = 22;
|
||||
bool disable_temp_indexes = 23;
|
||||
bool paused = 24;
|
||||
int32 weak_hash_threshold_pct = 25;
|
||||
string marker_name = 26;
|
||||
bool copy_ownership_from_parent = 27;
|
||||
int32 mod_time_window_s = 28 [(ext.goname) = "RawModTimeWindowS"];
|
||||
int32 max_concurrent_writes = 29 [(ext.default) = "2"];
|
||||
bool disable_fsync = 30;
|
||||
BlockPullOrder block_pull_order = 31;
|
||||
fs.CopyRangeMethod copy_range_method = 32 [(ext.default) = "standard"];
|
||||
bool case_sensitive_fs = 33 [(ext.goname) = "CaseSensitiveFS", (ext.xml) = "caseSensitiveFS", (ext.json) = "caseSensitiveFS"];
|
||||
bool follow_junctions = 34 [(ext.goname) = "JunctionsAsDirs", (ext.xml) = "junctionsAsDirs", (ext.json) = "junctionsAsDirs"];
|
||||
bool sync_ownership = 35;
|
||||
bool send_ownership = 36;
|
||||
bool sync_xattrs = 37;
|
||||
bool send_xattrs = 38;
|
||||
XattrFilter xattr_filter = 39;
|
||||
|
||||
// Legacy deprecated
|
||||
bool read_only = 9000 [deprecated=true, (ext.xml) = "ro,attr,omitempty"];
|
||||
double min_disk_free_pct = 9001 [deprecated=true];
|
||||
int32 pullers = 9002 [deprecated=true];
|
||||
bool scan_ownership = 9003 [deprecated=true];
|
||||
}
|
||||
|
||||
// Extended attribute filter. This is a list of patterns to match (glob
|
||||
// style), each with an action (permit or deny). First match is used. If the
|
||||
// filter is empty, all strings are permitted. If the filter is non-empty,
|
||||
// the default action becomes deny. To counter this, you can use the "*"
|
||||
// pattern to match all strings at the end of the filter. There are also
|
||||
// limits on the size of accepted attributes.
|
||||
message XattrFilter {
|
||||
repeated XattrFilterEntry entries = 1 [(ext.xml) = "entry"];
|
||||
int32 max_single_entry_size = 2 [(ext.xml) = "maxSingleEntrySize", (ext.default) = "1024"];
|
||||
int32 max_total_size = 3 [(ext.xml) = "maxTotalSize", (ext.default) = "4096"];
|
||||
}
|
||||
|
||||
message XattrFilterEntry {
|
||||
string match = 1 [(ext.xml) = "match,attr"];
|
||||
bool permit = 2 [(ext.xml) = "permit,attr"];
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package config;
|
||||
|
||||
import "repos/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
enum FolderType {
|
||||
option (gogoproto.goproto_enum_stringer) = false;
|
||||
|
||||
FOLDER_TYPE_SEND_RECEIVE = 0;
|
||||
FOLDER_TYPE_SEND_ONLY = 1;
|
||||
FOLDER_TYPE_RECEIVE_ONLY = 2;
|
||||
FOLDER_TYPE_RECEIVE_ENCRYPTED = 3;
|
||||
}
|
||||
@@ -1,24 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package config;
|
||||
|
||||
import "lib/config/authmode.proto";
|
||||
|
||||
import "ext.proto";
|
||||
|
||||
message GUIConfiguration {
|
||||
bool enabled = 1 [(ext.xml) = "enabled,attr", (ext.default) = "true"];
|
||||
string address = 2 [(ext.goname) = "RawAddress", (ext.default) = "127.0.0.1:8384"];
|
||||
string unix_socket_permissions = 3 [(ext.goname) = "RawUnixSocketPermissions", (ext.xml) = "unixSocketPermissions,omitempty"];
|
||||
string user = 4 [(ext.xml) = "user,omitempty"];
|
||||
string password = 5 [(ext.xml) = "password,omitempty"];
|
||||
AuthMode auth_mode = 6 [(ext.xml) = "authMode,omitempty"];
|
||||
bool use_tls = 7 [(ext.goname) = "RawUseTLS", (ext.xml) = "tls,attr", (ext.json) = "useTLS"];
|
||||
string api_key = 8 [(ext.goname) = "APIKey", (ext.xml) = "apikey,omitempty"];
|
||||
bool insecure_admin_access = 9 [(ext.xml) = "insecureAdminAccess,omitempty"];
|
||||
string theme = 10 [(ext.default) = "default"];
|
||||
bool debugging = 11 [(ext.xml) = "debugging,attr"];
|
||||
bool insecure_skip_host_check = 12 [(ext.xml) = "insecureSkipHostcheck,omitempty", (ext.json) = "insecureSkipHostcheck"];
|
||||
bool insecure_allow_frame_loading = 13 [(ext.xml) = "insecureAllowFrameLoading,omitempty"];
|
||||
bool send_basic_auth_prompt = 14 [(ext.xml) = "sendBasicAuthPrompt,attr"];
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package config;
|
||||
|
||||
import "lib/config/ldaptransport.proto";
|
||||
|
||||
import "ext.proto";
|
||||
|
||||
|
||||
message LDAPConfiguration {
|
||||
string address = 1 [(ext.xml) = "address,omitempty"];
|
||||
string bind_dn = 2 [(ext.goname) = "BindDN", (ext.xml) = "bindDN,omitempty", (ext.json) = "bindDN"];
|
||||
LDAPTransport transport = 3 [(ext.xml) = "transport,omitempty"];
|
||||
bool insecure_skip_verify = 4 [(ext.xml) = "insecureSkipVerify,omitempty", (ext.default) = "false"];
|
||||
string search_base_dn = 5 [(ext.goname) = "SearchBaseDN", (ext.xml) = "searchBaseDN,omitempty", (ext.json) = "searchBaseDN"];
|
||||
string search_filter = 6 [(ext.xml) = "searchFilter,omitempty"];
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package config;
|
||||
|
||||
import "repos/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
import "ext.proto";
|
||||
|
||||
enum LDAPTransport {
|
||||
option (gogoproto.goproto_enum_stringer) = false;
|
||||
|
||||
LDAP_TRANSPORT_PLAIN = 0 [(ext.enumgoname) = "LDAPTransportPlain"];
|
||||
LDAP_TRANSPORT_TLS = 2 [(ext.enumgoname) = "LDAPTransportTLS"];
|
||||
LDAP_TRANSPORT_START_TLS = 3 [(ext.enumgoname) = "LDAPTransportStartTLS"];
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package config;
|
||||
|
||||
import "google/protobuf/timestamp.proto";
|
||||
|
||||
import "ext.proto";
|
||||
|
||||
message ObservedFolder {
|
||||
google.protobuf.Timestamp time = 1 [(ext.xml) = "time,attr"];
|
||||
string id = 2 [(ext.goname) = "ID", (ext.xml) = "id,attr"];
|
||||
string label = 3 [(ext.xml) = "label,attr"];
|
||||
}
|
||||
|
||||
message ObservedDevice {
|
||||
google.protobuf.Timestamp time = 1 [(ext.xml) = "time,attr"];
|
||||
bytes id = 2 [(ext.goname) = "ID", (ext.json) = "deviceID", (ext.xml) = "id,attr", (ext.device_id) = true];
|
||||
string name = 3 [(ext.xml) = "name,attr"];
|
||||
string address = 4 [(ext.xml) = "address,attr"];
|
||||
}
|
||||
@@ -1,88 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package config;
|
||||
|
||||
import "lib/config/tuning.proto";
|
||||
import "lib/config/size.proto";
|
||||
|
||||
import "ext.proto";
|
||||
|
||||
message OptionsConfiguration {
|
||||
repeated string listen_addresses = 1 [(ext.goname) = "RawListenAddresses", (ext.default) = "default"];
|
||||
repeated string global_discovery_servers = 2 [(ext.goname) = "RawGlobalAnnServers", (ext.xml) = "globalAnnounceServer", (ext.json) = "globalAnnounceServers", (ext.default) = "default"];
|
||||
bool global_discovery_enabled = 3 [(ext.goname) = "GlobalAnnEnabled", (ext.xml) = "globalAnnounceEnabled", (ext.json) = "globalAnnounceEnabled", (ext.default) = "true"];
|
||||
bool local_discovery_enabled = 4 [(ext.goname) = "LocalAnnEnabled", (ext.xml) = "localAnnounceEnabled", (ext.json) = "localAnnounceEnabled", (ext.default) = "true"];
|
||||
int32 local_announce_port = 5 [(ext.goname) = "LocalAnnPort", (ext.xml) = "localAnnouncePort", (ext.json) = "localAnnouncePort", (ext.default) = "21027"];
|
||||
string local_announce_multicast_address = 6 [(ext.goname) = "LocalAnnMCAddr", (ext.xml) = "localAnnounceMCAddr", (ext.json) = "localAnnounceMCAddr", (ext.default) = "[ff12::8384]:21027"];
|
||||
int32 max_send_kbps = 7;
|
||||
int32 max_recv_kbps = 8;
|
||||
int32 reconnection_interval_s = 9 [(ext.goname) = "ReconnectIntervalS", (ext.default) = "60"];
|
||||
bool relays_enabled = 10 [(ext.default) = "true"];
|
||||
int32 relays_reconnect_interval_m = 11 [(ext.goname) = "RelayReconnectIntervalM", (ext.xml) = "relayReconnectIntervalM", (ext.json) = "relayReconnectIntervalM", (ext.default) = "10"];
|
||||
bool start_browser = 12 [(ext.default) = "true"];
|
||||
bool nat_traversal_enabled = 14 [(ext.goname) = "NATEnabled", (ext.xml) = "natEnabled", (ext.json) = "natEnabled", (ext.default) = "true"];
|
||||
int32 nat_traversal_lease_m = 15 [(ext.goname) = "NATLeaseM", (ext.xml) = "natLeaseMinutes", (ext.json) = "natLeaseMinutes", (ext.default) = "60"];
|
||||
int32 nat_traversal_renewal_m = 16 [(ext.goname) = "NATRenewalM", (ext.xml) = "natRenewalMinutes", (ext.json) = "natRenewalMinutes", (ext.default) = "30"];
|
||||
int32 nat_traversal_timeout_s = 17 [(ext.goname) = "NATTimeoutS", (ext.xml) = "natTimeoutSeconds", (ext.json) = "natTimeoutSeconds", (ext.default) = "10"];
|
||||
int32 usage_reporting_accepted = 18 [(ext.goname) = "URAccepted", (ext.xml) = "urAccepted", (ext.json) = "urAccepted"];
|
||||
int32 usage_reporting_seen = 19 [(ext.goname) = "URSeen", (ext.xml) = "urSeen", (ext.json) = "urSeen"];
|
||||
string usage_reporting_unique_id = 20 [(ext.goname) = "URUniqueID", (ext.xml) = "urUniqueID", (ext.json) = "urUniqueId"];
|
||||
string usage_reporting_url = 21 [(ext.goname) = "URURL", (ext.xml) = "urURL", (ext.json) = "urURL", (ext.default) = "https://data.syncthing.net/newdata"];
|
||||
bool usage_reporting_post_insecurely = 22 [(ext.goname) = "URPostInsecurely", (ext.xml) = "urPostInsecurely", (ext.json) = "urPostInsecurely", (ext.default) = "false"];
|
||||
int32 usage_reporting_initial_delay_s = 23 [(ext.goname) = "URInitialDelayS", (ext.xml) = "urInitialDelayS", (ext.json) = "urInitialDelayS", (ext.default) = "1800"];
|
||||
int32 auto_upgrade_interval_h = 25 [(ext.default) = "12"];
|
||||
bool upgrade_to_pre_releases = 26;
|
||||
int32 keep_temporaries_h = 27 [(ext.default) = "24"];
|
||||
bool cache_ignored_files = 28 [(ext.default) = "false"];
|
||||
int32 progress_update_interval_s = 29 [(ext.default) = "5"];
|
||||
bool limit_bandwidth_in_lan = 30 [(ext.default) = "false"];
|
||||
Size min_home_disk_free = 31 [(ext.default) = "1 %"];
|
||||
string releases_url = 32 [(ext.goname) = "ReleasesURL", (ext.xml) = "releasesURL", (ext.json) = "releasesURL", (ext.default) = "https://upgrades.syncthing.net/meta.json"];
|
||||
repeated string always_local_nets = 33;
|
||||
bool overwrite_remote_device_names_on_connect = 34 [(ext.goname) = "OverwriteRemoteDevNames", (ext.default) = "false"];
|
||||
int32 temp_index_min_blocks = 35 [(ext.default) = "10"];
|
||||
repeated string unacked_notification_ids = 36 [(ext.goname) = "UnackedNotificationIDs", (ext.xml) = "unackedNotificationID", (ext.json) = "unackedNotificationIDs"];
|
||||
int32 traffic_class = 37;
|
||||
string default_folder_path = 38 [deprecated = true];
|
||||
bool set_low_priority = 39 [(ext.default) = "true"];
|
||||
int32 max_folder_concurrency = 40 [(ext.goname) = "RawMaxFolderConcurrency"];
|
||||
string crash_reporting_url = 41 [(ext.goname) = "CRURL", (ext.xml) = "crashReportingURL", (ext.json) = "crURL", (ext.default) = "https://crash.syncthing.net/newcrash"];
|
||||
bool crash_reporting_enabled = 42 [(ext.goname) = "CREnabled", (ext.default) = "true"];
|
||||
int32 stun_keepalive_start_s = 43 [(ext.default) = "180"];
|
||||
int32 stun_keepalive_min_s = 44 [(ext.default) = "20"];
|
||||
repeated string stun_servers = 45 [(ext.goname) = "RawStunServers", (ext.default) = "default"];
|
||||
Tuning database_tuning = 46 [(ext.restart) = true];
|
||||
int32 max_concurrent_incoming_request_kib = 47 [(ext.goname) = "RawMaxCIRequestKiB", (ext.xml) = "maxConcurrentIncomingRequestKiB", (ext.json) = "maxConcurrentIncomingRequestKiB"];
|
||||
bool announce_lan_addresses = 48 [(ext.goname)= "AnnounceLANAddresses", (ext.xml) = "announceLANAddresses", (ext.json) = "announceLANAddresses", (ext.default) = "true"];
|
||||
bool send_full_index_on_upgrade = 49;
|
||||
repeated string feature_flags = 50;
|
||||
|
||||
// The number of connections at which we stop trying to connect to more
|
||||
// devices, zero meaning no limit. Does not affect incoming connections.
|
||||
int32 connection_limit_enough = 51;
|
||||
|
||||
// The maximum number of connections which we will allow in total, zero
|
||||
// meaning no limit. Affects incoming connections and prevents
|
||||
// attempting outgoing connections.
|
||||
int32 connection_limit_max = 52;
|
||||
|
||||
// When set, this allows TLS 1.2 on sync connections, where we otherwise
|
||||
// default to TLS 1.3+ only.
|
||||
bool insecure_allow_old_tls_versions = 53 [(ext.goname)= "InsecureAllowOldTLSVersions", (ext.xml) = "insecureAllowOldTLSVersions", (ext.json) = "insecureAllowOldTLSVersions"];
|
||||
|
||||
int32 connection_priority_tcp_lan = 54 [(ext.default) = "10", (ext.goname) = "ConnectionPriorityTCPLAN"];
|
||||
int32 connection_priority_quic_lan = 55 [(ext.default) = "20", (ext.goname) = "ConnectionPriorityQUICLAN"];
|
||||
int32 connection_priority_tcp_wan = 56 [(ext.default) = "30", (ext.goname) = "ConnectionPriorityTCPWAN"];
|
||||
int32 connection_priority_quic_wan = 57 [(ext.default) = "40", (ext.goname) = "ConnectionPriorityQUICWAN"];
|
||||
int32 connection_priority_relay = 58 [(ext.default) = "50"];
|
||||
int32 connection_priority_upgrade_threshold = 59 [(ext.default) = "0"];
|
||||
|
||||
// Legacy deprecated
|
||||
bool upnp_enabled = 9000 [deprecated = true, (ext.goname) = "DeprecatedUPnPEnabled"];
|
||||
int32 upnp_lease_m = 9001 [deprecated = true, (ext.goname) = "DeprecatedUPnPLeaseM", (ext.xml) = "upnpLeaseMinutes,omitempty"];
|
||||
int32 upnp_renewal_m = 9002 [deprecated = true, (ext.goname) = "DeprecatedUPnPRenewalM", (ext.xml) = "upnpRenewalMinutes,omitempty"];
|
||||
int32 upnp_timeout_s = 9003 [deprecated = true, (ext.goname) = "DeprecatedUPnPTimeoutS", (ext.xml) = "upnpTimeoutSeconds,omitempty"];
|
||||
repeated string relay_servers = 9004 [deprecated = true];
|
||||
double min_home_disk_free_pct = 9005 [deprecated = true];
|
||||
int32 max_concurrent_scans = 9006 [deprecated = true];
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package config;
|
||||
|
||||
import "repos/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
enum PullOrder {
|
||||
option (gogoproto.goproto_enum_stringer) = false;
|
||||
|
||||
PULL_ORDER_RANDOM = 0;
|
||||
PULL_ORDER_ALPHABETIC = 1;
|
||||
PULL_ORDER_SMALLEST_FIRST = 2;
|
||||
PULL_ORDER_LARGEST_FIRST = 3;
|
||||
PULL_ORDER_OLDEST_FIRST = 4;
|
||||
PULL_ORDER_NEWEST_FIRST = 5;
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package config;
|
||||
|
||||
import "repos/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
import "ext.proto";
|
||||
|
||||
message Size {
|
||||
option (gogoproto.goproto_stringer) = false;
|
||||
|
||||
double value = 1 [(ext.xml) = ",chardata"];
|
||||
string unit = 2 [(ext.xml) = "unit,attr"];
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package config;
|
||||
|
||||
import "repos/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
enum Tuning {
|
||||
option (gogoproto.goproto_enum_stringer) = false;
|
||||
|
||||
TUNING_AUTO = 0;
|
||||
TUNING_SMALL = 1;
|
||||
TUNING_LARGE = 2;
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package config;
|
||||
|
||||
import "lib/fs/types.proto";
|
||||
|
||||
import "ext.proto";
|
||||
|
||||
// VersioningConfiguration is used in the code and for JSON serialization
|
||||
message VersioningConfiguration {
|
||||
string type = 1[(ext.xml) = "type,attr"];
|
||||
map<string, string> parameters = 2 [(ext.goname) = "Params", (ext.json) = "params"];
|
||||
int32 cleanup_interval_s = 3 [(ext.default) = "3600"];
|
||||
string fs_path = 4 [(ext.goname) = "FSPath"];
|
||||
fs.FilesystemType fs_type = 5 [(ext.goname) = "FSType"];
|
||||
}
|
||||
@@ -1,106 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package db;
|
||||
|
||||
import "repos/protobuf/gogoproto/gogo.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "lib/protocol/bep.proto";
|
||||
import "ext.proto";
|
||||
|
||||
message FileVersion {
|
||||
protocol.Vector version = 1;
|
||||
bool deleted = 2;
|
||||
repeated bytes devices = 3;
|
||||
repeated bytes invalid_devices = 4;
|
||||
}
|
||||
|
||||
message VersionList {
|
||||
option (gogoproto.goproto_stringer) = false;
|
||||
repeated FileVersion versions = 1 [(ext.goname) = "RawVersions"];
|
||||
}
|
||||
|
||||
// Must be the same as FileInfo but without the blocks field
|
||||
message FileInfoTruncated {
|
||||
option (gogoproto.goproto_stringer) = false;
|
||||
string name = 1;
|
||||
int64 size = 3;
|
||||
int64 modified_s = 5;
|
||||
uint64 modified_by = 12 [(ext.gotype) = "github.com/syncthing/syncthing/lib/protocol.ShortID"];
|
||||
protocol.Vector version = 9;
|
||||
int64 sequence = 10;
|
||||
// repeated BlockInfo Blocks = 16
|
||||
string symlink_target = 17;
|
||||
bytes blocks_hash = 18;
|
||||
bytes encrypted = 19;
|
||||
protocol.FileInfoType type = 2;
|
||||
uint32 permissions = 4;
|
||||
int32 modified_ns = 11;
|
||||
int32 block_size = 13 [(ext.goname) = "RawBlockSize"];
|
||||
protocol.PlatformData platform = 14;
|
||||
|
||||
// see bep.proto
|
||||
uint32 local_flags = 1000;
|
||||
bytes version_hash = 1001;
|
||||
int64 inode_change_ns = 1002;
|
||||
|
||||
bool deleted = 6;
|
||||
bool invalid = 7 [(ext.goname) = "RawInvalid"];
|
||||
bool no_permissions = 8;
|
||||
}
|
||||
|
||||
// BlockList is the structure used to store block lists
|
||||
message BlockList {
|
||||
repeated protocol.BlockInfo blocks = 1;
|
||||
}
|
||||
|
||||
// IndirectionHashesOnly is used to only unmarshal the indirection hashes
|
||||
// from a FileInfo
|
||||
message IndirectionHashesOnly {
|
||||
bytes blocks_hash = 18;
|
||||
bytes version_hash = 1001;
|
||||
}
|
||||
|
||||
// For each folder and device we keep one of these to track the current
|
||||
// counts and sequence. We also keep one for the global state of the folder.
|
||||
message Counts {
|
||||
option (gogoproto.goproto_stringer) = false;
|
||||
|
||||
int32 files = 1;
|
||||
int32 directories = 2;
|
||||
int32 symlinks = 3;
|
||||
int32 deleted = 4;
|
||||
int64 bytes = 5;
|
||||
int64 sequence = 6; // zero for the global state
|
||||
bytes device_id = 17 [(ext.goname) = "DeviceID"]; // device ID for remote devices, or special values for local/global
|
||||
uint32 local_flags = 18; // the local flag for this count bucket
|
||||
}
|
||||
|
||||
message CountsSet {
|
||||
repeated Counts counts = 1;
|
||||
int64 created = 2; // unix nanos
|
||||
}
|
||||
|
||||
message FileVersionDeprecated {
|
||||
protocol.Vector version = 1;
|
||||
bytes device = 2;
|
||||
bool invalid = 3;
|
||||
bool deleted = 4;
|
||||
}
|
||||
|
||||
message VersionListDeprecated {
|
||||
option (gogoproto.goproto_stringer) = false;
|
||||
repeated FileVersionDeprecated versions = 1;
|
||||
}
|
||||
|
||||
message ObservedFolder {
|
||||
google.protobuf.Timestamp time = 1 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
string label = 2;
|
||||
bool receive_encrypted = 3;
|
||||
bool remote_encrypted = 4;
|
||||
}
|
||||
|
||||
message ObservedDevice {
|
||||
google.protobuf.Timestamp time = 1 [(gogoproto.stdtime) = true, (gogoproto.nullable) = false];
|
||||
string name = 2;
|
||||
string address = 3;
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package discover;
|
||||
|
||||
import "repos/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
import "ext.proto";
|
||||
|
||||
message Announce {
|
||||
bytes id = 1 [(ext.goname) = "ID", (ext.device_id) = true, (gogoproto.nullable) = false];
|
||||
repeated string addresses = 2;
|
||||
int64 instance_id = 3 [(ext.goname) = "InstanceID"];
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package fs;
|
||||
|
||||
import "repos/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
enum CopyRangeMethod {
|
||||
option (gogoproto.goproto_enum_stringer) = false;
|
||||
|
||||
COPY_RANGE_METHOD_STANDARD = 0;
|
||||
COPY_RANGE_METHOD_IOCTL = 1;
|
||||
COPY_RANGE_METHOD_COPY_FILE_RANGE = 2;
|
||||
COPY_RANGE_METHOD_SEND_FILE = 3;
|
||||
COPY_RANGE_METHOD_DUPLICATE_EXTENTS = 4;
|
||||
COPY_RANGE_METHOD_ALL_WITH_FALLBACK = 5;
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package fs;
|
||||
|
||||
import "repos/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
enum FilesystemType {
|
||||
option (gogoproto.goproto_enum_stringer) = false;
|
||||
|
||||
FILESYSTEM_TYPE_BASIC = 0;
|
||||
FILESYSTEM_TYPE_FAKE = 1;
|
||||
}
|
||||
@@ -1,261 +0,0 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package protocol;
|
||||
|
||||
import "ext.proto";
|
||||
import "repos/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
// --- Pre-auth ---
|
||||
|
||||
message Hello {
|
||||
string device_name = 1;
|
||||
string client_name = 2;
|
||||
string client_version = 3;
|
||||
int32 num_connections = 4;
|
||||
int64 timestamp = 5;
|
||||
}
|
||||
|
||||
// --- Header ---
|
||||
|
||||
message Header {
|
||||
MessageType type = 1;
|
||||
MessageCompression compression = 2;
|
||||
}
|
||||
|
||||
enum MessageType {
|
||||
MESSAGE_TYPE_CLUSTER_CONFIG = 0;
|
||||
MESSAGE_TYPE_INDEX = 1;
|
||||
MESSAGE_TYPE_INDEX_UPDATE = 2;
|
||||
MESSAGE_TYPE_REQUEST = 3;
|
||||
MESSAGE_TYPE_RESPONSE = 4;
|
||||
MESSAGE_TYPE_DOWNLOAD_PROGRESS = 5;
|
||||
MESSAGE_TYPE_PING = 6;
|
||||
MESSAGE_TYPE_CLOSE = 7;
|
||||
}
|
||||
|
||||
enum MessageCompression {
|
||||
MESSAGE_COMPRESSION_NONE = 0;
|
||||
MESSAGE_COMPRESSION_LZ4 = 1 [(ext.enumgoname) = "MessageCompressionLZ4"];
|
||||
}
|
||||
|
||||
// --- Actual messages ---
|
||||
|
||||
// Cluster Config
|
||||
|
||||
message ClusterConfig {
|
||||
repeated Folder folders = 1;
|
||||
bool secondary = 2;
|
||||
}
|
||||
|
||||
message Folder {
|
||||
string id = 1 [(ext.goname) = "ID"];
|
||||
string label = 2;
|
||||
bool read_only = 3;
|
||||
bool ignore_permissions = 4;
|
||||
bool ignore_delete = 5;
|
||||
bool disable_temp_indexes = 6;
|
||||
bool paused = 7;
|
||||
|
||||
repeated Device devices = 16;
|
||||
}
|
||||
|
||||
message Device {
|
||||
bytes id = 1 [(ext.goname) = "ID", (ext.device_id) = true];
|
||||
string name = 2;
|
||||
repeated string addresses = 3;
|
||||
Compression compression = 4;
|
||||
string cert_name = 5;
|
||||
int64 max_sequence = 6;
|
||||
bool introducer = 7;
|
||||
uint64 index_id = 8 [(ext.goname) = "IndexID", (ext.gotype) = "IndexID"];
|
||||
bool skip_introduction_removals = 9;
|
||||
bytes encryption_password_token = 10;
|
||||
}
|
||||
|
||||
enum Compression {
|
||||
COMPRESSION_METADATA = 0;
|
||||
COMPRESSION_NEVER = 1;
|
||||
COMPRESSION_ALWAYS = 2;
|
||||
}
|
||||
|
||||
// Index and Index Update
|
||||
|
||||
message Index {
|
||||
string folder = 1;
|
||||
repeated FileInfo files = 2;
|
||||
int64 last_sequence = 3; // the highest sequence in this batch
|
||||
}
|
||||
|
||||
message IndexUpdate {
|
||||
string folder = 1;
|
||||
repeated FileInfo files = 2;
|
||||
int64 last_sequence = 3; // the highest sequence in this batch
|
||||
int64 prev_sequence = 4; // the highest sequence in the previous batch
|
||||
}
|
||||
|
||||
message FileInfo {
|
||||
option (gogoproto.goproto_stringer) = false;
|
||||
|
||||
// The field ordering here optimizes for struct size / alignment --
|
||||
// large types come before smaller ones.
|
||||
|
||||
string name = 1;
|
||||
int64 size = 3;
|
||||
int64 modified_s = 5;
|
||||
uint64 modified_by = 12 [(ext.gotype) = "ShortID"];
|
||||
Vector version = 9;
|
||||
int64 sequence = 10;
|
||||
repeated BlockInfo blocks = 16;
|
||||
string symlink_target = 17;
|
||||
bytes blocks_hash = 18;
|
||||
bytes encrypted = 19;
|
||||
FileInfoType type = 2;
|
||||
uint32 permissions = 4;
|
||||
int32 modified_ns = 11;
|
||||
int32 block_size = 13 [(ext.goname) = "RawBlockSize"];
|
||||
PlatformData platform = 14;
|
||||
|
||||
// The local_flags fields stores flags that are relevant to the local
|
||||
// host only. It is not part of the protocol, doesn't get sent or
|
||||
// received (we make sure to zero it), nonetheless we need it on our
|
||||
// struct and to be able to serialize it to/from the database.
|
||||
uint32 local_flags = 1000;
|
||||
|
||||
// The version_hash is an implementation detail and not part of the wire
|
||||
// format.
|
||||
bytes version_hash = 1001;
|
||||
|
||||
// The time when the inode was last changed (i.e., permissions, xattrs
|
||||
// etc changed). This is host-local, not sent over the wire.
|
||||
int64 inode_change_ns = 1002;
|
||||
|
||||
// The size of the data appended to the encrypted file on disk. This is
|
||||
// host-local, not sent over the wire.
|
||||
int32 encryption_trailer_size = 1003;
|
||||
|
||||
bool deleted = 6;
|
||||
bool invalid = 7 [(ext.goname) = "RawInvalid"];
|
||||
bool no_permissions = 8;
|
||||
}
|
||||
|
||||
enum FileInfoType {
|
||||
FILE_INFO_TYPE_FILE = 0;
|
||||
FILE_INFO_TYPE_DIRECTORY = 1;
|
||||
FILE_INFO_TYPE_SYMLINK_FILE = 2 [deprecated = true];
|
||||
FILE_INFO_TYPE_SYMLINK_DIRECTORY = 3 [deprecated = true];
|
||||
FILE_INFO_TYPE_SYMLINK = 4;
|
||||
}
|
||||
|
||||
message BlockInfo {
|
||||
option (gogoproto.goproto_stringer) = false;
|
||||
bytes hash = 3;
|
||||
int64 offset = 1;
|
||||
int32 size = 2;
|
||||
uint32 weak_hash = 4;
|
||||
}
|
||||
|
||||
message Vector {
|
||||
repeated Counter counters = 1;
|
||||
}
|
||||
|
||||
message Counter {
|
||||
uint64 id = 1 [(ext.goname) = "ID", (ext.gotype) = "ShortID"];
|
||||
uint64 value = 2;
|
||||
}
|
||||
|
||||
message PlatformData {
|
||||
UnixData unix = 1 [(gogoproto.nullable) = true];
|
||||
WindowsData windows = 2 [(gogoproto.nullable) = true];
|
||||
XattrData linux = 3 [(gogoproto.nullable) = true];
|
||||
XattrData darwin = 4 [(gogoproto.nullable) = true];
|
||||
XattrData freebsd = 5 [(gogoproto.nullable) = true, (ext.goname) = "FreeBSD"];
|
||||
XattrData netbsd = 6 [(gogoproto.nullable) = true, (ext.goname) = "NetBSD"];
|
||||
}
|
||||
|
||||
message UnixData {
|
||||
// The owner name and group name are set when known (i.e., could be
|
||||
// resolved on the source device), while the UID and GID are always set
|
||||
// as they come directly from the stat() call.
|
||||
string owner_name = 1;
|
||||
string group_name = 2;
|
||||
int32 uid = 3 [(ext.goname) = "UID"];
|
||||
int32 gid = 4 [(ext.goname) = "GID"];
|
||||
}
|
||||
|
||||
message WindowsData {
|
||||
// Windows file objects have a single owner, which may be a user or a
|
||||
// group. We keep the name of that account, and a flag to indicate what
|
||||
// type it is.
|
||||
string owner_name = 1;
|
||||
bool owner_is_group = 2;
|
||||
}
|
||||
|
||||
message XattrData {
|
||||
repeated Xattr xattrs = 1;
|
||||
}
|
||||
|
||||
message Xattr {
|
||||
string name = 1;
|
||||
bytes value = 2;
|
||||
}
|
||||
|
||||
// Request
|
||||
|
||||
message Request {
|
||||
int32 id = 1 [(ext.goname) = "ID"];
|
||||
string folder = 2;
|
||||
string name = 3;
|
||||
int64 offset = 4;
|
||||
int32 size = 5;
|
||||
bytes hash = 6;
|
||||
bool from_temporary = 7;
|
||||
uint32 weak_hash = 8;
|
||||
int32 block_no = 9;
|
||||
}
|
||||
|
||||
// Response
|
||||
|
||||
message Response {
|
||||
int32 id = 1 [(ext.goname) = "ID"];
|
||||
bytes data = 2;
|
||||
ErrorCode code = 3;
|
||||
}
|
||||
|
||||
enum ErrorCode {
|
||||
ERROR_CODE_NO_ERROR = 0;
|
||||
ERROR_CODE_GENERIC = 1;
|
||||
ERROR_CODE_NO_SUCH_FILE = 2;
|
||||
ERROR_CODE_INVALID_FILE = 3;
|
||||
}
|
||||
|
||||
// DownloadProgress
|
||||
|
||||
message DownloadProgress {
|
||||
string folder = 1;
|
||||
repeated FileDownloadProgressUpdate updates = 2;
|
||||
}
|
||||
|
||||
message FileDownloadProgressUpdate {
|
||||
FileDownloadProgressUpdateType update_type = 1;
|
||||
string name = 2;
|
||||
Vector version = 3;
|
||||
repeated int32 block_indexes = 4 [packed=false];
|
||||
int32 block_size = 5;
|
||||
}
|
||||
|
||||
enum FileDownloadProgressUpdateType {
|
||||
FILE_DOWNLOAD_PROGRESS_UPDATE_TYPE_APPEND = 0;
|
||||
FILE_DOWNLOAD_PROGRESS_UPDATE_TYPE_FORGET = 1;
|
||||
}
|
||||
|
||||
// Ping
|
||||
|
||||
message Ping {
|
||||
}
|
||||
|
||||
// Close
|
||||
|
||||
message Close {
|
||||
string reason = 1;
|
||||
}
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package protocol;
|
||||
|
||||
import "ext.proto";
|
||||
import "repos/protobuf/gogoproto/gogo.proto";
|
||||
|
||||
message TestOldDeviceID {
|
||||
bytes test = 1;
|
||||
}
|
||||
|
||||
message TestNewDeviceID {
|
||||
bytes test = 1 [(ext.device_id) = true, (gogoproto.nullable) = false];
|
||||
}
|
||||
@@ -1,68 +0,0 @@
|
||||
// Copyright (C) 2020 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"encoding/csv"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"reflect"
|
||||
"strings"
|
||||
|
||||
"github.com/syncthing/syncthing/lib/config"
|
||||
)
|
||||
|
||||
func main() {
|
||||
new, err := os.Create("tags.csv")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
fmt.Println(filepath.Abs(new.Name()))
|
||||
w := csv.NewWriter(new)
|
||||
w.Write([]string{
|
||||
"path", "json", "xml", "default", "restart",
|
||||
})
|
||||
walk(w, "", &config.Configuration{})
|
||||
w.Flush()
|
||||
new.Close()
|
||||
}
|
||||
|
||||
func walk(w *csv.Writer, prefix string, data interface{}) {
|
||||
s := reflect.ValueOf(data).Elem()
|
||||
t := s.Type()
|
||||
for i := 0; i < s.NumField(); i++ {
|
||||
f := s.Field(i)
|
||||
ft := t.Field(i)
|
||||
|
||||
for f.Kind() == reflect.Ptr {
|
||||
f = f.Elem()
|
||||
}
|
||||
|
||||
pfx := prefix + "." + s.Type().Field(i).Name
|
||||
if f.Kind() == reflect.Slice {
|
||||
slc := reflect.MakeSlice(f.Type(), 1, 1)
|
||||
f = slc.Index(0)
|
||||
pfx = prefix + "." + s.Type().Field(i).Name + "[]"
|
||||
}
|
||||
|
||||
if f.Kind() == reflect.Struct && strings.HasPrefix(f.Type().PkgPath(), "github.com/syncthing/syncthing") {
|
||||
walk(w, pfx, f.Addr().Interface())
|
||||
} else {
|
||||
jsonTag := ft.Tag.Get("json")
|
||||
xmlTag := ft.Tag.Get("xml")
|
||||
defaultTag := ft.Tag.Get("default")
|
||||
restartTag := ft.Tag.Get("restart")
|
||||
w.Write([]string{
|
||||
strings.ToLower(pfx), jsonTag, xmlTag, defaultTag, restartTag,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,313 +0,0 @@
|
||||
// Copyright (C) 2020 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/syncthing/syncthing/proto/ext"
|
||||
|
||||
"github.com/gogo/protobuf/gogoproto"
|
||||
"github.com/gogo/protobuf/proto"
|
||||
"github.com/gogo/protobuf/protoc-gen-gogo/descriptor"
|
||||
"github.com/gogo/protobuf/vanity"
|
||||
"github.com/gogo/protobuf/vanity/command"
|
||||
)
|
||||
|
||||
func main() {
|
||||
req := command.Read()
|
||||
files := req.GetProtoFile()
|
||||
files = vanity.FilterFiles(files, vanity.NotGoogleProtobufDescriptorProto)
|
||||
|
||||
vanity.ForEachFile(files, vanity.TurnOffGoGettersAll)
|
||||
vanity.ForEachFile(files, TurnOnProtoSizerAll)
|
||||
vanity.ForEachFile(files, vanity.TurnOffGoEnumPrefixAll)
|
||||
vanity.ForEachFile(files, vanity.TurnOffGoUnrecognizedAll)
|
||||
vanity.ForEachFile(files, vanity.TurnOffGoUnkeyedAll)
|
||||
vanity.ForEachFile(files, vanity.TurnOffGoSizecacheAll)
|
||||
vanity.ForEachFile(files, vanity.TurnOnMarshalerAll)
|
||||
vanity.ForEachFile(files, vanity.TurnOnUnmarshalerAll)
|
||||
vanity.ForEachEnumInFiles(files, HandleCustomEnumExtensions)
|
||||
vanity.ForEachFile(files, SetPackagePrefix("github.com/syncthing/syncthing"))
|
||||
vanity.ForEachFile(files, HandleFile)
|
||||
vanity.ForEachFieldInFilesExcludingExtensions(files, TurnOffNullableForMessages)
|
||||
|
||||
resp := command.Generate(req)
|
||||
command.Write(resp)
|
||||
}
|
||||
|
||||
func TurnOnProtoSizerAll(file *descriptor.FileDescriptorProto) {
|
||||
vanity.SetBoolFileOption(gogoproto.E_ProtosizerAll, true)(file)
|
||||
}
|
||||
|
||||
func TurnOffNullableForMessages(field *descriptor.FieldDescriptorProto) {
|
||||
if !vanity.FieldHasBoolExtension(field, gogoproto.E_Nullable) {
|
||||
_, hasCustomType := GetFieldStringExtension(field, gogoproto.E_Customtype)
|
||||
if field.IsMessage() || hasCustomType {
|
||||
vanity.SetBoolFieldOption(gogoproto.E_Nullable, false)(field)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func HandleCustomEnumExtensions(enum *descriptor.EnumDescriptorProto) {
|
||||
for _, field := range enum.Value {
|
||||
if field == nil {
|
||||
continue
|
||||
}
|
||||
if field.Options == nil {
|
||||
field.Options = &descriptor.EnumValueOptions{}
|
||||
}
|
||||
customName := gogoproto.GetEnumValueCustomName(field)
|
||||
if customName != "" {
|
||||
continue
|
||||
}
|
||||
if v, ok := GetEnumValueStringExtension(field, ext.E_Enumgoname); ok {
|
||||
SetEnumValueStringFieldOption(field, gogoproto.E_EnumvalueCustomname, v)
|
||||
} else {
|
||||
SetEnumValueStringFieldOption(field, gogoproto.E_EnumvalueCustomname, toCamelCase(*field.Name, true))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
func SetPackagePrefix(prefix string) func(file *descriptor.FileDescriptorProto) {
|
||||
return func(file *descriptor.FileDescriptorProto) {
|
||||
if file.Options.GoPackage == nil {
|
||||
pkg, _ := filepath.Split(file.GetName())
|
||||
fullPkg := prefix + "/" + strings.TrimSuffix(pkg, "/")
|
||||
file.Options.GoPackage = &fullPkg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toCamelCase(input string, firstUpper bool) string {
|
||||
runes := []rune(strings.ToLower(input))
|
||||
outputRunes := make([]rune, 0, len(runes))
|
||||
|
||||
nextUpper := false
|
||||
for i, rune := range runes {
|
||||
if rune == '_' {
|
||||
nextUpper = true
|
||||
continue
|
||||
}
|
||||
if (firstUpper && i == 0) || nextUpper {
|
||||
rune = unicode.ToUpper(rune)
|
||||
nextUpper = false
|
||||
}
|
||||
outputRunes = append(outputRunes, rune)
|
||||
}
|
||||
return string(outputRunes)
|
||||
}
|
||||
|
||||
func SetStringFieldOption(field *descriptor.FieldDescriptorProto, extension *proto.ExtensionDesc, value string) {
|
||||
if _, ok := GetFieldStringExtension(field, extension); ok {
|
||||
return
|
||||
}
|
||||
if field.Options == nil {
|
||||
field.Options = &descriptor.FieldOptions{}
|
||||
}
|
||||
if err := proto.SetExtension(field.Options, extension, &value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func SetEnumValueStringFieldOption(field *descriptor.EnumValueDescriptorProto, extension *proto.ExtensionDesc, value string) {
|
||||
if _, ok := GetEnumValueStringExtension(field, extension); ok {
|
||||
return
|
||||
}
|
||||
if field.Options == nil {
|
||||
field.Options = &descriptor.EnumValueOptions{}
|
||||
}
|
||||
if err := proto.SetExtension(field.Options, extension, &value); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
}
|
||||
|
||||
func GetEnumValueStringExtension(enumValue *descriptor.EnumValueDescriptorProto, extension *proto.ExtensionDesc) (string, bool) {
|
||||
if enumValue.Options == nil {
|
||||
return "", false
|
||||
}
|
||||
value, err := proto.GetExtension(enumValue.Options, extension)
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
if value == nil {
|
||||
return "", false
|
||||
}
|
||||
if v, ok := value.(*string); !ok || v == nil {
|
||||
return "", false
|
||||
} else {
|
||||
return *v, true
|
||||
}
|
||||
}
|
||||
|
||||
func GetFieldStringExtension(field *descriptor.FieldDescriptorProto, extension *proto.ExtensionDesc) (string, bool) {
|
||||
if field.Options == nil {
|
||||
return "", false
|
||||
}
|
||||
value, err := proto.GetExtension(field.Options, extension)
|
||||
if err != nil {
|
||||
return "", false
|
||||
}
|
||||
if value == nil {
|
||||
return "", false
|
||||
}
|
||||
if v, ok := value.(*string); !ok || v == nil {
|
||||
return "", false
|
||||
} else {
|
||||
return *v, true
|
||||
}
|
||||
}
|
||||
|
||||
func GetFieldBooleanExtension(field *descriptor.FieldDescriptorProto, extension *proto.ExtensionDesc) (bool, bool) {
|
||||
if field.Options == nil {
|
||||
return false, false
|
||||
}
|
||||
value, err := proto.GetExtension(field.Options, extension)
|
||||
if err != nil {
|
||||
return false, false
|
||||
}
|
||||
if value == nil {
|
||||
return false, false
|
||||
}
|
||||
if v, ok := value.(*bool); !ok || v == nil {
|
||||
return false, false
|
||||
} else {
|
||||
return *v, true
|
||||
}
|
||||
}
|
||||
|
||||
func GetMessageBoolExtension(msg *descriptor.DescriptorProto, extension *proto.ExtensionDesc) (bool, bool) {
|
||||
if msg.Options == nil {
|
||||
return false, false
|
||||
}
|
||||
value, err := proto.GetExtension(msg.Options, extension)
|
||||
if err != nil {
|
||||
return false, false
|
||||
}
|
||||
if value == nil {
|
||||
return false, false
|
||||
}
|
||||
val, ok := value.(*bool)
|
||||
if !ok || val == nil {
|
||||
return false, false
|
||||
}
|
||||
return *val, true
|
||||
}
|
||||
|
||||
func HandleFile(file *descriptor.FileDescriptorProto) {
|
||||
vanity.ForEachMessageInFiles([]*descriptor.FileDescriptorProto{file}, HandleCustomExtensions(file))
|
||||
}
|
||||
|
||||
func HandleCustomExtensions(file *descriptor.FileDescriptorProto) func(msg *descriptor.DescriptorProto) {
|
||||
return func(msg *descriptor.DescriptorProto) {
|
||||
generateXmlTags := true
|
||||
if generate, ok := GetMessageBoolExtension(msg, ext.E_XmlTags); ok {
|
||||
generateXmlTags = generate
|
||||
}
|
||||
|
||||
vanity.ForEachField([]*descriptor.DescriptorProto{msg}, func(field *descriptor.FieldDescriptorProto) {
|
||||
if field.Options == nil {
|
||||
field.Options = &descriptor.FieldOptions{}
|
||||
}
|
||||
deprecated := field.Options.Deprecated != nil && *field.Options.Deprecated == true
|
||||
|
||||
if field.Type != nil && *field.Type == descriptor.FieldDescriptorProto_TYPE_INT32 {
|
||||
SetStringFieldOption(field, gogoproto.E_Casttype, "int")
|
||||
}
|
||||
|
||||
if field.TypeName != nil && *field.TypeName == ".google.protobuf.Timestamp" {
|
||||
vanity.SetBoolFieldOption(gogoproto.E_Stdtime, true)(field)
|
||||
}
|
||||
|
||||
if goName, ok := GetFieldStringExtension(field, ext.E_Goname); ok {
|
||||
SetStringFieldOption(field, gogoproto.E_Customname, goName)
|
||||
} else if deprecated {
|
||||
SetStringFieldOption(field, gogoproto.E_Customname, "Deprecated"+toCamelCase(*field.Name, true))
|
||||
}
|
||||
|
||||
if goType, ok := GetFieldStringExtension(field, ext.E_Gotype); ok {
|
||||
SetStringFieldOption(field, gogoproto.E_Customtype, goType)
|
||||
}
|
||||
|
||||
if val, ok := GetFieldBooleanExtension(field, ext.E_DeviceId); ok && val {
|
||||
if *file.Options.GoPackage != "github.com/syncthing/syncthing/lib/protocol" {
|
||||
SetStringFieldOption(field, gogoproto.E_Customtype, "github.com/syncthing/syncthing/lib/protocol.DeviceID")
|
||||
} else {
|
||||
SetStringFieldOption(field, gogoproto.E_Customtype, "DeviceID")
|
||||
}
|
||||
}
|
||||
|
||||
if jsonValue, ok := GetFieldStringExtension(field, ext.E_Json); ok {
|
||||
SetStringFieldOption(field, gogoproto.E_Jsontag, jsonValue)
|
||||
} else if deprecated {
|
||||
SetStringFieldOption(field, gogoproto.E_Jsontag, "-")
|
||||
} else {
|
||||
SetStringFieldOption(field, gogoproto.E_Jsontag, toCamelCase(*field.Name, false))
|
||||
}
|
||||
|
||||
current := ""
|
||||
if v, ok := GetFieldStringExtension(field, gogoproto.E_Moretags); ok {
|
||||
current = v
|
||||
}
|
||||
|
||||
if generateXmlTags {
|
||||
if len(current) > 0 {
|
||||
current += " "
|
||||
}
|
||||
if xmlValue, ok := GetFieldStringExtension(field, ext.E_Xml); ok {
|
||||
current += fmt.Sprintf(`xml:"%s"`, xmlValue)
|
||||
} else {
|
||||
xmlValue = toCamelCase(*field.Name, false)
|
||||
// XML dictates element name within the collection, not collection name, so trim plural suffix.
|
||||
if field.IsRepeated() {
|
||||
if strings.HasSuffix(xmlValue, "ses") {
|
||||
// addresses -> address
|
||||
xmlValue = strings.TrimSuffix(xmlValue, "es")
|
||||
} else {
|
||||
// devices -> device
|
||||
xmlValue = strings.TrimSuffix(xmlValue, "s")
|
||||
}
|
||||
}
|
||||
if deprecated {
|
||||
xmlValue += ",omitempty"
|
||||
}
|
||||
current += fmt.Sprintf(`xml:"%s"`, xmlValue)
|
||||
}
|
||||
}
|
||||
|
||||
if defaultValue, ok := GetFieldStringExtension(field, ext.E_Default); ok {
|
||||
if len(current) > 0 {
|
||||
current += " "
|
||||
}
|
||||
current += fmt.Sprintf(`default:"%s"`, defaultValue)
|
||||
}
|
||||
|
||||
if nodefaultValue, ok := GetFieldBooleanExtension(field, ext.E_Nodefault); ok {
|
||||
if len(current) > 0 {
|
||||
current += " "
|
||||
}
|
||||
current += fmt.Sprintf(`nodefault:"%t"`, nodefaultValue)
|
||||
}
|
||||
|
||||
if restartValue, ok := GetFieldBooleanExtension(field, ext.E_Restart); ok {
|
||||
if len(current) > 0 {
|
||||
current += " "
|
||||
}
|
||||
current += fmt.Sprintf(`restart:"%t"`, restartValue)
|
||||
}
|
||||
|
||||
SetStringFieldOption(field, gogoproto.E_Moretags, current)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
// Copyright (C) 2016 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
|
||||
//go:build ignore
|
||||
// +build ignore
|
||||
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
"text/tabwriter"
|
||||
)
|
||||
|
||||
func main() {
|
||||
flag.Parse()
|
||||
for _, arg := range flag.Args() {
|
||||
matches, err := filepath.Glob(arg)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
for _, file := range matches {
|
||||
if stat, err := os.Stat(file); err != nil {
|
||||
log.Fatal(err)
|
||||
} else if stat.IsDir() {
|
||||
err := filepath.Walk(file, func(path string, info os.FileInfo, err error) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if filepath.Ext(path) == ".proto" {
|
||||
return formatProtoFile(path)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
} else {
|
||||
if err := formatProtoFile(file); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func formatProtoFile(file string) error {
|
||||
log.Println("Formatting", file)
|
||||
in, err := os.Open(file)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer in.Close()
|
||||
out, err := os.Create(file + ".tmp")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer out.Close()
|
||||
if err := formatProto(in, out); err != nil {
|
||||
return err
|
||||
}
|
||||
in.Close()
|
||||
out.Close()
|
||||
return os.Rename(file+".tmp", file)
|
||||
}
|
||||
|
||||
func formatProto(in io.Reader, out io.Writer) error {
|
||||
sc := bufio.NewScanner(in)
|
||||
lineExp := regexp.MustCompile(`([^=]+)\s+([^=\s]+?)\s*=(.+)`)
|
||||
var tw *tabwriter.Writer
|
||||
for sc.Scan() {
|
||||
line := sc.Text()
|
||||
if strings.HasPrefix(line, "//") {
|
||||
if _, err := fmt.Fprintln(out, line); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
ms := lineExp.FindStringSubmatch(line)
|
||||
for i := range ms {
|
||||
ms[i] = strings.TrimSpace(ms[i])
|
||||
}
|
||||
if len(ms) == 4 && ms[1] != "option" {
|
||||
typ := strings.Join(strings.Fields(ms[1]), " ")
|
||||
name := ms[2]
|
||||
id := ms[3]
|
||||
if tw == nil {
|
||||
tw = tabwriter.NewWriter(out, 4, 4, 1, ' ', 0)
|
||||
}
|
||||
if typ == "" {
|
||||
// We're in an enum
|
||||
fmt.Fprintf(tw, "\t%s\t= %s\n", name, id)
|
||||
} else {
|
||||
// Message
|
||||
fmt.Fprintf(tw, "\t%s\t%s\t= %s\n", typ, name, id)
|
||||
}
|
||||
} else {
|
||||
if tw != nil {
|
||||
if err := tw.Flush(); err != nil {
|
||||
return err
|
||||
}
|
||||
tw = nil
|
||||
}
|
||||
if _, err := fmt.Fprintln(out, line); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user