~fnux/yggdrasil-go-coap

ref: 614f652b70b2 yggdrasil-go-coap/servermux.go -rw-r--r-- 4.2 KiB
614f652bTimothée Floure Add syntax highlighting to code snippets in README 1 year, 4 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
// Package coap provides a CoAP client and server.
package coap

import (
	"errors"
	"sync"
)

// ServeMux is an COAP request multiplexer. It matches the
// path name of each incoming request against a list of
// registered patterns add calls the handler for the pattern
// with same name.
// ServeMux is also safe for concurrent access from multiple goroutines.
type ServeMux struct {
	z              map[string]muxEntry
	m              *sync.RWMutex
	defaultHandler Handler
}

type muxEntry struct {
	h       Handler
	pattern string
}

// NewServeMux allocates and returns a new ServeMux.
func NewServeMux() *ServeMux {
	return &ServeMux{z: make(map[string]muxEntry), m: new(sync.RWMutex), defaultHandler: HandlerFunc(HandleFailed)}
}

// DefaultServeMux is the default ServeMux used by Serve.
var DefaultServeMux = NewServeMux()

// Does path match pattern?
func pathMatch(pattern, path string) bool {
	switch pattern {
	case "", "/":
		switch path {
		case "", "/":
			return true
		}
		return false
	default:
		n := len(pattern)
		if pattern[n-1] != '/' {
			return pattern == path
		}
		return len(path) >= n && path[0:n] == pattern
	}
}

// Find a handler on a handler map given a path string
// Most-specific (longest) pattern wins
func (mux *ServeMux) match(path string) (h Handler, pattern string) {
	mux.m.RLock()
	defer mux.m.RUnlock()
	var n = 0
	for k, v := range mux.z {
		if !pathMatch(k, path) {
			continue
		}
		if h == nil || len(k) > n {
			n = len(k)
			h = v.h
			pattern = v.pattern
		}
	}
	return
}

// Handle adds a handler to the ServeMux for pattern.
func (mux *ServeMux) Handle(pattern string, handler Handler) error {
	switch pattern {
	case "", "/":
     pattern = "/"
	default:
		if pattern[0] == '/' {
			pattern = pattern[1:]
		}
	}

	if handler == nil {
		return errors.New("nil handler")
	}

	mux.m.Lock()
	mux.z[pattern] = muxEntry{h: handler, pattern: pattern}
	mux.m.Unlock()
	return nil
}

// DefaultHandle set default handler to the ServeMux
func (mux *ServeMux) DefaultHandle(handler Handler) {
	mux.m.Lock()
	mux.defaultHandler = handler
	mux.m.Unlock()
}

// HandleFunc adds a handler function to the ServeMux for pattern.
func (mux *ServeMux) HandleFunc(pattern string, handler func(w ResponseWriter, r *Request)) {
	mux.Handle(pattern, HandlerFunc(handler))
}

// DefaultHandleFunc set a default handler function to the ServeMux.
func (mux *ServeMux) DefaultHandleFunc(handler func(w ResponseWriter, r *Request)) {
	mux.DefaultHandle(HandlerFunc(handler))
}

// HandleRemove deregistrars the handler specific for pattern from the ServeMux.
func (mux *ServeMux) HandleRemove(pattern string) error {
  switch pattern {
    case "", "/":
     pattern = "/"
  }
	mux.m.Lock()
  defer mux.m.Unlock()
  if _, ok := mux.z[pattern]; ok {
    delete(mux.z, pattern)
    return nil
  }
	return errors.New("pattern is not registered in")
}

// ServeCOAP dispatches the request to the handler whose
// pattern most closely matches the request message. If DefaultServeMux
// is used the correct thing for DS queries is done: a possible parent
// is sought.
// If no handler is found a standard NotFound message is returned
func (mux *ServeMux) ServeCOAP(w ResponseWriter, r *Request) {
	h, _ := mux.match(r.Msg.PathString())
	if h == nil {
		h = mux.defaultHandler
		if h == nil {
			h = failedHandler()
		}
	}
	h.ServeCOAP(w, r)
}

// Handle registers the handler with the given pattern
// in the DefaultServeMux. The documentation for
// ServeMux explains how patterns are matched.
func Handle(pattern string, handler Handler) { DefaultServeMux.Handle(pattern, handler) }

// HandleFunc registers the handler function with the given pattern
// in the DefaultServeMux.
func HandleFunc(pattern string, handler func(w ResponseWriter, r *Request)) {
	DefaultServeMux.HandleFunc(pattern, handler)
}

// HandleRemove deregisters the handle with the given pattern
// in the DefaultServeMux.
func HandleRemove(pattern string) { DefaultServeMux.HandleRemove(pattern) }

// DefaultHandle set the default handler in the DefaultServeMux.
func DefaultHandle(handler Handler) { DefaultServeMux.DefaultHandle(handler) }

// DefaultHandleFunc set the default handler in the DefaultServeMux.
func DefaultHandleFunc(handler func(w ResponseWriter, r *Request)) {
	DefaultServeMux.DefaultHandleFunc(handler)
}