diff --git a/adapter/adapter.go b/adapter/adapter.go index 6e0346b..0a1cdee 100644 --- a/adapter/adapter.go +++ b/adapter/adapter.go @@ -6,6 +6,7 @@ import ( type Adapter interface { Init(Settings, *chan SocketData) error + Stop() Name() string Subscribe(string, *string) []error Fetch(string, []string) error diff --git a/adapter/honk.go b/adapter/honk.go index d07af4f..0718d8f 100644 --- a/adapter/honk.go +++ b/adapter/honk.go @@ -101,13 +101,19 @@ func (self *HonkAdapter) Init(settings Settings, data *chan SocketData) error { self.token = string(buf[:]) fmt.Println(self.token) + + self.stop = make(chan bool) return nil } +func (self *HonkAdapter) Stop() { + close(self.stop) +} + func (self *HonkAdapter) Subscribe(filter string, target *string) []error { + if self.stop != nil { close(self.stop) - self.maxId = 0 } self.stop = make(chan bool) @@ -117,14 +123,18 @@ func (self *HonkAdapter) Subscribe(filter string, target *string) []error { } func (self *HonkAdapter) gethonks(filter string, target *string) { - + x := self.stop + self.maxId = 0 for { select { - case _, ok := <-self.stop: + case _, ok := <-x: if !ok { + fmt.Println("stopping! filter was " + filter) + return } default: + fmt.Println("getting honks, filter is " + filter) honkForm := url.Values{ "action": []string{"gethonks"}, "token": []string{self.token}, diff --git a/adapter/mastodon.go b/adapter/mastodon.go index 4aacd9f..d08de23 100644 --- a/adapter/mastodon.go +++ b/adapter/mastodon.go @@ -50,6 +50,10 @@ func (self *MastoAdapter) Init(settings Settings, data *chan SocketData) error { return err } +func (self *MastoAdapter) Stop() { + close(self.stop) +} + func (self *MastoAdapter) Subscribe(filter string, target *string) []error { // TODO: decode separate timelines and hashtags // for now, the filter is just the timeline @@ -71,7 +75,8 @@ func (self *MastoAdapter) Subscribe(filter string, target *string) []error { return []error{err} } go func() { - for e := range self.events { + ee := self.events + for e := range ee { log.Printf("event: %s !!!", e.Event) switch e.Event { case "error": diff --git a/adapter/misskey.go b/adapter/misskey.go index fa14206..f88f3a7 100644 --- a/adapter/misskey.go +++ b/adapter/misskey.go @@ -45,6 +45,10 @@ func (self *MisskeyAdapter) Name() string { return self.nickname } +func (self *MisskeyAdapter) Stop() { + close(self.stop) +} + func (self *MisskeyAdapter) Init(settings Settings, data *chan SocketData) error { log.Print("initializing misskey adapter") @@ -102,9 +106,11 @@ func (self *MisskeyAdapter) poll() { var notesService *n.Service var timelineService *tl.Service + x := self.stop + for { select { - case _, ok := <-self.stop: + case _, ok := <-x: if !ok { return } diff --git a/adapter/nostr.go b/adapter/nostr.go index 7d4abad..8524bbb 100644 --- a/adapter/nostr.go +++ b/adapter/nostr.go @@ -48,6 +48,11 @@ func (self *NostrAdapter) Init(settings Settings, data *chan SocketData) error { return nil } +func (self *NostrAdapter) Stop() { + // nostr has native streaming so we don't need to do anything in this method + return +} + func (self *NostrAdapter) Subscribe(filter string, target *string) []error { var filters nostr.Filters err := json.Unmarshal([]byte(filter), &filters) diff --git a/frontend/dist/index.html b/frontend/dist/index.html index bbe4d0a..c54eb2b 100644 --- a/frontend/dist/index.html +++ b/frontend/dist/index.html @@ -16,6 +16,7 @@
settings
+
timeline-select
timeline
diff --git a/frontend/ts/index.ts b/frontend/ts/index.ts index 8cfae05..43c0424 100644 --- a/frontend/ts/index.ts +++ b/frontend/ts/index.ts @@ -7,6 +7,7 @@ import { SettingsElement } from "./settings-element" import { ProfileElement } from "./profile-element" import { AuthorMessagesElement } from "./author-messages-element" import { TimelineElement } from "./timeline-element" +import { TimelineFilterElement } from "./timeline-filter-element" import {DatagramSocket} from "./websocket" function main() { @@ -18,6 +19,7 @@ function main() { customElements.define("underbbs-profile", ProfileElement); customElements.define("underbbs-author-messages", AuthorMessagesElement); customElements.define("underbbs-timeline", TimelineElement); + customElements.define("underbbs-timeline-filter", TimelineFilterElement); util._("closeErr", util.closeErr); @@ -40,6 +42,11 @@ function main() { if (timelineParent) { timelineParent.innerHTML = ""; } + + let timelineSelectParent = util.$("timeline_filter_parent"); + if (timelineSelectParent) { + timelineSelectParent.innerHTML = ""; + } } main(); diff --git a/frontend/ts/timeline-element.ts b/frontend/ts/timeline-element.ts index 58d402e..2a4f0d8 100644 --- a/frontend/ts/timeline-element.ts +++ b/frontend/ts/timeline-element.ts @@ -32,6 +32,7 @@ export class TimelineElement extends HTMLElement { } this._timeline = next; this.innerHTML = ``; + this._messages = []; if (this._subscriber) { this._subscriber.subscribe(next); } diff --git a/frontend/ts/timeline-filter-element.ts b/frontend/ts/timeline-filter-element.ts new file mode 100644 index 0000000..3ffd1a9 --- /dev/null +++ b/frontend/ts/timeline-filter-element.ts @@ -0,0 +1,55 @@ +export class TimelineFilter { + public name: string = ""; + public filter: string = ""; +} + +export class TimelineFilterElement extends HTMLElement { + static observedAttributes = [ "data-filters", "data-target", "data-latest" ]; + + private _filters: TimelineFilter[] = []; + private _target: string = ""; + + constructor() { + super(); + this.innerHTML = "" + + } + + connectedCallback() { + this._target = this.getAttribute("data-target") ?? ""; + this._filters = (this.getAttribute("data-filters") ?? "").split("/").map(f=>{ + const ff = f.split("::"); + return { name: ff[0], filter: ff[1] }; + }); + let html = ""; + this.innerHTML = html; + const select = this.querySelector(".filter_select"); + if (select) { + select.addEventListener("change", this.onChanges.bind(this)); + } + } + + onChanges() { + const select = this.querySelector(".filter_select") as HTMLSelectElement; + + // change target's target! + const target = document.getElementById(this._target); + if (target) { + target.setAttribute("data-target", select?.options[select.selectedIndex].value) + } + } + + attributeChangedCallback(attr: string, prev: string, next: string) { + switch (attr) { + case "data-latest": + const select = this.querySelector(".filter_select") as HTMLSelectElement; + select.selectedIndex = this._filters.findIndex(f=>f.name == next); + break; + } + } +} \ No newline at end of file diff --git a/server/server.go b/server/server.go index 9cb384a..f5af2b7 100644 --- a/server/server.go +++ b/server/server.go @@ -97,6 +97,10 @@ func (self *BBSServer) subscribeHandler(w http.ResponseWriter, r *http.Request) case <-ctx.Done(): self.logf("subscriber has disconnected") + for _, a := range self.subscribers[s] { + // keeps any adapter's subscription from trying to send on the data channel after we close it + a.Stop() + } close(s.data) return //ctx.Err() }