This repository has been archived on 2025-03-30. You can view files and clone it, but cannot push or open issues or pull requests.
bactdb/main.go
2015-10-05 10:34:28 -07:00

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)
}
}
}
}
}