Class: Knjappserver

Inherits:
Object
  • Object
show all
Defined in:
lib/include/class_knjappserver.rb,
lib/files/database_schema.rb,
lib/scripts/knjappserver_cgi.rb,
lib/scripts/knjappserver_fcgi.rb,
lib/include/class_knjappserver_web.rb,
lib/include/class_knjappserver_errors.rb,
lib/include/class_knjappserver_cleaner.rb,
lib/include/class_knjappserver_cmdline.rb,
lib/include/class_knjappserver_logging.rb,
lib/include/class_knjappserver_mailing.rb,
lib/include/class_knjappserver_sessions.rb,
lib/include/class_knjappserver_threadding.rb,
lib/include/class_knjappserver_translations.rb

Overview

The class that stands for the whole appserver / webserver.

Examples

appsrv = Knjappserver.new(

:locales_root => "/some/path/locales",
:locales_gettext_funcs => true,
:magic_methods => true

) appsrv.start appsrv.join

Defined Under Namespace

Classes: CustomIO, ERBHandler, Httpserver, Httpsession, Leakproxy_client, Leakproxy_server, Log, Log_access, Log_data, Log_data_link, Log_data_value, Log_link, Mail, Session, Thread_instance, Threadding_timeout

Constant Summary collapse

DATABASE_SCHEMA =
{
  "tables" => {
    "Log" => {
      "columns" => [
        {"name" => "id", "type" => "bigint", "autoincr" => true, "primarykey" => true},
        {"name" => "text_value_id", "type" => "bigint"},
        {"name" => "date_saved", "type" => "datetime"},
        {"name" => "get_keys_data_id", "type" => "bigint"},
        {"name" => "get_values_data_id", "type" => "bigint"},
        {"name" => "post_keys_data_id", "type" => "bigint"},
        {"name" => "post_values_data_id", "type" => "bigint"},
        {"name" => "cookie_keys_data_id", "type" => "bigint"},
        {"name" => "cookie_values_data_id", "type" => "bigint"},
        {"name" => "meta_keys_data_id", "type" => "bigint"},
        {"name" => "meta_values_data_id", "type" => "bigint"},
        {"name" => "session_keys_data_id", "type" => "bigint"},
        {"name" => "session_values_data_id", "type" => "bigint"},
        {"name" => "tag_data_id", "type" => "bigint"},
        {"name" => "comment_data_id", "type" => "bigint"}
      ],
      "indexes" => [
        {"name" => "text_value_id", "columns" => ["text_value_id"]},
        {"name" => "tag_data_id", "columns" => ["tag_data_id"]},
        {"name" => "comment_data_id", "columns" => ["comment_data_id"]}
      ]
    },
    "Log_access" => {
      "columns" => [
        {"name" => "id", "type" => "bigint", "autoincr" => true, "primarykey" => true},
        {"name" => "session_id", "type" => "bigint"},
        {"name" => "date_request", "type" => "datetime"},
        {"name" => "ip_data_id", "type" => "bigint"},
        {"name" => "get_keys_data_id", "type" => "bigint"},
        {"name" => "get_values_data_id", "type" => "bigint"},
        {"name" => "post_keys_data_id", "type" => "bigint"},
        {"name" => "post_values_data_id", "type" => "bigint"},
        {"name" => "cookie_keys_data_id", "type" => "bigint"},
        {"name" => "cookie_values_data_id", "type" => "bigint"},
        {"name" => "meta_keys_data_id", "type" => "bigint"},
        {"name" => "meta_values_data_id", "type" => "bigint"}
      ],
      "indexes" =>  [
        {"name" => "session_id", "columns" => ["session_id"]},
        {"name" => "date_request", "columns" => ["date_request"]}
      ]
    },
    "Log_data" => {
      "columns" => [
        {"name" => "id", "type" => "bigint", "autoincr" => true, "primarykey" => true},
        {"name" => "id_hash", "type" => "varchar"}
      ],
      "indexes" => [
        {"name" => "id_hash", "columns" => ["id_hash"]}
      ]
    },
    "Log_data_link" => {
      "columns" => [
        {"name" => "id", "type" => "bigint", "autoincr" => true, "primarykey" => true},
        {"name" => "no", "type" => "int"},
        {"name" => "data_id", "type" => "bigint"},
        {"name" => "value_id", "type" => "bigint"}
      ],
      "indexes" => [
        {"name" => "data_id", "columns" => ["data_id"]},
        {"name" => "value_id", "columns" => ["value_id"]}
      ]
    },
    "Log_data_value" => {
      "columns" => [
        {"name" => "id", "type" => "bigint", "autoincr" => true, "primarykey" => true},
        {"name" => "value", "type" => "text"}
      ]
    },
    "Log_link" => {
      "columns" => [
        {"name" => "id", "type" => "bigint", "autoincr" => true, "primarykey" => true},
        {"name" => "log_id", "type" => "bigint"},
        {"name" => "object_class_value_id", "type" => "bigint"},
        {"name" => "object_id", "type" => "bigint"}
      ],
      "indexes" => [
        {"name" => "log_id", "columns" => ["log_id"]},
        {"name" => "object_id", "columns" => ["object_id"]},
        {"name" => "object_class_value_id", "columns" => ["object_class_value_id"]},
        {"name" => "object_lookup", "columns" => ["object_class_value_id", "object_id"]},
        {"name" => "log_lookup", "columns" => ["object_class_value_id", "object_id", "log_id"]}
      ]
    },
    "Session" => {
      "columns" => [
        {"name" => "id", "type" => "bigint", "autoincr" => true, "primarykey" => true},
        {"name" => "idhash", "type" => "varchar"},
        {"name" => "sess_data", "type" => "text"},
        {"name" => "date_added", "type" => "datetime"},
        {"name" => "date_lastused", "type" => "datetime", "on_created" => proc{|d| d["db"].query("UPDATE Session SET date_lastused = '#{Datet.new.dbstr}'")}},
        {"name" => "ip", "type" => "varchar", "maxlength" => 15},
        {"name" => "user_agent", "type" => "text"},
        {"name" => "remember", "type" => "enum", "maxlength" => "'0','1'", "default" => 0, "comment" => "If the session should be remembered or not."}
      ],
      "indexes" => [
        {"name" => "date_added", "columns" => ["date_added"]},
        {"name" => "idhash", "columns" => ["idhash"]}
      ],
      "renames" => ["sessions"]
    },
    "Translation" => {
      "columns" => [
        {"name" => "id", "type" => "bigint", "autoincr" => true, "primarykey" => true},
        {"name" => "object_class", "type" => "varchar", "maxlength" => 50},
        {"name" => "object_id", "type" => "bigint"},
        {"name" => "key", "type" => "varchar", "maxlength" => 50},
        {"name" => "locale", "type" => "varchar", "maxlength" => 5},
        {"name" => "value", "type" => "text"}
      ],
      "indexes" => [
        {"name" => "lookup", "columns" => ["object_class", "object_id", "key", "locale"]}
      ],
      "indexes_remove" => {
        "object_class" => true
      }
    }
  }
}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ Knjappserver

Returns a new instance of Knjappserver.



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'lib/include/class_knjappserver.rb', line 29

def initialize(config)
  raise "No arguments given." if !config.is_a?(Hash)
  
  @config = {
    :host => "0.0.0.0",
    :timeout => 30,
    :default_page => "index.rhtml",
    :default_filetype => "text/html",
    :max_requests_working => 20,
    :size_send => 1024,
    :cleaner_timeout => 300
  }.merge(config)
  
  @config[:smtp_args] = {"smtp_host" => "localhost", "smtp_port" => 25} if !@config[:smtp_args]
  @config[:timeout] = 30 if !@config.has_key?(:timeout)
  raise "No ':doc_root' was given in arguments." if !@config.has_key?(:doc_root)
  
  
  #Require gems.
  gems = %w[datet php4r]
  gems.each do |gem|
    puts "Loading gem: '#{gem}'." if @debug
    require gem
  end
  
  
  #Setup default handlers if none are given.
  if !@config.has_key?(:handlers)
    @erbhandler = Knjappserver::ERBHandler.new
    @config[:handlers] = [
      {
        :file_ext => "rhtml",
        :callback => @erbhandler.method(:erb_handler)
      },{
        :path => "/fckeditor",
        :mount => "/usr/share/fckeditor"
      }
    ]
  end
  
  
  #Add extra handlers if given.
  @config[:handlers] += @config[:handlers_extra] if @config[:handlers_extra]
  
  
  #Setup cache to make .rhtml-calls faster.
  @config[:handlers_cache] = {}
  @config[:handlers].each do |handler_info|
    next if !handler_info[:file_ext] or !handler_info[:callback]
    @config[:handlers_cache][handler_info[:file_ext]] = handler_info[:callback]
  end
  
  
  @debug = @config[:debug]
  @paused = 0
  @paused_mutex = Mutex.new
  @should_restart = false
  @mod_events = {}
  @served = 0
  @mod_files = {}
  @sessions = {}
  @eruby_cache = {}
  @httpsessions_ids = {}
  
  @path_knjappserver = File.dirname(__FILE__)
  if @config[:knjrbfw_path]
    @path_knjrbfw = @config[:knjrbfw_path]
  else
    @path_knjrbfw = ""
  end
  
  
  #If auto-restarting is enabled - start the modified events-module.
  if @config[:autorestart]
    paths = [
      "#{@path_knjappserver}/../knjappserver.rb",
      "#{@path_knjappserver}/class_knjappserver.rb",
      "#{@path_knjappserver}/class_customio.rb"
    ]
    
    print "Auto restarting.\n" if @debug
    @mod_event = Knj::Event_filemod.new(:wait => 2, :paths => paths, &self.method(:on_event_filemod))
  end
  
  
  #Set up default file-types and merge given filetypes into it.
  @types = {
    :ico => "image/x-icon",
    :jpeg => "image/jpeg",
    :jpg => "image/jpeg",
    :gif => "image/gif",
    :png => "image/png",
    :html => "text/html",
    :htm => "text/html",
    :rhtml => "text/html",
    :css => "text/css",
    :xml => "text/xml",
    :js => "text/javascript"
  }
  @types.merge!(@config[:filetypes]) if @config.has_key?(:filetypes)
  
  
  
  #Load various required files from knjrbfw and stuff in the knjappserver-framework.
  files = [
    "#{@path_knjrbfw}knjrbfw.rb",
    "#{@path_knjappserver}/class_knjappserver_errors.rb",
    "#{@path_knjappserver}/class_knjappserver_logging.rb",
    "#{@path_knjappserver}/class_knjappserver_mailing.rb",
    "#{@path_knjappserver}/class_knjappserver_sessions.rb",
    "#{@path_knjappserver}/class_knjappserver_translations.rb",
    "#{@path_knjappserver}/class_knjappserver_web.rb"
  ]
  
  files << "#{@path_knjrbfw}knj/gettext_threadded.rb" if @config[:locales_root]
  files.each do |file|
    STDOUT.print "Loading: '#{file}'.\n" if @debug
    self.loadfile(file)
  end
  
  
  print "Setting up database.\n" if @debug
  if @config[:db].is_a?(Knj::Db)
    @db = @config[:db]
  elsif @config[:db].is_a?(Hash)
    @db = Knj::Db.new(@config[:db])
  elsif !@config[:db] and @config[:db_args]
    @db = Knj::Db.new(@config[:db_args])
  else
    raise "Unknown object given as db: '#{@config[:db].class.name}'."
  end
  
  
  if !@config.key?(:dbrev) or @config[:dbrev]
    print "Updating database.\n" if @debug
    
    dbschemapath = "#{File.dirname(__FILE__)}/../files/database_schema.rb"
    raise "'#{dbschemapath}' did not exist." if !File.exists?(dbschemapath)
    require dbschemapath
    raise "No schema-variable was spawned." if !Knjappserver::DATABASE_SCHEMA
    dbrev_args = {"schema" => Knjappserver::DATABASE_SCHEMA, "db" => @db}
    dbrev_args.merge!(@config[:dbrev_args]) if @config.key?(:dbrev_args)
    Knj::Db::Revision.new.init_db(dbrev_args)
    dbrev_args = nil
  end
  
  
  print "Spawning objects.\n" if @debug
  @ob = Knj::Objects.new(
    :db => db,
    :class_path => @path_knjappserver,
    :module => Knjappserver,
    :datarow => true,
    :knjappserver => self
  )
  @ob.events.connect(:no_date, &self.method(:no_date))
  
  
  if @config[:httpsession_db_args]
    @db_handler = Knj::Db.new(@config[:httpsession_db_args])
  else
    @db_handler = @db
  end
  
  
  #Start the Knj::Gettext_threadded- and Knj::Translations modules for translations.
  print "Loading Gettext and translations.\n" if @debug
  @translations = Knj::Translations.new(:db => @db)
  @ob.requireclass(:Translation, {:require => false, :class => Knj::Translations::Translation})
  
  if @config[:locales_root]
    @gettext = Knj::Gettext_threadded.new("dir" => config[:locales_root])
  end
  
  require "#{@path_knjappserver}/gettext_funcs" if @config[:locales_gettext_funcs]
  
  if @config[:magic_methods] or !@config.has_key?(:magic_methods)
    print "Loading magic-methods.\n" if @debug
    require "#{@path_knjappserver}/magic_methods"
  end
  
  if @config[:customio] or !@config.has_key?(:customio)
    print "Loading custom-io.\n" if @debug
    
    if $stdout.class.name != "Knjappserver::CustomIO"
      require "#{@path_knjappserver}/class_customio.rb"
      @cio = Knjappserver::CustomIO.new
      $stdout = @cio
    end
  end
  
  
  #Save the PID to the run-file.
  print "Setting run-file.\n" if @debug
  tmpdir = "#{Knj::Os.tmpdir}/knjappserver"
  tmppath = "#{tmpdir}/run_#{@config[:title]}"
  
  if !File.exists?(tmpdir)
    Dir.mkdir(tmpdir)
    File.chmod(0777, tmpdir)
  end
  
  File.open(tmppath, "w") do |fp|
    fp.write(Process.pid)
  end
  File.chmod(0777, tmppath)
  
  
  #Set up various events for the appserver.
  if !@config.key?(:events) or @config[:events]
    print "Loading events.\n" if @debug
    @events = Knj::Event_handler.new
    @events.add_event(
      :name => :check_page_access,
      :connections_max => 1
    )
    @events.add_event(
      :name => :ob,
      :connections_max => 1
    )
    @events.add_event(
      :name => :trans_no_str,
      :connections_max => 1
    )
    @events.add_event(
      :name => :request_done,
      :connections_max => 1
    )
    @events.add_event(
      :name => :request_begin,
      :connections_max => 1
    )
    
    #This event is used if the user himself wants stuff to be cleaned up when the appserver is cleaning up stuff.
    @events.add_event(
      :name => :on_clean
    )
  end
  
  #Set up the 'vars'-variable that can be used to set custom global variables for web-requests.
  @vars = Knj::Hash_methods.new
  @magic_vars = {}
  @magic_procs = {}
  
  
  #Initialize the various feature-modules.
  print "Init sessions.\n" if @debug
  self.initialize_sessions
  
  if !@config.key?(:threadding) or @config[:threadding]
    self.loadfile("#{@path_knjappserver}/class_knjappserver_threadding.rb")
    self.loadfile("#{@path_knjappserver}/class_knjappserver_threadding_timeout.rb")
    print "Init threadding.\n" if @debug
    self.initialize_threadding
  end
  
  print "Init mailing.\n" if @debug
  self.initialize_mailing
  
  print "Init errors.\n" if @debug
  self.initialize_errors
  
  print "Init logging.\n" if @debug
  self.initialize_logging
  
  if !@config.key?(:cleaner) or @config[:cleaner]
    self.loadfile("#{@path_knjappserver}/class_knjappserver_cleaner.rb")
    print "Init cleaner.\n" if @debug
    self.initialize_cleaner
  end
  
  if !@config.key?(:cmdline) or @config[:cmdline]
    self.loadfile("#{@path_knjappserver}/class_knjappserver_cmdline.rb")
    print "Init cmdline.\n" if @debug
    self.initialize_cmdline
  end
  
  
  #Clear memory at exit.
  Kernel.at_exit(&self.method(:stop))
  
  
  print "Appserver spawned.\n" if @debug
end

Instance Attribute Details

#cioObject (readonly)

Returns the value of attribute cio.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def cio
  @cio
end

#configObject (readonly)

Returns the value of attribute config.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def config
  @config
end

#dbObject (readonly)

Returns the value of attribute db.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def db
  @db
end

#db_handlerObject (readonly)

Returns the value of attribute db_handler.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def db_handler
  @db_handler
end

#debugObject (readonly)

Returns the value of attribute debug.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def debug
  @debug
end

#error_emails_pendingObject (readonly)

Returns the value of attribute error_emails_pending.



2
3
4
# File 'lib/include/class_knjappserver_errors.rb', line 2

def error_emails_pending
  @error_emails_pending
end

#eruby_cacheObject (readonly)

Returns the value of attribute eruby_cache.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def eruby_cache
  @eruby_cache
end

#eventsObject (readonly)

Returns the value of attribute events.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def events
  @events
end

#gettextObject (readonly)

Returns the value of attribute gettext.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def gettext
  @gettext
end

#httpservObject (readonly)

Returns the value of attribute httpserv.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def httpserv
  @httpserv
end

#httpsessions_idsObject (readonly)

Returns the value of attribute httpsessions_ids.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def httpsessions_ids
  @httpsessions_ids
end

#logs_access_pendingObject (readonly)

Returns the value of attribute logs_access_pending.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def logs_access_pending
  @logs_access_pending
end

#magic_procsObject (readonly)

Returns the value of attribute magic_procs.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def magic_procs
  @magic_procs
end

#magic_varsObject (readonly)

Returns the value of attribute magic_vars.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def magic_vars
  @magic_vars
end

#mails_waitingObject (readonly)

Returns the value of attribute mails_waiting.



2
3
4
# File 'lib/include/class_knjappserver_mailing.rb', line 2

def mails_waiting
  @mails_waiting
end

#mod_eventObject (readonly)

Returns the value of attribute mod_event.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def mod_event
  @mod_event
end

#obObject (readonly)

Returns the value of attribute ob.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def ob
  @ob
end

#pausedObject (readonly)

Returns the value of attribute paused.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def paused
  @paused
end

#servedObject

Returns the value of attribute served.



21
22
23
# File 'lib/include/class_knjappserver.rb', line 21

def served
  @served
end

#sessionsObject (readonly)

Returns the value of attribute sessions.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def sessions
  @sessions
end

#should_restartObject

Returns the value of attribute should_restart.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def should_restart
  @should_restart
end

#should_restart_doneObject

Returns the value of attribute should_restart_done.



21
22
23
# File 'lib/include/class_knjappserver.rb', line 21

def should_restart_done
  @should_restart_done
end

#threadpoolObject (readonly)

Returns the value of attribute threadpool.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def threadpool
  @threadpool
end

#translationsObject (readonly)

Returns the value of attribute translations.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def translations
  @translations
end

#typesObject (readonly)

Returns the value of attribute types.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def types
  @types
end

#varsObject (readonly)

Returns the value of attribute vars.



20
21
22
# File 'lib/include/class_knjappserver.rb', line 20

def vars
  @vars
end

Class Method Details

.const_missing(name) ⇒ Object

Autoloader for subclasses.



24
25
26
27
# File 'lib/include/class_knjappserver.rb', line 24

def self.const_missing(name)
  require "#{File.dirname(__FILE__)}/class_#{name.to_s.downcase}.rb"
  return Knjappserver.const_get(name)
end

.convert_fcgi_post(params) ⇒ Object



35
36
37
38
39
40
41
42
43
# File 'lib/scripts/knjappserver_cgi.rb', line 35

def self.convert_fcgi_post(params)
  post_hash = {}
  
  params.each do |key, val|
    post_hash[key] = val.first
  end
  
  return post_hash
end

.dataObject



446
447
448
449
# File 'lib/include/class_knjappserver.rb', line 446

def self.data
  raise "Could not register current thread." if !Thread.current[:knjappserver]
  return Thread.current[:knjappserver]
end

.fcgi_start(cgi) ⇒ Object



19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
# File 'lib/scripts/knjappserver_fcgi.rb', line 19

def self.fcgi_start(cgi)
  raise "No HTTP_KNJAPPSERVER_CGI_CONFIG-header was given." if !cgi.env_table["HTTP_KNJAPPSERVER_CGI_CONFIG"]
  require cgi.env_table["HTTP_KNJAPPSERVER_CGI_CONFIG"]
  
  begin
    conf = Knjappserver::CGI_CONF
  rescue NameError
    raise "No 'Knjappserver::CGI_CONF'-constant was spawned by '#{cgi.env_table["HTTP_KNJAPPSERVER_CGI_CONFIG"]}'."
  end
  
  knjappserver_conf = Knjappserver::CGI_CONF["knjappserver"]
  knjappserver_conf.merge!(
    :cmdline => false,
    :port => 0 #Ruby picks random port and we get the actual port after starting the appserver.
  )
  
  knjappserver = Knjappserver.new(knjappserver_conf)
  knjappserver.start
  
  port = knjappserver.port
  http = Http2.new(:host => "localhost", :port => port)
  
  return [knjappserver, http]
end

Instance Method Details

#alert(msg) ⇒ Object

Sends a javascript-alert to the HTML.

Examples

_kas.alert("Hello world!")


36
37
38
39
40
# File 'lib/include/class_knjappserver_web.rb', line 36

def alert(msg)
  _httpsession.alert_sent = true
  Knj::Web.alert(msg)
  return self
end

#backObject

Sends a javascript back to the browser and exits.



126
127
128
# File 'lib/include/class_knjappserver_web.rb', line 126

def back
  Knj::Web.back
end

#cleanObject



10
11
12
13
# File 'lib/include/class_knjappserver_cleaner.rb', line 10

def clean
   self.clean_sessions
   self.clean_autorestart
end

#clean_autorestartObject



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/include/class_knjappserver_cleaner.rb', line 15

def clean_autorestart
   begin
     if @config[:autorestart]
       time = 1
     else
       time = 15
     end
     
     loop do
       sleep time
       
       if @config.has_key?(:restart_when_used_memory) and !@should_restart
         mbs_used = (Php4r.memory_get_usage / 1024) / 1024
         STDOUT.print "Restart when over #{@config[:restart_when_used_memory]}mb\n" if @config[:debug]
         STDOUT.print "Used: #{mbs_used}mb\n" if @config[:debug]
         
         if mbs_used.to_i >= @config[:restart_when_used_memory].to_i
           STDOUT.print "Memory is over #{@config[:restart_when_used_memory]} - restarting.\n"
           @should_restart = true
         end
       end
       
       if @should_restart and !@should_restart_done and !@should_restart_runnning
         begin
           @should_restart_runnning = true
           
           #When we begin to restart it should go as fast as possible - so start by flushing out any emails waiting so it goes faster the last time...
           STDOUT.print "Flushing mails.\n"
           self.mail_flush
           
           #Lets try to find a time where no thread is working within the next 30 seconds. If we cant - we interrupt after 10 seconds and restart the server.
           begin
             Timeout.timeout(30) do
               loop do
                 working_count = self.httpserv.working_count
                 working = false
                 
                 if working_count and working_count > 0
                   working = true
                   STDOUT.print "Someone is working - wait two sec and try to restart again!\n"
                 end
                 
                 if !working
                   STDOUT.print "Found window where no sessions were active - restarting!\n"
                   break
                 else
                   sleep 0.2
                 end
                 
                 STDOUT.print "Trying to find window with no active sessions to restart...\n"
               end
             end
           rescue Timeout::Error
             STDOUT.print "Could not find a timing window for restarting... Forcing restart!\n"
           end
           
           #Flush emails again if any are pending (while we tried to find a window to restart)...
           STDOUT.print "Flushing mails.\n"
           self.mail_flush
           
           STDOUT.print "Stopping appserver.\n"
           self.stop
           
           STDOUT.print "Figuring out restart-command.\n"
           mycmd = @config[:restart_cmd]
           
           if !mycmd or mycmd.to_s.strip.length <= 0
             fpath = File.realpath("#{File.dirname(__FILE__)}/../knjappserver.rb")
             mycmd = Knj::Os.executed_cmd
             
             STDOUT.print "Previous cmd: #{mycmd}\n"
             mycmd = mycmd.gsub(/\s+knjappserver.rb/, " #{Knj::Strings.unixsafe(fpath)}")
           end
           
           STDOUT.print "Restarting knjAppServer with command: #{mycmd}\n"
           @should_restart_done = true
           print exec(mycmd)
           exit
         rescue => e
           STDOUT.puts e.inspect
           STDOUT.puts e.backtrace
         end
       end
     end
   rescue => e
     self.handle_error(e)
   end
end

#clean_sessionsObject

This method can be used to clean the appserver. Dont call this from a HTTP-request.



105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
# File 'lib/include/class_knjappserver_cleaner.rb', line 105

def clean_sessions
   STDOUT.print "Cleaning sessions on appserver.\n" if @config[:debug]
   
   #Clean up various inactive sessions.
   session_not_ids = []
   time_check = Time.now.to_i - 300
   newsessions = {}
   @sessions.each do |session_hash, session_data|
     session_data[:dbobj].flush
     
     if session_data[:time_lastused].to_i > time_check
       newsessions[session_hash] = session_data
       session_not_ids << session_data[:dbobj].id
     end
   end
   
   @sessions = newsessions
   
   STDOUT.print "Delete sessions...\n" if @config[:debug]
   @ob.list(:Session, {"id_not" => session_not_ids, "date_lastused_below" => (Time.now - 5356800)}) do |session|
     idhash = session[:idhash]
     STDOUT.print "Deleting session: '#{session.id}'.\n" if @config[:debug]
     @ob.delete(session)
     @sessions.delete(idhash)
   end
   
   #Clean database weak references from the tables-module.
   @db.clean
   
   #Clean the object-handler.
   @ob.clean_all
   
   #Call various user-connected methods.
   @events.call(:on_clean) if @events
end

#cmd_connect(cmd, &block) ⇒ Object

Connects a proc to a specific command in the command-line (key should be a regex).



48
49
50
51
# File 'lib/include/class_knjappserver_cmdline.rb', line 48

def cmd_connect(cmd, &block)
  @cmds[cmd] = [] if !@cmds.key?(cmd)
  @cmds[cmd] << {:block => block}
end

#cmdline_on_restart_cmd(data) ⇒ Object



37
38
39
40
# File 'lib/include/class_knjappserver_cmdline.rb', line 37

def cmdline_on_restart_cmd(data)
  print "Restart will begin shortly.\n"
  self.should_restart = true
end

#cmdline_on_stop_cmd(data) ⇒ Object



42
43
44
45
# File 'lib/include/class_knjappserver_cmdline.rb', line 42

def cmdline_on_stop_cmd(data)
  print "Stopping appserver.\n"
  self.stop
end

Define a cookies in the clients browser.

Examples

_kas.cookie(:name => "MyCookie", :value => "Trala")


45
46
47
48
49
50
51
# File 'lib/include/class_knjappserver_web.rb', line 45

def cookie(cookie)
  raise "No HTTP-session attached to this thread." if !_httpsession
  raise "HTTP-session not active." if !_httpsession.resp
  raise "Not a hash: '#{cookie.class.name}', '#{cookie}'." unless cookie.is_a?(Hash)
  _httpsession.resp.cookie(cookie)
  return nil
end

#debugs(str) ⇒ Object

Prints a string with a single file-line-backtrace prepended which is useful for debugging.



129
130
131
132
133
134
# File 'lib/include/class_knjappserver_errors.rb', line 129

def debugs(str)
  #Get backtrace.
  backtrace_str = caller[0]
  backtrace_match = backtrace_str.match(/^(.+):(\d+):in /)
  STDOUT.print "#{File.basename(backtrace_match[1])}:#{backtrace_match[2]}: #{str}\n"
end

#define_magic_proc(method_name, &block) ⇒ Object



486
487
488
489
490
491
492
493
494
495
496
# File 'lib/include/class_knjappserver.rb', line 486

def define_magic_proc(method_name, &block)
  raise "No block given." if !block_given?
  @magic_procs[method_name] = block
  
  if !Object.respond_to?(method_name)
    Object.send(:define_method, method_name) do
      return Thread.current[:knjappserver][:kas].magic_procs[method_name].call(:kas => self) if Thread.current[:knjappserver] and Thread.current[:knjappserver][:kas]
      raise "Could not figure out the object: '#{method_name}'."
    end
  end
end

#define_magic_var(method_name, var) ⇒ Object

Defines a variable as a method bound to the threads spawned by this instance of Knjappserver.



475
476
477
478
479
480
481
482
483
484
# File 'lib/include/class_knjappserver.rb', line 475

def define_magic_var(method_name, var)
  @magic_vars[method_name] = var
  
  if !Object.respond_to?(method_name)
    Object.send(:define_method, method_name) do
      return Thread.current[:knjappserver][:kas].magic_vars[method_name] if Thread.current[:knjappserver] and Thread.current[:knjappserver][:kas]
      raise "Could not figure out the object: '#{method_name}'."
    end
  end
end

#dprint(obj) ⇒ Object

Prints a detailed overview of the object in the terminal from where the appserver was started. This can be used for debugging.



124
125
126
# File 'lib/include/class_knjappserver_errors.rb', line 124

def dprint(obj)
  STDOUT.print Php4r.print_r(obj, true)
end

#flush_access_logObject

Writes all queued access-logs to the database.



12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/include/class_knjappserver_logging.rb', line 12

def flush_access_log
   return nil if @logs_access_pending.empty?
   
	@logs_mutex.synchronize do
		ins_arr = @logs_access_pending
		@logs_access_pending = []
		inserts = []
		inserts_links = []
		
		ins_arr.each do |ins|
			gothrough = [{
				:col => :get_keys_data_id,
				:hash => ins[:get],
				:type => :keys
			},{
				:col => :get_values_data_id,
				:hash => ins[:get],
				:type => :values
			},{
				:col => :post_keys_data_id,
				:hash => ins[:post],
				:type => :keys
			},{
				:col => :post_values_data_id,
				:hash => ins[:post],
				:type => :values
			},{
				:col => :cookie_keys_data_id,
				:hash => ins[:cookie],
				:type => :keys
			},{
				:col => :cookie_values_data_id,
				:hash => ins[:cookie],
				:type => :values
			},{
				:col => :meta_keys_data_id,
				:hash => ins[:meta],
				:type => :keys
			},{
				:col => :meta_values_data_id,
				:hash => ins[:meta],
				:type => :values
			}]
			ins_hash = {
				:session_id => ins[:session_id],
				:date_request => ins[:date_request]
			}
			
			gothrough.each do |data|
				if data[:type] == :keys
					hash = Knj::ArrayExt.hash_keys_hash(data[:hash])
				else
					hash = Knj::ArrayExt.hash_values_hash(data[:hash])
				end
				
				data_id = @ob.static(:Log_data, :by_id_hash, hash)
				if !data_id
					data_id = @db.insert(:Log_data, {"id_hash" => hash}, {:return_id => true})
					
					link_count = 0
					data[:hash].keys.sort.each do |key|
						if data[:type] == :keys
							ins_data = "#{key.to_s}"
						else
							ins_data = "#{data[:hash][key]}"
						end
						
						ins_data = ins_data.force_encoding("UTF-8") if ins_data.respond_to?(:force_encoding)
						data_value_id = @ob.static(:Log_data_value, :force_id, ins_data)
						inserts_links << {:no => link_count, :data_id => data_id, :value_id => data_value_id}
						link_count += 1
					end
				end
				
				ins_hash[data[:col]] = data_id
			end
			
			hash = Knj::ArrayExt.array_hash(ins[:ips])
			data_id = @ob.static(:Log_data, :by_id_hash, hash)
			
			if !data_id
				data_id = @db.insert(:Log_data, {"id_hash" => hash}, {:return_id => true})
				
				link_count = 0
				ins[:ips].each do |ip|
           data_value_id = @ob.static(:Log_data_value, :force_id, ip)
					inserts_links << {:no => link_count, :data_id => data_id, :value_id => data_value_id}
					link_count += 1
				end
			end
			
			ins_hash[:ip_data_id] = data_id
			inserts << ins_hash
		end
		
		@db.insert_multi(:Log_access, inserts)
		@db.insert_multi(:Log_data_link, inserts_links)
		@ob.unset_class([:Log_access, :Log_data, :Log_data_link, :Log_data_value])
	end
end

#flush_error_emailsObject

Send error-emails based on error-emails-cache (cached so the same error isnt send out every time it occurrs to prevent spamming).



20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
# File 'lib/include/class_knjappserver_errors.rb', line 20

def flush_error_emails
  @error_emails_pending_mutex.synchronize do
    send_time_older_than = Time.new.to_i - @error_emails_time
    
    @error_emails_pending.each do |backtrace_hash, error_email|
      if send_time_older_than < error_email[:last_time].to_i and error_email[:messages].length < 1000
        next
      end
      
      @config[:error_report_emails].each do |email|
        next if !email or error_email[:messages].length <= 0
        
        if error_email[:messages].length == 1
          html = error_email[:messages].first
        else
          html = "<b>First time:</b> #{Datet.in(error_email[:first_time]).out}<br />"
          html << "<b>Last time:</b> #{Datet.in(error_email[:last_time]).out}<br />"
          html << "<b>Number of errors:</b> #{error_email[:messages].length}<br />"
          count = 0
          
          error_email[:messages].each do |error_msg|
            count += 1
            
            if count > 10
              html << "<br /><br /><b><i>Limiting to showing 10 out of #{error_email[:messages].length} messages.</i></b>"
              break
            end
            
            html << "<br /><br />"
            html << "<b>Message #{count}</b><br />"
            html << error_msg
          end
        end
        
        self.mail(
          :to => email,
          :subject => error_email[:subject],
          :html => html,
          :from => @config[:error_report_from]
        )
      end
      
      @error_emails_pending.delete(backtrace_hash)
    end
  end
end

#get_parse_arrays(arg = nil, ob = nil) ⇒ Object

Hashes with numeric keys will be turned into arrays instead. This is not done automatically because it can wrongly corrupt data if not used correctly.



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/include/class_knjappserver_web.rb', line 153

def get_parse_arrays(arg = nil, ob = nil)
  arg = _get.clone if !arg
  
  #Parses key-numeric-hashes into arrays and converts special model-strings into actual models.
  if arg.is_a?(Hash) and Knj::ArrayExt.hash_numeric_keys?(arg)
    arr = []
    
    arg.each do |key, val|
      arr << val
    end
    
    return self.get_parse_arrays(arr, ob)
  elsif arg.is_a?(Hash)
    arg.each do |key, val|
      arg[key] = self.get_parse_arrays(val, ob)
    end
    
    return arg
  elsif arg.is_a?(Array)
    arg.each_index do |key|
      arg[key] = self.get_parse_arrays(arg[key], ob)
    end
    
    return arg
  elsif arg.is_a?(String) and match = arg.match(/^#<Model::(.+?)::(\d+)>$/)
    ob = @ob if !ob
    return ob.get(match[1], match[2])
  else
    return arg
  end
end

#handle_error(e, args = {}) ⇒ Object

Handels a given error. Sends to the admin-emails.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/include/class_knjappserver_errors.rb', line 68

def handle_error(e, args = {})
  @error_emails_pending_mutex.synchronize do
    if !Thread.current[:knjappserver] or !Thread.current[:knjappserver][:httpsession]
      STDOUT.print "#{Knj::Errors.error_str(e)}\n\n"
    end
    
    browser = _httpsession.browser if _httpsession
    
    send_email = true
    send_email = false if !@config[:smtp_args]
    send_email = false if !@config[:error_report_emails]
    send_email = false if args.has_key?(:email) and !args[:email]
    send_email = false if @config.key?(:error_report_bots) and !@config[:error_report_bots] and browser and browser["browser"] == "bot"
    
    if send_email
      backtrace_hash = Knj::ArrayExt.array_hash(e.backtrace)
      
      if !@error_emails_pending.has_key?(backtrace_hash)
        @error_emails_pending[backtrace_hash] = {
          :first_time => Time.new,
          :messages => [],
          :subject => sprintf("Error @ %s", @config[:title]) + " (#{Knj::Strings.shorten(e.message, 100)})"
        }
      end
      
      html = "An error occurred.<br /><br />"
      html << "<b>#{Knj::Web.html(e.class.name)}: #{Knj::Web.html(e.message)}</b><br /><br />"
      
      e.backtrace.each do |line|
        html << "#{Knj::Web.html(line)}<br />"
      end
      
      html << "<br /><b>Post:</b><br /><pre>#{Php4r.print_r(_post, true)}</pre>" if _post
      html << "<br /><b>Get:</b><br /><pre>#{Php4r.print_r(_get, true)}</pre>" if _get
      html << "<br /><b>Server:</b><br /><pre>#{Php4r.print_r(_server, true).html}</pre>" if _server
      html << "<br /><b>Cookie:</b><br /><pre>#{Php4r.print_r(_cookie, true).html}</pre>" if _meta
      html << "<br /><b>Session:</b><br /><pre>#{Php4r.print_r(_session, true).html}</pre>" if _session
      html << "<br /><b>Session hash:</b><br /><pre>#{Php4r.print_r(_session_hash, true).html}</pre>" if _session_hash
      
      error_hash = @error_emails_pending[backtrace_hash]
      error_hash[:last_time] = Time.new
      error_hash[:messages] << html
    end
  end
end

#header(key, val) ⇒ Object

Sends a header to the clients browser.

Examples

_kas.header("Content-Type", "text/javascript")


56
57
58
59
60
61
# File 'lib/include/class_knjappserver_web.rb', line 56

def header(key, val)
  raise "No HTTP-session attached to this thread." if !_httpsession
  raise "HTTP-session not active." if !_httpsession.resp
  _httpsession.resp.header(key, val)
  return nil
end

#header_raw(str) ⇒ Object

Sends a raw header-line to the clients browser.



64
65
66
67
68
69
# File 'lib/include/class_knjappserver_web.rb', line 64

def header_raw(str)
  raise "No HTTP-session attached to this thread." if !_httpsession
  raise "HTTP-session not active." if !_httpsession.resp
  Php4r.header(str)
  return nil
end

#headers_send_size=(newsize) ⇒ Object

Define the size for when to automatically send headers. If you want to send hundres of kilobytes and then a header, you can use this method to do so.

Examples

Set the size to 200 kb.

_kas.headers_send_size = (1024 * 200)


83
84
85
86
87
# File 'lib/include/class_knjappserver_web.rb', line 83

def headers_send_size=(newsize)
  raise "The headers are already sent and you cannot modify the send-size any more." if self.headers_sent?
  _httpsession.size_send = newsize.to_i
  return nil
end

#headers_sent?Boolean

Returns true if the headers are already sent.

Examples

_kas.headers_sent? #=> true

Returns:

  • (Boolean)


74
75
76
77
# File 'lib/include/class_knjappserver_web.rb', line 74

def headers_sent?
  return true if _httpsession.resp.headers_sent
  return false
end

#import(filepath) ⇒ Object

Imports a .rhtml-file and executes it.

Examples

_kas.import("/some/path/page.rhtml")


5
6
7
8
9
10
11
# File 'lib/include/class_knjappserver_web.rb', line 5

def import(filepath)
  if filepath.to_s.index("../proc/self") != nil
    raise Errno::EACCES, "Possible attempt to hack the appserver."
  end
  
  _httpsession.eruby.import(filepath)
end

#initialize_cleanerObject



2
3
4
5
6
7
8
# File 'lib/include/class_knjappserver_cleaner.rb', line 2

def initialize_cleaner
   #This should not be runned via _kas.timeout because timeout wont run when @should_restart is true! - knj
   Thread.new(&self.method(:clean_autorestart))
   
   #This flushes (writes) all session-data to the server and deletes old unused sessions from the database.
   self.timeout(:time => @config[:cleaner_timeout], &self.method(:clean_sessions))
end

#initialize_cmdlineObject



2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/include/class_knjappserver_cmdline.rb', line 2

def initialize_cmdline
  @cmds = {}
  
  Thread.new do
    begin
      $stdin.each_line do |line|
        called = 0
        @cmds.each do |key, connects|
          data = {}
          
          if key.is_a?(Regexp)
            if line.match(key)
              connects.each do |conn|
                called += 1
                conn[:block].call(data)
              end
            end
          else
            raise "Unknown class for 'cmd_connect': '#{key.class.name}'."
          end
        end
        
        if called == 0
          print "Unknown command: '#{line.strip}'.\n"
        end
      end
    rescue => e
      self.handle_error(e)
    end
  end
  
  self.cmd_connect(/^\s*restart\s*$/i, &self.method(:cmdline_on_restart_cmd))
  self.cmd_connect(/^\s*stop\s*$/i, &self.method(:cmdline_on_stop_cmd))
end

#initialize_errorsObject



4
5
6
7
8
9
10
11
12
13
14
15
16
17
# File 'lib/include/class_knjappserver_errors.rb', line 4

def initialize_errors
  @error_emails_pending = {}
  @error_emails_pending_mutex = Mutex.new
  
  if @config[:error_emails_time]
    @error_emails_time = @config[:error_emails_time]
  elsif @config[:debug]
    @error_emails_time = 5
  else
    @error_emails_time = 180
  end
  
  self.timeout(:time => @error_emails_time, &self.method(:flush_error_emails))
end

#initialize_loggingObject



2
3
4
5
6
7
8
9
# File 'lib/include/class_knjappserver_logging.rb', line 2

def initialize_logging
	@logs_access_pending = []
	@logs_mutex = Mutex.new
	
	if @config[:logging] and @config[:logging][:access_db]
		self.timeout(:time => 30, &self.method(:flush_access_log))
	end
end

#initialize_mailingObject



4
5
6
7
8
9
10
11
12
# File 'lib/include/class_knjappserver_mailing.rb', line 4

def initialize_mailing
   require "knj/autoload/ping"
   require "monitor"
   
	@mails_waiting = []
	@mails_mutex = Monitor.new
	@mails_queue_mutex = Monitor.new
	@mails_timeout = self.timeout(:time => 30, &self.method(:mail_flush))
end

#initialize_sessionsObject



2
3
4
# File 'lib/include/class_knjappserver_sessions.rb', line 2

def initialize_sessions
  @sessions = Tsafe::MonHash.new
end

#initialize_threaddingObject



2
3
4
5
6
7
8
# File 'lib/include/class_knjappserver_threadding.rb', line 2

def initialize_threadding
  @config[:threadding] = {} if !@config.has_key?(:threadding)
  @config[:threadding][:max_running] = 8 if !@config[:threadding].has_key?(:max_running)
  
  @threadpool = Knj::Threadpool.new(:threads => @config[:threadding][:max_running], :sleep => 0.1)
  @threadpool.events.connect(:on_error, &self.method(:threadpool_on_error))
end

#inputs(*args) ⇒ Object

Draw a input in a table.



131
132
133
# File 'lib/include/class_knjappserver_web.rb', line 131

def inputs(*args)
  return Knj::Web.inputs(args)
end

#joinObject

Sleeps until the server is stopped.



452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
# File 'lib/include/class_knjappserver.rb', line 452

def join
  raise "No http-server or http-server not running." if !@httpserv or !@httpserv.thread_accept
  
  begin
    @httpserv.thread_accept.join
    @httpserv.thread_restart.join if @httpserv and @httpserv.thread_restart
  rescue Interrupt => e
    self.stop
  end
  
  if @should_restart
    loop do
      if @should_restart_done
        STDOUT.print "Ending join because the restart is done.\n"
        break
      end
      
      sleep 1
    end
  end
end

#loadfile(fpath) ⇒ Object

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.



325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
# File 'lib/include/class_knjappserver.rb', line 325

def loadfile(fpath)
  if !@config[:autorestart]
    require fpath
    return nil
  end
  
  rpath = File.realpath(fpath)
  raise "No such filepath: #{fpath}" if !rpath or !File.exists?(rpath)
  
  return true if @mod_files[rpath]
  
  @mod_event.args[:paths] << rpath
  @mod_files = rpath
  
  require rpath
  return false
end

#log(msg, objs, args = {}) ⇒ Object

Writes a custom log to the database.



215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# File 'lib/include/class_knjappserver_logging.rb', line 215

def log(msg, objs, args = {})
   #This can come in handy if migrating logs to appserver-database.
   if args[:date_saved]
     date_saved = args[:date_saved]
   else
     date_saved = Time.now
   end
   
   objs = [objs] if !objs.is_a?(Array)
   
	@logs_mutex.synchronize do
		log_value_id = @ob.static(:Log_data_value, :force_id, msg)
		
		ins_data = {
			:date_saved => date_saved,
			:text_value_id => log_value_id
		}
		
		get_hash = log_hash_ins(_get) if _get
		if get_hash
			ins_data[:get_keys_data_id] = get_hash[:keys_data_id]
			ins_data[:get_values_data_id] = get_hash[:values_data_id]
		end
		
		post_hash = log_hash_ins(_post) if _post
		if post_hash
			ins_data[:post_keys_data_id] = post_hash[:keys_data_id]
			ins_data[:post_values_data_id] = post_hash[:values_data_id]
		end
		
		cookie_hash = log_hash_ins(_cookie) if _cookie
		if cookie_hash
       ins_data[:post_keys_data_id] = cookie_hash[:keys_data_id]
       ins_data[:post_values_data_id] = cookie_hash[:values_data_id]
		end
		
		meta_hash = log_hash_ins(_meta) if _meta
     if cookie_hash
       ins_data[:meta_keys_data_id] = meta_hash[:keys_data_id]
       ins_data[:meta_values_data_id] = meta_hash[:values_data_id]
     end
     
     session_hash = log_hash_ins(_session) if _session
     if session_hash
       ins_data[:session_keys_data_id] = session_hash[:keys_data_id]
       ins_data[:session_values_data_id] = session_hash[:values_data_id]
     end
     
     if args[:tag]
       tag_value_id = @ob.static(:Log_data_value, :force_id, args[:tag])
       ins_data[:tag_data_id] = tag_value_id
     end
     
     if args[:comment]
       comment_value_id = @ob.static(:Log_data_value, :force_id, args[:comment])
       ins_data[:comment_data_id] = comment_value_id
     end
		
		log_id = @db.insert(:Log, ins_data, {:return_id => true})
		
		log_links = []
		objs.each do |obj|
       class_data_id = @ob.static(:Log_data_value, :force_id, obj.class.name)
       
       log_links << {
         :object_class_value_id => class_data_id,
         :object_id => obj.id,
         :log_id => log_id
       }
		end
		
		@db.insert_multi(:Log_link, log_links)
	end
end

#log_data_hash(keys_id, values_id) ⇒ Object



176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
# File 'lib/include/class_knjappserver_logging.rb', line 176

def log_data_hash(keys_id, values_id)
   begin
     keys_data_obj = @ob.get(:Log_data, keys_id)
     values_data_obj = @ob.get(:Log_data, values_id)
   rescue Errno::ENOENT
     return {}
   end
	
	sql = "
		SELECT
			key_value.value AS `key`,
			value_value.value AS value
		
		FROM
			Log_data_link AS key_links,
			Log_data_link AS value_links,
			Log_data_value AS key_value,
			Log_data_value AS value_value
		
		WHERE
			key_links.data_id = '#{keys_id}' AND
			value_links.data_id = '#{values_id}' AND
			key_links.no = value_links.no AND
			key_value.id = key_links.value_id AND
			value_value.id = value_links.value_id
		
		ORDER BY
			key_links.no
	"
	
	hash = {}
	db.q(sql) do |d_hash|
		hash[d_hash[:key].to_sym] = d_hash[:value]
	end
	
	return hash
end

#log_hash_ins(hash_obj) ⇒ Object

Handles the hashes that should be logged.



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
# File 'lib/include/class_knjappserver_logging.rb', line 130

def log_hash_ins(hash_obj)
   #Sort out fileuploads - it would simply bee too big to log this.
   hash_obj = self.log_hash_safe(hash_obj)
   
	inserts_links = []
	ret = {}
	[:keys, :values].each do |type|
		if type == :keys
			hash = Knj::ArrayExt.hash_keys_hash(hash_obj)
		else
			hash = Knj::ArrayExt.hash_values_hash(hash_obj)
		end
		
		data_id = @db.single(:Log_data, {"id_hash" => hash})
		data_id = data_id[:id] if data_id
		
		if !data_id
			data_id = @db.insert(:Log_data, {"id_hash" => hash}, {:return_id => true})
			
			link_count = 0
			hash_obj.keys.sort.each do |key|
				if type == :keys
					ins_data = "#{key.to_s}"
				else
					ins_data = "#{hash_obj[key].to_s}"
				end
				
				ins_data = ins_data.force_encoding("UTF-8") if ins_data.respond_to?(:force_encoding)
				data_value_id = @ob.static(:Log_data_value, :force_id, ins_data)
				inserts_links << {:no => link_count, :data_id => data_id, :value_id => data_value_id}
				link_count += 1
			end
		end
		
		if type == :keys
			ret[:keys_data_id] = data_id
		else
			ret[:values_data_id] = data_id
		end
	end
	
	@db.insert_multi(:Log_data_link, inserts_links)
	
	return ret
end

#log_hash_safe(hash) ⇒ Object

Converts fileuploads into strings so logging wont be crazy big.



114
115
116
117
118
119
120
121
122
123
124
125
126
127
# File 'lib/include/class_knjappserver_logging.rb', line 114

def log_hash_safe(hash)
   hash_obj = {}
   hash.each do |key, val|
     if val.is_a?(Knjappserver::Httpsession::Post_multipart::File_upload)
       hash_obj[key] = "<Fileupload>"
     elsif val.is_a?(Hash)
       hash_obj[key] = self.log_hash_safe(val)
     else
       hash_obj[key] = val
     end
   end
   
   return hash_obj
end

#logs_delete(obj) ⇒ Object

Deletes all logs for an object.



291
292
293
294
295
296
297
298
299
300
301
# File 'lib/include/class_knjappserver_logging.rb', line 291

def logs_delete(obj)
   @db.q_buffer do |db_buffer|
     buffer_hash = {:db_buffer => db_buffer}
     
     @ob.list(:Log_link, {"object_class" => obj.class.name, "object_id" => obj.id}) do |log_link|
       log = log_link.log
       @ob.delete(log_link, buffer_hash)
       @ob.delete(log, buffer_hash) if log and log.links("count" => true) <= 0
     end
   end
end

#logs_delete_dead(args) ⇒ Object

Removes all logs for objects that have been deleted.

Examples

Remember to pass Knj::Objects-object handler to the method. appsrv.logs_delete_dead(:ob => ob, :debug => false)



365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
# File 'lib/include/class_knjappserver_logging.rb', line 365

def logs_delete_dead(args)
   raise "No :ob-argument given." if !args[:ob]
   
   @db.q_buffer do |db_buffer|
     STDOUT.puts "Starting to look for dead log-links." if @debug or args[:debug]
     @ob.list(:Log_link, :cloned_ubuf => true) do |log_link|
       classname = log_link.object_class.to_s.split("::").last
       obj_exists = args[:ob].exists?(classname, log_link[:object_id])
       next if obj_exists
       
       log = log_link.log
       
       STDOUT.puts "Deleting log-link #{log_link.id} for #{classname}(#{log_link[:object_id]})." if @debug or args[:debug]
       @ob.delete(log_link, :db_buffer => db_buffer)
       
       links_count = log.links("count" => true)
       
       if links_count <= 0
         STDOUT.puts "Deleting log #{log.id} because it has no more links." if @debug or args[:debug]
         @ob.delete(log, :db_buffer => db_buffer)
       end
     end
     
     STDOUT.puts "Starting to look for logs with no links." if @debug or args[:debug]
     @ob.list(:Log, {
       [:Log_link, "id"] => {:type => :sqlval, :val => :null},
       :cloned_ubuf => true
     }) do |log|
       STDOUT.puts "Deleting log #{log.id} because it has no links: '#{log.text}'." if @debug or args[:debug]
       @ob.delete(log, :db_buffer => db_buffer)
     end
   end
end

#logs_table(obj, args = {}) ⇒ Object

Returns the HTML for a table with logs from a given object.



304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
# File 'lib/include/class_knjappserver_logging.rb', line 304

def logs_table(obj, args = {})
	links = @ob.list(:Log_link, {"object_class" => obj.class.name, "object_id" => obj.id, "limit" => 500, "orderby" => [["id", "desc"]]})
	
	html = ""
	
	html << "<table class=\"list knjappserver_log_table\">"
	html << "<thead>"
	html << "<tr>"
	html << "<th>ID</th>"
	html << "<th>Message</th>"
	html << "<th style=\"width: 130px;\">Date &amp; time</th>"
	html << "<th>Tag</th>"
	html << "<th>Objects</th>" if args[:ob_use]
	html << "<th>IP</th>" if args[:show_ip]
	html << "</tr>"
	html << "</thead>"
	html << "<tbody>"
	
	links.each do |link|
     log = link.log
     
		msg_lines = log.text.split("\n")
		first_line = msg_lines[0].to_s
		
		classes = ["knjappserver_log", "knjappserver_log_#{log.id}"]
		classes << "knjappserver_log_multiple_lines" if msg_lines.length > 1
		
		html << "<tr class=\"#{classes.join(" ")}\">"
		html << "<td>#{log.id}</td>"
		html << "<td>#{first_line.html}</td>"
		html << "<td>#{log.date_saved_str}</td>"
		html << "<td>#{log.tag.html}</td>"
		
		if args[:ob_use]
       begin
         html << "<td>#{log.objects_html(args[:ob_use])}</td>"
       rescue => e
         html << "<td>#{e.message.html}</td>"
       end
     end
     
		html << "<td>#{log.ip}</td>" if args[:show_ip]
		html << "</tr>"
	end
	
	if links.empty?
		html << "<tr>"
		html << "<td colspan=\"2\" class=\"error\">No logs were found for that object.</td>"
		html << "</tr>"
	end
	
	html << "</tbody>"
	html << "</table>"
	
	return html
end

#mail(mail_args) ⇒ Object

Queue a mail for sending. Possible keys are: :subject, :from, :to, :text and :html.



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
# File 'lib/include/class_knjappserver_mailing.rb', line 15

def mail(mail_args)
   raise "'smtp_args' has not been given for the Knjappserver." if !@config[:smtp_args]
   
	@mails_queue_mutex.synchronize do
		count_wait = 0
		while @mails_waiting.length > 100
			if count_wait >= 30
				raise "Could not send email - too many emails was pending and none of them were being sent?"
			end
			
			count_wait += 1
			sleep 1
		end
		
		mailobj = Knjappserver::Mail.new({:kas => self, :errors => {}, :status => :waiting}.merge(mail_args))
		STDOUT.print "Added mail '#{mailobj.__id__}' to the mail-send-queue.\n" if debug
		@mails_waiting << mailobj
		self.mail_flush if mail_args[:now]
		return mailobj
	end
end

#mail_flushObject

Sends all queued mails to the respective servers, if we are online.



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/include/class_knjappserver_mailing.rb', line 38

def mail_flush
	@mails_mutex.synchronize do
     STDOUT.print "Flushing mails.\n" if @debug
     
     if @mails_waiting.length <= 0
       STDOUT.print "No mails to flush - skipping.\n" if @debug
       return false
     end
     
     STDOUT.print "Trying to ping Google to figure out if we are online...\n" if @debug
     status = Ping.pingecho("google.dk", 10, 80)
     if !status
       STDOUT.print "We are not online - skipping mail flush.\n"
       return false  #Dont run if we dont have a connection to the internet and then properly dont have a connection to the SMTP as well.
     end
     
     begin
       #Use subprocessing to avoid the mail-framework (activesupport and so on, also possible memory leaks in those large frameworks).
       STDOUT.print "Starting subprocess for mailing.\n" if @debug
       require "knj/process_meta"
       subproc = Knj::Process_meta.new("debug" => @debug, "debug_err" => true, "id" => "knjappserver_mailing")
       subproc.static("Object", "require", "rubygems")
       subproc.static("Object", "require", "mail")
       subproc.static("Object", "require", "#{@config[:knjrbfw_path]}knjrbfw")
       subproc.static("Object", "require", "knj/autoload")
       
       STDOUT.print "Flushing emails." if @debug
       @mails_waiting.each do |mail|
         begin
           STDOUT.print "Sending email: #{mail.__id__}\n" if @debug
           if mail.send("proc" => subproc)
             STDOUT.print "Email sent: #{mail.__id__}\n" if @debug
             @mails_waiting.delete(mail)
           end
         rescue Timeout::Error
           #ignore - 
         rescue => e
           @mails_waiting.delete(mail)
           self.handle_error(e, {:email => false})
         end
         
         sleep 1 #sleep so we dont take up too much bandwidth.
       end
     ensure
       subproc.destroy if subproc
       subproc = nil
     end
     
     return nil
	end
end

#no_date(event, classname) ⇒ Object



314
315
316
# File 'lib/include/class_knjappserver.rb', line 314

def no_date(event, classname)
  return "[no date]"
end

#num(*args) ⇒ Object

Returns a number localized as a string.



148
149
150
# File 'lib/include/class_knjappserver_web.rb', line 148

def num(*args)
  return Knj::Locales.number_out(*args)
end

#on_error_go_back(&block) ⇒ Object

Takes a proc and executes it. On error it alerts the error-message with javascript to the server, sends a javascript back and exits.



115
116
117
118
119
120
121
# File 'lib/include/class_knjappserver_errors.rb', line 115

def on_error_go_back(&block)
  begin
    block.call
  rescue => e
    self.alert(e.message).back
  end
end

#on_event_filemod(event, path) ⇒ Object



318
319
320
321
322
# File 'lib/include/class_knjappserver.rb', line 318

def on_event_filemod(event, path)
  print "File changed - restart server: #{path}\n"
  @should_restart = true
  @mod_event.destroy if @mod_event
end

#pauseObject

Stop running any more HTTP-requests - make them wait.



408
409
410
# File 'lib/include/class_knjappserver.rb', line 408

def pause
  @paused += 1
end

#paused?Boolean

Returns true if paued - otherwise false.

Returns:

  • (Boolean)


418
419
420
421
# File 'lib/include/class_knjappserver.rb', line 418

def paused?
  return true if @paused > 0
  return false
end

#paused_execObject

Will stop handeling any more HTTP-requests, run the proc given and return handeling HTTP-requests.



424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
# File 'lib/include/class_knjappserver.rb', line 424

def paused_exec
  raise "No block given." if !block_given?
  self.pause
  
  begin
    sleep 0.2 while @httpserv and @httpserv.working_count and @httpserv.working_count > 0
    @paused_mutex.synchronize do
      Timeout.timeout(15) do
        yield
      end
    end
  ensure
    self.unpause
  end
end

#portObject

Returns the socket-port the appserver is currently running on.



186
187
188
189
# File 'lib/include/class_knjappserver_web.rb', line 186

def port
  raise "Http-server not spawned yet. Call Knjappserver#start to spawn it." if !@httpserv
  return @httpserv.server.addr[1]
end

#redirect(url, args = {}) ⇒ Object

Redirects to another URL.

Examples

_kas.redirect("someotherpage.rhtml")
_kas.redirect("newpage.rhtml", :perm => true)


17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# File 'lib/include/class_knjappserver_web.rb', line 17

def redirect(url, args = {})
  #Header way
  if !_httpsession.alert_sent and !self.headers_sent?
    if args[:perm]
      _httpsession.resp.status = 301 if !self.headers_sent?
    else
      _httpsession.resp.status = 303 if !self.headers_sent?
    end
    
    self.header("Location", url) if !self.headers_sent?
  end
  
  print "<script type=\"text/javascript\">location.href=\"#{url}\";</script>"
  exit
end

#serve_file(filepath) ⇒ Object

Serves the given filepath and enables caching for it. No other content should be written to the page when using this method.

Examples

_kas.header("Content-Type", "text/javascript")
_kas.serve_file("somefile.js")


93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/include/class_knjappserver_web.rb', line 93

def serve_file(filepath)
  raise "File doesnt exist: '#{filepath}'." if !File.exists?(filepath)
  httpsess = _httpsession
  headers = httpsess.headers
  resp = httpsess.resp
  
  if headers["cache-control"] and headers["cache-control"][0]
    cache_control = {}
    headers["cache-control"][0].scan(/(.+)=(.+)/) do |match|
      cache_control[match[1]] = match[2]
    end
  end
  
  cache_dont = true if cache_control and cache_control.key?("max-age") and cache_control["max-age"].to_i <= 0
  lastmod = File.mtime(filepath)
  
  self.header("Last-Modified", lastmod.httpdate)
  self.header("Expires", (Time.now + 86400).httpdate) #next day.
  
  if !cache_dont and headers["if-modified-since"] and headers["if-modified-since"][0]
    request_mod = Datet.in(headers["if-modified-since"].first).time
    
    if request_mod == lastmod
      resp.status = 304
      return nil
    end
  end
  
  httpsess.force_content(:type => :file, :path => filepath)
  return nil
end

#session_fromid(ip, idhash, meta) ⇒ Object

Returns or adds session based on idhash and meta-data.



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
# File 'lib/include/class_knjappserver_sessions.rb', line 7

def session_fromid(ip, idhash, meta)
  ip = "bot" if idhash == "bot"
  
  if !@sessions.key?(idhash)
    session = @ob.get_by(:Session, {"idhash" => idhash})
    if !session
      session = @ob.add(:Session, {
        :idhash => idhash,
        :user_agent => meta["HTTP_USER_AGENT"],
        :ip => ip
      })
    end
    
    hash = {}
    @sessions[idhash] = {
      :dbobj => session,
      :hash => hash
    }
  else
    session = @sessions[idhash][:dbobj]
    hash = @sessions[idhash][:hash]
  end
  
  if ip != "bot" and !session.remember? and ip.to_s != session[:ip].to_s
    raise ArgumentError, "Invalid IP."
  end
  
  @sessions[idhash][:time_lastused] = Time.now
  return [session, hash]
end

#session_generate_id(meta) ⇒ Object

Generates a new session-ID by the meta data.



39
40
41
# File 'lib/include/class_knjappserver_sessions.rb', line 39

def session_generate_id(meta)
  return Digest::MD5.hexdigest("#{Time.now.to_f}_#{meta["HTTP_HOST"]}_#{meta["REMOTE_HOST"]}_#{meta["HTTP_X_FORWARDED_SERVER"]}_#{meta["HTTP_X_FORWARDED_FOR"]}_#{meta["HTTP_X_FORWARDED_HOST"]}_#{meta["REMOTE_ADDR"]}_#{meta["HTTP_USER_AGENT"]}")
end

#session_rememberObject

Will make the session rememberable for a year. IP wont be checked any more.



44
45
46
47
48
49
50
51
52
53
54
# File 'lib/include/class_knjappserver_sessions.rb', line 44

def session_remember
  session = _httpsession.session
  session[:remember] = 1
  
  self.cookie(
    "name" => "KnjappserverSession",
    "value" => _httpsession.session_id,
    "path" => "/",
    "expires" => Time.now + 32140800 #add around 12 months
  )
end

#sessions_flushObject

Writes all session-data to the database (normally it is cached in memory and not updated on change).



57
58
59
60
61
62
63
64
# File 'lib/include/class_knjappserver_sessions.rb', line 57

def sessions_flush
  if @sessions
    @sessions.each do |session_hash, session_data|
      STDOUT.print "Flushing session: #{session_data[:dbobj].id}\n" if @debug
      session_data[:dbobj].flush
    end
  end
end

#sessions_resetObject

Writes all session-data and resets the hash.



67
68
69
70
# File 'lib/include/class_knjappserver_sessions.rb', line 67

def sessions_reset
  self.sessions_flush
  @sessions = {}
end

#startObject

Starts the HTTP-server and threadpool.



344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
# File 'lib/include/class_knjappserver.rb', line 344

def start
  #Start the appserver.
  print "Spawning appserver.\n" if @debug
  @httpserv = Knjappserver::Httpserver.new(self)
  
  
  #Start Leakproxy-module if defined in config.
  if @config[:leakproxy]
    require "#{File.dirname(__FILE__)}/class_knjappserver_leakproxy_server.rb"
    @leakproxy_server = Knjappserver::Leakproxy_server.new(:kas => self)
  end
  
  
  STDOUT.print "Starting appserver.\n" if @debug
  Thread.current[:knjappserver] = {:kas => self} if !Thread.current[:knjappserver]
  
  if @config[:autoload]
    STDOUT.print "Autoloading #{@config[:autoload]}\n" if @debug
    require @config[:autoload]
  end
  
  begin
    @threadpool.start if @threadpool
    STDOUT.print "Threadpool startet.\n" if @debug
    @httpserv.start
    STDOUT.print "Appserver startet.\n" if @debug
  rescue Interrupt => e
    STDOUT.print "Got interrupt - trying to stop appserver.\n" if @debug
    self.stop
    raise e
  end
end

#stopObject

Stops the entire app and releases join.



378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
# File 'lib/include/class_knjappserver.rb', line 378

def stop
  return nil if @stop_called
  @stop_called = true
  
  proc_stop = proc{
    STDOUT.print "Stopping appserver.\n" if @debug
    @httpserv.stop if @httpserv and @httpserv.respond_to?(:stop)
    
    STDOUT.print "Stopping threadpool.\n" if @debug
    @threadpool.stop if @threadpool
    
    #This should be done first to be sure it finishes (else we have a serious bug).
    STDOUT.print "Flush out loaded sessions.\n" if @debug
    self.sessions_flush
    
    STDOUT.print "Stopping done...\n" if @debug
  }
  
  #If we cant get a paused-execution in 5 secs - we just force the stop.
  begin
    Timeout.timeout(5) do
      self.paused_exec(&proc_stop)
    end
  rescue Timeout::Error, SystemExit, Interrupt
    STDOUT.print "Forcing stop-appserver - couldnt get timing window.\n" if @debug
    proc_stop.call
  end
end

#thread(args = {}) ⇒ Object

Spawns a new thread with access to magic methods, _db-method and various other stuff in the appserver.



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/include/class_knjappserver_threadding.rb', line 23

def thread(args = {})
  raise "No block given." if !block_given?
  args[:args] = [] if !args[:args]
  
  thread_obj = Knjappserver::Thread_instance.new(
    :running => false,
    :error => false,
    :done => false
  )
  
  @threadpool.run_async do
    @ob.db.get_and_register_thread if @ob.db.opts[:threadsafe]
    @db_handler.get_and_register_thread if @db_handler.opts[:threadsafe]
    
    Thread.current[:knjappserver] = {
      :kas => self,
      :db => @db_handler
    }
    
    begin
      thread_obj.args[:running] = true
      yield(*args[:args])
    rescue => e
      self.handle_error(e)
      thread_obj.args[:error] = true
      thread_obj.args[:error_obj] = e
    ensure
      STDOUT.print "Free thread ob-db.\n" if @debug
      @ob.db.free_thread if @ob.db.opts[:threadsafe]
      
      STDOUT.print "Free thread db-handler.\n" if @debug
      @db_handler.free_thread if @db_handler.opts[:threadsafe]
      
      STDOUT.print "Set args on thread.\n" if @debug
      thread_obj.args[:running] = false
      thread_obj.args[:done] = true
    end
  end
  
  return thread_obj
end

#thread_init(thread = nil) ⇒ Object

Inits the thread so it has access to the appserver and various magic methods can be used.



16
17
18
19
20
# File 'lib/include/class_knjappserver_threadding.rb', line 16

def thread_init(thread = nil)
  thread = Thread.current if thread == nil
  thread[:knjappserver] = {} if !thread[:knjappserver]
  thread[:knjappserver][:kas] = self
end

#threadded_content(&block) ⇒ Object

Spawns a thread to run the given proc and add the output of that block in the correct order to the HTML.



75
76
77
78
# File 'lib/include/class_knjappserver_threadding.rb', line 75

def threadded_content(&block)
  _httpsession.threadded_content(block)
  return nil
end

#threadpool_on_error(event, error) ⇒ Object

Callback for when an error occurs in the threadpool.



11
12
13
# File 'lib/include/class_knjappserver_threadding.rb', line 11

def threadpool_on_error(event, error)
  self.handle_error(error)
end

#timeout(args = {}, &block) ⇒ Object

Runs a proc every number of seconds.



66
67
68
69
70
71
72
# File 'lib/include/class_knjappserver_threadding.rb', line 66

def timeout(args = {}, &block)
  return Knjappserver::Threadding_timeout.new({
    :kas => self,
    :block => block,
    :args => []
  }.merge(args)).start
end

#trans(obj, key, args = {}) ⇒ Object

Translates a given key for a given object.

Examples

print _kas.trans(obj, :title) #=> “Trala”



5
6
7
8
9
10
# File 'lib/include/class_knjappserver_translations.rb', line 5

def trans(obj, key, args = {})
  args[:locale] = self.trans_locale if !args[:locale]
  trans_val = @translations.get(obj, key, args).to_s
  trans_val = @events.call(:trans_no_str, {:obj => obj, :key => key, :args => args}) if trans_val.length <= 0
  return trans_val
end

#trans_del(obj) ⇒ Object

Deletes all translations for the given object.

Examples

_kas.trans_del(obj)



40
41
42
# File 'lib/include/class_knjappserver_translations.rb', line 40

def trans_del(obj)
  @translations.delete(obj)
end

#trans_locale(args = {}) ⇒ Object

Returns the locale for the current thread.



13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# File 'lib/include/class_knjappserver_translations.rb', line 13

def trans_locale(args = {})
  if args.is_a?(Hash) and args[:locale]
    return args[:locale]
  elsif _session and _session[:locale]
    return _session[:locale]
  elsif _httpsession and _httpsession.data[:locale]
    return _httpsession.data[:locale]
  elsif Thread.current[:locale]
    return Thread.current[:locale]
  elsif @config[:locale_default]
    return @config[:locale_default]
  end
  
  raise "Could not figure out locale."
end

#trans_set(obj, values, args = {}) ⇒ Object

Sets new translations for the given object.

Examples

_kas.trans_set(obj, => “Trala”)



32
33
34
35
# File 'lib/include/class_knjappserver_translations.rb', line 32

def trans_set(obj, values, args = {})
  args[:locale] = self.trans_locale if !args[:locale]
  @translations.set(obj, values, args)
end

#unpauseObject

Unpause - start handeling HTTP-requests again.



413
414
415
# File 'lib/include/class_knjappserver.rb', line 413

def unpause
  @paused -= 1
end

#urldec(str) ⇒ Object

Urldecodes a string.



143
144
145
# File 'lib/include/class_knjappserver_web.rb', line 143

def urldec(str)
  return Knj::Web.urldec(str)
end

#urlenc(str) ⇒ Object

Urlencodes a string.

Examples

_kas.redirect("mypage.rhtml?arg=#{_kas.urlenc(value_variable)}")


138
139
140
# File 'lib/include/class_knjappserver_web.rb', line 138

def urlenc(str)
  return Knj::Web.urlenc(str)
end

#working?Boolean

Returns true if a HTTP-request is working. Otherwise false.

Returns:

  • (Boolean)


441
442
443
444
# File 'lib/include/class_knjappserver.rb', line 441

def working?
  return true if @httpserv and @httpserv.working_count > 0
  return false
end