Skip to content

Commit e3fb561

Browse files
author
apinanyogaratnam
committed
feat: created cachier client class
1 parent 61f1e7b commit e3fb561

1 file changed

Lines changed: 115 additions & 0 deletions

File tree

cachier_client/main.py

Lines changed: 115 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,117 @@
1+
import json
2+
import socket
3+
from typing import Union
4+
5+
6+
class RequestError(Exception):
7+
pass
8+
9+
10+
class ServerError(Exception):
11+
pass
12+
13+
14+
class CachierClient:
15+
def __init__(self: "CachierClient", host: str, port: str) -> None:
16+
self.host = host
17+
self.port = port
18+
self.sock = None
19+
20+
def connect(self: "CachierClient") -> socket.socket:
21+
sock = socket.socket()
22+
sock.connect((self.host, self.port))
23+
24+
self.sock = sock
25+
26+
return self
27+
28+
def get_server_response(self: "CachierClient") -> str:
29+
return self.sock.recv(1024).decode()
30+
31+
def guard_invalid_connection(self: "CachierClient") -> None:
32+
if self.sock is None:
33+
raise ConnectionError("you must connect to the server first.")
34+
35+
def guard_closed_connection(self: "CachierClient", data: str) -> None:
36+
if not data:
37+
raise ConnectionError("connection to the server is closed.")
38+
39+
def guard_request_error(self: "CachierClient", data: str) -> None:
40+
status = data.get("status")
41+
if not status:
42+
raise ServerError(f"server returned invalid response {data}. please report this.")
43+
44+
if status == "error":
45+
raise RequestError(data.get("message", "unknown error occurred. please report this."))
46+
47+
def send(self: "CachierClient", message: str) -> None:
48+
self.guard_invalid_connection()
49+
50+
if not isinstance(message, str):
51+
raise TypeError("message must be a string.")
52+
53+
self.sock.send((message + "\n").encode())
54+
55+
def get(self: "CachierClient", key: str) -> Union[str, None]:
56+
self.guard_invalid_connection()
57+
58+
if not isinstance(key, str):
59+
raise TypeError("key must be a string.")
60+
61+
request = {
62+
"command": "get",
63+
"key": key,
64+
}
65+
66+
self.send(json.dumps(request))
67+
68+
data = self.get_server_response()
69+
self.guard_closed_connection(data)
70+
71+
serialized_data = json.loads(data)
72+
self.guard_request_error(serialized_data)
73+
74+
# value can be empty string, so we need to check if it's present
75+
return serialized_data.get("value") or None
76+
77+
def set(self: "CachierClient", key: str, value: str, ttl: Union[int, None]) -> None:
78+
self.guard_invalid_connection()
79+
80+
if not isinstance(key, str):
81+
raise TypeError("Key must be a string.")
82+
83+
if not isinstance(value, str):
84+
raise TypeError("Value must be a string.")
85+
86+
if ttl is not None and not isinstance(ttl, int):
87+
raise TypeError("TTL must be an integer.")
88+
89+
request = {
90+
"command": "set",
91+
"key": key,
92+
"value": value,
93+
"ttl": ttl,
94+
}
95+
96+
self.send(json.dumps(request))
97+
98+
data = self.get_server_response()
99+
self.guard_closed_connection(data)
100+
101+
serialized_data = json.loads(data)
102+
self.guard_request_error(serialized_data)
103+
104+
1105
def greetings():
2106
return "Hello, World!"
107+
108+
109+
if __name__ == '__main__':
110+
client = CachierClient("localhost", 8080).connect()
111+
112+
print("should be None:", client.get("greetings"))
113+
client.set("greetings", "Hello, World!", 10)
114+
print("should be something:", client.get("greetings"))
115+
import time
116+
time.sleep(11)
117+
print("should be None:", client.get("greetings"))

0 commit comments

Comments
 (0)