Compare commits

..

No commits in common. "master" and "lash/remove-session" have entirely different histories.

19 changed files with 234 additions and 672 deletions

View File

@ -3,44 +3,25 @@ package config
import ( import (
"strings" "strings"
"git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/visedriver/env" "git.grassecon.net/grassrootseconomics/visedriver/env"
"git.grassecon.net/grassrootseconomics/visedriver/storage"
) )
var ( var (
logg = logging.NewVanilla().WithDomain("visedriver-config") defaultLanguage = "eng"
defaultLanguage = "eng" languages []string
languages []string
DefaultLanguage string
dbConn string
dbConnMissing bool
dbConnMode storage.DbMode
stateDbConn string
stateDbConnMode storage.DbMode
resourceDbConn string
resourceDbConnMode storage.DbMode
userDbConn string
userDbConnMode storage.DbMode
Languages []string
) )
type Override struct { var (
DbConn string DbConn string
DbConnMode storage.DbMode DefaultLanguage string
StateConn string Languages []string
StateConnMode storage.DbMode )
ResourceConn string
ResourceConnMode storage.DbMode
UserConn string
UserConnMode storage.DbMode
}
func setLanguage() error { func setLanguage() error {
defaultLanguage = env.GetEnv("DEFAULT_LANGUAGE", defaultLanguage) defaultLanguage = env.GetEnv("DEFAULT_LANGUAGE", defaultLanguage)
languages = strings.Split(env.GetEnv("LANGUAGES", defaultLanguage), ",") languages = strings.Split(env.GetEnv("LANGUAGES", defaultLanguage), ",")
haveDefaultLanguage := false haveDefaultLanguage := false
for i, v := range languages { for i, v := range(languages) {
languages[i] = strings.ReplaceAll(v, " ", "") languages[i] = strings.ReplaceAll(v, " ", "")
if languages[i] == defaultLanguage { if languages[i] == defaultLanguage {
haveDefaultLanguage = true haveDefaultLanguage = true
@ -54,84 +35,13 @@ func setLanguage() error {
return nil return nil
} }
func setConn() error { func setConn() error {
dbConn = env.GetEnv("DB_CONN", "?") DbConn = env.GetEnv("DB_CONN", "")
stateDbConn = env.GetEnv("DB_CONN_STATE", dbConn)
resourceDbConn = env.GetEnv("DB_CONN_RESOURCE", dbConn)
userDbConn = env.GetEnv("DB_CONN_USER", dbConn)
return nil return nil
} }
func ApplyConn(override *Override) {
if override.DbConn != "?" {
dbConn = override.DbConn
stateDbConn = override.StateConn
resourceDbConn = override.ResourceConn
userDbConn = override.UserConn
}
dbConnMode = override.DbConnMode
if override.StateConn != "?" {
stateDbConn = override.StateConn
}
if override.ResourceConn != "?" {
resourceDbConn = override.ResourceConn
}
if override.UserConn != "?" {
userDbConn = override.UserConn
}
if dbConn == "?" {
dbConn = ""
}
if stateDbConn == "?" {
stateDbConn = dbConn
stateDbConnMode = dbConnMode
}
if resourceDbConn == "?" {
resourceDbConn = dbConn
resourceDbConnMode = dbConnMode
}
if userDbConn == "?" {
userDbConn = dbConn
userDbConnMode = dbConnMode
}
logg.Debugf("conns", "conn", dbConn, "user", userDbConn)
if override.DbConnMode != storage.DBMODE_ANY {
dbConnMode = override.DbConnMode
}
if override.StateConnMode != storage.DBMODE_ANY {
stateDbConnMode = override.StateConnMode
}
if override.ResourceConnMode != storage.DBMODE_ANY {
resourceDbConnMode = override.ResourceConnMode
}
if override.UserConnMode != storage.DBMODE_ANY {
userDbConnMode = override.UserConnMode
}
}
func GetConns() (storage.Conns, error) {
o := storage.NewConns()
c, err := storage.ToConnDataMode(stateDbConn, stateDbConnMode)
if err != nil {
return o, err
}
o.Set(c, storage.STORETYPE_STATE)
c, err = storage.ToConnDataMode(resourceDbConn, resourceDbConnMode)
if err != nil {
return o, err
}
o.Set(c, storage.STORETYPE_RESOURCE)
c, err = storage.ToConnDataMode(userDbConn, userDbConnMode)
if err != nil {
return o, err
}
o.Set(c, storage.STORETYPE_USER)
return o, nil
}
// LoadConfig initializes the configuration values after environment variables are loaded. // LoadConfig initializes the configuration values after environment variables are loaded.
func LoadConfig() error { func LoadConfig() error {
err := setConn() err := setConn()

View File

@ -2,9 +2,8 @@ package entry
import ( import (
"context" "context"
"git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/persist"
) )
type EntryHandler interface { type EntryHandler interface {

18
go.mod
View File

@ -3,25 +3,37 @@ module git.grassecon.net/grassrootseconomics/visedriver
go 1.23.0 go 1.23.0
require ( require (
git.defalsify.org/vise.git v0.2.3-0.20250120121301-10739fb4a8c9 git.defalsify.org/vise.git v0.2.3-0.20250103172917-3e190a44568d
github.com/alecthomas/assert/v2 v2.2.2
github.com/gofrs/uuid v4.4.0+incompatible
github.com/grassrootseconomics/eth-custodial v1.3.0-beta
github.com/grassrootseconomics/ussd-data-service v1.2.0-beta
github.com/jackc/pgx/v5 v5.7.1 github.com/jackc/pgx/v5 v5.7.1
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
github.com/peteole/testdata-loader v0.3.0
github.com/stretchr/testify v1.9.0
golang.org/x/crypto v0.27.0
) )
require ( require (
github.com/alecthomas/repr v0.2.0 // indirect
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c // indirect github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c // indirect
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect
github.com/fxamacker/cbor/v2 v2.4.0 // indirect github.com/fxamacker/cbor/v2 v2.4.0 // indirect
github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 // indirect github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 // indirect
github.com/hexops/gotextdiff v1.0.3 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect
github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jackc/puddle/v2 v2.2.2 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a // indirect github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a // indirect
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
github.com/stretchr/testify v1.9.0 // indirect github.com/rogpeppe/go-internal v1.13.1 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/x448/float16 v0.8.4 // indirect github.com/x448/float16 v0.8.4 // indirect
golang.org/x/crypto v0.27.0 // indirect
golang.org/x/sync v0.8.0 // indirect golang.org/x/sync v0.8.0 // indirect
golang.org/x/sys v0.25.0 // indirect
golang.org/x/text v0.18.0 // indirect golang.org/x/text v0.18.0 // indirect
gopkg.in/leonelquinteros/gotext.v1 v1.3.1 // indirect gopkg.in/leonelquinteros/gotext.v1 v1.3.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
) )

31
go.sum
View File

@ -1,14 +1,27 @@
git.defalsify.org/vise.git v0.2.3-0.20250120121301-10739fb4a8c9 h1:sPcqXQcywxA8W3W+9qQncLPmsrgqTIlec7vmD4/7vyA= git.defalsify.org/vise.git v0.2.3-0.20250103172917-3e190a44568d h1:bPAOVZOX4frSGhfOdcj7kc555f8dc9DmMd2YAyC2AMw=
git.defalsify.org/vise.git v0.2.3-0.20250120121301-10739fb4a8c9/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck= git.defalsify.org/vise.git v0.2.3-0.20250103172917-3e190a44568d/go.mod h1:jyBMe1qTYUz3mmuoC9JQ/TvFeW0vTanCUcPu3H8p4Ck=
github.com/alecthomas/assert/v2 v2.2.2 h1:Z/iVC0xZfWTaFNE6bA3z07T86hd45Xe2eLt6WVy2bbk=
github.com/alecthomas/assert/v2 v2.2.2/go.mod h1:pXcQ2Asjp247dahGEmsZ6ru0UVwnkhktn7S0bBDLxvQ=
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c h1:H9Nm+I7Cg/YVPpEV1RzU3Wq2pjamPc/UtHDgItcb7lE= github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c h1:H9Nm+I7Cg/YVPpEV1RzU3Wq2pjamPc/UtHDgItcb7lE=
github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c/go.mod h1:rGod7o6KPeJ+hyBpHfhi4v7blx9sf+QsHsA7KAsdN6U= github.com/barbashov/iso639-3 v0.0.0-20211020172741-1f4ffb2d8d1c/go.mod h1:rGod7o6KPeJ+hyBpHfhi4v7blx9sf+QsHsA7KAsdN6U=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM=
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88= github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD88=
github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA=
github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/grassrootseconomics/eth-custodial v1.3.0-beta h1:twrMBhl89GqDUL9PlkzQxMP/6OST1BByrNDj+rqXDmU=
github.com/grassrootseconomics/eth-custodial v1.3.0-beta/go.mod h1:7uhRcdnJplX4t6GKCEFkbeDhhjlcaGJeJqevbcvGLZo=
github.com/grassrootseconomics/ussd-data-service v1.2.0-beta h1:fn1gwbWIwHVEBtUC2zi5OqTlfI/5gU1SMk0fgGixIXk=
github.com/grassrootseconomics/ussd-data-service v1.2.0-beta/go.mod h1:omfI0QtUwIdpu9gMcUqLMCG8O1XWjqJGBx1qUMiGWC0=
github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 h1:U4kkNYryi/qfbBF8gh7Vsbuz+cVmhf5kt6pE9bYYyLo= github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4 h1:U4kkNYryi/qfbBF8gh7Vsbuz+cVmhf5kt6pE9bYYyLo=
github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4/go.mod h1:zpZDgZFzeq9s0MIeB1P50NIEWDFFHSFBohI/NbaTD/Y= github.com/graygnuorg/go-gdbm v0.0.0-20220711140707-71387d66dce4/go.mod h1:zpZDgZFzeq9s0MIeB1P50NIEWDFFHSFBohI/NbaTD/Y=
github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM=
github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo=
@ -19,6 +32,10 @@ github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo
github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a h1:0Q3H0YXzMHiciXtRcM+j0jiCe8WKPQHoRgQiRTnfcLY= github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a h1:0Q3H0YXzMHiciXtRcM+j0jiCe8WKPQHoRgQiRTnfcLY=
github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a/go.mod h1:CdTTBOYzS5E4mWS1N8NWP6AHI19MP0A2B18n3hLzRMk= github.com/mattn/kinako v0.0.0-20170717041458-332c0a7e205a/go.mod h1:CdTTBOYzS5E4mWS1N8NWP6AHI19MP0A2B18n3hLzRMk=
github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNLeHCb/s= github.com/pashagolub/pgxmock/v4 v4.3.0 h1:DqT7fk0OCK6H0GvqtcMsLpv8cIwWqdxWgfZNLeHCb/s=
@ -28,7 +45,11 @@ github.com/peteole/testdata-loader v0.3.0/go.mod h1:Mt0ZbRtb56u8SLJpNP+BnQbENljM
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U=
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
@ -39,9 +60,15 @@ golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM=
golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8=
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224= golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/leonelquinteros/gotext.v1 v1.3.1 h1:8d9/fdTG0kn/B7NNGV1BsEyvektXFAbkMsTZS2sFSCc= gopkg.in/leonelquinteros/gotext.v1 v1.3.1 h1:8d9/fdTG0kn/B7NNGV1BsEyvektXFAbkMsTZS2sFSCc=
gopkg.in/leonelquinteros/gotext.v1 v1.3.1/go.mod h1:X1WlGDeAFIYsW6GjgMm4VwUwZ2XjI7Zan2InxSUQWrU= gopkg.in/leonelquinteros/gotext.v1 v1.3.1/go.mod h1:X1WlGDeAFIYsW6GjgMm4VwUwZ2XjI7Zan2InxSUQWrU=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -1,26 +1,24 @@
package request package request
import ( import (
"context"
"git.defalsify.org/vise.git/db" "git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/visedriver/entry"
"git.grassecon.net/grassrootseconomics/visedriver/errors"
"git.grassecon.net/grassrootseconomics/visedriver/storage" "git.grassecon.net/grassrootseconomics/visedriver/storage"
"git.grassecon.net/grassrootseconomics/visedriver/errors"
"git.grassecon.net/grassrootseconomics/visedriver/entry"
) )
type BaseRequestHandler struct { type BaseRequestHandler struct {
cfgTemplate engine.Config cfgTemplate engine.Config
rp RequestParser rp RequestParser
rs resource.Resource rs resource.Resource
hn entry.EntryHandler hn entry.EntryHandler
provider storage.StorageProvider provider storage.StorageProvider
} }
// func NewBaseRequestHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp request.RequestParser, hn *handlers.Handlers) *BaseRequestHandler { //func NewBaseRequestHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp request.RequestParser, hn *handlers.Handlers) *BaseRequestHandler {
func NewBaseRequestHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp RequestParser, hn entry.EntryHandler) *BaseRequestHandler { func NewBaseRequestHandler(cfg engine.Config, rs resource.Resource, stateDb db.Db, userdataDb db.Db, rp RequestParser, hn entry.EntryHandler) *BaseRequestHandler {
return &BaseRequestHandler{ return &BaseRequestHandler{
cfgTemplate: cfg, cfgTemplate: cfg,
@ -31,8 +29,8 @@ func NewBaseRequestHandler(cfg engine.Config, rs resource.Resource, stateDb db.D
} }
} }
func (f *BaseRequestHandler) Shutdown(ctx context.Context) { func (f *BaseRequestHandler) Shutdown() {
err := f.provider.Close(ctx) err := f.provider.Close()
if err != nil { if err != nil {
logg.Errorf("handler shutdown error", "err", err) logg.Errorf("handler shutdown error", "err", err)
} }
@ -44,14 +42,14 @@ func (f *BaseRequestHandler) GetEngine(cfg engine.Config, rs resource.Resource,
return en return en
} }
func (f *BaseRequestHandler) Process(rqs RequestSession) (RequestSession, error) { func(f *BaseRequestHandler) Process(rqs RequestSession) (RequestSession, error) {
var r bool var r bool
var err error var err error
var ok bool var ok bool
logg.InfoCtxf(rqs.Ctx, "new request", "data", rqs) logg.InfoCtxf(rqs.Ctx, "new request", "data", rqs)
rqs.Storage, err = f.provider.Get(rqs.Ctx, rqs.Config.SessionId) rqs.Storage, err = f.provider.Get(rqs.Config.SessionId)
if err != nil { if err != nil {
logg.ErrorCtxf(rqs.Ctx, "", "storage get error", err) logg.ErrorCtxf(rqs.Ctx, "", "storage get error", err)
return rqs, errors.ErrStorage return rqs, errors.ErrStorage
@ -65,7 +63,7 @@ func (f *BaseRequestHandler) Process(rqs RequestSession) (RequestSession, error)
eni := f.GetEngine(rqs.Config, f.rs, rqs.Storage.Persister) eni := f.GetEngine(rqs.Config, f.rs, rqs.Storage.Persister)
en, ok := eni.(*engine.DefaultEngine) en, ok := eni.(*engine.DefaultEngine)
if !ok { if !ok {
perr := f.provider.Put(rqs.Ctx, rqs.Config.SessionId, rqs.Storage) perr := f.provider.Put(rqs.Config.SessionId, rqs.Storage)
rqs.Storage = nil rqs.Storage = nil
if perr != nil { if perr != nil {
logg.ErrorCtxf(rqs.Ctx, "", "storage put error", perr) logg.ErrorCtxf(rqs.Ctx, "", "storage put error", perr)
@ -80,7 +78,7 @@ func (f *BaseRequestHandler) Process(rqs RequestSession) (RequestSession, error)
r, err = rqs.Engine.Exec(rqs.Ctx, rqs.Input) r, err = rqs.Engine.Exec(rqs.Ctx, rqs.Input)
if err != nil { if err != nil {
perr := f.provider.Put(rqs.Ctx, rqs.Config.SessionId, rqs.Storage) perr := f.provider.Put(rqs.Config.SessionId, rqs.Storage)
rqs.Storage = nil rqs.Storage = nil
if perr != nil { if perr != nil {
logg.ErrorCtxf(rqs.Ctx, "", "storage put error", perr) logg.ErrorCtxf(rqs.Ctx, "", "storage put error", perr)
@ -92,21 +90,21 @@ func (f *BaseRequestHandler) Process(rqs RequestSession) (RequestSession, error)
return rqs, nil return rqs, nil
} }
func (f *BaseRequestHandler) Output(rqs RequestSession) (RequestSession, error) { func(f *BaseRequestHandler) Output(rqs RequestSession) (RequestSession, error) {
var err error var err error
_, err = rqs.Engine.Flush(rqs.Ctx, rqs.Writer) _, err = rqs.Engine.Flush(rqs.Ctx, rqs.Writer)
return rqs, err return rqs, err
} }
func (f *BaseRequestHandler) Reset(ctx context.Context, rqs RequestSession) (RequestSession, error) { func(f *BaseRequestHandler) Reset(rqs RequestSession) (RequestSession, error) {
defer f.provider.Put(ctx, rqs.Config.SessionId, rqs.Storage) defer f.provider.Put(rqs.Config.SessionId, rqs.Storage)
return rqs, rqs.Engine.Finish(ctx) return rqs, rqs.Engine.Finish()
} }
func (f *BaseRequestHandler) GetConfig() engine.Config { func (f *BaseRequestHandler) GetConfig() engine.Config {
return f.cfgTemplate return f.cfgTemplate
} }
func (f *BaseRequestHandler) GetRequestParser() RequestParser { func(f *BaseRequestHandler) GetRequestParser() RequestParser {
return f.rp return f.rp
} }

View File

@ -5,8 +5,8 @@ import (
"strconv" "strconv"
"git.defalsify.org/vise.git/logging" "git.defalsify.org/vise.git/logging"
"git.grassecon.net/grassrootseconomics/visedriver/errors"
"git.grassecon.net/grassrootseconomics/visedriver/request" "git.grassecon.net/grassrootseconomics/visedriver/request"
"git.grassecon.net/grassrootseconomics/visedriver/errors"
) )
var ( var (
@ -80,7 +80,7 @@ func (hh *HTTPRequestHandler) ServeHTTP(w http.ResponseWriter, req *http.Request
w.WriteHeader(200) w.WriteHeader(200)
w.Header().Set("Content-Type", "text/plain") w.Header().Set("Content-Type", "text/plain")
rqs, err = hh.Output(rqs) rqs, err = hh.Output(rqs)
rqs, perr = hh.Reset(rqs.Ctx, rqs) rqs, perr = hh.Reset(rqs)
if err != nil { if err != nil {
hh.WriteError(w, 500, err) hh.WriteError(w, 500, err)
return return

View File

@ -10,8 +10,8 @@ import (
"git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/engine"
viseerrors "git.grassecon.net/grassrootseconomics/visedriver/errors" viseerrors "git.grassecon.net/grassrootseconomics/visedriver/errors"
"git.grassecon.net/grassrootseconomics/visedriver/request"
"git.grassecon.net/grassrootseconomics/visedriver/testutil/mocks/httpmocks" "git.grassecon.net/grassrootseconomics/visedriver/testutil/mocks/httpmocks"
"git.grassecon.net/grassrootseconomics/visedriver/request"
) )
// invalidRequestType is a custom type to test invalid request scenarios // invalidRequestType is a custom type to test invalid request scenarios
@ -88,7 +88,7 @@ func TestRequestHandler_ServeHTTP(t *testing.T) {
OutputFunc: func(rs request.RequestSession) (request.RequestSession, error) { OutputFunc: func(rs request.RequestSession) (request.RequestSession, error) {
return rs, tt.outputErr return rs, tt.outputErr
}, },
ResetFunc: func(ctx context.Context, rs request.RequestSession) (request.RequestSession, error) { ResetFunc: func(rs request.RequestSession) (request.RequestSession, error) {
return rs, tt.resetErr return rs, tt.resetErr
}, },
GetRequestParserFunc: func() request.RequestParser { GetRequestParserFunc: func() request.RequestParser {
@ -165,7 +165,7 @@ func TestDefaultRequestParser_GetSessionId(t *testing.T) {
for _, tt := range tests { for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) { t.Run(tt.name, func(t *testing.T) {
id, err := parser.GetSessionId(context.Background(), tt.request) id, err := parser.GetSessionId(context.Background(),tt.request)
if id != tt.expectedID { if id != tt.expectedID {
t.Errorf("Expected session ID %s, got %s", tt.expectedID, id) t.Errorf("Expected session ID %s, got %s", tt.expectedID, id)

View File

@ -4,10 +4,10 @@ import (
"context" "context"
"io" "io"
"git.defalsify.org/vise.git/resource"
"git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/logging" "git.defalsify.org/vise.git/logging"
"git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource"
"git.grassecon.net/grassrootseconomics/visedriver/storage" "git.grassecon.net/grassrootseconomics/visedriver/storage"
) )
@ -16,27 +16,27 @@ var (
) )
type RequestSession struct { type RequestSession struct {
Ctx context.Context Ctx context.Context
Config engine.Config Config engine.Config
Engine engine.Engine Engine engine.Engine
Input []byte Input []byte
Storage *storage.Storage Storage *storage.Storage
Writer io.Writer Writer io.Writer
Continue bool Continue bool
} }
// TODO: seems like can remove this. // TODO: seems like can remove this.
type RequestParser interface { type RequestParser interface {
GetSessionId(context.Context, any) (string, error) GetSessionId(ctx context.Context, rq any) (string, error)
GetInput(any) ([]byte, error) GetInput(rq any) ([]byte, error)
} }
type RequestHandler interface { type RequestHandler interface {
GetConfig() engine.Config GetConfig() engine.Config
GetRequestParser() RequestParser GetRequestParser() RequestParser
GetEngine(engine.Config, resource.Resource, *persist.Persister) engine.Engine GetEngine(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine
Process(RequestSession) (RequestSession, error) Process(rs RequestSession) (RequestSession, error)
Output(RequestSession) (RequestSession, error) Output(rs RequestSession) (RequestSession, error)
Reset(context.Context, RequestSession) (RequestSession, error) Reset(rs RequestSession) (RequestSession, error)
Shutdown(ctx context.Context) Shutdown()
} }

View File

@ -1,98 +0,0 @@
package storage
import (
"fmt"
"net/url"
)
type DbMode uint8
const (
DBTYPE_NONE = iota
DBTYPE_MEM
DBTYPE_FS
DBTYPE_GDBM
DBTYPE_POSTGRES
)
const (
DBMODE_ANY DbMode = iota
DBMODE_BINARY
DBMODE_TEXT
)
const (
STORETYPE_STATE = iota
STORETYPE_RESOURCE
STORETYPE_USER
_STORETYPE_MAX
)
var (
DbModeDebug = []string{"ANY", "BIN", "TXT"}
DbTypeDebug = []string{"NONE", "MEM", "FS", "GDBM", "POSTGRES"}
DbStoreDebug = []string{"STATE", "RESOURCE", "USER"}
)
type Conns map[int8]ConnData
func NewConns() Conns {
c := make(Conns)
return c
}
func (c Conns) Set(conn ConnData, typ int8) {
if typ < 0 || typ >= _STORETYPE_MAX {
panic(fmt.Errorf("invalid store type: %d", typ))
}
c[typ] = conn
}
func (c Conns) Have(conn *ConnData) int8 {
for i := range _STORETYPE_MAX {
ii := int8(i)
v, ok := c[ii]
if !ok {
continue
}
if v.Raw() == conn.Raw() {
if v.Mode() == DBMODE_ANY || v.Mode() == conn.Mode() {
return ii
}
}
}
return -1
}
type ConnData struct {
typ int
str string
domain string
mode DbMode
}
func (cd *ConnData) DbType() int {
return cd.typ
}
func (cd ConnData) String() string {
return fmt.Sprintf("conn: %s, mod %s, typ %s", cd.str, DbModeDebug[uint8(cd.mode)], DbTypeDebug[uint8(cd.typ)])
}
func (cd *ConnData) Domain() string {
return cd.domain
}
func (cd *ConnData) Mode() DbMode {
return cd.mode
}
func (cd *ConnData) Path() string {
v, _ := url.Parse(cd.str)
v.RawQuery = ""
return v.String()
}
func (cd *ConnData) Raw() string {
return cd.str
}

View File

@ -18,7 +18,7 @@ var (
) )
type ThreadGdbmDb struct { type ThreadGdbmDb struct {
db db.Db db db.Db
connStr string connStr string
} }
@ -29,7 +29,7 @@ func NewThreadGdbmDb() *ThreadGdbmDb {
return &ThreadGdbmDb{} return &ThreadGdbmDb{}
} }
func (tdb *ThreadGdbmDb) Connect(ctx context.Context, connStr string) error { func(tdb *ThreadGdbmDb) Connect(ctx context.Context, connStr string) error {
var ok bool var ok bool
_, ok = dbC[connStr] _, ok = dbC[connStr]
if ok { if ok {
@ -42,18 +42,18 @@ func (tdb *ThreadGdbmDb) Connect(ctx context.Context, connStr string) error {
return err return err
} }
dbC[connStr] = make(chan db.Db, 1) dbC[connStr] = make(chan db.Db, 1)
dbC[connStr] <- gdb dbC[connStr]<- gdb
tdb.connStr = connStr tdb.connStr = connStr
return nil return nil
} }
func (tdb *ThreadGdbmDb) reserve() { func(tdb *ThreadGdbmDb) reserve() {
if tdb.db == nil { if tdb.db == nil {
tdb.db = <-dbC[tdb.connStr] tdb.db = <-dbC[tdb.connStr]
} }
} }
func (tdb *ThreadGdbmDb) release() { func(tdb *ThreadGdbmDb) release() {
if tdb.db == nil { if tdb.db == nil {
return return
} }
@ -61,87 +61,67 @@ func (tdb *ThreadGdbmDb) release() {
tdb.db = nil tdb.db = nil
} }
func (tdb *ThreadGdbmDb) SetPrefix(pfx uint8) { func(tdb *ThreadGdbmDb) SetPrefix(pfx uint8) {
tdb.reserve() tdb.reserve()
tdb.db.SetPrefix(pfx) tdb.db.SetPrefix(pfx)
} }
func (tdb *ThreadGdbmDb) SetSession(sessionId string) { func(tdb *ThreadGdbmDb) SetSession(sessionId string) {
tdb.reserve() tdb.reserve()
tdb.db.SetSession(sessionId) tdb.db.SetSession(sessionId)
} }
func (tdb *ThreadGdbmDb) SetLanguage(lng *lang.Language) { func(tdb *ThreadGdbmDb) SetLanguage(lng *lang.Language) {
tdb.reserve() tdb.reserve()
tdb.db.SetLanguage(lng) tdb.db.SetLanguage(lng)
} }
func (tdb *ThreadGdbmDb) Safe() bool { func(tdb *ThreadGdbmDb) Safe() bool {
tdb.reserve() tdb.reserve()
v := tdb.db.Safe() v := tdb.db.Safe()
tdb.release() tdb.release()
return v return v
} }
func (tdb *ThreadGdbmDb) Prefix() uint8 { func(tdb *ThreadGdbmDb) Prefix() uint8 {
tdb.reserve() tdb.reserve()
v := tdb.db.Prefix() v := tdb.db.Prefix()
tdb.release() tdb.release()
return v return v
} }
func (tdb *ThreadGdbmDb) SetLock(typ uint8, locked bool) error { func(tdb *ThreadGdbmDb) SetLock(typ uint8, locked bool) error {
tdb.reserve() tdb.reserve()
err := tdb.db.SetLock(typ, locked) err := tdb.db.SetLock(typ, locked)
tdb.release() tdb.release()
return err return err
} }
func (tdb *ThreadGdbmDb) Put(ctx context.Context, key []byte, val []byte) error { func(tdb *ThreadGdbmDb) Put(ctx context.Context, key []byte, val []byte) error {
tdb.reserve() tdb.reserve()
err := tdb.db.Put(ctx, key, val) err := tdb.db.Put(ctx, key, val)
tdb.release() tdb.release()
return err return err
} }
func (tdb *ThreadGdbmDb) Get(ctx context.Context, key []byte) ([]byte, error) { func(tdb *ThreadGdbmDb) Get(ctx context.Context, key []byte) ([]byte, error) {
tdb.reserve() tdb.reserve()
v, err := tdb.db.Get(ctx, key) v, err := tdb.db.Get(ctx, key)
tdb.release() tdb.release()
return v, err return v, err
} }
func (tdb *ThreadGdbmDb) Close(ctx context.Context) error { func(tdb *ThreadGdbmDb) Close() error {
tdb.reserve() tdb.reserve()
close(dbC[tdb.connStr]) close(dbC[tdb.connStr])
delete(dbC, tdb.connStr) delete(dbC, tdb.connStr)
err := tdb.db.Close(ctx) err := tdb.db.Close()
tdb.db = nil tdb.db = nil
return err return err
} }
func (tdb *ThreadGdbmDb) Dump(ctx context.Context, key []byte) (*db.Dumper, error) { func(tdb *ThreadGdbmDb) Dump(ctx context.Context, key []byte) (*db.Dumper, error) {
tdb.reserve() tdb.reserve()
defer tdb.release() defer tdb.release()
return tdb.db.Dump(ctx, key) return tdb.db.Dump(ctx, key)
} }
func (tdb *ThreadGdbmDb) DecodeKey(ctx context.Context, key []byte) ([]byte, error) {
return tdb.db.DecodeKey(ctx, key)
}
func (tdb *ThreadGdbmDb) Abort(ctx context.Context) {
tdb.db.Abort(ctx)
}
func (tdb *ThreadGdbmDb) Start(ctx context.Context) error {
return tdb.db.Start(ctx)
}
func (tdb *ThreadGdbmDb) Stop(ctx context.Context) error {
return tdb.db.Stop(ctx)
}
func (tdb *ThreadGdbmDb) Connection() string {
return tdb.db.Connection()
}

View File

@ -4,9 +4,38 @@ import (
"fmt" "fmt"
"net/url" "net/url"
"path" "path"
"path/filepath"
) )
const (
DBTYPE_MEM = iota
DBTYPE_GDBM
DBTYPE_POSTGRES
)
type ConnData struct {
typ int
str string
domain string
}
func (cd *ConnData) DbType() int {
return cd.typ
}
func (cd *ConnData) String() string {
return cd.str
}
func (cd *ConnData) Domain() string {
return cd.domain
}
func (cd *ConnData) Path() string {
v, _ := url.Parse(cd.str)
v.RawQuery = ""
return v.String()
}
func probePostgres(s string) (string, string, bool) { func probePostgres(s string) (string, string, bool) {
domain := "public" domain := "public"
v, err := url.Parse(s) v, err := url.Parse(s)
@ -24,62 +53,21 @@ func probePostgres(s string) (string, string, bool) {
} }
func probeGdbm(s string) (string, string, bool) { func probeGdbm(s string) (string, string, bool) {
domain := "public"
v, err := url.Parse(s)
if err != nil {
return "", "", false
}
if v.Scheme != "gdbm" {
return "", "", false
}
s = v.Path
return s, domain, true
}
func probeFs(s string) (string, string, bool) {
var err error
v, _ := url.Parse(s)
if v.Scheme != "" && v.Scheme != "file://" {
return "", "", false
}
if !path.IsAbs(s) { if !path.IsAbs(s) {
s, err = filepath.Abs(s) return "", "", false
if err != nil {
panic(err)
}
} }
s = path.Clean(s) s = path.Clean(s)
return s, "", true return s, "", true
} }
func probeMem(s string) (string, string, bool) {
if s != "" {
return "", "", false
}
return "", "", true
}
func ToConnDataMode(connStr string, mode DbMode) (ConnData, error) {
o, err := ToConnData(connStr)
if err != nil {
return o, err
}
o.mode = mode
return o, nil
}
func ToConnData(connStr string) (ConnData, error) { func ToConnData(connStr string) (ConnData, error) {
var o ConnData var o ConnData
v, domain, ok := probeMem(connStr) if connStr == "" {
if ok {
o.typ = DBTYPE_MEM
return o, nil return o, nil
} }
v, domain, ok = probePostgres(connStr) v, domain, ok := probePostgres(connStr)
if ok { if ok {
o.typ = DBTYPE_POSTGRES o.typ = DBTYPE_POSTGRES
o.str = v o.str = v
@ -94,12 +82,5 @@ func ToConnData(connStr string) (ConnData, error) {
return o, nil return o, nil
} }
v, _, ok = probeFs(connStr)
if ok {
o.typ = DBTYPE_FS
o.str = v
return o, nil
}
return o, fmt.Errorf("invalid connection string: %s", connStr) return o, fmt.Errorf("invalid connection string: %s", connStr)
} }

View File

@ -5,53 +5,24 @@ import (
) )
func TestParseConnStr(t *testing.T) { func TestParseConnStr(t *testing.T) {
v, err := ToConnData("postgres://foo:bar@localhost:5432/baz") _, err := ToConnData("postgres://foo:bar@localhost:5432/baz")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if v.DbType() != DBTYPE_POSTGRES { _, err = ToConnData("/foo/bar")
t.Fatalf("expected type %v, got %v", DBTYPE_POSTGRES, v.DbType())
}
v, err = ToConnData("gdbm:///foo/bar")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if v.DbType() != DBTYPE_GDBM { _, err = ToConnData("/foo/bar/")
t.Fatalf("expected type %v, got %v", DBTYPE_GDBM, v.DbType())
}
v, err = ToConnData("/foo/bar")
if err != nil { if err != nil {
t.Fatal(err) t.Fatal(err)
} }
if v.DbType() != DBTYPE_FS { _, err = ToConnData("foo/bar")
t.Fatalf("expected type %v, got %v", DBTYPE_FS, v.DbType())
}
v, err = ToConnData("/foo/bar/")
if err != nil {
t.Fatal(err)
}
if v.DbType() != DBTYPE_FS {
t.Fatalf("expected type %v, got %v", DBTYPE_FS, v.DbType())
}
v, err = ToConnData("foo/bar")
if err != nil {
t.Fatal(err)
}
if v.DbType() != DBTYPE_FS {
t.Fatalf("expected type %v, got %v", DBTYPE_FS, v.DbType())
}
v, err = ToConnData("")
if err != nil {
t.Fatal(err)
}
if v.DbType() != DBTYPE_MEM {
t.Fatalf("expected type %v, got %v", DBTYPE_MEM, v.DbType())
}
v, err = ToConnData("http://foo/bar")
if err == nil { if err == nil {
t.Fatalf("expected error") t.Fatalf("expected error")
} }
if v.DbType() != DBTYPE_NONE { _, err = ToConnData("http://foo/bar")
t.Fatalf("expected type %v, got %v", DBTYPE_NONE, v.DbType()) if err == nil {
t.Fatalf("expected error")
} }
} }

View File

@ -1,8 +1,6 @@
package storage package storage
import ( import (
"context"
"git.defalsify.org/vise.git/db" "git.defalsify.org/vise.git/db"
"git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/persist"
) )
@ -12,18 +10,14 @@ const (
) )
type Storage struct { type Storage struct {
Persister *persist.Persister Persister *persist.Persister
UserdataDb db.Db UserdataDb db.Db
} }
func (s *Storage) Close(ctx context.Context) error {
return s.UserdataDb.Close(ctx)
}
type StorageProvider interface { type StorageProvider interface {
Get(ctx context.Context, sessionId string) (*Storage, error) Get(sessionId string) (*Storage, error)
Put(ctx context.Context, sessionId string, storage *Storage) error Put(sessionId string, storage *Storage) error
Close(ctx context.Context) error Close() error
} }
type SimpleStorageProvider struct { type SimpleStorageProvider struct {
@ -35,22 +29,20 @@ func NewSimpleStorageProvider(stateStore db.Db, userdataStore db.Db) StorageProv
pe = pe.WithFlush() pe = pe.WithFlush()
return &SimpleStorageProvider{ return &SimpleStorageProvider{
Storage: &Storage{ Storage: &Storage{
Persister: pe, Persister: pe,
UserdataDb: userdataStore, UserdataDb: userdataStore,
}, },
} }
} }
func (p *SimpleStorageProvider) Get(ctx context.Context, sessionId string) (*Storage, error) { func (p *SimpleStorageProvider) Get(sessionId string) (*Storage, error) {
p.Storage.UserdataDb.Start(ctx)
return p.Storage, nil return p.Storage, nil
} }
func (p *SimpleStorageProvider) Put(ctx context.Context, sessionId string, storage *Storage) error { func (p *SimpleStorageProvider) Put(sessionId string, storage *Storage) error {
storage.UserdataDb.Stop(ctx)
return nil return nil
} }
func (p *SimpleStorageProvider) Close(ctx context.Context) error { func (p *SimpleStorageProvider) Close() error {
return p.Storage.Close(ctx) return p.Storage.UserdataDb.Close()
} }

View File

@ -2,21 +2,19 @@ package storage
import ( import (
"context" "context"
"errors"
"fmt" "fmt"
"os" "os"
"path" "path"
"github.com/jackc/pgx/v5/pgxpool"
"git.defalsify.org/vise.git/db" "git.defalsify.org/vise.git/db"
fsdb "git.defalsify.org/vise.git/db/fs" fsdb "git.defalsify.org/vise.git/db/fs"
memdb "git.defalsify.org/vise.git/db/mem"
"git.defalsify.org/vise.git/db/postgres" "git.defalsify.org/vise.git/db/postgres"
"git.defalsify.org/vise.git/lang" "git.defalsify.org/vise.git/lang"
"git.defalsify.org/vise.git/logging" "git.defalsify.org/vise.git/logging"
"git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/resource"
gdbmstorage "git.grassecon.net/grassrootseconomics/visedriver/storage/db/gdbm" gdbmstorage "git.grassecon.net/grassrootseconomics/visedriver/storage/db/gdbm"
"github.com/jackc/pgx/v5/pgxpool"
) )
var ( var (
@ -29,100 +27,61 @@ type StorageService interface {
GetResource(ctx context.Context) (resource.Resource, error) GetResource(ctx context.Context) (resource.Resource, error)
} }
// TODO: Support individual backend for each store (conndata)
type MenuStorageService struct { type MenuStorageService struct {
conns Conns conn ConnData
poResource resource.Resource resourceDir string
store map[int8]db.Db poResource resource.Resource
resourceStore db.Db
stateStore db.Db
userDataStore db.Db
} }
func NewMenuStorageService(conn Conns) *MenuStorageService { func NewMenuStorageService(conn ConnData, resourceDir string) *MenuStorageService {
return &MenuStorageService{ return &MenuStorageService{
conns: conn, conn: conn,
store: make(map[int8]db.Db), resourceDir: resourceDir,
} }
} }
func (ms *MenuStorageService) WithDb(store db.Db, typ int8) *MenuStorageService { func (ms *MenuStorageService) WithResourceDir(resourceDir string) *MenuStorageService {
var err error ms.resourceDir = resourceDir
if ms.store[typ] != nil {
panic(fmt.Errorf("db already set for typ: %d", typ))
}
ms.store[typ] = store
ms.conns[typ], err = ToConnData(store.Connection())
if err != nil {
panic(err)
}
return ms return ms
} }
func (ms *MenuStorageService) checkDb(ctx context.Context, typ int8) db.Db { // TODO: allow fsdb, memdb
store := ms.store[typ] func (ms *MenuStorageService) getOrCreateDb(ctx context.Context, existingDb db.Db, section string, typ string) (db.Db, error) {
if store != nil { var newDb db.Db
return store
}
connData := ms.conns[typ]
logg.DebugCtxf(ctx, "db check", "conn", connData, "store", DbStoreDebug[typ])
v := ms.conns.Have(&connData)
if v == -1 {
return nil
}
src := ms.store[v]
if src == nil {
return nil
}
ms.store[typ] = ms.store[v]
logg.DebugCtxf(ctx, "found existing db", "typ", typ, "srctyp", v, "store", ms.store[typ], "srcstore", ms.store[v], "conn", connData)
return ms.store[typ]
}
func (ms *MenuStorageService) getOrCreateDb(ctx context.Context, section string, typ int8) (db.Db, error) {
var err error var err error
newDb := ms.checkDb(ctx, typ) if existingDb != nil {
if newDb != nil { return existingDb, nil
logg.InfoCtxf(ctx, "using existing db", "typ", typ, "db", newDb)
return newDb, nil
} }
connData := ms.conns[typ] connStr := ms.conn.String()
connStr := connData.Raw() dbTyp := ms.conn.DbType()
dbTyp := connData.DbType()
if dbTyp == DBTYPE_POSTGRES { if dbTyp == DBTYPE_POSTGRES {
// TODO: move to vise // TODO: move to vise
err = ensureSchemaExists(ctx, connData) err = ensureSchemaExists(ctx, ms.conn)
if err != nil { if err != nil {
return nil, err return nil, err
} }
newDb = postgres.NewPgDb().WithSchema(connData.Domain()) newDb = postgres.NewPgDb().WithSchema(ms.conn.Domain())
} else if dbTyp == DBTYPE_GDBM { } else if dbTyp == DBTYPE_GDBM {
err = ms.ensureDbDir(connStr) err = ms.ensureDbDir()
if err != nil { if err != nil {
return nil, err return nil, err
} }
connStr = path.Join(connStr, section) connStr = path.Join(connStr, section)
newDb = gdbmstorage.NewThreadGdbmDb() newDb = gdbmstorage.NewThreadGdbmDb()
} else if dbTyp == DBTYPE_FS {
err = ms.ensureDbDir(connStr)
if err != nil {
return nil, err
}
fsdbInstance := fsdb.NewFsDb()
if connData.Mode() == DBMODE_BINARY {
fsdbInstance = fsdbInstance.WithBinary()
}
newDb = fsdbInstance
} else if dbTyp == DBTYPE_MEM {
logg.WarnCtxf(ctx, "using volatile storage (memdb)")
newDb = memdb.NewMemDb()
} else { } else {
return nil, fmt.Errorf("unsupported connection string: '%s'\n", connData.Raw()) return nil, fmt.Errorf("unsupported connection string: '%s'\n", ms.conn.String())
} }
logg.InfoCtxf(ctx, "connecting to db", "conn", connData, "typ", typ) logg.DebugCtxf(ctx, "connecting to db", "conn", connStr, "conndata", ms.conn, "typ", typ)
err = newDb.Connect(ctx, connStr) err = newDb.Connect(ctx, connStr)
if err != nil { if err != nil {
return nil, err return nil, err
} }
ms.store[typ] = newDb
return newDb, nil return newDb, nil
} }
@ -140,7 +99,7 @@ func (ms *MenuStorageService) WithGettext(path string, lns []lang.Language) *Men
} }
rs := resource.NewPoResource(lns[0], path) rs := resource.NewPoResource(lns[0], path)
for _, ln := range lns { for _, ln := range(lns) {
rs = rs.WithLanguage(ln) rs = rs.WithLanguage(ln)
} }
@ -166,49 +125,38 @@ func ensureSchemaExists(ctx context.Context, conn ConnData) error {
return nil return nil
} }
func applySession(ctx context.Context, store db.Db) error {
sessionId, ok := ctx.Value("SessionId").(string)
if !ok {
logg.DebugCtxf(ctx, "missing session to apply", "store", store)
return nil
//return fmt.Errorf("missing session to apply to store: %v", store)
}
store.SetSession(sessionId)
return nil
}
func (ms *MenuStorageService) GetPersister(ctx context.Context) (*persist.Persister, error) { func (ms *MenuStorageService) GetPersister(ctx context.Context) (*persist.Persister, error) {
stateStore, err := ms.GetStateStore(ctx) stateStore, err := ms.GetStateStore(ctx)
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = applySession(ctx, stateStore)
if err != nil {
return nil, err
}
pr := persist.NewPersister(stateStore) pr := persist.NewPersister(stateStore)
logg.TraceCtxf(ctx, "menu storage service", "persist", pr, "store", stateStore) logg.TraceCtxf(ctx, "menu storage service", "persist", pr, "store", stateStore)
return pr, nil return pr, nil
} }
func (ms *MenuStorageService) GetUserdataDb(ctx context.Context) (db.Db, error) { func (ms *MenuStorageService) GetUserdataDb(ctx context.Context) (db.Db, error) {
userStore, err := ms.getOrCreateDb(ctx, "userdata.gdbm", STORETYPE_USER) if ms.userDataStore != nil {
return ms.userDataStore, nil
}
userDataStore, err := ms.getOrCreateDb(ctx, ms.userDataStore, "userdata.gdbm", "userdata")
if err != nil { if err != nil {
return nil, err return nil, err
} }
err = applySession(ctx, userStore)
if err != nil { ms.userDataStore = userDataStore
return nil, err return ms.userDataStore, nil
}
return userStore, nil
} }
func (ms *MenuStorageService) GetResource(ctx context.Context) (resource.Resource, error) { func (ms *MenuStorageService) GetResource(ctx context.Context) (resource.Resource, error) {
store, err := ms.getOrCreateDb(ctx, "resource.gdbm", STORETYPE_RESOURCE) ms.resourceStore = fsdb.NewFsDb()
err := ms.resourceStore.Connect(ctx, ms.resourceDir)
if err != nil { if err != nil {
return nil, err return nil, err
} }
rfs := resource.NewDbResource(store) rfs := resource.NewDbResource(ms.resourceStore)
if ms.poResource != nil { if ms.poResource != nil {
logg.InfoCtxf(ctx, "using poresource for menu and template") logg.InfoCtxf(ctx, "using poresource for menu and template")
rfs.WithMenuGetter(ms.poResource.GetMenu) rfs.WithMenuGetter(ms.poResource.GetMenu)
@ -218,34 +166,33 @@ func (ms *MenuStorageService) GetResource(ctx context.Context) (resource.Resourc
} }
func (ms *MenuStorageService) GetStateStore(ctx context.Context) (db.Db, error) { func (ms *MenuStorageService) GetStateStore(ctx context.Context) (db.Db, error) {
return ms.getOrCreateDb(ctx, "state.gdbm", STORETYPE_STATE) if ms.stateStore != nil {
} return ms.stateStore, nil
}
func (ms *MenuStorageService) ensureDbDir(path string) error { stateStore, err := ms.getOrCreateDb(ctx, ms.stateStore, "state.gdbm", "state")
err := os.MkdirAll(path, 0700)
if err != nil { if err != nil {
return fmt.Errorf("store dir create exited with error: %v\n", err) return nil, err
}
ms.stateStore = stateStore
return ms.stateStore, nil
}
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)
} }
return nil return nil
} }
// TODO: how to handle persister here? func (ms *MenuStorageService) Close() error {
func (ms *MenuStorageService) Close(ctx context.Context) error { errA := ms.stateStore.Close()
var errs []error errB := ms.userDataStore.Close()
var haveErr bool errC := ms.resourceStore.Close()
for i := range _STORETYPE_MAX { if errA != nil || errB != nil || errC != nil {
err := ms.store[int8(i)].Close(ctx) return fmt.Errorf("%v %v %v", errA, errB, errC)
if err != nil {
haveErr = true
}
errs = append(errs, err)
}
if haveErr {
errStr := ""
for i, err := range errs {
errStr += fmt.Sprintf("(%d: %v)", i, err)
}
return errors.New(errStr)
} }
return nil return nil
} }

View File

@ -1,114 +0,0 @@
package storage
import (
"context"
"os"
"testing"
fsdb "git.defalsify.org/vise.git/db/fs"
)
func TestMenuStorageServiceOneSet(t *testing.T) {
d, err := os.MkdirTemp("", "visedriver-menustorageservice")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(d)
conns := NewConns()
connData, err := ToConnData(d)
if err != nil {
t.Fatal(err)
}
conns.Set(connData, STORETYPE_STATE)
ctx := context.Background()
ms := NewMenuStorageService(conns)
_, err = ms.GetStateStore(ctx)
if err != nil {
t.Fatal(err)
}
_, err = ms.GetResource(ctx)
if err == nil {
t.Fatalf("expected error getting resource")
}
_, err = ms.GetUserdataDb(ctx)
if err == nil {
t.Fatalf("expected error getting userdata")
}
}
func TestMenuStorageServiceExplicit(t *testing.T) {
d, err := os.MkdirTemp("", "visedriver-menustorageservice")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(d)
conns := NewConns()
connData, err := ToConnData(d)
if err != nil {
t.Fatal(err)
}
conns.Set(connData, STORETYPE_STATE)
ctx := context.Background()
d, err = os.MkdirTemp("", "visedriver-menustorageservice")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(d)
store := fsdb.NewFsDb()
err = store.Connect(ctx, d)
if err != nil {
t.Fatal(err)
}
ms := NewMenuStorageService(conns)
ms = ms.WithDb(store, STORETYPE_RESOURCE)
_, err = ms.GetStateStore(ctx)
if err != nil {
t.Fatal(err)
}
_, err = ms.GetResource(ctx)
if err != nil {
t.Fatal(err)
}
_, err = ms.GetUserdataDb(ctx)
if err == nil {
t.Fatalf("expected error getting userdata")
}
}
func TestMenuStorageServiceReuse(t *testing.T) {
d, err := os.MkdirTemp("", "visedriver-menustorageservice")
if err != nil {
t.Fatal(err)
}
defer os.RemoveAll(d)
conns := NewConns()
connData, err := ToConnData(d)
if err != nil {
t.Fatal(err)
}
conns.Set(connData, STORETYPE_STATE)
conns.Set(connData, STORETYPE_USER)
ctx := context.Background()
ctx = context.WithValue(ctx, "SessionId", "foo")
ms := NewMenuStorageService(conns)
stateStore, err := ms.GetStateStore(ctx)
if err != nil {
t.Fatal(err)
}
_, err = ms.GetResource(ctx)
if err == nil {
t.Fatalf("expected error getting resource")
}
userStore, err := ms.GetUserdataDb(ctx)
if err != nil {
t.Fatal(err)
}
if userStore != stateStore {
t.Fatalf("expected same store, but they are %p and %p", userStore, stateStore)
}
}

View File

@ -10,7 +10,7 @@ type MockEngine struct {
InitFunc func(context.Context) (bool, error) InitFunc func(context.Context) (bool, error)
ExecFunc func(context.Context, []byte) (bool, error) ExecFunc func(context.Context, []byte) (bool, error)
FlushFunc func(context.Context, io.Writer) (int, error) FlushFunc func(context.Context, io.Writer) (int, error)
FinishFunc func(context.Context) error FinishFunc func() error
} }
func (m *MockEngine) Init(ctx context.Context) (bool, error) { func (m *MockEngine) Init(ctx context.Context) (bool, error) {
@ -25,6 +25,6 @@ func (m *MockEngine) Flush(ctx context.Context, w io.Writer) (int, error) {
return m.FlushFunc(ctx, w) return m.FlushFunc(ctx, w)
} }
func (m *MockEngine) Finish(ctx context.Context) error { func (m *MockEngine) Finish() error {
return m.FinishFunc(ctx) return m.FinishFunc()
} }

View File

@ -1,8 +1,6 @@
package httpmocks package httpmocks
import ( import (
"context"
"git.defalsify.org/vise.git/engine" "git.defalsify.org/vise.git/engine"
"git.defalsify.org/vise.git/persist" "git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource" "git.defalsify.org/vise.git/resource"
@ -15,8 +13,8 @@ type MockRequestHandler struct {
GetConfigFunc func() engine.Config GetConfigFunc func() engine.Config
GetEngineFunc func(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine GetEngineFunc func(cfg engine.Config, rs resource.Resource, pe *persist.Persister) engine.Engine
OutputFunc func(rs request.RequestSession) (request.RequestSession, error) OutputFunc func(rs request.RequestSession) (request.RequestSession, error)
ResetFunc func(ctx context.Context, rs request.RequestSession) (request.RequestSession, error) ResetFunc func(rs request.RequestSession) (request.RequestSession, error)
ShutdownFunc func(ctx context.Context) ShutdownFunc func()
GetRequestParserFunc func() request.RequestParser GetRequestParserFunc func() request.RequestParser
} }
@ -36,12 +34,12 @@ func (m *MockRequestHandler) Output(rs request.RequestSession) (request.RequestS
return m.OutputFunc(rs) return m.OutputFunc(rs)
} }
func (m *MockRequestHandler) Reset(ctx context.Context, rs request.RequestSession) (request.RequestSession, error) { func (m *MockRequestHandler) Reset(rs request.RequestSession) (request.RequestSession, error) {
return m.ResetFunc(ctx, rs) return m.ResetFunc(rs)
} }
func (m *MockRequestHandler) Shutdown(ctx context.Context) { func (m *MockRequestHandler) Shutdown() {
m.ShutdownFunc(ctx) m.ShutdownFunc()
} }
func (m *MockRequestHandler) GetRequestParser() request.RequestParser { func (m *MockRequestHandler) GetRequestParser() request.RequestParser {

View File

@ -1,41 +0,0 @@
package mocks
import (
"context"
"git.defalsify.org/vise.git/db"
memdb "git.defalsify.org/vise.git/db/mem"
"git.defalsify.org/vise.git/persist"
"git.defalsify.org/vise.git/resource"
)
type MemStorageService struct {
Db db.Db
pe *persist.Persister
rs resource.Resource
}
func NewMemStorageService(ctx context.Context) *MemStorageService {
svc := &MemStorageService{
Db: memdb.NewMemDb(),
}
err := svc.Db.Connect(ctx, "")
if err != nil {
panic(err)
}
svc.pe = persist.NewPersister(svc.Db)
svc.rs = resource.NewMenuResource()
return svc
}
func (mss *MemStorageService) GetPersister(ctx context.Context) (*persist.Persister, error) {
return mss.pe, nil
}
func (mss *MemStorageService) GetUserdataDb(ctx context.Context) (db.Db, error) {
return mss.Db, nil
}
func (mss *MemStorageService) GetResource(ctx context.Context) (resource.Resource, error) {
return mss.rs, nil
}