Как приступить к автоматизации 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();
    }

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

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

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

1 комментарий

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *