mirror of
https://github.com/fiatjaf/nak.git
synced 2024-11-22 16:19:07 -05:00
dynamically adding relay hints to nip19 codes.
This commit is contained in:
parent
b6207ae104
commit
d912a28987
|
@ -22,7 +22,7 @@ object Components {
|
||||||
entry("canonical hex", bytes32.toHex),
|
entry("canonical hex", bytes32.toHex),
|
||||||
"if this is a public key:",
|
"if this is a public key:",
|
||||||
div(
|
div(
|
||||||
cls := "pl-2 mb-2",
|
cls := "mt-2 pl-2 mb-2",
|
||||||
entry(
|
entry(
|
||||||
"npub",
|
"npub",
|
||||||
NIP19.encode(XOnlyPublicKey(bytes32))
|
NIP19.encode(XOnlyPublicKey(bytes32))
|
||||||
|
@ -66,14 +66,13 @@ object Components {
|
||||||
)
|
)
|
||||||
|
|
||||||
def renderEventPointer(
|
def renderEventPointer(
|
||||||
|
store: Store,
|
||||||
evp: snow.EventPointer
|
evp: snow.EventPointer
|
||||||
): Resource[IO, HtmlDivElement[IO]] =
|
): Resource[IO, HtmlDivElement[IO]] =
|
||||||
div(
|
div(
|
||||||
cls := "text-md",
|
cls := "text-md",
|
||||||
entry("event id (hex)", evp.id),
|
entry("event id (hex)", evp.id),
|
||||||
if evp.relays.size > 0 then
|
relayHints(store, evp.relays),
|
||||||
Some(entry("relay hints", evp.relays.reduce((a, b) => s"$a, $b")))
|
|
||||||
else None,
|
|
||||||
evp.author.map { pk =>
|
evp.author.map { pk =>
|
||||||
entry("author hint (pubkey hex)", pk.value.toHex)
|
entry("author hint (pubkey hex)", pk.value.toHex)
|
||||||
},
|
},
|
||||||
|
@ -82,6 +81,7 @@ object Components {
|
||||||
)
|
)
|
||||||
|
|
||||||
def renderProfilePointer(
|
def renderProfilePointer(
|
||||||
|
store: Store,
|
||||||
pp: snow.ProfilePointer,
|
pp: snow.ProfilePointer,
|
||||||
sk: Option[PrivateKey] = None
|
sk: Option[PrivateKey] = None
|
||||||
): Resource[IO, HtmlDivElement[IO]] =
|
): Resource[IO, HtmlDivElement[IO]] =
|
||||||
|
@ -90,14 +90,13 @@ object Components {
|
||||||
sk.map { k => entry("private key (hex)", k.value.toHex) },
|
sk.map { k => entry("private key (hex)", k.value.toHex) },
|
||||||
sk.map { k => entry("nsec", NIP19.encode(k)) },
|
sk.map { k => entry("nsec", NIP19.encode(k)) },
|
||||||
entry("public key (hex)", pp.pubkey.value.toHex),
|
entry("public key (hex)", pp.pubkey.value.toHex),
|
||||||
if pp.relays.size > 0 then
|
relayHints(store, pp.relays),
|
||||||
Some(entry("relay hints", pp.relays.reduce((a, b) => s"$a, $b")))
|
|
||||||
else None,
|
|
||||||
entry("npub", NIP19.encode(pp.pubkey)),
|
entry("npub", NIP19.encode(pp.pubkey)),
|
||||||
nip19_21("nprofile", NIP19.encode(pp))
|
nip19_21("nprofile", NIP19.encode(pp))
|
||||||
)
|
)
|
||||||
|
|
||||||
def renderAddressPointer(
|
def renderAddressPointer(
|
||||||
|
store: Store,
|
||||||
addr: snow.AddressPointer
|
addr: snow.AddressPointer
|
||||||
): Resource[IO, HtmlDivElement[IO]] =
|
): Resource[IO, HtmlDivElement[IO]] =
|
||||||
div(
|
div(
|
||||||
|
@ -105,15 +104,13 @@ object Components {
|
||||||
entry("author (pubkey hex)", addr.author.value.toHex),
|
entry("author (pubkey hex)", addr.author.value.toHex),
|
||||||
entry("identifier", addr.d),
|
entry("identifier", addr.d),
|
||||||
entry("kind", addr.kind.toString),
|
entry("kind", addr.kind.toString),
|
||||||
if addr.relays.size > 0 then
|
relayHints(store, addr.relays),
|
||||||
Some(entry("relay hints", addr.relays.reduce((a, b) => s"$a, $b")))
|
|
||||||
else None,
|
|
||||||
nip19_21("naddr", NIP19.encode(addr))
|
nip19_21("naddr", NIP19.encode(addr))
|
||||||
)
|
)
|
||||||
|
|
||||||
def renderEvent(
|
def renderEvent(
|
||||||
event: Event,
|
store: Store,
|
||||||
store: Store
|
event: Event
|
||||||
): Resource[IO, HtmlDivElement[IO]] =
|
): Resource[IO, HtmlDivElement[IO]] =
|
||||||
div(
|
div(
|
||||||
cls := "text-md",
|
cls := "text-md",
|
||||||
|
@ -239,5 +236,49 @@ object Components {
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private def relayHints(
|
||||||
|
store: Store,
|
||||||
|
relays: List[String]
|
||||||
|
): Resource[IO, HtmlDivElement[IO]] =
|
||||||
|
SignallingRef[IO].of(false).toResource.flatMap { active =>
|
||||||
|
val value =
|
||||||
|
if relays.size > 0 then relays.reduce((a, b) => s"$a, $b") else ""
|
||||||
|
|
||||||
|
div(
|
||||||
|
cls := "flex items-center space-x-3",
|
||||||
|
span(cls := "font-bold", "relay hints "),
|
||||||
|
span(Styles.mono, cls := "max-w-xl", value),
|
||||||
|
active.map {
|
||||||
|
case true =>
|
||||||
|
div(
|
||||||
|
input.withSelf { self =>
|
||||||
|
(
|
||||||
|
onKeyPress --> (_.foreach(evt =>
|
||||||
|
evt.key match {
|
||||||
|
case "Enter" =>
|
||||||
|
self.value.get.flatMap(url =>
|
||||||
|
if url.startsWith("wss://") || url.startsWith("ws://")
|
||||||
|
then
|
||||||
|
store.input.update(
|
||||||
|
_.trim() ++ " + " ++ url
|
||||||
|
) >> active.set(false)
|
||||||
|
else IO.unit
|
||||||
|
)
|
||||||
|
case _ => IO.unit
|
||||||
|
}
|
||||||
|
))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
case false =>
|
||||||
|
button(
|
||||||
|
Styles.buttonSmall,
|
||||||
|
"add relay hint",
|
||||||
|
onClick --> (_.foreach(_ => active.set(true)))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private val external = img(cls := "inline w-4 ml-2", src := "ext.svg")
|
private val external = img(cls := "inline w-4 ml-2", src := "ext.svg")
|
||||||
}
|
}
|
||||||
|
|
|
@ -111,15 +111,16 @@ object Main extends IOWebApp {
|
||||||
store.result.map {
|
store.result.map {
|
||||||
case Left(msg) => div(msg)
|
case Left(msg) => div(msg)
|
||||||
case Right(bytes: ByteVector32) => render32Bytes(bytes)
|
case Right(bytes: ByteVector32) => render32Bytes(bytes)
|
||||||
case Right(event: Event) => renderEvent(event, store)
|
case Right(event: Event) => renderEvent(store, event)
|
||||||
case Right(pp: ProfilePointer) => renderProfilePointer(pp)
|
case Right(pp: ProfilePointer) => renderProfilePointer(store, pp)
|
||||||
case Right(evp: EventPointer) => renderEventPointer(evp)
|
case Right(evp: EventPointer) => renderEventPointer(store, evp)
|
||||||
case Right(sk: PrivateKey) =>
|
case Right(sk: PrivateKey) =>
|
||||||
renderProfilePointer(
|
renderProfilePointer(
|
||||||
|
store,
|
||||||
ProfilePointer(pubkey = sk.publicKey.xonly),
|
ProfilePointer(pubkey = sk.publicKey.xonly),
|
||||||
Some(sk)
|
Some(sk)
|
||||||
)
|
)
|
||||||
case Right(addr: AddressPointer) => renderAddressPointer(addr)
|
case Right(addr: AddressPointer) => renderAddressPointer(store, addr)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,31 +12,48 @@ type Result = Either[
|
||||||
]
|
]
|
||||||
|
|
||||||
object Parser {
|
object Parser {
|
||||||
def parseInput(input: String): Result = if input == "" then Left("")
|
val additions = raw" *\+ *".r
|
||||||
else
|
|
||||||
ByteVector
|
def parseInput(input: String): Result =
|
||||||
.fromHex(input)
|
if input == "" then Left("")
|
||||||
.flatMap(b => Try(Right(ByteVector32(b))).toOption)
|
else {
|
||||||
.getOrElse(
|
val spl = additions.split(input)
|
||||||
NIP19.decode(input) match {
|
val result = ByteVector
|
||||||
case Right(pp: ProfilePointer) => Right(pp)
|
.fromHex(spl.head)
|
||||||
case Right(evp: EventPointer) => Right(evp)
|
.flatMap(b => Try(Right(ByteVector32(b))).toOption)
|
||||||
case Right(sk: PrivateKey) => Right(sk)
|
.getOrElse(
|
||||||
case Right(addr: AddressPointer) => Right(addr)
|
NIP19.decode(spl.head) match {
|
||||||
case Left(_) =>
|
case Right(pp: ProfilePointer) => Right(pp)
|
||||||
parse(input) match {
|
case Right(evp: EventPointer) => Right(evp)
|
||||||
case Left(err: io.circe.ParsingFailure) =>
|
case Right(sk: PrivateKey) => Right(sk)
|
||||||
Left("not valid JSON or NIP-19 code")
|
case Right(addr: AddressPointer) => Right(addr)
|
||||||
case Right(json) =>
|
case Left(_) =>
|
||||||
json
|
parse(input) match {
|
||||||
.as[Event]
|
case Left(err: io.circe.ParsingFailure) =>
|
||||||
.leftMap { err =>
|
Left("not valid JSON or NIP-19 code")
|
||||||
err.pathToRootString match {
|
case Right(json) =>
|
||||||
case None => s"decoding ${err.pathToRootString}"
|
json
|
||||||
case Some(path) => s"field $path is missing or wrong"
|
.as[Event]
|
||||||
|
.leftMap { err =>
|
||||||
|
err.pathToRootString match {
|
||||||
|
case None => s"decoding ${err.pathToRootString}"
|
||||||
|
case Some(path) => s"field $path is missing or wrong"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
)
|
||||||
)
|
|
||||||
|
val extraRelays = spl
|
||||||
|
.drop(1)
|
||||||
|
.toList
|
||||||
|
.filter(e => e.startsWith("wss://") || e.startsWith("ws://"))
|
||||||
|
|
||||||
|
result.map {
|
||||||
|
case a: AddressPointer => a.copy(relays = a.relays ::: extraRelays)
|
||||||
|
case p: ProfilePointer => p.copy(relays = p.relays ::: extraRelays)
|
||||||
|
case e: EventPointer => e.copy(relays = e.relays ::: extraRelays)
|
||||||
|
case r => r
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user