Initial
This commit is contained in:
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
__pycache__
|
||||||
|
/dist
|
||||||
|
/src/funnel/env
|
||||||
95
README.md
Normal file
95
README.md
Normal file
@ -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
|
||||||
|
```
|
||||||
|
|
||||||
18
src/funnel/Makefile
Normal file
18
src/funnel/Makefile
Normal file
@ -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
|
||||||
33
src/funnel/main.py
Normal file
33
src/funnel/main.py
Normal file
@ -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()
|
||||||
2
src/funnel/requirements.txt
Normal file
2
src/funnel/requirements.txt
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
grpcio
|
||||||
|
grpcio-tools
|
||||||
0
src/funnel/stubs/__init__.py
Normal file
0
src/funnel/stubs/__init__.py
Normal file
29
src/funnel/stubs/serve_hours_pb2.py
Normal file
29
src/funnel/stubs/serve_hours_pb2.py
Normal file
@ -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)
|
||||||
17
src/funnel/stubs/serve_hours_pb2.pyi
Normal file
17
src/funnel/stubs/serve_hours_pb2.pyi
Normal file
@ -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: ...
|
||||||
66
src/funnel/stubs/serve_hours_pb2_grpc.py
Normal file
66
src/funnel/stubs/serve_hours_pb2_grpc.py
Normal file
@ -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)
|
||||||
15
src/protos/serve_current_time.proto
Normal file
15
src/protos/serve_current_time.proto
Normal file
@ -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;
|
||||||
|
}
|
||||||
7
src/protos/serve_hours.proto
Normal file
7
src/protos/serve_hours.proto
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
service ServeHours { rpc GetHours(GetHoursRequest) returns (GetHoursResponse); }
|
||||||
|
|
||||||
|
message GetHoursRequest { string timezone = 1; }
|
||||||
|
|
||||||
|
message GetHoursResponse { uint32 hours = 1; }
|
||||||
9
src/protos/serve_milliseconds.proto
Normal file
9
src/protos/serve_milliseconds.proto
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
service ServeMilliseconds {
|
||||||
|
rpc GetMilliseconds(GetMillisecondsRequest) returns (GetMillisecondsResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetMillisecondsRequest { string timezone = 1; }
|
||||||
|
|
||||||
|
message GetMillisecondsResponse { uint32 milliseconds = 1; }
|
||||||
9
src/protos/serve_minutes.proto
Normal file
9
src/protos/serve_minutes.proto
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
service ServeMinutes {
|
||||||
|
rpc GetMinutes(GetMinutesRequest) returns (GetMinutesResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetMinutesRequest { string timezone = 1; }
|
||||||
|
|
||||||
|
message GetMinutesResponse { uint32 minutes = 1; }
|
||||||
9
src/protos/serve_seconds.proto
Normal file
9
src/protos/serve_seconds.proto
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
service ServeSeconds {
|
||||||
|
rpc GetSeconds(GetSecondsRequest) returns (GetSecondsResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetSecondsRequest { string timezone = 1; }
|
||||||
|
|
||||||
|
message GetSecondsResponse { uint32 seconds = 1; }
|
||||||
Reference in New Issue
Block a user