17c804472Sopenharmony_ci/*
27c804472Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
37c804472Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
47c804472Sopenharmony_ci * you may not use this file except in compliance with the License.
57c804472Sopenharmony_ci * You may obtain a copy of the License at
67c804472Sopenharmony_ci *
77c804472Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
87c804472Sopenharmony_ci *
97c804472Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
107c804472Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
117c804472Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
127c804472Sopenharmony_ci * See the License for the specific language governing permissions and
137c804472Sopenharmony_ci * limitations under the License.
147c804472Sopenharmony_ci */
157c804472Sopenharmony_ci
167c804472Sopenharmony_ci#include <atomic>
177c804472Sopenharmony_ci#include <thread>
187c804472Sopenharmony_ci#include "CommandLineInterface.h"
197c804472Sopenharmony_ci#include "PreviewerEngineLog.h"
207c804472Sopenharmony_ci#include "WebSocketServer.h"
217c804472Sopenharmony_ci
227c804472Sopenharmony_cilws* WebSocketServer::webSocket = nullptr;
237c804472Sopenharmony_cistd::atomic<bool> WebSocketServer::interrupted = false;
247c804472Sopenharmony_ciWebSocketServer::WebSocketState WebSocketServer::webSocketWritable = WebSocketState::INIT;
257c804472Sopenharmony_ciuint8_t* WebSocketServer::firstImageBuffer = nullptr;
267c804472Sopenharmony_ciuint64_t WebSocketServer::firstImagebufferSize = 0;
277c804472Sopenharmony_ci
287c804472Sopenharmony_ciWebSocketServer::WebSocketServer() : serverThread(nullptr), serverPort(0)
297c804472Sopenharmony_ci{
307c804472Sopenharmony_ci    protocols[0] = {"ws", WebSocketServer::ProtocolCallback, 0, MAX_PAYLOAD_SIZE};
317c804472Sopenharmony_ci    protocols[1] = {NULL, NULL, 0, 0};
327c804472Sopenharmony_ci}
337c804472Sopenharmony_ci
347c804472Sopenharmony_ciWebSocketServer::~WebSocketServer() {}
357c804472Sopenharmony_ci
367c804472Sopenharmony_ciWebSocketServer& WebSocketServer::GetInstance()
377c804472Sopenharmony_ci{
387c804472Sopenharmony_ci    static WebSocketServer server;
397c804472Sopenharmony_ci    return server;
407c804472Sopenharmony_ci}
417c804472Sopenharmony_ci
427c804472Sopenharmony_civoid WebSocketServer::SetServerPort(int port)
437c804472Sopenharmony_ci{
447c804472Sopenharmony_ci    serverPort = port;
457c804472Sopenharmony_ci}
467c804472Sopenharmony_ci
477c804472Sopenharmony_ciint WebSocketServer::ProtocolCallback(struct lws* wsi,
487c804472Sopenharmony_ci                                      enum lws_callback_reasons reason,
497c804472Sopenharmony_ci                                      void* user,
507c804472Sopenharmony_ci                                      void* in,
517c804472Sopenharmony_ci                                      size_t len)
527c804472Sopenharmony_ci{
537c804472Sopenharmony_ci    switch (reason) {
547c804472Sopenharmony_ci        case LWS_CALLBACK_PROTOCOL_INIT:
557c804472Sopenharmony_ci            ILOG("Engine Websocket protocol init");
567c804472Sopenharmony_ci            break;
577c804472Sopenharmony_ci        case LWS_CALLBACK_ESTABLISHED:
587c804472Sopenharmony_ci            ILOG("Websocket client connect");
597c804472Sopenharmony_ci            webSocket = wsi;
607c804472Sopenharmony_ci            lws_callback_on_writable(wsi);
617c804472Sopenharmony_ci            break;
627c804472Sopenharmony_ci        case LWS_CALLBACK_RECEIVE:
637c804472Sopenharmony_ci            break;
647c804472Sopenharmony_ci        case LWS_CALLBACK_SERVER_WRITEABLE:
657c804472Sopenharmony_ci            ILOG("Engine websocket server writeable");
667c804472Sopenharmony_ci            if (firstImagebufferSize > 0 && webSocketWritable == WebSocketState::UNWRITEABLE) {
677c804472Sopenharmony_ci                ILOG("Send last image after websocket reconnected");
687c804472Sopenharmony_ci                std::lock_guard<std::mutex> guard(WebSocketServer::GetInstance().mutex);
697c804472Sopenharmony_ci                lws_write(wsi,
707c804472Sopenharmony_ci                          firstImageBuffer + LWS_PRE,
717c804472Sopenharmony_ci                          firstImagebufferSize,
727c804472Sopenharmony_ci                          LWS_WRITE_BINARY);
737c804472Sopenharmony_ci            }
747c804472Sopenharmony_ci            webSocketWritable = WebSocketState::WRITEABLE;
757c804472Sopenharmony_ci            break;
767c804472Sopenharmony_ci        case LWS_CALLBACK_CLOSED:
777c804472Sopenharmony_ci            ILOG("Websocket client connection closed");
787c804472Sopenharmony_ci            webSocketWritable = WebSocketState::UNWRITEABLE;
797c804472Sopenharmony_ci            break;
807c804472Sopenharmony_ci        default:
817c804472Sopenharmony_ci            break;
827c804472Sopenharmony_ci    }
837c804472Sopenharmony_ci    return 0;
847c804472Sopenharmony_ci}
857c804472Sopenharmony_ci
867c804472Sopenharmony_civoid WebSocketServer::SignalHandler(int sig)
877c804472Sopenharmony_ci{
887c804472Sopenharmony_ci    interrupted = true;
897c804472Sopenharmony_ci}
907c804472Sopenharmony_ci
917c804472Sopenharmony_civoid WebSocketServer::StartWebsocketListening()
927c804472Sopenharmony_ci{
937c804472Sopenharmony_ci    const auto sig = signal(SIGINT, SignalHandler);
947c804472Sopenharmony_ci    if (sig == SIG_ERR) {
957c804472Sopenharmony_ci        ELOG("StartWebsocketListening failed");
967c804472Sopenharmony_ci        return;
977c804472Sopenharmony_ci    }
987c804472Sopenharmony_ci    ILOG("Begin to start websocket listening!");
997c804472Sopenharmony_ci    struct lws_context_creation_info contextInfo = {0};
1007c804472Sopenharmony_ci    contextInfo.port = serverPort;
1017c804472Sopenharmony_ci    contextInfo.iface = serverHostname;
1027c804472Sopenharmony_ci    contextInfo.protocols = protocols;
1037c804472Sopenharmony_ci    contextInfo.ip_limit_wsi = websocketMaxConn;
1047c804472Sopenharmony_ci    contextInfo.options  = LWS_SERVER_OPTION_VALIDATE_UTF8;
1057c804472Sopenharmony_ci    struct lws_context* context = lws_create_context(&contextInfo);
1067c804472Sopenharmony_ci    if (context == nullptr) {
1077c804472Sopenharmony_ci        ELOG("WebSocketServer::StartWebsocketListening context memory allocation failed");
1087c804472Sopenharmony_ci        return;
1097c804472Sopenharmony_ci    }
1107c804472Sopenharmony_ci    while (!interrupted) {
1117c804472Sopenharmony_ci        if (lws_service(context, WEBSOCKET_SERVER_TIMEOUT)) {
1127c804472Sopenharmony_ci            interrupted = true;
1137c804472Sopenharmony_ci        }
1147c804472Sopenharmony_ci    }
1157c804472Sopenharmony_ci    lws_context_destroy(context);
1167c804472Sopenharmony_ci}
1177c804472Sopenharmony_ci
1187c804472Sopenharmony_civoid WebSocketServer::Run()
1197c804472Sopenharmony_ci{
1207c804472Sopenharmony_ci    serverThread = std::make_unique<std::thread>([this]() {
1217c804472Sopenharmony_ci        this->StartWebsocketListening();
1227c804472Sopenharmony_ci    });
1237c804472Sopenharmony_ci    if (serverThread == nullptr) {
1247c804472Sopenharmony_ci        ELOG("WebSocketServer::Start serverThread memory allocation failed");
1257c804472Sopenharmony_ci    }
1267c804472Sopenharmony_ci    serverThread->detach();
1277c804472Sopenharmony_ci}
1287c804472Sopenharmony_ci
1297c804472Sopenharmony_cisize_t WebSocketServer::WriteData(unsigned char* data, size_t length)
1307c804472Sopenharmony_ci{
1317c804472Sopenharmony_ci    while (webSocketWritable != WebSocketState::WRITEABLE) {
1327c804472Sopenharmony_ci        std::this_thread::sleep_for(std::chrono::milliseconds(1));
1337c804472Sopenharmony_ci    }
1347c804472Sopenharmony_ci    if (webSocket != nullptr && webSocketWritable == WebSocketState::WRITEABLE) {
1357c804472Sopenharmony_ci        return lws_write(webSocket, data, length, LWS_WRITE_BINARY);
1367c804472Sopenharmony_ci    }
1377c804472Sopenharmony_ci    return 0;
1387c804472Sopenharmony_ci}
139