mirror of
https://github.com/kunkundi/crossdesk-server.git
synced 2026-03-23 23:09:45 +08:00
[refactor] optimize Docker image size and build context
This commit is contained in:
36
.dockerignore
Normal file
36
.dockerignore
Normal file
@@ -0,0 +1,36 @@
|
||||
# Git
|
||||
.git
|
||||
.gitignore
|
||||
.github
|
||||
|
||||
# Build artifacts
|
||||
build/
|
||||
.xmake/
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
*.exe
|
||||
|
||||
# IDE
|
||||
.vs/
|
||||
.vscode/
|
||||
.idea/
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
|
||||
# Documentation
|
||||
*.md
|
||||
!README.md
|
||||
!README_EN.md
|
||||
|
||||
# Workflows (not needed in container)
|
||||
workflows/
|
||||
|
||||
# Docker files
|
||||
# docker/
|
||||
|
||||
# Temporary files
|
||||
*.log
|
||||
*.tmp
|
||||
*.cache
|
||||
@@ -1,22 +1,42 @@
|
||||
FROM ubuntu:22.04 AS builder
|
||||
|
||||
# Set non-interactive mode
|
||||
ENV DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
# Install build dependencies
|
||||
RUN apt-get update && \
|
||||
apt-get install -y software-properties-common git curl unzip build-essential && \
|
||||
add-apt-repository -y ppa:xmake-io/xmake && \
|
||||
apt-get install -y --no-install-recommends \
|
||||
ca-certificates \
|
||||
gnupg \
|
||||
software-properties-common \
|
||||
git \
|
||||
curl \
|
||||
unzip \
|
||||
build-essential
|
||||
|
||||
# Add xmake repository and install xmake
|
||||
RUN add-apt-repository -y ppa:xmake-io/xmake && \
|
||||
apt-get update && \
|
||||
apt-get install -y xmake && \
|
||||
apt-get install -y --no-install-recommends xmake && \
|
||||
xmake --version --root
|
||||
|
||||
# Clean up to reduce image size
|
||||
RUN apt-get clean && \
|
||||
rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/*
|
||||
|
||||
WORKDIR /src
|
||||
COPY . .
|
||||
|
||||
# Build and copy only the binary, clean up build artifacts
|
||||
RUN xmake b -vy --root crossdesk_server && \
|
||||
mkdir -p /output && \
|
||||
cp build/linux/x86_64/release/crossdesk_server /output/
|
||||
cp build/linux/x86_64/release/crossdesk_server /output/ && \
|
||||
rm -rf build .xmake
|
||||
|
||||
|
||||
FROM crossdesk/crossdesk-server-base:latest
|
||||
|
||||
# Generate coturn certificates and set permissions in one layer
|
||||
RUN mkdir -p /opt/turnserver && \
|
||||
cd /opt/turnserver && \
|
||||
openssl genrsa -out turn_server_pkey.pem 2048 && \
|
||||
@@ -27,11 +47,10 @@ RUN mkdir -p /opt/turnserver && \
|
||||
-out turn_server_cert.pem && \
|
||||
chmod 600 /opt/turnserver/turn_server_pkey.pem
|
||||
|
||||
|
||||
# Copy files and set permissions in one layer
|
||||
COPY docker/start.sh /start.sh
|
||||
COPY docker/generate_certs.sh /docker/generate_certs.sh
|
||||
COPY --from=builder /output/crossdesk_server /crossdesk-server/crossdesk_server
|
||||
|
||||
RUN chmod +x /start.sh /docker/generate_certs.sh /crossdesk-server/crossdesk_server
|
||||
|
||||
ENTRYPOINT ["/start.sh"]
|
||||
|
||||
@@ -70,8 +70,10 @@ echo "Signing server certificate with root certificate..."
|
||||
openssl x509 -req -in "$SERVER_CSR" -CA "$ROOT_CERT" -CAkey "$ROOT_KEY" -CAcreateserial \
|
||||
-out "$SERVER_CERT" -days 3650 -sha256 -extfile "$SAN_CONF" -extensions req_ext
|
||||
|
||||
# 6. 生成完整链证书
|
||||
# 6. 生成完整链证书并更新 bundle.crt(包含服务器证书和根证书)
|
||||
cat "$SERVER_CERT" "$ROOT_CERT" > "$FULLCHAIN_CERT"
|
||||
# 将完整证书链写入 bundle.crt,这样服务器可以使用完整的证书链
|
||||
cp "$FULLCHAIN_CERT" "$SERVER_CERT"
|
||||
|
||||
# 7. 清理中间文件
|
||||
rm -f "$ROOT_CERT.srl" "$SAN_CONF" "$ROOT_KEY" "$SERVER_CSR" "$FULLCHAIN_CERT"
|
||||
|
||||
@@ -80,8 +80,8 @@ exec turnserver -c "$CONF_FILE" &
|
||||
|
||||
# start crossdesk-server as main foreground process
|
||||
echo "Starting crossdesk-server..."
|
||||
# 程序现在使用固定目录:
|
||||
# - 数据库和配置文件:/var/lib/crossdesk
|
||||
# - 日志文件:/var/log/crossdesk
|
||||
# 只需传递端口参数
|
||||
./crossdesk-server/crossdesk_server ${CROSSDESK_SERVER_PORT}
|
||||
echo "Certificate directory: $CERT_DIR"
|
||||
echo "Certificate files:"
|
||||
ls -la "$CERT_DIR" || echo "Warning: Cannot list certificate directory"
|
||||
|
||||
exec ./crossdesk-server/crossdesk_server ${CROSSDESK_SERVER_PORT}
|
||||
12
src/main.cpp
12
src/main.cpp
@@ -24,8 +24,16 @@ int main(int argc, char* argv[]) {
|
||||
|
||||
InitLogger(log_dir);
|
||||
|
||||
SignalServer s(std::stoi(port), certs_dir, db_path);
|
||||
s.Run();
|
||||
try {
|
||||
SignalServer s(std::stoi(port), certs_dir, db_path);
|
||||
s.Run();
|
||||
} catch (std::exception& e) {
|
||||
LOG_ERROR("Fatal error: {}", e.what());
|
||||
return 1;
|
||||
} catch (...) {
|
||||
LOG_ERROR("Unknown fatal error occurred");
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "signal_server.h"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
|
||||
#include "common.h"
|
||||
@@ -113,6 +114,17 @@ context_ptr SignalServer::OnTlsInit(websocketpp::connection_hdl hdl) {
|
||||
|
||||
std::string cert_file = certs_dir_ + "/crossdesk.cn_bundle.crt";
|
||||
std::string key_file = certs_dir_ + "/crossdesk.cn.key";
|
||||
|
||||
// Check if certificate files exist
|
||||
if (!std::filesystem::exists(cert_file)) {
|
||||
LOG_ERROR("Certificate file not found: {}", cert_file);
|
||||
throw std::runtime_error("Certificate file not found: " + cert_file);
|
||||
}
|
||||
if (!std::filesystem::exists(key_file)) {
|
||||
LOG_ERROR("Private key file not found: {}", key_file);
|
||||
throw std::runtime_error("Private key file not found: " + key_file);
|
||||
}
|
||||
|
||||
ctx->use_certificate_chain_file(cert_file);
|
||||
ctx->use_private_key_file(key_file, asio::ssl::context::pem);
|
||||
|
||||
@@ -121,8 +133,11 @@ context_ptr SignalServer::OnTlsInit(websocketpp::connection_hdl hdl) {
|
||||
"ECDHE-RSA-AES256-GCM-SHA384:"
|
||||
"ECDHE-ECDSA-AES128-GCM-SHA256:"
|
||||
"ECDHE-RSA-AES128-GCM-SHA256");
|
||||
|
||||
LOG_INFO("TLS context initialized successfully");
|
||||
} catch (std::exception& e) {
|
||||
std::cout << "Exception: " << e.what() << std::endl;
|
||||
LOG_ERROR("Failed to initialize TLS context: {}", e.what());
|
||||
throw; // Re-throw to prevent invalid context from being used
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
@@ -142,12 +157,58 @@ void SignalServer::Run() {
|
||||
return;
|
||||
}
|
||||
|
||||
server_.set_reuse_addr(true);
|
||||
LOG_INFO("Signal server runs on port [{}]", port_);
|
||||
// Verify certificate files exist
|
||||
std::string cert_file = certs_dir_ + "/crossdesk.cn_bundle.crt";
|
||||
std::string key_file = certs_dir_ + "/crossdesk.cn.key";
|
||||
if (!std::filesystem::exists(cert_file)) {
|
||||
LOG_ERROR("Certificate file not found: {}", cert_file);
|
||||
return;
|
||||
}
|
||||
if (!std::filesystem::exists(key_file)) {
|
||||
LOG_ERROR("Private key file not found: {}", key_file);
|
||||
return;
|
||||
}
|
||||
|
||||
server_.listen(port_);
|
||||
server_.start_accept();
|
||||
server_.run();
|
||||
server_.set_reuse_addr(true);
|
||||
LOG_INFO("Signal server starting on port [{}]", port_);
|
||||
LOG_INFO("Certificate directory: [{}]", certs_dir_);
|
||||
LOG_INFO("Database path: [{}]", db_path_);
|
||||
|
||||
try {
|
||||
// Listen on all interfaces (0.0.0.0)
|
||||
namespace asio = websocketpp::lib::asio;
|
||||
asio::error_code ec;
|
||||
server_.listen(asio::ip::tcp::v4(), port_, ec);
|
||||
if (ec) {
|
||||
LOG_ERROR("Failed to listen on port {}: {}", port_, ec.message());
|
||||
return;
|
||||
}
|
||||
LOG_INFO("Successfully bound to port [{}]", port_);
|
||||
|
||||
server_.start_accept(ec);
|
||||
if (ec) {
|
||||
LOG_ERROR("Failed to start accepting connections: {}", ec.message());
|
||||
return;
|
||||
}
|
||||
LOG_INFO("Signal server listening on port [{}], waiting for connections...",
|
||||
port_);
|
||||
|
||||
server_.run();
|
||||
LOG_INFO("Server run() returned");
|
||||
} catch (std::exception& e) {
|
||||
LOG_ERROR("Server error: {}, attempting to restart...", e.what());
|
||||
// Try to restart the server
|
||||
try {
|
||||
server_.stop();
|
||||
server_.listen(port_);
|
||||
server_.start_accept();
|
||||
server_.run();
|
||||
} catch (std::exception& e2) {
|
||||
LOG_ERROR("Failed to restart server: {}", e2.what());
|
||||
}
|
||||
} catch (...) {
|
||||
LOG_ERROR("Unknown error occurred in server");
|
||||
}
|
||||
}
|
||||
|
||||
void SignalServer::SendMsg(websocketpp::connection_hdl hdl, json message) {
|
||||
@@ -164,43 +225,63 @@ void SignalServer::OnMessage(websocketpp::connection_hdl hdl,
|
||||
return;
|
||||
}
|
||||
|
||||
std::string payload = msg->get_payload();
|
||||
auto j = json::parse(payload);
|
||||
std::string type = j["type"].get<std::string>();
|
||||
|
||||
switch (HASH_STRING_PIECE(type.c_str())) {
|
||||
case "ping"_H: {
|
||||
if (transmission_manager_) {
|
||||
transmission_manager_->UpdateWsHandleLastActiveTime(hdl);
|
||||
json message = {{"type", "pong"}};
|
||||
server_.send(hdl, message.dump(), websocketpp::frame::opcode::text);
|
||||
}
|
||||
break;
|
||||
try {
|
||||
std::string payload = msg->get_payload();
|
||||
json j;
|
||||
try {
|
||||
j = json::parse(payload);
|
||||
} catch (json::parse_error& e) {
|
||||
LOG_ERROR("Failed to parse JSON message: {}", e.what());
|
||||
return;
|
||||
}
|
||||
case "login"_H:
|
||||
signal_negotiation_->login_user(hdl, j);
|
||||
break;
|
||||
case "user_leave_transmission"_H:
|
||||
signal_negotiation_->leave_transmission(hdl, j);
|
||||
break;
|
||||
case "query_user_id_list"_H:
|
||||
signal_negotiation_->query_user_id_list(hdl, j);
|
||||
break;
|
||||
case "join_transmission"_H:
|
||||
signal_negotiation_->join_transmission(hdl, j);
|
||||
break;
|
||||
case "offer"_H:
|
||||
signal_negotiation_->offer(hdl, j);
|
||||
break;
|
||||
case "answer"_H:
|
||||
signal_negotiation_->answer(hdl, j);
|
||||
break;
|
||||
case "new_candidate"_H:
|
||||
signal_negotiation_->new_candidate(hdl, j);
|
||||
break;
|
||||
case "new_candidate_mid"_H:
|
||||
signal_negotiation_->new_candidate_mid(hdl, j);
|
||||
default:
|
||||
break;
|
||||
|
||||
if (!j.contains("type")) {
|
||||
LOG_ERROR("Message missing 'type' field");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string type = j["type"].get<std::string>();
|
||||
|
||||
switch (HASH_STRING_PIECE(type.c_str())) {
|
||||
case "ping"_H: {
|
||||
if (transmission_manager_) {
|
||||
transmission_manager_->UpdateWsHandleLastActiveTime(hdl);
|
||||
json message = {{"type", "pong"}};
|
||||
server_.send(hdl, message.dump(), websocketpp::frame::opcode::text);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case "login"_H:
|
||||
signal_negotiation_->login_user(hdl, j);
|
||||
break;
|
||||
case "user_leave_transmission"_H:
|
||||
signal_negotiation_->leave_transmission(hdl, j);
|
||||
break;
|
||||
case "query_user_id_list"_H:
|
||||
signal_negotiation_->query_user_id_list(hdl, j);
|
||||
break;
|
||||
case "join_transmission"_H:
|
||||
signal_negotiation_->join_transmission(hdl, j);
|
||||
break;
|
||||
case "offer"_H:
|
||||
signal_negotiation_->offer(hdl, j);
|
||||
break;
|
||||
case "answer"_H:
|
||||
signal_negotiation_->answer(hdl, j);
|
||||
break;
|
||||
case "new_candidate"_H:
|
||||
signal_negotiation_->new_candidate(hdl, j);
|
||||
break;
|
||||
case "new_candidate_mid"_H:
|
||||
signal_negotiation_->new_candidate_mid(hdl, j);
|
||||
break;
|
||||
default:
|
||||
LOG_WARN("Unknown message type: {}", type);
|
||||
break;
|
||||
}
|
||||
} catch (std::exception& e) {
|
||||
LOG_ERROR("Error processing message: {}", e.what());
|
||||
} catch (...) {
|
||||
LOG_ERROR("Unknown error processing message");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user