diff --git a/adapter/mastodon.go b/adapter/mastodon.go index 18106fe..608dcac 100644 --- a/adapter/mastodon.go +++ b/adapter/mastodon.go @@ -99,24 +99,24 @@ func (self *MastoAdapter) DefaultSubscriptionFilter() string { } func (self *MastoAdapter) mastoUpdateToMessage(status madon.Status) *Message { - var parent *madon.Status - - if status.InReplyToID != nil { - parent, _ = self.masto.GetStatus(*status.InReplyToID) - } msg := Message{ - Protocol: "mastodon", + Datagram: Datagram{ + Protocol: "mastodon", + Adapter: self.nickname, + Id: fmt.Sprintf("%d", status.ID), + Uri: status.URI, + Type: "message", + }, Content: status.Content, - Uri: status.URI, Author: status.Account.Acct, Created: status.CreatedAt, Visibility: status.Visibility, } - if parent != nil { - msg.ReplyTo = &parent.URI + if status.InReplyToID != nil { + idStr := fmt.Sprintf("%d", *status.InReplyToID) + msg.ReplyTo = &idStr } // TODO: mentions and replies - msg.Aux = make(map[string]string) - msg.Aux["visibility"] = status.Visibility + return &msg } diff --git a/adapter/misskey.go b/adapter/misskey.go index e6f5bad..0ff117b 100644 --- a/adapter/misskey.go +++ b/adapter/misskey.go @@ -176,11 +176,17 @@ func (self *MisskeyAdapter) cacheAndConvert(n mkm.Note) *Message { if !exists || timestamp.Before(n.CreatedAt) { self.cache[n.ID] = n.CreatedAt msg := Message{ - Uri: n.URI, + Datagram: Datagram{ + Id: n.ID, + Uri: n.URI, + Protocol: "misskey", + Adapter: self.nickname, + Type: "message", + }, + + Created: n.CreatedAt, + Author: fmt.Sprintf("%s@%s", n.User.Username, mkcore.StringValue(n.User.Host)), - Protocol: "misskey", - Adapter: self.nickname, - Created: n.CreatedAt, Content: n.Text, Attachments: []Attachment{}, Visibility: n.Visibility, diff --git a/adapter/nostr.go b/adapter/nostr.go index 2185f22..38be7af 100644 --- a/adapter/nostr.go +++ b/adapter/nostr.go @@ -89,15 +89,18 @@ func (self *NostrAdapter) DefaultSubscriptionFilter() string { func (self *NostrAdapter) nostrEventToMsg(evt *nostr.Event) (Message, error) { m := Message{ - Protocol: "nostr", - Adapter: self.nickname, + Datagram: Datagram{ + Protocol: "nostr", + Adapter: self.nickname, + Type: "message", + }, } if evt == nil { return m, errors.New("no event") } switch evt.Kind { case nostr.KindTextNote: - m.Uri = evt.ID + m.Id = evt.ID m.Author = evt.PubKey m.Created = evt.CreatedAt.Time() m.Content = evt.Content diff --git a/models/msg.go b/models/msg.go index 2c9cef2..ea07478 100644 --- a/models/msg.go +++ b/models/msg.go @@ -5,11 +5,18 @@ import ( "time" ) +type Datagram struct { + Id string + Uri string + Protocol string + Adapter string + Type string + Target *string +} + type Message struct { - Uri string + Datagram Author string - Protocol string - Adapter string Content string Attachments []Attachment ReplyTo *string @@ -22,11 +29,11 @@ type Message struct { } type Author struct { - Id string + Datagram Name string ProfileData interface{} - ProfileUri string ProfilePic string + Messages []Message } type Attachment struct { diff --git a/ts/adapter.ts b/ts/adapter.ts index 2609381..7fa1d70 100644 --- a/ts/adapter.ts +++ b/ts/adapter.ts @@ -1,118 +1,17 @@ -import NDK, {NDKPrivateKeySigner} from "@nostr-dev-kit/ndk"; -import * as nip19 from 'nostr-tools/nip19' -import { createRestAPIClient, createStreamingAPIClient } from "masto"; -import * as masto from "masto"; - -type MastodonClient = masto.mastodon.rest.Client; -type MastodonStreamClient = masto.mastodon.streaming.Client; - -export class MastodonCompoundClient { - public rest: MastodonClient; - public stream: MastodonStreamClient; +import {Message, Author} from "./message" +export class AdapterData { + public protocol: string; + public directMessages Map(); + public messages: Map(); + public profileCache: Map; - public constructor(c: MastodonClient, s: MastodonStreamClient) { - this.rest = c; - this.stream = s; + constructor(protocol: string) { + this.protocol = protocol; + this.messages = []; + this.profileCache = []; } } -export class Adapter { - public nickname: string = ""; - public protocol: string = ""; - public identity: any | null; - - private _self: NDK | MastodonCompoundClient | null = null ; - - public init(): void {}; - public getInbox(): void {}; - public publish(): void {}; - public getFollowers(): any[] { return [] }; - public getFollowing(): any[] { return [] }; - public updateMetadata(): void {}; - public getMetadata(): any { return {} }; - - // according to the docs NDK must be a singleton... - // this probalby will make having more than one nostr adapter at once problematic - private static ndk: NDK | null = null; - - public static create(): Adapter { - return new Adapter(); - } - - public static toNostr(adapter: Adapter, settings: any): Adapter { - adapter.identity = { privkey: settings.privkey }; - adapter.nickname = settings.nickname; - - adapter.init = ()=> { - if (!Adapter.ndk) { - let privkey_raw = nip19.decode(settings.privkey); - Adapter.ndk = new NDK({ - signer: new NDKPrivateKeySigner(privkey_raw.data), - explicitRelayUrls: [ settings.relays ] - }); - adapter._self = Adapter.ndk; - Adapter.ndk.connect(); - } else { - Adapter.ndk.signer = new NDKPrivateKeySigner(settings.privatekey); - for (let i of settings.relays) { - Adapter.ndk.addExplicitRelay(i); - } - } - }; - - adapter.getInbox = async () => { - if (Adapter.ndk) { - const sub = Adapter.ndk.subscribe({ kinds: [1] }); // Get all kind:1s - sub.on("event", (event) => console.log(event.content)); // Show the content - sub.on("eose", () => console.log("All relays have reached the end of the event stream")); - sub.on("close", () => console.log("Subscription closed")); - setTimeout(() => sub.stop(), 10000); // Stop the subscription after 10 seconds - } - }; - - return adapter; - } - - public static toMasto(adapter: Adapter, settings: any): Adapter { - adapter.identity = { server: settings.server, apiKey: settings.apiKey }; - adapter.nickname = settings.nickname; - - adapter.init = () => { - const rawServer: string = adapter.identity.server.split("://")[1]; - - adapter._self = new MastodonCompoundClient(createRestAPIClient({ - url: adapter.identity.server, - accessToken: adapter.identity.apiKey - }), - createStreamingAPIClient({ - streamingApiUrl: `https://${rawServer}/v1/api/streaming`, - accessToken: adapter.identity.apiKey - })); - - } - - adapter.getInbox = async () => { - const rawServer: string = adapter.identity.server.split("://")[1]; - let conn = new WebSocket(`wss://${rawServer}/streaming/?i=${adapter.identity.apiKey}`) - conn.addEventListener("open", async (e:any)=> { - console.log(e); - let filter = { type: "connect", body: { channel: "localTimeline", id: crypto.randomUUID() }}; - let data = await JSON.stringify(filter); - console.log(data); - conn.send(data); - conn.addEventListener("message", (e:any)=>{console.log(e)}); - }); - - - - - } - - return adapter; - } -} - - - -export default { Adapter } - +export interface AdapterState { + [nickname: string]: AdapterData; +} \ No newline at end of file diff --git a/ts/index.ts b/ts/index.ts index 201994c..97433a9 100644 --- a/ts/index.ts +++ b/ts/index.ts @@ -11,17 +11,10 @@ function main():void { if (settings != null) { for (let s of settings.adapters ?? []) { - let a: Adapter = Adapter.create() - switch (s.protocol) { - case "nostr": - adapters.push(Adapter.toNostr(a, s)); - break; - case "mastodon": - adapters.push(Adapter.toMasto(a, s)); - } + } if (adapters.length > 0) { - _("currentAdapter", 0); + _("currentAdapter", adapters[0].nickname); // update tabbar and tabcontent with first adapter } } else { @@ -197,6 +190,9 @@ async function authorizedFetch(method: string, uri: string, body: any): Promise< function connect() { + var datastore: AdapterState = {} + datastore = _("datastore", datastore); + const wsProto = location.protocol == "https:" ? "wss" : "ws"; _conn = new WebSocket(`${wsProto}://${location.host}/subscribe`, "underbbs"); _conn.addEventListener("open", (e: any) => { @@ -214,13 +210,28 @@ function connect() { _("skey", data.key) authorizedFetch("POST", "/api/adapters", JSON.stringify(_("settings").adapters)) } else { - // typeswitch on the incoming data and adapters - - // if it's a regular message, add it to the store + if (!datastore[data.adapter]) { + datastore[data.adapter] = new AdapterData(data.protocol); + } + + // typeswitch on the incoming data type and fill the memory + switch (data.type) { + case "message": + datastore[data.adapter].messages[data.id] = data; + break; + case "author": + datastore[data.adapter].profileCache[data.id] = data; + break; + default: + break; + } // if the adapter is active, inject the web components // FOR HOTFETCHED DATA: // before fetching, we can set properties on the DOM, // so when those data return to us we know where to inject components! + if (_("currentAdapter") == data.adapter) { + // dive in and insert that shit in the dom + } } }); _conn.addEventListener("error", (e: any) => {