This commit is contained in:
Gareth
2023-12-10 06:32:35 -08:00
77 changed files with 1007 additions and 845 deletions
+3 -3
View File
@@ -1,4 +1,4 @@
resticui
resticui-*
restora
restora-*
dist
resticui.exe
restora.exe
+3 -3
View File
@@ -43,8 +43,8 @@ archives:
dockers:
- image_templates:
- garethgeorge/resticweb:latest
- garethgeorge/resticweb:{{ .Tag }}
- garethgeorge/restora:latest
- garethgeorge/restora:{{ .Tag }}
changelog:
sort: asc
@@ -56,4 +56,4 @@ changelog:
release:
github:
owner: garethgeorge
name: resticweb
name: restora
+86 -67
View File
@@ -1,91 +1,110 @@
# Changelog
## [0.4.0](https://github.com/garethgeorge/resticweb/compare/v0.3.0...v0.4.0) (2023-12-04)
## [0.5.0](https://github.com/garethgeorge/restora/compare/v0.4.0...v0.5.0) (2023-12-10)
### Features
* implement prune support ([#25](https://github.com/garethgeorge/resticweb/issues/25)) ([a311b0a](https://github.com/garethgeorge/resticweb/commit/a311b0a3fb5315f17d66361a3e72fa10b8a744a1))
* implement restore operation through snapshot browser UI ([#27](https://github.com/garethgeorge/resticweb/issues/27)) ([d758509](https://github.com/garethgeorge/resticweb/commit/d758509797e21e3ec4bc67eff4d974604e4a5476))
## [0.3.0](https://github.com/garethgeorge/resticweb/compare/v0.2.0...v0.3.0) (2023-12-03)
### Features
* autoinstall required restic version ([b385c01](https://github.com/garethgeorge/resticweb/commit/b385c011210087e6d6992a4e4b279fec4b22ab89))
* basic forget support in backend and UI ([d22d9d1](https://github.com/garethgeorge/resticweb/commit/d22d9d1a05831fae94ce397c0c73c6292d378cf5))
* begin UI integration with backend ([cccdd29](https://github.com/garethgeorge/resticweb/commit/cccdd297c15cd47268b2a1903e9624bdbca3dc68))
* display queued operations ([0c818bb](https://github.com/garethgeorge/resticweb/commit/0c818bb9452a944d8b1127e553142e1e60ed90af))
* forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/resticweb/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e))
* forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/resticweb/commit/38bc107db394716e34245f1edefc5e4cf4a15333))
* implement add plan UI ([9288589](https://github.com/garethgeorge/resticweb/commit/92885898cf551a2dcb4bb315f130138cd7a8cc67))
* implement backup scheduling in orchestrator ([eadb1a8](https://github.com/garethgeorge/resticweb/commit/eadb1a82019f0cfc82edf8559adbad7730a4e86a))
* implement basic plan view ([4c6f042](https://github.com/garethgeorge/resticweb/commit/4c6f042250946a036e46225e669ee39e2433b198))
* implement delete button for plan and repo UIs ([ffb0d85](https://github.com/garethgeorge/resticweb/commit/ffb0d859f19f4af66a7521768dab083995f9672a))
* implement forget and prune support in restic pkg ([ffb4573](https://github.com/garethgeorge/resticweb/commit/ffb4573737a73cc32f325bc0b9c3feed764b7879))
* implement forget operation ([ebccf3b](https://github.com/garethgeorge/resticweb/commit/ebccf3bc3b78083aee635de7c6ae23b52ee88284))
* implement repo, edit, and supporting RPCs ([d282c32](https://github.com/garethgeorge/resticweb/commit/d282c32c8bd3d8f5747e934d4af6a84faca1ec86))
* implement snapshot browsing ([8ffffa0](https://github.com/garethgeorge/resticweb/commit/8ffffa05e41ca31e2d38fde5427dae34ac4a1abb))
* implement snapshot indexing ([a90b30e](https://github.com/garethgeorge/resticweb/commit/a90b30e19f7107874bbfe244451b07f72c437213))
* improve oplist performance and display forget operations in oplist ([#22](https://github.com/garethgeorge/resticweb/issues/22)) ([51b4921](https://github.com/garethgeorge/resticweb/commit/51b49214e3d32cc4b28e13085bd196ba164a8c19))
* initial oplog implementation ([dd9142c](https://github.com/garethgeorge/resticweb/commit/dd9142c0e97e1175ff12f2861220af0e0d68b7d9))
* initial optree implementation ([ba390a2](https://github.com/garethgeorge/resticweb/commit/ba390a2ca1b5e9adaab36a7db0d988f54f5a6cdd))
* operations IDs are ordered by operation timestamp ([a1ed6f9](https://github.com/garethgeorge/resticweb/commit/a1ed6f90ba1d608e00c53221db45b67251085aa7))
* present list of operations on plan view ([6491dbe](https://github.com/garethgeorge/resticweb/commit/6491dbed146967c0e12eee4392d1d12843dc7c5e))
* repo can be created through UI ([9ccade5](https://github.com/garethgeorge/resticweb/commit/9ccade5ccd97f4e485d52ad5c675be6b0a4a1049))
* scaffolding basic UI structure ([1273f81](https://github.com/garethgeorge/resticweb/commit/1273f8105a2549b0ccd0c7a588eb60646b66366e))
* show snapshots in sidenav ([1a9a5b6](https://github.com/garethgeorge/resticweb/commit/1a9a5b60d24dd75752e5a3f84dd87af3e38422bb))
* snapshot items are viewable in the UI and minor element ordering fixes ([a333001](https://github.com/garethgeorge/resticweb/commit/a33300175c645f31b95b3038de02821a1f3d5559))
* support ImportSnapshotOperation in oplog ([89f95b3](https://github.com/garethgeorge/resticweb/commit/89f95b351fe250534cd39ac27ff34b2b148256e1))
* update getting started guide ([2c421d6](https://github.com/garethgeorge/resticweb/commit/2c421d661501fa4a3120aa3f39937cd58b29c2dc))
* implement repo unlocking and operation list implementation ([6665ad9](https://github.com/garethgeorge/restora/commit/6665ad98d7f54bea30ea532932a8a3409717c913))
* initial Windows OS support ([f048cbf](https://github.com/garethgeorge/restora/commit/f048cbf10dc60da51cd7f5aee4614a8750fd85b2))
* match system color theme (darkmode support) ([a8762dc](https://github.com/garethgeorge/restora/commit/a8762dca329927b93db40b01cc011c00e12891f0))
### Bug Fixes
* build and test fixes ([4957496](https://github.com/garethgeorge/resticweb/commit/49574967871494dcb5095e5699610097466f57f9))
* connectivity issues with embedded server ([482cc8e](https://github.com/garethgeorge/resticweb/commit/482cc8ebbc93b919991f6566b212247c5874f70f))
* deadlock in snapshots ([93b2120](https://github.com/garethgeorge/resticweb/commit/93b2120f74ea348e5084ab430573368bf4066eec))
* forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/resticweb/commit/b7c633d021d68d4880a5f442ce70a858002b4af2))
* improve error message formatting ([ae33b01](https://github.com/garethgeorge/resticweb/commit/ae33b01de408af3b1d711a369298a2782a24ad1e))
* improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/resticweb/issues/21)) ([b513b08](https://github.com/garethgeorge/resticweb/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e))
* improve UI performance ([8488d46](https://github.com/garethgeorge/resticweb/commit/8488d461bd7ffec2e8171d67f83093c32c79073f))
* repo orchestrator tests ([d077fc8](https://github.com/garethgeorge/resticweb/commit/d077fc83c97b7fbdbeda9702828c8780182b2616))
* restic fails to detect summary event for very short backups ([46b2a85](https://github.com/garethgeorge/resticweb/commit/46b2a8567706ddb21cfcf3e18b57e16d50809b56))
* standardize on fully qualified snapshot_id and decouple protobufs from restic package ([e6031bf](https://github.com/garethgeorge/resticweb/commit/e6031bfa543a7300e622c1b0f56efc6320e7611e))
* support more versions of restic ([0cdfd11](https://github.com/garethgeorge/resticweb/commit/0cdfd115e29a0b08d5814e71c0f4a8f2baf52e90))
* task priority not taking effect ([af7462c](https://github.com/garethgeorge/resticweb/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49))
* time formatting in operation list ([53c7f12](https://github.com/garethgeorge/resticweb/commit/53c7f1248f5284080fff872ac79b3996474412b3))
* UI layout adjustments ([7d1b95c](https://github.com/garethgeorge/resticweb/commit/7d1b95c81f0f69840ce1d20cb0d4a4bb90011dc9))
* improve output detail collection for command failures ([c492f9b](https://github.com/garethgeorge/restora/commit/c492f9ba63169942509349797ebe951879b53635))
* improve Windows path handling ([426aad4](https://github.com/garethgeorge/restora/commit/426aad4890d2de5d70cd2e0232c0d11c42606c92))
* ordering of operations when viewed from backup tree ([063f086](https://github.com/garethgeorge/restora/commit/063f086a6e31df250dd9be42cdb5fa549307106f))
* relax output parsing to skip over warnings ([8f85b74](https://github.com/garethgeorge/restora/commit/8f85b747f57844bbc898668723eec50a1666aa39))
* snapshots out of order in UI ([b9bcc7e](https://github.com/garethgeorge/restora/commit/b9bcc7e7c758abafa4878b6ef895adf2d2d0bc42))
* unexpected config location on MacOS ([8d40576](https://github.com/garethgeorge/restora/commit/8d40576c6526d6f180c96fbeb81d7f59f56b51b8))
## [0.2.0](https://github.com/garethgeorge/resticweb/compare/v0.1.3...v0.2.0) (2023-12-03)
## [0.4.0](https://github.com/garethgeorge/restora/compare/v0.3.0...v0.4.0) (2023-12-04)
### Features
* forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/resticweb/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e))
* forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/resticweb/commit/38bc107db394716e34245f1edefc5e4cf4a15333))
* improve oplist performance and display forget operations in oplist ([#22](https://github.com/garethgeorge/resticweb/issues/22)) ([51b4921](https://github.com/garethgeorge/resticweb/commit/51b49214e3d32cc4b28e13085bd196ba164a8c19))
* implement prune support ([#25](https://github.com/garethgeorge/restora/issues/25)) ([a311b0a](https://github.com/garethgeorge/restora/commit/a311b0a3fb5315f17d66361a3e72fa10b8a744a1))
* implement restore operation through snapshot browser UI ([#27](https://github.com/garethgeorge/restora/issues/27)) ([d758509](https://github.com/garethgeorge/restora/commit/d758509797e21e3ec4bc67eff4d974604e4a5476))
### Bug Fixes
* forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/resticweb/commit/b7c633d021d68d4880a5f442ce70a858002b4af2))
* improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/resticweb/issues/21)) ([b513b08](https://github.com/garethgeorge/resticweb/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e))
* task priority not taking effect ([af7462c](https://github.com/garethgeorge/resticweb/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49))
* UI layout adjustments ([7d1b95c](https://github.com/garethgeorge/resticweb/commit/7d1b95c81f0f69840ce1d20cb0d4a4bb90011dc9))
## [0.2.0](https://github.com/garethgeorge/resticweb/compare/v0.1.3...v0.2.0) (2023-12-02)
## [0.3.0](https://github.com/garethgeorge/restora/compare/v0.2.0...v0.3.0) (2023-12-03)
### Features
* forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/resticweb/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e))
* forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/resticweb/commit/38bc107db394716e34245f1edefc5e4cf4a15333))
* autoinstall required restic version ([b385c01](https://github.com/garethgeorge/restora/commit/b385c011210087e6d6992a4e4b279fec4b22ab89))
* basic forget support in backend and UI ([d22d9d1](https://github.com/garethgeorge/restora/commit/d22d9d1a05831fae94ce397c0c73c6292d378cf5))
* begin UI integration with backend ([cccdd29](https://github.com/garethgeorge/restora/commit/cccdd297c15cd47268b2a1903e9624bdbca3dc68))
* display queued operations ([0c818bb](https://github.com/garethgeorge/restora/commit/0c818bb9452a944d8b1127e553142e1e60ed90af))
* forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/restora/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e))
* forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/restora/commit/38bc107db394716e34245f1edefc5e4cf4a15333))
* implement add plan UI ([9288589](https://github.com/garethgeorge/restora/commit/92885898cf551a2dcb4bb315f130138cd7a8cc67))
* implement backup scheduling in orchestrator ([eadb1a8](https://github.com/garethgeorge/restora/commit/eadb1a82019f0cfc82edf8559adbad7730a4e86a))
* implement basic plan view ([4c6f042](https://github.com/garethgeorge/restora/commit/4c6f042250946a036e46225e669ee39e2433b198))
* implement delete button for plan and repo UIs ([ffb0d85](https://github.com/garethgeorge/restora/commit/ffb0d859f19f4af66a7521768dab083995f9672a))
* implement forget and prune support in restic pkg ([ffb4573](https://github.com/garethgeorge/restora/commit/ffb4573737a73cc32f325bc0b9c3feed764b7879))
* implement forget operation ([ebccf3b](https://github.com/garethgeorge/restora/commit/ebccf3bc3b78083aee635de7c6ae23b52ee88284))
* implement repo, edit, and supporting RPCs ([d282c32](https://github.com/garethgeorge/restora/commit/d282c32c8bd3d8f5747e934d4af6a84faca1ec86))
* implement snapshot browsing ([8ffffa0](https://github.com/garethgeorge/restora/commit/8ffffa05e41ca31e2d38fde5427dae34ac4a1abb))
* implement snapshot indexing ([a90b30e](https://github.com/garethgeorge/restora/commit/a90b30e19f7107874bbfe244451b07f72c437213))
* improve oplist performance and display forget operations in oplist ([#22](https://github.com/garethgeorge/restora/issues/22)) ([51b4921](https://github.com/garethgeorge/restora/commit/51b49214e3d32cc4b28e13085bd196ba164a8c19))
* initial oplog implementation ([dd9142c](https://github.com/garethgeorge/restora/commit/dd9142c0e97e1175ff12f2861220af0e0d68b7d9))
* initial optree implementation ([ba390a2](https://github.com/garethgeorge/restora/commit/ba390a2ca1b5e9adaab36a7db0d988f54f5a6cdd))
* operations IDs are ordered by operation timestamp ([a1ed6f9](https://github.com/garethgeorge/restora/commit/a1ed6f90ba1d608e00c53221db45b67251085aa7))
* present list of operations on plan view ([6491dbe](https://github.com/garethgeorge/restora/commit/6491dbed146967c0e12eee4392d1d12843dc7c5e))
* repo can be created through UI ([9ccade5](https://github.com/garethgeorge/restora/commit/9ccade5ccd97f4e485d52ad5c675be6b0a4a1049))
* scaffolding basic UI structure ([1273f81](https://github.com/garethgeorge/restora/commit/1273f8105a2549b0ccd0c7a588eb60646b66366e))
* show snapshots in sidenav ([1a9a5b6](https://github.com/garethgeorge/restora/commit/1a9a5b60d24dd75752e5a3f84dd87af3e38422bb))
* snapshot items are viewable in the UI and minor element ordering fixes ([a333001](https://github.com/garethgeorge/restora/commit/a33300175c645f31b95b3038de02821a1f3d5559))
* support ImportSnapshotOperation in oplog ([89f95b3](https://github.com/garethgeorge/restora/commit/89f95b351fe250534cd39ac27ff34b2b148256e1))
* update getting started guide ([2c421d6](https://github.com/garethgeorge/restora/commit/2c421d661501fa4a3120aa3f39937cd58b29c2dc))
### Bug Fixes
* forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/resticweb/commit/b7c633d021d68d4880a5f442ce70a858002b4af2))
* improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/resticweb/issues/21)) ([b513b08](https://github.com/garethgeorge/resticweb/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e))
* task priority not taking effect ([af7462c](https://github.com/garethgeorge/resticweb/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49))
* build and test fixes ([4957496](https://github.com/garethgeorge/restora/commit/49574967871494dcb5095e5699610097466f57f9))
* connectivity issues with embedded server ([482cc8e](https://github.com/garethgeorge/restora/commit/482cc8ebbc93b919991f6566b212247c5874f70f))
* deadlock in snapshots ([93b2120](https://github.com/garethgeorge/restora/commit/93b2120f74ea348e5084ab430573368bf4066eec))
* forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/restora/commit/b7c633d021d68d4880a5f442ce70a858002b4af2))
* improve error message formatting ([ae33b01](https://github.com/garethgeorge/restora/commit/ae33b01de408af3b1d711a369298a2782a24ad1e))
* improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/restora/issues/21)) ([b513b08](https://github.com/garethgeorge/restora/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e))
* improve UI performance ([8488d46](https://github.com/garethgeorge/restora/commit/8488d461bd7ffec2e8171d67f83093c32c79073f))
* repo orchestrator tests ([d077fc8](https://github.com/garethgeorge/restora/commit/d077fc83c97b7fbdbeda9702828c8780182b2616))
* restic fails to detect summary event for very short backups ([46b2a85](https://github.com/garethgeorge/restora/commit/46b2a8567706ddb21cfcf3e18b57e16d50809b56))
* standardize on fully qualified snapshot_id and decouple protobufs from restic package ([e6031bf](https://github.com/garethgeorge/restora/commit/e6031bfa543a7300e622c1b0f56efc6320e7611e))
* support more versions of restic ([0cdfd11](https://github.com/garethgeorge/restora/commit/0cdfd115e29a0b08d5814e71c0f4a8f2baf52e90))
* task priority not taking effect ([af7462c](https://github.com/garethgeorge/restora/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49))
* time formatting in operation list ([53c7f12](https://github.com/garethgeorge/restora/commit/53c7f1248f5284080fff872ac79b3996474412b3))
* UI layout adjustments ([7d1b95c](https://github.com/garethgeorge/restora/commit/7d1b95c81f0f69840ce1d20cb0d4a4bb90011dc9))
## [0.2.0](https://github.com/garethgeorge/restora/compare/v0.1.3...v0.2.0) (2023-12-03)
### Features
* forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/restora/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e))
* forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/restora/commit/38bc107db394716e34245f1edefc5e4cf4a15333))
* improve oplist performance and display forget operations in oplist ([#22](https://github.com/garethgeorge/restora/issues/22)) ([51b4921](https://github.com/garethgeorge/restora/commit/51b49214e3d32cc4b28e13085bd196ba164a8c19))
### Bug Fixes
* forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/restora/commit/b7c633d021d68d4880a5f442ce70a858002b4af2))
* improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/restora/issues/21)) ([b513b08](https://github.com/garethgeorge/restora/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e))
* task priority not taking effect ([af7462c](https://github.com/garethgeorge/restora/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49))
* UI layout adjustments ([7d1b95c](https://github.com/garethgeorge/restora/commit/7d1b95c81f0f69840ce1d20cb0d4a4bb90011dc9))
## [0.2.0](https://github.com/garethgeorge/restora/compare/v0.1.3...v0.2.0) (2023-12-02)
### Features
* forget soft-deletes operations associated with removed snapshots ([f3dc7ff](https://github.com/garethgeorge/restora/commit/f3dc7ffd077fef67870852f8f4e8b9aa6c94806e))
* forget soft-deletes operations associated with removed snapshots ([38bc107](https://github.com/garethgeorge/restora/commit/38bc107db394716e34245f1edefc5e4cf4a15333))
### Bug Fixes
* forget deadlocking and misc smaller bugs ([b7c633d](https://github.com/garethgeorge/restora/commit/b7c633d021d68d4880a5f442ce70a858002b4af2))
* improve operation ordering to fix snapshots indexed before forget operation ([#21](https://github.com/garethgeorge/restora/issues/21)) ([b513b08](https://github.com/garethgeorge/restora/commit/b513b08e51434c28c90f5f062b4ae292f6854f4e))
* task priority not taking effect ([af7462c](https://github.com/garethgeorge/restora/commit/af7462cefb130153cdaaa08e8ebefefa40e80e49))
+31
View File
@@ -0,0 +1,31 @@
# Contributing
## Commits
This repo uses [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/).
## Dev Depedencies
**Build Dependencies**
* Node.JS for UI development
* Go 1.21 or greater for server development
* go.rice `go install github.com/GeertJohan/go.rice@latest` and `go install github.com/GeertJohan/go.rice/rice@latest`
**To Edit Protobuffers**
```sh
apt install -y protobuf-compiler
go install \
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest \
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest
go install github.com/grpc-ecosystem/protoc-gen-grpc-gateway-ts@latest
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
go install github.com/bufbuild/buf/cmd/buf@v1.27.2
```
## Building
```sh
(cd webui && npm i && npm run build)
(cd cmd/restora && go build .)
```
+5 -5
View File
@@ -1,12 +1,12 @@
FROM golang:alpine as gobuild
RUN mkdir /tmp-orig
COPY resticweb /resticweb
RUN /resticweb --install-deps=true
COPY restora /restora
RUN /restora --install-deps=true
FROM scratch
COPY --from=gobuild /root/.local/share/resticui/ /.local/share/resticui/
COPY --from=gobuild /root/.local/share/restora/ /.local/share/restora/
COPY --from=gobuild /tmp-orig /tmp
COPY --from=gobuild /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
ENTRYPOINT ["/resticweb"]
COPY resticweb /resticweb
ENTRYPOINT ["/restora"]
COPY restora /restora
+119 -59
View File
@@ -1,78 +1,109 @@
# ResticUI
# Restora
[![Build and Test](https://github.com/garethgeorge/resticui/actions/workflows/build-and-test.yml/badge.svg)](https://github.com/garethgeorge/resticui/actions/workflows/build-and-test.yml)
[![Build and Test](https://github.com/garethgeorge/restora/actions/workflows/build-and-test.yml/badge.svg)](https://github.com/garethgeorge/restora/actions/workflows/build-and-test.yml)
ResticUI is a WebUI wrapper for [restic](https://restic.net/). It is intended to be used as a self-hosted application for managing backups of your data.
Restora is a free and open-source web UI wrapper for [restic](https://restic.net/).
The goals of this project are:
**Project goals:**
* Full featured web UI for restic: supports all basic operations (e.g. backup, restore, browse snapshots, prune old data, etc).
* Interactive: UI is fast and responds to operation progress in real time (e.g. backups show live progress bars).
* Safe: all backups leverage simple [restic](https://restic.net/) features and have test coverage.
* Easy to pull back the curtain: all common operations should be possible from the UI, but it should be easy to drop down to the command line and use restic directly if needed.
* Lightweight: your backup orchestration should blend into the background. The web UI binary is fully self contained as a single executable and the binary is <20 MB with very light memory overhead at runtime.
* Lightweight: your backup orchestration should blend into the background. The web UI binary is fully self contained as a single executable and the binary is ~25 MB with very light memory overhead at runtime.
* Runs everywhere: Restora should be able to run on any platform that restic supports and that you need backed up. Restora is originally conceived of as a self-hosted backup tool for NAS devices but runs just as well on an interactive Desktop or Laptop.
OS Support
**Platform Support**
* Linux
* Linux
* Docker
* MacOS (Darwin)
* Windows (note: must be run as administrator on first execution to install the restic binary in Program Files).
* (experimental) Windows
**Features**
* Scheduled (and one off) backup operations
* Scheduled restic forget and prune operations with configurable retention policy (e.g. keep 1 snapshot per day for 30 days, 1 snapshot per week for 1 year, etc) to manage repo size.
* Backup to local or remote repositories (e.g. S3, Backblaze, etc)
* Graphical backup browser and restore interface
* Real time progress visualization for backup and restore operations.
# Preview
| | |
| -------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------- |
| <img src="https://f000.backblazeb2.com/file/gshare/screenshots/restora-backup-view.png" width="400px"/> | <img src="https://f000.backblazeb2.com/file/gshare/screenshots/restora-add-repo.png" width="400px" /> |
| <img src="https://f000.backblazeb2.com/file/gshare/screenshots/restora-realtime-progress.png" width="400px" /> | <img src="https://f000.backblazeb2.com/file/gshare/screenshots/restora-add-plan.png" width="400px" /> |
# Getting Started
## Running
Restora is packaged as a single executable. It can be run directly on Linux, MacOS, and Windows with no dependencies. [restic](https://github.com/restic/restic) will be downloaded and installed automatically on first run.
Installation options
Download options
* Download and run a release from the [releases page](https://github.com/garethgeorge/resticui/releases).
* Download and run a release from the [releases page](https://github.com/garethgeorge/restora/releases).
* Build from source ([see below](#building)).
* Run with docker: `garethgeorge/resticweb:latest` ([see on dockerhub](https://hub.docker.com/repository/docker/garethgeorge/resticweb/))
* Run with docker: `garethgeorge/restora:latest` ([see on dockerhub](https://hub.docker.com/repository/docker/garethgeorge/restora/))
ResticUI is accessible from a web browser. By default it binds to `0.0.0.0:9898` and can be accessed at `http://localhost:9898`.
Restora is accessible from a web browser. By default it binds to `0.0.0.0:9898` and can be accessed at `http://localhost:9898`.
## Running with Docker Compose
# Configuration
Docker image: https://hub.docker.com/garethgeorge/restora
## Environment Variables
<details>
Example compose file:
* `RESTICUI_PORT` - the port to bind to. Defaults to 9898.
* `RESTICUI_CONFIG_PATH` - the path to the config file. Defaults to `$HOME/.config/resticui/config.json` or if `$XDG_CONFIG_HOME` is set, `$XDG_CONFIG_HOME/resticui/config.json`.
* `RESTICUI_DATA_DIR` - the path to the data directory. Defaults to `$HOME/.local/share/resticui` or if `$XDG_DATA_HOME` is set, `$XDG_DATA_HOME/resticui`.
* `RESTICUI_RESTIC_BIN_PATH` - the path to the restic binary. Defaults managed version of restic which will be downloaded and installed in the data directory.
* `XDG_CACHE_HOME` -- the path to the cache directory. This is propagated to restic.
```yaml
version: "3.2"
services:
restora:
image: garethgeorge/restora
container_name: restora
volumes:
- ./restora/data:/data
- ./restora/config:/config
- ./restora/cache:/cache
- /MY-BACKUP-DATA:/userdata # mount your directories to backup somewhere in the filesystem
environment:
- RESTORA_DATA=/data # path for restora data. restic binary and the database are placed here.
- RESTORA_CONFIG=/config/config.json # path for the restora config file.
- XDG_CACHE_HOME=/cache # path for the restic cache which greatly improves performance.
restart: unless-stopped
```
</details>
## Configuring ResticWeb at startup
ResticWeb is shipped today as a standalone executable, in future releases we'll provide system service installation for common operating systems.
### Linux
## Running on Linux
<details>
#### Cron (Basic)
Download a release from the [releases page](https://github.com/garethgeorge/restora/releases)
Move the resticweb binary to `/usr/local/bin`:
#### Run on startup with cron (Basic)
Move the restora binary to `/usr/local/bin`:
```sh
sudo mv resticui /usr/local/bin/resticui
sudo mv restora /usr/local/bin/restora
```
Add the following line to your crontab (e.g. `crontab -e`):
```sh
@reboot /usr/local/bin/resticui
@reboot /usr/local/bin/restora
```
#### Systemd (Recommended)
#### Run on startup with systemd (Recommended)
Move the resticweb binary to `/usr/local/bin`:
Download a Linux release from the [releases page](https://github.com/garethgeorge/restora/releases). Move the restora binary to `/usr/local/bin`:
```sh
sudo mv resticui /usr/local/bin/resticui
sudo mv restora /usr/local/bin/restora
```
Create a systemd service file at `/etc/systemd/system/resticweb.service` with the following contents:
Create a systemd service file at `/etc/systemd/system/restora.service` with the following contents:
```ini
[Unit]
@@ -83,7 +114,7 @@ After=network.target
Type=simple
User=<your linux user>
Group=<your linux group>
ExecStart=/usr/local/bin/resticweb
ExecStart=/usr/local/bin/restora
[Install]
WantedBy=multi-user.target
@@ -92,38 +123,67 @@ WantedBy=multi-user.target
Then run the following commands to enable and start the service:
```sh
sudo systemctl enable resticweb
sudo systemctl start resticweb
sudo systemctl enable restora
sudo systemctl start restora
```
Note: you can set the linux user and group to your primary user (e.g. `whoami` when logged in).
</details>
# Developer Setup
## Running on MacOS
## Dev Depedencies
<details>
**Build Dependencies**
Download a Darwin release from the [releases page](https://github.com/garethgeorge/restora/releases) and install it to `/usr/local/bin`.
* Node.JS for UI development
* Go 1.21 or greater for server development
* go.rice `go install github.com/GeertJohan/go.rice@latest` and `go install github.com/GeertJohan/go.rice/rice@latest`
At the moment there is no automated way to run Restora on startup on MacOS. You can run it manually or create a launch agent to run it on startup. See [lingon](https://www.peterborgapps.com/lingon/) for a GUI tool to create a launch agent that runs Restora at startup.
**To Edit Protobuffers**
```sh
apt install -y protobuf-compiler
go install \
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-grpc-gateway@latest \
github.com/grpc-ecosystem/grpc-gateway/v2/protoc-gen-openapiv2@latest
go install github.com/grpc-ecosystem/protoc-gen-grpc-gateway-ts@latest
go install google.golang.org/protobuf/cmd/protoc-gen-go@latest
go install google.golang.org/grpc/cmd/protoc-gen-go-grpc@latest
go install github.com/bufbuild/buf/cmd/buf@v1.27.2
```
## Building
</details>
```sh
(cd webui && npm i && npm run build)
(cd cmd/resticui && go build .)
```
## Running on Windows
<details>
Download a Windows release from the [releases page](https://github.com/garethgeorge/restora/releases) and install it to `C:\Program Files\Restora\restora.exe` (create the path if it does not exist).
To run the binary on login, create a shortcut to the binary and place it in the `shell:startup` folder. See [this windows support article](https://support.microsoft.com/en-us/windows/add-an-app-to-run-automatically-at-startup-in-windows-10-150da165-dcd9-7230-517b-cf3c295d89dd) for more details.
warning: Restora is not tested on Windows to the same bar as Linux and MacOS. Please report any issues you encounter. Some folders may not be accessible to Restora or to restic on Windows due to permissions issues.
</details>
# Configuration
## Environment Variables
* `RESTORA_PORT` - the port to bind to. Defaults to 9898.
* `RESTORA_CONFIG` - the path to the config file. Defaults to `$HOME/.config/restora/config.json` or if `$XDG_CONFIG_HOME` is set, `$XDG_CONFIG_HOME/restora/config.json`.
* `RESTORA_DATA` - the path to the data directory. Defaults to `$HOME/.local/share/restora` or if `$XDG_DATA_HOME` is set, `$XDG_DATA_HOME/restora`.
* `RESTORA_RESTIC_COMMAND` - the path to the restic binary. Defaults managed version of restic which will be downloaded and installed in the data directory.
* `XDG_CACHE_HOME` -- the path to the cache directory. This is propagated to restic.
# Usage
## Adding a Repository
A restora repository maps to the concept of a restic repository (and is indeed a restic repo under-the-hood). A repository is a location where restora will store your backups.
To add a repository, click the "Add Repository" button on the side nav. You will be prompted to enter a name for the repository and a path to the repository. The path can be a local path or a remote path (e.g. an S3 bucket). See the [restic docs](https://restic.readthedocs.io/en/stable/030_preparing_a_new_repo.html) for more details on the types of repositories that restic supports. Restora allows you to configure environment variables which should be used to pass additional credentials for remote repositories. For example, if you are using an S3 bucket, you can configure the `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` environment variables to pass your AWS credentials to restic.
## Adding a Plan
A plan is a new concept introduced by restora. A plan is a set of rules for backing up data. A plan can be configured to backup one or more directories to a single repository. Each plan has it's own schedule and retention policy controlling when backups are run and how long backups are kept.
To add a plan, click the "Add Plan" button on the side nav. You will be prompted to enter a name for the plan and select a repository to backup to. You will then be prompted to select one or more directories to backup. A default retention policy is given but you can also pick between time based retention or keeping a configurable number of snapshots.
## Running a Backup
Backups are run automatically based on the scheduled specified in your plan. You may additionally click the "Backup Now" button on the plan page to run a backup immediately. You can additionally trigger an immediate "Prune Now" or "Unlock Now" operation from the plan page, these operations are also run automatically in the course of a backup cycle but can be run manually if needed.
## Best Practices
* Configure a reasonable retention policy for each plan. Restora performs well up to a history of ~1000s of snapshots but too many may eventually slow performance.
* Backup your configuration (e.g. `$RESTORA_CONFIG` or `$HOME/.config/restora/config.json` by default on Linux/MacOS)
* Your configuration contains the encryption keys for your repositories. If you loose this file you will not be able to restore your backups.
* You may alternatively backup your encryption keys individually in which case you will be able to use restic directly to restore your backups.
+3 -3
View File
@@ -123,10 +123,10 @@ var file_types_value_proto_rawDesc = []byte{
0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22,
0x24, 0x0a, 0x0a, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x16, 0x0a,
0x06, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x09, 0x52, 0x06, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x73, 0x42, 0x2f, 0x5a, 0x2d, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x61, 0x6c, 0x75, 0x65, 0x73, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e,
0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72, 0x65, 0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65,
0x2f, 0x72, 0x65, 0x73, 0x74, 0x69, 0x63, 0x75, 0x69, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f,
0x2f, 0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x2f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x67, 0x6f, 0x2f,
0x74, 0x79, 0x70, 0x65, 0x73, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
+5 -5
View File
@@ -495,11 +495,11 @@ var file_v1_config_proto_rawDesc = []byte{
0x05, 0x52, 0x10, 0x6d, 0x61, 0x78, 0x55, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x50, 0x65, 0x72, 0x63,
0x65, 0x6e, 0x74, 0x12, 0x28, 0x0a, 0x10, 0x6d, 0x61, 0x78, 0x5f, 0x75, 0x6e, 0x75, 0x73, 0x65,
0x64, 0x5f, 0x62, 0x79, 0x74, 0x65, 0x73, 0x18, 0x65, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0e, 0x6d,
0x61, 0x78, 0x55, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x42, 0x2e, 0x5a,
0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72, 0x65,
0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x69, 0x63, 0x75,
0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x33,
0x61, 0x78, 0x55, 0x6e, 0x75, 0x73, 0x65, 0x64, 0x42, 0x79, 0x74, 0x65, 0x73, 0x42, 0x2d, 0x5a,
0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72, 0x65,
0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x61,
0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
}
var (
+4 -4
View File
@@ -475,7 +475,7 @@ func (x *OperationBackup) GetLastStatus() *BackupProgressEntry {
return nil
}
// OperationIndexSnapshot tracks that a snapshot was detected by resticui.
// OperationIndexSnapshot tracks that a snapshot was detected by restora.
type OperationIndexSnapshot struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -809,10 +809,10 @@ var file_v1_operations_proto_rawDesc = []byte{
0x54, 0x41, 0x54, 0x55, 0x53, 0x5f, 0x53, 0x59, 0x53, 0x54, 0x45, 0x4d, 0x5f, 0x43, 0x41, 0x4e,
0x43, 0x45, 0x4c, 0x4c, 0x45, 0x44, 0x10, 0x05, 0x12, 0x19, 0x0a, 0x15, 0x53, 0x54, 0x41, 0x54,
0x55, 0x53, 0x5f, 0x55, 0x53, 0x45, 0x52, 0x5f, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x4c, 0x45,
0x44, 0x10, 0x06, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
0x44, 0x10, 0x06, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f,
0x6d, 0x2f, 0x67, 0x61, 0x72, 0x65, 0x74, 0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x72,
0x65, 0x73, 0x74, 0x69, 0x63, 0x75, 0x69, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f,
0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x65, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f,
0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
+3 -3
View File
@@ -676,10 +676,10 @@ var file_v1_restic_proto_rawDesc = []byte{
0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x66, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73,
0x74, 0x6f, 0x72, 0x65, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x70, 0x65, 0x72, 0x63, 0x65, 0x6e, 0x74,
0x5f, 0x64, 0x6f, 0x6e, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x01, 0x52, 0x0b, 0x70, 0x65, 0x72,
0x63, 0x65, 0x6e, 0x74, 0x44, 0x6f, 0x6e, 0x65, 0x42, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68,
0x63, 0x65, 0x6e, 0x74, 0x44, 0x6f, 0x6e, 0x65, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68,
0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72, 0x65, 0x74, 0x68, 0x67, 0x65, 0x6f,
0x72, 0x67, 0x65, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x69, 0x63, 0x75, 0x69, 0x2f, 0x67, 0x6f, 0x2f,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
0x72, 0x67, 0x65, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x2f, 0x67, 0x6f, 0x2f, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
}
var (
+100 -100
View File
@@ -7,7 +7,7 @@
package v1
import (
types "github.com/garethgeorge/resticui/gen/go/types"
types "github.com/garethgeorge/restora/gen/go/types"
_ "google.golang.org/genproto/googleapis/api/annotations"
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
@@ -534,80 +534,80 @@ var file_v1_service_proto_rawDesc = []byte{
0x69, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6d, 0x74, 0x69, 0x6d, 0x65,
0x12, 0x14, 0x0a, 0x05, 0x61, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52,
0x05, 0x61, 0x74, 0x69, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x63, 0x74, 0x69, 0x6d, 0x65, 0x18,
0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x74, 0x69, 0x6d, 0x65, 0x32, 0xcd, 0x08, 0x0a,
0x08, 0x52, 0x65, 0x73, 0x74, 0x69, 0x63, 0x55, 0x49, 0x12, 0x43, 0x0a, 0x09, 0x47, 0x65, 0x74,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e,
0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0a,
0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93,
0x02, 0x0c, 0x12, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3a,
0x0a, 0x09, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x0a, 0x2e, 0x76, 0x31,
0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x0a, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e,
0x66, 0x69, 0x67, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x3a, 0x01, 0x2a, 0x22, 0x0a,
0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3b, 0x0a, 0x07, 0x41, 0x64,
0x64, 0x52, 0x65, 0x70, 0x6f, 0x12, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x1a,
0x0a, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x1a, 0x82, 0xd3, 0xe4,
0x93, 0x02, 0x14, 0x3a, 0x01, 0x2a, 0x22, 0x0f, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x12, 0x61, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4f, 0x70,
0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x2e,
0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02,
0x17, 0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x6f, 0x70,
0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x30, 0x01, 0x12, 0x57, 0x0a, 0x0d, 0x47, 0x65,
0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x18, 0x2e, 0x76, 0x31,
0x2e, 0x47, 0x65, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65,
0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61,
0x74, 0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13,
0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69,
0x6f, 0x6e, 0x73, 0x12, 0x5b, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73,
0x68, 0x6f, 0x74, 0x73, 0x12, 0x18, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e,
0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16,
0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x69, 0x63, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68,
0x6f, 0x74, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x3a, 0x01,
0x2a, 0x22, 0x0d, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73,
0x12, 0x70, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74,
0x46, 0x69, 0x6c, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53,
0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75,
0x65, 0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x61,
0x70, 0x73, 0x68, 0x6f, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
0x73, 0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f,
0x76, 0x31, 0x2f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x2f, 0x66, 0x69, 0x6c,
0x65, 0x73, 0x12, 0x4f, 0x0a, 0x06, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x12, 0x2e, 0x74,
0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65,
0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13,
0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x62, 0x61, 0x63,
0x6b, 0x75, 0x70, 0x12, 0x4d, 0x0a, 0x05, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x12, 0x12, 0x2e, 0x74,
0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65,
0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12,
0x3a, 0x01, 0x2a, 0x22, 0x0d, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x70, 0x72, 0x75,
0x6e, 0x65, 0x12, 0x4f, 0x0a, 0x06, 0x46, 0x6f, 0x72, 0x67, 0x65, 0x74, 0x12, 0x12, 0x2e, 0x74,
0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65,
0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62,
0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13,
0x3a, 0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x66, 0x6f, 0x72,
0x67, 0x65, 0x74, 0x12, 0x59, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x1a,
0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73,
0x68, 0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f,
0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70,
0x74, 0x79, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x3a, 0x01, 0x2a, 0x22, 0x0f, 0x2f,
0x76, 0x31, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x4f,
0x0a, 0x06, 0x55, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73,
0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67,
0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x63, 0x74, 0x69, 0x6d, 0x65, 0x32, 0xcc, 0x08, 0x0a,
0x07, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x12, 0x43, 0x0a, 0x09, 0x47, 0x65, 0x74, 0x43,
0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70,
0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0a, 0x2e,
0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x12, 0x82, 0xd3, 0xe4, 0x93, 0x02,
0x0c, 0x12, 0x0a, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3a, 0x0a,
0x09, 0x53, 0x65, 0x74, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x0a, 0x2e, 0x76, 0x31, 0x2e,
0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x1a, 0x0a, 0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66,
0x69, 0x67, 0x22, 0x15, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x0f, 0x3a, 0x01, 0x2a, 0x22, 0x0a, 0x2f,
0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x3b, 0x0a, 0x07, 0x41, 0x64, 0x64,
0x52, 0x65, 0x70, 0x6f, 0x12, 0x08, 0x2e, 0x76, 0x31, 0x2e, 0x52, 0x65, 0x70, 0x6f, 0x1a, 0x0a,
0x2e, 0x76, 0x31, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93,
0x02, 0x14, 0x3a, 0x01, 0x2a, 0x22, 0x0f, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6f, 0x6e, 0x66, 0x69,
0x67, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x12, 0x61, 0x0a, 0x12, 0x47, 0x65, 0x74, 0x4f, 0x70, 0x65,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x16, 0x2e, 0x67,
0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45,
0x6d, 0x70, 0x74, 0x79, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22,
0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x75, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x12,
0x5b, 0x0a, 0x10, 0x50, 0x61, 0x74, 0x68, 0x41, 0x75, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x6c,
0x65, 0x74, 0x65, 0x12, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69,
0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e,
0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93,
0x02, 0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x6f, 0x63,
0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x42, 0x2e, 0x5a, 0x2c,
0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72, 0x65, 0x74,
0x68, 0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x69, 0x63, 0x75, 0x69,
0x2f, 0x67, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72,
0x6f, 0x74, 0x6f, 0x33,
0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x45, 0x76, 0x65, 0x6e, 0x74, 0x22, 0x1d, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x17,
0x12, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x73, 0x2f, 0x6f, 0x70, 0x65,
0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x30, 0x01, 0x12, 0x57, 0x0a, 0x0d, 0x47, 0x65, 0x74,
0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x18, 0x2e, 0x76, 0x31, 0x2e,
0x47, 0x65, 0x74, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x52, 0x65, 0x71,
0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x76, 0x31, 0x2e, 0x4f, 0x70, 0x65, 0x72, 0x61, 0x74,
0x69, 0x6f, 0x6e, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a,
0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f,
0x6e, 0x73, 0x12, 0x5b, 0x0a, 0x0d, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68,
0x6f, 0x74, 0x73, 0x12, 0x18, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x61,
0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e,
0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x69, 0x63, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f,
0x74, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x3a, 0x01, 0x2a,
0x22, 0x0d, 0x2f, 0x76, 0x31, 0x2f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x12,
0x70, 0x0a, 0x11, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x46,
0x69, 0x6c, 0x65, 0x73, 0x12, 0x1c, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e,
0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
0x73, 0x74, 0x1a, 0x1d, 0x2e, 0x76, 0x31, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x6e, 0x61, 0x70,
0x73, 0x68, 0x6f, 0x74, 0x46, 0x69, 0x6c, 0x65, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73,
0x65, 0x22, 0x1e, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x18, 0x3a, 0x01, 0x2a, 0x22, 0x13, 0x2f, 0x76,
0x31, 0x2f, 0x73, 0x6e, 0x61, 0x70, 0x73, 0x68, 0x6f, 0x74, 0x73, 0x2f, 0x66, 0x69, 0x6c, 0x65,
0x73, 0x12, 0x4f, 0x0a, 0x06, 0x42, 0x61, 0x63, 0x6b, 0x75, 0x70, 0x12, 0x12, 0x2e, 0x74, 0x79,
0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a,
0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a,
0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x62, 0x61, 0x63, 0x6b,
0x75, 0x70, 0x12, 0x4d, 0x0a, 0x05, 0x50, 0x72, 0x75, 0x6e, 0x65, 0x12, 0x12, 0x2e, 0x74, 0x79,
0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a,
0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x18, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x12, 0x3a,
0x01, 0x2a, 0x22, 0x0d, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x70, 0x72, 0x75, 0x6e,
0x65, 0x12, 0x4f, 0x0a, 0x06, 0x46, 0x6f, 0x72, 0x67, 0x65, 0x74, 0x12, 0x12, 0x2e, 0x74, 0x79,
0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a,
0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a,
0x01, 0x2a, 0x22, 0x0e, 0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x66, 0x6f, 0x72, 0x67,
0x65, 0x74, 0x12, 0x59, 0x0a, 0x07, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x1a, 0x2e,
0x76, 0x31, 0x2e, 0x52, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x53, 0x6e, 0x61, 0x70, 0x73, 0x68,
0x6f, 0x74, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74,
0x79, 0x22, 0x1a, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x14, 0x3a, 0x01, 0x2a, 0x22, 0x0f, 0x2f, 0x76,
0x31, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x12, 0x4f, 0x0a,
0x06, 0x55, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e,
0x53, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x16, 0x2e, 0x67, 0x6f,
0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d,
0x70, 0x74, 0x79, 0x22, 0x19, 0x82, 0xd3, 0xe4, 0x93, 0x02, 0x13, 0x3a, 0x01, 0x2a, 0x22, 0x0e,
0x2f, 0x76, 0x31, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x75, 0x6e, 0x6c, 0x6f, 0x63, 0x6b, 0x12, 0x5b,
0x0a, 0x10, 0x50, 0x61, 0x74, 0x68, 0x41, 0x75, 0x74, 0x6f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65,
0x74, 0x65, 0x12, 0x12, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53, 0x74, 0x72, 0x69, 0x6e,
0x67, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x1a, 0x11, 0x2e, 0x74, 0x79, 0x70, 0x65, 0x73, 0x2e, 0x53,
0x74, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x69, 0x73, 0x74, 0x22, 0x20, 0x82, 0xd3, 0xe4, 0x93, 0x02,
0x1a, 0x3a, 0x01, 0x2a, 0x22, 0x15, 0x2f, 0x76, 0x31, 0x2f, 0x61, 0x75, 0x74, 0x6f, 0x63, 0x6f,
0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x2f, 0x70, 0x61, 0x74, 0x68, 0x42, 0x2d, 0x5a, 0x2b, 0x67,
0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x61, 0x72, 0x65, 0x74, 0x68,
0x67, 0x65, 0x6f, 0x72, 0x67, 0x65, 0x2f, 0x72, 0x65, 0x73, 0x74, 0x6f, 0x72, 0x61, 0x2f, 0x67,
0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x76, 0x31, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
0x6f, 0x33,
}
var (
@@ -641,32 +641,32 @@ var file_v1_service_proto_goTypes = []interface{}{
}
var file_v1_service_proto_depIdxs = []int32{
5, // 0: v1.ListSnapshotFilesResponse.entries:type_name -> v1.LsEntry
6, // 1: v1.ResticUI.GetConfig:input_type -> google.protobuf.Empty
7, // 2: v1.ResticUI.SetConfig:input_type -> v1.Config
8, // 3: v1.ResticUI.AddRepo:input_type -> v1.Repo
6, // 4: v1.ResticUI.GetOperationEvents:input_type -> google.protobuf.Empty
1, // 5: v1.ResticUI.GetOperations:input_type -> v1.GetOperationsRequest
0, // 6: v1.ResticUI.ListSnapshots:input_type -> v1.ListSnapshotsRequest
3, // 7: v1.ResticUI.ListSnapshotFiles:input_type -> v1.ListSnapshotFilesRequest
9, // 8: v1.ResticUI.Backup:input_type -> types.StringValue
9, // 9: v1.ResticUI.Prune:input_type -> types.StringValue
9, // 10: v1.ResticUI.Forget:input_type -> types.StringValue
2, // 11: v1.ResticUI.Restore:input_type -> v1.RestoreSnapshotRequest
9, // 12: v1.ResticUI.Unlock:input_type -> types.StringValue
9, // 13: v1.ResticUI.PathAutocomplete:input_type -> types.StringValue
7, // 14: v1.ResticUI.GetConfig:output_type -> v1.Config
7, // 15: v1.ResticUI.SetConfig:output_type -> v1.Config
7, // 16: v1.ResticUI.AddRepo:output_type -> v1.Config
10, // 17: v1.ResticUI.GetOperationEvents:output_type -> v1.OperationEvent
11, // 18: v1.ResticUI.GetOperations:output_type -> v1.OperationList
12, // 19: v1.ResticUI.ListSnapshots:output_type -> v1.ResticSnapshotList
4, // 20: v1.ResticUI.ListSnapshotFiles:output_type -> v1.ListSnapshotFilesResponse
6, // 21: v1.ResticUI.Backup:output_type -> google.protobuf.Empty
6, // 22: v1.ResticUI.Prune:output_type -> google.protobuf.Empty
6, // 23: v1.ResticUI.Forget:output_type -> google.protobuf.Empty
6, // 24: v1.ResticUI.Restore:output_type -> google.protobuf.Empty
6, // 25: v1.ResticUI.Unlock:output_type -> google.protobuf.Empty
13, // 26: v1.ResticUI.PathAutocomplete:output_type -> types.StringList
6, // 1: v1.Restora.GetConfig:input_type -> google.protobuf.Empty
7, // 2: v1.Restora.SetConfig:input_type -> v1.Config
8, // 3: v1.Restora.AddRepo:input_type -> v1.Repo
6, // 4: v1.Restora.GetOperationEvents:input_type -> google.protobuf.Empty
1, // 5: v1.Restora.GetOperations:input_type -> v1.GetOperationsRequest
0, // 6: v1.Restora.ListSnapshots:input_type -> v1.ListSnapshotsRequest
3, // 7: v1.Restora.ListSnapshotFiles:input_type -> v1.ListSnapshotFilesRequest
9, // 8: v1.Restora.Backup:input_type -> types.StringValue
9, // 9: v1.Restora.Prune:input_type -> types.StringValue
9, // 10: v1.Restora.Forget:input_type -> types.StringValue
2, // 11: v1.Restora.Restore:input_type -> v1.RestoreSnapshotRequest
9, // 12: v1.Restora.Unlock:input_type -> types.StringValue
9, // 13: v1.Restora.PathAutocomplete:input_type -> types.StringValue
7, // 14: v1.Restora.GetConfig:output_type -> v1.Config
7, // 15: v1.Restora.SetConfig:output_type -> v1.Config
7, // 16: v1.Restora.AddRepo:output_type -> v1.Config
10, // 17: v1.Restora.GetOperationEvents:output_type -> v1.OperationEvent
11, // 18: v1.Restora.GetOperations:output_type -> v1.OperationList
12, // 19: v1.Restora.ListSnapshots:output_type -> v1.ResticSnapshotList
4, // 20: v1.Restora.ListSnapshotFiles:output_type -> v1.ListSnapshotFilesResponse
6, // 21: v1.Restora.Backup:output_type -> google.protobuf.Empty
6, // 22: v1.Restora.Prune:output_type -> google.protobuf.Empty
6, // 23: v1.Restora.Forget:output_type -> google.protobuf.Empty
6, // 24: v1.Restora.Restore:output_type -> google.protobuf.Empty
6, // 25: v1.Restora.Unlock:output_type -> google.protobuf.Empty
13, // 26: v1.Restora.PathAutocomplete:output_type -> types.StringList
14, // [14:27] is the sub-list for method output_type
1, // [1:14] is the sub-list for method input_type
1, // [1:1] is the sub-list for extension type_name
+168 -168
View File
File diff suppressed because it is too large Load Diff
+147 -147
View File
@@ -8,7 +8,7 @@ package v1
import (
context "context"
types "github.com/garethgeorge/resticui/gen/go/types"
types "github.com/garethgeorge/restora/gen/go/types"
grpc "google.golang.org/grpc"
codes "google.golang.org/grpc/codes"
status "google.golang.org/grpc/status"
@@ -21,29 +21,29 @@ import (
const _ = grpc.SupportPackageIsVersion7
const (
ResticUI_GetConfig_FullMethodName = "/v1.ResticUI/GetConfig"
ResticUI_SetConfig_FullMethodName = "/v1.ResticUI/SetConfig"
ResticUI_AddRepo_FullMethodName = "/v1.ResticUI/AddRepo"
ResticUI_GetOperationEvents_FullMethodName = "/v1.ResticUI/GetOperationEvents"
ResticUI_GetOperations_FullMethodName = "/v1.ResticUI/GetOperations"
ResticUI_ListSnapshots_FullMethodName = "/v1.ResticUI/ListSnapshots"
ResticUI_ListSnapshotFiles_FullMethodName = "/v1.ResticUI/ListSnapshotFiles"
ResticUI_Backup_FullMethodName = "/v1.ResticUI/Backup"
ResticUI_Prune_FullMethodName = "/v1.ResticUI/Prune"
ResticUI_Forget_FullMethodName = "/v1.ResticUI/Forget"
ResticUI_Restore_FullMethodName = "/v1.ResticUI/Restore"
ResticUI_Unlock_FullMethodName = "/v1.ResticUI/Unlock"
ResticUI_PathAutocomplete_FullMethodName = "/v1.ResticUI/PathAutocomplete"
Restora_GetConfig_FullMethodName = "/v1.Restora/GetConfig"
Restora_SetConfig_FullMethodName = "/v1.Restora/SetConfig"
Restora_AddRepo_FullMethodName = "/v1.Restora/AddRepo"
Restora_GetOperationEvents_FullMethodName = "/v1.Restora/GetOperationEvents"
Restora_GetOperations_FullMethodName = "/v1.Restora/GetOperations"
Restora_ListSnapshots_FullMethodName = "/v1.Restora/ListSnapshots"
Restora_ListSnapshotFiles_FullMethodName = "/v1.Restora/ListSnapshotFiles"
Restora_Backup_FullMethodName = "/v1.Restora/Backup"
Restora_Prune_FullMethodName = "/v1.Restora/Prune"
Restora_Forget_FullMethodName = "/v1.Restora/Forget"
Restora_Restore_FullMethodName = "/v1.Restora/Restore"
Restora_Unlock_FullMethodName = "/v1.Restora/Unlock"
Restora_PathAutocomplete_FullMethodName = "/v1.Restora/PathAutocomplete"
)
// ResticUIClient is the client API for ResticUI service.
// RestoraClient is the client API for Restora service.
//
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
type ResticUIClient interface {
type RestoraClient interface {
GetConfig(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*Config, error)
SetConfig(ctx context.Context, in *Config, opts ...grpc.CallOption) (*Config, error)
AddRepo(ctx context.Context, in *Repo, opts ...grpc.CallOption) (*Config, error)
GetOperationEvents(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (ResticUI_GetOperationEventsClient, error)
GetOperationEvents(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (Restora_GetOperationEventsClient, error)
GetOperations(ctx context.Context, in *GetOperationsRequest, opts ...grpc.CallOption) (*OperationList, error)
ListSnapshots(ctx context.Context, in *ListSnapshotsRequest, opts ...grpc.CallOption) (*ResticSnapshotList, error)
ListSnapshotFiles(ctx context.Context, in *ListSnapshotFilesRequest, opts ...grpc.CallOption) (*ListSnapshotFilesResponse, error)
@@ -61,47 +61,47 @@ type ResticUIClient interface {
PathAutocomplete(ctx context.Context, in *types.StringValue, opts ...grpc.CallOption) (*types.StringList, error)
}
type resticUIClient struct {
type restoraClient struct {
cc grpc.ClientConnInterface
}
func NewResticUIClient(cc grpc.ClientConnInterface) ResticUIClient {
return &resticUIClient{cc}
func NewRestoraClient(cc grpc.ClientConnInterface) RestoraClient {
return &restoraClient{cc}
}
func (c *resticUIClient) GetConfig(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*Config, error) {
func (c *restoraClient) GetConfig(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (*Config, error) {
out := new(Config)
err := c.cc.Invoke(ctx, ResticUI_GetConfig_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Restora_GetConfig_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *resticUIClient) SetConfig(ctx context.Context, in *Config, opts ...grpc.CallOption) (*Config, error) {
func (c *restoraClient) SetConfig(ctx context.Context, in *Config, opts ...grpc.CallOption) (*Config, error) {
out := new(Config)
err := c.cc.Invoke(ctx, ResticUI_SetConfig_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Restora_SetConfig_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *resticUIClient) AddRepo(ctx context.Context, in *Repo, opts ...grpc.CallOption) (*Config, error) {
func (c *restoraClient) AddRepo(ctx context.Context, in *Repo, opts ...grpc.CallOption) (*Config, error) {
out := new(Config)
err := c.cc.Invoke(ctx, ResticUI_AddRepo_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Restora_AddRepo_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *resticUIClient) GetOperationEvents(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (ResticUI_GetOperationEventsClient, error) {
stream, err := c.cc.NewStream(ctx, &ResticUI_ServiceDesc.Streams[0], ResticUI_GetOperationEvents_FullMethodName, opts...)
func (c *restoraClient) GetOperationEvents(ctx context.Context, in *emptypb.Empty, opts ...grpc.CallOption) (Restora_GetOperationEventsClient, error) {
stream, err := c.cc.NewStream(ctx, &Restora_ServiceDesc.Streams[0], Restora_GetOperationEvents_FullMethodName, opts...)
if err != nil {
return nil, err
}
x := &resticUIGetOperationEventsClient{stream}
x := &restoraGetOperationEventsClient{stream}
if err := x.ClientStream.SendMsg(in); err != nil {
return nil, err
}
@@ -111,16 +111,16 @@ func (c *resticUIClient) GetOperationEvents(ctx context.Context, in *emptypb.Emp
return x, nil
}
type ResticUI_GetOperationEventsClient interface {
type Restora_GetOperationEventsClient interface {
Recv() (*OperationEvent, error)
grpc.ClientStream
}
type resticUIGetOperationEventsClient struct {
type restoraGetOperationEventsClient struct {
grpc.ClientStream
}
func (x *resticUIGetOperationEventsClient) Recv() (*OperationEvent, error) {
func (x *restoraGetOperationEventsClient) Recv() (*OperationEvent, error) {
m := new(OperationEvent)
if err := x.ClientStream.RecvMsg(m); err != nil {
return nil, err
@@ -128,95 +128,95 @@ func (x *resticUIGetOperationEventsClient) Recv() (*OperationEvent, error) {
return m, nil
}
func (c *resticUIClient) GetOperations(ctx context.Context, in *GetOperationsRequest, opts ...grpc.CallOption) (*OperationList, error) {
func (c *restoraClient) GetOperations(ctx context.Context, in *GetOperationsRequest, opts ...grpc.CallOption) (*OperationList, error) {
out := new(OperationList)
err := c.cc.Invoke(ctx, ResticUI_GetOperations_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Restora_GetOperations_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *resticUIClient) ListSnapshots(ctx context.Context, in *ListSnapshotsRequest, opts ...grpc.CallOption) (*ResticSnapshotList, error) {
func (c *restoraClient) ListSnapshots(ctx context.Context, in *ListSnapshotsRequest, opts ...grpc.CallOption) (*ResticSnapshotList, error) {
out := new(ResticSnapshotList)
err := c.cc.Invoke(ctx, ResticUI_ListSnapshots_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Restora_ListSnapshots_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *resticUIClient) ListSnapshotFiles(ctx context.Context, in *ListSnapshotFilesRequest, opts ...grpc.CallOption) (*ListSnapshotFilesResponse, error) {
func (c *restoraClient) ListSnapshotFiles(ctx context.Context, in *ListSnapshotFilesRequest, opts ...grpc.CallOption) (*ListSnapshotFilesResponse, error) {
out := new(ListSnapshotFilesResponse)
err := c.cc.Invoke(ctx, ResticUI_ListSnapshotFiles_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Restora_ListSnapshotFiles_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *resticUIClient) Backup(ctx context.Context, in *types.StringValue, opts ...grpc.CallOption) (*emptypb.Empty, error) {
func (c *restoraClient) Backup(ctx context.Context, in *types.StringValue, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, ResticUI_Backup_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Restora_Backup_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *resticUIClient) Prune(ctx context.Context, in *types.StringValue, opts ...grpc.CallOption) (*emptypb.Empty, error) {
func (c *restoraClient) Prune(ctx context.Context, in *types.StringValue, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, ResticUI_Prune_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Restora_Prune_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *resticUIClient) Forget(ctx context.Context, in *types.StringValue, opts ...grpc.CallOption) (*emptypb.Empty, error) {
func (c *restoraClient) Forget(ctx context.Context, in *types.StringValue, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, ResticUI_Forget_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Restora_Forget_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *resticUIClient) Restore(ctx context.Context, in *RestoreSnapshotRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
func (c *restoraClient) Restore(ctx context.Context, in *RestoreSnapshotRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, ResticUI_Restore_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Restora_Restore_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *resticUIClient) Unlock(ctx context.Context, in *types.StringValue, opts ...grpc.CallOption) (*emptypb.Empty, error) {
func (c *restoraClient) Unlock(ctx context.Context, in *types.StringValue, opts ...grpc.CallOption) (*emptypb.Empty, error) {
out := new(emptypb.Empty)
err := c.cc.Invoke(ctx, ResticUI_Unlock_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Restora_Unlock_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
func (c *resticUIClient) PathAutocomplete(ctx context.Context, in *types.StringValue, opts ...grpc.CallOption) (*types.StringList, error) {
func (c *restoraClient) PathAutocomplete(ctx context.Context, in *types.StringValue, opts ...grpc.CallOption) (*types.StringList, error) {
out := new(types.StringList)
err := c.cc.Invoke(ctx, ResticUI_PathAutocomplete_FullMethodName, in, out, opts...)
err := c.cc.Invoke(ctx, Restora_PathAutocomplete_FullMethodName, in, out, opts...)
if err != nil {
return nil, err
}
return out, nil
}
// ResticUIServer is the server API for ResticUI service.
// All implementations must embed UnimplementedResticUIServer
// RestoraServer is the server API for Restora service.
// All implementations must embed UnimplementedRestoraServer
// for forward compatibility
type ResticUIServer interface {
type RestoraServer interface {
GetConfig(context.Context, *emptypb.Empty) (*Config, error)
SetConfig(context.Context, *Config) (*Config, error)
AddRepo(context.Context, *Repo) (*Config, error)
GetOperationEvents(*emptypb.Empty, ResticUI_GetOperationEventsServer) error
GetOperationEvents(*emptypb.Empty, Restora_GetOperationEventsServer) error
GetOperations(context.Context, *GetOperationsRequest) (*OperationList, error)
ListSnapshots(context.Context, *ListSnapshotsRequest) (*ResticSnapshotList, error)
ListSnapshotFiles(context.Context, *ListSnapshotFilesRequest) (*ListSnapshotFilesResponse, error)
@@ -232,362 +232,362 @@ type ResticUIServer interface {
Unlock(context.Context, *types.StringValue) (*emptypb.Empty, error)
// PathAutocomplete provides path autocompletion options for a given filesystem path.
PathAutocomplete(context.Context, *types.StringValue) (*types.StringList, error)
mustEmbedUnimplementedResticUIServer()
mustEmbedUnimplementedRestoraServer()
}
// UnimplementedResticUIServer must be embedded to have forward compatible implementations.
type UnimplementedResticUIServer struct {
// UnimplementedRestoraServer must be embedded to have forward compatible implementations.
type UnimplementedRestoraServer struct {
}
func (UnimplementedResticUIServer) GetConfig(context.Context, *emptypb.Empty) (*Config, error) {
func (UnimplementedRestoraServer) GetConfig(context.Context, *emptypb.Empty) (*Config, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetConfig not implemented")
}
func (UnimplementedResticUIServer) SetConfig(context.Context, *Config) (*Config, error) {
func (UnimplementedRestoraServer) SetConfig(context.Context, *Config) (*Config, error) {
return nil, status.Errorf(codes.Unimplemented, "method SetConfig not implemented")
}
func (UnimplementedResticUIServer) AddRepo(context.Context, *Repo) (*Config, error) {
func (UnimplementedRestoraServer) AddRepo(context.Context, *Repo) (*Config, error) {
return nil, status.Errorf(codes.Unimplemented, "method AddRepo not implemented")
}
func (UnimplementedResticUIServer) GetOperationEvents(*emptypb.Empty, ResticUI_GetOperationEventsServer) error {
func (UnimplementedRestoraServer) GetOperationEvents(*emptypb.Empty, Restora_GetOperationEventsServer) error {
return status.Errorf(codes.Unimplemented, "method GetOperationEvents not implemented")
}
func (UnimplementedResticUIServer) GetOperations(context.Context, *GetOperationsRequest) (*OperationList, error) {
func (UnimplementedRestoraServer) GetOperations(context.Context, *GetOperationsRequest) (*OperationList, error) {
return nil, status.Errorf(codes.Unimplemented, "method GetOperations not implemented")
}
func (UnimplementedResticUIServer) ListSnapshots(context.Context, *ListSnapshotsRequest) (*ResticSnapshotList, error) {
func (UnimplementedRestoraServer) ListSnapshots(context.Context, *ListSnapshotsRequest) (*ResticSnapshotList, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListSnapshots not implemented")
}
func (UnimplementedResticUIServer) ListSnapshotFiles(context.Context, *ListSnapshotFilesRequest) (*ListSnapshotFilesResponse, error) {
func (UnimplementedRestoraServer) ListSnapshotFiles(context.Context, *ListSnapshotFilesRequest) (*ListSnapshotFilesResponse, error) {
return nil, status.Errorf(codes.Unimplemented, "method ListSnapshotFiles not implemented")
}
func (UnimplementedResticUIServer) Backup(context.Context, *types.StringValue) (*emptypb.Empty, error) {
func (UnimplementedRestoraServer) Backup(context.Context, *types.StringValue) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method Backup not implemented")
}
func (UnimplementedResticUIServer) Prune(context.Context, *types.StringValue) (*emptypb.Empty, error) {
func (UnimplementedRestoraServer) Prune(context.Context, *types.StringValue) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method Prune not implemented")
}
func (UnimplementedResticUIServer) Forget(context.Context, *types.StringValue) (*emptypb.Empty, error) {
func (UnimplementedRestoraServer) Forget(context.Context, *types.StringValue) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method Forget not implemented")
}
func (UnimplementedResticUIServer) Restore(context.Context, *RestoreSnapshotRequest) (*emptypb.Empty, error) {
func (UnimplementedRestoraServer) Restore(context.Context, *RestoreSnapshotRequest) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method Restore not implemented")
}
func (UnimplementedResticUIServer) Unlock(context.Context, *types.StringValue) (*emptypb.Empty, error) {
func (UnimplementedRestoraServer) Unlock(context.Context, *types.StringValue) (*emptypb.Empty, error) {
return nil, status.Errorf(codes.Unimplemented, "method Unlock not implemented")
}
func (UnimplementedResticUIServer) PathAutocomplete(context.Context, *types.StringValue) (*types.StringList, error) {
func (UnimplementedRestoraServer) PathAutocomplete(context.Context, *types.StringValue) (*types.StringList, error) {
return nil, status.Errorf(codes.Unimplemented, "method PathAutocomplete not implemented")
}
func (UnimplementedResticUIServer) mustEmbedUnimplementedResticUIServer() {}
func (UnimplementedRestoraServer) mustEmbedUnimplementedRestoraServer() {}
// UnsafeResticUIServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to ResticUIServer will
// UnsafeRestoraServer may be embedded to opt out of forward compatibility for this service.
// Use of this interface is not recommended, as added methods to RestoraServer will
// result in compilation errors.
type UnsafeResticUIServer interface {
mustEmbedUnimplementedResticUIServer()
type UnsafeRestoraServer interface {
mustEmbedUnimplementedRestoraServer()
}
func RegisterResticUIServer(s grpc.ServiceRegistrar, srv ResticUIServer) {
s.RegisterService(&ResticUI_ServiceDesc, srv)
func RegisterRestoraServer(s grpc.ServiceRegistrar, srv RestoraServer) {
s.RegisterService(&Restora_ServiceDesc, srv)
}
func _ResticUI_GetConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
func _Restora_GetConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(emptypb.Empty)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ResticUIServer).GetConfig(ctx, in)
return srv.(RestoraServer).GetConfig(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ResticUI_GetConfig_FullMethodName,
FullMethod: Restora_GetConfig_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ResticUIServer).GetConfig(ctx, req.(*emptypb.Empty))
return srv.(RestoraServer).GetConfig(ctx, req.(*emptypb.Empty))
}
return interceptor(ctx, in, info, handler)
}
func _ResticUI_SetConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
func _Restora_SetConfig_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Config)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ResticUIServer).SetConfig(ctx, in)
return srv.(RestoraServer).SetConfig(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ResticUI_SetConfig_FullMethodName,
FullMethod: Restora_SetConfig_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ResticUIServer).SetConfig(ctx, req.(*Config))
return srv.(RestoraServer).SetConfig(ctx, req.(*Config))
}
return interceptor(ctx, in, info, handler)
}
func _ResticUI_AddRepo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
func _Restora_AddRepo_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(Repo)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ResticUIServer).AddRepo(ctx, in)
return srv.(RestoraServer).AddRepo(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ResticUI_AddRepo_FullMethodName,
FullMethod: Restora_AddRepo_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ResticUIServer).AddRepo(ctx, req.(*Repo))
return srv.(RestoraServer).AddRepo(ctx, req.(*Repo))
}
return interceptor(ctx, in, info, handler)
}
func _ResticUI_GetOperationEvents_Handler(srv interface{}, stream grpc.ServerStream) error {
func _Restora_GetOperationEvents_Handler(srv interface{}, stream grpc.ServerStream) error {
m := new(emptypb.Empty)
if err := stream.RecvMsg(m); err != nil {
return err
}
return srv.(ResticUIServer).GetOperationEvents(m, &resticUIGetOperationEventsServer{stream})
return srv.(RestoraServer).GetOperationEvents(m, &restoraGetOperationEventsServer{stream})
}
type ResticUI_GetOperationEventsServer interface {
type Restora_GetOperationEventsServer interface {
Send(*OperationEvent) error
grpc.ServerStream
}
type resticUIGetOperationEventsServer struct {
type restoraGetOperationEventsServer struct {
grpc.ServerStream
}
func (x *resticUIGetOperationEventsServer) Send(m *OperationEvent) error {
func (x *restoraGetOperationEventsServer) Send(m *OperationEvent) error {
return x.ServerStream.SendMsg(m)
}
func _ResticUI_GetOperations_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
func _Restora_GetOperations_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(GetOperationsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ResticUIServer).GetOperations(ctx, in)
return srv.(RestoraServer).GetOperations(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ResticUI_GetOperations_FullMethodName,
FullMethod: Restora_GetOperations_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ResticUIServer).GetOperations(ctx, req.(*GetOperationsRequest))
return srv.(RestoraServer).GetOperations(ctx, req.(*GetOperationsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ResticUI_ListSnapshots_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
func _Restora_ListSnapshots_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListSnapshotsRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ResticUIServer).ListSnapshots(ctx, in)
return srv.(RestoraServer).ListSnapshots(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ResticUI_ListSnapshots_FullMethodName,
FullMethod: Restora_ListSnapshots_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ResticUIServer).ListSnapshots(ctx, req.(*ListSnapshotsRequest))
return srv.(RestoraServer).ListSnapshots(ctx, req.(*ListSnapshotsRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ResticUI_ListSnapshotFiles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
func _Restora_ListSnapshotFiles_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(ListSnapshotFilesRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ResticUIServer).ListSnapshotFiles(ctx, in)
return srv.(RestoraServer).ListSnapshotFiles(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ResticUI_ListSnapshotFiles_FullMethodName,
FullMethod: Restora_ListSnapshotFiles_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ResticUIServer).ListSnapshotFiles(ctx, req.(*ListSnapshotFilesRequest))
return srv.(RestoraServer).ListSnapshotFiles(ctx, req.(*ListSnapshotFilesRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ResticUI_Backup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
func _Restora_Backup_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(types.StringValue)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ResticUIServer).Backup(ctx, in)
return srv.(RestoraServer).Backup(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ResticUI_Backup_FullMethodName,
FullMethod: Restora_Backup_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ResticUIServer).Backup(ctx, req.(*types.StringValue))
return srv.(RestoraServer).Backup(ctx, req.(*types.StringValue))
}
return interceptor(ctx, in, info, handler)
}
func _ResticUI_Prune_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
func _Restora_Prune_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(types.StringValue)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ResticUIServer).Prune(ctx, in)
return srv.(RestoraServer).Prune(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ResticUI_Prune_FullMethodName,
FullMethod: Restora_Prune_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ResticUIServer).Prune(ctx, req.(*types.StringValue))
return srv.(RestoraServer).Prune(ctx, req.(*types.StringValue))
}
return interceptor(ctx, in, info, handler)
}
func _ResticUI_Forget_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
func _Restora_Forget_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(types.StringValue)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ResticUIServer).Forget(ctx, in)
return srv.(RestoraServer).Forget(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ResticUI_Forget_FullMethodName,
FullMethod: Restora_Forget_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ResticUIServer).Forget(ctx, req.(*types.StringValue))
return srv.(RestoraServer).Forget(ctx, req.(*types.StringValue))
}
return interceptor(ctx, in, info, handler)
}
func _ResticUI_Restore_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
func _Restora_Restore_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(RestoreSnapshotRequest)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ResticUIServer).Restore(ctx, in)
return srv.(RestoraServer).Restore(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ResticUI_Restore_FullMethodName,
FullMethod: Restora_Restore_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ResticUIServer).Restore(ctx, req.(*RestoreSnapshotRequest))
return srv.(RestoraServer).Restore(ctx, req.(*RestoreSnapshotRequest))
}
return interceptor(ctx, in, info, handler)
}
func _ResticUI_Unlock_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
func _Restora_Unlock_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(types.StringValue)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ResticUIServer).Unlock(ctx, in)
return srv.(RestoraServer).Unlock(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ResticUI_Unlock_FullMethodName,
FullMethod: Restora_Unlock_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ResticUIServer).Unlock(ctx, req.(*types.StringValue))
return srv.(RestoraServer).Unlock(ctx, req.(*types.StringValue))
}
return interceptor(ctx, in, info, handler)
}
func _ResticUI_PathAutocomplete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
func _Restora_PathAutocomplete_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
in := new(types.StringValue)
if err := dec(in); err != nil {
return nil, err
}
if interceptor == nil {
return srv.(ResticUIServer).PathAutocomplete(ctx, in)
return srv.(RestoraServer).PathAutocomplete(ctx, in)
}
info := &grpc.UnaryServerInfo{
Server: srv,
FullMethod: ResticUI_PathAutocomplete_FullMethodName,
FullMethod: Restora_PathAutocomplete_FullMethodName,
}
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
return srv.(ResticUIServer).PathAutocomplete(ctx, req.(*types.StringValue))
return srv.(RestoraServer).PathAutocomplete(ctx, req.(*types.StringValue))
}
return interceptor(ctx, in, info, handler)
}
// ResticUI_ServiceDesc is the grpc.ServiceDesc for ResticUI service.
// Restora_ServiceDesc is the grpc.ServiceDesc for Restora service.
// It's only intended for direct use with grpc.RegisterService,
// and not to be introspected or modified (even as a copy)
var ResticUI_ServiceDesc = grpc.ServiceDesc{
ServiceName: "v1.ResticUI",
HandlerType: (*ResticUIServer)(nil),
var Restora_ServiceDesc = grpc.ServiceDesc{
ServiceName: "v1.Restora",
HandlerType: (*RestoraServer)(nil),
Methods: []grpc.MethodDesc{
{
MethodName: "GetConfig",
Handler: _ResticUI_GetConfig_Handler,
Handler: _Restora_GetConfig_Handler,
},
{
MethodName: "SetConfig",
Handler: _ResticUI_SetConfig_Handler,
Handler: _Restora_SetConfig_Handler,
},
{
MethodName: "AddRepo",
Handler: _ResticUI_AddRepo_Handler,
Handler: _Restora_AddRepo_Handler,
},
{
MethodName: "GetOperations",
Handler: _ResticUI_GetOperations_Handler,
Handler: _Restora_GetOperations_Handler,
},
{
MethodName: "ListSnapshots",
Handler: _ResticUI_ListSnapshots_Handler,
Handler: _Restora_ListSnapshots_Handler,
},
{
MethodName: "ListSnapshotFiles",
Handler: _ResticUI_ListSnapshotFiles_Handler,
Handler: _Restora_ListSnapshotFiles_Handler,
},
{
MethodName: "Backup",
Handler: _ResticUI_Backup_Handler,
Handler: _Restora_Backup_Handler,
},
{
MethodName: "Prune",
Handler: _ResticUI_Prune_Handler,
Handler: _Restora_Prune_Handler,
},
{
MethodName: "Forget",
Handler: _ResticUI_Forget_Handler,
Handler: _Restora_Forget_Handler,
},
{
MethodName: "Restore",
Handler: _ResticUI_Restore_Handler,
Handler: _Restora_Restore_Handler,
},
{
MethodName: "Unlock",
Handler: _ResticUI_Unlock_Handler,
Handler: _Restora_Unlock_Handler,
},
{
MethodName: "PathAutocomplete",
Handler: _ResticUI_PathAutocomplete_Handler,
Handler: _Restora_PathAutocomplete_Handler,
},
},
Streams: []grpc.StreamDesc{
{
StreamName: "GetOperationEvents",
Handler: _ResticUI_GetOperationEvents_Handler,
Handler: _Restora_GetOperationEvents_Handler,
ServerStreams: true,
},
},
+1 -2
View File
@@ -1,4 +1,4 @@
module github.com/garethgeorge/resticui
module github.com/garethgeorge/restora
go 1.21.3
@@ -20,7 +20,6 @@ require (
require (
github.com/daaku/go.zipexe v1.0.2 // indirect
github.com/golang/protobuf v1.5.3 // indirect
github.com/google/renameio v1.0.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
go.uber.org/multierr v1.11.0 // indirect
-2
View File
@@ -14,8 +14,6 @@ github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiu
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/renameio v1.0.1 h1:Lh/jXZmvZxb0BBeSY5VKEfidcbcbenKjZFzM/q0fSeU=
github.com/google/renameio v1.0.1/go.mod h1:t/HQoYBZSsWSNK35C6CO/TpPLDVWvxOHboWUAweKUpk=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1 h1:HcUWd006luQPljE73d5sk+/VgYPGUReEVz2y1/qylwY=
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.1/go.mod h1:w9Y7gY31krpLmrVU5ZPG9H7l9fZuRu5/3R3S3FMtVQ4=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.18.1 h1:6UKoz5ujsI55KNpsJH3UwCq3T8kKbZwNZBNPuTTje8U=
+5 -5
View File
@@ -8,7 +8,7 @@ import (
"os"
"path/filepath"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
"go.uber.org/zap"
@@ -68,7 +68,7 @@ func serveGRPC(ctx context.Context, socket string, server *Server) error {
logging.StreamServerInterceptor(loggingFunc(logger)),
),
)
v1.RegisterResticUIServer(grpcServer, server)
v1.RegisterRestoraServer(grpcServer, server)
go func() {
<-ctx.Done()
grpcServer.GracefulStop()
@@ -81,7 +81,7 @@ func serveGRPC(ctx context.Context, socket string, server *Server) error {
}
func serveHTTPHandlers(ctx context.Context, server *Server, mux *runtime.ServeMux) error {
tmpDir, err := os.MkdirTemp("", "resticui")
tmpDir, err := os.MkdirTemp("", "restora")
if err != nil {
return fmt.Errorf("failed to create temp dir for unix domain socket: %w", err)
}
@@ -89,10 +89,10 @@ func serveHTTPHandlers(ctx context.Context, server *Server, mux *runtime.ServeMu
os.RemoveAll(tmpDir)
}()
socket := filepath.Join(tmpDir, "resticui.sock")
socket := filepath.Join(tmpDir, "restora.sock")
opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
err = v1.RegisterResticUIHandlerFromEndpoint(ctx, mux, fmt.Sprintf("unix:%v", socket), opts)
err = v1.RegisterRestoraHandlerFromEndpoint(ctx, mux, fmt.Sprintf("unix:%v", socket), opts)
if err != nil {
return fmt.Errorf("failed to register gateway: %w", err)
}
+12 -12
View File
@@ -8,28 +8,28 @@ import (
"path"
"time"
"github.com/garethgeorge/resticui/gen/go/types"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/internal/config"
"github.com/garethgeorge/resticui/internal/oplog"
"github.com/garethgeorge/resticui/internal/oplog/indexutil"
"github.com/garethgeorge/resticui/internal/orchestrator"
"github.com/garethgeorge/resticui/internal/protoutil"
"github.com/garethgeorge/resticui/internal/resticinstaller"
"github.com/garethgeorge/resticui/pkg/restic"
"github.com/garethgeorge/restora/gen/go/types"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/garethgeorge/restora/internal/config"
"github.com/garethgeorge/restora/internal/oplog"
"github.com/garethgeorge/restora/internal/oplog/indexutil"
"github.com/garethgeorge/restora/internal/orchestrator"
"github.com/garethgeorge/restora/internal/protoutil"
"github.com/garethgeorge/restora/internal/resticinstaller"
"github.com/garethgeorge/restora/pkg/restic"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/emptypb"
)
type Server struct {
*v1.UnimplementedResticUIServer
*v1.UnimplementedRestoraServer
config config.ConfigStore
orchestrator *orchestrator.Orchestrator
oplog *oplog.OpLog
}
var _ v1.ResticUIServer = &Server{}
var _ v1.RestoraServer = &Server{}
func NewServer(config config.ConfigStore, orchestrator *orchestrator.Orchestrator, oplog *oplog.OpLog) *Server {
s := &Server{
@@ -158,7 +158,7 @@ func (s *Server) ListSnapshotFiles(ctx context.Context, query *v1.ListSnapshotFi
}
// GetOperationEvents implements GET /v1/events/operations
func (s *Server) GetOperationEvents(_ *emptypb.Empty, stream v1.ResticUI_GetOperationEventsServer) error {
func (s *Server) GetOperationEvents(_ *emptypb.Empty, stream v1.Restora_GetOperationEventsServer) error {
errorChan := make(chan error)
defer close(errorChan)
callback := func(oldOp *v1.Operation, newOp *v1.Operation) {
+3 -3
View File
@@ -7,7 +7,7 @@ import (
"path"
"sync"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
v1 "github.com/garethgeorge/restora/gen/go/v1"
)
var ErrConfigNotFound = fmt.Errorf("config not found")
@@ -30,7 +30,7 @@ func configDir(override string) string {
}
if env := os.Getenv("XDG_CONFIG_HOME"); env != "" {
return path.Join(env, "resticui")
return path.Join(env, "restora")
}
home, err := os.UserHomeDir()
@@ -38,7 +38,7 @@ func configDir(override string) string {
panic(err)
}
return fmt.Sprintf("%v/.config/resticui", home)
return fmt.Sprintf("%v/.config/restora", home)
}
type CachingValidatingStore struct {
+21 -22
View File
@@ -4,36 +4,35 @@ import (
"strings"
"testing"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"google.golang.org/protobuf/proto"
)
func TestConfig(t *testing.T) {
dir := t.TempDir()
testRepo := &v1.Repo{
Id: "test-repo",
Uri: "/tmp/test",
Id: "test-repo",
Uri: "/tmp/test",
Password: "test",
}
testPlan := &v1.Plan{
Id: "test-plan",
Repo: "test-repo",
Id: "test-plan",
Repo: "test-repo",
Paths: []string{"/tmp/foo"},
Cron: "* * * * *",
Cron: "* * * * *",
}
tests := []struct {
name string
config *v1.Config
wantErr bool
name string
config *v1.Config
wantErr bool
wantErrContains string
store ConfigStore
store ConfigStore
}{
{
name: "default config",
name: "default config",
config: NewDefaultConfig(),
store: &CachingValidatingStore{ConfigStore: &JsonFileStore{Path: dir + "/default-config.json"}},
},
@@ -50,8 +49,8 @@ func TestConfig(t *testing.T) {
config: &v1.Config{
Plans: []*v1.Plan{testPlan},
},
store: &CachingValidatingStore{ConfigStore: &JsonFileStore{Path: dir + "/invalid-config.json"}},
wantErr: true,
store: &CachingValidatingStore{ConfigStore: &JsonFileStore{Path: dir + "/invalid-config.json"}},
wantErr: true,
wantErrContains: "repo \"test-repo\" not found",
},
{
@@ -62,8 +61,8 @@ func TestConfig(t *testing.T) {
testRepo,
},
},
store: &CachingValidatingStore{ConfigStore: &JsonFileStore{Path: dir + "/invalid-config2.json"}},
wantErr: true,
store: &CachingValidatingStore{ConfigStore: &JsonFileStore{Path: dir + "/invalid-config2.json"}},
wantErr: true,
wantErrContains: "repo test-repo: duplicate id",
},
{
@@ -74,15 +73,15 @@ func TestConfig(t *testing.T) {
},
Plans: []*v1.Plan{
{
Id: "test-plan",
Repo: "test-repo",
Id: "test-plan",
Repo: "test-repo",
Paths: []string{"/tmp/foo"},
Cron: "bad cron",
Cron: "bad cron",
},
},
},
store: &CachingValidatingStore{ConfigStore: &JsonFileStore{Path: dir + "/invalid-config3.json"}},
wantErr: true,
store: &CachingValidatingStore{ConfigStore: &JsonFileStore{Path: dir + "/invalid-config3.json"}},
wantErr: true,
wantErrContains: "invalid cron \"bad cron\"",
},
}
@@ -111,4 +110,4 @@ func TestConfig(t *testing.T) {
}
})
}
}
}
+13 -13
View File
@@ -9,37 +9,37 @@ import (
)
var (
EnvVarConfigPath = "RESTICUI_CONFIG_PATH"
EnvVarDataDir = "RESTICUI_DATA_DIR"
EnvVarBindAddress = "RESTICUI_PORT"
EnvVarBinPath = "RESTICUI_RESTIC_BIN_PATH"
EnvVarConfigPath = "RESTORA_CONFIG" // path to config file
EnvVarDataDir = "RESTORA_DATA" // path to data directory
EnvVarBindAddress = "RESTORA_PORT" // port to bind to (default 9898)
EnvVarBinPath = "RESTORA_RESTIC_COMMAND" // path to restic binary (default restic)
)
// ConfigFilePath
// - *nix systems use $XDG_CONFIG_HOME/resticui/config.json
// - windows uses %APPDATA%/resticui/config.json
// - *nix systems use $XDG_CONFIG_HOME/restora/config.json
// - windows uses %APPDATA%/restora/config.json
func ConfigFilePath() string {
if val := os.Getenv(EnvVarConfigPath); val != "" {
return val
}
return path.Join(getConfigDir(), "resticui/config.json")
return path.Join(getConfigDir(), "restora/config.json")
}
// DataDir
// - *nix systems use $XDG_DATA_HOME/resticui
// - windows uses %APPDATA%/resticui/data
// - *nix systems use $XDG_DATA_HOME/restora
// - windows uses %APPDATA%/restora/data
func DataDir() string {
if val := os.Getenv(EnvVarDataDir); val != "" {
return val
}
if val := os.Getenv("XDG_DATA_HOME"); val != "" {
return path.Join(val, "resticui")
return path.Join(val, "restora")
}
if runtime.GOOS == "windows" {
return path.Join(getConfigDir(), "resticui/data")
return path.Join(getConfigDir(), "restora/data")
}
return path.Join(getHomeDir(), ".local/share/resticui")
return path.Join(getHomeDir(), ".local/share/restora")
}
func BindAddress() string {
@@ -53,7 +53,7 @@ func BindAddress() string {
}
func ResticBinPath() string {
if val := os.Getenv("RESTICUI_RESTIC_BIN_PATH"); val != "" {
if val := os.Getenv(EnvVarBinPath); val != "" {
return val
}
return ""
+1 -1
View File
@@ -8,7 +8,7 @@ import (
"path/filepath"
"sync"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/natefinch/atomic"
"google.golang.org/protobuf/encoding/protojson"
)
+2 -2
View File
@@ -3,7 +3,7 @@ package config
import (
"sync"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
v1 "github.com/garethgeorge/restora/gen/go/v1"
)
type MemoryStore struct {
@@ -24,4 +24,4 @@ func (c *MemoryStore) Update(config *v1.Config) error {
defer c.mu.Unlock()
c.Config = config
return nil
}
}
+1 -1
View File
@@ -6,7 +6,7 @@ import (
"regexp"
"strings"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/gitploy-io/cronexpr"
"github.com/hashicorp/go-multierror"
)
+1 -1
View File
@@ -4,7 +4,7 @@ import (
"bytes"
"sort"
"github.com/garethgeorge/resticui/internal/oplog/serializationutil"
"github.com/garethgeorge/restora/internal/oplog/serializationutil"
bolt "go.etcd.io/bbolt"
)
+5 -5
View File
@@ -9,11 +9,11 @@ import (
"sync/atomic"
"time"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/internal/oplog/indexutil"
"github.com/garethgeorge/resticui/internal/oplog/serializationutil"
"github.com/garethgeorge/resticui/internal/protoutil"
"github.com/garethgeorge/resticui/pkg/restic"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/garethgeorge/restora/internal/oplog/indexutil"
"github.com/garethgeorge/restora/internal/oplog/serializationutil"
"github.com/garethgeorge/restora/internal/protoutil"
"github.com/garethgeorge/restora/pkg/restic"
bolt "go.etcd.io/bbolt"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
+2 -2
View File
@@ -4,8 +4,8 @@ import (
"slices"
"testing"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/internal/oplog/indexutil"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/garethgeorge/restora/internal/oplog/indexutil"
)
const (
+4 -4
View File
@@ -8,10 +8,10 @@ import (
"sync"
"time"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/internal/config"
"github.com/garethgeorge/resticui/internal/oplog"
"github.com/garethgeorge/resticui/pkg/restic"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/garethgeorge/restora/internal/config"
"github.com/garethgeorge/restora/internal/oplog"
"github.com/garethgeorge/restora/pkg/restic"
"go.uber.org/zap"
"google.golang.org/protobuf/proto"
)
+2 -2
View File
@@ -6,8 +6,8 @@ import (
"testing"
"time"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/internal/config"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/garethgeorge/restora/internal/config"
)
type testTask struct {
+3 -6
View File
@@ -8,9 +8,9 @@ import (
"sync"
"time"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/internal/protoutil"
"github.com/garethgeorge/resticui/pkg/restic"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/garethgeorge/restora/internal/protoutil"
"github.com/garethgeorge/restora/pkg/restic"
"go.uber.org/zap"
)
@@ -89,9 +89,6 @@ func (r *RepoOrchestrator) Backup(ctx context.Context, plan *v1.Plan, progressCa
}
func (r *RepoOrchestrator) ListSnapshotFiles(ctx context.Context, snapshotId string, path string) ([]*v1.LsEntry, error) {
r.mu.Lock()
defer r.mu.Unlock()
_, entries, err := r.repo.ListDirectory(ctx, snapshotId, path)
if err != nil {
return nil, fmt.Errorf("failed to list snapshot files: %w", err)
+4 -4
View File
@@ -5,10 +5,10 @@ import (
"slices"
"testing"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/pkg/restic"
"github.com/garethgeorge/resticui/test/helpers"
test "github.com/garethgeorge/resticui/test/helpers"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/garethgeorge/restora/pkg/restic"
"github.com/garethgeorge/restora/test/helpers"
test "github.com/garethgeorge/restora/test/helpers"
)
func TestBackup(t *testing.T) {
@@ -9,7 +9,7 @@ import (
"testing"
"time"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
v1 "github.com/garethgeorge/restora/gen/go/v1"
)
type heapTestTask struct {
+3 -3
View File
@@ -5,9 +5,9 @@ import (
"fmt"
"time"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/internal/protoutil"
"github.com/garethgeorge/resticui/pkg/restic"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/garethgeorge/restora/internal/protoutil"
"github.com/garethgeorge/restora/pkg/restic"
"github.com/gitploy-io/cronexpr"
"go.uber.org/zap"
)
+2 -2
View File
@@ -6,8 +6,8 @@ import (
"fmt"
"time"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/internal/oplog/indexutil"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/garethgeorge/restora/internal/oplog/indexutil"
"github.com/hashicorp/go-multierror"
"go.uber.org/zap"
)
+4 -4
View File
@@ -5,10 +5,10 @@ import (
"fmt"
"time"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/internal/oplog"
"github.com/garethgeorge/resticui/internal/oplog/indexutil"
"github.com/garethgeorge/resticui/internal/protoutil"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/garethgeorge/restora/internal/oplog"
"github.com/garethgeorge/restora/internal/oplog/indexutil"
"github.com/garethgeorge/restora/internal/protoutil"
"go.uber.org/zap"
)
+2 -2
View File
@@ -7,8 +7,8 @@ import (
"sync"
"time"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/internal/oplog/indexutil"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/garethgeorge/restora/internal/oplog/indexutil"
"go.uber.org/zap"
)
+1 -1
View File
@@ -5,7 +5,7 @@ import (
"fmt"
"time"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"go.uber.org/zap"
)
+2 -2
View File
@@ -7,8 +7,8 @@ import (
"sync/atomic"
"time"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/internal/oplog"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/garethgeorge/restora/internal/oplog"
"github.com/hashicorp/go-multierror"
)
+2 -2
View File
@@ -1,8 +1,8 @@
package protoutil
import (
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/pkg/restic"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/garethgeorge/restora/pkg/restic"
)
func SnapshotToProto(s *restic.Snapshot) *v1.ResticSnapshot {
+4 -4
View File
@@ -3,8 +3,8 @@ package protoutil
import (
"testing"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/pkg/restic"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/garethgeorge/restora/pkg/restic"
"google.golang.org/protobuf/proto"
)
@@ -13,7 +13,7 @@ func TestSnapshotToProto(t *testing.T) {
Id: "db155169d788e6e432e320aedbdff5a54cc439653093bb56944a67682528aa52",
Time: "2023-11-10T19:14:17.053824063-08:00",
Tree: "3e2918b261948e69602ee9504b8f475bcc7cdc4dcec0b3f34ecdb014287d07b2",
Paths: []string{"/resticui"},
Paths: []string{"/restora"},
Hostname: "pop-os",
Username: "dontpanic",
Tags: []string{},
@@ -24,7 +24,7 @@ func TestSnapshotToProto(t *testing.T) {
Id: "db155169d788e6e432e320aedbdff5a54cc439653093bb56944a67682528aa52",
UnixTimeMs: 1699672457053,
Tree: "3e2918b261948e69602ee9504b8f475bcc7cdc4dcec0b3f34ecdb014287d07b2",
Paths: []string{"/resticui"},
Paths: []string{"/restora"},
Hostname: "pop-os",
Username: "dontpanic",
Tags: []string{},
+2 -2
View File
@@ -4,8 +4,8 @@ import (
"errors"
"fmt"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/pkg/restic"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/garethgeorge/restora/pkg/restic"
)
// ValidateOperation verifies critical properties of the operation proto.
+1 -1
View File
@@ -14,7 +14,7 @@ import (
"strings"
"sync"
"github.com/garethgeorge/resticui/internal/config"
"github.com/garethgeorge/restora/internal/config"
"go.uber.org/zap"
)
+18 -11
View File
@@ -5,10 +5,12 @@ import (
"os/exec"
)
const outputBufferLimit = 1000
type CmdError struct {
Command string
Err error
Output string
Err error
Output string
}
func (e *CmdError) Error() string {
@@ -28,18 +30,23 @@ func (e *CmdError) Is(target error) bool {
return ok
}
// NewCmdError creates a new error indicating that running a command failed.
func NewCmdError(cmd *exec.Cmd, output []byte, err error) *CmdError {
// newCmdError creates a new error indicating that running a command failed.
func newCmdError(cmd *exec.Cmd, output string, err error) *CmdError {
cerr := &CmdError{
Command: cmd.String(),
Err: err,
Err: err,
}
if len(output) > 0 {
if len(output) > 1000 {
output = output[:1000]
}
cerr.Output = string(output)
if len(output) >= outputBufferLimit {
cerr.Output = output[:outputBufferLimit] + "\n...[truncated]"
}
return cerr
}
}
func newCmdErrorPreformatted(cmd *exec.Cmd, output string, err error) *CmdError {
return &CmdError{
Command: cmd.String(),
Err: err,
}
}
+86
View File
@@ -0,0 +1,86 @@
package restic
import (
"fmt"
"io"
)
// headWriter keeps the first 'limit' bytes in memory.
type headWriter struct {
buf []byte
limit int
}
var _ io.Writer = &headWriter{}
func (w *headWriter) Write(p []byte) (n int, err error) {
if len(w.buf) >= w.limit {
return len(p), nil
}
w.buf = append(w.buf, p...)
if len(w.buf) > w.limit {
w.buf = w.buf[:w.limit]
}
return len(p), nil
}
func (w *headWriter) Bytes() []byte {
return w.buf
}
// tailWriter keeps the last 'limit' bytes in memory.
type tailWriter struct {
buf []byte
limit int
}
var _ io.Writer = &tailWriter{}
func (w *tailWriter) Write(p []byte) (n int, err error) {
w.buf = append(w.buf, p...)
if len(w.buf) > w.limit {
w.buf = w.buf[len(w.buf)-w.limit:]
}
return len(p), nil
}
func (w *tailWriter) Bytes() []byte {
return w.buf
}
type outputCapturer struct {
headWriter
tailWriter
limit int
totalBytes int
}
var _ io.Writer = &outputCapturer{}
func newOutputCapturer(limit int) *outputCapturer {
return &outputCapturer{
headWriter: headWriter{limit: limit},
tailWriter: tailWriter{limit: limit},
limit: limit,
}
}
func (w *outputCapturer) Write(p []byte) (n int, err error) {
w.headWriter.Write(p)
w.tailWriter.Write(p)
w.totalBytes += len(p)
return len(p), nil
}
func (w *outputCapturer) String() string {
head := w.headWriter.Bytes()
tail := w.tailWriter.Bytes()
if w.totalBytes <= w.limit {
return string(head)
}
head = head[:w.limit/2]
tail = tail[len(tail)-w.limit/2:]
return fmt.Sprintf("%s...[%v bytes dropped]...%s", string(head), w.totalBytes-len(head)-len(tail), string(tail))
}
+24
View File
@@ -0,0 +1,24 @@
package restic
import "testing"
func TestOutputCapture(t *testing.T) {
c := newOutputCapturer(100)
c.Write([]byte("hello"))
if c.String() != "hello" {
t.Errorf("expected 'hello', got '%s'", c.String())
}
}
func TestOutputCaptureDrops(t *testing.T) {
c := newOutputCapturer(2)
c.Write([]byte("hello"))
want := "h...[3 bytes dropped]...o"
if c.String() != want {
t.Errorf("expected '%s', got '%s'", want, c.String())
}
}
-34
View File
@@ -1,34 +0,0 @@
package restic
import "io"
// limitWriter silently stops writing after 'limit' bytes.
type limitWriter struct {
written int64
limit int64
w io.Writer
}
var _ io.Writer = &limitWriter{}
func (w *limitWriter) Write(p []byte) (n int, err error) {
r := len(p)
if w.written >= w.limit {
return r, nil
}
if w.written+int64(len(p)) > w.limit {
p = p[:w.limit-w.written]
}
n, err = w.w.Write(p)
w.written += int64(n)
return r, err
}
func newLimitWriter(w io.Writer, limit int64) io.Writer {
return &limitWriter{
w: w,
limit: limit,
}
}
+7 -5
View File
@@ -10,7 +10,7 @@ import (
"slices"
"time"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
v1 "github.com/garethgeorge/restora/gen/go/v1"
)
type Snapshot struct {
@@ -105,7 +105,7 @@ func readBackupProgressEntries(cmd *exec.Cmd, output io.Reader, callback func(ev
bytes = append(bytes, scanner.Bytes()...)
}
return nil, NewCmdError(cmd, bytes, fmt.Errorf("command output was not JSON: %w", err))
return nil, newCmdError(cmd, string(bytes), fmt.Errorf("command output was not JSON: %w", err))
}
if err := event.Validate(); err != nil {
return nil, err
@@ -254,7 +254,7 @@ func readRestoreProgressEntries(cmd *exec.Cmd, output io.Reader, callback func(e
bytes = append(bytes, scanner.Bytes()...)
}
return nil, NewCmdError(cmd, bytes, fmt.Errorf("command output was not JSON: %w", err))
return nil, newCmdError(cmd, string(bytes), fmt.Errorf("command output was not JSON: %w", err))
}
if err := event.Validate(); err != nil {
return nil, err
@@ -271,10 +271,12 @@ func readRestoreProgressEntries(cmd *exec.Cmd, output io.Reader, callback func(e
for scanner.Scan() {
var event RestoreProgressEntry
if err := json.Unmarshal(scanner.Bytes(), &event); err != nil {
return nil, fmt.Errorf("failed to parse JSON: %w", err)
// skip it. Best effort parsing, restic will return with a non-zero exit code if it fails.
continue
}
if err := event.Validate(); err != nil {
return nil, err
// skip it. Best effort parsing, restic will return with a non-zero exit code if it fails.
continue
}
if callback != nil {
+1 -1
View File
@@ -28,7 +28,7 @@ func TestReadBackupProgressEntries(t *testing.T) {
}
func TestReadLs(t *testing.T) {
testInput := `{"time":"2023-11-10T19:14:17.053824063-08:00","tree":"3e2918b261948e69602ee9504b8f475bcc7cdc4dcec0b3f34ecdb014287d07b2","paths":["/resticui"],"hostname":"pop-os","username":"dontpanic","uid":1000,"gid":1000,"id":"db155169d788e6e432e320aedbdff5a54cc439653093bb56944a67682528aa52","short_id":"db155169","struct_type":"snapshot"}
testInput := `{"time":"2023-11-10T19:14:17.053824063-08:00","tree":"3e2918b261948e69602ee9504b8f475bcc7cdc4dcec0b3f34ecdb014287d07b2","paths":["/restora"],"hostname":"pop-os","username":"dontpanic","uid":1000,"gid":1000,"id":"db155169d788e6e432e320aedbdff5a54cc439653093bb56944a67682528aa52","short_id":"db155169","struct_type":"snapshot"}
{"name":".git","type":"dir","path":"/.git","uid":1000,"gid":1000,"mode":2147484157,"mtime":"2023-11-10T18:32:38.156599473-08:00","atime":"2023-11-10T18:32:38.156599473-08:00","ctime":"2023-11-10T18:32:38.156599473-08:00","struct_type":"node"}
{"name":".gitignore","type":"file","path":"/.gitignore","uid":1000,"gid":1000,"size":22,"mode":436,"mtime":"2023-11-10T00:41:26.611346634-08:00","atime":"2023-11-10T00:41:26.611346634-08:00","ctime":"2023-11-10T00:41:26.611346634-08:00","struct_type":"node"}
{"name":"README.md","type":"file","path":"/README.md","uid":1000,"gid":1000,"size":762,"mode":436,"mtime":"2023-11-10T00:59:06.842538768-08:00","atime":"2023-11-10T00:59:06.842538768-08:00","ctime":"2023-11-10T00:59:06.842538768-08:00","struct_type":"node"}`
+22 -47
View File
@@ -12,13 +12,11 @@ import (
"strings"
"sync"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
v1 "github.com/garethgeorge/restora/gen/go/v1"
)
var errAlreadyInitialized = errors.New("repo already initialized")
const outputBufferLimit = 1000
type Repo struct {
mu sync.Mutex
cmd string
@@ -71,7 +69,7 @@ func (r *Repo) init(ctx context.Context) error {
if strings.Contains(string(output), "config file already exists") || strings.Contains(string(output), "already initialized") {
return errAlreadyInitialized
}
return NewCmdError(cmd, output, err)
return newCmdError(cmd, string(output), err)
}
r.initialized = true
@@ -79,8 +77,6 @@ func (r *Repo) init(ctx context.Context) error {
}
func (r *Repo) Init(ctx context.Context) error {
r.mu.Lock()
defer r.mu.Unlock()
if err := r.init(ctx); err != nil && !errors.Is(err, errAlreadyInitialized) {
return fmt.Errorf("init failed: %w", err)
}
@@ -88,9 +84,6 @@ func (r *Repo) Init(ctx context.Context) error {
}
func (r *Repo) Backup(ctx context.Context, progressCallback func(*BackupProgressEntry), opts ...BackupOption) (*BackupProgressEntry, error) {
r.mu.Lock()
defer r.mu.Unlock()
opt := &BackupOpts{}
for _, o := range opts {
o(opt)
@@ -107,9 +100,9 @@ func (r *Repo) Backup(ctx context.Context, progressCallback func(*BackupProgress
args = append(args, opt.paths...)
args = append(args, opt.extraArgs...)
output := bytes.NewBuffer(nil)
output := newOutputCapturer(outputBufferLimit)
reader, writer := io.Pipe()
capture := io.MultiWriter(newLimitWriter(output, outputBufferLimit), writer)
capture := io.MultiWriter(output, writer)
cmd := exec.CommandContext(ctx, r.cmd, args...)
cmd.Env = append(cmd.Env, r.buildEnv()...)
@@ -117,7 +110,7 @@ func (r *Repo) Backup(ctx context.Context, progressCallback func(*BackupProgress
cmd.Stdout = capture
if err := cmd.Start(); err != nil {
return nil, NewCmdError(cmd, nil, err)
return nil, newCmdError(cmd, "", err)
}
var wg sync.WaitGroup
@@ -147,16 +140,13 @@ func (r *Repo) Backup(ctx context.Context, progressCallback func(*BackupProgress
wg.Wait()
if cmdErr != nil || readErr != nil {
return nil, NewCmdError(cmd, output.Bytes(), errors.Join(cmdErr, readErr))
return nil, newCmdErrorPreformatted(cmd, output.String(), errors.Join(cmdErr, readErr))
}
return summary, nil
}
func (r *Repo) Snapshots(ctx context.Context, opts ...GenericOption) ([]*Snapshot, error) {
r.mu.Lock()
defer r.mu.Unlock()
opt := resolveOpts(opts)
args := []string{"snapshots", "--json"}
@@ -169,12 +159,12 @@ func (r *Repo) Snapshots(ctx context.Context, opts ...GenericOption) ([]*Snapsho
output, err := cmd.CombinedOutput()
if err != nil {
return nil, NewCmdError(cmd, output, err)
return nil, newCmdError(cmd, "", err)
}
var snapshots []*Snapshot
if err := json.Unmarshal(output, &snapshots); err != nil {
return nil, NewCmdError(cmd, output, fmt.Errorf("command output is not valid JSON: %w", err))
return nil, newCmdError(cmd, "", fmt.Errorf("command output is not valid JSON: %w", err))
}
for _, snapshot := range snapshots {
if err := snapshot.Validate(); err != nil {
@@ -185,9 +175,6 @@ func (r *Repo) Snapshots(ctx context.Context, opts ...GenericOption) ([]*Snapsho
}
func (r *Repo) Forget(ctx context.Context, policy *RetentionPolicy, opts ...GenericOption) (*ForgetResult, error) {
r.mu.Lock()
defer r.mu.Unlock()
// first run the forget command
opt := resolveOpts(opts)
@@ -202,27 +189,24 @@ func (r *Repo) Forget(ctx context.Context, policy *RetentionPolicy, opts ...Gene
output, err := cmd.CombinedOutput()
if err != nil {
return nil, NewCmdError(cmd, output, err)
return nil, newCmdError(cmd, string(output), err)
}
var result []ForgetResult
if err := json.Unmarshal(output, &result); err != nil {
return nil, NewCmdError(cmd, output, fmt.Errorf("command output is not valid JSON: %w", err))
return nil, newCmdError(cmd, string(output), fmt.Errorf("command output is not valid JSON: %w", err))
}
if len(result) != 1 {
return nil, fmt.Errorf("expected 1 output from forget, got %v", len(result))
}
if err := result[0].Validate(); err != nil {
return nil, NewCmdError(cmd, output, fmt.Errorf("invalid forget result: %w", err))
return nil, newCmdError(cmd, string(output), fmt.Errorf("invalid forget result: %w", err))
}
return &result[0], nil
}
func (r *Repo) Prune(ctx context.Context, pruneOutput io.Writer, opts ...GenericOption) error {
r.mu.Lock()
defer r.mu.Unlock()
opt := resolveOpts(opts)
args := []string{"prune"}
@@ -233,10 +217,10 @@ func (r *Repo) Prune(ctx context.Context, pruneOutput io.Writer, opts ...Generic
cmd.Env = append(cmd.Env, r.buildEnv()...)
cmd.Env = append(cmd.Env, opt.extraEnv...)
buf := bytes.NewBuffer(nil)
var writer io.Writer = newLimitWriter(buf, outputBufferLimit)
var output = newOutputCapturer(outputBufferLimit)
var writer io.Writer = output
if pruneOutput != nil {
writer = io.MultiWriter(pruneOutput, buf)
writer = io.MultiWriter(pruneOutput, output)
}
cmd.Stdout = writer
cmd.Stderr = writer
@@ -244,25 +228,22 @@ func (r *Repo) Prune(ctx context.Context, pruneOutput io.Writer, opts ...Generic
writer.Write([]byte("command: " + strings.Join(cmd.Args, " ") + "\n"))
if err := cmd.Run(); err != nil {
return NewCmdError(cmd, buf.Bytes(), err)
return newCmdErrorPreformatted(cmd, output.String(), err)
}
return nil
}
func (r *Repo) Restore(ctx context.Context, snapshot string, callback func(*RestoreProgressEntry), opts ...GenericOption) (*RestoreProgressEntry, error) {
r.mu.Lock()
defer r.mu.Unlock()
opt := resolveOpts(opts)
args := []string{"restore", snapshot, "--json"}
args = append(args, r.extraArgs...)
args = append(args, opt.extraArgs...)
output := bytes.NewBuffer(nil)
output := newOutputCapturer(outputBufferLimit)
reader, writer := io.Pipe()
capture := io.MultiWriter(newLimitWriter(output, 1000), writer)
capture := io.MultiWriter(output, writer)
cmd := exec.CommandContext(ctx, r.cmd, args...)
cmd.Env = append(cmd.Env, r.buildEnv()...)
@@ -271,7 +252,7 @@ func (r *Repo) Restore(ctx context.Context, snapshot string, callback func(*Rest
cmd.Stdout = capture
if err := cmd.Start(); err != nil {
return nil, NewCmdError(cmd, nil, err)
return nil, newCmdError(cmd, "", err)
}
var wg sync.WaitGroup
@@ -301,16 +282,13 @@ func (r *Repo) Restore(ctx context.Context, snapshot string, callback func(*Rest
wg.Wait()
if cmdErr != nil || readErr != nil {
return nil, NewCmdError(cmd, output.Bytes(), errors.Join(cmdErr, readErr))
return nil, newCmdError(cmd, output.String(), errors.Join(cmdErr, readErr))
}
return summary, nil
}
func (r *Repo) ListDirectory(ctx context.Context, snapshot string, path string, opts ...GenericOption) (*Snapshot, []*LsEntry, error) {
r.mu.Lock()
defer r.mu.Unlock()
if path == "" {
// an empty path can trigger very expensive operations (e.g. iterates all files in the snapshot)
return nil, nil, errors.New("path must not be empty")
@@ -328,21 +306,18 @@ func (r *Repo) ListDirectory(ctx context.Context, snapshot string, path string,
output, err := cmd.CombinedOutput()
if err != nil {
return nil, nil, NewCmdError(cmd, output, err)
return nil, nil, newCmdError(cmd, string(output), err)
}
snapshots, entries, err := readLs(bytes.NewBuffer(output))
if err != nil {
return nil, nil, NewCmdError(cmd, output, err)
return nil, nil, newCmdError(cmd, string(output), err)
}
return snapshots, entries, nil
}
func (r *Repo) Unlock(ctx context.Context, opts ...GenericOption) error {
r.mu.Lock()
defer r.mu.Unlock()
opt := resolveOpts(opts)
args := []string{"unlock"}
@@ -355,7 +330,7 @@ func (r *Repo) Unlock(ctx context.Context, opts ...GenericOption) error {
output, err := cmd.CombinedOutput()
if err != nil {
return NewCmdError(cmd, output, err)
return newCmdError(cmd, string(output), err)
}
return nil
+8 -2
View File
@@ -8,8 +8,8 @@ import (
"slices"
"testing"
v1 "github.com/garethgeorge/resticui/gen/go/v1"
"github.com/garethgeorge/resticui/test/helpers"
v1 "github.com/garethgeorge/restora/gen/go/v1"
"github.com/garethgeorge/restora/test/helpers"
)
func TestResticInit(t *testing.T) {
@@ -79,8 +79,10 @@ func TestResticBackup(t *testing.T) {
for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
gotEvent := false
summary, err := r.Backup(context.Background(), func(event *BackupProgressEntry) {
t.Logf("backup event: %v", event)
gotEvent = true
}, tc.opts...)
if (err != nil) != tc.wantErr {
t.Fatalf("wanted error: %v, got: %v", tc.wantErr, err)
@@ -97,6 +99,10 @@ func TestResticBackup(t *testing.T) {
if summary.TotalFilesProcessed != tc.files {
t.Errorf("wanted %d files, got: %d", tc.files, summary.TotalFilesProcessed)
}
if !gotEvent {
t.Errorf("wanted backup event, got: false")
}
})
}
}
+1 -1
View File
@@ -2,7 +2,7 @@ syntax = "proto3";
package types;
option go_package = "github.com/garethgeorge/resticui/gen/go/types";
option go_package = "github.com/garethgeorge/restora/gen/go/types";
message StringValue {
string value = 1;
+1 -1
View File
@@ -2,7 +2,7 @@ syntax = "proto3";
package v1;
option go_package = "github.com/garethgeorge/resticui/go/proto/v1";
option go_package = "github.com/garethgeorge/restora/go/proto/v1";
// Config is the top level config object for restic UI.
message Config {
+2 -2
View File
@@ -2,7 +2,7 @@ syntax = "proto3";
package v1;
option go_package = "github.com/garethgeorge/resticui/go/proto/v1";
option go_package = "github.com/garethgeorge/restora/go/proto/v1";
import "v1/restic.proto";
import "v1/config.proto";
@@ -64,7 +64,7 @@ message OperationBackup {
BackupProgressEntry last_status = 3;
}
// OperationIndexSnapshot tracks that a snapshot was detected by resticui.
// OperationIndexSnapshot tracks that a snapshot was detected by restora.
message OperationIndexSnapshot {
ResticSnapshot snapshot = 2; // the snapshot that was indexed.
bool forgot = 3; // tracks whether this snapshot is forgotten yet.
+1 -1
View File
@@ -2,7 +2,7 @@ syntax = "proto3";
package v1;
option go_package = "github.com/garethgeorge/resticui/go/proto/v1";
option go_package = "github.com/garethgeorge/restora/go/proto/v1";
// ResticSnapshot represents a restic snapshot.
message ResticSnapshot {
+2 -2
View File
@@ -2,7 +2,7 @@ syntax = "proto3";
package v1;
option go_package = "github.com/garethgeorge/resticui/go/proto/v1";
option go_package = "github.com/garethgeorge/restora/go/proto/v1";
import "v1/config.proto";
import "v1/restic.proto";
@@ -11,7 +11,7 @@ import "types/value.proto";
import "google/protobuf/empty.proto";
import "google/api/annotations.proto";
service ResticUI {
service Restora {
rpc GetConfig (google.protobuf.Empty) returns (Config) {
option (google.api.http) = {
get: "/v1/config"
+6 -13
View File
@@ -13,11 +13,11 @@ import (
"syscall"
rice "github.com/GeertJohan/go.rice"
"github.com/garethgeorge/resticui/internal/api"
"github.com/garethgeorge/resticui/internal/config"
"github.com/garethgeorge/resticui/internal/oplog"
"github.com/garethgeorge/resticui/internal/orchestrator"
"github.com/garethgeorge/resticui/internal/resticinstaller"
"github.com/garethgeorge/restora/internal/api"
"github.com/garethgeorge/restora/internal/config"
"github.com/garethgeorge/restora/internal/oplog"
"github.com/garethgeorge/restora/internal/orchestrator"
"github.com/garethgeorge/restora/internal/resticinstaller"
"github.com/mattn/go-colorable"
"go.etcd.io/bbolt"
"go.uber.org/zap"
@@ -25,7 +25,7 @@ import (
)
var (
installOnly = flag.Bool("install-deps", false, "Install resticui and exit")
installOnly = flag.Bool("install-deps", false, "Install restora and exit")
)
func main() {
@@ -149,10 +149,3 @@ func onterm(callback func()) {
<-sigchan
callback()
}
func findResticBin() {
resticBin := config.ResticBinPath()
if resticBin != "" {
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 120 KiB

+6 -6
View File
@@ -2,17 +2,17 @@
(cd webui && npm i && npm run build)
for bin in resticui-*; do
for bin in restora-*; do
rm -f $bin
done
find webui/dist -name '*.map' -exec rm ./{} \;
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o resticui-linux-amd64
GOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -o resticui-linux-arm64
GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w" -o resticui-darwin-amd64
GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w" -o resticui-darwin-arm64
GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o restora-linux-amd64
GOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -o restora-linux-arm64
GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w" -o restora-darwin-amd64
GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w" -o restora-darwin-arm64
for bin in resticui-*; do
for bin in restora-*; do
rice append --exec $bin
done
+2 -2
View File
@@ -2,6 +2,6 @@
set -x
(cd webui && npm i && npm run build)
rm -f resticui
rm -f restora
go build .
rice append --exec resticui
rice append --exec restora
+1 -1
View File
@@ -3,7 +3,7 @@ package helpers
import (
"testing"
"github.com/garethgeorge/resticui/internal/resticinstaller"
"github.com/garethgeorge/restora/internal/resticinstaller"
)
func ResticBinary(t *testing.T) string {
+1 -1
View File
@@ -55,7 +55,7 @@ export type LsEntry = {
ctime?: string
}
export class ResticUI {
export class Restora {
static GetConfig(req: GoogleProtobufEmpty.Empty, initReq?: fm.InitReq): Promise<V1Config.Config> {
return fm.fetchReq<GoogleProtobufEmpty.Empty, V1Config.Config>(`/v1/config?${fm.renderURLSearchParams(req, [])}`, {...initReq, method: "GET"})
}
+2 -2
View File
@@ -1,11 +1,11 @@
{
"name": "resticui",
"name": "restora",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "resticui",
"name": "restora",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
+2 -2
View File
@@ -1,10 +1,10 @@
{
"name": "resticui",
"name": "restora",
"version": "1.0.0",
"description": "",
"scripts": {
"start": "parcel serve src/index.html",
"build": "RESTICUI_BUILD_VERSION=$(git describe --tags --abbrev=0) UI_OS=unix parcel build src/index.html",
"build": "RESTORA_BUILD_VERSION=$(git describe --tags --abbrev=0) UI_OS=unix parcel build src/index.html",
"build-windows": "set UI_OS=windows & parcel build src/index.html",
"test": "echo \"Error: no test specified\" && exit 1"
},
+1 -1
View File
@@ -179,7 +179,7 @@ export const OperationRow = ({
const title = (
<>
{formatTime(operation.unixTimeStartMs!)} - {opName}{" "}
<span className="resticui operation-details">{details.displayState}</span>
<span className="restora operation-details">{details.displayState}</span>
</>
);
+1 -1
View File
@@ -173,7 +173,7 @@ export const OperationTree = ({
let detailsElem: React.ReactNode | null = null;
if (details.length > 0) {
detailsElem = (
<span className="resticui operation-details">
<span className="restora operation-details">
[{details.join(", ")}]
</span>
);
+5 -5
View File
@@ -4,7 +4,7 @@ import type { DataNode, EventDataNode } from "antd/es/tree";
import {
ListSnapshotFilesResponse,
LsEntry,
ResticUI,
Restora,
RestoreSnapshotRequest,
} from "../../gen/ts/v1/service.pb";
import { useAlertApi } from "./Alerts";
@@ -81,7 +81,7 @@ export const SnapshotBrowser = ({
useEffect(() => {
(async () => {
try {
const resp = await ResticUI.ListSnapshotFiles(
const resp = await Restora.ListSnapshotFiles(
{
path: "/",
repoId,
@@ -101,7 +101,7 @@ export const SnapshotBrowser = ({
return;
}
const resp = await ResticUI.ListSnapshotFiles(
const resp = await Restora.ListSnapshotFiles(
{
path: (key + "/") as string,
repoId,
@@ -221,7 +221,7 @@ const FileNode = ({ entry }: { entry: LsEntry }) => {
<Space onMouseEnter={showDropdown} onMouseLeave={() => setDropdown(null)}>
{entry.name}
{entry.type === "file" ? (
<span className="resticui file-details">
<span className="restora file-details">
({formatBytes(entry.size)})
</span>
) : null}
@@ -263,7 +263,7 @@ const RestoreModal = ({
try {
const values = await validateForm(form);
await ResticUI.Restore(
await Restora.Restore(
{
planId,
repoId,
+2 -2
View File
@@ -1,6 +1,6 @@
import { AutoComplete } from "antd";
import React, { useEffect, useState } from "react";
import { ResticUI } from "../../gen/ts/v1/service.pb";
import { Restora } from "../../gen/ts/v1/service.pb";
import { StringList } from "../../gen/ts/types/value.pb";
import { isWindows } from "../state/buildcfg";
@@ -29,7 +29,7 @@ export const URIAutocomplete = (props: React.PropsWithChildren<any>) => {
}
timeout = setTimeout(() => {
ResticUI.PathAutocomplete({ value: value + sep }, { pathPrefix: "/api" })
Restora.PathAutocomplete({ value: value + sep }, { pathPrefix: "/api" })
.then((res: StringList) => {
if (!res.values) {
return;
+1 -1
View File
@@ -1,7 +1,7 @@
<!DOCTYPE html>
<html>
<head>
<title>ResticUI</title>
<title>Restora</title>
<link rel="stylesheet" href="index.sass" />
</head>
<body>
+1 -1
View File
@@ -1,7 +1,7 @@
body
margin: 0px
.resticui
.restora
&.operation-details
color: grey
font-family: monospace
+1 -1
View File
@@ -1,5 +1,5 @@
export const uios = (process.env.UI_OS || "").trim().toLowerCase();
export const isWindows = uios === "windows";
export const uiBuildVersion = (
process.env.RESTICUI_BUILD_VERSION || "dev-snapshot-build"
process.env.RESTORA_BUILD_VERSION || "dev-snapshot-build"
).trim();
+4 -4
View File
@@ -1,6 +1,6 @@
import { atom, useSetRecoilState } from "recoil";
import { Config, Repo } from "../../gen/ts/v1/config.pb";
import { ResticUI } from "../../gen/ts/v1/service.pb";
import { Restora } from "../../gen/ts/v1/service.pb";
import { API_PREFIX } from "../constants";
export const configState = atom<Config>({
@@ -9,17 +9,17 @@ export const configState = atom<Config>({
});
export const fetchConfig = async (): Promise<Config> => {
return await ResticUI.GetConfig({}, { pathPrefix: API_PREFIX });
return await Restora.GetConfig({}, { pathPrefix: API_PREFIX });
};
export const addRepo = async (repo: Repo): Promise<Config> => {
return await ResticUI.AddRepo(repo, {
return await Restora.AddRepo(repo, {
pathPrefix: API_PREFIX,
});
};
export const updateConfig = async (config: Config): Promise<Config> => {
return await ResticUI.SetConfig(config, {
return await Restora.SetConfig(config, {
pathPrefix: API_PREFIX,
});
};
+4 -4
View File
@@ -4,7 +4,7 @@ import {
OperationEventType,
OperationStatus,
} from "../../gen/ts/v1/operations.pb";
import { GetOperationsRequest, ResticUI } from "../../gen/ts/v1/service.pb";
import { GetOperationsRequest, Restora } from "../../gen/ts/v1/service.pb";
import { API_PREFIX } from "../constants";
import { BackupProgressEntry, ResticSnapshot } from "../../gen/ts/v1/restic.pb";
import _ from "lodash";
@@ -22,7 +22,7 @@ const subscribers: ((event: OperationEvent) => void)[] = [];
while (true) {
let nextConnWaitUntil = new Date().getTime() + 5000;
try {
await ResticUI.GetOperationEvents(
await Restora.GetOperationEvents(
{},
(event: OperationEvent) => {
console.log("operation event", event);
@@ -44,7 +44,7 @@ const subscribers: ((event: OperationEvent) => void)[] = [];
export const getOperations = async (
req: GetOperationsRequest
): Promise<EOperation[]> => {
const opList = await ResticUI.GetOperations(req, {
const opList = await Restora.GetOperations(req, {
pathPrefix: API_PREFIX,
});
return (opList.operations || []).map(toEop);
@@ -125,7 +125,7 @@ export class BackupInfoCollector {
(o) => o.id!
);
existing.operations.sort((a, b) => {
return parseInt(a.unixTimeStartMs!) - parseInt(b.unixTimeStartMs!);
return parseInt(b.unixTimeStartMs!) - parseInt(a.unixTimeStartMs!);
});
if (newInfo.backupLastStatus) {
existing.backupLastStatus = newInfo.backupLastStatus;
+3 -3
View File
@@ -15,7 +15,7 @@ import { Repo } from "../../gen/ts/v1/config.pb";
import { URIAutocomplete } from "../components/URIAutocomplete";
import { MinusCircleOutlined, PlusOutlined } from "@ant-design/icons";
import { useAlertApi } from "../components/Alerts";
import { ResticUI } from "../../gen/ts/v1/service.pb";
import { Restora } from "../../gen/ts/v1/service.pb";
import {
addRepo,
configState,
@@ -110,7 +110,7 @@ export const AddRepoModal = ({
// Update the snapshots for the repo to confirm the config works.
// TODO: this operation is only used here, find a different RPC for this purpose.
await ResticUI.ListSnapshots(
await Restora.ListSnapshots(
{
repoId: repo.id,
},
@@ -349,7 +349,7 @@ export const AddRepoModal = ({
</Form.List>
{/* Repo.flags */}
<Form.List name="flags" initialValue={[]}>
<Form.List name="flags" initialValue={template ? template.flags : []}>
{(fields, { add, remove }, { errors }) => (
<>
{fields.map((field, index) => (
+1 -1
View File
@@ -109,7 +109,7 @@ const getSidenavItems = (config: Config | null): MenuProps["items"] => {
key: "p-" + plan.id,
icon: <CheckCircleOutlined style={{ color: "green" }} />,
label: (
<div className="resticui visible-on-hover">
<div className="restora visible-on-hover">
{plan.id}{" "}
<Button
className="hidden-child"
+5 -5
View File
@@ -32,11 +32,11 @@ export const GettingStartedGuide = () => {
<Divider orientation="left">Tips</Divider>
<ul>
<li>
Backup your ResticUI configuration: your ResticUI config holds all
of your repos, plans, and the passwords to decrypt them. When you
have ResticUI configured to your liking make sure to store a copy of
your config (or minimally a copy of your passwords) in a safe
location e.g. a secure note in your password manager.
Backup your Restora configuration: your Restora config holds all of
your repos, plans, and the passwords to decrypt them. When you have
Restora configured to your liking make sure to store a copy of your
config (or minimally a copy of your passwords) in a safe location
e.g. a secure note in your password manager.
</li>
</ul>
<Divider orientation="left">Config View</Divider>
+4 -4
View File
@@ -5,7 +5,7 @@ import { useShowModal } from "../components/ModalManager";
import { useRecoilValue } from "recoil";
import { configState } from "../state/config";
import { useAlertApi } from "../components/Alerts";
import { ResticUI } from "../../gen/ts/v1/service.pb";
import { Restora } from "../../gen/ts/v1/service.pb";
import {
EOperation,
subscribeToOperations,
@@ -29,7 +29,7 @@ export const PlanView = ({ plan }: React.PropsWithChildren<{ plan: Plan }>) => {
const handleBackupNow = async () => {
try {
ResticUI.Backup({ value: plan.id }, { pathPrefix: "/api" });
Restora.Backup({ value: plan.id }, { pathPrefix: "/api" });
alertsApi.success("Backup scheduled.");
} catch (e: any) {
alertsApi.error("Failed to schedule backup: " + e.message);
@@ -38,7 +38,7 @@ export const PlanView = ({ plan }: React.PropsWithChildren<{ plan: Plan }>) => {
const handlePruneNow = () => {
try {
ResticUI.Prune({ value: plan.id }, { pathPrefix: "/api" });
Restora.Prune({ value: plan.id }, { pathPrefix: "/api" });
alertsApi.success("Prune scheduled.");
} catch (e: any) {
alertsApi.error("Failed to schedule prune: " + e.message);
@@ -48,7 +48,7 @@ export const PlanView = ({ plan }: React.PropsWithChildren<{ plan: Plan }>) => {
const handleUnlockNow = () => {
try {
alertsApi.info("Unlocking repo...");
ResticUI.Unlock({ value: plan.repo! }, { pathPrefix: "/api" });
Restora.Unlock({ value: plan.repo! }, { pathPrefix: "/api" });
alertsApi.success("Repo unlocked.");
} catch (e: any) {
alertsApi.error("Failed to unlock repo: " + e.message);