nitro 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. data/AUTHORS +8 -0
  2. data/ChangeLog +1546 -0
  3. data/LICENCE +32 -0
  4. data/README +278 -0
  5. data/RELEASES +7 -0
  6. data/Rakefile +79 -0
  7. data/bin/cluster.rb +219 -0
  8. data/doc/architecture.txt +28 -0
  9. data/doc/bugs.txt +7 -0
  10. data/doc/css.txt +20 -0
  11. data/doc/ideas.txt +120 -0
  12. data/doc/pg.txt +47 -0
  13. data/doc/svn.txt +82 -0
  14. data/doc/todo.txt +30 -0
  15. data/etc/new-project.rb +18 -0
  16. data/examples/simple/README +15 -0
  17. data/examples/simple/app.rb +31 -0
  18. data/examples/simple/conf/apache.conf +100 -0
  19. data/examples/simple/conf/config.rb +89 -0
  20. data/examples/simple/conf/debug-config.rb +53 -0
  21. data/examples/simple/conf/live-config.rb +48 -0
  22. data/examples/simple/conf/overrides.rb +9 -0
  23. data/examples/simple/conf/requires.rb +51 -0
  24. data/examples/simple/ctl +32 -0
  25. data/examples/simple/env.rb +33 -0
  26. data/examples/simple/install.rb +12 -0
  27. data/examples/simple/lib/articles/entities.rb +35 -0
  28. data/examples/simple/lib/articles/lc-en.rb +36 -0
  29. data/examples/simple/lib/articles/methods.rb +55 -0
  30. data/examples/simple/lib/articles/part.rb +58 -0
  31. data/examples/simple/logs/access_log +2 -0
  32. data/examples/simple/logs/apache.log +3 -0
  33. data/examples/simple/logs/app.log +1 -0
  34. data/examples/simple/logs/events.log +1 -0
  35. data/examples/simple/root/add-article.sx +15 -0
  36. data/examples/simple/root/article-form.ss +20 -0
  37. data/examples/simple/root/comments-form.ss +16 -0
  38. data/examples/simple/root/comments.si +30 -0
  39. data/examples/simple/root/index.sx +44 -0
  40. data/examples/simple/root/shader/shader.xsl +100 -0
  41. data/examples/simple/root/shader/style.css +9 -0
  42. data/examples/simple/root/view-article.sx +30 -0
  43. data/examples/tiny/app.rb +30 -0
  44. data/examples/tiny/conf/apache.conf +100 -0
  45. data/examples/tiny/conf/config.rb +67 -0
  46. data/examples/tiny/conf/requires.rb +40 -0
  47. data/examples/tiny/ctl +31 -0
  48. data/examples/tiny/logs/access_log +9 -0
  49. data/examples/tiny/logs/apache.log +9 -0
  50. data/examples/tiny/root/index.sx +35 -0
  51. data/lib/n/app/cluster.rb +219 -0
  52. data/lib/n/app/cookie.rb +86 -0
  53. data/lib/n/app/filters/autologin.rb +50 -0
  54. data/lib/n/app/fragment.rb +67 -0
  55. data/lib/n/app/handlers.rb +120 -0
  56. data/lib/n/app/handlers/code-handler.rb +184 -0
  57. data/lib/n/app/handlers/page-handler.rb +612 -0
  58. data/lib/n/app/request-part.rb +59 -0
  59. data/lib/n/app/request.rb +653 -0
  60. data/lib/n/app/script.rb +398 -0
  61. data/lib/n/app/server.rb +53 -0
  62. data/lib/n/app/session.rb +224 -0
  63. data/lib/n/app/user.rb +47 -0
  64. data/lib/n/app/webrick-servlet.rb +213 -0
  65. data/lib/n/app/webrick.rb +70 -0
  66. data/lib/n/application.rb +187 -0
  67. data/lib/n/config.rb +31 -0
  68. data/lib/n/db.rb +217 -0
  69. data/lib/n/db/README +232 -0
  70. data/lib/n/db/connection.rb +369 -0
  71. data/lib/n/db/make-release.sh +26 -0
  72. data/lib/n/db/managed.rb +235 -0
  73. data/lib/n/db/mixins.rb +282 -0
  74. data/lib/n/db/mysql.rb +342 -0
  75. data/lib/n/db/psql.rb +378 -0
  76. data/lib/n/db/tools.rb +110 -0
  77. data/lib/n/db/utils.rb +99 -0
  78. data/lib/n/events.rb +118 -0
  79. data/lib/n/l10n.rb +22 -0
  80. data/lib/n/logger.rb +33 -0
  81. data/lib/n/macros.rb +53 -0
  82. data/lib/n/mixins.rb +46 -0
  83. data/lib/n/parts.rb +154 -0
  84. data/lib/n/properties.rb +194 -0
  85. data/lib/n/server.rb +61 -0
  86. data/lib/n/server/PLAYBACK.txt +8 -0
  87. data/lib/n/server/RESEARCH.txt +13 -0
  88. data/lib/n/server/filter.rb +77 -0
  89. data/lib/n/shaders.rb +167 -0
  90. data/lib/n/sitemap.rb +188 -0
  91. data/lib/n/std.rb +69 -0
  92. data/lib/n/sync/clc.rb +108 -0
  93. data/lib/n/sync/handler.rb +221 -0
  94. data/lib/n/sync/server.rb +170 -0
  95. data/lib/n/tools/README +11 -0
  96. data/lib/n/ui/date-select.rb +74 -0
  97. data/lib/n/ui/pager.rb +187 -0
  98. data/lib/n/ui/popup.rb +45 -0
  99. data/lib/n/ui/select.rb +41 -0
  100. data/lib/n/ui/tabs.rb +34 -0
  101. data/lib/n/utils/array.rb +92 -0
  102. data/lib/n/utils/cache.rb +144 -0
  103. data/lib/n/utils/gfx.rb +108 -0
  104. data/lib/n/utils/hash.rb +148 -0
  105. data/lib/n/utils/html.rb +147 -0
  106. data/lib/n/utils/http.rb +98 -0
  107. data/lib/n/utils/mail.rb +28 -0
  108. data/lib/n/utils/number.rb +31 -0
  109. data/lib/n/utils/pool.rb +66 -0
  110. data/lib/n/utils/string.rb +297 -0
  111. data/lib/n/utils/template.rb +38 -0
  112. data/lib/n/utils/time.rb +91 -0
  113. data/lib/n/utils/uri.rb +193 -0
  114. data/lib/xsl/base.xsl +205 -0
  115. data/lib/xsl/ce.xsl +30 -0
  116. data/lib/xsl/localization.xsl +23 -0
  117. data/lib/xsl/xforms.xsl +26 -0
  118. data/test/run.rb +95 -0
  119. metadata +187 -0
@@ -0,0 +1,224 @@
1
+ # = Session
2
+ #
3
+ #--
4
+ # code:
5
+ # George Moschovitis <gm@navel.gr>
6
+ #
7
+ # (c) 2002-2003 Navel, all rights reserved.
8
+ # $Id: session.rb 84 2004-10-19 13:57:01Z gmosx $
9
+ #++
10
+
11
+ require "md5"
12
+
13
+ require "n/utils/hash"
14
+ require "n/app/user"
15
+
16
+ module N; module App
17
+
18
+ # = SessionManager
19
+ #
20
+ # This object manages Session Objects. Several utility methods
21
+ # are also provided.
22
+ #
23
+ # === WARNING:
24
+ #
25
+ # This object is typically called in a distributed configuration.
26
+ # Avoid writting methods that accept or return big objects!
27
+ #
28
+ # SOS: This object lives in the Cluster!
29
+ #
30
+ class SessionManager < N::SafeHash
31
+ # the collection of online users.
32
+ attr_reader :online
33
+
34
+ def initialize
35
+ super
36
+ @online = N::SafeHash.new
37
+ end
38
+
39
+ # Return the number of anonymous sessions.
40
+ #
41
+ def anonymous_count
42
+ return self.size - @online.size
43
+ end
44
+
45
+ # Login a named user.
46
+ # The caller may pass user.to_html instead of the user name.
47
+ # this method is distributed keep a lightweight
48
+ # signature. By using @online.keys i get access to the
49
+ # oids and in this way to the full objects.
50
+ #
51
+ def login(user_oid, user_name)
52
+ @online[user_oid] = user_name
53
+ end
54
+
55
+ # Logout a named user.
56
+ #
57
+ def logout(user_oid)
58
+ @online.delete(user_oid)
59
+ end
60
+
61
+ # Returns the session for the given user.
62
+ #
63
+ def session_for_user(user)
64
+ return values().find { |s| user.oid == s.user.oid }
65
+ end
66
+
67
+ # Returns the session for the given user.
68
+ #
69
+ def session_for_name(name)
70
+ return values().find { |s| name == s.user.name }
71
+ end
72
+
73
+ # garbage collect stale sessions
74
+ #
75
+ # === TODO:
76
+ #
77
+ # - add unit testing.
78
+ #
79
+ def self.garbage_collect!
80
+ # gmosx: the only way to get it to ruby with
81
+ # druby, aaarghhh!! Rethink this though! perhaps some
82
+ # fixes i made allow for recoding this.
83
+ for key in $sessions.keys()
84
+ begin
85
+ session = $sessions[key]
86
+ if session.stale?
87
+ $log.debug "Session finalized: logging out idle user '#{session.user}'" if $DBG
88
+ session.logout()
89
+ $sessions.delete(key)
90
+ end
91
+ rescue Exception, StandardError => e
92
+ $log.error "Session gc errror #$!"
93
+ end
94
+ end
95
+ end
96
+ end
97
+
98
+ # = Session
99
+ #
100
+ # This object encapsulates a WebApplication session.
101
+ #
102
+ # === Design:
103
+ #
104
+ # The session should be persistable to survive server shutdowns.
105
+ #
106
+ # === Usage
107
+ #
108
+ # State is a neccessary evil but try to avoid using session
109
+ # variables as much as possible. Session state is typically
110
+ # distributed to many servers so avoid storing complete objects
111
+ # in session variables, only store oids and integer/strings.
112
+ #
113
+ class Session < Hash
114
+ COOKIE_NAME = "nsid"
115
+
116
+ attr_reader :session_id
117
+
118
+ # keep the user to allow for session lookup based on user.
119
+ # also do NOT keep the full user as an object in the session hash
120
+ # to optimize druby usage!
121
+ #
122
+ attr_accessor :user
123
+
124
+ # the last touch time
125
+ attr_accessor :touch_time
126
+
127
+ #
128
+ #
129
+ def initialize(sid, request = nil)
130
+ super()
131
+ @session_id = sid
132
+ @touch_time = Time.now
133
+ @user = N::AnonymousUser.instance()
134
+ end
135
+
136
+ # Login a user
137
+ #
138
+ # Returns false for banned users.
139
+ #
140
+ def login(request, user)
141
+ return false if user.banned?
142
+ @user = user
143
+ @user.login(request)
144
+ $sessions.login(@user.oid, @user.name)
145
+ $log.info "User '#{user}' logged in!"
146
+ return true
147
+ end
148
+
149
+ # Logout a user
150
+ #
151
+ def logout()
152
+ self.clear()
153
+ @user.logout()
154
+ $sessions.logout(@user.oid)
155
+ $log.info "User '#{user}' logged out!"
156
+ @user = N::AnonymousUser.instance
157
+ end
158
+
159
+ #
160
+ #
161
+ def touch
162
+ @touch_time = Time.now
163
+ end
164
+
165
+ #
166
+ #
167
+ def stale?
168
+ timeout = @user.anonymous? ? $srv_anon_session_timeout : $srv_session_timeout
169
+ return (Time.now - @touch_time > timeout)
170
+ end
171
+
172
+ # call this method to synchronize the session with other servers
173
+ # in the cluster.
174
+ #
175
+ def synchronize!
176
+ # gmosx: TODO, add a check if the session is allready
177
+ # synchronized.
178
+ $sessions[@session_id] = self
179
+ end
180
+
181
+ # Refresh session entities.
182
+ #
183
+ # Call this when you manually change entities stored in the
184
+ # session. A typical scenario is when you change an online user.
185
+ #
186
+ # === Warning: the current version only refreshes the "USER" entity.
187
+ #
188
+ def refresh!
189
+ @user = $db.get(@user.oid, @user.class) if @user
190
+ end
191
+
192
+ # Calculates a unique id.
193
+ #
194
+ # The session id must be unique, a monotonically increasing function
195
+ # like time is appropriate. Random may produce equal ids? add a prefix
196
+ # (SALT) to stop hackers from creating session_ids.
197
+ #
198
+ # TODO:
199
+ # make the prefix configurable
200
+ #
201
+ def self.calculate_id
202
+ time = Time.now
203
+ # FIXME: make this more random?
204
+ id = Digest::MD5.md5("SALT#{time.to_i} #{time.tv_usec}").to_s
205
+ return id
206
+ end
207
+
208
+ # Initialize sessions garbage collection.
209
+ #
210
+ # === Warning: this is not used yet!
211
+ #
212
+ def self.initialize_gc(session_manager, interval)
213
+ # gmosx, FIXME: store this in a variable.
214
+ Thread.new {
215
+ loop do
216
+ sleep(interval)
217
+ garbage_collect(session_manager.sessions)
218
+ end
219
+ }
220
+ end
221
+
222
+ end
223
+
224
+ end; end # module
@@ -0,0 +1,47 @@
1
+ # = User
2
+ #
3
+ # A user of the Web Application. This is a base object, typically
4
+ # extended by the users part.
5
+ #
6
+ #--
7
+ # code:
8
+ # George Moschovitis <gm@navel.gr>
9
+ #
10
+ # (c) 2002-2003 Navel, all rights reserved.
11
+ # $Id: user.rb 86 2004-10-19 13:58:40Z gmosx $
12
+ #++
13
+
14
+ require "singleton"
15
+
16
+ module N
17
+
18
+ # = Anonymous User
19
+ #
20
+ # Implemented as singleton.
21
+ #
22
+ class AnonymousUser
23
+ include Singleton
24
+
25
+ attr_accessor :name
26
+ attr_accessor :locale
27
+ attr_accessor :shader
28
+
29
+ def initialize
30
+ super
31
+ @name = "anonymous"
32
+ @locale = "en"
33
+ @shader = $default_shader
34
+ end
35
+
36
+ def anonymous?
37
+ true
38
+ end
39
+
40
+ def login
41
+ end
42
+
43
+ def logout
44
+ end
45
+ end
46
+
47
+ end # module
@@ -0,0 +1,213 @@
1
+ # = Webrick Servlet.
2
+ #
3
+ # code:
4
+ # George Moschovitis <gm@navel.gr>
5
+ #
6
+ # (c) 2004 Navel, all rights reserved.
7
+ # $Id: webrick-servlet.rb 87 2004-10-19 17:27:45Z gmosx $
8
+
9
+ require "drb"
10
+ require "singleton"
11
+ require "webrick"
12
+
13
+ require "n/logger"
14
+ require "n/utils/cache"
15
+ require "n/app/request"
16
+ require "n/app/request"
17
+ require "n/app/handlers"
18
+ require "n/app/session"
19
+
20
+ # Override WEBrick to suit our needs.
21
+
22
+ module WEBrick
23
+ class HTTPRequest
24
+ alias_method :old_parse_uri, :parse_uri
25
+ def parse_uri(str, scheme="http")
26
+ old_parse_uri(__rewrite(str.dup), scheme)
27
+ end
28
+
29
+ # gmosx, FIXME: temp hack!
30
+ #
31
+ def __rewrite(uri)
32
+ # FIXME: scan for first ONLY.
33
+ realm = uri.scan(/^\/(.*?)\//)
34
+ realm = realm[0][0] unless realm.empty?
35
+
36
+ if rules = $rewrites[realm]
37
+ for rule in rules
38
+ return uri if uri.gsub!(rule[0], rule[1])
39
+ end
40
+ end
41
+
42
+ return uri
43
+ end
44
+ end
45
+
46
+ class HTTPResponse
47
+ attr_writer :header
48
+ attr_writer :cookies
49
+ end
50
+ end
51
+
52
+ module N; module App
53
+
54
+ # = WebrickServlet
55
+ #
56
+ class WebrickServlet < WEBrick::HTTPServlet::AbstractServlet
57
+ include WEBrick
58
+
59
+ def do_GET(wreq, wres)
60
+ request = create_request(wreq)
61
+ request.session = create_session(request)
62
+
63
+ extension = N::StringUtils.extension_from_path(request.path)
64
+ handler = $srv_extension_map[extension][1]
65
+
66
+ begin
67
+ fragment, script = handler.process(request)
68
+
69
+ if fragment
70
+ request.out["Content-Type"] = "text/html" unless request.out["Content-Type"]
71
+ request.out_buffer = fragment.body
72
+ end
73
+
74
+ unless request.expires?
75
+ request.expires!(Time.now())
76
+ end
77
+
78
+ rescue Exception, StandardError => e
79
+ $log.error "error while handling the request #{request.uri}"
80
+ $log.error pp_exception(e)
81
+
82
+ if $error_page_url
83
+ # internal redirect to error page.
84
+ # gmosx: reset handler for .rx pages.
85
+ handler = $srv_extension_map["sx"][1]
86
+ request.path = $error_page_url
87
+ retry
88
+ else
89
+ # no custom error page defined. Presen a simple yet
90
+ # useful error screen.
91
+ request.out["Content-Type"] = "text/html"
92
+ body = %{
93
+ <h1>ERROR</h1>
94
+ <p>Click <a href="#{request.referer}">here</a> to return
95
+ to the previous page.</p>
96
+ }
97
+ if request.error_log
98
+ body << %{
99
+ <h3>Request error log</h3>
100
+ <pre>#{request.error_log.join("\n")}</pre>
101
+ }
102
+ end
103
+ body << %{
104
+ <h3>Exception</h3>
105
+ <pre>#{pp_exception(e)}</pre>
106
+ }
107
+ request.out_buffer = body
108
+ end
109
+ end
110
+
111
+ # gmosx: optimize me, do something more clever!!!
112
+ request.session.synchronize!
113
+
114
+ wres.status = request.status
115
+ wres.header = request.out
116
+ wres.cookies = request.out_cookies.values()
117
+ wres.body = request.out_buffer
118
+ end
119
+
120
+ def do_POST(wreq, wres)
121
+ do_GET(wreq, wres)
122
+ end
123
+
124
+ #-------------------------------------------------------------------------------
125
+
126
+ private
127
+
128
+ # Convert a webrick request to an engine request
129
+ # FIXME: this is UNOPTIMIZED code!
130
+ #
131
+ def create_request(wreq)
132
+ # FIXME: use a resource pool!
133
+ request = N::App::Request.new
134
+
135
+ request.uri = wreq.unparsed_uri
136
+ request.translated_uri = wreq.path_info
137
+ request.path = wreq.path
138
+ # request.path_info = wreq.path_info
139
+ request.query_string = wreq.query_string
140
+ request.method = wreq.request_method
141
+ # request.remote_addr = wreq["REMOTE_ADDR"]
142
+ # gmosx: we use an apache proxy for the moment.
143
+ request.remote_addr = wreq["X-FORWARDED-FOR"]
144
+
145
+ # gmosx: remove this ??
146
+ request.in = {}
147
+ wreq.header.each { |k, v|
148
+ # gmosx: upcase to make compatible with n2 codebase.
149
+ request.in[k.upcase] = v[0]
150
+ }
151
+
152
+ request.parts = {}
153
+ request.parameters = {}
154
+
155
+ wreq.query.each { |k, v|
156
+ if v.filename
157
+ request.parts[k] = N::App::RequestPart.new(v.filename, v)
158
+ else
159
+ request.parameters[k] = v
160
+ end
161
+ }
162
+
163
+ request.in_cookies = {}
164
+ wreq.cookies.each { |c|
165
+ request.in_cookies[c.name] = c
166
+ }
167
+
168
+ # gmosx: is this STILL needed??
169
+ #
170
+ # INVESTIGATE, FIXME: this is a hack!
171
+ # apache prepends $srv_url and fucks up msie.
172
+ # FIXME: add unit test for this!
173
+
174
+ if ref = request.in["REFERER"]
175
+ split_re = Regexp.new($srv_url) unless split_re
176
+ xref = ref.split(split_re).last
177
+ if N::StringUtils.valid?(xref)
178
+ request.in["REFERER"] = xref
179
+ end
180
+ end
181
+
182
+ return request
183
+ end
184
+
185
+ # Create session
186
+ #
187
+ def create_session(request)
188
+ session = nil
189
+ session_id = nil
190
+
191
+ # gmosx: i have to fix the get_cookie method to return a
192
+ # full cookie object.
193
+
194
+ if session_id = request.get_cookie(N::App::Session::COOKIE_NAME)
195
+ session = $sessions[session_id]
196
+ $log.debug "Stale session cookie: #{session_id}" unless session
197
+ # FIXME: remove cookie if stale!
198
+ else
199
+ session_id = N::App::Session.calculate_id()
200
+ cookie = N::App::Cookie.new(N::App::Session::COOKIE_NAME, session_id)
201
+ request.out_cookies[N::App::Session::COOKIE_NAME] = cookie
202
+ end
203
+
204
+ # session not found and must be created
205
+ unless session
206
+ session = N::App::Session.new(session_id)
207
+ end
208
+
209
+ return session
210
+ end
211
+ end
212
+
213
+ end; end # module