rename fsedsl → virtfs
The package has outgrown its original 'eDSL' framing. It's a virtual filesystem library. Rename to match.
This commit is contained in:
parent
d71ff80993
commit
ee7426d628
|
|
@ -11,7 +11,7 @@ import (
|
||||||
"ollie/cmd/olliesrv/internal/agent"
|
"ollie/cmd/olliesrv/internal/agent"
|
||||||
"ollie/cmd/olliesrv/internal/backend"
|
"ollie/cmd/olliesrv/internal/backend"
|
||||||
"ollie/cmd/olliesrv/internal/bypass"
|
"ollie/cmd/olliesrv/internal/bypass"
|
||||||
"ollie/fsedsl"
|
"ollie/virtfs"
|
||||||
"ollie/cmd/olliesrv/internal/session"
|
"ollie/cmd/olliesrv/internal/session"
|
||||||
"ollie/toolsrv"
|
"ollie/toolsrv"
|
||||||
)
|
)
|
||||||
|
|
@ -44,7 +44,7 @@ func readBackends() ([]byte, error) {
|
||||||
var helpFn func() string
|
var helpFn func() string
|
||||||
|
|
||||||
// helpSpec stores the spec for help generation. Set during tree build.
|
// helpSpec stores the spec for help generation. Set during tree build.
|
||||||
var helpSpec *fsedsl.FsNodeDecl
|
var helpSpec *virtfs.FsNodeDecl
|
||||||
|
|
||||||
func readHelp() ([]byte, error) {
|
func readHelp() ([]byte, error) {
|
||||||
if helpFn == nil {
|
if helpFn == nil {
|
||||||
|
|
@ -57,7 +57,7 @@ func init() {
|
||||||
helpFn = func() string {
|
helpFn = func() string {
|
||||||
helpOnce.Do(func() {
|
helpOnce.Do(func() {
|
||||||
if helpSpec != nil {
|
if helpSpec != nil {
|
||||||
helpText = fsedsl.GenerateHelp(*helpSpec)
|
helpText = virtfs.GenerateHelp(*helpSpec)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return helpText
|
return helpText
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ import (
|
||||||
"context"
|
"context"
|
||||||
|
|
||||||
"ollie/cmd/olliesrv/internal/bypass"
|
"ollie/cmd/olliesrv/internal/bypass"
|
||||||
"ollie/fsedsl"
|
"ollie/virtfs"
|
||||||
olog "ollie/log"
|
olog "ollie/log"
|
||||||
"ollie/cmd/olliesrv/internal/session"
|
"ollie/cmd/olliesrv/internal/session"
|
||||||
)
|
)
|
||||||
|
|
@ -45,7 +45,7 @@ func NewRoot(cfg Config) *Tree {
|
||||||
// Build the tree from the spec.
|
// Build the tree from the spec.
|
||||||
spec := buildTreeSpec(rs)
|
spec := buildTreeSpec(rs)
|
||||||
helpSpec = &spec
|
helpSpec = &spec
|
||||||
tree := fsedsl.BuildTree(spec)
|
tree := virtfs.BuildTree(spec)
|
||||||
tree.Data = rs
|
tree.Data = rs
|
||||||
|
|
||||||
// Restore persisted sessions from disk.
|
// Restore persisted sessions from disk.
|
||||||
|
|
|
||||||
|
|
@ -11,29 +11,29 @@ import (
|
||||||
"ollie/cmd/olliesrv/internal/agent"
|
"ollie/cmd/olliesrv/internal/agent"
|
||||||
"ollie/cmd/olliesrv/internal/bypass"
|
"ollie/cmd/olliesrv/internal/bypass"
|
||||||
"ollie/cmd/olliesrv/internal/session"
|
"ollie/cmd/olliesrv/internal/session"
|
||||||
"ollie/fsedsl"
|
"ollie/virtfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Type aliases for fsedsl types used throughout the package.
|
// Type aliases for virtfs types used throughout the package.
|
||||||
type (
|
type (
|
||||||
Tree = fsedsl.Tree
|
Tree = virtfs.Tree
|
||||||
File = fsedsl.File
|
File = virtfs.File
|
||||||
SyntheticFileInfo = fsedsl.SyntheticFileInfo
|
SyntheticFileInfo = virtfs.SyntheticFileInfo
|
||||||
)
|
)
|
||||||
|
|
||||||
// Structural permissions.
|
// Structural permissions.
|
||||||
const (
|
const (
|
||||||
PermChildDir = fsedsl.PermChildDir
|
PermChildDir = virtfs.PermChildDir
|
||||||
PermIdx = fsedsl.PermIdx
|
PermIdx = virtfs.PermIdx
|
||||||
PermMkdir = fsedsl.PermMkdir
|
PermMkdir = virtfs.PermMkdir
|
||||||
PermMkdirPrivate = fsedsl.PermMkdirPrivate
|
PermMkdirPrivate = virtfs.PermMkdirPrivate
|
||||||
)
|
)
|
||||||
|
|
||||||
var treeSpecUID, treeSpecGID string
|
var treeSpecUID, treeSpecGID string
|
||||||
|
|
||||||
// buildTreeSpec constructs the full 9P namespace as an fsedsl.FsNodeDecl.
|
// buildTreeSpec constructs the full 9P namespace as an virtfs.FsNodeDecl.
|
||||||
// All handlers are closures that capture their dependencies at binding time.
|
// All handlers are closures that capture their dependencies at binding time.
|
||||||
func buildTreeSpec(rs *RootState) fsedsl.FsNodeDecl {
|
func buildTreeSpec(rs *RootState) virtfs.FsNodeDecl {
|
||||||
cfg := &rs.Cfg
|
cfg := &rs.Cfg
|
||||||
mc := cfg.ModelCache
|
mc := cfg.ModelCache
|
||||||
broker := cfg.BypassBroker
|
broker := cfg.BypassBroker
|
||||||
|
|
@ -45,71 +45,71 @@ func buildTreeSpec(rs *RootState) fsedsl.FsNodeDecl {
|
||||||
treeSpecUID = u.Username
|
treeSpecUID = u.Username
|
||||||
}
|
}
|
||||||
|
|
||||||
return fsedsl.DirNode("/",
|
return virtfs.DirNode("/",
|
||||||
fsedsl.UID(treeSpecUID),
|
virtfs.UID(treeSpecUID),
|
||||||
fsedsl.GID(treeSpecGID),
|
virtfs.GID(treeSpecGID),
|
||||||
|
|
||||||
fsedsl.FileNode("backends", 0444,
|
virtfs.FileNode("backends", 0444,
|
||||||
fsedsl.Doc("Available backend names, one per line"),
|
virtfs.Doc("Available backend names, one per line"),
|
||||||
fsedsl.Read(readBackends),
|
virtfs.Read(readBackends),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("help", 0444,
|
virtfs.FileNode("help", 0444,
|
||||||
fsedsl.Doc("Filesystem reference"),
|
virtfs.Doc("Filesystem reference"),
|
||||||
fsedsl.Read(readHelp),
|
virtfs.Read(readHelp),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("models", 0444,
|
virtfs.FileNode("models", 0444,
|
||||||
fsedsl.Doc("Available models. Format: backend<tab>model per line."),
|
virtfs.Doc("Available models. Format: backend<tab>model per line."),
|
||||||
fsedsl.Read(func() ([]byte, error) { return readModels(mc) }),
|
virtfs.Read(func() ([]byte, error) { return readModels(mc) }),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("agents", 0444,
|
virtfs.FileNode("agents", 0444,
|
||||||
fsedsl.Doc("Available agent profiles, one per line"),
|
virtfs.Doc("Available agent profiles, one per line"),
|
||||||
fsedsl.Read(readAgents),
|
virtfs.Read(readAgents),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("tools", 0444,
|
virtfs.FileNode("tools", 0444,
|
||||||
fsedsl.Doc("Available tools. Format: name<spaces>description per line."),
|
virtfs.Doc("Available tools. Format: name<spaces>description per line."),
|
||||||
fsedsl.Read(readTools),
|
virtfs.Read(readTools),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("ctl", 0666,
|
virtfs.FileNode("ctl", 0666,
|
||||||
fsedsl.Doc("Server control. Write: 'invalidate', 'kill'"),
|
virtfs.Doc("Server control. Write: 'invalidate', 'kill'"),
|
||||||
fsedsl.Request(rootCtlHandler(mc, cfg.Invalidate, cfg.Shutdown)),
|
virtfs.Request(rootCtlHandler(mc, cfg.Invalidate, cfg.Shutdown)),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("eventwait", 0444,
|
virtfs.FileNode("eventwait", 0444,
|
||||||
fsedsl.Doc("Blocking read for server events"),
|
virtfs.Doc("Blocking read for server events"),
|
||||||
fsedsl.Read(readEventwait),
|
virtfs.Read(readEventwait),
|
||||||
fsedsl.BlockOnce(blockEventwait),
|
virtfs.BlockOnce(blockEventwait),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("generate", 0666,
|
virtfs.FileNode("generate", 0666,
|
||||||
fsedsl.Doc("One-shot LLM generation"),
|
virtfs.Doc("One-shot LLM generation"),
|
||||||
fsedsl.Request(func(data []byte) ([]byte, error) { return requestGenerate(cfg.Ctx, data) }),
|
virtfs.Request(func(data []byte) ([]byte, error) { return requestGenerate(cfg.Ctx, data) }),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("aliases", 0444,
|
virtfs.FileNode("aliases", 0444,
|
||||||
fsedsl.Doc("Alias table. Format: id<tab>path per line."),
|
virtfs.Doc("Alias table. Format: id<tab>path per line."),
|
||||||
fsedsl.Read(readAliases),
|
virtfs.Read(readAliases),
|
||||||
),
|
),
|
||||||
|
|
||||||
fsedsl.DirNode("bypass",
|
virtfs.DirNode("bypass",
|
||||||
fsedsl.Doc("Bypass broker for sandboxed command approval"),
|
virtfs.Doc("Bypass broker for sandboxed command approval"),
|
||||||
fsedsl.FileNode("policy", 0666,
|
virtfs.FileNode("policy", 0666,
|
||||||
fsedsl.Doc("Global bypass policy"),
|
virtfs.Doc("Global bypass policy"),
|
||||||
fsedsl.Read(func() ([]byte, error) { return readBypassPolicy(broker) }),
|
virtfs.Read(func() ([]byte, error) { return readBypassPolicy(broker) }),
|
||||||
fsedsl.Write(func(data []byte) error { return writeBypassPolicy(broker, data) }),
|
virtfs.Write(func(data []byte) error { return writeBypassPolicy(broker, data) }),
|
||||||
),
|
),
|
||||||
fsedsl.Each("{reqid}", func() ([]fsedsl.Binding, error) {
|
virtfs.Each("{reqid}", func() ([]virtfs.Binding, error) {
|
||||||
return adaptBypassBindings(broker)
|
return adaptBypassBindings(broker)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
||||||
fsedsl.DirNode("session",
|
virtfs.DirNode("session",
|
||||||
fsedsl.Doc("Session management"),
|
virtfs.Doc("Session management"),
|
||||||
fsedsl.FileNode("new", 0666,
|
virtfs.FileNode("new", 0666,
|
||||||
fsedsl.Doc("Create session"),
|
virtfs.Doc("Create session"),
|
||||||
fsedsl.Request(requestSessionNew),
|
virtfs.Request(requestSessionNew),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("idx", 0444,
|
virtfs.FileNode("idx", 0444,
|
||||||
fsedsl.Doc("Session index"),
|
virtfs.Doc("Session index"),
|
||||||
fsedsl.Read(readSessionIdx),
|
virtfs.Read(readSessionIdx),
|
||||||
),
|
),
|
||||||
fsedsl.Each("{sname}", func() ([]fsedsl.Binding, error) {
|
virtfs.Each("{sname}", func() ([]virtfs.Binding, error) {
|
||||||
return buildSessionBindings(rs, broker)
|
return buildSessionBindings(rs, broker)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
@ -117,9 +117,9 @@ func buildTreeSpec(rs *RootState) fsedsl.FsNodeDecl {
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildSessionBindings produces bindings for each session.
|
// buildSessionBindings produces bindings for each session.
|
||||||
func buildSessionBindings(rs *RootState, broker *bypass.Broker) ([]fsedsl.Binding, error) {
|
func buildSessionBindings(rs *RootState, broker *bypass.Broker) ([]virtfs.Binding, error) {
|
||||||
sessions := session.Sessions()
|
sessions := session.Sessions()
|
||||||
var out []fsedsl.Binding
|
var out []virtfs.Binding
|
||||||
|
|
||||||
for name, sess := range sessions {
|
for name, sess := range sessions {
|
||||||
node := rs.GetOrCreateNode(sess)
|
node := rs.GetOrCreateNode(sess)
|
||||||
|
|
@ -138,7 +138,7 @@ func buildSessionBindings(rs *RootState, broker *bypass.Broker) ([]fsedsl.Bindin
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
out = append(out, fsedsl.Binding{
|
out = append(out, virtfs.Binding{
|
||||||
Name: sess.Name(),
|
Name: sess.Name(),
|
||||||
Aliases: []string{sess.ID},
|
Aliases: []string{sess.ID},
|
||||||
Remove: removeFn,
|
Remove: removeFn,
|
||||||
|
|
@ -156,39 +156,39 @@ func buildSessionChildren(
|
||||||
broker *bypass.Broker,
|
broker *bypass.Broker,
|
||||||
removeFn func(),
|
removeFn func(),
|
||||||
renameFn func(string) error,
|
renameFn func(string) error,
|
||||||
) []fsedsl.FsNodeDecl {
|
) []virtfs.FsNodeDecl {
|
||||||
return []fsedsl.FsNodeDecl{
|
return []virtfs.FsNodeDecl{
|
||||||
fsedsl.FileNode("env", 0444,
|
virtfs.FileNode("env", 0444,
|
||||||
fsedsl.Read(func() ([]byte, error) { return readSessionEnv(s) }),
|
virtfs.Read(func() ([]byte, error) { return readSessionEnv(s) }),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("paused", 0444,
|
virtfs.FileNode("paused", 0444,
|
||||||
fsedsl.Read(func() ([]byte, error) { return readSessionPaused(s) }),
|
virtfs.Read(func() ([]byte, error) { return readSessionPaused(s) }),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("connected", 0444,
|
virtfs.FileNode("connected", 0444,
|
||||||
fsedsl.Read(func() ([]byte, error) { return readSessionConnected(s) }),
|
virtfs.Read(func() ([]byte, error) { return readSessionConnected(s) }),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("ctl", 0666,
|
virtfs.FileNode("ctl", 0666,
|
||||||
fsedsl.Request(sessionCtlHandler(s, removeFn, renameFn)),
|
virtfs.Request(sessionCtlHandler(s, removeFn, renameFn)),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("name", 0666,
|
virtfs.FileNode("name", 0666,
|
||||||
fsedsl.Read(func() ([]byte, error) { return readSessionName(s) }),
|
virtfs.Read(func() ([]byte, error) { return readSessionName(s) }),
|
||||||
fsedsl.Write(func(data []byte) error { return writeSessionName(s, renameFn, data) }),
|
virtfs.Write(func(data []byte) error { return writeSessionName(s, renameFn, data) }),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("id", 0444,
|
virtfs.FileNode("id", 0444,
|
||||||
fsedsl.Read(func() ([]byte, error) { return readSessionID(s) }),
|
virtfs.Read(func() ([]byte, error) { return readSessionID(s) }),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("bypass", 0666,
|
virtfs.FileNode("bypass", 0666,
|
||||||
fsedsl.Read(func() ([]byte, error) { return readSessionBypass(broker, s) }),
|
virtfs.Read(func() ([]byte, error) { return readSessionBypass(broker, s) }),
|
||||||
fsedsl.Write(func(data []byte) error { return writeSessionBypass(broker, s, data) }),
|
virtfs.Write(func(data []byte) error { return writeSessionBypass(broker, s, data) }),
|
||||||
),
|
),
|
||||||
fsedsl.DirNode("agent",
|
virtfs.DirNode("agent",
|
||||||
fsedsl.FileNode("new", 0666,
|
virtfs.FileNode("new", 0666,
|
||||||
fsedsl.Request(func(data []byte) ([]byte, error) { return requestAgentNew(s, data) }),
|
virtfs.Request(func(data []byte) ([]byte, error) { return requestAgentNew(s, data) }),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("idx", 0444,
|
virtfs.FileNode("idx", 0444,
|
||||||
fsedsl.Read(func() ([]byte, error) { return readAgentIdx(s.Session) }),
|
virtfs.Read(func() ([]byte, error) { return readAgentIdx(s.Session) }),
|
||||||
),
|
),
|
||||||
fsedsl.Each("{aname}", func() ([]fsedsl.Binding, error) {
|
virtfs.Each("{aname}", func() ([]virtfs.Binding, error) {
|
||||||
return buildAgentBindings(s, rs)
|
return buildAgentBindings(s, rs)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
@ -196,9 +196,9 @@ func buildSessionChildren(
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildAgentBindings produces bindings for each agent in a session.
|
// buildAgentBindings produces bindings for each agent in a session.
|
||||||
func buildAgentBindings(s *SessionNode, rs *RootState) ([]fsedsl.Binding, error) {
|
func buildAgentBindings(s *SessionNode, rs *RootState) ([]virtfs.Binding, error) {
|
||||||
agents := s.Agents()
|
agents := s.Agents()
|
||||||
var out []fsedsl.Binding
|
var out []virtfs.Binding
|
||||||
|
|
||||||
for _, ag := range agents {
|
for _, ag := range agents {
|
||||||
a := ag
|
a := ag
|
||||||
|
|
@ -209,7 +209,7 @@ func buildAgentBindings(s *SessionNode, rs *RootState) ([]fsedsl.Binding, error)
|
||||||
wireAgentEvents(s.ID, a, al)
|
wireAgentEvents(s.ID, a, al)
|
||||||
}
|
}
|
||||||
|
|
||||||
out = append(out, fsedsl.Binding{
|
out = append(out, virtfs.Binding{
|
||||||
Name: a.Name(),
|
Name: a.Name(),
|
||||||
Aliases: []string{a.ID()},
|
Aliases: []string{a.ID()},
|
||||||
Remove: func() {
|
Remove: func() {
|
||||||
|
|
@ -223,67 +223,67 @@ func buildAgentBindings(s *SessionNode, rs *RootState) ([]fsedsl.Binding, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// buildAgentChildren returns the file nodes for a single agent.
|
// buildAgentChildren returns the file nodes for a single agent.
|
||||||
func buildAgentChildren(a *agent.Agent, al *AgentLog, s *SessionNode) []fsedsl.FsNodeDecl {
|
func buildAgentChildren(a *agent.Agent, al *AgentLog, s *SessionNode) []virtfs.FsNodeDecl {
|
||||||
return []fsedsl.FsNodeDecl{
|
return []virtfs.FsNodeDecl{
|
||||||
fsedsl.FileNode("prompt", 0666,
|
virtfs.FileNode("prompt", 0666,
|
||||||
fsedsl.Write(func(data []byte) error { return writeAgentPrompt(s, a, al, data) }),
|
virtfs.Write(func(data []byte) error { return writeAgentPrompt(s, a, al, data) }),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("fifo", 0666,
|
virtfs.FileNode("fifo", 0666,
|
||||||
fsedsl.Write(func(data []byte) error { return writeAgentFifoIn(a, data) }),
|
virtfs.Write(func(data []byte) error { return writeAgentFifoIn(a, data) }),
|
||||||
fsedsl.Read(func() ([]byte, error) { return readAgentFifoOut(a) }),
|
virtfs.Read(func() ([]byte, error) { return readAgentFifoOut(a) }),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("chat", 0444,
|
virtfs.FileNode("chat", 0444,
|
||||||
fsedsl.StatOverride(statAgentChat),
|
virtfs.StatOverride(statAgentChat),
|
||||||
fsedsl.Read(func() ([]byte, error) { return readAgentChatText(al) }),
|
virtfs.Read(func() ([]byte, error) { return readAgentChatText(al) }),
|
||||||
fsedsl.Stream(func(cctx context.Context, base string) ([]byte, string, error) {
|
virtfs.Stream(func(cctx context.Context, base string) ([]byte, string, error) {
|
||||||
return streamAgentChatText(s, al, cctx, base)
|
return streamAgentChatText(s, al, cctx, base)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("chat.raw", 0444,
|
virtfs.FileNode("chat.raw", 0444,
|
||||||
fsedsl.StatOverride(statAgentChat),
|
virtfs.StatOverride(statAgentChat),
|
||||||
fsedsl.Read(func() ([]byte, error) { return readAgentChat(al) }),
|
virtfs.Read(func() ([]byte, error) { return readAgentChat(al) }),
|
||||||
fsedsl.Stream(func(cctx context.Context, base string) ([]byte, string, error) {
|
virtfs.Stream(func(cctx context.Context, base string) ([]byte, string, error) {
|
||||||
return streamAgentChat(s, al, cctx, base)
|
return streamAgentChat(s, al, cctx, base)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("statewait", 0444,
|
virtfs.FileNode("statewait", 0444,
|
||||||
fsedsl.Read(func() ([]byte, error) {
|
virtfs.Read(func() ([]byte, error) {
|
||||||
return []byte(a.State() + "\n"), nil
|
return []byte(a.State() + "\n"), nil
|
||||||
}),
|
}),
|
||||||
fsedsl.BlockOnce(func(cctx context.Context, base string) ([]byte, string, error) {
|
virtfs.BlockOnce(func(cctx context.Context, base string) ([]byte, string, error) {
|
||||||
return blockAgentStateWait(s, a, cctx, base)
|
return blockAgentStateWait(s, a, cctx, base)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("log", 0444,
|
virtfs.FileNode("log", 0444,
|
||||||
fsedsl.Read(func() ([]byte, error) { return readAgentLog(al) }),
|
virtfs.Read(func() ([]byte, error) { return readAgentLog(al) }),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("plan", 0666,
|
virtfs.FileNode("plan", 0666,
|
||||||
fsedsl.Read(func() ([]byte, error) { return readAgentPlan(al) }),
|
virtfs.Read(func() ([]byte, error) { return readAgentPlan(al) }),
|
||||||
fsedsl.Write(func(data []byte) error { return writeAgentPlan(al, data) }),
|
virtfs.Write(func(data []byte) error { return writeAgentPlan(al, data) }),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("cfg", 0666,
|
virtfs.FileNode("cfg", 0666,
|
||||||
fsedsl.Read(func() ([]byte, error) { return readAgentCfg(s, a, al) }),
|
virtfs.Read(func() ([]byte, error) { return readAgentCfg(s, a, al) }),
|
||||||
fsedsl.Write(func(data []byte) error { return writeAgentCfg(a, data) }),
|
virtfs.Write(func(data []byte) error { return writeAgentCfg(a, data) }),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("ctl", 0666,
|
virtfs.FileNode("ctl", 0666,
|
||||||
fsedsl.Request(agentCtlHandler(s, a)),
|
virtfs.Request(agentCtlHandler(s, a)),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("stats", 0444,
|
virtfs.FileNode("stats", 0444,
|
||||||
fsedsl.Read(func() ([]byte, error) { return readAgentStats(a) }),
|
virtfs.Read(func() ([]byte, error) { return readAgentStats(a) }),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("tools", 0666,
|
virtfs.FileNode("tools", 0666,
|
||||||
fsedsl.Read(func() ([]byte, error) { return readAgentTools(a) }),
|
virtfs.Read(func() ([]byte, error) { return readAgentTools(a) }),
|
||||||
fsedsl.Write(func(data []byte) error { return writeAgentTools(a, data) }),
|
virtfs.Write(func(data []byte) error { return writeAgentTools(a, data) }),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("name", 0666,
|
virtfs.FileNode("name", 0666,
|
||||||
fsedsl.Read(func() ([]byte, error) { return readAgentName(a) }),
|
virtfs.Read(func() ([]byte, error) { return readAgentName(a) }),
|
||||||
fsedsl.Write(func(data []byte) error { return writeAgentName(s, a, data) }),
|
virtfs.Write(func(data []byte) error { return writeAgentName(s, a, data) }),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("id", 0444,
|
virtfs.FileNode("id", 0444,
|
||||||
fsedsl.Read(func() ([]byte, error) { return readAgentID(a) }),
|
virtfs.Read(func() ([]byte, error) { return readAgentID(a) }),
|
||||||
),
|
),
|
||||||
fsedsl.DirNode("proc",
|
virtfs.DirNode("proc",
|
||||||
fsedsl.Each("{pid}", func() ([]fsedsl.Binding, error) {
|
virtfs.Each("{pid}", func() ([]virtfs.Binding, error) {
|
||||||
return adaptProcessBindings(s)
|
return adaptProcessBindings(s)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
@ -291,22 +291,22 @@ func buildAgentChildren(a *agent.Agent, al *AgentLog, s *SessionNode) []fsedsl.F
|
||||||
}
|
}
|
||||||
|
|
||||||
// adaptBypassBindings returns bindings for pending bypass requests.
|
// adaptBypassBindings returns bindings for pending bypass requests.
|
||||||
func adaptBypassBindings(broker *bypass.Broker) ([]fsedsl.Binding, error) {
|
func adaptBypassBindings(broker *bypass.Broker) ([]virtfs.Binding, error) {
|
||||||
if broker == nil {
|
if broker == nil {
|
||||||
return nil, errNoBypass
|
return nil, errNoBypass
|
||||||
}
|
}
|
||||||
pending := broker.Pending()
|
pending := broker.Pending()
|
||||||
var out []fsedsl.Binding
|
var out []virtfs.Binding
|
||||||
for _, r := range pending {
|
for _, r := range pending {
|
||||||
req := r
|
req := r
|
||||||
out = append(out, fsedsl.Binding{
|
out = append(out, virtfs.Binding{
|
||||||
Name: req.ID,
|
Name: req.ID,
|
||||||
Children: []fsedsl.FsNodeDecl{
|
Children: []virtfs.FsNodeDecl{
|
||||||
fsedsl.FileNode("request", 0666,
|
virtfs.FileNode("request", 0666,
|
||||||
fsedsl.Read(func() ([]byte, error) {
|
virtfs.Read(func() ([]byte, error) {
|
||||||
return readBypassRequest(req)
|
return readBypassRequest(req)
|
||||||
}),
|
}),
|
||||||
fsedsl.Write(func(data []byte) error {
|
virtfs.Write(func(data []byte) error {
|
||||||
return writeBypassRequest(broker, req, data)
|
return writeBypassRequest(broker, req, data)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
@ -317,7 +317,7 @@ func adaptBypassBindings(broker *bypass.Broker) ([]fsedsl.Binding, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// adaptProcessBindings returns bindings for detached processes.
|
// adaptProcessBindings returns bindings for detached processes.
|
||||||
func adaptProcessBindings(s *SessionNode) ([]fsedsl.Binding, error) {
|
func adaptProcessBindings(s *SessionNode) ([]virtfs.Binding, error) {
|
||||||
if s == nil {
|
if s == nil {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
@ -327,26 +327,26 @@ func adaptProcessBindings(s *SessionNode) ([]fsedsl.Binding, error) {
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
raw := conn.ListDetachedRaw()
|
raw := conn.ListDetachedRaw()
|
||||||
var out []fsedsl.Binding
|
var out []virtfs.Binding
|
||||||
for _, r := range raw {
|
for _, r := range raw {
|
||||||
if m, ok := r.(map[string]any); ok {
|
if m, ok := r.(map[string]any); ok {
|
||||||
if id, ok := m["pid"].(int); ok {
|
if id, ok := m["pid"].(int); ok {
|
||||||
pid := id
|
pid := id
|
||||||
out = append(out, fsedsl.Binding{
|
out = append(out, virtfs.Binding{
|
||||||
Name: strconv.Itoa(pid),
|
Name: strconv.Itoa(pid),
|
||||||
Children: []fsedsl.FsNodeDecl{
|
Children: []virtfs.FsNodeDecl{
|
||||||
fsedsl.FileNode("out", 0444,
|
virtfs.FileNode("out", 0444,
|
||||||
fsedsl.Read(func() ([]byte, error) {
|
virtfs.Read(func() ([]byte, error) {
|
||||||
return readProcess(s, pid)
|
return readProcess(s, pid)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("ctl", 0222,
|
virtfs.FileNode("ctl", 0222,
|
||||||
fsedsl.Write(func(data []byte) error {
|
virtfs.Write(func(data []byte) error {
|
||||||
return writeProcessCtl(s, pid, data)
|
return writeProcessCtl(s, pid, data)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("status", 0444,
|
virtfs.FileNode("status", 0444,
|
||||||
fsedsl.Read(func() ([]byte, error) {
|
virtfs.Read(func() ([]byte, error) {
|
||||||
return readProcessStatus(s, pid)
|
return readProcessStatus(s, pid)
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// spec.go - fsedsl-based namespace specification for toolsrv.
|
// spec.go - virtfs-based namespace specification for toolsrv.
|
||||||
package fs
|
package fs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
|
@ -8,22 +8,22 @@ import (
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"ollie/fsedsl"
|
"ollie/virtfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Spec returns the fsedsl specification for the toolsrv namespace.
|
// Spec returns the virtfs specification for the toolsrv namespace.
|
||||||
// The server is captured by closures — no context threading needed.
|
// The server is captured by closures — no context threading needed.
|
||||||
func Spec(srv *Server) fsedsl.FsNodeDecl {
|
func Spec(srv *Server) virtfs.FsNodeDecl {
|
||||||
return fsedsl.DirNode("/",
|
return virtfs.DirNode("/",
|
||||||
fsedsl.FileNode("ctl", 0222,
|
virtfs.FileNode("ctl", 0222,
|
||||||
fsedsl.Doc("Control: write 'load <agentID> <tool>' or 'unload <agentID> <tool>'"),
|
virtfs.Doc("Control: write 'load <agentID> <tool>' or 'unload <agentID> <tool>'"),
|
||||||
fsedsl.Write(func(data []byte) error {
|
virtfs.Write(func(data []byte) error {
|
||||||
return srv.Fs.HandleCtl(strings.TrimSpace(string(data)))
|
return srv.Fs.HandleCtl(strings.TrimSpace(string(data)))
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("tools", 0666,
|
virtfs.FileNode("tools", 0666,
|
||||||
fsedsl.Doc("Tools: write agent ID, read tool list (rdwr)"),
|
virtfs.Doc("Tools: write agent ID, read tool list (rdwr)"),
|
||||||
fsedsl.Request(func(data []byte) ([]byte, error) {
|
virtfs.Request(func(data []byte) ([]byte, error) {
|
||||||
agentID := strings.TrimSpace(string(data))
|
agentID := strings.TrimSpace(string(data))
|
||||||
if agentID == "" {
|
if agentID == "" {
|
||||||
return nil, fmt.Errorf("agent ID required")
|
return nil, fmt.Errorf("agent ID required")
|
||||||
|
|
@ -31,16 +31,16 @@ func Spec(srv *Server) fsedsl.FsNodeDecl {
|
||||||
return []byte(srv.Fs.HandleToolsRequest(agentID)), nil
|
return []byte(srv.Fs.HandleToolsRequest(agentID)), nil
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("info", 0444,
|
virtfs.FileNode("info", 0444,
|
||||||
fsedsl.Doc("Host info: platform, arch"),
|
virtfs.Doc("Host info: platform, arch"),
|
||||||
fsedsl.Read(func() ([]byte, error) {
|
virtfs.Read(func() ([]byte, error) {
|
||||||
return []byte(srv.HostInfo()), nil
|
return []byte(srv.HostInfo()), nil
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
fsedsl.DirNode("proc",
|
virtfs.DirNode("proc",
|
||||||
fsedsl.FileNode("new", 0666,
|
virtfs.FileNode("new", 0666,
|
||||||
fsedsl.Doc("Execute tool: write token + tool + args, read result (blocking)"),
|
virtfs.Doc("Execute tool: write token + tool + args, read result (blocking)"),
|
||||||
fsedsl.Request(func(data []byte) ([]byte, error) {
|
virtfs.Request(func(data []byte) ([]byte, error) {
|
||||||
result, err := srv.Fs.HandleProcNew(context.Background(), string(data))
|
result, err := srv.Fs.HandleProcNew(context.Background(), string(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -48,9 +48,9 @@ func Spec(srv *Server) fsedsl.FsNodeDecl {
|
||||||
return []byte(result), nil
|
return []byte(result), nil
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("new.bg", 0666,
|
virtfs.FileNode("new.bg", 0666,
|
||||||
fsedsl.Doc("Execute tool in background: write token + tool + args, read pid"),
|
virtfs.Doc("Execute tool in background: write token + tool + args, read pid"),
|
||||||
fsedsl.Request(func(data []byte) ([]byte, error) {
|
virtfs.Request(func(data []byte) ([]byte, error) {
|
||||||
result, err := srv.Fs.HandleProcNewBg(context.Background(), string(data))
|
result, err := srv.Fs.HandleProcNewBg(context.Background(), string(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -58,40 +58,40 @@ func Spec(srv *Server) fsedsl.FsNodeDecl {
|
||||||
return []byte(result), nil
|
return []byte(result), nil
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
fsedsl.Each("{pid}", func() ([]fsedsl.Binding, error) {
|
virtfs.Each("{pid}", func() ([]virtfs.Binding, error) {
|
||||||
pids := srv.Fs.ListProcs()
|
pids := srv.Fs.ListProcs()
|
||||||
var bindings []fsedsl.Binding
|
var bindings []virtfs.Binding
|
||||||
for _, pid := range pids {
|
for _, pid := range pids {
|
||||||
proc := srv.Fs.GetProc(pid)
|
proc := srv.Fs.GetProc(pid)
|
||||||
if proc == nil {
|
if proc == nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
p := proc
|
p := proc
|
||||||
bindings = append(bindings, fsedsl.Binding{
|
bindings = append(bindings, virtfs.Binding{
|
||||||
Name: strconv.Itoa(pid),
|
Name: strconv.Itoa(pid),
|
||||||
Children: []fsedsl.FsNodeDecl{
|
Children: []virtfs.FsNodeDecl{
|
||||||
fsedsl.FileNode("out", 0444,
|
virtfs.FileNode("out", 0444,
|
||||||
fsedsl.Doc("Process output"),
|
virtfs.Doc("Process output"),
|
||||||
fsedsl.Read(func() ([]byte, error) {
|
virtfs.Read(func() ([]byte, error) {
|
||||||
return []byte(p.Output()), nil
|
return []byte(p.Output()), nil
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("wait", 0444,
|
virtfs.FileNode("wait", 0444,
|
||||||
fsedsl.Doc("Block until process exits, returns exit code"),
|
virtfs.Doc("Block until process exits, returns exit code"),
|
||||||
fsedsl.BlockOnce(func(_ context.Context, _ string) ([]byte, string, error) {
|
virtfs.BlockOnce(func(_ context.Context, _ string) ([]byte, string, error) {
|
||||||
exitCode := p.Wait()
|
exitCode := p.Wait()
|
||||||
return []byte(fmt.Sprintf("%d\n", exitCode)), "", nil
|
return []byte(fmt.Sprintf("%d\n", exitCode)), "", nil
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("stat", 0444,
|
virtfs.FileNode("stat", 0444,
|
||||||
fsedsl.Doc("Process status: running/exited, runtime, tool"),
|
virtfs.Doc("Process status: running/exited, runtime, tool"),
|
||||||
fsedsl.Read(func() ([]byte, error) {
|
virtfs.Read(func() ([]byte, error) {
|
||||||
return []byte(p.Stat()), nil
|
return []byte(p.Stat()), nil
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode("ctl", 0222,
|
virtfs.FileNode("ctl", 0222,
|
||||||
fsedsl.Doc("Process control: write 'signal <N>' or 'dismiss'"),
|
virtfs.Doc("Process control: write 'signal <N>' or 'dismiss'"),
|
||||||
fsedsl.Write(func(data []byte) error {
|
virtfs.Write(func(data []byte) error {
|
||||||
return srv.Fs.HandleProcCtl(p.ID, strings.TrimSpace(string(data)))
|
return srv.Fs.HandleProcCtl(p.ID, strings.TrimSpace(string(data)))
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"ollie/cmd/toolsrv/internal/registry"
|
"ollie/cmd/toolsrv/internal/registry"
|
||||||
"ollie/fsedsl"
|
"ollie/virtfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Server holds the state for the toolsrv 9P server.
|
// Server holds the state for the toolsrv 9P server.
|
||||||
|
|
@ -82,9 +82,9 @@ func (s *Server) HostInfo() string {
|
||||||
return fmt.Sprintf("platform=%s\narch=%s\n", runtime.GOOS, runtime.GOARCH)
|
return fmt.Sprintf("platform=%s\narch=%s\n", runtime.GOOS, runtime.GOARCH)
|
||||||
}
|
}
|
||||||
|
|
||||||
// BuildTree creates the fsedsl tree for this server.
|
// BuildTree creates the virtfs tree for this server.
|
||||||
func (s *Server) BuildTree() *fsedsl.Tree {
|
func (s *Server) BuildTree() *virtfs.Tree {
|
||||||
return fsedsl.BuildTree(Spec(s))
|
return virtfs.BuildTree(Spec(s))
|
||||||
}
|
}
|
||||||
|
|
||||||
// GenerateSecret generates a random shared secret for toolsrv auth.
|
// GenerateSecret generates a random shared secret for toolsrv auth.
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ import (
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
"ollie/cmd/toolsrv/internal/fs"
|
"ollie/cmd/toolsrv/internal/fs"
|
||||||
"ollie/fsedsl"
|
"ollie/virtfs"
|
||||||
|
|
||||||
"9fans.net/go/plan9"
|
"9fans.net/go/plan9"
|
||||||
)
|
)
|
||||||
|
|
@ -21,7 +21,7 @@ type fid struct {
|
||||||
qid plan9.Qid
|
qid plan9.Qid
|
||||||
mode uint8
|
mode uint8
|
||||||
opened bool
|
opened bool
|
||||||
entry fsedsl.File
|
entry virtfs.File
|
||||||
readBuf []byte // buffer for read data
|
readBuf []byte // buffer for read data
|
||||||
readDone bool // true if file has been read
|
readDone bool // true if file has been read
|
||||||
dirCache []byte
|
dirCache []byte
|
||||||
|
|
@ -46,8 +46,8 @@ type connState struct {
|
||||||
noAuth bool // skip authentication (for debugging)
|
noAuth bool // skip authentication (for debugging)
|
||||||
}
|
}
|
||||||
|
|
||||||
// serve9P handles a single 9P connection using the fsedsl tree.
|
// serve9P handles a single 9P connection using the virtfs tree.
|
||||||
func serve9P(ctx context.Context, conn net.Conn, tree *fsedsl.Tree, srv *fs.Server, noAuth bool) {
|
func serve9P(ctx context.Context, conn net.Conn, tree *virtfs.Tree, srv *fs.Server, noAuth bool) {
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
cs := &connState{
|
cs := &connState{
|
||||||
|
|
@ -81,7 +81,7 @@ func serve9P(ctx context.Context, conn net.Conn, tree *fsedsl.Tree, srv *fs.Serv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleFcall(cs *connState, fc *plan9.Fcall, tree *fsedsl.Tree) *plan9.Fcall {
|
func handleFcall(cs *connState, fc *plan9.Fcall, tree *virtfs.Tree) *plan9.Fcall {
|
||||||
switch fc.Type {
|
switch fc.Type {
|
||||||
case plan9.Tversion:
|
case plan9.Tversion:
|
||||||
return handleVersion(fc)
|
return handleVersion(fc)
|
||||||
|
|
@ -133,7 +133,7 @@ func handleAuth(cs *connState, fc *plan9.Fcall) *plan9.Fcall {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleAttach(cs *connState, fc *plan9.Fcall, tree *fsedsl.Tree) *plan9.Fcall {
|
func handleAttach(cs *connState, fc *plan9.Fcall, tree *virtfs.Tree) *plan9.Fcall {
|
||||||
// Skip auth check if noAuth is set (for debugging)
|
// Skip auth check if noAuth is set (for debugging)
|
||||||
if cs.noAuth {
|
if cs.noAuth {
|
||||||
cs.mu.Lock()
|
cs.mu.Lock()
|
||||||
|
|
@ -210,7 +210,7 @@ func handleAuthRead(cs *connState, fc *plan9.Fcall, af *authFid) *plan9.Fcall {
|
||||||
return &plan9.Fcall{Type: plan9.Rread, Tag: fc.Tag, Data: data[offset:end]}
|
return &plan9.Fcall{Type: plan9.Rread, Tag: fc.Tag, Data: data[offset:end]}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleWalk(cs *connState, fc *plan9.Fcall, tree *fsedsl.Tree) *plan9.Fcall {
|
func handleWalk(cs *connState, fc *plan9.Fcall, tree *virtfs.Tree) *plan9.Fcall {
|
||||||
cs.mu.RLock()
|
cs.mu.RLock()
|
||||||
f, ok := cs.fids[fc.Fid]
|
f, ok := cs.fids[fc.Fid]
|
||||||
cs.mu.RUnlock()
|
cs.mu.RUnlock()
|
||||||
|
|
@ -288,7 +288,7 @@ func handleWalk(cs *connState, fc *plan9.Fcall, tree *fsedsl.Tree) *plan9.Fcall
|
||||||
return &plan9.Fcall{Type: plan9.Rwalk, Tag: fc.Tag, Wqid: qids}
|
return &plan9.Fcall{Type: plan9.Rwalk, Tag: fc.Tag, Wqid: qids}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleOpen(cs *connState, fc *plan9.Fcall, tree *fsedsl.Tree) *plan9.Fcall {
|
func handleOpen(cs *connState, fc *plan9.Fcall, tree *virtfs.Tree) *plan9.Fcall {
|
||||||
cs.mu.Lock()
|
cs.mu.Lock()
|
||||||
defer cs.mu.Unlock()
|
defer cs.mu.Unlock()
|
||||||
|
|
||||||
|
|
@ -325,7 +325,7 @@ func handleOpen(cs *connState, fc *plan9.Fcall, tree *fsedsl.Tree) *plan9.Fcall
|
||||||
return &plan9.Fcall{Type: plan9.Ropen, Tag: fc.Tag, Qid: f.qid, Iounit: 8192}
|
return &plan9.Fcall{Type: plan9.Ropen, Tag: fc.Tag, Qid: f.qid, Iounit: 8192}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleRead(cs *connState, fc *plan9.Fcall, tree *fsedsl.Tree) *plan9.Fcall {
|
func handleRead(cs *connState, fc *plan9.Fcall, tree *virtfs.Tree) *plan9.Fcall {
|
||||||
// Check if reading from auth fid
|
// Check if reading from auth fid
|
||||||
cs.mu.RLock()
|
cs.mu.RLock()
|
||||||
af, isAuthFid := cs.authFids[fc.Fid]
|
af, isAuthFid := cs.authFids[fc.Fid]
|
||||||
|
|
@ -380,7 +380,7 @@ func handleRead(cs *connState, fc *plan9.Fcall, tree *fsedsl.Tree) *plan9.Fcall
|
||||||
return &plan9.Fcall{Type: plan9.Rread, Tag: fc.Tag, Data: f.readBuf[offset:end]}
|
return &plan9.Fcall{Type: plan9.Rread, Tag: fc.Tag, Data: f.readBuf[offset:end]}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleDirRead(cs *connState, f *fid, fc *plan9.Fcall, tree *fsedsl.Tree) *plan9.Fcall {
|
func handleDirRead(cs *connState, f *fid, fc *plan9.Fcall, tree *virtfs.Tree) *plan9.Fcall {
|
||||||
if fc.Offset == 0 || f.dirCache == nil {
|
if fc.Offset == 0 || f.dirCache == nil {
|
||||||
path := f.path
|
path := f.path
|
||||||
if path == "/" {
|
if path == "/" {
|
||||||
|
|
@ -428,7 +428,7 @@ func handleDirRead(cs *connState, f *fid, fc *plan9.Fcall, tree *fsedsl.Tree) *p
|
||||||
return &plan9.Fcall{Type: plan9.Rread, Tag: fc.Tag, Data: f.dirCache[offset:end]}
|
return &plan9.Fcall{Type: plan9.Rread, Tag: fc.Tag, Data: f.dirCache[offset:end]}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleWrite(cs *connState, fc *plan9.Fcall, tree *fsedsl.Tree) *plan9.Fcall {
|
func handleWrite(cs *connState, fc *plan9.Fcall, tree *virtfs.Tree) *plan9.Fcall {
|
||||||
// Check if writing to auth fid
|
// Check if writing to auth fid
|
||||||
cs.mu.Lock()
|
cs.mu.Lock()
|
||||||
af, isAuthFid := cs.authFids[fc.Fid]
|
af, isAuthFid := cs.authFids[fc.Fid]
|
||||||
|
|
@ -465,7 +465,7 @@ func handleClunk(cs *connState, fc *plan9.Fcall) *plan9.Fcall {
|
||||||
return &plan9.Fcall{Type: plan9.Rclunk, Tag: fc.Tag}
|
return &plan9.Fcall{Type: plan9.Rclunk, Tag: fc.Tag}
|
||||||
}
|
}
|
||||||
|
|
||||||
func handleStat(cs *connState, fc *plan9.Fcall, tree *fsedsl.Tree) *plan9.Fcall {
|
func handleStat(cs *connState, fc *plan9.Fcall, tree *virtfs.Tree) *plan9.Fcall {
|
||||||
cs.mu.RLock()
|
cs.mu.RLock()
|
||||||
f, ok := cs.fids[fc.Fid]
|
f, ok := cs.fids[fc.Fid]
|
||||||
cs.mu.RUnlock()
|
cs.mu.RUnlock()
|
||||||
|
|
|
||||||
|
|
@ -1,3 +0,0 @@
|
||||||
module ollie/fsedsl
|
|
||||||
|
|
||||||
go 1.25.6
|
|
||||||
4
go.mod
4
go.mod
|
|
@ -9,9 +9,9 @@ require (
|
||||||
github.com/simonfxr/pubsub v0.0.5
|
github.com/simonfxr/pubsub v0.0.5
|
||||||
golang.org/x/time v0.15.0
|
golang.org/x/time v0.15.0
|
||||||
gopkg.in/yaml.v3 v3.0.1
|
gopkg.in/yaml.v3 v3.0.1
|
||||||
ollie/fsedsl v0.0.0
|
ollie/virtfs v0.0.0
|
||||||
)
|
)
|
||||||
|
|
||||||
require golang.org/x/sys v0.47.0 // indirect
|
require golang.org/x/sys v0.47.0 // indirect
|
||||||
|
|
||||||
replace ollie/fsedsl => ./fsedsl
|
replace ollie/virtfs => ./virtfs
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
# fsedsl
|
# virtfs
|
||||||
|
|
||||||
A Go library providing an embedded domain-specific language (EDSL) for declaring synthetic filesystems. Define your namespace structure statically while populating it dynamically at runtime.
|
A Go library providing an embedded domain-specific language (EDSL) for declaring synthetic filesystems. Define your namespace structure statically while populating it dynamically at runtime.
|
||||||
|
|
||||||
|
|
@ -14,19 +14,19 @@ The library produces a generic `Tree` that can be used with any filesystem proto
|
||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
|
|
||||||
The library is currently embedded in the [ollie](https://git.lneely.de/lkn/ollie) repository at `fsedsl/`.
|
The library is currently embedded in the [ollie](https://git.lneely.de/lkn/ollie) repository at `virtfs/`.
|
||||||
|
|
||||||
To use it in your project, add a replace directive to your `go.mod`:
|
To use it in your project, add a replace directive to your `go.mod`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Clone or copy the fsedsl directory to your project, then:
|
# Clone or copy the virtfs directory to your project, then:
|
||||||
go mod edit -replace=git.lneely.de/lkn/fsedsl=./fsedsl
|
go mod edit -replace=git.lneely.de/lkn/virtfs=./virtfs
|
||||||
```
|
```
|
||||||
|
|
||||||
Or reference it directly from the ollie repo:
|
Or reference it directly from the ollie repo:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
go mod edit -replace=git.lneely.de/lkn/fsedsl=git.lneely.de/lkn/ollie/fsedsl@main
|
go mod edit -replace=git.lneely.de/lkn/virtfs=git.lneely.de/lkn/ollie/virtfs@main
|
||||||
```
|
```
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
@ -36,7 +36,7 @@ package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"git.lneely.de/lkn/fsedsl"
|
"git.lneely.de/lkn/virtfs"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Ctx struct {
|
type Ctx struct {
|
||||||
|
|
@ -55,18 +55,18 @@ var users = []*User{
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// Declare the filesystem spec
|
// Declare the filesystem spec
|
||||||
spec := fsedsl.DirNode[Ctx]("/",
|
spec := virtfs.DirNode[Ctx]("/",
|
||||||
fsedsl.FileNode[Ctx]("version", 0444,
|
virtfs.FileNode[Ctx]("version", 0444,
|
||||||
fsedsl.Doc[Ctx]("API version"),
|
virtfs.Doc[Ctx]("API version"),
|
||||||
fsedsl.Read(func(ctx Ctx) ([]byte, error) {
|
virtfs.Read(func(ctx Ctx) ([]byte, error) {
|
||||||
return []byte("1.0\n"), nil
|
return []byte("1.0\n"), nil
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
fsedsl.Each[Ctx]("{user}", func(ctx Ctx) ([]fsedsl.Binding[Ctx], error) {
|
virtfs.Each[Ctx]("{user}", func(ctx Ctx) ([]virtfs.Binding[Ctx], error) {
|
||||||
var out []fsedsl.Binding[Ctx]
|
var out []virtfs.Binding[Ctx]
|
||||||
for _, u := range users {
|
for _, u := range users {
|
||||||
user := u // capture
|
user := u // capture
|
||||||
out = append(out, fsedsl.Binding[Ctx]{
|
out = append(out, virtfs.Binding[Ctx]{
|
||||||
Name: user.Name,
|
Name: user.Name,
|
||||||
Aliases: []string{user.ID},
|
Aliases: []string{user.ID},
|
||||||
Applier: func(c Ctx) Ctx {
|
Applier: func(c Ctx) Ctx {
|
||||||
|
|
@ -77,13 +77,13 @@ func main() {
|
||||||
}
|
}
|
||||||
return out, nil
|
return out, nil
|
||||||
},
|
},
|
||||||
fsedsl.FileNode[Ctx]("id", 0444,
|
virtfs.FileNode[Ctx]("id", 0444,
|
||||||
fsedsl.Read(func(ctx Ctx) ([]byte, error) {
|
virtfs.Read(func(ctx Ctx) ([]byte, error) {
|
||||||
return []byte(ctx.User.ID + "\n"), nil
|
return []byte(ctx.User.ID + "\n"), nil
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
fsedsl.FileNode[Ctx]("name", 0444,
|
virtfs.FileNode[Ctx]("name", 0444,
|
||||||
fsedsl.Read(func(ctx Ctx) ([]byte, error) {
|
virtfs.Read(func(ctx Ctx) ([]byte, error) {
|
||||||
return []byte(ctx.User.Name + "\n"), nil
|
return []byte(ctx.User.Name + "\n"), nil
|
||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
|
|
@ -91,7 +91,7 @@ func main() {
|
||||||
)
|
)
|
||||||
|
|
||||||
// Build the tree
|
// Build the tree
|
||||||
tree := fsedsl.BuildTree(spec, Ctx{})
|
tree := virtfs.BuildTree(spec, Ctx{})
|
||||||
|
|
||||||
// Use the tree
|
// Use the tree
|
||||||
entries, _ := tree.List()
|
entries, _ := tree.List()
|
||||||
|
|
@ -112,7 +112,7 @@ Define your context type, then create type and function aliases that bake it in:
|
||||||
```go
|
```go
|
||||||
package fs
|
package fs
|
||||||
|
|
||||||
import "git.lneely.de/lkn/fsedsl"
|
import "git.lneely.de/lkn/virtfs"
|
||||||
|
|
||||||
// Ctx carries runtime dependencies for handler functions.
|
// Ctx carries runtime dependencies for handler functions.
|
||||||
type Ctx struct {
|
type Ctx struct {
|
||||||
|
|
@ -122,19 +122,19 @@ type Ctx struct {
|
||||||
|
|
||||||
// Type aliases for external consumers
|
// Type aliases for external consumers
|
||||||
type (
|
type (
|
||||||
FsNodeDecl = fsedsl.FsNodeDecl[Ctx]
|
FsNodeDecl = virtfs.FsNodeDecl[Ctx]
|
||||||
Binding = fsedsl.Binding[Ctx]
|
Binding = virtfs.Binding[Ctx]
|
||||||
Tree = fsedsl.Tree
|
Tree = virtfs.Tree
|
||||||
)
|
)
|
||||||
|
|
||||||
// Function aliases for clean spec definitions
|
// Function aliases for clean spec definitions
|
||||||
var (
|
var (
|
||||||
DirNode = fsedsl.DirNode[Ctx]
|
DirNode = virtfs.DirNode[Ctx]
|
||||||
FileNode = fsedsl.FileNode[Ctx]
|
FileNode = virtfs.FileNode[Ctx]
|
||||||
Each = fsedsl.Each[Ctx]
|
Each = virtfs.Each[Ctx]
|
||||||
Doc = fsedsl.Doc[Ctx]
|
Doc = virtfs.Doc[Ctx]
|
||||||
Read = fsedsl.Read[Ctx]
|
Read = virtfs.Read[Ctx]
|
||||||
Write = fsedsl.Write[Ctx]
|
Write = virtfs.Write[Ctx]
|
||||||
// ... add others as needed
|
// ... add others as needed
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -172,7 +172,7 @@ func userBindings(ctx Ctx) ([]Binding, error) {
|
||||||
Build and use:
|
Build and use:
|
||||||
|
|
||||||
```go
|
```go
|
||||||
tree := fsedsl.BuildTree(fs.Spec, fs.Ctx{DB: db})
|
tree := virtfs.BuildTree(fs.Spec, fs.Ctx{DB: db})
|
||||||
entries, _ := tree.List()
|
entries, _ := tree.List()
|
||||||
f, _ := tree.Open("alice/name")
|
f, _ := tree.Open("alice/name")
|
||||||
data, _ := f.Read()
|
data, _ := f.Read()
|
||||||
|
|
@ -208,7 +208,7 @@ data, _ := f.Read()
|
||||||
### Binding
|
### Binding
|
||||||
|
|
||||||
```go
|
```go
|
||||||
fsedsl.Binding[Ctx]{
|
virtfs.Binding[Ctx]{
|
||||||
Name: "filename", // Primary name
|
Name: "filename", // Primary name
|
||||||
Aliases: []string{"alt-name"}, // Alternate lookup names
|
Aliases: []string{"alt-name"}, // Alternate lookup names
|
||||||
UID: "owner", // Owner (optional)
|
UID: "owner", // Owner (optional)
|
||||||
|
|
@ -225,7 +225,7 @@ fsedsl.Binding[Ctx]{
|
||||||
### Tree Operations
|
### Tree Operations
|
||||||
|
|
||||||
```go
|
```go
|
||||||
tree := fsedsl.BuildTree(spec, rootCtx)
|
tree := virtfs.BuildTree(spec, rootCtx)
|
||||||
|
|
||||||
tree.List() // List entries
|
tree.List() // List entries
|
||||||
tree.Stat(name) // Get file info
|
tree.Stat(name) // Get file info
|
||||||
|
|
@ -239,7 +239,7 @@ tree.Readdir(path) // List subdirectory
|
||||||
### Help Generation
|
### Help Generation
|
||||||
|
|
||||||
```go
|
```go
|
||||||
help := fsedsl.GenerateHelp(spec)
|
help := virtfs.GenerateHelp(spec)
|
||||||
// Returns formatted documentation from Doc() annotations
|
// Returns formatted documentation from Doc() annotations
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fsedsl
|
package virtfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
// Package fsedsl provides an embedded domain-specific language for declaring
|
// Package virtfs provides an embedded domain-specific language for declaring
|
||||||
// synthetic filesystems. It is designed for building 9P namespaces where the
|
// synthetic filesystems. It is designed for building 9P namespaces where the
|
||||||
// entire filesystem structure is declared statically but populated dynamically.
|
// entire filesystem structure is declared statically but populated dynamically.
|
||||||
//
|
//
|
||||||
|
|
@ -30,7 +30,7 @@
|
||||||
// )
|
// )
|
||||||
//
|
//
|
||||||
// tree := BuildTree(spec)
|
// tree := BuildTree(spec)
|
||||||
package fsedsl
|
package virtfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fsedsl
|
package virtfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fsedsl
|
package virtfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
|
@ -0,0 +1,3 @@
|
||||||
|
module ollie/virtfs
|
||||||
|
|
||||||
|
go 1.25.6
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fsedsl
|
package virtfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fsedsl
|
package virtfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
package fsedsl
|
package virtfs
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
Loading…
Reference in New Issue