app/app.go
package app
import (
"context"
"os"
"os/signal"
"syscall"
"time"
"github.com/sprawl/sprawl/database/inmemory"
"github.com/sprawl/sprawl/database/leveldb"
"github.com/sprawl/sprawl/errors"
"github.com/sprawl/sprawl/identity"
"github.com/sprawl/sprawl/interfaces"
"github.com/sprawl/sprawl/p2p"
"github.com/sprawl/sprawl/pb"
"github.com/sprawl/sprawl/service"
"github.com/sprawl/sprawl/util"
)
// App ties Sprawl's services together
type App struct {
Storage interfaces.Storage
P2p *p2p.P2p
Server *service.Server
Logger interfaces.Logger
config interfaces.Config
WebsocketService interfaces.WebsocketService
}
func (app *App) debugPinger() {
var testChannel *pb.Channel = &pb.Channel{Id: []byte("testChannel")}
app.P2p.Subscribe(testChannel)
testRequest := &pb.CreateRequest{ChannelID: testChannel.GetId(), Asset: string("ETH"), CounterAsset: string("BTC"), Amount: 52153, Price: 0.2}
for {
app.Logger.Infof("Debug pinger is sending testRequest: %s\n", testRequest)
orderID, err := app.Server.Orders.Create(context.Background(), testRequest)
if !errors.IsEmpty(err) {
app.Logger.Error(errors.E(errors.Op("Create Request"), err))
}
testOrderSpecificRequest := &pb.OrderSpecificRequest{OrderID: orderID.GetCreatedOrder().GetId(), ChannelID: testChannel.GetId()}
time.Sleep(time.Minute)
app.Server.Orders.Delete(context.Background(), testOrderSpecificRequest)
}
}
// InitServices ties the services together before running
func (app *App) InitServices(config interfaces.Config, Logger interfaces.Logger) {
app.config = config
if Logger == nil {
app.Logger = new(util.PlaceholderLogger)
} else {
app.Logger = Logger
}
errors.SetDebug(app.config.GetStackTraceSetting())
app.Logger.Infof("Saving data to %s", app.config.GetDatabasePath())
// Start up the database
if app.config.GetInMemoryDatabaseSetting() {
app.Storage = &inmemory.Storage{
Db: make(map[string]string),
}
} else {
app.Storage = &leveldb.Storage{}
}
app.Storage.SetDbPath(app.config.GetDatabasePath())
app.Storage.Run()
privateKey, publicKey, err := identity.GetIdentity(app.Storage)
if !errors.IsEmpty(err) {
app.Logger.Error(errors.E(errors.Op("Get identity"), err))
}
if app.config.GetWebsocketEnable() {
app.WebsocketService = &service.WebsocketService{Logger: Logger, Port: app.config.GetWebsocketPort()}
go app.WebsocketService.Start()
}
// Run the P2P process
app.P2p = p2p.NewP2p(config, privateKey, publicKey, p2p.Logger(app.Logger), p2p.Storage(app.Storage))
// Construct the server struct
app.Server = service.NewServer(Logger, app.Storage, app.P2p, app.WebsocketService)
// Connect the order service as a receiver for p2p
app.P2p.AddReceiver(app.Server.Orders)
// Run the P2p service before running the gRPC server
app.P2p.Run()
systemSignals := make(chan os.Signal)
signal.Notify(systemSignals, syscall.SIGINT, syscall.SIGTERM)
go func() {
select {
case sig := <-systemSignals:
app.Logger.Infof("Received %s signal, shutting down.\n", sig)
app.Server.Close()
app.P2p.Close()
app.Storage.Close()
os.Exit(0)
}
}()
}
// Run is a separated main-function to ease testing
func (app *App) Run() {
defer app.Server.Close()
defer app.Storage.Close()
defer app.P2p.Close()
if app.WebsocketService != nil {
defer app.WebsocketService.Close()
}
if app.config.GetDebugSetting() {
if app.Logger != nil {
app.Logger.Info("Running the debug pinger on channel \"testChannel\"!")
}
go app.debugPinger()
}
// Run the gRPC API
app.Server.Run(app.config.GetRPCPort())
}