소스 검색

继续编写多人副本的服务端

王刚 3 년 전
부모
커밋
dddc61dc20

+ 13 - 0
CSserver/BattleRoom/BattleRoom.csproj

@@ -0,0 +1,13 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net5.0</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\Lib1\Lib1.csproj" />
+    <ProjectReference Include="..\PBReferens\PBReferens.csproj" />
+  </ItemGroup>
+
+</Project>

+ 63 - 0
CSserver/BattleRoom/Program.cs

@@ -0,0 +1,63 @@
+using System;
+using System.Net;
+using System.Net.Sockets;
+using System.Threading.Tasks;
+using System.Diagnostics;
+
+namespace BattleRoom
+{
+    internal class Program
+    {
+        static Socket SocketWatch = null;                                       // 创建一个和客户端通信的套接字 
+        const int port = 6006;                                                  // 端口号(用来监听的) 
+        static void Main(string[] args)
+        { 
+            selfTest();
+            IPAddress ip = IPAddress.Any;
+            IPEndPoint ipe = new IPEndPoint(ip, port);                         //将IP地址和端口号绑定到网络节点point上  
+
+            //定义一个套接字用于监听客户端发来的消息,包含三个参数(IP4寻址协议,流式连接,Tcp协议)  
+            SocketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
+            SocketWatch.Bind(ipe);                                             // 监听绑定的网络节点           
+            SocketWatch.Listen(20);                                            // 将套接字的监听队列长度限制为20    
+
+            Console.WriteLine("开启监听......");
+            Console.WriteLine("ctrl + c 退出程序......");
+
+            Task.Run(WatchConnecting).Wait();                                  // 开启监听线程
+            SocketWatch.Close();                                               // 结束监听socket
+
+        }
+
+
+        static void selfTest()
+        {
+            var rdb = Redis.Ins.GetDatabase(0);
+            Debug.Assert(rdb.StringSet("test", "wanggang" + DateTime.Now.ToString("yyyyMMddHHmmss")), "Redis读写失败!");
+        }
+
+        /// <summary>
+        /// 监听客户端发来的请求  
+        /// </summary>
+        async static Task WatchConnecting()
+        {
+            while (true)                                                                 // 持续不断监听客户端发来的请求     
+            {
+                Socket connection;
+                try
+                {
+                    connection = await SocketWatch.AcceptAsync();
+                }
+                catch (Exception ex)
+                {
+                    Console.WriteLine(ex.Message);                                       // 提示套接字监听异常     
+                    break;
+                }
+
+                Lobby.Instance.OnNewPeerConnected(new Peer(connection));                 // 有新客户端连入
+            }
+        }
+
+    }
+}
+

+ 179 - 0
CSserver/BattleRoom/server/Lobby.cs

@@ -0,0 +1,179 @@
+using System;
+using System.Collections.Generic;
+
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Threading.Channels;
+using ProtoDataBuff;
+
+using CSharpUtil;
+
+namespace MultiDup
+{
+
+
+    /// <summary>
+    /// 大厅 首先玩家连上来之后进入大厅, 下发当前房间列表, 可以创建/加入房间, 进入房间后归房间管
+    /// </summary>
+    internal class Lobby : Singleton<Lobby>
+    {
+
+        /// <summary>
+        /// 客户端
+        /// </summary>
+        public Dictionary<int, Peer> ClientPeers = new Dictionary<int, Peer>();
+        /// <summary>
+        /// 消息分发
+        /// </summary>
+        private Dictionary<eProtocalCommand, Action<int, sSocketData>> callbacks = new Dictionary<eProtocalCommand, Action<int, sSocketData>>();
+
+        /// <summary>
+        /// 客户端消息队列
+        /// </summary>
+        public Channel<KeyValuePair<int, sSocketData>> MsgChannel = Channel.CreateBounded<KeyValuePair<int, sSocketData>>(1000);
+
+
+        Dictionary<int, Room> roomDic = new Dictionary<int, Room>();
+
+
+        public Lobby()
+        {
+            this.callbacks.Add(eProtocalCommand.CsMdEnterLobby, On_EnterLobby);
+            this.callbacks.Add(eProtocalCommand.CsLeaveRoom, On_Leave);
+            callbacks.Add(eProtocalCommand.CsMdGetRoomList, On_GetRoomList);
+            callbacks.Add(eProtocalCommand.CsMdCreateRoom, On_CreateRoom);
+            callbacks.Add(eProtocalCommand.CsMdEnterRoom, On_EnterRoom);
+            var t = Task.Run(MsgLoop);
+
+        }
+        private object lock_peers = new object();
+        public void AddPeer(Peer p)
+        {
+            lock (lock_peers)
+            {
+                this.ClientPeers.Add(p.Id, p);
+            }
+
+        }
+        public void RemovePeer(int peerId)
+        {
+            lock (lock_peers)
+            {
+                if (this.ClientPeers.ContainsKey(peerId))
+                {
+                    this.ClientPeers.Remove(peerId);
+                }
+            }
+        }
+
+        public void OnNewPeerConnected(Peer peer)
+        {
+            AddPeer(peer);
+        }
+
+        /// <summary>
+        /// 进入大厅(登陆自己的uid)
+        /// </summary>
+        /// <param name="data"></param>
+        void On_EnterLobby(int peerId, sSocketData data)
+        {
+            var msg = CS_MD_EnterLobby.Parser.ParseFrom(data._data);
+
+            if (this.ClientPeers.TryGetValue(peerId, out var peer))
+            {
+                peer.SendEvent(eProtocalCommand.ScMdEnterLobby, new SC_MD_EnterLobby() { });
+                peer.CurrentState = ClientState.InLobby;
+                peer.Properties.Add(PropertyName.Uid, msg.Uid);
+                peer.Properties.Add(PropertyName.Zoneid, msg.Zoneid);
+            }
+        }
+
+        /// <summary>
+        /// 查询房间列表
+        /// </summary>
+        /// <param name="data"></param>
+        void On_GetRoomList(int peerId, sSocketData data)
+        {
+
+            var msg = new SC_MD_GetRoomList() { };
+            if (this.ClientPeers.TryGetValue(peerId, out var peer))
+            {
+                this.roomDic.Values.ToList().ForEach(r =>
+                {
+                    var info = new SC_MD_GetRoomList.Types.RoomInfo() { Battleserver =r.BattleServerIp, BattleServerPort=r.BattleServerPort, Mapid = r.mapId, RoomId = r.Id };
+                    r.ClientPeers.Values.ToList().ForEach(peer =>
+                    {
+                        info.PlayerUids.Add(peer.UID);
+                    });
+                    msg.RoomInfos.Add(info);
+                });
+
+                peer.SendEvent(eProtocalCommand.ScMdGetRoomList, msg);
+            }
+        }
+        /// <summary>
+        /// 创建一个房间(副本)
+        /// </summary>
+        /// <param name="data"></param>
+        void On_CreateRoom(int peerId, sSocketData data)
+        {
+            var msg = CS_MD_CreateRoom.Parser.ParseFrom(data._data);
+            if (this.ClientPeers.TryGetValue(peerId, out var peer))
+            {
+                peer.SendEvent(eProtocalCommand.ScMdCreateRoom, new SC_MD_CreateRoom() { });
+                var room = new Room(msg.Mapid);
+                room.AddPeer(peer);                   // 转移进房间
+                roomDic.Add(room.Id, room);
+
+                //RemovePeer(peerId);                                                  // 从大厅移除
+            }
+        }
+
+        /// <summary>
+        /// 进入房间
+        /// </summary>
+        /// <param name="data"></param>
+        void On_EnterRoom(int peerId, sSocketData data)
+        {
+            var msg = CS_MD_EnterRoom.Parser.ParseFrom(data._data);
+            if (this.ClientPeers.TryGetValue(peerId, out var peer))
+            {
+                if (roomDic.TryGetValue(msg.RoomId, out var room))
+                {
+                    room.AddPeer(peer);
+                }
+
+            }
+        }
+
+        /// <summary>
+        /// 离开房间(战斗结束)
+        /// </summary>
+        /// <param name="data"></param>
+        void On_Leave(int peerId, sSocketData data)
+        {
+            if (this.ClientPeers.TryGetValue(peerId, out var peer))
+            {
+                peer.SendEvent(eProtocalCommand.ScMdLeaveRoom, new SC_MD_LeaveRoom() { });
+                peer.Close();
+            }
+        }
+
+        async void MsgLoop()
+        {
+            while (true)
+            {
+                var msg = await MsgChannel.Reader.ReadAsync();
+                if (callbacks.ContainsKey(msg.Value._protocallType))
+                {
+                    callbacks[msg.Value._protocallType](msg.Key, msg.Value);
+                }
+                else
+                {
+                    // 未找到消息处理逻辑
+                }
+            }
+        }
+    }
+}

+ 219 - 0
CSserver/BattleRoom/server/Peer.cs

@@ -0,0 +1,219 @@
+using StackExchange.Redis;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Net.Sockets;
+using System.Threading.Channels;
+using System.Threading.Tasks;
+using ProtoDataBuff;
+using pb = global::Google.Protobuf;
+namespace MultiDup
+{
+    /// <summary>
+    /// 客户端状态
+    /// </summary>
+    enum ClientState
+    {
+        /// <summary>
+        /// 已连接,未登录
+        /// </summary>
+        Connected,
+        /// <summary>
+        /// 在大厅(已登录)
+        /// </summary>
+        InLobby,
+        /// <summary>
+        /// 在房间
+        /// </summary>
+        InRoom,
+        /// <summary>
+        /// 已开始游戏(在房间)
+        /// </summary>
+        InGame,
+        /// <summary>
+        /// 已断开
+        /// </summary>
+        Leaved
+    }
+
+
+    /// <summary>
+    /// 一个连接对象的抽象,代表一个远端的对象
+    /// </summary>
+    class Peer
+    {
+        /// <summary>
+        /// 玩家属性字段
+        /// </summary>
+        public Dictionary<string, object> Properties = new();
+
+        /// <summary>
+        /// 客户端状态字段
+        /// </summary>
+        public ClientState CurrentState = ClientState.Connected;
+
+
+        /// <summary>
+        /// peer的唯一Id
+        /// </summary>
+        public readonly int Id;
+
+        /// <summary>
+        /// socket连接
+        /// </summary>
+        public readonly Socket Sock;
+
+        public string UID => Properties.TryGetValue(PropertyName.Uid, out var uid)? uid.ToString():"";
+            
+        public int zoneid => Properties.TryGetValue(PropertyName.Zoneid, out var zoneid)?Convert.ToInt32(zoneid):1;
+
+
+        public Room room;
+
+        /// <summary>
+        /// 线程安全的peer计数器
+        /// </summary>
+        private volatile static int _UniqPeerId = 0;
+
+        /// <summary>
+        /// 构造函数
+        /// </summary>
+        /// <param name="sock"></param>
+        public Peer(Socket sock)
+        {
+            this.Sock = sock;
+            Sock.ReceiveTimeout = 1500;                                         // 接收等待超时时间设为1.5秒 
+            Id = _UniqPeerId++;
+            var t = Task.Run(() => recv(Sock));                                 // 新建接收线程 
+            var tcs = Task.Run(WriteToClient);                                  // 向客户端发送消息线程
+
+        }
+
+
+        public void Close()
+        {
+            this.CurrentState = ClientState.Leaved;                              // 关闭接收窗口
+            //room.RemovePeer(this);                                      // 从房间中移除自己
+            
+            this.sendDataBuffer.Reader.Completion
+                .ContinueWith(t =>
+                Task.Delay(5000).ContinueWith(t1 => Sock.Close())
+                );                                                               // 延迟5秒关闭套接字
+        }
+
+        #region 消息收发
+
+        /// <summary>
+        /// 向客户端发送事件
+        /// </summary>
+        public void SendEvent(eProtocalCommand msgType, pb::IMessage msg)
+        {
+            SendToClient(msgType, msg);
+        }
+
+        /// <summary>
+        /// 向客户端发送消息
+        /// </summary>
+        /// <param name="msgType"></param>
+        /// <param name="msg"></param>
+        void SendToClient(eProtocalCommand msgType, pb::IMessage msg)
+        {
+            using var ms = new MemoryStream();
+            using var os = new pb::CodedOutputStream(ms);
+            msg.WriteTo(os);
+            os.Flush();
+            ms.Seek(0, SeekOrigin.Begin);
+            var sdata = sSocketData.FromBytes(msgType, ms.ToArray());
+            sendDataBuffer.Writer.WriteAsync(sdata).AsTask().Wait();
+        }
+
+
+        /// <summary>
+        /// 向客户端写入消息
+        /// </summary>
+        async void WriteToClient()
+        {
+            while (true)
+            {
+                try
+                {
+                    var msg = await sendDataBuffer.Reader.ReadAsync();
+                    await Sock.SendAsync(new ArraySegment<byte>(msg.ToBytes()), SocketFlags.None);
+                }
+                catch (Exception)
+                {
+                    break;
+                }
+
+            }
+            Close();
+        }
+
+
+        /// <summary>
+        /// 发送buffer
+        /// </summary>
+        private Channel<sSocketData> sendDataBuffer = Channel.CreateUnbounded<sSocketData>();
+
+        /// <summary>
+        /// 接收客户端发来的信息,客户端套接字对象
+        /// </summary>
+        /// <param name="socketclientpara"></param>    
+        async void recv(Socket socketServer)
+        {
+
+            var _databuffer = new DataBuffer();
+            byte[] arrServerRecMsg = new byte[4096];                                       // 创建一个内存缓冲区,其大小为4k字节  
+            while (true)
+            {
+                try
+                {
+                    var length = await socketServer.ReceiveAsync(new ArraySegment<byte>(arrServerRecMsg), SocketFlags.None);   // 将接收到的信息存入到内存缓冲区,并返回其字节数组的长度    
+                    if (length <= 0 || CurrentState == ClientState.Leaved)                                                     // 视为客户端已经close连接
+                    {
+                        break;
+                    }
+                    _databuffer.AddBuffer(arrServerRecMsg, length);                                  //将收到的数据添加到缓存器中
+                    while (_databuffer.GetData(out sSocketData _socketData))                         //取出一条完整数据,转到room的消息队列,由room统一进行逻辑处理 
+                    {
+                        Console.WriteLine(" recv: " + _socketData._protocallType);
+                        switch (CurrentState)
+                        {
+                            case ClientState.Connected:
+                            case ClientState.InLobby:
+                                await Lobby.Instance.MsgChannel.Writer.WriteAsync(new KeyValuePair<int, sSocketData>(this.Id, _socketData)); // 放入大厅处理队列
+                                break;
+                            case ClientState.InRoom:
+                            case ClientState.InGame:
+                                if (null != room)
+                                {
+                                    await room.MsgChannel.Writer.WriteAsync(new KeyValuePair<int, sSocketData>(this.Id, _socketData));           // 放入房间channel
+                                }
+                                break;
+                            case ClientState.Leaved:
+                                break;
+                        }
+
+                    }
+                    Array.Clear(arrServerRecMsg, 0, length);
+                }
+                catch (SocketException e)
+                {
+                    if (e.ErrorCode == 10060)                                          // 超时的时候错误号码是10060
+                    {
+                        continue;                                                      // 继续等待  
+                    }
+                    break;
+                }
+                catch (Exception)
+                {
+                    break;
+                }
+            }
+
+            Close();                                                                 // 关闭
+        }
+        #endregion
+    }
+
+}

+ 240 - 0
CSserver/BattleRoom/server/Room.cs

@@ -0,0 +1,240 @@
+using CSharpUtil;
+using CSharpUtil.Net;
+using ProtoDataBuff;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Channels;
+using System.Threading.Tasks;
+using static System.Console;
+using pb = global::Google.Protobuf;
+
+namespace MultiDup
+{
+    /// <summary>
+    /// 房间状态
+    /// </summary>
+    enum RoomState
+    {
+        /// <summary>
+        /// 开启状态(可以连接登入)
+        /// </summary>
+        Open,
+        /// <summary>
+        /// 已关闭(不可继续登录)
+        /// </summary>
+        Close,
+    }
+
+    enum TargetType
+    {
+        /// <summary>
+        /// 所有
+        /// </summary>
+        All,
+        /// <summary>
+        /// 其他人
+        /// </summary>
+        Others,
+
+
+    }
+
+    class PropertyName
+    {
+        public const string Uid = nameof(Uid);
+        public const string Name = nameof(Name);
+        public const string Zoneid = nameof(Zoneid);
+        public const string Hp = nameof(Hp);
+        public const string MaxHp = nameof(MaxHp);
+        public const string TotalDamage = nameof(TotalDamage);
+    }
+
+    /// <summary>
+    /// 房间对象
+    /// </summary>
+    class Room
+    {
+
+        /// <summary>
+        /// 房间状态字段
+        /// </summary>
+        public RoomState CurrentState = RoomState.Close;
+
+        /// <summary>
+        /// 客户端
+        /// </summary>
+        public Dictionary<int, Peer> ClientPeers = new Dictionary<int, Peer>();
+
+        /// <summary>
+        /// 消息分发
+        /// </summary>
+        private Dictionary<eProtocalCommand, Action<int, sSocketData>> callbacks = new Dictionary<eProtocalCommand, Action<int, sSocketData>>();
+
+        /// <summary>
+        /// 客户端消息队列
+        /// </summary>
+        public Channel<KeyValuePair<int, sSocketData>> MsgChannel = Channel.CreateBounded<KeyValuePair<int, sSocketData>>(1000);
+
+        // 房间计数器
+        private static int _roomIdCounter = 0;
+        /// <summary>
+        /// 房间编号
+        /// </summary>
+        public int Id { get; }
+
+        public int mapId { get; }
+
+        /// <summary>
+        /// 战斗服务器端口
+        /// </summary>
+        public int BattleServerPort = 6006;
+        /// <summary>
+        /// 战斗服务器IP地址
+        /// </summary>
+        public string BattleServerIp = "192.168.10.17";
+
+        /// <summary>
+        /// 构造函数
+        /// </summary> 
+        public Room(int mapid)
+        {
+            mapId= mapid;
+            Id = _roomIdCounter++; 
+
+            callbacks.Add(eProtocalCommand.CsMdBeginDup, On_Start);
+
+            callbacks.Add(eProtocalCommand.CsLeaveRoom, On_Leave);
+
+            var t = Task.Run(MsgLoop);
+            Open();
+        }
+
+        /// <summary>
+        /// 开始游戏 
+        /// </summary>
+        /// <param name="data"></param>
+        void On_Start(int peerId, sSocketData data)
+        {
+            if (this.ClientPeers.TryGetValue(peerId, out var peer))
+            {
+                Broadcast(TargetType.All, eProtocalCommand.ScMdBeginDup, new SC_MD_BeginDup() { }); 
+            }
+        }
+
+
+        /// <summary>
+        /// 离开房间(战斗结束)
+        /// </summary>
+        /// <param name="data"></param>
+        void On_Leave(int peerId, sSocketData data)
+        {
+            if (this.ClientPeers.TryGetValue(peerId, out var peer))
+            {
+                Broadcast(TargetType.All, eProtocalCommand.ScMdLeaveRoom, new SC_MD_LeaveRoom() { Uid = peer.UID, Zoneid = peer.zoneid });
+                peer.Close();
+                RemovePeer(peerId);
+            }
+        }
+
+
+        #region 网络
+        async void MsgLoop()
+        {
+            while (true)
+            {
+                var msg = await MsgChannel.Reader.ReadAsync();
+                if (callbacks.ContainsKey(msg.Value._protocallType))
+                {
+                    callbacks[msg.Value._protocallType](msg.Key, msg.Value);
+                }
+                else
+                {
+                    // 未找到消息处理逻辑
+                }
+            }
+        }
+        /// <summary>
+        /// 广播消息
+        /// </summary>
+        /// <param name="targetType"></param>
+        /// <param name="msgType"></param>
+        /// <param name="msg"></param>
+        private void Broadcast(TargetType targetType, eProtocalCommand msgType, pb::IMessage msg)
+        {
+            switch (targetType)
+            {
+                case TargetType.All:
+                    this.ClientPeers.Values.ToList().ForEach(p => p.SendEvent(msgType, msg));
+                    break;
+                case TargetType.Others:
+                    break;
+            }
+
+        }
+        #endregion
+
+        /// <summary>
+        /// 开启
+        /// </summary>
+        public void Open()
+        {
+
+            this.CurrentState = RoomState.Open;
+        }
+        public void Close()
+        {
+            this.CurrentState = RoomState.Close;
+            Task.Delay(TimeSpan.FromMinutes(1)).ContinueWith(t => Open());
+        }
+
+
+        private object lock_peers = new object();
+        public void AddPeer(Peer p)
+        {
+            if (CurrentState == RoomState.Open)
+            {
+                lock (lock_peers)
+                {
+                    p.CurrentState = ClientState.InRoom;
+                    p.room = this;
+                    this.ClientPeers.Add(p.Id, p);
+                }
+                var list = new SC_MD_EnterRoom() { Uid = p.UID, Zoneid = p.zoneid };
+                
+                ClientPeers.Values.ToList().ForEach(c => list.PlayerUids.Add(c.UID));
+                Broadcast(TargetType.All, eProtocalCommand.ScMdEnterRoom, list);
+            }
+            else
+            {
+
+                WriteLine("游戏结束2 // 这里不应该执行到!!!");
+                p.SendEvent(eProtocalCommand.ScGameOver, new SC_MD_EnterRoom() { });
+                p.Close();
+            }
+        }
+
+        public void RemovePeer(Peer p)
+        {
+            lock (lock_peers)
+            {
+                if (this.ClientPeers.ContainsKey(p.Id))
+                {
+                    this.ClientPeers.Remove(p.Id);
+                }
+            }
+        }
+        public void RemovePeer(int peerId)
+        {
+            lock (lock_peers)
+            {
+                if (this.ClientPeers.ContainsKey(peerId))
+                {
+                    this.ClientPeers.Remove(peerId);
+                }
+            }
+        }
+
+    }
+
+}

+ 0 - 847
CSserver/BossServer/db/MysqlUtil.cs

@@ -1,847 +0,0 @@
-using MySql.Data.MySqlClient;
-using Newtonsoft.Json.Linq;
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Diagnostics;
-using static System.Diagnostics.Trace;
-using static System.String;
-
-namespace BossServer.db
-{
-    /// <summary>
-    /// MySQL操作辅助类.
-    /// </summary>
-    public class MysqlUtil : IDisposable
-    {
-
-        /// <summary>
-        /// MySQL字段详细信息,(用于GetFiledInfo方法返回值中取信息,可以用nameof来去掉硬编码字符串以防止拼写错误)
-        /// </summary>
-        public enum EFieldInfo
-        {
-            /// <summary>
-            /// 字段类型 in .net
-            /// </summary>
-            Type,
-            /// <summary>
-            /// 是否可空
-            /// </summary>
-            Null,
-            /// <summary>
-            /// 索引类型
-            /// </summary>
-            Key,
-            /// <summary>
-            /// 默认值
-            /// </summary>
-            Default,
-            /// <summary>
-            /// 注释
-            /// </summary>
-            Comment,
-            /// <summary>
-            /// 字符集
-            /// </summary>
-            Collation,
-            /// <summary>
-            /// 额外(自增等)
-            /// </summary>
-            Extra,
-            /// <summary>
-            /// 权限
-            /// </summary>
-            Privileges
-        }
-
-        #region `    基础代码   `
-        static MysqlUtil mInst;
-        public static MysqlUtil Ins
-        {
-            get
-            {
-                if (null == mInst)
-                {
-                    mInst = new MysqlUtil();
-                }
-                return mInst;
-            }
-        }
-
-        private MysqlUtil()
-        {
-            conn = new MySqlConnection(Config.Ins.mysql.ConnectionString);
-            conn.Open();
-            Assert(conn.State == ConnectionState.Open, "连接到数据库失败");
-        }
-  
-        private MySqlConnection conn = null;
-        /// <summary>
-        /// 建立连接
-        /// </summary>
-        /// <param name="host"></param>
-        /// <param name="port"></param>
-        /// <param name="user"></param>
-        /// <param name="pwd"></param>
-        /// <param name="dbName"></param>
-        public void Connect(string host, string port, string user, string pwd, string dbName)
-        {
-            var connStr = string.Format(
-                              "server={0};port={1};user={2};password={3};database={4};Charset=utf8",
-                              host, port, user, pwd, dbName);
-            conn = new MySqlConnection(connStr);
-            conn.Open();
-            Assert(conn.State == ConnectionState.Open, "连接到数据库失败");
-        }
-        /// <summary>
-        /// 关闭连接
-        /// </summary>
-        public void Close()
-        {
-            conn.Close();
-        }
-        /// <summary>
-        /// 释放资源
-        /// </summary>
-        public void Dispose()
-        {
-            conn.Dispose();
-        }
-        #endregion
-
-        #region `    数据读    `
-
-        /// <summary>
-        /// 读取数据库表-数据操作部分逻辑需要参数中定义
-        /// 一般情况下,使用其余八个读取函数即可,如果需要自己定制数据结构,可以通过在此函数回调中自行遍历整个数据表.
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="working">action to MysqlDataReader</param>
-        public void ReadTabel(string tableName, Action<MySqlDataReader> working)
-        {
-            Assert(TableExist(tableName), "表 " + tableName + " 不存在!");
-            var sql = string.Format("SELECT * FROM {0};", tableName);
-            using (var cmd = new MySqlCommand(sql, conn))
-            using (var rdr = cmd.ExecuteReader())
-            {
-                if (null != working) working.Invoke(rdr);
-            }
-        }
-
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个JArray中, []
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// /// <param name="excludeFields">排除的字段名列表</param>
-        /// <returns>JArray</returns>
-        public JArray ReadTabelToJArray(string tableName, params string[] excludeFields)
-        {
-            var ex = new List<string>(excludeFields);
-            var arr = new JArray();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var jobj = new JObject();
-
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            jobj.Add(rdr.GetName(i), JToken.FromObject(rdr.GetValue(i)));
-                        }
-                    }
-                    arr.Add(jobj);
-                }
-            });
-            return arr;
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个JObject中, {}
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="indexFieldName">用做索引的字段名</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <returns>{}</returns>
-        public JObject ReadTabelToJObject(string tableName, string indexFieldName, out bool isArray, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, indexFieldName),
-                Format("在表[{0}]中未找到key:[{1}]", tableName, indexFieldName));
-            bool _isArray = false;
-            var ex = new List<string>(excludeFields);
-            //ex.Add(indexFieldName);
-            var obj = new JObject();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var jobj = new JObject();
-                    var id = "";
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == indexFieldName)
-                        {
-                            id = rdr.GetValue(i).ToString();
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            object v = rdr.GetValue(i);
-
-                            if (DBNull.Value == v)
-                            {
-                                var t = rdr.GetFieldType(i).Name;
-                                switch (t)
-                                {
-                                    case "Int32":
-                                        v = 0;
-                                        break;
-                                    case "String":
-                                        v = "";
-                                        break;
-                                    case "Single":
-                                        v = 0;
-                                        break;
-                                }
-                            }
-                            jobj.Add(rdr.GetName(i), JToken.FromObject(v));
-                        }
-                    }
-                    if (obj[id] == null)
-                    {  // 这段代码智能转换多值对应为[]
-                        obj.Add(id, jobj);
-                    }
-                    else
-                    {
-                        _isArray = true;
-                        var arr = obj[id] as JArray;
-                        if (null != arr)
-                        {
-                            arr.Add(jobj);
-                        }
-                        else
-                        {
-                            obj[id] = new JArray() { obj[id], jobj };
-                        }
-                    }
-                }
-
-            });
-            if (_isArray)
-            {
-                foreach (var o in obj.Properties())
-                {
-                    if (null == (o.Value as JArray))
-                    {
-                        obj[o.Name] = new JArray() { o.Value };
-                    }
-                }
-            }
-            isArray = _isArray;
-            return obj;
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个JObject中, {k->[],k->[],...}
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="indexFieldName">用做索引的字段名</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <returns>{}</returns>
-        public JObject ReadTabelToJObjectWithArrayValues(string tableName, string indexFieldName, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, indexFieldName),
-                Format("在表[{0}]中未找到key:[{1}]", tableName, indexFieldName));
-
-            var ex = new List<string>(excludeFields);
-            //ex.Add(indexFieldName);
-            var obj = new JObject();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var jobj = new JObject();
-                    var id = "";
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == indexFieldName)
-                        {
-                            id = rdr.GetValue(i).ToString();
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            object v = rdr.GetValue(i);
-
-                            if (DBNull.Value == v)
-                            {
-                                var t = rdr.GetFieldType(i).Name;
-                                switch (t)
-                                {
-                                    case "Int32":
-                                        v = 0;
-                                        break;
-                                    case "String":
-                                        v = "";
-                                        break;
-                                    case "Single":
-                                        v = 0;
-                                        break;
-                                }
-                            }
-                            jobj.Add(rdr.GetName(i), JToken.FromObject(v));
-                        }
-                    }
-
-                    var arr = obj[id] as JArray;
-                    if (null != arr)
-                    {
-                        arr.Add(jobj);
-                    }
-                    else
-                    {
-                        obj[id] = new JArray() { jobj };
-                    }
-
-                }
-
-            });
-
-            return obj;
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个简单的key=>value结构中. 即只取表中的两个字段
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="keyName">用作属性名称的字段</param>
-        /// <param name="valueName">用作值的字段</param>
-        /// <returns>{k:v,k:v,...}</returns>
-        public JObject ReadTabelToSimpleJObject(string tableName, string keyName, string valueName)
-        {
-            Assert(HasFiledInTable(tableName, keyName),
-                    Format("在表[{0}]中未找到key:[{1}]", tableName, keyName));
-            Assert(HasFiledInTable(tableName, valueName),
-                Format("在表[{0}]中未找到字段:[{1}]", tableName, valueName));
-            var jobj = new JObject();
-
-            ReadTabel(tableName, rdr =>
-           {
-               while (rdr.Read())
-               {
-                   var key = "";
-                   Object value = null;
-                   for (int i = 0; i < rdr.FieldCount; i++)
-                   {
-                       if (rdr.GetName(i) == keyName)
-                       {
-                           key = rdr.GetValue(i).ToString();
-                       }
-                       if (rdr.GetName(i) == valueName)
-                       {
-                           value = rdr.GetValue(i);
-                       }
-                   }
-                   jobj.Add(key, JToken.FromObject(value));
-               }
-           });
-
-            return jobj;
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个由两个字段内容拼接成的字符串作为索引的JObject中
-        /// </summary>
-        /// <param name="tableName">表名称</param>
-        /// <param name="firstFieldName">第一个字段</param>
-        /// <param name="secondFieldName">第二个字段</param>
-        /// <param name="excludeFields">排除的字段名...</param>
-        /// <returns> {field(1)-field(2):{},...} </returns>
-        public JObject ReadTabelToJObjectWithCombinedIndex(string tableName, string firstFieldName, string secondFieldName, out bool isArray, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, firstFieldName),
-                 Format("在表[{0}]中未找到字段:[{1}]", tableName, firstFieldName));
-            Assert(HasFiledInTable(tableName, secondFieldName),
-                Format("在表[{0}]中未找到字段:[{1}]", tableName, secondFieldName));
-            bool _isArray = false;
-            var ex = new List<string>(excludeFields);
-            //ex.Add(firstFieldName);
-            //ex.Add(secondFieldName);
-            var obj = new JObject();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var jobj = new JObject();
-                    var firstId = "";
-                    var secondId = "";
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == firstFieldName)
-                        {
-                            firstId = rdr.GetValue(i).ToString();
-                        }
-                        if (rdr.GetName(i) == secondFieldName)
-                        {
-                            secondId = rdr.GetValue(i).ToString();
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            Object v = rdr.GetValue(i);
-                            if (DBNull.Value == v)
-                            {
-                                var t = rdr.GetFieldType(i).Name;
-                                switch (t)
-                                {
-                                    case "Int32":
-                                        v = 0;
-                                        break;
-                                    case "String":
-                                        v = "";
-                                        break;
-                                    case "Single":
-                                        v = 0;
-                                        break;
-                                }
-                            }
-                            jobj.Add(rdr.GetName(i), JToken.FromObject(v));
-                        }
-                    }
-                    var key = firstId + "-" + secondId;
-                    if (obj[key] == null)
-                    {  // 防止重复
-                        obj.Add(key, jobj);
-                    }
-                    else
-                    {  // 已有对象 => 智能转换多值对应为[]
-                        _isArray = true;
-                        var arr = obj[key] as JArray;
-                        if (arr != null)
-                        { // 已经是jarray
-                            arr.Add(jobj);
-                        }
-                        else
-                        {    // 创建Jarray
-                            obj[key] = new JArray() { obj[key], jobj };
-                        }
-                    }
-                }
-            });
-
-            if (_isArray)
-            {
-                foreach (var o in obj.Properties())
-                {
-                    if (null == (o.Value as JArray))
-                    {
-                        obj[o.Name] = new JArray() { o.Value };
-                    }
-                }
-            }
-            isArray = _isArray;
-            return obj;
-        }
-
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个{key11:{key1_21:{},key1_22:{},...},key12:{key2_21:{},key2_22:{},...},...}结构数据中
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="indexFieldName">用做索引的字段名</param>
-        /// <param name="secondaryIndexName">用做次级索引的字段名</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <returns>拥有二级索引的json对象,二级节点是{}</returns>
-        public JObject ReadTabelToJObjectWithSecondaryIndex(string tableName,
-            string indexFieldName, string secondaryIndexName, out bool isArray, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, indexFieldName),
-            Format("在表[{0}]中未找到字段:[{1}]", tableName, indexFieldName));
-            Assert(HasFiledInTable(tableName, secondaryIndexName),
-                Format("在表[{0}]中未找到字段:[{1}]", tableName, secondaryIndexName));
-            var _isArray = false;
-            var ex = new List<string>(excludeFields);
-            //ex.Add(indexFieldName);
-            //ex.Add(secondaryIndexName);
-            var obj = new JObject();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var jobj = new JObject();
-                    var id = "";
-                    var secondId = "";
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == indexFieldName)
-                        {
-                            id = rdr.GetValue(i).ToString();
-                        }
-                        if (rdr.GetName(i) == secondaryIndexName)
-                        {
-                            secondId = rdr.GetValue(i).ToString();
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            Object v = rdr.GetValue(i);
-                            if (DBNull.Value == v)
-                            {
-                                var t = rdr.GetFieldType(i).Name;
-                                switch (t)
-                                {
-                                    case "Int32":
-                                        v = 0;
-                                        break;
-                                    case "String":
-                                        v = "";
-                                        break;
-                                    case "Single":
-                                        v = 0;
-                                        break;
-                                }
-                            }
-                            jobj.Add(rdr.GetName(i), JToken.FromObject(v));
-                        }
-                    }
-
-                    if (obj[id] == null)
-                    {  // 没有建立一级对象
-                        var o = new JObject();
-                        o.Add(secondId, jobj);
-                        obj.Add(id, o);
-                    }
-                    else
-                    {  // 已有一级对象
-                        var o = obj[id] as JObject;  // 一级对象
-                        if (o[secondId] == null)
-                        {  // 添加新值
-                            o.Add(secondId, jobj);
-                        }
-                        else
-                        {    // 已有对象 => 智能转换多值对应为[]
-                            _isArray = true;
-                            var arr = o[secondId] as JArray;
-                            if (arr != null)
-                            { // 已经是jarray
-                                arr.Add(jobj);
-                            }
-                            else
-                            {    // 创建Jarray
-                                o[secondId] = new JArray() { o[secondId], jobj };
-                            }
-                        }
-                    }
-                }
-            });
-            if (_isArray)
-            {
-                foreach (var o in obj.Properties())
-                {
-                    foreach (var o2 in (o.Value as JObject).Properties())
-                    {
-                        if (!(obj[o.Name][o2.Name] is JArray))
-                        {
-                            obj[o.Name][o2.Name] = new JArray() { obj[o.Name][o2.Name] };
-                        }
-                    }
-                }
-            }
-            isArray = _isArray;
-            return obj;
-        }
-
-
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个行数组[{},{}]
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <returns>普通行数组[{},{},...]</returns>
-        public Dictionary<string, object>[] ReadTabelToArray(string tableName, params string[] excludeFields)
-        {
-            var ex = new List<string>(excludeFields);
-            var arr = new List<Dictionary<string, object>>();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var r = new Dictionary<string, object>(rdr.FieldCount - 1);
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            r.Add(rdr.GetName(i), rdr.GetValue(i));
-                        }
-                    }
-                    arr.Add(r);
-                }
-            });
-            return arr.ToArray();
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个dic中 {"key":{}}
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="indexFieldName">仅限索引字段(1对多的情况暂不支持)</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <typeparam name="T">string, number</typeparam>
-        /// <returns>嵌套的dictionary:{k:{k,v},k:{k:v},...}</returns>
-        public Dictionary<T, Dictionary<string, object>> ReadTabelToDic_Dic<T>(string tableName, string indexFieldName, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, indexFieldName),
-                Format("在表[{0}]中未找到字段:[{1}]", tableName, indexFieldName));
-            var ex = new List<string>(excludeFields);
-            //ex.Add(indexFieldName);
-            var dic = new Dictionary<T, Dictionary<string, object>>();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var r = new Dictionary<string, object>(rdr.FieldCount - 1);
-                    var t = default(T);
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == indexFieldName)
-                        {
-                            t = (T)rdr.GetValue(i);
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            r.Add(rdr.GetName(i), rdr.GetValue(i));
-                        }
-                    }
-                    dic.Add(t, r);
-                }
-
-            });
-            return dic;
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个dic中 {"key":[]}
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="indexFieldName">索引字段名</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <typeparam name="T">string, number</typeparam>
-        /// <returns>复杂嵌套dictionary:{k:[{},{},..],k:[{},{},..]..}</returns>
-        public Dictionary<T, List<Dictionary<string, object>>> ReadTabelToDic_List<T>(string tableName, string indexFieldName, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, indexFieldName),
-                Format("在表[{0}]中未找到字段:[{1}]", tableName, indexFieldName));
-            var ex = new List<string>(excludeFields);
-            //ex.Add(indexFieldName);
-            var dic = new Dictionary<T, List<Dictionary<string, object>>>();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var r = new Dictionary<string, object>(rdr.FieldCount - 1);
-                    var t = default(T);
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == indexFieldName)
-                        {
-                            t = (T)rdr.GetValue(i);
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            r.Add(rdr.GetName(i), rdr.GetValue(i));
-                        }
-                    }
-                    if (dic.ContainsKey(t))
-                    {
-                        dic[t].Add(r);
-                    }
-                    else
-                    {
-                        dic.Add(t, new List<Dictionary<string, object>> { r });
-                    }
-                }
-            });
-            return dic;
-        }
-
-        #endregion
-
-        #region `   数据写   `
-
-        /// <summary>
-        /// 执行非查询类的SQL语句,比如插入/更新/删除之类的.
-        /// </summary>
-        /// <param name="sql"></param>
-        /// <returns></returns>
-        public int ExecuteSqlNonQuery(string sql) {
-            using var cmd = new MySqlCommand(sql, conn);
-            return cmd.ExecuteNonQuery();
-        }
-
-
-
-        #endregion
-
-        #region '    辅助方法    '
-
-        /// <summary>
-        /// 查询某表中是否存在指定字段
-        /// </summary>
-        /// <param name="tableName"></param>
-        /// <param name="fieldName"></param>
-        /// <returns></returns>
-        public bool HasFiledInTable(string tableName, string fieldName)
-        {
-            Trace.Assert(TableExist(tableName), tableName + " 未找到");
-            return GetTableFieldsInfo(tableName).ContainsKey(fieldName);
-        }
-
-        /// <summary>
-        /// 检查指定的表格是否存在
-        /// </summary>
-        /// <param name="tableName"></param>
-        /// <returns></returns>
-        public bool TableExist(string tableName)
-        {
-            try
-            {
-                new MySqlCommand("select * from " + tableName + " limit 1;", conn).ExecuteNonQuery();
-            }
-            catch (MySqlException ex)
-            {
-                switch (ex.Number)
-                {
-                    case 1146:
-                        return false;
-                    default:
-                        Debug.WriteLine(ex.Message);
-                        return false;
-                }
-            }
-            return true;
-        }
-
-        /// <summary>
-        /// 执行sql
-        /// </summary>
-        /// <param name="sql"></param>
-        public void Query(string sql)
-        {
-            try
-            {
-                using (var cmd = new MySqlCommand(sql, conn))
-                {
-                    cmd.ExecuteNonQuery();
-                }
-            }
-            catch (MySqlException ex)
-            {
-                Debug.WriteLine(ex.Message);
-            }
-        }
-        /// <summary>
-        /// 执行sql 查询
-        /// </summary>
-        /// <param name="sqlcmd"></param>
-        /// <param name="working"></param>
-        public void QueryTable(string sqlcmd, Action<MySqlDataReader> working)
-        {
-            try
-            {
-                using (var cmd = new MySqlCommand(sqlcmd, conn))
-                using (MySqlDataReader rdr = cmd.ExecuteReader())
-                {
-
-                    if (null != working)
-                    {
-                        working.Invoke(rdr);
-                    }
-                }
-            }
-            catch (MySqlException ex)
-            {
-                Debug.WriteLine(ex.Message);
-            }
-        }
-
-        /// <summary>
-        /// 查询表格的字段信息  FieldName :
-        ///     <Type(字段类型 in .net)>
-        ///     <Collation(字符集及排序)>
-        ///     <Null(是否可空)>
-        ///     <Key(索引类型)>
-        ///     <Default(默认值)>
-        ///     <Extra(自增)>
-        ///     <Privileges(权限)>
-        ///     <Comment(注释)>
-        /// </summary>
-        /// <param name="tableName"></param>
-        /// <returns></returns>
-        public Dictionary<string, Dictionary<string, object>> GetTableFieldsInfo(string tableName)
-        {
-            var ex = new List<string>();
-            var dic = new Dictionary<string, Dictionary<string, object>>();
-            QueryTable(string.Format("show full fields from {0}", tableName), rdr =>
-            {
-                while (rdr.Read())
-                {
-
-                    var r = new Dictionary<string, object>();
-                    var fieldName = rdr.GetString(0);
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == "Field")
-                        {
-                            fieldName = rdr.GetString(i);
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            r.Add(rdr.GetName(i), rdr.GetValue(i));
-                        }
-
-                    }
-                    dic.Add(fieldName, r);
-                }
-            });
-            ReadTabel(tableName, rdr =>               // 用。net类型替换掉myslq 类型字符串
-            {
-                for (var i = 0; i < rdr.FieldCount; i++)
-                {
-
-                    var filedName = rdr.GetName(i);               // 字段名
-                    var filedType = rdr.GetFieldType(i).Name;     // 字段类型
-                    if (dic.ContainsKey(filedName))
-                    {
-                        dic[filedName][nameof(EFieldInfo.Type)] = filedType;
-                    }
-                }
-            });
-            return dic;
-        }
-
-        /// <summary>
-        /// 查询表格的最后修改时间
-        /// </summary>
-        /// <param name="tableName"></param>
-        /// <returns>最后修改时间或者创建时间, 异常: 返回当前时间</returns>
-        public DateTime TableLastModified(string tableName)
-        {
-            var sql = string.Format("SELECT UPDATE_TIME, CREATE_TIME " +
-                      "FROM information_schema.tables " +
-                      "where TABLE_SCHEMA='{0}' and TABLE_NAME='{1}'",
-                          this.conn.Database, tableName);
-            using (var cmd = new MySqlCommand(sql, conn))
-            using (MySqlDataReader rdr = cmd.ExecuteReader())
-            {
-                if (rdr.Read())
-                {  // 上次更新时间为null的情况下使用表的创建时间,都找不到值的情况下返回当前时间   
-                    return rdr.IsDBNull(0) ? (rdr.IsDBNull(1) ? DateTime.Now : rdr.GetDateTime(1)) : rdr.GetDateTime(0);
-                }
-            }
-            throw new Exception("没有找到对应的表");
-        }
-        #endregion
-
-
-
-    }
-}

+ 0 - 31
CSserver/BossServer/db/Redis.cs

@@ -1,31 +0,0 @@
-using StackExchange.Redis;
-
-namespace BossServer
-{
-  public  class Redis
-    {
-        private static ConnectionMultiplexer redis;
-
-        static public ConnectionMultiplexer Ins
-        {
-            get
-            {
-                if (null == redis)
-                {
-                    redis = ConnectionMultiplexer.Connect(Config.Ins.redis);
-                }
-                return redis;
-            }
-        }
-        /// <summary>
-        /// 获取操作redis数据库的接口对象
-        /// </summary>
-        /// <param name="id">指定db的编号</param>
-        /// <returns></returns>
-        public static IDatabase Rdb(int id = 0)
-        {
-            return Ins.GetDatabase(id);
-        }
-
-    }
-}

+ 1 - 1
CSserver/BossServer/server/EmailProc.cs

@@ -1,4 +1,4 @@
-using BossServer.db;
+
 using Newtonsoft.Json.Linq;
 using System;
 using System.Diagnostics;

+ 847 - 0
CSserver/Lib1/db/MysqlUtil.cs

@@ -0,0 +1,847 @@
+using MySql.Data.MySqlClient;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Diagnostics;
+using static System.Diagnostics.Trace;
+using static System.String;
+
+
+/// <summary>
+/// MySQL操作辅助类.
+/// </summary>
+public class MysqlUtil : IDisposable
+{
+
+    /// <summary>
+    /// MySQL字段详细信息,(用于GetFiledInfo方法返回值中取信息,可以用nameof来去掉硬编码字符串以防止拼写错误)
+    /// </summary>
+    public enum EFieldInfo
+    {
+        /// <summary>
+        /// 字段类型 in .net
+        /// </summary>
+        Type,
+        /// <summary>
+        /// 是否可空
+        /// </summary>
+        Null,
+        /// <summary>
+        /// 索引类型
+        /// </summary>
+        Key,
+        /// <summary>
+        /// 默认值
+        /// </summary>
+        Default,
+        /// <summary>
+        /// 注释
+        /// </summary>
+        Comment,
+        /// <summary>
+        /// 字符集
+        /// </summary>
+        Collation,
+        /// <summary>
+        /// 额外(自增等)
+        /// </summary>
+        Extra,
+        /// <summary>
+        /// 权限
+        /// </summary>
+        Privileges
+    }
+
+    #region `    基础代码   `
+    static MysqlUtil mInst;
+    public static MysqlUtil Ins
+    {
+        get
+        {
+            if (null == mInst)
+            {
+                mInst = new MysqlUtil();
+            }
+            return mInst;
+        }
+    }
+
+    private MysqlUtil()
+    {
+        conn = new MySqlConnection(Config.Ins.mysql.ConnectionString);
+        conn.Open();
+        Assert(conn.State == ConnectionState.Open, "连接到数据库失败");
+    }
+
+    private MySqlConnection conn = null;
+    /// <summary>
+    /// 建立连接
+    /// </summary>
+    /// <param name="host"></param>
+    /// <param name="port"></param>
+    /// <param name="user"></param>
+    /// <param name="pwd"></param>
+    /// <param name="dbName"></param>
+    public void Connect(string host, string port, string user, string pwd, string dbName)
+    {
+        var connStr = string.Format(
+                          "server={0};port={1};user={2};password={3};database={4};Charset=utf8",
+                          host, port, user, pwd, dbName);
+        conn = new MySqlConnection(connStr);
+        conn.Open();
+        Assert(conn.State == ConnectionState.Open, "连接到数据库失败");
+    }
+    /// <summary>
+    /// 关闭连接
+    /// </summary>
+    public void Close()
+    {
+        conn.Close();
+    }
+    /// <summary>
+    /// 释放资源
+    /// </summary>
+    public void Dispose()
+    {
+        conn.Dispose();
+    }
+    #endregion
+
+    #region `    数据读    `
+
+    /// <summary>
+    /// 读取数据库表-数据操作部分逻辑需要参数中定义
+    /// 一般情况下,使用其余八个读取函数即可,如果需要自己定制数据结构,可以通过在此函数回调中自行遍历整个数据表.
+    /// </summary>
+    /// <param name="tableName">表名</param>
+    /// <param name="working">action to MysqlDataReader</param>
+    public void ReadTabel(string tableName, Action<MySqlDataReader> working)
+    {
+        Assert(TableExist(tableName), "表 " + tableName + " 不存在!");
+        var sql = string.Format("SELECT * FROM {0};", tableName);
+        using (var cmd = new MySqlCommand(sql, conn))
+        using (var rdr = cmd.ExecuteReader())
+        {
+            if (null != working) working.Invoke(rdr);
+        }
+    }
+
+
+    /// <summary>
+    /// 读取数据库表 -> 到一个JArray中, []
+    /// </summary>
+    /// <param name="tableName">表名</param>
+    /// /// <param name="excludeFields">排除的字段名列表</param>
+    /// <returns>JArray</returns>
+    public JArray ReadTabelToJArray(string tableName, params string[] excludeFields)
+    {
+        var ex = new List<string>(excludeFields);
+        var arr = new JArray();
+        ReadTabel(tableName, rdr =>
+        {
+            while (rdr.Read())
+            {
+                var jobj = new JObject();
+
+                for (int i = 0; i < rdr.FieldCount; i++)
+                {
+                    if (!ex.Contains(rdr.GetName(i)))
+                    {
+                        jobj.Add(rdr.GetName(i), JToken.FromObject(rdr.GetValue(i)));
+                    }
+                }
+                arr.Add(jobj);
+            }
+        });
+        return arr;
+    }
+
+    /// <summary>
+    /// 读取数据库表 -> 到一个JObject中, {}
+    /// </summary>
+    /// <param name="tableName">表名</param>
+    /// <param name="indexFieldName">用做索引的字段名</param>
+    /// <param name="excludeFields">排除的字段名列表</param>
+    /// <returns>{}</returns>
+    public JObject ReadTabelToJObject(string tableName, string indexFieldName, out bool isArray, params string[] excludeFields)
+    {
+        Assert(HasFiledInTable(tableName, indexFieldName),
+            Format("在表[{0}]中未找到key:[{1}]", tableName, indexFieldName));
+        bool _isArray = false;
+        var ex = new List<string>(excludeFields);
+        //ex.Add(indexFieldName);
+        var obj = new JObject();
+        ReadTabel(tableName, rdr =>
+        {
+            while (rdr.Read())
+            {
+                var jobj = new JObject();
+                var id = "";
+                for (int i = 0; i < rdr.FieldCount; i++)
+                {
+                    if (rdr.GetName(i) == indexFieldName)
+                    {
+                        id = rdr.GetValue(i).ToString();
+                    }
+                    if (!ex.Contains(rdr.GetName(i)))
+                    {
+                        object v = rdr.GetValue(i);
+
+                        if (DBNull.Value == v)
+                        {
+                            var t = rdr.GetFieldType(i).Name;
+                            switch (t)
+                            {
+                                case "Int32":
+                                    v = 0;
+                                    break;
+                                case "String":
+                                    v = "";
+                                    break;
+                                case "Single":
+                                    v = 0;
+                                    break;
+                            }
+                        }
+                        jobj.Add(rdr.GetName(i), JToken.FromObject(v));
+                    }
+                }
+                if (obj[id] == null)
+                {  // 这段代码智能转换多值对应为[]
+                        obj.Add(id, jobj);
+                }
+                else
+                {
+                    _isArray = true;
+                    var arr = obj[id] as JArray;
+                    if (null != arr)
+                    {
+                        arr.Add(jobj);
+                    }
+                    else
+                    {
+                        obj[id] = new JArray() { obj[id], jobj };
+                    }
+                }
+            }
+
+        });
+        if (_isArray)
+        {
+            foreach (var o in obj.Properties())
+            {
+                if (null == (o.Value as JArray))
+                {
+                    obj[o.Name] = new JArray() { o.Value };
+                }
+            }
+        }
+        isArray = _isArray;
+        return obj;
+    }
+
+    /// <summary>
+    /// 读取数据库表 -> 到一个JObject中, {k->[],k->[],...}
+    /// </summary>
+    /// <param name="tableName">表名</param>
+    /// <param name="indexFieldName">用做索引的字段名</param>
+    /// <param name="excludeFields">排除的字段名列表</param>
+    /// <returns>{}</returns>
+    public JObject ReadTabelToJObjectWithArrayValues(string tableName, string indexFieldName, params string[] excludeFields)
+    {
+        Assert(HasFiledInTable(tableName, indexFieldName),
+            Format("在表[{0}]中未找到key:[{1}]", tableName, indexFieldName));
+
+        var ex = new List<string>(excludeFields);
+        //ex.Add(indexFieldName);
+        var obj = new JObject();
+        ReadTabel(tableName, rdr =>
+        {
+            while (rdr.Read())
+            {
+                var jobj = new JObject();
+                var id = "";
+                for (int i = 0; i < rdr.FieldCount; i++)
+                {
+                    if (rdr.GetName(i) == indexFieldName)
+                    {
+                        id = rdr.GetValue(i).ToString();
+                    }
+                    if (!ex.Contains(rdr.GetName(i)))
+                    {
+                        object v = rdr.GetValue(i);
+
+                        if (DBNull.Value == v)
+                        {
+                            var t = rdr.GetFieldType(i).Name;
+                            switch (t)
+                            {
+                                case "Int32":
+                                    v = 0;
+                                    break;
+                                case "String":
+                                    v = "";
+                                    break;
+                                case "Single":
+                                    v = 0;
+                                    break;
+                            }
+                        }
+                        jobj.Add(rdr.GetName(i), JToken.FromObject(v));
+                    }
+                }
+
+                var arr = obj[id] as JArray;
+                if (null != arr)
+                {
+                    arr.Add(jobj);
+                }
+                else
+                {
+                    obj[id] = new JArray() { jobj };
+                }
+
+            }
+
+        });
+
+        return obj;
+    }
+
+    /// <summary>
+    /// 读取数据库表 -> 到一个简单的key=>value结构中. 即只取表中的两个字段
+    /// </summary>
+    /// <param name="tableName">表名</param>
+    /// <param name="keyName">用作属性名称的字段</param>
+    /// <param name="valueName">用作值的字段</param>
+    /// <returns>{k:v,k:v,...}</returns>
+    public JObject ReadTabelToSimpleJObject(string tableName, string keyName, string valueName)
+    {
+        Assert(HasFiledInTable(tableName, keyName),
+                Format("在表[{0}]中未找到key:[{1}]", tableName, keyName));
+        Assert(HasFiledInTable(tableName, valueName),
+            Format("在表[{0}]中未找到字段:[{1}]", tableName, valueName));
+        var jobj = new JObject();
+
+        ReadTabel(tableName, rdr =>
+       {
+           while (rdr.Read())
+           {
+               var key = "";
+               Object value = null;
+               for (int i = 0; i < rdr.FieldCount; i++)
+               {
+                   if (rdr.GetName(i) == keyName)
+                   {
+                       key = rdr.GetValue(i).ToString();
+                   }
+                   if (rdr.GetName(i) == valueName)
+                   {
+                       value = rdr.GetValue(i);
+                   }
+               }
+               jobj.Add(key, JToken.FromObject(value));
+           }
+       });
+
+        return jobj;
+    }
+
+    /// <summary>
+    /// 读取数据库表 -> 到一个由两个字段内容拼接成的字符串作为索引的JObject中
+    /// </summary>
+    /// <param name="tableName">表名称</param>
+    /// <param name="firstFieldName">第一个字段</param>
+    /// <param name="secondFieldName">第二个字段</param>
+    /// <param name="excludeFields">排除的字段名...</param>
+    /// <returns> {field(1)-field(2):{},...} </returns>
+    public JObject ReadTabelToJObjectWithCombinedIndex(string tableName, string firstFieldName, string secondFieldName, out bool isArray, params string[] excludeFields)
+    {
+        Assert(HasFiledInTable(tableName, firstFieldName),
+             Format("在表[{0}]中未找到字段:[{1}]", tableName, firstFieldName));
+        Assert(HasFiledInTable(tableName, secondFieldName),
+            Format("在表[{0}]中未找到字段:[{1}]", tableName, secondFieldName));
+        bool _isArray = false;
+        var ex = new List<string>(excludeFields);
+        //ex.Add(firstFieldName);
+        //ex.Add(secondFieldName);
+        var obj = new JObject();
+        ReadTabel(tableName, rdr =>
+        {
+            while (rdr.Read())
+            {
+                var jobj = new JObject();
+                var firstId = "";
+                var secondId = "";
+                for (int i = 0; i < rdr.FieldCount; i++)
+                {
+                    if (rdr.GetName(i) == firstFieldName)
+                    {
+                        firstId = rdr.GetValue(i).ToString();
+                    }
+                    if (rdr.GetName(i) == secondFieldName)
+                    {
+                        secondId = rdr.GetValue(i).ToString();
+                    }
+                    if (!ex.Contains(rdr.GetName(i)))
+                    {
+                        Object v = rdr.GetValue(i);
+                        if (DBNull.Value == v)
+                        {
+                            var t = rdr.GetFieldType(i).Name;
+                            switch (t)
+                            {
+                                case "Int32":
+                                    v = 0;
+                                    break;
+                                case "String":
+                                    v = "";
+                                    break;
+                                case "Single":
+                                    v = 0;
+                                    break;
+                            }
+                        }
+                        jobj.Add(rdr.GetName(i), JToken.FromObject(v));
+                    }
+                }
+                var key = firstId + "-" + secondId;
+                if (obj[key] == null)
+                {  // 防止重复
+                        obj.Add(key, jobj);
+                }
+                else
+                {  // 已有对象 => 智能转换多值对应为[]
+                        _isArray = true;
+                    var arr = obj[key] as JArray;
+                    if (arr != null)
+                    { // 已经是jarray
+                            arr.Add(jobj);
+                    }
+                    else
+                    {    // 创建Jarray
+                            obj[key] = new JArray() { obj[key], jobj };
+                    }
+                }
+            }
+        });
+
+        if (_isArray)
+        {
+            foreach (var o in obj.Properties())
+            {
+                if (null == (o.Value as JArray))
+                {
+                    obj[o.Name] = new JArray() { o.Value };
+                }
+            }
+        }
+        isArray = _isArray;
+        return obj;
+    }
+
+
+    /// <summary>
+    /// 读取数据库表 -> 到一个{key11:{key1_21:{},key1_22:{},...},key12:{key2_21:{},key2_22:{},...},...}结构数据中
+    /// </summary>
+    /// <param name="tableName">表名</param>
+    /// <param name="indexFieldName">用做索引的字段名</param>
+    /// <param name="secondaryIndexName">用做次级索引的字段名</param>
+    /// <param name="excludeFields">排除的字段名列表</param>
+    /// <returns>拥有二级索引的json对象,二级节点是{}</returns>
+    public JObject ReadTabelToJObjectWithSecondaryIndex(string tableName,
+        string indexFieldName, string secondaryIndexName, out bool isArray, params string[] excludeFields)
+    {
+        Assert(HasFiledInTable(tableName, indexFieldName),
+        Format("在表[{0}]中未找到字段:[{1}]", tableName, indexFieldName));
+        Assert(HasFiledInTable(tableName, secondaryIndexName),
+            Format("在表[{0}]中未找到字段:[{1}]", tableName, secondaryIndexName));
+        var _isArray = false;
+        var ex = new List<string>(excludeFields);
+        //ex.Add(indexFieldName);
+        //ex.Add(secondaryIndexName);
+        var obj = new JObject();
+        ReadTabel(tableName, rdr =>
+        {
+            while (rdr.Read())
+            {
+                var jobj = new JObject();
+                var id = "";
+                var secondId = "";
+                for (int i = 0; i < rdr.FieldCount; i++)
+                {
+                    if (rdr.GetName(i) == indexFieldName)
+                    {
+                        id = rdr.GetValue(i).ToString();
+                    }
+                    if (rdr.GetName(i) == secondaryIndexName)
+                    {
+                        secondId = rdr.GetValue(i).ToString();
+                    }
+                    if (!ex.Contains(rdr.GetName(i)))
+                    {
+                        Object v = rdr.GetValue(i);
+                        if (DBNull.Value == v)
+                        {
+                            var t = rdr.GetFieldType(i).Name;
+                            switch (t)
+                            {
+                                case "Int32":
+                                    v = 0;
+                                    break;
+                                case "String":
+                                    v = "";
+                                    break;
+                                case "Single":
+                                    v = 0;
+                                    break;
+                            }
+                        }
+                        jobj.Add(rdr.GetName(i), JToken.FromObject(v));
+                    }
+                }
+
+                if (obj[id] == null)
+                {  // 没有建立一级对象
+                        var o = new JObject();
+                    o.Add(secondId, jobj);
+                    obj.Add(id, o);
+                }
+                else
+                {  // 已有一级对象
+                        var o = obj[id] as JObject;  // 一级对象
+                        if (o[secondId] == null)
+                    {  // 添加新值
+                            o.Add(secondId, jobj);
+                    }
+                    else
+                    {    // 已有对象 => 智能转换多值对应为[]
+                            _isArray = true;
+                        var arr = o[secondId] as JArray;
+                        if (arr != null)
+                        { // 已经是jarray
+                                arr.Add(jobj);
+                        }
+                        else
+                        {    // 创建Jarray
+                                o[secondId] = new JArray() { o[secondId], jobj };
+                        }
+                    }
+                }
+            }
+        });
+        if (_isArray)
+        {
+            foreach (var o in obj.Properties())
+            {
+                foreach (var o2 in (o.Value as JObject).Properties())
+                {
+                    if (!(obj[o.Name][o2.Name] is JArray))
+                    {
+                        obj[o.Name][o2.Name] = new JArray() { obj[o.Name][o2.Name] };
+                    }
+                }
+            }
+        }
+        isArray = _isArray;
+        return obj;
+    }
+
+
+
+    /// <summary>
+    /// 读取数据库表 -> 到一个行数组[{},{}]
+    /// </summary>
+    /// <param name="tableName">表名</param>
+    /// <param name="excludeFields">排除的字段名列表</param>
+    /// <returns>普通行数组[{},{},...]</returns>
+    public Dictionary<string, object>[] ReadTabelToArray(string tableName, params string[] excludeFields)
+    {
+        var ex = new List<string>(excludeFields);
+        var arr = new List<Dictionary<string, object>>();
+        ReadTabel(tableName, rdr =>
+        {
+            while (rdr.Read())
+            {
+                var r = new Dictionary<string, object>(rdr.FieldCount - 1);
+                for (int i = 0; i < rdr.FieldCount; i++)
+                {
+                    if (!ex.Contains(rdr.GetName(i)))
+                    {
+                        r.Add(rdr.GetName(i), rdr.GetValue(i));
+                    }
+                }
+                arr.Add(r);
+            }
+        });
+        return arr.ToArray();
+    }
+
+    /// <summary>
+    /// 读取数据库表 -> 到一个dic中 {"key":{}}
+    /// </summary>
+    /// <param name="tableName">表名</param>
+    /// <param name="indexFieldName">仅限索引字段(1对多的情况暂不支持)</param>
+    /// <param name="excludeFields">排除的字段名列表</param>
+    /// <typeparam name="T">string, number</typeparam>
+    /// <returns>嵌套的dictionary:{k:{k,v},k:{k:v},...}</returns>
+    public Dictionary<T, Dictionary<string, object>> ReadTabelToDic_Dic<T>(string tableName, string indexFieldName, params string[] excludeFields)
+    {
+        Assert(HasFiledInTable(tableName, indexFieldName),
+            Format("在表[{0}]中未找到字段:[{1}]", tableName, indexFieldName));
+        var ex = new List<string>(excludeFields);
+        //ex.Add(indexFieldName);
+        var dic = new Dictionary<T, Dictionary<string, object>>();
+        ReadTabel(tableName, rdr =>
+        {
+            while (rdr.Read())
+            {
+                var r = new Dictionary<string, object>(rdr.FieldCount - 1);
+                var t = default(T);
+                for (int i = 0; i < rdr.FieldCount; i++)
+                {
+                    if (rdr.GetName(i) == indexFieldName)
+                    {
+                        t = (T)rdr.GetValue(i);
+                    }
+                    if (!ex.Contains(rdr.GetName(i)))
+                    {
+                        r.Add(rdr.GetName(i), rdr.GetValue(i));
+                    }
+                }
+                dic.Add(t, r);
+            }
+
+        });
+        return dic;
+    }
+
+    /// <summary>
+    /// 读取数据库表 -> 到一个dic中 {"key":[]}
+    /// </summary>
+    /// <param name="tableName">表名</param>
+    /// <param name="indexFieldName">索引字段名</param>
+    /// <param name="excludeFields">排除的字段名列表</param>
+    /// <typeparam name="T">string, number</typeparam>
+    /// <returns>复杂嵌套dictionary:{k:[{},{},..],k:[{},{},..]..}</returns>
+    public Dictionary<T, List<Dictionary<string, object>>> ReadTabelToDic_List<T>(string tableName, string indexFieldName, params string[] excludeFields)
+    {
+        Assert(HasFiledInTable(tableName, indexFieldName),
+            Format("在表[{0}]中未找到字段:[{1}]", tableName, indexFieldName));
+        var ex = new List<string>(excludeFields);
+        //ex.Add(indexFieldName);
+        var dic = new Dictionary<T, List<Dictionary<string, object>>>();
+        ReadTabel(tableName, rdr =>
+        {
+            while (rdr.Read())
+            {
+                var r = new Dictionary<string, object>(rdr.FieldCount - 1);
+                var t = default(T);
+                for (int i = 0; i < rdr.FieldCount; i++)
+                {
+                    if (rdr.GetName(i) == indexFieldName)
+                    {
+                        t = (T)rdr.GetValue(i);
+                    }
+                    if (!ex.Contains(rdr.GetName(i)))
+                    {
+                        r.Add(rdr.GetName(i), rdr.GetValue(i));
+                    }
+                }
+                if (dic.ContainsKey(t))
+                {
+                    dic[t].Add(r);
+                }
+                else
+                {
+                    dic.Add(t, new List<Dictionary<string, object>> { r });
+                }
+            }
+        });
+        return dic;
+    }
+
+    #endregion
+
+    #region `   数据写   `
+
+    /// <summary>
+    /// 执行非查询类的SQL语句,比如插入/更新/删除之类的.
+    /// </summary>
+    /// <param name="sql"></param>
+    /// <returns></returns>
+    public int ExecuteSqlNonQuery(string sql)
+    {
+        using var cmd = new MySqlCommand(sql, conn);
+        return cmd.ExecuteNonQuery();
+    }
+
+
+
+    #endregion
+
+    #region '    辅助方法    '
+
+    /// <summary>
+    /// 查询某表中是否存在指定字段
+    /// </summary>
+    /// <param name="tableName"></param>
+    /// <param name="fieldName"></param>
+    /// <returns></returns>
+    public bool HasFiledInTable(string tableName, string fieldName)
+    {
+        Trace.Assert(TableExist(tableName), tableName + " 未找到");
+        return GetTableFieldsInfo(tableName).ContainsKey(fieldName);
+    }
+
+    /// <summary>
+    /// 检查指定的表格是否存在
+    /// </summary>
+    /// <param name="tableName"></param>
+    /// <returns></returns>
+    public bool TableExist(string tableName)
+    {
+        try
+        {
+            new MySqlCommand("select * from " + tableName + " limit 1;", conn).ExecuteNonQuery();
+        }
+        catch (MySqlException ex)
+        {
+            switch (ex.Number)
+            {
+                case 1146:
+                    return false;
+                default:
+                    Debug.WriteLine(ex.Message);
+                    return false;
+            }
+        }
+        return true;
+    }
+
+    /// <summary>
+    /// 执行sql
+    /// </summary>
+    /// <param name="sql"></param>
+    public void Query(string sql)
+    {
+        try
+        {
+            using (var cmd = new MySqlCommand(sql, conn))
+            {
+                cmd.ExecuteNonQuery();
+            }
+        }
+        catch (MySqlException ex)
+        {
+            Debug.WriteLine(ex.Message);
+        }
+    }
+    /// <summary>
+    /// 执行sql 查询
+    /// </summary>
+    /// <param name="sqlcmd"></param>
+    /// <param name="working"></param>
+    public void QueryTable(string sqlcmd, Action<MySqlDataReader> working)
+    {
+        try
+        {
+            using (var cmd = new MySqlCommand(sqlcmd, conn))
+            using (MySqlDataReader rdr = cmd.ExecuteReader())
+            {
+
+                if (null != working)
+                {
+                    working.Invoke(rdr);
+                }
+            }
+        }
+        catch (MySqlException ex)
+        {
+            Debug.WriteLine(ex.Message);
+        }
+    }
+
+    /// <summary>
+    /// 查询表格的字段信息  FieldName :
+    ///     <Type(字段类型 in .net)>
+    ///     <Collation(字符集及排序)>
+    ///     <Null(是否可空)>
+    ///     <Key(索引类型)>
+    ///     <Default(默认值)>
+    ///     <Extra(自增)>
+    ///     <Privileges(权限)>
+    ///     <Comment(注释)>
+    /// </summary>
+    /// <param name="tableName"></param>
+    /// <returns></returns>
+    public Dictionary<string, Dictionary<string, object>> GetTableFieldsInfo(string tableName)
+    {
+        var ex = new List<string>();
+        var dic = new Dictionary<string, Dictionary<string, object>>();
+        QueryTable(string.Format("show full fields from {0}", tableName), rdr =>
+        {
+            while (rdr.Read())
+            {
+
+                var r = new Dictionary<string, object>();
+                var fieldName = rdr.GetString(0);
+                for (int i = 0; i < rdr.FieldCount; i++)
+                {
+                    if (rdr.GetName(i) == "Field")
+                    {
+                        fieldName = rdr.GetString(i);
+                    }
+                    if (!ex.Contains(rdr.GetName(i)))
+                    {
+                        r.Add(rdr.GetName(i), rdr.GetValue(i));
+                    }
+
+                }
+                dic.Add(fieldName, r);
+            }
+        });
+        ReadTabel(tableName, rdr =>               // 用。net类型替换掉myslq 类型字符串
+        {
+            for (var i = 0; i < rdr.FieldCount; i++)
+            {
+
+                var filedName = rdr.GetName(i);               // 字段名
+                    var filedType = rdr.GetFieldType(i).Name;     // 字段类型
+                    if (dic.ContainsKey(filedName))
+                {
+                    dic[filedName][nameof(EFieldInfo.Type)] = filedType;
+                }
+            }
+        });
+        return dic;
+    }
+
+    /// <summary>
+    /// 查询表格的最后修改时间
+    /// </summary>
+    /// <param name="tableName"></param>
+    /// <returns>最后修改时间或者创建时间, 异常: 返回当前时间</returns>
+    public DateTime TableLastModified(string tableName)
+    {
+        var sql = string.Format("SELECT UPDATE_TIME, CREATE_TIME " +
+                  "FROM information_schema.tables " +
+                  "where TABLE_SCHEMA='{0}' and TABLE_NAME='{1}'",
+                      this.conn.Database, tableName);
+        using (var cmd = new MySqlCommand(sql, conn))
+        using (MySqlDataReader rdr = cmd.ExecuteReader())
+        {
+            if (rdr.Read())
+            {  // 上次更新时间为null的情况下使用表的创建时间,都找不到值的情况下返回当前时间   
+                return rdr.IsDBNull(0) ? (rdr.IsDBNull(1) ? DateTime.Now : rdr.GetDateTime(1)) : rdr.GetDateTime(0);
+            }
+        }
+        throw new Exception("没有找到对应的表");
+    }
+    #endregion
+
+
+
+}
+

+ 30 - 0
CSserver/Lib1/db/Redis.cs

@@ -0,0 +1,30 @@
+using StackExchange.Redis;
+
+
+public class Redis
+{
+    private static ConnectionMultiplexer redis;
+
+    static public ConnectionMultiplexer Ins
+    {
+        get
+        {
+            if (null == redis)
+            {
+                redis = ConnectionMultiplexer.Connect(Config.Ins.redis);
+            }
+            return redis;
+        }
+    }
+    /// <summary>
+    /// 获取操作redis数据库的接口对象
+    /// </summary>
+    /// <param name="id">指定db的编号</param>
+    /// <returns></returns>
+    public static IDatabase Rdb(int id = 0)
+    {
+        return Ins.GetDatabase(id);
+    }
+
+}
+

+ 0 - 847
CSserver/MultiDup/db/MysqlUtil.cs

@@ -1,847 +0,0 @@
-using MySql.Data.MySqlClient;
-using Newtonsoft.Json.Linq;
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Diagnostics;
-using static System.Diagnostics.Trace;
-using static System.String;
-
-namespace MultiDup
-{
-    /// <summary>
-    /// MySQL操作辅助类.
-    /// </summary>
-    public class MysqlUtil : IDisposable
-    {
-
-        /// <summary>
-        /// MySQL字段详细信息,(用于GetFiledInfo方法返回值中取信息,可以用nameof来去掉硬编码字符串以防止拼写错误)
-        /// </summary>
-        public enum EFieldInfo
-        {
-            /// <summary>
-            /// 字段类型 in .net
-            /// </summary>
-            Type,
-            /// <summary>
-            /// 是否可空
-            /// </summary>
-            Null,
-            /// <summary>
-            /// 索引类型
-            /// </summary>
-            Key,
-            /// <summary>
-            /// 默认值
-            /// </summary>
-            Default,
-            /// <summary>
-            /// 注释
-            /// </summary>
-            Comment,
-            /// <summary>
-            /// 字符集
-            /// </summary>
-            Collation,
-            /// <summary>
-            /// 额外(自增等)
-            /// </summary>
-            Extra,
-            /// <summary>
-            /// 权限
-            /// </summary>
-            Privileges
-        }
-
-        #region `    基础代码   `
-        static MysqlUtil mInst;
-        public static MysqlUtil Ins
-        {
-            get
-            {
-                if (null == mInst)
-                {
-                    mInst = new MysqlUtil();
-                }
-                return mInst;
-            }
-        }
-
-        private MysqlUtil()
-        {
-            conn = new MySqlConnection(Config.Ins.mysql.ConnectionString);
-            conn.Open();
-            Assert(conn.State == ConnectionState.Open, "连接到数据库失败");
-        }
-  
-        private MySqlConnection conn = null;
-        /// <summary>
-        /// 建立连接
-        /// </summary>
-        /// <param name="host"></param>
-        /// <param name="port"></param>
-        /// <param name="user"></param>
-        /// <param name="pwd"></param>
-        /// <param name="dbName"></param>
-        public void Connect(string host, string port, string user, string pwd, string dbName)
-        {
-            var connStr = string.Format(
-                              "server={0};port={1};user={2};password={3};database={4};Charset=utf8",
-                              host, port, user, pwd, dbName);
-            conn = new MySqlConnection(connStr);
-            conn.Open();
-            Assert(conn.State == ConnectionState.Open, "连接到数据库失败");
-        }
-        /// <summary>
-        /// 关闭连接
-        /// </summary>
-        public void Close()
-        {
-            conn.Close();
-        }
-        /// <summary>
-        /// 释放资源
-        /// </summary>
-        public void Dispose()
-        {
-            conn.Dispose();
-        }
-        #endregion
-
-        #region `    数据读    `
-
-        /// <summary>
-        /// 读取数据库表-数据操作部分逻辑需要参数中定义
-        /// 一般情况下,使用其余八个读取函数即可,如果需要自己定制数据结构,可以通过在此函数回调中自行遍历整个数据表.
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="working">action to MysqlDataReader</param>
-        public void ReadTabel(string tableName, Action<MySqlDataReader> working)
-        {
-            Assert(TableExist(tableName), "表 " + tableName + " 不存在!");
-            var sql = string.Format("SELECT * FROM {0};", tableName);
-            using (var cmd = new MySqlCommand(sql, conn))
-            using (var rdr = cmd.ExecuteReader())
-            {
-                if (null != working) working.Invoke(rdr);
-            }
-        }
-
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个JArray中, []
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// /// <param name="excludeFields">排除的字段名列表</param>
-        /// <returns>JArray</returns>
-        public JArray ReadTabelToJArray(string tableName, params string[] excludeFields)
-        {
-            var ex = new List<string>(excludeFields);
-            var arr = new JArray();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var jobj = new JObject();
-
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            jobj.Add(rdr.GetName(i), JToken.FromObject(rdr.GetValue(i)));
-                        }
-                    }
-                    arr.Add(jobj);
-                }
-            });
-            return arr;
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个JObject中, {}
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="indexFieldName">用做索引的字段名</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <returns>{}</returns>
-        public JObject ReadTabelToJObject(string tableName, string indexFieldName, out bool isArray, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, indexFieldName),
-                Format("在表[{0}]中未找到key:[{1}]", tableName, indexFieldName));
-            bool _isArray = false;
-            var ex = new List<string>(excludeFields);
-            //ex.Add(indexFieldName);
-            var obj = new JObject();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var jobj = new JObject();
-                    var id = "";
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == indexFieldName)
-                        {
-                            id = rdr.GetValue(i).ToString();
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            object v = rdr.GetValue(i);
-
-                            if (DBNull.Value == v)
-                            {
-                                var t = rdr.GetFieldType(i).Name;
-                                switch (t)
-                                {
-                                    case "Int32":
-                                        v = 0;
-                                        break;
-                                    case "String":
-                                        v = "";
-                                        break;
-                                    case "Single":
-                                        v = 0;
-                                        break;
-                                }
-                            }
-                            jobj.Add(rdr.GetName(i), JToken.FromObject(v));
-                        }
-                    }
-                    if (obj[id] == null)
-                    {  // 这段代码智能转换多值对应为[]
-                        obj.Add(id, jobj);
-                    }
-                    else
-                    {
-                        _isArray = true;
-                        var arr = obj[id] as JArray;
-                        if (null != arr)
-                        {
-                            arr.Add(jobj);
-                        }
-                        else
-                        {
-                            obj[id] = new JArray() { obj[id], jobj };
-                        }
-                    }
-                }
-
-            });
-            if (_isArray)
-            {
-                foreach (var o in obj.Properties())
-                {
-                    if (null == (o.Value as JArray))
-                    {
-                        obj[o.Name] = new JArray() { o.Value };
-                    }
-                }
-            }
-            isArray = _isArray;
-            return obj;
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个JObject中, {k->[],k->[],...}
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="indexFieldName">用做索引的字段名</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <returns>{}</returns>
-        public JObject ReadTabelToJObjectWithArrayValues(string tableName, string indexFieldName, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, indexFieldName),
-                Format("在表[{0}]中未找到key:[{1}]", tableName, indexFieldName));
-
-            var ex = new List<string>(excludeFields);
-            //ex.Add(indexFieldName);
-            var obj = new JObject();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var jobj = new JObject();
-                    var id = "";
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == indexFieldName)
-                        {
-                            id = rdr.GetValue(i).ToString();
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            object v = rdr.GetValue(i);
-
-                            if (DBNull.Value == v)
-                            {
-                                var t = rdr.GetFieldType(i).Name;
-                                switch (t)
-                                {
-                                    case "Int32":
-                                        v = 0;
-                                        break;
-                                    case "String":
-                                        v = "";
-                                        break;
-                                    case "Single":
-                                        v = 0;
-                                        break;
-                                }
-                            }
-                            jobj.Add(rdr.GetName(i), JToken.FromObject(v));
-                        }
-                    }
-
-                    var arr = obj[id] as JArray;
-                    if (null != arr)
-                    {
-                        arr.Add(jobj);
-                    }
-                    else
-                    {
-                        obj[id] = new JArray() { jobj };
-                    }
-
-                }
-
-            });
-
-            return obj;
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个简单的key=>value结构中. 即只取表中的两个字段
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="keyName">用作属性名称的字段</param>
-        /// <param name="valueName">用作值的字段</param>
-        /// <returns>{k:v,k:v,...}</returns>
-        public JObject ReadTabelToSimpleJObject(string tableName, string keyName, string valueName)
-        {
-            Assert(HasFiledInTable(tableName, keyName),
-                    Format("在表[{0}]中未找到key:[{1}]", tableName, keyName));
-            Assert(HasFiledInTable(tableName, valueName),
-                Format("在表[{0}]中未找到字段:[{1}]", tableName, valueName));
-            var jobj = new JObject();
-
-            ReadTabel(tableName, rdr =>
-           {
-               while (rdr.Read())
-               {
-                   var key = "";
-                   Object value = null;
-                   for (int i = 0; i < rdr.FieldCount; i++)
-                   {
-                       if (rdr.GetName(i) == keyName)
-                       {
-                           key = rdr.GetValue(i).ToString();
-                       }
-                       if (rdr.GetName(i) == valueName)
-                       {
-                           value = rdr.GetValue(i);
-                       }
-                   }
-                   jobj.Add(key, JToken.FromObject(value));
-               }
-           });
-
-            return jobj;
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个由两个字段内容拼接成的字符串作为索引的JObject中
-        /// </summary>
-        /// <param name="tableName">表名称</param>
-        /// <param name="firstFieldName">第一个字段</param>
-        /// <param name="secondFieldName">第二个字段</param>
-        /// <param name="excludeFields">排除的字段名...</param>
-        /// <returns> {field(1)-field(2):{},...} </returns>
-        public JObject ReadTabelToJObjectWithCombinedIndex(string tableName, string firstFieldName, string secondFieldName, out bool isArray, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, firstFieldName),
-                 Format("在表[{0}]中未找到字段:[{1}]", tableName, firstFieldName));
-            Assert(HasFiledInTable(tableName, secondFieldName),
-                Format("在表[{0}]中未找到字段:[{1}]", tableName, secondFieldName));
-            bool _isArray = false;
-            var ex = new List<string>(excludeFields);
-            //ex.Add(firstFieldName);
-            //ex.Add(secondFieldName);
-            var obj = new JObject();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var jobj = new JObject();
-                    var firstId = "";
-                    var secondId = "";
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == firstFieldName)
-                        {
-                            firstId = rdr.GetValue(i).ToString();
-                        }
-                        if (rdr.GetName(i) == secondFieldName)
-                        {
-                            secondId = rdr.GetValue(i).ToString();
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            Object v = rdr.GetValue(i);
-                            if (DBNull.Value == v)
-                            {
-                                var t = rdr.GetFieldType(i).Name;
-                                switch (t)
-                                {
-                                    case "Int32":
-                                        v = 0;
-                                        break;
-                                    case "String":
-                                        v = "";
-                                        break;
-                                    case "Single":
-                                        v = 0;
-                                        break;
-                                }
-                            }
-                            jobj.Add(rdr.GetName(i), JToken.FromObject(v));
-                        }
-                    }
-                    var key = firstId + "-" + secondId;
-                    if (obj[key] == null)
-                    {  // 防止重复
-                        obj.Add(key, jobj);
-                    }
-                    else
-                    {  // 已有对象 => 智能转换多值对应为[]
-                        _isArray = true;
-                        var arr = obj[key] as JArray;
-                        if (arr != null)
-                        { // 已经是jarray
-                            arr.Add(jobj);
-                        }
-                        else
-                        {    // 创建Jarray
-                            obj[key] = new JArray() { obj[key], jobj };
-                        }
-                    }
-                }
-            });
-
-            if (_isArray)
-            {
-                foreach (var o in obj.Properties())
-                {
-                    if (null == (o.Value as JArray))
-                    {
-                        obj[o.Name] = new JArray() { o.Value };
-                    }
-                }
-            }
-            isArray = _isArray;
-            return obj;
-        }
-
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个{key11:{key1_21:{},key1_22:{},...},key12:{key2_21:{},key2_22:{},...},...}结构数据中
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="indexFieldName">用做索引的字段名</param>
-        /// <param name="secondaryIndexName">用做次级索引的字段名</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <returns>拥有二级索引的json对象,二级节点是{}</returns>
-        public JObject ReadTabelToJObjectWithSecondaryIndex(string tableName,
-            string indexFieldName, string secondaryIndexName, out bool isArray, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, indexFieldName),
-            Format("在表[{0}]中未找到字段:[{1}]", tableName, indexFieldName));
-            Assert(HasFiledInTable(tableName, secondaryIndexName),
-                Format("在表[{0}]中未找到字段:[{1}]", tableName, secondaryIndexName));
-            var _isArray = false;
-            var ex = new List<string>(excludeFields);
-            //ex.Add(indexFieldName);
-            //ex.Add(secondaryIndexName);
-            var obj = new JObject();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var jobj = new JObject();
-                    var id = "";
-                    var secondId = "";
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == indexFieldName)
-                        {
-                            id = rdr.GetValue(i).ToString();
-                        }
-                        if (rdr.GetName(i) == secondaryIndexName)
-                        {
-                            secondId = rdr.GetValue(i).ToString();
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            Object v = rdr.GetValue(i);
-                            if (DBNull.Value == v)
-                            {
-                                var t = rdr.GetFieldType(i).Name;
-                                switch (t)
-                                {
-                                    case "Int32":
-                                        v = 0;
-                                        break;
-                                    case "String":
-                                        v = "";
-                                        break;
-                                    case "Single":
-                                        v = 0;
-                                        break;
-                                }
-                            }
-                            jobj.Add(rdr.GetName(i), JToken.FromObject(v));
-                        }
-                    }
-
-                    if (obj[id] == null)
-                    {  // 没有建立一级对象
-                        var o = new JObject();
-                        o.Add(secondId, jobj);
-                        obj.Add(id, o);
-                    }
-                    else
-                    {  // 已有一级对象
-                        var o = obj[id] as JObject;  // 一级对象
-                        if (o[secondId] == null)
-                        {  // 添加新值
-                            o.Add(secondId, jobj);
-                        }
-                        else
-                        {    // 已有对象 => 智能转换多值对应为[]
-                            _isArray = true;
-                            var arr = o[secondId] as JArray;
-                            if (arr != null)
-                            { // 已经是jarray
-                                arr.Add(jobj);
-                            }
-                            else
-                            {    // 创建Jarray
-                                o[secondId] = new JArray() { o[secondId], jobj };
-                            }
-                        }
-                    }
-                }
-            });
-            if (_isArray)
-            {
-                foreach (var o in obj.Properties())
-                {
-                    foreach (var o2 in (o.Value as JObject).Properties())
-                    {
-                        if (!(obj[o.Name][o2.Name] is JArray))
-                        {
-                            obj[o.Name][o2.Name] = new JArray() { obj[o.Name][o2.Name] };
-                        }
-                    }
-                }
-            }
-            isArray = _isArray;
-            return obj;
-        }
-
-
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个行数组[{},{}]
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <returns>普通行数组[{},{},...]</returns>
-        public Dictionary<string, object>[] ReadTabelToArray(string tableName, params string[] excludeFields)
-        {
-            var ex = new List<string>(excludeFields);
-            var arr = new List<Dictionary<string, object>>();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var r = new Dictionary<string, object>(rdr.FieldCount - 1);
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            r.Add(rdr.GetName(i), rdr.GetValue(i));
-                        }
-                    }
-                    arr.Add(r);
-                }
-            });
-            return arr.ToArray();
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个dic中 {"key":{}}
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="indexFieldName">仅限索引字段(1对多的情况暂不支持)</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <typeparam name="T">string, number</typeparam>
-        /// <returns>嵌套的dictionary:{k:{k,v},k:{k:v},...}</returns>
-        public Dictionary<T, Dictionary<string, object>> ReadTabelToDic_Dic<T>(string tableName, string indexFieldName, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, indexFieldName),
-                Format("在表[{0}]中未找到字段:[{1}]", tableName, indexFieldName));
-            var ex = new List<string>(excludeFields);
-            //ex.Add(indexFieldName);
-            var dic = new Dictionary<T, Dictionary<string, object>>();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var r = new Dictionary<string, object>(rdr.FieldCount - 1);
-                    var t = default(T);
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == indexFieldName)
-                        {
-                            t = (T)rdr.GetValue(i);
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            r.Add(rdr.GetName(i), rdr.GetValue(i));
-                        }
-                    }
-                    dic.Add(t, r);
-                }
-
-            });
-            return dic;
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个dic中 {"key":[]}
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="indexFieldName">索引字段名</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <typeparam name="T">string, number</typeparam>
-        /// <returns>复杂嵌套dictionary:{k:[{},{},..],k:[{},{},..]..}</returns>
-        public Dictionary<T, List<Dictionary<string, object>>> ReadTabelToDic_List<T>(string tableName, string indexFieldName, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, indexFieldName),
-                Format("在表[{0}]中未找到字段:[{1}]", tableName, indexFieldName));
-            var ex = new List<string>(excludeFields);
-            //ex.Add(indexFieldName);
-            var dic = new Dictionary<T, List<Dictionary<string, object>>>();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var r = new Dictionary<string, object>(rdr.FieldCount - 1);
-                    var t = default(T);
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == indexFieldName)
-                        {
-                            t = (T)rdr.GetValue(i);
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            r.Add(rdr.GetName(i), rdr.GetValue(i));
-                        }
-                    }
-                    if (dic.ContainsKey(t))
-                    {
-                        dic[t].Add(r);
-                    }
-                    else
-                    {
-                        dic.Add(t, new List<Dictionary<string, object>> { r });
-                    }
-                }
-            });
-            return dic;
-        }
-
-        #endregion
-
-        #region `   数据写   `
-
-        /// <summary>
-        /// 执行非查询类的SQL语句,比如插入/更新/删除之类的.
-        /// </summary>
-        /// <param name="sql"></param>
-        /// <returns></returns>
-        public int ExecuteSqlNonQuery(string sql) {
-            using var cmd = new MySqlCommand(sql, conn);
-            return cmd.ExecuteNonQuery();
-        }
-
-
-
-        #endregion
-
-        #region '    辅助方法    '
-
-        /// <summary>
-        /// 查询某表中是否存在指定字段
-        /// </summary>
-        /// <param name="tableName"></param>
-        /// <param name="fieldName"></param>
-        /// <returns></returns>
-        public bool HasFiledInTable(string tableName, string fieldName)
-        {
-            Trace.Assert(TableExist(tableName), tableName + " 未找到");
-            return GetTableFieldsInfo(tableName).ContainsKey(fieldName);
-        }
-
-        /// <summary>
-        /// 检查指定的表格是否存在
-        /// </summary>
-        /// <param name="tableName"></param>
-        /// <returns></returns>
-        public bool TableExist(string tableName)
-        {
-            try
-            {
-                new MySqlCommand("select * from " + tableName + " limit 1;", conn).ExecuteNonQuery();
-            }
-            catch (MySqlException ex)
-            {
-                switch (ex.Number)
-                {
-                    case 1146:
-                        return false;
-                    default:
-                        Debug.WriteLine(ex.Message);
-                        return false;
-                }
-            }
-            return true;
-        }
-
-        /// <summary>
-        /// 执行sql
-        /// </summary>
-        /// <param name="sql"></param>
-        public void Query(string sql)
-        {
-            try
-            {
-                using (var cmd = new MySqlCommand(sql, conn))
-                {
-                    cmd.ExecuteNonQuery();
-                }
-            }
-            catch (MySqlException ex)
-            {
-                Debug.WriteLine(ex.Message);
-            }
-        }
-        /// <summary>
-        /// 执行sql 查询
-        /// </summary>
-        /// <param name="sqlcmd"></param>
-        /// <param name="working"></param>
-        public void QueryTable(string sqlcmd, Action<MySqlDataReader> working)
-        {
-            try
-            {
-                using (var cmd = new MySqlCommand(sqlcmd, conn))
-                using (MySqlDataReader rdr = cmd.ExecuteReader())
-                {
-
-                    if (null != working)
-                    {
-                        working.Invoke(rdr);
-                    }
-                }
-            }
-            catch (MySqlException ex)
-            {
-                Debug.WriteLine(ex.Message);
-            }
-        }
-
-        /// <summary>
-        /// 查询表格的字段信息  FieldName :
-        ///     <Type(字段类型 in .net)>
-        ///     <Collation(字符集及排序)>
-        ///     <Null(是否可空)>
-        ///     <Key(索引类型)>
-        ///     <Default(默认值)>
-        ///     <Extra(自增)>
-        ///     <Privileges(权限)>
-        ///     <Comment(注释)>
-        /// </summary>
-        /// <param name="tableName"></param>
-        /// <returns></returns>
-        public Dictionary<string, Dictionary<string, object>> GetTableFieldsInfo(string tableName)
-        {
-            var ex = new List<string>();
-            var dic = new Dictionary<string, Dictionary<string, object>>();
-            QueryTable(string.Format("show full fields from {0}", tableName), rdr =>
-            {
-                while (rdr.Read())
-                {
-
-                    var r = new Dictionary<string, object>();
-                    var fieldName = rdr.GetString(0);
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == "Field")
-                        {
-                            fieldName = rdr.GetString(i);
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            r.Add(rdr.GetName(i), rdr.GetValue(i));
-                        }
-
-                    }
-                    dic.Add(fieldName, r);
-                }
-            });
-            ReadTabel(tableName, rdr =>               // 用。net类型替换掉myslq 类型字符串
-            {
-                for (var i = 0; i < rdr.FieldCount; i++)
-                {
-
-                    var filedName = rdr.GetName(i);               // 字段名
-                    var filedType = rdr.GetFieldType(i).Name;     // 字段类型
-                    if (dic.ContainsKey(filedName))
-                    {
-                        dic[filedName][nameof(EFieldInfo.Type)] = filedType;
-                    }
-                }
-            });
-            return dic;
-        }
-
-        /// <summary>
-        /// 查询表格的最后修改时间
-        /// </summary>
-        /// <param name="tableName"></param>
-        /// <returns>最后修改时间或者创建时间, 异常: 返回当前时间</returns>
-        public DateTime TableLastModified(string tableName)
-        {
-            var sql = string.Format("SELECT UPDATE_TIME, CREATE_TIME " +
-                      "FROM information_schema.tables " +
-                      "where TABLE_SCHEMA='{0}' and TABLE_NAME='{1}'",
-                          this.conn.Database, tableName);
-            using (var cmd = new MySqlCommand(sql, conn))
-            using (MySqlDataReader rdr = cmd.ExecuteReader())
-            {
-                if (rdr.Read())
-                {  // 上次更新时间为null的情况下使用表的创建时间,都找不到值的情况下返回当前时间   
-                    return rdr.IsDBNull(0) ? (rdr.IsDBNull(1) ? DateTime.Now : rdr.GetDateTime(1)) : rdr.GetDateTime(0);
-                }
-            }
-            throw new Exception("没有找到对应的表");
-        }
-        #endregion
-
-
-
-    }
-}

+ 0 - 31
CSserver/MultiDup/db/Redis.cs

@@ -1,31 +0,0 @@
-using StackExchange.Redis;
-
-namespace MultiDup
-{
-  public  class Redis
-    {
-        private static ConnectionMultiplexer redis;
-
-        static public ConnectionMultiplexer Ins
-        {
-            get
-            {
-                if (null == redis)
-                {
-                    redis = ConnectionMultiplexer.Connect(Config.Ins.redis);
-                }
-                return redis;
-            }
-        }
-        /// <summary>
-        /// 获取操作redis数据库的接口对象
-        /// </summary>
-        /// <param name="id">指定db的编号</param>
-        /// <returns></returns>
-        public static IDatabase Rdb(int id = 0)
-        {
-            return Ins.GetDatabase(id);
-        }
-
-    }
-}

+ 2 - 12
CSserver/MultiDup/server/Lobby.cs

@@ -41,7 +41,7 @@ namespace MultiDup
         {
             this.callbacks.Add(eProtocalCommand.CsMdEnterLobby, On_EnterLobby);
             this.callbacks.Add(eProtocalCommand.CsLeaveRoom, On_Leave);
-            callbacks.Add(eProtocalCommand.CsMdGetRoomList,)
+            callbacks.Add(eProtocalCommand.CsMdGetRoomList, On_GetRoomList);
             callbacks.Add(eProtocalCommand.CsMdCreateRoom, On_CreateRoom);
             callbacks.Add(eProtocalCommand.CsMdEnterRoom, On_EnterRoom);
             var t = Task.Run(MsgLoop);
@@ -87,16 +87,6 @@ namespace MultiDup
                 peer.Properties.Add(PropertyName.Uid, msg.Uid);
                 peer.Properties.Add(PropertyName.Zoneid, msg.Zoneid);
             }
-            //var msg = new SC_MD_GetRoomList() { };
-            //this.roomDic.Values.ToList().ForEach(r =>
-            //{
-            //    var info = new SC_MD_GetRoomList.Types.RoomInfo() { Battleserver = "", Mapid = r.mapId, RoomId = r.Id };
-            //    info.PlayerUids.Add(peer.UID);
-            //    msg.RoomInfos.Add(info);
-            //});
-
-            //peer.SendEvent(eProtocalCommand.ScMdGetRoomList, msg);
-
         }
 
         /// <summary>
@@ -111,7 +101,7 @@ namespace MultiDup
             {
                 this.roomDic.Values.ToList().ForEach(r =>
                 {
-                    var info = new SC_MD_GetRoomList.Types.RoomInfo() { Battleserver = "", Mapid = r.mapId, RoomId = r.Id };
+                    var info = new SC_MD_GetRoomList.Types.RoomInfo() { Battleserver =r.BattleServerIp, BattleServerPort=r.BattleServerPort, Mapid = r.mapId, RoomId = r.Id };
                     r.ClientPeers.Values.ToList().ForEach(peer =>
                     {
                         info.PlayerUids.Add(peer.UID);

+ 11 - 4
CSserver/MultiDup/server/Room.cs

@@ -85,14 +85,22 @@ namespace MultiDup
 
         public int mapId { get; }
 
+        /// <summary>
+        /// 战斗服务器端口
+        /// </summary>
+        public int BattleServerPort = 6006;
+        /// <summary>
+        /// 战斗服务器IP地址
+        /// </summary>
+        public string BattleServerIp = "192.168.10.17";
+
         /// <summary>
         /// 构造函数
         /// </summary> 
         public Room(int mapid)
         {
             mapId= mapid;
-            Id = _roomIdCounter++;
-            //this.Name = DateTime.Now.ToString("yyyyMMddHH");
+            Id = _roomIdCounter++; 
 
             callbacks.Add(eProtocalCommand.CsMdBeginDup, On_Start);
 
@@ -110,8 +118,7 @@ namespace MultiDup
         {
             if (this.ClientPeers.TryGetValue(peerId, out var peer))
             {
-                Broadcast(TargetType.All, eProtocalCommand.ScMdBeginDup, new SC_MD_BeginDup() { });
-
+                Broadcast(TargetType.All, eProtocalCommand.ScMdBeginDup, new SC_MD_BeginDup() { }); 
             }
         }
 

+ 7 - 0
CSserver/PBReferens/pb/MsgTypeEnum.proto

@@ -72,4 +72,11 @@ enum eProtocalCommand {
   // 多人副本, 开始游戏(创建者)
   SC_MD_BeginDup = 125;
 
+
+  //////////////   S - S    //////////////////
+  //创建战斗房间
+  SS_CreateBattleRoom =301;
+  // 创建房间OK
+  SS_CreateBattleRoomOk =302;
+
 }

+ 12 - 1
CSserver/PBReferens/pb/MultiDup.proto

@@ -62,7 +62,8 @@ package MultiDup;
 		int32 RoomId=1;
 		int32 Mapid=2;
 		repeated string  PlayerUids=3;  //??
-		string battleserver =4;
+		string Battleserver =4;
+		int32 BattleServerPort =5;
 	}	 
 	repeated RoomInfo RoomInfos=1;
 
@@ -85,4 +86,14 @@ package MultiDup;
   // 多人副本, 开始游戏(创建者)
  message SC_MD_BeginDup {
       
+ }
+
+ // 多人副本在战斗服创建房间
+ message SS_CreateBattleServer{
+	int32 RoomId=1;
+	repeated string PlayerUids=2;
+ }
+ // 多人副本,创建战斗房间OK
+ message SS_CreateBattleServerOK{
+	
  }

+ 12 - 2
CSserver/PBReferens/pbcs/MsgTypeEnum.cs

@@ -20,7 +20,7 @@ public static partial class MsgTypeEnumReflection {
   static MsgTypeEnumReflection() {
     byte[] descriptorData = global::System.Convert.FromBase64String(
         string.Concat(
-          "ChRwYi9Nc2dUeXBlRW51bS5wcm90byrrAwoQZVByb3RvY2FsQ29tbWFuZBII",
+          "ChRwYi9Nc2dUeXBlRW51bS5wcm90byqhBAoQZVByb3RvY2FsQ29tbWFuZBII",
           "CgRub29wEAASDAoIQ1NfTG9naW4QARITCg9DU19SZXBvcnREYW1hZ2UQAhIQ",
           "CgxDU19MZWF2ZVJvb20QAxITCg9DU19SZXBvcnRVc2VySHAQBBIQCgxDU19D",
           "aGF0TG9naW4QChISCg5DU19DaGF0U2VuZE1zZxALEhQKEENTX01EX0VudGVy",
@@ -31,7 +31,8 @@ public static partial class MsgTypeEnumReflection {
           "dExvZ2luEG4SEQoNU0NfQ2hhdE5ld01zZxBvEhQKEFNDX01EX0VudGVyTG9i",
           "YnkQeBIUChBTQ19NRF9DcmVhdGVSb29tEHkSFQoRU0NfTURfR2V0Um9vbUxp",
           "c3QQehITCg9TQ19NRF9FbnRlclJvb20QexITCg9TQ19NRF9MZWF2ZVJvb20Q",
-          "fBISCg5TQ19NRF9CZWdpbkR1cBB9YgZwcm90bzM="));
+          "fBISCg5TQ19NRF9CZWdpbkR1cBB9EhgKE1NTX0NyZWF0ZUJhdHRsZVJvb20Q",
+          "rQISGgoVU1NfQ3JlYXRlQmF0dGxlUm9vbU9rEK4CYgZwcm90bzM="));
     descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
         new pbr::FileDescriptor[] { },
         new pbr::GeneratedClrTypeInfo(new[] {typeof(global::eProtocalCommand), }, null));
@@ -138,6 +139,15 @@ public enum eProtocalCommand {
   /// 多人副本, 开始游戏(创建者)
   /// </summary>
   [pbr::OriginalName("SC_MD_BeginDup")] ScMdBeginDup = 125,
+  /// <summary>
+  ///////////////   S - S    //////////////////
+  ///创建战斗房间
+  /// </summary>
+  [pbr::OriginalName("SS_CreateBattleRoom")] SsCreateBattleRoom = 301,
+  /// <summary>
+  /// 创建房间OK
+  /// </summary>
+  [pbr::OriginalName("SS_CreateBattleRoomOk")] SsCreateBattleRoomOk = 302,
 }
 
 #endregion

+ 275 - 10
CSserver/PBReferens/pbcs/MultiDup.cs

@@ -32,14 +32,17 @@ namespace MultiDup {
             "ZWdpbkR1cBIOCgZab25laWQYASABKAUSCwoDVWlkGAIgASgJIhIKEFNDX01E",
             "X0VudGVyTG9iYnkiTgoQU0NfTURfQ3JlYXRlUm9vbRIOCgZab25laWQYASAB",
             "KAUSCwoDVWlkGAIgASgJEg0KBU1hcGlkGAMgASgFEg4KBlJvb21JZBgEIAEo",
-            "BSKhAQoRU0NfTURfR2V0Um9vbUxpc3QSNwoJUm9vbUluZm9zGAEgAygLMiQu",
-            "TXVsdGlEdXAuU0NfTURfR2V0Um9vbUxpc3QuUm9vbUluZm8aUwoIUm9vbUlu",
+            "BSK7AQoRU0NfTURfR2V0Um9vbUxpc3QSNwoJUm9vbUluZm9zGAEgAygLMiQu",
+            "TXVsdGlEdXAuU0NfTURfR2V0Um9vbUxpc3QuUm9vbUluZm8abQoIUm9vbUlu",
             "Zm8SDgoGUm9vbUlkGAEgASgFEg0KBU1hcGlkGAIgASgFEhIKClBsYXllclVp",
-            "ZHMYAyADKAkSFAoMYmF0dGxlc2VydmVyGAQgASgJImsKD1NDX01EX0VudGVy",
-            "Um9vbRIOCgZab25laWQYASABKAUSCwoDVWlkGAIgASgJEg0KBU1hcGlkGAMg",
-            "ASgFEgoKAklwGAQgASgJEgwKBFBvcnQYBSABKAUSEgoKUGxheWVyVWlkcxgG",
-            "IAMoCSIuCg9TQ19NRF9MZWF2ZVJvb20SDgoGWm9uZWlkGAEgASgFEgsKA1Vp",
-            "ZBgCIAEoCSIQCg5TQ19NRF9CZWdpbkR1cGIGcHJvdG8z"));
+            "ZHMYAyADKAkSFAoMQmF0dGxlc2VydmVyGAQgASgJEhgKEEJhdHRsZVNlcnZl",
+            "clBvcnQYBSABKAUiawoPU0NfTURfRW50ZXJSb29tEg4KBlpvbmVpZBgBIAEo",
+            "BRILCgNVaWQYAiABKAkSDQoFTWFwaWQYAyABKAUSCgoCSXAYBCABKAkSDAoE",
+            "UG9ydBgFIAEoBRISCgpQbGF5ZXJVaWRzGAYgAygJIi4KD1NDX01EX0xlYXZl",
+            "Um9vbRIOCgZab25laWQYASABKAUSCwoDVWlkGAIgASgJIhAKDlNDX01EX0Jl",
+            "Z2luRHVwIjsKFVNTX0NyZWF0ZUJhdHRsZVNlcnZlchIOCgZSb29tSWQYASAB",
+            "KAUSEgoKUGxheWVyVWlkcxgCIAMoCSIZChdTU19DcmVhdGVCYXR0bGVTZXJ2",
+            "ZXJPS2IGcHJvdG8z"));
       descriptor = pbr::FileDescriptor.FromGeneratedCode(descriptorData,
           new pbr::FileDescriptor[] { },
           new pbr::GeneratedClrTypeInfo(null, new pbr::GeneratedClrTypeInfo[] {
@@ -51,10 +54,12 @@ namespace MultiDup {
             new pbr::GeneratedClrTypeInfo(typeof(global::MultiDup.CS_MD_BeginDup), global::MultiDup.CS_MD_BeginDup.Parser, new[]{ "Zoneid", "Uid" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::MultiDup.SC_MD_EnterLobby), global::MultiDup.SC_MD_EnterLobby.Parser, null, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::MultiDup.SC_MD_CreateRoom), global::MultiDup.SC_MD_CreateRoom.Parser, new[]{ "Zoneid", "Uid", "Mapid", "RoomId" }, null, null, null),
-            new pbr::GeneratedClrTypeInfo(typeof(global::MultiDup.SC_MD_GetRoomList), global::MultiDup.SC_MD_GetRoomList.Parser, new[]{ "RoomInfos" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::MultiDup.SC_MD_GetRoomList.Types.RoomInfo), global::MultiDup.SC_MD_GetRoomList.Types.RoomInfo.Parser, new[]{ "RoomId", "Mapid", "PlayerUids", "Battleserver" }, null, null, null)}),
+            new pbr::GeneratedClrTypeInfo(typeof(global::MultiDup.SC_MD_GetRoomList), global::MultiDup.SC_MD_GetRoomList.Parser, new[]{ "RoomInfos" }, null, null, new pbr::GeneratedClrTypeInfo[] { new pbr::GeneratedClrTypeInfo(typeof(global::MultiDup.SC_MD_GetRoomList.Types.RoomInfo), global::MultiDup.SC_MD_GetRoomList.Types.RoomInfo.Parser, new[]{ "RoomId", "Mapid", "PlayerUids", "Battleserver", "BattleServerPort" }, null, null, null)}),
             new pbr::GeneratedClrTypeInfo(typeof(global::MultiDup.SC_MD_EnterRoom), global::MultiDup.SC_MD_EnterRoom.Parser, new[]{ "Zoneid", "Uid", "Mapid", "Ip", "Port", "PlayerUids" }, null, null, null),
             new pbr::GeneratedClrTypeInfo(typeof(global::MultiDup.SC_MD_LeaveRoom), global::MultiDup.SC_MD_LeaveRoom.Parser, new[]{ "Zoneid", "Uid" }, null, null, null),
-            new pbr::GeneratedClrTypeInfo(typeof(global::MultiDup.SC_MD_BeginDup), global::MultiDup.SC_MD_BeginDup.Parser, null, null, null, null)
+            new pbr::GeneratedClrTypeInfo(typeof(global::MultiDup.SC_MD_BeginDup), global::MultiDup.SC_MD_BeginDup.Parser, null, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::MultiDup.SS_CreateBattleServer), global::MultiDup.SS_CreateBattleServer.Parser, new[]{ "RoomId", "PlayerUids" }, null, null, null),
+            new pbr::GeneratedClrTypeInfo(typeof(global::MultiDup.SS_CreateBattleServerOK), global::MultiDup.SS_CreateBattleServerOK.Parser, null, null, null, null)
           }));
     }
     #endregion
@@ -1466,6 +1471,7 @@ namespace MultiDup {
           mapid_ = other.mapid_;
           playerUids_ = other.playerUids_.Clone();
           battleserver_ = other.battleserver_;
+          battleServerPort_ = other.battleServerPort_;
         }
 
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -1508,7 +1514,7 @@ namespace MultiDup {
           get { return playerUids_; }
         }
 
-        /// <summary>Field number for the "battleserver" field.</summary>
+        /// <summary>Field number for the "Battleserver" field.</summary>
         public const int BattleserverFieldNumber = 4;
         private string battleserver_ = "";
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -1519,6 +1525,17 @@ namespace MultiDup {
           }
         }
 
+        /// <summary>Field number for the "BattleServerPort" field.</summary>
+        public const int BattleServerPortFieldNumber = 5;
+        private int battleServerPort_;
+        [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+        public int BattleServerPort {
+          get { return battleServerPort_; }
+          set {
+            battleServerPort_ = value;
+          }
+        }
+
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
         public override bool Equals(object other) {
           return Equals(other as RoomInfo);
@@ -1536,6 +1553,7 @@ namespace MultiDup {
           if (Mapid != other.Mapid) return false;
           if(!playerUids_.Equals(other.playerUids_)) return false;
           if (Battleserver != other.Battleserver) return false;
+          if (BattleServerPort != other.BattleServerPort) return false;
           return true;
         }
 
@@ -1546,6 +1564,7 @@ namespace MultiDup {
           if (Mapid != 0) hash ^= Mapid.GetHashCode();
           hash ^= playerUids_.GetHashCode();
           if (Battleserver.Length != 0) hash ^= Battleserver.GetHashCode();
+          if (BattleServerPort != 0) hash ^= BattleServerPort.GetHashCode();
           return hash;
         }
 
@@ -1569,6 +1588,10 @@ namespace MultiDup {
             output.WriteRawTag(34);
             output.WriteString(Battleserver);
           }
+          if (BattleServerPort != 0) {
+            output.WriteRawTag(40);
+            output.WriteInt32(BattleServerPort);
+          }
         }
 
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -1584,6 +1607,9 @@ namespace MultiDup {
           if (Battleserver.Length != 0) {
             size += 1 + pb::CodedOutputStream.ComputeStringSize(Battleserver);
           }
+          if (BattleServerPort != 0) {
+            size += 1 + pb::CodedOutputStream.ComputeInt32Size(BattleServerPort);
+          }
           return size;
         }
 
@@ -1602,6 +1628,9 @@ namespace MultiDup {
           if (other.Battleserver.Length != 0) {
             Battleserver = other.Battleserver;
           }
+          if (other.BattleServerPort != 0) {
+            BattleServerPort = other.BattleServerPort;
+          }
         }
 
         [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
@@ -1628,6 +1657,10 @@ namespace MultiDup {
                 Battleserver = input.ReadString();
                 break;
               }
+              case 40: {
+                BattleServerPort = input.ReadInt32();
+                break;
+              }
             }
           }
         }
@@ -2143,6 +2176,238 @@ namespace MultiDup {
 
   }
 
+  /// <summary>
+  /// 多人副本在战斗服创建房间
+  /// </summary>
+  public sealed partial class SS_CreateBattleServer : pb::IMessage<SS_CreateBattleServer> {
+    private static readonly pb::MessageParser<SS_CreateBattleServer> _parser = new pb::MessageParser<SS_CreateBattleServer>(() => new SS_CreateBattleServer());
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pb::MessageParser<SS_CreateBattleServer> Parser { get { return _parser; } }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::MultiDup.MultiDupReflection.Descriptor.MessageTypes[12]; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public SS_CreateBattleServer() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public SS_CreateBattleServer(SS_CreateBattleServer other) : this() {
+      roomId_ = other.roomId_;
+      playerUids_ = other.playerUids_.Clone();
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public SS_CreateBattleServer Clone() {
+      return new SS_CreateBattleServer(this);
+    }
+
+    /// <summary>Field number for the "RoomId" field.</summary>
+    public const int RoomIdFieldNumber = 1;
+    private int roomId_;
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int RoomId {
+      get { return roomId_; }
+      set {
+        roomId_ = value;
+      }
+    }
+
+    /// <summary>Field number for the "PlayerUids" field.</summary>
+    public const int PlayerUidsFieldNumber = 2;
+    private static readonly pb::FieldCodec<string> _repeated_playerUids_codec
+        = pb::FieldCodec.ForString(18);
+    private readonly pbc::RepeatedField<string> playerUids_ = new pbc::RepeatedField<string>();
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public pbc::RepeatedField<string> PlayerUids {
+      get { return playerUids_; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override bool Equals(object other) {
+      return Equals(other as SS_CreateBattleServer);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool Equals(SS_CreateBattleServer other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      if (RoomId != other.RoomId) return false;
+      if(!playerUids_.Equals(other.playerUids_)) return false;
+      return true;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override int GetHashCode() {
+      int hash = 1;
+      if (RoomId != 0) hash ^= RoomId.GetHashCode();
+      hash ^= playerUids_.GetHashCode();
+      return hash;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void WriteTo(pb::CodedOutputStream output) {
+      if (RoomId != 0) {
+        output.WriteRawTag(8);
+        output.WriteInt32(RoomId);
+      }
+      playerUids_.WriteTo(output, _repeated_playerUids_codec);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int CalculateSize() {
+      int size = 0;
+      if (RoomId != 0) {
+        size += 1 + pb::CodedOutputStream.ComputeInt32Size(RoomId);
+      }
+      size += playerUids_.CalculateSize(_repeated_playerUids_codec);
+      return size;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(SS_CreateBattleServer other) {
+      if (other == null) {
+        return;
+      }
+      if (other.RoomId != 0) {
+        RoomId = other.RoomId;
+      }
+      playerUids_.Add(other.playerUids_);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+          case 8: {
+            RoomId = input.ReadInt32();
+            break;
+          }
+          case 18: {
+            playerUids_.AddEntriesFrom(input, _repeated_playerUids_codec);
+            break;
+          }
+        }
+      }
+    }
+
+  }
+
+  /// <summary>
+  /// 多人副本,创建战斗房间OK
+  /// </summary>
+  public sealed partial class SS_CreateBattleServerOK : pb::IMessage<SS_CreateBattleServerOK> {
+    private static readonly pb::MessageParser<SS_CreateBattleServerOK> _parser = new pb::MessageParser<SS_CreateBattleServerOK>(() => new SS_CreateBattleServerOK());
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pb::MessageParser<SS_CreateBattleServerOK> Parser { get { return _parser; } }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public static pbr::MessageDescriptor Descriptor {
+      get { return global::MultiDup.MultiDupReflection.Descriptor.MessageTypes[13]; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    pbr::MessageDescriptor pb::IMessage.Descriptor {
+      get { return Descriptor; }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public SS_CreateBattleServerOK() {
+      OnConstruction();
+    }
+
+    partial void OnConstruction();
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public SS_CreateBattleServerOK(SS_CreateBattleServerOK other) : this() {
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public SS_CreateBattleServerOK Clone() {
+      return new SS_CreateBattleServerOK(this);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override bool Equals(object other) {
+      return Equals(other as SS_CreateBattleServerOK);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public bool Equals(SS_CreateBattleServerOK other) {
+      if (ReferenceEquals(other, null)) {
+        return false;
+      }
+      if (ReferenceEquals(other, this)) {
+        return true;
+      }
+      return true;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override int GetHashCode() {
+      int hash = 1;
+      return hash;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public override string ToString() {
+      return pb::JsonFormatter.ToDiagnosticString(this);
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void WriteTo(pb::CodedOutputStream output) {
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public int CalculateSize() {
+      int size = 0;
+      return size;
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(SS_CreateBattleServerOK other) {
+      if (other == null) {
+        return;
+      }
+    }
+
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute]
+    public void MergeFrom(pb::CodedInputStream input) {
+      uint tag;
+      while ((tag = input.ReadTag()) != 0) {
+        switch(tag) {
+          default:
+            input.SkipLastField();
+            break;
+        }
+      }
+    }
+
+  }
+
   #endregion
 
 }

+ 7 - 1
CSserver/csserver.sln

@@ -17,7 +17,9 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Libs", "Libs", "{02C64572-A
 EndProject
 Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DataTransfer", "DataTransfer\DataTransfer.csproj", "{201B65E5-35B6-4AF0-B4DF-8334484BC804}"
 EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MultiDup", "MultiDup\MultiDup.csproj", "{25F90738-ECAE-40CC-883F-86A75E6C253B}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MultiDup", "MultiDup\MultiDup.csproj", "{25F90738-ECAE-40CC-883F-86A75E6C253B}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "BattleRoom", "BattleRoom\BattleRoom.csproj", "{B5253393-934B-4481-B7E3-5B9F4715EC00}"
 EndProject
 Global
 	GlobalSection(SolutionConfigurationPlatforms) = preSolution
@@ -53,6 +55,10 @@ Global
 		{25F90738-ECAE-40CC-883F-86A75E6C253B}.Debug|Any CPU.Build.0 = Debug|Any CPU
 		{25F90738-ECAE-40CC-883F-86A75E6C253B}.Release|Any CPU.ActiveCfg = Release|Any CPU
 		{25F90738-ECAE-40CC-883F-86A75E6C253B}.Release|Any CPU.Build.0 = Release|Any CPU
+		{B5253393-934B-4481-B7E3-5B9F4715EC00}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{B5253393-934B-4481-B7E3-5B9F4715EC00}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{B5253393-934B-4481-B7E3-5B9F4715EC00}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{B5253393-934B-4481-B7E3-5B9F4715EC00}.Release|Any CPU.Build.0 = Release|Any CPU
 	EndGlobalSection
 	GlobalSection(SolutionProperties) = preSolution
 		HideSolutionNode = FALSE

+ 0 - 847
CSserver/csserver/db/MysqlUtil.cs

@@ -1,847 +0,0 @@
-using MySql.Data.MySqlClient;
-using Newtonsoft.Json.Linq;
-using System;
-using System.Collections.Generic;
-using System.Data;
-using System.Diagnostics;
-using static System.Diagnostics.Trace;
-using static System.String;
-
-namespace Chat
-{
-    /// <summary>
-    /// MySQL操作辅助类.
-    /// </summary>
-    public class MysqlUtil : IDisposable
-    {
-
-        /// <summary>
-        /// MySQL字段详细信息,(用于GetFiledInfo方法返回值中取信息,可以用nameof来去掉硬编码字符串以防止拼写错误)
-        /// </summary>
-        public enum EFieldInfo
-        {
-            /// <summary>
-            /// 字段类型 in .net
-            /// </summary>
-            Type,
-            /// <summary>
-            /// 是否可空
-            /// </summary>
-            Null,
-            /// <summary>
-            /// 索引类型
-            /// </summary>
-            Key,
-            /// <summary>
-            /// 默认值
-            /// </summary>
-            Default,
-            /// <summary>
-            /// 注释
-            /// </summary>
-            Comment,
-            /// <summary>
-            /// 字符集
-            /// </summary>
-            Collation,
-            /// <summary>
-            /// 额外(自增等)
-            /// </summary>
-            Extra,
-            /// <summary>
-            /// 权限
-            /// </summary>
-            Privileges
-        }
-
-        #region `    基础代码   `
-        static MysqlUtil mInst;
-        public static MysqlUtil Ins
-        {
-            get
-            {
-                if (null == mInst)
-                {
-                    mInst = new MysqlUtil();
-                }
-                return mInst;
-            }
-        }
-
-        private MysqlUtil()
-        {
-            conn = new MySqlConnection(Config.Ins.mysql.ConnectionString);
-            conn.Open();
-            Assert(conn.State == ConnectionState.Open, "连接到数据库失败");
-        }
-  
-        private MySqlConnection conn = null;
-        /// <summary>
-        /// 建立连接
-        /// </summary>
-        /// <param name="host"></param>
-        /// <param name="port"></param>
-        /// <param name="user"></param>
-        /// <param name="pwd"></param>
-        /// <param name="dbName"></param>
-        public void Connect(string host, string port, string user, string pwd, string dbName)
-        {
-            var connStr = string.Format(
-                              "server={0};port={1};user={2};password={3};database={4};Charset=utf8",
-                              host, port, user, pwd, dbName);
-            conn = new MySqlConnection(connStr);
-            conn.Open();
-            Assert(conn.State == ConnectionState.Open, "连接到数据库失败");
-        }
-        /// <summary>
-        /// 关闭连接
-        /// </summary>
-        public void Close()
-        {
-            conn.Close();
-        }
-        /// <summary>
-        /// 释放资源
-        /// </summary>
-        public void Dispose()
-        {
-            conn.Dispose();
-        }
-        #endregion
-
-        #region `    数据读    `
-
-        /// <summary>
-        /// 读取数据库表-数据操作部分逻辑需要参数中定义
-        /// 一般情况下,使用其余八个读取函数即可,如果需要自己定制数据结构,可以通过在此函数回调中自行遍历整个数据表.
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="working">action to MysqlDataReader</param>
-        public void ReadTabel(string tableName, Action<MySqlDataReader> working)
-        {
-            Assert(TableExist(tableName), "表 " + tableName + " 不存在!");
-            var sql = string.Format("SELECT * FROM {0};", tableName);
-            using (var cmd = new MySqlCommand(sql, conn))
-            using (var rdr = cmd.ExecuteReader())
-            {
-                if (null != working) working.Invoke(rdr);
-            }
-        }
-
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个JArray中, []
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// /// <param name="excludeFields">排除的字段名列表</param>
-        /// <returns>JArray</returns>
-        public JArray ReadTabelToJArray(string tableName, params string[] excludeFields)
-        {
-            var ex = new List<string>(excludeFields);
-            var arr = new JArray();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var jobj = new JObject();
-
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            jobj.Add(rdr.GetName(i), JToken.FromObject(rdr.GetValue(i)));
-                        }
-                    }
-                    arr.Add(jobj);
-                }
-            });
-            return arr;
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个JObject中, {}
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="indexFieldName">用做索引的字段名</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <returns>{}</returns>
-        public JObject ReadTabelToJObject(string tableName, string indexFieldName, out bool isArray, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, indexFieldName),
-                Format("在表[{0}]中未找到key:[{1}]", tableName, indexFieldName));
-            bool _isArray = false;
-            var ex = new List<string>(excludeFields);
-            //ex.Add(indexFieldName);
-            var obj = new JObject();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var jobj = new JObject();
-                    var id = "";
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == indexFieldName)
-                        {
-                            id = rdr.GetValue(i).ToString();
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            object v = rdr.GetValue(i);
-
-                            if (DBNull.Value == v)
-                            {
-                                var t = rdr.GetFieldType(i).Name;
-                                switch (t)
-                                {
-                                    case "Int32":
-                                        v = 0;
-                                        break;
-                                    case "String":
-                                        v = "";
-                                        break;
-                                    case "Single":
-                                        v = 0;
-                                        break;
-                                }
-                            }
-                            jobj.Add(rdr.GetName(i), JToken.FromObject(v));
-                        }
-                    }
-                    if (obj[id] == null)
-                    {  // 这段代码智能转换多值对应为[]
-                        obj.Add(id, jobj);
-                    }
-                    else
-                    {
-                        _isArray = true;
-                        var arr = obj[id] as JArray;
-                        if (null != arr)
-                        {
-                            arr.Add(jobj);
-                        }
-                        else
-                        {
-                            obj[id] = new JArray() { obj[id], jobj };
-                        }
-                    }
-                }
-
-            });
-            if (_isArray)
-            {
-                foreach (var o in obj.Properties())
-                {
-                    if (null == (o.Value as JArray))
-                    {
-                        obj[o.Name] = new JArray() { o.Value };
-                    }
-                }
-            }
-            isArray = _isArray;
-            return obj;
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个JObject中, {k->[],k->[],...}
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="indexFieldName">用做索引的字段名</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <returns>{}</returns>
-        public JObject ReadTabelToJObjectWithArrayValues(string tableName, string indexFieldName, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, indexFieldName),
-                Format("在表[{0}]中未找到key:[{1}]", tableName, indexFieldName));
-
-            var ex = new List<string>(excludeFields);
-            //ex.Add(indexFieldName);
-            var obj = new JObject();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var jobj = new JObject();
-                    var id = "";
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == indexFieldName)
-                        {
-                            id = rdr.GetValue(i).ToString();
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            object v = rdr.GetValue(i);
-
-                            if (DBNull.Value == v)
-                            {
-                                var t = rdr.GetFieldType(i).Name;
-                                switch (t)
-                                {
-                                    case "Int32":
-                                        v = 0;
-                                        break;
-                                    case "String":
-                                        v = "";
-                                        break;
-                                    case "Single":
-                                        v = 0;
-                                        break;
-                                }
-                            }
-                            jobj.Add(rdr.GetName(i), JToken.FromObject(v));
-                        }
-                    }
-
-                    var arr = obj[id] as JArray;
-                    if (null != arr)
-                    {
-                        arr.Add(jobj);
-                    }
-                    else
-                    {
-                        obj[id] = new JArray() { jobj };
-                    }
-
-                }
-
-            });
-
-            return obj;
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个简单的key=>value结构中. 即只取表中的两个字段
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="keyName">用作属性名称的字段</param>
-        /// <param name="valueName">用作值的字段</param>
-        /// <returns>{k:v,k:v,...}</returns>
-        public JObject ReadTabelToSimpleJObject(string tableName, string keyName, string valueName)
-        {
-            Assert(HasFiledInTable(tableName, keyName),
-                    Format("在表[{0}]中未找到key:[{1}]", tableName, keyName));
-            Assert(HasFiledInTable(tableName, valueName),
-                Format("在表[{0}]中未找到字段:[{1}]", tableName, valueName));
-            var jobj = new JObject();
-
-            ReadTabel(tableName, rdr =>
-           {
-               while (rdr.Read())
-               {
-                   var key = "";
-                   Object value = null;
-                   for (int i = 0; i < rdr.FieldCount; i++)
-                   {
-                       if (rdr.GetName(i) == keyName)
-                       {
-                           key = rdr.GetValue(i).ToString();
-                       }
-                       if (rdr.GetName(i) == valueName)
-                       {
-                           value = rdr.GetValue(i);
-                       }
-                   }
-                   jobj.Add(key, JToken.FromObject(value));
-               }
-           });
-
-            return jobj;
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个由两个字段内容拼接成的字符串作为索引的JObject中
-        /// </summary>
-        /// <param name="tableName">表名称</param>
-        /// <param name="firstFieldName">第一个字段</param>
-        /// <param name="secondFieldName">第二个字段</param>
-        /// <param name="excludeFields">排除的字段名...</param>
-        /// <returns> {field(1)-field(2):{},...} </returns>
-        public JObject ReadTabelToJObjectWithCombinedIndex(string tableName, string firstFieldName, string secondFieldName, out bool isArray, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, firstFieldName),
-                 Format("在表[{0}]中未找到字段:[{1}]", tableName, firstFieldName));
-            Assert(HasFiledInTable(tableName, secondFieldName),
-                Format("在表[{0}]中未找到字段:[{1}]", tableName, secondFieldName));
-            bool _isArray = false;
-            var ex = new List<string>(excludeFields);
-            //ex.Add(firstFieldName);
-            //ex.Add(secondFieldName);
-            var obj = new JObject();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var jobj = new JObject();
-                    var firstId = "";
-                    var secondId = "";
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == firstFieldName)
-                        {
-                            firstId = rdr.GetValue(i).ToString();
-                        }
-                        if (rdr.GetName(i) == secondFieldName)
-                        {
-                            secondId = rdr.GetValue(i).ToString();
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            Object v = rdr.GetValue(i);
-                            if (DBNull.Value == v)
-                            {
-                                var t = rdr.GetFieldType(i).Name;
-                                switch (t)
-                                {
-                                    case "Int32":
-                                        v = 0;
-                                        break;
-                                    case "String":
-                                        v = "";
-                                        break;
-                                    case "Single":
-                                        v = 0;
-                                        break;
-                                }
-                            }
-                            jobj.Add(rdr.GetName(i), JToken.FromObject(v));
-                        }
-                    }
-                    var key = firstId + "-" + secondId;
-                    if (obj[key] == null)
-                    {  // 防止重复
-                        obj.Add(key, jobj);
-                    }
-                    else
-                    {  // 已有对象 => 智能转换多值对应为[]
-                        _isArray = true;
-                        var arr = obj[key] as JArray;
-                        if (arr != null)
-                        { // 已经是jarray
-                            arr.Add(jobj);
-                        }
-                        else
-                        {    // 创建Jarray
-                            obj[key] = new JArray() { obj[key], jobj };
-                        }
-                    }
-                }
-            });
-
-            if (_isArray)
-            {
-                foreach (var o in obj.Properties())
-                {
-                    if (null == (o.Value as JArray))
-                    {
-                        obj[o.Name] = new JArray() { o.Value };
-                    }
-                }
-            }
-            isArray = _isArray;
-            return obj;
-        }
-
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个{key11:{key1_21:{},key1_22:{},...},key12:{key2_21:{},key2_22:{},...},...}结构数据中
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="indexFieldName">用做索引的字段名</param>
-        /// <param name="secondaryIndexName">用做次级索引的字段名</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <returns>拥有二级索引的json对象,二级节点是{}</returns>
-        public JObject ReadTabelToJObjectWithSecondaryIndex(string tableName,
-            string indexFieldName, string secondaryIndexName, out bool isArray, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, indexFieldName),
-            Format("在表[{0}]中未找到字段:[{1}]", tableName, indexFieldName));
-            Assert(HasFiledInTable(tableName, secondaryIndexName),
-                Format("在表[{0}]中未找到字段:[{1}]", tableName, secondaryIndexName));
-            var _isArray = false;
-            var ex = new List<string>(excludeFields);
-            //ex.Add(indexFieldName);
-            //ex.Add(secondaryIndexName);
-            var obj = new JObject();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var jobj = new JObject();
-                    var id = "";
-                    var secondId = "";
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == indexFieldName)
-                        {
-                            id = rdr.GetValue(i).ToString();
-                        }
-                        if (rdr.GetName(i) == secondaryIndexName)
-                        {
-                            secondId = rdr.GetValue(i).ToString();
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            Object v = rdr.GetValue(i);
-                            if (DBNull.Value == v)
-                            {
-                                var t = rdr.GetFieldType(i).Name;
-                                switch (t)
-                                {
-                                    case "Int32":
-                                        v = 0;
-                                        break;
-                                    case "String":
-                                        v = "";
-                                        break;
-                                    case "Single":
-                                        v = 0;
-                                        break;
-                                }
-                            }
-                            jobj.Add(rdr.GetName(i), JToken.FromObject(v));
-                        }
-                    }
-
-                    if (obj[id] == null)
-                    {  // 没有建立一级对象
-                        var o = new JObject();
-                        o.Add(secondId, jobj);
-                        obj.Add(id, o);
-                    }
-                    else
-                    {  // 已有一级对象
-                        var o = obj[id] as JObject;  // 一级对象
-                        if (o[secondId] == null)
-                        {  // 添加新值
-                            o.Add(secondId, jobj);
-                        }
-                        else
-                        {    // 已有对象 => 智能转换多值对应为[]
-                            _isArray = true;
-                            var arr = o[secondId] as JArray;
-                            if (arr != null)
-                            { // 已经是jarray
-                                arr.Add(jobj);
-                            }
-                            else
-                            {    // 创建Jarray
-                                o[secondId] = new JArray() { o[secondId], jobj };
-                            }
-                        }
-                    }
-                }
-            });
-            if (_isArray)
-            {
-                foreach (var o in obj.Properties())
-                {
-                    foreach (var o2 in (o.Value as JObject).Properties())
-                    {
-                        if (!(obj[o.Name][o2.Name] is JArray))
-                        {
-                            obj[o.Name][o2.Name] = new JArray() { obj[o.Name][o2.Name] };
-                        }
-                    }
-                }
-            }
-            isArray = _isArray;
-            return obj;
-        }
-
-
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个行数组[{},{}]
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <returns>普通行数组[{},{},...]</returns>
-        public Dictionary<string, object>[] ReadTabelToArray(string tableName, params string[] excludeFields)
-        {
-            var ex = new List<string>(excludeFields);
-            var arr = new List<Dictionary<string, object>>();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var r = new Dictionary<string, object>(rdr.FieldCount - 1);
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            r.Add(rdr.GetName(i), rdr.GetValue(i));
-                        }
-                    }
-                    arr.Add(r);
-                }
-            });
-            return arr.ToArray();
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个dic中 {"key":{}}
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="indexFieldName">仅限索引字段(1对多的情况暂不支持)</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <typeparam name="T">string, number</typeparam>
-        /// <returns>嵌套的dictionary:{k:{k,v},k:{k:v},...}</returns>
-        public Dictionary<T, Dictionary<string, object>> ReadTabelToDic_Dic<T>(string tableName, string indexFieldName, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, indexFieldName),
-                Format("在表[{0}]中未找到字段:[{1}]", tableName, indexFieldName));
-            var ex = new List<string>(excludeFields);
-            //ex.Add(indexFieldName);
-            var dic = new Dictionary<T, Dictionary<string, object>>();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var r = new Dictionary<string, object>(rdr.FieldCount - 1);
-                    var t = default(T);
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == indexFieldName)
-                        {
-                            t = (T)rdr.GetValue(i);
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            r.Add(rdr.GetName(i), rdr.GetValue(i));
-                        }
-                    }
-                    dic.Add(t, r);
-                }
-
-            });
-            return dic;
-        }
-
-        /// <summary>
-        /// 读取数据库表 -> 到一个dic中 {"key":[]}
-        /// </summary>
-        /// <param name="tableName">表名</param>
-        /// <param name="indexFieldName">索引字段名</param>
-        /// <param name="excludeFields">排除的字段名列表</param>
-        /// <typeparam name="T">string, number</typeparam>
-        /// <returns>复杂嵌套dictionary:{k:[{},{},..],k:[{},{},..]..}</returns>
-        public Dictionary<T, List<Dictionary<string, object>>> ReadTabelToDic_List<T>(string tableName, string indexFieldName, params string[] excludeFields)
-        {
-            Assert(HasFiledInTable(tableName, indexFieldName),
-                Format("在表[{0}]中未找到字段:[{1}]", tableName, indexFieldName));
-            var ex = new List<string>(excludeFields);
-            //ex.Add(indexFieldName);
-            var dic = new Dictionary<T, List<Dictionary<string, object>>>();
-            ReadTabel(tableName, rdr =>
-            {
-                while (rdr.Read())
-                {
-                    var r = new Dictionary<string, object>(rdr.FieldCount - 1);
-                    var t = default(T);
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == indexFieldName)
-                        {
-                            t = (T)rdr.GetValue(i);
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            r.Add(rdr.GetName(i), rdr.GetValue(i));
-                        }
-                    }
-                    if (dic.ContainsKey(t))
-                    {
-                        dic[t].Add(r);
-                    }
-                    else
-                    {
-                        dic.Add(t, new List<Dictionary<string, object>> { r });
-                    }
-                }
-            });
-            return dic;
-        }
-
-        #endregion
-
-        #region `   数据写   `
-
-        /// <summary>
-        /// 执行非查询类的SQL语句,比如插入/更新/删除之类的.
-        /// </summary>
-        /// <param name="sql"></param>
-        /// <returns></returns>
-        public int ExecuteSqlNonQuery(string sql) {
-            using var cmd = new MySqlCommand(sql, conn);
-            return cmd.ExecuteNonQuery();
-        }
-
-
-
-        #endregion
-
-        #region '    辅助方法    '
-
-        /// <summary>
-        /// 查询某表中是否存在指定字段
-        /// </summary>
-        /// <param name="tableName"></param>
-        /// <param name="fieldName"></param>
-        /// <returns></returns>
-        public bool HasFiledInTable(string tableName, string fieldName)
-        {
-            Trace.Assert(TableExist(tableName), tableName + " 未找到");
-            return GetTableFieldsInfo(tableName).ContainsKey(fieldName);
-        }
-
-        /// <summary>
-        /// 检查指定的表格是否存在
-        /// </summary>
-        /// <param name="tableName"></param>
-        /// <returns></returns>
-        public bool TableExist(string tableName)
-        {
-            try
-            {
-                new MySqlCommand("select * from " + tableName + " limit 1;", conn).ExecuteNonQuery();
-            }
-            catch (MySqlException ex)
-            {
-                switch (ex.Number)
-                {
-                    case 1146:
-                        return false;
-                    default:
-                        Debug.WriteLine(ex.Message);
-                        return false;
-                }
-            }
-            return true;
-        }
-
-        /// <summary>
-        /// 执行sql
-        /// </summary>
-        /// <param name="sql"></param>
-        public void Query(string sql)
-        {
-            try
-            {
-                using (var cmd = new MySqlCommand(sql, conn))
-                {
-                    cmd.ExecuteNonQuery();
-                }
-            }
-            catch (MySqlException ex)
-            {
-                Debug.WriteLine(ex.Message);
-            }
-        }
-        /// <summary>
-        /// 执行sql 查询
-        /// </summary>
-        /// <param name="sqlcmd"></param>
-        /// <param name="working"></param>
-        public void QueryTable(string sqlcmd, Action<MySqlDataReader> working)
-        {
-            try
-            {
-                using (var cmd = new MySqlCommand(sqlcmd, conn))
-                using (MySqlDataReader rdr = cmd.ExecuteReader())
-                {
-
-                    if (null != working)
-                    {
-                        working.Invoke(rdr);
-                    }
-                }
-            }
-            catch (MySqlException ex)
-            {
-                Debug.WriteLine(ex.Message);
-            }
-        }
-
-        /// <summary>
-        /// 查询表格的字段信息  FieldName :
-        ///     <Type(字段类型 in .net)>
-        ///     <Collation(字符集及排序)>
-        ///     <Null(是否可空)>
-        ///     <Key(索引类型)>
-        ///     <Default(默认值)>
-        ///     <Extra(自增)>
-        ///     <Privileges(权限)>
-        ///     <Comment(注释)>
-        /// </summary>
-        /// <param name="tableName"></param>
-        /// <returns></returns>
-        public Dictionary<string, Dictionary<string, object>> GetTableFieldsInfo(string tableName)
-        {
-            var ex = new List<string>();
-            var dic = new Dictionary<string, Dictionary<string, object>>();
-            QueryTable(string.Format("show full fields from {0}", tableName), rdr =>
-            {
-                while (rdr.Read())
-                {
-
-                    var r = new Dictionary<string, object>();
-                    var fieldName = rdr.GetString(0);
-                    for (int i = 0; i < rdr.FieldCount; i++)
-                    {
-                        if (rdr.GetName(i) == "Field")
-                        {
-                            fieldName = rdr.GetString(i);
-                        }
-                        if (!ex.Contains(rdr.GetName(i)))
-                        {
-                            r.Add(rdr.GetName(i), rdr.GetValue(i));
-                        }
-
-                    }
-                    dic.Add(fieldName, r);
-                }
-            });
-            ReadTabel(tableName, rdr =>               // 用。net类型替换掉myslq 类型字符串
-            {
-                for (var i = 0; i < rdr.FieldCount; i++)
-                {
-
-                    var filedName = rdr.GetName(i);               // 字段名
-                    var filedType = rdr.GetFieldType(i).Name;     // 字段类型
-                    if (dic.ContainsKey(filedName))
-                    {
-                        dic[filedName][nameof(EFieldInfo.Type)] = filedType;
-                    }
-                }
-            });
-            return dic;
-        }
-
-        /// <summary>
-        /// 查询表格的最后修改时间
-        /// </summary>
-        /// <param name="tableName"></param>
-        /// <returns>最后修改时间或者创建时间, 异常: 返回当前时间</returns>
-        public DateTime TableLastModified(string tableName)
-        {
-            var sql = string.Format("SELECT UPDATE_TIME, CREATE_TIME " +
-                      "FROM information_schema.tables " +
-                      "where TABLE_SCHEMA='{0}' and TABLE_NAME='{1}'",
-                          this.conn.Database, tableName);
-            using (var cmd = new MySqlCommand(sql, conn))
-            using (MySqlDataReader rdr = cmd.ExecuteReader())
-            {
-                if (rdr.Read())
-                {  // 上次更新时间为null的情况下使用表的创建时间,都找不到值的情况下返回当前时间   
-                    return rdr.IsDBNull(0) ? (rdr.IsDBNull(1) ? DateTime.Now : rdr.GetDateTime(1)) : rdr.GetDateTime(0);
-                }
-            }
-            throw new Exception("没有找到对应的表");
-        }
-        #endregion
-
-
-
-    }
-}

+ 0 - 31
CSserver/csserver/db/Redis.cs

@@ -1,31 +0,0 @@
-using StackExchange.Redis;
-
-namespace Chat
-{
-    class Redis
-    {
-        private static ConnectionMultiplexer redis;
-
-        static public ConnectionMultiplexer Ins
-        {
-            get
-            {
-                if (null == redis)
-                {
-                    redis = ConnectionMultiplexer.Connect(Config.Ins.redis);
-                }
-                return redis;
-            }
-        }
-        /// <summary>
-        /// 获取操作redis数据库的接口对象
-        /// </summary>
-        /// <param name="id">指定db的编号</param>
-        /// <returns></returns>
-        public static IDatabase Rdb(int id = 0)
-        {
-            return Ins.GetDatabase(id);
-        }
-
-    }
-}