sync with master fixes and add more details in the HISTORY.md for the upcoming release

Former-commit-id: 13d5f3bd0dd844dbe2f709cfe8423a7417542744
This commit is contained in:
Gerasimos (Makis) Maropoulos 2018-10-17 07:13:34 +03:00
parent e3876d793c
commit df85be52a4
2 changed files with 90 additions and 6 deletions

View File

@ -28,6 +28,87 @@ Developers are not forced to upgrade if they don't really need it. Upgrade whene
## Routing ## Routing
I wrote a [new router implementation](https://github.com/kataras/muxie#philosophy) for our Iris internal(low-level) routing mechanism, it is good to know that this was the second time we have updated the router internals without a single breaking change after the v6, thanks to the very well-writen and designed-first code we have for the high-level path syntax component called [macro interpreter](macro/interpreter).
The new router supports things like **closest wildcard resolution**.
> If the name doesn't sound good to you it is because I named that feature myself, I don't know any other framework or router that supports a thing like that so be gentle:)
Previously you couldn't register routes like: `/{myparam:path}` and `/static` and `/{myparam:string}` and `/{myparam:string}/static` and `/static/{myparam:string}` all in one path prefix without a "decision handler". And generally if you had a wildcard it was possible to add (a single) static part and (a single) named parameter but not without performance cost and limits, why only one? (one is better than nothing: look the Iris' alternatives) We struggle to overcome our own selves, now you **can definitely do it without a bit of performance cost**, and surely we hand't imagine the wildcard to **catch all if nothing else found** without huge routing performance cost, the wildcard(`:path`) meant ONLY: "accept one or more path segments and put them into the declared parameter" so if you had register a dynamic single-path-segment named parameter like `:string, :int, :uint, :alphabetical...` in between those path segments it wouldn't work. The **closest wildcard resolution** offers you the opportunity to design your APIs even better via custom handlers and error handlers like `404 not found` to path prefixes for your API's groups, now you can do it without any custom code for path resolution inside a "decision handler" or a middleware.
Code worths 1000 words, now it is possible to define your routes like this without any issues:
```go
package main
import (
"github.com/kataras/iris"
"github.com/kataras/iris/context"
)
func main() {
app := iris.New()
// matches everyhing if nothing else found,
// so you can use it for custom 404 root-level/main pages!
app.Get("/{p:path}", func(ctx context.Context) {
path := ctx.Params().Get("p")
// gives the path without the first "/".
ctx.Writef("Site Custom 404 Error Message\nPage of: '%s' not found", path)
})
app.Get("/", indexHandler)
// request: http://localhost:8080/profile
// response: "Profile Index"
app.Get("/profile", func(ctx context.Context) {
ctx.Writef("Profile Index")
})
// request: http://localhost:8080/profile/kataras
// response: "Profile of username: 'kataras'"
app.Get("/profile/{username}", func(ctx context.Context) {
username := ctx.Params().Get("username")
ctx.Writef("Profile of username: '%s'", username)
})
// request: http://localhost:8080/profile/settings
// response: "Profile personal settings"
app.Get("/profile/settings", func(ctx context.Context) {
ctx.Writef("Profile personal settings")
})
// request: http://localhost:8080/profile/settings/security
// response: "Profile personal security settings"
app.Get("/profile/settings/security", func(ctx context.Context) {
ctx.Writef("Profile personal security settings")
})
// matches everyhing /profile/*somethng_here*
// if no other route matches the path semgnet after the
// /profile or /profile/
//
// So, you can use it for custom 404 profile pages
// side-by-side to your root wildcard without issues!
// For example:
// request: http://localhost:8080/profile/kataras/what
// response:
// Profile Page Custom 404 Error Message
// Profile Page of: 'kataras/what' was unable to be found
app.Get("/profile/{p:path}", func(ctx context.Context) {
path := ctx.Params().Get("p")
ctx.Writef("Profile Page Custom 404 Error Message\nProfile Page of: '%s' not found", path)
})
app.Run(iris.Addr(":8080"))
}
func indexHandler(ctx context.Context) {
ctx.HTML("This is the <strong>index page</strong>")
}
```
The `github.com/kataras/iris/core/router.AllMethods` is now a variable that can be altered by end-developers, so things like `app.Any` can register to custom methods as well, as requested at: https://github.com/kataras/iris/issues/1102. For example, import that package and do `router.AllMethods = append(router.AllMethods, "LINK")` in your `main` or `init` function. The `github.com/kataras/iris/core/router.AllMethods` is now a variable that can be altered by end-developers, so things like `app.Any` can register to custom methods as well, as requested at: https://github.com/kataras/iris/issues/1102. For example, import that package and do `router.AllMethods = append(router.AllMethods, "LINK")` in your `main` or `init` function.
The old `github.com/kataras/iris/core/router/macro` package was moved to `guthub.com/kataras/iris/macro` to allow end-developers to add custom parameter types and macros, it supports all go standard types by default as you will see below. The old `github.com/kataras/iris/core/router/macro` package was moved to `guthub.com/kataras/iris/macro` to allow end-developers to add custom parameter types and macros, it supports all go standard types by default as you will see below.
@ -48,7 +129,7 @@ Here is the full list of the built'n parameter types that we support now, includ
| Param Type | Go Type | Validation | Retrieve Helper | | Param Type | Go Type | Validation | Retrieve Helper |
| -----------------|------|-------------|------| | -----------------|------|-------------|------|
| `:string` | string | anything (single path segment) | `Params().Get` | | `:string` | string | the default if param type is missing, anything (single path segment) | `Params().Get` |
| `:int` | int | -9223372036854775808 to 9223372036854775807 (x64) or -2147483648 to 2147483647 (x32), depends on the host arch | `Params().GetInt` | | `:int` | int | -9223372036854775808 to 9223372036854775807 (x64) or -2147483648 to 2147483647 (x32), depends on the host arch | `Params().GetInt` |
| `:int8` | int8 | -128 to 127 | `Params().GetInt8` | | `:int8` | int8 | -128 to 127 | `Params().GetInt8` |
| `:int16` | int16 | -32768 to 32767 | `Params().GetInt16` | | `:int16` | int16 | -32768 to 32767 | `Params().GetInt16` |

View File

@ -52,9 +52,9 @@ type (
func New(cfg Config) *Server { func New(cfg Config) *Server {
cfg = cfg.Validate() cfg = cfg.Validate()
return &Server{ return &Server{
config: cfg, config: cfg,
connections: sync.Map{}, // ready-to-use, this is not necessary. connections: sync.Map{}, // ready-to-use, this is not necessary.
rooms: make(map[string][]string), rooms: make(map[string][]string),
onConnectionListeners: make([]ConnectionFunc, 0), onConnectionListeners: make([]ConnectionFunc, 0),
upgrader: websocket.Upgrader{ upgrader: websocket.Upgrader{
HandshakeTimeout: cfg.HandshakeTimeout, HandshakeTimeout: cfg.HandshakeTimeout,
@ -352,9 +352,12 @@ func (s *Server) GetConnectionsByRoom(roomName string) []Connection {
// let's keep it unexported for the best. // let's keep it unexported for the best.
func (s *Server) emitMessage(from, to string, data []byte) { func (s *Server) emitMessage(from, to string, data []byte) {
if to != All && to != Broadcast { if to != All && to != Broadcast {
if s.rooms[to] != nil { s.mu.RLock()
room := s.rooms[to]
s.mu.RUnlock()
if room != nil {
// it suppose to send the message to a specific room/or a user inside its own room // it suppose to send the message to a specific room/or a user inside its own room
for _, connectionIDInsideRoom := range s.rooms[to] { for _, connectionIDInsideRoom := range room {
if c, ok := s.getConnection(connectionIDInsideRoom); ok { if c, ok := s.getConnection(connectionIDInsideRoom); ok {
c.writeDefault(data) //send the message to the client(s) c.writeDefault(data) //send the message to the client(s)
} else { } else {