This repository has been archived on 2025-06-24. You can view files and clone it, but cannot push or open issues or pull requests.
superstar/TCPServer.cs

367 lines
17 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Text.RegularExpressions;
using System.Drawing;
using System.Threading.Tasks;
using System.IO; // 為 Path 和 File 提供支持
using System.Windows.Forms; // 為 Invoke 和 Form 控件提供支持
using System.Collections.Generic;
using DBObj;
using OverlayFormObj;
namespace DualScreenDemo
{
public class TCPServer
{
private TcpListener listener;
private const int Port = 1000;
private readonly string hostNameSuffix;
//private bool isProcessingCommand = false;
public TCPServer()
{
listener = new TcpListener(IPAddress.Any, Port);
hostNameSuffix = GetHostNameSuffix();
}
private bool IsFormReady(Form form)
{
if (form == null) return false;
bool isReady = false;
try
{
if (form.IsHandleCreated && !form.IsDisposed)
{
if (form.InvokeRequired)
{
form.Invoke(new Action(() => isReady = true));
}
else
{
isReady = true;
}
}
}
catch
{
isReady = false;
}
return isReady;
}
private async Task SafeInvoke(Form form, Action action, int maxRetries = 10)
{
if (form == null) return;
for (int i = 0; i < maxRetries; i++)
{
try
{
if (IsFormReady(form))
{
if (form.InvokeRequired)
{
form.Invoke(action);
}
else
{
action();
}
return;
}
}
catch (Exception ex)
{
Console.WriteLine($"Invoke attempt {i + 1} failed: {ex.Message}");
}
await Task.Delay(500); // 等待500毫秒后重试
}
Console.WriteLine("Failed to invoke action after maximum retries");
}
public void Start()
{
// 啟動 TCP 監聽器
listener.Start();
Console.WriteLine("Server started on port " + Port + ".");
try {
// 讀取初始狀態檔案
string stateFilePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "states.txt");
string initialState = ReadStateFile(stateFilePath);
// 若初始狀態為 "CLOSE",則顯示送客畫面,並禁用所有主畫面的控制項
if (initialState.Equals("CLOSE", StringComparison.OrdinalIgnoreCase))
{
_ = SafeInvoke(PrimaryForm.Instance, () =>
{
try {
foreach (Control ctrl in PrimaryForm.Instance.Controls)
{
ctrl.Enabled = false;
}
PrimaryForm.Instance.ShowSendOffScreen();
}
catch (Exception ex) {
Console.WriteLine($"顯示送客畫面時發生錯誤: {ex.Message}");
}
});
}
// 不斷等待並處理 TCP 連線
while (true)
{
Console.WriteLine("Waiting for connections...");
using (TcpClient client = listener.AcceptTcpClient())
{
Console.WriteLine("Connected!");
NetworkStream stream = client.GetStream();
// 處理來自 client 的指令
while (client.Connected)
{
byte[] buffer = new byte[1024];
int bytesRead = stream.Read(buffer, 0, buffer.Length);
if (bytesRead == 0)
break;
string request = Encoding.UTF8.GetString(buffer, 0, bytesRead);
Console.WriteLine("Received: " + request.Trim());
// 忽略長度太短的請求
if (request.Length < 5)
{
continue;
}
// 解析 host 名稱字尾與指令本體
string requestHostSuffix = request.Substring(0, 3);
string command = request.Substring(4);
// 比對主機名稱是否符合
if (requestHostSuffix.Equals(hostNameSuffix, StringComparison.OrdinalIgnoreCase))
{
// 指令為 "X":播放 CLOSE.MPG並顯示送客畫面
if (command.Trim().Equals("X", StringComparison.OrdinalIgnoreCase))
{
PrimaryForm.Instance.pictureBoxQRCode.Visible = false;
PrimaryForm.Instance.closeQRCodeButton.Visible = false;
_ = SafeInvoke(VideoPlayerForm.Instance, async () =>
{
if (IsFormReady(PrimaryForm.Instance))
{
await SafeInvoke(PrimaryForm.Instance, async () =>
{
PrimaryForm.Instance.ShowSendOffScreen();
PrimaryForm.Instance.HideFireScreen();
string marqueeMessage= "歡迎使用網路版系統,與你共度美好時光。";
OverlayForm.MainForm.UpdateMarqueeText(marqueeMessage, OverlayForm.MarqueeStartPosition.Middle, Color.White);
Console.WriteLine("開始設置新的播放列表");
string closePath = @"C:\video\CLOSE.MPG";
if (File.Exists(closePath))
{
// 建立結束播放用的 SongData 實例
SongData closeSong = new SongData(
"", "", "結束播放", 0, "", "", "", "",
DateTime.Now, closePath, "", "", "", "",
"", "", "", "", "", "", "", 1
);
// 建立新的播放清單
VideoPlayerForm.publicPlaylist = new List<SongData>();
VideoPlayerForm.playingSongList = new List<SongData>();
PrimaryForm.playedSongsHistory = new List<SongData>();
// 如果有正在播放的歌曲也加進去
if (VideoPlayerForm.Instance.currentPlayingSong != null)
{
VideoPlayerForm.playingSongList.Add(VideoPlayerForm.Instance.currentPlayingSong);
}
VideoPlayerForm.publicPlaylist.Add(closeSong);
// 將 CLOSE.MPG 加入播放清單
VideoPlayerForm.playingSongList.Add(closeSong);
// 清空使用者點播清單
PrimaryForm.userRequestedSongs = new List<SongData>();
// 隱藏 Overlay 的「下一首提示」
if (IsFormReady(OverlayForm.MainForm))
{
OverlayForm.MainForm.nextSongLabel.Visible = false;
}
VideoPlayerForm.Instance.PlayNextSong();
Console.WriteLine("已設置新的播放列表,包含當前歌曲和 CLOSE.MPG");
try
{
await HttpServer.RestartServer();
}
catch (Exception ex)
{
Console.WriteLine("RestartServer 發生錯誤: " + ex.Message);
}
}
else
{
Console.WriteLine($"錯誤: 找不到檔案 {closePath}");
}
});
}
});
// 更新狀態檔案為 CLOSE
UpdateStateFile(stateFilePath, "CLOSE");
continue;
}
// 指令為 "O":開啟系統,隱藏送客畫面
if (command.Trim().Equals("O", StringComparison.OrdinalIgnoreCase))
{
_ = SafeInvoke(PrimaryForm.Instance, () =>
{
PrimaryForm.Instance.HideSendOffScreen();
PrimaryForm.Instance.HideFireScreen();
string marqueeMessage= "歡迎使用網路版系統,與你共度美好時光。";
OverlayForm.MainForm.UpdateMarqueeText(marqueeMessage, OverlayForm.MarqueeStartPosition.Middle, Color.White);
});
VideoPlayerForm.publicPlaylist = new List<SongData>();
VideoPlayerForm.playingSongList = new List<SongData>();
VideoPlayerForm.Instance.PlayPublicPlaylist(); // 播放公播
// 更新狀態檔案為 OPEN
UpdateStateFile(stateFilePath, "OPEN");
continue;
}
if (command.Trim().Equals("F", StringComparison.OrdinalIgnoreCase))
{
_ = SafeInvoke(PrimaryForm.Instance, () =>
{
PrimaryForm.Instance.HideSendOffScreen();
PrimaryForm.Instance.ShowFireScreen();
VideoPlayerForm.Instance.Pause();
string marqueeMessage = "發生火災,請跟隨引導至逃生出口!!!";
OverlayForm.MainForm.UpdateMarqueeText(marqueeMessage, OverlayForm.MarqueeStartPosition.Middle, Color.Red);
});
// 更新狀態檔案(可選,若你要記錄狀態)
UpdateStateFile(stateFilePath, "PAUSE");
continue;
}
}
// 若 Overlay Form 準備好,嘗試顯示跑馬燈文字
if (IsFormReady(OverlayForm.MainForm))
{
string message = request.Trim();
string pattern = @"^(全部|\d{4})\((白色|紅色|綠色|黑色|藍色)\)-";
Match match = Regex.Match(message, pattern);
_ = SafeInvoke(OverlayForm.MainForm, () =>
{
if (match.Success)
{
// 若符合格式,顯示主跑馬燈文字
string marqueeMessage = message.Substring(match.Value.Length).Trim();
Color textColor = GetColorFromString(match.Groups[2].Value);
OverlayForm.MainForm.UpdateMarqueeText(marqueeMessage, OverlayForm.MarqueeStartPosition.Middle, textColor);
}
else
{
// 不符合格式,顯示在第二行跑馬燈
string marqueeMessage = "系統公告: " + message;
OverlayForm.MainForm.UpdateMarqueeTextSecondLine(marqueeMessage);
}
});
}
// 指令為 "exit":結束此連線
if (request.Trim().Equals("exit", StringComparison.OrdinalIgnoreCase))
{
break;
}
}
Console.WriteLine("Connection closed.");
}
}
}
catch (Exception e)
{
Console.WriteLine($"Error: {e.Message}");
}
finally
{
// 關閉 listener
listener.Stop();
}
}
private Color GetColorFromString(string colorName)
{
switch (colorName)
{
case "白色":
return Color.White;
case "紅色":
return Color.Red;
case "綠色":
return Color.LightGreen;
case "黑色":
return Color.Black;
case "藍色":
return Color.LightBlue;
default:
return Color.Black;
}
}
private string GetHostNameSuffix()
{
string hostName = Dns.GetHostName();
return hostName.Length > 3 ? hostName.Substring(hostName.Length - 3) : hostName;
}
private string ReadStateFile(string filePath)
{
try
{
if (File.Exists(filePath))
{
string state = File.ReadAllText(filePath).Trim();
Console.WriteLine($"✅ State file read: {filePath} -> {state}");
return state;
}
else
{
Console.WriteLine("⚠️ State file not found. Creating new file with default state: OPEN");
UpdateStateFile(filePath, "OPEN");
return "OPEN";
}
}
catch (Exception ex)
{
Console.WriteLine($"❌ Failed to read state file: {ex.Message}");
return "OPEN"; // 默認為 OPEN
}
}
private void UpdateStateFile(string filePath, string state)
{
try
{
File.WriteAllText(filePath, state);
Console.WriteLine($"✅ State file updated: {filePath} -> {state}");
}
catch (Exception ex)
{
Console.WriteLine($"❌ Failed to update state file: {ex.Message}");
}
}
}
}