knjrbfw 0.0.21 → 0.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/VERSION +1 -1
- data/knjrbfw.gemspec +2 -2
- data/lib/knj/arrayext.rb +17 -3
- data/lib/knj/cmd_parser.rb +26 -4
- data/lib/knj/csv.rb +3 -0
- data/lib/knj/datarow.rb +19 -4
- data/lib/knj/datet.rb +1 -1
- data/lib/knj/gettext_threadded.rb +2 -2
- data/lib/knj/google_sitemap.rb +57 -18
- data/lib/knj/http2.rb +100 -56
- data/lib/knj/knjdb/drivers/mysql/knjdb_mysql.rb +10 -5
- data/lib/knj/knjdb/drivers/mysql/knjdb_mysql_columns.rb +1 -1
- data/lib/knj/knjdb/drivers/mysql/knjdb_mysql_indexes.rb +11 -1
- data/lib/knj/knjdb/drivers/mysql/knjdb_mysql_tables.rb +0 -2
- data/lib/knj/knjdb/libknjdb.rb +41 -1
- data/lib/knj/knjdb/revision.rb +9 -2
- data/lib/knj/locales.rb +16 -9
- data/lib/knj/objects.rb +83 -61
- data/lib/knj/objects/objects_sqlhelper.rb +1 -1
- data/lib/knj/os.rb +5 -1
- data/lib/knj/php.rb +2 -0
- data/lib/knj/process_meta.rb +149 -14
- data/lib/knj/scripts/process_meta_exec.rb +36 -2
- data/lib/knj/unix_proc.rb +42 -33
- data/lib/knj/web.rb +34 -12
- data/lib/knj/wref.rb +4 -2
- metadata +15 -15
data/lib/knj/os.rb
CHANGED
@@ -194,9 +194,13 @@ module Knj::Os
|
|
194
194
|
if self.os == "linux"
|
195
195
|
unix_proc = Knj::Unix_proc.find_self
|
196
196
|
if unix_proc
|
197
|
-
if match_cmd = unix_proc["cmd"].match(/^(\/usr\/bin\/|)((j|iron|)ruby([\d\.-]
|
197
|
+
if match_cmd = unix_proc["cmd"].match(/^(\/usr\/bin\/|)((j|iron|)ruby([\d\.-]*))(\s+|$)/)
|
198
198
|
return "#{match_cmd[1]}#{match_cmd[2]}"
|
199
|
+
else
|
200
|
+
raise "Could not match the executed command from the process."
|
199
201
|
end
|
202
|
+
else
|
203
|
+
raise "Could not find the self-process."
|
200
204
|
end
|
201
205
|
end
|
202
206
|
|
data/lib/knj/php.rb
CHANGED
data/lib/knj/process_meta.rb
CHANGED
@@ -7,7 +7,10 @@ class Knj::Process_meta
|
|
7
7
|
def initialize(args = {})
|
8
8
|
@args = args
|
9
9
|
@objects = {}
|
10
|
+
|
11
|
+
#These variables are used to free memory in the subprocess, by using ObjectSpace#define_finalizer. The Mutex is the avoid problems when writing to the finalize-array multithreadded.
|
10
12
|
@finalize = []
|
13
|
+
@finalize_mutex = Mutex.new
|
11
14
|
|
12
15
|
if @args["exec_path"]
|
13
16
|
exec_path = @args["exec_path"]
|
@@ -69,22 +72,32 @@ class Knj::Process_meta
|
|
69
72
|
end
|
70
73
|
|
71
74
|
def proxy_finalizer(id)
|
72
|
-
@
|
75
|
+
@finalize_mutex.synchronize do
|
76
|
+
@finalize << id
|
77
|
+
end
|
73
78
|
end
|
74
79
|
|
75
80
|
def check_finalizers
|
76
81
|
return nil if @finalize.empty?
|
77
82
|
|
78
|
-
|
79
|
-
@
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
83
|
+
finalize = nil
|
84
|
+
@finalize_mutex.synchronize do
|
85
|
+
finalize = @finalize
|
86
|
+
@finalize = []
|
87
|
+
|
88
|
+
begin
|
89
|
+
@process.send("obj" => {
|
90
|
+
"type" => "unset_multiple",
|
91
|
+
"var_names" => finalize
|
92
|
+
})
|
93
|
+
rescue => e
|
94
|
+
if e.message.to_s.index("Var-name didnt exist when trying to unset:")
|
95
|
+
#ignore.
|
96
|
+
else
|
97
|
+
raise e
|
98
|
+
end
|
99
|
+
end
|
85
100
|
end
|
86
|
-
|
87
|
-
@finalize -= remove
|
88
101
|
end
|
89
102
|
|
90
103
|
#Parses the arguments given. Proxy-object-arguments will be their natural objects in the subprocess.
|
@@ -184,6 +197,10 @@ class Knj::Process_meta
|
|
184
197
|
|
185
198
|
#Spawns a new object in the subprocess by that classname, with those arguments and with that block.
|
186
199
|
def new(class_name, *args, &block)
|
200
|
+
#We need to check finalizers first, so we wont accidently reuse an ID, which will then be unset in the process.
|
201
|
+
self.check_finalizers
|
202
|
+
|
203
|
+
#Spawn and return the object.
|
187
204
|
return self.spawn_object(class_name, nil, *args, &block)
|
188
205
|
end
|
189
206
|
|
@@ -224,19 +241,23 @@ class Knj::Process_meta
|
|
224
241
|
|
225
242
|
#Calls a method on an object and returns the result.
|
226
243
|
def call_object(args, &block)
|
227
|
-
self.check_finalizers
|
228
|
-
|
229
244
|
if args.key?("capture_return")
|
230
245
|
capture_return = args["capture_return"]
|
231
246
|
else
|
232
247
|
capture_return = true
|
233
248
|
end
|
234
249
|
|
250
|
+
if args["buffered"]
|
251
|
+
type = "call_object_buffered"
|
252
|
+
else
|
253
|
+
type = "call_object_block"
|
254
|
+
end
|
255
|
+
|
235
256
|
res = @process.send(
|
236
257
|
{
|
237
258
|
"buffer_use" => args["buffer_use"],
|
238
259
|
"obj" => {
|
239
|
-
"type" =>
|
260
|
+
"type" => type,
|
240
261
|
"var_name" => args["var_name"],
|
241
262
|
"method_name" => args["method_name"],
|
242
263
|
"capture_return" => capture_return,
|
@@ -329,7 +350,12 @@ class Knj::Process_meta
|
|
329
350
|
@process.send("obj" => {"type" => "exit"})
|
330
351
|
@err_thread.kill if @err_thread
|
331
352
|
@process.destroy
|
332
|
-
|
353
|
+
|
354
|
+
begin
|
355
|
+
Process.kill("TERM", @pid)
|
356
|
+
rescue Errno::ESRCH
|
357
|
+
#Process is already dead - ignore.
|
358
|
+
end
|
333
359
|
|
334
360
|
begin
|
335
361
|
sleep 0.1
|
@@ -410,4 +436,113 @@ class Knj::Process_meta::Proxy_obj
|
|
410
436
|
&block
|
411
437
|
)
|
412
438
|
end
|
439
|
+
|
440
|
+
def _pm_buffered_caller(args)
|
441
|
+
return Knj::Process_meta::Proxy_obj::Buffered_caller.new({
|
442
|
+
:name => @args[:name],
|
443
|
+
:process_meta => @args[:process_meta]
|
444
|
+
}.merge(args))
|
445
|
+
end
|
446
|
+
end
|
447
|
+
|
448
|
+
class Knj::Process_meta::Proxy_obj::Buffered_caller
|
449
|
+
def initialize(args)
|
450
|
+
@args = args
|
451
|
+
@buffer = []
|
452
|
+
@mutex = Mutex.new
|
453
|
+
@mutex_write = Mutex.new
|
454
|
+
@count = 0
|
455
|
+
@debug = @args[:debug] if @args[:debug]
|
456
|
+
|
457
|
+
if @args[:count_to]
|
458
|
+
@count_to = @args[:count_to]
|
459
|
+
else
|
460
|
+
@count_to = 1000
|
461
|
+
end
|
462
|
+
|
463
|
+
@buffer_max = @count_to * 2
|
464
|
+
@threads = [] if @args[:async]
|
465
|
+
end
|
466
|
+
|
467
|
+
def method_missing(method_name, *args)
|
468
|
+
if method_name.to_s == @args[:method_name].to_s
|
469
|
+
self._pm_call(*args)
|
470
|
+
else
|
471
|
+
raise NoMethodError, "No such method: '#{method_name}'."
|
472
|
+
end
|
473
|
+
end
|
474
|
+
|
475
|
+
def _pm_call(*args)
|
476
|
+
raise @raise_error if @raise_error
|
477
|
+
|
478
|
+
@mutex.synchronize do
|
479
|
+
while @count >= @count_to and @buffer.length >= @buffer_max
|
480
|
+
STDOUT.print "Waiting for write to complete...\n" if @debug
|
481
|
+
sleep 0.1
|
482
|
+
end
|
483
|
+
|
484
|
+
STDOUT.print "Adding to buffer #{@buffer.length}...\n" if @debug
|
485
|
+
@buffer << args
|
486
|
+
@count += 1
|
487
|
+
end
|
488
|
+
|
489
|
+
self._pm_flush if @count >= @count_to and !@writing
|
490
|
+
return nil
|
491
|
+
end
|
492
|
+
|
493
|
+
def _pm_flush(*args)
|
494
|
+
raise @raise_error if @raise_error
|
495
|
+
|
496
|
+
buffer = nil
|
497
|
+
@mutex.synchronize do
|
498
|
+
buffer = @buffer
|
499
|
+
@buffer = []
|
500
|
+
@count = 0
|
501
|
+
end
|
502
|
+
|
503
|
+
if @args[:async]
|
504
|
+
begin
|
505
|
+
@threads << Thread.new do
|
506
|
+
self._pm_flush_real(buffer)
|
507
|
+
end
|
508
|
+
rescue => e
|
509
|
+
@raise_error = e
|
510
|
+
end
|
511
|
+
|
512
|
+
return nil
|
513
|
+
else
|
514
|
+
return self._pm_flush_real(buffer)
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
def _pm_flush_real(buffer)
|
519
|
+
@mutex_write.synchronize do
|
520
|
+
STDOUT.print "Writing...\n" if @debug
|
521
|
+
@writing = true
|
522
|
+
|
523
|
+
begin
|
524
|
+
return @args[:process_meta].call_object(
|
525
|
+
"var_name" => @args[:name],
|
526
|
+
"method_name" => @args[:method_name],
|
527
|
+
"args" => buffer,
|
528
|
+
"buffered" => true,
|
529
|
+
"capture_return" => false
|
530
|
+
)
|
531
|
+
ensure
|
532
|
+
@writing = false
|
533
|
+
end
|
534
|
+
end
|
535
|
+
end
|
536
|
+
|
537
|
+
def _pm_close
|
538
|
+
self._pm_flush
|
539
|
+
|
540
|
+
if @args[:async]
|
541
|
+
@threads.each do |thread|
|
542
|
+
thread.join
|
543
|
+
end
|
544
|
+
end
|
545
|
+
|
546
|
+
raise @raise_error if @raise_error
|
547
|
+
end
|
413
548
|
end
|
@@ -22,6 +22,8 @@ objects = {}
|
|
22
22
|
|
23
23
|
if obj.is_a?(Hash)
|
24
24
|
if obj["type"] == "spawn_object"
|
25
|
+
raise "An object by that name already exists: '#{obj["var_name"]}'." if objects.key?(obj["var_name"])
|
26
|
+
|
25
27
|
#Fix new integer.
|
26
28
|
if obj["class_name"].to_s == "Integer" or obj["class_name"].to_s == "Fixnum"
|
27
29
|
objects[obj["var_name"]] = obj["args"].first.to_i
|
@@ -35,7 +37,7 @@ objects = {}
|
|
35
37
|
d.answer("type" => "success")
|
36
38
|
elsif obj["type"] == "proxy_from_call"
|
37
39
|
raise "No 'var_name' was given in arguments." if !obj["var_name"]
|
38
|
-
raise "No object by that name: '#{obj["proxy_obj"]}' in '#{objects}'." if !objects.key?(obj["proxy_obj"])
|
40
|
+
raise "No object by that name when trying to do 'proxy_from_call': '#{obj["proxy_obj"]}' in '#{objects}'." if !objects.key?(obj["proxy_obj"])
|
39
41
|
obj_to_call = objects[obj["proxy_obj"]]
|
40
42
|
res = obj_to_call.__send__(obj["method_name"], *obj["args"])
|
41
43
|
objects[obj["var_name"]] = res
|
@@ -57,6 +59,28 @@ objects = {}
|
|
57
59
|
raise "No object by that name: '#{obj["var_name"]}'." if !obj
|
58
60
|
res = obj_to_call.__send__(obj["method_name"], *obj["args"])
|
59
61
|
res = nil if obj["capture_return"] == false
|
62
|
+
d.answer("type" => "call_object_success", "result" => res)
|
63
|
+
elsif obj["type"] == "call_object_buffered"
|
64
|
+
raise "Invalid var-name: '#{obj["var_name"]}'." if obj["var_name"].to_s.strip.length <= 0
|
65
|
+
|
66
|
+
obj_to_call = objects[obj["var_name"]]
|
67
|
+
raise "No object by that name: '#{obj["var_name"]}'." if !obj
|
68
|
+
capt_return = obj["capture_return"]
|
69
|
+
|
70
|
+
if capt_return != false
|
71
|
+
ret = []
|
72
|
+
else
|
73
|
+
ret = nil
|
74
|
+
end
|
75
|
+
|
76
|
+
obj["args"].each do |args|
|
77
|
+
if capt_return != false
|
78
|
+
ret << obj_to_call.__send__(obj["method_name"], *args)
|
79
|
+
else
|
80
|
+
obj_to_call.__send__(obj["method_name"], *args)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
60
84
|
d.answer("type" => "call_object_success", "result" => res)
|
61
85
|
elsif obj["type"] == "call_object_block"
|
62
86
|
raise "Invalid var-name: '#{obj["var_name"]}'." if obj["var_name"].to_s.strip.length <= 0
|
@@ -77,9 +101,19 @@ objects = {}
|
|
77
101
|
end
|
78
102
|
elsif obj["type"] == "unset"
|
79
103
|
raise "Invalid var-name: '#{obj["var_name"]}'." if obj["var_name"].to_s.strip.length <= 0
|
80
|
-
raise "Var-name
|
104
|
+
raise Knj::Errors::NotFound, "Var-name didnt exist when trying to unset: '#{obj["var_name"]}'." if !objects.key?(obj["var_name"])
|
81
105
|
objects.delete(obj["var_name"])
|
82
106
|
d.answer("type" => "unset_success")
|
107
|
+
elsif obj["type"] == "unset_multiple"
|
108
|
+
err = nil
|
109
|
+
obj["var_names"].each do |var_name|
|
110
|
+
err = [Knj::Errors::InvalidData, "Invalid var-name: '#{var_name}'."] if var_name.to_s.strip.length <= 0
|
111
|
+
err = [Knj::Errors::NotFound, "Var-name didnt exist when trying to unset: '#{var_name}'."] if !objects.key?(var_name)
|
112
|
+
objects.delete(var_name)
|
113
|
+
end
|
114
|
+
|
115
|
+
raise err[0], err[1] if err
|
116
|
+
d.answer("type" => "unset_success")
|
83
117
|
elsif obj["type"] == "static"
|
84
118
|
const = Knj::Strings.const_get_full(obj["const"])
|
85
119
|
res = const.__send__(obj["method_name"], *obj["args"], &block)
|
data/lib/knj/unix_proc.rb
CHANGED
@@ -1,17 +1,23 @@
|
|
1
|
+
require "#{$knjpath}wref"
|
2
|
+
|
1
3
|
class Knj::Unix_proc
|
2
4
|
attr_reader :data
|
3
|
-
|
5
|
+
|
6
|
+
PROCS = Knj::Wref_map.new
|
7
|
+
MUTEX = Mutex.new
|
4
8
|
|
5
9
|
def self.spawn(data)
|
6
|
-
|
10
|
+
pid = data["pid"].to_i
|
7
11
|
|
8
|
-
|
12
|
+
begin
|
13
|
+
proc_ele = PROCS[pid]
|
9
14
|
proc_ele.update_data(data)
|
10
|
-
|
11
|
-
|
15
|
+
rescue WeakRef::RefError
|
16
|
+
proc_ele = Knj::Unix_proc.new(data)
|
17
|
+
PROCS[pid] = proc_ele
|
12
18
|
end
|
13
19
|
|
14
|
-
return
|
20
|
+
return proc_ele
|
15
21
|
end
|
16
22
|
|
17
23
|
def self.list(args = {})
|
@@ -23,40 +29,43 @@ class Knj::Unix_proc
|
|
23
29
|
cmdstr << " | #{grepstr}"
|
24
30
|
end
|
25
31
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
res.scan(/^(\S+)\s+([0-9]+)\s+([0-9.]+)\s+([0-9.]+)\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+ (.+)($|\n)/) do |match|
|
30
|
-
pid = match[1]
|
31
|
-
|
32
|
-
data = {
|
33
|
-
"user" => match[0],
|
34
|
-
"pid" => pid,
|
35
|
-
"cpu_last" => match[2],
|
36
|
-
"ram_last" => match[3],
|
37
|
-
"cmd" => match[4],
|
38
|
-
"app" => File.basename(match[4])
|
39
|
-
}
|
40
|
-
|
41
|
-
next if (!args.key?("ignore_self") or args["ignore_self"]) and match[1].to_i == $$.to_i
|
42
|
-
next if grepstr.length > 0 and match[4].index(grepstr) != nil #dont return current process.
|
32
|
+
MUTEX.synchronize do
|
33
|
+
ret = []
|
34
|
+
res = Knj::Os.shellcmd(cmdstr)
|
43
35
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
36
|
+
res.scan(/^(\S+)\s+([0-9]+)\s+([0-9.]+)\s+([0-9.]+)\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+ (.+)($|\n)/) do |match|
|
37
|
+
pid = match[1]
|
38
|
+
|
39
|
+
data = {
|
40
|
+
"user" => match[0],
|
41
|
+
"pid" => pid,
|
42
|
+
"cpu_last" => match[2],
|
43
|
+
"ram_last" => match[3],
|
44
|
+
"cmd" => match[4],
|
45
|
+
"app" => File.basename(match[4])
|
46
|
+
}
|
47
|
+
|
48
|
+
next if (!args.key?("ignore_self") or args["ignore_self"]) and match[1].to_i == $$.to_i
|
49
|
+
next if grepstr.length > 0 and match[4].index(grepstr) != nil #dont return current process.
|
50
|
+
|
51
|
+
if args.key?("pids")
|
52
|
+
found = false
|
53
|
+
args["pids"].each do |pid_given|
|
54
|
+
if pid_given.to_s == pid.to_s
|
55
|
+
found = true
|
56
|
+
break
|
57
|
+
end
|
50
58
|
end
|
59
|
+
|
60
|
+
next if !found
|
51
61
|
end
|
52
62
|
|
53
|
-
|
63
|
+
ret << Knj::Unix_proc.spawn(data)
|
54
64
|
end
|
55
65
|
|
56
|
-
|
66
|
+
PROCS.clean
|
67
|
+
return ret
|
57
68
|
end
|
58
|
-
|
59
|
-
return ret
|
60
69
|
end
|
61
70
|
|
62
71
|
def self.find_self
|
data/lib/knj/web.rb
CHANGED
@@ -466,7 +466,7 @@ class Knj::Web
|
|
466
466
|
Knj::ArrayExt.hash_sym(args)
|
467
467
|
|
468
468
|
if args.key?(:value)
|
469
|
-
if args[:value].is_a?(Array) and args[:value].first.is_a?(NilClass)
|
469
|
+
if args[:value].is_a?(Array) and (args[:value].first.is_a?(NilClass) or args[:value].first == false)
|
470
470
|
value = nil
|
471
471
|
elsif args[:value].is_a?(Array)
|
472
472
|
if !args[:value][2] or args[:value][2] == :key
|
@@ -530,6 +530,7 @@ class Knj::Web
|
|
530
530
|
}
|
531
531
|
attr.merge!(args[:attr]) if args[:attr]
|
532
532
|
attr["disabled"] = "disabled" if args[:disabled]
|
533
|
+
attr["maxlength"] = args[:maxlength] if args.key?(:maxlength)
|
533
534
|
|
534
535
|
raise "No name given to the Web::input()-method." if !args[:name] and args[:type] != :info and args[:type] != :textshow and args[:type] != :plain and args[:type] != :spacer and args[:type] != :headline
|
535
536
|
|
@@ -553,6 +554,12 @@ class Knj::Web
|
|
553
554
|
classes_tr_html = ""
|
554
555
|
end
|
555
556
|
|
557
|
+
if args.key?(:title)
|
558
|
+
title_html = args[:title].to_s.html
|
559
|
+
elsif args.key?(:title_html)
|
560
|
+
title_html = args[:title_html]
|
561
|
+
end
|
562
|
+
|
556
563
|
html = ""
|
557
564
|
|
558
565
|
classes = ["input_#{args[:type]}"]
|
@@ -567,17 +574,17 @@ class Knj::Web
|
|
567
574
|
html << "<tr#{classes_tr_html}>"
|
568
575
|
html << "<td colspan=\"2\" class=\"tdcheck\">"
|
569
576
|
html << "<input#{self.attr_html(attr)} />"
|
570
|
-
html << "<label for=\"#{args[:id].html}\">#{
|
577
|
+
html << "<label for=\"#{args[:id].html}\">#{title_html}</label>"
|
571
578
|
html << "</td>"
|
572
579
|
html << "</tr>"
|
573
580
|
elsif args[:type] == :headline
|
574
|
-
html << "<tr#{classes_tr_html}><td colspan=\"2\"><h2 class=\"input_headline\">#{
|
581
|
+
html << "<tr#{classes_tr_html}><td colspan=\"2\"><h2 class=\"input_headline\">#{title_html}</h2></td></tr>"
|
575
582
|
elsif args[:type] == :spacer
|
576
583
|
html << "<tr#{classes_tr_html}><td colspan=\"2\"> </td></tr>"
|
577
584
|
else
|
578
585
|
html << "<tr#{classes_tr_html}>"
|
579
586
|
html << "<td class=\"tdt\">"
|
580
|
-
html <<
|
587
|
+
html << title_html
|
581
588
|
html << "</td>"
|
582
589
|
html << "<td#{self.style_html(css)} class=\"tdc\">"
|
583
590
|
|
@@ -671,12 +678,7 @@ class Knj::Web
|
|
671
678
|
|
672
679
|
def self.opts(opthash, curvalue = nil, opts_args = {})
|
673
680
|
opts_args = {} if !opts_args
|
674
|
-
opts_args
|
675
|
-
if !key.is_a?(Symbol)
|
676
|
-
opts_args[key.to_sym] = value
|
677
|
-
opts_args.delete(key)
|
678
|
-
end
|
679
|
-
end
|
681
|
+
Knj::ArrayExt.hash_sym(opts_args)
|
680
682
|
|
681
683
|
return "" if !opthash
|
682
684
|
cname = curvalue.class.name
|
@@ -739,7 +741,7 @@ class Knj::Web
|
|
739
741
|
return "gecko"
|
740
742
|
elsif agent.index("msie") != nil
|
741
743
|
return "msie"
|
742
|
-
elsif agent.index("w3c") != nil or agent.index("baiduspider") != nil or agent.index("googlebot") != nil
|
744
|
+
elsif agent.index("w3c") != nil or agent.index("baiduspider") != nil or agent.index("googlebot") != nil or agent.index("bot") != nil
|
743
745
|
return "bot"
|
744
746
|
else
|
745
747
|
#print "Unknown agent: #{agent}"
|
@@ -887,16 +889,36 @@ class Knj::Web
|
|
887
889
|
browser = "bot"
|
888
890
|
title = "AhrefsBot"
|
889
891
|
version = match[1]
|
892
|
+
elsif agent.index("sosospider") != nil
|
893
|
+
browser = "bot"
|
894
|
+
title = "Bot"
|
895
|
+
version = "Sosospider"
|
890
896
|
else
|
891
897
|
browser = "unknown"
|
892
898
|
title = "(unknown browser)"
|
893
899
|
version = "(unknown version)"
|
894
900
|
end
|
895
901
|
|
902
|
+
os = nil
|
903
|
+
os_version = nil
|
904
|
+
if agent.index("linux") != nil
|
905
|
+
os = "linux"
|
906
|
+
elsif match = agent.match(/mac\s+os\s+x\s+([\d_+])/)
|
907
|
+
os = "mac"
|
908
|
+
elsif match = agent.match(/windows\s+nt\s+([\d\.]+)/)
|
909
|
+
os = "windows"
|
910
|
+
|
911
|
+
if match[1] == "5.1"
|
912
|
+
os_version = "xp"
|
913
|
+
end
|
914
|
+
end
|
915
|
+
|
896
916
|
return {
|
897
917
|
"browser" => browser,
|
898
918
|
"title" => title,
|
899
|
-
"version" => version
|
919
|
+
"version" => version,
|
920
|
+
"os" => os,
|
921
|
+
"os_version" => os_version
|
900
922
|
}
|
901
923
|
end
|
902
924
|
|