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 | class HttpClientConnection(ConnectionMixin[HttpClientInfo]):
"""HTTP 客户端连接"""
dependencies = {AiohttpClientInterface}
http_interface: AiohttpClientInterface
def __init__(self, config: HttpClientInfo) -> None:
super().__init__(config)
self.is_hook: bool = False
async def request(
self,
method: str,
url: str,
params: Optional[dict] = None,
data: Optional[Any] = None,
json: Optional[dict] = None,
) -> Any:
if data and isinstance(data, dict):
form = FormData(quote_fields=False)
for k, v in data.items():
form.add_field(k, **v) if isinstance(v, dict) else form.add_field(k, v)
data = form
if json:
data = json_mod.dumps(json, cls=DatetimeJsonEncoder)
rider = await self.http_interface.request(method, url, params=params, data=data)
byte_data = await rider.io().read()
result = Json.deserialize(byte_data.decode("utf-8"))
return validate_response(result)
async def http_auth(self) -> None:
from ..app import Ariadne
app = Ariadne.current()
await app.launch_manager.get_interface(Memcache).delete(f"account.{app.account}.version")
data = await self.request(
"POST",
self.info.get_url("verify"),
json={"verifyKey": self.info.verify_key},
)
session_key = data["session"]
await self.request(
"POST",
self.info.get_url("bind"),
json={"qq": self.info.account, "sessionKey": session_key},
)
self.status.session_key = session_key
async def call(
self, command: str, method: CallMethod, params: Optional[dict] = None, *, in_session: bool = True
) -> Any:
params = params or {}
command = command.replace("_", "/")
while not self.status.connected:
await self.status.wait_for_update()
if in_session:
if not self.status.session_key:
await self.http_auth()
params["sessionKey"] = self.status.session_key
try:
if method in (CallMethod.GET, CallMethod.RESTGET):
return await self.request("GET", self.info.get_url(command), params=params)
elif method in (CallMethod.POST, CallMethod.RESTPOST):
return await self.request("POST", self.info.get_url(command), json=params)
elif method == CallMethod.MULTIPART:
return await self.request("POST", self.info.get_url(command), data=params)
except InvalidSession:
self.status.session_key = None
raise
@property
def stages(self):
return {} if self.is_hook else {"blocking"}
async def launch(self, mgr: Launart) -> None:
self.http_interface = mgr.get_interface(AiohttpClientInterface)
exit_signal = asyncio.create_task(mgr.status.wait_for_sigexit())
if self.is_hook: # FIXME
await exit_signal
return
async with self.stage("blocking"):
while not exit_signal.done():
try:
if not self.status.session_key:
logger.info("HttpClient: authenticate", style="dark_orange")
await self.http_auth()
data = await self.request(
"GET",
self.info.get_url("fetchMessage"),
{"sessionKey": self.status.session_key, "count": 10},
)
self.status.alive = True
except Exception as e:
self.status.session_key = None
self.status.alive = False
self._connection_fail()
logger.exception(e)
continue
assert isinstance(data, list)
for event_data in data:
event = build_event(event_data)
await asyncio.gather(*(callback(event) for callback in self.event_callbacks))
await wait_fut(
[asyncio.sleep(0.5), exit_signal],
return_when=asyncio.FIRST_COMPLETED,
)
|