├── .gitattributes
├── .gitignore
├── Build.fsx
├── Create-Mono.fsx
├── Examples
├── ActorFSharpSample1
│ ├── ActorFSharpSample1.fsproj
│ ├── App.config
│ ├── Program.fs
│ └── packages.config
├── ActorFSharpSample2
│ ├── ActorFSharpSample2.fsproj
│ ├── App.config
│ ├── Program.fs
│ └── packages.config
├── ActorFSharpSample3
│ ├── ActorFSharpSample3.fsproj
│ ├── App.config
│ ├── Program.fs
│ └── packages.config
├── ActorSample1
│ ├── ActorSample1-Mono.csproj
│ ├── ActorSample1.csproj
│ ├── App.config
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── packages.config
├── ActorSample2
│ ├── ActorSample2-Mono.csproj
│ ├── ActorSample2.csproj
│ ├── App.config
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── packages.config
├── PingPong
│ ├── App.config
│ ├── PingPong-Mono.csproj
│ ├── PingPong.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── packages.config
├── ProtobufSample
│ ├── App.config
│ ├── Client.cs
│ ├── Data.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── ProtobufSample-Mono.csproj
│ ├── ProtobufSample.csproj
│ ├── Server.cs
│ └── packages.config
├── ReactiveSample
│ ├── App.config
│ ├── Client.cs
│ ├── Data.cs
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── ReactiveSample-Mono.csproj
│ ├── ReactiveSample.csproj
│ ├── Server.cs
│ └── packages.config
└── RemoteActorsSample
│ ├── App.config
│ ├── Client.cs
│ ├── Program.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── RemoteActorsSample.csproj
│ ├── Server.cs
│ └── packages.config
├── LICENSE
├── PerfTests
├── Actors
│ ├── Actors-Mono.csproj
│ ├── Actors.csproj
│ ├── App.config
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── packages.config
├── Executors
│ ├── App.config
│ ├── Benchmark.cs
│ ├── Executors-Mono.csproj
│ ├── Executors.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── SingleExecutor.cs
│ └── packages.config
├── PingPong
│ ├── App.config
│ ├── PingPong.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── packages.config
└── SimpleThroughput
│ ├── FramedPerfTest
│ ├── App.config
│ ├── FramedPerfTest-Mono.csproj
│ ├── FramedPerfTest.csproj
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ └── packages.config
│ ├── RawStreamManyClients
│ ├── App.config
│ ├── Program.cs
│ ├── Properties
│ │ └── AssemblyInfo.cs
│ ├── RawStreamManyClients.csproj
│ └── packages.config
│ └── RawStreamPerfTest
│ ├── App.config
│ ├── Program.cs
│ ├── Properties
│ └── AssemblyInfo.cs
│ ├── RawStreamPerfTest-Mono.csproj
│ ├── RawStreamPerfTest.csproj
│ └── packages.config
├── README.md
├── SharedAssemblyInfo.cs
├── SharedAssemblyInfo.fs
├── Stacks-Mono.sln
├── Stacks.Actors.DI.Windsor
├── Properties
│ └── AssemblyInfo.cs
├── Stacks.Actors.DI.Windsor.csproj
├── Stacks.Actors.DI.Windsor.nuspec
├── WindsorDependencyResolver.cs
└── packages.config
├── Stacks.Actors.Tests.DI.Windsor
├── ContainerTests.cs
├── Properties
│ └── AssemblyInfo.cs
├── Stacks.Actors.Tests.DI.Windsor.csproj
└── packages.config
├── Stacks.Actors.Tests
├── ActorSystemTests
│ ├── ActorCodeGeneration.cs
│ ├── ActorSystemCreate.cs
│ ├── ActorTests.cs
│ ├── HierarchyTests.cs
│ └── TestActors.cs
├── Properties
│ └── AssemblyInfo.cs
├── Remote
│ ├── ActorSessionTests.cs
│ ├── ConnectionTests.cs
│ ├── CustomSerializerTests.cs
│ ├── MessageTests.cs
│ ├── ObservableTests.cs
│ ├── TimeoutTests.cs
│ └── Utils.cs
├── Stacks.Actors.Tests.csproj
└── packages.config
├── Stacks.Actors
├── Actor.cs
├── ActorContext.cs
├── ActorContextSettings.cs
├── ActorCtorGuardian.cs
├── ActorSettings.cs
├── ActorSystem.cs
├── Bit.cs
├── CodeGen
│ ├── ActorTypeGenerator.cs
│ ├── ActorWrapperBase.cs
│ ├── FormattingExtensions.cs
│ ├── Helpers.cs
│ ├── IActorCompilerStrategy.cs
│ ├── ObservableMethodCompiler.cs
│ ├── ObservablePropertiesCompiler.cs
│ ├── StandardMethodCompiler.cs
│ ├── StandardPropertiesCompiler.cs
│ └── TaskMethodsCompiler.cs
├── DI
│ ├── Args.cs
│ ├── DependencyInjectionHelper.cs
│ ├── IDependencyInjectionHelper.cs
│ └── IDependencyResolver.cs
├── Exceptions.cs
├── IActor.cs
├── IActorContext.cs
├── NoExceptionHandlerAttribute.cs
├── PathUtils.cs
├── Properties
│ └── AssemblyInfo.cs
├── Remote
│ ├── ActorClientProxy.cs
│ ├── ActorClientProxyOptions.cs
│ ├── ActorClientProxyTemplate.cs
│ ├── ActorPacketSerializer.cs
│ ├── ActorProtocol.cs
│ ├── ActorRemoteMessageClient.cs
│ ├── ActorServerProxy.cs
│ ├── ActorServerProxyOptions.cs
│ ├── ActorServerProxyTemplate.cs
│ ├── ClientActorDisconnectedData.cs
│ ├── CodeGen
│ │ ├── ActorTypeBuilder.cs
│ │ ├── ClientActorTypeBuilder.cs
│ │ └── ServerActorTypeBuilder.cs
│ ├── IActorClientProxy.cs
│ ├── IActorServerProxy.cs
│ ├── IActorSession.cs
│ └── IReplyMessage.cs
├── RootActor.cs
├── Stacks.Actors.csproj
├── Stacks.Actors.nuspec
└── packages.config
├── Stacks.FSharp
├── Actors
│ ├── ActorContext.fs
│ └── Executor.fs
├── AssemblyInfo.fs
├── Stacks.FSharp.fsproj
├── Stacks.FSharp.nuspec
└── packages.config
├── Stacks.MessagePack
├── Properties
│ └── AssemblyInfo.cs
├── Serializers
│ └── MessagePackStacksSerializer.cs
├── Stacks.MessagePack-Mono.csproj
├── Stacks.MessagePack.csproj
├── Stacks.MessagePack.nuspec
└── packages.config
├── Stacks.Tests
├── Client
│ ├── FramedClientTests.cs
│ ├── MessageClientTests.cs
│ ├── RawBytesClientTests.cs
│ ├── ReactiveMessageClientTests.cs
│ └── SslClientTests.cs
├── DataHelpers.cs
├── ExecutorTests.cs
├── IPHelpersTests.cs
├── Properties
│ └── AssemblyInfo.cs
├── Serialization
│ ├── MessagePackSerializerTests.cs
│ ├── ProtoBufSerializerTests.cs
│ └── SerializationHandlerTests.cs
├── SocketServerTests.cs
├── Stacks.Tests-Mono.csproj
├── Stacks.Tests.csproj
├── StacksTest.pfx
├── Utils.cs
└── packages.config
├── Stacks.sln
├── Stacks
├── AddressHelpers.cs
├── Client
│ ├── FramedClientBuffer.cs
│ ├── IFramedClient.cs
│ ├── IMessageClient.cs
│ ├── IRawByteClient.cs
│ ├── ISocketClient.cs
│ ├── RawByteClientStream.cs
│ └── Tcp
│ │ ├── FramedClient.cs
│ │ ├── MessageClient.cs
│ │ ├── MessageClientBase.cs
│ │ ├── ReactiveClientModelBuilder.cs
│ │ ├── ReactiveMessageClient.cs
│ │ ├── SocketClient.cs
│ │ └── SslClient.cs
├── Ensure.cs
├── Executors
│ ├── ActionBlockExecutor.Mono.cs
│ ├── ActionBlockExecutor.cs
│ ├── ActionBlockExecutorSettings.cs
│ ├── CapturedContextExecutor.cs
│ ├── Executor.cs
│ ├── ExecutorHelper.cs
│ └── IExecutor.cs
├── MessageClient
│ ├── IMessageIdCache.cs
│ ├── ImperativeMessageIdCache.cs
│ ├── MessageIdCache.cs
│ ├── MessageIdRegistration.cs
│ ├── ReactiveMessageReceiverCreator.cs
│ └── StacksMessageAttribute.cs
├── Properties
│ └── AssemblyInfo.cs
├── ResizableCyclicBuffer.cs
├── Serializers
│ ├── IMessageHandler.cs
│ ├── IStacksSerializer.cs
│ ├── ProtobufStacksSerializer.cs
│ └── StacksSerializationHandler.cs
├── Server
│ └── Tcp
│ │ └── SocketServer.cs
├── Stacks-Mono.csproj
├── Stacks.csproj
├── Stacks.nuspec
└── packages.config
├── build.cmd
└── tools
└── NuGet
└── nuget.exe
/.gitattributes:
--------------------------------------------------------------------------------
1 | ###############################################################################
2 | # Set default behavior to automatically normalize line endings.
3 | ###############################################################################
4 | * text=auto
5 |
6 | ###############################################################################
7 | # Set default behavior for command prompt diff.
8 | #
9 | # This is need for earlier builds of msysgit that does not have it on by
10 | # default for csharp files.
11 | # Note: This is only used by command line
12 | ###############################################################################
13 | #*.cs diff=csharp
14 |
15 | ###############################################################################
16 | # Set the merge driver for project and solution files
17 | #
18 | # Merging from the command prompt will add diff markers to the files if there
19 | # are conflicts (Merging from VS is not affected by the settings below, in VS
20 | # the diff markers are never inserted). Diff markers may cause the following
21 | # file extensions to fail to load in VS. An alternative would be to treat
22 | # these files as binary and thus will always conflict and require user
23 | # intervention with every merge. To do so, just uncomment the entries below
24 | ###############################################################################
25 | #*.sln merge=binary
26 | #*.csproj merge=binary
27 | #*.vbproj merge=binary
28 | #*.vcxproj merge=binary
29 | #*.vcproj merge=binary
30 | #*.dbproj merge=binary
31 | #*.fsproj merge=binary
32 | #*.lsproj merge=binary
33 | #*.wixproj merge=binary
34 | #*.modelproj merge=binary
35 | #*.sqlproj merge=binary
36 | #*.wwaproj merge=binary
37 |
38 | ###############################################################################
39 | # behavior for image files
40 | #
41 | # image files are treated as binary by default.
42 | ###############################################################################
43 | #*.jpg binary
44 | #*.png binary
45 | #*.gif binary
46 |
47 | ###############################################################################
48 | # diff behavior for common document formats
49 | #
50 | # Convert binary document formats to text before diffing them. This feature
51 | # is only available from the command line. Turn it on by uncommenting the
52 | # entries below.
53 | ###############################################################################
54 | #*.doc diff=astextplain
55 | #*.DOC diff=astextplain
56 | #*.docx diff=astextplain
57 | #*.DOCX diff=astextplain
58 | #*.dot diff=astextplain
59 | #*.DOT diff=astextplain
60 | #*.pdf diff=astextplain
61 | #*.PDF diff=astextplain
62 | #*.rtf diff=astextplain
63 | #*.RTF diff=astextplain
64 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | .fake/
5 | tools/FAKE/*
6 | !tools/NuGet/nuget.exe
7 |
8 | /*.nupkg
9 |
10 | # User-specific files
11 | *.suo
12 | *.user
13 | *.sln.docstates
14 |
15 | # Build results
16 |
17 | [Dd]ebug/
18 | [Rr]elease/
19 | x64/
20 | build/
21 | [Bb]in/
22 | [Oo]bj/
23 |
24 | # Enable "build/" folder in the NuGet Packages folder since NuGet packages use it for MSBuild targets
25 | !packages/*/build/
26 |
27 | # MSTest test Results
28 | [Tt]est[Rr]esult*/
29 | [Bb]uild[Ll]og.*
30 |
31 | *_i.c
32 | *_p.c
33 | *.ilk
34 | *.meta
35 | *.obj
36 | *.pch
37 | *.pdb
38 | *.pgc
39 | *.pgd
40 | *.rsp
41 | *.sbr
42 | *.tlb
43 | *.tli
44 | *.tlh
45 | *.tmp
46 | *.tmp_proj
47 | *.log
48 | *.vspscc
49 | *.vssscc
50 | .builds
51 | *.pidb
52 | *.log
53 | *.scc
54 |
55 | # Visual C++ cache files
56 | ipch/
57 | *.aps
58 | *.ncb
59 | *.opensdf
60 | *.sdf
61 | *.cachefile
62 |
63 | # Visual Studio profiler
64 | *.psess
65 | *.vsp
66 | *.vspx
67 |
68 | # Guidance Automation Toolkit
69 | *.gpState
70 |
71 | # ReSharper is a .NET coding add-in
72 | _ReSharper*/
73 | *.[Rr]e[Ss]harper
74 |
75 | # TeamCity is a build add-in
76 | _TeamCity*
77 |
78 | # DotCover is a Code Coverage Tool
79 | *.dotCover
80 |
81 | # NCrunch
82 | *.ncrunch*
83 | .*crunch*.local.xml
84 | _NCrunch_Stacks/
85 |
86 | # Installshield output folder
87 | [Ee]xpress/
88 |
89 | # DocProject is a documentation generator add-in
90 | DocProject/buildhelp/
91 | DocProject/Help/*.HxT
92 | DocProject/Help/*.HxC
93 | DocProject/Help/*.hhc
94 | DocProject/Help/*.hhk
95 | DocProject/Help/*.hhp
96 | DocProject/Help/Html2
97 | DocProject/Help/html
98 |
99 | # Click-Once directory
100 | publish/
101 |
102 | # Publish Web Output
103 | *.Publish.xml
104 |
105 | # NuGet Packages Directory
106 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line
107 | packages/
108 |
109 | # Windows Azure Build Output
110 | csx
111 | *.build.csdef
112 |
113 | # Windows Store app package directory
114 | AppPackages/
115 |
116 | # Others
117 | sql/
118 | *.Cache
119 | ClientBin/
120 | [Ss]tyle[Cc]op.*
121 | ~$*
122 | *~
123 | *.dbmdl
124 | *.[Pp]ublish.xml
125 | *.pfx
126 | *.publishsettings
127 |
128 | # RIA/Silverlight projects
129 | Generated_Code/
130 |
131 | # Backup & report files from converting an old project file to a newer
132 | # Visual Studio version. Backup files are not needed, because we have git ;-)
133 | _UpgradeReport_Files/
134 | Backup*/
135 | UpgradeLog*.XML
136 | UpgradeLog*.htm
137 |
138 | # SQL Server files
139 | App_Data/*.mdf
140 | App_Data/*.ldf
141 |
142 |
143 | #LightSwitch generated files
144 | GeneratedArtifacts/
145 | _Pvt_Extensions/
146 | ModelManifest.xml
147 |
148 | # =========================
149 | # Windows detritus
150 | # =========================
151 |
152 | # Windows image file caches
153 | Thumbs.db
154 | ehthumbs.db
155 |
156 | # Folder config file
157 | Desktop.ini
158 |
159 | # Recycle Bin used on file shares
160 | $RECYCLE.BIN/
161 |
162 | # Mac desktop service store files
163 | .DS_Store
164 |
--------------------------------------------------------------------------------
/Create-Mono.fsx:
--------------------------------------------------------------------------------
1 | #r "System.Xml.Linq.dll"
2 |
3 | open System
4 | open System.IO
5 | open System.Xml.Linq
6 | open System.Text.RegularExpressions
7 |
8 | let xn (ns: XNamespace) x = XName.Get(x, ns.ToString())
9 | let (@@) x y = Path.Combine(x, y)
10 |
11 | let PatchSolution solutionFile =
12 | let slnFile = FileInfo(solutionFile)
13 | let slnMonoFile = Path.GetDirectoryName(slnFile.FullName) @@
14 | (Path.GetFileNameWithoutExtension(slnFile.Name) + "-Mono.sln")
15 | if File.Exists(slnMonoFile) then File.Delete(slnMonoFile)
16 |
17 | let projRegex = @"Project\(""\{[^}]+\}""\) = ""[^""]+"", ""[^""]+"", ""\{[^}]+\}"
18 |
19 | let outFile = File.CreateText(slnMonoFile)
20 |
21 | for line in File.ReadAllLines(slnFile.FullName) do
22 | match Regex.IsMatch(line, projRegex) with
23 | | true -> outFile.WriteLine(line.Replace(".csproj", "-Mono.csproj"))
24 | | false -> outFile.WriteLine(line)
25 | outFile.Close();
26 |
27 | let PatchProject projectFile =
28 | let projFileInfo = FileInfo(projectFile)
29 | let projMonoFile = Path.GetDirectoryName(projFileInfo.FullName) @@
30 | (Path.GetFileNameWithoutExtension(projFileInfo.Name) + "-Mono.csproj")
31 | if File.Exists(projMonoFile) then
32 | File.Delete(projMonoFile)
33 |
34 | let xml = XDocument.Load(projFileInfo.FullName)
35 | let xn = xn (xml.Root.GetDefaultNamespace())
36 | let axn x = XName.Get(x)
37 |
38 | //Changed target framework version to 4.5
39 | xml.Element(xn"Project").Elements(xn"PropertyGroup")
40 | |> Seq.iter(fun p ->
41 | match p.Element(xn"TargetFrameworkVersion") with
42 | | null -> ()
43 | | t -> t.Value <- "v4.5"
44 | )
45 |
46 | //Patch constants to add MONO (compilation requires it)
47 | xml.Element(xn"Project").Elements(xn"PropertyGroup")
48 | |> Seq.iter(fun p ->
49 | match p.Element(xn"DefineConstants") with
50 | | null -> ()
51 | | t -> match t.Value.Contains("MONO") with
52 | | true -> ()
53 | | false -> t.Value <- t.Value + ";MONO"
54 | )
55 |
56 | //Patch tools version to 4.0 (old MsBuild versioning)
57 | xml.Element(xn"Project").Attribute(axn"ToolsVersion").Value <- "4.0"
58 |
59 | xml.Save(projMonoFile)
60 |
61 | let rec PatchAllProjects dir =
62 | Directory.EnumerateDirectories(dir)
63 | |> Seq.iter(fun d -> PatchAllProjects(d))
64 |
65 | Directory.EnumerateFiles(dir, "*.csproj")
66 | |> Seq.iter(fun f -> if not (f.Contains("-Mono")) then PatchProject(f))
67 |
68 | PatchSolution "Stacks.sln"
69 | PatchAllProjects "./"
70 |
71 |
72 |
--------------------------------------------------------------------------------
/Examples/ActorFSharpSample1/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Examples/ActorFSharpSample1/Program.fs:
--------------------------------------------------------------------------------
1 | open Stacks
2 | open Stacks.Actors
3 |
4 | type IFormatter =
5 | abstract member SayHello: string -> Async
6 |
7 | type Formatter() =
8 | inherit Actor()
9 |
10 | member this.GetContext() =
11 | base.GetActorSynchronizationContext()
12 |
13 | interface IFormatter with
14 | member this.SayHello(name: string) =
15 | async {
16 | do! Async.SwitchToContext(this.GetContext())
17 | return sprintf "Hello %s!" name
18 | }
19 |
20 | type Hello() =
21 |
22 | let formatter = ActorSystem.Default.CreateActor() :?> IFormatter
23 |
24 | member this.SayHelloToFriends(names: seq) =
25 | names
26 | |> Seq.iter (fun t -> printfn "%s" (Async.RunSynchronously <| formatter.SayHello(t)))
27 |
28 |
29 | []
30 | let main argv =
31 |
32 | let helloPrinter = Hello()
33 |
34 | helloPrinter.SayHelloToFriends( [ "Stan"; "Scott"; "John" ])
35 |
36 | 0
37 |
--------------------------------------------------------------------------------
/Examples/ActorFSharpSample1/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Examples/ActorFSharpSample2/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Examples/ActorFSharpSample2/Program.fs:
--------------------------------------------------------------------------------
1 |
2 | open System.Net.Http
3 | open Stacks.Actors
4 | open System.Xml.Linq
5 | open Stacks
6 |
7 |
8 | type IWeather =
9 | abstract member GetTemperature: string -> Async
10 |
11 | type Weather() =
12 | inherit Actor()
13 | let httpClient = new HttpClient()
14 |
15 | let xn s = XName.Get(s)
16 |
17 | interface IWeather with
18 | member __.GetTemperature(city: string) =
19 | base.Context.MakeAsync(async {
20 | let! response = sprintf "http://api.openweathermap.org/data/2.5/\
21 | weather?q=%s&mode=xml&units=metric" city
22 | |> httpClient.GetStringAsync
23 | |> Async.AwaitTask
24 |
25 | return double (XDocument.Parse(response)
26 | .Element(xn"current")
27 | .Element(xn"temperature")
28 | .Attribute(xn"value"))
29 | })
30 |
31 |
32 | []
33 | let main _ =
34 |
35 | let weather = ActorSystem.Default.CreateActor() :?> IWeather
36 |
37 | try
38 | let temp = weather.GetTemperature("Warsaw") |> Async.RunSynchronously
39 | printfn "Temperature in Warsaw, Poland: %.2f\u00B0C" temp
40 | with
41 | | _ -> printfn "Could not get temperature for Warsaw, Poland"
42 |
43 | 0
44 |
--------------------------------------------------------------------------------
/Examples/ActorFSharpSample2/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Examples/ActorFSharpSample3/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Examples/ActorFSharpSample3/Program.fs:
--------------------------------------------------------------------------------
1 | open RestSharp
2 | open Stacks
3 | open Newtonsoft.Json
4 | open Newtonsoft.Json.Linq
5 |
6 | let GetRepositories(user: string) = async {
7 | let c = new RestClient("https://api.github.com/")
8 |
9 | let! resp = c.ExecuteGetTaskAsync(RestRequest("users/" + user + "/repos"))
10 | |> Async.AwaitTask
11 |
12 | return JsonConvert.DeserializeObject(resp.Content) :?> JArray
13 | |> Seq.map(fun r -> r.["name"].Value())
14 | |> Seq.toArray
15 | }
16 |
17 | let GetStargazers user repo = async {
18 | let c = new RestClient("https://api.github.com/")
19 |
20 | let! resp = c.ExecuteGetTaskAsync(RestRequest(sprintf "repos/%s/%s/stargazers" user repo))
21 | |> Async.AwaitTask
22 |
23 | return JsonConvert.DeserializeObject(resp.Content) :?> JArray
24 | |> Seq.map(fun r -> r.["login"].Value())
25 | |> Seq.toArray
26 | }
27 |
28 | // This sample shows how to use executor to run an async block
29 | // All features, like Async.Parallel can be used, and user code
30 | // will run on executor's context, which can be in this context
31 | // assumed to be an actor. This also means, that external tasks
32 | // can be awaited inside async block on exector.
33 | //
34 | // Sample rules apply to actor contexts and actors, although
35 | // using Actor class is discouraged in F#, because of caveeats
36 | // with inheritance.
37 | // Instead, composition with ActorContext is a way to go
38 |
39 | []
40 | let main _ =
41 |
42 | let exec = ActionBlockExecutor("main")
43 |
44 | //RunAsync creates new async block, which will run given one
45 | //on executor's context. Whol block can be awaited synchronously
46 | //with Async.RunSynchronously or asynchronously, with Async.StartImmediate.
47 | exec.MakeAsync(async {
48 | printfn "Running on executor: %s" (Executor.GetCurrentName())
49 |
50 | let! repos = GetRepositories "Ravadre"
51 |
52 | printfn "Still running on executor: %s" (Executor.GetCurrentName())
53 | printfn ""
54 | printfn "Repositories:"
55 | printfn "%s" (System.String.Join(", ", repos))
56 |
57 | let! stargazers = repos
58 | |> Seq.map(fun r -> GetStargazers "Ravadre" r)
59 | |> Async.Parallel
60 |
61 | let stargazers = stargazers
62 | |> Array.collect id
63 | |> Set.ofArray
64 |
65 | printfn ""
66 | printfn "Still running on executor: %s" (Executor.GetCurrentName())
67 | printfn ""
68 | printfn "Stargazers:"
69 | printfn "%s" (System.String.Join(", ", stargazers))
70 | })
71 | |> Async.RunSynchronously
72 |
73 | 0
74 |
--------------------------------------------------------------------------------
/Examples/ActorFSharpSample3/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Examples/ActorSample1/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Examples/ActorSample1/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Stacks;
7 | using Stacks.Actors;
8 |
9 | namespace ActorSample1
10 | {
11 | class Program
12 | {
13 | static void Main(string[] args)
14 | {
15 | var formatter = ActorSystem.Default.CreateActor();
16 | var helloPrinter = new Hello(formatter);
17 |
18 | helloPrinter.SayHelloToFriends(new[] { "Stan", "Scott", "John" });
19 | }
20 | }
21 |
22 | class Hello
23 | {
24 | private readonly IFormatter formatter;
25 |
26 | public Hello(IFormatter formatter)
27 | {
28 | this.formatter = formatter;
29 | }
30 |
31 | public void SayHelloToFriends(IEnumerable names)
32 | {
33 | foreach (var name in names)
34 | {
35 | Console.WriteLine(formatter.SayHello(name).Result);
36 | }
37 | }
38 | }
39 |
40 | public interface IFormatter
41 | {
42 | Task SayHello(string name);
43 | }
44 |
45 | //One of the ways of defining an actor is to
46 | //inherit from Actor class
47 | class Formatter : Actor, IFormatter
48 | {
49 | //Because every call has to be scheduled on
50 | //actor's context, answer will not be ready instantly,
51 | //so Task is returned.
52 | public async Task SayHello(string name)
53 | {
54 | //Code after this await will be run
55 | //on actor's context.
56 | await Context;
57 |
58 | //When an actor wants to reply to request, it just
59 | //has to return the response.
60 | return "Hello " + name + "!";
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Examples/ActorSample1/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("ActorSample1")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("ActorSample1")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("a0f5a804-763c-4dc9-8efb-da0750f547b8")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Examples/ActorSample1/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Examples/ActorSample2/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Examples/ActorSample2/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Stacks.Actors;
7 | using System.Net.Http;
8 | using System.Xml.Linq;
9 |
10 | namespace ActorSample2
11 | {
12 | class Program
13 | {
14 | static void Main(string[] args)
15 | {
16 | var weather = ActorSystem.Default.CreateActor();
17 |
18 | try
19 | {
20 | var temp = weather.GetTemperature("Warsaw").Result;
21 | Console.WriteLine("Temperature in Warsaw, Poland: " +
22 | temp.ToString("F2") +
23 | "\u00B0C");
24 | }
25 | catch (Exception)
26 | {
27 | Console.WriteLine("Could not get temperature for Warsaw, Poland");
28 | }
29 | }
30 | }
31 |
32 | interface IWeather
33 | {
34 | Task GetTemperature(string city);
35 | }
36 |
37 | class Weather : Actor, IWeather
38 | {
39 | //Actor can also be implemented by defining context
40 | //private ActorContext actor = new ActorContext();
41 | private HttpClient httpClient = new HttpClient();
42 |
43 | public async Task GetTemperature(string city)
44 | {
45 | await Context;
46 |
47 | //Other actors or services can be awaited, execution will be resumed
48 | //on actor context automatically.
49 | var data = await httpClient.GetStringAsync(
50 | string.Format("http://api.openweathermap.org/data/2.5/" +
51 | "weather?q={0}&mode=xml&units=metric",
52 | city));
53 |
54 | return (double)XDocument.Parse(data)
55 | .Element("current")
56 | .Element("temperature")
57 | .Attribute("value");
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Examples/ActorSample2/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("ActorSample2")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("ActorSample2")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("cda5c838-94ea-4479-8238-8c5e501e1b58")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Examples/ActorSample2/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Examples/PingPong/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Examples/PingPong/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Stacks;
8 | using System.Reactive.Linq;
9 | using Stacks.Tcp;
10 |
11 | namespace PingPong
12 | {
13 | class Program
14 | {
15 | static IFramedClient client;
16 | static IFramedClient serverClient;
17 | static Encoding encoding;
18 |
19 | static void Main(string[] args)
20 | {
21 | encoding = Encoding.ASCII;
22 | SocketServer server;
23 | server = new SocketServer(new IPEndPoint(IPAddress.Loopback, 0));
24 |
25 | server.Connected.Subscribe(c =>
26 | {
27 | serverClient = new FramedClient(c);
28 |
29 | // When received is called, bs will contain no more and no less
30 | // data than whole packet as sent from client.
31 | serverClient.Received.Subscribe(bs =>
32 | {
33 | var msg = encoding.GetString(bs.Array, bs.Offset, bs.Count);
34 | msg = "Hello, " + msg + "!";
35 | serverClient.SendPacket(encoding.GetBytes(msg));
36 | });
37 | });
38 |
39 | server.Start();
40 | HandleClient(server.BindEndPoint.Port);
41 |
42 | Console.WriteLine("Press any key to stop...");
43 | Console.ReadKey();
44 |
45 | server.Stop();
46 | client.Close();
47 | serverClient.Close();
48 | }
49 |
50 | static async void HandleClient(int serverPort)
51 | {
52 | client = new FramedClient(
53 | new SocketClient());
54 |
55 | client.Received.Subscribe(bs =>
56 | {
57 | Console.WriteLine("Received: " +
58 | encoding.GetString(bs.Array, bs.Offset, bs.Count));
59 | });
60 |
61 | await client.Connect(new IPEndPoint(IPAddress.Loopback, serverPort));
62 | client.SendPacket(encoding.GetBytes("Steve"));
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Examples/PingPong/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("PingPong")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("PingPong")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("2834c464-bd71-418a-8d81-2144daa5f105")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Examples/PingPong/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Examples/ProtobufSample/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/Examples/ProtobufSample/Client.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Stacks.Tcp;
7 | using Stacks;
8 | using System.Net;
9 |
10 | namespace ProtobufSample
11 | {
12 | public class Client
13 | {
14 | MessageClient client;
15 |
16 | public Client()
17 | {
18 |
19 | }
20 |
21 | public void Run(int serverPort)
22 | {
23 | client = new MessageClient(
24 | new FramedClient(new SocketClient(useIPv6: true)),
25 | new ProtoBufStacksSerializer(),
26 | new ClientMessageHandler());
27 |
28 | client.PreLoadTypesFromAssemblyOfType();
29 |
30 | client.Connect(new IPEndPoint(IPAddress.IPv6Loopback, serverPort))
31 | .Subscribe(_ =>
32 | {
33 | Console.WriteLine("Querying for temperature in London, Warsaw, Madrid");
34 | client.Send(new TemperatureRequest { City = "London" });
35 | client.Send(new TemperatureRequest { City = "Warsaw" });
36 | client.Send(new TemperatureRequest { City = "Madrid" });
37 | });
38 | }
39 | }
40 |
41 | public class ClientMessageHandler : IMessageHandler
42 | {
43 | public void HandleTemperatureResponse(IMessageClient client, TemperatureResponse response)
44 | {
45 | Console.WriteLine("Received temperature response: " +
46 | response.City + " = " + response.Temperature.ToString("F2") + "\u00b0C");
47 | }
48 |
49 | public void HandleTemperatureChanged(IMessageClient client, TemperatureChanged tempChanged)
50 | {
51 | Console.WriteLine("Temperature changed: " +
52 | tempChanged.City + " = " + tempChanged.Temperature.ToString("F2") + "\u00b0C");
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Examples/ProtobufSample/Data.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using ProtoBuf;
7 | using Stacks;
8 |
9 | namespace ProtobufSample
10 | {
11 | [ProtoContract]
12 | [StacksMessage(3)]
13 | public class TemperatureChanged
14 | {
15 | [ProtoMember(1)]
16 | public string City { get; set; }
17 | [ProtoMember(2)]
18 | public double Temperature { get; set; }
19 | }
20 |
21 | [ProtoContract]
22 | [StacksMessage(1)]
23 | public class TemperatureRequest
24 | {
25 | [ProtoMember(1)]
26 | public string City { get; set; }
27 | }
28 |
29 | [ProtoContract]
30 | [StacksMessage(2)]
31 | public class TemperatureResponse
32 | {
33 | [ProtoMember(1)]
34 | public string City { get; set; }
35 | [ProtoMember(2)]
36 | public double Temperature { get; set; }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Examples/ProtobufSample/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ProtobufSample
8 | {
9 | class Program
10 | {
11 | static void Main(string[] args)
12 | {
13 | Server s = new Server();
14 | Client c = new Client();
15 | s.Run();
16 | c.Run(s.ServerPort);
17 |
18 | Console.WriteLine("Press any key to exit");
19 | Console.ReadKey();
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/ProtobufSample/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("ProtobufSample")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("ProtobufSample")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("0be6e15d-3d02-4c25-bba6-bbe57bea01db")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Examples/ProtobufSample/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Examples/ReactiveSample/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Examples/ReactiveSample/Client.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Reactive.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using Stacks;
9 | using Stacks.Tcp;
10 |
11 | namespace ReactiveSample
12 | {
13 | public class Client
14 | {
15 | ReactiveMessageClient client;
16 | IDisposable priceObserver;
17 |
18 | public Client()
19 | {
20 |
21 | }
22 |
23 | public void Run(int serverPort)
24 | {
25 | client = new ReactiveMessageClient(
26 | new FramedClient(new SocketClient()),
27 | new ProtoBufStacksSerializer());
28 |
29 | client.PreLoadTypesFromAssemblyOfType();
30 |
31 | priceObserver = client.Packets.Price.Subscribe(p =>
32 | {
33 | Console.WriteLine("Price received: {0} - {1:F5} / {2:F5}",
34 | p.Symbol, p.Bid, p.Offer);
35 | });
36 |
37 | client.Connect(new IPEndPoint(IPAddress.Loopback, serverPort))
38 | .Subscribe(async _ =>
39 | {
40 | await Task.Delay(2000);
41 | client.Send(new RegisterSymbolRequest() { Symbol = "EURUSD", Register = true });
42 | client.Send(new RegisterSymbolRequest() { Symbol = "GBPLN", Register = true });
43 | });
44 |
45 | }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/Examples/ReactiveSample/Data.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using ProtoBuf;
7 | using Stacks;
8 |
9 | namespace ReactiveSample
10 | {
11 | [ProtoContract]
12 | [StacksMessage(1)]
13 | public class RegisterSymbolRequest
14 | {
15 | [ProtoMember(1)]
16 | public string Symbol { get; set; }
17 | [ProtoMember(2)]
18 | public bool Register { get; set; }
19 | }
20 |
21 | [ProtoContract]
22 | [StacksMessage(2)]
23 | public class Price
24 | {
25 | [ProtoMember(1)]
26 | public string Symbol { get; set; }
27 | [ProtoMember(2)]
28 | public double Bid { get; set; }
29 | [ProtoMember(3)]
30 | public double Offer { get; set; }
31 | }
32 |
33 | public interface IServerPacketHandler
34 | {
35 | IObservable RegisterSymbol { get; }
36 | }
37 |
38 | public interface IClientPacketHandler
39 | {
40 | IObservable Price { get; }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/Examples/ReactiveSample/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ReactiveSample
8 | {
9 | class Program
10 | {
11 | static void Main(string[] args)
12 | {
13 | Server s = new Server();
14 | Client c = new Client();
15 | s.Run();
16 | c.Run(s.ServerPort);
17 |
18 | Console.WriteLine("Press any key to exit");
19 | Console.ReadKey();
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Examples/ReactiveSample/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("ReactiveSample")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("ReactiveSample")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("ee378fa7-9fc7-4d5b-9ba2-9927ceed87e7")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Examples/ReactiveSample/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/Examples/RemoteActorsSample/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/Examples/RemoteActorsSample/Client.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using ProtoBuf;
7 | using Stacks.Actors;
8 |
9 | namespace RemoteActorsSample
10 | {
11 | [ProtoContract]
12 | public class Rectangle
13 | {
14 | [ProtoMember(1)]
15 | public double A { get; set; }
16 | [ProtoMember(2)]
17 | public double B { get; set; }
18 | }
19 |
20 | [ProtoContract]
21 | public class RectangleInfo
22 | {
23 | [ProtoMember(1)]
24 | public double Field { get; set; }
25 | [ProtoMember(2)]
26 | public double Perimeter { get; set; }
27 | }
28 |
29 | [ProtoContract]
30 | public class Message
31 | {
32 | [ProtoMember(1)]
33 | public long X { get; set; }
34 | [ProtoMember(2)]
35 | public long Y { get; set; }
36 | [ProtoMember(3)]
37 | public RectangleInfo Info { get; set; }
38 | }
39 |
40 | public interface ICalculatorActor
41 | {
42 | Task Add(double x, double y);
43 | Task Subtract(double x, double y);
44 | Task Increment(int x);
45 |
46 | Task CalculateRectangle(Rectangle rect);
47 |
48 | Task PushNumber(double x);
49 | Task PopNumber();
50 | Task Ping();
51 |
52 | Task Mean(double[] xs);
53 | Task MeanEnum(IEnumerable xs);
54 |
55 | Task PingAsync();
56 |
57 | IObservable Rng { get; }
58 | IObservable Messages { get; }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/Examples/RemoteActorsSample/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("RemoteActorsSample")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("RemoteActorsSample")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("34b947e5-e731-4f9e-9714-02525dfeef78")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Examples/RemoteActorsSample/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2014 Marcin Deptuła
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/PerfTests/Actors/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/PerfTests/Actors/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Actors")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Actors")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("17318eaa-3a5d-4c13-a4ca-fa7078db9607")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/PerfTests/Actors/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/PerfTests/Executors/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/PerfTests/Executors/Benchmark.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Executors
9 | {
10 | public class Benchmark
11 | {
12 | public static BenchmarkStats Measure(Action action, int timesToRepeat)
13 | {
14 | var times = new List();
15 | var sw = new Stopwatch();
16 |
17 | for (int i = 0; i < timesToRepeat; ++i)
18 | {
19 | GC.Collect(); GC.Collect();
20 |
21 | sw.Restart();
22 | action();
23 | sw.Stop();
24 |
25 | if (i > 0)
26 | times.Add(sw.Elapsed);
27 | }
28 |
29 | return new BenchmarkStats(times);
30 | }
31 | }
32 |
33 | public class BenchmarkStats
34 | {
35 | public IReadOnlyList Times { get; private set; }
36 | public TimeSpan TotalAverageTime { get; private set; }
37 |
38 | public BenchmarkStats(IEnumerable times)
39 | {
40 | Times = times.ToList();
41 | TotalAverageTime = TimeSpan.FromSeconds(Times.Average(t => t.TotalSeconds));
42 | }
43 |
44 | public long GetAverateTimePerActionNs(int actionCount)
45 | {
46 | return TotalAverageTime.Ticks * 1000000L / TimeSpan.TicksPerMillisecond / actionCount;
47 | }
48 |
49 | public override string ToString()
50 | {
51 | return TotalAverageTime.TotalSeconds.ToString("F4") + "s";
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/PerfTests/Executors/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Stacks;
7 |
8 | namespace Executors
9 | {
10 | class Program
11 | {
12 | static void Main(string[] args)
13 | {
14 | RunSingleExecutor();
15 |
16 | Console.ReadLine();
17 | }
18 |
19 | static void RunSingleExecutor()
20 | {
21 | var test = new SingleExecutor(1000000, () => new ActionBlockExecutor());
22 | var stats = Benchmark.Measure(test.Run, 5);
23 |
24 | Console.WriteLine("Action block (ctx) executor: " + stats);
25 | Console.WriteLine("Action block (ctx) time per msg: " + stats.GetAverateTimePerActionNs(1000000).ToString() + "ns");
26 |
27 | test = new SingleExecutor(1000000, () => new ActionBlockExecutor(new ActionBlockExecutorSettings() { SupportSynchronizationContext = false }));
28 | stats = Benchmark.Measure(test.Run, 5);
29 |
30 | Console.WriteLine("Action block (no ctx) executor: " + stats);
31 | Console.WriteLine("Action block (no ctx) time per msg: " + stats.GetAverateTimePerActionNs(1000000).ToString() + "ns");
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/PerfTests/Executors/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Executors")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Executors")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("19836c5f-f70e-47fa-bed6-b5b617558cd4")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/PerfTests/Executors/SingleExecutor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Stacks;
7 |
8 | namespace Executors
9 | {
10 | class SingleExecutor
11 | {
12 | private int messageCount;
13 | private Func execFactory;
14 |
15 | public SingleExecutor(int messageCount, Func execFactory)
16 | {
17 | this.messageCount = messageCount;
18 | this.execFactory = execFactory;
19 | }
20 |
21 | public void Run()
22 | {
23 | var ex1 = execFactory();
24 |
25 | var counter = 0L;
26 |
27 | for (int i = 0; i < messageCount; ++i)
28 | ex1.Enqueue(() => ++counter);
29 |
30 | ex1.Stop().Wait();
31 |
32 | if (counter != messageCount)
33 | throw new Exception("Invalid result");
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/PerfTests/Executors/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/PerfTests/PingPong/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/PerfTests/PingPong/PingPong.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {E46A1856-8BC9-4EB2-8B04-5E290872B211}
8 | Exe
9 | Properties
10 | PingPong
11 | PingPong
12 | v4.5
13 | 512
14 |
15 |
16 | AnyCPU
17 | true
18 | full
19 | false
20 | bin\Debug\
21 | DEBUG;TRACE
22 | prompt
23 | 4
24 |
25 |
26 | AnyCPU
27 | pdbonly
28 | true
29 | bin\Release\
30 | TRACE
31 | prompt
32 | 4
33 | false
34 |
35 |
36 |
37 |
38 |
39 |
40 | ..\..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll
41 |
42 |
43 | ..\..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll
44 |
45 |
46 | ..\..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll
47 |
48 |
49 | ..\..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 | {733e7987-f63e-4057-8454-f601c87e934b}
68 | Stacks.Actors
69 |
70 |
71 | {9e0d5c52-ad78-4a5e-82ad-289d272a111d}
72 | Stacks
73 |
74 |
75 |
76 |
83 |
--------------------------------------------------------------------------------
/PerfTests/PingPong/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("PingPong")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("PingPong")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("b559385e-a43f-4f3a-885e-18dea127559b")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/PerfTests/PingPong/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/PerfTests/SimpleThroughput/FramedPerfTest/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/PerfTests/SimpleThroughput/FramedPerfTest/Program.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.Linq;
5 | using System.Reactive.Linq;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using Stacks;
10 | using Stacks.Tcp;
11 | using Stacks.Tests;
12 |
13 | namespace RawStreamPerfTest
14 | {
15 | class Program
16 | {
17 | static SocketServer s;
18 | static SocketClient c1, c2;
19 | static IFramedClient fc1, fc2;
20 |
21 | static void Main(string[] args)
22 | {
23 | ServerHelpers.CreateServerAndConnectedClient(out s, out c1, out c2);
24 |
25 | c1.Disconnected.Subscribe(exn => { Console.WriteLine("C1 d/c " + exn); });
26 | c2.Disconnected.Subscribe(exn => { Console.WriteLine("C2 d/c " + exn); });
27 |
28 | fc1 = new FramedClient(c1);
29 | fc2 = new FramedClient(c2);
30 |
31 | Measure(8192, 8192);
32 | Console.ReadLine();
33 | Measure(8192, 8192 * 64);
34 |
35 | Console.ReadLine();
36 | }
37 |
38 | private static void Measure(int bufSize, int packets)
39 | {
40 | var buffer = DataHelpers.CreateRandomBuffer(bufSize);
41 | long l = packets;
42 | long totalRecv = 0;
43 | long totalPacketsRecv = 0;
44 | var received = new ManualResetEventSlim();
45 |
46 | GC.Collect();
47 | Console.WriteLine("Gen 0: " + GC.CollectionCount(0) +
48 | ", Gen 1: " + GC.CollectionCount(1) + ", Gen 2: " +
49 | GC.CollectionCount(2));
50 | var sw = Stopwatch.StartNew();
51 |
52 | Action> recv = bs =>
53 | {
54 | totalRecv += bs.Count;
55 | ++totalPacketsRecv;
56 | if (totalPacketsRecv == packets) received.Set();
57 | };
58 |
59 | var recvSub = fc2.Received.Subscribe(recv);
60 |
61 | for (int i = 0; i < l; ++i)
62 | {
63 | fc1.SendPacket(buffer);
64 | }
65 |
66 | received.Wait();
67 |
68 | recvSub.Dispose();
69 |
70 | var elapsed = sw.Elapsed.TotalSeconds;
71 | GC.Collect();
72 | Console.WriteLine("Gen 0: " + GC.CollectionCount(0) +
73 | ", Gen 1: " + GC.CollectionCount(1) + ", Gen 2: " +
74 | GC.CollectionCount(2));
75 |
76 | Console.WriteLine("Elapsed s: " + elapsed);
77 | Console.WriteLine("Rate: " + (double)totalRecv * 8 / elapsed / 1024 / 1024 + " Mb/sec");
78 | Console.WriteLine("Sent {0} packets. Received: {1}", packets, totalPacketsRecv);
79 | Console.WriteLine($"Rate: {(int)(packets / elapsed)} packets/sec");
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/PerfTests/SimpleThroughput/FramedPerfTest/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("FramedPerfTest")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("FramedPerfTest")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("170382ca-62be-4e7a-9a8f-a47be27b483c")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/PerfTests/SimpleThroughput/FramedPerfTest/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/PerfTests/SimpleThroughput/RawStreamManyClients/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/PerfTests/SimpleThroughput/RawStreamManyClients/Program.cs:
--------------------------------------------------------------------------------
1 | using Stacks;
2 | using Stacks.Tests;
3 | using System;
4 | using System.CodeDom;
5 | using System.Collections.Generic;
6 | using System.Diagnostics;
7 | using System.Linq;
8 | using System.Text;
9 | using System.Threading;
10 | using System.Reactive.Linq;
11 | using System.Threading.Tasks;
12 | using Stacks.Tcp;
13 |
14 | namespace RawStreamPerfTest
15 | {
16 | class Program
17 | {
18 | static SocketServer s;
19 | private static SocketClient[] clients;
20 | private static SocketClient[] sClients;
21 |
22 | static void Main(string[] args)
23 | {
24 | var ex = new ActionBlockExecutor();
25 | clients = new SocketClient[1000];
26 | sClients = new SocketClient[1000];
27 | int sIdx = 0;
28 | var server = ServerHelpers.CreateServer();
29 | server.Start();
30 | server.Started.Wait();
31 |
32 | server.Connected.Subscribe(c =>
33 | {
34 | sClients[Interlocked.Increment(ref sIdx) - 1] = c;
35 | });
36 |
37 | var allConnected = new ManualResetEventSlim();
38 | var connectedCount = 0;
39 | for (var i = 0; i < clients.Length; ++i)
40 | {
41 | clients[i] = new SocketClient(ex);
42 | clients[i].Connected.Subscribe(_ =>
43 | {
44 | if (Interlocked.Increment(ref connectedCount) == 1000)
45 | allConnected.Set();
46 | });
47 | clients[i].Disconnected.Subscribe(exn =>
48 | {
49 | Console.WriteLine("Could not connect: " + exn);
50 | });
51 | clients[i].Connect("tcp://localhost:" + server.BindEndPoint.Port);
52 | }
53 |
54 | allConnected.Wait();
55 |
56 | Measure(8192, 10);
57 | Console.ReadLine();
58 | Measure(8192, 10 * 16);
59 |
60 | Console.ReadLine();
61 | }
62 |
63 | private static void Measure(int bufSize, int packets)
64 | {
65 | var buffer = DataHelpers.CreateRandomBuffer(bufSize);
66 | long l = packets;
67 | long totalRecv = 0;
68 | var received = new ManualResetEventSlim();
69 |
70 | GC.Collect();
71 | Console.WriteLine("Gen 0: " + GC.CollectionCount(0) +
72 | ", Gen 1: " + GC.CollectionCount(1) + ", Gen 2: " +
73 | GC.CollectionCount(2));
74 |
75 | Action> recv = bs =>
76 | {
77 | Interlocked.Add(ref totalRecv, bs.Count);
78 | //totalRecv += bs.Count;
79 | if (totalRecv == sClients.Length * l * bufSize) received.Set();
80 | };
81 |
82 | for (var i = 0; i < sClients.Length; ++i)
83 | {
84 | sClients[i].Received.Subscribe(recv);
85 | }
86 |
87 | var sw = Stopwatch.StartNew();
88 | for (int i = 0; i < clients.Length; ++i)
89 | {
90 | for (int p = 0; p < packets; ++p)
91 | {
92 | clients[i].Send(buffer);
93 | }
94 | }
95 |
96 | received.Wait();
97 |
98 | var elapsed = sw.Elapsed.TotalSeconds;
99 | GC.Collect();
100 | Console.WriteLine("Gen 0: " + GC.CollectionCount(0) +
101 | ", Gen 1: " + GC.CollectionCount(1) + ", Gen 2: " +
102 | GC.CollectionCount(2));
103 |
104 | Console.WriteLine("Elapsed s: " + elapsed);
105 | Console.WriteLine("Rate: " + (double)totalRecv * 8 / elapsed / 1024 / 1024 + " Mb/sec");
106 | }
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/PerfTests/SimpleThroughput/RawStreamManyClients/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("RawStreamManyClients")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("RawStreamManyClients")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("3582fb47-6715-44c6-9bdb-6bd863056a9f")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/PerfTests/SimpleThroughput/RawStreamManyClients/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/PerfTests/SimpleThroughput/RawStreamPerfTest/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/PerfTests/SimpleThroughput/RawStreamPerfTest/Program.cs:
--------------------------------------------------------------------------------
1 | using Stacks;
2 | using Stacks.Tests;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Diagnostics;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading;
9 | using System.Reactive.Linq;
10 | using System.Threading.Tasks;
11 | using Stacks.Tcp;
12 |
13 | namespace RawStreamPerfTest
14 | {
15 | class Program
16 | {
17 | static SocketServer s;
18 | static SocketClient c1, c2;
19 |
20 | static void Main(string[] args)
21 | {
22 |
23 | ServerHelpers.CreateServerAndConnectedClient(out s, out c1, out c2);
24 |
25 | c1.Disconnected.Subscribe(exn => { Console.WriteLine("C1 d/c " + exn); });
26 | c2.Disconnected.Subscribe(exn => { Console.WriteLine("C2 d/c " + exn); });
27 |
28 | Measure(8192, 81920);
29 | Console.ReadLine();
30 | Measure(8192, 81920 * 16);
31 |
32 | Console.ReadLine();
33 | }
34 |
35 | private static void Measure(int bufSize, int packets)
36 | {
37 | var buffer = DataHelpers.CreateRandomBuffer(bufSize);
38 | long l = packets;
39 | long totalRecv = 0;
40 | var received = new ManualResetEventSlim();
41 |
42 | GC.Collect();
43 | Console.WriteLine("Gen 0: " + GC.CollectionCount(0) +
44 | ", Gen 1: " + GC.CollectionCount(1) + ", Gen 2: " +
45 | GC.CollectionCount(2));
46 | var sw = Stopwatch.StartNew();
47 |
48 | Action> recv = bs =>
49 | {
50 | totalRecv += bs.Count;
51 | if (totalRecv == l * bufSize) received.Set();
52 | };
53 |
54 | var recvHandle = c2.Received.Subscribe(recv);
55 |
56 |
57 | for (int i = 0; i < l; ++i)
58 | {
59 | c1.Send(buffer);
60 | }
61 |
62 | received.Wait();
63 |
64 | recvHandle.Dispose();
65 |
66 | var elapsed = sw.Elapsed.TotalSeconds;
67 | GC.Collect();
68 | Console.WriteLine("Gen 0: " + GC.CollectionCount(0) +
69 | ", Gen 1: " + GC.CollectionCount(1) + ", Gen 2: " +
70 | GC.CollectionCount(2));
71 |
72 | Console.WriteLine("Elapsed s: " + elapsed);
73 | Console.WriteLine("Rate: " + (double)totalRecv * 8 / elapsed / 1024 / 1024 + " Mb/sec");
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/PerfTests/SimpleThroughput/RawStreamPerfTest/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("RawStreamPerfTest")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("RawStreamPerfTest")]
13 | [assembly: AssemblyCopyright("Copyright © 2014")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("9d0677a5-f933-4f46-b5b8-09f8764cb85a")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/PerfTests/SimpleThroughput/RawStreamPerfTest/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/SharedAssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | [assembly: AssemblyCompany("Marcin Deptuła")]
6 | [assembly: AssemblyCopyright("Copyright © Marcin Deptuła 2014-2016")]
7 | [assembly: AssemblyTrademark("")]
8 | [assembly: AssemblyCulture("")]
9 |
10 | [assembly: ComVisible(false)]
11 |
12 | [assembly: AssemblyVersion("2.1.1")]
13 | [assembly: AssemblyFileVersion("2.1.1")]
14 |
--------------------------------------------------------------------------------
/SharedAssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace Stacks.FSharp
2 |
3 | open System.Reflection
4 | open System.Runtime.CompilerServices
5 | open System.Runtime.InteropServices
6 |
7 | []
8 | []
9 | []
10 | []
11 |
12 | []
13 |
14 | []
15 | []
16 | do()
17 |
--------------------------------------------------------------------------------
/Stacks.Actors.DI.Windsor/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | [assembly: AssemblyTitle("Stacks.DI.Windsor")]
6 | [assembly: AssemblyDescription("Castle Windsor support for Stacks")]
7 | [assembly: AssemblyConfiguration("")]
8 | [assembly: AssemblyProduct("Stacks.DI.Windsor")]
9 |
10 |
11 | [assembly: Guid("D27D7D04-A865-4D3E-B605-15AEE777E373")]
12 |
--------------------------------------------------------------------------------
/Stacks.Actors.DI.Windsor/Stacks.Actors.DI.Windsor.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Stacks.Actors.DI.Windsor
5 | Stacks Actors DI Windsor
6 | @build.number@
7 | Marcin Deptuła
8 | Marcin Deptuła
9 | Castle Windsor DI support for Stacks
10 | https://raw.githubusercontent.com/Ravadre/Stacks/master/LICENSE
11 | https://github.com/Ravadre/Stacks
12 | false
13 | Castle Windsor DI support for Stacks
14 | Copyright Marcin Deptuła
15 | C# Socket Network Actor Reactive CastleWindsor
16 | @dependencies@
17 |
18 |
--------------------------------------------------------------------------------
/Stacks.Actors.DI.Windsor/WindsorDependencyResolver.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Runtime.Remoting.Messaging;
5 | using Castle.MicroKernel.ModelBuilder.Descriptors;
6 | using Castle.MicroKernel.Registration;
7 | using Castle.Windsor;
8 |
9 | namespace Stacks.Actors.DI.Windsor
10 | {
11 | public class WindsorDependencyResolver : IDependencyResolver
12 | {
13 | private readonly ActorSystem actorSystem;
14 | private readonly IWindsorContainer container;
15 |
16 | public WindsorDependencyResolver(ActorSystem actorSystem, IWindsorContainer container)
17 | {
18 | if (container == null)
19 | throw new ArgumentNullException(nameof(container));
20 |
21 | this.actorSystem = actorSystem;
22 | this.container = container;
23 | }
24 |
25 | IDictionary GetArgs(IDictionary arguments)
26 | {
27 | if (arguments == null)
28 | return null;
29 |
30 | var args = arguments as IDictionary;
31 |
32 | if (args != null)
33 | {
34 | return args;
35 | }
36 | else
37 | {
38 | var dic = new Dictionary(arguments);
39 | return dic;
40 | }
41 | }
42 |
43 | public void Register()
44 | where I: class
45 | where TImpl: I
46 | {
47 | container.Register(
48 | Component.For().UsingFactoryMethod(
49 | (kernel, model, ctx) =>
50 | {
51 | return actorSystem.CreateActor(() => kernel.Resolve("$Stacks$Internal$Registration$" + typeof(TImpl).FullName, ctx.AdditionalArguments), null, null);
52 | }),
53 | Component.For().ImplementedBy().Named("$Stacks$Internal$Registration$" + typeof(TImpl).FullName)
54 | );
55 | }
56 |
57 | public void RegisterTransient()
58 | where I : class
59 | where TImpl : I
60 | {
61 | container.Register(
62 | Component.For().UsingFactoryMethod(
63 | (kernel, model, ctx) =>
64 | {
65 | return actorSystem.CreateActor(() => kernel.Resolve("$Stacks$Internal$Registration$" + typeof(TImpl).FullName, ctx.AdditionalArguments), null, null);
66 | }).LifestyleTransient(),
67 | Component.For().ImplementedBy().Named("$Stacks$Internal$Registration$" + typeof(TImpl).FullName).LifestyleTransient()
68 | );
69 | }
70 |
71 | public T Resolve(string resolverKey, IDictionary arguments)
72 | {
73 | if (resolverKey == null)
74 | {
75 | return container.Resolve(GetArgs(arguments));
76 | }
77 | else
78 | {
79 | return container.Resolve(resolverKey, GetArgs(arguments));
80 | }
81 | }
82 |
83 | public void Release(T actor)
84 | {
85 | container.Release(actor);
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/Stacks.Actors.DI.Windsor/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Stacks.Actors.Tests.DI.Windsor/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Stacks.Tests.DI.Windsor")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Stacks.Tests.DI.Windsor")]
13 | [assembly: AssemblyCopyright("Copyright © 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("f5ba1de4-d376-4fdd-8dab-d7c3a8673307")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Stacks.Actors.Tests.DI.Windsor/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Stacks.Actors.Tests/ActorSystemTests/TestActors.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Linq;
3 | using System.Reactive.Linq;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 | using Stacks.Actors;
7 |
8 | namespace Stacks.Tests.ActorSystemTests
9 | {
10 |
11 | public interface ICalculatorActor : IActor
12 | {
13 | Task Div(double x, double y);
14 | }
15 |
16 | public interface ICalculatorExActor : IActor
17 | {
18 | Task Div(double x, double y);
19 | Task AddThenStop(double x, double y);
20 | Task Throw(string msg);
21 | Task Complicated(double x, double y);
22 | Task ComplicatedThenThrow(double x, double y);
23 | Task NoOp();
24 | }
25 |
26 | public interface ISingleMethodActor
27 | {
28 | Task Test();
29 | }
30 |
31 | public interface IExplicitInterfaceActor
32 | {
33 | Task Sum(double[] xs);
34 | IObservable Counter { get; }
35 | }
36 |
37 | public class ExplicitInterfaceActor : Actor, IExplicitInterfaceActor
38 | {
39 | IObservable IExplicitInterfaceActor.Counter
40 | {
41 | get { return Observable.Timer(TimeSpan.Zero, TimeSpan.FromSeconds(0.1)).Select(l => (double)l); }
42 | }
43 |
44 | async Task IExplicitInterfaceActor.Sum(double[] xs)
45 | {
46 | await Context;
47 | return xs.Sum();
48 | }
49 | }
50 |
51 | public class SingleMethodActor : Actor, ISingleMethodActor
52 | {
53 | public async Task Test()
54 | {
55 | await Context;
56 |
57 | return 5;
58 | }
59 | }
60 |
61 | public class CalculatorActor : Actor, ICalculatorActor
62 | {
63 | public async Task Div(double x, double y)
64 | {
65 | await Context;
66 |
67 | await Task.Delay(50);
68 |
69 | if (y == 0.0)
70 | throw new DivideByZeroException();
71 |
72 | return x / y;
73 | }
74 | }
75 |
76 | public class ActorWithExtraMethod : Actor, ICalculatorActor
77 | {
78 | public async Task Div(double x, double y)
79 | {
80 | await Context;
81 | return 5.0 + TestMethod();
82 | }
83 |
84 | public int TestMethod()
85 | {
86 | return 10;
87 | }
88 | }
89 |
90 | public class LongStopActor : Actor, ICalculatorActor
91 | {
92 | public async Task Div(double x, double y)
93 | {
94 | await Context;
95 | return 5;
96 | }
97 |
98 | protected override void OnStopped()
99 | {
100 | Thread.Sleep(1000);
101 | }
102 | }
103 | }
--------------------------------------------------------------------------------
/Stacks.Actors.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("Stacks.Actors.Tests")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("Stacks.Actors.Tests")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Setting ComVisible to false makes the types in this assembly not visible
18 | // to COM components. If you need to access a type in this assembly from
19 | // COM, set the ComVisible attribute to true on that type.
20 | [assembly: ComVisible(false)]
21 |
22 | // The following GUID is for the ID of the typelib if this project is exposed to COM
23 | [assembly: Guid("d07f335b-433e-4fbd-81ae-b98baae7144d")]
24 |
25 | // Version information for an assembly consists of the following four values:
26 | //
27 | // Major Version
28 | // Minor Version
29 | // Build Number
30 | // Revision
31 | //
32 | // You can specify all the values or you can default the Build and Revision Numbers
33 | // by using the '*' as shown below:
34 | // [assembly: AssemblyVersion("1.0.*")]
35 | [assembly: AssemblyVersion("1.0.0.0")]
36 | [assembly: AssemblyFileVersion("1.0.0.0")]
37 |
--------------------------------------------------------------------------------
/Stacks.Actors.Tests/Remote/ActorSessionTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Stacks.Actors;
7 | using Xunit;
8 |
9 | namespace Stacks.Tests.Remote
10 | {
11 | public class ActorSessionTests
12 | {
13 | private IActorServerProxy server;
14 | private IMessageActor client;
15 |
16 |
17 | [Fact]
18 | public async void If_Enabled_IActorSession_should_get_accessible_from_ActorSession_Current()
19 | {
20 | var opts = new ActorServerProxyOptions(actorSessionInjectionEnabled: true);
21 | Utils.CreateServerAndClient(opts, out server, out client);
22 |
23 | var client2 = ActorClientProxy.CreateActor("tcp://localhost:" + server.BindEndPoint.Port).Result;
24 |
25 | await client.PassDataForContext(1);
26 | await client.PassDataForContext(1);
27 | await client2.PassDataForContext(2);
28 | await client.PassDataForContext(1);
29 | await client2.PassDataForContext(2);
30 |
31 | }
32 |
33 | [Fact]
34 | public void If_Enabled_StressTest_IActorSession_should_get_accessible_from_ActorSession_Current()
35 | {
36 | var opts = new ActorServerProxyOptions(actorSessionInjectionEnabled: true);
37 | IMessageActor[] clients = new IMessageActor[20];
38 |
39 | Utils.CreateServerAndClient(opts, out server, out clients[0]);
40 |
41 | for (int i = 1; i < 20; ++i)
42 | clients[i] = ActorClientProxy.CreateActor("tcp://localhost:" + server.BindEndPoint.Port).Result;
43 |
44 | var tasks = new List();
45 |
46 | for (int i = 0; i < 100; ++i)
47 | {
48 | int idx = i % 20;
49 | tasks.Add(clients[idx].StressTestSession(idx));
50 | }
51 |
52 | Task.WaitAll(tasks.ToArray());
53 | }
54 |
55 | [Fact]
56 | public async void If_Not_Enabled_ActorSession_Current_should_be_null()
57 | {
58 | Utils.CreateServerAndClient(out server, out client);
59 |
60 | await client.AssertActorSessionIsNull();
61 | }
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/Stacks.Actors.Tests/Remote/ConnectionTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net.Sockets;
5 | using System.Text;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using Stacks.Actors;
9 | using Xunit;
10 |
11 | namespace Stacks.Tests.Remote
12 | {
13 | public class ConnectionTests
14 | {
15 | private IActorServerProxy server;
16 | private ITestActor client;
17 | private IActorClientProxy clientProxy;
18 |
19 | [Fact]
20 | public void Client_should_be_able_to_connect_to_server()
21 | {
22 | Utils.CreateServerAndClient(out server, out client);
23 | }
24 |
25 | [Fact]
26 | public void Client_and_server_should_be_able_to_close_without_errors()
27 | {
28 | Utils.CreateServerAndClient(out server, out client);
29 |
30 | server.Stop();
31 | // ReSharper disable once SuspiciousTypeConversion.Global
32 | ((IActorClientProxy)client).Close();
33 | }
34 |
35 | [Fact]
36 | public void Client_should_return_task_which_fails_if_it_could_not_connect_to_server()
37 | {
38 | var clientTask = ActorClientProxy.CreateProxy("tcp://localhost:" + Utils.FindFreePort());
39 |
40 | Assert.Throws(typeof(SocketException), () =>
41 | {
42 | try
43 | {
44 | clientTask.Wait();
45 | } catch (AggregateException exc)
46 | {
47 | throw exc.InnerException;
48 | }
49 | });
50 | }
51 |
52 | [Fact]
53 | public void Client_should_signal_disconnection_when_server_is_closed()
54 | {
55 | var disconnected = new ManualResetEventSlim();
56 | Utils.CreateServerAndClientProxy(out server, out clientProxy);
57 |
58 | clientProxy.Disconnected.Subscribe(exn => { disconnected.Set(); });
59 |
60 | server.Stop();
61 |
62 | disconnected.AssertWaitFor();
63 | }
64 | }
65 |
66 | public interface ITestActor
67 | {
68 | Task Ping();
69 | }
70 |
71 | public class TestActor : Actor, ITestActor
72 | {
73 | public async Task Ping()
74 | {
75 | await Context;
76 | }
77 |
78 | public void Close()
79 | {
80 | throw new NotImplementedException();
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/Stacks.Actors.Tests/Remote/Utils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Net.Sockets;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using Stacks.Actors;
9 | using Stacks.Actors.Remote;
10 |
11 | namespace Stacks.Tests.Remote
12 | {
13 | public static class Utils
14 | {
15 | public static void CreateServerAndClient(I impl, out IActorServerProxy server, out I client)
16 | {
17 | server = ActorServerProxy.Create("tcp://*:0", impl);
18 | int port = server.BindEndPoint.Port;
19 |
20 | client = ActorClientProxy.CreateActor("tcp://localhost:" + port).Result;
21 | }
22 |
23 | public static void CreateServerAndClient(out IActorServerProxy server, out I client)
24 | where T : Actor, I, new()
25 | {
26 | CreateServerAndClient(ActorServerProxyOptions.Default, out server, out client);
27 | }
28 |
29 | public static void CreateServerAndClient(ActorServerProxyOptions options, out IActorServerProxy server, out I client)
30 | where T: Actor, I, new()
31 | {
32 | server = ActorServerProxy.Create("tcp://*:0", options);
33 | int port = server.BindEndPoint.Port;
34 |
35 | client = ActorClientProxy.CreateActor("tcp://localhost:" + port).Result;
36 | }
37 |
38 | public static void CreateServerAndClient(ActorServerProxyOptions options, ActorClientProxyOptions cOptions,
39 | out IActorServerProxy server, out I client)
40 | where T : Actor, I, new()
41 | {
42 | server = ActorServerProxy.Create("tcp://*:0", options);
43 | int port = server.BindEndPoint.Port;
44 |
45 | client = ActorClientProxy.CreateActor("tcp://localhost:" + port, cOptions).Result;
46 | }
47 |
48 |
49 | public static void CreateServerAndClient(I impl, out IActorServerProxy server, out IActorClientProxy client)
50 | {
51 | server = ActorServerProxy.Create("tcp://*:0", impl);
52 | int port = server.BindEndPoint.Port;
53 |
54 | client = ActorClientProxy.CreateProxy("tcp://localhost:" + port).Result;
55 | }
56 |
57 | public static void CreateServerAndClientProxy(out IActorServerProxy server, out IActorClientProxy client)
58 | where T : Actor, I, new()
59 | {
60 | server = ActorServerProxy.Create("tcp://*:0");
61 | int port = server.BindEndPoint.Port;
62 |
63 | client = ActorClientProxy.CreateProxy("tcp://localhost:" + port).Result;
64 | }
65 |
66 | public static int FindFreePort()
67 | {
68 | TcpListener l = new TcpListener(new IPEndPoint(IPAddress.Any, 0));
69 | l.Start();
70 | int port = ((IPEndPoint)l.LocalEndpoint).Port;
71 | l.Stop();
72 | return port;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/Stacks.Actors.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Stacks.Actors/ActorContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Reactive;
3 | using System.Reactive.Concurrency;
4 | using System.Threading;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks.Actors
8 | {
9 | internal class ActorContext : IActorContext
10 | {
11 | private readonly IExecutor executor;
12 | private string name;
13 |
14 | public ActorContext()
15 | : this(new ActionBlockExecutor(ActionBlockExecutorSettings.Default))
16 | {
17 | }
18 |
19 | public ActorContext(ActorContextSettings settings)
20 | : this(new ActionBlockExecutor(ActionBlockExecutorSettings.DefaultWith(settings.SupportSynchronizationContext))
21 | )
22 | {
23 | }
24 |
25 | public ActorContext(IExecutor executor)
26 | {
27 | this.executor = executor;
28 | }
29 |
30 | public Task Completion => executor.Completion;
31 |
32 | public Task Stop()
33 | {
34 | return executor.Stop();
35 | }
36 |
37 | public void Post(Action action)
38 | {
39 | executor.Enqueue(action);
40 | }
41 |
42 | public Task PostTask(Action action)
43 | {
44 | return executor.PostTask(action);
45 | }
46 |
47 | public Task PostTask(Func func)
48 | {
49 | return executor.PostTask(func);
50 | }
51 |
52 | public IActorContext GetAwaiter()
53 | {
54 | return this;
55 | }
56 |
57 | public bool IsCompleted => executor.Completion.IsCompleted;
58 |
59 | public void OnCompleted(Action continuation)
60 | {
61 | executor.Enqueue(continuation);
62 | }
63 |
64 | public void GetResult()
65 | {
66 | if (executor.Completion.IsCompleted)
67 | throw new ActorStoppedException("Actor context is stopped. New tasks cannot be queued. Further awaits will result in exception being thrown.");
68 | }
69 |
70 | public SynchronizationContext SynchronizationContext => executor.Context;
71 | DateTimeOffset IScheduler.Now => DateTimeOffset.UtcNow;
72 |
73 | public IDisposable Schedule(TState state, DateTimeOffset dueTime,
74 | Func action)
75 | => executor.Schedule(state, dueTime, action);
76 |
77 | public IDisposable Schedule(TState state, TimeSpan dueTime,
78 | Func action)
79 | => executor.Schedule(state, dueTime, action);
80 |
81 | public IDisposable Schedule(TState state,
82 | Func action)
83 | => executor.Schedule(state, action);
84 |
85 | internal void SetName(string newName)
86 | {
87 | name = newName;
88 | }
89 |
90 | public override string ToString()
91 | {
92 | return name == null
93 | ? "Dispatcher context"
94 | : $"Dispatcher context ({name})";
95 | }
96 | }
97 | }
--------------------------------------------------------------------------------
/Stacks.Actors/ActorContextSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks.Actors
8 | {
9 | internal class ActorContextSettings
10 | {
11 | public bool SupportSynchronizationContext { get; set; }
12 |
13 | public ActorContextSettings()
14 | {
15 | SupportSynchronizationContext = true;
16 | }
17 |
18 | public static ActorContextSettings Default
19 | {
20 | get { return new ActorContextSettings(); }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Stacks.Actors/ActorCtorGuardian.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks.Actors
8 | {
9 | internal class ActorCtorGuardian
10 | {
11 | [ThreadStatic]
12 | private static ActorCtorGuardian current;
13 |
14 | public static void SetGuard()
15 | {
16 | current = new ActorCtorGuardian();
17 | }
18 |
19 | public static bool IsGuarded()
20 | {
21 | return current != null;
22 | }
23 |
24 | public static void ClearGuard()
25 | {
26 | current = null;
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Stacks.Actors/ActorSettings.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks.Actors
8 | {
9 | public class ActorSettings
10 | {
11 | public bool SupportSynchronizationContext { get; set; }
12 |
13 | public ActorSettings()
14 | {
15 | SupportSynchronizationContext = true;
16 | }
17 |
18 | public static ActorSettings Default
19 | {
20 | get { return new ActorSettings(); }
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Stacks.Actors/Bit.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks.Actors
8 | {
9 | static class Bit
10 | {
11 | public static bool IsSet(int flags, int bit)
12 | {
13 | return (flags & bit) != 0;
14 | }
15 |
16 | public static int Set(int flags, int bit)
17 | {
18 | return flags | bit;
19 | }
20 |
21 | public static int Clear(int flags, int bit)
22 | {
23 | return flags & (~bit);
24 | }
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Stacks.Actors/CodeGen/ActorWrapperBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks.Actors.CodeGen
8 | {
9 | public class ActorWrapperBase : IActor
10 | {
11 | protected readonly Actor actorImplementation;
12 | public string Name => actorImplementation.Name;
13 | public string Path => actorImplementation.Path;
14 | public IActor Parent => actorImplementation.Parent;
15 | public IEnumerable Children => actorImplementation.Children;
16 | public IObservable ExceptionThrown => actorImplementation.ExceptionThrown;
17 | public Task Stop() => actorImplementation.Stop();
18 | public bool Stopped => actorImplementation.Stopped;
19 |
20 |
21 | public ActorWrapperBase(Actor actorImplementation)
22 | {
23 | this.actorImplementation = actorImplementation;
24 | }
25 |
26 | protected void StopActorAndNotifySystem(string methodName, Exception exception)
27 | {
28 | // actorImplementation.StopBecauseOfError(methodName, exception);
29 | actorImplementation.OnExceptionThrown(exception);
30 | }
31 |
32 | protected Task HandleException(string methodName, Task task)
33 | {
34 | return task.ContinueWith(t =>
35 | {
36 | if (t.Exception != null)
37 | {
38 | StopActorAndNotifySystem(methodName, t.Exception.InnerException);
39 | throw t.Exception.InnerException;
40 | }
41 | return t.Result;
42 | });
43 | }
44 |
45 | protected Task HandleException(string methodName, Task task)
46 | {
47 | return task.ContinueWith(t =>
48 | {
49 | if (t.Exception != null)
50 | {
51 | StopActorAndNotifySystem(methodName, t.Exception.InnerException);
52 | throw t.Exception.InnerException;
53 | }
54 | });
55 | }
56 |
57 | internal Actor ActorImplementation => actorImplementation;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Stacks.Actors/CodeGen/FormattingExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Stacks.Actors.CodeGen
9 | {
10 | public static class FormattingExtensions
11 | {
12 | public static string FormatDeclaration(this MethodInfo method)
13 | {
14 | return method.Name;
15 | }
16 |
17 | public static string FormatDeclaration(this PropertyInfo property)
18 | {
19 | return property.Name;
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Stacks.Actors/CodeGen/IActorCompilerStrategy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Reflection.Emit;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Stacks.Actors.CodeGen
10 | {
11 | public interface IActorCompilerStrategy
12 | {
13 | bool CanCompile(MethodInfoMapping method);
14 | bool CanCompile(PropertyInfoMapping property);
15 | void Implement(MethodInfoMapping method, Type actorInterface, TypeBuilder wrapperBuilder);
16 | void Implement(PropertyInfoMapping property, Type actorInterface, TypeBuilder wrapperBuilder);
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Stacks.Actors/CodeGen/ObservableMethodCompiler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Linq.Expressions;
5 | using System.Reflection;
6 | using System.Reflection.Emit;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace Stacks.Actors.CodeGen
11 | {
12 | public class ObservableMethodCompiler : IActorCompilerStrategy
13 | {
14 | public bool CanCompile(MethodInfoMapping method)
15 | {
16 | var retType = method.InterfaceInfo.ReturnType;
17 | return retType.IsGenericType && retType.GetGenericTypeDefinition() == typeof(IObservable<>);
18 | }
19 |
20 | public bool CanCompile(PropertyInfoMapping property)
21 | {
22 | return false;
23 | }
24 |
25 | public void Implement(MethodInfoMapping method, Type actorInterface, TypeBuilder wrapperBuilder)
26 | {
27 | var mi = method.InterfaceInfo;
28 |
29 | var mBuilder = wrapperBuilder.DefineMethod(method.PublicName,
30 | MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot,
31 | CallingConventions.HasThis, mi.ReturnType,
32 | mi.GetParameters().Select(p => p.ParameterType).ToArray());
33 | var mParams = mi.GetParameters();
34 |
35 | for (var i = 1; i <= mParams.Length; ++i)
36 | {
37 | mBuilder.DefineParameter(i, ParameterAttributes.None, mParams[i - 1].Name);
38 | }
39 |
40 | var il = mBuilder.GetILGenerator();
41 | // ((actorInterface)base.actorImplementation).method(params...)
42 | {
43 | il.Emit(OpCodes.Ldarg_0);
44 | il.Emit(OpCodes.Ldfld,
45 | typeof (ActorWrapperBase).GetField("actorImplementation",
46 | BindingFlags.Instance | BindingFlags.NonPublic));
47 | il.Emit(OpCodes.Castclass, actorInterface);
48 | for (var i = 1; i <= mi.GetParameters().Length; ++i)
49 | {
50 | il.Emit(OpCodes.Ldarg, i);
51 | }
52 | il.EmitCall(OpCodes.Call, mi, null);
53 | }
54 |
55 | //il.EmitCall(OpCodes.Call);
56 |
57 | il.Emit(OpCodes.Ret);
58 | }
59 |
60 | public void Implement(PropertyInfoMapping property, Type actorInterface, TypeBuilder wrapperBuilder)
61 | {
62 | throw new NotSupportedException();
63 | }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Stacks.Actors/CodeGen/ObservablePropertiesCompiler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Reflection.Emit;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Stacks.Actors.CodeGen
10 | {
11 | public class ObservablePropertiesCompiler : IActorCompilerStrategy
12 | {
13 | public bool CanCompile(MethodInfoMapping method)
14 | {
15 | return false;
16 | }
17 |
18 | public bool CanCompile(PropertyInfoMapping property)
19 | {
20 | var propType = property.InterfaceInfo.PropertyType;
21 | return propType.IsGenericType && propType.GetGenericTypeDefinition() == typeof (IObservable<>);
22 | }
23 |
24 | public void Implement(MethodInfoMapping method, Type actorInterface, TypeBuilder wrapperBuilder)
25 | {
26 | throw new NotSupportedException();
27 | }
28 |
29 | public void Implement(PropertyInfoMapping property, Type actorInterface, TypeBuilder wrapperBuilder)
30 | {
31 | var prop = wrapperBuilder.DefineProperty(property.PublicName, PropertyAttributes.None, CallingConventions.HasThis,
32 | property.InterfaceInfo.PropertyType, null);
33 |
34 | var getMethod = wrapperBuilder.DefineMethod("get_" + property.PublicName,
35 | MethodAttributes.Public |
36 | MethodAttributes.HideBySig |
37 | MethodAttributes.SpecialName |
38 | MethodAttributes.Virtual,
39 | property.InterfaceInfo.PropertyType, Type.EmptyTypes);
40 |
41 | var il = getMethod.GetILGenerator();
42 |
43 | il.Emit(OpCodes.Ldarg_0);
44 | il.Emit(OpCodes.Ldfld, typeof(ActorWrapperBase).GetField("actorImplementation", BindingFlags.Instance | BindingFlags.NonPublic));
45 | il.Emit(OpCodes.Castclass, actorInterface);
46 |
47 | il.EmitCall(OpCodes.Callvirt, property.InterfaceInfo.GetGetMethod(true), null);
48 | il.Emit(OpCodes.Ret);
49 |
50 | prop.SetGetMethod(getMethod);
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Stacks.Actors/CodeGen/TaskMethodsCompiler.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using System.Reflection.Emit;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Stacks.Actors.CodeGen
10 | {
11 | public class TaskMethodsCompiler : IActorCompilerStrategy
12 | {
13 | public bool CanCompile(MethodInfoMapping method)
14 | {
15 | var retType = method.InterfaceInfo.ReturnType;
16 | return typeof (Task).IsAssignableFrom(retType) ||
17 | typeof (Task<>).IsAssignableFrom(retType);
18 | }
19 |
20 | public bool CanCompile(PropertyInfoMapping property)
21 | {
22 | return false;
23 | }
24 |
25 | public void Implement(MethodInfoMapping method, Type actorInterface, TypeBuilder wrapperBuilder)
26 | {
27 | var mi = method.InterfaceInfo;
28 |
29 | var mBuilder = wrapperBuilder.DefineMethod(method.PublicName,
30 | MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.Virtual | MethodAttributes.Final | MethodAttributes.NewSlot,
31 | CallingConventions.HasThis, mi.ReturnType,
32 | mi.GetParameters().Select(p => p.ParameterType).ToArray());
33 | var mParams = mi.GetParameters();
34 |
35 | for (var i = 1; i <= mParams.Length; ++i)
36 | {
37 | mBuilder.DefineParameter(i, ParameterAttributes.None, mParams[i - 1].Name);
38 | }
39 |
40 |
41 | var il = mBuilder.GetILGenerator();
42 |
43 | il.Emit(OpCodes.Ldarg_0);
44 | il.Emit(OpCodes.Ldstr, method.PublicName);
45 |
46 | // ((actorInterface)base.actorImplementation).method(params...)
47 | {
48 | il.Emit(OpCodes.Ldarg_0);
49 | il.Emit(OpCodes.Ldfld,
50 | typeof (ActorWrapperBase).GetField("actorImplementation",
51 | BindingFlags.Instance | BindingFlags.NonPublic));
52 | il.Emit(OpCodes.Castclass, actorInterface);
53 | for (var i = 1; i <= mi.GetParameters().Length; ++i)
54 | {
55 | il.Emit(OpCodes.Ldarg, i);
56 | }
57 |
58 | il.EmitCall(OpCodes.Call, mi, null);
59 | }
60 |
61 | il.EmitCall(OpCodes.Call, GetHandleExceptionMethod(mi.ReturnType), null);
62 |
63 | il.Emit(OpCodes.Ret);
64 | }
65 |
66 | private MethodInfo GetHandleExceptionMethod(Type returnType)
67 | {
68 | var g = returnType.IsGenericType;
69 | var method = typeof (ActorWrapperBase)
70 | .GetMethods(BindingFlags.Instance | BindingFlags.NonPublic)
71 | .Where(m => m.Name == "HandleException")
72 | .First(m => m.GetGenericArguments().Length == (g ? 1 : 0));
73 | return g ? method.MakeGenericMethod(returnType.GenericTypeArguments[0]) : method;
74 | }
75 |
76 | public void Implement(PropertyInfoMapping property, Type actorInterface, TypeBuilder wrapperBuilder)
77 | {
78 | throw new NotSupportedException();
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Stacks.Actors/DI/Args.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks.Actors.DI
8 | {
9 | public class Args : Dictionary
10 | {
11 | public Args(params object[] args)
12 | {
13 | if (args == null)
14 | return;
15 |
16 | for (var i = 0; i < args.Length; ++i)
17 | {
18 | this[i.ToString()] = args[i];
19 | }
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Stacks.Actors/DI/DependencyInjectionHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 |
4 | namespace Stacks.Actors.DI
5 | {
6 | class DependencyInjectionHelper : IDependencyInjectionHelper
7 | {
8 | private readonly ActorSystem actorSystem;
9 |
10 | public DependencyInjectionHelper(ActorSystem actorSystem)
11 | {
12 | this.actorSystem = actorSystem;
13 | }
14 |
15 | private IDependencyResolver GetResolverOrFail()
16 | {
17 | var resolver = actorSystem.DependencyResolver;
18 |
19 | if (resolver == null)
20 | throw new Exception($"Cannot use dependency injection ({nameof(ActorSystem)}.{nameof(ActorSystem.DI)}) before setting " +
21 | $"dependency resolver through {nameof(ActorSystem.SetDependencyResolver)} method");
22 |
23 | return resolver;
24 | }
25 |
26 | public T Resolve()
27 | {
28 | return Resolve(null, null);
29 | }
30 |
31 | public T Resolve(IDictionary args)
32 | {
33 | return Resolve(null, args);
34 | }
35 |
36 | public T Resolve(string resolveName, IDictionary args = null)
37 | {
38 | var resolver = GetResolverOrFail();
39 | return resolver.Resolve(resolveName, args);
40 | }
41 |
42 | public void Release(T obj)
43 | {
44 | var resolver = GetResolverOrFail();
45 | resolver.Release(obj);
46 | }
47 |
48 | public void Register()
49 | where I : class
50 | where TImpl : Actor, I
51 | {
52 | var resolver = GetResolverOrFail();
53 | resolver.Register();
54 | }
55 |
56 | public void RegisterTransient()
57 | where I : class
58 | where TImpl : Actor, I
59 | {
60 | var resolver = GetResolverOrFail();
61 | resolver.RegisterTransient();
62 | }
63 | }
64 | }
--------------------------------------------------------------------------------
/Stacks.Actors/DI/IDependencyInjectionHelper.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks.Actors.DI
8 | {
9 | public interface IDependencyInjectionHelper
10 | {
11 | T Resolve();
12 | T Resolve(IDictionary args);
13 | T Resolve(string resolveName, IDictionary args = null);
14 | void Release(T obj);
15 | void Register()
16 | where I : class
17 | where TImpl : Actor, I;
18 |
19 | void RegisterTransient()
20 | where I : class
21 | where TImpl : Actor, I;
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/Stacks.Actors/DI/IDependencyResolver.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 |
3 | namespace Stacks.Actors.DI
4 | {
5 | public interface IDependencyResolver
6 | {
7 | void Register()
8 | where I : class
9 | where TImpl : I;
10 |
11 | void RegisterTransient()
12 | where I : class
13 | where TImpl : I;
14 |
15 | T Resolve(string resolverKey, IDictionary arguments);
16 | void Release(T actor);
17 |
18 | }
19 | }
--------------------------------------------------------------------------------
/Stacks.Actors/Exceptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Runtime.Serialization;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Stacks.Actors
9 | {
10 | [Serializable]
11 | public class ActorStoppedException : Exception
12 | {
13 | public ActorStoppedException()
14 | {
15 | }
16 |
17 | public ActorStoppedException(string message) : base(message)
18 | {
19 | }
20 |
21 | public ActorStoppedException(string message, Exception inner) : base(message, inner)
22 | {
23 | }
24 |
25 | protected ActorStoppedException(
26 | SerializationInfo info,
27 | StreamingContext context) : base(info, context)
28 | {
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Stacks.Actors/IActor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks.Actors
8 | {
9 | public interface IActor
10 | {
11 | bool Stopped { get; }
12 | string Name { get; }
13 | string Path { get; }
14 | IActor Parent { get; }
15 | IEnumerable Children { get; }
16 |
17 | Task Stop();
18 |
19 | IObservable ExceptionThrown { get; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Stacks.Actors/IActorContext.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reactive.Concurrency;
5 | using System.Runtime.CompilerServices;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 |
10 | namespace Stacks.Actors
11 | {
12 | public interface IActorContext : INotifyCompletion, IScheduler
13 | {
14 | bool IsCompleted { get; }
15 |
16 | void Post(Action action);
17 | Task PostTask(Action action);
18 | Task PostTask(Func func);
19 |
20 | IActorContext GetAwaiter();
21 | void GetResult();
22 |
23 | Task Stop();
24 |
25 | SynchronizationContext SynchronizationContext { get; }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Stacks.Actors/NoExceptionHandlerAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks.Actors
8 | {
9 | public class NoExceptionHandlerAttribute : Attribute
10 | {
11 |
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Stacks.Actors/PathUtils.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks.Actors
8 | {
9 | static class PathUtils
10 | {
11 | public static string FixQueryPath(string path)
12 | {
13 | if (path == null)
14 | return null;
15 | if (path.Length == 0)
16 | return path;
17 |
18 | var pb = new StringBuilder(path);
19 |
20 | if (pb[0] != '/')
21 | pb.Insert(0, '/');
22 | if (!pb.ToString().StartsWith("/root"))
23 | pb.Insert(0, "/root");
24 | if (pb[pb.Length - 1] != '/')
25 | pb.Append('/');
26 | return pb.ToString();
27 | }
28 |
29 |
30 | public static void AssertNameForInvalidCharacters(string name)
31 | {
32 | if (name == null)
33 | return;
34 |
35 | if (name.Length == 0)
36 | throw new Exception("Name can't be empty whitespace");
37 |
38 | var invalidChars = new[] { '$', ' ', '\t', '/', '\\' };
39 |
40 | foreach (var ch in invalidChars.Where(ch => name.IndexOf(ch) != -1))
41 | {
42 | throw new Exception("Actor name cannot contain symbol '" + ch + "'");
43 | }
44 | }
45 |
46 | public static string GetActorPath(IActor parent, string name)
47 | {
48 | if (parent == null)
49 | return "/" + name + "/";
50 | return parent.Path + name + "/";
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/Stacks.Actors/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.InteropServices;
3 |
4 | [assembly: AssemblyTitle("Stacks Actors")]
5 | [assembly: AssemblyDescription("Stacks actor and network library")]
6 | [assembly: AssemblyConfiguration("")]
7 | [assembly: AssemblyProduct("Stacks Actors")]
8 |
9 |
--------------------------------------------------------------------------------
/Stacks.Actors/Remote/ActorClientProxyOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks.Actors.Remote
8 | {
9 | public class ActorClientProxyOptions
10 | {
11 | public Func SerializerProvider { get; private set; }
12 |
13 | public ActorClientProxyOptions(Func serializerProvider = null)
14 | {
15 | SerializerProvider = serializerProvider;
16 | }
17 |
18 |
19 | public static readonly ActorClientProxyOptions Default =
20 | new ActorClientProxyOptions(serializerProvider: null);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Stacks.Actors/Remote/ActorPacketSerializer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Stacks.Actors.Proto;
8 |
9 | namespace Stacks.Actors.Remote
10 | {
11 | public class ActorPacketSerializer
12 | {
13 | private readonly IStacksSerializer defaultSerializer;
14 |
15 | public ActorPacketSerializer(IStacksSerializer defaultSerializer)
16 | {
17 | this.defaultSerializer = defaultSerializer;
18 | }
19 |
20 | public virtual void Serialize(ActorProtocolFlags packetFlags, string requestName, T packet, MemoryStream ms)
21 | {
22 | defaultSerializer.Serialize(packet, ms);
23 | }
24 |
25 | public virtual T Deserialize(ActorProtocolFlags packetFlags, string requestName, MemoryStream ms)
26 | {
27 | return defaultSerializer.Deserialize(ms);
28 | }
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/Stacks.Actors/Remote/ActorProtocol.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using ProtoBuf;
7 |
8 | namespace Stacks.Actors.Proto
9 | {
10 | [Flags]
11 | public enum ActorProtocolFlags : int
12 | {
13 | RequestReponse = 0x01,
14 | Observable = 0x02,
15 | StacksProtocol = 0x04,
16 | }
17 |
18 | public static class ActorProtocol
19 | {
20 | public static readonly int Version = 1;
21 |
22 | public static readonly int HandshakeId = 1;
23 | public static readonly int PingId = 2;
24 | }
25 |
26 | [ProtoContract]
27 | public class HandshakeRequest
28 | {
29 | [ProtoMember(1)]
30 | public int ClientProtocolVersion { get; set; }
31 | }
32 |
33 | [ProtoContract]
34 | public class HandshakeResponse
35 | {
36 | [ProtoMember(1)]
37 | public int RequestedProtocolVersion { get; set; }
38 | [ProtoMember(2)]
39 | public int ServerProtocolVersion { get; set; }
40 | [ProtoMember(3)]
41 | public bool ProtocolMatch { get; set; }
42 | }
43 |
44 | [ProtoContract]
45 | public class Ping
46 | {
47 | [ProtoMember(1)]
48 | public long Timestamp { get; set; }
49 | }
50 | }
51 |
52 | namespace Stacks.Actors
53 | {
54 | [Serializable]
55 | public class InvalidProtocolException : Exception
56 | {
57 | public InvalidProtocolException() { }
58 | public InvalidProtocolException(string message) : base(message) { }
59 | public InvalidProtocolException(string message, Exception inner) : base(message, inner) { }
60 | protected InvalidProtocolException(
61 | System.Runtime.Serialization.SerializationInfo info,
62 | System.Runtime.Serialization.StreamingContext context)
63 | : base(info, context) { }
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/Stacks.Actors/Remote/ActorServerProxy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Net;
4 | using Stacks.Actors.Remote.CodeGen;
5 |
6 | // ReSharper disable InconsistentNaming
7 |
8 | namespace Stacks.Actors
9 | {
10 | public class ActorServerProxy
11 | {
12 | private static ServerActorTypeBuilder tBuilder;
13 |
14 | public static IActorServerProxy Create(IPEndPoint bindEndPoint)
15 | where T : Actor, I, new()
16 | {
17 | return Create(ActorSystem.Default.CreateActor(), bindEndPoint,
18 | ActorServerProxyOptions.Default);
19 | }
20 |
21 | public static IActorServerProxy Create(string bindEndPoint)
22 | where T : Actor, I, new()
23 | {
24 | return Create(ActorSystem.Default.CreateActor(), IPHelpers.Parse(bindEndPoint).Result,
25 | ActorServerProxyOptions.Default);
26 | }
27 |
28 | public static IActorServerProxy Create(IPEndPoint bindEndPoint, ActorServerProxyOptions options)
29 | where T : Actor, I, new()
30 | {
31 | return Create(ActorSystem.Default.CreateActor(), bindEndPoint, options);
32 | }
33 |
34 | public static IActorServerProxy Create(string bindEndPoint, ActorServerProxyOptions options)
35 | where T : Actor, I, new()
36 | {
37 | return Create(ActorSystem.Default.CreateActor(), IPHelpers.Parse(bindEndPoint).Result, options);
38 | }
39 |
40 | public static IActorServerProxy Create(IPEndPoint bindEndPoint, I actorImpl)
41 | {
42 | return Create(actorImpl, bindEndPoint, ActorServerProxyOptions.Default);
43 | }
44 |
45 | public static IActorServerProxy Create(string bindEndPoint, I actorImpl)
46 | {
47 | return Create(actorImpl, IPHelpers.Parse(bindEndPoint).Result, ActorServerProxyOptions.Default);
48 | }
49 |
50 | public static IActorServerProxy Create(IPEndPoint bindEndPoint, I actorImpl, ActorServerProxyOptions options)
51 | {
52 | return Create(actorImpl, bindEndPoint, options);
53 | }
54 |
55 | public static IActorServerProxy Create(string bindEndPoint, I actorImpl, ActorServerProxyOptions options)
56 | {
57 | return Create(actorImpl, IPHelpers.Parse(bindEndPoint).Result, options);
58 | }
59 |
60 | private static IActorServerProxy Create(I actorImplementation, IPEndPoint bindEndPoint,
61 | ActorServerProxyOptions options)
62 | {
63 | var aType = actorImplementation.GetType();
64 | tBuilder = new ServerActorTypeBuilder("ActorServerProxy_ " + aType.FullName);
65 |
66 | tBuilder.DefineMessagesFromInterfaceType(aType);
67 |
68 | var actorImplType = tBuilder.CreateActorType(aType);
69 | tBuilder.SaveToFile();
70 |
71 | var actor = Activator.CreateInstance(actorImplType, actorImplementation, bindEndPoint, options);
72 | return (IActorServerProxy)actor;
73 | }
74 | }
75 | }
--------------------------------------------------------------------------------
/Stacks.Actors/Remote/ActorServerProxyOptions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Stacks.Actors.Remote;
7 |
8 | namespace Stacks.Actors
9 | {
10 | public class ActorServerProxyOptions
11 | {
12 | public bool ActorSessionInjectionEnabled { get; private set; }
13 | public Func SerializerProvider { get; private set; }
14 |
15 | public ActorServerProxyOptions(bool actorSessionInjectionEnabled, Func serializerProvider = null)
16 | {
17 | SerializerProvider = serializerProvider;
18 | ActorSessionInjectionEnabled = actorSessionInjectionEnabled;
19 | }
20 |
21 | public static readonly ActorServerProxyOptions Default =
22 | new ActorServerProxyOptions(actorSessionInjectionEnabled: false,
23 | serializerProvider: null);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Stacks.Actors/Remote/ClientActorDisconnectedData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Stacks.Actors
4 | {
5 | public class ClientActorDisconnectedData
6 | {
7 | public ClientActorDisconnectedData(IActorSession session, Exception error)
8 | {
9 | Session = session;
10 | Error = error;
11 | }
12 |
13 | public IActorSession Session { get; private set; }
14 | public Exception Error { get; private set; }
15 | }
16 | }
--------------------------------------------------------------------------------
/Stacks.Actors/Remote/IActorClientProxy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks.Actors
8 | {
9 | public interface IActorClientProxy : IActorClientProxy
10 | {
11 | T Actor { get; }
12 | }
13 |
14 | public interface IActorClientProxy
15 | {
16 | void Close();
17 | IObservable Disconnected { get; }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Stacks.Actors/Remote/IActorServerProxy.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Stacks.Actors
9 | {
10 | public interface IActorServerProxy
11 | {
12 | IPEndPoint BindEndPoint { get; }
13 |
14 | IObservable ActorClientConnected { get; }
15 | IObservable ActorClientDisconnected { get; }
16 |
17 | Task GetCurrentClientSessions();
18 |
19 | void Stop();
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Stacks.Actors/Remote/IActorSession.cs:
--------------------------------------------------------------------------------
1 | using System.Runtime.Remoting.Messaging;
2 |
3 | namespace Stacks.Actors
4 | {
5 | public interface IActorSession
6 | {
7 | IFramedClient Client { get; }
8 | void Close();
9 | }
10 |
11 | public class ActorSession : IActorSession
12 | {
13 | public ActorSession(IFramedClient client)
14 | {
15 | Client = client;
16 | }
17 |
18 | public static IActorSession Current => CallContext.LogicalGetData(ActorSessionCallContextKey) as IActorSession;
19 |
20 | internal static readonly string ActorSessionCallContextKey = "__stacks.actor.session0xc0de";
21 |
22 | public IFramedClient Client { get; }
23 |
24 | public void Close()
25 | {
26 | Client.Close();
27 | }
28 | }
29 | }
--------------------------------------------------------------------------------
/Stacks.Actors/Remote/IReplyMessage.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks.Actors
8 | {
9 | public interface IReplyMessage
10 | {
11 | T GetResult();
12 | void SetResult(T result);
13 | void SetError(string error);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/Stacks.Actors/RootActor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks.Actors
8 | {
9 | public class RootActor : Actor, IRootActor
10 | {
11 | public RootActor()
12 | {
13 |
14 | }
15 | }
16 |
17 | public interface IRootActor : IActor
18 | {
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Stacks.Actors/Stacks.Actors.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Stacks.Actors
5 | Stacks Actors
6 | @build.number@
7 | Marcin Deptuła
8 | Marcin Deptuła
9 | Simple to use, async/await aware actor library
10 | https://raw.githubusercontent.com/Ravadre/Stacks/master/LICENSE
11 | https://github.com/Ravadre/Stacks
12 | false
13 | Stacks Actors- reactive actor/network library
14 | Copyright Marcin Deptuła
15 | C# Socket Network Actor Reactive
16 | @dependencies@
17 |
18 |
--------------------------------------------------------------------------------
/Stacks.Actors/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/Stacks.FSharp/Actors/ActorContext.fs:
--------------------------------------------------------------------------------
1 | namespace Stacks.Actors
2 |
3 |
4 | []
5 | module Actors =
6 | type Stacks.Actors.IActorContext with
7 |
8 | ///
9 | /// Creates a wrapper async expression which will execute
10 | /// given one on executor's context. Returned expression
11 | /// is not started automatically, however, it will be rescheduled
12 | /// almost immediately after start, so Async.RunSynchronously or
13 | /// Async.StartImmediate are recommended to start it.
14 | ///
15 | member this.MakeAsync<'T>(wf: Async<'T>) = async {
16 | do! Async.SwitchToContext(this.SynchronizationContext)
17 |
18 | return! wf
19 | }
20 |
--------------------------------------------------------------------------------
/Stacks.FSharp/Actors/Executor.fs:
--------------------------------------------------------------------------------
1 | namespace Stacks
2 |
3 | open Stacks
4 |
5 | []
6 | module Executors =
7 |
8 | type IExecutor with
9 | ///
10 | /// Creates a wrapper async expression which will execute
11 | /// given one on executor's context. Returned expression
12 | /// is not started automatically, however, it will be rescheduled
13 | /// almost immediately after start, so Async.RunSynchronously or
14 | /// Async.StartImmediate are recommended to start it.
15 | ///
16 | member this.MakeAsync<'a>(wf: Async<'a>) = async {
17 | do! Async.SwitchToContext(this.Context)
18 | return! wf
19 | }
20 |
21 | ///
22 | /// Runs given code on executor's context immediately. Result can be awaited with
23 | /// Async.RunSynchronously
24 | ///
25 | member this.RunAsync<'a>(code: unit -> 'a) =
26 | this.PostTask(code)
27 | |> Async.AwaitTask
28 |
29 | ///
30 | /// Runs given code on executor's context immediately.
31 | /// Async.RunSynchronously can be used to await completion of code.
32 | ///
33 | member this.RunAsync(code: unit -> unit) =
34 | this.PostTask(code)
35 | |> Async.AwaitTask
36 |
--------------------------------------------------------------------------------
/Stacks.FSharp/AssemblyInfo.fs:
--------------------------------------------------------------------------------
1 | namespace Stacks
2 |
3 | open System.Reflection
4 |
5 | []
6 | []
7 | []
8 | []
9 | do()
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Stacks.FSharp/Stacks.FSharp.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Stacks.FSharp
5 | Stacks FSharp
6 | @build.number@
7 | Marcin Deptuła
8 | Marcin Deptuła
9 | Simple to use actor/network library
10 | https://raw.githubusercontent.com/Ravadre/Stacks/master/LICENSE
11 | https://github.com/Ravadre/Stacks
12 | false
13 | F# wrapper for Stacks - reactive actor/network library
14 | Copyright Marcin Deptuła
15 | F# Socket Network Actor Reactive
16 | @dependencies@
17 |
18 |
--------------------------------------------------------------------------------
/Stacks.FSharp/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/Stacks.MessagePack/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | [assembly: AssemblyTitle("Stacks.MessagePack")]
6 | [assembly: AssemblyDescription("MessagePack serializer for Stacks")]
7 | [assembly: AssemblyConfiguration("")]
8 | [assembly: AssemblyProduct("Stacks")]
9 |
10 | [assembly: Guid("A5D6D241-A760-4FB2-BCCA-CDA387A0CB94")]
11 |
--------------------------------------------------------------------------------
/Stacks.MessagePack/Serializers/MessagePackStacksSerializer.cs:
--------------------------------------------------------------------------------
1 | using MsgPack;
2 | using MsgPack.Serialization;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Reflection;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace Stacks
12 | {
13 | public class MessagePackStacksSerializer : IStacksSerializer
14 | {
15 | private SerializationContext context;
16 |
17 | public MessagePackStacksSerializer()
18 | {
19 |
20 | }
21 |
22 | public void Initialize()
23 | {
24 | this.context = new SerializationContext();
25 | }
26 |
27 | public T Deserialize(MemoryStream ms)
28 | {
29 | var d = MessagePackSerializer.Get(this.context);
30 | return d.Unpack(ms);
31 | }
32 |
33 | public void Serialize(T obj, MemoryStream ms)
34 | {
35 | var s = MessagePackSerializer.Get(this.context);
36 | s.Pack(ms, obj);
37 | }
38 |
39 | public void PrepareSerializerForType()
40 | {
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Stacks.MessagePack/Stacks.MessagePack.nuspec:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Stacks.MessagePack
5 | Stacks - MessagePack
6 | @build.number@
7 | Marcin Deptuła
8 | Marcin Deptuła
9 | Stacks serialization extension which uses MessagePack
10 | https://raw.githubusercontent.com/Ravadre/Stacks/master/LICENSE
11 | https://github.com/Ravadre/Stacks
12 | false
13 | Stacks - reactive actor/network library
14 | Copyright Marcin Deptuła
15 | C# Socket Network Actor MessagePack Reactive
16 | @dependencies@
17 |
18 |
--------------------------------------------------------------------------------
/Stacks.MessagePack/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/Stacks.Tests/Client/SslClientTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Stacks.Tcp;
7 | using Xunit;
8 |
9 | namespace Stacks.Tests.Client
10 | {
11 | public class SslClientTests
12 | {
13 | private SocketServer server;
14 | private SslClient lClient, sClient;
15 |
16 | public SslClientTests()
17 | {
18 | }
19 |
20 | public void Cleanup()
21 | {
22 | server.StopAndAssertStopped();
23 | lClient.Close();
24 | sClient.Close();
25 | }
26 |
27 | private byte[] PrepareBuffer(int size)
28 | {
29 | Random rng = new Random();
30 | var buffer = new byte[size];
31 | rng.NextBytes(buffer);
32 |
33 | return buffer;
34 | }
35 |
36 | [Fact]
37 | public void Ssl_should_establish_connection()
38 | {
39 | SslHelpers.CreateServerAndConnectedClient(out server, out lClient, out sClient);
40 |
41 | Assert.True(lClient.IsConnected);
42 | Assert.True(sClient.IsConnected);
43 |
44 | Cleanup();
45 | }
46 |
47 | [Fact]
48 | public void Data_transfered_through_sockets_should_be_transfered_correctly()
49 | {
50 | SslHelpers.CreateServerAndConnectedClient(out server, out lClient, out sClient);
51 |
52 | var buffer = PrepareBuffer(20);
53 |
54 | var recvBuffer = lClient.ReceiveData(buffer.Length, 2000, () =>
55 | {
56 | sClient.Send(buffer);
57 | });
58 | var recvBuffer2 = sClient.ReceiveData(buffer.Length, 2000, () =>
59 | {
60 | lClient.Send(buffer);
61 | });
62 |
63 | Assert.Equal(buffer, recvBuffer);
64 | Assert.Equal(buffer, recvBuffer2);
65 | }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/Stacks.Tests/DataHelpers.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Cryptography;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Stacks.Tests
9 | {
10 | public class DataHelpers
11 | {
12 | public static byte[] CreateRandomBuffer(int size)
13 | {
14 | var rng = RandomNumberGenerator.Create();
15 | var buffer = new byte[size];
16 | rng.GetBytes(buffer);
17 |
18 | return buffer;
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/Stacks.Tests/ExecutorTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using Xunit;
4 |
5 | namespace Stacks.Tests
6 | {
7 | public class ExecutorTests
8 | {
9 | [Theory]
10 | [InlineData(typeof (ActionBlockExecutor))]
11 | public void PostTask_should_signal_task_when_action_is_completed(Type execType)
12 | {
13 | var exec = Activator.CreateInstance(execType) as IExecutor;
14 |
15 | var c = 0;
16 |
17 | var task = exec.PostTask(() => { Interlocked.Increment(ref c); });
18 |
19 | task.Wait();
20 | Assert.Equal(1, c);
21 | }
22 |
23 | [Theory]
24 | [InlineData(typeof (ActionBlockExecutor))]
25 | public void PostTask_should_signal_return_value_through_task(Type execType)
26 | {
27 | var exec = Activator.CreateInstance(execType) as IExecutor;
28 |
29 | var task = exec.PostTask(() => { return 5; });
30 |
31 | Assert.Equal(5, task.Result);
32 | }
33 |
34 | [Theory]
35 | [InlineData(typeof (ActionBlockExecutor))]
36 | public void PostTask_should_rethrow_exception(Type execType)
37 | {
38 | var exec = Activator.CreateInstance(execType) as IExecutor;
39 |
40 | var task = exec.PostTask(() => { throw new Exception("test"); });
41 |
42 | Assert.Throws(typeof (AggregateException), () => { var r = task.Result; });
43 | }
44 |
45 | [Theory]
46 | [InlineData(typeof (ActionBlockExecutor))]
47 | public void Executor_should_not_be_stopped_after_posttask_throws_exception(Type execType)
48 | {
49 | var errorOccured = new ManualResetEventSlim();
50 | var execIsRunning = new ManualResetEventSlim();
51 |
52 | var exec = Activator.CreateInstance(execType) as IExecutor;
53 |
54 | exec.Error += exception => { errorOccured.Set(); };
55 |
56 | var task = exec.PostTask(() => { throw new Exception("test"); });
57 |
58 | Assert.Throws(typeof (AggregateException), () => { task.Wait(); });
59 |
60 |
61 | exec.PostTask(() => { execIsRunning.Set(); }).Wait();
62 |
63 | Assert.False(errorOccured.IsSet);
64 | Assert.True(execIsRunning.IsSet);
65 | }
66 | }
67 | }
--------------------------------------------------------------------------------
/Stacks.Tests/IPHelpersTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using Xunit;
7 | using Stacks;
8 | using System.Net;
9 |
10 | namespace Stacks.Tests
11 | {
12 | public class IPHelpersTests
13 | {
14 | [Fact]
15 | public void Localhost_should_return_loopback_address()
16 | {
17 | var ep = IPHelpers.Parse("tcp://localhost:1234").Result;
18 |
19 | Assert.Equal(IPAddress.Loopback, ep.Address);
20 | Assert.Equal(1234, ep.Port);
21 | }
22 |
23 | [Fact]
24 | public void IPv6_Localhost_should_return_loopback_address()
25 | {
26 | var ep = IPHelpers.Parse("tcp6://localhost:1234").Result;
27 |
28 | Assert.Equal(IPAddress.IPv6Loopback, ep.Address);
29 | Assert.Equal(1234, ep.Port);
30 | }
31 |
32 | [Fact]
33 | public void Numeric_ip_should_be_parsed_properly()
34 | {
35 | var ep = IPHelpers.Parse("tcp://10.43.12.43:1234").Result;
36 |
37 | Assert.Equal(IPAddress.Parse("10.43.12.43"), ep.Address);
38 | Assert.Equal(1234, ep.Port);
39 | }
40 |
41 | [Fact]
42 | public void Asterisk_should_be_parsed_as_any()
43 | {
44 | var ep = IPHelpers.Parse("tcp://*:1234").Result;
45 |
46 | Assert.Equal(IPAddress.Any, ep.Address);
47 | Assert.Equal(1234, ep.Port);
48 | }
49 |
50 | [Fact]
51 | public void Plus_should_be_parsed_as_any()
52 | {
53 | var ep = IPHelpers.Parse("tcp://+:1234").Result;
54 |
55 | Assert.Equal(IPAddress.Any, ep.Address);
56 | Assert.Equal(1234, ep.Port);
57 | }
58 |
59 | [Fact]
60 | public void IPv6_Asterisk_should_be_parsed_as_any()
61 | {
62 | var ep = IPHelpers.Parse("tcp6://*:1234").Result;
63 |
64 | Assert.Equal(IPAddress.IPv6Any, ep.Address);
65 | Assert.Equal(1234, ep.Port);
66 | }
67 |
68 | [Fact]
69 | public void IPv6_Plus_should_be_parsed_as_any()
70 | {
71 | var ep = IPHelpers.Parse("tcp6://+:1234").Result;
72 |
73 | Assert.Equal(IPAddress.IPv6Any, ep.Address);
74 | Assert.Equal(1234, ep.Port);
75 | }
76 |
77 | [Fact]
78 | public async Task IP_should_resolve_from_host()
79 | {
80 | var ep = IPHelpers.Parse("tcp://google.com:1234").Result;
81 |
82 | Assert.Equal(1234, ep.Port);
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/Stacks.Tests/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | [assembly: AssemblyTitle("Stacks.Tests")]
6 | [assembly: AssemblyDescription("Tests for Stacks")]
7 | [assembly: AssemblyConfiguration("")]
8 | [assembly: AssemblyProduct("Stacks")]
9 |
10 | [assembly: Guid("e75bf177-2b84-47cb-aa93-64226e6c081d")]
11 |
--------------------------------------------------------------------------------
/Stacks.Tests/Serialization/MessagePackSerializerTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | using Moq;
8 | using Xunit;
9 |
10 | using MsgPack;
11 | using MsgPack.Serialization;
12 | using System.IO;
13 | using System.ComponentModel;
14 | using System.Threading;
15 |
16 | namespace Stacks.Tests.Serialization
17 | {
18 | public class MessagePackSerializerTests
19 | {
20 | protected MemoryStream CreateSerializedObject(T sample)
21 | {
22 | var serializer = MessagePackSerializer.Get();
23 | var ms = new MemoryStream();
24 |
25 | serializer.Pack(ms, sample);
26 |
27 | ms.Position = 0;
28 |
29 | return ms;
30 | }
31 |
32 | protected TestData CreateSampleTestData()
33 | {
34 | return new TestData { Bar = Math.PI , Zar = (decimal)Math.PI, Foo = 42, Sar = "Foo bar test" };
35 | }
36 |
37 | public class Deserialize_should : MessagePackSerializerTests
38 | {
39 | [Fact]
40 | public void Deserialize_object_properly()
41 | {
42 | var test = CreateSampleTestData();
43 | var obj = CreateSerializedObject(test);
44 |
45 | Console.WriteLine(new ArraySegment(obj.GetBuffer(), 0, (int)obj.Length).ToBinaryString());
46 |
47 | var serializer = new MessagePackStacksSerializer();
48 | serializer.Initialize();
49 | var recv = serializer.Deserialize(obj);
50 |
51 | Assert.Equal(test.Foo, recv.Foo);
52 | Assert.Equal(test.Bar, recv.Bar);
53 | Assert.Equal(test.Sar, recv.Sar);
54 | Assert.Equal(test.Zar, recv.Zar);
55 | }
56 | }
57 |
58 | public class Serialize_should : MessagePackSerializerTests
59 | {
60 | [Fact]
61 | public void Serialize_data_so_it_can_be_later_deserialized_with_Deserialize()
62 | {
63 | var test = CreateSampleTestData();
64 |
65 | var serializer = new MessagePackStacksSerializer();
66 | serializer.Initialize();
67 | var ms = new MemoryStream();
68 |
69 | serializer.Serialize(test, ms);
70 | ms.Position = 0;
71 | var data = serializer.Deserialize(ms);
72 |
73 | Assert.Equal(test.Bar, data.Bar);
74 | Assert.Equal(test.Foo, data.Foo);
75 | Assert.Equal(test.Sar, data.Sar);
76 | Assert.Equal(test.Zar, data.Zar);
77 | }
78 | }
79 |
80 |
81 |
82 | public class TestData
83 | {
84 | public int Foo { get; set; }
85 | public double Bar { get; set; }
86 | public decimal Zar { get; set; }
87 | public string Sar { get; set; }
88 | }
89 | }
90 | }
91 |
--------------------------------------------------------------------------------
/Stacks.Tests/Serialization/ProtoBufSerializerTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using Moq;
8 | using ProtoBuf;
9 | using Xunit;
10 |
11 |
12 | //TODO: Refactor those and messagepack tests to share some code base
13 | namespace Stacks.Tests.Serialization
14 | {
15 | public class ProtoBufSerializerTests
16 | {
17 | protected MemoryStream CreateSerializedObject(T sample)
18 | {
19 | var ms = new MemoryStream();
20 | Serializer.Serialize(ms, sample);
21 | ms.Position = 0;
22 |
23 | return ms;
24 | }
25 |
26 | protected TestData CreateSampleTestData()
27 | {
28 | return new TestData { Bar = Math.PI , Zar = (decimal)Math.PI, Foo = 42, Sar = "Foo bar test" };
29 | }
30 |
31 | public class Deserialize_should : ProtoBufSerializerTests
32 | {
33 | [Fact]
34 | public void Deserialize_object_properly()
35 | {
36 | var test = CreateSampleTestData();
37 | var obj = CreateSerializedObject(test);
38 |
39 | Console.WriteLine(new ArraySegment(obj.GetBuffer(), 0, (int)obj.Length).ToBinaryString());
40 |
41 | var serializer = new ProtoBufStacksSerializer();
42 | var data = serializer.Deserialize(obj);
43 |
44 | Assert.Equal(test.Bar, data.Bar);
45 | Assert.Equal(test.Foo, data.Foo);
46 | Assert.Equal(test.Sar, data.Sar);
47 | Assert.Equal(test.Zar, data.Zar);
48 | }
49 | }
50 |
51 |
52 | public class Serialize_should : ProtoBufSerializerTests
53 | {
54 | [Fact]
55 | public void Serialize_data_so_it_can_be_later_deserialized_with_Deserialize()
56 | {
57 | var test = CreateSampleTestData();
58 |
59 | var serializer = new ProtoBufStacksSerializer();
60 | var ms = new MemoryStream();
61 |
62 | serializer.Serialize(test, ms);
63 | ms.Position = 0;
64 | var data = serializer.Deserialize(ms);
65 |
66 | Assert.Equal(test.Bar, data.Bar);
67 | Assert.Equal(test.Foo, data.Foo);
68 | Assert.Equal(test.Sar, data.Sar);
69 | Assert.Equal(test.Zar, data.Zar);
70 | }
71 | }
72 |
73 |
74 | [ProtoContract]
75 | public class TestData
76 | {
77 | [ProtoMember(1)]
78 | public int Foo { get; set; }
79 | [ProtoMember(2)]
80 | public double Bar { get; set; }
81 | [ProtoMember(3)]
82 | public decimal Zar { get; set; }
83 | [ProtoMember(4)]
84 | public string Sar { get; set; }
85 | }
86 | }
87 | }
88 |
--------------------------------------------------------------------------------
/Stacks.Tests/SocketServerTests.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Net.Sockets;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using Xunit;
10 |
11 | namespace Stacks.Tests
12 | {
13 | public class SocketServerTests
14 | {
15 |
16 | public class Starting_and_stopping : SocketServerTests
17 | {
18 | [Fact]
19 | public void Starting_two_times_should_throw()
20 | {
21 | var server = ServerHelpers.CreateServer();
22 | server.Start();
23 |
24 | Assert.Throws(typeof(InvalidOperationException), () =>
25 | {
26 | server.Start();
27 | });
28 | }
29 |
30 | [Fact]
31 | public void Starting_should_call_started_callback()
32 | {
33 | var started = new ManualResetEventSlim();
34 | var server = ServerHelpers.CreateServer();
35 |
36 | server.Started.Subscribe(u => { started.Set(); });
37 | server.Start();
38 |
39 | started.AssertWaitFor(2000);
40 |
41 | server.StopAndAssertStopped();
42 | }
43 |
44 | [Fact]
45 | public void Starting_and_stopping_should_call_both_callbacks()
46 | {
47 | var started = new ManualResetEventSlim();
48 | var stopped = new ManualResetEventSlim();
49 | var server = ServerHelpers.CreateServer();
50 |
51 | server.Started.Subscribe(_ => { started.Set(); });
52 | server.Stopped.Subscribe(_ => { stopped.Set(); });
53 |
54 | server.Start();
55 | server.Stop();
56 |
57 | started.AssertWaitFor(2000);
58 | stopped.AssertWaitFor(2000);
59 | }
60 |
61 | [Fact]
62 | public void When_exception_is_thrown_inside_callback_executor_should_signal_error()
63 | {
64 | var errOccured = new ManualResetEventSlim();
65 |
66 | var exec = new ActionBlockExecutor(null, new ActionBlockExecutorSettings());
67 | var server = ServerHelpers.CreateServer(exec);
68 |
69 | exec.Error += exc => { Assert.Equal("abcdef", exc.Message); errOccured.Set(); };
70 | server.Started.Subscribe(_ => { throw new Exception("abcdef"); });
71 |
72 | server.Start();
73 |
74 | errOccured.AssertWaitFor(2000);
75 |
76 | server.Stop();
77 |
78 | }
79 | }
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Stacks.Tests/StacksTest.pfx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Ravadre/Stacks/3c124dd62e3ef1e55d2168f75f36ba50ed4b29b5/Stacks.Tests/StacksTest.pfx
--------------------------------------------------------------------------------
/Stacks.Tests/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Stacks/Client/FramedClientBuffer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace Stacks
4 | {
5 | public struct FramedClientBuffer
6 | {
7 | public ArraySegment Packet { get; private set; }
8 | internal byte[] InternalBuffer => Packet.Array;
9 |
10 | public FramedClientBuffer(int packetLength)
11 | : this()
12 | {
13 | var intBuffer = new byte[packetLength + 4];
14 | PrepareHeader(intBuffer, packetLength + 4);
15 |
16 | Packet = new ArraySegment(intBuffer, 4, packetLength);
17 | }
18 |
19 | public static FramedClientBuffer FromPacket(ArraySegment buffer)
20 | {
21 | Ensure.IsNotNull(buffer.Array, "buffer.Array");
22 |
23 | var intBuffer = new byte[buffer.Count + 4];
24 | PrepareHeader(intBuffer, buffer.Count + 4);
25 |
26 | Buffer.BlockCopy(buffer.Array, buffer.Offset, intBuffer, 4, buffer.Count);
27 |
28 | var framedBuffer = new FramedClientBuffer();
29 | framedBuffer.Packet = new ArraySegment(intBuffer, 4, buffer.Count);
30 |
31 | return framedBuffer;
32 | }
33 |
34 | private static unsafe void PrepareHeader(byte[] b, int p)
35 | {
36 | fixed (byte* bPtr = b)
37 | {
38 | int* iPtr = (int*)bPtr;
39 | *iPtr = p;
40 | }
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Stacks/Client/IFramedClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks
8 | {
9 | public interface IFramedClient : ISocketClient
10 | {
11 | IObservable Sent { get; }
12 | IObservable> Received { get; }
13 |
14 | void SendPacket(byte[] packet);
15 | void SendPacket(ArraySegment packet);
16 | void SendPacket(FramedClientBuffer packet);
17 | FramedClientBuffer PreparePacketBuffer(int packetBytes);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Stacks/Client/IMessageClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks
8 | {
9 | public interface IMessageClient : ISocketClient
10 | {
11 | IObservable Sent { get; }
12 |
13 | void Send(T obj);
14 |
15 | void PreLoadTypesFromAssemblyOfType();
16 | void PreLoadType();
17 | void PreLoadType(Type type);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Stacks/Client/IRawByteClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace Stacks
8 | {
9 | public interface IRawByteClient : ISocketClient
10 | {
11 | IObservable> Received { get; }
12 | IObservable Sent { get; }
13 |
14 | void Send(byte[] buffer);
15 | void Send(ArraySegment buffer);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/Stacks/Client/ISocketClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Net;
5 | using System.Reactive;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace Stacks
10 | {
11 | public interface ISocketClient
12 | {
13 | IExecutor Executor { get; }
14 | bool IsConnected { get; }
15 |
16 | IObservable Connected { get; }
17 | IObservable Disconnected { get; }
18 |
19 | IPEndPoint RemoteEndPoint { get; }
20 | IPEndPoint LocalEndPoint { get; }
21 |
22 | IObservable Connect(IPEndPoint remoteEndPoint);
23 | IObservable Connect(string remoteEndPoint);
24 | void Close();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Stacks/Client/RawByteClientStream.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading;
7 | using System.Threading.Tasks;
8 | using System.Reactive.Linq;
9 |
10 | namespace Stacks
11 | {
12 | public class RawByteClientStream : Stream
13 | {
14 | private IRawByteClient client;
15 | ResizableCyclicBuffer buffer;
16 | private ManualResetEventSlim hasDataEvent;
17 | private bool disposed;
18 |
19 | public RawByteClientStream(IRawByteClient client)
20 | {
21 | this.disposed = false;
22 | this.hasDataEvent = new ManualResetEventSlim();
23 | this.client = client;
24 | this.buffer = new ResizableCyclicBuffer(4096);
25 | this.client.Received.Subscribe(DataReceived);
26 | }
27 |
28 | public override bool CanRead => true;
29 | public override bool CanSeek => false;
30 | public override bool CanWrite => true;
31 |
32 | public override void Flush()
33 | {
34 |
35 | }
36 |
37 | public override long Length
38 | {
39 | get { throw new NotSupportedException(); }
40 | }
41 |
42 | public override long Position
43 | {
44 | get
45 | {
46 | throw new NotSupportedException();
47 | }
48 | set
49 | {
50 | throw new NotSupportedException();
51 | }
52 | }
53 |
54 | public override int Read(byte[] buffer, int offset, int count)
55 | {
56 | this.hasDataEvent.Wait();
57 |
58 | if (this.disposed)
59 | throw new ObjectDisposedException("Stream");
60 |
61 | lock (this.buffer)
62 | {
63 | var segment = new ArraySegment(buffer, offset, count);
64 | var read = this.buffer.ReadRawBytes(segment);
65 |
66 | if (this.buffer.Count == 0)
67 | this.hasDataEvent.Reset();
68 |
69 | return read;
70 | }
71 | }
72 |
73 | public override void Write(byte[] buffer, int offset, int count)
74 | {
75 | client.Send(new ArraySegment(buffer, offset, count));
76 | }
77 |
78 | public override long Seek(long offset, SeekOrigin origin)
79 | {
80 | throw new NotImplementedException();
81 | }
82 |
83 | public override void SetLength(long value)
84 | {
85 | throw new NotImplementedException();
86 | }
87 |
88 | private void DataReceived(ArraySegment data)
89 | {
90 | lock (this.buffer)
91 | {
92 | this.buffer.AddData(data);
93 | this.hasDataEvent.Set();
94 | }
95 | }
96 |
97 | protected override void Dispose(bool disposing)
98 | {
99 | base.Dispose(disposing);
100 |
101 | try
102 | {
103 | disposed = true;
104 | this.hasDataEvent.Set();
105 | }
106 | catch { }
107 | }
108 |
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/Stacks/Client/Tcp/FramedClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Net;
3 | using System.Reactive;
4 | using System.Reactive.Subjects;
5 |
6 | namespace Stacks.Tcp
7 | {
8 | public class FramedClient : IFramedClient
9 | {
10 | private readonly IRawByteClient client;
11 | private readonly Subject> received;
12 | private readonly ResizableCyclicBuffer recvBuffer;
13 |
14 | public FramedClient(IRawByteClient client)
15 | {
16 | received = new Subject>();
17 | this.client = client;
18 | recvBuffer = new ResizableCyclicBuffer(4096);
19 |
20 | this.client.Received.Subscribe(ClientReceivedData);
21 | }
22 |
23 | public IObservable Connected
24 | {
25 | get { return client.Connected; }
26 | }
27 |
28 | public IObservable Disconnected
29 | {
30 | get { return client.Disconnected; }
31 | }
32 |
33 | public IObservable Sent
34 | {
35 | get { return client.Sent; }
36 | }
37 |
38 | public IObservable> Received
39 | {
40 | get { return received; }
41 | }
42 |
43 | public IPEndPoint LocalEndPoint
44 | {
45 | get { return client.LocalEndPoint; }
46 | }
47 |
48 | public IPEndPoint RemoteEndPoint
49 | {
50 | get { return client.RemoteEndPoint; }
51 | }
52 |
53 | public void SendPacket(byte[] packet)
54 | {
55 | Ensure.IsNotNull(packet, "packet");
56 |
57 | SendPacket(new ArraySegment(packet));
58 | }
59 |
60 | public void SendPacket(ArraySegment packet)
61 | {
62 | Ensure.IsNotNull(packet.Array, "packet.Array");
63 |
64 | var buffer = FramedClientBuffer.FromPacket(packet);
65 | SendPacket(buffer);
66 | }
67 |
68 | public void SendPacket(FramedClientBuffer packet)
69 | {
70 | packet = OnBeforeSendPacket(packet);
71 | client.Send(packet.InternalBuffer);
72 | }
73 |
74 | public FramedClientBuffer PreparePacketBuffer(int packetBytes)
75 | {
76 | return new FramedClientBuffer(packetBytes);
77 | }
78 |
79 | public void Close()
80 | {
81 | client.Close();
82 | }
83 |
84 | public IExecutor Executor
85 | {
86 | get { return client.Executor; }
87 | }
88 |
89 | public bool IsConnected
90 | {
91 | get { return client.IsConnected; }
92 | }
93 |
94 | public IObservable Connect(IPEndPoint remoteEndPoint)
95 | {
96 | return client.Connect(remoteEndPoint);
97 | }
98 |
99 | public IObservable Connect(string endPoint)
100 | {
101 | return Connect(endPoint);
102 | }
103 |
104 | private void ClientReceivedData(ArraySegment data)
105 | {
106 | recvBuffer.AddData(data);
107 |
108 | foreach (var packet in recvBuffer.GetPackets())
109 | {
110 | OnReceived(packet);
111 | }
112 | }
113 |
114 | private void OnReceived(ArraySegment data)
115 | {
116 | data = OnBeforeReceivePacket(data);
117 | received.OnNext(data);
118 | }
119 |
120 | protected virtual ArraySegment OnBeforeReceivePacket(ArraySegment data)
121 | {
122 | return data;
123 | }
124 |
125 | protected virtual FramedClientBuffer OnBeforeSendPacket(FramedClientBuffer packet)
126 | {
127 | return packet;
128 | }
129 |
130 | }
131 | }
--------------------------------------------------------------------------------
/Stacks/Client/Tcp/MessageClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Net;
6 | using System.Reactive;
7 | using System.Reflection;
8 | using System.Text;
9 | using System.Threading.Tasks;
10 |
11 | namespace Stacks.Tcp
12 | {
13 | public class MessageClient : MessageClientBase
14 | {
15 | private StacksSerializationHandler packetSerializationHandler;
16 |
17 | public MessageClient(IFramedClient framedClient,
18 | IStacksSerializer packetSerializer,
19 | IMessageHandler messageHandler,
20 | Func registration)
21 | : this(registration(new MessageIdRegistration()).CreateCache(),
22 | framedClient, packetSerializer, messageHandler)
23 | {
24 | }
25 |
26 | public MessageClient(IFramedClient framedClient,
27 | IStacksSerializer packetSerializer,
28 | IMessageHandler messageHandler)
29 | : this(new MessageIdCache(),
30 | framedClient, packetSerializer, messageHandler)
31 | {
32 | }
33 |
34 | private MessageClient(IMessageIdCache messageIdCache,
35 | IFramedClient framedClient,
36 | IStacksSerializer packetSerializer,
37 | IMessageHandler messageHandler)
38 | : base(framedClient, messageIdCache, packetSerializer)
39 | {
40 |
41 | this.packetSerializationHandler = new StacksSerializationHandler(
42 | messageIdCache,
43 | this,
44 | packetSerializer,
45 | messageHandler);
46 |
47 | this.framedClient.Received.Subscribe(PacketReceived);
48 | }
49 |
50 | private unsafe void PacketReceived(ArraySegment buffer)
51 | {
52 | fixed (byte* b = &buffer.Array[buffer.Offset])
53 | {
54 | int messageId = *((int*)b);
55 | using (var ms = new MemoryStream(buffer.Array, buffer.Offset + 4, buffer.Count - 4))
56 | {
57 | this.packetSerializationHandler.Deserialize(messageId, ms);
58 | }
59 | }
60 | }
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/Stacks/Client/Tcp/MessageClientBase.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.IO;
4 | using System.Linq;
5 | using System.Net;
6 | using System.Reactive;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace Stacks.Tcp
11 | {
12 | public abstract class MessageClientBase : IMessageClient
13 | {
14 | protected readonly IFramedClient framedClient;
15 | protected readonly IMessageIdCache messageIdCache;
16 | protected readonly IStacksSerializer packetSerializer;
17 |
18 |
19 | public IExecutor Executor => framedClient.Executor;
20 | public bool IsConnected => framedClient.IsConnected;
21 |
22 | public IObservable Connected => framedClient.Connected;
23 | public IObservable Disconnected => framedClient.Disconnected;
24 | public IObservable Sent => framedClient.Sent;
25 |
26 | public IPEndPoint LocalEndPoint => framedClient.LocalEndPoint;
27 | public IPEndPoint RemoteEndPoint => framedClient.RemoteEndPoint;
28 |
29 | protected MessageClientBase(IFramedClient client, IMessageIdCache messageIdCache,
30 | IStacksSerializer packetSerializer)
31 | {
32 | this.framedClient = client;
33 | this.messageIdCache = messageIdCache;
34 | this.packetSerializer = packetSerializer;
35 | }
36 |
37 | public IObservable Connect(IPEndPoint endPoint) => framedClient.Connect(endPoint);
38 | public IObservable Connect(string endPoint) => Connect(endPoint);
39 |
40 | public void Close() => framedClient.Close();
41 |
42 | public unsafe void Send(T obj)
43 | {
44 | var messageId = messageIdCache.GetMessageId();
45 |
46 | using (var ms = new MemoryStream())
47 | {
48 | ms.SetLength(4);
49 | ms.Position = 4;
50 | this.packetSerializer.Serialize(obj, ms);
51 | ms.Position = 0;
52 |
53 | var buffer = ms.GetBuffer();
54 |
55 | fixed (byte* buf = buffer)
56 | {
57 | int* iBuf = (int*)buf;
58 | *iBuf = messageId;
59 | }
60 |
61 | this.framedClient.SendPacket(new ArraySegment(buffer, 0, (int)ms.Length));
62 | }
63 | }
64 |
65 | public void PreLoadTypesFromAssemblyOfType()
66 | {
67 | messageIdCache.PreLoadTypesFromAssemblyOfType();
68 | }
69 |
70 | public void PreLoadType()
71 | {
72 | messageIdCache.PreLoadType();
73 | }
74 |
75 | public void PreLoadType(Type type)
76 | {
77 | messageIdCache.PreLoadType(type);
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Stacks/Client/Tcp/ReactiveClientModelBuilder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Linq.Expressions;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace Stacks
9 | {
10 | public class ReactiveClientModelBuilder
11 | {
12 | private Dictionary