From f74b60e1d468980ca8f9f09eded6351f3a3c7efd Mon Sep 17 00:00:00 2001 From: c-wind Date: Sat, 16 Sep 2017 06:25:51 +0800 Subject: [PATCH 1/4] test --- Makefile | 2 +- handler/handler.go | 148 ++++++++++++++++++++++----------------------- main.go | 14 +++++ server/init.go | 10 ++- server/server.go | 28 ++++++--- v.go | 26 ++++++++ 6 files changed, 136 insertions(+), 92 deletions(-) create mode 100644 v.go diff --git a/Makefile b/Makefile index 57ce652..e521532 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ fmt: crab: - go build -o bin/$@ -ldflags '$(LDFLAGS)' ./main.go + go build -gcflags="-N -l" -o bin/$@ -ldflags '$(LDFLAGS)' ./main.go test: diff --git a/handler/handler.go b/handler/handler.go index ddb1d92..d0bcd51 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -18,10 +18,7 @@ var ( ) type server struct { - post map[string]iface - get map[string]iface - put map[string]iface - delete map[string]iface + path map[string]iface prefix *btree.BTree filter Filter mu sync.RWMutex @@ -29,26 +26,19 @@ type server struct { func newHTTPServer() *server { return &server{ - post: make(map[string]iface), - get: make(map[string]iface), - put: make(map[string]iface), - delete: make(map[string]iface), + path: make(map[string]iface), prefix: btree.New(3), filter: defaultFilter, } } -// Callback 用户接口 -type Callback func(http.ResponseWriter, *http.Request) - // Filter 请求过滤, 如果返回结果为nil,直接返回,不再进行后续处理. type Filter func(http.ResponseWriter, *http.Request) *http.Request -// iface 对外服务接口 +// iface 对外服务接口, path格式:Method/URI type iface struct { - method Method path string - call Callback + source reflect.Type } func (i *iface) Less(bi btree.Item) bool { @@ -73,31 +63,59 @@ func NameToPath(name string, depth int) string { } //AddInterface 自动注册接口 -//只要struct实现了DoGet(),DoPost(),DoDelete(),DoPut()接口就可以自动注册 -func (s *server) AddInterface(iface interface{}, path string) error { - rt := reflect.TypeOf(iface) +//只要struct实现了Get(),Post(),Delete(),Put()接口就可以自动注册 +func (s *server) AddInterface(obj interface{}, path string, isPrefix bool) error { + rt := reflect.TypeOf(obj) if rt.Kind() != reflect.Ptr { return fmt.Errorf("need ptr") } - rv := reflect.ValueOf(iface) + + if path == "" { + path = NameToPath(rt.String(), 0) + "/" + } + + if !strings.HasPrefix(path, "/") { + path = "/" + path + } + + s.mu.Lock() + defer s.mu.Unlock() + + rv := reflect.ValueOf(obj) for i := 0; i < rv.NumMethod(); i++ { - mt := rt.Method(i) - mv := rv.Method(i) - if path == "" { - path = NameToPath(rt.String(), 0) + "/" + method := rt.Method(i).Name + log.Debugf("rt:%v, %d, method:%v", rt, i, method) + switch method { + case POST.String(): + case GET.String(): + case PUT.String(): + case DELETE.String(): + default: + log.Debugf("ignore method:%v path:%v", method, path) + continue } - switch mt.Name { - case "DoPost": - s.AddHandler(POST, path, false, mv.Interface().(func(http.ResponseWriter, *http.Request))) - case "DoGet": - s.AddHandler(GET, path, false, mv.Interface().(func(http.ResponseWriter, *http.Request))) - case "DoPut": - s.AddHandler(PUT, path, false, mv.Interface().(func(http.ResponseWriter, *http.Request))) - case "DoDelete": - s.AddHandler(DELETE, path, false, mv.Interface().(func(http.ResponseWriter, *http.Request))) + ifc := iface{ + path: fmt.Sprintf("%v%v", method, path), + source: rt.Elem(), } - log.Debugf("%v %v", mt.Name, path) + + //前缀匹配 + if isPrefix { + if s.prefix.Has(&ifc) { + panic(fmt.Sprintf("exist url:%v %v", method, path)) + } + s.prefix.ReplaceOrInsert(&ifc) + log.Debugf("add prefix:%v", path) + continue + } + + //全路径匹配 + if _, ok := s.path[ifc.path]; ok { + panic(fmt.Sprintf("exist url:%v %v", method, path)) + } + + s.path[ifc.path] = ifc } return nil @@ -110,60 +128,26 @@ func (s *server) AddFilter(filter Filter) { s.filter = filter } -//AddHandler 注册接口 -func (s *server) AddHandler(method Method, path string, isPrefix bool, call Callback) { - s.mu.Lock() - defer s.mu.Unlock() - - i := iface{method, path, call} - if isPrefix { - s.prefix.ReplaceOrInsert(&i) - } - - var ms map[string]iface - switch method { - case GET: - ms = s.get - case POST: - ms = s.post - case PUT: - ms = s.put - case DELETE: - ms = s.delete - } - - if _, ok := ms[path]; ok { - panic(fmt.Sprintf("exist url:%v %v", method, path)) - } - - ms[path] = i -} - func (s *server) iface(w http.ResponseWriter, r *http.Request) (i iface, ok bool) { s.mu.RLock() defer s.mu.RUnlock() - switch r.Method { - case "GET": - i, ok = s.get[r.URL.Path] - case "POST": - i, ok = s.post[r.URL.Path] - case "PUT": - i, ok = s.put[r.URL.Path] - case "DELETE": - i, ok = s.delete[r.URL.Path] - } + path := r.Method + r.URL.Path - if ok { + if i, ok = s.path[path]; ok { + log.Debugf("find path:%v", path) return } //如果完全匹配没找到,再找前缀的 - s.prefix.AscendGreaterOrEqual(&iface{path: r.URL.Path}, func(item btree.Item) bool { + s.prefix.AscendGreaterOrEqual(&iface{path: path}, func(item btree.Item) bool { i = *(item.(*iface)) - ok = strings.HasPrefix(r.URL.Path, i.path) + ok = strings.HasPrefix(path, i.path) + log.Debugf("path:%v, ipath:%v, ok:%v", path, i.path, ok) return !ok }) + + log.Debugf("find prefix:%v, ok:%v", path, ok) return } @@ -189,9 +173,23 @@ func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { SendResponse(w, http.StatusNotFound, "invalid request") return } + log.Debugf("%v %v %v %v", r.RemoteAddr, r.Method, r.URL, i.path) - i.call(w, nr) + for j:=0; j<10; j++ { + fmt.Printf("========%p\n", reflect.New(i.source).Interface()) + log.Debugf("new:%p", reflect.New(i.source).Interface()) + } + + newObj := reflect.New(i.source) + fmt.Printf("obj:%p\n", newObj) + method := newObj.MethodByName(r.Method) + callback := method.Interface().(func(http.ResponseWriter, *http.Request)) + +// callback := .MethodByName(r.Method).Interface() + + callback(w, nr) + return } diff --git a/main.go b/main.go index badadf0..c002b7e 100644 --- a/main.go +++ b/main.go @@ -2,13 +2,25 @@ package main import ( "flag" + "fmt" "net" "net/http" + "time" "github.com/dearcode/crab/handler" _ "github.com/dearcode/crab/server" ) +type index struct { +} + +func (i *index) GET(w http.ResponseWriter, req *http.Request) { + fmt.Printf("index:%p\n", i) + w.Write([]byte("ok")) + time.Sleep(time.Minute) + +} + func main() { addr := flag.String("h", ":9000", "api listen address") flag.Parse() @@ -18,6 +30,8 @@ func main() { panic(err.Error()) } + handler.Server.AddInterface(&index{}, "/index", false) + if err = http.Serve(ln, handler.Server); err != nil { panic(err.Error()) } diff --git a/server/init.go b/server/init.go index 21a7f39..928e2ad 100644 --- a/server/init.go +++ b/server/init.go @@ -5,12 +5,10 @@ import ( ) func init() { - handler.Server.AddHandler(handler.GET, "/", true, onStaticGet) - handler.Server.AddHandler(handler.GET, "/debug/", true, onDebugGet) + handler.Server.AddInterface(&staticServer{}, "/", true) + handler.Server.AddInterface(&debugServer{}, "/debug/", true) - handler.Server.AddHandler(handler.GET, "/test/", false, onTestGet) - handler.Server.AddHandler(handler.POST, "/test/", false, onTestPost) - handler.Server.AddHandler(handler.DELETE, "/test/", false, onTestDelete) + handler.Server.AddInterface(&testServer{}, "/test/", false) - handler.Server.AddInterface(&user{}, "") + handler.Server.AddInterface(&user{}, "", false) } diff --git a/server/server.go b/server/server.go index 3b146ae..e942fa7 100644 --- a/server/server.go +++ b/server/server.go @@ -6,29 +6,37 @@ import ( "net/http/pprof" ) -//onTestGet 获取配置文件中域名 -func onTestGet(w http.ResponseWriter, r *http.Request) { +type testServer struct { +} + +func (s *testServer) GET(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Get test")) } -//onTestPost 获取配置文件中域名 -func onTestPost(w http.ResponseWriter, r *http.Request) { +func (s *testServer) POST(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Post test")) } -//onTestDelete 获取配置文件中域名 -func onTestDelete(w http.ResponseWriter, r *http.Request) { +func (s *testServer) PUT(w http.ResponseWriter, r *http.Request) { + w.Write([]byte("Put test")) +} + +func (s *testServer) DELETE(w http.ResponseWriter, r *http.Request) { w.Write([]byte("Delete test")) } -//onStaticGet 静态文件 -func onStaticGet(w http.ResponseWriter, r *http.Request) { +type staticServer struct { +} + +func (s *staticServer) GET(w http.ResponseWriter, r *http.Request) { path := fmt.Sprintf("/var/www/html/%s", r.URL.Path) w.Header().Add("Cache-control", "no-store") http.ServeFile(w, r, path) } -//onDebugGet debug接口 -func onDebugGet(w http.ResponseWriter, r *http.Request) { +type debugServer struct { +} + +func (s *debugServer) GET(w http.ResponseWriter, r *http.Request) { pprof.Index(w, r) } diff --git a/v.go b/v.go new file mode 100644 index 0000000..e20e0c4 --- /dev/null +++ b/v.go @@ -0,0 +1,26 @@ +package main + +import ( + "fmt" + "reflect" +) + +type testServer struct { + A int +} + +func test(t reflect.Type) { + for i := 0; i < 10; i++ { + fmt.Printf("new:%p\n", reflect.New(t).Interface()) + } +} + +func main() { + t := &testServer{} + + tt := reflect.TypeOf(t) + + test(tt.Elem()) + + +} From 587fb5d6ad2d8ac963454885055d47efadb126db Mon Sep 17 00:00:00 2001 From: c-wind Date: Mon, 18 Sep 2017 20:59:31 +0800 Subject: [PATCH 2/4] ok --- Makefile | 2 +- handler/handler.go | 19 ++++--------------- main.go | 9 ++++++--- v.go | 26 -------------------------- 4 files changed, 11 insertions(+), 45 deletions(-) delete mode 100644 v.go diff --git a/Makefile b/Makefile index e521532..57ce652 100644 --- a/Makefile +++ b/Makefile @@ -24,7 +24,7 @@ fmt: crab: - go build -gcflags="-N -l" -o bin/$@ -ldflags '$(LDFLAGS)' ./main.go + go build -o bin/$@ -ldflags '$(LDFLAGS)' ./main.go test: diff --git a/handler/handler.go b/handler/handler.go index d0bcd51..02de844 100644 --- a/handler/handler.go +++ b/handler/handler.go @@ -135,7 +135,7 @@ func (s *server) iface(w http.ResponseWriter, r *http.Request) (i iface, ok bool path := r.Method + r.URL.Path if i, ok = s.path[path]; ok { - log.Debugf("find path:%v", path) + //log.Debugf("find path:%v", path) return } @@ -143,11 +143,11 @@ func (s *server) iface(w http.ResponseWriter, r *http.Request) (i iface, ok bool s.prefix.AscendGreaterOrEqual(&iface{path: path}, func(item btree.Item) bool { i = *(item.(*iface)) ok = strings.HasPrefix(path, i.path) - log.Debugf("path:%v, ipath:%v, ok:%v", path, i.path, ok) + // log.Debugf("path:%v, ipath:%v, ok:%v", path, i.path, ok) return !ok }) - log.Debugf("find prefix:%v, ok:%v", path, ok) +// log.Debugf("find prefix:%v, ok:%v", path, ok) return } @@ -176,18 +176,7 @@ func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { log.Debugf("%v %v %v %v", r.RemoteAddr, r.Method, r.URL, i.path) - for j:=0; j<10; j++ { - fmt.Printf("========%p\n", reflect.New(i.source).Interface()) - log.Debugf("new:%p", reflect.New(i.source).Interface()) - } - - newObj := reflect.New(i.source) - fmt.Printf("obj:%p\n", newObj) - method := newObj.MethodByName(r.Method) - callback := method.Interface().(func(http.ResponseWriter, *http.Request)) - -// callback := .MethodByName(r.Method).Interface() - + callback := reflect.New(i.source).MethodByName(r.Method).Interface().(func(http.ResponseWriter, *http.Request)) callback(w, nr) return diff --git a/main.go b/main.go index c002b7e..7f456ff 100644 --- a/main.go +++ b/main.go @@ -5,20 +5,23 @@ import ( "fmt" "net" "net/http" - "time" "github.com/dearcode/crab/handler" _ "github.com/dearcode/crab/server" ) type index struct { + r *http.Request +} + +func test(r *http.Request) { + fmt.Printf("%v\n", r.RemoteAddr) } func (i *index) GET(w http.ResponseWriter, req *http.Request) { fmt.Printf("index:%p\n", i) + test(req) w.Write([]byte("ok")) - time.Sleep(time.Minute) - } func main() { diff --git a/v.go b/v.go deleted file mode 100644 index e20e0c4..0000000 --- a/v.go +++ /dev/null @@ -1,26 +0,0 @@ -package main - -import ( - "fmt" - "reflect" -) - -type testServer struct { - A int -} - -func test(t reflect.Type) { - for i := 0; i < 10; i++ { - fmt.Printf("new:%p\n", reflect.New(t).Interface()) - } -} - -func main() { - t := &testServer{} - - tt := reflect.TypeOf(t) - - test(tt.Elem()) - - -} From 0b1d8655c94fbd841057d65be0b534d3314a1c22 Mon Sep 17 00:00:00 2001 From: c-wind Date: Sat, 16 Sep 2017 07:46:27 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E6=8B=86=E5=88=86http=E7=9A=84server,clien?= =?UTF-8?q?t?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- {http_client => http/client}/client.go | 2 +- {handler => http/server}/common.go | 2 +- {handler => http/server}/handler.go | 77 ++++++++++++++------------ {handler => http/server}/vars.go | 2 +- {handler => http/server}/vars_test.go | 2 +- main.go | 18 ++---- server/init.go | 10 ++-- 7 files changed, 56 insertions(+), 57 deletions(-) rename {http_client => http/client}/client.go (99%) rename {handler => http/server}/common.go (99%) rename {handler => http/server}/handler.go (69%) rename {handler => http/server}/vars.go (99%) rename {handler => http/server}/vars_test.go (99%) diff --git a/http_client/client.go b/http/client/client.go similarity index 99% rename from http_client/client.go rename to http/client/client.go index c9b7d99..fa94754 100644 --- a/http_client/client.go +++ b/http/client/client.go @@ -1,4 +1,4 @@ -package httpClient +package client import ( "bytes" diff --git a/handler/common.go b/http/server/common.go similarity index 99% rename from handler/common.go rename to http/server/common.go index 0255813..1e7bc1e 100644 --- a/handler/common.go +++ b/http/server/common.go @@ -1,4 +1,4 @@ -package handler +package server import ( "encoding/json" diff --git a/handler/handler.go b/http/server/handler.go similarity index 69% rename from handler/handler.go rename to http/server/handler.go index 02de844..1aa4e5b 100644 --- a/handler/handler.go +++ b/http/server/handler.go @@ -1,7 +1,8 @@ -package handler +package server import ( "fmt" + "net" "net/http" "reflect" "runtime/debug" @@ -13,19 +14,24 @@ import ( ) var ( - //Server 默认服务 - Server = newHTTPServer() + server = newHTTPServer() ) -type server struct { +// iface 对外服务接口, path格式:Method/URI +type iface struct { + path string + source reflect.Type +} + +type httpServer struct { path map[string]iface prefix *btree.BTree filter Filter - mu sync.RWMutex + sync.RWMutex } -func newHTTPServer() *server { - return &server{ +func newHTTPServer() *httpServer { + return &httpServer{ path: make(map[string]iface), prefix: btree.New(3), filter: defaultFilter, @@ -35,12 +41,6 @@ func newHTTPServer() *server { // Filter 请求过滤, 如果返回结果为nil,直接返回,不再进行后续处理. type Filter func(http.ResponseWriter, *http.Request) *http.Request -// iface 对外服务接口, path格式:Method/URI -type iface struct { - path string - source reflect.Type -} - func (i *iface) Less(bi btree.Item) bool { return strings.Compare(i.path, bi.(*iface).path) == 1 } @@ -64,7 +64,7 @@ func NameToPath(name string, depth int) string { //AddInterface 自动注册接口 //只要struct实现了Get(),Post(),Delete(),Put()接口就可以自动注册 -func (s *server) AddInterface(obj interface{}, path string, isPrefix bool) error { +func AddInterface(obj interface{}, path string, isPrefix bool) error { rt := reflect.TypeOf(obj) if rt.Kind() != reflect.Ptr { return fmt.Errorf("need ptr") @@ -78,13 +78,13 @@ func (s *server) AddInterface(obj interface{}, path string, isPrefix bool) error path = "/" + path } - s.mu.Lock() - defer s.mu.Unlock() + server.Lock() + defer server.Unlock() rv := reflect.ValueOf(obj) for i := 0; i < rv.NumMethod(); i++ { method := rt.Method(i).Name - log.Debugf("rt:%v, %d, method:%v", rt, i, method) + log.Debugf("rt:%v, %d, method:%v", rt, i, method) switch method { case POST.String(): case GET.String(): @@ -102,57 +102,57 @@ func (s *server) AddInterface(obj interface{}, path string, isPrefix bool) error //前缀匹配 if isPrefix { - if s.prefix.Has(&ifc) { + if server.prefix.Has(&ifc) { panic(fmt.Sprintf("exist url:%v %v", method, path)) } - s.prefix.ReplaceOrInsert(&ifc) - log.Debugf("add prefix:%v", path) + server.prefix.ReplaceOrInsert(&ifc) + log.Debugf("add prefix:%v", path) continue } //全路径匹配 - if _, ok := s.path[ifc.path]; ok { + if _, ok := server.path[ifc.path]; ok { panic(fmt.Sprintf("exist url:%v %v", method, path)) } - s.path[ifc.path] = ifc + server.path[ifc.path] = ifc } return nil } //AddFilter 添加过滤函数. -func (s *server) AddFilter(filter Filter) { - s.mu.Lock() - defer s.mu.Unlock() - s.filter = filter +func AddFilter(filter Filter) { + server.Lock() + defer server.Unlock() + server.filter = filter } -func (s *server) iface(w http.ResponseWriter, r *http.Request) (i iface, ok bool) { - s.mu.RLock() - defer s.mu.RUnlock() +func getInterface(w http.ResponseWriter, r *http.Request) (i iface, ok bool) { + server.RLock() + defer server.RUnlock() path := r.Method + r.URL.Path - if i, ok = s.path[path]; ok { + if i, ok = server.path[path]; ok { //log.Debugf("find path:%v", path) return } //如果完全匹配没找到,再找前缀的 - s.prefix.AscendGreaterOrEqual(&iface{path: path}, func(item btree.Item) bool { + server.prefix.AscendGreaterOrEqual(&iface{path: path}, func(item btree.Item) bool { i = *(item.(*iface)) ok = strings.HasPrefix(path, i.path) - // log.Debugf("path:%v, ipath:%v, ok:%v", path, i.path, ok) + // log.Debugf("path:%v, ipath:%v, ok:%v", path, i.path, ok) return !ok }) -// log.Debugf("find prefix:%v, ok:%v", path, ok) + // log.Debugf("find prefix:%v, ok:%v", path, ok) return } //ServeHTTP 真正对外服务接口 -func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { +func (s *httpServer) ServeHTTP(w http.ResponseWriter, r *http.Request) { defer func() { if p := recover(); p != nil { log.Errorf("panic:%v req:%v, stack:%s", p, r, debug.Stack()) @@ -167,7 +167,7 @@ func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { return } - i, ok := s.iface(w, r) + i, ok := getInterface(w, r) if !ok { log.Errorf("%v %v %v not found.", r.RemoteAddr, r.Method, r.URL) SendResponse(w, http.StatusNotFound, "invalid request") @@ -176,7 +176,7 @@ func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { log.Debugf("%v %v %v %v", r.RemoteAddr, r.Method, r.URL, i.path) - callback := reflect.New(i.source).MethodByName(r.Method).Interface().(func(http.ResponseWriter, *http.Request)) + callback := reflect.New(i.source).MethodByName(r.Method).Interface().(func(http.ResponseWriter, *http.Request)) callback(w, nr) return @@ -185,3 +185,8 @@ func (s *server) ServeHTTP(w http.ResponseWriter, r *http.Request) { func defaultFilter(_ http.ResponseWriter, r *http.Request) *http.Request { return r } + +//Start 启动httpServer. +func Start(l net.Listener) error { + return http.Serve(l, server) +} diff --git a/handler/vars.go b/http/server/vars.go similarity index 99% rename from handler/vars.go rename to http/server/vars.go index 5d7f067..4b2c1ba 100644 --- a/handler/vars.go +++ b/http/server/vars.go @@ -1,4 +1,4 @@ -package handler +package server import ( "encoding/json" diff --git a/handler/vars_test.go b/http/server/vars_test.go similarity index 99% rename from handler/vars_test.go rename to http/server/vars_test.go index 7c2bca9..3b99f4f 100644 --- a/handler/vars_test.go +++ b/http/server/vars_test.go @@ -1,4 +1,4 @@ -package handler +package server import ( "bytes" diff --git a/main.go b/main.go index 7f456ff..1fa3288 100644 --- a/main.go +++ b/main.go @@ -6,22 +6,17 @@ import ( "net" "net/http" - "github.com/dearcode/crab/handler" + "github.com/dearcode/crab/http/server" _ "github.com/dearcode/crab/server" ) type index struct { - r *http.Request -} - -func test(r *http.Request) { - fmt.Printf("%v\n", r.RemoteAddr) + r *http.Request } func (i *index) GET(w http.ResponseWriter, req *http.Request) { - fmt.Printf("index:%p\n", i) - test(req) - w.Write([]byte("ok")) + i.r = req + w.Write([]byte(fmt.Sprintf("client:%v addr:%p", i.r.RemoteAddr, i))) } func main() { @@ -33,9 +28,8 @@ func main() { panic(err.Error()) } - handler.Server.AddInterface(&index{}, "/index", false) - - if err = http.Serve(ln, handler.Server); err != nil { + server.AddInterface(&index{}, "/index", false) + if err = server.Start(ln); err != nil { panic(err.Error()) } } diff --git a/server/init.go b/server/init.go index 928e2ad..0816cd2 100644 --- a/server/init.go +++ b/server/init.go @@ -1,14 +1,14 @@ package server import ( - "github.com/dearcode/crab/handler" + "github.com/dearcode/crab/http/server" ) func init() { - handler.Server.AddInterface(&staticServer{}, "/", true) - handler.Server.AddInterface(&debugServer{}, "/debug/", true) + server.AddInterface(&staticServer{}, "/", true) + server.AddInterface(&debugServer{}, "/debug/", true) - handler.Server.AddInterface(&testServer{}, "/test/", false) + server.AddInterface(&testServer{}, "/test/", false) - handler.Server.AddInterface(&user{}, "", false) + server.AddInterface(&user{}, "", false) } From 5e4ee5317ca898abff2282018918a38d841295ba Mon Sep 17 00:00:00 2001 From: c-wind Date: Sat, 16 Sep 2017 08:27:27 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9http=20client=E7=BB=93?= =?UTF-8?q?=E6=9E=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- http/client/client.go | 21 ++++++++------------- http/server/handler.go | 36 ++++++++++++++++++++++++++++-------- main.go | 27 ++++++++++++++++++++------- 3 files changed, 56 insertions(+), 28 deletions(-) diff --git a/http/client/client.go b/http/client/client.go index fa94754..99ca10f 100644 --- a/http/client/client.go +++ b/http/client/client.go @@ -11,14 +11,13 @@ import ( "github.com/zssky/log" ) -//Client 对http client简单封装. -type Client struct { +type httpClient struct { hc http.Client } //NewClient 创建一个带超时控制的http client. -func NewClient(timeout time.Duration) Client { - return Client{ +func New(timeout time.Duration) httpClient { + return httpClient{ hc: http.Client{ Transport: &http.Transport{ Dial: func(netw, addr string) (net.Conn, error) { @@ -39,7 +38,7 @@ func NewClient(timeout time.Duration) Client { } } -func (c Client) do(method, url string, headers map[string]string, body *bytes.Buffer) ([]byte, int, error) { +func (c httpClient) do(method, url string, headers map[string]string, body *bytes.Buffer) ([]byte, int, error) { var req *http.Request var err error @@ -72,22 +71,18 @@ func (c Client) do(method, url string, headers map[string]string, body *bytes.Bu return data, resp.StatusCode, nil } -//Get get 请求... -func (c Client) Get(url string, headers map[string]string, body *bytes.Buffer) ([]byte, int, error) { +func (c httpClient) Get(url string, headers map[string]string, body *bytes.Buffer) ([]byte, int, error) { return c.do("GET", url, headers, body) } -//POST post 请求. -func (c Client) POST(url string, headers map[string]string, body *bytes.Buffer) ([]byte, int, error) { +func (c httpClient) POST(url string, headers map[string]string, body *bytes.Buffer) ([]byte, int, error) { return c.do("POST", url, headers, body) } -//PUT put 请求. -func (c Client) PUT(url string, headers map[string]string, body *bytes.Buffer) ([]byte, int, error) { +func (c httpClient) PUT(url string, headers map[string]string, body *bytes.Buffer) ([]byte, int, error) { return c.do("PUT", url, headers, body) } -//DELETE delete 请求. -func (c Client) DELETE(url string, headers map[string]string, body *bytes.Buffer) ([]byte, int, error) { +func (c httpClient) DELETE(url string, headers map[string]string, body *bytes.Buffer) ([]byte, int, error) { return c.do("DELETE", url, headers, body) } diff --git a/http/server/handler.go b/http/server/handler.go index 1aa4e5b..66bd3e6 100644 --- a/http/server/handler.go +++ b/http/server/handler.go @@ -10,6 +10,7 @@ import ( "sync" "github.com/google/btree" + "github.com/juju/errors" "github.com/zssky/log" ) @@ -24,9 +25,10 @@ type iface struct { } type httpServer struct { - path map[string]iface - prefix *btree.BTree - filter Filter + path map[string]iface + prefix *btree.BTree + filter Filter + listener net.Listener sync.RWMutex } @@ -84,14 +86,14 @@ func AddInterface(obj interface{}, path string, isPrefix bool) error { rv := reflect.ValueOf(obj) for i := 0; i < rv.NumMethod(); i++ { method := rt.Method(i).Name - log.Debugf("rt:%v, %d, method:%v", rt, i, method) + //log.Debugf("rt:%v, %d, method:%v", rt, i, method) switch method { case POST.String(): case GET.String(): case PUT.String(): case DELETE.String(): default: - log.Debugf("ignore method:%v path:%v", method, path) + log.Warnf("ignore %v %v %v", method, path, rt) continue } @@ -106,7 +108,7 @@ func AddInterface(obj interface{}, path string, isPrefix bool) error { panic(fmt.Sprintf("exist url:%v %v", method, path)) } server.prefix.ReplaceOrInsert(&ifc) - log.Debugf("add prefix:%v", path) + log.Infof("add prefix %v %v %v", method, path, rt) continue } @@ -116,6 +118,7 @@ func AddInterface(obj interface{}, path string, isPrefix bool) error { } server.path[ifc.path] = ifc + log.Infof("add path %v %v %v", method, path, rt) } return nil @@ -187,6 +190,23 @@ func defaultFilter(_ http.ResponseWriter, r *http.Request) *http.Request { } //Start 启动httpServer. -func Start(l net.Listener) error { - return http.Serve(l, server) +func Start(addr string) error { + ln, err := net.Listen("tcp", addr) + if err != nil { + return errors.Trace(err) + } + + server.Lock() + server.listener = ln + server.Unlock() + + return http.Serve(ln, server) +} + +//Stop 停止httpServer监听, 进行中的任务并不会因此而停止. +func Stop() error { + server.Lock() + defer server.Unlock() + + return server.listener.Close() } diff --git a/main.go b/main.go index 1fa3288..c343a7b 100644 --- a/main.go +++ b/main.go @@ -3,9 +3,10 @@ package main import ( "flag" "fmt" - "net" "net/http" + "time" + "github.com/dearcode/crab/http/client" "github.com/dearcode/crab/http/server" _ "github.com/dearcode/crab/server" ) @@ -19,17 +20,29 @@ func (i *index) GET(w http.ResponseWriter, req *http.Request) { w.Write([]byte(fmt.Sprintf("client:%v addr:%p", i.r.RemoteAddr, i))) } -func main() { - addr := flag.String("h", ":9000", "api listen address") - flag.Parse() - - ln, err := net.Listen("tcp", *addr) +func testHTTPClient() { + url := "http://127.0.0.1:9000/index" + buf, _, err := client.New(time.Second).Get(url, nil, nil) if err != nil { panic(err.Error()) } + fmt.Printf("response:%s\n", buf) +} + +func main() { + addr := flag.String("h", ":9000", "api listen address") + flag.Parse() server.AddInterface(&index{}, "/index", false) - if err = server.Start(ln); err != nil { + + go func() { + for i := 0; i < 5; i++ { + time.Sleep(time.Second) + testHTTPClient() + } + }() + + if err := server.Start(*addr); err != nil { panic(err.Error()) } }