From 9fcb153f32ee8a4da6c21bcb8bb03858d72f906c Mon Sep 17 00:00:00 2001 From: Igor Sirotin Date: Fri, 18 Oct 2024 21:59:09 +0300 Subject: [PATCH] docs_: better usage docs for status-backend (#5955) --- README.md | 3 +- cmd/status-backend/README.md | 184 +++++++++++++++++++++++++++++------ 2 files changed, 156 insertions(+), 31 deletions(-) diff --git a/README.md b/README.md index aae838ea5..78b3b3e37 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,8 @@ - [How to run a Bootnode](BOOTNODE.md) - [How to run a Mailserver](MAILSERVER.md) - [How to run a Waku node](./_examples/README.md#run-waku-node) -- [How to configure status-go](/config) +- [How to configure status-go](/config/README.md) +- [How to run status-go as HTTP server](/cmd/status-backend/README.md) ## Policies diff --git a/cmd/status-backend/README.md b/cmd/status-backend/README.md index 4e04dee5d..bc24c1d62 100644 --- a/cmd/status-backend/README.md +++ b/cmd/status-backend/README.md @@ -1,4 +1,4 @@ -# Description +# 📝Description Welcome to `status-backend`. This is a tool for debugging and testing `status-go`. In contrast to existing `statusd` and `status-cli`, the `status-backend` exposes full status-go API through HTTP. @@ -13,17 +13,87 @@ This allows to communicate with status-go through HTTP the same way as `status-d - subscribe to status-go signals - etc. -# status-go API +# 📍status-go API -## Public methods in `./mobile/status.go` +> [!NOTE] +> Unfortunately, for now there is no convenient docs like OpenAPI -Only specific function signatures are currently supported: +## 1️⃣ Public methods in `./mobile/status.go` + +### Description + +Any **public** functions in `./mobile/status.go` with the one of the following signatures: - `func(string) string` - 1 argument, 1 return - `func() string` - 0 argument, 1 return +### Address + +Endpoints address: `http://
/statusgo/`. + +Here, `statusgo` is the name of the package in `/mobile/status.go`. We might create more APIs next to it in the future. + +### Response + +Responses have JSON body with a single `error` field. +If `error` is empty, no error occurred. + +The structure of response is defined in [`APIResponse`](https://github.com/status-im/status-go/blob/91c6949cd25449d5459581a21f2c8b929290ced0/mobile/types.go#L9-L12): +```go +// APIResponse generic response from API. +type APIResponse struct { + Error string `json:"error"` +} +``` + +### Parameters + +Parameters are passed as request JSON body. +Specific parameters for each endpoint should be checked in the source code. + +### How to read the source code? + +As example, let's look at [`CreateAccountAndLogin`](https://github.com/status-im/status-go/blob/fc36a7e980fc8f73dd36d7e3db29675ddff1d5dc/mobile/status.go#L415-L417). +```go +func CreateAccountAndLogin(requestJSON string) string { + return callWithResponse(createAccountAndLogin, requestJSON) +} +``` + +1. The function has 1 JSON string argument and 1 JSON string return value. +2. The function wraps a private `createAccountAndLogin` with `callWithResponse`. +`callWithResponse` does some internal magic like logging the request and response. +So we should check [the private function](https://github.com/status-im/status-go/blob/fc36a7e980fc8f73dd36d7e3db29675ddff1d5dc/mobile/status.go#L419) for real arguments and return values: + ```go + func createAccountAndLogin(requestJSON string) string { + var request requests.CreateAccount + err := json.Unmarshal([]byte(requestJSON), &request) + // ... + } + ``` +3. We can see that the parameters are unmarshalled to [`requests.CreateAccount`](https://github.com/status-im/status-go/blob/f660be0daa7cc742a07f6a139ea5ac9966f3ebe0/protocol/requests/create_account.go#L35): + ```go + type CreateAccount struct { + RootDataDir string `json:"rootDataDir"` + KdfIterations int `json:"kdfIterations"` + // ... + ``` +4. We can also see that each the response is formed as [`makeJSONResponse(err)`](https://github.com/status-im/status-go/blob/fc36a7e980fc8f73dd36d7e3db29675ddff1d5dc/mobile/status.go#L422-L424): + ```go + if err != nil { + return makeJSONResponse(err) + } + ``` + ... which wraps the error to [`APIResponse`](https://github.com/status-im/status-go/blob/91c6949cd25449d5459581a21f2c8b929290ced0/mobile/types.go#L9-L12): + ```go + // APIResponse generic response from API. + type APIResponse struct { + Error string `json:"error"` + } + ``` + ### Unsupported methods -Attempt to call any other functions will return `501: Not Implemented` HTTP code. +Attempt to call any functions with unsupported signatures will return `501: Not Implemented` HTTP code. For example, [`VerifyAccountPassword`](https://github.com/status-im/status-go/blob/669256095e16d953ca1af4954b90ca2ae65caa2f/mobile/status.go#L275-L277) has 3 arguments: ```go func VerifyAccountPassword(keyStoreDir, address, password string) string { @@ -38,7 +108,31 @@ For example, https://github.com/status-im/status-go/pull/5865 fixes some of thes Deprecated methods will have `Deprecation: true` HTTP header. -## Signals in `./signal` +## 2️⃣ Signals in `./signal` + +> [!NOTE] +> Unfortunately, there is no description of when any expected signals will appear. +> For now, you have to check the source code. + +### Address + +Signals are available at `ws://
/signals`. + +Connect to it as the first thing when running `status-backend`. + +### Available signals + +List of possible events can be found in `./signal/event_*.go` files. + +For example, `node.login` event is defined [here](https://github.com/status-im/status-go/blob/6bcf5f1289f9160168574290cbd6f90dede3f8f6/signal/events_node.go#L27-L28): +```go +const ( + // EventLoggedIn is once node was injected with user account and ready to be used. + EventLoggedIn = "node.login" +) +``` + +### Signals structure Each signal has [this structure](https://github.com/status-im/status-go/blob/c9b777a2186364b8f394ad65bdb18b128ceffa70/signal/signals.go#L30-L33): ```go @@ -49,16 +143,7 @@ type Envelope struct { } ``` -List of possible events can be found in `./signal/event_*.go` files. - -For example, `node.login` event is defined [here](https://github.com/status-im/status-go/blob/6bcf5f1289f9160168574290cbd6f90dede3f8f6/signal/events_node.go#L27-L28): -```go -const ( - // EventLoggedIn is once node was injected with user account and ready to be used. - EventLoggedIn = "node.login" -) -``` - +Here, `type` is the name of the event, e.g. `node.login`. And the structure of this event is [defined in the same file](https://github.com/status-im/status-go/blob/6bcf5f1289f9160168574290cbd6f90dede3f8f6/signal/events_node.go#L36-L42): ```go // NodeLoginEvent returns the result of the login event @@ -70,7 +155,6 @@ type NodeLoginEvent struct { } ``` - So the signal for `node.login` event will look like this (with corresponding data): ```json { @@ -84,9 +168,33 @@ So the signal for `node.login` event will look like this (with corresponding dat } ``` -## Services in `./services/**/api.go` +## 3️⃣ Services in `./services/**/api.go` -Services are registered in go-ethereum JSON-RPC server. To call such method, send request to `statusgo/CallRPC` endpoint. +Services are registered in the [go-ethereum JSON-RPC](https://geth.ethereum.org/docs/interacting-with-geth/rpc) server. +All `./services/**/api.go` are registered as services in geth. + +Each method name has form `_`. In most cases namespace is the directory name, but it can be ensured in the `APIs` method of each service. For example, for [wallet service](https://github.com/status-im/status-go/blob/1d173734a608de2d71480d6ad39f4559f11a75e2/services/wallet/service.go#L288-L298): +```go +// APIs returns list of available RPC APIs. +func (s *Service) APIs() []gethrpc.API { + return []gethrpc.API{ + { + Namespace: "wallet", + Version: "0.1.0", + Service: NewAPI(s), + Public: true, + }, + } +} +``` + +### Address + +These methods are available through `/statusgo/CallRPC` endpoint defined [here](https://github.com/status-im/status-go/blob/fc36a7e980fc8f73dd36d7e3db29675ddff1d5dc/mobile/status.go#L249-L260). + +This is the way desktop and mobile clients call these methods. You don't have to run a separate geth HTTP server for this. + +### Arguments For example: ```http request @@ -105,12 +213,14 @@ POST http://localhost:12345/statusgo/CallRPC } ``` +Please reference to the source code for the list of methods and its arguments. + ### Notes 1. In this case, there's no limitation to the number of arguments, comparing to `mobile/status.go`, so ll method are supported. 2. Deprecated methods won't have a corresponding `Deprecated: true` -# Usage +# 🏃‍♂️Usage Start the app with the address to listen to: ```shell @@ -135,21 +245,35 @@ Access the exposed API with any HTTP client you prefer: - [Python](https://pypi.org/project/requests/) - [Go](https://pkg.go.dev/net/http) -# Simple flows +# 👌 Simple flows In most cases to start testing you'll need some boilerplate. Below are the simple call flows for common cases. ## Create account and login -1. `InitializeApplication` -2. `CreateAccountAndLogin` -3. `wakuext_startMessenger` -4. `wallet_startWallet` -5. `settings_getSettings` (temporary workaround, otherwise settings don't get saved into DB) +1. Subscribe to `/signals` +2. Call `/statusgo/InitializeApplication` +3. Create an account + 1. Call `/statusgo/CreateAccountAndLogin` + 2. Wait for `node.login` signal + - If `error` is empty, no error occurred + - If `error` is not empty, stop the operation +4. Start required services + 1. Call `/statusgo/CallRPC` with `{ "method": "wakuext_startMessenger", "params": [] }` + 2. Call `/statusgo/CallRPC` with `{ "method": "wallet_startWallet", "params": [] }` +5. Apply temporary workarounds: + 1. Call `/statusgo/CallRPC` with `{ "method": "settings_getSettings", "params": [] }` + _(otherwise settings don't get saved into DB)_ ## Login into account -1. `InitializeApplication` -2. `LoginAccount` -3. `wakuext_startMessenger` -4. `wallet_startWallet` \ No newline at end of file +1. Subscribe to `/signals` +2. Call `/statusgo/InitializeApplication` +3. Create an account + 1. Call `/statusgo/LoginAccount` + 2. Wait for `node.login` signal + - If `error` is empty, no error occurred + - If `error` is not empty, stop the operation +4. Start required services + 1. Call `/statusgo/CallRPC` with `{ "method": "wakuext_startMessenger", "params": [] }` + 2. Call `/statusgo/CallRPC` with `{ "method": "wallet_startWallet", "params": [] }`