This commit is contained in:
parent
5d2497063f
commit
7ec8a77005
128
conf/wide.go
128
conf/wide.go
|
@ -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
81
main.go
|
@ -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")
|
||||||
|
|
Loading…
Reference in New Issue