forked from coracle/zooid
Eagerly generate nip29 admins and members lists
This commit is contained in:
@@ -1,26 +1,4 @@
|
|||||||
`README.md` contains high-level project information.
|
`README.md` contains high-level project information.
|
||||||
`justfile` contains common commands.
|
`justfile` contains common commands.
|
||||||
|
|
||||||
## Codebase Overview
|
On startup, run `tree zooid` to get an understanding of the structure of the codebase.
|
||||||
|
|
||||||
- **zooid/config.go**: Defines `Config` struct with TOML tags for relay configuration (self, groups, management, blossom, roles, data). Contains `LoadConfig()` function and `IsMember()` method.
|
|
||||||
|
|
||||||
- **zooid/http.go**: Simple HTTP handler that calls `GetInstance()` and delegates to khatru relay.
|
|
||||||
|
|
||||||
- **zooid/instance.go**: Core instance management. `Instance` struct holds config and khatru relay. `MakeInstance()` creates configured relay instances with handlers. `GetInstance()` provides singleton access with lazy loading.
|
|
||||||
|
|
||||||
- **zooid/blossom.go**: Blossom file storage integration with member-only access controls.
|
|
||||||
|
|
||||||
- **zooid/util.go**: Environment variable utilities with `Env()` function.
|
|
||||||
|
|
||||||
- **cmd/relay/main.go**: HTTP server entry point with graceful shutdown.
|
|
||||||
|
|
||||||
## SQLite EventStore
|
|
||||||
|
|
||||||
The `sqlite/` directory contains a complete SQLite-based khatru eventstore implementation.
|
|
||||||
|
|
||||||
### nostrlib API Compatibility
|
|
||||||
- `Event.Sig` is `[64]byte`, not a separate Signature type
|
|
||||||
- `Event.CreatedAt` is `nostr.Timestamp` (int64), not `time.Time`
|
|
||||||
- Use `hex.EncodeToString(evt.Sig[:])` for signature serialization
|
|
||||||
- Use `hex.DecodeString()` and `copy()` for signature parsing
|
|
||||||
|
|||||||
+4
-8
@@ -98,7 +98,7 @@ func (g *GroupStore) GetAdmins(h string) []nostr.PubKey {
|
|||||||
return g.Management.GetAdmins()
|
return g.Management.GetAdmins()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupStore) GenerateAdminsEvent(h string) nostr.Event {
|
func (g *GroupStore) UpdateAdminsList(h string) error {
|
||||||
tags := nostr.Tags{
|
tags := nostr.Tags{
|
||||||
nostr.Tag{"-"},
|
nostr.Tag{"-"},
|
||||||
nostr.Tag{"d", h},
|
nostr.Tag{"d", h},
|
||||||
@@ -114,9 +114,7 @@ func (g *GroupStore) GenerateAdminsEvent(h string) nostr.Event {
|
|||||||
Tags: tags,
|
Tags: tags,
|
||||||
}
|
}
|
||||||
|
|
||||||
g.Config.Sign(&event)
|
return g.Events.SignAndStoreEvent(&event, true)
|
||||||
|
|
||||||
return event
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Membership
|
// Membership
|
||||||
@@ -194,7 +192,7 @@ func (g *GroupStore) GetMembers(h string) []nostr.PubKey {
|
|||||||
return members
|
return members
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GroupStore) GenerateMembersEvent(h string) nostr.Event {
|
func (g *GroupStore) UpdateMembersList(h string) error {
|
||||||
tags := nostr.Tags{
|
tags := nostr.Tags{
|
||||||
nostr.Tag{"-"},
|
nostr.Tag{"-"},
|
||||||
nostr.Tag{"d", h},
|
nostr.Tag{"d", h},
|
||||||
@@ -210,9 +208,7 @@ func (g *GroupStore) GenerateMembersEvent(h string) nostr.Event {
|
|||||||
Tags: tags,
|
Tags: tags,
|
||||||
}
|
}
|
||||||
|
|
||||||
g.Config.Sign(&event)
|
return g.Events.SignAndStoreEvent(&event, true)
|
||||||
|
|
||||||
return event
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Other stuff
|
// Other stuff
|
||||||
|
|||||||
+21
-28
@@ -294,30 +294,6 @@ func (instance *Instance) QueryStored(ctx context.Context, filter nostr.Filter)
|
|||||||
generated = append(generated, instance.GenerateInviteEvent(pubkey))
|
generated = append(generated, instance.GenerateInviteEvent(pubkey))
|
||||||
}
|
}
|
||||||
|
|
||||||
if slices.Contains(filter.Kinds, nostr.KindSimpleGroupAdmins) {
|
|
||||||
groupsFilter := nostr.Filter{
|
|
||||||
Kinds: []nostr.Kind{nostr.KindSimpleGroupMetadata},
|
|
||||||
}
|
|
||||||
|
|
||||||
for event := range instance.Events.QueryEvents(groupsFilter, 0) {
|
|
||||||
if tag := event.Tags.Find("d"); tag != nil {
|
|
||||||
generated = append(generated, instance.Groups.GenerateAdminsEvent(tag[1]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if slices.Contains(filter.Kinds, nostr.KindSimpleGroupMembers) {
|
|
||||||
groupsFilter := nostr.Filter{
|
|
||||||
Kinds: []nostr.Kind{nostr.KindSimpleGroupMetadata},
|
|
||||||
}
|
|
||||||
|
|
||||||
for event := range instance.Events.QueryEvents(groupsFilter, 0) {
|
|
||||||
if tag := event.Tags.Find("d"); tag != nil {
|
|
||||||
generated = append(generated, instance.Groups.GenerateMembersEvent(tag[1]))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, event := range generated {
|
for _, event := range generated {
|
||||||
if !filter.Matches(event) {
|
if !filter.Matches(event) {
|
||||||
continue
|
continue
|
||||||
@@ -458,25 +434,42 @@ func (instance *Instance) OnEvent(ctx context.Context, event nostr.Event) (rejec
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (instance *Instance) OnEventSaved(ctx context.Context, event nostr.Event) {
|
func (instance *Instance) OnEventSaved(ctx context.Context, event nostr.Event) {
|
||||||
|
h := GetGroupIDFromEvent(event)
|
||||||
|
|
||||||
if event.Kind == nostr.KindSimpleGroupJoinRequest && instance.Config.Groups.AutoJoin {
|
if event.Kind == nostr.KindSimpleGroupJoinRequest && instance.Config.Groups.AutoJoin {
|
||||||
h := GetGroupIDFromEvent(event)
|
|
||||||
meta := instance.Groups.GetMetadata(h)
|
meta := instance.Groups.GetMetadata(h)
|
||||||
|
|
||||||
if !HasTag(meta.Tags, "closed") {
|
if !HasTag(meta.Tags, "closed") {
|
||||||
instance.Groups.AddMember(h, event.PubKey)
|
instance.Groups.AddMember(h, event.PubKey)
|
||||||
|
instance.Groups.UpdateMembersList(h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if event.Kind == nostr.KindSimpleGroupLeaveRequest && instance.Config.Groups.AutoLeave {
|
if event.Kind == nostr.KindSimpleGroupLeaveRequest && instance.Config.Groups.AutoLeave {
|
||||||
instance.Groups.RemoveMember(GetGroupIDFromEvent(event), event.PubKey)
|
instance.Groups.RemoveMember(h, event.PubKey)
|
||||||
|
instance.Groups.UpdateMembersList(h)
|
||||||
}
|
}
|
||||||
|
|
||||||
if event.Kind == nostr.KindSimpleGroupCreateGroup || event.Kind == nostr.KindSimpleGroupEditMetadata {
|
if event.Kind == nostr.KindSimpleGroupPutUser {
|
||||||
|
instance.Groups.UpdateMembersList(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.Kind == nostr.KindSimpleGroupRemoveUser {
|
||||||
|
instance.Groups.UpdateMembersList(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.Kind == nostr.KindSimpleGroupCreateGroup {
|
||||||
instance.Groups.SetMetadataFromEvent(event)
|
instance.Groups.SetMetadataFromEvent(event)
|
||||||
|
instance.Groups.UpdateAdminsList(h)
|
||||||
|
}
|
||||||
|
|
||||||
|
if event.Kind == nostr.KindSimpleGroupEditMetadata {
|
||||||
|
instance.Groups.SetMetadataFromEvent(event)
|
||||||
|
instance.Groups.UpdateAdminsList(h)
|
||||||
}
|
}
|
||||||
|
|
||||||
if event.Kind == nostr.KindSimpleGroupDeleteGroup {
|
if event.Kind == nostr.KindSimpleGroupDeleteGroup {
|
||||||
instance.Groups.DeleteGroup(GetGroupIDFromEvent(event))
|
instance.Groups.DeleteGroup(h)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user