mirror of https://github.com/gorilla/websocket.git
Add command example
This commit is contained in:
parent
f71d4a996f
commit
f9219095ab
|
@ -7,6 +7,7 @@ Gorilla WebSocket is a [Go](http://golang.org/) implementation of the
|
||||||
|
|
||||||
* [API Reference](http://godoc.org/github.com/gorilla/websocket)
|
* [API Reference](http://godoc.org/github.com/gorilla/websocket)
|
||||||
* [Chat example](https://github.com/gorilla/websocket/tree/master/examples/chat)
|
* [Chat example](https://github.com/gorilla/websocket/tree/master/examples/chat)
|
||||||
|
* [Command example](https://github.com/gorilla/websocket/tree/master/examples/command)
|
||||||
* [Client and server example](https://github.com/gorilla/websocket/tree/master/examples/echo)
|
* [Client and server example](https://github.com/gorilla/websocket/tree/master/examples/echo)
|
||||||
* [File watch example](https://github.com/gorilla/websocket/tree/master/examples/filewatch)
|
* [File watch example](https://github.com/gorilla/websocket/tree/master/examples/filewatch)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Command example
|
||||||
|
|
||||||
|
This example connects a websocket connection to stdin and stdout of a command.
|
||||||
|
Received messages are written to stdin followed by a `\\n`. Each line read from
|
||||||
|
from standard out is sent as a message to the client.
|
||||||
|
|
||||||
|
$ go get github.com/gorilla/websocket
|
||||||
|
$ cd `go list -f '{{.Dir}}' github.com/gorilla/websocket/examples/command`
|
||||||
|
$ go run main.go <command and arguments to run>
|
||||||
|
# Open http://localhost:8080/ .
|
||||||
|
|
||||||
|
Try the following commands.
|
||||||
|
|
||||||
|
# Echo sent messages to the output area.
|
||||||
|
$ go run main.go cat
|
||||||
|
|
||||||
|
# Run a shell.Try sending `ls` and `cat main.go`.
|
||||||
|
$ go run main.go sh
|
||||||
|
|
|
@ -0,0 +1,92 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<title>Command Example</title>
|
||||||
|
<script src="//ajax.googleapis.com/ajax/libs/jquery/2.0.3/jquery.min.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
$(function() {
|
||||||
|
|
||||||
|
var conn;
|
||||||
|
var msg = $("#msg");
|
||||||
|
var log = $("#log");
|
||||||
|
|
||||||
|
function appendLog(msg) {
|
||||||
|
var d = log[0]
|
||||||
|
var doScroll = d.scrollTop == d.scrollHeight - d.clientHeight;
|
||||||
|
msg.appendTo(log)
|
||||||
|
if (doScroll) {
|
||||||
|
d.scrollTop = d.scrollHeight - d.clientHeight;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$("#form").submit(function() {
|
||||||
|
if (!conn) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!msg.val()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
conn.send(msg.val());
|
||||||
|
msg.val("");
|
||||||
|
return false
|
||||||
|
});
|
||||||
|
|
||||||
|
if (window["WebSocket"]) {
|
||||||
|
conn = new WebSocket("ws://{{$}}/ws");
|
||||||
|
conn.onclose = function(evt) {
|
||||||
|
appendLog($("<div><b>Connection closed.</b></div>"))
|
||||||
|
}
|
||||||
|
conn.onmessage = function(evt) {
|
||||||
|
appendLog($("<div/>").text(evt.data))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
appendLog($("<div><b>Your browser does not support WebSockets.</b></div>"))
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
<style type="text/css">
|
||||||
|
html {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
overflow: hidden;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background: gray;
|
||||||
|
}
|
||||||
|
|
||||||
|
#log {
|
||||||
|
background: white;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0.5em 0.5em 0.5em 0.5em;
|
||||||
|
position: absolute;
|
||||||
|
top: 0.5em;
|
||||||
|
left: 0.5em;
|
||||||
|
right: 0.5em;
|
||||||
|
bottom: 3em;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
#form {
|
||||||
|
padding: 0 0.5em 0 0.5em;
|
||||||
|
margin: 0;
|
||||||
|
position: absolute;
|
||||||
|
bottom: 1em;
|
||||||
|
left: 0px;
|
||||||
|
width: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="log"></div>
|
||||||
|
<form id="form">
|
||||||
|
<input type="submit" value="Send" />
|
||||||
|
<input type="text" id="msg" size="64"/>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,156 @@
|
||||||
|
// Copyright 2015 The Gorilla WebSocket Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bufio"
|
||||||
|
"flag"
|
||||||
|
"io"
|
||||||
|
"log"
|
||||||
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"os/exec"
|
||||||
|
"text/template"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gorilla/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
addr = flag.String("addr", "127.0.0.1:8080", "http service address")
|
||||||
|
homeTempl = template.Must(template.ParseFiles("home.html"))
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Time allowed to write a message to the peer.
|
||||||
|
writeWait = 10 * time.Second
|
||||||
|
|
||||||
|
// Maximum message size allowed from peer.
|
||||||
|
maxMessageSize = 8192
|
||||||
|
)
|
||||||
|
|
||||||
|
// connection is an middleman between the websocket connection and the command.
|
||||||
|
type connection struct {
|
||||||
|
ws *websocket.Conn
|
||||||
|
stdout io.ReadCloser
|
||||||
|
stdin io.WriteCloser
|
||||||
|
cmd *exec.Cmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *connection) pumpStdin() {
|
||||||
|
defer c.ws.Close()
|
||||||
|
c.ws.SetReadLimit(maxMessageSize)
|
||||||
|
for {
|
||||||
|
_, message, err := c.ws.ReadMessage()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
message = append(message, '\n')
|
||||||
|
if _, err := c.stdin.Write(message); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
c.stdin.Close()
|
||||||
|
log.Println("exit stdin pump")
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *connection) pumpStdout() {
|
||||||
|
defer c.ws.Close()
|
||||||
|
s := bufio.NewScanner(c.stdout)
|
||||||
|
for s.Scan() {
|
||||||
|
c.ws.SetWriteDeadline(time.Now().Add(writeWait))
|
||||||
|
if err := c.ws.WriteMessage(websocket.TextMessage, s.Bytes()); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if s.Err() != nil {
|
||||||
|
log.Println("scan:", s.Err())
|
||||||
|
}
|
||||||
|
c.stdout.Close()
|
||||||
|
log.Println("exit stdout pump")
|
||||||
|
}
|
||||||
|
|
||||||
|
func internalError(ws *websocket.Conn, fmt string, err error) {
|
||||||
|
log.Println(fmt, err)
|
||||||
|
ws.WriteMessage(websocket.TextMessage, []byte("Internal server error."))
|
||||||
|
}
|
||||||
|
|
||||||
|
var upgrader = websocket.Upgrader{}
|
||||||
|
|
||||||
|
func serveWs(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.Method != "GET" {
|
||||||
|
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ws, err := upgrader.Upgrade(w, r, nil)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c := &connection{
|
||||||
|
cmd: exec.Command(flag.Args()[0], flag.Args()[1:]...),
|
||||||
|
ws: ws,
|
||||||
|
}
|
||||||
|
|
||||||
|
c.stdout, err = c.cmd.StdoutPipe()
|
||||||
|
if err != nil {
|
||||||
|
internalError(ws, "stdout: %v", err)
|
||||||
|
ws.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
c.stdin, err = c.cmd.StdinPipe()
|
||||||
|
if err != nil {
|
||||||
|
internalError(ws, "stdin: %v", err)
|
||||||
|
c.stdout.Close()
|
||||||
|
if closer, ok := c.cmd.Stdout.(io.Closer); ok {
|
||||||
|
closer.Close()
|
||||||
|
}
|
||||||
|
ws.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.cmd.Start(); err != nil {
|
||||||
|
internalError(ws, "start: %v", err)
|
||||||
|
c.stdout.Close()
|
||||||
|
c.stdin.Close()
|
||||||
|
ws.Close()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
go c.pumpStdout()
|
||||||
|
c.pumpStdin()
|
||||||
|
|
||||||
|
c.cmd.Process.Signal(os.Interrupt)
|
||||||
|
if err := c.cmd.Wait(); err != nil {
|
||||||
|
log.Println("wait:", err)
|
||||||
|
}
|
||||||
|
log.Println("exit serveWs")
|
||||||
|
}
|
||||||
|
|
||||||
|
func serveHome(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if r.URL.Path != "/" {
|
||||||
|
http.Error(w, "Not found", 404)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if r.Method != "GET" {
|
||||||
|
http.Error(w, "Method not allowed", 405)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
|
homeTempl.Execute(w, r.Host)
|
||||||
|
}
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
flag.Parse()
|
||||||
|
if len(flag.Args()) < 1 {
|
||||||
|
log.Fatal("must specify at least one argument")
|
||||||
|
}
|
||||||
|
http.HandleFunc("/", serveHome)
|
||||||
|
http.HandleFunc("/ws", serveWs)
|
||||||
|
log.Fatal(http.ListenAndServe(*addr, nil))
|
||||||
|
}
|
Loading…
Reference in New Issue