fs: pass NostrRoot everywhere with a signer only if it can actually sign.

This commit is contained in:
fiatjaf 2025-03-11 13:18:33 -03:00
parent bfe1e6ca94
commit c87371208e
6 changed files with 119 additions and 137 deletions

13
fs.go
View File

@ -22,7 +22,7 @@ var fsCmd = &cli.Command{
Usage: "mount a FUSE filesystem that exposes Nostr events as files.", Usage: "mount a FUSE filesystem that exposes Nostr events as files.",
Description: `(experimental)`, Description: `(experimental)`,
ArgsUsage: "<mountpoint>", ArgsUsage: "<mountpoint>",
Flags: []cli.Flag{ Flags: append(defaultKeyFlags,
&cli.StringFlag{ &cli.StringFlag{
Name: "pubkey", Name: "pubkey",
Usage: "public key from where to to prepopulate directories", Usage: "public key from where to to prepopulate directories",
@ -33,7 +33,7 @@ var fsCmd = &cli.Command{
return fmt.Errorf("invalid public key '%s'", pk) return fmt.Errorf("invalid public key '%s'", pk)
}, },
}, },
}, ),
DisableSliceFlagSeparator: true, DisableSliceFlagSeparator: true,
Action: func(ctx context.Context, c *cli.Command) error { Action: func(ctx context.Context, c *cli.Command) error {
mountpoint := c.Args().First() mountpoint := c.Args().First()
@ -41,10 +41,17 @@ var fsCmd = &cli.Command{
return fmt.Errorf("must be called with a directory path to serve as the mountpoint as an argument") return fmt.Errorf("must be called with a directory path to serve as the mountpoint as an argument")
} }
var kr nostr.User
if signer, _, err := gatherKeyerFromArguments(ctx, c); err == nil {
kr = signer
} else {
kr = keyer.NewReadOnlyUser(c.String("pubkey"))
}
root := nostrfs.NewNostrRoot( root := nostrfs.NewNostrRoot(
context.WithValue(ctx, "log", log), context.WithValue(ctx, "log", log),
sys, sys,
keyer.NewReadOnlyUser(c.String("pubkey")), kr,
mountpoint, mountpoint,
) )

View File

@ -42,36 +42,31 @@ func (e *EntityDir) Getattr(_ context.Context, f fs.FileHandle, out *fuse.AttrOu
return fs.OK return fs.OK
} }
func FetchAndCreateEntityDir( func (r *NostrRoot) FetchAndCreateEntityDir(
ctx context.Context,
parent fs.InodeEmbedder, parent fs.InodeEmbedder,
wd string,
extension string, extension string,
sys *sdk.System,
pointer nostr.EntityPointer, pointer nostr.EntityPointer,
) (*fs.Inode, error) { ) (*fs.Inode, error) {
event, _, err := sys.FetchSpecificEvent(ctx, pointer, sdk.FetchSpecificEventParameters{ event, _, err := r.sys.FetchSpecificEvent(r.ctx, pointer, sdk.FetchSpecificEventParameters{
WithRelays: false, WithRelays: false,
}) })
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to fetch: %w", err) return nil, fmt.Errorf("failed to fetch: %w", err)
} }
return CreateEntityDir(ctx, parent, wd, extension, event), nil return r.CreateEntityDir(parent, extension, event), nil
} }
func CreateEntityDir( func (r *NostrRoot) CreateEntityDir(
ctx context.Context,
parent fs.InodeEmbedder, parent fs.InodeEmbedder,
wd string,
extension string, extension string,
event *nostr.Event, event *nostr.Event,
) *fs.Inode { ) *fs.Inode {
log := ctx.Value("log").(func(msg string, args ...any)) log := r.ctx.Value("log").(func(msg string, args ...any))
h := parent.EmbeddedInode().NewPersistentInode( h := parent.EmbeddedInode().NewPersistentInode(
ctx, r.ctx,
&EntityDir{ctx: ctx, wd: wd, evt: event}, &EntityDir{ctx: r.ctx, wd: r.wd, evt: event},
fs.StableAttr{Mode: syscall.S_IFDIR, Ino: hexToUint64(event.ID)}, fs.StableAttr{Mode: syscall.S_IFDIR, Ino: hexToUint64(event.ID)},
) )
@ -82,16 +77,16 @@ func CreateEntityDir(
npub, _ := nip19.EncodePublicKey(event.PubKey) npub, _ := nip19.EncodePublicKey(event.PubKey)
h.AddChild("@author", h.NewPersistentInode( h.AddChild("@author", h.NewPersistentInode(
ctx, r.ctx,
&fs.MemSymlink{ &fs.MemSymlink{
Data: []byte(wd + "/" + npub), Data: []byte(r.wd + "/" + npub),
}, },
fs.StableAttr{Mode: syscall.S_IFLNK}, fs.StableAttr{Mode: syscall.S_IFLNK},
), true) ), true)
eventj, _ := json.MarshalIndent(event, "", " ") eventj, _ := json.MarshalIndent(event, "", " ")
h.AddChild("event.json", h.NewPersistentInode( h.AddChild("event.json", h.NewPersistentInode(
ctx, r.ctx,
&fs.MemRegularFile{ &fs.MemRegularFile{
Data: eventj, Data: eventj,
Attr: fuse.Attr{ Attr: fuse.Attr{
@ -105,7 +100,7 @@ func CreateEntityDir(
), true) ), true)
h.AddChild("identifier", h.NewPersistentInode( h.AddChild("identifier", h.NewPersistentInode(
ctx, r.ctx,
&fs.MemRegularFile{ &fs.MemRegularFile{
Data: []byte(event.Tags.GetD()), Data: []byte(event.Tags.GetD()),
Attr: fuse.Attr{ Attr: fuse.Attr{
@ -120,7 +115,7 @@ func CreateEntityDir(
if tag := event.Tags.Find("title"); tag != nil { if tag := event.Tags.Find("title"); tag != nil {
h.AddChild("title", h.NewPersistentInode( h.AddChild("title", h.NewPersistentInode(
ctx, r.ctx,
&fs.MemRegularFile{ &fs.MemRegularFile{
Data: []byte(tag[1]), Data: []byte(tag[1]),
Attr: fuse.Attr{ Attr: fuse.Attr{
@ -135,7 +130,7 @@ func CreateEntityDir(
} }
h.AddChild("content"+extension, h.NewPersistentInode( h.AddChild("content"+extension, h.NewPersistentInode(
ctx, r.ctx,
&fs.MemRegularFile{ &fs.MemRegularFile{
Data: []byte(event.Content), Data: []byte(event.Content),
Attr: fuse.Attr{ Attr: fuse.Attr{
@ -153,13 +148,13 @@ func CreateEntityDir(
for ref := range nip27.ParseReferences(*event) { for ref := range nip27.ParseReferences(*event) {
i++ i++
if refsdir == nil { if refsdir == nil {
refsdir = h.NewPersistentInode(ctx, &fs.Inode{}, fs.StableAttr{Mode: syscall.S_IFDIR}) refsdir = h.NewPersistentInode(r.ctx, &fs.Inode{}, fs.StableAttr{Mode: syscall.S_IFDIR})
h.AddChild("references", refsdir, true) h.AddChild("references", refsdir, true)
} }
refsdir.AddChild(fmt.Sprintf("ref_%02d", i), refsdir.NewPersistentInode( refsdir.AddChild(fmt.Sprintf("ref_%02d", i), refsdir.NewPersistentInode(
ctx, r.ctx,
&fs.MemSymlink{ &fs.MemSymlink{
Data: []byte(wd + "/" + nip19.EncodePointer(ref.Pointer)), Data: []byte(r.wd + "/" + nip19.EncodePointer(ref.Pointer)),
}, },
fs.StableAttr{Mode: syscall.S_IFLNK}, fs.StableAttr{Mode: syscall.S_IFLNK},
), true) ), true)
@ -169,15 +164,15 @@ func CreateEntityDir(
addImage := func(url string) { addImage := func(url string) {
if imagesdir == nil { if imagesdir == nil {
in := &fs.Inode{} in := &fs.Inode{}
imagesdir = h.NewPersistentInode(ctx, in, fs.StableAttr{Mode: syscall.S_IFDIR}) imagesdir = h.NewPersistentInode(r.ctx, in, fs.StableAttr{Mode: syscall.S_IFDIR})
h.AddChild("images", imagesdir, true) h.AddChild("images", imagesdir, true)
} }
imagesdir.AddChild(filepath.Base(url), imagesdir.NewPersistentInode( imagesdir.AddChild(filepath.Base(url), imagesdir.NewPersistentInode(
ctx, r.ctx,
&AsyncFile{ &AsyncFile{
ctx: ctx, ctx: r.ctx,
load: func() ([]byte, nostr.Timestamp) { load: func() ([]byte, nostr.Timestamp) {
ctx, cancel := context.WithTimeout(ctx, time.Second*20) ctx, cancel := context.WithTimeout(r.ctx, time.Second*20)
defer cancel() defer cancel()
r, err := http.NewRequestWithContext(ctx, "GET", url, nil) r, err := http.NewRequestWithContext(ctx, "GET", url, nil)
if err != nil { if err != nil {

View File

@ -36,47 +36,42 @@ func (e *EventDir) Getattr(_ context.Context, f fs.FileHandle, out *fuse.AttrOut
return fs.OK return fs.OK
} }
func FetchAndCreateEventDir( func (r *NostrRoot) FetchAndCreateEventDir(
ctx context.Context,
parent fs.InodeEmbedder, parent fs.InodeEmbedder,
wd string,
sys *sdk.System,
pointer nostr.EventPointer, pointer nostr.EventPointer,
) (*fs.Inode, error) { ) (*fs.Inode, error) {
event, _, err := sys.FetchSpecificEvent(ctx, pointer, sdk.FetchSpecificEventParameters{ event, _, err := r.sys.FetchSpecificEvent(r.ctx, pointer, sdk.FetchSpecificEventParameters{
WithRelays: false, WithRelays: false,
}) })
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to fetch: %w", err) return nil, fmt.Errorf("failed to fetch: %w", err)
} }
return CreateEventDir(ctx, parent, wd, event), nil return r.CreateEventDir(parent, event), nil
} }
func CreateEventDir( func (r *NostrRoot) CreateEventDir(
ctx context.Context,
parent fs.InodeEmbedder, parent fs.InodeEmbedder,
wd string,
event *nostr.Event, event *nostr.Event,
) *fs.Inode { ) *fs.Inode {
h := parent.EmbeddedInode().NewPersistentInode( h := parent.EmbeddedInode().NewPersistentInode(
ctx, r.ctx,
&EventDir{ctx: ctx, wd: wd, evt: event}, &EventDir{ctx: r.ctx, wd: r.wd, evt: event},
fs.StableAttr{Mode: syscall.S_IFDIR, Ino: hexToUint64(event.ID)}, fs.StableAttr{Mode: syscall.S_IFDIR, Ino: hexToUint64(event.ID)},
) )
npub, _ := nip19.EncodePublicKey(event.PubKey) npub, _ := nip19.EncodePublicKey(event.PubKey)
h.AddChild("@author", h.NewPersistentInode( h.AddChild("@author", h.NewPersistentInode(
ctx, r.ctx,
&fs.MemSymlink{ &fs.MemSymlink{
Data: []byte(wd + "/" + npub), Data: []byte(r.wd + "/" + npub),
}, },
fs.StableAttr{Mode: syscall.S_IFLNK}, fs.StableAttr{Mode: syscall.S_IFLNK},
), true) ), true)
eventj, _ := json.MarshalIndent(event, "", " ") eventj, _ := json.MarshalIndent(event, "", " ")
h.AddChild("event.json", h.NewPersistentInode( h.AddChild("event.json", h.NewPersistentInode(
ctx, r.ctx,
&fs.MemRegularFile{ &fs.MemRegularFile{
Data: eventj, Data: eventj,
Attr: fuse.Attr{ Attr: fuse.Attr{
@ -90,7 +85,7 @@ func CreateEventDir(
), true) ), true)
h.AddChild("id", h.NewPersistentInode( h.AddChild("id", h.NewPersistentInode(
ctx, r.ctx,
&fs.MemRegularFile{ &fs.MemRegularFile{
Data: []byte(event.ID), Data: []byte(event.ID),
Attr: fuse.Attr{ Attr: fuse.Attr{
@ -104,7 +99,7 @@ func CreateEventDir(
), true) ), true)
h.AddChild("content.txt", h.NewPersistentInode( h.AddChild("content.txt", h.NewPersistentInode(
ctx, r.ctx,
&fs.MemRegularFile{ &fs.MemRegularFile{
Data: []byte(event.Content), Data: []byte(event.Content),
Attr: fuse.Attr{ Attr: fuse.Attr{
@ -122,13 +117,13 @@ func CreateEventDir(
for ref := range nip27.ParseReferences(*event) { for ref := range nip27.ParseReferences(*event) {
i++ i++
if refsdir == nil { if refsdir == nil {
refsdir = h.NewPersistentInode(ctx, &fs.Inode{}, fs.StableAttr{Mode: syscall.S_IFDIR}) refsdir = h.NewPersistentInode(r.ctx, &fs.Inode{}, fs.StableAttr{Mode: syscall.S_IFDIR})
h.AddChild("references", refsdir, true) h.AddChild("references", refsdir, true)
} }
refsdir.AddChild(fmt.Sprintf("ref_%02d", i), refsdir.NewPersistentInode( refsdir.AddChild(fmt.Sprintf("ref_%02d", i), refsdir.NewPersistentInode(
ctx, r.ctx,
&fs.MemSymlink{ &fs.MemSymlink{
Data: []byte(wd + "/" + nip19.EncodePointer(ref.Pointer)), Data: []byte(r.wd + "/" + nip19.EncodePointer(ref.Pointer)),
}, },
fs.StableAttr{Mode: syscall.S_IFLNK}, fs.StableAttr{Mode: syscall.S_IFLNK},
), true) ), true)
@ -142,15 +137,15 @@ func CreateEventDir(
} }
if imagesdir == nil { if imagesdir == nil {
in := &fs.Inode{} in := &fs.Inode{}
imagesdir = h.NewPersistentInode(ctx, in, fs.StableAttr{Mode: syscall.S_IFDIR}) imagesdir = h.NewPersistentInode(r.ctx, in, fs.StableAttr{Mode: syscall.S_IFDIR})
h.AddChild("images", imagesdir, true) h.AddChild("images", imagesdir, true)
} }
imagesdir.AddChild(filepath.Base(imeta.URL), imagesdir.NewPersistentInode( imagesdir.AddChild(filepath.Base(imeta.URL), imagesdir.NewPersistentInode(
ctx, r.ctx,
&AsyncFile{ &AsyncFile{
ctx: ctx, ctx: r.ctx,
load: func() ([]byte, nostr.Timestamp) { load: func() ([]byte, nostr.Timestamp) {
ctx, cancel := context.WithTimeout(ctx, time.Second*20) ctx, cancel := context.WithTimeout(r.ctx, time.Second*20)
defer cancel() defer cancel()
r, err := http.NewRequestWithContext(ctx, "GET", imeta.URL, nil) r, err := http.NewRequestWithContext(ctx, "GET", imeta.URL, nil)
if err != nil { if err != nil {
@ -177,9 +172,9 @@ func CreateEventDir(
if pointer := nip10.GetThreadRoot(event.Tags); pointer != nil { if pointer := nip10.GetThreadRoot(event.Tags); pointer != nil {
nevent := nip19.EncodePointer(*pointer) nevent := nip19.EncodePointer(*pointer)
h.AddChild("@root", h.NewPersistentInode( h.AddChild("@root", h.NewPersistentInode(
ctx, r.ctx,
&fs.MemSymlink{ &fs.MemSymlink{
Data: []byte(wd + "/" + nevent), Data: []byte(r.wd + "/" + nevent),
}, },
fs.StableAttr{Mode: syscall.S_IFLNK}, fs.StableAttr{Mode: syscall.S_IFLNK},
), true) ), true)
@ -187,9 +182,9 @@ func CreateEventDir(
if pointer := nip10.GetImmediateParent(event.Tags); pointer != nil { if pointer := nip10.GetImmediateParent(event.Tags); pointer != nil {
nevent := nip19.EncodePointer(*pointer) nevent := nip19.EncodePointer(*pointer)
h.AddChild("@parent", h.NewPersistentInode( h.AddChild("@parent", h.NewPersistentInode(
ctx, r.ctx,
&fs.MemSymlink{ &fs.MemSymlink{
Data: []byte(wd + "/" + nevent), Data: []byte(r.wd + "/" + nevent),
}, },
fs.StableAttr{Mode: syscall.S_IFLNK}, fs.StableAttr{Mode: syscall.S_IFLNK},
), true) ), true)
@ -198,7 +193,7 @@ func CreateEventDir(
if pointer := nip22.GetThreadRoot(event.Tags); pointer != nil { if pointer := nip22.GetThreadRoot(event.Tags); pointer != nil {
if xp, ok := pointer.(nostr.ExternalPointer); ok { if xp, ok := pointer.(nostr.ExternalPointer); ok {
h.AddChild("@root", h.NewPersistentInode( h.AddChild("@root", h.NewPersistentInode(
ctx, r.ctx,
&fs.MemRegularFile{ &fs.MemRegularFile{
Data: []byte(`<!doctype html><meta http-equiv="refresh" content="0; url=` + xp.Thing + `" />`), Data: []byte(`<!doctype html><meta http-equiv="refresh" content="0; url=` + xp.Thing + `" />`),
}, },
@ -207,9 +202,9 @@ func CreateEventDir(
} else { } else {
nevent := nip19.EncodePointer(pointer) nevent := nip19.EncodePointer(pointer)
h.AddChild("@parent", h.NewPersistentInode( h.AddChild("@parent", h.NewPersistentInode(
ctx, r.ctx,
&fs.MemSymlink{ &fs.MemSymlink{
Data: []byte(wd + "/" + nevent), Data: []byte(r.wd + "/" + nevent),
}, },
fs.StableAttr{Mode: syscall.S_IFLNK}, fs.StableAttr{Mode: syscall.S_IFLNK},
), true) ), true)
@ -218,7 +213,7 @@ func CreateEventDir(
if pointer := nip22.GetImmediateParent(event.Tags); pointer != nil { if pointer := nip22.GetImmediateParent(event.Tags); pointer != nil {
if xp, ok := pointer.(nostr.ExternalPointer); ok { if xp, ok := pointer.(nostr.ExternalPointer); ok {
h.AddChild("@parent", h.NewPersistentInode( h.AddChild("@parent", h.NewPersistentInode(
ctx, r.ctx,
&fs.MemRegularFile{ &fs.MemRegularFile{
Data: []byte(`<!doctype html><meta http-equiv="refresh" content="0; url=` + xp.Thing + `" />`), Data: []byte(`<!doctype html><meta http-equiv="refresh" content="0; url=` + xp.Thing + `" />`),
}, },
@ -227,9 +222,9 @@ func CreateEventDir(
} else { } else {
nevent := nip19.EncodePointer(pointer) nevent := nip19.EncodePointer(pointer)
h.AddChild("@parent", h.NewPersistentInode( h.AddChild("@parent", h.NewPersistentInode(
ctx, r.ctx,
&fs.MemSymlink{ &fs.MemSymlink{
Data: []byte(wd + "/" + nevent), Data: []byte(r.wd + "/" + nevent),
}, },
fs.StableAttr{Mode: syscall.S_IFLNK}, fs.StableAttr{Mode: syscall.S_IFLNK},
), true) ), true)

View File

@ -14,41 +14,37 @@ import (
"github.com/hanwen/go-fuse/v2/fuse" "github.com/hanwen/go-fuse/v2/fuse"
"github.com/liamg/magic" "github.com/liamg/magic"
"github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr"
sdk "github.com/nbd-wtf/go-nostr/sdk"
) )
type NpubDir struct { type NpubDir struct {
sys *sdk.System
fs.Inode fs.Inode
root *NostrRoot
pointer nostr.ProfilePointer pointer nostr.ProfilePointer
ctx context.Context
fetched atomic.Bool fetched atomic.Bool
} }
func CreateNpubDir( func (r *NostrRoot) CreateNpubDir(
ctx context.Context,
sys *sdk.System,
parent fs.InodeEmbedder, parent fs.InodeEmbedder,
wd string,
pointer nostr.ProfilePointer, pointer nostr.ProfilePointer,
signer nostr.Signer,
) *fs.Inode { ) *fs.Inode {
npubdir := &NpubDir{ctx: ctx, sys: sys, pointer: pointer} npubdir := &NpubDir{root: r, pointer: pointer}
h := parent.EmbeddedInode().NewPersistentInode( h := parent.EmbeddedInode().NewPersistentInode(
ctx, r.ctx,
npubdir, npubdir,
fs.StableAttr{Mode: syscall.S_IFDIR, Ino: hexToUint64(pointer.PublicKey)}, fs.StableAttr{Mode: syscall.S_IFDIR, Ino: hexToUint64(pointer.PublicKey)},
) )
relays := sys.FetchOutboxRelays(ctx, pointer.PublicKey, 2) relays := r.sys.FetchOutboxRelays(r.ctx, pointer.PublicKey, 2)
h.AddChild("pubkey", h.NewPersistentInode( h.AddChild("pubkey", h.NewPersistentInode(
ctx, r.ctx,
&fs.MemRegularFile{Data: []byte(pointer.PublicKey + "\n"), Attr: fuse.Attr{Mode: 0444}}, &fs.MemRegularFile{Data: []byte(pointer.PublicKey + "\n"), Attr: fuse.Attr{Mode: 0444}},
fs.StableAttr{}, fs.StableAttr{},
), true) ), true)
go func() { go func() {
pm := sys.FetchProfileMetadata(ctx, pointer.PublicKey) pm := r.sys.FetchProfileMetadata(r.ctx, pointer.PublicKey)
if pm.Event == nil { if pm.Event == nil {
return return
} }
@ -57,7 +53,7 @@ func CreateNpubDir(
h.AddChild( h.AddChild(
"metadata.json", "metadata.json",
h.NewPersistentInode( h.NewPersistentInode(
ctx, r.ctx,
&fs.MemRegularFile{ &fs.MemRegularFile{
Data: metadataj, Data: metadataj,
Attr: fuse.Attr{ Attr: fuse.Attr{
@ -70,7 +66,7 @@ func CreateNpubDir(
true, true,
) )
ctx, cancel := context.WithTimeout(ctx, time.Second*20) ctx, cancel := context.WithTimeout(r.ctx, time.Second*20)
defer cancel() defer cancel()
r, err := http.NewRequestWithContext(ctx, "GET", pm.Picture, nil) r, err := http.NewRequestWithContext(ctx, "GET", pm.Picture, nil)
if err == nil { if err == nil {
@ -105,19 +101,17 @@ func CreateNpubDir(
h.AddChild( h.AddChild(
"notes", "notes",
h.NewPersistentInode( h.NewPersistentInode(
ctx, r.ctx,
&ViewDir{ &ViewDir{
ctx: ctx, root: r,
sys: sys,
wd: wd,
filter: nostr.Filter{ filter: nostr.Filter{
Kinds: []int{1}, Kinds: []int{1},
Authors: []string{pointer.PublicKey}, Authors: []string{pointer.PublicKey},
}, },
paginate: true, paginate: true,
relays: relays, relays: relays,
create: func(ctx context.Context, n *ViewDir, event *nostr.Event) (string, *fs.Inode) { create: func(n *ViewDir, event *nostr.Event) (string, *fs.Inode) {
return event.ID, CreateEventDir(ctx, n, n.wd, event) return event.ID, r.CreateEventDir(n, event)
}, },
}, },
fs.StableAttr{Mode: syscall.S_IFDIR}, fs.StableAttr{Mode: syscall.S_IFDIR},
@ -128,19 +122,17 @@ func CreateNpubDir(
h.AddChild( h.AddChild(
"comments", "comments",
h.NewPersistentInode( h.NewPersistentInode(
ctx, r.ctx,
&ViewDir{ &ViewDir{
ctx: ctx, root: r,
sys: sys,
wd: wd,
filter: nostr.Filter{ filter: nostr.Filter{
Kinds: []int{1111}, Kinds: []int{1111},
Authors: []string{pointer.PublicKey}, Authors: []string{pointer.PublicKey},
}, },
paginate: true, paginate: true,
relays: relays, relays: relays,
create: func(ctx context.Context, n *ViewDir, event *nostr.Event) (string, *fs.Inode) { create: func(n *ViewDir, event *nostr.Event) (string, *fs.Inode) {
return event.ID, CreateEventDir(ctx, n, n.wd, event) return event.ID, r.CreateEventDir(n, event)
}, },
}, },
fs.StableAttr{Mode: syscall.S_IFDIR}, fs.StableAttr{Mode: syscall.S_IFDIR},
@ -151,19 +143,17 @@ func CreateNpubDir(
h.AddChild( h.AddChild(
"photos", "photos",
h.NewPersistentInode( h.NewPersistentInode(
ctx, r.ctx,
&ViewDir{ &ViewDir{
ctx: ctx, root: r,
sys: sys,
wd: wd,
filter: nostr.Filter{ filter: nostr.Filter{
Kinds: []int{20}, Kinds: []int{20},
Authors: []string{pointer.PublicKey}, Authors: []string{pointer.PublicKey},
}, },
paginate: true, paginate: true,
relays: relays, relays: relays,
create: func(ctx context.Context, n *ViewDir, event *nostr.Event) (string, *fs.Inode) { create: func(n *ViewDir, event *nostr.Event) (string, *fs.Inode) {
return event.ID, CreateEventDir(ctx, n, n.wd, event) return event.ID, r.CreateEventDir(n, event)
}, },
}, },
fs.StableAttr{Mode: syscall.S_IFDIR}, fs.StableAttr{Mode: syscall.S_IFDIR},
@ -174,19 +164,17 @@ func CreateNpubDir(
h.AddChild( h.AddChild(
"videos", "videos",
h.NewPersistentInode( h.NewPersistentInode(
ctx, r.ctx,
&ViewDir{ &ViewDir{
ctx: ctx, root: r,
sys: sys,
wd: wd,
filter: nostr.Filter{ filter: nostr.Filter{
Kinds: []int{21, 22}, Kinds: []int{21, 22},
Authors: []string{pointer.PublicKey}, Authors: []string{pointer.PublicKey},
}, },
paginate: false, paginate: false,
relays: relays, relays: relays,
create: func(ctx context.Context, n *ViewDir, event *nostr.Event) (string, *fs.Inode) { create: func(n *ViewDir, event *nostr.Event) (string, *fs.Inode) {
return event.ID, CreateEventDir(ctx, n, n.wd, event) return event.ID, r.CreateEventDir(n, event)
}, },
}, },
fs.StableAttr{Mode: syscall.S_IFDIR}, fs.StableAttr{Mode: syscall.S_IFDIR},
@ -197,19 +185,17 @@ func CreateNpubDir(
h.AddChild( h.AddChild(
"highlights", "highlights",
h.NewPersistentInode( h.NewPersistentInode(
ctx, r.ctx,
&ViewDir{ &ViewDir{
ctx: ctx, root: r,
sys: sys,
wd: wd,
filter: nostr.Filter{ filter: nostr.Filter{
Kinds: []int{9802}, Kinds: []int{9802},
Authors: []string{pointer.PublicKey}, Authors: []string{pointer.PublicKey},
}, },
paginate: false, paginate: false,
relays: relays, relays: relays,
create: func(ctx context.Context, n *ViewDir, event *nostr.Event) (string, *fs.Inode) { create: func(n *ViewDir, event *nostr.Event) (string, *fs.Inode) {
return event.ID, CreateEventDir(ctx, n, n.wd, event) return event.ID, r.CreateEventDir(n, event)
}, },
}, },
fs.StableAttr{Mode: syscall.S_IFDIR}, fs.StableAttr{Mode: syscall.S_IFDIR},
@ -220,23 +206,21 @@ func CreateNpubDir(
h.AddChild( h.AddChild(
"articles", "articles",
h.NewPersistentInode( h.NewPersistentInode(
ctx, r.ctx,
&ViewDir{ &ViewDir{
ctx: ctx, root: r,
sys: sys,
wd: wd,
filter: nostr.Filter{ filter: nostr.Filter{
Kinds: []int{30023}, Kinds: []int{30023},
Authors: []string{pointer.PublicKey}, Authors: []string{pointer.PublicKey},
}, },
paginate: false, paginate: false,
relays: relays, relays: relays,
create: func(ctx context.Context, n *ViewDir, event *nostr.Event) (string, *fs.Inode) { create: func(n *ViewDir, event *nostr.Event) (string, *fs.Inode) {
d := event.Tags.GetD() d := event.Tags.GetD()
if d == "" { if d == "" {
d = "_" d = "_"
} }
return d, CreateEntityDir(ctx, n, n.wd, ".md", event) return d, r.CreateEntityDir(n, ".md", event)
}, },
}, },
fs.StableAttr{Mode: syscall.S_IFDIR}, fs.StableAttr{Mode: syscall.S_IFDIR},
@ -247,23 +231,21 @@ func CreateNpubDir(
h.AddChild( h.AddChild(
"wiki", "wiki",
h.NewPersistentInode( h.NewPersistentInode(
ctx, r.ctx,
&ViewDir{ &ViewDir{
ctx: ctx, root: r,
sys: sys,
wd: wd,
filter: nostr.Filter{ filter: nostr.Filter{
Kinds: []int{30818}, Kinds: []int{30818},
Authors: []string{pointer.PublicKey}, Authors: []string{pointer.PublicKey},
}, },
paginate: false, paginate: false,
relays: relays, relays: relays,
create: func(ctx context.Context, n *ViewDir, event *nostr.Event) (string, *fs.Inode) { create: func(n *ViewDir, event *nostr.Event) (string, *fs.Inode) {
d := event.Tags.GetD() d := event.Tags.GetD()
if d == "" { if d == "" {
d = "_" d = "_"
} }
return d, CreateEntityDir(ctx, n, n.wd, ".adoc", event) return d, r.CreateEntityDir(n, ".adoc", event)
}, },
}, },
fs.StableAttr{Mode: syscall.S_IFDIR}, fs.StableAttr{Mode: syscall.S_IFDIR},

View File

@ -28,9 +28,13 @@ var _ = (fs.NodeOnAdder)((*NostrRoot)(nil))
func NewNostrRoot(ctx context.Context, sys *sdk.System, user nostr.User, mountpoint string) *NostrRoot { func NewNostrRoot(ctx context.Context, sys *sdk.System, user nostr.User, mountpoint string) *NostrRoot {
pubkey, _ := user.GetPublicKey(ctx) pubkey, _ := user.GetPublicKey(ctx)
signer, _ := user.(nostr.Signer)
abs, _ := filepath.Abs(mountpoint) abs, _ := filepath.Abs(mountpoint)
var signer nostr.Signer
if user != nil {
signer, _ = user.(nostr.Signer)
}
return &NostrRoot{ return &NostrRoot{
ctx: ctx, ctx: ctx,
sys: sys, sys: sys,
@ -52,7 +56,7 @@ func (r *NostrRoot) OnAdd(_ context.Context) {
npub, _ := nip19.EncodePublicKey(f.Pubkey) npub, _ := nip19.EncodePublicKey(f.Pubkey)
r.AddChild( r.AddChild(
npub, npub,
CreateNpubDir(r.ctx, r.sys, r, r.wd, pointer), r.CreateNpubDir(r, pointer, nil),
true, true,
) )
} }
@ -61,9 +65,10 @@ func (r *NostrRoot) OnAdd(_ context.Context) {
npub, _ := nip19.EncodePublicKey(r.rootPubKey) npub, _ := nip19.EncodePublicKey(r.rootPubKey)
if r.GetChild(npub) == nil { if r.GetChild(npub) == nil {
pointer := nostr.ProfilePointer{PublicKey: r.rootPubKey} pointer := nostr.ProfilePointer{PublicKey: r.rootPubKey}
r.AddChild( r.AddChild(
npub, npub,
CreateNpubDir(r.ctx, r.sys, r, r.wd, pointer), r.CreateNpubDir(r, pointer, r.signer),
true, true,
) )
} }
@ -85,8 +90,11 @@ func (r *NostrRoot) Lookup(_ context.Context, name string, out *fuse.EntryOut) (
} }
if pp, err := nip05.QueryIdentifier(r.ctx, name); err == nil { if pp, err := nip05.QueryIdentifier(r.ctx, name); err == nil {
npubdir := CreateNpubDir(r.ctx, r.sys, r, r.wd, *pp) return r.NewPersistentInode(
return npubdir, fs.OK r.ctx,
&fs.MemSymlink{Data: []byte(r.wd + "/" + nip19.EncodePointer(*pp))},
fs.StableAttr{Mode: syscall.S_IFLNK},
), fs.OK
} }
pointer, err := nip19.ToPointer(name) pointer, err := nip19.ToPointer(name)
@ -96,10 +104,10 @@ func (r *NostrRoot) Lookup(_ context.Context, name string, out *fuse.EntryOut) (
switch p := pointer.(type) { switch p := pointer.(type) {
case nostr.ProfilePointer: case nostr.ProfilePointer:
npubdir := CreateNpubDir(r.ctx, r.sys, r, r.wd, p) npubdir := r.CreateNpubDir(r, p, nil)
return npubdir, fs.OK return npubdir, fs.OK
case nostr.EventPointer: case nostr.EventPointer:
eventdir, err := FetchAndCreateEventDir(r.ctx, r, r.wd, r.sys, p) eventdir, err := r.FetchAndCreateEventDir(r, p)
if err != nil { if err != nil {
return nil, syscall.ENOENT return nil, syscall.ENOENT
} }

View File

@ -8,19 +8,16 @@ import (
"github.com/hanwen/go-fuse/v2/fs" "github.com/hanwen/go-fuse/v2/fs"
"github.com/hanwen/go-fuse/v2/fuse" "github.com/hanwen/go-fuse/v2/fuse"
"github.com/nbd-wtf/go-nostr" "github.com/nbd-wtf/go-nostr"
sdk "github.com/nbd-wtf/go-nostr/sdk"
) )
type ViewDir struct { type ViewDir struct {
fs.Inode fs.Inode
ctx context.Context root *NostrRoot
sys *sdk.System
wd string
fetched atomic.Bool fetched atomic.Bool
filter nostr.Filter filter nostr.Filter
paginate bool paginate bool
relays []string relays []string
create func(context.Context, *ViewDir, *nostr.Event) (string, *fs.Inode) create func(*ViewDir, *nostr.Event) (string, *fs.Inode)
} }
var ( var (
@ -52,8 +49,8 @@ func (n *ViewDir) Opendir(_ context.Context) syscall.Errno {
aMonthAgo := now - 30*24*60*60 aMonthAgo := now - 30*24*60*60
n.filter.Since = &aMonthAgo n.filter.Since = &aMonthAgo
for ie := range n.sys.Pool.FetchMany(n.ctx, n.relays, n.filter, nostr.WithLabel("nakfs")) { for ie := range n.root.sys.Pool.FetchMany(n.root.ctx, n.relays, n.filter, nostr.WithLabel("nakfs")) {
basename, inode := n.create(n.ctx, n, ie.Event) basename, inode := n.create(n, ie.Event)
n.AddChild(basename, inode, true) n.AddChild(basename, inode, true)
} }
@ -61,19 +58,17 @@ func (n *ViewDir) Opendir(_ context.Context) syscall.Errno {
filter.Until = &aMonthAgo filter.Until = &aMonthAgo
n.AddChild("@previous", n.NewPersistentInode( n.AddChild("@previous", n.NewPersistentInode(
n.ctx, n.root.ctx,
&ViewDir{ &ViewDir{
ctx: n.ctx, root: n.root,
sys: n.sys,
filter: filter, filter: filter,
wd: n.wd,
relays: n.relays, relays: n.relays,
}, },
fs.StableAttr{Mode: syscall.S_IFDIR}, fs.StableAttr{Mode: syscall.S_IFDIR},
), true) ), true)
} else { } else {
for ie := range n.sys.Pool.FetchMany(n.ctx, n.relays, n.filter, nostr.WithLabel("nakfs")) { for ie := range n.root.sys.Pool.FetchMany(n.root.ctx, n.relays, n.filter, nostr.WithLabel("nakfs")) {
basename, inode := n.create(n.ctx, n, ie.Event) basename, inode := n.create(n, ie.Event)
n.AddChild(basename, inode, true) n.AddChild(basename, inode, true)
} }
} }