Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dockerfile and export simple api to send/receive messages #92

Merged
merged 1 commit into from
Jun 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.git
bin/
53 changes: 53 additions & 0 deletions API.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
RPC API
======
Start service with configuration file that enables API:

```
./bin/status-term-client -node-config ./_assets/api.conf -no-ui --keyhex=0x123
```

Configuration example:

```json
{
"HTTPHost": "localhost",
"HTTPPort": 8777,
"HTTPEnabled": true,
"APIModules": "ssm"
}
```

Add contact
===========

```
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"ssm_addContact","params":[{"name": "222"}],"id":1}' http://localhost:8777
```


Returns error if failed otherwise null.

Send to contact
===============

```
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"ssm_sendToContact","params":[{"name": "222"}, "plain text"],"id":1}' http://localhost:8777
```

Returns error if failed otherwise null.

Read all (including ours) from contact
======================================


To read all messages use 0 as offset:

```
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"ssm_readContactMessages","params":[{"name": "222"}, 0],"id":1}' http://localhost:8777
```

To read new messages use last known offset:

```
curl -H "Content-Type: application/json" -X POST --data '{"jsonrpc":"2.0","method":"ssm_readContactMessages","params":[{"name": "222"}, 2],"id":1}' http://localhost:8777
```
23 changes: 23 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Build status-go in a Go builder container
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also add a .dockerignore and ignore .git and other unnecessary dirs.

FROM golang:1.12.5-alpine as builder

RUN apk add --no-cache make gcc musl-dev linux-headers

RUN mkdir -p /go/src/github.com/status-im/status-console-client
ADD . /go/src/github.com/status-im/status-console-client
WORKDIR /go/src/github.com/status-im/status-console-client
RUN make build

# Copy the binary to the second image
FROM alpine:latest

LABEL maintainer="support@status.im"
LABEL source="https://github.com/status-im/status-console-client"

COPY --from=builder /go/src/github.com/status-im/status-console-client/bin/status-term-client /usr/local/bin/

# 30304 is used for Discovery v5
EXPOSE 8080 8545 30303 30303/udp 30304/udp

ENTRYPOINT ["/usr/local/bin/status-term-client", "-no-ui"]
CMD ["--help"]
16 changes: 13 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,10 +1,16 @@
SHELL := /bin/bash

GO111MODULE = on

ENABLE_METRICS ?= true
BUILD_FLAGS ?= $(shell echo "-ldflags '\
-X github.com/status-im/status-console-client/vendor/github.com/ethereum/go-ethereum/metrics.EnabledStr=$(ENABLE_METRICS)'")


DOCKER_IMAGE_NAME ?= statusteam/status-client
DOCKER_CUSTOM_TAG ?= $(shell git rev-parse --short HEAD)

build: GOFLAGS ?= "-mod=vendor"
build:
GOFLAGS=$(GOFLAGS) go build -o ./bin/status-term-client .
GOFLAGS=$(GOFLAGS) go build $(BUILD_FLAGS) -o ./bin/status-term-client .
.PHONY: build

run: ARGS ?=
Expand Down Expand Up @@ -57,3 +63,7 @@ mock:
gen-migrations:
pushd protocol/client/migrations/ && rm -f bindata.go && go-bindata -pkg migrations ./ && popd
.PHONY: gen-migrations

image:
docker build . -t $(DOCKER_IMAGE_NAME):latest -t $(DOCKER_IMAGE_NAME):$(DOCKER_CUSTOM_TAG)
.PHONY: image
6 changes: 6 additions & 0 deletions _assets/api.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"HTTPHost": "localhost",
"HTTPPort": 8777,
"HTTPEnabled": true,
"APIModules": "ssm"
}
3 changes: 2 additions & 1 deletion protocol/client/messenger.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,7 +141,8 @@ func (m *Messenger) Join(ctx context.Context, c Contact) error {
}

opts := protocol.DefaultRequestOptions()
if err := m.Request(ctx, c, opts); err != nil {
// NOTE(dshulyak) join ctx shouldn't have an impact on history timeout.
if err := m.Request(context.Background(), c, opts); err != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe we should remove sending a request when joining and make it a separate action? It wouldn't be this PR change though.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think ideally it should be managed in background, so that we can do multiple attempts without blocking an API

the same when messenger is started

return err
}
return m.db.UpdateHistories([]History{{Contact: c, Synced: opts.To}})
Expand Down
61 changes: 59 additions & 2 deletions protocol/gethservice/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ type RequestParams struct {

// Contact
type Contact struct {
Name string `json:"name"`
Type string `json:"type"`
Name string `json:"name"`
PublicKey hexutil.Bytes `json:"key"`
}

// PublicAPI provides an JSON-RPC API to interact with
Expand Down Expand Up @@ -244,6 +244,63 @@ func (api *PublicAPI) RequestAll(ctx context.Context, newest bool) error {
return api.service.messenger.RequestAll(ctx, newest)
}

// AddContact will ensure that contact is added to messenger database and new stream spawned for a contact if needed.
func (api *PublicAPI) AddContact(ctx context.Context, contact Contact) (err error) {
if api.service.messenger == nil {
return ErrMessengerNotSet
}
var c client.Contact
if len(contact.PublicKey) != 0 {
c, err = client.CreateContactPrivate(contact.Name, contact.PublicKey.String(), client.ContactAdded)
if err != nil {
return err
}
} else {
c = client.CreateContactPublicRoom(contact.Name, client.ContactAdded)
}
err = api.service.messenger.AddContact(c)
if err != nil {
return err
}
return api.service.messenger.Join(ctx, c)
}

// SendToContact send payload to specified contact. Contact should be added before sending message, otherwise error will
// be received.
func (api *PublicAPI) SendToContact(ctx context.Context, contact Contact, payload string) (err error) {
if api.service.messenger == nil {
return ErrMessengerNotSet
}
var c client.Contact
if len(contact.PublicKey) != 0 {
c, err = client.CreateContactPrivate(contact.Name, contact.PublicKey.String(), client.ContactAdded)
if err != nil {
return err
}
} else {
c = client.CreateContactPublicRoom(contact.Name, client.ContactAdded)
}
return api.service.messenger.Send(c, []byte(payload))
}

// ReadContactMessages read contact messages starting from offset.
// To read all offset should be zero. To read only new set offset to total number of previously read messages.
func (api *PublicAPI) ReadContactMessages(ctx context.Context, contact Contact, offset int64) (rst []*protocol.Message, err error) {
if api.service.messenger == nil {
return nil, ErrMessengerNotSet
}
var c client.Contact
if len(contact.PublicKey) != 0 {
c, err = client.CreateContactPrivate(contact.Name, contact.PublicKey.String(), client.ContactAdded)
if err != nil {
return nil, err
}
} else {
c = client.CreateContactPublicRoom(contact.Name, client.ContactAdded)
}
return api.service.messenger.Messages(c, offset)
}

func unmarshalPubKey(b hexutil.Bytes) (*ecdsa.PublicKey, error) {
if len(b) == 0 {
return nil, nil
Expand Down
21 changes: 15 additions & 6 deletions protocol/transport/whisper_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,20 @@ import (

"github.com/pkg/errors"

"github.com/ethereum/go-ethereum/p2p"
gethnode "github.com/ethereum/go-ethereum/node"
"github.com/ethereum/go-ethereum/p2p"

"github.com/status-im/status-go/services/shhext"
whisper "github.com/status-im/whisper/whisperv6"

"github.com/status-im/status-console-client/protocol/subscription"
)

var (
// ErrNoMailservers returned if there is no configured mailservers that can be used.
ErrNoMailservers = errors.New("no configured mailservers")
)

type WhisperServiceKeysManager struct {
shh *whisper.Whisper

Expand Down Expand Up @@ -64,10 +69,10 @@ func (m *WhisperServiceKeysManager) GetRawSymKey(id string) ([]byte, error) {
type WhisperServiceTransport struct {
node StatusNode // TODO: replace with an interface
shh *whisper.Whisper
shhextAPI *shhext.PublicAPI
shhextAPI *shhext.PublicAPI
keysManager *WhisperServiceKeysManager

mailservers []string
mailservers []string
selectedMailServerEnode string
}

Expand All @@ -87,9 +92,10 @@ func NewWhisperServiceTransport(
privateKey *ecdsa.PrivateKey,
) *WhisperServiceTransport {
return &WhisperServiceTransport{
node: node,
shh: shh,
shhextAPI: shhext.NewPublicAPI(shhextService),
node: node,
shh: shh,
mailservers: mailservers,
shhextAPI: shhext.NewPublicAPI(shhextService),
keysManager: &WhisperServiceKeysManager{
shh: shh,
privateKey: privateKey,
Expand Down Expand Up @@ -184,6 +190,9 @@ func (a *WhisperServiceTransport) selectAndAddMailServer() (string, error) {
if a.selectedMailServerEnode != "" {
return a.selectedMailServerEnode, nil
}
if len(a.mailservers) == 0 {
return "", ErrNoMailservers
}

enode := randomItem(a.mailservers)
errCh := waitForPeerAsync(
Expand Down
14 changes: 14 additions & 0 deletions protocol/transport/whisper_service_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package transport

import (
"testing"

"github.com/stretchr/testify/require"
)

func TestSelectAndAddNoMailservers(t *testing.T) {
svc := &WhisperServiceTransport{}
rst, err := svc.selectAndAddMailServer()
require.Empty(t, rst)
require.EqualError(t, ErrNoMailservers, err.Error())
}