11
11
from Xlib .error import DisplayError
12
12
import struct
13
13
import socket
14
+ import logging
14
15
15
16
import asyncio
16
17
from asyncio .subprocess import PIPE
22
23
_struct_header = f'={ len (_MAGIC )} sII'
23
24
_struct_header_size = struct .calcsize (_struct_header )
24
25
26
+ logger = logging .getLogger (__name__ )
25
27
26
28
class _AIOPubSub (PubSub ):
27
29
def queue_handler (self , handler , data = None ):
@@ -173,16 +175,23 @@ async def _find_socket_path() -> Optional[str]:
173
175
def exists (path ):
174
176
if not path :
175
177
return False
176
- return os .path .exists (path )
178
+ result = os .path .exists (path )
179
+ if not result :
180
+ logger .info ('file not found: %s' , socket_path )
181
+ return result
177
182
178
183
# first try environment variables
179
184
socket_path = os .environ .get ('I3SOCK' )
180
- if exists (socket_path ):
181
- return socket_path
185
+ if socket_path :
186
+ logger .info ('got socket path from I3SOCK env variable: %s' , socket_path )
187
+ if exists (socket_path ):
188
+ return socket_path
182
189
183
190
socket_path = os .environ .get ('SWAYSOCK' )
184
- if exists (socket_path ):
185
- return socket_path
191
+ if socket_path :
192
+ logger .info ('got socket path from SWAYSOCK env variable: %s' , socket_path )
193
+ if exists (socket_path ):
194
+ return socket_path
186
195
187
196
# next try the root window property
188
197
try :
@@ -192,11 +201,14 @@ def exists(path):
192
201
prop = root .get_full_property (atom , X .AnyPropertyType )
193
202
if prop and prop .value :
194
203
socket_path = prop .value .decode ()
195
- except DisplayError :
204
+ except DisplayError as e :
205
+ logger .info ('could not get i3 socket path from root atom' , exc_info = e )
196
206
pass
197
207
198
- if exists (socket_path ):
199
- return socket_path
208
+ if socket_path :
209
+ logger .info ('got socket path from root atom: %s' , socket_path )
210
+ if exists (socket_path ):
211
+ return socket_path
200
212
201
213
# finally try the binaries
202
214
for binary in ('i3' , 'sway' ):
@@ -205,17 +217,23 @@ def exists(path):
205
217
'--get-socketpath' ,
206
218
stdout = PIPE ,
207
219
stderr = PIPE )
208
- except Exception :
209
- continue
210
220
211
- stdout , stderr = await process .communicate ()
221
+ stdout , stderr = await process .communicate ()
222
+
223
+ if process .returncode == 0 and stdout :
224
+ socket_path = stdout .decode ().strip ()
225
+ if socket_path :
226
+ logger .info ('got socket path from `%s` binary: %s' , binary , socket_path )
227
+ if exists (socket_path ):
228
+ return socket_path
229
+ else :
230
+ logger .info ('could not get socket path from `%s` binary: returncode=%d, stdout=%s, stderr=%s' , process .returncode , stdout , stderr )
212
231
213
- if process .returncode == 0 and stdout :
214
- socket_path = stdout .decode ().strip ()
215
- if exists (socket_path ):
216
- return socket_path
232
+ except Exception as e :
233
+ logger .info ('could not get i3 socket path from `%s` binary' , binary , exc_info = e )
234
+ continue
217
235
218
- # could not find the socket path
236
+ logger . info ( ' could not find i3 socket path' )
219
237
return None
220
238
221
239
@@ -298,6 +316,7 @@ def _read_message(self):
298
316
self ._loop .remove_reader (self ._sub_fd )
299
317
300
318
if self ._auto_reconnect :
319
+ logger .info ('could not read message, reconnecting' , exc_info = error )
301
320
asyncio .ensure_future (self ._reconnect ())
302
321
else :
303
322
if error is not None :
@@ -309,14 +328,16 @@ def _read_message(self):
309
328
310
329
magic , message_length , event_type = _unpack_header (buf )
311
330
assert magic == _MAGIC
312
- message = json .loads (self ._sub_socket .recv (message_length ))
331
+ raw_message = self ._sub_socket .recv (message_length )
332
+ message = json .loads (raw_message )
313
333
314
334
# events have the highest bit set
315
335
if not event_type & (1 << 31 ):
316
336
# a reply
317
337
return
318
338
319
339
event_type = EventType (1 << (event_type & 0x7f ))
340
+ logger .info ('got message on subscription socket: type=%s, message=%s' , event_type , raw_message )
320
341
321
342
if event_type == EventType .WORKSPACE :
322
343
event = WorkspaceEvent (message , self , _Con = Con )
@@ -349,6 +370,9 @@ async def connect(self) -> 'Connection':
349
370
:returns: The ``Connection``.
350
371
:rtype: :class:`~.Connection`
351
372
"""
373
+ if self ._socket_path :
374
+ logger .info ('using user provided socket path: {}' , self ._socket_path )
375
+
352
376
if not self ._socket_path :
353
377
self ._socket_path = await _find_socket_path ()
354
378
@@ -402,6 +426,8 @@ async def _message(self, message_type: MessageType, payload: str = '') -> bytes:
402
426
if message_type is MessageType .SUBSCRIBE :
403
427
raise Exception ('cannot subscribe on the command socket' )
404
428
429
+ logger .info ('sending message: type=%s, payload=%s' , message_type , payload )
430
+
405
431
for tries in range (0 , 5 ):
406
432
try :
407
433
await self ._loop .sock_sendall (self ._cmd_socket , _pack (message_type , payload ))
@@ -411,6 +437,7 @@ async def _message(self, message_type: MessageType, payload: str = '') -> bytes:
411
437
if not self ._auto_reconnect :
412
438
raise e
413
439
440
+ logger .info ('got connection error, attempting to reconnect' , exc_info = e )
414
441
await self ._reconnect ()
415
442
416
443
if not buf :
@@ -427,6 +454,7 @@ async def _message(self, message_type: MessageType, payload: str = '') -> bytes:
427
454
asyncio .ensure_future (self ._reconnect ())
428
455
raise e
429
456
457
+ logger .info ('got message reply: %s' , message )
430
458
return message
431
459
432
460
async def subscribe (self , events : Union [List [Event ], List [str ]], force : bool = False ):
@@ -458,15 +486,21 @@ async def subscribe(self, events: Union[List[Event], List[str]], force: bool = F
458
486
f'only nondetailed events are subscribable (use Event.{ correct_event } )' )
459
487
subscriptions .add (e )
460
488
489
+ logger .info ('subscribing to events: %s' , subscriptions )
490
+ logger .info ('current subscriptions: %s' , self ._subscriptions )
491
+
461
492
if not force :
462
493
subscriptions = subscriptions .difference (self ._subscriptions )
463
494
if not subscriptions :
495
+ logger .info ('no new subscriptions' )
464
496
return
465
497
466
498
self ._subscriptions .update (subscriptions )
467
499
468
500
payload = json .dumps ([s .value for s in subscriptions ])
469
501
502
+ logger .info ('sending SUBSCRIBE message with payload: %s' , payload )
503
+
470
504
await self ._loop .sock_sendall (self ._sub_socket , _pack (MessageType .SUBSCRIBE , payload ))
471
505
472
506
def on (self , event : Union [Event , str ], handler : Callable [['Connection' , IpcBaseEvent ], None ]):
@@ -488,6 +522,8 @@ def on(self, event: Union[Event, str], handler: Callable[['Connection', IpcBaseE
488
522
else :
489
523
base_event = event
490
524
525
+ logger .info ('adding event handler: event=%s, handler=%s' , event , handler )
526
+
491
527
self ._pubsub .subscribe (event , handler )
492
528
asyncio .ensure_future (self .subscribe ([base_event ]))
493
529
@@ -498,6 +534,7 @@ def off(self, handler: Callable[['Connection', IpcBaseEvent], None]):
498
534
:func:`on()`.
499
535
:type handler: :class:`Callable`
500
536
"""
537
+ logger .info ('removing event handler: handler=%s' , handler )
501
538
self ._pubsub .unsubscribe (handler )
502
539
503
540
async def command (self , cmd : str ) -> List [CommandReply ]:
@@ -648,6 +685,7 @@ async def get_seats(self) -> List[SeatReply]:
648
685
649
686
def main_quit (self , _error = None ):
650
687
"""Quits the running main loop for this connection."""
688
+ logger .info ('quitting the main loop' , exc_info = _error )
651
689
if self ._main_future is not None :
652
690
if _error :
653
691
self ._main_future .set_exception (_error )
@@ -660,5 +698,6 @@ async def main(self):
660
698
"""Starts the main loop for this connection to start handling events."""
661
699
if self ._main_future is not None :
662
700
raise Exception ('the main loop is already running' )
701
+ logger .info ('starting the main loop' )
663
702
self ._main_future = self ._loop .create_future ()
664
703
await self ._main_future
0 commit comments