Skip to content

Commit 46fb0c7

Browse files
authored
refactor: ability to run a view with a different context (#1085)
- adding the ability to run a view with a different context. - adding more godocs - renaming - moving mock Signed-off-by: Angelo De Caro <[email protected]>
1 parent 427147b commit 46fb0c7

File tree

12 files changed

+2526
-315
lines changed

12 files changed

+2526
-315
lines changed

integration/fsc/pingpong/mock/initiator.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors"
1313
"github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/assert"
1414
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/id"
15-
view3 "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/view"
1615
"github.com/hyperledger-labs/fabric-smart-client/platform/view/view"
1716
)
1817

@@ -31,7 +30,7 @@ func (p *Initiator) Call(ctx view.Context) (interface{}, error) {
3130
responder := identityProvider.Identity("responder")
3231
var context view.Context
3332
if p.Mock {
34-
c := &view3.MockContext{Ctx: ctx}
33+
c := &DelegatedContext{Ctx: ctx}
3534
c.RespondToAs(ctx.Initiator(), responder, &Responder{})
3635
context = c
3736
} else {

platform/view/services/view/runner.go renamed to integration/fsc/pingpong/mock/runner.go

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ Copyright IBM Corp. All Rights Reserved.
44
SPDX-License-Identifier: Apache-2.0
55
*/
66

7-
package view
7+
package mock
88

99
import (
1010
"context"
1111
"sync"
1212

1313
"github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors"
1414
"github.com/hyperledger-labs/fabric-smart-client/platform/view/services/comm/session"
15+
view2 "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/view"
1516
"github.com/hyperledger-labs/fabric-smart-client/platform/view/view"
1617
"go.opentelemetry.io/otel/trace"
1718
"go.opentelemetry.io/otel/trace/noop"
@@ -25,61 +26,61 @@ type Responders struct {
2526
Channel *session.LocalBidirectionalChannel
2627
}
2728

28-
type MockContext struct {
29+
type DelegatedContext struct {
2930
Ctx view.Context
3031
responders []*Responders
3132
}
3233

33-
func (c *MockContext) StartSpanFrom(context.Context, string, ...trace.SpanStartOption) (context.Context, trace.Span) {
34+
func (c *DelegatedContext) StartSpanFrom(context.Context, string, ...trace.SpanStartOption) (context.Context, trace.Span) {
3435
return c.Context(), noop.Span{}
3536
}
3637

37-
func (c *MockContext) StartSpan(string, ...trace.SpanStartOption) trace.Span {
38+
func (c *DelegatedContext) StartSpan(string, ...trace.SpanStartOption) trace.Span {
3839
return noop.Span{}
3940
}
4041

41-
func (c *MockContext) GetService(v interface{}) (interface{}, error) {
42+
func (c *DelegatedContext) GetService(v interface{}) (interface{}, error) {
4243
return c.Ctx.GetService(v)
4344
}
4445

45-
func (c *MockContext) ID() string {
46+
func (c *DelegatedContext) ID() string {
4647
return c.Ctx.ID()
4748
}
4849

49-
func (c *MockContext) RunView(view view.View, opts ...view.RunViewOption) (interface{}, error) {
50+
func (c *DelegatedContext) RunView(view view.View, opts ...view.RunViewOption) (interface{}, error) {
5051
return c.Ctx.RunView(view, opts...)
5152
}
5253

53-
func (c *MockContext) Me() view.Identity {
54+
func (c *DelegatedContext) Me() view.Identity {
5455
return c.Ctx.Me()
5556
}
5657

57-
func (c *MockContext) IsMe(id view.Identity) bool {
58+
func (c *DelegatedContext) IsMe(id view.Identity) bool {
5859
return c.Ctx.IsMe(id)
5960
}
6061

61-
func (c *MockContext) Initiator() view.View {
62+
func (c *DelegatedContext) Initiator() view.View {
6263
return c.Ctx.Initiator()
6364
}
6465

65-
func (c *MockContext) GetSessionByID(id string, party view.Identity) (view.Session, error) {
66+
func (c *DelegatedContext) GetSessionByID(id string, party view.Identity) (view.Session, error) {
6667
// TODO: check among the responders
6768
return c.Ctx.GetSessionByID(id, party)
6869
}
6970

70-
func (c *MockContext) Session() view.Session {
71+
func (c *DelegatedContext) Session() view.Session {
7172
return c.Ctx.Session()
7273
}
7374

74-
func (c *MockContext) Context() context.Context {
75+
func (c *DelegatedContext) Context() context.Context {
7576
return c.Ctx.Context()
7677
}
7778

78-
func (c *MockContext) OnError(callback func()) {
79+
func (c *DelegatedContext) OnError(callback func()) {
7980
c.Ctx.OnError(callback)
8081
}
8182

82-
func (c *MockContext) GetSession(caller view.View, party view.Identity, boundToViews ...view.View) (view.Session, error) {
83+
func (c *DelegatedContext) GetSession(caller view.View, party view.Identity, boundToViews ...view.View) (view.Session, error) {
8384
for _, responder := range c.responders {
8485
if responder.InitiatorView == caller && responder.ResponderID.Equal(party) {
8586
responder.Lock.RLock()
@@ -103,7 +104,7 @@ func (c *MockContext) GetSession(caller view.View, party view.Identity, boundToV
103104
}
104105
left := biChannel.LeftSession()
105106
right := biChannel.RightSession()
106-
RunView(c, responder.ResponderView, view.AsResponder(right))
107+
view2.RunView(c, responder.ResponderView, view.AsResponder(right))
107108

108109
responder.Channel = biChannel
109110
return left, nil
@@ -113,30 +114,10 @@ func (c *MockContext) GetSession(caller view.View, party view.Identity, boundToV
113114
return c.Ctx.GetSession(caller, party)
114115
}
115116

116-
func (c *MockContext) RespondToAs(initiator view.View, responder view.Identity, r view.View) {
117+
func (c *DelegatedContext) RespondToAs(initiator view.View, responder view.Identity, r view.View) {
117118
c.responders = append(c.responders, &Responders{
118119
InitiatorView: initiator,
119120
ResponderID: responder,
120121
ResponderView: r,
121122
})
122123
}
123-
124-
// RunView runs passed view within the passed context and using the passed options in a separate goroutine
125-
func RunView(context view.Context, view view.View, opts ...view.RunViewOption) {
126-
defer func() {
127-
if r := recover(); r != nil {
128-
logger.Debugf("panic in RunView: %v", r)
129-
}
130-
}()
131-
go func() {
132-
defer func() {
133-
if r := recover(); r != nil {
134-
logger.Debugf("panic in RunView: %v", r)
135-
}
136-
}()
137-
_, err := context.RunView(view, opts...)
138-
if err != nil {
139-
logger.Errorf("failed to run view: %s", err)
140-
}
141-
}()
142-
}
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
/*
2+
Copyright IBM Corp. All Rights Reserved.
3+
4+
SPDX-License-Identifier: Apache-2.0
5+
*/
6+
7+
package view
8+
9+
import (
10+
"context"
11+
12+
"github.com/hyperledger-labs/fabric-smart-client/platform/view/view"
13+
"go.opentelemetry.io/otel/trace"
14+
)
15+
16+
//go:generate counterfeiter -o mock/parent_context.go -fake-name ParentContext . ParentContext
17+
type ParentContext interface {
18+
DisposableContext
19+
Cleanup()
20+
PutSession(caller view.View, party view.Identity, session view.Session) error
21+
}
22+
23+
// ChildContext is a view context with a parent.
24+
// It allows the developer to override session and initiator.
25+
// It also supports error callbacks.
26+
type ChildContext struct {
27+
Parent ParentContext
28+
29+
session view.Session
30+
initiator view.View
31+
errorCallbackFuncs []func()
32+
}
33+
34+
// NewChildContextFromParent return a new ChildContext from the given parent
35+
func NewChildContextFromParent(parentContext ParentContext) *ChildContext {
36+
return NewChildContext(parentContext, nil, nil, nil)
37+
}
38+
39+
// NewChildContextFromParentAndSession return a new ChildContext from the given parent and session
40+
func NewChildContextFromParentAndSession(parentContext ParentContext, session view.Session) *ChildContext {
41+
return NewChildContext(parentContext, session, nil, nil)
42+
}
43+
44+
// NewChildContextFromParentAndInitiator return a new ChildContext from the given parent and initiator view
45+
func NewChildContextFromParentAndInitiator(parentContext ParentContext, initiator view.View) *ChildContext {
46+
return NewChildContext(parentContext, nil, initiator, nil)
47+
}
48+
49+
// NewChildContext return a new ChildContext from the given arguments
50+
func NewChildContext(parentContext ParentContext, session view.Session, initiator view.View, errorCallbackFuncs ...func()) *ChildContext {
51+
return &ChildContext{Parent: parentContext, session: session, initiator: initiator, errorCallbackFuncs: errorCallbackFuncs}
52+
}
53+
54+
func (w *ChildContext) StartSpanFrom(c context.Context, name string, opts ...trace.SpanStartOption) (context.Context, trace.Span) {
55+
return w.Parent.StartSpanFrom(c, name, opts...)
56+
}
57+
58+
func (w *ChildContext) GetService(v interface{}) (interface{}, error) {
59+
return w.Parent.GetService(v)
60+
}
61+
62+
func (w *ChildContext) PutService(v interface{}) error {
63+
mutableContext, ok := w.Parent.(view.MutableContext)
64+
if ok {
65+
return mutableContext.PutService(v)
66+
}
67+
return nil
68+
}
69+
70+
func (w *ChildContext) ID() string {
71+
return w.Parent.ID()
72+
}
73+
74+
func (w *ChildContext) Me() view.Identity {
75+
return w.Parent.Me()
76+
}
77+
78+
func (w *ChildContext) IsMe(id view.Identity) bool {
79+
return w.Parent.IsMe(id)
80+
}
81+
82+
func (w *ChildContext) GetSession(caller view.View, party view.Identity, boundToViews ...view.View) (view.Session, error) {
83+
return w.Parent.GetSession(caller, party, boundToViews...)
84+
}
85+
86+
func (w *ChildContext) GetSessionByID(id string, party view.Identity) (view.Session, error) {
87+
return w.Parent.GetSessionByID(id, party)
88+
}
89+
90+
func (w *ChildContext) Context() context.Context {
91+
return w.Parent.Context()
92+
}
93+
94+
func (w *ChildContext) Session() view.Session {
95+
if w.session == nil {
96+
return w.Parent.Session()
97+
}
98+
return w.session
99+
}
100+
101+
func (w *ChildContext) ResetSessions() error {
102+
mutableContext, ok := w.Parent.(view.MutableContext)
103+
if ok {
104+
return mutableContext.ResetSessions()
105+
}
106+
return nil
107+
}
108+
109+
func (w *ChildContext) Initiator() view.View {
110+
if w.initiator == nil {
111+
return w.Parent.Initiator()
112+
}
113+
return w.initiator
114+
}
115+
116+
func (w *ChildContext) OnError(f func()) {
117+
w.errorCallbackFuncs = append(w.errorCallbackFuncs, f)
118+
}
119+
120+
func (w *ChildContext) RunView(v view.View, opts ...view.RunViewOption) (res interface{}, err error) {
121+
return RunViewNow(w, v, opts...)
122+
}
123+
124+
func (w *ChildContext) Dispose() {
125+
if w.Parent != nil {
126+
w.Parent.Dispose()
127+
}
128+
}
129+
130+
func (w *ChildContext) PutSession(caller view.View, party view.Identity, session view.Session) error {
131+
return w.Parent.PutSession(caller, party, session)
132+
}
133+
134+
func (w *ChildContext) Cleanup() {
135+
logger.Debugf("cleaning up child context [%s][%d]", w.ID(), len(w.errorCallbackFuncs))
136+
for _, callbackFunc := range w.errorCallbackFuncs {
137+
w.safeInvoke(callbackFunc)
138+
}
139+
}
140+
141+
func (w *ChildContext) safeInvoke(f func()) {
142+
defer func() {
143+
if r := recover(); r != nil {
144+
logger.Debugf("function [%s] panicked [%s]", f, r)
145+
}
146+
}()
147+
f()
148+
}

0 commit comments

Comments
 (0)