This graph shows how many times the word ______ has been mentioned throughout the history of the program.
Hola, ¿qué tal? Soy Batman.
No soy Batman, soy...
Bueno, muchas gracias por estar ahí.
Ahora me va a dar por la voz de Batman.
No lo había hecho en tres años y ahora de repente vamos a estar con la voz de Batman.
Bueno, hoy vamos a estar codeando, vamos a estar programando desde cero una aplicación en tiempo real.
¿Qué quiero decir esto?
Pues lo que vas a aprender hoy te serviría para hacer un videojuego multijugador,
un chat, notificaciones, un montón de cosas.
Es que hoy vas a aprender una cosa, una tecnología, que no sabe casi nadie porque de esto no habla ni Dios,
pero aquí vas a aprenderlo y de verdad te juro que si no te sorprende te devuelvo el dinero.
Si no te sorprende lo que te voy a enseñar hoy, te juro que te voy y te devuelvo el dinero.
Que te ha gastado una sub, te la devuelvo.
Porque es que a mí me parece, os lo juro, increíble, increíble, tal cual.
¿Por qué?
Porque es que es tan potente, algo que normalmente es tan difícil de hacer.
Y os voy a poner un ejemplo para que veáis.
Amigos, fijaos en esta página web.
Esta página web se actualiza en tiempo real cada vez que alguien entra.
Cuando uno de ustedes entra, vais a ver aquí que pone última visita desde...
Pues aquí vais entrando a esta página web y vais viendo que estamos viendo a la gente que nos está siguiendo.
Última visita desde Zalapa, tenemos a gente de Perú, de La Plata, de Argentina, de Encarnación, Paraguay,
de Bolivia, de Montevideo, de Valencia, de España.
Estos son ustedes en tiempo real.
En tiempo real estamos en una página web, estamos mostrando de dónde viene la última visita.
Y esto es increíble, ¿cómo lo vamos a hacer?
Porque vamos a hacer el frontend, vamos a hacer el backend, vamos a ver cómo tenemos que hacer en tiempo real,
vamos a ver la parte de base de datos, vamos a desplegar la base de datos.
O sea, y lo vamos a ver, lo vamos a hacer en un momento.
Lo vamos a hacer en un momento.
Y de verdad, el cómo es de sencillo, cómo lo vamos a hacer paso a paso, está muy chulo, ¿vale?
Esta idea, esta idea de mostrar la última visita, lo he sacado de la página de Rauno, ¿vale?
Rauno.me, que si no me equivoco trabaja en Vercel, que es un verdadero salvaje, o sea, es increíble.
La página web que tiene el porfolio es brutal.
Ves que pone aquí, last visit from Ludwigsburg, Germany.
Pero, ¿qué pasa?
Que lo que tiene Rauno, que está muy chulo, el tema es que no se actualiza en tiempo real.
Si vosotros entráis, pues aquí la última visita que aparece aquí no se actualiza en tiempo real.
Tienes que refrescar y entonces te aparece otra nueva visita, ¿no?
Así todo el rato.
Pero nosotros lo vamos a llevar a otro nivel.
Porque nosotros lo que vamos a hacer es que se actualice en tiempo real.
O sea, que en tiempo real vaya apareciendo la gente que se está conectando y aparezca su ciudad y su país.
Y esto, si vosotros entráis en esta página web, además también vais a ver que también veis vosotros.
Vais a poder ver perfectamente cómo se actualiza en tiempo real.
Esto es lo que vamos a hacer.
No sirve, no sale yo.
A ver, pensad que si se conectan demasiadas personas, que seguro que os estáis conectando un montón, no sale todo el mundo.
¿Por qué?
Porque ya veréis que he hecho un sistema para que no se vuelva loco y que sí que se vaya actualizando, pero solo con un orden, ¿vale?
Para que si no aparecería, ¿sabes? No veríamos nada porque empezaría ta, ta, ta, ta, ta, ta.
Lo he hecho con un sistema muy sencillo, pero muy guapo.
Como diría el Shokas, con un sistema muy guapo.
Entonces, si sirve, a mí me salió hasta la localidad donde vivo.
Bueno, una cosa que hay que tener en cuenta es que hay veces que no aparece exactamente vuestro pueblo, ¿vale?
Porque por tema de privacidad, con la IP se puede saber mucha información, pero no tanta.
Entonces, es muy chulo.
Esto lo vamos a hacer, lo vamos a desplegar y lo vais a entender.
Y para hacer todo esto, vamos a partir de la base de una cosa que es que no sé cómo expresar.
Hay veces, os lo digo en serio, hay veces que estoy tan feliz y tan apasionado por lo que hago,
que no sé cómo transmitirlo, porque es que me parece tan increíble que no sé cómo expresar en palabras
para que la gente realmente entienda cómo es increíble esto.
Pero bueno, es que a veces, sí, estoy muy hipeado, pero porque de verdad me parece brutal.
Os voy a explicar un poquito el contexto, ¿vale?
Dino, para el que no lo sepa, es una alternativa de Node, ¿ok?
Y bueno, es del creador de Node.
Crearon Dino.
Bueno, no os voy a explicar todo lo que es Dino y tal y tal,
pero lo que sí que voy a comentar es una alternativa a Node que tiene como cosas interesantes,
seguro por defecto, utilizas TypeScript de forma nativa,
que te trae el linting, el testing, te trae un montón de cosas ya por defecto,
pero lo bueno, además, es que están sacando como servicios alrededor de Dino, ¿no?
Una base de datos, un despliegue, un montón de cosas.
Y entre las bases de datos sacaron esta, Dino Key Value.
¿Qué es lo que hace esto?
Pues tú esto, lo único que haces es que puedes guardar una llave y un valor como un objeto, ¿no?
Pues Key Value, ya está.
Pero esta base de datos, que puede parecer una tontería, es súper potente,
porque resulta que el otro día anunciaron esto, el comando Watch.
¿Qué quiere decir esto?
Lo que podemos hacer ahora es observar cuando cambian los valores de la base de datos.
Esto es espectacular, ¿vale?
¿Por qué? Porque esto lo que nos permite es crear aplicaciones en tiempo real de una forma increíblemente sencilla.
Lo que estamos haciendo aquí es que vamos a poder hacer un Watch de forma que,
cuando se cambia un valor de la base de datos, poder tener un aviso, ¿vale?
O sea, tremendo, tremendo.
Y muy fácil.
O sea, es increíblemente fácil, ¿veis?
Aquí le hacemos un Watch y le decimos, vale, quiero que veas esta Key de aquí, con esta Key de aquí, ¿vale?
Estos son, en realidad las Keys están establecidas, esto lo veremos después, por elementos de un Array, ¿vale?
Entonces, aquí lo que podríamos decir es, quiero observar estas Keys de aquí y me haces un Stream.
Y entonces, conforme cada vez que me llega uno nuevo, ¿vale?
Pues hago un ForAwait y ya tengo cada una de las nuevas.
No os preocupéis que esto lo voy a explicar paso a paso porque vamos a necesitar entenderlo, ¿ok?
Esto, que alguien me dirá, ¿pero esto solo tiene Dino?
Bueno, esto es lo más increíble.
Y es que lo vais a poder utilizar también con Node.
Lo que vais a aprender hoy lo podéis utilizar con Node.
Porque la gente de Dino ha sacado el paquete y se llama Dino Key Value.
Lo ha publicado hace cinco días y lo podéis utilizar perfectamente con Node.js.
La API es un poquito más complicada porque, ¿veis?
Tenéis que conectar con la base de datos y tal.
Esto, si lo desplegáis con Dino Deploy, no necesitáis hacerlo.
Pero funcionar funciona.
Y tendríais la misma API incluso con el Watch y con todo, ¿vale?
O sea, que también funcionaría con Node.
Lo vamos a hacer con Dino por temas de que lo vamos a desplegar en Dino Deploy totalmente gratis y tal.
Pero que sepáis que lo que vais a aprender lo podríais utilizar en Node.
¿Y para qué serviría esto?
Esto sirve para hacer lo que te dé la gana en tiempo real.
Un chat, notificaciones, un juego multijugador.
Que lo haremos.
Haremos un juego multijugador y un proyecto secreto.
Vamos a hacer un proyecto secreto en comunidad con todo lo que vamos a aprender hoy.
Así que no te pierdas nada de hoy si quieres contribuir al proyecto de código abierto que vamos a hacer, que va a ser muy chulo.
Primero vamos a crear, vamos a crear aquí un Dino, no, Dino no, ¿cómo le llamamos?
Bueno, Last Time Visit, ¿vale?
Lo que vamos a crear es esta página de aquí.
Esta página en la que cada vez que alguien entra, pues en tiempo real vemos aquí y vemos la nueva visita, ¿ok?
Esta página está hecha con frontend, con backend, ¿ves?
Alguien sabe de Estados Unidos, de Francia, de Medellín, de donde sea, ¿no?
Bueno, pues esto lo vamos a hacer y esto está hecho en tiempo real.
Es muy interesante porque vas a ver que esto no está haciendo ninguna petición, ¿ves?
Yo no estoy haciendo ninguna petición y no para esto de actualizarse.
¿Cómo está funcionando esto?
Pues aquí es donde está el truco, en este.
Aquí tenemos un stream de datos que cada vez que alguien se conecta, se está cambiando en la base de datos esta información
y cuando cambian la información en la base de datos, nosotros tenemos el uso del watch este para informar y hacer un stream de estos datos.
Entonces esto lo vamos a ver desde cero cómo funciona, ¿vale?
No os preocupéis.
Pero por ahora lo más importante es que necesito que entiendas cómo funciona el key value.
Así que vamos a hacer una cosa aquí rápida.
Vamos a hacer un demo.ts.
Antes de hacer el demo.ts este, ¿por qué?
¿Por qué?
A ver, ¿cómo se hacía?
Dino init.
A ver, ¿dino init?
¿Init?
Es que no me acuerdo cómo se iniciaba un proyecto.
Dino init.
Init project.
Eso.
Vamos a inicializar un proyecto de eso.
Dino init, ¿vale?
Dino init.
Sabía que era Dino init.
Vale.
Tengo que ver la versión de Dino porque necesitamos la última.
¿Ok?
1.33.
Brave.
A great Dino porque creo que no es la última.
Vale.
Voy a actualizar mientras la versión de Dino.
Tarda unos segundos.
Me ha petado.
Me ha petado.
¿Por qué?
¿Por qué me ha petado?
¿Qué ha pasado?
A ver.
Dino version.
No parece que haya petado.
Ah, pues sí.
Dino.
¿Cuál es la última versión de Dino?
¿Cuál es la última versión de Dino?
Dino.dino.com.
¿Cuál es la última versión de Dino?
A ver si ahora la 3.8.
Pues sí, la hemos liado.
A ver.
¿Qué es lo que?
Brino clean up.
Dino not install.
Vale.
Disable deep behavior.
Vale.
Tenemos que hacer un clean up.
Vale.
Tengo que hacer esto.
No, no pasa nada.
¿Qué término usas?
Utilizo Warp.
Pues buen stream, Midu.
Nos vemos mañana.
No, hombre, joder.
Si estamos empezando.
Genera muchos costes con todos nosotros entrando.
Si es que eso es lo mejor, que es que es gratis.
Porque resulta que la gente de Dino, y ahora os lo voy a enseñar,
la gente de Dino, ajá, Brino install Dino, ¿vale?
La gente de Dino tiene un servicio que se llama Dino Deploy.
Este servicio es un servicio de hosting que, si veráis el pricing,
es absurdamente gratis.
A ver, tiene un servicio de pago por 20 dólares al mes,
pero fijaos, el free tiene un millón de peticiones al mes.
100 gigas de bandwidth.
O sea, que vamos sobraos.
Incluso si lo superásemos, es que al final solo serían 20 dólares
y escala bastante bien.
O sea, que está bastante increíble.
Así que no nos preocupemos.
Bueno, ahora está instalando ahora sí la versión de Dino.
No sé por qué me instala PHP.
Luego la gente se queja de instalar dependencias en Node.
Pero aquí, muchas veces, uno se vuelve loco de la de cosas que instala.
Tú quieres instalar Dino y se puede instalar cosas muy raras.
Que si PHP, que si no sé qué.
Dices, pero esto para qué lo necesito.
No lo necesito para nada, ¿eh?
Entonces, honestamente, Midu, necesito saber,
¿es rentable aprender Dino?
Mira, ¿por qué sí que creo que es rentable aprender Dino?
Dino, lo bueno que tiene es que todo lo que,
muchas de las cosas que vas a aprender son de la plataforma web.
Eso es una cosa muy buena que tiene Dino.
Que se ha basado mucho en la plataforma web.
Por lo tanto, ¿es por qué específicamente van a utilizar Dino las empresas?
A ver, yo creo que cada vez más lo van a utilizar.
O sea, sí que creo que cada vez más lo van a utilizar.
Pero no solo es por eso.
Lo digo sobre todo porque mi sensación...
Oye, no sé por qué no me está actualizando.
No me está actualizando Dino.
No me está actualizando Dino.
Cago en la leche.
¿Ves? Me dice 1.8, no sé qué, no sé cuánto.
Pero aquí me está utilizando otra versión.
¿Por qué?
¿Por qué esta versión?
¿Por qué me está instalando esta versión?
¿Por qué me está instalando esta versión?
A ver, install Dino.
A ver, porque me imagino que lo he instalado de otra forma, ¿no?
No, no sé.
Puede ser que lo haya instalado de otra forma.
Es que no lo haya instalado con Briwo en su día,
que lo haya instalado con otro.
Puede ser.
A ver, ahora sí.
Vale, el tema es que lo había instalado con esto
en lugar de utilizarlo con Homebrew.
Si necesitáis instalar Dino,
tenéis aquí las instrucciones en MacOS, Windows y Linux.
Yo pensaba que lo había hecho con Homebrew,
que en MacOS es de lo más típico,
pero no, resulta que lo había hecho así.
Bueno, ahora sí.
Ya tenemos...
Aquí tengo la versión correcta de Dino, ¿vale?
La 1.38, Dino version.
1.38.5, ¿vale?
Ya tenemos la última versión.
Esto sí que es importante para que podamos seguirlo todo.
Hacemos el Dino init, ¿vale?
Hemos inicializado nuestro proyecto.
Levantamos aquí el Visual Studio Code.
Aquí nos ha dejado un montón de cositas.
Por ejemplo, Dino JSON, Dino, Dino...
Aquí como diferentes cosas.
No vamos a necesitar nada de esto, la verdad.
Yo lo que pensaba es que nos iba a activar al menos la...
Nos iba a instalar aquí.
Se le puede poner un BiscodeExtensions.json
y pensaba, que no ha hecho,
pensaba que nos iba a poner la de Dino,
pero no lo ha hecho.
Entonces voy a ponerlo aquí para que básicamente tengamos esto
y el Settings.json.
Y así la gente...
¿Vale?
Vamos a poner Dino, Dino, Dino, Dino.
Vale.
Dino enable true.
Ok.
Y así vamos a activar la extensión de Dino.
Vamos a la extensión aquí de Visual Studio Code.
Súper importante que activéis la extensión de Dino
porque si no vais a tener un montón de problemas de linter y tal.
Por ejemplo, fijaos que yo ahora la tengo desactivada
y aquí si miramos ya console.log y ponemos aquí demo, ¿vale?
Que es donde vamos a empezar.
Si ponemos tal, pues ahora mismo no se queja.
No tiene ninguna cosa.
Pero si activamos esto, lo activamos para el workspace, ¿vale?
Bueno, veo que todavía...
Ah, porque aquí no he puesto lo del DinoLint.
Seguramente, ¿no?
A ver ahora.
Bueno, pues tampoco lo está pillando.
A ver ahora.
Tampoco.
No sé si es que no ha activado la extensión.
Debería activarse la extensión, Dino.
Deberíamos tener aquí linter.
A ver.
Bueno, a ver.
Const A, hola.
Debería activarse el linter y no me lo está activando.
Ah, bueno.
Aquí sí que pone...
No, pero esto...
Ah, sí, sí, sí.
¿Veis que sí que está...?
Ah, es que no tiene linter de los puntos y coma.
O sea, le da igual los puntos y coma.
Vaya tela.
Vaya tela.
Igual es que tiene DinoFormat también o algo, ¿no?
DinoFormat...
A ver.
Dino...
No sé si tendrá algún formato y tal.
Pero sí, sí, es eso, ¿eh?
Que los puntos y coma no lo está mirando.
La madre que lo parió.
Pensaba que sí que lo miraba, pero ya veo que no.
Que le daba igual.
Vale.
Entonces, vamos a iniciar con el tema de la demo, ¿vale?
Para que veamos cómo funciona lo del key value.
Primero, para empezar con una base de datos,
haríamos una database, una constante.
Y aquí ya deberíamos utilizar Dino.openkv.
Pero, vale.
Aquí ya empezamos con el primer problema, ¿no?
Porque OpenKV, ves que te dice que no existe porque todavía no está estable.
Y es que es verdad que si miramos esto de DinoKeyValue,
si vais aquí a DinoKeyValue, vais a ver que está en beta.
Y entonces, por eso vais a ver que todavía no está activado.
Pero para activar esto, podéis ir a DinoUnstable, aquí, ¿vale?
Le dais True y entonces ya se deja de quejar.
Ya entiende que estás utilizando Dino de forma no estable.
Aunque es muy pronto, van a pasarlo ya a producción.
O sea, lo van a poner estable.
Así que lo que estás aprendiendo te va a servir y no creo que haya muchos cambios.
Entonces, con esto ya abriríamos nuestra primera base de datos.
Fíjate que no hemos tenido que hacer nada,
no hemos tenido que abrir un servicio en algún sitio.
No, esto ya funciona así.
Y cuando lo despleguemos, automáticamente creará la base de datos, ¿vale?
Y ya la replicará y tal.
No tienes que configurar absolutamente nada, ¿eh?
O sea, no te preocupes.
Mira, vamos a crear aquí, imagínate, un usuario.
Y ya podríamos guardar en nuestra base de datos, pues, por ejemplo, el usuario.
Podríamos decir que el username es, en este caso, user.
Ahora, esto tendríamos el resultado que nos diría si se ha guardado o no se ha guardado.
Y luego podríamos recuperar el resultado haciendo una wait del get del username.
Y aquí tendríamos toda la información.
Entonces, vamos a ver lo que devuelve estas dos cosas, ¿vale?
Y lo comentamos.
Mirad, lo que estoy haciendo aquí es guardar esta información en la base de datos con la key username.
Fíjate que para crear las keys en Dino Key Value es un poco raro porque se hace con un array.
No es como normalmente se hace con un string.
Se hace con un array.
Y tú aquí le puedes poner tantos elementos, por ejemplo, name, midudev, no sé qué.
Y eso sería la key, la mezcla de todos los elementos.
O sea, el hecho de conjugar todos esos elementos.
Lo cual lo hace mucho más interesante que tener que crear tú la cadena de texto que puede tener bastantes errores.
Y por temas de seguridad también te pueden intentar atacar justamente porque hay veces que utilizas esto, ¿no?
Para separar los prefijos y la gente te puede intentar atacar por ahí.
Pero bueno, para que lo sepáis, esto es como funcionaría.
Ahora, tendríamos que ejecutar nuestra demo y lo normal es que la gente diga, vale, dino demo.ts.
¿Qué pasa?
Ah, no, dino run, perdona, dino run demo.ts.
Así es como ejecutaríamos este archivo.
Vale, lo que parece es que nos dice que open key value is not a function.
Vale, nos dice que no es una función porque, como hemos dicho, esto no es estable.
Así que tendríamos que ponerle unstable demo.ts.
No sé si se pone al revés o se pone así.
Vale, se pone así.
Vale, ya veis que ahora sí que funciona.
Entonces, que sepáis que tenéis que decir unstable porque todavía está en beta.
Pero ahora fijaos que me dice que este ok sería de esta línea 5 y la línea 8 me estaría ya devolviendo esto.
Y ojo que aquí viene lo interesante.
O sea, ya hemos guardado en nuestra base de datos un nombre de usuario y ya lo estamos recuperando.
Si yo ahora quito este código y lo vuelvo a ejecutar, fíjate que ya tiene guardado que en la key username el valor es midudev.
Y también tenemos un version stamp.
Y esto es muy importante que lo tengáis muy claro porque el version stamp lo que quiere decir es que ese campo se actualizó por última vez cuando diga el version stamp.
Esto es muy importante porque imagínate que quieres hacer un juego multijugador.
O quieres hacer un chat y quieres saber cuál es la última vez que se ha actualizado ese campo, pero tienes dos informaciones que no sabes cuál de las dos es la correcta.
Utilizando el version stamp, ahí puedes comparar y decir, vale, entre estos dos que tienen la misma información, uno de los dos tiene que ser más nuevo que el otro.
Lo voy a ver con el version stamp, ¿vale?
O sea que súper importante.
Pero fijaos, no he hecho nada y ya me está guardando en una base de datos la información.
¿Dónde está guardando esto?
Es la pregunta.
Vale, el local, obviamente, el local, esto lo está guardando en un archivo local, en uno de nuestro sistema operativo.
Seguramente, pues dentro de esta carpeta de Dino, no sé qué, no sé cuánto, pues aquí tendrá, lo está guardando en vuestro corazón, programador 420.
Bueno, seguramente lo estará guardando en algún sitio, en un archivo y todo esto.
Pero la cosa es que cuando estamos en producción, lo guarda automáticamente por nosotros, sin tener que hacer nada, lo guarda en FoundationDB, que esto es un servicio normalmente que es de pago, ¿vale?
Que es bastante interesante porque escala muy bien y que puedes tener más de, o sea, tiene un rendimiento buenísimo, que está preparado para producción, que es open source.
Está utilizando esto.
Y tú no te tienes que preocupar, ¿vale?
Vas a ver que no vamos a configurar nada, ¿eh?
Ya está, esto es todo lo que vamos a tener que hacer para que lo veáis.
O sea, no vais a tener que configurar.
Es que no tienes, me dice, coronel, ¿dónde configuro la base de datos?
Es que no la configuras.
No la configuras, te lo juro.
Lo vas a ver.
No voy a configurar absolutamente nada y os va a volar la cabeza porque esto que he hecho es todo lo que vamos a hacer de configuración.
No vamos a configurar nada.
Esto lo dejamos exactamente así.
Entonces, ya veis que tanto el set como el get funciona correctamente, ¿vale?
Entonces, el típico ejemplo podríamos tener el de un contador.
Os voy a poner este.
Esto sea un contador.
Os voy a explicar una cosa importante de los contadores.
Aquí lo que estaríamos haciendo es guardar en contador el cero y luego recuperaríamos el contador y hacemos un console.log.
Para ver el contador.
¿Qué podéis guardar?
Podéis guardar, por ejemplo, podéis guardar números.
Podéis guardar boleanos.
Podéis guardar, es que hay un montón de tipos de datos que podéis guardar.
Podéis guardar, tengo la lista por aquí.
Podéis guardar undefined, null, bolean, number, string, big, int, arrays, objects, maps, sets, fechas, regex y uno especial que lo vamos a ver ahora que es este de aquí, ¿vale?
Que sería un valor, un entero que no tiene signo de 64 bits y que es bastante interesante.
Ya veréis por qué, ¿vale?
Pero lo importante es que se pueden guardar un montón de valores y que no tiene ningún problema.
Entonces, esto sería un contador con un número, pero para los números normalmente nos gustaría hacerlo de otra forma.
Porque imaginad que aquí queremos incrementar el counter, que esto lo vamos a ver después y lo vamos a ver mejor, pero para que nos hagamos una idea, ¿no?
Aquí queremos incrementar el counter cada vez que alguien viene y dice, ah, pues me ha gustado esto que he visto.
Bueno, pues tal.
Muy bien.
¿Qué es lo que vamos a hacer?
Pues claro, necesitaríamos primero, imagina que voy a olvidar que voy a hacer el set.
Primero debería recuperar el counter inicial porque debería saber cuál es el valor inicial.
Entonces, aquí podemos extraer el value, que en este caso será cero.
Ahora que tengo el value, pues digo, vale, el nuevo contador, si el value es null porque no está inicializado, lo inicializaríamos en cero y si no, hacemos un value más uno, ¿no?
Aquí lo tendríamos.
Claro, aquí se me queja porque me dice, el operador no puede ser aplicado a tal y a número.
Esto es porque aquí en el get no sabe exactamente qué es lo que va a tener el value.
Esto es un tema de TypeScript porque veis que pone unknown.
Entonces, vosotros le podéis decir aquí cuál es el tipo que va a pillar.
En este caso, el que va a recuperar es un number y ahora sí que sabe que el value es number o null.
Entonces, si es null, lo inicializamos en cero y si no, value más uno.
Y ahora ya, pues podemos poner el result y hacemos esto.
Entonces, ya lo estaríamos incrementando.
Ahora, cada vez que lo llamemos, ¿vale?
Pues ya lo estaríamos incrementando.
Bueno, en este caso, ah, porque este es el result.
Esto no es, perdón, ese no tiene value.
Entonces, ahora, cada vez que llamemos esto, deberíamos ver, bueno, claro, me sale el ok true, ok true,
pero si aquí pongo el valor, vamos a poner con solo de valor porque lo que estamos viendo es el resultado, ¿vale?
Dos, tres, cuatro, ¿veis?
Ya estamos incrementando.
Perfecto.
Entonces, hasta aquí, bien, pero se debería hacer de otra forma más correcta.
¿Por qué?
Y esto es importante que te va, ya, y esto es lo más difícil que vas a ver hoy, ¿eh?
Esto es lo más difícil que vas a ver hoy.
A partir de aquí, ya va para abajo.
Vais a ver por qué.
El await, ¿para qué era?
Porque esto devuelve promesas, ¿vale?
Como esto es un método que es asíncrono, tenemos que esperar a que termine.
Estamos esperando y cuando termina, entonces recuperamos el valor.
Entonces, ahora os voy a explicar lo que va a ser más difícil y a partir de ahí vamos para abajo.
Y hacemos el frontend y tal y no os preocupéis, que es que lo tengo que explicar porque es importante,
pero a partir de aquí ya para abajo.
Y es que, vale, imaginad que queremos hacer lo de las visitas, ¿vale?
Imaginad que queremos hacer el tema de las visitas.
Y lo que queremos es que cada vez que alguien nos visite, vamos a tener aquí una key que se llama visits,
vamos a hacerlo con el número.
Pero como hemos visto es un poco rollo el counter, ¿no?
Porque el más uno, más uno, tenemos que recuperar el valor para leerlo, para no sé qué.
Para eso, lo que vamos a hacer es recuperar el valor que te comentaba que era un poco especial,
el del key value U64 este.
Y le decimos que empiece con cero.
Pero la N, esto es algo de JavaScript.
El cero N es de BigInt.
Es un formato que lo que te permite en JavaScript, ¿vale?
Que por eso os digo que es muy interesante a veces aprender Dino porque tiene estas cosas que dices,
ostras, es que no se ve.
Pero BigInt es un tipo de datos que funciona y que existe en JavaScript.
Y lo que te permite es básicamente, es un primitivo que te permite tener números, pues, bastante grandes.
Y aquí tenéis, ¿no?
¿Por qué?
Porque si no pierden precisión.
Es un problema que tiene JavaScript que los enteros que conocemos al final llega un momento que pierden precisión.
Si vosotros intentáis sumar, por ejemplo, si vosotros decís, voy a sumar el tru-tru-tru-tru-tru-tru más uno, ¿vale?
A veces os podéis llevar sorpresas, ¿vale?
Sorpresas que no esperabais.
Porque, por ejemplo, esto sería 894 más uno debería terminar en 895.
Y fijaos lo que pasa aquí.
7, 8, 3 y luego ya está perdiendo precisión al final.
Lo que está pasando es que pierde precisión.
Esto con los números grandes ocurre.
Pero, claro, si lo hacemos con las n estas, ¿veis?
Aquí sí que tenéis el resultado que esperabais.
No sé si esto no lo sabíais, pero la verdad es que es bastante interesante en el mundo de JavaScript tener en cuenta esto, ¿vale?
Porque las sumas grandes en JavaScript no son precisas.
Tiene un límite.
Para hacerlas precisas necesitáis BigInt, ¿ok?
¿Cuál es la aplicación que usa para hacer código de JavaScript en tiempo real?
Ranges.
Muy bien.
Entonces, por eso utilizamos aquí el BigInt, ¿ok?
Entonces, aquí vamos a setear como inicializar nuestro campo, ¿vale?
Y lo que podemos hacer ahora es, ojo con esto, incrementar el número, ¿vale?
Podríamos incrementar el número.
Pero, de hecho, esto nos lo podríamos saltar directamente y decirle directamente que queremos hacer una operación atómica,
que ahora te explicaré lo que es.
Y queremos incrementarlo en uno.
Así que le decimos que a las visitas vamos a incrementar en uno n, ¿vale?
Lo incrementamos en uno.
Esto, bueno, lo voy a setear primero para que tengamos el estilo, o sea, el valor del Dino Key Value correcto.
Y luego lo incrementamos.
Y luego le hacemos un commit.
¿Qué quiere decir esto?
Esta línea es muy importante y la vamos a ver después, pero eso tiene mucho que ver con las bases de datos.
Y te voy a explicar.
Y esto, con esto ya veréis que esto es lo más difícil, pero lo vas a entender fácil y a partir de aquí ya vamos para abajo.
Esto es como que hemos subido arriba y ya bajamos.
Una operación atómica es para asegurarnos que tenemos una consistencia de datos.
Porque en un multijugador, imagínate, ahora vas a entender cómo funcionan los multijugadores, los chats y todo esto.
Imagínate que tú tienes un juego multijugador y alguien aquí hace un movimiento, le dispara y lo matas,
pero el otro, que se supone que estaba muerto, dispara y mata al otro.
Entonces, para asegurarnos que en tiempo real en multijugador las operaciones siguen un orden,
lo que hacemos son operaciones atómicas.
Nos aseguramos que realmente cada una de esas operaciones ha terminado para que tenga un orden.
Por ejemplo, si este ha matado a este, este ya no podrá matar a este porque está muerto.
Tenemos que asegurarnos que lo que ha ocurrido primero termine y aunque sea asíncrono, tenga una consistencia.
¿Por qué?
Porque imagínate aquí en una base de datos.
Si dos personas modifican, incrementan el valor, si el valor que había era uno
y dos personas a la vez intentan incrementar el valor leyéndolo, ¿qué va a pasar?
¿Debería ser tres?
No.
El problema que vamos a tener es que puede ser que como uno incrementa a partir de uno
y el otro incrementa a partir de uno, aunque los dos están incrementando, el valor final sea dos.
Y necesitamos que la operación sea atómica.
¿Qué quiere decir eso?
Que ya sea por timestamp o lo que sea, es que sepamos identificar quién ha incrementado primero
y quién ha incrementado después y asegurarnos que sigue un orden para que al final de todas las operaciones
el número final sea tres porque se ha incrementado dos veces.
Esto es cuando hablamos de operaciones atómicas.
Nos estamos refiriendo al hecho de tener una operación,
nos aseguramos que ha terminado todas esas operaciones antes de poder proseguir, ¿vale?
Porque si no, vamos a tener un montón de condiciones de carrera por todos los sitios
donde vamos a tener un montón de inconsistencia de datos.
Y a veces, no siempre, pero a veces es interesante, ¿vale?
Entonces, aquí lo que estamos haciendo es justamente esto.
Es decir, vale, vamos a hacer una transacción atómica
y las transacciones es que queremos sumar las visitas en 1N.
Por lo tanto, vamos a esperar a cualquier otra transacción que haya habido
para asegurarnos que estamos incrementando correctamente el valor.
Y luego, vamos, aquí podemos hacer tantas como queramos.
Aquí podríais añadir más, ¿vale?
Tantas operaciones como queráis.
Y luego lo que hacemos es comitear, como decir, vale, y ahora sí que la hacemos, ¿ok?
Entonces, terminado esto, ahora ya deberíamos tener el resultado aquí.
Haríamos un get de visits.
Aquí le podemos decir que lo que esperamos es el dino keyvalue U64
y ya tendríamos aquí el resultado, result.value, ¿vale?
Entonces, si esto lo ejecutamos, ¿vale?
Tenemos 1N, 1N y tenemos 1N todo el rato.
¿Por qué tenemos 1N todo el rato?
Ah, coño, la he liado aquí, obvio.
La he liado porque estoy seteándolo arriba.
Claro, lo quería setear una vez y ya está.
Vale, ya está, ¿vale?
Gracias, ¿eh?
Vale, pues ya está.
¿Veis?
Ahora se está incrementando y tal.
Lo bueno de esto es que aunque vosotros lo estuvierais incrementando
en un montón de sitios a la vez, ¿vale?
Aunque lo estéis incrementando a la vez, no habría,
no se estaría chocando.
Y tú me dirás, pero amigo, ¿por qué me estás explicando esto?
¿Cómo te crees que funciona esto?
Claro, si yo mientras alguien envía la última visita,
intenta, claro, lo que estamos haciendo aquí es asegurarnos
que estamos haciendo un cambio atómico, ¿vale?
De que vamos a esperar que se ha guardado
y luego añadimos el siguiente, añadimos el siguiente, añadimos el siguiente.
Y así lo estamos haciendo en tiempo real de forma ordenada, ¿ok?
Entonces, esto es todo lo que necesitas saber para el tema de Dino Key Value.
Por supuesto, podéis guardar objetos, podéis guardar arrays,
podéis guardar un montón de cosas.
Una cosa interesante, mira, os voy a enseñar esta demo
de hacer un set de un objeto, ¿vale?
¡Pum!
Para que lo veáis.
Esto, tenemos aquí un objeto de preferencias,
aquí tengo a Facundo Capua y también tengo aquí el de Midudev.
Pues mira, vamos a añadir el de Facundo y vamos a añadir Midudev preferencias, ¿vale?
Que sería, vamos a poner user, Midudev y tal.
Esto, por ahora, lo vamos a quitar.
Vamos a hacer dos sets aquí para setear, para que lo veamos.
Y así os explicaré otro método que es bastante importante, ¿vale?
Esto no puede... Ah, aquí he puesto mal el const.
Const, ¿vale?
Entonces, aquí tenemos la Facundo Preferences, ¿vale?
Entonces, guardamos aquí en Facundo las preferencias.
Procede a entrar épicamente y lanzar para uno de los mejores creadores de contenido.
Midulove, Midulove, saludos de Argentina.
Gracias, Majo.
Y saludos desde España a los argentinos.
Mira, tenemos aquí dos objetos, ¿no?
Uno para Facundo, otro para Midu y lo guardamos.
Y fijaos cómo hago aquí.
Aquí tendríamos parte de la Key y luego la otra parte.
Preferencias de Facundo, las preferencias de Midudev.
¿Veis cómo se crean las keys?
Entonces, ahí hacemos los sets.
Vamos a ejecutarlo, ¿vale?
Hacemos los dos sets.
Ya se han guardado.
Ya podríamos comentar esto y ya lo deberíamos tener en la base de datos, ¿vale?
Entonces, si yo ahora hago de este console.log y lo miro, ¿vale?
¿Veis?
Ya tengo la información de Midudev tiene este objeto
y las preferencias de Facundo ya tiene todo este objeto.
Y fijaos, los dos tienen su versión stamp y tal.
Pero es importante una cosa.
No hace falta que hagas un get siempre a mano de cada uno.
Porque lo que puedes hacer es utilizar otra cosita que se llama esto.
Muy bien.
No, el promisor no.
Esto no.
No hagáis esto.
¿Por qué esto está mal?
Esto está mal.
Está mal porque esto lo que va a hacer es consumir dos peticiones.
Si nos vamos al precio, al pricing, ¿vale?
Vais a ver por aquí en algún sitio que habla del tema de las peticiones, ¿no?
Lecturas y todo esto.
Claro, lo que queremos es evitar que nos suba el pricing.
Así que lo que queremos hacer no es esto.
Lo que queremos hacer es utilizar una sola lectura a la vez.
Y le vamos a decir await db.getMany.
Y en el many le vamos a pasar un array y le vamos a decir, vale, queremos las preferencias de Facundo y las de Midudev.
Y así, con una sola lectura, conseguimos dos campos, ¿vale?
Esto es bastante importante para que justamente podamos optimizar todo nuestro código y nuestro proyecto.
¿Ok?
Así que ya tendríamos esto.
Perfecto.
Otra cosa que podéis hacer, solo para que lo sepáis porque también es interesante, podemos tener un db.list y decirle el prefijo de los campos que tenemos.
Por ejemplo, preferencias, ¿vale?
Y aquí podremos hacer console.log.entries.
Lo que vais a ver, ¿vale?
Que esto nos da un iterador.
Así que tenemos que utilizar un for await porque el iterador es asíncrono.
Así que cada entrada tendríamos que tener las entradas.
Y ahora sí, hacemos un console.log.entry, pero ojo, con el await, ¿vale?
Y ahora sí, tendríamos aquí todas las keys que empiezan por preferencias, ¿vale?
Ya las podemos listar.
Y finalmente, por supuesto, pues también podéis eliminar lo que sea.
Preferencia Facundo, si eliminamos esto, ¿vale?
Le damos una vez y ahora si le doy otra vez, solo va a aparecer la de Midudev porque hemos eliminado la nuestra, ¿vale?
Importante, acordaos que hay que hacer un await si queréis esperar que termine la operación porque es asíncrona.
Ya está.
Ha terminado el aquí value, ¿vale?
Con esto, con todo esto que ya sabemos, solo nos falta una cosa.
Pero con todo esto que sabemos, ya vamos a ser capaces de crear nuestra aplicación.
Con todo esto que sabemos, ¿vale?
¿Es un estilo ready?
Sí, es que es muy, muy parecido.
¿Cómo funciona el for await?
Pues justamente el for await lo que funciona es que cualquier cosa que sea iterable, como en este caso entries, que es un iterador, lo que hace es ir llamando al punto next cada vez.
Lo que pasa es que cada next es asíncrono y como es asíncrono, tienes que esperarlo.
Por eso funciona for await, porque tienes que esperar, porque el entries es un iterador que es asíncrono.
Así que ahí lo tendrías, ¿no?
Esto es JavaScript.
Por eso os digo que está muy chulo aprender Dino porque vais a aprender un montón de cosas que son de JavaScript y que a lo mejor no veis de otra forma.
Esto es todo lo que necesitamos con el tema de la base de datos, ¿vale?
El DB y tal.
Así que ya nos podemos olvidar de esto.
Nos podemos olvidar de esto y vamos a crear ya nuestra aplicación.
Vamos a crear aquí un index.html.
Vamos a poner aquí holamundo.h1.
Aquí tendremos un script, ¿vale?
Lo vamos a hacer con Vanilla, ¿vale?
Importante, lo vamos a hacer todo con Vanilla.
Vanilla JavaScript.
O sea, no vamos a necesitar ningún framework, no vamos a hacer nada especial.
O sea, va a ser todo con Vanilla.
Vamos a tener que crear el servidor.
Para crear el servidor, una cosa que podemos utilizar, seguro que conoces Express.
Y si no lo conoces, te lo digo, ¿vale?
Express de Node.
Es un framework.
Bueno, hay gente que dice que no es un framework, pero es un framework.
Lo pone hasta en la...
¿Ves?
Web framework.
Y sirve para crear, pues, aplicaciones web, APIs y un montón de cosas.
Express ha sido muy famoso durante mucho tiempo.
Pero existe una alternativa mucho más moderna, que funciona en un montón de nuevos,
nuevos runtimes como Van, como Dino.
En Node también funciona, en Cloudflare, que se llama Hono, que está súper chulo, que
yo recomiendo mucho que utilicéis, que a mí personalmente me gusta un montón y que
además tenéis la posibilidad de utilizarlo con Dino.
Si buscáis Dino, pues, vais a ver aquí que tenéis cómo instalar, ¿no?
Pues, podéis crear desde cero una aplicación de Dino y tal.
Y, ¿veis?
Ya os pone aquí cómo lo tenéis que hacer y todo esto.
Bueno, pues, vamos a copiarnos esto para crear nuestro Hello World.
Lo chulo que tiene Dino, o no chulo, o sea, que está bien o que no está bien, eso depende
de cada uno, es que no necesitáis instalar las dependencias con un package JSON.
Directamente podéis hacer un import de la URL.
Y esto, aunque vuelva locos y locas, esto es algo nativo también de JavaScript, ¿vale?
Dijiste que sería Vanilla sin frameworks.
Bueno, a ver, primero, lo dije para el index HTML, que esto es Vanilla.
La parte del cliente la vamos a hacer Vanilla, sin React ni nada.
En la parte del servidor, Vanilla no existe como tal, porque ya estaríamos utilizando Dino.
Pero, igualmente, la única dependencia que vamos a utilizar es Jono.
O sea, que la única dependencia que vamos a utilizar es Jono.
No vamos a utilizar ninguna otra dependencia.
Tampoco me parece tanto, la verdad.
Pero, bueno, es que si no, hacerlo a mano es un poco rollo.
Hacer un servidor web a mano.
Entonces, como hemos visto en la documentación, vamos a hacer el Hello World en un momento,
¿vale?
Que lo hacemos así, con import Jono de esta URL.
Esto que veis, en realidad, esto de traer de una URL, esto es puro JavaScript,
porque estos son los Xmascrid Modules.
¿Veis que tenemos este error y que no entiende qué es esta C?
Esto es porque le tenemos que decir, esto es una cosa que me da bastante rabia de Dino,
que no lo hace automáticamente.
Igual hay alguna opción, ¿vale?
Pero hay que, veis que pone Uncache or Missing Remote URL, ¿vale?
Pues le dais a Quick Fix y aquí le decís Cache, no sé qué, no sé cuánto y sus dependencias.
Y ahora lo que va a hacer es descargarse las dependencias, ¿vale?
Ahora, aquí veis que también se queja de que estás utilizando la última versión,
pero no lo estás poniendo.
Esto normalmente es una mala práctica, porque pensad que si lo dejáis así,
siempre va a tirar de la última versión y esto tiene bastante peligro.
Entonces, lo que deberíamos decir es, actualiza y especifica cuál es la versión que quieres utilizar.
Y ahora sí, tenemos la versión, perfectamente, ¿vale?
Luego vamos a necesitar también importar de aquí, de esta URL,
vamos a necesitar también, no exactamente esta URL,
pero del middleware, middleware.ts, tenemos que importar el serve static, ¿vale?
Para justamente servir nuestro HTML, que si no, no lo va a ver nadie.
Así que hacemos app.get, ¿vale?
App.get, app.get, index.html y aquí le decimos serve static,
le ponemos que el path es, no me acuerdo si es el path o, a ver,
no me ponen las opciones, no.
Pues yo creo que path es barra index.html.
Ahora vamos a ver si funciona un momento, ¿vale?
Nos dice lo mismo, que esto no está cacheado, ¿vale?
Y, vale, sí, es path, ¿vale?
Entonces le decimos, cuando recuperes el index.html,
bueno, de hecho, no hace falta hacer esto, ¿eh?
Yo he hecho lo en index.html, pero esto no tiene sentido.
Tiene sentido hacerlo aquí, claro.
Tiene sentido hacerlo aquí, directamente, en la barra,
que tiene mucho más sentido, ¿vale?
Entonces, lo que hacemos es crear la aplicación de Jono.
Cuando vamos a la slash, le servimos el html
y servimos esta aplicación directamente en app.fetch
y esto lo hacemos con dino.serve.
Con esto ya tendríamos nuestro servidor
y aquí crearemos la API y todo esto.
Hacemos dino run app.ts.
Pero ojo con dino, porque aquí tiene una cosa muy importante.
Si vamos a poner unstable,
porque también vamos a utilizar los key value aquí.
Pero imagínate, le das aquí y fíjate que esto está muy chulo de dino,
porque por defecto te pide permisos.
No le hemos dicho qué permisos tiene que utilizar y fíjate,
dino quiere acceso a internet para el puerto no sé qué.
¿Quieres ejecutar esto otra vez,
pero utilizando el allow.net no sé qué?
Y entonces le tienes que decir sí, ¿vale?
Y fíjate que me va a pasar otra vez,
porque si intento entrar, se me queda esto penchado
y es que me dice,
dino me está pidiendo acceso para leer el archivo index.html.
Bueno, esto está muy chulo porque justamente dino
tiene un sistema de permisos que tú, si lo controlas,
lo que puedes decir es decir,
yo sé que necesito el acceso a internet y tal.
Pues lo que hacéis es aquí,
le ponéis los flags que queráis,
allow, ahora no me acuerdo que era file,
creo que allow file, no sé si todos,
no me acuerdo ahora que, no, no es allow file,
no me acuerdo cómo era, allow file.
Ah, bueno, ahora me lo va a pedir otra vez.
A ver, me lo va a pedir otra vez.
A ver, ¿cómo era?
Allow read, vale.
Ya está, es lo que necesitamos, solo lectura.
Allow read, ¿vale?
Le damos permisos de lectura.
Y ahora, si vamos aquí, ves,
ahora sí que está funcionando porque tiene permiso de lectura.
Y tú dirás, menuda cosa.
Bueno, esto está bastante, bastante genial
y es una cosa que va a añadir Node, ¿vale?
Para que lo sepáis.
Node va a tener un permission system,
que es una cosa que hace mucho tiempo que no teníamos.
¿Ves?
Ya está la API disponible para que veáis, ¿eh?
Esto os estáis enterando aquí en exclusiva.
A partir de Node 21, bueno, ya en Node 20 ya había,
todavía está en experimental,
pero Node va a tener también un sistema de permisos
donde vais a tener que poner, por ejemplo,
vais a poder tener un archivo policy.json
para tener todas las políticas que tenéis.
de decir, vale, pues tienes acceso a estos recursos,
a estas cosas, no sé qué.
¿Ves qué dependencias puede utilizar?
Esto puede parecer una tontería,
pero seguro que sabéis un montón de historias
de gente que ha instalado una dependencia mala de Node.js
y le ha vaciado la cartera de bitcoins y cosas así.
Y esto lo podéis buscar porque es verdad.
O se ha puesto a minar.
Pues este tipo de cosas lo que buscan es mejorar los permisos,
¿vale?
Para que lo sepáis.
Y también, pues, que puedas escribir a un archivo,
que solo puedas leer archivos,
porque ahora mismo puedes hacer un RMRF con Node.js,
súper fácil, ¿ves?
Pues para tener sistema de archivos permisos.
O sea, Node se la ha copiado de Dino directamente.
Que me parece bien, ¿eh?
No lo digo como algo negativo, me parece fantástico.
Pero para que sepáis, porque a lo mejor alguien dice,
ay, qué pesado es Dino,
que me pregunta tantas cosas de permisos.
No, tiene sentido.
Y como podéis ver, Node también lo va a añadir,
porque es una cosa que al final estamos pidiendo.
Muy bien.
Entonces, ya tenemos nuestro primer servidor.
Tenemos el Hola Mundo,
pero hasta aquí no vamos a ir, obviamente.
Vamos a llevarlo al siguiente nivel.
Porque vamos a hacer aquí,
vamos a hacer ya nuestra,
vamos a hacer nuestro streaming del contenido.
O sea, vamos a estar haciendo el streaming.
Vamos a hacer esta parte del streaming.
Para ello, primero voy a crear aquí un counter.
Y vamos a crear aquí el callback, ¿vale?
La C es de context, por si no sabías qué era esto, ¿eh?
Entonces, por ahora voy a hacer C.json con tercero.
Por ahora voy a hacer esto.
Imagínate que está nuestra API,
que vas aquí a barra counter.
No es nuestra API definitiva, ya os lo digo yo.
¿Ves?
Ay, barra counter.
Ah, interesante.
Vale, ¿veis que me dice not found cuando en realidad lo tengo aquí?
Es porque se me ha olvidado pasarle otro flag muy chulo
que también se copió en out, por suerte, que es el watch, ¿vale?
Para que reinicie automáticamente la API cuando tengamos un cambio.
Entonces, ahora, ahora sí, obviamente esto sí que va a funcionar.
Pero si le digo que devuelva 10, pues debería, ¿veis?
Se ha refrescado y ahora ya tengo el 10.
Perfecto.
Pues eso, el modo watch, que no se me olvide.
Bueno, esto no es lo que quiero.
Lo que vamos a hacer es un streaming de datos.
¿Qué quiere decir esto?
Vamos a hacer lo que se le llaman server site events.
Y esto es muy interesante.
Primero, esto funciona con Node, con Dino, con cualquier tecnología, ¿vale?
Y de lo que trata es que el servidor va a poder enviarle información al cliente.
El cliente se va a suscribir, ¿vale?
Va a decir, bueno, este es el source al que me suscribo
y cada vez que recibo un evento hago algo.
Y entonces el servidor deja una conexión abierta
en la que cada vez que tiene algo nuevo que decir se lo envía al cliente.
Y es súper genial.
No son WebSockets.
De hecho, esto es mucho más barato que los WebSockets
porque los WebSockets son bidireccionales.
Esto no es bidireccional.
Esto es unidireccional.
Esto va del servidor al cliente.
Pero es súper interesante porque muchas veces no necesitamos que sea bidireccional,
sino que simplemente el servidor le vaya informando al cliente
de lo que viene nuevo y ya está.
Y el cliente, por otra petición totalmente distinta,
sí que puede hacer cambios o lo que sea,
pero no desde la misma conexión.
¿Lo entendemos?
WebSockets bidireccional, cliente-servidor-servidor-cliente,
y server-site-events, lo que tenemos es unidireccional,
del servidor al cliente, ¿ok?
Muy bien.
Lo vamos a hacer.
¿Cómo lo vamos a hacer?
Aquí podríamos hacerlo de la forma súper complicada,
súper difícil,
pero, por suerte, Jono tiene también una forma de hacerlo sencillísimo.
Así que vamos a aprovecharnos, ¿vale?
Vamos aquí a helper, helper-streaming-index.ts
y aquí importamos la utilidad stream-sse, ¿ok?
Muy bien.
Vamos a cachear esto, esta URL, cache, y ya tenemos esto.
Esto lo que vamos a hacer es que en este counter
vamos a devolver la ejecución de esto,
le vamos a pasar el contexto de nuestra función,
y aquí necesitamos ir pasándole stream de datos, ¿vale?
¿Cómo vamos a hacer esto?
Pues ahora lo vamos a hacer fácil.
Vamos a hacer un loop infinito,
porque, total, lo que quiero es enviar datos todo el rato
y lo que quiero es que lo veas, ¿no?
Vamos a crear un mensaje que sean son last,
new date, local stream, solo para que veas la información, ¿vale?
Y aquí vamos a hacer, vamos a esperar que el stream
va a escribir un evento donde vamos a enviarle,
por un lado, los datos, que va a ser el mensaje,
el nombre del evento, que vamos a decirle update,
el que tú quieras.
De hecho, el nombre es importante y luego verás por qué.
Y vamos a poner la id, vamos a poner aquí i++, ¿vale?
Vamos a poner una i por aquí, solo para que veáis
que esto se va a ir cada dos por tres.
Claro, es que necesitamos transformar un stream, ¿vale?
Tengo que pasarle la id.
Y es una constante.
Ah, porque he puesto que esto sea tal.
Vale, ya está.
Entonces, por una parte tendríamos esto, ¿vale?
Y ahora lo que vamos a hacer es que el stream,
vamos a hacer que se duerma por un segundo.
Y así irá recuperando cada segundo una cosita nueva.
Como tenemos un loop infinito, esto está loopeando todo el rato,
pero el stream, como se espera aquí un segundo,
aquí esto va a tener como un delay de un segundo
antes de seguir en la siguiente iteración.
Entonces, cada segundo le vamos a enviar un poco de información
al cliente.
Esto que vemos aquí, ¿vale?
Esto del stream, el site events, esto es JavaScript, ¿vale?
Se llama ssevents, lo tenéis MDN, ¿vale?
Eventos enviados por el servidor.
Esto es totalmente de JavaScript, es bastante chulo,
está genial y te puede salvar la vida en un montón de cosas.
De hecho, hay un montón de servicios que lo utilizan
porque utilizarlo es muy fácil.
Lo podéis hacer con Node, con Dino, con lo que queráis.
Y, de hecho, nosotros lo hemos utilizado con algún servicio también,
lo hemos hecho alguna vez.
Creo que lo hicimos con ChatGPT para crear el streaming de los datos
en su día.
Hoy ya no es necesario porque Vercel tiene un SDK tan increíble
que es mucho más fácil, ¿vale?
Entonces, lo que estamos haciendo aquí lo vamos a ver ahora claramente.
¿Por qué?
Porque vamos a ir al HTML y aquí donde teníamos el script y tal,
voy a hacer una cosa.
Voy a crear un source que va a ser un event source.
Esto es JavaScript, ¿vale?
Y le vamos a decir que se suscriba al counter,
que es justamente este que hemos creado aquí, ¿vale?
Ahora, en este source, vamos a decirle, ¿vale?
Cuando el source, vamos a escuchar los eventos.
¿Qué evento vamos a escuchar?
El que le hemos dicho aquí, el de update.
Si tú aquí le llamas Pepito, ¿vale?
Pues aquí te tienes que suscribir a Pepito, a Pepito, ¿vale?
Pero nosotros lo vamos a utilizar update,
que es el que hemos utilizado antes.
Ponemos update.
Hay gente que le pone lo más típico que he visto es utilizar message,
¿vale?
Es como el más típico,
pero no es obligatorio utilizar message,
que no sé por qué la gente siempre pone message.
De hecho, tiene sentido que tengas diferente dependiendo de lo que haces.
Imagínate un juego multijugador.
Pues aquí pondrías, por ejemplo, player movement,
para saber si el jugador se ha movido.
O yo qué sé, score, para ir cambiando la puntuación.
O sea, sería tan fácil como esto y tener diferentes eventos para cada cosa.
Nosotros vamos a utilizar ahora mismo solo uno, el de update.
Y lo que vamos a hacer aquí es que tenemos aquí el evento
y cada vez que tenemos el evento, hacemos un console log.
Para verlo más visual, que va a quedar mejor si lo vemos visualmente
y notamos que está abriendo la consola y tal,
voy a recuperar el document getElementById.
Esto es vanilla JavaScript, ¿vale?
Vamos a traernos esto y vamos a crear document.createElementLi.
Creo un li y en el ul append child del li y en el innerHTML
vamos a traernos el event data.
¿El event data qué va a ser?
Pues lo que le estamos enviando aquí, el mensaje.
Y el mensaje que vamos a tener aquí es este de aquí, ¿vale?
Con esto ya tendríamos básicamente nuestro cliente,
aunque luego lo vamos a complicar un poco más.
Pero tendríamos la parte del servidor que está enviando datos
y la del cliente que se ha suscrito al contador
y cada vez que le llega un evento update se actualiza.
Vamos a ver si esto funciona, ¿vale?
Voy a refrescar porque...
Ah, ¿qué ha pasado?
La he liado, la he liado, la he liado parda.
Hostia, hostia, algo he hecho aquí,
algo he hecho aquí que la he liado parda.
Algo se me ha olvidado.
Algo se me ha olvidado aquí, te, te, te, te.
En el await true, el retur...
Algo...
No sé si se ha vuelto loco por algo que he hecho yo o...
Sí, algo he hecho yo mal aquí, ¿no?
Algo he hecho mal porque...
Fijaos que esto se está volviendo tonto.
¡Se está volviendo tonto!
¿Ves?
Se ha vuelto tonto.
A ver, vamos a hacer una cosa.
¿Qué se me ha olvidado?
¿Qué se me ha olvidado aquí?
Cada vez que recibe el update.
A ver, borraste el delay.
¿Borré el delay?
Hostia, borré el delay.
La madre que me parió.
¿Por qué borré el delay?
Gracias, gracias.
Sí, exacto.
El delay.
El delay es importante, ¿vale?
El delay es importante.
Ah, el delay no, es sleep, ¿no?
Sleep, vale.
Gracias, gracias.
Madre mía, con razón.
Digo, ¿pero qué está pasando?
Vale, ahora sí, ahora sí.
Vale.
Entonces, ¿veis?
Ahora aquí tenemos esto.
Update, son las no sé qué, son las no sé cuánto.
Esto está pasando cada segundo.
Ahora, lo interesante es que aquí...
Aquí, event data...
Event data, vale.
Event data...
Claro, es que le he puesto el mismo nombre que data.
Y es un poco raro.
Pero aquí es que el event data...
El event data es el que tiene toda la información.
Y como lo he llamado data también...
Mirad, a ver, en el console.log...
¿Este console.log de este evento?
¿Por qué no aparece este evento?
¿Sabéis que aquí este console.log?
¿Por qué este console.log no aparece?
¿Por qué no aparece ese console.log?
A ver, vamos por partes.
Uno, ¿qué es lo que está pasando?
¿Veis aquí la petición counter?
Aquí, ¿veis que tenemos aquí un event stream?
Pues este event stream es el que se está actualizando constantemente.
Mira, vamos aquí, ¿vale?
Ah, vale, es que estoy viendo...
No estaba viendo el HTML, la madre que me parió.
Estaba viendo el API.
Vale, fijaos.
Ahora sí que funciona correctamente, ¿vale?
Aquí tendríamos el console.log, ya decía yo.
Y aquí tendríamos que cada segundo se está actualizando.
Pero ¿veis que es exactamente cada segundo?
Lo más interesante es que esto le pasaría a todo el mundo.
Todo el mundo recuperaría esta información.
¿Y cómo está funcionando esto?
Pues aquí, ¿veis que tenemos aquí la petición del counter?
Si le damos, aquí tenemos el stream de los datos.
Y podemos ver cómo va llegando el tipo, ¿vale?
Tipo update, la ID, justamente, que tendríamos ahí.
Y los datos.
54, 55, 56, 57.
O sea, podemos ver que cada segundo se está actualizando.
Esto es súper importante a la hora de hacer que realmente
podamos hacer el streaming de los datos, ¿vale?
Que eso lo vamos a necesitar.
Así que, al menos ahora ya estamos haciéndolo cada segundo, ¿vale?
Cada segundo estamos haciendo esto, perfecto.
Pero nosotros queremos llegar a esto.
A esto de poder ver la última visita de nuestros usuarios.
Vale, entonces, al menos ya tenemos una forma
en la que vamos a poder enviar cada vez que alguien entre.
O sea, ¿hasta aquí todo bien?
¿Alguien tiene alguna duda?
Venga, que os leo, ¿eh?
¿Así funciona el stream de vídeo en plataformas como YouTube y Twitch?
No.
El streaming de vídeo se utiliza normalmente streaming de datos directamente,
no eventos de server.
Aunque hay server que se puede utilizar, ¿vale?
O sea, sí que se puede utilizar para enviar cierta información.
Pero el streaming de datos es una cosa totalmente diferente.
Acabo de llegar, lo repasamos en un minuto.
Vale, ahora lo hacemos.
¿Adiós Socket Ayo?
No, porque Socket Ayo y Server Events...
Server Events es muy antiguo, ¿eh?
Es una tecnología muy vieja, muy vieja.
Entonces, no es que sea nueva, sino que no se utiliza mucho, no es muy conocida, pero es súper potente.
Acabo de llegar, ¿de qué me perdí?
Pues mira, para la gente que ha llegado, queremos hacer esta página.
Esta página es una aplicación en tiempo real que detecta de dónde viene el último usuario
y cada vez que entra un usuario se ve aquí de qué ciudad viene, ¿ves?
Cada vez que entre alguien podremos ver, bueno, pues ha entrado alguien de la Llagosta, de España.
Ha entrado alguien de no sé quién.
Cada vez que alguien entra, se actualiza con su sitio, ¿no?
Tal vez no se usa Server Events por seguridad.
No, no se hace por eso.
O sea, de hecho, los Server Events sí que se utilizan en la vida real, ¿eh?
Y, ojo, el límite creo que son seis conexiones.
El límite de los Server Site Events, que además el límite no es nuestro, sino es del mismo usuario.
Y eso en HTTP2 no pasa, ¿eh?
O sea, que no hay ningún tipo de problema.
¿Qué diferencia tienen estos proyectos con el Minipixel?
Lo vamos a ver ahora, porque en Minipixel no hicimos el Watch.
Pero es bastante similar, solo que es un poco diferente lo que vamos a hacer.
Está bueno para cuando tienes un job y después que se ejecute y manda un evento que se guardó bien, por ejemplo.
Totalmente.
Y lo bueno es que esto lo podéis utilizar para hacer un juego multijugador súper fácil.
O sea, súper fácil.
¿Se puede utilizar React en Dino?
Sí.
Y, de hecho, tenéis un framework muy chulo de Dino que se llama Fresh,
que tiene Tailwind CSS, que utiliza Priak, que es algo muy parecido con React,
y que además tiene siglas, tiene un rendimiento muy parecido a Astro.
Está muy chulo y además puedes hacer APIs fácilmente.
Está genial, ¿eh?
La verdad es que está súper bien, ¿eh?
¿Cómo complementaría esto con Astro?
Pues puedes crear la API y puedes crear el...
Esto no deja de ser lo que hemos hecho aquí, JavaScript.
Esto lo puedes hacer con JavaScript en cualquier sitio.
Sea Astro, no sea Astro, lo que tú quieras.
Vale.
Entonces, hasta ahora os he dicho lo del número.
Pero vamos a hacer algo más increíble para acercarnos a nuestro objetivo.
Vamos a crear otro endpoint, ¿vale?
Que sea post barra counter, que cada vez que hagamos una petición aquí,
vamos a incrementar en uno el contador, ¿vale?
Imagínate que vamos a hacer un contador de visitas.
Entonces, vamos a hacer una operación atómica, ¿vale?
Donde las visitas vamos a incrementarlas en uno.
Y aquí, pues, hacemos un commit, ¿vale?
Db, ah, no, es que...
Ah, claro, no he traído el db.
No he abierto la base de datos.
Dino.openKeyValue.
¿Vale?
Entonces, punto...
¿No es Atomic?
AtomicDb...
¿No era Atomic?
¿Ahora la he liado?
¿No era Atomic?
¿La he liado?
¿O me lo he imaginado yo que era Atomic y...?
A ver, vamos a tirar esto para atrás.
Sí, sí, era Atomic.
Dice Async...
PropertyAtoe no existe en la promesa...
Ah, porque esto es una wait.
Vale, vale.
Ya está, ya está.
Porque cuando abres la base de datos tienes que esperar a que termine de abrirla.
Vale, vale.
Ya está.
Entonces, vale, aquí tenemos la...
Esto está mal porque esto sería el...
La key sería así, ¿vale?
Entonces, vamos a incrementar en uno el contador de visitas cada vez que alguien entra.
¿Ok?
Entonces, hacemos esto y vamos a devolver aquí un JSON diciendo que ha ido bien.
Vale.
¿Para qué va a ser esto?
Porque esto es algo parecido a lo que vamos a hacer después.
Lo que vamos a necesitar después es que cada vez que alguien entre, cambie esto.
Pues lo haremos, ¿vale?
Con este post, con este mismo.
Entonces, ahora, en lugar de hacer esto, que es un poco aburrido de nosotros ir enviando
esta información, esto no tiene tanto sentido.
Lo que vamos a hacer en realidad es que cada vez que cambie el get este de visitas, ¿no?
Cada vez que cambie el de visitas, vamos a querer informarlo.
Lo que vamos a hacer primero es hacerlo cada segundo como lo hemos hecho antes, ¿vale?
Para que veamos cuál será el paso que tendremos que dar.
Aquí tenemos que pasar esto a number de value, ¿vale?
Claro, number, a ver, ¿qué devuelve esto?
Data, porque esto en realidad lo tenemos que pasar a un toString, ¿vale?
Lo pasamos primero a número y luego a un toString.
Lo tenemos que pasar a número porque es un vkint, ¿vale?
Veis que tiene la n y nos interesa el valor del número, ¿ok?
Vale, entonces enviamos esto y esto lo vamos a volver a hacer.
Ahora, ¿qué vamos a ver ahora?
Ahora el contador estará a cero, sobre todo al principio.
De hecho, no sé si inicializarlo o ya estará inicializado porque aquí lo hemos hecho.
Seguramente estará inicializado ya, ¿vale?
Entonces, primero estará con el contador que teníamos antes, que era 10, ¿vale?
Cada segundo vemos que es 10 y yo ahora podría ir aquí y actualizar el contador
y decir, vale, pues voy a llamar a http localhost 8000 barra counter, ¿vale?
Ok, y ahora pasa a ser 11, ¿no?
Vale, y ahora pasa a ser 12.
Pero como puedes ver, tenemos el problema que al final estamos enviando la información cada segundo.
Esto no tiene sentido.
En una aplicación de tiempo real no tiene sentido estar enviando constantemente la información cada segundo, ¿vale?
¿Por qué usamos Bikin?
¿Porque algún día alcanzará un número muy alto?
En este caso, es una buena pregunta.
¿Por qué usamos Bikin?
Por dos cosas.
Uno, porque es un tipo de dato que al final nos permite mucha flexibilidad para el día de mañana.
Y lo segundo, porque justamente en Dino Key Value, ¿vale?
La...
El tema de hacer sumar, sumar la sumatoria, el incremento, el mínimo y el máximo son tres operaciones
que solo puedes hacer con este tipo de dato.
Al final es un tipo de dato que quieras o no, está optimizado para los números.
Entonces, ya sea que quieras sacar el mínimo de un valor actual, el máximo, o hacer un sumatorio,
esto te va a ayudar.
Así que lo vamos a necesitar.
Bueno, vamos a arreglar esto porque como veis esto ahora es cada segundo.
Esto no tiene sentido.
Lo que queremos es que cada vez que hay un cambio, se lo enviemos al usuario.
Es como en un chat.
Cada vez que alguien escribe, se lo enviamos al usuario.
Como un juego multijugador.
Cada vez que pasa algo, lo vamos a enviar al usuario.
Lo que no tiene sentido es que estemos constantemente, cada segundo, haciendo esto.
No queremos un while true.
No queremos esto.
Punto.
Fuera.
Lo que queremos es la magia de...
Queremos observar el campo de visitas, ¿vale?
El campo de visitas.
Pero cuando hacemos un watch, tenemos que pasar todos los campos que queremos observar.
Por eso pasamos un array de arrays.
Porque queremos observar y tendrón le diríamos todos los campos que queremos observar.
No se le pasa solo un array, sino que le tenemos que pasar una lista de keys que queremos observar.
Y en este caso, el array de arrays, como solo queremos observar una, solo le pasamos uno.
Y como la key, mira, para que lo veamos más claro.
Visits key.
Esta sería la key, ¿vale?
Y lo que queremos aquí es list of keys to watch, pues sería visits key.
Y aquí, list of keys, ya lo tendríamos así.
¿Vale?
Entonces, tenemos que pasarle una lista de keys que queremos observar.
La única lista de lo que queremos observar es la de visitas.
Que luego, igual, esto lo cambiamos porque querremos observar las visitas y la última localización.
Pero por ahora, solo queremos esto.
Ahora que tenemos el watcher, que es el que está observando cada vez que hay un nuevo valor,
vamos a hacer el for await, ¿vale?
Que es justamente lo que os he enseñado antes.
Como tenemos un iterador que va a recibir un nuevo valor cada vez que se actualiza,
vamos a tener aquí, ¿vale?
Cada vez que el watcher recibe una nueva entry, por eso hacemos una wait, porque esto es asíncrono,
no sabemos cuando alguien va a crear una nueva visita.
Cuando ocurra, esto tendrá una nueva entrada y aquí podremos recuperar del valor del entry 0.
¿Por qué entry 0?
Porque aquí, si observamos más key, pues en la key, esta sería la second key,
esta second key estaría en la entry 1.
Este visits key está en la entry 0, ¿vale?
O sea, que depende de lo que estemos observando y tal, pues lo tenemos en una posición o en otra.
En este caso, en la entry 0 tendríamos visits key, ¿vale?
Porque podemos tener diferentes keys que observamos.
Recuperamos el valor, vamos a ver que el valor, si es diferente a null, ¿vale?
Si es diferente a null o undefined, entonces, ¿qué vamos a hacer?
Pues vamos a hacer esta línea de aquí y vamos a enviarle al cliente, le vamos a decir,
oye, esto ya value to string, yo creo que esto, yo creo que lo podemos hacer así directamente.
Creo que sí.
Le vamos a enviar el valor, lo transformamos a string, porque tenemos que transformarlo todo a string,
y luego lo veremos, que necesitamos hacer un JSON stringify también para enviar la información.
Le enviamos esto y ya está.
O sea, ahora lo que vamos a hacer, ya podemos, bueno, lo voy a dejar ahí comentado,
pero ahora lo que hacemos es suscribirnos, que cada vez que cambie algo en la base de datos,
entonces es que le informamos al usuario.
Entonces, vamos a ver si esto funciona, ¿vale?
Nos vamos aquí, refresco, vale, 13.
Está ahí quieto, ¿no?
Pero ahora yo voy a decirle, vale, actualízalo.
Ojo, 14.
Entonces, yo cada vez que actualizo esto, fíjate que casi en tiempo real,
cada vez que yo actualizo la base de datos por un sitio,
el cliente recibe el evento por el otro.
O sea, lo que estamos haciendo aquí es, básicamente,
esto para cualquier aplicación en tiempo real,
chats, videojuegos, notificaciones, cualquier cosa,
esto lo puedes hacer tan fácil como esto.
Parece un ejemplo sencillo, pero al final es bastante importante porque se está sincronizando totalmente de una forma muy sencilla.
Fíjate el poco código que hemos hecho, ¿vale?
Entonces, ahora, la pregunta del millón.
Vale, todo esto está muy bien, pero ¿dónde está lo que me has prometido?
Tú me has prometido esto, que esto, este efecto guau, está muy chulo, ¿no?
El hecho de tú tener en tu porfolio, por ejemplo, la última visita y que en tiempo real se pueda ir viendo de dónde viene la última visita, ¿vale?
Entonces, no me he dado tiempo a encontrar un buen servicio que le puedas pasar la IP y me devuelvo al JSON.
Entonces, lo he tenido que hacer en el cliente.
No os puedo enseñar que, bueno, espérate, os lo voy a enseñar para que lo veáis,
pero no quiero que me doxéis, entonces voy a intentar ir con cuidado a ver si, vale.
Creo que con esto está bien.
A ver, hay un servicio, es un servicio que se llama geolocation.microlink.io,
que vosotros podéis hacer una petición, de hecho, podéis entrar, es totalmente gratuita, ¿vale?
Podéis entrar y vais a ver que os da toda vuestra información.
Bueno, toda vuestra información no, no sabe las páginas porno que visitas ni nada de esto,
pero sí que sabe cuál fue la última persona que te rompió el corazón.
No, lo que te va a decir arriba del todo, te va a decir tu IP, tu IP de versión 6,
te va a decir tu ciudad, te va a decir tu país.
A veces la ciudad no es exacta, ¿vale?
Que la gente luego se vuelve bastante loca, ¿vale?
Que dice, no, es que no es la ciudad exacta.
Es normal, pero sí que al menos te va a decir, te va a dar bastante información.
De hecho, te dice incluso cuál es el aeropuerto que tienes más cerca,
las coordenadas no son exactas, las coordenadas, pensad que son de la IP, ¿vale?
Entonces, no os preocupéis de no es exacto.
Es normal porque las IPs al final pueden tener cierto movimiento.
No es justo en vuestra casa.
A veces sí que encaja la ciudad.
A mí, por ejemplo, no encaja la ciudad.
A mí me dice Barcelona, yo no estoy en Barcelona, mi código postal no es correcto.
O sea, tiene cosas, pero está bastante cerca, ¿vale?
Está bastante cerca.
Así que esto lo vamos a utilizar para poder enseñar la información, ¿vale?
Y este servicio, la información que estáis viendo aquí, estoy bastante seguro,
pero bastante, bastante, que es la misma que se saca aquí, bastante seguro.
Son los datos que da el ISP, claro, efectivamente, no es a nivel de routers, a nivel de ISP.
Pero estoy bastante seguro que es la misma que está aquí, para que lo sepáis.
Entonces, vamos a utilizar ese servicio.
Vamos a utilizar este servicio para recuperar la información del usuario.
¿Cómo lo vamos a hacer?
Pues, mira, nos vamos al cliente y aquí lo que vamos a hacer es,
primero, vamos a tener aquí la respuesta,
hacemos una wait del fetch y le pasamos la URL esta.
Creo que esto no va a funcionar, esta wait, pero lo vamos a arreglar ahora
y vais a ver cómo y vais a entender una cosa muy chula.
Vale, hacemos el JSON y aquí vamos a recuperar, por un lado, la IP, la ciudad,
de la ciudad, el nombre y ya está.
Y el nombre le vamos a llamar city.
Y el country, el nombre y el emoji, no, emoji no, ¿cómo se llama?
El flag, ¿vale?
Y con esto, esto lo vamos a sacar del JSON.
Vale, a ver, para la gente que no se me pierda, ¿qué estamos haciendo aquí?
Estamos haciendo, primero, una petición a una API.
Esto es JavaScript puro y duro.
Esto, de hecho, es JavaScript, que lo tenemos, es vanilla JavaScript.
Esto, estamos utilizando la wait, esto se le llama top level await, ¿vale?
Voy a hacer aquí un console log del city, el country y el flag, ¿vale?
Para ver si esto funciona.
¿Qué estamos haciendo?
Del JSON que devuelve, recuperamos, por un lado, la IP.
Bueno, la IP ni siquiera es necesaria.
Es que no es necesaria la IP.
No vamos a recuperar la IP.
Es que no es necesaria.
Y, de hecho, es peligroso guardar la IP del usuario porque te pueden meter en problemas.
Así que no lo vamos a hacer.
Entonces, recuperamos la ciudad y el país, que al final es lo que nos interesa.
Y, fijaos que lo que hacemos es, de la ciudad, extraemos la propiedad name y la renombramos a city.
Yo no soy muy fan de este tipo de construcciones.
Normalmente, lo que yo hago, y de hecho lo voy a hacer para que lo veáis más claro,
a mí me gusta más hacer algo así, country JSON.
Y ahora que ya tengo el city y no sé qué, entonces lo cambio de nombre.
Pero, ¿qué pasa?
Que como se llama city, que no sé qué, no sé cuánto, es un poco rollo.
Así que lo hago así de una y ya está.
¿Vale?
Y entonces así ya puedo reutilizar el nombre de city fácilmente sin hacer mucha historia.
Pero lo que estamos haciendo es una desestructuración en JavaScript mientras renombramos.
Entonces, en la propiedad json.country.name lo guardamos en la constante country.
¿Vale?
Así es como funciona la desestructuración con un renombrado, que es bastante útil hacer esto.
Así que ya sabéis.
Muy bien.
Ahora que ya tenemos esta información, la ciudad, el país y la banderita, lo que podríamos
hacer con esto es guardar esta información en nuestro servidor.
Lo ideal, lo ideal, también os digo, sería hacer todo esto en el servidor.
O sea, desde una sola petición hacer todo esto.
Pero el problema es que el servicio que os he dicho no se le puede pasar, no se le puede
pasar la IP, por desgracia.
Pero hay un montón de servicios por ahí que sí que le puedes pasar la IP y te da esta
información, pues lo podéis utilizar, lo podéis mirar y ya está.
¿Vale?
Entonces, una vez que ya tenemos esta información con el await, vamos a hacer un fetch de barra
visit.
¿Vale?
Y le damos aquí.
Vale.
Vamos a hacer esto.
Method post.
Le pasamos los headers que el contenido es del tipo json.
JSON, el body, le pasamos la información que hemos recuperado y ya está.
¿Vale?
Ya tendríamos esto.
Hacemos este await.
Y este visit lo tenemos que crear justamente, pues, aquí.
¿Vale?
Vamos a poner barra visit.
Y lo que vamos a hacer aquí son dos cosas.
Por un lado, podríamos tener un contador de visitas.
Vamos a quitar el del counter, que no lo vamos a usar para nada.
Esto puede estar bien, ¿vale?
Tener contador de visitas.
Y también lo que podríamos hacer aquí sería también, de forma atómica, vamos a hacer
dos cosas ahora, para que veáis que se pueden hacer más de dos cosas.
Vamos a hacer también aquí setear, podríamos setear la última visita, last visit, y le pasaríamos
aquí la información del country, el city y el flag.
¿De dónde sacamos esta información?
De lo que le estamos pasando aquí por el body.
Pues, entonces, en el body, aquí lo tenemos que recuperar de c.request.json, ¿vale?
Con este await, la c es el contexto.
Rec se refiere a la request.
Y esto es para recuperar el json.
Esto que te puede parecer muy raro, en realidad, es lo mismo que estamos haciendo en esta línea.
Solo que es así.
Pero es lo mismo.
Está utilizando la misma API por detrás, está utilizando lo mismo, y es parte de
javascript. Porque tú puedes transformar una request, una response, para recuperar el cuerpo
del json. Así que sería exactamente lo mismo, la misma cosa que está pasando aquí, es lo
mismo que está pasando en esta línea, aunque parezca raro, ¿vale?
Así que ahora tendríamos el city, tendríamos el flag y el country.
¿Ok? Vale.
¿Qué más? Aquí, ¿qué se me queja?
Ah, vale. Porque he puesto mal esto.
Esto es aquí, esto es acá.
Vale. Pues ya tendríamos la city, flag y country.
Si te parece bien y quieres mejorar un poco esto, le podrías poner los tipos, ¿vale?
Puedes poner interface last visit, le pones aquí el country string city flag, y ahora
aquí le podrías indicar que el json lo que tiene que pasear es esto.
Y ahora ya sabrás que city es string flag.
Si quieres, pues esto mejoraría un poquito el hecho de los tipos.
Pues te puede ayudar a detectar algún problema, si hay alguna cosa que estás haciendo que no
deberías. Pero bueno, con esto ya estamos haciendo dos cosas.
El cambiar la última visita y, por otro lado, incrementar las visitas, ¿vale?
Muy bien. Esto por aquí. Esto ya tendríamos aquí la parte del await del visit, ¿vale?
Guardando esto. Perfecto.
Vale. Ahora, cambiamos otras cosas. Tenemos que escuchar cada vez que cambia.
Me voy a basar en el del counter, pero el del counter lo voy a dejar quieto, ¿vale?
Lo vamos a poner aquí, lo vamos a comentar.
Me lo copio y ponemos aquí visit y es muy parecido.
Lo que pasa es que en lugar de el visits key, lo que vamos a poner para evitar esta cosa
que antes lo he puesto para que lo entendáis, ¿vale?
Lo vamos a poner aquí directamente.
Y vamos a llamar aquí que queremos ver el last visit, que es el que nos interesa, ¿vale?
Cuando el last visit, cada vez que cambia, entonces tenemos el watcher.
Y ahora aquí tenemos cada vez que tenemos el valor y lo que vamos a hacer aquí es pasarle la información en un string,
así que JSON Stringify, del value.
O sea, aquí cuando hacemos un evento y enviamos información del servidor al cliente,
no le podemos enviar un número o lo que nos dé la gana.
Aquí en el data siempre, siempre, siempre tiene que ser una cadena de texto.
Por eso hacemos el JSON Stringify, que luego nosotros lo podemos volver a transformar,
a parsear y hacer mil millones de cosas.
Pero aquí necesitamos que sea así, ¿vale?
Que hacemos un Stringify, le pasamos la cadena de texto y luego en el cliente hacemos el parse.
Por desgracia, así es como funciona el server Site Events.
Pero bueno, en otros no se funcionaría de una forma distinta.
Entonces, con esto ya tendríamos tanto las visitas,
que estamos guardando la última visita con la información y todo.
Solo nos faltaría mostrar la última visita.
Así que aquí, este evento que habíamos hecho del counter, esto lo cambiamos.
Vamos a poner visit, esto vamos a cambiarlo a un small, ¿vale?
Un small.
Y aquí, en lugar de un ul, vamos a poner un small también.
De hecho, vamos a poner small, inner y aquí lo que vamos a poner,
vamos a quitar todo esto que nos necesitamos, esto también.
Vamos a poner aquí que tenemos el city, el country y el flag al parsear el even.data.
Y ahora vamos a poder, con esta información, vamos a poner el last visit from, ¿vale?
Y le ponemos ahí esto.
Ahora luego haremos la animación, para que veas cómo se hace la animación esa tan chula.
Pero por ahora, al menos, vamos a tener esta parte en la que cada vez que alguien entre a la página,
deberíamos ver que cambia la visita, ¿vale?
El nombre del evento, no hay que cambiarlo, está update dos veces.
No pasa nada.
No pasa nada.
A ver, en este caso, hemos utilizado siempre update, pero solo lo utilizo una vez.
O sea, como lo he comentado, solo lo utilizamos una vez y aquí también solo lo utilizo una vez y ya está.
O sea, que en este caso tiene sentido.
Vale, sabía que iba a petar esto, no pasa nada.
Ah, mido el content como IDE, vale, eso sí que es importante.
Vale, ahí está, muy bien, muy bien visto, bien visto.
Esto está mal, porque esto debería ser document, query, selector y small, ¿vale?
Vale, entonces, await is only valid in async functions at the top level.
Ok, esto es súper importante, súper interesante, porque muchas veces la gente habla del tema este de,
¿qué es esto del await que lo estás utilizando sin un async que no sé qué?
Y es que hay una cosa que se llama top level await.
Pero eso, como ves aquí en este error, te dice await, solo es válido en las funciones async o en el top level de los cuerpos de los módulos.
Entonces, cuando tú estás utilizando justamente, estás utilizando en más script modules con los imports y los exports,
lo que puedes hacer es utilizar el await en el cuerpo de tu función.
Pues, en este caso, también lo podemos hacer si cambiamos este script y lo pasamos a tipo módulo.
Esto es totalmente vanilla JavaScript, ¿vale?
Y de hecho, esto, en unos años, hoy no es el por defecto, digamos, pero esto lo haremos automático, ¿sabes?
Lo haremos automático, el poner el script que sea de tipo módulo.
Lo bueno de esto es que ahora ya aquí podríais hacer un import, podríais hacer mil millones de cosas.
Y así es como funciona la magia de Codilink.
Si vais a Codilink y hacéis un import, es porque funciona así.
Y así es como, de hecho, mirad, para que veáis, Canvas, Confetti, para que veáis esto.
Y a ver, Canvas, Confetti, bueno, si voy a Codilink y aquí pongo Confetti, por ejemplo.
Esto, esto aquí.
Esto es lo que es espectacular.
Que esto, básicamente, es vanilla JavaScript, no tenemos ningún empaquetador ni nada.
Y esto debería funcionar.
¿Veis?
¿Veis el Confetti?
Este Confetti es porque he hecho un import de esta URL directamente desde mi archivo vanilla JavaScript con cero bundlers, sin ningún empaquetador ni nada, ¿vale?
O sea, no he hecho ningún empaquetador ni nada.
Solo para que lo sepáis, que podéis utilizar import y export, ¿ok?
Entonces, por eso también funciona el await.
Ahora que ya tenemos esto, pues nada, ya tenemos ahí nuestro last visit, que no está nada mal.
Pero, obviamente, el problema que tenemos es que no tenemos más usuarios que vea si esto, ¿no?
Que se actualice.
Nos falta un poco esto.
Entonces, voy a arreglarle un poco, un poco, tampoco mucho, ¿eh?
Voy a arreglarle un poco los estilos para que...
Voy a poner un Position Absolute solo porque lo que queremos...
Insert 0, Margin Auto, Font Side, 12 Pixels...
Solo para que se vea más o menos parecido al que tiene R1, ¿vale?
6, centramos en el texto, Font Family, Menlo, Monospace...
¿Vale?
Esto sería por aquí.
Y a ver cómo queda.
Vale.
Queda ahí regulín.
Queda regulín porque está todo oscuro.
¿Qué puedo hacer si no?
¿Cómo lo podemos hacer?
Puedo hacer...
Bueno, puedo hacer que sea todo...
Voy a hacer que sea todo en negro.
Y ya está.
Background.
Y ya está.
¿Vale?
Y al menos para que lo veamos así.
Entonces, vamos a poner Top 32 Pixels...
De hecho, estoy pensando que yo creo que si pongo Display Grid, Place Content Center,
para centrarlo todo, con la altura mínima de esto, entonces ya nos podemos quitar todo esto.
Y creo que quedará un poquito mejor, ¿vale?
Para que quede ahí en medio.
Entonces, ahora mismo, obviamente, solo soy yo y por lo tanto no puedo asegurarme que esto funcione.
Pero para eso necesitamos vuestra ayuda, porque con vuestra ayuda seguro que podemos hacer que funcione.
Así que vamos a ver cómo funciona esto, cómo lo desplegamos.
Así subimos el código y luego lo iteramos para hacer la animación, ¿ok?
Vale.
No, no voy a abrir puertos ni Hardtobino.
Lo que vamos a hacer es, primero, me voy a ir a GitHub.
Voy a crear un repositorio.
Vale.
Drop in.
Creamos uno nuevo por aquí.
Y lo que vamos a hacer...
Hostia, que lento va GitHub.
No sé si es cosa mía o es que va lento GitHub.
Vamos a ver.
Vamos a poner MewDev.
Last time visit, ¿vale?
Para saber la última visita y enseñarlo en tiempo real, ¿ok?
Entonces, vamos a poner public, bla, bla, bla, query repository.
Compartir.
Subimos a producción.
Hombre, no.
No, a túnel no, joder.
Subimos a producción, hombre.
Vale.
Entonces, vamos a...
Hostia, hay un error aquí.
Está mal la tabulación, ¿verdad?
Vale.
Vamos a iniciar el proyecto.
Vamos a git init.
Vamos a añadir el repositorio.
A ver, que no se suba nada raro.
Vale.
Yo creo que tiene sentido.
Add all files.
Pusheamos.
Y se debería actualizar esto con nuestros pushes.
Vamos a desplegar esto a producción gratis, con base de datos,
sin hacer absolutamente nada.
Coño.
No tarda.
Va.
No va fino, ¿eh?
Git.
GitHub va a regulinchis, ¿eh?
Va un poco regular.
Bueno, voy entrando a Dino Deploy.
Pero, ¿os pasa?
Está medio raro.
Está lento.
Oye, pues, qué rollo, ¿no?
Últimamente, pobre GitHub está...
Está el pobre.
No sé si es que está actualizando.
Oye, ahora no sé si soy yo que estoy viendo ahora.
Hostia, pero está tardando, ¿no?
Creo que es a ti.
Ah, pues, igual es a mí.
No sé.
Vale.
Aquí tenemos diferentes proyectos.
Vamos a crear un nuevo proyecto.
¿Vale?
Venga, aquí tenemos ya los archivos.
Perfecto.
Mirad.
Esto es Dino Deploy.
¿Vale?
Esto que vemos aquí, esto es Dino Deploy.
Es el hosting que tiene, que tiene una capa gratuita brutal, ¿vale?
Brutal, que está súper bien, esperando a YouTube.
¿Y por qué tengo que esperar a YouTube?
Hostia.
Hostia, es que me da la sensación que soy yo que me va súper lento internet.
Hostia, pero es raro que puedo...
O sea, que funciona bien el streaming, pero que me funciona...
Ya me están haciendo dos.
¿Tienes problemas de DNS?
Sí, seguramente.
Seguramente me está alguien haciendo un montón de ataques ahí.
Me cago en la leche.
¿Qué rollo?
Voy a tener que cambiar la IP.
Voy a intentar a ver si me está haciendo un dos de la IP.
Bueno, en fin.
Vamos a desplegar el código, ¿vale?
Midudev.
Nos dice seleccionar el repositorio.
Y aquí tenemos que seleccionar el repositorio que justamente hemos hecho, ¿vale?
Last time visit.
Este de aquí.
La rama, main, ¿vale?
Y aquí le tenemos que preguntar si hay que construirlo.
O sea, si tiene un paso de build o hay que hacerlo en GitHub.
Nosotros no tenemos paso de build porque todo lo que estamos haciendo es en build step.
Y luego el entry point.
El entry point es el punto de entrada de nuestra aplicación.
Que en nuestro caso lo tenemos aquí.
Main.ts.
No.
App.ts.
Ojo, cuidado.
No nos equivoquemos.
App.ts.
Que es donde tenemos toda la aplicación.
Así que este lo cambiamos.
Y le diremos ahora que es el app.ts, ¿vale?
App.ts.
Y le decimos create and deploy, ¿ok?
Esto lo que va a empezar ahora es pillar el código directamente y va a desplegar a producción.
Y lo va a desplegar.
Va a tardar nada.
Si es que ya lo ha hecho.
Ya está.
Ya lo tenemos en producción.
O sea, así de rápido.
Ahora lo que nos debería decir es la URL donde lo tenemos y todo esto, ¿vale?
¿Ves?
Vale.
Aquí lo tendríamos y ya tendríamos en esta URL.
Ya lo tendríamos.
Aquí tendríamos en esta URL.
Ya tendríamos el proyectito.
Ah, lo malo.
Lo malo es que algo que la he liado con algo.
Y es el course.
No hemos hecho que tenga course.
Ah, sí.
Hostia, pensaba que a lo mejor.
Ah, vale.
Porque está pillándose a sí mismo.
Vale.
Pues ya está.
Funcionaba bien.
Pues mirad.
¿Veis?
Ahora ya en tiempo real.
Villa va a estar.
Pues cada vez que entre.
Lo que pasa es que yo ahora tengo problemas de conectividad.
Porque hay alguien ahí que está como loco.
Que debe ser el mejor día de mi vida.
He pillado la IP y le voy a atacar así como no sé qué, no sé cuánto.
Anda, que no tiene que estar aburrido el pajero para hacer esto, ¿eh?
Entonces, vamos a ver.
Vamos a ver por qué.
Que no se me haya olvidado ninguna.
Vale, aquí sí.
Vale, no he puesto ningún error y tal.
Voy a hacer una cosa para que no haya un problema de course, para que no se olvide.
Por si acaso, vamos a poner aquí un course.
Y vamos a decirle aquí que utilice app.use course tal, ¿vale?
Muy bien.
Entonces, esto para el course.
Y para el tema de que vaya cambiando, porque fijaos que aquí cada vez que alguien va a actualizarse, pues, ir viendo que va apareciendo.
Lo que tenemos que hacer también para que tenga la animación, lo que, claro, va a ser complicado porque si no soy capaz de ir viendo cómo la gente la aparece, va a ser un poco más complicado.
Hablo del CSS.
Pero, bueno, lo puedo intentar más o menos si más o menos lo intento por aquí.
Mirad, tenemos, por un lado, tendríamos aquí, para cambiar la animación que hacemos, que hacíamos en esta página, esta animación que hacíamos en esta página, para hacer la transición, lo que necesitamos es básicamente tener dos dips, ¿vale?
Donde en un dip vamos a necesitar lo que sería el último y en un dip vamos a necesitar el siguiente, ¿ok?
Porque vamos a tener dos dips.
A ver, le llamo dip, que podrían ser spans.
Podrían ser spans también.
Lo que pasa es que si son spans, bueno, vamos a hacer spans.
Vamos a hacer spans y vamos a hacer que el small span sea display block, ¿vale?
Y vamos a ponerle una altura que sea fija de 20 píxeles, por ejemplo, para que siempre tenga la misma altura y así sepamos cuánto se tiene que subir arriba o cuánto se tiene que subir abajo.
Entonces, cuando aquí tenemos el update, ¿vale?
Cuando tenemos que escuchar el evento y hacemos esto, ahora mismo lo que estamos haciendo es siempre meter la última visita.
Y claro, esto se puede volver un poco loco.
Lo que vamos a hacer es, vamos a quitar esto, vamos a tener el elemento last, document get element by id last, y aquí vamos a poner el next, ¿vale?
Y lo que hacemos con esto, ¿vale?
Lo que vamos a hacer, oye, ¿estáis ahí?
Estáis muy callados.
De repente os habéis callado muy fuerte.
Digo, a ver si ahora ya me han tirado el stream.
Ya me han tirado el stream, cago en la leche.
Ya está.
No, entonces es que me han tirado el chat, ¿vale?
Sí, ¿nosotros a quién damos?
Ya, lo que pasa es que el chat me pone conectando y no sé qué.
Bueno, no pasa nada.
Entonces, lo podemos ir viendo.
No pasa nada.
Yo os lo comento mientras.
Y luego lo, sí, vaya rollo.
Lo que pasa es que, por suerte, tengo una IP dinámica y no pasa nada, la puedo cambiar.
O sea, se va a ir cambiando.
Pero que es un rollo que ahora voy a tener que estar pendiente de esto.
Si no, pues nada.
Es sabita, sí.
Bueno, entonces, lo que vamos a hacer aquí, ¿vale?
Tenemos la última visita del city country flag.
OK.
Lo que aquí queremos hacer es que, en lugar de siempre poner el mismo, ¿no?
Porque tenemos aquí el update y el city country flag,
lo que queremos es controlar cuando vamos a poner el last y el next, ¿vale?
Cuando cambiamos uno con el otro.
¿Por qué?
Porque no siempre vamos a querer enseñar solo uno, sino que queremos enseñar los dos,
el actual y el nuevo.
Ahora, lo que vamos a hacer aquí es poner también un flag que le damos ready true, ¿vale?
Que va a estar como disponible desde el principio.
Y vamos a decirle, si todavía no está el ready, ¿vale?
Pues lo vamos a pasar a false.
Esto lo ponemos un return aquí y ya está.
Ahora, no haces nada si todavía no está ready.
¿Y cuándo está ready realmente?
Pues va a estar ready por defecto la primera vez.
Sí que lo va a poner porque necesitamos la primera información ahí.
Y vamos a chequear también si el mensaje, vamos a crear el mensaje aquí ya separado, ¿vale?
Vamos a poner aquí const message, ¿vale?
Y ponemos aquí, si es el is last empty.
Si es el último, si el último está vacío, hacíamos last.innerHTML,
si es igual a esto, ¿vale?
Y le ponemos un console.log, console.log is last empty, ¿vale?
Vamos a mirar si el último está vacío, entonces, if is last empty,
vamos a hacer el innerHTML del message.
Y ya está, no hacemos nada más.
Porque esta es la primera vez.
La primera vez le enseñamos al usuario lo que queremos, ¿eh?
A ver qué ponéis.
Vengo a resolver ejercicio 5 las 20.yes.
Muy bien, hombre, muy bien.
¿Para qué son los signos del dólar en las variables?
Este signo del dólar, lo que quiere decir, esto lo utilizo yo normalmente,
para saber qué es un elemento del dólar.
Esto es una cosa que yo tenía muy común en su momento.
Me acostumbré y ya está, ¿no?
¿Midu, para qué son los signos?
Vale, pues ya está, ya lo he contestado.
Por eso lo utilizo, ¿vale?
Para saber más fácilmente que me refiero a un elemento del dólar,
porque si no es un poco rollo.
Vale, entonces, una vez que sabemos si es empty, pues hacemos esto, ¿vale?
Y ahora lo complicado, que es el hecho de, muy bien,
si no es la primera vez que ejecutamos esto,
vamos primero al next, ¿vale?
Al que estaría abajo, que todavía no se ve,
vamos a ponerle el mensaje.
Y ahora vamos a iniciar una animación
que le vamos a poner animation
y el del next va de abajo arriba.
Así que vamos a llamarle fading up, o sea, hacia arriba,
fading mientras hace hacia arriba,
de un segundo con ease in out y forwards, ¿vale?
Y si no sabes lo que es el forwards,
te vas a mi curso de CSS de animaciones, que te lo explico.
Porque hoy no te lo voy a explicar.
Pero en serio lo explico en el curso de CSS que tenéis en YouTube,
ahí te lo explico.
Y en el last, que sería la última ubicación que hemos podido ver,
aquí tendríamos que hacer al revés, fade out up.
¿De dónde salen estas animaciones?
Estas animaciones las vamos a escribir nosotros en CSS ahora,
o sea, que no te preocupes, ¿vale?
Y entonces aquí vamos a poner ready false.
¿Por qué le ponemos el ready a false?
Porque en mitad de una animación,
lo que vamos a hacer con esto es que en mitad de la animación
vamos a evitar que por lo que sea,
el usuario, ¿sabes?
Que rompamos la animación.
Imagínate si en mitad de la animación cambiamos el texto.
No tiene sentido.
Lo que hacemos es que cuando iniciamos la animación, ¿vale?
Cuando iniciamos la animación le decimos,
oye, ahora no estoy preparado porque me estoy animando,
enseñando una nueva ubicación.
Y lo que vamos a hacer,
y esto es de vanilla JavaScript total y es muy interesante,
y también es un evento que puedes escuchar, por ejemplo, en React,
es que cuando detectemos que termina la animación, ¿vale?
On animation end,
entonces lo que hacemos aquí, ¿ok?
Es decir, vale, ahora le quitamos el estilo de la animación,
porque ya ha terminado la animación,
la quitamos al next y al last, ¿vale?
También al last le vamos a poner que el HTML sea el mensaje
y el next, el innerHTML, le quitamos el mensaje
y le decimos que ya está en true.
Porque así lo que hacemos es,
lo que pasa, lo que tenemos abajo,
mira, lo que tenemos abajo, lo pasamos arriba.
Cuando está arriba,
entonces lo que hacemos es resetearlo todo
para que visualmente no se va a dar cuenta el usuario,
pero lo que pasa es que cuando termina la animación,
borramos ese mensaje de ahí y se lo ponemos al last
y volvemos como a resetearlo
y le decimos, vale, ya estamos ready otra vez.
Y así todo el rato, ¿vale?
Así todo el rato, ¿ok?
Así es lo que estamos haciendo.
¿Qué tal un stream sobre cosas?
Tener cuentas sobre ciberseguridad.
Sí, bueno, no enseñar tu IP
y no darle de comer a los pajeros.
Eso es lo que diríamos.
No enseñar tu IP público.
Mira que lo he intentado y al final se va a colar.
Muy bien, entonces, cuando tenemos esto,
ready, true, con esto no se me olvida nada más.
Yo creo que no.
Ah, sí, los estilos, claro, los estilos.
A ver, es bastante sencillo, ¿eh?
Tenemos dos, el fading up y el fade out up, ¿ok?
Entonces, tendríamos por aquí keyframes,
esto, hostia, esto aquí.
Vamos a crear keyframes, fade out up, ¿vale?
El from opacity 1 y transform, ¿vale?
Este, el inicial, este será el fade out up,
es que al principio se ve y luego se va para arriba.
Este es el que tenemos al principio por defecto.
No sé si todavía lo tenemos por aquí.
Pero este sería el que se vería aquí por defecto al principio, ¿vale?
El que se vería al principio por defecto.
Y aquí tendríamos 0, ¿ok?
Y luego esto viajaría opacity 0, transform y lo subimos.
Translate y menos 20 píxeles.
Y esto mismo, pero al revés, es lo que haríamos con el otro.
Lo que haríamos con el otro sería justamente al revés.
O sea, pasaríamos que no se ve, tendríamos 0 píxeles y luego subiría.
¿Por qué 0 píxeles?
O sea, ¿por qué sí que hacen el mismo movimiento?
Porque uno está debajo del otro, ¿vale?
Como ves aquí, este en realidad está encima del otro.
Y como lo queremos es mover los dos 20 píxeles hacia arriba.
Por eso, tanto si desaparece como si aparece en los dos casos,
lo movemos desde la parte 0 a menos 20 píxeles.
Lo vamos a mover 20 píxeles hacia arriba, ¿vale?
Eso es lo que vamos a hacer con los dos.
Por eso aquí, cuando cambia la ubicación, si tira mi internet,
pues veréis eso, ¿no?
Que lo que hacemos es justamente mover el contenido hacia arriba
para ver como si lo empujase mientras que este desaparece
y el otro aparece por abajo, ¿vale?
Eso es lo que estaríamos haciendo, básicamente.
Y a ver qué más tenemos por aquí.
Vale, pues con esto ya lo tendríamos definitivamente.
Te le puede pasar hasta el mejor.
Espero que se solucione el problema.
Te queremos.
Nada, hombre, no pasa nada.
¿Qué pro?
Solo faltaría cambiar el nombre de la animación.
Ay, no he puesto el nombre de animación.
Ay, tienes toda razón.
Menos mal.
Vale, menos mal.
Menos mal.
Vale, el next fading up.
Vale, pues sería el fading up.
Este lo tendríamos que poner aquí.
Y con este código ya lo tendríamos aquí.
Vamos a añadir esto por aquí.
Add new code.
Vale.
Publicamos la rama cuando se pueda subir.
Y ya está.
Al final del keyframe es 20, no negativo.
No negativo.
A ver, no por lo que he comentado.
O sea, aquí lo que queremos es justamente menos 20 píxeles.
Es una pena que no te lo puedo enseñar porque no me funciona internet, ¿vale?
Porque me lo tienen ahí bloqueado.
Pero justamente sí que funcionaría.
Midu, ¿qué diferencia hay entre Dino y Railway para Deploy?
A ver, Dino Deploy, Railway está más pensado para cualquier cosa.
Y Dino Deploy sería para aplicaciones solo de Dino.
O sea, yo te recomendaría Dino Deploy porque además es gratuita.
O sea, que échale un vistazo.
¿Midu, has probado la Google Topics API?
No.
¿Después de la Adven.js vas a hacer más retos?
Sí.
De hecho, ya os comentaré porque hay sorpresa con eso, ¿eh?
Me tengo que mirar tu curso.
Me tengo que mirar tu curso.
Esto de las animaciones mola mucho.
Solo usé una para dar efectos de borde a un botón,
pero quiero hacer cosas más chulas.
Sí que funciona, Braco.
¿Ves?
Ah, no sé si se ha pusheado ya y todo.
Se ha podido.
No, creo que no se ha podido pushear.
No, porque está en ello.
Pero, bueno, que sí, que funcionar, funcionaría.
Y si no, pues ya lo veremos.
Bueno, amigos, pues nada.
Me voy, me voy.
Os dejo hasta aquí.
Os he dejado, bueno, os dejaré cuando pueda hacerlo.
Os dejaré el código público de GitHub totalmente,
código abierto.
Y espero que os haya gustado con esto.
Ahora, a partir de esto, con esto que hemos aprendido,
lo que vamos a hacer es una cosa súper interesante.
Porque vamos a, con todo lo que hemos aprendido
de la base de datos y todo, lo que vamos a hacer es,
por un lado, vamos a crear un proyecto secreto
que empezaremos la semana que viene
para que todo el mundo pueda jugar,
que todo el mundo pueda echarle un montón de ganas
en el código abierto, participar.
Y será de en tiempo real.
O sea, todo lo que hemos aprendido hoy
lo vamos a poner ahí en práctica
y lo vamos a poner para que puedas echarle un vistazo,
lo puedas poner en tu porfolio y ayudes.
Creo que es un proyecto que va a ser divertido para la comunidad.
Así que espero que lo disfrutes
y vamos a poner en práctica todo lo que hemos aprendido hoy.
Veremos hasta dónde llega,
si realmente lo podemos llevar a siguiente nivel.
Pero creo que va a ser muy divertido.
Así que no os lo perdáis, que va a ser genial.