feat: allow multiple rel with matching value

This commit is contained in:
Jon Lundy 2023-04-19 17:53:00 -06:00
parent b8c2f9f510
commit 12a3e7b1ff
Signed by untrusted user who does not match committer: xuu
GPG Key ID: C63E6D61F3035024
7 changed files with 134 additions and 67 deletions

View File

@ -35,7 +35,3 @@ ifeq (, $(shell which gqlgen))
endif
gqlgen
EV_HOST?=localhost:8080
load:
watch -n .1 "http POST $(EV_HOST)/inbox/asdf/test a=b one=1 two:='{\"v\":2}' | jq"

View File

@ -9,7 +9,7 @@ type SubjectSet struct {
Aliases []string `json:"aliases,omitempty"`
Properties map[string]*string `json:"properties,omitempty"`
event.IsEvent
event.IsEvent `json:"-"`
}
var _ event.Event = (*SubjectSet)(nil)
@ -17,27 +17,29 @@ var _ event.Event = (*SubjectSet)(nil)
type SubjectDeleted struct {
Subject string `json:"subject"`
event.IsEvent
event.IsEvent `json:"-"`
}
var _ event.Event = (*SubjectDeleted)(nil)
type LinkSet struct {
Index uint64 `json:"idx"`
Rel string `json:"rel"`
Type string `json:"type,omitempty"`
HRef string `json:"href,omitempty"`
Titles map[string]string `json:"titles,omitempty"`
Properties map[string]*string `json:"properties,omitempty"`
event.IsEvent
event.IsEvent `json:"-"`
}
var _ event.Event = (*LinkSet)(nil)
type LinkDeleted struct {
Index uint64 `json:"idx"`
Rel string `json:"rel"`
event.IsEvent
event.IsEvent `json:"-"`
}
var _ event.Event = (*LinkDeleted)(nil)

View File

@ -27,9 +27,8 @@ type JRD struct {
Aliases []string `json:"aliases,omitempty" yaml:"aliases,omitempty"`
Properties map[string]*string `json:"properties,omitempty" yaml:"properties,omitempty"`
Links Links `json:"links,omitempty" yaml:"links,omitempty"`
deleted bool
event.IsAggregate `yaml:"-"`
event.IsAggregate `json:"-" yaml:"-"`
}
func (a *JRD) CloneValues() *JRD {
@ -49,6 +48,7 @@ var _ event.Aggregate = (*JRD)(nil)
// Link is a link to a related resource.
type Link struct {
Index uint64 `json:"-" yaml:"-"`
Rel string `json:"rel,omitempty"`
Type string `json:"type,omitempty"`
HRef string `json:"href,omitempty"`
@ -71,6 +71,9 @@ func (l Links) Less(i int, j int) bool {
if l[i] == nil || l[j] == nil {
return false
}
if l[i].Rel == l[j].Rel {
return l[i].Type < l[j].Type
}
return l[i].Rel < l[j].Rel
}
@ -89,6 +92,9 @@ func ParseJRD(blob []byte) (*JRD, error) {
if err != nil {
return nil, err
}
for i := range jrd.Links {
jrd.Links[i].Index = uint64(i)
}
return &jrd, nil
}
@ -102,7 +108,7 @@ func (jrd *JRD) GetLinkByRel(rel string) *Link {
return nil
}
// GetLinksByRel returns the first *Link with the specified rel value.
// GetLinksByRel returns each *Link with the specified rel value.
func (jrd *JRD) GetLinksByRel(rel ...string) []*Link {
var lis []*Link
rels := set.New(rel...)
@ -180,20 +186,21 @@ func (a *JRD) ApplyEvent(events ...event.Event) {
a.Properties = map[string]*string{}
case *LinkSet:
link, ok := slice.FindFn(func(l *Link) bool { return l.Rel == e.Rel }, a.Links...)
link, ok := slice.FindFn(func(l *Link) bool { return l.Index == e.Index }, a.Links...)
if !ok {
link = &Link{}
link.Rel = e.Rel
link.Index = uint64(len(a.Links))
a.Links = append(a.Links, link)
}
link.Rel = e.Rel
link.HRef = e.HRef
link.Type = e.Type
link.Titles = e.Titles
link.Properties = e.Properties
case *LinkDeleted:
a.Links = slice.FilterFn(func(link *Link) bool { return link.Rel != e.Rel }, a.Links...)
a.Links = slice.FilterFn(func(link *Link) bool { return link.Index != e.Index }, a.Links...)
}
}
}
@ -241,17 +248,15 @@ func (a *JRD) OnClaims(jrd *JRD) error {
return err
}
sort.Sort(jrd.Links)
sort.Sort(a.Links)
for _, z := range slice.Align(
jrd.Links,
a.Links,
func(l, r *Link) bool { return l.Rel < r.Rel },
func(l, r *Link) bool { return l.Index < r.Index },
) {
// Not in new == delete
if z.Key == nil {
link := *z.Value
event.Raise(a, &LinkDeleted{Rel: link.Rel})
event.Raise(a, &LinkDeleted{Index: link.Index, Rel: link.Rel})
continue
}
@ -259,6 +264,7 @@ func (a *JRD) OnClaims(jrd *JRD) error {
if z.Value == nil {
link := *z.Key
event.Raise(a, &LinkSet{
Index: link.Index,
Rel: link.Rel,
Type: link.Type,
HRef: link.HRef,
@ -324,6 +330,7 @@ func (a *JRD) OnSubjectSet(subject string, aliases []string, props map[string]*s
func (a *JRD) OnLinkSet(o, n *Link) error {
modified := false
e := &LinkSet{
Index: n.Index,
Rel: n.Rel,
Type: n.Type,
HRef: n.HRef,
@ -331,39 +338,66 @@ func (a *JRD) OnLinkSet(o, n *Link) error {
Properties: n.Properties,
}
// if n.Index != o.Index {
// fmt.Println(342)
// modified = true
// }
if n.Rel != o.Rel {
fmt.Println(346)
modified = true
}
if n.Type != o.Type {
fmt.Println(350)
modified = true
}
if n.HRef != o.HRef {
fmt.Println(355)
modified = true
}
nKeys := slice.FromMapKeys(n.Properties)
sort.Strings(nKeys)
oKeys := slice.FromMapKeys(o.Properties)
sort.Strings(oKeys)
for _, z := range slice.Zip(
slice.Zip(slice.FromMap(n.Titles)),
slice.Zip(slice.FromMap(o.Titles)),
slice.Zip(nKeys, slice.FromMapValues(n.Titles, nKeys)),
slice.Zip(oKeys, slice.FromMapValues(o.Titles, oKeys)),
) {
if z.Key != z.Value {
fmt.Println(365)
modified = true
break
}
}
nKeys = slice.FromMapKeys(n.Properties)
sort.Strings(nKeys)
oKeys = slice.FromMapKeys(o.Properties)
sort.Strings(oKeys)
for _, z := range slice.Zip(
slice.Zip(slice.FromMap(n.Properties)),
slice.Zip(slice.FromMap(o.Properties)),
slice.Zip(nKeys, slice.FromMapValues(n.Properties, nKeys)),
slice.Zip(oKeys, slice.FromMapValues(o.Properties, oKeys)),
) {
newValue := z.Key
curValue := z.Value
if newValue.Key != curValue.Key {
fmt.Println(380, newValue.Key, curValue.Key)
modified = true
break
}
if !cmpPtr(newValue.Value, curValue.Value) {
fmt.Println(387)
modified = true
break
}

View File

@ -111,14 +111,17 @@ func TestApplyEvents(t *testing.T) {
},
},
&webfinger.LinkSet{
Index: 0,
Rel: "salty:public",
Type: "application/json+salty",
},
&webfinger.LinkSet{
Index: 1,
Rel: "salty:private",
Type: "application/json+salty",
},
&webfinger.LinkSet{
Index: 0,
Rel: "salty:public",
Type: "application/json+salty",
HRef: "https://ev.sour.is/inbox/01GAEMKXYJ4857JQP1MJGD61Z5",
@ -127,6 +130,7 @@ func TestApplyEvents(t *testing.T) {
},
},
&webfinger.LinkDeleted{
Index: 1,
Rel: "salty:private",
},
)
@ -167,7 +171,6 @@ func TestCommands(t *testing.T) {
pub, priv, err := ed25519.GenerateKey(nil)
is.NoErr(err)
// fmt.Println(base64.RawURLEncoding.EncodeToString(key))
token := jwt.NewWithClaims(jwt.SigningMethodEdDSA, jwt.MapClaims{
"sub": "acct:me@sour.is",
"pub": enc(pub),

View File

@ -112,6 +112,10 @@ func (s *service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
return nil, fmt.Errorf("wrong type of claim")
}
if c.JRD == nil {
c.JRD = &JRD{}
}
c.JRD.Subject = c.RegisteredClaims.Subject
c.SetProperty(NSpubkey, &c.PubKey)
@ -149,9 +153,17 @@ func (s *service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
}
}
for i := range c.JRD.Links {
c.JRD.Links[i].Index = uint64(i)
}
a, err := ev.Upsert(ctx, s.es, StreamID(c.JRD.Subject), func(ctx context.Context, a *JRD) error {
var auth *JRD
for i := range a.Links {
a.Links[i].Index = uint64(i)
}
// does the target have a pubkey for self auth?
if _, ok := a.Properties[NSpubkey]; ok {
auth = a
@ -237,7 +249,7 @@ func (s *service) ServeHTTP(w http.ResponseWriter, r *http.Request) {
redirect.Host = u.URL.Host
redirect.RawQuery = r.URL.RawQuery
redirect.Path = "/.well-known/webfinger"
fmt.Println(redirect)
w.Header().Set("location", redirect.String())
w.WriteHeader(http.StatusSeeOther)
return
@ -300,31 +312,32 @@ func dec(s string) ([]byte, error) {
s = strings.TrimSpace(s)
return base64.RawURLEncoding.DecodeString(s)
}
func splitHostPort(hostPort string) (host, port string) {
host = hostPort
colon := strings.LastIndexByte(host, ':')
if colon != -1 && validOptionalPort(host[colon:]) {
host, port = host[:colon], host[colon+1:]
}
// func splitHostPort(hostPort string) (host, port string) {
// host = hostPort
if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
host = host[1 : len(host)-1]
}
// colon := strings.LastIndexByte(host, ':')
// if colon != -1 && validOptionalPort(host[colon:]) {
// host, port = host[:colon], host[colon+1:]
// }
return
}
func validOptionalPort(port string) bool {
if port == "" {
return true
}
if port[0] != ':' {
return false
}
for _, b := range port[1:] {
if b < '0' || b > '9' {
return false
}
}
return true
}
// if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") {
// host = host[1 : len(host)-1]
// }
// return
// }
// func validOptionalPort(port string) bool {
// if port == "" {
// return true
// }
// if port[0] != ':' {
// return false
// }
// for _, b := range port[1:] {
// if b < '0' || b > '9' {
// return false
// }
// }
// return true
// }

View File

@ -38,7 +38,7 @@ var _ = apps.Register(50, func(ctx context.Context, svc *service.Harness) error
cache.SetDefault(s, true)
return false
})
var withHostnames webfinger.WithHostnames = strings.Fields(env.Default("WEBFINGER_DOMAINS", "sour.is"))
var withHostnames webfinger.WithHostnames = strings.Fields(env.Default(" ", "sour.is"))
wf, err := webfinger.New(ctx, eventstore, withCache, withHostnames)
if err != nil {

View File

@ -44,11 +44,11 @@ func First[T any](in ...T) (T, bool) {
}
// Map applys func to each element s and returns results as slice.
func Map[T, U any](f func(T) U) func(...T) []U {
func Map[T, U any](f func(int, T) U) func(...T) []U {
return func(lis ...T) []U {
r := make([]U, len(lis))
for i, v := range lis {
r[i] = f(v)
r[i] = f(i, v)
}
return r
}
@ -73,19 +73,38 @@ func FromMap[K comparable, V any](m map[K]V) (keys []K, values []V) {
return nil, nil
}
keys = FromMapKeys(m)
return keys, FromMapValues(m, keys)
}
func FromMapKeys[K comparable, V any](m map[K]V) (keys []K) {
if m == nil {
return nil
}
keys = make([]K, 0, len(m))
values = make([]V, 0, len(m))
for k := range m {
keys = append(keys, k)
}
return keys
}
func FromMapValues[K comparable, V any](m map[K]V, keys []K) (values []V) {
if m == nil {
return nil
}
values = make([]V, 0, len(keys))
for _, k := range keys {
values = append(values, m[k])
}
return keys, values
return values
}
func ToMap[K comparable, V any](keys []K, values []V) (m map[K]V) {
m = make(map[K]V, len(keys))