Set window title by control message

This commit is contained in:
Iwasaki Yudai 2015-08-23 20:40:18 +09:00
parent 67b54b7f20
commit a765d6c660
7 changed files with 106 additions and 55 deletions

View File

@ -3,7 +3,7 @@ gotty: app/resource.go main.go app/*.go
resource: app/resource.go resource: app/resource.go
app/resource.go: bindata/static/hterm.js bindata/static/gotty.js bindata/templates/index.html app/resource.go: bindata/static/hterm.js bindata/static/gotty.js bindata/static/index.html
go-bindata -prefix bindata -pkg app -ignore=\\.gitkeep -o app/resource.go bindata/... go-bindata -prefix bindata -pkg app -ignore=\\.gitkeep -o app/resource.go bindata/...
gofmt -w app/resource.go gofmt -w app/resource.go
@ -23,5 +23,5 @@ bindata/static/hterm.js: bindata/static libapps/hterm/js/*.js
bindata/static/gotty.js: bindata/static resources/gotty.js bindata/static/gotty.js: bindata/static resources/gotty.js
cp resources/gotty.js bindata/static/gotty.js cp resources/gotty.js bindata/static/gotty.js
bindata/templates/index.html: bindata/templates resources/index.html bindata/static/index.html: bindata/static resources/index.html
cp resources/index.html bindata/templates/index.html cp resources/index.html bindata/static/index.html

View File

@ -1,19 +1,17 @@
package app package app
import ( import (
"bytes"
"crypto/rand" "crypto/rand"
"encoding/base64" "encoding/base64"
htemplate "html/template" "errors"
"log" "log"
"math/big" "math/big"
"net" "net"
"net/http" "net/http"
"os"
"os/exec" "os/exec"
"strconv" "strconv"
"strings" "strings"
ttemplate "text/template" "text/template"
"github.com/elazarl/go-bindata-assetfs" "github.com/elazarl/go-bindata-assetfs"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
@ -23,7 +21,8 @@ import (
type App struct { type App struct {
options Options options Options
upgrader *websocket.Upgrader upgrader *websocket.Upgrader
titleTemplate *template.Template
} }
type Options struct { type Options struct {
@ -36,7 +35,12 @@ type Options struct {
Command []string Command []string
} }
func New(options Options) *App { func New(options Options) (*App, error) {
titleTemplate, err := template.New("title").Parse(options.TitleFormat)
if err != nil {
return nil, errors.New("Title format string syntax error")
}
return &App{ return &App{
options: options, options: options,
@ -45,7 +49,8 @@ func New(options Options) *App {
WriteBufferSize: 1024, WriteBufferSize: 1024,
Subprotocols: []string{"gotty"}, Subprotocols: []string{"gotty"},
}, },
} titleTemplate: titleTemplate,
}, nil
} }
func (app *App) Run() error { func (app *App) Run() error {
@ -56,15 +61,13 @@ func (app *App) Run() error {
endpoint := app.options.Address + ":" + app.options.Port endpoint := app.options.Address + ":" + app.options.Port
indexHandler := http.HandlerFunc(app.handleIndex)
wsHandler := http.HandlerFunc(app.handleWS) wsHandler := http.HandlerFunc(app.handleWS)
staticHandler := http.FileServer( staticHandler := http.FileServer(
&assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, Prefix: "static"}, &assetfs.AssetFS{Asset: Asset, AssetDir: AssetDir, Prefix: "static"},
) )
var siteMux = http.NewServeMux() var siteMux = http.NewServeMux()
siteMux.Handle(path+"/", indexHandler) siteMux.Handle(path+"/", http.StripPrefix(path+"/", staticHandler))
siteMux.Handle(path+"/static/", http.StripPrefix(path+"/static/", staticHandler))
siteMux.Handle(path+"/ws", wsHandler) siteMux.Handle(path+"/ws", wsHandler)
siteHandler := http.Handler(siteMux) siteHandler := http.Handler(siteMux)
@ -94,36 +97,6 @@ func (app *App) Run() error {
return nil return nil
} }
type TitleVars struct {
Command string
Hostname string
}
type IndexVars struct {
Title string
}
func (app *App) handleIndex(w http.ResponseWriter, r *http.Request) {
title := make([]byte, 0)
titleBuf := bytes.NewBuffer(title)
hostname, _ := os.Hostname()
titleVars := TitleVars{
Command: strings.Join(app.options.Command, " "),
Hostname: hostname,
}
titleTmpl, _ := ttemplate.New("title").Parse(app.options.TitleFormat)
titleTmpl.Execute(titleBuf, titleVars)
data, _ := Asset("templates/index.html")
tmpl, _ := htemplate.New("index").Parse(string(data))
vars := IndexVars{
Title: titleBuf.String(),
}
tmpl.Execute(w, vars)
}
func (app *App) handleWS(w http.ResponseWriter, r *http.Request) { func (app *App) handleWS(w http.ResponseWriter, r *http.Request) {
log.Printf("New client connected: %s", r.RemoteAddr) log.Printf("New client connected: %s", r.RemoteAddr)

View File

@ -6,6 +6,7 @@ import (
"net/http" "net/http"
"os" "os"
"os/exec" "os/exec"
"strings"
"syscall" "syscall"
"unsafe" "unsafe"
@ -26,11 +27,23 @@ const (
ResizeTerminal = '1' ResizeTerminal = '1'
) )
const (
Output = '0'
SetWindowTitle = '1'
)
type argResizeTerminal struct { type argResizeTerminal struct {
Columns float64 Columns float64
Rows float64 Rows float64
} }
type ContextVars struct {
Command string
Pid int
Hostname string
RemoteAddr string
}
func (context *clientContext) goHandleClient() { func (context *clientContext) goHandleClient() {
exit := make(chan bool, 2) exit := make(chan bool, 2)
@ -56,6 +69,11 @@ func (context *clientContext) goHandleClient() {
} }
func (context *clientContext) processSend() { func (context *clientContext) processSend() {
if err := context.sendInitialize(); err != nil {
log.Printf(err.Error())
return
}
buf := make([]byte, 1024) buf := make([]byte, 1024)
utf8f := utf8reader.New(context.pty) utf8f := utf8reader.New(context.pty)
@ -71,11 +89,34 @@ func (context *clientContext) processSend() {
return return
} }
writer.Write([]byte{Output})
writer.Write(buf[:size]) writer.Write(buf[:size])
writer.Close() writer.Close()
} }
} }
func (context *clientContext) sendInitialize() error {
hostname, _ := os.Hostname()
titleVars := ContextVars{
Command: strings.Join(context.app.options.Command, " "),
Pid: context.command.Process.Pid,
Hostname: hostname,
RemoteAddr: context.request.RemoteAddr,
}
writer, err := context.connection.NextWriter(websocket.TextMessage)
if err != nil {
return err
}
writer.Write([]byte{SetWindowTitle})
if err = context.app.titleTemplate.Execute(writer, titleVars); err != nil {
return err
}
writer.Close()
return nil
}
func (context *clientContext) processReceive() { func (context *clientContext) processReceive() {
for { for {
_, data, err := context.connection.ReadMessage() _, data, err := context.connection.ReadMessage()

File diff suppressed because one or more lines are too long

10
main.go
View File

@ -56,7 +56,8 @@ func main() {
cli.ShowAppHelp(c) cli.ShowAppHelp(c)
os.Exit(1) os.Exit(1)
} }
app := app.New(
app, err := app.New(
app.Options{ app.Options{
c.String("addr"), c.String("addr"),
c.String("port"), c.String("port"),
@ -67,11 +68,16 @@ func main() {
c.Args(), c.Args(),
}, },
) )
err := app.Run()
if err != nil { if err != nil {
fmt.Println(err) fmt.Println(err)
os.Exit(2) os.Exit(2)
} }
err = app.Run()
if err != nil {
fmt.Println(err)
os.Exit(3)
}
} }
cli.AppHelpTemplate = helpTemplate cli.AppHelpTemplate = helpTemplate

View File

@ -38,7 +38,15 @@
}; };
ws.onmessage = function(event) { ws.onmessage = function(event) {
term.io.writeUTF16(event.data); data = event.data.slice(1);
switch(event.data[0]) {
case '0':
term.io.writeUTF16(data);
break;
case '1':
term.setWindowTitle(data);
break;
}
} }
ws.onclose = function(event) { ws.onclose = function(event) {

View File

@ -1,11 +1,11 @@
<!doctype html> <!doctype html>
<html> <html>
<head> <head>
<title>{{ .Title }}</title> <title>GoTTY</title>
<style>body {position: absolute; height: 100%; width: 100%; margin: 0px;}</style> <style>body {position: absolute; height: 100%; width: 100%; margin: 0px;}</style>
</head> </head>
<body> <body>
<script src="static/hterm.js"></script> <script src="hterm.js"></script>
<script src="static/gotty.js"></script> <script src="gotty.js"></script>
</body> </body>
</html> </html>