Initial Package for Thrift
This commit is contained in:
commit
3465725ed7
106
.gitignore
vendored
Normal file
106
.gitignore
vendored
Normal 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
|
||||
BIN
OriginalSource/thrift-0.22.0.tar.gz
Normal file
BIN
OriginalSource/thrift-0.22.0.tar.gz
Normal file
Binary file not shown.
8
Packages/com.bywaystudios.thrift/Runtime.meta
Normal file
8
Packages/com.bywaystudios.thrift/Runtime.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3a88ce6a250be42458ee10a717243914
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9570817580e1c32429e39fada8dd7b18
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6bd25820bab7e434aab147a0e6c0e8e7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e4336f3dc60386743b1c02f11df6fc99
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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")]
|
||||
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 595997754e2b7f541b41beda5001eabe
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/com.bywaystudios.thrift/Runtime/Properties.meta
Normal file
8
Packages/com.bywaystudios.thrift/Runtime/Properties.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5646b840c862f5a43a9f7fd65fd98e5f
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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")]
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cc3f9dc06d8829e43ab512a42384f133
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/com.bywaystudios.thrift/Runtime/Protocol.meta
Normal file
8
Packages/com.bywaystudios.thrift/Runtime/Protocol.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 172a2294fc8d1c74c9afd1ea617e1b86
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6156f3fc3227424282ffe1caa5276ff
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4cf4634e90ef156469d9c18a5ef260ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e853389f4c494204897e587c81be25ca
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c32933786e22b34286eb36df8f3c354
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 930f6d7df6e483743b9814df89e7f4ff
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a12e210a3b515904c9efc20848c86157
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f793acd60eaa194baa0acc12bd2363c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7375aae91c68c944a812e233bdf45f7d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aca0928aaf4273349b4a3aaab6c86eab
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
36
Packages/com.bywaystudios.thrift/Runtime/Protocol/TBase.cs
Normal file
36
Packages/com.bywaystudios.thrift/Runtime/Protocol/TBase.cs
Normal 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);
|
||||
}
|
||||
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d678ef8837850994788ab62b1041d807
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 560b2c8f00f662f46a9ebd661e8b62bb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3124fc994ddc723458d1ca617ecfa78f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
1044
Packages/com.bywaystudios.thrift/Runtime/Protocol/TJSONProtocol.cs
Normal file
1044
Packages/com.bywaystudios.thrift/Runtime/Protocol/TJSONProtocol.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2852a1ad0426ea54aa516b762a3ce775
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 785a0b3fdff50d5489cdd7626de12986
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
199
Packages/com.bywaystudios.thrift/Runtime/Protocol/TProtocol.cs
Normal file
199
Packages/com.bywaystudios.thrift/Runtime/Protocol/TProtocol.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 707e55b50657bac48b6aa280c626c7aa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 19b5bca1a81ff0e4d950ab9a26a08350
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4ba605f7d63e1314f9b930e4b8a2c7be
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bc1306af0fbb4444aabfb648f3361e7e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2074e4c9459760546bd43505c9481d62
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bb04768de16698c41a44db64dc06a464
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 761fd254a87199345ac100ae7ad63f88
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a7f1fdb7231fce94086107b61128e0b7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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' };
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e217a11c484220b4aaf3b2b92127067c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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');
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c0b7b8082d4f82543b7d7e4ec25a8596
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da904c2c7f62df841acde0448f0b0a6f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f86d77c239225104cab74e32b14c5d93
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
91
Packages/com.bywaystudios.thrift/Runtime/TBaseClient.cs
Normal file
91
Packages/com.bywaystudios.thrift/Runtime/TBaseClient.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Packages/com.bywaystudios.thrift/Runtime/TBaseClient.cs.meta
Normal file
11
Packages/com.bywaystudios.thrift/Runtime/TBaseClient.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: af1fb0222ec8a574aa069e3d3c4a7c94
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
36
Packages/com.bywaystudios.thrift/Runtime/TConfiguration.cs
Normal file
36
Packages/com.bywaystudios.thrift/Runtime/TConfiguration.cs
Normal 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
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 25f18e47ae18a504e9bd1b18dd0bac49
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
34
Packages/com.bywaystudios.thrift/Runtime/TException.cs
Normal file
34
Packages/com.bywaystudios.thrift/Runtime/TException.cs
Normal 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)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Packages/com.bywaystudios.thrift/Runtime/TException.cs.meta
Normal file
11
Packages/com.bywaystudios.thrift/Runtime/TException.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c31d338acd518d47894f98047ffe9ab
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
14
Packages/com.bywaystudios.thrift/Runtime/Thrift.asmdef
Normal file
14
Packages/com.bywaystudios.thrift/Runtime/Thrift.asmdef
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "Thrift",
|
||||
"rootNamespace": "",
|
||||
"references": [],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 80bc5989de867864f925938fc1ceb864
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Packages/com.bywaystudios.thrift/Runtime/Transport.meta
Normal file
8
Packages/com.bywaystudios.thrift/Runtime/Transport.meta
Normal file
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0de584fe90b6ad447a3e305ab93ec9c3
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5b44f0b64f17bfb45ae3deb0647b1078
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ffdc5327b1fab754789b71906c403f6a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7c87ebc03dc66ae47be0456d1e90e133
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d5fcf3d3e1ec0e94abe92fa217bc88df
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a03affec5f36f2e468e27282faeb048a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e145ef5b9c3663143b84e9befefe3a6c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 87695db59ada9b24ca9532c22d4e7430
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 825788dd34aebb141a8af1211bf684f7
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d92fa7b7befab22429bc60d6d107d6dd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0812fa4415186fa458b001a437836b07
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dc408d6d74391774fa67e1874cff1ad3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b3057f0c3ff0ec442b1162cc8ef0055d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
174
Packages/com.bywaystudios.thrift/Runtime/Transport/TTransport.cs
Normal file
174
Packages/com.bywaystudios.thrift/Runtime/Transport/TTransport.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f958cc470d8907f4ba2de25376b7a1ea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf3f37d29b264014c903e1a4dffd1ed5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -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 & 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
Loading…
Reference in New Issue
Block a user