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

org.kde.brooklyn.RocketChatBot Maven / Gradle / Ivy

Go to download

Canaveral is a Java wrapper for Rocket.Chat Realtime API designed to support bots.

There is a newer version: 0.6.6
Show newest version
/*
 * Copyright 2017 Davide Riva [email protected]
 *
 * Permission to use, copy, modify, and distribute this software
 * and its documentation for any purpose and without fee is hereby
 * granted, provided that the above copyright notice appear in all
 * copies and that both that the copyright notice and this
 * permission notice and warranty disclaimer appear in supporting
 * documentation, and that the name of the author not be used in
 * advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.
 *
 * The author disclaim all warranties with regard to this
 * software, including all implied warranties of merchantability
 * and fitness.  In no event shall the author be liable for any
 * special, indirect or consequential damages or any damages
 * whatsoever resulting from loss of use, data or profits, whether
 * in an action of contract, negligence or other tortious action,
 * arising out of or in connection with the use or performance of
 * this software.
 */

package org.kde.brooklyn;

import org.java_websocket.client.WebSocketClient;
import org.java_websocket.handshake.ServerHandshake;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;

import javax.net.ssl.SSLSocketFactory;
import java.io.IOException;
import java.net.URI;
import java.util.*;

public abstract class RocketChatBot extends WebSocketClient implements AutoCloseable {
    private final String username;
    private final String password;
    private final Object isLoggedSync = new Object();
    private final Map rooms = new HashMap<>();
    private final List roomUsers = new LinkedList<>();
    private int idCounter = 1;
    private int msgIdCounter = 1;

    private String roomsInfoId = "-1";
    private String loginId = "-1";
    private String usersListId = "-1";

    private boolean isLogged = false;

    private boolean debug = false;

    public RocketChatBot(final URI websocketURI,
                         final String username, final String password,
                         boolean debug) throws RocketChatException {
        this(websocketURI, username, password);
        this.debug = debug;
    }

    public RocketChatBot(final URI websocketURI,
                         final String username, final String password)
            throws RocketChatException {
        super(websocketURI);

        this.username = username;
        this.password = password;

        try {
            setSocket(SSLSocketFactory.getDefault().createSocket(websocketURI.getHost(), 443));
            super.connectBlocking();
        } catch (IOException | InterruptedException e) {
            throw new RocketChatException("Failed to connect to " + websocketURI.toString(), e);
        }

        // Don't return unless you know if you're logged or not
        final long timeout = 3000;
        final String loginFailedMsg = "Login failed. ";
        try {
            synchronized (isLoggedSync) {
                isLoggedSync.wait(timeout);
            }
        } catch (InterruptedException e) {
            super.close();
            throw new RocketChatException(loginFailedMsg, e);
        }
        if (!isLogged) {
            super.close();
            throw new RocketChatException(loginFailedMsg);
        }
    }

    public boolean isLogged() {
        return isLogged;
    }

    public String getRoomName(String roomId) {
        return rooms.getOrDefault(roomId, roomId);
    }

    private synchronized String getNextId() {
        return new Date().getTime() + "-" + Integer.toString(idCounter++);
    }

    private synchronized String getNextMsgId() {
        return new Date().getTime() + "-" + Integer.toString(msgIdCounter++);
    }

    private JSONObject generateMethodCall(final String method, final JSONArray params) {
        final JSONObject methodCall = generateCall("method");
        methodCall.put("method", method);
        methodCall.put("params", params);

        return methodCall;
    }

    private JSONObject generateSubscriptionCall(final String name, final JSONArray params) {
        final JSONObject subscriptionCall = generateCall("sub");
        subscriptionCall.put("id", getNextId());
        subscriptionCall.put("name", name);
        subscriptionCall.put("params", params);

        return subscriptionCall;
    }

    private JSONObject generateCall(final String msg) {
        final JSONObject call = new JSONObject();
        call.put("msg", msg);
        call.put("id", getNextId());
        return call;
    }

    @Override
    public void onOpen(ServerHandshake serverHandshake) {
        connectMessage();
    }

    private void connectMessage() {
        final JSONObject connect = new JSONObject();
        connect.put("msg", "connect");
        connect.put("version", "1");

        final JSONArray support = new JSONArray();
        support.add("1");
        connect.put("support", support);

        super.send(connect.toString());
    }

    private JSONObject generateMessageObject(final String text,
                                             final String msgId, final String roomId,
                                             final Optional alias) {
        final JSONObject message = new JSONObject();
        message.put("_id", msgId);
        message.put("rid", roomId);
        message.put("msg", text);
        alias.ifPresent(a -> message.put("alias", a));

        return message;
    }

    public String sendMessage(final String text, final String roomId,
                              final Optional alias) {
        final String msgId = getNextMsgId();

        final JSONArray params = new JSONArray();
        params.add(generateMessageObject(text, msgId, roomId, alias));
        final JSONObject sendMessage = generateMethodCall("sendMessage", params);

        super.send(sendMessage.toString());
        return msgId;
    }

    public void updateMessage(final String text, final String msgId, final String roomId) {
        final JSONArray params = new JSONArray();
        params.add(generateMessageObject(text, msgId, roomId, Optional.empty()));
        final JSONObject updateMessage = generateMethodCall("updateMessage", params);
        super.send(updateMessage.toString());
    }

    private void loginMethod() {
        final JSONObject loginParams = new JSONObject();

        final JSONObject user = new JSONObject();
        user.put("username", username);
        loginParams.put("user", user);
        loginParams.put("password", password);

        final JSONArray params = new JSONArray();
        params.add(loginParams);

        final JSONObject loginMethod = generateMethodCall("login", params);
        loginId = (String) loginMethod.get("id");
        super.send(loginMethod.toString());
    }

    @Override
    public void onMessage(String s) {
        try {
            final JSONObject message = (JSONObject) new JSONParser().parse(s);

            if (debug)
                System.out.println("Message: " + message.toString());

            final String msgKey = "msg";
            if (message.containsKey(msgKey)) {
                final String msg = (String) message.get(msgKey);
                if ("error".equals(msg))
                    System.err.println("Error: " + message.toString());
                else if ("ping".equals(msg)) {
                    final JSONObject pong = new JSONObject();
                    pong.put("msg", "pong");
                    super.send(pong.toString());
                } else if ("connected".equals(msg))
                    loginMethod();
                else if ("changed".equals(msg)) {
                    if (message.containsKey("collection")) {
                        final JSONObject fields = (JSONObject) message.get("fields");
                        final JSONArray args = (JSONArray) fields.get("args");
                        for (Object arg : args)
                            manageMessageReceived((JSONObject) arg);
                    }
                } else if (message.containsKey("id")) {
                    final String id = (String) message.get("id");
                    if (id.equals(loginId))
                        manageLogin(message);
                    else if (id.equals(roomsInfoId))
                        manageRoomsInfo(message);
                    else if (id.equals(usersListId))
                        manageUsersList(message);
                }
            }
        } catch (ParseException e) {
            System.err.println("Message received is not a valid JSON: ");
            e.printStackTrace();
        }
    }

    private void manageUsersList(JSONObject message) {
        final JSONObject result = (JSONObject) message.get("result");
        final JSONArray records = (JSONArray) result.get("records");

        for (Object record : records) {
            final JSONObject user = (JSONObject) record;
            final String username = (String) user.get("username");
            roomUsers.add(username);
        }

        synchronized (roomUsers) {
            roomUsers.notifyAll();
        }
    }

    private void manageRoomsInfo(final JSONObject message) {
        final JSONObject result = (JSONObject) message.get("result");
        final JSONArray update = (JSONArray) result.get("update");
        final JSONArray remove = (JSONArray) result.get("remove");

        for (Object room : update) manageRoomInfo((JSONObject) room);
        for (Object room : remove) manageRoomInfo((JSONObject) room);
    }

    private void manageRoomInfo(final JSONObject room) {
        final String t = (String) room.get("t");
        if (t.equals("c")) {
            final String name = (String) room.get("name");
            final String id = (String) room.get("_id");
            rooms.put(id, name);
        }
    }

    private void manageMessageReceived(final JSONObject message) {
        final RocketChatMessage rcMsg = RocketChatMessage.parse(message);
        // It is an edited message
        if (message.containsKey("editedBy"))
            onMessageEdited(rcMsg);
        else
            onMessageReceived(rcMsg);
    }

    protected abstract void onMessageReceived(final RocketChatMessage message);

    protected abstract void onMessageEdited(final RocketChatMessage message);

    private void manageLogin(JSONObject message) {
        final String resultKey = "result";
        if (message.containsKey(resultKey)) {
            final JSONObject result = (JSONObject) message.get(resultKey);

            final String tokenKey = "token";
            if (result.containsKey(tokenKey)) {
                isLogged = true;
                getRoomsInfo();
                synchronized (isLoggedSync) {
                    isLoggedSync.notifyAll();
                }
            }
        } else
            isLogged = false;
    }

    private void getRoomsInfo() {
        final JSONObject date = new JSONObject();
        date.put("$date", 0);
        final JSONArray params = new JSONArray();
        params.add(date);
        final JSONObject message = generateMethodCall("rooms/get", params);
        roomsInfoId = (String) message.get("id");

        super.send(message.toString());

    }

    @Override
    public void onClose(int i, String s, boolean b) {
    }

    @Override
    public void onError(Exception e) {
        e.printStackTrace();
    }

    public void addRoom(final String roomId) {
        final JSONArray params = new JSONArray();
        params.add(roomId);
        params.add(false);
        final JSONObject stream = generateSubscriptionCall("stream-room-messages", params);
        super.send(stream.toString());
    }

    public List getUsers(String roomId) {
        final JSONArray params = new JSONArray();
        params.add(roomId);
        params.add(false);

        final JSONObject method = generateMethodCall("getUsersOfRoom", params);
        usersListId = (String) method.get("id");

        super.send(method.toString());
        try {
            synchronized (roomUsers) {
                roomUsers.wait();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        List users = new ArrayList<>(roomUsers);
        roomUsers.clear();
        return users;
    }

    @Override
    public void close() {
        super.close();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy