dc4bc/cmd/dc4bc_d/main.go

244 lines
6.7 KiB
Go
Raw Permalink Normal View History

2020-08-04 00:45:32 -07:00
package main
import (
"context"
2020-10-13 07:41:02 -07:00
"encoding/json"
2020-09-07 09:06:28 -07:00
"fmt"
2020-10-13 07:41:02 -07:00
"io/ioutil"
2020-08-04 00:45:32 -07:00
"log"
"os"
"os/signal"
2020-10-15 09:35:06 -07:00
"reflect"
2020-08-04 00:45:32 -07:00
"syscall"
2020-11-05 01:43:54 -08:00
"github.com/lidofinance/dc4bc/client"
"github.com/lidofinance/dc4bc/qr"
"github.com/lidofinance/dc4bc/storage"
2020-08-04 00:45:32 -07:00
"github.com/spf13/cobra"
)
const (
2020-08-14 05:34:15 -07:00
flagUserName = "username"
2020-08-04 00:45:32 -07:00
flagListenAddr = "listen_addr"
flagStateDBDSN = "state_dbdsn"
flagStorageDBDSN = "storage_dbdsn"
2020-10-05 10:07:02 -07:00
flagStorageTopic = "storage_topic"
2020-08-14 05:34:15 -07:00
flagStoreDBDSN = "key_store_dbdsn"
2020-09-29 08:16:20 -07:00
flagFramesDelay = "frames_delay"
flagChunkSize = "chunk_size"
2020-10-13 07:41:02 -07:00
flagConfigPath = "config_path"
2020-08-04 00:45:32 -07:00
)
func init() {
2020-08-14 05:34:15 -07:00
rootCmd.PersistentFlags().String(flagUserName, "testUser", "Username")
rootCmd.PersistentFlags().String(flagListenAddr, "localhost:8080", "Listen Address")
2020-08-04 00:45:32 -07:00
rootCmd.PersistentFlags().String(flagStateDBDSN, "./dc4bc_client_state", "State DBDSN")
rootCmd.PersistentFlags().String(flagStorageDBDSN, "./dc4bc_file_storage", "Storage DBDSN")
2020-10-05 10:07:02 -07:00
rootCmd.PersistentFlags().String(flagStorageTopic, "messages", "Storage Topic (Kafka)")
2020-09-07 09:06:28 -07:00
rootCmd.PersistentFlags().String(flagStoreDBDSN, "./dc4bc_key_store", "Key Store DBDSN")
2020-09-29 08:16:20 -07:00
rootCmd.PersistentFlags().Int(flagFramesDelay, 10, "Delay times between frames in 100ths of a second")
rootCmd.PersistentFlags().Int(flagChunkSize, 256, "QR-code's chunk size")
2020-10-13 07:41:02 -07:00
rootCmd.PersistentFlags().String(flagConfigPath, "", "Path to a config file")
}
type config struct {
Username string `json:"username"`
ListenAddress string `json:"listen_address"`
StateDBDSN string `json:"state_dbdsn"`
StorageDBDSN string `json:"storage_dbdsn"`
StorageTopic string `json:"storage_topic"`
KeyStoreDBDSN string `json:"keystore_dbdsn"`
2020-10-15 09:35:06 -07:00
FramesDelay int `json:"frames_delay"`
2020-10-13 07:41:02 -07:00
ChunkSize int `json:"chunk_size"`
}
func readConfig(path string) (config, error) {
var cfg config
configBz, err := ioutil.ReadFile(path)
if err != nil {
return cfg, fmt.Errorf("failed to read config file: %w", err)
}
if err = json.Unmarshal(configBz, &cfg); err != nil {
return cfg, fmt.Errorf("failed to unmarshal config: %w", err)
}
return cfg, nil
}
2020-10-15 09:35:06 -07:00
func checkConfig(cfg *config) error {
v := reflect.ValueOf(cfg)
v = v.Elem()
t := reflect.TypeOf(*cfg)
for i := 0; i < v.NumField(); i++ {
if v.Field(i).IsZero() {
return fmt.Errorf("%s cannot be empty", t.Field(i).Tag.Get("json"))
}
}
if cfg.FramesDelay < 0 {
return fmt.Errorf("frames_delay cannot be less than zero")
}
if cfg.ChunkSize < 0 {
return fmt.Errorf("chunk_size cannot be less than zero")
}
return nil
}
2020-10-13 07:41:02 -07:00
func loadConfig(cmd *cobra.Command) (*config, error) {
var cfg config
cfgPath, err := cmd.Flags().GetString(flagConfigPath)
if err != nil {
return nil, fmt.Errorf("failed to read configuration: %v", err)
}
if cfgPath != "" {
cfg, err = readConfig(cfgPath)
if err != nil {
return nil, err
}
} else {
cfg.Username, err = cmd.Flags().GetString(flagUserName)
if err != nil {
return nil, fmt.Errorf("failed to read configuration: %v", err)
}
cfg.KeyStoreDBDSN, err = cmd.Flags().GetString(flagStoreDBDSN)
if err != nil {
return nil, fmt.Errorf("failed to read configuration: %v", err)
}
cfg.ListenAddress, err = cmd.Flags().GetString(flagListenAddr)
if err != nil {
return nil, fmt.Errorf("failed to read configuration: %v", err)
}
cfg.StateDBDSN, err = cmd.Flags().GetString(flagStateDBDSN)
if err != nil {
return nil, fmt.Errorf("failed to read configuration: %v", err)
}
2020-10-15 09:35:06 -07:00
cfg.FramesDelay, err = cmd.Flags().GetInt(flagFramesDelay)
2020-10-13 07:41:02 -07:00
if err != nil {
return nil, fmt.Errorf("failed to read configuration: %v", err)
}
cfg.ChunkSize, err = cmd.Flags().GetInt(flagChunkSize)
if err != nil {
return nil, fmt.Errorf("failed to read configuration: %v", err)
}
cfg.StorageDBDSN, err = cmd.Flags().GetString(flagStorageDBDSN)
if err != nil {
return nil, fmt.Errorf("failed to read configuration: %v", err)
}
cfg.StorageTopic, err = cmd.Flags().GetString(flagStorageTopic)
if err != nil {
return nil, fmt.Errorf("failed to read configuration: %v", err)
}
}
2020-10-15 09:35:06 -07:00
if err = checkConfig(&cfg); err != nil {
return nil, err
}
2020-10-13 07:41:02 -07:00
return &cfg, nil
2020-09-07 09:06:28 -07:00
}
func genKeyPairCommand() *cobra.Command {
return &cobra.Command{
Use: "gen_keys",
Short: "generates a keypair to sign and verify messages",
2020-10-15 09:35:06 -07:00
Run: func(cmd *cobra.Command, args []string) {
2020-10-13 07:41:02 -07:00
cfg, err := loadConfig(cmd)
2020-09-07 09:06:28 -07:00
if err != nil {
2020-10-15 09:35:06 -07:00
log.Fatalf("failed to load config: %v", err)
2020-09-07 09:06:28 -07:00
}
2020-10-13 07:41:02 -07:00
2020-09-07 09:06:28 -07:00
keyPair := client.NewKeyPair()
2020-10-13 07:41:02 -07:00
keyStore, err := client.NewLevelDBKeyStore(cfg.Username, cfg.KeyStoreDBDSN)
2020-09-07 09:06:28 -07:00
if err != nil {
2020-10-15 09:35:06 -07:00
log.Fatalf("failed to init key store: %v", err)
2020-09-07 09:06:28 -07:00
}
2020-10-13 07:41:02 -07:00
if err = keyStore.PutKeys(cfg.Username, keyPair); err != nil {
2020-10-15 09:35:06 -07:00
log.Fatalf("failed to save keypair: %v", err)
2020-09-07 09:06:28 -07:00
}
2020-10-13 07:41:02 -07:00
fmt.Printf("keypair generated for user %s and saved to %s\n", cfg.Username, cfg.KeyStoreDBDSN)
2020-09-07 09:06:28 -07:00
},
}
}
func startClientCommand() *cobra.Command {
return &cobra.Command{
Use: "start",
Short: "starts dc4bc client",
2020-10-15 09:35:06 -07:00
Run: func(cmd *cobra.Command, args []string) {
2020-10-13 07:41:02 -07:00
cfg, err := loadConfig(cmd)
2020-09-07 09:06:28 -07:00
if err != nil {
2020-10-15 09:35:06 -07:00
log.Fatalf("failed to load config: %v", err)
2020-09-07 09:06:28 -07:00
}
ctx := context.Background()
ctx, cancel := context.WithCancel(ctx)
2020-10-13 07:41:02 -07:00
state, err := client.NewLevelDBState(cfg.StateDBDSN)
2020-09-07 09:06:28 -07:00
if err != nil {
log.Fatalf("Failed to init state client: %v", err)
}
2020-10-13 07:41:02 -07:00
stg, err := storage.NewKafkaStorage(ctx, cfg.StorageDBDSN, cfg.StorageTopic)
2020-09-07 09:06:28 -07:00
if err != nil {
log.Fatalf("Failed to init storage client: %v", err)
}
2020-10-13 07:41:02 -07:00
keyStore, err := client.NewLevelDBKeyStore(cfg.Username, cfg.KeyStoreDBDSN)
2020-09-07 09:06:28 -07:00
if err != nil {
log.Fatalf("Failed to init key store: %v", err)
}
processor := qr.NewCameraProcessor()
2020-10-15 09:35:06 -07:00
processor.SetDelay(cfg.FramesDelay)
2020-10-13 07:41:02 -07:00
processor.SetChunkSize(cfg.ChunkSize)
2020-09-07 09:06:28 -07:00
2020-10-13 07:41:02 -07:00
cli, err := client.NewClient(ctx, cfg.Username, state, stg, keyStore, processor)
2020-09-07 09:06:28 -07:00
if err != nil {
log.Fatalf("Failed to init client: %v", err)
}
sigs := make(chan os.Signal, 1)
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigs
log.Println("Received signal, stopping client...")
cancel()
2020-10-05 08:00:54 -07:00
log.Println("BaseClient stopped, exiting")
2020-09-07 09:06:28 -07:00
os.Exit(0)
}()
go func() {
2020-10-13 07:41:02 -07:00
if err := cli.StartHTTPServer(cfg.ListenAddress); err != nil {
2020-09-07 09:06:28 -07:00
log.Fatalf("HTTP server error: %v", err)
}
}()
cli.GetLogger().Log("starting to poll messages from append-only log...")
if err = cli.Poll(); err != nil {
log.Fatalf("error while handling operations: %v", err)
}
cli.GetLogger().Log("polling is stopped")
},
}
2020-08-04 00:45:32 -07:00
}
var rootCmd = &cobra.Command{
2020-09-08 04:48:36 -07:00
Use: "dc4bc_d",
Short: "dc4bc client daemon implementation",
2020-08-04 00:45:32 -07:00
}
func main() {
2020-09-07 09:06:28 -07:00
rootCmd.AddCommand(
startClientCommand(),
genKeyPairCommand(),
)
2020-08-04 00:45:32 -07:00
if err := rootCmd.Execute(); err != nil {
log.Fatalf("Failed to execute root command: %v", err)
}
}