diff --git a/conf/wide.go b/conf/wide.go index 0a6d9b1..017a9b0 100644 --- a/conf/wide.go +++ b/conf/wide.go @@ -17,12 +17,22 @@ import ( "github.com/golang/glog" ) -type User struct { - Name string - Password string - Workspace string // 指定了该用户的 GOPATH 路径 +// 最后一次会话内容结构. +type LatestSessionContent struct { + FileTree []string // 文件树展开的路径集 + Files []string // 编辑器打开的文件路径集 + CurrentFile string // 当前编辑器文件路径 } +// 用户结构. +type User struct { + Name string + Password string + Workspace string // 指定了该用户的 GOPATH 路径 + LatestSessionContent *LatestSessionContent +} + +// 配置结构. type conf struct { Server string StaticServer string @@ -37,12 +47,16 @@ type conf struct { Users []*User } +// 配置. var Wide conf + +// 维护非变化部分的配置. +// 只有 Users 是会运行时变化的,保存回写文件时要使用这个变量. var rawWide conf // 定时检查 Wide 运行环境. // 如果是特别严重的问题(比如 $GOPATH 不存在)则退出进程,另一些不太严重的问题(比如 gocode 不存在)则放入全局通知队列. -func CheckEnv() { +func FixedTimeCheckEnv() { go func() { for { if "" == os.Getenv("GOPATH") { @@ -73,6 +87,19 @@ func CheckEnv() { } // TODO: 7 分钟进行一次检查环境 + time.Sleep(time.Second * 7) + } + }() +} + +// 定时(10 分钟)保存配置. +// 主要是保存用户会话内容,以备下一次用户打开 Wide 时进行会话还原. +func FixedTimeSave() { + go func() { + for { + Save() + + // TODO: 10 分钟进行一次配置保存 time.Sleep(time.Second * 10) } }() @@ -124,7 +151,7 @@ func getGOBIN() string { // 保存 Wide 配置. func Save() bool { - // 只有 Users 是可以通过界面修改的,其他属性只能手工维护 wide.json 配置文件 + // 只有 Users 是会运行时变化的,其他属性只能手工维护 wide.json 配置文件 rawWide.Users = Wide.Users // 原始配置文件内容 diff --git a/conf/wide.json b/conf/wide.json index 47ef6f9..67329aa 100644 --- a/conf/wide.json +++ b/conf/wide.json @@ -13,7 +13,19 @@ { "Name": "admin", "Password": "admin", - "Workspace": "{pwd}/data/user_workspaces/admin" + "Workspace": "{pwd}/data/user_workspaces/admin", + "LatestSessionContent": { + "FileTree": [ + "1/", + "2/" + ], + "Files": [ + "1.go", + "2.go", + "3.go" + ], + "CurrentFile": "current file" + } } ] } \ No newline at end of file diff --git a/main.go b/main.go index 40eff3b..2ba5d79 100644 --- a/main.go +++ b/main.go @@ -36,7 +36,10 @@ func init() { conf.Load() // 定时检查运行环境 - conf.CheckEnv() + conf.FixedTimeCheckEnv() + + // 定时保存配置 + conf.FixedTimeSave() } // 登录. @@ -158,6 +161,7 @@ func main() { http.HandleFunc("/login", loginHandler) http.HandleFunc("/", indexHandler) http.HandleFunc("/session/ws", session.WSHandler) + http.HandleFunc("/session/save", session.SaveContent) // 运行相关 http.HandleFunc("/build", output.BuildHandler) diff --git a/session/sessions.go b/session/sessions.go index 673a637..ec52de1 100644 --- a/session/sessions.go +++ b/session/sessions.go @@ -7,6 +7,7 @@ package session import ( + "encoding/json" "math/rand" "net/http" "os" @@ -14,6 +15,7 @@ import ( "sync" "time" + "github.com/b3log/wide/conf" "github.com/b3log/wide/event" "github.com/b3log/wide/util" "github.com/golang/glog" @@ -42,13 +44,15 @@ var HTTPSession = sessions.NewCookieStore([]byte("BEYOND")) // Wide 会话,对应一个浏览器 tab. type WideSession struct { - Id string // 唯一标识 - HTTPSession *sessions.Session // 关联的 HTTP 会话 - Processes []*os.Process // 关联的进程集 - EventQueue *event.UserEventQueue // 关联的事件队列 - State int // 状态 - Created time.Time // 创建时间 - Updated time.Time // 最近一次使用时间 + Id string // 唯一标识 + Username string // 用户名 + HTTPSession *sessions.Session // 关联的 HTTP 会话 + Processes []*os.Process // 关联的进程集 + EventQueue *event.UserEventQueue // 关联的事件队列 + State int // 状态 + Content *conf.LatestSessionContent // 最近一次会话内容 + Created time.Time // 创建时间 + Updated time.Time // 最近一次使用时间 } type Sessions []*WideSession @@ -133,6 +137,56 @@ func WSHandler(w http.ResponseWriter, r *http.Request) { } } +// 会话内容保存. +func SaveContent(w http.ResponseWriter, r *http.Request) { + data := map[string]interface{}{"succ": true} + defer util.RetJSON(w, r, data) + + var args map[string]interface{} + + if err := json.NewDecoder(r.Body).Decode(&args); err != nil { + glog.Error(err) + data["succ"] = false + + return + } + + sid := args["sid"].(string) + + wSession := WideSessions.Get(sid) + if nil == wSession { + data["succ"] = false + + return + } + + wSession.Content.CurrentFile = args["currentFile"].(string) + // TODO: Ugly + fileTree := args["fileTree"].([]interface{}) + ft := []string{} + for _, v := range fileTree { + ft = append(ft, v.(string)) + } + wSession.Content.FileTree = ft + + files := args["files"].([]interface{}) + fs := []string{} + for _, v := range files { + fs = append(fs, v.(string)) + } + wSession.Content.Files = fs + + for _, user := range conf.Wide.Users { + if user.Name == wSession.Username { + user.LatestSessionContent = wSession.Content + + // 定时任务会负责持久化 + + return + } + } +} + // 设置会话关联的进程集. func (s *WideSession) SetProcesses(ps []*os.Process) { s.Processes = ps @@ -160,9 +214,11 @@ func (sessions *Sessions) New(httpSession *sessions.Session) *WideSession { ret := &WideSession{ Id: id, + Username: httpSession.Values["username"].(string), HTTPSession: httpSession, EventQueue: userEventQueue, State: SessionStateActive, + Content: &conf.LatestSessionContent{}, Created: now, Updated: now, } diff --git a/static/js/session.js b/static/js/session.js index b37ef04..b66bedc 100644 --- a/static/js/session.js +++ b/static/js/session.js @@ -17,3 +17,21 @@ sessionWS.onerror = function (e) { console.log('[session onerror] ' + JSON.parse(e)); }; +// 定时(30 秒)保存会话内容. +setTimeout(function () { + var request = newWideRequest(); + + // TODO: 会话状态保存 + request.currentFile = "current file"; // 当前编辑器 + request.fileTree = ["1/", "2/"]; // 文件树展开状态 + request.files = ["1.go", "2.go", "3.go"]; // 编辑器打开状态 + + $.ajax({ + type: 'POST', + url: '/session/save', + data: JSON.stringify(request), + dataType: "json", + success: function (data) { + } + }); +}, 30000);