refactored totally, but now exits and doesn't serve for some reason

This commit is contained in:
Jeffrey Paul 2019-11-08 21:30:54 -08:00
parent 6c9b82a10c
commit 297b8f4e1a
5 changed files with 115 additions and 140 deletions

View File

@ -1,5 +0,0 @@
runtime: custom
env: flex
includes:
- prod-secrets.yaml

View File

@ -1,13 +1,13 @@
//3456789112345676892123456789312345678941234567895123456789612345678971234567898
package main package main
import "time"
import "os" import "os"
import "sync"
import "time"
import "github.com/rs/zerolog" import "github.com/rs/zerolog"
import "github.com/rs/zerolog/log" import "github.com/rs/zerolog/log"
import "golang.org/x/crypto/ssh/terminal"
import "github.com/sneak/merp" import "github.com/sneak/merp"
import "golang.org/x/crypto/ssh/terminal"
//revive:disable //revive:disable
var Version string var Version string
@ -21,7 +21,16 @@ var Appname string
func main() { func main() {
initLogging() initLogging()
identify() identify()
merp.ServeForever() var wg sync.WaitGroup
wg.Add(1)
go func() {
ms := merp.NewMerpServer()
ms.ServeForever()
wg.Done()
}()
wg.Wait()
} }
func identify() { func identify() {

View File

@ -1,62 +1,48 @@
package models package merp
import "os" import "os"
import "time" import "time"
import "github.com/astaxie/beego/orm" import "github.com/astaxie/beego/orm"
import "github.com/sneak/merp/models"
import "github.com/rs/zerolog/log" import "github.com/rs/zerolog/log"
import _ "github.com/lib/pq" //revive:disable-line import _ "github.com/lib/pq" //revive:disable-line
var ormObject orm.Ormer func GetDB() orm.Ormer {
func initialize() {
if os.Getenv("DEBUG") != "" { if os.Getenv("DEBUG") != "" {
orm.Debug = true orm.Debug = true
} }
connectToDb() o := connectDB()
syncDB() syncDB(o)
return o
} }
// ConnectToDb - Initializes the ORM and Connection to the postgres DB // ConnectToDb - Initializes the ORM and Connection to the postgres DB
func connectToDb() { func connectDB() orm.Ormer {
orm.DefaultTimeLoc = time.UTC orm.DefaultTimeLoc = time.UTC
dbURL := os.Getenv("POSTGRES_DB_URL") dbURL := os.Getenv("POSTGRES_DB_URL")
orm.RegisterDriver("postgres", orm.DRPostgres) orm.RegisterDriver("postgres", orm.DRPostgres)
orm.RegisterDataBase("default", "postgres", dbURL) orm.RegisterDataBase("default", "postgres", dbURL)
orm.SetMaxIdleConns("default", 1) orm.SetMaxIdleConns("default", 1)
orm.SetMaxOpenConns("default", 5) orm.SetMaxOpenConns("default", 5)
orm.RegisterModel(new(models.Merp))
orm.RegisterModel(new(Merp)) o := orm.NewOrm()
ormObject = orm.NewOrm() o.Using("default")
ormObject.Using("default") return o
} }
// SyncDB() is responsible for creating the schema in the database // SyncDB() is responsible for creating the schema in the database
func syncDB() { func syncDB(o orm.Ormer) {
// Database alias. // Database alias.
name := "default" name := "default"
// Drop table and re-create. // Drop table and re-create.
force := false force := false
// Print log. // Print log.
verbose := true verbose := true
// Error. // Error.
err := orm.RunSyncdb(name, force, verbose) err := orm.RunSyncdb(name, force, verbose)
if err != nil { if err != nil {
log.Fatal().Msg(err.Error()) log.Fatal().Msg(err.Error())
} }
} }
// GetOrmObject - Getter function for the ORM object with which we can query the database
func GetOrmObject() orm.Ormer {
if ormObject == nil {
initialize()
}
return ormObject
}

71
merp.go
View File

@ -2,7 +2,6 @@ package merp
import "encoding/json" import "encoding/json"
import "net/http" import "net/http"
import "regexp"
import "time" import "time"
import "github.com/astaxie/beego/orm" import "github.com/astaxie/beego/orm"
@ -11,34 +10,21 @@ import "github.com/google/uuid"
import "github.com/rs/zerolog/log" import "github.com/rs/zerolog/log"
import "github.com/sneak/merp/models" import "github.com/sneak/merp/models"
func thingRegex() *regexp.Regexp { func decodeJSON(in []byte) (interface{}, error) {
ThingRegex, e := regexp.Compile(`^[a-zA-Z0-9\_\-]+$`)
if e != nil {
panic(e)
}
return ThingRegex
}
func decodeJSON(in []byte) interface{} {
var out interface{} var out interface{}
err := json.Unmarshal(in, &out) err := json.Unmarshal(in, &out)
if err != nil { if err != nil {
log.Error().Msg("error decoding json") log.Error().Msg("error decoding json")
return nil return nil, err
} }
return out return out, nil
} }
func getLatestMerps() gin.HandlerFunc { func (ms *MerpServer) getLatestMerps() gin.HandlerFunc {
ThingRegex := thingRegex() return func(c *gin.Context) {
o := models.GetOrmObject()
h := func(c *gin.Context) {
thing := c.Param("thing") thing := c.Param("thing")
if thing != "" { if thing != "" {
if ThingRegex.MatchString(thing) == false { if ms.thingRegex.MatchString(thing) == false {
c.JSON(http.StatusPreconditionFailed, gin.H{ c.JSON(http.StatusPreconditionFailed, gin.H{
"this": "failed", "this": "failed",
"status": http.StatusPreconditionFailed, "status": http.StatusPreconditionFailed,
@ -50,9 +36,9 @@ func getLatestMerps() gin.HandlerFunc {
var qs orm.QuerySeter var qs orm.QuerySeter
if thing == "" { if thing == "" {
qs = o.QueryTable("merp").OrderBy("-created").Limit(50) qs = ms.db.QueryTable("merp").OrderBy("-created").Limit(50)
} else { } else {
qs = o.QueryTable("merp").Filter("thing", thing).OrderBy("-created").Limit(50) qs = ms.db.QueryTable("merp").Filter("thing", thing).OrderBy("-created").Limit(50)
} }
var merps []*models.Merp var merps []*models.Merp
@ -62,8 +48,8 @@ func getLatestMerps() gin.HandlerFunc {
for _, merp := range merps { for _, merp := range merps {
outelem := make(map[string]interface{}) outelem := make(map[string]interface{})
outelem["thing"] = merp.Thing outelem["thing"] = merp.Thing
outjs := decodeJSON([]byte(merp.Content)) outjs, err := decodeJSON([]byte(merp.Content))
if outjs == nil { if err != nil {
outelem["content"] = gin.H{} outelem["content"] = gin.H{}
} else { } else {
outelem["content"] = outjs outelem["content"] = outjs
@ -79,40 +65,13 @@ func getLatestMerps() gin.HandlerFunc {
"with": output, "with": output,
}) })
} }
return h
} }
func getLatestMerp() gin.HandlerFunc { func (ms *MerpServer) handleNewMerp() gin.HandlerFunc {
ThingRegex := thingRegex() return func(c *gin.Context) {
h := func(c *gin.Context) {
thing := c.Param("thing")
if ThingRegex.MatchString(thing) == false {
c.JSON(http.StatusPreconditionFailed, gin.H{
"this": "failed",
"status": http.StatusPreconditionFailed,
"because": "invalid thing format, try [a-zA-Z0-9-_]",
})
return
}
c.JSON(http.StatusOK, gin.H{
"this": "succeeded",
})
}
return h
}
func handleNewMerp() gin.HandlerFunc {
// server startup time
ThingRegex := thingRegex()
// establish db connection *first*, before requests
orm := models.GetOrmObject()
h := func(c *gin.Context) {
// request time // request time
thing := c.Param("thing") thing := c.Param("thing")
if ThingRegex.MatchString(thing) == false { if ms.thingRegex.MatchString(thing) == false {
c.JSON(http.StatusPreconditionFailed, gin.H{ c.JSON(http.StatusPreconditionFailed, gin.H{
"this": "failed", "this": "failed",
"status": http.StatusPreconditionFailed, "status": http.StatusPreconditionFailed,
@ -159,7 +118,7 @@ func handleNewMerp() gin.HandlerFunc {
UUID: u.String(), UUID: u.String(),
} }
_, err := orm.Insert(&merp) _, err := ms.db.Insert(&merp)
if err != nil { if err != nil {
c.JSON( c.JSON(
@ -185,6 +144,4 @@ func handleNewMerp() gin.HandlerFunc {
}, },
}) })
} }
return h
} }

122
server.go
View File

@ -1,27 +1,78 @@
package merp package merp
//3456789112345676892123456789312345678941234567895123456789612345678971234567898
import "encoding/json" import "encoding/json"
import "fmt" import "fmt"
import "net/http" import "net/http"
import "os" import "os"
import "regexp"
import "strconv"
import "time" import "time"
//import "github.com/rs/zerolog/log"
import "github.com/didip/tollbooth" import "github.com/didip/tollbooth"
import "github.com/didip/tollbooth_gin" import "github.com/didip/tollbooth_gin"
import "github.com/gin-gonic/gin" import "github.com/gin-gonic/gin"
import "github.com/dn365/gin-zerolog" import "github.com/dn365/gin-zerolog"
import "github.com/thoas/stats" import "github.com/thoas/stats"
// ServeForever causes merp to serve http forever import "github.com/astaxie/beego/orm"
func ServeForever() { import _ "github.com/lib/pq" //revive:disable-line
s := getServer()
s.ListenAndServe() type MerpServer struct {
db orm.Ormer
debug bool
gin *gin.Engine
port uint
server *http.Server
stats *stats.Stats
thingRegex *regexp.Regexp
} }
func getHealthCheckHandler() http.HandlerFunc { func NewMerpServer() *MerpServer {
ms := new(MerpServer)
ms.init()
return ms
}
func (ms *MerpServer) init() {
ms.thingRegex = regexp.MustCompile(`^[a-zA-Z0-9\_\-]+$`)
if os.Getenv("DEBUG") != "" {
ms.debug = true
}
ms.port = 8080
var s uint64
var err error
if os.Getenv("PORT") != "" {
if s, err = strconv.ParseUint(os.Getenv("PORT"), 10, 64); err == nil {
} else {
panic("invalid PORT in environment")
}
ms.port = uint(s)
}
ms.connectDB()
ms.setupRoutes()
ms.server = &http.Server{
Addr: fmt.Sprintf(":%s", ms.port),
Handler: ms.gin,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
}
func (ms *MerpServer) connectDB() {
ms.db = GetDB()
}
// ServeForever causes merp to serve http forever
func (ms *MerpServer) ServeForever() {
ms.server.ListenAndServe()
}
func (ms *MerpServer) HealthCheckHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
result := gin.H{ result := gin.H{
"status": "ok", "status": "ok",
@ -38,24 +89,23 @@ func getHealthCheckHandler() http.HandlerFunc {
} }
} }
func getStatsHandler(middleware *stats.Stats) http.HandlerFunc { func (ms *MerpServer) StatsHandler() http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
stats := middleware.Data() stats := ms.stats.Data()
b, _ := json.Marshal(stats) b, _ := json.Marshal(stats)
w.Write(b) w.Write(b)
} }
} }
func getRouter() *gin.Engine { func (ms *MerpServer) setupRoutes() {
if !ms.debug {
if os.Getenv("DEBUG") == "" {
gin.SetMode(gin.ReleaseMode) gin.SetMode(gin.ReleaseMode)
} }
limiter := tollbooth.NewLimiter(5, nil) limiter := tollbooth.NewLimiter(5, nil)
statsMiddleware := stats.New() ms.stats = stats.New()
// empty router // empty router
r := gin.New() r := gin.New()
@ -67,41 +117,19 @@ func getRouter() *gin.Engine {
r.Use(ginzerolog.Logger("gin")) r.Use(ginzerolog.Logger("gin"))
r.Use(func(c *gin.Context) { r.Use(func(c *gin.Context) {
beginning, recorder := statsMiddleware.Begin(c.Writer) beginning, recorder := ms.stats.Begin(c.Writer)
c.Next() c.Next()
statsMiddleware.End(beginning, stats.WithRecorder(recorder)) ms.stats.End(beginning, stats.WithRecorder(recorder))
}) })
r.GET("/.well-known/healthcheck.json", gin.WrapF(getHealthCheckHandler())) r.GET("/.well-known/healthcheck.json", gin.WrapF(ms.HealthCheckHandler()))
r.GET("/admin/healthcheck.json", gin.WrapF(getHealthCheckHandler())) r.GET("/admin/healthcheck.json", gin.WrapF(ms.HealthCheckHandler()))
r.GET("/admin/stats.json", gin.WrapF(getStatsHandler(statsMiddleware))) r.GET("/admin/stats.json", gin.WrapF(ms.StatsHandler()))
r.GET("/admin/other.json", gin.WrapF(getStatsHandler(statsMiddleware))) r.GET("/admin/other.json", gin.WrapF(ms.StatsHandler()))
r.GET("/merp/for/:thing", tollbooth_gin.LimitHandler(limiter), ms.handleNewMerp())
r.GET("/get/latest/merp/for/:thing", tollbooth_gin.LimitHandler(limiter), ms.getLatestMerps())
r.GET("/get/latest/merps", tollbooth_gin.LimitHandler(limiter), ms.getLatestMerps())
r.GET("/get/merps/for/:thing", tollbooth_gin.LimitHandler(limiter), ms.getLatestMerps())
// call it, it returns the appropriate handler function ms.gin = r
// so we can execute some code at startup time
// and not just request time
r.GET("/merp/for/:thing", tollbooth_gin.LimitHandler(limiter), handleNewMerp())
r.GET("/get/latest/merp/for/:thing", tollbooth_gin.LimitHandler(limiter), getLatestMerp())
r.GET("/get/latest/merps", tollbooth_gin.LimitHandler(limiter), getLatestMerps())
r.GET("/get/merps/for/:thing", tollbooth_gin.LimitHandler(limiter), getLatestMerps())
return r
}
func getServer() *http.Server {
r := getRouter()
port := "8080"
if os.Getenv("PORT") != "" {
port = os.Getenv("PORT")
}
s := &http.Server{
Addr: fmt.Sprintf(":%s", port),
Handler: r,
ReadTimeout: 10 * time.Second,
WriteTimeout: 10 * time.Second,
MaxHeaderBytes: 1 << 20,
}
return s
} }