wide/output/outputs.go

220 lines
4.5 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-18 17:51:03 +04:00
"github.com/b3log/wide/session"
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) {
session, _ := session.Store.Get(r, "wide-session")
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) {
session, _ := session.Store.Get(r, "wide-session")
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)
http.Error(w, err.Error(), 500)
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)
http.Error(w, err.Error(), 500)
return
}
stderr, err := cmd.StderrPipe()
if nil != err {
glog.Error(err)
http.Error(w, err.Error(), 500)
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())
ret, _ := json.Marshal(map[string]interface{}{"succ": true})
w.Header().Set("Content-Type", "application/json")
w.Write(ret)
}
func BuildHandler(w http.ResponseWriter, r *http.Request) {
session, _ := session.Store.Get(r, "wide-session")
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)
http.Error(w, err.Error(), 500)
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)
http.Error(w, err.Error(), 500)
return
}
code := args["code"].(string)
fout.WriteString(code)
if err := fout.Close(); nil != err {
glog.Error(err)
http.Error(w, err.Error(), 500)
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 等)
setCmdEnv(cmd)
2014-08-22 11:37:26 +04:00
glog.Infof("go build -o %s %s", executable, filePath)
executable = curDir + string(os.PathSeparator) + executable
// 先把可执行文件删了
os.RemoveAll(executable)
2014-08-18 17:45:43 +04:00
stdout, err := cmd.StdoutPipe()
if nil != err {
glog.Error(err)
http.Error(w, err.Error(), 500)
return
}
stderr, err := cmd.StderrPipe()
if nil != err {
glog.Error(err)
http.Error(w, err.Error(), 500)
return
}
reader := io.MultiReader(stdout, stderr)
cmd.Start()
go func(runningId int) {
2014-08-22 07:57:05 +04:00
glog.Infof("Session [%s] is building [id=%d, file=%s]", sid, runningId, filePath)
2014-08-18 17:45:43 +04:00
2014-08-22 07:57:05 +04:00
// 一次性读取
buf := make([]byte, 1024*8)
count, _ := reader.Read(buf)
2014-08-18 17:45:43 +04:00
2014-08-22 07:57:05 +04:00
channelRet := map[string]interface{}{}
2014-08-18 17:45:43 +04:00
2014-08-22 07:57:05 +04:00
channelRet["output"] = string(buf[:count])
channelRet["cmd"] = "build"
channelRet["nextCmd"] = "run"
2014-08-22 11:37:26 +04:00
channelRet["executable"] = executable
2014-08-18 17:45:43 +04:00
2014-08-22 07:57:05 +04:00
if nil != outputWS[sid] {
glog.Infof("Session [%s] 's build [id=%d, file=%s] has done", sid, runningId, filePath)
err := outputWS[sid].WriteJSON(&channelRet)
if nil != err {
glog.Error(err)
2014-08-18 17:45:43 +04:00
}
}
2014-08-22 07:57:05 +04:00
2014-08-18 17:45:43 +04:00
}(rand.Int())
ret, _ := json.Marshal(map[string]interface{}{"succ": true})
w.Header().Set("Content-Type", "application/json")
w.Write(ret)
}
2014-08-28 06:19:00 +04:00
func setCmdEnv(cmd *exec.Cmd) {
2014-08-28 06:51:03 +04:00
// TODO: 使用用户自己的仓库路径设置 GOPATH
cmd.Env = append(cmd.Env, "GOPATH="+conf.Wide.Repos, "GOROOT="+os.Getenv("GOROOT"))
2014-08-28 06:19:00 +04:00
}