Skip to content

Latest commit

 

History

History
344 lines (292 loc) · 11.2 KB

http.md

File metadata and controls

344 lines (292 loc) · 11.2 KB

HTTP API Docs (v1)

HHD now has a simple and fully featured HTTP endpoint, which allows configuring all available settings. All endpoints below should be prefixed with /api/v1/.

Authentication

By default, the endpoint is restricted to localhost, and is only available through the use of a token. This token is automatically generated in ~/.config/hhd/token and can be changed afterwards by the user as well.

The authentication is achieved through HTTP basic auth with a bearer token. This means that all requests to /api/v1 require the header Authorization with content Bearer <token>.

To retrieve the user, you can either ask the user for it (they can retrieve it with hhd token), or read it from ~/.config/hhd/token with either superuser or that user's permissions.

Settings endpoint (./api/v1/settings)

The API is on purpose very simple. The settings endpoint settings returns the currently available settings as a JSON. All the available settings types can be found in src/hhd/plugins.py. HHD ensures the json will have all the listed values in plugins.py, so you may not check if they exist.

Each setting has a title which is meant to be shown in the UI and an optional hint meant to be shown under a hover hint or ? button.

Each setting may include a set of tags, that work like classes. For example, a keyboard mapping setting may have the tags [razer_lycosa_123, razer_kbd, keyboard, advanced], which would allow the UI to customize the presentation based on the specific device make, manufacturer, or if neither are supported, show a generic keyboard remapper. Tags are ordered by specificity, so razer_lycosa_123 overrides razer_kbd. The tag advanced can be used as a hint to hide the setting in simplified UIs (TBD).

Essentially, under the type Settings are all the available settings, which are self explanatory.

  • event: Meant to simulate a one off event, like a reset. Set to true and hhd will remove it once it's applied (unused).
  • bool: Checkbox setting
  • multiple: Radial/dropdown setting. Options is a dictionary of values to UI friendly titles.
  • discrete: Allows a number of fixed integer or floating values (options is listed in increasing order). You may handle the same as multiple.
  • float: Floating point setting, with optional min, max values
  • int: Integer setting, same as above
  • color: Broken and unused right now

Each setting can be set to a single value coherent for its type (except color, tbd).

Settings are grouped within containers with a type container, which has an ordered dictionary of children. The key of the dictionary is the id that will be used for the option. Containers can be nested within containers, and the id of each container is appended to the option name.

HHD features settings sections, which are the outermost layer. This allows you to only focus at the settings necessary for each UI component (TDP, controllers, hhd settings).

Here is an example that you will receive in json form from /settings (in yaml):

version: <hex>
hhd:
    http:
        type: container
        tags: [hhd-http]
        title: REST API Configuration (BETA)
        hint: >-
            Settings for configuring the http endpoint of HHD.

        children:
            enable:
            type: bool
            title: Enable REST API.
            hint: >-
                Enables the rest API of Handheld Daemon
            default: False
            port:
            type: int
            title: REST API Port
            hint: >-
                Which port should the REST API be on?
            min: 1024
            max: 49151
            default: 5335

The example above will result in the following default state:

hhd:
    http:
        enable: False
        port: 5335

Settings can be viewed both as nested dictionaries and as a single dictionary. The following states are identical according to HHD.

hhd.http:
    enable: False
    port: 5335
hhd.http.enable: False
hhd.http.port: 5335
hhd:
    http:
        enable: False
hhd.http.port: 5335

You also receive a version hex, which contains whether the settings have changed and would prompt you to redraw your UI. Currently, HHD settings do not change after service start, but future plugins that rely on autodetection may start when e.g., a controller is connected. This will make the settings change.

HHD always performs validation for the currently loaded settings, so using a stale state will not create problems.

The final setting type is mode, which is a special type of container. It is meant to be displayed as an accordion, with a specific sub-container shown at a time.

controllers.legion_go:
    type: container
    tags: [lgc]
    title: Legion Controllers Configuration
    # ...

    children:
    xinput:
        type: mode
        # ...

        default: ds5e
        modes:
        disabled:
            type: container
            # ...

            children:
            shortcuts:
                # ...
        ds5e:
            type: container
            # ...

            children:
            led_support:
                # ...

The above will create the following default state:

controllers.legion_go.xinput.mode: ds5e
controllers.legion_go.xinput.disabled.shortcuts: disabled
controllers.legion_go.xinput.ds5e.led_support: True

Example call (token disabled):

curl -i http://localhost:5335/api/v1/settings
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.11.6
Date: ...
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
WWW-Authenticate: Bearer

{"controllers": {"legion_go": ...

State endpoint (./api/v1/state)

The state endpoint with GET returns the current app state in JSON form. Currently, only the nested dictionary form is returned, e.g.:

hhd:
    http:
        enable: False
        port: 5335

However, a future option will allow returning a single dictionary:

hhd.http.enable: False
hhd.http.port: 5335

You can also POST to the same endpoint with a mixed state presentation, which may include some options inlined and some as nested dictionaries. You only need to send changed options and HHD will merge them to the current state internally.

The POST endpoint will lock, apply the settings under HHD, and will return the updated state.

Warning: the post endpoint may lock for up to 5+ seconds. Use a separate fetch thread/promise! Typically, it will be much less than 1 second.

Example call (token disabled):

curl -i http://localhost:5335/api/v1/state
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.11.6
Date: ...
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
WWW-Authenticate: Bearer

{"controllers": {"legion_go": {"xinput": {"mode": "ds5e", "disabled": {"shortcuts": true}, "ds5e": {"led_support": true}}, "gyro": true, "accel": true, "gyro_fix": 100, "swap_legion": "disabled", "share_to_qam": true, "touchpad_mode": "crop_end", "debug": false, "shortcuts": true}}, "hhd": {"http": {"enable": true, "port": 5335, "localhost": true, "token": false}}, "version": "af6eb199"}%

Profile endpoint

HHD contains a profile system for changing multiple settings at a time. This can be done per game, when switching windows, etc.

The profile endpoint has 4 sub-endpoints: list, apply, get, set, del.

Only characters and spaces are supported for the profile name. HHD will silently strip other characters from the name.

profile/list Endpoint

The list GET endpoint returns a list of the available profiles.

curl -i http://localhost:5335/api/v1/profile/list
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.11.6
Date: ...
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
WWW-Authenticate: Bearer

["test"]%  

profile/apply Endpoint

The apply GET endpoint applies the selected profiles in the specified order and returns the new HHD state. The applied profiles are supplied as query arguments. You may apply multiple profiles at a time, by nesting them as query parameters.

curl -i http://localhost:5335/api/v1/profile/apply\?profile\=\&profile\=test2
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.11.6
Date: ...
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
WWW-Authenticate: Bearer

{"controllers": {"legion_go": {"xinput": {"mode": "ds5e", "disabled": {"shortcuts": true}, "ds5e": {"led_support": true}}, "gyro": true, "accel": true, "gyro_fix": 100, "swap_legion": "disabled", "share_to_qam": true, "touchpad_mode": "crop_end", "debug": false, "shortcuts": true}}, "hhd": {"http": {"enable": true, "port": 5335, "localhost": true, "token": false}}, "version": "af6eb199"}% 

profile/set Endpoint

The set endpoint allows you to update the contents of a profile. The response contains the updated profile. The set endpoint replaces the whole profile and validates it, unlike the state endpoint which merges it to the current state.

curl -i -X POST -d '{"controllers.legion_go.shortcuts": false}' http://localhost:5335/api/v1/profile/set\?profile\=test
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.11.6
Date: ...
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
WWW-Authenticate: Bearer

{"controllers": {"legion_go": {"shortcuts": false}}, "version": "af6eb199"}% 

profile/get Endpoint

The get GET endpoint allows you to retrieve the contents of a profile.

curl -i http://localhost:5335/api/v1/profile/get\?profile\=test
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.11.6
Date: ...
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
WWW-Authenticate: Bearer

{"controllers": {"legion_go": {"shortcuts": false}}, "version": "af6eb199"}%   

profile/del Endpoint

The del GET endpoint deletes the provided profile.

# Profile exists
curl -i http://localhost:5335/api/v1/profile/del\?profile\=test
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.11.6
Date: ...
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
WWW-Authenticate: Bearer

# Profile does not exist
curl -i http://localhost:5335/api/v1/profile/del\?profile\=test
HTTP/1.0 400 Bad Request
Server: BaseHTTP/0.6 Python/3.11.6
Date: ...
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
WWW-Authenticate: Bearer
Content-type: text / plain

Handheld Daemon Error:
Profile 'test' not found.% 

Handling Errors

The v1 API will always return a JSON object with status code 200 if called properly.

When called improperly, it will return the following status codes:

  • 401: Unauthorized: your token is invalid.
  • 404: The endpoint you tried to access does not exist.
  • 400: You supplied invalid parameters.

The content of the response will be a human readable explanation in text form. You may choose to display that to the user, through a modal or portal.

Version endpoint

You can query the version of the HHD V1 API to determine which features are available and whether the user should update either your app or HHD. The version is 1 now and this endpoint requires authentication. It might not require authentication in the future.

curl -i http://localhost:5335/api/v1/version
HTTP/1.0 200 OK
Server: BaseHTTP/0.6 Python/3.11.6
Date: ...
Access-Control-Allow-Origin: *
Access-Control-Allow-Credentials: true
WWW-Authenticate: Bearer

{"version": 1}%