La semana pasada estuve hablando en WebCamp Zagrebuna gran conferencia para desarrolladores y diseñadores. Hice una presentación titulada "Deja que tus dispositivos hablen entre sí". Para la parte de demostración hice una aplicación de mensajes muy simple que se sincroniza automáticamente con cualquier otra persona que la esté ejecutando en la misma red. Las diapositivas y el código de la demo están en github. La presentación se ha filmado y estará en línea en breve.
El tema de esta presentación es IoT (Internet de las cosas), M2M (De máquina a máquina) y la descentralización. Todas estas cosas de Internet suelen enviar sus datos (la mayoría de las veces datos muy privados, sí, te estoy mirando a ti, movimiento del yo cuantificado) a un servidor en algún lugar de la nube. Eso básicamente significa que ya no son tus datos (privados). Esto es muy triste. Esta es la idea principal que me llevó a hacer esta charla. Pero hay muchas otras buenas razones para dejar que tus dispositivos se comuniquen entre sí. Y esto no es algo nuevo. Lo que ahora llamamos M2M es muy común en la industria desde hace años.
Pero volvamos al tema original. Una forma de evitar esta centralización sería que tus cosas de Internet dejaran de ser cosas de Internet y empezaran a ser cosas de tu red doméstica. Deberían empezar a comunicarse entre sí y enviar sus datos donde tú decidas, como una instancia de Couchbase Lite corriendo en una RaspberryPI o cualquier otro pequeño dispositivo que soporte la JVM.
Y, por supuesto, una forma de hacer que los dispositivos se comuniquen entre sí puede ser instalar Couchbase Lite en ellos y utilizar la sincronización P2P. Ya tenemos varios entrada del blog sobre el asunto. Así que para aportar algo nuevo a esto te diré cómo hacer que esa sincronización sea automática.
La sincronización se basa en enlaces de replicación. Normalmente requieren una dirección y credenciales. Como quiero la menor fricción posible, me he saltado la parte de credenciales/seguridad. Lo cual es malo, pero hizo mi demo de presentación mucho más fácil. Entonces, si todo lo que necesitas es una dirección, ¿cómo la obtienes automáticamente?
Para que la sincronización P2P funcione, los dispositivos que se sincronizan tienen que estar en la misma red. Y la buena noticia es que existen varios protocolos de red para realizar el descubrimiento automático de servicios. Puede que hayas oído hablar de conceptos como Bonjour, RendezVous, ZeroConf, Android NSD, mDNS, DLNA, UPnP y muchos más. La mayoría de ellas se basan en el registro de servicios DNS. Porque sí, el DNS puede hacer algo más que asignar IPs a hosts. También puede almacenar una lista de servicios con su dirección, nombre y descripción.
Esto es lo que he utilizado en mi demostración. He elegido una implementación Java sencilla basada en el método Biblioteca JmDNS. De esta manera tengo casi el mismo impl en mi aplicación nativa Java y en Android. Funciona haciendo broadcasting UDP. Envía paquetes a otras cosas conectadas en la red.
He aquí un breve vistazo a los fragmentos de código más relevantes.
Iniciando Couchbase Lite Listener en el dispositivo para que pueda recibir conexiones.
|
1 2 3 4 5 6 7 8 9 |
public int startCBLiteListener(int port) { LiteListener ls = new LiteListener(database.getManager(), port, null); Thread thread = new Thread(ls); thread.start(); return ls.getListenPort(); } |
Exposición de un nuevo servicio mediante JmDNS
|
1 2 3 4 5 6 |
public void exposeService(int port) throws IOException { ServiceInfo sInfos = ServiceInfo.create(SERVICE_TYPE, serviceName, port, SERVICE_DESCRIPTION); jmdns.registerService(sInfos); } |
Escuchar un servicio en particular usando JmDNS. El oyente DiscoveryListener es importante porque es donde realmente se puede configurar la sincronización.
|
1 2 3 4 5 |
public void listenForService(){ jmdns.addServiceListener(SERVICE_TYPE, new DiscoveryListener(database, jmdns, serviceName)); } |
No es la implementación más limpia que existe, pero te harás una idea. Fíjate especialmente en el método serviceResolved. Es el que se llama cuando se ha descubierto un nuevo Servicio en la red. Nos da la URL del servicio permitiéndonos así configurar el enlace de replicación clásico.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
package org.couchbase.devex; import com.couchbase.lite.Database; import com.couchbase.lite.listener.LiteListener; import com.couchbase.lite.replicator.Replication; import javax.jmdns.JmDNS; import javax.jmdns.ServiceEvent; import javax.jmdns.ServiceListener; import java.io.IOException; import java.net.URL; /** * Created by ldoguin on 13/02/15. */ public class DiscoveryListener implements ServiceListener { private Database database; private JmDNS jmdns; private String serviceName; public DiscoveryListener(Database database, JmDNS jmdns, String serviceName) { this.database = database; this.jmdns = jmdns; this.serviceName = serviceName; } @Override public void serviceAdded(ServiceEvent event) { if (! serviceName.equals(event.getName())){ jmdns.requestServiceInfo(event.getType(), event.getName(), 10); } } @Override public void serviceRemoved(ServiceEvent event) { System.out.println(event.getName() + " removed"); } @Override public void serviceResolved(ServiceEvent event) { System.out.println("RESOLVED"); String[] serviceUrls = event.getInfo().getURLs(); for (String url : serviceUrls) { System.out.println(url); setupSync(database, url + "/messages"); } } public void setupSync(Database database, String syncUrl) { try { URL url = new URL(syncUrl); Replication pullReplication = database.createPullReplication(url); pullReplication.setContinuous(true); pullReplication.start(); Replication pushReplication = database.createPushReplication(url); pushReplication.setContinuous(true); pushReplication.start(); } catch (IOException e){ throw new RuntimeException(e); } } } |
Y ese es un divertido proyecto experimental, fácil de implementar, para asegurarte de que todos tus dispositivos Couchbase Lite pueden sincronizarse fácilmente. Hay por supuesto mucho más que se puede hacer. Como añadir la parte de seguridad. Podrías imaginar tener una primera sincronización manual que intercambie credenciales una vez y luego hacer todo lo demás automáticamente. Espero que encuentres esto útil. No dudes en comentar y darnos tu opinión.