parent
db29347e37
commit
e2d82ae952
63 changed files with 333 additions and 4107 deletions
@ -1,10 +1,7 @@ |
||||
<Project> |
||||
<PropertyGroup> |
||||
<DotXxlJobPackageNotes> |
||||
1. 修复回调一次过多的问题 |
||||
</DotXxlJobPackageNotes> |
||||
<HessianPackageNotes> |
||||
1. 实现基本的Hessian协议 |
||||
</HessianPackageNotes> |
||||
1. 修改接口方式为Restful方式,适配xxl-jobv2.2以上版本 |
||||
</DotXxlJobPackageNotes> |
||||
</PropertyGroup> |
||||
</Project> |
||||
|
||||
@ -1,6 +1,5 @@ |
||||
<Project> |
||||
<PropertyGroup> |
||||
<DotXxlJobPackageVersion>1.0.8</DotXxlJobPackageVersion> |
||||
<HessianPackageVersion>1.0.1</HessianPackageVersion> |
||||
<DotXxlJobPackageVersion>2.0.0</DotXxlJobPackageVersion> |
||||
</PropertyGroup> |
||||
</Project> |
||||
|
||||
@ -1,73 +0,0 @@ |
||||
------------ 0x43---------------- |
||||
ReadClassDefinition |
||||
Hessian.ClassDef={"Name":"com.xxl.rpc.remoting.net.params.XxlRpcRequest","Fields":["requestId","createMillisTime","accessToken","className","methodName","version","parameterTypes","parameters"]} |
||||
------------------------------------------------------------ |
||||
------------ 0x60---------------- |
||||
ReadObjectCompact XxlRpcRequest |
||||
------------ 0x30---------------- |
||||
ReadMediumString requestId |
||||
------------ 0x4c---------------- |
||||
ReadLongFull createMillisTime |
||||
------------ 0x00---------------- |
||||
ReadShortString accessToken |
||||
------------ 0x1d---------------- |
||||
ReadShortString className |
||||
------------ 0x08---------------- |
||||
ReadShortString methodName |
||||
------------ 0x4e---------------- |
||||
ReadNull version |
||||
------------ 0x71---------------- |
||||
ReadCompactFixList parameterTypes |
||||
------------ 0x43---------------- |
||||
ReadClassDefinition java.lang.Class |
||||
------------ 0x61---------------- |
||||
ReadObjectCompact java.lang.Class |
||||
------------ 0x0e---------------- |
||||
ReadShortString name |
||||
Hessian.HessianObject=[{"Item1":"requestId","Item2":"e24123be4a76417ca6f41f227532b235"},{"Item1":"createMillisTime","Item2":1547819469003},{"Item1":"accessToken","Item2":""},{"Item1":"className","Item2":"com.xxl.job.core.biz.AdminBiz"},{"It |
||||
em1":"methodName","Item2":"callback"},{"Item1":"version","Item2":null},{"Item1":"parameterTypes","Item2":[{"Name":"java.lang.Class","Fields":["name"]}]},{"Item1":"parameters","Item2":[{"Item1":"name","Item2":"java.util.List"}]}] |
||||
------------------------------------------------------------ |
||||
------------ 0x71---------------- |
||||
ReadCompactFixList parameters |
||||
------------ 0x72---------------- |
||||
ReadCompactFixList List |
||||
------------ 0x43---------------- |
||||
ReadClassDefinition HandleCallbackParam |
||||
------------ 0x62---------------- |
||||
ReadObjectCompact HandleCallbackParam |
||||
------------ 0x9b---------------- |
||||
ReadIntegerSingleByte logId |
||||
------------ 0x4c---------------- |
||||
ReadLongFull logDateTim |
||||
------------ 0x43---------------- |
||||
ReadClassDefinition executeResult |
||||
System.Collections.Generic.List`1[System.Object]=[[{"Name":"com.xxl.job.core.biz.model.HandleCallbackParam","Fields":["logId","logDateTim","executeResult"]},[{"Item1":"logId","Item2":11},{"Item1":"logDateTim","Item2":1547819469000},{"Item1" |
||||
:"executeResult","Item2":{"Name":"com.xxl.job.core.biz.model.ReturnT","Fields":["code","msg","content"]}}]]] |
||||
------------------------------------------------------------ |
||||
------------ 0x63---------------- |
||||
ReadObjectCompact executeResult |
||||
------------ 0xc8---------------- |
||||
ReadIntegerTwoBytes code |
||||
------------ 0x03---------------- |
||||
ReadShortString msg |
||||
------------ 0x07---------------- |
||||
ReadShortString content |
||||
Hessian.HessianObject=[{"Item1":"code","Item2":200},{"Item1":"msg","Item2":"1bc"},{"Item1":"content","Item2":"acd3323"}] |
||||
------------------------------------------------------------ |
||||
------------ 0x62---------------- |
||||
ReadObjectCompact HandleCallbackParam |
||||
------------ 0xa6---------------- |
||||
ReadIntegerSingleByte logId |
||||
------------ 0x4c---------------- |
||||
ReadLongFull logDateTim |
||||
------------ 0x63---------------- |
||||
ReadObjectCompact executeResult |
||||
------------ 0xc9---------------- |
||||
ReadIntegerTwoBytes code |
||||
------------ 0x03---------------- |
||||
ReadShortString msg |
||||
------------ 0x03---------------- |
||||
ReadShortString content |
||||
Hessian.HessianObject=[{"Item1":"logId","Item2":22},{"Item1":"logDateTim","Item2":1547819469000},{"Item1":"executeResult","Item2":[{"Item1":"code","Item2":500},{"Item1":"msg","Item2":"cac"},{"Item1":"content","Item2":"aad"}]}] |
||||
------------------------------------------------------------ |
||||
------------------------------------------------------------ |
||||
@ -1,74 +0,0 @@ |
||||
--------------------------------------------------------------- |
||||
------------ 0x43---------------- |
||||
ReadClassDefinition |
||||
Hessian.ClassDef={"Name":"com.xxl.rpc.remoting.net.params.XxlRpcRequest","Fields":["requestId","createMillisTime","accessToken","className","methodName","version","parameterTypes","parameters"]} |
||||
------------------------------------------------------------ |
||||
------------ 0x60---------------- |
||||
ReadObjectCompact |
||||
------------ 0x30---------------- |
||||
ReadMediumString |
||||
------------ 0x4c---------------- |
||||
ReadLongFull |
||||
------------ 0x00---------------- |
||||
ReadShortString |
||||
------------ 0x1d---------------- |
||||
ReadShortString |
||||
------------ 0x08---------------- |
||||
ReadShortString |
||||
------------ 0x4e---------------- |
||||
ReadNull |
||||
------------ 0x71---------------- |
||||
ReadCompactFixList |
||||
------------ 0x43---------------- |
||||
ReadClassDefinition |
||||
------------ 0x61---------------- |
||||
ReadObjectCompact |
||||
------------ 0x0e---------------- |
||||
ReadShortString |
||||
Hessian.HessianObject=[{"Item1":"requestId","Item2":"e24123be4a76417ca6f41f227532b235"},{"Item1":"createMillisTime","Item2":1547819469003},{"Item1":"accessToken","Item2":""},{"Item1":"className","Item2":"com.xxl.job.core.biz.AdminBiz"},{"I |
||||
tem1":"methodName","Item2":"callback"},{"Item1":"version","Item2":null},{"Item1":"parameterTypes","Item2":[{"Name":"java.lang.Class","Fields":["name"]}]},{"Item1":"parameters","Item2":[{"Item1":"name","Item2":"java.util.List"}]}] |
||||
------------------------------------------------------------ |
||||
------------ 0x71---------------- |
||||
ReadCompactFixList |
||||
------------ 0x72---------------- |
||||
ReadCompactFixList |
||||
------------ 0x43---------------- |
||||
ReadClassDefinition |
||||
------------ 0x62---------------- |
||||
ReadObjectCompact |
||||
------------ 0x9b---------------- |
||||
ReadIntegerSingleByte |
||||
------------ 0x4c---------------- |
||||
ReadLongFull |
||||
------------ 0x43---------------- |
||||
ReadClassDefinition |
||||
System.Collections.Generic.List`1[System.Object]=[[{"Name":"com.xxl.job.core.biz.model.HandleCallbackParam","Fields":["logId","logDateTim","executeResult"]},[{"Item1":"logId","Item2":11},{"Item1":"logDateTim","Item2":1547819469000},{"Item1 |
||||
":"executeResult","Item2":{"Name":"com.xxl.job.core.biz.model.ReturnT","Fields":["code","msg","content"]}}]]] |
||||
------------------------------------------------------------ |
||||
------------ 0x63---------------- |
||||
ReadObjectCompact |
||||
------------ 0xc8---------------- |
||||
ReadIntegerTwoBytes |
||||
------------ 0x03---------------- |
||||
ReadShortString |
||||
------------ 0x07---------------- |
||||
ReadShortString |
||||
Hessian.HessianObject=[{"Item1":"code","Item2":200},{"Item1":"msg","Item2":"1bc"},{"Item1":"content","Item2":"acd3323"}] |
||||
------------------------------------------------------------ |
||||
------------ 0x62---------------- |
||||
ReadObjectCompact |
||||
------------ 0xa6---------------- |
||||
ReadIntegerSingleByte |
||||
------------ 0x4c---------------- |
||||
ReadLongFull |
||||
------------ 0x63---------------- |
||||
ReadObjectCompact |
||||
------------ 0xc9---------------- |
||||
ReadIntegerTwoBytes |
||||
------------ 0x03---------------- |
||||
ReadShortString |
||||
------------ 0x03---------------- |
||||
ReadShortString |
||||
Hessian.HessianObject=[{"Item1":"logId","Item2":22},{"Item1":"logDateTim","Item2":1547819469000},{"Item1":"executeResult","Item2":[{"Item1":"code","Item2":500},{"Item1":"msg","Item2":"aad"},{"Item1":"content","Item2":"cac"}]}] |
||||
------------------------------------------------------------ |
||||
------------------------------------------------------------ |
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -1,18 +0,0 @@ |
||||
set -ex |
||||
|
||||
cd $(dirname $0)/../ |
||||
|
||||
artifactsFolder="./artifacts" |
||||
|
||||
if [ -d $artifactsFolder ]; then |
||||
rm -R $artifactsFolder |
||||
fi |
||||
|
||||
mkdir -p $artifactsFolder |
||||
|
||||
|
||||
dotnet build ./src/Hessian/Hessian.csproj -c Release |
||||
|
||||
dotnet pack ./src/Hessian/Hessian.csproj -c Release -o ../../$artifactsFolder |
||||
|
||||
dotnet nuget push ./$artifactsFolder/Hessian.*.nupkg -k $NUGET_KEY -s https://www.nuget.org |
||||
@ -1,132 +0,0 @@ |
||||
using System; |
||||
using System.Collections; |
||||
using System.Collections.Generic; |
||||
using System.Reflection; |
||||
using System.Runtime.Serialization; |
||||
using DotXxlJob.Core.Model; |
||||
using Hessian; |
||||
|
||||
namespace DotXxlJob.Core |
||||
{ |
||||
public class HessianObjectHelper |
||||
{ |
||||
|
||||
private static readonly Dictionary<string,Dictionary<string,PropertyInfo>> TransferObjCache |
||||
= new Dictionary<string, Dictionary<string, PropertyInfo>>(); |
||||
private static readonly Dictionary<string,Type> TransferTypeCache |
||||
= new Dictionary<string, Type>(); |
||||
static HessianObjectHelper() |
||||
{ |
||||
|
||||
InitProperties(typeof(RpcRequest)); |
||||
|
||||
InitProperties(typeof(TriggerParam)); |
||||
|
||||
InitProperties(typeof(RpcResponse)); |
||||
|
||||
InitProperties(typeof(ReturnT)); |
||||
|
||||
InitProperties(typeof(HandleCallbackParam)); |
||||
|
||||
InitProperties(typeof(JavaClass)); |
||||
|
||||
InitProperties(typeof(RegistryParam)); |
||||
|
||||
InitProperties(typeof(LogResult)); |
||||
} |
||||
private static void InitProperties(Type type) |
||||
{ |
||||
var propertyInfos = new Dictionary<string, PropertyInfo>(); |
||||
var typeInfo = type.GetTypeInfo(); |
||||
var classAttr = type.GetCustomAttribute<DataContractAttribute>(); |
||||
if (classAttr == null) |
||||
{ |
||||
return; |
||||
} |
||||
|
||||
foreach (var property in typeInfo.DeclaredProperties) |
||||
{ |
||||
var attribute = property.GetCustomAttribute<DataMemberAttribute>(); |
||||
|
||||
if (null == attribute) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
if (!property.CanRead || !property.CanWrite) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
propertyInfos.Add(attribute.Name,property); |
||||
} |
||||
TransferTypeCache.Add(classAttr.Name,type); |
||||
TransferObjCache.Add(classAttr.Name,propertyInfos); |
||||
} |
||||
|
||||
public static object GetRealObjectValue(Deserializer deserializer,object value) |
||||
{ |
||||
if (value == null || IsSimpleType(value.GetType())) |
||||
{ |
||||
return value; |
||||
} |
||||
|
||||
if (value is HessianObject hessianObject) |
||||
{ |
||||
if(TransferObjCache.TryGetValue(hessianObject.TypeName,out var properties)) |
||||
{ |
||||
var instance = Activator.CreateInstance(TransferTypeCache[hessianObject.TypeName]); |
||||
foreach (var (k, v) in hessianObject) |
||||
{ |
||||
if (properties.TryGetValue(k, out var p)) |
||||
{ |
||||
p.SetValue(instance,GetRealObjectValue(deserializer,v)); |
||||
} |
||||
} |
||||
|
||||
return instance; |
||||
} |
||||
} |
||||
|
||||
if (value is ClassDef) |
||||
{ |
||||
return GetRealObjectValue(deserializer, deserializer.ReadValue()); |
||||
} |
||||
|
||||
if (IsListType(value.GetType())) |
||||
{ |
||||
var listData = new List<object>(); |
||||
|
||||
var cList = value as List<object>; |
||||
foreach (var cItem in cList) |
||||
{ |
||||
listData.Add(GetRealObjectValue(deserializer,cItem)); |
||||
} |
||||
|
||||
return listData; |
||||
} |
||||
|
||||
throw new HessianException($"unknown item:{value.GetType()}"); |
||||
} |
||||
|
||||
private static bool IsListType(Type type) |
||||
{ |
||||
return typeof(ICollection).IsAssignableFrom(type); |
||||
} |
||||
private static bool IsSimpleType(Type typeInfo) |
||||
{ |
||||
if (typeInfo.IsValueType || typeInfo.IsEnum || typeInfo.IsPrimitive) |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
if (typeof (string) == typeInfo) |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
} |
||||
} |
||||
@ -1,79 +0,0 @@ |
||||
using System; |
||||
using System.IO; |
||||
using DotXxlJob.Core.Model; |
||||
using Hessian; |
||||
|
||||
namespace DotXxlJob.Core |
||||
{ |
||||
public static class HessianSerializer |
||||
{ |
||||
|
||||
public static RpcRequest DeserializeRequest(Stream stream) |
||||
{ |
||||
RpcRequest request = null; |
||||
|
||||
try |
||||
{ |
||||
var deserializer = new Deserializer(stream); |
||||
var classDef = deserializer.ReadValue() as ClassDef; |
||||
if (!Constants.RpcRequestJavaFullName.Equals(classDef.Name)) |
||||
{ |
||||
throw new HessianException($"unknown class :{classDef.Name}"); |
||||
} |
||||
request = HessianObjectHelper.GetRealObjectValue(deserializer,deserializer.ReadValue()) as RpcRequest; |
||||
} |
||||
catch (EndOfStreamException) |
||||
{ |
||||
//没有数据可读了 |
||||
} |
||||
return request; |
||||
|
||||
} |
||||
|
||||
|
||||
public static void SerializeRequest(Stream stream,RpcRequest req) |
||||
{ |
||||
var serializer = new Serializer(stream); |
||||
serializer.WriteObject(req); |
||||
} |
||||
|
||||
public static void SerializeResponse(Stream stream,RpcResponse res) |
||||
{ |
||||
var serializer = new Serializer(stream); |
||||
serializer.WriteObject(res); |
||||
} |
||||
|
||||
|
||||
public static RpcResponse DeserializeResponse(Stream resStream) |
||||
{ |
||||
RpcResponse rsp = null; |
||||
|
||||
try |
||||
{ |
||||
var deserializer = new Deserializer(resStream); |
||||
var classDef = deserializer.ReadValue() as ClassDef; |
||||
if (!Constants.RpcResponseJavaFullName.Equals(classDef.Name)) |
||||
{ |
||||
throw new HessianException($"unknown class :{classDef.Name}"); |
||||
} |
||||
|
||||
rsp = HessianObjectHelper.GetRealObjectValue(deserializer,deserializer.ReadValue()) as RpcResponse; |
||||
|
||||
} |
||||
catch (EndOfStreamException) |
||||
{ |
||||
//没有数据可读了 |
||||
} |
||||
catch |
||||
{ |
||||
//TODO: do something? |
||||
} |
||||
|
||||
return rsp; |
||||
} |
||||
|
||||
|
||||
} |
||||
|
||||
|
||||
} |
||||
@ -1,217 +0,0 @@ |
||||
using System; |
||||
using System.Collections.Concurrent; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Reflection; |
||||
using System.Threading.Tasks; |
||||
using Hessian; |
||||
using DotXxlJob.Core.Config; |
||||
using DotXxlJob.Core.Model; |
||||
using Microsoft.Extensions.Logging; |
||||
using Microsoft.Extensions.Options; |
||||
|
||||
namespace DotXxlJob.Core |
||||
{ |
||||
|
||||
/// <summary> |
||||
/// 负责执行Http请求,序列化和反序列化并发送响应 |
||||
/// </summary> |
||||
public class XxlRpcServiceHandler |
||||
{ |
||||
|
||||
private readonly JobDispatcher _jobDispatcher; |
||||
private readonly IJobLogger _jobLogger; |
||||
private readonly ILogger<XxlRpcServiceHandler> _logger; |
||||
private readonly XxlJobExecutorOptions _options; |
||||
|
||||
private readonly ConcurrentDictionary<string, MethodInfo> METHOD_CACHE = |
||||
new ConcurrentDictionary<string, MethodInfo>(); |
||||
|
||||
public XxlRpcServiceHandler(IOptions<XxlJobExecutorOptions> optionsAccessor, |
||||
JobDispatcher jobDispatcher, |
||||
IJobLogger jobLogger, |
||||
ILogger<XxlRpcServiceHandler> logger) |
||||
{ |
||||
|
||||
this._jobDispatcher = jobDispatcher; |
||||
this._jobLogger = jobLogger; |
||||
this._logger = logger; |
||||
|
||||
this._options = optionsAccessor.Value; |
||||
if (this._options == null) |
||||
{ |
||||
throw new ArgumentNullException(nameof(XxlJobExecutorOptions)); |
||||
} |
||||
|
||||
} |
||||
|
||||
/// <summary> |
||||
/// 处理XxlRpc请求流 |
||||
/// </summary> |
||||
/// <param name="reqStream"></param> |
||||
/// <returns></returns> |
||||
public async Task<byte[]> HandlerAsync(Stream reqStream) |
||||
{ |
||||
var req = HessianSerializer.DeserializeRequest(reqStream); |
||||
|
||||
var res = new RpcResponse { RequestId = req.RequestId}; |
||||
|
||||
if (!ValidRequest(req, out var error)) |
||||
{ |
||||
this._logger.LogWarning("job task request is not valid:{error}",error); |
||||
res.ErrorMsg = error; |
||||
} |
||||
else |
||||
{ |
||||
this._logger.LogDebug("receive job task ,req.RequestId={requestId},method={methodName}" |
||||
,req.RequestId,req.MethodName); |
||||
await Invoke(req, res); |
||||
this._logger.LogDebug("completed receive job task ,req.RequestId={requestId},method={methodName},IsError={IsError}" |
||||
,req.RequestId,req.MethodName,res.IsError); |
||||
} |
||||
|
||||
using (var outputStream = new MemoryStream()) |
||||
{ |
||||
HessianSerializer.SerializeResponse(outputStream,res); |
||||
return outputStream.GetBuffer(); |
||||
} |
||||
|
||||
} |
||||
|
||||
/// <summary> |
||||
/// 校验请求信息 |
||||
/// </summary> |
||||
/// <param name="req"></param> |
||||
/// <param name="error"></param> |
||||
/// <returns></returns> |
||||
private bool ValidRequest(RpcRequest req,out string error) |
||||
{ |
||||
error = string.Empty; |
||||
if (req == null) |
||||
{ |
||||
error = "unknown request stream data,codec fail"; |
||||
return false; |
||||
} |
||||
|
||||
if (!"com.xxl.job.core.biz.ExecutorBiz".Equals(req.ClassName)) // |
||||
{ |
||||
error = "not supported request!"; |
||||
return false; |
||||
} |
||||
|
||||
if (DateTime.UtcNow.Subtract(req.CreateMillisTime.FromMilliseconds()) > Constants.RpcRequestExpireTimeSpan) |
||||
{ |
||||
error = "request is timeout!"; |
||||
return false; |
||||
} |
||||
|
||||
if (!string.IsNullOrEmpty(this._options.AccessToken) && this._options.AccessToken != req.AccessToken) |
||||
{ |
||||
error = "need authorize"; |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// 执行请求,获取执行函数 |
||||
/// </summary> |
||||
/// <param name="req"></param> |
||||
/// <param name="res"></param> |
||||
/// <returns></returns> |
||||
private Task Invoke(RpcRequest req, RpcResponse res) |
||||
{ |
||||
try |
||||
{ |
||||
var method = GetMethodInfo(req.MethodName); |
||||
if (method == null) |
||||
{ |
||||
res.ErrorMsg = $"The method{req.MethodName} is not defined."; |
||||
this._logger.LogWarning( $"The method{req.MethodName} is not defined."); |
||||
} |
||||
else |
||||
{ |
||||
var result = method.Invoke(this, req.Parameters.ToArray()); |
||||
|
||||
res.Result = result; |
||||
} |
||||
|
||||
} |
||||
catch (Exception ex) |
||||
{ |
||||
res.ErrorMsg = ex.Message +"\n--------------\n"+ ex.StackTrace; |
||||
this._logger.LogError(ex,"invoke method error:{0}",ex.Message); |
||||
} |
||||
|
||||
return Task.CompletedTask; |
||||
|
||||
} |
||||
|
||||
private MethodInfo GetMethodInfo(string methodName) |
||||
{ |
||||
if (METHOD_CACHE.TryGetValue(methodName, out var method)) |
||||
{ |
||||
return method; |
||||
} |
||||
|
||||
var type = GetType(); |
||||
method = type.GetMethod( methodName, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.IgnoreCase); |
||||
if (method != null) |
||||
{ |
||||
METHOD_CACHE.TryAdd(methodName, method); |
||||
} |
||||
|
||||
return method; |
||||
} |
||||
|
||||
|
||||
#region rpc service |
||||
|
||||
private ReturnT Beat() |
||||
{ |
||||
return ReturnT.SUCCESS; |
||||
} |
||||
|
||||
private ReturnT IdleBeat(int jobId) |
||||
{ |
||||
return this._jobDispatcher.IdleBeat(jobId); |
||||
} |
||||
|
||||
private ReturnT Kill(int jobId) |
||||
{ |
||||
return this._jobDispatcher.TryRemoveJobTask(jobId) ? |
||||
ReturnT.SUCCESS |
||||
: |
||||
ReturnT.Success("job thread already killed."); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// read Log |
||||
/// </summary> |
||||
/// <param name="logDateTime"></param> |
||||
/// <param name="logId"></param> |
||||
/// <param name="fromLineNum"></param> |
||||
/// <returns></returns> |
||||
private ReturnT Log(long logDateTime, int logId, int fromLineNum) |
||||
{ |
||||
var ret = ReturnT.Success(null); |
||||
ret.Content = this._jobLogger.ReadLog(logDateTime, logId, fromLineNum); |
||||
return ret; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// 执行 |
||||
/// </summary> |
||||
/// <param name="triggerParam"></param> |
||||
/// <returns></returns> |
||||
private ReturnT Run(TriggerParam triggerParam) |
||||
{ |
||||
return this._jobDispatcher.Execute(triggerParam); |
||||
} |
||||
#endregion |
||||
|
||||
|
||||
|
||||
} |
||||
} |
||||
@ -1,11 +0,0 @@ |
||||
using System.Collections.Generic; |
||||
|
||||
namespace Hessian |
||||
{ |
||||
public class ClassElement |
||||
{ |
||||
public string ClassName { get; set; } |
||||
|
||||
public List<PropertyElement> Fields { get; set; } |
||||
} |
||||
} |
||||
File diff suppressed because it is too large
Load Diff
@ -1,39 +0,0 @@ |
||||
namespace Hessian |
||||
{ |
||||
internal static class Marker |
||||
{ |
||||
public const byte True = (byte) 'T';//0x54; |
||||
public const byte False = (byte) 'F';// 0x46; |
||||
public const byte Null = (byte) 'N';//0x4E; |
||||
public const byte BinaryNonfinalChunk = (byte) 'b';//0x41; |
||||
public const byte BinaryFinalChunk = (byte) 'B';//0x42; |
||||
public const byte ClassDefinition = (byte) 'C';//0x43; |
||||
public const byte DateTimeLong = 0x4A; |
||||
public const byte DateTimeCompact = 0x4B; |
||||
public const byte Double = 0x5A; |
||||
public const byte DoubleZero = 0x5B; |
||||
public const byte DoubleOne = 0x5C; |
||||
public const byte DoubleOctet = 0x5D; |
||||
public const byte DoubleShort = 0x5E; |
||||
public const byte DoubleFloat = 0x5F; |
||||
public const byte UnpackedInteger = (byte) 'I';// 0x49; |
||||
public const byte PackedLong = (byte) 'Y';// 0x59; |
||||
public const byte UnpackedLong = (byte) 'L';// 0x4C; |
||||
public const byte StringNonfinalChunk = 0x52; |
||||
public const byte StringFinalChunk = 0x53; |
||||
public const byte VarList = 0x55; |
||||
public const byte FixedList = 0x56; |
||||
public const byte VarListUntyped = 0x57; |
||||
public const byte FixListUntyped = 0x58; |
||||
|
||||
public const byte CompactFixListStart = 0x70; |
||||
public const byte CompactFixListEnd = 0x77; |
||||
public const byte CompactFixListUntypedStart = 0x78; |
||||
public const byte CompactFixListUntypedEnd = 0x7F; |
||||
|
||||
public const byte ClassReference = (byte) 'O';//0x4F |
||||
public const byte InstanceReference = (byte) 'Q'; //0x51; |
||||
|
||||
|
||||
} |
||||
} |
||||
@ -1,142 +0,0 @@ |
||||
using System; |
||||
using System.IO; |
||||
|
||||
namespace Hessian |
||||
{ |
||||
public class PeekStream : Stream |
||||
{ |
||||
private Stream inner; |
||||
private byte? peek; |
||||
|
||||
public PeekStream(Stream inner) |
||||
{ |
||||
if (inner == null) { |
||||
throw new ArgumentNullException("inner"); |
||||
} |
||||
|
||||
this.inner = inner; |
||||
this.peek = null; |
||||
} |
||||
|
||||
public override bool CanRead { |
||||
get { |
||||
return inner.CanRead; |
||||
} |
||||
} |
||||
|
||||
public override bool CanSeek { |
||||
get { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public override bool CanWrite { |
||||
get { |
||||
return false; |
||||
} |
||||
} |
||||
|
||||
public override long Length { |
||||
get { |
||||
return inner.Length; |
||||
} |
||||
} |
||||
|
||||
public override long Position { |
||||
get { |
||||
return inner.Position - (peek.HasValue ? 1 : 0); |
||||
} |
||||
set { |
||||
throw new NotSupportedException("Seeking not supported."); |
||||
} |
||||
} |
||||
|
||||
public byte? Peek () |
||||
{ |
||||
if (!peek.HasValue) { |
||||
var b = inner.ReadByte(); |
||||
|
||||
if (b == -1) { |
||||
return null; |
||||
} |
||||
|
||||
peek = (byte) b; |
||||
} |
||||
|
||||
return peek; |
||||
} |
||||
|
||||
public override int ReadByte () |
||||
{ |
||||
if (peek.HasValue) { |
||||
var val = peek.Value; |
||||
peek = null; |
||||
return val; |
||||
} |
||||
|
||||
return inner.ReadByte(); |
||||
} |
||||
|
||||
public override int Read (byte[] buffer, int offset, int count) |
||||
{ |
||||
Conditions.CheckNotNull(buffer, "buffer"); |
||||
Conditions.CheckGreaterOrEqual(offset, 0, "offset"); |
||||
Conditions.CheckLess(offset, buffer.Length, "offset"); |
||||
Conditions.CheckGreaterOrEqual(count, 0, "count"); |
||||
Conditions.CheckArgument( |
||||
offset + count <= buffer.Length, |
||||
"Buffer is not big enough to contain the requested amount of data at the given offset."); |
||||
|
||||
if (count == 0) { |
||||
return 0; |
||||
} |
||||
|
||||
var bytesToRead = count; |
||||
|
||||
if (peek.HasValue) { |
||||
buffer[offset++] = peek.Value; |
||||
peek = null; |
||||
--bytesToRead; |
||||
} |
||||
|
||||
int bytesRead; |
||||
while (bytesToRead > 0 && (bytesRead = inner.Read (buffer, offset, bytesToRead)) != 0) { |
||||
offset += bytesRead; |
||||
bytesToRead -= bytesRead; |
||||
} |
||||
|
||||
return count - bytesToRead; |
||||
} |
||||
|
||||
public override void Write (byte[] buffer, int offset, int count) |
||||
{ |
||||
throw new NotSupportedException("Writes not supported."); |
||||
} |
||||
|
||||
public override void SetLength (long value) |
||||
{ |
||||
throw new NotSupportedException("Seeking not supported."); |
||||
} |
||||
|
||||
public override long Seek (long offset, SeekOrigin origin) |
||||
{ |
||||
throw new NotSupportedException("Seeking not supported."); |
||||
} |
||||
|
||||
public override void Flush () |
||||
{ |
||||
throw new NotSupportedException("Writes not supported."); |
||||
} |
||||
|
||||
protected override void Dispose (bool disposing) |
||||
{ |
||||
if (inner != null) { |
||||
inner.Dispose (); |
||||
inner = null; |
||||
} |
||||
|
||||
base.Dispose (disposing); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -1,31 +0,0 @@ |
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Reflection; |
||||
|
||||
namespace Hessian |
||||
{ |
||||
public class PropertyElement |
||||
{ |
||||
public string Name { get; set; } |
||||
public int Order { get; set; } |
||||
public PropertyInfo PropertyInfo { get; set; } |
||||
} |
||||
|
||||
internal class PropertyComparer : IComparer<PropertyElement> |
||||
{ |
||||
private readonly IComparer<int> comparer; |
||||
|
||||
public PropertyComparer() |
||||
{ |
||||
comparer = Comparer<int>.Default; |
||||
} |
||||
|
||||
public int Compare(PropertyElement x, PropertyElement y) |
||||
{ |
||||
var eq = comparer.Compare(x.Order, y.Order); |
||||
return 0 == eq |
||||
? String.Compare(x.Name, y.Name, StringComparison.Ordinal) |
||||
: eq; |
||||
} |
||||
} |
||||
} |
||||
@ -1,523 +0,0 @@ |
||||
using System; |
||||
using System.Collections; |
||||
using System.Collections.Concurrent; |
||||
using System.Collections.Generic; |
||||
using System.IO; |
||||
using System.Linq; |
||||
using System.Reflection; |
||||
using System.Runtime.Serialization; |
||||
using System.Text; |
||||
|
||||
namespace Hessian |
||||
{ |
||||
public class Serializer |
||||
{ |
||||
static readonly ConcurrentDictionary<Type,ClassElement> ClassDefCache =new ConcurrentDictionary<Type, ClassElement>(); |
||||
|
||||
private readonly Stream _stream; |
||||
private readonly HessianSerializationContext _context; |
||||
|
||||
public Serializer (Stream stream) |
||||
{ |
||||
this._stream = stream ?? throw new ArgumentNullException(nameof(stream)); |
||||
_context = new HessianSerializationContext(); |
||||
} |
||||
|
||||
public void WriteObject(object graph) |
||||
{ |
||||
var objectType = graph.GetType(); |
||||
if (!ClassDefCache.TryGetValue(objectType, out var classDef)) |
||||
{ |
||||
classDef = GetClassDef(objectType.GetTypeInfo()); |
||||
} |
||||
|
||||
var index = this._context.Instances.IndexOf(graph); |
||||
|
||||
if (index > -1) |
||||
{ |
||||
WriteInstanceReference(index); |
||||
return; |
||||
} |
||||
|
||||
this._context.Instances.Add(graph); |
||||
|
||||
index = this._context.Classes.IndexOf(objectType); |
||||
|
||||
if (index < 0) |
||||
{ |
||||
BeginClassDefinition(); |
||||
WriteString(classDef.ClassName); |
||||
WriteInt32(classDef.Fields.Count); |
||||
|
||||
foreach (var property in classDef.Fields) |
||||
{ |
||||
WriteString(property.Name); |
||||
} |
||||
EndClassDefinition(); |
||||
|
||||
index = this._context.Classes.Count; |
||||
|
||||
this._context.Classes.Add(objectType); |
||||
} |
||||
WriteObjectReference(index); |
||||
foreach (var item in classDef.Fields) |
||||
{ |
||||
var value = item.PropertyInfo.GetValue(graph); |
||||
WriteValue(value); |
||||
} |
||||
} |
||||
|
||||
public void WriteValue(object val) |
||||
{ |
||||
if (val == null) |
||||
{ |
||||
WriteNull(); |
||||
return; |
||||
} |
||||
var valType = val.GetType(); |
||||
var typeInfo = valType.GetTypeInfo(); |
||||
if (IsSimpleType(typeInfo)) |
||||
{ |
||||
WriteSimpleValue(val); |
||||
return; |
||||
} |
||||
|
||||
if (IsListType(typeInfo)) |
||||
{ |
||||
WriteListValue(val); |
||||
return; |
||||
} |
||||
|
||||
WriteObject(val); |
||||
} |
||||
|
||||
private void WriteListValue(object val) |
||||
{ |
||||
var tag = (int)Marker.CompactFixListStart; |
||||
if (!(val is ICollection eVal)) |
||||
{ |
||||
throw new HessianException("write list data error"); |
||||
} |
||||
tag += eVal.Count; |
||||
if (tag > Marker.CompactFixListEnd) |
||||
{ |
||||
throw new HessianException("write list data error,tag too large"); |
||||
} |
||||
this._stream.WriteByte((byte)tag); |
||||
int index = 1; |
||||
foreach (var item in eVal) |
||||
{ |
||||
if (index == 1) |
||||
{ |
||||
WriteString("["+GetItemTypeName(item.GetType())); |
||||
} |
||||
WriteValue(item); |
||||
index++; |
||||
} |
||||
} |
||||
|
||||
private string GetItemTypeName(Type type) |
||||
{ |
||||
var classType = type.GetCustomAttribute<DataContractAttribute>(); |
||||
if (classType != null) |
||||
{ |
||||
return classType.Name; |
||||
} |
||||
|
||||
if (IsListType(type.GetTypeInfo())) |
||||
{ |
||||
return "java.util.List"; |
||||
} |
||||
|
||||
return type.Name; |
||||
} |
||||
private void WriteSimpleValue(object val) |
||||
{ |
||||
var valType = val.GetType(); |
||||
if (valType == typeof(int)) |
||||
{ |
||||
WriteInt32((int)val); |
||||
} |
||||
else if (valType == typeof(bool)) |
||||
{ |
||||
WriteBoolean((bool)val); |
||||
} |
||||
else if (valType == typeof(long)) |
||||
{ |
||||
WriteInt64((long)val); |
||||
} |
||||
else if (valType == typeof(double)) |
||||
{ |
||||
WriteDouble((double)val); |
||||
} |
||||
else if (valType == typeof(string)) |
||||
{ |
||||
WriteString((string)val); |
||||
} |
||||
else if (valType == typeof(DateTime)) |
||||
{ |
||||
WriteDateTime((DateTime)val); |
||||
} |
||||
} |
||||
|
||||
private ClassElement GetClassDef(TypeInfo typeInfo) |
||||
{ |
||||
|
||||
var classAttr = typeInfo.GetCustomAttribute<DataContractAttribute>(); |
||||
if (classAttr == null) |
||||
{ |
||||
throw new HessianException("DataContract must be set"); |
||||
} |
||||
|
||||
ClassElement ce = new ClassElement {ClassName = classAttr.Name, Fields = new List<PropertyElement>()}; |
||||
|
||||
//ClassDef def = new ClassDef(classAttr.Name); |
||||
foreach (var property in typeInfo.DeclaredProperties) |
||||
{ |
||||
var attribute = property.GetCustomAttribute<DataMemberAttribute>(); |
||||
|
||||
if (null == attribute) |
||||
{ |
||||
continue; |
||||
} |
||||
|
||||
if (!property.CanRead || !property.CanWrite) |
||||
{ |
||||
continue; |
||||
} |
||||
PropertyElement p = new PropertyElement { |
||||
Name = attribute.Name, |
||||
Order = attribute.Order, |
||||
PropertyInfo = property |
||||
}; |
||||
ce.Fields .Add( p ); |
||||
} |
||||
ce.Fields.Sort(new PropertyComparer()); |
||||
return ce; |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Writes NULL token into stream |
||||
/// </summary> |
||||
public void WriteNull() |
||||
{ |
||||
this._stream.WriteByte(Marker.Null); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Writes <see cref="System.Boolean" /> value into output stream. |
||||
/// </summary> |
||||
/// <param name="value">The value.</param> |
||||
public void WriteBoolean(bool value) |
||||
{ |
||||
this._stream.WriteByte(value ? Marker.True : Marker.False); |
||||
} |
||||
|
||||
/// <summary> |
||||
/// Writes array of <see cref="System.Byte" /> into output stream. |
||||
/// </summary> |
||||
/// <param name="buffer">The value.</param> |
||||
public void WriteBytes(byte[] buffer) |
||||
{ |
||||
if (null == buffer) |
||||
{ |
||||
WriteNull(); |
||||
return; |
||||
} |
||||
|
||||
WriteBytes(buffer, 0, buffer.Length); |
||||
} |
||||
|
||||
public void WriteBytes(byte[] buffer, int offset, int count) |
||||
{ |
||||
if (offset < 0) |
||||
{ |
||||
throw new ArgumentException("", nameof(offset)); |
||||
} |
||||
|
||||
if (null == buffer) |
||||
{ |
||||
WriteNull(); |
||||
return; |
||||
} |
||||
|
||||
if (count < 0x10) |
||||
{ |
||||
this._stream.WriteByte((byte)(0x20 + (count & 0x0F))); |
||||
this._stream.Write(buffer, offset, count); |
||||
return; |
||||
} |
||||
|
||||
const int chunkSize = 0x8000; |
||||
|
||||
while (count > chunkSize) |
||||
{ |
||||
this._stream.WriteByte(Marker.BinaryNonfinalChunk); |
||||
this._stream.WriteByte(chunkSize >> 8); |
||||
this._stream.WriteByte(chunkSize & 0xFF); |
||||
this._stream.Write(buffer, offset, chunkSize); |
||||
|
||||
count -= chunkSize; |
||||
offset += chunkSize; |
||||
} |
||||
|
||||
this._stream.WriteByte(Marker.BinaryFinalChunk); |
||||
this._stream.WriteByte((byte)(count >> 8)); |
||||
this._stream.WriteByte((byte)(count & 0xFF)); |
||||
this._stream.Write(buffer, offset, count); |
||||
} |
||||
|
||||
public void WriteDateTime(DateTime value) |
||||
{ |
||||
if (value.Second == 0) |
||||
{ |
||||
var s = value.GetTotalMinutes(); |
||||
|
||||
this._stream.WriteByte(Marker.DateTimeCompact); |
||||
this._stream.WriteByte((byte)(s >> 24)); |
||||
this._stream.WriteByte((byte)(s >> 16)); |
||||
this._stream.WriteByte((byte)(s >> 8)); |
||||
this._stream.WriteByte((byte)s); |
||||
|
||||
return; |
||||
} |
||||
|
||||
var dt = value.GetTotalMilliseconds(); |
||||
|
||||
this._stream.WriteByte(Marker.DateTimeLong); |
||||
this._stream.WriteByte((byte)(dt >> 56)); |
||||
this._stream.WriteByte((byte)(dt >> 48)); |
||||
this._stream.WriteByte((byte)(dt >> 40)); |
||||
this._stream.WriteByte((byte)(dt >> 32)); |
||||
this._stream.WriteByte((byte)(dt >> 24)); |
||||
this._stream.WriteByte((byte)(dt >> 16)); |
||||
this._stream.WriteByte((byte)(dt >> 8)); |
||||
this._stream.WriteByte((byte)dt); |
||||
} |
||||
|
||||
public void WriteDouble(double value) |
||||
{ |
||||
if (value.Equals(0.0d)) |
||||
{ |
||||
this._stream.WriteByte(Marker.DoubleZero); |
||||
return; |
||||
} |
||||
|
||||
if (value.Equals(1.0d)) |
||||
{ |
||||
this._stream.WriteByte(Marker.DoubleOne); |
||||
return; |
||||
} |
||||
|
||||
var fraction = Math.Abs(value - Math.Truncate(value)); |
||||
|
||||
if (Double.Epsilon >= fraction) |
||||
{ |
||||
if (Byte.MinValue <= value && value <= Byte.MaxValue) |
||||
{ |
||||
this._stream.WriteByte(Marker.DoubleOctet); |
||||
this._stream.WriteByte(Convert.ToByte(value)); |
||||
|
||||
return; |
||||
} |
||||
|
||||
if (Int16.MinValue <= value && value <= Int16.MaxValue) |
||||
{ |
||||
var val = Convert.ToInt16(value); |
||||
|
||||
this._stream.WriteByte(Marker.DoubleShort); |
||||
this._stream.WriteByte((byte)(val >> 8)); |
||||
this._stream.WriteByte((byte)val); |
||||
|
||||
return; |
||||
} |
||||
} |
||||
|
||||
if (Single.MinValue <= value && value <= Single.MaxValue) |
||||
{ |
||||
var bytes = BitConverter.GetBytes((float) value); |
||||
|
||||
this._stream.WriteByte(Marker.DoubleFloat); |
||||
|
||||
for (var index = bytes.Length - 1; index >= 0; index--) |
||||
{ |
||||
this._stream.WriteByte(bytes[index]); |
||||
} |
||||
|
||||
return; |
||||
} |
||||
|
||||
var temp = BitConverter.DoubleToInt64Bits(value); |
||||
|
||||
this._stream.WriteByte(Marker.Double); |
||||
|
||||
for (var index = 56; index >= 0; index -= 8) |
||||
{ |
||||
this._stream.WriteByte((byte) (temp >> index)); |
||||
} |
||||
} |
||||
|
||||
public void WriteInt32(int value) |
||||
{ |
||||
if (-16 <= value && value < 48) |
||||
{ |
||||
this._stream.WriteByte((byte)(0x90 + value)); |
||||
} |
||||
else if (-2048 <= value && value < 2048) |
||||
{ |
||||
this._stream.WriteByte((byte)(0xC8 + (byte)(value >> 8))); |
||||
this._stream.WriteByte((byte)value); |
||||
} |
||||
else if (-262144 <= value && value < 262144) |
||||
{ |
||||
this._stream.WriteByte((byte)(0xD4 + (byte)(value >> 16))); |
||||
this._stream.WriteByte((byte)(value >> 8)); |
||||
this._stream.WriteByte((byte)value); |
||||
} |
||||
else |
||||
{ |
||||
this._stream.WriteByte(Marker.UnpackedInteger); |
||||
this._stream.WriteByte((byte)(value >> 24)); |
||||
this._stream.WriteByte((byte)(value >> 16)); |
||||
this._stream.WriteByte((byte)(value >> 8)); |
||||
this._stream.WriteByte((byte)value); |
||||
} |
||||
} |
||||
|
||||
public void WriteInt64(long value) |
||||
{ |
||||
if (-8 <= value && value < 16) |
||||
{ |
||||
this._stream.WriteByte((byte)(0xE0 + value)); |
||||
} |
||||
else if (-2048 <= value && value < 2048) |
||||
{ |
||||
this._stream.WriteByte((byte)(0xF8 + (byte)(value >> 8))); |
||||
this._stream.WriteByte((byte)value); |
||||
} |
||||
else if (-262144 <= value && value < 262144) |
||||
{ |
||||
this._stream.WriteByte((byte)(0x3C + (byte)(value >> 16))); |
||||
this._stream.WriteByte((byte)(value >> 8)); |
||||
this._stream.WriteByte((byte)value); |
||||
} |
||||
else if (Int32.MinValue <= value && value <= Int32.MaxValue) |
||||
{ |
||||
this._stream.WriteByte(Marker.PackedLong); |
||||
this._stream.WriteByte((byte)(value >> 24)); |
||||
this._stream.WriteByte((byte)(value >> 16)); |
||||
this._stream.WriteByte((byte)(value >> 8)); |
||||
this._stream.WriteByte((byte)value); |
||||
} |
||||
else |
||||
{ |
||||
this._stream.WriteByte(Marker.UnpackedLong); |
||||
this._stream.WriteByte((byte)(value >> 56)); |
||||
this._stream.WriteByte((byte)(value >> 48)); |
||||
this._stream.WriteByte((byte)(value >> 40)); |
||||
this._stream.WriteByte((byte)(value >> 32)); |
||||
this._stream.WriteByte((byte)(value >> 24)); |
||||
this._stream.WriteByte((byte)(value >> 16)); |
||||
this._stream.WriteByte((byte)(value >> 8)); |
||||
this._stream.WriteByte((byte)value); |
||||
} |
||||
} |
||||
|
||||
public void WriteString(string value) |
||||
{ |
||||
if (string.IsNullOrEmpty(value)) |
||||
{ |
||||
this._stream.WriteByte(0x00); |
||||
return; |
||||
} |
||||
|
||||
var length = value.Length; |
||||
|
||||
if (1024 > length) |
||||
{ |
||||
var bytes = Encoding.UTF8.GetBytes(value.ToCharArray()); |
||||
|
||||
if (32 > length) |
||||
{ |
||||
this._stream.WriteByte((byte) length); |
||||
} |
||||
else |
||||
{ |
||||
this._stream.WriteByte((byte) (0x30 + (byte) (length >> 8))); |
||||
this._stream.WriteByte((byte) length); |
||||
} |
||||
|
||||
this._stream.Write(bytes, 0, bytes.Length); |
||||
|
||||
return; |
||||
} |
||||
|
||||
const int maxChunkLength = 1024; |
||||
var position = 0; |
||||
|
||||
while (position < length) |
||||
{ |
||||
var count = Math.Min(length - position, maxChunkLength); |
||||
var final = length == (position + count); |
||||
var chunk = value.Substring(position, count); |
||||
var bytes = Encoding.UTF8.GetBytes(chunk.ToCharArray()); |
||||
|
||||
this._stream.WriteByte(final ? Marker.StringFinalChunk : Marker.StringNonfinalChunk); |
||||
this._stream.WriteByte((byte)(count >> 8)); |
||||
this._stream.WriteByte((byte)count); |
||||
this._stream.Write(bytes, 0, bytes.Length); |
||||
|
||||
position += count; |
||||
} |
||||
} |
||||
|
||||
public void BeginClassDefinition() |
||||
{ |
||||
this._stream.WriteByte(Marker.ClassDefinition); |
||||
} |
||||
|
||||
public void EndClassDefinition() |
||||
{ |
||||
} |
||||
|
||||
public void WriteObjectReference(int index) |
||||
{ |
||||
if (index < 0x10) |
||||
{ |
||||
this._stream.WriteByte((byte)(0x60 + index)); |
||||
} |
||||
else |
||||
{ |
||||
this._stream.WriteByte(Marker.ClassReference); |
||||
WriteInt32(index); |
||||
} |
||||
} |
||||
|
||||
public void WriteInstanceReference(int index) |
||||
{ |
||||
this._stream.WriteByte(Marker.InstanceReference); |
||||
WriteInt32(index); |
||||
} |
||||
|
||||
|
||||
private static bool IsSimpleType(TypeInfo typeInfo) |
||||
{ |
||||
if (typeInfo.IsValueType || typeInfo.IsEnum || typeInfo.IsPrimitive) |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
if (typeof (String) == typeInfo.AsType()) |
||||
{ |
||||
return true; |
||||
} |
||||
|
||||
return false; |
||||
} |
||||
|
||||
private static bool IsListType(TypeInfo typeInfo) |
||||
{ |
||||
return typeof(ICollection).IsAssignableFrom(typeInfo); |
||||
} |
||||
} |
||||
} |
||||
@ -1,39 +0,0 @@ |
||||
using System; |
||||
using System.IO; |
||||
using System.Text; |
||||
|
||||
namespace Hessian |
||||
{ |
||||
public static class StringBuilderExtensions |
||||
{ |
||||
public static StringBuilder AppendCodepoint(this StringBuilder sb, uint codepoint) |
||||
{ |
||||
if (codepoint < 0x10000) { |
||||
return sb.Append((char)codepoint); |
||||
} |
||||
|
||||
var n = codepoint - 0x10000; |
||||
var high = (char)((n >> 10) + 0xD800); |
||||
var low = (char)((n & 0x3FF) + 0xDC00); |
||||
|
||||
AssertValidSurrogates(high, low); |
||||
|
||||
return sb |
||||
.Append (high) |
||||
.Append (low); |
||||
} |
||||
|
||||
[System.Diagnostics.Conditional("DEBUG")] |
||||
private static void AssertValidSurrogates (char high, char low) |
||||
{ |
||||
if (!Char.IsHighSurrogate (high)) { |
||||
throw new InvalidDataException ("Invalid high surrogate"); |
||||
} |
||||
|
||||
if (!Char.IsLowSurrogate (low)) { |
||||
throw new InvalidDataException ("Invalid low surrogate"); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -1,163 +0,0 @@ |
||||
using System; |
||||
using System.IO; |
||||
|
||||
namespace Hessian |
||||
{ |
||||
public class ValueReader |
||||
{ |
||||
private byte[] buffer = new byte[8]; |
||||
private PeekStream stream; |
||||
|
||||
public ValueReader (Stream stream) |
||||
{ |
||||
this.stream = stream as PeekStream ?? new PeekStream(stream); |
||||
} |
||||
|
||||
public byte? Peek () |
||||
{ |
||||
return stream.Peek (); |
||||
} |
||||
|
||||
public short ReadShort () |
||||
{ |
||||
Read (buffer, 0, 2); |
||||
return BitConverter.ToInt16(buffer, 0); |
||||
} |
||||
|
||||
public int ReadInt() |
||||
{ |
||||
Read (buffer, 0, 4); |
||||
return BitConverter.ToInt32(buffer, 0); |
||||
} |
||||
|
||||
public uint ReadUtf8Codepoint () |
||||
{ |
||||
const uint replacementChar = 0xFFFD; |
||||
|
||||
byte b0, b1, b2, b3; |
||||
b0 = ReadByte (); |
||||
|
||||
if (b0 < 0x80) { |
||||
return b0; |
||||
} |
||||
|
||||
if (b0 < 0xC2) { |
||||
return replacementChar; |
||||
} |
||||
|
||||
if (b0 < 0xE0) { |
||||
b1 = ReadByte (); |
||||
|
||||
if ((b1 ^ 0x80) >= 0x40) { |
||||
return replacementChar; |
||||
} |
||||
|
||||
return (b1 & 0x3Fu) | ((b0 & 0x1Fu) << 6); |
||||
} |
||||
|
||||
if (b0 < 0xF0) { |
||||
b1 = ReadByte (); |
||||
b2 = ReadByte (); |
||||
|
||||
// Valid range: E0 A0..BF 80..BF |
||||
if (b0 == 0xE0 && (b1 ^ 0xA0) >= 0x20) { |
||||
return replacementChar; |
||||
} |
||||
|
||||
// Valid range: ED 80..9F 80..BF |
||||
if (b0 == 0xED && (b1 ^ 0x80) >= 0x20) { |
||||
return replacementChar; |
||||
} |
||||
|
||||
// Valid range: E1..EC 80..BF 80..BF |
||||
if ((b1 ^ 0x80) >= 0x40 || (b2 ^ 0x80) >= 0x40) { |
||||
return replacementChar; |
||||
} |
||||
|
||||
return (b2 & 0x3Fu) |
||||
| ((b1 & 0x3Fu) << 6) |
||||
| ((b0 & 0x0Fu) << 12); |
||||
} |
||||
|
||||
if (b0 < 0xF1) { |
||||
b1 = ReadByte(); |
||||
|
||||
if ((b1 ^ 0x90) < 0x30) { |
||||
return replacementChar; |
||||
} |
||||
|
||||
b2 = ReadByte(); |
||||
b3 = ReadByte(); |
||||
|
||||
if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) { |
||||
return replacementChar; |
||||
} |
||||
|
||||
return (b3 & 0x3Fu) |
||||
| ((b2 & 0x3Fu) << 6) |
||||
| ((b1 & 0x3Fu) << 12) |
||||
| ((b0 & 0x07u) << 18); |
||||
} |
||||
|
||||
if (b0 < 0xF4) { |
||||
b1 = ReadByte (); |
||||
b2 = ReadByte (); |
||||
b3 = ReadByte (); |
||||
|
||||
// Valid range: F1..F3 80..BF 80..BF 80..BF |
||||
if ((b1 & 0xC0) != 0x80 || (b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) |
||||
{ |
||||
return replacementChar; |
||||
} |
||||
|
||||
return (b3 & 0x3Fu) |
||||
| ((b2 & 0x3Fu) << 6) |
||||
| ((b1 & 0x3Fu) << 12) |
||||
| ((b0 & 0x07u) << 18); |
||||
} |
||||
|
||||
if (b0 < 0xF5) { |
||||
b1 = ReadByte (); |
||||
|
||||
// Valid range: F4 80..8F 80..BF 80..BF |
||||
if ((b1 ^ 0x80) >= 0x10) { |
||||
return replacementChar; |
||||
} |
||||
|
||||
b2 = ReadByte(); |
||||
b3 = ReadByte(); |
||||
|
||||
if ((b2 & 0xC0) != 0x80 || (b3 & 0xC0) != 0x80) |
||||
{ |
||||
return replacementChar; |
||||
} |
||||
|
||||
return (b3 & 0x3Fu) |
||||
| ((b2 & 0x3Fu) << 6) |
||||
| ((b1 & 0x3Fu) << 12) |
||||
| ((b0 & 0x07u) << 18); |
||||
} |
||||
|
||||
return replacementChar; |
||||
} |
||||
|
||||
public byte ReadByte() |
||||
{ |
||||
var b = stream.ReadByte(); |
||||
if (b == -1) throw new EndOfStreamException(); |
||||
return (byte)b; |
||||
} |
||||
|
||||
public void Read(byte[] buffer, int count) |
||||
{ |
||||
Read (buffer, 0, count); |
||||
} |
||||
|
||||
private void Read(byte[] buffer, int offset, int count) |
||||
{ |
||||
var bytesRead = stream.Read (buffer, offset, count); |
||||
if (bytesRead != count) throw new EndOfStreamException(); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@ -1,13 +0,0 @@ |
||||
using System; |
||||
using Xunit; |
||||
|
||||
namespace Hessian.Tests |
||||
{ |
||||
public class UnitTest1 |
||||
{ |
||||
[Fact] |
||||
public void Test1() |
||||
{ |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue