//==============================================================
//  版权所有：深圳杰文科技
//  文件名：ChannelSinkProvider.cs
//  版本：V1.0  
//  创建者：Jay  ( QQ： 85363208 )
//  创建时间：2017-11-28 16:18
//  创建描述：
//  修改者：
//  修改时间：
//  修改说明： 
//==============================================================

using System;
using System.Collections;
using System.IO;
using System.Net;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Messaging;
using Framework.Common;
using Framework.HandlerBase;
using Infrastructure.Log;
using Infrastructure.Utilities;

namespace Framework.Server
{
	//[DebuggerStepThrough]
	public class CustomServerSinkProvider : IServerChannelSinkProvider
	{
		#region - ChannelSinkProvider -

		private IServerChannelSinkProvider next = null;

		public CustomServerSinkProvider()
		{
		}

		public CustomServerSinkProvider(IDictionary properties, ICollection providerData)
		{
		}

		public void GetChannelData(IChannelDataStore channelData)
		{
		}

		public IServerChannelSink CreateSink(IChannelReceiver channel)
		{
			IServerChannelSink nextSink = null;
			if (next != null)
			{
				nextSink = next.CreateSink(channel);
			}

			return new CustomServerSink(nextSink);
		}

		public IServerChannelSinkProvider Next
		{
			get
			{
				return next;
			}
			set
			{
				next = value;
			}
		}
		#endregion
	}

	//非常重要的类，用于管理Session期间的数据库事务。
	//当Session开始时自动打开事务，当Session结束时自动提交事务，调用服务遇到异常则自动回滚事务。
	//[DebuggerStepThrough]
	public class CustomServerSink : BaseChannelSinkWithProperties, IServerChannelSink //BaseChannelObjectWithProperties, IServerChannelSink, IChannelSinkBase
	{
		#region - IServerChannelSink -

		private IServerChannelSink _next;

		public CustomServerSink(IServerChannelSink next)
		{
			_next = next;
		}

		public IServerChannelSink NextChannelSink
		{
			get
			{
				return _next;
			}
			set
			{
				_next = value;
			}
		}

		public void AsyncProcessResponse(IServerResponseChannelSinkStack sinkStack, Object state, IMessage msg, ITransportHeaders headers, Stream stream)
		{
			//如果客户端指定了压缩的标志，压缩数据流，默认为不压缩
			object compress = headers["Compress"];
			if (compress != null && compress.ToString() == "True")
			{
				// 压缩数据流
				stream = CompressionHelper.GetCompressedStream(stream);
				// forwarding to the stack for further processing
				sinkStack.AsyncProcessResponse(msg, headers, stream);
			}
			else
			{
				_next.AsyncProcessResponse(sinkStack, state, msg, headers, stream);
			}
		}

		public Stream GetResponseStream(IServerResponseChannelSinkStack sinkStack, Object state, IMessage msg, ITransportHeaders headers)
		{
			return null;
		}

		#endregion

		public string SessionDataName = "SessionData";

		public ServerProcessing ProcessMessage(IServerChannelSinkStack sinkStack, IMessage requestMsg, ITransportHeaders requestHeaders, Stream requestStream, out IMessage responseMsg, out ITransportHeaders responseHeaders, out Stream responseStream)
		{
			if (_next == null)
			{
				responseMsg = null;
				responseHeaders = null;
				responseStream = null;
				return ServerProcessing.Complete;
			}

			string ip = (requestHeaders[CommonTransportKeys.IPAddress] as IPAddress).ToString();

			IMethodCallMessage methodCall = requestMsg as IMethodCallMessage; //如果是调用方法，
			IUser user = ValidateUser(methodCall, ip);

			sinkStack.Push(this, null);

			ServerProcessing serverProcessing = ServerProcessing.Complete;

			object compress = requestHeaders["Compress"];
			if (compress != null && compress.ToString() == "True")
			{
				Stream localrequestStream = CompressionHelper.GetUncompressedStream(requestStream);

				Stream localresponseStream;
				serverProcessing = _next.ProcessMessage(sinkStack,
					requestMsg,
					requestHeaders,
					localrequestStream,
					out responseMsg,
					out responseHeaders,
					out localresponseStream);

				responseStream = CompressionHelper.GetCompressedStream(localresponseStream);
			}
			else
			{
				serverProcessing = _next.ProcessMessage(sinkStack, requestMsg, requestHeaders, requestStream, out responseMsg, out responseHeaders, out responseStream);
			}

			if (serverProcessing == ServerProcessing.Complete)
			{
				IMethodReturnMessage methodReturnMesage = responseMsg as IMethodReturnMessage;
				if (methodReturnMesage != null)
				{
					Commit(methodCall, methodReturnMesage, user, ip);
				}
			}

			return serverProcessing;
		}

		private void Commit(IMethodCallMessage methodCall, IMethodReturnMessage methodReturnMesage, IUser user, string ip)
		{
			IDB db = (IDB)CallContext.GetData("db");
			try
			{
				if (methodReturnMesage.Exception == null) //如果调用的方法没有抛出异常，那么提交事务。
				{
					if (db != null)
					{
						if (db.CurrentUser == null)
						{
							db.CurrentUser = user;
						}
						db.Save();
					}
				}
				else if (user != null)
				{
					SystemLogger.Instance.Write(user.Account, "{0} {1}\r\n{2}".Fmt(ip, methodReturnMesage.Exception.Message, methodReturnMesage.Exception.StackTrace));
					throw methodReturnMesage.Exception;
				}
			}
			finally
			{
				CallContext.SetData("db", null);
				if (db != null)
				{
					db.Close();
					db.Dispose();
					db = null;
				}
			}
		}

		private IUser ValidateUser(IMethodCallMessage methodCall, string ip)
		{
			if (methodCall == null)
			{
				return null;
			}

			string methodName = methodCall.MethodBase.DeclaringType.Name + "." + methodCall.MethodName;

			if (methodCall.LogicalCallContext.HasInfo)
			{
				SessionData session = methodCall.LogicalCallContext.GetData(SessionDataName) as SessionData;
				if (session != null)
				{
					IUser user = ServiceContext.ActiveUser(session.SessionId, methodName);
					if (user == null)
					{
						SystemLogger.Instance.Write(session.Account, "{0} {1}".Fmt(ip, "The current user is offline"));
						throw new ServiceException("您已经离线，请重新登录");
					}

					if (methodName != "SessionHandler.Heartbeat2")
					{
						SystemLogger.Instance.Write(session.Account, "{0} {1}".Fmt(ip, methodName));
					}
					return user;
				}
			}
			SystemLogger.Instance.Write("", "{0} {1}".Fmt(ip, methodName));
			return null;
		}

	}

}
