wj_eventmachine 1.3.0.dev.1

Sign up to get free protection for your applications and to get access to all the features.
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.