14
14
# limitations under the License.
15
15
#
16
16
from __future__ import annotations
17
-
17
+ from struct import Struct
18
18
import asyncio
19
19
import logging
20
20
import socket
21
- from typing import TYPE_CHECKING , Any
21
+ from typing import TYPE_CHECKING , Any , Iterable
22
22
23
23
import aiohappyeyeballs
24
24
from async_interrupt import interrupt
45
45
from aiohomekit .protocol .tlv import TLV
46
46
from aiohomekit .utils import async_create_task , asyncio_timeout
47
47
48
+ PACK_UNSIGNED_SHORT = Struct (">H" ).pack
49
+
50
+
48
51
if TYPE_CHECKING :
49
52
from .pairing import IpPairing
50
53
@@ -80,11 +83,11 @@ def __init__(self, connection: HomeKitConnection) -> None:
80
83
self .current_response = HttpResponse ()
81
84
self .loop = asyncio .get_running_loop ()
82
85
83
- def connection_made (self , transport ) :
86
+ def connection_made (self , transport : asyncio . Transport ) -> None :
84
87
super ().connection_made (transport )
85
88
self .transport = transport
86
89
87
- def connection_lost (self , exception ) :
90
+ def connection_lost (self , exception : Exception ) -> None :
88
91
self .connection ._connection_lost (exception )
89
92
self ._cancel_pending_requests ()
90
93
@@ -94,10 +97,14 @@ def _handle_timeout(self, fut: asyncio.Future[Any]) -> None:
94
97
fut .set_exception (asyncio .TimeoutError )
95
98
96
99
async def send_bytes (self , payload : bytes ) -> HttpResponse :
100
+ """Send bytes to the device."""
101
+ return await self .send_lines ((payload ,))
102
+
103
+ async def send_lines (self , payload : Iterable [bytes ]) -> HttpResponse :
97
104
"""Send bytes to the device."""
98
105
if self .transport .is_closing ():
99
106
# FIXME: It would be nice to try and wait for the reconnect in future.
100
- # In that case we need to make sure we do it at a layer above send_bytes otherwise
107
+ # In that case we need to make sure we do it at a layer above send_lines otherwise
101
108
# we might encrypt payloads with the last sessions keys t
F921
hen wait for a new connection
102
109
# to send them - and on that connection the keys would be different.
103
110
# Also need to make sure that the new connection has chance to pair-verify before
@@ -113,7 +120,7 @@ async def send_bytes(self, payload: bytes) -> HttpResponse:
113
120
timeout_handle = loop .call_at (loop .time () + 30 , self ._handle_timeout , result )
114
121
timeout_expired = False
115
122
try :
116
- self .transport .write (payload )
123
+ self .transport .writelines (payload )
117
124
return await result
118
125
except (asyncio .TimeoutError , BaseException ) as ex :
119
126
# If we get a timeout or any other exception then we need to
@@ -188,18 +195,12 @@ async def send_bytes(self, payload: bytes) -> HttpResponse:
188
195
while len (payload ) > 0 :
189
196
current = payload [:1024 ]
190
197
payload = payload [1024 :]
191
- len_bytes = len (current ). to_bytes ( 2 , byteorder = "little" )
198
+ len_bytes = PACK_UNSIGNED_SHORT ( len (current ))
192
199
buffer .append (len_bytes )
193
- buffer .append (
194
- self .encryptor .encrypt (
195
- len_bytes ,
196
- PACK_NONCE (self .c2a_counter ),
197
- bytes (current ),
198
- )
199
- )
200
+ buffer .append (self .encryptor .encrypt (len_bytes , PACK_NONCE (self .c2a_counter ), current ))
200
201
self .c2a_counter += 1
201
202
202
- return await super (). send_bytes ( b"" . join ( buffer ) )
203
+ return await self . send_lines ( buffer )
203
204
204
205
def data_received (self , data : bytes ) -> None :
205
206
"""
0 commit comments