mirror of
https://github.com/garethgeorge/backrest.git
synced 2026-08-27 19:36:29 +00:00
feat: implement 'run command' button to execute arbitrary restic commands in a repo
This commit is contained in:
+432
-295
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,230 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.32.0
|
||||
// protoc (unknown)
|
||||
// source: v1/hub.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
_ "github.com/garethgeorge/backrest/gen/go/types"
|
||||
_ "google.golang.org/genproto/googleapis/api/annotations"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type GetInstancesResponse struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Instances []*Instance `protobuf:"bytes,1,rep,name=instances,proto3" json:"instances,omitempty"`
|
||||
}
|
||||
|
||||
func (x *GetInstancesResponse) Reset() {
|
||||
*x = GetInstancesResponse{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_v1_hub_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *GetInstancesResponse) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*GetInstancesResponse) ProtoMessage() {}
|
||||
|
||||
func (x *GetInstancesResponse) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_v1_hub_proto_msgTypes[0]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use GetInstancesResponse.ProtoReflect.Descriptor instead.
|
||||
func (*GetInstancesResponse) Descriptor() ([]byte, []int) {
|
||||
return file_v1_hub_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *GetInstancesResponse) GetInstances() []*Instance {
|
||||
if x != nil {
|
||||
return x.Instances
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Instance struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
|
||||
}
|
||||
|
||||
func (x *Instance) Reset() {
|
||||
*x = Instance{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_v1_hub_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *Instance) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Instance) ProtoMessage() {}
|
||||
|
||||
func (x *Instance) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_v1_hub_proto_msgTypes[1]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Instance.ProtoReflect.Descriptor instead.
|
||||
func (*Instance) Descriptor() ([]byte, []int) {
|
||||
return file_v1_hub_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *Instance) GetId() string {
|
||||
if x != nil {
|
||||
return x.Id
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_v1_hub_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_v1_hub_proto_rawDesc = []byte{
|
||||
0x0a, 0x0c, 0x76, 0x31, 0x2f, 0x68, 0x75, 0x62, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x02,
|
||||
0x76, 0x31, 0x1a, 0x0f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x1a, 0x0f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x69, 0x63, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x13, 0x76, 0x31, 0x2f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
|
||||
0x6f, 0x6e, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x11, 0x74, 0x79, 0x70, 0x65, 0x73,
|
||||
0x2f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1b, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x65, 0x6d,
|
||||
0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1c, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||
0x65, 0x2f, 0x61, 0x70, 0x69, 0x2f, 0x61, 0x6e, 0x6e, 0x6f, 0x74, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x42, 0x0a, 0x14, 0x47, 0x65, 0x74, 0x49, 0x6e,
|
||||
0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12,
|
||||
0x2a, 0x0a, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03,
|
||||
0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x76, 0x31, 0x2e, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65,
|
||||
0x52, 0x09, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x22, 0x1a, 0x0a, 0x08, 0x49,
|
||||
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20,
|
||||
0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x32, 0x49, 0x0a, 0x03, 0x48, 0x75, 0x62, 0x12, 0x42,
|
||||
0x0a, 0x0c, 0x47, 0x65, 0x74, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x12, 0x16,
|
||||
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
|
||||
0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x18, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x49,
|
||||
0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x22, 0x00, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x2f, 0x67, 0x61, 0x72, 0x65, 0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x62, 0x61,
|
||||
0x63, 0x6b, 0x72, 0x65, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31,
|
||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
file_v1_hub_proto_rawDescOnce sync.Once
|
||||
file_v1_hub_proto_rawDescData = file_v1_hub_proto_rawDesc
|
||||
)
|
||||
|
||||
func file_v1_hub_proto_rawDescGZIP() []byte {
|
||||
file_v1_hub_proto_rawDescOnce.Do(func() {
|
||||
file_v1_hub_proto_rawDescData = protoimpl.X.CompressGZIP(file_v1_hub_proto_rawDescData)
|
||||
})
|
||||
return file_v1_hub_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_v1_hub_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||
var file_v1_hub_proto_goTypes = []interface{}{
|
||||
(*GetInstancesResponse)(nil), // 0: v1.GetInstancesResponse
|
||||
(*Instance)(nil), // 1: v1.Instance
|
||||
(*emptypb.Empty)(nil), // 2: google.protobuf.Empty
|
||||
}
|
||||
var file_v1_hub_proto_depIdxs = []int32{
|
||||
1, // 0: v1.GetInstancesResponse.instances:type_name -> v1.Instance
|
||||
2, // 1: v1.Hub.GetInstances:input_type -> google.protobuf.Empty
|
||||
0, // 2: v1.Hub.GetInstances:output_type -> v1.GetInstancesResponse
|
||||
2, // [2:3] is the sub-list for method output_type
|
||||
1, // [1:2] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_v1_hub_proto_init() }
|
||||
func file_v1_hub_proto_init() {
|
||||
if File_v1_hub_proto != nil {
|
||||
return
|
||||
}
|
||||
file_v1_config_proto_init()
|
||||
file_v1_restic_proto_init()
|
||||
file_v1_operations_proto_init()
|
||||
if !protoimpl.UnsafeEnabled {
|
||||
file_v1_hub_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*GetInstancesResponse); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_v1_hub_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*Instance); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_v1_hub_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 2,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_v1_hub_proto_goTypes,
|
||||
DependencyIndexes: file_v1_hub_proto_depIdxs,
|
||||
MessageInfos: file_v1_hub_proto_msgTypes,
|
||||
}.Build()
|
||||
File_v1_hub_proto = out.File
|
||||
file_v1_hub_proto_rawDesc = nil
|
||||
file_v1_hub_proto_goTypes = nil
|
||||
file_v1_hub_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.3.0
|
||||
// - protoc (unknown)
|
||||
// source: v1/hub.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.32.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion7
|
||||
|
||||
const (
|
||||
Hub_GetInstances_FullMethodName = "/v1.Hub/GetInstances"
|
||||
)
|
||||
|
||||
// HubClient is the client API for Hub service.
|
||||
//
|
||||
// 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 HubClient interface {
|
||||
// GetInstances returns a list of all instances
|
||||
GetInstances(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetInstancesResponse, error)
|
||||
}
|
||||
|
||||
type hubClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewHubClient(cc grpc.ClientConnInterface) HubClient {
|
||||
return &hubClient{cc}
|
||||
}
|
||||
|
||||
func (c *hubClient) GetInstances(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*GetInstancesResponse, error) {
|
||||
out := new(GetInstancesResponse)
|
||||
err := c.cc.Invoke(ctx, Hub_GetInstances_FullMethodName, in, out, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// HubServer is the server API for Hub service.
|
||||
// All implementations must embed UnimplementedHubServer
|
||||
// for forward compatibility
|
||||
type HubServer interface {
|
||||
// GetInstances returns a list of all instances
|
||||
GetInstances(context.Context, *emptypb.Empty) (*GetInstancesResponse, error)
|
||||
mustEmbedUnimplementedHubServer()
|
||||
}
|
||||
|
||||
// UnimplementedHubServer must be embedded to have forward compatible implementations.
|
||||
type UnimplementedHubServer struct {
|
||||
}
|
||||
|
||||
func (UnimplementedHubServer) GetInstances(context.Context, *emptypb.Empty) (*GetInstancesResponse, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetInstances not implemented")
|
||||
}
|
||||
func (UnimplementedHubServer) mustEmbedUnimplementedHubServer() {}
|
||||
|
||||
// UnsafeHubServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to HubServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeHubServer interface {
|
||||
mustEmbedUnimplementedHubServer()
|
||||
}
|
||||
|
||||
func RegisterHubServer(s grpc.ServiceRegistrar, srv HubServer) {
|
||||
s.RegisterService(&Hub_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _Hub_GetInstances_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(emptypb.Empty)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(HubServer).GetInstances(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: Hub_GetInstances_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(HubServer).GetInstances(ctx, req.(*emptypb.Empty))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// Hub_ServiceDesc is the grpc.ServiceDesc for Hub service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var Hub_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "v1.Hub",
|
||||
HandlerType: (*HubServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "GetInstances",
|
||||
Handler: _Hub_GetInstances_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "v1/hub.proto",
|
||||
}
|
||||
+194
-116
@@ -662,6 +662,61 @@ func (x *LsEntry) GetCtime() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
type RunCommandRequest struct {
|
||||
state protoimpl.MessageState
|
||||
sizeCache protoimpl.SizeCache
|
||||
unknownFields protoimpl.UnknownFields
|
||||
|
||||
RepoId string `protobuf:"bytes,1,opt,name=repo_id,json=repoId,proto3" json:"repo_id,omitempty"`
|
||||
Command string `protobuf:"bytes,2,opt,name=command,proto3" json:"command,omitempty"`
|
||||
}
|
||||
|
||||
func (x *RunCommandRequest) Reset() {
|
||||
*x = RunCommandRequest{}
|
||||
if protoimpl.UnsafeEnabled {
|
||||
mi := &file_v1_service_proto_msgTypes[9]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
}
|
||||
|
||||
func (x *RunCommandRequest) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RunCommandRequest) ProtoMessage() {}
|
||||
|
||||
func (x *RunCommandRequest) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_v1_service_proto_msgTypes[9]
|
||||
if protoimpl.UnsafeEnabled && x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use RunCommandRequest.ProtoReflect.Descriptor instead.
|
||||
func (*RunCommandRequest) Descriptor() ([]byte, []int) {
|
||||
return file_v1_service_proto_rawDescGZIP(), []int{9}
|
||||
}
|
||||
|
||||
func (x *RunCommandRequest) GetRepoId() string {
|
||||
if x != nil {
|
||||
return x.RepoId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *RunCommandRequest) GetCommand() string {
|
||||
if x != nil {
|
||||
return x.Command
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_v1_service_proto protoreflect.FileDescriptor
|
||||
|
||||
var file_v1_service_proto_rawDesc = []byte{
|
||||
@@ -741,81 +796,89 @@ var file_v1_service_proto_rawDesc = []byte{
|
||||
0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a,
|
||||
0x05, 0x61, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x61, 0x74,
|
||||
0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x0a, 0x20, 0x01,
|
||||
0x28, 0x09, 0x52, 0x05, 0x63, 0x74, 0x69, 0x6d, 0x65, 0x32, 0xe2, 0x08, 0x0a, 0x08, 0x42, 0x61,
|
||||
0x63, 0x6b, 0x72, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e,
|
||||
0x66, 0x69, 0x67, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
|
||||
0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0a, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x00, 0x12, 0x25, 0x0a, 0x09, 0x53, 0x65, 0x74,
|
||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x0a, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66,
|
||||
0x69, 0x67, 0x1a, 0x0a, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x00,
|
||||
0x12, 0x21, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x52, 0x65, 0x70, 0x6f, 0x12, 0x08, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x52, 0x65, 0x70, 0x6f, 0x1a, 0x0a, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69,
|
||||
0x67, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
|
||||
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74,
|
||||
0x79, 0x1a, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
||||
0x45, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x00, 0x30, 0x01, 0x12, 0x3e, 0x0a, 0x0d, 0x47, 0x65, 0x74,
|
||||
0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x18, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x47, 0x65, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
|
||||
0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x00, 0x12, 0x43, 0x0a, 0x0d, 0x4c, 0x69, 0x73,
|
||||
0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x12, 0x18, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x52, 0x65, 0x71,
|
||||
0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x69, 0x63,
|
||||
0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x00, 0x12, 0x52,
|
||||
0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x46, 0x69,
|
||||
0x6c, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x61,
|
||||
0x70, 0x73, 0x68, 0x6f, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
|
||||
0x74, 0x1a, 0x1d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73,
|
||||
0x68, 0x6f, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65,
|
||||
0x22, 0x00, 0x12, 0x3e, 0x0a, 0x0e, 0x49, 0x6e, 0x64, 0x65, 0x78, 0x53, 0x6e, 0x61, 0x70, 0x73,
|
||||
0x68, 0x6f, 0x74, 0x73, 0x12, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72,
|
||||
0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79,
|
||||
0x22, 0x00, 0x12, 0x36, 0x0a, 0x06, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x12, 0x2e, 0x74,
|
||||
0x28, 0x09, 0x52, 0x05, 0x63, 0x74, 0x69, 0x6d, 0x65, 0x22, 0x46, 0x0a, 0x11, 0x52, 0x75, 0x6e,
|
||||
0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17,
|
||||
0x0a, 0x07, 0x72, 0x65, 0x70, 0x6f, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
|
||||
0x06, 0x72, 0x65, 0x70, 0x6f, 0x49, 0x64, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61,
|
||||
0x6e, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e,
|
||||
0x64, 0x32, 0x9e, 0x09, 0x0a, 0x08, 0x42, 0x61, 0x63, 0x6b, 0x72, 0x65, 0x73, 0x74, 0x12, 0x31,
|
||||
0x0a, 0x09, 0x47, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x16, 0x2e, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
|
||||
0x70, 0x74, 0x79, 0x1a, 0x0a, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22,
|
||||
0x00, 0x12, 0x25, 0x0a, 0x09, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x0a,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x0a, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x00, 0x12, 0x21, 0x0a, 0x07, 0x41, 0x64, 0x64, 0x52,
|
||||
0x65, 0x70, 0x6f, 0x12, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x1a, 0x0a, 0x2e,
|
||||
0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x12, 0x47,
|
||||
0x65, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74,
|
||||
0x73, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
|
||||
0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x4f,
|
||||
0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x00, 0x30,
|
||||
0x01, 0x12, 0x3e, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
|
||||
0x6e, 0x73, 0x12, 0x18, 0x2e, 0x76, 0x31, 0x2e, 0x47, 0x65, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61,
|
||||
0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x22,
|
||||
0x00, 0x12, 0x43, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f,
|
||||
0x74, 0x73, 0x12, 0x18, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x61, 0x70,
|
||||
0x73, 0x68, 0x6f, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x76,
|
||||
0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x69, 0x63, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74,
|
||||
0x4c, 0x69, 0x73, 0x74, 0x22, 0x00, 0x12, 0x52, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e,
|
||||
0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x46, 0x69, 0x6c,
|
||||
0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x76, 0x31, 0x2e, 0x4c,
|
||||
0x69, 0x73, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73,
|
||||
0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x3e, 0x0a, 0x0e, 0x49, 0x6e,
|
||||
0x64, 0x65, 0x78, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x12, 0x12, 0x2e, 0x74,
|
||||
0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
|
||||
0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x35, 0x0a, 0x05, 0x50, 0x72,
|
||||
0x75, 0x6e, 0x65, 0x12, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69,
|
||||
0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
|
||||
0x00, 0x12, 0x35, 0x0a, 0x06, 0x46, 0x6f, 0x72, 0x67, 0x65, 0x74, 0x12, 0x11, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x46, 0x6f, 0x72, 0x67, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16,
|
||||
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
|
||||
0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3f, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x74,
|
||||
0x6f, 0x72, 0x65, 0x12, 0x1a, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65,
|
||||
0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
|
||||
0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x06, 0x42, 0x61,
|
||||
0x63, 0x6b, 0x75, 0x70, 0x12, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72,
|
||||
0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c,
|
||||
0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79,
|
||||
0x22, 0x00, 0x12, 0x35, 0x0a, 0x05, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x12, 0x12, 0x2e, 0x74, 0x79,
|
||||
0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a,
|
||||
0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||
0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x36, 0x0a, 0x06, 0x55, 0x6e, 0x6c,
|
||||
0x6f, 0x63, 0x6b, 0x12, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69,
|
||||
0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
|
||||
0x00, 0x12, 0x35, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x73, 0x12, 0x12, 0x2e, 0x74, 0x79, 0x70,
|
||||
0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16,
|
||||
0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66,
|
||||
0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x35, 0x0a, 0x06, 0x43, 0x61, 0x6e, 0x63,
|
||||
0x65, 0x6c, 0x12, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x36, 0x34,
|
||||
0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
|
||||
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12,
|
||||
0x32, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x73, 0x12, 0x12, 0x2e, 0x76, 0x31, 0x2e,
|
||||
0x4c, 0x6f, 0x67, 0x44, 0x61, 0x74, 0x61, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11,
|
||||
0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75,
|
||||
0x65, 0x22, 0x00, 0x12, 0x39, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x44, 0x6f, 0x77, 0x6e, 0x6c, 0x6f,
|
||||
0x61, 0x64, 0x55, 0x52, 0x4c, 0x12, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x49, 0x6e,
|
||||
0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73,
|
||||
0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x00, 0x12, 0x41,
|
||||
0x0a, 0x0c, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x17,
|
||||
0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x48, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79,
|
||||
0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x35, 0x0a, 0x06, 0x46, 0x6f, 0x72,
|
||||
0x67, 0x65, 0x74, 0x12, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x46, 0x6f, 0x72, 0x67, 0x65, 0x74, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00,
|
||||
0x12, 0x3f, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x1a, 0x2e, 0x76, 0x31,
|
||||
0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74,
|
||||
0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65,
|
||||
0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22,
|
||||
0x00, 0x12, 0x3b, 0x0a, 0x10, 0x50, 0x61, 0x74, 0x68, 0x41, 0x75, 0x74, 0x6f, 0x63, 0x6f, 0x6d,
|
||||
0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74,
|
||||
0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65,
|
||||
0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x00, 0x42, 0x2c,
|
||||
0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72,
|
||||
0x65, 0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x62, 0x61, 0x63, 0x6b, 0x72, 0x65,
|
||||
0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72,
|
||||
0x6f, 0x74, 0x6f, 0x33,
|
||||
0x00, 0x12, 0x36, 0x0a, 0x06, 0x55, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x12, 0x2e, 0x74, 0x79,
|
||||
0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a,
|
||||
0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
|
||||
0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x35, 0x0a, 0x05, 0x53, 0x74, 0x61,
|
||||
0x74, 0x73, 0x12, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e,
|
||||
0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
|
||||
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00,
|
||||
0x12, 0x35, 0x0a, 0x06, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x12, 0x11, 0x2e, 0x74, 0x79, 0x70,
|
||||
0x65, 0x73, 0x2e, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e,
|
||||
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
|
||||
0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x32, 0x0a, 0x07, 0x47, 0x65, 0x74, 0x4c, 0x6f,
|
||||
0x67, 0x73, 0x12, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x6f, 0x67, 0x44, 0x61, 0x74, 0x61, 0x52,
|
||||
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x42,
|
||||
0x79, 0x74, 0x65, 0x73, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x00, 0x12, 0x3a, 0x0a, 0x0a, 0x52,
|
||||
0x75, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x15, 0x2e, 0x76, 0x31, 0x2e, 0x52,
|
||||
0x75, 0x6e, 0x43, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
|
||||
0x1a, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x42, 0x79, 0x74, 0x65, 0x73, 0x56, 0x61,
|
||||
0x6c, 0x75, 0x65, 0x22, 0x00, 0x30, 0x01, 0x12, 0x39, 0x0a, 0x0e, 0x47, 0x65, 0x74, 0x44, 0x6f,
|
||||
0x77, 0x6e, 0x6c, 0x6f, 0x61, 0x64, 0x55, 0x52, 0x4c, 0x12, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65,
|
||||
0x73, 0x2e, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x12, 0x2e, 0x74,
|
||||
0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65,
|
||||
0x22, 0x00, 0x12, 0x41, 0x0a, 0x0c, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x48, 0x69, 0x73, 0x74, 0x6f,
|
||||
0x72, 0x79, 0x12, 0x17, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6c, 0x65, 0x61, 0x72, 0x48, 0x69, 0x73,
|
||||
0x74, 0x6f, 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f,
|
||||
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
|
||||
0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x10, 0x50, 0x61, 0x74, 0x68, 0x41, 0x75, 0x74,
|
||||
0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65,
|
||||
0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x11, 0x2e,
|
||||
0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74,
|
||||
0x22, 0x00, 0x42, 0x2c, 0x5a, 0x2a, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d,
|
||||
0x2f, 0x67, 0x61, 0x72, 0x65, 0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x62, 0x61,
|
||||
0x63, 0x6b, 0x72, 0x65, 0x73, 0x74, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f, 0x76, 0x31,
|
||||
0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -830,7 +893,7 @@ func file_v1_service_proto_rawDescGZIP() []byte {
|
||||
return file_v1_service_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_v1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 9)
|
||||
var file_v1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 10)
|
||||
var file_v1_service_proto_goTypes = []interface{}{
|
||||
(*ClearHistoryRequest)(nil), // 0: v1.ClearHistoryRequest
|
||||
(*ForgetRequest)(nil), // 1: v1.ForgetRequest
|
||||
@@ -841,59 +904,62 @@ var file_v1_service_proto_goTypes = []interface{}{
|
||||
(*ListSnapshotFilesResponse)(nil), // 6: v1.ListSnapshotFilesResponse
|
||||
(*LogDataRequest)(nil), // 7: v1.LogDataRequest
|
||||
(*LsEntry)(nil), // 8: v1.LsEntry
|
||||
(*emptypb.Empty)(nil), // 9: google.protobuf.Empty
|
||||
(*Config)(nil), // 10: v1.Config
|
||||
(*Repo)(nil), // 11: v1.Repo
|
||||
(*types.StringValue)(nil), // 12: types.StringValue
|
||||
(*types.Int64Value)(nil), // 13: types.Int64Value
|
||||
(*OperationEvent)(nil), // 14: v1.OperationEvent
|
||||
(*OperationList)(nil), // 15: v1.OperationList
|
||||
(*ResticSnapshotList)(nil), // 16: v1.ResticSnapshotList
|
||||
(*types.BytesValue)(nil), // 17: types.BytesValue
|
||||
(*types.StringList)(nil), // 18: types.StringList
|
||||
(*RunCommandRequest)(nil), // 9: v1.RunCommandRequest
|
||||
(*emptypb.Empty)(nil), // 10: google.protobuf.Empty
|
||||
(*Config)(nil), // 11: v1.Config
|
||||
(*Repo)(nil), // 12: v1.Repo
|
||||
(*types.StringValue)(nil), // 13: types.StringValue
|
||||
(*types.Int64Value)(nil), // 14: types.Int64Value
|
||||
(*OperationEvent)(nil), // 15: v1.OperationEvent
|
||||
(*OperationList)(nil), // 16: v1.OperationList
|
||||
(*ResticSnapshotList)(nil), // 17: v1.ResticSnapshotList
|
||||
(*types.BytesValue)(nil), // 18: types.BytesValue
|
||||
(*types.StringList)(nil), // 19: types.StringList
|
||||
}
|
||||
var file_v1_service_proto_depIdxs = []int32{
|
||||
8, // 0: v1.ListSnapshotFilesResponse.entries:type_name -> v1.LsEntry
|
||||
9, // 1: v1.Backrest.GetConfig:input_type -> google.protobuf.Empty
|
||||
10, // 2: v1.Backrest.SetConfig:input_type -> v1.Config
|
||||
11, // 3: v1.Backrest.AddRepo:input_type -> v1.Repo
|
||||
9, // 4: v1.Backrest.GetOperationEvents:input_type -> google.protobuf.Empty
|
||||
10, // 1: v1.Backrest.GetConfig:input_type -> google.protobuf.Empty
|
||||
11, // 2: v1.Backrest.SetConfig:input_type -> v1.Config
|
||||
12, // 3: v1.Backrest.AddRepo:input_type -> v1.Repo
|
||||
10, // 4: v1.Backrest.GetOperationEvents:input_type -> google.protobuf.Empty
|
||||
3, // 5: v1.Backrest.GetOperations:input_type -> v1.GetOperationsRequest
|
||||
2, // 6: v1.Backrest.ListSnapshots:input_type -> v1.ListSnapshotsRequest
|
||||
5, // 7: v1.Backrest.ListSnapshotFiles:input_type -> v1.ListSnapshotFilesRequest
|
||||
12, // 8: v1.Backrest.IndexSnapshots:input_type -> types.StringValue
|
||||
12, // 9: v1.Backrest.Backup:input_type -> types.StringValue
|
||||
12, // 10: v1.Backrest.Prune:input_type -> types.StringValue
|
||||
13, // 8: v1.Backrest.IndexSnapshots:input_type -> types.StringValue
|
||||
13, // 9: v1.Backrest.Backup:input_type -> types.StringValue
|
||||
13, // 10: v1.Backrest.Prune:input_type -> types.StringValue
|
||||
1, // 11: v1.Backrest.Forget:input_type -> v1.ForgetRequest
|
||||
4, // 12: v1.Backrest.Restore:input_type -> v1.RestoreSnapshotRequest
|
||||
12, // 13: v1.Backrest.Unlock:input_type -> types.StringValue
|
||||
12, // 14: v1.Backrest.Stats:input_type -> types.StringValue
|
||||
13, // 15: v1.Backrest.Cancel:input_type -> types.Int64Value
|
||||
13, // 13: v1.Backrest.Unlock:input_type -> types.StringValue
|
||||
13, // 14: v1.Backrest.Stats:input_type -> types.StringValue
|
||||
14, // 15: v1.Backrest.Cancel:input_type -> types.Int64Value
|
||||
7, // 16: v1.Backrest.GetLogs:input_type -> v1.LogDataRequest
|
||||
13, // 17: v1.Backrest.GetDownloadURL:input_type -> types.Int64Value
|
||||
0, // 18: v1.Backrest.ClearHistory:input_type -> v1.ClearHistoryRequest
|
||||
12, // 19: v1.Backrest.PathAutocomplete:input_type -> types.StringValue
|
||||
10, // 20: v1.Backrest.GetConfig:output_type -> v1.Config
|
||||
10, // 21: v1.Backrest.SetConfig:output_type -> v1.Config
|
||||
10, // 22: v1.Backrest.AddRepo:output_type -> v1.Config
|
||||
14, // 23: v1.Backrest.GetOperationEvents:output_type -> v1.OperationEvent
|
||||
15, // 24: v1.Backrest.GetOperations:output_type -> v1.OperationList
|
||||
16, // 25: v1.Backrest.ListSnapshots:output_type -> v1.ResticSnapshotList
|
||||
6, // 26: v1.Backrest.ListSnapshotFiles:output_type -> v1.ListSnapshotFilesResponse
|
||||
9, // 27: v1.Backrest.IndexSnapshots:output_type -> google.protobuf.Empty
|
||||
9, // 28: v1.Backrest.Backup:output_type -> google.protobuf.Empty
|
||||
9, // 29: v1.Backrest.Prune:output_type -> google.protobuf.Empty
|
||||
9, // 30: v1.Backrest.Forget:output_type -> google.protobuf.Empty
|
||||
9, // 31: v1.Backrest.Restore:output_type -> google.protobuf.Empty
|
||||
9, // 32: v1.Backrest.Unlock:output_type -> google.protobuf.Empty
|
||||
9, // 33: v1.Backrest.Stats:output_type -> google.protobuf.Empty
|
||||
9, // 34: v1.Backrest.Cancel:output_type -> google.protobuf.Empty
|
||||
17, // 35: v1.Backrest.GetLogs:output_type -> types.BytesValue
|
||||
12, // 36: v1.Backrest.GetDownloadURL:output_type -> types.StringValue
|
||||
9, // 37: v1.Backrest.ClearHistory:output_type -> google.protobuf.Empty
|
||||
18, // 38: v1.Backrest.PathAutocomplete:output_type -> types.StringList
|
||||
20, // [20:39] is the sub-list for method output_type
|
||||
1, // [1:20] is the sub-list for method input_type
|
||||
9, // 17: v1.Backrest.RunCommand:input_type -> v1.RunCommandRequest
|
||||
14, // 18: v1.Backrest.GetDownloadURL:input_type -> types.Int64Value
|
||||
0, // 19: v1.Backrest.ClearHistory:input_type -> v1.ClearHistoryRequest
|
||||
13, // 20: v1.Backrest.PathAutocomplete:input_type -> types.StringValue
|
||||
11, // 21: v1.Backrest.GetConfig:output_type -> v1.Config
|
||||
11, // 22: v1.Backrest.SetConfig:output_type -> v1.Config
|
||||
11, // 23: v1.Backrest.AddRepo:output_type -> v1.Config
|
||||
15, // 24: v1.Backrest.GetOperationEvents:output_type -> v1.OperationEvent
|
||||
16, // 25: v1.Backrest.GetOperations:output_type -> v1.OperationList
|
||||
17, // 26: v1.Backrest.ListSnapshots:output_type -> v1.ResticSnapshotList
|
||||
6, // 27: v1.Backrest.ListSnapshotFiles:output_type -> v1.ListSnapshotFilesResponse
|
||||
10, // 28: v1.Backrest.IndexSnapshots:output_type -> google.protobuf.Empty
|
||||
10, // 29: v1.Backrest.Backup:output_type -> google.protobuf.Empty
|
||||
10, // 30: v1.Backrest.Prune:output_type -> google.protobuf.Empty
|
||||
10, // 31: v1.Backrest.Forget:output_type -> google.protobuf.Empty
|
||||
10, // 32: v1.Backrest.Restore:output_type -> google.protobuf.Empty
|
||||
10, // 33: v1.Backrest.Unlock:output_type -> google.protobuf.Empty
|
||||
10, // 34: v1.Backrest.Stats:output_type -> google.protobuf.Empty
|
||||
10, // 35: v1.Backrest.Cancel:output_type -> google.protobuf.Empty
|
||||
18, // 36: v1.Backrest.GetLogs:output_type -> types.BytesValue
|
||||
18, // 37: v1.Backrest.RunCommand:output_type -> types.BytesValue
|
||||
13, // 38: v1.Backrest.GetDownloadURL:output_type -> types.StringValue
|
||||
10, // 39: v1.Backrest.ClearHistory:output_type -> google.protobuf.Empty
|
||||
19, // 40: v1.Backrest.PathAutocomplete:output_type -> types.StringList
|
||||
21, // [21:41] is the sub-list for method output_type
|
||||
1, // [1:21] is the sub-list for method input_type
|
||||
1, // [1:1] is the sub-list for extension type_name
|
||||
1, // [1:1] is the sub-list for extension extendee
|
||||
0, // [0:1] is the sub-list for field type_name
|
||||
@@ -1016,6 +1082,18 @@ func file_v1_service_proto_init() {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
file_v1_service_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} {
|
||||
switch v := v.(*RunCommandRequest); i {
|
||||
case 0:
|
||||
return &v.state
|
||||
case 1:
|
||||
return &v.sizeCache
|
||||
case 2:
|
||||
return &v.unknownFields
|
||||
default:
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
@@ -1023,7 +1101,7 @@ func file_v1_service_proto_init() {
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: file_v1_service_proto_rawDesc,
|
||||
NumEnums: 0,
|
||||
NumMessages: 9,
|
||||
NumMessages: 10,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
|
||||
@@ -37,6 +37,7 @@ const (
|
||||
Backrest_Stats_FullMethodName = "/v1.Backrest/Stats"
|
||||
Backrest_Cancel_FullMethodName = "/v1.Backrest/Cancel"
|
||||
Backrest_GetLogs_FullMethodName = "/v1.Backrest/GetLogs"
|
||||
Backrest_RunCommand_FullMethodName = "/v1.Backrest/RunCommand"
|
||||
Backrest_GetDownloadURL_FullMethodName = "/v1.Backrest/GetDownloadURL"
|
||||
Backrest_ClearHistory_FullMethodName = "/v1.Backrest/ClearHistory"
|
||||
Backrest_PathAutocomplete_FullMethodName = "/v1.Backrest/PathAutocomplete"
|
||||
@@ -71,6 +72,8 @@ type BackrestClient interface {
|
||||
Cancel(ctx context.Context, in *types.Int64Value, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||
// GetLogs returns the keyed large data for the given operation.
|
||||
GetLogs(ctx context.Context, in *LogDataRequest, opts ...grpc.CallOption) (*types.BytesValue, error)
|
||||
// RunCommand executes a generic restic command on the repository.
|
||||
RunCommand(ctx context.Context, in *RunCommandRequest, opts ...grpc.CallOption) (Backrest_RunCommandClient, error)
|
||||
// GetDownloadURL returns a signed download URL given a forget operation ID.
|
||||
GetDownloadURL(ctx context.Context, in *types.Int64Value, opts ...grpc.CallOption) (*types.StringValue, error)
|
||||
// Clears the history of operations
|
||||
@@ -254,6 +257,38 @@ func (c *backrestClient) GetLogs(ctx context.Context, in *LogDataRequest, opts .
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *backrestClient) RunCommand(ctx context.Context, in *RunCommandRequest, opts ...grpc.CallOption) (Backrest_RunCommandClient, error) {
|
||||
stream, err := c.cc.NewStream(ctx, &Backrest_ServiceDesc.Streams[1], Backrest_RunCommand_FullMethodName, opts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
x := &backrestRunCommandClient{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
|
||||
}
|
||||
|
||||
type Backrest_RunCommandClient interface {
|
||||
Recv() (*types.BytesValue, error)
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
type backrestRunCommandClient struct {
|
||||
grpc.ClientStream
|
||||
}
|
||||
|
||||
func (x *backrestRunCommandClient) Recv() (*types.BytesValue, error) {
|
||||
m := new(types.BytesValue)
|
||||
if err := x.ClientStream.RecvMsg(m); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return m, nil
|
||||
}
|
||||
|
||||
func (c *backrestClient) GetDownloadURL(ctx context.Context, in *types.Int64Value, opts ...grpc.CallOption) (*types.StringValue, error) {
|
||||
out := new(types.StringValue)
|
||||
err := c.cc.Invoke(ctx, Backrest_GetDownloadURL_FullMethodName, in, out, opts...)
|
||||
@@ -310,6 +345,8 @@ type BackrestServer interface {
|
||||
Cancel(context.Context, *types.Int64Value) (*emptypb.Empty, error)
|
||||
// GetLogs returns the keyed large data for the given operation.
|
||||
GetLogs(context.Context, *LogDataRequest) (*types.BytesValue, error)
|
||||
// RunCommand executes a generic restic command on the repository.
|
||||
RunCommand(*RunCommandRequest, Backrest_RunCommandServer) error
|
||||
// GetDownloadURL returns a signed download URL given a forget operation ID.
|
||||
GetDownloadURL(context.Context, *types.Int64Value) (*types.StringValue, error)
|
||||
// Clears the history of operations
|
||||
@@ -371,6 +408,9 @@ func (UnimplementedBackrestServer) Cancel(context.Context, *types.Int64Value) (*
|
||||
func (UnimplementedBackrestServer) GetLogs(context.Context, *LogDataRequest) (*types.BytesValue, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetLogs not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) RunCommand(*RunCommandRequest, Backrest_RunCommandServer) error {
|
||||
return status.Errorf(codes.Unimplemented, "method RunCommand not implemented")
|
||||
}
|
||||
func (UnimplementedBackrestServer) GetDownloadURL(context.Context, *types.Int64Value) (*types.StringValue, error) {
|
||||
return nil, status.Errorf(codes.Unimplemented, "method GetDownloadURL not implemented")
|
||||
}
|
||||
@@ -684,6 +724,27 @@ func _Backrest_GetLogs_Handler(srv interface{}, ctx context.Context, dec func(in
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _Backrest_RunCommand_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||
m := new(RunCommandRequest)
|
||||
if err := stream.RecvMsg(m); err != nil {
|
||||
return err
|
||||
}
|
||||
return srv.(BackrestServer).RunCommand(m, &backrestRunCommandServer{stream})
|
||||
}
|
||||
|
||||
type Backrest_RunCommandServer interface {
|
||||
Send(*types.BytesValue) error
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
type backrestRunCommandServer struct {
|
||||
grpc.ServerStream
|
||||
}
|
||||
|
||||
func (x *backrestRunCommandServer) Send(m *types.BytesValue) error {
|
||||
return x.ServerStream.SendMsg(m)
|
||||
}
|
||||
|
||||
func _Backrest_GetDownloadURL_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(types.Int64Value)
|
||||
if err := dec(in); err != nil {
|
||||
@@ -824,6 +885,11 @@ var Backrest_ServiceDesc = grpc.ServiceDesc{
|
||||
Handler: _Backrest_GetOperationEvents_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
{
|
||||
StreamName: "RunCommand",
|
||||
Handler: _Backrest_RunCommand_Handler,
|
||||
ServerStreams: true,
|
||||
},
|
||||
},
|
||||
Metadata: "v1/service.proto",
|
||||
}
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
// Code generated by protoc-gen-connect-go. DO NOT EDIT.
|
||||
//
|
||||
// Source: v1/hub.proto
|
||||
|
||||
package v1connect
|
||||
|
||||
import (
|
||||
connect "connectrpc.com/connect"
|
||||
context "context"
|
||||
errors "errors"
|
||||
v1 "github.com/garethgeorge/backrest/gen/go/v1"
|
||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||
http "net/http"
|
||||
strings "strings"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file and the connect package are
|
||||
// compatible. If you get a compiler error that this constant is not defined, this code was
|
||||
// generated with a version of connect newer than the one compiled into your binary. You can fix the
|
||||
// problem by either regenerating this code with an older version of connect or updating the connect
|
||||
// version compiled into your binary.
|
||||
const _ = connect.IsAtLeastVersion1_13_0
|
||||
|
||||
const (
|
||||
// HubName is the fully-qualified name of the Hub service.
|
||||
HubName = "v1.Hub"
|
||||
)
|
||||
|
||||
// These constants are the fully-qualified names of the RPCs defined in this package. They're
|
||||
// exposed at runtime as Spec.Procedure and as the final two segments of the HTTP route.
|
||||
//
|
||||
// Note that these are different from the fully-qualified method names used by
|
||||
// google.golang.org/protobuf/reflect/protoreflect. To convert from these constants to
|
||||
// reflection-formatted method names, remove the leading slash and convert the remaining slash to a
|
||||
// period.
|
||||
const (
|
||||
// HubGetInstancesProcedure is the fully-qualified name of the Hub's GetInstances RPC.
|
||||
HubGetInstancesProcedure = "/v1.Hub/GetInstances"
|
||||
)
|
||||
|
||||
// These variables are the protoreflect.Descriptor objects for the RPCs defined in this package.
|
||||
var (
|
||||
hubServiceDescriptor = v1.File_v1_hub_proto.Services().ByName("Hub")
|
||||
hubGetInstancesMethodDescriptor = hubServiceDescriptor.Methods().ByName("GetInstances")
|
||||
)
|
||||
|
||||
// HubClient is a client for the v1.Hub service.
|
||||
type HubClient interface {
|
||||
// GetInstances returns a list of all instances
|
||||
GetInstances(context.Context, *connect.Request[emptypb.Empty]) (*connect.Response[v1.GetInstancesResponse], error)
|
||||
}
|
||||
|
||||
// NewHubClient constructs a client for the v1.Hub service. By default, it uses the Connect protocol
|
||||
// with the binary Protobuf Codec, asks for gzipped responses, and sends uncompressed requests. To
|
||||
// use the gRPC or gRPC-Web protocols, supply the connect.WithGRPC() or connect.WithGRPCWeb()
|
||||
// options.
|
||||
//
|
||||
// The URL supplied here should be the base URL for the Connect or gRPC server (for example,
|
||||
// http://api.acme.com or https://acme.com/grpc).
|
||||
func NewHubClient(httpClient connect.HTTPClient, baseURL string, opts ...connect.ClientOption) HubClient {
|
||||
baseURL = strings.TrimRight(baseURL, "/")
|
||||
return &hubClient{
|
||||
getInstances: connect.NewClient[emptypb.Empty, v1.GetInstancesResponse](
|
||||
httpClient,
|
||||
baseURL+HubGetInstancesProcedure,
|
||||
connect.WithSchema(hubGetInstancesMethodDescriptor),
|
||||
connect.WithClientOptions(opts...),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
// hubClient implements HubClient.
|
||||
type hubClient struct {
|
||||
getInstances *connect.Client[emptypb.Empty, v1.GetInstancesResponse]
|
||||
}
|
||||
|
||||
// GetInstances calls v1.Hub.GetInstances.
|
||||
func (c *hubClient) GetInstances(ctx context.Context, req *connect.Request[emptypb.Empty]) (*connect.Response[v1.GetInstancesResponse], error) {
|
||||
return c.getInstances.CallUnary(ctx, req)
|
||||
}
|
||||
|
||||
// HubHandler is an implementation of the v1.Hub service.
|
||||
type HubHandler interface {
|
||||
// GetInstances returns a list of all instances
|
||||
GetInstances(context.Context, *connect.Request[emptypb.Empty]) (*connect.Response[v1.GetInstancesResponse], error)
|
||||
}
|
||||
|
||||
// NewHubHandler builds an HTTP handler from the service implementation. It returns the path on
|
||||
// which to mount the handler and the handler itself.
|
||||
//
|
||||
// By default, handlers support the Connect, gRPC, and gRPC-Web protocols with the binary Protobuf
|
||||
// and JSON codecs. They also support gzip compression.
|
||||
func NewHubHandler(svc HubHandler, opts ...connect.HandlerOption) (string, http.Handler) {
|
||||
hubGetInstancesHandler := connect.NewUnaryHandler(
|
||||
HubGetInstancesProcedure,
|
||||
svc.GetInstances,
|
||||
connect.WithSchema(hubGetInstancesMethodDescriptor),
|
||||
connect.WithHandlerOptions(opts...),
|
||||
)
|
||||
return "/v1.Hub/", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case HubGetInstancesProcedure:
|
||||
hubGetInstancesHandler.ServeHTTP(w, r)
|
||||
default:
|
||||
http.NotFound(w, r)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// UnimplementedHubHandler returns CodeUnimplemented from all methods.
|
||||
type UnimplementedHubHandler struct{}
|
||||
|
||||
func (UnimplementedHubHandler) GetInstances(context.Context, *connect.Request[emptypb.Empty]) (*connect.Response[v1.GetInstancesResponse], error) {
|
||||
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("v1.Hub.GetInstances is not implemented"))
|
||||
}
|
||||
@@ -69,6 +69,8 @@ const (
|
||||
BackrestCancelProcedure = "/v1.Backrest/Cancel"
|
||||
// BackrestGetLogsProcedure is the fully-qualified name of the Backrest's GetLogs RPC.
|
||||
BackrestGetLogsProcedure = "/v1.Backrest/GetLogs"
|
||||
// BackrestRunCommandProcedure is the fully-qualified name of the Backrest's RunCommand RPC.
|
||||
BackrestRunCommandProcedure = "/v1.Backrest/RunCommand"
|
||||
// BackrestGetDownloadURLProcedure is the fully-qualified name of the Backrest's GetDownloadURL RPC.
|
||||
BackrestGetDownloadURLProcedure = "/v1.Backrest/GetDownloadURL"
|
||||
// BackrestClearHistoryProcedure is the fully-qualified name of the Backrest's ClearHistory RPC.
|
||||
@@ -97,6 +99,7 @@ var (
|
||||
backrestStatsMethodDescriptor = backrestServiceDescriptor.Methods().ByName("Stats")
|
||||
backrestCancelMethodDescriptor = backrestServiceDescriptor.Methods().ByName("Cancel")
|
||||
backrestGetLogsMethodDescriptor = backrestServiceDescriptor.Methods().ByName("GetLogs")
|
||||
backrestRunCommandMethodDescriptor = backrestServiceDescriptor.Methods().ByName("RunCommand")
|
||||
backrestGetDownloadURLMethodDescriptor = backrestServiceDescriptor.Methods().ByName("GetDownloadURL")
|
||||
backrestClearHistoryMethodDescriptor = backrestServiceDescriptor.Methods().ByName("ClearHistory")
|
||||
backrestPathAutocompleteMethodDescriptor = backrestServiceDescriptor.Methods().ByName("PathAutocomplete")
|
||||
@@ -129,6 +132,8 @@ type BackrestClient interface {
|
||||
Cancel(context.Context, *connect.Request[types.Int64Value]) (*connect.Response[emptypb.Empty], error)
|
||||
// GetLogs returns the keyed large data for the given operation.
|
||||
GetLogs(context.Context, *connect.Request[v1.LogDataRequest]) (*connect.Response[types.BytesValue], error)
|
||||
// RunCommand executes a generic restic command on the repository.
|
||||
RunCommand(context.Context, *connect.Request[v1.RunCommandRequest]) (*connect.ServerStreamForClient[types.BytesValue], error)
|
||||
// GetDownloadURL returns a signed download URL given a forget operation ID.
|
||||
GetDownloadURL(context.Context, *connect.Request[types.Int64Value]) (*connect.Response[types.StringValue], error)
|
||||
// Clears the history of operations
|
||||
@@ -243,6 +248,12 @@ func NewBackrestClient(httpClient connect.HTTPClient, baseURL string, opts ...co
|
||||
connect.WithSchema(backrestGetLogsMethodDescriptor),
|
||||
connect.WithClientOptions(opts...),
|
||||
),
|
||||
runCommand: connect.NewClient[v1.RunCommandRequest, types.BytesValue](
|
||||
httpClient,
|
||||
baseURL+BackrestRunCommandProcedure,
|
||||
connect.WithSchema(backrestRunCommandMethodDescriptor),
|
||||
connect.WithClientOptions(opts...),
|
||||
),
|
||||
getDownloadURL: connect.NewClient[types.Int64Value, types.StringValue](
|
||||
httpClient,
|
||||
baseURL+BackrestGetDownloadURLProcedure,
|
||||
@@ -282,6 +293,7 @@ type backrestClient struct {
|
||||
stats *connect.Client[types.StringValue, emptypb.Empty]
|
||||
cancel *connect.Client[types.Int64Value, emptypb.Empty]
|
||||
getLogs *connect.Client[v1.LogDataRequest, types.BytesValue]
|
||||
runCommand *connect.Client[v1.RunCommandRequest, types.BytesValue]
|
||||
getDownloadURL *connect.Client[types.Int64Value, types.StringValue]
|
||||
clearHistory *connect.Client[v1.ClearHistoryRequest, emptypb.Empty]
|
||||
pathAutocomplete *connect.Client[types.StringValue, types.StringList]
|
||||
@@ -367,6 +379,11 @@ func (c *backrestClient) GetLogs(ctx context.Context, req *connect.Request[v1.Lo
|
||||
return c.getLogs.CallUnary(ctx, req)
|
||||
}
|
||||
|
||||
// RunCommand calls v1.Backrest.RunCommand.
|
||||
func (c *backrestClient) RunCommand(ctx context.Context, req *connect.Request[v1.RunCommandRequest]) (*connect.ServerStreamForClient[types.BytesValue], error) {
|
||||
return c.runCommand.CallServerStream(ctx, req)
|
||||
}
|
||||
|
||||
// GetDownloadURL calls v1.Backrest.GetDownloadURL.
|
||||
func (c *backrestClient) GetDownloadURL(ctx context.Context, req *connect.Request[types.Int64Value]) (*connect.Response[types.StringValue], error) {
|
||||
return c.getDownloadURL.CallUnary(ctx, req)
|
||||
@@ -409,6 +426,8 @@ type BackrestHandler interface {
|
||||
Cancel(context.Context, *connect.Request[types.Int64Value]) (*connect.Response[emptypb.Empty], error)
|
||||
// GetLogs returns the keyed large data for the given operation.
|
||||
GetLogs(context.Context, *connect.Request[v1.LogDataRequest]) (*connect.Response[types.BytesValue], error)
|
||||
// RunCommand executes a generic restic command on the repository.
|
||||
RunCommand(context.Context, *connect.Request[v1.RunCommandRequest], *connect.ServerStream[types.BytesValue]) error
|
||||
// GetDownloadURL returns a signed download URL given a forget operation ID.
|
||||
GetDownloadURL(context.Context, *connect.Request[types.Int64Value]) (*connect.Response[types.StringValue], error)
|
||||
// Clears the history of operations
|
||||
@@ -519,6 +538,12 @@ func NewBackrestHandler(svc BackrestHandler, opts ...connect.HandlerOption) (str
|
||||
connect.WithSchema(backrestGetLogsMethodDescriptor),
|
||||
connect.WithHandlerOptions(opts...),
|
||||
)
|
||||
backrestRunCommandHandler := connect.NewServerStreamHandler(
|
||||
BackrestRunCommandProcedure,
|
||||
svc.RunCommand,
|
||||
connect.WithSchema(backrestRunCommandMethodDescriptor),
|
||||
connect.WithHandlerOptions(opts...),
|
||||
)
|
||||
backrestGetDownloadURLHandler := connect.NewUnaryHandler(
|
||||
BackrestGetDownloadURLProcedure,
|
||||
svc.GetDownloadURL,
|
||||
@@ -571,6 +596,8 @@ func NewBackrestHandler(svc BackrestHandler, opts ...connect.HandlerOption) (str
|
||||
backrestCancelHandler.ServeHTTP(w, r)
|
||||
case BackrestGetLogsProcedure:
|
||||
backrestGetLogsHandler.ServeHTTP(w, r)
|
||||
case BackrestRunCommandProcedure:
|
||||
backrestRunCommandHandler.ServeHTTP(w, r)
|
||||
case BackrestGetDownloadURLProcedure:
|
||||
backrestGetDownloadURLHandler.ServeHTTP(w, r)
|
||||
case BackrestClearHistoryProcedure:
|
||||
@@ -650,6 +677,10 @@ func (UnimplementedBackrestHandler) GetLogs(context.Context, *connect.Request[v1
|
||||
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("v1.Backrest.GetLogs is not implemented"))
|
||||
}
|
||||
|
||||
func (UnimplementedBackrestHandler) RunCommand(context.Context, *connect.Request[v1.RunCommandRequest], *connect.ServerStream[types.BytesValue]) error {
|
||||
return connect.NewError(connect.CodeUnimplemented, errors.New("v1.Backrest.RunCommand is not implemented"))
|
||||
}
|
||||
|
||||
func (UnimplementedBackrestHandler) GetDownloadURL(context.Context, *connect.Request[types.Int64Value]) (*connect.Response[types.StringValue], error) {
|
||||
return nil, connect.NewError(connect.CodeUnimplemented, errors.New("v1.Backrest.GetDownloadURL is not implemented"))
|
||||
}
|
||||
|
||||
@@ -411,6 +411,47 @@ func (s *BackrestHandler) Stats(ctx context.Context, req *connect.Request[types.
|
||||
|
||||
}
|
||||
|
||||
func (s *BackrestHandler) RunCommand(ctx context.Context, req *connect.Request[v1.RunCommandRequest], resp *connect.ServerStream[types.BytesValue]) error {
|
||||
repo, err := s.orchestrator.GetRepoOrchestrator(req.Msg.RepoId)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get repo %q: %w", req.Msg.RepoId, err)
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
|
||||
errChan := make(chan error, 1)
|
||||
var outputBuf []byte
|
||||
|
||||
go func() {
|
||||
if err := repo.RunCommand(ctx, req.Msg.Command, func(output []byte) {
|
||||
outputBuf = append(outputBuf, output...)
|
||||
}); err != nil {
|
||||
errChan <- err
|
||||
}
|
||||
cancel()
|
||||
}()
|
||||
|
||||
for {
|
||||
select {
|
||||
case err := <-errChan:
|
||||
if err := resp.Send(&types.BytesValue{Value: outputBuf}); err != nil {
|
||||
return fmt.Errorf("failed to write output: %w", err)
|
||||
}
|
||||
return err
|
||||
case <-ctx.Done():
|
||||
if err := resp.Send(&types.BytesValue{Value: outputBuf}); err != nil {
|
||||
return fmt.Errorf("failed to write output: %w", err)
|
||||
}
|
||||
return nil
|
||||
case <-time.After(100 * time.Millisecond):
|
||||
if err := resp.Send(&types.BytesValue{Value: outputBuf}); err != nil {
|
||||
return fmt.Errorf("failed to write output: %w", err)
|
||||
}
|
||||
outputBuf = outputBuf[:0] // clear the buffer and continue
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (s *BackrestHandler) Cancel(ctx context.Context, req *connect.Request[types.Int64Value]) (*connect.Response[emptypb.Empty], error) {
|
||||
if err := s.orchestrator.CancelOperation(req.Msg.Value, v1.OperationStatus_STATUS_USER_CANCELLED); err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -11,12 +11,12 @@ import (
|
||||
// pipeResticLogsToWriter sets the restic logger to write to the provided writer.
|
||||
// returns a new context with the logger set and a function to flush the logs.
|
||||
func forwardResticLogs(ctx context.Context) (context.Context, func()) {
|
||||
writer := logging.WriterFromContext(ctx)
|
||||
if writer == nil {
|
||||
return ctx, func() {}
|
||||
}
|
||||
capture := ioutil.NewOutputCapturer(64 * 1024)
|
||||
return restic.ContextWithLogger(ctx, capture), func() {
|
||||
writer := logging.WriterFromContext(ctx)
|
||||
if writer == nil {
|
||||
return
|
||||
}
|
||||
_, _ = writer.Write(capture.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,8 @@ import (
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// RepoOrchestrator is responsible for managing a single repo.
|
||||
// RepoOrchestrator implements higher level repository operations on top of
|
||||
// the restic package. It can be thought of as a controller for a repo.
|
||||
type RepoOrchestrator struct {
|
||||
mu sync.Mutex
|
||||
|
||||
@@ -326,6 +327,8 @@ func (r *RepoOrchestrator) Stats(ctx context.Context) (*v1.RepoStats, error) {
|
||||
func (r *RepoOrchestrator) AddTags(ctx context.Context, snapshotIDs []string, tags []string) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
ctx, flush := forwardResticLogs(ctx)
|
||||
defer flush()
|
||||
|
||||
for idx, snapshotIDs := range chunkBy(snapshotIDs, 20) {
|
||||
r.l.Debug("adding tag to snapshots", zap.Strings("snapshots", snapshotIDs), zap.Strings("tags", tags))
|
||||
@@ -337,6 +340,24 @@ func (r *RepoOrchestrator) AddTags(ctx context.Context, snapshotIDs []string, ta
|
||||
return nil
|
||||
}
|
||||
|
||||
// RunCommand runs a command in the repo's environment. Output is buffered and sent to the onProgress callback in batches.
|
||||
func (r *RepoOrchestrator) RunCommand(ctx context.Context, command string, onProgress func([]byte)) error {
|
||||
r.mu.Lock()
|
||||
defer r.mu.Unlock()
|
||||
ctx, flush := forwardResticLogs(ctx)
|
||||
defer flush()
|
||||
|
||||
r.l.Debug("running command", zap.String("command", command))
|
||||
args, err := shlex.Split(command)
|
||||
if err != nil {
|
||||
return fmt.Errorf("parse command: %w", err)
|
||||
}
|
||||
|
||||
ctx = restic.ContextWithLogger(ctx, &callbackWriter{callback: onProgress})
|
||||
|
||||
return r.repo.GenericCommand(ctx, args)
|
||||
}
|
||||
|
||||
func (r *RepoOrchestrator) Config() *v1.Repo {
|
||||
if r == nil {
|
||||
return nil
|
||||
@@ -356,3 +377,12 @@ func chunkBy[T any](items []T, chunkSize int) (chunks [][]T) {
|
||||
}
|
||||
return append(chunks, items)
|
||||
}
|
||||
|
||||
type callbackWriter struct {
|
||||
callback func([]byte)
|
||||
}
|
||||
|
||||
func (w *callbackWriter) Write(p []byte) (n int, err error) {
|
||||
w.callback(p)
|
||||
return len(p), nil
|
||||
}
|
||||
|
||||
+16
-7
@@ -124,10 +124,10 @@ func (r *Repo) Backup(ctx context.Context, paths []string, progressCallback func
|
||||
args = append(args, paths...)
|
||||
|
||||
cmd := r.commandWithContext(ctx, args, opts...)
|
||||
fullOutput := ioutil.NewOutputCapturer(outputBufferLimit)
|
||||
outputForErr := ioutil.NewOutputCapturer(outputBufferLimit)
|
||||
buf := buffer.New(32 * 1024) // 32KB IO buffer for the realtime event parsing
|
||||
reader, writer := nio.Pipe(buf)
|
||||
r.pipeCmdOutputToWriter(cmd, fullOutput, writer)
|
||||
r.pipeCmdOutputToWriter(cmd, outputForErr, writer)
|
||||
|
||||
var readErr error
|
||||
var summary *BackupProgressEntry
|
||||
@@ -158,7 +158,7 @@ func (r *Repo) Backup(ctx context.Context, paths []string, progressCallback func
|
||||
}
|
||||
}
|
||||
}
|
||||
return summary, newCmdErrorPreformatted(ctx, cmd, string(fullOutput.Bytes()), errors.Join(cmdErr, readErr))
|
||||
return summary, newCmdErrorPreformatted(ctx, cmd, string(outputForErr.Bytes()), errors.Join(cmdErr, readErr))
|
||||
}
|
||||
return summary, nil
|
||||
}
|
||||
@@ -239,9 +239,10 @@ func (r *Repo) Prune(ctx context.Context, pruneOutput io.Writer, opts ...Generic
|
||||
|
||||
func (r *Repo) Restore(ctx context.Context, snapshot string, callback func(*RestoreProgressEntry), opts ...GenericOption) (*RestoreProgressEntry, error) {
|
||||
cmd := r.commandWithContext(ctx, []string{"restore", "--json", snapshot}, opts...)
|
||||
capture := ioutil.NewOutputCapturer(outputBufferLimit) // for error reporting.
|
||||
reader, writer := io.Pipe()
|
||||
r.pipeCmdOutputToWriter(cmd, writer, capture)
|
||||
outputForErr := ioutil.NewOutputCapturer(outputBufferLimit) // for error reporting.
|
||||
buf := buffer.New(32 * 1024) // 32KB IO buffer for the realtime event parsing
|
||||
reader, writer := nio.Pipe(buf)
|
||||
r.pipeCmdOutputToWriter(cmd, writer, outputForErr)
|
||||
|
||||
var readErr error
|
||||
var summary *RestoreProgressEntry
|
||||
@@ -272,7 +273,7 @@ func (r *Repo) Restore(ctx context.Context, snapshot string, callback func(*Rest
|
||||
}
|
||||
}
|
||||
|
||||
return summary, newCmdErrorPreformatted(ctx, cmd, string(capture.Bytes()), errors.Join(cmdErr, readErr))
|
||||
return summary, newCmdErrorPreformatted(ctx, cmd, string(outputForErr.Bytes()), errors.Join(cmdErr, readErr))
|
||||
}
|
||||
return summary, nil
|
||||
}
|
||||
@@ -341,6 +342,14 @@ func (r *Repo) AddTags(ctx context.Context, snapshotIDs []string, tags []string,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *Repo) GenericCommand(ctx context.Context, args []string, opts ...GenericOption) error {
|
||||
cmd := r.commandWithContext(ctx, args, opts...)
|
||||
if err := cmd.Run(); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type RetentionPolicy struct {
|
||||
KeepLastN int // keep the last n snapshots.
|
||||
KeepHourly int // keep the last n hourly snapshots.
|
||||
|
||||
@@ -53,6 +53,9 @@ service Backrest {
|
||||
// GetLogs returns the keyed large data for the given operation.
|
||||
rpc GetLogs(LogDataRequest) returns (types.BytesValue) {}
|
||||
|
||||
// RunCommand executes a generic restic command on the repository.
|
||||
rpc RunCommand(RunCommandRequest) returns (stream types.BytesValue) {}
|
||||
|
||||
// GetDownloadURL returns a signed download URL given a forget operation ID.
|
||||
rpc GetDownloadURL(types.Int64Value) returns (types.StringValue) {}
|
||||
|
||||
@@ -125,3 +128,8 @@ message LsEntry {
|
||||
string atime = 9;
|
||||
string ctime = 10;
|
||||
}
|
||||
|
||||
message RunCommandRequest {
|
||||
string repo_id = 1;
|
||||
string command = 2;
|
||||
}
|
||||
@@ -6,6 +6,88 @@
|
||||
import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf";
|
||||
import { Message, proto3 } from "@bufbuild/protobuf";
|
||||
|
||||
/**
|
||||
* @generated from message v1.HubConfig
|
||||
*/
|
||||
export class HubConfig extends Message<HubConfig> {
|
||||
/**
|
||||
* @generated from field: repeated v1.HubConfig.InstanceInfo instances = 1;
|
||||
*/
|
||||
instances: HubConfig_InstanceInfo[] = [];
|
||||
|
||||
constructor(data?: PartialMessage<HubConfig>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "v1.HubConfig";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "instances", kind: "message", T: HubConfig_InstanceInfo, repeated: true },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): HubConfig {
|
||||
return new HubConfig().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): HubConfig {
|
||||
return new HubConfig().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): HubConfig {
|
||||
return new HubConfig().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: HubConfig | PlainMessage<HubConfig> | undefined, b: HubConfig | PlainMessage<HubConfig> | undefined): boolean {
|
||||
return proto3.util.equals(HubConfig, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message v1.HubConfig.InstanceInfo
|
||||
*/
|
||||
export class HubConfig_InstanceInfo extends Message<HubConfig_InstanceInfo> {
|
||||
/**
|
||||
* @generated from field: string id = 1;
|
||||
*/
|
||||
id = "";
|
||||
|
||||
/**
|
||||
* secret used to authenticate with the hub.
|
||||
*
|
||||
* @generated from field: string secret = 2;
|
||||
*/
|
||||
secret = "";
|
||||
|
||||
constructor(data?: PartialMessage<HubConfig_InstanceInfo>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "v1.HubConfig.InstanceInfo";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 2, name: "secret", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): HubConfig_InstanceInfo {
|
||||
return new HubConfig_InstanceInfo().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): HubConfig_InstanceInfo {
|
||||
return new HubConfig_InstanceInfo().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): HubConfig_InstanceInfo {
|
||||
return new HubConfig_InstanceInfo().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: HubConfig_InstanceInfo | PlainMessage<HubConfig_InstanceInfo> | undefined, b: HubConfig_InstanceInfo | PlainMessage<HubConfig_InstanceInfo> | undefined): boolean {
|
||||
return proto3.util.equals(HubConfig_InstanceInfo, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Config is the top level config object for restic UI.
|
||||
*
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
// @generated by protoc-gen-connect-es v1.3.0 with parameter "target=ts"
|
||||
// @generated from file v1/hub.proto (package v1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import { Empty, MethodKind } from "@bufbuild/protobuf";
|
||||
import { GetInstancesResponse } from "./hub_pb.js";
|
||||
|
||||
/**
|
||||
* @generated from service v1.Hub
|
||||
*/
|
||||
export const Hub = {
|
||||
typeName: "v1.Hub",
|
||||
methods: {
|
||||
/**
|
||||
* GetInstances returns a list of all instances
|
||||
*
|
||||
* @generated from rpc v1.Hub.GetInstances
|
||||
*/
|
||||
getInstances: {
|
||||
name: "GetInstances",
|
||||
I: Empty,
|
||||
O: GetInstancesResponse,
|
||||
kind: MethodKind.Unary,
|
||||
},
|
||||
}
|
||||
} as const;
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
// @generated by protoc-gen-es v1.6.0 with parameter "target=ts"
|
||||
// @generated from file v1/hub.proto (package v1, syntax proto3)
|
||||
/* eslint-disable */
|
||||
// @ts-nocheck
|
||||
|
||||
import type { BinaryReadOptions, FieldList, JsonReadOptions, JsonValue, PartialMessage, PlainMessage } from "@bufbuild/protobuf";
|
||||
import { Message, proto3 } from "@bufbuild/protobuf";
|
||||
|
||||
/**
|
||||
* @generated from message v1.GetInstancesResponse
|
||||
*/
|
||||
export class GetInstancesResponse extends Message<GetInstancesResponse> {
|
||||
/**
|
||||
* @generated from field: repeated v1.Instance instances = 1;
|
||||
*/
|
||||
instances: Instance[] = [];
|
||||
|
||||
constructor(data?: PartialMessage<GetInstancesResponse>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "v1.GetInstancesResponse";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "instances", kind: "message", T: Instance, repeated: true },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): GetInstancesResponse {
|
||||
return new GetInstancesResponse().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): GetInstancesResponse {
|
||||
return new GetInstancesResponse().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): GetInstancesResponse {
|
||||
return new GetInstancesResponse().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: GetInstancesResponse | PlainMessage<GetInstancesResponse> | undefined, b: GetInstancesResponse | PlainMessage<GetInstancesResponse> | undefined): boolean {
|
||||
return proto3.util.equals(GetInstancesResponse, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message v1.Instance
|
||||
*/
|
||||
export class Instance extends Message<Instance> {
|
||||
/**
|
||||
* @generated from field: string id = 1;
|
||||
*/
|
||||
id = "";
|
||||
|
||||
constructor(data?: PartialMessage<Instance>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "v1.Instance";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): Instance {
|
||||
return new Instance().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): Instance {
|
||||
return new Instance().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): Instance {
|
||||
return new Instance().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: Instance | PlainMessage<Instance> | undefined, b: Instance | PlainMessage<Instance> | undefined): boolean {
|
||||
return proto3.util.equals(Instance, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import { Empty, MethodKind } from "@bufbuild/protobuf";
|
||||
import { Config, Repo } from "./config_pb.js";
|
||||
import { OperationEvent, OperationList } from "./operations_pb.js";
|
||||
import { ClearHistoryRequest, ForgetRequest, GetOperationsRequest, ListSnapshotFilesRequest, ListSnapshotFilesResponse, ListSnapshotsRequest, LogDataRequest, RestoreSnapshotRequest } from "./service_pb.js";
|
||||
import { ClearHistoryRequest, ForgetRequest, GetOperationsRequest, ListSnapshotFilesRequest, ListSnapshotFilesResponse, ListSnapshotsRequest, LogDataRequest, RestoreSnapshotRequest, RunCommandRequest } from "./service_pb.js";
|
||||
import { ResticSnapshotList } from "./restic_pb.js";
|
||||
import { BytesValue, Int64Value, StringList, StringValue } from "../types/value_pb.js";
|
||||
|
||||
@@ -178,6 +178,17 @@ export const Backrest = {
|
||||
O: BytesValue,
|
||||
kind: MethodKind.Unary,
|
||||
},
|
||||
/**
|
||||
* RunCommand executes a generic restic command on the repository.
|
||||
*
|
||||
* @generated from rpc v1.Backrest.RunCommand
|
||||
*/
|
||||
runCommand: {
|
||||
name: "RunCommand",
|
||||
I: RunCommandRequest,
|
||||
O: BytesValue,
|
||||
kind: MethodKind.ServerStreaming,
|
||||
},
|
||||
/**
|
||||
* GetDownloadURL returns a signed download URL given a forget operation ID.
|
||||
*
|
||||
|
||||
@@ -503,3 +503,46 @@ export class LsEntry extends Message<LsEntry> {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @generated from message v1.RunCommandRequest
|
||||
*/
|
||||
export class RunCommandRequest extends Message<RunCommandRequest> {
|
||||
/**
|
||||
* @generated from field: string repo_id = 1;
|
||||
*/
|
||||
repoId = "";
|
||||
|
||||
/**
|
||||
* @generated from field: string command = 2;
|
||||
*/
|
||||
command = "";
|
||||
|
||||
constructor(data?: PartialMessage<RunCommandRequest>) {
|
||||
super();
|
||||
proto3.util.initPartial(data, this);
|
||||
}
|
||||
|
||||
static readonly runtime: typeof proto3 = proto3;
|
||||
static readonly typeName = "v1.RunCommandRequest";
|
||||
static readonly fields: FieldList = proto3.util.newFieldList(() => [
|
||||
{ no: 1, name: "repo_id", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
{ no: 2, name: "command", kind: "scalar", T: 9 /* ScalarType.STRING */ },
|
||||
]);
|
||||
|
||||
static fromBinary(bytes: Uint8Array, options?: Partial<BinaryReadOptions>): RunCommandRequest {
|
||||
return new RunCommandRequest().fromBinary(bytes, options);
|
||||
}
|
||||
|
||||
static fromJson(jsonValue: JsonValue, options?: Partial<JsonReadOptions>): RunCommandRequest {
|
||||
return new RunCommandRequest().fromJson(jsonValue, options);
|
||||
}
|
||||
|
||||
static fromJsonString(jsonString: string, options?: Partial<JsonReadOptions>): RunCommandRequest {
|
||||
return new RunCommandRequest().fromJsonString(jsonString, options);
|
||||
}
|
||||
|
||||
static equals(a: RunCommandRequest | PlainMessage<RunCommandRequest> | undefined, b: RunCommandRequest | PlainMessage<RunCommandRequest> | undefined): boolean {
|
||||
return proto3.util.equals(RunCommandRequest, a, b);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
{
|
||||
"tabWidth": 2,
|
||||
"useTabs": false
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { Plan } from "../../gen/ts/v1/config_pb";
|
||||
import { Flex, Tabs, Tooltip, Typography } from "antd";
|
||||
import { Button, Flex, Tabs, Tooltip, Typography } from "antd";
|
||||
import { useAlertApi } from "../components/Alerts";
|
||||
import { OperationList } from "../components/OperationList";
|
||||
import { OperationTree } from "../components/OperationTree";
|
||||
@@ -9,9 +9,11 @@ import { backrestService } from "../api";
|
||||
import { GetOperationsRequest } from "../../gen/ts/v1/service_pb";
|
||||
import { SpinButton } from "../components/SpinButton";
|
||||
import { shouldHideStatus } from "../state/oplog";
|
||||
import { useShowModal } from "../components/ModalManager";
|
||||
|
||||
export const PlanView = ({ plan }: React.PropsWithChildren<{ plan: Plan }>) => {
|
||||
const alertsApi = useAlertApi()!;
|
||||
const showModal = useShowModal();
|
||||
|
||||
const handleBackupNow = async () => {
|
||||
try {
|
||||
@@ -77,6 +79,14 @@ export const PlanView = ({ plan }: React.PropsWithChildren<{ plan: Plan }>) => {
|
||||
Clear Error History
|
||||
</SpinButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Open a restic shell to run commands on the repository.">
|
||||
<Button type="default" onClick={async () => {
|
||||
const { RunCommandModal } = await import("./RunCommandModal");
|
||||
showModal(<RunCommandModal repoId={plan.repo!} />);
|
||||
}}>
|
||||
Run Command
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
<Tabs
|
||||
defaultActiveKey="1"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React, { useContext, useEffect, useState } from "react";
|
||||
import { Repo } from "../../gen/ts/v1/config_pb";
|
||||
import { Col, Empty, Flex, Row, Spin, TabsProps, Tabs, Tooltip, Typography } from "antd";
|
||||
import { Col, Empty, Flex, Row, Spin, TabsProps, Tabs, Tooltip, Typography, Button } from "antd";
|
||||
import { OperationList } from "../components/OperationList";
|
||||
import { OperationTree } from "../components/OperationTree";
|
||||
import { MAX_OPERATION_HISTORY, STATS_OPERATION_HISTORY } from "../constants";
|
||||
@@ -14,10 +14,12 @@ import { SpinButton } from "../components/SpinButton";
|
||||
import { useConfig } from "../components/ConfigProvider";
|
||||
import { useAlertApi } from "../components/Alerts";
|
||||
import { LineChart } from "@mui/x-charts";
|
||||
import { useShowModal } from "../components/ModalManager";
|
||||
|
||||
|
||||
export const RepoView = ({ repo }: React.PropsWithChildren<{ repo: Repo }>) => {
|
||||
const [config, setConfig] = useConfig();
|
||||
const showModal = useShowModal();
|
||||
|
||||
// Task handlers
|
||||
const handleIndexNow = async () => {
|
||||
@@ -99,6 +101,14 @@ export const RepoView = ({ repo }: React.PropsWithChildren<{ repo: Repo }>) => {
|
||||
Compute Stats
|
||||
</SpinButton>
|
||||
</Tooltip>
|
||||
<Tooltip title="Open a restic shell to run commands on the repository.">
|
||||
<Button type="default" onClick={async () => {
|
||||
const { RunCommandModal } = await import("./RunCommandModal");
|
||||
showModal(<RunCommandModal repoId={repo.id!} />);
|
||||
}}>
|
||||
Run Command
|
||||
</Button>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
<Tabs
|
||||
defaultActiveKey={items[0].key}
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
import { Button, Input, Modal, Space } from "antd";
|
||||
import React from "react";
|
||||
import { useShowModal } from "../components/ModalManager";
|
||||
import { backrestService } from "../api";
|
||||
import { SpinButton } from "../components/SpinButton";
|
||||
import { ConnectError } from "@connectrpc/connect";
|
||||
|
||||
|
||||
interface Invocation {
|
||||
command: string;
|
||||
output: string;
|
||||
error: string;
|
||||
}
|
||||
|
||||
|
||||
export const RunCommandModal = ({ repoId }: { repoId: string }) => {
|
||||
const showModal = useShowModal();
|
||||
const [command, setCommand] = React.useState("");
|
||||
const [running, setRunning] = React.useState(false);
|
||||
const [invocations, setInvocations] = React.useState<Invocation[]>([]);
|
||||
|
||||
const handleCancel = () => {
|
||||
showModal(null);
|
||||
}
|
||||
|
||||
const doExecute = async () => {
|
||||
if (running) return;
|
||||
setRunning(true);
|
||||
|
||||
const newInvocation = { command, output: "", error: "" };
|
||||
setInvocations((invocations) => [newInvocation, ...invocations]);
|
||||
|
||||
let segments: string[] = [];
|
||||
|
||||
try {
|
||||
for await (const bytes of backrestService.runCommand({ repoId, command })) {
|
||||
const output = new TextDecoder("utf-8").decode(bytes.value);
|
||||
segments.push(output);
|
||||
setInvocations((invocations) => {
|
||||
const copy = [...invocations];
|
||||
copy[0] = {
|
||||
...copy[0],
|
||||
output: segments.join(""),
|
||||
}
|
||||
return copy;
|
||||
});
|
||||
}
|
||||
} catch (e: any) {
|
||||
setInvocations((invocations) => {
|
||||
const copy = [...invocations];
|
||||
copy[0] = {
|
||||
...copy[0],
|
||||
error: (e as Error).message,
|
||||
}
|
||||
return copy;
|
||||
});
|
||||
} finally {
|
||||
setRunning(false);
|
||||
}
|
||||
}
|
||||
|
||||
return <Modal
|
||||
open={true}
|
||||
onCancel={handleCancel}
|
||||
title={"Run Command in repo " + repoId}
|
||||
width="80vw"
|
||||
footer={[]}
|
||||
>
|
||||
<Space.Compact style={{ width: '100%' }}>
|
||||
<Input placeholder="Run a restic comamnd e.g. 'help' to print help text" onChange={(e) => setCommand(e.target.value)} onKeyUp={(e) => {
|
||||
if (e.key === "Enter") {
|
||||
doExecute();
|
||||
}
|
||||
}} />
|
||||
<SpinButton type="primary" onClickAsync={doExecute}>Execute</SpinButton>
|
||||
</Space.Compact>
|
||||
{invocations.map((invocation, i) => <div key={i}>
|
||||
{invocation.output ? <pre>{invocation.output}</pre> : null}
|
||||
{invocation.error ? <pre style={{ color: "red" }}>{invocation.error}</pre> : null}
|
||||
</div>)}
|
||||
</Modal>
|
||||
}
|
||||
Reference in New Issue
Block a user