All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.automately.java.eventbus.EventBus Maven / Gradle / Ivy

There is a newer version: 1.0.8
Show newest version
package com.github.automately.java.eventbus;

import com.github.automately.java.Automately;
import io.jsync.Async;
import io.jsync.AsyncFactory;
import io.jsync.buffer.Buffer;
import io.jsync.http.HttpClient;
import io.jsync.http.WebSocket;
import io.jsync.json.JsonObject;

import java.util.*;

/**
 * The EventBus class provides a way to connect to the Automately Cluster's underlying
 * jsync.io EventBus system. The EventBus provides an interface for authentication, handler
 * registering, and more. This class is very important.
 */
public class EventBus {

    final public static long CONNECTING = 0;
    final public static long OPEN = 1;
    final public static long CLOSING = 2;
    final public static long CLOSED = 3;

    final private String AUTH_IDENTIFIER = "automately.sdk.auth";

    public static String DEFAULT_HOST = "sdk.automate.ly";
    public static int DEFAULT_PORT = 443;
    public static boolean USE_SSL = true;


    private Async async;

    public EventBus(){
        this(AsyncFactory.newAsync());
    }

    public EventBus(Async async){
        this.async = async;
    }

    private WebSocket socket;

    private long state = CONNECTING;

    private long pingTimerID;

    private Runnable openHandler = null;
    private Runnable closeHandler = null;

    private HashMap>> handlersMap = new LinkedHashMap<>();
    private HashMap> replyHandlers = new LinkedHashMap<>();

    private String sessionId = "";

    public void connect(){

        HttpClient client;
        String url;

        if(USE_SSL){
            client = async.createHttpClient()
                    .setSSL(true)
                    .setKeyStorePassword("changeit")
                    .setKeyStorePath(System.getProperty("java.home") + "/lib/security/cacerts")
                    .setHost(DEFAULT_HOST).setPort(DEFAULT_PORT);
        } else {
            client = async.createHttpClient()
                    .setHost(DEFAULT_HOST).setPort(DEFAULT_PORT);
        }

        url = "/automately.sdk.eventBus/websocket";

        client.setTryUseCompression(true);
        client.setKeepAlive(true);

        client.connectWebsocket(url, socket1 -> {

            socket = socket1;

            socket.closeHandler(event -> {
                state = CLOSED;
                if(closeHandler != null){
                    closeHandler.run();
                }
            });

            socket.dataHandler(event -> {

                JsonObject message = new JsonObject(event.toString());

                Object body = message.getValue("body");
                String address = message.getString("address");

                // TODO Implement this
                final String replyAddress = message.getString("replyAddress");

                Set> handlers = handlersMap.get(address);

                if(handlers != null && handlers.size() > 0){
                    for(Event handler: handlers){
                        handler.run(body);
                    }
                } else {
                    Event handler = replyHandlers.get(address);
                    if(handler !=  null){
                        replyHandlers.remove(address);
                        handler.run(body);
                    }
                }
            });

            sendPing();

            pingTimerID = async.setPeriodic(5000, event -> sendPing());

            state = OPEN;

            if(openHandler != null){
                openHandler.run();
            }
        });
    }

    public void onOpen(Runnable handler) {
        this.openHandler = handler;
    }

    public void onClose(Runnable handler) {
        this.closeHandler = handler;
    }

    public long readyState(){
        return state;
    }

    public void login(String publicApiKey, final Event replyHandler){
        sendOrPub("send", AUTH_IDENTIFIER + ".login", (new JsonObject()).putString("publicKey", publicApiKey).putString("sessionID", sessionId), event -> {
            JsonObject response = new JsonObject(event.toString());
            if(response.getString("status").equals("ok")){
                sessionId = response.getString("sessionID");
            }
            if(replyHandler != null){
                response.removeField("sessionID");
                replyHandler.run(response.encode());
            }
        });
    }

    public void authenticate(String publicApiKey, String apikey, final Event replyHandler){
        sendOrPub("send", AUTH_IDENTIFIER + ".login", (new JsonObject()).putString("publicKey", publicApiKey)
                .putString("key", apikey)
                .putString("sessionID", sessionId), event -> {
            JsonObject response = new JsonObject(event.toString());
            if(response.getString("status").equals("ok")){
                sessionId = response.getString("sessionID");
            }
            if(replyHandler != null){
                response.removeField("sessionID");
                replyHandler.run(response.encode());
            }
        });
    }

    public void logout(final Event replyHandler){
        sendOrPub("send", AUTH_IDENTIFIER + ".logout", (new JsonObject()).putString("sessionID", sessionId), event -> {
            JsonObject response = new JsonObject(event.toString());
            if(response.getString("status").equals("ok")){
                sessionId = response.getString("sessionID");
            }
            if(replyHandler != null){
                response.removeField("sessionID");
                replyHandler.run(response.encode());
            }
        });
    }

    public void authorise(final Event replyHandler){
        sendOrPub("send", AUTH_IDENTIFIER + ".authorise", (new JsonObject()).putString("sessionID", sessionId), event -> {
            JsonObject response = new JsonObject(event.toString());
            if (response.getString("status").equals("ok")) {
                sessionId = response.getString("sessionID");
            }
            if (replyHandler != null) {
                response.removeField("sessionID");
                replyHandler.run(response.encode());
            }
        });
    }

    public void send(String address, Object message, Event replyHandler){
        sendOrPub("send", address, message, replyHandler);
    }

    public void publish(String address, Object message, Event replyHandler){
        sendOrPub("publish", address, message, replyHandler);
    }

    public void registerHandler(String address, Event handler){
        if(address == null){
            throw new NullPointerException();
        }
        if(handler == null){
            throw  new NullPointerException();
        }
        address = address.trim();
        Set> handlers = handlersMap.get(address);
        if(handlers == null){
            handlers = new LinkedHashSet<>();
            handlers.add(handler);
            handlersMap.put(address, handlers);
            JsonObject message = new JsonObject()
                    .putString("type", "register")
                    .putString("address", address);
            try {
                socket.writeTextFrame(message.encode());
            } catch (IllegalStateException e){
                System.err.println("Failed to send: " + e.getMessage());
                System.exit(-1);
            }
        } else {
            handlers.add(handler);
        }
    }

    public void unregisterHandler(String address, Event handler){
        if(address == null){
            throw new NullPointerException();
        }
        if(handler == null){
            throw  new NullPointerException();
        }
        address = address.trim();
        Set> handlers = handlersMap.get(address);
        if(handlers != null){
            if(handlers.contains(handler)){
                handlers.remove(handler);
                handlersMap.put(address, handlers);
            }
            if(handlers.size() == 0){
                JsonObject message = new JsonObject()
                        .putString("type", "unregister")
                        .putString("address", address);
                socket.writeTextFrame(message.encode());
                handlersMap.remove(address);
            }
        }
    }

    private void sendPing(){
        try {
            JsonObject message = new JsonObject();
            message.putString("type", "ping");
            socket.writeTextFrame(message.encode());
        } catch (IllegalStateException e){
            System.err.println("Failed to send: " + e.getMessage());
            System.exit(-1);
        }
    }

    private void sendOrPub(String sendOrPub, String address, Object message, Event replyHandler){
        JsonObject envl = new JsonObject();
        envl.putString("type", sendOrPub);
        envl.putString("address", address);
        if(message instanceof String) {
            envl.putString("body", (String) message);
        } else if (message instanceof Number) {
            envl.putValue("body", message);
        } else if (message instanceof JsonObject){
            envl.putObject("body", (JsonObject) message);
        } else if(message instanceof Buffer){
            envl.putBinary("body", ((Buffer) message).getBytes());
        } else {
            envl.putValue("body", message);
        }
        if(sessionId != null){
            envl.putString("sessionID", sessionId);
        }
        if(replyHandler != null){
            String replyAddress = UUID.randomUUID().toString();
            envl.putString("replyAddress", replyAddress);
            replyHandlers.put(replyAddress, replyHandler);
        }
        try {
            socket.writeTextFrame(envl.encode());
        } catch (IllegalStateException e){
            System.err.println("Failed to send: " + e.getMessage());
            System.exit(-1);
        }
    }

    private void checkOpen() throws Exception {
        if(state != OPEN){
            throw new Exception("INVALID_STATE_ERR");
        }
    }

    public String sessionID(){
        return sessionId;
    }

    public void close() throws Exception {
        checkOpen();
        if(pingTimerID != 0) async.cancelTimer(pingTimerID);
        state = CLOSING;
        socket.close();
    }

}