From 999b9bf9b21111ef58e14bddd7cf1c38edfa47be Mon Sep 17 00:00:00 2001 From: Samuel N Cui Date: Tue, 3 Oct 2023 16:12:44 +0800 Subject: [PATCH] feat: add tapes index view --- README.md | 2 - apis/library_trim.go | 14 + apis/tape_get_positions.go | 17 + build.sh | 3 +- entity/service.pb.go | 864 +++++++++++++++++--------- entity/service.proto | 19 + entity/service_grpc.pb.go | 72 +++ frontend/package.json | 2 +- frontend/src/api.ts | 57 +- frontend/src/app.tsx | 4 +- frontend/src/entity/service.client.ts | 44 +- frontend/src/entity/service.ts | 225 ++++++- frontend/src/pages/jobs.tsx | 19 +- frontend/src/pages/tapes.tsx | 97 ++- frontend/src/tools.ts | 5 + go.mod | 2 +- go.sum | 4 + install-release.sh | 6 +- library/library.go | 85 +++ library/position.go | 70 +++ resource/db.go | 41 ++ scripts/encrypt | 1 + scripts/get_device | 24 + scripts/mkfs | 4 +- scripts/mount | 14 +- scripts/mount.openltfs | 16 + scripts/readinfo | 4 +- 27 files changed, 1357 insertions(+), 358 deletions(-) create mode 100644 apis/library_trim.go create mode 100644 apis/tape_get_positions.go create mode 100755 scripts/get_device create mode 100755 scripts/mount.openltfs diff --git a/README.md b/README.md index 2450922..104177d 100644 --- a/README.md +++ b/README.md @@ -43,9 +43,7 @@ Or you can download binary from `releases`, and run the following shell commands ```shell # If you put this to other path, you need to change scripts and systemd service file. -mkdir -p /opt/ltfs mkdir -p /opt/yatm - tar -xvzf yatm-linux-amd64-${RELEASE_VERSION}.tar.gz -C /opt/yatm cp /opt/yatm/config.example.yaml /opt/yatm/config.yaml diff --git a/apis/library_trim.go b/apis/library_trim.go new file mode 100644 index 0000000..666e456 --- /dev/null +++ b/apis/library_trim.go @@ -0,0 +1,14 @@ +package apis + +import ( + "context" + + "github.com/samuelncui/yatm/entity" +) + +func (api *API) LibraryTrim(ctx context.Context, req *entity.LibraryTrimRequest) (*entity.LibraryTrimReply, error) { + if err := api.lib.Trim(ctx, req.TrimPosition, req.TrimFile); err != nil { + return nil, err + } + return &entity.LibraryTrimReply{}, nil +} diff --git a/apis/tape_get_positions.go b/apis/tape_get_positions.go new file mode 100644 index 0000000..70e6084 --- /dev/null +++ b/apis/tape_get_positions.go @@ -0,0 +1,17 @@ +package apis + +import ( + "context" + "fmt" + + "github.com/samuelncui/yatm/entity" +) + +func (api *API) TapeGetPositions(ctx context.Context, req *entity.TapeGetPositionsRequest) (*entity.TapeGetPositionsReply, error) { + positions, err := api.lib.ListPositions(ctx, req.Id, req.Directory) + if err != nil { + return nil, fmt.Errorf("list position has error, %w", err) + } + + return &entity.TapeGetPositionsReply{Positions: convertPositions(positions...)}, nil +} diff --git a/build.sh b/build.sh index 0ae8dae..f6f6aa1 100755 --- a/build.sh +++ b/build.sh @@ -8,6 +8,7 @@ export TARGET_FILE="yatm-linux-amd64-${RELEASE_VERSION}.tar.gz" rm -rf output; mkdir -p output; +mkdir -p output/captured_indices; cp -r scripts ./output/; cp ./cmd/httpd/yatm-httpd.service ./output/ @@ -16,7 +17,7 @@ cp ./LICENSE ./output/ cp ./README.md ./output/ echo "${RELEASE_VERSION}" > ./output/VERSION -# docker run --rm -v $(pwd):/app golang:1.21 sh -c "cd /app && bash " +# docker run --rm -v $(pwd):/app golang:1.21 sh -c "cd /app && bash build_backend.sh" # docker run --rm -v $(pwd):/app node:20-slim sh -c "cd /app && bash build_frontend.sh" ./build_backend.sh ./build_frontend.sh diff --git a/entity/service.pb.go b/entity/service.pb.go index a40b9b8..751d85d 100644 --- a/entity/service.pb.go +++ b/entity/service.pb.go @@ -772,6 +772,108 @@ func (*TapeDeleteReply) Descriptor() ([]byte, []int) { return file_service_proto_rawDescGZIP(), []int{14} } +type TapeGetPositionsRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + Directory string `protobuf:"bytes,2,opt,name=directory,proto3" json:"directory,omitempty"` +} + +func (x *TapeGetPositionsRequest) Reset() { + *x = TapeGetPositionsRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_service_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TapeGetPositionsRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TapeGetPositionsRequest) ProtoMessage() {} + +func (x *TapeGetPositionsRequest) ProtoReflect() protoreflect.Message { + mi := &file_service_proto_msgTypes[15] + 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 TapeGetPositionsRequest.ProtoReflect.Descriptor instead. +func (*TapeGetPositionsRequest) Descriptor() ([]byte, []int) { + return file_service_proto_rawDescGZIP(), []int{15} +} + +func (x *TapeGetPositionsRequest) GetId() int64 { + if x != nil { + return x.Id + } + return 0 +} + +func (x *TapeGetPositionsRequest) GetDirectory() string { + if x != nil { + return x.Directory + } + return "" +} + +type TapeGetPositionsReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Positions []*Position `protobuf:"bytes,1,rep,name=positions,proto3" json:"positions,omitempty"` +} + +func (x *TapeGetPositionsReply) Reset() { + *x = TapeGetPositionsReply{} + if protoimpl.UnsafeEnabled { + mi := &file_service_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TapeGetPositionsReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TapeGetPositionsReply) ProtoMessage() {} + +func (x *TapeGetPositionsReply) ProtoReflect() protoreflect.Message { + mi := &file_service_proto_msgTypes[16] + 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 TapeGetPositionsReply.ProtoReflect.Descriptor instead. +func (*TapeGetPositionsReply) Descriptor() ([]byte, []int) { + return file_service_proto_rawDescGZIP(), []int{16} +} + +func (x *TapeGetPositionsReply) GetPositions() []*Position { + if x != nil { + return x.Positions + } + return nil +} + type JobListRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -786,7 +888,7 @@ type JobListRequest struct { func (x *JobListRequest) Reset() { *x = JobListRequest{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[15] + mi := &file_service_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -799,7 +901,7 @@ func (x *JobListRequest) String() string { func (*JobListRequest) ProtoMessage() {} func (x *JobListRequest) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[15] + mi := &file_service_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -812,7 +914,7 @@ func (x *JobListRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use JobListRequest.ProtoReflect.Descriptor instead. func (*JobListRequest) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{15} + return file_service_proto_rawDescGZIP(), []int{17} } func (m *JobListRequest) GetParam() isJobListRequest_Param { @@ -863,7 +965,7 @@ type JobMGetRequest struct { func (x *JobMGetRequest) Reset() { *x = JobMGetRequest{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[16] + mi := &file_service_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -876,7 +978,7 @@ func (x *JobMGetRequest) String() string { func (*JobMGetRequest) ProtoMessage() {} func (x *JobMGetRequest) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[16] + mi := &file_service_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -889,7 +991,7 @@ func (x *JobMGetRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use JobMGetRequest.ProtoReflect.Descriptor instead. func (*JobMGetRequest) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{16} + return file_service_proto_rawDescGZIP(), []int{18} } func (x *JobMGetRequest) GetIds() []int64 { @@ -910,7 +1012,7 @@ type JobListReply struct { func (x *JobListReply) Reset() { *x = JobListReply{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[17] + mi := &file_service_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -923,7 +1025,7 @@ func (x *JobListReply) String() string { func (*JobListReply) ProtoMessage() {} func (x *JobListReply) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[17] + mi := &file_service_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -936,7 +1038,7 @@ func (x *JobListReply) ProtoReflect() protoreflect.Message { // Deprecated: Use JobListReply.ProtoReflect.Descriptor instead. func (*JobListReply) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{17} + return file_service_proto_rawDescGZIP(), []int{19} } func (x *JobListReply) GetJobs() []*Job { @@ -957,7 +1059,7 @@ type JobCreateRequest struct { func (x *JobCreateRequest) Reset() { *x = JobCreateRequest{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[18] + mi := &file_service_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -970,7 +1072,7 @@ func (x *JobCreateRequest) String() string { func (*JobCreateRequest) ProtoMessage() {} func (x *JobCreateRequest) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[18] + mi := &file_service_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -983,7 +1085,7 @@ func (x *JobCreateRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use JobCreateRequest.ProtoReflect.Descriptor instead. func (*JobCreateRequest) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{18} + return file_service_proto_rawDescGZIP(), []int{20} } func (x *JobCreateRequest) GetJob() *CreatableJob { @@ -1004,7 +1106,7 @@ type JobCreateReply struct { func (x *JobCreateReply) Reset() { *x = JobCreateReply{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[19] + mi := &file_service_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1017,7 +1119,7 @@ func (x *JobCreateReply) String() string { func (*JobCreateReply) ProtoMessage() {} func (x *JobCreateReply) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[19] + mi := &file_service_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1030,7 +1132,7 @@ func (x *JobCreateReply) ProtoReflect() protoreflect.Message { // Deprecated: Use JobCreateReply.ProtoReflect.Descriptor instead. func (*JobCreateReply) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{19} + return file_service_proto_rawDescGZIP(), []int{21} } func (x *JobCreateReply) GetJob() *Job { @@ -1051,7 +1153,7 @@ type JobDeleteRequest struct { func (x *JobDeleteRequest) Reset() { *x = JobDeleteRequest{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[20] + mi := &file_service_proto_msgTypes[22] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1064,7 +1166,7 @@ func (x *JobDeleteRequest) String() string { func (*JobDeleteRequest) ProtoMessage() {} func (x *JobDeleteRequest) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[20] + mi := &file_service_proto_msgTypes[22] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1077,7 +1179,7 @@ func (x *JobDeleteRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use JobDeleteRequest.ProtoReflect.Descriptor instead. func (*JobDeleteRequest) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{20} + return file_service_proto_rawDescGZIP(), []int{22} } func (x *JobDeleteRequest) GetIds() []int64 { @@ -1096,7 +1198,7 @@ type JobDeleteReply struct { func (x *JobDeleteReply) Reset() { *x = JobDeleteReply{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[21] + mi := &file_service_proto_msgTypes[23] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1109,7 +1211,7 @@ func (x *JobDeleteReply) String() string { func (*JobDeleteReply) ProtoMessage() {} func (x *JobDeleteReply) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[21] + mi := &file_service_proto_msgTypes[23] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1122,7 +1224,7 @@ func (x *JobDeleteReply) ProtoReflect() protoreflect.Message { // Deprecated: Use JobDeleteReply.ProtoReflect.Descriptor instead. func (*JobDeleteReply) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{21} + return file_service_proto_rawDescGZIP(), []int{23} } type JobNextRequest struct { @@ -1137,7 +1239,7 @@ type JobNextRequest struct { func (x *JobNextRequest) Reset() { *x = JobNextRequest{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[22] + mi := &file_service_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1150,7 +1252,7 @@ func (x *JobNextRequest) String() string { func (*JobNextRequest) ProtoMessage() {} func (x *JobNextRequest) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[22] + mi := &file_service_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1163,7 +1265,7 @@ func (x *JobNextRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use JobNextRequest.ProtoReflect.Descriptor instead. func (*JobNextRequest) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{22} + return file_service_proto_rawDescGZIP(), []int{24} } func (x *JobNextRequest) GetId() int64 { @@ -1191,7 +1293,7 @@ type JobNextReply struct { func (x *JobNextReply) Reset() { *x = JobNextReply{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[23] + mi := &file_service_proto_msgTypes[25] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1204,7 +1306,7 @@ func (x *JobNextReply) String() string { func (*JobNextReply) ProtoMessage() {} func (x *JobNextReply) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[23] + mi := &file_service_proto_msgTypes[25] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1217,7 +1319,7 @@ func (x *JobNextReply) ProtoReflect() protoreflect.Message { // Deprecated: Use JobNextReply.ProtoReflect.Descriptor instead. func (*JobNextReply) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{23} + return file_service_proto_rawDescGZIP(), []int{25} } func (x *JobNextReply) GetJob() *Job { @@ -1238,7 +1340,7 @@ type JobDisplayRequest struct { func (x *JobDisplayRequest) Reset() { *x = JobDisplayRequest{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[24] + mi := &file_service_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1251,7 +1353,7 @@ func (x *JobDisplayRequest) String() string { func (*JobDisplayRequest) ProtoMessage() {} func (x *JobDisplayRequest) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[24] + mi := &file_service_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1264,7 +1366,7 @@ func (x *JobDisplayRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use JobDisplayRequest.ProtoReflect.Descriptor instead. func (*JobDisplayRequest) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{24} + return file_service_proto_rawDescGZIP(), []int{26} } func (x *JobDisplayRequest) GetId() int64 { @@ -1285,7 +1387,7 @@ type JobDisplayReply struct { func (x *JobDisplayReply) Reset() { *x = JobDisplayReply{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[25] + mi := &file_service_proto_msgTypes[27] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1298,7 +1400,7 @@ func (x *JobDisplayReply) String() string { func (*JobDisplayReply) ProtoMessage() {} func (x *JobDisplayReply) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[25] + mi := &file_service_proto_msgTypes[27] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1311,7 +1413,7 @@ func (x *JobDisplayReply) ProtoReflect() protoreflect.Message { // Deprecated: Use JobDisplayReply.ProtoReflect.Descriptor instead. func (*JobDisplayReply) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{25} + return file_service_proto_rawDescGZIP(), []int{27} } func (x *JobDisplayReply) GetDisplay() *JobDisplay { @@ -1333,7 +1435,7 @@ type JobGetLogRequest struct { func (x *JobGetLogRequest) Reset() { *x = JobGetLogRequest{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[26] + mi := &file_service_proto_msgTypes[28] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1346,7 +1448,7 @@ func (x *JobGetLogRequest) String() string { func (*JobGetLogRequest) ProtoMessage() {} func (x *JobGetLogRequest) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[26] + mi := &file_service_proto_msgTypes[28] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1359,7 +1461,7 @@ func (x *JobGetLogRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use JobGetLogRequest.ProtoReflect.Descriptor instead. func (*JobGetLogRequest) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{26} + return file_service_proto_rawDescGZIP(), []int{28} } func (x *JobGetLogRequest) GetJobId() int64 { @@ -1387,7 +1489,7 @@ type JobGetLogReply struct { func (x *JobGetLogReply) Reset() { *x = JobGetLogReply{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[27] + mi := &file_service_proto_msgTypes[29] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1400,7 +1502,7 @@ func (x *JobGetLogReply) String() string { func (*JobGetLogReply) ProtoMessage() {} func (x *JobGetLogReply) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[27] + mi := &file_service_proto_msgTypes[29] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1413,7 +1515,7 @@ func (x *JobGetLogReply) ProtoReflect() protoreflect.Message { // Deprecated: Use JobGetLogReply.ProtoReflect.Descriptor instead. func (*JobGetLogReply) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{27} + return file_service_proto_rawDescGZIP(), []int{29} } func (x *JobGetLogReply) GetLogs() []byte { @@ -1434,7 +1536,7 @@ type SourceListRequest struct { func (x *SourceListRequest) Reset() { *x = SourceListRequest{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[28] + mi := &file_service_proto_msgTypes[30] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1447,7 +1549,7 @@ func (x *SourceListRequest) String() string { func (*SourceListRequest) ProtoMessage() {} func (x *SourceListRequest) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[28] + mi := &file_service_proto_msgTypes[30] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1460,7 +1562,7 @@ func (x *SourceListRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use SourceListRequest.ProtoReflect.Descriptor instead. func (*SourceListRequest) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{28} + return file_service_proto_rawDescGZIP(), []int{30} } func (x *SourceListRequest) GetPath() string { @@ -1483,7 +1585,7 @@ type SourceListReply struct { func (x *SourceListReply) Reset() { *x = SourceListReply{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[29] + mi := &file_service_proto_msgTypes[31] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1496,7 +1598,7 @@ func (x *SourceListReply) String() string { func (*SourceListReply) ProtoMessage() {} func (x *SourceListReply) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[29] + mi := &file_service_proto_msgTypes[31] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1509,7 +1611,7 @@ func (x *SourceListReply) ProtoReflect() protoreflect.Message { // Deprecated: Use SourceListReply.ProtoReflect.Descriptor instead. func (*SourceListReply) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{29} + return file_service_proto_rawDescGZIP(), []int{31} } func (x *SourceListReply) GetFile() *SourceFile { @@ -1542,7 +1644,7 @@ type DeviceListRequest struct { func (x *DeviceListRequest) Reset() { *x = DeviceListRequest{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[30] + mi := &file_service_proto_msgTypes[32] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1555,7 +1657,7 @@ func (x *DeviceListRequest) String() string { func (*DeviceListRequest) ProtoMessage() {} func (x *DeviceListRequest) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[30] + mi := &file_service_proto_msgTypes[32] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1568,7 +1670,7 @@ func (x *DeviceListRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use DeviceListRequest.ProtoReflect.Descriptor instead. func (*DeviceListRequest) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{30} + return file_service_proto_rawDescGZIP(), []int{32} } type DeviceListReply struct { @@ -1582,7 +1684,7 @@ type DeviceListReply struct { func (x *DeviceListReply) Reset() { *x = DeviceListReply{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[31] + mi := &file_service_proto_msgTypes[33] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1595,7 +1697,7 @@ func (x *DeviceListReply) String() string { func (*DeviceListReply) ProtoMessage() {} func (x *DeviceListReply) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[31] + mi := &file_service_proto_msgTypes[33] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1608,7 +1710,7 @@ func (x *DeviceListReply) ProtoReflect() protoreflect.Message { // Deprecated: Use DeviceListReply.ProtoReflect.Descriptor instead. func (*DeviceListReply) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{31} + return file_service_proto_rawDescGZIP(), []int{33} } func (x *DeviceListReply) GetDevices() []string { @@ -1629,7 +1731,7 @@ type LibraryExportRequest struct { func (x *LibraryExportRequest) Reset() { *x = LibraryExportRequest{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[32] + mi := &file_service_proto_msgTypes[34] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1642,7 +1744,7 @@ func (x *LibraryExportRequest) String() string { func (*LibraryExportRequest) ProtoMessage() {} func (x *LibraryExportRequest) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[32] + mi := &file_service_proto_msgTypes[34] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1655,7 +1757,7 @@ func (x *LibraryExportRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use LibraryExportRequest.ProtoReflect.Descriptor instead. func (*LibraryExportRequest) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{32} + return file_service_proto_rawDescGZIP(), []int{34} } func (x *LibraryExportRequest) GetTypes() []LibraryEntityType { @@ -1676,7 +1778,7 @@ type LibraryExportReply struct { func (x *LibraryExportReply) Reset() { *x = LibraryExportReply{} if protoimpl.UnsafeEnabled { - mi := &file_service_proto_msgTypes[33] + mi := &file_service_proto_msgTypes[35] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1689,7 +1791,7 @@ func (x *LibraryExportReply) String() string { func (*LibraryExportReply) ProtoMessage() {} func (x *LibraryExportReply) ProtoReflect() protoreflect.Message { - mi := &file_service_proto_msgTypes[33] + mi := &file_service_proto_msgTypes[35] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1702,7 +1804,7 @@ func (x *LibraryExportReply) ProtoReflect() protoreflect.Message { // Deprecated: Use LibraryExportReply.ProtoReflect.Descriptor instead. func (*LibraryExportReply) Descriptor() ([]byte, []int) { - return file_service_proto_rawDescGZIP(), []int{33} + return file_service_proto_rawDescGZIP(), []int{35} } func (x *LibraryExportReply) GetJson() []byte { @@ -1712,6 +1814,99 @@ func (x *LibraryExportReply) GetJson() []byte { return nil } +type LibraryTrimRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + TrimPosition bool `protobuf:"varint,1,opt,name=trim_position,json=trimPosition,proto3" json:"trim_position,omitempty"` + TrimFile bool `protobuf:"varint,2,opt,name=trim_file,json=trimFile,proto3" json:"trim_file,omitempty"` +} + +func (x *LibraryTrimRequest) Reset() { + *x = LibraryTrimRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_service_proto_msgTypes[36] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LibraryTrimRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LibraryTrimRequest) ProtoMessage() {} + +func (x *LibraryTrimRequest) ProtoReflect() protoreflect.Message { + mi := &file_service_proto_msgTypes[36] + 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 LibraryTrimRequest.ProtoReflect.Descriptor instead. +func (*LibraryTrimRequest) Descriptor() ([]byte, []int) { + return file_service_proto_rawDescGZIP(), []int{36} +} + +func (x *LibraryTrimRequest) GetTrimPosition() bool { + if x != nil { + return x.TrimPosition + } + return false +} + +func (x *LibraryTrimRequest) GetTrimFile() bool { + if x != nil { + return x.TrimFile + } + return false +} + +type LibraryTrimReply struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *LibraryTrimReply) Reset() { + *x = LibraryTrimReply{} + if protoimpl.UnsafeEnabled { + mi := &file_service_proto_msgTypes[37] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LibraryTrimReply) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LibraryTrimReply) ProtoMessage() {} + +func (x *LibraryTrimReply) ProtoReflect() protoreflect.Message { + mi := &file_service_proto_msgTypes[37] + 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 LibraryTrimReply.ProtoReflect.Descriptor instead. +func (*LibraryTrimReply) Descriptor() ([]byte, []int) { + return file_service_proto_rawDescGZIP(), []int{37} +} + var File_service_proto protoreflect.FileDescriptor var file_service_proto_rawDesc = []byte{ @@ -1775,74 +1970,90 @@ var file_service_proto_rawDesc = []byte{ 0x0a, 0x11, 0x54, 0x61, 0x70, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x03, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x11, 0x0a, 0x0f, 0x54, 0x61, 0x70, 0x65, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x6e, 0x0a, 0x0e, 0x4a, 0x6f, 0x62, 0x4c, - 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x04, 0x6d, 0x67, - 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x4d, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x48, 0x00, 0x52, 0x04, 0x6d, 0x67, 0x65, 0x74, 0x12, 0x24, 0x0a, 0x04, 0x6c, 0x69, 0x73, - 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6a, 0x6f, 0x62, 0x2e, 0x4a, 0x6f, - 0x62, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x48, 0x00, 0x52, 0x04, 0x6c, 0x69, 0x73, 0x74, 0x42, - 0x07, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x22, 0x22, 0x0a, 0x0e, 0x4a, 0x6f, 0x62, 0x4d, - 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, - 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x03, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x2c, 0x0a, 0x0c, - 0x4a, 0x6f, 0x62, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1c, 0x0a, 0x04, - 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x6a, 0x6f, 0x62, - 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x22, 0x37, 0x0a, 0x10, 0x4a, 0x6f, - 0x62, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, - 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6a, 0x6f, - 0x62, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x03, - 0x6a, 0x6f, 0x62, 0x22, 0x2c, 0x0a, 0x0e, 0x4a, 0x6f, 0x62, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1a, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x6a, 0x6f, 0x62, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x03, 0x6a, 0x6f, - 0x62, 0x22, 0x24, 0x0a, 0x10, 0x4a, 0x6f, 0x62, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, - 0x28, 0x03, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4a, 0x6f, 0x62, 0x44, 0x65, - 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x49, 0x0a, 0x0e, 0x4a, 0x6f, 0x62, - 0x4e, 0x65, 0x78, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x27, 0x0a, 0x05, 0x70, - 0x61, 0x72, 0x61, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x6a, 0x6f, 0x62, - 0x2e, 0x4a, 0x6f, 0x62, 0x4e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x52, 0x05, 0x70, - 0x61, 0x72, 0x61, 0x6d, 0x22, 0x2a, 0x0a, 0x0c, 0x4a, 0x6f, 0x62, 0x4e, 0x65, 0x78, 0x74, 0x52, - 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1a, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x0b, 0x32, 0x08, 0x2e, 0x6a, 0x6f, 0x62, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x03, 0x6a, 0x6f, 0x62, - 0x22, 0x23, 0x0a, 0x11, 0x4a, 0x6f, 0x62, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x03, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3c, 0x0a, 0x0f, 0x4a, 0x6f, 0x62, 0x44, 0x69, 0x73, 0x70, - 0x6c, 0x61, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x29, 0x0a, 0x07, 0x64, 0x69, 0x73, 0x70, - 0x6c, 0x61, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x6a, 0x6f, 0x62, 0x2e, - 0x4a, 0x6f, 0x62, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x07, 0x64, 0x69, 0x73, 0x70, - 0x6c, 0x61, 0x79, 0x22, 0x51, 0x0a, 0x10, 0x4a, 0x6f, 0x62, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, - 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x1b, - 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x03, 0x48, 0x00, - 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x88, 0x01, 0x01, 0x42, 0x09, 0x0a, 0x07, 0x5f, - 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x24, 0x0a, 0x0e, 0x4a, 0x6f, 0x62, 0x47, 0x65, 0x74, - 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x22, 0x27, 0x0a, 0x11, - 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0x93, 0x01, 0x0a, 0x0f, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, 0x0a, 0x04, 0x66, 0x69, 0x6c, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x04, 0x66, 0x69, 0x6c, - 0x65, 0x12, 0x28, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x12, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x46, 0x69, 0x6c, 0x65, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x12, 0x2e, 0x0a, 0x08, 0x63, - 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x11, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, - 0x65, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, 0x13, 0x0a, 0x11, 0x44, - 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x22, 0x2b, 0x0a, 0x0f, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, - 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, 0x73, 0x22, 0x54, 0x0a, - 0x14, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x6c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x5f, 0x65, - 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x4c, 0x69, 0x62, 0x72, 0x61, - 0x72, 0x79, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, 0x52, 0x05, 0x74, 0x79, - 0x70, 0x65, 0x73, 0x22, 0x28, 0x0a, 0x12, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x45, 0x78, - 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x12, 0x0a, 0x04, 0x6a, 0x73, 0x6f, - 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x32, 0xce, 0x08, + 0x65, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x47, 0x0a, 0x17, 0x54, 0x61, 0x70, 0x65, + 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, + 0x79, 0x22, 0x49, 0x0a, 0x15, 0x54, 0x61, 0x70, 0x65, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x30, 0x0a, 0x09, 0x70, 0x6f, + 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, + 0x6e, 0x52, 0x09, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x6e, 0x0a, 0x0e, + 0x4a, 0x6f, 0x62, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, + 0x0a, 0x04, 0x6d, 0x67, 0x65, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x4d, 0x47, 0x65, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x04, 0x6d, 0x67, 0x65, 0x74, 0x12, 0x24, 0x0a, + 0x04, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x6a, 0x6f, + 0x62, 0x2e, 0x4a, 0x6f, 0x62, 0x46, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x48, 0x00, 0x52, 0x04, 0x6c, + 0x69, 0x73, 0x74, 0x42, 0x07, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x22, 0x22, 0x0a, 0x0e, + 0x4a, 0x6f, 0x62, 0x4d, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, + 0x0a, 0x03, 0x69, 0x64, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x03, 0x52, 0x03, 0x69, 0x64, 0x73, + 0x22, 0x2c, 0x0a, 0x0c, 0x4a, 0x6f, 0x62, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x12, 0x1c, 0x0a, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x08, + 0x2e, 0x6a, 0x6f, 0x62, 0x2e, 0x4a, 0x6f, 0x62, 0x52, 0x04, 0x6a, 0x6f, 0x62, 0x73, 0x22, 0x37, + 0x0a, 0x10, 0x4a, 0x6f, 0x62, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x12, 0x23, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x11, 0x2e, 0x6a, 0x6f, 0x62, 0x2e, 0x43, 0x72, 0x65, 0x61, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x4a, + 0x6f, 0x62, 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x22, 0x2c, 0x0a, 0x0e, 0x4a, 0x6f, 0x62, 0x43, 0x72, + 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1a, 0x0a, 0x03, 0x6a, 0x6f, 0x62, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x6a, 0x6f, 0x62, 0x2e, 0x4a, 0x6f, 0x62, + 0x52, 0x03, 0x6a, 0x6f, 0x62, 0x22, 0x24, 0x0a, 0x10, 0x4a, 0x6f, 0x62, 0x44, 0x65, 0x6c, 0x65, + 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x73, + 0x18, 0x01, 0x20, 0x03, 0x28, 0x03, 0x52, 0x03, 0x69, 0x64, 0x73, 0x22, 0x10, 0x0a, 0x0e, 0x4a, + 0x6f, 0x62, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x49, 0x0a, + 0x0e, 0x4a, 0x6f, 0x62, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, + 0x27, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, + 0x2e, 0x6a, 0x6f, 0x62, 0x2e, 0x4a, 0x6f, 0x62, 0x4e, 0x65, 0x78, 0x74, 0x50, 0x61, 0x72, 0x61, + 0x6d, 0x52, 0x05, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x22, 0x2a, 0x0a, 0x0c, 0x4a, 0x6f, 0x62, 0x4e, + 0x65, 0x78, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x1a, 0x0a, 0x03, 0x6a, 0x6f, 0x62, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x08, 0x2e, 0x6a, 0x6f, 0x62, 0x2e, 0x4a, 0x6f, 0x62, 0x52, + 0x03, 0x6a, 0x6f, 0x62, 0x22, 0x23, 0x0a, 0x11, 0x4a, 0x6f, 0x62, 0x44, 0x69, 0x73, 0x70, 0x6c, + 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x22, 0x3c, 0x0a, 0x0f, 0x4a, 0x6f, 0x62, + 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x29, 0x0a, 0x07, + 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, + 0x6a, 0x6f, 0x62, 0x2e, 0x4a, 0x6f, 0x62, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x07, + 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x22, 0x51, 0x0a, 0x10, 0x4a, 0x6f, 0x62, 0x47, 0x65, + 0x74, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, + 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x05, 0x6a, 0x6f, 0x62, + 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x03, 0x48, 0x00, 0x52, 0x06, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x88, 0x01, 0x01, 0x42, + 0x09, 0x0a, 0x07, 0x5f, 0x6f, 0x66, 0x66, 0x73, 0x65, 0x74, 0x22, 0x24, 0x0a, 0x0e, 0x4a, 0x6f, + 0x62, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x12, 0x0a, 0x04, + 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, + 0x22, 0x27, 0x0a, 0x11, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x12, 0x0a, 0x04, 0x70, 0x61, 0x74, 0x68, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x04, 0x70, 0x61, 0x74, 0x68, 0x22, 0x93, 0x01, 0x0a, 0x0f, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x26, 0x0a, + 0x04, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, + 0x04, 0x66, 0x69, 0x6c, 0x65, 0x12, 0x28, 0x0a, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x18, 0x02, + 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x53, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x05, 0x63, 0x68, 0x61, 0x69, 0x6e, 0x12, + 0x2e, 0x0a, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x18, 0x11, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x46, 0x69, 0x6c, 0x65, 0x52, 0x08, 0x63, 0x68, 0x69, 0x6c, 0x64, 0x72, 0x65, 0x6e, 0x22, + 0x13, 0x0a, 0x11, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x22, 0x2b, 0x0a, 0x0f, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, + 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x18, 0x0a, 0x07, 0x64, 0x65, 0x76, 0x69, 0x63, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x07, 0x64, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x73, 0x22, 0x54, 0x0a, 0x14, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x45, 0x78, 0x70, 0x6f, + 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3c, 0x0a, 0x05, 0x74, 0x79, 0x70, + 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0e, 0x32, 0x26, 0x2e, 0x6c, 0x69, 0x62, 0x72, 0x61, + 0x72, 0x79, 0x5f, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x2e, 0x4c, + 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x45, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x05, 0x74, 0x79, 0x70, 0x65, 0x73, 0x22, 0x28, 0x0a, 0x12, 0x4c, 0x69, 0x62, 0x72, 0x61, + 0x72, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x12, 0x12, 0x0a, + 0x04, 0x6a, 0x73, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x6a, 0x73, 0x6f, + 0x6e, 0x22, 0x56, 0x0a, 0x12, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x54, 0x72, 0x69, 0x6d, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x72, 0x69, 0x6d, 0x5f, + 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0c, + 0x74, 0x72, 0x69, 0x6d, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1b, 0x0a, 0x09, + 0x74, 0x72, 0x69, 0x6d, 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x08, 0x74, 0x72, 0x69, 0x6d, 0x46, 0x69, 0x6c, 0x65, 0x22, 0x12, 0x0a, 0x10, 0x4c, 0x69, 0x62, + 0x72, 0x61, 0x72, 0x79, 0x54, 0x72, 0x69, 0x6d, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x32, 0xef, 0x09, 0x0a, 0x07, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x3b, 0x0a, 0x07, 0x46, 0x69, 0x6c, 0x65, 0x47, 0x65, 0x74, 0x12, 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x46, 0x69, 0x6c, 0x65, 0x47, 0x65, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, @@ -1873,48 +2084,58 @@ var file_service_proto_rawDesc = []byte{ 0x74, 0x65, 0x12, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x54, 0x61, 0x70, 0x65, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x54, 0x61, 0x70, 0x65, 0x44, 0x65, 0x6c, - 0x65, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x07, 0x4a, 0x6f, - 0x62, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, - 0x4a, 0x6f, 0x62, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, - 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x4c, 0x69, 0x73, 0x74, - 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x43, 0x72, - 0x65, 0x61, 0x74, 0x65, 0x12, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4a, - 0x6f, 0x62, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x43, 0x72, 0x65, - 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x4a, 0x6f, - 0x62, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, - 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3b, 0x0a, - 0x07, 0x4a, 0x6f, 0x62, 0x4e, 0x65, 0x78, 0x74, 0x12, 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x4e, - 0x65, 0x78, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0a, 0x4a, 0x6f, - 0x62, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x12, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4a, - 0x6f, 0x62, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, - 0x12, 0x41, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x12, 0x19, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x47, 0x65, 0x74, 0x4c, 0x6f, - 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, - 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x70, 0x6c, - 0x79, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, - 0x74, 0x12, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, - 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0a, 0x44, 0x65, 0x76, - 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, - 0x65, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x65, - 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, - 0x4d, 0x0a, 0x0d, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, - 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x62, 0x72, 0x61, - 0x72, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, - 0x79, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, 0x23, - 0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x61, 0x6d, - 0x75, 0x65, 0x6c, 0x6e, 0x63, 0x75, 0x69, 0x2f, 0x79, 0x61, 0x74, 0x6d, 0x2f, 0x65, 0x6e, 0x74, - 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x56, 0x0a, 0x10, 0x54, 0x61, + 0x70, 0x65, 0x47, 0x65, 0x74, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x20, + 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x54, 0x61, 0x70, 0x65, 0x47, 0x65, 0x74, + 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1e, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x54, 0x61, 0x70, 0x65, 0x47, + 0x65, 0x74, 0x50, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x07, 0x4a, 0x6f, 0x62, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x17, 0x2e, + 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x4c, 0x69, 0x73, 0x74, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, + 0x2e, 0x4a, 0x6f, 0x62, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, + 0x41, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x12, 0x19, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x43, 0x72, 0x65, 0x61, 0x74, 0x65, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x12, + 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x44, 0x65, 0x6c, + 0x65, 0x74, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x73, 0x65, 0x72, + 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x44, 0x65, 0x6c, 0x65, 0x74, 0x65, 0x52, 0x65, + 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x3b, 0x0a, 0x07, 0x4a, 0x6f, 0x62, 0x4e, 0x65, 0x78, 0x74, + 0x12, 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x4e, 0x65, + 0x78, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x4e, 0x65, 0x78, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, + 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0a, 0x4a, 0x6f, 0x62, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, + 0x12, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x44, 0x69, + 0x73, 0x70, 0x6c, 0x61, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x73, + 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x44, 0x69, 0x73, 0x70, 0x6c, 0x61, + 0x79, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x41, 0x0a, 0x09, 0x4a, 0x6f, 0x62, 0x47, + 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x12, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x4a, 0x6f, 0x62, 0x47, 0x65, 0x74, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x17, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4a, 0x6f, 0x62, 0x47, 0x65, + 0x74, 0x4c, 0x6f, 0x67, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x44, 0x0a, 0x0a, 0x53, + 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x76, + 0x69, 0x63, 0x65, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, + 0x00, 0x12, 0x44, 0x0a, 0x0a, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, 0x12, + 0x1a, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, + 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x18, 0x2e, 0x73, 0x65, + 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x44, 0x65, 0x76, 0x69, 0x63, 0x65, 0x4c, 0x69, 0x73, 0x74, + 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x4d, 0x0a, 0x0d, 0x4c, 0x69, 0x62, 0x72, 0x61, + 0x72, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x1d, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, + 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x2e, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x45, 0x78, 0x70, 0x6f, 0x72, 0x74, 0x52, + 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x12, 0x47, 0x0a, 0x0b, 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, + 0x79, 0x54, 0x72, 0x69, 0x6d, 0x12, 0x1b, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, + 0x4c, 0x69, 0x62, 0x72, 0x61, 0x72, 0x79, 0x54, 0x72, 0x69, 0x6d, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x73, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x2e, 0x4c, 0x69, 0x62, + 0x72, 0x61, 0x72, 0x79, 0x54, 0x72, 0x69, 0x6d, 0x52, 0x65, 0x70, 0x6c, 0x79, 0x22, 0x00, 0x42, + 0x23, 0x5a, 0x21, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x73, 0x61, + 0x6d, 0x75, 0x65, 0x6c, 0x6e, 0x63, 0x75, 0x69, 0x2f, 0x79, 0x61, 0x74, 0x6d, 0x2f, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1929,115 +2150,124 @@ func file_service_proto_rawDescGZIP() []byte { return file_service_proto_rawDescData } -var file_service_proto_msgTypes = make([]protoimpl.MessageInfo, 34) +var file_service_proto_msgTypes = make([]protoimpl.MessageInfo, 38) var file_service_proto_goTypes = []interface{}{ - (*FileGetRequest)(nil), // 0: service.FileGetRequest - (*FileGetReply)(nil), // 1: service.FileGetReply - (*FileEditRequest)(nil), // 2: service.FileEditRequest - (*FileEditReply)(nil), // 3: service.FileEditReply - (*FileMkdirRequest)(nil), // 4: service.FileMkdirRequest - (*FileMkdirReply)(nil), // 5: service.FileMkdirReply - (*FileDeleteRequest)(nil), // 6: service.FileDeleteRequest - (*FileDeleteReply)(nil), // 7: service.FileDeleteReply - (*FileListParentsRequest)(nil), // 8: service.FileListParentsRequest - (*FileListParentsReply)(nil), // 9: service.FileListParentsReply - (*TapeListRequest)(nil), // 10: service.TapeListRequest - (*TapeMGetRequest)(nil), // 11: service.TapeMGetRequest - (*TapeListReply)(nil), // 12: service.TapeListReply - (*TapeDeleteRequest)(nil), // 13: service.TapeDeleteRequest - (*TapeDeleteReply)(nil), // 14: service.TapeDeleteReply - (*JobListRequest)(nil), // 15: service.JobListRequest - (*JobMGetRequest)(nil), // 16: service.JobMGetRequest - (*JobListReply)(nil), // 17: service.JobListReply - (*JobCreateRequest)(nil), // 18: service.JobCreateRequest - (*JobCreateReply)(nil), // 19: service.JobCreateReply - (*JobDeleteRequest)(nil), // 20: service.JobDeleteRequest - (*JobDeleteReply)(nil), // 21: service.JobDeleteReply - (*JobNextRequest)(nil), // 22: service.JobNextRequest - (*JobNextReply)(nil), // 23: service.JobNextReply - (*JobDisplayRequest)(nil), // 24: service.JobDisplayRequest - (*JobDisplayReply)(nil), // 25: service.JobDisplayReply - (*JobGetLogRequest)(nil), // 26: service.JobGetLogRequest - (*JobGetLogReply)(nil), // 27: service.JobGetLogReply - (*SourceListRequest)(nil), // 28: service.SourceListRequest - (*SourceListReply)(nil), // 29: service.SourceListReply - (*DeviceListRequest)(nil), // 30: service.DeviceListRequest - (*DeviceListReply)(nil), // 31: service.DeviceListReply - (*LibraryExportRequest)(nil), // 32: service.LibraryExportRequest - (*LibraryExportReply)(nil), // 33: service.LibraryExportReply - (*File)(nil), // 34: file.File - (*Position)(nil), // 35: position.Position - (*EditedFile)(nil), // 36: file.EditedFile - (*TapeFilter)(nil), // 37: tape.TapeFilter - (*Tape)(nil), // 38: tape.Tape - (*JobFilter)(nil), // 39: job.JobFilter - (*Job)(nil), // 40: job.Job - (*CreatableJob)(nil), // 41: job.CreatableJob - (*JobNextParam)(nil), // 42: job.JobNextParam - (*JobDisplay)(nil), // 43: job.JobDisplay - (*SourceFile)(nil), // 44: source.SourceFile - (LibraryEntityType)(0), // 45: library_entity_type.LibraryEntityType + (*FileGetRequest)(nil), // 0: service.FileGetRequest + (*FileGetReply)(nil), // 1: service.FileGetReply + (*FileEditRequest)(nil), // 2: service.FileEditRequest + (*FileEditReply)(nil), // 3: service.FileEditReply + (*FileMkdirRequest)(nil), // 4: service.FileMkdirRequest + (*FileMkdirReply)(nil), // 5: service.FileMkdirReply + (*FileDeleteRequest)(nil), // 6: service.FileDeleteRequest + (*FileDeleteReply)(nil), // 7: service.FileDeleteReply + (*FileListParentsRequest)(nil), // 8: service.FileListParentsRequest + (*FileListParentsReply)(nil), // 9: service.FileListParentsReply + (*TapeListRequest)(nil), // 10: service.TapeListRequest + (*TapeMGetRequest)(nil), // 11: service.TapeMGetRequest + (*TapeListReply)(nil), // 12: service.TapeListReply + (*TapeDeleteRequest)(nil), // 13: service.TapeDeleteRequest + (*TapeDeleteReply)(nil), // 14: service.TapeDeleteReply + (*TapeGetPositionsRequest)(nil), // 15: service.TapeGetPositionsRequest + (*TapeGetPositionsReply)(nil), // 16: service.TapeGetPositionsReply + (*JobListRequest)(nil), // 17: service.JobListRequest + (*JobMGetRequest)(nil), // 18: service.JobMGetRequest + (*JobListReply)(nil), // 19: service.JobListReply + (*JobCreateRequest)(nil), // 20: service.JobCreateRequest + (*JobCreateReply)(nil), // 21: service.JobCreateReply + (*JobDeleteRequest)(nil), // 22: service.JobDeleteRequest + (*JobDeleteReply)(nil), // 23: service.JobDeleteReply + (*JobNextRequest)(nil), // 24: service.JobNextRequest + (*JobNextReply)(nil), // 25: service.JobNextReply + (*JobDisplayRequest)(nil), // 26: service.JobDisplayRequest + (*JobDisplayReply)(nil), // 27: service.JobDisplayReply + (*JobGetLogRequest)(nil), // 28: service.JobGetLogRequest + (*JobGetLogReply)(nil), // 29: service.JobGetLogReply + (*SourceListRequest)(nil), // 30: service.SourceListRequest + (*SourceListReply)(nil), // 31: service.SourceListReply + (*DeviceListRequest)(nil), // 32: service.DeviceListRequest + (*DeviceListReply)(nil), // 33: service.DeviceListReply + (*LibraryExportRequest)(nil), // 34: service.LibraryExportRequest + (*LibraryExportReply)(nil), // 35: service.LibraryExportReply + (*LibraryTrimRequest)(nil), // 36: service.LibraryTrimRequest + (*LibraryTrimReply)(nil), // 37: service.LibraryTrimReply + (*File)(nil), // 38: file.File + (*Position)(nil), // 39: position.Position + (*EditedFile)(nil), // 40: file.EditedFile + (*TapeFilter)(nil), // 41: tape.TapeFilter + (*Tape)(nil), // 42: tape.Tape + (*JobFilter)(nil), // 43: job.JobFilter + (*Job)(nil), // 44: job.Job + (*CreatableJob)(nil), // 45: job.CreatableJob + (*JobNextParam)(nil), // 46: job.JobNextParam + (*JobDisplay)(nil), // 47: job.JobDisplay + (*SourceFile)(nil), // 48: source.SourceFile + (LibraryEntityType)(0), // 49: library_entity_type.LibraryEntityType } var file_service_proto_depIdxs = []int32{ - 34, // 0: service.FileGetReply.file:type_name -> file.File - 35, // 1: service.FileGetReply.positions:type_name -> position.Position - 34, // 2: service.FileGetReply.children:type_name -> file.File - 36, // 3: service.FileEditRequest.file:type_name -> file.EditedFile - 34, // 4: service.FileEditReply.file:type_name -> file.File - 34, // 5: service.FileMkdirReply.file:type_name -> file.File - 34, // 6: service.FileListParentsReply.parents:type_name -> file.File + 38, // 0: service.FileGetReply.file:type_name -> file.File + 39, // 1: service.FileGetReply.positions:type_name -> position.Position + 38, // 2: service.FileGetReply.children:type_name -> file.File + 40, // 3: service.FileEditRequest.file:type_name -> file.EditedFile + 38, // 4: service.FileEditReply.file:type_name -> file.File + 38, // 5: service.FileMkdirReply.file:type_name -> file.File + 38, // 6: service.FileListParentsReply.parents:type_name -> file.File 11, // 7: service.TapeListRequest.mget:type_name -> service.TapeMGetRequest - 37, // 8: service.TapeListRequest.list:type_name -> tape.TapeFilter - 38, // 9: service.TapeListReply.tapes:type_name -> tape.Tape - 16, // 10: service.JobListRequest.mget:type_name -> service.JobMGetRequest - 39, // 11: service.JobListRequest.list:type_name -> job.JobFilter - 40, // 12: service.JobListReply.jobs:type_name -> job.Job - 41, // 13: service.JobCreateRequest.job:type_name -> job.CreatableJob - 40, // 14: service.JobCreateReply.job:type_name -> job.Job - 42, // 15: service.JobNextRequest.param:type_name -> job.JobNextParam - 40, // 16: service.JobNextReply.job:type_name -> job.Job - 43, // 17: service.JobDisplayReply.display:type_name -> job.JobDisplay - 44, // 18: service.SourceListReply.file:type_name -> source.SourceFile - 44, // 19: service.SourceListReply.chain:type_name -> source.SourceFile - 44, // 20: service.SourceListReply.children:type_name -> source.SourceFile - 45, // 21: service.LibraryExportRequest.types:type_name -> library_entity_type.LibraryEntityType - 0, // 22: service.Service.FileGet:input_type -> service.FileGetRequest - 2, // 23: service.Service.FileEdit:input_type -> service.FileEditRequest - 4, // 24: service.Service.FileMkdir:input_type -> service.FileMkdirRequest - 6, // 25: service.Service.FileDelete:input_type -> service.FileDeleteRequest - 8, // 26: service.Service.FileListParents:input_type -> service.FileListParentsRequest - 10, // 27: service.Service.TapeList:input_type -> service.TapeListRequest - 13, // 28: service.Service.TapeDelete:input_type -> service.TapeDeleteRequest - 15, // 29: service.Service.JobList:input_type -> service.JobListRequest - 18, // 30: service.Service.JobCreate:input_type -> service.JobCreateRequest - 20, // 31: service.Service.JobDelete:input_type -> service.JobDeleteRequest - 22, // 32: service.Service.JobNext:input_type -> service.JobNextRequest - 24, // 33: service.Service.JobDisplay:input_type -> service.JobDisplayRequest - 26, // 34: service.Service.JobGetLog:input_type -> service.JobGetLogRequest - 28, // 35: service.Service.SourceList:input_type -> service.SourceListRequest - 30, // 36: service.Service.DeviceList:input_type -> service.DeviceListRequest - 32, // 37: service.Service.LibraryExport:input_type -> service.LibraryExportRequest - 1, // 38: service.Service.FileGet:output_type -> service.FileGetReply - 3, // 39: service.Service.FileEdit:output_type -> service.FileEditReply - 5, // 40: service.Service.FileMkdir:output_type -> service.FileMkdirReply - 7, // 41: service.Service.FileDelete:output_type -> service.FileDeleteReply - 9, // 42: service.Service.FileListParents:output_type -> service.FileListParentsReply - 12, // 43: service.Service.TapeList:output_type -> service.TapeListReply - 14, // 44: service.Service.TapeDelete:output_type -> service.TapeDeleteReply - 17, // 45: service.Service.JobList:output_type -> service.JobListReply - 19, // 46: service.Service.JobCreate:output_type -> service.JobCreateReply - 21, // 47: service.Service.JobDelete:output_type -> service.JobDeleteReply - 23, // 48: service.Service.JobNext:output_type -> service.JobNextReply - 25, // 49: service.Service.JobDisplay:output_type -> service.JobDisplayReply - 27, // 50: service.Service.JobGetLog:output_type -> service.JobGetLogReply - 29, // 51: service.Service.SourceList:output_type -> service.SourceListReply - 31, // 52: service.Service.DeviceList:output_type -> service.DeviceListReply - 33, // 53: service.Service.LibraryExport:output_type -> service.LibraryExportReply - 38, // [38:54] is the sub-list for method output_type - 22, // [22:38] is the sub-list for method input_type - 22, // [22:22] is the sub-list for extension type_name - 22, // [22:22] is the sub-list for extension extendee - 0, // [0:22] is the sub-list for field type_name + 41, // 8: service.TapeListRequest.list:type_name -> tape.TapeFilter + 42, // 9: service.TapeListReply.tapes:type_name -> tape.Tape + 39, // 10: service.TapeGetPositionsReply.positions:type_name -> position.Position + 18, // 11: service.JobListRequest.mget:type_name -> service.JobMGetRequest + 43, // 12: service.JobListRequest.list:type_name -> job.JobFilter + 44, // 13: service.JobListReply.jobs:type_name -> job.Job + 45, // 14: service.JobCreateRequest.job:type_name -> job.CreatableJob + 44, // 15: service.JobCreateReply.job:type_name -> job.Job + 46, // 16: service.JobNextRequest.param:type_name -> job.JobNextParam + 44, // 17: service.JobNextReply.job:type_name -> job.Job + 47, // 18: service.JobDisplayReply.display:type_name -> job.JobDisplay + 48, // 19: service.SourceListReply.file:type_name -> source.SourceFile + 48, // 20: service.SourceListReply.chain:type_name -> source.SourceFile + 48, // 21: service.SourceListReply.children:type_name -> source.SourceFile + 49, // 22: service.LibraryExportRequest.types:type_name -> library_entity_type.LibraryEntityType + 0, // 23: service.Service.FileGet:input_type -> service.FileGetRequest + 2, // 24: service.Service.FileEdit:input_type -> service.FileEditRequest + 4, // 25: service.Service.FileMkdir:input_type -> service.FileMkdirRequest + 6, // 26: service.Service.FileDelete:input_type -> service.FileDeleteRequest + 8, // 27: service.Service.FileListParents:input_type -> service.FileListParentsRequest + 10, // 28: service.Service.TapeList:input_type -> service.TapeListRequest + 13, // 29: service.Service.TapeDelete:input_type -> service.TapeDeleteRequest + 15, // 30: service.Service.TapeGetPositions:input_type -> service.TapeGetPositionsRequest + 17, // 31: service.Service.JobList:input_type -> service.JobListRequest + 20, // 32: service.Service.JobCreate:input_type -> service.JobCreateRequest + 22, // 33: service.Service.JobDelete:input_type -> service.JobDeleteRequest + 24, // 34: service.Service.JobNext:input_type -> service.JobNextRequest + 26, // 35: service.Service.JobDisplay:input_type -> service.JobDisplayRequest + 28, // 36: service.Service.JobGetLog:input_type -> service.JobGetLogRequest + 30, // 37: service.Service.SourceList:input_type -> service.SourceListRequest + 32, // 38: service.Service.DeviceList:input_type -> service.DeviceListRequest + 34, // 39: service.Service.LibraryExport:input_type -> service.LibraryExportRequest + 36, // 40: service.Service.LibraryTrim:input_type -> service.LibraryTrimRequest + 1, // 41: service.Service.FileGet:output_type -> service.FileGetReply + 3, // 42: service.Service.FileEdit:output_type -> service.FileEditReply + 5, // 43: service.Service.FileMkdir:output_type -> service.FileMkdirReply + 7, // 44: service.Service.FileDelete:output_type -> service.FileDeleteReply + 9, // 45: service.Service.FileListParents:output_type -> service.FileListParentsReply + 12, // 46: service.Service.TapeList:output_type -> service.TapeListReply + 14, // 47: service.Service.TapeDelete:output_type -> service.TapeDeleteReply + 16, // 48: service.Service.TapeGetPositions:output_type -> service.TapeGetPositionsReply + 19, // 49: service.Service.JobList:output_type -> service.JobListReply + 21, // 50: service.Service.JobCreate:output_type -> service.JobCreateReply + 23, // 51: service.Service.JobDelete:output_type -> service.JobDeleteReply + 25, // 52: service.Service.JobNext:output_type -> service.JobNextReply + 27, // 53: service.Service.JobDisplay:output_type -> service.JobDisplayReply + 29, // 54: service.Service.JobGetLog:output_type -> service.JobGetLogReply + 31, // 55: service.Service.SourceList:output_type -> service.SourceListReply + 33, // 56: service.Service.DeviceList:output_type -> service.DeviceListReply + 35, // 57: service.Service.LibraryExport:output_type -> service.LibraryExportReply + 37, // 58: service.Service.LibraryTrim:output_type -> service.LibraryTrimReply + 41, // [41:59] is the sub-list for method output_type + 23, // [23:41] is the sub-list for method input_type + 23, // [23:23] is the sub-list for extension type_name + 23, // [23:23] is the sub-list for extension extendee + 0, // [0:23] is the sub-list for field type_name } func init() { file_service_proto_init() } @@ -2233,7 +2463,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobListRequest); i { + switch v := v.(*TapeGetPositionsRequest); i { case 0: return &v.state case 1: @@ -2245,7 +2475,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobMGetRequest); i { + switch v := v.(*TapeGetPositionsReply); i { case 0: return &v.state case 1: @@ -2257,7 +2487,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobListReply); i { + switch v := v.(*JobListRequest); i { case 0: return &v.state case 1: @@ -2269,7 +2499,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobCreateRequest); i { + switch v := v.(*JobMGetRequest); i { case 0: return &v.state case 1: @@ -2281,7 +2511,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobCreateReply); i { + switch v := v.(*JobListReply); i { case 0: return &v.state case 1: @@ -2293,7 +2523,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobDeleteRequest); i { + switch v := v.(*JobCreateRequest); i { case 0: return &v.state case 1: @@ -2305,7 +2535,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobDeleteReply); i { + switch v := v.(*JobCreateReply); i { case 0: return &v.state case 1: @@ -2317,7 +2547,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobNextRequest); i { + switch v := v.(*JobDeleteRequest); i { case 0: return &v.state case 1: @@ -2329,7 +2559,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobNextReply); i { + switch v := v.(*JobDeleteReply); i { case 0: return &v.state case 1: @@ -2341,7 +2571,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobDisplayRequest); i { + switch v := v.(*JobNextRequest); i { case 0: return &v.state case 1: @@ -2353,7 +2583,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobDisplayReply); i { + switch v := v.(*JobNextReply); i { case 0: return &v.state case 1: @@ -2365,7 +2595,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobGetLogRequest); i { + switch v := v.(*JobDisplayRequest); i { case 0: return &v.state case 1: @@ -2377,7 +2607,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[27].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*JobGetLogReply); i { + switch v := v.(*JobDisplayReply); i { case 0: return &v.state case 1: @@ -2389,7 +2619,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SourceListRequest); i { + switch v := v.(*JobGetLogRequest); i { case 0: return &v.state case 1: @@ -2401,7 +2631,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[29].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*SourceListReply); i { + switch v := v.(*JobGetLogReply); i { case 0: return &v.state case 1: @@ -2413,7 +2643,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[30].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeviceListRequest); i { + switch v := v.(*SourceListRequest); i { case 0: return &v.state case 1: @@ -2425,7 +2655,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[31].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*DeviceListReply); i { + switch v := v.(*SourceListReply); i { case 0: return &v.state case 1: @@ -2437,7 +2667,7 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[32].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*LibraryExportRequest); i { + switch v := v.(*DeviceListRequest); i { case 0: return &v.state case 1: @@ -2449,6 +2679,30 @@ func file_service_proto_init() { } } file_service_proto_msgTypes[33].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*DeviceListReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_service_proto_msgTypes[34].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LibraryExportRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_service_proto_msgTypes[35].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*LibraryExportReply); i { case 0: return &v.state @@ -2460,24 +2714,48 @@ func file_service_proto_init() { return nil } } + file_service_proto_msgTypes[36].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LibraryTrimRequest); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_service_proto_msgTypes[37].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LibraryTrimReply); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } file_service_proto_msgTypes[1].OneofWrappers = []interface{}{} file_service_proto_msgTypes[10].OneofWrappers = []interface{}{ (*TapeListRequest_Mget)(nil), (*TapeListRequest_List)(nil), } - file_service_proto_msgTypes[15].OneofWrappers = []interface{}{ + file_service_proto_msgTypes[17].OneofWrappers = []interface{}{ (*JobListRequest_Mget)(nil), (*JobListRequest_List)(nil), } - file_service_proto_msgTypes[26].OneofWrappers = []interface{}{} + file_service_proto_msgTypes[28].OneofWrappers = []interface{}{} type x struct{} out := protoimpl.TypeBuilder{ File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_service_proto_rawDesc, NumEnums: 0, - NumMessages: 34, + NumMessages: 38, NumExtensions: 0, NumServices: 1, }, diff --git a/entity/service.proto b/entity/service.proto index 6459cf5..4248491 100644 --- a/entity/service.proto +++ b/entity/service.proto @@ -18,6 +18,7 @@ service Service { rpc TapeList(TapeListRequest) returns (TapeListReply) {} rpc TapeDelete(TapeDeleteRequest) returns (TapeDeleteReply) {} + rpc TapeGetPositions(TapeGetPositionsRequest) returns (TapeGetPositionsReply) {} rpc JobList(JobListRequest) returns (JobListReply) {} rpc JobCreate(JobCreateRequest) returns (JobCreateReply) {} @@ -31,6 +32,7 @@ service Service { rpc DeviceList(DeviceListRequest) returns (DeviceListReply) {} rpc LibraryExport(LibraryExportRequest) returns (LibraryExportReply) {} + rpc LibraryTrim(LibraryTrimRequest) returns (LibraryTrimReply) {} } message FileGetRequest { @@ -98,6 +100,15 @@ message TapeDeleteRequest { message TapeDeleteReply { } +message TapeGetPositionsRequest { + int64 id = 1; + string directory = 2; +} + +message TapeGetPositionsReply { + repeated position.Position positions = 1; +} + message JobListRequest { oneof param { JobMGetRequest mget = 1; @@ -177,3 +188,11 @@ message LibraryExportRequest { message LibraryExportReply { bytes json = 1; } + +message LibraryTrimRequest { + bool trim_position = 1; + bool trim_file = 2; +} + +message LibraryTrimReply { +} diff --git a/entity/service_grpc.pb.go b/entity/service_grpc.pb.go index c4adb04..682ffee 100644 --- a/entity/service_grpc.pb.go +++ b/entity/service_grpc.pb.go @@ -29,6 +29,7 @@ type ServiceClient interface { FileListParents(ctx context.Context, in *FileListParentsRequest, opts ...grpc.CallOption) (*FileListParentsReply, error) TapeList(ctx context.Context, in *TapeListRequest, opts ...grpc.CallOption) (*TapeListReply, error) TapeDelete(ctx context.Context, in *TapeDeleteRequest, opts ...grpc.CallOption) (*TapeDeleteReply, error) + TapeGetPositions(ctx context.Context, in *TapeGetPositionsRequest, opts ...grpc.CallOption) (*TapeGetPositionsReply, error) JobList(ctx context.Context, in *JobListRequest, opts ...grpc.CallOption) (*JobListReply, error) JobCreate(ctx context.Context, in *JobCreateRequest, opts ...grpc.CallOption) (*JobCreateReply, error) JobDelete(ctx context.Context, in *JobDeleteRequest, opts ...grpc.CallOption) (*JobDeleteReply, error) @@ -38,6 +39,7 @@ type ServiceClient interface { SourceList(ctx context.Context, in *SourceListRequest, opts ...grpc.CallOption) (*SourceListReply, error) DeviceList(ctx context.Context, in *DeviceListRequest, opts ...grpc.CallOption) (*DeviceListReply, error) LibraryExport(ctx context.Context, in *LibraryExportRequest, opts ...grpc.CallOption) (*LibraryExportReply, error) + LibraryTrim(ctx context.Context, in *LibraryTrimRequest, opts ...grpc.CallOption) (*LibraryTrimReply, error) } type serviceClient struct { @@ -111,6 +113,15 @@ func (c *serviceClient) TapeDelete(ctx context.Context, in *TapeDeleteRequest, o return out, nil } +func (c *serviceClient) TapeGetPositions(ctx context.Context, in *TapeGetPositionsRequest, opts ...grpc.CallOption) (*TapeGetPositionsReply, error) { + out := new(TapeGetPositionsReply) + err := c.cc.Invoke(ctx, "/service.Service/TapeGetPositions", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + func (c *serviceClient) JobList(ctx context.Context, in *JobListRequest, opts ...grpc.CallOption) (*JobListReply, error) { out := new(JobListReply) err := c.cc.Invoke(ctx, "/service.Service/JobList", in, out, opts...) @@ -192,6 +203,15 @@ func (c *serviceClient) LibraryExport(ctx context.Context, in *LibraryExportRequ return out, nil } +func (c *serviceClient) LibraryTrim(ctx context.Context, in *LibraryTrimRequest, opts ...grpc.CallOption) (*LibraryTrimReply, error) { + out := new(LibraryTrimReply) + err := c.cc.Invoke(ctx, "/service.Service/LibraryTrim", in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + // ServiceServer is the server API for Service service. // All implementations must embed UnimplementedServiceServer // for forward compatibility @@ -203,6 +223,7 @@ type ServiceServer interface { FileListParents(context.Context, *FileListParentsRequest) (*FileListParentsReply, error) TapeList(context.Context, *TapeListRequest) (*TapeListReply, error) TapeDelete(context.Context, *TapeDeleteRequest) (*TapeDeleteReply, error) + TapeGetPositions(context.Context, *TapeGetPositionsRequest) (*TapeGetPositionsReply, error) JobList(context.Context, *JobListRequest) (*JobListReply, error) JobCreate(context.Context, *JobCreateRequest) (*JobCreateReply, error) JobDelete(context.Context, *JobDeleteRequest) (*JobDeleteReply, error) @@ -212,6 +233,7 @@ type ServiceServer interface { SourceList(context.Context, *SourceListRequest) (*SourceListReply, error) DeviceList(context.Context, *DeviceListRequest) (*DeviceListReply, error) LibraryExport(context.Context, *LibraryExportRequest) (*LibraryExportReply, error) + LibraryTrim(context.Context, *LibraryTrimRequest) (*LibraryTrimReply, error) mustEmbedUnimplementedServiceServer() } @@ -240,6 +262,9 @@ func (UnimplementedServiceServer) TapeList(context.Context, *TapeListRequest) (* func (UnimplementedServiceServer) TapeDelete(context.Context, *TapeDeleteRequest) (*TapeDeleteReply, error) { return nil, status.Errorf(codes.Unimplemented, "method TapeDelete not implemented") } +func (UnimplementedServiceServer) TapeGetPositions(context.Context, *TapeGetPositionsRequest) (*TapeGetPositionsReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method TapeGetPositions not implemented") +} func (UnimplementedServiceServer) JobList(context.Context, *JobListRequest) (*JobListReply, error) { return nil, status.Errorf(codes.Unimplemented, "method JobList not implemented") } @@ -267,6 +292,9 @@ func (UnimplementedServiceServer) DeviceList(context.Context, *DeviceListRequest func (UnimplementedServiceServer) LibraryExport(context.Context, *LibraryExportRequest) (*LibraryExportReply, error) { return nil, status.Errorf(codes.Unimplemented, "method LibraryExport not implemented") } +func (UnimplementedServiceServer) LibraryTrim(context.Context, *LibraryTrimRequest) (*LibraryTrimReply, error) { + return nil, status.Errorf(codes.Unimplemented, "method LibraryTrim not implemented") +} func (UnimplementedServiceServer) mustEmbedUnimplementedServiceServer() {} // UnsafeServiceServer may be embedded to opt out of forward compatibility for this service. @@ -406,6 +434,24 @@ func _Service_TapeDelete_Handler(srv interface{}, ctx context.Context, dec func( return interceptor(ctx, in, info, handler) } +func _Service_TapeGetPositions_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TapeGetPositionsRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ServiceServer).TapeGetPositions(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/service.Service/TapeGetPositions", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ServiceServer).TapeGetPositions(ctx, req.(*TapeGetPositionsRequest)) + } + return interceptor(ctx, in, info, handler) +} + func _Service_JobList_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { in := new(JobListRequest) if err := dec(in); err != nil { @@ -568,6 +614,24 @@ func _Service_LibraryExport_Handler(srv interface{}, ctx context.Context, dec fu return interceptor(ctx, in, info, handler) } +func _Service_LibraryTrim_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LibraryTrimRequest) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(ServiceServer).LibraryTrim(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: "/service.Service/LibraryTrim", + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(ServiceServer).LibraryTrim(ctx, req.(*LibraryTrimRequest)) + } + return interceptor(ctx, in, info, handler) +} + // Service_ServiceDesc is the grpc.ServiceDesc for Service service. // It's only intended for direct use with grpc.RegisterService, // and not to be introspected or modified (even as a copy) @@ -603,6 +667,10 @@ var Service_ServiceDesc = grpc.ServiceDesc{ MethodName: "TapeDelete", Handler: _Service_TapeDelete_Handler, }, + { + MethodName: "TapeGetPositions", + Handler: _Service_TapeGetPositions_Handler, + }, { MethodName: "JobList", Handler: _Service_JobList_Handler, @@ -639,6 +707,10 @@ var Service_ServiceDesc = grpc.ServiceDesc{ MethodName: "LibraryExport", Handler: _Service_LibraryExport_Handler, }, + { + MethodName: "LibraryTrim", + Handler: _Service_LibraryTrim_Handler, + }, }, Streams: []grpc.StreamDesc{}, Metadata: "service.proto", diff --git a/frontend/package.json b/frontend/package.json index 3458f61..4ea0ffb 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,5 +1,5 @@ { - "name": "tape-manager", + "name": "yatm", "private": true, "version": "0.0.0", "type": "module", diff --git a/frontend/src/api.ts b/frontend/src/api.ts index f8ef0dd..4d17ca9 100644 --- a/frontend/src/api.ts +++ b/frontend/src/api.ts @@ -1,6 +1,6 @@ import { FileData } from "@aperturerobotics/chonky"; import { GrpcWebFetchTransport } from "@protobuf-ts/grpcweb-transport"; -import { ServiceClient, File, SourceFile } from "./entity"; +import { ServiceClient, File, SourceFile, Tape, Position } from "./entity"; import moment from "moment"; @@ -28,11 +28,6 @@ export const Root: FileData = { droppable: true, }; -export const sleep = (ms: number): Promise => - new Promise((resolve) => { - setTimeout(resolve, ms); - }); - const transport = new GrpcWebFetchTransport({ baseUrl: apiBase, format: "binary", @@ -81,6 +76,56 @@ export function convertSourceFiles(files: Array): FileData[] { }); } +export function convertTapes(tapes: Array): FileData[] { + return tapes.map((tape) => { + // const isDir = (file.mode & ModeDir) > 0; + + return { + id: `${tape.id}`, + name: tape.barcode, + ext: "", + isDir: true, + isHidden: false, + openable: true, + selectable: true, + draggable: false, + droppable: false, + size: 0, + modDate: moment.unix(Number(tape.createTime)).toDate(), + isTape: true, + }; + }); +} + +export function convertPositions(positions: Array): FileData[] { + return positions.map((posi) => { + const isDir = (posi.mode & ModeDir) > 0; + const name = isDir ? splitPath(posi.path.slice(0, -1)) : splitPath(posi.path); + + return { + id: `${posi.tapeId}:${posi.path}`, + name: name, + ext: extname(name), + isDir: isDir, + isHidden: false, + openable: isDir, + selectable: false, + draggable: false, + droppable: false, + size: Number(posi.size), + modDate: moment.unix(Number(posi.writeTime)).toDate(), + }; + }); +} + +function splitPath(filename: string): string { + const idx = filename.lastIndexOf("/"); + if (idx < 0) { + return filename; + } + return filename.slice(idx + 1); +} + function extname(filename: string): string { const idx = filename.lastIndexOf("."); if (idx < 0) { diff --git a/frontend/src/app.tsx b/frontend/src/app.tsx index fe8111e..00d0c0e 100644 --- a/frontend/src/app.tsx +++ b/frontend/src/app.tsx @@ -12,7 +12,7 @@ import { TapesBrowser, TapesType } from "./pages/tapes"; import { JobsBrowser, JobsType } from "./pages/jobs"; import "./app.less"; -import { sleep } from "./api"; +import { sleep } from "./tools"; import { Nullable } from "tsdef"; import { Job } from "./entity"; import { useEffect } from "react"; @@ -46,7 +46,7 @@ const App = () => { (_: ChangeEvent<{}>, newValue: string) => { navigate("/" + newValue); }, - [navigate] + [navigate], ); return ( diff --git a/frontend/src/entity/service.client.ts b/frontend/src/entity/service.client.ts index d68b161..601f109 100644 --- a/frontend/src/entity/service.client.ts +++ b/frontend/src/entity/service.client.ts @@ -4,6 +4,8 @@ import type { RpcTransport } from "@protobuf-ts/runtime-rpc"; import type { ServiceInfo } from "@protobuf-ts/runtime-rpc"; import { Service } from "./service"; +import type { LibraryTrimReply } from "./service"; +import type { LibraryTrimRequest } from "./service"; import type { LibraryExportReply } from "./service"; import type { LibraryExportRequest } from "./service"; import type { DeviceListReply } from "./service"; @@ -22,6 +24,8 @@ import type { JobCreateReply } from "./service"; import type { JobCreateRequest } from "./service"; import type { JobListReply } from "./service"; import type { JobListRequest } from "./service"; +import type { TapeGetPositionsReply } from "./service"; +import type { TapeGetPositionsRequest } from "./service"; import type { TapeDeleteReply } from "./service"; import type { TapeDeleteRequest } from "./service"; import type { TapeListReply } from "./service"; @@ -71,6 +75,10 @@ export interface IServiceClient { * @generated from protobuf rpc: TapeDelete(service.TapeDeleteRequest) returns (service.TapeDeleteReply); */ tapeDelete(input: TapeDeleteRequest, options?: RpcOptions): UnaryCall; + /** + * @generated from protobuf rpc: TapeGetPositions(service.TapeGetPositionsRequest) returns (service.TapeGetPositionsReply); + */ + tapeGetPositions(input: TapeGetPositionsRequest, options?: RpcOptions): UnaryCall; /** * @generated from protobuf rpc: JobList(service.JobListRequest) returns (service.JobListReply); */ @@ -107,6 +115,10 @@ export interface IServiceClient { * @generated from protobuf rpc: LibraryExport(service.LibraryExportRequest) returns (service.LibraryExportReply); */ libraryExport(input: LibraryExportRequest, options?: RpcOptions): UnaryCall; + /** + * @generated from protobuf rpc: LibraryTrim(service.LibraryTrimRequest) returns (service.LibraryTrimReply); + */ + libraryTrim(input: LibraryTrimRequest, options?: RpcOptions): UnaryCall; } /** * @generated from protobuf service service.Service @@ -166,67 +178,81 @@ export class ServiceClient implements IServiceClient, ServiceInfo { const method = this.methods[6], opt = this._transport.mergeOptions(options); return stackIntercept("unary", this._transport, method, opt, input); } + /** + * @generated from protobuf rpc: TapeGetPositions(service.TapeGetPositionsRequest) returns (service.TapeGetPositionsReply); + */ + tapeGetPositions(input: TapeGetPositionsRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[7], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } /** * @generated from protobuf rpc: JobList(service.JobListRequest) returns (service.JobListReply); */ jobList(input: JobListRequest, options?: RpcOptions): UnaryCall { - const method = this.methods[7], opt = this._transport.mergeOptions(options); + const method = this.methods[8], opt = this._transport.mergeOptions(options); return stackIntercept("unary", this._transport, method, opt, input); } /** * @generated from protobuf rpc: JobCreate(service.JobCreateRequest) returns (service.JobCreateReply); */ jobCreate(input: JobCreateRequest, options?: RpcOptions): UnaryCall { - const method = this.methods[8], opt = this._transport.mergeOptions(options); + const method = this.methods[9], opt = this._transport.mergeOptions(options); return stackIntercept("unary", this._transport, method, opt, input); } /** * @generated from protobuf rpc: JobDelete(service.JobDeleteRequest) returns (service.JobDeleteReply); */ jobDelete(input: JobDeleteRequest, options?: RpcOptions): UnaryCall { - const method = this.methods[9], opt = this._transport.mergeOptions(options); + const method = this.methods[10], opt = this._transport.mergeOptions(options); return stackIntercept("unary", this._transport, method, opt, input); } /** * @generated from protobuf rpc: JobNext(service.JobNextRequest) returns (service.JobNextReply); */ jobNext(input: JobNextRequest, options?: RpcOptions): UnaryCall { - const method = this.methods[10], opt = this._transport.mergeOptions(options); + const method = this.methods[11], opt = this._transport.mergeOptions(options); return stackIntercept("unary", this._transport, method, opt, input); } /** * @generated from protobuf rpc: JobDisplay(service.JobDisplayRequest) returns (service.JobDisplayReply); */ jobDisplay(input: JobDisplayRequest, options?: RpcOptions): UnaryCall { - const method = this.methods[11], opt = this._transport.mergeOptions(options); + const method = this.methods[12], opt = this._transport.mergeOptions(options); return stackIntercept("unary", this._transport, method, opt, input); } /** * @generated from protobuf rpc: JobGetLog(service.JobGetLogRequest) returns (service.JobGetLogReply); */ jobGetLog(input: JobGetLogRequest, options?: RpcOptions): UnaryCall { - const method = this.methods[12], opt = this._transport.mergeOptions(options); + const method = this.methods[13], opt = this._transport.mergeOptions(options); return stackIntercept("unary", this._transport, method, opt, input); } /** * @generated from protobuf rpc: SourceList(service.SourceListRequest) returns (service.SourceListReply); */ sourceList(input: SourceListRequest, options?: RpcOptions): UnaryCall { - const method = this.methods[13], opt = this._transport.mergeOptions(options); + const method = this.methods[14], opt = this._transport.mergeOptions(options); return stackIntercept("unary", this._transport, method, opt, input); } /** * @generated from protobuf rpc: DeviceList(service.DeviceListRequest) returns (service.DeviceListReply); */ deviceList(input: DeviceListRequest, options?: RpcOptions): UnaryCall { - const method = this.methods[14], opt = this._transport.mergeOptions(options); + const method = this.methods[15], opt = this._transport.mergeOptions(options); return stackIntercept("unary", this._transport, method, opt, input); } /** * @generated from protobuf rpc: LibraryExport(service.LibraryExportRequest) returns (service.LibraryExportReply); */ libraryExport(input: LibraryExportRequest, options?: RpcOptions): UnaryCall { - const method = this.methods[15], opt = this._transport.mergeOptions(options); + const method = this.methods[16], opt = this._transport.mergeOptions(options); return stackIntercept("unary", this._transport, method, opt, input); } + /** + * @generated from protobuf rpc: LibraryTrim(service.LibraryTrimRequest) returns (service.LibraryTrimReply); + */ + libraryTrim(input: LibraryTrimRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[17], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } } diff --git a/frontend/src/entity/service.ts b/frontend/src/entity/service.ts index 9f1c59c..1046b5a 100644 --- a/frontend/src/entity/service.ts +++ b/frontend/src/entity/service.ts @@ -181,6 +181,28 @@ export interface TapeDeleteRequest { */ export interface TapeDeleteReply { } +/** + * @generated from protobuf message service.TapeGetPositionsRequest + */ +export interface TapeGetPositionsRequest { + /** + * @generated from protobuf field: int64 id = 1; + */ + id: bigint; + /** + * @generated from protobuf field: string directory = 2; + */ + directory: string; +} +/** + * @generated from protobuf message service.TapeGetPositionsReply + */ +export interface TapeGetPositionsReply { + /** + * @generated from protobuf field: repeated position.Position positions = 1; + */ + positions: Position[]; +} /** * @generated from protobuf message service.JobListRequest */ @@ -374,6 +396,24 @@ export interface LibraryExportReply { */ json: Uint8Array; } +/** + * @generated from protobuf message service.LibraryTrimRequest + */ +export interface LibraryTrimRequest { + /** + * @generated from protobuf field: bool trim_position = 1; + */ + trimPosition: boolean; + /** + * @generated from protobuf field: bool trim_file = 2; + */ + trimFile: boolean; +} +/** + * @generated from protobuf message service.LibraryTrimReply + */ +export interface LibraryTrimReply { +} // @generated message type with reflection information, may provide speed optimized methods class FileGetRequest$Type extends MessageType { constructor() { @@ -1103,6 +1143,107 @@ class TapeDeleteReply$Type extends MessageType { */ export const TapeDeleteReply = new TapeDeleteReply$Type(); // @generated message type with reflection information, may provide speed optimized methods +class TapeGetPositionsRequest$Type extends MessageType { + constructor() { + super("service.TapeGetPositionsRequest", [ + { no: 1, name: "id", kind: "scalar", T: 3 /*ScalarType.INT64*/, L: 0 /*LongType.BIGINT*/ }, + { no: 2, name: "directory", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): TapeGetPositionsRequest { + const message = { id: 0n, directory: "" }; + globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TapeGetPositionsRequest): TapeGetPositionsRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* int64 id */ 1: + message.id = reader.int64().toBigInt(); + break; + case /* string directory */ 2: + message.directory = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TapeGetPositionsRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* int64 id = 1; */ + if (message.id !== 0n) + writer.tag(1, WireType.Varint).int64(message.id); + /* string directory = 2; */ + if (message.directory !== "") + writer.tag(2, WireType.LengthDelimited).string(message.directory); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message service.TapeGetPositionsRequest + */ +export const TapeGetPositionsRequest = new TapeGetPositionsRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TapeGetPositionsReply$Type extends MessageType { + constructor() { + super("service.TapeGetPositionsReply", [ + { no: 1, name: "positions", kind: "message", repeat: 1 /*RepeatType.PACKED*/, T: () => Position } + ]); + } + create(value?: PartialMessage): TapeGetPositionsReply { + const message = { positions: [] }; + globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TapeGetPositionsReply): TapeGetPositionsReply { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* repeated position.Position positions */ 1: + message.positions.push(Position.internalBinaryRead(reader, reader.uint32(), options)); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TapeGetPositionsReply, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* repeated position.Position positions = 1; */ + for (let i = 0; i < message.positions.length; i++) + Position.internalBinaryWrite(message.positions[i], writer.tag(1, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message service.TapeGetPositionsReply + */ +export const TapeGetPositionsReply = new TapeGetPositionsReply$Type(); +// @generated message type with reflection information, may provide speed optimized methods class JobListRequest$Type extends MessageType { constructor() { super("service.JobListRequest", [ @@ -2018,6 +2159,86 @@ class LibraryExportReply$Type extends MessageType { * @generated MessageType for protobuf message service.LibraryExportReply */ export const LibraryExportReply = new LibraryExportReply$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class LibraryTrimRequest$Type extends MessageType { + constructor() { + super("service.LibraryTrimRequest", [ + { no: 1, name: "trim_position", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 2, name: "trim_file", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): LibraryTrimRequest { + const message = { trimPosition: false, trimFile: false }; + globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: LibraryTrimRequest): LibraryTrimRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* bool trim_position */ 1: + message.trimPosition = reader.bool(); + break; + case /* bool trim_file */ 2: + message.trimFile = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: LibraryTrimRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* bool trim_position = 1; */ + if (message.trimPosition !== false) + writer.tag(1, WireType.Varint).bool(message.trimPosition); + /* bool trim_file = 2; */ + if (message.trimFile !== false) + writer.tag(2, WireType.Varint).bool(message.trimFile); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message service.LibraryTrimRequest + */ +export const LibraryTrimRequest = new LibraryTrimRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class LibraryTrimReply$Type extends MessageType { + constructor() { + super("service.LibraryTrimReply", []); + } + create(value?: PartialMessage): LibraryTrimReply { + const message = {}; + globalThis.Object.defineProperty(message, MESSAGE_TYPE, { enumerable: false, value: this }); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: LibraryTrimReply): LibraryTrimReply { + return target ?? this.create(); + } + internalBinaryWrite(message: LibraryTrimReply, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message service.LibraryTrimReply + */ +export const LibraryTrimReply = new LibraryTrimReply$Type(); /** * @generated ServiceType for protobuf service service.Service */ @@ -2029,6 +2250,7 @@ export const Service = new ServiceType("service.Service", [ { name: "FileListParents", options: {}, I: FileListParentsRequest, O: FileListParentsReply }, { name: "TapeList", options: {}, I: TapeListRequest, O: TapeListReply }, { name: "TapeDelete", options: {}, I: TapeDeleteRequest, O: TapeDeleteReply }, + { name: "TapeGetPositions", options: {}, I: TapeGetPositionsRequest, O: TapeGetPositionsReply }, { name: "JobList", options: {}, I: JobListRequest, O: JobListReply }, { name: "JobCreate", options: {}, I: JobCreateRequest, O: JobCreateReply }, { name: "JobDelete", options: {}, I: JobDeleteRequest, O: JobDeleteReply }, @@ -2037,5 +2259,6 @@ export const Service = new ServiceType("service.Service", [ { name: "JobGetLog", options: {}, I: JobGetLogRequest, O: JobGetLogReply }, { name: "SourceList", options: {}, I: SourceListRequest, O: SourceListReply }, { name: "DeviceList", options: {}, I: DeviceListRequest, O: DeviceListReply }, - { name: "LibraryExport", options: {}, I: LibraryExportRequest, O: LibraryExportReply } + { name: "LibraryExport", options: {}, I: LibraryExportRequest, O: LibraryExportReply }, + { name: "LibraryTrim", options: {}, I: LibraryTrimRequest, O: LibraryTrimReply } ]); diff --git a/frontend/src/pages/jobs.tsx b/frontend/src/pages/jobs.tsx index 7733706..cb5787a 100644 --- a/frontend/src/pages/jobs.tsx +++ b/frontend/src/pages/jobs.tsx @@ -34,7 +34,8 @@ import { TreeView, TreeItem } from "@mui/x-tree-view"; import ExpandMoreIcon from "@mui/icons-material/ExpandMore"; import ChevronRightIcon from "@mui/icons-material/ChevronRight"; -import { cli, sleep, fileBase } from "../api"; +import { cli, fileBase } from "../api"; +import { sleep } from "../tools"; import { Job, JobDisplay, JobListRequest, JobNextRequest, JobStatus, CopyStatus, LibraryEntityType, JobDeleteRequest } from "../entity"; import { JobArchiveCopyingParam, JobArchiveStep, JobArchiveDisplay, JobArchiveState } from "../entity"; @@ -54,8 +55,20 @@ export const JobsBrowser = () => { const [jobs, setJobs] = useState(null); const refresh = useCallback(async () => { const jobReplys = await cli.jobList(JobListRequest.create({ param: { oneofKind: "list", list: {} } })).response; - const displayReplys = await Promise.all(jobReplys.jobs.map((job) => cli.jobDisplay({ id: job.id }).response)); - const targets = jobReplys.jobs.map((job, idx) => ({ ...job, ...displayReplys[idx].display })); + const displays = new Map(); + for (const reply of await Promise.all( + jobReplys.jobs + .filter((job) => job.status === JobStatus.PROCESSING) + .map((job) => cli.jobDisplay({ id: job.id }).response.then((reply) => ({ ...reply, jobID: job.id }))), + )) { + if (!reply.display) { + continue; + } + + displays.set(reply.jobID, reply.display); + } + + const targets = jobReplys.jobs.map((job) => ({ ...job, ...displays.get(job.id) })); console.log("refresh jobs list, ", targets); setJobs(targets); }, [setJobs]); diff --git a/frontend/src/pages/tapes.tsx b/frontend/src/pages/tapes.tsx index fd0e9b8..3b9a9de 100644 --- a/frontend/src/pages/tapes.tsx +++ b/frontend/src/pages/tapes.tsx @@ -6,48 +6,78 @@ import Box from "@mui/material/Box"; import { FileBrowser, FileNavbar, FileToolbar, FileList, FileContextMenu, FileArray, FileBrowserHandle } from "@aperturerobotics/chonky"; import { ChonkyActions, ChonkyFileActionData, FileData } from "@aperturerobotics/chonky"; -import { cli, Root } from "../api"; -import { TapeListRequest, Source, Tape } from "../entity"; +import { cli, Root, convertTapes, convertPositions } from "../api"; +import { TapeListRequest, Source, Tape, Position } from "../entity"; export const TapesType = "tapes"; -const convertTapes = (tapes: Array): FileData[] => { - return tapes.map((tape) => { - // const isDir = (file.mode & ModeDir) > 0; - - return { - id: `${tape.id}`, - name: tape.barcode, - ext: "", - isDir: true, - isHidden: false, - openable: false, - selectable: true, - draggable: true, - droppable: false, - size: 0, - modDate: moment.unix(Number(tape.createTime)).toDate(), - }; - }); -}; - const useTapesSourceBrowser = (source: RefObject) => { const [files, setFiles] = useState(Array(1).fill(null)); const [folderChain, setFolderChan] = useState([Root]); + const current = useMemo(() => { + if (folderChain.length === 0) { + return Root; + } + + const last = folderChain.slice(-1)[0]; + if (!last) { + return Root; + } + + return last; + }, [folderChain]); + + const openFolder = useCallback( + async (target: FileData) => { + if (target.id === Root.id) { + const reply = await cli.tapeList({ param: { oneofKind: "list", list: { offset: 0n, limit: 1000n } } }).response; + + setFiles(convertTapes(reply.tapes)); + setFolderChan([Root]); + return; + } - const openFolder = useCallback(async (id: string) => { - const reply = await cli.tapeList({ param: { oneofKind: "list", list: { offset: 0n, limit: 1000n } } }).response; + const id = target.id; + var tapeIDStr = id; + var dir = ""; - setFiles(convertTapes(reply.tapes)); - setFolderChan([Root]); - }, []); + const splitIdx = tapeIDStr.indexOf(":"); + if (splitIdx >= 0) { + dir = tapeIDStr.slice(splitIdx + 1); + tapeIDStr = tapeIDStr.slice(0, splitIdx); + } + + const reply = await cli.tapeGetPositions({ id: BigInt(tapeIDStr), directory: dir }).response; + const files = convertPositions(reply.positions); + console.log("refresh jobs list, target= ", target, "tape_id= ", tapeIDStr, "dir= ", dir, "reply= ", reply, "files= ", files); + setFiles(files); + + const targetFolderChain = []; + for (const folder of folderChain) { + if (!folder) { + continue; + } + if (folder.id === target.id) { + targetFolderChain.push(folder); + setFolderChan(targetFolderChain); + return; + } + + targetFolderChain.push(folder); + } + + targetFolderChain.push(target); + setFolderChan(targetFolderChain); + return; + }, + [folderChain], + ); useEffect(() => { - openFolder(Root.id); + openFolder(Root); }, []); const onFileAction = useCallback( (data: ChonkyFileActionData) => { - console.log("source", data); switch (data.id) { case ChonkyActions.OpenFiles.id: (async () => { @@ -59,7 +89,7 @@ const useTapesSourceBrowser = (source: RefObject) => { } if (fileToOpen.isDir) { - await openFolder(fileToOpen.id); + await openFolder(fileToOpen); return; } })(); @@ -67,7 +97,12 @@ const useTapesSourceBrowser = (source: RefObject) => { return; case ChonkyActions.DeleteFiles.id: (async () => { - await cli.tapeDelete({ ids: data.state.selectedFiles.map((file) => BigInt(file.id)) }); + const targetTapes = data.state.selectedFiles; + if (!confirm(`Following tapes will be deleted, may cause data loss. Are you sure?\n${targetTapes.map((tape) => tape.name).join(", ")}`)) { + return; + } + await cli.tapeDelete({ ids: targetTapes.filter((file) => file.isTape).map((file) => BigInt(file.id)) }); + await openFolder(current); })(); return; } diff --git a/frontend/src/tools.ts b/frontend/src/tools.ts index 55d510e..0e5e476 100644 --- a/frontend/src/tools.ts +++ b/frontend/src/tools.ts @@ -22,3 +22,8 @@ export const download = (buf: Uint8Array, filename: string, contentType: string) link.download = filename; link.click(); }; + +export const sleep = (ms: number): Promise => + new Promise((resolve) => { + setTimeout(resolve, ms); + }); diff --git a/go.mod b/go.mod index 10a57ed..f947991 100644 --- a/go.mod +++ b/go.mod @@ -18,7 +18,7 @@ require ( github.com/modern-go/reflect2 v1.0.2 github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 github.com/samber/lo v1.38.1 - github.com/samuelncui/acp v0.0.0-20230927193628-457f88d5268d + github.com/samuelncui/acp v0.0.0-20230929123032-b9f8584ad50c github.com/sirupsen/logrus v1.9.3 google.golang.org/grpc v1.53.0 google.golang.org/protobuf v1.30.0 diff --git a/go.sum b/go.sum index 53ba844..cc855a7 100644 --- a/go.sum +++ b/go.sum @@ -362,6 +362,10 @@ github.com/samuelncui/acp v0.0.0-20230927173814-44b54705fc4b h1:wfi5H9nbag1rnUM5 github.com/samuelncui/acp v0.0.0-20230927173814-44b54705fc4b/go.mod h1:HDBJGNFN6yd3kWuCU5eKaCICvmCwVWb6AzFS+wSKyWQ= github.com/samuelncui/acp v0.0.0-20230927193628-457f88d5268d h1:/xwkO9zlY8TMcG+asORTXWEqKY9tD4wEx4kb3q/7TNY= github.com/samuelncui/acp v0.0.0-20230927193628-457f88d5268d/go.mod h1:HDBJGNFN6yd3kWuCU5eKaCICvmCwVWb6AzFS+wSKyWQ= +github.com/samuelncui/acp v0.0.0-20230928143329-dd07ebc94c58 h1:Mgc3xitaiqsbL6hNEUzic5JCESmEQ3Ll+KdJEwMniGs= +github.com/samuelncui/acp v0.0.0-20230928143329-dd07ebc94c58/go.mod h1:HDBJGNFN6yd3kWuCU5eKaCICvmCwVWb6AzFS+wSKyWQ= +github.com/samuelncui/acp v0.0.0-20230929123032-b9f8584ad50c h1:xJVq1UOaqjI3JVGUQvT+w6584UdEBGzxy7WN8XXuSnk= +github.com/samuelncui/acp v0.0.0-20230929123032-b9f8584ad50c/go.mod h1:HDBJGNFN6yd3kWuCU5eKaCICvmCwVWb6AzFS+wSKyWQ= github.com/samuelncui/godf v0.0.0-20230927093204-37ea5acb9fc1 h1:K2m4b66nzupWlkfUPJKIw2tgz4aDociv5XwtlynwbzI= github.com/samuelncui/godf v0.0.0-20230927093204-37ea5acb9fc1/go.mod h1:lGc26yUHA5Fr2Cm/FzlkwCQJ9VtBUK9cue56biDDnWo= github.com/schollz/progressbar/v3 v3.13.1 h1:o8rySDYiQ59Mwzy2FELeHY5ZARXZTVJC7iHD6PEFUiE= diff --git a/install-release.sh b/install-release.sh index c8f4bfb..4d75b6c 100644 --- a/install-release.sh +++ b/install-release.sh @@ -138,13 +138,13 @@ main() { exit 1 fi - mkdir -p /opt/ltfs mkdir -p /opt/yatm tar -xvzf ${GZIP_FILE} -C /opt/yatm if [[ ! -f '/opt/yatm/config.yaml' ]]; then - cp /opt/yatm/config.example.yaml /opt/yatm/config.yaml - echo "Copy example config to /opt/yatm/config.yaml, you may edit it later" + cp /opt/yatm/config.example.yaml /opt/yatm/config.yaml; + vim /opt/yatm/config.yaml; + echo "Copy example config to /opt/yatm/config.yaml, you may edit it later"; fi systemctl daemon-reload diff --git a/library/library.go b/library/library.go index 539d889..5a2586a 100644 --- a/library/library.go +++ b/library/library.go @@ -5,6 +5,7 @@ import ( "encoding/json" "fmt" + mapset "github.com/deckarep/golang-set/v2" "github.com/modern-go/reflect2" "github.com/samber/lo" "github.com/samuelncui/yatm/entity" @@ -98,6 +99,90 @@ func (l *Library) Import(ctx context.Context, buf []byte) error { return nil } +func (l *Library) Trim(ctx context.Context, position, file bool) error { + if !position { + return nil + } + + var current int64 + for { + positions := make([]*Position, 0, batchSize) + if r := l.db.WithContext(ctx).Where("id > ?", current).Order("id ASC").Limit(batchSize).Find(&positions); r.Error != nil { + return fmt.Errorf("scan position fail, err= %w", r.Error) + } + if len(positions) == 0 { + break + } + current = positions[len(positions)-1].ID + + tapeIDs := mapset.NewThreadUnsafeSetWithSize[int64](1) + for _, posi := range positions { + tapeIDs.Add(posi.TapeID) + } + + tapes, err := l.MGetTape(ctx, tapeIDs.ToSlice()...) + if err != nil { + return fmt.Errorf("mget tape fail, %w", err) + } + + needDelete := make([]int64, 0) + for _, posi := range positions { + if tape, has := tapes[posi.TapeID]; has && tape != nil { + continue + } + + needDelete = append(needDelete, posi.ID) + } + if len(needDelete) == 0 { + continue + } + + if err := l.DeletePositions(ctx, needDelete...); err != nil { + return fmt.Errorf("delete position fail, %w", err) + } + } + + if !file { + return nil + } + + current = 0 + for { + files := make([]*File, 0, batchSize) + if r := l.db.WithContext(ctx).Where("id > ?", current).Order("id ASC").Limit(batchSize).Find(&files); r.Error != nil { + return fmt.Errorf("scan file fail, err= %w", r.Error) + } + if len(files) == 0 { + break + } + current = files[len(files)-1].ID + + fileIDs := lo.Map(files, func(f *File, _ int) int64 { return f.ID }) + positions, err := l.MGetPositionByFileID(ctx, fileIDs...) + if err != nil { + return fmt.Errorf("mget position by file id fail, %w", err) + } + + needDelete := make([]int64, 0) + for _, file := range files { + if posis, has := positions[file.ID]; has && len(posis) > 0 { + continue + } + + needDelete = append(needDelete, file.ID) + } + if len(needDelete) == 0 { + continue + } + + if r := l.db.WithContext(ctx).Where("id IN (?)", needDelete).Delete(ModelFile); r.Error != nil { + return fmt.Errorf("delete files fail, err= %w", r.Error) + } + } + + return nil +} + func listAll[T any](ctx context.Context, l *Library, items []T) ([]T, error) { v := new(T) id := reflect2.TypeOfPtr(*v).Elem().(reflect2.StructType).FieldByName("ID") diff --git a/library/position.go b/library/position.go index 14acfb9..96aea2d 100644 --- a/library/position.go +++ b/library/position.go @@ -3,7 +3,13 @@ package library import ( "context" "fmt" + "io/fs" + "sort" + "strings" "time" + + "github.com/samuelncui/yatm/resource" + "github.com/samuelncui/yatm/tools" ) var ( @@ -23,6 +29,10 @@ type Position struct { Hash []byte `gorm:"type:varbinary(32)" json:"hash,omitempty"` // sha256 } +func (l *Library) SavePosition(ctx context.Context, posi *Position) error { + return l.db.WithContext(ctx).Save(posi).Error +} + func (l *Library) GetPositionByFileID(ctx context.Context, fileID int64) ([]*Position, error) { results, err := l.MGetPositionByFileID(ctx, fileID) if err != nil { @@ -48,3 +58,63 @@ func (l *Library) MGetPositionByFileID(ctx context.Context, fileIDs ...int64) (m return results, nil } + +func (l *Library) ListPositions(ctx context.Context, tapeID int64, prefix string) ([]*Position, error) { + positions := make([]*Position, 0, 128) + if r := l.db.WithContext(ctx).Where("tape_id = ? AND path LIKE ?", tapeID, resource.SQLEscape(prefix)+"%").Order("path ASC").Find(&positions); r.Error != nil { + return nil, fmt.Errorf("find position by file id fail, %w", r.Error) + } + + convertPath := tools.Cache(func(p string) string { return strings.ReplaceAll(p, "/", "\x00") }) + sort.Slice(positions, func(i int, j int) bool { + return convertPath(positions[i].Path) < convertPath(positions[j].Path) + }) + + filtered := make([]*Position, 0, 128) + for _, posi := range positions { + if !strings.HasPrefix(posi.Path, prefix) { + continue + } + + suffix := posi.Path[len(prefix):] + idx := strings.IndexRune(suffix, '/') + if idx < 0 { + filtered = append(filtered, posi) + continue + } + + path := prefix + suffix[:idx+1] + if len(filtered) > 0 && filtered[len(filtered)-1].Path == path { + target := filtered[len(filtered)-1] + target.Size += posi.Size + + if target.ModTime.Before(posi.ModTime) { + target.ModTime = posi.ModTime + } + if target.WriteTime.Before(posi.WriteTime) { + target.WriteTime = posi.WriteTime + } + + continue + } + + filtered = append(filtered, &Position{ + TapeID: posi.TapeID, + Path: path, + Mode: uint32(fs.ModeDir | fs.ModePerm), + ModTime: posi.ModTime, + WriteTime: posi.WriteTime, + Size: posi.Size, + }) + } + + return filtered, nil +} + +func (l *Library) DeletePositions(ctx context.Context, ids ...int64) error { + if r := l.db.WithContext(ctx).Where("id IN (?)", ids).Delete(ModelPosition); r.Error != nil { + return fmt.Errorf("delete positions fail, err= %w", r.Error) + } + + return nil +} diff --git a/resource/db.go b/resource/db.go index 972b97a..5912fb9 100644 --- a/resource/db.go +++ b/resource/db.go @@ -17,3 +17,44 @@ func NewDBConn(dialect, dsn string) (*gorm.DB, error) { return gorm.Open(dialector) } + +func SQLEscape(sql string) string { + dest := make([]byte, 0, 2*len(sql)) + var escape byte + for i := 0; i < len(sql); i++ { + c := sql[i] + + escape = 0 + + switch c { + case 0: /* Must be escaped for 'mysql' */ + escape = '0' + break + case '\n': /* Must be escaped for logs */ + escape = 'n' + break + case '\r': + escape = 'r' + break + case '\\': + escape = '\\' + break + case '\'': + escape = '\'' + break + case '"': /* Better safe than sorry */ + escape = '"' + break + case '\032': //十进制26,八进制32,十六进制1a, /* This gives problems on Win32 */ + escape = 'Z' + } + + if escape != 0 { + dest = append(dest, '\\', escape) + } else { + dest = append(dest, c) + } + } + + return string(dest) +} diff --git a/scripts/encrypt b/scripts/encrypt index 6fe447d..7dcffb5 100755 --- a/scripts/encrypt +++ b/scripts/encrypt @@ -1,6 +1,7 @@ #!/usr/bin/env bash set -ex; +mt -f ${DEVICE} load sleep 5 for i in {1..60}; do diff --git a/scripts/get_device b/scripts/get_device new file mode 100755 index 0000000..3b2d912 --- /dev/null +++ b/scripts/get_device @@ -0,0 +1,24 @@ +#!/usr/bin/env bash +set -e; + +DEVICE=`readlink -f ${DEVICE}` +REGEXP='/dev/n?st([0-9]+)[alm]?' + +if [[ ! $DEVICE =~ $REGEXP ]]; then + echo "'$DEVICE' doesn't match" >&2 + exit 1 +fi + +NUM="${BASH_REMATCH[1]}" +TRIES=("/dev/nst${NUM}" "/dev/st${NUM}") +for TRY in ${TRIES[@]}; do + SG_DEVICE=`sg_map | grep ${TRY} || echo ''`; + + if [[ $SG_DEVICE != "" ]]; then + echo $SG_DEVICE | awk '{print $1}' + exit 0; + fi +done + +echo "'$DEVICE' not found" >&2 +exit 1 diff --git a/scripts/mkfs b/scripts/mkfs index 9718783..ff23351 100755 --- a/scripts/mkfs +++ b/scripts/mkfs @@ -1,6 +1,8 @@ #!/usr/bin/env bash set -ex; -SG_DEVICE=`sg_map | grep ${DEVICE} | awk '{print $1}'` +CURDIR=$(cd $(dirname $0); pwd); +SG_DEVICE=`${CURDIR}/get_device` + mkltfs -f -d ${SG_DEVICE} -s ${TAPE_BARCODE} -n ${TAPE_NAME} sleep 3 diff --git a/scripts/mount b/scripts/mount index c9cf27a..164e82e 100755 --- a/scripts/mount +++ b/scripts/mount @@ -1,6 +1,16 @@ #!/usr/bin/env bash set -ex; -SG_DEVICE=`sg_map | grep ${DEVICE} | awk '{print $1}'` -ltfs -o devname=${SG_DEVICE} -o noatime -o sync_type=unmount -o work_directory=/opt/ltfs -o capture_index -o min_pool_size=256 -o max_pool_size=1024 -o eject -s ${MOUNT_POINT} +CURDIR=$(cd $(dirname $0); pwd); +SG_DEVICE=`${CURDIR}/get_device` + +ltfs -o devname=${SG_DEVICE} -o noatime -o sync_type=unmount -o work_directory=/opt/yatm/captured_indices -o capture_index -o min_pool_size=256 -o max_pool_size=1024 -o eject -s ${MOUNT_POINT} sleep 3 + +MOUNT_POINT_TARGET=`df ${MOUNT_POINT} --output=target | sed -n '1!p'` +if [[ $MOUNT_POINT != $MOUNT_POINT_TARGET ]]; then + echo "mount '$MOUNT_POINT' fail, current target is '$MOUNT_POINT_TARGET'" >&2 + exit 1 +fi + +echo "mount '$MOUNT_POINT' success" >&2 diff --git a/scripts/mount.openltfs b/scripts/mount.openltfs new file mode 100755 index 0000000..965b7a2 --- /dev/null +++ b/scripts/mount.openltfs @@ -0,0 +1,16 @@ +#!/usr/bin/env bash +set -ex; + +CURDIR=$(cd $(dirname $0); pwd); +SG_DEVICE=`${CURDIR}/get_device` + +ltfs -o devname=${SG_DEVICE} -o noatime -o sync_type=unmount -o work_directory=/opt/yatm/captured_indices -o capture_index=/opt/yatm/captured_indices -o min_pool_size=256 -o max_pool_size=1024 -o eject -s ${MOUNT_POINT} +sleep 3 + +MOUNT_POINT_TARGET=`df ${MOUNT_POINT} --output=target | sed -n '1!p'` +if [[ $MOUNT_POINT != $MOUNT_POINT_TARGET ]]; then + echo "mount '$MOUNT_POINT' fail, current target is '$MOUNT_POINT_TARGET'" >&2 + exit 1 +fi + +echo "mount '$MOUNT_POINT' success" >&2 diff --git a/scripts/readinfo b/scripts/readinfo index 68bcaa4..0d745f9 100755 --- a/scripts/readinfo +++ b/scripts/readinfo @@ -1,7 +1,7 @@ #!/usr/bin/env bash set -ex; -# SG_DEVICE=`sg_map | grep ${DEVICE} | awk '{print $1}'` -BARCODE=`./yatm-lto-info -f /dev/nst0 | grep 'Barcode' | awk '{print $3}'` +mt -f ${DEVICE} load +BARCODE=`./yatm-lto-info -f ${DEVICE} | grep 'Barcode' | awk '{print $3}'` echo "{\"barcode\": \"$BARCODE\"}" > $OUT sleep 3