rove/cmd/rove-accountant/main.go

132 lines
3.2 KiB
Go

package main
import (
"context"
"fmt"
"log"
"net"
"os"
"os/signal"
"strconv"
"sync"
"syscall"
"github.com/mdiluz/rove/cmd/rove-accountant/internal"
"github.com/mdiluz/rove/pkg/accounts"
"github.com/mdiluz/rove/pkg/persistence"
"google.golang.org/grpc"
)
var data = os.Getenv("DATA_PATH")
// accountantServer is the internal object to manage the requests
type accountantServer struct {
accountant *internal.Accountant
sync sync.RWMutex
}
// Register will register an account
func (a *accountantServer) Register(ctx context.Context, in *accounts.RegisterInfo) (*accounts.RegisterResponse, error) {
a.sync.Lock()
defer a.sync.Unlock()
// Try and register the account itself
log.Printf("Registering account: %s\n", in.Name)
if _, err := a.accountant.RegisterAccount(in.Name); err != nil {
log.Printf("Error: %s\n", err)
return nil, err
}
// Save out the accounts
if err := persistence.Save("accounts", a.accountant); err != nil {
log.Printf("Error: %s\n", err)
return nil, err
}
return &accounts.RegisterResponse{}, nil
}
// AssignData assigns a key value pair to an account
func (a *accountantServer) AssignValue(_ context.Context, in *accounts.DataKeyValue) (*accounts.DataKeyResponse, error) {
a.sync.RLock()
defer a.sync.RUnlock()
// Try and assign the data
log.Printf("Assigning value for account %s: %s->%s\n", in.Account, in.Key, in.Value)
err := a.accountant.AssignData(in.Account, in.Key, in.Value)
if err != nil {
log.Printf("Error: %s\n", err)
return nil, err
}
return &accounts.DataKeyResponse{}, nil
}
// GetData gets the value for a key
func (a *accountantServer) GetValue(_ context.Context, in *accounts.DataKey) (*accounts.DataResponse, error) {
a.sync.RLock()
defer a.sync.RUnlock()
// Try and fetch the rover
log.Printf("Getting value for account %s: %s\n", in.Account, in.Key)
data, err := a.accountant.GetValue(in.Account, in.Key)
if err != nil {
log.Printf("Error: %s\n", err)
return nil, err
}
return &accounts.DataResponse{Value: data}, nil
}
// main
func main() {
// Verify the input
var port = os.Getenv("PORT")
if len(port) == 0 {
log.Fatal("Must set $PORT")
}
iport, err := strconv.Atoi(port)
if err != nil {
log.Fatal("$PORT not valid int")
}
persistence.SetPath(data)
// Initialise and load the accountant
accountant := internal.NewAccountant()
if err := persistence.Load("accounts", accountant); err != nil {
log.Fatalf("failed to load account data: %s", err)
}
// Set up the RPC server and register
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", iport))
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
grpcServer := grpc.NewServer()
accounts.RegisterAccountantServer(grpcServer, &accountantServer{
accountant: accountant,
})
// Set up the close handler
c := make(chan os.Signal)
signal.Notify(c, os.Interrupt, syscall.SIGTERM)
go func() {
<-c
log.Println("Quit requested, exiting...")
grpcServer.Stop()
}()
// Serve the RPC server
log.Printf("Serving accountant on %s\n", port)
if err := grpcServer.Serve(lis); err != nil {
log.Fatalf("failed to serve gRPC: %s", err)
}
// Save out the accountant data
if err := persistence.Save("accounts", accountant); err != nil {
log.Fatalf("failed to save accounts: %s", err)
}
}