From a48b217d2c61e4d35a24c07a0e4ebdcf768c0f91 Mon Sep 17 00:00:00 2001 From: Sarah Jamie Lewis Date: Wed, 1 Mar 2023 09:48:34 -0800 Subject: [PATCH] Optional App Experiment --- experiments/servers/servers_functionality.go | 15 +++- generate/generate_bindings.go | 81 +++++++++++++++-- go.mod | 4 +- go.sum | 12 +-- spec | 12 ++- templates/lib_template.go | 95 +------------------- 6 files changed, 100 insertions(+), 119 deletions(-) diff --git a/experiments/servers/servers_functionality.go b/experiments/servers/servers_functionality.go index 72f54bc..28288b1 100644 --- a/experiments/servers/servers_functionality.go +++ b/experiments/servers/servers_functionality.go @@ -51,7 +51,7 @@ var appServers server.Servers var killStatsUpdate chan bool = make(chan bool, 1) var enabled bool = false -func InitServers(acn connectivity.ACN, appdir string, ) *ServersFunctionality { +func Init(acn connectivity.ACN, appdir string, ) *ServersFunctionality { lock.Lock() defer lock.Unlock() if appServers == nil { @@ -62,7 +62,10 @@ func InitServers(acn connectivity.ACN, appdir string, ) *ServersFunctionality { } appServers = server.NewServers(acn, serversDir) } - return new(ServersFunctionality) + + serversFunctionality := new(ServersFunctionality) + + return serversFunctionality } // track acnStatus across events @@ -115,7 +118,7 @@ func (sh *ServersFunctionality) UpdateSettings(appl app.Application, acn connect } else { sh.LoadServers(appl, acn, app.DefactoPasswordForUnencryptedProfiles) if !sh.Enabled() { - sh.Enable(appl) + sh.Enable(appl, acn) serversList := sh.ListServers() for _, server := range serversList { serverInfo := sh.GetServerInfo(server) @@ -161,11 +164,15 @@ func (sh *ServersFunctionality) LaunchServers(appl app.Application, acn connecti } } -func (sf *ServersFunctionality) Enable(application app.Application) { +func (sf *ServersFunctionality) Enable(application app.Application, acn connectivity.ACN, ) { lock.Lock() defer lock.Unlock() if appServers != nil && !enabled { enabled = true + + // load unencrypted profiles + sf.LoadServers(application, acn, app.DefactoPasswordForUnencryptedProfiles) + go cacheForwardServerMetricUpdates(application) } } diff --git a/generate/generate_bindings.go b/generate/generate_bindings.go index 21bfe98..cd5d379 100644 --- a/generate/generate_bindings.go +++ b/generate/generate_bindings.go @@ -12,8 +12,14 @@ import ( func main() { + loadedExperiments := make(map[string]bool) + for _, exp := range os.Args[1:] { + loadedExperiments[exp] = true + } + generatedBindingsPrefix := `` generatedBindings := `` + experimentRegistry := `` file, err := os.Open("spec") if err != nil { log.Fatal(err) @@ -37,31 +43,58 @@ func main() { fType := parts[0] fName := parts[1] + args := parts[2:] - if strings.HasPrefix(line, "import") { + experiment := "" + if strings.HasPrefix(fType, "!") { + experiment = strings.ReplaceAll(fType, "!", "") + if _, gen := loadedExperiments[experiment]; gen { + fType = parts[1] + fName = parts[2] + args = parts[3:] + } else { + continue // skip experiment + } + } + + if strings.HasPrefix(fType, "import") { generatedBindingsPrefix += fName + "\n" continue } + if strings.HasPrefix(fType, "global") { + generatedBindings += fmt.Sprintf("var %s %s\n", parts[2], parts[3]) + + experimentRegistry += fmt.Sprintf(` + %s = %s.Init(&globalACN, appDir) + eventHandler.AddModule(%s) + %s.Enable(application, &globalACN) +`, parts[2], parts[4], parts[2], parts[2]) + continue + } + fmt.Printf("generating %v function for %v\n", fType, fName) switch fType { case "app": - generatedBindings = generateAppFunction(generatedBindings, fName, parts[2:]) + generatedBindings = generateAppFunction(generatedBindings, fName, args) + case "exp": + generatedBindings = generateExpFunction(generatedBindings, fName, experiment, args) case "(json)app": - generatedBindings = generateJsonAppFunction(generatedBindings, fName, parts[2:]) + generatedBindings = generateJsonAppFunction(generatedBindings, fName, args) case "profile": - generatedBindings = generateProfileFunction(generatedBindings, fName, parts[2:]) + generatedBindings = generateProfileFunction(generatedBindings, fName, args) case "(json)profile": - generatedBindings = generateJsonProfileFunction(generatedBindings, fName, parts[2:]) + generatedBindings = generateJsonProfileFunction(generatedBindings, fName, args) case "@profile-experiment": - experiment := parts[2] - generatedBindings = generateExperimentalProfileFunction(generatedBindings, experiment, fName, parts[3:]) + experiment := args[0] + generatedBindings = generateExperimentalProfileFunction(generatedBindings, experiment, fName, args[1:]) case "@(json)profile-experiment": - experiment := parts[2] - generatedBindings = generateExperimentalJsonProfileFunction(generatedBindings, experiment, fName, parts[3:]) + experiment := args[0] + generatedBindings = generateExperimentalJsonProfileFunction(generatedBindings, experiment, fName, args[1:]) default: + fmt.Printf("unknown function type %v\n", parts) os.Exit(1) } @@ -78,6 +111,7 @@ func main() { template, _ := os.ReadFile("templates/lib_template.go") templateString := string(template) templateString = strings.ReplaceAll(templateString, "{{BINDINGS}}", generatedBindings) + templateString = strings.ReplaceAll(templateString, "{{EXPERIMENT_REGISTER}}", experimentRegistry) templateString = strings.ReplaceAll(templateString, "{{IMPORTS}}", generatedBindingsPrefix) os.WriteFile("lib.go", []byte(templateString), 0644) } @@ -133,6 +167,10 @@ func mapArgs(argsTypes []string) (string, string, string, string) { argTypeParts := strings.Split(argSpec, ":") argType := argTypeParts[0] switch argType { + case "application": + gUse = append(gUse, "application") + case "acn": + gUse = append(gUse, "&globalACN") case "profile": c1, c2, c3, c4 := profileHandleArgPrototype() cArgs = append(cArgs, c1) @@ -235,6 +273,31 @@ func {{FNAME}}({{GO_ARGS_SPEC}}) { return bindings } +func generateExpFunction(bindings string, name string, exp string, argsTypes []string) string { + appPrototype := ` +//export c_{{FNAME}} +func c_{{FNAME}}({{C_ARGS}}) { + {{FNAME}}({{C2GO_ARGS}}) +} + +func {{FNAME}}({{GO_ARGS_SPEC}}) { + {{EXPERIMENT}}.{{LIBNAME}}({{GO_ARG}}) +} +` + + cArgs, c2GoArgs, goSpec, gUse := mapArgs(argsTypes) + appPrototype = strings.ReplaceAll(appPrototype, "{{FNAME}}", strings.TrimPrefix(name, "Enhanced")) + appPrototype = strings.ReplaceAll(appPrototype, "{{EXPERIMENT}}", exp) + appPrototype = strings.ReplaceAll(appPrototype, "{{LIBNAME}}", name) + appPrototype = strings.ReplaceAll(appPrototype, "{{C_ARGS}}", cArgs) + appPrototype = strings.ReplaceAll(appPrototype, "{{C2GO_ARGS}}", c2GoArgs) + appPrototype = strings.ReplaceAll(appPrototype, "{{GO_ARGS_SPEC}}", goSpec) + appPrototype = strings.ReplaceAll(appPrototype, "{{GO_ARG}}", gUse) + + bindings += appPrototype + return bindings +} + func generateJsonAppFunction(bindings string, name string, argsTypes []string) string { appPrototype := ` //export c_{{FNAME}} diff --git a/go.mod b/go.mod index cd9c6a4..4092886 100644 --- a/go.mod +++ b/go.mod @@ -3,15 +3,13 @@ module git.openprivacy.ca/cwtch.im/cwtch-autobindings go 1.19 require ( - cwtch.im/cwtch v0.18.10-0.20230227213132-dfaed356c491 + cwtch.im/cwtch v0.19.0 git.openprivacy.ca/cwtch.im/server v1.4.5 git.openprivacy.ca/openprivacy/connectivity v1.8.6 git.openprivacy.ca/openprivacy/log v1.0.3 github.com/mutecomm/go-sqlcipher/v4 v4.4.2 ) -replace cwtch.im/cwtch => /home/sarah/workspace/src/cwtch.im/cwtch - require ( filippo.io/edwards25519 v1.0.0 // indirect git.openprivacy.ca/cwtch.im/tapir v0.6.0 // indirect diff --git a/go.sum b/go.sum index 562ce03..7a18675 100644 --- a/go.sum +++ b/go.sum @@ -1,8 +1,6 @@ cwtch.im/cwtch v0.18.0/go.mod h1:StheazFFY7PKqBbEyDVLhzWW6WOat41zV0ckC240c5Y= -cwtch.im/cwtch v0.18.10-0.20230227213132-dfaed356c491 h1:pzzWnyXQHsnKDNHhG+JRTlDg3Eit62grfkM6KeUiv8g= -cwtch.im/cwtch v0.18.10-0.20230227213132-dfaed356c491/go.mod h1:h8S7EgEM+8pE1k+XLB5jAFdIPlOzwoXEY0GH5mQye5A= -cwtch.im/cwtch v0.18.10-0.20230227220552-0f83fb79f0c7 h1:hHKB6bPgYPwjOBGg3JR/3ovmSys1rKs6nsnpkrXslbU= -cwtch.im/cwtch v0.18.10-0.20230227220552-0f83fb79f0c7/go.mod h1:h8S7EgEM+8pE1k+XLB5jAFdIPlOzwoXEY0GH5mQye5A= +cwtch.im/cwtch v0.19.0 h1:s5YkU3od1ZJB+8OXoJAy8vjgi6lkIVhbdkXIE8V+iZY= +cwtch.im/cwtch v0.19.0/go.mod h1:h8S7EgEM+8pE1k+XLB5jAFdIPlOzwoXEY0GH5mQye5A= filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= filippo.io/edwards25519 v1.0.0 h1:0wAIcmJUqRdI8IJ/3eGi5/HwXZWPujYXXlkrQogz0Ek= filippo.io/edwards25519 v1.0.0/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= @@ -92,12 +90,8 @@ golang.org/x/crypto v0.0.0-20201012173705-84dcc777aaee/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d h1:3qF+Z8Hkrw9sOhrFHti9TlB1Hkac1x+DNRkv0XQiFjo= golang.org/x/crypto v0.0.0-20220826181053-bd7e27e6170d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/mobile v0.0.0-20221110043201-43a038452099 h1:aIu0lKmfdgtn2uTj7JI2oN4TUrQvgB+wzTPO23bCKt8= -golang.org/x/mobile v0.0.0-20221110043201-43a038452099/go.mod h1:aAjjkJNdrh3PMckS4B10TGS2nag27cbKR1y2BpUxsiY= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -148,8 +142,6 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20201224043029-2b0845dc783e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.10/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= -golang.org/x/tools v0.1.12 h1:VveCTK38A2rkS8ZqFY25HIDFscX5X9OoEhJd3quQmXU= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/spec b/spec index eb6d28b..9baf012 100644 --- a/spec +++ b/spec @@ -43,4 +43,14 @@ import "cwtch.im/cwtch/functionality/filesharing" # Server Hosting Experiment -# app-experiment ServerFunctionality \ No newline at end of file +!serverExperiment import "git.openprivacy.ca/cwtch.im/cwtch-autobindings/experiments/servers" +!serverExperiment global serverExperiment *servers.ServersFunctionality servers +!serverExperiment exp CreateServer application password string:description bool:autostart +!serverExperiment exp SetServerAttribute application string:handle string:key string:val +!serverExperiment exp LoadServers application acn password +!serverExperiment exp LaunchServers application acn +!serverExperiment exp LaunchServer application string:handle +!serverExperiment exp StopServer application string:handle +!serverExperiment exp StopServers application +!serverExperiment exp DestroyServers +!serverExperiment exp DeleteServer application string:handle password diff --git a/templates/lib_template.go b/templates/lib_template.go index 3669f23..369d350 100644 --- a/templates/lib_template.go +++ b/templates/lib_template.go @@ -12,9 +12,7 @@ import ( "cwtch.im/cwtch/model/constants" "encoding/json" "fmt" - "git.openprivacy.ca/cwtch.im/cwtch-autobindings/experiments/servers" "git.openprivacy.ca/cwtch.im/cwtch-autobindings/utils" - _ "git.openprivacy.ca/cwtch.im/server" "git.openprivacy.ca/openprivacy/connectivity/tor" "git.openprivacy.ca/openprivacy/log" "os" @@ -165,7 +163,7 @@ func _startCwtch(appDir string, torPath string) { // Allow the user of a custom torrc globalAppDir = appDir globalTorPath = torPath - settingsFile := app.InitApp(appDir) + settingsFile := app.LoadAppSettings(appDir) newACN, settings := buildACN(settingsFile.ReadGlobalSettings(), globalTorPath, globalAppDir) globalACN = connectivity.NewProxyACN(newACN) settingsFile.WriteGlobalSettings(settings) @@ -193,10 +191,8 @@ func _startCwtch(appDir string, torPath string) { application.QueryACNVersion() application.LoadProfiles(app.DefactoPasswordForUnencryptedProfiles) - serverExperiment = servers.InitServers(&globalACN, appDir) - eventHandler.AddModule(serverExperiment) - serverExperiment.Enable(application) - serverExperiment.LoadServers(application, &globalACN, app.DefactoPasswordForUnencryptedProfiles) + {{EXPERIMENT_REGISTER}} + } // the pointer returned from this function **must** be freed using c_Free @@ -494,91 +490,6 @@ func UpdateSettings(settingsJson string) { application.UpdateSettings(newSettings) } -//***** Server APIs ***** - -var serverExperiment *servers.ServersFunctionality - -//export c_LoadServers -func c_LoadServers(passwordPtr *C.char, passwordLen C.int) { - LoadServers(C.GoStringN(passwordPtr, passwordLen)) -} - -func LoadServers(password string) { - serverExperiment.LoadServers(application, &globalACN, password) -} - -//export c_CreateServer -func c_CreateServer(passwordPtr *C.char, passwordLen C.int, descPtr *C.char, descLen C.int, autostart C.char) { - CreateServer(C.GoStringN(passwordPtr, passwordLen), C.GoStringN(descPtr, descLen), autostart == 1) -} - -func CreateServer(password string, description string, autostart bool) { - serverExperiment.CreateServer(application, password, description, autostart) -} - -//export c_DeleteServer -func c_DeleteServer(onionPtr *C.char, onionLen C.int, currentPasswordPtr *C.char, currentPasswordLen C.int) { - DeleteServer(C.GoStringN(onionPtr, onionLen), C.GoStringN(currentPasswordPtr, currentPasswordLen)) -} - -func DeleteServer(onion string, currentPassword string) { - serverExperiment.DeleteServer(application, onion, currentPassword) -} - -//export c_LaunchServers -func c_LaunchServers() { - LaunchServers() -} - -func LaunchServers() { - serverExperiment.LaunchServers(application, &globalACN) -} - -//export c_LaunchServer -func c_LaunchServer(onionPtr *C.char, onionLen C.int) { - LaunchServer(C.GoStringN(onionPtr, onionLen)) -} - -func LaunchServer(onion string) { - serverExperiment.LaunchServer(application, onion) -} - -//export c_StopServer -func c_StopServer(onionPtr *C.char, onionLen C.int) { - StopServer(C.GoStringN(onionPtr, onionLen)) -} - -func StopServer(onion string) { - serverExperiment.StopServer(application, onion) -} - -//export c_StopServers -func c_StopServers() { - StopServers() -} - -func StopServers() { - serverExperiment.StopServers(application) -} - -//export c_DestroyServers -func c_DestroyServers() { - DestroyServers() -} - -func DestroyServers() { - serverExperiment.DestroyServers() -} - -//export c_SetServerAttribute -func c_SetServerAttribute(onionPtr *C.char, onionLen C.int, keyPtr *C.char, keyLen C.int, valPtr *C.char, valLen C.int) { - SetServerAttribute(C.GoStringN(onionPtr, onionLen), C.GoStringN(keyPtr, keyLen), C.GoStringN(valPtr, valLen)) -} - -func SetServerAttribute(onion string, key string, val string) { - serverExperiment.SetServerAttribute(application, onion, key, val) -} - {{BINDINGS}}