mirror of https://github.com/fiatjaf/nak.git
fs: pass NostrRoot everywhere with a signer only if it can actually sign.
This commit is contained in:
parent
bfe1e6ca94
commit
c87371208e
13
fs.go
13
fs.go
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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)
|
||||||
|
|
|
@ -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},
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue