plezi 0.7.0

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 (68) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +22 -0
  3. data/CHANGELOG.md +450 -0
  4. data/Gemfile +4 -0
  5. data/KNOWN_ISSUES.md +13 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +341 -0
  8. data/Rakefile +2 -0
  9. data/TODO.md +19 -0
  10. data/bin/plezi +301 -0
  11. data/lib/plezi.rb +125 -0
  12. data/lib/plezi/base/cache.rb +77 -0
  13. data/lib/plezi/base/connections.rb +33 -0
  14. data/lib/plezi/base/dsl.rb +177 -0
  15. data/lib/plezi/base/engine.rb +85 -0
  16. data/lib/plezi/base/events.rb +84 -0
  17. data/lib/plezi/base/io_reactor.rb +41 -0
  18. data/lib/plezi/base/logging.rb +62 -0
  19. data/lib/plezi/base/rack_app.rb +89 -0
  20. data/lib/plezi/base/services.rb +57 -0
  21. data/lib/plezi/base/timers.rb +71 -0
  22. data/lib/plezi/handlers/controller_magic.rb +383 -0
  23. data/lib/plezi/handlers/http_echo.rb +27 -0
  24. data/lib/plezi/handlers/http_host.rb +215 -0
  25. data/lib/plezi/handlers/http_router.rb +69 -0
  26. data/lib/plezi/handlers/magic_helpers.rb +43 -0
  27. data/lib/plezi/handlers/route.rb +272 -0
  28. data/lib/plezi/handlers/stubs.rb +143 -0
  29. data/lib/plezi/server/README.md +33 -0
  30. data/lib/plezi/server/helpers/http.rb +169 -0
  31. data/lib/plezi/server/helpers/mime_types.rb +999 -0
  32. data/lib/plezi/server/protocols/http_protocol.rb +318 -0
  33. data/lib/plezi/server/protocols/http_request.rb +133 -0
  34. data/lib/plezi/server/protocols/http_response.rb +294 -0
  35. data/lib/plezi/server/protocols/websocket.rb +208 -0
  36. data/lib/plezi/server/protocols/ws_response.rb +92 -0
  37. data/lib/plezi/server/services/basic_service.rb +224 -0
  38. data/lib/plezi/server/services/no_service.rb +196 -0
  39. data/lib/plezi/server/services/ssl_service.rb +193 -0
  40. data/lib/plezi/version.rb +3 -0
  41. data/plezi.gemspec +26 -0
  42. data/resources/404.erb +68 -0
  43. data/resources/404.haml +64 -0
  44. data/resources/404.html +67 -0
  45. data/resources/404.slim +63 -0
  46. data/resources/500.erb +68 -0
  47. data/resources/500.haml +63 -0
  48. data/resources/500.html +67 -0
  49. data/resources/500.slim +63 -0
  50. data/resources/Gemfile +85 -0
  51. data/resources/anorexic_gray.png +0 -0
  52. data/resources/anorexic_websockets.html +47 -0
  53. data/resources/code.rb +8 -0
  54. data/resources/config.ru +39 -0
  55. data/resources/controller.rb +139 -0
  56. data/resources/db_ac_config.rb +58 -0
  57. data/resources/db_dm_config.rb +51 -0
  58. data/resources/db_sequel_config.rb +42 -0
  59. data/resources/en.yml +204 -0
  60. data/resources/environment.rb +41 -0
  61. data/resources/haml_config.rb +6 -0
  62. data/resources/i18n_config.rb +14 -0
  63. data/resources/rakefile.rb +22 -0
  64. data/resources/redis_config.rb +35 -0
  65. data/resources/routes.rb +26 -0
  66. data/resources/welcome_page.html +72 -0
  67. data/websocket chatroom.md +639 -0
  68. metadata +141 -0
@@ -0,0 +1,193 @@
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
@@ -0,0 +1,3 @@
1
+ module Plezi
2
+ VERSION = "0.7.0"
3
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'plezi/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "plezi"
8
+ spec.version = Plezi::VERSION
9
+ spec.authors = ["Boaz Segev"]
10
+ spec.email = ['boaz@2be.co.il']
11
+ spec.summary = %q{The Ruby Websocket Framework with RESTful and HTTP streaming support.}
12
+ spec.description = %q{Plezi is The Ruby Websocket and HTTP streaming Framework. Advance to next step in Ruby evolution - a framework with an integrated server, ready for seamless WebSockets and RESTful applications.}
13
+ spec.homepage = "http://boazsegev.github.io/plezi/"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+
24
+ spec.post_install_message = "Plezi is hungry - feed it your code!"
25
+
26
+ end
@@ -0,0 +1,68 @@
1
+ <!DOCTYPE html>
2
+ <head>
3
+ <style>
4
+ body, html
5
+ {
6
+ background-color: #eee;
7
+ padding: 0; margin: 0;
8
+ width: 100%;
9
+ }
10
+ h1
11
+ {
12
+ background-color: #ddd;
13
+ color: #008;
14
+ text-align: center;
15
+ border-bottom: 1px solid #000;
16
+ margin: 0;
17
+ padding: 0.5em;
18
+ width: auto;
19
+ }
20
+ p
21
+ {
22
+ color:#004;
23
+ font-size: 1.2em;
24
+ padding: 0 1em;
25
+ }
26
+ #wrapper
27
+ {
28
+ background-color: #fff;
29
+ margin: 1em 5%;
30
+ padding: 0 0 2% 0;
31
+ border-radius: 20px;
32
+ min-height: 50%;
33
+ color: #007;
34
+ }
35
+ #wrapper h2
36
+ {
37
+ background-color: #ddd;
38
+ color: #008;
39
+ text-align: center;
40
+ margin: 0 0 1em 0;
41
+ padding: 0.5em 0;
42
+ width: 100%;
43
+ border-radius: 20px;
44
+ }
45
+ #wrapper p{ padding: 0 2%;}
46
+ #wrapper #missing
47
+ {
48
+ color:#904;
49
+ font-size: 1.4em;
50
+ padding: 0.5em 0;
51
+ text-align: center;
52
+ background-color: #fee;
53
+ border-bottom: 1px solid #800;
54
+ margin: 0;
55
+ }
56
+ </style>
57
+ </head>
58
+ <body>
59
+ <h1>Plezi 404 error code (missing, not broken)...</h1>
60
+ <div id='wrapper'>
61
+ <h2 id='missing'>
62
+ couldn't find
63
+ <%= defined?(request) ? request.path : "what you're looking for..." %>
64
+ </h2>
65
+ <p>Sorry, we couldn't find what you're looking for...</p>
66
+ <p>... but we can always bring you something nice from another location, right?</p>
67
+ </div>
68
+ </body>
@@ -0,0 +1,64 @@
1
+ !!!5
2
+ %head
3
+ :css
4
+ body, html
5
+ {
6
+ background-color: #eee;
7
+ padding: 0; margin: 0;
8
+ width: 100%;
9
+ }
10
+ h1
11
+ {
12
+ background-color: #ddd;
13
+ color: #008;
14
+ text-align: center;
15
+ border-bottom: 1px solid #000;
16
+ margin: 0;
17
+ padding: 0.5em;
18
+ width: auto;
19
+ }
20
+ p
21
+ {
22
+ color:#004;
23
+ font-size: 1.2em;
24
+ padding: 0 1em;
25
+ }
26
+ #wrapper
27
+ {
28
+ background-color: #fff;
29
+ margin: 1em 5%;
30
+ padding: 0 0 2% 0;
31
+ border-radius: 20px;
32
+ min-height: 50%;
33
+ color: #007;
34
+ }
35
+ #wrapper h2
36
+ {
37
+ background-color: #ddd;
38
+ color: #008;
39
+ text-align: center;
40
+ margin: 0 0 1em 0;
41
+ padding: 0.5em 0;
42
+ width: 100%;
43
+ border-radius: 20px;
44
+ }
45
+ #wrapper p{ padding: 0 2%;}
46
+ #wrapper #missing
47
+ {
48
+ color:#904;
49
+ font-size: 1.4em;
50
+ padding: 0.5em 0;
51
+ text-align: center;
52
+ background-color: #fee;
53
+ border-bottom: 1px solid #800;
54
+ margin: 0;
55
+ }
56
+ %body
57
+ %h1< Plezi 404 error code (missing, not broken)...
58
+ #wrapper
59
+ %h2#missing
60
+ couldn't find
61
+ = defined?(request) ? request.path : "what you're looking for..."
62
+ %p Sorry, we couldn't find what you're looking for...
63
+ %p ... but we can always bring you something nice from another location, right?
64
+ / want to use your layout? use the :haml_concat method to wrap the 404 error code message. see http://haml.info/docs/yardoc/Haml/Helpers.html#haml_concat-instance_method .
@@ -0,0 +1,67 @@
1
+ <!DOCTYPE html>
2
+ <head>
3
+ <style>
4
+ body, html
5
+ {
6
+ background-color: #eee;
7
+ padding: 0; margin: 0;
8
+ width: 100%;
9
+ }
10
+ h1
11
+ {
12
+ background-color: #ddd;
13
+ color: #008;
14
+ text-align: center;
15
+ border-bottom: 1px solid #000;
16
+ margin: 0;
17
+ padding: 0.5em;
18
+ width: 100%;
19
+ }
20
+ p
21
+ {
22
+ color:#004;
23
+ font-size: 1.2em;
24
+ padding: 0 1em;
25
+ }
26
+ #wrapper
27
+ {
28
+ background-color: #fff;
29
+ margin: 1em 5%;
30
+ padding: 0 0 2%;
31
+ border-radius: 20px;
32
+ height: auto;
33
+ color: #007;
34
+ }
35
+ #wrapper h2
36
+ {
37
+ background-color: #ddd;
38
+ color: #008;
39
+ text-align: center;
40
+ margin: 0 0 1em 0;
41
+ padding: 0.5em 0;
42
+ width: 100%;
43
+ border-radius: 20px;
44
+ }
45
+ #wrapper p{ padding: 0 2%;}
46
+ #wrapper #missing
47
+ {
48
+ color:#904;
49
+ font-size: 1.4em;
50
+ padding: 0.5em 0;
51
+ text-align: center;
52
+ background-color: #fee;
53
+ border-bottom: 1px solid #800;
54
+ margin: 0;
55
+ }
56
+ </style>
57
+ </head>
58
+ <body>
59
+ <h1>Plezi 404 error code (missing, not broken)...</h1>
60
+ <div id='wrapper'>
61
+ <h2 id='missing'>
62
+ couldn't find your request...
63
+ </h2>
64
+ <p>Sorry, we couldn't find what you're looking for...</p>
65
+ <p>... but we can always bring you something nice from another location, right?</p>
66
+ </div>
67
+ </body>
@@ -0,0 +1,63 @@
1
+ doctype html
2
+ head
3
+ css:
4
+ body, html
5
+ {
6
+ background-color: #eee;
7
+ padding: 0; margin: 0;
8
+ width: 100%;
9
+ }
10
+ h1
11
+ {
12
+ background-color: #ddd;
13
+ color: #008;
14
+ text-align: center;
15
+ border-bottom: 1px solid #000;
16
+ margin: 0;
17
+ padding: 0.5em;
18
+ width: auto;
19
+ }
20
+ p
21
+ {
22
+ color:#004;
23
+ font-size: 1.2em;
24
+ padding: 0 1em;
25
+ }
26
+ #wrapper
27
+ {
28
+ background-color: #fff;
29
+ margin: 1em 5%;
30
+ padding: 0 0 2% 0;
31
+ border-radius: 20px;
32
+ min-height: 50%;
33
+ color: #007;
34
+ }
35
+ #wrapper h2
36
+ {
37
+ background-color: #ddd;
38
+ color: #008;
39
+ text-align: center;
40
+ margin: 0 0 1em 0;
41
+ padding: 0.5em 0;
42
+ width: 100%;
43
+ border-radius: 20px;
44
+ }
45
+ #wrapper p { padding: 0 2%; }
46
+ #wrapper #missing
47
+ {
48
+ color:#904;
49
+ font-size: 1.4em;
50
+ padding: 0.5em 0;
51
+ text-align: center;
52
+ background-color: #fee;
53
+ border-bottom: 1px solid #800;
54
+ margin: 0;
55
+ }
56
+ body
57
+ h1 Plezi 404 error code (missing, not broken)...
58
+ #wrapper
59
+ h2#missing
60
+ | couldn't find
61
+ =< defined?(request) ? request.path : "what you're looking for..."
62
+ p Sorry, we couldn't find what you're looking for...
63
+ p ... but we can always bring you something nice from another location, right?