diff --git a/api/server/route_listeners.go b/api/server/route_listeners.go new file mode 100644 index 000000000..42bddf495 --- /dev/null +++ b/api/server/route_listeners.go @@ -0,0 +1,76 @@ +package server + +import ( + "context" + + "github.com/fnproject/fn/api/models" + "github.com/fnproject/fn/fnext" +) + +type routeListeners []fnext.RouteListener + +var _ fnext.RouteListener = new(routeListeners) + +func (s *Server) AddRouteListener(listener fnext.RouteListener) { + *s.routeListeners = append(*s.routeListeners, listener) +} + +func (a *routeListeners) BeforeRouteCreate(ctx context.Context, route *models.Route) error { + for _, l := range *a { + err := l.BeforeRouteCreate(ctx, route) + if err != nil { + return err + } + } + return nil +} + +func (a *routeListeners) AfterRouteCreate(ctx context.Context, route *models.Route) error { + for _, l := range *a { + err := l.BeforeRouteCreate(ctx, route) + if err != nil { + return err + } + } + return nil +} + +func (a *routeListeners) BeforeRouteUpdate(ctx context.Context, route *models.Route) error { + for _, l := range *a { + err := l.BeforeRouteUpdate(ctx, route) + if err != nil { + return err + } + } + return nil +} + +func (a *routeListeners) AfterRouteUpdate(ctx context.Context, route *models.Route) error { + for _, l := range *a { + err := l.AfterRouteUpdate(ctx, route) + if err != nil { + return err + } + } + return nil +} + +func (a *routeListeners) BeforeRouteDelete(ctx context.Context, appName string, routePath string) error { + for _, l := range *a { + err := l.BeforeRouteDelete(ctx, appName, routePath) + if err != nil { + return err + } + } + return nil +} + +func (a *routeListeners) AfterRouteDelete(ctx context.Context, appName string, routePath string) error { + for _, l := range *a { + err := l.AfterRouteDelete(ctx, appName, routePath) + if err != nil { + return err + } + } + return nil +} diff --git a/api/server/server.go b/api/server/server.go index 28745b7b6..af6f0061b 100644 --- a/api/server/server.go +++ b/api/server/server.go @@ -111,6 +111,7 @@ type Server struct { certKey string certAuthority string appListeners *appListeners + routeListeners *routeListeners rootMiddlewares []fnext.Middleware apiMiddlewares []fnext.Middleware promExporter *prometheus.Exporter @@ -516,7 +517,9 @@ func New(ctx context.Context, opts ...ServerOption) *Server { s.bindHandlers(ctx) s.appListeners = new(appListeners) - s.datastore = fnext.NewDatastore(s.datastore, s.appListeners) + s.routeListeners = new(routeListeners) + + s.datastore = fnext.NewDatastore(s.datastore, s.appListeners, s.routeListeners) return s } diff --git a/fnext/datastore.go b/fnext/datastore.go index 38e708f71..cb57a56ee 100644 --- a/fnext/datastore.go +++ b/fnext/datastore.go @@ -6,16 +6,18 @@ import ( "github.com/fnproject/fn/api/models" ) -func NewDatastore(ds models.Datastore, al AppListener) models.Datastore { +func NewDatastore(ds models.Datastore, al AppListener, rl RouteListener) models.Datastore { return &extds{ Datastore: ds, al: al, + rl: rl, } } type extds struct { models.Datastore al AppListener + rl RouteListener } func (e *extds) GetApp(ctx context.Context, appName string) (*models.App, error) { @@ -93,3 +95,45 @@ func (e *extds) GetApps(ctx context.Context, filter *models.AppFilter) ([]*model err = e.al.AfterAppsList(ctx, apps) return apps, err } + +func (e *extds) InsertRoute(ctx context.Context, route *models.Route) (*models.Route, error) { + err := e.rl.BeforeRouteCreate(ctx, route) + if err != nil { + return nil, err + } + + route, err = e.Datastore.InsertRoute(ctx, route) + if err != nil { + return nil, err + } + + err = e.rl.AfterRouteCreate(ctx, route) + return route, err +} + +func (e *extds) UpdateRoute(ctx context.Context, route *models.Route) (*models.Route, error) { + err := e.rl.BeforeRouteUpdate(ctx, route) + if err != nil { + return nil, err + } + + route, err = e.Datastore.UpdateRoute(ctx, route) + if err != nil { + return nil, err + } + + err = e.rl.AfterRouteUpdate(ctx, route) + return route, err +} + +func (e *extds) RemoveRoute(ctx context.Context, appName string, routePath string) error { + err := e.rl.BeforeRouteDelete(ctx, appName, routePath) + if err != nil { + return err + } + err = e.Datastore.RemoveRoute(ctx, appName, routePath) + if err != nil { + return err + } + return e.rl.AfterRouteDelete(ctx, appName, routePath) +} diff --git a/fnext/listeners.go b/fnext/listeners.go index d3d5ec85a..0d53d50b0 100644 --- a/fnext/listeners.go +++ b/fnext/listeners.go @@ -41,6 +41,21 @@ type AppListener interface { // } } +type RouteListener interface { + // BeforeRouteCreate called before route created in the datastore + BeforeRouteCreate(ctx context.Context, route *models.Route) error + // AfterRouteCreate called after route create in the datastore + AfterRouteCreate(ctx context.Context, route *models.Route) error + // BeforeRouteUpdate called before route update in datastore + BeforeRouteUpdate(ctx context.Context, route *models.Route) error + // AfterRouteUpdate called after route updated in datastore + AfterRouteUpdate(ctx context.Context, route *models.Route) error + // BeforeRouteDelete called before route deleted from the datastore + BeforeRouteDelete(ctx context.Context, appName string, routePath string) error + // AfterRouteDelete called after route deleted from the datastore + AfterRouteDelete(ctx context.Context, appName string, routePath string) error +} + // CallListener enables callbacks around Call events type CallListener interface { // BeforeCall called before a function is executed