mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Added support for hooks to customize behavior.
This commit is contained in:
@@ -3,13 +3,16 @@ package server
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/iron-io/functions/api/models"
|
||||
titancommon "github.com/iron-io/titan/common"
|
||||
)
|
||||
|
||||
func handleAppCreate(c *gin.Context) {
|
||||
log := c.MustGet("log").(logrus.FieldLogger)
|
||||
ctx := c.MustGet("ctx").(context.Context)
|
||||
log := titancommon.Logger(ctx)
|
||||
|
||||
wapp := &models.AppWrapper{}
|
||||
|
||||
@@ -32,12 +35,26 @@ func handleAppCreate(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
err = Api.FireBeforeAppUpdate(ctx, wapp.App)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorln(models.ErrAppsCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(err))
|
||||
return
|
||||
}
|
||||
|
||||
app, err := Api.Datastore.StoreApp(wapp.App)
|
||||
if err != nil {
|
||||
log.WithError(err).Debug(models.ErrAppsCreate)
|
||||
log.WithError(err).Errorln(models.ErrAppsCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(models.ErrAppsCreate))
|
||||
return
|
||||
}
|
||||
|
||||
err = Api.FireAfterAppUpdate(ctx, wapp.App)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorln(models.ErrAppsCreate)
|
||||
c.JSON(http.StatusInternalServerError, simpleError(err))
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, app)
|
||||
}
|
||||
|
||||
@@ -3,13 +3,16 @@ package server
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/iron-io/functions/api/models"
|
||||
titancommon "github.com/iron-io/titan/common"
|
||||
)
|
||||
|
||||
func handleAppDelete(c *gin.Context) {
|
||||
log := c.MustGet("log").(logrus.FieldLogger)
|
||||
ctx := c.MustGet("ctx").(context.Context)
|
||||
log := titancommon.Logger(ctx)
|
||||
|
||||
appName := c.Param("app")
|
||||
err := Api.Datastore.RemoveApp(appName)
|
||||
|
||||
@@ -3,13 +3,16 @@ package server
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/iron-io/functions/api/models"
|
||||
titancommon "github.com/iron-io/titan/common"
|
||||
)
|
||||
|
||||
func handleAppGet(c *gin.Context) {
|
||||
log := c.MustGet("log").(logrus.FieldLogger)
|
||||
ctx := c.MustGet("ctx").(context.Context)
|
||||
log := titancommon.Logger(ctx)
|
||||
|
||||
appName := c.Param("app")
|
||||
app, err := Api.Datastore.GetApp(appName)
|
||||
|
||||
@@ -3,13 +3,16 @@ package server
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/iron-io/functions/api/models"
|
||||
titancommon "github.com/iron-io/titan/common"
|
||||
)
|
||||
|
||||
func handleAppList(c *gin.Context) {
|
||||
log := c.MustGet("log").(logrus.FieldLogger)
|
||||
ctx := c.MustGet("ctx").(context.Context)
|
||||
log := titancommon.Logger(ctx)
|
||||
|
||||
filter := &models.AppFilter{}
|
||||
|
||||
|
||||
@@ -3,13 +3,16 @@ package server
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/iron-io/functions/api/models"
|
||||
titancommon "github.com/iron-io/titan/common"
|
||||
)
|
||||
|
||||
func handleAppUpdate(c *gin.Context) {
|
||||
log := c.MustGet("log").(logrus.FieldLogger)
|
||||
ctx := c.MustGet("ctx").(context.Context)
|
||||
log := titancommon.Logger(ctx)
|
||||
|
||||
app := &models.App{}
|
||||
|
||||
|
||||
@@ -3,13 +3,16 @@ package server
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/iron-io/functions/api/models"
|
||||
titancommon "github.com/iron-io/titan/common"
|
||||
)
|
||||
|
||||
func handleRouteCreate(c *gin.Context) {
|
||||
log := c.MustGet("log").(logrus.FieldLogger)
|
||||
ctx := c.MustGet("ctx").(context.Context)
|
||||
log := titancommon.Logger(ctx)
|
||||
|
||||
var wroute models.RouteWrapper
|
||||
|
||||
|
||||
@@ -3,13 +3,16 @@ package server
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/iron-io/functions/api/models"
|
||||
titancommon "github.com/iron-io/titan/common"
|
||||
)
|
||||
|
||||
func handleRouteDelete(c *gin.Context) {
|
||||
log := c.MustGet("log").(logrus.FieldLogger)
|
||||
ctx := c.MustGet("ctx").(context.Context)
|
||||
log := titancommon.Logger(ctx)
|
||||
|
||||
appName := c.Param("app")
|
||||
routeName := c.Param("route")
|
||||
|
||||
@@ -3,13 +3,17 @@ package server
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/iron-io/functions/api/models"
|
||||
titancommon "github.com/iron-io/titan/common"
|
||||
)
|
||||
|
||||
func handleRouteGet(c *gin.Context) {
|
||||
log := c.MustGet("log").(logrus.FieldLogger)
|
||||
ctx := c.MustGet("ctx").(context.Context)
|
||||
log := titancommon.Logger(ctx)
|
||||
|
||||
appName := c.Param("app")
|
||||
routeName := c.Param("route")
|
||||
|
||||
@@ -3,13 +3,17 @@ package server
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/iron-io/functions/api/models"
|
||||
titancommon "github.com/iron-io/titan/common"
|
||||
)
|
||||
|
||||
func handleRouteList(c *gin.Context) {
|
||||
log := c.MustGet("log").(logrus.FieldLogger)
|
||||
ctx := c.MustGet("ctx").(context.Context)
|
||||
log := titancommon.Logger(ctx)
|
||||
|
||||
appName := c.Param("app")
|
||||
|
||||
|
||||
@@ -3,13 +3,16 @@ package server
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/iron-io/functions/api/models"
|
||||
titancommon "github.com/iron-io/titan/common"
|
||||
)
|
||||
|
||||
func handleRouteUpdate(c *gin.Context) {
|
||||
log := c.MustGet("log").(logrus.FieldLogger)
|
||||
ctx := c.MustGet("ctx").(context.Context)
|
||||
log := titancommon.Logger(ctx)
|
||||
|
||||
var wroute models.RouteWrapper
|
||||
|
||||
|
||||
@@ -7,25 +7,40 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"encoding/json"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/iron-io/functions/api/models"
|
||||
"github.com/iron-io/functions/api/runner"
|
||||
titancommon "github.com/iron-io/titan/common"
|
||||
"github.com/satori/go.uuid"
|
||||
)
|
||||
|
||||
func handleSpecial(c *gin.Context) {
|
||||
ctx := c.MustGet("ctx").(context.Context)
|
||||
log := titancommon.Logger(ctx)
|
||||
|
||||
err := Api.UseSpecialHandlers(c)
|
||||
if err != nil {
|
||||
log.WithError(err).Errorln("Error using special handler!")
|
||||
// todo: what do we do here?
|
||||
}
|
||||
}
|
||||
|
||||
func handleRunner(c *gin.Context) {
|
||||
if strings.HasPrefix(c.Request.URL.Path, "/v1") {
|
||||
c.Status(http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
log := c.MustGet("log").(logrus.FieldLogger)
|
||||
ctx := c.MustGet("ctx").(context.Context)
|
||||
log := titancommon.Logger(ctx)
|
||||
|
||||
reqID := uuid.NewV5(uuid.Nil, fmt.Sprintf("%s%s%d", c.Request.RemoteAddr, c.Request.URL.Path, time.Now().Unix())).String()
|
||||
c.Set("reqID", reqID)
|
||||
c.Set("reqID", reqID) // todo: put this in the ctx instead of gin's
|
||||
|
||||
log = log.WithFields(logrus.Fields{"request_id": reqID})
|
||||
|
||||
@@ -54,8 +69,17 @@ func handleRunner(c *gin.Context) {
|
||||
|
||||
appName := c.Param("app")
|
||||
if appName == "" {
|
||||
host := strings.Split(c.Request.Host, ":")[0]
|
||||
appName = strings.Split(host, ".")[0]
|
||||
// check context, app can be added via special handlers
|
||||
a, ok := c.Get("app")
|
||||
if ok {
|
||||
appName = a.(string)
|
||||
}
|
||||
}
|
||||
// if still no appName, we gotta exit
|
||||
if appName == "" {
|
||||
log.WithError(err).Error(models.ErrAppsNotFound)
|
||||
c.JSON(http.StatusBadRequest, simpleError(models.ErrAppsNotFound))
|
||||
return
|
||||
}
|
||||
|
||||
route := c.Param("route")
|
||||
|
||||
@@ -3,17 +3,25 @@ package server
|
||||
import (
|
||||
"path"
|
||||
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/Sirupsen/logrus"
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/iron-io/functions/api/ifaces"
|
||||
"github.com/iron-io/functions/api/models"
|
||||
titancommon "github.com/iron-io/titan/common"
|
||||
)
|
||||
|
||||
// Would be nice to not have this is a global, but hard to pass things around to the
|
||||
// handlers in Gin without it.
|
||||
var Api *Server
|
||||
|
||||
type Server struct {
|
||||
Router *gin.Engine
|
||||
Config *models.Config
|
||||
Datastore models.Datastore
|
||||
Router *gin.Engine
|
||||
Config *models.Config
|
||||
Datastore models.Datastore
|
||||
AppListeners []ifaces.AppListener
|
||||
SpecialHandlers []ifaces.SpecialHandler
|
||||
}
|
||||
|
||||
func New(ds models.Datastore, config *models.Config) *Server {
|
||||
@@ -25,6 +33,49 @@ func New(ds models.Datastore, config *models.Config) *Server {
|
||||
return Api
|
||||
}
|
||||
|
||||
// AddAppListener adds a listener that will be notified on App changes.
|
||||
func (s *Server) AddAppListener(listener ifaces.AppListener) {
|
||||
s.AppListeners = append(s.AppListeners, listener)
|
||||
}
|
||||
|
||||
func (s *Server) FireBeforeAppUpdate(ctx context.Context, app *models.App) error {
|
||||
for _, l := range s.AppListeners {
|
||||
err := l.BeforeAppUpdate(ctx, app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) FireAfterAppUpdate(ctx context.Context, app *models.App) error {
|
||||
for _, l := range s.AppListeners {
|
||||
err := l.AfterAppUpdate(ctx, app)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) AddSpecialHandler(handler ifaces.SpecialHandler) {
|
||||
s.SpecialHandlers = append(s.SpecialHandlers, handler)
|
||||
}
|
||||
|
||||
func (s *Server) UseSpecialHandlers(ginC *gin.Context) error {
|
||||
c := &SpecialHandlerContext{
|
||||
server: s,
|
||||
ginContext: ginC,
|
||||
}
|
||||
for _, l := range s.SpecialHandlers {
|
||||
err := l.Handle(c)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func extractFields(c *gin.Context) logrus.Fields {
|
||||
fields := logrus.Fields{"action": path.Base(c.HandlerName())}
|
||||
for _, param := range c.Params {
|
||||
@@ -33,9 +84,11 @@ func extractFields(c *gin.Context) logrus.Fields {
|
||||
return fields
|
||||
}
|
||||
|
||||
func (s *Server) Run() {
|
||||
func (s *Server) Run(ctx context.Context) {
|
||||
|
||||
s.Router.Use(func(c *gin.Context) {
|
||||
c.Set("log", logrus.WithFields(extractFields(c)))
|
||||
ctx, _ := titancommon.LoggerWithFields(ctx, extractFields(c))
|
||||
c.Set("ctx", ctx)
|
||||
c.Next()
|
||||
})
|
||||
|
||||
@@ -66,11 +119,12 @@ func bindHandlers(engine *gin.Engine) {
|
||||
apps.PUT("/routes/*route", handleRouteUpdate)
|
||||
apps.DELETE("/routes/*route", handleRouteDelete)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
engine.Any("/r/:app/*route", handleRunner)
|
||||
engine.NoRoute(handleRunner)
|
||||
|
||||
// This final route is used for extensions, see Server.Add
|
||||
engine.NoRoute(handleSpecial)
|
||||
}
|
||||
|
||||
func simpleError(err error) *models.Error {
|
||||
|
||||
28
api/server/special_handler_context.go
Normal file
28
api/server/special_handler_context.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/iron-io/functions/api/models"
|
||||
)
|
||||
|
||||
type SpecialHandlerContext struct {
|
||||
server *Server
|
||||
ginContext *gin.Context
|
||||
}
|
||||
|
||||
func (c *SpecialHandlerContext) Request() *http.Request {
|
||||
return c.ginContext.Request
|
||||
}
|
||||
|
||||
func (c *SpecialHandlerContext) Datastore() models.Datastore {
|
||||
return c.server.Datastore
|
||||
}
|
||||
|
||||
func (c *SpecialHandlerContext) Set(key string, value interface{}) {
|
||||
c.ginContext.Set(key, value)
|
||||
}
|
||||
func (c *SpecialHandlerContext) Get(key string) (value interface{}, exists bool) {
|
||||
return c.ginContext.Get(key)
|
||||
}
|
||||
@@ -6,6 +6,9 @@ import (
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// Version of IronFunctions
|
||||
var Version = "0.0.1"
|
||||
|
||||
func handleVersion(c *gin.Context) {
|
||||
c.JSON(http.StatusNotImplemented, "Not Implemented")
|
||||
c.JSON(http.StatusOK, gin.H{"version": Version})
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user