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