diff --git a/client-gui2 b/client-gui2 index 412a577e..45677dc5 160000 --- a/client-gui2 +++ b/client-gui2 @@ -1 +1 @@ -Subproject commit 412a577e47d64c1b220aef061da983268ee48dc6 +Subproject commit 45677dc55a11b1889663c2566239c44df951b694 diff --git a/common/proto/backup.proto b/common/proto/backup.proto index 9673ba2d..9d8c0651 100644 --- a/common/proto/backup.proto +++ b/common/proto/backup.proto @@ -12,6 +12,8 @@ service BackupService { rpc ListDatabases(komp_ac.common.Empty) returns (ListDatabasesResponse); rpc CreateDatabase(CreateDatabaseRequest) returns (DatabaseInfo); rpc RunDatabaseMigrations(DatabaseRequest) returns (DatabaseInfo); + rpc ListDatabaseDumps(komp_ac.common.Empty) returns (ListDatabaseDumpsResponse); + rpc RestoreDatabase(RestoreDatabaseRequest) returns (DatabaseInfo); } message DatabaseRequest { @@ -22,6 +24,21 @@ message CreateDatabaseRequest { string database_name = 1; } +message RestoreDatabaseRequest { + string database_name = 1; + string dump_file_name = 2; +} + +message DatabaseDumpInfo { + string file_name = 1; + int64 size_bytes = 2; + int64 modified_at_unix_seconds = 3; +} + +message ListDatabaseDumpsResponse { + repeated DatabaseDumpInfo dumps = 1; +} + message DatabaseInfo { string database_name = 1; bool active = 2; @@ -32,6 +49,7 @@ message DatabaseInfo { bool migration_dirty = 7; bool application_database = 8; string status = 9; + bool empty = 10; } message ListDatabasesResponse { diff --git a/common/src/proto/descriptor.bin b/common/src/proto/descriptor.bin index b1d04d2a..1970654a 100644 Binary files a/common/src/proto/descriptor.bin and b/common/src/proto/descriptor.bin differ diff --git a/common/src/proto/komp_ac.backup.rs b/common/src/proto/komp_ac.backup.rs index dab16035..16f36faf 100644 --- a/common/src/proto/komp_ac.backup.rs +++ b/common/src/proto/komp_ac.backup.rs @@ -10,6 +10,27 @@ pub struct CreateDatabaseRequest { pub database_name: ::prost::alloc::string::String, } #[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct RestoreDatabaseRequest { + #[prost(string, tag = "1")] + pub database_name: ::prost::alloc::string::String, + #[prost(string, tag = "2")] + pub dump_file_name: ::prost::alloc::string::String, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] +pub struct DatabaseDumpInfo { + #[prost(string, tag = "1")] + pub file_name: ::prost::alloc::string::String, + #[prost(int64, tag = "2")] + pub size_bytes: i64, + #[prost(int64, tag = "3")] + pub modified_at_unix_seconds: i64, +} +#[derive(Clone, PartialEq, ::prost::Message)] +pub struct ListDatabaseDumpsResponse { + #[prost(message, repeated, tag = "1")] + pub dumps: ::prost::alloc::vec::Vec, +} +#[derive(Clone, PartialEq, Eq, Hash, ::prost::Message)] pub struct DatabaseInfo { #[prost(string, tag = "1")] pub database_name: ::prost::alloc::string::String, @@ -29,6 +50,8 @@ pub struct DatabaseInfo { pub application_database: bool, #[prost(string, tag = "9")] pub status: ::prost::alloc::string::String, + #[prost(bool, tag = "10")] + pub empty: bool, } #[derive(Clone, PartialEq, ::prost::Message)] pub struct ListDatabasesResponse { @@ -475,6 +498,55 @@ pub mod backup_service_client { ); self.inner.unary(req, path, codec).await } + pub async fn list_database_dumps( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + > { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/komp_ac.backup.BackupService/ListDatabaseDumps", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("komp_ac.backup.BackupService", "ListDatabaseDumps"), + ); + self.inner.unary(req, path, codec).await + } + pub async fn restore_database( + &mut self, + request: impl tonic::IntoRequest, + ) -> std::result::Result, tonic::Status> { + self.inner + .ready() + .await + .map_err(|e| { + tonic::Status::unknown( + format!("Service was not ready: {}", e.into()), + ) + })?; + let codec = tonic_prost::ProstCodec::default(); + let path = http::uri::PathAndQuery::from_static( + "/komp_ac.backup.BackupService/RestoreDatabase", + ); + let mut req = request.into_request(); + req.extensions_mut() + .insert( + GrpcMethod::new("komp_ac.backup.BackupService", "RestoreDatabase"), + ); + self.inner.unary(req, path, codec).await + } } } /// Generated server implementations. @@ -540,6 +612,17 @@ pub mod backup_service_server { &self, request: tonic::Request, ) -> std::result::Result, tonic::Status>; + async fn list_database_dumps( + &self, + request: tonic::Request, + ) -> std::result::Result< + tonic::Response, + tonic::Status, + >; + async fn restore_database( + &self, + request: tonic::Request, + ) -> std::result::Result, tonic::Status>; } #[derive(Debug)] pub struct BackupServiceServer { @@ -982,6 +1065,98 @@ pub mod backup_service_server { }; Box::pin(fut) } + "/komp_ac.backup.BackupService/ListDatabaseDumps" => { + #[allow(non_camel_case_types)] + struct ListDatabaseDumpsSvc(pub Arc); + impl< + T: BackupService, + > tonic::server::UnaryService + for ListDatabaseDumpsSvc { + type Response = super::ListDatabaseDumpsResponse; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::list_database_dumps(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = ListDatabaseDumpsSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } + "/komp_ac.backup.BackupService/RestoreDatabase" => { + #[allow(non_camel_case_types)] + struct RestoreDatabaseSvc(pub Arc); + impl< + T: BackupService, + > tonic::server::UnaryService + for RestoreDatabaseSvc { + type Response = super::DatabaseInfo; + type Future = BoxFuture< + tonic::Response, + tonic::Status, + >; + fn call( + &mut self, + request: tonic::Request, + ) -> Self::Future { + let inner = Arc::clone(&self.0); + let fut = async move { + ::restore_database(&inner, request) + .await + }; + Box::pin(fut) + } + } + let accept_compression_encodings = self.accept_compression_encodings; + let send_compression_encodings = self.send_compression_encodings; + let max_decoding_message_size = self.max_decoding_message_size; + let max_encoding_message_size = self.max_encoding_message_size; + let inner = self.inner.clone(); + let fut = async move { + let method = RestoreDatabaseSvc(inner); + let codec = tonic_prost::ProstCodec::default(); + let mut grpc = tonic::server::Grpc::new(codec) + .apply_compression_config( + accept_compression_encodings, + send_compression_encodings, + ) + .apply_max_message_size_config( + max_decoding_message_size, + max_encoding_message_size, + ); + let res = grpc.unary(method, req).await; + Ok(res) + }; + Box::pin(fut) + } _ => { Box::pin(async move { let mut response = http::Response::new( diff --git a/server b/server index 8f18fa39..b8ca18a6 160000 --- a/server +++ b/server @@ -1 +1 @@ -Subproject commit 8f18fa39e342626c10b08e7409a1a6909c383f55 +Subproject commit b8ca18a627297bb6c2b3a3207b32c116a00de08a