Skip to content

Commit dd05c13

Browse files
committed
Support for restart i3 reconnection.
Search the socket path on reconnect if no user's socket_path defined.
1 parent 20e3a0e commit dd05c13

File tree

2 files changed

+36
-22
lines changed

2 files changed

+36
-22
lines changed

i3ipc/aio/connection.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,7 @@ class Connection:
264264
def __init__(self, socket_path: Optional[str] = None, auto_reconnect: bool = False, *,
265265
display: Optional[str] = None):
266266
self._socket_path = socket_path
267+
self._connection_socket_path = None
267268
self._auto_reconnect = auto_reconnect
268269
self._pubsub = _AIOPubSub(self)
269270
self._subscriptions = set()
@@ -284,7 +285,7 @@ def socket_path(self) -> str:
284285
285286
:rtype: str
286287
"""
287-
return self._socket_path
288+
return self._connection_socket_path or self._socket_path
288289

289290
@property
290291
def auto_reconect(self) -> bool:
@@ -380,8 +381,10 @@ async def connect(self) -> 'Connection':
380381
if self._socket_path:
381382
logger.info('using user provided socket path: {}', self._socket_path)
382383

383-
if not self._socket_path:
384-
self._socket_path = await _find_socket_path(self._display)
384+
if self._socket_path:
385+
self._connection_socket_path = self._socket_path
386+
else:
387+
self._connection_socket_path = await _find_socket_path(self._display)
385388

386389
if not self.socket_path:
387390
raise Exception('Failed to retrieve the i3 or sway IPC socket path')
@@ -415,6 +418,7 @@ async def do_reconnect():
415418
error = None
416419
break
417420
except Exception as e:
421+
self._connection_socket_path = None
418422
error = e
419423
await asyncio.sleep(0.001)
420424

i3ipc/connection.py

Lines changed: 29 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -56,26 +56,33 @@ def __init__(self, socket_path=None, auto_reconnect=False, display=None):
5656

5757
if socket_path:
5858
logger.info('using user provided socket path: %s', socket_path)
59-
else:
60-
socket_path = self._find_socket_path(display)
61-
62-
if not socket_path:
63-
raise Exception('Failed to retrieve the i3 or sway IPC socket path')
59+
# else _find_socket_path() will be used
6460

6561
self.subscriptions = 0
6662
self._pubsub = PubSub(self)
63+
self._display = display
6764
self._socket_path = socket_path
65+
self._connection_socket_path = self._get_socket_path()
6866
self._cmd_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
69-
self._cmd_socket.connect(self._socket_path)
67+
self._cmd_socket.connect(self._connection_socket_path)
7068
self._cmd_lock = Lock()
7169
self._sub_socket = None
7270
self._sub_lock = Lock()
7371
self._auto_reconnect = auto_reconnect
7472
self._quitting = False
7573
self._synchronizer = None
76-
self._display = display
7774

78-
def _find_socket_path(self, disp=None):
75+
def _get_socket_path(self):
76+
"""Returns a current socket path."""
77+
if self._socket_path:
78+
socket_path = self._socket_path
79+
else:
80+
socket_path = self._find_socket_path()
81+
if not socket_path:
82+
raise Exception('Failed to retrieve the i3 or sway IPC socket path')
83+
return socket_path
84+
85+
def _find_socket_path(self):
7986
socket_path = os.environ.get("I3SOCK")
8087
if socket_path:
8188
logger.info('got socket path from I3SOCK env variable: %s', socket_path)
@@ -86,8 +93,8 @@ def _find_socket_path(self, disp=None):
8693
logger.info('got socket path from SWAYSOCK env variable: %s', socket_path)
8794
return socket_path
8895

89-
if disp:
90-
env = {**os.environ, 'DISPLAY': disp}
96+
if self._display:
97+
env = {**os.environ, 'DISPLAY': self._display}
9198
else:
9299
env = None
93100
for binary in ('i3', 'sway'):
@@ -121,7 +128,7 @@ def socket_path(self) -> str:
121128
122129
:rtype: str
123130
"""
124-
return self._socket_path
131+
return self._connection_socket_path or self._socket_path
125132

126133
@property
127134
def auto_reconnect(self) -> bool:
@@ -182,14 +189,16 @@ def _ipc_send(self, sock, message_type, payload):
182189

183190
def _wait_for_socket(self):
184191
# for the auto_reconnect feature only
185-
socket_path_exists = False
186192
for tries in range(0, 500):
187-
socket_path_exists = os.path.exists(self._socket_path)
188-
if socket_path_exists:
189-
break
193+
try:
194+
self._connection_socket_path = self._get_socket_path()
195+
if os.path.exists(self._connection_socket_path):
196+
return True
197+
except Exception:
198+
pass
190199
time.sleep(0.001)
191200

192-
return socket_path_exists
201+
return False
193202

194203
def _message(self, message_type, payload):
195204
try:
@@ -198,15 +207,16 @@ def _message(self, message_type, payload):
198207
except ConnectionError as e:
199208
if not self.auto_reconnect:
200209
raise e
210+
self._connection_socket_path = None
201211

202212
logger.info('got a connection error, reconnecting', exc_info=e)
203-
# XXX: can the socket path change between restarts?
213+
# The socket path can change between restarts.
204214
if not self._wait_for_socket():
205215
logger.info('could not reconnect')
206216
raise e
207217

208218
self._cmd_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
209-
self._cmd_socket.connect(self._socket_path)
219+
self._cmd_socket.connect(self._connection_socket_path)
210220
return self._ipc_send(self._cmd_socket, message_type, payload)
211221
finally:
212222
self._cmd_lock.release()
@@ -462,7 +472,7 @@ def _on(self, event: Union[Event, str], handler: Callable[['Connection', IpcBase
462472

463473
def _event_socket_setup(self):
464474
self._sub_socket = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
465-
self._sub_socket.connect(self._socket_path)
475+
self._sub_socket.connect(self._connection_socket_path)
466476

467477
self._subscribe(self.subscriptions)
468478

0 commit comments

Comments
 (0)