lining things up for UI goodness

This commit is contained in:
Iris Lightshard 2024-06-29 18:18:31 -06:00
parent 2244bbcf7a
commit b8429533df
Signed by: Iris Lightshard
GPG key ID: 688407174966CAF3
6 changed files with 75 additions and 149 deletions

View file

@ -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{
Datagram: Datagram{
Protocol: "mastodon",
Content: status.Content,
Adapter: self.nickname,
Id: fmt.Sprintf("%d", status.ID),
Uri: status.URI,
Type: "message",
},
Content: status.Content,
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
}

View file

@ -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{
Datagram: Datagram{
Id: n.ID,
Uri: n.URI,
Author: fmt.Sprintf("%s@%s", n.User.Username, mkcore.StringValue(n.User.Host)),
Protocol: "misskey",
Adapter: self.nickname,
Type: "message",
},
Created: n.CreatedAt,
Author: fmt.Sprintf("%s@%s", n.User.Username, mkcore.StringValue(n.User.Host)),
Content: n.Text,
Attachments: []Attachment{},
Visibility: n.Visibility,

View file

@ -89,15 +89,18 @@ func (self *NostrAdapter) DefaultSubscriptionFilter() string {
func (self *NostrAdapter) nostrEventToMsg(evt *nostr.Event) (Message, error) {
m := Message{
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

View file

@ -5,11 +5,18 @@ import (
"time"
)
type Message struct {
type Datagram struct {
Id string
Uri string
Author string
Protocol string
Adapter string
Type string
Target *string
}
type Message struct {
Datagram
Author 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 {

View file

@ -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";
import {Message, Author} from "./message"
export class AdapterData {
public protocol: string;
public directMessages Map<string, Message>();
public messages: Map<string, Message>();
public profileCache: Map<string, Author>;
type MastodonClient = masto.mastodon.rest.Client;
type MastodonStreamClient = masto.mastodon.streaming.Client;
export class MastodonCompoundClient {
public rest: MastodonClient;
public stream: MastodonStreamClient;
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();
export interface AdapterState {
[nickname: string]: AdapterData;
}
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(<string>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 }

View file

@ -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 (!datastore[data.adapter]) {
datastore[data.adapter] = new AdapterData(data.protocol);
}
// if it's a regular message, add it to the store
// typeswitch on the incoming data type and fill the memory
switch (data.type) {
case "message":
datastore[data.adapter].messages[data.id] = <Message>data;
break;
case "author":
datastore[data.adapter].profileCache[data.id] = <Author>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) => {