@@ -4,15 +4,19 @@ import (
4
4
"context"
5
5
"encoding/json"
6
6
"fmt"
7
- "io"
8
7
"net"
9
8
10
9
"cdr.dev/coder-cli/coder-sdk"
11
10
"github.com/hashicorp/yamux"
11
+ "github.com/pion/datachannel"
12
12
"github.com/pion/webrtc/v3"
13
13
"nhooyr.io/websocket"
14
14
)
15
15
16
+ // Listen connects to the broker and returns a Listener that's triggered
17
+ // when a new connection is requested from a Dialer.
18
+ //
19
+ // LocalAddr on connections indicates the target specified by the dialer.
16
20
func Listen (ctx context.Context , broker string ) (net.Listener , error ) {
17
21
conn , resp , err := websocket .Dial (ctx , broker , nil )
18
22
if err != nil {
@@ -26,100 +30,174 @@ func Listen(ctx context.Context, broker string) (net.Listener, error) {
26
30
nconn := websocket .NetConn (ctx , conn , websocket .MessageBinary )
27
31
session , err := yamux .Server (nconn , nil )
28
32
if err != nil {
29
- return nil , fmt .Errorf ("" )
33
+ return nil , fmt .Errorf ("create multiplex: %w" , err )
30
34
}
31
- return nil , nil
35
+ l := & listener {
36
+ ws : conn ,
37
+ conns : make (chan net.Conn ),
38
+ }
39
+ go func () {
40
+ for {
41
+ conn , err := session .Accept ()
42
+ if err != nil {
43
+ l .acceptError = err
44
+ l .Close ()
45
+ return
46
+ }
47
+ l .negotiate (conn )
48
+ }
49
+ }()
50
+ return l , nil
32
51
}
33
52
34
53
type listener struct {
35
- session * yamux. Session
36
- }
54
+ acceptError error
55
+ ws * websocket. Conn
37
56
38
- func (l * listener ) Accept () (net.Conn , error ) {
39
- conn , err := l .session .Accept ()
40
- if err != nil {
41
- return nil , err
42
- }
57
+ conns chan net.Conn
58
+ }
43
59
60
+ // Negotiates the handshake protocol over the connection provided.
61
+ func (l * listener ) negotiate (conn net.Conn ) {
44
62
var (
45
- decoder = json .NewDecoder (conn )
46
- closeError = func (err error ) error {
63
+ err error
64
+ decoder = json .NewDecoder (conn )
65
+ rtc * webrtc.PeerConnection
66
+ // Sends the error provided then closes the connection.
67
+ // If RTC isn't connected, we'll close it.
68
+ closeError = func (err error ) {
47
69
d , _ := json .Marshal (& protoMessage {
48
70
Error : err .Error (),
49
71
})
50
72
_ , _ = conn .Write (d )
51
73
_ = conn .Close ()
52
- return err
74
+ if rtc != nil {
75
+ if rtc .ConnectionState () != webrtc .PeerConnectionStateConnected {
76
+ rtc .Close ()
77
+ rtc = nil
78
+ }
79
+ }
53
80
}
54
- rtc * webrtc.PeerConnection
55
81
)
56
82
57
83
for {
58
84
var msg protoMessage
59
85
err = decoder .Decode (& msg )
60
- if err == io .EOF {
61
- break
62
- }
63
86
if err != nil {
64
- return nil , err
87
+ closeError (err )
88
+ return
65
89
}
66
90
67
91
if msg .Candidate != "" {
68
92
if rtc == nil {
69
- return nil , closeError (fmt .Errorf ("Offer must be sent before candidates" ))
93
+ closeError (fmt .Errorf ("offer must be sent before candidates" ))
94
+ return
70
95
}
71
96
72
97
err = rtc .AddICECandidate (webrtc.ICECandidateInit {
73
98
Candidate : msg .Candidate ,
74
99
})
75
100
if err != nil {
76
- return nil , closeError (fmt .Errorf ("accept ice candidate: %w" , err ))
101
+ closeError (fmt .Errorf ("accept ice candidate: %w" , err ))
102
+ return
77
103
}
78
104
}
79
105
80
106
if msg .Offer != nil {
81
107
if msg .Servers == nil {
82
- return nil , closeError (fmt .Errorf ("ICEServers must be provided" ))
108
+ closeError (fmt .Errorf ("ICEServers must be provided" ))
109
+ return
83
110
}
84
111
rtc , err = newPeerConnection (msg .Servers )
85
112
if err != nil {
86
- return nil , closeError (err )
113
+ closeError (err )
114
+ return
87
115
}
116
+ rtc .OnDataChannel (l .handle )
88
117
flushCandidates := proxyICECandidates (rtc , conn )
89
118
err = rtc .SetRemoteDescription (* msg .Offer )
90
119
if err != nil {
91
- return nil , closeError (fmt .Errorf ("apply offer: %w" , err ))
120
+ closeError (fmt .Errorf ("apply offer: %w" , err ))
121
+ return
92
122
}
93
123
answer , err := rtc .CreateAnswer (nil )
94
124
if err != nil {
95
- return nil , closeError (fmt .Errorf ("create answer: %w" , err ))
125
+ closeError (fmt .Errorf ("create answer: %w" , err ))
126
+ return
96
127
}
97
128
err = rtc .SetLocalDescription (answer )
98
129
if err != nil {
99
- return nil , closeError (fmt .Errorf ("set local answer: %w" , err ))
130
+ closeError (fmt .Errorf ("set local answer: %w" , err ))
131
+ return
100
132
}
101
133
flushCandidates ()
102
134
103
135
data , err := json .Marshal (& protoMessage {
104
136
Answer : rtc .LocalDescription (),
105
137
})
106
138
if err != nil {
107
- return nil , closeError (fmt .Errorf ("marshal: %w" , err ))
139
+ closeError (fmt .Errorf ("marshal: %w" , err ))
140
+ return
108
141
}
109
142
_ , err = conn .Write (data )
110
143
if err != nil {
111
- return nil , closeError (fmt .Errorf ("write: %w" , err ))
144
+ closeError (fmt .Errorf ("write: %w" , err ))
145
+ return
112
146
}
113
147
}
114
148
}
149
+ }
150
+
151
+ func (l * listener ) handle (dc * webrtc.DataChannel ) {
152
+ // if dc.Protocol() == controlChannel {
153
+ // return
154
+ // }
155
+
156
+ fmt .Printf ("GOT CHANNEL %s\n " , dc .Protocol ())
157
+
158
+ // dc.OnOpen(func() {
159
+ // rw, err := dc.Detach()
160
+ // })
161
+ }
115
162
116
- return nil , nil
163
+ // Accept accepts a new connection.
164
+ func (l * listener ) Accept () (net.Conn , error ) {
165
+ return <- l .conns , l .acceptError
117
166
}
118
167
168
+ // Close closes the broker socket.
119
169
func (l * listener ) Close () error {
120
- return nil
170
+ close (l .conns )
171
+ return l .ws .Close (websocket .StatusNormalClosure , "" )
121
172
}
122
173
174
+ // Since this listener is bound to the WebSocket, we could
175
+ // return that resolved Addr, but until we need it we won't.
123
176
func (l * listener ) Addr () net.Addr {
124
177
return nil
125
178
}
179
+
180
+ type dataChannelConn struct {
181
+ rw datachannel.ReadWriteCloser
182
+ localAddr net.Addr
183
+ }
184
+
185
+ func (d * dataChannelConn ) Read (b []byte ) (n int , err error ) {
186
+ return d .rw .Read (b )
187
+ }
188
+
189
+ func (d * dataChannelConn ) Write (b []byte ) (n int , err error ) {
190
+ return d .rw .Write (b )
191
+ }
192
+
193
+ func (d * dataChannelConn ) Close () error {
194
+ return d .Close ()
195
+ }
196
+
197
+ func (d * dataChannelConn ) LocalAddr () net.Addr {
198
+ return d .localAddr
199
+ }
200
+
201
+ func (d * dataChannelConn ) RemoteAddr () net.Addr {
202
+ return nil
203
+ }
0 commit comments