xweb.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Package web is a lightweight web framework for Go. It's ideal for
  2. // writing simple, performant backend web services.
  3. package xweb
  4. import (
  5. "crypto/tls"
  6. "fmt"
  7. "io"
  8. "net/http"
  9. "os"
  10. "path/filepath"
  11. "app.yhyue.com/moapp/jybase/go-xweb/log"
  12. )
  13. const (
  14. Version = "0.2.1"
  15. )
  16. func redirect(w http.ResponseWriter, url string, status ...int) error {
  17. s := 302
  18. if len(status) > 0 {
  19. s = status[0]
  20. }
  21. w.Header().Set("Location", url)
  22. w.WriteHeader(s)
  23. _, err := w.Write([]byte("Redirecting to: " + url))
  24. return err
  25. }
  26. func Download(w http.ResponseWriter, fpath string) error {
  27. f, err := os.Open(fpath)
  28. if err != nil {
  29. return err
  30. }
  31. defer f.Close()
  32. fName := filepath.Base(fpath)
  33. w.Header().Set("Content-Disposition", fmt.Sprintf("attachment; filename=\"%v\"", fName))
  34. _, err = io.Copy(w, f)
  35. return err
  36. }
  37. const (
  38. defaultErrorTmpl = `<!DOCTYPE html>
  39. <html lang="en">
  40. <meta charset="UTF-8" />
  41. <title>%d - %s</title>
  42. <style type="text/css">
  43. body{border:0;margin:0;padding:0;background:#eee url('data:image/gif;base64,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') right bottom;}
  44. .error{width:600px;border:1px solid #ccc;margin:100px auto;border-radius:5px;box-shadow:0 0 10px #ccc;background:#fff url('data:image/gif;base64,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') no-repeat right bottom;}
  45. .error-body,.error-foot{margin:0 10px 10px 10px;}
  46. .error-body{margin-top:10px;min-height:180px}
  47. .error-head h1{padding:10px 10px 0 10px;margin:0 2px;vertical-align:middle;border-bottom:1px solid #eee;}
  48. .framework{color:#eee;font-size:11px}
  49. </style>
  50. <body>
  51. <div class="error">
  52. <div class="error-head">
  53. <h1>%d - %s</h1>
  54. </div>
  55. <div class="error-body">%s</div>
  56. <div class="error-foot">
  57. <input type="button" title="Back" value="返回" onclick="history.go(-1)"/>
  58. <em class="framework">(xweb v%s)</em>
  59. </div>
  60. </div>
  61. </body>
  62. </html>`
  63. )
  64. var errorTmpl string = ""
  65. func Error(w http.ResponseWriter, status int, content string) error {
  66. return mainServer.error(w, status, content)
  67. }
  68. // Process invokes the main server's routing system.
  69. func Process(c http.ResponseWriter, req *http.Request) {
  70. mainServer.Process(c, req)
  71. }
  72. // Run starts the web application and serves HTTP requests for the main server.
  73. func Run(addr string) {
  74. mainServer.Run(addr)
  75. }
  76. func RunBase(addr string, mux *http.ServeMux) {
  77. mainServer.RunBase(addr, mux)
  78. }
  79. func SimpleTLSConfig(certFile, keyFile string) (*tls.Config, error) {
  80. config := &tls.Config{}
  81. if config.NextProtos == nil {
  82. config.NextProtos = []string{"http/1.1"}
  83. }
  84. var err error
  85. config.Certificates = make([]tls.Certificate, 1)
  86. config.Certificates[0], err = tls.LoadX509KeyPair(certFile, keyFile)
  87. if err != nil {
  88. return nil, err
  89. }
  90. return config, nil
  91. }
  92. // RunTLS starts the web application and serves HTTPS requests for the main server.
  93. func RunTLS(addr string, config *tls.Config) {
  94. mainServer.RunTLS(addr, config)
  95. }
  96. // RunScgi starts the web application and serves SCGI requests for the main server.
  97. func RunScgi(addr string) {
  98. mainServer.RunScgi(addr)
  99. }
  100. // RunFcgi starts the web application and serves FastCGI requests for the main server.
  101. func RunFcgi(addr string) {
  102. mainServer.RunFcgi(addr)
  103. }
  104. // Close stops the main server.
  105. func Close() {
  106. mainServer.Close()
  107. }
  108. func AutoAction(c ...interface{}) {
  109. mainServer.AutoAction(c...)
  110. }
  111. func AddAction(c ...interface{}) {
  112. mainServer.AddAction(c...)
  113. }
  114. func AddTmplVar(name string, varOrFun interface{}) {
  115. mainServer.AddTmplVar(name, varOrFun)
  116. }
  117. func AddTmplVars(t *T) {
  118. mainServer.AddTmplVars(t)
  119. }
  120. func AddRouter(url string, c interface{}) {
  121. mainServer.AddRouter(url, c)
  122. }
  123. func AddFilter(filter Filter) {
  124. mainServer.AddFilter(filter)
  125. }
  126. func AddApp(a *App) {
  127. mainServer.AddApp(a)
  128. }
  129. func AddConfig(name string, value interface{}) {
  130. mainServer.AddConfig(name, value)
  131. }
  132. func AddHook(name string, fns ...interface{}) {
  133. XHook.Bind(name, fns...)
  134. }
  135. func SetTemplateDir(dir string) {
  136. mainServer.SetTemplateDir(dir)
  137. }
  138. func SetStaticDir(dir string) {
  139. mainServer.SetStaticDir(dir)
  140. }
  141. // SetLogger sets the logger for the main server.
  142. func SetLogger(logger *log.Logger) {
  143. mainServer.SetLogger(logger)
  144. }
  145. func MainServer() *Server {
  146. return mainServer
  147. }
  148. func RootApp() *App {
  149. return mainServer.RootApp
  150. }
  151. func Serv(name string) *Server {
  152. server, ok := Servers[name]
  153. if ok {
  154. return server
  155. }
  156. return nil
  157. }
  158. // Config is the configuration of the main server.
  159. var (
  160. Config *ServerConfig = &ServerConfig{
  161. RecoverPanic: true,
  162. EnableGzip: true,
  163. //Profiler: true,
  164. StaticExtensionsToGzip: []string{".css", ".js"},
  165. }
  166. Servers map[string]*Server = make(map[string]*Server) //[SWH|+]
  167. mainServer *Server = NewServer("main")
  168. )