|
| 1 | +# MSC2659: Application service ping endpoint |
| 2 | + |
| 3 | +## Problem |
| 4 | +A relatively common problem when setting up appservices is the connection |
| 5 | +between the appservice and homeserver not working in one or both directions. |
| 6 | +If the appservice is unable to connect to the homeserver, it can simply show |
| 7 | +the error message to the user. However, there's currently no easy way for the |
| 8 | +appservice to know if the homeserver is unable to connect to it. This means |
| 9 | +that the appservice might start up fine, but not actually work, because the |
| 10 | +homeserver isn't sending events to it. |
| 11 | + |
| 12 | +## Proposed solution |
| 13 | +The proposed solution is a new endpoint in homeservers that appservices can use |
| 14 | +to trigger a ping. A new endpoint is also added to the appservice side for the |
| 15 | +homeserver to call without any side-effects. |
| 16 | + |
| 17 | +Appservices can use the endpoint at startup to ensure communication works in |
| 18 | +both directions, and show an error to the user if it doesn't. |
| 19 | + |
| 20 | +### `POST /_matrix/app/v1/ping` |
| 21 | +This endpoint is on the appservice side. Like all other appservice-side |
| 22 | +endpoints, it is authenticated using the `hs_token`. When the token is correct, |
| 23 | +this returns HTTP 200 and an empty JSON object as the body. |
| 24 | + |
| 25 | +The request body contains an optional `transaction_id` string field, which |
| 26 | +comes from the client ping request defined below. |
| 27 | + |
| 28 | +Appservices don't need to have any special behavior on this endpoint, but they |
| 29 | +may use the incoming request to verify that an outgoing ping actually pinged |
| 30 | +the appservice rather than going somewhere else. |
| 31 | + |
| 32 | +This proposal doesn't define any cases where a homeserver would call the ping |
| 33 | +endpoint unless explicitly requested by the appservice (using the client |
| 34 | +endpoint below). Therefore, appservices don't necessarily have to implement |
| 35 | +this endpoint if they never call the client ping endpoint. |
| 36 | + |
| 37 | +### `POST /_matrix/client/v1/appservice/{appserviceId}/ping` |
| 38 | +When the endpoint is called, the homeserver makes a `/_matrix/app/v1/ping` |
| 39 | +request to the appservice. |
| 40 | + |
| 41 | +The request body may contain a `transaction_id` string field, which, if present, |
| 42 | +must be passed through to the appservice `/ping` request body as-is. |
| 43 | + |
| 44 | +This endpoint is only allowed when using a valid appservice token, and it can |
| 45 | +only ping the appservice associated with the token. If the token or appservice |
| 46 | +ID in the path is wrong, the server may return `M_FORBIDDEN`. However, |
| 47 | +implementations and future spec proposals may extend what kinds of pings are |
| 48 | +allowed. |
| 49 | + |
| 50 | +In case the homeserver had backed off on sending transactions, it may treat a |
| 51 | +successful ping as a sign that the appservice is up again and transactions |
| 52 | +should be retried. |
| 53 | + |
| 54 | +#### Response |
| 55 | +If the ping request returned successfully, the endpoint returns HTTP 200. The |
| 56 | +response body has a `duration_ms` field containing the `/_matrix/app/v1/ping` |
| 57 | +request roundtrip time as milliseconds. |
| 58 | + |
| 59 | +If the request fails, the endpoint returns a standard error response with |
| 60 | +`errcode`s and HTTP status codes as specified below: |
| 61 | + |
| 62 | +* If the appservice doesn't have a URL configured, `M_URL_NOT_SET` and HTTP 400. |
| 63 | +* For non-2xx responses, `M_BAD_STATUS` and HTTP 502. Additionally, the response |
| 64 | + may include `status` (integer) and `body` (string) fields containing the HTTP |
| 65 | + status code and response body text respectively to aid with debugging. |
| 66 | +* For connection timeouts, `M_CONNECTION_TIMEOUT` and HTTP 504. |
| 67 | +* For other connection errors, `M_CONNECTION_FAILED` and HTTP 502. |
| 68 | + It is recommended to put a more detailed explanation in the `error` field. |
| 69 | + |
| 70 | +### Example flow |
| 71 | + |
| 72 | +1. bridge -> homeserver (request #1): `POST http://synapse:8008/_matrix/client/v1/appservice/whatsapp/ping` |
| 73 | + * Header `Authorization: Bearer as_token` |
| 74 | + * Body: `{"transaction_id": "meow"}` |
| 75 | +2. homeserver -> bridge (request #2): `POST http://bridge:29318/_matrix/app/v1/ping` |
| 76 | + * Header `Authorization: Bearer hs_token` |
| 77 | + * Body: `{"transaction_id": "meow"}` |
| 78 | +3. bridge -> homeserver (response to #2): 200 OK with body `{}` |
| 79 | +4. homeserver -> bridge (response to #1): 200 OK with body `{"duration_ms": 123}` |
| 80 | + (123 milliseconds being the time it took for request #2 to complete). |
| 81 | + |
| 82 | +## Alternatives |
| 83 | + |
| 84 | +* The ping could make an empty `/transactions` request instead of adding a new |
| 85 | + ping endpoint. A new endpoint was found to be cleaner while implementing, and |
| 86 | + there didn't seem to be any significant benefits to reusing transactions. |
| 87 | +* A `/versions` endpoint could be introduced to work for both pinging and |
| 88 | + checking what spec versions an appservice supports. However, it's not clear |
| 89 | + that a new endpoint is the best way to detect version support (a simple flag |
| 90 | + in the registration file may be preferable), so this MSC proposes a `/ping` |
| 91 | + endpoint that doesn't have other behavior. |
| 92 | +* Appservices could be switched to using websockets instead of the server |
| 93 | + pushing events. This option is already used by some bridges, but implementing |
| 94 | + websocket support on the homeserver side is much more complicated than a |
| 95 | + simple ping endpoint. |
| 96 | + |
| 97 | +## Unstable prefix |
| 98 | +The endpoints can be implemented as `/_matrix/app/unstable/fi.mau.msc2659/ping` |
| 99 | +and `/_matrix/client/unstable/fi.mau.msc2659/appservice/{appserviceId}/ping`. |
| 100 | +Error codes can use `FI.MAU.MSC2659_` instead of `M_` as the prefix. |
| 101 | + |
| 102 | +`fi.mau.msc2659` can be used as an `unstable_features` flag in `/versions` to |
| 103 | +indicate support for the unstable prefixed endpoint. Once the MSC is approved, |
| 104 | +`fi.mau.msc2659.stable` can be used to indicate support for the stable endpoint |
| 105 | +until the spec release containing the endpoint is supported. |
0 commit comments