diff --git a/cmd/olliesrv/server.go b/cmd/olliesrv/server.go index a24e670..dc0d486 100644 --- a/cmd/olliesrv/server.go +++ b/cmd/olliesrv/server.go @@ -50,6 +50,7 @@ type fid struct { completeResult []byte // for /complete: result of last write (per-fid state) generateResult []byte // for /generate: result of last write (per-fid state) routeResult []byte // for /route: result of last write (per-fid state) + sessionResult []byte // for /session/new: session name from last write } // connState tracks all open fids for a single 9P connection. @@ -836,13 +837,19 @@ func (s *Server) read(cs *connState, fc *plan9.Fcall, ctx context.Context) *plan return s.readDNS(fc, &f.generateResult) } - // /route: return per-fid result from previous write (offset 0-based) - if path == "/route" { - s.log.Debug("Tread path=%q offset=%d count=%d", path, fc.Offset, fc.Count) - return s.readDNS(fc, &f.routeResult) - } +// /route: return per-fid result from previous write (offset 0-based) + if path == "/route" { + s.log.Debug("Tread path=%q offset=%d count=%d", path, fc.Offset, fc.Count) + return s.readDNS(fc, &f.routeResult) + } - s.log.Debug("Tread path=%q offset=%d count=%d", path, fc.Offset, fc.Count) + // /session/new: return per-fid result from previous write + if path == "/session/new" { + s.log.Debug("Tread path=%q offset=%d count=%d", path, fc.Offset, fc.Count) + return s.readDNS(fc, &f.sessionResult) + } + + s.log.Debug("Tread path=%q offset=%d count=%d", path, fc.Offset, fc.Count) entry, err := s.openEntry(path) if err != nil { return errFcall(fc, err.Error()) @@ -1010,11 +1017,22 @@ func (s *Server) write(cs *connState, fc *plan9.Fcall) *plan9.Fcall { if err != nil { return errFcall(fc, err.Error()) } - f.routeResult = []byte(fmt.Sprintf("backend=%s model=%s", result.Backend, result.Model)) - return &plan9.Fcall{Type: plan9.Rwrite, Tag: fc.Tag, Count: uint32(len(fc.Data))} - } +f.routeResult = []byte(fmt.Sprintf("backend=%s model=%s", result.Backend, result.Model)) + return &plan9.Fcall{Type: plan9.Rwrite, Tag: fc.Tag, Count: uint32(len(fc.Data))} + } - // Accumulate; the 9P client may split large writes across multiple Twrite messages. + // /session/new: synchronous create-session (per-fid state, like /net/dns) + if f.path == "/session/new" { + cs.mu.Unlock() + name, err := fs.CreateFromRoot(s.sessionTree, strings.Fields(strings.TrimSpace(string(fc.Data)))) + if err != nil { + return errFcall(fc, err.Error()) + } + f.sessionResult = []byte(name) + return &plan9.Fcall{Type: plan9.Rwrite, Tag: fc.Tag, Count: uint32(len(fc.Data))} + } + + // Accumulate; the 9P client may split large writes across multiple Twrite messages. end := int(fc.Offset) + len(fc.Data) if end > len(f.writeBuf) { grown := make([]byte, end) diff --git a/fs/session/root.go b/fs/session/root.go index 16c0e45..27c794a 100644 --- a/fs/session/root.go +++ b/fs/session/root.go @@ -422,28 +422,19 @@ func rootOpen(rs *rootState, name string) (File, error) { }, IsBlocking_: true, }, nil -case "new": - var sessResult string - return &FileConfig{ - StatFn: func() (os.FileInfo, error) { - return &SyntheticFileInfo{Name_: "new", Mode_: Perms[PathSessions].Files["new"]}, nil - }, - ReadFn: func() ([]byte, error) { - if sessResult != "" { - return []byte(sessResult + "\n"), nil - } - return []byte("name=\n"), nil - }, - WriteFn: func(data []byte) error { - name, err := Create(rs, strings.Fields(strings.TrimSpace(string(data)))) - if err != nil { - return err - } - sessResult = name - return nil - }, - BlockingReadFn: notBlocking, - }, nil + case "new": + return &FileConfig{ + StatFn: func() (os.FileInfo, error) { + return &SyntheticFileInfo{Name_: "new", Mode_: Perms[PathSessions].Files["new"]}, nil + }, + ReadFn: func() ([]byte, error) { + return []byte("name=\n"), nil + }, + WriteFn: func(data []byte) error { + return fmt.Errorf("use ollie-9p rdwr session/new") + }, + BlockingReadFn: notBlocking, + }, nil case "idx": return &FileConfig{ StatFn: func() (os.FileInfo, error) { @@ -472,30 +463,30 @@ case "new": if len(parts) == 2 { return nil, fmt.Errorf("%s: is a directory", name) } -if len(parts) >= 3 && parts[2] == "new" { - if len(parts) == 3 { - // agent/new — request-response file to create an agent - var agentResult string - return &FileConfig{ - StatFn: func() (os.FileInfo, error) { - return &SyntheticFileInfo{Name_: "new", Mode_: Perms[PathSessionFile].Files["new"]}, nil - }, - ReadFn: func() ([]byte, error) { - if agentResult != "" { - return []byte(agentResult + "\n"), nil - } - return []byte("cwd=\nbackend=\nmodel=\nagent=\nagent_alias=\nremote=\nsystem_prompt=\n"), nil - }, - WriteFn: func(data []byte) error { - if err := CreateAgent(rs, sessID, strings.Fields(strings.TrimSpace(string(data)))); err != nil { - return err - } - agentResult = "ok" - return nil - }, - BlockingReadFn: notBlocking, - }, nil - } + if len(parts) >= 3 && parts[2] == "new" { + if len(parts) == 3 { + // agent/new — request-response file to create an agent + var agentResult string + return &FileConfig{ + StatFn: func() (os.FileInfo, error) { + return &SyntheticFileInfo{Name_: "new", Mode_: Perms[PathSessionFile].Files["new"]}, nil + }, + ReadFn: func() ([]byte, error) { + if agentResult != "" { + return []byte(agentResult + "\n"), nil + } + return []byte("cwd=\nbackend=\nmodel=\nagent=\nagent_alias=\nremote=\nsystem_prompt=\n"), nil + }, + WriteFn: func(data []byte) error { + if err := CreateAgent(rs, sessID, strings.Fields(strings.TrimSpace(string(data)))); err != nil { + return err + } + agentResult = "ok" + return nil + }, + BlockingReadFn: notBlocking, + }, nil + } return nil, fmt.Errorf("%s: not a file", name) } if len(parts) < 4 {