Comments (3)
Thanks for your time, it's appreciated! Seems so obvious now that someone showed me the solution 😄. For anyone else that is trying to use the Charm modules to make ssh apps like the Wish module here's a more interesting app from the Wish module examples that just works out of the box. I see myself leaning into Nano unikernels more for some of my services and apps.
package main
// An example Bubble Tea server. This will put an ssh session into alt screen
// and continually print up to date terminal information.
import (
"context"
"errors"
"fmt"
"net"
"os"
"os/signal"
"syscall"
"time"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/charmbracelet/log"
"github.com/charmbracelet/ssh"
"github.com/charmbracelet/wish"
"github.com/charmbracelet/wish/activeterm"
"github.com/charmbracelet/wish/bubbletea"
"github.com/charmbracelet/wish/logging"
)
const (
host = ""
port = "23234"
)
func main() {
s, err := wish.NewServer(
wish.WithAddress(net.JoinHostPort(host, port)),
wish.WithMiddleware(
bubbletea.Middleware(teaHandler),
activeterm.Middleware(), // Bubble Tea apps usually require a PTY.
logging.Middleware(),
),
)
if err != nil {
log.Error("Could not start server", "error", err)
}
done := make(chan os.Signal, 1)
signal.Notify(done, os.Interrupt, syscall.SIGINT, syscall.SIGTERM)
log.Info("Starting SSH server", "host", host, "port", port)
go func() {
if err = s.ListenAndServe(); err != nil && !errors.Is(err, ssh.ErrServerClosed) {
log.Error("Could not start server", "error", err)
done <- nil
}
}()
<-done
log.Info("Stopping SSH server")
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
defer func() { cancel() }()
if err := s.Shutdown(ctx); err != nil && !errors.Is(err, ssh.ErrServerClosed) {
log.Error("Could not stop server", "error", err)
}
}
// You can wire any Bubble Tea model up to the middleware with a function that
// handles the incoming ssh.Session. Here we just grab the terminal info and
// pass it to the new model. You can also return tea.ProgramOptions (such as
// tea.WithAltScreen) on a session by session basis.
func teaHandler(s ssh.Session) (tea.Model, []tea.ProgramOption) {
// This should never fail, as we are using the activeterm middleware.
pty, _, _ := s.Pty()
// When running a Bubble Tea app over SSH, you shouldn't use the default
// lipgloss.NewStyle function.
// That function will use the color profile from the os.Stdin, which is the
// server, not the client.
// We provide a MakeRenderer function in the bubbletea middleware package,
// so you can easily get the correct renderer for the current session, and
// use it to create the styles.
// The recommended way to use these styles is to then pass them down to
// your Bubble Tea model.
renderer := bubbletea.MakeRenderer(s)
txtStyle := renderer.NewStyle().Foreground(lipgloss.Color("10"))
quitStyle := renderer.NewStyle().Foreground(lipgloss.Color("8"))
m := model{
term: pty.Term,
width: pty.Window.Width,
height: pty.Window.Height,
txtStyle: txtStyle,
quitStyle: quitStyle,
}
return m, []tea.ProgramOption{tea.WithAltScreen()}
}
// Just a generic tea.Model to demo terminal information of ssh.
type model struct {
term string
width int
height int
txtStyle lipgloss.Style
quitStyle lipgloss.Style
}
func (m model) Init() tea.Cmd {
return nil
}
func (m model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
switch msg := msg.(type) {
case tea.WindowSizeMsg:
m.height = msg.Height
m.width = msg.Width
case tea.KeyMsg:
switch msg.String() {
case "q", "ctrl+c":
return m, tea.Quit
}
}
return m, nil
}
func (m model) View() string {
s := fmt.Sprintf("Your term is %s\nYour window size is %dx%d", m.term, m.width, m.height)
return m.txtStyle.Render(s) + "\n\n" + m.quitStyle.Render("Press 'q' to quit\n")
}
And when you hit that port with ssh on an instance with a Nano unikernel you get this and pressing q works!
Your term is xterm-256color
Your window size is 180x51
Press 'q' to quit
from ops.
it doesn't allow the user to execute any commands, only to hit the ssh server and be served content much like a http hello world REST API
you don't need a "real" PTY then.
Can you try and check if the following changes work for you?
- comment/delete
ssh.AllocatePty(),
or change it tossh.EmulatePty(),
- remove
wish.Printf(sess, "PTY: "+pty.Slave.Name()+"\r\n")
since there are no fd allocated or change it to smth likeif !pty.IsZero() { wish.Printf(sess, "PTY: "+pty.Slave.Name()+"\r\n") }
from ops.
I'll close this as the reply from @rinor solved it.
from ops.
Related Issues (20)
- feature request to deploy to Hivelocity.net provider HOT 4
- GCP instance creation to an instance-group fails from non-default interface name HOT 1
- qmp for local instances doesn't work w/custom instance names HOT 1
- unimplemented socket options for Python amqp HOT 5
- GCP rate limit: one disk image create every 10 minutes HOT 4
- Unikernel Process Not Starting with Memory Size Beyond a Certain Range in Firecracker HOT 7
- Incomplete documentation, no real world nodejs runner example HOT 2
- Instance tags through config.json in DO HOT 2
- Ops deploy does not use InstanceName on DO HOT 1
- Memory metric not showing for instance on digital ocean HOT 2
- Error: failed converting configuration file: json: cannot unmarshal number into Go struct field RunConfig.RunConfig.Ports of type string HOT 3
- Run on GCP Cloud Run HOT 3
- Cannot seem to push locally built package HOT 3
- Feat suggestion: Show progress in ops image create HOT 5
- [Mac M1] ops pkg list (question / bug) HOT 2
- No network on Azure HOT 2
- Does exec/command need full paths? HOT 9
- GPU integration with nanos HOT 9
- How to package a program on the outer layer of a public package? HOT 4
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ops.