rigged shuffle
This commit is contained in:
273
cmd/cli/main.go
Normal file
273
cmd/cli/main.go
Normal file
@@ -0,0 +1,273 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
_ "embed"
|
||||
"flag"
|
||||
"fmt"
|
||||
"go-nkode/internal/entities"
|
||||
"go-nkode/internal/models"
|
||||
"go-nkode/internal/repository"
|
||||
sqlite_queue "go-nkode/internal/sqlc"
|
||||
"go-nkode/sqlite"
|
||||
"log"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
|
||||
_ "github.com/mattn/go-sqlite3"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) < 2 {
|
||||
log.Fatal("Please provide a command: build-db")
|
||||
}
|
||||
switch os.Args[1] {
|
||||
case "build-db":
|
||||
BuildDB()
|
||||
case "create-customer":
|
||||
CreateCustomer()
|
||||
case "add-user":
|
||||
AddUser()
|
||||
default:
|
||||
log.Fatalf("Unknown command: %s", os.Args[1])
|
||||
}
|
||||
}
|
||||
|
||||
func CreateCustomer() {
|
||||
cliCmd := flag.NewFlagSet("create-customer", flag.ExitOnError)
|
||||
customerIDStr := cliCmd.String("customer-id", "", "Customer UUID")
|
||||
dbPath := cliCmd.String("db-path", "", "Path to sqlite database")
|
||||
if err := cliCmd.Parse(os.Args[2:]); err != nil {
|
||||
log.Fatalf("Failed to parse flags: %v", err)
|
||||
}
|
||||
customerID, err := models.CustomerIDFromString(*customerIDStr)
|
||||
if err != nil {
|
||||
log.Fatalf("Failed to parse flags: %v", err)
|
||||
}
|
||||
ctx := context.Background()
|
||||
sqliteDb, err := sqlite_queue.OpenSqliteDb(*dbPath)
|
||||
queue, err := sqlite_queue.NewQueue(ctx, sqliteDb)
|
||||
queue.Start()
|
||||
defer queue.Stop()
|
||||
sqliteRepo := repository.NewSqliteRepository(ctx, queue)
|
||||
if err != nil {
|
||||
log.Fatal("error starting sqlite repo: ", err)
|
||||
}
|
||||
nkodePolicy := models.NewDefaultNKodePolicy()
|
||||
customer, err := entities.NewCustomer(nkodePolicy)
|
||||
customer.ID = customerID
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
if err = sqliteRepo.CreateCustomer(*customer); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func AddUser() {
|
||||
cliCmd := flag.NewFlagSet("add-user", flag.ExitOnError)
|
||||
imgPath := cliCmd.String("img-path", "", "Path to directory with image files to add to database. The total must number must equal attrs-per-key X numb-of-keys")
|
||||
imgType := cliCmd.String("img-type", "webp", "Image types webp, svg, png, jpeg, default webp")
|
||||
customerIDStr := cliCmd.String("customer-id", "", "Customer ID")
|
||||
dbPath := cliCmd.String("db-path", "", "Path to the database")
|
||||
userEmailStr := cliCmd.String("user-email", "", "User email")
|
||||
attrsPerKey := cliCmd.Int("attrs-per-key", -1, "Attributes per key")
|
||||
numbOfKeys := cliCmd.Int("numb-of-keys", -1, "Number of keys")
|
||||
nkodeIcons := cliCmd.String("nkode-icons", "", "common separated file names of the users nKode icons with no space. filename order sets the nkode passcode order")
|
||||
if err := cliCmd.Parse(os.Args[2:]); err != nil {
|
||||
log.Fatalf("Failed to parse flags: %v", err)
|
||||
}
|
||||
fmt.Println("os args: ", os.Args)
|
||||
ctx := context.Background()
|
||||
sqliteDb, err := sqlite_queue.OpenSqliteDb(*dbPath)
|
||||
queue, err := sqlite_queue.NewQueue(ctx, sqliteDb)
|
||||
queue.Start()
|
||||
defer queue.Stop()
|
||||
sqliteRepo := repository.NewSqliteRepository(ctx, queue)
|
||||
if err != nil {
|
||||
log.Fatal("error starting sqlite repo: ", err)
|
||||
}
|
||||
customer, err := validCustomerID(*customerIDStr, &sqliteRepo)
|
||||
if err != nil {
|
||||
log.Println("db path: ", *dbPath)
|
||||
log.Fatal("invalid customer id: ", err)
|
||||
}
|
||||
validateUserEmail(*userEmailStr, customer.ID, &sqliteRepo)
|
||||
kp := entities.KeypadDimension{
|
||||
AttrsPerKey: *attrsPerKey,
|
||||
NumbOfKeys: *numbOfKeys,
|
||||
}
|
||||
if *attrsPerKey < entities.KeypadMin.AttrsPerKey || entities.KeypadMax.AttrsPerKey < *attrsPerKey {
|
||||
log.Fatalf("invalid attributes per key valid range is %d-%d", entities.KeypadMin.AttrsPerKey, entities.KeypadMax.AttrsPerKey)
|
||||
}
|
||||
if *numbOfKeys < entities.KeypadMin.NumbOfKeys || entities.KeypadMax.NumbOfKeys < *numbOfKeys {
|
||||
log.Fatalf("invalid number of keys. valid range is %d-%d", entities.KeypadMin.NumbOfKeys, entities.KeypadMax.NumbOfKeys)
|
||||
}
|
||||
if kp.IsDispersable() {
|
||||
log.Fatal("Keypad can't be dispersable")
|
||||
}
|
||||
imgs := getImgs(*imgPath, *imgType)
|
||||
if len(imgs) != kp.TotalAttrs() {
|
||||
log.Fatal("svgs in directory not equal to keypad size")
|
||||
}
|
||||
imgIDs := make([]int, len(imgs))
|
||||
for idx, img := range imgs {
|
||||
id, err := sqliteRepo.AddSVGIcon(img)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
imgIDs[idx] = int(id)
|
||||
}
|
||||
iconNames := strings.Split(*nkodeIcons, ",")
|
||||
passcodeIdxs := getPasscodeSvgIdx(iconNames, *imgPath)
|
||||
if err = customer.IsValidNKode(kp, passcodeIdxs); err != nil {
|
||||
log.Fatal("invalid nkode: ", err)
|
||||
}
|
||||
userInterface, err := entities.NewUserInterface(&kp, models.SvgIdInterface(imgIDs))
|
||||
if err != nil {
|
||||
log.Fatal("error creating user interface: ", err)
|
||||
}
|
||||
user, err := entities.NewUser(customer, *userEmailStr, passcodeIdxs, *userInterface, kp)
|
||||
if err != nil {
|
||||
log.Fatal("error creating user: ", err)
|
||||
}
|
||||
if err = sqliteRepo.WriteNewUser(*user); err != nil {
|
||||
log.Fatal("error storing user: ", err)
|
||||
}
|
||||
}
|
||||
|
||||
func getPasscodeSvgIdx(nkodeSvgFileNames []string, svgDir string) []int {
|
||||
files, err := os.ReadDir(svgDir)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
fileNames := make([]string, 0)
|
||||
for _, file := range files {
|
||||
if file.IsDir() || filepath.Ext(file.Name()) != ".svg" {
|
||||
continue
|
||||
}
|
||||
fileNames = append(fileNames, file.Name())
|
||||
}
|
||||
passcode := make([]int, 0)
|
||||
for _, fileName := range nkodeSvgFileNames {
|
||||
idx := indexOf(fileNames, fileName)
|
||||
if idx == -1 {
|
||||
log.Fatal("file does not exist in svg dir: ", fileName)
|
||||
}
|
||||
passcode = append(passcode, idx)
|
||||
}
|
||||
return passcode
|
||||
}
|
||||
|
||||
func indexOf(slice []string, value string) int {
|
||||
for i, v := range slice {
|
||||
if v == value {
|
||||
return i
|
||||
}
|
||||
}
|
||||
return -1 // not found
|
||||
}
|
||||
|
||||
func getImgs(imgDir, imgType string) []string {
|
||||
files, err := os.ReadDir(imgDir)
|
||||
if err != nil {
|
||||
log.Fatalf("error opening dir: %s with err: %v", imgDir, err)
|
||||
}
|
||||
imgs := make([]string, 0)
|
||||
for _, file := range files {
|
||||
if file.IsDir() || filepath.Ext(file.Name()) != "."+imgType {
|
||||
continue
|
||||
}
|
||||
filePath := filepath.Join(imgDir, file.Name())
|
||||
content, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
log.Println("Error reading file:", filePath, err)
|
||||
continue
|
||||
}
|
||||
imgs = append(imgs, string(content))
|
||||
}
|
||||
return imgs
|
||||
}
|
||||
|
||||
func validCustomerID(id string, repo *repository.SqliteRepository) (entities.Customer, error) {
|
||||
cID, err := models.CustomerIDFromString(id)
|
||||
if err != nil {
|
||||
return entities.Customer{}, err
|
||||
}
|
||||
customer, err := repo.GetCustomer(cID)
|
||||
if err != nil {
|
||||
return entities.Customer{}, err
|
||||
}
|
||||
return *customer, nil
|
||||
}
|
||||
|
||||
func validateUserEmail(email string, customerID models.CustomerID, repo *repository.SqliteRepository) {
|
||||
userEmail, err := models.ParseEmail(email)
|
||||
if err != nil {
|
||||
log.Fatal("user email error: ", err)
|
||||
}
|
||||
_, err = repo.GetUser(userEmail, customerID)
|
||||
if err == nil {
|
||||
log.Fatal("user already exists")
|
||||
}
|
||||
fmt.Println("user email is valid:", userEmail)
|
||||
}
|
||||
|
||||
func BuildDB() {
|
||||
sqliteSchema, err := sqlite.FS.ReadFile("schema.sql")
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
cliCmd := flag.NewFlagSet("build-db", flag.ExitOnError)
|
||||
dbPath := cliCmd.String("db-path", "", "Path to the database")
|
||||
imgPath := cliCmd.String("img-path", "", "Path to the directory with images")
|
||||
imgType := cliCmd.String("img-type", "svg", "Image types webp, svg, png, jpeg, default webp")
|
||||
if err = cliCmd.Parse(os.Args[2:]); err != nil {
|
||||
log.Fatalf("Failed to parse flags: %v", err)
|
||||
}
|
||||
if err = MakeTables(*dbPath, string(sqliteSchema)); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
ctx := context.Background()
|
||||
sqliteDb, err := sqlite_queue.OpenSqliteDb(*dbPath)
|
||||
queue, err := sqlite_queue.NewQueue(ctx, sqliteDb)
|
||||
queue.Start()
|
||||
defer queue.Stop()
|
||||
sqliteRepo := repository.NewSqliteRepository(ctx, queue)
|
||||
if err != nil {
|
||||
log.Fatal("error starting sqlite repo: ", err)
|
||||
}
|
||||
numbImgs := IconImgToSqlite(&sqliteRepo, *imgPath, *imgType)
|
||||
log.Printf("Successfully added %d Images in %s to the database at %s\n", numbImgs, *imgPath, *dbPath)
|
||||
}
|
||||
|
||||
func IconImgToSqlite(repo *repository.SqliteRepository, imgDir, imgType string) int {
|
||||
imgs := getImgs(imgDir, imgType)
|
||||
for _, img := range imgs {
|
||||
if _, err := repo.AddSVGIcon(img); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
}
|
||||
return len(imgs)
|
||||
}
|
||||
|
||||
func MakeTables(dbPath string, schema string) error {
|
||||
if _, err := os.Stat(dbPath); os.IsNotExist(err) {
|
||||
if err = os.MkdirAll(filepath.Dir(dbPath), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = os.Create(dbPath); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
db, err := sql.Open("sqlite3", dbPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if _, err = db.Exec(schema); err != nil {
|
||||
return err
|
||||
}
|
||||
return db.Close()
|
||||
}
|
||||
Reference in New Issue
Block a user