Initial Package for Thrift

This commit is contained in:
wsycarlos 2025-12-15 11:34:28 +08:00
commit 3465725ed7
127 changed files with 9812 additions and 0 deletions

106
.gitignore vendored Normal file
View File

@ -0,0 +1,106 @@
# This .gitignore file should be placed at the root of your Unity project directory
#
# Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore
#
.utmp/
/[Ll]ibrary/
/[Tt]emp/
/[Oo]bj/
/[Bb]uild/
/[Bb]uilds/
/[Ll]ogs/
/[Uu]ser[Ss]ettings/
*.log
# By default unity supports Blender asset imports, *.blend1 blender files do not need to be commited to version control.
*.blend1
*.blend1.meta
# MemoryCaptures can get excessive in size.
# They also could contain extremely sensitive data
/[Mm]emoryCaptures/
# Recordings can get excessive in size
/[Rr]ecordings/
# Uncomment this line if you wish to ignore the asset store tools plugin
# /[Aa]ssets/AssetStoreTools*
# Autogenerated Jetbrains Rider plugin
/[Aa]ssets/Plugins/Editor/JetBrains*
# Jetbrains Rider personal-layer settings
*.DotSettings.user
# Visual Studio cache directory
.vs/
# Gradle cache directory
.gradle/
# Autogenerated VS/MD/Consulo solution and project files
ExportedObj/
.consulo/
*.csproj
*.unityproj
*.sln
*.suo
*.tmp
*.user
*.userprefs
*.pidb
*.booproj
*.svd
*.pdb
*.mdb
*.opendb
*.VC.db
# Unity3D generated meta files
*.pidb.meta
*.pdb.meta
*.mdb.meta
# Unity3D generated file on crash reports
sysinfo.txt
# Mono auto generated files
mono_crash.*
# Builds
*.apk
*.aab
*.unitypackage
*.unitypackage.meta
# Crashlytics generated file
crashlytics-build.properties
# TestRunner generated files
InitTestScene*.unity*
# Addressables default ignores, before user customizations
/ServerData
/[Aa]ssets/StreamingAssets/aa*
/[Aa]ssets/AddressableAssetsData/link.xml*
/[Aa]ssets/Addressables_Temp*
# By default, Addressables content builds will generate addressables_content_state.bin
# files in platform-specific subfolders, for example:
# /Assets/AddressableAssetsData/OSX/addressables_content_state.bin
/[Aa]ssets/AddressableAssetsData/*/*.bin*
# Visual Scripting auto-generated files
/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Flow/UnitOptions.db
/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Flow/UnitOptions.db.meta
/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Core/Property Providers
/[Aa]ssets/Unity.VisualScripting.Generated/VisualScripting.Core/Property Providers.meta
# Auto-generated scenes by play mode tests
/[Aa]ssets/[Ii]nit[Tt]est[Ss]cene*.unity*
.vsconfig
Logs/
[Aa]ssets/
[Pp]ublish/
.vscode/settings.json
*.dat

Binary file not shown.

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 3a88ce6a250be42458ee10a717243914
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9570817580e1c32429e39fada8dd7b18
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,115 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System.Collections;
using System.Collections.Generic;
namespace Thrift.Collections
{
// ReSharper disable once InconsistentNaming
public static class TCollections
{
/// <summary>
/// This will return true if the two collections are value-wise the same.
/// If the collection contains a collection, the collections will be compared using this method.
/// </summary>
public static bool Equals(IEnumerable first, IEnumerable second)
{
if (first == null && second == null)
{
return true;
}
if (first == null || second == null)
{
return false;
}
// for dictionaries, we need to compare keys and values separately
// because KeyValuePair<K,V>.Equals() will not do what we want
var fdict = first as IDictionary;
var sdict = second as IDictionary;
if ((fdict != null) || (sdict != null))
{
if ((fdict == null) || (sdict == null))
return false;
return TCollections.Equals(fdict.Keys, sdict.Keys)
&& TCollections.Equals(fdict.Values, sdict.Values);
}
var fiter = first.GetEnumerator();
var siter = second.GetEnumerator();
var fnext = fiter.MoveNext();
var snext = siter.MoveNext();
while (fnext && snext)
{
var fenum = fiter.Current as IEnumerable;
var senum = siter.Current as IEnumerable;
if (fenum != null && senum != null)
{
if (!Equals(fenum, senum))
{
return false;
}
}
else if (fenum == null ^ senum == null)
{
return false;
}
else if (!Equals(fiter.Current, siter.Current))
{
return false;
}
fnext = fiter.MoveNext();
snext = siter.MoveNext();
}
return fnext == snext;
}
/// <summary>
/// This returns a hashcode based on the value of the enumerable.
/// </summary>
public static int GetHashCode(IEnumerable enumerable)
{
if (enumerable == null)
{
return 0;
}
var hashcode = 0;
foreach (var obj in enumerable)
{
var objHash = (obj is IEnumerable enum2) ? GetHashCode(enum2) : obj.GetHashCode();
unchecked
{
hashcode = (hashcode * 397) ^ (objHash);
}
}
return hashcode;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6bd25820bab7e434aab147a0e6c0e8e7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,51 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Collections;
using System.Collections.Generic;
namespace Thrift.Collections
{
// ReSharper disable once InconsistentNaming
[Obsolete("deprecated, use HashSet<T> instead")]
public class THashSet<T> : System.Collections.Generic.HashSet<T>
{
public THashSet()
: base()
{
}
public THashSet(int capacity)
#if NET5_0_OR_GREATER
: base(capacity)
#elif NETFRAMEWORK || NETSTANDARD
: base(/*capacity not supported*/)
#else
#error Unknown platform
#endif
{
}
public THashSet(IEnumerable<T> collection)
: base(collection)
{
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e4336f3dc60386743b1c02f11df6fc99
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,34 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// This file is used by Code Analysis to maintain SuppressMessage
// attributes that are applied to this project.
// Project-level suppressions either have no target or are given
// a specific target and scoped to a namespace, type, member, etc.
using System.Diagnostics.CodeAnalysis;
// suppress certain messages for compatibility reasons with older C# versions we want to support
[assembly: SuppressMessage("Style", "IDE0057", Justification = "compatibility", Scope = "module")]
[assembly: SuppressMessage("Style", "IDE0066", Justification = "compatibility", Scope = "module")]
[assembly: SuppressMessage("Style", "IDE0090", Justification = "compatibility", Scope = "module")]
[assembly: SuppressMessage("Style", "IDE0063", Justification = "compatibility", Scope = "module")]
[assembly: SuppressMessage("Style", "IDE0130", Justification = "compatibility", Scope = "module")]
[assembly: SuppressMessage("Style", "IDE0290", Justification = "compatibility", Scope = "module")]
[assembly: SuppressMessage("Style", "CS0114", Justification = "known issue, see JIRA ticket", Scope = "module")]

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 595997754e2b7f541b41beda5001eabe
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5646b840c862f5a43a9f7fd65fd98e5f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,56 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System.Reflection;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Thrift")]
[assembly: AssemblyDescription("C# .NET Core bindings for the Apache Thrift RPC system")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("The Apache Software Foundation")]
[assembly: AssemblyProduct("Thrift")]
[assembly: AssemblyCopyright("The Apache Software Foundation")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//@TODO where to put License information?
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a exType in this assembly from
// COM, set the ComVisible attribute to true on that exType.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("df3f8ef0-e0a3-4c86-a65b-8ec84e016b1d")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("0.22.0.0")]
[assembly: AssemblyFileVersion("0.22.0.0")]

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cc3f9dc06d8829e43ab512a42384f133
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 172a2294fc8d1c74c9afd1ea617e1b86
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c6156f3fc3227424282ffe1caa5276ff
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,40 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#pragma warning disable IDE0079 // net20 - unneeded suppression
#pragma warning disable IDE0290 // net8 - primary CTOR
namespace Thrift.Protocol.Entities
{
// ReSharper disable once InconsistentNaming
public struct TField
{
public TField(string name, TType type, short id)
{
Name = name;
Type = type;
ID = id;
}
public string Name { get; set; }
public TType Type { get; set; }
// ReSharper disable once InconsistentNaming - do not rename - it used for generation
public short ID { get; set; }
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4cf4634e90ef156469d9c18a5ef260ba
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,36 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#pragma warning disable IDE0079 // net20 - unneeded suppression
#pragma warning disable IDE0290 // net8 - primary CTOR
namespace Thrift.Protocol.Entities
{
// ReSharper disable once InconsistentNaming
public struct TList
{
public TList(TType elementType, int count)
{
ElementType = elementType;
Count = count;
}
public TType ElementType { get; set; }
public int Count { get; set; }
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e853389f4c494204897e587c81be25ca
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,39 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#pragma warning disable IDE0079 // net20 - unneeded suppression
#pragma warning disable IDE0290 // net8 - primary CTOR
namespace Thrift.Protocol.Entities
{
// ReSharper disable once InconsistentNaming
public struct TMap
{
public TMap(TType keyType, TType valueType, int count)
{
KeyType = keyType;
ValueType = valueType;
Count = count;
}
public TType KeyType { get; set; }
public TType ValueType { get; set; }
public int Count { get; set; }
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4c32933786e22b34286eb36df8f3c354
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,40 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#pragma warning disable IDE0079 // net20 - unneeded suppression
#pragma warning disable IDE0290 // net8 - primary CTOR
namespace Thrift.Protocol.Entities
{
// ReSharper disable once InconsistentNaming
public struct TMessage
{
public TMessage(string name, TMessageType type, int seqid)
{
Name = name;
Type = type;
SeqID = seqid;
}
public string Name { get; set; }
public TMessageType Type { get; set; }
// ReSharper disable once InconsistentNaming - do not rename - it used for generation
public int SeqID { get; set; }
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 930f6d7df6e483743b9814df89e7f4ff
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,28 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
namespace Thrift.Protocol.Entities
{
// ReSharper disable once InconsistentNaming
public enum TMessageType
{
Call = 1,
Reply = 2,
Exception = 3,
Oneway = 4
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a12e210a3b515904c9efc20848c86157
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,41 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#pragma warning disable IDE0079 // net20 - unneeded suppression
#pragma warning disable IDE0290 // net8 - primary CTOR
namespace Thrift.Protocol.Entities
{
// ReSharper disable once InconsistentNaming
public struct TSet
{
public TSet(TType elementType, int count)
{
ElementType = elementType;
Count = count;
}
public TSet(TList list)
: this(list.ElementType, list.Count)
{
}
public TType ElementType { get; set; }
public int Count { get; set; }
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8f793acd60eaa194baa0acc12bd2363c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,33 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#pragma warning disable IDE0079 // net20 - unneeded suppression
#pragma warning disable IDE0290 // net8 - primary CTOR
namespace Thrift.Protocol.Entities
{
// ReSharper disable once InconsistentNaming
public readonly struct TStruct
{
public TStruct(string name)
{
Name = name;
}
public string Name { get; }
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7375aae91c68c944a812e233bdf45f7d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,38 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
namespace Thrift.Protocol.Entities
{
// ReSharper disable once InconsistentNaming
public enum TType : byte
{
Stop = 0,
Void = 1,
Bool = 2,
Byte = 3,
Double = 4,
I16 = 6,
I32 = 8,
I64 = 10,
String = 11,
Struct = 12,
Map = 13,
Set = 14,
List = 15,
Uuid = 16
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: aca0928aaf4273349b4a3aaab6c86eab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,36 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System.Threading;
using System.Threading.Tasks;
#pragma warning disable IDE1006 // some interfaces here are intentionally not I-prefixed
namespace Thrift.Protocol
{
public interface TUnionBase
{
Task WriteAsync(TProtocol tProtocol, CancellationToken cancellationToken = default);
}
// ReSharper disable once InconsistentNaming
public interface TBase : TUnionBase
{
Task ReadAsync(TProtocol tProtocol, CancellationToken cancellationToken = default);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d678ef8837850994788ab62b1041d807
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,496 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Buffers.Binary;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Thrift.Protocol.Entities;
using Thrift.Protocol.Utilities;
using Thrift.Transport;
#pragma warning disable IDE0079 // net20 - unneeded suppression
#pragma warning disable IDE0290 // net8 - primary CTOR
namespace Thrift.Protocol
{
// ReSharper disable once InconsistentNaming
public class TBinaryProtocol : TProtocol
{
protected const uint VersionMask = 0xffff0000;
protected const uint Version1 = 0x80010000;
protected readonly bool StrictRead;
protected readonly bool StrictWrite;
// minimize memory allocations by means of an preallocated bytes buffer
// The value of 128 is arbitrarily chosen, the required minimum size must be sizeof(long)
private readonly byte[] PreAllocatedBuffer = new byte[128];
public TBinaryProtocol(TTransport trans)
: this(trans, false, true)
{
}
public TBinaryProtocol(TTransport trans, bool strictRead, bool strictWrite)
: base(trans)
{
StrictRead = strictRead;
StrictWrite = strictWrite;
}
public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (StrictWrite)
{
var version = Version1 | (uint) message.Type;
await WriteI32Async((int) version, cancellationToken);
await WriteStringAsync(message.Name, cancellationToken);
await WriteI32Async(message.SeqID, cancellationToken);
}
else
{
await WriteStringAsync(message.Name, cancellationToken);
await WriteByteAsync((sbyte) message.Type, cancellationToken);
await WriteI32Async(message.SeqID, cancellationToken);
}
}
public override Task WriteMessageEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override Task WriteStructBeginAsync(TStruct @struct, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override Task WriteStructEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await WriteByteAsync((sbyte) field.Type, cancellationToken);
await WriteI16Async(field.ID, cancellationToken);
}
public override Task WriteFieldEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override async Task WriteFieldStopAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await WriteByteAsync((sbyte) TType.Stop, cancellationToken);
}
public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
PreAllocatedBuffer[0] = (byte)map.KeyType;
PreAllocatedBuffer[1] = (byte)map.ValueType;
await Trans.WriteAsync(PreAllocatedBuffer, 0, 2, cancellationToken);
await WriteI32Async(map.Count, cancellationToken);
}
public override Task WriteMapEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await WriteByteAsync((sbyte) list.ElementType, cancellationToken);
await WriteI32Async(list.Count, cancellationToken);
}
public override Task WriteListEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await WriteByteAsync((sbyte) set.ElementType, cancellationToken);
await WriteI32Async(set.Count, cancellationToken);
}
public override Task WriteSetEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await WriteByteAsync(b ? (sbyte) 1 : (sbyte) 0, cancellationToken);
}
public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
PreAllocatedBuffer[0] = (byte)b;
await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
}
public override async Task WriteI16Async(short i16, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
BinaryPrimitives.WriteInt16BigEndian(PreAllocatedBuffer, i16);
await Trans.WriteAsync(PreAllocatedBuffer, 0, 2, cancellationToken);
}
public override async Task WriteI32Async(int i32, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
BinaryPrimitives.WriteInt32BigEndian(PreAllocatedBuffer, i32);
await Trans.WriteAsync(PreAllocatedBuffer, 0, 4, cancellationToken);
}
public override async Task WriteI64Async(long i64, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
BinaryPrimitives.WriteInt64BigEndian(PreAllocatedBuffer, i64);
await Trans.WriteAsync(PreAllocatedBuffer, 0, 8, cancellationToken);
}
public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await WriteI64Async(BitConverter.DoubleToInt64Bits(d), cancellationToken);
}
public override async Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await WriteI32Async(bytes.Length, cancellationToken);
await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
}
public override async Task WriteUuidAsync(Guid uuid, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var bytes = uuid.SwapByteOrder().ToByteArray();
await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
}
public override async ValueTask<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var message = new TMessage();
var size = await ReadI32Async(cancellationToken);
if (size < 0)
{
var version = (uint) size & VersionMask;
if (version != Version1)
{
throw new TProtocolException(TProtocolException.BAD_VERSION,
$"Bad version in ReadMessageBegin: {version}");
}
message.Type = (TMessageType) (size & 0x000000ff);
message.Name = await ReadStringAsync(cancellationToken);
message.SeqID = await ReadI32Async(cancellationToken);
}
else
{
if (StrictRead)
{
throw new TProtocolException(TProtocolException.BAD_VERSION,
"Missing version in ReadMessageBegin, old client?");
}
message.Name = (size > 0) ? await ReadStringBodyAsync(size, cancellationToken) : string.Empty;
message.Type = (TMessageType) await ReadByteAsync(cancellationToken);
message.SeqID = await ReadI32Async(cancellationToken);
}
return message;
}
public override Task ReadMessageEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
Transport.ResetMessageSizeAndConsumedBytes();
return Task.CompletedTask;
}
public override ValueTask<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return new ValueTask<TStruct>(AnonymousStruct);
}
public override Task ReadStructEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override async ValueTask<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var type = (TType)await ReadByteAsync(cancellationToken);
if (type == TType.Stop)
{
return StopField;
}
return new TField {
Type = type,
ID = await ReadI16Async(cancellationToken)
};
}
public override Task ReadFieldEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override async ValueTask<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var map = new TMap
{
KeyType = (TType) await ReadByteAsync(cancellationToken),
ValueType = (TType) await ReadByteAsync(cancellationToken),
Count = await ReadI32Async(cancellationToken)
};
CheckReadBytesAvailable(map);
return map;
}
public override Task ReadMapEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override async ValueTask<TList> ReadListBeginAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var list = new TList
{
ElementType = (TType) await ReadByteAsync(cancellationToken),
Count = await ReadI32Async(cancellationToken)
};
CheckReadBytesAvailable(list);
return list;
}
public override Task ReadListEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override async ValueTask<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var set = new TSet
{
ElementType = (TType) await ReadByteAsync(cancellationToken),
Count = await ReadI32Async(cancellationToken)
};
CheckReadBytesAvailable(set);
return set;
}
public override Task ReadSetEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override async ValueTask<bool> ReadBoolAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return await ReadByteAsync(cancellationToken) == 1;
}
public override async ValueTask<sbyte> ReadByteAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
return (sbyte)PreAllocatedBuffer[0];
}
public override async ValueTask<short> ReadI16Async(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 2, cancellationToken);
var result = BinaryPrimitives.ReadInt16BigEndian(PreAllocatedBuffer);
return result;
}
public override async ValueTask<int> ReadI32Async(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 4, cancellationToken);
var result = BinaryPrimitives.ReadInt32BigEndian(PreAllocatedBuffer);
return result;
}
public override async ValueTask<long> ReadI64Async(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 8, cancellationToken);
return BinaryPrimitives.ReadInt64BigEndian(PreAllocatedBuffer);
}
public override async ValueTask<double> ReadDoubleAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var d = await ReadI64Async(cancellationToken);
return BitConverter.Int64BitsToDouble(d);
}
public override async ValueTask<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var size = await ReadI32Async(cancellationToken);
Transport.CheckReadBytesAvailable(size);
var buf = new byte[size];
await Trans.ReadAllAsync(buf, 0, size, cancellationToken);
return buf;
}
public override async ValueTask<Guid> ReadUuidAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
Transport.CheckReadBytesAvailable(16); // = sizeof(uuid)
var buf = new byte[16];
await Trans.ReadAllAsync(buf, 0, 16, cancellationToken);
return new Guid(buf).SwapByteOrder();
}
public override async ValueTask<string> ReadStringAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var size = await ReadI32Async(cancellationToken);
return size > 0 ? await ReadStringBodyAsync(size, cancellationToken) : string.Empty;
}
private async ValueTask<string> ReadStringBodyAsync(int size, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (size <= PreAllocatedBuffer.Length)
{
await Trans.ReadAllAsync(PreAllocatedBuffer, 0, size, cancellationToken);
return Encoding.UTF8.GetString(PreAllocatedBuffer, 0, size);
}
Transport.CheckReadBytesAvailable(size);
var buf = new byte[size];
await Trans.ReadAllAsync(buf, 0, size, cancellationToken);
return Encoding.UTF8.GetString(buf, 0, buf.Length);
}
// Return the minimum number of bytes a type will consume on the wire
public override int GetMinSerializedSize(TType type)
{
switch (type)
{
case TType.Stop: return 0;
case TType.Void: return 0;
case TType.Bool: return sizeof(byte);
case TType.Byte: return sizeof(byte);
case TType.Double: return sizeof(double);
case TType.I16: return sizeof(short);
case TType.I32: return sizeof(int);
case TType.I64: return sizeof(long);
case TType.String: return sizeof(int); // string length
case TType.Struct: return 0; // empty struct
case TType.Map: return sizeof(int); // element count
case TType.Set: return sizeof(int); // element count
case TType.List: return sizeof(int); // element count
case TType.Uuid: return 16; // uuid bytes
default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code");
}
}
public class Factory : TProtocolFactory
{
protected readonly bool StrictRead;
protected readonly bool StrictWrite;
// emtpy default CTOR required
public Factory()
: this(false, true)
{
}
public Factory(bool strictRead, bool strictWrite)
{
StrictRead = strictRead;
StrictWrite = strictWrite;
}
public override TProtocol GetProtocol(TTransport trans)
{
return new TBinaryProtocol(trans, StrictRead, StrictWrite);
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 560b2c8f00f662f46a9ebd661e8b62bb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,866 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Thrift.Protocol.Entities;
using Thrift.Protocol.Utilities;
using Thrift.Transport;
#pragma warning disable IDE0079 // net20 - unneeded suppression
#pragma warning disable IDE0301 // net8 - simplified collection init
namespace Thrift.Protocol
{
// ReSharper disable once InconsistentNaming
public class TCompactProtocol : TProtocol
{
private const byte ProtocolId = 0x82;
private const byte Version = 1;
private const byte VersionMask = 0x1f; // 0001 1111
private const byte TypeMask = 0xE0; // 1110 0000
private const byte TypeBits = 0x07; // 0000 0111
private const int TypeShiftAmount = 5;
private const byte NoTypeOverride = 0xFF;
// ReSharper disable once InconsistentNaming
private static readonly byte[] TTypeToCompactType = new byte[17];
private static readonly TType[] CompactTypeToTType = new TType[14];
/// <summary>
/// Used to keep track of the last field for the current and previous structs, so we can do the delta stuff.
/// </summary>
private readonly Stack<short> _lastField = new Stack<short>(15);
/// <summary>
/// If we encounter a boolean field begin, save the TField here so it can have the value incorporated.
/// </summary>
private TField? _booleanField;
/// <summary>
/// If we Read a field header, and it's a boolean field, save the boolean value here so that ReadBool can use it.
/// </summary>
private bool? _boolValue;
private short _lastFieldId;
// minimize memory allocations by means of an preallocated bytes buffer
// The value of 128 is arbitrarily chosen, the required minimum size must be sizeof(long)
private readonly byte[] PreAllocatedBuffer = new byte[128];
private struct VarInt
{
public byte[] bytes;
public int count;
}
// minimize memory allocations by means of an preallocated VarInt buffer
private VarInt PreAllocatedVarInt = new VarInt()
{
bytes = new byte[10], // see Int64ToVarInt()
count = 0
};
public TCompactProtocol(TTransport trans)
: base(trans)
{
TTypeToCompactType[(int)TType.Stop] = Types.Stop;
TTypeToCompactType[(int)TType.Bool] = Types.BooleanTrue;
TTypeToCompactType[(int)TType.Byte] = Types.Byte;
TTypeToCompactType[(int)TType.I16] = Types.I16;
TTypeToCompactType[(int)TType.I32] = Types.I32;
TTypeToCompactType[(int)TType.I64] = Types.I64;
TTypeToCompactType[(int)TType.Double] = Types.Double;
TTypeToCompactType[(int)TType.String] = Types.Binary;
TTypeToCompactType[(int)TType.List] = Types.List;
TTypeToCompactType[(int)TType.Set] = Types.Set;
TTypeToCompactType[(int)TType.Map] = Types.Map;
TTypeToCompactType[(int)TType.Struct] = Types.Struct;
TTypeToCompactType[(int)TType.Uuid] = Types.Uuid;
CompactTypeToTType[Types.Stop] = TType.Stop;
CompactTypeToTType[Types.BooleanTrue] = TType.Bool;
CompactTypeToTType[Types.BooleanFalse] = TType.Bool;
CompactTypeToTType[Types.Byte] = TType.Byte;
CompactTypeToTType[Types.I16] = TType.I16;
CompactTypeToTType[Types.I32] = TType.I32;
CompactTypeToTType[Types.I64] = TType.I64;
CompactTypeToTType[Types.Double] = TType.Double;
CompactTypeToTType[Types.Binary] = TType.String;
CompactTypeToTType[Types.List] = TType.List;
CompactTypeToTType[Types.Set] = TType.Set;
CompactTypeToTType[Types.Map] = TType.Map;
CompactTypeToTType[Types.Struct] = TType.Struct;
CompactTypeToTType[Types.Uuid] = TType.Uuid;
}
public void Reset()
{
_lastField.Clear();
_lastFieldId = 0;
}
public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken)
{
PreAllocatedBuffer[0] = ProtocolId;
PreAllocatedBuffer[1] = (byte)((Version & VersionMask) | (((uint)message.Type << TypeShiftAmount) & TypeMask));
await Trans.WriteAsync(PreAllocatedBuffer, 0, 2, cancellationToken);
Int32ToVarInt((uint) message.SeqID, ref PreAllocatedVarInt);
await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
await WriteStringAsync(message.Name, cancellationToken);
}
public override Task WriteMessageEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
/// <summary>
/// Write a struct begin. This doesn't actually put anything on the wire. We
/// use it as an opportunity to put special placeholder markers on the field
/// stack so we can get the field id deltas correct.
/// </summary>
public override Task WriteStructBeginAsync(TStruct @struct, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
_lastField.Push(_lastFieldId);
_lastFieldId = 0;
return Task.CompletedTask;
}
public override Task WriteStructEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
_lastFieldId = _lastField.Pop();
return Task.CompletedTask;
}
private async Task WriteFieldBeginInternalAsync(TField field, byte fieldType, CancellationToken cancellationToken)
{
// if there's a exType override passed in, use that. Otherwise ask GetCompactType().
if (fieldType == NoTypeOverride)
fieldType = GetCompactType(field.Type);
// check if we can use delta encoding for the field id
if (field.ID > _lastFieldId)
{
var delta = field.ID - _lastFieldId;
if (delta <= 15)
{
// Write them together
PreAllocatedBuffer[0] = (byte)((delta << 4) | fieldType);
await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
_lastFieldId = field.ID;
return;
}
}
// Write them separate
PreAllocatedBuffer[0] = fieldType;
await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
await WriteI16Async(field.ID, cancellationToken);
_lastFieldId = field.ID;
}
public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken)
{
if (field.Type == TType.Bool)
{
_booleanField = field;
}
else
{
await WriteFieldBeginInternalAsync(field, NoTypeOverride, cancellationToken);
}
}
public override Task WriteFieldEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override async Task WriteFieldStopAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
PreAllocatedBuffer[0] = Types.Stop;
await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
}
protected async Task WriteCollectionBeginAsync(TType elemType, int size, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
/*
Abstract method for writing the start of lists and sets. List and sets on
the wire differ only by the exType indicator.
*/
if (size <= 14)
{
PreAllocatedBuffer[0] = (byte)((size << 4) | GetCompactType(elemType));
await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
}
else
{
PreAllocatedBuffer[0] = (byte)(0xf0 | GetCompactType(elemType));
await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
Int32ToVarInt((uint) size, ref PreAllocatedVarInt);
await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
}
}
public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken)
{
await WriteCollectionBeginAsync(list.ElementType, list.Count, cancellationToken);
}
public override Task WriteListEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await WriteCollectionBeginAsync(set.ElementType, set.Count, cancellationToken);
}
public override Task WriteSetEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
/*
Write a boolean value. Potentially, this could be a boolean field, in
which case the field header info isn't written yet. If so, decide what the
right exType header is for the value and then Write the field header.
Otherwise, Write a single byte.
*/
if (_booleanField != null)
{
// we haven't written the field header yet
var type = b ? Types.BooleanTrue : Types.BooleanFalse;
await WriteFieldBeginInternalAsync(_booleanField.Value, type, cancellationToken);
_booleanField = null;
}
else
{
// we're not part of a field, so just write the value.
PreAllocatedBuffer[0] = b ? Types.BooleanTrue : Types.BooleanFalse;
await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
}
}
public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
PreAllocatedBuffer[0] = (byte)b;
await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
}
public override async Task WriteI16Async(short i16, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
Int32ToVarInt(IntToZigzag(i16), ref PreAllocatedVarInt);
await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
}
private static void Int32ToVarInt(uint n, ref VarInt varint)
{
// Write an i32 as a varint. Results in 1 - 5 bytes on the wire.
varint.count = 0;
Debug.Assert(varint.bytes.Length >= 5);
while (true)
{
if ((n & ~0x7F) == 0)
{
varint.bytes[varint.count++] = (byte)n;
break;
}
varint.bytes[varint.count++] = (byte)((n & 0x7F) | 0x80);
n >>= 7;
}
}
public override async Task WriteI32Async(int i32, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
Int32ToVarInt(IntToZigzag(i32), ref PreAllocatedVarInt);
await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
}
static private void Int64ToVarInt(ulong n, ref VarInt varint)
{
// Write an i64 as a varint. Results in 1-10 bytes on the wire.
varint.count = 0;
Debug.Assert(varint.bytes.Length >= 10);
while (true)
{
if ((n & ~(ulong)0x7FL) == 0)
{
varint.bytes[varint.count++] = (byte)n;
break;
}
varint.bytes[varint.count++] = (byte)((n & 0x7F) | 0x80);
n >>= 7;
}
}
public override async Task WriteI64Async(long i64, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
Int64ToVarInt(LongToZigzag(i64), ref PreAllocatedVarInt);
await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
}
public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
BinaryPrimitives.WriteInt64LittleEndian(PreAllocatedBuffer, BitConverter.DoubleToInt64Bits(d));
await Trans.WriteAsync(PreAllocatedBuffer, 0, 8, cancellationToken);
}
public override async Task WriteStringAsync(string str, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var buf = ArrayPool<byte>.Shared.Rent(Encoding.UTF8.GetByteCount(str));
try
{
var numberOfBytes = Encoding.UTF8.GetBytes(str, 0, str.Length, buf, 0);
Int32ToVarInt((uint)numberOfBytes, ref PreAllocatedVarInt);
await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
await Trans.WriteAsync(buf, 0, numberOfBytes, cancellationToken);
}
finally
{
ArrayPool<byte>.Shared.Return(buf);
}
}
public override async Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
Int32ToVarInt((uint) bytes.Length, ref PreAllocatedVarInt);
await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
}
public override async Task WriteUuidAsync(Guid uuid, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var bytes = uuid.SwapByteOrder().ToByteArray();
await Trans.WriteAsync(bytes, 0, bytes.Length, cancellationToken);
}
public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (map.Count == 0)
{
PreAllocatedBuffer[0] = 0;
await Trans.WriteAsync( PreAllocatedBuffer, 0, 1, cancellationToken);
}
else
{
Int32ToVarInt((uint) map.Count, ref PreAllocatedVarInt);
await Trans.WriteAsync(PreAllocatedVarInt.bytes, 0, PreAllocatedVarInt.count, cancellationToken);
PreAllocatedBuffer[0] = (byte)((GetCompactType(map.KeyType) << 4) | GetCompactType(map.ValueType));
await Trans.WriteAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
}
}
public override Task WriteMapEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override async ValueTask<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
var protocolId = (byte) await ReadByteAsync(cancellationToken);
if (protocolId != ProtocolId)
{
throw new TProtocolException($"Expected protocol id {ProtocolId:X} but got {protocolId:X}");
}
var versionAndType = (byte) await ReadByteAsync(cancellationToken);
var version = (byte) (versionAndType & VersionMask);
if (version != Version)
{
throw new TProtocolException($"Expected version {Version} but got {version}");
}
var type = (byte) ((versionAndType >> TypeShiftAmount) & TypeBits);
var seqid = (int) await ReadVarInt32Async(cancellationToken);
var messageName = await ReadStringAsync(cancellationToken);
return new TMessage(messageName, (TMessageType) type, seqid);
}
public override Task ReadMessageEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
Transport.ResetMessageSizeAndConsumedBytes();
return Task.CompletedTask;
}
public override ValueTask<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
_lastField.Push(_lastFieldId);
_lastFieldId = 0;
return new ValueTask<TStruct>(AnonymousStruct);
}
public override Task ReadStructEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
/*
Doesn't actually consume any wire data, just removes the last field for
this struct from the field stack.
*/
// consume the last field we Read off the wire.
_lastFieldId = _lastField.Pop();
return Task.CompletedTask;
}
public override async ValueTask<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
{
// Read a field header off the wire.
var type = (byte) await ReadByteAsync(cancellationToken);
// if it's a stop, then we can return immediately, as the struct is over.
if (type == Types.Stop)
{
return StopField;
}
// mask off the 4 MSB of the exType header. it could contain a field id delta.
var modifier = (short) ((type & 0xf0) >> 4);
var compactType = (byte)(type & 0x0f);
short fieldId;
if (modifier == 0)
{
fieldId = await ReadI16Async(cancellationToken);
}
else
{
fieldId = (short) (_lastFieldId + modifier);
}
var ttype = GetTType(compactType);
var field = new TField(string.Empty, ttype, fieldId);
// if this happens to be a boolean field, the value is encoded in the exType
if( ttype == TType.Bool)
{
_boolValue = (compactType == Types.BooleanTrue);
}
// push the new field onto the field stack so we can keep the deltas going.
_lastFieldId = field.ID;
return field;
}
public override Task ReadFieldEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override async ValueTask<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
/*
Read a map header off the wire. If the size is zero, skip Reading the key
and value exType. This means that 0-length maps will yield TMaps without the
"correct" types.
*/
var size = (int) await ReadVarInt32Async(cancellationToken);
var keyAndValueType = size == 0 ? (byte) 0 : (byte) await ReadByteAsync(cancellationToken);
var map = new TMap(GetTType((byte) (keyAndValueType >> 4)), GetTType((byte) (keyAndValueType & 0xf)), size);
CheckReadBytesAvailable(map);
return map;
}
public override Task ReadMapEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override async ValueTask<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
{
/*
Read a set header off the wire. If the set size is 0-14, the size will
be packed into the element exType header. If it's a longer set, the 4 MSB
of the element exType header will be 0xF, and a varint will follow with the
true size.
*/
return new TSet(await ReadListBeginAsync(cancellationToken));
}
public override ValueTask<bool> ReadBoolAsync(CancellationToken cancellationToken)
{
/*
Read a boolean off the wire. If this is a boolean field, the value should
already have been Read during ReadFieldBegin, so we'll just consume the
pre-stored value. Otherwise, Read a byte.
*/
if (_boolValue != null)
{
var result = _boolValue.Value;
_boolValue = null;
return new ValueTask<bool>(result);
}
return InternalCall();
async ValueTask<bool> InternalCall()
{
var data = await ReadByteAsync(cancellationToken);
return (data == Types.BooleanTrue);
}
}
public override async ValueTask<sbyte> ReadByteAsync(CancellationToken cancellationToken)
{
// Read a single byte off the wire. Nothing interesting here.
await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 1, cancellationToken);
return (sbyte)PreAllocatedBuffer[0];
}
public override async ValueTask<short> ReadI16Async(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return (short) ZigzagToInt(await ReadVarInt32Async(cancellationToken));
}
public override async ValueTask<int> ReadI32Async(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return ZigzagToInt(await ReadVarInt32Async(cancellationToken));
}
public override async ValueTask<long> ReadI64Async(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return ZigzagToLong(await ReadVarInt64Async(cancellationToken));
}
public override async ValueTask<double> ReadDoubleAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await Trans.ReadAllAsync(PreAllocatedBuffer, 0, 8, cancellationToken);
return BitConverter.Int64BitsToDouble(BinaryPrimitives.ReadInt64LittleEndian(PreAllocatedBuffer));
}
public override async ValueTask<string> ReadStringAsync(CancellationToken cancellationToken)
{
// read length
var length = (int) await ReadVarInt32Async(cancellationToken);
if (length == 0)
{
return string.Empty;
}
// read and decode data
if (length < PreAllocatedBuffer.Length)
{
await Trans.ReadAllAsync(PreAllocatedBuffer, 0, length, cancellationToken);
return Encoding.UTF8.GetString(PreAllocatedBuffer, 0, length);
}
Transport.CheckReadBytesAvailable(length);
var buf = ArrayPool<byte>.Shared.Rent(length);
try
{
await Trans.ReadAllAsync(buf, 0, length, cancellationToken);
return Encoding.UTF8.GetString(buf, 0, length);
}
finally
{
ArrayPool<byte>.Shared.Return(buf);
}
}
public override async ValueTask<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
{
// read length
var length = (int) await ReadVarInt32Async(cancellationToken);
if (length == 0)
{
return Array.Empty<byte>();
}
// read data
Transport.CheckReadBytesAvailable(length);
var buf = new byte[length];
await Trans.ReadAllAsync(buf, 0, length, cancellationToken);
return buf;
}
public override async ValueTask<Guid> ReadUuidAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
Transport.CheckReadBytesAvailable(16); // = sizeof(uuid)
var buf = new byte[16];
await Trans.ReadAllAsync(buf, 0, 16, cancellationToken);
return new Guid(buf).SwapByteOrder();
}
public override async ValueTask<TList> ReadListBeginAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
/*
Read a list header off the wire. If the list size is 0-14, the size will
be packed into the element exType header. If it's a longer list, the 4 MSB
of the element exType header will be 0xF, and a varint will follow with the
true size.
*/
var sizeAndType = (byte) await ReadByteAsync(cancellationToken);
var size = (sizeAndType >> 4) & 0x0f;
if (size == 15)
{
size = (int) await ReadVarInt32Async(cancellationToken);
}
var type = GetTType(sizeAndType);
var list = new TList(type, size);
CheckReadBytesAvailable(list);
return list;
}
public override Task ReadListEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override Task ReadSetEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
private static byte GetCompactType(TType ttype)
{
// Given a TType value, find the appropriate TCompactProtocol.Types constant.
return TTypeToCompactType[(int) ttype];
}
private async ValueTask<uint> ReadVarInt32Async(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
/*
Read an i32 from the wire as a varint. The MSB of each byte is set
if there is another byte to follow. This can Read up to 5 bytes.
*/
uint result = 0;
var shift = 0;
while (true)
{
var b = (byte) await ReadByteAsync(cancellationToken);
result |= (uint) (b & 0x7f) << shift;
if ((b & 0x80) != 0x80)
{
break;
}
shift += 7;
}
return result;
}
private async ValueTask<ulong> ReadVarInt64Async(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
/*
Read an i64 from the wire as a proper varint. The MSB of each byte is set
if there is another byte to follow. This can Read up to 10 bytes.
*/
var shift = 0;
ulong result = 0;
while (true)
{
var b = (byte) await ReadByteAsync(cancellationToken);
result |= (ulong) (b & 0x7f) << shift;
if ((b & 0x80) != 0x80)
{
break;
}
shift += 7;
}
return result;
}
private static int ZigzagToInt(uint n)
{
return (int) (n >> 1) ^ -(int) (n & 1);
}
private static long ZigzagToLong(ulong n)
{
return (long) (n >> 1) ^ -(long) (n & 1);
}
private static TType GetTType(byte type)
{
// Given a TCompactProtocol.Types constant, convert it to its corresponding TType value.
return CompactTypeToTType[type & 0x0f];
}
private static ulong LongToZigzag(long n)
{
// Convert l into a zigzag long. This allows negative numbers to be represented compactly as a varint
return (ulong) (n << 1) ^ (ulong) (n >> 63);
}
private static uint IntToZigzag(int n)
{
// Convert n into a zigzag int. This allows negative numbers to be represented compactly as a varint
return (uint) (n << 1) ^ (uint) (n >> 31);
}
// Return the minimum number of bytes a type will consume on the wire
public override int GetMinSerializedSize(TType type)
{
switch (type)
{
case TType.Stop: return 0;
case TType.Void: return 0;
case TType.Bool: return sizeof(byte);
case TType.Double: return 8; // uses fixedLongToBytes() which always writes 8 bytes
case TType.Byte: return sizeof(byte);
case TType.I16: return sizeof(byte); // zigzag
case TType.I32: return sizeof(byte); // zigzag
case TType.I64: return sizeof(byte); // zigzag
case TType.String: return sizeof(byte); // string length
case TType.Struct: return 0; // empty struct
case TType.Map: return sizeof(byte); // element count
case TType.Set: return sizeof(byte); // element count
case TType.List: return sizeof(byte); // element count
case TType.Uuid: return 16; // uuid bytes
default: throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "unrecognized type code");
}
}
public class Factory : TProtocolFactory
{
public override TProtocol GetProtocol(TTransport trans)
{
return new TCompactProtocol(trans);
}
}
/// <summary>
/// All of the on-wire exType codes.
/// </summary>
private static class Types
{
public const byte Stop = 0x00;
public const byte BooleanTrue = 0x01;
public const byte BooleanFalse = 0x02;
public const byte Byte = 0x03;
public const byte I16 = 0x04;
public const byte I32 = 0x05;
public const byte I64 = 0x06;
public const byte Double = 0x07;
public const byte Binary = 0x08;
public const byte List = 0x09;
public const byte Set = 0x0A;
public const byte Map = 0x0B;
public const byte Struct = 0x0C;
public const byte Uuid = 0x0D;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3124fc994ddc723458d1ca617ecfa78f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2852a1ad0426ea54aa516b762a3ce775
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,94 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System.Threading;
using System.Threading.Tasks;
using Thrift.Protocol.Entities;
#pragma warning disable IDE0079 // net20 - unneeded suppression
#pragma warning disable IDE0290 // net8 - primary CTOR
namespace Thrift.Protocol
{
/**
* TMultiplexedProtocol is a protocol-independent concrete decorator that allows a Thrift
* client to communicate with a multiplexing Thrift server, by prepending the service name
* to the function name during function calls.
*
* NOTE: THIS IS NOT TO BE USED BY SERVERS.
* On the server, use TMultiplexedProcessor to handle requests from a multiplexing client.
*
* This example uses a single socket transport to invoke two services:
*
* TSocketTransport transport = new TSocketTransport("localhost", 9090);
* transport.open();
*
* TBinaryProtocol protocol = new TBinaryProtocol(transport);
*
* TMultiplexedProtocol mp = new TMultiplexedProtocol(protocol, "Calculator");
* Calculator.Client service = new Calculator.Client(mp);
*
* TMultiplexedProtocol mp2 = new TMultiplexedProtocol(protocol, "WeatherReport");
* WeatherReport.Client service2 = new WeatherReport.Client(mp2);
*
* System.out.println(service.add(2,2));
* System.out.println(service2.getTemperature());
*
*/
//TODO: implementation of TProtocol
// ReSharper disable once InconsistentNaming
public class TMultiplexedProtocol : TProtocolDecorator
{
/** Used to delimit the service name from the function name */
public const string Separator = ":";
private readonly string _serviceName;
/**
* Wrap the specified protocol, allowing it to be used to communicate with a
* multiplexing server. The <code>serviceName</code> is required as it is
* prepended to the message header so that the multiplexing server can broker
* the function call to the proper service.
*
* Args:
* protocol Your communication protocol of choice, e.g. TBinaryProtocol
* serviceName The service name of the service communicating via this protocol.
*/
public TMultiplexedProtocol(TProtocol protocol, string serviceName)
: base(protocol)
{
_serviceName = serviceName;
}
public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken)
{
switch (message.Type)
{
case TMessageType.Call:
case TMessageType.Oneway:
await base.WriteMessageBeginAsync(new TMessage($"{_serviceName}{Separator}{message.Name}", message.Type, message.SeqID), cancellationToken);
break;
default:
await base.WriteMessageBeginAsync(message, cancellationToken);
break;
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 785a0b3fdff50d5489cdd7626de12986
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,199 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Thrift.Protocol.Entities;
using Thrift.Transport;
namespace Thrift.Protocol
{
// ReSharper disable once InconsistentNaming
public abstract class TProtocol : IDisposable
{
private bool _isDisposed;
protected int RecursionDepth;
protected TTransport Trans;
protected static readonly TStruct AnonymousStruct = new TStruct(string.Empty);
protected static readonly TField StopField = new TField() { Type = TType.Stop };
protected TProtocol(TTransport trans)
{
Trans = trans;
RecursionLimit = trans.Configuration.RecursionLimit;
RecursionDepth = 0;
}
public TTransport Transport => Trans;
protected int RecursionLimit { get; set; }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void IncrementRecursionDepth()
{
if (RecursionDepth < RecursionLimit)
{
++RecursionDepth;
}
else
{
throw new TProtocolException(TProtocolException.DEPTH_LIMIT, "Depth limit exceeded");
}
}
public void DecrementRecursionDepth()
{
--RecursionDepth;
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
(Trans as IDisposable)?.Dispose();
}
}
_isDisposed = true;
}
protected void CheckReadBytesAvailable(TSet set)
{
Transport.CheckReadBytesAvailable(set.Count * GetMinSerializedSize(set.ElementType));
}
protected void CheckReadBytesAvailable(TList list)
{
Transport.CheckReadBytesAvailable(list.Count * GetMinSerializedSize(list.ElementType));
}
protected void CheckReadBytesAvailable(TMap map)
{
var elmSize = GetMinSerializedSize(map.KeyType) + GetMinSerializedSize(map.ValueType);
Transport.CheckReadBytesAvailable(map.Count * elmSize);
}
// Returns the minimum amount of bytes needed to store the smallest possible instance of TType.
public abstract int GetMinSerializedSize(TType type);
public abstract Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken = default);
public abstract Task WriteMessageEndAsync(CancellationToken cancellationToken = default);
public abstract Task WriteStructBeginAsync(TStruct @struct, CancellationToken cancellationToken = default);
public abstract Task WriteStructEndAsync(CancellationToken cancellationToken = default);
public abstract Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken = default);
public abstract Task WriteFieldEndAsync(CancellationToken cancellationToken = default);
public abstract Task WriteFieldStopAsync(CancellationToken cancellationToken = default);
public abstract Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken = default);
public abstract Task WriteMapEndAsync(CancellationToken cancellationToken = default);
public abstract Task WriteListBeginAsync(TList list, CancellationToken cancellationToken = default);
public abstract Task WriteListEndAsync(CancellationToken cancellationToken = default);
public abstract Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken = default);
public abstract Task WriteSetEndAsync(CancellationToken cancellationToken = default);
public abstract Task WriteBoolAsync(bool b, CancellationToken cancellationToken = default);
public abstract Task WriteByteAsync(sbyte b, CancellationToken cancellationToken = default);
public abstract Task WriteI16Async(short i16, CancellationToken cancellationToken = default);
public abstract Task WriteI32Async(int i32, CancellationToken cancellationToken = default);
public abstract Task WriteI64Async(long i64, CancellationToken cancellationToken = default);
public abstract Task WriteDoubleAsync(double d, CancellationToken cancellationToken = default);
public virtual async Task WriteStringAsync(string s, CancellationToken cancellationToken = default)
{
var bytes = Encoding.UTF8.GetBytes(s);
await WriteBinaryAsync(bytes, cancellationToken);
}
public abstract Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken = default);
public abstract Task WriteUuidAsync(Guid uuid, CancellationToken cancellationToken = default);
public abstract ValueTask<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken = default);
public abstract Task ReadMessageEndAsync(CancellationToken cancellationToken = default);
public abstract ValueTask<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken = default);
public abstract Task ReadStructEndAsync(CancellationToken cancellationToken = default);
public abstract ValueTask<TField> ReadFieldBeginAsync(CancellationToken cancellationToken = default);
public abstract Task ReadFieldEndAsync(CancellationToken cancellationToken = default);
public abstract ValueTask<TMap> ReadMapBeginAsync(CancellationToken cancellationToken = default);
public abstract Task ReadMapEndAsync(CancellationToken cancellationToken = default);
public abstract ValueTask<TList> ReadListBeginAsync(CancellationToken cancellationToken = default);
public abstract Task ReadListEndAsync(CancellationToken cancellationToken = default);
public abstract ValueTask<TSet> ReadSetBeginAsync(CancellationToken cancellationToken = default);
public abstract Task ReadSetEndAsync(CancellationToken cancellationToken = default);
public abstract ValueTask<bool> ReadBoolAsync(CancellationToken cancellationToken = default);
public abstract ValueTask<sbyte> ReadByteAsync(CancellationToken cancellationToken = default);
public abstract ValueTask<short> ReadI16Async(CancellationToken cancellationToken = default);
public abstract ValueTask<int> ReadI32Async(CancellationToken cancellationToken = default);
public abstract ValueTask<long> ReadI64Async(CancellationToken cancellationToken = default);
public abstract ValueTask<double> ReadDoubleAsync(CancellationToken cancellationToken = default);
public virtual async ValueTask<string> ReadStringAsync(CancellationToken cancellationToken = default)
{
var buf = await ReadBinaryAsync(cancellationToken);
return Encoding.UTF8.GetString(buf, 0, buf.Length);
}
public abstract ValueTask<byte[]> ReadBinaryAsync(CancellationToken cancellationToken = default);
public abstract ValueTask<Guid> ReadUuidAsync(CancellationToken cancellationToken = default);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 707e55b50657bac48b6aa280c626c7aa
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,267 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Threading;
using System.Threading.Tasks;
using Thrift.Protocol.Entities;
namespace Thrift.Protocol
{
// ReSharper disable once InconsistentNaming
/// <summary>
/// TProtocolDecorator forwards all requests to an enclosed TProtocol instance,
/// providing a way to author concise concrete decorator subclasses.While it has
/// no abstract methods, it is marked abstract as a reminder that by itself,
/// it does not modify the behaviour of the enclosed TProtocol.
/// </summary>
public abstract class TProtocolDecorator : TProtocol
{
private readonly TProtocol _wrappedProtocol;
protected TProtocolDecorator(TProtocol protocol)
: base(protocol.Transport)
{
_wrappedProtocol = protocol ?? throw new ArgumentNullException(nameof(protocol));
}
public override async Task WriteMessageBeginAsync(TMessage message, CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteMessageBeginAsync(message, cancellationToken);
}
public override async Task WriteMessageEndAsync(CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteMessageEndAsync(cancellationToken);
}
public override async Task WriteStructBeginAsync(TStruct @struct, CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteStructBeginAsync(@struct, cancellationToken);
}
public override async Task WriteStructEndAsync(CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteStructEndAsync(cancellationToken);
}
public override async Task WriteFieldBeginAsync(TField field, CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteFieldBeginAsync(field, cancellationToken);
}
public override async Task WriteFieldEndAsync(CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteFieldEndAsync(cancellationToken);
}
public override async Task WriteFieldStopAsync(CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteFieldStopAsync(cancellationToken);
}
public override async Task WriteMapBeginAsync(TMap map, CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteMapBeginAsync(map, cancellationToken);
}
public override async Task WriteMapEndAsync(CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteMapEndAsync(cancellationToken);
}
public override async Task WriteListBeginAsync(TList list, CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteListBeginAsync(list, cancellationToken);
}
public override async Task WriteListEndAsync(CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteListEndAsync(cancellationToken);
}
public override async Task WriteSetBeginAsync(TSet set, CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteSetBeginAsync(set, cancellationToken);
}
public override async Task WriteSetEndAsync(CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteSetEndAsync(cancellationToken);
}
public override async Task WriteBoolAsync(bool b, CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteBoolAsync(b, cancellationToken);
}
public override async Task WriteByteAsync(sbyte b, CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteByteAsync(b, cancellationToken);
}
public override async Task WriteI16Async(short i16, CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteI16Async(i16, cancellationToken);
}
public override async Task WriteI32Async(int i32, CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteI32Async(i32, cancellationToken);
}
public override async Task WriteI64Async(long i64, CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteI64Async(i64, cancellationToken);
}
public override async Task WriteDoubleAsync(double d, CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteDoubleAsync(d, cancellationToken);
}
public override async Task WriteStringAsync(string s, CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteStringAsync(s, cancellationToken);
}
public override async Task WriteBinaryAsync(byte[] bytes, CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteBinaryAsync(bytes, cancellationToken);
}
public override async Task WriteUuidAsync(Guid uuid, CancellationToken cancellationToken)
{
await _wrappedProtocol.WriteUuidAsync(uuid, cancellationToken);
}
public override async ValueTask<TMessage> ReadMessageBeginAsync(CancellationToken cancellationToken)
{
return await _wrappedProtocol.ReadMessageBeginAsync(cancellationToken);
}
public override async Task ReadMessageEndAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
await _wrappedProtocol.ReadMessageEndAsync(cancellationToken);
Transport.ResetMessageSizeAndConsumedBytes();
}
public override async ValueTask<TStruct> ReadStructBeginAsync(CancellationToken cancellationToken)
{
return await _wrappedProtocol.ReadStructBeginAsync(cancellationToken);
}
public override async Task ReadStructEndAsync(CancellationToken cancellationToken)
{
await _wrappedProtocol.ReadStructEndAsync(cancellationToken);
}
public override async ValueTask<TField> ReadFieldBeginAsync(CancellationToken cancellationToken)
{
return await _wrappedProtocol.ReadFieldBeginAsync(cancellationToken);
}
public override async Task ReadFieldEndAsync(CancellationToken cancellationToken)
{
await _wrappedProtocol.ReadFieldEndAsync(cancellationToken);
}
public override async ValueTask<TMap> ReadMapBeginAsync(CancellationToken cancellationToken)
{
return await _wrappedProtocol.ReadMapBeginAsync(cancellationToken);
}
public override async Task ReadMapEndAsync(CancellationToken cancellationToken)
{
await _wrappedProtocol.ReadMapEndAsync(cancellationToken);
}
public override async ValueTask<TList> ReadListBeginAsync(CancellationToken cancellationToken)
{
return await _wrappedProtocol.ReadListBeginAsync(cancellationToken);
}
public override async Task ReadListEndAsync(CancellationToken cancellationToken)
{
await _wrappedProtocol.ReadListEndAsync(cancellationToken);
}
public override async ValueTask<TSet> ReadSetBeginAsync(CancellationToken cancellationToken)
{
return await _wrappedProtocol.ReadSetBeginAsync(cancellationToken);
}
public override async Task ReadSetEndAsync(CancellationToken cancellationToken)
{
await _wrappedProtocol.ReadSetEndAsync(cancellationToken);
}
public override async ValueTask<bool> ReadBoolAsync(CancellationToken cancellationToken)
{
return await _wrappedProtocol.ReadBoolAsync(cancellationToken);
}
public override async ValueTask<sbyte> ReadByteAsync(CancellationToken cancellationToken)
{
return await _wrappedProtocol.ReadByteAsync(cancellationToken);
}
public override async ValueTask<short> ReadI16Async(CancellationToken cancellationToken)
{
return await _wrappedProtocol.ReadI16Async(cancellationToken);
}
public override async ValueTask<int> ReadI32Async(CancellationToken cancellationToken)
{
return await _wrappedProtocol.ReadI32Async(cancellationToken);
}
public override async ValueTask<long> ReadI64Async(CancellationToken cancellationToken)
{
return await _wrappedProtocol.ReadI64Async(cancellationToken);
}
public override async ValueTask<double> ReadDoubleAsync(CancellationToken cancellationToken)
{
return await _wrappedProtocol.ReadDoubleAsync(cancellationToken);
}
public override async ValueTask<string> ReadStringAsync(CancellationToken cancellationToken)
{
return await _wrappedProtocol.ReadStringAsync(cancellationToken);
}
public override async ValueTask<byte[]> ReadBinaryAsync(CancellationToken cancellationToken)
{
return await _wrappedProtocol.ReadBinaryAsync(cancellationToken);
}
public override async ValueTask<Guid> ReadUuidAsync(CancellationToken cancellationToken)
{
return await _wrappedProtocol.ReadUuidAsync(cancellationToken);
}
// Returns the minimum amount of bytes needed to store the smallest possible instance of TType.
public override int GetMinSerializedSize(TType type)
{
return _wrappedProtocol.GetMinSerializedSize(type);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 19b5bca1a81ff0e4d950ab9a26a08350
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,62 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
// ReSharper disable InconsistentNaming
using System;
namespace Thrift.Protocol
{
public class TProtocolException : TException
{
// do not rename public constants - they used in generated files
public const int UNKNOWN = 0;
public const int INVALID_DATA = 1;
public const int NEGATIVE_SIZE = 2;
public const int SIZE_LIMIT = 3;
public const int BAD_VERSION = 4;
public const int NOT_IMPLEMENTED = 5;
public const int DEPTH_LIMIT = 6;
protected int Type = UNKNOWN;
public TProtocolException()
{
}
public TProtocolException(int type, Exception inner = null)
: base(string.Empty, inner)
{
Type = type;
}
public TProtocolException(int type, string message, Exception inner = null)
: base(message, inner)
{
Type = type;
}
public TProtocolException(string message, Exception inner = null)
: base(message, inner)
{
}
public int GetExceptionType()
{
return Type;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4ba605f7d63e1314f9b930e4b8a2c7be
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,27 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using Thrift.Transport;
namespace Thrift.Protocol
{
// ReSharper disable once InconsistentNaming
public abstract class TProtocolFactory
{
public abstract TProtocol GetProtocol(TTransport trans);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bc1306af0fbb4444aabfb648f3361e7e
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,87 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Text;
using Thrift.Protocol;
namespace Thrift.Protocol
{
public static class ToStringExtensions
{
public static void ToString(this object self, StringBuilder sb, bool first = true)
{
if (!first)
sb.Append(", ");
bool first_child = true;
if (self is string str) // string is IEnumerable
{
sb.Append('"');
sb.Append(str);
sb.Append('"');
}
else if (self is IDictionary dict)
{
sb.Append("{ ");
foreach (DictionaryEntry pair in dict)
{
if (first_child)
first_child = false;
else
sb.Append(',');
sb.Append("{ ");
pair.Key.ToString(sb);
sb.Append(", ");
pair.Value.ToString(sb);
sb.Append('}');
}
sb.Append('}');
}
else if (self is IEnumerable enumerable)
{
sb.Append("{ ");
foreach (var elm in enumerable)
{
elm.ToString(sb, first_child);
first_child = false;
}
sb.Append('}');
}
else if (self is TBase tbase)
{
sb.Append(tbase.ToString());
}
else if (self is double dbVal)
{
sb.Append(dbVal.ToString(CultureInfo.InvariantCulture));
}
else
{
sb.Append(self != null ? self.ToString() : "<null>");
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2074e4c9459760546bd43505c9481d62
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bb04768de16698c41a44db64dc06a464
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,107 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
#pragma warning disable IDE0079 // net20 - unneeded suppression
#pragma warning disable IDE0300 // net8 - simplified collection init
#pragma warning disable IDE0028 // net8 - simplified collection init
#pragma warning disable CA1510 // net8 - use ThrowIfNull
#pragma warning disable CA1513 // net8 - use ThrowIfNull
namespace Thrift.Protocol.Utilities
{
// ReSharper disable once InconsistentNaming
internal static class TBase64Utils
{
//TODO: Constants
//TODO: Check for args
//TODO: Unitests
internal const string EncodeTable = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
private static readonly int[] DecodeTable =
{
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63,
52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1,
-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1,
-1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
};
internal static void Encode(byte[] src, int srcOff, int len, byte[] dst, int dstOff)
{
if (src == null)
{
throw new ArgumentNullException(nameof(src));
}
dst[dstOff] = (byte) EncodeTable[(src[srcOff] >> 2) & 0x3F];
if (len == 3)
{
dst[dstOff + 1] = (byte) EncodeTable[((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
dst[dstOff + 2] = (byte) EncodeTable[((src[srcOff + 1] << 2) & 0x3C) | ((src[srcOff + 2] >> 6) & 0x03)];
dst[dstOff + 3] = (byte) EncodeTable[src[srcOff + 2] & 0x3F];
}
else if (len == 2)
{
dst[dstOff + 1] = (byte) EncodeTable[((src[srcOff] << 4) & 0x30) | ((src[srcOff + 1] >> 4) & 0x0F)];
dst[dstOff + 2] = (byte) EncodeTable[(src[srcOff + 1] << 2) & 0x3C];
}
else
{
// len == 1
dst[dstOff + 1] = (byte) EncodeTable[(src[srcOff] << 4) & 0x30];
}
}
internal static void Decode(byte[] src, int srcOff, int len, byte[] dst, int dstOff)
{
if (src == null)
{
throw new ArgumentNullException(nameof(src));
}
dst[dstOff] = (byte) ((DecodeTable[src[srcOff] & 0x0FF] << 2) | (DecodeTable[src[srcOff + 1] & 0x0FF] >> 4));
if (len > 2)
{
dst[dstOff + 1] =
(byte)
(((DecodeTable[src[srcOff + 1] & 0x0FF] << 4) & 0xF0) | (DecodeTable[src[srcOff + 2] & 0x0FF] >> 2));
if (len > 3)
{
dst[dstOff + 2] =
(byte)
(((DecodeTable[src[srcOff + 2] & 0x0FF] << 6) & 0xC0) | DecodeTable[src[srcOff + 3] & 0x0FF]);
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 761fd254a87199345ac100ae7ad63f88
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,80 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
namespace Thrift.Protocol.Utilities
{
public static class TGuidExtensions
{
public static Guid SwapByteOrder(this Guid self)
{
var bytes = self.ToByteArray();
// already network order on BigEndian machines
if (BitConverter.IsLittleEndian)
{
SwapBytes(ref bytes[0], ref bytes[3]);
SwapBytes(ref bytes[1], ref bytes[2]);
SwapBytes(ref bytes[4], ref bytes[5]);
SwapBytes(ref bytes[6], ref bytes[7]);
}
return new Guid(bytes);
}
private static void SwapBytes(ref byte one, ref byte two)
{
(two, one) = (one, two);
}
#region SelfTest
#if DEBUG
static private readonly Guid TEST_GUID = new Guid("{00112233-4455-6677-8899-aabbccddeeff}");
static TGuidExtensions()
{
SelfTest();
}
private static void SelfTest()
{
// host to network
var guid = TEST_GUID;
guid = guid.SwapByteOrder();
// validate network order
var bytes = guid.ToByteArray();
for (var i = 0; i < 10; ++i)
{
var expected = i * 0x11;
Debug.Assert( bytes[i] == expected);
}
// network to host and final validation
guid = guid.SwapByteOrder();
Debug.Assert(guid.Equals(TEST_GUID));
}
#endif
#endregion
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a7f1fdb7231fce94086107b61128e0b7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,65 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#pragma warning disable IDE0079 // net20 - unneeded suppression
#pragma warning disable IDE0300 // net8 - simplified collection init
namespace Thrift.Protocol.Utilities
{
// ReSharper disable once InconsistentNaming
public static class TJSONProtocolConstants
{
//TODO Check for performance for reusing ImmutableArray from System.Collections.Immutable (https://blogs.msdn.microsoft.com/dotnet/2013/06/24/please-welcome-immutablearrayt/)
// can be possible to get better performance and also better GC
public static readonly byte[] Comma = {(byte) ','};
public static readonly byte[] Colon = {(byte) ':'};
public static readonly byte[] LeftBrace = {(byte) '{'};
public static readonly byte[] RightBrace = {(byte) '}'};
public static readonly byte[] LeftBracket = {(byte) '['};
public static readonly byte[] RightBracket = {(byte) ']'};
public static readonly byte[] Quote = {(byte) '"'};
public static readonly byte[] Backslash = {(byte) '\\'};
public static readonly byte[] JsonCharTable =
{
0, 0, 0, 0, 0, 0, 0, 0, (byte) 'b', (byte) 't', (byte) 'n', 0, (byte) 'f', (byte) 'r', 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, (byte) '"', 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
};
public static readonly char[] EscapeChars = "\"\\/bfnrt".ToCharArray();
public static readonly byte[] EscapeCharValues = {(byte) '"', (byte) '\\', (byte) '/', (byte) '\b', (byte) '\f', (byte) '\n', (byte) '\r', (byte) '\t'};
public static readonly byte[] EscSequences = {(byte) '\\', (byte) 'u', (byte) '0', (byte) '0'};
public static class TypeNames
{
public static readonly byte[] NameBool = { (byte)'t', (byte)'f' };
public static readonly byte[] NameByte = { (byte)'i', (byte)'8' };
public static readonly byte[] NameI16 = { (byte)'i', (byte)'1', (byte)'6' };
public static readonly byte[] NameI32 = { (byte)'i', (byte)'3', (byte)'2' };
public static readonly byte[] NameI64 = { (byte)'i', (byte)'6', (byte)'4' };
public static readonly byte[] NameDouble = { (byte)'d', (byte)'b', (byte)'l' };
public static readonly byte[] NameStruct = { (byte)'r', (byte)'e', (byte)'c' };
public static readonly byte[] NameString = { (byte)'s', (byte)'t', (byte)'r' };
public static readonly byte[] NameMap = { (byte)'m', (byte)'a', (byte)'p' };
public static readonly byte[] NameList = { (byte)'l', (byte)'s', (byte)'t' };
public static readonly byte[] NameSet = { (byte)'s', (byte)'e', (byte)'t' };
public static readonly byte[] NameUuid = { (byte)'u', (byte)'i', (byte)'d' };
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e217a11c484220b4aaf3b2b92127067c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,181 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using Thrift.Protocol.Entities;
namespace Thrift.Protocol.Utilities
{
// ReSharper disable once InconsistentNaming
public static class TJSONProtocolHelper
{
public static byte[] GetTypeNameForTypeId(TType typeId)
{
switch (typeId)
{
case TType.Bool:
return TJSONProtocolConstants.TypeNames.NameBool;
case TType.Byte:
return TJSONProtocolConstants.TypeNames.NameByte;
case TType.I16:
return TJSONProtocolConstants.TypeNames.NameI16;
case TType.I32:
return TJSONProtocolConstants.TypeNames.NameI32;
case TType.I64:
return TJSONProtocolConstants.TypeNames.NameI64;
case TType.Double:
return TJSONProtocolConstants.TypeNames.NameDouble;
case TType.String:
return TJSONProtocolConstants.TypeNames.NameString;
case TType.Struct:
return TJSONProtocolConstants.TypeNames.NameStruct;
case TType.Map:
return TJSONProtocolConstants.TypeNames.NameMap;
case TType.Set:
return TJSONProtocolConstants.TypeNames.NameSet;
case TType.List:
return TJSONProtocolConstants.TypeNames.NameList;
case TType.Uuid:
return TJSONProtocolConstants.TypeNames.NameUuid;
default:
throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized exType");
}
}
public static TType GetTypeIdForTypeName(byte[] name)
{
var result = TType.Stop;
if (name.Length > 1)
{
switch (name[0])
{
case (byte) 'd':
result = TType.Double;
break;
case (byte) 'i':
switch (name[1])
{
case (byte) '8':
result = TType.Byte;
break;
case (byte) '1':
result = TType.I16;
break;
case (byte) '3':
result = TType.I32;
break;
case (byte) '6':
result = TType.I64;
break;
}
break;
case (byte) 'l':
result = TType.List;
break;
case (byte) 'm':
result = TType.Map;
break;
case (byte) 'r':
result = TType.Struct;
break;
case (byte) 's':
if (name[1] == (byte) 't')
{
result = TType.String;
}
else if (name[1] == (byte) 'e')
{
result = TType.Set;
}
break;
case (byte) 't':
result = TType.Bool;
break;
case (byte)'u':
result = TType.Uuid;
break;
}
}
if (result == TType.Stop)
{
throw new TProtocolException(TProtocolException.NOT_IMPLEMENTED, "Unrecognized exType");
}
return result;
}
/// <summary>
/// Return true if the given byte could be a valid part of a JSON number.
/// </summary>
public static bool IsJsonNumeric(byte b)
{
switch (b)
{
case (byte)'+':
case (byte)'-':
case (byte)'.':
case (byte)'0':
case (byte)'1':
case (byte)'2':
case (byte)'3':
case (byte)'4':
case (byte)'5':
case (byte)'6':
case (byte)'7':
case (byte)'8':
case (byte)'9':
case (byte)'E':
case (byte)'e':
return true;
default:
return false;
}
}
/// <summary>
/// Convert a byte containing a hex char ('0'-'9' or 'a'-'f') into its
/// corresponding hex value
/// </summary>
public static byte ToHexVal(byte ch)
{
if (ch >= '0' && ch <= '9')
{
return (byte)((char)ch - '0');
}
if (ch >= 'a' && ch <= 'f')
{
ch += 10;
return (byte)((char)ch - 'a');
}
throw new TProtocolException(TProtocolException.INVALID_DATA, "Expected hex character");
}
/// <summary>
/// Convert a byte containing a hex value to its corresponding hex character
/// </summary>
public static byte ToHexChar(byte val)
{
val &= 0x0F;
if (val < 10)
{
return (byte)((char)val + '0');
}
val -= 10;
return (byte)((char)val + 'a');
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c0b7b8082d4f82543b7d7e4ec25a8596
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,110 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System.Threading;
using System.Threading.Tasks;
using Thrift.Protocol.Entities;
namespace Thrift.Protocol.Utilities
{
// ReSharper disable once InconsistentNaming
public static class TProtocolUtil
{
public static async Task SkipAsync(TProtocol protocol, TType type, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
protocol.IncrementRecursionDepth();
try
{
switch (type)
{
case TType.Bool:
await protocol.ReadBoolAsync(cancellationToken);
break;
case TType.Byte:
await protocol.ReadByteAsync(cancellationToken);
break;
case TType.I16:
await protocol.ReadI16Async(cancellationToken);
break;
case TType.I32:
await protocol.ReadI32Async(cancellationToken);
break;
case TType.I64:
await protocol.ReadI64Async(cancellationToken);
break;
case TType.Double:
await protocol.ReadDoubleAsync(cancellationToken);
break;
case TType.String:
// Don't try to decode the string, just skip it.
await protocol.ReadBinaryAsync(cancellationToken);
break;
case TType.Uuid:
await protocol.ReadUuidAsync(cancellationToken);
break;
case TType.Struct:
await protocol.ReadStructBeginAsync(cancellationToken);
while (true)
{
var field = await protocol.ReadFieldBeginAsync(cancellationToken);
if (field.Type == TType.Stop)
{
break;
}
await SkipAsync(protocol, field.Type, cancellationToken);
await protocol.ReadFieldEndAsync(cancellationToken);
}
await protocol.ReadStructEndAsync(cancellationToken);
break;
case TType.Map:
var map = await protocol.ReadMapBeginAsync(cancellationToken);
for (var i = 0; i < map.Count; i++)
{
await SkipAsync(protocol, map.KeyType, cancellationToken);
await SkipAsync(protocol, map.ValueType, cancellationToken);
}
await protocol.ReadMapEndAsync(cancellationToken);
break;
case TType.Set:
var set = await protocol.ReadSetBeginAsync(cancellationToken);
for (var i = 0; i < set.Count; i++)
{
await SkipAsync(protocol, set.ElementType, cancellationToken);
}
await protocol.ReadSetEndAsync(cancellationToken);
break;
case TType.List:
var list = await protocol.ReadListBeginAsync(cancellationToken);
for (var i = 0; i < list.Count; i++)
{
await SkipAsync(protocol, list.ElementType, cancellationToken);
}
await protocol.ReadListEndAsync(cancellationToken);
break;
default:
throw new TProtocolException(TProtocolException.INVALID_DATA, "Unknown data type " + type.ToString("d"));
}
}
finally
{
protocol.DecrementRecursionDepth();
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: da904c2c7f62df841acde0448f0b0a6f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,147 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System.Threading;
using System.Threading.Tasks;
using Thrift.Protocol;
using Thrift.Protocol.Entities;
using Thrift.Protocol.Utilities;
namespace Thrift
{
// ReSharper disable once InconsistentNaming
public class TApplicationException : TException
{
public enum ExceptionType
{
Unknown,
UnknownMethod,
InvalidMessageType,
WrongMethodName,
BadSequenceId,
MissingResult,
InternalError,
ProtocolError,
InvalidTransform,
InvalidProtocol,
UnsupportedClientType
}
private const int MessageTypeFieldId = 1;
private const int ExTypeFieldId = 2;
public ExceptionType Type { get; private set; }
public TApplicationException()
{
}
public TApplicationException(ExceptionType type)
{
Type = type;
}
public TApplicationException(ExceptionType type, string message)
: base(message, null) // TApplicationException is serializable, but we never serialize InnerException
{
Type = type;
}
public static async ValueTask<TApplicationException> ReadAsync(TProtocol inputProtocol, CancellationToken cancellationToken)
{
string message = null;
var type = ExceptionType.Unknown;
await inputProtocol.ReadStructBeginAsync(cancellationToken);
while (true)
{
var field = await inputProtocol.ReadFieldBeginAsync(cancellationToken);
if (field.Type == TType.Stop)
{
break;
}
switch (field.ID)
{
case MessageTypeFieldId:
if (field.Type == TType.String)
{
message = await inputProtocol.ReadStringAsync(cancellationToken);
}
else
{
await TProtocolUtil.SkipAsync(inputProtocol, field.Type, cancellationToken);
}
break;
case ExTypeFieldId:
if (field.Type == TType.I32)
{
type = (ExceptionType) await inputProtocol.ReadI32Async(cancellationToken);
}
else
{
await TProtocolUtil.SkipAsync(inputProtocol, field.Type, cancellationToken);
}
break;
default:
await TProtocolUtil.SkipAsync(inputProtocol, field.Type, cancellationToken);
break;
}
await inputProtocol.ReadFieldEndAsync(cancellationToken);
}
await inputProtocol.ReadStructEndAsync(cancellationToken);
return new TApplicationException(type, message);
}
public async Task WriteAsync(TProtocol outputProtocol, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
const string messageTypeFieldName = "message";
const string exTypeFieldName = "exType";
const string structApplicationExceptionName = "TApplicationException";
var struc = new TStruct(structApplicationExceptionName);
var field = new TField();
await outputProtocol.WriteStructBeginAsync(struc, cancellationToken);
if (!string.IsNullOrEmpty(Message))
{
field.Name = messageTypeFieldName;
field.Type = TType.String;
field.ID = MessageTypeFieldId;
await outputProtocol.WriteFieldBeginAsync(field, cancellationToken);
await outputProtocol.WriteStringAsync(Message, cancellationToken);
await outputProtocol.WriteFieldEndAsync(cancellationToken);
}
field.Name = exTypeFieldName;
field.Type = TType.I32;
field.ID = ExTypeFieldId;
await outputProtocol.WriteFieldBeginAsync(field, cancellationToken);
await outputProtocol.WriteI32Async((int) Type, cancellationToken);
await outputProtocol.WriteFieldEndAsync(cancellationToken);
await outputProtocol.WriteFieldStopAsync(cancellationToken);
await outputProtocol.WriteStructEndAsync(cancellationToken);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f86d77c239225104cab74e32b14c5d93
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,91 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Threading;
using System.Threading.Tasks;
using Thrift.Protocol;
namespace Thrift
{
// ReSharper disable once InconsistentNaming
/// <summary>
/// TBaseClient.
/// Base client for generated clients.
/// Do not change this class without checking generated code (namings, etc.)
/// </summary>
public abstract class TBaseClient
{
private readonly TProtocol _inputProtocol;
private readonly TProtocol _outputProtocol;
private bool _isDisposed;
private int _seqId;
public readonly Guid ClientId = Guid.NewGuid();
protected TBaseClient(TProtocol inputProtocol, TProtocol outputProtocol)
{
_inputProtocol = inputProtocol ?? throw new ArgumentNullException(nameof(inputProtocol));
_outputProtocol = outputProtocol ?? throw new ArgumentNullException(nameof(outputProtocol));
}
public TProtocol InputProtocol => _inputProtocol;
public TProtocol OutputProtocol => _outputProtocol;
public int SeqId
{
get { return ++_seqId; }
}
public virtual async Task OpenTransportAsync()
{
await OpenTransportAsync(CancellationToken.None);
}
public virtual async Task OpenTransportAsync(CancellationToken cancellationToken)
{
if (!_inputProtocol.Transport.IsOpen)
{
await _inputProtocol.Transport.OpenAsync(cancellationToken);
}
if (!_outputProtocol.Transport.IsOpen)
{
await _outputProtocol.Transport.OpenAsync(cancellationToken);
}
}
public void Dispose()
{
Dispose(true);
}
protected virtual void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
_inputProtocol?.Dispose();
_outputProtocol?.Dispose();
}
}
_isDisposed = true;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: af1fb0222ec8a574aa069e3d3c4a7c94
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,36 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Collections.Generic;
using System.Text;
namespace Thrift
{
public class TConfiguration
{
public const int DEFAULT_MAX_MESSAGE_SIZE = 100 * 1024 * 1024;
public const int DEFAULT_MAX_FRAME_SIZE = 16384000; // this value is used consistently across all Thrift libraries
public const int DEFAULT_RECURSION_DEPTH = 64;
public int MaxMessageSize { get; set; } = DEFAULT_MAX_MESSAGE_SIZE;
public int MaxFrameSize { get; set; } = DEFAULT_MAX_FRAME_SIZE;
public int RecursionLimit { get; set; } = DEFAULT_RECURSION_DEPTH;
// TODO(JensG): add connection and i/o timeouts
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 25f18e47ae18a504e9bd1b18dd0bac49
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,34 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
namespace Thrift
{
// ReSharper disable once InconsistentNaming
public class TException : Exception
{
public TException()
{
}
public TException(string message, Exception inner)
: base(message, inner)
{
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4c31d338acd518d47894f98047ffe9ab
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,14 @@
{
"name": "Thrift",
"rootNamespace": "",
"references": [],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": false,
"overrideReferences": false,
"precompiledReferences": [],
"autoReferenced": true,
"defineConstraints": [],
"versionDefines": [],
"noEngineReferences": false
}

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 80bc5989de867864f925938fc1ceb864
AssemblyDefinitionImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 0de584fe90b6ad447a3e305ab93ec9c3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 5b44f0b64f17bfb45ae3deb0647b1078
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,301 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
#pragma warning disable IDE0079 // unneeded suppression -> all except net8
#pragma warning disable IDE0301 // simplify collection init -> net8 only
namespace Thrift.Transport.Client
{
// ReSharper disable once InconsistentNaming
public class THttpTransport : TEndpointTransport
{
private readonly X509Certificate[] _certificates;
private readonly Uri _uri;
private int _connectTimeout = 30000; // Timeouts in milliseconds
private HttpClient _httpClient;
private Stream _inputStream;
private MemoryStream _outputStream = new MemoryStream();
private bool _isDisposed;
public THttpTransport(Uri uri, TConfiguration config, IDictionary<string, string> customRequestHeaders = null, string userAgent = null)
: this(uri, config, Enumerable.Empty<X509Certificate>(), customRequestHeaders, userAgent)
{
}
public THttpTransport(Uri uri, TConfiguration config, IEnumerable<X509Certificate> certificates,
IDictionary<string, string> customRequestHeaders, string userAgent = null)
: base(config)
{
_uri = uri;
_certificates = (certificates ?? Enumerable.Empty<X509Certificate>()).ToArray();
if (!string.IsNullOrEmpty(userAgent))
UserAgent = userAgent;
// due to current bug with performance of Dispose in netcore https://github.com/dotnet/corefx/issues/8809
// this can be switched to default way (create client->use->dispose per flush) later
_httpClient = CreateClient(customRequestHeaders);
ConfigureClient(_httpClient);
}
/// <summary>
/// Constructor that takes a <c>HttpClient</c> instance to support using <c>IHttpClientFactory</c>.
/// </summary>
/// <remarks>As the <c>HttpMessageHandler</c> of the client must be configured at the time of creation, it
/// is assumed that the consumer has already added any certificates and configured decompression methods. The
/// consumer can use the <c>CreateHttpClientHandler</c> method to get a handler with these set.</remarks>
/// <param name="httpClient">Client configured with the desired message handler, user agent, and URI if not
/// specified in the <c>uri</c> parameter. A default user agent will be used if not set.</param>
/// <param name="config">Thrift configuration object</param>
/// <param name="uri">Optional URI to use for requests, if not specified the base address of <c>httpClient</c>
/// is used.</param>
public THttpTransport(HttpClient httpClient, TConfiguration config, Uri uri = null)
: base(config)
{
_httpClient = httpClient;
_uri = uri ?? httpClient.BaseAddress;
httpClient.BaseAddress = _uri;
var userAgent = _httpClient.DefaultRequestHeaders.UserAgent.ToString();
if (!string.IsNullOrEmpty(userAgent))
UserAgent = userAgent;
ConfigureClient(_httpClient);
}
// According to RFC 2616 section 3.8, the "User-Agent" header may not carry a version number
public readonly string UserAgent = "Thrift netstd THttpClient";
public int ConnectTimeout
{
set
{
_connectTimeout = value;
if(_httpClient != null)
_httpClient.Timeout = TimeSpan.FromMilliseconds(_connectTimeout);
}
get
{
if (_httpClient == null)
return _connectTimeout;
return (int)_httpClient.Timeout.TotalMilliseconds;
}
}
public override bool IsOpen => true;
public HttpRequestHeaders RequestHeaders => _httpClient.DefaultRequestHeaders;
public MediaTypeHeaderValue ContentType { get; set; }
public override Task OpenAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override void Close()
{
if (_inputStream != null)
{
_inputStream.Dispose();
_inputStream = null;
}
if (_outputStream != null)
{
_outputStream.Dispose();
_outputStream = null;
}
if (_httpClient != null)
{
_httpClient.Dispose();
_httpClient = null;
}
}
public override async ValueTask<int> ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (_inputStream == null)
throw new TTransportException(TTransportException.ExceptionType.NotOpen, "No request has been sent");
CheckReadBytesAvailable(length);
try
{
#if NET5_0_OR_GREATER
var ret = await _inputStream.ReadAsync(new Memory<byte>(buffer, offset, length), cancellationToken);
#else
var ret = await _inputStream.ReadAsync(buffer, offset, length, cancellationToken);
#endif
if (ret == -1)
{
throw new TTransportException(TTransportException.ExceptionType.EndOfFile, "No more data available");
}
CountConsumedMessageBytes(ret);
return ret;
}
catch (IOException iox)
{
throw new TTransportException(TTransportException.ExceptionType.Unknown, iox.ToString(), iox);
}
}
public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
#if NET5_0_OR_GREATER
await _outputStream.WriteAsync(buffer.AsMemory(offset, length), cancellationToken);
#else
await _outputStream.WriteAsync(buffer, offset, length, cancellationToken);
#endif
}
/// <summary>
/// Get a client handler configured with recommended properties to use with the <c>HttpClient</c> constructor
/// and an <c>IHttpClientFactory</c>.
/// </summary>
/// <param name="certificates">An optional array of client certificates to associate with the handler.</param>
/// <returns>
/// A client handler with deflate and gZip compression-decompression algorithms and any client
/// certificates passed in via <c>certificates</c>.
/// </returns>
public virtual HttpClientHandler CreateHttpClientHandler(X509Certificate[] certificates = null)
{
var handler = new HttpClientHandler();
if (certificates != null)
handler.ClientCertificates.AddRange(certificates);
handler.AutomaticDecompression = System.Net.DecompressionMethods.Deflate | System.Net.DecompressionMethods.GZip;
return handler;
}
private HttpClient CreateClient(IDictionary<string, string> customRequestHeaders)
{
var handler = CreateHttpClientHandler(_certificates);
var httpClient = new HttpClient(handler);
if (customRequestHeaders != null)
{
foreach (var item in customRequestHeaders)
{
httpClient.DefaultRequestHeaders.Add(item.Key, item.Value);
}
}
return httpClient;
}
private void ConfigureClient(HttpClient httpClient)
{
if (_connectTimeout > 0)
{
httpClient.Timeout = TimeSpan.FromMilliseconds(_connectTimeout);
}
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/x-thrift"));
// Clear any user agent values to avoid drift with the field value
httpClient.DefaultRequestHeaders.UserAgent.Clear();
httpClient.DefaultRequestHeaders.UserAgent.TryParseAdd(UserAgent);
httpClient.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("deflate"));
httpClient.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
}
public override async Task FlushAsync(CancellationToken cancellationToken)
{
try
{
_outputStream.Seek(0, SeekOrigin.Begin);
using (var contentStream = new StreamContent(_outputStream))
{
contentStream.Headers.ContentType = ContentType ?? new MediaTypeHeaderValue(@"application/x-thrift");
var response = (await _httpClient.PostAsync(_uri, contentStream, cancellationToken)).EnsureSuccessStatusCode();
_inputStream?.Dispose();
#if NET5_0_OR_GREATER
_inputStream = await response.Content.ReadAsStreamAsync(cancellationToken);
#else
_inputStream = await response.Content.ReadAsStreamAsync();
#endif
if (_inputStream.CanSeek)
{
_inputStream.Seek(0, SeekOrigin.Begin);
}
}
}
catch (IOException iox)
{
throw new TTransportException(TTransportException.ExceptionType.Unknown, iox.ToString(), iox);
}
catch (HttpRequestException wx)
{
throw new TTransportException(TTransportException.ExceptionType.Unknown,
"Couldn't connect to server: " + wx, wx);
}
catch (OperationCanceledException ocx)
{
throw new TTransportException(TTransportException.ExceptionType.Interrupted, ocx.Message, ocx);
}
catch (Exception ex)
{
throw new TTransportException(TTransportException.ExceptionType.Unknown, ex.Message, ex);
}
finally
{
_outputStream = new MemoryStream();
ResetMessageSizeAndConsumedBytes();
}
}
// IDisposable
protected override void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
_inputStream?.Dispose();
_outputStream?.Dispose();
_httpClient?.Dispose();
}
}
_isDisposed = true;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ffdc5327b1fab754789b71906c403f6a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,178 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Thrift.Transport.Client
{
// ReSharper disable once InconsistentNaming
public class TMemoryBufferTransport : TEndpointTransport
{
private bool IsDisposed;
private byte[] Bytes;
private int _bytesUsed;
public TMemoryBufferTransport(TConfiguration config, int initialCapacity = 2048)
: base(config)
{
Bytes = new byte[initialCapacity];
}
public TMemoryBufferTransport(byte[] buf, TConfiguration config)
:base(config)
{
Bytes = (byte[])buf.Clone();
_bytesUsed = Bytes.Length;
UpdateKnownMessageSize(_bytesUsed);
}
public int Position { get; set; }
public int Capacity
{
get
{
Debug.Assert(_bytesUsed <= Bytes.Length);
return Bytes.Length;
}
set
{
Array.Resize(ref Bytes, value);
_bytesUsed = value;
}
}
public int Length
{
get {
Debug.Assert(_bytesUsed <= Bytes.Length);
return _bytesUsed;
}
set {
if ((Bytes.Length < value) || (Bytes.Length > (10 * value)))
Array.Resize(ref Bytes, Math.Max(2048, (int)(value * 1.25)));
_bytesUsed = value;
}
}
public void SetLength(int value)
{
Length = value;
Position = Math.Min(Position, value);
}
public override bool IsOpen => true;
public override Task OpenAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override void Close()
{
/* do nothing */
}
public void Seek(int delta, SeekOrigin origin)
{
int newPos;
switch (origin)
{
case SeekOrigin.Begin:
newPos = delta;
break;
case SeekOrigin.Current:
newPos = Position + delta;
break;
case SeekOrigin.End:
newPos = _bytesUsed + delta;
break;
default:
throw new ArgumentException("Unrecognized value",nameof(origin));
}
if ((0 > newPos) || (newPos > _bytesUsed))
throw new ArgumentException("Cannot seek outside of the valid range",nameof(origin));
Position = newPos;
ResetMessageSizeAndConsumedBytes();
CountConsumedMessageBytes(Position);
}
public override ValueTask<int> ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
{
var count = Math.Min(Length - Position, length);
Buffer.BlockCopy(Bytes, Position, buffer, offset, count);
Position += count;
CountConsumedMessageBytes(count);
return new ValueTask<int>(count);
}
public override Task WriteAsync(byte[] buffer, CancellationToken cancellationToken)
{
return WriteAsync(buffer, 0, buffer.Length, cancellationToken);
}
public override Task WriteAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
{
var free = Length - Position;
Length = Length + count - free;
Buffer.BlockCopy(buffer, offset, Bytes, Position, count);
Position += count;
return Task.CompletedTask;
}
public override Task FlushAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
ResetMessageSizeAndConsumedBytes();
return Task.CompletedTask;
}
public byte[] GetBuffer()
{
var retval = new byte[Length];
Buffer.BlockCopy(Bytes, 0, retval, 0, Length);
return retval;
}
internal bool TryGetBuffer(out ArraySegment<byte> bufSegment)
{
bufSegment = new ArraySegment<byte>(Bytes, 0, _bytesUsed);
return true;
}
// IDisposable
protected override void Dispose(bool disposing)
{
if (!IsDisposed)
{
if (disposing)
{
// nothing to do
}
}
IsDisposed = true;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7c87ebc03dc66ae47be0456d1e90e133
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,133 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.IO.Pipes;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;
namespace Thrift.Transport.Client
{
// ReSharper disable once InconsistentNaming
public class TNamedPipeTransport : TEndpointTransport
{
private NamedPipeClientStream PipeStream;
private readonly int ConnectTimeout;
private const int DEFAULT_CONNECT_TIMEOUT = 60 * 1000; // Timeout.Infinite is not a good default
public TNamedPipeTransport(string pipe, TConfiguration config, int timeout = DEFAULT_CONNECT_TIMEOUT)
: this(".", pipe, config, timeout)
{
}
public TNamedPipeTransport(string server, string pipe, TConfiguration config, int timeout = DEFAULT_CONNECT_TIMEOUT)
: base(config)
{
var serverName = string.IsNullOrWhiteSpace(server) ? server : ".";
ConnectTimeout = (timeout > 0) ? timeout : DEFAULT_CONNECT_TIMEOUT;
PipeStream = new NamedPipeClientStream(serverName, pipe, PipeDirection.InOut, PipeOptions.None, TokenImpersonationLevel.Anonymous);
}
public override bool IsOpen => PipeStream != null && PipeStream.IsConnected;
public override async Task OpenAsync(CancellationToken cancellationToken)
{
if (IsOpen)
{
throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen);
}
await PipeStream.ConnectAsync( ConnectTimeout, cancellationToken);
ResetMessageSizeAndConsumedBytes();
}
public override void Close()
{
if (PipeStream != null)
{
if (PipeStream.IsConnected)
PipeStream.Close();
PipeStream.Dispose();
PipeStream = null;
}
}
public override async ValueTask<int> ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
{
if (PipeStream == null)
{
throw new TTransportException(TTransportException.ExceptionType.NotOpen);
}
CheckReadBytesAvailable(length);
#if NET5_0_OR_GREATER
var numRead = await PipeStream.ReadAsync(new Memory<byte>(buffer, offset, length), cancellationToken);
#else
var numRead = await PipeStream.ReadAsync(buffer, offset, length, cancellationToken);
#endif
CountConsumedMessageBytes(numRead);
return numRead;
}
public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
{
if (PipeStream == null)
{
throw new TTransportException(TTransportException.ExceptionType.NotOpen);
}
// if necessary, send the data in chunks
// there's a system limit around 0x10000 bytes that we hit otherwise
// MSDN: "Pipe write operations across a network are limited to 65,535 bytes per write. For more information regarding pipes, see the Remarks section."
var nBytes = Math.Min(15 * 4096, length); // 16 would exceed the limit
while (nBytes > 0)
{
#if NET5_0_OR_GREATER
await PipeStream.WriteAsync(buffer.AsMemory(offset, nBytes), cancellationToken);
#else
await PipeStream.WriteAsync(buffer, offset, nBytes, cancellationToken);
#endif
offset += nBytes;
length -= nBytes;
nBytes = Math.Min(nBytes, length);
}
}
public override async Task FlushAsync(CancellationToken cancellationToken)
{
await PipeStream.FlushAsync(cancellationToken);
ResetMessageSizeAndConsumedBytes();
}
protected override void Dispose(bool disposing)
{
if (disposing)
{
if (PipeStream != null)
{
if (PipeStream.IsConnected)
PipeStream.Close();
PipeStream.Dispose();
PipeStream = null;
}
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d5fcf3d3e1ec0e94abe92fa217bc88df
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,229 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Threading.Tasks;
namespace Thrift.Transport.Client
{
// ReSharper disable once InconsistentNaming
public class TSocketTransport : TStreamTransport
{
private bool _isDisposed;
public TSocketTransport(TcpClient client, TConfiguration config)
: base(config)
{
TcpClient = client ?? throw new ArgumentNullException(nameof(client));
SetInputOutputStream();
}
/// <summary>
/// The constructor for a TSocketTransport which takes an IPAddress object.
/// </summary>
/// <param name="host">The IP address.</param>
/// <param name="port">The TcpClient port number.</param>
/// <param name="config">The <see cref="TConfiguration"/>.</param>
/// <param name="timeout">The TcpClient send timeout.</param>
/// <remarks>
/// The TcpClient is not connected automatically. You are required to use <see cref="OpenAsync(CancellationToken)"/>.
/// </remarks>
public TSocketTransport(IPAddress host, int port, TConfiguration config, int timeout = 0)
: base(config)
{
Host = host;
Port = port;
TcpClient = new TcpClient();
TcpClient.ReceiveTimeout = TcpClient.SendTimeout = timeout;
TcpClient.Client.NoDelay = true;
SetInputOutputStream();
}
/// <summary>
/// The constructor for a TSocketTransport which takes either a host name, e.g. 'host.example.com' and port number.
/// If host is not found using Dns.GetHostEntry(host) an exception will be thrown.
/// </summary>
/// <param name="host">The host name.</param>
/// <param name="port">The TcpClient port number.</param>
/// <param name="config">The <see cref="TConfiguration"/>.</param>
/// <param name="timeout">The TcpClient send timeout.</param>
/// <exception cref="TTransportException"></exception>
/// <remarks>
/// The TcpClient is connected automatically.
/// </remarks>
public TSocketTransport(string host, int port, TConfiguration config, int timeout = 0)
: base(config)
{
try
{
var entry = Dns.GetHostEntry(host);
if (entry.AddressList.Length == 0)
throw new TTransportException(TTransportException.ExceptionType.Unknown, "unable to resolve host name");
Host = entry.AddressList[0];
Port = port;
TcpClient = new TcpClient(host, port);
TcpClient.ReceiveTimeout = TcpClient.SendTimeout = timeout;
TcpClient.Client.NoDelay = true;
SetInputOutputStream();
}
catch (SocketException e)
{
throw new TTransportException(TTransportException.ExceptionType.Unknown, e.Message, e);
}
}
/// <summary>
/// <para>The constructor for a TSocketTransport which takes either a host name, e.g. 'host.example.com' or and IP address string, e.g '123.456.789' and port number.
/// If hostNameOrIpAddress represents a valid IP address this will be used directly.
/// If hostNameOrIpAddress does not represent a valid IP address an IP address will be retrieved using Dns.GetHostEntry(hostNameOrIpAddress).
/// If that fails an exception will be thrown.</para>
/// </summary>
/// <param name="hostNameOrIpAddress">The host name or IP address.</param>
/// <param name="port">The TcpClient port number.</param>
/// <param name="connectClient">If true attempt to connect the TcpClient.</param>
/// <param name="config">The <see cref="TConfiguration"/>.</param>
/// <param name="timeout">The TcpClient send timeout.</param>
/// <exception cref="TTransportException"></exception>
/// <remarks>
/// The TcpClient is connected dependent on the value of <paramref name="connectClient"/>./>.
/// </remarks>
public TSocketTransport(string hostNameOrIpAddress, int port, bool connectClient, TConfiguration config, int timeout = 0)
: base(config)
{
try
{
if (!IPAddress.TryParse(hostNameOrIpAddress, out var address))
{
var entry = Dns.GetHostEntry(hostNameOrIpAddress);
if (entry.AddressList.Length == 0)
throw new TTransportException(TTransportException.ExceptionType.Unknown, "unable to resolve host name");
address = entry.AddressList[0];
}
Host = address;
Port = port;
TcpClient = new TcpClient();
TcpClient.ReceiveTimeout = TcpClient.SendTimeout = timeout;
TcpClient.Client.NoDelay = true;
if (connectClient)
{
TcpClient.Connect(Host, Port);
}
SetInputOutputStream();
}
catch (SocketException e)
{
throw new TTransportException(TTransportException.ExceptionType.Unknown, e.Message, e);
}
}
private void SetInputOutputStream()
{
if (IsOpen)
{
InputStream = TcpClient.GetStream();
OutputStream = TcpClient.GetStream();
}
}
public TcpClient TcpClient { get; private set; }
public IPAddress Host { get; }
public int Port { get; }
public int Timeout
{
set
{
if (TcpClient != null)
{
TcpClient.ReceiveTimeout = TcpClient.SendTimeout = value;
}
}
}
public override bool IsOpen
{
get
{
return (TcpClient != null) && TcpClient.Connected;
}
}
public override async Task OpenAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
if (IsOpen)
{
throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected");
}
if (Port <= 0)
{
throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port");
}
if (TcpClient == null)
{
throw new InvalidOperationException("Invalid or not initialized tcp client");
}
await TcpClient.ConnectAsync(Host, Port);
SetInputOutputStream();
}
public override void Close()
{
base.Close();
if (TcpClient != null)
{
TcpClient.Dispose();
TcpClient = null;
}
}
// IDisposable
protected override void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
TcpClient?.Dispose();
base.Dispose(disposing);
}
}
_isDisposed = true;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a03affec5f36f2e468e27282faeb048a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,146 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Drawing;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Thrift.Transport.Client
{
// ReSharper disable once InconsistentNaming
public class TStreamTransport : TEndpointTransport
{
private bool _isDisposed;
protected TStreamTransport(TConfiguration config)
:base(config)
{
}
public TStreamTransport(Stream inputStream, Stream outputStream, TConfiguration config)
: base(config)
{
InputStream = inputStream;
OutputStream = outputStream;
}
protected Stream OutputStream { get; set; }
private Stream _InputStream = null;
protected Stream InputStream {
get => _InputStream;
set {
_InputStream = value;
ResetMessageSizeAndConsumedBytes(-1); // full reset to configured maximum
UpdateKnownMessageSize(-1); // adjust to real stream size
}
}
public override void UpdateKnownMessageSize(long size)
{
long adjusted = 0;
if (InputStream != null)
{
adjusted = MaxMessageSize;
if (size > 0)
adjusted = Math.Min(adjusted, size);
if( InputStream.CanSeek)
adjusted = Math.Min(adjusted, InputStream.Length);
}
base.UpdateKnownMessageSize(adjusted);
}
public override bool IsOpen => true;
public override Task OpenAsync(CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
return Task.CompletedTask;
}
public override void Close()
{
if (InputStream != null)
{
InputStream.Dispose();
InputStream = null;
}
if (OutputStream != null)
{
OutputStream.Dispose();
OutputStream = null;
}
}
public override async ValueTask<int> ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
{
if (InputStream == null)
{
throw new TTransportException(TTransportException.ExceptionType.NotOpen,
"Cannot read from null inputstream");
}
#if NET5_0_OR_GREATER
return await InputStream.ReadAsync(new Memory<byte>(buffer, offset, length), cancellationToken);
#else
return await InputStream.ReadAsync(buffer, offset, length, cancellationToken);
#endif
}
public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
{
if (OutputStream == null)
{
throw new TTransportException(TTransportException.ExceptionType.NotOpen,
"Cannot write to null outputstream");
}
#if NET5_0_OR_GREATER
await OutputStream.WriteAsync(buffer.AsMemory(offset, length), cancellationToken);
#else
await OutputStream.WriteAsync(buffer, offset, length, cancellationToken);
#endif
}
public override async Task FlushAsync(CancellationToken cancellationToken)
{
await OutputStream.FlushAsync(cancellationToken);
ResetMessageSizeAndConsumedBytes();
}
// IDisposable
protected override void Dispose(bool disposing)
{
if (!_isDisposed)
{
if (disposing)
{
InputStream?.Dispose();
OutputStream?.Dispose();
}
}
_isDisposed = true;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e145ef5b9c3663143b84e9befefe3a6c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,292 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Diagnostics;
using System.Net;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Threading.Tasks;
#pragma warning disable IDE0079 // net20 - unneeded suppression
#pragma warning disable IDE0028 // net8 - simplified collection init
namespace Thrift.Transport.Client
{
//TODO: check for correct work
// ReSharper disable once InconsistentNaming
public class TTlsSocketTransport : TStreamTransport
{
private readonly X509Certificate2 _certificate;
private readonly RemoteCertificateValidationCallback _certValidator;
private readonly IPAddress _host;
private readonly bool _isServer;
private readonly LocalCertificateSelectionCallback _localCertificateSelectionCallback;
private readonly int _port;
private readonly SslProtocols _sslProtocols;
private readonly string _targetHost;
private TcpClient _client;
private SslStream _secureStream;
private int _timeout;
#if NET7_0_OR_GREATER
public const SslProtocols DefaultSslProtocols = SslProtocols.Tls12 | SslProtocols.Tls13;
#else
public const SslProtocols DefaultSslProtocols = SslProtocols.Tls12;
#endif
public TTlsSocketTransport(TcpClient client, TConfiguration config,
X509Certificate2 certificate, bool isServer = false,
RemoteCertificateValidationCallback certValidator = null,
LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
SslProtocols sslProtocols = DefaultSslProtocols)
: base(config)
{
_client = client;
_certificate = certificate;
_certValidator = certValidator;
_localCertificateSelectionCallback = localCertificateSelectionCallback;
_sslProtocols = sslProtocols;
_isServer = isServer;
if (isServer && certificate == null)
{
throw new ArgumentException("TTlsSocketTransport needs certificate to be used for server",
nameof(certificate));
}
if (IsOpen)
{
InputStream = client.GetStream();
OutputStream = client.GetStream();
}
}
#if NET9_0_OR_GREATER
[Obsolete("SYSLIB0057: X509Certificate2 and X509Certificate constructors for binary and file content are obsolete")]
#pragma warning disable SYSLIB0057
#endif
public TTlsSocketTransport(IPAddress host, int port, TConfiguration config,
string certificatePath,
RemoteCertificateValidationCallback certValidator = null,
LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
SslProtocols sslProtocols = DefaultSslProtocols)
: this(host, port, config, 0,
new X509Certificate2(certificatePath),
certValidator,
localCertificateSelectionCallback,
sslProtocols)
{
}
#pragma warning restore SYSLIB0057
public TTlsSocketTransport(IPAddress host, int port, TConfiguration config,
X509Certificate2 certificate = null,
RemoteCertificateValidationCallback certValidator = null,
LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
SslProtocols sslProtocols = DefaultSslProtocols)
: this(host, port, config, 0,
certificate,
certValidator,
localCertificateSelectionCallback,
sslProtocols)
{
}
public TTlsSocketTransport(IPAddress host, int port, TConfiguration config, int timeout,
X509Certificate2 certificate,
RemoteCertificateValidationCallback certValidator = null,
LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
SslProtocols sslProtocols = DefaultSslProtocols)
: base(config)
{
_host = host;
_port = port;
_timeout = timeout;
_certificate = certificate;
_certValidator = certValidator;
_localCertificateSelectionCallback = localCertificateSelectionCallback;
_sslProtocols = sslProtocols;
InitSocket();
}
public TTlsSocketTransport(string host, int port, TConfiguration config, int timeout,
X509Certificate2 certificate,
RemoteCertificateValidationCallback certValidator = null,
LocalCertificateSelectionCallback localCertificateSelectionCallback = null,
SslProtocols sslProtocols = DefaultSslProtocols)
: base(config)
{
try
{
_targetHost = host;
var entry = Dns.GetHostEntry(host);
if (entry.AddressList.Length == 0)
throw new TTransportException(TTransportException.ExceptionType.Unknown, "unable to resolve host name");
_host = entry.AddressList[0];
_port = port;
_timeout = timeout;
_certificate = certificate;
_certValidator = certValidator;
_localCertificateSelectionCallback = localCertificateSelectionCallback;
_sslProtocols = sslProtocols;
InitSocket();
}
catch (SocketException e)
{
throw new TTransportException(TTransportException.ExceptionType.Unknown, e.Message, e);
}
}
public int Timeout
{
set { _client.ReceiveTimeout = _client.SendTimeout = _timeout = value; }
}
public TcpClient TcpClient => _client;
public IPAddress Host => _host;
public int Port => _port;
public override bool IsOpen
{
get
{
if (_client == null)
{
return false;
}
return _client.Connected;
}
}
private void InitSocket()
{
_client = new TcpClient();
_client.ReceiveTimeout = _client.SendTimeout = _timeout;
_client.Client.NoDelay = true;
}
private bool DefaultCertificateValidator(object sender, X509Certificate certificate, X509Chain chain,
SslPolicyErrors sslValidationErrors)
{
return sslValidationErrors == SslPolicyErrors.None;
}
public override async Task OpenAsync(CancellationToken cancellationToken)
{
if (IsOpen)
{
throw new TTransportException(TTransportException.ExceptionType.AlreadyOpen, "Socket already connected");
}
if (_host == null)
{
throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open null host");
}
if (_port <= 0)
{
throw new TTransportException(TTransportException.ExceptionType.NotOpen, "Cannot open without port");
}
if (_client == null)
{
InitSocket();
}
if (_client != null)
{
await _client.ConnectAsync(_host, _port);
await SetupTlsAsync();
}
}
public async Task SetupTlsAsync()
{
var validator = _certValidator ?? DefaultCertificateValidator;
if (_localCertificateSelectionCallback != null)
{
_secureStream = new SslStream(_client.GetStream(), false, validator, _localCertificateSelectionCallback);
}
else
{
_secureStream = new SslStream(_client.GetStream(), false, validator);
}
try
{
if (_isServer)
{
// Server authentication
await
_secureStream.AuthenticateAsServerAsync(_certificate, _certValidator != null, _sslProtocols,
true);
}
else
{
// Client authentication
var certs = _certificate != null
? new X509CertificateCollection { _certificate }
: new X509CertificateCollection();
var targetHost = _targetHost ?? _host.ToString();
await _secureStream.AuthenticateAsClientAsync(targetHost, certs, _sslProtocols, true);
}
}
catch (Exception)
{
Close();
throw;
}
InputStream = _secureStream;
OutputStream = _secureStream;
}
public override void Close()
{
base.Close();
if (_client != null)
{
_client.Dispose();
_client = null;
}
if (_secureStream != null)
{
_secureStream.Dispose();
_secureStream = null;
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 87695db59ada9b24ca9532c22d4e7430
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 825788dd34aebb141a8af1211bf684f7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,211 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
namespace Thrift.Transport
{
// ReSharper disable once InconsistentNaming
public class TBufferedTransport : TLayeredTransport
{
private readonly int DesiredBufferSize;
private readonly Client.TMemoryBufferTransport ReadBuffer;
private readonly Client.TMemoryBufferTransport WriteBuffer;
private bool IsDisposed;
public class Factory : TTransportFactory
{
public override TTransport GetTransport(TTransport trans)
{
return new TBufferedTransport(trans);
}
}
//TODO: should support only specified input transport?
public TBufferedTransport(TTransport transport, int bufSize = 1024)
: base(transport)
{
if (bufSize <= 0)
{
throw new ArgumentOutOfRangeException(nameof(bufSize), "Buffer size must be a positive number.");
}
DesiredBufferSize = bufSize;
WriteBuffer = new Client.TMemoryBufferTransport(InnerTransport.Configuration, bufSize);
ReadBuffer = new Client.TMemoryBufferTransport(InnerTransport.Configuration, bufSize);
Debug.Assert(DesiredBufferSize == ReadBuffer.Capacity);
Debug.Assert(DesiredBufferSize == WriteBuffer.Capacity);
}
public TTransport UnderlyingTransport
{
get
{
CheckNotDisposed();
return InnerTransport;
}
}
public override bool IsOpen => !IsDisposed && InnerTransport.IsOpen;
public override async Task OpenAsync(CancellationToken cancellationToken)
{
CheckNotDisposed();
await InnerTransport.OpenAsync(cancellationToken);
}
public override void Close()
{
CheckNotDisposed();
InnerTransport.Close();
}
public override async ValueTask<int> ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
{
CheckNotDisposed();
ValidateBufferArgs(buffer, offset, length);
if (!IsOpen)
{
throw new TTransportException(TTransportException.ExceptionType.NotOpen);
}
// do we have something buffered?
var count = ReadBuffer.Length - ReadBuffer.Position;
if (count > 0)
{
return await ReadBuffer.ReadAsync(buffer, offset, length, cancellationToken);
}
// does the request even fit into the buffer?
// Note we test for >= instead of > to avoid nonsense buffering
if (length >= ReadBuffer.Capacity)
{
return await InnerTransport.ReadAsync(buffer, offset, length, cancellationToken);
}
// buffer a new chunk of bytes from the underlying transport
ReadBuffer.Length = ReadBuffer.Capacity;
ReadBuffer.TryGetBuffer(out ArraySegment<byte> bufSegment);
ReadBuffer.Length = await InnerTransport.ReadAsync(bufSegment.Array, 0, bufSegment.Count, cancellationToken);
ReadBuffer.Position = 0;
// deliver the bytes
return await ReadBuffer.ReadAsync(buffer, offset, length, cancellationToken);
}
public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
{
CheckNotDisposed();
ValidateBufferArgs(buffer, offset, length);
if (!IsOpen)
{
throw new TTransportException(TTransportException.ExceptionType.NotOpen);
}
// enough space left in buffer?
var free = WriteBuffer.Capacity - WriteBuffer.Length;
if (length > free)
{
WriteBuffer.TryGetBuffer(out ArraySegment<byte> bufSegment);
await InnerTransport.WriteAsync(bufSegment.Array, 0, bufSegment.Count, cancellationToken);
WriteBuffer.SetLength(0);
}
// do the data even fit into the buffer?
// Note we test for < instead of <= to avoid nonsense buffering
if (length < WriteBuffer.Capacity)
{
await WriteBuffer.WriteAsync(buffer, offset, length, cancellationToken);
return;
}
// write thru
await InnerTransport.WriteAsync(buffer, offset, length, cancellationToken);
}
public override async Task FlushAsync(CancellationToken cancellationToken)
{
CheckNotDisposed();
if (!IsOpen)
{
throw new TTransportException(TTransportException.ExceptionType.NotOpen);
}
if (WriteBuffer.Length > 0)
{
WriteBuffer.TryGetBuffer(out ArraySegment<byte> bufSegment);
await InnerTransport.WriteAsync(bufSegment.Array, 0, bufSegment.Count, cancellationToken);
WriteBuffer.SetLength(0);
}
await InnerTransport.FlushAsync(cancellationToken);
}
public override void CheckReadBytesAvailable(long numBytes)
{
var buffered = ReadBuffer.Length - ReadBuffer.Position;
if (buffered < numBytes)
{
numBytes -= buffered;
InnerTransport.CheckReadBytesAvailable(numBytes);
}
}
public override void ResetMessageSizeAndConsumedBytes(long newSize = -1)
{
base.ResetMessageSizeAndConsumedBytes(newSize);
ReadBuffer.ResetMessageSizeAndConsumedBytes(newSize);
}
private void CheckNotDisposed()
{
if (IsDisposed)
{
throw new ObjectDisposedException(nameof(InnerTransport));
}
}
// IDisposable
protected override void Dispose(bool disposing)
{
if (!IsDisposed)
{
if (disposing)
{
ReadBuffer?.Dispose();
WriteBuffer?.Dispose();
InnerTransport?.Dispose();
}
}
IsDisposed = true;
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d92fa7b7befab22429bc60d6d107d6dd
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,200 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Buffers.Binary;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
#pragma warning disable IDE0079 // net20 - unneeded suppression
#pragma warning disable CA1510 // net8 - use ThrowIfNull
#pragma warning disable CA1513 // net8 - use ThrowIfNull
namespace Thrift.Transport
{
// ReSharper disable once InconsistentNaming
public class TFramedTransport : TLayeredTransport
{
private const int HeaderSize = 4;
private readonly byte[] HeaderBuf = new byte[HeaderSize];
private readonly Client.TMemoryBufferTransport ReadBuffer;
private readonly Client.TMemoryBufferTransport WriteBuffer;
private bool IsDisposed;
public class Factory : TTransportFactory
{
public override TTransport GetTransport(TTransport trans)
{
return new TFramedTransport(trans);
}
}
public TFramedTransport(TTransport transport)
: base(transport)
{
ReadBuffer = new Client.TMemoryBufferTransport(Configuration);
WriteBuffer = new Client.TMemoryBufferTransport(Configuration);
InitWriteBuffer();
}
public override bool IsOpen => !IsDisposed && InnerTransport.IsOpen;
public override async Task OpenAsync(CancellationToken cancellationToken)
{
CheckNotDisposed();
await InnerTransport.OpenAsync(cancellationToken);
}
public override void Close()
{
CheckNotDisposed();
InnerTransport.Close();
}
public override async ValueTask<int> ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
{
CheckNotDisposed();
ValidateBufferArgs(buffer, offset, length);
if (!IsOpen)
{
throw new TTransportException(TTransportException.ExceptionType.NotOpen);
}
// Read another frame of data if we run out of bytes
if (ReadBuffer.Position >= ReadBuffer.Length)
{
await ReadFrameAsync(cancellationToken);
}
return await ReadBuffer.ReadAsync(buffer, offset, length, cancellationToken);
}
private async ValueTask ReadFrameAsync(CancellationToken cancellationToken)
{
UpdateKnownMessageSize(-1);
await InnerTransport.ReadAllAsync(HeaderBuf, 0, HeaderSize, cancellationToken);
int size = BinaryPrimitives.ReadInt32BigEndian(HeaderBuf);
if ((0 > size) || (size > Configuration.MaxFrameSize)) // size must be in the range 0 to allowed max
throw new TTransportException(TTransportException.ExceptionType.Unknown, $"Maximum frame size exceeded ({size} bytes)");
UpdateKnownMessageSize(size + HeaderSize);
ReadBuffer.SetLength(size);
ReadBuffer.Seek(0, SeekOrigin.Begin);
ReadBuffer.TryGetBuffer(out ArraySegment<byte> bufSegment);
await InnerTransport.ReadAllAsync(bufSegment.Array, 0, size, cancellationToken);
}
public override async Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
{
CheckNotDisposed();
ValidateBufferArgs(buffer, offset, length);
if (!IsOpen)
{
throw new TTransportException(TTransportException.ExceptionType.NotOpen);
}
if (WriteBuffer.Length > (int.MaxValue - length))
{
await FlushAsync(cancellationToken);
}
await WriteBuffer.WriteAsync(buffer, offset, length, cancellationToken);
}
public override async Task FlushAsync(CancellationToken cancellationToken)
{
CheckNotDisposed();
if (!IsOpen)
{
throw new TTransportException(TTransportException.ExceptionType.NotOpen);
}
WriteBuffer.TryGetBuffer(out ArraySegment<byte> bufSegment);
int dataLen = bufSegment.Count - HeaderSize;
if (dataLen < 0)
{
throw new InvalidOperationException(); // logic error actually
}
// Inject message header into the reserved buffer space
BinaryPrimitives.WriteInt32BigEndian(bufSegment.Array, dataLen);
// Send the entire message at once
await InnerTransport.WriteAsync(bufSegment.Array, 0, bufSegment.Count, cancellationToken);
InitWriteBuffer();
await InnerTransport.FlushAsync(cancellationToken);
}
private void InitWriteBuffer()
{
// Reserve space for message header to be put right before sending it out
WriteBuffer.SetLength(HeaderSize);
WriteBuffer.Seek(0, SeekOrigin.End);
}
public override void CheckReadBytesAvailable(long numBytes)
{
var buffered = ReadBuffer.Length - ReadBuffer.Position;
if (buffered < numBytes)
{
numBytes -= buffered;
InnerTransport.CheckReadBytesAvailable(numBytes);
}
}
private void CheckNotDisposed()
{
if (IsDisposed)
{
throw new ObjectDisposedException(this.GetType().Name);
}
}
// IDisposable
protected override void Dispose(bool disposing)
{
if (!IsDisposed)
{
if (disposing)
{
ReadBuffer?.Dispose();
WriteBuffer?.Dispose();
InnerTransport?.Dispose();
}
}
IsDisposed = true;
}
public override void ResetMessageSizeAndConsumedBytes(long newSize = -1)
{
base.ResetMessageSizeAndConsumedBytes(newSize);
ReadBuffer.ResetMessageSizeAndConsumedBytes(newSize);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0812fa4415186fa458b001a437836b07
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,51 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
#pragma warning disable IDE0079 // net20 - unneeded suppression
#pragma warning disable IDE0290 // net8 - primary CTOR
namespace Thrift.Transport
{
public abstract class TLayeredTransport : TTransport
{
public readonly TTransport InnerTransport;
public override TConfiguration Configuration { get => InnerTransport.Configuration; }
public TLayeredTransport(TTransport transport)
{
InnerTransport = transport ?? throw new ArgumentNullException(nameof(transport));
}
public override void UpdateKnownMessageSize(long size)
{
InnerTransport.UpdateKnownMessageSize(size);
}
public override void CheckReadBytesAvailable(long numBytes)
{
InnerTransport.CheckReadBytesAvailable(numBytes);
}
public override void ResetMessageSizeAndConsumedBytes(long newSize = -1)
{
InnerTransport.ResetMessageSizeAndConsumedBytes(newSize);
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dc408d6d74391774fa67e1874cff1ad3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,104 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
namespace Thrift.Transport
{
abstract public class TEndpointTransport : TTransport
{
protected long MaxMessageSize { get => Configuration.MaxMessageSize; }
protected long KnownMessageSize { get; private set; }
protected long RemainingMessageSize { get; private set; }
private readonly TConfiguration _configuration;
public override TConfiguration Configuration { get => _configuration; }
public TEndpointTransport( TConfiguration config)
{
_configuration = config ?? new TConfiguration();
Debug.Assert(Configuration != null);
ResetMessageSizeAndConsumedBytes();
}
/// <summary>
/// Resets RemainingMessageSize to the configured maximum
/// </summary>
public override void ResetMessageSizeAndConsumedBytes(long newSize = -1)
{
// full reset
if (newSize < 0)
{
KnownMessageSize = MaxMessageSize;
RemainingMessageSize = MaxMessageSize;
return;
}
// update only: message size can shrink, but not grow
Debug.Assert(KnownMessageSize <= MaxMessageSize);
if (newSize > KnownMessageSize)
throw new TTransportException(TTransportException.ExceptionType.EndOfFile, "MaxMessageSize reached");
KnownMessageSize = newSize;
RemainingMessageSize = newSize;
}
/// <summary>
/// Updates RemainingMessageSize to reflect then known real message size (e.g. framed transport).
/// Will throw if we already consumed too many bytes or if the new size is larger than allowed.
/// </summary>
/// <param name="size"></param>
public override void UpdateKnownMessageSize(long size)
{
var consumed = KnownMessageSize - RemainingMessageSize;
ResetMessageSizeAndConsumedBytes(size);
CountConsumedMessageBytes(consumed);
}
/// <summary>
/// Throws if there are not enough bytes in the input stream to satisfy a read of numBytes bytes of data
/// </summary>
/// <param name="numBytes"></param>
public override void CheckReadBytesAvailable(long numBytes)
{
if ((RemainingMessageSize < numBytes) || (numBytes < 0))
throw new TTransportException(TTransportException.ExceptionType.EndOfFile, "MaxMessageSize reached");
}
/// <summary>
/// Consumes numBytes from the RemainingMessageSize.
/// </summary>
/// <param name="numBytes"></param>
protected void CountConsumedMessageBytes(long numBytes)
{
if (RemainingMessageSize >= numBytes)
{
RemainingMessageSize -= numBytes;
}
else
{
RemainingMessageSize = 0;
throw new TTransportException(TTransportException.ExceptionType.EndOfFile, "MaxMessageSize reached");
}
}
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b3057f0c3ff0ec442b1162cc8ef0055d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,174 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
#pragma warning disable IDE0079 // net20 - unneeded suppression
#pragma warning disable CA1510 // net8 - use ThrowIfNull
#pragma warning disable CA1513 // net8 - use ThrowIfNull
namespace Thrift.Transport
{
//TODO: think about client info
// ReSharper disable once InconsistentNaming
public abstract class TTransport : IDisposable
{
//TODO: think how to avoid peek byte
private readonly byte[] _peekBuffer = new byte[1];
private bool _hasPeekByte;
public abstract bool IsOpen { get; }
public abstract TConfiguration Configuration { get; }
public abstract void UpdateKnownMessageSize(long size);
public abstract void CheckReadBytesAvailable(long numBytes);
public abstract void ResetMessageSizeAndConsumedBytes(long newSize = -1);
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public async ValueTask<bool> PeekAsync(CancellationToken cancellationToken)
{
//If we already have a byte read but not consumed, do nothing.
if (_hasPeekByte)
{
return true;
}
//If transport closed we can't peek.
if (!IsOpen)
{
return false;
}
//Try to read one byte. If succeeds we will need to store it for the next read.
try
{
var bytes = await ReadAsync(_peekBuffer, 0, 1, cancellationToken);
if (bytes == 0)
{
return false;
}
}
catch (IOException)
{
return false;
}
_hasPeekByte = true;
return true;
}
public abstract Task OpenAsync(CancellationToken cancellationToken = default);
public abstract void Close();
protected static void ValidateBufferArgs(byte[] buffer, int offset, int length)
{
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}
#if DEBUG // let it fail with OutOfRange in RELEASE mode
if (offset < 0)
{
throw new ArgumentOutOfRangeException(nameof(offset), "Buffer offset must be >= 0");
}
if (length < 0)
{
throw new ArgumentOutOfRangeException(nameof(length), "Buffer length must be >= 0");
}
if (offset + length > buffer.Length)
{
throw new ArgumentOutOfRangeException(nameof(buffer), "Not enough data");
}
#endif
}
public abstract ValueTask<int> ReadAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken);
public virtual async ValueTask<int> ReadAllAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken)
{
cancellationToken.ThrowIfCancellationRequested();
ValidateBufferArgs(buffer, offset, length);
if (length <= 0)
return 0;
// If we previously peeked a byte, we need to use that first.
var totalBytes = 0;
if (_hasPeekByte)
{
buffer[offset++] = _peekBuffer[0];
_hasPeekByte = false;
if (1 == length)
{
return 1; // we're done
}
++totalBytes;
}
var remaining = length - totalBytes;
Debug.Assert(remaining > 0); // any other possible cases should have been handled already
while (true)
{
var numBytes = await ReadAsync(buffer, offset, remaining, cancellationToken);
totalBytes += numBytes;
if (totalBytes >= length)
{
return totalBytes; // we're done
}
if (numBytes <= 0)
{
throw new TTransportException(TTransportException.ExceptionType.EndOfFile,
"Cannot read, Remote side has closed");
}
remaining -= numBytes;
offset += numBytes;
}
}
public virtual async Task WriteAsync(byte[] buffer, CancellationToken cancellationToken)
{
await WriteAsync(buffer, 0, buffer.Length, CancellationToken.None);
}
public virtual async Task WriteAsync(byte[] buffer, int offset, int length)
{
await WriteAsync(buffer, offset, length, CancellationToken.None);
}
public abstract Task WriteAsync(byte[] buffer, int offset, int length, CancellationToken cancellationToken);
public abstract Task FlushAsync(CancellationToken cancellationToken);
protected abstract void Dispose(bool disposing);
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f958cc470d8907f4ba2de25376b7a1ea
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,60 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
using System;
namespace Thrift.Transport
{
// ReSharper disable once InconsistentNaming
public class TTransportException : TException
{
public enum ExceptionType
{
Unknown,
NotOpen,
AlreadyOpen,
TimedOut,
EndOfFile,
Interrupted
}
public ExceptionType ExType { get; private set; }
public TTransportException()
{
}
public TTransportException(ExceptionType exType, Exception inner = null)
: base(string.Empty, inner)
{
ExType = exType;
}
public TTransportException(ExceptionType exType, string message, Exception inner = null)
: base(message, inner)
{
ExType = exType;
}
public TTransportException(string message, Exception inner = null)
: base(message, inner)
{
}
public ExceptionType Type => ExType;
}
}

View File

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: bf3f37d29b264014c903e1a4dffd1ed5
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,35 @@
// Licensed to the Apache Software Foundation(ASF) under one
// or more contributor license agreements.See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
namespace Thrift.Transport
{
/// <summary>
/// From Mark Slee &amp; Aditya Agarwal of Facebook:
/// Factory class used to create wrapped instance of Transports.
/// This is used primarily in servers, which get Transports from
/// a ServerTransport and then may want to mutate them (i.e. create
/// a BufferedTransport from the underlying base transport)
/// </summary>
// ReSharper disable once InconsistentNaming
public class TTransportFactory
{
public virtual TTransport GetTransport(TTransport trans)
{
return trans;
}
}
}

Some files were not shown because too many files have changed in this diff Show More