super-graph/serv/serv.go

212 lines
3.9 KiB
Go
Raw Normal View History

2019-03-24 14:57:29 +01:00
package serv
import (
2019-05-13 01:27:26 +02:00
"context"
2019-03-24 14:57:29 +01:00
"fmt"
"net/http"
"os"
2019-05-13 01:27:26 +02:00
"os/signal"
2019-03-24 14:57:29 +01:00
"strings"
2019-05-13 01:27:26 +02:00
"time"
2019-03-24 14:57:29 +01:00
rice "github.com/GeertJohan/go.rice"
2019-03-24 14:57:29 +01:00
"github.com/dosco/super-graph/psql"
"github.com/dosco/super-graph/qcode"
)
2019-04-08 08:47:59 +02:00
func initCompilers(c *config) (*qcode.Compiler, *psql.Compiler, error) {
schema, err := psql.NewDBSchema(db, c.getAliasMap())
2019-05-13 01:27:26 +02:00
if err != nil {
return nil, nil, err
2019-04-08 08:47:59 +02:00
}
2019-03-24 14:57:29 +01:00
conf := qcode.Config{
Blocklist: c.DB.Defaults.Blocklist,
KeepArgs: false,
}
2019-10-14 08:51:36 +02:00
qc, err := qcode.NewCompiler(conf)
if err != nil {
return nil, nil, err
}
blockFilter := []string{"false"}
2019-10-14 08:51:36 +02:00
for _, r := range c.Roles {
for _, t := range r.Tables {
query := qcode.QueryConfig{
Limit: t.Query.Limit,
2019-10-25 07:39:59 +02:00
Filters: t.Query.Filters,
2019-10-14 08:51:36 +02:00
Columns: t.Query.Columns,
DisableFunctions: t.Query.DisableFunctions,
2019-10-14 08:51:36 +02:00
}
if t.Query.Block {
query.Filters = blockFilter
}
2019-10-14 08:51:36 +02:00
insert := qcode.InsertConfig{
2019-10-25 07:39:59 +02:00
Filters: t.Insert.Filters,
2019-10-14 08:51:36 +02:00
Columns: t.Insert.Columns,
Set: t.Insert.Set,
}
if t.Query.Block {
insert.Filters = blockFilter
}
2019-10-14 08:51:36 +02:00
update := qcode.UpdateConfig{
2019-10-25 07:39:59 +02:00
Filters: t.Insert.Filters,
2019-10-14 08:51:36 +02:00
Columns: t.Insert.Columns,
Set: t.Insert.Set,
}
2019-03-24 14:57:29 +01:00
if t.Query.Block {
update.Filters = blockFilter
}
2019-10-14 08:51:36 +02:00
delete := qcode.DeleteConfig{
2019-10-25 07:39:59 +02:00
Filters: t.Insert.Filters,
2019-10-14 08:51:36 +02:00
Columns: t.Insert.Columns,
}
if t.Query.Block {
delete.Filters = blockFilter
}
2019-10-14 08:51:36 +02:00
qc.AddRole(r.Name, t.Name, qcode.TRConfig{
Query: query,
Insert: insert,
Update: update,
Delete: delete,
})
}
2019-03-24 14:57:29 +01:00
}
2019-04-08 08:47:59 +02:00
pc := psql.NewCompiler(psql.Config{
Schema: schema,
Vars: c.DB.Vars,
2019-04-08 08:47:59 +02:00
})
2019-03-24 14:57:29 +01:00
2019-04-08 08:47:59 +02:00
return qc, pc, nil
2019-03-24 14:57:29 +01:00
}
func initWatcher(cpath string) {
2019-09-08 20:56:32 +02:00
if conf.WatchAndReload == false {
return
}
var d dir
if len(cpath) == 0 || cpath == "./" {
2019-09-08 20:56:32 +02:00
d = Dir("./config", ReExec)
} else {
d = Dir(cpath, ReExec)
2019-09-08 20:56:32 +02:00
}
go func() {
err := Do(logger.Printf, d)
if err != nil {
logger.Fatal().Err(err).Send()
2019-09-08 20:56:32 +02:00
}
}()
}
2019-05-13 01:27:26 +02:00
func startHTTP() {
2019-07-30 07:38:05 +02:00
hp := strings.SplitN(conf.HostPort, ":", 2)
if len(conf.Host) != 0 {
hp[0] = conf.Host
}
if len(conf.Port) != 0 {
hp[1] = conf.Port
}
hostPort := fmt.Sprintf("%s:%s", hp[0], hp[1])
2019-05-13 01:27:26 +02:00
srv := &http.Server{
2019-07-30 07:38:05 +02:00
Addr: hostPort,
2019-05-13 01:27:26 +02:00
Handler: routeHandler(),
ReadTimeout: 5 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
idleConnsClosed := make(chan struct{})
go func() {
sigint := make(chan os.Signal, 1)
signal.Notify(sigint, os.Interrupt)
<-sigint
if err := srv.Shutdown(context.Background()); err != nil {
logger.Error().Err(err).Msg("shutdown signal received")
2019-05-13 01:27:26 +02:00
}
close(idleConnsClosed)
}()
srv.RegisterOnShutdown(func() {
2019-09-26 06:35:31 +02:00
db.Close()
2019-05-13 01:27:26 +02:00
})
2019-07-30 07:38:05 +02:00
fmt.Printf("%s listening on %s (%s)\n", serverName, hostPort, conf.Env)
2019-05-13 01:27:26 +02:00
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
logger.Error().Err(err).Msg("server closed")
2019-05-13 01:27:26 +02:00
}
<-idleConnsClosed
}
2019-03-24 14:57:29 +01:00
2019-05-13 01:27:26 +02:00
func routeHandler() http.Handler {
mux := http.NewServeMux()
mux.Handle("/api/v1/graphql", withAuth(apiv1Http))
2019-04-08 08:47:59 +02:00
if conf.WebUI {
mux.Handle("/", http.FileServer(rice.MustFindBox("../web/build").HTTPBox()))
2019-03-24 14:57:29 +01:00
}
2019-05-13 01:27:26 +02:00
fn := func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Server", serverName)
mux.ServeHTTP(w, r)
}
2019-04-08 08:47:59 +02:00
2019-05-13 01:27:26 +02:00
return http.HandlerFunc(fn)
2019-04-08 08:47:59 +02:00
}
func getConfigName() string {
2019-09-29 07:49:13 +02:00
if len(os.Getenv("GO_ENV")) == 0 {
return "dev"
}
2019-04-08 08:47:59 +02:00
ge := strings.ToLower(os.Getenv("GO_ENV"))
switch {
case strings.HasPrefix(ge, "pro"):
return "prod"
case strings.HasPrefix(ge, "sta"):
return "stage"
case strings.HasPrefix(ge, "tes"):
return "test"
2019-09-28 17:34:03 +02:00
case strings.HasPrefix(ge, "dev"):
return "dev"
2019-04-08 08:47:59 +02:00
}
2019-09-28 17:34:03 +02:00
return ge
2019-04-08 08:47:59 +02:00
}
func getAuthFailBlock(c *config) int {
switch c.AuthFailBlock {
case "always":
return authFailBlockAlways
case "per_query", "perquery", "query":
return authFailBlockPerQuery
case "never", "false":
return authFailBlockNever
}
2019-03-24 14:57:29 +01:00
2019-04-08 08:47:59 +02:00
return authFailBlockAlways
2019-03-24 14:57:29 +01:00
}