Skip to content

Commit

Permalink
introduction v2 as go module
Browse files Browse the repository at this point in the history
  • Loading branch information
igm committed Mar 29, 2020
1 parent cd6986d commit 00dcf4b
Show file tree
Hide file tree
Showing 45 changed files with 2,897 additions and 11 deletions.
29 changes: 18 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,25 +15,32 @@ SockJS-Go server library

SockJS-Go is a [SockJS](https://github.com/sockjs/sockjs-client) server library written in Go.

To use current stable version **v2**
To use current stable version **v2** use the import path:

go get gopkg.in/igm/sockjs-go.v2/sockjs
github.com/igm/sockjs-go/v2/sockjs

To use previous version **v1** (DEPRECATED)

go get gopkg.in/igm/sockjs-go.v1/sockjs

To install **development** version of `sockjs-go` run:
Versioning
-

go get github.com/igm/sockjs-go/sockjs
Each version should have different import path and thus in the beginning
SockJS-Go project adopted [gopkg.in](http://gopkg.in) approach for versioning.

With the introduction of [go modules](https://golang.org/doc/go1.11#modules) we adopted
the standard and update the source layout accordingly.

Versioning
-
All the development for *all versions* happens in `master`. Branches `v2` and `v1` will
remain in the repository for backwards compatibility reasons so that
importing `gopkg.in/igm/sockjs-go.v2/sockjs` will work as before.
No further functionality will be added into those branches.

SockJS-Go project adopted [gopkg.in](http://gopkg.in) approach for versioning. SockJS-Go library details can be found [here](https://gopkg.in/igm/sockjs-go.v2/sockjs)
Migration to go mod
--

In order to migrate existing project to go modules change the import path from
`gopkg.in/igm/sockjs-go.v2/sockjs` to `github.com/igm/sockjs-go/v2/sockjs` in the codebase.


Example
-

Expand All @@ -47,7 +54,7 @@ import (
"log"
"net/http"

"gopkg.in/igm/sockjs-go.v2/sockjs"
"github.com/igm/sockjs-go/v2/sockjs"
)

func main() {
Expand Down
16 changes: 16 additions & 0 deletions v2/examples/webchat/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Chat Example

Simple sockjs chat example.

## Run
```shell
$ go run webchat.go
```
Navigate using web browser: http://127.0.0.1:8080
Open multiple windows with the same URL and see how chat works.

## Docker
```shell
$ docker run -p=80:8080 -d imihalik/sockjs-chat
```

22 changes: 22 additions & 0 deletions v2/examples/webchat/web/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
if (!window.location.origin) { // Some browsers (mainly IE) do not have this property, so we need to build it manually...
window.location.origin = window.location.protocol + '//' + window.location.hostname + (window.location.port ? (':' + window.location.port) : '');
}


var sock = new SockJS(window.location.origin+'/echo')

sock.onopen = function() {
// console.log('connection open');
document.getElementById("status").innerHTML = "connected";
document.getElementById("send").disabled=false;
};

sock.onmessage = function(e) {
document.getElementById("output").value += e.data +"\n";
};

sock.onclose = function() {
// console.log('connection closed');
document.getElementById("status").innerHTML = "disconnected";
document.getElementById("send").disabled=true;
};
24 changes: 24 additions & 0 deletions v2/examples/webchat/web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript" src="//cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
<script type="text/javascript" src="app.js"></script>
<meta charset="UTF-8">
<title>Chat Web Example</title>
</head>

<body>
<h1>Chat - Web Example</h1>
<form onSubmit='sock.send(document.getElementById("input").value); return false;'>
Input text: <input id="input" focus="true"/>
<input type="submit" disabled="true" id="send" value="Send"/>
</form>
<br/>
Messages from server:</br>
<textarea cols=80 rows=20 id="output">
</textarea>
<br/>
status: <span id="status">connecting...</span>

</body>
</html>
48 changes: 48 additions & 0 deletions v2/examples/webchat/webchat.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package main

import (
"log"
"net/http"

"github.com/igm/pubsub"
"github.com/igm/sockjs-go/v2/sockjs"
)

var chat pubsub.Publisher

func main() {
http.Handle("/echo/", sockjs.NewHandler("/echo", sockjs.DefaultOptions, echoHandler))
http.Handle("/", http.FileServer(http.Dir("web/")))
log.Println("Server started on port: 8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}

func echoHandler(session sockjs.Session) {
log.Println("new sockjs session established")
var closedSession = make(chan struct{})
chat.Publish("[info] new participant joined chat")
defer chat.Publish("[info] participant left chat")
go func() {
reader, _ := chat.SubChannel(nil)
for {
select {
case <-closedSession:
return
case msg := <-reader:
if err := session.Send(msg.(string)); err != nil {
return
}
}

}
}()
for {
if msg, err := session.Recv(); err == nil {
chat.Publish(msg)
continue
}
break
}
close(closedSession)
log.Println("sockjs session closed")
}
9 changes: 9 additions & 0 deletions v2/examples/webecho/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# Echo Example

Simple echo sockjs example.

## Run
```shell
$ go run webecho.go
```
Navigate using web browser: http://127.0.0.1:8080
34 changes: 34 additions & 0 deletions v2/examples/webecho/web/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
if (!window.location.origin) { // Some browsers (mainly IE) do not have this property, so we need to build it manually...
window.location.origin = window.location.protocol + '//' + window.location.hostname + (window.location.port ? (':' + window.location.port) : '');
}

var origin = window.location.origin;

// options usage example
var options = {
debug: true,
devel: true,
protocols_whitelist: ['websocket', 'xdr-streaming', 'xhr-streaming', 'iframe-eventsource', 'iframe-htmlfile', 'xdr-polling', 'xhr-polling', 'iframe-xhr-polling', 'jsonp-polling']
};

var sock = new SockJS(origin+'/echo', undefined, options);

sock.onopen = function() {
//console.log('connection open');
document.getElementById("status").innerHTML = "connected";
document.getElementById("send").disabled=false;
};

sock.onmessage = function(e) {
document.getElementById("output").value += e.data +"\n";
};

sock.onclose = function() {
document.getElementById("status").innerHTML = "connection closed";
//console.log('connection closed');
};

function send() {
text = document.getElementById("input").value;
sock.send(document.getElementById("input").value); return false;
}
24 changes: 24 additions & 0 deletions v2/examples/webecho/web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<script type="text/javascript" src="//cdn.jsdelivr.net/npm/sockjs-client@1/dist/sockjs.min.js"></script>
<script type="text/javascript" src="app.js"></script>
<meta charset="UTF-8">
<title>Echo Web Example</title>
</head>

<body>
<h1>Echo - Web Example</h1>
<form onSubmit='sock.send(document.getElementById("input").value); return false;'>
Input text: <input id="input" focus="true"/>
<input type="submit" disabled="true" id="send" value="Send"/>
</form>
<br/>
Messages from server:</br>
<textarea cols=80 rows=20 id="output">
</textarea>
<br/>
status: <span id="status">connecting...</span>

</body>
</html>
39 changes: 39 additions & 0 deletions v2/examples/webecho/webecho.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package main

import (
"flag"
"log"
"net/http"

"github.com/igm/sockjs-go/v2/sockjs"
)

var (
websocket = flag.Bool("websocket", true, "enable/disable websocket protocol")
)

func init() {
flag.Parse()
}

func main() {
opts := sockjs.DefaultOptions
opts.Websocket = *websocket
handler := sockjs.NewHandler("/echo", opts, echoHandler)
http.Handle("/echo/", handler)
http.Handle("/", http.FileServer(http.Dir("web/")))
log.Println("Server started on port: 8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}

func echoHandler(session sockjs.Session) {
log.Println("new sockjs session established")
for {
if msg, err := session.Recv(); err == nil {
session.Send(msg)
continue
}
break
}
log.Println("sockjs session closed")
}
9 changes: 9 additions & 0 deletions v2/go.mod
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module github.com/igm/sockjs-go/v2

go 1.14

require (
github.com/gorilla/websocket v1.4.2
github.com/igm/pubsub v1.0.0
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e
)
7 changes: 7 additions & 0 deletions v2/go.sum
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/igm/pubsub v1.0.0/go.mod h1:q4OjwAiOVflOQD1dXrh3QfJ+IqTG/xiQIvZwDeQIiqY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
94 changes: 94 additions & 0 deletions v2/sockjs/benchmarks_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package sockjs

import (
"bufio"
"fmt"
"log"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"sync"
"testing"
)

func BenchmarkSimple(b *testing.B) {
var messages = make(chan string, 10)
h := NewHandler("/echo", DefaultOptions, func(session Session) {
for m := range messages {
session.Send(m)
}
session.Close(1024, "Close")
})
server := httptest.NewServer(h)
defer server.Close()

req, _ := http.NewRequest("POST", server.URL+fmt.Sprintf("/echo/server/%d/xhr_streaming", 1000), nil)
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
for n := 0; n < b.N; n++ {
messages <- "some message"
}
fmt.Println(b.N)
close(messages)
resp.Body.Close()
}

func BenchmarkMessages(b *testing.B) {
msg := strings.Repeat("m", 10)
h := NewHandler("/echo", DefaultOptions, func(session Session) {
for n := 0; n < b.N; n++ {
session.Send(msg)
}
session.Close(1024, "Close")
})
server := httptest.NewServer(h)

var wg sync.WaitGroup

for i := 0; i < 100; i++ {
wg.Add(1)
go func(session int) {
reqc := 0
// req, _ := http.NewRequest("POST", server.URL+fmt.Sprintf("/echo/server/%d/xhr_streaming", session), nil)
req, _ := http.NewRequest("GET", server.URL+fmt.Sprintf("/echo/server/%d/eventsource", session), nil)
for {
reqc++
resp, err := http.DefaultClient.Do(req)
if err != nil {
log.Fatal(err)
}
reader := bufio.NewReader(resp.Body)
for {
line, err := reader.ReadString('\n')
if err != nil {
goto AGAIN
}
if strings.HasPrefix(line, "data: c[1024") {
resp.Body.Close()
goto DONE
}
}
AGAIN:
resp.Body.Close()
}
DONE:
wg.Done()
}(i)
}
wg.Wait()
server.Close()
}

func BenchmarkHandler_ParseSessionID(b *testing.B) {
h := handler{prefix: "/prefix"}
url, _ := url.Parse("http://server:80/prefix/server/session/whatever")

b.ReportAllocs()
b.ResetTimer()
for i := 0; i < b.N; i++ {
h.parseSessionID(url)
}
}
5 changes: 5 additions & 0 deletions v2/sockjs/doc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/*
Package sockjs is a server side implementation of sockjs protocol.
*/

package sockjs
Loading

0 comments on commit 00dcf4b

Please sign in to comment.