-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathclient.py
More file actions
202 lines (172 loc) · 8.84 KB
/
client.py
File metadata and controls
202 lines (172 loc) · 8.84 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
import socket
import api
import argparse
import api
# region Predefined
# The following are for convenience. You can use them to build expressions.
pi_c = api.NAMED_CONSTANTS.PI
tau_c = api.NAMED_CONSTANTS.TAU
e_c = api.NAMED_CONSTANTS.E
add_b = api.BINARY_OPERATORS.ADD
sub_b = api.BINARY_OPERATORS.SUB
mul_b = api.BINARY_OPERATORS.MUL
div_b = api.BINARY_OPERATORS.DIV
mod_b = api.BINARY_OPERATORS.MOD
pow_b = api.BINARY_OPERATORS.POW
neg_u = api.UNARY_OPERATORS.NEG
pos_u = api.UNARY_OPERATORS.POS
sin_f = api.FUNCTIONS.SIN
cos_f = api.FUNCTIONS.COS
tan_f = api.FUNCTIONS.TAN
sqrt_f = api.FUNCTIONS.SQRT
log_f = api.FUNCTIONS.LOG
max_f = api.FUNCTIONS.MAX
min_f = api.FUNCTIONS.MIN
pow_f = api.FUNCTIONS.POW
rand_f = api.FUNCTIONS.RAND
# endregion
def process_response(response: api.CalculatorHeader) -> None:
if response.is_request:
raise api.CalculatorClientError("Got a request instead of a response")
if response.status_code == api.CalculatorHeader.STATUS_OK:
result, steps = api.data_to_result(response)
print("Result:", result)
if steps:
print("Steps:")
expr, first, *rest = steps
print(f"{expr} = {first}", end="\n"*(not bool(rest)))
if rest:
print(
"".join(map(lambda v: f"\n{' ' * len(expr)} = {v}", rest)))
elif response.status_code == api.CalculatorHeader.STATUS_CLIENT_ERROR:
err = api.data_to_error(response)
raise api.CalculatorClientError(err)
elif response.status_code == api.CalculatorHeader.STATUS_SERVER_ERROR:
err = api.data_to_error(response)
raise api.CalculatorServerError(err)
else:
raise api.CalculatorClientError(
f"Unknown status code: {response.status_code}")
def client(server_address: tuple[str, int], expression: api.Expression, show_steps: bool = False, cache_result: bool = False, cache_control: int = api.CalculatorHeader.MAX_CACHE_CONTROL) -> None:
server_prefix = f"{{{server_address[0]}:{server_address[1]}}}"
with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as client_socket:
client_socket.connect(server_address)
print(f"\n{server_prefix} Connection established")
###add#### (1)
# we don't want that the connection will close until the client decide to with typing 0
#so we pading it in with while True loop
while True:
###add#### (1)
try:
request = api.CalculatorHeader.from_expression(
expression, show_steps, cache_result, cache_control)
request = request.pack()
print(f"{server_prefix} Sending request of length {len(request)} bytes")
client_socket.sendall(request)
response = client_socket.recv(api.BUFFER_SIZE)
print(f"{server_prefix} Got response of length {len(response)} bytes")
response = api.CalculatorHeader.unpack(response)
process_response(response)
except api.CalculatorError as e:
print(f"{server_prefix} Got error: {str(e)}")
except Exception as e:
print(f"{server_prefix} Unexpected error: {str(e)}")
###add#### (2)
# After the first calculation we except new input from the client
# we're showing the menu of the expressions and ask him if he wants to show steps
# we check if the input is a number (int) in the range of the expressions list or 0
# if the number is 0 we break from the loop and close the connection
# else we send the expression to calculating
print("\nTo open the connection Enter a number for calculate (1-6) or 0 to exit: ")
showMenu()
client_input = input()
while (not client_input.isdigit() or int(client_input) < 0 or int(client_input) > 6):
print("This is not between 1 to 6, and not 0")
client_input = input("Enter a number for calculate(1-6), or 0 to exit: ")
if int(client_input) == 0:
break
steps = input("do you want to see the steps? if yes press 'y' if not press something else: ")
if steps == 'y':
show_steps = True
else:
show_steps = False
expression = expressions[int(client_input) - 1]
###add#### (2)
print(f"{server_prefix} Connection closed")
if __name__ == "__main__":
arg_parser = argparse.ArgumentParser(description="A Calculator Client.")
# we change after 3.1 question to proxy port & host
arg_parser.add_argument("-p", "--port", type=int,
default=api.DEFAULT_SERVER_PORT, help="The port to connect to.")
arg_parser.add_argument("-H", "--host", type=str,
default=api.DEFAULT_SERVER_HOST, help="The host to connect to.")
args = arg_parser.parse_args()
host = args.host
port = args.port
# * Change in start (1)
# Example expressions: (uncomment one of them for your needs)
# (1) '(sin(max(2, 3 * 4, 5, 6 * ((7 * 8) / 9), 10 / 11)) / 12) * 13' = -0.38748277824137206
#expr = mul_b(div_b(sin_f(max_f(2, mul_b(3, 4), 5, mul_b(
# 6, div_b(mul_b(7, 8), 9)), div_b(10, 11))), 12), 13) # (1)
# (2) '(max(2, 3) + 3)' = 6
#expr = add_b(max_f(2, 3), 3) # (2)
# (3) '3 + ((4 * 2) / ((1 - 5) ** (2 ** 3)))' = 3.0001220703125
# expr = add_b(3, div_b(mul_b(4, 2), pow_b(sub_b(1, 5), pow_b(2, 3)))) # (3)
# (4) '((1 + 2) ** (3 * 4)) / (5 * 6)' = 17714.7
# expr = div_b(pow_b(add_b(1, 2), mul_b(3, 4)), mul_b(5, 6)) # (4)
# (5) '-(-((1 + (2 + 3)) ** -(4 + 5)))' = 9.92290301275212e-08
# expr = neg_u(neg_u(pow_b(add_b(1, add_b(2, 3)), neg_u(add_b(4, 5))))) # (5)
# (6) 'max(2, (3 * 4), log(e), (6 * 7), (9 / 8))' = 42
# expr = max_f(2, mul_b(3, 4), log_f(e_c), mul_b(6, 7), div_b(9, 8)) # (6)
###add#### (3)
# we create a list of the expressions and this is for that user will just choose one of them
expressions = [
mul_b(div_b(sin_f(max_f(2, mul_b(3, 4), 5, mul_b(
6, div_b(mul_b(7, 8), 9)), div_b(10, 11))), 12), 13) , # (1)
add_b(max_f(2, 3), 3) , # (2)
add_b(3, div_b(mul_b(4, 2), pow_b(sub_b(1, 5), pow_b(2, 3)))) , # (3)
div_b(pow_b(add_b(1, 2), mul_b(3, 4)), mul_b(5, 6)), # (4)
neg_u(neg_u(pow_b(add_b(1, add_b(2, 3)), neg_u(add_b(4, 5))))) , # (5)
max_f(2, mul_b(3, 4), log_f(e_c), mul_b(6, 7), div_b(9, 8)) , # (6)
]
# This function print the menu of the expressions
def showMenu() -> None:
print("\n"
"1. mul_b(div_b(sin_f(max_f(2, mul_b(3, 4), 5, mul_b(6, div_b(mul_b(7, 8), 9)), div_b(10, 11))), 12), 13) \n"
"2. add_b(max_f(2, 3), 3)\n"
"3. add_b(3, div_b(mul_b(4, 2), pow_b(sub_b(1, 5), pow_b(2, 3)))) \n"
"4. div_b(pow_b(add_b(1, 2), mul_b(3, 4)), mul_b(5, 6)) \n"
"5. neg_u(neg_u(pow_b(add_b(1, add_b(2, 3)), neg_u(add_b(4, 5)))))\n"
"6. max_f(2, mul_b(3, 4), log_f(e_c), mul_b(6, 7), div_b(9, 8)) \n")
###add#### (3)
# * Change in end (1)
# Change the following values according to your needs:
show_steps = True # Request the steps of the calculation
cache_result = True # Request to cache the result of the calculation
# If the result is cached, this is the maximum age of the cached response
# that the client is willing to accept (in seconds)
cache_control = 2**16 - 1
# * Change in start (2)
###add#### (4)
# we're showing the menu of the expressions and wait for input from the client
# we check if the input is a number (int) in the range of the expressions list
# if the number in the range we continue
# else we wait for legal input
# we ask him if he wants to show steps
# we send the expression that fit to the number to client function with other parameters
# in this action we start the connection with server/proxy
print("To open the connection Enter a number for calculate (1-6): ")
showMenu()
client_input = input()
while(not client_input.isdigit() or int(client_input)<1 or int(client_input)>6):
print("This is not between 1 to 6!!!")
client_input = input("To open the connection enter a number for calculate(1-6): ")
steps = input("do you want to see the steps? if yes press 'y' if not press something else: ")
if steps == 'y':
show_steps = True
else:
show_steps = False
expr = expressions[int(client_input)-1]
###add#### (4)
client((host, port), expr, show_steps, cache_result, cache_control)
# * Change in end (2)