You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
217 lines
8.2 KiB
217 lines
8.2 KiB
//------------------------------------------------------------------------------ |
|
// 此代码版权(除特别声明或在XREF结尾的命名空间的代码)归作者本人若汝棋茗所有 |
|
// 源代码使用协议遵循本仓库的开源协议及附加协议,若本仓库没有设置,则按MIT开源协议授权 |
|
// CSDN博客:https://blog.csdn.net/qq_40374647 |
|
// 哔哩哔哩视频:https://space.bilibili.com/94253567 |
|
// Gitee源代码仓库:https://gitee.com/RRQM_Home |
|
// Github源代码仓库:https://github.com/RRQM |
|
// API首页:https://www.yuque.com/rrqm/touchsocket/index |
|
// 交流QQ群:234762506 |
|
// 感谢您的下载和使用 |
|
//------------------------------------------------------------------------------ |
|
//------------------------------------------------------------------------------ |
|
using System; |
|
using System.Net.Sockets; |
|
using System.Xml; |
|
using TouchSocket.Core; |
|
using TouchSocket.Http; |
|
using TouchSocket.Sockets; |
|
|
|
namespace TouchSocket.Rpc.XmlRpc |
|
{ |
|
/// <summary> |
|
/// XmlRpc解析器 |
|
/// </summary> |
|
public class XmlRpcParserPlugin : HttpPluginBase, IRpcParser |
|
{ |
|
private readonly ActionMap m_actionMap; |
|
private RpcStore m_rpcStore; |
|
private string m_xmlRpcUrl = "/xmlrpc"; |
|
|
|
/// <summary> |
|
/// 构造函数 |
|
/// </summary> |
|
public XmlRpcParserPlugin([DependencyParamterInject(true)] RpcStore rpcStore) |
|
{ |
|
m_actionMap = new ActionMap(); |
|
rpcStore?.AddRpcParser(GetType().Name, this); |
|
} |
|
|
|
/// <summary> |
|
/// XmlRpc调用 |
|
/// </summary> |
|
public ActionMap ActionMap => m_actionMap; |
|
|
|
/// <summary> |
|
/// 所属服务器 |
|
/// </summary> |
|
public RpcStore RpcStore => m_rpcStore; |
|
|
|
/// <summary> |
|
/// 当挂载在<see cref="HttpService"/>时,匹配Url然后响应。当设置为null或空时,会全部响应。 |
|
/// </summary> |
|
public string XmlRpcUrl |
|
{ |
|
get => m_xmlRpcUrl; |
|
set => m_xmlRpcUrl = string.IsNullOrEmpty(value) ? "/" : value; |
|
} |
|
|
|
#region RPC解析器 |
|
|
|
void IRpcParser.OnRegisterServer(MethodInstance[] methodInstances) |
|
{ |
|
foreach (var methodInstance in methodInstances) |
|
{ |
|
if (methodInstance.GetAttribute<XmlRpcAttribute>() is XmlRpcAttribute attribute) |
|
{ |
|
m_actionMap.Add(attribute.GetInvokenKey(methodInstance), methodInstance); |
|
} |
|
} |
|
} |
|
|
|
void IRpcParser.OnUnregisterServer(MethodInstance[] methodInstances) |
|
{ |
|
foreach (var methodInstance in methodInstances) |
|
{ |
|
if (methodInstance.GetAttribute<XmlRpcAttribute>() is XmlRpcAttribute attribute) |
|
{ |
|
m_actionMap.Remove(attribute.GetInvokenKey(methodInstance)); |
|
} |
|
} |
|
} |
|
|
|
void IRpcParser.SetRpcStore(RpcStore rpcService) |
|
{ |
|
m_rpcStore = rpcService; |
|
} |
|
|
|
#endregion RPC解析器 |
|
|
|
/// <summary> |
|
/// 当挂载在<see cref="HttpService"/>时,匹配Url然后响应。当设置为null或空时,会全部响应。 |
|
/// </summary> |
|
/// <param name="xmlRpcUrl"></param> |
|
/// <returns></returns> |
|
public XmlRpcParserPlugin SetXmlRpcUrl(string xmlRpcUrl) |
|
{ |
|
XmlRpcUrl = xmlRpcUrl; |
|
return this; |
|
} |
|
|
|
/// <summary> |
|
/// <inheritdoc/> |
|
/// </summary> |
|
/// <param name="client"></param> |
|
/// <param name="e"></param> |
|
protected override void OnPost(ITcpClientBase client, HttpContextEventArgs e) |
|
{ |
|
if (m_xmlRpcUrl == "/" || e.Context.Request.UrlEquals(m_xmlRpcUrl)) |
|
{ |
|
e.Handled = true; |
|
|
|
XmlDocument xml = new XmlDocument(); |
|
string xmlstring = e.Context.Request.GetBody(); |
|
xml.LoadXml(xmlstring); |
|
XmlNode methodName = xml.SelectSingleNode("methodCall/methodName"); |
|
string actionKey = methodName.InnerText; |
|
|
|
object[] ps = null; |
|
InvokeResult invokeResult = new InvokeResult(); |
|
XmlRpcCallContext callContext = null; |
|
|
|
if (m_actionMap.TryGetMethodInstance(actionKey, out MethodInstance methodInstance)) |
|
{ |
|
if (methodInstance.IsEnable) |
|
{ |
|
try |
|
{ |
|
callContext = new XmlRpcCallContext() |
|
{ |
|
Caller = client, |
|
HttpContext = e.Context, |
|
MethodInstance = methodInstance, |
|
XmlString = xmlstring |
|
}; |
|
ps = new object[methodInstance.ParameterNames.Length]; |
|
XmlNode paramsNode = xml.SelectSingleNode("methodCall/params"); |
|
if (methodInstance.MethodFlags.HasFlag(MethodFlags.IncludeCallContext)) |
|
{ |
|
ps[0] = callContext; |
|
int index = 1; |
|
foreach (XmlNode paramNode in paramsNode.ChildNodes) |
|
{ |
|
XmlNode valueNode = paramNode.FirstChild.FirstChild; |
|
ps[index] = (XmlDataTool.GetValue(valueNode, methodInstance.ParameterTypes[index])); |
|
index++; |
|
} |
|
} |
|
else |
|
{ |
|
int index = 0; |
|
foreach (XmlNode paramNode in paramsNode.ChildNodes) |
|
{ |
|
XmlNode valueNode = paramNode.FirstChild.FirstChild; |
|
ps[index] = (XmlDataTool.GetValue(valueNode, methodInstance.ParameterTypes[index])); |
|
index++; |
|
} |
|
} |
|
} |
|
catch (Exception ex) |
|
{ |
|
invokeResult.Status = InvokeStatus.Exception; |
|
invokeResult.Message = ex.Message; |
|
} |
|
} |
|
else |
|
{ |
|
invokeResult.Status = InvokeStatus.UnEnable; |
|
invokeResult.Message = "服务不可用"; |
|
} |
|
} |
|
else |
|
{ |
|
invokeResult.Status = InvokeStatus.UnFound; |
|
invokeResult.Message = "没有找到这个服务。"; |
|
} |
|
|
|
if (invokeResult.Status == InvokeStatus.Ready) |
|
{ |
|
IRpcServer rpcServer = methodInstance.ServerFactory.Create(callContext, ps); |
|
if (rpcServer is ITransientRpcServer transientRpcServer) |
|
{ |
|
transientRpcServer.CallContext = callContext; |
|
} |
|
invokeResult = m_rpcStore.Execute(rpcServer, ps, callContext); |
|
} |
|
|
|
HttpResponse httpResponse = e.Context.Response; |
|
|
|
ByteBlock byteBlock = new ByteBlock(); |
|
|
|
if (invokeResult.Status == InvokeStatus.Success) |
|
{ |
|
XmlDataTool.CreatResponse(httpResponse, invokeResult.Result); |
|
} |
|
else |
|
{ |
|
httpResponse.StatusCode = "201"; |
|
httpResponse.StatusMessage = invokeResult.Message; |
|
} |
|
try |
|
{ |
|
httpResponse.Answer(); |
|
} |
|
finally |
|
{ |
|
byteBlock.Dispose(); |
|
} |
|
|
|
if (!e.Context.Request.KeepAlive) |
|
{ |
|
client.TryShutdown(SocketShutdown.Both); |
|
} |
|
} |
|
base.OnPost(client, e); |
|
} |
|
} |
|
} |