func (mod *htmod) stat(path string) (hub.Msg, error) { res := apiRes{ws.NewId(path), path, false} if r := mod.ws.Res(res.Id); r != nil { r.Lock() defer r.Unlock() res.Name, res.IsDir = r.Name, r.Flag&ws.FlagDir != 0 if r.Dir != nil { cs := make([]apiRes, 0, len(r.Children)) for _, c := range r.Children { if c.Flag&ws.FlagIgnore == 0 { cs = append(cs, apiRes{ c.Id, c.Name, c.Flag&ws.FlagDir != 0, }) } } return hub.Marshal("stat", struct { apiRes Path string Children []apiRes }{res, path, cs}) } return hub.Marshal("stat", struct { apiRes Path string }{res, path}) } return hub.Marshal("stat.err", struct { apiRes Path string Error string }{res, path, "not found"}) }
func (mod *htmod) route(m hub.Msg, id hub.Id) { var ( err error msg hub.Msg ) switch m.Head { case hub.Signon: // send reports for all working packages msg, err = hub.Marshal("reports", mod.src.AllReports()) case "stat": var path string if err = m.Unmarshal(&path); err != nil { break } msg, err = mod.stat(path) case "subscribe", "unsubscribe", "revise", "publish": mod.docroute(m, id) return case "complete", "format": mod.actionRoute(m, id) return default: msg, err = hub.Marshal("unknown", m.Head) } if err != nil { log.Println(err) return } mod.SendMsg(msg, id) }
func (mod *htmod) Handle(op ws.Op, r *ws.Res) { if op&(ws.Modify|ws.Delete) == 0 { return } if r.Flag&(ws.FlagIgnore|ws.FlagDir) != 0 { return } mod.docs.RLock() _, found := mod.docs.all[r.Id] mod.docs.RUnlock() if !found { return } mod.docs.Lock() defer mod.docs.Unlock() doc := mod.docs.all[r.Id] if doc == nil { return } doc.Lock() defer doc.Unlock() // delete doc if op&ws.Delete != 0 { mod.Hub.Del <- doc delete(mod.docs.all, doc.Id) msg, err := hub.Marshal("unsubscribe", apiRev{ Id: r.Id, User: DocGroup, }) if err != nil { fmt.Println(err) return } for _, cid := range doc.group { mod.Hub.SendMsg(msg, cid) } return } // update from filesystem data, err := ioutil.ReadFile(r.Path()) if err != nil { fmt.Println(err) return } rev := doc.Rev() ops := doc.diffops(data) if ops != nil { mod.handlerev("revise", apiRev{Id: r.Id, Rev: rev, Ops: ops}, doc) } }
func (mod *htmod) Run() { mod.Hub = hub.New() mod.docs = &docs{all: make(map[ws.Id]*otdoc)} go func() { for e := range mod.Hub.Route { mod.route(e.Msg, e.From) } }() mod.src.SignalReports(func(r *gosrc.Report) { m, err := hub.Marshal("report", r) if err != nil { log.Println(err) return } mod.SendMsg(m, hub.Group) }) http.Handle("/ws", mod.Hub) var err error server := &http.Server{ Addr: mod.conf.Addr, } if mod.conf.Https { if mod.conf.CAFile != "" { pemByte, err := ioutil.ReadFile(mod.conf.CAFile) if err != nil { log.Fatalf("reading ca file:\n\t%s\n", err) } block, _ := pem.Decode(pemByte) cert, err := x509.ParseCertificate(block.Bytes) if err != nil { log.Fatalf("parsing ca file:\n\t%s\n", err) } pool := x509.NewCertPool() pool.AddCert(cert) server.TLSConfig = &tls.Config{ ClientAuth: tls.RequireAndVerifyClientCert, ClientCAs: pool, CipherSuites: ciphers, } } err = server.ListenAndServeTLS(mod.conf.CertFile, mod.conf.KeyFile) } else { err = server.ListenAndServe() } if err != nil { log.Fatalf("http %s\n", err) } }
func (mod *htmod) Run() { mod.Hub = hub.New() mod.docs = &docs{all: make(map[ws.Id]*otdoc)} go func() { for e := range mod.Hub.Route { mod.route(e.Msg, e.From) } }() mod.src.SignalReports(func(r *gosrc.Report) { m, err := hub.Marshal("report", r) if err != nil { log.Println(err) return } mod.SendMsg(m, hub.Group) }) http.Handle("/ws", mod.Hub) err := http.ListenAndServe(mod.addr, nil) if err != nil { log.Fatalf("http %s\n", err) } }
func (mod *htmod) handlerev(head string, rev apiRev, doc *otdoc) { var m hub.Msg var err error to := rev.User if doc == nil { if head != "subscribe" { log.Println("doc not found") return } r := mod.ws.Res(rev.Id) if r == nil { log.Println("res not found") return } if r.Flag&(ws.FlagIgnore|ws.FlagDir) != 0 { log.Println("ignored or dir") return } path := r.Path() data, err := ioutil.ReadFile(path) if err != nil { log.Println(err) return } doc = &otdoc{Id: rev.Id, Path: path, Server: &ot.Server{}} doc.Lock() defer doc.Unlock() doc.Doc = (*ot.Doc)(&data) mod.docs.all[doc.Id] = doc mod.Hub.Add <- doc } switch head { case "subscribe": doc.group = append(doc.group, rev.User) m, err = hub.Marshal("subscribe", apiRev{ Id: rev.Id, Rev: doc.Rev(), Ops: ot.Ops{ot.Op{S: string(*doc.Doc)}}, User: rev.User, }) case "unsubscribe": for i, cid := range doc.group { if cid != rev.User { continue } doc.group = append(doc.group[:i], doc.group[i+1:]...) if len(doc.group) == 0 { mod.Hub.Del <- doc } break } m, err = hub.Marshal("unsubscribe", apiRev{ Id: rev.Id, }) case "revise": ops, err := doc.Recv(rev.Rev, rev.Ops) if err != nil { to = rev.User m, err = hub.Marshal("revise.err", struct { apiRev Err error }{rev, err}) break } to = doc.GroupId() m, err = hub.Marshal("revise", apiRev{ Id: rev.Id, Rev: doc.Rev(), Ops: ops, User: rev.User, }) case "publish": // write to file var f *os.File f, err = os.OpenFile(doc.Path, os.O_WRONLY|os.O_TRUNC, 0) if err != nil { break } var n int data := ([]byte)(*doc.Doc) n, err = f.Write(data) f.Close() if err != nil { break } if n < len(data) { log.Println("short write") return } to = doc.GroupId() m, err = hub.Marshal("publish", apiRev{ Id: rev.Id, Rev: doc.Rev(), User: rev.User, }) } if err != nil { log.Println(err) return } if to != 0 { mod.SendMsg(m, to) } }
func (mod *htmod) actionRoute(m hub.Msg, from hub.Id) { var req actionReq err := m.Unmarshal(&req) if err != nil { log.Println(err) return } mod.docs.RLock() doc, found := mod.docs.all[req.Id] mod.docs.RUnlock() if !found { log.Println("no document open with id", req) return } if pl := len(doc.Path); pl < 3 || doc.Path[pl-3:] != ".go" { log.Println("document not a go file", doc.Path) return } switch { case m.Head == "complete" && gocode != "": cmd := &exec.Cmd{ Path: gocode, Args: []string{ "gocode", "-f=json", "autocomplete", fmt.Sprint(req.Offs), }, } var buf bytes.Buffer doc.Lock() buf.Write(([]byte)(*doc.Doc)) doc.Unlock() cmd.Stdin = &buf data, err := cmd.CombinedOutput() if err != nil { log.Println(err, data) return } if len(data) < 10 { return } data = data[4 : len(data)-1] m, err = hub.Marshal("complete", struct { actionReq Proposed *json.RawMessage }{req, (*json.RawMessage)(&data)}) if err != nil { log.Println(err) return } mod.SendMsg(m, from) case m.Head == "format": doc.Lock() defer doc.Unlock() data, err := format.Source(([]byte)(*doc.Doc)) if err != nil { log.Println(err, data) } rev := doc.Rev() ops := doc.diffops(data) if ops != nil { mod.handlerev("revise", apiRev{Id: req.Id, Rev: rev, Ops: ops}, doc) } return default: log.Println("unexpected msg", m.Head) return } }