From 4fc9b9aa3514f0602492822e3fd8eda04f384312 Mon Sep 17 00:00:00 2001 From: Ryan McKinley Date: Tue, 4 Oct 2022 11:57:26 -0700 Subject: [PATCH] Storage: Cleanup object history API (#56215) --- .betterer.results | 8 +- .../store/object/dummy/dummy_server.go | 100 ++- pkg/services/store/object/http.go | 12 +- pkg/services/store/object/json.go | 101 --- pkg/services/store/object/object.pb.go | 675 +++++++++++------- pkg/services/store/object/object.proto | 47 +- pkg/services/store/object/object_grpc.pb.go | 2 +- .../object/tests/server_integration_test.go | 124 +++- 8 files changed, 658 insertions(+), 411 deletions(-) delete mode 100644 pkg/services/store/object/json.go diff --git a/.betterer.results b/.betterer.results index bc7f616f948..af83c521777 100644 --- a/.betterer.results +++ b/.betterer.results @@ -6030,11 +6030,9 @@ exports[`better eslint`] = { [0, 0, 0, "Unexpected any. Specify a different type.", "11"], [0, 0, 0, "Unexpected any. Specify a different type.", "12"], [0, 0, 0, "Unexpected any. Specify a different type.", "13"], - [0, 0, 0, "Unexpected any. Specify a different type.", "14"], - [0, 0, 0, "Do not use any type assertions.", "15"], - [0, 0, 0, "Unexpected any. Specify a different type.", "16"], - [0, 0, 0, "Unexpected any. Specify a different type.", "17"], - [0, 0, 0, "Unexpected any. Specify a different type.", "18"] + [0, 0, 0, "Do not use any type assertions.", "14"], + [0, 0, 0, "Unexpected any. Specify a different type.", "15"], + [0, 0, 0, "Unexpected any. Specify a different type.", "16"] ], "public/app/plugins/datasource/elasticsearch/components/AddRemove.tsx:5381": [ [0, 0, 0, "Unexpected any. Specify a different type.", "0"] diff --git a/pkg/services/store/object/dummy/dummy_server.go b/pkg/services/store/object/dummy/dummy_server.go index 20a439f6d93..ee3f631f922 100644 --- a/pkg/services/store/object/dummy/dummy_server.go +++ b/pkg/services/store/object/dummy/dummy_server.go @@ -17,9 +17,15 @@ import ( "github.com/grafana/grafana/pkg/setting" ) +type ObjectVersionWithBody struct { + *object.ObjectVersionInfo `json:"info,omitempty"` + + Body []byte `json:"body,omitempty"` +} + type RawObjectWithHistory struct { *object.RawObject `json:"rawObject,omitempty"` - History []*object.RawObject `json:"history,omitempty"` + History []*ObjectVersionWithBody `json:"history,omitempty"` } var ( @@ -74,13 +80,26 @@ func (i dummyObjectServer) findObject(ctx context.Context, uid string, kind stri getLatestVersion := version == "" if getLatestVersion { - objVersion := obj.History[len(obj.History)-1] - return obj, objVersion, nil + return obj, obj.RawObject, nil } for _, objVersion := range obj.History { if objVersion.Version == version { - return obj, objVersion, nil + copy := &object.RawObject{ + UID: obj.UID, + Kind: obj.Kind, + Created: obj.Created, + CreatedBy: obj.CreatedBy, + Modified: objVersion.Modified, + ModifiedBy: objVersion.ModifiedBy, + ETag: objVersion.ETag, + Version: objVersion.Version, + + // Body is added from the dummy server cache (it does not exist in ObjectVersionInfo) + Body: objVersion.Body, + } + + return obj, copy, nil } } @@ -125,7 +144,7 @@ func createContentsHash(contents []byte) string { } func (i dummyObjectServer) update(ctx context.Context, r *object.WriteObjectRequest, namespace string) (*object.WriteObjectResponse, error) { - var updated *object.RawObject + rsp := &object.WriteObjectResponse{} updatedCount, err := i.collection.Update(ctx, namespace, func(i *RawObjectWithHistory) (bool, *RawObjectWithHistory, error) { match := i.UID == r.UID && i.Kind == r.Kind @@ -144,7 +163,7 @@ func (i dummyObjectServer) update(ctx context.Context, r *object.WriteObjectRequ modifier := userFromContext(ctx) - updated = &object.RawObject{ + updated := &object.RawObject{ UID: r.UID, Kind: r.Kind, Created: i.Created, @@ -158,12 +177,32 @@ func (i dummyObjectServer) update(ctx context.Context, r *object.WriteObjectRequ ETag: createContentsHash(r.Body), Body: r.Body, Version: fmt.Sprintf("%d", prevVersion+1), - Comment: r.Comment, + } + + versionInfo := &ObjectVersionWithBody{ + Body: r.Body, + ObjectVersionInfo: &object.ObjectVersionInfo{ + Version: updated.Version, + Modified: updated.Modified, + ModifiedBy: updated.ModifiedBy, + Size: updated.Size, + ETag: updated.ETag, + Comment: r.Comment, + }, + } + rsp.Object = versionInfo.ObjectVersionInfo + rsp.Status = object.WriteObjectResponse_MODIFIED + + // When saving, it must be different than the head version + if i.ETag == updated.ETag { + versionInfo.ObjectVersionInfo.Version = i.Version + rsp.Status = object.WriteObjectResponse_UNCHANGED + return false, nil, nil } return true, &RawObjectWithHistory{ RawObject: updated, - History: append(i.History, updated), + History: append(i.History, versionInfo), }, nil }) @@ -171,14 +210,11 @@ func (i dummyObjectServer) update(ctx context.Context, r *object.WriteObjectRequ return nil, err } - if updatedCount == 0 { + if updatedCount == 0 && rsp.Object == nil { return nil, fmt.Errorf("could not find object with uid %s and kind %s", r.UID, r.Kind) } - return &object.WriteObjectResponse{ - Error: nil, - Object: updated, - }, nil + return rsp, nil } func (i dummyObjectServer) insert(ctx context.Context, r *object.WriteObjectRequest, namespace string) (*object.WriteObjectResponse, error) { @@ -200,11 +236,23 @@ func (i dummyObjectServer) insert(ctx context.Context, r *object.WriteObjectRequ ETag: createContentsHash(r.Body), Body: r.Body, Version: fmt.Sprintf("%d", 1), - Comment: r.Comment, } + + info := &object.ObjectVersionInfo{ + Version: rawObj.Version, + Modified: rawObj.Modified, + ModifiedBy: rawObj.ModifiedBy, + Size: rawObj.Size, + ETag: rawObj.ETag, + Comment: r.Comment, + } + newObj := &RawObjectWithHistory{ RawObject: rawObj, - History: []*object.RawObject{rawObj}, + History: []*ObjectVersionWithBody{{ + ObjectVersionInfo: info, + Body: r.Body, + }}, } err := i.collection.Insert(ctx, namespace, newObj) @@ -214,13 +262,17 @@ func (i dummyObjectServer) insert(ctx context.Context, r *object.WriteObjectRequ return &object.WriteObjectResponse{ Error: nil, - Object: newObj.RawObject, + Object: info, + Status: object.WriteObjectResponse_CREATED, }, nil } func (i dummyObjectServer) Write(ctx context.Context, r *object.WriteObjectRequest) (*object.WriteObjectResponse, error) { namespace := namespaceFromUID(r.UID) obj, err := i.collection.FindFirst(ctx, namespace, func(i *RawObjectWithHistory) (bool, error) { + if i == nil || r == nil { + return false, nil + } return i.UID == r.UID, nil }) if err != nil { @@ -263,15 +315,15 @@ func (i dummyObjectServer) History(ctx context.Context, r *object.ObjectHistoryR return nil, err } - if obj == nil { - return &object.ObjectHistoryResponse{ - Object: nil, - }, nil + rsp := &object.ObjectHistoryResponse{} + if obj != nil { + // Return the most recent versions first + // Better? save them in this order? + for i := len(obj.History) - 1; i >= 0; i-- { + rsp.Versions = append(rsp.Versions, obj.History[i].ObjectVersionInfo) + } } - - return &object.ObjectHistoryResponse{ - Object: obj.History, - }, nil + return rsp, nil } func (i dummyObjectServer) Search(ctx context.Context, r *object.ObjectSearchRequest) (*object.ObjectSearchResponse, error) { diff --git a/pkg/services/store/object/http.go b/pkg/services/store/object/http.go index 8558b0f072f..ae3881766a1 100644 --- a/pkg/services/store/object/http.go +++ b/pkg/services/store/object/http.go @@ -60,6 +60,14 @@ func parseRequestParams(req *http.Request) (uid string, kind string, params map[ uid = path kind = "?" } + + // Read parameters that are encoded in the URL + vals := req.URL.Query() + for k, v := range vals { + if len(v) > 0 { + params[k] = v[0] + } + } return } @@ -151,7 +159,7 @@ func (s *httpObjectStore) doWriteObject(c *models.ReqContext) response.Response Kind: kind, Body: b, Comment: params["comment"], - PreviousVersion: params["previous"], + PreviousVersion: params["previousVersion"], }) if err != nil { return response.Error(500, "?", err) @@ -164,7 +172,7 @@ func (s *httpObjectStore) doDeleteObject(c *models.ReqContext) response.Response rsp, err := s.store.Delete(c.Req.Context(), &DeleteObjectRequest{ UID: uid, Kind: kind, - PreviousVersion: params["previous"], + PreviousVersion: params["previousVersion"], }) if err != nil { return response.Error(500, "?", err) diff --git a/pkg/services/store/object/json.go b/pkg/services/store/object/json.go deleted file mode 100644 index b6fdfbbddda..00000000000 --- a/pkg/services/store/object/json.go +++ /dev/null @@ -1,101 +0,0 @@ -package object - -import ( - "encoding/json" - "unsafe" - - jsoniter "github.com/json-iterator/go" -) - -func init() { //nolint:gochecknoinits - //jsoniter.RegisterTypeEncoder("object.ReadObjectResponse", &readObjectResponseCodec{}) - jsoniter.RegisterTypeEncoder("object.RawObject", &rawObjectCodec{}) -} - -// Unlike the standard JSON marshal, this will write bytes as JSON when it can -type rawObjectCodec struct{} - -// Custom marshal for RawObject (if JSON body) -func (obj *RawObject) MarshalJSON() ([]byte, error) { - var json = jsoniter.ConfigCompatibleWithStandardLibrary - return json.Marshal(obj) -} - -func (codec *rawObjectCodec) IsEmpty(ptr unsafe.Pointer) bool { - f := (*RawObject)(ptr) - return f.UID == "" && f.Body == nil -} - -func (codec *rawObjectCodec) Encode(ptr unsafe.Pointer, stream *jsoniter.Stream) { - obj := (*RawObject)(ptr) - stream.WriteObjectStart() - stream.WriteObjectField("UID") - stream.WriteString(obj.UID) - - if obj.Kind != "" { - stream.WriteMore() - stream.WriteObjectField("kind") - stream.WriteString(obj.Kind) - } - if obj.Created > 0 { - stream.WriteMore() - stream.WriteObjectField("created") - stream.WriteInt64(obj.Created) - } - if obj.CreatedBy != nil { - stream.WriteMore() - stream.WriteObjectField("createdBy") - stream.WriteVal(obj.CreatedBy) - } - if obj.Modified > 0 { - stream.WriteMore() - stream.WriteObjectField("modified") - stream.WriteInt64(obj.Modified) - } - if obj.ModifiedBy != nil { - stream.WriteMore() - stream.WriteObjectField("modifiedBy") - stream.WriteVal(obj.ModifiedBy) - } - - if obj.Size > 0 { - stream.WriteMore() - stream.WriteObjectField("size") - stream.WriteInt64(obj.Size) - } - if obj.ETag != "" { - stream.WriteMore() - stream.WriteObjectField("etag") - stream.WriteString(obj.ETag) - } - if obj.Version != "" { - stream.WriteMore() - stream.WriteObjectField("version") - stream.WriteString(obj.Version) - } - - // The one real difference (encodes JSON things directly) - if obj.Body != nil { - stream.WriteMore() - stream.WriteObjectField("body") - if json.Valid(obj.Body) { - stream.WriteRaw(string(obj.Body)) // works for strings - } else { - stream.WriteString("// link to raw bytes //") - //stream.WriteVal(obj.Body) - } - } - - if obj.SyncSrc != "" { - stream.WriteMore() - stream.WriteObjectField("syncSrc") - stream.WriteString(obj.SyncSrc) - } - if obj.SyncTime > 0 { - stream.WriteMore() - stream.WriteObjectField("syncTime") - stream.WriteInt64(obj.SyncTime) - } - - stream.WriteObjectEnd() -} diff --git a/pkg/services/store/object/object.pb.go b/pkg/services/store/object/object.pb.go index 93d87d3a839..c2e212488ff 100644 --- a/pkg/services/store/object/object.pb.go +++ b/pkg/services/store/object/object.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: // protoc-gen-go v1.28.1 -// protoc v3.21.5 +// protoc v3.21.7 // source: object.proto package object @@ -20,6 +20,59 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) +// Status enumeration +type WriteObjectResponse_Status int32 + +const ( + WriteObjectResponse_ERROR WriteObjectResponse_Status = 0 + WriteObjectResponse_CREATED WriteObjectResponse_Status = 1 + WriteObjectResponse_MODIFIED WriteObjectResponse_Status = 2 + WriteObjectResponse_UNCHANGED WriteObjectResponse_Status = 3 +) + +// Enum value maps for WriteObjectResponse_Status. +var ( + WriteObjectResponse_Status_name = map[int32]string{ + 0: "ERROR", + 1: "CREATED", + 2: "MODIFIED", + 3: "UNCHANGED", + } + WriteObjectResponse_Status_value = map[string]int32{ + "ERROR": 0, + "CREATED": 1, + "MODIFIED": 2, + "UNCHANGED": 3, + } +) + +func (x WriteObjectResponse_Status) Enum() *WriteObjectResponse_Status { + p := new(WriteObjectResponse_Status) + *p = x + return p +} + +func (x WriteObjectResponse_Status) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (WriteObjectResponse_Status) Descriptor() protoreflect.EnumDescriptor { + return file_object_proto_enumTypes[0].Descriptor() +} + +func (WriteObjectResponse_Status) Type() protoreflect.EnumType { + return &file_object_proto_enumTypes[0] +} + +func (x WriteObjectResponse_Status) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use WriteObjectResponse_Status.Descriptor instead. +func (WriteObjectResponse_Status) EnumDescriptor() ([]byte, []int) { + return file_object_proto_rawDescGZIP(), []int{9, 0} +} + // Will be replaced with something from the SDK type UserInfo struct { state protoimpl.MessageState @@ -107,18 +160,14 @@ type RawObject struct { // // NOTE: currently managed by the dashboard+dashboard_version tables Version string `protobuf:"bytes,10,opt,name=version,proto3" json:"version,omitempty"` - // optional "save" or "commit" message - // - // NOTE: currently managed by the dashboard_version table, and will be returned from a "history" command - Comment string `protobuf:"bytes,11,opt,name=comment,proto3" json:"comment,omitempty"` // Location (path/repo/etc) that defines the canonocal form // // NOTE: currently managed by the dashboard_provisioning table - SyncSrc string `protobuf:"bytes,12,opt,name=sync_src,json=syncSrc,proto3" json:"sync_src,omitempty"` + SyncSrc string `protobuf:"bytes,11,opt,name=sync_src,json=syncSrc,proto3" json:"sync_src,omitempty"` // Time in epoch milliseconds that the object was last synced with an external system (provisioning/git) // // NOTE: currently managed by the dashboard_provisioning table - SyncTime int64 `protobuf:"varint,13,opt,name=sync_time,json=syncTime,proto3" json:"sync_time,omitempty"` + SyncTime int64 `protobuf:"varint,12,opt,name=sync_time,json=syncTime,proto3" json:"sync_time,omitempty"` } func (x *RawObject) Reset() { @@ -223,13 +272,6 @@ func (x *RawObject) GetVersion() string { return "" } -func (x *RawObject) GetComment() string { - if x != nil { - return x.Comment - } - return "" -} - func (x *RawObject) GetSyncSrc() string { if x != nil { return x.SyncSrc @@ -312,6 +354,102 @@ func (x *ObjectErrorInfo) GetDetailsJson() []byte { return nil } +// This is a subset of RawObject that does not include body or sync info +type ObjectVersionInfo struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // The version will change when the object is saved. It is not necessarily sortable + Version string `protobuf:"bytes,1,opt,name=version,proto3" json:"version,omitempty"` + // Time in epoch milliseconds that the object was modified + Modified int64 `protobuf:"varint,2,opt,name=modified,proto3" json:"modified,omitempty"` + // Who modified the object + ModifiedBy *UserInfo `protobuf:"bytes,3,opt,name=modified_by,json=modifiedBy,proto3" json:"modified_by,omitempty"` + // Content Length + Size int64 `protobuf:"varint,4,opt,name=size,proto3" json:"size,omitempty"` + // MD5 digest of the body + ETag string `protobuf:"bytes,5,opt,name=ETag,proto3" json:"ETag,omitempty"` + // optional "save" or "commit" message + // + // NOTE: currently managed by the dashboard_version table, and will be returned from a "history" command + Comment string `protobuf:"bytes,6,opt,name=comment,proto3" json:"comment,omitempty"` +} + +func (x *ObjectVersionInfo) Reset() { + *x = ObjectVersionInfo{} + if protoimpl.UnsafeEnabled { + mi := &file_object_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ObjectVersionInfo) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ObjectVersionInfo) ProtoMessage() {} + +func (x *ObjectVersionInfo) ProtoReflect() protoreflect.Message { + mi := &file_object_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ObjectVersionInfo.ProtoReflect.Descriptor instead. +func (*ObjectVersionInfo) Descriptor() ([]byte, []int) { + return file_object_proto_rawDescGZIP(), []int{3} +} + +func (x *ObjectVersionInfo) GetVersion() string { + if x != nil { + return x.Version + } + return "" +} + +func (x *ObjectVersionInfo) GetModified() int64 { + if x != nil { + return x.Modified + } + return 0 +} + +func (x *ObjectVersionInfo) GetModifiedBy() *UserInfo { + if x != nil { + return x.ModifiedBy + } + return nil +} + +func (x *ObjectVersionInfo) GetSize() int64 { + if x != nil { + return x.Size + } + return 0 +} + +func (x *ObjectVersionInfo) GetETag() string { + if x != nil { + return x.ETag + } + return "" +} + +func (x *ObjectVersionInfo) GetComment() string { + if x != nil { + return x.Comment + } + return "" +} + type ReadObjectRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -332,7 +470,7 @@ type ReadObjectRequest struct { func (x *ReadObjectRequest) Reset() { *x = ReadObjectRequest{} if protoimpl.UnsafeEnabled { - mi := &file_object_proto_msgTypes[3] + mi := &file_object_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -345,7 +483,7 @@ func (x *ReadObjectRequest) String() string { func (*ReadObjectRequest) ProtoMessage() {} func (x *ReadObjectRequest) ProtoReflect() protoreflect.Message { - mi := &file_object_proto_msgTypes[3] + mi := &file_object_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -358,7 +496,7 @@ func (x *ReadObjectRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ReadObjectRequest.ProtoReflect.Descriptor instead. func (*ReadObjectRequest) Descriptor() ([]byte, []int) { - return file_object_proto_rawDescGZIP(), []int{3} + return file_object_proto_rawDescGZIP(), []int{4} } func (x *ReadObjectRequest) GetUID() string { @@ -410,7 +548,7 @@ type ReadObjectResponse struct { func (x *ReadObjectResponse) Reset() { *x = ReadObjectResponse{} if protoimpl.UnsafeEnabled { - mi := &file_object_proto_msgTypes[4] + mi := &file_object_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -423,7 +561,7 @@ func (x *ReadObjectResponse) String() string { func (*ReadObjectResponse) ProtoMessage() {} func (x *ReadObjectResponse) ProtoReflect() protoreflect.Message { - mi := &file_object_proto_msgTypes[4] + mi := &file_object_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -436,7 +574,7 @@ func (x *ReadObjectResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ReadObjectResponse.ProtoReflect.Descriptor instead. func (*ReadObjectResponse) Descriptor() ([]byte, []int) { - return file_object_proto_rawDescGZIP(), []int{4} + return file_object_proto_rawDescGZIP(), []int{5} } func (x *ReadObjectResponse) GetObject() *RawObject { @@ -464,7 +602,7 @@ type BatchReadObjectRequest struct { func (x *BatchReadObjectRequest) Reset() { *x = BatchReadObjectRequest{} if protoimpl.UnsafeEnabled { - mi := &file_object_proto_msgTypes[5] + mi := &file_object_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -477,7 +615,7 @@ func (x *BatchReadObjectRequest) String() string { func (*BatchReadObjectRequest) ProtoMessage() {} func (x *BatchReadObjectRequest) ProtoReflect() protoreflect.Message { - mi := &file_object_proto_msgTypes[5] + mi := &file_object_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -490,7 +628,7 @@ func (x *BatchReadObjectRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use BatchReadObjectRequest.ProtoReflect.Descriptor instead. func (*BatchReadObjectRequest) Descriptor() ([]byte, []int) { - return file_object_proto_rawDescGZIP(), []int{5} + return file_object_proto_rawDescGZIP(), []int{6} } func (x *BatchReadObjectRequest) GetBatch() []*ReadObjectRequest { @@ -511,7 +649,7 @@ type BatchReadObjectResponse struct { func (x *BatchReadObjectResponse) Reset() { *x = BatchReadObjectResponse{} if protoimpl.UnsafeEnabled { - mi := &file_object_proto_msgTypes[6] + mi := &file_object_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -524,7 +662,7 @@ func (x *BatchReadObjectResponse) String() string { func (*BatchReadObjectResponse) ProtoMessage() {} func (x *BatchReadObjectResponse) ProtoReflect() protoreflect.Message { - mi := &file_object_proto_msgTypes[6] + mi := &file_object_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -537,7 +675,7 @@ func (x *BatchReadObjectResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use BatchReadObjectResponse.ProtoReflect.Descriptor instead. func (*BatchReadObjectResponse) Descriptor() ([]byte, []int) { - return file_object_proto_rawDescGZIP(), []int{6} + return file_object_proto_rawDescGZIP(), []int{7} } func (x *BatchReadObjectResponse) GetResults() []*ReadObjectResponse { @@ -567,7 +705,7 @@ type WriteObjectRequest struct { func (x *WriteObjectRequest) Reset() { *x = WriteObjectRequest{} if protoimpl.UnsafeEnabled { - mi := &file_object_proto_msgTypes[7] + mi := &file_object_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -580,7 +718,7 @@ func (x *WriteObjectRequest) String() string { func (*WriteObjectRequest) ProtoMessage() {} func (x *WriteObjectRequest) ProtoReflect() protoreflect.Message { - mi := &file_object_proto_msgTypes[7] + mi := &file_object_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -593,7 +731,7 @@ func (x *WriteObjectRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use WriteObjectRequest.ProtoReflect.Descriptor instead. func (*WriteObjectRequest) Descriptor() ([]byte, []int) { - return file_object_proto_rawDescGZIP(), []int{7} + return file_object_proto_rawDescGZIP(), []int{8} } func (x *WriteObjectRequest) GetUID() string { @@ -639,15 +777,17 @@ type WriteObjectResponse struct { // Error info -- if exists, the save did not happen Error *ObjectErrorInfo `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` // Object details with the body removed - Object *RawObject `protobuf:"bytes,2,opt,name=object,proto3" json:"object,omitempty"` + Object *ObjectVersionInfo `protobuf:"bytes,2,opt,name=object,proto3" json:"object,omitempty"` // Object summary as JSON SummaryJson []byte `protobuf:"bytes,3,opt,name=summary_json,json=summaryJson,proto3" json:"summary_json,omitempty"` + // Status code + Status WriteObjectResponse_Status `protobuf:"varint,4,opt,name=status,proto3,enum=object.WriteObjectResponse_Status" json:"status,omitempty"` } func (x *WriteObjectResponse) Reset() { *x = WriteObjectResponse{} if protoimpl.UnsafeEnabled { - mi := &file_object_proto_msgTypes[8] + mi := &file_object_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -660,7 +800,7 @@ func (x *WriteObjectResponse) String() string { func (*WriteObjectResponse) ProtoMessage() {} func (x *WriteObjectResponse) ProtoReflect() protoreflect.Message { - mi := &file_object_proto_msgTypes[8] + mi := &file_object_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -673,7 +813,7 @@ func (x *WriteObjectResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use WriteObjectResponse.ProtoReflect.Descriptor instead. func (*WriteObjectResponse) Descriptor() ([]byte, []int) { - return file_object_proto_rawDescGZIP(), []int{8} + return file_object_proto_rawDescGZIP(), []int{9} } func (x *WriteObjectResponse) GetError() *ObjectErrorInfo { @@ -683,7 +823,7 @@ func (x *WriteObjectResponse) GetError() *ObjectErrorInfo { return nil } -func (x *WriteObjectResponse) GetObject() *RawObject { +func (x *WriteObjectResponse) GetObject() *ObjectVersionInfo { if x != nil { return x.Object } @@ -697,6 +837,13 @@ func (x *WriteObjectResponse) GetSummaryJson() []byte { return nil } +func (x *WriteObjectResponse) GetStatus() WriteObjectResponse_Status { + if x != nil { + return x.Status + } + return WriteObjectResponse_ERROR +} + type DeleteObjectRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -713,7 +860,7 @@ type DeleteObjectRequest struct { func (x *DeleteObjectRequest) Reset() { *x = DeleteObjectRequest{} if protoimpl.UnsafeEnabled { - mi := &file_object_proto_msgTypes[9] + mi := &file_object_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -726,7 +873,7 @@ func (x *DeleteObjectRequest) String() string { func (*DeleteObjectRequest) ProtoMessage() {} func (x *DeleteObjectRequest) ProtoReflect() protoreflect.Message { - mi := &file_object_proto_msgTypes[9] + mi := &file_object_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -739,7 +886,7 @@ func (x *DeleteObjectRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteObjectRequest.ProtoReflect.Descriptor instead. func (*DeleteObjectRequest) Descriptor() ([]byte, []int) { - return file_object_proto_rawDescGZIP(), []int{9} + return file_object_proto_rawDescGZIP(), []int{10} } func (x *DeleteObjectRequest) GetUID() string { @@ -774,7 +921,7 @@ type DeleteObjectResponse struct { func (x *DeleteObjectResponse) Reset() { *x = DeleteObjectResponse{} if protoimpl.UnsafeEnabled { - mi := &file_object_proto_msgTypes[10] + mi := &file_object_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -787,7 +934,7 @@ func (x *DeleteObjectResponse) String() string { func (*DeleteObjectResponse) ProtoMessage() {} func (x *DeleteObjectResponse) ProtoReflect() protoreflect.Message { - mi := &file_object_proto_msgTypes[10] + mi := &file_object_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -800,7 +947,7 @@ func (x *DeleteObjectResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use DeleteObjectResponse.ProtoReflect.Descriptor instead. func (*DeleteObjectResponse) Descriptor() ([]byte, []int) { - return file_object_proto_rawDescGZIP(), []int{10} + return file_object_proto_rawDescGZIP(), []int{11} } func (x *DeleteObjectResponse) GetOK() bool { @@ -828,7 +975,7 @@ type ObjectHistoryRequest struct { func (x *ObjectHistoryRequest) Reset() { *x = ObjectHistoryRequest{} if protoimpl.UnsafeEnabled { - mi := &file_object_proto_msgTypes[11] + mi := &file_object_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -841,7 +988,7 @@ func (x *ObjectHistoryRequest) String() string { func (*ObjectHistoryRequest) ProtoMessage() {} func (x *ObjectHistoryRequest) ProtoReflect() protoreflect.Message { - mi := &file_object_proto_msgTypes[11] + mi := &file_object_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -854,7 +1001,7 @@ func (x *ObjectHistoryRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ObjectHistoryRequest.ProtoReflect.Descriptor instead. func (*ObjectHistoryRequest) Descriptor() ([]byte, []int) { - return file_object_proto_rawDescGZIP(), []int{11} + return file_object_proto_rawDescGZIP(), []int{12} } func (x *ObjectHistoryRequest) GetUID() string { @@ -891,7 +1038,7 @@ type ObjectHistoryResponse struct { unknownFields protoimpl.UnknownFields // Object metadata without the raw bytes - Object []*RawObject `protobuf:"bytes,1,rep,name=object,proto3" json:"object,omitempty"` + Versions []*ObjectVersionInfo `protobuf:"bytes,1,rep,name=versions,proto3" json:"versions,omitempty"` // More results exist... pass this in the next request NextPageToken string `protobuf:"bytes,2,opt,name=next_page_token,json=nextPageToken,proto3" json:"next_page_token,omitempty"` } @@ -899,7 +1046,7 @@ type ObjectHistoryResponse struct { func (x *ObjectHistoryResponse) Reset() { *x = ObjectHistoryResponse{} if protoimpl.UnsafeEnabled { - mi := &file_object_proto_msgTypes[12] + mi := &file_object_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -912,7 +1059,7 @@ func (x *ObjectHistoryResponse) String() string { func (*ObjectHistoryResponse) ProtoMessage() {} func (x *ObjectHistoryResponse) ProtoReflect() protoreflect.Message { - mi := &file_object_proto_msgTypes[12] + mi := &file_object_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -925,12 +1072,12 @@ func (x *ObjectHistoryResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ObjectHistoryResponse.ProtoReflect.Descriptor instead. func (*ObjectHistoryResponse) Descriptor() ([]byte, []int) { - return file_object_proto_rawDescGZIP(), []int{12} + return file_object_proto_rawDescGZIP(), []int{13} } -func (x *ObjectHistoryResponse) GetObject() []*RawObject { +func (x *ObjectHistoryResponse) GetVersions() []*ObjectVersionInfo { if x != nil { - return x.Object + return x.Versions } return nil } @@ -971,7 +1118,7 @@ type ObjectSearchRequest struct { func (x *ObjectSearchRequest) Reset() { *x = ObjectSearchRequest{} if protoimpl.UnsafeEnabled { - mi := &file_object_proto_msgTypes[13] + mi := &file_object_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -984,7 +1131,7 @@ func (x *ObjectSearchRequest) String() string { func (*ObjectSearchRequest) ProtoMessage() {} func (x *ObjectSearchRequest) ProtoReflect() protoreflect.Message { - mi := &file_object_proto_msgTypes[13] + mi := &file_object_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -997,7 +1144,7 @@ func (x *ObjectSearchRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ObjectSearchRequest.ProtoReflect.Descriptor instead. func (*ObjectSearchRequest) Descriptor() ([]byte, []int) { - return file_object_proto_rawDescGZIP(), []int{13} + return file_object_proto_rawDescGZIP(), []int{14} } func (x *ObjectSearchRequest) GetNextPageToken() string { @@ -1076,7 +1223,7 @@ type ObjectSearchResponse struct { func (x *ObjectSearchResponse) Reset() { *x = ObjectSearchResponse{} if protoimpl.UnsafeEnabled { - mi := &file_object_proto_msgTypes[14] + mi := &file_object_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1089,7 +1236,7 @@ func (x *ObjectSearchResponse) String() string { func (*ObjectSearchResponse) ProtoMessage() {} func (x *ObjectSearchResponse) ProtoReflect() protoreflect.Message { - mi := &file_object_proto_msgTypes[14] + mi := &file_object_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1102,7 +1249,7 @@ func (x *ObjectSearchResponse) ProtoReflect() protoreflect.Message { // Deprecated: Use ObjectSearchResponse.ProtoReflect.Descriptor instead. func (*ObjectSearchResponse) Descriptor() ([]byte, []int) { - return file_object_proto_rawDescGZIP(), []int{14} + return file_object_proto_rawDescGZIP(), []int{15} } func (x *ObjectSearchResponse) GetResults() []*RawObject { @@ -1126,7 +1273,7 @@ var file_object_proto_rawDesc = []byte{ 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x22, 0x30, 0x0a, 0x08, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x22, 0xf3, 0x02, 0x0a, 0x09, 0x52, 0x61, 0x77, + 0x09, 0x52, 0x05, 0x6c, 0x6f, 0x67, 0x69, 0x6e, 0x22, 0xd9, 0x02, 0x0a, 0x09, 0x52, 0x61, 0x77, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, @@ -1144,143 +1291,163 @@ var file_object_proto_rawDesc = []byte{ 0x61, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x45, 0x54, 0x61, 0x67, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x18, 0x0a, 0x07, - 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, - 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x73, - 0x72, 0x63, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x79, 0x6e, 0x63, 0x53, 0x72, - 0x63, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0d, - 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x73, 0x79, 0x6e, 0x63, 0x54, 0x69, 0x6d, 0x65, 0x22, 0x62, - 0x0a, 0x0f, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x49, 0x6e, 0x66, - 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, - 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, - 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x4a, 0x73, - 0x6f, 0x6e, 0x22, 0x93, 0x01, 0x0a, 0x11, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x49, 0x44, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, - 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x18, - 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x69, 0x74, 0x68, - 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x77, 0x69, 0x74, - 0x68, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x73, 0x75, - 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x77, 0x69, 0x74, - 0x68, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, 0x62, 0x0a, 0x12, 0x52, 0x65, 0x61, 0x64, - 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, - 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, - 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x52, 0x61, 0x77, 0x4f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x6d, - 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, - 0x0b, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x4a, 0x73, 0x6f, 0x6e, 0x22, 0x49, 0x0a, 0x16, - 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, 0x05, 0x62, 0x61, 0x74, 0x63, 0x68, 0x18, - 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x52, - 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x52, 0x05, 0x62, 0x61, 0x74, 0x63, 0x68, 0x22, 0x4f, 0x0a, 0x17, 0x42, 0x61, 0x74, 0x63, 0x68, - 0x52, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x34, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x52, 0x65, 0x61, - 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, - 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, 0x93, 0x01, 0x0a, 0x12, 0x57, 0x72, 0x69, - 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x0a, 0x08, + 0x73, 0x79, 0x6e, 0x63, 0x5f, 0x73, 0x72, 0x63, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, + 0x73, 0x79, 0x6e, 0x63, 0x53, 0x72, 0x63, 0x12, 0x1b, 0x0a, 0x09, 0x73, 0x79, 0x6e, 0x63, 0x5f, + 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x73, 0x79, 0x6e, 0x63, + 0x54, 0x69, 0x6d, 0x65, 0x22, 0x62, 0x0a, 0x0f, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x72, + 0x72, 0x6f, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x6d, + 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, + 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, + 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x64, 0x65, 0x74, + 0x61, 0x69, 0x6c, 0x73, 0x4a, 0x73, 0x6f, 0x6e, 0x22, 0xbe, 0x01, 0x0a, 0x11, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x18, + 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x6f, 0x64, 0x69, + 0x66, 0x69, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x08, 0x6d, 0x6f, 0x64, 0x69, + 0x66, 0x69, 0x65, 0x64, 0x12, 0x31, 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, + 0x5f, 0x62, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x2e, 0x55, 0x73, 0x65, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x0a, 0x6d, 0x6f, 0x64, + 0x69, 0x66, 0x69, 0x65, 0x64, 0x42, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04, 0x73, 0x69, 0x7a, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x45, + 0x54, 0x61, 0x67, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x45, 0x54, 0x61, 0x67, 0x12, + 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x22, 0x93, 0x01, 0x0a, 0x11, 0x52, 0x65, + 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, - 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, - 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, - 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, - 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x92, - 0x01, 0x0a, 0x13, 0x57, 0x72, 0x69, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x4f, - 0x62, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x29, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, - 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x52, + 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x1b, 0x0a, 0x09, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x08, 0x77, 0x69, 0x74, 0x68, 0x42, 0x6f, 0x64, 0x79, 0x12, 0x21, 0x0a, 0x0c, + 0x77, 0x69, 0x74, 0x68, 0x5f, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x0b, 0x77, 0x69, 0x74, 0x68, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x22, + 0x62, 0x0a, 0x12, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x52, 0x61, 0x77, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, - 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x4a, - 0x73, 0x6f, 0x6e, 0x22, 0x66, 0x0a, 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x49, - 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, - 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, - 0x12, 0x29, 0x0a, 0x10, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x76, 0x65, 0x72, - 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x72, 0x65, 0x76, - 0x69, 0x6f, 0x75, 0x73, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x26, 0x0a, 0x14, 0x44, - 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x4f, 0x4b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x02, 0x4f, 0x4b, 0x22, 0x7a, 0x0a, 0x14, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x69, 0x73, - 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x55, - 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x49, 0x44, 0x12, 0x12, 0x0a, - 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, - 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, - 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, - 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, - 0x6a, 0x0a, 0x15, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x29, 0x0a, 0x06, 0x6f, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x2e, 0x52, 0x61, 0x77, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x06, 0x6f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x4a, + 0x73, 0x6f, 0x6e, 0x22, 0x49, 0x0a, 0x16, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x61, 0x64, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2f, 0x0a, + 0x05, 0x62, 0x61, 0x74, 0x63, 0x68, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x52, 0x05, 0x62, 0x61, 0x74, 0x63, 0x68, 0x22, 0x4f, + 0x0a, 0x17, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x34, 0x0a, 0x07, 0x72, 0x65, 0x73, + 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x22, + 0x93, 0x01, 0x0a, 0x12, 0x57, 0x72, 0x69, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x49, 0x44, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x03, 0x55, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x62, 0x6f, 0x64, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x62, 0x6f, 0x64, 0x79, + 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x65, 0x6e, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x70, 0x72, + 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x06, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x95, 0x02, 0x0a, 0x13, 0x57, 0x72, 0x69, 0x74, 0x65, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2d, 0x0a, + 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x45, 0x72, 0x72, 0x6f, + 0x72, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x31, 0x0a, 0x06, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x56, 0x65, 0x72, 0x73, + 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x12, + 0x21, 0x0a, 0x0c, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x5f, 0x6a, 0x73, 0x6f, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x0b, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x4a, 0x73, + 0x6f, 0x6e, 0x12, 0x3a, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x04, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x22, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x57, 0x72, 0x69, 0x74, + 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x2e, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x3d, + 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, + 0x52, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x43, 0x52, 0x45, 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, + 0x12, 0x0c, 0x0a, 0x08, 0x4d, 0x4f, 0x44, 0x49, 0x46, 0x49, 0x45, 0x44, 0x10, 0x02, 0x12, 0x0d, + 0x0a, 0x09, 0x55, 0x4e, 0x43, 0x48, 0x41, 0x4e, 0x47, 0x45, 0x44, 0x10, 0x03, 0x22, 0x66, 0x0a, + 0x13, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x03, 0x55, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x29, 0x0a, 0x10, 0x70, 0x72, + 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x70, 0x72, 0x65, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x56, 0x65, + 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x22, 0x26, 0x0a, 0x14, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, + 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, + 0x02, 0x4f, 0x4b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x02, 0x4f, 0x4b, 0x22, 0x7a, 0x0a, + 0x14, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x55, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x03, 0x55, 0x49, 0x44, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x6c, + 0x69, 0x6d, 0x69, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, + 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, + 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, + 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x76, 0x0a, 0x15, 0x4f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x12, 0x35, 0x0a, 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x4f, 0x62, + 0x6a, 0x65, 0x63, 0x74, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x49, 0x6e, 0x66, 0x6f, 0x52, + 0x08, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, + 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x22, 0xda, 0x02, 0x0a, 0x13, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, + 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, + 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, + 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x12, 0x0a, + 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, + 0x64, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x06, 0x6c, 0x61, 0x62, + 0x65, 0x6c, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x6f, + 0x72, 0x74, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x73, 0x6f, 0x72, 0x74, 0x12, 0x16, + 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, + 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x62, + 0x6f, 0x64, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, 0x77, 0x69, 0x74, 0x68, 0x42, + 0x6f, 0x64, 0x79, 0x1a, 0x39, 0x0a, 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x6b, + 0x0a, 0x14, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x2b, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, + 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x2e, 0x52, 0x61, 0x77, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, + 0x6c, 0x74, 0x73, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, - 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0xda, 0x02, 0x0a, 0x13, - 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x12, 0x26, 0x0a, 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, - 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, - 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x6c, - 0x69, 0x6d, 0x69, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6c, 0x69, 0x6d, 0x69, - 0x74, 0x12, 0x14, 0x0a, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x71, 0x75, 0x65, 0x72, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x18, - 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x6b, 0x69, 0x6e, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x66, - 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x6f, 0x6c, - 0x64, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x06, 0x6c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x18, 0x06, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x4f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x2e, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x06, 0x6c, 0x61, - 0x62, 0x65, 0x6c, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x6f, 0x72, 0x74, 0x18, 0x07, 0x20, 0x03, - 0x28, 0x09, 0x52, 0x04, 0x73, 0x6f, 0x72, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x65, 0x6c, - 0x64, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x73, - 0x12, 0x1b, 0x0a, 0x09, 0x77, 0x69, 0x74, 0x68, 0x5f, 0x62, 0x6f, 0x64, 0x79, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x08, 0x77, 0x69, 0x74, 0x68, 0x42, 0x6f, 0x64, 0x79, 0x1a, 0x39, 0x0a, - 0x0b, 0x4c, 0x61, 0x62, 0x65, 0x6c, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, - 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, - 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x6b, 0x0a, 0x14, 0x4f, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x2b, 0x0a, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x11, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x52, 0x61, 0x77, 0x4f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x52, 0x07, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x73, 0x12, 0x26, 0x0a, - 0x0f, 0x6e, 0x65, 0x78, 0x74, 0x5f, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x6e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, - 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x32, 0xae, 0x03, 0x0a, 0x0b, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x3d, 0x0a, 0x04, 0x52, 0x65, 0x61, 0x64, 0x12, 0x19, 0x2e, - 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x61, - 0x64, 0x12, 0x1e, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, - 0x52, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x1f, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, - 0x52, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x40, 0x0a, 0x05, 0x57, 0x72, 0x69, 0x74, 0x65, 0x12, 0x1a, 0x2e, 0x6f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, - 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x06, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1b, - 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x07, 0x48, 0x69, 0x73, - 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1c, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x4f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x4f, 0x62, 0x6a, 0x65, - 0x63, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x12, 0x43, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x1b, 0x2e, 0x6f, 0x62, - 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, - 0x74, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0b, 0x5a, 0x09, 0x2e, 0x2f, 0x3b, 0x6f, 0x62, 0x6a, - 0x65, 0x63, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x78, 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x32, 0xae, 0x03, 0x0a, 0x0b, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x3d, 0x0a, 0x04, 0x52, + 0x65, 0x61, 0x64, 0x12, 0x19, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x52, 0x65, 0x61, + 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, + 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x4c, 0x0a, 0x09, 0x42, 0x61, + 0x74, 0x63, 0x68, 0x52, 0x65, 0x61, 0x64, 0x12, 0x1e, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x2e, 0x42, 0x61, 0x74, 0x63, 0x68, 0x52, 0x65, 0x61, 0x64, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a, 0x05, 0x57, 0x72, 0x69, 0x74, + 0x65, 0x12, 0x1a, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, + 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, + 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x57, 0x72, 0x69, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, + 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x06, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x12, 0x1b, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x44, 0x65, + 0x6c, 0x65, 0x74, 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x1a, 0x1c, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x44, 0x65, 0x6c, 0x65, 0x74, + 0x65, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, + 0x46, 0x0a, 0x07, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x1c, 0x2e, 0x6f, 0x62, 0x6a, + 0x65, 0x63, 0x74, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x43, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x12, 0x1b, 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, + 0x74, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1c, + 0x2e, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x2e, 0x4f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x53, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x42, 0x0b, 0x5a, 0x09, + 0x2e, 0x2f, 0x3b, 0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, } var ( @@ -1295,53 +1462,58 @@ func file_object_proto_rawDescGZIP() []byte { return file_object_proto_rawDescData } -var file_object_proto_msgTypes = make([]protoimpl.MessageInfo, 16) +var file_object_proto_enumTypes = make([]protoimpl.EnumInfo, 1) +var file_object_proto_msgTypes = make([]protoimpl.MessageInfo, 17) var file_object_proto_goTypes = []interface{}{ - (*UserInfo)(nil), // 0: object.UserInfo - (*RawObject)(nil), // 1: object.RawObject - (*ObjectErrorInfo)(nil), // 2: object.ObjectErrorInfo - (*ReadObjectRequest)(nil), // 3: object.ReadObjectRequest - (*ReadObjectResponse)(nil), // 4: object.ReadObjectResponse - (*BatchReadObjectRequest)(nil), // 5: object.BatchReadObjectRequest - (*BatchReadObjectResponse)(nil), // 6: object.BatchReadObjectResponse - (*WriteObjectRequest)(nil), // 7: object.WriteObjectRequest - (*WriteObjectResponse)(nil), // 8: object.WriteObjectResponse - (*DeleteObjectRequest)(nil), // 9: object.DeleteObjectRequest - (*DeleteObjectResponse)(nil), // 10: object.DeleteObjectResponse - (*ObjectHistoryRequest)(nil), // 11: object.ObjectHistoryRequest - (*ObjectHistoryResponse)(nil), // 12: object.ObjectHistoryResponse - (*ObjectSearchRequest)(nil), // 13: object.ObjectSearchRequest - (*ObjectSearchResponse)(nil), // 14: object.ObjectSearchResponse - nil, // 15: object.ObjectSearchRequest.LabelsEntry + (WriteObjectResponse_Status)(0), // 0: object.WriteObjectResponse.Status + (*UserInfo)(nil), // 1: object.UserInfo + (*RawObject)(nil), // 2: object.RawObject + (*ObjectErrorInfo)(nil), // 3: object.ObjectErrorInfo + (*ObjectVersionInfo)(nil), // 4: object.ObjectVersionInfo + (*ReadObjectRequest)(nil), // 5: object.ReadObjectRequest + (*ReadObjectResponse)(nil), // 6: object.ReadObjectResponse + (*BatchReadObjectRequest)(nil), // 7: object.BatchReadObjectRequest + (*BatchReadObjectResponse)(nil), // 8: object.BatchReadObjectResponse + (*WriteObjectRequest)(nil), // 9: object.WriteObjectRequest + (*WriteObjectResponse)(nil), // 10: object.WriteObjectResponse + (*DeleteObjectRequest)(nil), // 11: object.DeleteObjectRequest + (*DeleteObjectResponse)(nil), // 12: object.DeleteObjectResponse + (*ObjectHistoryRequest)(nil), // 13: object.ObjectHistoryRequest + (*ObjectHistoryResponse)(nil), // 14: object.ObjectHistoryResponse + (*ObjectSearchRequest)(nil), // 15: object.ObjectSearchRequest + (*ObjectSearchResponse)(nil), // 16: object.ObjectSearchResponse + nil, // 17: object.ObjectSearchRequest.LabelsEntry } var file_object_proto_depIdxs = []int32{ - 0, // 0: object.RawObject.created_by:type_name -> object.UserInfo - 0, // 1: object.RawObject.modified_by:type_name -> object.UserInfo - 1, // 2: object.ReadObjectResponse.object:type_name -> object.RawObject - 3, // 3: object.BatchReadObjectRequest.batch:type_name -> object.ReadObjectRequest - 4, // 4: object.BatchReadObjectResponse.results:type_name -> object.ReadObjectResponse - 2, // 5: object.WriteObjectResponse.error:type_name -> object.ObjectErrorInfo - 1, // 6: object.WriteObjectResponse.object:type_name -> object.RawObject - 1, // 7: object.ObjectHistoryResponse.object:type_name -> object.RawObject - 15, // 8: object.ObjectSearchRequest.labels:type_name -> object.ObjectSearchRequest.LabelsEntry - 1, // 9: object.ObjectSearchResponse.results:type_name -> object.RawObject - 3, // 10: object.ObjectStore.Read:input_type -> object.ReadObjectRequest - 5, // 11: object.ObjectStore.BatchRead:input_type -> object.BatchReadObjectRequest - 7, // 12: object.ObjectStore.Write:input_type -> object.WriteObjectRequest - 9, // 13: object.ObjectStore.Delete:input_type -> object.DeleteObjectRequest - 11, // 14: object.ObjectStore.History:input_type -> object.ObjectHistoryRequest - 13, // 15: object.ObjectStore.Search:input_type -> object.ObjectSearchRequest - 4, // 16: object.ObjectStore.Read:output_type -> object.ReadObjectResponse - 6, // 17: object.ObjectStore.BatchRead:output_type -> object.BatchReadObjectResponse - 8, // 18: object.ObjectStore.Write:output_type -> object.WriteObjectResponse - 10, // 19: object.ObjectStore.Delete:output_type -> object.DeleteObjectResponse - 12, // 20: object.ObjectStore.History:output_type -> object.ObjectHistoryResponse - 14, // 21: object.ObjectStore.Search:output_type -> object.ObjectSearchResponse - 16, // [16:22] is the sub-list for method output_type - 10, // [10:16] is the sub-list for method input_type - 10, // [10:10] is the sub-list for extension type_name - 10, // [10:10] is the sub-list for extension extendee - 0, // [0:10] is the sub-list for field type_name + 1, // 0: object.RawObject.created_by:type_name -> object.UserInfo + 1, // 1: object.RawObject.modified_by:type_name -> object.UserInfo + 1, // 2: object.ObjectVersionInfo.modified_by:type_name -> object.UserInfo + 2, // 3: object.ReadObjectResponse.object:type_name -> object.RawObject + 5, // 4: object.BatchReadObjectRequest.batch:type_name -> object.ReadObjectRequest + 6, // 5: object.BatchReadObjectResponse.results:type_name -> object.ReadObjectResponse + 3, // 6: object.WriteObjectResponse.error:type_name -> object.ObjectErrorInfo + 4, // 7: object.WriteObjectResponse.object:type_name -> object.ObjectVersionInfo + 0, // 8: object.WriteObjectResponse.status:type_name -> object.WriteObjectResponse.Status + 4, // 9: object.ObjectHistoryResponse.versions:type_name -> object.ObjectVersionInfo + 17, // 10: object.ObjectSearchRequest.labels:type_name -> object.ObjectSearchRequest.LabelsEntry + 2, // 11: object.ObjectSearchResponse.results:type_name -> object.RawObject + 5, // 12: object.ObjectStore.Read:input_type -> object.ReadObjectRequest + 7, // 13: object.ObjectStore.BatchRead:input_type -> object.BatchReadObjectRequest + 9, // 14: object.ObjectStore.Write:input_type -> object.WriteObjectRequest + 11, // 15: object.ObjectStore.Delete:input_type -> object.DeleteObjectRequest + 13, // 16: object.ObjectStore.History:input_type -> object.ObjectHistoryRequest + 15, // 17: object.ObjectStore.Search:input_type -> object.ObjectSearchRequest + 6, // 18: object.ObjectStore.Read:output_type -> object.ReadObjectResponse + 8, // 19: object.ObjectStore.BatchRead:output_type -> object.BatchReadObjectResponse + 10, // 20: object.ObjectStore.Write:output_type -> object.WriteObjectResponse + 12, // 21: object.ObjectStore.Delete:output_type -> object.DeleteObjectResponse + 14, // 22: object.ObjectStore.History:output_type -> object.ObjectHistoryResponse + 16, // 23: object.ObjectStore.Search:output_type -> object.ObjectSearchResponse + 18, // [18:24] is the sub-list for method output_type + 12, // [12:18] is the sub-list for method input_type + 12, // [12:12] is the sub-list for extension type_name + 12, // [12:12] is the sub-list for extension extendee + 0, // [0:12] is the sub-list for field type_name } func init() { file_object_proto_init() } @@ -1387,7 +1559,7 @@ func file_object_proto_init() { } } file_object_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReadObjectRequest); i { + switch v := v.(*ObjectVersionInfo); i { case 0: return &v.state case 1: @@ -1399,7 +1571,7 @@ func file_object_proto_init() { } } file_object_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ReadObjectResponse); i { + switch v := v.(*ReadObjectRequest); i { case 0: return &v.state case 1: @@ -1411,7 +1583,7 @@ func file_object_proto_init() { } } file_object_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BatchReadObjectRequest); i { + switch v := v.(*ReadObjectResponse); i { case 0: return &v.state case 1: @@ -1423,7 +1595,7 @@ func file_object_proto_init() { } } file_object_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*BatchReadObjectResponse); i { + switch v := v.(*BatchReadObjectRequest); i { case 0: return &v.state case 1: @@ -1435,7 +1607,7 @@ func file_object_proto_init() { } } file_object_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WriteObjectRequest); i { + switch v := v.(*BatchReadObjectResponse); i { case 0: return &v.state case 1: @@ -1447,7 +1619,7 @@ func file_object_proto_init() { } } file_object_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*WriteObjectResponse); i { + switch v := v.(*WriteObjectRequest); i { case 0: return &v.state case 1: @@ -1459,7 +1631,7 @@ func file_object_proto_init() { } } file_object_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteObjectRequest); i { + switch v := v.(*WriteObjectResponse); i { case 0: return &v.state case 1: @@ -1471,7 +1643,7 @@ func file_object_proto_init() { } } file_object_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeleteObjectResponse); i { + switch v := v.(*DeleteObjectRequest); i { case 0: return &v.state case 1: @@ -1483,7 +1655,7 @@ func file_object_proto_init() { } } file_object_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ObjectHistoryRequest); i { + switch v := v.(*DeleteObjectResponse); i { case 0: return &v.state case 1: @@ -1495,7 +1667,7 @@ func file_object_proto_init() { } } file_object_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ObjectHistoryResponse); i { + switch v := v.(*ObjectHistoryRequest); i { case 0: return &v.state case 1: @@ -1507,7 +1679,7 @@ func file_object_proto_init() { } } file_object_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ObjectSearchRequest); i { + switch v := v.(*ObjectHistoryResponse); i { case 0: return &v.state case 1: @@ -1519,6 +1691,18 @@ func file_object_proto_init() { } } file_object_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ObjectSearchRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_object_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ObjectSearchResponse); i { case 0: return &v.state @@ -1536,13 +1720,14 @@ func file_object_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_object_proto_rawDesc, - NumEnums: 0, - NumMessages: 16, + NumEnums: 1, + NumMessages: 17, NumExtensions: 0, NumServices: 1, }, GoTypes: file_object_proto_goTypes, DependencyIndexes: file_object_proto_depIdxs, + EnumInfos: file_object_proto_enumTypes, MessageInfos: file_object_proto_msgTypes, }.Build() File_object_proto = out.File diff --git a/pkg/services/store/object/object.proto b/pkg/services/store/object/object.proto index b9eedebb787..ab4a3015234 100644 --- a/pkg/services/store/object/object.proto +++ b/pkg/services/store/object/object.proto @@ -47,20 +47,15 @@ message RawObject { // NOTE: currently managed by the dashboard+dashboard_version tables string version = 10; - // optional "save" or "commit" message - // - // NOTE: currently managed by the dashboard_version table, and will be returned from a "history" command - string comment = 11; - // Location (path/repo/etc) that defines the canonocal form // // NOTE: currently managed by the dashboard_provisioning table - string sync_src = 12; + string sync_src = 11; // Time in epoch milliseconds that the object was last synced with an external system (provisioning/git) // // NOTE: currently managed by the dashboard_provisioning table - int64 sync_time = 13; + int64 sync_time = 12; } // Report error while working with objects @@ -76,6 +71,29 @@ message ObjectErrorInfo { bytes details_json = 3; } +// This is a subset of RawObject that does not include body or sync info +message ObjectVersionInfo { + // The version will change when the object is saved. It is not necessarily sortable + string version = 1; + + // Time in epoch milliseconds that the object was modified + int64 modified = 2; + + // Who modified the object + UserInfo modified_by = 3; + + // Content Length + int64 size = 4; + + // MD5 digest of the body + string ETag = 5; + + // optional "save" or "commit" message + // + // NOTE: currently managed by the dashboard_version table, and will be returned from a "history" command + string comment = 6; +} + //----------------------------------------------- // Get request/response //----------------------------------------------- @@ -143,10 +161,21 @@ message WriteObjectResponse { ObjectErrorInfo error = 1; // Object details with the body removed - RawObject object = 2; + ObjectVersionInfo object = 2; // Object summary as JSON bytes summary_json = 3; + + // Status code + Status status = 4; + + // Status enumeration + enum Status { + ERROR = 0; + CREATED = 1; + MODIFIED = 2; + UNCHANGED = 3; + } } //----------------------------------------------- @@ -188,7 +217,7 @@ message ObjectHistoryRequest { message ObjectHistoryResponse { // Object metadata without the raw bytes - repeated RawObject object = 1; + repeated ObjectVersionInfo versions = 1; // More results exist... pass this in the next request string next_page_token = 2; diff --git a/pkg/services/store/object/object_grpc.pb.go b/pkg/services/store/object/object_grpc.pb.go index 1a4887e7353..9fbbf97d41c 100644 --- a/pkg/services/store/object/object_grpc.pb.go +++ b/pkg/services/store/object/object_grpc.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go-grpc. DO NOT EDIT. // versions: // - protoc-gen-go-grpc v1.2.0 -// - protoc v3.21.5 +// - protoc v3.21.7 // source: object.proto package object diff --git a/pkg/services/store/object/tests/server_integration_test.go b/pkg/services/store/object/tests/server_integration_test.go index e0410c63e91..ee696c4e43f 100644 --- a/pkg/services/store/object/tests/server_integration_test.go +++ b/pkg/services/store/object/tests/server_integration_test.go @@ -29,12 +29,23 @@ type rawObjectMatcher struct { modifiedBy *object.UserInfo body []byte version *string +} + +type objectVersionMatcher struct { + modifiedRange []time.Time + modifiedBy *object.UserInfo + version *string + etag *string comment *string } func userInfoMatches(expected *object.UserInfo, actual *object.UserInfo) (bool, string) { var mismatches []string + if actual == nil && expected != nil { + return true, "Missing user info" + } + if expected.Id != actual.Id { mismatches = append(mismatches, fmt.Sprintf("expected ID %d, actual ID: %d", expected.Id, actual.Id)) } @@ -52,6 +63,8 @@ func timestampInRange(ts int64, tsRange []time.Time) bool { func requireObjectMatch(t *testing.T, obj *object.RawObject, m rawObjectMatcher) { t.Helper() + require.NotNil(t, obj) + mismatches := "" if m.uid != nil && *m.uid != obj.UID { mismatches += fmt.Sprintf("expected UID: %s, actual UID: %s\n", *m.uid, obj.UID) @@ -66,7 +79,7 @@ func requireObjectMatch(t *testing.T, obj *object.RawObject, m rawObjectMatcher) } if len(m.modifiedRange) == 2 && !timestampInRange(obj.Modified, m.modifiedRange) { - mismatches += fmt.Sprintf("expected createdBy range: [from %s to %s], actual created: %s\n", m.createdRange[0], m.createdRange[1], time.Unix(obj.Created, 0)) + mismatches += fmt.Sprintf("expected createdBy range: [from %s to %s], actual created: %s\n", m.modifiedRange[0], m.modifiedRange[1], time.Unix(obj.Modified, 0)) } if m.createdBy != nil { @@ -97,8 +110,30 @@ func requireObjectMatch(t *testing.T, obj *object.RawObject, m rawObjectMatcher) mismatches += fmt.Sprintf("expected version: %s, actual version: %s\n", *m.version, obj.Version) } - if m.comment != nil && *m.comment != obj.Comment { - mismatches += fmt.Sprintf("expected comment: %s, actual comment: %s\n", *m.comment, obj.Comment) + require.True(t, len(mismatches) == 0, mismatches) +} + +func requireVersionMatch(t *testing.T, obj *object.ObjectVersionInfo, m objectVersionMatcher) { + t.Helper() + mismatches := "" + + if m.etag != nil && *m.etag != obj.ETag { + mismatches += fmt.Sprintf("expected etag: %s, actual etag: %s\n", *m.etag, obj.ETag) + } + + if len(m.modifiedRange) == 2 && !timestampInRange(obj.Modified, m.modifiedRange) { + mismatches += fmt.Sprintf("expected createdBy range: [from %s to %s], actual created: %s\n", m.modifiedRange[0], m.modifiedRange[1], time.Unix(obj.Modified, 0)) + } + + if m.modifiedBy != nil { + userInfoMatches, msg := userInfoMatches(m.modifiedBy, obj.ModifiedBy) + if !userInfoMatches { + mismatches += fmt.Sprintf("modifiedBy: %s\n", msg) + } + } + + if m.version != nil && *m.version != obj.Version { + mismatches += fmt.Sprintf("expected version: %s, actual version: %s\n", *m.version, obj.Version) } require.True(t, len(mismatches) == 0, mismatches) @@ -144,18 +179,13 @@ func TestObjectServer(t *testing.T) { writeResp, err := testCtx.client.Write(ctx, writeReq) require.NoError(t, err) - objectMatcher := rawObjectMatcher{ - uid: &uid, - kind: &kind, - createdRange: []time.Time{before, time.Now()}, + versionMatcher := objectVersionMatcher{ modifiedRange: []time.Time{before, time.Now()}, - createdBy: fakeUser, modifiedBy: fakeUser, - body: body, version: &firstVersion, comment: &writeReq.Comment, } - requireObjectMatch(t, writeResp.Object, objectMatcher) + requireVersionMatch(t, writeResp.Object, versionMatcher) readResp, err := testCtx.client.Read(ctx, &object.ReadObjectRequest{ UID: uid, @@ -165,7 +195,18 @@ func TestObjectServer(t *testing.T) { }) require.NoError(t, err) require.Nil(t, readResp.SummaryJson) - requireObjectMatch(t, writeResp.Object, objectMatcher) + + objectMatcher := rawObjectMatcher{ + uid: &uid, + kind: &kind, + createdRange: []time.Time{before, time.Now()}, + modifiedRange: []time.Time{before, time.Now()}, + createdBy: fakeUser, + modifiedBy: fakeUser, + body: body, + version: &firstVersion, + } + requireObjectMatch(t, readResp.Object, objectMatcher) deleteResp, err := testCtx.client.Delete(ctx, &object.DeleteObjectRequest{ UID: uid, @@ -195,6 +236,7 @@ func TestObjectServer(t *testing.T) { } writeResp1, err := testCtx.client.Write(ctx, writeReq1) require.NoError(t, err) + require.Equal(t, object.WriteObjectResponse_CREATED, writeResp1.Status) body2 := []byte("{\"name\":\"John2\"}") @@ -208,6 +250,14 @@ func TestObjectServer(t *testing.T) { require.NoError(t, err) require.NotEqual(t, writeResp1.Object.Version, writeResp2.Object.Version) + // Duplicate write (no change) + writeDupRsp, err := testCtx.client.Write(ctx, writeReq2) + require.NoError(t, err) + require.Nil(t, writeDupRsp.Error) + require.Equal(t, object.WriteObjectResponse_UNCHANGED, writeDupRsp.Status) + require.Equal(t, writeResp2.Object.Version, writeDupRsp.Object.Version) + require.Equal(t, writeResp2.Object.ETag, writeDupRsp.Object.ETag) + body3 := []byte("{\"name\":\"John3\"}") writeReq3 := &object.WriteObjectRequest{ UID: uid, @@ -228,7 +278,6 @@ func TestObjectServer(t *testing.T) { modifiedBy: fakeUser, body: body3, version: &writeResp3.Object.Version, - comment: &writeReq3.Comment, } readRespLatest, err := testCtx.client.Read(ctx, &object.ReadObjectRequest{ UID: uid, @@ -259,7 +308,6 @@ func TestObjectServer(t *testing.T) { modifiedBy: fakeUser, body: body, version: &firstVersion, - comment: &writeReq1.Comment, }) history, err := testCtx.client.History(ctx, &object.ObjectHistoryRequest{ @@ -267,11 +315,11 @@ func TestObjectServer(t *testing.T) { Kind: kind, }) require.NoError(t, err) - require.Equal(t, []*object.RawObject{ - writeResp1.Object, - writeResp2.Object, + require.Equal(t, []*object.ObjectVersionInfo{ writeResp3.Object, - }, history.Object) + writeResp2.Object, + writeResp1.Object, + }, history.Versions) deleteResp, err := testCtx.client.Delete(ctx, &object.DeleteObjectRequest{ UID: uid, @@ -316,19 +364,47 @@ func TestObjectServer(t *testing.T) { require.NoError(t, err) search, err := testCtx.client.Search(ctx, &object.ObjectSearchRequest{ - Kind: []string{kind, kind2}, + Kind: []string{kind, kind2}, + WithBody: false, }) require.NoError(t, err) - require.Equal(t, []*object.RawObject{ - w1.Object, w2.Object, w3.Object, w4.Object, - }, search.Results) + require.NotNil(t, search) + uids := make([]string, 0, len(search.Results)) + kinds := make([]string, 0, len(search.Results)) + version := make([]string, 0, len(search.Results)) + for _, res := range search.Results { + uids = append(uids, res.UID) + kinds = append(kinds, res.Kind) + version = append(version, res.Version) + } + require.Equal(t, []string{"my-test-entity", "uid2", "uid3", "uid4"}, uids) + require.Equal(t, []string{"dashboard", "dashboard", "kind2", "kind2"}, kinds) + require.Equal(t, []string{ + w1.Object.Version, + w2.Object.Version, + w3.Object.Version, + w4.Object.Version, + }, version) + + // Again with only one kind searchKind1, err := testCtx.client.Search(ctx, &object.ObjectSearchRequest{ Kind: []string{kind}, }) require.NoError(t, err) - require.Equal(t, []*object.RawObject{ - w1.Object, w2.Object, - }, searchKind1.Results) + uids = make([]string, 0, len(searchKind1.Results)) + kinds = make([]string, 0, len(searchKind1.Results)) + version = make([]string, 0, len(searchKind1.Results)) + for _, res := range searchKind1.Results { + uids = append(uids, res.UID) + kinds = append(kinds, res.Kind) + version = append(version, res.Version) + } + require.Equal(t, []string{"my-test-entity", "uid2"}, uids) + require.Equal(t, []string{"dashboard", "dashboard"}, kinds) + require.Equal(t, []string{ + w1.Object.Version, + w2.Object.Version, + }, version) }) }