blob: 35a97687fbe357c0f0bdd1a7f8ee837c76f22889 [file] [log] [blame]
Brad Bishopa34c0302019-09-23 22:34:48 -04001# Copyright (C) 2019 Garmin Ltd.
2#
3# SPDX-License-Identifier: GPL-2.0-only
4#
5
Brad Bishopa34c0302019-09-23 22:34:48 -04006import logging
7import socket
Andrew Geisslerc926e172021-05-07 16:11:35 -05008import bb.asyncrpc
Patrick Williamsac13d5f2023-11-24 18:59:46 -06009import json
Andrew Geisslerc926e172021-05-07 16:11:35 -050010from . import create_async_client
Brad Bishopa34c0302019-09-23 22:34:48 -040011
12
Andrew Geissler6ce62a22020-11-30 19:58:47 -060013logger = logging.getLogger("hashserv.client")
Brad Bishopa34c0302019-09-23 22:34:48 -040014
15
Andrew Geisslerc926e172021-05-07 16:11:35 -050016class AsyncClient(bb.asyncrpc.AsyncClient):
Brad Bishopa34c0302019-09-23 22:34:48 -040017 MODE_NORMAL = 0
18 MODE_GET_STREAM = 1
19
Patrick Williamsac13d5f2023-11-24 18:59:46 -060020 def __init__(self, username=None, password=None):
21 super().__init__("OEHASHEQUIV", "1.1", logger)
Brad Bishopa34c0302019-09-23 22:34:48 -040022 self.mode = self.MODE_NORMAL
Patrick Williamsac13d5f2023-11-24 18:59:46 -060023 self.username = username
24 self.password = password
25 self.saved_become_user = None
Brad Bishopa34c0302019-09-23 22:34:48 -040026
Andrew Geisslerc926e172021-05-07 16:11:35 -050027 async def setup_connection(self):
28 await super().setup_connection()
29 cur_mode = self.mode
30 self.mode = self.MODE_NORMAL
31 await self._set_mode(cur_mode)
Patrick Williamsac13d5f2023-11-24 18:59:46 -060032 if self.username:
33 # Save off become user temporarily because auth() resets it
34 become = self.saved_become_user
35 await self.auth(self.username, self.password)
36
37 if become:
38 await self.become_user(become)
Brad Bishopa34c0302019-09-23 22:34:48 -040039
Andrew Geissler6ce62a22020-11-30 19:58:47 -060040 async def send_stream(self, msg):
41 async def proc():
Patrick Williamsac13d5f2023-11-24 18:59:46 -060042 await self.socket.send(msg)
43 return await self.socket.recv()
Brad Bishopa34c0302019-09-23 22:34:48 -040044
Andrew Geissler6ce62a22020-11-30 19:58:47 -060045 return await self._send_wrapper(proc)
Brad Bishopa34c0302019-09-23 22:34:48 -040046
Andrew Geissler6ce62a22020-11-30 19:58:47 -060047 async def _set_mode(self, new_mode):
Patrick Williamsac13d5f2023-11-24 18:59:46 -060048 async def stream_to_normal():
49 await self.socket.send("END")
50 return await self.socket.recv()
51
Brad Bishopa34c0302019-09-23 22:34:48 -040052 if new_mode == self.MODE_NORMAL and self.mode == self.MODE_GET_STREAM:
Patrick Williamsac13d5f2023-11-24 18:59:46 -060053 r = await self._send_wrapper(stream_to_normal)
Andrew Geissler6ce62a22020-11-30 19:58:47 -060054 if r != "ok":
Patrick Williamsac13d5f2023-11-24 18:59:46 -060055 self.check_invoke_error(r)
56 raise ConnectionError("Unable to transition to normal mode: Bad response from server %r" % r)
Brad Bishopa34c0302019-09-23 22:34:48 -040057 elif new_mode == self.MODE_GET_STREAM and self.mode == self.MODE_NORMAL:
Patrick Williamsac13d5f2023-11-24 18:59:46 -060058 r = await self.invoke({"get-stream": None})
Andrew Geissler6ce62a22020-11-30 19:58:47 -060059 if r != "ok":
Patrick Williamsac13d5f2023-11-24 18:59:46 -060060 raise ConnectionError("Unable to transition to stream mode: Bad response from server %r" % r)
Brad Bishopa34c0302019-09-23 22:34:48 -040061 elif new_mode != self.mode:
Andrew Geissler6ce62a22020-11-30 19:58:47 -060062 raise Exception(
63 "Undefined mode transition %r -> %r" % (self.mode, new_mode)
64 )
Brad Bishopa34c0302019-09-23 22:34:48 -040065
66 self.mode = new_mode
67
Andrew Geissler6ce62a22020-11-30 19:58:47 -060068 async def get_unihash(self, method, taskhash):
69 await self._set_mode(self.MODE_GET_STREAM)
70 r = await self.send_stream("%s %s" % (method, taskhash))
Brad Bishopa34c0302019-09-23 22:34:48 -040071 if not r:
72 return None
73 return r
74
Andrew Geissler6ce62a22020-11-30 19:58:47 -060075 async def report_unihash(self, taskhash, method, outhash, unihash, extra={}):
76 await self._set_mode(self.MODE_NORMAL)
Brad Bishopa34c0302019-09-23 22:34:48 -040077 m = extra.copy()
Andrew Geissler6ce62a22020-11-30 19:58:47 -060078 m["taskhash"] = taskhash
79 m["method"] = method
80 m["outhash"] = outhash
81 m["unihash"] = unihash
Patrick Williamsac13d5f2023-11-24 18:59:46 -060082 return await self.invoke({"report": m})
Brad Bishopa34c0302019-09-23 22:34:48 -040083
Andrew Geissler6ce62a22020-11-30 19:58:47 -060084 async def report_unihash_equiv(self, taskhash, method, unihash, extra={}):
85 await self._set_mode(self.MODE_NORMAL)
Andrew Geissler82c905d2020-04-13 13:39:40 -050086 m = extra.copy()
Andrew Geissler6ce62a22020-11-30 19:58:47 -060087 m["taskhash"] = taskhash
88 m["method"] = method
89 m["unihash"] = unihash
Patrick Williamsac13d5f2023-11-24 18:59:46 -060090 return await self.invoke({"report-equiv": m})
Andrew Geissler82c905d2020-04-13 13:39:40 -050091
Andrew Geissler6ce62a22020-11-30 19:58:47 -060092 async def get_taskhash(self, method, taskhash, all_properties=False):
93 await self._set_mode(self.MODE_NORMAL)
Patrick Williamsac13d5f2023-11-24 18:59:46 -060094 return await self.invoke(
Andrew Geissler6ce62a22020-11-30 19:58:47 -060095 {"get": {"taskhash": taskhash, "method": method, "all": all_properties}}
96 )
Andrew Geissler475cb722020-07-10 16:00:51 -050097
Andrew Geissler20137392023-10-12 04:59:14 -060098 async def get_outhash(self, method, outhash, taskhash, with_unihash=True):
Andrew Geisslerd1e89492021-02-12 15:35:20 -060099 await self._set_mode(self.MODE_NORMAL)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600100 return await self.invoke(
101 {
102 "get-outhash": {
103 "outhash": outhash,
104 "taskhash": taskhash,
105 "method": method,
106 "with_unihash": with_unihash,
107 }
108 }
Andrew Geisslerd1e89492021-02-12 15:35:20 -0600109 )
110
Andrew Geissler6ce62a22020-11-30 19:58:47 -0600111 async def get_stats(self):
112 await self._set_mode(self.MODE_NORMAL)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600113 return await self.invoke({"get-stats": None})
Brad Bishopa34c0302019-09-23 22:34:48 -0400114
Andrew Geissler6ce62a22020-11-30 19:58:47 -0600115 async def reset_stats(self):
116 await self._set_mode(self.MODE_NORMAL)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600117 return await self.invoke({"reset-stats": None})
Andrew Geissler6ce62a22020-11-30 19:58:47 -0600118
119 async def backfill_wait(self):
120 await self._set_mode(self.MODE_NORMAL)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600121 return (await self.invoke({"backfill-wait": None}))["tasks"]
Andrew Geissler6ce62a22020-11-30 19:58:47 -0600122
Andrew Geissler20137392023-10-12 04:59:14 -0600123 async def remove(self, where):
124 await self._set_mode(self.MODE_NORMAL)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600125 return await self.invoke({"remove": {"where": where}})
Andrew Geissler20137392023-10-12 04:59:14 -0600126
127 async def clean_unused(self, max_age):
128 await self._set_mode(self.MODE_NORMAL)
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600129 return await self.invoke({"clean-unused": {"max_age_seconds": max_age}})
130
131 async def auth(self, username, token):
132 await self._set_mode(self.MODE_NORMAL)
133 result = await self.invoke({"auth": {"username": username, "token": token}})
134 self.username = username
135 self.password = token
136 self.saved_become_user = None
137 return result
138
139 async def refresh_token(self, username=None):
140 await self._set_mode(self.MODE_NORMAL)
141 m = {}
142 if username:
143 m["username"] = username
144 result = await self.invoke({"refresh-token": m})
145 if (
146 self.username
147 and not self.saved_become_user
148 and result["username"] == self.username
149 ):
150 self.password = result["token"]
151 return result
152
153 async def set_user_perms(self, username, permissions):
154 await self._set_mode(self.MODE_NORMAL)
155 return await self.invoke(
156 {"set-user-perms": {"username": username, "permissions": permissions}}
157 )
158
159 async def get_user(self, username=None):
160 await self._set_mode(self.MODE_NORMAL)
161 m = {}
162 if username:
163 m["username"] = username
164 return await self.invoke({"get-user": m})
165
166 async def get_all_users(self):
167 await self._set_mode(self.MODE_NORMAL)
168 return (await self.invoke({"get-all-users": {}}))["users"]
169
170 async def new_user(self, username, permissions):
171 await self._set_mode(self.MODE_NORMAL)
172 return await self.invoke(
173 {"new-user": {"username": username, "permissions": permissions}}
174 )
175
176 async def delete_user(self, username):
177 await self._set_mode(self.MODE_NORMAL)
178 return await self.invoke({"delete-user": {"username": username}})
179
180 async def become_user(self, username):
181 await self._set_mode(self.MODE_NORMAL)
182 result = await self.invoke({"become-user": {"username": username}})
183 if username == self.username:
184 self.saved_become_user = None
185 else:
186 self.saved_become_user = username
187 return result
188
189 async def get_db_usage(self):
190 await self._set_mode(self.MODE_NORMAL)
191 return (await self.invoke({"get-db-usage": {}}))["usage"]
192
193 async def get_db_query_columns(self):
194 await self._set_mode(self.MODE_NORMAL)
195 return (await self.invoke({"get-db-query-columns": {}}))["columns"]
Andrew Geissler20137392023-10-12 04:59:14 -0600196
Andrew Geissler6ce62a22020-11-30 19:58:47 -0600197
Andrew Geisslerc926e172021-05-07 16:11:35 -0500198class Client(bb.asyncrpc.Client):
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600199 def __init__(self, username=None, password=None):
200 self.username = username
201 self.password = password
202
Andrew Geisslerc926e172021-05-07 16:11:35 -0500203 super().__init__()
204 self._add_methods(
Andrew Geissler6ce62a22020-11-30 19:58:47 -0600205 "connect_tcp",
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600206 "connect_websocket",
Andrew Geissler6ce62a22020-11-30 19:58:47 -0600207 "get_unihash",
208 "report_unihash",
209 "report_unihash_equiv",
210 "get_taskhash",
Andrew Geisslereff27472021-10-29 15:35:00 -0500211 "get_outhash",
Andrew Geissler6ce62a22020-11-30 19:58:47 -0600212 "get_stats",
213 "reset_stats",
214 "backfill_wait",
Andrew Geissler20137392023-10-12 04:59:14 -0600215 "remove",
216 "clean_unused",
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600217 "auth",
218 "refresh_token",
219 "set_user_perms",
220 "get_user",
221 "get_all_users",
222 "new_user",
223 "delete_user",
224 "become_user",
225 "get_db_usage",
226 "get_db_query_columns",
Andrew Geisslerc926e172021-05-07 16:11:35 -0500227 )
Andrew Geissler6ce62a22020-11-30 19:58:47 -0600228
Andrew Geisslerc926e172021-05-07 16:11:35 -0500229 def _get_async_client(self):
Patrick Williamsac13d5f2023-11-24 18:59:46 -0600230 return AsyncClient(self.username, self.password)