You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
166 lines
5.1 KiB
166 lines
5.1 KiB
#! env/bin/python3
|
|
import sys
|
|
import asyncio
|
|
import aiohttp
|
|
import logging
|
|
|
|
from typing import List, Tuple, Any
|
|
|
|
|
|
loop = asyncio.get_event_loop()
|
|
|
|
|
|
SERVER_DOMAIN = "http://127.0.0.1:2007"
|
|
|
|
|
|
LOG_LEVELS = {logging.ERROR: "ERROR",
|
|
logging.INFO: "INFO",
|
|
logging.WARNING: "WARNING",
|
|
logging.DEBUG: "DEBUG",
|
|
logging.CRITICAL: "CRITICAL",
|
|
}
|
|
|
|
|
|
async def check_server(client: aiohttp.ClientSession):
|
|
try:
|
|
async with client.get(f"{SERVER_DOMAIN}/") as response:
|
|
assert response.status == 200
|
|
|
|
data = await response.json()
|
|
assert data == {"status": "active"}
|
|
|
|
print(f"Connected to the Calculate Server on {SERVER_DOMAIN}")
|
|
return True
|
|
except Exception:
|
|
print("Can not connect to the calculate server.")
|
|
return False
|
|
|
|
|
|
async def get_commands(client: aiohttp.ClientSession):
|
|
async with client.get(f"{SERVER_DOMAIN}/commands") as response:
|
|
assert response.status == 200
|
|
data = await response.json()
|
|
return data
|
|
|
|
|
|
async def create_worker(client: aiohttp.ClientSession, command: str,
|
|
arguments: List[str]):
|
|
worker_args = {"arguments": arguments}
|
|
async with client.post(f"{SERVER_DOMAIN}/workers/{command}",
|
|
json=worker_args) as response:
|
|
assert response.status == 200
|
|
data = await response.json()
|
|
return data["wid"]
|
|
|
|
|
|
async def start_worker(client: aiohttp.ClientSession, wid: int):
|
|
async with client.post(f"{SERVER_DOMAIN}/workers/{wid}/start") as response:
|
|
assert response.status == 200
|
|
data = await response.json()
|
|
return data
|
|
|
|
|
|
async def get_worker_messages(client: aiohttp.ClientSession, wid: int):
|
|
async with client.get(f"{SERVER_DOMAIN}/workers/{wid}/messages"
|
|
) as response:
|
|
assert response.status == 200
|
|
data = await response.json()
|
|
return data["data"]
|
|
|
|
|
|
async def send_data_to_worker(client: aiohttp.ClientSession, wid: int,
|
|
data: Any):
|
|
first_try = True
|
|
while True:
|
|
answer = {"data": data}
|
|
try:
|
|
async with client.post(f"{SERVER_DOMAIN}/workers/{wid}/send",
|
|
json=answer) as response:
|
|
assert response.status == 200
|
|
data = await response.json()
|
|
return
|
|
except aiohttp.client_exceptions.ClientOSError:
|
|
if first_try:
|
|
first_try = False
|
|
continue
|
|
else:
|
|
raise
|
|
# return data
|
|
|
|
|
|
async def finish_worker(client: aiohttp.ClientSession, wid: int):
|
|
async with client.post(f"{SERVER_DOMAIN}/workers/{wid}/finish"
|
|
) as response:
|
|
assert response.status == 200
|
|
data = await response.json()
|
|
return data
|
|
|
|
|
|
async def main():
|
|
print("Calculate Console Client 0.0.1")
|
|
async with aiohttp.ClientSession(
|
|
connector=aiohttp.TCPConnector(force_close=False)) as client:
|
|
if not await check_server(client):
|
|
return
|
|
|
|
commands = await get_commands(client)
|
|
command, command_args = get_console_command()
|
|
message = check_command(command, commands)
|
|
if message:
|
|
print(message)
|
|
return
|
|
|
|
wid = await create_worker(client, command, command_args)
|
|
try:
|
|
print("CREATED WORKER ID:", wid)
|
|
status_data = await start_worker(client, wid)
|
|
if status_data.get("status", None) == "error":
|
|
print("ERROR:", status_data.get("description", "NONE"))
|
|
return
|
|
|
|
finished = False
|
|
while not finished:
|
|
messages = await get_worker_messages(client, wid)
|
|
for message in messages:
|
|
if message["type"] == "output":
|
|
print(f"{LOG_LEVELS[message['level']]}:"
|
|
f" {message['msg']}")
|
|
elif message["type"] == "input":
|
|
print(message["msg"])
|
|
input_data = input(">> ")
|
|
await send_data_to_worker(client, wid, input_data)
|
|
elif (message["type"] == "control"
|
|
and message["action"] == "finish"):
|
|
finished = True
|
|
finally:
|
|
await finish_worker(client, wid)
|
|
|
|
|
|
def get_console_command() -> Tuple[str, List[str]]:
|
|
offset = 1 if sys.argv[0].endswith("client.py") else 0
|
|
|
|
if len(sys.argv) < 1 + offset:
|
|
command = None
|
|
command_args = []
|
|
else:
|
|
command = sys.argv[offset]
|
|
command_args = sys.argv[1 + offset:]
|
|
|
|
return command, command_args
|
|
|
|
|
|
def check_command(command: str, available_commands: List[str]) -> str:
|
|
if command is None:
|
|
return "Command is not set."
|
|
if command not in available_commands:
|
|
return "Command is not available."
|
|
return ''
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
loop.run_until_complete(main())
|
|
except KeyboardInterrupt:
|
|
print("\r<< Keyboard interrupt.")
|
|
loop.close()
|