Skip to content

Commit

Permalink
Refactor according to DDD specs (#11)
Browse files Browse the repository at this point in the history
* initial domain implementation

* feed domain

* go mod / sum

* ports layer kraken web socket

* reset socketConn in KrakenWebSocket impl

* Feed service for krakenWebSocket

* export TicketWithPrice member in ports package

* start feeder_service

* tdexDaemonPriceUpdater in ports package

* add updater_service.go

* change tickers to subcribe param for factory function

* feeder service base implementation

* base implementation of config_service

* delete old files

* base implementation main

* main test

* handle close error

* improve interupt

* change logger in krakenWebSocket.go

* feeder domain test

* fix message checks in krakenWebSocket.go

* krakenWebSocket tests

* create the chan in constructor function

* stop the feeder in feeder test

* add sleep time between two socket read

* switch to quitChan pattern in FeedService.go

* feed service test

* change nigiri endpoint explorer address

* main_test pass

* cleanup

* add mutex in tdexFeeder for isRunning function

* delete test file

* add integration test + shortest in makefile

* add some info logs

* add default config to gitignore

* add diagram

* Update README.md

* Update README.md

* remove unused uuid

* remove uuid package

* remove t.Run statements in tests

* remove t.Run in main_test.go

* Add some comments

* add go kraken

* use go kraken for web socket implementation

* change env var name

* test XBT/USDT ticker

* test XBT/USDT in feed_service

* formatting + cleaning

* add interval manament to updater_service

* add interval config in config_service

* create feeder from config

* formatting + cleaning

* better error handling in config_service.go

* ErrInvalidAssetHash implements error interface

* add go docs + clean some code

* remove gorilla/websocket package

* new config.example file

* update README

* Update dockerfile

* replace baseprice by quoteprice in priceupdater

* camel case to underscore filenames

* notify interupt channel if SIGTERM / SIGINT occur

* add viper

* handle default config file for integration test

* add viper env vars in Makefile

* move tdex_feeder from domain layer to application one

* add logs

* format test config

* Update internal/application/tdex_feeder.go

Co-authored-by: Marco Argentieri <[email protected]>
  • Loading branch information
louisinger and tiero authored Dec 10, 2020
1 parent c330778 commit 488cd2b
Show file tree
Hide file tree
Showing 36 changed files with 1,468 additions and 445 deletions.
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,8 @@
# Dependency directories (remove the comment below to include it)
# vendor/
build/

cmd/feederd/tdexd
cmd/feederd/config.json

config.json
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ RUN go mod download

COPY . .

RUN go build -o feederd-linux cmd/feederd/main.go
RUN GOOS=linux GOARCH=amd64 go build -o feederd-linux cmd/feederd/main.go

WORKDIR /build

Expand All @@ -20,4 +20,4 @@ RUN apt-get update && apt-get install -y --no-install-recommends ca-certificates

COPY --from=builder /build/ /

CMD ["/feederd-linux","-debug","-conf=./data/config.json"]
CMD ["/feederd-linux"]
15 changes: 11 additions & 4 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -41,20 +41,27 @@ help:

## run-linux: Run locally with default configuration
run-linux: clean build-linux
export FEEDER_LOG_LEVEL=5; \
./build/feederd-linux-amd64

## run-mac: Run locally with default configuration
run-mac: clean build-mac
export FEEDER_LOG_LEVEL=5; \
./build/feederd-darwin-amd64

## vet: code analysis
vet:
@echo "Vet..."
@go vet ./...


## test: runs go unit test with default values
test: fmt
chmod u+x ./scripts/test
./scripts/test
test: fmt shorttest

shorttest:
@echo "Testing..."
go test -v -count=1 -race -short ./...

integrationtest:
export FEEDER_CONFIG_PATH="./config.test.json"; \
export FEEDER_LOG_LEVEL=5; \
go test -v -count=1 ./cmd/feederd
35 changes: 14 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
# tdex-feeder

Feeder allows to connect an external price feed to the TDex Daemon to determine the current market price
Feeder allows to connect several price feeds to TDex Daemon(s) in order to automatically update the markets prices.

## Overview

tdex-feeder connects to exchanges and retrieves market prices in order to consume the gRPC
interface exposed from tdex-deamon `UpdateMarketPrice`.

![tdex-schema](./tdexfeeder.png)

## ⬇️ Run Standalone

### Install
Expand All @@ -24,11 +26,8 @@ interface exposed from tdex-deamon `UpdateMarketPrice`.
# Run with default config and default flags.
$ feederd

# Run with debug mode on.
$ feederd -debug

# Run with debug mode and different config path.
$ feederd -debug -conf=./config.json
$ FEEDER_CONFIG_PATH=./config.json feederd
```

## 🖥 Local Development
Expand All @@ -43,17 +42,19 @@ Build and use `feederd` with docker.

At the root of the repository
```
docker build -t tdex-feederd .
docker build --pull --rm -f 'Dockerfile' -t feederd:latest .
```

#### Run the daemon

Create a [config.json](#config-file) file
and run the following command in the same folder:
```
docker run -it -d --net=host -v $PWD/config.json:/data/config.json tdex-feederd
docker run -it --name feederd -v $HOME/config.json:/config.json --network="host" feederd
```
`--net=host` in case you're running tdex-deamon locally
the `$HOME/config.json` is the path to the feederd configuration file.

> `--net=host` in case you're running tdex-deamon locally
### Build it yourself

Expand All @@ -71,13 +72,6 @@ Builds feeder as static binary and runs the project with default configuration.

`make run-linux`

##### Flags

```
-conf: Configuration File Path. Default: "./config.json"
-debug: Log Debug Informations Default: false
```

##### Config file

Rename the file `./config.example.json` into `./config.json`
Expand All @@ -86,11 +80,10 @@ connects to kraken socket and to a local instance of tdex-deamon.

```
daemon_endpoint: String with the address and port of gRPC host. Required.
daemon_macaroon: String with the daemon_macaroon necessary for authentication.
kraken_ws_endpoint: String with the address and port of kraken socket. Required.
markets: Json List with necessary markets informations. Required.
base_asset: String of the Hash of the base asset for gRPC request. Required.
quote_asset: String of the Hash of the quote asset for gRPC request. Required.
kraken_ticker: String with the ticker we want kraken to provide informations on. Required.
interval: Int with the time in secods between gRPC requests. Required.
```
base_asset: String of the Hash of the base asset for gRPC request. Required.
quote_asset: String of the Hash of the quote asset for gRPC request. Required.
kraken_ticker: String with the ticker we want kraken to provide informations on. Required.
interval: the minimum time in milliseconds between two updateMarketPrice requests. Required.
```
5 changes: 0 additions & 5 deletions cmd/feeder/main.go

This file was deleted.

10 changes: 10 additions & 0 deletions cmd/feederd/config.test.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"daemon_endpoint":"127.0.0.1:9000",
"kraken_ws_endpoint":"ws.kraken.com",
"markets": [
{
"base_asset":"5ac9f65c0efcc4775e0baec4ec03abdde22473cd3cf33c0419ca290e0751b225","quote_asset":"bffce3908a595436b6ab08f916fea2c9fc6a702f46b268ca354205d127f60c48","kraken_ticker":"LTC/USDT",
"interval":500
}
]
}
123 changes: 36 additions & 87 deletions cmd/feederd/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,114 +4,63 @@
package main

import (
"flag"
"encoding/json"
"io/ioutil"
"os"
"os/signal"
"time"
"syscall"

log "github.com/sirupsen/logrus"
"google.golang.org/grpc"

"github.com/gorilla/websocket"
"github.com/tdex-network/tdex-feeder/config"
"github.com/tdex-network/tdex-feeder/pkg/conn"
"github.com/tdex-network/tdex-feeder/pkg/marketinfo"

pboperator "github.com/tdex-network/tdex-protobuf/generated/go/operator"
)

const (
defaultConfigPath = "./config.json"
"github.com/tdex-network/tdex-feeder/internal/adapters"
"github.com/tdex-network/tdex-feeder/internal/application"
)

func main() {
interrupt, cSocket, marketsInfos, conngRPC := setup()
infiniteLoops(interrupt, cSocket, marketsInfos, conngRPC)
}

func setup() (chan os.Signal, *websocket.Conn, []marketinfo.MarketInfo, *grpc.ClientConn) {
conf := checkFlags()

// Interrupt Notification.
interrupt := make(chan os.Signal, 1)
signal.Notify(interrupt, os.Interrupt)
signal.Notify(interrupt, os.Interrupt, syscall.SIGTERM, syscall.SIGINT)

// Dials the connection the the Socket.
cSocket, err := conn.ConnectToSocket(conf.KrakenWsEndpoint)
if err != nil {
log.Fatal("Socket Connection Error: ", err)
}
marketsInfos := loadMarkets(conf, cSocket)
if len(marketsInfos) == 0 {
log.Warn("list of market to feed is empty")
}
// retrieve feeder service from config file
feeder := configFileToFeederService(config.GetConfigPath())

// Set up the connection to the gRPC server.
conngRPC, err := conn.ConnectTogRPC(conf.DaemonEndpoint)
log.Info("Start the feeder...")
go func() {
err := feeder.Start()
if err != nil {
log.Fatal(err)
}
}()

// check for interupt
<-interrupt
log.Info("Shutting down the feeder...")
err := feeder.Stop()
log.Info("Feeder service stopped")
if err != nil {
log.Fatal("gRPC Connection Error: ", err)
log.Fatal(err)
}
return interrupt, cSocket, marketsInfos, conngRPC
os.Exit(0)
}

// Checks for command line flags for Config Path and Debug mode.
// Loads flags as required.
func checkFlags() config.Config {
confFlag := flag.String("conf", defaultConfigPath, "Configuration File Path")
debugFlag := flag.Bool("debug", false, "Log Debug Informations")
flag.Parse()
if *debugFlag == true {
log.SetLevel(log.DebugLevel)
}
// Loads Config File.
conf, err := config.LoadConfig(*confFlag)
func configFileToFeederService(configFilePath string) application.FeederService {
jsonFile, err := os.Open(configFilePath)
if err != nil {
log.Fatal(err)
}
return conf
}
defer jsonFile.Close()

// Loads Config Markets infos into Data Structure and Subscribes to
// Messages from this Markets.
func loadMarkets(conf config.Config, cSocket *websocket.Conn) []marketinfo.MarketInfo {
numberOfMarkets := len(conf.Markets)
marketsInfos := make([]marketinfo.MarketInfo, numberOfMarkets)
for i, marketConfig := range conf.Markets {
marketsInfos[i] = marketinfo.InitialMarketInfo(marketConfig)
m := conn.CreateSubscribeToMarketMessage(marketConfig.KrakenTicker)
err := conn.SendRequestMessage(cSocket, m)
if err != nil {
log.Fatal("Couldn't send request message: ", err)
}
configBytes, err := ioutil.ReadAll(jsonFile)
if err != nil {
log.Fatal(err)
}
return marketsInfos
}

func infiniteLoops(interrupt chan os.Signal, cSocket *websocket.Conn, marketsInfos []marketinfo.MarketInfo, conngRPC *grpc.ClientConn) {
defer cSocket.Close()
defer conngRPC.Close()
clientgRPC := pboperator.NewOperatorClient(conngRPC)
done := make(chan string)
// Handles Messages from subscriptions. Will periodically call the
// gRPC UpdateMarketPrice with the price info from the messages.
go conn.HandleMessages(done, cSocket, marketsInfos, clientgRPC)
checkInterrupt(interrupt, cSocket, done)
}

// Loop to keep cycle alive. Waits Interrupt to close the connection.
func checkInterrupt(interrupt chan os.Signal, cSocket *websocket.Conn, done chan string) {
for {
for range interrupt {
log.Println("Shutting down Feeder")
err := cSocket.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, ""))
if err != nil {
log.Fatal("write close:", err)
}
select {
case <-done:
case <-time.After(time.Second):
}
return
}
config := &adapters.Config{}
err = json.Unmarshal(configBytes, config)
if err != nil {
log.Fatal(err)
}

feeder := config.ToFeederService()
return feeder
}
Loading

0 comments on commit 488cd2b

Please sign in to comment.