├── .gitignore ├── NuGet └── NuGet.exe ├── README.md ├── Tarantool.Net.Examples ├── App.config ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── Tarantool.Net.Examples.csproj └── packages.config ├── Tarantool.Net.Tests ├── App.config ├── Properties │ └── AssemblyInfo.cs ├── Tarantool.Net.Tests.csproj ├── TarantoolClientTest.cs └── packages.config ├── Tarantool.Net.sln └── Tarantool.Net ├── AuthToken.cs ├── Connection.cs ├── IProto ├── Builders │ ├── AuthRequestBuilder.cs │ ├── CallRequestBuilder.cs │ ├── DeleteRequestBuilder.cs │ ├── EvalRequestBuilder.cs │ ├── InsertRequestBuilder.cs │ ├── OperationsTupleBuilder.cs │ ├── PingRequestBuilder.cs │ ├── ReplaceRequestBuilder.cs │ ├── SelectRequestBuilder.cs │ ├── TupleBuilder.cs │ ├── UpdateOperationsTupleBuilder.cs │ ├── UpdateRequestBuilder.cs │ └── UpsertRequestBuilder.cs ├── Command.cs ├── GreatingResponse.cs ├── Iterator.cs ├── Key.cs ├── OperationsTuple.cs ├── PacketHeader.cs ├── PacketType.cs ├── Request.cs ├── RequestBody.cs ├── Requests │ ├── AuthRequest.cs │ ├── CallRequest.cs │ ├── DeleteRequest.cs │ ├── EvalRequest.cs │ ├── InsertReplaceRequest.cs │ ├── PingRequest.cs │ ├── RequestBase.cs │ ├── SelectRequest.cs │ ├── UpdateRequest.cs │ └── UpsertRequest.cs ├── Response.cs ├── Tuple.cs ├── UpdateOperation.cs └── UpdateOperationCode.cs ├── Properties └── AssemblyInfo.cs ├── Tarantool.Net.csproj ├── Tarantool.Net.nuspec ├── Tarantool.cs ├── TarantoolConnectionSupervisor.cs ├── app.config └── packages.config /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | x64/ 19 | x86/ 20 | build/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | 28 | # MSTest test Results 29 | [Tt]est[Rr]esult*/ 30 | [Bb]uild[Ll]og.* 31 | 32 | # NUNIT 33 | *.VisualState.xml 34 | TestResult.xml 35 | 36 | # Build Results of an ATL Project 37 | [Dd]ebugPS/ 38 | [Rr]eleasePS/ 39 | dlldata.c 40 | 41 | # DNX 42 | project.lock.json 43 | artifacts/ 44 | 45 | *_i.c 46 | *_p.c 47 | *_i.h 48 | *.ilk 49 | *.meta 50 | *.obj 51 | *.pch 52 | *.pdb 53 | *.pgc 54 | *.pgd 55 | *.rsp 56 | *.sbr 57 | *.tlb 58 | *.tli 59 | *.tlh 60 | *.tmp 61 | *.tmp_proj 62 | *.log 63 | *.vspscc 64 | *.vssscc 65 | .builds 66 | *.pidb 67 | *.svclog 68 | *.scc 69 | 70 | # Chutzpah Test files 71 | _Chutzpah* 72 | 73 | # Visual C++ cache files 74 | ipch/ 75 | *.aps 76 | *.ncb 77 | *.opensdf 78 | *.sdf 79 | *.cachefile 80 | 81 | # Visual Studio profiler 82 | *.psess 83 | *.vsp 84 | *.vspx 85 | 86 | # TFS 2012 Local Workspace 87 | $tf/ 88 | 89 | # Guidance Automation Toolkit 90 | *.gpState 91 | 92 | # ReSharper is a .NET coding add-in 93 | _ReSharper*/ 94 | *.[Rr]e[Ss]harper 95 | *.DotSettings.user 96 | 97 | # JustCode is a .NET coding add-in 98 | .JustCode 99 | 100 | # TeamCity is a build add-in 101 | _TeamCity* 102 | 103 | # DotCover is a Code Coverage Tool 104 | *.dotCover 105 | 106 | # NCrunch 107 | _NCrunch_* 108 | .*crunch*.local.xml 109 | 110 | # MightyMoose 111 | *.mm.* 112 | AutoTest.Net/ 113 | 114 | # Web workbench (sass) 115 | .sass-cache/ 116 | 117 | # Installshield output folder 118 | [Ee]xpress/ 119 | 120 | # DocProject is a documentation generator add-in 121 | DocProject/buildhelp/ 122 | DocProject/Help/*.HxT 123 | DocProject/Help/*.HxC 124 | DocProject/Help/*.hhc 125 | DocProject/Help/*.hhk 126 | DocProject/Help/*.hhp 127 | DocProject/Help/Html2 128 | DocProject/Help/html 129 | 130 | # Click-Once directory 131 | publish/ 132 | 133 | # Publish Web Output 134 | *.[Pp]ublish.xml 135 | *.azurePubxml 136 | ## TODO: Comment the next line if you want to checkin your 137 | ## web deploy settings but do note that will include unencrypted 138 | ## passwords 139 | #*.pubxml 140 | 141 | *.publishproj 142 | 143 | # NuGet Packages 144 | *.nupkg 145 | # The packages folder can be ignored because of Package Restore 146 | **/packages/* 147 | # except build/, which is used as an MSBuild target. 148 | !**/packages/build/ 149 | # Uncomment if necessary however generally it will be regenerated when needed 150 | #!**/packages/repositories.config 151 | 152 | # Windows Azure Build Output 153 | csx/ 154 | *.build.csdef 155 | 156 | # Windows Store app package directory 157 | AppPackages/ 158 | 159 | # Visual Studio cache files 160 | # files ending in .cache can be ignored 161 | *.[Cc]ache 162 | # but keep track of directories ending in .cache 163 | !*.[Cc]ache/ 164 | 165 | # Others 166 | ClientBin/ 167 | [Ss]tyle[Cc]op.* 168 | ~$* 169 | *~ 170 | *.dbmdl 171 | *.dbproj.schemaview 172 | *.pfx 173 | *.publishsettings 174 | node_modules/ 175 | orleans.codegen.cs 176 | 177 | # RIA/Silverlight projects 178 | Generated_Code/ 179 | 180 | # Backup & report files from converting an old project file 181 | # to a newer Visual Studio version. Backup files are not needed, 182 | # because we have git ;-) 183 | _UpgradeReport_Files/ 184 | Backup*/ 185 | UpgradeLog*.XML 186 | UpgradeLog*.htm 187 | 188 | # SQL Server files 189 | *.mdf 190 | *.ldf 191 | 192 | # Business Intelligence projects 193 | *.rdl.data 194 | *.bim.layout 195 | *.bim_*.settings 196 | 197 | # Microsoft Fakes 198 | FakesAssemblies/ 199 | 200 | # Node.js Tools for Visual Studio 201 | .ntvs_analysis.dat 202 | 203 | # Visual Studio 6 build log 204 | *.plg 205 | 206 | # Visual Studio 6 workspace options file 207 | *.opt 208 | 209 | # LightSwitch generated files 210 | GeneratedArtifacts/ 211 | _Pvt_Extensions/ 212 | ModelManifest.xml 213 | -------------------------------------------------------------------------------- /NuGet/NuGet.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/donmikel/tarantool-net/894e9adf31dab3586624f3bb26d93b1fc67ce71f/NuGet/NuGet.exe -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # tarantool-net [![NuGet version](https://badge.fury.io/nu/Tarantool.NET.svg)](https://badge.fury.io/nu/Tarantool.NET) [![Build status](https://ci.appveyor.com/api/projects/status/66ecs2jx3qx0qb3i?svg=true)](https://ci.appveyor.com/project/donmikel/tarantool-net) 2 | A .Net client for Tarantool http://tarantool.org written with the Akka.Net I/O package 3 | 4 | This is beta version. It is necessary to increase the test coverage. 5 | 6 | 7 | Some Docs wiil be soon. 8 | -------------------------------------------------------------------------------- /Tarantool.Net.Examples/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 |
5 | 6 | 7 | 8 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /Tarantool.Net.Examples/Program.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Akka; 3 | using Akka.Actor; 4 | using Tarantool.Net.IProto; 5 | 6 | namespace Tarantool.Net.Examples 7 | { 8 | static class Program 9 | { 10 | static ActorSystem _actorSystem; 11 | 12 | [STAThread] 13 | static void Main() 14 | { 15 | _actorSystem = ActorSystem.Create("tarantool"); 16 | var connection = _actorSystem.ActorOf(Tarantool.Create()); 17 | 18 | connection.Ask(Request 19 | .Select() 20 | .WithSpaceId(512) 21 | .WithIndexId(0) 22 | .WithIterator(Iterator.ALL) 23 | .Build()) 24 | .Result 25 | .Match() 26 | .With(f => 27 | { 28 | Console.WriteLine($"Error: {f.Exception}"); 29 | }) 30 | .With(r => 31 | { 32 | foreach (var tuple in r.Body) 33 | { 34 | Console.WriteLine(tuple); 35 | } 36 | 37 | }); 38 | 39 | Console.ReadLine(); 40 | } 41 | 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /Tarantool.Net.Examples/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Управление общими сведениями о сборке осуществляется с помощью 6 | // набора атрибутов. Измените значения этих атрибутов, чтобы изменить сведения, 7 | // связанные со сборкой. 8 | [assembly: AssemblyTitle("Tarantool.Net.Examples")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Tarantool.Net.Examples")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Параметр ComVisible со значением FALSE делает типы в сборке невидимыми 18 | // для COM-компонентов. Если требуется обратиться к типу в этой сборке через 19 | // COM, задайте атрибуту ComVisible значение TRUE для этого типа. 20 | [assembly: ComVisible(false)] 21 | 22 | // Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM 23 | [assembly: Guid("cc7a5732-d9cf-4038-a34b-2e48491df032")] 24 | 25 | // Сведения о версии сборки состоят из следующих четырех значений: 26 | // 27 | // Основной номер версии 28 | // Дополнительный номер версии 29 | // Номер сборки 30 | // Редакция 31 | // 32 | // Можно задать все значения или принять номера сборки и редакции по умолчанию 33 | // используя "*", как показано ниже: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Tarantool.Net.Examples/Tarantool.Net.Examples.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {CC7A5732-D9CF-4038-A34B-2E48491DF032} 8 | Exe 9 | Properties 10 | Tarantool.Net.Examples 11 | Tarantool.Net.Examples 12 | v4.5.2 13 | 512 14 | true 15 | 16 | 17 | x64 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | AnyCPU 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\packages\Akka.1.0.7\lib\net45\Akka.dll 38 | True 39 | 40 | 41 | ..\packages\MsgPack.Cli.0.6.8\lib\net45\MsgPack.dll 42 | True 43 | 44 | 45 | ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll 46 | True 47 | 48 | 49 | 50 | ..\packages\System.Collections.Immutable.1.1.37\lib\dotnet\System.Collections.Immutable.dll 51 | True 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | Designer 71 | 72 | 73 | 74 | 75 | {8EE464C8-B151-42C3-96BF-8D655FF8B6B9} 76 | Tarantool.Net 77 | 78 | 79 | 80 | 87 | -------------------------------------------------------------------------------- /Tarantool.Net.Examples/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Tarantool.Net.Tests/App.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 |
6 | 7 | 8 | 9 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Tarantool.Net.Tests/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Управление общими сведениями о сборке осуществляется с помощью 6 | // набора атрибутов. Измените значения этих атрибутов, чтобы изменить сведения, 7 | // связанные со сборкой. 8 | [assembly: AssemblyTitle("Tarantool.Net.Tests")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Tarantool.Net.Tests")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Параметр ComVisible со значением FALSE делает типы в сборке невидимыми 18 | // для COM-компонентов. Если требуется обратиться к типу в этой сборке через 19 | // COM, задайте атрибуту ComVisible значение TRUE для этого типа. 20 | [assembly: ComVisible(false)] 21 | 22 | // Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM 23 | [assembly: Guid("8462a3a5-8c7d-4cd6-afc8-f487c23da28e")] 24 | 25 | // Сведения о версии сборки состоят из следующих четырех значений: 26 | // 27 | // Основной номер версии 28 | // Дополнительный номер версии 29 | // Номер сборки 30 | // Редакция 31 | // 32 | // Можно задать все значения или принять номера сборки и редакции по умолчанию 33 | // используя "*", как показано ниже: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Tarantool.Net.Tests/Tarantool.Net.Tests.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {8462A3A5-8C7D-4CD6-AFC8-F487C23DA28E} 8 | Library 9 | Properties 10 | Tarantool.Net.Tests 11 | Tarantool.Net.Tests 12 | v4.5.2 13 | 512 14 | 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | ..\packages\Akka.1.0.7\lib\net45\Akka.dll 37 | True 38 | 39 | 40 | ..\packages\Akka.TestKit.1.0.7\lib\net45\Akka.TestKit.dll 41 | True 42 | 43 | 44 | ..\packages\Akka.TestKit.Xunit2.1.0.7\lib\net45\Akka.TestKit.Xunit2.dll 45 | True 46 | 47 | 48 | ..\packages\MsgPack.Cli.0.6.8\lib\net45\MsgPack.dll 49 | True 50 | 51 | 52 | ..\packages\Newtonsoft.Json.8.0.3\lib\net45\Newtonsoft.Json.dll 53 | True 54 | 55 | 56 | 57 | ..\packages\System.Collections.Immutable.1.1.37\lib\dotnet\System.Collections.Immutable.dll 58 | True 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | ..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll 69 | True 70 | 71 | 72 | ..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll 73 | True 74 | 75 | 76 | ..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll 77 | True 78 | 79 | 80 | ..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll 81 | True 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | {8ee464c8-b151-42c3-96bf-8d655ff8b6b9} 95 | Tarantool.Net 96 | 97 | 98 | 99 | 100 | 101 | 102 | 109 | -------------------------------------------------------------------------------- /Tarantool.Net.Tests/TarantoolClientTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading; 4 | using Akka.Actor; 5 | using Akka.TestKit.Xunit2; 6 | using Tarantool.Net.IProto; 7 | using Xunit; 8 | using Xunit.Abstractions; 9 | 10 | namespace Tarantool.Net.Tests 11 | { 12 | public class TarantoolClientTest : TestKit 13 | { 14 | private readonly IActorRef _tarantool; 15 | public TarantoolClientTest() 16 | { 17 | _tarantool = ActorOfAsTestActorRef(Tarantool.Create(port: 3301, listeners: new HashSet { TestActor })); 18 | 19 | ExpectMsg(); 20 | ExpectMsg(); 21 | } 22 | 23 | [Fact(DisplayName = "Should respond to ping")] 24 | public void Ping() 25 | { 26 | _tarantool.Tell(Request.Ping().Build()); 27 | ExpectMsg(r => !r.IsError); 28 | } 29 | 30 | [Fact] 31 | public void Select() 32 | { 33 | _tarantool.Tell(Request 34 | .Select() 35 | .WithSpaceId(513) 36 | .WithIndexId(0) 37 | .WithIterator(Iterator.ALL) 38 | .Build() 39 | ); 40 | 41 | ExpectMsg(r => !r.IsError); 42 | } 43 | 44 | [Fact] 45 | public void Pipeline() 46 | { 47 | _tarantool.Tell(Request.Ping().Build()); 48 | _tarantool.Tell(Request.Ping().Build()); 49 | _tarantool.Tell(Request.Ping().Build()); 50 | 51 | ExpectMsg(); 52 | ExpectMsg(); 53 | ExpectMsg(); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /Tarantool.Net.Tests/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tarantool.Net.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.24720.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tarantool.Net", "Tarantool.Net\Tarantool.Net.csproj", "{8EE464C8-B151-42C3-96BF-8D655FF8B6B9}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tarantool.Net.Tests", "Tarantool.Net.Tests\Tarantool.Net.Tests.csproj", "{8462A3A5-8C7D-4CD6-AFC8-F487C23DA28E}" 9 | EndProject 10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tarantool.Net.Examples", "Tarantool.Net.Examples\Tarantool.Net.Examples.csproj", "{CC7A5732-D9CF-4038-A34B-2E48491DF032}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{35166E13-3CA4-4013-BB47-623FE1894423}" 13 | ProjectSection(SolutionItems) = preProject 14 | README.md = README.md 15 | EndProjectSection 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Release|Any CPU = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {8EE464C8-B151-42C3-96BF-8D655FF8B6B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {8EE464C8-B151-42C3-96BF-8D655FF8B6B9}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {8EE464C8-B151-42C3-96BF-8D655FF8B6B9}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {8EE464C8-B151-42C3-96BF-8D655FF8B6B9}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {8462A3A5-8C7D-4CD6-AFC8-F487C23DA28E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {8462A3A5-8C7D-4CD6-AFC8-F487C23DA28E}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {8462A3A5-8C7D-4CD6-AFC8-F487C23DA28E}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {8462A3A5-8C7D-4CD6-AFC8-F487C23DA28E}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {CC7A5732-D9CF-4038-A34B-2E48491DF032}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {CC7A5732-D9CF-4038-A34B-2E48491DF032}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {CC7A5732-D9CF-4038-A34B-2E48491DF032}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {CC7A5732-D9CF-4038-A34B-2E48491DF032}.Release|Any CPU.Build.0 = Release|Any CPU 35 | EndGlobalSection 36 | GlobalSection(SolutionProperties) = preSolution 37 | HideSolutionNode = FALSE 38 | EndGlobalSection 39 | GlobalSection(ExtensibilityGlobals) = postSolution 40 | EnterpriseLibraryConfigurationToolBinariesPath = packages\Unity.2.1.505.0\lib\NET35 41 | EndGlobalSection 42 | EndGlobal 43 | -------------------------------------------------------------------------------- /Tarantool.Net/AuthToken.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Tarantool.Net 4 | { 5 | public class AuthToken 6 | { 7 | public AuthToken(string username, string password) 8 | { 9 | Username = username; 10 | Password = password; 11 | } 12 | 13 | public string Username { get; private set; } 14 | public string Password { get; private set; } 15 | 16 | public static AuthToken GuestToken => new AuthToken("guest", string.Empty); 17 | } 18 | } -------------------------------------------------------------------------------- /Tarantool.Net/Connection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Diagnostics; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Threading; 7 | using System.Threading.Tasks; 8 | using Akka.Actor; 9 | using Akka.Event; 10 | using Akka.IO; 11 | using MsgPack.Serialization; 12 | using Tarantool.Net.IProto; 13 | using Tarantool.Net.IProto.Requests; 14 | using Dns = System.Net.Dns; 15 | using Tuple = System.Tuple; 16 | 17 | namespace Tarantool.Net 18 | { 19 | public class Connection : ReceiveActor 20 | { 21 | private const int SyncMaxValue = int.MaxValue - 100; 22 | private static readonly MessagePackSerializer Serializer = 23 | SerializationContext.Default.GetSerializer(); 24 | public class StateChange { } 25 | public class Connecting : StateChange 26 | { 27 | public Connecting(string host, int port) 28 | { 29 | Host = host; 30 | Port = port; 31 | } 32 | 33 | public string Host { get; } 34 | public int Port { get; } 35 | } 36 | public class Connected : StateChange 37 | { 38 | public Connected(string host, int port, string salt, string version) 39 | { 40 | Port = port; 41 | Salt = salt; 42 | Version = version; 43 | Host = host; 44 | } 45 | 46 | public string Version { get; } 47 | public string Salt { get; } 48 | public string Host { get; } 49 | public int Port { get; } 50 | } 51 | public class Disconnected : StateChange 52 | { 53 | public Disconnected(string host, int port) 54 | { 55 | Port = port; 56 | Host = host; 57 | } 58 | 59 | public string Host { get; } 60 | public int Port { get; } 61 | } 62 | public class ConnectionFailed : StateChange 63 | { 64 | public ConnectionFailed(string host, int port) 65 | { 66 | Port = port; 67 | Host = host; 68 | } 69 | 70 | public string Host { get; } 71 | public int Port { get; } 72 | } 73 | private class CommandAck : Tcp.Event 74 | { 75 | public CommandAck(IActorRef sender, int sync) 76 | { 77 | Sender = sender; 78 | Sync = sync; 79 | } 80 | 81 | public IActorRef Sender { get; private set; } 82 | public int Sync { get; private set; } 83 | } 84 | private class Heartbeat 85 | { 86 | public Heartbeat(TimeSpan delay) 87 | { 88 | Delay = delay; 89 | } 90 | 91 | public TimeSpan Delay { get; private set; } 92 | } 93 | internal class Connect 94 | { 95 | } 96 | public class CurrentConnection 97 | { 98 | public CurrentConnection(IActorRef socket, int sync = 10) 99 | { 100 | Sync = sync; 101 | Socket = socket; 102 | } 103 | 104 | public int GetNextSync() 105 | { 106 | if (Sync > SyncMaxValue) Sync = 0; 107 | return Sync++; 108 | } 109 | 110 | public int Sync { get; private set; } 111 | public IActorRef Socket { get; private set; } 112 | } 113 | 114 | private readonly IActorRef _listener; 115 | private readonly string _host; 116 | private readonly int _port; 117 | private readonly TimeSpan _connectionTimeout; 118 | private readonly TimeSpan _heartbeatDelay; 119 | //private readonly Queue _requesterQueue; 120 | private readonly Dictionary _requesterDictionary; 121 | private GreatingResponse _greatingResponse; 122 | private CurrentConnection _currentConnection; 123 | private DateTime _lastDataReceived = DateTime.Now; 124 | private byte[] _responseBuffer; 125 | private ICancelable _heartbeatTimer; 126 | 127 | public Connection(IActorRef listener, string host, int port, TimeSpan connectionTimeout, TimeSpan? heartbeatDelay = null) 128 | { 129 | _listener = listener; 130 | _host = host; 131 | _port = port; 132 | _connectionTimeout = connectionTimeout; 133 | _heartbeatDelay = heartbeatDelay ?? TimeSpan.FromSeconds(2); 134 | _requesterDictionary = new Dictionary(); 135 | _responseBuffer = new byte[] { }; 136 | Become(EstablishConnect); 137 | } 138 | 139 | protected override void PreStart() 140 | { 141 | Self.Tell(new Connect()); 142 | base.PreStart(); 143 | } 144 | 145 | private void EstablishConnect() 146 | { 147 | Receive(_ => 148 | { 149 | IPAddress ip; 150 | if (!IPAddress.TryParse(_host, out ip)) 151 | ip = Dns.GetHostAddresses(_host).First(); 152 | 153 | var endPoint = new IPEndPoint(ip, _port); 154 | _listener.Tell(new Connecting(_host.ToString(), _port)); 155 | Context.System.Tcp().Tell(new Tcp.Connect(endPoint, timeout: _connectionTimeout)); 156 | }); 157 | 158 | Receive(c => 159 | { 160 | _currentConnection = new CurrentConnection(Sender); 161 | _currentConnection.Socket.Tell(new Tcp.Register(Self, useResumeWriting: false)); 162 | var greatingMessageTimer = Context.System.Scheduler.ScheduleTellOnceCancelable(_connectionTimeout, Self, 163 | ReceiveTimeout.Instance, Self); 164 | 165 | Become(() => WaitingGreating(greatingMessageTimer)); 166 | }); 167 | 168 | } 169 | 170 | 171 | private void WaitingGreating(ICancelable greatingMessageTimer) 172 | { 173 | Receive(data => 174 | { 175 | _lastDataReceived = DateTime.Now; 176 | greatingMessageTimer.Cancel(); 177 | _greatingResponse = GreatingResponse.Parse(data.Data.ToArray()); 178 | var scheduler = Context.System.Scheduler; 179 | var self = Self; 180 | Self.Ask(Request.Ping().Build(), _heartbeatDelay).ContinueWith(t => 181 | { 182 | StateChange state = new Connected(_host.ToString(), _port, _greatingResponse.Salt, _greatingResponse.Version); 183 | if (t.IsFaulted) 184 | state = new ConnectionFailed(_host.ToString(), _port); 185 | else 186 | { 187 | _heartbeatTimer = scheduler.ScheduleTellRepeatedlyCancelable(TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(1), self, new Heartbeat(_heartbeatDelay), self); 188 | } 189 | 190 | 191 | return state; 192 | }, TaskContinuationOptions.AttachedToParent & TaskContinuationOptions.ExecuteSynchronously).PipeTo(_listener); 193 | Become(WaitingAuth); 194 | }); 195 | 196 | Receive(t => 197 | { 198 | _currentConnection.Socket.Tell(Tcp.Close.Instance); 199 | }); 200 | 201 | ConnectionManagement(); 202 | 203 | } 204 | 205 | private void WaitingAuth() 206 | { 207 | Receive(data => 208 | { 209 | ReceiveData(data); 210 | Become(ConnectedState); 211 | }); 212 | 213 | ConnectionManagement(); 214 | } 215 | 216 | private void ReceiveData(Tcp.Received data) 217 | { 218 | _lastDataReceived = DateTime.Now; 219 | var responses = ParseResponse(data.Data.ToArray()); 220 | 221 | foreach (var response in responses) 222 | { 223 | if (!_requesterDictionary.ContainsKey(response.Sync)) 224 | return; 225 | 226 | 227 | var sender = _requesterDictionary[response.Sync]; 228 | 229 | if (sender != null) 230 | { 231 | if (response.IsError) 232 | sender.Tell(new Failure { Exception = new Exception(response.Error) }, Self); 233 | else if (!Equals(sender, Self)) 234 | sender.Tell(response); 235 | } 236 | _requesterDictionary.Remove(response.Sync); 237 | } 238 | } 239 | 240 | private void ConnectedState() 241 | { 242 | Receive(data => 243 | { 244 | ReceiveData(data); 245 | }); 246 | 247 | ConnectionManagement(); 248 | 249 | } 250 | 251 | private void ConnectionManagement() 252 | { 253 | Receive(_ => 254 | { 255 | _requesterDictionary.Clear(); 256 | _listener.Tell(new Disconnected(_host.ToString(), _port)); 257 | _heartbeatTimer.Cancel(); 258 | Become(EstablishConnect); 259 | }); 260 | 261 | Receive(p => p.Cmd is Tcp.Write, c => _currentConnection.Socket.Tell(c.Cmd)); 262 | Receive(p => p.Cmd is Tcp.Connect, 263 | c => _listener.Tell(new ConnectionFailed(_host.ToString(), _port))); 264 | 265 | Receive(s => 266 | { 267 | _requesterDictionary.Add(s.Sync, s.Sender); 268 | }); 269 | 270 | Receive(h => 271 | { 272 | var idle = DateTime.Now - _lastDataReceived; 273 | var result = Tuple.Create(idle > (h.Delay + h.Delay), idle > h.Delay); 274 | if (result.Item1 && result.Item2) 275 | _currentConnection.Socket.Tell(Tcp.Close.Instance); 276 | else if (!result.Item1 && result.Item2) 277 | Self.Tell(Request.Ping().Build()); 278 | }); 279 | 280 | ReceiveRequests(); 281 | } 282 | 283 | private void ReceiveRequests() 284 | { 285 | Receive(s => 286 | { 287 | _sender = Sender; 288 | SendRequest(s); 289 | }); 290 | } 291 | 292 | private IActorRef _sender = null; 293 | private void SendRequest(RequestBase s) 294 | { 295 | var sync = _currentConnection.GetNextSync(); 296 | var message = s.WithSync(sync).GetBytes(); 297 | _currentConnection.Socket.Tell(Tcp.Write.Create(ByteString.Create(message), new CommandAck(Sender, sync))); 298 | } 299 | 300 | private List ParseResponse(byte[] response) 301 | { 302 | var result = new List(); 303 | int totalLen = response.Length; 304 | 305 | if (_responseBuffer.Length > 0) 306 | { 307 | totalLen = totalLen + _responseBuffer.Length; 308 | var temp = new byte[totalLen]; 309 | Array.Copy(_responseBuffer, 0, temp, 0, _responseBuffer.Length); 310 | Array.Copy(response, 0, temp, _responseBuffer.Length, response.Length); 311 | response = temp; 312 | _responseBuffer = new byte[0]; 313 | } 314 | 315 | int position = 0; 316 | while (position < totalLen) 317 | { 318 | position++; 319 | if (totalLen - position < 4) 320 | { 321 | position = position - 1; 322 | _responseBuffer = new byte[totalLen - position]; 323 | Array.Copy(response, position, _responseBuffer, 0, totalLen - position); 324 | break; 325 | } 326 | 327 | var respLenArray = new byte[4]; 328 | Array.Copy(response, position, respLenArray, 0, 4); 329 | Array.Reverse(respLenArray); 330 | var respLen = BitConverter.ToInt32(respLenArray, 0); 331 | position = position + 4; 332 | 333 | if (totalLen - position < respLen) 334 | { 335 | position = position - 5; 336 | _responseBuffer = new byte[totalLen - position]; 337 | Array.Copy(response, position, _responseBuffer, 0, totalLen - position); 338 | break; 339 | } 340 | 341 | var resp = new byte[respLen]; 342 | Array.Copy(response, position, resp, 0, respLen); 343 | position = position + respLen; 344 | 345 | result.Add(Serializer.UnpackSingleObject(resp)); 346 | } 347 | 348 | return result; 349 | } 350 | 351 | } 352 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Builders/AuthRequestBuilder.cs: -------------------------------------------------------------------------------- 1 | using Tarantool.Net.IProto.Requests; 2 | 3 | namespace Tarantool.Net.IProto.Builders 4 | { 5 | public class AuthRequestBuilder : RequestBuilder 6 | { 7 | private readonly AuthRequest _authRequest; 8 | 9 | public AuthRequestBuilder(AuthRequest authRequest) : base(authRequest) 10 | { 11 | _authRequest = authRequest; 12 | } 13 | 14 | public override RequestBase Build() 15 | { 16 | WithHeader(Command.AUTH) 17 | .WithInstruction(Key.USER_NAME, _authRequest.Username) 18 | .WithTuple(_authRequest.GetAuthTuple()); 19 | return this; 20 | } 21 | 22 | public AuthRequestBuilder UserName(string userName) 23 | { 24 | _authRequest.Username = userName; 25 | return this; 26 | } 27 | 28 | public AuthRequestBuilder Password(string password) 29 | { 30 | _authRequest.Password = password; 31 | return this; 32 | } 33 | 34 | public AuthRequestBuilder Salt(string salt) 35 | { 36 | _authRequest.SetSalt(salt); 37 | return this; 38 | } 39 | 40 | public static implicit operator AuthRequest(AuthRequestBuilder authRequestBuilder) 41 | { 42 | return authRequestBuilder._authRequest; 43 | } 44 | } 45 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Builders/CallRequestBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using Tarantool.Net.IProto.Requests; 4 | 5 | namespace Tarantool.Net.IProto.Builders 6 | { 7 | public class CallRequestBuilder : RequestBuilder 8 | { 9 | private readonly CallRequest _callRequest; 10 | 11 | public CallRequestBuilder(CallRequest callRequest) : base(callRequest) 12 | { 13 | _callRequest = callRequest; 14 | } 15 | 16 | public CallRequestBuilder WithFunction(string name) 17 | { 18 | _callRequest.FunctionName = name; 19 | return this; 20 | } 21 | 22 | public CallRequestBuilder WithParams(params object[] parameters) 23 | { 24 | _callRequest.Params = parameters.ToList(); 25 | return this; 26 | } 27 | 28 | public override RequestBase Build() 29 | { 30 | WithHeader(Command.CALL) 31 | .WithInstruction(Key.FUNCTION, _callRequest.FunctionName) 32 | .WithParams(_callRequest.Params); 33 | 34 | return this; 35 | } 36 | 37 | public static implicit operator CallRequest(CallRequestBuilder callRequestBuilder) 38 | { 39 | return callRequestBuilder._callRequest; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Builders/DeleteRequestBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Tarantool.Net.IProto.Requests; 3 | 4 | namespace Tarantool.Net.IProto.Builders 5 | { 6 | public class DeleteRequestBuilder : RequestBuilder 7 | { 8 | private readonly DeleteRequest _deleteRequest; 9 | 10 | public DeleteRequestBuilder(DeleteRequest deleteRequest) : base(deleteRequest) 11 | { 12 | _deleteRequest = deleteRequest; 13 | } 14 | 15 | public DeleteRequestBuilder WithSpaceId(UInt32 spaceId) 16 | { 17 | _deleteRequest.SpaceId = spaceId; 18 | return this; 19 | } 20 | 21 | public DeleteRequestBuilder WithIndexId(UInt32 indexId) 22 | { 23 | _deleteRequest.IndexId = indexId; 24 | return this; 25 | } 26 | 27 | public DeleteRequestBuilder WithKey(Func tupleBuilder) 28 | { 29 | var tb = new TupleBuilder(_deleteRequest.Key); 30 | _deleteRequest.Key = tupleBuilder(tb); 31 | return this; 32 | } 33 | 34 | public override RequestBase Build() 35 | { 36 | WithHeader(Command.DELETE) 37 | .WithInstruction(Key.SPACE, _deleteRequest.SpaceId) 38 | .WithInstruction(Key.INDEX, _deleteRequest.IndexId) 39 | .WithInstruction(Key.KEY, _deleteRequest.Key); 40 | 41 | return this; 42 | } 43 | 44 | public static implicit operator DeleteRequest(DeleteRequestBuilder deleteRequestBuilder) 45 | { 46 | return deleteRequestBuilder._deleteRequest; 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Builders/EvalRequestBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Tarantool.Net.IProto.Requests; 3 | 4 | namespace Tarantool.Net.IProto.Builders 5 | { 6 | public class EvalRequestBuilder : RequestBuilder 7 | { 8 | private readonly EvalRequest _evalRequest; 9 | 10 | public EvalRequestBuilder(EvalRequest evalRequest) : base(evalRequest) 11 | { 12 | _evalRequest = evalRequest; 13 | } 14 | 15 | public EvalRequestBuilder WithExpression(string expression) 16 | { 17 | _evalRequest.Expression = expression; 18 | return this; 19 | } 20 | 21 | public EvalRequestBuilder WithTuple(Func evalTupleBuilder) 22 | { 23 | var etb = new TupleBuilder(_evalRequest.Tuple); 24 | _evalRequest.Tuple = evalTupleBuilder(etb); 25 | return this; 26 | } 27 | 28 | public override RequestBase Build() 29 | { 30 | WithHeader(Command.EVAL) 31 | .WithInstruction(Key.EXPRESSION, _evalRequest.Expression) 32 | .WithTuple(_evalRequest.Tuple); 33 | 34 | return this; 35 | } 36 | 37 | public static implicit operator EvalRequest(EvalRequestBuilder evalRequestBuilder) 38 | { 39 | return evalRequestBuilder._evalRequest; 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Builders/InsertRequestBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Tarantool.Net.IProto.Requests; 3 | 4 | namespace Tarantool.Net.IProto.Builders 5 | { 6 | public class InsertRequestBuilder : RequestBuilder 7 | { 8 | private readonly InsertReplaceRequest _insertReplaceRequest; 9 | 10 | public InsertRequestBuilder(InsertReplaceRequest insertReplaceRequest) : base(insertReplaceRequest) 11 | { 12 | _insertReplaceRequest = insertReplaceRequest; 13 | } 14 | 15 | /// 16 | /// Set Space Id 17 | /// 18 | /// Space Id 19 | /// 20 | public InsertRequestBuilder WithSpaceId(UInt32 spaceId) 21 | { 22 | _insertReplaceRequest.SpaceId = spaceId; 23 | return this; 24 | } 25 | 26 | public InsertRequestBuilder WithTuple(Func insertTupleBuilder) 27 | { 28 | var tb = new TupleBuilder(_insertReplaceRequest.Tuple); 29 | _insertReplaceRequest.Tuple = insertTupleBuilder(tb); 30 | return this; 31 | } 32 | 33 | public InsertRequestBuilder WithTuple(object[] tuple) 34 | { 35 | _insertReplaceRequest.Tuple = new Tuple(tuple); 36 | return this; 37 | } 38 | 39 | public override RequestBase Build() 40 | { 41 | WithHeader(Command.INSERT) 42 | .WithInstruction(Key.SPACE, _insertReplaceRequest.SpaceId) 43 | .WithTuple(_insertReplaceRequest.Tuple); 44 | 45 | return this; 46 | } 47 | 48 | public static implicit operator InsertReplaceRequest(InsertRequestBuilder insertRequestBuilder) 49 | { 50 | return insertRequestBuilder._insertReplaceRequest; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Builders/OperationsTupleBuilder.cs: -------------------------------------------------------------------------------- 1 | namespace Tarantool.Net.IProto.Builders 2 | { 3 | public class OperationsTupleBuilder 4 | { 5 | protected readonly OperationsTuple _tuple; 6 | public OperationsTupleBuilder(OperationsTuple tuple) 7 | { 8 | _tuple = tuple; 9 | } 10 | 11 | public OperationsTupleBuilder Addition(int fieldNumber, int argument) 12 | { 13 | return AddOperation(UpdateOperationCode.Addition, fieldNumber, argument); 14 | } 15 | 16 | public OperationsTupleBuilder Subtraction(int fieldNumber, int argument) 17 | { 18 | return AddOperation(UpdateOperationCode.Subtraction, fieldNumber, argument); 19 | } 20 | 21 | public OperationsTupleBuilder Delete(int fieldNumber, T argument) 22 | { 23 | return AddOperation(UpdateOperationCode.Delete, fieldNumber, argument); 24 | } 25 | 26 | public OperationsTupleBuilder Insert(int fieldNumber, T argument) 27 | { 28 | return AddOperation(UpdateOperationCode.Insert, fieldNumber, argument); 29 | } 30 | 31 | public OperationsTupleBuilder Assign(int fieldNumber, T argument) 32 | { 33 | return AddOperation(UpdateOperationCode.Assign, fieldNumber, argument); 34 | } 35 | 36 | protected OperationsTupleBuilder AddOperation(string operationType, int fieldNumber, T argument) 37 | { 38 | _tuple.AddField(new UpdateOperation 39 | { 40 | Code = operationType, 41 | FieldNo = (uint)fieldNumber, 42 | Arg = argument 43 | }); 44 | 45 | return this; 46 | } 47 | 48 | public static implicit operator OperationsTuple(OperationsTupleBuilder tupleBuilder) 49 | { 50 | return tupleBuilder._tuple; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Builders/PingRequestBuilder.cs: -------------------------------------------------------------------------------- 1 | using Tarantool.Net.IProto.Requests; 2 | 3 | namespace Tarantool.Net.IProto.Builders 4 | { 5 | public class PingRequestBuilder : RequestBuilder 6 | { 7 | private readonly PingRequest _pingRequest; 8 | 9 | public PingRequestBuilder(PingRequest pingRequest) : base(pingRequest) 10 | { 11 | _pingRequest = pingRequest; 12 | } 13 | 14 | public override RequestBase Build() 15 | { 16 | WithHeader(Command.PING); 17 | return this; 18 | } 19 | 20 | public static implicit operator PingRequest(PingRequestBuilder pingRequestBuilder) 21 | { 22 | return pingRequestBuilder._pingRequest; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Builders/ReplaceRequestBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Tarantool.Net.IProto.Requests; 3 | 4 | namespace Tarantool.Net.IProto.Builders 5 | { 6 | public class ReplaceRequestBuilder : RequestBuilder 7 | { 8 | private readonly InsertReplaceRequest _insertReplaceRequest; 9 | 10 | public ReplaceRequestBuilder(InsertReplaceRequest insertReplaceRequest) : base(insertReplaceRequest) 11 | { 12 | _insertReplaceRequest = insertReplaceRequest; 13 | } 14 | 15 | /// 16 | /// Set Space Id 17 | /// 18 | /// Space Id 19 | /// 20 | public ReplaceRequestBuilder WithSpaceId(UInt32 spaceId) 21 | { 22 | _insertReplaceRequest.SpaceId = spaceId; 23 | return this; 24 | } 25 | 26 | public ReplaceRequestBuilder WithTuple(Func insertTupleBuilder) 27 | { 28 | var tb = new TupleBuilder(_insertReplaceRequest.Tuple); 29 | _insertReplaceRequest.Tuple = insertTupleBuilder(tb); 30 | return this; 31 | } 32 | 33 | public override RequestBase Build() 34 | { 35 | WithHeader(Command.REPLACE) 36 | .WithInstruction(Key.SPACE, _insertReplaceRequest.SpaceId) 37 | .WithTuple(_insertReplaceRequest.Tuple); 38 | 39 | return this; 40 | } 41 | 42 | public static implicit operator InsertReplaceRequest(ReplaceRequestBuilder replaceRequestBuilder) 43 | { 44 | return replaceRequestBuilder._insertReplaceRequest; 45 | } 46 | } 47 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Builders/SelectRequestBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Tarantool.Net.IProto.Requests; 3 | 4 | namespace Tarantool.Net.IProto.Builders 5 | { 6 | public class SelectRequestBuilder : RequestBuilder 7 | { 8 | private readonly SelectRequest _selectRequest; 9 | 10 | public SelectRequestBuilder(SelectRequest selectRequest) : base(selectRequest) 11 | { 12 | _selectRequest = selectRequest; 13 | } 14 | 15 | public override RequestBase Build() 16 | { 17 | WithHeader(Command.SELECT) 18 | .WithInstruction(Key.SPACE, _selectRequest.SpaceId) 19 | .WithInstruction(Key.INDEX, _selectRequest.IndexId) 20 | .WithInstruction(Key.LIMIT, _selectRequest.Limit) 21 | .WithInstruction(Key.OFFSET, _selectRequest.Offset) 22 | .WithInstruction(Key.ITERATOR, (int) _selectRequest.Iterator) 23 | .WithInstruction(Key.KEY, _selectRequest.Key); 24 | 25 | return this; 26 | } 27 | 28 | public SelectRequestBuilder WithSpaceId(UInt32 spaceId) 29 | { 30 | _selectRequest.SpaceId = spaceId; 31 | return this; 32 | } 33 | 34 | public SelectRequestBuilder WithIndexId(UInt32 indexId) 35 | { 36 | _selectRequest.IndexId = indexId; 37 | return this; 38 | } 39 | 40 | public SelectRequestBuilder WithOffset(UInt32 offset) 41 | { 42 | _selectRequest.Offset = offset; 43 | return this; 44 | } 45 | 46 | public SelectRequestBuilder WithLimit(UInt32 limit) 47 | { 48 | _selectRequest.Limit = limit; 49 | return this; 50 | } 51 | public SelectRequestBuilder WithIterator(Iterator iterator) 52 | { 53 | _selectRequest.Iterator = iterator; 54 | return this; 55 | } 56 | public SelectRequestBuilder WithKey(Func tupleBuilder) 57 | { 58 | var tb = new TupleBuilder(_selectRequest.Key); 59 | _selectRequest.Key = tupleBuilder(tb); 60 | return this; 61 | } 62 | 63 | public static implicit operator SelectRequest(SelectRequestBuilder selectRequestBuilder) 64 | { 65 | return selectRequestBuilder._selectRequest; 66 | } 67 | } 68 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Builders/TupleBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Tarantool.Net.IProto.Builders 4 | { 5 | public class TupleBuilder 6 | { 7 | private readonly Tuple _tuple; 8 | 9 | public TupleBuilder(Tuple tuple) 10 | { 11 | _tuple = tuple; 12 | } 13 | 14 | public TupleBuilder AddField(object data) 15 | { 16 | _tuple.AddField(data); 17 | return this; 18 | } 19 | 20 | 21 | public static implicit operator Tuple(TupleBuilder tupleBuilder) 22 | { 23 | return tupleBuilder._tuple; 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Builders/UpdateOperationsTupleBuilder.cs: -------------------------------------------------------------------------------- 1 | using Tarantool.Net.IProto.Requests; 2 | 3 | namespace Tarantool.Net.IProto.Builders 4 | { 5 | public class UpdateOperationsTupleBuilder : OperationsTupleBuilder 6 | { 7 | 8 | public UpdateOperationsTupleBuilder(OperationsTuple tuple) : base(tuple) 9 | { 10 | } 11 | 12 | /// 13 | /// Addition OP='+' .space[][] += 14 | /// 15 | /// Field Number 16 | /// Argument 17 | /// 18 | public new UpdateOperationsTupleBuilder Addition(int fieldNumber, int argument) 19 | { 20 | return (UpdateOperationsTupleBuilder)base.Addition(fieldNumber, argument); 21 | } 22 | 23 | /// 24 | /// Subtraction OP='-' .space[][] -= 25 | /// 26 | /// Field Number 27 | /// Argument 28 | /// 29 | public UpdateOperationsTupleBuilder Subtraction(int fieldNumber, int argument) 30 | { 31 | return (UpdateOperationsTupleBuilder)base.Subtraction(fieldNumber, argument); 32 | } 33 | 34 | /// 35 | /// Bitwise AND OP='&' .space[][] &= 36 | /// 37 | /// Field Number 38 | /// Argument 39 | /// 40 | public UpdateOperationsTupleBuilder BitwiseAnd(int fieldNumber, int argument) 41 | { 42 | return AddOperation(UpdateOperationCode.BitwiseAnd, fieldNumber, argument); 43 | } 44 | 45 | // ReSharper disable once InconsistentNaming 46 | public UpdateOperationsTupleBuilder BitwiseXOR(int fieldNumber, int argument) 47 | { 48 | return AddOperation(UpdateOperationCode.BitwiseXOR, fieldNumber, argument); 49 | } 50 | 51 | public UpdateOperationsTupleBuilder BitwiseOr(int fieldNumber, int argument) 52 | { 53 | return AddOperation(UpdateOperationCode.BitwiseOr, fieldNumber, argument); 54 | } 55 | 56 | /// 57 | /// Delete fields starting from in the space[] 58 | /// 59 | /// 60 | /// 61 | /// 62 | public new UpdateOperationsTupleBuilder Delete(int fieldNumber, T argument) 63 | { 64 | return (UpdateOperationsTupleBuilder)base.Delete(fieldNumber, argument); 65 | } 66 | 67 | public new UpdateOperationsTupleBuilder Insert(int fieldNumber, T argument) 68 | { 69 | return (UpdateOperationsTupleBuilder)base.Insert(fieldNumber, argument); 70 | } 71 | 72 | public new UpdateOperationsTupleBuilder Assign(int fieldNumber, T argument) 73 | { 74 | return (UpdateOperationsTupleBuilder)base.Assign(fieldNumber, argument); 75 | } 76 | 77 | private new UpdateOperationsTupleBuilder AddOperation(string operationType, int fieldNumber, T argument) 78 | { 79 | return (UpdateOperationsTupleBuilder)base.AddOperation(operationType, fieldNumber, argument); 80 | } 81 | 82 | /// 83 | /// Splice OP=':' take the string from space[][] and substitute bytes from with 84 | /// 85 | /// Field Number 86 | /// Offset 87 | /// Argument 88 | /// Possition 89 | /// 90 | public UpdateOperationsTupleBuilder Splice(int fieldNumber, int possition, int offset, string argument) 91 | { 92 | _tuple.AddField(new SpliceUpdateOperation 93 | { 94 | Offset = (uint)offset, 95 | Position = (uint)possition, 96 | FieldNo = (uint)fieldNumber, 97 | Arg = argument 98 | }); 99 | return this; 100 | } 101 | 102 | public static implicit operator OperationsTuple(UpdateOperationsTupleBuilder tupleBuilder) 103 | { 104 | return tupleBuilder._tuple; 105 | } 106 | } 107 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Builders/UpdateRequestBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Tarantool.Net.IProto.Requests; 3 | 4 | namespace Tarantool.Net.IProto.Builders 5 | { 6 | public class UpdateRequestBuilder : RequestBuilder 7 | { 8 | private readonly UpdateRequest _updateRequest; 9 | 10 | public UpdateRequestBuilder(UpdateRequest updateRequest) : base(updateRequest) 11 | { 12 | _updateRequest = updateRequest; 13 | } 14 | 15 | /// 16 | /// Set Space Id 17 | /// 18 | /// Space Id 19 | /// 20 | public UpdateRequestBuilder WithSpaceId(UInt32 spaceId) 21 | { 22 | _updateRequest.SpaceId = spaceId; 23 | return this; 24 | } 25 | 26 | /// 27 | /// Set Index Id 28 | /// 29 | /// Index Id 30 | /// 31 | public UpdateRequestBuilder WithIndexId(UInt32 indexId) 32 | { 33 | _updateRequest.IndexId = indexId; 34 | return this; 35 | } 36 | 37 | /// 38 | /// Set Key Tuple 39 | /// 40 | /// Key tuple 41 | /// 42 | public UpdateRequestBuilder WithKeys(object[] keys) 43 | { 44 | _updateRequest.Key = new Tuple(keys); 45 | return this; 46 | } 47 | 48 | /// 49 | /// Set Key Tuple 50 | /// 51 | /// Key Builder 52 | /// 53 | public UpdateRequestBuilder WithKeys(Func keyTupleBuilder) 54 | { 55 | var ktb = new TupleBuilder(_updateRequest.Key); 56 | _updateRequest.Key = keyTupleBuilder(ktb); 57 | return this; 58 | } 59 | 60 | /// 61 | /// Set Key Tuple 62 | /// 63 | /// Key tuple 64 | /// 65 | public UpdateRequestBuilder WithKey(object key) 66 | { 67 | return WithKeys(t => t.AddField(key)); 68 | } 69 | 70 | /// 71 | /// Set Update Operations 72 | /// 73 | /// Create Operation Tuple Action 74 | /// 75 | public UpdateRequestBuilder WithOperation(Func operationTupleBuilder) 76 | { 77 | var uotp = new UpdateOperationsTupleBuilder(_updateRequest.UpdateOperations); 78 | _updateRequest.UpdateOperations = operationTupleBuilder(uotp); 79 | return this; 80 | } 81 | 82 | public override RequestBase Build() 83 | { 84 | WithHeader(Command.UPDATE) 85 | .WithInstruction(Key.SPACE, _updateRequest.SpaceId) 86 | .WithInstruction(Key.INDEX, _updateRequest.IndexId) 87 | .WithInstruction(Key.KEY, _updateRequest.Key) 88 | .WithTuple(_updateRequest.UpdateOperations); 89 | 90 | return this; 91 | } 92 | 93 | public static implicit operator UpdateRequest(UpdateRequestBuilder updateRequestBuilder) 94 | { 95 | return updateRequestBuilder._updateRequest; 96 | } 97 | } 98 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Builders/UpsertRequestBuilder.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Tarantool.Net.IProto.Requests; 3 | 4 | namespace Tarantool.Net.IProto.Builders 5 | { 6 | public class UpsertRequestBuilder : RequestBuilder 7 | { 8 | private readonly UpsertRequest _upsertRequest; 9 | 10 | public UpsertRequestBuilder(UpsertRequest upsertRequest) : base(upsertRequest) 11 | { 12 | _upsertRequest = upsertRequest; 13 | } 14 | 15 | /// 16 | /// Set Space Id 17 | /// 18 | /// Space Id 19 | /// 20 | public UpsertRequestBuilder WithSpaceId(UInt32 spaceId) 21 | { 22 | _upsertRequest.SpaceId = spaceId; 23 | return this; 24 | } 25 | 26 | /// 27 | /// Set Tuple 28 | /// 29 | /// Tuple 30 | /// 31 | public UpsertRequestBuilder WithTuple(object[] tuple) 32 | { 33 | _upsertRequest.Tuple = new Tuple(tuple); 34 | return this; 35 | } 36 | 37 | /// 38 | /// Set Tuple 39 | /// 40 | /// Key Builder 41 | /// 42 | public UpsertRequestBuilder WithTuple(Func tupleBuilder) 43 | { 44 | var tb = new TupleBuilder(_upsertRequest.Tuple); 45 | _upsertRequest.Tuple = tupleBuilder(tb); 46 | return this; 47 | } 48 | 49 | /// 50 | /// Set Tuple 51 | /// 52 | /// One element tuple 53 | /// 54 | public UpsertRequestBuilder WithTuple(object field) 55 | { 56 | return WithTuple(t => t.AddField(field)); 57 | } 58 | 59 | public UpsertRequestBuilder WithOperation(Func operationTupleBuilder) 60 | { 61 | var uotp = new OperationsTupleBuilder(_upsertRequest.UpsertOperations); 62 | _upsertRequest.UpsertOperations = operationTupleBuilder(uotp); 63 | return this; 64 | } 65 | 66 | public override RequestBase Build() 67 | { 68 | WithHeader(Command.UPSERT) 69 | .WithInstruction(Key.SPACE, _upsertRequest.SpaceId) 70 | .WithTuple(_upsertRequest.Tuple) 71 | .WithInstruction(Key.UPSERT_OPS, _upsertRequest.UpsertOperations); 72 | 73 | return this; 74 | } 75 | 76 | public static implicit operator UpsertRequest(UpsertRequestBuilder upsertRequestBuilder) 77 | { 78 | return upsertRequestBuilder._upsertRequest; 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Command.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable InconsistentNaming 2 | namespace Tarantool.Net.IProto 3 | { 4 | public enum Command 5 | { 6 | SELECT = 0x01, 7 | INSERT = 0x02, 8 | REPLACE = 0x03, 9 | UPDATE = 0x04, 10 | DELETE = 0x05, 11 | CALL = 0x06, 12 | AUTH = 0x07, 13 | EVAL = 0x08, 14 | UPSERT = 0x09, 15 | // Admin command codes 16 | PING = 0x40 17 | } 18 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/GreatingResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Text; 3 | 4 | namespace Tarantool.Net.IProto 5 | { 6 | public class GreatingResponse 7 | { 8 | public GreatingResponse(string version, string salt) 9 | { 10 | Version = version; 11 | Salt = salt; 12 | } 13 | 14 | public string Version { get; private set; } 15 | public string Salt { get; private set; } 16 | 17 | public static GreatingResponse Parse(byte[] value) 18 | { 19 | byte[] ver = new byte[63]; 20 | Array.Copy(value, 0, ver, 0, 63); 21 | 22 | byte[] salt = new byte[44]; 23 | Array.Copy(value, 64, salt, 0, 44); 24 | 25 | return new GreatingResponse(Encoding.ASCII.GetString(ver), Encoding.ASCII.GetString(salt)); 26 | } 27 | 28 | } 29 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Iterator.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable InconsistentNaming 2 | namespace Tarantool.Net.IProto 3 | { 4 | public enum Iterator 5 | { 6 | EQ = 0, 7 | REQ = 1, 8 | ALL = 2, 9 | LT = 3, 10 | LE = 4, 11 | GE = 5, 12 | GT = 6, 13 | BITSET_ALL_SET = 7, 14 | BITSET_ANY_SET = 8, 15 | BITSET_ALL_NOT_SET = 9 16 | } 17 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Key.cs: -------------------------------------------------------------------------------- 1 | // ReSharper disable InconsistentNaming 2 | namespace Tarantool.Net.IProto 3 | { 4 | public enum Key 5 | { 6 | CODE = 0x00, 7 | SYNC = 0x01, 8 | 9 | SCHEMA_ID = 0x05, 10 | 11 | SPACE = 0x10, 12 | INDEX = 0x11, 13 | LIMIT = 0x12, 14 | OFFSET = 0x13, 15 | ITERATOR = 0x14, 16 | 17 | KEY = 0x20, 18 | TUPLE = 0x21, 19 | FUNCTION = 0x22, 20 | USER_NAME = 0x23, 21 | EXPRESSION = 0x27, 22 | UPSERT_OPS = 0x28, 23 | DATA = 0x30, 24 | ERROR = 0x31 25 | } 26 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/OperationsTuple.cs: -------------------------------------------------------------------------------- 1 | namespace Tarantool.Net.IProto 2 | { 3 | public class OperationsTuple : Tuple 4 | { 5 | 6 | } 7 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/PacketHeader.cs: -------------------------------------------------------------------------------- 1 | namespace Tarantool.Net.IProto 2 | { 3 | public class PacketHeader 4 | { 5 | public PacketHeader(Command command, int sync, int schemaId = 0) 6 | { 7 | Command = command; 8 | SchemaId = schemaId; 9 | Sync = sync; 10 | } 11 | 12 | public Command Command { get; private set; } 13 | 14 | public int SchemaId { get; private set; } 15 | public int Sync { get; private set; } 16 | 17 | public byte[] Raw 18 | { 19 | get 20 | { 21 | var temp = new byte[] 22 | { 23 | 0x82, (byte)Key.CODE, (byte)Command, (byte)Key.SYNC, 0xce, (byte)(Sync >> 24), (byte)(Sync >> 16), 24 | (byte)(Sync >> 8), (byte)Sync 25 | }; 26 | 27 | return temp; 28 | } 29 | } 30 | } 31 | } 32 | 33 | -------------------------------------------------------------------------------- /Tarantool.Net/IProto/PacketType.cs: -------------------------------------------------------------------------------- 1 | namespace Tarantool.Net.IProto 2 | { 3 | public enum PacketType 4 | { 5 | Insert = 13, 6 | Select = 17, 7 | Update = 19, 8 | Delete = 21, 9 | Call = 22, 10 | Ping = 65280 11 | } 12 | } 13 | 14 | -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Request.cs: -------------------------------------------------------------------------------- 1 | using Tarantool.Net.IProto.Builders; 2 | using Tarantool.Net.IProto.Requests; 3 | 4 | namespace Tarantool.Net.IProto 5 | { 6 | public class Request 7 | { 8 | public static AuthRequestBuilder Auth() 9 | { 10 | return new AuthRequestBuilder(new AuthRequest()); 11 | } 12 | 13 | public static PingRequestBuilder Ping() 14 | { 15 | return new PingRequestBuilder(new PingRequest()); 16 | } 17 | 18 | public static SelectRequestBuilder Select() 19 | { 20 | return new SelectRequestBuilder(new SelectRequest()); 21 | } 22 | 23 | public static UpdateRequestBuilder Update() 24 | { 25 | return new UpdateRequestBuilder(new UpdateRequest()); 26 | } 27 | 28 | public static InsertRequestBuilder Insert() 29 | { 30 | return new InsertRequestBuilder(new InsertReplaceRequest()); 31 | } 32 | 33 | public static DeleteRequestBuilder Delete() 34 | { 35 | return new DeleteRequestBuilder(new DeleteRequest()); 36 | } 37 | 38 | public static CallRequestBuilder Call() 39 | { 40 | return new CallRequestBuilder(new CallRequest()); 41 | } 42 | 43 | public static EvalRequestBuilder Eval() 44 | { 45 | return new EvalRequestBuilder(new EvalRequest()); 46 | } 47 | 48 | public static UpsertRequestBuilder Upsert() 49 | { 50 | return new UpsertRequestBuilder(new UpsertRequest()); 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /Tarantool.Net/IProto/RequestBody.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using MsgPack; 4 | using MsgPack.Serialization; 5 | 6 | namespace Tarantool.Net.IProto 7 | { 8 | public class RequestBody : IPackable 9 | { 10 | private readonly Dictionary _bodyParts = new Dictionary(); 11 | 12 | [MessagePackMember(0)] 13 | public Dictionary Parts => _bodyParts; 14 | 15 | public void AddBodyData(Key key, T value) 16 | { 17 | _bodyParts[(UInt32)key] = value; 18 | } 19 | 20 | public void PackToMessage(Packer packer, PackingOptions options) 21 | { 22 | packer.PackMapHeader(_bodyParts.Count); 23 | foreach (var part in _bodyParts) 24 | { 25 | packer.Pack(part.Key); 26 | packer.Pack(part.Value); 27 | } 28 | } 29 | } 30 | } 31 | 32 | -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Requests/AuthRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Cryptography; 3 | using System.Text; 4 | 5 | namespace Tarantool.Net.IProto.Requests 6 | { 7 | public class AuthRequest : RequestBase 8 | { 9 | public AuthRequest() 10 | { 11 | Username = "guest"; 12 | Password = string.Empty; 13 | } 14 | 15 | public string Username { get; set; } 16 | public string Password { get; set; } 17 | 18 | private string _salt; 19 | 20 | public void SetSalt(string salt) 21 | { 22 | _salt = salt; 23 | } 24 | public Tuple GetAuthTuple() 25 | { 26 | var tuple = new Tuple(); 27 | if (string.IsNullOrWhiteSpace(Password)) 28 | return tuple; 29 | 30 | var salt = Convert.FromBase64String(_salt); 31 | var sha = new SHA1Managed(); 32 | var step1 = sha.ComputeHash(Encoding.UTF8.GetBytes(Password)); 33 | var step2 = sha.ComputeHash(step1); 34 | var scrambleSize = 20; 35 | 36 | var saltedHash = new byte[step2.Length + salt.Length]; 37 | salt.CopyTo(saltedHash, 0); 38 | step2.CopyTo(saltedHash, salt.Length); 39 | sha.Clear(); 40 | sha = new SHA1Managed(); 41 | 42 | sha.TransformBlock(salt, 0, scrambleSize, saltedHash, 0); 43 | sha.TransformFinalBlock(step2, 0, step2.Length); 44 | 45 | var step3 = sha.Hash; 46 | sha.Clear(); 47 | 48 | var xor = XOR(step1, step3); 49 | tuple.AddField("chap-sha1"); 50 | tuple.AddField(xor); 51 | return tuple; 52 | } 53 | 54 | private byte[] XOR(byte[] buffer1, byte[] buffer2) 55 | { 56 | byte[] result = new byte[20]; 57 | for (int i = 0; i < buffer1.Length; i++) 58 | result[i] = (byte)(buffer1[i] ^ buffer2[i]); 59 | return result; 60 | } 61 | } 62 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Requests/CallRequest.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace Tarantool.Net.IProto.Requests 4 | { 5 | public class CallRequest : RequestBase 6 | { 7 | public CallRequest() 8 | { 9 | Params = new List(); 10 | FunctionName = ""; 11 | } 12 | 13 | public string FunctionName { get; set; } 14 | 15 | public List Params { get; set; } 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Requests/DeleteRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Tarantool.Net.IProto.Requests 4 | { 5 | public class DeleteRequest : RequestBase 6 | { 7 | public DeleteRequest() 8 | { 9 | SpaceId = 0; 10 | IndexId = 0; 11 | Key = new Tuple(); 12 | } 13 | 14 | public UInt32 SpaceId { get; set; } 15 | public UInt32 IndexId { get; set; } 16 | public Tuple Key { get; set; } 17 | } 18 | } 19 | 20 | -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Requests/EvalRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Tarantool.Net.IProto.Requests 2 | { 3 | public class EvalRequest : RequestBase 4 | { 5 | public EvalRequest() 6 | { 7 | Expression = string.Empty; 8 | Tuple = new Tuple(); 9 | } 10 | 11 | public string Expression { get; set; } 12 | public Tuple Tuple { get; set; } 13 | } 14 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Requests/InsertReplaceRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Tarantool.Net.IProto.Requests 4 | { 5 | public class InsertReplaceRequest : RequestBase 6 | { 7 | public InsertReplaceRequest() 8 | { 9 | SpaceId = 0; 10 | Tuple = new Tuple(); 11 | } 12 | 13 | public UInt32 SpaceId { get; set; } 14 | public Tuple Tuple { get; set; } 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Requests/PingRequest.cs: -------------------------------------------------------------------------------- 1 | namespace Tarantool.Net.IProto.Requests 2 | { 3 | public class PingRequest : RequestBase 4 | { 5 | } 6 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Requests/RequestBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using MsgPack; 4 | using MsgPack.Serialization; 5 | 6 | namespace Tarantool.Net.IProto.Requests 7 | { 8 | public abstract class RequestBase 9 | { 10 | private static readonly MessagePackSerializer Serializer = SerializationContext.Default.GetSerializer(); 11 | internal PacketHeader Header; 12 | internal readonly RequestBody Body = new RequestBody(); 13 | 14 | public RequestBase WithSync(int requestId) 15 | { 16 | Header = new PacketHeader(Header.Command, requestId, Header.SchemaId); 17 | return this; 18 | } 19 | 20 | public byte[] GetBytes() 21 | { 22 | SerializationContext.Default.CompatibilityOptions.PackerCompatibilityOptions = 23 | PackerCompatibilityOptions.PackBinaryAsRaw; 24 | 25 | var header = Header.Raw; 26 | var body = Serializer.PackSingleObject(Body); 27 | 28 | var totalLen = body.Length + header.Length; 29 | var resArray = new byte[totalLen + 5]; 30 | var prefix = new byte[] { 0xCE }; 31 | prefix.CopyTo(resArray, 0); 32 | 33 | resArray[1] = (byte)(totalLen >> 24); 34 | resArray[2] = (byte)(totalLen >> 16); 35 | resArray[3] = (byte)(totalLen >> 8); 36 | resArray[4] = (byte)totalLen; 37 | header.CopyTo(resArray, 5); 38 | var offcet = 5 + header.Length; 39 | Array.Copy(body, 0, resArray, offcet, body.Length); 40 | 41 | return resArray; 42 | } 43 | 44 | } 45 | 46 | public abstract class RequestBuilder 47 | { 48 | private readonly RequestBase _replaceRequest; 49 | 50 | protected RequestBuilder(RequestBase replaceRequest) 51 | { 52 | _replaceRequest = replaceRequest; 53 | } 54 | 55 | protected internal RequestBuilder WithHeader(Command commmand, int schemaId = 0) 56 | { 57 | _replaceRequest.Header = new PacketHeader(commmand, 0, schemaId); 58 | return this; 59 | } 60 | 61 | protected internal RequestBuilder WithInstruction(Key key, T value) 62 | { 63 | _replaceRequest.Body.AddBodyData(key, value); 64 | return this; 65 | } 66 | 67 | protected internal RequestBuilder WithTuple(Tuple tuple) 68 | { 69 | _replaceRequest.Body.AddBodyData(Key.TUPLE, tuple); 70 | return this; 71 | } 72 | 73 | protected internal RequestBuilder WithParams(List parameters) 74 | { 75 | _replaceRequest.Body.AddBodyData(Key.TUPLE, parameters); 76 | return this; 77 | } 78 | 79 | public abstract RequestBase Build(); 80 | 81 | } 82 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Requests/SelectRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Tarantool.Net.IProto.Requests 4 | { 5 | public class SelectRequest : RequestBase 6 | { 7 | public SelectRequest() 8 | { 9 | SpaceId = 0; 10 | IndexId = 0; 11 | Offset = 0; 12 | Limit = int.MaxValue; 13 | Iterator = Iterator.EQ; 14 | Key = new Tuple(); 15 | } 16 | 17 | public UInt32 SpaceId { get; set; } 18 | 19 | public UInt32 IndexId { get; set; } 20 | 21 | public UInt32 Offset { get; set; } 22 | 23 | public UInt32 Limit { get; set; } 24 | public Iterator Iterator { get; set; } 25 | public Tuple Key { get; set; } 26 | } 27 | 28 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Requests/UpdateRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Tarantool.Net.IProto.Requests 4 | { 5 | public class UpdateRequest : RequestBase 6 | { 7 | public UpdateRequest() 8 | { 9 | SpaceId = 0; 10 | IndexId = 0; 11 | Key = new Tuple(); 12 | UpdateOperations = new OperationsTuple(); 13 | } 14 | 15 | public UInt32 SpaceId { get; set; } 16 | public UInt32 IndexId { get; set; } 17 | 18 | /// 19 | /// Key to be updated 20 | /// 21 | public Tuple Key { get; set; } 22 | public OperationsTuple UpdateOperations { get; set; } 23 | } 24 | } 25 | 26 | -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Requests/UpsertRequest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace Tarantool.Net.IProto.Requests 4 | { 5 | public class UpsertRequest : RequestBase 6 | { 7 | public UpsertRequest() 8 | { 9 | SpaceId = 0; 10 | Tuple = new Tuple(); 11 | UpsertOperations = new OperationsTuple(); 12 | } 13 | 14 | public UInt32 SpaceId { get; set; } 15 | public Tuple Tuple { get; set; } 16 | public OperationsTuple UpsertOperations { get; set; } 17 | } 18 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Response.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using MsgPack; 5 | 6 | namespace Tarantool.Net.IProto 7 | { 8 | public class Response : IUnpackable 9 | { 10 | public int Code { get; set; } 11 | public int Sync { get; set; } 12 | public int SchemaId { get; set; } 13 | public bool IsError { get; set; } 14 | public string Error { get; set; } 15 | public List Body { get; set; } 16 | 17 | public void UnpackFromMessage(Unpacker unpacker) 18 | { 19 | int codeResult; 20 | MessagePackObject obj; 21 | unpacker.ReadInt32(out codeResult); 22 | unpacker.ReadObject(out obj); 23 | ParseIProtoResponse(codeResult, obj); 24 | 25 | unpacker.ReadInt32(out codeResult); 26 | unpacker.ReadObject(out obj); 27 | ParseIProtoResponse(codeResult, obj); 28 | 29 | unpacker.ReadInt32(out codeResult); 30 | unpacker.ReadObject(out obj); 31 | ParseIProtoResponse(codeResult, obj); 32 | 33 | unpacker.ReadObject(out obj); 34 | if (obj.IsDictionary) 35 | { 36 | var dict = obj.AsDictionary(); 37 | if (dict.Keys.Count > 0) 38 | { 39 | foreach (var key in dict.Keys) 40 | { 41 | var code = key.AsInt32(); 42 | 43 | ParseIProtoResponse(code, dict[key]); 44 | } 45 | } 46 | } 47 | } 48 | 49 | private void ParseIProtoResponse(int code, MessagePackObject value) 50 | { 51 | switch (code) 52 | { 53 | case (int)Key.CODE: 54 | Code = value.AsInt32(); 55 | break; 56 | case (int)Key.SYNC: 57 | Sync = value.AsInt32(); 58 | break; 59 | case (int)Key.SCHEMA_ID: 60 | SchemaId = value.AsInt32(); 61 | break; 62 | case (int)Key.DATA: 63 | Body = value.AsList().Select(i => new Tuple(i.AsList().Select(a => a.ToObject()).ToList())).ToList(); 64 | break; 65 | case (int)Key.ERROR: 66 | Error = value.AsString(); 67 | IsError = true; 68 | break; 69 | } 70 | } 71 | } 72 | 73 | public class TarantoolException : Exception 74 | { 75 | public TarantoolException(string message) : base(message) 76 | { 77 | } 78 | } 79 | 80 | public class TarantoolDisconnectedException : Exception 81 | { 82 | public TarantoolDisconnectedException(string message) : base(message) 83 | { 84 | } 85 | } 86 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/Tuple.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | using Akka.Dispatch.SysMsg; 5 | using MsgPack; 6 | using Tarantool.Net.IProto.Builders; 7 | 8 | namespace Tarantool.Net.IProto 9 | { 10 | public class Tuple : IPackable 11 | { 12 | public Tuple() 13 | { 14 | } 15 | 16 | public Tuple(IEnumerable fields) 17 | { 18 | _fields.AddRange(fields); 19 | } 20 | 21 | public void AddField(object data) 22 | { 23 | _fields.Add(data); 24 | } 25 | 26 | public void Reset() 27 | { 28 | _fields.Clear(); 29 | } 30 | 31 | public static Tuple Create(Func keyTupleBuilder) 32 | { 33 | var ktb = new TupleBuilder(new Tuple()); 34 | return keyTupleBuilder(ktb); 35 | } 36 | 37 | public List Fields => _fields; 38 | 39 | private readonly List _fields = new List(); 40 | 41 | public void PackToMessage(Packer packer, PackingOptions options) 42 | { 43 | packer.PackArrayHeader(_fields.Count); 44 | foreach (var field in _fields) 45 | { 46 | if (field is string) 47 | packer.PackString(field.ToString()); 48 | else { 49 | packer.Pack(field); 50 | } 51 | } 52 | } 53 | 54 | 55 | public override string ToString() 56 | { 57 | return string.Concat("[", string.Join(", ", _fields), "]"); 58 | } 59 | } 60 | } 61 | 62 | -------------------------------------------------------------------------------- /Tarantool.Net/IProto/UpdateOperation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using MsgPack; 3 | using MsgPack.Serialization; 4 | 5 | namespace Tarantool.Net.IProto 6 | { 7 | public class UpdateOperation : IPackable 8 | { 9 | public UpdateOperation() 10 | { 11 | FieldNo = 0; 12 | Code = UpdateOperationCode.Assign; 13 | Arg = default(T); 14 | } 15 | 16 | [MessagePackMember(1)] 17 | public UInt32 FieldNo { protected get; set; } 18 | 19 | [MessagePackMember(0)] 20 | public string Code { protected get; set; } 21 | 22 | [MessagePackMember(2)] 23 | public T Arg { protected get; set; } 24 | 25 | public void PackToMessage(Packer packer, PackingOptions options) 26 | { 27 | packer.PackArrayHeader(3); 28 | packer.PackString(Code); 29 | packer.Pack(FieldNo); 30 | packer.Pack(Arg); 31 | } 32 | } 33 | 34 | public class SpliceUpdateOperation : UpdateOperation, IPackable 35 | { 36 | public SpliceUpdateOperation() 37 | { 38 | Code = UpdateOperationCode.Splice; 39 | Position = 0; 40 | Offset = 0; 41 | } 42 | 43 | public UInt32 Position { get; set; } 44 | public UInt32 Offset { get; set; } 45 | 46 | public new void PackToMessage(Packer packer, PackingOptions options) 47 | { 48 | packer.PackArrayHeader(5); 49 | packer.PackString(Code); 50 | packer.Pack(FieldNo); 51 | packer.Pack(Position); 52 | packer.Pack(Offset); 53 | packer.PackString(Arg); 54 | } 55 | } 56 | } -------------------------------------------------------------------------------- /Tarantool.Net/IProto/UpdateOperationCode.cs: -------------------------------------------------------------------------------- 1 | namespace Tarantool.Net.IProto 2 | { 3 | public static class UpdateOperationCode 4 | { 5 | public const string Addition = "+"; 6 | public const string Subtraction = "-"; 7 | public const string BitwiseAnd = "&"; 8 | // ReSharper disable once InconsistentNaming 9 | public const string BitwiseXOR = "^"; 10 | public const string BitwiseOr = "|"; 11 | public const string Delete = "#"; 12 | public const string Insert = "!"; 13 | public const string Assign = "="; 14 | public const string Splice = ":"; 15 | } 16 | } -------------------------------------------------------------------------------- /Tarantool.Net/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // Управление общими сведениями о сборке осуществляется с помощью 6 | // набора атрибутов. Измените значения этих атрибутов, чтобы изменить сведения, 7 | // связанные со сборкой. 8 | [assembly: AssemblyTitle("Tarantool-net")] 9 | [assembly: AssemblyDescription("A .Net client for Tarantool written with the Akka.Net I/O package")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("donmikel")] 12 | [assembly: AssemblyProduct("Tarantool-net")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Параметр ComVisible со значением FALSE делает типы в сборке невидимыми 18 | // для COM-компонентов. Если требуется обратиться к типу в этой сборке через 19 | // COM, задайте атрибуту ComVisible значение TRUE для этого типа. 20 | [assembly: ComVisible(false)] 21 | 22 | // Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM 23 | [assembly: Guid("8ee464c8-b151-42c3-96bf-8d655ff8b6b9")] 24 | 25 | // Сведения о версии сборки состоят из следующих четырех значений: 26 | // 27 | // Основной номер версии 28 | // Дополнительный номер версии 29 | // Номер сборки 30 | // Редакция 31 | // 32 | // Можно задать все значения или принять номера сборки и редакции по умолчанию 33 | // используя "*", как показано ниже: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Tarantool.Net/Tarantool.Net.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {8EE464C8-B151-42C3-96BF-8D655FF8B6B9} 8 | Library 9 | Properties 10 | Tarantool.Net 11 | Tarantool.Net 12 | v4.5.2 13 | 512 14 | 15 | 16 | 17 | 18 | true 19 | full 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | prompt 24 | 4 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | 34 | 35 | 36 | 37 | 38 | 39 | ..\packages\Akka.1.0.7\lib\net45\Akka.dll 40 | True 41 | 42 | 43 | ..\packages\MsgPack.Cli.0.6.8\lib\net45\MsgPack.dll 44 | True 45 | 46 | 47 | 48 | ..\packages\System.Collections.Immutable.1.1.37\lib\dotnet\System.Collections.Immutable.dll 49 | True 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 119 | -------------------------------------------------------------------------------- /Tarantool.Net/Tarantool.Net.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Tarantool.NET 5 | $version$ 6 | Tarantool.NET 7 | donmikel 8 | Mike Po 9 | https://github.com/donmikel/tarantool-net 10 | false 11 | A .Net client for Tarantool http://tarantool.org written with the Akka.Net I/O package 12 | 13 | Copyright 2016 14 | tarantool akka.net 15 | 16 | -------------------------------------------------------------------------------- /Tarantool.Net/Tarantool.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Akka.Actor; 4 | using Akka.Configuration; 5 | using Akka.Util.Internal; 6 | using Tarantool.Net.IProto; 7 | using Tarantool.Net.IProto.Requests; 8 | 9 | namespace Tarantool.Net 10 | { 11 | public class Tarantool : TarantoolConnectionSupervisor, IWithUnboundedStash 12 | { 13 | public static Props Create(string host = "localhost", int port = 3301, AuthToken authToken = null, HashSet listeners = null, bool? stashMessage = null, 14 | TimeSpan? connectionTimeOut = null, TimeSpan? connectionRetryDelay = null, 15 | int? connectionRetryAttempts = null, TimeSpan? connectionHeartbeatDelay = null) 16 | { 17 | var config = ConfigurationFactory.Load(); 18 | return Props.Create( 19 | host, 20 | port, 21 | authToken ?? AuthToken.GuestToken, 22 | listeners ?? new HashSet(), 23 | stashMessage ?? config.GetBoolean("tarantool.connection.stash", true), 24 | connectionTimeOut ?? config.GetTimeSpan("tarantool.connection.timeout", TimeSpan.FromSeconds(2)), 25 | connectionRetryDelay ?? config.GetTimeSpan("tarantool.connection.retry.delay", TimeSpan.FromSeconds(1)), 26 | connectionRetryAttempts ?? config.GetInt("tarantool.connection.retry.attempts", 3), 27 | connectionHeartbeatDelay 28 | ); 29 | 30 | } 31 | 32 | public class AuthenticationFailed : Connection.StateChange 33 | { 34 | public AuthenticationFailed(string host, int port) 35 | { 36 | Host = host; 37 | Port = port; 38 | } 39 | 40 | public string Host { get; } 41 | public int Port { get; } 42 | } 43 | 44 | private readonly string _host; 45 | private readonly int _port; 46 | private readonly bool _stashMessage; 47 | private readonly HashSet _listeners; 48 | private readonly TimeSpan _connectionRetryDelay; 49 | private readonly int? _connectionRetryAttempts; 50 | 51 | 52 | private int _retries = 0; 53 | 54 | public Tarantool(string host, int port, AuthToken authToken, HashSet listeners, bool stashMessage, TimeSpan connectionTimeOut, TimeSpan connectionRetryDelay, int? connectionRetryAttempts, TimeSpan? connectionHeartbeatDelay) : 55 | base(authToken, listeners, connectionTimeOut, connectionHeartbeatDelay) 56 | { 57 | _host = host; 58 | _port = port; 59 | _listeners = listeners; 60 | _connectionRetryDelay = connectionRetryDelay; 61 | _connectionRetryAttempts = connectionRetryAttempts; 62 | _stashMessage = stashMessage; 63 | 64 | Become(Disconnected); 65 | } 66 | 67 | protected override void PreStart() 68 | { 69 | _listeners.ForEach(l => Context.Watch(l)); 70 | Self.Tell(new Connect(_host, _port)); 71 | } 72 | 73 | protected override void Disconnected() 74 | { 75 | DisconnectedWithRetry(); 76 | base.Disconnected(); 77 | } 78 | 79 | private void DisconnectedWithRetry() 80 | { 81 | Receive(_ => !_stashMessage, 82 | x => 83 | Sender.Tell(new Failure 84 | { 85 | Exception = new TarantoolDisconnectedException($"Disconnected from {_host}:{_port}") 86 | })); 87 | 88 | Receive(_ => _stashMessage, _ => Stash.Stash()); 89 | 90 | Receive(x => 91 | { 92 | _retries = 0; 93 | NotifyStateChanged(x.Connected); 94 | if(_stashMessage) 95 | Stash.UnstashAll(); 96 | 97 | Become(Connected); 98 | 99 | }); 100 | 101 | Receive(_ => 102 | { 103 | if (_connectionRetryAttempts.HasValue & _connectionRetryAttempts > _retries) 104 | { 105 | _retries++; 106 | Context.System.Scheduler.ScheduleTellOnce(_connectionRetryDelay, Connection, new Connection.Connect(), Self); 107 | } 108 | else if (!_connectionRetryAttempts.HasValue) 109 | { 110 | Context.System.Scheduler.ScheduleTellOnce(_connectionRetryDelay, Connection, new Connection.Connect(), Self); 111 | } 112 | }); 113 | } 114 | 115 | public IStash Stash { get; set; } 116 | } 117 | } -------------------------------------------------------------------------------- /Tarantool.Net/TarantoolConnectionSupervisor.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using Akka.Actor; 4 | using Akka.Event; 5 | using Akka.Util.Internal; 6 | using Tarantool.Net.IProto; 7 | using Tarantool.Net.IProto.Requests; 8 | 9 | namespace Tarantool.Net 10 | { 11 | public abstract class TarantoolConnectionSupervisor : ReceiveActor 12 | { 13 | protected class Connect 14 | { 15 | public Connect(string host, int port) 16 | { 17 | Host = host; 18 | Port = port; 19 | } 20 | 21 | public string Host { get; private set; } 22 | public int Port { get; private set; } 23 | } 24 | protected class Reconnect {} 25 | protected class AuthOk 26 | { 27 | public AuthOk(Connection.Connected connected) 28 | { 29 | Connected = connected; 30 | } 31 | 32 | public Connection.Connected Connected { get; } 33 | } 34 | 35 | public IActorRef Connection = Context.System.DeadLetters; 36 | 37 | private readonly AuthToken _authToken; 38 | private readonly HashSet _listeners; 39 | private readonly TimeSpan _connectionTimeOut; 40 | private readonly TimeSpan? _connectionHeartbeatDelay; 41 | private readonly ILoggingAdapter _log = Context.GetLogger(); 42 | 43 | protected TarantoolConnectionSupervisor(AuthToken authToken, HashSet listeners, TimeSpan connectionTimeOut, TimeSpan? connectionHeartbeatDelay = null) 44 | { 45 | _authToken = authToken; 46 | _listeners = listeners; 47 | _connectionTimeOut = connectionTimeOut; 48 | _connectionHeartbeatDelay = connectionHeartbeatDelay; 49 | 50 | Status = new Connection.Disconnected("unknown", 0); 51 | } 52 | 53 | protected Connection.StateChange Status { get; private set; } 54 | 55 | protected void Connected() 56 | { 57 | _log.Warning("Connected"); 58 | 59 | HandleListeners(); 60 | 61 | Receive(m => Connection.Forward(m)); 62 | 63 | Receive(dm => 64 | { 65 | NotifyStateChanged(dm); 66 | Become(Disconnected); 67 | Self.Tell(new Reconnect()); 68 | }); 69 | } 70 | 71 | protected virtual void Disconnected() 72 | { 73 | _log.Warning("Disconnected"); 74 | HandleListeners(); 75 | 76 | Receive(x => 77 | { 78 | Connection.Tell(PoisonPill.Instance); 79 | Connection = 80 | Context.ActorOf(Props.Create(Self, x.Host, x.Port, _connectionTimeOut, _connectionHeartbeatDelay)); 81 | }); 82 | 83 | Receive(x => NotifyStateChanged(x)); 84 | 85 | Receive(x => Authenticate(x)); 86 | 87 | Receive(x => 88 | { 89 | NotifyStateChanged(x.Connected); 90 | Become(Connected); 91 | }); 92 | 93 | Receive(x => 94 | { 95 | NotifyStateChanged(x); 96 | Self.Tell(new Reconnect()); 97 | }); 98 | 99 | } 100 | 101 | private void Authenticate(Connection.Connected x) 102 | { 103 | var self = Self; 104 | Connection.Ask(Request 105 | .Auth() 106 | .Password(_authToken.Password) 107 | .UserName(_authToken.Username) 108 | .Salt(x.Salt) 109 | .Build()).ContinueWith(tr => 110 | { 111 | if (tr.IsFaulted) 112 | NotifyStateChanged(new Tarantool.AuthenticationFailed(x.Host, x.Port)); 113 | 114 | self.Tell(new AuthOk(x)); 115 | }); 116 | } 117 | 118 | private void HandleListeners() 119 | { 120 | Receive(ar => 121 | { 122 | _listeners.Add(ar); 123 | ar.Tell(Status); 124 | }); 125 | 126 | Receive(m => _listeners.Remove(m.ActorRef)); 127 | } 128 | 129 | protected void NotifyStateChanged(Connection.StateChange newState) 130 | { 131 | Status = newState; 132 | _listeners.ForEach(l => l.Tell(newState)); 133 | } 134 | } 135 | } -------------------------------------------------------------------------------- /Tarantool.Net/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /Tarantool.Net/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | --------------------------------------------------------------------------------