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

Refactor #28

Merged
merged 9 commits into from
Sep 6, 2021
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
16 changes: 7 additions & 9 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.PHONY: build run clean cov fmt help vet test shorttest integrationtest

## build-arm: build binary for ARM
## build: builds binary for all platforms
build:
chmod u+x ./scripts/build
./scripts/build
Expand All @@ -15,7 +15,7 @@ cov:
@echo "Coverage..."
go test -cover ./...

## fmt: Go Format
## fmt: checks if code is well formatted
fmt:
@echo "Gofmt..."
@if [ -n "$(gofmt -l .)" ]; then echo "Go code is not formatted"; exit 1; fi
Expand All @@ -26,24 +26,22 @@ help:
@echo "Usage: \n"
@sed -n 's/^##//p' ${MAKEFILE_LIST} | column -t -s ':' | sed -e 's/^/ /'

## run-linux: Run locally with default configuration
# run: runs locally without building binary
run: clean
export FEEDER_CONFIG_PATH=./config.example.json; \
export FEEDER_LOG_LEVEL=5; \
go run cmd/feederd/main.go

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

## test: runs go unit test with default values
test: fmt shorttest

shorttest:
## test: runs unit tests
test: fmt
@echo "Testing..."
go test -v -count=1 -race -short ./...

## integrationtest: run integration tests
integrationtest:
export FEEDER_CONFIG_PATH="./config.test.json"; \
export FEEDER_LOG_LEVEL=5; \
Expand Down
45 changes: 24 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@ Feeder allows to connect several price feeds to TDex Daemon(s) in order to autom

## Overview

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

tdex-feeder connects to exchanges and forwards market(s) price feeds to some tdex-daemon(s) by consuming its `UpdateMarketPrice` RPC.
![tdex-schema](./tdexfeeder.png)

## ⬇️ Run Standalone
Expand Down Expand Up @@ -58,31 +56,36 @@ the `$HOME/config.json` is the path to the feederd configuration file.

### Build it yourself

Builds feeder as static binary and runs the project with default configuration.

#### Linux

`make build-linux`

#### Mac
Build feeder as static binary and run the project with default configuration.

`make build-mac`
```sh
# build feeder as a static binary
$ make build

#### Run Linux
# run the binary on Linux
$ ./build/feederd-linux-amd64

`make run-linux`
# run the binary on MacOS
$ ./build/feederd-darwin-amd64
```

##### Config file

Rename the file `./config.example.json` into `./config.json`
and adapt if for your specific purpose. The default example
connects to kraken socket and to a local instance of tdex-deamon.
uses kraken as price feeder and forwards the feeds related to the BTC/USDT market to a local daemon (with mac auth disabled).

NOTE: All entries of the JSON configuration file are mandatory if not otherwise expressed. Below you can find a brief explanation of the JSON object.

```
daemon_endpoint: String with the address and port of gRPC host. Required.
market: 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: the minimum time in milliseconds between two updateMarketPrice requests. Required.
```
price_feeder: service where to source prices (only "kraken" available for now).
interval: the period in millisecond with which the feeder updates its target(s).
markets: list with necessary markets info.
base_asset: hex string of the hash of the market base asset.
quote_asset: hex string of the hash of the market quote asset.
ticker: string of the corresponding feeder's market ticker.
targets: list of daemons to update for every feed received on this market.
rpc_address: string with hostname and port of the target daemon.
tls_cert_path: string path of the TLS cert file to use to connect with the target daemon. Optional.
macaroons_path: string path of the macaroon file to use to connect with the target daemon. Optional.
```
1 change: 0 additions & 1 deletion cmd/feederd/config.test.json

This file was deleted.

105 changes: 60 additions & 45 deletions cmd/feederd/main.go
Original file line number Diff line number Diff line change
@@ -1,70 +1,85 @@
// Copyright (c) 2020 The VulpemVentures developers

// Feeder allows to connect an external price feed to the TDex Daemon to determine the current market price.
package main

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

log "github.com/sirupsen/logrus"
"github.com/tdex-network/tdex-feeder/config"
"github.com/tdex-network/tdex-feeder/internal/adapters"
"github.com/tdex-network/tdex-feeder/internal/application"
)

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

// retrieve feeder service from config file
feeder := configFileToFeederService(config.GetConfigPath())
"github.com/tdex-network/tdex-feeder/internal/config"
"github.com/tdex-network/tdex-feeder/internal/core/application"
grpcclient "github.com/tdex-network/tdex-feeder/internal/core/infrastructure/client/grpc"
krakenfeeder "github.com/tdex-network/tdex-feeder/internal/core/infrastructure/feeder/kraken"
"github.com/tdex-network/tdex-feeder/internal/core/ports"
)

log.Info("Start the feeder...")
go func() {
err := feeder.Start()
if err != nil {
log.Fatal(err)
}
}()
type indexedPriceFeeders map[string]func(args ...interface{}) (ports.PriceFeeder, error)

// check for interupt
<-interrupt
log.Info("Shutting down the feeder...")
err := feeder.Stop()
log.Info("Feeder service stopped")
if err != nil {
log.Fatal(err)
func (i indexedPriceFeeders) supported() []string {
keys := make([]string, 0, len(i))
for k := range i {
keys = append(keys, k)
}
os.Exit(0)
return keys
}

func configFileToFeederService(configFilePath string) application.FeederService {
jsonFile, err := os.Open(configFilePath)
if err != nil {
log.Fatal(err)
var (
priceFeeders = indexedPriceFeeders{
"kraken": krakenfeeder.NewKrakenPriceFeeder,
}
defer jsonFile.Close()
)

configBytes, err := ioutil.ReadAll(jsonFile)
func main() {
cfg, err := config.NewConfigFromFile()
if err != nil {
log.Fatal(err)
log.WithError(err).Fatalf(
"error while reading config from file %s", config.GetConfigPath(),
)
}

config := &adapters.Config{}
err = json.Unmarshal(configBytes, config)
if err != nil {
log.Fatal(err)
priceFeederFactory, ok := priceFeeders[cfg.PriceFeeder]
if !ok {
log.Fatalf(
"price feeder must be one of: '%s'", priceFeeders.supported(),
)
}

feeder, err := config.ToFeederService()
priceFeeder, err := priceFeederFactory(cfg.Interval, cfg.PortableMarkets())
if err != nil {
log.Fatal(err)
log.WithError(err).Fatal("error while initializing price feeder")
}

indexedTargets := make(application.IndexedTargetsByMarket)
for _, mkt := range cfg.Markets {
targets := make(map[string]ports.TdexClient)
for _, t := range mkt.CTargets {
target, err := grpcclient.NewGRPCClient(t.RPCAddress, t.MacaroonsPath, t.TLSCertPath)
if err != nil {
log.WithError(err).Fatalf(
"error while connecting with target %s", t.RPCAddress,
)
}
targets[target.RPCAddress()] = target
}
mktKey := ports.MarketKey(mkt)
indexedTargets[mktKey] = targets
}

return feeder
app := application.NewService(priceFeeder, indexedTargets)

defer app.Stop()

log.Info("starting service")
go func() {
if err := app.Start(); err != nil {
log.WithError(err).Fatal("service exited with error")
}
}()

sigChan := make(chan os.Signal, 1)
signal.Notify(sigChan, syscall.SIGTERM, syscall.SIGINT)
<-sigChan

log.Info("shutting down")
}
Loading