-
Notifications
You must be signed in to change notification settings - Fork 881
feat: add port-forward subcommand #1350
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Codecov Report
@@ Coverage Diff @@
## main #1350 +/- ##
==========================================
- Coverage 66.58% 66.39% -0.19%
==========================================
Files 284 278 -6
Lines 18593 18450 -143
Branches 235 235
==========================================
- Hits 12380 12250 -130
+ Misses 4950 4934 -16
- Partials 1263 1266 +3
Continue to review full report at Codecov.
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really clean! Just a few minor comments. 😎😎😎
cases := []struct { | ||
name string | ||
setup func(t *testing.T) net.Listener | ||
}{ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These are done beautifully! 😍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a small suggestion and logic check, looks good otherwise 👍🏻.
agent/agent.go
Outdated
ctx, cancel := context.WithCancel(ctx) | ||
|
||
copyFunc := func(dst io.WriteCloser, src io.Reader) { | ||
defer cancel() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could it lead to problems if c1
finishes early, resulting in c2.Close()
being called before c2
has finished copying?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I switched this to a WaitGroup to avoid this case... not sure if it could've happened in practice but better to be safe than sorry
Closes #828 |
Incidentally while testing this PR I found and fixed two bugs:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Great job on this, very awesome developer UX 🥳🥳🥳🥳🥳.
// Bicopy copies all of the data between the two connections and will close them | ||
// after one or both of them are done writing. If the context is canceled, both | ||
// of the connections will be closed. | ||
func Bicopy(ctx context.Context, c1, c2 io.ReadWriteCloser) { | ||
defer c1.Close() | ||
defer c2.Close() | ||
|
||
var wg sync.WaitGroup | ||
copyFunc := func(dst io.WriteCloser, src io.Reader) { | ||
defer wg.Done() | ||
_, _ = io.Copy(dst, src) | ||
} | ||
|
||
wg.Add(2) | ||
go copyFunc(c1, c2) | ||
go copyFunc(c2, c1) | ||
|
||
// Convert waitgroup to a channel so we can also wait on the context. | ||
done := make(chan struct{}) | ||
go func() { | ||
defer close(done) | ||
wg.Wait() | ||
}() | ||
|
||
select { | ||
case <-ctx.Done(): | ||
case <-done: | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we just close the other connection if one finishes? Because the dialer already has a context, all connections will be closed when it exists.
go func() {
defer c1.Close()
_, _ = io.Copy(c1, c2)
}()
defer c2.Close()
_, _ = io.Copy(c2, c1)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Once connected the context passed to DialContext does not affect the lifetime of the connection, so if the context is cancelled the net.Conn won't be closed.
Adds a new webrtc sub-protocol
dial
where the datachannel label is a URI to dial i.e.tcp://127.0.0.1:1234
orunix:///path/to/socket.sock
. All protocols supported bynet.Dial()
on the agent's OS are supported, includingtcp
,udp
, andunix
(except Windows).To transmit errors, the first packet on a
dial
datachannel is a JSON payload sent from the agent with the error fromnet.Dial
if any. If there was an error, the datachannel will be closed immediately.The
coder port-forward <workspace>
subcommand accepts one or more flags such as--tcp
,--udp
, or--unix
. You can specify multiple flags of each type, and multiple types of flags in the same command. To aid Windows users debugging Unix sockets in their workspace (as Unix sockets are not supported on Windows), you can use--unix <port>:<path>
instead which will listen locally on a TCP port.Port 0 is unsupported at this time but could be easily added in the future. Avoided for now because it's difficult to test (as we would need to parse the output to detect what port was actually used).
Subtasks
dial
WebRTC sub-protocoldial
sub-protocol tests for TCP, UDP and Unixcoder port-forward
command with aliascoder tunnel
that uses itResolves #1306