Merge pull request 'Implement connstring handling' (#247) from lash/purify-more into master
Reviewed-on: #247
This commit is contained in:
		
						commit
						1f0568df32
					
				
							
								
								
									
										10
									
								
								.env.example
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								.env.example
									
									
									
									
									
								
							| @ -6,13 +6,9 @@ HOST=127.0.0.1 | ||||
| AT_ENDPOINT=/ussd/africastalking | ||||
| 
 | ||||
| #PostgreSQL | ||||
| DB_HOST=localhost | ||||
| DB_USER=postgres | ||||
| DB_PASSWORD=strongpass | ||||
| DB_NAME=urdt_ussd | ||||
| DB_PORT=5432 | ||||
| DB_SSLMODE=disable | ||||
| DB_TIMEZONE=Africa/Nairobi | ||||
| DB_CONN=postgres://postgres:strongpass@localhost:5432/urdt_ussd | ||||
| #DB_TIMEZONE=Africa/Nairobi | ||||
| #DB_SCHEMA=vise | ||||
| 
 | ||||
| #External API Calls | ||||
| CUSTODIAL_URL_BASE=http://localhost:5003 | ||||
|  | ||||
| @ -20,7 +20,6 @@ import ( | ||||
| 	"git.grassecon.net/urdt/ussd/initializers" | ||||
| 	"git.grassecon.net/urdt/ussd/internal/handlers" | ||||
| 	"git.grassecon.net/urdt/ussd/internal/http/at" | ||||
| 	httpserver "git.grassecon.net/urdt/ussd/internal/http/at" | ||||
| 	"git.grassecon.net/urdt/ussd/internal/storage" | ||||
| 	"git.grassecon.net/urdt/ussd/remote" | ||||
| 	"git.grassecon.net/urdt/ussd/internal/args" | ||||
| @ -36,21 +35,23 @@ var ( | ||||
| func init() { | ||||
| 	initializers.LoadEnvVariables() | ||||
| } | ||||
| 
 | ||||
| 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 | ||||
| 	var err error | ||||
| 	var gettextDir string | ||||
| 	var langs args.LangVar | ||||
| 	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") | ||||
| @ -59,7 +60,16 @@ func main() { | ||||
| 	flag.Var(&langs, "language", "add symbol resolution for language") | ||||
| 	flag.Parse() | ||||
| 
 | ||||
| 	logg.Infof("start command", "build", build, "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size) | ||||
| 	if connStr != "" { | ||||
| 		connStr = config.DbConn | ||||
| 	} | ||||
| 	connData, err := storage.ToConnData(connStr) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "connstr err: %v", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	logg.Infof("start command", "build", build, "conn", connData, "resourcedir", resourceDir, "outputsize", size) | ||||
| 
 | ||||
| 	ctx := context.Background() | ||||
| 	ctx = context.WithValue(ctx, "Database", database) | ||||
| @ -83,14 +93,13 @@ func main() { | ||||
| 		cfg.EngineDebug = true | ||||
| 	} | ||||
| 
 | ||||
| 	menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir) | ||||
| 	rs, err := menuStorageService.GetResource(ctx) | ||||
| 	menuStorageService := storage.NewMenuStorageService(connData, resourceDir) | ||||
| 	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) | ||||
| @ -136,7 +145,7 @@ func main() { | ||||
| 
 | ||||
| 	rp := &at.ATRequestParser{} | ||||
| 	bsh := handlers.NewBaseSessionHandler(cfg, rs, stateStore, userdataStore, rp, hl) | ||||
| 	sh := httpserver.NewATSessionHandler(bsh) | ||||
| 	sh := at.NewATSessionHandler(bsh) | ||||
| 
 | ||||
| 	mux := http.NewServeMux() | ||||
| 	mux.Handle(initializers.GetEnv("AT_ENDPOINT", "/"), sh) | ||||
|  | ||||
| @ -48,20 +48,21 @@ func (p *asyncRequestParser) GetInput(r any) ([]byte, error) { | ||||
| func main() { | ||||
| 	config.LoadConfig() | ||||
| 
 | ||||
| 	var connStr string | ||||
| 	var sessionId string | ||||
| 	var dbDir string | ||||
| 	var resourceDir string | ||||
| 	var size uint | ||||
| 	var database string | ||||
| 	var engineDebug bool | ||||
| 	var host string | ||||
| 	var port uint | ||||
| 	var err error | ||||
| 	var gettextDir string | ||||
| 	var langs args.LangVar | ||||
| 
 | ||||
| 	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") | ||||
| @ -70,7 +71,16 @@ func main() { | ||||
| 	flag.Var(&langs, "language", "add symbol resolution for language") | ||||
| 	flag.Parse() | ||||
| 
 | ||||
| 	logg.Infof("start command", "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size, "sessionId", sessionId) | ||||
| 	if connStr != "" { | ||||
| 		connStr = config.DbConn | ||||
| 	} | ||||
| 	connData, err := storage.ToConnData(connStr) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "connstr err: %v", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	logg.Infof("start command", "conn", connData, "resourcedir", resourceDir, "outputsize", size, "sessionId", sessionId) | ||||
| 
 | ||||
| 	ctx := context.Background() | ||||
| 	ctx = context.WithValue(ctx, "Database", database) | ||||
| @ -95,18 +105,18 @@ func main() { | ||||
| 		cfg.EngineDebug = true | ||||
| 	} | ||||
| 
 | ||||
| 	menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir) | ||||
| 	menuStorageService := storage.NewMenuStorageService(connData, resourceDir) | ||||
| 	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 { | ||||
|  | ||||
| @ -38,18 +38,19 @@ 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 | ||||
| 	var err error | ||||
| 	var gettextDir string | ||||
| 	var langs args.LangVar | ||||
| 	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") | ||||
| @ -58,7 +59,16 @@ func main() { | ||||
| 	flag.Var(&langs, "language", "add symbol resolution for language") | ||||
| 	flag.Parse() | ||||
| 
 | ||||
| 	logg.Infof("start command", "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size) | ||||
| 	if connStr != "" { | ||||
| 		connStr = config.DbConn | ||||
| 	} | ||||
| 	connData, err := storage.ToConnData(connStr) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "connstr err: %v", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	logg.Infof("start command", "conn", connData, "resourcedir", resourceDir, "outputsize", size) | ||||
| 
 | ||||
| 	ctx := context.Background() | ||||
| 	ctx = context.WithValue(ctx, "Database", database) | ||||
| @ -83,19 +93,14 @@ func main() { | ||||
| 		cfg.EngineDebug = true | ||||
| 	} | ||||
| 
 | ||||
| 	menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir) | ||||
| 	menuStorageService := storage.NewMenuStorageService(connData, resourceDir) | ||||
| 	 | ||||
| 	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 { | ||||
| 		fmt.Fprintf(os.Stderr, err.Error()) | ||||
|  | ||||
							
								
								
									
										30
									
								
								cmd/main.go
									
									
									
									
									
								
							
							
						
						
									
										30
									
								
								cmd/main.go
									
									
									
									
									
								
							| @ -33,23 +33,35 @@ 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 resourceDir string | ||||
| 	var err error | ||||
| 	var gettextDir string | ||||
| 	var langs args.LangVar | ||||
| 
 | ||||
| 	flag.StringVar(&resourceDir, "resourcedir", scriptDir, "resource dir") | ||||
| 	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.StringVar(&gettextDir, "gettext", "", "use gettext translations from given directory") | ||||
| 	flag.Var(&langs, "language", "add symbol resolution for language") | ||||
| 	flag.Parse() | ||||
| 
 | ||||
| 	logg.Infof("start command", "dbdir", dbDir, "outputsize", size) | ||||
| 	if connStr != "" { | ||||
| 		connStr = config.DbConn | ||||
| 	} | ||||
| 	connData, err := storage.ToConnData(connStr) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "connstr err: %v", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	logg.Infof("start command", "conn", connData, "outputsize", size) | ||||
| 
 | ||||
| 	if len(langs.Langs()) == 0 { | ||||
| 		langs.Set(config.DefaultLanguage) | ||||
| @ -76,18 +88,12 @@ func main() { | ||||
| 		MenuSeparator: menuSeparator, | ||||
| 	} | ||||
| 
 | ||||
| 	resourceDir := scriptDir | ||||
| 	menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir) | ||||
| 	menuStorageService := storage.NewMenuStorageService(connData, resourceDir) | ||||
| 	 | ||||
| 	if gettextDir != "" { | ||||
| 		menuStorageService = menuStorageService.WithGettext(gettextDir, langs.Langs()) | ||||
| 	} | ||||
| 
 | ||||
| 	err = menuStorageService.EnsureDbDir() | ||||
| 	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()) | ||||
|  | ||||
| @ -14,7 +14,10 @@ import ( | ||||
| 	"git.defalsify.org/vise.git/engine" | ||||
| 	"git.defalsify.org/vise.git/logging" | ||||
| 
 | ||||
| 	"git.grassecon.net/urdt/ussd/config" | ||||
| 	"git.grassecon.net/urdt/ussd/initializers" | ||||
| 	"git.grassecon.net/urdt/ussd/internal/ssh" | ||||
| 	"git.grassecon.net/urdt/ussd/internal/storage" | ||||
| ) | ||||
| 
 | ||||
| var ( | ||||
| @ -26,25 +29,49 @@ var ( | ||||
| 	build = "dev" | ||||
| ) | ||||
| 
 | ||||
| func init() { | ||||
| 	initializers.LoadEnvVariables() | ||||
| } | ||||
| 
 | ||||
| func main() { | ||||
| 	var dbDir string | ||||
| 	config.LoadConfig() | ||||
| 
 | ||||
| 	var connStr string | ||||
| 	var authConnStr string | ||||
| 	var resourceDir string | ||||
| 	var size uint | ||||
| 	var engineDebug bool | ||||
| 	var stateDebug bool | ||||
| 	var host string | ||||
| 	var port uint | ||||
| 	flag.StringVar(&dbDir, "dbdir", ".state", "database dir to read from") | ||||
| 	flag.StringVar(&connStr, "c", "", "connection string") | ||||
| 	flag.StringVar(&authConnStr, "authdb", "", "auth connection string") | ||||
| 	flag.StringVar(&resourceDir, "resourcedir", path.Join("services", "registration"), "resource dir") | ||||
| 	flag.BoolVar(&engineDebug, "engine-debug", false, "use engine debug output") | ||||
| 	flag.BoolVar(&stateDebug, "state-debug", false, "use engine debug output") | ||||
| 	flag.BoolVar(&engineDebug, "d", false, "use engine debug output") | ||||
| 	flag.UintVar(&size, "s", 160, "max size of output") | ||||
| 	flag.StringVar(&host, "h", "127.0.0.1", "http host") | ||||
| 	flag.UintVar(&port, "p", 7122, "http port") | ||||
| 	flag.StringVar(&host, "h", "127.0.0.1", "socket host") | ||||
| 	flag.UintVar(&port, "p", 7122, "socket port") | ||||
| 	flag.Parse() | ||||
| 
 | ||||
| 	if connStr == "" { | ||||
| 		connStr = config.DbConn | ||||
| 	} | ||||
| 	if authConnStr == "" { | ||||
| 		authConnStr = connStr | ||||
| 	} | ||||
| 	connData, err := storage.ToConnData(connStr) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "connstr err: %v", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	authConnData, err := storage.ToConnData(authConnStr) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "auth connstr err: %v", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	sshKeyFile := flag.Arg(0) | ||||
| 	_, err := os.Stat(sshKeyFile) | ||||
| 	_, err = os.Stat(sshKeyFile) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "cannot open ssh server private key file: %v\n", err) | ||||
| 		os.Exit(1) | ||||
| @ -57,7 +84,7 @@ func main() { | ||||
| 	logg.WarnCtxf(ctx, "!!!!! Do not expose to internet and only use with tunnel!") | ||||
| 	logg.WarnCtxf(ctx, "!!!!! (See ssh -L <...>)") | ||||
| 
 | ||||
| 	logg.Infof("start command", "dbdir", dbDir, "resourcedir", resourceDir, "outputsize", size, "keyfile", sshKeyFile, "host", host, "port", port) | ||||
| 	logg.Infof("start command", "conn", connData, "authconn", authConnData, "resourcedir", resourceDir, "outputsize", size, "keyfile", sshKeyFile, "host", host, "port", port) | ||||
| 
 | ||||
| 	pfp := path.Join(scriptDir, "pp.csv") | ||||
| 
 | ||||
| @ -73,7 +100,7 @@ func main() { | ||||
| 		cfg.EngineDebug = true | ||||
| 	} | ||||
| 
 | ||||
| 	authKeyStore, err := ssh.NewSshKeyStore(ctx, dbDir) | ||||
| 	authKeyStore, err := ssh.NewSshKeyStore(ctx, authConnData.String()) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "keystore file open error: %v", err) | ||||
| 		os.Exit(1) | ||||
| @ -92,10 +119,10 @@ func main() { | ||||
| 	signal.Notify(cterm, os.Interrupt, syscall.SIGTERM) | ||||
| 
 | ||||
| 	runner := &ssh.SshRunner{ | ||||
| 		Cfg:         cfg, | ||||
| 		Debug:       engineDebug, | ||||
| 		FlagFile:    pfp, | ||||
| 		DbDir:       dbDir, | ||||
| 		Cfg: cfg, | ||||
| 		Debug: engineDebug, | ||||
| 		FlagFile: pfp, | ||||
| 		Conn: connData, | ||||
| 		ResourceDir: resourceDir, | ||||
| 		SrvKeyFile:  sshKeyFile, | ||||
| 		Host:        host, | ||||
|  | ||||
| @ -23,17 +23,17 @@ 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 | ||||
| } | ||||
| 
 | ||||
| type StorageService struct { | ||||
| 	svc *storage.MenuStorageService | ||||
| } | ||||
| 
 | ||||
| func NewStorageService(dbDir string) *StorageService { | ||||
| 	return &StorageService{ | ||||
| 		svc: storage.NewMenuStorageService(dbDir, ""), | ||||
| func NewStorageService(conn storage.ConnData) (*StorageService, error) { | ||||
| 	svc := &StorageService{ | ||||
| 		svc: storage.NewMenuStorageService(conn, ""), | ||||
| 	} | ||||
| 	return svc, nil | ||||
| } | ||||
| 
 | ||||
| func(ss *StorageService) GetPersister(ctx context.Context) (*persist.Persister, error) { | ||||
| @ -47,7 +47,3 @@ func(ss *StorageService) GetUserdataDb(ctx context.Context) (db.Db, error) { | ||||
| func(ss *StorageService) GetResource(ctx context.Context) (resource.Resource, error) { | ||||
| 	return nil, errors.New("not implemented") | ||||
| } | ||||
| 
 | ||||
| func(ss *StorageService) EnsureDbDir() error { | ||||
| 	return ss.svc.EnsureDbDir() | ||||
| } | ||||
|  | ||||
| @ -40,6 +40,7 @@ var ( | ||||
| 	VoucherTransfersURL string | ||||
| 	VoucherDataURL      string | ||||
| 	CheckAliasURL       string | ||||
| 	DbConn		string | ||||
| 	DefaultLanguage	    string | ||||
| 	Languages	[]string | ||||
| ) | ||||
| @ -69,14 +70,20 @@ func setBase() error { | ||||
| 	dataURLBase = initializers.GetEnv("DATA_URL_BASE", "http://localhost:5006") | ||||
| 	BearerToken = initializers.GetEnv("BEARER_TOKEN", "") | ||||
| 
 | ||||
| 	_, err = url.JoinPath(custodialURLBase, "/foo") | ||||
| 	_, err = url.Parse(custodialURLBase) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	_, err = url.JoinPath(dataURLBase, "/bar") | ||||
| 	_, err = url.Parse(dataURLBase) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 
 | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| func setConn() error { | ||||
| 	DbConn = initializers.GetEnv("DB_CONN", "") | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| @ -86,6 +93,10 @@ func LoadConfig() error { | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	err = setConn() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	err = setLanguage() | ||||
| 	if err != nil { | ||||
| 		return err | ||||
|  | ||||
| @ -37,23 +37,34 @@ func formatItem(k []byte, v []byte) (string, error) { | ||||
| 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 = config.DbConn | ||||
| 	} | ||||
| 	connData, err := storage.ToConnData(config.DbConn) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "connstr err: %v", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	logg.Infof("start command", "conn", connData) | ||||
| 
 | ||||
| 	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(connData, resourceDir) | ||||
| 
 | ||||
| 	store, err := menuStorageService.GetUserdataDb(ctx) | ||||
| 	if err != nil { | ||||
|  | ||||
| @ -28,24 +28,35 @@ 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 = config.DbConn | ||||
| 	} | ||||
| 	connData, err := storage.ToConnData(config.DbConn) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "connstr err: %v", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	logg.Infof("start command", "conn", connData) | ||||
| 
 | ||||
| 	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(connData, resourceDir) | ||||
| 	 | ||||
| 	store, err := menuStorageService.GetUserdataDb(ctx) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, err.Error()) | ||||
|  | ||||
| @ -41,6 +41,7 @@ func NewAuther(ctx context.Context, keyStore *SshKeyStore) *auther { | ||||
| } | ||||
| 
 | ||||
| func(a *auther) Check(conn ssh.ConnMetadata, pubKey ssh.PublicKey) (*ssh.Permissions, error) { | ||||
| 	logg.TraceCtxf(a.Ctx, "looking for publickey", "pubkey", fmt.Sprintf("%x", pubKey)) | ||||
| 	va, err := a.keyStore.Get(a.Ctx, pubKey) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| @ -71,6 +72,20 @@ func(a *auther) Get(k []byte) (string, error) { | ||||
| 	return v, nil | ||||
| } | ||||
| 
 | ||||
| type SshRunner struct { | ||||
| 	Ctx context.Context | ||||
| 	Cfg engine.Config | ||||
| 	FlagFile string | ||||
| 	Conn storage.ConnData | ||||
| 	ResourceDir string | ||||
| 	Debug bool | ||||
| 	SrvKeyFile string | ||||
| 	Host string | ||||
| 	Port uint | ||||
| 	wg sync.WaitGroup | ||||
| 	lst net.Listener | ||||
| } | ||||
| 
 | ||||
| func(s *SshRunner) serve(ctx context.Context, sessionId string, ch ssh.NewChannel, en engine.Engine) error { | ||||
| 	if ch == nil { | ||||
| 		return errors.New("nil channel") | ||||
| @ -128,32 +143,13 @@ func(s *SshRunner) serve(ctx context.Context, sessionId string, ch ssh.NewChanne | ||||
| 	return nil | ||||
| } | ||||
| 
 | ||||
| type SshRunner struct { | ||||
| 	Ctx context.Context | ||||
| 	Cfg engine.Config | ||||
| 	FlagFile string | ||||
| 	DbDir string | ||||
| 	ResourceDir string | ||||
| 	Debug bool | ||||
| 	SrvKeyFile string | ||||
| 	Host string | ||||
| 	Port uint | ||||
| 	wg sync.WaitGroup | ||||
| 	lst net.Listener | ||||
| } | ||||
| 
 | ||||
| func(s *SshRunner) Stop() error { | ||||
| 	return s.lst.Close() | ||||
| } | ||||
| 
 | ||||
| func(s *SshRunner) GetEngine(sessionId string) (engine.Engine, func(), error) { | ||||
| 	ctx := s.Ctx | ||||
| 	menuStorageService := storage.NewMenuStorageService(s.DbDir, s.ResourceDir) | ||||
| 
 | ||||
| 	err := menuStorageService.EnsureDbDir() | ||||
| 	if err != nil { | ||||
| 		return nil, nil, err | ||||
| 	} | ||||
| 	menuStorageService := storage.NewMenuStorageService(s.Conn, s.ResourceDir) | ||||
| 
 | ||||
| 	rs, err := menuStorageService.GetResource(ctx) | ||||
| 	if err != nil { | ||||
| @ -208,6 +204,7 @@ func(s *SshRunner) GetEngine(sessionId string) (engine.Engine, func(), error) { | ||||
| 
 | ||||
| // adapted example from crypto/ssh package, NewServerConn doc
 | ||||
| func(s *SshRunner) Run(ctx context.Context, keyStore *SshKeyStore) { | ||||
| 	s.Ctx = ctx | ||||
| 	running := true | ||||
| 
 | ||||
| 	// TODO: waitgroup should probably not be global
 | ||||
|  | ||||
							
								
								
									
										69
									
								
								internal/storage/parse.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								internal/storage/parse.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,69 @@ | ||||
| package storage | ||||
| 
 | ||||
| import ( | ||||
| 	"fmt" | ||||
| 	"net/url" | ||||
| 	"path" | ||||
| ) | ||||
| 
 | ||||
| const ( | ||||
| 	DBTYPE_MEM = iota | ||||
| 	DBTYPE_GDBM | ||||
| 	DBTYPE_POSTGRES | ||||
| ) | ||||
| 
 | ||||
| type ConnData struct { | ||||
| 	typ int | ||||
| 	str string | ||||
| } | ||||
| 
 | ||||
| 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 | ||||
| 	} | ||||
| 	s = path.Clean(s) | ||||
| 	return s, true | ||||
| } | ||||
| 
 | ||||
| func ToConnData(connStr string) (ConnData, error) { | ||||
| 	var o ConnData | ||||
| 
 | ||||
| 	if connStr == "" { | ||||
| 		return o, nil | ||||
| 	} | ||||
| 
 | ||||
| 	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) | ||||
| } | ||||
							
								
								
									
										28
									
								
								internal/storage/parse_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								internal/storage/parse_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,28 @@ | ||||
| package storage | ||||
| 
 | ||||
| import ( | ||||
| 	"testing" | ||||
| ) | ||||
| 
 | ||||
| func TestParseConnStr(t *testing.T) { | ||||
| 	_, err := ToConnData("postgres://foo:bar@localhost:5432/baz") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err)	 | ||||
| 	} | ||||
| 	_, err = ToConnData("/foo/bar") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err)	 | ||||
| 	} | ||||
| 	_, err = ToConnData("/foo/bar/") | ||||
| 	if err != nil { | ||||
| 		t.Fatal(err)	 | ||||
| 	} | ||||
| 	_, err = ToConnData("foo/bar") | ||||
| 	if err == nil { | ||||
| 		t.Fatalf("expected error") | ||||
| 	} | ||||
| 	_, err = ToConnData("http://foo/bar") | ||||
| 	if err == nil { | ||||
| 		t.Fatalf("expected error") | ||||
| 	} | ||||
| } | ||||
| @ -13,7 +13,6 @@ import ( | ||||
| 	"git.defalsify.org/vise.git/logging" | ||||
| 	"git.defalsify.org/vise.git/persist" | ||||
| 	"git.defalsify.org/vise.git/resource" | ||||
| 	"git.grassecon.net/urdt/ussd/initializers" | ||||
| 	gdbmstorage "git.grassecon.net/urdt/ussd/internal/storage/db/gdbm" | ||||
| ) | ||||
| 
 | ||||
| @ -25,11 +24,10 @@ 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 | ||||
| } | ||||
| 
 | ||||
| type MenuStorageService struct { | ||||
| 	dbDir         string | ||||
| 	conn ConnData | ||||
| 	resourceDir   string | ||||
| 	poResource    resource.Resource | ||||
| 	resourceStore db.Db | ||||
| @ -37,29 +35,45 @@ type MenuStorageService struct { | ||||
| 	userDataStore db.Db | ||||
| } | ||||
| 
 | ||||
| func buildConnStr() string { | ||||
| 	host := initializers.GetEnv("DB_HOST", "localhost") | ||||
| 	user := initializers.GetEnv("DB_USER", "postgres") | ||||
| 	password := initializers.GetEnv("DB_PASSWORD", "") | ||||
| 	dbName := initializers.GetEnv("DB_NAME", "") | ||||
| 	port := initializers.GetEnv("DB_PORT", "5432") | ||||
| 
 | ||||
| 	connString := fmt.Sprintf( | ||||
| 		"postgres://%s:%s@%s:%s/%s", | ||||
| 		user, password, host, port, dbName, | ||||
| 	) | ||||
| 	logg.Debugf("pg conn string", "conn", connString) | ||||
| 
 | ||||
| 	return connString | ||||
| } | ||||
| 
 | ||||
| func NewMenuStorageService(dbDir string, resourceDir string) *MenuStorageService { | ||||
| func NewMenuStorageService(conn ConnData, resourceDir string) *MenuStorageService { | ||||
| 	return &MenuStorageService{ | ||||
| 		dbDir:       dbDir, | ||||
| 		conn: conn, | ||||
| 		resourceDir: resourceDir, | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| func (ms *MenuStorageService) getOrCreateDb(ctx context.Context, existingDb db.Db, section string) (db.Db, error) { | ||||
| 	var newDb db.Db | ||||
| 	var err error | ||||
| 
 | ||||
| 	if existingDb != nil { | ||||
| 		return existingDb, nil | ||||
| 	} | ||||
| 
 | ||||
| 
 | ||||
| 	connStr := ms.conn.String() | ||||
| 	dbTyp := ms.conn.DbType() | ||||
| 	if dbTyp == DBTYPE_POSTGRES { | ||||
| 		newDb = postgres.NewPgDb() | ||||
| 	} else if dbTyp == DBTYPE_GDBM { | ||||
| 		err = ms.ensureDbDir() | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		connStr = path.Join(connStr, section) | ||||
| 		newDb = gdbmstorage.NewThreadGdbmDb() | ||||
| 	} else { | ||||
| 		return nil, fmt.Errorf("unsupported connection string: '%s'\n", ms.conn.String()) | ||||
| 	} | ||||
| 	logg.DebugCtxf(ctx, "connecting to db", "conn", connStr) | ||||
| 	err = newDb.Connect(ctx, connStr) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return newDb, nil | ||||
| } | ||||
| 
 | ||||
| // WithGettext triggers use of gettext for translation of templates and menus.
 | ||||
| //
 | ||||
| // The first language in `lns` will be used as default language, to resolve node keys to 
 | ||||
| @ -82,36 +96,6 @@ func (ms *MenuStorageService) WithGettext(path string, lns []lang.Language) *Men | ||||
| 	return ms | ||||
| } | ||||
| 
 | ||||
| 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") | ||||
| 	} | ||||
| 
 | ||||
| 	if existingDb != nil { | ||||
| 		return existingDb, nil | ||||
| 	} | ||||
| 
 | ||||
| 	var newDb db.Db | ||||
| 	var err error | ||||
| 
 | ||||
| 	if database == "postgres" { | ||||
| 		newDb = postgres.NewPgDb() | ||||
| 		connStr := buildConnStr() | ||||
| 		err = newDb.Connect(ctx, connStr) | ||||
| 	} else { | ||||
| 		newDb = gdbmstorage.NewThreadGdbmDb() | ||||
| 		storeFile := path.Join(ms.dbDir, fileName) | ||||
| 		err = newDb.Connect(ctx, storeFile) | ||||
| 	} | ||||
| 
 | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 
 | ||||
| 	return newDb, nil | ||||
| } | ||||
| 
 | ||||
| func (ms *MenuStorageService) GetPersister(ctx context.Context) (*persist.Persister, error) { | ||||
| 	stateStore, err := ms.GetStateStore(ctx) | ||||
| 	if err != nil { | ||||
| @ -166,8 +150,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) | ||||
| 	} | ||||
|  | ||||
| @ -5,6 +5,7 @@ import ( | ||||
| 	"fmt" | ||||
| 	"os" | ||||
| 	"path" | ||||
| 	"path/filepath" | ||||
| 	"time" | ||||
| 
 | ||||
| 	"git.defalsify.org/vise.git/engine" | ||||
| @ -27,7 +28,6 @@ var ( | ||||
| func TestEngine(sessionId string) (engine.Engine, func(), chan bool) { | ||||
| 	ctx := context.Background() | ||||
| 	ctx = context.WithValue(ctx, "SessionId", sessionId) | ||||
| 	ctx = context.WithValue(ctx, "Database", "gdbm") | ||||
| 	pfp := path.Join(scriptDir, "pp.csv") | ||||
| 
 | ||||
| 	var eventChannel = make(chan bool) | ||||
| @ -39,37 +39,40 @@ func TestEngine(sessionId string) (engine.Engine, func(), chan bool) { | ||||
| 		FlagCount:  uint32(128), | ||||
| 	} | ||||
| 
 | ||||
| 	dbDir := ".test_state" | ||||
| 	resourceDir := scriptDir | ||||
| 	menuStorageService := storage.NewMenuStorageService(dbDir, resourceDir) | ||||
| 
 | ||||
| 	err := menuStorageService.EnsureDbDir() | ||||
| 	connStr, err := filepath.Abs(".test_state/state.gdbm") | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, err.Error()) | ||||
| 		fmt.Fprintf(os.Stderr, "connstr err: %v", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	conn, err := storage.ToConnData(connStr) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, "connstr parse err: %v", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 	resourceDir := scriptDir | ||||
| 	menuStorageService := storage.NewMenuStorageService(conn, resourceDir) | ||||
| 
 | ||||
| 	rs, err := menuStorageService.GetResource(ctx) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, err.Error()) | ||||
| 		fmt.Fprintf(os.Stderr, "resource error: %v", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	pe, err := menuStorageService.GetPersister(ctx) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, err.Error()) | ||||
| 		fmt.Fprintf(os.Stderr, "persister error: %v", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	userDataStore, err := menuStorageService.GetUserdataDb(ctx) | ||||
| 	if err != nil { | ||||
| 		fmt.Fprintf(os.Stderr, err.Error()) | ||||
| 		fmt.Fprintf(os.Stderr, "userdb error: %v", err) | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
| 	dbResource, ok := rs.(*resource.DbResource) | ||||
| 	if !ok { | ||||
| 		fmt.Fprintf(os.Stderr, err.Error()) | ||||
| 		fmt.Fprintf(os.Stderr, "dbresource cast error") | ||||
| 		os.Exit(1) | ||||
| 	} | ||||
| 
 | ||||
							
								
								
									
										15
									
								
								internal/testutil/engine_test.go
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								internal/testutil/engine_test.go
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,15 @@ | ||||
| package testutil | ||||
| 
 | ||||
| import ( | ||||
| 	"testing" | ||||
| ) | ||||
| 
 | ||||
| func TestCreateEngine(t *testing.T) { | ||||
| 	o, clean, eventC := TestEngine("foo") | ||||
| 	defer clean() | ||||
| 	defer func() { | ||||
| 		<-eventC | ||||
| 		close(eventC) | ||||
| 	}() | ||||
| 	_ = o | ||||
| } | ||||
| @ -7,6 +7,7 @@ import ( | ||||
| 	"log" | ||||
| 	"math/rand" | ||||
| 	"os" | ||||
| 	"path/filepath" | ||||
| 	"regexp" | ||||
| 	"testing" | ||||
| 
 | ||||
| @ -17,7 +18,6 @@ import ( | ||||
| 
 | ||||
| var ( | ||||
| 	testData  = driver.ReadData() | ||||
| 	testStore = ".test_state" | ||||
| 	sessionID string | ||||
| 	src       = rand.NewSource(42) | ||||
| 	g         = rand.New(src) | ||||
| @ -25,6 +25,11 @@ var ( | ||||
| 
 | ||||
| var groupTestFile = flag.String("test-file", "group_test.json", "The test file to use for running the group tests") | ||||
| 
 | ||||
| func testStore() string { | ||||
| 	v, _ :=  filepath.Abs(".test_state/state.gdbm") | ||||
| 	return v | ||||
| } | ||||
| 
 | ||||
| func GenerateSessionId() string { | ||||
| 	uu := uuid.NewGenWithOptions(uuid.WithRandomReader(g)) | ||||
| 	v, err := uu.NewV4() | ||||
| @ -81,8 +86,8 @@ func extractSendAmount(response []byte) string { | ||||
| func TestMain(m *testing.M) { | ||||
| 	sessionID = GenerateSessionId() | ||||
| 	defer func() { | ||||
| 		if err := os.RemoveAll(testStore); err != nil { | ||||
| 			log.Fatalf("Failed to delete state store %s: %v", testStore, err) | ||||
| 		if err := os.RemoveAll(testStore()); err != nil { | ||||
| 			log.Fatalf("Failed to delete state store %s: %v", testStore(), err) | ||||
| 		} | ||||
| 	}() | ||||
| 	m.Run() | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user