Skip to content

Commit

Permalink
ErrEventUnhandled to indicate call next handler
Browse files Browse the repository at this point in the history
  • Loading branch information
linkdata committed Oct 11, 2023
1 parent aa40ff5 commit 439cc6d
Show file tree
Hide file tree
Showing 14 changed files with 70 additions and 56 deletions.
6 changes: 3 additions & 3 deletions clickhandler.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ package jaws
import "github.com/linkdata/jaws/what"

type ClickHandler interface {
JawsClick(e *Element, name string) (stop bool, err error)
JawsClick(e *Element, name string) (err error)
}

type clickHandlerWapper struct{ ClickHandler }

func (chw clickHandlerWapper) JawsEvent(e *Element, w what.What, v string) (stop bool, err error) {
func (chw clickHandlerWapper) JawsEvent(e *Element, w what.What, v string) error {
if w == what.Click {
return chw.JawsClick(e, v)
}
return
return ErrEventUnhandled
}
26 changes: 19 additions & 7 deletions eventhandler.go
Original file line number Diff line number Diff line change
@@ -1,33 +1,45 @@
package jaws

import "github.com/linkdata/jaws/what"
import (
"github.com/linkdata/jaws/what"
)

type EventHandler interface {
JawsEvent(e *Element, wht what.What, val string) (stop bool, err error)
JawsEvent(e *Element, wht what.What, val string) (err error)
}

type errEventUnhandled struct{}

func (errEventUnhandled) Error() string {
return "event unhandled"
}

// ErrEventUnhandled returned by JawsEvent() or JawsClick() causes the next
// available handler to be invoked.
var ErrEventUnhandled = errEventUnhandled{}

// EventFn is the signature of a event handling function to be called when JaWS receives
// an event message from the Javascript via the WebSocket connection.
type EventFn = func(e *Element, wht what.What, val string) (stop bool, err error)
type EventFn = func(e *Element, wht what.What, val string) (err error)

type eventFnWrapper struct{ EventFn }

func (ehf eventFnWrapper) JawsEvent(e *Element, w what.What, v string) (stop bool, err error) {
func (ehf eventFnWrapper) JawsEvent(e *Element, w what.What, v string) (err error) {
return ehf.EventFn(e, w, v)
}

var _ EventFn = eventFnWrapper{}.JawsEvent // statically ensure JawsEvent and EventFn are compatible

func callEventHandler(obj any, e *Element, wht what.What, val string) (stop bool, err error) {
func callEventHandler(obj any, e *Element, wht what.What, val string) (err error) {
if wht == what.Click {
if h, ok := obj.(ClickHandler); ok {
if stop, err = h.JawsClick(e, val); stop || err != nil {
if err = h.JawsClick(e, val); err != ErrEventUnhandled {
return
}
}
}
if h, ok := obj.(EventHandler); ok {
return h.JawsEvent(e, wht, val)
}
return
return ErrEventUnhandled
}
8 changes: 5 additions & 3 deletions request.go
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,6 @@ func (rq *Request) process(broadcastMsgCh chan Message, incomingMsgCh <-chan wsM

func (rq *Request) callAllEventHandlers(id Jid, wht what.What, val string) (err error) {
var elems []*Element
var stop bool
rq.mu.RLock()
if id == 0 {
if wht == what.Click {
Expand All @@ -639,15 +638,18 @@ func (rq *Request) callAllEventHandlers(id Jid, wht what.What, val string) (err
rq.mu.RUnlock()

for _, e := range elems {
if stop, err = callEventHandler(e.ui, e, wht, val); stop || err != nil {
if err = callEventHandler(e.ui, e, wht, val); err != ErrEventUnhandled {
return
}
for _, h := range e.handlers {
if stop, err = h.JawsEvent(e, wht, val); stop || err != nil {
if err = h.JawsEvent(e, wht, val); err != ErrEventUnhandled {
return
}
}
}
if err == ErrEventUnhandled {
return nil
}
return
}

Expand Down
32 changes: 16 additions & 16 deletions request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -210,11 +210,11 @@ func TestRequest_OutboundRespectsJawsClosed(t *testing.T) {
jw := rq.jw
var callCount int32
tag := Tag("foo")
rq.Register(tag, func(e *Element, evt what.What, val string) (bool, error) {
rq.Register(tag, func(e *Element, evt what.What, val string) error {
atomic.AddInt32(&callCount, 1)
is.Equal(1, jw.RequestCount())
jw.Close()
return false, errors.New(val)
return errors.New(val)
})
fillWsCh(rq.outCh)
jw.Broadcast(Message{Dest: Tag("foo"), What: what.Hook, Data: "bar"})
Expand All @@ -233,10 +233,10 @@ func TestRequest_OutboundRespectsContextDone(t *testing.T) {
defer rq.Close()
var callCount int32
tag := Tag("foo")
rq.Register(tag, func(e *Element, evt what.What, val string) (bool, error) {
rq.Register(tag, func(e *Element, evt what.What, val string) error {
atomic.AddInt32(&callCount, 1)
rq.cancel()
return false, errors.New(val)
return errors.New(val)
})
fillWsCh(rq.outCh)
rq.jw.Broadcast(Message{Dest: Tag("foo"), What: what.Hook, Data: "bar"})
Expand Down Expand Up @@ -278,16 +278,16 @@ func TestRequest_Trigger(t *testing.T) {
defer rq.Close()
gotFooCall := make(chan struct{})
gotEndCall := make(chan struct{})
rq.Register("foo", func(e *Element, evt what.What, val string) (bool, error) {
rq.Register("foo", func(e *Element, evt what.What, val string) error {
defer close(gotFooCall)
return false, nil
return nil
})
rq.Register(("err"), func(e *Element, evt what.What, val string) (bool, error) {
return false, errors.New(val)
rq.Register(("err"), func(e *Element, evt what.What, val string) error {
return errors.New(val)
})
rq.Register(("end"), func(e *Element, evt what.What, val string) (bool, error) {
rq.Register(("end"), func(e *Element, evt what.What, val string) error {
defer close(gotEndCall)
return false, nil
return nil
})

// broadcasts from ourselves should not invoke fn
Expand Down Expand Up @@ -337,7 +337,7 @@ func TestRequest_EventFnQueue(t *testing.T) {
firstDoneCh := make(chan struct{})
var sleepDone int32
var callCount int32
rq.Register(("sleep"), func(e *Element, evt what.What, val string) (bool, error) {
rq.Register(("sleep"), func(e *Element, evt what.What, val string) error {
count := int(atomic.AddInt32(&callCount, 1))
if val != strconv.Itoa(count) {
t.Logf("val=%s, count=%d, cap=%d", val, count, cap(rq.outCh))
Expand All @@ -349,7 +349,7 @@ func TestRequest_EventFnQueue(t *testing.T) {
for atomic.LoadInt32(&sleepDone) == 0 {
time.Sleep(time.Millisecond)
}
return false, nil
return nil
})

for i := 0; i < cap(rq.outCh); i++ {
Expand Down Expand Up @@ -389,9 +389,9 @@ func TestRequest_EventFnQueueOverflowPanicsWithNoLogger(t *testing.T) {

var wait int32

rq.Register(("bomb"), func(e *Element, evt what.What, val string) (bool, error) {
rq.Register(("bomb"), func(e *Element, evt what.What, val string) error {
time.Sleep(time.Millisecond * time.Duration(atomic.AddInt32(&wait, 1)))
return false, nil
return nil
})

rq.expectPanic = true
Expand All @@ -418,7 +418,7 @@ func TestRequest_IgnoresIncomingMsgsDuringShutdown(t *testing.T) {

var spewState int32
var callCount int32
rq.Register(("spew"), func(e *Element, evt what.What, val string) (bool, error) {
rq.Register(("spew"), func(e *Element, evt what.What, val string) error {
atomic.AddInt32(&callCount, 1)
if len(rq.outCh) < cap(rq.outCh) {
rq.jw.Broadcast(Message{Dest: Tag("spew"), What: what.Input})
Expand All @@ -428,7 +428,7 @@ func TestRequest_IgnoresIncomingMsgsDuringShutdown(t *testing.T) {
time.Sleep(time.Millisecond)
}
}
return false, errors.New("chunks")
return errors.New("chunks")
})
rq.Register(Tag("foo"))

Expand Down
4 changes: 2 additions & 2 deletions session_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ func TestSession_Delete(t *testing.T) {
rq2 := ts.jw.NewRequest(hr2)
is.Equal(ts.sess, rq2.Session())

ts.rq.Register("byebye", func(e *Element, evt what.What, val string) (bool, error) {
ts.rq.Register("byebye", func(e *Element, evt what.What, val string) error {
sess2 := ts.jw.GetSession(e.Request.Initial)
is.Equal(ts.sess, sess2)
cookie2 := sess2.Close()
Expand All @@ -185,7 +185,7 @@ func TestSession_Delete(t *testing.T) {
is.True(cookie2.Expires.IsZero())
is.Equal(cookie1.Name, cookie2.Name)
is.Equal(cookie1.Value, cookie2.Value)
return false, nil
return nil
})

conn, resp, err := websocket.Dial(ts.ctx, ts.Url(), nil)
Expand Down
2 changes: 1 addition & 1 deletion template.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,6 @@ func (t Template) JawsUpdate(e *Element) {

var _ EventHandler = (*Template)(nil) // statically ensure interface is defined

func (t Template) JawsEvent(e *Element, wht what.What, val string) (bool, error) {
func (t Template) JawsEvent(e *Element, wht what.What, val string) error {
return callEventHandler(t.Dot, e, wht, val)
}
32 changes: 16 additions & 16 deletions uihtml.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,65 +50,65 @@ func parseParams(elem *Element, params []interface{}) (attrs []string) {
case func(*Request, string) error: // Deprecated: ClickFn
if data != nil {
elem.handlers = append(elem.handlers, eventFnWrapper{
func(e *Element, wht what.What, val string) (stop bool, err error) {
func(e *Element, wht what.What, val string) error {
if wht == what.Click {
err = data(e.Request, e.jid.String())
return data(e.Request, e.jid.String())
}
return
return ErrEventUnhandled
}})
}
case func(*Request, string, string) error: // Deprecated: InputTextFn
if data != nil {
elem.handlers = append(elem.handlers, eventFnWrapper{func(e *Element, wht what.What, val string) (stop bool, err error) {
elem.handlers = append(elem.handlers, eventFnWrapper{func(e *Element, wht what.What, val string) error {
if wht == what.Input {
err = data(e.Request, e.jid.String(), val)
return data(e.Request, e.jid.String(), val)
}
return
return ErrEventUnhandled
}})
}
case func(*Request, string, bool) error: // Deprecated: InputBoolFn
if data != nil {
elem.handlers = append(elem.handlers, eventFnWrapper{func(e *Element, wht what.What, val string) (stop bool, err error) {
elem.handlers = append(elem.handlers, eventFnWrapper{func(e *Element, wht what.What, val string) (err error) {
if wht == what.Input {
var v bool
if val != "" {
if v, err = strconv.ParseBool(val); err != nil {
return
}
}
err = data(e.Request, e.jid.String(), v)
return data(e.Request, e.jid.String(), v)
}
return
return ErrEventUnhandled
}})
}
case func(*Request, string, float64) error: // Deprecated: InputFloatFn
if data != nil {
elem.handlers = append(elem.handlers, eventFnWrapper{func(e *Element, wht what.What, val string) (stop bool, err error) {
elem.handlers = append(elem.handlers, eventFnWrapper{func(e *Element, wht what.What, val string) (err error) {
if wht == what.Input {
var v float64
if val != "" {
if v, err = strconv.ParseFloat(val, 64); err != nil {
return
}
}
err = data(e.Request, e.jid.String(), v)
return data(e.Request, e.jid.String(), v)
}
return
return ErrEventUnhandled
}})
}
case func(*Request, string, time.Time) error: // Deprecated: InputDateFn
if data != nil {
elem.handlers = append(elem.handlers, eventFnWrapper{func(e *Element, wht what.What, val string) (stop bool, err error) {
elem.handlers = append(elem.handlers, eventFnWrapper{func(e *Element, wht what.What, val string) (err error) {
if wht == what.Input {
var v time.Time
if val != "" {
if v, err = time.Parse(ISO8601, val); err != nil {
return
}
}
err = data(e.Request, e.jid.String(), v)
return data(e.Request, e.jid.String(), v)
}
return
return ErrEventUnhandled
}})
}
default:
Expand Down Expand Up @@ -141,6 +141,6 @@ func (ui *UiHtml) JawsUpdate(e *Element) {
}
}

func (ui *UiHtml) JawsEvent(e *Element, wht what.What, val string) (bool, error) {
func (ui *UiHtml) JawsEvent(e *Element, wht what.What, val string) error {
return callEventHandler(ui.Tag, e, wht, val)
}
2 changes: 1 addition & 1 deletion uiinputbool.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func (ui *UiInputBool) JawsUpdate(e *Element) {
}
}

func (ui *UiInputBool) JawsEvent(e *Element, wht what.What, val string) (stop bool, err error) {
func (ui *UiInputBool) JawsEvent(e *Element, wht what.What, val string) (err error) {
if wht == what.Input {
var v bool
if val != "" {
Expand Down
2 changes: 1 addition & 1 deletion uiinputdate.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (ui *UiInputDate) JawsUpdate(e *Element) {
}
}

func (ui *UiInputDate) JawsEvent(e *Element, wht what.What, val string) (stop bool, err error) {
func (ui *UiInputDate) JawsEvent(e *Element, wht what.What, val string) (err error) {
if wht == what.Input {
var v time.Time
if val != "" {
Expand Down
2 changes: 1 addition & 1 deletion uiinputfloat.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (ui *UiInputFloat) JawsUpdate(e *Element) {
}
}

func (ui *UiInputFloat) JawsEvent(e *Element, wht what.What, val string) (stop bool, err error) {
func (ui *UiInputFloat) JawsEvent(e *Element, wht what.What, val string) (err error) {
if wht == what.Input {
var v float64
if val != "" {
Expand Down
2 changes: 1 addition & 1 deletion uiinputtext.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ func (ui *UiInputText) JawsUpdate(e *Element) {
}
}

func (ui *UiInputText) JawsEvent(e *Element, wht what.What, val string) (stop bool, err error) {
func (ui *UiInputText) JawsEvent(e *Element, wht what.What, val string) (err error) {
if wht == what.Input {
ui.Last.Store(val)
err = ui.StringGetter.(StringSetter).JawsSetString(e, val)
Expand Down
2 changes: 1 addition & 1 deletion uiselect.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ func (ui *UiSelect) JawsUpdate(e *Element) {
ui.uiWrapContainer.JawsUpdate(e)
}

func (ui *UiSelect) JawsEvent(e *Element, wht what.What, val string) (stop bool, err error) {
func (ui *UiSelect) JawsEvent(e *Element, wht what.What, val string) (err error) {
if wht == what.Input {
err = ui.uiWrapContainer.Container.(StringSetter).JawsSetString(e, val)
e.Dirty(ui.Tag)
Expand Down
2 changes: 1 addition & 1 deletion uitextarea.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ func (ui *UiTextarea) JawsUpdate(e *Element) {
e.SetInner(template.HTML(ui.JawsGetString(e))) // #nosec G203
}

func (ui *UiTextarea) JawsEvent(e *Element, wht what.What, val string) (stop bool, err error) {
func (ui *UiTextarea) JawsEvent(e *Element, wht what.What, val string) (err error) {
if wht == what.Input {
err = ui.StringGetter.(StringSetter).JawsSetString(e, val)
e.Dirty(ui.Tag)
Expand Down
4 changes: 2 additions & 2 deletions ws_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,9 @@ func TestWS_NormalExchange(t *testing.T) {

gotCallCh := make(chan struct{})

ts.rq.Register(("foo"), func(e *Element, evt what.What, val string) (bool, error) {
ts.rq.Register(("foo"), func(e *Element, evt what.What, val string) error {
close(gotCallCh)
return false, fooError
return fooError
})

conn, resp, err := websocket.Dial(ts.ctx, ts.Url(), nil)
Expand Down

0 comments on commit 439cc6d

Please sign in to comment.