refactor: normalise internal/uri

This commit is contained in:
Adrien Marquès 2021-05-14 17:23:33 +02:00
parent 6c47dbc38f
commit d092eaed01
Signed by: xdrm-brackets
GPG Key ID: D75243CA236D825E
5 changed files with 150 additions and 159 deletions

View File

@ -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
} }

View File

@ -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) {

View File

@ -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
}

View File

@ -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

View File

@ -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)
} }