Commit Graph

113 Commits

Author SHA1 Message Date
Raman Gupta
c1ed7dff65 python-client: fix imports and extract a reusable scrypted_client library (#2094)
* python-client: link transitive server modules required by plugin_remote

plugin_remote now imports cluster_labels, cluster_setup, plugin_console,
plugin_pip, and plugin_volume (plus a lazy plugin_repl import), but
packages/python-client only symlinks plugin_remote, rpc, rpc_reader, and
scrypted_python. As a result the client cannot be imported at all:

    ModuleNotFoundError: No module named 'cluster_labels'

Add symlinks for the missing modules, matching the existing pattern of
sharing one implementation with server/python.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WaSWgBV1XsZxWiYM16sWME

* python-client: extract reusable scrypted_client library from test.py

The only way to connect to Scrypted from Python has been to copy the
bootstrap out of test.py, which is not importable (module-level event
loop) and had drifted from the current rpc_reader/PluginRemote APIs
(writeJSON vs writeSerialized, missing ClusterSetup argument).

Move the transport and connection handshake into an importable
scrypted_client module:

- EioRpcTransport gains a close() method, an optional injectable
  aiohttp session for the engine.io connection, and queues its send
  loop on the running loop instead of via run_coroutine_threadsafe.
- connect_scrypted_client() performs login, the engine.io connect, and
  the getRemote handshake, with a connect timeout and consistent
  ScryptedConnectionError on failure. It also attaches the constructed
  SystemManager to remote.systemManager, the same wiring loadZip does
  for plugins, so PluginRemote.notify can dispatch events to
  systemManager.listen() callbacks.
- test.py becomes a small demo of the library and exits cleanly
  without os._exit(); the server URL is configurable via
  SCRYPTED_BASE_URL.

Verified live against a Scrypted server (device enumeration and OnOff
state reads).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WaSWgBV1XsZxWiYM16sWME

* python-client: bound all connect phases and tear down tasks on close

Address review feedback:

- close() now cancels and awaits both the send loop and the peer read
  loop (previously the send task was cancelled but never awaited and
  the read task was untracked), so closing the event loop after
  close() no longer risks 'Task was destroyed but it is pending'
  warnings.
- connect_scrypted_client() stores the read-loop task on the transport
  and propagates read-loop failures into the pending handshake future,
  so a link that dies mid-handshake fails immediately with the
  underlying error instead of waiting out the timeout.
- The timeout parameter now bounds every phase: the login POST
  (aiohttp ClientTimeout), the engine.io connect (asyncio.wait_for),
  and the wait for initial system state.
- Document session ownership: login_session is borrowed and never
  closed; an http_session given to EioRpcTransport is owned by the
  transport and closed by close().

Verified live against a Scrypted server: clean run with empty stderr,
plus connection-refused and bad-credential paths both raising
ScryptedConnectionError.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WaSWgBV1XsZxWiYM16sWME

* python-client: lazily import plugin host modules in plugin_remote

A client consuming plugin_remote (for SystemManager, DeviceManager,
MediaManager) only needs the types and the engine.io/rpc bits. The
plugin host modules (cluster_labels, plugin_console, plugin_pip,
plugin_volume) are only used inside loadZipWrapped, so import them
there -- importing plugin_remote no longer requires them, and the
client directory drops those symlinks (plugin_repl was already a lazy
import). cluster_setup stays: the client bootstrap constructs a
ClusterSetup.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-27 13:36:55 -07:00
Raman Gupta
9a6fc6e810 server: dispatch python plugin events to systemManager listeners (#2086)
The python port of plugin-remote's notify() updates systemState but the
dispatch to systemManager.events was left as a commented-out TODO, so
systemManager.listen() callbacks never fire in python plugins/clients
(plugin-remote.ts dispatches via notifyEventDetails here). Port the
current typescript semantics: plain property changes update state and
notify listeners with the unwrapped value, everything else passes
through raw, and mixin property events no longer write device state.

Also fix EventRegistry.listenDevice to register callbacks in the
token-keyed listener set (it raised KeyError on the device id key,
diverging from event-registry.ts) so watch-mode device listeners work.

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-16 11:14:13 -07:00
Koushik Dutta
2cbcc05428 server: formatting 2025-07-31 11:04:16 -07:00
Brett Jia
19832c9537 python: partial repl reimplementation (#1763)
* python: partial repl reimplementation

* make more readable?

* document questionable design choices
2025-03-04 14:37:55 -08:00
Koushik Dutta
df10c4e5f2 server: fixup address, make it available on cluster manager 2025-02-05 12:08:50 -08:00
Koushik Dutta
93f94b0b0a server: Fixup casing 2024-12-30 21:29:15 -08:00
Koushik Dutta
404cf47d2e server: make mediaManager cluster aware 2024-12-30 21:28:06 -08:00
Brett Jia
55cb62cb72 server: use standard-telnetlib for Python 3.13+ (#1669)
* bump portable-python to version with 3.13

* add standard-telnetlib to scrypted requirements for Python 3.13+
2024-12-29 14:22:32 -08:00
Koushik Dutta
0b04d92131 server: use site packages in python for debugging 2024-12-28 13:24:40 -08:00
Koushik Dutta
05e9627f4a server: add debugpy to install list 2024-12-28 13:09:47 -08:00
Koushik Dutta
0d9d425ef0 server: fix python search order 2024-12-22 12:05:33 -08:00
Koushik Dutta
b4aa20b4cd server: remove legacy storage event 2024-12-05 09:24:36 -08:00
Koushik Dutta
a75b263141 server: cluster cpu usage monitoring 2024-12-02 15:08:56 -08:00
Koushik Dutta
dcae7ce367 server: remove debug code causing crashes 2024-11-23 08:05:17 -08:00
Koushik Dutta
d26c595fd6 server: clean up clustering lifecycle management 2024-11-22 20:57:34 -08:00
Koushik Dutta
2c5b79291f server: python formatting 2024-11-21 14:53:16 -08:00
Koushik Dutta
53cab91b02 server: refactor runtime worker creation 2024-11-20 14:53:58 -08:00
Koushik Dutta
69f4de66e9 server: exit hooks for python fork 2024-11-20 12:18:25 -08:00
Koushik Dutta
aed6e0c446 server: wip cluster mode load balancing 2024-11-20 11:39:21 -08:00
Koushik Dutta
347a957cd3 sdk: add cluster manager 2024-11-20 10:10:47 -08:00
Koushik Dutta
ca243e79bb server: apply default runtime for cluster fork 2024-11-18 21:03:00 -08:00
Koushik Dutta
153cc3ed94 server: python cleanup 2024-11-18 12:26:46 -08:00
Koushik Dutta
2ae6113750 server: wip python cluster fork 2024-11-18 11:31:52 -08:00
Koushik Dutta
0bf0ec08ab server: plugin init cleanups 2024-11-15 23:40:38 -08:00
Koushik Dutta
d868c3b3bb server: remove stats checker 2024-11-15 22:43:19 -08:00
Koushik Dutta
953b7812c5 server: shuffle python cluster code 2024-11-15 19:53:16 -08:00
Koushik Dutta
a965f9b569 server: simplify pong 2024-11-15 10:02:13 -08:00
Koushik Dutta
ce10a49f0f server: fix ping/pong 2024-11-15 10:02:13 -08:00
Koushik Dutta
5e31a0db96 server: python cleanup 2024-11-15 10:02:13 -08:00
Koushik Dutta
670216135b server: fix python stats updater 2024-11-15 10:02:13 -08:00
Koushik Dutta
09b9b33bac server: working python clustering 2024-11-15 10:02:13 -08:00
Koushik Dutta
02d090cb94 server: fix python cluster server loop missing 2024-11-15 10:02:13 -08:00
Koushik Dutta
7d28d1d9d4 server: wip python clustering 2024-11-15 10:02:13 -08:00
Koushik Dutta
f69b93c9fa server: fix consoles in clustered environment 2024-11-15 10:02:13 -08:00
Brett Jia
a4e484698d server: implement python listen + listenDevice (#1587)
* server: implement python listen + listenDevice

* fix unregister

* make functions synchronous
2024-09-23 09:34:10 -07:00
Brett Jia
d01fe4310b server: python createMediaManager func (#1574)
* server: python createMediaManager func

* use api's media manager directly
2024-09-12 13:08:03 -07:00
Koushik Dutta
5f4e2793ff server: possibly fix bug where rpc object may not be found 2024-09-04 10:36:56 -07:00
Koushik Dutta
1e1755fa7e server: cluster cleanups 2024-09-04 10:17:30 -07:00
Koushik Dutta
6d0da449ad server: simplify convoluted peer key 2024-09-03 22:31:51 -07:00
Koushik Dutta
561852bc15 server: fixup python remote debugging, fs chdir locations 2024-08-14 08:42:55 -07:00
Koushik Dutta
6aaaccaece server: revert back to original change that conditionally added unzipped path 2024-08-13 23:21:05 -07:00
Koushik Dutta
0e42b71e4b server: fixup python requirements calc 2024-08-13 23:14:26 -07:00
Koushik Dutta
8a8bee33c1 server: normalize fs path 2024-08-13 22:45:51 -07:00
Koushik Dutta
4c04e9e403 server: implement multi server clustering 2024-07-31 22:51:56 -07:00
Koushik Dutta
82908b82c0 server: enable stable cluster proxyIds 2024-07-29 18:34:18 -07:00
Koushik Dutta
1aa1df885d server: fix connectRPCObject gc race condition 2024-07-29 13:43:52 -07:00
Brett Jia
4adb8e4202 server: implement python WritableDeviceState (#1537) 2024-07-28 11:35:27 -07:00
Brett Jia
232298d7f4 server: fix python connectRPCObject sha256 (#1525) 2024-07-11 15:38:40 -07:00
Brett Jia
321d5b364f server: fix python systemManager.getDeviceByName (#1523) 2024-07-10 15:42:24 -07:00
Brett Jia
bc71fd8515 server: print python interpreter path (#1484) 2024-05-25 22:29:46 -07:00