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

Try fetch upstream #24

Open
wants to merge 10 commits into
base: main
Choose a base branch
from
2 changes: 1 addition & 1 deletion lecture_3/03_project/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ We are building a simple betting platform. You can find further information in t
- Name: "Run Controller"
- Run kind: "Package"
- Package path: "github.com/superbet-group/code-cadets-2021/lecture_3/03_project/controller/cmd"
- Working directory (replace with your path!): "/Users/oreskd/Axilis/code-cadets/2021/code-cadets-2021/lecture_3/temp"
- Working directory (replace with your path!): "/Users/oreskd/Axilis/code-cadets/2021/code-cadets-2021/lecture_3/03_project/controller"
- under "EnvFile" check "Enable EnvFile" and click "+" under the table (which currently contains only one entry)
- choose `.env` file from `controller/` directory (note: the file may be hidden, you need to show hidden files in that case)

5 changes: 5 additions & 0 deletions lecture_3/03_project/calculator/.env
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
RABBIT_CONSUMER_BET_QUEUE="bets"
RABBIT_CONSUMER_EVENT_UPDATE_QUEUE="event-updates"
RABBIT_PUBLISHER_BET_CALCULATED_QUEUE="bets-calculated"

SQLITE_DATABASE="../db/calc_bets.db"
119 changes: 119 additions & 0 deletions lecture_3/03_project/calculator/cmd/bootstrap/engine.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
package bootstrap

import (
"github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/cmd/config"
"github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/internal/domain/mappers"
"github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/internal/engine"
"github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/internal/engine/consumer"
"github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/internal/engine/handler"
"github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/internal/engine/publisher"
"github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/internal/infrastructure/rabbitmq"
"github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/internal/infrastructure/sqlite"
)

func newBetConsumer(channel rabbitmq.Channel) *rabbitmq.BetConsumer {
betConsumer, err := rabbitmq.NewBetConsumer(
channel,
rabbitmq.ConsumerConfig{
Queue: config.Cfg.Rabbit.ConsumerBetQueue,
DeclareDurable: config.Cfg.Rabbit.DeclareDurable,
DeclareAutoDelete: config.Cfg.Rabbit.DeclareAutoDelete,
DeclareExclusive: config.Cfg.Rabbit.DeclareExclusive,
DeclareNoWait: config.Cfg.Rabbit.DeclareNoWait,
DeclareArgs: nil,
ConsumerName: config.Cfg.Rabbit.ConsumerBetName,
AutoAck: config.Cfg.Rabbit.ConsumerAutoAck,
Exclusive: config.Cfg.Rabbit.ConsumerExclusive,
NoLocal: config.Cfg.Rabbit.ConsumerNoLocal,
NoWait: config.Cfg.Rabbit.ConsumerNoWait,
Args: nil,
},
)
if err != nil {
panic(err)
}
return betConsumer
}

func newEventUpdateConsumer(channel rabbitmq.Channel) *rabbitmq.EventUpdateConsumer {
eventUpdateConsumer, err := rabbitmq.NewEventUpdateConsumer(
channel,
rabbitmq.ConsumerConfig{
Queue: config.Cfg.Rabbit.ConsumerEventUpdateQueue,
DeclareDurable: config.Cfg.Rabbit.DeclareDurable,
DeclareAutoDelete: config.Cfg.Rabbit.DeclareAutoDelete,
DeclareExclusive: config.Cfg.Rabbit.DeclareExclusive,
DeclareNoWait: config.Cfg.Rabbit.DeclareNoWait,
DeclareArgs: nil,
ConsumerName: config.Cfg.Rabbit.ConsumerEventUpdateName,
AutoAck: config.Cfg.Rabbit.ConsumerAutoAck,
Exclusive: config.Cfg.Rabbit.ConsumerExclusive,
NoLocal: config.Cfg.Rabbit.ConsumerNoLocal,
NoWait: config.Cfg.Rabbit.ConsumerNoWait,
Args: nil,
},
)
if err != nil {
panic(err)
}
return eventUpdateConsumer
}

func newConsumer(
betConsumer consumer.BetConsumer,
eventUpdateConsumer consumer.EventUpdateConsumer,
) *consumer.Consumer {
return consumer.New(betConsumer, eventUpdateConsumer)
}

func newBetMapper() *mappers.BetMapper {
return mappers.NewBetMapper()
}

func newBetRepository(dbExecutor sqlite.DatabaseExecutor, betMapper sqlite.BetMapper) *sqlite.BetRepository {
return sqlite.NewBetRepository(dbExecutor, betMapper)
}

func newHandler(betRepository handler.BetRepository) *handler.Handler {
return handler.New(betRepository)
}

func newBetCalculatedPublisher(channel rabbitmq.Channel) *rabbitmq.BetCalculatedPublisher {
betPublisher, err := rabbitmq.NewBetCalculatedPublisher(
channel,
rabbitmq.PublisherConfig{
Queue: config.Cfg.Rabbit.PublisherBetCalculatedQueue,
DeclareDurable: config.Cfg.Rabbit.DeclareDurable,
DeclareAutoDelete: config.Cfg.Rabbit.DeclareAutoDelete,
DeclareExclusive: config.Cfg.Rabbit.DeclareExclusive,
DeclareNoWait: config.Cfg.Rabbit.DeclareNoWait,
DeclareArgs: nil,
Exchange: config.Cfg.Rabbit.PublisherExchange,
Mandatory: config.Cfg.Rabbit.PublisherMandatory,
Immediate: config.Cfg.Rabbit.PublisherImmediate,
},
)
if err != nil {
panic(err)
}
return betPublisher
}

func newPublisher(betPublisher publisher.BetCalculatedPublisher) *publisher.Publisher {
return publisher.New(betPublisher)
}

func Engine(rabbitMqChannel rabbitmq.Channel, dbExecutor sqlite.DatabaseExecutor) *engine.Engine {
betReceivedConsumer := newBetConsumer(rabbitMqChannel)
betCalculatedConsumer := newEventUpdateConsumer(rabbitMqChannel)
consumer := newConsumer(betReceivedConsumer, betCalculatedConsumer)

betMapper := newBetMapper()
betRepository := newBetRepository(dbExecutor, betMapper)
handler := newHandler(betRepository)

betCalculatedPublisher := newBetCalculatedPublisher(rabbitMqChannel)
publisher := newPublisher(betCalculatedPublisher)

return engine.New(consumer, handler, publisher)
}
17 changes: 17 additions & 0 deletions lecture_3/03_project/calculator/cmd/bootstrap/rabbitmq.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package bootstrap

import "github.com/streadway/amqp"

func RabbitMq() *amqp.Channel {
conn, err := amqp.Dial("amqp://guest:guest@localhost:5672/")
if err != nil {
panic(err)
}

channel, err := conn.Channel()
if err != nil {
panic(err)
}

return channel
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package bootstrap

import "github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/internal/tasks"

func SignalHandler() *tasks.SignalHandler {
return tasks.NewSignalHandler()
}
18 changes: 18 additions & 0 deletions lecture_3/03_project/calculator/cmd/bootstrap/sqlite.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package bootstrap

import (
"database/sql"

_ "github.com/mattn/go-sqlite3"

"github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/cmd/config"
)

func Sqlite() *sql.DB {
db, err := sql.Open("sqlite3", config.Cfg.SqliteDatabase)
if err != nil {
panic(err)
}

return db
}
45 changes: 45 additions & 0 deletions lecture_3/03_project/calculator/cmd/config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package config

import "github.com/kelseyhightower/envconfig"

// Cfg is the single instance of configuration that gets automatically populated from the
// environment variables once the module loads.
var Cfg Config

// Config contains all the configuration needed for service to work.
type Config struct {
Rabbit rabbitConfig `split_words:"true"`
SqliteDatabase string `split_words:"true"`
}

type rabbitConfig struct {
ConsumerBetQueue string `split_words:"true" required:"true"`
ConsumerEventUpdateQueue string `split_words:"true" required:"true"`
ConsumerBetName string `split_words:"true" default:"calculatorbet"`
ConsumerEventUpdateName string `split_words:"true" default:"calculatoreventupdate"`
ConsumerAutoAck bool `split_words:"true" default:"true"`
ConsumerExclusive bool `split_words:"true" default:"false"`
ConsumerNoLocal bool `split_words:"true" default:"false"`
ConsumerNoWait bool `split_words:"true" default:"false"`
PublisherBetCalculatedQueue string `split_words:"true" required:"true"`
PublisherDeclareDurable bool `split_words:"true" default:"true"`
PublisherDeclareAutoDelete bool `split_words:"true" default:"false"`
PublisherDeclareExclusive bool `split_words:"true" default:"false"`
PublisherDeclareNoWait bool `split_words:"true" default:"false"`
PublisherExchange string `split_words:"true" default:""`
PublisherMandatory bool `split_words:"true" default:"false"`
PublisherImmediate bool `split_words:"true" default:"false"`
DeclareDurable bool `split_words:"true" default:"true"`
DeclareAutoDelete bool `split_words:"true" default:"false"`
DeclareExclusive bool `split_words:"true" default:"false"`
DeclareNoWait bool `split_words:"true" default:"false"`
}

// Load loads the configuration on bootstrap, this avoid injecting the same config object
// everywhere.
func Load() {
err := envconfig.Process("", &Cfg)
if err != nil {
panic(err)
}
}
27 changes: 27 additions & 0 deletions lecture_3/03_project/calculator/cmd/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package main

import (
"log"

"github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/cmd/bootstrap"
"github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/cmd/config"
"github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/internal/tasks"
)

func main() {
log.Println("Bootstrap initiated")

config.Load()

rabbitMqChannel := bootstrap.RabbitMq()
db := bootstrap.Sqlite()

signalHandler := bootstrap.SignalHandler()
engine := bootstrap.Engine(rabbitMqChannel, db)

log.Println("Bootstrap finished. Engine is starting")

tasks.RunTasks(signalHandler, engine)

log.Println("Service finished gracefully")
}
10 changes: 10 additions & 0 deletions lecture_3/03_project/calculator/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator

go 1.14

require (
github.com/kelseyhightower/envconfig v1.4.0
github.com/mattn/go-sqlite3 v1.14.7
github.com/pkg/errors v0.9.1
github.com/streadway/amqp v1.0.0
)
8 changes: 8 additions & 0 deletions lecture_3/03_project/calculator/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
github.com/kelseyhightower/envconfig v1.4.0 h1:Im6hONhd3pLkfDFsbRgu68RDNkGF1r3dvMUtDTo2cv8=
github.com/kelseyhightower/envconfig v1.4.0/go.mod h1:cccZRl6mQpaq41TPp5QxidR+Sa3axMbJDNb//FQX6Gg=
github.com/mattn/go-sqlite3 v1.14.7 h1:fxWBnXkxfM6sRiuH3bqJ4CfzZojMOLVc0UTsTglEghA=
github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/streadway/amqp v1.0.0 h1:kuuDrUJFZL1QYL9hUNuCxNObNzB0bV/ZG5jV3RWAQgo=
github.com/streadway/amqp v1.0.0/go.mod h1:AZpEONHx3DKn8O/DFsRAY58/XVQiIPMTMB1SddzLXVw=
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package mappers

import (
"math"

domainmodels "github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/internal/domain/models"
storagemodels "github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/internal/infrastructure/sqlite/models"
)

// BetMapper maps storage bets to domain bets and vice versa.
type BetMapper struct {
}

// NewBetMapper creates and returns a new BetMapper.
func NewBetMapper() *BetMapper {
return &BetMapper{}
}

// MapDomainBetToStorageBet maps the given domain bet into storage bet. Floating point values will
// be converted to corresponding integer values of the storage bet by multiplying them with 100.
func (m *BetMapper) MapDomainBetToStorageBet(domainBet domainmodels.Bet) storagemodels.Bet {
return storagemodels.Bet{
Id: domainBet.Id,
SelectionId: domainBet.SelectionId,
SelectionCoefficient: int(math.Round(domainBet.SelectionCoefficient * 100)),
Payment: int(math.Round(domainBet.Payment * 100)),
}
}

// MapStorageBetToDomainBet maps the given storage bet into domain bet. Floating point values will
// be converted from corresponding integer values of the storage bet by dividing them with 100.
func (m *BetMapper) MapStorageBetToDomainBet(storageBet storagemodels.Bet) domainmodels.Bet {
return domainmodels.Bet{
Id: storageBet.Id,
SelectionId: storageBet.SelectionId,
SelectionCoefficient: float64(storageBet.SelectionCoefficient) / 100,
Payment: float64(storageBet.Payment) / 100,
}
}
9 changes: 9 additions & 0 deletions lecture_3/03_project/calculator/internal/domain/models/bet.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package models

// Bet represents a domain model representation of a bet.
type Bet struct {
Id string
SelectionId string
SelectionCoefficient float64
Payment float64
}
12 changes: 12 additions & 0 deletions lecture_3/03_project/calculator/internal/engine/consumer.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package engine

import (
"context"

rabbitmqmodels "github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/internal/infrastructure/rabbitmq/models"
)

type Consumer interface {
ConsumeBets(ctx context.Context) (<-chan rabbitmqmodels.Bet, error)
ConsumeEventUpdates(ctx context.Context) (<-chan rabbitmqmodels.EventUpdate, error)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package consumer

import (
"context"

rabbitmqmodels "github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/internal/infrastructure/rabbitmq/models"
)

type BetConsumer interface {
Consume(ctx context.Context) (<-chan rabbitmqmodels.Bet, error)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package consumer

import (
"context"

rabbitmqmodels "github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/internal/infrastructure/rabbitmq/models"
)

// Consumer offers methods for consuming from input queues.
type Consumer struct {
betConsumer BetConsumer
eventUpdateConsumer EventUpdateConsumer
}

// New creates and returns a new Consumer.
func New(betConsumer BetConsumer, eventUpdateConsumer EventUpdateConsumer) *Consumer {
return &Consumer{
betConsumer: betConsumer,
eventUpdateConsumer: eventUpdateConsumer,
}
}

// ConsumeBets consumes bets queue.
func (c *Consumer) ConsumeBets(ctx context.Context) (<-chan rabbitmqmodels.Bet, error) {
return c.betConsumer.Consume(ctx)
}

// ConsumeEventUpdates consumes event-updates queue.
func (c *Consumer) ConsumeEventUpdates(ctx context.Context) (<-chan rabbitmqmodels.EventUpdate, error) {
return c.eventUpdateConsumer.Consume(ctx)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package consumer

import (
"context"

rabbitmqmodels "github.com/superbet-group/code-cadets-2021/lecture_3/03_project/calculator/internal/infrastructure/rabbitmq/models"
)

type EventUpdateConsumer interface {
Consume(ctx context.Context) (<-chan rabbitmqmodels.EventUpdate, error)
}
Loading