Skip to content

Latest commit

 

History

History
68 lines (51 loc) · 8.96 KB

api.md

File metadata and controls

68 lines (51 loc) · 8.96 KB

Syncer launcher API

Personal builds only. The launcher API is compiled only into the maintainer's personal build (wails build -tags personal). It isn't part of the public release (v1.0.0 and later) and there the named pipe isn't opened and --api exits at once. It may come back as an add-on.

A local API for game launchers (such as Seaglass): show a game's save status, sync saves before a game starts, back them up after it exits, and deal with conflicts.

Connecting

  • Transport: the named pipe \\.\pipe\syncer. Only the current Windows user can connect (the pipe's DACL grants access to that user alone), and remote clients are refused.
  • Who serves it: the Syncer window, while it runs (including in the tray). Otherwise start Syncer.exe --api: it serves the same pipe without a window and exits after a minute without connections (after any backup it started has finished). When the pipe is already served, --api exits right away.
  • Finding Syncer.exe: the DisplayIcon value of HKCU\Software\Microsoft\Windows\CurrentVersion\Uninstall\ApolloFSyncer, or %LOCALAPPDATA%\Programs\Syncer\Syncer.exe.
  • Clients should check the server: GetNamedPipeServerProcessId, then compare the owner of that process with the current user, so another account can't pose as Syncer.

Messages

JSON-RPC 2.0, one JSON object per line (UTF-8, \n-terminated, at most 1 MB). Requests on one connection may overlap; answers carry the request's id. A request without id is a notification and gets no answer.

{"jsonrpc":"2.0","id":1,"method":"gameStatus","params":{"title":"Elden Ring"}}
{"jsonrpc":"2.0","id":1,"result":{"known":true,"folders":[{"id":"elden-ring","label":"Elden Ring","state":"idle", …}]}}

Errors use the standard codes (-32700 parse error, -32600 invalid request, -32601 unknown method, -32602 bad params) and -32000 for a valid call that didn't work, with the reason in message.

Versioning

status returns protocol (now 1). New methods and fields can be added within a version; clients ignore fields they don't know. A change that breaks clients raises the version. Clients should check it and treat an unknown or missing Syncer as "not available".

Methods

Method Params Result
status – {protocol, version, window, syncthing, paused, pausedUntil?, backingUp, lastBackup?, games, conflicts}
games – every save folder, as Folder objects
gameStatus {title?, dir?, steamAppId?, gogId?} (at least one of the first three) {known, folders: [Folder]}
syncNow {ids: [folder id], timeoutMs?} (default 30 s, at most 2 min) [{id, done, state, needBytes}]
backupNow {wait?, timeoutMs?} (default 2 min, at most 30 min) {started, finished, ok, at?, copied, errors?}
conflicts {id} [{rel, copy, device, deviceName, size, modified, missing, copySize, copyModified}]
resolveConflict {id, copy, useCopy} true
getNewer {id} {files}
open – true (shows the Syncer window, starting it if needed)
registerGames {games: [{title, dir?, steamAppId?, gogId?}]} (at most 20,000) {games: n}
subscribe – true, then changed notifications on this connection
accounts – {enabled, active?, accounts: [{id, name, color?, active}], split: [{game, label, accounts}]}
switchAccount {id} true once that account's saves are in place on this PC
launcherData {launcher, path} {id?, label?, sync, backup, added, dismissed, error?, repaired?}

Folder: {id, label, path, sync, backup, state, needBytes, errors, problem?, conflicts, exists, modified?, backedUp?, newerOn?, newerAt?, newerCanGet?, kind?, account?}.

  • problem: what keeps Syncthing from syncing the folder, in plain words (it stopped the folder, or some files can't be synced). Set exactly when Syncer counts the folder as having an issue.

  • sync: synced with other PCs; false means only backed up.

  • state: Syncthing's state (idle, scanning, syncing, …), or backup-only, off, paused.

  • newerOn: another PC backed up a newer save that hasn't arrived here yet. Syncer takes it from that PC's backup by itself when it safely can (the saves here are exactly what this PC last backed up, no game runs, and that PC's whole backup has arrived through Google Drive). newerCanGet: it wasn't, but getNewer can take it now.

  • kind: set for mod folders: mods (Vortex's installed mods), mods-profiles (its load orders), mods-deployed (mods deployed into the game's folder). gameStatus never returns deployed-mods folders, and syncNow doesn't apply their updates: that only happens from Syncer's window.

  • account: the game has separate saves per account and this folder holds this account's (the one playing on this PC). Its id is <game>.u-<account>; the other accounts' saves aren't listed.

Notes

  • gameStatus matches folders by the game's title, the names the game database (Ludusavi manifest) has for its Steam app or install folder, and the title a launcher registered for that install folder. Emulator save folders (Game (RUNE saves)) count as their game. known: false means Syncer has no saves for it.
  • syncNow asks Syncthing to rescan each synced folder and waits until the folder is idle with nothing left to fetch. done: false after the timeout means it's still catching up (for example, the other PC is offline). Backup-only folders report done: true, state: "not-synced"; paused folders report state: "paused".
  • backupNow runs the same incremental backup as Back up now. With wait, it returns once the backup has finished or the timeout has passed (finished: false).
  • resolveConflict keeps one version: with useCopy the conflict copy replaces the file, otherwise the current file stays. The other version goes to backup history, never deleted.
  • getNewer takes a game's newer save from the other PC's backup (see newerCanGet), after keeping the saves here as a restore point. files is how many files changed. A launcher can call it before starting the game.
  • registerGames replaces the previous list. Syncer keeps it in %APPDATA%\Syncer\launcher-games.json.
  • subscribe: Syncer checks folder states every 3 seconds while someone is subscribed and sends {"jsonrpc":"2.0","method":"changed","params":{}} when something changed. Call games or gameStatus again for the details.
  • launcherData has Syncer sync and back up a launcher's own data folder (Seaglass: playtime, achievements and settings) like a game's saves, shared with every paired PC at the same place under AppData. path must be an existing subfolder of the launcher's own folder in %APPDATA% or %LOCALAPPDATA% (%APPDATA%\Seaglass\Profile for Seaglass), and a real folder (no link or junction on the way). Only launchers Syncer knows can ask (for now Seaglass): any program running as the user can reach the API, and a made-up name must not get another program's data synced. Other PCs learn from Syncer's shared list that the folder is a launcher's data, so none of them splits it per account or removes it as an uninstalled game. Asking again is harmless: it reports how the folder is doing (added: false). Once the user stops syncing it (removes it, or keeps it backed up only), it stays that way (dismissed: true) until they add it again in Syncer. Such a folder can't be split per account: the launcher keeps each account's data apart itself (one file per PC and account, so PCs never write the same file). The launcher must add up every file in the folder (playtime summed, achievements joined, the newest settings win) and skip Syncthing's conflict copies (.sync-conflict-). sync: false with error means Syncthing can't sync the folder right now; error says why, in plain words. When the folder was emptied or replaced outside Syncer (Syncthing stops such a folder, so the other PCs keep their copies), the call repairs it (repaired: true): files the backup has that are missing come back as they were; for a file the launcher already started again, the backup's copy is put next to it as <name>.restored-<YYYYMMDD-HHMMSS><ext> (the time is the copy's), never over it; then the folder joins again like a new PC, takes what the other PCs have and deletes nothing on them. The background task does the same. An older Syncer answers -32601 (unknown method).
  • accounts / switchAccount: with Accounts on in Syncer, several people can keep their own saves of the same game. A launcher can ask who's playing before it starts a game and call switchAccount to put that person's saves in place. Switching fails (nothing changed) while a game is running or when that account's saves haven't reached this PC yet. A split game's folder id changes with the account (<game>.u-<account>), so call games or gameStatus again after switching, before syncNow. enabled: false means accounts are off; then every game has one set of saves.