Archive for 2024

Mi investigación sobre cómo se programa un feed de Bluesky

jueves, noviembre 28th, 2024

Esto no es un sustituto para la «maravillosa» experiencia que resulta de leer la documentación oficial de ATProto y Bluesky, solamente quiero dejar anotado lo que he aprendido para poder revisarlo en el futuro


¿Cómo sabe Bluesky cuál es el algoritmo que proporciona la inteligencia de un feed?

Bueno, la respuesta parece ser que un feed de Bluesky no es más que un servicio HTTP con el que Bluesky interactúa usando la API RPC con los endpoints definidos en el protocolo ATProto.

Entonces, «crear» un feed es exponer a través de un servicio web esos endpoints y prepararlos para que Bluesky pueda lanzarle peticiones cuando una persona consulta el feed.


¿Y cómo sabe Bluesky cuál es el servicio web que debe usar?

Cuando «creas» un feed, es decir, cuando lo haces público para que salga en tu perfil y para que «exista» para Bluesky, hay que darle un parámetro que codifica el hostname. De modo que cuando alguien intenta consultar tu feed, Bluesky usa el hostname para saber a qué servidor hacer las peticiones HTTP que devuelven los datos del feed y así «usar tu algoritmo».

Ejemplo: el feed Linux está creado por @mackuba.eu. El DID de esta cuenta es did:plc:oio4hkxaop4ao4wz2pp3f4cr. Si uso el endpoint RPC com.atproto.repo.listRecords para pedirle todos los app.bsky.feed.generator creados por esta cuenta, el array JSON incluye el feed Linux.

Petición RPC al endpoint com.atproto.repo.listRecords en el PDS bsky.social
https://bsky.social/xrpc/com.atproto.repo.listRecords?repo=did:plc:oio4hkxaop4ao4wz2pp3f4cr&collection=app.bsky.feed.generator

El campo did de este record tiene como valor did:web:blue.mackuba.eu. Eso significa que el feed está asociado con el hostname blue.mackuba.eu y que cuando quieras consultar el feed Linux, Bluesky le tiene que tirar las peticiones a https://blue.mackuba.eu.

La API de un feed

Leyendo la documentación del generador que he consultado, un servicio web que sirva feeds de Bluesky debe implementar tres métodos:

  • /.well-known/did.json: este tiene que validar que, efectivamente, ese servicio web es el correcto, para evitar impersonaciones.
  • /xrpc/app.bsky.feed.describeFeedGenerator: este es el que devuelve información de los feeds que se sirven desde ese servicio.
  • /xrpc/app.bsky.feed.getFeedSkeleton: este es el que devuelve el contenido del feed, para que los posts se puedan ver. Va paginado.

ericvolp12/go-bsky-feed-generator es un generador de feeds hecho por @jaz.bsky.social que está programado en Go. De aquí es de donde he sacado esta información. Todavía no lo he clonado para ver si es tan sencillo como tomar la plantilla, programar los algoritmos, y dejar que el proyecto levante el servidor web.

did.json

El endpoint de DID parece confirmar que estamos en la ubicación correcta. Imagino que validar el feed quiere decir verificar que no estás usando otro hostname diferente o que alguien se ha equivocado al poner la URL del servidor. No tengo ni idea del contexto de este endpoint.

Petición al endpoint did.json de blue.mackuba.eu.
https://blue.mackuba.eu/.well-known/did.json

app.bsky.feed.describeFeedGenerator

El endpoint app.bsky.feed.describeFeedGenerator devuelve la lista de feeds servidos desde ese servicio web. La documentación con los tipos del objeto devuelto están en la API de Bluesky.

Petición RPC al endpoint app.bsky.feed.describeFeedGenerator de blue.mackuba.eu.
https://blue.mackuba.eu/xrpc/app.bsky.feed.describeFeedGenerator

app.bsky.feed.getFeedSkeleton

El endpoint app.bsky.feed.getFeedSkeleton es el que devuelve los datos de un feed. Si le pido sin más que me hable, da un error HTTP 500, aunque supongo que esto depende del servidor.

Petición RPC al endpoint app.bsky.feed.getFeedSkeleton de blue.mackuba.eu.
https://blue.mackuba.eu/xrpc/app.bsky.feed.getFeedSkeleton

Eso es porque según la documentación de ese endpoint, le tengo que poner como queryparam feed para indicarle el record del feed que quiero que me devuelva. El feed tiene que estar en formato URL de protocolo ATProto, es decir, at://[did]/app.bsky.feed.generator/[slug], que para el feed «Linux» es at://did:plc:oio4hkxaop4ao4wz2pp3f4cr/app.bsky.feed.generator/linux, siendo el DID de la cuenta de mackuba. En cuanto hago eso, el feed empieza a hablar.

Petición RPC al endpoint app.bsky.feed.getFeedSkeleton de blue.mackuba.eu con un feed como parámetro.
https://blue.mackuba.eu/xrpc/app.bsky.feed.getFeedSkeleton?feed=at://did:plc:oio4hkxaop4ao4wz2pp3f4cr/app.bsky.feed.generator/linux

El formato de un feed tiene el siguiente tipo (voy a usar una interfaz de TypeScript por simplicidad):

interface Feed {
  cursor: string;
  feed: Array<{
    post: string;
  }>;
}

Uno de los campos de retorno es cursor, que es el que permite paginar el feed. Es un paginador un poco complejo porque como el feed se puede actualizar en tiempo real a medida que se va paginando si se agregan o se borran posts, se recomienda que lleve también un timestamp para asegurarse que se sincroniza bien.

El otro es feed, que devuelve un array de objetos con los IDs de cada post. El feed no porta el contenido de los posts, solamente sus IDs externos. Tú devuelves la URL en protocolo ATProto de un post, y ya se ocupa Bluesky de recuperar por separado el contenido de cada post a partir de la propia API del PDS.

Voy a hacer la prueba tratando de resolver desde el PDS https://bsky.social uno de los posts del feed, en este caso, at://did:plc:gxt7mot2ujgovitv6j4eo7n4/app.bsky.feed.post/3lbyn6inlds22. Puedo sacarlo mediante el endpoint RPC app.bsky.feed.getPosts. Como este endpoint requiere autenticación, voy a usar https://public.api.bsky.app, que permite acceso anónimo, para no tener que aprender ahora a crear tokens.

Petición RPC a app.bsky.feed.getPosts para este endpoint y este PDS.
https://public.api.bsky.app/xrpc/app.bsky.feed.getPosts?uris=at://did:plc:gxt7mot2ujgovitv6j4eo7n4/app.bsky.feed.post/3lbyn6inlds22

Estrategias para fabricar un algoritmo

Si quiero programar un feed estático, puedo devolver hardcodeado el array con las URLs ATProto de los posts que quiero que porte. Sin embargo, imagino que la gracia está en prestar atención a JetStream o al firehose de Bluesky directamente, que es el websocket que te trae en tiempo real los posts a medida que se publican. Para mirar a la cara a este websocket sin usar comandos de consola se pueden usar las siguientes herramientas web:

Cuando encuentre un post en el websocket que concuerde con el criterio de mi algoritmo, puedo anotar su ID para poder devolverlo más adelante cuando se pidan datos del feed. Se recomienda también descartar los posts más antiguos para no devolver un feed muy grande.

Siguientes puntos

La siguiente pregunta que me queda por hacer es cómo funciona la autenticación, porque algunos feeds son anónimos ya que solo tienen que devolver datos del firehose público. Sin embargo, si quiero filtrar para que muestre información relacionada con mi cuenta (por ejemplo, posts de la gente que sigo o posts de la gente que me sigue), supongo que el feed necesita una forma de saber quién soy. Esto es algo que dejo para investigar otro día.

Mastodon me tumba el blog

lunes, octubre 28th, 2024

Mastodon puede causar un DDoS, pero no lo hace con mala intención.

He vuelto a cometer el error de publicar una entrada de blog usando una etiqueta demasiado genérica. Al minuto de hacer eso, mi blog ha empezado a fallar, y el access.log se ha llenado de tráfico procedente de instancias de Mastodon.

NGINX recibiendo un DDoS de Mastodon
(más…)

Impresiones rápidas sobre TikTok, ahora en primera persona

lunes, octubre 28th, 2024

Normalmente he criticado y despreciado a TikTok en tercera persona, únicamente en base a lo que he leído por ahí. Sin embargo, hace poco abrí una cuenta para makigas, donde estoy dándole una segunda vida a los shorts que cargo en YouTube una vez que empiezan a decaer, o para intentar crear imagen de marca más allá a ver si cae algún suscriptor nuevo.

En cualquier caso, en estas semanas he podido fijarme en cómo funciona en primera persona, usándola yo mismo, y estas son mis impresiones de lo que he visto hasta el momento.

(más…)

Modelos experimentales de microblog

viernes, octubre 25th, 2024

Últimamente le ando dando vueltas a la idea de si la forma en la que se mantienen los blogs de notas es la óptima. Me refiero a cuando publicas en tu blog o en tu propia web un mensaje de texto corto y plano que cabría perfectamente en un tweet, pero que publicas en tu blog para poseer el control de él y no regalárselo a un multimillonario cabrón. (También me vale en un post de Mastodon o en un skeet de Bluesky).

(más…)

10-10-2024

jueves, octubre 10th, 2024

Me cuesta hacer que el contraste del tema que uso en mi blog se vea bien en modo oscuro.

El problema es que los temas de WordPress twenty-pico modernos ya pasan del soporte para microformatos y yo preferiría mantener esa función para poner cosas cortas.

La caída de Discord

lunes, octubre 7th, 2024

Por alguna razón estoy diciendo esto en todas partes menos en mi propia guild de Discord. Ahí dentro la gente es feliz e inocente sin saber que básicamente a finales de agosto decidí dejar de darle recursos al servidor y dejar de preocuparme por su falta de uso. Está clasificado como obsoleto, y aunque no lo voy a borrar, no me voy a preocupar ya tanto de si faltan canales, o si la gente lo está descubriendo bien.

En los últimos dos años, la interacción en el servidor de Discord de makigas había caído completamente. De ser una plaza de pueblo activa donde la gente hacía preguntas, o compartía cosas de su día, a ser un lugar vacío donde muy de vez en cuando alguien pregunta algo y donde cada vez se comparten menos cosas. Evidentemente, no puedo forzar a la gente a utilizarlo, pero sí puedo al menos entender las razones por las que ha caído en popularidad.

(más…)

Por qué no uso IA para la mayor parte del proceso de producción de makigas.es

lunes, septiembre 30th, 2024

Sé que este post no va a contentar a los tech-bros, pero me permite desahogarme. Además, es un buen punto al que poder citar en el futuro si surge esta pregunta y no tengo ganas de repetirme.

Sería técnicamente incorrecto decir que no uso IA en mi canal de YouTube y en makigas.es, ya que hay al menos dos instancias en las que uso IA. Por eso este post está dividido en dos partes. Primero diré las partes en las que utilizo IA en makigas.es, y las partes en las que no me planteo usar IA a pesar de que sé que son las más tediosas y las que más tiempo me toman.

(más…)

El widget de cabeceras HTTP por fin está hecho

miércoles, abril 10th, 2024

Como dicen que una imagen vale más que mil palabras, os quiero enseñar una cosa.

Efectivamente, el widget de cabeceras HTTP por fin está programado, lo que significa que por fin se puede completar toda la información necesaria para tirar una petición HTTP mínima con Cartero. Dejad que os cuente cómo funciona por dentro.

(más…)

Qué ha pasado estos días en Cartero

miércoles, abril 3rd, 2024

Me disculpen que no haya anotado por aquí lo que ha pasado en Cartero en los últimos días. Estuve un poco de vacaciones. Pero bueno, este es un resumen de lo que se ha incorporado al repositorio y ha pasado en el streaming en los últimos días.

  • El viernes en stream se empezó a implementar el cliente HTTP como tal. He decidido utilizar la biblioteca isahc. No tengo ninguna preferencia ni odio reqwest. Sin embargo, me parecía más idiomática y además me parecía buena idea probar cosas nuevas para experimentar. (Reqwest la tengo más tocada.)
  • Entró un pull request de @claufedacosta que arregla la interfaz de usuario. Estoy muy contento con este cambio y muy agradecido. Pone la barra de URL donde estaba antes, para que no sea difícil mover la ventana, y además la hace responsiva, o sea que si ahora la ventana se hace más estrecha, se apilan las partes de la aplicación una encima de la otra.
  • Anoche empecé a trabajar en el soporte para Flatpak y metí un manifest básico que por el momento funciona y compila la aplicación. He agregado comandos al README para explicar cómo generar este Flatpak con las herramientas de desarrollo instaladas.

Y esto sería todo, mucha calma. Dejo un patallazo de cómo está la aplicación en este momento.

Un pantallazo de cómo se está viendo en este momento la aplicación.

Compilación en Windows

viernes, marzo 29th, 2024
Un pantallazo de Cartero ejecutandose en Windows.

No es bonito el proceso todavía, pero compila en Windows. He utilizado rustup-init.exe y la toolchain stable-x86_64-pc-windows-gnu y estoy instalando las bibliotecas de GTK a través de MSYS2. La gracia está en que un usuario de Windows pueda simplemente descargar y ejecutar, para hacerlo atractivo como alternativa. Sobre que el ejecutable pese 124 MB, supongo que habrá que hacerse preguntas algún día.