mirror of
https://github.com/kataras/iris.git
synced 2025-02-02 07:20:35 +01:00
add Context.ResponseWriter.IsHijacked
to report whether the underline conn is already hijacked and a lot of cleanup and minor ws stress test example improvements
Former-commit-id: 444d4f0718d5c6d7544834c5e44dafb872980238
This commit is contained in:
parent
bda36145e5
commit
ddec78af0a
14
HISTORY.md
14
HISTORY.md
|
@ -38,7 +38,7 @@ I have some features in-mind but lately I do not have the time to humanize those
|
|||
|
||||
- fix [#1164](https://github.com/kataras/iris/issues/1164). [701e8e46c20395f87fa34bf9fabd145074c7b78c](https://github.com/kataras/iris/commit/701e8e46c20395f87fa34bf9fabd145074c7b78c) (@kataras)
|
||||
|
||||
- `context#ReadForm` can skip unkown fields by `IsErrPath(err)`, fixes: [#1157](https://github.com/kataras/iris/issues/1157). [1607bb5113568af6a34142f23bfa44903205b314](https://github.com/kataras/iris/commit/1607bb5113568af6a34142f23bfa44903205b314) (@kataras)
|
||||
- `context#ReadForm` can skip unknown fields by `IsErrPath(err)`, fixes: [#1157](https://github.com/kataras/iris/issues/1157). [1607bb5113568af6a34142f23bfa44903205b314](https://github.com/kataras/iris/commit/1607bb5113568af6a34142f23bfa44903205b314) (@kataras)
|
||||
|
||||
|
||||
Doc updates:
|
||||
|
@ -281,7 +281,7 @@ wsServer := websocket.New(websocket.Config{
|
|||
|
||||
// [...]
|
||||
|
||||
// serve the javascript built'n client-side library,
|
||||
// serve the javascript builtin client-side library,
|
||||
// see websockets.html script tags, this path is used.
|
||||
app.Any("/iris-ws.js", func(ctx iris.Context) {
|
||||
ctx.Write(wsServer.ClientSource)
|
||||
|
@ -401,7 +401,7 @@ The old `github.com/kataras/iris/core/router/macro` package was moved to `guthub
|
|||
- Add `:uint64` parameter type and `ctx.Params().GetUint64`
|
||||
- Add alias `:bool` for the `:boolean` parameter type
|
||||
|
||||
Here is the full list of the built'n parameter types that we support now, including their validations/path segment rules.
|
||||
Here is the full list of the builtin parameter types that we support now, including their validations/path segment rules.
|
||||
|
||||
| Param Type | Go Type | Validation | Retrieve Helper |
|
||||
| -----------------|------|-------------|------|
|
||||
|
@ -430,7 +430,7 @@ app.Get("/users/{id:uint64}", func(ctx iris.Context){
|
|||
})
|
||||
```
|
||||
|
||||
| Built'n Func | Param Types |
|
||||
| Builtin Func | Param Types |
|
||||
| -----------|---------------|
|
||||
| `regexp`(expr string) | :string |
|
||||
| `prefix`(prefix string) | :string |
|
||||
|
@ -633,7 +633,7 @@ Sincerely,
|
|||
|
||||
# We, 25 April 2018 | v10.6.1
|
||||
|
||||
- Re-implement the [BoltDB](https://github.com/coreos/bbolt) as built'n back-end storage for sessions(`sessiondb`) using the latest features: [/sessions/sessiondb/boltdb/database.go](sessions/sessiondb/boltdb/database.go), example can be found at [/_examples/sessions/database/boltdb/main.go](_examples/sessions/database/boltdb/main.go).
|
||||
- Re-implement the [BoltDB](https://github.com/coreos/bbolt) as builtin back-end storage for sessions(`sessiondb`) using the latest features: [/sessions/sessiondb/boltdb/database.go](sessions/sessiondb/boltdb/database.go), example can be found at [/_examples/sessions/database/boltdb/main.go](_examples/sessions/database/boltdb/main.go).
|
||||
- Fix a minor issue on [Badger sessiondb example](_examples/sessions/database/badger/main.go). Its `sessions.Config { Expires }` field was `2 *time.Second`, it's `45 *time.Minute` now.
|
||||
- Other minor improvements to the badger sessiondb.
|
||||
|
||||
|
@ -642,7 +642,7 @@ Sincerely,
|
|||
- Fix open redirect by @wozz via PR: https://github.com/kataras/iris/pull/972.
|
||||
- Fix when destroy session can't remove cookie in subdomain by @Chengyumeng via PR: https://github.com/kataras/iris/pull/964.
|
||||
- Add `OnDestroy(sid string)` on sessions for registering a listener when a session is destroyed with commit: https://github.com/kataras/iris/commit/d17d7fecbe4937476d00af7fda1c138c1ac6f34d.
|
||||
- Finally, sessions are in full-sync with the registered database now. That required a lot of internal code changed but **zero code change requirements by your side**. We kept only `badger` and `redis` as the back-end built'n supported sessions storages, they are enough. Made with commit: https://github.com/kataras/iris/commit/f2c3a5f0cef62099fd4d77c5ccb14f654ddbfb5c relative to many issues that you've requested it.
|
||||
- Finally, sessions are in full-sync with the registered database now. That required a lot of internal code changed but **zero code change requirements by your side**. We kept only `badger` and `redis` as the back-end builtin supported sessions storages, they are enough. Made with commit: https://github.com/kataras/iris/commit/f2c3a5f0cef62099fd4d77c5ccb14f654ddbfb5c relative to many issues that you've requested it.
|
||||
|
||||
# Sa, 24 March 2018 | v10.5.0
|
||||
|
||||
|
@ -840,7 +840,7 @@ The new package [hero](hero) contains features for binding any object or functio
|
|||
|
||||
Below you will see some screenshots we prepared for you in order to be easier to understand:
|
||||
|
||||
### 1. Path Parameters - Built'n Dependencies
|
||||
### 1. Path Parameters - Builtin Dependencies
|
||||
|
||||
![](https://github.com/kataras/explore/raw/master/iris/hero/hero-1-monokai.png)
|
||||
|
||||
|
|
|
@ -201,7 +201,7 @@ This history entry is not yet translated to Greek. Please read [the english vers
|
|||
|
||||
Παρακάτω θα δείτε μερικά στιγμιότυπα που ετοιμάσαμε για εσάς, ώστε να γίνουν πιο κατανοητά τα παραπάνω:
|
||||
|
||||
### 1. Παράμετροι διαδρομής - Ενσωματωμένες Εξαρτήσεις (Built'n Dependencies)
|
||||
### 1. Παράμετροι διαδρομής - Ενσωματωμένες Εξαρτήσεις (Builtin Dependencies)
|
||||
|
||||
![](https://github.com/kataras/explore/raw/master/iris/hero/hero-1-monokai.png)
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ This history entry is not translated yet to the Bahasa Indonesia language yet, p
|
|||
|
||||
# We, 25 April 2018 | v10.6.1
|
||||
|
||||
- Re-implement the [BoltDB](https://github.com/coreos/bbolt) as built'n back-end storage for sessions(`sessiondb`) using the latest features: [/sessions/sessiondb/boltdb/database.go](sessions/sessiondb/boltdb/database.go), example can be found at [/_examples/sessions/database/boltdb/main.go](_examples/sessions/database/boltdb/main.go).
|
||||
- Re-implement the [BoltDB](https://github.com/coreos/bbolt) as builtin back-end storage for sessions(`sessiondb`) using the latest features: [/sessions/sessiondb/boltdb/database.go](sessions/sessiondb/boltdb/database.go), example can be found at [/_examples/sessions/database/boltdb/main.go](_examples/sessions/database/boltdb/main.go).
|
||||
- Fix a minor issue on [Badger sessiondb example](_examples/sessions/database/badger/main.go). Its `sessions.Config { Expires }` field was `2 *time.Second`, it's `45 *time.Minute` now.
|
||||
- Other minor improvements to the badger sessiondb.
|
||||
|
||||
|
@ -80,7 +80,7 @@ This history entry is not translated yet to the Bahasa Indonesia language yet, p
|
|||
- Fix open redirect by @wozz via PR: https://github.com/kataras/iris/pull/972.
|
||||
- Fix when destroy session can't remove cookie in subdomain by @Chengyumeng via PR: https://github.com/kataras/iris/pull/964.
|
||||
- Add `OnDestroy(sid string)` on sessions for registering a listener when a session is destroyed with commit: https://github.com/kataras/iris/commit/d17d7fecbe4937476d00af7fda1c138c1ac6f34d.
|
||||
- Finally, sessions are in full-sync with the registered database now. That required a lot of internal code changed but **zero code change requirements by your side**. We kept only `badger` and `redis` as the back-end built'n supported sessions storages, they are enough. Made with commit: https://github.com/kataras/iris/commit/f2c3a5f0cef62099fd4d77c5ccb14f654ddbfb5c relative to many issues that you've requested it.
|
||||
- Finally, sessions are in full-sync with the registered database now. That required a lot of internal code changed but **zero code change requirements by your side**. We kept only `badger` and `redis` as the back-end builtin supported sessions storages, they are enough. Made with commit: https://github.com/kataras/iris/commit/f2c3a5f0cef62099fd4d77c5ccb14f654ddbfb5c relative to many issues that you've requested it.
|
||||
|
||||
# Sa, 24 March 2018 | v10.5.0
|
||||
|
||||
|
@ -278,7 +278,7 @@ The new package [hero](hero) contains features for binding any object or functio
|
|||
|
||||
Below you will see some screenshots we prepared for you in order to be easier to understand:
|
||||
|
||||
### 1. Path Parameters - Built'n Dependencies
|
||||
### 1. Path Parameters - Builtin Dependencies
|
||||
|
||||
![](https://github.com/kataras/explore/raw/master/iris/hero/hero-1-monokai.png)
|
||||
|
||||
|
|
|
@ -176,7 +176,7 @@ app.Get("/users/{id:uint64}", func(ctx iris.Context){
|
|||
})
|
||||
```
|
||||
|
||||
| Built'n Func | Param Types |
|
||||
| Builtin Func | Param Types |
|
||||
| -----------|---------------|
|
||||
| `regexp`(expr string) | :string |
|
||||
| `prefix`(prefix string) | :string |
|
||||
|
@ -300,7 +300,7 @@ With Iris you get truly safe bindings thanks to the [hero](_examples/hero) [pack
|
|||
|
||||
Below you will see some screenshots I prepared for you in order to be easier to understand:
|
||||
|
||||
#### 1. Path Parameters - Built'n Dependencies
|
||||
#### 1. Path Parameters - Builtin Dependencies
|
||||
|
||||
![](https://github.com/kataras/explore/raw/master/iris/hero/hero-1-monokai.png)
|
||||
|
||||
|
@ -797,7 +797,7 @@ func setupWebsocket(app *iris.Application) {
|
|||
// 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,
|
||||
// serve the javascript builtin client-side library,
|
||||
// see websockets.html script tags, this path is used.
|
||||
app.Any("/iris-ws.js", websocket.ClientHandler())
|
||||
}
|
||||
|
|
|
@ -134,7 +134,7 @@ func main() {
|
|||
|
||||
```
|
||||
|
||||
## Built'n Configurators
|
||||
## Builtin Configurators
|
||||
|
||||
```go
|
||||
// WithoutServerError will cause to ignore the matched "errors"
|
||||
|
|
|
@ -10,7 +10,7 @@ import (
|
|||
func main() {
|
||||
app := iris.New()
|
||||
app.Logger().SetLevel("debug")
|
||||
// Optionally, add two built'n handlers
|
||||
// Optionally, add two builtin handlers
|
||||
// that can recover from any http-relative panics
|
||||
// and log the requests to the terminal.
|
||||
app.Use(recover.New())
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# hero: basic
|
||||
|
||||
## 1. Path Parameters - Built'n Dependencies
|
||||
## 1. Path Parameters - Builtin Dependencies
|
||||
|
||||
![](https://github.com/kataras/explore/raw/master/iris/hero/hero-1-monokai.png)
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ var helloView = hero.View{
|
|||
// Hello will return a predefined view with bind data.
|
||||
//
|
||||
// `hero.Result` is just an interface with a `Dispatch` function.
|
||||
// `hero.Response` and `hero.View` are the built'n result type dispatchers
|
||||
// `hero.Response` and `hero.View` are the builtin result type dispatchers
|
||||
// you can even create custom response dispatchers by
|
||||
// implementing the `github.com/kataras/iris/hero#Result` interface.
|
||||
func Hello() hero.Result {
|
||||
|
|
|
@ -32,7 +32,7 @@ import (
|
|||
// for the main_test.go.
|
||||
func newApp() *iris.Application {
|
||||
app := iris.New()
|
||||
// Optionally, add two built'n handlers
|
||||
// Optionally, add two builtin handlers
|
||||
// that can recover from any http-relative panics
|
||||
// and log the requests to the terminal.
|
||||
app.Use(recover.New())
|
||||
|
|
|
@ -23,7 +23,7 @@ var helloView = mvc.View{
|
|||
// Get will return a predefined view with bind data.
|
||||
//
|
||||
// `mvc.Result` is just an interface with a `Dispatch` function.
|
||||
// `mvc.Response` and `mvc.View` are the built'n result type dispatchers
|
||||
// `mvc.Response` and `mvc.View` are the builtin result type dispatchers
|
||||
// you can even create custom response dispatchers by
|
||||
// implementing the `github.com/kataras/iris/hero#Result` interface.
|
||||
func (c *HelloController) Get() mvc.Result {
|
||||
|
|
|
@ -52,7 +52,7 @@ func main() {
|
|||
|
||||
/*
|
||||
http://localhost:8080/test_slice_hero/myvaluei1/myavlue2 ->
|
||||
myparam's value (a trailing path parameter type) is: []string{"myvaluei1", "myavlue2"}
|
||||
myparam's value (a trailing path parameter type) is: []string{"myvalue1", "myavlue2"}
|
||||
*/
|
||||
app.Get("/test_slice_hero/{myparam:slice}", hero.Handler(func(myparam []string) string {
|
||||
return fmt.Sprintf("myparam's value (a trailing path parameter type) is: %#v\n", myparam)
|
||||
|
@ -66,7 +66,7 @@ func main() {
|
|||
myparam's value (a trailing path parameter type) is: []string{"value1", "value2"}
|
||||
*/
|
||||
app.Get("/test_slice_contains/{myparam:slice contains([value1,value2])}", func(ctx context.Context) {
|
||||
// When it is not a built'n function available to retrieve your value with the type you want, such as ctx.Params().GetInt
|
||||
// When it is not a builtin function available to retrieve your value with the type you want, such as ctx.Params().GetInt
|
||||
// then you can use the `GetEntry.ValueRaw` to get the real value, which is set-ed by your macro above.
|
||||
myparam := ctx.Params().GetEntry("myparam").ValueRaw.([]string)
|
||||
ctx.Writef("myparam's value (a trailing path parameter type) is: %#v\n", myparam)
|
||||
|
|
|
@ -115,7 +115,7 @@ func main() {
|
|||
// 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,
|
||||
// serve the javascript builtin client-side library,
|
||||
// see websockets.html script tags, this path is used.
|
||||
app.Any("/iris-ws.js", func(ctx iris.Context) {
|
||||
ctx.Write(websocket.ClientSource)
|
||||
|
|
|
@ -40,7 +40,7 @@ func setupWebsocket(app *iris.Application) {
|
|||
// 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,
|
||||
// serve the javascript builtin client-side library,
|
||||
// see websockets.html script tags, this path is used.
|
||||
app.Any("/iris-ws.js", func(ctx iris.Context) {
|
||||
ctx.Write(ws.ClientSource)
|
||||
|
|
|
@ -25,7 +25,7 @@ func main() {
|
|||
// 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,
|
||||
// serve the javascript builtin client-side library,
|
||||
// see websockets.html script tags, this path is used.
|
||||
app.Any("/iris-ws.js", func(ctx iris.Context) {
|
||||
ctx.Write(websocket.ClientSource)
|
||||
|
|
|
@ -2,6 +2,7 @@ package main
|
|||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"log"
|
||||
"math/rand"
|
||||
"net"
|
||||
|
@ -19,7 +20,7 @@ var (
|
|||
)
|
||||
|
||||
const totalClients = 16000 // max depends on the OS.
|
||||
const verbose = true
|
||||
const verbose = false
|
||||
|
||||
var connectionFailures uint64
|
||||
|
||||
|
@ -43,7 +44,7 @@ func collectError(op string, err error) {
|
|||
}
|
||||
|
||||
func main() {
|
||||
log.Println("--Running...")
|
||||
log.Println("-- Running...")
|
||||
var err error
|
||||
f, err = os.Open("./test.data")
|
||||
if err != nil {
|
||||
|
@ -63,7 +64,7 @@ func main() {
|
|||
wg.Add(1)
|
||||
waitTime := time.Duration(rand.Intn(5)) * time.Millisecond
|
||||
time.Sleep(waitTime)
|
||||
go connect(wg, 7*time.Second+waitTime)
|
||||
go connect(wg, 14*time.Second+waitTime)
|
||||
}
|
||||
|
||||
for i := 0; i < totalClients/4; i++ {
|
||||
|
@ -77,7 +78,7 @@ func main() {
|
|||
wg.Add(1)
|
||||
waitTime := time.Duration(rand.Intn(5)) * time.Millisecond
|
||||
time.Sleep(waitTime)
|
||||
go connect(wg, 14*time.Second+waitTime)
|
||||
go connect(wg, 7*time.Second+waitTime)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
|
@ -136,16 +137,19 @@ func main() {
|
|||
log.Println("ALL OK.")
|
||||
}
|
||||
|
||||
log.Println("--Finished.")
|
||||
log.Println("-- Finished.")
|
||||
}
|
||||
|
||||
func connect(wg *sync.WaitGroup, alive time.Duration) {
|
||||
c, err := websocket.Dial(nil, url, websocket.ConnectionConfig{})
|
||||
func connect(wg *sync.WaitGroup, alive time.Duration) error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), alive)
|
||||
defer cancel()
|
||||
|
||||
c, err := websocket.Dial(ctx, url, websocket.ConnectionConfig{})
|
||||
if err != nil {
|
||||
atomic.AddUint64(&connectionFailures, 1)
|
||||
collectError("connect", err)
|
||||
wg.Done()
|
||||
return
|
||||
return err
|
||||
}
|
||||
|
||||
c.OnError(func(err error) {
|
||||
|
@ -167,23 +171,28 @@ func connect(wg *sync.WaitGroup, alive time.Duration) {
|
|||
}
|
||||
})
|
||||
|
||||
go func() {
|
||||
time.Sleep(alive)
|
||||
if err := c.Disconnect(); err != nil {
|
||||
collectError("disconnect", err)
|
||||
}
|
||||
if alive > 0 {
|
||||
go func() {
|
||||
time.Sleep(alive)
|
||||
if err := c.Disconnect(); err != nil {
|
||||
collectError("disconnect", err)
|
||||
}
|
||||
|
||||
wg.Done()
|
||||
}()
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(f)
|
||||
for !disconnected {
|
||||
if !scanner.Scan() || scanner.Err() != nil {
|
||||
break
|
||||
if !scanner.Scan() {
|
||||
return scanner.Err()
|
||||
}
|
||||
|
||||
if text := scanner.Text(); len(text) > 1 {
|
||||
c.Emit("chat", text)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -11,21 +11,24 @@ import (
|
|||
"github.com/kataras/iris/websocket"
|
||||
)
|
||||
|
||||
const totalClients = 16000 // max depends on the OS.
|
||||
const verbose = true
|
||||
const (
|
||||
endpoint = "localhost:8080"
|
||||
totalClients = 16000 // max depends on the OS.
|
||||
verbose = false
|
||||
maxC = 0
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
ws := websocket.New(websocket.Config{})
|
||||
ws.OnConnection(handleConnection)
|
||||
|
||||
// websocket.Config{PingPeriod: ((60 * time.Second) * 9) / 10}
|
||||
|
||||
go func() {
|
||||
dur := 8 * time.Second
|
||||
dur := 4 * time.Second
|
||||
if totalClients >= 64000 {
|
||||
// if more than 64000 then let's no check every 8 seconds, let's do it every 24 seconds,
|
||||
// just for simplicity, either way works.
|
||||
// if more than 64000 then let's perform those checks every 24 seconds instead,
|
||||
// either way works.
|
||||
dur = 24 * time.Second
|
||||
}
|
||||
t := time.NewTicker(dur)
|
||||
|
@ -40,12 +43,16 @@ func main() {
|
|||
n := ws.GetTotalConnections()
|
||||
if n > 0 {
|
||||
started = true
|
||||
if maxC > 0 && n > maxC {
|
||||
log.Printf("current connections[%d] > MaxConcurrentConnections[%d]", n, maxC)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if started {
|
||||
totalConnected := atomic.LoadUint64(&count)
|
||||
|
||||
if totalConnected == totalClients {
|
||||
disconnectedN := atomic.LoadUint64(&totalDisconnected)
|
||||
connectedN := atomic.LoadUint64(&totalConnected)
|
||||
if disconnectedN == totalClients && connectedN == totalClients {
|
||||
if n != 0 {
|
||||
log.Println("ALL CLIENTS DISCONNECTED BUT LEFTOVERS ON CONNECTIONS LIST.")
|
||||
} else {
|
||||
|
@ -53,7 +60,7 @@ func main() {
|
|||
}
|
||||
return
|
||||
} else if n == 0 {
|
||||
log.Printf("%d/%d CLIENTS WERE NOT CONNECTED AT ALL. CHECK YOUR OS NET SETTINGS. ALL OTHER CONNECTED CLIENTS DISCONNECTED SUCCESSFULLY.\n",
|
||||
log.Printf("%d/%d CLIENTS WERE NOT CONNECTED AT ALL. CHECK YOUR OS NET SETTINGS. THE REST CLIENTS WERE DISCONNECTED SUCCESSFULLY.\n",
|
||||
totalClients-totalConnected, totalClients)
|
||||
|
||||
return
|
||||
|
@ -64,11 +71,18 @@ func main() {
|
|||
|
||||
app := iris.New()
|
||||
app.Get("/", ws.Handler())
|
||||
app.Run(iris.Addr(":8080"))
|
||||
|
||||
app.Run(iris.Addr(endpoint), iris.WithoutServerError(iris.ErrServerClosed))
|
||||
}
|
||||
|
||||
var totalConnected uint64
|
||||
|
||||
func handleConnection(c websocket.Connection) {
|
||||
if c.Err() != nil {
|
||||
log.Fatalf("[%d] upgrade failed: %v", atomic.LoadUint64(&totalConnected)+1, c.Err())
|
||||
return
|
||||
}
|
||||
|
||||
atomic.AddUint64(&totalConnected, 1)
|
||||
c.OnError(func(err error) { handleErr(c, err) })
|
||||
c.OnDisconnect(func() { handleDisconnect(c) })
|
||||
c.On("chat", func(message string) {
|
||||
|
@ -76,12 +90,12 @@ func handleConnection(c websocket.Connection) {
|
|||
})
|
||||
}
|
||||
|
||||
var count uint64
|
||||
var totalDisconnected uint64
|
||||
|
||||
func handleDisconnect(c websocket.Connection) {
|
||||
atomic.AddUint64(&count, 1)
|
||||
newC := atomic.AddUint64(&totalDisconnected, 1)
|
||||
if verbose {
|
||||
log.Printf("client [%s] disconnected!\n", c.ID())
|
||||
log.Printf("[%d] client [%s] disconnected!\n", newC, c.ID())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ func main() {
|
|||
// 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,
|
||||
// serve the javascript builtin client-side library,
|
||||
// see websockets.html script tags, this path is used.
|
||||
app.Any("/iris-ws.js", func(ctx iris.Context) {
|
||||
ctx.Write(websocket.ClientSource)
|
||||
|
|
2
cache/client/handler.go
vendored
2
cache/client/handler.go
vendored
|
@ -125,7 +125,7 @@ func (h *Handler) ServeHTTP(ctx context.Context) {
|
|||
// if it's expired, then execute the original handler
|
||||
// with our custom response recorder response writer
|
||||
// because the net/http doesn't give us
|
||||
// a built'n way to get the status code & body
|
||||
// a builtin way to get the status code & body
|
||||
recorder := ctx.Recorder()
|
||||
bodyHandler(ctx)
|
||||
|
||||
|
|
|
@ -3177,7 +3177,7 @@ func (ctx *context) SendFile(filename string, destinationName string) error {
|
|||
// context's methods like `SetCookieKV`, `RemoveCookie` and `SetCookie`
|
||||
// as their (last) variadic input argument to amend the end cookie's form.
|
||||
//
|
||||
// Any custom or built'n `CookieOption` is valid,
|
||||
// Any custom or builtin `CookieOption` is valid,
|
||||
// see `CookiePath`, `CookieCleanPath`, `CookieExpires` and `CookieHTTPOnly` for more.
|
||||
type CookieOption func(*http.Cookie)
|
||||
|
||||
|
|
|
@ -41,6 +41,9 @@ type ResponseWriter interface {
|
|||
// Here is the place which we can make the last checks or do a cleanup.
|
||||
EndResponse()
|
||||
|
||||
// IsHijacked reports whether this response writer's connection is hijacked.
|
||||
IsHijacked() bool
|
||||
|
||||
// Writef formats according to a format specifier and writes to the response.
|
||||
//
|
||||
// Returns the number of bytes written and any write error encountered.
|
||||
|
@ -195,6 +198,15 @@ func (w *responseWriter) tryWriteHeader() {
|
|||
}
|
||||
}
|
||||
|
||||
// IsHijacked reports whether this response writer's connection is hijacked.
|
||||
func (w *responseWriter) IsHijacked() bool {
|
||||
// Note:
|
||||
// A zero-byte `ResponseWriter.Write` on a hijacked connection will
|
||||
// return `http.ErrHijacked` without any other side effects.
|
||||
_, err := w.ResponseWriter.Write(nil)
|
||||
return err == http.ErrHijacked
|
||||
}
|
||||
|
||||
// Write writes to the client
|
||||
// If WriteHeader has not yet been called, Write calls
|
||||
// WriteHeader(http.StatusOK) before writing the data. If the Header
|
||||
|
|
4
doc.go
4
doc.go
|
@ -1471,7 +1471,7 @@ Example Server Code:
|
|||
// see the inline javascript code i 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,
|
||||
// serve the javascript builtin client-side library,
|
||||
// see websockets.html script tags, this path is used.
|
||||
app.Any("/iris-ws.js", func(ctx iris.Context) {
|
||||
ctx.Write(websocket.ClientSource)
|
||||
|
@ -1554,7 +1554,7 @@ Example Code:
|
|||
|
||||
func main() {
|
||||
app := iris.New()
|
||||
// Optionally, add two built'n handlers
|
||||
// Optionally, add two builtin handlers
|
||||
// that can recover from any http-relative panics
|
||||
// and log the requests to the terminal.
|
||||
app.Use(recover.New())
|
||||
|
|
2
go19.go
2
go19.go
|
@ -82,7 +82,7 @@ type (
|
|||
// context's methods like `SetCookieKV`, `RemoveCookie` and `SetCookie`
|
||||
// as their (last) variadic input argument to amend the end cookie's form.
|
||||
//
|
||||
// Any custom or built'n `CookieOption` is valid,
|
||||
// Any custom or builtin `CookieOption` is valid,
|
||||
// see `CookiePath`, `CookieCleanPath`, `CookieExpires` and `CookieHTTPOnly` for more.
|
||||
//
|
||||
// An alias for the `context/Context#CookieOption`.
|
||||
|
|
|
@ -144,7 +144,7 @@ func (s *FuncInjector) addValue(inputIndex int, value reflect.Value) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// Retry used to add missing dependencies, i.e path parameter built'n bindings if not already exists
|
||||
// Retry used to add missing dependencies, i.e path parameter builtin bindings if not already exists
|
||||
// in the `hero.Handler`, once, only for that func injector.
|
||||
func (s *FuncInjector) Retry(retryFn func(inIndex int, inTyp reflect.Type) (reflect.Value, bool)) bool {
|
||||
for _, missing := range s.lost {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
package hero
|
||||
|
||||
// It's so easy, no need to be lived anywhere as built'n.. users should understand
|
||||
// It's so easy, no need to be lived anywhere as builtin.. users should understand
|
||||
// how easy it's by using it.
|
||||
|
||||
// // Session is a binder that will fill a *sessions.Session function input argument
|
||||
|
|
2
iris.go
2
iris.go
|
@ -613,7 +613,7 @@ func (app *Application) Shutdown(ctx stdContext.Context) error {
|
|||
// It can be used to register a custom runner with `Run` in order
|
||||
// to set the framework's server listen action.
|
||||
//
|
||||
// Currently Runner is being used to declare the built'n server listeners.
|
||||
// Currently `Runner` is being used to declare the builtin server listeners.
|
||||
//
|
||||
// See `Run` for more.
|
||||
type Runner func(*Application) error
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
Built'n Handlers
|
||||
Builtin Handlers
|
||||
------------
|
||||
|
||||
| Middleware | Example |
|
||||
|
|
|
@ -49,7 +49,7 @@ type (
|
|||
// CookieSecureTLS set to true if server is running over TLS
|
||||
// and you need the session's cookie "Secure" field to be setted true.
|
||||
//
|
||||
// Note: The user should fill the Decode configuation field in order for this to work.
|
||||
// Note: The user should fill the Decode configuration field in order for this to work.
|
||||
// Recommendation: You don't need this to be setted to true, just fill the Encode and Decode fields
|
||||
// with a third-party library like secure cookie, example is provided at the _examples folder.
|
||||
//
|
||||
|
|
|
@ -77,7 +77,7 @@ func main() {
|
|||
// - amber | iris.Amber(...)
|
||||
tmpl := iris.HTML("./templates", ".html")
|
||||
|
||||
// built'n template funcs are:
|
||||
// builtin template funcs are:
|
||||
//
|
||||
// - {{ urlpath "mynamedroute" "pathParameter_ifneeded" }}
|
||||
// - {{ render "header.html" }}
|
||||
|
|
|
@ -192,8 +192,9 @@ type (
|
|||
// Wait starts the pinger and the messages reader,
|
||||
// it's named as "Wait" because it should be called LAST,
|
||||
// after the "On" events IF server's `Upgrade` is used,
|
||||
// otherise you don't have to call it because the `Handler()` does it automatically.
|
||||
// otherwise you don't have to call it because the `Handler()` does it automatically.
|
||||
Wait()
|
||||
// UnderlyingConn returns the underline gorilla websocket connection.
|
||||
UnderlyingConn() *websocket.Conn
|
||||
}
|
||||
|
||||
|
@ -592,6 +593,14 @@ func (c *connection) fireOnLeave(roomName string) {
|
|||
// after the "On" events IF server's `Upgrade` is used,
|
||||
// otherise you don't have to call it because the `Handler()` does it automatically.
|
||||
func (c *connection) Wait() {
|
||||
// if c.server != nil && c.server.config.MaxConcurrentConnections > 0 {
|
||||
// defer func() {
|
||||
// go func() {
|
||||
// c.server.threads <- struct{}{}
|
||||
// }()
|
||||
// }()
|
||||
// }
|
||||
|
||||
if c.started {
|
||||
return
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ type (
|
|||
// See `OnConnection` , to register a single event which will handle all incoming connections and
|
||||
// the `Handler` which builds the upgrader handler that you can register to a route based on an Endpoint.
|
||||
//
|
||||
// To serve the built'n javascript client-side library look the `websocket.ClientHandler`.
|
||||
// To serve the builtin javascript client-side library look the `websocket.ClientHandler`.
|
||||
Server struct {
|
||||
config Config
|
||||
// ClientSource contains the javascript side code
|
||||
|
@ -44,10 +44,11 @@ type (
|
|||
// See `OnConnection` , to register a single event which will handle all incoming connections and
|
||||
// the `Handler` which builds the upgrader handler that you can register to a route based on an Endpoint.
|
||||
//
|
||||
// To serve the built'n javascript client-side library look the `websocket.ClientHandler`.
|
||||
// To serve the builtin javascript client-side library look the `websocket.ClientHandler`.
|
||||
func New(cfg Config) *Server {
|
||||
cfg = cfg.Validate()
|
||||
return &Server{
|
||||
|
||||
s := &Server{
|
||||
config: cfg,
|
||||
ClientSource: bytes.Replace(ClientSource, []byte(DefaultEvtMessageKey), cfg.EvtMessagePrefix, -1),
|
||||
connections: sync.Map{}, // ready-to-use, this is not necessary.
|
||||
|
@ -63,6 +64,8 @@ func New(cfg Config) *Server {
|
|||
EnableCompression: cfg.EnableCompression,
|
||||
},
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
// Handler builds the handler based on the configuration and returns it.
|
||||
|
@ -72,7 +75,7 @@ func New(cfg Config) *Server {
|
|||
//
|
||||
// Endpoint is the path which the websocket Server will listen for clients/connections.
|
||||
//
|
||||
// To serve the built'n javascript client-side library look the `websocket.ClientHandler`.
|
||||
// To serve the builtin javascript client-side library look the `websocket.ClientHandler`.
|
||||
func (s *Server) Handler() context.Handler {
|
||||
return func(ctx context.Context) {
|
||||
c := s.Upgrade(ctx)
|
||||
|
@ -104,14 +107,14 @@ func (s *Server) Handler() context.Handler {
|
|||
// If the upgrade fails, then Upgrade replies to the client with an HTTP error
|
||||
// response and the return `Connection.Err()` is filled with that error.
|
||||
//
|
||||
// For a more high-level function use the `Handler()` and `OnConnecton` events.
|
||||
// For a more high-level function use the `Handler()` and `OnConnection` events.
|
||||
// This one does not starts the connection's writer and reader, so after your `On/OnMessage` events registration
|
||||
// the caller has to call the `Connection#Wait` function, otherwise the connection will be not handled.
|
||||
func (s *Server) Upgrade(ctx context.Context) Connection {
|
||||
conn, err := s.upgrader.Upgrade(ctx.ResponseWriter(), ctx.Request(), ctx.ResponseWriter().Header())
|
||||
if err != nil {
|
||||
ctx.Application().Logger().Warnf("websocket error: %v\n", err)
|
||||
ctx.StatusCode(503) // Status Service Unavailable
|
||||
// ctx.StatusCode(503) // Status Service Unavailable
|
||||
return &connection{err: err}
|
||||
}
|
||||
|
||||
|
@ -150,29 +153,6 @@ func (s *Server) handleConnection(ctx context.Context, websocketConn *websocket.
|
|||
return c
|
||||
}
|
||||
|
||||
/* Notes:
|
||||
We use the id as the signature of the connection because with the custom IDGenerator
|
||||
the developer can share this ID with a database field, so we want to give the oportunnity to handle
|
||||
his/her websocket connections without even use the connection itself.
|
||||
|
||||
Another question may be:
|
||||
Q: Why you use Server as the main actioner for all of the connection actions?
|
||||
For example the Server.Disconnect(connID) manages the connection internal fields, is this code-style correct?
|
||||
A: It's the correct code-style for these type of applications and libraries, Server manages all, the connnection's functions
|
||||
should just do some internal checks (if needed) and push the action to its parent, which is the Server, the Server is able to
|
||||
remove a connection, the rooms of its connected and all these things, so in order to not split the logic, we have the main logic
|
||||
here, in the Server, and let the connection with some exported functions whose exists for the per-connection action user's code-style.
|
||||
|
||||
Ok my english are s** I can feel it, but these comments are mostly for me.
|
||||
*/
|
||||
|
||||
/*
|
||||
connection actions, same as the connection's method,
|
||||
but these methods accept the connection ID,
|
||||
which is useful when the developer maps
|
||||
this id with a database field (using config.IDGenerator).
|
||||
*/
|
||||
|
||||
// OnConnection is the main event you, as developer, will work with each of the websocket connections.
|
||||
func (s *Server) OnConnection(cb ConnectionFunc) {
|
||||
s.onConnectionListeners = append(s.onConnectionListeners, cb)
|
||||
|
|
|
@ -47,7 +47,7 @@ Example code:
|
|||
// this endpoint is used to connect to the server.
|
||||
app.Get("/echo", ws.Handler())
|
||||
|
||||
// serve the javascript built'n client-side library,
|
||||
// serve the javascript builtin client-side library,
|
||||
// see websockets.html script tags, this path is used.
|
||||
app.Any("/iris-ws.js", func(ctx context.Context) {
|
||||
ctx.Write(websocket.ClientSource)
|
||||
|
|
Loading…
Reference in New Issue
Block a user