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"
|
address = ns + "/ollie"
|
||||||
}
|
}
|
||||||
|
// Strip plan9port-style unix! prefix if present
|
||||||
|
address = strings.TrimPrefix(address, "unix!")
|
||||||
|
|
||||||
aname := os.Getenv("OLLIE_UNAME")
|
aname := os.Getenv("OLLIE_UNAME")
|
||||||
if aname == "" {
|
if aname == "" {
|
||||||
|
|
@ -128,6 +130,11 @@ func dial() *client.Fsys {
|
||||||
aname = "none"
|
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)
|
fsys, err := mountWithAname(address, aname)
|
||||||
if err != nil {
|
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)",
|
rs.cfg.Log.Info("new session %s (backend=%s model=%s agent=%s)",
|
||||||
sessID, core.Agent().BackendName(), core.Agent().ModelName(), core.Agent().Name())
|
sessID, core.Agent().BackendName(), core.Agent().ModelName(), core.Agent().Name())
|
||||||
|
broadcastEvents()
|
||||||
return sessID, nil
|
return sessID, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -57,8 +57,9 @@ var Perms = map[string]Perm{
|
||||||
DirMode: 0755,
|
DirMode: 0755,
|
||||||
FileMode: 0444,
|
FileMode: 0444,
|
||||||
Files: map[string]os.FileMode{
|
Files: map[string]os.FileMode{
|
||||||
"new": 0666,
|
"new": 0666,
|
||||||
"idx": 0444,
|
"idx": 0444,
|
||||||
|
"eventwait": 0444,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
PathSessionDir: {DirMode: 0755},
|
PathSessionDir: {DirMode: 0755},
|
||||||
|
|
|
||||||
|
|
@ -31,6 +31,7 @@ func Kill(rs *rootState, id string) {
|
||||||
removePersistedAgent(rs, id)
|
removePersistedAgent(rs, id)
|
||||||
rs.cfg.Log.Info("killed session %s", id)
|
rs.cfg.Log.Info("killed session %s", id)
|
||||||
}
|
}
|
||||||
|
broadcastEvents()
|
||||||
}
|
}
|
||||||
|
|
||||||
// KillFromRoot is the public API for callers with *Tree.
|
// 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.mu.Unlock()
|
||||||
|
|
||||||
rs.cfg.Log.Info("renamed session %s -> %s", old, new)
|
rs.cfg.Log.Info("renamed session %s -> %s", old, new)
|
||||||
|
broadcastEvents()
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,45 @@ import (
|
||||||
"ollie/toolsrv"
|
"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,
|
// FileMode returns the mode for a fixed session file,
|
||||||
// or 0 and false if the name is not a fixed 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) {
|
notBlocking := func(context.Context, string) ([]byte, string, error) {
|
||||||
return nil, "", fmt.Errorf("blocking read not supported")
|
return nil, "", fmt.Errorf("blocking read not supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
parts := strings.SplitN(name, "/", 3)
|
parts := strings.SplitN(name, "/", 3)
|
||||||
|
|
||||||
// Proc file: {id}/proc/{pid}
|
// Proc file: {id}/proc/{pid}
|
||||||
|
|
@ -328,6 +367,27 @@ func rootOpen(rs *rootState, name string) (File, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
switch name {
|
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":
|
case "new":
|
||||||
return &FileConfig{
|
return &FileConfig{
|
||||||
StatFn: func() (os.FileInfo, error) {
|
StatFn: func() (os.FileInfo, error) {
|
||||||
|
|
|
||||||
2
kde
2
kde
|
|
@ -1 +1 @@
|
||||||
Subproject commit cd0f92e16de666f23885614c23d7fa33dab8ad9f
|
Subproject commit 76f97c42ebbba47e96d99554da88d4625db2d378
|
||||||
Loading…
Reference in New Issue