78 lines
2.1 KiB
Python
78 lines
2.1 KiB
Python
"""Client library for LSP tool scripts. Connects to the bridge daemon, starting it if needed."""
|
|
|
|
import json
|
|
import os
|
|
import socket
|
|
import subprocess
|
|
import sys
|
|
import time
|
|
|
|
SOCK_PATH = os.path.join(os.environ.get("XDG_RUNTIME_DIR", "/tmp"), "ollie-lsp.sock")
|
|
PID_PATH = SOCK_PATH + ".pid"
|
|
|
|
|
|
def _bridge_running() -> bool:
|
|
if not os.path.exists(PID_PATH):
|
|
return False
|
|
try:
|
|
pid = int(open(PID_PATH).read().strip())
|
|
os.kill(pid, 0)
|
|
return True
|
|
except (OSError, ValueError):
|
|
return False
|
|
|
|
|
|
def _start_bridge():
|
|
"""Start the bridge daemon as a background process."""
|
|
lib_dir = os.path.dirname(os.path.abspath(__file__))
|
|
bridge_script = os.path.join(lib_dir, "bridge.py")
|
|
subprocess.Popen(
|
|
[sys.executable, bridge_script],
|
|
stdin=subprocess.DEVNULL,
|
|
stdout=subprocess.DEVNULL,
|
|
stderr=subprocess.DEVNULL,
|
|
start_new_session=True,
|
|
)
|
|
# Wait for socket to appear
|
|
for _ in range(50):
|
|
if os.path.exists(SOCK_PATH):
|
|
return
|
|
time.sleep(0.1)
|
|
print("error: bridge daemon failed to start", file=sys.stderr)
|
|
sys.exit(1)
|
|
|
|
|
|
def request(method: str, **kwargs) -> dict:
|
|
"""Send a request to the bridge and return the response."""
|
|
if not _bridge_running():
|
|
_start_bridge()
|
|
|
|
payload = {"method": method, **kwargs}
|
|
data = json.dumps(payload).encode()
|
|
|
|
sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
|
|
try:
|
|
sock.connect(SOCK_PATH)
|
|
sock.sendall(data)
|
|
sock.shutdown(socket.SHUT_WR)
|
|
chunks = []
|
|
while True:
|
|
chunk = sock.recv(4096)
|
|
if not chunk:
|
|
break
|
|
chunks.append(chunk)
|
|
response = json.loads(b"".join(chunks))
|
|
except ConnectionRefusedError:
|
|
# Stale socket, restart
|
|
if os.path.exists(SOCK_PATH):
|
|
os.unlink(SOCK_PATH)
|
|
_start_bridge()
|
|
return request(method, **kwargs)
|
|
finally:
|
|
sock.close()
|
|
|
|
if "error" in response:
|
|
print(f"error: {response['error']}", file=sys.stderr)
|
|
sys.exit(1)
|
|
return response.get("result")
|