This commit is contained in:
Liang Ding 2014-10-29 14:05:10 +08:00
parent 5d2497063f
commit 7ec8a77005
2 changed files with 94 additions and 115 deletions

View File

@ -1,4 +1,4 @@
// Wide 配置相关,所有配置(包括用户配置)都是保存在 wide.json 中. // Configurations manipulations, all configurations (including user configurations) are stored in wide.json.
package conf package conf
import ( import (
@ -18,60 +18,60 @@ import (
) )
const ( const (
PathSeparator = string(os.PathSeparator) // 系统文件路径分隔符 PathSeparator = string(os.PathSeparator) // OS-specific path separator
PathListSeparator = string(os.PathListSeparator) // 系统路径列表分隔符 PathListSeparator = string(os.PathListSeparator) // OS-specific path list separator
) )
// 最后一次会话内容结构. // The latest session content.
type LatestSessionContent struct { type LatestSessionContent struct {
FileTree []string // 文件树展开的路径集 FileTree []string // paths of expanding nodes of file tree
Files []string // 编辑器打开的文件路径集 Files []string // paths of files of opening editor tabs
CurrentFile string // 当前编辑器文件路径 CurrentFile string // path of file of the current focused editor tab
} }
// 用户结构. // User.
type User struct { type User struct {
Name string Name string
Password string Password string
Workspace string // 该用户的工作空间 GOPATH 路径 Workspace string // the GOPATH of this user
Locale string Locale string
GoFormat string GoFormat string
LatestSessionContent *LatestSessionContent LatestSessionContent *LatestSessionContent
} }
// 配置结构. // Configuration.
type conf struct { type conf struct {
Server string // 服务地址({IP}:7070 Server string // server host and port ({IP}:7070)
StaticServer string // 静态资源服务地址http://{IP}:7070 StaticServer string // static resources server scheme, host and port (http://{IP}:7070)
EditorChannel string // 编辑器通道地址ws://{IP}:7070 EditorChannel string // editor channel (ws://{IP}:7070)
OutputChannel string // 输出窗口通道地址ws://{IP}:7070 OutputChannel string // output channel (ws://{IP}:7070)
ShellChannel string // Shell 通道地址ws://{IP}:7070 ShellChannel string // shell channel(ws://{IP}:7070)
SessionChannel string // Wide 会话通道地址ws://{IP}:7070 SessionChannel string // wide session channel (ws://{IP}:7070)
HTTPSessionMaxAge int // HTTP 会话失效时间(秒) HTTPSessionMaxAge int // HTTP session max age (in seciond)
StaticResourceVersion string // 静态资源版本 StaticResourceVersion string // version of static resources
MaxProcs int // 并发执行数 MaxProcs int // Go max procs
RuntimeMode string // 运行模式 RuntimeMode string // runtime mode (dev/prod)
Pwd string // 工作目录 Pwd string // current working direcitory
Workspace string // 主工作空间 GOPATH 路径 Workspace string // path of master workspace
Locale string // 默认的区域 Locale string // default locale
Users []*User // 用户集 Users []*User // configurations of users
} }
// 配置. // Configuration variable.
var Wide conf var Wide conf
// 维护非变化部分的配置. // A raw copy of configuration variable.
// //
// 只有 Users 是会运行时变化的,保存回写文件时要使用这个变量. // Save function will use this variable to persist.
var rawWide conf var rawWide conf
// 定时检查 Wide 运行环境. // FixedTimeCheckEnv checks Wide runtime enviorment periodically (7 minutes).
// //
// 如果是特别严重的问题(比如 $GOPATH 不存在)则退出进程,另一些不太严重的问题(比如 gocode 不存在)则放入全局通知队列. // Exits process if found fatal issues (such as not found $GOPATH),
// Notifies user by notification queue if found warning issues (such as not found gocode).
func FixedTimeCheckEnv() { func FixedTimeCheckEnv() {
go func() { go func() {
// 7 分钟进行一次检查环境
for _ = range time.Tick(time.Minute * 7) { for _ = range time.Tick(time.Minute * 7) {
if "" == os.Getenv("GOPATH") { if "" == os.Getenv("GOPATH") {
glog.Fatal("Not found $GOPATH") glog.Fatal("Not found $GOPATH")
@ -106,9 +106,9 @@ func FixedTimeCheckEnv() {
}() }()
} }
// 定时1 分钟)保存配置. // FixedTimeSave saves configurations (wide.json) periodically (1 minute).
// //
// 主要目的是保存用户会话内容,以备下一次用户打开 Wide 时进行会话还原. // Main goal of this function is to save user session content, for restoring session content while user open Wide next time.
func FixedTimeSave() { func FixedTimeSave() {
go func() { go func() {
// 1 分钟进行一次配置保存 // 1 分钟进行一次配置保存
@ -118,11 +118,12 @@ func FixedTimeSave() {
}() }()
} }
// 获取 username 指定的用户的工作空间路径,查找不到时返回空字符串. // GetUserWorkspace gets workspace path with the specified username, returns "" if not found.
func (c *conf) GetUserWorkspace(username string) string { func (c *conf) GetUserWorkspace(username string) string {
for _, user := range c.Users { for _, user := range c.Users {
if user.Name == username { if user.Name == username {
ret := strings.Replace(user.Workspace, "{pwd}", c.Pwd, 1) ret := strings.Replace(user.Workspace, "{pwd}", c.Pwd, 1)
return filepath.FromSlash(ret) return filepath.FromSlash(ret)
} }
} }
@ -130,16 +131,16 @@ func (c *conf) GetUserWorkspace(username string) string {
return "" return ""
} }
// 获取主工作空间路径. // GetWorkspace gets the master workspace path.
// //
// 相比起使用 Wide.Workspace该函数会做如下处理 // Compared to the use of Wide.Workspace, this function will be processed as follows:
// 1. 替换里面的 {pwd} 变量为实际的目录路径 // 1. Replace {pwd} variable with the actual directory path
// 2. 把 / 替换为 \\ Windows // 2. Replace "/" with "\\" (Windows)
func (c *conf) GetWorkspace() string { func (c *conf) GetWorkspace() string {
return filepath.FromSlash(strings.Replace(c.Workspace, "{pwd}", c.Pwd, 1)) return filepath.FromSlash(strings.Replace(c.Workspace, "{pwd}", c.Pwd, 1))
} }
// 获取 username 指定的用户的 Go 源码格式化工具路径,查找不到时返回 "gofmt". // GetGoFmt gets the path of Go format tool, returns "gofmt" if not found.
func (c *conf) GetGoFmt(username string) string { func (c *conf) GetGoFmt(username string) string {
for _, user := range c.Users { for _, user := range c.Users {
if user.Name == username { if user.Name == username {
@ -158,16 +159,16 @@ func (c *conf) GetGoFmt(username string) string {
return "gofmt" return "gofmt"
} }
// 获取用户的工作空间路径. // GetWorkspace gets workspace path of the user.
// //
// 相比起使用 User.Workspace该函数会做如下处理 // Compared to the use of Wide.Workspace, this function will be processed as follows:
// 1. 替换里面的 {pwd} 变量为实际的目录路径 // 1. Replace {pwd} variable with the actual directory path
// 2. 把 / 替换为 \\ Windows // 2. Replace "/" with "\\" (Windows)
func (u *User) GetWorkspace() string { func (u *User) GetWorkspace() string {
return filepath.FromSlash(strings.Replace(u.Workspace, "{pwd}", Wide.Pwd, 1)) return filepath.FromSlash(strings.Replace(u.Workspace, "{pwd}", Wide.Pwd, 1))
} }
// 获取 username 指定的用户配置. // GetUser gets configuration of the user specified by the given username, returns nil if not found.
func (*conf) GetUser(username string) *User { func (*conf) GetUser(username string) *User {
for _, user := range Wide.Users { for _, user := range Wide.Users {
if user.Name == username { if user.Name == username {
@ -178,9 +179,9 @@ func (*conf) GetUser(username string) *User {
return nil return nil
} }
// 获取 GOBIN 中 executable 指定的文件路径. // GetExecutableInGOBIN gets executable file under GOBIN path.
// //
// 函数内部会判断操作系统,如果是 Windows 则在 executable 实参后加入 .exe 后缀. // The specified executable should not with extension, this function will append .exe if on Windows.
func (*conf) GetExecutableInGOBIN(executable string) string { func (*conf) GetExecutableInGOBIN(executable string) string {
if util.OS.IsWindows() { if util.OS.IsWindows() {
executable += ".exe" executable += ".exe"
@ -214,12 +215,12 @@ func (*conf) GetExecutableInGOBIN(executable string) string {
return os.Getenv("GOBIN") + PathSeparator + executable return os.Getenv("GOBIN") + PathSeparator + executable
} }
// 保存 Wide 配置. // Save saves Wide configurations.
func Save() bool { func Save() bool {
// 只有 Users 是会运行时变化的,其他属性只能手工维护 wide.json 配置文件 // just the Users field are volatile
rawWide.Users = Wide.Users rawWide.Users = Wide.Users
// 原始配置文件内容 // format
bytes, err := json.MarshalIndent(rawWide, "", " ") bytes, err := json.MarshalIndent(rawWide, "", " ")
if nil != err { if nil != err {
@ -237,7 +238,7 @@ func Save() bool {
return true return true
} }
// 加载 Wide 配置. // Load loads the configurations from wide.json.
func Load() { func Load() {
bytes, _ := ioutil.ReadFile("conf/wide.json") bytes, _ := ioutil.ReadFile("conf/wide.json")
@ -248,7 +249,7 @@ func Load() {
os.Exit(-1) os.Exit(-1)
} }
// 保存未经变量替换处理的原始配置文件,用于写回时 // keep the raw content
json.Unmarshal(bytes, &rawWide) json.Unmarshal(bytes, &rawWide)
ip, err := util.Net.LocalIP() ip, err := util.Net.LocalIP()
@ -275,9 +276,9 @@ func Load() {
initWorkspaceDirs() initWorkspaceDirs()
} }
// 初始化主工作空间、各个用户的工作空间目录. // initWorkspaceDirs initializes the directories of master workspace, users' workspaces.
// //
// 如果不存在 Workspace 配置所指定的目录路径则创建该目录. // Creates directories if not found on path of workspace.
func initWorkspaceDirs() { func initWorkspaceDirs() {
paths := filepath.SplitList(Wide.GetWorkspace()) paths := filepath.SplitList(Wide.GetWorkspace())
@ -291,27 +292,20 @@ func initWorkspaceDirs() {
} }
} }
// 在 path 指定的路径下创建工作空间目录. // createWorkspaceDir creates directories on the path.
// //
// 1. 根目录:{path} // 1. root directory:{path}
// 2. 源码目录:{path}/src // 2. src directory: {path}/src
// 3. 包目录:{path}/pkg // 3. package directory: {path}/pkg
// 4. 可执行文件目录:{path}/bin // 4. binary directory: {path}/bin
func createWorkspaceDir(path string) { func createWorkspaceDir(path string) {
// {path}, workspace root
createDir(path) createDir(path)
// {path}/src
createDir(path + PathSeparator + "src") createDir(path + PathSeparator + "src")
// {path}/pkg
createDir(path + PathSeparator + "pkg") createDir(path + PathSeparator + "pkg")
// {path}/bin
createDir(path + PathSeparator + "bin") createDir(path + PathSeparator + "bin")
} }
// 在 path 指定的路径下不存在目录或文件则创建目录. // createDir creates a directory on the path if it not exists.
func createDir(path string) { func createDir(path string) {
if !isExist(path) { if !isExist(path) {
if err := os.MkdirAll(path, 0775); nil != err { if err := os.MkdirAll(path, 0775); nil != err {
@ -324,9 +318,7 @@ func createDir(path string) {
} }
} }
// 检查文件或目录是否存在. // isExist determines whether the file spcified by the given filename is exists.
//
// 如果由 filename 指定的文件或目录存在则返回 true否则返回 false.
func isExist(filename string) bool { func isExist(filename string) bool {
_, err := os.Stat(filename) _, err := os.Stat(filename)

81
main.go
View File

@ -25,37 +25,30 @@ import (
) )
const ( const (
Ver = "1.0.1" // Wide 版本 Ver = "1.0.1" // wide version
CodeMirrorVer = "4.7" // 编辑器版本 CodeMirrorVer = "4.7" // editor version
) )
// Wide 中唯一一个 init 函数. // The only one init function in Wide.
func init() { func init() {
// TODO: 默认启动参数 // TODO: args
flag.Set("logtostderr", "true") flag.Set("logtostderr", "true")
flag.Set("v", "3") flag.Set("v", "3")
flag.Parse() flag.Parse()
// 加载事件处理
event.Load() event.Load()
// 加载配置
conf.Load() conf.Load()
// 定时检查运行环境
conf.FixedTimeCheckEnv() conf.FixedTimeCheckEnv()
// 定时保存配置
conf.FixedTimeSave() conf.FixedTimeSave()
// 定时检查无效会话
session.FixedTimeRelease() session.FixedTimeRelease()
} }
// 登录. // loginHandler handles request of user login.
func loginHandler(w http.ResponseWriter, r *http.Request) { func loginHandler(w http.ResponseWriter, r *http.Request) {
if "GET" == r.Method { if "GET" == r.Method {
// 展示登录页面 // show the login page
model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(conf.Wide.Locale), model := map[string]interface{}{"conf": conf.Wide, "i18n": i18n.GetAll(conf.Wide.Locale),
"locale": conf.Wide.Locale, "ver": Ver} "locale": conf.Wide.Locale, "ver": Ver}
@ -74,7 +67,8 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
// 非 GET 请求当作是登录请求 // non-GET request as login request
succ := false succ := false
data := map[string]interface{}{"succ": &succ} data := map[string]interface{}{"succ": &succ}
@ -102,7 +96,7 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
return return
} }
// 创建 HTTP 会话 // create a HTTP session
httpSession, _ := session.HTTPSession.Get(r, "wide-session") httpSession, _ := session.HTTPSession.Get(r, "wide-session")
httpSession.Values["username"] = args.Username httpSession.Values["username"] = args.Username
httpSession.Values["id"] = strconv.Itoa(rand.Int()) httpSession.Values["id"] = strconv.Itoa(rand.Int())
@ -112,7 +106,7 @@ func loginHandler(w http.ResponseWriter, r *http.Request) {
glog.Infof("Created a HTTP session [%s] for user [%s]", httpSession.Values["id"].(string), args.Username) glog.Infof("Created a HTTP session [%s] for user [%s]", httpSession.Values["id"].(string), args.Username)
} }
// 退出(登出). // logoutHandler handles request of user logout (exit).
func logoutHandler(w http.ResponseWriter, r *http.Request) { func logoutHandler(w http.ResponseWriter, r *http.Request) {
data := map[string]interface{}{"succ": true} data := map[string]interface{}{"succ": true}
defer util.RetJSON(w, r, data) defer util.RetJSON(w, r, data)
@ -123,7 +117,7 @@ func logoutHandler(w http.ResponseWriter, r *http.Request) {
httpSession.Save(r, w) httpSession.Save(r, w)
} }
// Wide 首页. // indexHandler handles request of Wide index.
func indexHandler(w http.ResponseWriter, r *http.Request) { func indexHandler(w http.ResponseWriter, r *http.Request) {
httpSession, _ := session.HTTPSession.Get(r, "wide-session") httpSession, _ := session.HTTPSession.Get(r, "wide-session")
@ -136,7 +130,7 @@ func indexHandler(w http.ResponseWriter, r *http.Request) {
httpSession.Options.MaxAge = conf.Wide.HTTPSessionMaxAge httpSession.Options.MaxAge = conf.Wide.HTTPSessionMaxAge
httpSession.Save(r, w) httpSession.Save(r, w)
// 创建一个 Wide 会话 // create a Wide session
wideSession := session.WideSessions.New(httpSession) wideSession := session.WideSessions.New(httpSession)
username := httpSession.Values["username"].(string) username := httpSession.Values["username"].(string)
@ -163,14 +157,14 @@ func indexHandler(w http.ResponseWriter, r *http.Request) {
t.Execute(w, model) t.Execute(w, model)
} }
// 单个文件资源请求处理. // serveSingle registers the handler function for the given pattern and filename.
func serveSingle(pattern string, filename string) { func serveSingle(pattern string, filename string) {
http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) { http.HandleFunc(pattern, func(w http.ResponseWriter, r *http.Request) {
http.ServeFile(w, r, filename) http.ServeFile(w, r, filename)
}) })
} }
// 起始页请求处理. // startHandler handles request of start page.
func startHandler(w http.ResponseWriter, r *http.Request) { func startHandler(w http.ResponseWriter, r *http.Request) {
httpSession, _ := session.HTTPSession.Get(r, "wide-session") httpSession, _ := session.HTTPSession.Get(r, "wide-session")
@ -202,7 +196,7 @@ func startHandler(w http.ResponseWriter, r *http.Request) {
t.Execute(w, model) t.Execute(w, model)
} }
// 键盘快捷键页请求处理. // keyboardShortcutsHandler handles request of keyboard shortcuts page.
func keyboardShortcutsHandler(w http.ResponseWriter, r *http.Request) { func keyboardShortcutsHandler(w http.ResponseWriter, r *http.Request) {
httpSession, _ := session.HTTPSession.Get(r, "wide-session") httpSession, _ := session.HTTPSession.Get(r, "wide-session")
@ -232,7 +226,7 @@ func keyboardShortcutsHandler(w http.ResponseWriter, r *http.Request) {
t.Execute(w, model) t.Execute(w, model)
} }
// 关于页请求处理. // aboutHandle handles request of about page.
func aboutHandler(w http.ResponseWriter, r *http.Request) { func aboutHandler(w http.ResponseWriter, r *http.Request) {
httpSession, _ := session.HTTPSession.Get(r, "wide-session") httpSession, _ := session.HTTPSession.Get(r, "wide-session")
@ -263,7 +257,7 @@ func aboutHandler(w http.ResponseWriter, r *http.Request) {
t.Execute(w, model) t.Execute(w, model)
} }
// 主程序入口. // Main.
func main() { func main() {
runtime.GOMAXPROCS(conf.Wide.MaxProcs) runtime.GOMAXPROCS(conf.Wide.MaxProcs)
@ -279,18 +273,18 @@ func main() {
http.HandleFunc("/about", handlerWrapper(aboutHandler)) http.HandleFunc("/about", handlerWrapper(aboutHandler))
http.HandleFunc("/keyboard_shortcuts", handlerWrapper(keyboardShortcutsHandler)) http.HandleFunc("/keyboard_shortcuts", handlerWrapper(keyboardShortcutsHandler))
// 静态资源 // static resources
http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static")))) http.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.Dir("static"))))
serveSingle("/favicon.ico", "./static/favicon.ico") serveSingle("/favicon.ico", "./static/favicon.ico")
// 库资源 // workspaces
http.Handle("/data/", http.StripPrefix("/data/", http.FileServer(http.Dir("data")))) http.Handle("/data/", http.StripPrefix("/data/", http.FileServer(http.Dir("data"))))
// 会话 // session
http.HandleFunc("/session/ws", handlerWrapper(session.WSHandler)) http.HandleFunc("/session/ws", handlerWrapper(session.WSHandler))
http.HandleFunc("/session/save", handlerWrapper(session.SaveContent)) http.HandleFunc("/session/save", handlerWrapper(session.SaveContent))
// 运行相关 // run
http.HandleFunc("/build", handlerWrapper(output.BuildHandler)) http.HandleFunc("/build", handlerWrapper(output.BuildHandler))
http.HandleFunc("/run", handlerWrapper(output.RunHandler)) http.HandleFunc("/run", handlerWrapper(output.RunHandler))
http.HandleFunc("/stop", handlerWrapper(output.StopHandler)) http.HandleFunc("/stop", handlerWrapper(output.StopHandler))
@ -299,7 +293,7 @@ func main() {
http.HandleFunc("/go/install", handlerWrapper(output.GoInstallHandler)) http.HandleFunc("/go/install", handlerWrapper(output.GoInstallHandler))
http.HandleFunc("/output/ws", handlerWrapper(output.WSHandler)) http.HandleFunc("/output/ws", handlerWrapper(output.WSHandler))
// 文件树 // file tree
http.HandleFunc("/files", handlerWrapper(file.GetFiles)) http.HandleFunc("/files", handlerWrapper(file.GetFiles))
http.HandleFunc("/file", handlerWrapper(file.GetFile)) http.HandleFunc("/file", handlerWrapper(file.GetFile))
http.HandleFunc("/file/save", handlerWrapper(file.SaveFile)) http.HandleFunc("/file/save", handlerWrapper(file.SaveFile))
@ -307,7 +301,7 @@ func main() {
http.HandleFunc("/file/remove", handlerWrapper(file.RemoveFile)) http.HandleFunc("/file/remove", handlerWrapper(file.RemoveFile))
http.HandleFunc("/file/search/text", handlerWrapper(file.SearchText)) http.HandleFunc("/file/search/text", handlerWrapper(file.SearchText))
// 编辑器 // editor
http.HandleFunc("/editor/ws", handlerWrapper(editor.WSHandler)) http.HandleFunc("/editor/ws", handlerWrapper(editor.WSHandler))
http.HandleFunc("/go/fmt", handlerWrapper(editor.GoFmtHandler)) http.HandleFunc("/go/fmt", handlerWrapper(editor.GoFmtHandler))
http.HandleFunc("/autocomplete", handlerWrapper(editor.AutocompleteHandler)) http.HandleFunc("/autocomplete", handlerWrapper(editor.AutocompleteHandler))
@ -317,20 +311,17 @@ func main() {
http.HandleFunc("/html/fmt", handlerWrapper(editor.HTMLFmtHandler)) http.HandleFunc("/html/fmt", handlerWrapper(editor.HTMLFmtHandler))
http.HandleFunc("/json/fmt", handlerWrapper(editor.JSONFmtHandler)) http.HandleFunc("/json/fmt", handlerWrapper(editor.JSONFmtHandler))
// Shell // shell
http.HandleFunc("/shell/ws", handlerWrapper(shell.WSHandler)) http.HandleFunc("/shell/ws", handlerWrapper(shell.WSHandler))
http.HandleFunc("/shell", handlerWrapper(shell.IndexHandler)) http.HandleFunc("/shell", handlerWrapper(shell.IndexHandler))
// 通知 // notification
http.HandleFunc("/notification/ws", handlerWrapper(notification.WSHandler)) http.HandleFunc("/notification/ws", handlerWrapper(notification.WSHandler))
// 用户 // user
http.HandleFunc("/user/new", handlerWrapper(session.AddUser)) http.HandleFunc("/user/new", handlerWrapper(session.AddUser))
http.HandleFunc("/user/repos/init", handlerWrapper(session.InitGitRepos)) http.HandleFunc("/user/repos/init", handlerWrapper(session.InitGitRepos))
// 文档
http.Handle("/doc/", http.StripPrefix("/doc/", http.FileServer(http.Dir("doc"))))
glog.V(0).Infof("Wide is running [%s]", conf.Wide.Server) glog.V(0).Infof("Wide is running [%s]", conf.Wide.Server)
err := http.ListenAndServe(conf.Wide.Server, nil) err := http.ListenAndServe(conf.Wide.Server, nil)
@ -339,12 +330,11 @@ func main() {
} }
} }
// HTTP Handler 包装,完成共性处理. // handlerWrapper wraps the HTTP Handler for some common processes.
//
// 共性处理:
// //
// 1. panic recover // 1. panic recover
// 2. 请求计时 // 2. request stopwatch
// 3. i18n
func handlerWrapper(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) { func handlerWrapper(f func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
handler := panicRecover(f) handler := panicRecover(f)
handler = stopwatch(handler) handler = stopwatch(handler)
@ -353,17 +343,16 @@ func handlerWrapper(f func(w http.ResponseWriter, r *http.Request)) func(w http.
return handler return handler
} }
// 国际化处理包装. // i18nLoad wraps the i18n process.
func i18nLoad(handler func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) { func i18nLoad(handler func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
i18n.Load() i18n.Load()
// Handler 处理
handler(w, r) handler(w, r)
} }
} }
// Handler 包装请求计时. // stopwatch wraps the request stopwatch process.
func stopwatch(handler func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) { func stopwatch(handler func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
start := time.Now() start := time.Now()
@ -372,24 +361,22 @@ func stopwatch(handler func(w http.ResponseWriter, r *http.Request)) func(w http
glog.V(5).Infof("[%s] [%s]", r.RequestURI, time.Since(start)) glog.V(5).Infof("[%s] [%s]", r.RequestURI, time.Since(start))
}() }()
// Handler 处理
handler(w, r) handler(w, r)
} }
} }
// Handler 包装 recover panic. // panicRecover wraps the panic recover process.
func panicRecover(handler func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) { func panicRecover(handler func(w http.ResponseWriter, r *http.Request)) func(w http.ResponseWriter, r *http.Request) {
return func(w http.ResponseWriter, r *http.Request) { return func(w http.ResponseWriter, r *http.Request) {
defer util.Recover() defer util.Recover()
// Handler 处理
handler(w, r) handler(w, r)
} }
} }
// 初始化 mime. // initMime initializes mime types.
// //
// 有的操作系统(例如 Windows XP上运行时根据文件后缀获取不到对应的 mime 类型,会导致响应的 HTTP content-type 不正确。 // We can't get the mime types on some OS (such as Windows XP) by default, so initializes them here.
func initMime() { func initMime() {
mime.AddExtensionType(".css", "text/css") mime.AddExtensionType(".css", "text/css")
mime.AddExtensionType(".js", "application/x-javascript") mime.AddExtensionType(".js", "application/x-javascript")