knjappserver 0.0.15 → 0.0.16

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/Gemfile +4 -2
  2. data/Gemfile.lock +24 -10
  3. data/README.rdoc +298 -1
  4. data/VERSION +1 -1
  5. data/bin/check_running.rb +2 -2
  6. data/knjappserver.gemspec +23 -5
  7. data/lib/files/database_schema.rb +124 -111
  8. data/lib/include/class_customio.rb +19 -5
  9. data/lib/include/class_erbhandler.rb +5 -22
  10. data/lib/include/class_httpresp.rb +66 -28
  11. data/lib/include/class_httpserver.rb +27 -14
  12. data/lib/include/class_httpsession.rb +161 -212
  13. data/lib/include/class_httpsession_contentgroup.rb +144 -0
  14. data/lib/include/class_httpsession_knjengine.rb +33 -68
  15. data/lib/include/class_httpsession_mongrel.rb +1 -1
  16. data/lib/include/class_httpsession_webrick.rb +1 -1
  17. data/lib/include/class_knjappserver.rb +105 -130
  18. data/lib/include/class_knjappserver_cleaner.rb +20 -13
  19. data/lib/include/class_knjappserver_cmdline.rb +44 -0
  20. data/lib/include/class_knjappserver_errors.rb +4 -1
  21. data/lib/include/class_knjappserver_logging.rb +48 -8
  22. data/lib/include/class_knjappserver_mailing.rb +36 -14
  23. data/lib/include/class_knjappserver_sessions.rb +78 -0
  24. data/lib/include/class_knjappserver_threadding.rb +18 -45
  25. data/lib/include/class_knjappserver_threadding_timeout.rb +78 -0
  26. data/lib/include/class_knjappserver_translations.rb +30 -0
  27. data/lib/include/class_knjappserver_web.rb +55 -3
  28. data/lib/include/class_log.rb +31 -3
  29. data/lib/include/class_log_access.rb +0 -15
  30. data/lib/include/class_log_data.rb +0 -15
  31. data/lib/include/class_log_data_link.rb +1 -14
  32. data/lib/include/class_log_data_value.rb +5 -17
  33. data/lib/include/class_session.rb +6 -18
  34. data/lib/include/magic_methods.rb +12 -14
  35. data/lib/pages/benchmark.rhtml +0 -0
  36. data/lib/pages/benchmark_print.rhtml +14 -0
  37. data/lib/pages/benchmark_simple.rhtml +3 -0
  38. data/lib/pages/benchmark_threadded_content.rhtml +21 -0
  39. data/lib/pages/spec.rhtml +26 -0
  40. data/lib/pages/spec_test_multiple_clients.rhtml +3 -0
  41. data/lib/pages/spec_threadded_content.rhtml +38 -0
  42. data/lib/scripts/benchmark.rb +65 -0
  43. data/spec/knjappserver_spec.rb +87 -43
  44. metadata +54 -20
@@ -0,0 +1,144 @@
1
+ #This class handels the adding of content and writing to socket. Since this can be done with multiple threads and multiple IO's it can get complicated.
2
+ class Knjappserver::Httpsession::Contentgroup
3
+ attr_reader :done, :cur_data
4
+ attr_accessor :chunked, :socket
5
+ NL = "\r\n"
6
+
7
+ def initialize(args = {})
8
+ @block = args[:restart_proc]
9
+ @socket = args[:socket]
10
+ @chunked = args[:chunked]
11
+ @mutex = Mutex.new
12
+ @debug = false
13
+ end
14
+
15
+ def init
16
+ @done = false
17
+ @thread = nil
18
+ @cur_data = {
19
+ :str => "",
20
+ :done => false
21
+ }
22
+ @ios = [@cur_data]
23
+ end
24
+
25
+ def reset
26
+ @ios = []
27
+ @done = false
28
+ @thread = nil
29
+
30
+ @mutex.synchronize do
31
+ self.new_io
32
+ end
33
+
34
+ self.register_thread
35
+ end
36
+
37
+ def new_io(obj = "")
38
+ @cur_data[:done] = true if @cur_data
39
+ @cur_data = {:str => obj, :done => false}
40
+ @ios << @cur_data
41
+ end
42
+
43
+ def register_thread
44
+ Thread.current[:knjappserver] = {} if !Thread.current[:knjappserver]
45
+ Thread.current[:knjappserver][:contentgroup] = self
46
+ end
47
+
48
+ def new_thread
49
+ @mutex.synchronize do
50
+ cgroup = Knjappserver::Httpsession::Contentgroup.new(:socket => @socket, :chunked => @chunked)
51
+ cgroup.init
52
+
53
+ data = {:cgroup => cgroup}
54
+ @ios << data
55
+ self.new_io
56
+ self.register_thread
57
+
58
+ return data
59
+ end
60
+ end
61
+
62
+ def write(cont)
63
+ @mutex.synchronize do
64
+ @cur_data[:str] << cont.to_s
65
+ end
66
+ end
67
+
68
+ def write_output
69
+ if @block and !@thread
70
+ @mutex.synchronize do
71
+ @thread = Knj::Thread.new do
72
+ @block.call
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ def mark_done
79
+ @cur_data[:done] = true
80
+ @done = true
81
+ end
82
+
83
+ def join
84
+ if @block
85
+ sleep 0.1 while !@thread
86
+ @thread.join
87
+ end
88
+ end
89
+
90
+ def write_to_socket
91
+ count = 0
92
+
93
+ @ios.each do |data|
94
+ if data.key?(:cgroup)
95
+ data[:cgroup].write_to_socket
96
+ elsif data.key?(:str)
97
+ if data[:str].is_a?(File)
98
+ file = data[:str]
99
+
100
+ loop do
101
+ begin
102
+ buf = file.sysread(4096)
103
+ rescue EOFError
104
+ break
105
+ end
106
+
107
+ if @chunked
108
+ @socket.write("#{buf.length.to_s(16)}#{NL}#{buf}#{NL}")
109
+ else
110
+ @socket.write(buf)
111
+ end
112
+ end
113
+
114
+ file.close
115
+ else
116
+ loop do
117
+ break if data[:done] and data[:str].size <= 0
118
+ sleep 0.1 while data[:str].size <= 512 and !data[:done]
119
+
120
+ str = nil
121
+ @mutex.synchronize do
122
+ str = data[:str].bytes
123
+ data[:str] = ""
124
+ end
125
+
126
+ str.each_slice(512) do |slice|
127
+ buf = slice.pack("C*")
128
+
129
+ if @chunked
130
+ @socket.write("#{buf.length.to_s(16)}#{NL}#{buf}#{NL}")
131
+ else
132
+ @socket.write(buf)
133
+ end
134
+ end
135
+ end
136
+ end
137
+ else
138
+ raise "Unknown object: '#{data.class.name}'."
139
+ end
140
+ end
141
+
142
+ count += 1
143
+ end
144
+ end
@@ -1,12 +1,11 @@
1
1
  require "uri"
2
- require "cgi"
3
2
 
4
3
  if RUBY_PLATFORM == "java" or RUBY_ENGINE == "rbx"
5
4
  BasicSocket.do_not_reverse_lookup = true
6
5
  end
7
6
 
8
7
  class Knjappserver::Httpsession::Knjengine
9
- attr_reader :get, :post, :cookie, :meta, :page_path, :headers
8
+ attr_reader :get, :post, :cookie, :meta, :page_path, :headers, :http_version
10
9
 
11
10
  def initialize(args)
12
11
  @args = args
@@ -18,7 +17,7 @@ class Knjappserver::Httpsession::Knjengine
18
17
  loop do
19
18
  raise Errno::ECONNRESET, "Socket closed." if @socket.closed?
20
19
  read = @socket.gets
21
- raise Errno::ECONNRESET, "Socket returned non-string." if !read.is_a?(String)
20
+ raise Errno::ECONNRESET, "Socket returned non-string: '#{read.class.name}'." if !read.is_a?(String)
22
21
  @cont += read
23
22
  break if @cont[-4..-1] == "\r\n\r\n" or @cont[-2..-1] == "\n\n"
24
23
  end
@@ -31,21 +30,21 @@ class Knjappserver::Httpsession::Knjengine
31
30
 
32
31
  #Parse URI (page_path and get).
33
32
  match = @cont.match(/^(GET|POST|HEAD) (.+) HTTP\/1\.(\d+)\s*/)
34
- if !match
35
- raise "Could not parse request: '#{@cont.split("\n").first}'."
36
- end
33
+ raise "Could not parse request: '#{@cont.split("\n").first}'." if !match
34
+
35
+ @http_version = "1.#{match[3]}"
37
36
 
38
37
  method = match[1]
39
38
  @cont = @cont.gsub(match[0], "")
40
39
  uri = URI.parse(match[2])
41
40
 
42
- page_filepath = CGI.unescape(uri.path)
41
+ page_filepath = Knj::Web.urldec(uri.path)
43
42
  if page_filepath.length <= 0 or page_filepath == "/" or File.directory?("#{@kas.config[:doc_root]}/#{page_filepath}")
44
43
  page_filepath = "#{page_filepath}/#{@kas.config[:default_page]}"
45
44
  end
46
45
 
47
46
  @page_path = "#{@kas.config[:doc_root]}/#{page_filepath}"
48
- @get = Knj::Web.parse_urlquery(uri.query.to_s, {:urldecode => true})
47
+ @get = Knj::Web.parse_urlquery(uri.query.to_s, {:urldecode => true, :force_utf8 => true})
49
48
 
50
49
 
51
50
  #Parse headers, cookies and meta.
@@ -83,26 +82,13 @@ class Knjappserver::Httpsession::Knjengine
83
82
  @headers[key] << val
84
83
 
85
84
  case key
86
- when "host"
87
- @meta["HTTP_HOST"] = val
88
- when "connection"
89
- @meta["HTTP_CONNECTION"] = val
90
- when "accept"
91
- @meta["HTTP_ACCEPT"] = val
92
- when "accept-encoding"
93
- @meta["HTTP_ACCEPT_ENCODING"] = val
94
- when "accept-language"
95
- @meta["HTTP_ACCEPT_LANGUAGE"] = val
96
- when "accept-charset"
97
- @meta["HTTP_ACCEPT_CHARSET"] = val
98
- when "user-agent"
99
- @meta["HTTP_USER_AGENT"] = val
100
- when "referer"
101
- @meta["HTTP_REFERER"] = val
102
85
  when "cookie"
103
86
  Knj::Web.parse_cookies(val).each do |key, val|
104
87
  @cookie[key] = val
105
88
  end
89
+ else
90
+ key = key.upcase.gsub("-", "_")
91
+ @meta["HTTP_#{key}"] = val
106
92
  end
107
93
  end
108
94
 
@@ -120,7 +106,7 @@ class Knjappserver::Httpsession::Knjengine
120
106
  else
121
107
  post_data.split("&").each do |splitted|
122
108
  splitted = splitted.split("=")
123
- post_treated[Knj::Php.urldecode(splitted[0])] = splitted[1]
109
+ post_treated[Knj::Web.urldec(splitted[0])] = splitted[1]
124
110
  end
125
111
  end
126
112
 
@@ -137,53 +123,32 @@ class Knjappserver::Httpsession::Knjengine
137
123
  #Thanks to WEBrick
138
124
  def parse_form_data(io, boundary)
139
125
  boundary_regexp = /\A--#{boundary}(--)?#{@crlf}\z/
140
- form_data = Hash.new
126
+ form_data = {}
141
127
  return form_data unless io
142
128
  data = nil
143
- io.each{|line|
129
+
130
+ io.each do |line|
144
131
  if boundary_regexp =~ line
145
- if data
146
- data.chop!
147
- key = data.name
148
- if form_data.has_key?(key)
149
- form_data[key].append_data(data)
150
- else
151
- form_data[key] = data
152
- end
153
- end
154
- data = WEBrick::HTTPUtils::FormData.new
155
- next
132
+ if data
133
+ data.chop!
134
+ key = data.name
135
+
136
+ if form_data.has_key?(key)
137
+ form_data[key].append_data(data)
138
+ else
139
+ form_data[key] = data
140
+ end
141
+ end
142
+
143
+ data = WEBrick::HTTPUtils::FormData.new
144
+ next
156
145
  else
157
- if data
158
- data << line
159
- end
146
+ if data
147
+ data << line
148
+ end
160
149
  end
161
- }
162
- return form_data
163
- end
164
-
165
- def destroy
166
- @args.clear if @args
167
- @args = nil
168
- @kas = nil
169
- @socket = nil
170
- @cont = nil
171
-
172
- @meta.clear if @meta
173
- @meta = nil
174
-
175
- @page_path = nil
176
-
177
- @get.clear if @get
178
- @get = nil
179
-
180
- @post.clear if @post
181
- @post = nil
182
-
183
- @headers.clear if @headers
184
- @headers = nil
150
+ end
185
151
 
186
- @cookie.clear if @cookie
187
- @cookie = nil
188
- end
152
+ return form_data
153
+ end
189
154
  end
@@ -40,7 +40,7 @@ class Knjappserver::Httpsession::Webrick
40
40
  @cookie = {}
41
41
 
42
42
  req.cookies.each do |cookie_enum|
43
- @cookie[cookie_enum.name] = CGI.unescape(cookie_enum.value)
43
+ @cookie[cookie_enum.name] = Knj::Web.urldec(cookie_enum.value)
44
44
  end
45
45
 
46
46
 
@@ -40,7 +40,7 @@ class Knjappserver::Httpsession::Webrick
40
40
  @cookie = {}
41
41
 
42
42
  req.cookies.each do |cookie_enum|
43
- @cookie[cookie_enum.name] = CGI.unescape(cookie_enum.value)
43
+ @cookie[cookie_enum.name] = Knj::Web.urldec(cookie_enum.value)
44
44
  end
45
45
 
46
46
 
@@ -1,9 +1,13 @@
1
+ require "#{File.dirname(__FILE__)}/class_knjappserver_cleaner"
2
+ require "#{File.dirname(__FILE__)}/class_knjappserver_cmdline"
1
3
  require "#{File.dirname(__FILE__)}/class_knjappserver_errors"
2
4
  require "#{File.dirname(__FILE__)}/class_knjappserver_logging"
3
5
  require "#{File.dirname(__FILE__)}/class_knjappserver_mailing"
6
+ require "#{File.dirname(__FILE__)}/class_knjappserver_sessions"
4
7
  require "#{File.dirname(__FILE__)}/class_knjappserver_threadding"
8
+ require "#{File.dirname(__FILE__)}/class_knjappserver_threadding_timeout"
9
+ require "#{File.dirname(__FILE__)}/class_knjappserver_translations"
5
10
  require "#{File.dirname(__FILE__)}/class_knjappserver_web"
6
- require "#{File.dirname(__FILE__)}/class_knjappserver_cleaner"
7
11
 
8
12
  require "timeout"
9
13
  require "digest"
@@ -13,24 +17,30 @@ require "stringio"
13
17
  require "socket"
14
18
 
15
19
  class Knjappserver
16
- attr_reader :config, :httpserv, :db, :db_handler, :ob, :translations, :paused, :should_restart, :events, :mod_event, :paused, :db_handler, :gettext, :sessions, :logs_access_pending, :threadpool, :vars, :magic_vars, :types, :eruby_cache
20
+ attr_reader :config, :httpserv, :debug, :db, :db_handler, :ob, :translations, :paused, :should_restart, :events, :mod_event, :db_handler, :gettext, :sessions, :logs_access_pending, :threadpool, :vars, :magic_vars, :types, :eruby_cache
17
21
  attr_accessor :served, :should_restart, :should_restart_done
18
22
 
19
23
  autoload :ERBHandler, "#{File.dirname(__FILE__)}/class_erbhandler"
20
24
 
21
25
  def initialize(config)
22
26
  raise "No arguments given." if !config.is_a?(Hash)
27
+
23
28
  @config = {
29
+ :host => "0.0.0.0",
24
30
  :timeout => 30,
25
31
  :default_page => "index.rhtml",
26
32
  :default_filetype => "text/html",
27
- :max_requests_working => 20
33
+ :max_requests_working => 20,
34
+ :size_send => 1024
28
35
  }.merge(config)
29
36
 
37
+ @config[:smtp_args] = {"smtp_host" => "localhost", "smtp_port" => 25} if !@config[:smtp_args]
30
38
  @config[:timeout] = 30 if !@config.has_key?(:timeout)
31
39
  @config[:engine_knjengine] = true if !@config[:engine_knjengine] and !@config[:engine_webrick] and !@config[:engine_mongrel]
32
40
  raise "No ':doc_root' was given in arguments." if !@config.has_key?(:doc_root)
33
41
 
42
+
43
+ #Setup default handlers if none are given.
34
44
  if !@config.has_key?(:handlers)
35
45
  @erbhandler = Knjappserver::ERBHandler.new
36
46
  @config[:handlers] = [
@@ -44,6 +54,7 @@ class Knjappserver
44
54
  ]
45
55
  end
46
56
 
57
+ @debug = @config[:debug]
47
58
  @paused = 0
48
59
  @paused_mutex = Mutex.new
49
60
  @should_restart = false
@@ -71,7 +82,7 @@ class Knjappserver
71
82
  "#{@path_knjappserver}/class_customio.rb"
72
83
  ]
73
84
 
74
- print "Auto restarting.\n" if @config[:debug]
85
+ print "Auto restarting.\n" if @debug
75
86
  @mod_event = Knj::Event_filemod.new(:wait => 2, :paths => paths) do |event, path|
76
87
  print "File changed - restart server: #{path}\n"
77
88
  @should_restart = true
@@ -79,6 +90,8 @@ class Knjappserver
79
90
  end
80
91
  end
81
92
 
93
+
94
+ #Set up default file-types and merge given filetypes into it.
82
95
  @types = {
83
96
  :ico => "image/x-icon",
84
97
  :jpeg => "image/jpeg",
@@ -95,6 +108,8 @@ class Knjappserver
95
108
  @types = @types.merge(@config[:filetypes]) if @config.has_key?(:filetypes)
96
109
 
97
110
 
111
+
112
+ #Load various required files from knjrbfw and stuff in the knjappserver-framework.
98
113
  files = [
99
114
  "#{@path_knjrbfw}knjrbfw.rb",
100
115
  "#{@path_knjrbfw}knj/arrayext.rb",
@@ -115,28 +130,46 @@ class Knjappserver
115
130
  "#{@path_knjappserver}/class_httpresp.rb",
116
131
  "#{@path_knjappserver}/class_httpserver.rb",
117
132
  "#{@path_knjappserver}/class_httpsession.rb",
133
+ "#{@path_knjappserver}/class_httpsession_contentgroup.rb",
118
134
  "#{@path_knjappserver}/class_session.rb",
119
135
  "#{@path_knjappserver}/class_log.rb",
120
136
  "#{@path_knjappserver}/class_log_access.rb",
121
137
  "#{@path_knjappserver}/class_log_data_value.rb"
122
138
  ]
139
+ files << "#{@path_knjrbfw}knj/gettext_threadded.rb" if @config[:locales_root]
123
140
  files.each do |file|
124
- STDOUT.print "Loading: '#{file}'.\n" if @config[:debug]
141
+ STDOUT.print "Loading: '#{file}'.\n" if @debug
125
142
  self.loadfile(file)
126
143
  end
127
144
 
128
145
 
129
- print "Setting up database.\n" if @config[:debug]
146
+ print "Setting up database.\n" if @debug
130
147
  if @config[:db].is_a?(Knj::Db)
131
148
  @db = @config[:db]
132
149
  elsif @config[:db].is_a?(Hash)
133
150
  @db = Knj::Db.new(@config[:db])
151
+ elsif !@config[:db] and @config[:db_args]
152
+ @db = Knj::Db.new(@config[:db_args])
134
153
  else
135
154
  raise "Unknown object given as db: '#{@config[:db].class.name}'."
136
155
  end
137
156
 
138
157
 
139
- print "Starting objects.\n" if @config[:debug]
158
+ print "Updating database.\n" if @debug
159
+ require "rubygems" if !@config.key?(:knjdbrevision_path)
160
+ require "#{@config[:knjdbrevision_path]}knjdbrevision"
161
+
162
+ dbschemapath = "#{File.dirname(__FILE__)}/../files/database_schema.rb"
163
+ raise "'#{dbschemapath}' did not exist." if !File.exists?(dbschemapath)
164
+ require dbschemapath
165
+ raise "No schema-variable was spawned." if !DATABASE_SCHEMA
166
+
167
+ dbpath = "#{File.dirname(__FILE__)}/../files/database.sqlite3"
168
+ dbrev = Knjdbrevision.new
169
+ dbrev.init_db(DATABASE_SCHEMA, @db)
170
+
171
+
172
+ print "Spawning objects.\n" if @debug
140
173
  @ob = Knj::Objects.new(
141
174
  :db => db,
142
175
  :class_path => @path_knjappserver,
@@ -157,8 +190,10 @@ class Knjappserver
157
190
 
158
191
 
159
192
  #Start the Knj::Gettext_threadded- and Knj::Translations modules for translations.
160
- print "Loading Gettext and translations.\n" if @config[:debug]
193
+ print "Loading Gettext and translations.\n" if @debug
161
194
  @translations = Knj::Translations.new(:db => @db)
195
+ @ob.requireclass(:Translation, {:require => false, :class => Knj::Translations::Translation})
196
+
162
197
  if @config[:locales_root]
163
198
  @gettext = Knj::Gettext_threadded.new("dir" => config[:locales_root])
164
199
  end
@@ -168,32 +203,40 @@ class Knjappserver
168
203
  end
169
204
 
170
205
  if @config[:magic_methods] or !@config.has_key?(:magic_methods)
171
- print "Loading magic-methods.\n" if @config[:debug]
206
+ print "Loading magic-methods.\n" if @debug
172
207
  require "#{@path_knjappserver}/magic_methods"
173
208
  end
174
209
 
175
210
  if @config[:customio] or !@config.has_key?(:customio)
176
- print "Loading custom-io.\n" if @config[:debug]
177
- require "#{@path_knjappserver}/class_customio.rb"
178
- cio = Knjappserver::CustomIO.new
179
- $stdout = cio
211
+ print "Loading custom-io.\n" if @debug
212
+
213
+ if $stdout.class.name != "Knjappserver::CustomIO"
214
+ require "#{@path_knjappserver}/class_customio.rb"
215
+ cio = Knjappserver::CustomIO.new
216
+ $stdout = cio
217
+ end
180
218
  end
181
219
 
182
220
 
183
221
  #Save the PID to the run-file.
184
- print "Setting run-file.\n" if @config[:debug]
222
+ print "Setting run-file.\n" if @debug
185
223
  require "tmpdir"
186
224
  tmpdir = "#{Dir.tmpdir}/knjappserver"
187
225
  tmppath = "#{tmpdir}/run_#{@config[:title]}"
188
226
 
189
- Dir.mkdir(tmpdir) if !File.exists?(tmpdir)
227
+ if !File.exists?(tmpdir)
228
+ Dir.mkdir(tmpdir)
229
+ File.chmod(0777, tmpdir)
230
+ end
231
+
190
232
  File.open(tmppath, "w") do |fp|
191
233
  fp.write(Process.pid)
192
234
  end
235
+ File.chmod(0777, tmppath)
193
236
 
194
237
 
195
238
  #Set up various events for the appserver.
196
- print "Loading events.\n" if @config[:debug]
239
+ print "Loading events.\n" if @debug
197
240
  @events = Knj::Event_handler.new
198
241
  @events.add_event(
199
242
  :name => :check_page_access,
@@ -203,7 +246,10 @@ class Knjappserver
203
246
  :name => :ob,
204
247
  :connections_max => 1
205
248
  )
206
-
249
+ @events.add_event(
250
+ :name => :trans_no_str,
251
+ :connections_max => 1
252
+ )
207
253
 
208
254
  #Set up the 'vars'-variable that can be used to set custom global variables for web-requests.
209
255
  @vars = Knj::Hash_methods.new
@@ -211,24 +257,30 @@ class Knjappserver
211
257
 
212
258
 
213
259
  #Initialize the various feature-modules.
214
- print "Init threadding.\n" if @config[:debug]
260
+ print "Init sessions.\n" if @debug
261
+ initialize_sessions
262
+
263
+ print "Init threadding.\n" if @debug
215
264
  initialize_threadding
216
265
 
217
- print "Init mailing.\n" if @config[:debug]
266
+ print "Init mailing.\n" if @debug
218
267
  initialize_mailing
219
268
 
220
- print "Init errors.\n" if @config[:debug]
269
+ print "Init errors.\n" if @debug
221
270
  initialize_errors
222
271
 
223
- print "Init logging.\n" if @config[:debug]
272
+ print "Init logging.\n" if @debug
224
273
  initialize_logging
225
274
 
226
- print "Init cleaner.\n" if @config[:debug]
275
+ print "Init cleaner.\n" if @debug
227
276
  initialize_cleaner
228
277
 
278
+ print "Init cmdline.\n" if @debug
279
+ initialize_cmdline
280
+
229
281
 
230
282
  #Start the appserver.
231
- print "Spawning appserver.\n" if @config[:debug]
283
+ print "Spawning appserver.\n" if @debug
232
284
  @httpserv = Knjappserver::Httpserver.new(self)
233
285
 
234
286
 
@@ -238,9 +290,10 @@ class Knjappserver
238
290
  end
239
291
 
240
292
 
241
- print "Appserver spawned.\n" if @config[:debug]
293
+ print "Appserver spawned.\n" if @debug
242
294
  end
243
295
 
296
+ #If you want to use auto-restart, every file reloaded through loadfile will be watched for changes. When changed the server will do a restart to reflect that.
244
297
  def loadfile(fpath)
245
298
  if !@config[:autorestart]
246
299
  require fpath
@@ -259,54 +312,39 @@ class Knjappserver
259
312
  return false
260
313
  end
261
314
 
315
+ #Starts the HTTP-server and threadpool.
262
316
  def start
263
- print "Starting appserver.\n" if @config[:debug]
317
+ STDOUT.print "Starting appserver.\n" if @debug
264
318
  Thread.current[:knjappserver] = {:kas => self} if !Thread.current[:knjappserver]
265
319
 
266
320
  if @config[:autoload]
267
- print "Autoloading #{@config[:autoload]}\n" if @config[:debug]
321
+ STDOUT.print "Autoloading #{@config[:autoload]}\n" if @debug
268
322
  require @config[:autoload]
269
323
  end
270
324
 
271
325
  begin
272
326
  @threadpool.start if @threadpool
273
- print "Threadpool startet.\n" if @config[:debug]
327
+ STDOUT.print "Threadpool startet.\n" if @debug
274
328
  @httpserv.start
275
- print "Appserver startet.\n" if @config[:debug]
329
+ STDOUT.print "Appserver startet.\n" if @debug
276
330
  rescue Interrupt
277
- print "Got interrupt - stopping appserver.\n" if @config[:debug]
278
- stop
331
+ STDOUT.print "Got interrupt - stopping appserver.\n" if @debug
332
+ self.stop
279
333
  end
280
334
  end
281
335
 
336
+ #Stops the entire app and releases join.
282
337
  def stop
283
338
  proc_stop = proc{
284
- print "Stopping appserver for real.\n" if @config[:debug]
339
+ #This should be done first to be sure it finishes (else we have a serious bug).
340
+ STDOUT.print "Flush out loaded sessions.\n" if @debug
341
+ self.sessions_flush
342
+
343
+ STDOUT.print "Stopping appserver for real.\n" if @debug
285
344
  @httpserv.stop if @httpserv and @httpserv.respond_to?(:stop)
286
345
 
287
- print "Stopping threadpool.\n" if @config[:debug]
346
+ STDOUT.print "Stopping threadpool.\n" if @debug
288
347
  @threadpool.stop if @threadpool
289
-
290
- print "Cleaning out loaded sessions.\n" if @config[:debug]
291
- if @sessions
292
- @sessions.each do |ip, ip_sessions|
293
- ip_sessions.each do |session_hash, session_data|
294
- session_data[:dbobj].flush
295
- @ob.unset(session_data[:dbobj])
296
- session_data[:hash].clear
297
- ip_sessions.delete(session_hash)
298
- session_data.clear
299
- end
300
- end
301
- @sessions.clear
302
- end
303
-
304
- print "Stopping databases.\n" if @config[:debug]
305
- @db.destroy if @db.is_a?(Knj::Threadhandler)
306
- @db.close if @db.is_a?(Knj::Db)
307
-
308
- @db_handler.destroy if @db.is_a?(Knj::Threadhandler)
309
- @db_handler.close if @db_handler.is_a?(Knj::Db)
310
348
  }
311
349
 
312
350
  #If we cant get a paused-execution in 10 secs - we just force the stop.
@@ -316,46 +354,43 @@ class Knjappserver
316
354
  proc_stop.call
317
355
  end
318
356
  end
319
- rescue Timeout::Error
357
+ rescue Timeout::Error, SystemExit, Interrupt
358
+ STDOUT.print "Forcing stop-appserver - couldnt get timing window.\n" if @debug
320
359
  proc_stop.call
321
360
  end
322
361
  end
323
362
 
324
- # Stop running any more http requests - make them wait.
363
+ #Stop running any more HTTP-requests - make them wait.
325
364
  def pause
326
365
  @paused += 1
327
366
  end
328
367
 
368
+ #Unpause - start handeling HTTP-requests again.
329
369
  def unpause
330
370
  @paused -= 1
331
371
  end
332
372
 
373
+ #Returns true if paued - otherwise false.
333
374
  def paused?
334
375
  return true if @paused > 0
335
376
  return false
336
377
  end
337
378
 
379
+ #Will stop handeling any more HTTP-requests, run the proc given and return handeling HTTP-requests.
338
380
  def paused_exec
339
381
  self.pause
340
382
 
341
383
  begin
342
- loop do
343
- if @httpserv.working_count > 0
344
- sleep 0.2
345
- next
346
- end
347
-
348
- @paused_mutex.synchronize do
349
- yield
350
- end
351
-
352
- break
384
+ sleep 0.2 while @httpserv and @httpserv.working_count and @httpserv.working_count > 0
385
+ @paused_mutex.synchronize do
386
+ yield
353
387
  end
354
388
  ensure
355
389
  self.unpause
356
390
  end
357
391
  end
358
392
 
393
+ #Returns true if a HTTP-request is working. Otherwise false.
359
394
  def working?
360
395
  return true if @httpserv and @httpserv.working_count > 0
361
396
  return false
@@ -366,76 +401,15 @@ class Knjappserver
366
401
  return Thread.current[:knjappserver]
367
402
  end
368
403
 
369
- def session_fromid(args)
370
- ip = args[:ip].to_s
371
- idhash = args[:idhash].to_s
372
- ip = "bot" if idhash == "bot"
373
-
374
- @sessions[ip] = {} if !@sessions.has_key?(ip)
375
-
376
- if !@sessions[ip].has_key?(idhash)
377
- session = @ob.get_by(:Session, {"idhash" => args[:idhash]})
378
- if !session
379
- session = @ob.add(:Session, {
380
- :idhash => idhash,
381
- :ip => ip
382
- })
383
- end
384
-
385
- @sessions[ip][idhash] = {
386
- :dbobj => session,
387
- :hash => {}
388
- }
389
- end
390
-
391
- @sessions[ip][idhash][:time_lastused] = Time.now
392
- return @sessions[ip][idhash]
393
- end
394
-
395
- def trans(obj, key)
396
- args = {}
397
- args[:locale] = _session[:locale] if _session[:locale] and !args[:locale]
398
- args[:locale] = _httpsession.data[:locale] if _httpsession.data[:locale] and !args[:locale]
399
- @translations.get(obj, key, args)
400
- end
401
-
402
- def trans_set(obj, values)
403
- args = {}
404
- args[:locale] = _session[:locale] if _session[:locale] and !args[:locale]
405
- args[:locale] = _httpsession.data[:locale] if _httpsession.data[:locale] and !args[:locale]
406
- @translations.set(obj, values, args)
407
- end
408
-
409
- def trans_del(obj)
410
- @translations.delete(obj)
411
- end
412
-
413
- def import(filepath)
414
- _httpsession.eruby.import(filepath)
415
- end
416
-
417
- def update_db
418
- require "rubygems"
419
- require "#{@config[:knjdbrevision_path]}knjdbrevision"
420
-
421
- dbschemapath = "#{File.dirname(__FILE__)}/../files/database_schema.rb"
422
- raise "'#{dbschemapath}' did not exist." if !File.exists?(dbschemapath)
423
- require dbschemapath
424
- raise "No schema-variable was spawned." if !$tables
425
-
426
- dbpath = "#{File.dirname(__FILE__)}/../files/database.sqlite3"
427
- dbrev = Knjdbrevision.new
428
- dbrev.init_db($tables, @db)
429
- end
430
-
404
+ #Sleeps until the server is stopped.
431
405
  def join
432
406
  raise "No http-server or http-server not running." if !@httpserv or !@httpserv.thread_accept
433
407
 
434
408
  begin
435
409
  @httpserv.thread_accept.join
436
- @httpserv.thread_restart.join
410
+ @httpserv.thread_restart.join if @httpserv and @httpserv.thread_restart
437
411
  rescue Interrupt
438
- stop
412
+ self.stop
439
413
  end
440
414
 
441
415
  if @should_restart
@@ -450,6 +424,7 @@ class Knjappserver
450
424
  end
451
425
  end
452
426
 
427
+ #Defines a variable as a method bound to the threads spawned by this instance of Knjappserver.
453
428
  def define_magic_var(method_name, var)
454
429
  @magic_vars[method_name] = var
455
430