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.
- data/Gemfile +4 -2
- data/Gemfile.lock +24 -10
- data/README.rdoc +298 -1
- data/VERSION +1 -1
- data/bin/check_running.rb +2 -2
- data/knjappserver.gemspec +23 -5
- data/lib/files/database_schema.rb +124 -111
- data/lib/include/class_customio.rb +19 -5
- data/lib/include/class_erbhandler.rb +5 -22
- data/lib/include/class_httpresp.rb +66 -28
- data/lib/include/class_httpserver.rb +27 -14
- data/lib/include/class_httpsession.rb +161 -212
- data/lib/include/class_httpsession_contentgroup.rb +144 -0
- data/lib/include/class_httpsession_knjengine.rb +33 -68
- data/lib/include/class_httpsession_mongrel.rb +1 -1
- data/lib/include/class_httpsession_webrick.rb +1 -1
- data/lib/include/class_knjappserver.rb +105 -130
- data/lib/include/class_knjappserver_cleaner.rb +20 -13
- data/lib/include/class_knjappserver_cmdline.rb +44 -0
- data/lib/include/class_knjappserver_errors.rb +4 -1
- data/lib/include/class_knjappserver_logging.rb +48 -8
- data/lib/include/class_knjappserver_mailing.rb +36 -14
- data/lib/include/class_knjappserver_sessions.rb +78 -0
- data/lib/include/class_knjappserver_threadding.rb +18 -45
- data/lib/include/class_knjappserver_threadding_timeout.rb +78 -0
- data/lib/include/class_knjappserver_translations.rb +30 -0
- data/lib/include/class_knjappserver_web.rb +55 -3
- data/lib/include/class_log.rb +31 -3
- data/lib/include/class_log_access.rb +0 -15
- data/lib/include/class_log_data.rb +0 -15
- data/lib/include/class_log_data_link.rb +1 -14
- data/lib/include/class_log_data_value.rb +5 -17
- data/lib/include/class_session.rb +6 -18
- data/lib/include/magic_methods.rb +12 -14
- data/lib/pages/benchmark.rhtml +0 -0
- data/lib/pages/benchmark_print.rhtml +14 -0
- data/lib/pages/benchmark_simple.rhtml +3 -0
- data/lib/pages/benchmark_threadded_content.rhtml +21 -0
- data/lib/pages/spec.rhtml +26 -0
- data/lib/pages/spec_test_multiple_clients.rhtml +3 -0
- data/lib/pages/spec_threadded_content.rhtml +38 -0
- data/lib/scripts/benchmark.rb +65 -0
- data/spec/knjappserver_spec.rb +87 -43
- 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
|
-
|
36
|
-
|
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 =
|
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::
|
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 =
|
126
|
+
form_data = {}
|
141
127
|
return form_data unless io
|
142
128
|
data = nil
|
143
|
-
|
129
|
+
|
130
|
+
io.each do |line|
|
144
131
|
if boundary_regexp =~ line
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
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
|
-
|
158
|
-
|
159
|
-
|
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
|
-
|
187
|
-
|
188
|
-
end
|
152
|
+
return form_data
|
153
|
+
end
|
189
154
|
end
|
@@ -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, :
|
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 @
|
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 @
|
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 @
|
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 "
|
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 @
|
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 @
|
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 @
|
177
|
-
|
178
|
-
|
179
|
-
|
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 @
|
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
|
-
|
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 @
|
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
|
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 @
|
266
|
+
print "Init mailing.\n" if @debug
|
218
267
|
initialize_mailing
|
219
268
|
|
220
|
-
print "Init errors.\n" if @
|
269
|
+
print "Init errors.\n" if @debug
|
221
270
|
initialize_errors
|
222
271
|
|
223
|
-
print "Init logging.\n" if @
|
272
|
+
print "Init logging.\n" if @debug
|
224
273
|
initialize_logging
|
225
274
|
|
226
|
-
print "Init cleaner.\n" if @
|
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 @
|
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 @
|
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 @
|
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 @
|
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 @
|
327
|
+
STDOUT.print "Threadpool startet.\n" if @debug
|
274
328
|
@httpserv.start
|
275
|
-
print "Appserver startet.\n" if @
|
329
|
+
STDOUT.print "Appserver startet.\n" if @debug
|
276
330
|
rescue Interrupt
|
277
|
-
print "Got interrupt - stopping appserver.\n" if @
|
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
|
-
|
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 @
|
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
|
-
#
|
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
|
-
|
343
|
-
|
344
|
-
|
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
|
-
|
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
|
|