-
Notifications
You must be signed in to change notification settings - Fork 1
/
relay.go
145 lines (124 loc) · 4.93 KB
/
relay.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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
package water
import (
"context"
"errors"
"net"
)
// Relay listens on a local network address and handles requests
// on incoming connections by passing the incoming connection to
// the WebAssembly Transport Module and dial corresponding
// outbound connections to a pre-defined destination address.
// By doing so, WATM upgrades the incoming connection.
//
// The structure of a Relay is as follows:
//
// accept +---------------+ +---------------+ dial
// ------->| |----->| Upgrade |----->
// Source | net.Listener | | WebAssembly | Remote
// <-------| |<-----| Downgrade |<-----
// +---------------+ +---------------+
// \ /
// \------Relay-------/
type Relay interface {
// RelayTo relays the incoming connection to the address specified
// by network and address.
RelayTo(network, address string) error
// ListenAndRelayTo listens on the local network address and relays
// the incoming connection to the address specified by rnetwork
// and raddress.
ListenAndRelayTo(lnetwork, laddress, rnetwork, raddress string) error
// Close closes the relay. No further incoming connections will be
// accepted and no further outbound connections will be dialed. It
// does not close the established connections.
Close() error
// Addr returns the local address the relay is listening on.
//
// If no address is available, instead of panicking it returns nil.
Addr() net.Addr
mustEmbedUnimplementedRelay()
}
type newRelayFunc func(context.Context, *Config) (Relay, error)
var (
knownRelayVersions = make(map[string]newRelayFunc)
ErrRelayAlreadyRegistered = errors.New("water: relay already registered")
ErrRelayVersionNotFound = errors.New("water: relay version not found")
ErrUnimplementedRelay = errors.New("water: unimplemented relay")
ErrRelayAlreadyStarted = errors.New("water: relay already started") // RelayTo and ListenAndRelayTo may return this error if a relay was reused.
_ Relay = (*UnimplementedRelay)(nil) // type guard
)
// UnimplementedRelay is a Relay that always returns errors.
//
// It is used to ensure forward compatibility of the Relay interface.
type UnimplementedRelay struct{}
// RelayTo implements Relay.RelayTo().
func (*UnimplementedRelay) RelayTo(_, _ string) error {
return ErrUnimplementedRelay
}
// ListenAndRelayTo implements Relay.ListenAndRelayTo().
func (*UnimplementedRelay) ListenAndRelayTo(_, _, _, _ string) error {
return ErrUnimplementedRelay
}
// Close implements Relay.Close().
func (*UnimplementedRelay) Close() error {
return ErrUnimplementedRelay
}
// Addr implements Relay.Addr().
func (*UnimplementedRelay) Addr() net.Addr {
return nil
}
// mustEmbedUnimplementedRelay is a function that developers cannot
// manually implement. It is used to ensure forward compatibility of
// the Relay interface.
func (*UnimplementedRelay) mustEmbedUnimplementedRelay() {} //nolint:unused
// RegisterWATMRelay is a function used by Transport Module drivers
// (e.g., `transport/v0`) to register a function that spawns a new [Relay]
// from a given [Config] for a specific version. Renamed from RegisterRelay.
//
// This is not a part of WATER API and should not be used by developers
// wishing to integrate WATER into their applications.
func RegisterWATMRelay(version string, relay newRelayFunc) error {
if _, ok := knownRelayVersions[version]; ok {
return ErrRelayAlreadyRegistered
}
knownRelayVersions[version] = relay
return nil
}
// NewRelay creates a new [Relay] from the given [Config].
//
// It automatically detects the version of the WebAssembly Transport
// Module specified in the config.
//
// Deprecated: use [NewRelayWithContext] instead.
func NewRelay(c *Config) (Relay, error) {
return NewRelayWithContext(context.Background(), c)
}
// NewRelayWithContext creates a new [Relay] from the [Config] with
// the given [context.Context].
//
// It automatically detects the version of the WebAssembly Transport
// Module specified in the config.
//
// The context is passed to [NewCoreWithContext] and the registered versioned
// relay creation function to control the lifetime of the call to function
// calls into the WebAssembly module.
// If the context is canceled or reaches its deadline, any current and future
// function call will return with an error.
// Call [WazeroRuntimeConfigFactory.SetCloseOnContextDone] with false to disable
// this behavior.
func NewRelayWithContext(ctx context.Context, c *Config) (Relay, error) {
core, err := NewCoreWithContext(ctx, c)
if err != nil {
return nil, err
}
// Search through all exported names and match them to potential
// Listener versions.
//
// TODO: detect the version of the WebAssembly Transport Module
// in a more organized way.
for exportName := range core.Exports() {
if f, ok := knownRelayVersions[exportName]; ok {
return f(ctx, c)
}
}
return nil, ErrRelayVersionNotFound
}