pgweb/main.go

214 lines
4.8 KiB
Go
Raw Normal View History

2014-10-08 21:26:57 -05:00
package main
import (
"fmt"
"os"
"os/exec"
"os/signal"
"os/user"
"strings"
2014-11-10 23:10:05 -06:00
"github.com/gin-gonic/gin"
"github.com/jessevdk/go-flags"
_ "github.com/lib/pq"
2014-10-08 21:26:57 -05:00
)
2014-12-01 21:04:39 -06:00
const VERSION = "0.4.1"
2014-10-13 21:12:19 -05:00
2014-10-08 21:26:57 -05:00
var options struct {
2014-10-27 15:50:57 -05:00
Version bool `short:"v" long:"version" description:"Print version"`
Debug bool `short:"d" long:"debug" description:"Enable debugging mode" default:"false"`
2014-10-26 11:47:15 -05:00
Url string `long:"url" description:"Database connection string"`
Host string `long:"host" description:"Server hostname or IP"`
2014-10-26 11:47:15 -05:00
Port int `long:"port" description:"Server port" default:"5432"`
User string `long:"user" description:"Database user"`
Pass string `long:"pass" description:"Password for user"`
DbName string `long:"db" description:"Database name"`
Ssl string `long:"ssl" description:"SSL option"`
HttpHost string `long:"bind" description:"HTTP server host" default:"localhost"`
2014-10-26 18:43:33 -05:00
HttpPort uint `long:"listen" description:"HTTP server listen port" default:"8080"`
2014-10-29 19:45:12 -05:00
AuthUser string `long:"auth-user" description:"HTTP basic auth user"`
AuthPass string `long:"auth-pass" description:"HTTP basic auth password"`
SkipOpen bool `short:"s" long:"skip-open" description:"Skip browser open on start"`
2014-10-08 21:26:57 -05:00
}
2014-10-10 17:14:17 -05:00
var dbClient *Client
2014-10-10 00:03:03 -05:00
func exitWithMessage(message string) {
fmt.Println("Error:", message)
os.Exit(1)
}
2014-10-08 21:26:57 -05:00
func getConnectionString() string {
if options.Url != "" {
url := options.Url
if strings.Contains(url, "postgresql://") {
fmt.Println("Invalid URL format. It should match: postgres://user:password@host:port/db?sslmode=mode")
os.Exit(1)
}
// Append sslmode parameter only if its defined as a flag and not present
// in the connection string.
if options.Ssl != "" && !strings.Contains(url, "sslmode") {
url += fmt.Sprintf("?sslmode=%s", options.Ssl)
}
return url
}
// Try to detect user from current OS user
if options.User == "" {
user, err := user.Current()
if err == nil {
options.User = user.Username
}
}
str := fmt.Sprintf(
"host=%s port=%d user=%s dbname=%s",
2014-10-08 21:26:57 -05:00
options.Host, options.Port,
options.User, options.DbName,
)
if options.Ssl == "" {
// Disable ssl for localhost connections, most users have it disabled
if options.Host == "localhost" || options.Host == "127.0.0.1" {
options.Ssl = "disable"
}
}
if options.Ssl != "" {
str += fmt.Sprintf(" sslmode=%s", options.Ssl)
}
if options.Pass != "" {
str += fmt.Sprintf(" password=%s", options.Pass)
}
return str
2014-10-08 21:26:57 -05:00
}
func connectionSettingsBlank() bool {
return options.Host == "" &&
options.User == "" &&
options.DbName == "" &&
options.Url == ""
}
2014-10-08 21:26:57 -05:00
func initClient() {
if connectionSettingsBlank() {
return
}
2014-10-08 21:26:57 -05:00
client, err := NewClient()
if err != nil {
exitWithMessage(err.Error())
2014-10-08 21:26:57 -05:00
}
2014-10-11 22:38:32 -05:00
fmt.Println("Connecting to server...")
err = client.Test()
if err != nil {
exitWithMessage(err.Error())
}
2014-10-11 22:38:32 -05:00
fmt.Println("Checking tables...")
2014-10-29 12:11:52 -07:00
_, err = client.Tables()
if err != nil {
exitWithMessage(err.Error())
}
2014-10-08 21:26:57 -05:00
dbClient = client
}
func initOptions() {
_, err := flags.ParseArgs(&options, os.Args)
if err != nil {
2014-10-10 17:20:14 -05:00
os.Exit(1)
2014-10-08 21:26:57 -05:00
}
2014-10-22 07:54:47 -06:00
if options.Url == "" {
options.Url = os.Getenv("DATABASE_URL")
}
2014-10-22 07:54:47 -06:00
if options.Version {
fmt.Printf("pgweb v%s\n", VERSION)
2014-10-27 15:49:43 -05:00
os.Exit(0)
2014-10-22 07:54:47 -06:00
}
2014-10-08 21:26:57 -05:00
}
func startServer() {
2014-10-08 21:26:57 -05:00
router := gin.Default()
2014-10-09 19:05:51 -05:00
2014-10-29 19:45:12 -05:00
// Enable HTTP basic authentication only if both user and password are set
if options.AuthUser != "" && options.AuthPass != "" {
auth := map[string]string{options.AuthUser: options.AuthPass}
router.Use(gin.BasicAuth(auth))
}
2014-10-13 13:55:19 -05:00
router.GET("/", API_Home)
router.POST("/connect", API_Connect)
2014-10-15 16:05:23 -05:00
router.GET("/databases", API_GetDatabases)
2014-10-10 00:03:03 -05:00
router.GET("/info", API_Info)
2014-10-08 21:26:57 -05:00
router.GET("/tables", API_GetTables)
2014-10-11 13:20:16 -05:00
router.GET("/tables/:table", API_GetTable)
router.GET("/tables/:table/info", API_GetTableInfo)
2014-10-11 13:20:16 -05:00
router.GET("/tables/:table/indexes", API_TableIndexes)
2014-10-10 17:14:17 -05:00
router.GET("/query", API_RunQuery)
router.POST("/query", API_RunQuery)
2014-10-11 13:24:12 -05:00
router.GET("/explain", API_ExplainQuery)
router.POST("/explain", API_ExplainQuery)
2014-10-09 19:59:18 -05:00
router.GET("/history", API_History)
2014-10-13 14:40:56 -05:00
router.GET("/static/:type/:name", API_ServeAsset)
2014-10-09 19:05:51 -05:00
2014-10-13 18:40:17 -05:00
fmt.Println("Starting server...")
go router.Run(fmt.Sprintf("%v:%v", options.HttpHost, options.HttpPort))
}
func handleSignals() {
c := make(chan os.Signal, 1)
signal.Notify(c, os.Interrupt, os.Kill)
<-c
}
func openPage() {
url := fmt.Sprintf("http://%v:%v", options.HttpHost, options.HttpPort)
2014-10-26 11:47:15 -05:00
fmt.Println("To view database open", url, "in browser")
if options.SkipOpen {
return
}
_, err := exec.Command("which", "open").Output()
if err != nil {
return
}
2014-10-26 11:47:15 -05:00
exec.Command("open", url).Output()
}
func main() {
initOptions()
2014-11-16 12:01:13 -06:00
fmt.Println("Pgweb version", VERSION)
initClient()
if dbClient != nil {
defer dbClient.db.Close()
}
if !options.Debug {
gin.SetMode("release")
}
if options.Debug {
startRuntimeProfiler()
}
startServer()
openPage()
handleSignals()
2014-10-08 21:26:57 -05:00
}