package web
import (
)
var Program prog.Program = program{}
type program struct{}
func (program) ( *prog.Flags) bool { return .Web }
func (program) ( [3]*os.File, *prog.Flags, []string) error {
if len() > 0 {
return prog.BadUsage("arguments are not allowed with -web")
}
if .CodeInArg {
return prog.BadUsage("-c cannot be used together with -web")
}
:= Web{BinPath: .Bin, SockPath: .Sock, DbPath: .DB, Port: .Port}
return .Main(, nil)
}
type Web struct {
BinPath string
SockPath string
DbPath string
Port int
}
type httpHandler struct {
ev *eval.Evaler
}
type ExecuteResponse struct {
OutBytes string
OutValues []interface{}
ErrBytes string
Err string
}
func ( *Web) ( [3]*os.File, []string) error {
:= shell.MakePaths([2],
shell.Paths{Bin: .BinPath, Sock: .SockPath, Db: .DbPath})
:= shell.InitRuntime([2], , true)
defer shell.CleanupRuntime([2], )
:= httpHandler{}
http.HandleFunc("/", .handleMainPage)
http.HandleFunc("/execute", .handleExecute)
:= fmt.Sprintf("localhost:%d", .Port)
log.Println("going to listen", )
:= http.ListenAndServe(, nil)
log.Println()
return nil
}
func ( httpHandler) ( http.ResponseWriter, *http.Request) {
, := .Write([]byte(mainPageHTML))
if != nil {
log.Println("cannot write response:", )
}
}
func ( httpHandler) ( http.ResponseWriter, *http.Request) {
, := ioutil.ReadAll(.Body)
if != nil {
log.Println("cannot read request body:", )
return
}
:= string()
, , , := evalAndCollect(.ev, )
:= ""
if != nil {
= .Error()
}
, := json.Marshal(
&ExecuteResponse{string(), , string(), })
if != nil {
log.Println("cannot marshal response body:", )
}
_, = .Write()
if != nil {
log.Println("cannot write response:", )
}
}
const (
outFileBufferSize = 1024
outChanBufferSize = 32
)
func ( *eval.Evaler, string) (
[]byte, []interface{}, []byte, error) {
, := makeBytesWriterAndCollect()
, := makeValuesWriterAndCollect()
, := makeBytesWriterAndCollect()
:= []*eval.Port{
eval.DummyInputPort,
{File: , Chan: },
{File: , Chan: eval.BlackholeChan},
}
= .Eval(
parse.Source{Name: "[web]", Code: }, eval.EvalCfg{Ports: })
.Close()
close()
.Close()
return <-, <-, <-,
}
func () (*os.File, <-chan []byte) {
, , := os.Pipe()
if != nil {
panic()
}
:= make(chan []byte)
go func() {
var (
[]byte
[outFileBufferSize]byte
)
for {
, := .Read([:])
= append(, [:]...)
if != nil {
if != io.EOF {
log.Println("error when reading output pipe:", )
}
break
}
}
.Close()
<-
}()
return ,
}
func () (chan interface{}, <-chan []interface{}) {
:= make(chan interface{}, outChanBufferSize)
:= make(chan []interface{})
go func() {
var []interface{}
for {
for := range {
= append(, )
}
<-
}
}()
return ,
}