From 99f7d0bed3d21c954ec271f0d6a93d4ff508e92d Mon Sep 17 00:00:00 2001 From: Santtu Lakkala Date: Tue, 1 Oct 2024 12:34:48 +0300 Subject: [PATCH] Refactor locale and timezone setting Change locale and timezone to be signalled from admin to agent after registration. Signed-off-by: Santtu Lakkala --- Cargo.lock | 19 +- Cargo.toml | 1 + api/admin/admin.pb.go | 204 ++++++++-------- api/admin/admin.proto | 3 +- api/locale/locale.pb.go | 271 +++++++++++++++++++++ api/locale/locale.proto | 21 ++ api/locale/locale_grpc.pb.go | 149 +++++++++++ api/protoc.sh | 7 +- client/src/client.rs | 7 +- common/build.rs | 5 + common/src/lib.rs | 3 + internal/cmd/givc-agent/main.go | 30 +-- internal/pkgs/localelistener/controller.go | 56 +++++ internal/pkgs/localelistener/transport.go | 65 +++++ src/admin/server.rs | 111 ++++++++- src/bin/givc-agent.rs | 20 +- 16 files changed, 804 insertions(+), 168 deletions(-) create mode 100644 api/locale/locale.pb.go create mode 100644 api/locale/locale.proto create mode 100644 api/locale/locale_grpc.pb.go create mode 100644 internal/pkgs/localelistener/controller.go create mode 100644 internal/pkgs/localelistener/transport.go diff --git a/Cargo.lock b/Cargo.lock index b9f1057..3932928 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -595,6 +595,7 @@ dependencies = [ "http-body 0.4.6", "hyper 0.14.30", "prost 0.12.6", + "regex", "serde", "serde_json", "strum 0.25.0", @@ -1326,14 +1327,14 @@ dependencies = [ [[package]] name = "regex" -version = "1.10.6" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619" +checksum = "38200e5ee88914975b69f657f0801b6f6dccafd44fd9326302a4aaeecfacb1d8" dependencies = [ "aho-corasick", "memchr", - "regex-automata 0.4.7", - "regex-syntax 0.8.4", + "regex-automata 0.4.8", + "regex-syntax 0.8.5", ] [[package]] @@ -1347,13 +1348,13 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" +checksum = "368758f23274712b504848e9d5a6f010445cc8b87a7cdb4d7cbee666c1288da3" dependencies = [ "aho-corasick", "memchr", - "regex-syntax 0.8.4", + "regex-syntax 0.8.5", ] [[package]] @@ -1364,9 +1365,9 @@ checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" [[package]] name = "regex-syntax" -version = "0.8.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "ring" diff --git a/Cargo.toml b/Cargo.toml index c525f99..1af528a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,7 @@ http = "0.2" http-body = "0.4.2" hyper = "0.14" prost = "0.12" +regex = "1.11" tokio = {version = "1.0", features = ["rt-multi-thread", "time", "macros", "fs"]} tokio-stream = "0.1" tokio-vsock = "0.5" diff --git a/api/admin/admin.pb.go b/api/admin/admin.pb.go index ba46fda..d99d0a4 100644 --- a/api/admin/admin.pb.go +++ b/api/admin/admin.pb.go @@ -257,8 +257,7 @@ type RegistryResponse struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Timezone string `protobuf:"bytes,1,opt,name=Timezone,proto3" json:"Timezone,omitempty"` - Locale string `protobuf:"bytes,2,opt,name=Locale,proto3" json:"Locale,omitempty"` + Error *string `protobuf:"bytes,1,opt,name=Error,proto3,oneof" json:"Error,omitempty"` } func (x *RegistryResponse) Reset() { @@ -293,16 +292,9 @@ func (*RegistryResponse) Descriptor() ([]byte, []int) { return file_admin_proto_rawDescGZIP(), []int{3} } -func (x *RegistryResponse) GetTimezone() string { - if x != nil { - return x.Timezone - } - return "" -} - -func (x *RegistryResponse) GetLocale() string { - if x != nil { - return x.Locale +func (x *RegistryResponse) GetError() string { + if x != nil && x.Error != nil { + return *x.Error } return "" } @@ -816,104 +808,103 @@ var file_admin_proto_rawDesc = []byte{ 0x72, 0x61, 0x6e, 0x73, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x27, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x55, 0x6e, 0x69, 0x74, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x05, 0x53, 0x74, 0x61, 0x74, - 0x65, 0x22, 0x46, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, - 0x65, 0x12, 0x16, 0x0a, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x22, 0x6a, 0x0a, 0x12, 0x41, 0x70, 0x70, - 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, - 0x18, 0x0a, 0x07, 0x41, 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x07, 0x41, 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x06, 0x56, 0x6d, 0x4e, - 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x56, 0x6d, 0x4e, - 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x72, 0x67, 0x73, 0x18, 0x03, - 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x41, 0x72, 0x67, 0x73, 0x42, 0x09, 0x0a, 0x07, 0x5f, 0x56, - 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x51, 0x0a, 0x13, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, 0x09, - 0x43, 0x6d, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x09, 0x43, 0x6d, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x41, 0x70, - 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x41, - 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x22, 0x81, 0x01, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x49, - 0x74, 0x65, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x44, 0x65, 0x73, 0x63, 0x72, - 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x44, 0x65, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x56, 0x6d, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x56, 0x6d, 0x53, - 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x54, 0x72, 0x75, 0x73, 0x74, 0x4c, 0x65, - 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x54, 0x72, 0x75, 0x73, 0x74, - 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x3d, 0x0a, 0x11, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, - 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x04, 0x4c, 0x69, - 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x52, 0x04, - 0x4c, 0x69, 0x73, 0x74, 0x22, 0xdd, 0x01, 0x0a, 0x09, 0x57, 0x61, 0x74, 0x63, 0x68, 0x49, 0x74, - 0x65, 0x6d, 0x12, 0x34, 0x0a, 0x07, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x51, 0x75, 0x65, 0x72, - 0x79, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, 0x52, - 0x07, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x2c, 0x0a, 0x05, 0x41, 0x64, 0x64, 0x65, - 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x48, 0x00, 0x52, - 0x05, 0x41, 0x64, 0x64, 0x65, 0x64, 0x12, 0x30, 0x0a, 0x07, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, - 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x48, 0x00, 0x52, - 0x07, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x30, 0x0a, 0x07, 0x52, 0x65, 0x6d, 0x6f, - 0x76, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x48, - 0x00, 0x52, 0x07, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x53, 0x74, - 0x61, 0x74, 0x75, 0x73, 0x22, 0x27, 0x0a, 0x0d, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x52, 0x65, - 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x22, 0x2d, 0x0a, - 0x0f, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x1a, 0x0a, 0x08, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x32, 0xf9, 0x05, 0x0a, - 0x0c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x44, 0x0a, - 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, - 0x12, 0x16, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, - 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, - 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, - 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x70, 0x70, 0x6c, - 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, - 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, - 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, - 0x12, 0x4b, 0x0a, 0x10, 0x50, 0x61, 0x75, 0x73, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, 0x70, - 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1a, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4c, 0x0a, - 0x11, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, - 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0f, 0x53, - 0x74, 0x6f, 0x70, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, + 0x65, 0x22, 0x37, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x19, 0x0a, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x88, 0x01, 0x01, + 0x42, 0x08, 0x0a, 0x06, 0x5f, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x22, 0x6a, 0x0a, 0x12, 0x41, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x12, 0x18, 0x0a, 0x07, 0x41, 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x07, 0x41, 0x70, 0x70, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x1b, 0x0a, 0x06, 0x56, 0x6d, + 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x06, 0x56, 0x6d, + 0x4e, 0x61, 0x6d, 0x65, 0x88, 0x01, 0x01, 0x12, 0x12, 0x0a, 0x04, 0x41, 0x72, 0x67, 0x73, 0x18, + 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x41, 0x72, 0x67, 0x73, 0x42, 0x09, 0x0a, 0x07, 0x5f, + 0x56, 0x6d, 0x4e, 0x61, 0x6d, 0x65, 0x22, 0x51, 0x0a, 0x13, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1c, 0x0a, + 0x09, 0x43, 0x6d, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x43, 0x6d, 0x64, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1c, 0x0a, 0x09, 0x41, + 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, + 0x41, 0x70, 0x70, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, + 0x74, 0x79, 0x22, 0x81, 0x01, 0x0a, 0x0d, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, + 0x49, 0x74, 0x65, 0x6d, 0x12, 0x12, 0x0a, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x44, 0x65, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x44, + 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x56, 0x6d, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x56, 0x6d, + 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x54, 0x72, 0x75, 0x73, 0x74, 0x4c, + 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x54, 0x72, 0x75, 0x73, + 0x74, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x3d, 0x0a, 0x11, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, + 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x28, 0x0a, 0x04, 0x4c, + 0x69, 0x73, 0x74, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x52, + 0x04, 0x4c, 0x69, 0x73, 0x74, 0x22, 0xdd, 0x01, 0x0a, 0x09, 0x57, 0x61, 0x74, 0x63, 0x68, 0x49, + 0x74, 0x65, 0x6d, 0x12, 0x34, 0x0a, 0x07, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x51, 0x75, 0x65, + 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x48, 0x00, + 0x52, 0x07, 0x49, 0x6e, 0x69, 0x74, 0x69, 0x61, 0x6c, 0x12, 0x2c, 0x0a, 0x05, 0x41, 0x64, 0x64, + 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x48, 0x00, + 0x52, 0x05, 0x41, 0x64, 0x64, 0x65, 0x64, 0x12, 0x30, 0x0a, 0x07, 0x55, 0x70, 0x64, 0x61, 0x74, + 0x65, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, 0x48, 0x00, + 0x52, 0x07, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x64, 0x12, 0x30, 0x0a, 0x07, 0x52, 0x65, 0x6d, + 0x6f, 0x76, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x14, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, 0x73, 0x74, 0x49, 0x74, 0x65, 0x6d, + 0x48, 0x00, 0x52, 0x07, 0x52, 0x65, 0x6d, 0x6f, 0x76, 0x65, 0x64, 0x42, 0x08, 0x0a, 0x06, 0x53, + 0x74, 0x61, 0x74, 0x75, 0x73, 0x22, 0x27, 0x0a, 0x0d, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x22, 0x2d, + 0x0a, 0x0f, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x12, 0x1a, 0x0a, 0x08, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x08, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x32, 0xf9, 0x05, + 0x0a, 0x0c, 0x41, 0x64, 0x6d, 0x69, 0x6e, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, 0x65, 0x12, 0x44, + 0x0a, 0x0f, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x53, 0x65, 0x72, 0x76, 0x69, 0x63, + 0x65, 0x12, 0x16, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, + 0x72, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x17, 0x2e, 0x61, 0x64, 0x6d, 0x69, + 0x6e, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x72, 0x79, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, + 0x73, 0x65, 0x22, 0x00, 0x12, 0x4b, 0x0a, 0x10, 0x53, 0x74, 0x61, 0x72, 0x74, 0x41, 0x70, 0x70, + 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, + 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, + 0x00, 0x12, 0x4b, 0x0a, 0x10, 0x50, 0x61, 0x75, 0x73, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, + 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, + 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, + 0x1a, 0x1a, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4c, + 0x0a, 0x11, 0x52, 0x65, 0x73, 0x75, 0x6d, 0x65, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x12, 0x19, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, + 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x73, - 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x09, 0x53, 0x65, 0x74, 0x4c, 0x6f, - 0x63, 0x61, 0x6c, 0x65, 0x12, 0x14, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x6f, 0x63, - 0x61, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x64, 0x6d, - 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x35, 0x0a, 0x0b, 0x53, 0x65, - 0x74, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x12, 0x16, 0x2e, 0x61, 0x64, 0x6d, 0x69, - 0x6e, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, - 0x00, 0x12, 0x28, 0x0a, 0x08, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x6f, 0x66, 0x66, 0x12, 0x0c, 0x2e, - 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x26, 0x0a, 0x06, 0x52, - 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x12, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, - 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, - 0x79, 0x22, 0x00, 0x12, 0x27, 0x0a, 0x07, 0x53, 0x75, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x12, 0x0c, + 0x6f, 0x6e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x4a, 0x0a, 0x0f, + 0x53, 0x74, 0x6f, 0x70, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, + 0x19, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1a, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x65, + 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x31, 0x0a, 0x09, 0x53, 0x65, 0x74, 0x4c, + 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x12, 0x14, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x4c, 0x6f, + 0x63, 0x61, 0x6c, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x64, + 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x35, 0x0a, 0x0b, 0x53, + 0x65, 0x74, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x12, 0x16, 0x2e, 0x61, 0x64, 0x6d, + 0x69, 0x6e, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, + 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x22, 0x00, 0x12, 0x28, 0x0a, 0x08, 0x50, 0x6f, 0x77, 0x65, 0x72, 0x6f, 0x66, 0x66, 0x12, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x26, 0x0a, 0x06, - 0x57, 0x61, 0x6b, 0x65, 0x75, 0x70, 0x12, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, + 0x52, 0x65, 0x62, 0x6f, 0x6f, 0x74, 0x12, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x22, 0x00, 0x12, 0x35, 0x0a, 0x09, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, 0x73, - 0x74, 0x12, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, - 0x18, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, 0x73, - 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2b, 0x0a, 0x05, 0x57, - 0x61, 0x74, 0x63, 0x68, 0x12, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, - 0x74, 0x79, 0x1a, 0x10, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x57, 0x61, 0x74, 0x63, 0x68, - 0x49, 0x74, 0x65, 0x6d, 0x22, 0x00, 0x30, 0x01, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x61, 0x64, - 0x6d, 0x69, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x74, 0x79, 0x22, 0x00, 0x12, 0x27, 0x0a, 0x07, 0x53, 0x75, 0x73, 0x70, 0x65, 0x6e, 0x64, 0x12, + 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, + 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x26, 0x0a, + 0x06, 0x57, 0x61, 0x6b, 0x65, 0x75, 0x70, 0x12, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, + 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x35, 0x0a, 0x09, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, + 0x73, 0x74, 0x12, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, + 0x1a, 0x18, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x51, 0x75, 0x65, 0x72, 0x79, 0x4c, 0x69, + 0x73, 0x74, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x22, 0x00, 0x12, 0x2b, 0x0a, 0x05, + 0x57, 0x61, 0x74, 0x63, 0x68, 0x12, 0x0c, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x1a, 0x10, 0x2e, 0x61, 0x64, 0x6d, 0x69, 0x6e, 0x2e, 0x57, 0x61, 0x74, 0x63, + 0x68, 0x49, 0x74, 0x65, 0x6d, 0x22, 0x00, 0x30, 0x01, 0x42, 0x09, 0x5a, 0x07, 0x2e, 0x2f, 0x61, + 0x64, 0x6d, 0x69, 0x6e, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1135,6 +1126,7 @@ func file_admin_proto_init() { } } } + file_admin_proto_msgTypes[3].OneofWrappers = []interface{}{} file_admin_proto_msgTypes[4].OneofWrappers = []interface{}{} file_admin_proto_msgTypes[9].OneofWrappers = []interface{}{ (*WatchItem_Initial)(nil), diff --git a/api/admin/admin.proto b/api/admin/admin.proto index 035ad6a..c1057b0 100644 --- a/api/admin/admin.proto +++ b/api/admin/admin.proto @@ -28,8 +28,7 @@ message RegistryRequest { } message RegistryResponse { - string Timezone = 1; - string Locale = 2; + optional string Error = 1; } message ApplicationRequest { diff --git a/api/locale/locale.pb.go b/api/locale/locale.pb.go new file mode 100644 index 0000000..ef198e9 --- /dev/null +++ b/api/locale/locale.pb.go @@ -0,0 +1,271 @@ +// Copyright 2024 TII (SSRC) and the Ghaf contributors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.34.1 +// protoc v4.24.4 +// source: locale.proto + +package locale + +import ( + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +type LocaleMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Locale string `protobuf:"bytes,1,opt,name=Locale,proto3" json:"Locale,omitempty"` +} + +func (x *LocaleMessage) Reset() { + *x = LocaleMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_locale_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *LocaleMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*LocaleMessage) ProtoMessage() {} + +func (x *LocaleMessage) ProtoReflect() protoreflect.Message { + mi := &file_locale_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use LocaleMessage.ProtoReflect.Descriptor instead. +func (*LocaleMessage) Descriptor() ([]byte, []int) { + return file_locale_proto_rawDescGZIP(), []int{0} +} + +func (x *LocaleMessage) GetLocale() string { + if x != nil { + return x.Locale + } + return "" +} + +type TimezoneMessage struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Timezone string `protobuf:"bytes,1,opt,name=Timezone,proto3" json:"Timezone,omitempty"` +} + +func (x *TimezoneMessage) Reset() { + *x = TimezoneMessage{} + if protoimpl.UnsafeEnabled { + mi := &file_locale_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *TimezoneMessage) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*TimezoneMessage) ProtoMessage() {} + +func (x *TimezoneMessage) ProtoReflect() protoreflect.Message { + mi := &file_locale_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use TimezoneMessage.ProtoReflect.Descriptor instead. +func (*TimezoneMessage) Descriptor() ([]byte, []int) { + return file_locale_proto_rawDescGZIP(), []int{1} +} + +func (x *TimezoneMessage) GetTimezone() string { + if x != nil { + return x.Timezone + } + return "" +} + +type Empty struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *Empty) Reset() { + *x = Empty{} + if protoimpl.UnsafeEnabled { + mi := &file_locale_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Empty) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Empty) ProtoMessage() {} + +func (x *Empty) ProtoReflect() protoreflect.Message { + mi := &file_locale_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Empty.ProtoReflect.Descriptor instead. +func (*Empty) Descriptor() ([]byte, []int) { + return file_locale_proto_rawDescGZIP(), []int{2} +} + +var File_locale_proto protoreflect.FileDescriptor + +var file_locale_proto_rawDesc = []byte{ + 0x0a, 0x0c, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x06, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x22, 0x27, 0x0a, 0x0d, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, + 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, + 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x4c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x22, + 0x2d, 0x0a, 0x0f, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, + 0x67, 0x65, 0x12, 0x1a, 0x0a, 0x08, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x22, 0x07, + 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x32, 0x7c, 0x0a, 0x0c, 0x4c, 0x6f, 0x63, 0x61, 0x6c, + 0x65, 0x43, 0x6c, 0x69, 0x65, 0x6e, 0x74, 0x12, 0x33, 0x0a, 0x09, 0x4c, 0x6f, 0x63, 0x61, 0x6c, + 0x65, 0x53, 0x65, 0x74, 0x12, 0x15, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x4c, 0x6f, + 0x63, 0x61, 0x6c, 0x65, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x1a, 0x0d, 0x2e, 0x6c, 0x6f, + 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x00, 0x12, 0x37, 0x0a, 0x0b, + 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x53, 0x65, 0x74, 0x12, 0x17, 0x2e, 0x6c, 0x6f, + 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x54, 0x69, 0x6d, 0x65, 0x7a, 0x6f, 0x6e, 0x65, 0x4d, 0x65, 0x73, + 0x73, 0x61, 0x67, 0x65, 0x1a, 0x0d, 0x2e, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x65, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x22, 0x00, 0x42, 0x0a, 0x5a, 0x08, 0x2e, 0x2f, 0x6c, 0x6f, 0x63, 0x61, 0x6c, + 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_locale_proto_rawDescOnce sync.Once + file_locale_proto_rawDescData = file_locale_proto_rawDesc +) + +func file_locale_proto_rawDescGZIP() []byte { + file_locale_proto_rawDescOnce.Do(func() { + file_locale_proto_rawDescData = protoimpl.X.CompressGZIP(file_locale_proto_rawDescData) + }) + return file_locale_proto_rawDescData +} + +var file_locale_proto_msgTypes = make([]protoimpl.MessageInfo, 3) +var file_locale_proto_goTypes = []interface{}{ + (*LocaleMessage)(nil), // 0: locale.LocaleMessage + (*TimezoneMessage)(nil), // 1: locale.TimezoneMessage + (*Empty)(nil), // 2: locale.Empty +} +var file_locale_proto_depIdxs = []int32{ + 0, // 0: locale.LocaleClient.LocaleSet:input_type -> locale.LocaleMessage + 1, // 1: locale.LocaleClient.TimezoneSet:input_type -> locale.TimezoneMessage + 2, // 2: locale.LocaleClient.LocaleSet:output_type -> locale.Empty + 2, // 3: locale.LocaleClient.TimezoneSet:output_type -> locale.Empty + 2, // [2:4] is the sub-list for method output_type + 0, // [0:2] is the sub-list for method input_type + 0, // [0:0] is the sub-list for extension type_name + 0, // [0:0] is the sub-list for extension extendee + 0, // [0:0] is the sub-list for field type_name +} + +func init() { file_locale_proto_init() } +func file_locale_proto_init() { + if File_locale_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_locale_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*LocaleMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_locale_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*TimezoneMessage); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_locale_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Empty); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_locale_proto_rawDesc, + NumEnums: 0, + NumMessages: 3, + NumExtensions: 0, + NumServices: 1, + }, + GoTypes: file_locale_proto_goTypes, + DependencyIndexes: file_locale_proto_depIdxs, + MessageInfos: file_locale_proto_msgTypes, + }.Build() + File_locale_proto = out.File + file_locale_proto_rawDesc = nil + file_locale_proto_goTypes = nil + file_locale_proto_depIdxs = nil +} diff --git a/api/locale/locale.proto b/api/locale/locale.proto new file mode 100644 index 0000000..d506c52 --- /dev/null +++ b/api/locale/locale.proto @@ -0,0 +1,21 @@ +// Copyright 2024 TII (SSRC) and the Ghaf contributors +// SPDX-License-Identifier: Apache-2.0 +syntax = "proto3"; +option go_package = "./locale"; +package locale; + +message LocaleMessage { + string Locale = 1; +} + +message TimezoneMessage { + string Timezone = 1; +} + +message Empty { +} + +service LocaleClient { + rpc LocaleSet(LocaleMessage) returns (Empty) {} + rpc TimezoneSet(TimezoneMessage) returns (Empty) {} +} diff --git a/api/locale/locale_grpc.pb.go b/api/locale/locale_grpc.pb.go new file mode 100644 index 0000000..f281560 --- /dev/null +++ b/api/locale/locale_grpc.pb.go @@ -0,0 +1,149 @@ +// Copyright 2024 TII (SSRC) and the Ghaf contributors +// SPDX-License-Identifier: Apache-2.0 + +// Code generated by protoc-gen-go-grpc. DO NOT EDIT. +// versions: +// - protoc-gen-go-grpc v1.3.0 +// - protoc v4.24.4 +// source: locale.proto + +package locale + +import ( + context "context" + grpc "google.golang.org/grpc" + codes "google.golang.org/grpc/codes" + status "google.golang.org/grpc/status" +) + +// This is a compile-time assertion to ensure that this generated file +// is compatible with the grpc package it is being compiled against. +// Requires gRPC-Go v1.32.0 or later. +const _ = grpc.SupportPackageIsVersion7 + +const ( + LocaleClient_LocaleSet_FullMethodName = "/locale.LocaleClient/LocaleSet" + LocaleClient_TimezoneSet_FullMethodName = "/locale.LocaleClient/TimezoneSet" +) + +// LocaleClientClient is the client API for LocaleClient 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 LocaleClientClient interface { + LocaleSet(ctx context.Context, in *LocaleMessage, opts ...grpc.CallOption) (*Empty, error) + TimezoneSet(ctx context.Context, in *TimezoneMessage, opts ...grpc.CallOption) (*Empty, error) +} + +type localeClientClient struct { + cc grpc.ClientConnInterface +} + +func NewLocaleClientClient(cc grpc.ClientConnInterface) LocaleClientClient { + return &localeClientClient{cc} +} + +func (c *localeClientClient) LocaleSet(ctx context.Context, in *LocaleMessage, opts ...grpc.CallOption) (*Empty, error) { + out := new(Empty) + err := c.cc.Invoke(ctx, LocaleClient_LocaleSet_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +func (c *localeClientClient) TimezoneSet(ctx context.Context, in *TimezoneMessage, opts ...grpc.CallOption) (*Empty, error) { + out := new(Empty) + err := c.cc.Invoke(ctx, LocaleClient_TimezoneSet_FullMethodName, in, out, opts...) + if err != nil { + return nil, err + } + return out, nil +} + +// LocaleClientServer is the server API for LocaleClient service. +// All implementations must embed UnimplementedLocaleClientServer +// for forward compatibility +type LocaleClientServer interface { + LocaleSet(context.Context, *LocaleMessage) (*Empty, error) + TimezoneSet(context.Context, *TimezoneMessage) (*Empty, error) + mustEmbedUnimplementedLocaleClientServer() +} + +// UnimplementedLocaleClientServer must be embedded to have forward compatible implementations. +type UnimplementedLocaleClientServer struct { +} + +func (UnimplementedLocaleClientServer) LocaleSet(context.Context, *LocaleMessage) (*Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method LocaleSet not implemented") +} +func (UnimplementedLocaleClientServer) TimezoneSet(context.Context, *TimezoneMessage) (*Empty, error) { + return nil, status.Errorf(codes.Unimplemented, "method TimezoneSet not implemented") +} +func (UnimplementedLocaleClientServer) mustEmbedUnimplementedLocaleClientServer() {} + +// UnsafeLocaleClientServer may be embedded to opt out of forward compatibility for this service. +// Use of this interface is not recommended, as added methods to LocaleClientServer will +// result in compilation errors. +type UnsafeLocaleClientServer interface { + mustEmbedUnimplementedLocaleClientServer() +} + +func RegisterLocaleClientServer(s grpc.ServiceRegistrar, srv LocaleClientServer) { + s.RegisterService(&LocaleClient_ServiceDesc, srv) +} + +func _LocaleClient_LocaleSet_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(LocaleMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(LocaleClientServer).LocaleSet(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: LocaleClient_LocaleSet_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(LocaleClientServer).LocaleSet(ctx, req.(*LocaleMessage)) + } + return interceptor(ctx, in, info, handler) +} + +func _LocaleClient_TimezoneSet_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) { + in := new(TimezoneMessage) + if err := dec(in); err != nil { + return nil, err + } + if interceptor == nil { + return srv.(LocaleClientServer).TimezoneSet(ctx, in) + } + info := &grpc.UnaryServerInfo{ + Server: srv, + FullMethod: LocaleClient_TimezoneSet_FullMethodName, + } + handler := func(ctx context.Context, req interface{}) (interface{}, error) { + return srv.(LocaleClientServer).TimezoneSet(ctx, req.(*TimezoneMessage)) + } + return interceptor(ctx, in, info, handler) +} + +// LocaleClient_ServiceDesc is the grpc.ServiceDesc for LocaleClient service. +// It's only intended for direct use with grpc.RegisterService, +// and not to be introspected or modified (even as a copy) +var LocaleClient_ServiceDesc = grpc.ServiceDesc{ + ServiceName: "locale.LocaleClient", + HandlerType: (*LocaleClientServer)(nil), + Methods: []grpc.MethodDesc{ + { + MethodName: "LocaleSet", + Handler: _LocaleClient_LocaleSet_Handler, + }, + { + MethodName: "TimezoneSet", + Handler: _LocaleClient_TimezoneSet_Handler, + }, + }, + Streams: []grpc.StreamDesc{}, + Metadata: "locale.proto", +} diff --git a/api/protoc.sh b/api/protoc.sh index 2d2bfa3..c2be2e2 100755 --- a/api/protoc.sh +++ b/api/protoc.sh @@ -7,7 +7,6 @@ gen_protoc() { "$1"/"$2" } -gen_protoc api/admin admin.proto -gen_protoc api/systemd systemd.proto -gen_protoc api/wifi wifi.proto -gen_protoc api/hwid hwid.proto +for api in admin systemd wifi hwid locale; do + gen_protoc api/$api $api.proto +done diff --git a/client/src/client.rs b/client/src/client.rs index 855818d..fe54944 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -63,7 +63,7 @@ impl AdminClient { ty: UnitType, endpoint: EndpointEntry, status: UnitStatus, - ) -> anyhow::Result<(String, String)> { + ) -> anyhow::Result<()> { // Convert everything into wire format let request = pb::admin::RegistryRequest { name, @@ -78,7 +78,10 @@ impl AdminClient { .register_service(request) .await? .into_inner(); - Ok((response.timezone, response.locale)) + if let Some(err) = response.error { + bail!("{err}"); + } + Ok(()) } pub async fn start( diff --git a/common/build.rs b/common/build.rs index 3e967cc..f76b44f 100644 --- a/common/build.rs +++ b/common/build.rs @@ -8,6 +8,11 @@ fn main() { .compile(&["api/admin/admin.proto"], &["admin"]) .unwrap(); + tonic_build::configure() + .file_descriptor_set_path(out_dir.join("locale_descriptor.bin")) + .compile(&["api/locale/locale.proto"], &["locale"]) + .unwrap(); + tonic_build::configure() .file_descriptor_set_path(out_dir.join("systemd_descriptor.bin")) .compile(&["api/systemd/systemd.proto"], &["systemd"]) diff --git a/common/src/lib.rs b/common/src/lib.rs index 9209e20..240dc0e 100644 --- a/common/src/lib.rs +++ b/common/src/lib.rs @@ -6,6 +6,9 @@ pub mod pb { pub mod admin { tonic::include_proto!("admin"); } + pub mod locale { + tonic::include_proto!("locale"); + } pub mod systemd { tonic::include_proto!("systemd"); } diff --git a/internal/cmd/givc-agent/main.go b/internal/cmd/givc-agent/main.go index 51464a9..7cb81e5 100644 --- a/internal/cmd/givc-agent/main.go +++ b/internal/cmd/givc-agent/main.go @@ -6,7 +6,6 @@ import ( "context" "crypto/tls" "os" - "os/exec" "path/filepath" "strconv" "strings" @@ -15,6 +14,7 @@ import ( givc_app "givc/internal/pkgs/applications" givc_grpc "givc/internal/pkgs/grpc" "givc/internal/pkgs/hwidmanager" + "givc/internal/pkgs/localelistener" "givc/internal/pkgs/serviceclient" "givc/internal/pkgs/servicemanager" "givc/internal/pkgs/types" @@ -177,29 +177,9 @@ func main() { <-serverStarted // Register agent - response, err := serviceclient.RegisterRemoteService(cfgAdminServer, agentEntryRequest) + _, err := serviceclient.RegisterRemoteService(cfgAdminServer, agentEntryRequest) if err != nil { log.Fatalf("Error register agent: %s", err) - } else { - if response.Locale != "" { - if err := exec.Command("localectl", "set-locale", response.Locale).Run(); err != nil { - log.Warningf("Failed to set locale: %s", err) - } - if givc_util.IsRoot() { - if err := exec.Command("systemctl", "set-environment", "LANG="+response.Locale).Run(); err != nil { - log.Warningf("Failed to set environment: %s", err) - } - } else { - if err := exec.Command("systemctl", "--user", "set-environment", "LANG="+response.Locale).Run(); err != nil { - log.Warningf("Failed to set environment: %s", err) - } - } - } - if response.Timezone != "" { - if err := exec.Command("timedatectl", "set-timezone", response.Timezone).Run(); err != nil { - log.Warningf("Failed to set timezone: %s", err) - } - } } // Register services @@ -238,6 +218,12 @@ func main() { } grpcServices = append(grpcServices, systemdControlServer) + localeClientServer, err := localelistener.NewLocaleServer() + if err != nil { + log.Fatalf("Cannot create locale listener server") + } + grpcServices = append(grpcServices, localeClientServer) + if wifiEnabled { // Create wifi control server wifiControlServer, err := wifimanager.NewWifiControlServer() diff --git a/internal/pkgs/localelistener/controller.go b/internal/pkgs/localelistener/controller.go new file mode 100644 index 0000000..66b61a4 --- /dev/null +++ b/internal/pkgs/localelistener/controller.go @@ -0,0 +1,56 @@ +// Copyright 2024 TII (SSRC) and the Ghaf contributors +// SPDX-License-Identifier: Apache-2.0 +package localelistener + +import ( + "context" + "fmt" + givc_util "givc/internal/pkgs/utility" + "os/exec" + + log "github.com/sirupsen/logrus" +) + +type LocaleController struct { +} + +func NewController() (*LocaleController, error) { + return &LocaleController{}, nil +} + +func (c *LocaleController) SetLocale(ctx context.Context, locale string) error { + + // Input validation + if ctx == nil { + return fmt.Errorf("context cannot be nil") + } + + if err := exec.Command("localectl", "set-locale", locale).Run(); err != nil { + log.Warningf("Failed to set locale: %s", err) + } + if givc_util.IsRoot() { + if err := exec.Command("systemctl", "set-environment", "LANG="+locale).Run(); err != nil { + log.Warningf("Failed to set environment: %s", err) + } + } else { + if err := exec.Command("systemctl", "--user", "set-environment", "LANG="+locale).Run(); err != nil { + log.Warningf("Failed to set environment: %s", err) + } + } + + return nil +} + +func (c *LocaleController) SetTimezone(ctx context.Context, timezone string) error { + + // Input validation + if ctx == nil { + return fmt.Errorf("context cannot be nil") + } + + if err := exec.Command("timedatectl", "set-timezone", timezone).Run(); err != nil { + log.Warningf("Failed to set timezone: %s", err) + } + + return nil +} diff --git a/internal/pkgs/localelistener/transport.go b/internal/pkgs/localelistener/transport.go new file mode 100644 index 0000000..6a8533a --- /dev/null +++ b/internal/pkgs/localelistener/transport.go @@ -0,0 +1,65 @@ +// Copyright 2024 TII (SSRC) and the Ghaf contributors +// SPDX-License-Identifier: Apache-2.0 +package localelistener + +import ( + "context" + "fmt" + + locale_api "givc/api/locale" + + log "github.com/sirupsen/logrus" + "google.golang.org/grpc" +) + +type LocaleServer struct { + Controller *LocaleController + locale_api.UnimplementedLocaleClientServer +} + +func (s *LocaleServer) Name() string { + return "Locale listener" +} + +func (s *LocaleServer) RegisterGrpcService(srv *grpc.Server) { + locale_api.RegisterLocaleClientServer(srv, s) +} + +func NewLocaleServer() (*LocaleServer, error) { + + localeController, err := NewController() + if err != nil { + log.Errorf("Error creating locale controller: %v", err) + return nil, err + } + + localeServer := LocaleServer{ + Controller: localeController, + } + + return &localeServer, nil +} + +func (s *LocaleServer) LocaleSet(ctx context.Context, req *locale_api.LocaleMessage) (*locale_api.Empty, error) { + log.Infof("Incoming notification of changes locale\n") + + err := s.Controller.SetLocale(context.Background(), req.Locale) + if err != nil { + log.Infof("[SetLocale] Error setting locale: %v\n", err) + return nil, fmt.Errorf("Cannot set locale") + } + + return &locale_api.Empty{}, nil +} + +func (s *LocaleServer) TimezoneSet(ctx context.Context, req *locale_api.TimezoneMessage) (*locale_api.Empty, error) { + log.Infof("Incoming notification of set timezone\n") + + err := s.Controller.SetTimezone(context.Background(), req.Timezone) + if err != nil { + log.Infof("[SetLocale] Error setting timezone: %v\n", err) + return nil, fmt.Errorf("Cannot set timezone") + } + + return &locale_api.Empty{}, nil +} diff --git a/src/admin/server.rs b/src/admin/server.rs index b78ff5f..0a7383b 100644 --- a/src/admin/server.rs +++ b/src/admin/server.rs @@ -3,6 +3,7 @@ use crate::pb::{self, *}; use anyhow::{bail, Context}; use async_stream::try_stream; use givc_common::query::Event; +use regex::Regex; use std::pin::Pin; use std::sync::Arc; use std::time::Duration; @@ -47,6 +48,22 @@ pub struct AdminService { inner: Arc, } +struct Validator(); + +impl Validator { + pub fn validate_locale(locale: &str) -> bool { + let validator = Regex::new( + r"^(?:C|POSIX|[a-z]{2}(?:_[A-Z]{2})?(?:@[a-zA-Z0-9]+)?)(?:\.[-a-zA-Z0-9]+)?$", + ) + .unwrap(); + validator.is_match(locale) + } + pub fn validate_timezone(timezone: &str) -> bool { + let validator = Regex::new(r"^[A-Z][-+a-zA-Z0-9]*(?:/[A-Z][-+a-zA-Z0-9_]*)*$").unwrap(); + validator.is_match(timezone) + } +} + impl AdminService { pub fn new(use_tls: Option) -> Self { let inner = Arc::new(AdminServiceImpl::new(use_tls)); @@ -323,12 +340,38 @@ impl pb::admin_service_server::AdminService for AdminService { info!("Registering service {:?}", req); let entry = RegistryEntry::try_from(req) .map_err(|e| Status::new(Code::InvalidArgument, format!("{e}")))?; + let mut notify = None; + + if matches!( + entry.r#type, + UnitType { + service: ServiceType::Mgr, + .. + } + ) { + notify = Some(entry.name.to_owned()); + } self.inner.register(entry); - let res = RegistryResponse { - timezone: self.inner.timezone.lock().await.clone(), - locale: self.inner.locale.lock().await.clone(), - }; + let res = RegistryResponse { error: None }; + + if let Some(name) = notify { + if let Ok(endpoint) = self.inner.agent_endpoint(&name) { + let locale = self.inner.locale.lock().await.clone(); + let timezone = self.inner.timezone.lock().await.clone(); + tokio::spawn(async move { + if let Ok(conn) = endpoint.connect().await { + let mut client = + pb::locale::locale_client_client::LocaleClientClient::new(conn); + let localemsg = pb::locale::LocaleMessage { locale }; + let _ = client.locale_set(localemsg).await; + + let timezonemsg = pb::locale::TimezoneMessage { timezone }; + let _ = client.timezone_set(timezonemsg).await; + } + }); + } + } info!("Responding with {res:?}"); Ok(Response::new(res)) } @@ -458,6 +501,9 @@ impl pb::admin_service_server::AdminService for AdminService { request: tonic::Request, ) -> std::result::Result, tonic::Status> { escalate(request, |req| async move { + if !Validator::validate_locale(&req.locale) { + bail!("Invalid locale"); + } let _ = tokio::fs::write(LOCALE_CONF, format!("LANG={}", req.locale)).await; *self.inner.locale.lock().await = req.locale; Ok(Empty {}) @@ -470,6 +516,9 @@ impl pb::admin_service_server::AdminService for AdminService { request: tonic::Request, ) -> std::result::Result, tonic::Status> { escalate(request, |req| async move { + if !Validator::validate_timezone(&req.timezone) { + bail!("Invalid timezone"); + } let _ = tokio::fs::write(TIMEZONE_CONF, &req.timezone).await; *self.inner.timezone.lock().await = req.timezone; Ok(Empty {}) @@ -505,3 +554,57 @@ impl pb::admin_service_server::AdminService for AdminService { .await } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_locale_validator() -> anyhow::Result<()> { + if ![ + "en_US.UTF-8", + "C", + "POSIX", + "C.UTF-8", + "ar_AE.UTF-8", + "fi_FI@euro.UTF-8", + "fi_FI@euro", + ] + .into_iter() + .all(Validator::validate_locale) + { + bail!("Valid locale rejected"); + } + if ["`rm -Rf --no-preserve-root /`", "; whoami", "iwaenfli"] + .into_iter() + .any(Validator::validate_locale) + { + bail!("Invalid locale accepted"); + } + Ok(()) + } + + #[test] + fn test_timezone_validator() -> anyhow::Result<()> { + if ![ + "UTC", + "Europe/Helsinki", + "Asia/Abu_Dhabi", + "Etc/GMT+8", + "GMT-0", + "America/Argentina/Rio_Gallegos", + ] + .into_iter() + .all(Validator::validate_timezone) + { + bail!("Valid timezone rejected"); + } + if ["/foobar", "`whoami`", "Almost//Valid"] + .into_iter() + .any(Validator::validate_timezone) + { + bail!("Invalid timezone accepted"); + } + Ok(()) + } +} diff --git a/src/bin/givc-agent.rs b/src/bin/givc-agent.rs index a9291c2..8b91898 100644 --- a/src/bin/givc-agent.rs +++ b/src/bin/givc-agent.rs @@ -9,7 +9,6 @@ use givc_common::pb; use givc_common::pb::reflection::SYSTEMD_DESCRIPTOR; use std::net::SocketAddr; use std::path::PathBuf; -use std::process::{Command, Stdio}; use tonic::transport::Server; use tracing::info; @@ -108,27 +107,10 @@ async fn main() -> std::result::Result<(), Box> { let admin_tls = tls.clone().map(|tls| (cli.admin_server_name, tls)); let admin = AdminClient::new(cli.admin_server_addr, cli.admin_server_port, admin_tls); - let (timezone, locale) = admin + admin .register_service(agent_service_name, cli.r#type.try_into()?, endpoint, status) .await?; - if !timezone.is_empty() { - Command::new("timedatectl") - .args(["set-timezone", timezone.as_str()]) - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .spawn()?; - } - if !locale.is_empty() { - Command::new("localectl") - .args(["set-locale", locale.as_str()]) - .stdin(Stdio::null()) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .spawn()?; - } - let reflect = tonic_reflection::server::Builder::configure() .register_encoded_file_descriptor_set(SYSTEMD_DESCRIPTOR) .build_v1()