From 49a81c9c1fad026b79d76cb64ad1f118123fef90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Fri, 31 Jul 2026 14:44:15 +0200 Subject: [PATCH 1/4] Cleanup .bingo --- .bingo/go-xgettext.mod | 2 -- 1 file changed, 2 deletions(-) diff --git a/.bingo/go-xgettext.mod b/.bingo/go-xgettext.mod index b14946a0b8..8e3c6210b5 100644 --- a/.bingo/go-xgettext.mod +++ b/.bingo/go-xgettext.mod @@ -3,5 +3,3 @@ module _ // Auto generated by https://github.com/bwplotka/bingo. DO NOT EDIT go 1.23.4 require github.com/gosexy/gettext v0.0.0-20160830220431-74466a0a0c4a // go-xgettext - -require github.com/jessevdk/go-flags v1.6.1 // indirect From e26a009fc138e5fdff634f3a7aa0a9f56157000c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Fri, 31 Jul 2026 14:44:22 +0200 Subject: [PATCH 2/4] Improve "opencloud search index" command The command no longer times out after 10 minutes when the processing hasn't been finished yet. Instead it shows progress and logs successful and failed spaces. The process can also be aborted using ctrl+c. Example output: ``` $ bin/opencloud search index --all-spaces --insecure --force-rescan [1/602] indexed space a9033d65-6c13-4556-b923-f321ab33a9ca$eb6a8a0e-2e62-4b40-bce9-360063236676!eb6a8a0e-2e62-4b40-bce9-360063236676 in 5.501190908s [2/602] indexed space a9033d65-6c13-4556-b923-f321ab33a9ca$34b7c565-da3b-4f53-8559-825e87db4011!34b7c565-da3b-4f53-8559-825e87db4011 in 5.935075697s [3/602] indexed space a9033d65-6c13-4556-b923-f321ab33a9ca$e08c6026-24f6-4a9e-a805-ed335b34b8da!e08c6026-24f6-4a9e-a805-ed335b34b8da in 6.016350958s ^Caborted, indexing has been stopped ``` Fixes #2592 --- .../messages/settings/v0/settings.pb.go | 130 +++---- .../v0/mocks/search_provider_service.go | 16 +- .../opencloud/services/search/v0/search.pb.go | 129 +++++-- .../services/search/v0/search.pb.micro.go | 107 +++++- .../services/search/v0/search.pb.web.go | 346 ------------------ .../services/search/v0/search.swagger.json | 40 +- .../services/search/v0/search_grpc.pb.go | 60 +-- protogen/proto/buf.gen.yaml | 4 +- .../opencloud/services/search/v0/search.proto | 15 +- services/search/pkg/command/index.go | 42 ++- .../search/pkg/service/grpc/v0/service.go | 76 +++- 11 files changed, 458 insertions(+), 507 deletions(-) delete mode 100644 protogen/gen/opencloud/services/search/v0/search.pb.web.go diff --git a/protogen/gen/opencloud/messages/settings/v0/settings.pb.go b/protogen/gen/opencloud/messages/settings/v0/settings.pb.go index 99641dcb8c..aa9f81b327 100644 --- a/protogen/gen/opencloud/messages/settings/v0/settings.pb.go +++ b/protogen/gen/opencloud/messages/settings/v0/settings.pb.go @@ -627,13 +627,13 @@ type Bundle struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // @gotags: yaml:"id" - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // @gotags: yaml:"name" - Type Bundle_Type `protobuf:"varint,3,opt,name=type,proto3,enum=opencloud.messages.settings.v0.Bundle_Type" json:"type,omitempty"` // @gotags: yaml:"type" - Extension string `protobuf:"bytes,4,opt,name=extension,proto3" json:"extension,omitempty"` // @gotags: yaml:"extension" - DisplayName string `protobuf:"bytes,5,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` // @gotags: yaml:"display_name" - Settings []*Setting `protobuf:"bytes,6,rep,name=settings,proto3" json:"settings,omitempty"` // @gotags: yaml:"settings" - Resource *Resource `protobuf:"bytes,7,opt,name=resource,proto3" json:"resource,omitempty"` // @gotags: yaml:"resource" + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` // @gotags: yaml:"id" + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty" yaml:"name"` // @gotags: yaml:"name" + Type Bundle_Type `protobuf:"varint,3,opt,name=type,proto3,enum=opencloud.messages.settings.v0.Bundle_Type" json:"type,omitempty" yaml:"type"` // @gotags: yaml:"type" + Extension string `protobuf:"bytes,4,opt,name=extension,proto3" json:"extension,omitempty" yaml:"extension"` // @gotags: yaml:"extension" + DisplayName string `protobuf:"bytes,5,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty" yaml:"display_name"` // @gotags: yaml:"display_name" + Settings []*Setting `protobuf:"bytes,6,rep,name=settings,proto3" json:"settings,omitempty" yaml:"settings"` // @gotags: yaml:"settings" + Resource *Resource `protobuf:"bytes,7,opt,name=resource,proto3" json:"resource,omitempty" yaml:"resource"` // @gotags: yaml:"resource" } func (x *Bundle) Reset() { @@ -722,10 +722,10 @@ type Setting struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // @gotags: yaml:"id" - Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` // @gotags: yaml:"name" - DisplayName string `protobuf:"bytes,3,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty"` // @gotags: yaml:"display_name" - Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty"` // @gotags: yaml:"description" + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` // @gotags: yaml:"id" + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty" yaml:"name"` // @gotags: yaml:"name" + DisplayName string `protobuf:"bytes,3,opt,name=display_name,json=displayName,proto3" json:"display_name,omitempty" yaml:"display_name"` // @gotags: yaml:"display_name" + Description string `protobuf:"bytes,4,opt,name=description,proto3" json:"description,omitempty" yaml:"description"` // @gotags: yaml:"description" // Types that are assignable to Value: // // *Setting_IntValue @@ -736,7 +736,7 @@ type Setting struct { // *Setting_PermissionValue // *Setting_MultiChoiceCollectionValue Value isSetting_Value `protobuf_oneof:"value"` - Resource *Resource `protobuf:"bytes,11,opt,name=resource,proto3" json:"resource,omitempty"` // @gotags: yaml:"resource" + Resource *Resource `protobuf:"bytes,11,opt,name=resource,proto3" json:"resource,omitempty" yaml:"resource"` // @gotags: yaml:"resource" } func (x *Setting) Reset() { @@ -867,31 +867,31 @@ type isSetting_Value interface { } type Setting_IntValue struct { - IntValue *Int `protobuf:"bytes,5,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value" + IntValue *Int `protobuf:"bytes,5,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value" } type Setting_StringValue struct { - StringValue *String `protobuf:"bytes,6,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value" + StringValue *String `protobuf:"bytes,6,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value" } type Setting_BoolValue struct { - BoolValue *Bool `protobuf:"bytes,7,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value" + BoolValue *Bool `protobuf:"bytes,7,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value" } type Setting_SingleChoiceValue struct { - SingleChoiceValue *SingleChoiceList `protobuf:"bytes,8,opt,name=single_choice_value,json=singleChoiceValue,proto3,oneof"` // @gotags: yaml:"single_choice_value" + SingleChoiceValue *SingleChoiceList `protobuf:"bytes,8,opt,name=single_choice_value,json=singleChoiceValue,proto3,oneof" yaml:"single_choice_value"` // @gotags: yaml:"single_choice_value" } type Setting_MultiChoiceValue struct { - MultiChoiceValue *MultiChoiceList `protobuf:"bytes,9,opt,name=multi_choice_value,json=multiChoiceValue,proto3,oneof"` // @gotags: yaml:"multi_choice_value" + MultiChoiceValue *MultiChoiceList `protobuf:"bytes,9,opt,name=multi_choice_value,json=multiChoiceValue,proto3,oneof" yaml:"multi_choice_value"` // @gotags: yaml:"multi_choice_value" } type Setting_PermissionValue struct { - PermissionValue *Permission `protobuf:"bytes,10,opt,name=permission_value,json=permissionValue,proto3,oneof"` // @gotags: yaml:"permission_value" + PermissionValue *Permission `protobuf:"bytes,10,opt,name=permission_value,json=permissionValue,proto3,oneof" yaml:"permission_value"` // @gotags: yaml:"permission_value" } type Setting_MultiChoiceCollectionValue struct { - MultiChoiceCollectionValue *MultiChoiceCollection `protobuf:"bytes,12,opt,name=multi_choice_collection_value,json=multiChoiceCollectionValue,proto3,oneof"` // @gotags: yaml:"multi_choice_collection_value" + MultiChoiceCollectionValue *MultiChoiceCollection `protobuf:"bytes,12,opt,name=multi_choice_collection_value,json=multiChoiceCollectionValue,proto3,oneof" yaml:"multi_choice_collection_value"` // @gotags: yaml:"multi_choice_collection_value" } func (*Setting_IntValue) isSetting_Value() {} @@ -913,11 +913,11 @@ type Int struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Default int64 `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default" - Min int64 `protobuf:"varint,2,opt,name=min,proto3" json:"min,omitempty"` // @gotags: yaml:"min" - Max int64 `protobuf:"varint,3,opt,name=max,proto3" json:"max,omitempty"` // @gotags: yaml:"max" - Step int64 `protobuf:"varint,4,opt,name=step,proto3" json:"step,omitempty"` // @gotags: yaml:"step" - Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty"` // @gotags: yaml:"placeholder" + Default int64 `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default" + Min int64 `protobuf:"varint,2,opt,name=min,proto3" json:"min,omitempty" yaml:"min"` // @gotags: yaml:"min" + Max int64 `protobuf:"varint,3,opt,name=max,proto3" json:"max,omitempty" yaml:"max"` // @gotags: yaml:"max" + Step int64 `protobuf:"varint,4,opt,name=step,proto3" json:"step,omitempty" yaml:"step"` // @gotags: yaml:"step" + Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty" yaml:"placeholder"` // @gotags: yaml:"placeholder" } func (x *Int) Reset() { @@ -992,11 +992,11 @@ type String struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Default string `protobuf:"bytes,1,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default" - Required bool `protobuf:"varint,2,opt,name=required,proto3" json:"required,omitempty"` // @gotags: yaml:"required" - MinLength int32 `protobuf:"varint,3,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty"` // @gotags: yaml:"min_length" - MaxLength int32 `protobuf:"varint,4,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty"` // @gotags: yaml:"max_length" - Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty"` // @gotags: yaml:"placeholder" + Default string `protobuf:"bytes,1,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default" + Required bool `protobuf:"varint,2,opt,name=required,proto3" json:"required,omitempty" yaml:"required"` // @gotags: yaml:"required" + MinLength int32 `protobuf:"varint,3,opt,name=min_length,json=minLength,proto3" json:"min_length,omitempty" yaml:"min_length"` // @gotags: yaml:"min_length" + MaxLength int32 `protobuf:"varint,4,opt,name=max_length,json=maxLength,proto3" json:"max_length,omitempty" yaml:"max_length"` // @gotags: yaml:"max_length" + Placeholder string `protobuf:"bytes,5,opt,name=placeholder,proto3" json:"placeholder,omitempty" yaml:"placeholder"` // @gotags: yaml:"placeholder" } func (x *String) Reset() { @@ -1071,8 +1071,8 @@ type Bool struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Default bool `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default" - Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty"` // @gotags: yaml:"label" + Default bool `protobuf:"varint,1,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default" + Label string `protobuf:"bytes,2,opt,name=label,proto3" json:"label,omitempty" yaml:"label"` // @gotags: yaml:"label" } func (x *Bool) Reset() { @@ -1126,7 +1126,7 @@ type SingleChoiceList struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty"` // @gotags: yaml:"options" + Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty" yaml:"options"` // @gotags: yaml:"options" } func (x *SingleChoiceList) Reset() { @@ -1173,7 +1173,7 @@ type MultiChoiceList struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty"` // @gotags: yaml:"options" + Options []*ListOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty" yaml:"options"` // @gotags: yaml:"options" } func (x *MultiChoiceList) Reset() { @@ -1220,9 +1220,9 @@ type ListOption struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Value *ListOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` // @gotags: yaml:"value" - Default bool `protobuf:"varint,2,opt,name=default,proto3" json:"default,omitempty"` // @gotags: yaml:"default" - DisplayValue string `protobuf:"bytes,3,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty"` // @gotags: yaml:"display_value" + Value *ListOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty" yaml:"value"` // @gotags: yaml:"value" + Default bool `protobuf:"varint,2,opt,name=default,proto3" json:"default,omitempty" yaml:"default"` // @gotags: yaml:"default" + DisplayValue string `protobuf:"bytes,3,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty" yaml:"display_value"` // @gotags: yaml:"display_value" } func (x *ListOption) Reset() { @@ -1283,7 +1283,7 @@ type MultiChoiceCollection struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Options []*MultiChoiceCollectionOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty"` // @gotags: yaml:"options" + Options []*MultiChoiceCollectionOption `protobuf:"bytes,1,rep,name=options,proto3" json:"options,omitempty" yaml:"options"` // @gotags: yaml:"options" } func (x *MultiChoiceCollection) Reset() { @@ -1330,10 +1330,10 @@ type MultiChoiceCollectionOption struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Value *MultiChoiceCollectionOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` // @gotags: yaml:"value" - Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty"` // @gotags: yaml:"key" - Attribute string `protobuf:"bytes,3,opt,name=attribute,proto3" json:"attribute,omitempty"` // @gotags: yaml:"attribute" - DisplayValue string `protobuf:"bytes,4,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty"` // @gotags: yaml:"display_value" + Value *MultiChoiceCollectionOptionValue `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty" yaml:"value"` // @gotags: yaml:"value" + Key string `protobuf:"bytes,2,opt,name=key,proto3" json:"key,omitempty" yaml:"key"` // @gotags: yaml:"key" + Attribute string `protobuf:"bytes,3,opt,name=attribute,proto3" json:"attribute,omitempty" yaml:"attribute"` // @gotags: yaml:"attribute" + DisplayValue string `protobuf:"bytes,4,opt,name=display_value,json=displayValue,proto3" json:"display_value,omitempty" yaml:"display_value"` // @gotags: yaml:"display_value" } func (x *MultiChoiceCollectionOption) Reset() { @@ -1474,15 +1474,15 @@ type isMultiChoiceCollectionOptionValue_Option interface { } type MultiChoiceCollectionOptionValue_IntValue struct { - IntValue *Int `protobuf:"bytes,1,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value" + IntValue *Int `protobuf:"bytes,1,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value" } type MultiChoiceCollectionOptionValue_StringValue struct { - StringValue *String `protobuf:"bytes,2,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value" + StringValue *String `protobuf:"bytes,2,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value" } type MultiChoiceCollectionOptionValue_BoolValue struct { - BoolValue *Bool `protobuf:"bytes,3,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value" + BoolValue *Bool `protobuf:"bytes,3,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value" } func (*MultiChoiceCollectionOptionValue_IntValue) isMultiChoiceCollectionOptionValue_Option() {} @@ -1496,8 +1496,8 @@ type Permission struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Operation Permission_Operation `protobuf:"varint,1,opt,name=operation,proto3,enum=opencloud.messages.settings.v0.Permission_Operation" json:"operation,omitempty"` // @gotags: yaml:"operation" - Constraint Permission_Constraint `protobuf:"varint,2,opt,name=constraint,proto3,enum=opencloud.messages.settings.v0.Permission_Constraint" json:"constraint,omitempty"` // @gotags: yaml:"constraint" + Operation Permission_Operation `protobuf:"varint,1,opt,name=operation,proto3,enum=opencloud.messages.settings.v0.Permission_Operation" json:"operation,omitempty" yaml:"operation"` // @gotags: yaml:"operation" + Constraint Permission_Constraint `protobuf:"varint,2,opt,name=constraint,proto3,enum=opencloud.messages.settings.v0.Permission_Constraint" json:"constraint,omitempty" yaml:"constraint"` // @gotags: yaml:"constraint" } func (x *Permission) Reset() { @@ -1552,12 +1552,12 @@ type Value struct { unknownFields protoimpl.UnknownFields // id is the id of the Value. It is generated on saving it. - Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` // @gotags: yaml:"id" - BundleId string `protobuf:"bytes,2,opt,name=bundle_id,json=bundleId,proto3" json:"bundle_id,omitempty"` // @gotags: yaml:"bundle_id" + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty" yaml:"id"` // @gotags: yaml:"id" + BundleId string `protobuf:"bytes,2,opt,name=bundle_id,json=bundleId,proto3" json:"bundle_id,omitempty" yaml:"bundle_id"` // @gotags: yaml:"bundle_id" // setting_id is the id of the setting from within its bundle. - SettingId string `protobuf:"bytes,3,opt,name=setting_id,json=settingId,proto3" json:"setting_id,omitempty"` // @gotags: yaml:"setting_id" - AccountUuid string `protobuf:"bytes,4,opt,name=account_uuid,json=accountUuid,proto3" json:"account_uuid,omitempty"` // @gotags: yaml:"account_uuid" - Resource *Resource `protobuf:"bytes,5,opt,name=resource,proto3" json:"resource,omitempty"` // @gotags: yaml:"resource" + SettingId string `protobuf:"bytes,3,opt,name=setting_id,json=settingId,proto3" json:"setting_id,omitempty" yaml:"setting_id"` // @gotags: yaml:"setting_id" + AccountUuid string `protobuf:"bytes,4,opt,name=account_uuid,json=accountUuid,proto3" json:"account_uuid,omitempty" yaml:"account_uuid"` // @gotags: yaml:"account_uuid" + Resource *Resource `protobuf:"bytes,5,opt,name=resource,proto3" json:"resource,omitempty" yaml:"resource"` // @gotags: yaml:"resource" // Types that are assignable to Value: // // *Value_BoolValue @@ -1682,23 +1682,23 @@ type isValue_Value interface { } type Value_BoolValue struct { - BoolValue bool `protobuf:"varint,6,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value" + BoolValue bool `protobuf:"varint,6,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value" } type Value_IntValue struct { - IntValue int64 `protobuf:"varint,7,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value" + IntValue int64 `protobuf:"varint,7,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value" } type Value_StringValue struct { - StringValue string `protobuf:"bytes,8,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value" + StringValue string `protobuf:"bytes,8,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value" } type Value_ListValue struct { - ListValue *ListValue `protobuf:"bytes,9,opt,name=list_value,json=listValue,proto3,oneof"` // @gotags: yaml:"list_value" + ListValue *ListValue `protobuf:"bytes,9,opt,name=list_value,json=listValue,proto3,oneof" yaml:"list_value"` // @gotags: yaml:"list_value" } type Value_CollectionValue struct { - CollectionValue *CollectionValue `protobuf:"bytes,10,opt,name=collection_value,json=collectionValue,proto3,oneof"` // @gotags: yaml:"collection_value" + CollectionValue *CollectionValue `protobuf:"bytes,10,opt,name=collection_value,json=collectionValue,proto3,oneof" yaml:"collection_value"` // @gotags: yaml:"collection_value" } func (*Value_BoolValue) isValue_Value() {} @@ -1716,7 +1716,7 @@ type ListValue struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Values []*ListOptionValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` // @gotags: yaml:"values" + Values []*ListOptionValue `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty" yaml:"values"` // @gotags: yaml:"values" } func (x *ListValue) Reset() { @@ -1836,15 +1836,15 @@ type isListOptionValue_Option interface { } type ListOptionValue_StringValue struct { - StringValue string `protobuf:"bytes,1,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value" + StringValue string `protobuf:"bytes,1,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value" } type ListOptionValue_IntValue struct { - IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value" + IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value" } type ListOptionValue_BoolValue struct { - BoolValue bool `protobuf:"varint,3,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value" + BoolValue bool `protobuf:"varint,3,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value" } func (*ListOptionValue_StringValue) isListOptionValue_Option() {} @@ -1858,7 +1858,7 @@ type CollectionValue struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Values []*CollectionOption `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty"` // @gotags: yaml:"values" + Values []*CollectionOption `protobuf:"bytes,1,rep,name=values,proto3" json:"values,omitempty" yaml:"values"` // @gotags: yaml:"values" } func (x *CollectionValue) Reset() { @@ -1906,7 +1906,7 @@ type CollectionOption struct { unknownFields protoimpl.UnknownFields // required - Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` // @gotags: yaml:"key" + Key string `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty" yaml:"key"` // @gotags: yaml:"key" // Types that are assignable to Option: // // *CollectionOption_IntValue @@ -1987,15 +1987,15 @@ type isCollectionOption_Option interface { } type CollectionOption_IntValue struct { - IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof"` // @gotags: yaml:"int_value" + IntValue int64 `protobuf:"varint,2,opt,name=int_value,json=intValue,proto3,oneof" yaml:"int_value"` // @gotags: yaml:"int_value" } type CollectionOption_StringValue struct { - StringValue string `protobuf:"bytes,3,opt,name=string_value,json=stringValue,proto3,oneof"` // @gotags: yaml:"string_value" + StringValue string `protobuf:"bytes,3,opt,name=string_value,json=stringValue,proto3,oneof" yaml:"string_value"` // @gotags: yaml:"string_value" } type CollectionOption_BoolValue struct { - BoolValue bool `protobuf:"varint,4,opt,name=bool_value,json=boolValue,proto3,oneof"` // @gotags: yaml:"bool_value" + BoolValue bool `protobuf:"varint,4,opt,name=bool_value,json=boolValue,proto3,oneof" yaml:"bool_value"` // @gotags: yaml:"bool_value" } func (*CollectionOption_IntValue) isCollectionOption_Option() {} diff --git a/protogen/gen/opencloud/services/search/v0/mocks/search_provider_service.go b/protogen/gen/opencloud/services/search/v0/mocks/search_provider_service.go index 0ac66733dc..8a917e03a7 100644 --- a/protogen/gen/opencloud/services/search/v0/mocks/search_provider_service.go +++ b/protogen/gen/opencloud/services/search/v0/mocks/search_provider_service.go @@ -40,7 +40,7 @@ func (_m *SearchProviderService) EXPECT() *SearchProviderService_Expecter { } // IndexSpace provides a mock function for the type SearchProviderService -func (_mock *SearchProviderService) IndexSpace(ctx context.Context, in *v0.IndexSpaceRequest, opts ...client.CallOption) (*v0.IndexSpaceResponse, error) { +func (_mock *SearchProviderService) IndexSpace(ctx context.Context, in *v0.IndexSpaceRequest, opts ...client.CallOption) (v0.SearchProvider_IndexSpaceService, error) { var tmpRet mock.Arguments if len(opts) > 0 { tmpRet = _mock.Called(ctx, in, opts) @@ -53,16 +53,16 @@ func (_mock *SearchProviderService) IndexSpace(ctx context.Context, in *v0.Index panic("no return value specified for IndexSpace") } - var r0 *v0.IndexSpaceResponse + var r0 v0.SearchProvider_IndexSpaceService var r1 error - if returnFunc, ok := ret.Get(0).(func(context.Context, *v0.IndexSpaceRequest, ...client.CallOption) (*v0.IndexSpaceResponse, error)); ok { + if returnFunc, ok := ret.Get(0).(func(context.Context, *v0.IndexSpaceRequest, ...client.CallOption) (v0.SearchProvider_IndexSpaceService, error)); ok { return returnFunc(ctx, in, opts...) } - if returnFunc, ok := ret.Get(0).(func(context.Context, *v0.IndexSpaceRequest, ...client.CallOption) *v0.IndexSpaceResponse); ok { + if returnFunc, ok := ret.Get(0).(func(context.Context, *v0.IndexSpaceRequest, ...client.CallOption) v0.SearchProvider_IndexSpaceService); ok { r0 = returnFunc(ctx, in, opts...) } else { if ret.Get(0) != nil { - r0 = ret.Get(0).(*v0.IndexSpaceResponse) + r0 = ret.Get(0).(v0.SearchProvider_IndexSpaceService) } } if returnFunc, ok := ret.Get(1).(func(context.Context, *v0.IndexSpaceRequest, ...client.CallOption) error); ok { @@ -112,12 +112,12 @@ func (_c *SearchProviderService_IndexSpace_Call) Run(run func(ctx context.Contex return _c } -func (_c *SearchProviderService_IndexSpace_Call) Return(indexSpaceResponse *v0.IndexSpaceResponse, err error) *SearchProviderService_IndexSpace_Call { - _c.Call.Return(indexSpaceResponse, err) +func (_c *SearchProviderService_IndexSpace_Call) Return(searchProvider_IndexSpaceService v0.SearchProvider_IndexSpaceService, err error) *SearchProviderService_IndexSpace_Call { + _c.Call.Return(searchProvider_IndexSpaceService, err) return _c } -func (_c *SearchProviderService_IndexSpace_Call) RunAndReturn(run func(ctx context.Context, in *v0.IndexSpaceRequest, opts ...client.CallOption) (*v0.IndexSpaceResponse, error)) *SearchProviderService_IndexSpace_Call { +func (_c *SearchProviderService_IndexSpace_Call) RunAndReturn(run func(ctx context.Context, in *v0.IndexSpaceRequest, opts ...client.CallOption) (v0.SearchProvider_IndexSpaceService, error)) *SearchProviderService_IndexSpace_Call { _c.Call.Return(run) return _c } diff --git a/protogen/gen/opencloud/services/search/v0/search.pb.go b/protogen/gen/opencloud/services/search/v0/search.pb.go index 6887541719..144662c81b 100644 --- a/protogen/gen/opencloud/services/search/v0/search.pb.go +++ b/protogen/gen/opencloud/services/search/v0/search.pb.go @@ -12,6 +12,7 @@ import ( _ "google.golang.org/genproto/googleapis/api/annotations" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" + durationpb "google.golang.org/protobuf/types/known/durationpb" _ "google.golang.org/protobuf/types/known/fieldmaskpb" reflect "reflect" sync "sync" @@ -369,6 +370,17 @@ type IndexSpaceResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + // The id of the space that has just been indexed. + SpaceId string `protobuf:"bytes,1,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` + // The duration it took to index this space. + SpaceDuration *durationpb.Duration `protobuf:"bytes,2,opt,name=space_duration,json=spaceDuration,proto3" json:"space_duration,omitempty"` + // The number of spaces that have been indexed so far. + IndexedSpaces int64 `protobuf:"varint,3,opt,name=indexed_spaces,json=indexedSpaces,proto3" json:"indexed_spaces,omitempty"` + // The total number of spaces that are being indexed. + TotalSpaces int64 `protobuf:"varint,4,opt,name=total_spaces,json=totalSpaces,proto3" json:"total_spaces,omitempty"` + // Contains an error message in case indexing this particular space failed. + Error string `protobuf:"bytes,5,opt,name=error,proto3" json:"error,omitempty"` } func (x *IndexSpaceResponse) Reset() { @@ -403,6 +415,41 @@ func (*IndexSpaceResponse) Descriptor() ([]byte, []int) { return file_opencloud_services_search_v0_search_proto_rawDescGZIP(), []int{5} } +func (x *IndexSpaceResponse) GetSpaceId() string { + if x != nil { + return x.SpaceId + } + return "" +} + +func (x *IndexSpaceResponse) GetSpaceDuration() *durationpb.Duration { + if x != nil { + return x.SpaceDuration + } + return nil +} + +func (x *IndexSpaceResponse) GetIndexedSpaces() int64 { + if x != nil { + return x.IndexedSpaces + } + return 0 +} + +func (x *IndexSpaceResponse) GetTotalSpaces() int64 { + if x != nil { + return x.TotalSpaces + } + return 0 +} + +func (x *IndexSpaceResponse) GetError() string { + if x != nil { + return x.Error + } + return "" +} + var File_opencloud_services_search_v0_search_proto protoreflect.FileDescriptor var file_opencloud_services_search_v0_search_proto_rawDesc = []byte{ @@ -422,6 +469,8 @@ var file_opencloud_services_search_v0_search_proto_rawDesc = []byte{ 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x20, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2e, + 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xae, 0x01, 0x0a, 0x0d, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x21, 0x0a, 0x09, 0x70, 0x61, 0x67, 0x65, 0x5f, 0x73, 0x69, 0x7a, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x01, @@ -471,28 +520,40 @@ var file_opencloud_services_search_v0_search_proto_rawDesc = []byte{ 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x5f, 0x72, 0x65, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0c, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0x14, 0x0a, - 0x12, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, - 0x6e, 0x73, 0x65, 0x32, 0xb1, 0x02, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x72, - 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x85, 0x01, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x12, 0x2b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, - 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, - 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x53, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, - 0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, - 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x96, - 0x01, 0x0a, 0x0a, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x12, 0x2f, 0x2e, - 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x49, 0x6e, 0x64, - 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, - 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x49, 0x6e, - 0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x3a, 0x01, 0x2a, 0x22, 0x1a, 0x2f, 0x61, 0x70, - 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x69, 0x6e, 0x64, 0x65, - 0x78, 0x2d, 0x73, 0x70, 0x61, 0x63, 0x65, 0x32, 0xa7, 0x01, 0x0a, 0x0d, 0x49, 0x6e, 0x64, 0x65, + 0x0c, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0xd1, 0x01, + 0x0a, 0x12, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, + 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, + 0x40, 0x0a, 0x0e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, + 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x52, 0x0d, 0x73, 0x70, 0x61, 0x63, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x5f, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x69, 0x6e, 0x64, 0x65, 0x78, + 0x65, 0x64, 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x6f, 0x74, 0x61, + 0x6c, 0x5f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, + 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x32, 0xb3, 0x02, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x64, 0x65, 0x72, 0x12, 0x85, 0x01, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, + 0x2b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x53, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, + 0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x73, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x98, 0x01, 0x0a, + 0x0a, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x12, 0x2f, 0x2e, 0x6f, 0x70, + 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, + 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x6f, + 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x49, 0x6e, 0x64, 0x65, + 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, + 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x3a, 0x01, 0x2a, 0x22, 0x1a, 0x2f, 0x61, 0x70, 0x69, 0x2f, + 0x76, 0x30, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2d, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x30, 0x01, 0x32, 0xa7, 0x01, 0x0a, 0x0d, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x95, 0x01, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x30, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, @@ -551,23 +612,25 @@ var file_opencloud_services_search_v0_search_proto_goTypes = []interface{}{ (*IndexSpaceResponse)(nil), // 5: opencloud.services.search.v0.IndexSpaceResponse (*v0.Reference)(nil), // 6: opencloud.messages.search.v0.Reference (*v0.Match)(nil), // 7: opencloud.messages.search.v0.Match + (*durationpb.Duration)(nil), // 8: google.protobuf.Duration } var file_opencloud_services_search_v0_search_proto_depIdxs = []int32{ 6, // 0: opencloud.services.search.v0.SearchRequest.ref:type_name -> opencloud.messages.search.v0.Reference 7, // 1: opencloud.services.search.v0.SearchResponse.matches:type_name -> opencloud.messages.search.v0.Match 6, // 2: opencloud.services.search.v0.SearchIndexRequest.ref:type_name -> opencloud.messages.search.v0.Reference 7, // 3: opencloud.services.search.v0.SearchIndexResponse.matches:type_name -> opencloud.messages.search.v0.Match - 0, // 4: opencloud.services.search.v0.SearchProvider.Search:input_type -> opencloud.services.search.v0.SearchRequest - 4, // 5: opencloud.services.search.v0.SearchProvider.IndexSpace:input_type -> opencloud.services.search.v0.IndexSpaceRequest - 2, // 6: opencloud.services.search.v0.IndexProvider.Search:input_type -> opencloud.services.search.v0.SearchIndexRequest - 1, // 7: opencloud.services.search.v0.SearchProvider.Search:output_type -> opencloud.services.search.v0.SearchResponse - 5, // 8: opencloud.services.search.v0.SearchProvider.IndexSpace:output_type -> opencloud.services.search.v0.IndexSpaceResponse - 3, // 9: opencloud.services.search.v0.IndexProvider.Search:output_type -> opencloud.services.search.v0.SearchIndexResponse - 7, // [7:10] is the sub-list for method output_type - 4, // [4:7] is the sub-list for method input_type - 4, // [4:4] is the sub-list for extension type_name - 4, // [4:4] is the sub-list for extension extendee - 0, // [0:4] is the sub-list for field type_name + 8, // 4: opencloud.services.search.v0.IndexSpaceResponse.space_duration:type_name -> google.protobuf.Duration + 0, // 5: opencloud.services.search.v0.SearchProvider.Search:input_type -> opencloud.services.search.v0.SearchRequest + 4, // 6: opencloud.services.search.v0.SearchProvider.IndexSpace:input_type -> opencloud.services.search.v0.IndexSpaceRequest + 2, // 7: opencloud.services.search.v0.IndexProvider.Search:input_type -> opencloud.services.search.v0.SearchIndexRequest + 1, // 8: opencloud.services.search.v0.SearchProvider.Search:output_type -> opencloud.services.search.v0.SearchResponse + 5, // 9: opencloud.services.search.v0.SearchProvider.IndexSpace:output_type -> opencloud.services.search.v0.IndexSpaceResponse + 3, // 10: opencloud.services.search.v0.IndexProvider.Search:output_type -> opencloud.services.search.v0.SearchIndexResponse + 8, // [8:11] is the sub-list for method output_type + 5, // [5:8] is the sub-list for method input_type + 5, // [5:5] is the sub-list for extension type_name + 5, // [5:5] is the sub-list for extension extendee + 0, // [0:5] is the sub-list for field type_name } func init() { file_opencloud_services_search_v0_search_proto_init() } diff --git a/protogen/gen/opencloud/services/search/v0/search.pb.micro.go b/protogen/gen/opencloud/services/search/v0/search.pb.micro.go index e66c3fc5f6..15738fa76b 100644 --- a/protogen/gen/opencloud/services/search/v0/search.pb.micro.go +++ b/protogen/gen/opencloud/services/search/v0/search.pb.micro.go @@ -9,6 +9,7 @@ import ( _ "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/messages/search/v0" _ "google.golang.org/genproto/googleapis/api/annotations" proto "google.golang.org/protobuf/proto" + _ "google.golang.org/protobuf/types/known/durationpb" _ "google.golang.org/protobuf/types/known/fieldmaskpb" math "math" ) @@ -45,6 +46,7 @@ func NewSearchProviderEndpoints() []*api.Endpoint { Name: "SearchProvider.IndexSpace", Path: []string{"/api/v0/search/index-space"}, Method: []string{"POST"}, + Stream: true, Handler: "rpc", }, } @@ -54,7 +56,9 @@ func NewSearchProviderEndpoints() []*api.Endpoint { type SearchProviderService interface { Search(ctx context.Context, in *SearchRequest, opts ...client.CallOption) (*SearchResponse, error) - IndexSpace(ctx context.Context, in *IndexSpaceRequest, opts ...client.CallOption) (*IndexSpaceResponse, error) + // IndexSpace (re)indexes one or all spaces. The response is streamed, sending + // progress information after each space has been indexed. + IndexSpace(ctx context.Context, in *IndexSpaceRequest, opts ...client.CallOption) (SearchProvider_IndexSpaceService, error) } type searchProviderService struct { @@ -79,27 +83,73 @@ func (c *searchProviderService) Search(ctx context.Context, in *SearchRequest, o return out, nil } -func (c *searchProviderService) IndexSpace(ctx context.Context, in *IndexSpaceRequest, opts ...client.CallOption) (*IndexSpaceResponse, error) { - req := c.c.NewRequest(c.name, "SearchProvider.IndexSpace", in) - out := new(IndexSpaceResponse) - err := c.c.Call(ctx, req, out, opts...) +func (c *searchProviderService) IndexSpace(ctx context.Context, in *IndexSpaceRequest, opts ...client.CallOption) (SearchProvider_IndexSpaceService, error) { + req := c.c.NewRequest(c.name, "SearchProvider.IndexSpace", &IndexSpaceRequest{}) + stream, err := c.c.Stream(ctx, req, opts...) if err != nil { return nil, err } - return out, nil + if err := stream.Send(in); err != nil { + return nil, err + } + return &searchProviderServiceIndexSpace{stream}, nil +} + +type SearchProvider_IndexSpaceService interface { + Context() context.Context + SendMsg(interface{}) error + RecvMsg(interface{}) error + CloseSend() error + Close() error + Recv() (*IndexSpaceResponse, error) +} + +type searchProviderServiceIndexSpace struct { + stream client.Stream +} + +func (x *searchProviderServiceIndexSpace) CloseSend() error { + return x.stream.CloseSend() +} + +func (x *searchProviderServiceIndexSpace) Close() error { + return x.stream.Close() +} + +func (x *searchProviderServiceIndexSpace) Context() context.Context { + return x.stream.Context() +} + +func (x *searchProviderServiceIndexSpace) SendMsg(m interface{}) error { + return x.stream.Send(m) +} + +func (x *searchProviderServiceIndexSpace) RecvMsg(m interface{}) error { + return x.stream.Recv(m) +} + +func (x *searchProviderServiceIndexSpace) Recv() (*IndexSpaceResponse, error) { + m := new(IndexSpaceResponse) + err := x.stream.Recv(m) + if err != nil { + return nil, err + } + return m, nil } // Server API for SearchProvider service type SearchProviderHandler interface { Search(context.Context, *SearchRequest, *SearchResponse) error - IndexSpace(context.Context, *IndexSpaceRequest, *IndexSpaceResponse) error + // IndexSpace (re)indexes one or all spaces. The response is streamed, sending + // progress information after each space has been indexed. + IndexSpace(context.Context, *IndexSpaceRequest, SearchProvider_IndexSpaceStream) error } func RegisterSearchProviderHandler(s server.Server, hdlr SearchProviderHandler, opts ...server.HandlerOption) error { type searchProvider interface { Search(ctx context.Context, in *SearchRequest, out *SearchResponse) error - IndexSpace(ctx context.Context, in *IndexSpaceRequest, out *IndexSpaceResponse) error + IndexSpace(ctx context.Context, stream server.Stream) error } type SearchProvider struct { searchProvider @@ -115,6 +165,7 @@ func RegisterSearchProviderHandler(s server.Server, hdlr SearchProviderHandler, Name: "SearchProvider.IndexSpace", Path: []string{"/api/v0/search/index-space"}, Method: []string{"POST"}, + Stream: true, Handler: "rpc", })) return s.Handle(s.NewHandler(&SearchProvider{h}, opts...)) @@ -128,8 +179,44 @@ func (h *searchProviderHandler) Search(ctx context.Context, in *SearchRequest, o return h.SearchProviderHandler.Search(ctx, in, out) } -func (h *searchProviderHandler) IndexSpace(ctx context.Context, in *IndexSpaceRequest, out *IndexSpaceResponse) error { - return h.SearchProviderHandler.IndexSpace(ctx, in, out) +func (h *searchProviderHandler) IndexSpace(ctx context.Context, stream server.Stream) error { + m := new(IndexSpaceRequest) + if err := stream.Recv(m); err != nil { + return err + } + return h.SearchProviderHandler.IndexSpace(ctx, m, &searchProviderIndexSpaceStream{stream}) +} + +type SearchProvider_IndexSpaceStream interface { + Context() context.Context + SendMsg(interface{}) error + RecvMsg(interface{}) error + Close() error + Send(*IndexSpaceResponse) error +} + +type searchProviderIndexSpaceStream struct { + stream server.Stream +} + +func (x *searchProviderIndexSpaceStream) Close() error { + return x.stream.Close() +} + +func (x *searchProviderIndexSpaceStream) Context() context.Context { + return x.stream.Context() +} + +func (x *searchProviderIndexSpaceStream) SendMsg(m interface{}) error { + return x.stream.Send(m) +} + +func (x *searchProviderIndexSpaceStream) RecvMsg(m interface{}) error { + return x.stream.Recv(m) +} + +func (x *searchProviderIndexSpaceStream) Send(m *IndexSpaceResponse) error { + return x.stream.Send(m) } // Api Endpoints for IndexProvider service diff --git a/protogen/gen/opencloud/services/search/v0/search.pb.web.go b/protogen/gen/opencloud/services/search/v0/search.pb.web.go deleted file mode 100644 index a6a5842fec..0000000000 --- a/protogen/gen/opencloud/services/search/v0/search.pb.web.go +++ /dev/null @@ -1,346 +0,0 @@ -// Code generated by protoc-gen-microweb. DO NOT EDIT. -// source: v0.proto - -package v0 - -import ( - "bytes" - "encoding/json" - "net/http" - - "github.com/go-chi/chi/v5" - "github.com/go-chi/render" - "github.com/golang/protobuf/jsonpb" - merrors "go-micro.dev/v4/errors" -) - -type webSearchProviderHandler struct { - r chi.Router - h SearchProviderHandler -} - -func (h *webSearchProviderHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - h.r.ServeHTTP(w, r) -} - -func (h *webSearchProviderHandler) Search(w http.ResponseWriter, r *http.Request) { - req := &SearchRequest{} - resp := &SearchResponse{} - - if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - http.Error(w, err.Error(), http.StatusPreconditionFailed) - return - } - - if err := h.h.Search( - r.Context(), - req, - resp, - ); err != nil { - if merr, ok := merrors.As(err); ok && merr.Code == http.StatusNotFound { - http.Error(w, err.Error(), http.StatusNotFound) - } else { - http.Error(w, err.Error(), http.StatusBadRequest) - } - return - } - - render.Status(r, http.StatusCreated) - render.JSON(w, r, resp) -} - -func (h *webSearchProviderHandler) IndexSpace(w http.ResponseWriter, r *http.Request) { - req := &IndexSpaceRequest{} - resp := &IndexSpaceResponse{} - - if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - http.Error(w, err.Error(), http.StatusPreconditionFailed) - return - } - - if err := h.h.IndexSpace( - r.Context(), - req, - resp, - ); err != nil { - if merr, ok := merrors.As(err); ok && merr.Code == http.StatusNotFound { - http.Error(w, err.Error(), http.StatusNotFound) - } else { - http.Error(w, err.Error(), http.StatusBadRequest) - } - return - } - - render.Status(r, http.StatusCreated) - render.JSON(w, r, resp) -} - -func RegisterSearchProviderWeb(r chi.Router, i SearchProviderHandler, middlewares ...func(http.Handler) http.Handler) { - handler := &webSearchProviderHandler{ - r: r, - h: i, - } - - r.MethodFunc("POST", "/api/v0/search/search", handler.Search) - r.MethodFunc("POST", "/api/v0/search/index-space", handler.IndexSpace) -} - -type webIndexProviderHandler struct { - r chi.Router - h IndexProviderHandler -} - -func (h *webIndexProviderHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { - h.r.ServeHTTP(w, r) -} - -func (h *webIndexProviderHandler) Search(w http.ResponseWriter, r *http.Request) { - req := &SearchIndexRequest{} - resp := &SearchIndexResponse{} - - if err := json.NewDecoder(r.Body).Decode(&req); err != nil { - http.Error(w, err.Error(), http.StatusPreconditionFailed) - return - } - - if err := h.h.Search( - r.Context(), - req, - resp, - ); err != nil { - if merr, ok := merrors.As(err); ok && merr.Code == http.StatusNotFound { - http.Error(w, err.Error(), http.StatusNotFound) - } else { - http.Error(w, err.Error(), http.StatusBadRequest) - } - return - } - - render.Status(r, http.StatusCreated) - render.JSON(w, r, resp) -} - -func RegisterIndexProviderWeb(r chi.Router, i IndexProviderHandler, middlewares ...func(http.Handler) http.Handler) { - handler := &webIndexProviderHandler{ - r: r, - h: i, - } - - r.MethodFunc("POST", "/api/v0/search/index/search", handler.Search) -} - -// SearchRequestJSONMarshaler describes the default jsonpb.Marshaler used by all -// instances of SearchRequest. This struct is safe to replace or modify but -// should not be done so concurrently. -var SearchRequestJSONMarshaler = new(jsonpb.Marshaler) - -// MarshalJSON satisfies the encoding/json Marshaler interface. This method -// uses the more correct jsonpb package to correctly marshal the message. -func (m *SearchRequest) MarshalJSON() ([]byte, error) { - if m == nil { - return json.Marshal(nil) - } - - buf := &bytes.Buffer{} - - if err := SearchRequestJSONMarshaler.Marshal(buf, m); err != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -var _ json.Marshaler = (*SearchRequest)(nil) - -// SearchRequestJSONUnmarshaler describes the default jsonpb.Unmarshaler used by all -// instances of SearchRequest. This struct is safe to replace or modify but -// should not be done so concurrently. -var SearchRequestJSONUnmarshaler = new(jsonpb.Unmarshaler) - -// UnmarshalJSON satisfies the encoding/json Unmarshaler interface. This method -// uses the more correct jsonpb package to correctly unmarshal the message. -func (m *SearchRequest) UnmarshalJSON(b []byte) error { - return SearchRequestJSONUnmarshaler.Unmarshal(bytes.NewReader(b), m) -} - -var _ json.Unmarshaler = (*SearchRequest)(nil) - -// SearchResponseJSONMarshaler describes the default jsonpb.Marshaler used by all -// instances of SearchResponse. This struct is safe to replace or modify but -// should not be done so concurrently. -var SearchResponseJSONMarshaler = new(jsonpb.Marshaler) - -// MarshalJSON satisfies the encoding/json Marshaler interface. This method -// uses the more correct jsonpb package to correctly marshal the message. -func (m *SearchResponse) MarshalJSON() ([]byte, error) { - if m == nil { - return json.Marshal(nil) - } - - buf := &bytes.Buffer{} - - if err := SearchResponseJSONMarshaler.Marshal(buf, m); err != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -var _ json.Marshaler = (*SearchResponse)(nil) - -// SearchResponseJSONUnmarshaler describes the default jsonpb.Unmarshaler used by all -// instances of SearchResponse. This struct is safe to replace or modify but -// should not be done so concurrently. -var SearchResponseJSONUnmarshaler = new(jsonpb.Unmarshaler) - -// UnmarshalJSON satisfies the encoding/json Unmarshaler interface. This method -// uses the more correct jsonpb package to correctly unmarshal the message. -func (m *SearchResponse) UnmarshalJSON(b []byte) error { - return SearchResponseJSONUnmarshaler.Unmarshal(bytes.NewReader(b), m) -} - -var _ json.Unmarshaler = (*SearchResponse)(nil) - -// SearchIndexRequestJSONMarshaler describes the default jsonpb.Marshaler used by all -// instances of SearchIndexRequest. This struct is safe to replace or modify but -// should not be done so concurrently. -var SearchIndexRequestJSONMarshaler = new(jsonpb.Marshaler) - -// MarshalJSON satisfies the encoding/json Marshaler interface. This method -// uses the more correct jsonpb package to correctly marshal the message. -func (m *SearchIndexRequest) MarshalJSON() ([]byte, error) { - if m == nil { - return json.Marshal(nil) - } - - buf := &bytes.Buffer{} - - if err := SearchIndexRequestJSONMarshaler.Marshal(buf, m); err != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -var _ json.Marshaler = (*SearchIndexRequest)(nil) - -// SearchIndexRequestJSONUnmarshaler describes the default jsonpb.Unmarshaler used by all -// instances of SearchIndexRequest. This struct is safe to replace or modify but -// should not be done so concurrently. -var SearchIndexRequestJSONUnmarshaler = new(jsonpb.Unmarshaler) - -// UnmarshalJSON satisfies the encoding/json Unmarshaler interface. This method -// uses the more correct jsonpb package to correctly unmarshal the message. -func (m *SearchIndexRequest) UnmarshalJSON(b []byte) error { - return SearchIndexRequestJSONUnmarshaler.Unmarshal(bytes.NewReader(b), m) -} - -var _ json.Unmarshaler = (*SearchIndexRequest)(nil) - -// SearchIndexResponseJSONMarshaler describes the default jsonpb.Marshaler used by all -// instances of SearchIndexResponse. This struct is safe to replace or modify but -// should not be done so concurrently. -var SearchIndexResponseJSONMarshaler = new(jsonpb.Marshaler) - -// MarshalJSON satisfies the encoding/json Marshaler interface. This method -// uses the more correct jsonpb package to correctly marshal the message. -func (m *SearchIndexResponse) MarshalJSON() ([]byte, error) { - if m == nil { - return json.Marshal(nil) - } - - buf := &bytes.Buffer{} - - if err := SearchIndexResponseJSONMarshaler.Marshal(buf, m); err != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -var _ json.Marshaler = (*SearchIndexResponse)(nil) - -// SearchIndexResponseJSONUnmarshaler describes the default jsonpb.Unmarshaler used by all -// instances of SearchIndexResponse. This struct is safe to replace or modify but -// should not be done so concurrently. -var SearchIndexResponseJSONUnmarshaler = new(jsonpb.Unmarshaler) - -// UnmarshalJSON satisfies the encoding/json Unmarshaler interface. This method -// uses the more correct jsonpb package to correctly unmarshal the message. -func (m *SearchIndexResponse) UnmarshalJSON(b []byte) error { - return SearchIndexResponseJSONUnmarshaler.Unmarshal(bytes.NewReader(b), m) -} - -var _ json.Unmarshaler = (*SearchIndexResponse)(nil) - -// IndexSpaceRequestJSONMarshaler describes the default jsonpb.Marshaler used by all -// instances of IndexSpaceRequest. This struct is safe to replace or modify but -// should not be done so concurrently. -var IndexSpaceRequestJSONMarshaler = new(jsonpb.Marshaler) - -// MarshalJSON satisfies the encoding/json Marshaler interface. This method -// uses the more correct jsonpb package to correctly marshal the message. -func (m *IndexSpaceRequest) MarshalJSON() ([]byte, error) { - if m == nil { - return json.Marshal(nil) - } - - buf := &bytes.Buffer{} - - if err := IndexSpaceRequestJSONMarshaler.Marshal(buf, m); err != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -var _ json.Marshaler = (*IndexSpaceRequest)(nil) - -// IndexSpaceRequestJSONUnmarshaler describes the default jsonpb.Unmarshaler used by all -// instances of IndexSpaceRequest. This struct is safe to replace or modify but -// should not be done so concurrently. -var IndexSpaceRequestJSONUnmarshaler = new(jsonpb.Unmarshaler) - -// UnmarshalJSON satisfies the encoding/json Unmarshaler interface. This method -// uses the more correct jsonpb package to correctly unmarshal the message. -func (m *IndexSpaceRequest) UnmarshalJSON(b []byte) error { - return IndexSpaceRequestJSONUnmarshaler.Unmarshal(bytes.NewReader(b), m) -} - -var _ json.Unmarshaler = (*IndexSpaceRequest)(nil) - -// IndexSpaceResponseJSONMarshaler describes the default jsonpb.Marshaler used by all -// instances of IndexSpaceResponse. This struct is safe to replace or modify but -// should not be done so concurrently. -var IndexSpaceResponseJSONMarshaler = new(jsonpb.Marshaler) - -// MarshalJSON satisfies the encoding/json Marshaler interface. This method -// uses the more correct jsonpb package to correctly marshal the message. -func (m *IndexSpaceResponse) MarshalJSON() ([]byte, error) { - if m == nil { - return json.Marshal(nil) - } - - buf := &bytes.Buffer{} - - if err := IndexSpaceResponseJSONMarshaler.Marshal(buf, m); err != nil { - return nil, err - } - - return buf.Bytes(), nil -} - -var _ json.Marshaler = (*IndexSpaceResponse)(nil) - -// IndexSpaceResponseJSONUnmarshaler describes the default jsonpb.Unmarshaler used by all -// instances of IndexSpaceResponse. This struct is safe to replace or modify but -// should not be done so concurrently. -var IndexSpaceResponseJSONUnmarshaler = new(jsonpb.Unmarshaler) - -// UnmarshalJSON satisfies the encoding/json Unmarshaler interface. This method -// uses the more correct jsonpb package to correctly unmarshal the message. -func (m *IndexSpaceResponse) UnmarshalJSON(b []byte) error { - return IndexSpaceResponseJSONUnmarshaler.Unmarshal(bytes.NewReader(b), m) -} - -var _ json.Unmarshaler = (*IndexSpaceResponse)(nil) diff --git a/protogen/gen/opencloud/services/search/v0/search.swagger.json b/protogen/gen/opencloud/services/search/v0/search.swagger.json index a8d7b9bd8f..b54877badc 100644 --- a/protogen/gen/opencloud/services/search/v0/search.swagger.json +++ b/protogen/gen/opencloud/services/search/v0/search.swagger.json @@ -34,12 +34,22 @@ "paths": { "/api/v0/search/index-space": { "post": { + "summary": "IndexSpace (re)indexes one or all spaces. The response is streamed, sending\nprogress information after each space has been indexed.", "operationId": "SearchProvider_IndexSpace", "responses": { "200": { - "description": "A successful response.", + "description": "A successful response.(streaming responses)", "schema": { - "$ref": "#/definitions/v0IndexSpaceResponse" + "type": "object", + "properties": { + "result": { + "$ref": "#/definitions/v0IndexSpaceResponse" + }, + "error": { + "$ref": "#/definitions/rpcStatus" + } + }, + "title": "Stream result of v0IndexSpaceResponse" } }, "default": { @@ -336,7 +346,31 @@ } }, "v0IndexSpaceResponse": { - "type": "object" + "type": "object", + "properties": { + "spaceId": { + "type": "string", + "description": "The id of the space that has just been indexed." + }, + "spaceDuration": { + "type": "string", + "description": "The duration it took to index this space." + }, + "indexedSpaces": { + "type": "string", + "format": "int64", + "description": "The number of spaces that have been indexed so far." + }, + "totalSpaces": { + "type": "string", + "format": "int64", + "description": "The total number of spaces that are being indexed." + }, + "error": { + "type": "string", + "description": "Contains an error message in case indexing this particular space failed." + } + } }, "v0Match": { "type": "object", diff --git a/protogen/gen/opencloud/services/search/v0/search_grpc.pb.go b/protogen/gen/opencloud/services/search/v0/search_grpc.pb.go index cb4b237311..417a235f5b 100644 --- a/protogen/gen/opencloud/services/search/v0/search_grpc.pb.go +++ b/protogen/gen/opencloud/services/search/v0/search_grpc.pb.go @@ -28,7 +28,9 @@ const ( // For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream. type SearchProviderClient interface { Search(ctx context.Context, in *SearchRequest, opts ...grpc.CallOption) (*SearchResponse, error) - IndexSpace(ctx context.Context, in *IndexSpaceRequest, opts ...grpc.CallOption) (*IndexSpaceResponse, error) + // IndexSpace (re)indexes one or all spaces. The response is streamed, sending + // progress information after each space has been indexed. + IndexSpace(ctx context.Context, in *IndexSpaceRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[IndexSpaceResponse], error) } type searchProviderClient struct { @@ -49,22 +51,33 @@ func (c *searchProviderClient) Search(ctx context.Context, in *SearchRequest, op return out, nil } -func (c *searchProviderClient) IndexSpace(ctx context.Context, in *IndexSpaceRequest, opts ...grpc.CallOption) (*IndexSpaceResponse, error) { +func (c *searchProviderClient) IndexSpace(ctx context.Context, in *IndexSpaceRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[IndexSpaceResponse], error) { cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...) - out := new(IndexSpaceResponse) - err := c.cc.Invoke(ctx, SearchProvider_IndexSpace_FullMethodName, in, out, cOpts...) + stream, err := c.cc.NewStream(ctx, &SearchProvider_ServiceDesc.Streams[0], SearchProvider_IndexSpace_FullMethodName, cOpts...) if err != nil { return nil, err } - return out, nil + x := &grpc.GenericClientStream[IndexSpaceRequest, IndexSpaceResponse]{ClientStream: stream} + if err := x.ClientStream.SendMsg(in); err != nil { + return nil, err + } + if err := x.ClientStream.CloseSend(); err != nil { + return nil, err + } + return x, nil } +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type SearchProvider_IndexSpaceClient = grpc.ServerStreamingClient[IndexSpaceResponse] + // SearchProviderServer is the server API for SearchProvider service. // All implementations must embed UnimplementedSearchProviderServer // for forward compatibility. type SearchProviderServer interface { Search(context.Context, *SearchRequest) (*SearchResponse, error) - IndexSpace(context.Context, *IndexSpaceRequest) (*IndexSpaceResponse, error) + // IndexSpace (re)indexes one or all spaces. The response is streamed, sending + // progress information after each space has been indexed. + IndexSpace(*IndexSpaceRequest, grpc.ServerStreamingServer[IndexSpaceResponse]) error mustEmbedUnimplementedSearchProviderServer() } @@ -78,8 +91,8 @@ type UnimplementedSearchProviderServer struct{} func (UnimplementedSearchProviderServer) Search(context.Context, *SearchRequest) (*SearchResponse, error) { return nil, status.Error(codes.Unimplemented, "method Search not implemented") } -func (UnimplementedSearchProviderServer) IndexSpace(context.Context, *IndexSpaceRequest) (*IndexSpaceResponse, error) { - return nil, status.Error(codes.Unimplemented, "method IndexSpace not implemented") +func (UnimplementedSearchProviderServer) IndexSpace(*IndexSpaceRequest, grpc.ServerStreamingServer[IndexSpaceResponse]) error { + return status.Error(codes.Unimplemented, "method IndexSpace not implemented") } func (UnimplementedSearchProviderServer) mustEmbedUnimplementedSearchProviderServer() {} func (UnimplementedSearchProviderServer) testEmbeddedByValue() {} @@ -120,24 +133,17 @@ func _SearchProvider_Search_Handler(srv interface{}, ctx context.Context, dec fu return interceptor(ctx, in, info, handler) } -func _SearchProvider_IndexSpace_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { - in := new(IndexSpaceRequest) - if err := dec(in); err != nil { - return nil, err +func _SearchProvider_IndexSpace_Handler(srv interface{}, stream grpc.ServerStream) error { + m := new(IndexSpaceRequest) + if err := stream.RecvMsg(m); err != nil { + return err } - if interceptor == nil { - return srv.(SearchProviderServer).IndexSpace(ctx, in) - } - info := &grpc.UnaryServerInfo{ - Server: srv, - FullMethod: SearchProvider_IndexSpace_FullMethodName, - } - handler := func(ctx context.Context, req interface{}) (interface{}, error) { - return srv.(SearchProviderServer).IndexSpace(ctx, req.(*IndexSpaceRequest)) - } - return interceptor(ctx, in, info, handler) + return srv.(SearchProviderServer).IndexSpace(m, &grpc.GenericServerStream[IndexSpaceRequest, IndexSpaceResponse]{ServerStream: stream}) } +// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name. +type SearchProvider_IndexSpaceServer = grpc.ServerStreamingServer[IndexSpaceResponse] + // SearchProvider_ServiceDesc is the grpc.ServiceDesc for SearchProvider service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -149,12 +155,14 @@ var SearchProvider_ServiceDesc = grpc.ServiceDesc{ MethodName: "Search", Handler: _SearchProvider_Search_Handler, }, + }, + Streams: []grpc.StreamDesc{ { - MethodName: "IndexSpace", - Handler: _SearchProvider_IndexSpace_Handler, + StreamName: "IndexSpace", + Handler: _SearchProvider_IndexSpace_Handler, + ServerStreams: true, }, }, - Streams: []grpc.StreamDesc{}, Metadata: "opencloud/services/search/v0/search.proto", } diff --git a/protogen/proto/buf.gen.yaml b/protogen/proto/buf.gen.yaml index af767d4261..9887a132fc 100644 --- a/protogen/proto/buf.gen.yaml +++ b/protogen/proto/buf.gen.yaml @@ -31,7 +31,9 @@ plugins: opencloud.services.eventhistory.v0;\ opencloud.messages.eventhistory.v0;\ opencloud.services.policies.v0;\ - opencloud.messages.policies.v0" + opencloud.messages.policies.v0;\ + opencloud.services.search.v0;\ + opencloud.messages.search.v0" - name: openapiv2 path: ../../.bingo/protoc-gen-openapiv2 diff --git a/protogen/proto/opencloud/services/search/v0/search.proto b/protogen/proto/opencloud/services/search/v0/search.proto index 25b085d660..9b1d3cbfc6 100644 --- a/protogen/proto/opencloud/services/search/v0/search.proto +++ b/protogen/proto/opencloud/services/search/v0/search.proto @@ -9,6 +9,7 @@ import "protoc-gen-openapiv2/options/annotations.proto"; import "google/api/field_behavior.proto"; import "google/api/annotations.proto"; import "google/protobuf/field_mask.proto"; +import "google/protobuf/duration.proto"; option (grpc.gateway.protoc_gen_openapiv2.options.openapiv2_swagger) = { info: { @@ -41,7 +42,9 @@ service SearchProvider { body: "*" }; }; - rpc IndexSpace(IndexSpaceRequest) returns (IndexSpaceResponse) { + // IndexSpace (re)indexes one or all spaces. The response is streamed, sending + // progress information after each space has been indexed. + rpc IndexSpace(IndexSpaceRequest) returns (stream IndexSpaceResponse) { option (google.api.http) = { post: "/api/v0/search/index-space", body: "*" @@ -108,4 +111,14 @@ message IndexSpaceRequest { } message IndexSpaceResponse { + // The id of the space that has just been indexed. + string space_id = 1; + // The duration it took to index this space. + google.protobuf.Duration space_duration = 2; + // The number of spaces that have been indexed so far. + int64 indexed_spaces = 3; + // The total number of spaces that are being indexed. + int64 total_spaces = 4; + // Contains an error message in case indexing this particular space failed. + string error = 5; } diff --git a/services/search/pkg/command/index.go b/services/search/pkg/command/index.go index 3951ee6fd3..30ea29cba8 100644 --- a/services/search/pkg/command/index.go +++ b/services/search/pkg/command/index.go @@ -5,6 +5,10 @@ import ( "crypto/tls" "errors" "fmt" + "io" + "os" + "os/signal" + "syscall" "time" "github.com/opencloud-eu/opencloud/pkg/config/configlog" @@ -24,6 +28,9 @@ func Index(cfg *config.Config) *cobra.Command { Use: "index", Short: "index the files for one one more users", Aliases: []string{"i"}, + // Don't print the usage on runtime errors (e.g. a cancelled request); + // usage is only helpful for flag/argument errors. + SilenceUsage: true, PreRunE: func(cmd *cobra.Command, args []string) error { return configlog.ReturnFatal(parser.ParseConfig(cfg)) }, @@ -54,17 +61,46 @@ func Index(cfg *config.Config) *cobra.Command { c := searchsvc.NewSearchProviderClient(conn) - ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) + // Cancel the operation when the user presses Ctrl+C (SIGINT) or the + // process receives SIGTERM. The cancellation propagates over the + // gRPC stream so the server stops indexing. + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + defer stop() + ctx, cancel := context.WithTimeout(ctx, 10*time.Minute) defer cancel() - _, err = c.IndexSpace(ctx, &searchsvc.IndexSpaceRequest{ + stream, err := c.IndexSpace(ctx, &searchsvc.IndexSpaceRequest{ SpaceId: spaceFlag, ForceReindex: forceRescanFlag, }) if err != nil { - fmt.Println("failed to index space: " + err.Error()) return err } + + for { + progress, err := stream.Recv() + if errors.Is(err, io.EOF) { + break + } + if err != nil { + // The user aborted (Ctrl+C / SIGTERM). Exit quietly instead + // of dumping a "context canceled" gRPC error. + if errors.Is(ctx.Err(), context.Canceled) { + fmt.Println("aborted, indexing has been stopped") + return nil + } + return err + } + + if progress.GetError() != "" { + fmt.Printf("[%d/%d] failed to index space %s: %s\n", + progress.GetIndexedSpaces(), progress.GetTotalSpaces(), progress.GetSpaceId(), progress.GetError()) + continue + } + + fmt.Printf("[%d/%d] indexed space %s in %s\n", + progress.GetIndexedSpaces(), progress.GetTotalSpaces(), progress.GetSpaceId(), progress.GetSpaceDuration().AsDuration()) + } return nil }, } diff --git a/services/search/pkg/service/grpc/v0/service.go b/services/search/pkg/service/grpc/v0/service.go index f382159c31..6ebfc558a3 100644 --- a/services/search/pkg/service/grpc/v0/service.go +++ b/services/search/pkg/service/grpc/v0/service.go @@ -4,6 +4,7 @@ import ( "context" "errors" "fmt" + "sync" "time" gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" @@ -21,6 +22,7 @@ import ( "go-micro.dev/v4/metadata" "golang.org/x/sync/errgroup" grpcmetadata "google.golang.org/grpc/metadata" + "google.golang.org/protobuf/types/known/durationpb" "github.com/opencloud-eu/opencloud/pkg/log" v0 "github.com/opencloud-eu/opencloud/protogen/gen/opencloud/messages/search/v0" @@ -119,10 +121,27 @@ func (s Service) Search(ctx context.Context, in *searchsvc.SearchRequest, out *s return nil } -// IndexSpace (re)indexes all resources of a given space. -func (s Service) IndexSpace(_ context.Context, in *searchsvc.IndexSpaceRequest, _ *searchsvc.IndexSpaceResponse) error { +// IndexSpace (re)indexes all resources of a given space. Progress information is +// streamed back to the caller after every space that has been indexed. +func (s Service) IndexSpace(_ context.Context, in *searchsvc.IndexSpaceRequest, stream searchsvc.SearchProvider_IndexSpaceStream) error { + // Use the stream's context so that indexing stops when the client cancels + // the request or disconnects. + ctx := stream.Context() + if in.GetSpaceId() != "" { - return s.searcher.IndexSpace(&provider.StorageSpaceId{OpaqueId: in.GetSpaceId()}, in.GetForceReindex()) + err := s.searcher.IndexSpace(&provider.StorageSpaceId{OpaqueId: in.GetSpaceId()}, in.GetForceReindex()) + resp := &searchsvc.IndexSpaceResponse{ + SpaceId: in.GetSpaceId(), + IndexedSpaces: 1, + TotalSpaces: 1, + } + if err != nil { + resp.Error = err.Error() + } + if sendErr := stream.Send(resp); sendErr != nil { + return sendErr + } + return err } // index all spaces instead @@ -131,7 +150,7 @@ func (s Service) IndexSpace(_ context.Context, in *searchsvc.IndexSpaceRequest, return err } - ctx, err := utils.GetServiceUserContext(s.cfg.ServiceAccount.ServiceAccountID, gwc, s.cfg.ServiceAccount.ServiceAccountSecret) + ctx, err = utils.GetServiceUserContextWithContext(ctx, gwc, s.cfg.ServiceAccount.ServiceAccountID, s.cfg.ServiceAccount.ServiceAccountSecret) if err != nil { return err } @@ -145,24 +164,59 @@ func (s Service) IndexSpace(_ context.Context, in *searchsvc.IndexSpaceRequest, return errors.New(resp.GetStatus().GetMessage()) } + spaces := resp.GetStorageSpaces() + totalSpaces := int64(len(spaces)) + // Index all spaces concurrently, limited to a configurable number of spaces - // being reindexed at the same time. + // being reindexed at the same time. The errgroup context is cancelled as + // soon as the client goes away or a stream send fails, so the remaining + // goroutines stop indexing early. concurrency := max(s.cfg.ReindexMaxConcurrency, 1) - var g errgroup.Group + g, ctx := errgroup.WithContext(ctx) g.SetLimit(concurrency) - for _, space := range resp.GetStorageSpaces() { + // Serialize progress updates on the stream, as gRPC streams must not be + // written to from multiple goroutines concurrently. + var ( + mu sync.Mutex + indexedCount int64 + ) + + for _, space := range spaces { + // Stop early if the client cancelled the request. + if err := ctx.Err(); err != nil { + return err + } g.Go(func() error { s.log.Info().Str("space_id", space.GetId().GetOpaqueId()).Msg("indexing space") + t := time.Now() - err := s.searcher.IndexSpace(space.GetId(), in.GetForceReindex()) - if err != nil { - s.log.Error().Err(err).Str("space_id", space.GetId().GetOpaqueId()).Msg("failed to index space") + indexErr := s.searcher.IndexSpace(space.GetId(), in.GetForceReindex()) + if indexErr != nil { + s.log.Error().Err(indexErr).Str("space_id", space.GetId().GetOpaqueId()).Msg("failed to index space") } else { s.log.Info().Str("space_id", space.GetId().GetOpaqueId()).Msg("finished indexing space") } - return nil + mu.Lock() + defer mu.Unlock() + + // Don't try to send progress on an already cancelled stream. + if err := ctx.Err(); err != nil { + return err + } + + indexedCount++ + progress := &searchsvc.IndexSpaceResponse{ + SpaceId: space.GetId().GetOpaqueId(), + IndexedSpaces: indexedCount, + TotalSpaces: totalSpaces, + SpaceDuration: durationpb.New(time.Since(t)), + } + if indexErr != nil { + progress.Error = indexErr.Error() + } + return stream.Send(progress) }) } From a82b6223aa1e1a4638f467f481fb67b6bb6cac7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Fri, 31 Jul 2026 15:53:57 +0200 Subject: [PATCH 3/4] Remove the SilenceUsage flag again It will be obsolete once #3140 has been merged --- services/search/pkg/command/index.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/services/search/pkg/command/index.go b/services/search/pkg/command/index.go index 30ea29cba8..ad1a71b0fe 100644 --- a/services/search/pkg/command/index.go +++ b/services/search/pkg/command/index.go @@ -28,9 +28,6 @@ func Index(cfg *config.Config) *cobra.Command { Use: "index", Short: "index the files for one one more users", Aliases: []string{"i"}, - // Don't print the usage on runtime errors (e.g. a cancelled request); - // usage is only helpful for flag/argument errors. - SilenceUsage: true, PreRunE: func(cmd *cobra.Command, args []string) error { return configlog.ReturnFatal(parser.ParseConfig(cfg)) }, From 2eb1fe069c1edb528c4637ef6640926bf928b018 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Duffeck?= Date: Fri, 31 Jul 2026 16:07:18 +0200 Subject: [PATCH 4/4] Add a --concurrency flag to the index command It controls the number of spaces that are indexed in parallel. The max concurrency configured in the server is still considered. --- .../opencloud/services/search/v0/search.pb.go | 157 ++++++++++-------- .../services/search/v0/search.swagger.json | 4 + .../opencloud/services/search/v0/search.proto | 1 + services/search/pkg/command/index.go | 11 ++ .../search/pkg/service/grpc/v0/service.go | 2 + 5 files changed, 102 insertions(+), 73 deletions(-) diff --git a/protogen/gen/opencloud/services/search/v0/search.pb.go b/protogen/gen/opencloud/services/search/v0/search.pb.go index 144662c81b..1346c98197 100644 --- a/protogen/gen/opencloud/services/search/v0/search.pb.go +++ b/protogen/gen/opencloud/services/search/v0/search.pb.go @@ -311,6 +311,7 @@ type IndexSpaceRequest struct { SpaceId string `protobuf:"bytes,1,opt,name=space_id,json=spaceId,proto3" json:"space_id,omitempty"` UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"` ForceReindex bool `protobuf:"varint,3,opt,name=force_reindex,json=forceReindex,proto3" json:"force_reindex,omitempty"` + Concurrency int32 `protobuf:"varint,4,opt,name=concurrency,proto3" json:"concurrency,omitempty"` } func (x *IndexSpaceRequest) Reset() { @@ -366,6 +367,13 @@ func (x *IndexSpaceRequest) GetForceReindex() bool { return false } +func (x *IndexSpaceRequest) GetConcurrency() int32 { + if x != nil { + return x.Concurrency + } + return 0 +} + type IndexSpaceResponse struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -514,80 +522,83 @@ var file_opencloud_services_search_v0_search_proto_rawDesc = []byte{ 0x74, 0x50, 0x61, 0x67, 0x65, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x6d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x4d, 0x61, 0x74, 0x63, 0x68, 0x65, 0x73, 0x22, - 0x6c, 0x0a, 0x11, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, - 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x6f, 0x72, 0x63, - 0x65, 0x5f, 0x72, 0x65, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, - 0x0c, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x22, 0xd1, 0x01, - 0x0a, 0x12, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, - 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, - 0x40, 0x0a, 0x0e, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, - 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x0d, 0x73, 0x70, 0x61, 0x63, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x5f, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x69, 0x6e, 0x64, 0x65, 0x78, - 0x65, 0x64, 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x6f, 0x74, 0x61, - 0x6c, 0x5f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, - 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x53, 0x70, 0x61, 0x63, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, - 0x72, 0x32, 0xb3, 0x02, 0x0a, 0x0e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x72, 0x6f, 0x76, - 0x69, 0x64, 0x65, 0x72, 0x12, 0x85, 0x01, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, - 0x2b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, - 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x53, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x53, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, - 0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x73, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x98, 0x01, 0x0a, - 0x0a, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x12, 0x2f, 0x2e, 0x6f, 0x70, - 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, - 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, - 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x6f, - 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, - 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x3a, 0x01, 0x2a, 0x22, 0x1a, 0x2f, 0x61, 0x70, 0x69, 0x2f, - 0x76, 0x30, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2d, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x30, 0x01, 0x32, 0xa7, 0x01, 0x0a, 0x0d, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x95, 0x01, 0x0a, 0x06, 0x53, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x12, 0x30, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x94, 0x01, 0x0a, 0x11, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, + 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, + 0x12, 0x17, 0x0a, 0x07, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x75, 0x73, 0x65, 0x72, 0x49, 0x64, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x6f, 0x72, + 0x63, 0x65, 0x5f, 0x72, 0x65, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0c, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x52, 0x65, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x12, 0x26, + 0x0a, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x18, 0x04, 0x20, + 0x01, 0x28, 0x05, 0x42, 0x04, 0xe2, 0x41, 0x01, 0x01, 0x52, 0x0b, 0x63, 0x6f, 0x6e, 0x63, 0x75, + 0x72, 0x72, 0x65, 0x6e, 0x63, 0x79, 0x22, 0xd1, 0x01, 0x0a, 0x12, 0x49, 0x6e, 0x64, 0x65, 0x78, + 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, + 0x08, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x07, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x40, 0x0a, 0x0e, 0x73, 0x70, 0x61, 0x63, + 0x65, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, + 0x32, 0x19, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x75, 0x66, 0x2e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x0d, 0x73, 0x70, 0x61, + 0x63, 0x65, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x65, 0x64, 0x5f, 0x73, 0x70, 0x61, 0x63, 0x65, 0x73, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x0d, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x65, 0x64, 0x53, 0x70, 0x61, 0x63, 0x65, + 0x73, 0x12, 0x21, 0x0a, 0x0c, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x53, 0x70, + 0x61, 0x63, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x32, 0xb3, 0x02, 0x0a, 0x0e, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x12, 0x85, 0x01, + 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x2b, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, + 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, + 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x2c, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x52, 0x65, 0x73, 0x70, 0x6f, + 0x6e, 0x73, 0x65, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, + 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x73, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x98, 0x01, 0x0a, 0x0a, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, + 0x70, 0x61, 0x63, 0x65, 0x12, 0x2f, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, - 0x2e, 0x76, 0x30, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, - 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x31, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, - 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, - 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x64, 0x65, - 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, - 0x20, 0x3a, 0x01, 0x2a, 0x22, 0x1b, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x73, 0x65, - 0x61, 0x72, 0x63, 0x68, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, - 0x68, 0x42, 0xf2, 0x02, 0x5a, 0x4a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, 0x65, 0x75, 0x2f, 0x6f, 0x70, - 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x67, 0x65, 0x6e, - 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x73, - 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x76, 0x30, - 0x92, 0x41, 0xa2, 0x02, 0x12, 0xb7, 0x01, 0x0a, 0x10, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6c, 0x6f, - 0x75, 0x64, 0x20, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x22, 0x51, 0x0a, 0x0e, 0x4f, 0x70, 0x65, - 0x6e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x20, 0x47, 0x6d, 0x62, 0x48, 0x12, 0x29, 0x68, 0x74, 0x74, - 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, - 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, 0x65, 0x75, 0x2f, 0x6f, 0x70, 0x65, - 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x1a, 0x14, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x40, - 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x65, 0x75, 0x2a, 0x49, 0x0a, 0x0a, - 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2d, 0x32, 0x2e, 0x30, 0x12, 0x3b, 0x68, 0x74, 0x74, 0x70, - 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, - 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2d, 0x65, 0x75, 0x2f, 0x6f, 0x70, 0x65, 0x6e, - 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x62, 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, - 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, 0x32, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x2a, 0x02, - 0x01, 0x02, 0x32, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, - 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x10, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x72, 0x3e, 0x0a, 0x10, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, - 0x70, 0x65, 0x72, 0x20, 0x4d, 0x61, 0x6e, 0x75, 0x61, 0x6c, 0x12, 0x2a, 0x68, 0x74, 0x74, 0x70, - 0x73, 0x3a, 0x2f, 0x2f, 0x64, 0x6f, 0x63, 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, - 0x75, 0x64, 0x2e, 0x65, 0x75, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73, - 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x76, 0x30, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x30, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, + 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x70, 0x61, 0x63, 0x65, 0x52, + 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x25, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1f, 0x3a, + 0x01, 0x2a, 0x22, 0x1a, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x73, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x2f, 0x69, 0x6e, 0x64, 0x65, 0x78, 0x2d, 0x73, 0x70, 0x61, 0x63, 0x65, 0x30, 0x01, + 0x32, 0xa7, 0x01, 0x0a, 0x0d, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, + 0x65, 0x72, 0x12, 0x95, 0x01, 0x0a, 0x06, 0x53, 0x65, 0x61, 0x72, 0x63, 0x68, 0x12, 0x30, 0x2e, + 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x53, 0x65, 0x61, + 0x72, 0x63, 0x68, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, + 0x31, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x73, 0x2e, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2e, 0x76, 0x30, 0x2e, 0x53, + 0x65, 0x61, 0x72, 0x63, 0x68, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x26, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x20, 0x3a, 0x01, 0x2a, 0x22, 0x1b, 0x2f, + 0x61, 0x70, 0x69, 0x2f, 0x76, 0x30, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x69, 0x6e, + 0x64, 0x65, 0x78, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x42, 0xf2, 0x02, 0x5a, 0x4a, 0x67, + 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, + 0x6f, 0x75, 0x64, 0x2d, 0x65, 0x75, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x6f, 0x70, + 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2f, + 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x76, 0x30, 0x92, 0x41, 0xa2, 0x02, 0x12, 0xb7, 0x01, + 0x0a, 0x10, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x20, 0x73, 0x65, 0x61, 0x72, + 0x63, 0x68, 0x22, 0x51, 0x0a, 0x0e, 0x4f, 0x70, 0x65, 0x6e, 0x43, 0x6c, 0x6f, 0x75, 0x64, 0x20, + 0x47, 0x6d, 0x62, 0x48, 0x12, 0x29, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, + 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, + 0x75, 0x64, 0x2d, 0x65, 0x75, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x1a, + 0x14, 0x73, 0x75, 0x70, 0x70, 0x6f, 0x72, 0x74, 0x40, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, + 0x75, 0x64, 0x2e, 0x65, 0x75, 0x2a, 0x49, 0x0a, 0x0a, 0x41, 0x70, 0x61, 0x63, 0x68, 0x65, 0x2d, + 0x32, 0x2e, 0x30, 0x12, 0x3b, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, + 0x64, 0x2d, 0x65, 0x75, 0x2f, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2f, 0x62, + 0x6c, 0x6f, 0x62, 0x2f, 0x6d, 0x61, 0x69, 0x6e, 0x2f, 0x4c, 0x49, 0x43, 0x45, 0x4e, 0x53, 0x45, + 0x32, 0x05, 0x31, 0x2e, 0x30, 0x2e, 0x30, 0x2a, 0x02, 0x01, 0x02, 0x32, 0x10, 0x61, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x3a, 0x10, 0x61, + 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2f, 0x6a, 0x73, 0x6f, 0x6e, 0x72, + 0x3e, 0x0a, 0x10, 0x44, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x72, 0x20, 0x4d, 0x61, 0x6e, + 0x75, 0x61, 0x6c, 0x12, 0x2a, 0x68, 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x64, 0x6f, 0x63, + 0x73, 0x2e, 0x6f, 0x70, 0x65, 0x6e, 0x63, 0x6c, 0x6f, 0x75, 0x64, 0x2e, 0x65, 0x75, 0x2f, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x73, 0x2f, 0x73, 0x65, 0x61, 0x72, 0x63, 0x68, 0x2f, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/protogen/gen/opencloud/services/search/v0/search.swagger.json b/protogen/gen/opencloud/services/search/v0/search.swagger.json index b54877badc..f726ca5fe5 100644 --- a/protogen/gen/opencloud/services/search/v0/search.swagger.json +++ b/protogen/gen/opencloud/services/search/v0/search.swagger.json @@ -342,6 +342,10 @@ }, "forceReindex": { "type": "boolean" + }, + "concurrency": { + "type": "integer", + "format": "int32" } } }, diff --git a/protogen/proto/opencloud/services/search/v0/search.proto b/protogen/proto/opencloud/services/search/v0/search.proto index 9b1d3cbfc6..62b4b31436 100644 --- a/protogen/proto/opencloud/services/search/v0/search.proto +++ b/protogen/proto/opencloud/services/search/v0/search.proto @@ -108,6 +108,7 @@ message IndexSpaceRequest { string space_id = 1; string user_id = 2; bool force_reindex = 3; + int32 concurrency = 4 [(google.api.field_behavior) = OPTIONAL]; } message IndexSpaceResponse { diff --git a/services/search/pkg/command/index.go b/services/search/pkg/command/index.go index ad1a71b0fe..f56b2d1888 100644 --- a/services/search/pkg/command/index.go +++ b/services/search/pkg/command/index.go @@ -37,9 +37,14 @@ func Index(cfg *config.Config) *cobra.Command { forceRescanFlag, _ := cmd.Flags().GetBool("force-rescan") endpointFlag, _ := cmd.Flags().GetString("endpoint") insecureFlag, _ := cmd.Flags().GetBool("insecure") + concurrencyFlag, _ := cmd.Flags().GetInt("concurrency") + if spaceFlag == "" && !allSpacesFlag { return errors.New("either --space or --all-spaces is required") } + if int(concurrencyFlag) > cfg.ReindexMaxConcurrency { + return fmt.Errorf("concurrency %d exceeds max allowed %d", concurrencyFlag, cfg.ReindexMaxConcurrency) + } var dialOpts []grpc.DialOption if cfg.GRPCClientTLS.Mode == "insecure" || insecureFlag { @@ -69,6 +74,7 @@ func Index(cfg *config.Config) *cobra.Command { stream, err := c.IndexSpace(ctx, &searchsvc.IndexSpaceRequest{ SpaceId: spaceFlag, ForceReindex: forceRescanFlag, + Concurrency: int32(concurrencyFlag), }) if err != nil { return err @@ -127,6 +133,11 @@ func Index(cfg *config.Config) *cobra.Command { false, "disable TLS for the gRPC connection.", ) + indexCmd.Flags().Int( + "concurrency", + 3, + "the number of concurrent indexing operations.", + ) return indexCmd } diff --git a/services/search/pkg/service/grpc/v0/service.go b/services/search/pkg/service/grpc/v0/service.go index 6ebfc558a3..6cb258ee43 100644 --- a/services/search/pkg/service/grpc/v0/service.go +++ b/services/search/pkg/service/grpc/v0/service.go @@ -172,6 +172,8 @@ func (s Service) IndexSpace(_ context.Context, in *searchsvc.IndexSpaceRequest, // soon as the client goes away or a stream send fails, so the remaining // goroutines stop indexing early. concurrency := max(s.cfg.ReindexMaxConcurrency, 1) + concurrency = min(concurrency, int(in.GetConcurrency())) + g, ctx := errgroup.WithContext(ctx) g.SetLimit(concurrency)