From 678e5e62584a2edc9f909c0b02247fa7ba95f71c Mon Sep 17 00:00:00 2001 From: Iris Lightshard Date: Sat, 22 Jun 2024 10:39:02 -0600 Subject: [PATCH] start naive misskey adapter --- adapter/adapter.go | 7 +-- adapter/mastodon.go | 23 ++++----- adapter/misskey.go | 119 ++++++++++++++++++++++++++++++++++++++++++++ adapter/nostr.go | 15 ++---- go.mod | 2 + go.sum | 6 +++ 6 files changed, 143 insertions(+), 29 deletions(-) create mode 100644 adapter/misskey.go diff --git a/adapter/adapter.go b/adapter/adapter.go index 807a232..a808970 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -7,10 +7,7 @@ import ( type Adapter interface { Init(Settings, chan SocketData) error Subscribe(string) []error - SendMessage(Message) error - Follow(Author) error - Unfollow(Author) error - GetFollowers() error - UpdateMetadata(interface{}) error + Fetch(string) error + Do(string) error DefaultSubscriptionFilter() string } diff --git a/adapter/mastodon.go b/adapter/mastodon.go index b846fbc..12ff0cc 100644 --- a/adapter/mastodon.go +++ b/adapter/mastodon.go @@ -52,9 +52,13 @@ func (self *MastoAdapter) Subscribe(filter string) []error { self.done = make(chan bool) - self.masto.StreamListener(filter, "", self.events, self.stop, self.done) + err := self.masto.StreamListener(filter, "", self.events, self.stop, self.done) + if err != nil { + return []error{err} + } go func() { for e := range self.events { + fmt.Println("event: %s !!!", e.Event) switch e.Event { case "error": case "update": @@ -81,24 +85,17 @@ func (self *MastoAdapter) Subscribe(filter string) []error { // the stopCh will be closed by a subsequent call to subscribe return nil } -func (self *MastoAdapter) SendMessage(msg Message) error { + +func (self *MastoAdapter) Fetch(query string) error { return nil } -func (self *MastoAdapter) Follow(author Author) error { - return nil -} -func (self *MastoAdapter) Unfollow(author Author) error { - return nil -} -func (self *MastoAdapter) GetFollowers() error { - return nil -} -func (self *MastoAdapter) UpdateMetadata(data interface{}) error { + +func (self *MastoAdapter) Do(action string) error { return nil } func (self *MastoAdapter) DefaultSubscriptionFilter() string { - return "home" + return "user" } func (self *MastoAdapter) mastoUpdateToMessage(status madon.Status) *Message { diff --git a/adapter/misskey.go b/adapter/misskey.go new file mode 100644 index 0000000..c7a25dc --- /dev/null +++ b/adapter/misskey.go @@ -0,0 +1,119 @@ +package adapter + +import ( + "fmt" + . "forge.lightcrystal.systems/lightcrystal/underbbs/models" + "github.com/yitsushi/go-misskey" + mkm "github.com/yitsushi/go-misskey/models" + notes "github.com/yitsushi/go-misskey/services/notes" + tl "github.com/yitsushi/go-misskey/services/notes/timeline" + _ "strings" + "time" +) + +type MisskeyAdapter struct { + data chan SocketData + nickname string + server string + apiKey string + + mk *misskey.Client + + // unlike the mastodon client, we have to manage combining resources + // from different API calls instead of streaming them in a single channel + + cache map[string]time.Time + + stop chan bool + + notes chan mkm.Note + users chan mkm.User + follows chan mkm.FollowStatus +} + +func (self *MisskeyAdapter) Init(settings Settings, data chan SocketData) error { + self.nickname = settings.Nickname + self.server = *settings.Server + self.apiKey = *settings.ApiKey + self.data = data + + client, err := misskey.NewClientWithOptions( + misskey.WithAPIToken(self.apiKey), + misskey.WithBaseURL("https", self.server, ""), + ) + + if err != nil { + return err + } + self.mk = client + return nil +} + +func (self *MisskeyAdapter) Subscribe(filter string) []error { + // misskey streaming API is undocumented.... + // we could try to reverse engineer it by directly connecting to the websocket??? + // alternatively, we can poll timelines, mentions, etc with a cancellation channel, + // keep a cache of IDs in memory, and send new objects on the data channel + + // TODO: decode the filter so we can send data to the mk services + + // same as in masto, we will want to close and reopen the stop channel + if self.stop != nil { + close(self.stop) + } + self.stop = make(chan bool) + + // in the background, continuously read data from these API endpoints + // if they are newer than the cache, convert them to UnderBBS objects + // and send them on the data channel + + go func() { + notesService := self.mk.Notes() + timelineService := notesService.Timeline() + + for { + _, moar := <-self.stop + if !moar { + break + } + + // TODO: we have to actually decode and pass our filter criteria + tlnotes, tlerr := timelineService.Get(tl.GetRequest{}) + mentions, merr := notesService.Mentions(notes.MentionsRequest{}) + + if tlerr != nil { + fmt.Println(tlerr.Error()) + } + if merr != nil { + fmt.Println(merr.Error()) + } + + // check the cache for everything we just collected + // if anything is newer or as of yet not in the cache, add it + // and convert it to a SocketData implementation before sending on data channel + for _, n := range tlnotes { + fmt.Println(n.ID) + // check existence and cache + // convert + // send + } + for _, n := range mentions { + fmt.Println(n.ID) + // check existence and cache + // convert + // send + } + } + + }() + + return nil +} + +func (self *MisskeyAdapter) Fetch(query string) error { + return nil +} + +func (self *MisskeyAdapter) Do(action string) error { + return nil +} diff --git a/adapter/nostr.go b/adapter/nostr.go index 86d85ab..991a7f4 100644 --- a/adapter/nostr.go +++ b/adapter/nostr.go @@ -74,19 +74,12 @@ func (self *NostrAdapter) Subscribe(filter string) []error { fmt.Println("subscription operation completed without errors") return nil } -func (self *NostrAdapter) SendMessage(msg Message) error { + +func (self *NostrAdapter) Fetch(query string) error { return nil } -func (self *NostrAdapter) Follow(author Author) error { - return nil -} -func (self *NostrAdapter) Unfollow(author Author) error { - return nil -} -func (self *NostrAdapter) GetFollowers() error { - return nil -} -func (self *NostrAdapter) UpdateMetadata(data interface{}) error { + +func (self *NostrAdapter) Do(action string) error { return nil } diff --git a/go.mod b/go.mod index 0294768..7eb410e 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.22.0 require ( github.com/McKael/madon v2.3.0+incompatible github.com/nbd-wtf/go-nostr v0.31.2 + github.com/yitsushi/go-misskey v1.1.6 golang.org/x/time v0.5.0 hacklab.nilfm.cc/quartzgun v0.3.2 nhooyr.io/websocket v1.8.11 @@ -24,6 +25,7 @@ require ( github.com/pkg/errors v0.9.1 // indirect github.com/puzpuzpuz/xsync/v3 v3.0.2 // indirect github.com/sendgrid/rest v2.6.9+incompatible // indirect + github.com/sirupsen/logrus v1.7.0 // indirect github.com/tidwall/gjson v1.14.4 // indirect github.com/tidwall/match v1.1.1 // indirect github.com/tidwall/pretty v1.2.0 // indirect diff --git a/go.sum b/go.sum index 9ba91e9..144f2f4 100644 --- a/go.sum +++ b/go.sum @@ -34,6 +34,9 @@ github.com/puzpuzpuz/xsync/v3 v3.0.2 h1:3yESHrRFYr6xzkz61LLkvNiPFXxJEAABanTQpKbA github.com/puzpuzpuz/xsync/v3 v3.0.2/go.mod h1:VjzYrABPabuM4KyBh1Ftq6u8nhwY5tBPKP9jpmh0nnA= github.com/sendgrid/rest v2.6.9+incompatible h1:1EyIcsNdn9KIisLW50MKwmSRSK+ekueiEMJ7NEoxJo0= github.com/sendgrid/rest v2.6.9+incompatible/go.mod h1:kXX7q3jZtJXK5c5qK83bSGMdV6tsOE70KbHoqJls4lE= +github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= +github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/tidwall/gjson v1.14.4 h1:uo0p8EbA09J7RQaflQ1aBRffTR7xedD2bcIVSYxLnkM= @@ -42,12 +45,15 @@ github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA= github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM= github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs= github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU= +github.com/yitsushi/go-misskey v1.1.6 h1:aMfu7N9RzS2JO2QP9TPBXQyvudwU7NTr6jiOeUcho3Q= +github.com/yitsushi/go-misskey v1.1.6/go.mod h1:FeLNMTVebkWTbjRt5X1YqkKc61dOjgTy2hyUDaOC+zc= golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o= golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w= golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= golang.org/x/oauth2 v0.21.0 h1:tsimM75w1tF/uws5rbeHzIWxEqElMehnc+iW793zsZs= golang.org/x/oauth2 v0.21.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=