FoldingAtHome / fah-client-bastet

Folding@home client, code named Bastet
GNU General Public License v3.0
61 stars 10 forks source link

API documentation #175

Closed felix920506 closed 7 months ago

felix920506 commented 10 months ago

Currently there doesn't appear to be any documentation available for the client API apart from the code itself. It would be much easier for 3rd party programs to be able to control the FAH client if such documentation was made available.

jcoffland commented 10 months ago

Indeed. The API is still in flux. Once we are closer to a public release of the v8 client it will make more sense to release documentation on the API.

In the meantime here is a rough outline. All of this is subject to change.

Websocket

The web frontend (fah-web-client-bastet) connects to the backend (fah-client-bastet) via at Websocket at /api/websocket. This is the only communication channel between the front and back ends.

Commands

The frontend can send the following commands to the backend by sending a JSON object over the Websocket. This object must contain a cmd variable which can be one of the following:

Status

Upon Websocket connection the backend will send an JSON object. It will then send updates to this object. The object is the entire available internal state of the backend client. You can see what this looks like by monitoring the Websocket connection in the browser via the browser's developer console.

Status updates

Object updates are applied by with the Javascript function update_obj() in machine.js. Updates are JSON arrays. The array is format like this:

[<path 0>, <path 1>, . . ., <path n>, <value>]

Where path is either a key (string) of an object or an integer representing an index in to an array.

Two special index values -1 and -2 must be handled separately. -1 means append the value to the end of the array. -2 means concatenate the value, which must be an array, to the end of the array.

If an array or object does not yet exist it its automatically added. The value is inserted at the specified location possibly replacing the previous value. The special value null does not insert a null but removes any value at that location. Otherwise the value could be any valid JSON.

You may notice that update_obj() also cleans the keys by replacing - with _. This is only necessary for backwards compatibility with older clients.

Examples

Here is an example client state:

{
  "info": {
    "version": "8.2.4",
    "os": "linux",
    "os_version": 6,
    "cpu": "amd64",
    "cpu_brand": "AMD Ryzen 9 3900X 12-Core Processor",
    "cpus": 24,
    "gpus": {
      "gpu:45:00:00": {
        "vendor": 4318,
        "type": "nvidia",
        "description": "NVIDIA GeForce RTX 3060",
        "uuid": "2d31c03a-3d11-88b3-010b-4fc7b7a20a75",
        "opencl": {
          "platform": 0,
          "device": 0,
          "compute": "3.0",
          "driver": "525.89"
        },
        "cuda": {
          "platform": 0,
          "device": 0,
          "compute": "8.6",
          "driver": "12.0"
        },
        "device": 9476,
        "supported": true
      }
    },
    "mach_name": "luma",
    "hostname": "luma",
    "id": "tWhTIJhhbYOQW6lPeLYTxGrJKk-NohQtejdwb2eAw9k",
    "account": "15_5Co2Ml3AXv_P6-Ux1PPBxxIDOLj6yrmO_icWmuoM"
  },
  "config": {
    "user": "jcoffland",
    "team": 1234,
    "passkey": "<redacted>",
    "on_idle": false,
    "paused": true,
    "finish": false,
    "beta": false,
    "cause": "any",
    "key": 0,
    "cpus": 22,
    "gpus": {
      "gpu:45:00:00": {
        "enabled": true,
        "beta": false,
        "key": 0
      }
    },
    "priority": "idle"
  },
  "units": [
    {
      "number": 91,
      "cpus": 21,
      "gpus": [],
      "state": "RUN",
      "paused": false,
      "id": "qIFTSOkedztyVJiKoWqhn1n9baFPi4ntEDFAhfBmsXY",
      "progress": 0.014,
      "assignment": {
        "time": "2023-11-28T13:15:07Z",
        "ws": "vav20.fah.temple.edu",
        "port": 443,
        "project": 12413,
        "deadline": 432000,
        "timeout": 302400,
        "credit": 150542,
        "cpus": 21,
        "min_cpus": 1,
        "max_cpus": 64,
        "core": {
          "type": "0xa8",
          "url": "https://cores.foldingathome.org/fahcore-a8-lin-64bit-avx2_256-0.0.12.tar.bz2",
          "sha256": "5d81e2df84fb0857e9804ce4c263e412d632b0e7c65bada542b608f1f8a2f204"
        }
      },
      "wu": {
        "time": "2023-11-28T13:15:07Z",
        "cs": [
          "129.32.209.205",
          "129.32.209.200",
          "129.32.209.202",
          "129.32.209.206",
          "highland4.seas.upenn.edu",
          "highland3.seas.upenn.edu",
          "vav24.fah.temple.edu",
          "129.32.209.204",
          "129.32.209.201",
          "fahwork01.psivant.com",
          "ds03.scs.illinois.edu",
          "ds01.scs.illinois.edu"
        ],
        "server": 2166411723,
        "run": 104,
        "clone": 3,
        "gen": 21,
        "sha256": "n69sF1jr32fDyedhv4uho0J3v0jwtcLwcni0hja3NGw="
      },
      "eta": "22 hours 43 mins",
      "ppd": 309186,
      "frames": 2,
      "run_time": 1182,
      "delay": 0,
      "wait": "2023-11-28T13:38:46Z",
      "pause_reason": "Paused by user"
    }
  ]
}

Here is an example update:

["config", "paused", false]
kbernhagen commented 10 months ago

There is also support for legacy v8.1 commands cmd of pause, unpause, finish.

time must be a UTC string, like 2023-11-28T13:15:07Z

The client may occasionally send the JSON fragment "ping" This is for the benefit of Web Control, which cannot easily see a protocol-level ping.

Argument config is a sparse dictionary containing the keys/values to change. Do not directly alter paused or finish; use the state command.

If a machine is associated with an account, you should probably refrain from altering account settings, such as user, team, passkey, cause.

jcoffland commented 10 months ago

Those legacy commands are deprecated.

FYI, the time format is called ISO 8601.

To accommodate the "ping" message the frontend just ignores anything after the first message that is not an array.

kbernhagen commented 9 months ago

Yes, legacy deprecated. But used by the current beta v8.1.

kbernhagen commented 8 months ago

Example snapshot from v8.3.2:

{
  "info": {
    "version": "8.3.2",
    "os": "macosx",
    "os_version": "14.3",
    "cpu": "arm64",
    "cpu_brand": "Apple M1",
    "cpus": 8,
    "gpus": {},
    "mach_name": "Panda",
    "hostname": "Panda",
    "id": "<redacted>",
    "account": "<redacted>"
  },
  "config": {
    "user": "calxalot",
    "team": 1971,
    "passkey": "<redacted>",
    "cause": "alzheimers"
  },
  "groups": {
    "": {
      "config": {
        "on_idle": false,
        "on_battery": false,
        "keep_awake": true,
        "paused": false,
        "finish": true,
        "beta": false,
        "key": 0,
        "cpus": 4,
        "gpus": {}
      },
      "wait": "2024-01-26T18:42:14Z"
    },
    "alt": {
      "config": {
        "on_idle": false,
        "on_battery": false,
        "keep_awake": false,
        "paused": true,
        "finish": false,
        "beta": false,
        "key": 0,
        "cpus": 0,
        "gpus": {}
      },
      "wait": "2024-01-26T23:40:02Z"
    }
  },
  "units": [
    {
      "group": "",
      "number": 1293,
      "cpus": 4,
      "gpus": [],
      "state": "RUN",
      "paused": false,
      "id": "v3iZj649Pz9UkLmko22Xn8XCUoVqbrff9nXq87Hh-TU",
      "progress": 0.932,
      "assignment": {
        "time": "2024-01-26T18:42:10Z",
        "ws": "vav20.fah.temple.edu",
        "port": 443,
        "project": 12416,
        "deadline": 432000,
        "timeout": 302400,
        "credit": 9260,
        "cpus": 4,
        "min_cpus": 1,
        "max_cpus": 64,
        "core": {
          "type": "0xa8",
          "url": "https://cores.foldingathome.org/fahcore-a8-osx-64bit-aarch64-0.0.12.tar.bz2",
          "sha256": "045ecffcbc2a3e04edc6d29ab6d56f7dab8fb356042e263dddd26f02a496f0b6"
        }
      },
      "wu": {
        "time": "2024-01-26T18:42:10Z",
        "cs": [
          "129.32.209.202",
          "129.32.209.205",
          "129.32.209.200",
          "129.32.209.206",
          "fahwork01.psivant.com",
          "highland4.seas.upenn.edu",
          "vav24.fah.temple.edu",
          "highland3.seas.upenn.edu",
          "ds03.scs.illinois.edu",
          "ds01.scs.illinois.edu",
          "129.32.209.204",
          "129.32.209.201"
        ],
        "server": 2166411723,
        "run": 39,
        "clone": 0,
        "gen": 110,
        "sha256": "LV0F7UWRP371NwzdanWWcjOwldm/LneeZESGOOs/Ax4="
      },
      "eta": "22 mins 39 secs",
      "ppd": 159789,
      "frames": 94
    }
  ]
}
kbernhagen commented 8 months ago

For v8.3.2 state commands directed at a group, there must be a group argument. Example:

{"state": "finish", "cmd": "state", "group": "alt", "time": "2024-01-27T00:05:22.722479Z"}

Without group, the state command applies to all groups. Note that the default group is "" (the empty string).

user, team, passkey and cause can be set on the client and affect all groups. Example:

{"cmd": "config", "config": {"cause": "any"}, "time": "2024-01-27T00:14:47.783101Z"}

Changes to a group config must include all groups. A missing group will be deleted. An extra group would be created. Example:

{"cmd": "config", "config": {"groups": {"": {}, "alt": {"on_idle": false}}}, "time": "2024-01-27T00:17:48.516350Z"}

Currently, a simple way to create a group is to send a state command:

{"state": "pause", "cmd": "state", "group": "create me"}

Groups cannot be renamed.