wj_eventmachine 1.3.0.dev.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (180) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +179 -0
  3. data/GNU +281 -0
  4. data/LICENSE +60 -0
  5. data/README.md +110 -0
  6. data/docs/DocumentationGuidesIndex.md +27 -0
  7. data/docs/GettingStarted.md +520 -0
  8. data/docs/old/ChangeLog +211 -0
  9. data/docs/old/DEFERRABLES +246 -0
  10. data/docs/old/EPOLL +141 -0
  11. data/docs/old/INSTALL +13 -0
  12. data/docs/old/KEYBOARD +42 -0
  13. data/docs/old/LEGAL +25 -0
  14. data/docs/old/LIGHTWEIGHT_CONCURRENCY +130 -0
  15. data/docs/old/PURE_RUBY +75 -0
  16. data/docs/old/RELEASE_NOTES +94 -0
  17. data/docs/old/SMTP +4 -0
  18. data/docs/old/SPAWNED_PROCESSES +148 -0
  19. data/docs/old/TODO +8 -0
  20. data/examples/guides/getting_started/01_eventmachine_echo_server.rb +18 -0
  21. data/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb +22 -0
  22. data/examples/guides/getting_started/03_simple_chat_server.rb +149 -0
  23. data/examples/guides/getting_started/04_simple_chat_server_step_one.rb +27 -0
  24. data/examples/guides/getting_started/05_simple_chat_server_step_two.rb +43 -0
  25. data/examples/guides/getting_started/06_simple_chat_server_step_three.rb +98 -0
  26. data/examples/guides/getting_started/07_simple_chat_server_step_four.rb +121 -0
  27. data/examples/guides/getting_started/08_simple_chat_server_step_five.rb +141 -0
  28. data/examples/old/ex_channel.rb +43 -0
  29. data/examples/old/ex_queue.rb +2 -0
  30. data/examples/old/ex_tick_loop_array.rb +15 -0
  31. data/examples/old/ex_tick_loop_counter.rb +32 -0
  32. data/examples/old/helper.rb +2 -0
  33. data/ext/binder.cpp +124 -0
  34. data/ext/binder.h +52 -0
  35. data/ext/cmain.cpp +1046 -0
  36. data/ext/ed.cpp +2238 -0
  37. data/ext/ed.h +460 -0
  38. data/ext/em.cpp +2378 -0
  39. data/ext/em.h +266 -0
  40. data/ext/eventmachine.h +152 -0
  41. data/ext/extconf.rb +285 -0
  42. data/ext/fastfilereader/extconf.rb +120 -0
  43. data/ext/fastfilereader/mapper.cpp +214 -0
  44. data/ext/fastfilereader/mapper.h +59 -0
  45. data/ext/fastfilereader/rubymain.cpp +126 -0
  46. data/ext/kb.cpp +79 -0
  47. data/ext/page.cpp +107 -0
  48. data/ext/page.h +51 -0
  49. data/ext/pipe.cpp +354 -0
  50. data/ext/project.h +174 -0
  51. data/ext/rubymain.cpp +1610 -0
  52. data/ext/ssl.cpp +627 -0
  53. data/ext/ssl.h +103 -0
  54. data/ext/wait_for_single_fd.h +36 -0
  55. data/java/.classpath +8 -0
  56. data/java/.project +17 -0
  57. data/java/src/com/rubyeventmachine/EmReactor.java +625 -0
  58. data/java/src/com/rubyeventmachine/EmReactorException.java +40 -0
  59. data/java/src/com/rubyeventmachine/EmReactorInterface.java +70 -0
  60. data/java/src/com/rubyeventmachine/EventableChannel.java +72 -0
  61. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +201 -0
  62. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +415 -0
  63. data/java/src/com/rubyeventmachine/NullEmReactor.java +157 -0
  64. data/java/src/com/rubyeventmachine/NullEventableChannel.java +81 -0
  65. data/lib/em/buftok.rb +59 -0
  66. data/lib/em/callback.rb +58 -0
  67. data/lib/em/channel.rb +69 -0
  68. data/lib/em/completion.rb +307 -0
  69. data/lib/em/connection.rb +776 -0
  70. data/lib/em/deferrable.rb +210 -0
  71. data/lib/em/deferrable/pool.rb +2 -0
  72. data/lib/em/file_watch.rb +73 -0
  73. data/lib/em/future.rb +61 -0
  74. data/lib/em/io_streamer.rb +68 -0
  75. data/lib/em/iterator.rb +252 -0
  76. data/lib/em/messages.rb +66 -0
  77. data/lib/em/pool.rb +151 -0
  78. data/lib/em/process_watch.rb +45 -0
  79. data/lib/em/processes.rb +123 -0
  80. data/lib/em/protocols.rb +37 -0
  81. data/lib/em/protocols/header_and_content.rb +138 -0
  82. data/lib/em/protocols/httpclient.rb +303 -0
  83. data/lib/em/protocols/httpclient2.rb +602 -0
  84. data/lib/em/protocols/line_and_text.rb +125 -0
  85. data/lib/em/protocols/line_protocol.rb +33 -0
  86. data/lib/em/protocols/linetext2.rb +179 -0
  87. data/lib/em/protocols/memcache.rb +331 -0
  88. data/lib/em/protocols/object_protocol.rb +46 -0
  89. data/lib/em/protocols/postgres3.rb +246 -0
  90. data/lib/em/protocols/saslauth.rb +175 -0
  91. data/lib/em/protocols/smtpclient.rb +394 -0
  92. data/lib/em/protocols/smtpserver.rb +666 -0
  93. data/lib/em/protocols/socks4.rb +66 -0
  94. data/lib/em/protocols/stomp.rb +205 -0
  95. data/lib/em/protocols/tcptest.rb +54 -0
  96. data/lib/em/pure_ruby.rb +1299 -0
  97. data/lib/em/queue.rb +80 -0
  98. data/lib/em/resolver.rb +232 -0
  99. data/lib/em/spawnable.rb +84 -0
  100. data/lib/em/streamer.rb +118 -0
  101. data/lib/em/threaded_resource.rb +90 -0
  102. data/lib/em/tick_loop.rb +85 -0
  103. data/lib/em/timers.rb +61 -0
  104. data/lib/em/version.rb +3 -0
  105. data/lib/eventmachine.rb +1602 -0
  106. data/lib/jeventmachine.rb +318 -0
  107. data/rakelib/package.rake +120 -0
  108. data/rakelib/test.rake +6 -0
  109. data/rakelib/test_pure.rake +11 -0
  110. data/tests/client.crt +31 -0
  111. data/tests/client.key +51 -0
  112. data/tests/dhparam.pem +13 -0
  113. data/tests/em_ssl_handlers.rb +153 -0
  114. data/tests/em_test_helper.rb +198 -0
  115. data/tests/jruby/test_jeventmachine.rb +38 -0
  116. data/tests/test_attach.rb +199 -0
  117. data/tests/test_basic.rb +321 -0
  118. data/tests/test_channel.rb +75 -0
  119. data/tests/test_completion.rb +178 -0
  120. data/tests/test_connection_count.rb +83 -0
  121. data/tests/test_connection_write.rb +35 -0
  122. data/tests/test_defer.rb +35 -0
  123. data/tests/test_deferrable.rb +35 -0
  124. data/tests/test_epoll.rb +141 -0
  125. data/tests/test_error_handler.rb +38 -0
  126. data/tests/test_exc.rb +37 -0
  127. data/tests/test_file_watch.rb +86 -0
  128. data/tests/test_fork.rb +75 -0
  129. data/tests/test_futures.rb +170 -0
  130. data/tests/test_handler_check.rb +35 -0
  131. data/tests/test_hc.rb +155 -0
  132. data/tests/test_httpclient.rb +238 -0
  133. data/tests/test_httpclient2.rb +132 -0
  134. data/tests/test_idle_connection.rb +31 -0
  135. data/tests/test_inactivity_timeout.rb +102 -0
  136. data/tests/test_io_streamer.rb +47 -0
  137. data/tests/test_ipv4.rb +96 -0
  138. data/tests/test_ipv6.rb +107 -0
  139. data/tests/test_iterator.rb +122 -0
  140. data/tests/test_kb.rb +28 -0
  141. data/tests/test_keepalive.rb +113 -0
  142. data/tests/test_line_protocol.rb +33 -0
  143. data/tests/test_ltp.rb +155 -0
  144. data/tests/test_ltp2.rb +332 -0
  145. data/tests/test_many_fds.rb +21 -0
  146. data/tests/test_next_tick.rb +104 -0
  147. data/tests/test_object_protocol.rb +36 -0
  148. data/tests/test_pause.rb +109 -0
  149. data/tests/test_pending_connect_timeout.rb +52 -0
  150. data/tests/test_pool.rb +196 -0
  151. data/tests/test_process_watch.rb +50 -0
  152. data/tests/test_processes.rb +128 -0
  153. data/tests/test_proxy_connection.rb +180 -0
  154. data/tests/test_pure.rb +156 -0
  155. data/tests/test_queue.rb +64 -0
  156. data/tests/test_resolver.rb +129 -0
  157. data/tests/test_running.rb +14 -0
  158. data/tests/test_sasl.rb +46 -0
  159. data/tests/test_send_file.rb +217 -0
  160. data/tests/test_servers.rb +32 -0
  161. data/tests/test_shutdown_hooks.rb +23 -0
  162. data/tests/test_smtpclient.rb +75 -0
  163. data/tests/test_smtpserver.rb +90 -0
  164. data/tests/test_sock_opt.rb +53 -0
  165. data/tests/test_spawn.rb +290 -0
  166. data/tests/test_ssl_args.rb +41 -0
  167. data/tests/test_ssl_dhparam.rb +57 -0
  168. data/tests/test_ssl_ecdh_curve.rb +57 -0
  169. data/tests/test_ssl_extensions.rb +24 -0
  170. data/tests/test_ssl_methods.rb +31 -0
  171. data/tests/test_ssl_protocols.rb +190 -0
  172. data/tests/test_ssl_verify.rb +52 -0
  173. data/tests/test_stomp.rb +38 -0
  174. data/tests/test_system.rb +46 -0
  175. data/tests/test_threaded_resource.rb +68 -0
  176. data/tests/test_tick_loop.rb +58 -0
  177. data/tests/test_timers.rb +150 -0
  178. data/tests/test_ud.rb +8 -0
  179. data/tests/test_unbind_reason.rb +40 -0
  180. metadata +384 -0
data/LICENSE ADDED
@@ -0,0 +1,60 @@
1
+ EventMachine is copyrighted free software owned by Francis Cianfrocca
2
+ (blackhedd ... gmail.com). The Owner of this software permits you to
3
+ redistribute and/or modify the software under either the terms of the GPL
4
+ version 2 (see the file GPL), or the conditions below ("Ruby License"):
5
+
6
+ 1. You may make and give away verbatim copies of the source form of this
7
+ software without restriction, provided that you retain ALL of the
8
+ original copyright notices and associated disclaimers.
9
+
10
+ 2. You may modify your copy of the software in any way, provided that
11
+ you do at least ONE of the following:
12
+
13
+ a) place your modifications in the Public Domain or otherwise
14
+ make them Freely Available, such as by posting said
15
+ modifications to Usenet or an equivalent medium, or by allowing
16
+ the author to include your modifications in the software.
17
+
18
+ b) use the modified software only within your corporation or
19
+ organization.
20
+
21
+ c) give non-standard binaries non-standard names, with
22
+ instructions on where to get the original software distribution.
23
+
24
+ d) make other distribution arrangements with the Owner.
25
+
26
+ 3. You may distribute the software in object code or binary form,
27
+ provided that you do at least ONE of the following:
28
+
29
+ a) distribute the binaries and library files of the software,
30
+ together with instructions (in a manual page or equivalent)
31
+ on where to get the original distribution.
32
+
33
+ b) accompany the distribution with the machine-readable source of
34
+ the software.
35
+
36
+ c) give non-standard binaries non-standard names, with
37
+ instructions on where to get the original software distribution.
38
+
39
+ d) make other distribution arrangements with the Owner.
40
+
41
+ 4. You may modify and include parts of the software into any other
42
+ software (possibly commercial), provided you comply with the terms in
43
+ Sections 1, 2, and 3 above. But some files in the distribution
44
+ are not written by the Owner, so they may be made available to you
45
+ under different terms.
46
+
47
+ For the list of those files and their copying conditions, see the
48
+ file LEGAL.
49
+
50
+ 5. The scripts and library files supplied as input to or produced as
51
+ output from the software do not automatically fall under the
52
+ copyright of the software, but belong to whoever generated them,
53
+ and may be sold commercially, and may be aggregated with this
54
+ software.
55
+
56
+ 6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
57
+ IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
58
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
59
+ PURPOSE.
60
+
@@ -0,0 +1,110 @@
1
+ # About EventMachine [![Build Status](https://travis-ci.org/eventmachine/eventmachine.svg?branch=master)](https://travis-ci.org/eventmachine/eventmachine) [![Code Climate Maintainability](https://api.codeclimate.com/v1/badges/e9b0603462905d5b9118/maintainability)](https://codeclimate.com/github/eventmachine/eventmachine/maintainability)
2
+
3
+
4
+ ## What is EventMachine ##
5
+
6
+ EventMachine is an event-driven I/O and lightweight concurrency library for Ruby.
7
+ It provides event-driven I/O using the [Reactor pattern](http://en.wikipedia.org/wiki/Reactor_pattern),
8
+ much like [JBoss Netty](http://www.jboss.org/netty), [Apache MINA](http://mina.apache.org/),
9
+ Python's [Twisted](http://twistedmatrix.com), [Node.js](http://nodejs.org), libevent and libev.
10
+
11
+ EventMachine is designed to simultaneously meet two key needs:
12
+
13
+ * Extremely high scalability, performance and stability for the most demanding production environments.
14
+ * An API that eliminates the complexities of high-performance threaded network programming,
15
+ allowing engineers to concentrate on their application logic.
16
+
17
+ This unique combination makes EventMachine a premier choice for designers of critical networked
18
+ applications, including Web servers and proxies, email and IM production systems, authentication/authorization
19
+ processors, and many more.
20
+
21
+ EventMachine has been around since the early 2000s and is a mature and battle-tested library.
22
+
23
+
24
+ ## What EventMachine is good for? ##
25
+
26
+ * Scalable event-driven servers. Examples: [Thin](http://code.macournoyer.com/thin/) or [Goliath](https://github.com/postrank-labs/goliath/).
27
+ * Scalable asynchronous clients for various protocols, RESTful APIs and so on. Examples: [em-http-request](https://github.com/igrigorik/em-http-request) or [amqp gem](https://github.com/ruby-amqp/amqp).
28
+ * Efficient network proxies with custom logic. Examples: [Proxymachine](https://github.com/mojombo/proxymachine/).
29
+ * File and network monitoring tools. Examples: [eventmachine-tail](https://github.com/jordansissel/eventmachine-tail) and [logstash](https://github.com/logstash/logstash).
30
+
31
+
32
+
33
+ ## What platforms are supported by EventMachine? ##
34
+
35
+ EventMachine supports Ruby 2.0.0 through 2.7, JRuby and **works well on Windows** as well
36
+ as many operating systems from the Unix family (Linux, Mac OS X, BSD flavors).
37
+
38
+
39
+
40
+ ## Install the gem ##
41
+
42
+ Install it with [RubyGems](https://rubygems.org/)
43
+
44
+ gem install eventmachine
45
+
46
+ or add this to your Gemfile if you use [Bundler](http://gembundler.com/):
47
+
48
+ gem 'eventmachine'
49
+
50
+
51
+
52
+ ## Getting started ##
53
+
54
+ For an introduction to EventMachine, check out:
55
+
56
+ * [blog post about EventMachine by Ilya Grigorik](http://www.igvita.com/2008/05/27/ruby-eventmachine-the-speed-demon/).
57
+ * [EventMachine Introductions by Dan Sinclair](http://everburning.com/news/eventmachine-introductions.html).
58
+
59
+
60
+ ### Server example: Echo server ###
61
+
62
+ Here's a fully-functional echo server written with EventMachine:
63
+
64
+ ```ruby
65
+ require 'eventmachine'
66
+
67
+ module EchoServer
68
+ def post_init
69
+ puts "-- someone connected to the echo server!"
70
+ end
71
+
72
+ def receive_data data
73
+ send_data ">>>you sent: #{data}"
74
+ close_connection if data =~ /quit/i
75
+ end
76
+
77
+ def unbind
78
+ puts "-- someone disconnected from the echo server!"
79
+ end
80
+ end
81
+
82
+ # Note that this will block current thread.
83
+ EventMachine.run {
84
+ EventMachine.start_server "127.0.0.1", 8081, EchoServer
85
+ }
86
+ ```
87
+
88
+
89
+ ## EventMachine documentation ##
90
+
91
+ Currently we only have [reference documentation](http://rdoc.info/github/eventmachine/eventmachine/frames) and a [wiki](https://github.com/eventmachine/eventmachine/wiki).
92
+
93
+
94
+ ## Community and where to get help ##
95
+
96
+ * Join the [mailing list](http://groups.google.com/group/eventmachine) (Google Group)
97
+ * Join IRC channel #eventmachine on irc.freenode.net
98
+
99
+
100
+ ## License and copyright ##
101
+
102
+ EventMachine is copyrighted free software made available under the terms
103
+ of either the GPL or Ruby's License.
104
+
105
+ Copyright: (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
106
+
107
+
108
+ ## Alternatives ##
109
+
110
+ If you are unhappy with EventMachine and want to use Ruby, check out [Celluloid](https://celluloid.io/).
@@ -0,0 +1,27 @@
1
+ # EventMachine documentation guides #
2
+
3
+ Welcome to the documentation guides for [EventMachine](http://github.com/eventmachine/eventmachine),
4
+ a fast and simple event-processing library for Ruby programs (à la JBoss Netty, Twisted, Node.js
5
+ and so on).
6
+
7
+ ## Guide list ##
8
+
9
+ * {file:docs/GettingStarted.md Getting started with EventMachine}
10
+ * {file:docs/EventDrivenServers.md Writing event-driven servers}
11
+ * {file:docs/EventDrivenClients.md Writing event-driven clients}
12
+ * {file:docs/ConnectionFailureAndRecovery.md Connection Failure and Recovery}
13
+ * {file:docs/TLS.md TLS (aka SSL)}
14
+ * {file:docs/Ecosystem.md EventMachine ecosystem}: Thin, Goliath, em-http-request, em-websockets, Proxymachine and beyond
15
+ * {file:docs/BlockingEventLoop.md On blocking the event loop: why it is harmful for performance and how to avoid it}
16
+ * {file:docs/LightweightConcurrency.md Lightweight concurrency with EventMachine}
17
+ * {file:docs/Deferrables.md Deferrables}
18
+ * {file:docs/ModernKernelInputOutputAPIs.md Brief introduction to epoll, kqueue, select}
19
+ * {file:docs/WorkingWithOtherIOSources.md Working with other IO sources such as the keyboard}
20
+
21
+
22
+ ## Tell us what you think! ##
23
+
24
+ Please take a moment and tell us what you think about this guide on the [EventMachine mailing list](http://bit.ly/jW3cR3)
25
+ or in the #eventmachine channel on irc.freenode.net: what was unclear? What wasn't covered?
26
+ Maybe you don't like the guide style or the grammar and spelling are incorrect? Reader feedback is
27
+ key to making documentation better.
@@ -0,0 +1,520 @@
1
+ # @title Getting Started with Ruby EventMachine
2
+ # @markup markdown
3
+ # @author Michael S. Klishin, Dan Sinclair
4
+
5
+ # Getting started with Ruby EventMachine #
6
+
7
+
8
+ ## About this guide ##
9
+
10
+ This guide is a quick tutorial that helps you to get started with EventMachine for writing event-driven
11
+ servers, clients and using it as a lightweight concurrency library.
12
+ It should take about 20 minutes to read and study the provided code examples. This guide covers
13
+
14
+ * Installing EventMachine via [Rubygems](http://rubygems.org) and [Bundler](http://gembundler.com).
15
+ * Building an Echo server, the "Hello, world"-like code example of network servers.
16
+ * Building a simple chat, both server and client.
17
+ * Building a very small asynchronous Websockets client.
18
+
19
+
20
+ ## Covered versions ##
21
+
22
+ This guide covers EventMachine v0.12.10 and 1.0 (including betas).
23
+
24
+
25
+ ## Level ##
26
+
27
+ This guide assumes you are comfortable (but not necessary a guru) with the command line. On Microsoft Windows™,
28
+ we recommend you to use [JRuby](http://jruby.org) when running these examples.
29
+
30
+
31
+ ## Installing EventMachine ##
32
+
33
+ ### Make sure you have Ruby installed ###
34
+
35
+ This guide assumes you have one of the supported Ruby implementations installed:
36
+
37
+ * Ruby 1.9.2
38
+ * [JRuby](http://jruby.org) (we recommend 1.6)
39
+ * [Rubinius](http://rubini.us) 1.2 or higher
40
+ * [Ruby Enterprise Edition](http://www.rubyenterpriseedition.com)
41
+
42
+ EventMachine works on Microsoft Windows™.
43
+
44
+
45
+ ### With Rubygems ###
46
+
47
+ To install the EventMachine gem do
48
+
49
+ gem install eventmachine
50
+
51
+
52
+ ### With Bundler ###
53
+
54
+ gem "eventmachine"
55
+
56
+
57
+ ### Verifying your installation ###
58
+
59
+ Lets verify your installation with this quick IRB session:
60
+
61
+ irb -rubygems
62
+
63
+ ruby-1.9.2-p180 :001 > require "eventmachine"
64
+ => true
65
+ ruby-1.9.2-p180 :002 > EventMachine::VERSION
66
+ => "1.0.0.beta.3"
67
+
68
+
69
+ ## An Echo Server Example ##
70
+
71
+ Lets begin with the classic "Hello, world"-like example, an echo server. The echo server responds clients with the
72
+ same data that was provided. First, here's the code:
73
+
74
+ {include:file:examples/guides/getting\_started/01\_eventmachine\_echo_server.rb}
75
+
76
+
77
+ When run, the server binds to port 10000. We can connect using Telnet and verify it's working:
78
+
79
+ telnet localhost 10000
80
+
81
+ On my machine the output looks like:
82
+
83
+ ~ telnet localhost 10000
84
+ Trying 127.0.0.1...
85
+ Connected to localhost.
86
+ Escape character is '^]'.
87
+
88
+ Let's send something to our server. Type in "Hello, EventMachine" and hit Enter. The server will respond with
89
+ the same string:
90
+
91
+ ~ telnet localhost 10000
92
+ Trying 127.0.0.1...
93
+ Connected to localhost.
94
+ Escape character is '^]'.
95
+ Hello, EventMachine
96
+ # (here we hit Enter)
97
+ Hello, EventMachine
98
+ # (this ^^^ is our echo server reply)
99
+
100
+ It works! Congratulations, you now can tell your Node.js-loving friends that you "have done some event-driven programming, too".
101
+ Oh, and to stop Telnet, hit Control + Shift + ] and then Control + C.
102
+
103
+ Lets walk this example line by line and see what's going on. These lines
104
+
105
+ require 'rubygems' # or use Bundler.setup
106
+ require 'eventmachine'
107
+
108
+ probably look familiar: you use [RubyGems](http://rubygems.org) (or [Bundler](http://gembundler.com/)) for dependencies and then require EventMachine gem. Boring.
109
+
110
+ Next:
111
+
112
+ class EchoServer < EventMachine::Connection
113
+ def receive_data(data)
114
+ send_data(data)
115
+ end
116
+ end
117
+
118
+ Is the implementation of our echo server. We define a class that inherits from {EventMachine::Connection}
119
+ and a handler (aka callback) for one event: when we receive data from a client.
120
+
121
+ EventMachine handles the connection setup, receiving data and passing it to our handler, {EventMachine::Connection#receive_data}.
122
+
123
+ Then we implement our protocol logic, which in the case of Echo is pretty trivial: we send back whatever we receive.
124
+ To do so, we're using {EventMachine::Connection#send_data}.
125
+
126
+ Lets modify the example to recognize `exit` command:
127
+
128
+ {include:file:examples/guides/getting\_started/02\_eventmachine\_echo_server\_that\_recognizes\_exit\_command.rb}
129
+
130
+ Our `receive\_data` changed slightly and now looks like this:
131
+
132
+ def receive_data(data)
133
+ if data.strip =~ /exit$/i
134
+ EventMachine.stop_event_loop
135
+ else
136
+ send_data(data)
137
+ end
138
+ end
139
+
140
+ Because incoming data has trailing newline character, we strip it off before matching it against a simple regular
141
+ expression. If the data ends in `exit`, we stop EventMachine event loop with {EventMachine.stop_event_loop}. This unblocks
142
+ main thread and it finishes execution, and our little program exits as the result.
143
+
144
+ To summarize this first example:
145
+
146
+ * Subclass {EventMachine::Connection} and override {EventMachine::Connection#send_data} to handle incoming data.
147
+ * Use {EventMachine.run} to start EventMachine event loop and then bind echo server with {EventMachine.start_server}.
148
+ * To stop the event loop, use {EventMachine.stop_event_loop} (aliased as {EventMachine.stop})
149
+
150
+ Lets move on to a slightly more sophisticated example that will introduce several more features and methods
151
+ EventMachine has to offer.
152
+
153
+
154
+ ## A Simple Chat Server Example ##
155
+
156
+ Next we will write a simple chat. Initially clients will still use telnet to connect, but then we will add little
157
+ client application that will serve as a proxy between telnet and the chat server. This example is certainly longer
158
+ (~ 150 lines with whitespace and comments) so instead of looking at the final version and going through it line by line,
159
+ we will instead begin with a very simple version that only keeps track of connected clients and then add features
160
+ as we go.
161
+
162
+ To set some expectations about our example:
163
+
164
+ * It will keep track of connected clients
165
+ * It will support a couple of commands, à la IRC
166
+ * It will support direct messages using Twitter-like @usernames
167
+ * It won't use MongoDB, fibers or distributed map/reduce for anything but will be totally [Web Scale™](http://bit.ly/webscaletm) nonetheless. Maybe even [ROFLscale](http://bit.ly/roflscalevideo).
168
+
169
+ ### Step one: detecting connections and disconnectons ###
170
+
171
+ First step looks like this:
172
+
173
+ {include:file:examples/guides/getting\_started/04\_simple\_chat\_server\_step\_one.rb}
174
+
175
+ We see familiar {EventMachine.run} and {EventMachine.start_server}, but also {EventMachine::Connection#post_init} and {EventMachine::Connection#unbind} we haven't
176
+ met yet. We don't use them in this code, so when are they run? Like {EventMachine::Connection#receive_data}, these methods are callbacks. EventMachine calls them
177
+ when certain events happen:
178
+
179
+ * {EventMachine#post_init} is called by the event loop immediately after the network connection has been established.
180
+ In the chat server example case, this is when a new client connects.
181
+ * {EventMachine#unbind} is called when client disconnects, connection is closed or is lost (because of a network issue, for example).
182
+
183
+ All our chat server does so far is logging connections or disconnections. What we want it to do next is to keep track of connected clients.
184
+
185
+
186
+ ### Step two: keep track of connected clients ###
187
+
188
+ Next iteration of the code looks like this:
189
+
190
+ {include:file:examples/guides/getting\_started/05\_simple\_chat\_server\_step\_two.rb}
191
+
192
+ While the code we added is very straightforward, we have to clarify one this first: subclasses of {EventMachine::Connection} are instantiated by
193
+ EventMachine for every new connected peer. So for 10 connected chat clients, there will be 10 separate `SimpleChatServer` instances in our
194
+ server process. Like any other objects, they can be stored in a collection, can provide public API other objects use, can instantiate or inject
195
+ dependencies and in general live a happy life all Ruby objects live until garbage collection happens.
196
+
197
+ In the example above we use a @@class_variable to keep track of connected clients. In Ruby, @@class variables are accessible from instance
198
+ methods so we can add new connections to the list from `SimpleChatServer#post_init` and remove them in `SimpleChatServer#unbind`. We can also
199
+ filter connections by some criteria, as `SimpleChatServer#other_peers demonstrates`.
200
+
201
+ So, we keep track of connections but how do we identify them? For a chat app, it's pretty common to use usernames for that. Lets ask our clients
202
+ to enter usernames when they connect.
203
+
204
+
205
+ ### Step three: adding usernames ##
206
+
207
+ To add usernames, we need to add a few things:
208
+
209
+ * We need to invite newly connected clients to enter their username.
210
+ * A reader (getter) method on our {EventMachine::Connection} subclass.
211
+ * An idea of connection state (keeping track of whether a particular participant had entered username before).
212
+
213
+ Here is one way to do it:
214
+
215
+ {include:file:examples/guides/getting\_started/06\_simple\_chat\_server\_step\_three.rb}
216
+
217
+ This is quite an update so lets take a look at each method individually. First, `SimpleChatServer#post_init`:
218
+
219
+ def post_init
220
+ @username = nil
221
+ puts "A client has connected..."
222
+ ask_username
223
+ end
224
+
225
+ To keep track of username we ask chat participants for, we add @username instance variable to our connection class. Connection
226
+ instances are just Ruby objects associated with a particular connected peer, so using @ivars is very natural. To make username
227
+ value accessible to other objects, we added a reader method that was not shown on the snippet above.
228
+
229
+ Lets dig into `SimpleChatServer#ask_username`:
230
+
231
+ def ask_username
232
+ self.send_line("[info] Enter your username:")
233
+ end # ask_username
234
+
235
+ # ...
236
+
237
+ def send_line(line)
238
+ self.send_data("#{line}\n")
239
+ end # send_line(line)
240
+
241
+ Nothing new here, we are using {EventMachine::Connection#send_data} which we have seen before.
242
+
243
+
244
+ In `SimpleChatServer#receive_data` we now have to check if the username was entered or we need
245
+ to ask for it:
246
+
247
+ def receive_data(data)
248
+ if entered_username?
249
+ handle_chat_message(data.strip)
250
+ else
251
+ handle_username(data.strip)
252
+ end
253
+ end
254
+
255
+ # ...
256
+
257
+ def entered_username?
258
+ !@username.nil? && !@username.empty?
259
+ end # entered_username?
260
+
261
+ Finally, handler of chat messages is not yet implemented:
262
+
263
+ def handle_chat_message(msg)
264
+ raise NotImplementedError
265
+ end
266
+
267
+ Lets try this example out using Telnet:
268
+
269
+ ~ telnet localhost 10000
270
+ Trying 127.0.0.1...
271
+ Connected to localhost.
272
+ Escape character is '^]'.
273
+ [info] Enter your username:
274
+ antares_
275
+ [info] Ohai, antares_
276
+
277
+ and the server output:
278
+
279
+ A client has connected...
280
+ antares_ has joined
281
+
282
+ This version requires you to remember how to terminate your Telnet session (Ctrl + Shift + ], then Ctrl + C).
283
+ It is annoying, so why don't we add the same `exit` command to our chat server?
284
+
285
+
286
+ ### Step four: adding exit command and delivering chat messages ####
287
+
288
+ {include:file:examples/guides/getting\_started/07\_simple\_chat\_server\_step\_four.rb}
289
+
290
+ TBD
291
+
292
+ Lets test-drive this version. Client A:
293
+
294
+ ~ telnet localhost 10000
295
+ Trying 127.0.0.1...
296
+ Connected to localhost.
297
+ Escape character is '^]'.
298
+ [info] Enter your username:
299
+ michael
300
+ [info] Ohai, michael
301
+ Hi everyone
302
+ michael: Hi everyone
303
+ joe has joined the room
304
+ # here ^^^ client B connects, lets greet him
305
+ hi joe
306
+ michael: hi joe
307
+ joe: hey michael
308
+ # ^^^ client B replies
309
+ exit
310
+ # ^^^ out command in action
311
+ Connection closed by foreign host.
312
+
313
+ Client B:
314
+
315
+ ~ telnet localhost 10000
316
+ Trying 127.0.0.1...
317
+ Connected to localhost.
318
+ Escape character is '^]'.
319
+ [info] Enter your username:
320
+ joe
321
+ [info] Ohai, joe
322
+ michael: hi joe
323
+ # ^^^ client A greets us, lets reply
324
+ hey michael
325
+ joe: hey michael
326
+ exit
327
+ # ^^^ out command in action
328
+ Connection closed by foreign host.
329
+
330
+ And finally, the server output:
331
+
332
+ A client has connected...
333
+ michael has joined
334
+ A client has connected...
335
+ _antares has joined
336
+ [info] _antares has left
337
+ [info] michael has left
338
+
339
+ Our little char server now supports usernames, sending messages and the `exit` command. Next up, private (aka direct) messages.
340
+
341
+
342
+ ### Step five: adding direct messages and one more command ###
343
+
344
+ To add direct messages, we come up with a simple convention: private messages begin with @username and may have optional colon before
345
+ message text, like this:
346
+
347
+ @joe: hey, how do you like eventmachine?
348
+
349
+ This convention makes parsing of messages simple so that we can concentrate on delivering them to a particular client connection.
350
+ Remember when we added `username` reader on our connection class? That tiny change makes this step possible: when a new direct
351
+ message comes in, we extract username and message text and then find then connection for @username in question:
352
+
353
+ #
354
+ # Message handling
355
+ #
356
+
357
+ def handle_chat_message(msg)
358
+ if command?(msg)
359
+ self.handle_command(msg)
360
+ else
361
+ if direct_message?(msg)
362
+ self.handle_direct_message(msg)
363
+ else
364
+ self.announce(msg, "#{@username}:")
365
+ end
366
+ end
367
+ end # handle_chat_message(msg)
368
+
369
+ def direct_message?(input)
370
+ input =~ DM_REGEXP
371
+ end # direct_message?(input)
372
+
373
+ def handle_direct_message(input)
374
+ username, message = parse_direct_message(input)
375
+
376
+ if connection = @@connected_clients.find { |c| c.username == username }
377
+ puts "[dm] @#{@username} => @#{username}"
378
+ connection.send_line("[dm] @#{@username}: #{message}")
379
+ else
380
+ send_line "@#{username} is not in the room. Here's who is: #{usernames.join(', ')}"
381
+ end
382
+ end # handle_direct_message(input)
383
+
384
+ def parse_direct_message(input)
385
+ return [$1, $2] if input =~ DM_REGEXP
386
+ end # parse_direct_message(input)
387
+
388
+ This snippet demonstrates how one connection instance can obtain another connection instance and send data to it.
389
+ This is a very powerful feature, consider just a few use cases:
390
+
391
+ * Peer-to-peer protocols
392
+ * Content-aware routing
393
+ * Efficient streaming with optional filtering
394
+
395
+ Less common use cases include extending C++ core of EventMachine to provide access to hardware that streams events that
396
+ can be re-broadcasted to any interested parties connected via TCP, UDP or something like AMQP or WebSockets. With this,
397
+ sky is the limit. Actually, EventMachine has several features for efficient proxying data between connections.
398
+ We will not cover them in this guide.
399
+
400
+ One last feature that we are going to add to our chat server is the `status` command that tells you current server time and how many people
401
+ are there in the chat room:
402
+
403
+ #
404
+ # Commands handling
405
+ #
406
+
407
+ def command?(input)
408
+ input =~ /(exit|status)$/i
409
+ end # command?(input)
410
+
411
+ def handle_command(cmd)
412
+ case cmd
413
+ when /exit$/i then self.close_connection
414
+ when /status$/i then self.send_line("[chat server] It's #{Time.now.strftime('%H:%M')} and there are #{self.number_of_connected_clients} people in the room")
415
+ end
416
+ end # handle_command(cmd)
417
+
418
+ Hopefully this piece of code is easy to follow. Try adding a few more commands, for example, the `whoishere` command that lists people
419
+ currently in the chat room.
420
+
421
+ In the end, our chat server looks like this:
422
+
423
+ {include:file:examples/guides/getting\_started/08\_simple\_chat\_server\_step\_five.rb}
424
+
425
+ We are almost done with the server but there are some closing thoughts.
426
+
427
+
428
+ ### Step six: final version ###
429
+
430
+ Just in case, here is the final version of the chat server code we have built:
431
+
432
+ {include:file:examples/guides/getting\_started/03\_simple\_chat\_server.rb}
433
+
434
+
435
+ ### Step seven: future directions and some closing thoughts ###
436
+
437
+ The chat server is just about 150 lines of Ruby including empty lines and comments, yet it has a few features most of chat server
438
+ examples never add. We did not, however, implement many other features that popular IRC clients like [Colloquy](http://colloquy.info) have:
439
+
440
+ * Chat moderation
441
+ * Multiple rooms
442
+ * Connection timeout detection
443
+
444
+ How would one go about implementing them? We thought it is worth discussing what else EventMachine has to offer and what ecosystem projects
445
+ one can use to build a really feature-rich Web-based IRC chat client.
446
+
447
+ With multiple rooms it's more or less straightforward, just add one more hash and a bunch of commands and use the information about which rooms participant
448
+ is in when you are delivering messages. There is nothing in EventMachine itself that can make the job much easier for developer.
449
+
450
+ To implement chat moderation feature you may want to do a few things:
451
+
452
+ * Work with client IP addresses. Maybe we want to consider everyone who connects from certain IPs a moderator.
453
+ * Access persistent data about usernames of moderators and their credentials.
454
+
455
+ Does EventMachine have anything to offer here? It does. To obtain peer IP address, take a look at {EventMachine::Connection#get_peername}. The name of this method is
456
+ a little bit misleading and originates from low-level socket programming APIs.
457
+
458
+ #### A whirlwind tour of the EventMachine ecosystem ####
459
+
460
+ To work with data stores you can use several database drivers that ship with EventMachine itself, however, quite often there are some 3rd party projects in
461
+ the EventMachine ecosystem that have more features, are faster or just better maintained. So we figured it will be helpful to provide a few pointers
462
+ to some of those projects:
463
+
464
+ * For MySQL, check out [em-mysql](https://github.com/eventmachine/em-mysql) project.
465
+ * For PostgreSQL, have a look at Mike Perham's [EventMachine-based PostgreSQL driver](https://github.com/mperham/em_postgresql).
466
+ * For Redis, there is a young but already popular [em-hiredis](https://github.com/mloughran/em-hiredis) library that combines EventMachine's non-blocking I/O with
467
+ extreme performance of the official Redis C client, [hiredis](https://github.com/antirez/hiredis).
468
+ * For MongoDB, see [em-mongo](https://github.com/bcg/em-mongo)
469
+ * For Cassandra, Mike Perham [added transport agnosticism feature](http://www.mikeperham.com/2010/02/09/cassandra-and-eventmachine/) to the [cassandra gem](https://rubygems.org/gems/cassandra).
470
+
471
+ [Riak](http://www.basho.com/products_riak_overview.php) and CouchDB talk HTTP so it's possible to use [em-http-request](https://github.com/igrigorik/em-http-request).
472
+ If you are aware of EventMachine-based non-blocking drivers for these databases, as well as for HBase, let us know on the [EventMachine mailing list](http://groups.google.com/group/eventmachine).
473
+ Also, EventMachine supports TLS (aka SSL) and works well on [JRuby](http://jruby.org) and Windows.
474
+
475
+ Learn more in our {file:docs/Ecosystem.md EventMachine ecosystem} and {file:docs/TLS.md TLS (aka SSL)} guides.
476
+
477
+
478
+ #### Connection loss detection ####
479
+
480
+ Finally, connection loss detection. When our chat participant closes her laptop lid, how do we know that she is no longer active? The answer is, when EventMachine
481
+ detects TCP connectin closure, it calls {EventMachine::Connection#unbind}. Version 1.0.beta3 and later also pass an optional argument to that method. The argument
482
+ indicates what error (if any) caused the connection to be closed.
483
+
484
+ Learn more in our {file:docs/ConnectionFailureAndRecovery.md Connection Failure and Recovery} guide.
485
+
486
+
487
+ #### What the Chat Server Example doesn't demonstrate ####
488
+
489
+ This chat server also leaves out something production quality clients and servers must take care of: buffering. We intentionally did not include any buffering in
490
+ our chat server example: it would only distract you from learning what you really came here to learn: how to use EventMachine to build blazing fast asynchronous
491
+ networking programs quickly. However, {EventMachine::Connection#receive_data} does not offer any guarantees that you will be receiving "whole messages" all the time,
492
+ largely because the underlying transport (UDP or TCP) does not offer such guarantees. Many protocols, for example, AMQP, mandate that large content chunks are
493
+ split into smaller _frames_ of certain size. This means that [amq-client](https://github.com/ruby-amqp/amq-client) library, for instance, that has EventMachine-based driver,
494
+ has to deal with figuring out when exactly we received "the whole message". To do so, it uses buffering and employs various checks to detect _frame boundaries_.
495
+ So **don't be deceived by the simplicity of this chat example**: it intentionally leaves framing out, but real world protocols usually require it.
496
+
497
+
498
+
499
+ ## A (Proxying) Chat Client Example ##
500
+
501
+ TBD
502
+
503
+
504
+ ## Wrapping up ##
505
+
506
+ This tutorial ends here. Congratulations! You have learned quite a bit about EventMachine.
507
+
508
+
509
+ ## What to read next ##
510
+
511
+ The documentation is organized as a {file:docs/DocumentationGuidesIndex.md number of guides}, covering all kinds of
512
+ topics. TBD
513
+
514
+
515
+ ## Tell us what you think! ##
516
+
517
+ Please take a moment and tell us what you think about this guide on the [EventMachine mailing list](http://bit.ly/jW3cR3)
518
+ or in the #eventmachine channel on irc.freenode.net: what was unclear? What wasn't covered?
519
+ Maybe you don't like the guide style or the grammar and spelling are incorrect? Reader feedback is
520
+ key to making documentation better.