func (c Console) handle(r *byteio.StickyReader, w *byteio.StickyWriter) error { id := int(r.ReadInt32()) if r.Err != nil { return r.Err } s := c.c.c.Server(id) if s == nil { return ErrUnknownServer } s.RLock() //Needed? Path never gets changed! p := s.Path s.RUnlock() var ( f *os.File err error logPath string ) for _, lp := range logPaths { logPath = path.Join(p, lp) f, err = os.Open(logPath) if err == nil { break } } if f == nil { return errors.New("unable to open log file") } defer func() { f.Close() }() fsw, err := fsnotify.NewWatcher() if err != nil { return err } logDir := path.Dir(logPath) fsw.Add(logDir) defer fsw.Remove(logDir) pw := partWriter{w} io.Copy(pw, f) if w.Err != nil { return w.Err } t := time.NewTimer(time.Second * 10) for { select { case ev := <-fsw.Events: switch ev.Op { case fsnotify.Create: if ev.Name == logPath { f, err = os.Open(logPath) if err != nil { return err } } case fsnotify.Write: if ev.Name == logPath { io.Copy(pw, f) if w.Err != nil { return w.Err } } case fsnotify.Remove: if ev.Name == logPath { f.Close() } } case err = <-fsw.Errors: case <-t.C: w.WriteUint8(2) //ping if w.Err != nil { return w.Err } } t.Reset(time.Second * 10) } }
func transferFile(typeName, method string, typeID uint8, o *overlay.Overlay) dom.Node { name := xform.InputText("name", "") url := xform.InputRadio("url", "switch", true) upload := xform.InputRadio("upload", "switch", false) fileI := xform.InputUpload("") urlI := xform.InputURL("", "") s := xform.InputSubmit(method) name.Required = true typeFunc := func(dom.Event) { if url.Checked { urlI.Style().RemoveProperty("display") fileI.Style().SetProperty("display", "none", "") urlI.Required = true fileI.Required = false fileI.SetID("") urlI.SetID("file") } else { fileI.Style().RemoveProperty("display") urlI.Style().SetProperty("display", "none", "") fileI.Required = true urlI.Required = false urlI.SetID("") fileI.SetID("file") } } typeFunc(nil) url.AddEventListener("change", false, typeFunc) upload.AddEventListener("change", false, typeFunc) f := xjs.AppendChildren(xdom.Form(), xjs.AppendChildren(xdom.Fieldset(), xjs.SetInnerText(xdom.Legend(), method+" "+typeName), xform.Label(typeName+" Name", "name"), name, xdom.Br(), xform.Label("URL", "url"), url, xdom.Br(), xform.Label("Upload", "upload"), upload, xdom.Br(), xform.Label("File", "file"), fileI, urlI, xdom.Br(), s, )) s.AddEventListener("click", false, func(e dom.Event) { if name.Value == "" { return } if url.Checked { if urlI.Value == "" { return } } else if len(fileI.Files()) != 1 { return } s.Disabled = true name.Disabled = true url.Disabled = true upload.Disabled = true fileI.Disabled = true urlI.Disabled = true e.PreventDefault() go func() { d := xdom.Div() uo := overlay.New(d) uo.OnClose(func() { o.Close() }) xjs.Body().AppendChild(uo) status := xdom.Div() d.AppendChild(xjs.SetInnerText(status, "Transferring...")) conn, err := websocket.Dial("ws://" + js.Global.Get("location").Get("host").String() + "/transfer") if err != nil { xjs.SetInnerText(status, err.Error()) return } defer conn.Close() w := byteio.StickyWriter{Writer: byteio.LittleEndianWriter{Writer: conn}} r := byteio.StickyReader{Reader: byteio.LittleEndianReader{Reader: conn}} pb := progress.New(color.RGBA{255, 0, 0, 0}, color.RGBA{0, 0, 255, 0}, 400, 50) d.AppendChild(pb) if url.Checked { w.WriteUint8(typeID << 1) data.WriteString(&w, urlI.Value) length := int(r.ReadInt32()) total := 0 for total < length { switch v := r.ReadUint8(); v { case 1: i := int(r.ReadInt32()) total += i pb.Percent(100 * total / length) default: xjs.SetInnerText(status, ReadError(&r).Error()) return } } } else { f := files.NewFileReader(files.NewFile(fileI.Files()[0])) l := f.Len() if l == 0 { xjs.SetInnerText(status, "Zero-length file") return } w.WriteUint8(typeID<<1 | 1) w.WriteInt32(int32(l)) io.Copy(&w, pb.Reader(f, l)) } d.RemoveChild(pb) xjs.SetInnerText(status, "Checking File") data.WriteString(&w, name.Value) var ctx *dom.CanvasRenderingContext2D for { switch v := r.ReadUint8(); v { case 0: if r.Err != nil { xjs.SetInnerText(status, r.Err.Error()) } else { xjs.SetInnerText(status, ReadError(&r).Error()) } return case 1: files := make([]xform.Option, r.ReadInt16()) for i := range files { files[i] = xform.Option{ Value: strconv.Itoa(i), Label: data.ReadString(&r), } } j := xform.SelectBox("files", files...) sel := xjs.SetInnerText(xdom.Button(), "Select") fo := overlay.New(xjs.AppendChildren(xdom.Div(), xjs.AppendChildren(xdom.Fieldset(), xjs.SetInnerText(xdom.Legend(), "Please select the "+typeName+" file"), xform.Label("File", "files"), j, xdom.Br(), sel, ))) c := make(chan int16, 0) done := false fo.OnClose(func() { if !done { done = true c <- -1 } }) sel.AddEventListener("click", false, func(dom.Event) { if !done { done = true v, err := strconv.Atoi(j.Value) if err != nil { v = -1 } c <- int16(v) fo.Close() } }) xjs.Body().AppendChild(fo) w.WriteInt16(<-c) close(c) case 2: w := r.ReadInt32() h := r.ReadInt32() canvas := xdom.Canvas() canvas.Width = int(w) * 8 canvas.Height = int(h) * 8 d.AppendChild(canvas) ctx = canvas.GetContext2d() ctx.Scale(8, 8) case 3: xjs.SetInnerText(status, data.ReadString(&r)) case 4: x := r.ReadInt32() y := r.ReadInt32() red := r.ReadUint8() green := r.ReadUint8() blue := r.ReadUint8() alpha := r.ReadUint8() ctx.FillStyle = "rgba(" + strconv.Itoa(int(red)) + ", " + strconv.Itoa(int(green)) + ", " + strconv.Itoa(int(blue)) + ", " + strconv.FormatFloat(float64(alpha)/255, 'f', -1, 32) + ")" ctx.FillRect(int(x), int(y), 1, 1) case 255: uo.Close() return } } }() }) return f }