mirror of
https://github.com/coder/coder.git
synced 2025-07-09 11:45:56 +00:00
feat: Add vscodeipc
subcommand for VS Code Extension (#5326)
* Add extio * feat: Add `vscodeipc` subcommand for VS Code Extension This enables the VS Code extension to communicate with a Coder client. The extension will download the slim binary from `/bin/*` for the respective client architecture and OS, then execute `coder vscodeipc` for the connecting workspace. * Add authentication header, improve comments, and add tests for the CLI * Update cli/vscodeipc_test.go Co-authored-by: Mathias Fredriksson <mafredri@gmail.com> * Update cli/vscodeipc_test.go Co-authored-by: Mathias Fredriksson <mafredri@gmail.com> * Update cli/vscodeipc/vscodeipc_test.go Co-authored-by: Mathias Fredriksson <mafredri@gmail.com> * Fix requested changes * Fix IPC tests * Fix shell execution * Fix nix flake * Silence usage Co-authored-by: Mathias Fredriksson <mafredri@gmail.com>
This commit is contained in:
88
cli/vscodeipc.go
Normal file
88
cli/vscodeipc.go
Normal file
@ -0,0 +1,88 @@
|
||||
package cli
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/spf13/cobra"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/coder/coder/cli/cliflag"
|
||||
"github.com/coder/coder/cli/vscodeipc"
|
||||
"github.com/coder/coder/codersdk"
|
||||
)
|
||||
|
||||
// vscodeipcCmd spawns a local HTTP server on the provided port that listens to messages.
|
||||
// It's made for use by the Coder VS Code extension. See: https://github.com/coder/vscode-coder
|
||||
func vscodeipcCmd() *cobra.Command {
|
||||
var (
|
||||
rawURL string
|
||||
token string
|
||||
port uint16
|
||||
)
|
||||
cmd := &cobra.Command{
|
||||
Use: "vscodeipc <workspace-agent>",
|
||||
Args: cobra.ExactArgs(1),
|
||||
SilenceUsage: true,
|
||||
Hidden: true,
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
if rawURL == "" {
|
||||
return xerrors.New("CODER_URL must be set!")
|
||||
}
|
||||
// token is validated in a header on each request to prevent
|
||||
// unauthenticated clients from connecting.
|
||||
if token == "" {
|
||||
return xerrors.New("CODER_TOKEN must be set!")
|
||||
}
|
||||
listener, err := net.Listen("tcp", fmt.Sprintf("127.0.0.1:%d", port))
|
||||
if err != nil {
|
||||
return xerrors.Errorf("listen: %w", err)
|
||||
}
|
||||
defer listener.Close()
|
||||
addr, ok := listener.Addr().(*net.TCPAddr)
|
||||
if !ok {
|
||||
return xerrors.Errorf("listener.Addr() is not a *net.TCPAddr: %T", listener.Addr())
|
||||
}
|
||||
url, err := url.Parse(rawURL)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
agentID, err := uuid.Parse(args[0])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
client := codersdk.New(url)
|
||||
client.SetSessionToken(token)
|
||||
|
||||
handler, closer, err := vscodeipc.New(cmd.Context(), client, agentID, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer closer.Close()
|
||||
// nolint:gosec
|
||||
server := http.Server{
|
||||
Handler: handler,
|
||||
}
|
||||
defer server.Close()
|
||||
_, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s\n", addr.String())
|
||||
errChan := make(chan error, 1)
|
||||
go func() {
|
||||
err := server.Serve(listener)
|
||||
errChan <- err
|
||||
}()
|
||||
select {
|
||||
case <-cmd.Context().Done():
|
||||
return cmd.Context().Err()
|
||||
case err := <-errChan:
|
||||
return err
|
||||
}
|
||||
},
|
||||
}
|
||||
cliflag.StringVarP(cmd.Flags(), &rawURL, "url", "u", "CODER_URL", "", "The URL of the Coder instance!")
|
||||
cliflag.StringVarP(cmd.Flags(), &token, "token", "t", "CODER_TOKEN", "", "The session token of the user!")
|
||||
cmd.Flags().Uint16VarP(&port, "port", "p", 0, "The port to listen on!")
|
||||
return cmd
|
||||
}
|
Reference in New Issue
Block a user