ifURI examples
← all examples

35 — deploy a browser/office/tools surface onto a remote node (no SSH)

Push a self-contained, multi-scheme surface onto a running urirun node over POST /deploy — and then control the remote machine's browser from the host. One file, only stdlib + the Chrome that's already on the node, so it deploys where pip-installing the real connector packages isn't possible.

host                         remote node (e.g. lenovo, behind NAT, SSH closed)
 host copy-id    ──signed──►  enroll the SSH key (TOFU / signed)
 host deploy     ──code+──►   write lenovo_node.py + hot-swap the served registry
                  bindings    (no restart) — routeCount jumps, new schemes appear
        │
        ▼  browser://laptop/page/query/text {url}
 drive it ───────────────►   node runs headless Chrome, returns the page text
        ◄───────────────     ...or a screenshot, or opens a real window

What it deploys (14 routes, 8 schemes)

schemeroutes
browser://page/query/text, page/query/screenshot, desktop/page/command/openreal headless Chrome
sys://host/query/info, disk/query/usage
fs://file/command/write, file/query/read, dir/query/list (sandboxed under ~/.urirun-node/ws)
codec:// hash:// uuid://base64 / sha256 / uuidv4 (the polyglot connectors, in stdlib)
httpcheck://url/query/status
office://note/command/write, note/query/read

Run

NODE_URL=http://192.168.188.201:8765 ./deploy.sh   # enroll key + deploy + verify
NODE_URL=http://192.168.188.201:8765 python3 verify.py

Verified live on a real Fedora node ("lenovo"):

  ✓ browser://laptop/page/query/text        {"text":"Example Domain ... documentation examples ..."}
  ✓ browser://laptop/page/query/screenshot  {"screenshot":"~/.urirun-node/ws/shot-….png","bytes":18150}
  ✓ sys://laptop/disk/query/usage           {"total_gb":157.7,"free_gb":11.2,"used_pct":92.4}
  ... 9/9 routes verified on the remote node

Why isolated=False matters here

The handlers are declared isolated=False, which compiles to a local-function binding (run in the node's own process) rather than local-function-subprocess. That's the key to deploy: /deploy adds its code dir to the *node process's* sys.path, so an in-process handler imports the pushed module — an isolated subprocess would start fresh and ModuleNotFoundError. (See tellmesh_bridge.py in example 31, which deploys the same way.)

Bootstrap from git — the github connector

To put *real* connector packages on a node (not just this stdlib surface), use urirun-connector-github: the node clones a repo and emits its bindings, which you then host deploy:

urirun run 'github://host/repo/command/clone'   --payload '{"url":"https://github.com/if-uri/urirun-connector-time-tools.git"}' --execute
urirun run 'github://host/repo/query/bindings'  --payload '{"dest":"~/.urirun-projects/urirun-connector-time-tools","module":"urirun_connector_time_tools"}' --execute
# -> bindings → compile → host deploy onto any machine

For the full desktop (windows / keyboard / mouse / LibreOffice), the tellmesh packs (urihim/urikvm/uribrowser/urioffice) must be importable on the node; bridge them as in example 31. This example covers everything that is self-contained-deployable, including real browser control.

Files

Files

.gitignoreREADME.mddeploy.shlenovo_cdp.pylenovo_node.pynode-surface.bindings.jsonverify.py

View on GitHub →