diff --git a/controller.go b/controller.go index e0f9bfd..f2cc3d1 100644 --- a/controller.go +++ b/controller.go @@ -1,8 +1,6 @@ package websocket -import ( - "git.xdrm.io/go/ws/internal/uri/parser" -) +import "git.xdrm.io/go/ws/internal/uri" // Client contains available information about a client type Client struct { @@ -16,7 +14,7 @@ type ControllerFunc func(*Client, <-chan Message, chan<- Message, chan<- Message // Controller is a websocket controller type Controller struct { - URI *parser.Scheme // uri scheme + URI *uri.Scheme // uri scheme Fun ControllerFunc // controller function } diff --git a/internal/uri/parser/private.go b/internal/uri/parser.go similarity index 56% rename from internal/uri/parser/private.go rename to internal/uri/parser.go index 7daa62c..e35a4ee 100644 --- a/internal/uri/parser/private.go +++ b/internal/uri/parser.go @@ -1,10 +1,154 @@ -package parser +package uri import ( "fmt" "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 // from a pattern string func buildScheme(ss []string) (Scheme, error) { diff --git a/internal/uri/parser/public.go b/internal/uri/parser/public.go deleted file mode 100644 index e564ddc..0000000 --- a/internal/uri/parser/public.go +++ /dev/null @@ -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 - -} diff --git a/internal/uri/parser/types.go b/internal/uri/parser/types.go deleted file mode 100644 index f68826c..0000000 --- a/internal/uri/parser/types.go +++ /dev/null @@ -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 diff --git a/server.go b/server.go index 7bc47d3..9102b25 100644 --- a/server.go +++ b/server.go @@ -4,7 +4,7 @@ import ( "fmt" "net" - "git.xdrm.io/go/ws/internal/uri/parser" + "git.xdrm.io/go/ws/internal/uri" ) // All channels that a server features @@ -63,10 +63,10 @@ func (s *Server) BindDefault(f ControllerFunc) { } // 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 - uriScheme, err := parser.Build(uri) + uriScheme, err := uri.FromString(uriStr) if err != nil { return fmt.Errorf("Cannot build URI: %s", err) }