协议改进

pull/1/head
wangshaoming 7 years ago
parent aa35e4b6a6
commit 6bd8ee846c
No known key found for this signature in database
GPG Key ID: 29F5223B4DB362B5
  1. 47
      DotXxlJob.sln
  2. BIN
      samples/ASPNetCoreExecutor/1547620263.dat
  3. BIN
      samples/ASPNetCoreExecutor/1547621183.dat
  4. 16
      samples/ASPNetCoreExecutor/ASPNetCoreExecutor.csproj
  5. 12
      samples/ASPNetCoreExecutor/ApplicationBuilderExtensions.cs
  6. 24
      samples/ASPNetCoreExecutor/Program.cs
  7. 27
      samples/ASPNetCoreExecutor/Properties/launchSettings.json
  8. 29
      samples/ASPNetCoreExecutor/Startup.cs
  9. 41
      samples/ASPNetCoreExecutor/XxlJobExecutorMiddleware.cs
  10. 9
      samples/ASPNetCoreExecutor/appsettings.Development.json
  11. 8
      samples/ASPNetCoreExecutor/appsettings.json
  12. BIN
      samples/HessianReader/1547620263.dat
  13. BIN
      samples/HessianReader/1547621183.dat
  14. 19
      samples/HessianReader/HessianReader.csproj
  15. 133
      samples/HessianReader/Program.cs
  16. 12
      src/DotXxlJob.Core/CallbackTaskQueue.cs
  17. 27
      src/DotXxlJob.Core/Config/XxlJobExecutorOptions.cs
  18. 42
      src/DotXxlJob.Core/Constants.cs
  19. 35
      src/DotXxlJob.Core/DateTimeExtensions.cs
  20. 10
      src/DotXxlJob.Core/DefaultJobHandlerFactory.cs
  21. 4
      src/DotXxlJob.Core/DotXxlJob.Core.csproj
  22. 7
      src/DotXxlJob.Core/ExecutorRegistry.cs
  23. 18
      src/DotXxlJob.Core/HttpJobHandler.cs
  24. 6
      src/DotXxlJob.Core/IJobHandler.cs
  25. 12
      src/DotXxlJob.Core/ITaskExecutor.cs
  26. 15
      src/DotXxlJob.Core/IXxlJobExecutor.cs
  27. 130
      src/DotXxlJob.Core/JobDispatcher.cs
  28. 2
      src/DotXxlJob.Core/JobLogger.cs
  29. 7
      src/DotXxlJob.Core/LogResult.cs
  30. 10
      src/DotXxlJob.Core/Model/CallbackParam.cs
  31. 11
      src/DotXxlJob.Core/Model/HessianArrayList.cs
  32. 7
      src/DotXxlJob.Core/Model/JobExecuteContext.cs
  33. 42
      src/DotXxlJob.Core/Model/ReturnT.cs
  34. 44
      src/DotXxlJob.Core/Model/RpcRequest.cs
  35. 11
      src/DotXxlJob.Core/Model/RpcResponse.cs
  36. 38
      src/DotXxlJob.Core/Model/TriggerParam.cs
  37. 11
      src/DotXxlJob.Core/ReturnT.cs
  38. 20
      src/DotXxlJob.Core/ServiceCollectionExtensions.cs
  39. 35
      src/DotXxlJob.Core/TaskExecutorFactory.cs
  40. 34
      src/DotXxlJob.Core/TaskExecutors/BeanTaskExecutor.cs
  41. 116
      src/DotXxlJob.Core/TaskQueue.cs
  42. 212
      src/DotXxlJob.Core/XxlRpcServiceHandler.cs
  43. 50
      src/Hessian.NET/HessianInputReader.cs
  44. 18
      src/Hessian.NET/HessianSerializationScheme.cs
  45. 10
      src/Hessian.NET/LeadingByte.cs
  46. 167
      src/Hessian.NET/ListElement.cs
  47. 13
      src/Hessian.NET/ListPreamble.cs
  48. 13
      src/Hessian.NET/Marker.cs
  49. 5
      src/Hessian.NET/ObjectElement.cs
  50. 9
      src/Hessian.NET/ObjectPreamble.cs
  51. 59
      src/Hessian/ClassDef.cs
  52. 91
      src/Hessian/Collections/ForwardingDictionary.cs
  53. 32
      src/Hessian/Collections/IRefMap.cs
  54. 59
      src/Hessian/Collections/ITwoWayDictionary.cs
  55. 34
      src/Hessian/Collections/ListRefMap.cs
  56. 123
      src/Hessian/Collections/TwoWayDictionary.cs
  57. 34
      src/Hessian/Collections/TwoWayDictionaryRefMap.cs
  58. 114
      src/Hessian/Conditions.cs
  59. 892
      src/Hessian/Deserializer.cs
  60. 46
      src/Hessian/DictionaryTypeResolver.cs
  61. 7
      src/Hessian/Hessian.csproj
  62. 24
      src/Hessian/HessianException.cs
  63. 75
      src/Hessian/HessianObject.cs
  64. 15
      src/Hessian/InvalidRefException.cs
  65. 66
      src/Hessian/ListTypeResolver.cs
  66. 24
      src/Hessian/Main.cs
  67. 142
      src/Hessian/PeekStream.cs
  68. 25
      src/Hessian/Platform/BigEndianBitConverter.cs
  69. 215
      src/Hessian/Platform/EndianBitConverter.cs
  70. 25
      src/Hessian/Platform/LittleEndianBitConverter.cs
  71. 39
      src/Hessian/StringBuilderExtensions.cs
  72. 18
      src/Hessian/UnexpectedTagException.cs
  73. 163
      src/Hessian/ValueReader.cs

@ -13,6 +13,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{352EC932
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hessian.NET.Tests", "tests\Hessian.NET.Tests\Hessian.NET.Tests.csproj", "{187B28C7-C3D7-4E0A-A84B-98B7C1C758F9}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "samples", "samples", "{E959F9B5-F3EB-48B1-B842-2CDDFDB01900}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ASPNetCoreExecutor", "samples\ASPNetCoreExecutor\ASPNetCoreExecutor.csproj", "{DC9E5AF3-18FF-4713-BDB4-672E47ADA4E5}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "HessianReader", "samples\HessianReader\HessianReader.csproj", "{F822B528-95FD-40B4-9EE0-3AE8878075AC}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Hessian", "src\Hessian\Hessian.csproj", "{BD9B8108-6528-430F-AD28-6F8434A29F55}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -29,6 +37,9 @@ Global
{FFFEEA78-CB09-4BFB-89B7-E9A46EC3ED65} = {97756BA5-1E7C-4536-A49E-AE2190C0E6A5}
{86456232-19D5-48DD-AC39-A0526517E0AD} = {97756BA5-1E7C-4536-A49E-AE2190C0E6A5}
{187B28C7-C3D7-4E0A-A84B-98B7C1C758F9} = {352EC932-F112-4A2F-9DC3-F0761C85E068}
{DC9E5AF3-18FF-4713-BDB4-672E47ADA4E5} = {E959F9B5-F3EB-48B1-B842-2CDDFDB01900}
{F822B528-95FD-40B4-9EE0-3AE8878075AC} = {E959F9B5-F3EB-48B1-B842-2CDDFDB01900}
{BD9B8108-6528-430F-AD28-6F8434A29F55} = {97756BA5-1E7C-4536-A49E-AE2190C0E6A5}
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{FFFEEA78-CB09-4BFB-89B7-E9A46EC3ED65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
@ -67,5 +78,41 @@ Global
{187B28C7-C3D7-4E0A-A84B-98B7C1C758F9}.Release|x64.Build.0 = Release|Any CPU
{187B28C7-C3D7-4E0A-A84B-98B7C1C758F9}.Release|x86.ActiveCfg = Release|Any CPU
{187B28C7-C3D7-4E0A-A84B-98B7C1C758F9}.Release|x86.Build.0 = Release|Any CPU
{DC9E5AF3-18FF-4713-BDB4-672E47ADA4E5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DC9E5AF3-18FF-4713-BDB4-672E47ADA4E5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DC9E5AF3-18FF-4713-BDB4-672E47ADA4E5}.Debug|x64.ActiveCfg = Debug|Any CPU
{DC9E5AF3-18FF-4713-BDB4-672E47ADA4E5}.Debug|x64.Build.0 = Debug|Any CPU
{DC9E5AF3-18FF-4713-BDB4-672E47ADA4E5}.Debug|x86.ActiveCfg = Debug|Any CPU
{DC9E5AF3-18FF-4713-BDB4-672E47ADA4E5}.Debug|x86.Build.0 = Debug|Any CPU
{DC9E5AF3-18FF-4713-BDB4-672E47ADA4E5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DC9E5AF3-18FF-4713-BDB4-672E47ADA4E5}.Release|Any CPU.Build.0 = Release|Any CPU
{DC9E5AF3-18FF-4713-BDB4-672E47ADA4E5}.Release|x64.ActiveCfg = Release|Any CPU
{DC9E5AF3-18FF-4713-BDB4-672E47ADA4E5}.Release|x64.Build.0 = Release|Any CPU
{DC9E5AF3-18FF-4713-BDB4-672E47ADA4E5}.Release|x86.ActiveCfg = Release|Any CPU
{DC9E5AF3-18FF-4713-BDB4-672E47ADA4E5}.Release|x86.Build.0 = Release|Any CPU
{F822B528-95FD-40B4-9EE0-3AE8878075AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F822B528-95FD-40B4-9EE0-3AE8878075AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F822B528-95FD-40B4-9EE0-3AE8878075AC}.Debug|x64.ActiveCfg = Debug|Any CPU
{F822B528-95FD-40B4-9EE0-3AE8878075AC}.Debug|x64.Build.0 = Debug|Any CPU
{F822B528-95FD-40B4-9EE0-3AE8878075AC}.Debug|x86.ActiveCfg = Debug|Any CPU
{F822B528-95FD-40B4-9EE0-3AE8878075AC}.Debug|x86.Build.0 = Debug|Any CPU
{F822B528-95FD-40B4-9EE0-3AE8878075AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F822B528-95FD-40B4-9EE0-3AE8878075AC}.Release|Any CPU.Build.0 = Release|Any CPU
{F822B528-95FD-40B4-9EE0-3AE8878075AC}.Release|x64.ActiveCfg = Release|Any CPU
{F822B528-95FD-40B4-9EE0-3AE8878075AC}.Release|x64.Build.0 = Release|Any CPU
{F822B528-95FD-40B4-9EE0-3AE8878075AC}.Release|x86.ActiveCfg = Release|Any CPU
{F822B528-95FD-40B4-9EE0-3AE8878075AC}.Release|x86.Build.0 = Release|Any CPU
{BD9B8108-6528-430F-AD28-6F8434A29F55}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BD9B8108-6528-430F-AD28-6F8434A29F55}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BD9B8108-6528-430F-AD28-6F8434A29F55}.Debug|x64.ActiveCfg = Debug|Any CPU
{BD9B8108-6528-430F-AD28-6F8434A29F55}.Debug|x64.Build.0 = Debug|Any CPU
{BD9B8108-6528-430F-AD28-6F8434A29F55}.Debug|x86.ActiveCfg = Debug|Any CPU
{BD9B8108-6528-430F-AD28-6F8434A29F55}.Debug|x86.Build.0 = Debug|Any CPU
{BD9B8108-6528-430F-AD28-6F8434A29F55}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BD9B8108-6528-430F-AD28-6F8434A29F55}.Release|Any CPU.Build.0 = Release|Any CPU
{BD9B8108-6528-430F-AD28-6F8434A29F55}.Release|x64.ActiveCfg = Release|Any CPU
{BD9B8108-6528-430F-AD28-6F8434A29F55}.Release|x64.Build.0 = Release|Any CPU
{BD9B8108-6528-430F-AD28-6F8434A29F55}.Release|x86.ActiveCfg = Release|Any CPU
{BD9B8108-6528-430F-AD28-6F8434A29F55}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
EndGlobal

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
<AspNetCoreHostingModel>InProcess</AspNetCoreHostingModel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.App" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\DotXxlJob.Core\DotXxlJob.Core.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,12 @@
using Microsoft.AspNetCore.Builder;
namespace ASPNetCoreExecutor
{
public static class ApplicationBuilderExtensions
{
public static IApplicationBuilder UseXxlJobExecutor(this IApplicationBuilder @this)
{
return @this.UseMiddleware<XxlJobExecutorMiddleware>();
}
}
}

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
namespace ASPNetCoreExecutor
{
public class Program
{
public static void Main(string[] args)
{
CreateWebHostBuilder(args).Build().Run();
}
public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.UseStartup<Startup>();
}
}

@ -0,0 +1,27 @@
{
"iisSettings": {
"windowsAuthentication": false,
"anonymousAuthentication": true,
"iisExpress": {
"applicationUrl": "http://localhost:22613",
"sslPort": 44333
}
},
"profiles": {
"IIS Express": {
"commandName": "IISExpress",
"launchBrowser": true,
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
},
"ASPNetCoreExecutor": {
"commandName": "Project",
"launchBrowser": true,
"applicationUrl": "https://localhost:5001;http://localhost:5000",
"environmentVariables": {
"ASPNETCORE_ENVIRONMENT": "Development"
}
}
}
}

@ -0,0 +1,29 @@
using DotXxlJob.Core;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.DependencyInjection;
namespace ASPNetCoreExecutor
{
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddXxlJobExecutor();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
//启用XxlExecutor
app.UseXxlJobExecutor();
}
}
}

@ -0,0 +1,41 @@
using System;
using System.Net;
using System.Threading.Tasks;
using DotXxlJob.Core;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
namespace ASPNetCoreExecutor
{
public class XxlJobExecutorMiddleware
{
private readonly IServiceProvider _provider;
private readonly RequestDelegate _next;
private readonly XxlRpcServiceHandler _rpcService;
public XxlJobExecutorMiddleware(IServiceProvider provider, RequestDelegate next)
{
_provider = provider;
_next = next;
_rpcService = _provider.GetRequiredService<XxlRpcServiceHandler>();
}
public async Task Invoke(HttpContext context)
{
if ("POST".Equals(context.Request.Method, StringComparison.OrdinalIgnoreCase) &&
"application/octet-stream".Equals(context.Request.ContentType, StringComparison.OrdinalIgnoreCase))
{
var rsp = await _rpcService.HandlerAsync(context.Request.Body);
context.Response.StatusCode = (int) HttpStatusCode.OK;
context.Response.ContentType = "text/plain;utf-8";
await context.Response.Body.WriteAsync(rsp,0,rsp.Length);
}
await _next.Invoke(context);
}
}
}

@ -0,0 +1,9 @@
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"System": "Information",
"Microsoft": "Information"
}
}
}

@ -0,0 +1,8 @@
{
"Logging": {
"LogLevel": {
"Default": "Warning"
}
},
"AllowedHosts": "*"
}

@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\DotXxlJob.Core\DotXxlJob.Core.csproj" />
<ProjectReference Include="..\..\src\Hessian\Hessian.csproj" />
</ItemGroup>
<ItemGroup>
<Reference Include="Newtonsoft.Json, Version=11.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed">
<HintPath>C:\Program Files\dotnet\sdk\NuGetFallbackFolder\newtonsoft.json\11.0.2\lib\netstandard2.0\Newtonsoft.Json.dll</HintPath>
</Reference>
</ItemGroup>
</Project>

@ -0,0 +1,133 @@
using System;
using System.Collections;
using System.IO;
using DotXxlJob.Core.Model;
using Hessian.Net;
using Newtonsoft.Json;
namespace HessianReader
{
class Program
{
static void Main(string[] args)
{
byte[] myBinary = File.ReadAllBytes("1547621183.dat");
foreach (var i in myBinary)
{
Console.Write("0x");
Console.Write(i.ToString("x2"));
Console.Write(",");
}
Console.WriteLine(Environment.NewLine);
Console.WriteLine("---------------------------------------------------------------");
var serializer = new DataContractHessianSerializer(typeof (RpcRequest));
using (var stream1 = new MemoryStream(myBinary))
{
var ds = new Hessian.Deserializer(stream1);
Hessian.ClassDef def = ds.ReadClassDefinition();
Console.WriteLine(JsonConvert.SerializeObject(def));
Console.WriteLine(ds.ReadValue());
//Console.WriteLine(ds.ReadLong());
//Console.WriteLine(ds.ReadString());
//Console.WriteLine(ds.ReadString());
//Console.WriteLine(ds.ReadString());
//Console.WriteLine(ds.ReadString());
//Console.WriteLine(ds.ReadValue());
//Console.WriteLine(ds.ReadValue());
Console.WriteLine(JsonConvert.SerializeObject(def));
}
return;
RpcRequest req = new RpcRequest {
RequestId = "71565f61-94e8-4dcf-9760-f2fb73a6886a",
CreateMillisTime = 1547621183585,
AccessToken = "",
ClassName = "com.xxl.job.core.biz.ExecutorBiz",
MethodName = "run",
ParameterTypes = new HessianArrayList {"class com.xxl.job.core.biz.model.TriggerParam"},
Version = "null",
Parameters = new HessianArrayList()
};
var p =new TriggerParam {
JobId=1,
ExecutorHandler="demoJobHandler",
ExecutorParams="111",
ExecutorBlockStrategy="SERIAL_EXECUTION",
ExecutorTimeout=0,
LogId=5,
LogDateTime=1547621183414L,
GlueType="BEAN",
GlueSource="",
GlueUpdateTime=1541254891000,
BroadcastIndex=0,
BroadcastTotal=1
};
req.Parameters.Add(p);
byte[] distArray;
using (MemoryStream stream = new MemoryStream())
{
serializer.WriteObject(stream,req);
//Console.WriteLine(Environment.NewLine);
//Console.WriteLine("---------------------------"+ stream.Length+"------------------------------------");
stream.Flush();
distArray =stream.ToArray();
}
foreach (var j in distArray)
{
Console.Write("0x");
Console.Write(j.ToString("x2"));
Console.Write(",");
}
Console.WriteLine(Environment.NewLine);
Console.WriteLine("---------------------------------------------------------------");
using (var stream2 = new MemoryStream(distArray))
{
var instance = serializer.ReadObject(stream2) as RpcRequest;
Console.WriteLine(JsonConvert.SerializeObject(instance));
}
/**
* requestId='71565f61-94e8-4dcf-9760-f2fb73a6886a',
* createMillisTime=1547621183585,
* accessToken='',
* className='com.xxl.job.core.biz.ExecutorBiz',
* methodName='run',
* parameterTypes=[class com.xxl.job.core.biz.model.TriggerParam],
* parameters=[
* TriggerParam{
* jobId=1,
* executorHandler='demoJobHandler',
* executorParams='111',
* executorBlockStrategy='SERIAL_EXECUTION',
* executorTimeout=0,
* logId=5,
* logDateTim=1547621183414,
* glueType='BEAN',
* glueSource='',
* glueUpdatetime=1541254891000,
* broadcastIndex=0,
* broadcastTotal=1
* }
* ], version='null'
*
*/
}
}
}

@ -0,0 +1,12 @@
using DotXxlJob.Core.Model;
namespace DotXxlJob.Core
{
public class CallbackTaskQueue
{
public void Push(CallbackParam callbackParam)
{
throw new System.NotImplementedException();
}
}
}

@ -0,0 +1,27 @@
namespace DotXxlJob.Core.Config
{
public class XxlJobExecutorOptions
{
public string AdminAddresses { get; set; }
public string AppName { get; set; }
public string SpecialBindAddress { get; set; }
public int Port { get; set; }
public string AccessToken { get; set; }
public string LogPath { get; set; }
public int LogRetentionDays { get; set; }
}
}

@ -0,0 +1,42 @@
using System;
namespace DotXxlJob.Core
{
internal static class Constants
{
public const string XxlLogsDefaultRootDirectory = "xxl-job-logs";
public const string HandleLogsDirectory = "HandlerLogs";
public const string LogFileNameCallContextKey = "XxlJob.LogFileName";
public const int DefaultLogRetentionDays = 30;
public static TimeSpan RpcRequestExpireTimeSpan = TimeSpan.FromMinutes(3);
public const int MaxCallbackRetryTimes = 10;
//每次回调最多发送几条记录
public const int MaxCallbackRecordsPerRequest = 100;
public static TimeSpan CallbackRetryInterval = TimeSpan.FromSeconds(600);
//Admin集群机器请求默认超时时间
public static TimeSpan AdminServerDefaultTimeout = TimeSpan.FromSeconds(15);
//Admin集群中的某台机器熔断后间隔多长时间再重试
public static TimeSpan AdminServerReconnectInterval = TimeSpan.FromMinutes(3);
//Admin集群中的某台机器请求失败多少次后熔断
public const int AdminServerCircuitFaildTimes = 3;
public static TimeSpan JobThreadWaitTime = TimeSpan.FromSeconds(90);
public static class GlueType
{
public const string BEAN = "BEAN";
}
public static class ExecutorBlockStrategy
{
public const string SERIAL_EXECUTION = "SERIAL_EXECUTION";
public const string DISCARD_LATER = "DISCARD_LATER";
public const string COVER_EARLY = "COVER_EARLY";
}
}
}

@ -0,0 +1,35 @@
using System;
namespace DotXxlJob.Core
{
public static class DateTimeExtensions
{
private const long UnixEpochTicks = 621355968000000000;
private const long UnixEpochSeconds = 62135596800;
private const long UnixEpochMilliseconds = 62135596800000;
public static DateTimeOffset FromUnixTimeSeconds(this long seconds)
{
long ticks = seconds * TimeSpan.TicksPerSecond + UnixEpochTicks;
return new DateTime(ticks, DateTimeKind.Utc);
}
public static DateTime FromUnixTimeMilliseconds(this long milliseconds)
{
long ticks = milliseconds * TimeSpan.TicksPerMillisecond + UnixEpochTicks;
return new DateTime(ticks, DateTimeKind.Utc);
}
public static long ToUnixTimeSeconds(this DateTime dateTime)
{
long seconds = dateTime.ToUniversalTime().Ticks / TimeSpan.TicksPerSecond;
return seconds - UnixEpochSeconds;
}
public static long ToUnixTimeMilliseconds(this DateTime dateTime)
{
long milliseconds = dateTime.ToUniversalTime().Ticks / TimeSpan.TicksPerMillisecond;
return milliseconds - UnixEpochMilliseconds;
}
}
}

@ -0,0 +1,10 @@
namespace DotXxlJob.Core
{
public class DefaultJobHandlerFactory:IJobHandlerFactory
{
public IJobHandler GetJobHandler(string handlerName)
{
return new HttpJobHandler();
}
}
}

@ -8,4 +8,8 @@
<PackageReference Include="Microsoft.Extensions.Hosting" Version="2.2.0" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Hessian.NET\Hessian.NET.csproj" />
</ItemGroup>
</Project>

@ -3,8 +3,11 @@ namespace DotXxlJob.Core
/// <summary>
/// 执行器注册注册
/// </summary>
public class ExecutorRegistry
public class ExecutorRegistry:IExecutorRegistry
{
public void Start()
{
throw new System.NotImplementedException();
}
}
}

@ -0,0 +1,18 @@
using System.Threading.Tasks;
using DotXxlJob.Core.Model;
namespace DotXxlJob.Core
{
public class HttpJobHandler:IJobHandler
{
public void Dispose()
{
}
public Task<ReturnT> Execute(JobExecuteContext context)
{
return Task.FromResult(ReturnT.SUCCESS);
}
}
}

@ -1,17 +1,17 @@
using System;
using System.Threading.Tasks;
using DotXxlJob.Core.Model;
namespace DotXxlJob.Core
{
public abstract class AbstractJobHandler:IJobHandler
{
/// <summary>
///
/// </summary>
/// <param name="param"></param>
/// <returns></returns>
public abstract Task<ReturnT<string>> Execute(string param);
public abstract Task<ReturnT> Execute(JobExecuteContext context);
public virtual void Dispose()
@ -21,6 +21,6 @@ namespace DotXxlJob.Core
public interface IJobHandler:IDisposable
{
Task<ReturnT<string>> Execute(string param);
Task<ReturnT> Execute(JobExecuteContext context);
}
}

@ -0,0 +1,12 @@
using System.Threading.Tasks;
using DotXxlJob.Core.Model;
namespace DotXxlJob.Core
{
public interface ITaskExecutor
{
string GlueType { get; }
Task<ReturnT> Execute(TriggerParam triggerParam);
}
}

@ -1,7 +1,20 @@
using DotXxlJob.Core.Model;
namespace DotXxlJob.Core
{
public interface IXxlJobExecutor
{
ReturnT Beat();
ReturnT IdleBeat(int jobId);
ReturnT Kill(int jobId);
ReturnT Log(long logDateTim, int logId, int fromLineNum);
ReturnT Run(TriggerParam triggerParam);
}
}

@ -0,0 +1,130 @@
using System;
using System.Collections.Concurrent;
using DotXxlJob.Core.Model;
using Microsoft.Extensions.Logging;
namespace DotXxlJob.Core
{
/// <summary>
/// 负责实际的JOB轮询
/// </summary>
public class JobDispatcher
{
private readonly TaskExecutorFactory _executorFactory;
private readonly CallbackTaskQueue _callbackTaskQueue;
private readonly ConcurrentDictionary<int,JobQueue> RUNNING_QUEUE = new ConcurrentDictionary<int, JobQueue>();
private readonly ILogger<JobQueue> _jobQueueLogger;
private readonly ILogger<JobDispatcher> _logger;
public JobDispatcher(
TaskExecutorFactory executorFactory,
CallbackTaskQueue callbackTaskQueue,
ILoggerFactory loggerFactory
)
{
this. _executorFactory = executorFactory;
this. _callbackTaskQueue = callbackTaskQueue;
this._jobQueueLogger = loggerFactory.CreateLogger<JobQueue>();
this._logger = loggerFactory.CreateLogger<JobDispatcher>();
}
/// <summary>
/// 尝试移除JobTask
/// </summary>
/// <param name="jobId"></param>
/// <param name="reason"></param>
/// <returns></returns>
public bool TryRemoveJobTask(int jobId)
{
if (RUNNING_QUEUE.TryGetValue(jobId, out var jobQueue))
{
jobQueue.Stop();
return true;
}
return false;
}
/// <summary>
/// 执行队列,并快速返回结果
/// </summary>
/// <param name="triggerParam"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public ReturnT Execute(TriggerParam triggerParam)
{
var executor = this._executorFactory.GetTaskExecutor(triggerParam.GlueType);
if (executor == null)
{
return ReturnT.Failed($"glueType[{triggerParam.GlueType}] is not supported ");
}
// 1. 根据JobId 获取 TaskQueue; 用于判断是否有正在执行的任务
if (RUNNING_QUEUE.TryGetValue(triggerParam.JobId, out var taskQueue))
{
if (taskQueue.Executor != executor) //任务执行器变更
{
return ChangeJobQueue(triggerParam, executor);
}
}
if (taskQueue != null) //旧任务还在执行,判断执行策略
{
//丢弃后续的
if (Constants.ExecutorBlockStrategy.DISCARD_LATER == triggerParam.ExecutorBlockStrategy)
{
return ReturnT.Failed($"block strategy effect:{triggerParam.ExecutorBlockStrategy}");
}
//覆盖较早的
if (Constants.ExecutorBlockStrategy.COVER_EARLY == triggerParam.ExecutorBlockStrategy)
{
return taskQueue.Replace(triggerParam);
}
}
return PushJobQueue(triggerParam, executor);
}
/// <summary>
/// 等待检查
/// </summary>
/// <param name="jobId"></param>
/// <returns></returns>
public ReturnT IdleBeat(int jobId)
{
return RUNNING_QUEUE.ContainsKey(jobId) ?
new ReturnT(ReturnT.FAIL_CODE, "job thread is running or has trigger queue.")
: ReturnT.SUCCESS;
}
private ReturnT PushJobQueue(TriggerParam triggerParam, ITaskExecutor executor)
{
JobQueue jobQueue = new JobQueue ( executor, this._callbackTaskQueue,this._jobQueueLogger);
if (RUNNING_QUEUE.TryAdd(triggerParam.JobId, jobQueue))
{
jobQueue.Push(triggerParam);
}
return ReturnT.Failed("add running queue executor error");
}
private ReturnT ChangeJobQueue(TriggerParam triggerParam, ITaskExecutor executor)
{
JobQueue jobQueue = new JobQueue ( executor, this._callbackTaskQueue,this._jobQueueLogger);
if (RUNNING_QUEUE.TryUpdate(triggerParam.JobId, jobQueue, null))
{
return jobQueue.Push(triggerParam);
}
return ReturnT.Failed(" replace running queue executor error");
}
}
}

@ -1,6 +1,6 @@
namespace DotXxlJob.Core
{
public class TaskExcutor
public class JobLogger
{
}

@ -0,0 +1,7 @@
namespace DotXxlJob.Core
{
public class LogResult
{
}
}

@ -0,0 +1,10 @@
namespace DotXxlJob.Core.Model
{
public class CallbackParam
{
public CallbackParam(TriggerParam triggerParam, ReturnT result)
{
throw new System.NotImplementedException();
}
}
}

@ -0,0 +1,11 @@
using System.Collections.Generic;
using System.Runtime.Serialization;
namespace DotXxlJob.Core.Model
{
[DataContract(Name = "hessianArrayList")]
public class HessianArrayList:List<object>
{
}
}

@ -0,0 +1,7 @@
namespace DotXxlJob.Core.Model
{
public class JobExecuteContext
{
}
}

@ -0,0 +1,42 @@
using System.Runtime.Serialization;
namespace DotXxlJob.Core
{
[DataContract]
public class ReturnT
{
public const int SUCCESS_CODE = 200;
public const int FAIL_CODE = 500;
public static readonly ReturnT SUCCESS = new ReturnT(SUCCESS_CODE, null);
public static readonly ReturnT FAIL = new ReturnT(FAIL_CODE, null);
public static readonly ReturnT FAIL_TIMEOUT = new ReturnT(502, null);
[DataMember(Name = "code",Order = 1)]
public int Code { get; set; }
[DataMember(Name = "msg",Order = 2)]
public string Msg { get; set; }
public ReturnT() { }
public ReturnT(int code, string msg)
{
this.Code = code;
this.Msg = msg;
}
public static ReturnT Failed(string msg)
{
return new ReturnT(FAIL_CODE, msg);
}
public static ReturnT Success(string msg)
{
return new ReturnT(SUCCESS_CODE, msg);
}
[DataMember(Name = "content",Order = 3)]
public object Content { get; set; }
}
}

@ -1,7 +1,51 @@
using System.Collections;
using System.Collections.Specialized;
using System.Runtime.Serialization;
namespace DotXxlJob.Core.Model
{
[DataContract(Name = "com.xxl.rpc.remoting.net.params.XxlRpcRequest")]
public class RpcRequest
{
/*
requestId
createMillisTime
accessToken
className
methodName
version
parameterTypes
parameters
*/
[DataMember(Name = "requestId",Order = 1)]
public string RequestId { get; set; }
//[DataMember(Name = "serverAddress")]
//public string ServerAddress{ get; set; }
[DataMember(Name = "createMillisTime" ,Order = 2)]
public long CreateMillisTime{ get; set; }
[DataMember(Name = "accessToken" ,Order = 3)]
public string AccessToken{ get; set; }
[DataMember(Name = "className" ,Order = 4)]
public string ClassName{ get; set; }
[DataMember(Name = "methodName" ,Order = 5)]
public string MethodName{ get; set; }
[DataMember(Name = "version" ,Order = 6)]
public string Version{ get; set; }
[DataMember(Name = "parameterTypes",Order = 7)]
public HessianArrayList ParameterTypes{ get; set; }
[DataMember(Name = "parameters",Order = 8)]
public HessianArrayList Parameters{ get; set; }
}
}

@ -1,7 +1,18 @@
using System.Runtime.Serialization;
namespace DotXxlJob.Core.Model
{
[DataContract(Name = "com.xxl.rpc.remoting.net.params.XxlRpcResponse")]
public class RpcResponse
{
[DataMember(Name = "requestId",Order = 1)]
public string RequestId{ get; set; }
[DataMember(Name = "errorMsg",Order = 2)]
public string ErrorMsg;
[DataMember(Name = "result",Order = 3)]
public object Result{ get; set; }
public bool IsError => this.ErrorMsg != null;
}
}

@ -1,7 +1,45 @@
using System.Runtime.Serialization;
namespace DotXxlJob.Core.Model
{
[DataContract(Name = "triggerParam")]
public class TriggerParam
{
static readonly long SerialVersionUID = 42L;
[DataMember(Name = "jobId")]
public int JobId { get; set; }
[DataMember(Name = "executorHandler")]
public string ExecutorHandler { get; set; }
[DataMember(Name = "executorParams")]
public string ExecutorParams{ get; set; }
[DataMember(Name = "executorBlockStrategy")]
public string ExecutorBlockStrategy{ get; set; }
[DataMember(Name = "executorTimeout")]
public int ExecutorTimeout{ get; set; }
[DataMember(Name = "logId")]
public int LogId{ get; set; }
[DataMember(Name = "logDateTim")]
public long LogDateTime{ get; set; }
[DataMember(Name = "glueType")]
public string GlueType{ get; set; }
[DataMember(Name = "glueSource")]
public string GlueSource{ get; set; }
[DataMember(Name = "glueUpdatetime")]
public long GlueUpdateTime{ get; set; }
[DataMember(Name = "broadcastIndex")]
public int BroadcastIndex{ get; set; }
[DataMember(Name = "broadcastTotal")]
public int BroadcastTotal{ get; set; }
}
}

@ -1,11 +0,0 @@
namespace DotXxlJob.Core
{
public class ReturnT<T>
{
public int Code { get; set; }
public string Msg { get; set; }
public T Content { get; set; }
}
}

@ -0,0 +1,20 @@
using Microsoft.Extensions.DependencyInjection;
namespace DotXxlJob.Core
{
public static class ServiceCollectionExtensions
{
public static IServiceCollection AddXxlJobExecutor(this IServiceCollection services)
{
services.AddSingleton<ITaskExecutor, TaskExecutors.BeanTaskExecutor>();
services.AddSingleton<IJobHandlerFactory,DefaultJobHandlerFactory >();
services.AddSingleton<JobDispatcher>();
services.AddSingleton<TaskExecutorFactory>();
services.AddSingleton<XxlRpcServiceHandler>();
services.AddSingleton<CallbackTaskQueue>();
services.AddSingleton<IExecutorRegistry, ExecutorRegistry>();
return services;
}
}
}

@ -1,7 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Extensions.DependencyInjection;
namespace DotXxlJob.Core
{
/// <summary>
/// 负责响应RPC请求,调度任务执行器的工厂类
/// </summary>
public class TaskExecutorFactory
{
private readonly IServiceProvider _provider;
private readonly Dictionary<string, ITaskExecutor> _cache = new Dictionary<string, ITaskExecutor>();
public TaskExecutorFactory(IServiceProvider provider)
{
_provider = provider;
Initialize();
}
private void Initialize()
{
var executors = _provider.GetServices<ITaskExecutor>();
if (executors != null && executors.Any())
{
foreach (var item in executors)
{
_cache.Add(item.GlueType,item);
}
}
}
public ITaskExecutor GetTaskExecutor(string glueType)
{
return _cache.TryGetValue(glueType, out var executor) ? executor : null;
}
}
}

@ -0,0 +1,34 @@
using System.Threading.Tasks;
using DotXxlJob.Core.Model;
namespace DotXxlJob.Core.TaskExecutors
{
/// <summary>
/// 实现 IJobHandler的执行器
/// </summary>
public class BeanTaskExecutor:ITaskExecutor
{
private readonly IJobHandlerFactory _handlerFactory;
public BeanTaskExecutor(IJobHandlerFactory handlerFactory)
{
_handlerFactory = handlerFactory;
}
public string GlueType { get; } = Constants.GlueType.BEAN;
public Task<ReturnT> Execute(TriggerParam triggerParam)
{
var handler = _handlerFactory.GetJobHandler(triggerParam.ExecutorHandler);
if (handler == null)
{
return Task.FromResult(ReturnT.Failed($"job handler [{triggerParam.ExecutorHandler} not found."));
}
return Task.FromResult(ReturnT.Success("OK"));
//return handler.Execute(new JobExecuteContext());
}
}
}

@ -0,0 +1,116 @@
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using DotXxlJob.Core.Model;
using Microsoft.Extensions.Logging;
namespace DotXxlJob.Core
{
public class JobQueue
{
private readonly ITaskExecutor _executor;
private readonly CallbackTaskQueue _callbackTaskQueue;
private readonly ILogger<JobQueue> _logger;
private readonly ConcurrentQueue<TriggerParam> TASK_QUEUE = new ConcurrentQueue<TriggerParam>();
public JobQueue(ITaskExecutor executor,CallbackTaskQueue callbackTaskQueue,ILogger<JobQueue> logger)
{
_executor = executor;
_callbackTaskQueue = callbackTaskQueue;
_logger = logger;
}
public ITaskExecutor Executor => this._executor;
private CancellationTokenSource _cancellationTokenSource;
/// <summary>
/// 覆盖之前的队列
/// </summary>
/// <param name="triggerParam"></param>
/// <returns></returns>
public ReturnT Replace(TriggerParam triggerParam)
{
Stop();
while (!TASK_QUEUE.IsEmpty)
{
TASK_QUEUE.TryDequeue(out _);
}
return Push(triggerParam);
}
public ReturnT Push(TriggerParam triggerParam)
{
this.TASK_QUEUE.Enqueue(triggerParam);
StartTask();
return ReturnT.SUCCESS;
}
public void Stop()
{
this._cancellationTokenSource?.Cancel();
this._cancellationTokenSource?.Dispose();
this._cancellationTokenSource = null;
}
private void StartTask()
{
if (this._cancellationTokenSource != null )
{
return; //running
}
this._cancellationTokenSource =new CancellationTokenSource();
CancellationToken ct = _cancellationTokenSource.Token;
Task.Factory.StartNew(async () =>
{
//ct.ThrowIfCancellationRequested();
while (!ct.IsCancellationRequested)
{
if (TASK_QUEUE.IsEmpty)
{
break;
}
ReturnT result = null;
TriggerParam triggerParam = null;
try
{
if (TASK_QUEUE.TryDequeue(out triggerParam))
{
result = await this._executor.Execute(triggerParam);
}
else
{
this._logger.LogWarning("Dequeue Task Failed");
}
}
catch (Exception ex)
{
result = ReturnT.Failed("Dequeue Task Failed:"+ex.Message);
}
if(triggerParam !=null)
{
this._callbackTaskQueue.Push(new CallbackParam(triggerParam, result));
}
}
this._cancellationTokenSource.Dispose();
this._cancellationTokenSource = null;
}, this._cancellationTokenSource.Token);
}
}
}

@ -0,0 +1,212 @@
using System;
using System.Collections.Concurrent;
using System.IO;
using System.Reflection;
using System.Threading.Tasks;
using DotXxlJob.Core.Config;
using DotXxlJob.Core.Model;
using Hessian.Net;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace DotXxlJob.Core
{
/// <summary>
/// 负责执行Http请求,序列化和反序列化并发送响应
/// </summary>
public class XxlRpcServiceHandler
{
private readonly JobDispatcher _jobDispatcher;
private readonly ILogger<XxlRpcServiceHandler> _logger;
private readonly DataContractHessianSerializer _reqSerializer;
private readonly DataContractHessianSerializer _resSerializer;
private readonly XxlJobExecutorOptions _options;
private readonly ConcurrentDictionary<string, MethodInfo> METHOD_CACHE =
new ConcurrentDictionary<string, MethodInfo>();
public XxlRpcServiceHandler(IOptions<XxlJobExecutorOptions> optionsAccessor,
JobDispatcher jobDispatcher,
ILogger<XxlRpcServiceHandler> logger)
{
_jobDispatcher = jobDispatcher;
this._logger = logger;
this._reqSerializer = new DataContractHessianSerializer(typeof (RpcRequest));
this._resSerializer = new DataContractHessianSerializer(typeof (RpcResponse));
this._options = optionsAccessor.Value;
if (this._options == null)
{
throw new ArgumentNullException(nameof(XxlJobExecutorOptions));
}
}
/// <summary>
/// 处理XxlRpc请求流
/// </summary>
/// <param name="reqStream"></param>
/// <returns></returns>
/// <exception cref="NotImplementedException"></exception>
public async Task<byte[]> HandlerAsync(Stream reqStream)
{
using (Stream output = File.OpenWrite(DateTime.Now.ToUnixTimeSeconds()+".dat"))
{
reqStream.CopyTo(output);
}
var req = _reqSerializer.ReadObject(reqStream) as RpcRequest;
var res = new RpcResponse();
if (!ValidRequest(req, out var error))
{
res.ErrorMsg = error;
}
else
{
await Invoke(req, res);
}
using (var outputStream = new MemoryStream())
{
_resSerializer.WriteObject(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.FromUnixTimeMilliseconds()) > 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.";
}
else
{
var result = method.Invoke(this, req.Parameters.ToArray());
res.Result = result;
}
}
catch (Exception ex)
{
res.ErrorMsg = ex.ToString();
}
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>
/// TODO:获取执行日志
/// </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 logResult = JobLogger.ReadLog(logDateTime, logId, fromLineNum);
return ReturnT.Success(null);
}
/// <summary>
/// 执行
/// </summary>
/// <param name="triggerParam"></param>
/// <returns></returns>
private ReturnT Run(TriggerParam triggerParam)
{
return this._jobDispatcher.Execute(triggerParam);
}
#endregion
}
}

@ -95,7 +95,7 @@ namespace Hessian.Net
{
return ReadPackedInt64();
}
if (!LeadingByte.IsUnpackedInt64)
{
throw new HessianSerializerException();
@ -286,6 +286,48 @@ namespace Hessian.Net
{
preamble = ObjectPreamble.None;
}
public ObjectPreamble BeginList()
{
ReadLeadingByte();
if (LeadingByte.IsVarList)
{
preamble = ObjectPreamble.VarList;
}
else if (LeadingByte.IsFixedList)
{
preamble = ObjectPreamble.FixList;
}
else if (LeadingByte.IsVarListUntyped)
{
preamble = ObjectPreamble.VarListUntyped;
}
else if (LeadingByte.IsFixListUntyped)
{
preamble = ObjectPreamble.FixListUntyped;
}
else if (LeadingByte.IsCompactFixList)
{
preamble = ObjectPreamble.CompactFixList;
}
else if (LeadingByte.IsCompactFixListUntyped)
{
preamble = ObjectPreamble.CompactFixListUntyped;
}
else
{
throw new HessianSerializerException();
}
return preamble;
}
public void EndList()
{
preamble = ObjectPreamble.None;
}
public void EndClassDefinition()
{
@ -313,10 +355,16 @@ namespace Hessian.Net
return ReadInt32();
}
public byte? Peek()
{
return this.Stream.
}
protected void ReadLeadingByte()
{
var data = Stream.ReadByte();
Console.WriteLine(data.ToString("x2"));
if (-1 == data)
{
throw new HessianSerializerException();

@ -51,10 +51,15 @@ namespace Hessian.Net
var serializer = factory.GetSerializer(type);
return new ValueElement(type, serializer);
}
if (IsListType(info))
{
return new ListElement(info);
}
return BuildSerializationObject(type, catalog, factory);
}
private static ISerializationElement BuildSerializationObject(Type type, IDictionary<Type, ISerializationElement> catalog, IObjectSerializerFactory factory)
{
ISerializationElement existing;
@ -101,19 +106,24 @@ namespace Hessian.Net
return element;
}
private static bool IsSimpleType(TypeInfo typeinfo)
private static bool IsSimpleType(TypeInfo typeInfo)
{
if (typeinfo.IsValueType || typeinfo.IsEnum || typeinfo.IsPrimitive)
if (typeInfo.IsValueType || typeInfo.IsEnum || typeInfo.IsPrimitive)
{
return true;
}
if (typeof (String) == typeinfo.AsType())
if (typeof (String) == typeInfo.AsType())
{
return true;
}
return false;
}
public static bool IsListType(TypeInfo typeInfo)
{
return typeInfo.IsArray && typeInfo.HasElementType;
}
}
}

@ -71,6 +71,16 @@ namespace Hessian.Net
public bool IsLongObjectReference => Check(If.Marker.Equals(Marker.ClassReference));
public bool IsInstanceReference => Check(If.Marker.Equals(Marker.InstanceReference));
public bool IsVarList => Check(If.Marker.Equals(Marker.VarList));
public bool IsFixedList => Check(If.Marker.Equals(Marker.FixedList));
public bool IsVarListUntyped => Check(If.Marker.Equals(Marker.VarListUntyped));
public bool IsFixListUntyped => Check(If.Marker.Equals(Marker.FixListUntyped));
public bool IsCompactFixList => Check(If.Marker.Between(Marker.CompactFixListStart).And(Marker.CompactFixListEnd));
public bool IsCompactFixListUntyped => Check(If.Marker.Between(Marker.CompactFixListUntypedStart).And(Marker.CompactFixListUntypedEnd));
public void SetData(byte value)
{

@ -0,0 +1,167 @@
using System;
using System.Collections.Generic;
using System.IO;
namespace Hessian.Net
{
public class ListElement: ISerializationElement
{
public ListElement(Type listType)
{
this.ObjectType = listType.GetElementType();
}
public Type ObjectType { get; }
public void Serialize(HessianOutputWriter writer, object graph, HessianSerializationContext context)
{
throw new NotImplementedException();
}
public object Deserialize(HessianInputReader reader, HessianSerializationContext context)
{
var preamble = reader.BeginList();
switch (preamble)
{
case ObjectPreamble.FixList:
break;
case ObjectPreamble.VarList:
break;
case ObjectPreamble.FixListUntyped:
break;
case ObjectPreamble.VarListUntyped:
break;
case ObjectPreamble.CompactFixList:
break;
case ObjectPreamble.CompactFixListUntyped:
break;
}
reader.EndList();
}
private string ReadTypeName(HessianInputReader reader)
{
reader.re
var tag = reader.Peek();
if (!tag.HasValue) {
throw new EndOfStreamException();
}
// A type name is either a string, or an integer reference to a
// string already read and stored in the type-name ref map.
if ((tag >= 0x00 && tag < 0x20)
|| (tag >= 0x30 && tag < 0x34)
|| tag == 0x52
|| tag == 0x53) {
var typeName = ReadString();
typeNameRefs.Add(typeName);
return typeName;
}
return typeNameRefs.Get(ReadInteger());
}
#region List
private IList<object> ReadVarList()
{
reader.ReadByte();
var type = ReadTypeName();
return ReadListCore(type: type);
}
private IList<object> ReadFixList()
{
reader.ReadByte();
var type = ReadTypeName();
var length = ReadInteger();
return ReadListCore(length, type);
}
private IList<object> ReadVarListUntyped()
{
reader.ReadByte();
return ReadListCore();
}
private IList<object> ReadFixListUntyped()
{
reader.ReadByte();
var length = ReadInteger();
return ReadListCore(length);
}
private IList<object> ReadCompactFixList()
{
var tag = reader.ReadByte();
var length = tag - 0x70;
var type = ReadTypeName();
return ReadListCore(length, type);
}
private IList<object> ReadCompactFixListUntyped()
{
var tag = reader.ReadByte();
var length = tag - 0x70;
return ReadListCore(length);
}
private IList<object> ReadListCore(int? length = null, string type = null)
{
var list = GetListIntance(type, length);
objectRefs.Add(list);
if (length.HasValue) {
PopulateFixLengthList(list, length.Value);
} else {
PopulateVarList(list);
}
return list;
}
private IList<object> GetListIntance(string type, int? length = null)
{
IList<object> list;
if (length.HasValue) {
if (!listTypeResolver.Value.TryGetListInstance(type, length.Value, out list)) {
list = new List<object>(length.Value);
}
} else {
if (!listTypeResolver.Value.TryGetListInstance(type, out list)) {
list = new List<object>();
}
}
return list;
}
private void PopulateFixLengthList(IList<object> list, int length)
{
for (var i = 0; i < length; ++i) {
list.Add(ReadValue());
}
}
private void PopulateVarList(IList<object> list)
{
while (true) {
var tag = reader.Peek();
if (!tag.HasValue) {
throw new EndOfStreamException();
}
if (tag == 'Z') {
reader.ReadByte();
break;
}
list.Add(ReadValue());
}
}
#endregion
}
}

@ -0,0 +1,13 @@
namespace Hessian.Net
{
public enum ListPreamble
{
None,
VarList,
FixList,
VarListUntyped,
FixListUntyped,
CompactFixList,
CompactFixListUntyped
}
}

@ -24,8 +24,19 @@
public const byte UnpackedLong = (byte) 'L';// 0x4C;
public const byte StringNonfinalChunk = 0x52;
public const byte StringFinalChunk = 0x53;
public const byte FixedLengthList = 0x56;
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;
}
}

@ -108,6 +108,7 @@ namespace Hessian.Net
for (var index = 0; index < propertiesCount; index++)
{
var propertyName = reader.ReadString();
Console.WriteLine(propertyName);
var exists = ObjectProperties.Any(property => String.Equals(property.PropertyName, propertyName));
if (!exists)
@ -130,10 +131,12 @@ namespace Hessian.Net
var instance = Activator.CreateInstance(ObjectType);
context.Instances.Add(instance);
Console.WriteLine("===========================================");
foreach (var item in ObjectProperties)
{
Console.WriteLine(item.PropertyName);
var value = item.Deserialize(reader, context);
Console.WriteLine(value);
item.Property.SetValue(instance, value);
}

@ -5,6 +5,13 @@
None = -1,
ClassDefinition,
ObjectReference,
InstanceReference
InstanceReference,
VarList,
FixList,
VarListUntyped,
FixListUntyped,
CompactFixList,
CompactFixListUntyped
}
}

@ -0,0 +1,59 @@
using System;
namespace Hessian
{
public class ClassDef : IEquatable<ClassDef>
{
public string Name { get; private set; }
public string[] Fields { get; private set; }
public ClassDef(string name, string[] fields)
{
Name = Conditions.CheckNotNull(name, "name");
Fields = Conditions.CheckNotNull(fields, "fields");
}
public override int GetHashCode()
{
unchecked {
const uint prime = 16777619;
var hash = 2166136261;
hash *= prime;
hash ^= (uint)Name.GetHashCode();
for (var i = 0; i < Fields.Length; ++i) {
hash *= prime;
hash ^= (uint)Fields[i].GetHashCode();
}
return (int)hash;
}
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) {
return false;
}
if (ReferenceEquals(this, obj)) {
return true;
}
if (obj.GetType() != GetType()) {
return false;
}
return Equals((ClassDef) obj);
}
public bool Equals(ClassDef other)
{
if (ReferenceEquals(null, other)) {
return false;
}
if (ReferenceEquals(this, other)) {
return true;
}
return string.Equals(Name, other.Name) && Fields.Equals(other.Fields);
}
}
}

@ -0,0 +1,91 @@
using System.Collections;
using System.Collections.Generic;
namespace Hessian.Collections
{
public abstract class ForwardingDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
protected abstract IDictionary<TKey, TValue> Delegate { get; }
public virtual ICollection<TKey> Keys
{
get { return Delegate.Keys; }
}
public virtual ICollection<TValue> Values
{
get { return Delegate.Values; }
}
public virtual IEnumerator<KeyValuePair<TKey, TValue>> GetEnumerator()
{
return Delegate.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public virtual void Add(KeyValuePair<TKey, TValue> item)
{
Delegate.Add(item);
}
public virtual void Clear()
{
Delegate.Clear();
}
public virtual bool Contains(KeyValuePair<TKey, TValue> item)
{
return Delegate.Contains(item);
}
public virtual void CopyTo(KeyValuePair<TKey, TValue>[] array, int arrayIndex)
{
Delegate.CopyTo(array, arrayIndex);
}
public virtual bool Remove(KeyValuePair<TKey, TValue> item)
{
return Delegate.Remove(item);
}
public virtual int Count
{
get { return Delegate.Count; }
}
public virtual bool IsReadOnly
{
get { return Delegate.IsReadOnly; }
}
public virtual bool ContainsKey(TKey key)
{
return Delegate.ContainsKey(key);
}
public virtual void Add(TKey key, TValue value)
{
Delegate.Add(key, value);
}
public virtual bool Remove(TKey key)
{
return Delegate.Remove(key);
}
public virtual bool TryGetValue(TKey key, out TValue value)
{
return Delegate.TryGetValue(key, out value);
}
public virtual TValue this[TKey key]
{
get { return Delegate[key]; }
set { Delegate[key] = value; }
}
}
}

@ -0,0 +1,32 @@
namespace Hessian.Collections
{
/// <summary>
/// Represents a map that associates objects with a zero-based integer
/// index. Specified in Hessian 2.0.
/// </summary>
/// <typeparam name="T"></typeparam>
public interface IRefMap<T>
{
/// <summary>
/// Adds an element to the ref map and returns its ID.
/// </summary>
/// <param name="entry"></param>
/// <returns></returns>
int Add(T entry);
/// <summary>
/// Retrieves the element identified by the given ID.
/// </summary>
/// <param name="refId"></param>
/// <returns></returns>
T Get(int refId);
/// <summary>
/// Looks up an element in the ref map and, if present, returns its ID.
/// </summary>
/// <remarks>
/// Performance of this method is not guaranteed and is implementation-specific.
/// </remarks>
int? Lookup(T entry);
}
}

@ -0,0 +1,59 @@
using System.Collections.Generic;
namespace Hessian.Collections
{
/// <summary>
/// Represents a dictionary which maintains uniqueness of both keys and values,
/// allowing for the lookup of a key by its value in additon to the normal
/// operations expected of a dictionary.
/// </summary>
public interface ITwoWayDictionary<TKey, TValue> : IDictionary<TKey, TValue>
{
/// <summary>
/// Exposes a view of the current dictionary that reverses keys and
/// values. Note that the same underlying data is shared.
/// </summary>
ITwoWayDictionary<TValue, TKey> Inverse { get; }
/// <summary>
/// Gets or sets a key by the given value.
/// </summary>
/// <param name="value">
/// The value with which to get or set a key.
/// </param>
/// <returns>
/// Returns the key indexing the given <paramref name="value"/>.
/// </returns>
TKey this[TValue valueKey] { get; set; }
/// <summary>
/// Gets a value indicating whether the given <paramref name="value"/>
/// is contained in this dictionary.
/// </summary>
/// <param name="value">
/// The value whose presence is to be determined.
/// </param>
/// <returns>
/// Returns <see langword="true"/> if <paramref name="value"/> is in
/// this dictionary, and <see langword="false"/> otherwise.
/// </returns>
bool ContainsValue(TValue value);
/// <summary>
/// Attempts to look up a key by the given value. A return value
/// indicates whether the lookip is successful.
/// </summary>
/// <param name="value">
/// The value whose corresponding key is to be retrieved.
/// </param>
/// <param name="key">
/// When the method returns, contains the looked-up key if the lookup
/// succeeded.
/// </param>
/// <returns>
/// Returns <see langword="true"/> if the lookup succeeded, and
/// <see langword="false"/> otherwise.
/// </returns>
bool TryGetKey(TValue value, out TKey key);
}
}

@ -0,0 +1,34 @@
using System.Collections.Generic;
namespace Hessian.Collections
{
public class ListRefMap<T> : IRefMap<T>
{
private readonly List<T> list = new List<T>();
public int Add(T entry)
{
list.Add(entry);
return list.Count - 1;
}
public T Get(int refId)
{
if (refId < 0 || refId >= list.Count) {
throw new InvalidRefException(refId);
}
return list[refId];
}
public int? Lookup(T entry)
{
for (var i = 0; i < list.Count; ++i) {
if (entry.Equals(list[i])) {
return i;
}
}
return null;
}
}
}

@ -0,0 +1,123 @@
using System.Collections.Generic;
namespace Hessian.Collections
{
public class TwoWayDictionary<TKey, TValue> : ForwardingDictionary<TKey, TValue>, ITwoWayDictionary<TKey, TValue>
{
private readonly IDictionary<TKey, TValue> dict;
private readonly TwoWayDictionary<TValue, TKey> inverse;
protected override IDictionary<TKey, TValue> Delegate {
get { return dict; }
}
public override bool IsReadOnly {
get { return false; }
}
public ITwoWayDictionary<TValue, TKey> Inverse {
get { return inverse; }
}
public override TValue this[TKey key] {
set { UpdateDictAndInverse(key, value, false); }
}
public TKey this[TValue valueKey] {
get { return inverse[valueKey]; }
set { inverse[valueKey] = value; }
}
public override ICollection<TValue> Values {
get { return inverse.dict.Keys; }
}
public TwoWayDictionary()
: this(new Dictionary<TKey, TValue>(), new Dictionary<TValue, TKey>())
{
}
public TwoWayDictionary(IDictionary<TKey, TValue> forwards, IDictionary<TValue, TKey> backwards)
{
dict = Conditions.CheckNotNull(forwards, "forwards");
inverse = new TwoWayDictionary<TValue, TKey>(backwards, this);
}
private TwoWayDictionary(IDictionary<TKey, TValue> dict, TwoWayDictionary<TValue, TKey> inverse)
{
this.dict = Conditions.CheckNotNull(dict, "dict");
this.inverse = inverse;
}
public bool ContainsValue(TValue value)
{
return inverse.ContainsKey(value);
}
public bool TryGetKey(TValue value, out TKey key)
{
return inverse.TryGetValue(value, out key);
}
public override void Add(TKey key, TValue value)
{
UpdateDictAndInverse(key, value, true);
}
public override bool Remove(TKey key)
{
return RemoveFromDictAndInverse(key);
}
private void UpdateDictAndInverse(TKey key, TValue value, bool throwIfContained)
{
if (!throwIfContained) {
dict.Remove(key);
inverse.dict.Remove(value);
}
dict.Add(key, value);
inverse.dict.Add(value, key);
}
private bool RemoveFromDictAndInverse(TKey key)
{
TValue value;
if (!TryGetValue(key, out value)) {
return false;
}
return RemoveFromDictAndInverse(key, value);
}
private bool RemoveFromDictAndInverse(TKey key, TValue value)
{
if (!ContainsKey(key) || !ContainsValue(value)) {
return false;
}
return dict.Remove(key) && inverse.dict.Remove(value);
}
#region ICollection<KeyValuePair<TKey, TValue>>
public override bool Remove(KeyValuePair<TKey, TValue> kvp)
{
return RemoveFromDictAndInverse(kvp.Key, kvp.Value);
}
public override void Clear()
{
dict.Clear();
inverse.dict.Clear();
}
public override bool Contains(KeyValuePair<TKey, TValue> kvp)
{
return ContainsKey(kvp.Key) && ContainsValue(kvp.Value);
}
#endregion
}
}

@ -0,0 +1,34 @@
namespace Hessian.Collections
{
public class TwoWayDictionaryRefMap<T> : IRefMap<T>
{
private readonly TwoWayDictionary<T, int> map = new TwoWayDictionary<T, int>();
public int Add(T value)
{
var refid = map.Count;
map.Add(value, refid);
return refid;
}
public T Get(int refid)
{
T entry;
if (map.TryGetKey(refid, out entry)) {
return entry;
}
throw new InvalidRefException(refid);
}
public int? Lookup(T entry)
{
int refId;
if (map.TryGetValue(entry, out refId)) {
return refId;
}
return null;
}
}
}

@ -0,0 +1,114 @@
using System;
namespace Hessian
{
public class Conditions
{
protected Conditions()
{
}
public static void CheckArgument(bool condition, string message, params object[] args)
{
if (condition) {
return;
}
if (args.Length > 0) {
message = String.Format(message, args);
}
throw new ArgumentException(message);
}
public static T CheckNotNull<T>(T value, string name)
where T : class
{
if (!ReferenceEquals(value, null)) {
return value;
}
throw new ArgumentNullException(name);
}
public static TComparable CheckGreater<TComparable, TComparand>(TComparable value, TComparand bounds,
string name)
where TComparable : IComparable<TComparand>
{
if (value.CompareTo(bounds) > 0) {
return value;
}
throw new ArgumentOutOfRangeException(name);
}
public static TComparable CheckLess<TComparable, TComparand>(TComparable value, TComparand bounds,
string name)
where TComparable : IComparable<TComparand>
{
if (value.CompareTo(bounds) < 0) {
return value;
}
throw new ArgumentOutOfRangeException(name);
}
public static TComparable CheckGreaterOrEqual<TComparable, TComparand>(TComparable value, TComparand bounds,
string name)
where TComparable : IComparable<TComparand>
{
if (value.CompareTo(bounds) >= 0) {
return value;
}
throw new ArgumentOutOfRangeException(name);
}
public static TComparable CheckLessOrEqual<TComparable, TComparand>(TComparable value, TComparand bounds,
string name)
where TComparable : IComparable<TComparand>
{
if (value.CompareTo(bounds) <= 0) {
return value;
}
throw new ArgumentOutOfRangeException(name);
}
public static int CheckGreater(int value, int bounds, string name)
{
if (value > bounds) {
return value;
}
throw new ArgumentOutOfRangeException(name);
}
public static int CheckLess(int value, int bounds, string name)
{
if (value < bounds) {
return value;
}
throw new ArgumentOutOfRangeException(name);
}
public static int CheckGreaterOrEqual(int value, int bounds, string name)
{
if (value >= bounds) {
return value;
}
throw new ArgumentOutOfRangeException(name);
}
public static int CheckLessOrEqual(int value, int bounds, string name)
{
if (value <= bounds) {
return value;
}
throw new ArgumentOutOfRangeException(name);
}
}
}

@ -0,0 +1,892 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using Hessian.Collections;
using Hessian.Platform;
namespace Hessian
{
public class Deserializer
{
private readonly ValueReader reader;
private readonly IRefMap<ClassDef> classDefs;
private readonly IRefMap<object> objectRefs;
private readonly IRefMap<string> typeNameRefs;
private readonly Lazy<ListTypeResolver> listTypeResolver = new Lazy<ListTypeResolver>();
private readonly Lazy<DictionaryTypeResolver> dictTypeResolver = new Lazy<DictionaryTypeResolver>();
private static readonly EndianBitConverter BitConverter = new BigEndianBitConverter();
public Deserializer (Stream stream)
{
if (stream == null) {
throw new ArgumentNullException("stream");
}
reader = new ValueReader(stream);
classDefs = new ListRefMap<ClassDef>();
objectRefs = new ListRefMap<object>();
typeNameRefs = new ListRefMap<string>();
}
#region ReadValue
public object ReadValue ()
{
var tag = reader.Peek ();
if (!tag.HasValue) {
throw new EndOfStreamException();
}
switch (tag.Value) {
case 0x00: case 0x01: case 0x02: case 0x03: case 0x04: case 0x05: case 0x06: case 0x07:
case 0x08: case 0x09: case 0x0A: case 0x0B: case 0x0C: case 0x0D: case 0x0E: case 0x0F:
case 0x10: case 0x11: case 0x12: case 0x13: case 0x14: case 0x15: case 0x16: case 0x17:
case 0x18: case 0x19: case 0x1A: case 0x1B: case 0x1C: case 0x1D: case 0x1E: case 0x1F:
return ReadShortString();
case 0x20: case 0x21: case 0x22: case 0x23: case 0x24: case 0x25: case 0x26: case 0x27:
case 0x28: case 0x29: case 0x2A: case 0x2B: case 0x2C: case 0x2D: case 0x2E: case 0x2F:
return ReadShortBinary();
case 0x30: case 0x31: case 0x32: case 0x33:
return ReadMediumString();
case 0x34: case 0x35: case 0x36: case 0x37:
return ReadMediumBinary();
case 0x38: case 0x39: case 0x3A: case 0x3B: case 0x3C: case 0x3D: case 0x3E: case 0x3F:
return ReadLongThreeBytes();
case 0x40:
return Reserved();
case 0x41: case 0x42:
return ReadChunkedBinary();
case 0x43:
return ReadClassDefinition();
case 0x44:
return ReadFullDouble();
case 0x45:
return Reserved();
case 0x46:
return ReadBoolean();
case 0x47:
return Reserved();
case 0x48:
return ReadUntypedMap();
case 0x49:
return ReadInteger();
case 0x4A:
return ReadDateInMillis();
case 0x4B:
return ReadDateInMinutes();
case 0x4C:
return ReadLongFull();
case 0x4D:
return ReadTypedMap();
case 0x4E:
return ReadNull();
case 0x4F:
return ReadObject();
case 0x50:
return Reserved();
case 0x51:
return ReadRef();
case 0x52: case 0x53:
return ReadChunkedString();
case 0x54:
return ReadBoolean();
case 0x55:
return ReadVarList();
case 0x56:
return ReadFixList();
case 0x57:
return ReadVarListUntyped();
case 0x58:
return ReadFixListUntyped();
case 0x59:
return ReadLongFourBytes();
case 0x5A:
// List terminator - solitary list terminators are most definitely not legit.
throw new UnexpectedTagException(0x5A, "value");
case 0x5B: case 0x5C:
return ReadDoubleOneByte();
case 0x5D:
return ReadDoubleOneByte();
case 0x5E:
return ReadDoubleTwoBytes();
case 0x5F:
return ReadDoubleFourBytes();
case 0x60: case 0x61: case 0x62: case 0x63: case 0x64: case 0x65: case 0x66: case 0x67:
case 0x68: case 0x69: case 0x6A: case 0x6B: case 0x6C: case 0x6D: case 0x6E: case 0x6F:
return ReadObjectCompact();
case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
return ReadCompactFixList();
case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F:
return ReadCompactFixListUntyped();
case 0x80: case 0x81: case 0x82: case 0x83: case 0x84: case 0x85: case 0x86: case 0x87:
case 0x88: case 0x89: case 0x8A: case 0x8B: case 0x8C: case 0x8D: case 0x8E: case 0x8F:
case 0x90: case 0x91: case 0x92: case 0x93: case 0x94: case 0x95: case 0x96: case 0x97:
case 0x98: case 0x99: case 0x9A: case 0x9B: case 0x9C: case 0x9D: case 0x9E: case 0x9F:
case 0xA0: case 0xA1: case 0xA2: case 0xA3: case 0xA4: case 0xA5: case 0xA6: case 0xA7:
case 0xA8: case 0xA9: case 0xAA: case 0xAB: case 0xAC: case 0xAD: case 0xAE: case 0xAF:
case 0xB0: case 0xB1: case 0xB2: case 0xB3: case 0xB4: case 0xB5: case 0xB6: case 0xB7:
case 0xB8: case 0xB9: case 0xBA: case 0xBB: case 0xBC: case 0xBD: case 0xBE: case 0xBF:
return ReadIntegerSingleByte();
case 0xC0: case 0xC1: case 0xC2: case 0xC3: case 0xC4: case 0xC5: case 0xC6: case 0xC7:
case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF:
return ReadIntegerTwoBytes();
case 0xD0: case 0xD1: case 0xD2: case 0xD3: case 0xD4: case 0xD5: case 0xD6: case 0xD7:
return ReadIntegerThreeBytes();
case 0xD8: case 0xD9: case 0xDA: case 0xDB: case 0xDC: case 0xDD: case 0xDE: case 0xDF:
case 0xE0: case 0xE1: case 0xE2: case 0xE3: case 0xE4: case 0xE5: case 0xE6: case 0xE7:
case 0xE8: case 0xE9: case 0xEA: case 0xEB: case 0xEC: case 0xED: case 0xEE: case 0xEF:
return ReadLongOneByte();
case 0xF0: case 0xF1: case 0xF2: case 0xF3: case 0xF4: case 0xF5: case 0xF6: case 0xF7:
case 0xF8: case 0xF9: case 0xFA: case 0xFB: case 0xFC: case 0xFD: case 0xFE: case 0xFF:
return ReadLongTwoBytes();
}
throw new Exception("WTF: byte value " + tag.Value + " not accounted for!");
}
#endregion
private string ReadTypeName()
{
var tag = reader.Peek();
if (!tag.HasValue) {
throw new EndOfStreamException();
}
// A type name is either a string, or an integer reference to a
// string already read and stored in the type-name ref map.
if ((tag >= 0x00 && tag < 0x20)
|| (tag >= 0x30 && tag < 0x34)
|| tag == 0x52
|| tag == 0x53) {
var typeName = ReadString();
typeNameRefs.Add(typeName);
return typeName;
}
return typeNameRefs.Get(ReadInteger());
}
#region List
private IList<object> ReadVarList()
{
reader.ReadByte();
var type = ReadTypeName();
return ReadListCore(type: type);
}
private IList<object> ReadFixList()
{
reader.ReadByte();
var type = ReadTypeName();
var length = ReadInteger();
return ReadListCore(length, type);
}
private IList<object> ReadVarListUntyped()
{
reader.ReadByte();
return ReadListCore();
}
private IList<object> ReadFixListUntyped()
{
reader.ReadByte();
var length = ReadInteger();
return ReadListCore(length);
}
private IList<object> ReadCompactFixList()
{
var tag = reader.ReadByte();
var length = tag - 0x70;
var type = ReadTypeName();
return ReadListCore(length, type);
}
private IList<object> ReadCompactFixListUntyped()
{
var tag = reader.ReadByte();
var length = tag - 0x70;
return ReadListCore(length);
}
private IList<object> ReadListCore(int? length = null, string type = null)
{
var list = GetListIntance(type, length);
objectRefs.Add(list);
if (length.HasValue) {
PopulateFixLengthList(list, length.Value);
} else {
PopulateVarList(list);
}
return list;
}
private IList<object> GetListIntance(string type, int? length = null)
{
IList<object> list;
if (length.HasValue) {
if (!listTypeResolver.Value.TryGetListInstance(type, length.Value, out list)) {
list = new List<object>(length.Value);
}
} else {
if (!listTypeResolver.Value.TryGetListInstance(type, out list)) {
list = new List<object>();
}
}
return list;
}
private void PopulateFixLengthList(IList<object> list, int length)
{
for (var i = 0; i < length; ++i) {
list.Add(ReadValue());
}
}
private void PopulateVarList(IList<object> list)
{
while (true) {
var tag = reader.Peek();
if (!tag.HasValue) {
throw new EndOfStreamException();
}
if (tag == 'Z') {
reader.ReadByte();
break;
}
list.Add(ReadValue());
}
}
#endregion
public object Reserved ()
{
reader.ReadByte();
return ReadValue();
}
#region String
public string ReadString()
{
var tag = reader.Peek();
if (!tag.HasValue) {
throw new EndOfStreamException();
}
if (tag.Value < 0x20) {
return ReadShortString();
}
if (tag.Value >= 0x30 && tag.Value <= 0x33) {
return ReadMediumString();
}
if (tag.Value == 'R' || tag.Value == 'S') {
return ReadChunkedString();
}
throw new UnexpectedTagException(tag.Value, "string");
}
private string ReadShortString ()
{
var length = reader.ReadByte();
return ReadStringWithLength(length);
}
private string ReadMediumString ()
{
var b0 = reader.ReadByte ();
var b1 = reader.ReadByte ();
var length = ((b0 - 0x30) << 8) | b1;
return ReadStringWithLength(length);
}
private string ReadStringWithLength (int length)
{
var sb = new StringBuilder (length);
while (length-- > 0) {
sb.AppendCodepoint(reader.ReadUtf8Codepoint());
}
return sb.ToString();
}
private string ReadChunkedString()
{
var sb = new StringBuilder();
var final = false;
while (!final) {
var tag = reader.ReadByte();
final = tag == 'S';
var length = reader.ReadShort();
while (length-- > 0) {
sb.AppendCodepoint(reader.ReadUtf8Codepoint());
}
}
return sb.ToString();
}
#endregion
#region Binary
public byte[] ReadBinary()
{
var tag = reader.Peek();
if (!tag.HasValue) {
throw new EndOfStreamException();
}
if (tag.Value >= 0x20 && tag.Value <= 0x2F) {
return ReadShortBinary();
}
if (tag.Value >= 0x34 && tag.Value <= 0x37) {
return ReadMediumBinary();
}
if (tag.Value == 0x41 || tag.Value == 0x42) {
return ReadChunkedBinary();
}
throw new UnexpectedTagException(tag.Value, "binary");
}
private byte[] ReadShortBinary ()
{
var length = reader.ReadByte();
var data = new byte[length];
reader.Read(data, length);
return data;
}
private byte[] ReadMediumBinary()
{
var b0 = reader.ReadByte();
var b1 = reader.ReadByte();
var length = ((b0 - 0x34) << 8) | b1;
var data = new byte[length];
reader.Read(data, length);
return data;
}
public byte[] ReadChunkedBinary()
{
var data = new List<byte>();
var final = false;
while (!final) {
var tag = reader.ReadByte();
final = tag == 'B';
var length = reader.ReadShort();
var buff = new byte[length];
reader.Read(buff, length);
data.AddRange(buff);
}
return data.ToArray();
}
#endregion Binary
#region Integer
public int ReadInteger()
{
var tag = reader.Peek();
if (!tag.HasValue) {
throw new EndOfStreamException();
}
// Full-length integer encoding is 'I' b0 b1 b2 b3 - i.e. a full 32-bit integer in big-endian order.
if (tag == 0x49) {
return ReadIntegerFull();
}
// Ints between -16 and 47 are encoded as value + 0x90.
if (tag >= 0x80 && tag <= 0xBF) {
return ReadIntegerSingleByte();
}
// Ints between -2048 and 2047 can be encoded as two octets with the leading byte from 0xC0 to 0xCF.
if (tag >= 0xC0 && tag <= 0xCF) {
return ReadIntegerTwoBytes();
}
// Ints between -262144 and 262143 can be three bytes with the first from 0xD0 to 0xD7.
if (tag >= 0xD0 && tag <= 0xD7) {
return ReadIntegerThreeBytes();
}
throw new UnexpectedTagException(tag.Value, "integer");
}
private int ReadIntegerFull()
{
reader.ReadByte(); // Discard tag.
byte b0 = reader.ReadByte(),
b1 = reader.ReadByte(),
b2 = reader.ReadByte(),
b3 = reader.ReadByte();
return (b0 << 24) | (b1 << 16) | (b2 << 8) | b3;
}
private int ReadIntegerSingleByte()
{
return reader.ReadByte() - 0x90;
}
private int ReadIntegerTwoBytes()
{
byte b0 = reader.ReadByte(),
b1 = reader.ReadByte();
return ((b0 - 0xC8) << 8) | b1;
}
private int ReadIntegerThreeBytes()
{
byte b0 = reader.ReadByte(),
b1 = reader.ReadByte(),
b2 = reader.ReadByte();
return ((b0 - 0xD4) << 16) | (b1 << 8) | b2;
}
#endregion Integer
#region Class Definition
public ClassDef ReadClassDefinition()
{
var tag = reader.ReadByte();
if (tag != 'C') {
throw new UnexpectedTagException(tag, "classdef");
}
var name = ReadString();
var fieldCount = ReadInteger();
var fields = new string[fieldCount];
for (var i = 0; i < fields.Length; ++i) {
fields[i] = ReadString();
}
var classDef = new ClassDef(name, fields);
classDefs.Add(classDef);
return classDef;
}
#endregion Class Definition
#region Double
public double ReadDouble()
{
var tag = reader.Peek();
if (!tag.HasValue) {
throw new EndOfStreamException();
}
if (tag == 0x44) {
return ReadFullDouble();
}
if (tag == 0x5B || tag == 0x5C) {
return ReadDoubleOneByte();
}
if (tag == 0x5D) {
return ReadDoubleTwoBytes();
}
if (tag == 0x5E) {
return ReadDoubleThreeBytes();
}
if (tag == 0x5F) {
return ReadDoubleFourBytes();
}
throw new UnexpectedTagException(tag.Value, "double");
}
private double ReadFullDouble()
{
var data = new byte[9]; // 9 bytes: tag + IEEE 8-byte double
reader.Read(data, data.Length);
return BitConverter.ToDouble(data, 1);
}
private double ReadDoubleOneByte()
{
// 0x5B encodes the double value 0.0, and 0x5C encodes 1.0.
return reader.ReadByte() - 0x5B;
}
private double ReadDoubleTwoBytes()
{
// Doubles representing integral values between -128.0 and 127.0 are
// encoded as single bytes. Java bytes are signed, .NET bytes aren't,
// so we have to cast it first.
reader.ReadByte();
return (sbyte) reader.ReadByte();
}
private double ReadDoubleThreeBytes()
{
// Doubles representing integral values between -32768.0 and 32767.0 are
// encoded as two-byte integers.
reader.ReadByte();
return reader.ReadShort();
}
private double ReadDoubleFourBytes()
{
// Doubles that can be represented as singles are thusly encoded.
var data = new byte[5];
reader.Read(data, data.Length);
return BitConverter.ToSingle(data, 0);
}
#endregion Double
public bool ReadBoolean()
{
var tag = reader.ReadByte();
switch (tag) {
case 0x46: return false;
case 0x54: return true;
}
throw new UnexpectedTagException(tag, "boolean");
}
#region Date
public DateTime ReadDate()
{
var tag = reader.Peek();
if (!tag.HasValue) {
throw new EndOfStreamException();
}
if (tag == 0x4A) {
return ReadDateInMillis();
}
if (tag == 0x4B) {
return ReadDateInMinutes();
}
throw new UnexpectedTagException(tag.Value, "date");
}
private DateTime ReadDateInMillis()
{
var data = new byte[9];
reader.Read(data, data.Length);
var millis = LongFromBytes(data, 1);
return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMilliseconds(millis);
}
private DateTime ReadDateInMinutes()
{
var data = new byte[5];
reader.Read(data, data.Length);
var minutes = IntFromBytes(data, 1);
return new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc).AddMinutes(minutes);
}
#endregion Date
#region Long
public long ReadLong()
{
var tag = reader.Peek();
if (!tag.HasValue) {
throw new EndOfStreamException();
}
if (tag == 0x4C) {
return ReadLongFull();
}
if (tag >= 0xD8 && tag <= 0xEF) {
return ReadLongOneByte();
}
if (tag >= 0xF0 && tag <= 0xFF) {
return ReadLongTwoBytes();
}
if (tag >= 0x38 && tag <= 0x3F) {
return ReadLongThreeBytes();
}
if (tag == 0x59) {
return ReadLongFourBytes();
}
throw new UnexpectedTagException(tag.Value, "long");
}
private long ReadLongFull()
{
var data = new byte[9];
reader.Read(data, data.Length);
return LongFromBytes(data, 1);
}
private long ReadLongOneByte()
{
return reader.ReadByte() - 0xE0;
}
private long ReadLongTwoBytes()
{
byte b0 = reader.ReadByte(),
b1 = reader.ReadByte();
return ((b0 - 0xF8) << 8) | b1;
}
private long ReadLongThreeBytes()
{
byte b0 = reader.ReadByte(),
b1 = reader.ReadByte(),
b2 = reader.ReadByte();
return ((b0 - 0x3C) << 16) | (b1 << 8) | b2;
}
private long ReadLongFourBytes()
{
var data = new byte[5];
reader.Read(data, data.Length);
return IntFromBytes(data, 1);
}
#endregion Long
#region Dictionary/Map
public IDictionary<object, object> ReadMap()
{
var tag = reader.Peek();
if (!tag.HasValue) {
throw new EndOfStreamException();
}
if (tag == 'H') {
return ReadUntypedMap();
}
if (tag == 'M') {
return ReadTypedMap();
}
throw new UnexpectedTagException(tag.Value, "map");
}
private IDictionary<object, object> ReadUntypedMap()
{
reader.ReadByte();
return ReadMapCore();
}
private IDictionary<object, object> ReadTypedMap()
{
reader.ReadByte();
var typeName = ReadTypeName();
return ReadMapCore(typeName);
}
private IDictionary<object, object> ReadMapCore(string type = null)
{
IDictionary<object, object> dictionary;
if (type == null || !dictTypeResolver.Value.TryGetInstance("", out dictionary)) {
dictionary = new Dictionary<object, object>();
}
objectRefs.Add(dictionary);
while (true) {
var tag = reader.Peek();
if (!tag.HasValue) {
throw new EndOfStreamException();
}
if (tag == 'Z') {
break;
}
var key = ReadValue();
var value = ReadValue();
dictionary.Add(key, value);
}
return dictionary;
}
#endregion
#region Object
public object ReadObject()
{
var tag = reader.Peek();
if (!tag.HasValue) {
throw new EndOfStreamException();
}
if (tag == 'O') {
return ReadObjectFull();
}
if (tag >= 0x60 && tag < 0x70) {
return ReadObjectCompact();
}
throw new UnexpectedTagException(tag.Value, "object");
}
private object ReadObjectFull()
{
reader.ReadByte();
var classDefId = ReadInteger();
var classDef = classDefs.Get(classDefId);
return ReadObjectCore(classDef);
}
private object ReadObjectCompact()
{
var classDefId = reader.ReadByte() - 0x60;
var classDef = classDefs.Get(classDefId);
return ReadObjectCore(classDef);
}
private object ReadObjectCore(ClassDef classDef)
{
// XXX: This needs a better implementation - maybe, you know, constructing
// the requested type?
var builder = HessianObject.Builder.New(classDef.Name);
objectRefs.Add(builder.Object);
foreach (var field in classDef.Fields) {
builder.Add(field, ReadValue());
}
return builder.Create();
}
#endregion
public object ReadNull()
{
reader.ReadByte();
return null;
}
public object ReadRef()
{
var tag = reader.Peek();
if (!tag.HasValue) {
throw new EndOfStreamException();
}
if (tag != 0x51) {
throw new UnexpectedTagException(tag.Value, "ref");
}
return objectRefs.Get(ReadInteger());
}
private static int IntFromBytes(byte[] buffer, int offset)
{
return (buffer[offset + 0] << 0x18)
| (buffer[offset + 1] << 0x10)
| (buffer[offset + 2] << 0x08)
| (buffer[offset + 3] << 0x00);
}
private static long LongFromBytes(byte[] buffer, int offset)
{
return (buffer[offset + 0] << 0x38)
| (buffer[offset + 1] << 0x30)
| (buffer[offset + 2] << 0x28)
| (buffer[offset + 3] << 0x20)
| (buffer[offset + 4] << 0x18)
| (buffer[offset + 5] << 0x10)
| (buffer[offset + 6] << 0x08)
| (buffer[offset + 7] << 0x00);
}
}
}

@ -0,0 +1,46 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Hessian
{
public class DictionaryTypeResolver
{
private readonly Dictionary<string, Func<IDictionary<object, object>>> constructors;
public DictionaryTypeResolver()
{
constructors = new Dictionary<string, Func<IDictionary<object, object>>> {
{"System.Collections.Hashtable", DefaultCtor},
{"System.Collections.Generic.IDictionary`2", DefaultCtor},
{"System.Collections.Generic.Dictionary`2", DefaultCtor},
{"System.Collections.IDictionary", DefaultCtor},
{"java.lang.Map", DefaultCtor},
{"java.util.HashMap", DefaultCtor},
{"java.util.EnumMap", DefaultCtor},
{"java.util.TreeMap", DefaultCtor},
{"java.util.concurrent.ConcurrentHashMap", DefaultCtor}
};
}
public bool TryGetInstance(string type, out IDictionary<object, object> instance)
{
instance = null;
if (!constructors.TryGetValue(type, out var ctor)) {
return false;
}
instance = ctor();
return true;
}
private static IDictionary<object, object> DefaultCtor()
{
return new Dictionary<object, object>();
}
}
}

@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.2</TargetFramework>
</PropertyGroup>
</Project>

@ -0,0 +1,24 @@
using System;
namespace Hessian
{
public class HessianException : ApplicationException
{
public HessianException()
{
}
public HessianException(string message)
: base(message)
{
}
public HessianException(string message, Exception innerException)
: base(message, innerException)
{
}
}
}

@ -0,0 +1,75 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
namespace Hessian
{
public class HessianObject : IReadOnlyCollection<Tuple<string, object>>
{
private readonly string typeName;
private readonly IDictionary<string, object> fields;
public string TypeName
{
get { return typeName; }
}
public object this[string key]
{
get { return fields[key]; }
}
public int Count
{
get { return fields.Count; }
}
private HessianObject(string typeName)
{
this.typeName = Conditions.CheckNotNull(typeName, "typeName");
fields = new Dictionary<string, object>();
}
public IEnumerator<Tuple<string, object>> GetEnumerator()
{
return fields.Select(kvp => Tuple.Create(kvp.Key, kvp.Value)).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public class Builder
{
private readonly HessianObject obj;
public HessianObject Object
{
get { return obj; }
}
private Builder(string typeName)
{
obj = new HessianObject(typeName);
}
public static Builder New(string typeName)
{
return new Builder(typeName);
}
public Builder Add(string field, object value)
{
obj.fields.Add(field, value);
return this;
}
public HessianObject Create()
{
return obj;
}
}
}
}

@ -0,0 +1,15 @@
using System;
namespace Hessian
{
public class InvalidRefException : HessianException
{
public int RefId { get; private set; }
public InvalidRefException(int refId)
: base(String.Format("Invalid ref ID: {0}", refId))
{
RefId = refId;
}
}
}

@ -0,0 +1,66 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Hessian
{
public class ListTypeResolver
{
private readonly Dictionary<string, Func<IList<object>>> constructors = new Dictionary<string, Func<IList<object>>>();
private readonly Dictionary<string, Func<int, IList<object>>> length_constructors = new Dictionary<string, Func<int, IList<object>>>();
private readonly Func<IList<object>> empty_list_ctor = () => new List<object>();
private readonly Func<int, IList<object>> empty_list_ctor_with_length = length => new List<object>(length);
public ListTypeResolver()
{
constructors.Add("System.Collections.ArrayList", empty_list_ctor);
constructors.Add("System.Collections.List", empty_list_ctor);
constructors.Add("System.Collections.IList", empty_list_ctor);
constructors.Add("System.Collections.Generic.List`1", empty_list_ctor);
constructors.Add("System.Collections.Generic.IList`1", empty_list_ctor);
constructors.Add("System.Collections.ObjectModel.Collection`1", () => new Collection<object>());
constructors.Add("java.util.List", empty_list_ctor);
constructors.Add("java.util.Vector", empty_list_ctor);
constructors.Add("java.util.ArrayList", empty_list_ctor);
constructors.Add("java.util.LinkedList", empty_list_ctor);
length_constructors.Add("System.Collections.List", empty_list_ctor_with_length);
length_constructors.Add("System.Collections.IList", empty_list_ctor_with_length);
length_constructors.Add("System.Collections.Generic.List`1", empty_list_ctor_with_length);
length_constructors.Add("System.Collections.Generic.IList`1", empty_list_ctor_with_length);
length_constructors.Add("java.util.List", empty_list_ctor_with_length);
length_constructors.Add("java.util.Vector", empty_list_ctor_with_length);
length_constructors.Add("java.util.ArrayList", empty_list_ctor_with_length);
length_constructors.Add("java.util.LinkedList", empty_list_ctor_with_length);
}
public bool TryGetListInstance(string type, out IList<object> list)
{
list = null;
Func<IList<object>> ctor;
if (!constructors.TryGetValue(type, out ctor)) {
return false;
}
list = ctor();
return true;
}
public bool TryGetListInstance(string type, int length, out IList<object> list)
{
list = null;
Func<int, IList<object>> ctor;
if (!length_constructors.TryGetValue(type, out ctor)) {
return false;
}
list = ctor(length);
return true;
}
}
}

@ -0,0 +1,24 @@
using System;
using System.IO;
using System.Text;
namespace Hessian
{
class MainClass
{
public static void Main (string[] args)
{
Console.WriteLine ("Hello World!");
var bytes = Encoding.UTF8.GetBytes("Hessian");
var ms = new MemoryStream();
ms.WriteByte((byte)"Hessian".Length);
ms.Write (bytes, 0, bytes.Length);
ms.Position = 0;
var ds = new Deserializer(ms);
var actual = ds.ReadValue();
Console.WriteLine(actual);
}
}
}

@ -0,0 +1,142 @@
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);
}
}
}

@ -0,0 +1,25 @@
namespace Hessian.Platform
{
public class BigEndianBitConverter : EndianBitConverter
{
protected override long FromBytes(byte[] bytes, int offset, int count)
{
var result = 0L;
for (var i = 0; i < count; ++i)
{
result = (result << 8) | bytes[offset + i];
}
return result;
}
protected override void CopyBytes(long source, byte[] buffer, int offset, int count)
{
var end = offset + count - 1;
for (var i = 0; i < count; ++i)
{
buffer[end - i] = (byte)(source & 0xFF);
source >>= 8;
}
}
}
}

@ -0,0 +1,215 @@
using System;
using System.Runtime.InteropServices;
namespace Hessian.Platform
{
public abstract class EndianBitConverter
{
#region T -> byte[]
public byte[] GetBytes(bool value)
{
// One byte, no endianness
return BitConverter.GetBytes(value);
}
public byte[] GetBytes(char value)
{
return GetBytes(value, sizeof (char));
}
public byte[] GetBytes(short value)
{
return GetBytes(value, sizeof (short));
}
public byte[] GetBytes(ushort value)
{
return GetBytes(value, sizeof (ushort));
}
public byte[] GetBytes(int value)
{
return GetBytes(value, sizeof (int));
}
public byte[] GetBytes(uint value)
{
return GetBytes(value, sizeof (uint));
}
public byte[] GetBytes(long value)
{
return GetBytes(value, sizeof (long));
}
public byte[] GetBytes(ulong value)
{
return GetBytes((long)value, sizeof (ulong));
}
public byte[] GetBytes(float value)
{
return GetBytes(SingleToInt32(value), sizeof (int));
}
public byte[] GetBytes(double value)
{
return GetBytes(DoubleToInt64(value), sizeof (long));
}
private byte[] GetBytes(long value, int size)
{
var buffer = new byte[size];
CopyBytes(value, buffer, 0, size);
return buffer;
}
#endregion
#region byte[] -> T
public bool ToBoolean(byte[] value, int index)
{
// one byte, no endianness
return BitConverter.ToBoolean(value, index);
}
public char ToChar(byte[] value, int index)
{
return (char) FromBytes(value, index, sizeof (char));
}
public short ToInt16(byte[] value, int index)
{
return (short) FromBytes(value, index, sizeof (short));
}
public ushort ToUInt16(byte[] value, int index)
{
return (ushort) FromBytes(value, index, sizeof (ushort));
}
public int ToInt32(byte[] value, int index)
{
return (int) FromBytes(value, index, sizeof (int));
}
public uint ToUInt32(byte[] value, int index)
{
return (uint) FromBytes(value, index, sizeof (uint));
}
public long ToInt64(byte[] value, int index)
{
return FromBytes(value, index, sizeof (long));
}
public ulong ToUInt64(byte[] value, int index)
{
return (ulong) FromBytes(value, index, sizeof (ulong));
}
public float ToSingle(byte[] value, int index)
{
var int32 = (int) FromBytes(value, index, sizeof (int));
return Int32ToSingle(int32);
}
public double ToDouble(byte[] value, int index)
{
var int64 = FromBytes(value, index, sizeof (long));
return Int64ToDouble(int64);
}
#endregion
protected abstract long FromBytes(byte[] bytes, int offset, int count);
protected abstract void CopyBytes(long source, byte[] buffer, int index, int count);
private static int SingleToInt32(float value)
{
return new JonSkeetUnion32(value).AsInt;
}
private static float Int32ToSingle(int value)
{
return new JonSkeetUnion32(value).AsFloat;
}
private static long DoubleToInt64(double value)
{
return new JonSkeetUnion64(value).AsLong;
}
private static double Int64ToDouble(long value)
{
return new JonSkeetUnion64(value).AsDouble;
}
[StructLayout(LayoutKind.Explicit)]
private struct JonSkeetUnion32
{
[FieldOffset(0)]
private readonly int i;
[FieldOffset(0)]
private readonly float f;
public int AsInt
{
get { return i; }
}
public float AsFloat
{
get { return f; }
}
public JonSkeetUnion32(int value)
{
f = 0;
i = value;
}
public JonSkeetUnion32(float value)
{
i = 0;
f = value;
}
}
[StructLayout(LayoutKind.Explicit)]
private struct JonSkeetUnion64
{
[FieldOffset(0)]
private readonly long l;
[FieldOffset(0)]
private readonly double d;
public long AsLong
{
get { return l; }
}
public double AsDouble
{
get { return d; }
}
public JonSkeetUnion64(long value)
{
d = 0;
l = value;
}
public JonSkeetUnion64(double value)
{
l = 0;
d = value;
}
}
}
}

@ -0,0 +1,25 @@
namespace Hessian.Platform
{
public class LittleEndianBitConverter : EndianBitConverter
{
protected override long FromBytes(byte[] bytes, int offset, int count)
{
var result = 0L;
var end = offset + count - 1;
for (var i = 0; i < count; ++i)
{
result = (result << 8) | bytes[end - i];
}
return result;
}
protected override void CopyBytes(long source, byte[] buffer, int offset, int count)
{
for (var i = 0; i < count; ++i)
{
buffer[offset + i] = (byte)(source & 0xFF);
source >>= 8;
}
}
}
}

@ -0,0 +1,39 @@
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");
}
}
}
}

@ -0,0 +1,18 @@
namespace Hessian
{
public class UnexpectedTagException : HessianException
{
public byte Tag { get; private set; }
public UnexpectedTagException(byte tag, string expectedType)
: base(FormatErrorMessage(tag, expectedType))
{
Tag = tag;
}
private static string FormatErrorMessage(byte tag, string expectedType)
{
return string.Format("{0:X} is not a valid {1} tag.", tag, expectedType);
}
}
}

@ -0,0 +1,163 @@
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();
}
}
}
Loading…
Cancel
Save