refactor: normalise internal/uri
This commit is contained in:
parent
6c47dbc38f
commit
d092eaed01
|
@ -1,8 +1,6 @@
|
||||||
package websocket
|
package websocket
|
||||||
|
|
||||||
import (
|
import "git.xdrm.io/go/ws/internal/uri"
|
||||||
"git.xdrm.io/go/ws/internal/uri/parser"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Client contains available information about a client
|
// Client contains available information about a client
|
||||||
type Client struct {
|
type Client struct {
|
||||||
|
@ -16,7 +14,7 @@ type ControllerFunc func(*Client, <-chan Message, chan<- Message, chan<- Message
|
||||||
|
|
||||||
// Controller is a websocket controller
|
// Controller is a websocket controller
|
||||||
type Controller struct {
|
type Controller struct {
|
||||||
URI *parser.Scheme // uri scheme
|
URI *uri.Scheme // uri scheme
|
||||||
Fun ControllerFunc // controller function
|
Fun ControllerFunc // controller function
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,10 +1,154 @@
|
||||||
package parser
|
package uri
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// === WILDCARDS ===
|
||||||
|
//
|
||||||
|
// The star '*' -> matches 0 or 1 slash-bounded string
|
||||||
|
// The multi star '**' -> matches 0 or more slash-separated strings
|
||||||
|
// The dot '.' -> matches 1 slash-bounded string
|
||||||
|
// The multi dot '..' -> matches 1 or more slash-separated strings
|
||||||
|
//
|
||||||
|
// === SCHEME POLICY ===
|
||||||
|
//
|
||||||
|
// - The last '/' is optional
|
||||||
|
// - Any '**' at the very end will match anything that starts with the given prefix
|
||||||
|
//
|
||||||
|
// === LIMITATIONS ==
|
||||||
|
//
|
||||||
|
// - A scheme must begin with '/'
|
||||||
|
// - A scheme cannot contain something else than a STRING or WILDCARD between 2 '/' separators
|
||||||
|
// - A scheme STRING cannot contain the symbols '/' as a character
|
||||||
|
// - A scheme STRING containing '*' or '.' characters will be treating as STRING only
|
||||||
|
// - A maximum of 16 slash-separated matchers (STRING or WILDCARD) are allowed
|
||||||
|
|
||||||
|
const maxMatch = 16
|
||||||
|
|
||||||
|
// Represents an URI matcher
|
||||||
|
type matcher struct {
|
||||||
|
pat string // pattern to match (empty if wildcard)
|
||||||
|
req bool // whether it is required
|
||||||
|
mul bool // whether multiple matches are allowed
|
||||||
|
|
||||||
|
buf []string // matched content (when matching)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scheme represents an URI scheme
|
||||||
|
type Scheme []*matcher
|
||||||
|
|
||||||
|
// FromString builds an URI scheme from a pattern string
|
||||||
|
func FromString(s string) (*Scheme, error) {
|
||||||
|
|
||||||
|
// 1. Manage '/' at the start
|
||||||
|
if len(s) < 1 || s[0] != '/' {
|
||||||
|
return nil, fmt.Errorf("URI must begin with '/'")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Split by '/'
|
||||||
|
parts := strings.Split(s, "/")
|
||||||
|
|
||||||
|
// 3. Max exceeded
|
||||||
|
if len(parts)-2 > maxMatch {
|
||||||
|
for i, p := range parts {
|
||||||
|
fmt.Printf("%d: '%s'\n", i, p)
|
||||||
|
}
|
||||||
|
return nil, fmt.Errorf("URI must not exceed %d slash-separated components, got %d", maxMatch, len(parts))
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Build for each part
|
||||||
|
sch, err := buildScheme(parts)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 5. Optimise structure
|
||||||
|
opti, err := sch.optimise()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &opti, nil
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Match returns if the given URI is matched by the scheme
|
||||||
|
func (s Scheme) Match(str string) bool {
|
||||||
|
|
||||||
|
// 1. Nothing -> match all
|
||||||
|
if len(s) == 0 {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Check for string match
|
||||||
|
clearURI, match := s.matchString(str)
|
||||||
|
if !match {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. Check for non-string match (wildcards)
|
||||||
|
match = s.matchWildcards(clearURI)
|
||||||
|
if !match {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetMatch returns the indexed match (excluding string matchers)
|
||||||
|
func (s Scheme) GetMatch(n uint8) ([]string, error) {
|
||||||
|
|
||||||
|
// 1. Index out of range
|
||||||
|
if n > uint8(len(s)) {
|
||||||
|
return nil, fmt.Errorf("Index out of range")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Iterate to find index (exclude strings)
|
||||||
|
ni := -1
|
||||||
|
for _, m := range s {
|
||||||
|
|
||||||
|
// ignore strings
|
||||||
|
if len(m.pat) > 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
// increment match counter : ni
|
||||||
|
ni++
|
||||||
|
|
||||||
|
// if expected index -> return matches
|
||||||
|
if uint8(ni) == n {
|
||||||
|
return m.buf, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3. If nothing found -> return empty set
|
||||||
|
return nil, fmt.Errorf("Index out of range (max: %d)", ni)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetAllMatch returns all the indexed match (excluding string matchers)
|
||||||
|
func (s Scheme) GetAllMatch() [][]string {
|
||||||
|
|
||||||
|
match := make([][]string, 0, len(s))
|
||||||
|
|
||||||
|
for _, m := range s {
|
||||||
|
|
||||||
|
// ignore strings
|
||||||
|
if len(m.pat) > 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
match = append(match, m.buf)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
return match
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
// buildScheme builds a 'basic' scheme
|
// buildScheme builds a 'basic' scheme
|
||||||
// from a pattern string
|
// from a pattern string
|
||||||
func buildScheme(ss []string) (Scheme, error) {
|
func buildScheme(ss []string) (Scheme, error) {
|
|
@ -1,116 +0,0 @@
|
||||||
package parser
|
|
||||||
|
|
||||||
import (
|
|
||||||
"fmt"
|
|
||||||
"strings"
|
|
||||||
)
|
|
||||||
|
|
||||||
// Build builds an URI scheme from a pattern string
|
|
||||||
func Build(s string) (*Scheme, error) {
|
|
||||||
|
|
||||||
// 1. Manage '/' at the start
|
|
||||||
if len(s) < 1 || s[0] != '/' {
|
|
||||||
return nil, fmt.Errorf("URI must begin with '/'")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Split by '/'
|
|
||||||
parts := strings.Split(s, "/")
|
|
||||||
|
|
||||||
// 3. Max exceeded
|
|
||||||
if len(parts)-2 > maxMatch {
|
|
||||||
for i, p := range parts {
|
|
||||||
fmt.Printf("%d: '%s'\n", i, p)
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("URI must not exceed %d slash-separated components, got %d", maxMatch, len(parts))
|
|
||||||
}
|
|
||||||
|
|
||||||
// 4. Build for each part
|
|
||||||
sch, err := buildScheme(parts)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// 5. Optimise structure
|
|
||||||
opti, err := sch.optimise()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return &opti, nil
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Match returns if the given URI is matched by the scheme
|
|
||||||
func (s Scheme) Match(str string) bool {
|
|
||||||
|
|
||||||
// 1. Nothing -> match all
|
|
||||||
if len(s) == 0 {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Check for string match
|
|
||||||
clearURI, match := s.matchString(str)
|
|
||||||
if !match {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Check for non-string match (wildcards)
|
|
||||||
match = s.matchWildcards(clearURI)
|
|
||||||
if !match {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetMatch returns the indexed match (excluding string matchers)
|
|
||||||
func (s Scheme) GetMatch(n uint8) ([]string, error) {
|
|
||||||
|
|
||||||
// 1. Index out of range
|
|
||||||
if n > uint8(len(s)) {
|
|
||||||
return nil, fmt.Errorf("Index out of range")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 2. Iterate to find index (exclude strings)
|
|
||||||
ni := -1
|
|
||||||
for _, m := range s {
|
|
||||||
|
|
||||||
// ignore strings
|
|
||||||
if len(m.pat) > 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
// increment match counter : ni
|
|
||||||
ni++
|
|
||||||
|
|
||||||
// if expected index -> return matches
|
|
||||||
if uint8(ni) == n {
|
|
||||||
return m.buf, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. If nothing found -> return empty set
|
|
||||||
return nil, fmt.Errorf("Index out of range (max: %d)", ni)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetAllMatch returns all the indexed match (excluding string matchers)
|
|
||||||
func (s Scheme) GetAllMatch() [][]string {
|
|
||||||
|
|
||||||
match := make([][]string, 0, len(s))
|
|
||||||
|
|
||||||
for _, m := range s {
|
|
||||||
|
|
||||||
// ignore strings
|
|
||||||
if len(m.pat) > 0 {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
match = append(match, m.buf)
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
return match
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,35 +0,0 @@
|
||||||
package parser
|
|
||||||
|
|
||||||
// === WILDCARDS ===
|
|
||||||
//
|
|
||||||
// The star '*' -> matches 0 or 1 slash-bounded string
|
|
||||||
// The multi star '**' -> matches 0 or more slash-separated strings
|
|
||||||
// The dot '.' -> matches 1 slash-bounded string
|
|
||||||
// The multi dot '..' -> matches 1 or more slash-separated strings
|
|
||||||
//
|
|
||||||
// === SCHEME POLICY ===
|
|
||||||
//
|
|
||||||
// - The last '/' is optional
|
|
||||||
// - Any '**' at the very end will match anything that starts with the given prefix
|
|
||||||
//
|
|
||||||
// === LIMITATIONS ==
|
|
||||||
//
|
|
||||||
// - A scheme must begin with '/'
|
|
||||||
// - A scheme cannot contain something else than a STRING or WILDCARD between 2 '/' separators
|
|
||||||
// - A scheme STRING cannot contain the symbols '/' as a character
|
|
||||||
// - A scheme STRING containing '*' or '.' characters will be treating as STRING only
|
|
||||||
// - A maximum of 16 slash-separated matchers (STRING or WILDCARD) are allowed
|
|
||||||
|
|
||||||
const maxMatch = 16
|
|
||||||
|
|
||||||
// Represents an URI matcher
|
|
||||||
type matcher struct {
|
|
||||||
pat string // pattern to match (empty if wildcard)
|
|
||||||
req bool // whether it is required
|
|
||||||
mul bool // whether multiple matches are allowed
|
|
||||||
|
|
||||||
buf []string // matched content (when matching)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Represents an URI scheme
|
|
||||||
type Scheme []*matcher
|
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
|
|
||||||
"git.xdrm.io/go/ws/internal/uri/parser"
|
"git.xdrm.io/go/ws/internal/uri"
|
||||||
)
|
)
|
||||||
|
|
||||||
// All channels that a server features
|
// All channels that a server features
|
||||||
|
@ -63,10 +63,10 @@ func (s *Server) BindDefault(f ControllerFunc) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bind a controller to an URI scheme
|
// Bind a controller to an URI scheme
|
||||||
func (s *Server) Bind(uri string, f ControllerFunc) error {
|
func (s *Server) Bind(uriStr string, f ControllerFunc) error {
|
||||||
|
|
||||||
// 1. Build URI parser
|
// 1. Build URI parser
|
||||||
uriScheme, err := parser.Build(uri)
|
uriScheme, err := uri.FromString(uriStr)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("Cannot build URI: %s", err)
|
return fmt.Errorf("Cannot build URI: %s", err)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue