ApiHttp支持参数
大石头 编写于 2018-12-12 10:14:43
X
using System;
using System.Threading.Tasks;
using NewLife.Collections;
using NewLife.Data;
using NewLife.Log;
using NewLife.Messaging;
using NewLife.Model;
using NewLife.Net;
using NewLife.Reflection;

namespace NewLife.Remoting
{
    /// <summary>Api主机</summary>
    public interface IApiHost
    {
        /// <summary>编码器</summary>
        IEncoder Encoder { get; set; }

        /// <summary>处理器</summary>
        IApiHandler Handler { get; set; }

        /// <summary>接口动作管理器</summary>
        IApiManager Manager { get; }

        /// <summary>获取消息编码器。重载以指定不同的封包协议</summary>
        /// <returns></returns>
        IHandler GetMessageCodec();

        /// <summary>处理消息</summary>
        /// <param name="session"></param>
        /// <param name="msg"></param>
        /// <returns></returns>
        IMessage Process(IApiSession session, IMessage msg);

        /// <summary>发送统计</summary>
        ICounter StatInvoke { get; set; }

        /// <summary>接收统计</summary>
        ICounter StatProcess { get; set; }

        /// <summary>日志</summary>
        ILog Log { get; set; }

        /// <summary>写日志</summary>
        /// <param name="format"></param>
        /// <param name="args"></param>
        void WriteLog(String format, params Object[] args);
    }

    /// <summary>Api主机助手</summary>
    public static class ApiHostHelper
    {
        /// <summary>调用</summary>
        /// <param name="host"></param>
        /// <param name="session"></param>
        /// <param name="resultType">结果类型</param>
        /// <param name="action">服务操作</param>
        /// <param name="args">参数</param>
        /// <param name="flag">标识</param>
        /// <returns></returns>
        public static async Task<Object> InvokeAsync(IApiHost host, Object session, Type resultType, String action, Object args, Byte flag)
        {
            if (session == null) return null;

            // 性能计数器,次数、TPS、平均耗时
            //host.StatSend?.Increment();
            var st = host.StatInvoke;
            var sw = st.StartCount();

            // 编码请求,构造消息
            var enc = host.Encoder;
            var msg = enc.CreateRequest(action, args);
            if (flag > 0 && msg is DefaultMessage dm) dm.Flag = flag;

            var invoker = session;
            IMessage rs = null;
            try
            {
                if (session is IApiSession ss)
                {
                    var rs2 = await ss.SendAsync(msg);
                    rs = rs2.Item1;
                    if (rs2.Item2 != null) invoker = rs2.Item2;
                }
                else if (session is ISocketRemote client)
                    rs = (await client.SendMessageAsync(msg)) as IMessage;
                else
                    throw new InvalidOperationException();
                //rs = await session.SendAsync(msg);
                if (rs == null) return null;
            }
            catch (AggregateException aggex)
            {
                var ex = aggex.GetTrue();
                if (ex is TaskCanceledException)
                {
                    throw new TimeoutException($"请求[{action}]超时!", ex);
                }
                throw aggex;
            }
            catch (TaskCanceledException ex)
            {
                throw new TimeoutException($"请求[{action}]超时!", ex);
            }
            finally
            {
                st.StopCount(sw);
            }

            // 特殊返回类型
            if (resultType == typeof(IMessage)) return rs;
            //if (resultType == typeof(Packet)) return rs.Payload;

            if (!enc.Decode(rs, out var act, out var code, out var data)) throw new InvalidOperationException();

            // 是否成功
            if (code != 0) throw new ApiException(code, $"远程[{invoker}]错误! {data.ToStr()}");

            if (data == null) return null;
            if (resultType == typeof(Packet)) return data;

            // 解码结果
            var result = enc.DecodeResult(action, data);
            if (resultType == typeof(Object)) return result;

            // 返回
            return enc.Convert(result, resultType);
        }

        /// <summary>调用</summary>
        /// <param name="host"></param>
        /// <param name="session"></param>
        /// <param name="action">服务操作</param>
        /// <param name="args">参数</param>
        /// <param name="flag">标识</param>
        /// <returns></returns>
        public static Boolean Invoke(IApiHost host, Object session, String action, Object args, Byte flag = 0)
        {
            if (session == null) return false;

            // 性能计数器,次数、TPS、平均耗时
            //host.StatSend?.Increment();
            var st = host.StatInvoke;

            // 编码请求
            var msg = host.Encoder.CreateRequest(action, args);

            if (msg is DefaultMessage dm)
            {
                dm.OneWay = true;
                if (flag > 0) dm.Flag = flag;
            }

            var sw = st.StartCount();
            try
            {
                if (session is IApiSession ss)
                    return ss.Send(msg);
                else if (session is ISocketRemote client)
                    return client.SendMessage(msg);
                else
                    throw new InvalidOperationException();
            }
            finally
            {
                st.StopCount(sw);
            }
        }

        /// <summary>创建控制器实例</summary>
        /// <param name="host"></param>
        /// <param name="session"></param>
        /// <param name="api"></param>
        /// <returns></returns>
        public static Object CreateController(this IApiHost host, IApiSession session, ApiAction api)
        {
            var controller = api.Controller;
            if (controller != null) return controller;

            controller = api.Type.CreateInstance();

            return controller;
        }

        #region 统计
        /// <summary>获取统计信息</summary>
        /// <param name="host"></param>
        /// <returns></returns>
        public static String GetStat(this IApiHost host)
        {
            if (host == null) return null;

            var sb = Pool.StringBuilder.Get();
            var pf1 = host.StatInvoke;
            var pf2 = host.StatProcess;
            if (pf1 != null && pf1.Value > 0) sb.AppendFormat("请求:{0} ", pf1);
            if (pf2 != null && pf2.Value > 0) sb.AppendFormat("处理:{0} ", pf2);

            if (host is ApiServer svr && svr.Server is NetServer ns)
                sb.Append(ns.GetStat());
            else if (host is ApiClient ac)
            {
                var st1 = ac.StatSend;
                var st2 = ac.StatReceive;
                if (st1 != null && st1.Value > 0) sb.AppendFormat("发送:{0} ", st1);
                if (st2 != null && st2.Value > 0) sb.AppendFormat("接收:{0} ", st2);
            }

            return sb.Put(true);
        }
        #endregion
    }
}