feat: implement repo, edit, and supporting RPCs

This commit is contained in:
garethgeorge
2023-11-11 23:38:50 -08:00
parent a6fdb46b09
commit d282c32c8b
33 changed files with 1318 additions and 458 deletions

View File

@@ -10,7 +10,9 @@ import (
"syscall"
"github.com/garethgeorge/resticui/internal/api"
"github.com/garethgeorge/resticui/static"
"github.com/garethgeorge/resticui/internal/config"
"github.com/garethgeorge/resticui/internal/orchestrator"
static "github.com/garethgeorge/resticui/webui"
"go.uber.org/zap"
_ "embed"
@@ -21,6 +23,10 @@ func main() {
ctx, cancel := context.WithCancel(ctx)
go onterm(cancel)
if _, err := config.Default.Get(); err != nil {
zap.S().Fatalf("Error loading config: %v", err)
}
var wg sync.WaitGroup
// Configure the HTTP mux
@@ -32,11 +38,13 @@ func main() {
Handler: mux,
}
orchestrator := orchestrator.NewOrchestrator(config.Default)
// Serve the API
wg.Add(1)
go func() {
defer wg.Done()
err := api.ServeAPI(ctx, mux)
err := api.ServeAPI(ctx, orchestrator, mux)
if err != nil {
zap.S().Fatal("Error serving API", zap.Error(err))
}

View File

@@ -25,7 +25,10 @@ type Config struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Version int32 `protobuf:"varint,1,opt,name=version,proto3" json:"version,omitempty"`
// modification number, used for read-modify-write consistency in the UI. Incremented on every write.
Modno int32 `protobuf:"varint,1,opt,name=modno,proto3" json:"modno,omitempty"`
// override the hostname tagged on backups. If provided it will be used in addition to tags to group backups.
HostOverride string `protobuf:"bytes,2,opt,name=host_override,proto3" json:"host_override,omitempty"`
Repos []*Repo `protobuf:"bytes,3,rep,name=repos,proto3" json:"repos,omitempty"`
Plans []*Plan `protobuf:"bytes,4,rep,name=plans,proto3" json:"plans,omitempty"`
}
@@ -62,13 +65,20 @@ func (*Config) Descriptor() ([]byte, []int) {
return file_v1_config_proto_rawDescGZIP(), []int{0}
}
func (x *Config) GetVersion() int32 {
func (x *Config) GetModno() int32 {
if x != nil {
return x.Version
return x.Modno
}
return 0
}
func (x *Config) GetHostOverride() string {
if x != nil {
return x.HostOverride
}
return ""
}
func (x *Config) GetRepos() []*Repo {
if x != nil {
return x.Repos
@@ -83,61 +93,6 @@ func (x *Config) GetPlans() []*Plan {
return nil
}
type User struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"`
Password string `protobuf:"bytes,2,opt,name=password,proto3" json:"password,omitempty"` // plaintext password
}
func (x *User) Reset() {
*x = User{}
if protoimpl.UnsafeEnabled {
mi := &file_v1_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *User) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*User) ProtoMessage() {}
func (x *User) ProtoReflect() protoreflect.Message {
mi := &file_v1_config_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 User.ProtoReflect.Descriptor instead.
func (*User) Descriptor() ([]byte, []int) {
return file_v1_config_proto_rawDescGZIP(), []int{1}
}
func (x *User) GetName() string {
if x != nil {
return x.Name
}
return ""
}
func (x *User) GetPassword() string {
if x != nil {
return x.Password
}
return ""
}
type Repo struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -153,7 +108,7 @@ type Repo struct {
func (x *Repo) Reset() {
*x = Repo{}
if protoimpl.UnsafeEnabled {
mi := &file_v1_config_proto_msgTypes[2]
mi := &file_v1_config_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -166,7 +121,7 @@ func (x *Repo) String() string {
func (*Repo) ProtoMessage() {}
func (x *Repo) ProtoReflect() protoreflect.Message {
mi := &file_v1_config_proto_msgTypes[2]
mi := &file_v1_config_proto_msgTypes[1]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -179,7 +134,7 @@ func (x *Repo) ProtoReflect() protoreflect.Message {
// Deprecated: Use Repo.ProtoReflect.Descriptor instead.
func (*Repo) Descriptor() ([]byte, []int) {
return file_v1_config_proto_rawDescGZIP(), []int{2}
return file_v1_config_proto_rawDescGZIP(), []int{1}
}
func (x *Repo) GetId() string {
@@ -233,7 +188,7 @@ type Plan struct {
func (x *Plan) Reset() {
*x = Plan{}
if protoimpl.UnsafeEnabled {
mi := &file_v1_config_proto_msgTypes[3]
mi := &file_v1_config_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -246,7 +201,7 @@ func (x *Plan) String() string {
func (*Plan) ProtoMessage() {}
func (x *Plan) ProtoReflect() protoreflect.Message {
mi := &file_v1_config_proto_msgTypes[3]
mi := &file_v1_config_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -259,7 +214,7 @@ func (x *Plan) ProtoReflect() protoreflect.Message {
// Deprecated: Use Plan.ProtoReflect.Descriptor instead.
func (*Plan) Descriptor() ([]byte, []int) {
return file_v1_config_proto_rawDescGZIP(), []int{3}
return file_v1_config_proto_rawDescGZIP(), []int{2}
}
func (x *Plan) GetId() string {
@@ -323,7 +278,7 @@ type RetentionPolicy struct {
func (x *RetentionPolicy) Reset() {
*x = RetentionPolicy{}
if protoimpl.UnsafeEnabled {
mi := &file_v1_config_proto_msgTypes[4]
mi := &file_v1_config_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -336,7 +291,7 @@ func (x *RetentionPolicy) String() string {
func (*RetentionPolicy) ProtoMessage() {}
func (x *RetentionPolicy) ProtoReflect() protoreflect.Message {
mi := &file_v1_config_proto_msgTypes[4]
mi := &file_v1_config_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -349,7 +304,7 @@ func (x *RetentionPolicy) ProtoReflect() protoreflect.Message {
// Deprecated: Use RetentionPolicy.ProtoReflect.Descriptor instead.
func (*RetentionPolicy) Descriptor() ([]byte, []int) {
return file_v1_config_proto_rawDescGZIP(), []int{4}
return file_v1_config_proto_rawDescGZIP(), []int{3}
}
func (x *RetentionPolicy) GetMaxUnusedLimit() string {
@@ -412,57 +367,55 @@ var File_v1_config_proto protoreflect.FileDescriptor
var file_v1_config_proto_rawDesc = []byte{
0x0a, 0x0f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x12, 0x02, 0x76, 0x31, 0x22, 0x62, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x18, 0x0a, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05,
0x52, 0x07, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x0a, 0x05, 0x72, 0x65, 0x70,
0x6f, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65,
0x70, 0x6f, 0x52, 0x05, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x12, 0x1e, 0x0a, 0x05, 0x70, 0x6c, 0x61,
0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x50, 0x6c,
0x61, 0x6e, 0x52, 0x05, 0x70, 0x6c, 0x61, 0x6e, 0x73, 0x22, 0x36, 0x0a, 0x04, 0x55, 0x73, 0x65,
0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72,
0x64, 0x22, 0x6c, 0x0a, 0x04, 0x52, 0x65, 0x70, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18,
0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x1a, 0x0a, 0x08, 0x70,
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70,
0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x04,
0x20, 0x03, 0x28, 0x09, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61,
0x67, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x22,
0xa3, 0x01, 0x0a, 0x04, 0x50, 0x6c, 0x61, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f,
0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x12, 0x14, 0x0a, 0x05,
0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x70, 0x61, 0x74,
0x68, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x18, 0x05,
0x20, 0x03, 0x28, 0x09, 0x52, 0x08, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x12, 0x12,
0x0a, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x72,
0x6f, 0x6e, 0x12, 0x31, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x18,
0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x74, 0x65, 0x6e,
0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x09, 0x72, 0x65, 0x74, 0x65,
0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xb2, 0x02, 0x0a, 0x0f, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74,
0x69, 0x6f, 0x6e, 0x50, 0x6f, 0x6c, 0x69, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x78,
0x5f, 0x75, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20,
0x01, 0x28, 0x09, 0x52, 0x0e, 0x6d, 0x61, 0x78, 0x55, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x4c, 0x69,
0x6d, 0x69, 0x74, 0x12, 0x1e, 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x6c, 0x61, 0x73, 0x74,
0x5f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x4c, 0x61,
0x73, 0x74, 0x4e, 0x12, 0x1f, 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x68, 0x6f, 0x75, 0x72,
0x6c, 0x79, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x48, 0x6f,
0x75, 0x72, 0x6c, 0x79, 0x12, 0x1d, 0x0a, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x64, 0x61, 0x69,
0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x44, 0x61,
0x69, 0x6c, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x77, 0x65, 0x65, 0x6b,
0x6c, 0x79, 0x18, 0x05, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x57, 0x65,
0x65, 0x6b, 0x6c, 0x79, 0x12, 0x21, 0x0a, 0x0c, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x6d, 0x6f, 0x6e,
0x74, 0x68, 0x6c, 0x79, 0x18, 0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6b, 0x65, 0x65, 0x70,
0x4d, 0x6f, 0x6e, 0x74, 0x68, 0x6c, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f,
0x79, 0x65, 0x61, 0x72, 0x6c, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6b, 0x65,
0x65, 0x70, 0x59, 0x65, 0x61, 0x72, 0x6c, 0x79, 0x12, 0x30, 0x0a, 0x14, 0x6b, 0x65, 0x65, 0x70,
0x5f, 0x77, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e,
0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x6b, 0x65, 0x65, 0x70, 0x57, 0x69, 0x74, 0x68,
0x69, 0x6e, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69,
0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72, 0x65, 0x74, 0x68, 0x67,
0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x69, 0x63, 0x75, 0x69, 0x2f, 0x67,
0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
0x6f, 0x12, 0x02, 0x76, 0x31, 0x22, 0x84, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67,
0x12, 0x14, 0x0a, 0x05, 0x6d, 0x6f, 0x64, 0x6e, 0x6f, 0x18, 0x01, 0x20, 0x01, 0x28, 0x05, 0x52,
0x05, 0x6d, 0x6f, 0x64, 0x6e, 0x6f, 0x12, 0x24, 0x0a, 0x0d, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x6f,
0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x68,
0x6f, 0x73, 0x74, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x12, 0x1e, 0x0a, 0x05,
0x72, 0x65, 0x70, 0x6f, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31,
0x2e, 0x52, 0x65, 0x70, 0x6f, 0x52, 0x05, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x12, 0x1e, 0x0a, 0x05,
0x70, 0x6c, 0x61, 0x6e, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x76, 0x31,
0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x05, 0x70, 0x6c, 0x61, 0x6e, 0x73, 0x22, 0x6c, 0x0a, 0x04,
0x52, 0x65, 0x70, 0x6f, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x02, 0x69, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x69, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x03, 0x75, 0x72, 0x69, 0x12, 0x1a, 0x0a, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
0x72, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f,
0x72, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52,
0x03, 0x65, 0x6e, 0x76, 0x12, 0x14, 0x0a, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x18, 0x05, 0x20,
0x03, 0x28, 0x09, 0x52, 0x05, 0x66, 0x6c, 0x61, 0x67, 0x73, 0x22, 0xa3, 0x01, 0x0a, 0x04, 0x50,
0x6c, 0x61, 0x6e, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x18, 0x02, 0x20, 0x01, 0x28,
0x09, 0x52, 0x04, 0x72, 0x65, 0x70, 0x6f, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73,
0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x12, 0x1a, 0x0a,
0x08, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52,
0x08, 0x65, 0x78, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x72, 0x6f,
0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x63, 0x72, 0x6f, 0x6e, 0x12, 0x31, 0x0a,
0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b,
0x32, 0x13, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50,
0x6f, 0x6c, 0x69, 0x63, 0x79, 0x52, 0x09, 0x72, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e,
0x22, 0xb2, 0x02, 0x0a, 0x0f, 0x52, 0x65, 0x74, 0x65, 0x6e, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x6f,
0x6c, 0x69, 0x63, 0x79, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x6e, 0x75, 0x73,
0x65, 0x64, 0x5f, 0x6c, 0x69, 0x6d, 0x69, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e,
0x6d, 0x61, 0x78, 0x55, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x12, 0x1e,
0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x6c, 0x61, 0x73, 0x74, 0x5f, 0x6e, 0x18, 0x02, 0x20,
0x01, 0x28, 0x05, 0x52, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x4c, 0x61, 0x73, 0x74, 0x4e, 0x12, 0x1f,
0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x68, 0x6f, 0x75, 0x72, 0x6c, 0x79, 0x18, 0x03, 0x20,
0x01, 0x28, 0x05, 0x52, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x48, 0x6f, 0x75, 0x72, 0x6c, 0x79, 0x12,
0x1d, 0x0a, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x18, 0x04, 0x20,
0x01, 0x28, 0x05, 0x52, 0x09, 0x6b, 0x65, 0x65, 0x70, 0x44, 0x61, 0x69, 0x6c, 0x79, 0x12, 0x1f,
0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x77, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x18, 0x05, 0x20,
0x01, 0x28, 0x05, 0x52, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x57, 0x65, 0x65, 0x6b, 0x6c, 0x79, 0x12,
0x21, 0x0a, 0x0c, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x6d, 0x6f, 0x6e, 0x74, 0x68, 0x6c, 0x79, 0x18,
0x06, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x4d, 0x6f, 0x6e, 0x74, 0x68,
0x6c, 0x79, 0x12, 0x1f, 0x0a, 0x0b, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x79, 0x65, 0x61, 0x72, 0x6c,
0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0a, 0x6b, 0x65, 0x65, 0x70, 0x59, 0x65, 0x61,
0x72, 0x6c, 0x79, 0x12, 0x30, 0x0a, 0x14, 0x6b, 0x65, 0x65, 0x70, 0x5f, 0x77, 0x69, 0x74, 0x68,
0x69, 0x6e, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x08, 0x20, 0x01, 0x28,
0x09, 0x52, 0x12, 0x6b, 0x65, 0x65, 0x70, 0x57, 0x69, 0x74, 0x68, 0x69, 0x6e, 0x44, 0x75, 0x72,
0x61, 0x74, 0x69, 0x6f, 0x6e, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72, 0x65, 0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65,
0x2f, 0x72, 0x65, 0x73, 0x74, 0x69, 0x63, 0x75, 0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f,
0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -477,18 +430,17 @@ func file_v1_config_proto_rawDescGZIP() []byte {
return file_v1_config_proto_rawDescData
}
var file_v1_config_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_v1_config_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_v1_config_proto_goTypes = []interface{}{
(*Config)(nil), // 0: v1.Config
(*User)(nil), // 1: v1.User
(*Repo)(nil), // 2: v1.Repo
(*Plan)(nil), // 3: v1.Plan
(*RetentionPolicy)(nil), // 4: v1.RetentionPolicy
(*Repo)(nil), // 1: v1.Repo
(*Plan)(nil), // 2: v1.Plan
(*RetentionPolicy)(nil), // 3: v1.RetentionPolicy
}
var file_v1_config_proto_depIdxs = []int32{
2, // 0: v1.Config.repos:type_name -> v1.Repo
3, // 1: v1.Config.plans:type_name -> v1.Plan
4, // 2: v1.Plan.retention:type_name -> v1.RetentionPolicy
1, // 0: v1.Config.repos:type_name -> v1.Repo
2, // 1: v1.Config.plans:type_name -> v1.Plan
3, // 2: v1.Plan.retention:type_name -> v1.RetentionPolicy
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
@@ -515,18 +467,6 @@ func file_v1_config_proto_init() {
}
}
file_v1_config_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*User); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_v1_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Repo); i {
case 0:
return &v.state
@@ -538,7 +478,7 @@ func file_v1_config_proto_init() {
return nil
}
}
file_v1_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
file_v1_config_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*Plan); i {
case 0:
return &v.state
@@ -550,7 +490,7 @@ func file_v1_config_proto_init() {
return nil
}
}
file_v1_config_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
file_v1_config_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*RetentionPolicy); i {
case 0:
return &v.state
@@ -569,7 +509,7 @@ func file_v1_config_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_v1_config_proto_rawDesc,
NumEnums: 0,
NumMessages: 5,
NumMessages: 4,
NumExtensions: 0,
NumServices: 0,
},

View File

@@ -155,7 +155,7 @@ type Event_Log struct {
}
type Event_BackupStatusChange struct {
BackupStatusChange *BackupStatusEvent `protobuf:"bytes,4,opt,name=backup_status_change,json=backup_status,proto3,oneof"`
BackupStatusChange *BackupStatusEvent `protobuf:"bytes,4,opt,name=backup_status_change,json=backupStatusChange,proto3,oneof"`
}
func (*Event_Log) isEvent_Event() {}
@@ -276,33 +276,33 @@ var File_v1_events_proto protoreflect.FileDescriptor
var file_v1_events_proto_rawDesc = []byte{
0x0a, 0x0f, 0x76, 0x31, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x12, 0x02, 0x76, 0x31, 0x22, 0x96, 0x01, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12,
0x6f, 0x12, 0x02, 0x76, 0x31, 0x22, 0x9b, 0x01, 0x0a, 0x05, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12,
0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x01, 0x20, 0x01,
0x28, 0x03, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x20, 0x0a,
0x03, 0x6c, 0x6f, 0x67, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0c, 0x2e, 0x76, 0x31, 0x2e,
0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12,
0x44, 0x0a, 0x14, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
0x49, 0x0a, 0x14, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73,
0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e,
0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x45,
0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x5f, 0x73,
0x74, 0x61, 0x74, 0x75, 0x73, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x24,
0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x6d, 0x65,
0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x6d, 0x65, 0x73,
0x73, 0x61, 0x67, 0x65, 0x22, 0x65, 0x0a, 0x11, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x74,
0x61, 0x74, 0x75, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61,
0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x22, 0x0a,
0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e,
0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01,
0x28, 0x0d, 0x52, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x2a, 0x3f, 0x0a, 0x06, 0x53,
0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e,
0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x5f, 0x50, 0x52, 0x4f, 0x47, 0x52, 0x45, 0x53,
0x53, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x02,
0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x42, 0x2e, 0x5a, 0x2c,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72, 0x65, 0x74,
0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x69, 0x63, 0x75, 0x69,
0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
0x76, 0x65, 0x6e, 0x74, 0x48, 0x00, 0x52, 0x12, 0x62, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x53, 0x74,
0x61, 0x74, 0x75, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x76,
0x65, 0x6e, 0x74, 0x22, 0x24, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12,
0x18, 0x0a, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
0x52, 0x07, 0x6d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x22, 0x65, 0x0a, 0x11, 0x42, 0x61, 0x63,
0x6b, 0x75, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x12, 0x12,
0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x6c,
0x61, 0x6e, 0x12, 0x22, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x76, 0x31, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06,
0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x18, 0x0a, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e,
0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74,
0x2a, 0x3f, 0x0a, 0x06, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x0b, 0x0a, 0x07, 0x55, 0x4e,
0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x49, 0x4e, 0x5f, 0x50, 0x52,
0x4f, 0x47, 0x52, 0x45, 0x53, 0x53, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43,
0x45, 0x53, 0x53, 0x10, 0x02, 0x12, 0x0a, 0x0a, 0x06, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x10,
0x03, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
0x67, 0x61, 0x72, 0x65, 0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x72, 0x65, 0x73,
0x74, 0x69, 0x63, 0x75, 0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76,
0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (

View File

@@ -26,7 +26,7 @@ type ResticSnapshot struct {
unknownFields protoimpl.UnknownFields
Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"`
UnixTimeMs int64 `protobuf:"varint,2,opt,name=unix_time_ms,json=time,proto3" json:"unix_time_ms,omitempty"`
UnixTimeMs int64 `protobuf:"varint,2,opt,name=unix_time_ms,json=unixTimeMs,proto3" json:"unix_time_ms,omitempty"`
Hostname string `protobuf:"bytes,3,opt,name=hostname,proto3" json:"hostname,omitempty"`
Username string `protobuf:"bytes,4,opt,name=username,proto3" json:"username,omitempty"`
Tree string `protobuf:"bytes,5,opt,name=tree,proto3" json:"tree,omitempty"` // tree hash
@@ -123,6 +123,53 @@ func (x *ResticSnapshot) GetTags() []string {
return nil
}
type ResticSnapshotList struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Snapshots []*ResticSnapshot `protobuf:"bytes,1,rep,name=snapshots,proto3" json:"snapshots,omitempty"`
}
func (x *ResticSnapshotList) Reset() {
*x = ResticSnapshotList{}
if protoimpl.UnsafeEnabled {
mi := &file_v1_restic_proto_msgTypes[1]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ResticSnapshotList) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ResticSnapshotList) ProtoMessage() {}
func (x *ResticSnapshotList) ProtoReflect() protoreflect.Message {
mi := &file_v1_restic_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 ResticSnapshotList.ProtoReflect.Descriptor instead.
func (*ResticSnapshotList) Descriptor() ([]byte, []int) {
return file_v1_restic_proto_rawDescGZIP(), []int{1}
}
func (x *ResticSnapshotList) GetSnapshots() []*ResticSnapshot {
if x != nil {
return x.Snapshots
}
return nil
}
type BackupProgressEntry struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -138,7 +185,7 @@ type BackupProgressEntry struct {
func (x *BackupProgressEntry) Reset() {
*x = BackupProgressEntry{}
if protoimpl.UnsafeEnabled {
mi := &file_v1_restic_proto_msgTypes[1]
mi := &file_v1_restic_proto_msgTypes[2]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -151,7 +198,7 @@ func (x *BackupProgressEntry) String() string {
func (*BackupProgressEntry) ProtoMessage() {}
func (x *BackupProgressEntry) ProtoReflect() protoreflect.Message {
mi := &file_v1_restic_proto_msgTypes[1]
mi := &file_v1_restic_proto_msgTypes[2]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -164,7 +211,7 @@ func (x *BackupProgressEntry) ProtoReflect() protoreflect.Message {
// Deprecated: Use BackupProgressEntry.ProtoReflect.Descriptor instead.
func (*BackupProgressEntry) Descriptor() ([]byte, []int) {
return file_v1_restic_proto_rawDescGZIP(), []int{1}
return file_v1_restic_proto_rawDescGZIP(), []int{2}
}
func (m *BackupProgressEntry) GetEntry() isBackupProgressEntry_Entry {
@@ -209,17 +256,17 @@ type BackupProgressStatusEntry struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
PercentDone float64 `protobuf:"fixed64,1,opt,name=percent_done,json=percent,proto3" json:"percent_done,omitempty"` // 0.0 - 1.0
TotalFiles int64 `protobuf:"varint,2,opt,name=total_files,proto3" json:"total_files,omitempty"`
TotalBytes int64 `protobuf:"varint,3,opt,name=total_bytes,proto3" json:"total_bytes,omitempty"`
FilesDone int64 `protobuf:"varint,4,opt,name=files_done,proto3" json:"files_done,omitempty"`
BytesDone int64 `protobuf:"varint,5,opt,name=bytes_done,proto3" json:"bytes_done,omitempty"`
PercentDone float64 `protobuf:"fixed64,1,opt,name=percent_done,json=percentDone,proto3" json:"percent_done,omitempty"` // 0.0 - 1.0
TotalFiles int64 `protobuf:"varint,2,opt,name=total_files,json=totalFiles,proto3" json:"total_files,omitempty"`
TotalBytes int64 `protobuf:"varint,3,opt,name=total_bytes,json=totalBytes,proto3" json:"total_bytes,omitempty"`
FilesDone int64 `protobuf:"varint,4,opt,name=files_done,json=filesDone,proto3" json:"files_done,omitempty"`
BytesDone int64 `protobuf:"varint,5,opt,name=bytes_done,json=bytesDone,proto3" json:"bytes_done,omitempty"`
}
func (x *BackupProgressStatusEntry) Reset() {
*x = BackupProgressStatusEntry{}
if protoimpl.UnsafeEnabled {
mi := &file_v1_restic_proto_msgTypes[2]
mi := &file_v1_restic_proto_msgTypes[3]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -232,7 +279,7 @@ func (x *BackupProgressStatusEntry) String() string {
func (*BackupProgressStatusEntry) ProtoMessage() {}
func (x *BackupProgressStatusEntry) ProtoReflect() protoreflect.Message {
mi := &file_v1_restic_proto_msgTypes[2]
mi := &file_v1_restic_proto_msgTypes[3]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -245,7 +292,7 @@ func (x *BackupProgressStatusEntry) ProtoReflect() protoreflect.Message {
// Deprecated: Use BackupProgressStatusEntry.ProtoReflect.Descriptor instead.
func (*BackupProgressStatusEntry) Descriptor() ([]byte, []int) {
return file_v1_restic_proto_rawDescGZIP(), []int{2}
return file_v1_restic_proto_rawDescGZIP(), []int{3}
}
func (x *BackupProgressStatusEntry) GetPercentDone() float64 {
@@ -288,25 +335,25 @@ type BackupProgressSummary struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
FilesNew int64 `protobuf:"varint,1,opt,name=files_new,proto3" json:"files_new,omitempty"`
FilesChanged int64 `protobuf:"varint,2,opt,name=files_changed,proto3" json:"files_changed,omitempty"`
FilesUnmodified int64 `protobuf:"varint,3,opt,name=files_unmodified,proto3" json:"files_unmodified,omitempty"`
DirsNew int64 `protobuf:"varint,4,opt,name=dirs_new,proto3" json:"dirs_new,omitempty"`
DirsChanged int64 `protobuf:"varint,5,opt,name=dirs_changed,proto3" json:"dirs_changed,omitempty"`
DirsUnmodified int64 `protobuf:"varint,6,opt,name=dirs_unmodified,proto3" json:"dirs_unmodified,omitempty"`
DataBlobs int64 `protobuf:"varint,7,opt,name=data_blobs,proto3" json:"data_blobs,omitempty"`
TreeBlobs int64 `protobuf:"varint,8,opt,name=tree_blobs,proto3" json:"tree_blobs,omitempty"`
DataAdded int64 `protobuf:"varint,9,opt,name=data_added,proto3" json:"data_added,omitempty"`
TotalFilesProcessed int64 `protobuf:"varint,10,opt,name=total_files_processed,proto3" json:"total_files_processed,omitempty"`
TotalBytesProcessed int64 `protobuf:"varint,11,opt,name=total_bytes_processed,proto3" json:"total_bytes_processed,omitempty"`
TotalDuration int64 `protobuf:"varint,12,opt,name=total_duration,proto3" json:"total_duration,omitempty"`
SnapshotId string `protobuf:"bytes,13,opt,name=snapshot_id,proto3" json:"snapshot_id,omitempty"`
FilesNew int64 `protobuf:"varint,1,opt,name=files_new,json=filesNew,proto3" json:"files_new,omitempty"`
FilesChanged int64 `protobuf:"varint,2,opt,name=files_changed,json=filesChanged,proto3" json:"files_changed,omitempty"`
FilesUnmodified int64 `protobuf:"varint,3,opt,name=files_unmodified,json=filesUnmodified,proto3" json:"files_unmodified,omitempty"`
DirsNew int64 `protobuf:"varint,4,opt,name=dirs_new,json=dirsNew,proto3" json:"dirs_new,omitempty"`
DirsChanged int64 `protobuf:"varint,5,opt,name=dirs_changed,json=dirsChanged,proto3" json:"dirs_changed,omitempty"`
DirsUnmodified int64 `protobuf:"varint,6,opt,name=dirs_unmodified,json=dirsUnmodified,proto3" json:"dirs_unmodified,omitempty"`
DataBlobs int64 `protobuf:"varint,7,opt,name=data_blobs,json=dataBlobs,proto3" json:"data_blobs,omitempty"`
TreeBlobs int64 `protobuf:"varint,8,opt,name=tree_blobs,json=treeBlobs,proto3" json:"tree_blobs,omitempty"`
DataAdded int64 `protobuf:"varint,9,opt,name=data_added,json=dataAdded,proto3" json:"data_added,omitempty"`
TotalFilesProcessed int64 `protobuf:"varint,10,opt,name=total_files_processed,json=totalFilesProcessed,proto3" json:"total_files_processed,omitempty"`
TotalBytesProcessed int64 `protobuf:"varint,11,opt,name=total_bytes_processed,json=totalBytesProcessed,proto3" json:"total_bytes_processed,omitempty"`
TotalDuration int64 `protobuf:"varint,12,opt,name=total_duration,json=totalDuration,proto3" json:"total_duration,omitempty"`
SnapshotId string `protobuf:"bytes,13,opt,name=snapshot_id,json=snapshotId,proto3" json:"snapshot_id,omitempty"`
}
func (x *BackupProgressSummary) Reset() {
*x = BackupProgressSummary{}
if protoimpl.UnsafeEnabled {
mi := &file_v1_restic_proto_msgTypes[3]
mi := &file_v1_restic_proto_msgTypes[4]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
@@ -319,7 +366,7 @@ func (x *BackupProgressSummary) String() string {
func (*BackupProgressSummary) ProtoMessage() {}
func (x *BackupProgressSummary) ProtoReflect() protoreflect.Message {
mi := &file_v1_restic_proto_msgTypes[3]
mi := &file_v1_restic_proto_msgTypes[4]
if protoimpl.UnsafeEnabled && x != nil {
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
if ms.LoadMessageInfo() == nil {
@@ -332,7 +379,7 @@ func (x *BackupProgressSummary) ProtoReflect() protoreflect.Message {
// Deprecated: Use BackupProgressSummary.ProtoReflect.Descriptor instead.
func (*BackupProgressSummary) Descriptor() ([]byte, []int) {
return file_v1_restic_proto_rawDescGZIP(), []int{3}
return file_v1_restic_proto_rawDescGZIP(), []int{4}
}
func (x *BackupProgressSummary) GetFilesNew() int64 {
@@ -430,77 +477,81 @@ var File_v1_restic_proto protoreflect.FileDescriptor
var file_v1_restic_proto_rawDesc = []byte{
0x0a, 0x0f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x69, 0x63, 0x2e, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x12, 0x02, 0x76, 0x31, 0x22, 0xca, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x74, 0x69, 0x63,
0x6f, 0x12, 0x02, 0x76, 0x31, 0x22, 0xd0, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x73, 0x74, 0x69, 0x63,
0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01,
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x0c, 0x75, 0x6e, 0x69, 0x78,
0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x04,
0x74, 0x69, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65,
0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65,
0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01,
0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04,
0x74, 0x72, 0x65, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x72, 0x65, 0x65,
0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09,
0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x14, 0x0a, 0x05, 0x70, 0x61, 0x74, 0x68,
0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x12, 0x12,
0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61,
0x67, 0x73, 0x22, 0x8e, 0x01, 0x0a, 0x13, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x50, 0x72, 0x6f,
0x67, 0x72, 0x65, 0x73, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x37, 0x0a, 0x06, 0x73, 0x74,
0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x76, 0x31, 0x2e,
0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74,
0x61, 0x74, 0x75, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x61,
0x74, 0x75, 0x73, 0x12, 0x35, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x02,
0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70,
0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x48,
0x00, 0x52, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x6e,
0x74, 0x72, 0x79, 0x22, 0xbe, 0x01, 0x0a, 0x19, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x50, 0x72,
0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x45, 0x6e, 0x74, 0x72,
0x79, 0x12, 0x1d, 0x0a, 0x0c, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x6e,
0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x07, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74,
0x12, 0x20, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x18,
0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c,
0x65, 0x73, 0x12, 0x20, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65,
0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62,
0x79, 0x74, 0x65, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x64, 0x6f,
0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f,
0x64, 0x6f, 0x6e, 0x65, 0x12, 0x1e, 0x0a, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x64, 0x6f,
0x6e, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f,
0x64, 0x6f, 0x6e, 0x65, 0x22, 0x87, 0x04, 0x0a, 0x15, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x50,
0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x1c,
0x0a, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x6e, 0x65, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28,
0x03, 0x52, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x6e, 0x65, 0x77, 0x12, 0x24, 0x0a, 0x0d,
0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x02, 0x20,
0x01, 0x28, 0x03, 0x52, 0x0d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67,
0x65, 0x64, 0x12, 0x2a, 0x0a, 0x10, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x75, 0x6e, 0x6d, 0x6f,
0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x10, 0x66, 0x69,
0x6c, 0x65, 0x73, 0x5f, 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x1a,
0x0a, 0x08, 0x64, 0x69, 0x72, 0x73, 0x5f, 0x6e, 0x65, 0x77, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03,
0x52, 0x08, 0x64, 0x69, 0x72, 0x73, 0x5f, 0x6e, 0x65, 0x77, 0x12, 0x22, 0x0a, 0x0c, 0x64, 0x69,
0x72, 0x73, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03,
0x52, 0x0c, 0x64, 0x69, 0x72, 0x73, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x28,
0x0a, 0x0f, 0x64, 0x69, 0x72, 0x73, 0x5f, 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65,
0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x64, 0x69, 0x72, 0x73, 0x5f, 0x75, 0x6e,
0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61,
0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, 0x61,
0x74, 0x61, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x74, 0x72, 0x65, 0x65,
0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x73, 0x18, 0x08, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x72,
0x65, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61,
0x5f, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x64, 0x61,
0x74, 0x61, 0x5f, 0x61, 0x64, 0x64, 0x65, 0x64, 0x12, 0x34, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61,
0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65,
0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x66,
0x69, 0x6c, 0x65, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x12, 0x34,
0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x70, 0x72,
0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03, 0x52, 0x15, 0x74,
0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65,
0x73, 0x73, 0x65, 0x64, 0x12, 0x26, 0x0a, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x64, 0x75,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0e, 0x74, 0x6f,
0x74, 0x61, 0x6c, 0x5f, 0x64, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b,
0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x20, 0x0a, 0x0c, 0x75, 0x6e, 0x69, 0x78,
0x5f, 0x74, 0x69, 0x6d, 0x65, 0x5f, 0x6d, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a,
0x75, 0x6e, 0x69, 0x78, 0x54, 0x69, 0x6d, 0x65, 0x4d, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x68, 0x6f,
0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f,
0x73, 0x74, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61,
0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x75, 0x73, 0x65, 0x72, 0x6e, 0x61,
0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x72, 0x65, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09,
0x52, 0x04, 0x74, 0x72, 0x65, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74,
0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x12, 0x14,
0x0a, 0x05, 0x70, 0x61, 0x74, 0x68, 0x73, 0x18, 0x07, 0x20, 0x03, 0x28, 0x09, 0x52, 0x05, 0x70,
0x61, 0x74, 0x68, 0x73, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x08, 0x20, 0x03,
0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, 0x73, 0x22, 0x46, 0x0a, 0x12, 0x52, 0x65, 0x73, 0x74,
0x69, 0x63, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x30,
0x0a, 0x09, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x69, 0x63, 0x53, 0x6e, 0x61,
0x70, 0x73, 0x68, 0x6f, 0x74, 0x52, 0x09, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73,
0x22, 0x8e, 0x01, 0x0a, 0x13, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x50, 0x72, 0x6f, 0x67, 0x72,
0x65, 0x73, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x37, 0x0a, 0x06, 0x73, 0x74, 0x61, 0x74,
0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61,
0x63, 0x6b, 0x75, 0x70, 0x50, 0x72, 0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x61, 0x74,
0x75, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x48, 0x00, 0x52, 0x06, 0x73, 0x74, 0x61, 0x74, 0x75,
0x73, 0x12, 0x35, 0x0a, 0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01,
0x28, 0x0b, 0x32, 0x19, 0x2e, 0x76, 0x31, 0x2e, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x50, 0x72,
0x6f, 0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x48, 0x00, 0x52,
0x07, 0x73, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x42, 0x07, 0x0a, 0x05, 0x65, 0x6e, 0x74, 0x72,
0x79, 0x22, 0xbe, 0x01, 0x0a, 0x19, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x50, 0x72, 0x6f, 0x67,
0x72, 0x65, 0x73, 0x73, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12,
0x21, 0x0a, 0x0c, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x5f, 0x64, 0x6f, 0x6e, 0x65, 0x18,
0x01, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0b, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74, 0x44, 0x6f,
0x6e, 0x65, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x65,
0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x46, 0x69,
0x6c, 0x65, 0x73, 0x12, 0x1f, 0x0a, 0x0b, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74,
0x65, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0a, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42,
0x79, 0x74, 0x65, 0x73, 0x12, 0x1d, 0x0a, 0x0a, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x64, 0x6f,
0x6e, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x44,
0x6f, 0x6e, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x79, 0x74, 0x65, 0x73, 0x5f, 0x64, 0x6f, 0x6e,
0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x62, 0x79, 0x74, 0x65, 0x73, 0x44, 0x6f,
0x6e, 0x65, 0x22, 0xf8, 0x03, 0x0a, 0x15, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x50, 0x72, 0x6f,
0x67, 0x72, 0x65, 0x73, 0x73, 0x53, 0x75, 0x6d, 0x6d, 0x61, 0x72, 0x79, 0x12, 0x1b, 0x0a, 0x09,
0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x6e, 0x65, 0x77, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52,
0x08, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x4e, 0x65, 0x77, 0x12, 0x23, 0x0a, 0x0d, 0x66, 0x69, 0x6c,
0x65, 0x73, 0x5f, 0x63, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03,
0x52, 0x0c, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x29,
0x0a, 0x10, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69,
0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x55,
0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x69, 0x72,
0x73, 0x5f, 0x6e, 0x65, 0x77, 0x18, 0x04, 0x20, 0x01, 0x28, 0x03, 0x52, 0x07, 0x64, 0x69, 0x72,
0x73, 0x4e, 0x65, 0x77, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x72, 0x73, 0x5f, 0x63, 0x68, 0x61,
0x6e, 0x67, 0x65, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0b, 0x64, 0x69, 0x72, 0x73,
0x43, 0x68, 0x61, 0x6e, 0x67, 0x65, 0x64, 0x12, 0x27, 0x0a, 0x0f, 0x64, 0x69, 0x72, 0x73, 0x5f,
0x75, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03,
0x52, 0x0e, 0x64, 0x69, 0x72, 0x73, 0x55, 0x6e, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x69, 0x65, 0x64,
0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x73, 0x18, 0x07,
0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x42, 0x6c, 0x6f, 0x62, 0x73, 0x12,
0x1d, 0x0a, 0x0a, 0x74, 0x72, 0x65, 0x65, 0x5f, 0x62, 0x6c, 0x6f, 0x62, 0x73, 0x18, 0x08, 0x20,
0x01, 0x28, 0x03, 0x52, 0x09, 0x74, 0x72, 0x65, 0x65, 0x42, 0x6c, 0x6f, 0x62, 0x73, 0x12, 0x1d,
0x0a, 0x0a, 0x64, 0x61, 0x74, 0x61, 0x5f, 0x61, 0x64, 0x64, 0x65, 0x64, 0x18, 0x09, 0x20, 0x01,
0x28, 0x03, 0x52, 0x09, 0x64, 0x61, 0x74, 0x61, 0x41, 0x64, 0x64, 0x65, 0x64, 0x12, 0x32, 0x0a,
0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x5f, 0x70, 0x72, 0x6f,
0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x03, 0x52, 0x13, 0x74, 0x6f,
0x74, 0x61, 0x6c, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65,
0x64, 0x12, 0x32, 0x0a, 0x15, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73,
0x5f, 0x70, 0x72, 0x6f, 0x63, 0x65, 0x73, 0x73, 0x65, 0x64, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x03,
0x52, 0x13, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x42, 0x79, 0x74, 0x65, 0x73, 0x50, 0x72, 0x6f, 0x63,
0x65, 0x73, 0x73, 0x65, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x64,
0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x74,
0x6f, 0x74, 0x61, 0x6c, 0x44, 0x75, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1f, 0x0a, 0x0b,
0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x69, 0x64, 0x18, 0x0d, 0x20, 0x01, 0x28,
0x09, 0x52, 0x0b, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x5f, 0x69, 0x64, 0x42, 0x2e,
0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72,
0x65, 0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x69, 0x63,
0x75, 0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x09, 0x52, 0x0a, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x49, 0x64, 0x42, 0x2e, 0x5a,
0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72, 0x65,
0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x69, 0x63, 0x75,
0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
@@ -515,21 +566,23 @@ func file_v1_restic_proto_rawDescGZIP() []byte {
return file_v1_restic_proto_rawDescData
}
var file_v1_restic_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
var file_v1_restic_proto_msgTypes = make([]protoimpl.MessageInfo, 5)
var file_v1_restic_proto_goTypes = []interface{}{
(*ResticSnapshot)(nil), // 0: v1.ResticSnapshot
(*BackupProgressEntry)(nil), // 1: v1.BackupProgressEntry
(*BackupProgressStatusEntry)(nil), // 2: v1.BackupProgressStatusEntry
(*BackupProgressSummary)(nil), // 3: v1.BackupProgressSummary
(*ResticSnapshotList)(nil), // 1: v1.ResticSnapshotList
(*BackupProgressEntry)(nil), // 2: v1.BackupProgressEntry
(*BackupProgressStatusEntry)(nil), // 3: v1.BackupProgressStatusEntry
(*BackupProgressSummary)(nil), // 4: v1.BackupProgressSummary
}
var file_v1_restic_proto_depIdxs = []int32{
2, // 0: v1.BackupProgressEntry.status:type_name -> v1.BackupProgressStatusEntry
3, // 1: v1.BackupProgressEntry.summary:type_name -> v1.BackupProgressSummary
2, // [2:2] is the sub-list for method output_type
2, // [2:2] is the sub-list for method input_type
2, // [2:2] is the sub-list for extension type_name
2, // [2:2] is the sub-list for extension extendee
0, // [0:2] is the sub-list for field type_name
0, // 0: v1.ResticSnapshotList.snapshots:type_name -> v1.ResticSnapshot
3, // 1: v1.BackupProgressEntry.status:type_name -> v1.BackupProgressStatusEntry
4, // 2: v1.BackupProgressEntry.summary:type_name -> v1.BackupProgressSummary
3, // [3:3] is the sub-list for method output_type
3, // [3:3] is the sub-list for method input_type
3, // [3:3] is the sub-list for extension type_name
3, // [3:3] is the sub-list for extension extendee
0, // [0:3] is the sub-list for field type_name
}
func init() { file_v1_restic_proto_init() }
@@ -551,7 +604,7 @@ func file_v1_restic_proto_init() {
}
}
file_v1_restic_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BackupProgressEntry); i {
switch v := v.(*ResticSnapshotList); i {
case 0:
return &v.state
case 1:
@@ -563,7 +616,7 @@ func file_v1_restic_proto_init() {
}
}
file_v1_restic_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BackupProgressStatusEntry); i {
switch v := v.(*BackupProgressEntry); i {
case 0:
return &v.state
case 1:
@@ -575,6 +628,18 @@ func file_v1_restic_proto_init() {
}
}
file_v1_restic_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BackupProgressStatusEntry); i {
case 0:
return &v.state
case 1:
return &v.sizeCache
case 2:
return &v.unknownFields
default:
return nil
}
}
file_v1_restic_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*BackupProgressSummary); i {
case 0:
return &v.state
@@ -587,7 +652,7 @@ func file_v1_restic_proto_init() {
}
}
}
file_v1_restic_proto_msgTypes[1].OneofWrappers = []interface{}{
file_v1_restic_proto_msgTypes[2].OneofWrappers = []interface{}{
(*BackupProgressEntry_Status)(nil),
(*BackupProgressEntry_Summary)(nil),
}
@@ -597,7 +662,7 @@ func file_v1_restic_proto_init() {
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
RawDescriptor: file_v1_restic_proto_rawDesc,
NumEnums: 0,
NumMessages: 4,
NumMessages: 5,
NumExtensions: 0,
NumServices: 0,
},

View File

@@ -13,6 +13,7 @@ import (
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
emptypb "google.golang.org/protobuf/types/known/emptypb"
reflect "reflect"
sync "sync"
)
const (
@@ -22,67 +23,151 @@ const (
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
)
type ListSnapshotsRequest 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"`
PlanId string `protobuf:"bytes,2,opt,name=plan_id,json=planId,proto3" json:"plan_id,omitempty"`
}
func (x *ListSnapshotsRequest) Reset() {
*x = ListSnapshotsRequest{}
if protoimpl.UnsafeEnabled {
mi := &file_v1_service_proto_msgTypes[0]
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
ms.StoreMessageInfo(mi)
}
}
func (x *ListSnapshotsRequest) String() string {
return protoimpl.X.MessageStringOf(x)
}
func (*ListSnapshotsRequest) ProtoMessage() {}
func (x *ListSnapshotsRequest) ProtoReflect() protoreflect.Message {
mi := &file_v1_service_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 ListSnapshotsRequest.ProtoReflect.Descriptor instead.
func (*ListSnapshotsRequest) Descriptor() ([]byte, []int) {
return file_v1_service_proto_rawDescGZIP(), []int{0}
}
func (x *ListSnapshotsRequest) GetRepoId() string {
if x != nil {
return x.RepoId
}
return ""
}
func (x *ListSnapshotsRequest) GetPlanId() string {
if x != nil {
return x.PlanId
}
return ""
}
var File_v1_service_proto protoreflect.FileDescriptor
var file_v1_service_proto_rawDesc = []byte{
0x0a, 0x10, 0x76, 0x31, 0x2f, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 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, 0x65, 0x76, 0x65, 0x6e,
0x74, 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, 0x32, 0xeb, 0x02, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x74, 0x69,
0x63, 0x55, 0x49, 0x12, 0x43, 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, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x76,
0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3a, 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, 0x15, 0x82,
0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x3a, 0x01, 0x2a, 0x22, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f,
0x6e, 0x66, 0x69, 0x67, 0x12, 0x3b, 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, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x3a, 0x01, 0x2a,
0x22, 0x0f, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72, 0x65, 0x70,
0x6f, 0x12, 0x44, 0x0a, 0x09, 0x47, 0x65, 0x74, 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, 0x09, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x76, 0x65, 0x6e,
0x74, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x65,
0x76, 0x65, 0x6e, 0x74, 0x73, 0x30, 0x01, 0x12, 0x5b, 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, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, 0x2f,
0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x2f,
0x70, 0x61, 0x74, 0x68, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63,
0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72, 0x65, 0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f,
0x72, 0x65, 0x73, 0x74, 0x69, 0x63, 0x75, 0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x74, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x0f, 0x76, 0x31, 0x2f, 0x72, 0x65, 0x73,
0x74, 0x69, 0x63, 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, 0x48, 0x0a, 0x14, 0x4c, 0x69, 0x73, 0x74, 0x53,
0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 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, 0x17, 0x0a, 0x07, 0x70, 0x6c, 0x61, 0x6e,
0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x6c, 0x61, 0x6e, 0x49,
0x64, 0x32, 0xc8, 0x03, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x74, 0x69, 0x63, 0x55, 0x49, 0x12, 0x43,
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,
0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x12, 0x3a, 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, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f,
0x3a, 0x01, 0x2a, 0x22, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12,
0x3b, 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, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x3a, 0x01, 0x2a, 0x22, 0x0f, 0x2f, 0x76, 0x31,
0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x12, 0x44, 0x0a, 0x09,
0x47, 0x65, 0x74, 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, 0x09, 0x2e, 0x76, 0x31, 0x2e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x12, 0x82, 0xd3,
0xe4, 0x93, 0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73,
0x30, 0x01, 0x12, 0x5b, 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, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x3a, 0x01, 0x2a,
0x22, 0x0d, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x12,
0x5b, 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, 0x20, 0x82, 0xd3, 0xe4, 0x93,
0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x6f, 0x63,
0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x42, 0x2e, 0x5a, 0x2c,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72, 0x65, 0x74,
0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x69, 0x63, 0x75, 0x69,
0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
}
var (
file_v1_service_proto_rawDescOnce sync.Once
file_v1_service_proto_rawDescData = file_v1_service_proto_rawDesc
)
func file_v1_service_proto_rawDescGZIP() []byte {
file_v1_service_proto_rawDescOnce.Do(func() {
file_v1_service_proto_rawDescData = protoimpl.X.CompressGZIP(file_v1_service_proto_rawDescData)
})
return file_v1_service_proto_rawDescData
}
var file_v1_service_proto_msgTypes = make([]protoimpl.MessageInfo, 1)
var file_v1_service_proto_goTypes = []interface{}{
(*emptypb.Empty)(nil), // 0: google.protobuf.Empty
(*Config)(nil), // 1: v1.Config
(*Repo)(nil), // 2: v1.Repo
(*types.StringValue)(nil), // 3: types.StringValue
(*Event)(nil), // 4: v1.Event
(*types.StringList)(nil), // 5: types.StringList
(*ListSnapshotsRequest)(nil), // 0: v1.ListSnapshotsRequest
(*emptypb.Empty)(nil), // 1: google.protobuf.Empty
(*Config)(nil), // 2: v1.Config
(*Repo)(nil), // 3: v1.Repo
(*types.StringValue)(nil), // 4: types.StringValue
(*Event)(nil), // 5: v1.Event
(*ResticSnapshotList)(nil), // 6: v1.ResticSnapshotList
(*types.StringList)(nil), // 7: types.StringList
}
var file_v1_service_proto_depIdxs = []int32{
0, // 0: v1.ResticUI.GetConfig:input_type -> google.protobuf.Empty
1, // 1: v1.ResticUI.SetConfig:input_type -> v1.Config
2, // 2: v1.ResticUI.AddRepo:input_type -> v1.Repo
0, // 3: v1.ResticUI.GetEvents:input_type -> google.protobuf.Empty
3, // 4: v1.ResticUI.PathAutocomplete:input_type -> types.StringValue
1, // 5: v1.ResticUI.GetConfig:output_type -> v1.Config
1, // 6: v1.ResticUI.SetConfig:output_type -> v1.Config
1, // 7: v1.ResticUI.AddRepo:output_type -> v1.Config
4, // 8: v1.ResticUI.GetEvents:output_type -> v1.Event
5, // 9: v1.ResticUI.PathAutocomplete:output_type -> types.StringList
5, // [5:10] is the sub-list for method output_type
0, // [0:5] is the sub-list for method input_type
1, // 0: v1.ResticUI.GetConfig:input_type -> google.protobuf.Empty
2, // 1: v1.ResticUI.SetConfig:input_type -> v1.Config
3, // 2: v1.ResticUI.AddRepo:input_type -> v1.Repo
1, // 3: v1.ResticUI.GetEvents:input_type -> google.protobuf.Empty
0, // 4: v1.ResticUI.ListSnapshots:input_type -> v1.ListSnapshotsRequest
4, // 5: v1.ResticUI.PathAutocomplete:input_type -> types.StringValue
2, // 6: v1.ResticUI.GetConfig:output_type -> v1.Config
2, // 7: v1.ResticUI.SetConfig:output_type -> v1.Config
2, // 8: v1.ResticUI.AddRepo:output_type -> v1.Config
5, // 9: v1.ResticUI.GetEvents:output_type -> v1.Event
6, // 10: v1.ResticUI.ListSnapshots:output_type -> v1.ResticSnapshotList
7, // 11: v1.ResticUI.PathAutocomplete:output_type -> types.StringList
6, // [6:12] is the sub-list for method output_type
0, // [0:6] is the sub-list for method input_type
0, // [0:0] is the sub-list for extension type_name
0, // [0:0] is the sub-list for extension extendee
0, // [0:0] is the sub-list for field type_name
@@ -95,18 +180,34 @@ func file_v1_service_proto_init() {
}
file_v1_config_proto_init()
file_v1_events_proto_init()
file_v1_restic_proto_init()
if !protoimpl.UnsafeEnabled {
file_v1_service_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} {
switch v := v.(*ListSnapshotsRequest); 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_service_proto_rawDesc,
NumEnums: 0,
NumMessages: 0,
NumMessages: 1,
NumExtensions: 0,
NumServices: 1,
},
GoTypes: file_v1_service_proto_goTypes,
DependencyIndexes: file_v1_service_proto_depIdxs,
MessageInfos: file_v1_service_proto_msgTypes,
}.Build()
File_v1_service_proto = out.File
file_v1_service_proto_rawDesc = nil

View File

@@ -136,6 +136,40 @@ func request_ResticUI_GetEvents_0(ctx context.Context, marshaler runtime.Marshal
}
func request_ResticUI_ListSnapshots_0(ctx context.Context, marshaler runtime.Marshaler, client ResticUIClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ListSnapshotsRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := client.ListSnapshots(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
return msg, metadata, err
}
func local_request_ResticUI_ListSnapshots_0(ctx context.Context, marshaler runtime.Marshaler, server ResticUIServer, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq ListSnapshotsRequest
var metadata runtime.ServerMetadata
newReader, berr := utilities.IOReaderFactory(req.Body)
if berr != nil {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
}
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
}
msg, err := server.ListSnapshots(ctx, &protoReq)
return msg, metadata, err
}
func request_ResticUI_PathAutocomplete_0(ctx context.Context, marshaler runtime.Marshaler, client ResticUIClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
var protoReq types.StringValue
var metadata runtime.ServerMetadata
@@ -258,6 +292,31 @@ func RegisterResticUIHandlerServer(ctx context.Context, mux *runtime.ServeMux, s
return
})
mux.Handle("POST", pattern_ResticUI_ListSnapshots_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
var stream runtime.ServerTransportStream
ctx = grpc.NewContextWithServerTransportStream(ctx, &stream)
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateIncomingContext(ctx, mux, req, "/v1.ResticUI/ListSnapshots", runtime.WithHTTPPathPattern("/v1/snapshots"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := local_request_ResticUI_ListSnapshots_0(annotatedContext, inboundMarshaler, server, req, pathParams)
md.HeaderMD, md.TrailerMD = metadata.Join(md.HeaderMD, stream.Header()), metadata.Join(md.TrailerMD, stream.Trailer())
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_ResticUI_ListSnapshots_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ResticUI_PathAutocomplete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@@ -412,6 +471,28 @@ func RegisterResticUIHandlerClient(ctx context.Context, mux *runtime.ServeMux, c
})
mux.Handle("POST", pattern_ResticUI_ListSnapshots_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
var err error
var annotatedContext context.Context
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/v1.ResticUI/ListSnapshots", runtime.WithHTTPPathPattern("/v1/snapshots"))
if err != nil {
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
return
}
resp, md, err := request_ResticUI_ListSnapshots_0(annotatedContext, inboundMarshaler, client, req, pathParams)
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
if err != nil {
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
return
}
forward_ResticUI_ListSnapshots_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
})
mux.Handle("POST", pattern_ResticUI_PathAutocomplete_0, func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
ctx, cancel := context.WithCancel(req.Context())
defer cancel()
@@ -446,6 +527,8 @@ var (
pattern_ResticUI_GetEvents_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "events"}, ""))
pattern_ResticUI_ListSnapshots_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "snapshots"}, ""))
pattern_ResticUI_PathAutocomplete_0 = runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 2, 2}, []string{"v1", "autocomplete", "path"}, ""))
)
@@ -458,5 +541,7 @@ var (
forward_ResticUI_GetEvents_0 = runtime.ForwardResponseStream
forward_ResticUI_ListSnapshots_0 = runtime.ForwardResponseMessage
forward_ResticUI_PathAutocomplete_0 = runtime.ForwardResponseMessage
)

View File

@@ -25,6 +25,7 @@ const (
ResticUI_SetConfig_FullMethodName = "/v1.ResticUI/SetConfig"
ResticUI_AddRepo_FullMethodName = "/v1.ResticUI/AddRepo"
ResticUI_GetEvents_FullMethodName = "/v1.ResticUI/GetEvents"
ResticUI_ListSnapshots_FullMethodName = "/v1.ResticUI/ListSnapshots"
ResticUI_PathAutocomplete_FullMethodName = "/v1.ResticUI/PathAutocomplete"
)
@@ -36,6 +37,7 @@ type ResticUIClient interface {
SetConfig(ctx context.Context, in *Config, opts ...grpc.CallOption) (*Config, error)
AddRepo(ctx context.Context, in *Repo, opts ...grpc.CallOption) (*Config, error)
GetEvents(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (ResticUI_GetEventsClient, error)
ListSnapshots(ctx context.Context, in *ListSnapshotsRequest, opts ...grpc.CallOption) (*ResticSnapshotList, error)
PathAutocomplete(ctx context.Context, in *types.StringValue, opts ...grpc.CallOption) (*types.StringList, error)
}
@@ -106,6 +108,15 @@ func (x *resticUIGetEventsClient) Recv() (*Event, error) {
return m, nil
}
func (c *resticUIClient) ListSnapshots(ctx context.Context, in *ListSnapshotsRequest, opts ...grpc.CallOption) (*ResticSnapshotList, error) {
out := new(ResticSnapshotList)
err := c.cc.Invoke(ctx, ResticUI_ListSnapshots_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *resticUIClient) PathAutocomplete(ctx context.Context, in *types.StringValue, opts ...grpc.CallOption) (*types.StringList, error) {
out := new(types.StringList)
err := c.cc.Invoke(ctx, ResticUI_PathAutocomplete_FullMethodName, in, out, opts...)
@@ -123,6 +134,7 @@ type ResticUIServer interface {
SetConfig(context.Context, *Config) (*Config, error)
AddRepo(context.Context, *Repo) (*Config, error)
GetEvents(*emptypb.Empty, ResticUI_GetEventsServer) error
ListSnapshots(context.Context, *ListSnapshotsRequest) (*ResticSnapshotList, error)
PathAutocomplete(context.Context, *types.StringValue) (*types.StringList, error)
mustEmbedUnimplementedResticUIServer()
}
@@ -143,6 +155,9 @@ func (UnimplementedResticUIServer) AddRepo(context.Context, *Repo) (*Config, err
func (UnimplementedResticUIServer) GetEvents(*emptypb.Empty, ResticUI_GetEventsServer) error {
return status.Errorf(codes.Unimplemented, "method GetEvents not implemented")
}
func (UnimplementedResticUIServer) ListSnapshots(context.Context, *ListSnapshotsRequest) (*ResticSnapshotList, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListSnapshots not implemented")
}
func (UnimplementedResticUIServer) PathAutocomplete(context.Context, *types.StringValue) (*types.StringList, error) {
return nil, status.Errorf(codes.Unimplemented, "method PathAutocomplete not implemented")
}
@@ -234,6 +249,24 @@ func (x *resticUIGetEventsServer) Send(m *Event) error {
return x.ServerStream.SendMsg(m)
}
func _ResticUI_ListSnapshots_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListSnapshotsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ResticUIServer).ListSnapshots(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ResticUI_ListSnapshots_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ResticUIServer).ListSnapshots(ctx, req.(*ListSnapshotsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ResticUI_PathAutocomplete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(types.StringValue)
if err := dec(in); err != nil {
@@ -271,6 +304,10 @@ var ResticUI_ServiceDesc = grpc.ServiceDesc{
MethodName: "AddRepo",
Handler: _ResticUI_AddRepo_Handler,
},
{
MethodName: "ListSnapshots",
Handler: _ResticUI_ListSnapshots_Handler,
},
{
MethodName: "PathAutocomplete",
Handler: _ResticUI_PathAutocomplete_Handler,

1
go.mod
View File

@@ -5,6 +5,7 @@ go 1.21.3
require (
github.com/gitploy-io/cronexpr v0.2.2
github.com/google/renameio v1.0.1
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1
github.com/hashicorp/go-multierror v1.1.1
go.uber.org/zap v1.26.0

2
go.sum
View File

@@ -28,6 +28,8 @@ github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
github.com/google/renameio v1.0.1 h1:Lh/jXZmvZxb0BBeSY5VKEfidcbcbenKjZFzM/q0fSeU=
github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1 h1:HcUWd006luQPljE73d5sk+/VgYPGUReEVz2y1/qylwY=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1/go.mod h1:w9Y7gY31krpLmrVU5ZPG9H7l9fZuRu5/3R3S3FMtVQ4=
github.com/grpc-ecosystem/grpc-gateway v1.16.0 h1:gmcG1KaJ57LophUzW0Hy8NmPhnMZb4M0+kPpLofRdBo=
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.2 h1:dygLcbEBA+t/P7ck6a8AkXv6juQ4cK0RHBoh32jxhHM=

View File

@@ -9,18 +9,68 @@ import (
"path/filepath"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/internal/orchestrator"
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"go.uber.org/zap"
"google.golang.org/grpc"
"google.golang.org/grpc/credentials/insecure"
)
func serveGRPC(ctx context.Context, socket string) error {
func loggingFunc(l *zap.Logger) logging.Logger {
return logging.LoggerFunc(func(ctx context.Context, lvl logging.Level, msg string, fields ...any) {
f := make([]zap.Field, 0, len(fields)/2)
for i := 0; i < len(fields); i += 2 {
key := fields[i]
value := fields[i+1]
switch v := value.(type) {
case string:
f = append(f, zap.String(key.(string), v))
case int:
f = append(f, zap.Int(key.(string), v))
case bool:
f = append(f, zap.Bool(key.(string), v))
default:
f = append(f, zap.Any(key.(string), v))
}
}
logger := l.WithOptions(zap.AddCallerSkip(1)).With(f...)
switch lvl {
case logging.LevelDebug:
logger.Debug(msg)
case logging.LevelInfo:
logger.Info(msg)
case logging.LevelWarn:
logger.Warn(msg)
case logging.LevelError:
logger.Error(msg)
default:
panic(fmt.Sprintf("unknown level %v", lvl))
}
})
}
func serveGRPC(ctx context.Context, orchestrator *orchestrator.Orchestrator, socket string) error {
lis, err := net.Listen("unix", socket)
if err != nil {
return fmt.Errorf("failed to listen: %w", err)
}
grpcServer := grpc.NewServer()
v1.RegisterResticUIServer(grpcServer, NewServer())
logger := zap.L()
grpcServer := grpc.NewServer(
grpc.ChainUnaryInterceptor(
logging.UnaryServerInterceptor(loggingFunc(logger)),
),
grpc.ChainStreamInterceptor(
logging.StreamServerInterceptor(loggingFunc(logger)),
),
)
v1.RegisterResticUIServer(grpcServer, NewServer(orchestrator))
go func() {
<-ctx.Done()
grpcServer.GracefulStop()
@@ -32,7 +82,7 @@ func serveGRPC(ctx context.Context, socket string) error {
return nil
}
func serveHTTPHandlers(ctx context.Context, mux *runtime.ServeMux) error {
func serveHTTPHandlers(ctx context.Context, orchestrator *orchestrator.Orchestrator, mux *runtime.ServeMux) error {
tmpDir, err := os.MkdirTemp("", "resticui")
if err != nil {
return fmt.Errorf("failed to create temp dir for unix domain socket: %w", err)
@@ -49,7 +99,7 @@ func serveHTTPHandlers(ctx context.Context, mux *runtime.ServeMux) error {
return fmt.Errorf("failed to register gateway: %w", err)
}
if err := serveGRPC(ctx, socket); err != nil {
if err := serveGRPC(ctx, orchestrator, socket); err != nil {
return err
}
@@ -57,8 +107,8 @@ func serveHTTPHandlers(ctx context.Context, mux *runtime.ServeMux) error {
}
// Handler returns an http.Handler serving the API, cancel the context to cleanly shut down the server.
func ServeAPI(ctx context.Context, mux *http.ServeMux) error {
func ServeAPI(ctx context.Context, orchestrator *orchestrator.Orchestrator, mux *http.ServeMux) error {
apiMux := runtime.NewServeMux()
mux.Handle("/api/", http.StripPrefix("/api", apiMux))
return serveHTTPHandlers(ctx, apiMux)
return serveHTTPHandlers(ctx, orchestrator, apiMux)
}

View File

@@ -7,18 +7,20 @@ import (
"os"
"sync"
"sync/atomic"
"time"
"github.com/garethgeorge/resticui/gen/go/types"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/internal/config"
"github.com/garethgeorge/resticui/internal/orchestrator"
"github.com/garethgeorge/resticui/pkg/restic"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/emptypb"
)
type Server struct {
*v1.UnimplementedResticUIServer
orchestrator *orchestrator.Orchestrator
reqId atomic.Uint64
eventChannelsMu sync.Mutex
@@ -27,23 +29,25 @@ type Server struct {
var _ v1.ResticUIServer = &Server{}
func NewServer() *Server {
func NewServer(orchestrator *orchestrator.Orchestrator) *Server {
s := &Server{
eventChannels: make(map[uint64]chan *v1.Event),
orchestrator: orchestrator,
}
go func() {
for {
time.Sleep(3 * time.Second)
s.PublishEvent(&v1.Event{
Event: &v1.Event_Log{
Log: &v1.LogEvent{
Message: fmt.Sprintf("event push test, it is %v", time.Now().Format(time.RFC3339)),
},
},
})
}
}()
// go func() {
// // TODO: disable this when proper event sources are implemented.
// for {
// time.Sleep(3 * time.Second)
// s.PublishEvent(&v1.Event{
// Event: &v1.Event_Log{
// Log: &v1.LogEvent{
// Message: fmt.Sprintf("event push test, it is %v", time.Now().Format(time.RFC3339)),
// },
// },
// })
// }
// }()
return s
}
@@ -55,8 +59,18 @@ func (s *Server) GetConfig(ctx context.Context, empty *emptypb.Empty) (*v1.Confi
// SetConfig implements POST /v1/config
func (s *Server) SetConfig(ctx context.Context, c *v1.Config) (*v1.Config, error) {
err := config.Default.Update(c)
existing, err := config.Default.Get()
if err != nil {
return nil, fmt.Errorf("failed to check current config: %w", err)
}
// Compare and increment modno
if existing.Modno != c.Modno {
return nil, errors.New("config modno mismatch, reload and try again")
}
c.Modno += 1
if err := config.Default.Update(c); err != nil {
return nil, fmt.Errorf("failed to update config: %w", err)
}
return config.Default.Get()
@@ -69,14 +83,20 @@ func (s *Server) AddRepo(ctx context.Context, repo *v1.Repo) (*v1.Config, error)
return nil, fmt.Errorf("failed to get config: %w", err)
}
c = proto.Clone(c).(*v1.Config)
c.Repos = append(c.Repos, repo)
if err := config.ValidateConfig(c); err != nil {
return nil, fmt.Errorf("validation error: %w", err)
}
r := restic.NewRepo(repo)
// use background context such that the init op can try to complete even if the connection is closed.
if err := r.Init(context.Background()); err != nil {
return nil, fmt.Errorf("failed to init repo: %w", err)
}
c.Repos = append(c.Repos, repo)
zap.S().Debug("Updating config")
if err := config.Default.Update(c); err != nil {
return nil, fmt.Errorf("failed to update config: %w", err)
}
@@ -84,6 +104,40 @@ func (s *Server) AddRepo(ctx context.Context, repo *v1.Repo) (*v1.Config, error)
return c, nil
}
// ListSnapshots implements GET /v1/snapshots/{repo.id}/{plan.id?}
func (s *Server) ListSnapshots(ctx context.Context, query *v1.ListSnapshotsRequest) (*v1.ResticSnapshotList, error) {
repo, err := s.orchestrator.GetRepo(query.RepoId)
if err != nil {
return nil, fmt.Errorf("failed to get repo: %w", err)
}
var snapshots []*restic.Snapshot
if query.PlanId != "" {
var plan *v1.Plan
plan, err = s.orchestrator.GetPlan(query.PlanId)
if err != nil {
return nil, fmt.Errorf("failed to get plan %q: %w", query.PlanId, err)
}
snapshots, err = repo.SnapshotsForPlan(ctx, plan)
} else {
snapshots, err = repo.Snapshots(ctx)
}
if err != nil {
return nil, fmt.Errorf("failed to list snapshots: %w", err)
}
// Transform the snapshots and return them.
var rs []*v1.ResticSnapshot
for _, snapshot := range snapshots {
rs = append(rs, snapshot.ToProto())
}
return &v1.ResticSnapshotList{
Snapshots: rs,
}, nil
}
// GetEvents implements GET /v1/events
func (s *Server) GetEvents(_ *emptypb.Empty, stream v1.ResticUI_GetEventsServer) error {

View File

@@ -1,18 +1,23 @@
package config
import (
"errors"
"flag"
"fmt"
"os"
"path"
"sync"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
)
var ErrConfigNotFound = fmt.Errorf("config not found")
var configDirFlag = flag.String("config_dir", "", "The directory to store the config file")
var Default ConfigStore = &YamlFileStore{
var Default ConfigStore = &CachingValidatingStore{
ConfigStore: &YamlFileStore{
Path: path.Join(configDir(*configDirFlag), "config.yaml"),
},
}
type ConfigStore interface {
@@ -43,3 +48,50 @@ func configDir(override string) string {
return fmt.Sprintf("%v/.config/resticui", home)
}
type CachingValidatingStore struct {
ConfigStore
mu sync.Mutex
config *v1.Config
}
func (c *CachingValidatingStore) Get() (*v1.Config, error) {
c.mu.Lock()
defer c.mu.Unlock()
if c.config != nil {
return c.config, nil
}
config, err := c.ConfigStore.Get()
if err != nil {
if errors.Is(err, ErrConfigNotFound) {
c.config = NewDefaultConfig()
return c.config, nil
}
return c.config, err
}
if err := ValidateConfig(config); err != nil {
return nil, err
}
c.config = config
return config, nil
}
func (c *CachingValidatingStore) Update(config *v1.Config) error {
c.mu.Lock()
defer c.mu.Unlock()
if err := ValidateConfig(config); err != nil {
return err
}
if err := c.ConfigStore.Update(config); err != nil {
return err
}
c.config = config
return nil
}

View File

@@ -0,0 +1,114 @@
package config
import (
"strings"
"testing"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"google.golang.org/protobuf/proto"
)
func TestConfig(t *testing.T) {
dir := t.TempDir()
testRepo := &v1.Repo{
Id: "test-repo",
Uri: "/tmp/test",
Password: "test",
}
testPlan := &v1.Plan{
Id: "test-plan",
Repo: "test-repo",
Paths: []string{"/tmp/foo"},
Cron: "* * * * *",
}
tests := []struct {
name string
config *v1.Config
wantErr bool
wantErrContains string
store ConfigStore
}{
{
name: "default config",
config: NewDefaultConfig(),
store: &CachingValidatingStore{ConfigStore: &YamlFileStore{Path: dir + "/default-config.yaml"}},
},
{
name: "simple valid config",
config: &v1.Config{
Repos: []*v1.Repo{testRepo},
Plans: []*v1.Plan{testPlan},
},
store: &CachingValidatingStore{ConfigStore: &YamlFileStore{Path: dir + "/valid-config.yaml"}},
},
{
name: "plan references non-existent repo",
config: &v1.Config{
Plans: []*v1.Plan{testPlan},
},
store: &CachingValidatingStore{ConfigStore: &YamlFileStore{Path: dir + "/invalid-config.yaml"}},
wantErr: true,
wantErrContains: "repo \"test-repo\" not found",
},
{
name: "repo with duplicate id",
config: &v1.Config{
Repos: []*v1.Repo{
testRepo,
testRepo,
},
},
store: &CachingValidatingStore{ConfigStore: &YamlFileStore{Path: dir + "/invalid-config2.yaml"}},
wantErr: true,
wantErrContains: "repo test-repo: duplicate id",
},
{
name: "plan with bad cron",
config: &v1.Config{
Repos: []*v1.Repo{
testRepo,
},
Plans: []*v1.Plan{
{
Id: "test-plan",
Repo: "test-repo",
Paths: []string{"/tmp/foo"},
Cron: "bad cron",
},
},
},
store: &CachingValidatingStore{ConfigStore: &YamlFileStore{Path: dir + "/invalid-config3.yaml"}},
wantErr: true,
wantErrContains: "invalid cron \"bad cron\"",
},
}
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
t.Parallel()
err := tc.store.Update(tc.config)
if (err != nil) != tc.wantErr {
t.Errorf("Config.Update() error = %v, wantErr %v", err, tc.wantErr)
}
if tc.wantErrContains != "" && (err == nil || !strings.Contains(err.Error(), tc.wantErrContains)) {
t.Errorf("Config.Update() error = %v, wantErrContains %v", err, tc.wantErrContains)
}
if err == nil {
config, err := tc.store.Get()
if err != nil {
t.Errorf("Config.Get() error = %v, wantErr nil", err)
}
if !proto.Equal(config, tc.config) {
t.Errorf("Config.Get() = %v, want %v", config, tc.config)
}
}
})
}
}

View File

@@ -11,7 +11,7 @@ import (
"github.com/hashicorp/go-multierror"
)
func validateConfig(c *v1.Config) error {
func ValidateConfig(c *v1.Config) error {
var err error
repos := make(map[string]*v1.Repo)
if c.Repos != nil {
@@ -19,15 +19,17 @@ func validateConfig(c *v1.Config) error {
if e := validateRepo(repo); e != nil {
err = multierror.Append(e, fmt.Errorf("repo %s: %w", repo.GetId(), err))
}
if _, ok := repos[repo.GetId()]; ok {
err = multierror.Append(err, fmt.Errorf("repo %s: duplicate id", repo.GetId()))
}
repos[repo.GetId()] = repo
}
}
if c.Plans != nil {
for _, plan := range c.Plans {
err := validatePlan(plan, repos);
if err != nil {
err = multierror.Append(err, fmt.Errorf("plan %s: %w", plan.GetId(), err))
if e := validatePlan(plan, repos); e != nil {
err = multierror.Append(err, fmt.Errorf("plan %s: %w", plan.GetId(), e))
}
}
}
@@ -73,7 +75,7 @@ func validatePlan(plan *v1.Plan, repos map[string]*v1.Repo) error {
}
if _, e := cronexpr.Parse(plan.GetCron()); err != nil {
if _, e := cronexpr.Parse(plan.GetCron()); e != nil {
err = multierror.Append(err, fmt.Errorf("invalid cron %q: %w", plan.GetCron(), e))
}

View File

@@ -17,31 +17,22 @@ import (
type YamlFileStore struct {
Path string
mu sync.Mutex
config *v1.Config
}
var _ ConfigStore = &YamlFileStore{}
func (f *YamlFileStore) Get() (*v1.Config, error) {
f.mu.Lock()
if f.config != nil {
f.mu.Unlock()
return f.config, nil
}
defer f.mu.Unlock()
data, err := os.ReadFile(f.Path)
if err != nil {
if errors.Is(err, os.ErrNotExist) {
f.config = NewDefaultConfig()
f.mu.Unlock()
f.Update(f.config)
return f.config, nil
return nil, ErrConfigNotFound
}
return nil, fmt.Errorf("failed to read config file: %w", err)
}
defer f.mu.Unlock()
data, err = yamlToJson(data)
if err != nil {
@@ -54,19 +45,18 @@ func (f *YamlFileStore) Get() (*v1.Config, error) {
return nil, fmt.Errorf("failed to unmarshal config: %w", err)
}
if err := validateConfig(&config); err != nil {
if err := ValidateConfig(&config); err != nil {
return nil, fmt.Errorf("invalid config: %w", err)
}
f.config = &config
return f.config, nil
return &config, nil
}
func (f *YamlFileStore) Update(config *v1.Config) error {
f.mu.Lock()
defer f.mu.Unlock()
if err := validateConfig(config); err != nil {
if err := ValidateConfig(config); err != nil {
return fmt.Errorf("invalid config: %w", err)
}
@@ -90,7 +80,6 @@ func (f *YamlFileStore) Update(config *v1.Config) error {
return fmt.Errorf("failed to write config file: %w", err)
}
f.config = config
return nil
}

View File

@@ -0,0 +1,121 @@
package orchestrator
import (
"errors"
"fmt"
"sync"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/internal/config"
"github.com/garethgeorge/resticui/pkg/restic"
"google.golang.org/protobuf/proto"
)
var ErrRepoNotFound = errors.New("repo not found")
var ErrRepoInitializationFailed = errors.New("repo initialization failed")
var ErrPlanNotFound = errors.New("plan not found")
// Orchestrator is responsible for managing repos and backups.
type Orchestrator struct {
configProvider config.ConfigStore
repoPool *resticRepoPool
}
func NewOrchestrator(configProvider config.ConfigStore) *Orchestrator {
return &Orchestrator{
configProvider: configProvider,
repoPool: newResticRepoPool(configProvider),
}
}
func (o *Orchestrator) GetRepo(repoId string) (repo *RepoOrchestrator, err error) {
r, err := o.repoPool.GetRepo(repoId)
if err != nil {
return nil, fmt.Errorf("failed to get repo %q: %w", repoId, err)
}
return r, nil
}
func (o *Orchestrator) GetPlan(planId string) (*v1.Plan, error) {
cfg, err := o.configProvider.Get()
if err != nil {
return nil, fmt.Errorf("failed to get config: %w", err)
}
if cfg.Plans == nil {
return nil, ErrPlanNotFound
}
for _, p := range cfg.Plans {
if p.Id == planId {
return p, nil
}
}
return nil, ErrPlanNotFound
}
// resticRepoPool caches restic repos.
type resticRepoPool struct {
mu sync.Mutex
repos map[string]*RepoOrchestrator
configProvider config.ConfigStore
}
func newResticRepoPool(configProvider config.ConfigStore) *resticRepoPool {
return &resticRepoPool{
repos: make(map[string]*RepoOrchestrator),
configProvider: configProvider,
}
}
func (rp *resticRepoPool) GetRepo(repoId string) (repo *RepoOrchestrator, err error) {
cfg, err := rp.configProvider.Get()
if err != nil {
return nil, fmt.Errorf("failed to get config: %w", err)
}
rp.mu.Lock()
defer rp.mu.Unlock()
if cfg.Repos == nil {
return nil, ErrRepoNotFound
}
var repoProto *v1.Repo
for _, r := range cfg.Repos {
if r.GetId() == repoId {
repoProto = r
}
}
if repoProto == nil {
return nil, ErrRepoNotFound
}
// Check if we already have a repo for this id, if we do return it.
repo, ok := rp.repos[repoId]
if ok && proto.Equal(repo.repoConfig, repoProto) {
return repo, nil
}
delete(rp.repos, repoId);
var opts []restic.GenericOption
if len(repoProto.GetEnv()) > 0 {
opts = append(opts, restic.WithEnv(repoProto.GetEnv()...))
}
if len(repoProto.GetFlags()) > 0 {
opts = append(opts, restic.WithFlags(repoProto.GetFlags()...))
}
// Otherwise create a new repo.
repo = &RepoOrchestrator{
repoConfig: repoProto,
repo: restic.NewRepo(repoProto, opts...),
}
rp.repos[repoId] = repo
return repo, nil
}

View File

@@ -0,0 +1,108 @@
package orchestrator
import (
"context"
"fmt"
"slices"
"sort"
"sync"
"time"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/pkg/restic"
)
// RepoOrchestrator is responsible for managing a single repo.
type RepoOrchestrator struct {
mu sync.Mutex
repoConfig *v1.Repo
repo *restic.Repo
snapshotsAge time.Time
snapshots []*restic.Snapshot
}
func (r *RepoOrchestrator) updateSnapshotsIfNeeded(ctx context.Context) error {
if time.Since(r.snapshotsAge) > 10 * time.Minute {
r.snapshots = nil
}
if r.snapshots != nil {
return nil
}
snapshots, err := r.repo.Snapshots(ctx, restic.WithPropagatedEnvVars(restic.EnvToPropagate...))
if err != nil {
return fmt.Errorf("failed to update snapshots: %w", err)
}
sort.SliceStable(snapshots, func(i, j int) bool {
return snapshots[i].Time > snapshots[j].Time
})
r.snapshots = snapshots
return nil
}
func (r *RepoOrchestrator) Snapshots(ctx context.Context) ([]*restic.Snapshot, error) {
r.mu.Lock()
defer r.mu.Unlock()
if err := r.updateSnapshotsIfNeeded(ctx); err != nil {
return nil, err
}
return r.snapshots, nil
}
func (r *RepoOrchestrator) SnapshotsForPlan(ctx context.Context, plan *v1.Plan) ([]*restic.Snapshot, error) {
r.mu.Lock()
defer r.mu.Unlock()
if err := r.updateSnapshotsIfNeeded(ctx); err != nil {
return nil, err
}
return filterSnapshotsForPlan(r.snapshots, plan), nil
}
func (r *RepoOrchestrator) Backup(ctx context.Context, plan *v1.Plan, progressCallback func(event *restic.BackupProgressEntry)) error {
snapshots, err := r.SnapshotsForPlan(ctx, plan)
if err != nil {
return err
}
var opts []restic.BackupOption
opts = append(opts, restic.WithBackupPaths(plan.Paths...))
opts = append(opts, restic.WithBackupExcludes(plan.Excludes...))
opts = append(opts, restic.WithBackupTags(tagForPlan(plan)))
if len(snapshots) > 0 {
// TODO: design a test strategy to verify that the backup parent is used correctly.
opts = append(opts, restic.WithBackupParent(snapshots[len(snapshots) - 1].Id))
}
panic("not yet implemented")
}
func filterSnapshotsForPlan(snapshots []*restic.Snapshot, plan *v1.Plan) []*restic.Snapshot {
wantTag := tagForPlan(plan)
var filtered []*restic.Snapshot
for _, snapshot := range snapshots {
if snapshot.Tags == nil {
continue
}
if slices.Contains(snapshot.Tags, wantTag) {
filtered = append(filtered, snapshot)
}
}
return filtered
}
func tagForPlan(plan *v1.Plan) string {
return fmt.Sprintf("plan:%s", plan.Id)
}

View File

@@ -7,6 +7,9 @@ import (
"io"
"os/exec"
"slices"
"time"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
)
type LsEntry struct {
@@ -33,6 +36,23 @@ type Snapshot struct {
Parent string `json:"parent"`
}
func (s *Snapshot) ToProto() *v1.ResticSnapshot {
t, err := time.Parse(time.RFC3339Nano, s.Time)
if err != nil {
t = time.Unix(0, 0)
}
return &v1.ResticSnapshot{
Id: s.Id,
UnixTimeMs: t.UnixMilli(),
Tree: s.Tree,
Paths: s.Paths,
Hostname: s.Hostname,
Username: s.Username,
Tags: s.Tags,
Parent: s.Parent,
}
}
type BackupProgressEntry struct {
// Common fields
MessageType string `json:"message_type"` // "summary" or "status"

View File

@@ -27,6 +27,7 @@ func TestReadBackupProgressEntries(t *testing.T) {
}
}
func TestReadLs(t *testing.T) {
testInput := `{"time":"2023-11-10T19:14:17.053824063-08:00","tree":"3e2918b261948e69602ee9504b8f475bcc7cdc4dcec0b3f34ecdb014287d07b2","paths":["/resticui"],"hostname":"pop-os","username":"dontpanic","uid":1000,"gid":1000,"id":"db155169d788e6e432e320aedbdff5a54cc439653093bb56944a67682528aa52","short_id":"db155169","struct_type":"snapshot"}
{"name":".git","type":"dir","path":"/.git","uid":1000,"gid":1000,"mode":2147484157,"mtime":"2023-11-10T18:32:38.156599473-08:00","atime":"2023-11-10T18:32:38.156599473-08:00","ctime":"2023-11-10T18:32:38.156599473-08:00","struct_type":"node"}
@@ -46,3 +47,40 @@ func TestReadLs(t *testing.T) {
t.Errorf("wanted 3 entries, got: %d", len(entries))
}
}
func TestSnapshotToProto(t *testing.T) {
snapshot := &Snapshot{
Id: "db155169d788e6e432e320aedbdff5a54cc439653093bb56944a67682528aa52",
Time: "2023-11-10T19:14:17.053824063-08:00",
Tree: "3e2918b261948e69602ee9504b8f475bcc7cdc4dcec0b3f34ecdb014287d07b2",
Paths: []string{"/resticui"},
Hostname: "pop-os",
Username: "dontpanic",
Tags: []string{},
Parent: "",
}
proto := snapshot.ToProto()
if proto.Id != snapshot.Id {
t.Errorf("wanted id %q, got: %q", snapshot.Id, proto.Id)
}
if proto.Tree != snapshot.Tree {
t.Errorf("wanted tree %q, got: %q", snapshot.Tree, proto.Tree)
}
if proto.Hostname != snapshot.Hostname {
t.Errorf("wanted hostname %q, got: %q", snapshot.Hostname, proto.Hostname)
}
if proto.Username != snapshot.Username {
t.Errorf("wanted username %q, got: %q", snapshot.Username, proto.Username)
}
if len(proto.Tags) != len(snapshot.Tags) {
t.Errorf("wanted %d tags, got: %d", len(snapshot.Tags), len(proto.Tags))
}
if proto.Parent != snapshot.Parent {
t.Errorf("wanted parent %q, got: %q", snapshot.Parent, proto.Parent)
}
if proto.UnixTimeMs != 1699672457053 {
t.Errorf("wanted unix time %d, got: %d", 1699672457053, proto.UnixTimeMs)
}
}

View File

@@ -9,6 +9,7 @@ import (
"io"
"os"
"os/exec"
"strings"
"sync"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
@@ -25,6 +26,7 @@ type Repo struct {
extraEnv []string
}
// NewRepo instantiates a new repository. TODO: should not accept a v1.Repo
func NewRepo(repo *v1.Repo, opts ...GenericOption) *Repo {
opt := &GenericOpts{}
for _, o := range opts {
@@ -63,8 +65,10 @@ func (r *Repo) init(ctx context.Context) error {
cmd.Env = append(cmd.Env, r.buildEnv()...)
if output, err := cmd.CombinedOutput(); err != nil {
if !strings.Contains(string(output), "config file already exists") {
return NewCmdError(cmd, output, err)
}
}
r.initialized = true
return nil
@@ -242,6 +246,12 @@ func WithBackupTags(tags ...string) BackupOption {
}
}
func WithBackupParent(parent string) BackupOption {
return func(opts *BackupOpts) {
opts.extraArgs = append(opts.extraArgs, "--parent", parent)
}
}
type GenericOpts struct {
extraArgs []string
extraEnv []string

View File

@@ -140,6 +140,13 @@ func TestSnapshot(t *testing.T) {
if len(snapshots) != tc.count {
t.Errorf("wanted %d snapshots, got: %d", tc.count, len(snapshots))
}
// Ensure that snapshot timestamps are set, this is critical for correct ordering in the orchestrator.
for _, snapshot := range snapshots {
if p := snapshot.ToProto(); p.UnixTimeMs == 0 {
t.Errorf("wanted snapshot time to be non-zero, got: %v", p.UnixTimeMs)
}
}
})
}
}

View File

@@ -5,14 +5,15 @@ package v1;
option go_package = "github.com/garethgeorge/resticui/go/proto/v1";
message Config {
int32 version = 1;
repeated Repo repos = 3 [json_name="repos"];
repeated Plan plans = 4 [json_name="plans"];
}
// modification number, used for read-modify-write consistency in the UI. Incremented on every write.
int32 modno = 1 [json_name="modno"];
message User {
string name = 1;
string password = 2; // plaintext password
// override the hostname tagged on backups. If provided it will be used in addition to tags to group backups.
string host_override = 2 [json_name="host_override"];
repeated Repo repos = 3 [json_name="repos"];
repeated Plan plans = 4 [json_name="plans"];
}
message Repo {

View File

@@ -6,22 +6,22 @@ option go_package = "github.com/garethgeorge/resticui/go/proto/v1";
message Event {
// timestamp is the number of milliseconds since the Unix epoch.
int64 timestamp = 1 [json_name="timestamp"];
int64 timestamp = 1;
oneof event {
LogEvent log = 3 [json_name="log"];
BackupStatusEvent backup_status_change = 4 [json_name="backup_status"];
LogEvent log = 3;
BackupStatusEvent backup_status_change = 4;
}
}
message LogEvent {
string message = 1 [json_name="message"];
string message = 1;
}
message BackupStatusEvent {
string plan = 1 [json_name="plan"];
Status status = 2 [json_name="status"];
uint32 percent = 3 [json_name="percent"];
string plan = 1;
Status status = 2;
uint32 percent = 3;
}
enum Status {

View File

@@ -5,43 +5,47 @@ package v1;
option go_package = "github.com/garethgeorge/resticui/go/proto/v1";
message ResticSnapshot {
string id = 1 [json_name = "id"];
int64 unix_time_ms = 2 [json_name = "time"];
string hostname = 3 [json_name = "hostname"];
string username = 4 [json_name = "username"];
string tree = 5 [json_name = "tree"]; // tree hash
string parent = 6 [json_name = "parent"]; // parent snapshot's id
repeated string paths = 7 [json_name = "paths"];
repeated string tags = 8 [json_name = "tags"];
string id = 1;
int64 unix_time_ms = 2;
string hostname = 3;
string username = 4;
string tree = 5; // tree hash
string parent = 6; // parent snapshot's id
repeated string paths = 7;
repeated string tags = 8;
}
message ResticSnapshotList {
repeated ResticSnapshot snapshots = 1;
}
message BackupProgressEntry {
oneof entry {
BackupProgressStatusEntry status = 1 [json_name = "status"];
BackupProgressSummary summary = 2 [json_name = "summary"];
BackupProgressStatusEntry status = 1;
BackupProgressSummary summary = 2;
}
}
message BackupProgressStatusEntry {
double percent_done = 1 [json_name = "percent"]; // 0.0 - 1.0
int64 total_files = 2 [json_name = "total_files"];
int64 total_bytes = 3 [json_name = "total_bytes"];
int64 files_done = 4 [json_name = "files_done"];
int64 bytes_done = 5 [json_name = "bytes_done"];
double percent_done = 1; // 0.0 - 1.0
int64 total_files = 2;
int64 total_bytes = 3;
int64 files_done = 4;
int64 bytes_done = 5;
}
message BackupProgressSummary {
int64 files_new = 1 [json_name = "files_new"];
int64 files_changed = 2 [json_name = "files_changed"];
int64 files_unmodified = 3 [json_name = "files_unmodified"];
int64 dirs_new = 4 [json_name = "dirs_new"];
int64 dirs_changed = 5 [json_name = "dirs_changed"];
int64 dirs_unmodified = 6 [json_name = "dirs_unmodified"];
int64 data_blobs = 7 [json_name = "data_blobs"];
int64 tree_blobs = 8 [json_name = "tree_blobs"];
int64 data_added = 9 [json_name = "data_added"];
int64 total_files_processed = 10 [json_name = "total_files_processed"];
int64 total_bytes_processed = 11 [json_name = "total_bytes_processed"];
int64 total_duration = 12 [json_name = "total_duration"];
string snapshot_id = 13 [json_name = "snapshot_id"];
int64 files_new = 1;
int64 files_changed = 2;
int64 files_unmodified = 3;
int64 dirs_new = 4;
int64 dirs_changed = 5;
int64 dirs_unmodified = 6;
int64 data_blobs = 7;
int64 tree_blobs = 8;
int64 data_added = 9;
int64 total_files_processed = 10;
int64 total_bytes_processed = 11;
int64 total_duration = 12;
string snapshot_id = 13;
}

View File

@@ -6,6 +6,7 @@ option go_package = "github.com/garethgeorge/resticui/go/proto/v1";
import "v1/config.proto";
import "v1/events.proto";
import "v1/restic.proto";
import "types/value.proto";
import "google/protobuf/empty.proto";
import "google/api/annotations.proto";
@@ -37,6 +38,13 @@ service ResticUI {
};
}
rpc ListSnapshots(ListSnapshotsRequest) returns (ResticSnapshotList) {
option (google.api.http) = {
post: "/v1/snapshots"
body: "*"
};
}
rpc PathAutocomplete (types.StringValue) returns (types.StringList) {
option (google.api.http) = {
post: "/v1/autocomplete/path"
@@ -44,3 +52,8 @@ service ResticUI {
};
}
}
message ListSnapshotsRequest {
string repo_id = 1;
string plan_id = 2;
}

View File

@@ -4,16 +4,12 @@
* This file is a generated Typescript file for GRPC Gateway, DO NOT MODIFY
*/
export type Config = {
version?: number
modno?: number
hostOverride?: string
repos?: Repo[]
plans?: Plan[]
}
export type User = {
name?: string
password?: string
}
export type Repo = {
id?: string
uri?: string

View File

@@ -23,6 +23,10 @@ export type ResticSnapshot = {
tags?: string[]
}
export type ResticSnapshotList = {
snapshots?: ResticSnapshot[]
}
type BaseBackupProgressEntry = {
}

View File

@@ -9,6 +9,12 @@ import * as GoogleProtobufEmpty from "../google/protobuf/empty.pb"
import * as TypesValue from "../types/value.pb"
import * as V1Config from "./config.pb"
import * as V1Events from "./events.pb"
import * as V1Restic from "./restic.pb"
export type ListSnapshotsRequest = {
repoId?: string
planId?: string
}
export class ResticUI {
static GetConfig(req: GoogleProtobufEmpty.Empty, initReq?: fm.InitReq): Promise<V1Config.Config> {
return fm.fetchReq<GoogleProtobufEmpty.Empty, V1Config.Config>(`/v1/config?${fm.renderURLSearchParams(req, [])}`, {...initReq, method: "GET"})
@@ -22,6 +28,9 @@ export class ResticUI {
static GetEvents(req: GoogleProtobufEmpty.Empty, entityNotifier?: fm.NotifyStreamEntityArrival<V1Events.Event>, initReq?: fm.InitReq): Promise<void> {
return fm.fetchStreamingRequest<GoogleProtobufEmpty.Empty, V1Events.Event>(`/v1/events?${fm.renderURLSearchParams(req, [])}`, entityNotifier, {...initReq, method: "GET"})
}
static ListSnapshots(req: ListSnapshotsRequest, initReq?: fm.InitReq): Promise<V1Restic.ResticSnapshotList> {
return fm.fetchReq<ListSnapshotsRequest, V1Restic.ResticSnapshotList>(`/v1/snapshots`, {...initReq, method: "POST", body: JSON.stringify(req, fm.replacer)})
}
static PathAutocomplete(req: TypesValue.StringValue, initReq?: fm.InitReq): Promise<TypesValue.StringList> {
return fm.fetchReq<TypesValue.StringValue, TypesValue.StringList>(`/v1/autocomplete/path`, {...initReq, method: "POST", body: JSON.stringify(req, fm.replacer)})
}

View File

@@ -5,7 +5,9 @@ import { StringList } from "../../gen/ts/types/value.pb";
let timeout: NodeJS.Timeout | undefined = undefined;
export const URIAutocomplete = (props: React.PropsWithChildren) => {
export const URIAutocomplete = (
props: React.PropsWithChildren<{ disabled: boolean }>
) => {
const [value, setValue] = useState("");
const [options, setOptions] = useState<{ value: string }[]>([]);
const [showOptions, setShowOptions] = useState<{ value: string }[]>([]);

View File

@@ -17,7 +17,7 @@ export const addRepo = async (repo: Repo): Promise<Config> => {
});
};
export const setConfig = async (config: Config): Promise<Config> => {
export const updateConfig = async (config: Config): Promise<Config> => {
return await ResticUI.SetConfig(config, {
pathPrefix: "/api/",
});

View File

@@ -14,20 +14,26 @@ import { URIAutocomplete } from "../components/URIAutocomplete";
import { MinusCircleOutlined, PlusOutlined } from "@ant-design/icons";
import { useAlertApi } from "../components/Alerts";
import { ResticUI } from "../../gen/ts/v1/service.pb";
import {
addRepo,
configState,
fetchConfig,
updateConfig,
} from "../state/config";
import { useRecoilState, useSetRecoilState } from "recoil";
export const AddRepoModel = ({
template,
}: {
template: Partial<Repo> | null;
}) => {
const setConfig = useSetRecoilState(configState);
const [confirmLoading, setConfirmLoading] = useState(false);
const showModal = useShowModal();
const alertsApi = useAlertApi()!;
const [form] = Form.useForm<Repo>();
template = template || {};
const handleOk = () => {
const handleOk = async () => {
const errors = form
.getFieldsError()
.map((e) => e.errors)
@@ -40,22 +46,43 @@ export const AddRepoModel = ({
const repo = form.getFieldsValue() as Repo;
if (template === null) {
if (template !== null) {
// We are in the edit repo flow, update the repo in the config
try {
let config = await fetchConfig();
const idx = config.repos!.findIndex((r) => r.id === template!.id);
if (idx === -1) {
alertsApi.error("Can't update repo, not found");
return;
}
config.repos![idx] = { ...repo };
setConfig(await updateConfig(config));
showModal(null);
alertsApi.success("Updated repo " + repo.uri);
// Update the snapshots for the repo
await ResticUI.ListSnapshots(
{
repoId: repo.id,
},
{ pathPrefix: "/api" }
);
} catch (e: any) {
alertsApi.error("Error updating repo: " + e.message, 15);
} finally {
setConfirmLoading(false);
}
} else {
// We are in the create repo flow, create the new repo via the service
ResticUI.AddRepo(repo, {
pathPrefix: "/api",
})
.then((res) => {
try {
setConfig(await addRepo(repo));
showModal(null);
alertsApi.success("Added repo " + repo.uri);
})
.catch((e) => {
} catch (e: any) {
alertsApi.error("Error adding repo: " + e.message, 15);
})
.finally(() => {
} finally {
setConfirmLoading(false);
});
} else {
}
}
};
@@ -67,7 +94,7 @@ export const AddRepoModel = ({
<>
<Modal
open={true}
title={template ? "Add Restic Repository" : "Edit Restic Repository"}
title={template ? "Edit Restic Repository" : "Add Restic Repository"}
onOk={handleOk}
confirmLoading={confirmLoading}
onCancel={handleCancel}
@@ -78,7 +105,7 @@ export const AddRepoModel = ({
hasFeedback
name="id"
label="Repo Name"
initialValue={template.id}
initialValue={template && template.id}
validateTrigger={["onChange", "onBlur"]}
rules={[
{
@@ -91,7 +118,7 @@ export const AddRepoModel = ({
},
]}
>
<Input />
<Input disabled={!!template} />
</Form.Item>
{/* Repo.uri */}
@@ -118,8 +145,8 @@ export const AddRepoModel = ({
<Form.Item<Repo>
hasFeedback
name="uri"
label="Repo URI"
initialValue={template.id}
label="Repository URI (e.g. ./local-path or s3://bucket-name/path)"
initialValue={template && template.uri}
validateTrigger={["onChange", "onBlur"]}
rules={[
{
@@ -128,7 +155,7 @@ export const AddRepoModel = ({
},
]}
>
<Input />
<URIAutocomplete disabled={!!template} />
</Form.Item>
</Tooltip>
@@ -137,7 +164,7 @@ export const AddRepoModel = ({
hasFeedback
name="password"
label="Password"
initialValue={template.password}
initialValue={template && template.password}
validateTrigger={["onChange", "onBlur"]}
rules={[
{
@@ -150,7 +177,7 @@ export const AddRepoModel = ({
},
]}
>
<Input />
<Input disabled={!!template} />
</Form.Item>
{/* Repo.env */}
@@ -164,7 +191,7 @@ export const AddRepoModel = ({
},
},
]}
initialValue={[]}
initialValue={(template && template.env) || undefined}
>
{(fields, { add, remove }, { errors }) => (
<>

View File

@@ -11,7 +11,7 @@ import { configState, fetchConfig } from "../state/config";
import { useRecoilState } from "recoil";
import { Config } from "../../gen/ts/v1/config.pb";
import { AlertContextProvider, useAlertApi } from "../components/Alerts";
import { useShowModal, useShowSpinner } from "../components/ModalManager";
import { useShowModal } from "../components/ModalManager";
import { AddPlanModal } from "./AddPlanModel";
import { AddRepoModel } from "./AddRepoModel";
@@ -41,6 +41,7 @@ export const App: React.FC = () => {
});
}, []);
console.log("rerender config ", config);
const items = getSidenavItems(config);
return (

View File

@@ -2,8 +2,7 @@ package static
import (
"embed"
_ "embed"
)
//go:embed *
//go:embed dist/*.js dist/*.css dist/*.html
var FS embed.FS