rBits.exe服务备份

发布于:2025-02-10 ⋅ 阅读:(139) ⋅ 点赞:(0)

Program.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;

namespace rBits
{
    internal static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        static void Main()
        {
            ServiceBase[] ServicesToRun;
            ServicesToRun = new ServiceBase[]
            {
                new Service1()
            };
            ServiceBase.Run(ServicesToRun);
        }
    }
}

Service1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Linq;
using System.ServiceProcess;
using System.Text;
using System.Threading.Tasks;
using Notify;
using Notify.Log;

namespace rBits
{
    public partial class Service1 : ServiceBase
    {
        private TcpServer rBits;
        private NtLog log = new NtLog();
        public Service1()
        {
            InitializeComponent();
            rBits = new TcpServer("127.0.0.1", 8421);
            //订阅事件
            rBits.LogReady += log.OnLogging;
        }

        protected override void OnStart(string[] args)
        {
            string path = AppDomain.CurrentDomain.BaseDirectory;
            path += "\\VerCtrl.Cfg.json";
            rBits.ReadCtrlVersionCfg(path);
            rBits.Startup();
        }

        protected override void OnStop()
        {
            rBits.Stop();
        }
    }
}

ProjectInstall.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Configuration.Install;
using System.Linq;
using System.Threading.Tasks;

namespace rBits
{
    [RunInstaller(true)]
    public partial class ProjectInstaller : System.Configuration.Install.Installer
    {
        public ProjectInstaller()
        {
            InitializeComponent();
        }
    }
}

Libraries.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Net.Http.Headers;
using System.Net.Http;
using System.Xml.Linq;
using System.IO;
using System.Diagnostics;
using System.Net.Mail;
using System.Net.Configuration;
using System.Reflection;
using System.IO.Compression;
//不常用的库
//using Microsoft.Data.Sqlite;
//以下是第三方库,从NuGet里导入
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using SQLitePCL;
using Microsoft.Data.Sqlite;
using MimeKit;
//using MailKit.Net.Smtp;
//using MailKit.Security;
//以下是自定义命名空间
using Notify;
using Notify.Log;
using Notify.App;
using Notify.App.Cpolar;
//using Notify.Cploar;
//using bRedBit;


//项目依赖项
/* Newtonsoft.Json.dll
 * verctrlcfg.json
 * 
 * */

namespace Notify
{
    class CtrlVersion
    {
        public ushort min { get; set; }
        public ushort max { get; set; }

        public CtrlVersion()
        {
            min = 498;
            max = 506;
        }
        public CtrlVersion(ushort min, ushort max)
        {
            this.min = min;
            this.max = max;
        }
    }
    class NotNtFlagException : Exception
    {
        public NotNtFlagException(string message) : base(message) { }
    }
    class NtVersionCtrlException : Exception
    {
        public NtVersionCtrlException(string message) : base(message) { }
    }
    static class Nt
    {
        static public bool CheckFlag(ref byte[] msg)
        {
            //"N" 78 0x4E 
            //"t"116 0x74
            if (msg != null && msg[0] == 0x4E && msg[1] == 0x74)
            {
                return true;
            }
            return false;
        }
        /// <summary>
        /// 检查消息的前4个字节,检查Flag和版本号
        /// </summary>
        /// <param name="msg">接收的数据,消息</param>
        /// <param name="verctrlcfg">版本控制配置文件</param>
        /// <returns>Flag和Version都没问题就返回true,否则返回false</returns>
        static public bool CheckFlagVersion(ref byte[] msg, string verctrlcfg)
        {
            var ctrlver = ReadConfig(verctrlcfg);
            if (CheckFlag(ref msg) == true && CtrlVersion(ref msg, ctrlver.min, ctrlver.max) == true)
                return true;
            return false;
        }
        static public uint CheckFlagVerCmdno(ref byte[] msg, string verctrlcfg)
        {
            if (CheckFlag(ref msg) == false)
            {
                throw new NotNtFlagException("NotNtFlag CheckFlag false");
            }
            var ctrlver = ReadConfig(verctrlcfg);
            if (CtrlVersion(ref msg, ctrlver.min, ctrlver.max) == false)
            {
                throw new NtVersionCtrlException("客户端版本不在控制的范围内");
            }
            return GetCmdNo(ref msg);
        }
        static public ushort GetVersion(ref byte[] msg)
        {
            return (ushort)((msg[2] << 8) + msg[3]);
        }
        static public bool CtrlVersion(ref byte[] msg, ushort min = 498, ushort max = 503)
        {
            ushort ver = (ushort)((msg[2] << 8) + msg[3]);
            //Console.WriteLine($"{ver},{msg[2]},{msg[3]}");
            if (ver >= min && ver <= max)
            {
                return true;
            }
            return false;
        }
        static public bool CtrlVersion(ref byte[] msg, string verctrlcfg)
        {
            var ctrlver = ReadConfig(verctrlcfg);
            ushort ver = (ushort)((msg[2] << 8) + msg[3]);
            //Console.WriteLine($"{ver},{msg[2]},{msg[3]}");
            if (ver >= ctrlver.min && ver <= ctrlver.max)
            {
                return true;
            }
            return false;
        }
        static public uint GetCmdNo(ref byte[] msg)
        {
            uint CmdNo = (uint)((msg[4] << 24) + (msg[5] << 16) + (msg[6] << 8) + msg[7]);

            return CmdNo;
        }
        static public CtrlVersion ReadConfig(string cfg = "verctrlcfg.json")
        {
            try
            {
                // 读取文件内容  
                string jsonContent = File.ReadAllText(cfg); //File.ReadAllText这个操作是阻塞的,并且比较费时。

                // 反序列化JSON字符串到对象  
                CtrlVersion vers = JsonConvert.DeserializeObject<CtrlVersion>(jsonContent);
                // 输出结果  
                //Console.WriteLine($"{vers.min} >= ver >= {vers.max}");
                return vers;
            }
            catch (Exception e)
            {
                throw e;
            }
        }


    }
    class TcpServer
    {
        private TcpListener tcpListener;
        private Thread listenThread;
        private volatile bool runing = false;
        private List<TcpClient> clients = new List<TcpClient>();
        private volatile bool IsWritingLog = false;//只能有一个线程写,不能多个线程同时写。
        //private int aliveclients = 5;//这个要大约等于3,也就是至少要保留3个线程
        private CtrlVersion VerCtrl = new CtrlVersion();
        //private ulong totalAccess = 0;
        private List<LogContent> logBuffer = new List<LogContent>();
        private readonly SynchronizationContext _synchronizationContext = SynchronizationContext.Current;//跨线程需要同步上下文
        public int ClientsCount { get { return clients.Count; } }
        /// <summary>
        /// 阶段性访问量,一读就清空。
        /// </summary>
        //public ulong TotalAccess 
        //{ 
        //    get 
        //    {
        //        var temp = this.totalAccess;
        //        this.totalAccess = 0;
        //        return temp; 
        //    } 
        //}
        /// <summary>
        /// 日志缓存器,这个属性读后就清空了。
        /// </summary>
        public List<LogContent> LogBuf
        {
            get //深拷贝,防止并发环境里的遗漏
            {
                List<LogContent> temp = new List<LogContent>();
                //在 C# 中,使用 foreach 循环遍历集合时,如果集合在遍历过程中被修改(如添加、删除元素),就会抛出此异常System.InvalidOperationException。
                foreach (LogContent content in this.logBuffer)
                {
                    temp.Add(content);
                }
                foreach (LogContent content in temp)
                {
                    this.logBuffer.Remove(content);
                }
                return temp;
            }
        }
        public int LogBufferCount { get { return this.logBuffer.Count; } }
        // 定义一个委托
        public delegate void LogReadyHandler(List<LogContent> logs);
        // 定义一个事件
        public event LogReadyHandler LogReady;
        // 模拟数据生产
        private void LogTrigger()
        {
            //#if DEBUG
            //            TempLog.logging($"{this.LogBufferCount}");
            //#endif
            //SynchronizationContext _synchronizationContext = SynchronizationContext.Current;//跨线程需要同步上下文
            //_synchronizationContext = SynchronizationContext.Current;
            // 触发事件
            if (this.LogBufferCount > 0)
            {
                //#if DEBUG
                //                TempLog.logging($"{this.LogBufferCount}触发日志缓存和写入{this.LogReady.ToString()}");
                //#endif
                //LogReady?.Invoke(this.LogBuf);//读数据并清空了日志缓存
                if (_synchronizationContext != null)
                {
                    _synchronizationContext.Send(state =>
                    {
                        try
                        {
                            LogReady?.Invoke(this.LogBuf); // 如果有任何订阅者,调用他们的方法
                        }
                        catch (Exception ex)
                        {
                            //Console.WriteLine($"Exception during event invocation: {ex.Message}");
#if DEBUG
                            TempLog.logging($"{this.LogBufferCount}触发日志缓存和写入{this.LogReady.ToString()} {ex.ToString()}");
#endif
                        }
                    }, null);
                }
                else
                {
                    try
                    {
                        LogReady?.Invoke(this.LogBuf); // 如果有任何订阅者,调用他们的方法
                    }
                    catch (Exception ex)
                    {
                        //Console.WriteLine($"Exception during event invocation: {ex.Message}");
#if DEBUG
                        TempLog.logging($"{this.LogBufferCount} Context==null {this.LogReady.ToString()} {ex.ToString()}");
#endif
                    }
                }
            }
        }

        public TcpServer(string ipAddress, int port)
        {
            this.tcpListener = new TcpListener(IPAddress.Parse(ipAddress), port);
            if (clients == null)
                clients = new List<TcpClient>();
        }
        public void Startup()
        {
            if (this.listenThread == null || this.listenThread.IsAlive == false)
            {
                this.listenThread = new Thread(new ThreadStart(ListenForClients));
                this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
            }
            switch (listenThread.ThreadState)
            {
                case System.Threading.ThreadState.Unstarted:
                    this.listenThread.Start();
                    runing = true;
                    break;
                case System.Threading.ThreadState.StopRequested:
                case System.Threading.ThreadState.AbortRequested:
                case System.Threading.ThreadState.Aborted:
                case System.Threading.ThreadState.Stopped:
                case System.Threading.ThreadState.Suspended:
                case System.Threading.ThreadState.SuspendRequested:
                    this.listenThread.Abort();
                    this.listenThread = new Thread(new ThreadStart(ListenForClients));
                    this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
                    this.listenThread.Start();
                    runing = true;
                    break;
                case System.Threading.ThreadState.Running:
                    runing = true;
                    break;
            }
            if (clients == null)
                clients = new List<TcpClient>();
        }
        public void Startup(string ipaddr, int port)
        {
            this.tcpListener = new TcpListener(IPAddress.Parse(ipaddr), port);
            if (this.listenThread == null || this.listenThread.IsAlive == false)
            {
                this.listenThread = new Thread(new ThreadStart(ListenForClients));
                this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
            }
            switch (listenThread.ThreadState)
            {
                case System.Threading.ThreadState.Unstarted:
                    this.listenThread.Start();
                    runing = true;
                    break;
                case System.Threading.ThreadState.StopRequested:
                case System.Threading.ThreadState.AbortRequested:
                case System.Threading.ThreadState.Aborted:
                case System.Threading.ThreadState.Stopped:
                case System.Threading.ThreadState.Suspended:
                case System.Threading.ThreadState.SuspendRequested:
                    this.listenThread.Abort();
                    this.listenThread = new Thread(new ThreadStart(ListenForClients));
                    this.listenThread.IsBackground = false;//前台线程不会自动退出,thread类默认前台线程,前台线程会阻塞主线程
                    this.listenThread.Start();
                    runing = true;
                    break;
                case System.Threading.ThreadState.Running:
                    runing = true;
                    break;
            }
            if (clients == null)
                clients = new List<TcpClient>();
        }

        public static bool CheckPortAvali(int port, string ipaddr)
        {
            TcpListener tcp = new TcpListener(IPAddress.Parse(ipaddr), port);
            try
            {
                tcp.Start();
                tcp.Stop();
            }
            catch (SocketException se)
            {
                //if(se.ErrorCode==10048)
                if (se.ErrorCode == (int)SocketError.AddressAlreadyInUse)
                {
                    return false;
                }
            }
            return true;
        }

        public void ReadCtrlVersionCfg(string cfg = "verctrlcfg.json")
        {
            try
            {
                // 读取文件内容  
                string jsonContent = File.ReadAllText(cfg); //File.ReadAllText这个操作是阻塞的,并且比较费时。

                // 反序列化JSON字符串到对象  
                CtrlVersion vers = JsonConvert.DeserializeObject<CtrlVersion>(jsonContent);
                // 输出结果  
                //Console.WriteLine($"{vers.min} >= ver >= {vers.max}");
                this.VerCtrl = vers;
            }
            catch (Exception e)
            {
                throw e;
            }
        }
        /// <summary>
        /// 剔除掉Tcp的Accept阻塞,要与runing = false;配合使用
        /// </summary>
        private void kickAcceptBlock()
        {
            // 创建一个TcpClient实例并连接到服务器  
            TcpClient client = new TcpClient();
            client.Connect((IPEndPoint)this.tcpListener.LocalEndpoint);
            // 关闭连接  
            client.Close();
            client.Dispose();
        }
        public void Stop()
        {
            //#if DEBUG
            //            TempLog.logging($"IsBlocking:{this.tcpListener.Server.Blocking}");
            //#endif

            runing = false;
            if (this.tcpListener.Server.Blocking)
                kickAcceptBlock();
            //#if DEBUG
            //            TempLog.logging($"Clients Count:{clients.Count}");
            //#endif
            foreach (TcpClient client in clients)
            {
                client.Close();
                client.Dispose();
            }
            clients.Clear();
            //#if DEBUG
            //            TempLog.logging($"Pending:{this.tcpListener.Pending()}");
            //#endif
            this.tcpListener.Server.Blocking = false;   //设为非阻塞模式
            //this.listenThread.Join();//Stop其他线程,本线程会运行,但是会阻塞程序和界面。
            //Console.WriteLine("Stop");
            this.tcpListener.Stop();//先调用Stop方法,Socket会报错。
            //System.Net.Sockets.SocketException (0x80004005): 一个封锁操作被对 WSACancelBlockingCall 的调用中断。
            this.listenThread.Abort();
            System.GC.Collect();
        }

        private void ListenForClients()
        {
            TcpClient client = new TcpClient();
            this.tcpListener.Start();
            //#if DEBUG
            //            TempLog.logging($"TcpServierIsRuning:{this.runing}");
            //#endif
            Task.Run(() =>
            {
                try
                {
                    while (this.runing)
                    {
                        // 阻塞直到客户端连接  
                        client = this.tcpListener.AcceptTcpClient();  //关闭的时候可能会发生异常
                        //this.totalAccess++; //统计接访客户端数量
                        // 创建一个新的线程来处理客户端通信  
                        Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
                        clientThread.IsBackground = true;   //后台线程不阻塞主线程,后台线程用完后自动退出
                        clientThread.Start(client);

                        //剔除休眠客户端
                        for (int i = 0; (i < clients.Count); i++)   // && (clients.Count >= this.aliveclients)
                        {
                            bool IsConnectedR = false, IsConnectedW = false, IsConnectedE = false;
                            if (clients[i].Available != 0 && clients[i].Client.Poll(6000, SelectMode.SelectRead))
                                IsConnectedR = true;//isConnected

                            if (clients[i].Client.Poll(6000, SelectMode.SelectWrite))
                                IsConnectedW = true;

                            if (clients[i].Client.Poll(6000, SelectMode.SelectError) == false)
                                IsConnectedE = true;

                            if (!(IsConnectedR || IsConnectedW) || (IsConnectedE == true))
                            {
                                clients[i].Close();
                                clients[i].Dispose();
                                clients.RemoveAt(i);
                            }
                            if (i >= 5)
                                GC.Collect();
                        }


                        //阻塞问题
                        if (this.runing == false)
                        {
                            clientThread.Abort();
                        }
                        //#if DEBUG
                        //                        TempLog.logging("NotifyService Into ListenForClients");
                        //#endif
                    }
                }
                catch (ObjectDisposedException ode)
                {
                    this.logBuffer.Add(new LogContent(LogLevel.Critical, ode.Message, ode));
                    //throw ode;
                    //return;//Stop时候报错
                }
                catch (SocketException se)
                {
                    // 确保释放资源  
                    if (client != null)
                    {
                        client.Close();
                    }
                    if (this.tcpListener != null)
                    {
                        this.tcpListener.Stop(); // 如果还没有停止的话  
                    }
                    this.logBuffer.Add(new LogContent(LogLevel.Fault, se.Message, se));
                    //throw se;
                }
                catch (Exception ex)
                {
                    this.logBuffer.Add(new LogContent(LogLevel.Exception, ex.Message, ex));
                    //throw ex;
                }
            });
        }


        /// <summary>
        /// 注意接受缓存只有4096字节。
        /// </summary>
        /// <param name="client">连接进来的客户端</param>
        private async void HandleClientComm(object client)
        {
            this.logBuffer.Add(new LogContent(LogLevel.Statistic, "HandleClientComm"));
            TcpClient tcpClient = (TcpClient)client; //注意tcpClient.Close()关闭之后后面就无法接受连接。
            NetworkStream clientStream = tcpClient.GetStream();

            byte[] message = new byte[4096];
            int messagebytes;

            while (this.runing)
            {
                messagebytes = 0;

                //接收数据
                try
                {
                    // 阻塞直到客户端发送数据  
                    messagebytes = clientStream.Read(message, 0, message.Length);//这里有可能缓冲小了
                }
                catch (ArgumentOutOfRangeException outrange)//缓存区太小异常
                {
                    this.logBuffer.Add(new LogContent(LogLevel.Error, outrange.Message, outrange));
                    //return;
                    clientStream.Close();
                    goto End;
                }
                catch (ObjectDisposedException ode)     //关闭Client,下一个客户端访问就报这个异常。//这个异常会陷入一个死循环,烧CPU
                {
                    this.logBuffer.Add(new LogContent(LogLevel.Critical, ode.Message, ode));
                    //return; //NetworkStream Dispose, can not send
                    clientStream.Close();
                    goto End;
                }
                catch (IOException ioe) //多个线程写文件操作就会报这个异常
                {
                    if (ioe.InnerException is SocketException socketEx)
                    {
                        switch (socketEx.SocketErrorCode)
                        {
                            case SocketError.ConnectionReset:
                                // 连接被对方重置(可能是客户端关闭)
                                this.logBuffer.Add(new LogContent(LogLevel.Warning, "连接被对方重置(可能是客户端关闭)", ioe));
                                break;
                            case SocketError.ConnectionAborted:
                                // 连接被对方异常关闭
                                this.logBuffer.Add(new LogContent(LogLevel.Warning, "连接被对方异常关闭", ioe));
                                break;
                                // 处理其他 SocketError 代码
                        }
                    }
                    //return; //NetworkStream Dispose, can not send
                    goto End;
                }
                catch (InvalidOperationException ioe)  //Socket未启动导致后面的操作无效
                {
                    this.logBuffer.Add(new LogContent(LogLevel.Error, ioe.Message, ioe));
                    goto End;
                }
                catch (ArgumentException ae)    //参数引发的异常,可能message有问题
                {
                    this.logBuffer.Add(new LogContent(LogLevel.Error, ae.Message, ae));
                    goto End;
                }
                catch (Exception e) //其他异常,比如 客户端断开了连接  
                {
                    this.logBuffer.Add(new LogContent(LogLevel.Exception, e.Message, e));
                    goto End;
                }
                if (messagebytes < 6)
                {
                    this.logBuffer.Add(new LogContent(LogLevel.Mistake, "messagebytes < 6"));
                    goto End;
                }
                //检查版本号 改读类的字段了 //每次这里读配置文件比较费时间。可能是因为其他线程占用文件。
                if (Nt.CtrlVersion(ref message, this.VerCtrl.min, this.VerCtrl.max) == false)
                {
#if DEBUG
                    TempLog.logging("CheckVersionFalse");
#endif
                    this.logBuffer.Add(new LogContent(LogLevel.Warning, "来访客户端版本不在受控范围内"));
                    goto End;
                }

                //按Falg选择应用框架
                switch ((message[0] << 8) | message[1])
                {
                    case (int)SwitchApp.Nt:
                        goto NtApp;
                    //break;
                    case (int)SwitchApp.bRB:
                        goto End;
                    //break;
                    case (int)SwitchApp.ECHO:
                        goto Turn;  //ECHO 回显
                                    //break;
                    default:
                        this.logBuffer.Add(new LogContent(LogLevel.Warning, "应用标识Flag不存在"));
                        goto End;
                }
            NtApp:
                try
                {
                    switch (Nt.GetCmdNo(ref message))
                    {
                        case 1://获取Cploar并写缓存
                            {
                                //异步
                                var cpinfos = await DynamicCpolar.GetCpolarInfo();
                                // 写缓存到文件
                                CpolarCache cpolarCache = new CpolarCache();
                                cpolarCache.FurthestUpdate = DynamicCpolar.GetLastUpdateFromCpolarInfp(cpinfos);
                                cpolarCache.cpolarCache = cpinfos;
                                var cpjson = JsonConvert.SerializeObject(cpolarCache);

                                try
                                {
                                    if (cpjson != null)
                                        File.WriteAllText("./CpolarCache.json.cache", cpjson);//在服务里要用绝对路径
                                }
                                catch (Exception ex)
                                {
#if DEBUG
                                    TempLog.logging(ex.ToString());
#endif
                                    this.logBuffer.Add(new LogContent(LogLevel.Mistake, "写缓存文件错误\"./CpolarCache.json.cache\"", ex));
                                }
                                // 将CploarInfo对象序列化成JSON字符串  
                                string jsonString = JsonConvert.SerializeObject(cpinfos);
                                ASCIIEncoding encod = new ASCIIEncoding();
                                message = encod.GetBytes(jsonString);
                                messagebytes = message.Length;
                            }
                            break;
                        case 2:
                            //读DynamicCpolar缓存文件
                            {
                                string jsonStr = string.Empty;
                                if (File.Exists("./CpolarCache.json.cache"))
                                {
                                    var cpojson = File.ReadAllText("./CpolarCache.json.cache");
                                    CpolarCache CpolarCache = new CpolarCache();
                                    CpolarCache = JsonConvert.DeserializeObject<CpolarCache>(cpojson);
                                    if (CpolarCache.FurthestUpdate > DateTime.Now.AddHours(-12))
                                    {
                                        // 将CploarInfo对象序列化成JSON字符串  
                                        jsonStr = JsonConvert.SerializeObject(CpolarCache.cpolarCache);
                                        ASCIIEncoding encod = new ASCIIEncoding();
                                        message = encod.GetBytes(jsonStr);
                                        messagebytes = message.Length;
                                    }
                                    else
                                    {
                                        goto case 1;
                                    }
                                }
                                else
                                {
                                    goto case 1;
                                }
                            }
                            break;
                        case 3: //无缓存
                            {
                                //异步
                                var cpinfos = await DynamicCpolar.GetCpolarInfo();
                                // 将CploarInfo对象序列化成JSON字符串  
                                string jsonString = JsonConvert.SerializeObject(cpinfos);
                                ASCIIEncoding encod = new ASCIIEncoding();
                                message = encod.GetBytes(jsonString);
                                messagebytes = message.Length;
                            }
                            break;
                    }
                    goto Turn;
                }
                catch (Exception e)
                {
                    this.logBuffer.Add(new LogContent(LogLevel.Exception, e.Message, e));
                    goto End;
                }
            //            bRBApp:
            //                if (bRB.CheckFlagRB(ref message, messagebytes) == true && messagebytes > 4)
            //                {
            //                    byte key = bRB.GetKey(ref message, messagebytes);
            //#if DEBUG
            //                    Console.WriteLine("bRB应用来访");
            //                    Console.WriteLine("key:{0}", key);
            //#endif
            //                    byte[] data = new byte[messagebytes - 4];
            //                    for (int i = 0; i < data.Length; i++)
            //                    {
            //                        data[i] = (byte)(message[i + 4] ^ key);
            //                    }

            //                    goto End;
            //                }
            //                ;
            Turn:
                try
                {
                    //#if DEBUG
                    //                    TempLog.logging(ASCIIEncoding.ASCII.GetString(message,4,messagebytes));
                    //#endif
                    // 发送回显数据给客户端  
                    clientStream.Write(message, 0, messagebytes);
                    clientStream.Flush();
                }
                catch (Exception e)
                {
                    this.logBuffer.Add(new LogContent(LogLevel.Exception, e.Message, e));
                }
            End:
                try
                {
                    //this.logBuffer.Add(new LogContent(LogLevel.Debug, "进入日志程序"));
                    clientStream.Close();//无法访问已释放的对象。对象名:“System.Net.Sockets.NetworkStream”。
                    tcpClient.Close();//调用此方法最终将导致关联的 Socket 关闭,TcpListener也可能会关闭。

                    //导出日志
                    LogTrigger();
                }
                catch (Exception e)  //不处理
                {
                    this.logBuffer.Add(new LogContent(LogLevel.Exception, e.Message, e));
                    return;
                }
                return;
            }
        }
    }

}


namespace Notify.Log
{
    public enum LogLevel
    {
        Trace = 0,
        Debug = 1,
        Information = 2,
        Statistic = 3,
        Warning = 4,
        Mistake = 6,    //轻微错误
        Exception = 5,
        Error = 7,      //逻辑错误
        Critical = 8,    //严重错误
        Fault = 9       //致命错误
    }

    //临时日志是写文本文件,这种操作在高并发程序里会造成程序崩溃
    public class TempLog
    {
        //注意只有一个线程写,不能多个线程同时写文件。
        static public void logging(List<NtLog> logbuf, string filepath = "./NotifyLog.log")
        {
            // 确保日志文件的目录存在  
            Directory.CreateDirectory(Path.GetDirectoryName(filepath));
            // 使用StreamWriter写入日志  
            using (StreamWriter writer = new StreamWriter(filepath, true)) // true表示追加模式  
            {
                //writer.WriteLine($"Log Entry: {DateTime.Now} - This is a test log entry.");
                // 这里可以添加更多的日志写入操作
                //foreach (NtLog log in logbuf)
                //{
                //    writer.WriteLine(log.ToString());
                //    移除已经写了的缓存
                //    logbuf.Remove(log);//迭代器安全问题
                //}
                for (int i = 0; i < logbuf.Count; i++)
                {
                    //#if DEBUG
                    //                    Console.WriteLine(logbuf[i].ToString());
                    //#endif
                    writer.WriteLine(logbuf[i].ToString());
                    logbuf.RemoveAt(i);
                }
            }
        }
        static public void logging(List<NtLog> logbuf)
        {
            string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"  
            string fullPath = Path.Combine("./logs", fileName);
            // 确保日志文件的目录存在  
            Directory.CreateDirectory(Path.GetDirectoryName(fullPath));
            // 使用StreamWriter写入日志  
            using (StreamWriter writer = new StreamWriter(fullPath, true)) // true表示追加模式  
            {
                //writer.WriteLine($"Log Entry: {DateTime.Now} - This is a test log entry.");
                // 这里可以添加更多的日志写入操作
                //foreach (NtLog log in logbuf)
                //{
                //    writer.WriteLine(log.ToString());
                //    移除已经写了的缓存
                //    logbuf.Remove(log);//迭代器安全问题
                //}
                for (int i = 0; i < logbuf.Count; i++)
                {
#if DEBUG
                    Console.WriteLine(logbuf[i].ToString());
#endif
                    writer.WriteLine(logbuf[i].ToString());
                    logbuf.RemoveAt(i);
                }
            }
        }

        static public void logging(string message, string logpath)
        {
            using (StreamWriter writer = new StreamWriter(logpath, true)) // true表示追加模式  
            {
                //string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"  
                string content = $"{DateTime.Now:yyyy-MM-ddTHH:mm:ss} {message}";
                writer.WriteLine(content);
            }
        }
        static public void logging(string message)
        {
            string path = AppDomain.CurrentDomain.BaseDirectory;

            using (StreamWriter writer = new StreamWriter(path + "//TempLog.log", true)) // true表示追加模式  
            {
                //string fileName = $"{DateTime.Now:yyyy-MM-dd}.log"; // 构建文件名,例如 "2023-04-01.log"  
                string content = $"{DateTime.Now:yyyy-MM-ddTHH:mm:ss} {message}";
                writer.WriteLine(content);
            }
        }
    }
    public class LogContent
    {
        public DateTime Occurrence { get; set; }
        public LogLevel Level { get; set; }
        public StackTrace Trace { get; set; }
        public string Message { get; set; }

        public LogContent() { }
        public LogContent(LogLevel level, string message)
        {
            this.Occurrence = DateTime.Now;
            this.Level = level;
            this.Trace = new StackTrace(true);//捕捉当前堆栈
            this.Message = message;
        }
        public LogContent(LogLevel level, string message, Exception e)
        {
            this.Occurrence = DateTime.Now;
            this.Level = level;
            this.Trace = new StackTrace(e, true);//捕捉当前异常堆栈堆栈
            this.Message = message;
        }
        public override string ToString()
        {
            string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";

            return tmp;
        }
    }
    public class LogContentX
    {
        public DateTime Occurrence { get; set; }
        public LogLevel Level { get; set; }
        public StackTrace Trace { get; set; }
        public string Message { get; set; }

        public LogContentX() { }
        public LogContentX(LogLevel level, string message) { this.SetLog(level, message); }
        public LogContentX(LogLevel level, string message, Exception e) { this.SetLog(level, message, e); }
        public void SetLog(LogLevel level, string message)
        {
            this.Occurrence = DateTime.Now;
            this.Level = level;
            this.Trace = new StackTrace(true);//捕捉当前堆栈
            this.Message = message;
        }
        public void SetLog(LogLevel level, string message, Exception e)
        {
            this.Occurrence = DateTime.Now;
            this.Level = level;
            this.Trace = new StackTrace(e, true);//捕捉当前异常堆栈堆栈
            this.Message = message;
        }
        public override string ToString()
        {
            string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";

            return tmp;
        }
        public string TraceDetail()
        {
            string tmp = Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + Level.ToString() + " " + Message + "\n";
            tmp += this.Trace.ToString() + "\r\n";
            //StackFrame sf = Trace.GetFrame(0); 
            //tmp += $" Method: {sf.GetMethod()}\r\n";
            //$" File: {sf.GetFileName()}\r\n" +
            //$" Line Number: {sf.GetFileLineNumber()}\r\n";

            return tmp;
        }
        public static string TraceDetail(LogContent log)
        {
            string tmp = log.Occurrence.ToString("yyyy-MM-ddTHH:mm:ss.FFFF") + " " + log.Level.ToString() + " " + log.Message + "\n";
            tmp += log.Trace.ToString() + "\r\n";
            //StackFrame sf = Trace.GetFrame(0); 
            //tmp += $" Method: {sf.GetMethod()}\r\n";
            //$" File: {sf.GetFileName()}\r\n" +
            //$" Line Number: {sf.GetFileLineNumber()}\r\n";

            return tmp;
        }
        public string TraceTopFrame()
        {
            return this.Trace.GetFrame(0).ToString();
        }
        public StackFrame TraceTopStackFrame()
        {
            return Trace.GetFrame(0);
        }
        public StackFrame TraceBottomStackFrame()
        {
            return Trace.GetFrame(this.Trace.FrameCount - 1);
        }
        public int GetSize()
        {
            //在safe环境中无法使用sizeof(DateTime),sizeof(DateTime)用8字节代替
            // Each character in a string is 2 bytes (UTF-16 encoding).
            int total = sizeof(LogLevel) + this.Message.Length * 2 + 8;
            for (int i = 0; i < this.Trace.FrameCount; i++)
            {
                StackFrame sf = this.Trace.GetFrame(i);
                //sf.GetFileLineNumber();sf.GetFileName(); sf.GetMethod().Name; 
                total += sf.ToString().Length * 2;
            }
            return total;
        }
        public static int GetSize(LogContent log)
        {
            //在safe环境中无法使用sizeof(DateTime),sizeof(DateTime)用8字节代替
            // Each character in a string is 2 bytes (UTF-16 encoding).
            int total = sizeof(LogLevel) + log.Message.Length * 2 + 8;
            for (int i = 0; i < log.Trace.FrameCount; i++)
            {
                StackFrame sf = log.Trace.GetFrame(i);
                //sf.GetFileLineNumber();sf.GetFileName(); sf.GetMethod().Name; 
                total += sf.ToString().Length * 2;
            }
            return total;
        }
    }

    public class LogBuffer
    {
        protected List<LogContent> buf = new List<LogContent>();
        public List<LogContent> Buffer { get { return buf; } }

        public LogBuffer()
        {
            buf = new List<LogContent>();
        }
        public LogBuffer(List<LogContent> buf)
        {
            this.buf = buf;
        }
        public void Insert(LogContent log)
        {
            this.buf.Add(log);
        }
        public void Insert(LogBuffer log)
        {
            foreach (var item in log.Buffer)
            {
                this.buf.Add(item);
            }
        }
        public int LogSize()
        {
            int size = 0;
            foreach (LogContent cnt in this.buf)
            {
                size += LogContentX.GetSize(cnt);
            }
            return size;
        }
    }
    public class LogBufQuery
    {
        public List<LogContent> Buffer { get; set; }

        public void TimeOrderAsc()
        {
            Buffer.Sort((x, y) => x.Occurrence.CompareTo(y.Occurrence));
        }
        public void TimeOrderDsc()
        {
            Buffer.Sort((x, y) => y.Occurrence.CompareTo(x.Occurrence));
        }
        public List<LogContent> FilterByLoglevel(LogLevel loglevel)
        {
            return Buffer.FindAll(log => log.Level == loglevel);
        }
    }

    public class LogStatistic : LogBufQuery
    {
        private SqliteConnection connection;
        private string dbfile = string.Empty;

        //将db信息生成文本或文本文件

        //寻找路径并创建文件
        private void MakeFile()
        {
            string path = AppDomain.CurrentDomain.BaseDirectory;
            // 获取当前应用程序域的名称(通常是程序集名称)
            string assemblyName = AppDomain.CurrentDomain.FriendlyName;
            // 去掉路径和扩展名,只保留文件名
            assemblyName = Path.GetFileNameWithoutExtension(assemblyName);
            // 组合成完整的路径
            this.dbfile = System.IO.Path.Combine(path, assemblyName + ".db");
            //确保数据库文件存在
            string connectionString = $"Data Source={this.dbfile}";
            try
            {
                this.connection = new SqliteConnection(connectionString);
                connection.Open(); // 这将尝试打开数据库,如果不存在则会创建它
                connection.Close();
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        //检查并创建数据表,确保必要的数据表存在。这里就固定了格式和标准。
        private void EnsureDbTableExist()
        {
            //key-word形式
        }

        //连接db

        //释放连接

        //从Buffer中分析并向表中写入统计数据

        //读表中数据

        //插入或更新数据

        //Clear
    }

    //将日志写成文本文件,注意在多线程环境下要排除线程互斥。
    public class NtLog
    {
        private Queue<LogBuffer> Buff = new Queue<LogBuffer>();
        public string LogPath { get; }
        private string curfilepath = string.Empty;
        private string errorLgFile = string.Empty;  //定义从Exception到Fault这5个层级为Error
        private Task task;
        private Stopwatch watcher = new Stopwatch();
        private long maxms, minms, lastms;
        private volatile bool IsWriting = false;
        public bool Writing { get { return IsWriting; } }
        /// <summary>
        /// 平均耗时
        /// </summary>
        public long AverageConsum
        {
            get
            {
                return (maxms + minms + lastms) / 3;
            }
        }
        public NtLog()
        {
            this.LogPath = AppDomain.CurrentDomain.BaseDirectory;


            创建日志文件夹
            this.LogPath = CreateLogDirectory();
            MakeLogFileName();
            maxms = minms = lastms = 0;
        }
        public void OnLogging(List<LogContent> logs)
        {
            //#if DEBUG
            //            TempLog.logging($"查看原始数据。{logs.Count} ");//{logs.First().Message}
            //#endif
            this.Buff.Enqueue(new LogBuffer(logs));

            //#if DEBUG
            //            TempLog.logging($"执行事件。{this.Buff.Count} {this.IsWriting}");
            //#endif

            //#if DEBUG
            //            TempLog.logging($"查看写缓存。{Temp.Buffer.Count} {Temp.Buffer.First().Message}");
            //#endif
            this.UpdatePathFileName();
            if (this.IsWriting == false && this.Buff.Count > 0)
            {
                LogBuffer Temp = this.Buff.Dequeue();
                while (this.Buff.Count > 0)
                {
                    Temp.Insert(this.Buff.Dequeue());
                }
                WriteLogByThread(Temp);
            }

        }
        public static string CreateLogDirectory()
        {
            string path = AppDomain.CurrentDomain.BaseDirectory;

            // 获取当前应用程序域的名称(通常是程序集名称)
            string assemblyName = AppDomain.CurrentDomain.FriendlyName;

            // 去掉路径和扩展名,只保留文件名
            assemblyName = Path.GetFileNameWithoutExtension(assemblyName);

            // 组合成完整的路径
            path = System.IO.Path.Combine(path, assemblyName + "Log");
            //TempLog.logging(path);
            //创建日志文件夹
            Directory.CreateDirectory(path);
            return path;
        }
        public void UpdatePathFileName()
        {
            string path = AppDomain.CurrentDomain.BaseDirectory;

            // 获取当前应用程序域的名称(通常是程序集名称)
            string assemblyName = AppDomain.CurrentDomain.FriendlyName;

            // 去掉路径和扩展名,只保留文件名
            assemblyName = Path.GetFileNameWithoutExtension(assemblyName);

            // 组合成完整的路径
            path = System.IO.Path.Combine(path, assemblyName + "Log");
            //TempLog.logging(path);
            //创建日志文件夹
            Directory.CreateDirectory(path);

            string dn = DateTime.Now.ToString("yyyy-MM-dd");

            this.curfilepath = Path.Combine(this.LogPath, assemblyName + dn + ".log");
            this.errorLgFile = Path.Combine(this.LogPath, assemblyName + dn + "err.log");
        }
        public void MakeLogFileName()
        {
            // 获取当前应用程序域的名称(通常是程序集名称)
            string assemblyName = AppDomain.CurrentDomain.FriendlyName;

            // 去掉路径和扩展名,只保留文件名
            assemblyName = Path.GetFileNameWithoutExtension(assemblyName);

            string dn = DateTime.Now.ToString("yyyy-MM-dd");

            this.curfilepath = Path.Combine(this.LogPath, assemblyName + dn + ".log");
            this.errorLgFile = Path.Combine(this.LogPath, assemblyName + dn + "err.log");
        }

        public void WriteLogFile()
        {
            using (StreamWriter writer = new StreamWriter(this.curfilepath, true)) // true表示追加模式  
            {
                foreach (var Buffer in this.Buff)
                {
                    foreach (var cnt in Buffer.Buffer)
                    {
                        writer.WriteLine(cnt.ToString());
                    }
                }
            }
        }
        public void WriteErrorLog()
        {
            using (StreamWriter writer = new StreamWriter(this.errorLgFile, true)) // true表示追加模式  
            {
                foreach (var Buffer in this.Buff)
                {
                    foreach (var cnt in Buffer.Buffer)
                    {
                        if (cnt.Level >= LogLevel.Exception)
                            writer.WriteLine(LogContentX.TraceDetail(cnt));
                    }
                }

            }
        }

        //发现它仍然阻塞主线程
        //注意只有一个线程写,不能多个线程同时写文件。
        //请注意,Buffer.Remove(cnt) 在循环中可能会导致问题,因为从集合中移除元素会改变集合的大小,从而可能导致迭代器失效。为了避免这个问题,可以先收集需要删除的元素,然后在循环结束后统一删除它们。
        public void WriteLogByThread(LogBuffer logs)
        {
            this.watcher.Start();
            this.IsWriting = true;
            //#if DEBUG
            //            TempLog.logging($"BeofreWriteLog。{this.curfilepath} {this.errorLgFile}");
            //#endif
            
            // 使用Task.Run在后台线程中执行文件写入操作
            this.task = Task.Run(() =>
            {
                //FileStream可以设置成独享锁定模式,防止 线程互斥
                using (FileStream fs1 = new FileStream(this.curfilepath, FileMode.Append, FileAccess.Write, FileShare.None),
                        fs2 = new FileStream(this.errorLgFile, FileMode.Append, FileAccess.Write, FileShare.None))
                {
                    using (StreamWriter writer = new StreamWriter(fs1), writer2 = new StreamWriter(fs2))
                    {
                        foreach (var cnt in logs.Buffer)
                        {
                            writer.WriteLine(cnt.ToString());

                            if (cnt.Level >= LogLevel.Warning)
                                writer2.WriteLine(LogContentX.TraceDetail(cnt));
                        }
                    }
                }
                //Buffer没有上锁是希望它尽快完成操作,但有风险
            });
            this.watcher.Stop();
            this.IsWriting = false;
            if (this.lastms > 0 && this.lastms > this.maxms)
            {
                this.maxms = this.lastms;
            }
            if (this.lastms > 0 && this.minms == 0)
                this.minms = this.lastms;
            if (this.lastms > 0 && this.lastms < this.minms)
            {
                this.minms = this.lastms;
            }
            this.lastms = watcher.ElapsedMilliseconds;
        }


    }
}

namespace Notify.App
{
    enum SwitchApp
    {
        //"N" 78 0x4E 
        //"t"116 0x74
        Nt = (0x4E << 8) | 0x74,
        //ASCII 'A' 0x41 65
        //ASCII 'B' 0x42 66
        bRB = (0x41 << 8) | 0x42,//
        ECHO = (0x08 << 8) | 0x0A //Turn;  //ECHO 回显
    }
}

namespace Notify.App.Cpolar
{
    class DynamicCpolar
    {
        public static async Task<string> GetTunels(string token)
        {
            // 定义URL  
            string url = "http://localhost:9200/api/v1/tunnels";

            // 定义Bearer令牌  
            //string token = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJleHAiOjE3MjIxNzU0NjcsImlhdCI6MTcyMjAwMjY2NywiVXNlcklEIjowLCJVc2VybmFtZSI6IiIsIkVtYWlsIjoiaHV4eWNAcXEuY29tIiwiQXBpU2VydmljZVRva2VuIjoiZXlKaGJHY2lPaUpJVXpJMU5pSXNJblI1Y0NJNklrcFhWQ0o5LmV5SmxlSEFpT2pFM01qSXhOelUwTmpjc0ltbGhkQ0k2TVRjeU1qQXdNalkyTnl3aVZYTmxja2xFSWpveU56RXhNVEFzSWxWelpYSnVZVzFsSWpvaVVtbHpZU0lzSWtWdFlXbHNJam9pYUhWNGVXTkFjWEV1WTI5dEluMC5IMWVfYzl0VjZab1pabFlHVUxEMFlIWWN0VFl3RERMbm5MTFczNC1NZVhvIn0.oLtor_R5YnZgH3AQT17qCRXx5dRTDGUEP8amx8OD8Jo";

            // 创建HttpClient实例  
            using (HttpClient client = new HttpClient())
            {
                // 设置请求头  
                client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

                // 发送GET请求  
                try
                {
                    HttpResponseMessage response = await client.GetAsync(url);

                    // 确保HTTP成功状态值  
                    response.EnsureSuccessStatusCode();

                    // 读取响应内容  
                    string responseBody = await response.Content.ReadAsStringAsync();

                    // 打印响应内容  
                    //Console.WriteLine(responseBody);

                    return responseBody;
                }
                catch (HttpRequestException hre)
                {
                    //Console.WriteLine("\nException Caught!");
                    //Console.WriteLine($"Message :{hre.Message}");
                    throw hre;
                    //return "";
                }
                catch (Exception e)
                {
                    throw e;
                }
            }
        }
        public static async Task<string> GetToken()
        {
            // 创建HttpClient实例  
            using (var client = new HttpClient())
            {
                // 设置请求URL  
                string url = "http://localhost:9200/api/v1/user/login";

                // 准备要发送的JSON数据  
                var loginData = new
                {
                    // 假设你需要发送用户名和密码  
                    email = "youremail@qq.com",
                    password = "yourpassword"
                };

                // 将对象序列化为JSON字符串  
                string jsonContent = JsonConvert.SerializeObject(loginData); // 如果你使用System.Text.Json,则使用JsonSerializer.Serialize  

                // 创建StringContent实例,并设置媒体类型为application/json  
                StringContent content = new StringContent(jsonContent, Encoding.UTF8, "application/json");

                // 发送POST请求  
                try
                {
                    HttpResponseMessage response = await client.PostAsync(url, content);

                    // 检查响应是否成功  
                    response.EnsureSuccessStatusCode();

                    // 读取响应内容  
                    string responseBody = await response.Content.ReadAsStringAsync();

                    // 输出响应内容  
                    //Console.WriteLine(responseBody);

                    // 字符转Json并提取data属性值
                    // 使用 Newtonsoft.Json.Linq 来解析 JSON 字符串  
                    JObject jsonObj = JObject.Parse(responseBody);
                    // 访问 data 属性并提取 token 值  
                    if (jsonObj["data"] != null && jsonObj["data"].Type == JTokenType.Object)
                    {
                        JToken tokenToken = jsonObj["data"]["token"];
                        if (tokenToken != null && tokenToken.Type == JTokenType.String)
                        {
                            string token = tokenToken.Value<string>();
                            //Console.WriteLine($"Token: {token}");
                            return token;
                        }
                        else
                        {
                            //Console.WriteLine("Token is not a string or is null.");
                            throw new JsonException("Token is not a string or is null.");
                            //return "";
                        }
                    }
                    else
                    {
                        throw new JsonException("Data is null or not an object.");
                        //Console.WriteLine("Data is null or not an object.");
                        //return "";
                    }
                }
                catch (HttpRequestException he)
                {
                    // 请求异常处理  
                    //Console.WriteLine("\nException Caught!");
                    //Console.WriteLine("Message :{0} ", e.Message);
                    throw he;
                }
                catch (Exception e)
                {
                    throw e;
                }
                //return "";
            }
        }
        public static CpolarInfo GetCpolarInfoFromJsonString(string json)
        {
            //装载CpolarInfo数据
            CpolarInfo cpolarInfo = new CpolarInfo();

            try
            {
                // 解析JSON字符串为JObject  
                JObject jsonObject = JObject.Parse(json);

                // 访问data对象下的items数组  
                JArray itemsArray = (JArray)jsonObject["data"]["items"];
                //int total = (int)jsonObject["data"]["total"];

                //获取total
                cpolarInfo.total = (int)jsonObject["data"]["total"];
                cpolarInfo.items = new item[cpolarInfo.total];
                //Console.WriteLine($"{cpolarInfo.total}");

                //初始化item,否则会报错
                for (int j = 0; j < cpolarInfo.total; j++)
                {
                    cpolarInfo.items[j] = new item
                    {
                        name = string.Empty,
                        create_datetime = string.Empty,
                        pubulic_url = string.Empty
                    };
                }

                int i = 0;
                // 遍历items数组,提取publish_tunnels
                foreach (JObject item in itemsArray)
                {
                    // 提取name和public_url  
                    string name = item["name"].ToString();
                    string public_url = item["public_url"].ToString();
                    string create_datetime = "";

                    // 访问publish_tunnels数组(假设每个条目至少有一个tunnel)  
                    JArray tunnelsArray = (JArray)item["publish_tunnels"];


                    // 遍历publish_tunnels数组(这里假设我们只关心第一个tunnel的create_datetime)  
                    foreach (JObject tunnel in tunnelsArray)
                    {
                        // 提取create_datetime  
                        create_datetime = tunnel["create_datetime"].ToString();

                        // 打印或处理数据  
                        //Console.WriteLine($"Name: {name}, Public URL: {public_url}, Create Datetime: {create_datetime}");

                        // 如果不需要处理多个tunnel,可以跳出内层循环  
                        break; // 如果你想处理所有tunnel,请移除这行代码  
                    }

                    // 使用Replace方法替换协议部分  
                    string newUrl = public_url.Replace("tls://", "https://");
                    //Console.WriteLine($"{name},{create_datetime},{newUrl}");

                    // 打印或处理数据 
                    //Console.WriteLine($"{name},{create_datetime},{public_url}");

                    //组装CpolarInfo
                    cpolarInfo.items[i].name = name;
                    cpolarInfo.items[i].create_datetime = create_datetime;
                    cpolarInfo.items[i].pubulic_url = newUrl;
                    i++;
                }
            }
            catch (JsonException je)
            {
                throw je;
            }
            catch (Exception e)
            {
                throw e;
            }

            return cpolarInfo;
        }
        public static async Task<CpolarInfo> GetCpolarInfo()
        {
            string token = await GetToken();
            // 输出响应内容  
            //Console.WriteLine(token);
            string json = await GetTunels(token);

            //装载CpolarInfo数据
            CpolarInfo cpolarInfo = new CpolarInfo();

            // 解析JSON字符串为JObject  
            JObject jsonObject = JObject.Parse(json);

            // 访问data对象下的items数组  
            JArray itemsArray = (JArray)jsonObject["data"]["items"];
            //int total = (int)jsonObject["data"]["total"];

            //获取total
            cpolarInfo.total = (int)jsonObject["data"]["total"];
            cpolarInfo.items = new item[cpolarInfo.total];
            //Console.WriteLine($"{cpolarInfo.total}");

            //初始化item,否则会报错
            for (int j = 0; j < cpolarInfo.total; j++)
            {
                cpolarInfo.items[j] = new item
                {
                    name = string.Empty,
                    create_datetime = string.Empty,
                    pubulic_url = string.Empty
                };
            }

            int i = 0;
            // 遍历items数组,提取publish_tunnels
            foreach (JObject item in itemsArray)
            {
                // 提取name和public_url  
                string name = item["name"].ToString();
                string public_url = item["public_url"].ToString();
                string create_datetime = "";

                // 访问publish_tunnels数组(假设每个条目至少有一个tunnel)  
                JArray tunnelsArray = (JArray)item["publish_tunnels"];


                // 遍历publish_tunnels数组(这里假设我们只关心第一个tunnel的create_datetime)  
                foreach (JObject tunnel in tunnelsArray)
                {
                    // 提取create_datetime  
                    create_datetime = tunnel["create_datetime"].ToString();

                    // 打印或处理数据  
                    //Console.WriteLine($"Name: {name}, Public URL: {public_url}, Create Datetime: {create_datetime}");

                    // 如果不需要处理多个tunnel,可以跳出内层循环  
                    break; // 如果你想处理所有tunnel,请移除这行代码  
                }

                // 打印或处理数据  
                //Console.WriteLine($"Name: {name},Create Datetime:{create_datetime}, Public URL: {public_url}");
                //Console.WriteLine($"{name},{create_datetime},{public_url}");

                // 使用Replace方法替换协议部分  
                string newUrl = public_url.Replace("tls://", "https://");
                //Console.WriteLine($"{name},{create_datetime},{newUrl}");
                //Uri url = new Uri(public_url);
                //public_url = url.Host;
                //Console.WriteLine($"{name},{create_datetime},{public_url}");

                //组装CpolarInfo
                cpolarInfo.items[i].name = name;
                cpolarInfo.items[i].create_datetime = create_datetime;
                cpolarInfo.items[i].pubulic_url = newUrl;
                i++;
            }
            return cpolarInfo;
        }

        public static DateTime GetLastUpdateFromCpolarInfp(CpolarInfo cptu)
        {
            DateTime now = DateTime.Now;
            DateTime furthest = DateTime.Parse(cptu.items[cptu.total - 1].create_datetime);
            DateTime tmp;
            for (int i = 0; i < cptu.total - 1; i++)
            {
                tmp = DateTime.Parse(cptu.items[i].create_datetime);
                if (furthest.CompareTo(tmp) > 0)
                {
                    furthest = tmp;
                }
            }
            return furthest;
        }
    }
    public class CpolarCache
    {
        //public DateTime CacheOn { get; set; }   //token请求时间
        //public string tokenCache { get; set; }
        public DateTime FurthestUpdate { get; set; }    //CpolarInfo所有隧道的距离现在最长的时间
        public CpolarInfo cpolarCache { get; set; }
    }
    public class CpolarInfo
    {
        public int total { get; set; }
        public item[] items { get; set; }
    }
    public class item
    {
        public string name { get; set; }
        public string create_datetime { get; set; }
        public string pubulic_url { get; set; }
    }
}

rBitsTest

using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Sockets;
using System.Reflection;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.IO;
using Newtonsoft;
using Newtonsoft.Json;

namespace rBitsTest
{
    public class IPport
    {
        public string IP { get; set; }
        public int Port { get; set; }
    }
    public class CpolarInfo
    {
        public int total { get; set; }
        public item[] items { get; set; }
    }
    public class item
    {
        public string name { get; set; }
        public string create_datetime { get; set; }
        public string pubulic_url { get; set; }
    }
    internal class Program
    {
        static void Main(string[] args)
        {
            try
            {
                Console.WriteLine("Version:{0}", Assembly.GetEntryAssembly().GetName().Version.ToString());

                string jsonFilePath = "ipport.json"; // 替换为你的JSON文件路径  

                // 读取文件内容  
                string jsonContent = File.ReadAllText(jsonFilePath);

                // 反序列化JSON字符串到对象  
                List<IPport> ipaddrs = JsonConvert.DeserializeObject<List<IPport>>(jsonContent);

                // 输出结果  
                foreach (var host in ipaddrs)
                {
                    Console.WriteLine($"Host:  IP: {host.IP}, Port: {host.Port}");
                }
                 创建一个Random对象
                //Random random = new Random((int)DateTime.Now.Ticks);
                 定义一个数组,其中包含更多你想要的值(例如1),以增加其出现的概率
                //int[] weightedArray = new int[20];
                //for (int i = 0; i < 10; i++) // 50% 是 1
                //{
                //    weightedArray[i] = 1;
                //}
                //for (int i = 10; i < 16; i++) // 25% 是 1
                //{
                //    weightedArray[i] = 0;
                //}
                //for (int i = 16; i < 20; i++) // 25% 是 1
                //{
                //    weightedArray[i] = 2;
                //}
                 从加权数组中随机选择一个元素
                //int randomIndex = random.Next(weightedArray.Length);
                //int randomNumber = weightedArray[randomIndex];
                //var conhost = ipaddrs[randomNumber];   //randomNumber%2
                //var conhost = new IPport();
                var conhost = ipaddrs[2];
                //conhost.Port = 25984;
                //conhost.IP = "cn-hb-lt-tmp3.natfrp.cloud";
                Console.WriteLine($"Selected Connect Host:  IP: {conhost.IP}, Port: {conhost.Port}");

                // 创建一个TcpClient实例并连接到服务器  
                TcpClient client = new TcpClient($"{conhost.IP}", conhost.Port);

                // 获取一个NetworkStream对象以进行读写  
                NetworkStream stream = client.GetStream();

                // 将消息转换为字节数组  
                //string message = "Hello from the client!";
                //byte[] data = Encoding.ASCII.GetBytes(message);
                //Flag1 Flag2 VerH VerL
                byte[] data = { 0x4E, 0x74, 0x01, 0xF9, 0x00, 0x00, 0x00, 0x01 };

                // 发送消息到服务器  
                stream.Write(data, 0, data.Length);

                // 读取服务器的响应  
                byte[] buffer = new byte[4096];
                int bytesRead = stream.Read(buffer, 0, buffer.Length);

                // 将接收到的字节转换为字符串  
                string responseData = Encoding.ASCII.GetString(buffer, 0, bytesRead);
                Console.WriteLine("Received from server: " + responseData);
                Console.WriteLine("ReceivedBytes:{0}", bytesRead);

                //将Json写入文件
                File.WriteAllText("cpolarinfo.json", responseData);

                // 关闭连接  
                client.Close();
            }
            catch (Exception e)
            {
                Console.WriteLine("Error: " + e.Message);
            }

            // 等待用户按键,以便在控制台中查看结果  
            //Console.WriteLine("Press Enter to continue...");
            //Console.ReadLine();
            // 设置定时器,6秒后执行ExitApplication方法
            var timer = new System.Threading.Timer(ExitApplication, null, 6000, Timeout.Infinite);

            Console.WriteLine("Press any key to exit...");
            Console.ReadKey(); // 等待用户按键

            // 如果用户提前按下了键,取消定时器
            timer.Dispose();
        }
        static void ExitApplication(object state)
        {
            Console.WriteLine("Time's up! Exiting the application...");
            Environment.Exit(0); // 退出程序
        }
    }
}


网站公告

今日签到

点亮在社区的每一天
去签到