v7.3.2018.0614   重构高性能资源池,减少GC压力,增加线程池,让异步任务得到平等竞争CPU的机会
大石头 编写于 2018-06-14 17:56:44
X
using System;
using System.Threading.Tasks;
using NewLife.Data;
using NewLife.Log;
using NewLife.Messaging;
using NewLife.Net;
using NewLife.Net.Handlers;
using NewLife.Reflection;

namespace NewLife.Remoting
{
    class ApiNetClient : DisposeBase, IApiClient, IServiceProvider
    {
        #region 属性
        /// <summary>是否已打开</summary>
        public Boolean Active { get; set; }

        public ISocketClient Client { get; set; }

        /// <summary>服务提供者</summary>
        public IServiceProvider Provider { get; set; }
        #endregion

        #region 构造
        /// <summary>销毁</summary>
        /// <param name="disposing"></param>
        protected override void OnDispose(Boolean disposing)
        {
            base.OnDispose(disposing);

            Close(GetType().Name + (disposing ? "Dispose" : "GC"));
        }
        #endregion

        #region 方法
        public virtual Boolean Init(Object config)
        {
            var uri = config is String ? new NetUri(config + "") : config as NetUri;
            if (uri == null) return false;

            var ct = Client = uri.CreateRemote();

            // 新生命标准网络封包协议
            ct.Add(new StandardCodec { UserPacket = false });

            // Udp客户端默认超时时间
            //if (ct is UdpServer) (ct as UdpServer).SessionTimeout = 10 * 60;

            // 网络非法断开时,自动恢复
            ct.OnDisposed += (s, e) => { if (Active) { Init(config); Open(); } };

            return true;
        }

        public Boolean Open()
        {
            var ct = Client;
            ct.Received += Client_Received;
            ct.Log = Log;
            ct.Opened += Client_Opened;

            return Active = ct.Open();
        }

        /// <summary>关闭</summary>
        /// <param name="reason">关闭原因。便于日志分析</param>
        public void Close(String reason)
        {
            Active = false;

            var tc = Client;
            tc.Received -= Client_Received;
            tc.Opened -= Client_Opened;
            tc.Close(reason);
        }

        /// <summary>打开后触发。</summary>
        public event EventHandler Opened;

        private void Client_Opened(Object sender, EventArgs e)
        {
            // 提前设置Active,避免外部时间进行特殊操作
            var ct = Client;
            if (ct.Active) Active = true;

            Opened?.Invoke(this, e);
        }
        #endregion

        #region 发送
        /// <summary>创建消息</summary>
        /// <param name="pk"></param>
        /// <returns></returns>
        public IMessage CreateMessage(Packet pk) => new DefaultMessage { Payload = pk };

        /// <summary>远程调用</summary>
        /// <param name="msg"></param>
        /// <returns></returns>
        public async Task<IMessage> SendAsync(IMessage msg) => await Client.SendAsync(msg) as IMessage;
        #endregion

        #region 异步接收
        private void Client_Received(Object sender, ReceivedEventArgs e)
        {
            var msg = e.Message as IMessage;
            if (msg == null || msg.Reply) return;

            if (Provider is ApiClient ac) ac.LastActive = DateTime.Now;

            //var host = this.GetService<IApiHost>();
            var host = Provider as IApiHost;

            var rs = host.Process(host as IApiSession, msg);
            if (rs != null) Client.SendAsync(rs);
        }
        #endregion

        #region 服务提供者
        /// <summary>获取服务提供者</summary>
        /// <param name="serviceType"></param>
        /// <returns></returns>
        public Object GetService(Type serviceType)
        {
            // 服务类是否当前类的基类
            if (GetType().As(serviceType)) return this;

            if (serviceType == typeof(IApiClient)) return this;
            if (serviceType == typeof(ISocketClient)) return Client;

            return Provider?.GetService(serviceType);
        }
        #endregion

        #region 日志
        /// <summary>日志</summary>
        public ILog Log { get; set; } = Logger.Null;
        #endregion
    }
}