159 lines
3.9 KiB
Go
159 lines
3.9 KiB
Go
package main
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"os"
|
|
"sync"
|
|
|
|
"github.com/thermokarst/bactdb/Godeps/_workspace/src/github.com/DavidHuie/gomigrate"
|
|
"github.com/thermokarst/bactdb/Godeps/_workspace/src/github.com/codegangsta/cli"
|
|
"github.com/thermokarst/bactdb/Godeps/_workspace/src/github.com/jmoiron/sqlx"
|
|
"github.com/thermokarst/bactdb/Godeps/_workspace/src/github.com/lib/pq"
|
|
"github.com/thermokarst/bactdb/Godeps/_workspace/src/github.com/mailgun/mailgun-go"
|
|
"github.com/thermokarst/bactdb/api"
|
|
"github.com/thermokarst/bactdb/handlers"
|
|
"github.com/thermokarst/bactdb/models"
|
|
)
|
|
|
|
func init() {
|
|
var connectOnce sync.Once
|
|
connectOnce.Do(func() {
|
|
var err error
|
|
connection := "timezone=UTC "
|
|
if heroku := os.Getenv("HEROKU"); heroku == "true" {
|
|
url := os.Getenv("DATABASE_URL")
|
|
conn, _ := pq.ParseURL(url)
|
|
connection += conn
|
|
connection += " sslmode=require"
|
|
} else {
|
|
connection += " sslmode=disable"
|
|
}
|
|
models.DB.Dbx, err = sqlx.Open("postgres", connection)
|
|
if err != nil {
|
|
log.Fatal("Error connecting to PostgreSQL database (using PG* environment variables): ", err)
|
|
}
|
|
models.DB.TraceOn("[modl]", log.New(os.Stdout, "bactdb:", log.Lmicroseconds))
|
|
models.DB.Db = models.DB.Dbx.DB
|
|
})
|
|
}
|
|
|
|
func main() {
|
|
app := cli.NewApp()
|
|
app.Name = "bactdb"
|
|
app.Usage = "a database for bacteria"
|
|
app.Authors = []cli.Author{
|
|
cli.Author{
|
|
Name: "Matthew Ryan Dillon",
|
|
Email: "mrdillon@alaska.edu",
|
|
},
|
|
}
|
|
app.Version = "0.1.0"
|
|
|
|
app.Commands = []cli.Command{
|
|
{
|
|
Name: "serve",
|
|
ShortName: "s",
|
|
Usage: "Start web server",
|
|
Action: cmdServe,
|
|
},
|
|
{
|
|
Name: "migrate",
|
|
ShortName: "m",
|
|
Usage: "Migrate the database schema",
|
|
Flags: []cli.Flag{
|
|
cli.BoolFlag{
|
|
Name: "drop",
|
|
Usage: "Drop DB before migrating",
|
|
},
|
|
cli.StringFlag{
|
|
Name: "migration_path",
|
|
Usage: "Path to migration DDL",
|
|
Value: "./migrations",
|
|
},
|
|
},
|
|
Action: cmdMigrateDb,
|
|
},
|
|
}
|
|
app.Run(os.Args)
|
|
}
|
|
|
|
func cmdServe(c *cli.Context) {
|
|
var err error
|
|
|
|
// Set up Mailgun handlers:
|
|
// [{"ref":"hymenobacter","domain":"hymenobacter.info","public":"abc","private":"123"}]
|
|
type account struct {
|
|
Ref string
|
|
Domain string
|
|
Public string
|
|
Private string
|
|
}
|
|
var accounts []account
|
|
json.Unmarshal([]byte(os.Getenv("ACCOUNT_KEYS")), &accounts)
|
|
log.Printf("Mailgun: %+v", accounts)
|
|
|
|
for _, a := range accounts {
|
|
api.MgAccts[a.Ref] = mailgun.NewMailgun(a.Domain, a.Private, a.Public)
|
|
}
|
|
|
|
addr := os.Getenv("PORT")
|
|
if addr == "" {
|
|
addr = "8901"
|
|
}
|
|
httpAddr := fmt.Sprintf(":%v", addr)
|
|
|
|
m := http.NewServeMux()
|
|
m.Handle("/api/", http.StripPrefix("/api", handlers.Handler()))
|
|
|
|
log.Print("Listening on ", httpAddr)
|
|
err = http.ListenAndServe(httpAddr, m)
|
|
if err != nil {
|
|
log.Fatal("ListenAndServe: ", err)
|
|
}
|
|
}
|
|
|
|
func cmdMigrateDb(c *cli.Context) {
|
|
migrationsPath := c.String("migration_path")
|
|
migrator, err := gomigrate.NewMigrator(models.DB.Dbx.DB, gomigrate.Postgres{}, migrationsPath)
|
|
if err != nil {
|
|
log.Fatal("Error initializing migrations: ", err)
|
|
}
|
|
|
|
users := make(models.Users, 0)
|
|
|
|
if c.Bool("drop") {
|
|
// Back up users table
|
|
// TODO: look into this
|
|
if err := models.DBH.Select(&users, `SELECT * FROM users;`); err != nil {
|
|
log.Printf("Couldn't back up identity tables: %+v", err)
|
|
}
|
|
log.Printf("%+v Users", len(users))
|
|
|
|
// Drop tables
|
|
if err = migrator.RollbackAll(); err != nil && err != gomigrate.NoActiveMigrations {
|
|
log.Fatal("Error rolling back migrations: ", err)
|
|
}
|
|
}
|
|
|
|
// Run migrations
|
|
if err = migrator.Migrate(); err != nil {
|
|
log.Fatal("Error applying migrations: ", err)
|
|
}
|
|
|
|
// If we dropped, restore the user records
|
|
if c.Bool("drop") {
|
|
// Stick users back into DB
|
|
if len(users) > 0 {
|
|
// varargs don't seem to work here, loop instead
|
|
for _, user := range users {
|
|
// TODO: look into this
|
|
if err := models.DBH.Insert(user.UserBase); err != nil {
|
|
log.Fatal("Couldn't restore user: ", err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|