Skip to content

Commit

Permalink
feat: Introduce reflection call wrapper to prevent panics on partiall…
Browse files Browse the repository at this point in the history
…y sent Dudirekta messages
  • Loading branch information
pojntfx committed Oct 16, 2023
1 parent c74b4e2 commit d61bf81
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 3 deletions.
7 changes: 6 additions & 1 deletion pkg/rpc/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"sync"

"github.com/google/uuid"
"github.com/pojntfx/dudirekta/pkg/utils"
)

var (
Expand Down Expand Up @@ -55,7 +56,11 @@ func createClosure(fn interface{}) (func(args ...interface{}) (interface{}, erro
}
}

out := reflect.ValueOf(fn).Call(in)
out, err := utils.Call(reflect.ValueOf(fn), in)
if err != nil {
return nil, err
}

if len(out) == 1 {
if out[0].IsValid() && !out[0].IsNil() {
return nil, out[0].Interface().(error)
Expand Down
15 changes: 13 additions & 2 deletions pkg/rpc/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import (
"time"

"github.com/google/uuid"
"github.com/pojntfx/dudirekta/pkg/utils"
"github.com/teivah/broadcast"
)

Expand Down Expand Up @@ -400,7 +401,12 @@ func (r Registry[R]) Link(
rpcArgs = append(rpcArgs, args[i].Interface())
}

rcpRv := rpc.Call([]reflect.Value{reflect.ValueOf(r.ctx), reflect.ValueOf(closureID), reflect.ValueOf(rpcArgs)})
rcpRv, err := utils.Call(rpc, []reflect.Value{reflect.ValueOf(r.ctx), reflect.ValueOf(closureID), reflect.ValueOf(rpcArgs)})
if err != nil {
errs <- err

return
}

rv := []reflect.Value{}
if functionType.NumOut() == 1 {
Expand Down Expand Up @@ -439,7 +445,12 @@ func (r Registry[R]) Link(
}

go func() {
res := function.Call(args)
res, err := utils.Call(function, args)
if err != nil {
errs <- err

return
}

switch len(res) {
case 0:
Expand Down
26 changes: 26 additions & 0 deletions pkg/utils/call.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package utils

import (
"errors"
"reflect"
)

var (
ErrPanickedWithNonErrorValue = errors.New("panicked with no error value")
)

func Call(fn reflect.Value, in []reflect.Value) (out []reflect.Value, err error) {
defer func() {
if e := recover(); e != nil {
var ok bool
err, ok = e.(error)
if !ok {
err = ErrPanickedWithNonErrorValue
}
}
}()

out = fn.Call(in)

return
}

0 comments on commit d61bf81

Please sign in to comment.