Browse Source

Add command example

Gary Burd 10 năm trước cách đây
mục cha
commit
f9219095ab
4 tập tin đã thay đổi với 268 bổ sung0 xóa
  1. 1 0
      README.md
  2. 19 0
      examples/command/README.md
  3. 92 0
      examples/command/home.html
  4. 156 0
      examples/command/main.go

+ 1 - 0
README.md

@@ -7,6 +7,7 @@ Gorilla WebSocket is a [Go](http://golang.org/) implementation of the
 
 * [API Reference](http://godoc.org/github.com/gorilla/websocket)
 * [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)
 * [File watch example](https://github.com/gorilla/websocket/tree/master/examples/filewatch)
 

+ 19 - 0
examples/command/README.md

@@ -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
+

+ 92 - 0
examples/command/home.html

@@ -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>

+ 156 - 0
examples/command/main.go

@@ -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))
+}