session rename: eventwait file, broadcast on create/delete/rename, ollie-9p mv
This commit is contained in:
parent
c18d4560de
commit
8ae8a6ead4
|
|
@ -116,6 +116,8 @@ func dial() *client.Fsys {
|
|||
}
|
||||
address = ns + "/ollie"
|
||||
}
|
||||
// Strip plan9port-style unix! prefix if present
|
||||
address = strings.TrimPrefix(address, "unix!")
|
||||
|
||||
aname := os.Getenv("OLLIE_UNAME")
|
||||
if aname == "" {
|
||||
|
|
@ -128,6 +130,11 @@ func dial() *client.Fsys {
|
|||
aname = "none"
|
||||
}
|
||||
}
|
||||
// If OLLIE_SESSION_ID is set, we're inside a session and must use OLLIE_UNAME.
|
||||
// If it's not set, we're outside (e.g. GUI) and use $USER.
|
||||
// The GUI calls renameSession which spawns ollie-9p without OLLIE_SESSION_ID,
|
||||
// so it falls through to $USER. That's correct — the server accepts $USER
|
||||
// as a valid attach identity for non-session operations.
|
||||
|
||||
fsys, err := mountWithAname(address, aname)
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -260,6 +260,7 @@ func Create(rs *rootState, args []string) (string, error) {
|
|||
|
||||
rs.cfg.Log.Info("new session %s (backend=%s model=%s agent=%s)",
|
||||
sessID, core.Agent().BackendName(), core.Agent().ModelName(), core.Agent().Name())
|
||||
broadcastEvents()
|
||||
return sessID, nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -57,8 +57,9 @@ var Perms = map[string]Perm{
|
|||
DirMode: 0755,
|
||||
FileMode: 0444,
|
||||
Files: map[string]os.FileMode{
|
||||
"new": 0666,
|
||||
"idx": 0444,
|
||||
"new": 0666,
|
||||
"idx": 0444,
|
||||
"eventwait": 0444,
|
||||
},
|
||||
},
|
||||
PathSessionDir: {DirMode: 0755},
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ func Kill(rs *rootState, id string) {
|
|||
removePersistedAgent(rs, id)
|
||||
rs.cfg.Log.Info("killed session %s", id)
|
||||
}
|
||||
broadcastEvents()
|
||||
}
|
||||
|
||||
// KillFromRoot is the public API for callers with *Tree.
|
||||
|
|
@ -66,6 +67,7 @@ func Rename(rs *rootState, old, new string) error {
|
|||
rs.mu.Unlock()
|
||||
|
||||
rs.cfg.Log.Info("renamed session %s -> %s", old, new)
|
||||
broadcastEvents()
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -17,7 +17,45 @@ import (
|
|||
"ollie/toolsrv"
|
||||
)
|
||||
|
||||
var rootFileOrder = []string{"new", "idx"}
|
||||
// eventBroadcaster manages notification of session index changes.
|
||||
// The GUI can tail session/eventwait to detect creates, deletes, and renames.
|
||||
var (
|
||||
evMu sync.Mutex
|
||||
evChans []chan struct{}
|
||||
)
|
||||
|
||||
func broadcastEvents() {
|
||||
evMu.Lock()
|
||||
for _, ch := range evChans {
|
||||
select {
|
||||
case ch <- struct{}{}:
|
||||
default:
|
||||
}
|
||||
}
|
||||
evMu.Unlock()
|
||||
}
|
||||
|
||||
// eventRegister returns a channel that fires on the next session index change.
|
||||
func eventRegister() chan struct{} {
|
||||
ch := make(chan struct{}, 1)
|
||||
evMu.Lock()
|
||||
evChans = append(evChans, ch)
|
||||
evMu.Unlock()
|
||||
return ch
|
||||
}
|
||||
|
||||
func eventRelease(ch chan struct{}) {
|
||||
evMu.Lock()
|
||||
for i, c := range evChans {
|
||||
if c == ch {
|
||||
evChans = append(evChans[:i], evChans[i+1:]...)
|
||||
break
|
||||
}
|
||||
}
|
||||
evMu.Unlock()
|
||||
}
|
||||
|
||||
var rootFileOrder = []string{"new", "idx", "eventwait"}
|
||||
|
||||
// FileMode returns the mode for a fixed session file,
|
||||
// or 0 and false if the name is not a fixed file.
|
||||
|
|
@ -295,6 +333,7 @@ func rootOpen(rs *rootState, name string) (File, error) {
|
|||
notBlocking := func(context.Context, string) ([]byte, string, error) {
|
||||
return nil, "", fmt.Errorf("blocking read not supported")
|
||||
}
|
||||
|
||||
parts := strings.SplitN(name, "/", 3)
|
||||
|
||||
// Proc file: {id}/proc/{pid}
|
||||
|
|
@ -328,6 +367,27 @@ func rootOpen(rs *rootState, name string) (File, error) {
|
|||
}
|
||||
|
||||
switch name {
|
||||
case "eventwait":
|
||||
return &FileConfig{
|
||||
StatFn: func() (os.FileInfo, error) {
|
||||
return &SyntheticFileInfo{Name_: "eventwait", Mode_: Perms[PathSessions].Files["eventwait"]}, nil
|
||||
},
|
||||
ReadFn: func() ([]byte, error) {
|
||||
return []byte(buildIndex(rs)), nil
|
||||
},
|
||||
WriteFn: func([]byte) error { return fmt.Errorf("eventwait: read-only") },
|
||||
BlockingReadFn: func(ctx context.Context, _ string) ([]byte, string, error) {
|
||||
ch := eventRegister()
|
||||
defer eventRelease(ch)
|
||||
select {
|
||||
case <-ch:
|
||||
return []byte(buildIndex(rs)), "", nil
|
||||
case <-ctx.Done():
|
||||
return nil, "", ctx.Err()
|
||||
}
|
||||
},
|
||||
IsBlocking_: true,
|
||||
}, nil
|
||||
case "new":
|
||||
return &FileConfig{
|
||||
StatFn: func() (os.FileInfo, error) {
|
||||
|
|
|
|||
2
kde
2
kde
|
|
@ -1 +1 @@
|
|||
Subproject commit cd0f92e16de666f23885614c23d7fa33dab8ad9f
|
||||
Subproject commit 76f97c42ebbba47e96d99554da88d4625db2d378
|
||||
Loading…
Reference in New Issue