1
0
mirror of https://github.com/kataras/iris.git synced 2026-01-21 02:45:59 +00:00

move sessions and websocket examples, gofmt, fix misspells and experimental optimizations 🍐

Former-commit-id: cae4f94bbd404d26ab13dade02b52f81feaddf24
This commit is contained in:
hiveminded
2017-07-22 22:57:20 +03:00
parent 90b8c1af44
commit 9a0b18acbf
36 changed files with 155 additions and 97 deletions

View File

@@ -179,17 +179,32 @@ The `httptest` package is your way for end-to-end HTTP testing, it uses the http
### Caching
iris cache library lives on its own package: [https://github.com/kataras/iris/tree/master/cache](https://github.com/kataras/iris/tree/master/cache) **it contains examples**
iris cache library lives on its own [package](https://github.com/kataras/iris/tree/master/cache).
- [Simple](cache/simple/main.go)
> You're free to use your own favourite caching package if you'd like so.
### Sessions
iris session manager lives on its own [package](https://github.com/kataras/iris/tree/master/sessions).
iris session manager lives on its own package: [https://github.com/kataras/iris/tree/master/sessions](https://github.com/kataras/iris/tree/master/sessions) **it contains examples**
- [Overview](sessions/overview/main.go)
- [Standalone](sessions/standalone/main.go)
- [Secure Cookie](sessions/securecookie/main.go)
- [Flash Messages](sessions/flash-messages/main.go)
- [Database](sessions/database/main.go)
> You're free to use your own favourite sessions package if you'd like so.
### Websockets
iris websocket library lives on its own package: [https://github.com/kataras/iris/tree/master/websocket](https://github.com/kataras/iris/tree/master/websocket) **it contains examples**
iris websocket library lives on its own [package](https://github.com/kataras/iris/tree/master/websocket).
- [Chat](websocket/chat/main.go)
- [Native Messages](websocket/native-messages/main.go)
- [Connection List](websocket/connectionlist/main.go)
- [TLS Enabled](websocket/secure/main.go)
- [Custom Raw Go Client](websocket/custom-go-client/main.go)
> You're free to use your own favourite websockets package if you'd like so.

76
_examples/cache/simple/main.go vendored Normal file
View File

@@ -0,0 +1,76 @@
package main
import (
"time"
"github.com/kataras/iris"
"github.com/kataras/iris/context"
"github.com/kataras/iris/cache"
)
var markdownContents = []byte(`## Hello Markdown
This is a sample of Markdown contents
Features
--------
All features of Sundown are supported, including:
* **Compatibility**. The Markdown v1.0.3 test suite passes with
the --tidy option. Without --tidy, the differences are
mostly in whitespace and entity escaping, where blackfriday is
more consistent and cleaner.
* **Common extensions**, including table support, fenced code
blocks, autolinks, strikethroughs, non-strict emphasis, etc.
* **Safety**. Blackfriday is paranoid when parsing, making it safe
to feed untrusted user input without fear of bad things
happening. The test suite stress tests this and there are no
known inputs that make it crash. If you find one, please let me
know and send me the input that does it.
NOTE: "safety" in this context means *runtime safety only*. In order to
protect yourself against JavaScript injection in untrusted content, see
[this example](https://github.com/russross/blackfriday#sanitize-untrusted-content).
* **Fast processing**. It is fast enough to render on-demand in
most web applications without having to cache the output.
* **Routine safety**. You can run multiple parsers in different
goroutines without ill effect. There is no dependence on global
shared state.
* **Minimal dependencies**. Blackfriday only depends on standard
library packages in Go. The source code is pretty
self-contained, so it is easy to add to any project, including
Google App Engine projects.
* **Standards compliant**. Output successfully validates using the
W3C validation tool for HTML 4.01 and XHTML 1.0 Transitional.
[this is a link](https://github.com/kataras/iris) `)
// Cache should not be used on handlers that contain dynamic data.
// Cache is a good and a must-feature on static content, i.e "about page" or for a whole blog site.
func main() {
app := iris.New()
app.Get("/", cache.Handler(10*time.Second), writeMarkdown)
// saves its content on the first request and serves it instead of re-calculating the content.
// After 10 seconds it will be cleared and resetted.
app.Run(iris.Addr(":8080"))
}
func writeMarkdown(ctx context.Context) {
// tap multiple times the browser's refresh button and you will
// see this println only once every 10 seconds.
println("Handler executed. Content refreshed.")
ctx.Markdown(markdownContents)
}

View File

@@ -42,7 +42,6 @@ func main() {
Age: 25,
}
ctx.StatusCode(iris.StatusOK)
// Manually setting a content type: ctx.ContentType("application/javascript")
ctx.JSON(peter)
})
@@ -83,5 +82,13 @@ func main() {
// http://localhost:8080/jsonp
// http://localhost:8080/xml
// http://localhost:8080/markdown
app.Run(iris.Addr(":8080"))
//
// `iris.WithOptimizations` is an optional configurator,
// if passed to the `Run` then it will ensure that the application
// response to the client as fast as possible.
//
//
// `iris.WithoutServerError` is an optional configurator,
// if passed to the `Run` then it will not print its passed error as an actual server error.
app.Run(iris.Addr(":8080"), iris.WithoutServerError(iris.ErrServerClosed), iris.WithOptimizations)
}

View File

@@ -0,0 +1,69 @@
package main
import (
"github.com/kataras/iris"
"github.com/kataras/iris/context"
"github.com/kataras/iris/sessions"
"github.com/kataras/iris/sessions/sessiondb/redis"
"github.com/kataras/iris/sessions/sessiondb/redis/service"
)
func main() {
// replace with your running redis' server settings:
db := redis.New(service.Config{Network: service.DefaultRedisNetwork,
Addr: service.DefaultRedisAddr,
Password: "",
Database: "",
MaxIdle: 0,
MaxActive: 0,
IdleTimeout: service.DefaultRedisIdleTimeout,
Prefix: "",
MaxAgeSeconds: service.DefaultRedisMaxAgeSeconds}) // optionally configure the bridge between your redis server
sess := sessions.New(sessions.Config{Cookie: "sessionscookieid"})
//
// IMPORTANT:
//
sess.UseDatabase(db)
// the rest of the code stays the same.
app := iris.New()
app.Get("/", func(ctx context.Context) {
ctx.Writef("You should navigate to the /set, /get, /delete, /clear,/destroy instead")
})
app.Get("/set", func(ctx context.Context) {
//set session values
sess.Start(ctx).Set("name", "iris")
//test if setted here
ctx.Writef("All ok session setted to: %s", sess.Start(ctx).GetString("name"))
})
app.Get("/get", func(ctx context.Context) {
// get a specific key, as string, if no found returns just an empty string
name := sess.Start(ctx).GetString("name")
ctx.Writef("The name on the /set was: %s", name)
})
app.Get("/delete", func(ctx context.Context) {
// delete a specific key
sess.Start(ctx).Delete("name")
})
app.Get("/clear", func(ctx context.Context) {
// removes all entries
sess.Start(ctx).Clear()
})
app.Get("/destroy", func(ctx context.Context) {
//destroy, removes the entire session data and cookie
sess.Destroy(ctx)
})
app.Run(iris.Addr(":8080"))
}

View File

@@ -0,0 +1,43 @@
package main
import (
"github.com/kataras/iris"
"github.com/kataras/iris/context"
"github.com/kataras/iris/sessions"
)
func main() {
app := iris.New()
sess := sessions.New(sessions.Config{Cookie: "myappsessionid"})
app.Get("/set", func(ctx context.Context) {
s := sess.Start(ctx)
s.SetFlash("name", "iris")
ctx.Writef("Message setted, is available for the next request")
})
app.Get("/get", func(ctx context.Context) {
s := sess.Start(ctx)
name := s.GetFlashString("name")
if name == "" {
ctx.Writef("Empty name!!")
return
}
ctx.Writef("Hello %s", name)
})
app.Get("/test", func(ctx context.Context) {
s := sess.Start(ctx)
name := s.GetFlashString("name")
if name == "" {
ctx.Writef("Empty name!!")
return
}
ctx.Writef("Ok you are coming from /set ,the value of the name is %s", name)
ctx.Writef(", and again from the same context: %s", name)
})
app.Run(iris.Addr(":8080"))
}

View File

@@ -0,0 +1,52 @@
package main
import (
"github.com/kataras/iris"
"github.com/kataras/iris/context"
"github.com/kataras/iris/sessions"
)
var (
cookieNameForSessionID = "mycookiesessionnameid"
sess = sessions.New(sessions.Config{Cookie: cookieNameForSessionID})
)
func secret(ctx context.Context) {
// Check if user is authenticated
if auth, _ := sess.Start(ctx).GetBoolean("authenticated"); !auth {
ctx.StatusCode(iris.StatusForbidden)
return
}
// Print secret message
ctx.WriteString("The cake is a lie!")
}
func login(ctx context.Context) {
session := sess.Start(ctx)
// Authentication goes here
// ...
// Set user as authenticated
session.Set("authenticated", true)
}
func logout(ctx context.Context) {
session := sess.Start(ctx)
// Revoke users authentication
session.Set("authenticated", false)
}
func main() {
app := iris.New()
app.Get("/secret", secret)
app.Get("/login", login)
app.Get("/logout", logout)
app.Run(iris.Addr(":8080"))
}

View File

@@ -0,0 +1,80 @@
package main
// developers can use any library to add a custom cookie encoder/decoder.
// At this example we use the gorilla's securecookie package:
// $ go get github.com/gorilla/securecookie
// $ go run main.go
import (
"github.com/kataras/iris"
"github.com/kataras/iris/context"
"github.com/kataras/iris/sessions"
"github.com/gorilla/securecookie"
)
func newApp() *iris.Application {
app := iris.New()
cookieName := "mycustomsessionid"
// AES only supports key sizes of 16, 24 or 32 bytes.
// You either need to provide exactly that amount or you derive the key from what you type in.
hashKey := []byte("the-big-and-secret-fash-key-here")
blockKey := []byte("lot-secret-of-characters-big-too")
secureCookie := securecookie.New(hashKey, blockKey)
mySessions := sessions.New(sessions.Config{
Cookie: cookieName,
Encode: secureCookie.Encode,
Decode: secureCookie.Decode,
})
app.Get("/", func(ctx context.Context) {
ctx.Writef("You should navigate to the /set, /get, /delete, /clear,/destroy instead")
})
app.Get("/set", func(ctx context.Context) {
//set session values
s := mySessions.Start(ctx)
s.Set("name", "iris")
//test if setted here
ctx.Writef("All ok session setted to: %s", s.GetString("name"))
})
app.Get("/get", func(ctx context.Context) {
// get a specific key, as string, if no found returns just an empty string
s := mySessions.Start(ctx)
name := s.GetString("name")
ctx.Writef("The name on the /set was: %s", name)
})
app.Get("/delete", func(ctx context.Context) {
// delete a specific key
s := mySessions.Start(ctx)
s.Delete("name")
})
app.Get("/clear", func(ctx context.Context) {
// removes all entries
mySessions.Start(ctx).Clear()
})
app.Get("/destroy", func(ctx context.Context) {
//destroy, removes the entire session data and cookie
mySessions.Destroy(ctx)
}) // Note about destroy:
//
// You can destroy a session outside of a handler too, using the:
// mySessions.DestroyByID
// mySessions.DestroyAll
return app
}
func main() {
app := newApp()
app.Run(iris.Addr(":8080"))
}

View File

@@ -0,0 +1,27 @@
package main
import (
"testing"
"github.com/kataras/iris"
"github.com/kataras/iris/httptest"
)
func TestSessionsEncodeDecode(t *testing.T) {
app := newApp()
e := httptest.New(t, app, httptest.URL("http://example.com"))
es := e.GET("/set").Expect()
es.Status(iris.StatusOK)
es.Cookies().NotEmpty()
es.Body().Equal("All ok session setted to: iris")
e.GET("/get").Expect().Status(iris.StatusOK).Body().Equal("The name on the /set was: iris")
// delete and re-get
e.GET("/delete").Expect().Status(iris.StatusOK)
e.GET("/get").Expect().Status(iris.StatusOK).Body().Equal("The name on the /set was: ")
// set, clear and re-get
e.GET("/set").Expect().Body().Equal("All ok session setted to: iris")
e.GET("/clear").Expect().Status(iris.StatusOK)
e.GET("/get").Expect().Status(iris.StatusOK).Body().Equal("The name on the /set was: ")
}

View File

@@ -0,0 +1,120 @@
package main
import (
"time"
"github.com/kataras/iris"
"github.com/kataras/iris/context"
"github.com/kataras/iris/sessions"
)
type businessModel struct {
Name string
}
func main() {
app := iris.New()
sess := sessions.New(sessions.Config{
// Cookie string, the session's client cookie name, for example: "mysessionid"
//
// Defaults to "irissessionid"
Cookie: "mysessionid",
// it's time.Duration, from the time cookie is created, how long it can be alive?
// 0 means no expire.
// -1 means expire when browser closes
// or set a value, like 2 hours:
Expires: time.Hour * 2,
// if you want to invalid cookies on different subdomains
// of the same host, then enable it
DisableSubdomainPersistence: false,
// want to be crazy safe? Take a look at the "securecookie" example folder.
})
app.Get("/", func(ctx context.Context) {
ctx.Writef("You should navigate to the /set, /get, /delete, /clear,/destroy instead")
})
app.Get("/set", func(ctx context.Context) {
//set session values.
s := sess.Start(ctx)
s.Set("name", "iris")
//test if setted here
ctx.Writef("All ok session setted to: %s", s.GetString("name"))
// Set will set the value as-it-is,
// if it's a slice or map
// you will be able to change it on .Get directly!
// Keep note that I don't recommend saving big data neither slices or maps on a session
// but if you really need it then use the `SetImmutable` instead of `Set`.
// Use `SetImmutable` consistently, it's slower.
// Read more about muttable and immutable go types: https://stackoverflow.com/a/8021081
})
app.Get("/get", func(ctx context.Context) {
// get a specific value, as string, if no found returns just an empty string
name := sess.Start(ctx).GetString("name")
ctx.Writef("The name on the /set was: %s", name)
})
app.Get("/delete", func(ctx context.Context) {
// delete a specific key
sess.Start(ctx).Delete("name")
})
app.Get("/clear", func(ctx context.Context) {
// removes all entries
sess.Start(ctx).Clear()
})
app.Get("/destroy", func(ctx context.Context) {
//destroy, removes the entire session data and cookie
sess.Destroy(ctx)
})
// Note about Destroy:
//
// You can destroy a session outside of a handler too, using the:
// mySessions.DestroyByID
// mySessions.DestroyAll
// remember: slices and maps are muttable by-design
// The `SetImmutable` makes sure that they will be stored and received
// as immutable, so you can't change them directly by mistake.
//
// Use `SetImmutable` consistently, it's slower than `Set`.
// Read more about muttable and immutable go types: https://stackoverflow.com/a/8021081
app.Get("/set_immutable", func(ctx context.Context) {
business := []businessModel{{Name: "Edward"}, {Name: "value 2"}}
s := sess.Start(ctx)
s.SetImmutable("businessEdit", business)
businessGet := s.Get("businessEdit").([]businessModel)
// try to change it, if we used `Set` instead of `SetImmutable` this
// change will affect the underline array of the session's value "businessEdit", but now it will not.
businessGet[0].Name = "Gabriel"
})
app.Get("/get_immutable", func(ctx context.Context) {
valSlice := sess.Start(ctx).Get("businessEdit")
if valSlice == nil {
ctx.HTML("please navigate to the <a href='/set_immutable'>/set_immutable</a> first")
return
}
firstModel := valSlice.([]businessModel)[0]
// businessGet[0].Name is equal to Edward initially
if firstModel.Name != "Edward" {
panic("Report this as a bug, immutable data cannot be changed from the caller without re-SetImmutable")
}
ctx.Writef("[]businessModel[0].Name remains: %s", firstModel.Name)
// the name should remains "Edward"
})
app.Run(iris.Addr(":8080"))
}

View File

@@ -0,0 +1,56 @@
package main
import (
"fmt"
"github.com/kataras/iris"
"github.com/kataras/iris/context"
"github.com/kataras/iris/websocket"
)
func main() {
app := iris.New()
app.Get("/", func(ctx context.Context) {
ctx.ServeFile("websockets.html", false) // second parameter: enable gzip?
})
setupWebsocket(app)
// x2
// http://localhost:8080
// http://localhost:8080
// write something, press submit, see the result.
app.Run(iris.Addr(":8080"))
}
func setupWebsocket(app *iris.Application) {
// create our echo websocket server
ws := websocket.New(websocket.Config{
ReadBufferSize: 1024,
WriteBufferSize: 1024,
})
ws.OnConnection(handleConnection)
// register the server on an endpoint.
// see the inline javascript code in the websockets.html, this endpoint is used to connect to the server.
app.Get("/echo", ws.Handler())
// serve the javascript built'n client-side library,
// see weboskcets.html script tags, this path is used.
app.Any("/iris-ws.js", func(ctx context.Context) {
ctx.Write(websocket.ClientSource)
})
}
func handleConnection(c websocket.Connection) {
// Read events from browser
c.On("chat", func(msg string) {
// Print the message to the console, c.Context() is the iris's http context.
fmt.Printf("%s sent: %s\n", c.Context().RemoteAddr(), msg)
// Write message back to the client message owner:
// c.Emit("chat", msg)
c.To(websocket.Broadcast).Emit("chat", msg)
})
}

View File

@@ -0,0 +1,33 @@
<input id="input" type="text" />
<button onclick="send()">Send</button>
<pre id="output"></pre>
<script src="/iris-ws.js"></script>
<script>
var input = document.getElementById("input");
var output = document.getElementById("output");
// Ws comes from the auto-served '/iris-ws.js'
var socket = new Ws("ws://localhost:8080/echo");
socket.OnConnect(function () {
output.innerHTML += "Status: Connected\n";
});
socket.OnDisconnect(function () {
output.innerHTML += "Status: Disconnected\n";
});
// read events from the server
socket.On("chat", function (msg) {
addMessage(msg)
});
function send() {
addMessage("Me: "+input.value) // write ourselves
socket.Emit("chat", input.value);// send chat event data to the websocket server
input.value = ""; // clear the input
}
function addMessage(msg) {
output.innerHTML += msg + "\n";
}
</script>

View File

@@ -0,0 +1,98 @@
package main
import (
"fmt"
"sync"
"time"
"github.com/kataras/iris"
"github.com/kataras/iris/context"
"github.com/kataras/iris/view"
"github.com/kataras/iris/websocket"
)
type clientPage struct {
Title string
Host string
}
func main() {
app := iris.New()
app.RegisterView(view.HTML("./templates", ".html")) // select the html engine to serve templates
ws := websocket.New(websocket.Config{})
// register the server on an endpoint.
// see the inline javascript code i the websockets.html, this endpoint is used to connect to the server.
app.Get("/my_endpoint", ws.Handler())
// serve the javascript built'n client-side library,
// see weboskcets.html script tags, this path is used.
app.Any("/iris-ws.js", func(ctx context.Context) {
ctx.Write(websocket.ClientSource)
})
app.StaticWeb("/js", "./static/js") // serve our custom javascript code
app.Get("/", func(ctx context.Context) {
ctx.ViewData("", clientPage{"Client Page", "localhost:8080"})
ctx.View("client.html")
})
Conn := make(map[websocket.Connection]bool)
var myChatRoom = "room1"
var mutex = new(sync.Mutex)
ws.OnConnection(func(c websocket.Connection) {
c.Join(myChatRoom)
mutex.Lock()
Conn[c] = true
mutex.Unlock()
c.On("chat", func(message string) {
if message == "leave" {
c.Leave(myChatRoom)
c.To(myChatRoom).Emit("chat", "Client with ID: "+c.ID()+" left from the room and cannot send or receive message to/from this room.")
c.Emit("chat", "You have left from the room: "+myChatRoom+" you cannot send or receive any messages from others inside that room.")
return
}
})
c.OnDisconnect(func() {
mutex.Lock()
delete(Conn, c)
mutex.Unlock()
fmt.Printf("\nConnection with ID: %s has been disconnected!\n", c.ID())
})
})
var delay = 1 * time.Second
go func() {
i := 0
for {
mutex.Lock()
broadcast(Conn, fmt.Sprintf("aaaa %d\n", i))
mutex.Unlock()
time.Sleep(delay)
i++
}
}()
go func() {
i := 0
for {
mutex.Lock()
broadcast(Conn, fmt.Sprintf("aaaa2 %d\n", i))
mutex.Unlock()
time.Sleep(delay)
i++
}
}()
app.Run(iris.Addr(":8080"))
}
func broadcast(Conn map[websocket.Connection]bool, message string) {
for k := range Conn {
k.To("room1").Emit("chat", message)
}
}

View File

@@ -0,0 +1,38 @@
var messageTxt;
var messages;
$(function () {
messageTxt = $("#messageTxt");
messages = $("#messages");
w = new Ws("ws://" + HOST + "/my_endpoint");
w.OnConnect(function () {
console.log("Websocket connection established");
});
w.OnDisconnect(function () {
appendMessage($("<div><center><h3>Disconnected</h3></center></div>"));
});
w.On("chat", function (message) {
appendMessage($("<div>" + message + "</div>"));
});
$("#sendBtn").click(function () {
w.Emit("chat", messageTxt.val().toString());
messageTxt.val("");
});
})
function appendMessage(messageDiv) {
var theDiv = messages[0];
var doScroll = theDiv.scrollTop == theDiv.scrollHeight - theDiv.clientHeight;
messageDiv.appendTo(messages);
if (doScroll) {
theDiv.scrollTop = theDiv.scrollHeight - theDiv.clientHeight;
}
}

View File

@@ -0,0 +1,24 @@
<html>
<head>
<title>{{ .Title}}</title>
</head>
<body>
<div id="messages"
style="border-width: 1px; border-style: solid; height: 400px; width: 375px;">
</div>
<input type="text" id="messageTxt" />
<button type="button" id="sendBtn">Send</button>
<script type="text/javascript">
var HOST = {{.Host}}
</script>
<script src="js/vendor/jquery-2.2.3.min.js" type="text/javascript"></script>
<!-- This is auto-serving by the iris, you don't need to have this file in your disk-->
<script src="/iris-ws.js" type="text/javascript"></script>
<!-- -->
<script src="js/chat.js" type="text/javascript"></script>
</body>
</html>

View File

@@ -0,0 +1,177 @@
package main
// Run first `go run main.go server`
// and `go run main.go client` as many times as you want.
// Originally written by: github.com/antlaw to describe an old issue.
import (
"fmt"
"os"
"strings"
"time"
"github.com/kataras/iris"
"github.com/kataras/iris/websocket"
xwebsocket "golang.org/x/net/websocket"
)
// WS is the current websocket connection
var WS *xwebsocket.Conn
func main() {
if len(os.Args) == 2 && strings.ToLower(os.Args[1]) == "server" {
ServerLoop()
} else if len(os.Args) == 2 && strings.ToLower(os.Args[1]) == "client" {
ClientLoop()
} else {
fmt.Println("wsserver [server|client]")
}
}
/////////////////////////////////////////////////////////////////////////
// client side
func sendUntilErr(sendInterval int) {
i := 1
for {
time.Sleep(time.Duration(sendInterval) * time.Second)
err := SendMessage("2", "all", "objectupdate", "2.UsrSchedule_v1_1")
if err != nil {
fmt.Println("failed to send join message", err.Error())
return
}
fmt.Println("objectupdate", i)
i++
}
}
func recvUntilErr() {
var msg = make([]byte, 2048)
var n int
var err error
i := 1
for {
if n, err = WS.Read(msg); err != nil {
fmt.Println(err.Error())
return
}
fmt.Printf("%v Received: %s.%v\n", time.Now(), string(msg[:n]), i)
i++
}
}
//ConnectWebSocket connect a websocket to host
func ConnectWebSocket() error {
var origin = "http://localhost/"
var url = "ws://localhost:8080/socket"
var err error
WS, err = xwebsocket.Dial(url, "", origin)
return err
}
// CloseWebSocket closes the current websocket connection
func CloseWebSocket() error {
if WS != nil {
return WS.Close()
}
return nil
}
// SendMessage broadcast a message to server
func SendMessage(serverID, to, method, message string) error {
buffer := []byte(message)
return SendtBytes(serverID, to, method, buffer)
}
// SendtBytes broadcast a message to server
func SendtBytes(serverID, to, method string, message []byte) error {
// look https://github.com/kataras/iris/tree/master/adaptors/websocket/message.go , client.go and client.js
// to understand the buffer line:
buffer := []byte(fmt.Sprintf("iris-websocket-message:%v;0;%v;%v;", method, serverID, to))
buffer = append(buffer, message...)
_, err := WS.Write(buffer)
if err != nil {
fmt.Println(err)
return err
}
return nil
}
// ClientLoop connects to websocket server, the keep send and recv dataS
func ClientLoop() {
for {
time.Sleep(time.Second)
err := ConnectWebSocket()
if err != nil {
fmt.Println("failed to connect websocket", err.Error())
continue
}
// time.Sleep(time.Second)
err = SendMessage("2", "all", "join", "dummy2")
go sendUntilErr(1)
recvUntilErr()
err = CloseWebSocket()
if err != nil {
fmt.Println("failed to close websocket", err.Error())
}
}
}
/////////////////////////////////////////////////////////////////////////
// server side
// OnConnect handles incoming websocket connection
func OnConnect(c websocket.Connection) {
fmt.Println("socket.OnConnect()")
c.On("join", func(message string) { OnJoin(message, c) })
c.On("objectupdate", func(message string) { OnObjectUpdated(message, c) })
// ok works too c.EmitMessage([]byte("dsadsa"))
c.OnDisconnect(func() { OnDisconnect(c) })
}
// ServerLoop listen and serve websocket requests
func ServerLoop() {
app := iris.New()
ws := websocket.New(websocket.Config{})
// register the server on an endpoint.
// see the inline javascript code i the websockets.html, this endpoint is used to connect to the server.
app.Get("/socket", ws.Handler())
ws.OnConnection(OnConnect)
app.Run(iris.Addr(":8080"))
}
// OnJoin handles Join broadcast group request
func OnJoin(message string, c websocket.Connection) {
t := time.Now()
c.Join("server2")
fmt.Println("OnJoin() time taken:", time.Since(t))
}
// OnObjectUpdated broadcasts to all client an incoming message
func OnObjectUpdated(message string, c websocket.Connection) {
t := time.Now()
s := strings.Split(message, ";")
if len(s) != 3 {
fmt.Println("OnObjectUpdated() invalid message format:" + message)
return
}
serverID, _, objectID := s[0], s[1], s[2]
err := c.To("server"+serverID).Emit("objectupdate", objectID)
if err != nil {
fmt.Println(err, "failed to broacast object")
return
}
fmt.Println(fmt.Sprintf("OnObjectUpdated() message:%v, time taken: %v", message, time.Since(t)))
}
// OnDisconnect clean up things when a client is disconnected
func OnDisconnect(c websocket.Connection) {
c.Leave("server2")
fmt.Println("OnDisconnect(): client disconnected!")
}

View File

@@ -0,0 +1,63 @@
package main
import (
"fmt"
"github.com/kataras/iris"
"github.com/kataras/iris/context"
"github.com/kataras/iris/view"
"github.com/kataras/iris/websocket"
)
/* Native messages no need to import the iris-ws.js to the ./templates.client.html
Use of: OnMessage and EmitMessage.
NOTICE: IF YOU HAVE RAN THE PREVIOUS EXAMPLES YOU HAVE TO CLEAR YOUR BROWSER's CACHE
BECAUSE chat.js is different than the CACHED. OTHERWISE YOU WILL GET Ws is undefined from the browser's console, because it will use the cached.
*/
type clientPage struct {
Title string
Host string
}
func main() {
app := iris.New()
app.RegisterView(view.HTML("./templates", ".html")) // select the html engine to serve templates
ws := websocket.New(websocket.Config{
// to enable binary messages (useful for protobuf):
// BinaryMessages: true,
})
// register the server on an endpoint.
// see the inline javascript code i the websockets.html, this endpoint is used to connect to the server.
app.Get("/my_endpoint", ws.Handler())
app.StaticWeb("/js", "./static/js") // serve our custom javascript code
app.Get("/", func(ctx context.Context) {
ctx.ViewData("", clientPage{"Client Page", "localhost:8080"})
ctx.View("client.html")
})
ws.OnConnection(func(c websocket.Connection) {
c.OnMessage(func(data []byte) {
message := string(data)
c.To(websocket.Broadcast).EmitMessage([]byte("Message from: " + c.ID() + "-> " + message)) // broadcast to all clients except this
c.EmitMessage([]byte("Me: " + message)) // writes to itself
})
c.OnDisconnect(func() {
fmt.Printf("\nConnection with ID: %s has been disconnected!", c.ID())
})
})
app.Run(iris.Addr(":8080"))
}

View File

@@ -0,0 +1,38 @@
var messageTxt;
var messages;
$(function () {
messageTxt = $("#messageTxt");
messages = $("#messages");
w = new WebSocket("ws://" + HOST + "/my_endpoint");
w.onopen = function () {
console.log("Websocket connection enstablished");
};
w.onclose = function () {
appendMessage($("<div><center><h3>Disconnected</h3></center></div>"));
};
w.onmessage = function(message){
appendMessage($("<div>" + message.data + "</div>"));
};
$("#sendBtn").click(function () {
w.send(messageTxt.val().toString());
messageTxt.val("");
});
})
function appendMessage(messageDiv) {
var theDiv = messages[0];
var doScroll = theDiv.scrollTop == theDiv.scrollHeight - theDiv.clientHeight;
messageDiv.appendTo(messages);
if (doScroll) {
theDiv.scrollTop = theDiv.scrollHeight - theDiv.clientHeight;
}
}

View File

@@ -0,0 +1,21 @@
<html>
<head>
<title>{{ .Title}}</title>
</head>
<body>
<div id="messages"
style="border-width: 1px; border-style: solid; height: 400px; width: 375px;">
</div>
<input type="text" id="messageTxt" />
<button type="button" id="sendBtn">Send</button>
<script type="text/javascript">
var HOST = {{.Host}}
</script>
<script src="js/vendor/jquery-2.2.3.min.js" type="text/javascript"></script>
<script src="js/chat.js" type="text/javascript"></script>
</body>
</html>

View File

@@ -0,0 +1,176 @@
package main
import (
"fmt"
"io/ioutil"
"os"
"time"
"github.com/kataras/iris"
"github.com/kataras/iris/context"
"github.com/kataras/iris/view"
"github.com/kataras/iris/websocket"
)
type clientPage struct {
Title string
Host string
}
func main() {
app := iris.New()
app.RegisterView(view.HTML("./templates", ".html")) // select the html engine to serve templates
ws := websocket.New(websocket.Config{})
// register the server on an endpoint.
// see the inline javascript code i the websockets.html, this endpoint is used to connect to the server.
app.Get("/my_endpoint", ws.Handler())
// serve the javascript built'n client-side library,
// see weboskcets.html script tags, this path is used.
app.Any("/iris-ws.js", func(ctx context.Context) {
ctx.Write(websocket.ClientSource)
})
app.StaticWeb("/js", "./static/js")
app.Get("/", func(ctx context.Context) {
// send our custom javascript source file before client really asks for that
// using the go v1.8's HTTP/2 Push.
// Note that you have to listen using ListenTLS in order this to work.
if err := ctx.ResponseWriter().Push("/js/chat.js", nil); err != nil {
ctx.Application().Logger().Warnln(err.Error())
}
ctx.ViewData("", clientPage{"Client Page", ctx.Host()})
ctx.View("client.html")
})
var myChatRoom = "room1"
ws.OnConnection(func(c websocket.Connection) {
// Context returns the (upgraded) context.Context of this connection
// avoid using it, you normally don't need it,
// websocket has everything you need to authenticate the user BUT if it's necessary
// then you use it to receive user information, for example: from headers.
// ctx := c.Context()
// join to a room (optional)
c.Join(myChatRoom)
c.On("chat", func(message string) {
if message == "leave" {
c.Leave(myChatRoom)
c.To(myChatRoom).Emit("chat", "Client with ID: "+c.ID()+" left from the room and cannot send or receive message to/from this room.")
c.Emit("chat", "You have left from the room: "+myChatRoom+" you cannot send or receive any messages from others inside that room.")
return
}
// to all except this connection ->
// c.To(websocket.Broadcast).Emit("chat", "Message from: "+c.ID()+"-> "+message)
// to all connected clients: c.To(websocket.All)
// to the client itself ->
//c.Emit("chat", "Message from myself: "+message)
//send the message to the whole room,
//all connections are inside this room will receive this message
c.To(myChatRoom).Emit("chat", "From: "+c.ID()+": "+message)
})
// or create a new leave event
// c.On("leave", func() {
// c.Leave(myChatRoom)
// })
c.OnDisconnect(func() {
fmt.Printf("Connection with ID: %s has been disconnected!\n", c.ID())
})
})
listenTLS(app)
}
// a test listenTLS for our localhost
func listenTLS(app *iris.Application) {
const (
testTLSCert = `-----BEGIN CERTIFICATE-----
MIIDBTCCAe2gAwIBAgIJAOYzROngkH6NMA0GCSqGSIb3DQEBBQUAMBkxFzAVBgNV
BAMMDmxvY2FsaG9zdDo4MDgwMB4XDTE3MDIxNzAzNDM1NFoXDTI3MDIxNTAzNDM1
NFowGTEXMBUGA1UEAwwObG9jYWxob3N0OjgwODAwggEiMA0GCSqGSIb3DQEBAQUA
A4IBDwAwggEKAoIBAQCfsiVHO14FpKsi0pvBv68oApQm2MO+dCvq87sDU4E0QJhG
KV1RCUmQVypChEqdLlUQsopcXSyKwbWoyg1/KNHYO3DHMfePb4bC1UD2HENq7Ph2
8QJTEi/CJvUB9hqke/YCoWYdjFiI3h3Hw8q5whGO5XR3R23z69vr5XxoNlcF2R+O
TdkzArd0CWTZS27vbgdnyi9v3Waydh/rl+QRtPUgEoCEqOOkMSMldXO6Z9GlUk9b
FQHwIuEnlSoVFB5ot5cqebEjJnWMLLP83KOCQekJeHZOyjeTe8W0Fy1DGu5fvFNh
xde9e/7XlFE//00vT7nBmJAUV/2CXC8U5lsjLEqdAgMBAAGjUDBOMB0GA1UdDgQW
BBQOfENuLn/t0Z4ZY1+RPWaz7RBH+TAfBgNVHSMEGDAWgBQOfENuLn/t0Z4ZY1+R
PWaz7RBH+TAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQBG7AEEuIq6
rWCE5I2t4IXz0jN7MilqEhUWDbUajl1paYf6Ikx5QhMsFx21p6WEWYIYcnWAKZe2
chAgnnGojuxdx0qjiaH4N4xWGHsWhaesnIF1xJepLlX3kJZQURvRxM4wlljlQPIb
9tqzKP131K1HDqplAtp7nWQ72m3J0ZfzH0mYIUxuaS/uQIVtgKqdilwy/VE5dRZ9
QFIb4G9TnNThXMqgTLjfNr33jVbTuv6fzKHYNbCkP3L10ydEs/ddlREmtsn9nE8Q
XCTIYXzA2kr5kWk7d3LkUiSvu3g2S1Ol1YaIKaOQyRveseCGwR4xohLT+dPUW9dL
3hDVLlwE3mB3
-----END CERTIFICATE-----
`
testTLSKey = `-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAn7IlRzteBaSrItKbwb+vKAKUJtjDvnQr6vO7A1OBNECYRild
UQlJkFcqQoRKnS5VELKKXF0sisG1qMoNfyjR2DtwxzH3j2+GwtVA9hxDauz4dvEC
UxIvwib1AfYapHv2AqFmHYxYiN4dx8PKucIRjuV0d0dt8+vb6+V8aDZXBdkfjk3Z
MwK3dAlk2Utu724HZ8ovb91msnYf65fkEbT1IBKAhKjjpDEjJXVzumfRpVJPWxUB
8CLhJ5UqFRQeaLeXKnmxIyZ1jCyz/NyjgkHpCXh2Tso3k3vFtBctQxruX7xTYcXX
vXv+15RRP/9NL0+5wZiQFFf9glwvFOZbIyxKnQIDAQABAoIBAEzBx4ExW8PCni8i
o5LAm2PTuXniflMwa1uGwsCahmOjGI3AnAWzPRSPkNRf2a0q8+AOsMosTphy+umi
FFKmQBZ6m35i2earaE6FSbABbbYbKGGi/ccH2sSrDOBgdfXRTzF8eiSBrJw8hnvZ
87rNOLtCNnSOdJ7lItODfgRo+fLo4uQenJ8VONYwtwm1ejn8qLXq8O5zF66IYUD6
gAzqOiAWumgZL0tEmndeQ+noe4STpJZlOjiCsA12NiJaKDDeDIn5A/pXce+bYNfJ
k4yoroyq/JXBkhyuZDvX9vYp5AA+Q68h8/KmsKkifUgSGSHun5/80lYyT/f60TLX
PxT9GYECgYEA0s8qck7L29nBBTQ6IPF3GHGmqiRdfH+qhP/Jn4NtoW3XuVe4A15i
REq1L8WAiOUIBnBaD8HzbeioqJJYx1pu7x9h/GCNDhdBfwhTjnBe+JjfLqvJKnc0
HUT5wj4DVqattxKzUW8kTRBSWtVremzeffDo+EL6dnR7Bc02Ibs4WpUCgYEAwe34
Uqhie+/EFr4HjYRUNZSNgYNAJkKHVxk4qGzG5VhvjPafnHUbo+Kk/0QW7eIB+kvR
FDO8oKh9wTBrWZEcLJP4jDIKh4y8hZTo9B8EjxFONXVxZlOSYuGjheL8AiLzE7L9
C1spaKMM/MyxAXDRHpG/NeEgXM7Kn6kUGwJdNekCgYAshLNiEGHcu8+XWcAs1NFh
yB56L9PORuerzpi1pvuv65JzAaNKktQNt/krbXoHbtaTBYb/bOYLf+aeMsmsz9w9
g1MeCQXAxAiA2zFKE1D7Ds2S/ZQt8559z+MusgnicrCcyMY1nFL+M0QxCoD4CaWy
0v1f8EUUXuTcBMo5tV/hQQKBgDoBBW8jsiFDu7DZscSgOde00QZVzZAkAfsJLisi
LfNXGjZdZawUUuoX1iYLpZgNK25D0wtp1hdvjf2Ej/dAMd8bexHjvcaBT7ncqjiq
NmDcWjofIIXspTIyLwjStXGmJnJT7N/CqoYDjtTmHGND7Shpi3mAFn/r0isjFUJm
2J5RAoGALuGXxzmSRWmkIp11F/Qr3PBFWBWkrRWaH2TRLMhrU/wO8kCsSyo4PmAZ
ltOfD7InpDiCu43hcDPQ/29FUbDnmAhvMnmIQuHXGgPF/LhqEhbKPA/o/eZdQVCK
QG+tmveBBIYMed5YbWstZu/95lIHF+u8Hl+Z6xgveozfE5yqiUA=
-----END RSA PRIVATE KEY-----
`
)
// create the key and cert files on the fly, and delete them when this test finished
certFile, ferr := ioutil.TempFile("", "cert")
if ferr != nil {
panic(ferr)
}
keyFile, ferr := ioutil.TempFile("", "key")
if ferr != nil {
panic(ferr)
}
certFile.WriteString(testTLSCert)
keyFile.WriteString(testTLSKey)
// https://localhost
app.Run(iris.TLS("localhost:443", certFile.Name(), keyFile.Name()))
certFile.Close()
time.Sleep(50 * time.Millisecond)
os.Remove(certFile.Name())
keyFile.Close()
time.Sleep(50 * time.Millisecond)
os.Remove(keyFile.Name())
}

View File

@@ -0,0 +1,38 @@
var messageTxt;
var messages;
$(function () {
messageTxt = $("#messageTxt");
messages = $("#messages");
/* secure wss because we ListenTLS */
w = new Ws("wss://" + HOST + "/my_endpoint");
w.OnConnect(function () {
console.log("Websocket connection established");
});
w.OnDisconnect(function () {
appendMessage($("<div><center><h3>Disconnected</h3></center></div>"));
});
w.On("chat", function (message) {
appendMessage($("<div>" + message + "</div>"));
});
$("#sendBtn").click(function () {
w.Emit("chat", messageTxt.val().toString());
messageTxt.val("");
});
})
function appendMessage(messageDiv) {
var theDiv = messages[0];
var doScroll = theDiv.scrollTop == theDiv.scrollHeight - theDiv.clientHeight;
messageDiv.appendTo(messages);
if (doScroll) {
theDiv.scrollTop = theDiv.scrollHeight - theDiv.clientHeight;
}
}

View File

@@ -0,0 +1,24 @@
<html>
<head>
<title>{{ .Title}}</title>
</head>
<body>
<div id="messages"
style="border-width: 1px; border-style: solid; height: 400px; width: 375px;">
</div>
<input type="text" id="messageTxt" />
<button type="button" id="sendBtn">Send</button>
<script type="text/javascript">
var HOST = {{.Host}}
</script>
<script src="/js/vendor/jquery-2.2.3.min.js"></script>
<!-- This is auto-serving by the iris, you don't need to have this file in your disk-->
<script src="/iris-ws.js"></script>
<!-- -->
<script src="/js/chat.js"></script>
</body>
</html>