Class: Knjappserver

Inherits:
Object
  • Object
show all
Defined in:
lib/include/class_knjappserver.rb,
lib/files/database_schema.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.


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
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
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
# File 'lib/include/class_knjappserver.rb', line 20

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)
  
  
  #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.
  if @config[:handlers_extra]
    @config[:handlers] += @config[:handlers_extra]
  end
  
  
  #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) do |event, path|
      print "File changed - restart server: #{path}\n"
      @should_restart = true
      @mod_event.destroy if @mod_event
    end
  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_httpserver.rb",
    "#{@path_knjappserver}/class_httpsession.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"
  ]
  
  if @config[:preload]
    require "timeout"
    require "digest"
    require "erubis"
    require "base64"
    require "stringio"
    require "socket"
    require "tsafe" if !Kernel.const_defined?(:Tsafe)
    
    files += [
      "#{@path_knjrbfw}knj/event_handler.rb",
      "#{@path_knjrbfw}knj/errors.rb",
      "#{@path_knjrbfw}knj/eruby.rb",
      "#{@path_knjrbfw}knj/hash_methods.rb",
      "#{@path_knjrbfw}knj/objects.rb",
      "#{@path_knjrbfw}knj/web.rb",
      "#{@path_knjrbfw}knj/datarow.rb",
      "#{@path_knjrbfw}knj/datet.rb",
      "#{@path_knjrbfw}knj/php.rb",
      "#{@path_knjrbfw}knj/thread.rb",
      "#{@path_knjrbfw}knj/threadhandler.rb",
      "#{@path_knjrbfw}knj/threadpool.rb",
      "#{@path_knjrbfw}knj/translations.rb",
      "#{@path_knjrbfw}knj/knjdb/libknjdb.rb",
    ]
  else
    files << "#{@path_knjrbfw}knj/autoload.rb"
  end
  
  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
    require "knj/knjdb/revision.rb"
    
    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 = Knj::Db::Revision.new
    dbrev.init_db("schema" => Knjappserver::DATABASE_SCHEMA, "db" => @db)
  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) do |event, classname|
    "[no date]"
  end
  
  
  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 do
    self.stop
  end
  
  
  print "Appserver spawned.\n" if @debug
end

Instance Attribute Details

#cioObject (readonly)

Returns the value of attribute cio


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

def cio
  @cio
end

#configObject (readonly)

Returns the value of attribute config


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

def config
  @config
end

#dbObject (readonly)

Returns the value of attribute db


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

def db
  @db
end

#db_handlerObject (readonly)

Returns the value of attribute db_handler


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

def db_handler
  @db_handler
end

#debugObject (readonly)

Returns the value of attribute debug


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

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


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

def eruby_cache
  @eruby_cache
end

#eventsObject (readonly)

Returns the value of attribute events


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

def events
  @events
end

#gettextObject (readonly)

Returns the value of attribute gettext


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

def gettext
  @gettext
end

#httpservObject (readonly)

Returns the value of attribute httpserv


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

def httpserv
  @httpserv
end

#httpsessions_idsObject (readonly)

Returns the value of attribute httpsessions_ids


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

def httpsessions_ids
  @httpsessions_ids
end

#logs_access_pendingObject (readonly)

Returns the value of attribute logs_access_pending


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

def logs_access_pending
  @logs_access_pending
end

#magic_procsObject (readonly)

Returns the value of attribute magic_procs


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

def magic_procs
  @magic_procs
end

#magic_varsObject (readonly)

Returns the value of attribute magic_vars


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

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


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

def mod_event
  @mod_event
end

#obObject (readonly)

Returns the value of attribute ob


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

def ob
  @ob
end

#pausedObject (readonly)

Returns the value of attribute paused


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

def paused
  @paused
end

#servedObject

Returns the value of attribute served


12
13
14
# File 'lib/include/class_knjappserver.rb', line 12

def served
  @served
end

#sessionsObject (readonly)

Returns the value of attribute sessions


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

def sessions
  @sessions
end

#should_restartObject

Returns the value of attribute should_restart


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

def should_restart
  @should_restart
end

#should_restart_doneObject

Returns the value of attribute should_restart_done


12
13
14
# File 'lib/include/class_knjappserver.rb', line 12

def should_restart_done
  @should_restart_done
end

#threadpoolObject (readonly)

Returns the value of attribute threadpool


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

def threadpool
  @threadpool
end

#translationsObject (readonly)

Returns the value of attribute translations


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

def translations
  @translations
end

#typesObject (readonly)

Returns the value of attribute types


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

def types
  @types
end

#varsObject (readonly)

Returns the value of attribute vars


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

def vars
  @vars
end

Class Method Details

.const_missing(name) ⇒ Object

Autoloader for subclasses.


15
16
17
18
# File 'lib/include/class_knjappserver.rb', line 15

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

.dataObject


460
461
462
463
# File 'lib/include/class_knjappserver.rb', line 460

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

Instance Method Details

#alert(msg) ⇒ Object

Sends a javascript-alert to the HTML.


29
30
31
32
33
# File 'lib/include/class_knjappserver_web.rb', line 29

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

#backObject

Sends a javascript back to the browser and exits.


71
72
73
# File 'lib/include/class_knjappserver_web.rb', line 71

def back
  Knj::Web.back
end

#cleanObject

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


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
# File 'lib/include/class_knjappserver_cleaner.rb', line 98

def clean
   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).


45
46
47
48
# File 'lib/include/class_knjappserver_cmdline.rb', line 45

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

Define a cookies in the clients browser.


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

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)
end

#debugs(str) ⇒ Object

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


131
132
133
134
135
136
# File 'lib/include/class_knjappserver_errors.rb', line 131

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


500
501
502
503
504
505
506
507
508
509
510
# File 'lib/include/class_knjappserver.rb', line 500

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.


489
490
491
492
493
494
495
496
497
498
# File 'lib/include/class_knjappserver.rb', line 489

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.


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

def dprint(obj)
  STDOUT.print Knj::Php.print_r(obj, true)
end

#flush_access_logObject

Writes all queued access-logs to the database.


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
112
113
# File 'lib/include/class_knjappserver_logging.rb', line 16

def flush_access_log
	@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).


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
# File 'lib/include/class_knjappserver_errors.rb', line 22

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.


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
# File 'lib/include/class_knjappserver_web.rb', line 96

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.


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
# File 'lib/include/class_knjappserver_errors.rb', line 70

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>#{Knj::Php.print_r(_post, true)}</pre>" if _post
      html << "<br /><b>Get:</b><br /><pre>#{Knj::Php.print_r(_get, true)}</pre>" if _get
      html << "<br /><b>Server:</b><br /><pre>#{Knj::Php.print_r(_server, true).html}</pre>" if _server
      html << "<br /><b>Cookie:</b><br /><pre>#{Knj::Php.print_r(_cookie, true).html}</pre>" if _meta
      html << "<br /><b>Session:</b><br /><pre>#{Knj::Php.print_r(_session, true).html}</pre>" if _session
      html << "<br /><b>Session hash:</b><br /><pre>#{Knj::Php.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.


44
45
46
47
48
# File 'lib/include/class_knjappserver_web.rb', line 44

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)
end

#header_raw(str) ⇒ Object

Sends a raw header-line to the clients browser.


51
52
53
54
55
# File 'lib/include/class_knjappserver_web.rb', line 51

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

#headers_send_size=(newsize) ⇒ Object


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

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

#headers_sent?Boolean

Returns:

  • (Boolean)

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

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

#import(filepath) ⇒ Object

Imports a .rhtml-file and executes it.


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

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
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
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
# File 'lib/include/class_knjappserver_cleaner.rb', line 2

def initialize_cleaner
   if @config[:autorestart]
     time = 1
   else
     time = 15
   end
   
   #This should not be runned via _kas.timeout because timeout wont run when @should_restart is true! - knj
   Thread.new do
     begin
       loop do
         sleep time
         
         if @config.has_key?(:restart_when_used_memory) and !@should_restart
           mbs_used = (Knj::Php.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
   
   #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"))
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
36
37
38
39
40
41
42
# 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) do |data|
    print "Restart will begin shortly.\n"
    self.should_restart = true
  end
  
  self.cmd_connect(/^\s*stop\s*$/i) do |data|
    print "Stopping appserver.\n"
    self.stop
  end
end

#initialize_errorsObject


4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 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) do
    self.flush_error_emails
  end
end

#initialize_loggingObject


2
3
4
5
6
7
8
9
10
11
12
13
# 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) do
			if @logs_access_pending.length > 0
				flush_access_log
			end
		end
	end
end

#initialize_mailingObject


4
5
6
7
8
9
10
11
12
13
14
15
# 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) do
     STDOUT.print "Flushing mails.\n" if @debug
		self.mail_flush
	end
end

#initialize_sessionsObject


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

def initialize_sessions
  require "tsafe" if !Kernel.const_defined?(:Tsafe)
  @sessions = Tsafe::MonHash.new
end

#initialize_threaddingObject


2
3
4
5
6
7
8
9
10
# 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) do |event, error|
    self.handle_error(error)
  end
end

#inputs(*args) ⇒ Object

Draw a input in a table.


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

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

#joinObject

Sleeps until the server is stopped.


466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
# File 'lib/include/class_knjappserver.rb', line 466

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.


339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
# File 'lib/include/class_knjappserver.rb', line 339

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.


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
# File 'lib/include/class_knjappserver_logging.rb', line 217

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


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
# File 'lib/include/class_knjappserver_logging.rb', line 178

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.


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
# File 'lib/include/class_knjappserver_logging.rb', line 132

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.


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

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.


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

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.


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 306

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 = "<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.


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

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.


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
# File 'lib/include/class_knjappserver_mailing.rb', line 41

def mail_flush
	@mails_mutex.synchronize do
     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
	end
end

#num(*args) ⇒ Object

Returns a number localized as a string.


91
92
93
# File 'lib/include/class_knjappserver_web.rb', line 91

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.


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

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

#pauseObject

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


422
423
424
# File 'lib/include/class_knjappserver.rb', line 422

def pause
  @paused += 1
end

#paused?Boolean

Returns true if paued - otherwise false.

Returns:

  • (Boolean)

432
433
434
435
# File 'lib/include/class_knjappserver.rb', line 432

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.


438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
# File 'lib/include/class_knjappserver.rb', line 438

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.


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

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.


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

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

#session_fromid(ip, idhash, meta) ⇒ Object

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


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
37
# File 'lib/include/class_knjappserver_sessions.rb', line 8

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.


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

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.


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

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).


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

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.


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

def sessions_reset
  self.sessions_flush
  @sessions = {}
end

#startObject

Starts the HTTP-server and threadpool.


358
359
360
361
362
363
364
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
# File 'lib/include/class_knjappserver.rb', line 358

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.


392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
# File 'lib/include/class_knjappserver.rb', line 392

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.


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
# File 'lib/include/class_knjappserver_threadding.rb', line 20

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.


13
14
15
16
17
# File 'lib/include/class_knjappserver_threadding.rb', line 13

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.


72
73
74
# File 'lib/include/class_knjappserver_threadding.rb', line 72

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

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

Runs a proc every number of seconds.


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

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

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


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

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

#trans_del(obj) ⇒ Object


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

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

#trans_locale(args = {}) ⇒ Object


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


29
30
31
32
# File 'lib/include/class_knjappserver_translations.rb', line 29

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.


427
428
429
# File 'lib/include/class_knjappserver.rb', line 427

def unpause
  @paused -= 1
end

#urldec(str) ⇒ Object

Urldecodes a string.


86
87
88
# File 'lib/include/class_knjappserver_web.rb', line 86

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

#urlenc(str) ⇒ Object

Urlencodes a string.


81
82
83
# File 'lib/include/class_knjappserver_web.rb', line 81

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

#working?Boolean

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

Returns:

  • (Boolean)

455
456
457
458
# File 'lib/include/class_knjappserver.rb', line 455

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