add deterministic icon and start context relay stuff

This commit is contained in:
smolgrrr 2023-09-15 20:04:05 +10:00
parent d754c20158
commit e968c13939
4 changed files with 192 additions and 3 deletions

View File

@ -3,7 +3,9 @@ import './App.css';
import Home from './components/Home';
import Settings from './components/Settings';
import SwipeableViews from 'react-swipeable-views';
import { NostrProvider } from './utils/relays';
const relayUrls = ['wss://relay.damus.io'];
function App() {
const [index, setIndex] = React.useState(1);
@ -13,7 +15,7 @@ function App() {
};
return (
<div>
<NostrProvider relayUrls={relayUrls} debug={true}>
<SwipeableViews index={index} onChangeIndex={handleChangeIndex}>
<div>
<Settings />
@ -22,7 +24,7 @@ function App() {
<Home />
</div>
</SwipeableViews>
</div>
</NostrProvider>
);
}

View File

@ -25,6 +25,19 @@ function getRandomElement(array: string[]): string {
const index = Math.floor(Math.random() * array.length);
return array[index];
}
const getColorFromHash = (id: string, colors: string[]): string => {
// Create a simple hash from the event.id
let hash = 0;
for (let i = 0; i < id.length; i++) {
hash = (hash << 5) - hash + id.charCodeAt(i);
}
// Use the hash to pick a color from the colors array
const index = Math.abs(hash) % colors.length;
return colors[index];
};
const timeAgo = (unixTime: number) => {
const seconds = Math.floor((new Date().getTime() / 1000) - unixTime);
@ -52,6 +65,7 @@ const PostCard = ({ event}: { event: Event }) => {
// limit: 200,
// },
// ]);
const colorCombo = getColorFromHash(event.id, colorCombos);
return (
<>
@ -59,7 +73,7 @@ const PostCard = ({ event}: { event: Event }) => {
<div className="flex flex-col">
<div className="flex justify-between items-center">
<div className="flex items-center">
<div className={`h-5 w-5 bg-gradient-to-r ${getRandomElement(colorCombos)} rounded-full`} />
<div className={`h-5 w-5 bg-gradient-to-r ${colorCombo} rounded-full`} />
<div className="ml-2 text-md font-semibold">Anonymous</div>
</div>
<div className="flex items-center ml-auto">

152
client/src/utils/relays.tsx Normal file
View File

@ -0,0 +1,152 @@
import {
createContext,
ReactNode,
useCallback,
useContext,
useEffect,
useRef,
useState,
} from "react"
import { Relay, Filter, Event, relayInit, Sub } from "nostr-tools"
import { uniqBy } from "./utils"
type OnConnectFunc = (relay: Relay) => void
type OnDisconnectFunc = (relay: Relay) => void
type OnEventFunc = (event: Event) => void
type OnDoneFunc = () => void
type OnSubscribeFunc = (sub: Sub, relay: Relay) => void
interface NostrContextType {
isLoading: boolean
debug?: boolean
connectedRelays: Relay[]
onConnect: (_onConnectCallback?: OnConnectFunc) => void
onDisconnect: (_onDisconnectCallback?: OnDisconnectFunc) => void
publish: (event: Event) => void
}
const NostrContext = createContext<NostrContextType>({
isLoading: true,
connectedRelays: [],
onConnect: () => null,
onDisconnect: () => null,
publish: () => null,
})
const log = (
isOn: boolean | undefined,
type: "info" | "error" | "warn",
...args: unknown[]
) => {
if (!isOn) return
console[type](...args)
}
export function NostrProvider({
children,
relayUrls,
debug,
}: {
children: ReactNode
relayUrls: string[]
debug?: boolean
}) {
const [isLoading, setIsLoading] = useState(true)
const [connectedRelays, setConnectedRelays] = useState<Relay[]>([])
const [relays, setRelays] = useState<Relay[]>([])
const relayUrlsRef = useRef<string[]>([])
let onConnectCallback: null | OnConnectFunc = null
let onDisconnectCallback: null | OnDisconnectFunc = null
const disconnectToRelays = useCallback(
(relayUrls: string[]) => {
relayUrls.forEach(async (relayUrl) => {
await relays.find((relay) => relay.url === relayUrl)?.close()
setRelays((prev) => prev.filter((r) => r.url !== relayUrl))
})
},
[relays],
)
const connectToRelays = useCallback(
(relayUrls: string[]) => {
relayUrls.forEach(async (relayUrl) => {
const relay = relayInit(relayUrl)
if (connectedRelays.findIndex((r) => r.url === relayUrl) >= 0) {
// already connected, skip
return
}
setRelays((prev) => uniqBy([...prev, relay], "url"))
relay.connect()
relay.on("connect", () => {
log(debug, "info", `✅ nostr (${relayUrl}): Connected!`)
setIsLoading(false)
onConnectCallback?.(relay)
setConnectedRelays((prev) => uniqBy([...prev, relay], "url"))
})
relay.on("disconnect", () => {
log(debug, "warn", `🚪 nostr (${relayUrl}): Connection closed.`)
onDisconnectCallback?.(relay)
setConnectedRelays((prev) => prev.filter((r) => r.url !== relayUrl))
})
relay.on("error", () => {
log(debug, "error", `❌ nostr (${relayUrl}): Connection error!`)
})
})
},
[connectedRelays, debug, onConnectCallback, onDisconnectCallback],
)
useEffect(() => {
if (relayUrlsRef.current === relayUrls) {
// relayUrls isn't updated, skip
return
}
const relayUrlsToDisconnect = relayUrlsRef.current.filter(
(relayUrl) => !relayUrls.includes(relayUrl),
)
disconnectToRelays(relayUrlsToDisconnect)
connectToRelays(relayUrls)
relayUrlsRef.current = relayUrls
}, [relayUrls, connectToRelays, disconnectToRelays])
const publish = (event: Event) => {
return connectedRelays.map((relay) => {
log(debug, "info", `⬆️ nostr (${relay.url}): Sending event:`, event)
return relay.publish(event)
})
}
const value: NostrContextType = {
debug,
isLoading,
connectedRelays,
publish,
onConnect: (_onConnectCallback?: OnConnectFunc) => {
if (_onConnectCallback) {
onConnectCallback = _onConnectCallback
}
},
onDisconnect: (_onDisconnectCallback?: OnDisconnectFunc) => {
if (_onDisconnectCallback) {
onDisconnectCallback = _onDisconnectCallback
}
},
}
return <NostrContext.Provider value={value}>{children}</NostrContext.Provider>
}
export function useNostr() {
return useContext(NostrContext)
}

21
client/src/utils/utils.ts Normal file
View File

@ -0,0 +1,21 @@
export const uniqBy = <T>(arr: T[], key: keyof T): T[] => {
return Object.values(
arr.reduce(
(map, item) => ({
...map,
[`${item[key]}`]: item,
}),
{},
),
)
}
export const uniqValues = (value: string, index: number, self: string[]) => {
return self.indexOf(value) === index
}
export const dateToUnix = (_date?: Date) => {
const date = _date || new Date()
return Math.floor(date.getTime() / 1000)
}