improve documentation and add events http endpoint for filter queries
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -104,3 +104,4 @@ pkg/database/testrealy
|
||||
/.idea/material_theme_project_new.xml
|
||||
/.idea/orly.iml
|
||||
/.idea/go.imports.xml
|
||||
/.idea/inspectionProfiles/Project_Default.xml
|
||||
|
||||
@@ -14,7 +14,6 @@ import (
|
||||
"orly.dev/pkg/encoders/tags"
|
||||
"orly.dev/pkg/encoders/text"
|
||||
"orly.dev/pkg/encoders/timestamp"
|
||||
"orly.dev/pkg/encoders/unix"
|
||||
"orly.dev/pkg/interfaces/signer"
|
||||
"orly.dev/pkg/utils/chk"
|
||||
"orly.dev/pkg/utils/errorf"
|
||||
@@ -92,6 +91,9 @@ func (ev *E) Id() []byte { return ev.ID }
|
||||
// CreatedAtInt64 returns the created_at timestamp as a standard int64.
|
||||
func (ev *E) CreatedAtInt64() (i int64) { return ev.CreatedAt.I64() }
|
||||
|
||||
// KindInt returns the kind as an int, as is often needed for JSON.
|
||||
func (ev *E) KindInt() (i int) { return int(ev.Kind.K) }
|
||||
|
||||
// KindInt32 returns the kind as an int32, as is often needed for JSON.
|
||||
func (ev *E) KindInt32() (i int32) { return int32(ev.Kind.K) }
|
||||
|
||||
@@ -109,13 +111,13 @@ func (ev *E) ContentString() (s string) { return string(ev.Content) }
|
||||
|
||||
// J is an event.E encoded in more basic types than used in this library.
|
||||
type J struct {
|
||||
Id string `json:"id"`
|
||||
Pubkey string `json:"pubkey"`
|
||||
CreatedAt unix.Time `json:"created_at"`
|
||||
Kind int32 `json:"kind"`
|
||||
Tags [][]string `json:"tags"`
|
||||
Content string `json:"content"`
|
||||
Sig string `json:"sig"`
|
||||
Id string `json:"id" doc:"event id (SHA256 hash of canonical form of event, 64 characters hex)"`
|
||||
Pubkey string `json:"pubkey" doc:"public key of author of event, required to verify signature (BIP-340 Schnorr public key, 64 characters hex)"`
|
||||
CreatedAt int64 `json:"created_at" doc:"unix timestamp of time when event was created"`
|
||||
Kind int `json:"kind" doc:"kind number of event"`
|
||||
Tags [][]string `json:"tags" doc:"tags that add metadata to the event"`
|
||||
Content string `json:"content" doc:"content of event"`
|
||||
Sig string `json:"sig" doc:"signature of event (BIP-340 schnorr signature, 128 characters hex)"`
|
||||
}
|
||||
|
||||
// ToEventJ converts an event.E into an event.J.
|
||||
@@ -123,8 +125,8 @@ func (ev *E) ToEventJ() (j *J) {
|
||||
j = &J{}
|
||||
j.Id = ev.IdString()
|
||||
j.Pubkey = ev.PubKeyString()
|
||||
j.CreatedAt = unix.Time{ev.CreatedAt.Time()}
|
||||
j.Kind = ev.KindInt32()
|
||||
j.CreatedAt = ev.CreatedAt.I64()
|
||||
j.Kind = ev.KindInt()
|
||||
j.Content = ev.ContentString()
|
||||
j.Tags = ev.Tags.ToStringsSlice()
|
||||
j.Sig = ev.SigString()
|
||||
@@ -151,6 +153,13 @@ func (ev *E) KindFromInt32(i int32) {
|
||||
return
|
||||
}
|
||||
|
||||
// KindFromInt encodes an int representation of a kind.T into an event.E.
|
||||
func (ev *E) KindFromInt(i int) {
|
||||
ev.Kind = &kind.T{}
|
||||
ev.Kind.K = uint16(i)
|
||||
return
|
||||
}
|
||||
|
||||
// PubKeyFromString decodes a hex-encoded string into the event.E Pubkey field.
|
||||
func (ev *E) PubKeyFromString(s string) (err error) {
|
||||
if len(s) != 2*schnorr.PubKeyBytesLen {
|
||||
@@ -200,8 +209,8 @@ func (e J) ToEvent() (ev *E, err error) {
|
||||
if err = ev.IdFromString(e.Id); chk.E(err) {
|
||||
return
|
||||
}
|
||||
ev.CreatedAtFromInt64(e.CreatedAt.Unix())
|
||||
ev.KindFromInt32(e.Kind)
|
||||
ev.CreatedAtFromInt64(e.CreatedAt)
|
||||
ev.KindFromInt(e.Kind)
|
||||
if err = ev.PubKeyFromString(e.Pubkey); chk.E(err) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -19,15 +19,62 @@ import (
|
||||
"orly.dev/pkg/utils/log"
|
||||
)
|
||||
|
||||
var EventBody = &huma.RequestBody{
|
||||
Description: "a signed nostr event",
|
||||
Content: map[string]*huma.MediaType{
|
||||
"application/json": {
|
||||
Schema: &huma.Schema{
|
||||
Type: huma.TypeObject,
|
||||
Properties: map[string]*huma.Schema{
|
||||
"id": {
|
||||
Type: huma.TypeString,
|
||||
Description: "SHA256 hash of event in canonical (JSON array with fixed ordering) form, 64 characters hex",
|
||||
},
|
||||
"pubkey": {
|
||||
Type: huma.TypeString,
|
||||
Description: "BIP-340 Schnorr public key, 64 characters hex",
|
||||
},
|
||||
"created_at": {
|
||||
Type: huma.TypeInteger,
|
||||
Description: "unix timestamp of time of event creation",
|
||||
},
|
||||
"kind": {
|
||||
Type: huma.TypeInteger,
|
||||
Description: "kind number of event",
|
||||
},
|
||||
"tags": {
|
||||
Type: huma.TypeArray,
|
||||
Description: "array of arrays of strings",
|
||||
Items: &huma.Schema{
|
||||
Type: huma.TypeArray,
|
||||
Items: &huma.Schema{
|
||||
Type: huma.TypeString,
|
||||
},
|
||||
},
|
||||
},
|
||||
"content": {
|
||||
Type: huma.TypeString,
|
||||
Description: "content of event, escaped using NIP-01 standard escapes and UTF-8 encoding",
|
||||
},
|
||||
"sig": {
|
||||
Type: huma.TypeString,
|
||||
Description: "BIP-340 Schnorr signature, 128 characters hex",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
// EventInput is the parameters for the Event HTTP API method.
|
||||
type EventInput struct {
|
||||
Auth string `header:"Authorization" doc:"nostr nip-98 (and expiring variant)" required:"false"`
|
||||
Accept string `header:"Accept" default:"application/nostr+json"`
|
||||
Body string `doc:"event JSON"`
|
||||
Auth string `header:"Authorization" doc:"nostr nip-98 (and expiring variant)" required:"false"`
|
||||
Accept string `header:"Accept" default:"application/nostr+json"`
|
||||
Body *event.J `doc:"event JSON"`
|
||||
}
|
||||
|
||||
// EventOutput is the return parameters for the HTTP API Event method.
|
||||
type EventOutput struct{ Body string }
|
||||
type EventOutput struct{}
|
||||
|
||||
// RegisterEvent is the implementation of the HTTP API Event method.
|
||||
func (x *Operations) RegisterEvent(api huma.API) {
|
||||
@@ -43,6 +90,7 @@ func (x *Operations) RegisterEvent(api huma.API) {
|
||||
Path: path,
|
||||
Method: method,
|
||||
Tags: []string{"events"},
|
||||
RequestBody: EventBody,
|
||||
Description: helpers.GenerateDescription(description, scopes),
|
||||
Security: []map[string][]string{{"auth": scopes}},
|
||||
}, func(ctx context.T, input *EventInput) (
|
||||
@@ -63,17 +111,13 @@ func (x *Operations) RegisterEvent(api huma.API) {
|
||||
return
|
||||
}
|
||||
}
|
||||
ev := &event.E{}
|
||||
var rem []byte
|
||||
if rem, err = ev.Unmarshal([]byte(input.Body)); chk.T(err) {
|
||||
var ev *event.E
|
||||
if ev, err = input.Body.ToEvent(); chk.E(err) {
|
||||
err = huma.Error422UnprocessableEntity(
|
||||
"Failed to parse event", err,
|
||||
"Failed to convert event", err,
|
||||
)
|
||||
return
|
||||
}
|
||||
if len(rem) > 0 {
|
||||
log.D.F("remainder:\n%s", rem)
|
||||
}
|
||||
// these aliases make it so most of the following code can be copied
|
||||
// verbatim from its counterpart in socketapi.HandleEvent, with the
|
||||
// aid of a different implementation of the openapi.OK type.
|
||||
@@ -393,7 +437,6 @@ func (x *Operations) RegisterEvent(api huma.API) {
|
||||
return
|
||||
}
|
||||
}
|
||||
output = &EventOutput{"event accepted"}
|
||||
return
|
||||
},
|
||||
)
|
||||
|
||||
@@ -4,25 +4,583 @@ import (
|
||||
"errors"
|
||||
"github.com/danielgtaylor/huma/v2"
|
||||
"github.com/dgraph-io/badger/v4"
|
||||
"math"
|
||||
"net/http"
|
||||
"orly.dev/pkg/app/relay/helpers"
|
||||
"orly.dev/pkg/encoders/event"
|
||||
"orly.dev/pkg/encoders/filter"
|
||||
"orly.dev/pkg/encoders/filters"
|
||||
"orly.dev/pkg/encoders/kind"
|
||||
"orly.dev/pkg/encoders/tag"
|
||||
"orly.dev/pkg/encoders/timestamp"
|
||||
"orly.dev/pkg/protocol/auth"
|
||||
"orly.dev/pkg/utils/context"
|
||||
"orly.dev/pkg/utils/log"
|
||||
"orly.dev/pkg/utils/pointers"
|
||||
)
|
||||
|
||||
type Filter struct {
|
||||
Ids []string `json:"ids,omitempty"`
|
||||
Kinds []int `json:"kinds,omitempty"`
|
||||
Authors []string `json:"authors,omitempty"`
|
||||
Tag_a []string `json:"#a,omitempty"`
|
||||
Tag_b []string `json:"#b,omitempty"`
|
||||
Tag_c []string `json:"#c,omitempty"`
|
||||
Tag_d []string `json:"#d,omitempty"`
|
||||
Tag_e []string `json:"#e,omitempty"`
|
||||
Tag_f []string `json:"#f,omitempty"`
|
||||
Tag_g []string `json:"#g,omitempty"`
|
||||
Tag_h []string `json:"#h,omitempty"`
|
||||
Tag_i []string `json:"#i,omitempty"`
|
||||
Tag_j []string `json:"#j,omitempty"`
|
||||
Tag_k []string `json:"#k,omitempty"`
|
||||
Tag_l []string `json:"#l,omitempty"`
|
||||
Tag_m []string `json:"#m,omitempty"`
|
||||
Tag_n []string `json:"#n,omitempty"`
|
||||
Tag_o []string `json:"#o,omitempty"`
|
||||
Tag_p []string `json:"#p,omitempty"`
|
||||
Tag_q []string `json:"#q,omitempty"`
|
||||
Tag_r []string `json:"#r,omitempty"`
|
||||
Tag_s []string `json:"#s,omitempty"`
|
||||
Tag_t []string `json:"#t,omitempty"`
|
||||
Tag_u []string `json:"#u,omitempty"`
|
||||
Tag_v []string `json:"#v,omitempty"`
|
||||
Tag_w []string `json:"#w,omitempty"`
|
||||
Tag_x []string `json:"#x,omitempty"`
|
||||
Tag_y []string `json:"#y,omitempty"`
|
||||
Tag_z []string `json:"#z,omitempty"`
|
||||
Tag_A []string `json:"#A,omitempty"`
|
||||
Tag_B []string `json:"#B,omitempty"`
|
||||
Tag_C []string `json:"#C,omitempty"`
|
||||
Tag_D []string `json:"#D,omitempty"`
|
||||
Tag_E []string `json:"#E,omitempty"`
|
||||
Tag_F []string `json:"#F,omitempty"`
|
||||
Tag_G []string `json:"#G,omitempty"`
|
||||
Tag_H []string `json:"#H,omitempty"`
|
||||
Tag_I []string `json:"#I,omitempty"`
|
||||
Tag_J []string `json:"#J,omitempty"`
|
||||
Tag_K []string `json:"#K,omitempty"`
|
||||
Tag_L []string `json:"#L,omitempty"`
|
||||
Tag_M []string `json:"#M,omitempty"`
|
||||
Tag_N []string `json:"#N,omitempty"`
|
||||
Tag_O []string `json:"#O,omitempty"`
|
||||
Tag_P []string `json:"#P,omitempty"`
|
||||
Tag_Q []string `json:"#Q,omitempty"`
|
||||
Tag_R []string `json:"#R,omitempty"`
|
||||
Tag_S []string `json:"#S,omitempty"`
|
||||
Tag_T []string `json:"#T,omitempty"`
|
||||
Tag_U []string `json:"#U,omitempty"`
|
||||
Tag_V []string `json:"#V,omitempty"`
|
||||
Tag_W []string `json:"#W,omitempty"`
|
||||
Tag_X []string `json:"#X,omitempty"`
|
||||
Tag_Y []string `json:"#Y,omitempty"`
|
||||
Tag_Z []string `json:"#Z,omitempty"`
|
||||
Since *int64 `json:"since,omitempty"`
|
||||
Until *int64 `json:"until,omitempty"`
|
||||
Search *string `json:"search,omitempty"`
|
||||
Limit *int `json:"limit,omitempty"`
|
||||
}
|
||||
|
||||
func (f *Filter) ToFilter() (ff *filter.F) {
|
||||
ff = filter.New()
|
||||
|
||||
// Convert Ids
|
||||
if f.Ids != nil && len(f.Ids) > 0 {
|
||||
for _, id := range f.Ids {
|
||||
ff.Ids.Append([]byte(id))
|
||||
}
|
||||
}
|
||||
if f.Kinds != nil && len(f.Kinds) > 0 {
|
||||
for _, k := range f.Kinds {
|
||||
ff.Kinds.K = append(ff.Kinds.K, kind.New(uint16(k)))
|
||||
}
|
||||
}
|
||||
if f.Authors != nil && len(f.Authors) > 0 {
|
||||
for _, author := range f.Authors {
|
||||
ff.Authors.Append([]byte(author))
|
||||
}
|
||||
}
|
||||
if f.Since != nil {
|
||||
ts := timestamp.New(*f.Since)
|
||||
ff.Since = ts
|
||||
}
|
||||
if f.Until != nil {
|
||||
ts := timestamp.New(*f.Until)
|
||||
ff.Until = ts
|
||||
}
|
||||
if f.Search != nil {
|
||||
ff.Search = []byte(*f.Search)
|
||||
}
|
||||
if f.Limit != nil {
|
||||
u := uint(*f.Limit)
|
||||
ff.Limit = &u
|
||||
}
|
||||
if f.Tag_a != nil && len(f.Tag_a) > 0 {
|
||||
t := tag.New("#a")
|
||||
for _, v := range f.Tag_a {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_b != nil && len(f.Tag_b) > 0 {
|
||||
t := tag.New("#b")
|
||||
for _, v := range f.Tag_b {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_c != nil && len(f.Tag_c) > 0 {
|
||||
t := tag.New("#c")
|
||||
for _, v := range f.Tag_c {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_d != nil && len(f.Tag_d) > 0 {
|
||||
t := tag.New("#d")
|
||||
for _, v := range f.Tag_d {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_e != nil && len(f.Tag_e) > 0 {
|
||||
t := tag.New("#e")
|
||||
for _, v := range f.Tag_e {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_f != nil && len(f.Tag_f) > 0 {
|
||||
t := tag.New("#f")
|
||||
for _, v := range f.Tag_f {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_g != nil && len(f.Tag_g) > 0 {
|
||||
t := tag.New("#g")
|
||||
for _, v := range f.Tag_g {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_h != nil && len(f.Tag_h) > 0 {
|
||||
t := tag.New("#h")
|
||||
for _, v := range f.Tag_h {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_i != nil && len(f.Tag_i) > 0 {
|
||||
t := tag.New("#i")
|
||||
for _, v := range f.Tag_i {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_j != nil && len(f.Tag_j) > 0 {
|
||||
t := tag.New("#j")
|
||||
for _, v := range f.Tag_j {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_k != nil && len(f.Tag_k) > 0 {
|
||||
t := tag.New("#k")
|
||||
for _, v := range f.Tag_k {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_l != nil && len(f.Tag_l) > 0 {
|
||||
t := tag.New("#l")
|
||||
for _, v := range f.Tag_l {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_m != nil && len(f.Tag_m) > 0 {
|
||||
t := tag.New("#m")
|
||||
for _, v := range f.Tag_m {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_n != nil && len(f.Tag_n) > 0 {
|
||||
t := tag.New("#n")
|
||||
for _, v := range f.Tag_n {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_o != nil && len(f.Tag_o) > 0 {
|
||||
t := tag.New("#o")
|
||||
for _, v := range f.Tag_o {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_p != nil && len(f.Tag_p) > 0 {
|
||||
t := tag.New("#p")
|
||||
for _, v := range f.Tag_p {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_q != nil && len(f.Tag_q) > 0 {
|
||||
t := tag.New("#q")
|
||||
for _, v := range f.Tag_q {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_r != nil && len(f.Tag_r) > 0 {
|
||||
t := tag.New("#r")
|
||||
for _, v := range f.Tag_r {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_s != nil && len(f.Tag_s) > 0 {
|
||||
t := tag.New("#s")
|
||||
for _, v := range f.Tag_s {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_t != nil && len(f.Tag_t) > 0 {
|
||||
t := tag.New("#t")
|
||||
for _, v := range f.Tag_t {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_u != nil && len(f.Tag_u) > 0 {
|
||||
t := tag.New("#u")
|
||||
for _, v := range f.Tag_u {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_v != nil && len(f.Tag_v) > 0 {
|
||||
t := tag.New("#v")
|
||||
for _, v := range f.Tag_v {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_w != nil && len(f.Tag_w) > 0 {
|
||||
t := tag.New("#w")
|
||||
for _, v := range f.Tag_w {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_x != nil && len(f.Tag_x) > 0 {
|
||||
t := tag.New("#x")
|
||||
for _, v := range f.Tag_x {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_y != nil && len(f.Tag_y) > 0 {
|
||||
t := tag.New("#y")
|
||||
for _, v := range f.Tag_y {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_z != nil && len(f.Tag_z) > 0 {
|
||||
t := tag.New("#z")
|
||||
for _, v := range f.Tag_z {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_A != nil && len(f.Tag_A) > 0 {
|
||||
t := tag.New("#A")
|
||||
for _, v := range f.Tag_A {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_B != nil && len(f.Tag_B) > 0 {
|
||||
t := tag.New("#B")
|
||||
for _, v := range f.Tag_B {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_C != nil && len(f.Tag_C) > 0 {
|
||||
t := tag.New("#C")
|
||||
for _, v := range f.Tag_C {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_D != nil && len(f.Tag_D) > 0 {
|
||||
t := tag.New("#D")
|
||||
for _, v := range f.Tag_D {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_E != nil && len(f.Tag_E) > 0 {
|
||||
t := tag.New("#E")
|
||||
for _, v := range f.Tag_E {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_F != nil && len(f.Tag_F) > 0 {
|
||||
t := tag.New("#F")
|
||||
for _, v := range f.Tag_F {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_G != nil && len(f.Tag_G) > 0 {
|
||||
t := tag.New("#G")
|
||||
for _, v := range f.Tag_G {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_H != nil && len(f.Tag_H) > 0 {
|
||||
t := tag.New("#H")
|
||||
for _, v := range f.Tag_H {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_I != nil && len(f.Tag_I) > 0 {
|
||||
t := tag.New("#I")
|
||||
for _, v := range f.Tag_I {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_J != nil && len(f.Tag_J) > 0 {
|
||||
t := tag.New("#J")
|
||||
for _, v := range f.Tag_J {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_K != nil && len(f.Tag_K) > 0 {
|
||||
t := tag.New("#K")
|
||||
for _, v := range f.Tag_K {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_L != nil && len(f.Tag_L) > 0 {
|
||||
t := tag.New("#L")
|
||||
for _, v := range f.Tag_L {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_M != nil && len(f.Tag_M) > 0 {
|
||||
t := tag.New("#M")
|
||||
for _, v := range f.Tag_M {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_N != nil && len(f.Tag_N) > 0 {
|
||||
t := tag.New("#N")
|
||||
for _, v := range f.Tag_N {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_O != nil && len(f.Tag_O) > 0 {
|
||||
t := tag.New("#O")
|
||||
for _, v := range f.Tag_O {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_P != nil && len(f.Tag_P) > 0 {
|
||||
t := tag.New("#P")
|
||||
for _, v := range f.Tag_P {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_Q != nil && len(f.Tag_Q) > 0 {
|
||||
t := tag.New("#Q")
|
||||
for _, v := range f.Tag_Q {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_R != nil && len(f.Tag_R) > 0 {
|
||||
t := tag.New("#R")
|
||||
for _, v := range f.Tag_R {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_S != nil && len(f.Tag_S) > 0 {
|
||||
t := tag.New("#S")
|
||||
for _, v := range f.Tag_S {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_T != nil && len(f.Tag_T) > 0 {
|
||||
t := tag.New("#T")
|
||||
for _, v := range f.Tag_T {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_U != nil && len(f.Tag_U) > 0 {
|
||||
t := tag.New("#U")
|
||||
for _, v := range f.Tag_U {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_V != nil && len(f.Tag_V) > 0 {
|
||||
t := tag.New("#V")
|
||||
for _, v := range f.Tag_V {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_W != nil && len(f.Tag_W) > 0 {
|
||||
t := tag.New("#W")
|
||||
for _, v := range f.Tag_W {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_X != nil && len(f.Tag_X) > 0 {
|
||||
t := tag.New("#X")
|
||||
for _, v := range f.Tag_X {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_Y != nil && len(f.Tag_Y) > 0 {
|
||||
t := tag.New("#Y")
|
||||
for _, v := range f.Tag_Y {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
if f.Tag_Z != nil && len(f.Tag_Z) > 0 {
|
||||
t := tag.New("#Z")
|
||||
for _, v := range f.Tag_Z {
|
||||
t.Append([]byte(v))
|
||||
}
|
||||
ff.Tags.AppendTags(t)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var exampleSince int64 = 1753432853
|
||||
var exampleUntil int64 = 1753462853
|
||||
var exampleLimit int = 20
|
||||
var created_atMinimum float64 = 0
|
||||
var created_atMaximum float64 = float64(math.MaxInt64)
|
||||
var limitMinimum float64 = 0
|
||||
var limitMaximum float64 = float64(math.MaxUint64)
|
||||
|
||||
var EventsBody = &huma.RequestBody{
|
||||
Description: "array of nostr events",
|
||||
Content: map[string]*huma.MediaType{
|
||||
"application/json": {
|
||||
Schema: &huma.Schema{
|
||||
Type: huma.TypeObject,
|
||||
Examples: []any{
|
||||
Filter{
|
||||
Kinds: []int{0, 1},
|
||||
Authors: []string{
|
||||
"deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008",
|
||||
"deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008",
|
||||
},
|
||||
Tag_e: []string{
|
||||
"deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008",
|
||||
"deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008",
|
||||
"deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008",
|
||||
"deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008",
|
||||
},
|
||||
Since: &exampleSince,
|
||||
Until: &exampleUntil,
|
||||
Limit: &exampleLimit,
|
||||
},
|
||||
Filter{
|
||||
Ids: []string{
|
||||
"deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008",
|
||||
"deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008deadbeefcafe8008",
|
||||
},
|
||||
},
|
||||
},
|
||||
Properties: map[string]*huma.Schema{
|
||||
"ids": {
|
||||
Type: huma.TypeArray,
|
||||
Description: "list of event IDs to search for (if present, all other fields are excluded)",
|
||||
Items: &huma.Schema{
|
||||
Type: huma.TypeString,
|
||||
},
|
||||
},
|
||||
"kinds": {
|
||||
Type: huma.TypeArray,
|
||||
Description: "list of event kinds to search for",
|
||||
Items: &huma.Schema{
|
||||
Type: huma.TypeInteger,
|
||||
},
|
||||
},
|
||||
"authors": {
|
||||
Type: huma.TypeArray,
|
||||
Description: "list of pubkeys to search for",
|
||||
Items: &huma.Schema{
|
||||
Type: huma.TypeString,
|
||||
},
|
||||
},
|
||||
"^#[a-zA-Z]$": {
|
||||
Type: huma.TypeArray,
|
||||
Description: "list of tag values to search for",
|
||||
Items: &huma.Schema{
|
||||
Type: huma.TypeString,
|
||||
},
|
||||
},
|
||||
"since": {
|
||||
Type: huma.TypeInteger,
|
||||
Description: "earliest (smallest, inclusive) created_at value for events",
|
||||
Minimum: &created_atMinimum,
|
||||
Maximum: &created_atMaximum,
|
||||
},
|
||||
"until": {
|
||||
Type: huma.TypeInteger,
|
||||
Description: "latest (largest, inclusive) created_at value for events",
|
||||
Minimum: &created_atMinimum,
|
||||
Maximum: &created_atMaximum,
|
||||
},
|
||||
"limit": {
|
||||
Type: huma.TypeInteger,
|
||||
Description: "maximum number of events to return (newest first, reverse chronological order)",
|
||||
Minimum: &limitMinimum,
|
||||
Maximum: &limitMaximum,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
type EventsInput struct {
|
||||
Auth string `header:"Authorization" doc:"nostr nip-98 (and expiring variant)" required:"false"`
|
||||
Accept string `header:"Accept" default:"application/nostr+json"`
|
||||
Body []byte `doc:"filter JSON (standard NIP-01 filter syntax)"`
|
||||
Auth string `header:"Authorization" doc:"nostr nip-98 (and expiring variant)" required:"false"`
|
||||
Accept string `header:"Accept" default:"application/nostr+json"`
|
||||
Body *Filter `doc:"filter JSON (standard NIP-01 filter syntax)"`
|
||||
}
|
||||
|
||||
type EventsOutput struct {
|
||||
Body []byte
|
||||
Body []event.J
|
||||
}
|
||||
|
||||
// RegisterEvents is the implementation of the HTTP API Events method.
|
||||
@@ -42,6 +600,7 @@ func (x *Operations) RegisterEvents(api huma.API) {
|
||||
Path: path,
|
||||
Method: method,
|
||||
Tags: []string{"events"},
|
||||
RequestBody: EventsBody,
|
||||
Description: helpers.GenerateDescription(description, scopes),
|
||||
Security: []map[string][]string{{"auth": scopes}},
|
||||
}, func(ctx context.T, input *EventsInput) (
|
||||
|
||||
@@ -20,7 +20,9 @@ type ExportOutput struct{ RawBody []byte }
|
||||
// RegisterExport implements the Export HTTP API method.
|
||||
func (x *Operations) RegisterExport(api huma.API) {
|
||||
name := "Export"
|
||||
description := "Export all events (only works with NIP-98 capable client, will not work with UI)"
|
||||
description := `Export all events (only works with NIP-98 capable client, will not work with UI)
|
||||
|
||||
Returns the events as line structured JSON (JSONL) in the order that they were received by the relay.`
|
||||
path := x.path + "/export"
|
||||
scopes := []string{"admin", "read"}
|
||||
method := http.MethodGet
|
||||
|
||||
@@ -16,6 +16,7 @@ import (
|
||||
// stream of line structured JSON events.
|
||||
type ImportInput struct {
|
||||
Auth string `header:"Authorization" doc:"nostr nip-98 (and expiring variant) token for authentication" required:"true"`
|
||||
Body string `doc:"events in line structured JSON (JSONL)"`
|
||||
}
|
||||
|
||||
// ImportOutput is nothing, basically; a 204 or 200 status is expected.
|
||||
|
||||
Reference in New Issue
Block a user