nitro 0.1.2

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 (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