From 4b1413ce9ed796c7d56874b27c3eca780f89c39d Mon Sep 17 00:00:00 2001 From: qydysky <32743305+qydysky@users.noreply.github.com> Date: Thu, 9 Feb 2023 02:44:59 +0800 Subject: [PATCH] Improve --- web/Web.go | 160 ++++++++++++++++++++++++++++++++++++------------ web/Web_test.go | 80 +++++++++++++++++++----- 2 files changed, 184 insertions(+), 56 deletions(-) diff --git a/web/Web.go b/web/Web.go index 4831e55..a467c63 100644 --- a/web/Web.go +++ b/web/Web.go @@ -2,6 +2,7 @@ package part import ( "context" + "fmt" "net/http" "strconv" "sync" @@ -13,32 +14,131 @@ import ( 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 { @@ -48,23 +148,15 @@ func NewSync(conf *http.Server) (o *Web) { 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() @@ -74,10 +166,8 @@ func NewSyncMap(conf *http.Server, m *sync.Map) (o *Web) { 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) } }) @@ -85,21 +175,11 @@ func NewSyncMap(conf *http.Server, m *sync.Map) (o *Web) { } 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()), diff --git a/web/Web_test.go b/web/Web_test.go index 520c3d4..ec557c5 100644 --- a/web/Web_test.go +++ b/web/Web_test.go @@ -1,9 +1,9 @@ package part import ( + "encoding/json" "net/http" "strconv" - "sync" "testing" "time" ) @@ -14,32 +14,80 @@ func Test_Server(t *testing.T) { 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) } -- 2.39.2