{"id":15493487,"url":"https://github.com/sinclairzx81/reactor","last_synced_at":"2025-04-22T20:11:50.683Z","repository":{"id":14104415,"uuid":"16808893","full_name":"sinclairzx81/reactor","owner":"sinclairzx81","description":"Asynchronous Event Driven IO for .NET","archived":false,"fork":false,"pushed_at":"2019-10-17T05:52:41.000Z","size":1147,"stargazers_count":44,"open_issues_count":2,"forks_count":13,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-04-22T20:11:48.588Z","etag":null,"topics":["async","dotnet","io","nodejs","sockets"],"latest_commit_sha":null,"homepage":"","language":"C#","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/sinclairzx81.png","metadata":{"files":{"readme":"readme.md","changelog":null,"contributing":null,"funding":null,"license":"license.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2014-02-13T16:24:54.000Z","updated_at":"2023-12-30T05:06:34.000Z","dependencies_parsed_at":"2022-09-21T05:31:48.045Z","dependency_job_id":null,"html_url":"https://github.com/sinclairzx81/reactor","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinclairzx81%2Freactor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinclairzx81%2Freactor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinclairzx81%2Freactor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/sinclairzx81%2Freactor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/sinclairzx81","download_url":"https://codeload.github.com/sinclairzx81/reactor/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250316056,"owners_count":21410476,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","dotnet","io","nodejs","sockets"],"created_at":"2024-10-02T08:07:09.292Z","updated_at":"2025-04-22T20:11:50.664Z","avatar_url":"https://github.com/sinclairzx81.png","language":"C#","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Reactor\n\n## Asynchronous event driven IO for .net\n\n```csharp\nReactor.Loop.Start();\n\nvar server = Reactor.Http.Server.Create(context =\u003e {\n\n\tcontext.Response.Write(\"hello world!!\");\n\n\tcontext.Response.End();\n\t\n}).Listen(8080);\n```\n\n### overview\n\nReactor is a event driven, asynchronous io and networking framework written for Microsoft.Net, Mono, Xamarin, and Unity3D\nplatforms. Reactor is heavily influenced by libuv and nodejs, and aims to mirror both their feature set, and ultimately \nprovide easy interoperability between .net applications and real-time network services.\n\nReactor is specifically written to target .net applications running versions as low as 2.0. Developers can \nleverage Reactor to both consume realtime network services, as well as expose realtime services of their own.\n\n[download reactor 0.9](https://s3.amazonaws.com/sinclair-code/reactor-0.9.zip \"download 0.9\")\n\n### contents\n\n* [getting started](#getting_started)\n\t* [the event loop](#getting_started_event_loop)\n\t* [console applications](#getting_started_console_applications)\n\t* [windows forms applications](#getting_started_windows_forms_applications)\n\t* [unity3D applications](#getting_started_unity3D_applications)\n* [timers](#timers)\n\t* [timeout](#timers_timeout)\n\t* [interval](#timers_interval)\n* [buffers](#buffers)\n* [streams](#streams)\n\t* [readstream](#streams_readstream)\n\t* [writestream](#streams_writestream)\n* [files](#files)\n\t* [readstream](#file_readstream)\n\t* [writestream](#file_writestream)\n* [http](#http)\n\t* [server](#http_server)\n\t\t* [request](#http_server_request)\n\t\t* [response](#http_server_response)\n\t* [requests](#http_requests)\n* [tcp](#tcp)\n\t* [server](#tcp_server)\n\t* [socket](#tcp_socket)\n* [udp](#udp)\n\t* [socket](#udp_socket)\n\n\u003ca name='getting_started' /\u003e\n\n### getting started\n\nThe following section describes setting up a Reactor application.\n\n\u003ca name='getting_started_event_loop' /\u003e\n\n#### the event loop\n\nAt its core, reactor requires that users start an event loop. The reactor event loop internally demultiplexes asynchronous callback \noperations back to the caller. The following describes recommended approaches to running a loop.\n\n\u003ca name='getting_started_console_applications' /\u003e\n\n#### console applications\n\nThe following describes running a reactor event loop in a typical console application. Calling Reactor.Loop.Start()\nwill begin a background thread which will enumerate reactors internal event queue. By doing this, reactor will dispatch \nany asynchronous completation callbacks to the caller. The in example below, we start the loop, make a request to google, \nthen (optionally) stop the loop. \n\n```csharp\nclass Program \n{\n\tstatic void Main(string [] args)\n\t{\n\t\tReactor.Loop.Start();\n\n        Reactor.Http.Request.Get(\"http://google.com\", (exception, buffer) =\u003e {\n\n\t\t\tConsole.WriteLine(buffer.ToString(\"utf8\"));\n\n\t\t\tReactor.Loop.Stop(); // optional\n        });\n\t}\n}\n```\n\n\u003ca name='getting_started_windows_forms_applications' /\u003e\n\n#### windows forms applications\n\nWhen developing UI applications, handling asynchronous callbacks typically requires the developer to manage \nsynchronization back on the application UI thread by way of a synchronization context. Reactor provides a \nconvienient overload for starting loops that accepts a System.Threading.SynchronizationContext as a argument. \nIn the example below, the loop is started with System.Threading.SynchronizationContext.Current on OnLoad(). \nThis ensures that all async completations are always returned to the UI thread.\n\n```csharp\npublic partial class Form1 : Form\n{\n    public Form1()\n    {\n        InitializeComponent();\n    }\n\n    protected override void OnLoad(EventArgs e)\n    {\n        base.OnLoad(e);\n\n        Reactor.Loop.Start(System.Threading.SynchronizationContext.Current);\n    }\n\n    private void button1_Click(object sender, EventArgs e)\n    {\n        Reactor.Http.Request.Get(\"http://google.com\", (exception, buffer) =\u003e {\n\n\t\t\tthis.textbox1.Text = buffer.ToString(\"utf8\");\n        });\n    }\n}\n```\n\n\u003ca name='getting_started_unity3D_applications' /\u003e\n\n#### unity3D applications\n\nIn Unity3D, a SynchronizationContext is not available to developers. Rather, Unity3D requires developers to \nuse cooroutines to orchestrate asynchrony. In these scenarios, Reactor provides a Reactor.Loop.Enumerator() that\nUnity can use to enumerate completed asynchronous operations. The example below demonstrates how.\n\n```csharp\nusing UnityEngine;\nusing System.Collections;\n\npublic class MyGameObject : MonoBehaviour {\n\t\n\tvoid Start () {\n\t\t\n        Reactor.Http.Request.Get(\"http://google.com\", (exception, buffer) =\u003e {\n\n\t\t\t// ready to go!!\n        });\n\t}\n\t\n\tvoid Update () {\n\n\t\tStartCoroutine ( Reactor.Loop.Enumerator() );\n\t}\n}\n```\n\n\u003ca name='timers' /\u003e\n\n### timers\n\nReactor comes bundled with two timing primitives, Timeouts and Intervals. These are\nfashioned after javascript setTimeout() and setInterval() respectively. \n\n\u003ca name='timers_timeout' /\u003e\n\n#### timeouts\n\nUse the Timeout class set a delay.\n\n```csharp\nReactor.Timeout.Create(() =\u003e {\n\n\tConsole.WriteLine(\"this code will be run in 1 second\");\n\n}, 1000);\n```\n\n\u003ca name='timers_interval' /\u003e\n\n#### intervals\n\nUse the Interval class setup a repeating interval.\n\n```csharp\nReactor.Interval.Create(() =\u003e {\n\n\tConsole.WriteLine(\"this code will be run every 2 seconds\");\n\n}, 2000);\n```\n\nAdditionally, Intervals can be cleared...\n\n```csharp\nReactor.Interval interval = null;\n\ninterval = Reactor.Interval.Create(() =\u003e {\n\n\tConsole.WriteLine(\"this code will be run once\");\n\n\tinterval.Clear();\n\t\n}, 2000);\n```\n\u003ca name='buffers' /\u003e\n\n### buffers\n\nReactor has a single buffer primitive which is used to buffer data in memory, and to act as\na container for data transmitted via a stream. The buffer contains read and write operations, \nand is type passed back on all OnData events.\n\n```csharp\nReactor.Tcp.Server.Create(socket =\u003e {\n\t\n\tsocket.OnData += data =\u003e {\n\t\n\t\t// data is of type Reactor.Buffer\n\t};\n\n    var buffer = Reactor.Buffer.Create();\n\n    buffer.Write(10.0f);\n\n    buffer.Write(20.0f);\n\n    buffer.Write(30.0f);\n\n    socket.Write(buffer);\n\n}).Listen(5000);\n```\n\n\u003ca name='streams' /\u003e\n\n### streams\n\nReactor aligns closely with the evented io model found in nodejs. Reactor implements IReadable, \nIWriteable, or IDuplexable interfaces across file io, tcp, http request / response, stdio etc, with \nthe intent of enabling effecient, evented piping of data across transports.\n\n```csharp\nReactor.Http.Server.Create(context =\u003e {\n\n\tvar readstream = Reactor.File.ReadStream.Create(\"c:/video.mp4\");\n\n    context.Response.ContentLength = readstream.Length;\n\n    context.Response.ContentType = \"video/mp4\";\n\n    readstream.Pipe(context.Response);\n\n}).Listen(8080);\n```\n\n\u003ca name='streams_readstream' /\u003e\n\n#### IReadable\n\nSupports OnData, OnEnd and OnError events. As well as Pause(), Resume() and Pipe().\n\nThe following demonstrates opening a file as a readstream.\n\n```csharp\nvar readstream = Reactor.File.ReadStream.Create(\"myfile.txt\");\n\nreadstream.OnData += (data) =\u003e { \n\t\n\t// fired when we have read data from the file system.\n};\n\nreadstream.OnEnd += () =\u003e { \n\n\t// fired when we have read to the end of the file.\n};\n\nreadstream.OnError += (error) =\u003e { \n\t\n\t// fired on error. error is of type System.Exception.\n};\n```\n\n\u003ca name='streams_writestream' /\u003e\n\n#### IWriteable\n\nSupports Write(), Flush() and End() operations on a underlying stream.\n\n```csharp\nvar writestream = Reactor.File.WriteStream.Create(\"myfile.txt\");\n\nwritestream.Write(\"hello\");\n\nwritestream.Write(123);\n\nwritestream.Write(new byte[] {0, 1, 2, 3});\n\nwritestream.End();\n```\n\n\u003ca name='files' /\u003e\n\n### files\n\nReactor provides a evented abstraction for the .net type System.IO.FileStream. The following outlines its use.\n\n\u003ca name='files_readstream' /\u003e\n\n#### readstream\n\nThe following creates a reactor file readstream. The example outputs its contents to the console window.\n\n```csharp\nvar readstream = Reactor.File.ReadStream.Create(\"input.txt\");\n\nreadstream.OnData += (data) =\u003e Console.Write(data.ToString(\"utf8\"));\n\nreadstream.OnEnd  += ()     =\u003e Console.Write(\"finished reading\");\n```\n\n\u003ca name='files_writestream' /\u003e\n\n#### writestream\n\nThe followinf creates a reactor file writestream. The example writes data and ends the stream when complete.\n\n```csharp\nvar writestream = Reactor.File.WriteStream.Create(\"output.txt\");\n\nwritestream.Write(\"hello world\");\n\nwritestream.End();\n\n```\n\n\u003ca name='http' /\u003e\n\n### http\n\nReactor provides a evented abstraction over the http bcl classes.\n\n\u003ca name='http_server' /\u003e\n\n#### server\n\nThe following will create a simple http server and listen on port 8080.\n\n```csharp\nvar server = Reactor.Http.Server.Create(context =\u003e {\n\n    context.Response.Write(\"hello world\");\n\n    context.Response.End();\n\n}).Listen(8080);\n```\n\nThe reactor http server passes a 'context' for each request. The context object contains Request, Response objects, which \nare in themselves, implementations of IReadable and IWritable respectively.\n\n\u003ca name='http_request' /\u003e\n\n#### request\n\nReactor provides a evented abstraction over both HttpWebRequest and HttpWebResponse classes. \n\nMake a GET request.\n```csharp\nvar request = Reactor.Http.Request.Create(\"http://domain.com\", (response) =\u003e {\n\n\tresponse.OnData += (data) =\u003e Console.WriteLine(data.ToString(Encoding.UTF8));\n\n\tresponse.OnEnd += ()      =\u003e Console.WriteLine(\"the response has ended\");\n\n});\n\nrequest.End(); // signals to make the request.\n```\nMake a POST request\n\n```csharp\nvar request = Reactor.Http.Request.Create(\"http://domain.com\", (response) =\u003e {\n\n    response.OnData += (data) =\u003e Console.WriteLine(data.ToString(Encoding.UTF8));\n        \n});\n\nbyte[] postdata = System.Text.Encoding.UTF8.GetBytes(\"this is some data\");\n\nrequest.Method         = \"POST\";\n\nrequest.ContentLength  = postdata.Length;\n\nrequest.Write(postdata);\n\nrequest.End();\n```\n\n\n\u003ca name='tcp' /\u003e\n\n### tcp\n\nReactor provides a evented abstraction over the System.Net.Sockets.Socket TCP socket.\n\n\u003ca name='tcp_server' /\u003e\n\n#### server\n\nCreate a tcp socket server. The following example emits the message \"hello world\" to a connecting client, \nthen closes the connection with End().\n\n```csharp\nReactor.Tcp.Server.Create(socket =\u003e {\n\n\tsocket.Write(\"hello there\");\n\t\n\tsocket.End();\n\n}).Listen(5000);\n```\n\n\u003ca name='tcp_socket' /\u003e\n\n#### socket\n\nReactor tcp sockets are evented abstractions over System.Net.Socket.Socket. Tcp sockets are implementations\nof type IDuplexable. The following code connects to the server in the previous example. (assumed to be both on localhost)\n\n```csharp\nvar client = Reactor.Tcp.Socket.Create(5000);\n\nclient.OnConnect += () =\u003e { // wait for connection.\n\n    client.OnData += (d) =\u003e Console.WriteLine(d.ToString(\"utf8\"));\n\n    client.OnEnd  += ()  =\u003e Console.WriteLine(\"tcp transport closed\");\n};\n```\n\n\u003ca name='udp' /\u003e\n\n### udp\n\nReactor provides a evented abstraction over a System.Net.Sockets.Socket for UDP sockets. The following \ndemonstrates setting up two udp endpoints, and exchanging messages between both.\n\n\u003ca name='udp_socket' /\u003e\n\n#### socket\n\nThe following demonstrates setting up two sockets, one to connect to the other.\n\n```csharp\n//--------------------------------------------------\n// socket a: create a udp socket and bind to port. \n// on receiving a message. print to console.\n//--------------------------------------------------\n\nvar a = Reactor.Udp.Socket.Create();\n            \na.Bind(System.Net.IPAddress.Any, 5000);\n           \na.OnMessage += (remote_endpoint, message) =\u003e {\n\n    Console.WriteLine(System.Text.Encoding.UTF8.GetString(message));\n};\n\n//--------------------------------------------------\n// socket b: create a udp socket and send message\n// to port localhost on port 5000.\n//--------------------------------------------------\n\nvar b = Reactor.Udp.Socket.Create();\n\nb.Send(IPAddress.Loopback, 5000, System.Text.Encoding.UTF8.GetBytes(\"hello from b\"));\n\n```\n\n\u003ca name='threads' /\u003e\n\n### threads\n\nReactor has the ability to execute threads within the applications thread pool.\n\n\u003ca name='threads_worker' /\u003e\n\n#### async tasks\n\nIn the following example, a 'task' is created which accepts an integer argument, and returns a integer. Inside the \nbody of the task, Thread.Sleep() is invoked to emulate some long running computation.\n\n```csharp\nvar task = Reactor.Async.Task\u003cint, int\u003e(interval =\u003e {\n\n    Thread.Sleep(interval); // run computation here !\n\n    return 0;\n});\n```\nOnce the task has been created, the user can invoke the process with the following.\n\n```csharp\ntask(10000, (error, result) =\u003e {\n\n    Console.WriteLine(result);\n});\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsinclairzx81%2Freactor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsinclairzx81%2Freactor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsinclairzx81%2Freactor/lists"}