server.go 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362
  1. package xweb
  2. import (
  3. "crypto/tls"
  4. "fmt"
  5. "net"
  6. "net/http"
  7. "net/http/pprof"
  8. "os"
  9. "qfw/util/endless"
  10. "runtime"
  11. runtimePprof "runtime/pprof"
  12. "strconv"
  13. "strings"
  14. "time"
  15. "github.com/go-xweb/httpsession"
  16. "github.com/go-xweb/log"
  17. )
  18. // ServerConfig is configuration for server objects.
  19. type ServerConfig struct {
  20. Addr string
  21. Port int
  22. RecoverPanic bool
  23. Profiler bool
  24. EnableGzip bool
  25. StaticExtensionsToGzip []string
  26. Url string
  27. UrlPrefix string
  28. UrlSuffix string
  29. StaticHtmlDir string
  30. SessionTimeout time.Duration
  31. }
  32. var ServerNumber uint = 0
  33. // Server represents a xweb server.
  34. type Server struct {
  35. Config *ServerConfig
  36. Apps map[string]*App
  37. AppsNamePath map[string]string
  38. Name string
  39. SessionManager *httpsession.Manager
  40. RootApp *App
  41. Logger *log.Logger
  42. Env map[string]interface{}
  43. //save the listener so it can be closed
  44. l net.Listener
  45. }
  46. func NewServer(args ...string) *Server {
  47. name := ""
  48. if len(args) == 1 {
  49. name = args[0]
  50. } else {
  51. name = fmt.Sprintf("Server%d", ServerNumber)
  52. ServerNumber++
  53. }
  54. s := &Server{
  55. Config: Config,
  56. Env: map[string]interface{}{},
  57. Apps: map[string]*App{},
  58. AppsNamePath: map[string]string{},
  59. Name: name,
  60. }
  61. Servers[s.Name] = s
  62. s.SetLogger(log.New(os.Stdout, "", log.Ldefault()))
  63. app := NewApp("/", "root")
  64. s.AddApp(app)
  65. return s
  66. }
  67. func (s *Server) AddApp(a *App) {
  68. a.BasePath = strings.TrimRight(a.BasePath, "/") + "/"
  69. s.Apps[a.BasePath] = a
  70. if a.Name != "" {
  71. s.AppsNamePath[a.Name] = a.BasePath
  72. }
  73. a.Server = s
  74. a.Logger = s.Logger
  75. if a.BasePath == "/" {
  76. s.RootApp = a
  77. }
  78. }
  79. func (s *Server) AddAction(cs ...interface{}) {
  80. s.RootApp.AddAction(cs...)
  81. }
  82. func (s *Server) AutoAction(c ...interface{}) {
  83. s.RootApp.AutoAction(c...)
  84. }
  85. func (s *Server) AddRouter(url string, c interface{}) {
  86. s.RootApp.AddRouter(url, c)
  87. }
  88. func (s *Server) AddTmplVar(name string, varOrFun interface{}) {
  89. s.RootApp.AddTmplVar(name, varOrFun)
  90. }
  91. func (s *Server) AddTmplVars(t *T) {
  92. s.RootApp.AddTmplVars(t)
  93. }
  94. func (s *Server) AddFilter(filter Filter) {
  95. s.RootApp.AddFilter(filter)
  96. }
  97. func (s *Server) AddConfig(name string, value interface{}) {
  98. s.RootApp.SetConfig(name, value)
  99. }
  100. func (s *Server) SetConfig(name string, value interface{}) {
  101. s.RootApp.SetConfig(name, value)
  102. }
  103. func (s *Server) GetConfig(name string) interface{} {
  104. return s.RootApp.GetConfig(name)
  105. }
  106. func (s *Server) error(w http.ResponseWriter, status int, content string) error {
  107. return s.RootApp.error(w, status, content)
  108. }
  109. func (s *Server) initServer() {
  110. if s.Config == nil {
  111. s.Config = &ServerConfig{}
  112. s.Config.Profiler = true
  113. }
  114. for _, app := range s.Apps {
  115. app.initApp()
  116. }
  117. }
  118. // ServeHTTP is the interface method for Go's http server package
  119. func (s *Server) ServeHTTP(c http.ResponseWriter, req *http.Request) {
  120. s.Process(c, req)
  121. }
  122. // Process invokes the routing system for server s
  123. // non-root app's route will override root app's if there is same path
  124. func (s *Server) Process(w http.ResponseWriter, req *http.Request) {
  125. var result bool = true
  126. _, _ = XHook.Call("BeforeProcess", &result, s, w, req)
  127. if !result {
  128. return
  129. }
  130. if s.Config.UrlSuffix != "" && strings.HasSuffix(req.URL.Path, s.Config.UrlSuffix) {
  131. req.URL.Path = strings.TrimSuffix(req.URL.Path, s.Config.UrlSuffix)
  132. }
  133. if s.Config.UrlPrefix != "" && strings.HasPrefix(req.URL.Path, "/"+s.Config.UrlPrefix) {
  134. req.URL.Path = strings.TrimPrefix(req.URL.Path, "/"+s.Config.UrlPrefix)
  135. }
  136. if req.URL.Path[0] != '/' {
  137. req.URL.Path = "/" + req.URL.Path
  138. }
  139. for _, app := range s.Apps {
  140. if app != s.RootApp && strings.HasPrefix(req.URL.Path, app.BasePath) {
  141. app.routeHandler(req, w)
  142. return
  143. }
  144. }
  145. s.RootApp.routeHandler(req, w)
  146. _, _ = XHook.Call("AfterProcess", &result, s, w, req)
  147. }
  148. // Run starts the web application and serves HTTP requests for s
  149. func (s *Server) RunBase(addr string, mux *http.ServeMux) {
  150. addrs := strings.Split(addr, ":")
  151. s.Config.Addr = addrs[0]
  152. s.Config.Port, _ = strconv.Atoi(addrs[1])
  153. s.initServer()
  154. //mux := http.NewServeMux()
  155. if s.Config.Profiler {
  156. mux.Handle("/debug/pprof", http.HandlerFunc(pprof.Index))
  157. mux.Handle("/debug/pprof/heap", pprof.Handler("heap"))
  158. mux.Handle("/debug/pprof/block", pprof.Handler("block"))
  159. mux.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine"))
  160. mux.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate"))
  161. mux.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
  162. mux.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
  163. mux.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
  164. mux.Handle("/debug/pprof/startcpuprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  165. StartCPUProfile()
  166. }))
  167. mux.Handle("/debug/pprof/stopcpuprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  168. StopCPUProfile()
  169. }))
  170. mux.Handle("/debug/pprof/memprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  171. runtime.GC()
  172. runtimePprof.WriteHeapProfile(rw)
  173. }))
  174. mux.Handle("/debug/pprof/gc", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  175. PrintGCSummary(rw)
  176. }))
  177. }
  178. if c, err := XHook.Call("MuxHandle", mux); err == nil {
  179. if ret := XHook.Value(c, 0); ret != nil {
  180. mux = ret.(*http.ServeMux)
  181. }
  182. }
  183. mux.Handle("/", s)
  184. s.Logger.Infof("http server is listening %s", addr)
  185. err := endless.ListenAndServe(addr, mux, func() {})
  186. if err != nil {
  187. s.Logger.Error("ListenAndServe:", err)
  188. }
  189. /*l, err := net.Listen("tcp", addr)
  190. if err != nil {
  191. s.Logger.Error("ListenAndServe:", err)
  192. }
  193. s.l = l
  194. err = http.Serve(s.l, mux)
  195. s.l.Close()*/
  196. }
  197. func (s *Server) Run(addr string) {
  198. addrs := strings.Split(addr, ":")
  199. s.Config.Addr = addrs[0]
  200. s.Config.Port, _ = strconv.Atoi(addrs[1])
  201. s.initServer()
  202. mux := http.NewServeMux()
  203. if s.Config.Profiler {
  204. mux.Handle("/debug/pprof", http.HandlerFunc(pprof.Index))
  205. mux.Handle("/debug/pprof/heap", pprof.Handler("heap"))
  206. mux.Handle("/debug/pprof/block", pprof.Handler("block"))
  207. mux.Handle("/debug/pprof/goroutine", pprof.Handler("goroutine"))
  208. mux.Handle("/debug/pprof/threadcreate", pprof.Handler("threadcreate"))
  209. mux.Handle("/debug/pprof/cmdline", http.HandlerFunc(pprof.Cmdline))
  210. mux.Handle("/debug/pprof/profile", http.HandlerFunc(pprof.Profile))
  211. mux.Handle("/debug/pprof/symbol", http.HandlerFunc(pprof.Symbol))
  212. mux.Handle("/debug/pprof/startcpuprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  213. StartCPUProfile()
  214. }))
  215. mux.Handle("/debug/pprof/stopcpuprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  216. StopCPUProfile()
  217. }))
  218. mux.Handle("/debug/pprof/memprof", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  219. runtime.GC()
  220. runtimePprof.WriteHeapProfile(rw)
  221. }))
  222. mux.Handle("/debug/pprof/gc", http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) {
  223. PrintGCSummary(rw)
  224. }))
  225. }
  226. if c, err := XHook.Call("MuxHandle", mux); err == nil {
  227. if ret := XHook.Value(c, 0); ret != nil {
  228. mux = ret.(*http.ServeMux)
  229. }
  230. }
  231. mux.Handle("/", s)
  232. s.Logger.Infof("http server is listening %s", addr)
  233. err := endless.ListenAndServe(addr, mux, func() {})
  234. if err != nil {
  235. s.Logger.Error("ListenAndServe:", func() {})
  236. }
  237. /*l, err := net.Listen("tcp", addr)
  238. if err != nil {
  239. s.Logger.Error("ListenAndServe:", err)
  240. }
  241. s.l = l
  242. err = http.Serve(s.l, mux)
  243. s.l.Close()*/
  244. }
  245. // RunFcgi starts the web application and serves FastCGI requests for s.
  246. func (s *Server) RunFcgi(addr string) {
  247. s.initServer()
  248. s.Logger.Infof("fcgi server is listening %s", addr)
  249. s.listenAndServeFcgi(addr)
  250. }
  251. // RunScgi starts the web application and serves SCGI requests for s.
  252. func (s *Server) RunScgi(addr string) {
  253. s.initServer()
  254. s.Logger.Infof("scgi server is listening %s", addr)
  255. s.listenAndServeScgi(addr)
  256. }
  257. // RunTLS starts the web application and serves HTTPS requests for s.
  258. func (s *Server) RunTLS(addr string, config *tls.Config) error {
  259. s.initServer()
  260. mux := http.NewServeMux()
  261. mux.Handle("/", s)
  262. l, err := tls.Listen("tcp", addr, config)
  263. if err != nil {
  264. s.Logger.Errorf("Listen: %v", err)
  265. return err
  266. }
  267. s.l = l
  268. s.Logger.Infof("https server is listening %s", addr)
  269. return http.Serve(s.l, mux)
  270. }
  271. // Close stops server s.
  272. func (s *Server) Close() {
  273. if s.l != nil {
  274. s.l.Close()
  275. }
  276. }
  277. // SetLogger sets the logger for server s
  278. func (s *Server) SetLogger(logger *log.Logger) {
  279. s.Logger = logger
  280. s.Logger.SetPrefix("[" + s.Name + "] ")
  281. if s.RootApp != nil {
  282. s.RootApp.Logger = s.Logger
  283. }
  284. }
  285. func (s *Server) InitSession() {
  286. if s.SessionManager == nil {
  287. s.SessionManager = httpsession.Default()
  288. }
  289. if s.Config.SessionTimeout > time.Second {
  290. s.SessionManager.SetMaxAge(s.Config.SessionTimeout)
  291. }
  292. s.SessionManager.Run()
  293. if s.RootApp != nil {
  294. s.RootApp.SessionManager = s.SessionManager
  295. }
  296. }
  297. func (s *Server) SetTemplateDir(path string) {
  298. s.RootApp.SetTemplateDir(path)
  299. }
  300. func (s *Server) SetStaticDir(path string) {
  301. s.RootApp.SetStaticDir(path)
  302. }
  303. func (s *Server) App(name string) *App {
  304. path, ok := s.AppsNamePath[name]
  305. if ok {
  306. return s.Apps[path]
  307. }
  308. return nil
  309. }