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; }