diff --git a/cmd/africastalking/main.go b/cmd/africastalking/main.go index 2696b51..11c6512 100644 --- a/cmd/africastalking/main.go +++ b/cmd/africastalking/main.go @@ -15,11 +15,10 @@ import ( "git.defalsify.org/vise.git/logging" "git.defalsify.org/vise.git/resource" - "git.grassecon.net/urdt/ussd/common" "git.grassecon.net/urdt/ussd/config" "git.grassecon.net/urdt/ussd/initializers" "git.grassecon.net/urdt/ussd/internal/handlers" - httpserver "git.grassecon.net/urdt/ussd/internal/http/at" + at "git.grassecon.net/urdt/ussd/internal/http/at" "git.grassecon.net/urdt/ussd/internal/storage" "git.grassecon.net/urdt/ussd/remote" ) diff --git a/cmd/async/main.go b/cmd/async/main.go index 9cd04b3..a9a0b1e 100644 --- a/cmd/async/main.go +++ b/cmd/async/main.go @@ -7,6 +7,7 @@ import ( "os" "os/signal" "path" + "path/filepath" "syscall" "git.defalsify.org/vise.git/engine" @@ -47,24 +48,33 @@ func main() { config.LoadConfig() var sessionId string - var dbDir string + var connStr string var resourceDir string var size uint var database string var engineDebug bool var host string var port uint + var err error + flag.StringVar(&sessionId, "session-id", "075xx2123", "session id") - flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from") flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir") - flag.StringVar(&database, "db", "gdbm", "database to be used") + flag.StringVar(&connStr, "c", ".", "connection string") flag.BoolVar(&engineDebug, "d", false, "use engine debug output") flag.UintVar(&size, "s", 160, "max size of output") flag.StringVar(&host, "h", initializers.GetEnv("HOST", "127.0.0.1"), "http host") flag.UintVar(&port, "p", initializers.GetEnvUint("PORT", 7123), "http port") flag.Parse() - logg.Infof("start command", "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size, "sessionId", sessionId) + if connStr == "." { + connStr, err = filepath.Abs(".state/state.gdbm") + if err != nil { + fmt.Fprintf(os.Stderr, "auto connstr generate error: %v", err) + os.Exit(1) + } + } + + logg.Infof("start command", "connstr", connStr, "resourcedir", resourceDir, "outputsize", size, "sessionId", sessionId) ctx := context.Background() ctx = context.WithValue(ctx, "Database", database) @@ -81,18 +91,19 @@ func main() { cfg.EngineDebug = true } - menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir) + menuStorageService := storage.NewMenuStorageService(resourceDir) + err = menuStorageService.SetConn(connStr) + if err != nil { + fmt.Fprintf(os.Stderr, err.Error()) + os.Exit(1) + } + rs, err := menuStorageService.GetResource(ctx) if err != nil { fmt.Fprintf(os.Stderr, err.Error()) os.Exit(1) } - err = menuStorageService.EnsureDbDir() - if err != nil { - fmt.Fprintf(os.Stderr, err.Error()) - os.Exit(1) - } userdataStore, err := menuStorageService.GetUserdataDb(ctx) if err != nil { diff --git a/cmd/http/main.go b/cmd/http/main.go index 6ddfded..dec4e64 100644 --- a/cmd/http/main.go +++ b/cmd/http/main.go @@ -8,6 +8,7 @@ import ( "os" "os/signal" "path" + "path/filepath" "strconv" "syscall" @@ -36,23 +37,31 @@ func init() { func main() { config.LoadConfig() - var dbDir string + var connStr string var resourceDir string var size uint var database string var engineDebug bool var host string var port uint - flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from") + var err error + flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir") - flag.StringVar(&database, "db", "gdbm", "database to be used") flag.BoolVar(&engineDebug, "d", false, "use engine debug output") flag.UintVar(&size, "s", 160, "max size of output") flag.StringVar(&host, "h", initializers.GetEnv("HOST", "127.0.0.1"), "http host") flag.UintVar(&port, "p", initializers.GetEnvUint("PORT", 7123), "http port") flag.Parse() - logg.Infof("start command", "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size) + if connStr == "." { + connStr, err = filepath.Abs(".state/state.gdbm") + if err != nil { + fmt.Fprintf(os.Stderr, "auto connstr generate error: %v", err) + os.Exit(1) + } + } + + logg.Infof("start command", "connstr", connStr, "resourcedir", resourceDir, "outputsize", size) ctx := context.Background() ctx = context.WithValue(ctx, "Database", database) @@ -69,14 +78,14 @@ func main() { cfg.EngineDebug = true } - menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir) - rs, err := menuStorageService.GetResource(ctx) + menuStorageService := storage.NewMenuStorageService(resourceDir) + err = menuStorageService.SetConn(connStr) if err != nil { fmt.Fprintf(os.Stderr, err.Error()) os.Exit(1) } - err = menuStorageService.EnsureDbDir() + rs, err := menuStorageService.GetResource(ctx) if err != nil { fmt.Fprintf(os.Stderr, err.Error()) os.Exit(1) diff --git a/cmd/main.go b/cmd/main.go index 4fd084f..c45615b 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "path" + "path/filepath" "git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/logging" @@ -30,19 +31,28 @@ func init() { func main() { config.LoadConfig() - var dbDir string + var connStr string var size uint var sessionId string var database string var engineDebug bool + var err error + flag.StringVar(&sessionId, "session-id", "075xx2123", "session id") - flag.StringVar(&database, "db", "gdbm", "database to be used") - flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from") + flag.StringVar(&connStr, "c", ".", "connection string") flag.BoolVar(&engineDebug, "d", false, "use engine debug output") flag.UintVar(&size, "s", 160, "max size of output") flag.Parse() - logg.Infof("start command", "dbdir", dbDir, "outputsize", size) + if connStr == "." { + connStr, err = filepath.Abs(".state/state.gdbm") + if err != nil { + fmt.Fprintf(os.Stderr, "auto connstr generate error: %v", err) + os.Exit(1) + } + } + + logg.Infof("start command", "connstr", connStr, "outputsize", size) ctx := context.Background() ctx = context.WithValue(ctx, "SessionId", sessionId) @@ -58,9 +68,9 @@ func main() { } resourceDir := scriptDir - menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir) + menuStorageService := storage.NewMenuStorageService(resourceDir) - err := menuStorageService.EnsureDbDir() + err = menuStorageService.SetConn(connStr) if err != nil { fmt.Fprintf(os.Stderr, err.Error()) os.Exit(1) diff --git a/common/storage.go b/common/storage.go index d37bce3..c8a4ff2 100644 --- a/common/storage.go +++ b/common/storage.go @@ -23,17 +23,19 @@ type StorageServices interface { GetPersister(ctx context.Context) (*persist.Persister, error) GetUserdataDb(ctx context.Context) (db.Db, error) GetResource(ctx context.Context) (resource.Resource, error) - EnsureDbDir() error + SetConn(connStr string) error } type StorageService struct { svc *storage.MenuStorageService } -func NewStorageService(dbDir string) *StorageService { - return &StorageService{ - svc: storage.NewMenuStorageService(dbDir, ""), +func NewStorageService(connStr string) (*StorageService, error) { + svc := &StorageService{ + svc: storage.NewMenuStorageService(""), } + err := svc.SetConn(connStr) + return svc, err } func(ss *StorageService) GetPersister(ctx context.Context) (*persist.Persister, error) { @@ -48,6 +50,6 @@ func(ss *StorageService) GetResource(ctx context.Context) (resource.Resource, er return nil, errors.New("not implemented") } -func(ss *StorageService) EnsureDbDir() error { - return ss.svc.EnsureDbDir() +func(ss *StorageService) SetConn(connStr string) error { + return ss.svc.SetConn(connStr) } diff --git a/devtools/gen/main.go b/devtools/gen/main.go index b9e2aed..448cc16 100644 --- a/devtools/gen/main.go +++ b/devtools/gen/main.go @@ -7,6 +7,7 @@ import ( "fmt" "os" "path" + "path/filepath" "git.defalsify.org/vise.git/logging" "git.grassecon.net/urdt/ussd/config" @@ -28,23 +29,38 @@ func init() { func main() { config.LoadConfig() - var dbDir string + var connStr string var sessionId string var database string var engineDebug bool + var err error flag.StringVar(&sessionId, "session-id", "075xx2123", "session id") - flag.StringVar(&database, "db", "gdbm", "database to be used") - flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from") + flag.StringVar(&connStr, "c", ".", "connection string") flag.BoolVar(&engineDebug, "d", false, "use engine debug output") flag.Parse() + if connStr == "." { + connStr, err = filepath.Abs(".state/state.gdbm") + if err != nil { + fmt.Fprintf(os.Stderr, "auto connstr generate error: %v", err) + os.Exit(1) + } + } + + logg.Infof("start command", "connstr", connStr) + ctx := context.Background() ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "Database", database) resourceDir := scriptDir - menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir) + menuStorageService := storage.NewMenuStorageService(resourceDir) + err = menuStorageService.SetConn(connStr) + if err != nil { + fmt.Fprintf(os.Stderr, "connection string error: %v", err) + os.Exit(1) + } store, err := menuStorageService.GetUserdataDb(ctx) if err != nil { diff --git a/devtools/store/main.go b/devtools/store/main.go index 8bd4d16..ed54ba3 100644 --- a/devtools/store/main.go +++ b/devtools/store/main.go @@ -6,6 +6,7 @@ import ( "fmt" "os" "path" + "path/filepath" "git.grassecon.net/urdt/ussd/config" "git.grassecon.net/urdt/ussd/initializers" @@ -28,23 +29,36 @@ func init() { func main() { config.LoadConfig() - var dbDir string + var connStr string var sessionId string var database string var engineDebug bool + var err error flag.StringVar(&sessionId, "session-id", "075xx2123", "session id") - flag.StringVar(&database, "db", "gdbm", "database to be used") - flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from") + flag.StringVar(&connStr, "c", ".state", "connection string") flag.BoolVar(&engineDebug, "d", false, "use engine debug output") flag.Parse() + if connStr == "." { + connStr, err = filepath.Abs(".state/state.gdbm") + if err != nil { + fmt.Fprintf(os.Stderr, "auto connstr generate error: %v", err) + os.Exit(1) + } + } + ctx := context.Background() ctx = context.WithValue(ctx, "SessionId", sessionId) ctx = context.WithValue(ctx, "Database", database) resourceDir := scriptDir - menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir) + menuStorageService := storage.NewMenuStorageService(resourceDir) + err = menuStorageService.SetConn(connStr) + if err != nil { + fmt.Fprintf(os.Stderr, "connection string error: %v", err) + os.Exit(1) + } store, err := menuStorageService.GetUserdataDb(ctx) if err != nil { diff --git a/internal/storage/parse.go b/internal/storage/parse.go index 0745a72..d4bc564 100644 --- a/internal/storage/parse.go +++ b/internal/storage/parse.go @@ -1,5 +1,11 @@ package storage +import ( + "fmt" + "net/url" + "path" +) + const ( DBTYPE_MEM = iota DBTYPE_GDBM @@ -11,11 +17,56 @@ type connData struct { str string } -func toConnData(s string) connData { +func (cd *connData) DbType() int { + return cd.typ +} + +func (cd *connData) String() string { + return cd.str +} + +func probePostgres(s string) (string, bool) { + v, err := url.Parse(s) + if err != nil { + return "", false + } + if v.Scheme != "postgres" { + return "", false + } + return s, true +} + +func probeGdbm(s string) (string, bool) { + if !path.IsAbs(s) { + return "", false + } + if path.Ext(s) != ".gdbm" { + return "", false + } + s = path.Clean(s) + return s, true +} + +func toConnData(connStr string) (connData, error) { var o connData - if s == "" { - return o + if connStr == "" { + return o, nil } - return o + + v, ok := probePostgres(connStr) + if ok { + o.typ = DBTYPE_POSTGRES + o.str = v + return o, nil + } + + v, ok = probeGdbm(connStr) + if ok { + o.typ = DBTYPE_GDBM + o.str = v + return o, nil + } + + return o, fmt.Errorf("invalid connection string: %s", connStr) } diff --git a/internal/storage/parse_test.go b/internal/storage/parse_test.go new file mode 100644 index 0000000..d4b8ecb --- /dev/null +++ b/internal/storage/parse_test.go @@ -0,0 +1,37 @@ +package storage + +import ( + "testing" +) + +func TestParseConnStr(t *testing.T) { + svc := NewMenuStorageService("") + err := svc.SetConn("postgres://foo:bar@localhost:5432/baz") + if err != nil { + t.Fatal(err) + } + err = svc.SetConn("/foo/bar/baz.gdbm") + if err != nil { + t.Fatal(err) + } + err = svc.SetConn("foo/bar/baz.gdbm") + if err == nil { + t.Fatalf("expected error") + } + err = svc.SetConn("http://foo/bar") + if err == nil { + t.Fatalf("expected error") + } + err = svc.SetConn("foo/bar/baz.txt") + if err == nil { + t.Fatalf("expected error") + } + err = svc.SetConn("/foo/bar") + if err == nil { + t.Fatalf("expected error") + } + err = svc.SetConn("foo/bar") + if err == nil { + t.Fatalf("expected error") + } +} diff --git a/internal/storage/storageservice.go b/internal/storage/storageservice.go index 04e75ce..6a42bac 100644 --- a/internal/storage/storageservice.go +++ b/internal/storage/storageservice.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "os" - "path" "git.defalsify.org/vise.git/db" fsdb "git.defalsify.org/vise.git/db/fs" @@ -24,11 +23,12 @@ type StorageService interface { GetPersister(ctx context.Context) (*persist.Persister, error) GetUserdataDb(ctx context.Context) db.Db GetResource(ctx context.Context) (resource.Resource, error) - EnsureDbDir() error + SetConn(connStr string) error } type MenuStorageService struct { - dbDir string + //dbDir string + conn connData resourceDir string resourceStore db.Db stateStore db.Db @@ -51,36 +51,47 @@ func buildConnStr() string { return connString } -func NewMenuStorageService(dbDir string, resourceDir string) *MenuStorageService { +func NewMenuStorageService(resourceDir string) *MenuStorageService { return &MenuStorageService{ - dbDir: dbDir, resourceDir: resourceDir, } } -func (ms *MenuStorageService) getOrCreateDb(ctx context.Context, existingDb db.Db, fileName string) (db.Db, error) { - database, ok := ctx.Value("Database").(string) - if !ok { - return nil, fmt.Errorf("failed to select the database") +func (ms *MenuStorageService) SetConn(connStr string) error { + o, err := toConnData(connStr) + if err != nil { + return err } + ms.conn = o + return nil +} + +func (ms *MenuStorageService) getOrCreateDb(ctx context.Context, existingDb db.Db, fileName string) (db.Db, error) { + var newDb db.Db + var err error +// database, ok := ctx.Value("Database").(string) +// if !ok { +// return nil, fmt.Errorf("failed to select the database") +// } if existingDb != nil { return existingDb, nil } - var newDb db.Db - var err error - if database == "postgres" { + dbTyp := ms.conn.DbType() + if dbTyp == DBTYPE_POSTGRES { newDb = postgres.NewPgDb() - connStr := buildConnStr() - err = newDb.Connect(ctx, connStr) - } else { + } else if dbTyp == DBTYPE_GDBM { + err = ms.ensureDbDir() + if err != nil { + return nil, err + } newDb = gdbmstorage.NewThreadGdbmDb() - storeFile := path.Join(ms.dbDir, fileName) - err = newDb.Connect(ctx, storeFile) + } else { + return nil, fmt.Errorf("unsupported connection string: %s", ms.conn.String()) } - + err = newDb.Connect(ctx, ms.conn.String()) if err != nil { return nil, err } @@ -137,8 +148,8 @@ func (ms *MenuStorageService) GetStateStore(ctx context.Context) (db.Db, error) return ms.stateStore, nil } -func (ms *MenuStorageService) EnsureDbDir() error { - err := os.MkdirAll(ms.dbDir, 0700) +func (ms *MenuStorageService) ensureDbDir() error { + err := os.MkdirAll(ms.conn.String(), 0700) if err != nil { return fmt.Errorf("state dir create exited with error: %v\n", err) } diff --git a/internal/testutil/TestEngine.go b/internal/testutil/TestEngine.go index 3fcb307..63e9e84 100644 --- a/internal/testutil/TestEngine.go +++ b/internal/testutil/TestEngine.go @@ -41,9 +41,11 @@ func TestEngine(sessionId string) (engine.Engine, func(), chan bool) { dbDir := ".test_state" resourceDir := scriptDir - menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir) + //menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir) + menuStorageService := storage.NewMenuStorageService(resourceDir) - err := menuStorageService.EnsureDbDir() + //err := menuStorageService.EnsureDbDir() + err := menuStorageService.SetConn(dbDir) if err != nil { fmt.Fprintf(os.Stderr, err.Error()) os.Exit(1)