CLOUDMORROW

Resources / User handbook

The desktop app

The web app in a window of its own, with what a browser tab cannot do.

The desktop app

The client is two things on a computer: the terminal app, and a window with the web app in it that also does what a browser tab is not allowed to — mount a share on this computer, open the folder it landed in, say whether this machine's agent is running.

cloudmorrow app                       # open it (or click Cloudmorrow in the menu)
cloudmorrow app --dry-run             # what it would open, and whether it could
cloudmorrow app --print-url           # just the address
cloudmorrow app --install-launcher    # put it in the applications menu

It is the web app. The window loads the signed-in server's /app, the same page a phone and a browser get, so a deploy reaches it the moment it reaches them and there is no second interface to keep level. The window is the system's own web view, driven by pywebview: WebView2 on Windows, WKWebView on a Mac, and on Linux Qt WebEngine — which comes as wheels, so nothing is asked of the distribution. It runs in the client's own Python, in cloudmorrow/desktop/, and the window is titled with the cloud's name and wears the hedgehog.

What the page may ask. Beside the page pywebview puts one object, window.pywebview.api — desktop/bridge.py — and server/web/desktopbridge.js finds it. A phone and a browser have no such object, and there the file does nothing at all, so none of what follows is ever drawn anywhere else. Every method is the command line's own code, called rather than copied — mounting is client/mounts.py, a missing rclone is client/rclone.py, the agent is agent/setup.py — and every answer is plain JSON: a refusal comes back as {"error": …} in the same words cloudmorrow share mount would print, never as an exception. Only a page from the cloud the window was opened on is answered; a link to anywhere else opens in the browser.

method what it does
platform() which system, the host name, the name the agent goes by, whether a share can be mounted here and with what
shares() the server's shares, each with whether and where it is mounted on this machine
mounted_here() the same, from mounts.json alone — quick, no server
mount(name) / unmount(name) as cloudmorrow share mount / unmount, signed in the same way
open_folder(path) Finder, Explorer, or xdg-open
agent_status() enrolled or not, and whether the service is running
notify(title, body) a system notification, best effort
version() this client's version, and the server it talks to

Files. In the desktop app every share in the Files tab (the Files Quill's grid; the lines come in through the grid's hook, from desktopbridge.js) has a line under it: Mounted at ~/Fileshares/media with Open folder and Unmount, or Mount on this computer. It is the same mount the terminal app and cloudmorrow share mount make — recorded in the same mounts.json — so all three agree on what is mounted. On Linux the mount is rclone's; if rclone is missing the answer is the one command that installs it, since the window has no terminal for sudo to ask its password in. Me gets a This computer group: the machine's name, whether its agent is running, what mounts shares here, and the desktop app's version.

One sign-in. The token in credentials.json is the machine's, and the window shares it. When the window opens, the page asks for the stored token and takes it, so someone who ran cloudmorrow login is not asked again. A sign-in in the window is written back, so the terminal app is signed in by it — and, as cloudmorrow login does, a machine with no agent yet is enrolled. Signing out in the window, or its token running out, clears the stored one too, but only if it is still the window's: a sign-in the terminal app made since is left alone. At start the stored one always wins, being the most recent from either side. The page's own storage — which sort a folder was left in — is kept in desktop/ beside the client config.

Installing it. It is the desktop extra: pywebview, and on Linux qtpy, PyQt6 and PyQt6-WebEngine. /install.sh adds it on Linux when it runs in a graphical session (WAYLAND_DISPLAY or DISPLAY set), without --force-reinstall, so running the installer again does not fetch Qt again, and then cloudmorrow app --install-launcher writes ~/.local/share/applications/cloudmorrow.desktop and the hedgehog into ~/.local/share/icons. A machine reached over ssh, a server and a root install get the terminal app alone, as before; --no-desktop says the same on purpose. cloudmorrow update keeps the extra where it was installed.

Not yet. macOS: the extra installs as it is, and cloudmorrow app works from a terminal, but there is no .app bundle in ~/Applications to click. Windows: the installer is a shell script and does not run there, mounting has no branch for it yet (net use on the WebDAV URL, or rclone with WinFsp), and there is no Start-menu shortcut or toast notification. Each is a marked TODO in desktop/launcher.py, desktop/system.py or the installer, where it will go. Push notifications are the browser's, and a desktop web view does not deliver them; notify() is there for when the app sends its own.

From docs/MANUAL.md in the Cloudmorrow repository. Something wrong? A pull request there fixes it here.