plezi 0.7.7 → 0.8.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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -0
  3. data/README.md +3 -3
  4. data/lib/plezi.rb +35 -36
  5. data/lib/plezi/common/cache.rb +94 -0
  6. data/lib/plezi/{base → common}/dsl.rb +87 -68
  7. data/lib/plezi/{base → common}/logging.rb +15 -15
  8. data/lib/plezi/eventmachine/connection.rb +192 -0
  9. data/lib/plezi/eventmachine/em.rb +95 -0
  10. data/lib/plezi/eventmachine/io.rb +265 -0
  11. data/lib/plezi/eventmachine/protocol.rb +54 -0
  12. data/lib/plezi/eventmachine/queue.rb +51 -0
  13. data/lib/plezi/eventmachine/ssl_connection.rb +138 -0
  14. data/lib/plezi/eventmachine/timers.rb +117 -0
  15. data/lib/plezi/eventmachine/workers.rb +35 -0
  16. data/lib/plezi/handlers/http_host.rb +4 -4
  17. data/lib/plezi/handlers/magic_helpers.rb +1 -21
  18. data/lib/plezi/handlers/route.rb +3 -3
  19. data/lib/plezi/server/{helpers/http.rb → http.rb} +1 -57
  20. data/lib/plezi/server/{protocols/http_protocol.rb → http_protocol.rb} +18 -35
  21. data/lib/plezi/server/{protocols/http_request.rb → http_request.rb} +1 -1
  22. data/lib/plezi/server/{protocols/http_response.rb → http_response.rb} +45 -22
  23. data/lib/plezi/server/{helpers/mime_types.rb → mime_types.rb} +0 -0
  24. data/lib/plezi/server/{protocols/websocket.rb → websocket.rb} +34 -37
  25. data/lib/plezi/server/{protocols/ws_response.rb → ws_response.rb} +37 -19
  26. data/lib/plezi/version.rb +1 -1
  27. data/plezi.gemspec +3 -3
  28. data/resources/config.ru +9 -11
  29. metadata +27 -30
  30. data/lib/plezi/base/cache.rb +0 -89
  31. data/lib/plezi/base/connections.rb +0 -33
  32. data/lib/plezi/base/engine.rb +0 -77
  33. data/lib/plezi/base/events.rb +0 -93
  34. data/lib/plezi/base/io_reactor.rb +0 -62
  35. data/lib/plezi/base/rack_app.rb +0 -89
  36. data/lib/plezi/base/services.rb +0 -57
  37. data/lib/plezi/base/timers.rb +0 -71
  38. data/lib/plezi/server/README.md +0 -33
  39. data/lib/plezi/server/services/basic_service.rb +0 -224
  40. data/lib/plezi/server/services/no_service.rb +0 -196
  41. data/lib/plezi/server/services/ssl_service.rb +0 -193
@@ -1,196 +0,0 @@
1
- module Plezi
2
-
3
- # this class is a basic TCP socket service.
4
- #
5
- # a protocol should be assigned, or the service will fall back to an echo service.
6
- #
7
- # a protocol should answer to: on_connect(service), on_message(service, data), on_disconnect(service) and on_exception(service, exception)
8
- #
9
- # the on_message method should return any data that wasn't used (to be sent again as part of the next `on_message` call, once more data is received).
10
- #
11
- # if the protocol is a class, these methods should be instance methods.
12
- # a protocol class should support the initialize(service, parameters={}) method as well.
13
- #
14
- # to-do: fix logging
15
- class NoService
16
-
17
- # create a listener (io) - will create a TCPServer socket
18
- #
19
- # listeners are 'server sockets' that answer to `accept` by creating a new connection socket (io).
20
- def self.create_service port, parameters
21
- self
22
- end
23
-
24
- def self.accept
25
- false
26
- end
27
-
28
- # instance methods
29
-
30
- attr_reader :socket, :locker, :closed, :parameters, :out_que, :active_time
31
- attr_accessor :protocol, :handler, :timeout
32
-
33
- # creates a new connection wrapper object for the new socket that was recieved from the `accept_nonblock` method call.
34
- def initialize socket, parameters = {}
35
- @handler = parameters[:handler]
36
- @socket = nil
37
- # socket.setsockopt Socket::SOL_SOCKET, Socket::SO_RCVTIMEO, "\n\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" #== [10 sec 0 usec].pack '1_2'
38
- @out_que = []
39
- @locker = Mutex.new
40
- @parameters = parameters
41
- @protocol = parameters[:protocol]
42
- @protocol = protocol.new self, parameters if protocol.is_a?(Class)
43
- @protocol.on_connect self if @protocol && @protocol.methods.include?(:on_connect)
44
- touch
45
- @timeout ||= 5
46
- # Plezi.callback self, :on_message
47
- end
48
-
49
- # # sets a connection timeout
50
- # def set_timeout timeout = 8
51
- # @timeout = timeout
52
- # end
53
-
54
- # checks if a connection timed out
55
- def timedout?
56
- Time.now - @active_time > @timeout
57
- end
58
-
59
- # resets the timer for the connection timeout
60
- def touch
61
- @active_time = Time.now
62
- end
63
-
64
- # returns an IO-like object used for reading/writing (unlike the original IO object, this can be an SSL layer or any other wrapper object).
65
- def io
66
- touch
67
- @socket
68
- end
69
-
70
- # sends data immidiately - forcing the data to be sent, flushing any pending messages in the que
71
- def send data = nil
72
- touch
73
- end
74
-
75
- # sends data immidiately, interrupting any pending que and ignoring thread safety.
76
- def send_unsafe_interrupt data = nil
77
- touch
78
- _send data rescue disconnect
79
- end
80
-
81
- # sends data without waiting - data might be sent in a different order then intended.
82
- def send_nonblock data
83
- touch
84
- locker.synchronize {@out_que << data}
85
- Plezi.callback(self, :send)
86
- end
87
-
88
- # adds data to the out buffer - but doesn't send the data until a send event is called.
89
- def << data
90
- touch
91
- locker.synchronize {@out_que << data}
92
- end
93
-
94
- # makes sure any data in the que is send and calls `flush` on the socket, to make sure the buffer is sent.
95
- def flush
96
- end
97
-
98
- # event based interface for messages.
99
-
100
- # notice: since it is all async evet base - multipart messages might be garbled up...?
101
- # todo: protect from garbeling.
102
- def on_message
103
- # return false if locker.locked?
104
- return false if locker.locked?
105
- return disconnect if (_disconnected? rescue true)
106
- locker.synchronize do
107
- begin
108
- touch
109
- if protocol
110
- protocol.on_message self
111
- end
112
- rescue Exception => e
113
- Plezi.error e
114
- return disconnect
115
- end
116
- end
117
- end
118
-
119
- # called once a socket is disconnected or needs to be disconnected.
120
- def on_disconnect
121
- Plezi.callback Plezi, :remove_connection, self
122
-
123
- close
124
- end
125
-
126
- # status markers
127
-
128
- # closes the connection
129
- def close
130
- end
131
- # returns true if the service is disconnected
132
- def disconnected?
133
- false
134
- end
135
- # disconects the service.
136
- def disconnect
137
- on_disconnect
138
- end
139
- # returns true if the socket has content to be read.
140
- def has_incoming_data?
141
- false
142
- end
143
-
144
-
145
- # identification markers
146
-
147
- #returns the service type - set to normal
148
- def service_type
149
- 'no-service'
150
- end
151
- #returns true if the service is encrypted using the OpenSSL library.
152
- def ssl?
153
- false
154
- end
155
-
156
- #################
157
- # overide the followind methods for any child class.
158
-
159
- # this is a public method and it should be used by child classes to implement each
160
- # read(_nonblock) action. accepts one argument ::size for an optional buffer size to be read.
161
- def read size = 1048576
162
- ''
163
- end
164
-
165
- protected
166
-
167
- # this is a protected method, it should be used by child classes to implement each
168
- # send action.
169
- def _send data
170
- ''
171
- end
172
- # this is a protected method, it should be used by child classes to implement each
173
- # close action. doesn't accept any arguments.
174
- def _close
175
- end
176
- # this is a protected method, it should be used by child classes to tell if the socket
177
- # was closed (returns true/false).
178
- def _disconnected?
179
- false # if mode is read only, it's the same as closed.
180
- end
181
-
182
- end
183
- end
184
-
185
-
186
- ######
187
- ## example requests
188
-
189
- # GET / HTTP/1.1
190
- # Host: localhost:2000
191
- # Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
192
- # Cookie: user_token=2INa32_vDgx8Aa1qe43oILELpSdIe9xwmT8GTWjkS-w
193
- # User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10) AppleWebKit/600.1.25 (KHTML, like Gecko) Version/8.0 Safari/600.1.25
194
- # Accept-Language: en-us
195
- # Accept-Encoding: gzip, deflate
196
- # Connection: keep-alive
@@ -1,193 +0,0 @@
1
- module Plezi
2
-
3
- # test connections with: openssl s_client -connect localhost:3000
4
-
5
- # this class is a basic TCP socket service with SSL.
6
- #
7
- # a protocol should be assigned, or the service will fall back to an echo service.
8
- #
9
- # to-do: fix self certificate issue (fails).
10
- class SSLService < BasicService
11
-
12
- # instance methods
13
-
14
- attr_reader :ssl_socket
15
-
16
- # creates a new connection wrapper object for the new socket that was recieved from the `accept_nonblock` method call.
17
- def initialize soc, parameters = {}
18
- context = OpenSSL::SSL::SSLContext.new
19
- context.set_params verify_mode: OpenSSL::SSL::VERIFY_NONE# OpenSSL::SSL::VERIFY_PEER #OpenSSL::SSL::VERIFY_NONE
20
- # context.options DoNotReverseLookup: true
21
- if parameters[:ssl_cert] && parameters[:ssl_key]
22
- context.cert = parameters[:ssl_cert]
23
- context.key = parameters[:ssl_key]
24
- else
25
- context.cert, context.key = self.class.self_cert
26
- end
27
- context.cert_store = OpenSSL::X509::Store.new
28
- context.cert_store.set_default_paths
29
- @ssl_socket = OpenSSL::SSL::SSLSocket.new(soc, context)
30
- @ssl_socket.sync_close = true
31
- @socket = soc
32
- @ssl_socket.accept
33
- super
34
- end
35
- # identification markers
36
-
37
- #returns the service type - set to normal
38
- def service_type
39
- 'encrypted'
40
- end
41
- #returns true if the service is encrypted using the OpenSSL library.
42
- def ssl?
43
- true
44
- end
45
-
46
- # returns an IO-like object used for reading/writing (unlike the original IO object, this can be an SSL layer or any other wrapper object).
47
- def io
48
- touch
49
- @ssl_socket
50
- end
51
-
52
- # reads from the connection
53
- def read size = 1048576
54
- data = ''
55
- begin
56
- loop { data << ssl_socket.read_nonblock( size) }
57
- rescue Exception => e
58
-
59
- end
60
- touch unless data.empty?
61
- data
62
- end
63
-
64
- protected
65
-
66
- #sends data over the connection
67
- def _send data
68
- ssl_socket.write data
69
- end
70
-
71
- #closes the connection
72
- def _close
73
- ssl_socket.flush rescue true
74
- ssl_socket.close
75
- end
76
-
77
- # checks if the connection is closed
78
- def _disconnected?
79
- ssl_socket.closed? || ssl_socket.io.closed? rescue true # || ssl_socket.io.stat.mode == 0140222 <= if mode is read only, it's the same as closed.
80
- end
81
-
82
-
83
- # SSL certificate
84
-
85
- # returns the current self-signed certificate - or creates a new one, if there is no current certificate.
86
- def self.self_cert bits=2048, cn=nil, comment='a self signed certificate for when we only need encryption and no more.'
87
- @@self_cert ||= create_cert
88
- return *@@self_cert
89
- end
90
- #creates a self-signed certificate
91
- def self.create_cert bits=2048, cn=nil, comment='a self signed certificate for when we only need encryption and no more.'
92
- unless cn
93
- host_name = Socket::gethostbyname(Socket::gethostname)[0].split('.')
94
- cn = ''
95
- host_name.each {|n| cn << "/DC=#{n}"}
96
- cn << "/CN=#{host_name.join('.')}"
97
- end
98
- # cn ||= "CN=#{Socket::gethostbyname(Socket::gethostname)[0] rescue Socket::gethostname}"
99
-
100
- rsa = OpenSSL::PKey::RSA.new(bits)
101
- cert = OpenSSL::X509::Certificate.new
102
- cert.version = 2
103
- cert.serial = 1
104
- name = OpenSSL::X509::Name.parse(cn)
105
- cert.subject = name
106
- cert.issuer = name
107
- cert.not_before = Time.now
108
- cert.not_after = Time.now + (365*24*60*60)
109
- cert.public_key = rsa.public_key
110
-
111
- ef = OpenSSL::X509::ExtensionFactory.new(nil,cert)
112
- ef.issuer_certificate = cert
113
- cert.extensions = [
114
- ef.create_extension("basicConstraints","CA:FALSE"),
115
- ef.create_extension("keyUsage", "keyEncipherment"),
116
- ef.create_extension("subjectKeyIdentifier", "hash"),
117
- ef.create_extension("extendedKeyUsage", "serverAuth"),
118
- ef.create_extension("nsComment", comment),
119
- ]
120
- aki = ef.create_extension("authorityKeyIdentifier",
121
- "keyid:always,issuer:always")
122
- cert.add_extension(aki)
123
- cert.sign(rsa, OpenSSL::Digest::SHA1.new)
124
-
125
- return cert, rsa
126
- end
127
-
128
- # def self.cert_test
129
- # #Creating a CA
130
- # root_key = OpenSSL::PKey::RSA.new 2048 # the CA's public/private key
131
- # root_ca = OpenSSL::X509::Certificate.new
132
- # root_ca.version = 2 # cf. RFC 5280 - to make it a "v3" certificate
133
- # root_ca.serial = 1
134
- # root_ca.subject = OpenSSL::X509::Name.parse "/DC=org/DC=ruby-lang/CN=Ruby CA"
135
- # root_ca.issuer = root_ca.subject # root CA's are "self-signed"
136
- # root_ca.public_key = root_key.public_key
137
- # root_ca.not_before = Time.now
138
- # root_ca.not_after = root_ca.not_before + 2 * 365 * 24 * 60 * 60 # 2 years validity
139
- # ef = OpenSSL::X509::ExtensionFactory.new
140
- # ef.subject_certificate = root_ca
141
- # ef.issuer_certificate = root_ca
142
- # root_ca.add_extension(ef.create_extension("basicConstraints","CA:TRUE",true))
143
- # root_ca.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true))
144
- # root_ca.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
145
- # root_ca.add_extension(ef.create_extension("authorityKeyIdentifier","keyid:always",false))
146
- # root_ca.sign(root_key, OpenSSL::Digest::SHA256.new)
147
- # #Creating an End-Point Certificate
148
- # key = OpenSSL::PKey::RSA.new 2048
149
- # cert = OpenSSL::X509::Certificate.new
150
- # cert.version = 2
151
- # cert.serial = 2
152
- # cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=ruby-lang/CN=Ruby certificate"
153
- # cert.issuer = root_ca.subject # root CA is the issuer
154
- # cert.public_key = key.public_key
155
- # cert.not_before = Time.now
156
- # cert.not_after = cert.not_before + 1 * 365 * 24 * 60 * 60 # 1 years validity
157
- # ef = OpenSSL::X509::ExtensionFactory.new
158
- # ef.subject_certificate = cert
159
- # ef.issuer_certificate = root_ca
160
- # cert.add_extension extension_factory.create_extension('keyUsage', 'keyEncipherment,dataEncipherment,digitalSignature')
161
- # cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
162
- # cert.sign(root_key, OpenSSL::Digest::SHA256.new)
163
-
164
- # # #Creating a Certificate
165
- # # name = OpenSSL::X509::Name.parse 'CN=localhost/DC=localhost'
166
- # # cert = OpenSSL::X509::Certificate.new
167
- # # cert.version = 2
168
- # # cert.serial = 0
169
- # # cert.not_before = Time.now
170
- # # cert.not_after = Time.now + 3600
171
- # # key = OpenSSL::PKey::RSA.new 2048
172
- # # cert.public_key = key.public_key
173
- # # cert.subject = name
174
-
175
- # # # Certificate Extensions
176
- # # cert.add_extension extension_factory.create_extension('basicConstraints', 'CA:FALSE', true)
177
- # # cert.add_extension extension_factory.create_extension('keyUsage', 'keyEncipherment,dataEncipherment,digitalSignature')
178
- # # cert.add_extension extension_factory.create_extension('subjectKeyIdentifier', 'hash')
179
-
180
- # # # Signing a Certificate
181
- # # cert.issuer = name
182
- # # cert.sign key, OpenSSL::Digest::SHA1.new
183
-
184
- # #server
185
- # context = OpenSSL::SSL::SSLContext.new
186
- # context.cert = cert
187
- # context.key = key
188
- # tcp_server = TCPServer.new 8080
189
- # ssl_server = OpenSSL::SSL::SSLServer.new tcp_server, context
190
- # ssl_socket = ssl_server.accept
191
- # end
192
- end
193
- end