Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
dev6699 committed May 13, 2024
0 parents commit 3b69cc5
Show file tree
Hide file tree
Showing 19 changed files with 862 additions and 0 deletions.
17 changes: 17 additions & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/go
{
"name": "RTerm",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/go:1-1.22-bookworm"
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Use 'postCreateCommand' to run commands after the container is created.
// "postCreateCommand": "go version",
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "root"
}
7 changes: 7 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.PHONY: run
run:
go run cmd/rterm/main.go

.PHONY: build
build:
CGO_ENABLED=0 go build -o rterm cmd/rterm/main.go
39 changes: 39 additions & 0 deletions cmd/rterm/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package main

import (
"log"

"github.com/dev6699/rterm/command"
"github.com/dev6699/rterm/server"
"github.com/dev6699/rterm/ui"
)

func main() {
err := run()
if err != nil {
log.Fatalf("program exited; err = %v", err)
}
}

func run() error {
assets, err := ui.Assets()
if err != nil {
return err
}

srv, err := server.New(
assets,
func() (*command.Command, error) {
return command.New("bash", nil)
},
)
if err != nil {
return err
}

addr := ":5000"
log.Println("⚠️ CAUTION USE AT YOUR OWN RISK!!! ⚠️")
log.Printf("Server listening on http://0.0.0.0%s", addr)

return srv.Run(addr)
}
70 changes: 70 additions & 0 deletions command/command.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
package command

import (
"os"
"os/exec"
"syscall"
"unsafe"

"github.com/creack/pty"
)

type Command struct {
pty *os.File
cmd *exec.Cmd
}

func New(name string, arg []string) (*Command, error) {
cmd := exec.Command(name, arg...)

f, err := pty.Start(cmd)
if err != nil {
return nil, err
}

c := &Command{
cmd: cmd,
pty: f,
}

go c.wait()
return c, nil
}

func (c *Command) wait() {
defer c.pty.Close()
c.cmd.Wait()
}

func (c *Command) Read(p []byte) (n int, err error) {
return c.pty.Read(p)
}

func (c *Command) Write(p []byte) (n int, err error) {
return c.pty.Write(p)
}

func (c *Command) ResizeTerminal(width int, height int) error {
window := struct {
row uint16
col uint16
x uint16
y uint16
}{
uint16(height),
uint16(width),
0,
0,
}
_, _, errno := syscall.Syscall(
syscall.SYS_IOCTL,
c.pty.Fd(),
syscall.TIOCSWINSZ,
uintptr(unsafe.Pointer(&window)),
)
if errno != 0 {
return errno
} else {
return nil
}
}
10 changes: 10 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
module github.com/dev6699/rterm

go 1.22.3

require (
github.com/creack/pty v1.1.21
github.com/gorilla/websocket v1.5.1
)

require golang.org/x/net v0.17.0 // indirect
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
github.com/creack/pty v1.1.21 h1:1/QdRyBaHHJP61QkWMXlOIBfsgdDeeKfK8SYVUWJKf0=
github.com/creack/pty v1.1.21/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY=
github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY=
golang.org/x/net v0.17.0 h1:pVaXccu2ozPjCXewfr1S7xza/zcXTity9cCdXQYSjIM=
golang.org/x/net v0.17.0/go.mod h1:NxSsAGuq816PNPmqtQdLE42eU2Fs7NoRIZrHJAlaCOE=
61 changes: 61 additions & 0 deletions server/server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package server

import (
"io/fs"
"log"
"net/http"

"github.com/dev6699/rterm/command"
"github.com/dev6699/rterm/tty"
"github.com/gorilla/websocket"
)

type CommandFactory = func() (*command.Command, error)

type Server struct {
wsUpgrader *websocket.Upgrader
cmdFac CommandFactory
}

func New(assets fs.FS, cmdFac CommandFactory) (*Server, error) {
s := &Server{
wsUpgrader: &websocket.Upgrader{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
CheckOrigin: func(r *http.Request) bool {
return true
},
},
cmdFac: cmdFac,
}

http.Handle("/", http.FileServer(http.FS(assets)))
http.HandleFunc("/ws", s.handleWebSocket)

return s, nil
}

func (s *Server) Run(addr string) error {
return http.ListenAndServe(addr, nil)
}

func (s *Server) handleWebSocket(w http.ResponseWriter, r *http.Request) {
conn, err := s.wsUpgrader.Upgrade(w, r, nil)
if err != nil {
log.Printf("server: failed to upgrade websocket; err = %v", err)
return
}
defer conn.Close()

cmd, err := s.cmdFac()
if err != nil {
log.Printf("server: failed to start command; err = %v", err)
return
}

t := tty.New(WSController{Conn: conn}, cmd)
err = t.Run(r.Context())
if err != nil {
log.Printf("server: socket connection closed; err = %v", err)
}
}
31 changes: 31 additions & 0 deletions server/ws.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package server

import "github.com/gorilla/websocket"

type WSController struct {
*websocket.Conn
}

func (w WSController) Write(p []byte) (n int, err error) {
writer, err := w.Conn.NextWriter(websocket.TextMessage)
if err != nil {
return 0, err
}
defer writer.Close()
return writer.Write(p)
}

func (w WSController) Read(p []byte) (n int, err error) {
for {
msgType, reader, err := w.Conn.NextReader()
if err != nil {
return 0, err
}

if msgType != websocket.TextMessage {
continue
}

return reader.Read(p)
}
}
9 changes: 9 additions & 0 deletions tty/agent.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package tty

import "io"

type Agent interface {
io.ReadWriter

ResizeTerminal(columns int, row int) error
}
7 changes: 7 additions & 0 deletions tty/controller.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package tty

import "io"

type Controller interface {
io.ReadWriter
}
9 changes: 9 additions & 0 deletions tty/message.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package tty

type Message rune

const (
Input Message = '0'
Output Message = '1'
ResizeTerminal Message = '2'
)
Loading

0 comments on commit 3b69cc5

Please sign in to comment.