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"
|
2020-04-24 07:23:35 +02:00
|
|
|
"path"
|
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
|
|
|
|
2019-09-27 08:19:24 +02:00
|
|
|
rice "github.com/GeertJohan/go.rice"
|
2019-12-31 07:30:20 +01:00
|
|
|
"github.com/NYTimes/gziphandler"
|
2020-04-16 06:26:32 +02:00
|
|
|
"github.com/dosco/super-graph/internal/serv/internal/auth"
|
2020-05-24 08:24:24 +02:00
|
|
|
"go.opencensus.io/plugin/ochttp"
|
|
|
|
)
|
|
|
|
|
|
|
|
var (
|
|
|
|
apiRoute string = "/api/v1/graphql"
|
2019-03-24 14:57:29 +01:00
|
|
|
)
|
|
|
|
|
2020-04-10 08:27:43 +02:00
|
|
|
func initWatcher() {
|
2020-04-11 08:45:06 +02:00
|
|
|
cpath := conf.cpath
|
2020-01-19 09:12:51 +01:00
|
|
|
if conf != nil && !conf.WatchAndReload {
|
2019-09-08 20:56:32 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
var d dir
|
2019-09-27 08:19:24 +02:00
|
|
|
if len(cpath) == 0 || cpath == "./" {
|
2019-09-08 20:56:32 +02:00
|
|
|
d = Dir("./config", ReExec)
|
|
|
|
} else {
|
2019-09-27 08:19:24 +02:00
|
|
|
d = Dir(cpath, ReExec)
|
2019-09-08 20:56:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
go func() {
|
2020-04-10 08:27:43 +02:00
|
|
|
err := Do(log.Printf, d)
|
2019-09-08 20:56:32 +02:00
|
|
|
if err != nil {
|
2020-04-10 08:27:43 +02:00
|
|
|
log.Fatalf("ERR %s", err)
|
2019-09-08 20:56:32 +02:00
|
|
|
}
|
|
|
|
}()
|
|
|
|
}
|
|
|
|
|
2019-05-13 01:27:26 +02:00
|
|
|
func startHTTP() {
|
2020-01-19 09:12:51 +01:00
|
|
|
var appName string
|
2019-07-30 07:38:05 +02:00
|
|
|
|
2020-01-19 09:12:51 +01:00
|
|
|
defaultHP := "0.0.0.0:8080"
|
|
|
|
env := os.Getenv("GO_ENV")
|
|
|
|
|
|
|
|
if conf != nil {
|
|
|
|
appName = conf.AppName
|
|
|
|
hp := strings.SplitN(conf.HostPort, ":", 2)
|
|
|
|
|
|
|
|
if len(hp) == 2 {
|
|
|
|
if len(conf.Host) != 0 {
|
|
|
|
hp[0] = conf.Host
|
|
|
|
}
|
2019-07-30 07:38:05 +02:00
|
|
|
|
2020-01-19 09:12:51 +01:00
|
|
|
if len(conf.Port) != 0 {
|
|
|
|
hp[1] = conf.Port
|
|
|
|
}
|
|
|
|
|
2020-05-23 17:43:57 +02:00
|
|
|
conf.hostPort = fmt.Sprintf("%s:%s", hp[0], hp[1])
|
2020-01-19 09:12:51 +01:00
|
|
|
}
|
2019-07-30 07:38:05 +02:00
|
|
|
}
|
|
|
|
|
2020-05-23 17:43:57 +02:00
|
|
|
if len(conf.hostPort) == 0 {
|
|
|
|
conf.hostPort = defaultHP
|
2020-01-19 09:12:51 +01:00
|
|
|
}
|
2019-07-30 07:38:05 +02:00
|
|
|
|
2020-02-03 07:21:07 +01:00
|
|
|
routes, err := routeHandler()
|
|
|
|
if err != nil {
|
2020-04-10 08:27:43 +02:00
|
|
|
log.Fatalf("ERR %s", err)
|
2020-02-03 07:21:07 +01:00
|
|
|
}
|
|
|
|
|
2019-05-13 01:27:26 +02:00
|
|
|
srv := &http.Server{
|
2020-05-23 17:43:57 +02:00
|
|
|
Addr: conf.hostPort,
|
2020-02-03 07:21:07 +01:00
|
|
|
Handler: routes,
|
2019-05-13 01:27:26 +02:00
|
|
|
ReadTimeout: 5 * time.Second,
|
|
|
|
WriteTimeout: 10 * time.Second,
|
|
|
|
MaxHeaderBytes: 1 << 20,
|
|
|
|
}
|
|
|
|
|
2020-05-24 08:24:24 +02:00
|
|
|
if conf.telemetryEnabled() {
|
|
|
|
srv.Handler = &ochttp.Handler{Handler: routes}
|
|
|
|
}
|
|
|
|
|
2019-05-13 01:27:26 +02:00
|
|
|
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 {
|
2020-04-10 08:27:43 +02:00
|
|
|
log.Fatalln("INF shutdown signal received")
|
2019-05-13 01:27:26 +02:00
|
|
|
}
|
|
|
|
close(idleConnsClosed)
|
|
|
|
}()
|
|
|
|
|
|
|
|
srv.RegisterOnShutdown(func() {
|
2020-05-23 17:43:57 +02:00
|
|
|
if conf.closeFn != nil {
|
|
|
|
conf.closeFn()
|
|
|
|
}
|
2019-09-26 06:35:31 +02:00
|
|
|
db.Close()
|
2020-05-23 17:43:57 +02:00
|
|
|
log.Fatalln("INF shutdown complete")
|
2019-05-13 01:27:26 +02:00
|
|
|
})
|
|
|
|
|
2020-05-23 17:43:57 +02:00
|
|
|
log.Printf("INF Super Graph started, version: %s, git-branch: %s, host-port: %s, app-name: %s, env: %s\n",
|
|
|
|
version, gitBranch, conf.hostPort, appName, env)
|
2019-05-13 01:27:26 +02:00
|
|
|
|
|
|
|
if err := srv.ListenAndServe(); err != http.ErrServerClosed {
|
2020-04-10 08:27:43 +02:00
|
|
|
log.Fatalln("INF server closed")
|
2019-05-13 01:27:26 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
<-idleConnsClosed
|
|
|
|
}
|
2019-03-24 14:57:29 +01:00
|
|
|
|
2020-02-03 07:21:07 +01:00
|
|
|
func routeHandler() (http.Handler, error) {
|
2020-05-23 17:43:57 +02:00
|
|
|
var err error
|
2020-02-03 07:21:07 +01:00
|
|
|
mux := http.NewServeMux()
|
2019-05-13 01:27:26 +02:00
|
|
|
|
2020-02-03 07:21:07 +01:00
|
|
|
if conf == nil {
|
|
|
|
return mux, nil
|
2019-12-31 07:30:20 +01:00
|
|
|
}
|
2019-12-09 07:59:30 +01:00
|
|
|
|
2020-04-24 07:23:35 +02:00
|
|
|
if len(conf.APIPath) != 0 {
|
|
|
|
apiRoute = path.Join("/", conf.APIPath, "/v1/graphql")
|
|
|
|
}
|
|
|
|
|
2020-02-03 07:21:07 +01:00
|
|
|
routes := map[string]http.Handler{
|
2020-04-24 07:23:35 +02:00
|
|
|
"/health": http.HandlerFunc(health),
|
|
|
|
apiRoute: apiV1Handler(),
|
2020-02-03 07:21:07 +01:00
|
|
|
}
|
2019-11-15 07:35:19 +01:00
|
|
|
|
2020-02-03 07:21:07 +01:00
|
|
|
if err := setActionRoutes(routes); err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
if conf.WebUI {
|
2020-04-10 08:27:43 +02:00
|
|
|
routes["/"] = http.FileServer(rice.MustFindBox("./web/build").HTTPBox())
|
2020-02-03 07:21:07 +01:00
|
|
|
}
|
2020-01-19 09:12:51 +01:00
|
|
|
|
2020-02-03 07:21:07 +01:00
|
|
|
if conf.HTTPGZip {
|
|
|
|
gz := gziphandler.MustNewGzipLevelHandler(6)
|
|
|
|
for k, v := range routes {
|
|
|
|
routes[k] = gz(v)
|
2020-01-19 09:12:51 +01:00
|
|
|
}
|
2019-03-24 14:57:29 +01:00
|
|
|
}
|
|
|
|
|
2020-02-03 07:21:07 +01:00
|
|
|
for k, v := range routes {
|
|
|
|
mux.Handle(k, v)
|
|
|
|
}
|
|
|
|
|
2020-05-23 17:43:57 +02:00
|
|
|
if conf.telemetryEnabled() {
|
|
|
|
conf.closeFn, err = enableObservability(mux)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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
|
|
|
|
2020-02-03 07:21:07 +01:00
|
|
|
return http.HandlerFunc(fn), nil
|
2019-04-08 08:47:59 +02:00
|
|
|
}
|
|
|
|
|
2020-02-03 07:21:07 +01:00
|
|
|
func setActionRoutes(routes map[string]http.Handler) error {
|
|
|
|
var err error
|
2019-04-08 08:47:59 +02:00
|
|
|
|
2020-02-03 07:21:07 +01:00
|
|
|
for _, a := range conf.Actions {
|
|
|
|
var fn http.Handler
|
2019-04-08 08:47:59 +02:00
|
|
|
|
2020-04-10 08:27:43 +02:00
|
|
|
fn, err = newAction(&a)
|
2020-02-03 07:21:07 +01:00
|
|
|
if err != nil {
|
|
|
|
break
|
|
|
|
}
|
2019-04-08 08:47:59 +02:00
|
|
|
|
2020-02-03 07:21:07 +01:00
|
|
|
p := fmt.Sprintf("/api/v1/actions/%s", strings.ToLower(a.Name))
|
2019-09-28 17:34:03 +02:00
|
|
|
|
2020-04-10 08:27:43 +02:00
|
|
|
if ac := findAuth(a.AuthName); ac != nil {
|
|
|
|
routes[p], err = auth.WithAuth(fn, ac)
|
2020-02-03 07:21:07 +01:00
|
|
|
} else {
|
|
|
|
routes[p] = fn
|
|
|
|
}
|
2020-04-10 08:27:43 +02:00
|
|
|
|
2020-05-24 08:24:24 +02:00
|
|
|
if conf.telemetryEnabled() {
|
|
|
|
routes[p] = ochttp.WithRouteTag(routes[p], p)
|
|
|
|
}
|
|
|
|
|
2020-04-10 08:27:43 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2019-04-08 08:47:59 +02:00
|
|
|
}
|
2020-02-03 07:21:07 +01:00
|
|
|
return nil
|
2019-04-08 08:47:59 +02:00
|
|
|
}
|
2020-01-19 09:12:51 +01:00
|
|
|
|
2020-04-11 08:45:06 +02:00
|
|
|
func findAuth(name string) *auth.Auth {
|
2020-02-03 07:21:07 +01:00
|
|
|
for _, a := range conf.Auths {
|
|
|
|
if strings.EqualFold(a.Name, name) {
|
2020-04-10 08:27:43 +02:00
|
|
|
return &a
|
2020-02-03 07:21:07 +01:00
|
|
|
}
|
|
|
|
}
|
2020-04-10 08:27:43 +02:00
|
|
|
return nil
|
2020-01-19 09:12:51 +01:00
|
|
|
}
|