-
Notifications
You must be signed in to change notification settings - Fork 64
/
Copy pathsession.go
129 lines (110 loc) · 3.14 KB
/
session.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
/*
Copyright IBM Corp. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package ttx
import (
"context"
"encoding/base64"
"github.com/hyperledger-labs/fabric-smart-client/platform/view/view"
"github.com/pkg/errors"
)
// LocalBidirectionalChannel is a bidirectional channel that is used to simulate
// a session between two views (let's call them L and R) running in the same process.
type LocalBidirectionalChannel struct {
left view.Session
right view.Session
}
// NewLocalBidirectionalChannel creates a new bidirectional channel
func NewLocalBidirectionalChannel(caller string, contextID string, endpoint string, pkid []byte) (*LocalBidirectionalChannel, error) {
ID, err := GetRandomNonce()
if err != nil {
return nil, errors.Wrap(err, "failed to generate session ID")
}
lr := make(chan *view.Message, 10)
rl := make(chan *view.Message, 10)
info := view.SessionInfo{
ID: base64.StdEncoding.EncodeToString(ID),
Caller: nil,
CallerViewID: "",
Endpoint: endpoint,
EndpointPKID: pkid,
Closed: false,
}
return &LocalBidirectionalChannel{
left: &localSession{
name: "left",
contextID: contextID,
caller: caller,
info: info,
readChannel: rl,
writeChannel: lr,
},
right: &localSession{
name: "right",
contextID: contextID,
caller: caller,
info: info,
readChannel: lr,
writeChannel: rl,
},
}, nil
}
// LeftSession returns the session from the L to R
func (c *LocalBidirectionalChannel) LeftSession() view.Session {
return c.left
}
// RightSession returns the session from the R to L
func (c *LocalBidirectionalChannel) RightSession() view.Session {
return c.right
}
// localSession is a local session that is used to simulate a session between two views.
// It has a read channel and a write channel.
type localSession struct {
name string
contextID string
caller string
info view.SessionInfo
readChannel chan *view.Message
writeChannel chan *view.Message
}
func (s *localSession) Info() view.SessionInfo {
return s.info
}
func (s *localSession) Send(payload []byte) error {
return s.SendWithContext(context.Background(), payload)
}
func (s *localSession) SendWithContext(ctx context.Context, payload []byte) error {
return s.send(ctx, payload, view.OK)
}
func (s *localSession) SendError(payload []byte) error {
return s.SendErrorWithContext(context.Background(), payload)
}
func (s *localSession) SendErrorWithContext(ctx context.Context, payload []byte) error {
return s.send(ctx, payload, view.ERROR)
}
func (s *localSession) send(ctx context.Context, payload []byte, status int32) error {
if s.info.Closed {
return errors.New("session is closed")
}
s.writeChannel <- &view.Message{
SessionID: s.info.ID,
ContextID: s.contextID,
Caller: s.caller,
FromEndpoint: s.info.Endpoint,
FromPKID: s.info.EndpointPKID,
Status: status,
Payload: payload,
Ctx: ctx,
}
return nil
}
func (s *localSession) Receive() <-chan *view.Message {
if s.info.Closed {
return nil
}
return s.readChannel
}
func (s *localSession) Close() {
s.info.Closed = true
}