wide/output/outputs.go

237 lines
4.9 KiB
Go
Raw Normal View History

2014-08-18 17:45:43 +04:00
package output
import (
"encoding/json"
2014-08-28 06:19:00 +04:00
"github.com/b3log/wide/conf"
2014-08-31 13:39:39 +04:00
"github.com/b3log/wide/user"
2014-09-01 16:50:51 +04:00
"github.com/b3log/wide/util"
2014-08-18 17:45:43 +04:00
"github.com/golang/glog"
"github.com/gorilla/websocket"
"io"
"math/rand"
"net/http"
"os"
"os/exec"
2014-08-22 07:57:05 +04:00
"runtime"
"strings"
2014-08-18 17:45:43 +04:00
)
var outputWS = map[string]*websocket.Conn{}
func WSHandler(w http.ResponseWriter, r *http.Request) {
2014-08-31 13:39:39 +04:00
session, _ := user.Session.Get(r, "wide-session")
2014-08-18 17:45:43 +04:00
sid := session.Values["id"].(string)
outputWS[sid], _ = websocket.Upgrade(w, r, nil, 1024, 1024)
ret := map[string]interface{}{"output": "Ouput initialized", "cmd": "init-output"}
outputWS[sid].WriteJSON(&ret)
glog.Infof("Open a new [Output] with session [%s], %d", sid, len(outputWS))
}
func RunHandler(w http.ResponseWriter, r *http.Request) {
2014-09-01 16:50:51 +04:00
data := map[string]interface{}{"succ": true}
defer util.RetJSON(w, r, data)
2014-08-31 13:39:39 +04:00
session, _ := user.Session.Get(r, "wide-session")
2014-08-18 17:45:43 +04:00
sid := session.Values["id"].(string)
decoder := json.NewDecoder(r.Body)
var args map[string]interface{}
if err := decoder.Decode(&args); err != nil {
glog.Error(err)
2014-09-01 16:50:51 +04:00
data["succ"] = false
2014-08-18 17:45:43 +04:00
return
}
2014-08-22 07:57:05 +04:00
filePath := args["executable"].(string)
curDir := filePath[:strings.LastIndex(filePath, string(os.PathSeparator))]
cmd := exec.Command(filePath)
cmd.Dir = curDir
stdout, err := cmd.StdoutPipe()
if nil != err {
glog.Error(err)
2014-09-01 16:50:51 +04:00
data["succ"] = false
2014-08-22 07:57:05 +04:00
return
}
stderr, err := cmd.StderrPipe()
if nil != err {
glog.Error(err)
2014-09-01 16:50:51 +04:00
data["succ"] = false
2014-08-22 07:57:05 +04:00
return
}
reader := io.MultiReader(stdout, stderr)
cmd.Start()
2014-08-22 11:37:26 +04:00
channelRet := map[string]interface{}{}
2014-08-22 07:57:05 +04:00
go func(runningId int) {
glog.Infof("Session [%s] is running [id=%d, file=%s]", sid, runningId, filePath)
for {
buf := make([]byte, 1024)
count, err := reader.Read(buf)
if nil != err || 0 == count {
glog.Infof("Session [%s] 's running [id=%d, file=%s] has done", sid, runningId, filePath)
break
} else {
2014-08-22 11:37:26 +04:00
channelRet["output"] = string(buf[:count])
channelRet["cmd"] = "run"
2014-08-22 07:57:05 +04:00
if nil != outputWS[sid] {
2014-08-22 11:37:26 +04:00
err := outputWS[sid].WriteJSON(&channelRet)
2014-08-22 07:57:05 +04:00
if nil != err {
glog.Error(err)
break
}
}
}
}
}(rand.Int())
}
func BuildHandler(w http.ResponseWriter, r *http.Request) {
2014-09-01 16:50:51 +04:00
data := map[string]interface{}{"succ": true}
defer util.RetJSON(w, r, data)
2014-08-31 13:39:39 +04:00
session, _ := user.Session.Get(r, "wide-session")
2014-08-22 07:57:05 +04:00
sid := session.Values["id"].(string)
2014-09-02 20:26:10 +04:00
username := session.Values["username"].(string)
2014-08-22 07:57:05 +04:00
decoder := json.NewDecoder(r.Body)
var args map[string]interface{}
if err := decoder.Decode(&args); err != nil {
glog.Error(err)
2014-09-01 16:50:51 +04:00
data["succ"] = false
2014-08-22 07:57:05 +04:00
return
}
2014-08-18 17:45:43 +04:00
filePath := args["file"].(string)
2014-08-22 07:57:05 +04:00
curDir := filePath[:strings.LastIndex(filePath, string(os.PathSeparator))]
2014-08-18 17:45:43 +04:00
fout, err := os.Create(filePath)
if nil != err {
glog.Error(err)
2014-09-01 16:50:51 +04:00
data["succ"] = false
2014-08-18 17:45:43 +04:00
return
}
code := args["code"].(string)
fout.WriteString(code)
if err := fout.Close(); nil != err {
glog.Error(err)
2014-09-01 16:50:51 +04:00
data["succ"] = false
2014-08-18 17:45:43 +04:00
return
}
2014-08-22 07:57:05 +04:00
suffix := ""
if "windows" == runtime.GOOS {
suffix = ".exe"
}
executable := "main" + suffix
argv := []string{"build", "-o", executable, filePath}
2014-08-18 17:45:43 +04:00
cmd := exec.Command("go", argv...)
2014-08-22 07:57:05 +04:00
cmd.Dir = curDir
2014-08-28 06:19:00 +04:00
// 设置环境变量(设置当前用户的 GOPATH 等)
2014-09-02 20:26:10 +04:00
setCmdEnv(cmd, username)
2014-08-28 06:19:00 +04:00
2014-08-22 11:37:26 +04:00
glog.Infof("go build -o %s %s", executable, filePath)
executable = curDir + string(os.PathSeparator) + executable
// 先把可执行文件删了
2014-09-01 16:50:51 +04:00
err = os.RemoveAll(executable)
if nil != err {
glog.Info(err)
data["succ"] = false
2014-08-18 17:45:43 +04:00
2014-09-01 16:50:51 +04:00
return
}
2014-09-01 14:55:11 +04:00
2014-08-18 17:45:43 +04:00
stdout, err := cmd.StdoutPipe()
if nil != err {
glog.Error(err)
2014-09-01 14:55:11 +04:00
data["succ"] = false
2014-08-18 17:45:43 +04:00
return
}
stderr, err := cmd.StderrPipe()
if nil != err {
glog.Error(err)
2014-09-01 14:55:11 +04:00
data["succ"] = false
2014-08-18 17:45:43 +04:00
return
}
2014-09-01 16:50:51 +04:00
if data["succ"].(bool) {
reader := io.MultiReader(stdout, stderr)
2014-08-18 17:45:43 +04:00
2014-09-01 16:50:51 +04:00
cmd.Start()
2014-08-18 17:45:43 +04:00
2014-09-01 16:50:51 +04:00
go func(runningId int) {
glog.Infof("Session [%s] is building [id=%d, file=%s]", sid, runningId, filePath)
2014-08-18 17:45:43 +04:00
2014-09-01 16:50:51 +04:00
// 一次性读取
buf := make([]byte, 1024*8)
count, _ := reader.Read(buf)
2014-08-18 17:45:43 +04:00
2014-09-01 16:50:51 +04:00
channelRet := map[string]interface{}{}
2014-08-18 17:45:43 +04:00
2014-09-01 16:50:51 +04:00
channelRet["output"] = string(buf[:count])
channelRet["cmd"] = "build"
channelRet["nextCmd"] = "run"
channelRet["executable"] = executable
2014-08-18 17:45:43 +04:00
2014-09-01 16:50:51 +04:00
if nil != outputWS[sid] {
glog.Infof("Session [%s] 's build [id=%d, file=%s] has done", sid, runningId, filePath)
2014-08-22 07:57:05 +04:00
2014-09-01 16:50:51 +04:00
err := outputWS[sid].WriteJSON(&channelRet)
if nil != err {
glog.Error(err)
}
2014-08-18 17:45:43 +04:00
}
2014-09-01 16:50:51 +04:00
}(rand.Int())
}
2014-08-18 17:45:43 +04:00
}
2014-08-28 06:19:00 +04:00
2014-09-02 20:26:10 +04:00
func setCmdEnv(cmd *exec.Cmd, username string) {
userRepos := strings.Replace(conf.Wide.UserRepos, "{user}", username, -1)
userWorkspace := userRepos[:strings.LastIndex(userRepos, "/src")]
// glog.Infof("User [%s] workspace [%s]", username, userWorkspace)
masterWorkspace := conf.Wide.Repos[:strings.LastIndex(conf.Wide.Repos, "/src")]
// glog.Infof("Master workspace [%s]", masterWorkspace)
cmd.Env = append(cmd.Env,
2014-09-03 12:03:12 +04:00
"GOPATH="+GOPATH+string(os.PathListSeparator)+
userWorkspace+string(os.PathListSeparator)+
masterWorkspace,
2014-09-02 20:26:10 +04:00
"GOROOT="+os.Getenv("GOROOT"))
2014-08-28 06:19:00 +04:00
}