-
Notifications
You must be signed in to change notification settings - Fork 3
Expand file tree
/
Copy pathprotocol.py
More file actions
164 lines (112 loc) · 5.07 KB
/
protocol.py
File metadata and controls
164 lines (112 loc) · 5.07 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
#!/usr/bin/env python3
import enum
import typing
import channel
class ProtocolException(Exception):
MAX_RESPONSE_LENGTH = 1024
def __init__(self, message: str, response: str = ''):
super().__init__()
self.message = message
self.response = response[:self.MAX_RESPONSE_LENGTH]
class PingResponse(enum.Enum):
SUCCESS = enum.auto()
class RegisterResponse(enum.Enum):
ALREADY_REGISTERED = enum.auto()
SUCCESS = enum.auto()
class LoginResponse(enum.Enum):
DOES_NOT_EXIST = enum.auto()
INVALID_PASSWORD = enum.auto()
SUCCESS = enum.auto()
class LogoutResponse(enum.Enum):
SUCCESS = enum.auto()
class GetResponse(enum.Enum):
USER_DOES_NOT_EXIST = enum.auto()
PROPERTY_DOES_NOT_EXIST = enum.auto()
SUCCESS = enum.auto()
class PutResponse(enum.Enum):
WRONG_USER = enum.auto()
USER_DOES_NOT_EXIST = enum.auto()
PROPERTY_ALREADY_EXISTS = enum.auto()
SUCCESS = enum.auto()
class ExitResponse(enum.Enum):
SUCCESS = enum.auto()
class VirushProtocol:
def __init__(self, channel: channel.Channel) -> None:
self.channel = channel
async def ping(self) -> PingResponse:
await self.channel.sendline(f'PING')
response = await self.channel.recvline()
if response == f'SUCCESS: PONG':
return PingResponse.SUCCESS
raise ProtocolException('wrong response for ping', response)
async def register(self, username: str, password: str) -> RegisterResponse:
await self.channel.sendline(f'REGISTER')
await self.channel.sendline(f'{username} {password}')
response = await self.channel.recvline()
if response == f'ERROR: USER {username} IS ALREADY REGISTERED':
return RegisterResponse.ALREADY_REGISTERED
elif response == f'SUCCESS: USER {username} HAS BEEN REGISTERED':
return RegisterResponse.SUCCESS
raise ProtocolException('wrong response for register', response)
async def login(self, username: str, password: str) -> LoginResponse:
await self.channel.sendline(f'LOGIN')
await self.channel.sendline(f'{username} {password}')
response = await self.channel.recvline()
if response == f'ERROR: USER {username} DOES NOT EXIST':
return LoginResponse.DOES_NOT_EXIST
elif response == f'ERROR: INVALID PASSWORD FOR USER {username}':
return LoginResponse.INVALID_PASSWORD
elif response == f'SUCCESS: LOGGED IN AS {username}':
return LoginResponse.SUCCESS
raise ProtocolException('wrong response for login', response)
async def logout(self) -> LogoutResponse:
await self.channel.sendline(f'LOGOUT')
response = await self.channel.recvline()
if response == f'SUCCESS: LOGGED OUT':
return LogoutResponse.SUCCESS
raise ProtocolException('wrong response for logout', response)
async def get(
self, username: str, property_name: str, encrypted: bool,
) -> typing.Tuple[GetResponse, typing.Optional[str]]:
mode = 'ENCRYPTED' if encrypted else ''
await self.channel.sendline(f'GET')
await self.channel.sendline(f'{username} {property_name} {mode}')
response = await self.channel.recvline()
if response == f'ERROR: USER {username} DOES NOT EXIST':
result = GetResponse.USER_DOES_NOT_EXIST
elif response == f'ERROR: {property_name} DOES NOT EXIST FOR USER {username}':
result = GetResponse.PROPERTY_DOES_NOT_EXIST
elif response == f'SUCCESS: TRYING TO GET {property_name} FROM USER {username}':
result = GetResponse.SUCCESS
else:
raise ProtocolException('wrong response for get', response)
return result, (
await self.channel.recvline()
if result is GetResponse.SUCCESS
else None
)
async def put(
self, username: str, property_name: str, encrypted: bool, data: str = '',
) -> PutResponse:
mode = 'ENCRYPTED' if encrypted else ''
await self.channel.sendline(f'PUT')
await self.channel.sendline(f'{username} {property_name} {mode}')
response = await self.channel.recvline()
if response == f'ERROR: YOU ARE NOT {username}':
return PutResponse.WRONG_USER
elif response == f'ERROR: USER {username} DOES NOT EXIST':
return PutResponse.USER_DOES_NOT_EXIST
elif response == f'ERROR: {property_name} ALREADY EXISTS FOR USER {username}':
return PutResponse.PROPERTY_ALREADY_EXISTS
elif response == f'SUCCESS: TRYING TO PUT {property_name} TO USER {username}':
result = PutResponse.SUCCESS
else:
raise ProtocolException('wrong response for put', response)
await self.channel.sendline(data)
return result
async def exit(self) -> None:
await self.channel.sendline(f'EXIT')
response = await self.channel.recvline()
if response == f'SUCCESS: BYE':
return ExitResponse.SUCCESS
raise ProtocolException('wrong response for exit', response)