mirror of
https://github.com/block/buzz.git
synced 2026-08-18 06:50:31 +02:00
Add desktop presence UI (#35)
This commit is contained in:
@@ -5,7 +5,7 @@ import {
|
||||
getRelayWsUrl,
|
||||
signRelayEvent,
|
||||
} from "@/shared/api/tauri";
|
||||
import type { RelayEvent } from "@/shared/api/types";
|
||||
import type { PresenceStatus, RelayEvent } from "@/shared/api/types";
|
||||
|
||||
type RelaySubscriptionFilter = {
|
||||
kinds: number[];
|
||||
@@ -125,29 +125,27 @@ class RelayClient {
|
||||
tags: [["h", channelId]],
|
||||
});
|
||||
|
||||
return new Promise<RelayEvent>((resolve, reject) => {
|
||||
const timeout = window.setTimeout(() => {
|
||||
this.pendingEvents.delete(event.id);
|
||||
reject(new Error("Timed out while sending the message."));
|
||||
}, 8_000);
|
||||
return this.publishEvent(
|
||||
event,
|
||||
"Timed out while sending the message.",
|
||||
"Failed to send the message.",
|
||||
);
|
||||
}
|
||||
|
||||
this.pendingEvents.set(event.id, {
|
||||
event,
|
||||
resolve,
|
||||
reject,
|
||||
timeout,
|
||||
});
|
||||
async sendPresence(status: PresenceStatus) {
|
||||
await this.ensureConnected();
|
||||
|
||||
void this.sendRaw(["EVENT", event]).catch((error) => {
|
||||
window.clearTimeout(timeout);
|
||||
this.pendingEvents.delete(event.id);
|
||||
reject(
|
||||
error instanceof Error
|
||||
? error
|
||||
: new Error("Failed to send the message."),
|
||||
);
|
||||
});
|
||||
const event = await signRelayEvent({
|
||||
kind: 20001,
|
||||
content: status,
|
||||
tags: [],
|
||||
});
|
||||
|
||||
return this.publishEvent(
|
||||
event,
|
||||
"Timed out while updating presence.",
|
||||
"Failed to update presence.",
|
||||
);
|
||||
}
|
||||
|
||||
async subscribeToChannel(
|
||||
@@ -260,6 +258,32 @@ class RelayClient {
|
||||
await this.sendRaw(["CLOSE", subId]);
|
||||
}
|
||||
|
||||
private publishEvent(
|
||||
event: RelayEvent,
|
||||
timeoutMessage: string,
|
||||
sendErrorMessage: string,
|
||||
) {
|
||||
return new Promise<RelayEvent>((resolve, reject) => {
|
||||
const timeout = window.setTimeout(() => {
|
||||
this.pendingEvents.delete(event.id);
|
||||
reject(new Error(timeoutMessage));
|
||||
}, 8_000);
|
||||
|
||||
this.pendingEvents.set(event.id, {
|
||||
event,
|
||||
resolve,
|
||||
reject,
|
||||
timeout,
|
||||
});
|
||||
|
||||
void this.sendRaw(["EVENT", event]).catch((error) => {
|
||||
window.clearTimeout(timeout);
|
||||
this.pendingEvents.delete(event.id);
|
||||
reject(error instanceof Error ? error : new Error(sendErrorMessage));
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private async handleWsMessage(message: unknown) {
|
||||
if (
|
||||
typeof message === "object" &&
|
||||
|
||||
@@ -11,10 +11,13 @@ import type {
|
||||
GetHomeFeedInput,
|
||||
HomeFeedResponse,
|
||||
Identity,
|
||||
PresenceLookup,
|
||||
PresenceStatus,
|
||||
Profile,
|
||||
RelayEvent,
|
||||
SearchMessagesInput,
|
||||
SearchMessagesResponse,
|
||||
SetPresenceResult,
|
||||
SetChannelPurposeInput,
|
||||
SetChannelTopicInput,
|
||||
UpdateProfileInput,
|
||||
@@ -46,6 +49,13 @@ type RawUsersBatchResponse = {
|
||||
missing: string[];
|
||||
};
|
||||
|
||||
type RawPresenceLookup = Record<string, PresenceStatus>;
|
||||
|
||||
type RawSetPresenceResult = {
|
||||
status: PresenceStatus;
|
||||
ttl_seconds: number;
|
||||
};
|
||||
|
||||
type RawChannel = {
|
||||
id: string;
|
||||
name: string;
|
||||
@@ -268,6 +278,32 @@ export async function getUsersBatch(
|
||||
};
|
||||
}
|
||||
|
||||
export async function getPresence(pubkeys: string[]): Promise<PresenceLookup> {
|
||||
const response = await invoke<RawPresenceLookup>("get_presence", {
|
||||
pubkeys,
|
||||
});
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(response).map(([pubkey, status]) => [
|
||||
pubkey.toLowerCase(),
|
||||
status,
|
||||
]),
|
||||
);
|
||||
}
|
||||
|
||||
export async function setPresence(
|
||||
status: PresenceStatus,
|
||||
): Promise<SetPresenceResult> {
|
||||
const response = await invoke<RawSetPresenceResult>("set_presence", {
|
||||
status,
|
||||
});
|
||||
|
||||
return {
|
||||
status: response.status,
|
||||
ttlSeconds: response.ttl_seconds,
|
||||
};
|
||||
}
|
||||
|
||||
export function getRelayWsUrl(): Promise<string> {
|
||||
return invoke<string>("get_relay_ws_url");
|
||||
}
|
||||
|
||||
@@ -104,6 +104,15 @@ export type UpdateProfileInput = {
|
||||
nip05Handle?: string;
|
||||
};
|
||||
|
||||
export type PresenceStatus = "online" | "away" | "offline";
|
||||
|
||||
export type PresenceLookup = Record<string, PresenceStatus>;
|
||||
|
||||
export type SetPresenceResult = {
|
||||
status: PresenceStatus;
|
||||
ttlSeconds: number;
|
||||
};
|
||||
|
||||
export type RelayEvent = {
|
||||
id: string;
|
||||
pubkey: string;
|
||||
|
||||
Reference in New Issue
Block a user