WSS

Как приступить к автоматизации WebSocket API

Так, с REST API разобрались. Там есть ендпоинты, в которые можно швырять реквесты и получать ожидаемые респонсы, запихивая их в модели. А как же быть с WebSocket API, в основе которого лежит wss соединение. Клиент создает постоянное соединение с сервером и отправляет туда данные (тоже например в json формате) и получает ответы (необязательно), а также отправляет уведомления о том, что сообщение принято.

Ладно, как создать wss соединение с сервером? Подключим для начала через мавен библиотеку:

<dependency>
            <groupId>com.squareup.okhttp3</groupId>
            <artifactId>okhttp-ws</artifactId>
            <version>3.4.1</version>
</dependency>

Потом создаем новый класс, который будет поддерживать соединение и отвечать на запросы:

public final class WebSocketClient implements WebSocketListener

В этом классе заимплементим метод, который запускает соединение:

private final ExecutorService writeExecutor = Executors.newSingleThreadExecutor();
    private WebSocket sharedConnection;
    private int msgNumber = 900;

    public void run(String token) throws IOException, InterruptedException {
        String wssUrl = ConfigurationInstance.getInstance().getWssUrl(); // Получаем адрес wss api через конфигурацию нашу
        publicToken = token;

        OkHttpClient client = new OkHttpClient.Builder()
                .readTimeout(0,  TimeUnit.MILLISECONDS)
                .build();

        Log.console("Connecting to websocket...");

        Request request = new Request.Builder() // Добавляем актуальные хедеры для нашего апи
                .url(wssUrl)
                .addHeader("Authorization", "Bearer " + publicToken)
                .addHeader("Sec-WebSocket-Protocol", "json")
                .addHeader("User-Agent", "")
                .addHeader("Accept-Language", "ru-RU")
                .build();
        WebSocketCall.create(client, request).enqueue(this);

        // Trigger shutdown of the dispatcher's executor so this process can exit cleanly.
        client.dispatcher().executorService().shutdown();
    }

    @Override public void onOpen(final WebSocket webSocket, Response response) {
        writeExecutor.execute(new Runnable() {
            @Override public void run() {
                Log.console("Client '" + publicToken + "' ONLINE");
                sharedConnection = webSocket;
            }
        });
    }

И файналли создаем метод который триггерится когда приходит сообщение с сервера. Здесь мы уже конструируем базовое общение с сервером. Например, если приходит сообщение, на которое нужно подтверждение о получении, то отправляем его. А если приходит сообщение ping, отвечаем pong, таким образом давая понять, что соединение не разорвано:

@Override public void onMessage(ResponseBody message) throws IOException {
        String wsServerMessage = message.string();
        Log.console("< RECEIVED MESSAGE: " + wsServerMessage);

        JsonParser parser = new JsonParser();
        JsonElement element = parser.parse(wsServerMessage);
        JsonArray wsServerMessageArr = element.getAsJsonArray();

        String messageType = wsServerMessageArr.get(0).toString();
        String messageName = wsServerMessageArr.get(2).toString();
        String receivedMsgNumber = wsServerMessageArr.get(1).toString();

        if (Objects.equals(messageType, "1")) { // Сообщение типа 1 - нужно ответить что принял его

            JsonElement wsData = wsServerMessageArr.get(3);

            int answerType = 2;
            String ackMess = "[" + answerType + "," + msgNumber++ + "," + receivedMsgNumber + "]";
            Log.console("> SENDING MESSAGE: " + ackMess);
            sharedConnection.sendMessage(RequestBody.create(TEXT, ackMess)); // Отправляем 

        } else if (Objects.equals(messageType, "0")) { // 0 Сообщение типа 0 - отвечать не надо
            if (Objects.equals(messageName, "\"svc.ping\"")) { // Но если это пинг, то пингануть в ответ
                int answerType = 0;
                String answerMessageName = "svc.pong";

                String sendMsg = "[" + answerType + "," + msgNumber++ + ",\"" + answerMessageName + "\"]";
                Log.console("> SENDING MESSAGE: " + sendMsg);
                sharedConnection.sendMessage(RequestBody.create(TEXT, sendMsg));
            }
        }
        message.close();
    }

Далее в этом же классе реализуем методы, которые будут отправлять определенные сообщения на сервер при получении от него каких-то данных. Тут уже всё зависит от вашего апи, какие активности нужно покрыть. Этого я уже показывать не буду, разобраться далее не сложно.

Стоит отметить, что описанное вами далее специфичное общение сервером не отменяет вышеперечисленного базового общения, т.е. если на какое-то сообщение с сервера нужен определенного формата ответ, это не отменяет того, что сначала на него нужно ответить подтверждением получения, а потом уже отправлять ответ. Также и сервер вам будет отвечать подтверждениями получения ваших сообщений, можно это тоже обрабатывать и как минимум писать в лог.

Для начала понимания материала хватит, дальше изи должно быть.