#if !UNITY_WEBGL using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.WebSockets; namespace ET { public class WService: AService { private long idGenerater = 200000000; private HttpListener httpListener; private readonly Dictionary channels = new Dictionary(); public WService(ThreadSynchronizationContext threadSynchronizationContext, IEnumerable prefixs) { this.ThreadSynchronizationContext = threadSynchronizationContext; this.httpListener = new HttpListener(); StartAccept(prefixs).Coroutine(); } public WService(ThreadSynchronizationContext threadSynchronizationContext) { this.ThreadSynchronizationContext = threadSynchronizationContext; } private long GetId { get { return ++this.idGenerater; } } public WChannel Create(string address, long id) { ClientWebSocket webSocket = new ClientWebSocket(); WChannel channel = new WChannel(id, webSocket, address, this); this.channels[channel.Id] = channel; return channel; } public override void Remove(long id) { WChannel channel; if (!this.channels.TryGetValue(id, out channel)) { return; } this.channels.Remove(id); channel.Dispose(); } public override bool IsDispose() { return this.httpListener == null; } protected void Get(long id, string address) { if (!this.channels.TryGetValue(id, out _)) { this.Create(address, id); } } public override void Dispose() { this.ThreadSynchronizationContext = null; this.httpListener?.Close(); this.httpListener = null; } private async ETTask StartAccept(IEnumerable prefixs) { try { foreach (string prefix in prefixs) { this.httpListener.Prefixes.Add(prefix); Log.Console($"start {prefix}"); } httpListener.Start(); while (true) { var context = await this.httpListener.GetContextAsync(); Log.Info($"Accept WebSocket {context.Request.RemoteEndPoint}"); //跨域设置 { context.Response.AddHeader("Access-Control-Allow-Credentials", "true"); context.Response.AddHeader("Access-Control-Allow-Headers", "content-type, Signature, Timestamp, Token"); context.Response.AddHeader("Access-Control-Allow-Methods", "POST"); context.Response.AddHeader("Access-Control-Allow-Origin", "*"); if (context.Request.HttpMethod == "OPTIONS") { context.Response.StatusCode = 204; } } if (context.Request.IsWebSocketRequest) { var webSocket = await context.AcceptWebSocketAsync(null); WChannel channel = new WChannel(this.GetId, webSocket.WebSocket, this, context.Request.RemoteEndPoint); this.channels[channel.Id] = channel; this.OnAccept(channel.Id, channel.RemoteAddress); } else { context.Response.StatusCode = 400; context.Response.Close(); } } } catch (HttpListenerException e) { if (e.ErrorCode == 5) { throw new Exception($"CMD管理员中输入: netsh http add urlacl url=http://{string.Join(",", prefixs)}/ user=Everyone", e); } Log.Error(e); } catch (Exception e) { Log.Error(e); } } protected override void Get(long id, IPEndPoint address) { // 将IPEndPoint转换为WebSocket适用的地址格式(ws://或wss://) string webSocketAddress = $"ws://{address.Address}:{address.Port}"; // 检查是否已存在该通道 if (!this.channels.TryGetValue(id, out _)) { // 不存在则创建新的WebSocket连接 this.Create(webSocketAddress, id); } } protected override void Send(long channelId, long actorId, MemoryStream stream) { this.channels.TryGetValue(channelId, out WChannel channel); if (channel == null) { return; } channel.Send(stream); } public override void Update() { } } } #endif