Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update websocket example #80

Merged
merged 1 commit into from
Dec 11, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 5 additions & 31 deletions examples/websocket/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,14 @@ Any websocket server will suffice; however, for the purpose of demonstration, we

### Containerize
```shell
➜ docker build -t nicksardo/websocketexample .
Sending build context to Docker daemon 6.134 MB
Step 1 : FROM alpine:3.5
---> 4a415e366388
Step 2 : COPY wsserver /wsserver
---> 8002887d752d
Removing intermediate container 7772a3e76155
Step 3 : CMD /wsserver
---> Running in 27c8ff226267
---> eecd0574e5d1
Removing intermediate container 27c8ff226267
Successfully built eecd0574e5d1

➜ docker push nicksardo/websocketexample:latest
➜ docker build -t [YOUR_IMAGE] .
...
➜ docker push [YOUR_IMAGE]
...
```

### Deploy
Either update the image in the `Deployment` to your newly created image or continue using `nicksardo/websocketexample.`
Either update the image in the `Deployment` to your newly created image.
```shell
➜ vi deployment.yaml
# Change image to your own
Expand All @@ -49,22 +38,7 @@ NAME HOSTS ADDRESS PORTS AGE
ws-example-ing * xxx.xxx.xxx.xxx 80 3m
```

Wait for the loadbalancer to be created and functioning. When you receive a successful response, you can proceed.
```
➜ curl http://xxx.xxx.xxx.xxx
Websocket example. Connect to /ws%
```

The binary we deployed does not have any html/javascript to demonstrate the websocket, so we'll use websocket.org's client.

Visit http://www.websocket.org/echo.html. It's important to use `HTTP` instead of `HTTPS` since we assembled an `HTTP` load balancer. Browsers may prevent `HTTP` websocket connections as a security feature.
Set the `Location` to
```
ws://xxx.xxx.xxx.xxx/ws
```
Click 'Connect' and you should see messages received from server:
![Log screenshot](http://i.imgur.com/hlwwa0G.png)

Wait for the loadbalancer to be created and functioning. Visit http://xxx.xxx.xxx.xxx and click 'Connect'. You should receive messages from server with timestamps.

### Change backend timeout

Expand Down
2 changes: 1 addition & 1 deletion examples/websocket/deployment.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ spec:
spec:
containers:
- name: websocketexample
image: nicksardo/websocketexample
image: [YOUR_IMAGE]
imagePullPolicy: Always
ports:
- name: http
Expand Down
155 changes: 133 additions & 22 deletions examples/websocket/server.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,24 @@
/*
Copyright 2017 The Kubernetes Authors.

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package main

import (
"fmt"
"html/template"
"log"
"net/http"
"os"
Expand All @@ -19,6 +36,16 @@ var upgrader = websocket.Upgrader{

func init() {
podName = os.Getenv("podname")
if podName == "" {
podName = "UNKNOWN"
}
}

func main() {
log.Println("Starting on :8080")
http.HandleFunc("/ws", ws)
http.HandleFunc("/", root)
log.Fatal(http.ListenAndServe(":8080", nil))
}

func ws(w http.ResponseWriter, r *http.Request) {
Expand All @@ -31,51 +58,135 @@ func ws(w http.ResponseWriter, r *http.Request) {
defer c.Close()

s := fmt.Sprintf("Connected to %v", podName)
c.WriteMessage(websocket.TextMessage, []byte(s))
if err := c.WriteMessage(websocket.TextMessage, []byte(s)); err != nil {
log.Println("err:", err)
}
handleWSConn(c)
}

func handleWSConn(c *websocket.Conn) {
stop := make(chan struct{})
in := make(chan string)
ticker := time.NewTicker(5 * time.Second)

go func() {
for {
time.Sleep(5 * time.Second)

select {
case <-stop:
return
default:
_, message, err := c.ReadMessage()
if err != nil {
log.Println("Error while reading:", err)
close(stop)
break
}

s := fmt.Sprintf("%s reports time: %v", podName, time.Now().String())
c.WriteMessage(websocket.TextMessage, []byte(s))
in <- string(message)
}
log.Println("Stop reading of connection from", c.RemoteAddr())
}()

for {
mt, message, err := c.ReadMessage()
if err != nil {
log.Println("Error while reading:", err)
var msg string
select {
case t := <-ticker.C:
msg = fmt.Sprintf("%s reports time: %v", podName, t.String())
case m := <-in:
msg = m
case <-stop:
break
}
if err = c.WriteMessage(mt, message); err != nil {

if err := c.WriteMessage(websocket.TextMessage, []byte(msg)); err != nil {
log.Println("Error while writing:", err)
break
}
}
close(stop)
log.Println("Stop handling of connection from", c.RemoteAddr())
}

func root(w http.ResponseWriter, r *http.Request) {
if r.URL.Path != "/" {
http.NotFound(w, r)
return
}
w.Write([]byte(`Websocket example. Connect to /ws`))
s := struct {
URL string
PodName string
}{
URL: "ws://" + r.Host + "/ws",
PodName: podName,
}
testPage.Execute(w, s)
}

func main() {
log.Println("Starting")
http.HandleFunc("/ws", ws)
http.HandleFunc("/", root)
log.Fatal(http.ListenAndServe(":8080", nil))
}
var testPage = template.Must(template.New("").Parse(`
<!DOCTYPE html><head><title>Websocket Server</title>
<script>
function htmlize(m) {
var line = document.createElement("div");
line.innerHTML = m;
result.appendChild(line)
};

window.addEventListener("load", function(evt) {
var socket;
var txt = document.getElementById("txt");
var result = document.getElementById("result");

document.getElementById("connect").onclick = function(evt) {
if (socket) {
return false;
}

socket = new WebSocket("{{.URL}}");

socket.onopen = function(evt) {
htmlize("<p>Connected<p>");
}
socket.onclose = function(evt) {
htmlize("<p>Disconnected<p>");
socket = null;
}
socket.onmessage = function(e) {
htmlize("Received: " + e.data);
}
socket.onerror = function(e) {
print("error: " + e.data);
}

return false;
};

document.getElementById("send").onclick = function(e) {
if (!socket) {
return false;
}

socket.send(txt.value);
htmlize("Sent: " + txt.value);

return false;
};

document.getElementById("disconnect").onclick = function(e) {
if (!socket) {
return false;
}

socket.close();

return false;
};

});
</script>
</head>
<body>
<p>Page served by pod '{{.PodName}}'</p>
<form>
<button id="connect">Connect</button>
<button id="disconnect">Disconnect</button>
<input id="txt" type="text" value="">
<button id="send">Send</button>
</form>

<div id="result"></div>
</body></html>
`))