knjappserver 0.0.15 → 0.0.16

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