예제 #1
0
파일: htmod.go 프로젝트: smillaedler/lab
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"})
}
예제 #2
0
파일: htmod.go 프로젝트: smillaedler/lab
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)
}
예제 #3
0
파일: otdocs.go 프로젝트: napsy/lab
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)
	}
}
예제 #4
0
파일: htmod.go 프로젝트: napsy/lab
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)
	}
}
예제 #5
0
파일: htmod.go 프로젝트: smillaedler/lab
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)
	}
}
예제 #6
0
파일: otdocs.go 프로젝트: napsy/lab
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)
	}
}
예제 #7
0
파일: actions.go 프로젝트: sbinet/lab
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
	}
}