Skip to content

Commit

Permalink
feat(cmd)_: status-backend (#5847)
Browse files Browse the repository at this point in the history
* feat_: server supports for mobile api

fix(statusd)_: manually serve

* feat_: generate endpoints list from status/mobile.go

* chore_: mark public endpoint OpenAccounts as deprecated

* chore_: added status-backend makefile targets

* feat_: expose deprecated endpoints, with special header field

* docs(status-backend)_: added README
  • Loading branch information
igor-sirotin authored Sep 27, 2024
1 parent 42f715f commit fc36a7e
Show file tree
Hide file tree
Showing 10 changed files with 723 additions and 26 deletions.
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,13 @@ spiff-workflow: build/bin/spiff-workflow
status-cli: ##@build Build status-cli to send messages
status-cli: build/bin/status-cli

status-backend: ##@build Build status-backend to run status-go as HTTP server
status-backend: build/bin/status-backend

run-status-backend: PORT ?= 0
run-status-backend: ##@run Start status-backend server listening to localhost:PORT
go run ./cmd/status-backend --address localhost:${PORT}

statusd-prune-docker-image: SHELL := /bin/sh
statusd-prune-docker-image: ##@statusd-prune Build statusd-prune docker image
@echo "Building docker image for ststusd-prune..."
Expand Down
155 changes: 155 additions & 0 deletions cmd/status-backend/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# 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.

This allows to communicate with status-go through HTTP the same way as `status-desktop` and `status-mobile` do, including:
- create account
- restore account
- login
- logout
- start messenger
- start wallet
- subscribe to status-go signals
- etc.

# status-go API

## Public methods in `./mobile/status.go`

Only specific function signatures are currently supported:
- `func(string) string` - 1 argument, 1 return
- `func() string` - 0 argument, 1 return

### Unsupported methods

Attempt to call any other functions 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 {
return logAndCallString(verifyAccountPassword, keyStoreDir, address, password)
}
```

Later, as needed, a V2 of these functions will be introduced. V2 will have a single JSON argument composing all args in 1.
For example, https://github.com/status-im/status-go/pull/5865 fixes some of these.

### Deprecated methods

Deprecated methods will have `Deprecation: true` HTTP header.

## Signals in `./signal`

Each signal has [this structure](https://github.com/status-im/status-go/blob/c9b777a2186364b8f394ad65bdb18b128ceffa70/signal/signals.go#L30-L33):
```go
// Envelope is a general signal sent upward from node to RN app
type Envelope struct {
Type string `json:"type"`
Event interface{} `json:"event"`
}
```

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"
)
```

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
type NodeLoginEvent struct {
Error string `json:"error,omitempty"`
Settings *settings.Settings `json:"settings,omitempty"`
Account *multiaccounts.Account `json:"account,omitempty"`
EnsUsernames json.RawMessage `json:"ensUsernames,omitempty"`
}
```


So the signal for `node.login` event will look like this (with corresponding data):
```json
{
"type": "node.login",
"event": {
"error": "",
"settings": {},
"account": {},
"endUsernames": {}
}
}
```

## Services in `./services/**/api.go`

Services are registered in go-ethereum JSON-RPC server. To call such method, send request to `statusgo/CallRPC` endpoint.

For example:
```http request
### Send Contact Request
POST http://localhost:12345/statusgo/CallRPC
{
"jsonrpc": "2.0",
"method": "wakuext_sendContactRequest",
"params": [
{
"id": "0x048f0b885010783429c2298b916e24b3c01f165e55fe8f98fce63df0a55ade80089f512943d4fde5f8c7211f1a87b267a85cbcb3932eb2e4f88aa4ca3918f97541",
"message": "Hi, Alice!"
}
]
}
```

### 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

Start the app with the address to listen to:
```shell
status-backend --address localhost:12345
```

Or just use the root repo Makefile command:
```shell
make run-status-backend PORT=12345
```

Access the exposed API with any HTTP client you prefer:
- From your IDE:
- [JetBrains](https://www.jetbrains.com/help/idea/http-client-in-product-code-editor.html)
- [VS Code](https://marketplace.visualstudio.com/items?itemName=humao.rest-client)
- From UI client:
- [Postman](https://learning.postman.com/docs/getting-started/first-steps/sending-the-first-request/)
- [Insomnia](https://docs.insomnia.rest/insomnia/send-your-first-request)
- From command line:
- [Curl](https://curl.se/docs/httpscripting.html)
- From your script:
- [Python](https://pypi.org/project/requests/)
- [Go](https://pkg.go.dev/net/http)

# 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)

## Login into account

1. `InitializeApplication`
2. `LoginAccount`
3. `wakuext_startMessenger`
4. `wallet_startWallet`
48 changes: 48 additions & 0 deletions cmd/status-backend/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package main

import (
"flag"
stdlog "log"
"os"

"golang.org/x/crypto/ssh/terminal"

"github.com/ethereum/go-ethereum/log"

"github.com/status-im/status-go/cmd/statusd/server"
"github.com/status-im/status-go/logutils"
)

var (
address = flag.String("address", "", "host:port to listen")
logger = log.New("package", "status-go/cmd/status-backend")
)

func init() {
logSettings := logutils.LogSettings{
Enabled: true,
MobileSystem: false,
Level: "INFO",
}
colors := terminal.IsTerminal(int(os.Stdin.Fd()))
if err := logutils.OverrideRootLogWithConfig(logSettings, colors); err != nil {
stdlog.Fatalf("failed to initialize log: %v", err)
}
}

func main() {
flag.Parse()

srv := server.NewServer()
srv.Setup()

err := srv.Listen(*address)
if err != nil {
logger.Error("failed to start server", "error", err)
return
}

log.Info("server started", "address", srv.Address())
srv.RegisterMobileAPI()
srv.Serve()
}
1 change: 1 addition & 0 deletions cmd/statusd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,7 @@ func main() {
logger.Error("failed to start server", "error", err)
return
}
go srv.Serve()
log.Info("server started", "address", srv.Address())
defer func() {
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
Expand Down
120 changes: 120 additions & 0 deletions cmd/statusd/server/endpoints.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

30 changes: 30 additions & 0 deletions cmd/statusd/server/parse-api/endpoints_template.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Code generated by parse-api/main.go. DO NOT EDIT.
// source: parse-api/main.go

package server

import statusgo "github.com/status-im/status-go/mobile"

var EndpointsWithRequest = map[string]func(string) string{
{{- range .FunctionsWithResp }}
"/{{ $.PackageName }}/{{ . }}": {{ $.PackageName }}.{{ . }},
{{- end }}
}

var EndpointsWithoutRequest = map[string]func() string{
{{- range .FunctionsNoArgs }}
"/{{ $.PackageName }}/{{ . }}": {{ $.PackageName }}.{{ . }},
{{- end }}
}

var EndpointsUnsupported = []string{
{{- range .UnsupportedEndpoints }}
"/{{ $.PackageName }}/{{ . }}",
{{- end }}
}

var EndpointsDeprecated = map[string]struct{}{
{{- range .DeprecatedEndpoints }}
"/{{ $.PackageName }}/{{ . }}": {},
{{- end }}
}
Loading

0 comments on commit fc36a7e

Please sign in to comment.