9p: remove all peer code
Peers were removed from core but lingered in the 9P layer. Deleted: PeerAdd, PeerRemove, PeerList, PeerSubmit (D-Bus + manager), peer directory listing, peer file handling, peer stat, peer creation/removal, HasPeer, peers field on Session.
This commit is contained in:
parent
aeef7ff718
commit
82a7f585f2
34
dbus.go
34
dbus.go
|
|
@ -476,36 +476,6 @@ func (a *DBusAdapter) ListAgents() ([]string, *dbus.Error) {
|
||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Peers ---
|
|
||||||
|
|
||||||
func (a *DBusAdapter) PeerAdd(sessionID, peerID string) (bool, *dbus.Error) {
|
|
||||||
if err := a.mgr.PeerAdd(sessionID, peerID); err != nil {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *DBusAdapter) PeerRemove(sessionID, peerID string) (bool, *dbus.Error) {
|
|
||||||
if err := a.mgr.PeerRemove(sessionID, peerID); err != nil {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *DBusAdapter) PeerList(sessionID string) ([]string, *dbus.Error) {
|
|
||||||
peers, err := a.mgr.PeerList(sessionID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, nil
|
|
||||||
}
|
|
||||||
return peers, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (a *DBusAdapter) PeerSubmit(sessionID, peerID, prompt string) (bool, *dbus.Error) {
|
|
||||||
if err := a.mgr.PeerSubmit(sessionID, peerID, prompt); err != nil {
|
|
||||||
return false, nil
|
|
||||||
}
|
|
||||||
return true, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Detached processes ---
|
// --- Detached processes ---
|
||||||
|
|
||||||
|
|
@ -737,10 +707,6 @@ var introspectXML = `<node>
|
||||||
<method name="ListModelsByBackend"><arg direction="in" type="s" name="backend"/><arg direction="out" type="as"/></method>
|
<method name="ListModelsByBackend"><arg direction="in" type="s" name="backend"/><arg direction="out" type="as"/></method>
|
||||||
<method name="ListModels"><arg direction="in" type="s" name="sessionID"/><arg direction="out" type="as"/></method>
|
<method name="ListModels"><arg direction="in" type="s" name="sessionID"/><arg direction="out" type="as"/></method>
|
||||||
<method name="ListAgents"><arg direction="out" type="as"/></method>
|
<method name="ListAgents"><arg direction="out" type="as"/></method>
|
||||||
<method name="PeerAdd"><arg direction="in" type="s" name="sessionID"/><arg direction="in" type="s" name="peerID"/><arg direction="out" type="b"/></method>
|
|
||||||
<method name="PeerRemove"><arg direction="in" type="s" name="sessionID"/><arg direction="in" type="s" name="peerID"/><arg direction="out" type="b"/></method>
|
|
||||||
<method name="PeerList"><arg direction="in" type="s" name="sessionID"/><arg direction="out" type="as"/></method>
|
|
||||||
<method name="PeerSubmit"><arg direction="in" type="s" name="sessionID"/><arg direction="in" type="s" name="peerID"/><arg direction="in" type="s" name="prompt"/><arg direction="out" type="b"/></method>
|
|
||||||
<method name="DetachProcess"><arg direction="in" type="s" name="sessionID"/><arg direction="out" type="b"/></method>
|
<method name="DetachProcess"><arg direction="in" type="s" name="sessionID"/><arg direction="out" type="b"/></method>
|
||||||
<method name="ListDetached"><arg direction="in" type="s" name="sessionID"/><arg direction="out" type="as"/></method>
|
<method name="ListDetached"><arg direction="in" type="s" name="sessionID"/><arg direction="out" type="as"/></method>
|
||||||
<method name="SignalDetached"><arg direction="in" type="s" name="sessionID"/><arg direction="in" type="i" name="pid"/><arg direction="in" type="s" name="signal"/><arg direction="out" type="b"/></method>
|
<method name="SignalDetached"><arg direction="in" type="s" name="sessionID"/><arg direction="in" type="i" name="pid"/><arg direction="in" type="s" name="signal"/><arg direction="out" type="b"/></method>
|
||||||
|
|
|
||||||
151
mgr/manager.go
151
mgr/manager.go
|
|
@ -183,112 +183,9 @@ func (s *Manager) Readdir(name string) ([]os.DirEntry, error) {
|
||||||
return entries, nil
|
return entries, nil
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// {id}/peer — list peer session IDs
|
|
||||||
if len(parts) == 2 && parts[1] == "peer" {
|
|
||||||
peers, _ := s.PeerList(sessID)
|
|
||||||
entries := make([]os.DirEntry, len(peers))
|
|
||||||
for i, p := range peers {
|
|
||||||
entries[i] = fs.FileEntry(p, 0666)
|
|
||||||
}
|
|
||||||
return entries, nil
|
|
||||||
}
|
|
||||||
return nil, fmt.Errorf("%s: not a directory", name)
|
return nil, fmt.Errorf("%s: not a directory", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Peer Management ---
|
|
||||||
|
|
||||||
// PeerAdd creates a bidirectional peer link between two sessions.
|
|
||||||
func (s *Manager) PeerAdd(sessID, peerID string) error {
|
|
||||||
s.mu.RLock()
|
|
||||||
sess, ok := s.sessions[sessID]
|
|
||||||
peer, peerOk := s.sessions[peerID]
|
|
||||||
s.mu.RUnlock()
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("session not found: %s", sessID)
|
|
||||||
}
|
|
||||||
if !peerOk {
|
|
||||||
return fmt.Errorf("peer session not found: %s", peerID)
|
|
||||||
}
|
|
||||||
if sessID == peerID {
|
|
||||||
return fmt.Errorf("cannot peer a session with itself")
|
|
||||||
}
|
|
||||||
|
|
||||||
sess.mu.Lock()
|
|
||||||
if sess.peers == nil {
|
|
||||||
sess.peers = make(map[string]bool)
|
|
||||||
}
|
|
||||||
sess.peers[peerID] = true
|
|
||||||
sess.mu.Unlock()
|
|
||||||
|
|
||||||
peer.mu.Lock()
|
|
||||||
if peer.peers == nil {
|
|
||||||
peer.peers = make(map[string]bool)
|
|
||||||
}
|
|
||||||
peer.peers[sessID] = true
|
|
||||||
peer.mu.Unlock()
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PeerRemove removes a bidirectional peer link between two sessions.
|
|
||||||
func (s *Manager) PeerRemove(sessID, peerID string) error {
|
|
||||||
s.mu.RLock()
|
|
||||||
sess, ok := s.sessions[sessID]
|
|
||||||
peer, peerOk := s.sessions[peerID]
|
|
||||||
s.mu.RUnlock()
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("session not found: %s", sessID)
|
|
||||||
}
|
|
||||||
|
|
||||||
sess.mu.Lock()
|
|
||||||
delete(sess.peers, peerID)
|
|
||||||
sess.mu.Unlock()
|
|
||||||
|
|
||||||
if peerOk {
|
|
||||||
peer.mu.Lock()
|
|
||||||
delete(peer.peers, sessID)
|
|
||||||
peer.mu.Unlock()
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PeerList returns the peer session IDs for a session.
|
|
||||||
func (s *Manager) PeerList(sessID string) ([]string, error) {
|
|
||||||
s.mu.RLock()
|
|
||||||
sess, ok := s.sessions[sessID]
|
|
||||||
s.mu.RUnlock()
|
|
||||||
if !ok {
|
|
||||||
return nil, fmt.Errorf("session not found: %s", sessID)
|
|
||||||
}
|
|
||||||
sess.mu.RLock()
|
|
||||||
result := make([]string, 0, len(sess.peers))
|
|
||||||
for id := range sess.peers {
|
|
||||||
result = append(result, id)
|
|
||||||
}
|
|
||||||
sess.mu.RUnlock()
|
|
||||||
return result, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// PeerSubmit sends a prompt to a peer session.
|
|
||||||
func (s *Manager) PeerSubmit(sessID, peerID, prompt string) error {
|
|
||||||
s.mu.RLock()
|
|
||||||
sess, ok := s.sessions[sessID]
|
|
||||||
peer, peerOk := s.sessions[peerID]
|
|
||||||
s.mu.RUnlock()
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("session not found: %s", sessID)
|
|
||||||
}
|
|
||||||
if !peerOk {
|
|
||||||
return fmt.Errorf("peer session not found: %s", peerID)
|
|
||||||
}
|
|
||||||
sess.mu.RLock()
|
|
||||||
isPeer := sess.peers[peerID]
|
|
||||||
sess.mu.RUnlock()
|
|
||||||
if !isPeer {
|
|
||||||
return fmt.Errorf("%s is not a peer of %s", peerID, sessID)
|
|
||||||
}
|
|
||||||
go peer.Core.Agent().Submit(peer.Ctx, prompt)
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Manager) stat(name string) (os.FileInfo, error) {
|
func (s *Manager) stat(name string) (os.FileInfo, error) {
|
||||||
// Top-level fixed files (new, idx, sh, etc.)
|
// Top-level fixed files (new, idx, sh, etc.)
|
||||||
|
|
@ -326,21 +223,6 @@ func (s *Manager) stat(name string) (os.FileInfo, error) {
|
||||||
}
|
}
|
||||||
return afs.Stat(parts[3])
|
return afs.Stat(parts[3])
|
||||||
}
|
}
|
||||||
// Peer directory: {id}/peer
|
|
||||||
if parts[1] == "peer" {
|
|
||||||
if len(parts) == 2 {
|
|
||||||
return &fs.SyntheticFileInfo{Name_: "peer", Mode_: 0755, IsDir_: true}, nil
|
|
||||||
}
|
|
||||||
// Peer file: {id}/peer/{peer-id}
|
|
||||||
peerID := parts[2]
|
|
||||||
sess.mu.RLock()
|
|
||||||
isPeer := sess.peers[peerID]
|
|
||||||
sess.mu.RUnlock()
|
|
||||||
if !isPeer {
|
|
||||||
return nil, fmt.Errorf("%s: not found", name)
|
|
||||||
}
|
|
||||||
return &fs.SyntheticFileInfo{Name_: peerID, Mode_: 0666}, nil
|
|
||||||
}
|
|
||||||
// Session file: {id}/{file} (plan, env)
|
// Session file: {id}/{file} (plan, env)
|
||||||
sfs, err := s.openSessionTree(sess)
|
sfs, err := s.openSessionTree(sess)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -353,8 +235,6 @@ func (s *Manager) openEntry(name string) (fs.File, error) {
|
||||||
notBlocking := func(context.Context, string) ([]byte, string, error) {
|
notBlocking := func(context.Context, string) ([]byte, string, error) {
|
||||||
return nil, "", fmt.Errorf("blocking read not supported")
|
return nil, "", fmt.Errorf("blocking read not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
// Peer file: {id}/peer/{peer-id} — write submits prompt to peer
|
|
||||||
parts := strings.SplitN(name, "/", 3)
|
parts := strings.SplitN(name, "/", 3)
|
||||||
|
|
||||||
// Proc file: {id}/proc/{pid} — read returns ring buffer output
|
// Proc file: {id}/proc/{pid} — read returns ring buffer output
|
||||||
|
|
@ -385,28 +265,6 @@ func (s *Manager) openEntry(name string) (fs.File, error) {
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(parts) == 3 && parts[1] == "peer" {
|
|
||||||
sessID := parts[0]
|
|
||||||
peerID := parts[2]
|
|
||||||
return &fs.FileConfig{
|
|
||||||
StatFn: func() (os.FileInfo, error) {
|
|
||||||
return &fs.SyntheticFileInfo{Name_: peerID, Mode_: 0666}, nil
|
|
||||||
},
|
|
||||||
ReadFn: func() ([]byte, error) {
|
|
||||||
return nil, nil // empty read
|
|
||||||
},
|
|
||||||
WriteFn: func(data []byte) error {
|
|
||||||
prompt := strings.TrimSpace(string(data))
|
|
||||||
if prompt == "" {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
return s.PeerSubmit(sessID, peerID, prompt)
|
|
||||||
},
|
|
||||||
BlockingReadFn: notBlocking,
|
|
||||||
}, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Top-level fixed files.
|
|
||||||
switch name {
|
switch name {
|
||||||
case "new":
|
case "new":
|
||||||
return &fs.FileConfig{
|
return &fs.FileConfig{
|
||||||
|
|
@ -478,11 +336,6 @@ func (s *Manager) openEntry(name string) (fs.File, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Manager) create(name string) error {
|
func (s *Manager) create(name string) error {
|
||||||
// Peer creation: {id}/peer/{peer-id}
|
|
||||||
parts := strings.SplitN(name, "/", 3)
|
|
||||||
if len(parts) == 3 && parts[1] == "peer" {
|
|
||||||
return s.PeerAdd(parts[0], parts[2])
|
|
||||||
}
|
|
||||||
return fmt.Errorf("create not supported: %s", name)
|
return fmt.Errorf("create not supported: %s", name)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -500,10 +353,6 @@ func (s *Manager) del(name string) error {
|
||||||
}
|
}
|
||||||
return fmt.Errorf("session not found: %s", sessID)
|
return fmt.Errorf("session not found: %s", sessID)
|
||||||
}
|
}
|
||||||
// Peer removal: {id}/peer/{peer-id}
|
|
||||||
if len(parts) == 3 && parts[1] == "peer" {
|
|
||||||
return s.PeerRemove(sessID, parts[2])
|
|
||||||
}
|
|
||||||
// Proc dismiss: {id}/proc/{pid}
|
// Proc dismiss: {id}/proc/{pid}
|
||||||
if len(parts) == 3 && parts[1] == "proc" {
|
if len(parts) == 3 && parts[1] == "proc" {
|
||||||
sess := s.Session(sessID)
|
sess := s.Session(sessID)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ type Session struct {
|
||||||
ChatOffset int
|
ChatOffset int
|
||||||
plan []byte
|
plan []byte
|
||||||
prevPrompt []byte // last submitted prompt; overwritten on each new submission
|
prevPrompt []byte // last submitted prompt; overwritten on each new submission
|
||||||
peers map[string]bool // peer session IDs (bidirectional links)
|
|
||||||
remote string // SSH target for remote execution (empty = local)
|
remote string // SSH target for remote execution (empty = local)
|
||||||
|
|
||||||
// Cached model list (expensive API call; refreshed every 24h).
|
// Cached model list (expensive API call; refreshed every 24h).
|
||||||
|
|
@ -71,12 +70,6 @@ func (sess *Session) InvalidateModelsCache() {
|
||||||
sess.modelsMu.Unlock()
|
sess.modelsMu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
// HasPeer reports whether peerID is a registered peer of this session.
|
|
||||||
func (sess *Session) HasPeer(peerID string) bool {
|
|
||||||
sess.mu.RLock()
|
|
||||||
defer sess.mu.RUnlock()
|
|
||||||
return sess.peers[peerID]
|
|
||||||
}
|
|
||||||
|
|
||||||
func (sess *Session) RunnableID() string { return sess.id }
|
func (sess *Session) RunnableID() string { return sess.id }
|
||||||
func (sess *Session) Uname() string { return sess.uname }
|
func (sess *Session) Uname() string { return sess.uname }
|
||||||
|
|
|
||||||
|
|
@ -192,12 +192,9 @@ func (s *Server) dirMode(path string) plan9.Perm {
|
||||||
func (s *Server) filePerm(path string) os.FileMode {
|
func (s *Server) filePerm(path string) os.FileMode {
|
||||||
// Session files have per-file overrides.
|
// Session files have per-file overrides.
|
||||||
if strings.HasPrefix(path, fs.PathSessions) {
|
if strings.HasPrefix(path, fs.PathSessions) {
|
||||||
// Peer/proc file permissions.
|
// Proc file permissions.
|
||||||
name := strings.TrimPrefix(path, fs.PathSessions)
|
name := strings.TrimPrefix(path, fs.PathSessions)
|
||||||
parts := strings.SplitN(name, "/", 3)
|
parts := strings.SplitN(name, "/", 3)
|
||||||
if len(parts) == 3 && parts[1] == "peer" {
|
|
||||||
return 0666
|
|
||||||
}
|
|
||||||
if len(parts) == 3 && parts[1] == "proc" {
|
if len(parts) == 3 && parts[1] == "proc" {
|
||||||
return 0444
|
return 0444
|
||||||
}
|
}
|
||||||
|
|
@ -531,22 +528,11 @@ func (s *Server) pathType(path string) string {
|
||||||
}
|
}
|
||||||
return "dir"
|
return "dir"
|
||||||
}
|
}
|
||||||
// /session/{id}/peer or /session/{id}/proc — directory
|
// /session/{id}/proc — directory
|
||||||
parts := strings.SplitN(name, "/", 3)
|
parts := strings.SplitN(name, "/", 3)
|
||||||
if len(parts) == 2 && (parts[1] == "peer" || parts[1] == "proc") {
|
if len(parts) == 2 && parts[1] == "proc" {
|
||||||
return "dir"
|
return "dir"
|
||||||
}
|
}
|
||||||
// /session/{id}/peer/{peer-id} — verify peer exists
|
|
||||||
if len(parts) == 3 && parts[1] == "peer" {
|
|
||||||
sess := s.sessionMgr.Session(parts[0])
|
|
||||||
if sess == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
if sess.HasPeer(parts[2]) {
|
|
||||||
return "file"
|
|
||||||
}
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
// /session/{id}/proc/{pid} — verify PID exists in detached list
|
// /session/{id}/proc/{pid} — verify PID exists in detached list
|
||||||
if len(parts) == 3 && parts[1] == "proc" {
|
if len(parts) == 3 && parts[1] == "proc" {
|
||||||
sess := s.sessionMgr.Session(parts[0])
|
sess := s.sessionMgr.Session(parts[0])
|
||||||
|
|
|
||||||
Reference in New Issue