import (
"context"
+ "fmt"
"net/http"
"strconv"
"sync"
type Web struct {
Server *http.Server
mux *http.ServeMux
- wrs sync.Map
- mode string
}
-func New(conf *http.Server) (o *Web) {
-
- o = new(Web)
+type WebSync struct {
+ Server *http.Server
+ mux *http.ServeMux
+ wrs *WebPath
+}
- o.mode = "simple"
- o.Server = conf
+type WebPath struct {
+ path string
+ f func(w http.ResponseWriter, r *http.Request)
+ sameP *WebPath
+ next *WebPath
+ l sync.RWMutex
+}
- if o.Server.Handler == nil {
- o.mux = http.NewServeMux()
- o.Server.Handler = o.mux
+func (t *WebPath) Load(path string) (func(w http.ResponseWriter, r *http.Request), bool) {
+ fmt.Println("l", t.path, path)
+ t.l.RLock()
+ if t.path == "" {
+ t.l.RUnlock()
+ return nil, false
+ } else if t.path == path {
+ t.l.RUnlock()
+ return t.f, true
+ } else if len(path) > len(t.path) && path[:len(t.path)] == t.path {
+ if t.path == "/" || path[len(t.path)] == '/' {
+ fmt.Println("-")
+ if t.sameP != nil {
+ if f, ok := t.sameP.Load(path); ok {
+ t.l.RUnlock()
+ return f, true
+ } else {
+ t.l.RUnlock()
+ return t.f, true
+ }
+ } else {
+ t.l.RUnlock()
+ return t.f, true
+ }
+ } else {
+ if t.next != nil {
+ t.l.RUnlock()
+ return t.next.Load(path)
+ } else {
+ t.l.RUnlock()
+ return nil, false
+ }
+ }
+ } else if t.next != nil {
+ t.l.RUnlock()
+ return t.next.Load(path)
+ } else {
+ t.l.RUnlock()
+ return nil, false
}
+}
- go o.Server.ListenAndServe()
-
- return
+func (t *WebPath) Store(path string, f func(w http.ResponseWriter, r *http.Request)) {
+ t.l.RLock()
+ if t.path == path || t.path == "" {
+ t.l.RUnlock()
+ t.l.Lock()
+ t.path = path
+ t.f = f
+ t.l.Unlock()
+ } else if len(path) > len(t.path) && path[:len(t.path)] == t.path {
+ if path[len(t.path)-1] == '/' {
+ if t.sameP != nil {
+ t.l.RUnlock()
+ t.sameP.Store(path, f)
+ } else {
+ t.l.RUnlock()
+ t.l.Lock()
+ t.sameP = &WebPath{
+ path: path,
+ f: f,
+ }
+ t.l.Unlock()
+ }
+ } else {
+ if t.next != nil {
+ t.l.RUnlock()
+ t.l.Lock()
+ tmp := WebPath{path: t.path, f: t.f, sameP: t.sameP, next: t.next}
+ t.path = path
+ t.f = f
+ t.next = &tmp
+ t.l.Unlock()
+ } else {
+ t.l.RUnlock()
+ t.l.Lock()
+ t.next = &WebPath{
+ path: path,
+ f: f,
+ }
+ t.l.Unlock()
+ }
+ }
+ } else if len(path) < len(t.path) && t.path[:len(path)] == path {
+ t.l.RUnlock()
+ t.l.Lock()
+ tmp := WebPath{path: t.path, f: t.f, sameP: t.sameP, next: t.next}
+ t.path = path
+ t.f = f
+ t.sameP = &tmp
+ t.l.Unlock()
+ } else if t.next != nil {
+ t.l.RUnlock()
+ t.next.Store(path, f)
+ } else {
+ t.l.RUnlock()
+ t.l.Lock()
+ t.next = &WebPath{
+ path: path,
+ f: f,
+ }
+ t.l.Unlock()
+ }
}
-func NewSync(conf *http.Server) (o *Web) {
+func New(conf *http.Server) (o *Web) {
o = new(Web)
- o.mode = "sync"
o.Server = conf
if o.Server.Handler == nil {
go o.Server.ListenAndServe()
- o.mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
- if wr, ok := o.wrs.Load(r.URL.Path); ok {
- if f, ok := wr.(func(http.ResponseWriter, *http.Request)); ok {
- f(w, r)
- }
- }
- })
-
return
}
-func NewSyncMap(conf *http.Server, m *sync.Map) (o *Web) {
+func NewSyncMap(conf *http.Server, m *WebPath) (o *WebSync) {
- o = new(Web)
+ o = new(WebSync)
- o.mode = "syncmap"
o.Server = conf
+ o.wrs = m
if o.Server.Handler == nil {
o.mux = http.NewServeMux()
go o.Server.ListenAndServe()
o.mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
- if wr, ok := m.Load(r.URL.Path); ok {
- if f, ok := wr.(func(http.ResponseWriter, *http.Request)); ok {
- f(w, r)
- }
+ if f, ok := o.wrs.Load(r.URL.Path); ok {
+ f(w, r)
}
})
}
func (t *Web) Handle(path_func map[string]func(http.ResponseWriter, *http.Request)) {
- if t.mode != "simple" {
- panic("必须是New创建的")
- }
for k, v := range path_func {
t.mux.HandleFunc(k, v)
}
}
-func (t *Web) HandleSync(path string, path_func func(http.ResponseWriter, *http.Request)) {
- if t.mode != "sync" {
- panic("必须是NewSync创建的")
- }
- t.wrs.Store(path, path_func)
-}
-
func Easy_boot() *Web {
s := New(&http.Server{
Addr: "127.0.0.1:" + strconv.Itoa(sys.Sys().GetFreePort()),
package part
import (
+ "encoding/json"
"net/http"
"strconv"
- "sync"
"testing"
"time"
)
time.Sleep(time.Second * time.Duration(100))
}
-func Test_ServerSync(t *testing.T) {
- s := NewSync(&http.Server{
- Addr: "127.0.0.1:9090",
+func Test_ServerSyncMap(t *testing.T) {
+ var m WebPath
+ m.Store("/", func(w http.ResponseWriter, r *http.Request) {
+ w.Write([]byte("1"))
})
+ NewSyncMap(&http.Server{
+ Addr: "127.0.0.1:9090",
+ }, &m)
for i := 0; i < 20; i++ {
time.Sleep(time.Second)
- s.HandleSync("/1", func(w http.ResponseWriter, r *http.Request) {
- w.Write([]byte(strconv.Itoa(i)))
+ m.Store("/1", func(w http.ResponseWriter, r *http.Request) {
+
+ type d struct {
+ A string `json:"a"`
+ B []string `json:"b"`
+ C map[string]int `json:"c"`
+ }
+
+ t := strconv.Itoa(i)
+
+ ResStruct{0, "ok", d{t, []string{t}, map[string]int{t: 1}}}.Write(w)
})
}
}
-func Test_ServerSyncMap(t *testing.T) {
- var m sync.Map
+func BenchmarkXxx(b *testing.B) {
+ var m WebPath
+ type d struct {
+ A string `json:"path"`
+ }
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ m.Store("/", func(w http.ResponseWriter, r *http.Request) {
+ ResStruct{0, "ok", d{"/"}}.Write(w)
+ })
+ }
+}
+
+func Test_ServerSyncMapP(t *testing.T) {
+ var m WebPath
+ type d struct {
+ A string `json:"path"`
+ }
m.Store("/", func(w http.ResponseWriter, r *http.Request) {
- w.Write([]byte("1"))
+ ResStruct{0, "ok", d{"/"}}.Write(w)
+ })
+ m.Store("/1", func(w http.ResponseWriter, r *http.Request) {
+ ResStruct{0, "ok", d{"/1"}}.Write(w)
})
+ m.Store("/2", func(w http.ResponseWriter, r *http.Request) {
+ ResStruct{0, "ok", d{"/2"}}.Write(w)
+ })
+
NewSyncMap(&http.Server{
Addr: "127.0.0.1:9090",
}, &m)
- for i := 0; i < 20; i++ {
- time.Sleep(time.Second)
- m.Store("/1", func(w http.ResponseWriter, r *http.Request) {
- t.Log(r.URL.Path)
- t.Log(r.URL.EscapedPath())
- w.Write([]byte(strconv.Itoa(i)))
- })
+
+ time.Sleep(time.Second * time.Duration(23))
+}
+
+type ResStruct struct {
+ Code int `json:"code"`
+ Message string `json:"message"`
+ Data any `json:"data"`
+}
+
+func (t ResStruct) Write(w http.ResponseWriter) {
+ w.Header().Set("Content-Type", "application/json")
+ data, e := json.Marshal(t)
+ if e != nil {
+ t.Code = -1
+ t.Data = nil
+ t.Message = e.Error()
+ data, _ = json.Marshal(t)
}
+ w.Write(data)
}