This repository has been archived by the owner on Mar 27, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 162
/
outbound.go
109 lines (84 loc) · 2.65 KB
/
outbound.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
/*
Copyright SecureKey Technologies Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/
package ws
import (
"context"
"fmt"
"strings"
"nhooyr.io/websocket"
"github.com/hyperledger/aries-framework-go/pkg/didcomm/common/service"
"github.com/hyperledger/aries-framework-go/pkg/didcomm/protocol/decorator"
"github.com/hyperledger/aries-framework-go/pkg/didcomm/transport"
)
const webSocketScheme = "ws"
// OutboundClient websocket outbound.
type OutboundClient struct {
pool *connPool
prov transport.Provider
}
// NewOutbound creates a client for Outbound WS transport.
func NewOutbound() *OutboundClient {
return &OutboundClient{}
}
// Start starts the outbound transport.
func (cs *OutboundClient) Start(prov transport.Provider) error {
cs.pool = getConnPool(prov)
cs.prov = prov
return nil
}
// Send sends a2a data via WS.
func (cs *OutboundClient) Send(data []byte, destination *service.Destination) (string, error) {
conn, cleanup, err := cs.getConnection(destination)
defer cleanup()
if err != nil {
return "", fmt.Errorf("get websocket connection : %w", err)
}
err = conn.Write(context.Background(), websocket.MessageText, data)
if err != nil {
return "", fmt.Errorf("websocket write message : %w", err)
}
return "", nil
}
// Accept checks for the url scheme.
func (cs *OutboundClient) Accept(url string) bool {
return strings.HasPrefix(url, webSocketScheme)
}
// AcceptRecipient checks if there is a connection for the list of recipient keys
func (cs *OutboundClient) AcceptRecipient(keys []string) bool {
return acceptRecipient(cs.pool, keys)
}
func (cs *OutboundClient) getConnection(destination *service.Destination) (*websocket.Conn, func(), error) {
var conn *websocket.Conn
// get the connection for the recipient keys
for _, v := range destination.RecipientKeys {
if c := cs.pool.fetch(v); c != nil {
conn = c
break
}
}
cleanup := func() {}
if conn == nil {
var err error
conn, _, err = websocket.Dial(context.Background(), destination.ServiceEndpoint, nil)
if err != nil {
return nil, cleanup, fmt.Errorf("websocket client : %w", err)
}
// keep the connection open to listen to the response in case of return route option set
if destination.TransportReturnRoute == decorator.TransportReturnRouteAll {
for _, v := range destination.RecipientKeys {
cs.pool.add(v, conn)
}
go cs.pool.listener(conn)
} else {
cleanup = func() {
err = conn.Close(websocket.StatusNormalClosure, "closing the connection")
if err != nil && websocket.CloseStatus(err) != websocket.StatusNormalClosure {
logger.Errorf("failed to close connection: %v", err)
}
}
}
}
return conn, cleanup, nil
}