Skip to content

Commit ea6f8cc

Browse files
authoredMar 11, 2023
Add files via upload
0 parents  commit ea6f8cc

File tree

2 files changed

+340
-0
lines changed

2 files changed

+340
-0
lines changed
 

‎client.py

+207
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
# Author
2+
# Name: Aditya Parab
3+
4+
# Import the socket library
5+
import socket
6+
import json
7+
8+
# Constants for API communication
9+
COMMAND = "command"
10+
STATUS = "status"
11+
PAYLOAD = "payload"
12+
API_RESPONSE_OK = "OK"
13+
API_RESPONSE_EMPTY = "EMPTY"
14+
15+
16+
class Client:
17+
def __init__(self):
18+
# Cache for proxy
19+
self.cache = {}
20+
21+
# Connection host and port
22+
self.SERVER_HOST = "127.0.0.1"
23+
self.SERVER_PORT = 8094
24+
25+
# Socket object
26+
self.socket = None
27+
28+
self.connect_server()
29+
30+
def connect_server(self):
31+
# Create a socket object
32+
self.socket = socket.socket()
33+
# Connect to the server on localhost
34+
print(f"[*] Connecting to {self.SERVER_HOST}:{self.SERVER_PORT} ...")
35+
self.socket.connect((self.SERVER_HOST, self.SERVER_PORT))
36+
print("[+] Connected.")
37+
# Receive data from the server and decoding to get the string.
38+
print("Server reply: ", self.socket.recv(1024).decode())
39+
40+
def process(self, inp):
41+
if inp is None or len(inp.strip()) == 0:
42+
print("*** Invalid command. Enter command from available options ***")
43+
return None
44+
45+
valid = ["GET", "PUT", "DUMP", "EXIT"]
46+
command_list = inp.split(" ", 1)
47+
cmd = command_list[0].upper()
48+
if cmd not in valid:
49+
return self.invalid()
50+
51+
# get name
52+
if cmd == "GET":
53+
if len(command_list) != 2:
54+
return self.invalid()
55+
56+
command_list = command_list[:1] + [_.strip() for _ in command_list[1:]]
57+
return self.get(command_list)
58+
59+
# put name = adi put name=adi
60+
elif cmd == "PUT":
61+
if len(command_list) != 2 or "=" not in command_list[1]:
62+
return self.invalid()
63+
64+
command_list = command_list[:1] + [_.strip() for _ in command_list[1].split("=")]
65+
self.put(command_list)
66+
67+
elif cmd == "DUMP":
68+
self.dump()
69+
70+
elif cmd == "EXIT":
71+
return self.exit()
72+
73+
"""
74+
GET API Request Format
75+
{
76+
"command": "GET",
77+
"payload": "name"
78+
}
79+
80+
GET API Good Response
81+
{
82+
"status": "OK",
83+
"payload": "adi"
84+
}
85+
86+
GET API Error Response
87+
{
88+
"status": "EMPTY",
89+
"payload": NONE
90+
}
91+
"""
92+
93+
def get(self, command_list):
94+
key = command_list[1].upper()
95+
if key in self.cache:
96+
print("Output (From proxy server):", key, "=", self.cache[key])
97+
98+
else:
99+
api_data = {COMMAND: "GET", PAYLOAD: key}
100+
try:
101+
self.socket.send(json.dumps(api_data).encode())
102+
api_response = self.socket.recv(1024).decode()
103+
except Exception as e:
104+
# Client no longer connected remove it from the set
105+
print(f"[!] Error: {e}")
106+
return self.exit()
107+
else:
108+
response = json.loads(api_response)
109+
if response[STATUS] == API_RESPONSE_OK:
110+
self.cache[key] = response[PAYLOAD]
111+
print("Output:", key, "=", response[PAYLOAD])
112+
elif response[STATUS] == API_RESPONSE_EMPTY:
113+
print("Output: Key", key, "not found")
114+
else:
115+
print("Something went wrong!")
116+
117+
return "OK"
118+
119+
"""
120+
PUT API Request Format
121+
{
122+
"command": "PUT"
123+
"payload": {"name":"adi"}
124+
}
125+
126+
PUT API Good Response
127+
{
128+
"status": "OK"
129+
"payload": None
130+
}
131+
"""
132+
133+
def put(self, command_list):
134+
key = command_list[1].upper()
135+
api_data = {COMMAND: "PUT", PAYLOAD: {key: command_list[2]}}
136+
try:
137+
self.socket.send(json.dumps(api_data).encode())
138+
api_response = self.socket.recv(1024).decode()
139+
except Exception as e:
140+
print(f"[!] Error: {e}")
141+
return self.exit()
142+
else:
143+
response = json.loads(api_response)
144+
if response[STATUS] == API_RESPONSE_OK:
145+
print("Request forwarded to the Server.")
146+
self.cache.pop(key, None)
147+
148+
"""
149+
DUMP API Request Format
150+
{
151+
"command": "DUMP"
152+
}
153+
154+
DUMP API Good Response
155+
{
156+
"status": "OK"
157+
"payload": {"name":"adi"}
158+
}
159+
160+
DUMP API Error Response
161+
{
162+
"status": "EMPTY"
163+
"payload": NONE
164+
}
165+
"""
166+
167+
def dump(self):
168+
api_data = {"command": "DUMP"}
169+
try:
170+
self.socket.send(json.dumps(api_data).encode())
171+
api_response = self.socket.recv(1024).decode()
172+
except Exception as e:
173+
# Client no longer connected remove it from the set
174+
print(f"[!] Error: {e}")
175+
return self.exit()
176+
else:
177+
response = json.loads(api_response)
178+
if response[STATUS] == API_RESPONSE_OK:
179+
print("Output:")
180+
for k, v in response[PAYLOAD].items():
181+
print(k, "=", v, end="\n")
182+
elif response[STATUS] == API_RESPONSE_EMPTY:
183+
print("Output: No data found")
184+
else:
185+
print("Something went wrong!")
186+
187+
def invalid(self):
188+
print("*** Invalid command. Enter command from available options following the exact syntax ***")
189+
return None
190+
191+
def exit(self):
192+
# close the connection
193+
self.socket.close()
194+
return "EXIT"
195+
196+
197+
if __name__ == '__main__':
198+
obj = Client()
199+
while True:
200+
inp = input("\nCommand List\n1.PUT (Format: PUT $key = $value)\n"
201+
"2.GET (Format: GET $key)\n"
202+
"3.DUMP (Format: DUMP)\n"
203+
"4.Exit (Format: EXIT)\n"
204+
"Enter your command: ")
205+
result = obj.process(inp)
206+
if result == "EXIT":
207+
break

‎server.py

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
# Author
2+
# Name: Aditya Parab
3+
4+
# Import the socket library
5+
import socket
6+
from threading import Thread
7+
import json
8+
9+
# Constants for API communication
10+
COMMAND = "command"
11+
STATUS = "status"
12+
PAYLOAD = "payload"
13+
API_RESPONSE_OK = "OK"
14+
API_RESPONSE_EMPTY = "EMPTY"
15+
16+
17+
class Server:
18+
def __init__(self):
19+
# initialize set for all connected client's sockets
20+
self.client_sockets = set()
21+
22+
# Server Connection host and port
23+
self.SERVER_HOST = "0.0.0.0"
24+
self.SERVER_PORT = 8094
25+
26+
# Create a socket object
27+
self.socket = socket.socket()
28+
print("Socket successfully created")
29+
30+
# make the port as reusable port
31+
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
32+
# Bind the port
33+
self.socket.bind((self.SERVER_HOST, self.SERVER_PORT))
34+
# Put the socket into listening mode
35+
self.socket.listen(6)
36+
print(f"[*] Listening at {self.SERVER_HOST}:{self.SERVER_PORT}")
37+
38+
self.run()
39+
40+
def listen_for_client(self, cs):
41+
data = {}
42+
# This function keep listening for a message from `cs` socket
43+
while True:
44+
try:
45+
# Keep listening for a message from `cs` socket
46+
msg = cs.recv(1024).decode()
47+
if not msg:
48+
host, port = cs.getpeername()
49+
print(f"[-] Disconnecting client ('{host}', {port})")
50+
cs.close()
51+
self.client_sockets.remove(cs)
52+
break
53+
except Exception as e:
54+
# Client no longer connected remove it from the set
55+
print(f"[!] Error: {e}")
56+
self.client_sockets.remove(cs)
57+
else:
58+
# if we received a message
59+
result = self.process(data, msg)
60+
cs.send(result.encode())
61+
62+
# Request
63+
# {
64+
# "command": "PUT"
65+
# "payload": {"name":"adi"}
66+
# }
67+
68+
# Request
69+
# {
70+
# "command": "GET"
71+
# "payload": "name"
72+
# }
73+
74+
# Response
75+
# {
76+
# "status": "OK"
77+
# "payload": {"name":"adi"}
78+
# }
79+
80+
# Error Response
81+
# {
82+
# "status": "EMPTY"
83+
# "payload": NONE
84+
# }
85+
def process(self, data, msg):
86+
data_rcv = json.loads(msg)
87+
command = data_rcv[COMMAND]
88+
89+
if command == "PUT":
90+
data.update(data_rcv[PAYLOAD])
91+
return json.dumps({STATUS: API_RESPONSE_OK, PAYLOAD: None})
92+
93+
elif command == "GET":
94+
key = data_rcv[PAYLOAD]
95+
if key in data:
96+
return json.dumps({STATUS: API_RESPONSE_OK, PAYLOAD: data[key]})
97+
else:
98+
return json.dumps({STATUS: API_RESPONSE_EMPTY, PAYLOAD: None})
99+
100+
elif command == "DUMP":
101+
if data:
102+
return json.dumps({STATUS: API_RESPONSE_OK, PAYLOAD: data})
103+
else:
104+
return json.dumps({STATUS: API_RESPONSE_EMPTY, PAYLOAD: None})
105+
106+
def run(self):
107+
while True:
108+
# Keep listening for new connections all the time
109+
client_socket, client_address = self.socket.accept()
110+
print(f"[+] {client_address} connected.")
111+
client_socket.send('Connection established. Session Started.'.encode())
112+
113+
# Add the new connected client to connected sockets
114+
self.client_sockets.add(client_socket)
115+
116+
# Start a new thread that listens for each client's messages
117+
t = Thread(target=self.listen_for_client, args=(client_socket,))
118+
119+
# Make the thread daemon, so it ends whenever the main thread ends
120+
t.daemon = True
121+
122+
# Start the thread
123+
t.start()
124+
125+
# # close client sockets
126+
# for cs in client_sockets:
127+
# cs.close()
128+
# # close server socket
129+
# s.close()
130+
131+
132+
if __name__ == '__main__':
133+
serverObj = Server()

0 commit comments

Comments
 (0)
Please sign in to comment.