Skip to content

Commit

Permalink
Merge pull request #1370 from notzippy/develop
Browse files Browse the repository at this point in the history
Updated revel internal event handling system so external users can raise the events manually
  • Loading branch information
notzippy committed Sep 22, 2018
2 parents 9bf125f + bfddb60 commit 383a5e1
Show file tree
Hide file tree
Showing 13 changed files with 95 additions and 61 deletions.
51 changes: 51 additions & 0 deletions event.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package revel

type (
// The event type
Event int
// The event response
EventResponse int
// The handler signature
EventHandler func(typeOf Event, value interface{}) (responseOf EventResponse)
)
const (
// Event type when templates are going to be refreshed (receivers are registered template engines added to the template.engine conf option)
TEMPLATE_REFRESH_REQUESTED Event = iota
// Event type when templates are refreshed (receivers are registered template engines added to the template.engine conf option)
TEMPLATE_REFRESH_COMPLETED
// Event type before all module loads, events thrown to handlers added to AddInitEventHandler

// Event type before all module loads, events thrown to handlers added to AddInitEventHandler
REVEL_BEFORE_MODULES_LOADED
// Event type after all module loads, events thrown to handlers added to AddInitEventHandler
REVEL_AFTER_MODULES_LOADED

// Event type before server engine is initialized, receivers are active server engine and handlers added to AddInitEventHandler
ENGINE_BEFORE_INITIALIZED
// Event type before server engine is started, receivers are active server engine and handlers added to AddInitEventHandler
ENGINE_STARTED
// Event type after server engine is stopped, receivers are active server engine and handlers added to AddInitEventHandler
ENGINE_SHUTDOWN

// Called before routes are refreshed
ROUTE_REFRESH_REQUESTED
// Called after routes have been refreshed
ROUTE_REFRESH_COMPLETED

// Fired when a panic is caught during the startup process
REVEL_FAILURE
)

// Fires system events from revel
func RaiseEvent(key Event, value interface{}) (response EventResponse) {
for _, handler := range initEventList {
response |= handler(key, value)
}
return
}

// Add event handler to listen for all system events
func AddInitEventHandler(handler EventHandler) {
initEventList = append(initEventList, handler)
return
}
24 changes: 24 additions & 0 deletions event_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package revel_test

import (
"github.com/revel/revel"
"github.com/stretchr/testify/assert"
"testing"
)

// Test that the event handler can be attached and it dispatches the event received
func TestEventHandler(t *testing.T){
counter := 0
newListener := func(typeOf revel.Event, value interface{}) (responseOf revel.EventResponse) {
if typeOf==revel.REVEL_FAILURE {
counter ++
}
return
}
// Attach the same handlder twice so we expect to see the response twice as well
revel.AddInitEventHandler(newListener)
revel.AddInitEventHandler(newListener)
revel.RaiseEvent(revel.REVEL_AFTER_MODULES_LOADED, nil)
revel.RaiseEvent(revel.REVEL_FAILURE, nil)
assert.Equal(t, counter,2,"Expected event handler to have been called")
}
2 changes: 1 addition & 1 deletion fakeapp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ func (c Static) Serve(prefix, path string) Result {
// Register controllers is in its own function so the route test can use it as well
func registerControllers() {
controllers = make(map[string]*ControllerType)
fireEvent(ROUTE_REFRESH_REQUESTED, nil)
RaiseEvent(ROUTE_REFRESH_REQUESTED, nil)
RegisterController((*Hotels)(nil),
[]*MethodType{
{
Expand Down
1 change: 1 addition & 0 deletions filter.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ var Filters = []Filter{
I18nFilter, // Resolve the requested language.
InterceptorFilter, // Run interceptors around the action.
CompressFilter, // Compress the result.
BeforeAfterFilter,
ActionInvoker, // Invoke the action.
}

Expand Down
2 changes: 1 addition & 1 deletion module.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ func RegisterModuleInit(callback ModuleCallbackInterface) {

// Called on startup to make a callback so that modules can be initialized through the `RegisterModuleInit` function
func init() {
AddInitEventHandler(func(typeOf int, value interface{}) (responseOf int) {
AddInitEventHandler(func(typeOf Event, value interface{}) (responseOf EventResponse) {
if typeOf == REVEL_BEFORE_MODULES_LOADED {
Modules = []*Module{appModule}
appModule.Path = filepath.ToSlash(AppPath)
Expand Down
48 changes: 3 additions & 45 deletions revel.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,40 +20,12 @@ const (
// RevelImportPath Revel framework import path
RevelImportPath = "github.com/revel/revel"
)
const (
// Event type when templates are going to be refreshed (receivers are registered template engines added to the template.engine conf option)
TEMPLATE_REFRESH_REQUESTED = iota
// Event type when templates are refreshed (receivers are registered template engines added to the template.engine conf option)
TEMPLATE_REFRESH_COMPLETED
// Event type before all module loads, events thrown to handlers added to AddInitEventHandler

// Event type before all module loads, events thrown to handlers added to AddInitEventHandler
REVEL_BEFORE_MODULES_LOADED
// Event type after all module loads, events thrown to handlers added to AddInitEventHandler
REVEL_AFTER_MODULES_LOADED

// Event type before server engine is initialized, receivers are active server engine and handlers added to AddInitEventHandler
ENGINE_BEFORE_INITIALIZED
// Event type before server engine is started, receivers are active server engine and handlers added to AddInitEventHandler
ENGINE_STARTED
// Event type after server engine is stopped, receivers are active server engine and handlers added to AddInitEventHandler
ENGINE_SHUTDOWN

// Called before routes are refreshed
ROUTE_REFRESH_REQUESTED
// Called after routes have been refreshed
ROUTE_REFRESH_COMPLETED

// Fired when a panic is caught during the startup process
REVEL_FAILURE
)

const (
TEST_MODE_FLAG = "testModeFlag"
SPECIAL_USE_FLAG = "specialUseFlag"
)

type EventHandler func(typeOf int, value interface{}) (responseOf int)

// App details
var (
AppName string // e.g. "sample"
Expand Down Expand Up @@ -202,9 +174,9 @@ func Init(inputmode, importPath, srcPath string) {
SetSecretKey([]byte(secretStr))
}

fireEvent(REVEL_BEFORE_MODULES_LOADED, nil)
RaiseEvent(REVEL_BEFORE_MODULES_LOADED, nil)
loadModules()
fireEvent(REVEL_AFTER_MODULES_LOADED, nil)
RaiseEvent(REVEL_AFTER_MODULES_LOADED, nil)

Initialized = true
RevelLog.Info("Initialized Revel", "Version", Version, "BuildDate", BuildDate, "MinimumGoVersion", MinimumGoVersion)
Expand Down Expand Up @@ -268,20 +240,6 @@ func updateLog(inputmode string) (returnMode string) {
return
}

// Fires system events from revel
func fireEvent(key int, value interface{}) (response int) {
for _, handler := range initEventList {
response |= handler(key, value)
}
return
}

// Add event handler to listen for all system events
func AddInitEventHandler(handler EventHandler) {
initEventList = append(initEventList, handler)
return
}

// Set the secret key
func SetSecretKey(newKey []byte) error {
secretKey = newKey
Expand Down
6 changes: 3 additions & 3 deletions router.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ var (
var routerLog = RevelLog.New("section", "router")

func init() {
AddInitEventHandler(func(typeOf int, value interface{}) (responseOf int) {
AddInitEventHandler(func(typeOf Event, value interface{}) (responseOf EventResponse) {
// Add in an
if typeOf == ROUTE_REFRESH_REQUESTED {
// Clear the actionPathCacheMap cache
Expand Down Expand Up @@ -246,9 +246,9 @@ func (router *Router) Route(req *Request) (routeMatch *RouteMatch) {
// Refresh re-reads the routes file and re-calculates the routing table.
// Returns an error if a specified action could not be found.
func (router *Router) Refresh() (err *Error) {
fireEvent(ROUTE_REFRESH_REQUESTED, nil)
RaiseEvent(ROUTE_REFRESH_REQUESTED, nil)
router.Routes, err = parseRoutesFile(appModule, router.path, "", true)
fireEvent(ROUTE_REFRESH_COMPLETED, nil)
RaiseEvent(ROUTE_REFRESH_COMPLETED, nil)
if err != nil {
return
}
Expand Down
2 changes: 1 addition & 1 deletion server-engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ type ServerEngine interface {
// Starts the server. This will block until server is stopped
Start()
// Fires a new event to the server
Event(event int, args interface{})
Event(event Event, args interface{})
// Returns the engine instance for specific calls
Engine() interface{}
// Returns the engine Name
Expand Down
6 changes: 3 additions & 3 deletions server.go
Original file line number Diff line number Diff line change
Expand Up @@ -64,15 +64,15 @@ func Run(port int) {
defer func() {
if r := recover(); r != nil {
RevelLog.Crit("Recovered error in startup", "error", r)
fireEvent(REVEL_FAILURE, r)
RaiseEvent(REVEL_FAILURE, r)
panic("Fatal error in startup")
}
}() // Create the CurrentEngine instance from the application config
InitServerEngine(port, Config.StringDefault("server.engine", GO_NATIVE_SERVER_ENGINE))
CurrentEngine.Event(ENGINE_BEFORE_INITIALIZED, nil)
fireEvent(ENGINE_BEFORE_INITIALIZED, nil)
RaiseEvent(ENGINE_BEFORE_INITIALIZED, nil)
InitServer()
fireEvent(ENGINE_STARTED, nil)
RaiseEvent(ENGINE_STARTED, nil)
CurrentEngine.Event(ENGINE_STARTED, nil)
// This is needed for the harness to recognize that the server is started, it looks for the word
// "Listening" in the stdout stream
Expand Down
4 changes: 2 additions & 2 deletions server_adapter_go.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ var signalChan = make(chan os.Signal)

// Register the GoHttpServer engine
func init() {
AddInitEventHandler(func(typeOf int, value interface{}) (responseOf int){
AddInitEventHandler(func(typeOf Event, value interface{}) (responseOf EventResponse){
if typeOf == REVEL_BEFORE_MODULES_LOADED {
RegisterServerEngine(GO_NATIVE_SERVER_ENGINE, func() ServerEngine { return &GoHttpServer{} })
}
Expand Down Expand Up @@ -129,7 +129,7 @@ func (g *GoHttpServer) Engine() interface{} {
return g.Server
}

func (g *GoHttpServer) Event(event int, args interface{}) {
func (g *GoHttpServer) Event(event Event, args interface{}) {
switch event {
case ENGINE_STARTED:
signal.Notify(signalChan, syscall.SIGINT, syscall.SIGTERM, syscall.SIGKILL, syscall.SIGUSR2)
Expand Down
4 changes: 2 additions & 2 deletions template.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,12 +120,12 @@ func (loader *TemplateLoader) Refresh() (err *Error) {
for _, engine := range runtimeLoader.templatesAndEngineList {
engine.Event(TEMPLATE_REFRESH_REQUESTED, nil)
}
fireEvent(TEMPLATE_REFRESH_REQUESTED, nil)
RaiseEvent(TEMPLATE_REFRESH_REQUESTED, nil)
defer func() {
for _, engine := range runtimeLoader.templatesAndEngineList {
engine.Event(TEMPLATE_REFRESH_COMPLETED, nil)
}
fireEvent(TEMPLATE_REFRESH_COMPLETED, nil)
RaiseEvent(TEMPLATE_REFRESH_COMPLETED, nil)

// Reset the runtimeLoader
loader.runtimeLoader.Store(runtimeLoader)
Expand Down
4 changes: 2 additions & 2 deletions template_adapter_go.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ const GO_TEMPLATE = "go"

// Called on startup, initialized when the REVEL_BEFORE_MODULES_LOADED is called
func init() {
AddInitEventHandler(func(typeOf int, value interface{}) (responseOf int){
AddInitEventHandler(func(typeOf Event, value interface{}) (responseOf EventResponse){
if typeOf == REVEL_BEFORE_MODULES_LOADED {
RegisterTemplateLoader(GO_TEMPLATE, func(loader *TemplateLoader) (TemplateEngine, error) {
// Set the template delimiters for the project if present, then split into left
Expand Down Expand Up @@ -119,7 +119,7 @@ func (engine *GoEngine) Name() string {
}

// An event listener to listen for Revel INIT events
func (engine *GoEngine) Event(action int, i interface{}) {
func (engine *GoEngine) Event(action Event, i interface{}) {
if action == TEMPLATE_REFRESH_REQUESTED {
// At this point all the templates have been passed into the
engine.templatesByName = map[string]*GoTemplate{}
Expand Down
2 changes: 1 addition & 1 deletion template_engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ type TemplateEngine interface {
Lookup(templateName string) Template

// Fired by the template loader when events occur
Event(event int, arg interface{})
Event(event Event, arg interface{})

// returns true if this engine should be used to parse the file specified in baseTemplate
Handles(templateView *TemplateView) bool
Expand Down

0 comments on commit 383a5e1

Please sign in to comment.