github.com/gocaveman/caveman@v0.0.0-20191211162744-0ddf99dbdf6e/gen/main-rest-sqlite3.go (about) 1 package gen 2 3 import ( 4 "flag" 5 "path/filepath" 6 ) 7 8 func init() { 9 globalMapGenerator["main-rest-sqlite3"] = GeneratorFunc(func(s *Settings, name string, args ...string) error { 10 11 // FIXME: see if we want to move to pflag - it's probably better and 12 // would be smart to be consistent 13 fset := flag.NewFlagSet("gen", flag.ContinueOnError) 14 // storeName := fset.String("name", "Store", "The name of the store struct to define") 15 targetFile, data, err := ParseFlagsAndOneFile(s, fset, args) 16 if err != nil { 17 return err 18 } 19 20 targetDir, _ := filepath.Split(targetFile) 21 _, targetDirName := filepath.Split(targetDir) 22 23 data["TargetDirName"] = targetDirName 24 25 return OutputGoSrcTemplate(s, data, targetFile, ` 26 package main 27 28 import ( 29 "github.com/gocraft/dbr" 30 "github.com/gocaveman/dbrobj" 31 32 _ "github.com/mattn/go-sqlite3" 33 // _ "github.com/go-sql-driver/mysql" 34 // _ "github.com/lib/pq" 35 ) 36 37 const APP_NAME = "{{.TargetDirName}}" 38 39 func main() { 40 41 var err error 42 43 // TODO: HTTPS support, including certificates - letsencrypt with option to override 44 // and workable solution for local development 45 pflag.StringP("http-listen", "l", ":8080", "IP:Port to listen on for HTTP") 46 // pflag.StringP("db-dsn", "", "root:@tcp(localhost:3306)/"+APP_NAME+"?charset=utf8mb4,utf8", "Database connection string") 47 pflag.StringP("db-dsn", "", "file:"+APP_NAME+"?mode=memory&cache=shared", "Database connection string") 48 pflag.StringP("db-driver", "", "sqlite3", "Database driver name") 49 // TODO: on the migrations we probably also want a way to separately check, and then update 50 // without running the app - so you can build the new version with the schema changes, check it 51 // apply it, and then deploy. 52 pflag.StringP("db-migrate", "", "auto", "Database migration behavior ('auto' to update, 'check' to report out of date, or 'none' to ignore migrations)") 53 pflag.BoolP("debug", "g", false, "Enable debug output (intended for development only)") 54 pflag.Parse() 55 viper.BindPFlags(pflag.CommandLine) 56 57 // TODO: add viper config file search and load stuff 58 59 if wd := viper.GetString("workdir"); wd != "" { 60 if err := os.Chdir(wd); err != nil { 61 log.Fatalf("Error changing directory to %q: %v", wd, err) 62 } 63 } 64 65 hl := webutil.NewDefaultHandlerList() 66 for _, item := range handlerregistry.Contents() { 67 hl = append(hl, item.Value) 68 } 69 hl = append(hl, http.NotFoundHandler()) 70 71 dbDriver := viper.GetString("db-driver") 72 dbDsn := viper.GetString("db-dsn") 73 // TODO: provide in autowire, just need to know the pattern for names... 74 75 dbrConn, err := dbr.Open(dbDriver, dbDsn, nil) 76 if err != nil { 77 log.Fatal(err) 78 } 79 autowire.Provide("", dbrConn) 80 81 connector := dbrobj.NewConfig().NewConnector(dbrConn, nil) 82 autowire.Provide("", connector) 83 84 err = autowire.Contents().Run() 85 if err != nil { 86 log.Fatalf("autowire error: %v", err) 87 } 88 89 dbMigrateMode := viper.GetString("db-migrate") 90 ml := migrateregistry.Contents().WithDriverName(dbDriver).Sorted() 91 // EDITME: you can filter migrations here if needed 92 versioner, err := migratedbr.New(dbDriver, dbDsn) 93 if err != nil { 94 log.Fatal(err) 95 } 96 runner := migrate.NewRunner(dbDriver, dbDsn, versioner, ml) 97 if dbMigrateMode == "check" { 98 result, err := runner.CheckAll(true) 99 if err != nil { 100 log.Fatalf("Migration check error: %v", err) 101 } 102 log.Printf("Migration check result: %+v", result) // TODO: better output 103 } else if dbMigrateMode == "auto" { 104 err := runner.RunAllUpToLatest() 105 if err != nil { 106 log.Fatalf("Migration auto-update error: %v", err) 107 } 108 } 109 110 var wg sync.WaitGroup 111 112 // FIXME: HTTP/HTTPS graceful shutdown; 113 // example here https://gist.github.com/peterhellberg/38117e546c217960747aacf689af3dc2 114 // The idea is that if we stop receiving new requests and succesfully complete the old, 115 // a load balancer can reliably hold onto and retry connections that are rejected 116 // and we can get a deploy/restart (even on a single server) with no actual "down time". 117 // FIXME: we should also look at runtime.SetFinalizer and anything else relevant and 118 // see if there is some sort of "shutdown" hook that can easily be put together - without 119 // getting too weird and complicated - maybe it's just a matter of calling Close() on 120 // whatever needs it as defer in main and things get cleaned up that way (and possibly 121 // autowire needs to support some sort of Close() mechanism as well) 122 webutil.StartHTTPServer(&http.Server{ 123 Addr: viper.GetString("http-listen"), 124 Handler: hl, 125 }, &wg) 126 127 wg.Wait() 128 } 129 130 `, false) 131 132 }) 133 }