mirror of
https://github.com/weechat/weechat.git
synced 2026-06-12 14:14:48 +02:00
1829 lines
45 KiB
Plaintext
1829 lines
45 KiB
Plaintext
// SPDX-FileCopyrightText: 2003-2026 Sébastien Helleu <flashcode@flashtux.org>
|
||
//
|
||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||
|
||
= WeeChat API Relay
|
||
:author: Sébastien Helleu
|
||
:email: flashcode@flashtux.org
|
||
:lang: en
|
||
include::includes/attributes-en.adoc[]
|
||
|
||
[[introduction]]
|
||
== Introduction
|
||
|
||
This document is the specification of _api_ relay protocol: the protocol used
|
||
to relay WeeChat data to clients using an HTTP REST API.
|
||
|
||
[[terminology]]
|
||
=== Terminology
|
||
|
||
The following terms are used in this document:
|
||
|
||
* _relay_: this is the WeeChat with relay plugin, which acts as "server" and
|
||
allows _clients_ to connect
|
||
* _client_: this is a software connected to _relay_ via a network connection
|
||
(WeeChat itself or a remote interface).
|
||
|
||
[[network_diagram]]
|
||
=== Network diagram
|
||
|
||
The _clients_ are connected to _relay_ like shown in this diagram:
|
||
|
||
include::includes/relay.en.adoc[tag=diagram]
|
||
|
||
All clients here are clients using _api_ protocol in _relay_ plugin. +
|
||
The _relay_ plugin also allows _irc_ and _weechat_ protocols (not described in this document).
|
||
|
||
[[protocol_generalities]]
|
||
== Protocol generalities
|
||
|
||
* Connections from _client_ to _relay_ are made using TCP sockets on IP/port
|
||
used by _relay_ plugin to listen to new connections.
|
||
* Number of _clients_ is limited by the option _relay.network.max_clients_.
|
||
* Each _client_ is independent from other clients.
|
||
* The _api_ relay is an HTTP REST API using JSON format for input/output.
|
||
* Messages are automatically compressed (deflate, gzip, zstd and permessage-deflate
|
||
for websocket protocol).
|
||
* WeeChat can be used as client of this relay.
|
||
|
||
[[api_versioning]]
|
||
=== API versioning
|
||
|
||
The API is versioned using a "practical" https://semver.org[semantic Versioning ^↗^^],
|
||
like WeeChat, on three digits `X.Y.Z`, where:
|
||
|
||
* `X` is the major version
|
||
* `Y` is the minor version
|
||
* `Z` is the patch version.
|
||
|
||
Example: version `2.0.0` brings breaking changes vs version `1.2.3`.
|
||
|
||
The API version is returned by the <<resource_version,version>> resource.
|
||
|
||
[[api_schema]]
|
||
=== API schema
|
||
|
||
You can browse and test the API online: https://weechat.org/api/[WeeChat Relay API ^↗^^].
|
||
|
||
[[response_codes]]
|
||
=== Response codes
|
||
|
||
The following HTTP response codes can be sent back to the client:
|
||
|
||
* `200 OK`: response OK with a body (JSON)
|
||
* `204 No Content`: response OK without body
|
||
* `400 Bad Request`: invalid request received
|
||
* `401 Unauthorized`: missing or invalid credentials
|
||
* `403 Forbidden`: insufficient permissions
|
||
* `404 Not Found`: resource not found
|
||
* `500 Internal Server Error`: internal server error
|
||
* `503 Service Unavailable`: service unavailable
|
||
|
||
When connected via websocket protocol, an extra response code is sent when WeeChat
|
||
pushes data to the client on events:
|
||
|
||
* `0 Event`: event pushed to the client, if synchronization is enabled with
|
||
<<resource_sync,sync>> resource.
|
||
|
||
[[date_format]]
|
||
=== Date format
|
||
|
||
The date format is https://en.wikipedia.org/wiki/ISO_8601[ISO 8601 ^↗^^],
|
||
using UTC timezone (this is then different from the display by WeeChat which
|
||
uses the local timezone). +
|
||
The dates are returned with maximum precision: up to microseconds if possible,
|
||
or milliseconds, or just seconds.
|
||
|
||
Examples:
|
||
|
||
----
|
||
2023-12-05T19:46:03.847625Z
|
||
2023-12-05T19:46:03.847Z
|
||
2023-12-05T19:46:03Z
|
||
----
|
||
|
||
[[authentication]]
|
||
== Authentication
|
||
|
||
The password must be sent in the header `Authorization` with `Basic`
|
||
authentication schema or in the header `Sec-WebSocket-Protocol` (see details
|
||
below).
|
||
|
||
The password can be sent as plain text or hashed, with one of these formats
|
||
for user and password:
|
||
|
||
* `plain:<password>`
|
||
* `hash:sha256:<timestamp>:<hash>`
|
||
* `hash:sha512:<timestamp>:<hash>`
|
||
* `hash:pbkdf2+sha256:<timestamp>:<iterations>:<hash>`
|
||
* `hash:pbkdf2+sha512:<timestamp>:<iterations>:<hash>`
|
||
|
||
Where:
|
||
|
||
* `<password>` is the password as plain text
|
||
* `<timestamp>` is the current timestamp as integer (number of seconds since
|
||
the Unix Epoch); it is used to prevent replay attacks
|
||
* `<iterations>` is the number of iterations (for PBKDF2 algorithm only)
|
||
* `<hash>` is the hashed value of timestamp + password (as hexadecimal)
|
||
|
||
[NOTE]
|
||
The max number of seconds allowed before and after the received time
|
||
(when password is sent hashed) can be configured with option _relay.network.time_window_.
|
||
|
||
Example:
|
||
|
||
* current timestamp is `1706431066`
|
||
* password is `secret_password`
|
||
* hash algorithm is `sha256`
|
||
* result hash is the SHA256 of string `1706431066secret_password` which is as hexadecimal:
|
||
`dfa1db3f6bb6445d18d9ec7427c10f6421274e3a4751e6c1ffc7dd28c94eadf6`
|
||
* the `Authorization` header is the base64 encoded string
|
||
`hash:sha256:1706431066:dfa1db3f6bb6445d18d9ec7427c10f6421274e3a4751e6c1ffc7dd28c94eadf6`:
|
||
`aGFzaDpzaGEyNTY6MTcwNjQzMTA2NjpkZmExZGIzZjZiYjY0NDVkMThkOWVjNzQyN2MxMGY2NDIxMjc0ZTNhNDc1MWU2YzFmZmM3ZGQyOGM5NGVhZGY2`.
|
||
|
||
The headers `Authorization` and `Sec-WebSocket-Protocol` are allowed in the first
|
||
request with the websocket protocol or any HTTP request in the other cases.
|
||
|
||
Request example with plain text password:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/version'
|
||
----
|
||
|
||
Request example with hashed password (SHA256):
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'hash:sha256:1706431066:dfa1db3f6bb6445d18d9ec7427c10f6421274e3a4751e6c1ffc7dd28c94eadf6' 'https://localhost:9000/api/version'
|
||
----
|
||
|
||
If TOTP (Time-based One-Time Password) is enabled on WeeChat/relay side
|
||
(option `relay.network.totp_secret` is set), you must send the TOTP value
|
||
in the `x-weechat-totp` header like this:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'hash:sha256:1706431066:dfa1db3f6bb6445d18d9ec7427c10f6421274e3a4751e6c1ffc7dd28c94eadf6' -H "x-weechat-totp: 123456" 'https://localhost:9000/api/version'
|
||
----
|
||
|
||
In case of error, a response `401 Unauthorized` is returned with a field `error`
|
||
in JSON data that describes the error.
|
||
|
||
Response: missing password:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 401 Unauthorized
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"error": "Missing password"
|
||
}
|
||
----
|
||
|
||
Response: wrong password:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 401 Unauthorized
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"error": "Invalid password"
|
||
}
|
||
----
|
||
|
||
Response: invalid hash algorithm:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 401 Unauthorized
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"error": "Invalid hash algorithm (not found or not supported)"
|
||
}
|
||
----
|
||
|
||
Response: invalid timestamp:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 401 Unauthorized
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"error": "Invalid timestamp"
|
||
}
|
||
----
|
||
|
||
Response: invalid number of iterations:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 401 Unauthorized
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"error": "Invalid number of iterations"
|
||
}
|
||
----
|
||
|
||
Response: missing TOTP:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 401 Unauthorized
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"error": "Missing TOTP"
|
||
}
|
||
----
|
||
|
||
Response: wrong TOTP:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 401 Unauthorized
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"error": "Invalid TOTP"
|
||
}
|
||
----
|
||
|
||
[[authentication_sec_websocket_protocol]]
|
||
=== Sec-WebSocket-Protocol
|
||
|
||
The JavaScript WebSocket API used in current web browsers does not support
|
||
specifying the `Authorization` header. Therefore it's also supported to send
|
||
the password in the `Sec-WebSocket-Protocol` header which is the only header
|
||
possible to set with this API.
|
||
|
||
To use this header, you must specify the sub-protocols `api.weechat` and
|
||
`base64url.bearer.authorization.weechat.<auth>` where `<auth>` is the base64url
|
||
encoded string of the password in the same format as explained above.
|
||
|
||
Example with password `secret_password` encoded in plain text. This makes the
|
||
string to base64url encode `plain:secret_password` which is
|
||
`cGxhaW46c2VjcmV0X3Bhc3N3b3Jk`.
|
||
|
||
----
|
||
Sec-WebSocket-Protocol: api.weechat, base64url.bearer.authorization.weechat.cGxhaW46c2VjcmV0X3Bhc3N3b3Jk
|
||
----
|
||
|
||
This can be set with the JavaScript WebSocket API like this:
|
||
|
||
[source,javascript]
|
||
----
|
||
const ws = new WebSocket("wss://localhost:9000/api", [
|
||
"api.weechat",
|
||
"base64url.bearer.authorization.weechat.cGxhaW46c2VjcmV0X3Bhc3N3b3Jk",
|
||
])
|
||
----
|
||
|
||
[[compression]]
|
||
== Compression
|
||
|
||
Compression of response body is automatic and based on header `Accept-Encoding`
|
||
sent by the client.
|
||
|
||
Supported compression formats are:
|
||
|
||
* `deflate` (zlib)
|
||
* `gzip`
|
||
* `zstd`
|
||
|
||
Request example:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' -H "Accept-Encoding: gzip" 'https://localhost:9000/api/version'
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 200 OK
|
||
Content-Type: application/json; charset=utf-8
|
||
Content-Encoding: gzip
|
||
Content-Length: 77
|
||
----
|
||
|
||
----
|
||
[77 bytes data]
|
||
----
|
||
|
||
Note: with websocket protocol, the extension "permessage-deflate" allows to
|
||
compress messages with zlib.
|
||
|
||
[[resources]]
|
||
== Resources
|
||
|
||
[[resource_preflight]]
|
||
=== Preflight request
|
||
|
||
The preflight request with HTTP method `OPTIONS` is used by web browsers to check
|
||
that the server (WeeChat) will permit the actual request.
|
||
|
||
Request example: check that request `GET /api/version` is authorized:
|
||
|
||
[source,http]
|
||
----
|
||
OPTIONS /api/version HTTP/1.1
|
||
Host: localhost:9000
|
||
Connection: keep-alive
|
||
Accept: */*
|
||
Access-Control-Request-Method: GET
|
||
Access-Control-Request-Headers: authorization
|
||
Origin: https://localhost
|
||
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/123.0.0.0 Safari/537.36
|
||
Sec-Fetch-Mode: cors
|
||
Sec-Fetch-Site: same-site
|
||
Sec-Fetch-Dest: empty
|
||
Referer: https://localhost/
|
||
Accept-Encoding: gzip, deflate, br, zstd
|
||
Accept-Language: en-US,en;q=0.9,fr;q=0.8
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 204 No Content
|
||
Access-Control-Allow-Methods: GET, POST, PUT, DELETE
|
||
Access-Control-Allow-Headers: origin, content-type, accept, authorization
|
||
Access-Control-Allow-Origin: *
|
||
Content-Type: application/json; charset=utf-8
|
||
Content-Length: 0
|
||
----
|
||
|
||
[[resource_handshake]]
|
||
=== Handshake
|
||
|
||
Perform an handshake between the client and WeeChat.
|
||
|
||
This resource is accessible without authentication.
|
||
|
||
Endpoint:
|
||
|
||
----
|
||
POST /api/handshake
|
||
----
|
||
|
||
Body parameters:
|
||
|
||
* `password_hash_algo` (array of strings, optional): list of hash algorithms
|
||
supported by the client, each string can be:
|
||
** `plain`: plain-text password (no hash)
|
||
** `sha256`: hash SHA256
|
||
** `sha512`: hash SHA512
|
||
** `pbkdf2+sha256`: hash PBKDF2 with SHA256
|
||
** `pbkdf2+sha512`: hash PBKDF2 with SHA512
|
||
|
||
The response has the following fields:
|
||
|
||
* `password_hash_algo` (string): the hash algorithm to use
|
||
(`null` if no algorithm is compatible)
|
||
* `password_hash_iterations` (integer): the number of iterations to use if
|
||
hash PBKDF2 is used
|
||
* `totp` (boolean): `true` if TOTP is enabled in WeeChat (then the client must
|
||
send TOTP in specific header), `false` otherwise
|
||
|
||
Request example:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -X POST -d '{"password_hash_algo": ["plain", "sha256", "sha512"]}' 'https://localhost:9000/api/handshake'
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 200 OK
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"password_hash_algo": "sha512",
|
||
"password_hash_iterations": 100000,
|
||
"totp": false
|
||
}
|
||
----
|
||
|
||
[[resource_version]]
|
||
=== Version
|
||
|
||
Return the WeeChat and relay API versions.
|
||
|
||
Endpoint:
|
||
|
||
----
|
||
GET /api/version
|
||
----
|
||
|
||
Request example:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/version'
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 200 OK
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"weechat_version": "4.2.0-dev",
|
||
"weechat_version_git": "v4.1.0-143-g0b1cda1c4",
|
||
"weechat_version_number": 67239936,
|
||
"relay_api_version": "0.0.1",
|
||
"relay_api_version_number": 1
|
||
}
|
||
----
|
||
|
||
[[resource_buffers]]
|
||
=== Buffers
|
||
|
||
Return buffers, lines and nicks.
|
||
|
||
Endpoints:
|
||
|
||
----
|
||
GET /api/buffers
|
||
GET /api/buffers/{buffer_id}
|
||
GET /api/buffers/{buffer_name}
|
||
----
|
||
|
||
Path parameters:
|
||
|
||
* `buffer_id` (integer, optional): buffer unique identifier (not to be confused
|
||
with the buffer number, which is different)
|
||
* `buffer_name` (string, optional): buffer name
|
||
|
||
Query parameters:
|
||
|
||
* `lines` (integer, optional, default: `0`): number of lines to return in buffers
|
||
with formatted content:
|
||
** negative number: return N lines from the end of buffer (newest lines)
|
||
** `0`: do not return any line
|
||
** positive number: return N lines from the beginning of buffer (oldest lines)
|
||
* `lines_free` (integer, optional, default: `0` if `lines` is `0`, otherwise all lines):
|
||
number of lines to return in buffers with free content:
|
||
** negative number: return N lines from the end of buffer
|
||
** `0`: do not return any line
|
||
** positive number: return N lines from the beginning of buffer
|
||
* `nicks` (boolean, optional, default: `false`): return nicks in buffer
|
||
* `colors` (string, optional, default: `ansi`): how to return strings with color codes:
|
||
** `ansi`: return ANSI color codes
|
||
** `weechat`: return WeeChat internal color codes
|
||
** `strip`: strip colors
|
||
|
||
Request example: get all buffers without lines:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/buffers'
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 200 OK
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
[
|
||
{
|
||
"id": 1709932823238637,
|
||
"name": "core.weechat",
|
||
"short_name": "weechat",
|
||
"number": 1,
|
||
"type": "formatted",
|
||
"hidden": false,
|
||
"title": "WeeChat 4.2.0-dev (C) 2003-2023 - https://weechat.org/",
|
||
"modes": "",
|
||
"input_prompt": "",
|
||
"input": "",
|
||
"input_position": 0,
|
||
"input_multiline": false,
|
||
"nicklist": false,
|
||
"nicklist_case_sensitive": false,
|
||
"nicklist_display_groups": true,
|
||
"time_displayed": true,
|
||
"local_variables": {
|
||
"plugin": "core",
|
||
"name": "weechat"
|
||
},
|
||
"keys": []
|
||
},
|
||
{
|
||
"id": 1709932823423765,
|
||
"name": "irc.server.libera",
|
||
"short_name": "libera",
|
||
"number": 2,
|
||
"type": "formatted",
|
||
"hidden": false,
|
||
"title": "IRC: irc.libera.chat/6697 (2001:4b7a:a008::6667)",
|
||
"modes": "",
|
||
"input_prompt": "",
|
||
"input": "",
|
||
"input_position": 0,
|
||
"input_multiline": false,
|
||
"nicklist": false,
|
||
"nicklist_case_sensitive": false,
|
||
"nicklist_display_groups": true,
|
||
"time_displayed": true,
|
||
"local_variables": {
|
||
"plugin": "irc",
|
||
"name": "server.libera",
|
||
"type": "server",
|
||
"server": "libera",
|
||
"channel": "libera",
|
||
"charset_modifier": "irc.libera",
|
||
"nick": "alice",
|
||
"tls_version": "TLS1.3",
|
||
"host": "~alice@example.com"
|
||
},
|
||
"keys": []
|
||
},
|
||
{
|
||
"id": 1709932823649069,
|
||
"name": "irc.libera.#weechat",
|
||
"short_name": "#weechat",
|
||
"number": 3,
|
||
"type": "formatted",
|
||
"hidden": false,
|
||
"title": "Welcome to the WeeChat official support channel",
|
||
"modes": "+nt",
|
||
"input_prompt": "\u001b[92m@\u001b[96malice\u001b[48;5;22m(\u001b[39mi\u001b[48;5;22m)",
|
||
"input": "",
|
||
"input_position": 0,
|
||
"input_multiline": false,
|
||
"nicklist": true,
|
||
"nicklist_case_sensitive": false,
|
||
"nicklist_display_groups": false,
|
||
"time_displayed": true,
|
||
"local_variables": {
|
||
"plugin": "irc",
|
||
"name": "libera.#weechat",
|
||
"type": "channel",
|
||
"server": "libera",
|
||
"channel": "#weechat",
|
||
"nick": "alice",
|
||
"host": "~alice@example.com"
|
||
},
|
||
"keys": []
|
||
}
|
||
]
|
||
----
|
||
|
||
Request example: get WeeChat core buffer with only last line and no color codes:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/buffers/core.weechat?lines=-1&colors=strip'
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 200 OK
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"id": 1709932823238637,
|
||
"name": "core.weechat",
|
||
"short_name": "weechat",
|
||
"number": 1,
|
||
"type": "formatted",
|
||
"hidden": false,
|
||
"title": "WeeChat 4.2.0-dev (C) 2003-2023 - https://weechat.org/",
|
||
"modes": "",
|
||
"input_prompt": "",
|
||
"input": "",
|
||
"input_position": 0,
|
||
"input_multiline": false,
|
||
"nicklist": false,
|
||
"nicklist_case_sensitive": false,
|
||
"nicklist_display_groups": true,
|
||
"time_displayed": true,
|
||
"local_variables": {
|
||
"plugin": "core",
|
||
"name": "weechat"
|
||
},
|
||
"keys": [],
|
||
"lines": [
|
||
{
|
||
"id": 10,
|
||
"y": -1,
|
||
"date": "2023-12-24T08:17:20.786538Z",
|
||
"date_printed": "2023-12-24T08:17:20.786538Z",
|
||
"displayed": true,
|
||
"highlight": false,
|
||
"notify_level": 0,
|
||
"prefix": "",
|
||
"message": "Plugins loaded: alias, buflist, charset, exec, fifo, fset, guile, irc, javascript, logger, lua, perl, php, python, relay, ruby, script, spell, tcl, trigger, typing, xfer",
|
||
"tags": []
|
||
}
|
||
]
|
||
}
|
||
----
|
||
|
||
Request example: get an IRC channel buffers with nicks:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/buffers/irc.libera.%23weechat?nicks=true'
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 200 OK
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"id": 1709932823649069,
|
||
"name": "irc.libera.#weechat",
|
||
"short_name": "#weechat",
|
||
"number": 3,
|
||
"type": "formatted",
|
||
"hidden": false,
|
||
"title": "Welcome to the WeeChat official support channel",
|
||
"modes": "+nt",
|
||
"input_prompt": "\u001b[92m@\u001b[96malice\u001b[48;5;22m(\u001b[39mi\u001b[48;5;22m)",
|
||
"input": "",
|
||
"input_position": 0,
|
||
"input_multiline": false,
|
||
"nicklist": true,
|
||
"nicklist_case_sensitive": false,
|
||
"nicklist_display_groups": false,
|
||
"time_displayed": true,
|
||
"local_variables": {
|
||
"plugin": "irc",
|
||
"name": "libera.#weechat",
|
||
"type": "channel",
|
||
"server": "libera",
|
||
"channel": "#weechat",
|
||
"nick": "alice",
|
||
"host": "~alice@example.com"
|
||
},
|
||
"keys": [],
|
||
"nicklist_root": {
|
||
"id": 0,
|
||
"parent_group_id": -1,
|
||
"name": "root",
|
||
"color_name": "",
|
||
"color": "",
|
||
"visible": false,
|
||
"groups": [
|
||
{
|
||
"id": 1709932823649181,
|
||
"parent_group_id": 0,
|
||
"name": "000|o",
|
||
"color_name": "weechat.color.nicklist_group",
|
||
"color": "\u001b[32m",
|
||
"visible": true,
|
||
"groups": [],
|
||
"nicks": [
|
||
{
|
||
"id": 1709932823649184,
|
||
"parent_group_id": 1709932823649181,
|
||
"prefix": "@",
|
||
"prefix_color_name": "lightgreen",
|
||
"prefix_color": "\u001b[92m",
|
||
"name": "alice",
|
||
"color_name": "bar_fg",
|
||
"color": "",
|
||
"visible": true
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": 1709932823649189,
|
||
"parent_group_id": 0,
|
||
"name": "001|h",
|
||
"color_name": "weechat.color.nicklist_group",
|
||
"color": "\u001b[32m",
|
||
"visible": true,
|
||
"groups": [],
|
||
"nicks": []
|
||
},
|
||
{
|
||
"id": 1709932823649203,
|
||
"parent_group_id": 0,
|
||
"name": "002|v",
|
||
"color_name": "weechat.color.nicklist_group",
|
||
"color": "\u001b[32m",
|
||
"visible": true,
|
||
"groups": [],
|
||
"nicks": []
|
||
},
|
||
{
|
||
"id": 1709932823649210,
|
||
"parent_group_id": 0,
|
||
"name": "999|...",
|
||
"color_name": "weechat.color.nicklist_group",
|
||
"color": "\u001b[32m",
|
||
"visible": true,
|
||
"groups": [],
|
||
"nicks": []
|
||
}
|
||
],
|
||
"nicks": []
|
||
}
|
||
}
|
||
----
|
||
|
||
Request example: get fset buffer:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/buffers/fset.fset'
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 200 OK
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"id": 1709932823897200,
|
||
"name": "fset.fset",
|
||
"short_name": "",
|
||
"number": 4,
|
||
"type": "free",
|
||
"hidden": false,
|
||
"title": "\u001b[96m1/\u001b[36m3565 | Filter: \u001b[93m* | Sort: \u001b[97m~name | Key(input): alt+space=toggle boolean, alt+'-'(-)=subtract 1 or set, alt+'+'(+)=add 1 or append, alt+f,alt+r(r)=reset, alt+f,alt+u(u)=unset, alt+enter(s)=set, alt+f,alt+n(n)=set new value, alt+f,alt+a(a)=append, alt+','=mark/unmark, shift+down=mark and move down, shift+up=move up and mark, ($)=refresh, ($$)=unmark/refresh, (m)=mark matching options, (u)=unmark matching options, alt+p(p)=toggle plugins desc, alt+v(v)=toggle help bar, ctrl+x(x)=switch format, (q)=close buffer",
|
||
"modes": "",
|
||
"input_prompt": "",
|
||
"input": "",
|
||
"input_position": 0,
|
||
"input_multiline": false,
|
||
"nicklist": false,
|
||
"nicklist_case_sensitive": false,
|
||
"nicklist_display_groups": true,
|
||
"time_displayed": true,
|
||
"local_variables": {
|
||
"plugin": "fset",
|
||
"name": "fset",
|
||
"type": "option",
|
||
"filter": "*"
|
||
},
|
||
"keys": [
|
||
{
|
||
"key": "ctrl-l",
|
||
"command": "/fset -refresh"
|
||
},
|
||
{
|
||
"key": "ctrl-n",
|
||
"command": "/eval ${if:${weechat.bar.buflist.hidden}?/fset -down:/buffer +1}"
|
||
},
|
||
{
|
||
"key": "ctrl-x",
|
||
"command": "/fset -format"
|
||
},
|
||
{
|
||
"key": "down",
|
||
"command": "/fset -down"
|
||
},
|
||
{
|
||
"key": "f11",
|
||
"command": "/fset -left"
|
||
},
|
||
{
|
||
"key": "f12",
|
||
"command": "/fset -right"
|
||
},
|
||
{
|
||
"key": "meta-+",
|
||
"command": "/fset -add 1"
|
||
},
|
||
{
|
||
"key": "meta--",
|
||
"command": "/fset -add -1"
|
||
},
|
||
{
|
||
"key": "meta-comma",
|
||
"command": "/fset -mark"
|
||
},
|
||
{
|
||
"key": "meta-end",
|
||
"command": "/fset -go end"
|
||
},
|
||
{
|
||
"key": "meta-f,meta-a",
|
||
"command": "/fset -append"
|
||
},
|
||
{
|
||
"key": "meta-f,meta-n",
|
||
"command": "/fset -setnew"
|
||
},
|
||
{
|
||
"key": "meta-f,meta-r",
|
||
"command": "/fset -reset"
|
||
},
|
||
{
|
||
"key": "meta-f,meta-u",
|
||
"command": "/fset -unset"
|
||
},
|
||
{
|
||
"key": "meta-home",
|
||
"command": "/fset -go 0"
|
||
},
|
||
{
|
||
"key": "meta-p",
|
||
"command": "/mute /set fset.look.show_plugins_desc toggle"
|
||
},
|
||
{
|
||
"key": "meta-q",
|
||
"command": "/input insert meta-q fset ${property}"
|
||
},
|
||
{
|
||
"key": "meta-return",
|
||
"command": "/fset -set"
|
||
},
|
||
{
|
||
"key": "meta-space",
|
||
"command": "/fset -toggle"
|
||
},
|
||
{
|
||
"key": "meta-v",
|
||
"command": "/bar toggle fset"
|
||
},
|
||
{
|
||
"key": "shift-down",
|
||
"command": "/fset -mark; /fset -down"
|
||
},
|
||
{
|
||
"key": "shift-up",
|
||
"command": "/fset -up; /fset -mark"
|
||
},
|
||
{
|
||
"key": "up",
|
||
"command": "/fset -up"
|
||
}
|
||
]
|
||
}
|
||
----
|
||
|
||
[[resource_buffers_lines]]
|
||
==== Lines
|
||
|
||
Return lines in a buffer.
|
||
|
||
Endpoints:
|
||
|
||
----
|
||
GET /api/buffers/{buffer_id}/lines
|
||
GET /api/buffers/{buffer_id}/lines/{line_id}
|
||
GET /api/buffers/{buffer_name}/lines
|
||
GET /api/buffers/{buffer_name}/lines/{line_id}
|
||
----
|
||
|
||
Path parameters:
|
||
|
||
* `buffer_id` (integer, **required**): buffer unique identifier (not to be
|
||
confused with the buffer number, which is different)
|
||
* `buffer_name` (string, **required**): buffer name
|
||
* `line_id` (integer, optional): return a single line with this identifier
|
||
|
||
Query parameters:
|
||
|
||
* `lines` (integer, optional, default: all lines): number of lines to return:
|
||
** negative number: return N lines from the end of buffer (newest lines)
|
||
** `0`: do not return any line (allowed but doesn't make sense with this resource)
|
||
** positive number: return N lines from the beginning of buffer (oldest lines)
|
||
* `colors` (string, optional, default: `ansi`): how to return strings with color codes:
|
||
** `ansi`: return ANSI color codes
|
||
** `weechat`: return WeeChat internal color codes
|
||
** `strip`: strip colors
|
||
|
||
Request example: get last 1000 lines of a buffer, without color codes:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/buffers/irc.libera.%23weechat/lines?lines=-1000&colors=strip'
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 200 OK
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
[
|
||
{
|
||
"id": 0,
|
||
"y": -1,
|
||
"date": "2023-12-05T19:46:03.847625Z",
|
||
"date_printed": "2023-12-05T19:46:03.847625Z",
|
||
"displayed": true,
|
||
"highlight": false,
|
||
"notify_level": 0,
|
||
"prefix": "-->",
|
||
"message": "alice (~alice@example.com) has joined #test",
|
||
"tags": [
|
||
"irc_join",
|
||
"irc_tag_account=alice",
|
||
"irc_tag_time=2023-12-05T19:46:03.847Z",
|
||
"nick_alice",
|
||
"host_~alice@example.com",
|
||
"log4"
|
||
]
|
||
},
|
||
{
|
||
"id": 1,
|
||
"y": -1,
|
||
"date": "2023-12-05T19:46:03.986543Z",
|
||
"date_printed": "2023-12-05T19:46:03.986543Z",
|
||
"displayed": true,
|
||
"highlight": false,
|
||
"notify_level": 0,
|
||
"prefix": "--",
|
||
"message": "Mode #test [+Cnst] by zirconium.libera.chat",
|
||
"tags": [
|
||
"irc_mode",
|
||
"irc_tag_time=2023-12-05T19:46:03.986Z",
|
||
"nick_zirconium.libera.chat",
|
||
"log3"
|
||
]
|
||
},
|
||
{
|
||
"id": 2,
|
||
"y": -1,
|
||
"date": "2023-12-05T19:46:04.287546Z",
|
||
"date_printed": "2023-12-05T19:46:04.287546Z",
|
||
"displayed": true,
|
||
"highlight": false,
|
||
"notify_level": 0,
|
||
"prefix": "--",
|
||
"message": "Channel #test: 1 nick (1 op, 0 voiced, 0 regular)",
|
||
"tags": [
|
||
"irc_366",
|
||
"irc_numeric",
|
||
"irc_tag_time=2023-12-05T19:46:04.287Z",
|
||
"nick_zirconium.libera.chat",
|
||
"log3"
|
||
]
|
||
}
|
||
]
|
||
----
|
||
|
||
[[resources_buffers_nicks]]
|
||
==== Nicks
|
||
|
||
Return nicks in a buffer.
|
||
|
||
Endpoints:
|
||
|
||
----
|
||
GET /api/buffers/{buffer_id}/nicks
|
||
GET /api/buffers/{buffer_name}/nicks
|
||
----
|
||
|
||
Path parameters:
|
||
|
||
* `buffer_id` (integer, **required**): buffer unique identifier (not to be
|
||
confused with the buffer number, which is different)
|
||
* `buffer_name` (string, **required**): buffer name
|
||
|
||
Request example: get nicks of a buffer:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/buffers/irc.libera.%23weechat/nicks'
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 200 OK
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"id": 0,
|
||
"parent_group_id": -1,
|
||
"name": "root",
|
||
"color_name": "",
|
||
"color": "",
|
||
"visible": false,
|
||
"groups": [
|
||
{
|
||
"id": 1709932823649181,
|
||
"parent_group_id": 0,
|
||
"name": "000|o",
|
||
"color_name": "weechat.color.nicklist_group",
|
||
"color": "\u001b[32m",
|
||
"visible": true,
|
||
"groups": [],
|
||
"nicks": [
|
||
{
|
||
"id": 1709932823649184,
|
||
"parent_group_id": 1709932823649181,
|
||
"prefix": "@",
|
||
"prefix_color_name": "lightgreen",
|
||
"prefix_color": "\u001b[92m",
|
||
"name": "alice",
|
||
"color_name": "bar_fg",
|
||
"color": "",
|
||
"visible": true
|
||
}
|
||
]
|
||
},
|
||
{
|
||
"id": 1709932823649189,
|
||
"parent_group_id": 0,
|
||
"name": "001|h",
|
||
"color_name": "weechat.color.nicklist_group",
|
||
"color": "\u001b[32m",
|
||
"visible": true,
|
||
"groups": [],
|
||
"nicks": []
|
||
},
|
||
{
|
||
"id": 1709932823649203,
|
||
"parent_group_id": 0,
|
||
"name": "002|v",
|
||
"color_name": "weechat.color.nicklist_group",
|
||
"color": "\u001b[32m",
|
||
"visible": true,
|
||
"groups": [],
|
||
"nicks": []
|
||
},
|
||
{
|
||
"id": 1709932823649210,
|
||
"parent_group_id": 0,
|
||
"name": "999|...",
|
||
"color_name": "weechat.color.nicklist_group",
|
||
"color": "\u001b[32m",
|
||
"visible": true,
|
||
"groups": [],
|
||
"nicks": []
|
||
}
|
||
],
|
||
"nicks": []
|
||
}
|
||
----
|
||
|
||
[[resource_hotlist]]
|
||
=== Hotlist
|
||
|
||
Return hotlist.
|
||
|
||
Endpoint:
|
||
|
||
----
|
||
GET /api/hotlist
|
||
----
|
||
|
||
Request example:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/hotlist'
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 200 OK
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
[
|
||
{
|
||
"priority": 0,
|
||
"date": "2024-03-17T16:38:51.572834Z",
|
||
"buffer_id": 1710693531508204,
|
||
"count": [
|
||
44,
|
||
0,
|
||
0,
|
||
0
|
||
]
|
||
},
|
||
{
|
||
"priority": 0,
|
||
"date": "2024-03-17T16:38:51.573028Z",
|
||
"buffer_id": 1710693530395959,
|
||
"count": [
|
||
14,
|
||
0,
|
||
0,
|
||
0
|
||
]
|
||
},
|
||
{
|
||
"priority": 0,
|
||
"date": "2024-03-17T16:38:51.611617Z",
|
||
"buffer_id": 1710693531529248,
|
||
"count": [
|
||
4,
|
||
0,
|
||
0,
|
||
0
|
||
]
|
||
}
|
||
]
|
||
----
|
||
|
||
[[resource_input]]
|
||
=== Input
|
||
|
||
Send command or text to a buffer.
|
||
|
||
Endpoint:
|
||
|
||
----
|
||
POST /api/input
|
||
----
|
||
|
||
Body parameters:
|
||
|
||
* `buffer_id` (integer, optional): buffer unique identifier (not to be confused
|
||
with the buffer number, which is different)
|
||
* `buffer_name` (string, optional, default: `core.weechat`): buffer name
|
||
* `command` (string, **required**): command or text to send to the buffer
|
||
|
||
Request example: say "hello!" on channel #weechat:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' -X POST \
|
||
-d '{"buffer_name": "irc.libera.#weechat", "command": "hello!"}' \
|
||
'https://localhost:9000/api/input'
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 204 No content
|
||
----
|
||
|
||
Request example: part and close channel #weechat (command executed on WeeChat
|
||
core buffer):
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' -X POST \
|
||
-d '{"command": "/buffer close irc.libera.#weechat"}' \
|
||
'https://localhost:9000/api/input'
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 204 No content
|
||
----
|
||
|
||
[[resource_completion]]
|
||
=== Completion
|
||
|
||
Complete user command or text in a buffer.
|
||
|
||
Endpoint:
|
||
|
||
----
|
||
POST /api/completion
|
||
----
|
||
|
||
Body parameters:
|
||
|
||
* `buffer_id` (integer, optional): buffer unique identifier (not to be confused
|
||
with the buffer number, which is different)
|
||
* `buffer_name` (string, optional, default: `core.weechat`): buffer name
|
||
* `command` (string, **required**): command or text to complete
|
||
* `position` (integer, optional, default: end of string): position in command
|
||
(first position is 0)
|
||
|
||
Request example: complete command `/qu` on channel #weechat:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' -X POST \
|
||
-d '{"buffer_name": "irc.libera.#weechat", "command": "/qu"}' \
|
||
'https://localhost:9000/api/completion'
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 200 OK
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"context": "command",
|
||
"base_word": "qu",
|
||
"position_replace": 1,
|
||
"add_space": true,
|
||
"list": [
|
||
"query",
|
||
"quiet",
|
||
"quit",
|
||
"quote"
|
||
]
|
||
}
|
||
----
|
||
|
||
[[resource_ping]]
|
||
=== Ping
|
||
|
||
Send a "ping" request.
|
||
|
||
Endpoint:
|
||
|
||
----
|
||
POST /api/ping
|
||
----
|
||
|
||
Body parameters:
|
||
|
||
* `data` (string, optional): string that is sent back in the response
|
||
|
||
Request example: no body:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' -X POST 'https://localhost:9000/api/ping'
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 204 No content
|
||
----
|
||
|
||
Request example: with data:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' -X POST \
|
||
-d '{"data": "1702835741"}' \
|
||
'https://localhost:9000/api/ping'
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 200 OK
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"data": "1702835741"
|
||
}
|
||
----
|
||
|
||
[[resource_sync]]
|
||
=== Sync
|
||
|
||
Start or stop synchronization of data with WeeChat.
|
||
|
||
This resource can be used only when the client is connected with websocket
|
||
protocol, as WeeChat will push messages to the client at any time.
|
||
|
||
If this resource is used without a websocket connection, an error 403 (Forbidden)
|
||
is returned.
|
||
|
||
Endpoint:
|
||
|
||
----
|
||
POST /api/sync
|
||
----
|
||
|
||
Body parameters:
|
||
|
||
* `sync` (boolean, optional, default: `true`): `true` to enable synchronization
|
||
with WeeChat
|
||
* `nicks` (boolean, optional, default: `true`): `true` to receive nick updates
|
||
in buffers (used only if `sync` is `true`)
|
||
* `input` (boolean, optional, default: `true`): `true` to synchronize buffer input
|
||
from remote relay to local client (used only if `sync` is `true`)
|
||
* `colors` (string, optional, default: `ansi`): how to return strings with
|
||
color codes (used only if `sync` is `true`):
|
||
** `ansi`: return ANSI color codes
|
||
** `weechat`: return WeeChat internal color codes
|
||
** `strip`: strip colors
|
||
|
||
Request example with websocket protocol:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"request": "POST /api/sync",
|
||
"body": {
|
||
"nicks": false
|
||
}
|
||
}
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"code": 204,
|
||
"message": "No Content",
|
||
"request": "POST /api/sync",
|
||
"request_body": {
|
||
"nicks":false
|
||
},
|
||
"body_type": null,
|
||
"body": null
|
||
}
|
||
----
|
||
|
||
Request example without websocket protocol (not authorized):
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' -X POST \
|
||
-d '{"nicks": false}' \
|
||
'https://localhost:9000/api/sync'
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 403 Forbidden
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"error": "Sync resource is available only with a websocket connection"
|
||
}
|
||
----
|
||
|
||
[[websocket]]
|
||
== Websocket
|
||
|
||
Websocket protocol is used to make a persistent connection between the client
|
||
and WeeChat and receive events in real-time if synchronization is enabled with
|
||
<<resource_sync,sync>> resource.
|
||
|
||
Authentication must be done only one time when the websocket protocol is used
|
||
(see <<authentication,authentication>>).
|
||
|
||
[[websocket_handshake]]
|
||
=== Websocket handshake
|
||
|
||
To establish the connection, a handshake is performed on the `/api` endpoint
|
||
and looks like:
|
||
|
||
[source,http]
|
||
----
|
||
GET /api HTTP/1.1
|
||
Host: localhost:9000
|
||
Connection: Upgrade
|
||
Pragma: no-cache
|
||
Cache-Control: no-cache
|
||
User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
|
||
Upgrade: websocket
|
||
Origin: https://example.com
|
||
Sec-WebSocket-Version: 13
|
||
Accept-Encoding: gzip, deflate, br
|
||
Accept-Language: en-US,en;q=0.9,fr;q=0.8
|
||
Sec-WebSocket-Key: 2XE8VAJktqi3Tpw5QnfxVQ==
|
||
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
|
||
----
|
||
|
||
WeeChat returns its handshake response to confirm that websocket protocol is
|
||
properly supported (and authentication was successful):
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 101 Switching Protocols
|
||
Upgrade: websocket
|
||
Connection: Upgrade
|
||
Sec-WebSocket-Accept: PaY9vRflWeOKuD0/F7e5gD9At9U=
|
||
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
|
||
----
|
||
|
||
[NOTE]
|
||
The `Sec-WebSocket-Accept` value returned is the SHA-1 hash of the value received,
|
||
concatenated to the GUID `258EAFA5-E914-47DA-95CA-C5AB0DC85B11` (the SHA-1 is
|
||
encoded in base64). +
|
||
In the example above, the SHA-1 of
|
||
`2XE8VAJktqi3Tpw5QnfxVQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11` is
|
||
`PaY9vRflWeOKuD0/F7e5gD9At9U=` (in base64).
|
||
|
||
[[websocket_frames]]
|
||
=== Frames
|
||
|
||
When the client is connected via the websocket protocol:
|
||
|
||
* requests and responses are in JSON, inside websocket frames
|
||
* if synchronization is enabled with <<resource_sync,sync>> resource, WeeChat
|
||
can send JSON frames at any time to the client.
|
||
|
||
Requests to WeeChat are made with a JSON object containing these fields:
|
||
|
||
* `request` (string): the HTTP method and path (example: `GET /api/buffers?lines=-100`)
|
||
* `body` (object or array): the body (optional, for `POST` and `PUT` methods)
|
||
* `request_id` (string): identifier sent back in the response
|
||
|
||
Multiple requests can be sent at once using an array of objects, each object
|
||
being a separate request. +
|
||
Requests are executed in the order received (see example below).
|
||
|
||
Responses to client are made with a JSON object containing these fields:
|
||
|
||
* `code` (integer): HTTP response code (example: `200`)
|
||
* `message` (string): message for the code (example: `OK`)
|
||
* `request` (string): the request (example: `GET /api/buffers?lines=-100`)
|
||
* `request_body` (object): the request body, or `null` if the request had no body
|
||
* `request_id` (string): the request id, or `null` if the request had no id
|
||
* `body_type` (string): type of objects returned in body (see below), or `null`
|
||
if the response has no body
|
||
* `body` (object or array): the body returned, or `null` if the response has no body
|
||
|
||
Body types that can be returned:
|
||
|
||
* `handshake` (object)
|
||
* `version` (object)
|
||
* `buffers` (array)
|
||
* `buffer` (object)
|
||
* `lines` (array)
|
||
* `line` (object)
|
||
* `nick_group` (object)
|
||
* `nick` (object)
|
||
* `hotlist` (object)
|
||
* `ping` (object)
|
||
|
||
[TIP]
|
||
You can browse these schemas online: https://weechat.org/api/[WeeChat Relay API ^↗^^].
|
||
|
||
Request example: get version:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"request": "GET /api/version",
|
||
"request_id": "get_version"
|
||
}
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"code": 200,
|
||
"message": "OK",
|
||
"request": "GET /api/version",
|
||
"request_body": null,
|
||
"request_id": "get_version",
|
||
"body_type": "version",
|
||
"body": {
|
||
"weechat_version": "4.2.0-dev",
|
||
"weechat_version_git": "v4.1.0-143-g0b1cda1c4",
|
||
"weechat_version_number": 67239936,
|
||
"relay_api_version": "0.0.1",
|
||
"relay_api_version_number": 1
|
||
}
|
||
}
|
||
----
|
||
|
||
Request example: say "hello!" on channel #weechat:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"request": "POST /api/input",
|
||
"body": {
|
||
"buffer_name": "irc.libera.#weechat",
|
||
"command": "hello!"
|
||
}
|
||
}
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"code": 204,
|
||
"message": "No Content",
|
||
"request": "POST /api/input",
|
||
"request_body": {
|
||
"buffer_name": "irc.libera.#weechat",
|
||
"command": "hello!"
|
||
},
|
||
"request_id": null,
|
||
"body_type": null,
|
||
"body": null
|
||
}
|
||
----
|
||
|
||
Requests example: send two requests at once: get list of all buffers with lines
|
||
and nicks, then synchronize with the remote:
|
||
|
||
[source,json]
|
||
----
|
||
[
|
||
{
|
||
"request": "GET /api/buffers?lines=-1000&nicks=true&colors=weechat",
|
||
"request_id": "initial_sync"
|
||
},
|
||
{
|
||
"request": "POST /api/sync",
|
||
"body": {
|
||
"colors": "weechat"
|
||
}
|
||
}
|
||
]
|
||
----
|
||
|
||
[NOTE]
|
||
It is recommended to send the synchronization request together with the first
|
||
request that is fetching data, so that no events are missed.
|
||
|
||
First response (body with buffers is truncated for readability):
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"code": 200,
|
||
"message": "OK",
|
||
"request": "GET /api/buffers?lines=-1000&nicks=true&colors=weechat",
|
||
"request_body": null,
|
||
"request_id": "initial_sync",
|
||
"body_type": "buffers",
|
||
"body": [
|
||
{
|
||
"id": 1709932823238637,
|
||
"name": "core.weechat",
|
||
"short_name": "weechat",
|
||
"number": 1,
|
||
"type": "formatted"
|
||
}
|
||
]
|
||
}
|
||
----
|
||
|
||
Second response:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"code": 204,
|
||
"message": "No Content",
|
||
"request": "POST /api/sync",
|
||
"request_body": {
|
||
"colors": "weechat"
|
||
},
|
||
"request_id": null,
|
||
"body_type": null,
|
||
"body": null
|
||
}
|
||
----
|
||
|
||
WeeChat pushes data to the client at any time on some events: when lines are
|
||
displayed, buffers added/removed/changed, nicks added/removed/changed, etc.
|
||
|
||
The messages sent to client have the following fields:
|
||
|
||
* `code`: `0`
|
||
* `message`: `Event`
|
||
* `event_name` (string): the event name (name of signal or hsignal)
|
||
* `buffer_id` (integer): the buffer unique identifier, set only for sub-objects,
|
||
-1 in other cases
|
||
|
||
The following events are sent to the client, according to synchronization options:
|
||
|
||
[width="100%",cols="5,3,3,5",options="header"]
|
||
|===
|
||
| Event name | Buffer id | Body type | Body
|
||
| `buffer_opened` | buffer id | `buffer` | buffer with all lines and nicks
|
||
| `buffer_type_changed` | buffer id | `buffer` | buffer
|
||
| `buffer_moved` | buffer id | `buffer` | buffer
|
||
| `buffer_merged` | buffer id | `buffer` | buffer
|
||
| `buffer_unmerged` | buffer id | `buffer` | buffer
|
||
| `buffer_hidden` | buffer id | `buffer` | buffer
|
||
| `buffer_unhidden` | buffer id | `buffer` | buffer
|
||
| `buffer_renamed` | buffer id | `buffer` | buffer
|
||
| `buffer_title_changed` | buffer id | `buffer` | buffer
|
||
| `buffer_time_for_each_line_changed` | buffer id | `buffer` | buffer
|
||
| `buffer_localvar_added` | buffer id | `buffer` | buffer
|
||
| `buffer_localvar_changed` | buffer id | `buffer` | buffer
|
||
| `buffer_localvar_removed` | buffer id | `buffer` | buffer
|
||
| `buffer_cleared` | buffer id | `buffer` | buffer
|
||
| `buffer_closing` | buffer id | `buffer` | buffer
|
||
| `buffer_closed` | buffer id | null | null
|
||
| `buffer_line_added` | buffer id | `line` | buffer line
|
||
| `buffer_line_data_changed` | buffer id | `line` | buffer line
|
||
| `input_text_changed` | buffer id | `buffer` | buffer
|
||
| `input_text_cursor_moved` | buffer id | `buffer` | buffer
|
||
| `nicklist_group_changed` | buffer id | `nick_group` | nick group
|
||
| `nicklist_group_added` | buffer id | `nick_group` | nick group
|
||
| `nicklist_group_removing` | buffer id | `nick_group` | nick group
|
||
| `nicklist_nick_added` | buffer id | `nick` | nick
|
||
| `nicklist_nick_removing` | buffer id | `nick` | nick
|
||
| `nicklist_nick_changed` | buffer id | `nick` | nick
|
||
| `upgrade` ^(1)^ | -1 | null | null
|
||
| `upgrade_ended` ^(1)^ | -1 | null | null
|
||
| `quit` | -1 | null | null
|
||
|===
|
||
|
||
[NOTE]
|
||
^(1)^ The events `upgrade` and `upgrade_ended` are sent only if the client is
|
||
connected with plain text (no TLS), because with TLS the client is disconnected
|
||
before the upgrade is done (upgrade of TLS connections is not supported).
|
||
|
||
Example: new buffer: channel `#weechat` has been joined:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"code": 0,
|
||
"message": "Event",
|
||
"event_name": "buffer_opened",
|
||
"buffer_id": 1709932823649069,
|
||
"body_type": "buffer",
|
||
"body": {
|
||
"id": 1709932823649069,
|
||
"name": "irc.libera.#test",
|
||
"short_name": "",
|
||
"number": 4,
|
||
"type": "formatted",
|
||
"hidden": false,
|
||
"title": "",
|
||
"modes": "+nt",
|
||
"input_prompt": "\u001b[92m@\u001b[96malice\u001b[48;5;22m(\u001b[39mi\u001b[48;5;22m)",
|
||
"input": "",
|
||
"input_position": 0,
|
||
"input_multiline": false,
|
||
"nicklist": true,
|
||
"nicklist_case_sensitive": false,
|
||
"nicklist_display_groups": false,
|
||
"time_displayed": true,
|
||
"local_variables": {
|
||
"plugin": "irc",
|
||
"name": "libera.#test",
|
||
"type": "channel",
|
||
"nick": "alice",
|
||
"host": "~alice@example.com",
|
||
"server": "libera",
|
||
"channel": "#test"
|
||
},
|
||
"keys": [],
|
||
"lines": []
|
||
}
|
||
}
|
||
----
|
||
|
||
Example: new line displayed on channel `#weechat`:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"code": 0,
|
||
"message": "Event",
|
||
"event_name": "buffer_line_added",
|
||
"buffer_id": 1709932823649069,
|
||
"body_type": "line",
|
||
"body": {
|
||
"id": 5,
|
||
"index": -1,
|
||
"date": "2024-01-07T08:54:00.179483Z",
|
||
"date_printed": "2024-01-07T08:54:00.179483Z",
|
||
"displayed": true,
|
||
"highlight": false,
|
||
"notify_level": 0,
|
||
"prefix": "alice",
|
||
"message": "hello!",
|
||
"tags": [
|
||
"irc_privmsg",
|
||
"self_msg",
|
||
"notify_none",
|
||
"no_highlight",
|
||
"prefix_nick_white",
|
||
"nick_alice",
|
||
"log1"
|
||
]
|
||
}
|
||
}
|
||
----
|
||
|
||
Example: nick `bob` added with operator status in channel `#weechat`:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"code": 0,
|
||
"message": "Event",
|
||
"event_name": "nicklist_nick_added",
|
||
"buffer_id": 1709932823649069,
|
||
"body_type": "nick",
|
||
"body": {
|
||
"id": 1709932823649902,
|
||
"parent_group_id": 1709932823649181,
|
||
"prefix": "@",
|
||
"prefix_color_name": "lightgreen",
|
||
"prefix_color": "\u001b[92m",
|
||
"name": "bob",
|
||
"color_name": "bar_fg",
|
||
"color": "",
|
||
"visible": true
|
||
}
|
||
}
|
||
----
|
||
|
||
Example: channel buffer `#weechat` has been closed:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"code": 0,
|
||
"message": "Event",
|
||
"event_name": "buffer_closed",
|
||
"buffer_id": 1709932823649069,
|
||
"body_type": null,
|
||
"body": null
|
||
}
|
||
----
|
||
|
||
Example: WeeChat is upgrading:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"code": 0,
|
||
"message": "Event",
|
||
"event_name": "upgrade",
|
||
"buffer_id": -1,
|
||
"body_type": null,
|
||
"body": null
|
||
}
|
||
----
|
||
|
||
Example: upgrade of WeeChat is done:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"code": 0,
|
||
"message": "Event",
|
||
"event_name": "upgrade_ended",
|
||
"buffer_id": -1,
|
||
"body_type": null,
|
||
"body": null
|
||
}
|
||
----
|