mirror of
https://github.com/weechat/weechat.git
synced 2026-06-12 14:14:48 +02:00
1883 lines
56 KiB
Plaintext
1883 lines
56 KiB
Plaintext
// SPDX-FileCopyrightText: 2003-2026 Sébastien Helleu <flashcode@flashtux.org>
|
||
// SPDX-FileCopyrightText: 2021-2025 Иван Пешић <ivan.pesic@gmail.com>
|
||
//
|
||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||
|
||
= WeeChat Релеј API
|
||
:author: Sébastien Helleu
|
||
:email: flashcode@flashtux.org
|
||
:lang: sr
|
||
include::includes/attributes-sr.adoc[]
|
||
|
||
[[introduction]]
|
||
== Увод
|
||
|
||
Овај документ је спецификација _api_ релеј протокола: протокола који се
|
||
користи за прослеђивање WeeChat података клијентима употребом HTTP REST API.
|
||
|
||
[[terminology]]
|
||
=== Терминологија
|
||
|
||
У документу се користе следећи појмови:
|
||
|
||
* _релеј_: то је програм WeeChat за релеј додатком који се понаша као „сервер”
|
||
омогућава _клијентима_ да се успоставе везу са њим
|
||
* _клијент_: то је софтвер повезан са _релејем_ преком мрежне везе (сам
|
||
WeeChat или удаљени интерфејс).
|
||
|
||
[[network_diagram]]
|
||
=== Мрежни дијаграм
|
||
|
||
_клијенти_ су повезани са _релејем_ као што је приказано на следећем дијаграму:
|
||
|
||
include::includes/relay.sr.adoc[tag=diagram]
|
||
|
||
[NOTE]
|
||
Сви клијенти овде су клијенти који користе _api_ протокол у _релеј_ додатку. +
|
||
_релеј_ додатак такође подржава _irc_ и _weechat_ протоколе (који нису описани у овом документу).
|
||
|
||
[[protocol_generalities]]
|
||
== Уопштено о протоколу
|
||
|
||
* Везе од _клијента_ ка _релеју_ се успостављају преко TCP сокета на IP/порту
|
||
који користи _релеј_ додатак за ослушкивање нових веза.
|
||
* Број _клијената_ је ограничен опцијом _relay.network.max_clients_.
|
||
* Сваки _клијент_ је независан у односу на остале клијенте.
|
||
* _api_ релеј је HTTP REST API који користи JSON формат за улаз/излаз.
|
||
* Поруке се аутоматски компресују (deflate, gzip, zstd и permessage-deflate
|
||
за websocket протокол).
|
||
* WeeChat може да се користи као клијент за овај релеј.
|
||
|
||
[[api_versioning]]
|
||
=== API верзије
|
||
|
||
API верзије се додељују користећи „практично” https://semver.org[семантичко Верзирање ^↗^^],
|
||
као и WeeChat, на три цифре `X.Y.Z`, при чему је:
|
||
|
||
* `X` главна верзија
|
||
* `Y` мала верзија
|
||
* `Z` верзија закрпе.
|
||
|
||
Пример: верзија `2.0.0` уводи измене које нису компатибилне са верзијом `1.2.3`.
|
||
|
||
API верзију враћа <<resource_version,version>> ресурс.
|
||
|
||
[[api_schema]]
|
||
=== API схема
|
||
|
||
API можете да прегледате и тестирате на мрежи: https://weechat.org/api/[WeeChat API релеј ^↗^^].
|
||
|
||
[[response_codes]]
|
||
=== Кодови одговора
|
||
|
||
Клијенту могу да се врате следећи HTTP кодови одговора:
|
||
|
||
* `200 OK`: одговор OK са телом (JSON)
|
||
* `204 No Content`: одговор OK без тела
|
||
* `400 Bad Request`: примљен је неисправан захтев
|
||
* `401 Unauthorized`: подаци за пријаву недостају или нису исправни
|
||
* `403 Forbidden`: нема довољно дозвола
|
||
* `404 Not Found`: није пронађен ресурс
|
||
* `500 Internal Server Error`: интерна грешка сервера
|
||
* `503 Service Unavailable`: сервис није доступан
|
||
|
||
Када је веза успостављена преко websocket протокола, шаље се још један додатни код
|
||
одговора када WeeChat гура податке клијенту приликом догађаја:
|
||
|
||
* `0 Event`: догађај је гурнут клијенту, ако је синхронизација укључена
|
||
<<resource_sync,sync>> ресурсом.
|
||
|
||
[[date_format]]
|
||
=== Формат датума
|
||
|
||
Формат датума је https://en.wikipedia.org/wiki/ISO_8601[ISO 8601 ^↗^^],
|
||
уз коришћење UTC временске зоне (ово се разликује у односу на приказ у програму
|
||
WeeChat који користи локалну временску зону). +
|
||
Датуми се враћају са максималном прецизношћу: до микросекунде, ако је то могуће,
|
||
или милисекунде, или само секунде.
|
||
|
||
Примери:
|
||
|
||
----
|
||
2023-12-05T19:46:03.847625Z
|
||
2023-12-05T19:46:03.847Z
|
||
2023-12-05T19:46:03Z
|
||
----
|
||
|
||
[[authentication]]
|
||
== Потврда идентитета
|
||
|
||
Лозинка мора да се пошаље у `Authorization` заглављу са `Basic` схемом
|
||
потврде идентитета или у заглављу `Sec-WebSocket-Protocol` (погледајте
|
||
детаље испод).
|
||
|
||
Лозинка може да се пошаље као прости текст или хеширана, користећи један од
|
||
следећих формата за корисничко име и лозинку:
|
||
|
||
* `plain:<лозинка>`
|
||
* `hash:sha256:<временска_ознака>:<хеш>`
|
||
* `hash:sha512:<временска_ознака>:<хеш>`
|
||
* `hash:pbkdf2+sha256:<временска_ознака>:<итерација>:<хеш>`
|
||
* `hash:pbkdf2+sha512:<временска_ознака>:<итерација>:<хеш>`
|
||
|
||
Где је:
|
||
|
||
* `<лозинка>` лозинка као прости текст
|
||
* `<временска_ознака>` је текућа временска ознака као цео број (број секунди
|
||
протекао од Unix Епохе); користи се за спречавање replay напада
|
||
* `<итерација>` број итерација (само за PBKDF2 алгоритам)
|
||
* `<хеш>` је хеширана вредност временска_ознака + лозинка (као хексадецимални број)
|
||
|
||
[NOTE]
|
||
Максимални број секунди који се дозвољава пре и након примљеног времена
|
||
(када се лозинка шаље хеширана) може да се подеси опцијом _relay.network.time_window_.
|
||
|
||
Пример:
|
||
|
||
* тренутна временска ознака је `1706431066`
|
||
* лозинка је `secret_password`
|
||
* хеш алгоритам је `sha256`
|
||
* добијени хеш је SHA256 стринга `1706431066secret_password` и он је хексадецимални број:
|
||
`dfa1db3f6bb6445d18d9ec7427c10f6421274e3a4751e6c1ffc7dd28c94eadf6`
|
||
* `Authorization` заглавље је base64 кодирани стринг
|
||
`hash:sha256:1706431066:dfa1db3f6bb6445d18d9ec7427c10f6421274e3a4751e6c1ffc7dd28c94eadf6`:
|
||
`aGFzaDpzaGEyNTY6MTcwNjQzMTA2NjpkZmExZGIzZjZiYjY0NDVkMThkOWVjNzQyN2MxMGY2NDIxMjc0ZTNhNDc1MWU2YzFmZmM3ZGQyOGM5NGVhZGY2`.
|
||
|
||
Заглавља `Authorization` и `Sec-WebSocket-Protocol` се дозвољавају у првом захтеву
|
||
код websocket протокола, или у било ком HTTP захтеву у осталим случајевима.
|
||
|
||
Пример захтева са лозинком у простом тексту:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/version'
|
||
----
|
||
|
||
Пример захтева са хешираном лозинком (SHA256):
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'hash:sha256:1706431066:dfa1db3f6bb6445d18d9ec7427c10f6421274e3a4751e6c1ffc7dd28c94eadf6' 'https://localhost:9000/api/version'
|
||
----
|
||
|
||
Ако је на WeeChat/релеј страни укључен TOTP (Time-based One-Time Password)
|
||
(постављена је опција `relay.network.totp_secret`), у `x-weechat-totp` заглављу морате
|
||
да пошаљете TOTP вредност на следећи начин:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'hash:sha256:1706431066:dfa1db3f6bb6445d18d9ec7427c10f6421274e3a4751e6c1ffc7dd28c94eadf6' -H "x-weechat-totp: 123456" 'https://localhost:9000/api/version'
|
||
----
|
||
|
||
У случају грешке, враћа се одговор `401 Unauthorized` са пољем `error` у
|
||
JSON подацима које описује грешку.
|
||
|
||
Одговор: недостаје лозинка:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 401 Unauthorized
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"error": "Missing password"
|
||
}
|
||
----
|
||
|
||
Одговор: неисправна лозинка:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 401 Unauthorized
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"error": "Invalid password"
|
||
}
|
||
----
|
||
|
||
Одговор: неисправан хеш алгоритам:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 401 Unauthorized
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"error": "Invalid hash algorithm (not found or not supported)"
|
||
}
|
||
----
|
||
|
||
Одговор: неисправна временска ознака:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 401 Unauthorized
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"error": "Invalid timestamp"
|
||
}
|
||
----
|
||
|
||
Одговор: неисправан број итерација:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 401 Unauthorized
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"error": "Invalid number of iterations"
|
||
}
|
||
----
|
||
|
||
Одговор: недостаје TOTP:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 401 Unauthorized
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"error": "Missing TOTP"
|
||
}
|
||
----
|
||
|
||
Одговор: неисправан TOTP:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 401 Unauthorized
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"error": "Invalid TOTP"
|
||
}
|
||
----
|
||
|
||
[[authentication_sec_websocket_protocol]]
|
||
=== Sec-WebSocket-Protocol
|
||
|
||
JavaScript WebSocket API који се користи у текућим веб прегледачима не подржава
|
||
навођење `Authorization` заглавља. Због тога се такође подржава и слање
|
||
лозинке у `Sec-WebSocket-Protocol` заглављу и то је једино заглавље које
|
||
може да се постави овим API.
|
||
|
||
Да бисте користили ово заглавље, морате да наведете под-протоколе `api.weechat` и
|
||
`base64url.bearer.authorization.weechat.<аут>` где је `<аут>` base64url
|
||
кодирани стринг лозинке у истом формату који је објашњен изнад.
|
||
|
||
Пример са лозинком `secret_password` кодираном у простом тексту. То значи да
|
||
base64url треба да кодира стринг `plain:secret_password`, а то је
|
||
`cGxhaW46c2VjcmV0X3Bhc3N3b3Jk`.
|
||
|
||
----
|
||
Sec-WebSocket-Protocol: api.weechat, base64url.bearer.authorization.weechat.cGxhaW46c2VjcmV0X3Bhc3N3b3Jk
|
||
----
|
||
|
||
Ово може да се постави са JavaScript WebSocket API на следећи начин:
|
||
|
||
[source,javascript]
|
||
----
|
||
const ws = new WebSocket("wss://localhost:9000/api", [
|
||
"api.weechat",
|
||
"base64url.bearer.authorization.weechat.cGxhaW46c2VjcmV0X3Bhc3N3b3Jk",
|
||
])
|
||
----
|
||
|
||
[[compression]]
|
||
== Компресија
|
||
|
||
Компресија тела одговора је аутоматска и заснива се на заглављу `Accept-Encoding`
|
||
које пошаље клијент.
|
||
|
||
Подржавају се следећи формати компресије:
|
||
|
||
* `deflate` (zlib)
|
||
* `gzip`
|
||
* `zstd`
|
||
|
||
Пример захтева:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' -H "Accept-Encoding: gzip" 'https://localhost:9000/api/version'
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 200 OK
|
||
Content-Type: application/json; charset=utf-8
|
||
Content-Encoding: gzip
|
||
Content-Length: 77
|
||
----
|
||
|
||
----
|
||
[77 bytes data]
|
||
----
|
||
|
||
Напомена: са websocket протоколом, проширење „permessage-deflate” омогућава да се
|
||
поруке компресују са zlib.
|
||
|
||
[[resources]]
|
||
== Ресурси
|
||
|
||
[[resource_preflight]]
|
||
=== Пробни захтев
|
||
|
||
Веб прегледачи користе пробне захтеве са HTTP методом `OPTIONS` да провере да ли ће сервер
|
||
(WeeChat) дозволити стварни захтев.
|
||
|
||
Пример захтева: провера да ли је захтев `GET /api/version` одобрен:
|
||
|
||
[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
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[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
|
||
|
||
Обавља усаглашавање клијента и WeeChat.
|
||
|
||
Приступ овом ресурсу је дозвољен и без провере идентитета.
|
||
|
||
Крајња тачка:
|
||
|
||
----
|
||
POST /api/handshake
|
||
----
|
||
|
||
Параметри тела:
|
||
|
||
* `password_hash_algo` (низ стрингова, није обавезан): листа хеш алгоритама
|
||
које подржава клијент, сваки стринг може да буде:
|
||
** `plain`: лозинка у чистом тексту (нема хеширања)
|
||
** `sha256`: хеш SHA256
|
||
** `sha512`: хеш SHA512
|
||
** `pbkdf2+sha256`: хеш PBKDF2 са SHA256
|
||
** `pbkdf2+sha512`: хеш PBKDF2 са SHA512
|
||
|
||
Одговор има следећа поља:
|
||
|
||
* `password_hash_algo` (стринг): хеш алгоритам који треба да се користи
|
||
(`null` ако ниједан алгоритам није компатибилан)
|
||
* `password_hash_iterations` (цео број): број итерација који треба да се
|
||
примени ако се користи хеш PBKDF2
|
||
* `totp` (логичка): `true` ако је у WeeChat укључен TOTP (онда клијент
|
||
мора да пошаље TOTP у одређеном заглављу), `false` у супротном
|
||
|
||
Пример захтева:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -X POST -d '{"password_hash_algo": ["plain", "sha256", "sha512"]}' 'https://localhost:9000/api/handshake'
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 200 OK
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"password_hash_algo": "sha512",
|
||
"password_hash_iterations": 100000,
|
||
"totp": false
|
||
}
|
||
----
|
||
|
||
[[resource_version]]
|
||
=== Version
|
||
|
||
Враћа верзије програма WeeChat и релеј API-ја.
|
||
|
||
Крајња тачка:
|
||
|
||
----
|
||
GET /api/version
|
||
----
|
||
|
||
Пример захтева:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/version'
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[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
|
||
|
||
Враћа бафере, линије и надимке.
|
||
|
||
Крајње тачке:
|
||
|
||
----
|
||
GET /api/buffers
|
||
GET /api/buffers/{id_бафера}
|
||
GET /api/buffers/{име_бафера}
|
||
----
|
||
|
||
Path parameters:
|
||
|
||
* `id_бафера` (цео број, није обавезно): јединствени идентификатор бафера (не треба
|
||
да се помеша са бројем бафера, то је нешто друго)
|
||
* `име_бафера` (стринг, није обавезно): име бафера
|
||
|
||
Параметри упита:
|
||
|
||
* `lines` (цео број, није обавезно, подразумевано: `0`): број линија које се враћају у
|
||
баферима са форматираним садржајем:
|
||
** негативни број: враћа N линија од краја бафера (најновијих линија)
|
||
** `0`: не враћа ниједну линију
|
||
** позитивни број: враћа N линија од почетка бафера (најстаријих линија)
|
||
* `lines_free` (цео број, није обавезно, подразумевано: `0` ако је `lines` `0`, у супротном, све линије):
|
||
број линија који се враћа у баверима са слободним садржајем:
|
||
** негативни број: враћа N линија од краја бафера
|
||
** `0`: не враћа ниједну линију
|
||
** позитивни број: враћа N линија од почетка бафера
|
||
* `nicks` (логичка, није обавезно, подразумевано: `false`): враћа надимке у баферу
|
||
* `colors` (стринг, није обавезно, подразумевано: `ansi`): како се враћају стрингови са кодовима боје:
|
||
** `ansi`: враћају се ANSI кодови боје
|
||
** `weechat`: враћају се WeeChat интерни кодови боје
|
||
** `strip`: уклањају се боје
|
||
|
||
Пример захтева: врати све бафере без линија:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/buffers'
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[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": [],
|
||
"last_read_line_id": -1
|
||
},
|
||
{
|
||
"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": [],
|
||
"last_read_line_id": -1
|
||
},
|
||
{
|
||
"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": [],
|
||
"last_read_line_id": -1
|
||
}
|
||
]
|
||
----
|
||
|
||
Пример захтева: врати WeeChat основни бафер само са последњом линијом и без кодова боје:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/buffers/core.weechat?lines=-1&colors=strip'
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[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": "Учитани додаци: alias, buflist, charset, exec, fifo, fset, guile, irc, javascript, logger, lua, perl, php, python, relay, ruby, script, spell, tcl, trigger, typing, xfer",
|
||
"tags": []
|
||
}
|
||
],
|
||
"last_read_line_id": -1
|
||
}
|
||
----
|
||
|
||
Пример захтева: врати бафере IRC канала са надимцима:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/buffers/irc.libera.%23weechat?nicks=true'
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[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": [],
|
||
"last_read_line_id": -1,
|
||
"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": []
|
||
}
|
||
}
|
||
----
|
||
|
||
Пример захтева: врати fset бафер:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/buffers/fset.fset'
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[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"
|
||
}
|
||
],
|
||
"last_read_line_id": -1
|
||
}
|
||
----
|
||
|
||
[[resource_buffers_lines]]
|
||
==== Lines
|
||
|
||
Враћа линије бафера.
|
||
|
||
Крајње тачке:
|
||
|
||
----
|
||
GET /api/buffers/{id_бафера}/lines
|
||
GET /api/buffers/{id_бафера}/lines/{id_линије}
|
||
GET /api/buffers/{име_бафера}/lines
|
||
GET /api/buffers/{име_бафера}/lines/{id_линије}
|
||
----
|
||
|
||
Параметри путање:
|
||
|
||
* `id_бафера` (цео број, **обавезно**): јединствени идентификатор бафера (не треба
|
||
да се помеша са именом бафера, то је нешто друго)
|
||
* `име_бафера` (стринг, **обавезно**): име бафера
|
||
* `id_линије` (цео број, није обавезно): враћа једну линију са овим идентификатором
|
||
|
||
Параметри упита:
|
||
|
||
* `lines` (цео број, није обавезно, подразумевано: све линије): број линија који се враћа:
|
||
** негативни број: враћа N линија од краја бафера (најновијих линија)
|
||
** `0`: не враћа се ниједна линија (дозвољено је, али нема смисла са овим ресурсом)
|
||
** позитивни број: враћа N линија од почетка бафера (најстаријих линија)
|
||
* `colors` (стринг, није обавезно, подразумевано: `ansi`): како да се врати стринг са кодовима боје:
|
||
** `ansi`: враћају се ANSI кодови боје
|
||
** `weechat`: враћају се WeeChat интерни кодови боје
|
||
** `strip`: уклањају се боје
|
||
|
||
Пример захтева: врати последњих 1000 линија бафера, без кодова боје:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/buffers/irc.libera.%23weechat/lines?lines=-1000&colors=strip'
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[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
|
||
|
||
Враћа надимке у баферу.
|
||
|
||
Крајње тачке:
|
||
|
||
----
|
||
GET /api/buffers/{id_бафера}/nicks
|
||
GET /api/buffers/{име_бафера}/nicks
|
||
----
|
||
|
||
Параметри упита:
|
||
|
||
* `id_бафера` (цео број, **обавезно**): јединствени идентификатор бафера (не треба
|
||
да се помеша са бројем бафера, то је нешто друго)
|
||
* `име_бафера` (стринг, **обавезно**): име бафера
|
||
|
||
Пример захтева: врати надимке бафера:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/buffers/irc.libera.%23weechat/nicks'
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[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
|
||
|
||
Враћа врућу листу.
|
||
|
||
Крајња тачка:
|
||
|
||
----
|
||
GET /api/hotlist
|
||
----
|
||
|
||
Пример захтева:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/hotlist'
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[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
|
||
]
|
||
}
|
||
]
|
||
----
|
||
|
||
// TRANSLATION MISSING
|
||
[[resource_scripts]]
|
||
=== Scripts
|
||
|
||
// TRANSLATION MISSING
|
||
Return loaded scripts (all languages).
|
||
|
||
Крајња тачка:
|
||
|
||
----
|
||
GET /api/scripts
|
||
----
|
||
|
||
Пример захтева:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' 'https://localhost:9000/api/scripts'
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 200 OK
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
[
|
||
{
|
||
"name": "highmon.pl",
|
||
"version": "2.7",
|
||
"description": "Highlight Monitor",
|
||
"author": "KenjiE20",
|
||
"license": "GPL3"
|
||
},
|
||
{
|
||
"name": "go.py",
|
||
"version": "3.1.1",
|
||
"description": "Quick jump to buffers",
|
||
"author": "Sébastien Helleu <flashcode@flashtux.org>",
|
||
"license": "GPL3"
|
||
}
|
||
]
|
||
----
|
||
|
||
[[resource_input]]
|
||
=== Input
|
||
|
||
Шаље команду или текст у бафер.
|
||
|
||
Крајња тачка:
|
||
|
||
----
|
||
POST /api/input
|
||
----
|
||
|
||
Параметри тела:
|
||
|
||
* `buffer_id` (цео број, није обавезно): јединствени идентификатор бафера (не треба
|
||
да се помеша са бројем бафера, то је нешто друго)
|
||
* `buffer_name` (стринг, није обавезно, подразумевано: `core.weechat`): име бафера
|
||
* `command` (стринг, **обавезно**): команда или текст који се шаље баферу
|
||
|
||
Пример захтева: кажи „здраво!” на канал #weechat:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' -X POST \
|
||
-d '{"buffer_name": "irc.libera.#weechat", "command": "здраво!"}' \
|
||
'https://localhost:9000/api/input'
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 204 No content
|
||
----
|
||
|
||
Пример захтева: напусти и затвори канал #weechat (команда се извршава у WeeChat
|
||
основном баферу):
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' -X POST \
|
||
-d '{"command": "/buffer close irc.libera.#weechat"}' \
|
||
'https://localhost:9000/api/input'
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 204 No content
|
||
----
|
||
|
||
[[resource_completion]]
|
||
=== Completion
|
||
|
||
Довршава команду или текст у баферу.
|
||
|
||
Крајња тачка:
|
||
|
||
----
|
||
POST /api/completion
|
||
----
|
||
|
||
Параметри тела:
|
||
|
||
* `buffer_id` (цео број, није обавезно): јединствени идентификатор (не треба
|
||
да се помеша са бројем бафера, то је нешто друго)
|
||
* `buffer_name` (стринг, није обавезно, подразумевано: `core.weechat`): име бафера
|
||
* `command` (стринг, **обавезно**): команда или текст који се довршава
|
||
* `position` (цео број, није обавезно, подразумевано: крај стринга): позиција
|
||
у команди (прва позиција је 0)
|
||
|
||
Пример захтева: доврши команду `/qu` на каналу #weechat:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' -X POST \
|
||
-d '{"buffer_name": "irc.libera.#weechat", "command": "/qu"}' \
|
||
'https://localhost:9000/api/completion'
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[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
|
||
|
||
Шаље „ping” захтев.
|
||
|
||
Крајња тачка:
|
||
|
||
----
|
||
POST /api/ping
|
||
----
|
||
|
||
Параметри тела:
|
||
|
||
* `data` (стринг, није обавезно): стринг који се шаље назад у одговору
|
||
|
||
Пример захтева: без тела:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' -X POST 'https://localhost:9000/api/ping'
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 204 No content
|
||
----
|
||
|
||
Пример захтева: са подацима:
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' -X POST \
|
||
-d '{"data": "1702835741"}' \
|
||
'https://localhost:9000/api/ping'
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 200 OK
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"data": "1702835741"
|
||
}
|
||
----
|
||
|
||
[[resource_sync]]
|
||
=== Sync
|
||
|
||
Почиње или зауставља синхронизацију података са WeeChat.
|
||
|
||
Овај ресурс може да се користи само онда када је клијент повезан websocket
|
||
протоколом, јер ће WeeChat гурати поруке клијенту у било које време.
|
||
|
||
Ако се овај ресурс употреби без websocket везе, враћа се грешка 403 (Forbidden).
|
||
|
||
Крајња тачка:
|
||
|
||
----
|
||
POST /api/sync
|
||
----
|
||
|
||
Параметри тела:
|
||
|
||
* `sync` (логичка, није обавезно, подразумевано: `true`): `true` да се укључи синхронизација
|
||
са WeeChat
|
||
* `nicks` (логичка, није обавезно, подразумевано: `true`): `true` да се примају
|
||
ажурирања надимака у баферима (користи се само ако је `sync` `true`)
|
||
* `input` (логичка, није обавезно, подразумевано: `true`): `true` да се синхронизује улаз
|
||
бафера са удаљеног релеја на локални клијент (користи се само ако је `sync` `true`)
|
||
* `colors` (стринг, није обавезно, подразумевано: `ansi`): како се враћају стрингови са
|
||
кодовома боје (користи се само ако је `sync` `true`):
|
||
** `ansi`: враћају се ANSI кодови боје
|
||
** `weechat`: враћају се WeeChat интерни кодови боје
|
||
** `strip`: уклањају се боје
|
||
|
||
Пример захтева са websocket протоколом:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"request": "POST /api/sync",
|
||
"body": {
|
||
"nicks": false
|
||
}
|
||
}
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"code": 204,
|
||
"message": "No Content",
|
||
"request": "POST /api/sync",
|
||
"request_body": {
|
||
"nicks":false
|
||
},
|
||
"body_type": null,
|
||
"body": null
|
||
}
|
||
----
|
||
|
||
Пример захтева без websocket протокола (без пријаве):
|
||
|
||
[source,shell]
|
||
----
|
||
curl -L -u 'plain:secret_password' -X POST \
|
||
-d '{"nicks": false}' \
|
||
'https://localhost:9000/api/sync'
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[source,http]
|
||
----
|
||
HTTP/1.1 403 Forbidden
|
||
----
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"error": "Sync resource is available only with a websocket connection"
|
||
}
|
||
----
|
||
|
||
[[websocket]]
|
||
== Websocket
|
||
|
||
Websocket протокол се користи за креирање сталне везе измељу клијента и
|
||
WeeChat програма, и за пријем догађаја у стварном времену, у случају када је
|
||
<<resource_sync,sync>> ресурсом укључена синхронизација.
|
||
|
||
Када се користи websocket протокол, потврда идентитета мора да се обави само једном.
|
||
(погледајте <<authentication,потврду идентитета>>).
|
||
|
||
[[websocket_handshake]]
|
||
=== Websocket усаглашавање
|
||
|
||
Да би се успоставила веза, врши се усаглашавање на `/api` крајњој тачки, које
|
||
изгледа овако:
|
||
|
||
[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 враћа свој одговор усаглашавања којим потврђује да је websocket протокол исправно
|
||
подржан (и да је потврда идентитета била успешна):
|
||
|
||
[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]
|
||
Враћена `Sec-WebSocket-Accept` вредност је SHA-1 хеш примљене вредности на коју је надовезан
|
||
GUID `258EAFA5-E914-47DA-95CA-C5AB0DC85B11` (SHA-1 се кодира у base64). +
|
||
У горњем примеру, SHA-1 од
|
||
`2XE8VAJktqi3Tpw5QnfxVQ==258EAFA5-E914-47DA-95CA-C5AB0DC85B11` је
|
||
`PaY9vRflWeOKuD0/F7e5gD9At9U=` (у base64).
|
||
|
||
[[websocket_frames]]
|
||
=== Оквири
|
||
|
||
Када је клијент повезан websocket протоколом:
|
||
|
||
* захтеви и одговори су у JSON, унутар websocket оквира
|
||
* ако је ресурсом <<resource_sync,sync>> укључена синхронизација, WeeChat
|
||
може клијенту да пошаље JSON оквире у било које време.
|
||
|
||
Захтеви WeeChat програму се праве JSON објектом који садржи следећа поља:
|
||
|
||
* `request` (стринг): HTTP метода и путања (пример: `GET /api/buffers?lines=-100`)
|
||
* `body` (објекат или низ): тело (није обавезно, за `POST` и `PUT` методе)
|
||
* `request_id` (стринг): идентификатор који се шаље назад у одговору
|
||
|
||
Употребом низа објеката, више захтева може да се пошаље одједном, тако што је
|
||
сваки објекат посебан захтев. +
|
||
Захтеви се извршавају у редоследу у којем су примљени (погледајте пример испод).
|
||
|
||
Одговори клијенту се шаљу као JSON објекат који садржи следећа поља:
|
||
|
||
* `code` (цео број): код HTTP одговора (пример: `200`)
|
||
* `message` (стринг): порука за код (пример: `OK`)
|
||
* `request` (стринг): захтев (пример: `GET /api/buffers?lines=-100`)
|
||
* `request_body` (објекат): тело захтева, или `null` ако захтев није имао тело
|
||
* `request_id` (стринг): id захтева, или `null` ако захтев није имао id
|
||
* `body_type` (стринг): тип објеката који се враћа у телу (погледајте испод),
|
||
или `null` ако одговор нема тело
|
||
* `body` (објекат или низ): враћено тело, или `null` ако одговор нема тело
|
||
|
||
Типови тела који могу да се врате:
|
||
|
||
* `handshake` (објекат)
|
||
* `version` (објекат)
|
||
* `buffers` (низ)
|
||
* `buffer` (објекат)
|
||
* `lines` (низ)
|
||
* `line` (објекат)
|
||
* `nick_group` (објекат)
|
||
* `nick` (објекат)
|
||
* `hotlist` (објекат)
|
||
* `scripts` (низ)
|
||
* `ping` (објекат)
|
||
|
||
[TIP]
|
||
Ове схеме можете да прегледате на мрежи: https://weechat.org/api/[WeeChat Relay API ^↗^^].
|
||
|
||
Пример захтева: врати верзију:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"request": "GET /api/version",
|
||
"request_id": "get_version"
|
||
}
|
||
----
|
||
|
||
Одговор:
|
||
|
||
[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
|
||
}
|
||
}
|
||
----
|
||
|
||
Пример захтева: кажи „здраво!” на каналу #weechat:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"request": "POST /api/input",
|
||
"body": {
|
||
"buffer_name": "irc.libera.#weechat",
|
||
"command": "здраво!"
|
||
}
|
||
}
|
||
----
|
||
|
||
Response:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"code": 204,
|
||
"message": "No Content",
|
||
"request": "POST /api/input",
|
||
"request_body": {
|
||
"buffer_name": "irc.libera.#weechat",
|
||
"command": "здраво!"
|
||
},
|
||
"request_id": null,
|
||
"body_type": null,
|
||
"body": null
|
||
}
|
||
----
|
||
|
||
Пример захтева: пошаљи сва захтева одједном: врати листу свих бафера са линијама и
|
||
надимцима, а затим се синхронизуј са удаљеним:
|
||
|
||
[source,json]
|
||
----
|
||
[
|
||
{
|
||
"request": "GET /api/buffers?lines=-1000&nicks=true&colors=weechat",
|
||
"request_id": "initial_sync"
|
||
},
|
||
{
|
||
"request": "POST /api/sync",
|
||
"body": {
|
||
"colors": "weechat"
|
||
}
|
||
}
|
||
]
|
||
----
|
||
|
||
[NOTE]
|
||
Препоручује се да се захтев за синхронизацијом пошаље заједно са првим
|
||
захтевом који преузима податке, тако да се не пропусти ниједан догађај.
|
||
|
||
Први одговор (тело са баферима је одсечено ради лакшег читања):
|
||
|
||
[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"
|
||
}
|
||
]
|
||
}
|
||
----
|
||
|
||
Други одговор:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"code": 204,
|
||
"message": "No Content",
|
||
"request": "POST /api/sync",
|
||
"request_body": {
|
||
"colors": "weechat"
|
||
},
|
||
"request_id": null,
|
||
"body_type": null,
|
||
"body": null
|
||
}
|
||
----
|
||
|
||
WeeChat гура податке клијенту у било које време када се десе одређени догађаји:
|
||
када се линије приказују,бафери додају/уклањају/мењају, надимци nicks додају/уклањају/мењају, итд.
|
||
|
||
Поруке које се шаљу клијенту имају следећа поља:
|
||
|
||
* `code`: `0`
|
||
* `message`: `Event`
|
||
* `event_name` (стринг): име догађаја (име сигнала or hsignal)
|
||
* `buffer_id` (цео број): јединствени идентификатор бафера, поставља се само за под-објекте,
|
||
-1 у осталим случајевима
|
||
|
||
Клијенту се шаљу следећи догађаји, у сагласности са опцијама синхронизације:
|
||
|
||
[width="100%",cols="5,3,3,5",options="header"]
|
||
|===
|
||
| Име догађаја | Id бафера | Тип тела | Тело
|
||
| `buffer_opened` | buffer id | `buffer` | бафер са свим линијама и надимцима
|
||
| `buffer_type_changed` | buffer id | `buffer` | бафер
|
||
| `buffer_moved` | buffer id | `buffer` | бафер
|
||
| `buffer_merged` | buffer id | `buffer` | бафер
|
||
| `buffer_unmerged` | buffer id | `buffer` | бафер
|
||
| `buffer_hidden` | buffer id | `buffer` | бафер
|
||
| `buffer_unhidden` | buffer id | `buffer` | бафер
|
||
| `buffer_renamed` | buffer id | `buffer` | бафер
|
||
| `buffer_title_changed` | buffer id | `buffer` | бафер
|
||
| `buffer_time_for_each_line_changed` | buffer id | `buffer` | бафер
|
||
| `buffer_localvar_added` | buffer id | `buffer` | бафер
|
||
| `buffer_localvar_changed` | buffer id | `buffer` | бафер
|
||
| `buffer_localvar_removed` | buffer id | `buffer` | бафер
|
||
| `buffer_cleared` | buffer id | `buffer` | бафер
|
||
| `buffer_closing` | buffer id | `buffer` | бафер
|
||
| `buffer_closed` | buffer id | null | null
|
||
| `buffer_line_added` | buffer id | `line` | бафер линија
|
||
| `buffer_line_data_changed` | buffer id | `line` | бафер линија
|
||
| `input_text_changed` | buffer id | `buffer` | бафер
|
||
| `input_text_cursor_moved` | buffer id | `buffer` | бафер
|
||
| `nicklist_group_changed` | buffer id | `nick_group` | група надимака
|
||
| `nicklist_group_added` | buffer id | `nick_group` | група надимака
|
||
| `nicklist_group_removing` | buffer id | `nick_group` | група надимака
|
||
| `nicklist_nick_added` | buffer id | `nick` | надимак
|
||
| `nicklist_nick_removing` | buffer id | `nick` | надимак
|
||
| `nicklist_nick_changed` | buffer id | `nick` | надимак
|
||
| `upgrade` ^(1)^ | -1 | null | null
|
||
| `upgrade_ended` ^(1)^ | -1 | null | null
|
||
| `quit` | -1 | null | null
|
||
|===
|
||
|
||
[NOTE]
|
||
^(1)^ Догађаји `upgrade` и `upgrade_ended` се шаљу само ако је клијент повезан чистим
|
||
текстом (без TLS), јер се у случају TLS веза са клијентом најпре прекида пре
|
||
него што се обави ажурирање (ажурирање TLS веза није подржано).
|
||
|
||
Пример: нови бафер: приступљено је каналу `#weechat`:
|
||
|
||
[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": []
|
||
}
|
||
}
|
||
----
|
||
|
||
Пример: приказана је нова линија на каналу `#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"
|
||
]
|
||
}
|
||
}
|
||
----
|
||
|
||
Пример: додат је надимак `bob` са статусом оператора у канал `#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
|
||
}
|
||
}
|
||
----
|
||
|
||
Пример: затворен је бафер канала `#weechat`:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"code": 0,
|
||
"message": "Event",
|
||
"event_name": "buffer_closed",
|
||
"buffer_id": 1709932823649069,
|
||
"body_type": null,
|
||
"body": null
|
||
}
|
||
----
|
||
|
||
Пример: WeeChat се ажурира:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"code": 0,
|
||
"message": "Event",
|
||
"event_name": "upgrade",
|
||
"buffer_id": -1,
|
||
"body_type": null,
|
||
"body": null
|
||
}
|
||
----
|
||
|
||
Пример: извршено је ажурирање програма WeeChat:
|
||
|
||
[source,json]
|
||
----
|
||
{
|
||
"code": 0,
|
||
"message": "Event",
|
||
"event_name": "upgrade_ended",
|
||
"buffer_id": -1,
|
||
"body_type": null,
|
||
"body": null
|
||
}
|
||
----
|