mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
Fixes to recent extension changes. (#568)
* Fixes to recent extension changes. * Fixes issue where gin will continue calling the handler even if next() isn't called. * Updated docs.
This commit is contained in:
@@ -43,6 +43,12 @@ func HandleErrorResponse(ctx context.Context, w http.ResponseWriter, err error)
|
|||||||
statuscode = http.StatusInternalServerError
|
statuscode = http.StatusInternalServerError
|
||||||
err = ErrInternalServerError
|
err = ErrInternalServerError
|
||||||
}
|
}
|
||||||
|
WriteError(ctx, w, statuscode, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WriteError easy way to do standard error response, but can set statuscode and error message easier than HandleErrorResponse
|
||||||
|
func WriteError(ctx context.Context, w http.ResponseWriter, statuscode int, err error) {
|
||||||
|
log := common.Logger(ctx)
|
||||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
w.WriteHeader(statuscode)
|
w.WriteHeader(statuscode)
|
||||||
err = json.NewEncoder(w).Encode(simpleError(err))
|
err = json.NewEncoder(w).Encode(simpleError(err))
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package server
|
package server
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
"github.com/fnproject/fn/fnext"
|
"github.com/fnproject/fn/fnext"
|
||||||
@@ -10,15 +9,15 @@ import (
|
|||||||
// TODO: Move this into `github.com/fnproject/fn` package after main is moved out of root dir.
|
// TODO: Move this into `github.com/fnproject/fn` package after main is moved out of root dir.
|
||||||
var extensions = map[string]fnext.Extension{}
|
var extensions = map[string]fnext.Extension{}
|
||||||
|
|
||||||
// RegisterExtension registers the extension so it's available, but does not initialize it or anything
|
// RegisterExtension registers the extension so it's available, but does not initialize it.
|
||||||
|
// This is generally what third party extensions will use in their init() method.
|
||||||
func RegisterExtension(ext fnext.Extension) {
|
func RegisterExtension(ext fnext.Extension) {
|
||||||
extensions[ext.Name()] = ext
|
extensions[ext.Name()] = ext
|
||||||
}
|
}
|
||||||
|
|
||||||
// AddExtensionByName This essentially just makes sure the extensions are ordered properly.
|
// AddExtensionByName This essentially just makes sure the extensions are ordered properly and is
|
||||||
// It could do some initialization if required too.
|
// what the CLI uses for the `fn build-server` command. Probably not used by much else.
|
||||||
func (s *Server) AddExtensionByName(name string) {
|
func (s *Server) AddExtensionByName(name string) {
|
||||||
fmt.Printf("extensions: %+v\n", extensions)
|
|
||||||
e, ok := extensions[name]
|
e, ok := extensions[name]
|
||||||
if !ok {
|
if !ok {
|
||||||
log.Fatalf("Extension %v not registered.\n", name)
|
log.Fatalf("Extension %v not registered.\n", name)
|
||||||
@@ -28,3 +27,10 @@ func (s *Server) AddExtensionByName(name string) {
|
|||||||
log.Fatalf("Failed to add extension %v: %v\n", name, err)
|
log.Fatalf("Failed to add extension %v: %v\n", name, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// AddExtension both registers an extension and adds it. This is useful during extension development
|
||||||
|
// or if you want to build a custom server without using `fn build-server`.
|
||||||
|
func (s *Server) AddExtension(ext fnext.Extension) {
|
||||||
|
RegisterExtension(ext)
|
||||||
|
s.AddExtensionByName(ext.Name())
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ package server
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"fmt"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/fnproject/fn/api/common"
|
"github.com/fnproject/fn/api/common"
|
||||||
@@ -37,12 +36,14 @@ func (c *middlewareController) FunctionCalled() bool {
|
|||||||
|
|
||||||
func (s *Server) apiMiddlewareWrapper() gin.HandlerFunc {
|
func (s *Server) apiMiddlewareWrapper() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
|
// fmt.Println("api middleware")
|
||||||
s.runMiddleware(c, s.apiMiddlewares)
|
s.runMiddleware(c, s.apiMiddlewares)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) rootMiddlewareWrapper() gin.HandlerFunc {
|
func (s *Server) rootMiddlewareWrapper() gin.HandlerFunc {
|
||||||
return func(c *gin.Context) {
|
return func(c *gin.Context) {
|
||||||
|
// fmt.Println("ROOT MIDDLE")
|
||||||
s.runMiddleware(c, s.rootMiddlewares)
|
s.runMiddleware(c, s.rootMiddlewares)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -50,7 +51,9 @@ func (s *Server) rootMiddlewareWrapper() gin.HandlerFunc {
|
|||||||
// This is basically a single gin middleware that runs a bunch of fn middleware.
|
// This is basically a single gin middleware that runs a bunch of fn middleware.
|
||||||
// The final handler will pass it back to gin for further processing.
|
// The final handler will pass it back to gin for further processing.
|
||||||
func (s *Server) runMiddleware(c *gin.Context, ms []fnext.Middleware) {
|
func (s *Server) runMiddleware(c *gin.Context, ms []fnext.Middleware) {
|
||||||
|
// fmt.Println("runMiddleware")
|
||||||
if len(ms) == 0 {
|
if len(ms) == 0 {
|
||||||
|
// fmt.Println("ZERO MIDDLEWARE")
|
||||||
c.Next()
|
c.Next()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -65,11 +68,11 @@ func (s *Server) runMiddleware(c *gin.Context, ms []fnext.Middleware) {
|
|||||||
|
|
||||||
ctx := context.WithValue(c.Request.Context(), fnext.MiddlewareControllerKey, s.newMiddlewareController(c))
|
ctx := context.WithValue(c.Request.Context(), fnext.MiddlewareControllerKey, s.newMiddlewareController(c))
|
||||||
last := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
last := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
fmt.Println("final function called")
|
// fmt.Println("final handler called")
|
||||||
// check for bypass
|
// check for bypass
|
||||||
mctx := fnext.GetMiddlewareController(r.Context())
|
mctx := fnext.GetMiddlewareController(r.Context())
|
||||||
if mctx.FunctionCalled() {
|
if mctx.FunctionCalled() {
|
||||||
fmt.Println("function already called, skipping")
|
// fmt.Println("func already called, skipping")
|
||||||
c.Abort()
|
c.Abort()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -77,6 +80,8 @@ func (s *Server) runMiddleware(c *gin.Context, ms []fnext.Middleware) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
chainAndServe(ms, c.Writer, c.Request.WithContext(ctx), last)
|
chainAndServe(ms, c.Writer, c.Request.WithContext(ctx), last)
|
||||||
|
|
||||||
|
c.Abort() // we always abort here because the middleware decides to call next or not. If the `last` handler gets called, it will continue, otherwise we abort.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Server) newMiddlewareController(c *gin.Context) *middlewareController {
|
func (s *Server) newMiddlewareController(c *gin.Context) *middlewareController {
|
||||||
@@ -86,6 +91,14 @@ func (s *Server) newMiddlewareController(c *gin.Context) *middlewareController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: I will remove this and other debug commented lines once I'm sure it's all right.
|
||||||
|
func debugH(i int, m fnext.Middleware, h http.Handler) http.Handler {
|
||||||
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
// fmt.Println("handling", i, "m:", reflect.TypeOf(m), "h:", reflect.TypeOf(h))
|
||||||
|
h.ServeHTTP(w, r) // call original
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// chainAndServe essentially makes a chain of middleware wrapped around each other, then calls ServerHTTP on the end result.
|
// chainAndServe essentially makes a chain of middleware wrapped around each other, then calls ServerHTTP on the end result.
|
||||||
// then each middleware also calls ServeHTTP within it
|
// then each middleware also calls ServeHTTP within it
|
||||||
func chainAndServe(ms []fnext.Middleware, w http.ResponseWriter, r *http.Request, last http.Handler) {
|
func chainAndServe(ms []fnext.Middleware, w http.ResponseWriter, r *http.Request, last http.Handler) {
|
||||||
@@ -93,7 +106,7 @@ func chainAndServe(ms []fnext.Middleware, w http.ResponseWriter, r *http.Request
|
|||||||
// These get chained in reverse order so they play out in the right order. Don't ask.
|
// These get chained in reverse order so they play out in the right order. Don't ask.
|
||||||
for i := len(ms) - 1; i >= 0; i-- {
|
for i := len(ms) - 1; i >= 0; i-- {
|
||||||
m := ms[i]
|
m := ms[i]
|
||||||
h = m.Handle(h)
|
h = m.Handle(debugH(i, m, h))
|
||||||
}
|
}
|
||||||
h.ServeHTTP(w, r)
|
h.ServeHTTP(w, r)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,7 +5,8 @@
|
|||||||
If you are a developer using Fn through the API, this section is for you.
|
If you are a developer using Fn through the API, this section is for you.
|
||||||
|
|
||||||
### Getting Started
|
### Getting Started
|
||||||
* [Quickstart](https://github.com/fnproject/fn)
|
|
||||||
|
* [Quickstart](https://github.com/fnproject/fn#quickstart)
|
||||||
* [API Reference](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/fnproject/fn/master/docs/swagger.yml)
|
* [API Reference](http://petstore.swagger.io/?url=https://raw.githubusercontent.com/fnproject/fn/master/docs/swagger.yml)
|
||||||
* [FAQ](faq.md)
|
* [FAQ](faq.md)
|
||||||
* [Object Model](developers/model.md)
|
* [Object Model](developers/model.md)
|
||||||
@@ -17,17 +18,25 @@ If you are a developer using Fn through the API, this section is for you.
|
|||||||
* [Writing functions](writing.md)
|
* [Writing functions](writing.md)
|
||||||
|
|
||||||
### Advanced
|
### Advanced
|
||||||
|
|
||||||
* [Open Function Format](function-format.md)
|
* [Open Function Format](function-format.md)
|
||||||
* [Packaging functions](packaging.md)
|
* [Packaging functions](packaging.md)
|
||||||
* [CLI Source](https://github.com/fnproject/cli/)
|
* [CLI Source](https://github.com/fnproject/cli/)
|
||||||
* [Async functions](async.md)
|
* [Async functions](async.md)
|
||||||
* [Organizing functions into an application](developers/apps.md)
|
* [Organizing functions into an application](developers/apps.md)
|
||||||
|
|
||||||
|
### Learn More
|
||||||
|
|
||||||
|
* [Examples](../examples)
|
||||||
|
* [Getting Started Series](../examples/tutorial)
|
||||||
|
* [Tutorials](https://github.com/fnproject/tutorials)
|
||||||
|
|
||||||
## For Operators
|
## For Operators
|
||||||
|
|
||||||
If you are operating Fn, this section is for you.
|
If you are operating Fn, this section is for you.
|
||||||
|
|
||||||
### Getting Started
|
### Getting Started
|
||||||
|
|
||||||
* [Running in Production](operating/production.md)
|
* [Running in Production](operating/production.md)
|
||||||
* [Logging](operating/logging.md)
|
* [Logging](operating/logging.md)
|
||||||
* [Message Queues](operating/mqs/README.md)
|
* [Message Queues](operating/mqs/README.md)
|
||||||
@@ -37,18 +46,15 @@ If you are operating Fn, this section is for you.
|
|||||||
* [User Interface](operating/ui.md)
|
* [User Interface](operating/ui.md)
|
||||||
|
|
||||||
### Advanced
|
### Advanced
|
||||||
|
|
||||||
* [Extending Fn](operating/extending.md)
|
* [Extending Fn](operating/extending.md)
|
||||||
* [Running Fn on Kubernetes](operating/kubernetes/README.md)
|
* [Running Fn on Kubernetes](operating/kubernetes/README.md)
|
||||||
* [Setting up development environment with Docker compose](./operating/compose.md)
|
* [Setting up development environment with Docker compose](./operating/compose.md)
|
||||||
* [OpenStack Triggers](operating/triggers.md)
|
* [OpenStack Triggers](operating/triggers.md)
|
||||||
* [Docker Configuration](operating/docker.md)
|
* [Docker Configuration](operating/docker.md)
|
||||||
|
|
||||||
|
## For Contributors
|
||||||
|
|
||||||
|
If you are working on the Fn Project, want to work on it or are creating extensions, this section is for you.
|
||||||
|
|
||||||
## Learn More
|
* [Writing Extensions](contributors/extensions.md)
|
||||||
|
|
||||||
* [Examples](../examples)
|
|
||||||
* [Getting Started Series](../examples/tutorial)
|
|
||||||
* [Tutorials](https://github.com/fnproject/tutorials)
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
# Docs for Contributors
|
|
||||||
|
|
||||||
* [Writing Extensions](extending.md)
|
|
||||||
@@ -20,17 +20,19 @@ to be called during setup:
|
|||||||
```go
|
```go
|
||||||
func init() {
|
func init() {
|
||||||
server.RegisterExtension(&fnext.Extension{
|
server.RegisterExtension(&fnext.Extension{
|
||||||
Name: "logspam",
|
Name: "github.com/treeder/fn-ext-example/logspam", // Should be the import name
|
||||||
Setup: setup, // Fn will call this during startup
|
Setup: setup, // Fn will call this during startup
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func setup(s *fnext.ExtServer) error {
|
func setup(s *fnext.ExtServer) error {
|
||||||
// Add all the hooks you extension needs here
|
// Add all the hooks your extension needs here
|
||||||
s.AddCallListener(&LogSpam{})
|
s.AddCallListener(&LogSpam{})
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
See https://github.com/treeder/fn-ext-example for full example.
|
||||||
|
|
||||||
## Listeners
|
## Listeners
|
||||||
|
|
||||||
Listeners are the main way to extend Fn.
|
Listeners are the main way to extend Fn.
|
||||||
|
|||||||
Reference in New Issue
Block a user