From ce3eff47eafa61a70de481f4243f4cc2edb6c12a Mon Sep 17 00:00:00 2001 From: Eden Kirin Date: Sat, 18 Mar 2023 21:30:15 +0100 Subject: [PATCH] Initial --- .gitignore | 3 + README.md | 95 ++++++++++++++++++++++++ src/funnel/Makefile | 18 +++++ src/funnel/main.py | 33 ++++++++ src/funnel/requirements.txt | 2 + src/funnel/stubs/__init__.py | 0 src/funnel/stubs/serve_hours_pb2.py | 29 ++++++++ src/funnel/stubs/serve_hours_pb2.pyi | 17 +++++ src/funnel/stubs/serve_hours_pb2_grpc.py | 66 ++++++++++++++++ src/protos/serve_current_time.proto | 15 ++++ src/protos/serve_hours.proto | 7 ++ src/protos/serve_milliseconds.proto | 9 +++ src/protos/serve_minutes.proto | 9 +++ src/protos/serve_seconds.proto | 9 +++ 14 files changed, 312 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 src/funnel/Makefile create mode 100644 src/funnel/main.py create mode 100644 src/funnel/requirements.txt create mode 100644 src/funnel/stubs/__init__.py create mode 100644 src/funnel/stubs/serve_hours_pb2.py create mode 100644 src/funnel/stubs/serve_hours_pb2.pyi create mode 100644 src/funnel/stubs/serve_hours_pb2_grpc.py create mode 100644 src/protos/serve_current_time.proto create mode 100644 src/protos/serve_hours.proto create mode 100644 src/protos/serve_milliseconds.proto create mode 100644 src/protos/serve_minutes.proto create mode 100644 src/protos/serve_seconds.proto diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..42ebde0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +__pycache__ +/dist +/src/funnel/env diff --git a/README.md b/README.md new file mode 100644 index 0000000..fff84ef --- /dev/null +++ b/README.md @@ -0,0 +1,95 @@ + +# Clocker + +## Sequence diagram + +```plantuml +@startuml +participant FE as "Frontend" << React >> +participant Funnel as "Funnel" << Python >> +participant Hours as "ServeHours" << Go >> +participant Minutes as "ServeMinutes" << Go >> +participant Seconds as "ServeSeconds" << Go >> +participant Milliseconds as "ServeMilliseconds" << Go >> +participant CurrentTime as "ServeCurrentTime" << Rust >> + +activate FE #hotpink + FE -> FE: Load page + FE -> Funnel: WS Connect + + loop #ivory + activate Funnel #gold + Funnel -> Hours: GetHours() + activate Hours #skyblue + Hours -> CurrentTime: GetCurrentTime() + activate CurrentTime #sandybrown + return HH:MM:SS.ms + return HH + + Funnel -> Minutes: GetMinutes() + activate Minutes #skyblue + Minutes -> CurrentTime: GetCurrentTime() + activate CurrentTime #sandybrown + return HH:MM:SS.ms + return MM + + Funnel -> Seconds: GetSeconds() + activate Seconds #skyblue + Seconds -> CurrentTime: GetCurrentTime() + activate CurrentTime #sandybrown + return HH:MM:SS.ms + return SS + + Funnel -> Milliseconds: GetMilliseconds() + activate Milliseconds #skyblue + Milliseconds -> CurrentTime: GetCurrentTime() + activate CurrentTime #sandybrown + return HH:MM:SS.ms + return ms + + Funnel -> FE: WS: Send formatted time + deactivate Funnel + end +deactivate FE + +@enduml +``` + +## Services + +| Service | Language | Port | +| -- | -- | -- | +| Funnel | Python | - | +| ServeCurrentTime | Rust | 50000 | +| ServeHours | Go | 50001 | +| ServeMinutes | Go | 50002 | +| ServeSeconds | Go | 50003 | +| ServeMilliseconds | Go | 50004 | + +### Funnel + +Requirements: +- python 3.8+ +- grpcio +- grpcio-tools + +Install virtualenv and libs +```sh +cd src/funnel +virtualenv env +source env/bin/activate +pip install -r requirements.txt +``` + +Compile proto stubs: +```sh +cd src/funnel +make proto +``` + +Run service: +```sh +cd src/funnel +make run +``` + diff --git a/src/funnel/Makefile b/src/funnel/Makefile new file mode 100644 index 0000000..3b7bde0 --- /dev/null +++ b/src/funnel/Makefile @@ -0,0 +1,18 @@ +PROTO_DIR=../protos +STUBS_DIR=./stubs +PROTO_FILENAME=serve_hours.proto + +run: + @source env/bin/activate && \ + python main.py + +proto: + @source env/bin/activate && \ + python \ + -m grpc_tools.protoc \ + -I$(PROTO_DIR) \ + --python_out=$(STUBS_DIR) \ + --pyi_out=$(STUBS_DIR) \ + --grpc_python_out=$(STUBS_DIR) \ + $(PROTO_DIR)/$(PROTO_FILENAME) + @sed -i -E 's/^(import\s[a-zA-Z0-9_]+_pb2)/from . \1/g' $(STUBS_DIR)/*_grpc.py diff --git a/src/funnel/main.py b/src/funnel/main.py new file mode 100644 index 0000000..3cfd5ba --- /dev/null +++ b/src/funnel/main.py @@ -0,0 +1,33 @@ +import logging +import grpc +from stubs import serve_hours_pb2 +from stubs import serve_hours_pb2_grpc + +SERVE_HOURS_HOST = "localhost" +SERVE_HOURS_PORT = 50001 +SERVE_MINUTES_HOST = "localhost" +SERVE_MINUTES_PORT = 50002 +SERVE_SECONDS_HOST = "localhost" +SERVE_SECONDS_PORT = 50003 +SERVE_MILLISECONDS_HOST = "localhost" +SERVE_MILLISECONDS_PORT = 50004 + +TIMEZONE = "Europe/Zagreb" + + +def get_hours() -> int: + with grpc.insecure_channel(f"{SERVE_HOURS_HOST}:{SERVE_HOURS_PORT}") as channel: + stub = serve_hours_pb2_grpc.ServeHoursStub(channel) + response = stub.GetHours(serve_hours_pb2.GetHoursRequest(timezone=TIMEZONE)) + print("GetHours() response: " + response.message) + return response.hours + + +def run(): + hours = get_hours() + print(">>>>>>>>>>>>> Hours:", hours) + + +if __name__ == "__main__": + logging.basicConfig() + run() diff --git a/src/funnel/requirements.txt b/src/funnel/requirements.txt new file mode 100644 index 0000000..a6646e7 --- /dev/null +++ b/src/funnel/requirements.txt @@ -0,0 +1,2 @@ +grpcio +grpcio-tools diff --git a/src/funnel/stubs/__init__.py b/src/funnel/stubs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/src/funnel/stubs/serve_hours_pb2.py b/src/funnel/stubs/serve_hours_pb2.py new file mode 100644 index 0000000..3b31f73 --- /dev/null +++ b/src/funnel/stubs/serve_hours_pb2.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# Generated by the protocol buffer compiler. DO NOT EDIT! +# source: serve_hours.proto +"""Generated protocol buffer code.""" +from google.protobuf.internal import builder as _builder +from google.protobuf import descriptor as _descriptor +from google.protobuf import descriptor_pool as _descriptor_pool +from google.protobuf import symbol_database as _symbol_database +# @@protoc_insertion_point(imports) + +_sym_db = _symbol_database.Default() + + + + +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x11serve_hours.proto\"#\n\x0fGetHoursRequest\x12\x10\n\x08timezone\x18\x01 \x01(\t\"!\n\x10GetHoursResponse\x12\r\n\x05hours\x18\x01 \x01(\r2=\n\nServeHours\x12/\n\x08GetHours\x12\x10.GetHoursRequest\x1a\x11.GetHoursResponseb\x06proto3') + +_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals()) +_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'serve_hours_pb2', globals()) +if _descriptor._USE_C_DESCRIPTORS == False: + + DESCRIPTOR._options = None + _GETHOURSREQUEST._serialized_start=21 + _GETHOURSREQUEST._serialized_end=56 + _GETHOURSRESPONSE._serialized_start=58 + _GETHOURSRESPONSE._serialized_end=91 + _SERVEHOURS._serialized_start=93 + _SERVEHOURS._serialized_end=154 +# @@protoc_insertion_point(module_scope) diff --git a/src/funnel/stubs/serve_hours_pb2.pyi b/src/funnel/stubs/serve_hours_pb2.pyi new file mode 100644 index 0000000..0d9782c --- /dev/null +++ b/src/funnel/stubs/serve_hours_pb2.pyi @@ -0,0 +1,17 @@ +from google.protobuf import descriptor as _descriptor +from google.protobuf import message as _message +from typing import ClassVar as _ClassVar, Optional as _Optional + +DESCRIPTOR: _descriptor.FileDescriptor + +class GetHoursRequest(_message.Message): + __slots__ = ["timezone"] + TIMEZONE_FIELD_NUMBER: _ClassVar[int] + timezone: str + def __init__(self, timezone: _Optional[str] = ...) -> None: ... + +class GetHoursResponse(_message.Message): + __slots__ = ["hours"] + HOURS_FIELD_NUMBER: _ClassVar[int] + hours: int + def __init__(self, hours: _Optional[int] = ...) -> None: ... diff --git a/src/funnel/stubs/serve_hours_pb2_grpc.py b/src/funnel/stubs/serve_hours_pb2_grpc.py new file mode 100644 index 0000000..05933d8 --- /dev/null +++ b/src/funnel/stubs/serve_hours_pb2_grpc.py @@ -0,0 +1,66 @@ +# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT! +"""Client and server classes corresponding to protobuf-defined services.""" +import grpc + +from . import serve_hours_pb2 as serve__hours__pb2 + + +class ServeHoursStub(object): + """Missing associated documentation comment in .proto file.""" + + def __init__(self, channel): + """Constructor. + + Args: + channel: A grpc.Channel. + """ + self.GetHours = channel.unary_unary( + '/ServeHours/GetHours', + request_serializer=serve__hours__pb2.GetHoursRequest.SerializeToString, + response_deserializer=serve__hours__pb2.GetHoursResponse.FromString, + ) + + +class ServeHoursServicer(object): + """Missing associated documentation comment in .proto file.""" + + def GetHours(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + + +def add_ServeHoursServicer_to_server(servicer, server): + rpc_method_handlers = { + 'GetHours': grpc.unary_unary_rpc_method_handler( + servicer.GetHours, + request_deserializer=serve__hours__pb2.GetHoursRequest.FromString, + response_serializer=serve__hours__pb2.GetHoursResponse.SerializeToString, + ), + } + generic_handler = grpc.method_handlers_generic_handler( + 'ServeHours', rpc_method_handlers) + server.add_generic_rpc_handlers((generic_handler,)) + + + # This class is part of an EXPERIMENTAL API. +class ServeHours(object): + """Missing associated documentation comment in .proto file.""" + + @staticmethod + def GetHours(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary(request, target, '/ServeHours/GetHours', + serve__hours__pb2.GetHoursRequest.SerializeToString, + serve__hours__pb2.GetHoursResponse.FromString, + options, channel_credentials, + insecure, call_credentials, compression, wait_for_ready, timeout, metadata) diff --git a/src/protos/serve_current_time.proto b/src/protos/serve_current_time.proto new file mode 100644 index 0000000..e5ca726 --- /dev/null +++ b/src/protos/serve_current_time.proto @@ -0,0 +1,15 @@ +syntax = "proto3"; + +service ServeCurrentTime { + rpc GetCurrentTime(GetCurrentTimeRequest) returns (GetCurrentTimeResponse); +} + +message GetCurrentTimeRequest { string timezone = 1; } + +message GetCurrentTimeResponse { + uint32 hours = 1; + uint32 minutes = 2; + uint32 seconds = 3; + uint32 milliseconds = 4; + string formatted_time = 5; +} diff --git a/src/protos/serve_hours.proto b/src/protos/serve_hours.proto new file mode 100644 index 0000000..fd2750a --- /dev/null +++ b/src/protos/serve_hours.proto @@ -0,0 +1,7 @@ +syntax = "proto3"; + +service ServeHours { rpc GetHours(GetHoursRequest) returns (GetHoursResponse); } + +message GetHoursRequest { string timezone = 1; } + +message GetHoursResponse { uint32 hours = 1; } diff --git a/src/protos/serve_milliseconds.proto b/src/protos/serve_milliseconds.proto new file mode 100644 index 0000000..eb098c2 --- /dev/null +++ b/src/protos/serve_milliseconds.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +service ServeMilliseconds { + rpc GetMilliseconds(GetMillisecondsRequest) returns (GetMillisecondsResponse); +} + +message GetMillisecondsRequest { string timezone = 1; } + +message GetMillisecondsResponse { uint32 milliseconds = 1; } diff --git a/src/protos/serve_minutes.proto b/src/protos/serve_minutes.proto new file mode 100644 index 0000000..85b0323 --- /dev/null +++ b/src/protos/serve_minutes.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +service ServeMinutes { + rpc GetMinutes(GetMinutesRequest) returns (GetMinutesResponse); +} + +message GetMinutesRequest { string timezone = 1; } + +message GetMinutesResponse { uint32 minutes = 1; } diff --git a/src/protos/serve_seconds.proto b/src/protos/serve_seconds.proto new file mode 100644 index 0000000..27aa073 --- /dev/null +++ b/src/protos/serve_seconds.proto @@ -0,0 +1,9 @@ +syntax = "proto3"; + +service ServeSeconds { + rpc GetSeconds(GetSecondsRequest) returns (GetSecondsResponse); +} + +message GetSecondsRequest { string timezone = 1; } + +message GetSecondsResponse { uint32 seconds = 1; }