Class: QStat

Inherits:
Object
  • Object
show all
Defined in:
lib/ruby-qstat.rb

Defined Under Namespace

Classes: PlayerInfo, Response, ServerInfo

Constant Summary collapse

DEFAULT_MAX_PING =
50
@@qstat_path =
"qstat"
@@logger =
Logger.new(nil)

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeQStat

Returns a new instance of QStat.



321
322
323
# File 'lib/ruby-qstat.rb', line 321

def initialize
  raise "not implemented"
end

Class Method Details

.exec_cmd(*params, &filter) ⇒ Object



438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
# File 'lib/ruby-qstat.rb', line 438

def self.exec_cmd(*params, &filter)
  data = ""
  Open3.popen3(*params){ |i,o,e,w|
    i.close_write

    tl = Thread.new{
      begin
        while line = o.gets 
          if block_given? and filter.call(line)
            data += line
            Process.kill :TERM, w.pid
            break
          end
          data += line
        end
      rescue
        @@logger.error $!
      end
    }
    tl2 = Thread.new{
      begin
        while !e.eof?
          @@logger.info e.read 1024
        end
      rescue
        @@logger.error $!
      end
    }
    tl.join
  }
  data
end

.exec_qstat_query_cmd(cmd_str) ⇒ Object

Low API



434
435
436
# File 'lib/ruby-qstat.rb', line 434

def self.exec_qstat_query_cmd(cmd_str)
  ServerInfo.new self.exec_cmd(cmd_str).force_convert_to("UTF-8")
end

.get_xml(host, gametype, gamename, &filter) ⇒ Object



471
472
473
# File 'lib/ruby-qstat.rb', line 471

def self.get_xml(host, gametype, gamename, &filter)
  self.exec_cmd("#{@@qstat_path} -utf8 -xml -P -R -nh -#{gametype},game=#{gamename} #{host}", &filter)
end

.logger=(logger) ⇒ Object



329
330
331
# File 'lib/ruby-qstat.rb', line 329

def self.logger=(logger)
  @@logger = logger
end

.qslist(host, gametype, gamename, maxping = DEFAULT_MAX_PING, &block) ⇒ Object



399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
# File 'lib/ruby-qstat.rb', line 399

def self.qslist(host, gametype, gamename, maxping=DEFAULT_MAX_PING, &block)
  res = Response.new
  res.address = host
  res.gametype = gametype
  res.gamename = gamename

  broken_xml = self.get_xml(host, gametype, gamename){ |line|
    if line =~ /<ping>(\d+)<\/ping>/
      ping = Regexp.last_match(1).to_i 
      if maxping < ping
        true
      end
    end
  }

  doc = Nokogiri(broken_xml)
  doc.search("/qstat/server/ping").each{ |ping_tag|
    if ping_tag.text.to_i >= maxping
      ping_tag.parent.remove
    end
  }
  res.doc = doc
  res.xml = doc.to_s

  if block_given?
    block.call(res)
  else
    res
  end
end

.qstat(*args, &block) ⇒ Object



429
430
431
# File 'lib/ruby-qstat.rb', line 429

def self.qstat(*args, &block)
  self.qslist(*args, &block)
end

.qstat_path=(path) ⇒ Object



325
326
327
# File 'lib/ruby-qstat.rb', line 325

def self.qstat_path=(path)
  @@qstat_path = path
end

.query(host, gametype) ⇒ Object

query player info



333
334
335
# File 'lib/ruby-qstat.rb', line 333

def self.query(host, gametype) # query player info
  self.exec_qstat_query_cmd "#{@@qstat_path} -P -utf8 -nh -#{gametype} #{host}"
end

.query_serverinfo(host, gametype) ⇒ Object

query server info



340
341
342
# File 'lib/ruby-qstat.rb', line 340

def self.query_serverinfo(host, gametype) # query server info
  self.exec_qstat_query_cmd "#{@@qstat_path} -R -utf8 -nh -#{gametype} #{host}"
end

.query_serverlist(host, gametype, gamename, maxping = DEFAULT_MAX_PING) ⇒ Object



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
# File 'lib/ruby-qstat.rb', line 344

def self.query_serverlist(host, gametype, gamename, maxping=DEFAULT_MAX_PING)
  self.qslist(host, gametype, gamename, maxping){ |response|
    if response.valid?
      servers = response.doc.search("/qstat/server").to_a
      if servers.size <= 1
        raise "broken response" # 1件以下はおかしいっす
      end

      # 最初のserverは構造情報なので除去
      servers.shift

      # からじゃないよね??
      if servers.empty?
        raise "broken response#2"
      end

      # 取得したすべてのサーバー情報に対して
      # ServerInfo化していく
      infos = []
      servers.each{ |server|
        info = ServerInfo.create_from_xml(Nokogiri(server.to_s))
        infos << info
      }
      infos
    else
      raise "response is invalid: #{response.inspect}"
    end
  }
end

.read_from_xml(path) ⇒ Object



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/ruby-qstat.rb', line 374

def self.read_from_xml(path)
  doc = Nokogiri(File.read(path))
  servers = doc.search("/qstat/server").to_a
  if servers.size <= 1
    raise "broken response" # 1件以下はおかしいっす
  end

  # 最初のserverは構造情報なので除去
  servers.shift

  # からじゃないよね??
  if servers.empty?
    raise "broken response#2"
  end

  # 取得したすべてのサーバー情報に対して
  # ServerInfo化していく
  infos = []
  servers.each{ |server|
    info = ServerInfo.create_from_xml(Nokogiri(server.to_s))
    infos << info
  }
  infos
end

.server_info(*args) ⇒ Object



336
337
338
# File 'lib/ruby-qstat.rb', line 336

def self.server_info(*args)
  self.query(*args)
end