Skip to content

Commit

Permalink
fix merge
Browse files Browse the repository at this point in the history
Signed-off-by: hunnywar <[email protected]>
  • Loading branch information
hunnywar committed Jan 17, 2025
1 parent fedeaf4 commit a4f0b9e
Show file tree
Hide file tree
Showing 8 changed files with 197 additions and 4 deletions.
1 change: 1 addition & 0 deletions cmd/daytona/config/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ func GetIdeList() []Ide {
{"codium", "VSCodium"},
{"codium-insiders", "VSCodium Insiders"},
{"ssh", "Terminal SSH"},
{"browser-tty", "Browser Terminal"},
{"jupyter", "Jupyter"},
{"fleet", "Fleet"},
{"positron", "Positron"},
Expand Down
2 changes: 1 addition & 1 deletion docs/daytona_code.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ daytona code [WORKSPACE] [PROJECT] [flags]
### Options

```
-i, --ide string Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm)
-i, --ide string Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, browser-tty, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm)
-y, --yes Automatically confirm any prompts
```

Expand Down
2 changes: 1 addition & 1 deletion docs/daytona_create.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ daytona create [REPOSITORY_URL | PROJECT_CONFIG_NAME]... [flags]
--devcontainer-path string Automatically assign the devcontainer builder with the path passed as the flag value
--env stringArray Specify environment variables (e.g. --env 'KEY1=VALUE1' --env 'KEY2=VALUE2' ...')
--git-provider-config string Specify the Git provider configuration ID or alias
-i, --ide string Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm)
-i, --ide string Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, browser-tty, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm)
--manual Manually enter the Git repository
--multi-project Workspace with multiple projects/repos
--name string Specify the workspace name
Expand Down
2 changes: 1 addition & 1 deletion hack/docs/daytona_code.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ options:
- name: ide
shorthand: i
usage: |
Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm)
Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, browser-tty, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm)
- name: "yes"
shorthand: "y"
default_value: "false"
Expand Down
2 changes: 1 addition & 1 deletion hack/docs/daytona_create.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ options:
- name: ide
shorthand: i
usage: |
Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm)
Specify the IDE (vscode, code-insiders, browser, cursor, codium, codium-insiders, ssh, browser-tty, jupyter, fleet, positron, zed, windsurf, clion, goland, intellij, phpstorm, pycharm, rider, rubymine, webstorm)
- name: manual
default_value: "false"
usage: Manually enter the Git repository
Expand Down
53 changes: 53 additions & 0 deletions hack/get-ttyd.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/bin/bash
# Copyright 2024 Daytona Platforms Inc.
# SPDX-License-Identifier: Apache-2.0

RELEASE_TAG="1.7.7"
RELEASE_ORG="tsl0922"
TTYD_ROOT="$HOME/ttyd"

# Check if ttyd is already installed
if [ -d "$TTYD_ROOT" ]; then
echo "Terminal Server is already installed. Skipping installation."
exit 0
fi

# Ensure the RELEASE_TAG is set
if [ -z "$RELEASE_TAG" ]; then
echo "The RELEASE_TAG build arg must be set." >&2
exit 1
fi

# Determine system architecture
arch=$(uname -m)
if [ "$arch" = "x86_64" ]; then
arch="x86_64"
elif [ "$arch" = "aarch64" ]; then
arch="aarch64"
elif [ "$arch" = "armv7l" ]; then
arch="armhf"
else
echo "Unsupported architecture: $arch"
exit 1
fi

# Define the download URL and target file
download_url="https://github.com/$RELEASE_ORG/ttyd/releases/download/$RELEASE_TAG/ttyd.$arch"
target_file="$HOME/ttyd-$arch"

# Download the file using wget or curl
if command -v wget &>/dev/null; then
wget -O "$target_file" "$download_url"
elif command -v curl &>/dev/null; then
curl -fsSL -o "$target_file" "$download_url"
else
echo "Neither wget nor curl is available. Please install one of them."
exit 1
fi

# Make the binary executable
chmod +x "$target_file"

# Move ttyd to the installation directory
mkdir -p "$TTYD_ROOT/bin"
mv "$target_file" "$TTYD_ROOT/bin/ttyd"
2 changes: 2 additions & 0 deletions pkg/cmd/workspace/code.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,8 @@ func openIDE(ideId string, activeProfile config.Profile, workspaceId string, pro
return ide.OpenTerminalSsh(activeProfile, workspaceId, projectName, gpgKey, nil)
case "browser":
return ide.OpenBrowserIDE(activeProfile, workspaceId, projectName, projectProviderMetadata, gpgKey)
case "browser-tty":
return ide.OpenBrowserTerminal(activeProfile, workspaceId, projectName, gpgKey)
case "codium":
return ide.OpenVScodium(activeProfile, workspaceId, projectName, projectProviderMetadata, gpgKey)
case "codium-insiders":
Expand Down
137 changes: 137 additions & 0 deletions pkg/ide/browser-terminal.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// Copyright 2024 Daytona Platforms Inc.
// SPDX-License-Identifier: Apache-2.0

package ide

import (
"context"
"fmt"
"io"
"os"
"os/signal"
"os/exec"
"sync"
"syscall"
"time"

"github.com/daytonaio/daytona/cmd/daytona/config"
"github.com/daytonaio/daytona/internal/cmd/tailscale"
"github.com/daytonaio/daytona/internal/util"
"github.com/daytonaio/daytona/pkg/ports"
"github.com/daytonaio/daytona/pkg/views"

"github.com/pkg/browser"
log "github.com/sirupsen/logrus"
)

const startCommand = "$HOME/ttyd/bin/ttyd --port 63777 --writable --cwd"

// OpenBrowserTerminal starts a browser-based terminal and opens it in the browser
func OpenBrowserTerminal(activeProfile config.Profile, workspaceId string, projectName string, gpgKey string) error {
// Create a cancellation context for graceful shutdown
ctx, cancel := context.WithCancel(context.Background())
defer cancel() // Ensure the context is canceled on exit

// Capture OS interrupt signals for graceful exit
signalChan := make(chan os.Signal, 1)
signal.Notify(signalChan, os.Interrupt, syscall.SIGTERM)

// WaitGroup to wait for all goroutines to finish
var wg sync.WaitGroup

// Ensure SSH config exists
err := config.EnsureSshConfigEntryAdded(activeProfile.Id, workspaceId, projectName, gpgKey)
if err != nil {
return err
}

views.RenderInfoMessageBold("Downloading Terminal Server...")
projectHostname := config.GetProjectHostname(activeProfile.Id, workspaceId, projectName)

// Download and install ttyd
installServerCommand := exec.Command("ssh", projectHostname, "curl -fsSL https://download.daytona.io/daytona/tools/get-ttyd.sh | sh")
installServerCommand.Stdout = io.Writer(&util.DebugLogWriter{})
installServerCommand.Stderr = io.Writer(&util.DebugLogWriter{})

err = installServerCommand.Run()
if err != nil {
return err
}

projectDir, err := util.GetProjectDir(activeProfile, workspaceId, projectName, gpgKey)
if err != nil {
return err
}

views.RenderInfoMessageBold("Starting Terminal Server...")

// Start the terminal server in a goroutine
wg.Add(1)
go func() {
defer wg.Done()

startServerCommand := exec.CommandContext(ctx, "ssh", projectHostname, fmt.Sprintf("%s %s bash", startCommand, projectDir))
startServerCommand.Stdout = io.Writer(&util.DebugLogWriter{})
startServerCommand.Stderr = io.Writer(&util.DebugLogWriter{})

err = startServerCommand.Run()
if err != nil && ctx.Err() == nil { // Ignore errors if context was canceled
log.Error(err)
}
}()

// Forward ttyd (Terminal server) port
browserPort, errChan := tailscale.ForwardPort(workspaceId, projectName, 63777, activeProfile)
if browserPort == nil {
if err := <-errChan; err != nil {
return err
}
}

ideURL := fmt.Sprintf("http://localhost:%d", *browserPort)
// Wait for the port to be ready
for {
if ports.IsPortReady(*browserPort) {
break
}
time.Sleep(100 * time.Millisecond)
}

views.RenderInfoMessageBold(fmt.Sprintf("Forwarded %s Terminal port to %s.\nOpening browser...\n", projectName, ideURL))

err = browser.OpenURL(ideURL)
if err != nil {
log.Error("Error opening URL: " + err.Error())
}

// Handle errors from the port-forwarding goroutine
wg.Add(1)
go func() {
defer wg.Done()

for {
select {
case <-ctx.Done():
return
case err := <-errChan:
if err != nil {
// Log errors in debug mode
// Connection errors to the forwarded port should not exit the process
log.Debug(err)
}
}
}
}()

// Wait for a termination signal
<-signalChan
log.Info("Received termination signal. Shutting down gracefully...")

// Cancel the context to stop all goroutines
cancel()

// Wait for all goroutines to complete
wg.Wait()
log.Info("All tasks stopped. Exiting.")
return nil
}

0 comments on commit a4f0b9e

Please sign in to comment.