mirror of
https://github.com/mistergibson/gxg-framework.git
synced 2026-10-19 04:49:44 -07:00
Initial Commit
This commit is contained in:
parent
3215e21a8a
commit
4bb9f2f2ea
189 changed files with 135079 additions and 2 deletions
907
lib/gxg-framework.rb
Normal file
907
lib/gxg-framework.rb
Normal file
|
|
@ -0,0 +1,907 @@
|
|||
# shell command:
|
||||
module Kernel
|
||||
def shell(command=nil,&block)
|
||||
if command.to_s.size > 0
|
||||
block.call(`#{command.to_s}`)
|
||||
true
|
||||
end
|
||||
end
|
||||
end
|
||||
# bootstrap.rb is a separate file so other external scripts can avail themselves of it.
|
||||
require(::File.expand_path(::File.dirname(__FILE__) << "/gxg/bootstrap.rb"))
|
||||
# Load base requirements:
|
||||
requirements = []
|
||||
requirements.push({:requirement => "ostruct", :gem => nil})
|
||||
requirements.push({:requirement => "logger", :gem => nil})
|
||||
requirements.push({:requirement => "fileutils", :gem => nil})
|
||||
requirements.push({:requirement => "bigdecimal", :gem => nil})
|
||||
requirements.push({:requirement => "singleton", :gem => nil})
|
||||
requirements.push({:requirement => "set", :gem => nil})
|
||||
requirements.push({:requirement => "csv", :gem => nil})
|
||||
requirements.push({:requirement => "uri", :gem => nil})
|
||||
requirements.push({:requirement => "socket", :gem => nil})
|
||||
requirements.push({:requirement => "resolv", :gem => nil})
|
||||
requirements.push({:requirement => "stringio", :gem => nil})
|
||||
requirements.push({:requirement => "date", :gem => nil})
|
||||
requirements.push({:requirement => "ffi", :gem => "ffi"})
|
||||
requirements.push({:requirement => "base64", :gem => nil})
|
||||
requirements.push({:requirement => "digest/md5", :gem => nil})
|
||||
requirements.push({:requirement => "digest/sha2", :gem => nil})
|
||||
requirements.push({:requirement => "securerandom", :gem => nil})
|
||||
requirements.push({:requirement => "json", :gem => nil})
|
||||
requirements.push({:requirement => "sys-cpu", :gem => "sys-cpu"})
|
||||
requirements.push({:requirement => "sys-proctable", :gem => "sys-proctable"})
|
||||
requirements.push({:requirement => "chronic", :gem => "chronic"})
|
||||
# FIX : big hassle with windows - exclude for now
|
||||
# requirements.push({:requirement => "ffi-rzmq", :gem => "ffi-rzmq"})
|
||||
# requirements.push({:requirement => "ezmq", :gem => "ezmq"})
|
||||
requirements.push({:requirement => "nokogiri", :gem => "nokogiri"})
|
||||
requirements.push({:requirement => "rufus-scheduler", :gem => "rufus-scheduler"})
|
||||
requirements.push({:requirement => "mimemagic", :gem => "mimemagic"})
|
||||
# requirements.push({:requirement => "mimemagic/overlay", :gem => "mimemagic"})
|
||||
requirements.push({:requirement => "bcrypt", :gem => "bcrypt"})
|
||||
requirements.push({:requirement => "matrix_sdk", :gem => "matrix_sdk"})
|
||||
requirements.push({:requirement => "state_machines", :gem => "state_machines"})
|
||||
# consider adding facets later - esp. if file io needs extension
|
||||
# ### Database Adapter for JRuby:
|
||||
if ::RUBY_ENGINE == "jruby"
|
||||
requirements.push({:requirement => "jdbc/sqlite3", :gem => "jdbc-sqlite3"})
|
||||
requirements.push({:requirement => "jdbc/mysql", :gem => "jdbc-mysql"})
|
||||
requirements.push({:requirement => "jdbc-postgresql", :gem => "jdbc-postgresql"})
|
||||
requirements.push({:requirement => "jdbc/as400", :gem => "jdbc-as400"})
|
||||
requirements.push({:requirement => "jdbc/cassandra", :gem => "jdbc-cassandra"})
|
||||
requirements.push({:requirement => "jdbc/crate", :gem => "jdbc-crate"})
|
||||
requirements.push({:requirement => "jdbc/derby", :gem => "jdbc-derby"})
|
||||
requirements.push({:requirement => "jdbc/filemaker", :gem => "jdbc-filemaker"})
|
||||
requirements.push({:requirement => "jdbc/firebird", :gem => "jdbc-firebird"})
|
||||
requirements.push({:requirement => "jdbc/h2", :gem => "jdbc-h2"})
|
||||
requirements.push({:requirement => "jdbc/hive2", :gem => "jdbc-hive2"})
|
||||
requirements.push({:requirement => "jdbc/hsqldb", :gem => "jdbc-hsqldb"})
|
||||
requirements.push({:requirement => "jdbc/jt400", :gem => "jdbc-jt400"})
|
||||
requirements.push({:requirement => "jdbc/jtds", :gem => "jdbc-jtds"})
|
||||
requirements.push({:requirement => "jdbc/luciddb", :gem => "jdbc-luciddb"})
|
||||
# ### FIX : MS-SQL Server driver not in OpenJDK 14 - exclude on THAT JDK for now
|
||||
if ENV_JAVA.is_a?(::Hash)
|
||||
if ENV_JAVA['java.specification.version'] == "1.8"
|
||||
requirements.push({:requirement => "jdbc/mssql", :gem => "jdbc-mssql"})
|
||||
end
|
||||
end
|
||||
requirements.push({:requirement => "jdbc/nuodb", :gem => "jdbc-nuodb"})
|
||||
# ### FIX : openedge requires external .jars in classpath -- exclude for now.
|
||||
# requirements.push({:requirement => "jdbc/openedge", :gem => "jdbc-openedge"})
|
||||
requirements.push({:requirement => "jdbc/orientdb", :gem => "jdbc-orientdb"})
|
||||
requirements.push({:requirement => "jdbc/phoenix", :gem => "jdbc-phoenix"})
|
||||
# ### FIX : redshift is missing the RedshiftJDBC4.jar file
|
||||
# requirements.push({:requirement => "redshift", :gem => "jdbc-redshift"})
|
||||
requirements.push({:requirement => "jdbc/splice", :gem => "jdbc-splice"})
|
||||
requirements.push({:requirement => "jdbc/vertica", :gem => "jdbc-vertica"})
|
||||
end
|
||||
# ### Load Requirements
|
||||
load_error = nil
|
||||
requirements.to_enum.each do |entry|
|
||||
begin
|
||||
require entry[:requirement]
|
||||
rescue LoadError => the_error
|
||||
puts "Error: Missing Requirement\n" + the_error.to_s + "\n"
|
||||
if entry[:gem]
|
||||
puts "You need to install " + (entry[:gem]) + ", like so:\n"
|
||||
puts "sudo gem install '" + (entry[:gem]) + "'"
|
||||
else
|
||||
puts "You need to install " + (entry[:requirement]) + "."
|
||||
end
|
||||
load_error = true
|
||||
break
|
||||
end
|
||||
end
|
||||
unless load_error
|
||||
## ---------------------------------------------------------------------------------------------------------------------
|
||||
# Various preliminary patches to dependencies:
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
# Various preliminary patches to standard classes:
|
||||
# <none>
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
# main module declaration:
|
||||
module GxG
|
||||
#
|
||||
def self.uuid_generate()
|
||||
::SecureRandom::uuid.to_s
|
||||
end
|
||||
# LOG = $LOG
|
||||
LOG = ::Logger.new(STDOUT)
|
||||
#
|
||||
end
|
||||
#
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
# Various data element classes:
|
||||
require File.expand_path("./gxg/gxg_elements.rb",File.dirname(__FILE__))
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
# Preliminary alternations to Kernel/Object class: Actor/Event support
|
||||
class Object
|
||||
# private methods
|
||||
private
|
||||
def this()
|
||||
self
|
||||
end
|
||||
#
|
||||
def pause(params={})
|
||||
#
|
||||
end
|
||||
# public methods
|
||||
public
|
||||
def is_any?(*args)
|
||||
result = false
|
||||
args.flatten.to_enum.each do |thing|
|
||||
if thing.class == Class
|
||||
if self.is_a?(thing)
|
||||
result = true
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def alive?()
|
||||
# Why: adjusting the entire object space to dealing with possibilities introduced by Celluloid.
|
||||
true
|
||||
end
|
||||
#
|
||||
def actor?()
|
||||
false
|
||||
end
|
||||
#
|
||||
def handle_error(the_error={})
|
||||
if the_error[:error].is_a?(::Exception)
|
||||
log_error(the_error)
|
||||
end
|
||||
end
|
||||
#
|
||||
def serialize()
|
||||
if self.is_any?(::Array, ::Hash, ::Set, ::Struct)
|
||||
data = self.process do |entry, selector|
|
||||
entry.serialize()
|
||||
end
|
||||
begin
|
||||
("structure:" + ::Marshal.dump(data).encode64())
|
||||
rescue Exception => the_error
|
||||
"marshal:BAgw"
|
||||
end
|
||||
else
|
||||
if self.is_a?(::String)
|
||||
if self.serialized?()
|
||||
self
|
||||
else
|
||||
("marshal:" + ::Marshal.dump(self).encode64())
|
||||
end
|
||||
else
|
||||
# by default, or upon error, returns marshaled nil, must override to get other serialization
|
||||
begin
|
||||
("marshal:" + ::Marshal.dump(self).encode64())
|
||||
rescue Exception => the_error
|
||||
"marshal:BAgw"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
end
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
# Units and support element classes:
|
||||
require File.expand_path("./gxg/gxg_units.rb",File.dirname(__FILE__))
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
# Event classes:
|
||||
require File.expand_path("./gxg/gxg_events.rb",File.dirname(__FILE__))
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
# Additional alternations to Kernel/Object class: Data element class support, quota support functions
|
||||
module Kernel
|
||||
#
|
||||
# alias :stock_enum_for :enum_for
|
||||
# alias :stock_to_enum :to_enum
|
||||
# def enum_for(method=:each,*args)
|
||||
# GxG::Enumerator.new(self,method,*args)
|
||||
# end
|
||||
# alias :to_enum :enum_for
|
||||
#
|
||||
def slots_used(counted=[], options={})
|
||||
# returns how many heap slots are consumed by this *instance* (and elements) and its instance variables (and elements) all the way down.
|
||||
# General Research: see memprof for how much is consumed by a Module or Class or Method.
|
||||
# TODO: ::Kernel#slots_used : find the byte-size of a given :method and add it to slot_count initial value.
|
||||
unless counted.is_a?(Array)
|
||||
if counted.is_a?(Hash)
|
||||
options = counted
|
||||
end
|
||||
counted = []
|
||||
end
|
||||
# warning: assumes references to nil incur no RVALUE allocation.
|
||||
exclusions = [nil]
|
||||
if options[:exclude]
|
||||
unless options[:exclude].is_a?(Array)
|
||||
options[:exclude] = [(options[:exclude])]
|
||||
end
|
||||
exclusions = (options[:exclude] << nil)
|
||||
end
|
||||
slot_count = 0
|
||||
unless (counted.include?(self) || exclusions.include?(self))
|
||||
counted << self
|
||||
slot_count = 1
|
||||
if self.is_any?(::Array,::Hash,::Set,::Struct)
|
||||
self.search do |entry,selector,container|
|
||||
unless (counted.include?(entry) || exclusions.include?(entry))
|
||||
unless selector.is_a?(Numeric)
|
||||
slot_count += selector.slots_used(counted, {:exclude => exclusions})
|
||||
end
|
||||
slot_count += entry.slots_used(counted, {:exclude => exclusions})
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
self.instance_variables.to_enum.each do |ivar|
|
||||
unless (counted.include?(ivar) || exclusions.include?(ivar))
|
||||
if ivar.is_any?(::Array,::Hash,::Set,::Struct)
|
||||
ivar.search do |entry,selector,container|
|
||||
unless (counted.include?(entry) || exclusions.include?(entry))
|
||||
unless selector.is_a?(Numeric)
|
||||
slot_count += selector.slots_used(counted, {:exclude => exclusions})
|
||||
end
|
||||
slot_count += entry.slots_used(counted, {:exclude => exclusions})
|
||||
end
|
||||
end
|
||||
else
|
||||
slot_count += ivar.slots_used(counted, {:exclude => exclusions})
|
||||
end
|
||||
end
|
||||
end
|
||||
slot_count
|
||||
end
|
||||
#
|
||||
def content_size_used(counted=[], options={})
|
||||
# returns how many bytes are consumed by this *instance* (and elements) and its instance variables (and elements) all the way down.
|
||||
unless counted.is_a?(Array)
|
||||
if counted.is_a?(Hash)
|
||||
options = counted
|
||||
end
|
||||
counted = []
|
||||
end
|
||||
exclusions = [nil]
|
||||
if options[:exclude]
|
||||
unless options[:exclude].is_a?(Array)
|
||||
options[:exclude] = [(options[:exclude])]
|
||||
end
|
||||
exclusions = (options[:exclude] << nil)
|
||||
end
|
||||
count = 0
|
||||
unless (counted.include?(self) || exclusions.include?(self))
|
||||
counted << self
|
||||
if self.is_any?(::Array,::Hash,::Struct)
|
||||
self.search do |entry,selector,container|
|
||||
unless counted.include?(entry)
|
||||
unless selector.is_a?(Numeric)
|
||||
count += selector.content_size_used(counted, {:exclude => exclusions})
|
||||
end
|
||||
count += entry.content_size_used(counted, {:exclude => exclusions})
|
||||
end
|
||||
end
|
||||
else
|
||||
unless self.is_a?(::GxG::ByteArray)
|
||||
if self.respond_to?(:bytesize)
|
||||
count = self.bytesize
|
||||
else
|
||||
if self.respond_to?(:size)
|
||||
count = self.size
|
||||
else
|
||||
# TODO: cull the size of more exotic classes by class:
|
||||
count = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
self.instance_variables.to_enum.each do |ivar|
|
||||
# must decode from symbol to actual instance var
|
||||
ivar = self.instance_eval(ivar.to_s)
|
||||
unless (counted.include?(ivar) || exclusions.include?(ivar))
|
||||
if ivar.is_any?(::Array,::Hash,::Struct)
|
||||
ivar.search do |entry,selector,container|
|
||||
unless (counted.include?(entry) || exclusions.include?(entry))
|
||||
unless selector.is_a?(Numeric)
|
||||
# Symbols and Strings in Hashes take up heap space, so lets count it.
|
||||
count += selector.content_size_used(counted, {:exclude => exclusions})
|
||||
end
|
||||
count += entry.content_size_used(counted, {:exclude => exclusions})
|
||||
end
|
||||
end
|
||||
else
|
||||
unless (counted.include?(ivar) || exclusions.include?(ivar))
|
||||
count += ivar.content_size_used(counted, {:exclude => exclusions}).to_i
|
||||
# Subsequent references to this object will only incur an RVALUE slot count (me thinks)
|
||||
counted << ivar
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
count
|
||||
end
|
||||
#
|
||||
end
|
||||
#
|
||||
class Object
|
||||
include Kernel
|
||||
#
|
||||
private
|
||||
#
|
||||
# logging hooks
|
||||
def log_unknown(message = nil, progname = nil, &block)
|
||||
# a.k.a 'unknown'
|
||||
if message.is_a?(::Hash)
|
||||
if message[:trace]
|
||||
message = (message[:trace].to_s + "\n Parameters: #{message[:parameters].inspect.to_s}")
|
||||
else
|
||||
message = (message[:unknown].to_s + "\n Parameters: #{message[:parameters].inspect.to_s}")
|
||||
end
|
||||
end
|
||||
::GxG::LOG.unknown(message.to_s)
|
||||
end
|
||||
alias :log_trace :log_unknown
|
||||
def log_fatal(message = nil, progname = nil, &block)
|
||||
if message.is_a?(::Hash)
|
||||
if message[:error].is_a?(::Exception) || message[:fatal].is_a?(::Exception)
|
||||
if message[:error]
|
||||
message = (message[:error].to_s + "\n Parameters: #{message[:parameters].inspect.to_s},\n Backtrace: " + message[:error].backtrace.join("\n"))
|
||||
else
|
||||
message = (message[:fatal].to_s + "\n Parameters: #{message[:parameters].inspect.to_s},\n Backtrace: " + message[:fatal].backtrace.join("\n"))
|
||||
end
|
||||
else
|
||||
if message[:error]
|
||||
message = (message[:error].to_s + "\n Parameters: #{message[:parameters].inspect.to_s}")
|
||||
else
|
||||
message = (message[:fatal].to_s + "\n Parameters: #{message[:parameters].inspect.to_s}")
|
||||
end
|
||||
end
|
||||
end
|
||||
::GxG::LOG.fatal(message.to_s)
|
||||
end
|
||||
def log_error(message = nil, progname = nil, &block)
|
||||
if message.is_a?(::Hash)
|
||||
if message[:error].is_a?(::Exception)
|
||||
message = (message[:error].to_s + "\n Parameters: #{message[:parameters].inspect.to_s},\n Backtrace: " + (message[:error].backtrace || []).join("\n"))
|
||||
else
|
||||
message = (message[:error].to_s + "\n Parameters: #{message[:parameters].inspect.to_s}")
|
||||
end
|
||||
end
|
||||
::GxG::LOG.error(message.to_s)
|
||||
end
|
||||
def log_warn(message = nil, progname = nil, &block)
|
||||
if message.is_a?(::Hash)
|
||||
if message[:warning]
|
||||
message = (message[:warning].to_s + "\n Parameters: #{message[:parameters].inspect.to_s}")
|
||||
else
|
||||
message = (message[:warn].to_s + "\n Parameters: #{message[:parameters].inspect.to_s}")
|
||||
end
|
||||
end
|
||||
::GxG::LOG.warn(message.to_s)
|
||||
end
|
||||
alias :log_warning :log_warn
|
||||
def log_info(message = nil, progname = nil, &block)
|
||||
if message.is_a?(::Hash)
|
||||
message = (message[:info].to_s + "\n Parameters: #{message[:parameters].inspect.to_s}")
|
||||
end
|
||||
::GxG::LOG.info(message.to_s)
|
||||
end
|
||||
def log_debug(message = nil, progname = nil, &block)
|
||||
if message.is_a?(::Hash)
|
||||
if message[:dev] || message[:development]
|
||||
if message[:dev]
|
||||
message = (message[:dev].to_s + "\n Parameters: #{message[:parameters].inspect.to_s}")
|
||||
else
|
||||
message = (message[:development].to_s + "\n Parameters: #{message[:parameters].inspect.to_s}")
|
||||
end
|
||||
else
|
||||
message = (message[:debug].to_s + "\n Parameters: #{message[:parameters].inspect.to_s}")
|
||||
end
|
||||
end
|
||||
::GxG::LOG.debug(message.to_s)
|
||||
end
|
||||
alias :log_dev :log_debug
|
||||
alias :log_development :log_debug
|
||||
#
|
||||
def bytes(*args)
|
||||
GxG::ByteArray::try_convert(args)
|
||||
end
|
||||
#
|
||||
def new_message(*args)
|
||||
if this.actor?()
|
||||
::GxG::Events::Message.new({:sender => this().to_uri(), :subject => args[1], :body => args[0]})
|
||||
else
|
||||
::GxG::Events::Message.new({:sender => this(), :subject => args[1], :body => args[0]})
|
||||
end
|
||||
end
|
||||
#
|
||||
public
|
||||
#
|
||||
def millisecond_latency(*args,&block)
|
||||
if block
|
||||
starting = Time.now.to_f
|
||||
result = block.call(*args)
|
||||
ending = Time.now.to_f
|
||||
# Results are approximate: does not include the time ruby needs to return from the call,
|
||||
# assign the result RVALUE, collect a time, convert it to a Float, and assign ending RVALUE..
|
||||
# However, it is pretty darn close.
|
||||
{:result => result, :milliseconds => (ending - starting)}
|
||||
else
|
||||
# If :milliseconds are nil then the block was not passed and since it never ran, there is no latency to count up.
|
||||
# Simply do a return_var[:milliseconds].to_f for auto-accumulators w/o post-call comparison.
|
||||
{:result => nil, :milliseconds => 0.0}
|
||||
end
|
||||
# Attribution : http://stackoverflow.com/questions/2289381/how-to-time-an-operation-in-milliseconds-in-ruby
|
||||
end
|
||||
end
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
require File.expand_path("./gxg/gxg_augmented.rb",File.dirname(__FILE__))
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
require File.expand_path("./gxg/gxg_entities.rb",File.dirname(__FILE__))
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
require 'jruby'
|
||||
JRuby.objectspace = true
|
||||
require File.expand_path("./gxg/gxg_engine.rb",File.dirname(__FILE__))
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
# Alterations to Object class: GxG::Engine dependency - quota supports
|
||||
class Object
|
||||
public
|
||||
#
|
||||
def heap_used(options={})
|
||||
unless options.is_a?(Hash)
|
||||
options={}
|
||||
end
|
||||
(self.content_size_used(options).to_i + (self.slots_used(options).to_i * GxG::Engine::profile[:slot_size]).to_i)
|
||||
end
|
||||
#
|
||||
end
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
require File.expand_path("./gxg/gxg_transcode.rb",File.dirname(__FILE__))
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
if GxG::SYSTEM.platform[:platform] == :windows
|
||||
# Fixes an issue where IO::SYNC and File::SYNC are not defined on Windows.
|
||||
class IO
|
||||
SYNC = DSYNC
|
||||
end
|
||||
class File
|
||||
SYNC = DSYNC
|
||||
end
|
||||
end
|
||||
require File.expand_path("./gxg/gxg_io.rb",File.dirname(__FILE__))
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
require File.expand_path("./gxg/gxg_net.rb",File.dirname(__FILE__))
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
# FIX : big hassle with windows - exclude for now
|
||||
# require File.expand_path("./gxg/gxg_zmq.rb",File.dirname(__FILE__))
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
# Set GxG Version and instantiate GxG::SYSTEM object:
|
||||
module GxG
|
||||
# setup constants, dispose of BOOTSTRAP data.
|
||||
VERSION = GxG::Version.new({:phase => :alpha, :revision => 50})
|
||||
VERSION.freeze
|
||||
#
|
||||
def self.shutdown()
|
||||
[::GxG::Networking::SshClient, ::GxG::Networking::ImapClient, ::GxG::Networking::RestClient, ::GxG::Networking::SoapClient, ::GxG::Networking::SmtpClient, ::GxG::Networking::XmlrpcClient, ::GxG::Networking::SftpClient, ::GxG::Networking::Pop3Client, ::GxG::Networking::HttpsClient, ::GxG::Networking::HttpClient, ::GxG::Networking::MatrixClient, ::GxG::Networking::FtpClient].each do |the_class|
|
||||
::GxG::Engine::instance_process(the_class) do |the_object|
|
||||
if the_object.respond_to?(:logout)
|
||||
the_object.logout()
|
||||
end
|
||||
end
|
||||
end
|
||||
$Dispatcher.shutdown()
|
||||
# FOR NOW : ZMQ is excluded awaiting dep fix.
|
||||
# ::GxG::Networking::ZMQ::zmq_default_context.terminate()
|
||||
end
|
||||
end
|
||||
# First attempt at object serialization/reconstitution:
|
||||
module GxG
|
||||
def self.reconstitute(raw_data="")
|
||||
# See: http://stackoverflow.com/questions/5758464/ruby-how-do-i-check-if-a-class-is-defined
|
||||
#
|
||||
if raw_data.is_a?(::String)
|
||||
if raw_data.serialized?()
|
||||
result = nil
|
||||
if raw_data.include?("marshal:")
|
||||
begin
|
||||
result = ::Marshal.load(raw_data[(8..-1)].decode64())
|
||||
rescue Exception
|
||||
# Question : what to do here.
|
||||
end
|
||||
else
|
||||
if raw_data.include?("structure:")
|
||||
data = ::Marshal.load(raw_data[(10..-1)].decode64())
|
||||
if data.is_any?(::Array, ::Hash, ::Set, ::Struct)
|
||||
result = data.process do |entry, selector|
|
||||
if entry.is_a?(::String)
|
||||
if entry.serialized?()
|
||||
::GxG::reconstitute(entry)
|
||||
# entry.unserialize()
|
||||
else
|
||||
entry
|
||||
end
|
||||
else
|
||||
entry
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
raise Exception, "unrecognized serialization format"
|
||||
end
|
||||
end
|
||||
else
|
||||
result = raw_data
|
||||
end
|
||||
else
|
||||
result = raw_data
|
||||
end
|
||||
result
|
||||
#
|
||||
end
|
||||
#
|
||||
# Generic toolbox of methods
|
||||
def self.passes_needed(size_used=0, container_limit=0)
|
||||
if size_used > 0 and container_limit > 0
|
||||
needed_raw = size_used.to_f / container_limit.to_f
|
||||
overhang = needed_raw - needed_raw.to_i.to_f
|
||||
needed_raw = needed_raw.to_i.to_f
|
||||
if overhang > 0.0
|
||||
needed_raw += 1.0
|
||||
end
|
||||
needed_raw.to_i
|
||||
else
|
||||
0
|
||||
end
|
||||
end
|
||||
#
|
||||
def self.apportioned_ranges(how_much_data=0, container_limit=0, original_offset=0)
|
||||
result = []
|
||||
the_count = ::GxG::passes_needed(how_much_data, container_limit)
|
||||
if the_count > 0
|
||||
offset = original_offset
|
||||
the_count.times do
|
||||
if (offset + (container_limit - 1)) <= (how_much_data - 1)
|
||||
end_point = (offset + (container_limit - 1))
|
||||
else
|
||||
end_point = (how_much_data - 1)
|
||||
end
|
||||
result << ((offset)..(end_point))
|
||||
offset = (end_point + 1)
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def self.valid_uuid?(uuid=nil,strict=true)
|
||||
if uuid.is_any?(::String, ::Symbol)
|
||||
if strict == true
|
||||
pattern = /[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[4][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]/
|
||||
else
|
||||
pattern = /[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f]-[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]/
|
||||
end
|
||||
if uuid.to_s.match(pattern)
|
||||
if uuid.to_s.size == 36
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
else
|
||||
false
|
||||
end
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
#
|
||||
def self.sql_statement?(the_string)
|
||||
# See: https://larrysteinle.com/2011/02/20/use-regular-expressions-to-detect-sql-code-injection/
|
||||
if /('(''|[^'])*')|(;)|(\\x08(ALTER|CREATE|DELETE|DROP|EXEC(UTE){0,1}|INSERT( +INTO){0,1}|MERGE|SELECT|UPDATE|UNION( +ALL){0,1})\\x08)/.match(the_string)
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
#
|
||||
def self.valid_domain_name?(the_string)
|
||||
if /^[a-zA-Z0-9][a-zA-Z0-9-]{1,61}[a-zA-Z0-9]\.[a-zA-Z]{2,}$/.match(the_string)
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
#
|
||||
def self.status()
|
||||
result = nil
|
||||
# Review : do some planning on tasks --> how does that impact status object cloning??
|
||||
$ThreadSafety.synchronize { result = $Status.clone }
|
||||
result
|
||||
end
|
||||
#
|
||||
def self.set_mode(the_mode=nil)
|
||||
if the_mode
|
||||
$ThreadSafety.synchronize { $Status[:mode] = the_mode.to_s.to_sym }
|
||||
end
|
||||
end
|
||||
#
|
||||
end
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
require File.expand_path("./gxg/gxg_database.rb",File.dirname(__FILE__))
|
||||
require File.expand_path("./gxg/gxg_dbfs.rb",File.dirname(__FILE__))
|
||||
require File.expand_path("./gxg/net_clients.rb",File.dirname(__FILE__))
|
||||
# Database record retrieval methods:
|
||||
class Object
|
||||
# private methods
|
||||
private
|
||||
#
|
||||
def fetch(reference=nil)
|
||||
result = nil
|
||||
#
|
||||
if ::GxG::valid_uuid?(reference)
|
||||
record = ::GxG::DB[:roles][:data].retrieve_by_uuid(reference, ::GxG::DB[:administrator])
|
||||
if record
|
||||
result = record
|
||||
end
|
||||
else
|
||||
if reference.to_s.valid_path?
|
||||
result = ::GxG::VFS.open(reference)
|
||||
else
|
||||
criteria = {}
|
||||
if reference.is_a?(::Hash)
|
||||
criteria = reference
|
||||
else
|
||||
criteria[:title] = reference.to_s
|
||||
end
|
||||
list = []
|
||||
::GxG::DB[:roles].keys.each do |db_role|
|
||||
list << ::GxG::DB[:roles][(db_role)].search_database(::GxG::DB[:administrator], criteria)
|
||||
end
|
||||
list = list.flatten!
|
||||
if list[0].is_a?(::Hash)
|
||||
result = ::GxG::DB[:roles][:data].retrieve_by_uuid(list[0][:uuid], ::GxG::DB[:administrator])
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
result
|
||||
end
|
||||
#
|
||||
def fetch_structure(reference=nil)
|
||||
record = fetch(reference)
|
||||
if record
|
||||
record.as_structure
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
#
|
||||
def fetch_detached(reference=nil)
|
||||
record = nil
|
||||
if ::GxG::valid_uuid?(reference)
|
||||
if ::GxG::DB_SAFETY.synchronize { ::GxG::DB[:cache][(reference.to_s.to_sym)].is_any?(::GxG::Database::DetachedArray, ::GxG::Database::DetachedHash) }
|
||||
record = ::GxG::DB_SAFETY.synchronize { ::GxG::DB[:cache][(reference.to_s.to_sym)] }
|
||||
end
|
||||
else
|
||||
found = nil
|
||||
::GxG::DB_SAFETY.synchronize {
|
||||
::GxG::DB[:cache].values.each do |the_record|
|
||||
if the_record.title == reference
|
||||
found = the_record.uuid
|
||||
break
|
||||
end
|
||||
end
|
||||
}
|
||||
if found
|
||||
record = ::GxG::DB_SAFETY.synchronize { ::GxG::DB[:cache][(found)] }
|
||||
end
|
||||
end
|
||||
unless record.is_any?(::GxG::Database::DetachedArray, ::GxG::Database::DetachedHash)
|
||||
record = fetch(reference)
|
||||
if record.is_any?(::GxG::Database::PersistedArray, ::GxG::Database::PersistedHash)
|
||||
record = record.detach
|
||||
::GxG::DB_SAFETY.synchronize { ::GxG::DB[:cache][(record.uuid)] = record }
|
||||
else
|
||||
record = nil
|
||||
end
|
||||
end
|
||||
record
|
||||
end
|
||||
#
|
||||
def new_structure(credential=nil, ufs_criteria=nil, the_role=:data)
|
||||
result = nil
|
||||
if ::GxG::valud_uuid?(credential)
|
||||
unless ufs_criteria.is_a?(::Hash)
|
||||
ufs_criteria = nil
|
||||
end
|
||||
unless the_role.is_a?(::Symbol)
|
||||
the_role = :data
|
||||
end
|
||||
the_database = nil
|
||||
if ::GxG::DB[:roles][(the_role)]
|
||||
the_database = ::GxG::DB[:roles][(the_role)]
|
||||
end
|
||||
if the_database.is_a?(::GxG::Database::Database)
|
||||
if ufs_criteria
|
||||
result = the_database.new_structure_from_format(credential, ufs_criteria)
|
||||
else
|
||||
result = the_database.try_persist({}, credential)
|
||||
end
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
end
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
require File.expand_path("./gxg/net_tools.rb",File.dirname(__FILE__))
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
require File.expand_path("./gxg/gxg_communications.rb",File.dirname(__FILE__))
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
# Register Database as supported protocol classes
|
||||
::GxG::CLIENTS.register_client("sqlite", ::GxG::Database::Database)
|
||||
::GxG::CLIENTS.register_client("mysql", ::GxG::Database::Database)
|
||||
# ### Define runtime constants
|
||||
module GxG
|
||||
DOCUMENTS = {}
|
||||
end
|
||||
#
|
||||
$ThreadSafety = ::Mutex.new
|
||||
$Status = {:mode => :loading, :tasks => :undefined, :load => nil}
|
||||
$Dispatcher = ::GxG::Events::EventDispatcher.new(0.333)
|
||||
$Dispatcher.startup
|
||||
$Dispatcher.every("5 seconds") do
|
||||
load = GxG::Engine.determine_loads
|
||||
$ThreadSafety.synchronize { $Status[:load] = load }
|
||||
end
|
||||
::GxG::LOG[:default] = ::Logger.new(STDOUT)
|
||||
::GxG::LOG[:default].level = ::Logger::ERROR
|
||||
$Dispatcher.every("0.333 seconds") do
|
||||
::GxG::LOG.process_messages()
|
||||
end
|
||||
# ### Defer long-runnign cpu info gather on Winderz
|
||||
if ::GxG::SYSTEM.platform[:platform] == :windows
|
||||
$Dispatcher.post_event(:root) do
|
||||
gxg_template = {
|
||||
:processor=>0,
|
||||
:vendor_id=>"",
|
||||
:cpu_family=> -1,
|
||||
:model=> -1,
|
||||
:model_name=>"",
|
||||
:stepping=> -1,
|
||||
:microcode=>"",
|
||||
:cpu_mhz=>0.0,
|
||||
:cache_size=>0,
|
||||
:physical_id=> -1,
|
||||
:siblings=> -1,
|
||||
:core_id=> -1,
|
||||
:cpu_cores=> 0,
|
||||
:apicid=> -1,
|
||||
:initial_apicid=>0,
|
||||
:fpu=>false,
|
||||
:fpu_exception=>false,
|
||||
:cpuid_level=> -1,
|
||||
:wp=>false,
|
||||
:flags=>[],
|
||||
:bugs=>"",
|
||||
:bogomips=> 0.0,
|
||||
:tlb_size=>"",
|
||||
:clflush_size=> -1,
|
||||
:cache_alignment=> -1,
|
||||
:address_sizes=>{
|
||||
:physical_bits=> -1,
|
||||
:virtual_bits=> -1
|
||||
},
|
||||
:power_management=>""
|
||||
}
|
||||
#
|
||||
local_mapping = {
|
||||
:AddressWidth=>"64",
|
||||
:Architecture=>"9 ",
|
||||
:AssetTag=>"",
|
||||
:Availability=>"3 ",
|
||||
:Caption=>"AMD64 Family 21 Model 2 Stepping 0",
|
||||
:Characteristics=>" ",
|
||||
:ConfigManagerErrorCode=>"",
|
||||
:ConfigManagerUserConfig=>" ",
|
||||
:CpuStatus=>"0",
|
||||
:CreationClassName=>"Win32_Processor",
|
||||
:CurrentClockSpeed=>:cpu_mhz,
|
||||
:CurrentVoltage=>"",
|
||||
:DataWidth=>"64 ",
|
||||
:Description=>"AMD64 Family 21 Model 2 Stepping 0",
|
||||
:DeviceID=>"CPU0",
|
||||
:ErrorCleared=>"",
|
||||
:ErrorDescription=>"",
|
||||
:ExtClock=>"",
|
||||
:Family=>:cpu_family,
|
||||
:InstallDate=>" ",
|
||||
:L2CacheSize=>" ",
|
||||
:L2CacheSpeed=>"",
|
||||
:L3CacheSize=>:cache_size,
|
||||
:L3CacheSpeed=>"0 ",
|
||||
:LastErrorCode=>" ",
|
||||
:Level=>:cpuid_level,
|
||||
:LoadPercentage=>"6 ",
|
||||
:Manufacturer=>:vendor_id,
|
||||
:MaxClockSpeed=>"4013 ",
|
||||
:Name=>:model_name,
|
||||
:NumberOfCores=>:cpu_cores,
|
||||
:NumberOfEnabledCore=>" ",
|
||||
:NumberOfLogicalProcessors=>"4",
|
||||
:OtherFamilyDescription=>"",
|
||||
:PartNumber=>"",
|
||||
:PNPDeviceID=>" ",
|
||||
:PowerManagementCapabilities=>" ",
|
||||
:PowerManagementSupported=>"FALSE ",
|
||||
:ProcessorId=>:physical_id,
|
||||
:ProcessorType=>" ",
|
||||
:Revision=>"512 ",
|
||||
:Role=>"CPU ",
|
||||
:SecondLevelAddressTranslationExtensions=>"FALSE",
|
||||
:SerialNumber=>"",
|
||||
:SocketDesignation=>" ",
|
||||
:Status=>"OK",
|
||||
:StatusInfo=>"3 ",
|
||||
:Stepping=>:stepping,
|
||||
:SystemCreationClassName=>"Win32_ComputerSystem ",
|
||||
:SystemName=>"DESKTOP-D87M3K5",
|
||||
:ThreadCount=>" ",
|
||||
:UniqueId=>"",
|
||||
:UpgradeMethod=>:model,
|
||||
:Version=>"Model 2, Stepping 0",
|
||||
:VirtualizationFirmwareEnabled=>"TRUE ",
|
||||
:VMMonitorModeExtensions=>"FALSE",
|
||||
:VoltageCaps=>" "
|
||||
}
|
||||
headers = ["AddressWidth", "Architecture", "AssetTag", "Availability", "Caption", "Characteristics", "ConfigManagerErrorCode", "ConfigManagerUserConfig", "CpuStatus", "CreationClassName", "CurrentClockSpeed", "CurrentVoltage", "DataWidth", "Description", "DeviceID", "ErrorCleared", "ErrorDescription", "ExtClock", "Family", "InstallDate", "L2CacheSize", "L2CacheSpeed", "L3CacheSize", "L3CacheSpeed", "LastErrorCode", "Level", "LoadPercentage", "Manufacturer", "MaxClockSpeed", "Name", "NumberOfCores", "NumberOfEnabledCore", "NumberOfLogicalProcessors", "OtherFamilyDescription", "PartNumber", "PNPDeviceID", "PowerManagementCapabilities", "PowerManagementSupported", "ProcessorId", "ProcessorType", "Revision", "Role", "SecondLevelAddressTranslationExtensions", "SerialNumber", "SocketDesignation", "Status", "StatusInfo", "Stepping", "SystemCreationClassName", "SystemName", "ThreadCount", "UniqueId", "UpgradeMethod", "Version", "VirtualizationFirmwareEnabled", "VMMonitorModeExtensions", "VoltageCaps"]
|
||||
local_data = {}
|
||||
headers.each do |the_header|
|
||||
raw_data = `wmic cpu get #{the_header}`.split("\r\n")
|
||||
data = raw_data[1].gsub(" ","")
|
||||
#
|
||||
if ["AddressWidth", "Architecture", "Availability", "CpuStatus","CurrentClockSpeed","DataWidth","Family","L2CacheSize","L2CacheSpeed","L3CacheSize","L3CacheSpeed","Level","LoadPercentage","MaxClockSpeed","NumberOfCores","NumberOfEnabledCore","NumberOfLogicalProcessors","StatusInfo","Stepping","ThreadCount","UpgradeMethod"].include?(the_header)
|
||||
if data.to_s.size > 0 && data.to_s != " "
|
||||
data = data.to_i
|
||||
else
|
||||
data = 0
|
||||
end
|
||||
end
|
||||
if ["PowerManagementSupported","SecondLevelAddressTranslationExtensions","VirtualizationFirmwareEnabled","VMMonitorModeExtensions"].include?(the_header)
|
||||
if data.to_s.size > 0 && (data.to_s.include?("TRUE") || data.to_s.include?("true"))
|
||||
data = true
|
||||
else
|
||||
data = false
|
||||
end
|
||||
end
|
||||
if ["CurrentVoltage","VoltageCaps"].include?(the_header)
|
||||
if data.to_s.size > 0 && data.to_s != " "
|
||||
data = data.to_f
|
||||
else
|
||||
data = 0.0
|
||||
end
|
||||
end
|
||||
#
|
||||
local_data[(raw_data[0].gsub(" ","").to_sym)] = data
|
||||
end
|
||||
local_data[:NumberOfLogicalProcessors].times do |the_cpu_selector|
|
||||
cpu_record = gxg_template.clone
|
||||
cpu_record[:processor] = the_cpu_selector
|
||||
local_mapping.keys.each do |the_key|
|
||||
if local_mapping[(the_key)].is_a?(::Symbol)
|
||||
cpu_record[(local_mapping[(the_key)])] = local_data[(the_key)]
|
||||
end
|
||||
if the_key == :AddressWidth
|
||||
cpu_record[:address_sizes][:physical_bits] = local_data[:AddressWidth]
|
||||
cpu_record[:address_sizes][:virtual_bits] = local_data[:AddressWidth]
|
||||
end
|
||||
end
|
||||
::GxG::SYSTEM.gxg_cpu_add(cpu_record)
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
::GxG::set_mode(:running)
|
||||
#
|
||||
end
|
||||
#
|
||||
394
lib/gxg/bootstrap.rb
Normal file
394
lib/gxg/bootstrap.rb
Normal file
|
|
@ -0,0 +1,394 @@
|
|||
#!/usr/bin/env ruby
|
||||
require "rubygems"
|
||||
# determine the arch, platform with version, and ruby implementation with version
|
||||
# store this in GxG::BOOTSTRAP
|
||||
module GxG
|
||||
if $GXGROOT
|
||||
details = {:gxg_root => $GXGROOT}
|
||||
else
|
||||
details = {}
|
||||
end
|
||||
details[:architecture] = RUBY_PLATFORM.split("-")[0].downcase
|
||||
details[:platform_version] = {}
|
||||
# ### determine platform and environment details
|
||||
if RUBY_PLATFORM == "java" || RUBY_PLATFORM == "java_64"
|
||||
platform = nil
|
||||
#
|
||||
unless platform
|
||||
raw_data = `uname -a`.downcase
|
||||
# Attempt to determine the distro and version
|
||||
[:freebsd, :openbsd, :netbsd, :dragonfly, :pcbsd].to_enum.each do |entry|
|
||||
if raw_data.include?(entry.to_s)
|
||||
platform = "bsd"
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
unless platform
|
||||
if `uname -a`.downcase.include?("darwin")
|
||||
platform = "darwin"
|
||||
end
|
||||
end
|
||||
#
|
||||
unless platform
|
||||
if `uname -a`.downcase.include?("aix")
|
||||
platform = "aix"
|
||||
end
|
||||
end
|
||||
#
|
||||
unless platform
|
||||
if `uname -a`.downcase.include?("solaris")
|
||||
platform = "solaris"
|
||||
end
|
||||
end
|
||||
#
|
||||
unless platform
|
||||
raw_data = `uname -a`.downcase
|
||||
# Attempt to determine the distro and version
|
||||
[:debian, :redhat, :gentoo, :ubuntu, :linuxmint, :angstrom, :gobolinux, :caldera,
|
||||
:suse, :mandrake, :fedora, :slackware, :united, :yellowdog, :sun, :puppy, :linux].to_enum.each do |entry|
|
||||
if raw_data.include?(entry.to_s)
|
||||
platform = "linux"
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
unless platform
|
||||
raw_data = `ver`.to_s.gsub!("[","").to_s.gsub!("]","").to_s.split(" ")
|
||||
if raw_data.include?("Windows")
|
||||
if ([ -1 ].pack('l!').length == 8)
|
||||
platform = "mswin64"
|
||||
else
|
||||
platform = "mswin32"
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
unless platform
|
||||
platform = "unknown"
|
||||
end
|
||||
#
|
||||
else
|
||||
#
|
||||
unless platform
|
||||
raw_data = `uname -a`.downcase
|
||||
# Attempt to determine the distro and version
|
||||
[:debian, :redhat, :gentoo, :ubuntu, :linuxmint, :angstrom, :gobolinux, :caldera,
|
||||
:suse, :mandrake, :fedora, :slackware, :united, :yellowdog, :sun, :puppy, :linux].to_enum.each do |entry|
|
||||
if raw_data.include?(entry.to_s)
|
||||
platform = "linux"
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
unless platform
|
||||
if RUBY_PLATFORM.split("-")[1] == "unknown"
|
||||
platform = RUBY_PLATFORM.split("-")[2]
|
||||
else
|
||||
if RUBY_ENGINE = "rbx"
|
||||
platform = RUBY_PLATFORM.split("-")[2]
|
||||
else
|
||||
platform = RUBY_PLATFORM.split("-")[1]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
case platform
|
||||
# SOMEDAY: look into the legal aspects of solutions published in the public space.
|
||||
# Attribution: http://www.unix.com/slackware/23652-determine-linux-version.html
|
||||
# and: http://www.novell.com/coolsolutions/feature/11251.html
|
||||
when /mswin32/
|
||||
details[:platform] = :windows
|
||||
details[:environment] = :mswin32
|
||||
details[:environment_variant] = :standard
|
||||
details[:environment_version] = nil
|
||||
when /mswin64/
|
||||
details[:platform] = :windows
|
||||
details[:environment] = :mswin64
|
||||
details[:environment_variant] = :standard
|
||||
details[:environment_version] = nil
|
||||
when /mingw32/
|
||||
details[:platform] = :windows
|
||||
details[:environment] = :mingw32
|
||||
details[:environment_variant] = :standard
|
||||
details[:environment_version] = nil
|
||||
when /bccwin32/
|
||||
details[:platform] = :windows
|
||||
details[:environment] = :bccwin32
|
||||
details[:environment_variant] = :standard
|
||||
details[:environment_version] = nil
|
||||
when /cygwin/
|
||||
details[:platform] = :windows
|
||||
# TODO: find out how deep cygwin goes (looks like a linux kernel??)
|
||||
# using the kernel version as the platform version
|
||||
details[:platform_version] = {:interpret => `uname -r`}
|
||||
details[:environment] = :cygwin
|
||||
details[:environment_variant] = :standard
|
||||
details[:environment_version] = nil
|
||||
when /solaris|sunos/
|
||||
details[:platform] = :solaris
|
||||
details[:environment] = :solaris
|
||||
details[:environment_variant] = :standard
|
||||
details[:environment_version] = nil
|
||||
raw_text = `more /etc/release`
|
||||
unless raw_text.downcase.include?("no such file")
|
||||
details[:environment_version] = {:interpret => raw_text}
|
||||
end
|
||||
when /bsd/, /dragonfly/
|
||||
details[:platform] = :bsd
|
||||
# using the kernel version as the platform version
|
||||
details[:platform_version] = {:interpret => `uname -r`}
|
||||
details[:environment] = :bsd
|
||||
temp_env = `uname -a`.downcase
|
||||
# Attempt to determine the distro and version
|
||||
[:freebsd, :openbsd, :netbsd, :dragonfly, :pcbsd].to_enum.each do |entry|
|
||||
if temp_env.include?(entry.to_s)
|
||||
details[:environment] = entry
|
||||
break
|
||||
end
|
||||
end
|
||||
details[:environment_variant] = :standard
|
||||
details[:environment_version] = nil
|
||||
when /darwin|mac os|macos/
|
||||
details[:platform] = :darwin
|
||||
# using the kernel version as the platform version
|
||||
details[:platform_version] = {:interpret => `uname -r`}
|
||||
if (::File.exists?("/System") && ::File.exists?("/Library") && ::File.exists?("/Volumes") && ::File.exists?("/Users"))
|
||||
details[:environment] = :macos
|
||||
else
|
||||
details[:environment] = :darwin
|
||||
end
|
||||
details[:environment_variant] = :standard
|
||||
details[:environment_version] = nil
|
||||
when /linux/
|
||||
# ###
|
||||
details[:platform] = :linux
|
||||
# using the kernel version as the platform version
|
||||
details[:platform_version] = {:interpret => `uname -r`}
|
||||
details[:environment] = :linux
|
||||
temp_env = `uname -a`.downcase
|
||||
# Attempt to determine the distro and version
|
||||
[:debian, :redhat, :gentoo, :ubuntu, :linuxmint, :angstrom, :gobolinux, :caldera,
|
||||
:suse, :mandrake, :fedora, :slackware, :united, :yellowdog, :sun, :puppy].to_enum.each do |entry|
|
||||
if temp_env.include?(entry.to_s)
|
||||
details[:environment] = entry
|
||||
break
|
||||
end
|
||||
end
|
||||
details[:environment_variant] = :standard
|
||||
details[:environment_version] = nil
|
||||
raw_text = ""
|
||||
raw_version = {}
|
||||
case details[:environment]
|
||||
when :debian
|
||||
raw_text = `more /etc/debian_version`
|
||||
if raw_text.downcase.include?("no such file")
|
||||
raw_text = `more /etc/debian_release`
|
||||
end
|
||||
when :ubuntu
|
||||
raw_text = `more /etc/lsb-release | grep 'DISTRIB_RELEASE' | sed -e 's#[^0-9.]##g'`
|
||||
# LATER: @determine :environment_variant : attempt to determine if :desktop or :server or :what?
|
||||
# unless raw_text.downcase.include?("no such file")
|
||||
# temp_text = `more /etc/lsb-release | grep 'DISTRIB_CODENAME' | sed -e 's#[^a-zA-Z=]##g'`.split("=")[1]
|
||||
# details[:environment_variant] = temp_text.downcase.to_sym
|
||||
#end
|
||||
when :suse
|
||||
raw_text = `more /etc/SuSE-version | grep 'VERSION' | sed -e 's#[^0-9.]##g'`
|
||||
if raw_text.downcase.include?("no such file")
|
||||
raw_text = `more /etc/SUSE-version | grep 'VERSION' | sed -e 's#[^0-9.]##g'`
|
||||
end
|
||||
when :united
|
||||
raw_text = `more /etc/UnitedLinux-release`
|
||||
when :slackware
|
||||
raw_text = `more /etc/slackware-release`
|
||||
if raw_text.downcase.include?("no such file")
|
||||
raw_text = `more /etc/slackware-version`
|
||||
end
|
||||
when :redhat
|
||||
the_file = "redhat-release"
|
||||
temp_text = `more /etc/#{the_file}`
|
||||
if temp_text.downcase.include?("no such file")
|
||||
the_file = "redhat_version"
|
||||
temp_text = `more /etc/#{the_file}`
|
||||
end
|
||||
unless temp_text.downcase.include?("no such file")
|
||||
if temp_text.downcase.include?("scientific")
|
||||
details[:environment_variant] = :scientific
|
||||
raw_text = `more /etc/#{the_file} | sed -e 's#[^0-9.]##g' | cut -c1`
|
||||
else
|
||||
if temp_text.downcase.include?("enterprise")
|
||||
details[:environment_variant] = :enterprise
|
||||
else
|
||||
if temp_text.downcase.include?("cern")
|
||||
details[:environment_variant] = :cern
|
||||
end
|
||||
end
|
||||
raw_text = `more /etc/#{the_file} | sed -e 's#[^0-9.]##g' -e 's#7[0-2.]#73.#'`
|
||||
end
|
||||
end
|
||||
#
|
||||
else
|
||||
raw_text = `more /etc/#{details[:environment].to_s}-release`
|
||||
end
|
||||
#
|
||||
if (raw_text.downcase.include?("no such file") && raw_text.size == 0)
|
||||
if raw_version.keys.size > 0
|
||||
details[:environment_version] = raw_version
|
||||
end
|
||||
else
|
||||
details[:environment_version] = {:interpret => raw_text}.merge(raw_version)
|
||||
end
|
||||
#
|
||||
when /aix/
|
||||
details[:platform] = :aix
|
||||
details[:environment] = :aix
|
||||
details[:environment_variant] = :standard
|
||||
details[:environment_version] = nil
|
||||
else
|
||||
# unknown (unsupported) platform
|
||||
details[:platform] = RUBY_PLATFORM.split("-")[1].to_s.downcase.to_sym
|
||||
details[:environment] = details[:platform]
|
||||
details[:environment_variant] = :standard
|
||||
details[:environment_version] = nil
|
||||
end
|
||||
# Arch detail determination: Special thanks to Jari Bakken (Jarib) at https://github.com/jarib/childprocess/blob/master/lib/childprocess.rb
|
||||
if details[:architecture] == "java"
|
||||
# TODO: get arch via other means
|
||||
case details[:platform]
|
||||
when :windows
|
||||
if ([ -1 ].pack('l!').length == 8)
|
||||
details[:architecture] = "x86_64"
|
||||
else
|
||||
details[:architecture] = "i686"
|
||||
end
|
||||
when :linux, :bsd, :darwin, :aix, :solaris
|
||||
raw_data = `uname -a`.downcase
|
||||
[:i686, :i586, :i486, :i386, :amd64, :x86_64, :ppc, :powerpc, :arm, :mips].to_enum(:each).each do |the_arch|
|
||||
if raw_data.include?(the_arch.to_s)
|
||||
details[:architecture] = the_arch.to_s
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
case details[:architecture]
|
||||
when /i[3456]86/
|
||||
if (details[:platform] == :darwin && ([ -1 ].pack('l!').length == 8))
|
||||
details[:architecture] = :x86_64
|
||||
else
|
||||
# details[:architecture] = :i386
|
||||
# Jarib's solution does not help folks deal with the differences between the 32bit arch flavors. I'll be more specific
|
||||
details[:architecture] = details[:architecture].to_sym
|
||||
end
|
||||
when /amd64|x86_64/
|
||||
details[:architecture] = :x86_64
|
||||
when /ppc|powerpc/
|
||||
if [ -1 ].pack('l!').length == 8
|
||||
details[:architecture] = :powerpc_64
|
||||
else
|
||||
details[:architecture] = :powerpc
|
||||
end
|
||||
else
|
||||
if [ -1 ].pack('l!').length == 8
|
||||
details[:architecture] = (details[:architecture] + "_64").to_sym
|
||||
else
|
||||
details[:architecture] = details[:architecture].to_sym
|
||||
end
|
||||
end
|
||||
#
|
||||
# ### propose private gem and library paths for standalone support:
|
||||
details[:common_gems] = "common"
|
||||
details[:native_gems] = "#{details[:architecture].to_s}-#{details[:platform].to_s}-#{RUBY_ENGINE.to_s.downcase}-#{RUBY_VERSION.to_s.downcase}"
|
||||
details[:native_libraries] = details[:native_gems]
|
||||
# ### Gather CPU data by platform
|
||||
# I would really prefer that ALL architectures use the *same* detail format for profiling a given CPU.
|
||||
details[:processors] = []
|
||||
case details[:platform]
|
||||
when :windows
|
||||
# Review : working with wmic on windows takes Sooooo long that I had to put this block in a thread at startup. (not pretty but it works)
|
||||
# Review : waiting upon a bug fix for JRUBY under Windows --> Null pointer exception thrown.
|
||||
# Review : See - https://github.com/jruby/jruby/issues/6440
|
||||
# Sys::CPU.processors()
|
||||
when :bsd
|
||||
gxg_template = {
|
||||
:processor=>0,
|
||||
:vendor_id=>"",
|
||||
:cpu_family=> -1,
|
||||
:model=> -1,
|
||||
:model_name=>"",
|
||||
:stepping=> -1,
|
||||
:microcode=>"",
|
||||
:cpu_mhz=>0.0,
|
||||
:cache_size=>0,
|
||||
:physical_id=> -1,
|
||||
:siblings=> -1,
|
||||
:core_id=> -1,
|
||||
:cpu_cores=> 0,
|
||||
:apicid=> -1,
|
||||
:initial_apicid=>0,
|
||||
:fpu=>false,
|
||||
:fpu_exception=>false,
|
||||
:cpuid_level=> -1,
|
||||
:wp=>false,
|
||||
:flags=>[],
|
||||
:bugs=>"",
|
||||
:bogomips=> 0.0,
|
||||
:tlb_size=>"",
|
||||
:clflush_size=> -1,
|
||||
:cache_alignment=> -1,
|
||||
:address_sizes=>{
|
||||
:physical_bits=> -1,
|
||||
:virtual_bits=> -1
|
||||
},
|
||||
:power_management=>""
|
||||
}
|
||||
#
|
||||
when :linux
|
||||
# for now: work around for unworkable Struct behavioral variation in Sys::CPU :P
|
||||
# Gather CPU(n) data
|
||||
cpu_entry = {}
|
||||
lastcpu = 0
|
||||
parse_cpu_info = Proc.new do |raw_line|
|
||||
line = raw_line.split(":")
|
||||
if line[0].to_s.size > 1
|
||||
key = line[0].to_s.downcase.strip.gsub(/\s+/,"_")
|
||||
value = line[1].to_s.strip
|
||||
#
|
||||
if value.to_s.size > 0
|
||||
if value.to_s.include?("yes")
|
||||
value = true
|
||||
end
|
||||
if value.to_s.include?("no")
|
||||
value = false
|
||||
end
|
||||
#
|
||||
else
|
||||
value = nil
|
||||
end
|
||||
cpu_entry[(key)] = value
|
||||
else
|
||||
if cpu_entry.keys.size > 0
|
||||
details[:processors] << cpu_entry
|
||||
cpu_entry = {}
|
||||
end
|
||||
next
|
||||
end
|
||||
#
|
||||
end
|
||||
::IO::foreach("/proc/cpuinfo").each {|line| parse_cpu_info.call(line)}
|
||||
if cpu_entry.keys.size > 0
|
||||
details[:processors] << cpu_entry
|
||||
end
|
||||
#
|
||||
end
|
||||
# cleanup
|
||||
#
|
||||
# return final result
|
||||
BOOTSTRAP=details
|
||||
# for testing innards
|
||||
# puts details.inspect()
|
||||
end
|
||||
# reset rubygems paths if in stand-alone mode
|
||||
4366
lib/gxg/gxg_augmented.rb
Normal file
4366
lib/gxg/gxg_augmented.rb
Normal file
File diff suppressed because it is too large
Load diff
964
lib/gxg/gxg_communications.rb
Normal file
964
lib/gxg/gxg_communications.rb
Normal file
|
|
@ -0,0 +1,964 @@
|
|||
# ### GxG Communications Layer
|
||||
# Note: MatrixClient --> 64K max message size (gross), less than 1K overhead --> so, 63K max payload size (64512 bytes).
|
||||
module GxG
|
||||
BRIDGES = {}
|
||||
BRIDGES_AVAILABLE = {}
|
||||
module Communications
|
||||
BRIDGE_THREAD_SAFETY = ::Mutex.new
|
||||
def self.bridge(the_uuid)
|
||||
if ::GxG::valid_uuid?(the_uuid)
|
||||
BRIDGE_THREAD_SAFETY.synchronize { ::GxG::BRIDGES[(the_uuid)] }
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
#
|
||||
def self.open_bridge(process=nil, the_url=nil, options=nil)
|
||||
new_bridge = ::GxG::Communications::Bridge.new(process, the_url, options)
|
||||
BRIDGE_THREAD_SAFETY.synchronize { ::GxG::BRIDGES[(new_bridge.uuid)] = new_bridge }
|
||||
new_bridge.uuid
|
||||
end
|
||||
#
|
||||
def self.close_bridge(the_uuid=nil)
|
||||
if ::GxG::valid_uuid?(the_uuid)
|
||||
the_bridge = BRIDGE_THREAD_SAFETY.synchronize { ::GxG::BRIDGES.delete(the_uuid) }
|
||||
if the_bridge
|
||||
the_bridge.close
|
||||
timeout = ::Chronic::parse("30 seconds from now").to_f
|
||||
while the_bridge.open? do
|
||||
sleep 1.0
|
||||
if Time.now.to_f >= timeout
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
# ### Adapters
|
||||
class BridgeAdapter
|
||||
# WARNING: Only instantiate subclasses
|
||||
def self.protocol()
|
||||
:unspecified
|
||||
end
|
||||
#
|
||||
def self.abilities()
|
||||
[]
|
||||
end
|
||||
#
|
||||
def self.limits()
|
||||
{}
|
||||
end
|
||||
#
|
||||
def self.templates()
|
||||
{}
|
||||
end
|
||||
#
|
||||
def initialize(the_process=nil, the_url=nil, options=nil)
|
||||
if the_url.is_a?(::String)
|
||||
the_url = ::URI::parse(the_url)
|
||||
end
|
||||
unless the_url.is_a?(::URI::Generic)
|
||||
raise ArgumentError, "You MUST provide a valid URL as a String or URI."
|
||||
end
|
||||
unless the_process
|
||||
raise ArgumentError, "You MUST provide a Service or Application object to interact with."
|
||||
end
|
||||
@process = the_process
|
||||
@url = the_url
|
||||
@options = (options || {})
|
||||
unless @options.is_a?(::Hash)
|
||||
raise ArgumentError, "You must provide options as a Hash."
|
||||
end
|
||||
@active = false
|
||||
@connector = nil
|
||||
@thread_safety = ::Mutex.new
|
||||
#
|
||||
@uuid = ::GxG::uuid_generate.to_sym
|
||||
self
|
||||
end
|
||||
#
|
||||
def uuid()
|
||||
@uuid
|
||||
end
|
||||
#
|
||||
def my_id()
|
||||
nil
|
||||
end
|
||||
#
|
||||
def open?()
|
||||
if @connector
|
||||
if @connector.closed?
|
||||
@active = false
|
||||
else
|
||||
@active = true
|
||||
end
|
||||
end
|
||||
@active
|
||||
end
|
||||
#
|
||||
def open()
|
||||
unless self.open?
|
||||
@active = @connector.login(@url, @options)
|
||||
end
|
||||
@active
|
||||
end
|
||||
#
|
||||
def close()
|
||||
if self.open?
|
||||
@connector.logout()
|
||||
@active = false
|
||||
end
|
||||
true
|
||||
end
|
||||
# ### Information Refresh
|
||||
def notify(details=nil)
|
||||
#
|
||||
end
|
||||
#
|
||||
# ### Basic Entity Support
|
||||
def entitiies()
|
||||
[]
|
||||
end
|
||||
#
|
||||
def entity_status(the_address=nil)
|
||||
:online
|
||||
end
|
||||
# ### Basic Channel Support
|
||||
def channels()
|
||||
{}
|
||||
end
|
||||
end
|
||||
# ### Matrix
|
||||
class BridgeAdapterMatrix < ::GxG::Communications::BridgeAdapter
|
||||
def self.protocol()
|
||||
:"matrix-https"
|
||||
end
|
||||
#
|
||||
def self.abilities()
|
||||
[:message, :file_transfer, :request]
|
||||
end
|
||||
#
|
||||
def self.limits()
|
||||
{:message_size => 64512, :file_transfer_size => nil, :request_size => 64512}
|
||||
end
|
||||
#
|
||||
def self.templates()
|
||||
{}
|
||||
end
|
||||
#
|
||||
private
|
||||
def decode_message(the_message=nil)
|
||||
result = message
|
||||
if message.is_a?(::GxG::Events::Message)
|
||||
fallback_key = nil
|
||||
key = nil
|
||||
message_sender = message[:sender].to_s
|
||||
@thread_safety.synchronize {
|
||||
if @keychain[(message_sender.to_s)]
|
||||
fallback_key = @keychain[(message_sender.to_s)][:original]
|
||||
key = @keychain[(message_sender.to_s)][:current]
|
||||
end
|
||||
}
|
||||
new_body = nil
|
||||
if key && fallback_key
|
||||
if message[:body].is_a?(::String)
|
||||
begin
|
||||
if message[:body].base64?
|
||||
new_body = message[:body].decode64.decrypt(key)
|
||||
else
|
||||
new_body = message[:body].decrypt(key)
|
||||
end
|
||||
new_body = ::Hash::gxg_import(::JSON::parse(new_body, {:symbolize_names => true}))
|
||||
rescue Exception => the_error
|
||||
begin
|
||||
if message[:body].base64?
|
||||
new_body = message[:body].decode64.decrypt(fallback_key)
|
||||
else
|
||||
new_body = message[:body].decrypt(fallback_key)
|
||||
end
|
||||
new_body = ::Hash::gxg_import(::JSON::parse(new_body, {:symbolize_names => true}))
|
||||
rescue Exception => the_error
|
||||
message[:bridge_unintelligible] = true
|
||||
log_error({:error => the_error})
|
||||
new_body = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
if message[:body].is_a?(::String)
|
||||
if message[:body].base64?
|
||||
new_body = message[:body].decode64
|
||||
else
|
||||
new_body = message[:body]
|
||||
end
|
||||
begin
|
||||
new_body = ::Hash::gxg_import(::JSON::parse(new_body, {:symbolize_names => true}))
|
||||
rescue Exception => the_error
|
||||
log_error({:error => the_error})
|
||||
new_body = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
if new_body.is_a?(::Hash)
|
||||
message[:body] = new_body
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
public
|
||||
#
|
||||
def initialize(the_process=nil, the_url=nil, options={:sasl => :digest, :digest => true})
|
||||
super(the_process, the_url, options)
|
||||
unless @options[:sasl]
|
||||
@options = {:sasl => :digest, :digest => true}
|
||||
end
|
||||
#
|
||||
# Channels format: {<uuid> => {:channel => <XMPPConversation>, :entities => [<jid-string>, ...]}}
|
||||
@channels = {}
|
||||
# Keychain format: {:original => "", :current => ""}
|
||||
@keychain = {}
|
||||
# Messages format: {<uuid> => [<::GxG::Events::Message>, ...]}
|
||||
@messages = {}
|
||||
@messages_busy_semaphore = false
|
||||
@invitations = {}
|
||||
@file_transfers = {}
|
||||
#
|
||||
@connector = ::GxG::Networking::MatrixClient.new(the_url)
|
||||
self.open
|
||||
#
|
||||
self
|
||||
end
|
||||
#
|
||||
def my_id()
|
||||
if @connector
|
||||
@connector.my_jid.to_s
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
# ### Information Refresh
|
||||
def notify(details=nil)
|
||||
# Review : totally re-write this --> VFS integration, Matrix-based approach (adapt)
|
||||
if details.is_a?(::Hash)
|
||||
if @process
|
||||
if @process.respond_to?(:dispatcher) && @process.respond_to?(:respond_to_event?)
|
||||
case details[:event]
|
||||
when :new_invitation
|
||||
active_list = {}
|
||||
@connector.invitations.each do |the_invitation|
|
||||
active_list[(the_invitation.uuid)] = {:invitation => the_invitation, :title => the_invitation[:title].to_s, :sender => the_invitation[:sender].to_s, :type => the_invitation[:type].to_s}
|
||||
end
|
||||
@thread_safety.synchronize { @invitations = active_list }
|
||||
#
|
||||
if @process.respond_to_event?(:new_invitation)
|
||||
@process.dispatcher.post_event(:communications) do
|
||||
@process.call_event({:new_invitation => {:invitation => details[:invitation], :sender => details[:sender], :at => ::DateTime.now}})
|
||||
end
|
||||
end
|
||||
when :new_file_transfer
|
||||
# First, update Bridge Manifest
|
||||
active_list = {}
|
||||
@connector.file_transfers.each do |the_transfer|
|
||||
reference = the_transfer.reference
|
||||
file_name = the_transfer.file_details[:filename]
|
||||
file_size = the_transfer.file_details[:size]
|
||||
sender = the_transfer.info[:sender]
|
||||
# set download path
|
||||
unless ::File.exists?(GxG::SYSTEM_PATHS[:temporary] + "/" + reference.to_s)
|
||||
::FileUtils.mkpath(GxG::SYSTEM_PATHS[:temporary] + "/" + reference.to_s)
|
||||
end
|
||||
the_transfer.download_directory = (GxG::SYSTEM_PATHS[:temporary] + "/" + reference.to_s)
|
||||
# store entry
|
||||
active_list[(reference)] = {:transfer => the_transfer, :sender => sender, :file => file_name, :size => file_size, :path => ("/System/Temporary/" + reference.to_s + "/" + file_name)}
|
||||
end
|
||||
@thread_safety.synchronize { @file_transfers = active_list }
|
||||
if @process.respond_to_event?(:new_file_transfer)
|
||||
@process.dispatcher.post_event(:communications) do
|
||||
@process.call_event({:new_file_transfer => {:transfer => details[:transfer], :sender => details[:sender], :at => ::DateTime.now}})
|
||||
end
|
||||
end
|
||||
when :file_transfer_complete, :file_transfer_cancelled, :file_transfer_error
|
||||
notification = {}
|
||||
notification[(details[:event])] = {:transfer => details[:transfer], :at => ::DateTime.now}
|
||||
#
|
||||
active_list = {}
|
||||
@connector.file_transfers.each do |the_transfer|
|
||||
reference = the_transfer.reference
|
||||
file_name = the_transfer.file_details[:filename]
|
||||
file_size = the_transfer.file_details[:size]
|
||||
sender = the_transfer.info[:sender]
|
||||
# store entry
|
||||
active_list[(reference)] = {:transfer => the_transfer, :sender => sender, :file => file_name, :size => file_size, :path => ("/System/Temporary/" + reference.to_s + "/" + file_name)}
|
||||
end
|
||||
@thread_safety.synchronize { @file_transfers = active_list }
|
||||
#
|
||||
if @process.respond_to_event?(details[:event])
|
||||
@process.call_event(notification)
|
||||
end
|
||||
when :file_transfer_progress
|
||||
if @process.respond_to_event?(:file_transfer_progress)
|
||||
@process.call_event({:file_transfer_progress => {:transfer => details[:transfer], :progress => details[:progress], :at => ::DateTime.now}})
|
||||
end
|
||||
when :new_message, :new_private_message, :new_announcement, :new_error
|
||||
# ### unless channel exists - add it
|
||||
the_channel = @thread_safety.synchronize { @channels[(details[:conversation].to_sym)] }
|
||||
unless the_channel
|
||||
found = nil
|
||||
@connector.conversations.each do |channel_object|
|
||||
if details[:conversation].to_sym == channel_object.uuid
|
||||
found = channel_object
|
||||
break
|
||||
end
|
||||
end
|
||||
if found
|
||||
@thread_safety.synchronize { @channels[(details[:conversation].to_sym)] = {:channel => found, :title => found.title()}}
|
||||
the_channel = found
|
||||
end
|
||||
end
|
||||
# ### get messages
|
||||
if the_channel
|
||||
unless @thread_safety.synchronize { @messages[(the_channel.uuid)].is_a?(::Array) }
|
||||
@thread_safety.synchronize { @messages[(the_channel.uuid)] = [] }
|
||||
end
|
||||
the_channel.process_received() do |the_message|
|
||||
# Note: this will pick up other messages from the adapter now, but it is ok - a notification will be generated on EACH message.
|
||||
the_message[:channel] = the_channel.uuid
|
||||
@thread_safety.synchronize { @messages[(the_channel.uuid)] << the_message }
|
||||
end
|
||||
end
|
||||
# Review : differentiate beteween private and open messages? How to do?
|
||||
if @process.respond_to_event?(:new_message)
|
||||
notification = {}
|
||||
notification[:new_message] = {:channel => details[:conversation], :message => details[:message], :sender => details[:sender].to_s, :at => ::DateTime.now}
|
||||
#
|
||||
@process.dispatcher.post_event(:communications) do
|
||||
@process.call_event(notification)
|
||||
end
|
||||
end
|
||||
#
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
# ### Keychain
|
||||
def set_key(recipient=nil, password=nil)
|
||||
result = false
|
||||
if recipient.to_s.valid_jid? && password.is_a?(::String)
|
||||
@thread_safety.synchronize {
|
||||
if @keychain[(recipient.to_s)]
|
||||
@keychain[(recipient.to_s)][:current] = password
|
||||
else
|
||||
@keychain[(recipient.to_s)] = {:original => password, :current => password}
|
||||
end
|
||||
result = true
|
||||
}
|
||||
end
|
||||
result
|
||||
end
|
||||
# ### Invitations
|
||||
def accept_invitation(the_invitation_uuid=nil)
|
||||
result = false
|
||||
if ::GxG::valid_uuid?(the_invitation_uuid)
|
||||
found = nil
|
||||
@thread_safety.synchronize {
|
||||
found = @invitations[(the_invitation_uuid.to_sym)]
|
||||
}
|
||||
if found
|
||||
found[:invitation].accept()
|
||||
result = true
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def decline_invitation(the_invitation_uuid=nil)
|
||||
result = false
|
||||
if ::GxG::valid_uuid?(the_invitation_uuid)
|
||||
found = nil
|
||||
@thread_safety.synchronize {
|
||||
found = @invitations[(the_invitation_uuid.to_sym)]
|
||||
}
|
||||
if found
|
||||
found[:invitation].decline()
|
||||
result = true
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
# ### File Transfers
|
||||
def file_transfers()
|
||||
result = {}
|
||||
@thread_safety.synchronize {
|
||||
@file_transfers.each_pair do |the_uuid, the_record|
|
||||
result[(the_uuid)] = {:sender => the_record[:sender], :file => the_record[:file], :size => the_record[:size], :path => the_record[:path]}
|
||||
end
|
||||
}
|
||||
result
|
||||
end
|
||||
#
|
||||
def accept_file_transfer(the_transfer_uuid=nil)
|
||||
result = false
|
||||
if ::GxG::valid_uuid?(the_transfer_uuid)
|
||||
found = nil
|
||||
@thread_safety.synchronize {
|
||||
found = @file_transfers[(the_transfer_uuid.to_sym)]
|
||||
}
|
||||
if found
|
||||
found[:transfer].accept()
|
||||
result = true
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def decline_file_transfer(the_transfer_uuid=nil)
|
||||
result = false
|
||||
if ::GxG::valid_uuid?(the_transfer_uuid)
|
||||
found = nil
|
||||
@thread_safety.synchronize {
|
||||
found = @file_transfers[(the_transfer_uuid.to_sym)]
|
||||
}
|
||||
if found
|
||||
found[:transfer].decline()
|
||||
if ::File.exists?(GxG::SYSTEM_PATHS[:temporary] + "/" + found[:transfer].reference.to_s)
|
||||
::GxG::VFS.rmdir("/System/Temporary/" + found[:transfer].reference.to_s)
|
||||
end
|
||||
result = true
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def cancel_file_transfer(the_transfer_uuid=nil)
|
||||
result = false
|
||||
if ::GxG::valid_uuid?(the_transfer_uuid)
|
||||
found = nil
|
||||
@thread_safety.synchronize {
|
||||
found = @file_transfers[(the_transfer_uuid.to_sym)]
|
||||
}
|
||||
if found
|
||||
found[:transfer].cancel()
|
||||
if ::File.exists?(GxG::SYSTEM_PATHS[:temporary] + "/" + found[:transfer].reference.to_s)
|
||||
::GxG::VFS.rmdir("/System/Temporary/" + found[:transfer].reference.to_s)
|
||||
end
|
||||
result = true
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
# ### Entities
|
||||
def entities()
|
||||
result = []
|
||||
@connector.buddies().each do |record|
|
||||
new_record = {:id => "", :title => "Untitled", :groups => [], :status => :offline}
|
||||
new_record[:id] = record[:jid]
|
||||
new_record[:title] = record[:title]
|
||||
new_record[:groups] = record[:groups]
|
||||
case record[:status]
|
||||
when :chat, :normal, :available
|
||||
new_record[:status] = :online
|
||||
when :dnd
|
||||
new_record[:status] = :busy
|
||||
when :away
|
||||
new_record[:status] = :away
|
||||
when :xa
|
||||
new_record[:status] = :extended_away
|
||||
when :unavailable, :offline
|
||||
new_record[:status] = :offline
|
||||
when :error
|
||||
new_record[:status] = :error
|
||||
end
|
||||
result << new_record
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def entity_status(the_address=nil)
|
||||
result = :invalid_address
|
||||
if the_address.valid_jid?()
|
||||
result = :unknown_address
|
||||
self.entities.each do |the_record|
|
||||
if the_record[:id] == the_address
|
||||
result = the_record[:status]
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def status()
|
||||
result = :offline
|
||||
case @adapter.get_status
|
||||
when :chat, :normal, :available
|
||||
result = :online
|
||||
when :dnd
|
||||
result = :busy
|
||||
when :away
|
||||
result = :away
|
||||
when :xa
|
||||
result = :extended_away
|
||||
when :unavailable, :offline
|
||||
result = :offline
|
||||
when :error
|
||||
result = :error
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def status=(the_status=nil, message=nil)
|
||||
result = :available
|
||||
case the_status
|
||||
when :online
|
||||
result = :available
|
||||
when :busy
|
||||
result = :dnd
|
||||
when :away
|
||||
result = :away
|
||||
when :extended_away
|
||||
result = :xa
|
||||
when :offline
|
||||
result = :unavailable
|
||||
when :error
|
||||
result = :error
|
||||
end
|
||||
@adapter.set_status(result, message)
|
||||
end
|
||||
# ### Basic Channel Support
|
||||
def channels()
|
||||
result = {}
|
||||
@thread_safety.synchronize {
|
||||
@channels.each_pair do |the_uuid, the_record|
|
||||
result[(the_uuid)] = the_record[:title]
|
||||
end
|
||||
}
|
||||
result
|
||||
end
|
||||
#
|
||||
def associate(recipient=nil)
|
||||
result = false
|
||||
if recipient.is_a?(::String)
|
||||
if recipient.valid_jid?
|
||||
@adapter.add_buddy(recipient)
|
||||
result = true
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def disassociate(recipient=nil)
|
||||
result = false
|
||||
if recipient.is_a?(::String)
|
||||
if recipient.valid_jid?
|
||||
@adapter.remove_buddy(recipient)
|
||||
result = true
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def open_channel(with_jid=nil, password=nil, configuration={})
|
||||
result = nil
|
||||
if with_jid.is_a?(::String)
|
||||
if with_jid.valid_jid? && configuration.is_any?(::Hash, ::GxG::Database::PersistedHash)
|
||||
# If channel already exists and they attempt a repeat opening action:
|
||||
@thread_safety.synchronize {
|
||||
@channels.each_pair do |the_uuid, the_record|
|
||||
if with_jid.to_s == the_record.jid.to_s
|
||||
result = the_record.uuid
|
||||
break
|
||||
end
|
||||
end
|
||||
}
|
||||
unless result
|
||||
# Channel needs to be constructed:
|
||||
if @connector.create_conversation(with_jid, password, configuration) == true
|
||||
existing_channels = self.channels()
|
||||
found = nil
|
||||
@thread_safety.synchronize {
|
||||
@connector.conversations.each do |channel_object|
|
||||
if existing_channels.keys.include?(channel_object.uuid)
|
||||
next
|
||||
else
|
||||
found = channel_object
|
||||
@channels[(channel_object.uuid)] = {:channel => found, :title => found.title()}
|
||||
break
|
||||
end
|
||||
end
|
||||
}
|
||||
if found
|
||||
result = channel_object.uuid
|
||||
if password
|
||||
if channel_object[:type] == :chat
|
||||
# on :groupchat password is only used for access, not encryption.
|
||||
self.set_key(with_jid, password)
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def join_channel(channel_jid=nil, password=nil, options={})
|
||||
result = nil
|
||||
if channel_jid.is_a?(::String)
|
||||
if channel_jid.valid_jid? && options.is_any?(::Hash, ::GxG::Database::PersistedHash)
|
||||
if @connector.join_conversation(channel_jid, password, options) == true
|
||||
existing_channels = self.channels()
|
||||
found = nil
|
||||
@thread_safety.synchronize {
|
||||
@connector.conversations.each do |channel_object|
|
||||
if existing_channels.keys.include?(channel_object.uuid)
|
||||
next
|
||||
else
|
||||
found = channel_object
|
||||
@channels[(channel_object.uuid)] = {:channel => found, :title => found.title()}
|
||||
break
|
||||
end
|
||||
end
|
||||
}
|
||||
if found
|
||||
result = channel_object.uuid
|
||||
end
|
||||
#
|
||||
end
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def close_channel(the_channel_uuid=nil)
|
||||
if ::GxG::valid_uuid?(the_channel_uuid)
|
||||
the_channel = nil
|
||||
@thread_safety.synchronize {
|
||||
if @channels[(the_channel_uuid.to_sym)].is_a?(::Hash)
|
||||
the_channel = @channels.delete(the_channel_uuid.to_sym)[:channel]
|
||||
end
|
||||
}
|
||||
if the_channel
|
||||
the_channel.leave("{ \"exit_channel\":\"#{the_channel.my_jid.to_s}\" }")
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
# ### Messages
|
||||
def send_message(the_channel_uuid=nil, message=nil, recipient=nil, use_fallback_key=false)
|
||||
result = false
|
||||
#
|
||||
if ::GxG::valid_uuid?(the_channel_uuid)
|
||||
the_channel = nil
|
||||
@thread_safety.synchronize {
|
||||
if @channels[(the_channel_uuid.to_sym)].is_a?(::Hash)
|
||||
the_channel = @channels[(the_channel_uuid.to_sym)][:channel]
|
||||
end
|
||||
}
|
||||
if the_channel
|
||||
if message.is_any?(::String, ::Hash, ::GxG::Database::PersistedHash, ::GxG::Events::Message)
|
||||
if message.is_a?(::String)
|
||||
message = new_message({:sender => @connector.my_jid.to_s, :body => {:message => message}.gxg_export.to_json})
|
||||
end
|
||||
if message.is_a?(::Hash)
|
||||
message = new_message({:sender => @connector.my_jid.to_s, :body => message.gxg_export.to_json})
|
||||
end
|
||||
if message.is_a?(::GxG::Database::PersistedHash)
|
||||
message = new_message({:sender => @connector.my_jid.to_s, :body => message.sync_export.gxg_export.to_json})
|
||||
end
|
||||
if message.is_a?(::GxG::Events::Message)
|
||||
if message[:body].is_a?(::Hash)
|
||||
message[:body] = message[:body].gxg_export.to_json
|
||||
end
|
||||
if message[:body].is_a?(::GxG::Database::PersistedHash)
|
||||
message[:body] = message[:body].sync_export.gxg_export.to_json
|
||||
end
|
||||
end
|
||||
#
|
||||
if message.is_a?(::GxG::Events::Message)
|
||||
# Reset :sender if a ruby object is the current setting. (bridge addressing translation)
|
||||
unless message[:sender].is_a?(::String)
|
||||
message[:sender] = @connector.my_jid.to_s
|
||||
end
|
||||
# encrypt body?
|
||||
key = nil
|
||||
if recipient.is_a?(::String)
|
||||
intended_recipient = recipient
|
||||
else
|
||||
intended_recipient = the_channel.jid()
|
||||
end
|
||||
@thread_safety.synchronize {
|
||||
if @keychain[(intended_recipient.to_s)]
|
||||
if use_fallback_key == true
|
||||
key = @keychain[(intended_recipient.to_s)][:original]
|
||||
else
|
||||
key = @keychain[(intended_recipient.to_s)][:current]
|
||||
end
|
||||
end
|
||||
}
|
||||
if key.is_a?(::String)
|
||||
message[:body] = message[:body].encrypt(key).encode64
|
||||
else
|
||||
message[:body] = message[:body].encode64
|
||||
end
|
||||
# send message
|
||||
result = the_channel.say_something(message, recipient)
|
||||
# Review : use this next little bit of code in the request/reply code:
|
||||
# if result == true
|
||||
# message.succeed(message)
|
||||
# else
|
||||
# message.fail(message)
|
||||
# end
|
||||
end
|
||||
else
|
||||
raise ArgumentError, "You MUST provide the message as a String, Hash, GxG::Database::PersistedHash, or GxG::Events::Message; NOT #{message.class} ."
|
||||
end
|
||||
else
|
||||
raise ArgumentError, "Invalid Channel selector, the Channel was not found: #{the_channel.inspect} . Try opening the channel first."
|
||||
end
|
||||
else
|
||||
raise ArgumentError, "Invalid Channel selector: #{the_channel.inspect} . You MUST provide a valid UUID."
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def next_message(the_channel_uuid=nil)
|
||||
result = nil
|
||||
if ::GxG::valid_uuid?(the_channel_uuid)
|
||||
@thread_safety.synchronize {
|
||||
if @messages[(the_channel_uuid.to_sym)].is_a?(::Array)
|
||||
result = @messages[(the_channel_uuid.to_sym)].shift
|
||||
end
|
||||
}
|
||||
if result
|
||||
result = decode_message(result)
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def all_messages(the_channel_uuid=nil)
|
||||
result = []
|
||||
if ::GxG::valid_uuid?(the_channel_uuid)
|
||||
@thread_safety.synchronize {
|
||||
if @messages[(the_channel_uuid.to_sym)].is_a?(::Array)
|
||||
@messages[(the_channel_uuid.to_sym)].size.times do
|
||||
result << decode_message(@messages[(the_channel_uuid.to_sym)].shift)
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def get_message(the_channel_uuid=nil, the_message_uuid=nil)
|
||||
result = nil
|
||||
if ::GxG::valid_uuid?(the_channel_uuid) && the_message_uuid
|
||||
@thread_safety.synchronize {
|
||||
if @messages[(the_channel_uuid.to_sym)].is_a?(::Array)
|
||||
@messages[(the_channel_uuid.to_sym)].each_with_index do |the_message, the_index|
|
||||
if the_message_uuid == the_message.id()
|
||||
result = @messages[(the_channel_uuid.to_sym)].delete_at(the_index)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
if result
|
||||
result = decode_message(result)
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def get_messages_by_context(the_channel_uuid=nil, the_context_uuid=nil)
|
||||
result = []
|
||||
if ::GxG::valid_uuid?(the_channel_uuid) && the_context_uuid
|
||||
@thread_safety.synchronize {
|
||||
if @messages[(the_channel_uuid.to_sym)].is_a?(::Array)
|
||||
@messages[(the_channel_uuid.to_sym)].each_with_index do |the_message, the_index|
|
||||
if the_context_uuid.to_s.to_sym == the_message[:context].to_s.to_sym
|
||||
result << @messages[(the_channel_uuid.to_sym)].delete_at(the_index)
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
if result
|
||||
result = decode_message(result)
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def get_messages_by_sender(the_channel_uuid=nil, the_sender=nil)
|
||||
result = []
|
||||
if ::GxG::valid_uuid?(the_channel_uuid) && the_sender
|
||||
@thread_safety.synchronize {
|
||||
if @messages[(the_channel_uuid.to_sym)].is_a?(::Array)
|
||||
@messages[(the_channel_uuid.to_sym)].each_with_index do |the_message, the_index|
|
||||
if the_sender.to_s == the_message[:sender].to_s
|
||||
result << @messages[(the_channel_uuid.to_sym)].delete_at(the_index)
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
if result
|
||||
result = decode_message(result)
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
end
|
||||
#
|
||||
class Bridge
|
||||
def initialize(process=nil, the_url=nil, options=nil)
|
||||
# Note: process (required) is a Service or Application instance only
|
||||
unless process.is_a?(::GxG::Services::Service)
|
||||
raise ArgumentError, "You MUST provide a Service or Application instance to bind to."
|
||||
end
|
||||
# Ensure protocol supported
|
||||
if the_url.is_a?(::String)
|
||||
the_url = ::URI::parse(the_url)
|
||||
end
|
||||
unless the_url.is_a?(::URI::Generic)
|
||||
raise ArgumentError, "You MUST provide a valid URL as a String or URI."
|
||||
end
|
||||
the_type = ::GxG::BRIDGES_AVAILABLE[(the_url.scheme.to_sym)]
|
||||
unless the_type
|
||||
raise ArgumentError, "Sorry, #{the_url.scheme.to_sym.inspect} is not a supported protocol."
|
||||
end
|
||||
# Variables
|
||||
@process = process
|
||||
@url = the_url
|
||||
@adapter = the_type.new(self, @url, options)
|
||||
@uuid = ::GxG::uuid_generate.to_sym
|
||||
@interface = {}
|
||||
self.on(:interface, "Available Commands") do
|
||||
self.interface()
|
||||
end
|
||||
self
|
||||
end
|
||||
#
|
||||
def uuid()
|
||||
@uuid
|
||||
end
|
||||
# ### Command Interface
|
||||
def on(the_event, description=nil, &block)
|
||||
unless the_event.is_a?(::Symbol)
|
||||
raise ArgumentError, "You must specify an event listener with a unique Symbol."
|
||||
end
|
||||
unless block.respond_to?(:call)
|
||||
raise ArgumentError, "You must provide an event code block to execute."
|
||||
end
|
||||
unless description
|
||||
description = "{ '#{the_event.to_s}': '(your_data_payload)' }"
|
||||
end
|
||||
@interface[(the_event)] = {:description => description, :procedure => block}
|
||||
true
|
||||
end
|
||||
#
|
||||
def call_event(operation_envelope=nil)
|
||||
result = nil
|
||||
if operation_envelope.is_a?(::Hash)
|
||||
the_event = operation_envelope.keys[0]
|
||||
if the_event
|
||||
data = operation_envelope[(the_event)]
|
||||
if @interface[(the_event)]
|
||||
begin
|
||||
result = {:result => @interface[(the_event)][:procedure].call(@process, self, data)}
|
||||
rescue Exception => the_error
|
||||
log_error({:error => the_error, :parameters => {:data => data}})
|
||||
result = {:result => nil, :error => the_error.to_s}
|
||||
end
|
||||
else
|
||||
result = {:result => nil, :error => "Command #{the_event.inspect} Not Found"}
|
||||
end
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def interface()
|
||||
result = {}
|
||||
@interface.each_pair do |the_event, the_record|
|
||||
result[(the_event)] = the_record[:description]
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def respond_to_event?(the_event=nil)
|
||||
result = false
|
||||
if the_event.is_a?(::Symbol)
|
||||
if @interface[(the_event)]
|
||||
result = true
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
# ### Request/Reply Support
|
||||
def request(the_channel_uuid=nil, request_body=nil, address=nil, options={})
|
||||
result = nil
|
||||
#
|
||||
if ::GxG::valid_uuid?(the_channel_uuid) && request_body.is_a?(::GxG::Events::Message) && address
|
||||
payload = nil
|
||||
context = ::GxG::uuid_generate
|
||||
if address.to_s.valid_jid?
|
||||
# Point-to-Point Request
|
||||
payload = new_message({:sender => @adapter.jid().to_s, :body => request_body})
|
||||
payload[:context] = context.to_s
|
||||
if payload
|
||||
@adapter.send_message(the_channel_uuid, payload, address)
|
||||
the_reply_list = @adapter.get_messages_by_context(the_channel_uuid, context)
|
||||
if options.is_a?(::Hash)
|
||||
if options[:timeout].is_a?(::Numeric)
|
||||
timeout = Time.now.to_f + options[:timeout].to_f
|
||||
else
|
||||
timeout = Time.now.to_f + 30.0
|
||||
end
|
||||
else
|
||||
timeout = Time.now.to_f + 30.0
|
||||
end
|
||||
until the_reply_list.size > 0 do
|
||||
the_reply_list = @adapter.get_messages_by_context(the_channel_uuid, context)
|
||||
sleep 0.5
|
||||
if Time.now.to_f >= timeout
|
||||
break
|
||||
end
|
||||
end
|
||||
if the_reply_list.size > 0
|
||||
result = the_reply_list[0]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
result
|
||||
end
|
||||
#
|
||||
def reply(the_channel_uuid=nil, reply_body=nil, address=nil)
|
||||
result = {:result => false}
|
||||
if ::GxG::valid_uuid?(the_channel_uuid) && reply_body.is_a?(::GxG::Events::Message) && address
|
||||
@adapter.send_message(the_channel_uuid, reply_body, address)
|
||||
result[:result] = true
|
||||
end
|
||||
result
|
||||
end
|
||||
end
|
||||
#
|
||||
end
|
||||
end
|
||||
# ### Register BridgeAdapters by protocol
|
||||
::GxG::Communications::BridgeAdapter.descendants.each do |the_adapter_class|
|
||||
::GxG::BRIDGES_AVAILABLE[((the_adapter_class)::protocol)] = the_adapter_class
|
||||
end
|
||||
5505
lib/gxg/gxg_database.rb
Normal file
5505
lib/gxg/gxg_database.rb
Normal file
File diff suppressed because it is too large
Load diff
3092
lib/gxg/gxg_database_persistedarray.rb
Normal file
3092
lib/gxg/gxg_database_persistedarray.rb
Normal file
File diff suppressed because it is too large
Load diff
2859
lib/gxg/gxg_database_persistedhash.rb
Normal file
2859
lib/gxg/gxg_database_persistedhash.rb
Normal file
File diff suppressed because it is too large
Load diff
2820
lib/gxg/gxg_dbfs.rb
Normal file
2820
lib/gxg/gxg_dbfs.rb
Normal file
File diff suppressed because it is too large
Load diff
2263
lib/gxg/gxg_elements.rb
Normal file
2263
lib/gxg/gxg_elements.rb
Normal file
File diff suppressed because it is too large
Load diff
853
lib/gxg/gxg_engine.rb
Normal file
853
lib/gxg/gxg_engine.rb
Normal file
|
|
@ -0,0 +1,853 @@
|
|||
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
# GxG Engine interface: rational memory management, and quota supports
|
||||
module GxG
|
||||
#
|
||||
module Engine
|
||||
# ok... why?
|
||||
# example: ::Process::getrlimit(:AS) => [<1Exabyte>,<1Exabyte>]
|
||||
# Now that is the Amsterdam-style pull on a bong with stirrups - so far as dealing with real memory limits goes.
|
||||
# Rather - I want my apps to be *able* to deal with reality as the system resources determine
|
||||
# Eventually provides a *corrected* drop-in replacement for Process module in standard MRI 1.9.2
|
||||
# See : http://www.ruby-doc.org/core-1.9.3/Process.html
|
||||
#
|
||||
@@details = {}
|
||||
# running effectively in 32 or 64 bits? See: http://www.ruby-forum.com/topic/164583
|
||||
@@details[:runtime_bits] = ([ -1 ].pack('l!').length * 8)
|
||||
# default to 32 bit size:
|
||||
if @@details[:runtime_bits] == 64
|
||||
@@details[:runtime_rvalue_size] = 40
|
||||
else
|
||||
@@details[:runtime_rvalue_size] = 20
|
||||
end
|
||||
#
|
||||
@@details[:files] = {:maximum_file_descriptors => 1024}
|
||||
# FORNOW : Review : server claims 50% of all system threads
|
||||
@@details[:events] = {:maximum_event_descriptors => (GxG::SYSTEM["kernel.threads_max"]["kernel.threads_max"].to_f * 0.5).to_i , :event_descriptors_threshold => 0.05, :event_descriptors_envelope => (20..100), :event_minimum_threshold => 20}
|
||||
# Fix for Windows: per-process theads max is 2000.
|
||||
if GxG::SYSTEM.platform[:platform] == :windows
|
||||
@@details[:files][:maximum_file_descriptors] = 512
|
||||
@@details[:events][:maximum_event_descriptors] = 2000
|
||||
end
|
||||
#
|
||||
@@details[:runtime] = RUBY_ENGINE.to_sym
|
||||
@@details[:runtime_version] = GxG::Version.new({:interpret => RUBY_VERSION, :patch_level => RUBY_PATCHLEVEL, :revision => RUBY_REVISION})
|
||||
# determine the byte size of a Ruby RVALUE (a.k.a :slot_size)
|
||||
# See: http://www.engineyard.com/blog/2010/mri-memory-allocation-a-primer-for-developers/
|
||||
#
|
||||
@@details[:memory_load] = {:high => false, :medium => false, :low => true, :percent => 0.0}
|
||||
@@details[:engine_load] = {:high => false, :medium => false, :low => true, :percent => 0.0}
|
||||
#
|
||||
@@details[:key_map] = []
|
||||
@@details[:key_map] << {:key => "files.max_descriptors", :path => "/:files/:maximum_file_descriptors"}
|
||||
@@details[:key_map] << {:key => "events.max_descriptors", :path => "/:events/:maximum_event_descriptors"}
|
||||
#
|
||||
@@thread_safety = Mutex.new
|
||||
@@event_descriptors = 0
|
||||
#
|
||||
def self.detail_mapping()
|
||||
@@details[:key_map]
|
||||
end
|
||||
#
|
||||
def self.[](the_path="")
|
||||
# Public interface for accessing system keyed values.
|
||||
# access cached or system-read values on /proc (sysctl-style) keys. (frankly missing from BSD, etc)
|
||||
result = nil
|
||||
reference = ::GxG::Engine::detail_mapping()
|
||||
#
|
||||
reference.to_enum.each do |mapping|
|
||||
if mapping[:key] == the_path
|
||||
@@thread_safety.synchronize {
|
||||
result = @@details.get_at_path(mapping[:path]).clone
|
||||
}
|
||||
break
|
||||
end
|
||||
end
|
||||
# unless result
|
||||
# # attempt to fetch the data from the system somehow.
|
||||
# result = get_system_data(the_path)
|
||||
# unless result.keys.size > 0
|
||||
# result = nil
|
||||
# end
|
||||
# end
|
||||
#
|
||||
result
|
||||
end
|
||||
#
|
||||
def self.memory_load_high?()
|
||||
@@thread_safety.synchronize {
|
||||
@@details[:memory_load][:high]
|
||||
}
|
||||
end
|
||||
#
|
||||
def self.memory_load_medium?()
|
||||
@@thread_safety.synchronize {
|
||||
@@details[:memory_load][:medium]
|
||||
}
|
||||
end
|
||||
#
|
||||
def self.memory_load_low?()
|
||||
@@thread_safety.synchronize {
|
||||
@@details[:memory_load][:low]
|
||||
}
|
||||
end
|
||||
#
|
||||
def self.memory_load()
|
||||
@@thread_safety.synchronize {
|
||||
@@details[:memory_load][:percent]
|
||||
}
|
||||
end
|
||||
#
|
||||
def self.engine_load_high?()
|
||||
@@thread_safety.synchronize {
|
||||
@@details[:engine_load][:high]
|
||||
}
|
||||
end
|
||||
#
|
||||
def self.engine_load_medium?()
|
||||
@@thread_safety.synchronize {
|
||||
@@details[:engine_load][:medium]
|
||||
}
|
||||
end
|
||||
#
|
||||
def self.engine_load_low?()
|
||||
@@thread_safety.synchronize {
|
||||
@@details[:engine_load][:low]
|
||||
}
|
||||
end
|
||||
#
|
||||
def self.engine_load()
|
||||
@@thread_safety.synchronize {
|
||||
@@details[:engine_load][:percent]
|
||||
}
|
||||
end
|
||||
#
|
||||
def self.determine_memory_load()
|
||||
current_load = ((GxG::Engine::memory_used()[:total].to_f / GxG::SYSTEM.memory_limits()[:process].first.to_f) * 100.0)
|
||||
if (0.0..40.0).include?(current_load)
|
||||
# low
|
||||
@@thread_safety.synchronize {
|
||||
@@details[:memory_load][:high] = false
|
||||
@@details[:memory_load][:medium] = false
|
||||
@@details[:memory_load][:low] = true
|
||||
@@details[:memory_load][:percent] = current_load
|
||||
}
|
||||
else
|
||||
if (40.0..70.0).include?(current_load)
|
||||
# medium
|
||||
@@thread_safety.synchronize {
|
||||
@@details[:memory_load][:high] = false
|
||||
@@details[:memory_load][:medium] = true
|
||||
@@details[:memory_load][:low] = false
|
||||
@@details[:memory_load][:percent] = current_load
|
||||
}
|
||||
else
|
||||
if current_load > 70.0
|
||||
# high
|
||||
@@thread_safety.synchronize {
|
||||
@@details[:memory_load][:high] = true
|
||||
@@details[:memory_load][:medium] = false
|
||||
@@details[:memory_load][:low] = false
|
||||
@@details[:memory_load][:percent] = current_load
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
def self.determine_engine_load()
|
||||
max_event_descriptors = ::GxG::Engine::maximum_event_descriptors()
|
||||
available_events = ::GxG::Engine::available_event_descriptors()
|
||||
current_load = (((max_event_descriptors - available_events).to_f / max_event_descriptors.to_f) * 100.0)
|
||||
if (0.0..40.0).include?(current_load)
|
||||
# low
|
||||
@@thread_safety.synchronize {
|
||||
@@details[:engine_load][:high] = false
|
||||
@@details[:engine_load][:medium] = false
|
||||
@@details[:engine_load][:low] = true
|
||||
@@details[:memory_load][:percent] = current_load
|
||||
}
|
||||
else
|
||||
if (40.0..70.0).include?(current_load)
|
||||
# medium
|
||||
@@thread_safety.synchronize {
|
||||
@@details[:engine_load][:high] = false
|
||||
@@details[:engine_load][:medium] = true
|
||||
@@details[:engine_load][:low] = false
|
||||
@@details[:engine_load][:percent] = current_load
|
||||
}
|
||||
else
|
||||
if current_load > 70.0
|
||||
# high
|
||||
@@thread_safety.synchronize {
|
||||
@@details[:engine_load][:high] = true
|
||||
@@details[:engine_load][:medium] = false
|
||||
@@details[:engine_load][:low] = false
|
||||
@@details[:engine_load][:percent] = current_load
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
def self.engine_gear()
|
||||
# inverse of load
|
||||
result = :low
|
||||
@@thread_safety.synchronize {
|
||||
if @@details[:engine_load][:medium]
|
||||
result = :medium
|
||||
end
|
||||
if @@details[:engine_load][:low]
|
||||
result = :high
|
||||
end
|
||||
}
|
||||
result
|
||||
end
|
||||
#
|
||||
def self.memory_gear()
|
||||
# inverse of load
|
||||
result = :low
|
||||
@@thread_safety.synchronize {
|
||||
if @@details[:memory_load][:medium]
|
||||
result = :medium
|
||||
end
|
||||
if @@details[:memory_load][:low]
|
||||
result = :high
|
||||
end
|
||||
}
|
||||
result
|
||||
end
|
||||
#
|
||||
def self.gear()
|
||||
"#{::GxG::Engine::engine_gear().to_s}_#{::GxG::Engine::memory_gear().to_s}".to_sym
|
||||
end
|
||||
#
|
||||
def self.determine_loads()
|
||||
mem_gear = ::GxG::Engine::memory_gear()
|
||||
eng_gear = ::GxG::Engine::engine_gear()
|
||||
{
|
||||
:engine => {:load => ::GxG::Engine::determine_engine_load(), :gear => eng_gear},
|
||||
:memory => {:load => ::GxG::Engine::determine_memory_load(), :gear => mem_gear},
|
||||
:gear => "#{eng_gear.to_s}_#{mem_gear.to_s}".to_sym
|
||||
}
|
||||
end
|
||||
#
|
||||
include ::Process
|
||||
# overrides
|
||||
#
|
||||
# [:exec, :fork, :spawn, :exit!, :exit, :abort, :kill, :wait, :wait2, :waitpid, :waitpid2, :waitall, :detach, :pid, :ppid,
|
||||
# .
|
||||
def self.exec(*args)
|
||||
::Process::exec(*args)
|
||||
end
|
||||
#
|
||||
def self.fork(*args)
|
||||
::Process::fork(*args)
|
||||
end
|
||||
#
|
||||
def self.spawn(*args)
|
||||
::Process::spawn(*args)
|
||||
end
|
||||
#
|
||||
def self.exit!(*args)
|
||||
::Process::exit!(*args)
|
||||
end
|
||||
#
|
||||
def self.exit(*args)
|
||||
::Process::exit(*args)
|
||||
end
|
||||
#
|
||||
def self.abort(*args)
|
||||
::Process::abort(*args)
|
||||
end
|
||||
#
|
||||
def self.kill(*args)
|
||||
::Process::kill(*args)
|
||||
end
|
||||
#
|
||||
def self.wait(*args)
|
||||
::Process::wait(*args)
|
||||
end
|
||||
#
|
||||
def self.wait2(*args)
|
||||
::Process::wait2(*args)
|
||||
end
|
||||
#
|
||||
def self.waitpid(*args)
|
||||
::Process::waitpid(*args)
|
||||
end
|
||||
#
|
||||
def self.waitpid2(*args)
|
||||
::Process::waitpid2(*args)
|
||||
end
|
||||
#
|
||||
def self.waitall(*args)
|
||||
::Process::waitall(*args)
|
||||
end
|
||||
#
|
||||
def self.detach(*args)
|
||||
::Process::detach(*args)
|
||||
end
|
||||
#
|
||||
def self.pid(*args)
|
||||
::Process::pid(*args)
|
||||
end
|
||||
#
|
||||
def self.ppid(*args)
|
||||
::Process::ppid(*args)
|
||||
end
|
||||
#
|
||||
# :getpgrp, :setpgrp, :getpgid, :setpgid, :setsid, :getpriority, :setpriority, :getrlimit, :setrlimit, :uid, :gid, :euid, :egid,
|
||||
#
|
||||
def self.getpgrp(*args)
|
||||
::Process::getpgrp(*args)
|
||||
end
|
||||
#
|
||||
def self.setpgrp(*args)
|
||||
::Process::setpgrp(*args)
|
||||
end
|
||||
#
|
||||
def self.getpgid(*args)
|
||||
::Process::getpgid(*args)
|
||||
end
|
||||
#
|
||||
def self.setpgid(*args)
|
||||
::Process::setpgid(*args)
|
||||
end
|
||||
#
|
||||
def self.setsid(*args)
|
||||
::Process::setsid(*args)
|
||||
end
|
||||
#
|
||||
def self.getpriority(*args)
|
||||
::Process::getpriority(*args)
|
||||
end
|
||||
#
|
||||
def self.setpriority(*args)
|
||||
::Process::setpriority(*args)
|
||||
end
|
||||
#
|
||||
def self.getrlimit(key)
|
||||
result = nil
|
||||
# FIX: GxG::Engine::getrlimit : Awaiting rbx bug #2112 fix : https://github.com/rubinius/rubinius/issues/2112
|
||||
case ::GxG::Engine::profile()[:engine]
|
||||
when :ruby
|
||||
raw_data = ::Process::getrlimit(key)
|
||||
case key
|
||||
when :AS
|
||||
if GxG::SYSTEM
|
||||
memory_limits = GxG::SYSTEM.memory_limits()
|
||||
result = [raw_data[0],(memory_limits[:process].max)]
|
||||
else
|
||||
result = raw_data
|
||||
end
|
||||
else
|
||||
result = raw_data
|
||||
end
|
||||
when :jruby
|
||||
memory_limits = GxG::SYSTEM.memory_limits()
|
||||
result = [(memory_limits[:process].first),(memory_limits[:process].last)]
|
||||
when :rbx
|
||||
memory_limits = GxG::SYSTEM.memory_limits()
|
||||
result = [(memory_limits[:process].first),(memory_limits[:process].last)]
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def self.setrlimit(*args)
|
||||
::Process::setrlimit(*args)
|
||||
end
|
||||
#
|
||||
def self.uid(*args)
|
||||
::Process::uid(*args)
|
||||
end
|
||||
#
|
||||
def self.gid(*args)
|
||||
::Process::gid(*args)
|
||||
end
|
||||
#
|
||||
def self.euid(*args)
|
||||
::Process::euid(*args)
|
||||
end
|
||||
#
|
||||
def self.egid(*args)
|
||||
::Process::egid(*args)
|
||||
end
|
||||
#
|
||||
# :initgroups, :groups, :maxgroups, :daemon, :times]
|
||||
#
|
||||
def self.initgroups(*args)
|
||||
::Process::initgroups(*args)
|
||||
end
|
||||
#
|
||||
def self.groups(*args)
|
||||
::Process::groups(*args)
|
||||
end
|
||||
#
|
||||
def self.maxgroups(*args)
|
||||
::Process::maxgroups(*args)
|
||||
end
|
||||
#
|
||||
def self.daemon(*args)
|
||||
::Process::daemon(*args)
|
||||
end
|
||||
#
|
||||
def self.times(*args)
|
||||
::Process::times(*args)
|
||||
end
|
||||
#
|
||||
# extensions
|
||||
#
|
||||
def self.profile()
|
||||
@@thread_safety.synchronize {
|
||||
{:engine => @@details[:runtime], :version => @@details[:runtime_version], :bits => @@details[:runtime_bits], :slot_size => @@details[:runtime_rvalue_size]}.clone
|
||||
}
|
||||
end
|
||||
#
|
||||
def self.instance_process(the_class, &block)
|
||||
if block.respond_to?(:call)
|
||||
::ObjectSpace.each_object(Class) do |the_object|
|
||||
if the_object.alive?()
|
||||
if the_object.is_a?(the_class)
|
||||
block.call(the_object)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
def self.object_memory_used()
|
||||
#
|
||||
slots = 0
|
||||
other = 0
|
||||
::ObjectSpace.each_object(Class) do |the_object|
|
||||
slots += 1
|
||||
if the_object.alive?()
|
||||
if the_object.is_a?(::String)
|
||||
other += the_object.bytesize()
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
((::GxG::Engine::profile()[:slot_size].to_i * slots) + other)
|
||||
end
|
||||
#
|
||||
def self.memory_used()
|
||||
# ok... why in the fly'n F isn't this provided by core ruby?!?
|
||||
# Attribution: http://stackoverflow.com/questions/7220896/get-current-ruby-process-memory-usage
|
||||
result = {:actual => 0, :virtual => 0, :total => 0}
|
||||
#
|
||||
if ::GxG::SYSTEM
|
||||
case ::GxG::SYSTEM.platform[:platform]
|
||||
when :windows
|
||||
# FORNOW: user object space enumeration
|
||||
result[:actual] = ::GxG::Engine::object_memory_used()
|
||||
when :bsd
|
||||
pid_string = "#{::Process::pid}"
|
||||
env = self.environment()
|
||||
case env[:environment]
|
||||
when :openbsd
|
||||
# See: http://modman.unixdev.net/?sektion=1&page=procmap&manpath=OpenBSD-3.6
|
||||
# use `procmap -p #{pid_string}`
|
||||
# LATER: GxG::Engine::memory_used (OpenBSD) : determine how to cull procmap text data into :actual and :virtual memory usage.
|
||||
# FORNOW: user object space enumeration
|
||||
result[:actual] = ::GxG::Engine::object_memory_used()
|
||||
#
|
||||
when :freebsd, :dragonfly, :pcbsd
|
||||
# TODO: GxG::Engine::memory_used: Test with FreeBSD, DragonFlyBSD, and PCBSD.
|
||||
raw_data = `top -d 1`
|
||||
raw_data.to_enum(:each_line).each do |the_line|
|
||||
if the_line.split(" ")[0] == pid_string
|
||||
result[:actual] = (the_line.split(" ")[6] << "B").numeric_values([:byte])[:byte].to_i
|
||||
# TODO: GxG::Engine.memory_used() (netbsd) : Find a reliable way to get result[:virtual] mem used.
|
||||
break
|
||||
end
|
||||
end
|
||||
when :netbsd
|
||||
# TODO: GxG::Engine::memory_used: Test with NetBSD.
|
||||
raw_data = `top -d 1`
|
||||
raw_data.to_enum(:each_line).each do |the_line|
|
||||
if the_line.split(" ")[0] == pid_string
|
||||
result[:actual] = (the_line.split(" ")[4] << "B").numeric_values([:byte])[:byte].to_i
|
||||
# TODO: GxG::Engine.memory_used() (netbsd) : Find a reliable way to get result[:virtual] mem used.
|
||||
break
|
||||
end
|
||||
end
|
||||
when :darwin, :macos
|
||||
# TODO: GxG::Engine::memory_used: Test with Darwin/MacOSX.
|
||||
raw_data = `top -l 1`
|
||||
raw_data.to_enum(:each_line).each do |the_line|
|
||||
if the_line.split(" ")[0] == pid_string
|
||||
result[:actual] = (the_line.split(" ")[9] << "B").numeric_values([:byte])[:byte].to_i
|
||||
# TODO: GxG::Engine.memory_used() (darwin) : Find a reliable way to get result[:virtual] mem used.
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
when :linux, :solaris
|
||||
# PS is universal, but unfortunately universally incorrect, See: http://stackoverflow.com/questions/131303/linux-how-to-measure-actual-memory-usage-of-an-application-or-process
|
||||
# TODO: GxG::Engine::memory_used: create a non-toolbox version for bootstrap memory profiling.
|
||||
# TODO: GxG::Engine::memory_used: Test with Solaris.
|
||||
raw_data = `pmap -d #{::Process::pid} | tail -n 1`.split(" ")
|
||||
result[:actual] = (raw_data[3].to_s << "B").numeric_values()[:byte].to_i
|
||||
result[:virtual] = (raw_data[1].to_s << "B").numeric_values()[:byte].to_i
|
||||
# result[:shared] = (raw_data[5] << "B").numeric_values()[:byte].to_i
|
||||
end
|
||||
end
|
||||
result[:total] = (result[:actual] + result[:virtual])
|
||||
result
|
||||
end
|
||||
#
|
||||
def self.memory_available()
|
||||
# Memory available for this process
|
||||
result = {:actual => 0, :virtual => 0, :total => 0}
|
||||
if ::GxG::SYSTEM
|
||||
used_memory = ::GxG::Engine::memory_used()
|
||||
free_memory = ::GxG::SYSTEM.memory()
|
||||
limits = ::GxG::Engine::getrlimit(:AS)
|
||||
latitude_total = (limits[0] - used_memory[:actual])
|
||||
if latitude_total < 0
|
||||
latitude_total = 0
|
||||
end
|
||||
# latitude_virtual = (limits[0] - used_memory[:actual])
|
||||
# latitude_actual = (limits[0] - used_memory[:virtual])
|
||||
# indicates available ram vs. paged swap first
|
||||
if free_memory[:actual][:free].to_i > limits[0]
|
||||
result[:actual] = latitude_total
|
||||
result[:virtual] = 0
|
||||
else
|
||||
result[:actual] = free_memory[:actual][:free]
|
||||
# vm calc is crack-monkey, but someplace close to reality.
|
||||
if free_memory[:virtual][:free] > ((limits[0] - result[:actual]) - used_memory[:total])
|
||||
result[:virtual] = ((limits[0] - result[:actual]) - used_memory[:total])
|
||||
unless result[:virtual] > 0
|
||||
result[:virtual] = 0
|
||||
end
|
||||
else
|
||||
if ((free_memory[:virtual][:free] - result[:actual]) - used_memory[:total]) > 0
|
||||
result[:virtual] = ((free_memory[:virtual][:free] - result[:actual]) - used_memory[:total])
|
||||
else
|
||||
result[:virtual] = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
end
|
||||
result[:total] = (result[:actual] + result[:virtual])
|
||||
result
|
||||
end
|
||||
#
|
||||
def self.engine_data_keys(other_platform=nil)
|
||||
#
|
||||
result = []
|
||||
data = []
|
||||
data << {:key => "files.max_descriptors", :platforms => [:linux], :operation => {:getconf => "OPEN_MAX", :format => :to_int}}
|
||||
# TODO: Research maximum socket limit under zmq:
|
||||
# See: http://news.ycombinator.com/item?id=1740823
|
||||
# Also : http://stackoverflow.com/questions/651665/how-many-socket-connections-possible
|
||||
# inventory the various platform variables that affect what threshold of max_socket_count a given system would end up with.
|
||||
# TODO: find a way to ask the OS and ZMQ for: how many descriptors available to this process, and how many in use under zmq 2.x & 3.x respectively?
|
||||
# ALSO: factor in passed preferences for these settings.
|
||||
# update available_file_descriptors when all that becomes clear and is a bit settled.
|
||||
# current_memory = ::GxG::Engine::memory_available()[:actual]
|
||||
# TODO: GxG::Engine::engine_data_keys : determine precise socket size (32bit/64bit arch) for event zmq sockets used (exact type used).
|
||||
# GxG::Engine::profile()[:bits]
|
||||
# zmq_socket_size = 16384
|
||||
#
|
||||
# event_allocation = 0.5
|
||||
#
|
||||
# TODO: GxG::Engine::engine_data_keys : tie event allocation percentage into defaults / config.file loader.
|
||||
data << {:key => "events.max_descriptors", :platforms => [:linux], :operation => {:event_allocation => 0.5, :format => :noop}}
|
||||
# See: http://www.metabrew.com/article/a-million-user-comet-application-with-mochiweb-part-3
|
||||
# Sysctl tuning: http://www.metabrew.com/article/a-million-user-comet-application-with-mochiweb-part-1
|
||||
# LATER: develop a series of formulas for calculating approx. how many clients one can support under one 'cluster' controller (session manager).
|
||||
data.to_enum.each do |entry|
|
||||
if entry[:platforms].include?((other_platform || ::GxG::SYSTEM.platform()[:platform]))
|
||||
result << entry
|
||||
end
|
||||
end
|
||||
#
|
||||
result
|
||||
end
|
||||
#
|
||||
def self.get_engine_data(keys=[])
|
||||
# Support for <SYSTEM>.refresh_data_for(a_path) (private_method)
|
||||
# some sort of sysctl + config + etc for *all* platforms:
|
||||
# "sysctl -n net.ipv4.tcp_sack" becomes: "/net/ipv4/tcp/selective_ack" (external use path)
|
||||
# @details[:memory_limits][:buffers][:socket][:ipc] becomes colllection_point = @details.at_path(":memory_limits/:buffers/:socket/:ipc");collection_point[(key)]=value
|
||||
# procs for gathering data, and formatting for use.
|
||||
# by_platform key between sysctl/config-key and @details hash path.
|
||||
# {:synonyms => ["external-path"], :sysctl => "key-string', :format => :proc-name, :location => "hash-path", :location_key => (:sym or int)}
|
||||
#
|
||||
unless keys.is_a?(::Array)
|
||||
keys = [(keys)]
|
||||
end
|
||||
result = {}
|
||||
#
|
||||
format_noop = Proc.new do |the_data|
|
||||
the_data
|
||||
end
|
||||
format_to_int = Proc.new do |the_string|
|
||||
(the_string.numeric_values()[:integer] || 0)
|
||||
end
|
||||
format_to_float = Proc.new do |the_string|
|
||||
(the_string.numeric_values()[:float] || 0.0)
|
||||
end
|
||||
format_zerofalse = Proc.new do |the_string|
|
||||
( format_to_int.call(the_string) > 0 )
|
||||
end
|
||||
format_valid_with_initial = Proc.new do |the_string|
|
||||
raw_data = the_string.split(" ")
|
||||
{:initial => format_to_int.call(raw_data[1]), :valid => ((format_to_int.call(raw_data[0]))..(format_to_int.call(raw_data[2])))}
|
||||
end
|
||||
sysctl_read = Proc.new do |a_key,the_formatter|
|
||||
( the_formatter.call(`sysctl -n #{a_key.to_s}`.split("\n")[0]) )
|
||||
end
|
||||
getconf_read = Proc.new do |a_key, the_formatter|
|
||||
( the_formatter.call(`getconf #{a_key.to_s}`.split("\n")[0]) )
|
||||
end
|
||||
event_allocation = Proc.new do |the_allocation, the_formatter|
|
||||
# more precise zmq socket byte size goes here.
|
||||
zmq_socket_size = 16384
|
||||
#
|
||||
(((::GxG::Engine::memory_available()[:actual].to_f * the_allocation.to_f).to_i / zmq_socket_size) - 1)
|
||||
end
|
||||
#
|
||||
reference = ::GxG::Engine::engine_data_keys()
|
||||
#
|
||||
fetch_data = Proc.new do |the_key|
|
||||
data = nil
|
||||
reference.to_enum.each do |entry|
|
||||
if entry[:key] == the_key
|
||||
case entry[:operation][:format]
|
||||
when :noop
|
||||
the_formatter = format_noop
|
||||
when :zerofalse
|
||||
the_formatter = format_zerofalse
|
||||
when :to_int
|
||||
the_formatter = format_to_int
|
||||
when :to_float
|
||||
the_formatter = format_to_float
|
||||
when :valid_with_initial
|
||||
the_formatter = format_valid_with_initial
|
||||
else
|
||||
the_formatter = format_noop
|
||||
end
|
||||
if entry[:operation][:sysctl]
|
||||
data = sysctl_read.call(entry[:operation][:sysctl],the_formatter)
|
||||
else
|
||||
if entry[:operation][:getconf]
|
||||
data = getconf_read.call(entry[:operation][:getconf],the_formatter)
|
||||
else
|
||||
if entry[:operation][:event_allocation]
|
||||
data = event_allocation.call(entry[:operation][:event_allocation],the_formatter)
|
||||
else
|
||||
#
|
||||
end
|
||||
#
|
||||
end
|
||||
end
|
||||
if data
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
data
|
||||
end
|
||||
#
|
||||
keys.to_enum.each do |specifier|
|
||||
if specifier.is_a?(::String)
|
||||
# if element is String: serves as result Hash key to hold result value.
|
||||
# single result with this result key
|
||||
result[(specifier)] = fetch_data.call(specifier)
|
||||
else
|
||||
if specifier.is_a?(::Hash)
|
||||
# if element is Hash: {ukey => hash_path}, {:key => <keystring>, :path => <hash_path>}
|
||||
# if hash_path supplied, read the data; set the @details hash element, and return the formatted data
|
||||
if specifier[:key]
|
||||
# {:key => <keystring>, :path => <hash_path>}
|
||||
result[(specifier[:key])] = fetch_data.call(specifier[:key])
|
||||
if specifier[:path]
|
||||
@@thread_safety.synchronize {
|
||||
@@details.set_at_path(specifier[:path],result[(specifier[:key])])
|
||||
}
|
||||
end
|
||||
else
|
||||
# {ukey => hash_path}
|
||||
subkeys = specifier.keys
|
||||
subkeys.to_enum.each do |a_key|
|
||||
result[(a_key)] = fetch_data.call(a_key)
|
||||
@@thread_safety.synchronize {
|
||||
@@details.set_at_path(specifier[(a_key)],result[(a_key)])
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
result
|
||||
end
|
||||
#
|
||||
def self.set_engine_data(keys=[])
|
||||
# LATER: GxG::Engine::set_engine_data : when you figure out system(sudo) authentication - use this for ops that require elevated privs to set system parameters.
|
||||
# Define a set of universal_keys that affect what other keys; upon setting any one, unique-list a set of keys to read back in w/ hash paths.
|
||||
result = nil
|
||||
if nil
|
||||
::GxG::Engine::get_engine_data(nil,nil)
|
||||
# compare hash value to the_value; return true if successful
|
||||
end
|
||||
result
|
||||
end
|
||||
# ### Descriptors in general
|
||||
def self.descriptor_limits()
|
||||
{:events => @@details[:events][:maximum_event_descriptors], :files => @@details[:files][:maximum_file_descriptors]}.clone
|
||||
end
|
||||
#
|
||||
def self.descriptor_heap_used()
|
||||
result = {:total => 0}
|
||||
slot_size = ::GxG::Engine::profile[:slot_size]
|
||||
file_total = 0
|
||||
GxG::Engine::file_descriptors().to_enum.each do |item|
|
||||
file_total += item.heap_used()
|
||||
end
|
||||
@@thread_safety.synchronize {
|
||||
result[:files] = file_total
|
||||
unless ::GxG::Engine::descriptor_limits()[:events] == :files
|
||||
# see available_file_descriptors : beware counting event descriptors twice (w/ file descriptors)
|
||||
# TODO: GxG::Engine::descriptor_heap_used : sync w/ more precise event socket size determination
|
||||
result[:events] = (@@event_descriptors * (slot_size + 4))
|
||||
end
|
||||
}
|
||||
result[:total] = (result[:files].to_i + result[:events].to_i)
|
||||
#
|
||||
result
|
||||
end
|
||||
# ### File Descriptors
|
||||
def self.maximum_file_descriptors()
|
||||
::GxG::Engine::descriptor_limits()[:files]
|
||||
end
|
||||
#
|
||||
def self.file_descriptors()
|
||||
# Return an Array of currently opened file descriptors.
|
||||
# About File Descriptors: http://stackoverflow.com/questions/848717/handling-more-than-1024-file-descriptors-in-c-on-linux
|
||||
#
|
||||
result = []
|
||||
exclude_list = []
|
||||
[::IO, ::IO::descendants()].flatten!.to_enum.each do |the_class|
|
||||
unless exclude_list.include?(the_class)
|
||||
::ObjectSpace.each_object(the_class) do |the_io|
|
||||
unless (the_io.closed? || result.include?(the_io))
|
||||
result << the_io
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def self.available_file_descriptors()
|
||||
(::GxG::Engine::maximum_file_descriptors() - ::GxG::Engine::file_descriptors().size)
|
||||
end
|
||||
#
|
||||
# ### Event Descriptors
|
||||
def self.maximum_event_descriptors()
|
||||
::GxG::Engine::descriptor_limits()[:events]
|
||||
end
|
||||
#
|
||||
def self.event_descriptors_threshold()
|
||||
# Percentage of allocation that must be available for events to be released.
|
||||
@@thread_safety.synchronize {
|
||||
@@details[:events][:event_descriptors_threshold].clone
|
||||
}
|
||||
end
|
||||
#
|
||||
def self.event_minimum_threshold()
|
||||
# Percentage of allocation that must be available for events to be released.
|
||||
@@thread_safety.synchronize {
|
||||
@@details[:events][:event_minimum_threshold].clone
|
||||
}
|
||||
end
|
||||
#
|
||||
def self.events_in_use()
|
||||
@@thread_safety.synchronize {
|
||||
@@event_descriptors
|
||||
}
|
||||
end
|
||||
#
|
||||
def self.available_event_descriptors()
|
||||
result = 0
|
||||
current = 0
|
||||
@@thread_safety.synchronize {
|
||||
current = (::GxG::Engine::maximum_event_descriptors() - @@event_descriptors)
|
||||
}
|
||||
if current > 0
|
||||
result = current
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def self.reserve_event_descriptor()
|
||||
result = false
|
||||
if ::GxG::Engine::available_event_descriptors() > 0
|
||||
@@thread_safety.synchronize {
|
||||
@@event_descriptors += 1
|
||||
}
|
||||
result = true
|
||||
else
|
||||
raise Errno::ENOMEM, "maximum number of event descriptors in use (#{GxG::Engine::maximum_event_descriptors().to_s})"
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def self.release_event_descriptor()
|
||||
result = false
|
||||
@@thread_safety.synchronize {
|
||||
if @@event_descriptors > 0
|
||||
@@event_descriptors -= 1
|
||||
end
|
||||
}
|
||||
result = true
|
||||
result
|
||||
end
|
||||
#
|
||||
def self.determine_event_allocations()
|
||||
#
|
||||
total = ::GxG::Engine::maximum_event_descriptors()
|
||||
dispatchers = []
|
||||
[::GxG::Events::EventDispatcher, ::GxG::Events::EventDispatcher::descendants()].flatten!.each do |the_class|
|
||||
::ObjectSpace.each_object(the_class) do |the_dispatcher|
|
||||
if the_dispatcher.alive?()
|
||||
if the_dispatcher.running?()
|
||||
dispatchers << the_dispatcher
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
# Note : a ghost-dispatcher representing all other system funcitons is added to the dispatcher count.
|
||||
maximum_events = (total.to_f / (dispatchers.size + 1).to_f).to_i
|
||||
threshold = (maximum_events.to_f * ::GxG::Engine::event_descriptors_threshold().to_f).to_i
|
||||
unless threshold > 0
|
||||
threshold = 1
|
||||
end
|
||||
@@thread_safety.synchronize {
|
||||
@@details[:events][:event_minimum_threshold] = threshold
|
||||
@@details[:events][:event_descriptors_envelope] = ((threshold)..(maximum_events))
|
||||
}
|
||||
true
|
||||
end
|
||||
#
|
||||
def self.event_allocation_envelope()
|
||||
result = (20..100)
|
||||
@@thread_safety.synchronize {
|
||||
result = @@details[:events][:event_descriptors_envelope]
|
||||
}
|
||||
result
|
||||
end
|
||||
#
|
||||
end
|
||||
# FIX / Review : this appears to set file and event max descriptors to NIL on Winderz. Do I need this?
|
||||
# ::GxG::Engine::get_engine_data(::GxG::Engine::detail_mapping())
|
||||
#
|
||||
end
|
||||
#
|
||||
2169
lib/gxg/gxg_entities.rb
Normal file
2169
lib/gxg/gxg_entities.rb
Normal file
File diff suppressed because it is too large
Load diff
774
lib/gxg/gxg_events.rb
Normal file
774
lib/gxg/gxg_events.rb
Normal file
|
|
@ -0,0 +1,774 @@
|
|||
#
|
||||
module GxG
|
||||
#
|
||||
module Events
|
||||
#
|
||||
class Message
|
||||
#
|
||||
def initialize(*args)
|
||||
# MUST provide a hash with at least :sender message field set
|
||||
# {:sender => <some-object>, :body => <some-object>, :on_success => <some-proc>, :on_fail => <some-proc> }
|
||||
unless args[0].is_a?(::Hash)
|
||||
raise ArgumentError, "you must pass a Hash to create the message"
|
||||
end
|
||||
@data = {:sender => nil, :id => (::GxG::uuid_generate().to_s.to_sym), :ufs => :"org.gxg.message", :subject => args[1], :body => nil, :on_success => nil, :on_fail => nil}.merge(args[0])
|
||||
unless @data[:sender]
|
||||
raise ArgumentError, "you must set the :sender key in the argument Hash"
|
||||
end
|
||||
self
|
||||
end
|
||||
#
|
||||
def inspect()
|
||||
@data.inspect
|
||||
end
|
||||
#
|
||||
def id()
|
||||
@data[:id]
|
||||
end
|
||||
#
|
||||
def sender()
|
||||
@data[:sender]
|
||||
end
|
||||
#
|
||||
def subject()
|
||||
@data[:subject]
|
||||
end
|
||||
# ### Universal Format Specifier of the body attribute.
|
||||
def ufs()
|
||||
@data[:ufs]
|
||||
end
|
||||
#
|
||||
def ufs=(the_format=nil)
|
||||
if the_format.is_any(::String, ::Symbol)
|
||||
@data[:ufs] = the_format.to_s.to_sym
|
||||
end
|
||||
end
|
||||
#
|
||||
def body()
|
||||
@data[:body]
|
||||
end
|
||||
#
|
||||
def compose_reply(&block)
|
||||
if block.respond_to?(:call)
|
||||
# Review : consider just cloning the @data variable and swapping sender/to.
|
||||
reply_message = ::GxG::Events::Message.new({:sender => self[:to], :to => self[:sender], :ufs => self.ufs(), :context => self[:context], :subject => self[:subject], :body => self[:body]})
|
||||
block.call(reply_message)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
#
|
||||
def succeed(input=nil)
|
||||
if @data[:on_success].respond_to?(:call)
|
||||
@data[:on_success].call(input)
|
||||
end
|
||||
end
|
||||
#
|
||||
def fail(input=nil)
|
||||
if @data[:on_fail].respond_to?(:call)
|
||||
@data[:on_fail].call(input)
|
||||
end
|
||||
end
|
||||
#
|
||||
def on(event_type=nil,&block)
|
||||
if [:success, :fail].include?(event_type)
|
||||
if block.respond_to?(:call)
|
||||
case event_type
|
||||
when :success
|
||||
@data[:on_success] = block
|
||||
when :fail
|
||||
@data[:on_fail] = block
|
||||
end
|
||||
else
|
||||
raise ArgumentError, "You MUST provide a callable block."
|
||||
end
|
||||
else
|
||||
# Custom Events:
|
||||
@data[(("on_" + event_type.to_s.downcase).to_sym)] = block
|
||||
end
|
||||
end
|
||||
#
|
||||
def respond_to_event?(event_type=nil)
|
||||
result = false
|
||||
if event_type.is_any(::String, ::Symbol)
|
||||
if @data[(("on_" + event_type.to_s.downcase).to_sym)]
|
||||
result = true
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
def call_event(operation_envelope=nil)
|
||||
result = nil
|
||||
if operation_envelope.is_a?(::Hash)
|
||||
the_event = operation_envelope.keys[0]
|
||||
if self.respond_to?(the_event)
|
||||
data = operation_envelope[(the_event)]
|
||||
result = {:result => @data[(("on_" + event_type.to_s.downcase).to_sym)].call(data)}
|
||||
else
|
||||
result = {:result => nil, :error => "Command #{the_event.inspect} Not Found"}
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
# Hash-like support methods:
|
||||
def keys()
|
||||
@data.keys()
|
||||
end
|
||||
def [](the_key)
|
||||
@data[(the_key)]
|
||||
end
|
||||
def []=(the_key, the_value)
|
||||
@data[(the_key)] = the_value
|
||||
end
|
||||
def process(&block)
|
||||
@data.process(&block)
|
||||
end
|
||||
def process!(&block)
|
||||
@data.process!(&block)
|
||||
end
|
||||
def search(&block)
|
||||
@data.search(&block)
|
||||
end
|
||||
def paths_to(*args)
|
||||
@data.paths_to(*args)
|
||||
end
|
||||
def get_at_path(*args)
|
||||
@data.get_at_path(*args)
|
||||
end
|
||||
def set_at_path(*args)
|
||||
@data.set_at_path(*args)
|
||||
end
|
||||
end
|
||||
#
|
||||
class LoggerDB
|
||||
#
|
||||
end
|
||||
class LogRing < ::Logger
|
||||
#
|
||||
def initialize(*args)
|
||||
super(::STDOUT)
|
||||
@thread_safety = ::Mutex.new
|
||||
@busy = false
|
||||
@messages = []
|
||||
@outlets = {}
|
||||
self
|
||||
end
|
||||
#
|
||||
def keys()
|
||||
@thread_safety.synchronize { @outlets.keys() }
|
||||
end
|
||||
def [](the_key)
|
||||
@thread_safety.synchronize { @outlets[(the_key)] }
|
||||
end
|
||||
def []=(the_key,the_logger)
|
||||
if the_logger.is_any?(::Logger, ::GxG::Events::LoggerDB)
|
||||
@thread_safety.synchronize { @outlets[(the_key)] = the_logger }
|
||||
the_logger
|
||||
else
|
||||
raise ArgumentError, "You must supply a Logger or GxG::Events::LoggerDB instance, you provided a #{the_logger.class}"
|
||||
end
|
||||
end
|
||||
# ### Message handlers
|
||||
def post(the_message=nil)
|
||||
if the_message.is_a?(::GxG::Events::Message)
|
||||
@thread_safety.synchronize { @messages << the_message }
|
||||
true
|
||||
else
|
||||
false
|
||||
end
|
||||
end
|
||||
#
|
||||
def next_message()
|
||||
@thread_safety.synchronize { @messages.shift }
|
||||
end
|
||||
#
|
||||
def process_messages()
|
||||
unless @thread_safety.synchronize { @busy == true }
|
||||
@thread_safety.synchronize { @busy = true }
|
||||
#
|
||||
the_message = self.next_message()
|
||||
if the_message.is_a?(::GxG::Events::Message)
|
||||
begin
|
||||
if the_message[:subject] == :notification
|
||||
if the_message[:body].is_a?(::Hash)
|
||||
outlets = this.keys()
|
||||
outlets.to_enum(:each).each do |the_outlet_key|
|
||||
the_outlet = this()[(the_outlet_key)]
|
||||
if (the_message[:body][:severity] || ::Logger::UNKNOWN) >= the_outlet.level()
|
||||
# output
|
||||
if the_outlet.is_a?(::GxG::Events::LoggerDB)
|
||||
# TODO: GxG::Events::LogRing : build out object-based event logging:
|
||||
else
|
||||
# conventional string based:
|
||||
if (the_message[:body][:message].is_a?(::String) || the_message[:body][:message].is_a?(::Exception))
|
||||
the_outlet.add(the_message[:body][:severity], the_message[:body][:message], the_message[:body][:progname])
|
||||
else
|
||||
if the_message[:body][:message].is_a?(::Hash)
|
||||
#
|
||||
if the_message[:body][:message][:error].is_a?(::Exception)
|
||||
if the_message[:body][:message][:error].backtrace.is_a?(::Array)
|
||||
if the_message[:body][:message][:parameters]
|
||||
the_outlet.add(the_message[:body][:severity], ("\n #{the_message[:body][:message][:error].exception.class.to_s}: " + the_message[:body][:message][:error].to_s + "\n Parameters: " + the_message[:body][:message][:parameters].inspect + "\n Trace: " + the_message[:body][:message][:error].backtrace.join("\n") + "\n"), the_message[:body][:progname])
|
||||
else
|
||||
the_outlet.add(the_message[:body][:severity], ("\n #{the_message[:body][:message][:error].exception.class.to_s}: " + the_message[:body][:message][:error].to_s + "\n Trace: " + the_message[:body][:message][:error].backtrace.join("\n") + "\n"), the_message[:body][:progname])
|
||||
end
|
||||
else
|
||||
if the_message[:body][:message][:parameters]
|
||||
the_outlet.add(the_message[:body][:severity], ("\n #{the_message[:body][:message][:error].exception.class.to_s}: " + the_message[:body][:message][:error].to_s + "\n Parameters: " + the_message[:body][:message][:parameters].inspect + "\n"), the_message[:body][:progname])
|
||||
else
|
||||
the_outlet.add(the_message[:body][:severity], ("\n #{the_message[:body][:message][:error].exception.class.to_s}: " + the_message[:body][:message][:error].to_s + "\n"), the_message[:body][:progname])
|
||||
end
|
||||
end
|
||||
else
|
||||
the_outlet.add(the_message[:body][:severity], the_message[:body][:message].inspect, the_message[:body][:progname])
|
||||
end
|
||||
else
|
||||
the_outlet.add(the_message[:body][:severity], the_message[:body][:message].inspect, the_message[:body][:progname])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
end
|
||||
end
|
||||
end
|
||||
rescue Exception => the_error
|
||||
log_error({:error => the_error, :parameters => {:message => the_message}})
|
||||
end
|
||||
end
|
||||
#
|
||||
@thread_safety.synchronize { @busy = false }
|
||||
end
|
||||
true
|
||||
end
|
||||
#
|
||||
def add(severity = nil, message = nil, progname = nil, origin = nil, &block)
|
||||
#
|
||||
unless [::Logger::DEBUG, ::Logger::INFO, ::Logger::WARN, ::Logger::ERROR, ::Logger::FATAL, ::Logger::UNKNOWN].include?(severity)
|
||||
severity = ::Logger::UNKNOWN
|
||||
end
|
||||
if progname
|
||||
unless message
|
||||
message = progname
|
||||
progname = nil
|
||||
end
|
||||
end
|
||||
begin
|
||||
unless message
|
||||
if block.respond_to?(:call)
|
||||
message = block.call()
|
||||
end
|
||||
end
|
||||
# this.mailbox << ::GxG::Events::Message.new({:sender => (origin || this), :severity => severity, :message => message, :progname => progname})
|
||||
the_message = new_message({:sender => (origin || self), :ufs => :"org.gxg.message.notification", :severity => severity, :message => message, :progname => progname}, :notification)
|
||||
self.post(the_message)
|
||||
true
|
||||
rescue => the_error
|
||||
log_error({:error => the_error, :parameters => {:severity => severity, :message => message, :progname => progname, :block => block}})
|
||||
false
|
||||
end
|
||||
end
|
||||
def unknown?()
|
||||
true
|
||||
end
|
||||
alias :trace? :unknown?
|
||||
def unknown(message = nil, progname = nil, origin = nil, &block)
|
||||
if self.alive?()
|
||||
self.add(::Logger::UNKNOWN, message, progname, (origin || self), &block)
|
||||
end
|
||||
end
|
||||
alias :trace :unknown
|
||||
def fatal?()
|
||||
true
|
||||
end
|
||||
def fatal(message = nil, progname = nil, origin = nil, &block)
|
||||
if self.alive?()
|
||||
self.add(::Logger::FATAL, message, progname, (origin || self), &block)
|
||||
end
|
||||
end
|
||||
def error?()
|
||||
true
|
||||
end
|
||||
def error(message = nil, progname = nil, origin = nil, &block)
|
||||
if self.alive?()
|
||||
self.add(::Logger::ERROR, message, progname, (origin || self), &block)
|
||||
end
|
||||
end
|
||||
def warn?()
|
||||
true
|
||||
end
|
||||
alias :warning? :warn?
|
||||
def warn(message = nil, progname = nil, origin = nil, &block)
|
||||
if self.alive?()
|
||||
self.add(::Logger::WARN, message, progname, (origin || self), &block)
|
||||
end
|
||||
end
|
||||
alias :warning :warn
|
||||
def info?()
|
||||
true
|
||||
end
|
||||
def info(message = nil, progname = nil, origin = nil, &block)
|
||||
if self.alive?()
|
||||
self.add(::Logger::INFO, message, progname, (origin || self), &block)
|
||||
end
|
||||
end
|
||||
def debug?()
|
||||
true
|
||||
end
|
||||
def debug(message = nil, progname = nil, origin = nil, &block)
|
||||
if self.alive?()
|
||||
self.add(::Logger::DEBUG, message, progname, (origin || self), &block)
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
# Provide a Cooperative Processing facility for sessions
|
||||
class EventDispatcher
|
||||
def initialize(interval=0.333, thread_reservation=100)
|
||||
super()
|
||||
@reserved_threads = (thread_reservation.to_i || 100)
|
||||
@uuid = ::GxG::uuid_generate().to_sym
|
||||
@event_queues = {:root => {:events => [], :settings => {:active => true, :portion => 100.0}}}
|
||||
@running = false
|
||||
@ticking = false
|
||||
# Timer format: {:when => Time_Object.to_f, :what => event_frame, :interval => float, :id => uuid.sym}
|
||||
@timers = []
|
||||
@scheduler = Rufus::Scheduler.new(:max_work_threads => @reserved_threads)
|
||||
def @scheduler.on_error(job, error)
|
||||
log_error({:error => error, :parameters => {:job => job}})
|
||||
end
|
||||
@scheduler.pause
|
||||
@tick_timer = nil
|
||||
@tick_interval = interval
|
||||
#
|
||||
self
|
||||
end
|
||||
#
|
||||
def running?()
|
||||
@running
|
||||
end
|
||||
#
|
||||
def startup()
|
||||
@running = true
|
||||
if @scheduler.paused?
|
||||
@scheduler.resume
|
||||
end
|
||||
unless @tick_timer
|
||||
@tick_timer = @scheduler.every(@tick_interval) do
|
||||
tick
|
||||
end
|
||||
end
|
||||
@reserved_threads.times do
|
||||
begin
|
||||
::GxG::Engine::reserve_event_descriptor()
|
||||
rescue Exception => the_error
|
||||
log_error({:error => the_error})
|
||||
break
|
||||
end
|
||||
end
|
||||
@running
|
||||
end
|
||||
#
|
||||
def shutdown()
|
||||
@running = false
|
||||
if @tick_timer
|
||||
self.cancel_timer(@tick_timer)
|
||||
@tick_timer = nil
|
||||
@scheduler.pause
|
||||
@reserved_threads.times do
|
||||
::GxG::Engine::release_event_descriptor()
|
||||
end
|
||||
end
|
||||
true
|
||||
end
|
||||
#
|
||||
def tick()
|
||||
if @running
|
||||
unless @ticking
|
||||
@ticking = true
|
||||
events = []
|
||||
envelope = ::GxG::Engine::event_allocation_envelope()
|
||||
if envelope.last >= envelope.first
|
||||
prefetch = {}
|
||||
@event_queues.keys.each do |the_queue|
|
||||
if (@event_queues[(the_queue)][:settings][:active] && @event_queues[(the_queue)][:events].size > 0)
|
||||
((@event_queues[(the_queue)][:settings][:portion].to_f / 100.0) * envelope.last.to_f).to_i.times do
|
||||
op = @event_queues[(the_queue)][:events].shift
|
||||
if op.respond_to?(:call)
|
||||
(prefetch[(the_queue)] ||= []) << op
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
prefetch_count = 0
|
||||
prefetch.keys.each do |the_queue|
|
||||
prefetch_count += prefetch[(the_queue)].size
|
||||
end
|
||||
#
|
||||
while prefetch_count > 0 do
|
||||
prefetch.keys.each do |the_queue|
|
||||
op = prefetch[(the_queue)].shift
|
||||
if op
|
||||
events << op
|
||||
end
|
||||
prefetch_count -= 1
|
||||
end
|
||||
end
|
||||
#
|
||||
end
|
||||
# xxx old version:
|
||||
# queues = {}
|
||||
# load_size = 0
|
||||
# @event_queues.keys.each do |the_queue|
|
||||
# if (@event_queues[(the_queue)][:settings][:active] && @event_queues[(the_queue)][:events].size > 0)
|
||||
# queues[(the_queue)] = {:portion => ((@event_queues[(the_queue)][:settings][:portion].to_f / 100.0) * total_slots.to_f).to_i}
|
||||
# if queues[(the_queue)][:portion] == 0
|
||||
# # Fudging a little here in case of real heavy loads and/or too many queues.
|
||||
# queues[(the_queue)][:portion] = 1
|
||||
# end
|
||||
# queues[(the_queue)][:size] = @event_queues[(the_queue)][:events].size
|
||||
# load_size += queues[(the_queue)][:size]
|
||||
# end
|
||||
# end
|
||||
# queues.keys.each do |the_queue|
|
||||
# # TODO: devise apportioned event dispatch
|
||||
# queues[(the_queue)][:portion].times do
|
||||
# op = @event_queues[(the_queue)][:events].shift
|
||||
# if op.respond_to?(:call)
|
||||
# events << op
|
||||
# else
|
||||
# break
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
#
|
||||
events.each do |the_event|
|
||||
if the_event
|
||||
Thread.new do
|
||||
::GxG::Engine::reserve_event_descriptor()
|
||||
begin
|
||||
the_event.call()
|
||||
rescue Exception => the_error
|
||||
log_error({:error => the_error})
|
||||
end
|
||||
::GxG::Engine::release_event_descriptor()
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
@ticking = false
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
def inspect_timers()
|
||||
@scheduler.jobs()
|
||||
end
|
||||
def inspect_queue(queue=:root)
|
||||
@event_queues[(queue)]
|
||||
end
|
||||
#
|
||||
def adjust_event_queue(queue=:root,settings={})
|
||||
# RESEARCH: GxG::Events::EventDispatcher.adjust_event_queue : refactor :portion of each queue algo needed.
|
||||
unless queue.to_s.to_sym == :root
|
||||
if @event_queues[(queue.to_sym)]
|
||||
# LATER: Eventually add :portion as valid setting to accept.
|
||||
[:active].each do |the_setting|
|
||||
if settings[(the_setting.to_sym)]
|
||||
new_setting = {}
|
||||
# portion adjustment algo here
|
||||
new_setting[(the_setting.to_sym)] = settings[(the_setting.to_sym)]
|
||||
#
|
||||
@event_queues[(queue.to_sym)][:settings].merge!(new_setting)
|
||||
end
|
||||
end
|
||||
else
|
||||
puts "Warning: queue #{queue.inspect} does not exist"
|
||||
# For Now: just ignore references to non-existent queues. (reconsider later)
|
||||
# raise ArgumentError, "Event Queue :#{queue} does not exist to alter"
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
def create_event_queue(settings={})
|
||||
unless settings.is_a?(Hash)
|
||||
raise ArgumentError, "you must provide a Hash as a parameter set"
|
||||
end
|
||||
queue_name = settings.delete(:name).to_s.to_sym
|
||||
if queue_name.to_s.size > 0
|
||||
if @event_queues[(queue_name)]
|
||||
raise ArgumentError, "Event Queue #{queue_name.inspect} already exists"
|
||||
else
|
||||
@event_queues[(queue_name)] = {:events => [], :settings => {:active => false, :portion => 0.0}}
|
||||
# For Now: simply evenly divide the portions equally, only :root can be 100%.
|
||||
even_portion = (100.0 / @event_queues.keys.size.to_f)
|
||||
@event_queues.keys.each do |the_queue|
|
||||
@event_queues[(the_queue)][:settings][:portion] = (even_portion)
|
||||
end
|
||||
self.adjust_event_queue(queue_name, settings.merge({:active => true}))
|
||||
true
|
||||
end
|
||||
else
|
||||
raise ArgumentError, ":name must be provided for Event Queue"
|
||||
end
|
||||
end
|
||||
#
|
||||
def delete_event_queue(queue=nil)
|
||||
if queue.to_s.to_sym == :root
|
||||
false
|
||||
else
|
||||
@event_queues.delete(queue)
|
||||
# For Now: simply evenly divide the portions equally, only :root can be 100%.
|
||||
even_portion = (@event_queues.keys.size.to_f / 100.0)
|
||||
@event_queues.keys.each do |the_queue|
|
||||
@event_queues[(the_queue)][:settings][:portion] = (even_portion)
|
||||
end
|
||||
true
|
||||
end
|
||||
end
|
||||
#
|
||||
def pause_event_queue(queue=nil)
|
||||
unless queue.to_s.to_sym == :root
|
||||
self.adjust_event_queue(queue,{:active => true})
|
||||
end
|
||||
end
|
||||
#
|
||||
def unpause_event_queue(queue=nil)
|
||||
unless queue.to_s.to_sym == :root
|
||||
self.adjust_event_queue(queue,{:active => false})
|
||||
end
|
||||
end
|
||||
#
|
||||
def post_to_event_queue(queue=:root,the_event=nil)
|
||||
if the_event.respond_to?(:call)
|
||||
if @event_queues[(queue)]
|
||||
@event_queues[(queue)][:events] << the_event
|
||||
else
|
||||
# issue a warning, and post to :root queue anyways (for now). (link to logger, and output)
|
||||
@event_queues[:root][:events] << the_event
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
def post_event(queue_name=:root,&block)
|
||||
unless @event_queues[(queue_name.to_sym)]
|
||||
self.create_event_queue({:name => queue_name.to_sym})
|
||||
end
|
||||
self.post_to_event_queue(queue_name.to_sym,block)
|
||||
true
|
||||
end
|
||||
# Adding Timers
|
||||
# See: https://stackoverflow.com/questions/235504/validating-crontab-entries-with-php
|
||||
# Cron REGEX: /^((?:[1-9]?\d|\*)\s*(?:(?:[\/-][1-9]?\d)|(?:,[1-9]?\d)+)?\s*){5}$/
|
||||
# Rufus Duration REGEX: /^(-?)([\d\.smhdwy]+)$/
|
||||
# at, in, every, cron
|
||||
#
|
||||
def cancel_timer(timer_reference=nil)
|
||||
@scheduler.jobs().each do |the_task|
|
||||
if the_task.job_id == timer_reference
|
||||
the_task.unschedule
|
||||
break
|
||||
end
|
||||
end
|
||||
true
|
||||
end
|
||||
#
|
||||
def at(expression="",&block)
|
||||
the_time = nil
|
||||
case expression.class
|
||||
when ::DateTime
|
||||
the_time = expression.to_time()
|
||||
when ::Time
|
||||
the_time = expression
|
||||
when ::String
|
||||
the_time = ::Chronic::parse(expression)
|
||||
unless the_time
|
||||
raise ArgumentError, "Invalid time expression: #{expression.inspect}"
|
||||
end
|
||||
else
|
||||
raise ArgumentError, "Invalid time expression: #{expression.inspect}"
|
||||
end
|
||||
if the_time
|
||||
if block.respond_to?(:call)
|
||||
event_frame = Proc.new {
|
||||
GxG::Engine.reserve_event_descriptor()
|
||||
block.call()
|
||||
GxG::Engine.release_event_descriptor()
|
||||
}
|
||||
@scheduler.at(the_time.iso8601,&event_frame)
|
||||
else
|
||||
nil
|
||||
end
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
#
|
||||
def in(expression="", &block)
|
||||
if expression.is_a?(::Numeric)
|
||||
interval = expression
|
||||
else
|
||||
if expression.include?(" ")
|
||||
# parse to Rufus duration
|
||||
duration_type = nil
|
||||
interval = nil
|
||||
expression.split(" ").each do |entry|
|
||||
if duration_type && interval
|
||||
break
|
||||
else
|
||||
if ["s","second", "seconds"].include?(entry)
|
||||
duration_type = "s"
|
||||
end
|
||||
if ["m","minute", "minutes"].include?(entry)
|
||||
duration_type = "m"
|
||||
end
|
||||
if ["h","hour", "hours"].include?(entry)
|
||||
duration_type = "h"
|
||||
end
|
||||
if ["d","day", "days"].include?(entry)
|
||||
duration_type = "d"
|
||||
end
|
||||
if ["w","week", "weeks"].include?(entry)
|
||||
duration_type = "w"
|
||||
end
|
||||
if /[-+0-9.,]*/.match(entry).to_s.size > 0
|
||||
if entry.include?(".")
|
||||
interval = entry.to_f
|
||||
else
|
||||
interval = entry.to_i
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
interval = (interval.to_s + duration_type.to_s)
|
||||
else
|
||||
# Verify standard Rufus expression
|
||||
duration_type = expression.split(/[-+0-9.,]*/)[1].to_s
|
||||
if ["s","m","h","d","w"].include?(duration_type.downcase)
|
||||
interval = /[-+0-9.,]*/.match(expression).to_s.to_i
|
||||
if interval > 0
|
||||
interval = (interval.to_s + duration_type.to_s)
|
||||
else
|
||||
raise ArgumentError, "Invalid interval expression: #{expression.inspect}"
|
||||
end
|
||||
else
|
||||
raise ArgumentError, "Invalid interval expression: #{expression.inspect}"
|
||||
end
|
||||
end
|
||||
end
|
||||
if block.respond_to?(:call)
|
||||
event_frame = Proc.new {
|
||||
GxG::Engine.reserve_event_descriptor()
|
||||
block.call()
|
||||
GxG::Engine.release_event_descriptor()
|
||||
}
|
||||
@scheduler.in(interval,&event_frame)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
#
|
||||
def every(expression="", &block)
|
||||
if expression.is_a?(::Numeric)
|
||||
interval = expression
|
||||
else
|
||||
if expression.include?(" ")
|
||||
# parse to Rufus duration
|
||||
duration_type = nil
|
||||
interval = nil
|
||||
expression.split(" ").each do |entry|
|
||||
if duration_type && interval
|
||||
break
|
||||
else
|
||||
if ["s","second", "seconds"].include?(entry)
|
||||
duration_type = "s"
|
||||
end
|
||||
if ["m","minute", "minutes"].include?(entry)
|
||||
duration_type = "m"
|
||||
end
|
||||
if ["h","hour", "hours"].include?(entry)
|
||||
duration_type = "h"
|
||||
end
|
||||
if ["d","day", "days"].include?(entry)
|
||||
duration_type = "d"
|
||||
end
|
||||
if ["w","week", "weeks"].include?(entry)
|
||||
duration_type = "w"
|
||||
end
|
||||
if /[-+0-9.,]*/.match(entry).to_s.size > 0
|
||||
if entry.include?(".")
|
||||
interval = entry.to_f
|
||||
else
|
||||
interval = entry.to_i
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
the_interval = (interval.to_s + duration_type.to_s)
|
||||
else
|
||||
# Verify standard Rufus expression
|
||||
duration_type = expression.split(/[-+0-9.,]*/)[1].to_s
|
||||
if ["s","m","h","d","w"].include?(duration_type.downcase)
|
||||
interval = /[-+0-9.,]*/.match(expression).to_s.to_i
|
||||
if interval > 0
|
||||
the_interval = (interval.to_s + duration_type.to_s)
|
||||
else
|
||||
raise ArgumentError, "Invalid interval expression: #{expression.inspect}"
|
||||
end
|
||||
else
|
||||
raise ArgumentError, "Invalid interval expression: #{expression.inspect}"
|
||||
end
|
||||
end
|
||||
end
|
||||
if block.respond_to?(:call)
|
||||
event_frame = Proc.new {
|
||||
GxG::Engine.reserve_event_descriptor()
|
||||
block.call()
|
||||
GxG::Engine.release_event_descriptor()
|
||||
}
|
||||
@scheduler.every(the_interval,&event_frame)
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
#
|
||||
def cron(expression="",&block)
|
||||
if /^((?:[1-9]?\d|\*)\s*(?:(?:[\/-][1-9]?\d)|(?:,[1-9]?\d)+)?\s*){5}$/.match(expression)
|
||||
if block.respond_to?(:call)
|
||||
event_frame = Proc.new {
|
||||
GxG::Engine.reserve_event_descriptor()
|
||||
block.call()
|
||||
GxG::Engine.release_event_descriptor()
|
||||
}
|
||||
@scheduler.cron(expression,&event_frame)
|
||||
else
|
||||
nil
|
||||
end
|
||||
else
|
||||
raise ArgumentError, "Invalid CRON expression: #{expression.inspect}"
|
||||
end
|
||||
end
|
||||
#
|
||||
end
|
||||
#
|
||||
end
|
||||
#
|
||||
module EventManager
|
||||
#
|
||||
def self.manager_running?()
|
||||
result = false
|
||||
if $Dispatcher
|
||||
result = $Dispatcher.running?
|
||||
end
|
||||
result
|
||||
end
|
||||
end
|
||||
# ### Re-define the LOG Constant
|
||||
if const_defined?(:LOG)
|
||||
remove_const(:LOG)
|
||||
end
|
||||
LOG = ::GxG::Events::LogRing.new()
|
||||
end
|
||||
#
|
||||
2717
lib/gxg/gxg_io.rb
Normal file
2717
lib/gxg/gxg_io.rb
Normal file
File diff suppressed because it is too large
Load diff
810
lib/gxg/gxg_net.rb
Normal file
810
lib/gxg/gxg_net.rb
Normal file
|
|
@ -0,0 +1,810 @@
|
|||
module GxG
|
||||
module Networking
|
||||
#
|
||||
def self.buffer_limits(direction=:in, whatfor=nil)
|
||||
limits = GxG::SYSTEM.memory_limits()[:buffers]
|
||||
result = {:initial=>0, :valid=>0..0}
|
||||
# unless whatfor.is_a?(::Symbol)
|
||||
# # :unknown will play it safe with :socket buffer limits
|
||||
# whatfor = :socket
|
||||
# #
|
||||
# if self.is_any?(::UNIXServer, ::UNIXSocket, ::Socket)
|
||||
# whatfor = :socket
|
||||
# else
|
||||
# if self.is_any?(::TCPServer, ::SOCKSocket, ::TCPSocket)
|
||||
# whatfor = :tcp
|
||||
# else
|
||||
# if self.is_any?(::UDPServer, ::UDPSource, ::UDPSocket)
|
||||
# whatfor = :udp
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
case whatfor
|
||||
when :socket
|
||||
if direction == :in
|
||||
result = limits[:socket][:ipc][:read].clone
|
||||
else
|
||||
result = limits[:socket][:ipc][:write].clone
|
||||
end
|
||||
when :tcp
|
||||
if direction == :in
|
||||
result = limits[:ipv4][:tcp][:read].clone
|
||||
else
|
||||
result = limits[:ipv4][:tcp][:write].clone
|
||||
end
|
||||
when :udp
|
||||
if direction == :in
|
||||
result = limits[:ipv4][:udp][:read].clone
|
||||
else
|
||||
result = limits[:ipv4][:udp][:write].clone
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
end
|
||||
end
|
||||
# WRONG Direction : there for pickings - eventually deleted.
|
||||
## Tier 2 Augmentation: networking classes
|
||||
##
|
||||
#class BasicSocket
|
||||
# #
|
||||
# protected
|
||||
# include ::GxG::Support::Library::Transcoding
|
||||
# #
|
||||
# public
|
||||
# #
|
||||
# def self.new(*args)
|
||||
# #
|
||||
# allocate.instance_eval do
|
||||
# @signature = nil
|
||||
# # UUIDTools::UUID::random_create.to_s.hash
|
||||
# #
|
||||
# @in_buffer = ::StringIO.new("",::IO::RDWR)
|
||||
# @in_buffer.set_encoding(::Encoding::ASCII_8BIT)
|
||||
# @out_buffer = ""
|
||||
# @out_buffer.force_encoding(::Encoding::ASCII_8BIT)
|
||||
# @unbind_reason = nil
|
||||
# @remote_closed = false
|
||||
# #
|
||||
# @before_receive_data = nil
|
||||
# @after_receive_data = nil
|
||||
# @before_send_data = nil
|
||||
# @after_send_data = nil
|
||||
# #
|
||||
# @halt_receive_to_buffer = false
|
||||
# #
|
||||
# initialize(*args)
|
||||
# #
|
||||
# # Socket IO *should* be set to non-blocking IO me thinks
|
||||
# self.fcntl(::Fcntl::F_SETFL,::Fcntl::O_NONBLOCK)
|
||||
# # post_init
|
||||
# #
|
||||
# unless @signature
|
||||
# # define signature based upon IO.fileno, then add, based upon class, to connection list or acceptor list for servers.
|
||||
# # ::EventMachine::gxg_add_connection / ::EventMachine::gxg_add_acceptor
|
||||
# end
|
||||
# self
|
||||
# end
|
||||
# end
|
||||
# #
|
||||
# def self.open(*args,&block)
|
||||
# if block.respond_to?(:call)
|
||||
# block.call(new(*args))
|
||||
# else
|
||||
# new(*args)
|
||||
# end
|
||||
# end
|
||||
# #
|
||||
# # alias :original_method :method
|
||||
# #
|
||||
# def initialize(*args)
|
||||
# #
|
||||
# super(*args)
|
||||
# end
|
||||
# #
|
||||
# def signature()
|
||||
# @signature.dup
|
||||
# end
|
||||
# #
|
||||
# def signature=(sig)
|
||||
# if sig.is_a?(::String)
|
||||
# sig = sig.hash
|
||||
# end
|
||||
# if sig.is_a?(::Numeric)
|
||||
# @signature = sig.to_i
|
||||
# else
|
||||
# @signature = sig.to_s.hash
|
||||
# end
|
||||
# @signature.dup
|
||||
# end
|
||||
# #
|
||||
# def unbind_reason()
|
||||
# @unbind_reason
|
||||
# end
|
||||
# #
|
||||
# def unbind_reason=(reason)
|
||||
# @unbind_reason = reason
|
||||
# end
|
||||
# #
|
||||
# def buffer_limits(direction=:in, whatfor=nil)
|
||||
# limits = GxG::SYSTEM.memory_limits()[:buffers]
|
||||
# result = {:initial=>0, :valid=>0..0}
|
||||
# unless whatfor.is_a?(::Symbol)
|
||||
# # :unknown will play it safe with :socket buffer limits
|
||||
# whatfor = :socket
|
||||
# #
|
||||
# if self.is_any?(::UNIXServer, ::UNIXSocket, ::Socket)
|
||||
# whatfor = :socket
|
||||
# else
|
||||
# if self.is_any?(::TCPServer, ::SOCKSocket, ::TCPSocket)
|
||||
# whatfor = :tcp
|
||||
# else
|
||||
# if self.is_any?(::UDPServer, ::UDPSource, ::UDPSocket)
|
||||
# whatfor = :udp
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# case whatfor
|
||||
# when :socket
|
||||
# if direction == :in
|
||||
# result = limits[:socket][:ipc][:read].dup
|
||||
# else
|
||||
# result = limits[:socket][:ipc][:write].dup
|
||||
# end
|
||||
# when :tcp
|
||||
# if direction == :in
|
||||
# result = limits[:ipv4][:tcp][:read].dup
|
||||
# else
|
||||
# result = limits[:ipv4][:tcp][:write].dup
|
||||
# end
|
||||
# when :udp
|
||||
# if direction == :in
|
||||
# result = limits[:ipv4][:udp][:read].dup
|
||||
# else
|
||||
# result = limits[:ipv4][:udp][:write].dup
|
||||
# end
|
||||
# end
|
||||
# result
|
||||
# end
|
||||
# #
|
||||
# def passes_needed(size_used=0, container_limit=0)
|
||||
# needed_raw = size_used.to_f / container_limit.to_f
|
||||
# overhang = needed_raw - needed_raw.to_i.to_f
|
||||
# needed_raw = needed_raw.to_i.to_f
|
||||
# if overhang > 0.0
|
||||
# needed_raw += 1.0
|
||||
# end
|
||||
# needed_raw.to_i
|
||||
# end
|
||||
# #
|
||||
# def receive_to_buffer(options={:propogate => false})
|
||||
# unless self.closed?()
|
||||
# unless options.is_a?(::Hash)
|
||||
# options={:propogate => false}
|
||||
# end
|
||||
# if @halt_receive_to_buffer == true
|
||||
# @halt_receive_to_buffer = false
|
||||
# else
|
||||
# data = self.recv().to_s
|
||||
# if data.bytesize() > 0
|
||||
# @in_buffer.string << data
|
||||
# end
|
||||
# while data.bytesize() > 0
|
||||
# data = self.recv().to_s
|
||||
# if data.bytesize() > 0
|
||||
# @in_buffer.string << data
|
||||
# end
|
||||
# pause
|
||||
# end
|
||||
# if GxG::EventManager::manager_running?()[:result]
|
||||
# if options[:propogate]
|
||||
# if options[:interval].is_a?(::Numeric)
|
||||
# ::GxG::EventManager::post_event(Proc.new { pause({:interval => options[:interval]});self.receive_to_buffer(options) })
|
||||
# else
|
||||
# ::GxG::EventManager::post_event(Proc.new { self.receive_to_buffer(options) })
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# end
|
||||
# #
|
||||
# def halt_receive_to_buffer()
|
||||
# @halt_receive_to_buffer = true
|
||||
# end
|
||||
# #
|
||||
#end
|
||||
##
|
||||
#class UNIXSocket
|
||||
# #
|
||||
# alias :original_recvfrom :recvfrom
|
||||
# alias :original_recvfrom_nonblock :recvfrom
|
||||
# alias :recvfrom_nonblock :recvfrom
|
||||
# #
|
||||
# # alias :original_recvmsg :recvmsg
|
||||
# alias :original_recv :recv
|
||||
# # alias :original_sendmsg :sendmsg
|
||||
# alias :original_send :send
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketIO
|
||||
# # Since in binary mode, transcoding itself is useless, but other compatibility and object type-casting benefits if included.
|
||||
# include ::GxG::Support::Library::TranscodingIO
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketIORecvFrom
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketRW
|
||||
# #
|
||||
# public
|
||||
# #
|
||||
# def self.new(*args)
|
||||
# #
|
||||
# allocate.instance_eval do
|
||||
# @signature = nil
|
||||
# # UUIDTools::UUID::random_create.to_s.hash
|
||||
# #
|
||||
# @in_buffer = ::StringIO.new("",::IO::RDWR)
|
||||
# @in_buffer.set_encoding(::Encoding::ASCII_8BIT)
|
||||
# @out_buffer = ""
|
||||
# @out_buffer.force_encoding(::Encoding::ASCII_8BIT)
|
||||
# @unbind_reason = nil
|
||||
# @remote_closed = false
|
||||
# #
|
||||
# @before_receive_data = nil
|
||||
# @after_receive_data = nil
|
||||
# @before_send_data = nil
|
||||
# @after_send_data = nil
|
||||
# #
|
||||
# @halt_receive_to_buffer = false
|
||||
# #
|
||||
# initialize(*args)
|
||||
# #
|
||||
# # Socket IO *should* be set to non-blocking IO me thinks
|
||||
# self.fcntl(::Fcntl::F_SETFL,::Fcntl::O_NONBLOCK)
|
||||
# # post_init
|
||||
# #
|
||||
# unless @signature
|
||||
# # define signature based upon IO.fileno, then add, based upon class, to connection list or acceptor list for servers.
|
||||
# # ::EventMachine::gxg_add_connection / ::EventMachine::gxg_add_acceptor
|
||||
# end
|
||||
# self
|
||||
# end
|
||||
# end
|
||||
# #
|
||||
#end
|
||||
##
|
||||
#class UNIXServer
|
||||
# #
|
||||
# alias :original_recvfrom :recvfrom
|
||||
# alias :original_recvfrom_nonblock :recvfrom
|
||||
# alias :recvfrom_nonblock :recvfrom
|
||||
# #
|
||||
# # alias :original_recvmsg :recvmsg
|
||||
# alias :original_recv :recv
|
||||
# # alias :original_sendmsg :sendmsg
|
||||
# alias :original_send :send
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketIO
|
||||
# # Since in binary mode, transcoding itself is useless, but other compatibility and object type-casting benefits if included.
|
||||
# include ::GxG::Support::Library::TranscodingIO
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketIORecvFrom
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketRW
|
||||
# #
|
||||
# public
|
||||
# #
|
||||
# def self.new(*args)
|
||||
# #
|
||||
# allocate.instance_eval do
|
||||
# @signature = nil
|
||||
# # UUIDTools::UUID::random_create.to_s.hash
|
||||
# #
|
||||
# @in_buffer = ::StringIO.new("",::IO::RDWR)
|
||||
# @in_buffer.set_encoding(::Encoding::ASCII_8BIT)
|
||||
# @out_buffer = ""
|
||||
# @out_buffer.force_encoding(::Encoding::ASCII_8BIT)
|
||||
# @unbind_reason = nil
|
||||
# @remote_closed = false
|
||||
# #
|
||||
# @before_receive_data = nil
|
||||
# @after_receive_data = nil
|
||||
# @before_send_data = nil
|
||||
# @after_send_data = nil
|
||||
# #
|
||||
# @halt_receive_to_buffer = false
|
||||
# #
|
||||
# initialize(*args)
|
||||
# #
|
||||
# # Socket IO *should* be set to non-blocking IO me thinks
|
||||
# self.fcntl(::Fcntl::F_SETFL,::Fcntl::O_NONBLOCK)
|
||||
# # post_init
|
||||
# #
|
||||
# unless @signature
|
||||
# # define signature based upon IO.fileno, then add, based upon class, to connection list or acceptor list for servers.
|
||||
# # ::EventMachine::gxg_add_connection / ::EventMachine::gxg_add_acceptor
|
||||
# end
|
||||
# self
|
||||
# end
|
||||
# end
|
||||
# #
|
||||
#end
|
||||
##
|
||||
#class Socket
|
||||
# #
|
||||
# # alias :original_recvmsg :recvmsg
|
||||
# alias :original_recv :recv
|
||||
# # alias :original_sendmsg :sendmsg
|
||||
# alias :original_send :send
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketIO
|
||||
# # Since in binary mode, transcoding itself is useless, but other compatibility and object type-casting benefits if included.
|
||||
# include ::GxG::Support::Library::TranscodingIO
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketRW
|
||||
# #
|
||||
# public
|
||||
# #
|
||||
# def self.new(*args)
|
||||
# #
|
||||
# allocate.instance_eval do
|
||||
# @signature = nil
|
||||
# # UUIDTools::UUID::random_create.to_s.hash
|
||||
# #
|
||||
# @in_buffer = ::StringIO.new("",::IO::RDWR)
|
||||
# @in_buffer.set_encoding(::Encoding::ASCII_8BIT)
|
||||
# @out_buffer = ""
|
||||
# @out_buffer.force_encoding(::Encoding::ASCII_8BIT)
|
||||
# @unbind_reason = nil
|
||||
# @remote_closed = false
|
||||
# #
|
||||
# @before_receive_data = nil
|
||||
# @after_receive_data = nil
|
||||
# @before_send_data = nil
|
||||
# @after_send_data = nil
|
||||
# #
|
||||
# @halt_receive_to_buffer = false
|
||||
# #
|
||||
# initialize(*args)
|
||||
# #
|
||||
# # Socket IO *should* be set to non-blocking IO me thinks
|
||||
# self.fcntl(::Fcntl::F_SETFL,::Fcntl::O_NONBLOCK)
|
||||
# # post_init
|
||||
# #
|
||||
# unless @signature
|
||||
# # define signature based upon IO.fileno, then add, based upon class, to connection list or acceptor list for servers.
|
||||
# # ::EventMachine::gxg_add_connection / ::EventMachine::gxg_add_acceptor
|
||||
# end
|
||||
# self
|
||||
# end
|
||||
# end
|
||||
# #
|
||||
#end
|
||||
##
|
||||
#class IPSocket
|
||||
# #
|
||||
# # alias :original_recvmsg :recvmsg
|
||||
# alias :original_recv :recv
|
||||
# # alias :original_sendmsg :sendmsg
|
||||
# alias :original_send :send
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketIO
|
||||
# # Since in binary mode, transcoding itself is useless, but other compatibility and object type-casting benefits if included.
|
||||
# include ::GxG::Support::Library::TranscodingIO
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketRW
|
||||
# #
|
||||
# public
|
||||
# #
|
||||
# def self.new(*args)
|
||||
# #
|
||||
# allocate.instance_eval do
|
||||
# @signature = nil
|
||||
# # UUIDTools::UUID::random_create.to_s.hash
|
||||
# #
|
||||
# @in_buffer = ::StringIO.new("",::IO::RDWR)
|
||||
# @in_buffer.set_encoding(::Encoding::ASCII_8BIT)
|
||||
# @out_buffer = ""
|
||||
# @out_buffer.force_encoding(::Encoding::ASCII_8BIT)
|
||||
# @unbind_reason = nil
|
||||
# @remote_closed = false
|
||||
# #
|
||||
# @before_receive_data = nil
|
||||
# @after_receive_data = nil
|
||||
# @before_send_data = nil
|
||||
# @after_send_data = nil
|
||||
# #
|
||||
# @halt_receive_to_buffer = false
|
||||
# #
|
||||
# initialize(*args)
|
||||
# #
|
||||
# # Socket IO *should* be set to non-blocking IO me thinks
|
||||
# self.fcntl(::Fcntl::F_SETFL,::Fcntl::O_NONBLOCK)
|
||||
# # post_init
|
||||
# #
|
||||
# unless @signature
|
||||
# # define signature based upon IO.fileno, then add, based upon class, to connection list or acceptor list for servers.
|
||||
# # ::EventMachine::gxg_add_connection / ::EventMachine::gxg_add_acceptor
|
||||
# end
|
||||
# self
|
||||
# end
|
||||
# end
|
||||
# #
|
||||
#end
|
||||
##
|
||||
#class TCPSocket
|
||||
# #
|
||||
# alias :original_recvfrom :recvfrom
|
||||
# alias :original_recvfrom_nonblock :recvfrom
|
||||
# alias :recvfrom_nonblock :recvfrom
|
||||
# #
|
||||
# alias :original_recvmsg :recvmsg
|
||||
# alias :original_recv :recv
|
||||
# alias :original_sendmsg :sendmsg
|
||||
# alias :original_send :send
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketIO
|
||||
# # Since in binary mode, transcoding itself is useless, but other compatibility and object type-casting benefits if included.
|
||||
# include ::GxG::Support::Library::TranscodingIO
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketIORecvFrom
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketRW
|
||||
# #
|
||||
# public
|
||||
# #
|
||||
# def self.new(*args)
|
||||
# #
|
||||
# allocate.instance_eval do
|
||||
# @signature = nil
|
||||
# # UUIDTools::UUID::random_create.to_s.hash
|
||||
# #
|
||||
# @in_buffer = ::StringIO.new("",::IO::RDWR)
|
||||
# @in_buffer.set_encoding(::Encoding::ASCII_8BIT)
|
||||
# @out_buffer = ""
|
||||
# @out_buffer.force_encoding(::Encoding::ASCII_8BIT)
|
||||
# @unbind_reason = nil
|
||||
# @remote_closed = false
|
||||
# #
|
||||
# @before_receive_data = nil
|
||||
# @after_receive_data = nil
|
||||
# @before_send_data = nil
|
||||
# @after_send_data = nil
|
||||
# #
|
||||
# @halt_receive_to_buffer = false
|
||||
# #
|
||||
# initialize(*args)
|
||||
# #
|
||||
# # Socket IO *should* be set to non-blocking IO me thinks
|
||||
# self.fcntl(::Fcntl::F_SETFL,::Fcntl::O_NONBLOCK)
|
||||
# # post_init
|
||||
# #
|
||||
# unless @signature
|
||||
# # define signature based upon IO.fileno, then add, based upon class, to connection list or acceptor list for servers.
|
||||
# # ::EventMachine::gxg_add_connection / ::EventMachine::gxg_add_acceptor
|
||||
# end
|
||||
# self
|
||||
# end
|
||||
# end
|
||||
# #
|
||||
#end
|
||||
##
|
||||
#class TCPServer
|
||||
# #
|
||||
# alias :original_recvfrom :recvfrom
|
||||
# alias :original_recvfrom_nonblock :recvfrom
|
||||
# alias :recvfrom_nonblock :recvfrom
|
||||
# #
|
||||
# alias :original_recvmsg :recvmsg
|
||||
# alias :original_recv :recv
|
||||
# alias :original_sendmsg :sendmsg
|
||||
# alias :original_send :send
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketIO
|
||||
# # Since in binary mode, transcoding itself is useless, but other compatibility and object type-casting benefits if included.
|
||||
# include ::GxG::Support::Library::TranscodingIO
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketIORecvFrom
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketRW
|
||||
# #
|
||||
# public
|
||||
# #
|
||||
# def self.new(*args)
|
||||
# #
|
||||
# allocate.instance_eval do
|
||||
# @signature = nil
|
||||
# # UUIDTools::UUID::random_create.to_s.hash
|
||||
# #
|
||||
# @in_buffer = ::StringIO.new("",::IO::RDWR)
|
||||
# @in_buffer.set_encoding(::Encoding::ASCII_8BIT)
|
||||
# @out_buffer = ""
|
||||
# @out_buffer.force_encoding(::Encoding::ASCII_8BIT)
|
||||
# @unbind_reason = nil
|
||||
# @remote_closed = false
|
||||
# #
|
||||
# @before_receive_data = nil
|
||||
# @after_receive_data = nil
|
||||
# @before_send_data = nil
|
||||
# @after_send_data = nil
|
||||
# #
|
||||
# @halt_receive_to_buffer = false
|
||||
# #
|
||||
# initialize(*args)
|
||||
# #
|
||||
# # Socket IO *should* be set to non-blocking IO me thinks
|
||||
# self.fcntl(::Fcntl::F_SETFL,::Fcntl::O_NONBLOCK)
|
||||
# # post_init
|
||||
# #
|
||||
# unless @signature
|
||||
# # define signature based upon IO.fileno, then add, based upon class, to connection list or acceptor list for servers.
|
||||
# # ::EventMachine::gxg_add_connection / ::EventMachine::gxg_add_acceptor
|
||||
# end
|
||||
# self
|
||||
# end
|
||||
# end
|
||||
# #
|
||||
#end
|
||||
##
|
||||
#class UDPSocket
|
||||
# #
|
||||
# alias :original_recvfrom :recvfrom
|
||||
# alias :original_recvfrom_nonblock :recvfrom_nonblock
|
||||
# #
|
||||
# alias :original_recvmsg :recvmsg
|
||||
# alias :original_recv :recv
|
||||
# alias :original_sendmsg :sendmsg
|
||||
# alias :original_send :send
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketIO
|
||||
# # Since in binary mode, transcoding itself is useless, but other compatibility and object type-casting benefits if included.
|
||||
# include ::GxG::Support::Library::TranscodingIO
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketIORecvFrom
|
||||
# #
|
||||
# include ::GxG::Support::Library::SocketRW
|
||||
# #
|
||||
# public
|
||||
# #
|
||||
# def self.new(*args)
|
||||
# #
|
||||
# allocate.instance_eval do
|
||||
# @signature = nil
|
||||
# # UUIDTools::UUID::random_create.to_s.hash
|
||||
# #
|
||||
# @in_buffer = ::StringIO.new("",::IO::RDWR)
|
||||
# @in_buffer.set_encoding(::Encoding::ASCII_8BIT)
|
||||
# @out_buffer = ""
|
||||
# @out_buffer.force_encoding(::Encoding::ASCII_8BIT)
|
||||
# @unbind_reason = nil
|
||||
# @remote_closed = false
|
||||
# #
|
||||
# @before_receive_data = nil
|
||||
# @after_receive_data = nil
|
||||
# @before_send_data = nil
|
||||
# @after_send_data = nil
|
||||
# #
|
||||
# @halt_receive_to_buffer = false
|
||||
# #
|
||||
# initialize(*args)
|
||||
# #
|
||||
# # Socket IO *should* be set to non-blocking IO me thinks
|
||||
# self.fcntl(::Fcntl::F_SETFL,::Fcntl::O_NONBLOCK)
|
||||
# # post_init
|
||||
# #
|
||||
# unless @signature
|
||||
# # define signature based upon IO.fileno, then add, based upon class, to connection list or acceptor list for servers.
|
||||
# # ::EventMachine::gxg_add_connection / ::EventMachine::gxg_add_acceptor
|
||||
# end
|
||||
# self
|
||||
# end
|
||||
# end
|
||||
# #
|
||||
#end
|
||||
##
|
||||
#class UDPServer < ::UDPSocket
|
||||
# #
|
||||
# def initialize(the_host_ip, the_port)
|
||||
# #
|
||||
# @interface = Addrinfo.udp(the_host_ip, the_port)
|
||||
# if ::GxG::SYSTEM.network_port_used?(@interface.ip_address(),@interface.ip_port())
|
||||
# raise Errno::EADDRINUSE, "#{@interface.ip_address()}:#{@interface.ip_port()} is already in use"
|
||||
# end
|
||||
# #
|
||||
# if @interface.ipv6?()
|
||||
# super(::Socket::AF_INET6)
|
||||
# else
|
||||
# super(::Socket::AF_INET)
|
||||
# end
|
||||
# self.bind(@interface.ip_address(),@interface.ip_port())
|
||||
# #
|
||||
# unless ::GxG::SYSTEM.network_port_used?(@interface.ip_address(),@interface.ip_port())
|
||||
# raise Errno::EADDRNOTAVAIL, "#{@interface.ip_address()}:#{@interface.ip_port()} could not be bound properly"
|
||||
# end
|
||||
# #
|
||||
# public
|
||||
# #
|
||||
# def self.new(*args)
|
||||
# #
|
||||
# allocate.instance_eval do
|
||||
# @signature = nil
|
||||
# # UUIDTools::UUID::random_create.to_s.hash
|
||||
# #
|
||||
# @in_buffer = ::StringIO.new("",::IO::RDWR)
|
||||
# @in_buffer.set_encoding(::Encoding::ASCII_8BIT)
|
||||
# @out_buffer = ""
|
||||
# @out_buffer.force_encoding(::Encoding::ASCII_8BIT)
|
||||
# @unbind_reason = nil
|
||||
# @remote_closed = false
|
||||
# #
|
||||
# @before_receive_data = nil
|
||||
# @after_receive_data = nil
|
||||
# @before_send_data = nil
|
||||
# @after_send_data = nil
|
||||
# #
|
||||
# @halt_receive_to_buffer = false
|
||||
# #
|
||||
# initialize(*args)
|
||||
# #
|
||||
# # Socket IO *should* be set to non-blocking IO me thinks
|
||||
# self.fcntl(::Fcntl::F_SETFL,::Fcntl::O_NONBLOCK)
|
||||
# # post_init
|
||||
# #
|
||||
# unless @signature
|
||||
# # define signature based upon IO.fileno, then add, based upon class, to connection list or acceptor list for servers.
|
||||
# # ::EventMachine::gxg_add_connection / ::EventMachine::gxg_add_acceptor
|
||||
# end
|
||||
# self
|
||||
# end
|
||||
# end
|
||||
# #
|
||||
# end
|
||||
#end
|
||||
##
|
||||
#class SOCKSocket
|
||||
# #
|
||||
# public
|
||||
# #
|
||||
# def self.new(*args)
|
||||
# #
|
||||
# allocate.instance_eval do
|
||||
# @signature = nil
|
||||
# # UUIDTools::UUID::random_create.to_s.hash
|
||||
# #
|
||||
# @in_buffer = ::StringIO.new("",::IO::RDWR)
|
||||
# @in_buffer.set_encoding(::Encoding::ASCII_8BIT)
|
||||
# @out_buffer = ""
|
||||
# @out_buffer.force_encoding(::Encoding::ASCII_8BIT)
|
||||
# @unbind_reason = nil
|
||||
# @remote_closed = false
|
||||
# #
|
||||
# @before_receive_data = nil
|
||||
# @after_receive_data = nil
|
||||
# @before_send_data = nil
|
||||
# @after_send_data = nil
|
||||
# #
|
||||
# @halt_receive_to_buffer = false
|
||||
# #
|
||||
# initialize(*args)
|
||||
# #
|
||||
# # Socket IO *should* be set to non-blocking IO me thinks
|
||||
# self.fcntl(::Fcntl::F_SETFL,::Fcntl::O_NONBLOCK)
|
||||
# # post_init
|
||||
# #
|
||||
# unless @signature
|
||||
# # define signature based upon IO.fileno, then add, based upon class, to connection list or acceptor list for servers.
|
||||
# # ::EventMachine::gxg_add_connection / ::EventMachine::gxg_add_acceptor
|
||||
# end
|
||||
# self
|
||||
# end
|
||||
# end
|
||||
# #
|
||||
#end
|
||||
##
|
||||
## ### Networking Section of GxG
|
||||
#module GxG
|
||||
# #
|
||||
# module Networking
|
||||
# def self.buffer_limits(direction=:in, whatfor=nil)
|
||||
# limits = GxG::SYSTEM.memory_limits()[:buffers]
|
||||
# result = {:initial=>0, :valid=>0..0}
|
||||
# case whatfor
|
||||
# when :socket, :ipc
|
||||
# if direction == :in
|
||||
# result = limits[:socket][:ipc][:read].dup
|
||||
# else
|
||||
# result = limits[:socket][:ipc][:write].dup
|
||||
# end
|
||||
# when :inproc, :tcp, :tcp4, :pgm, :epgm
|
||||
# if direction == :in
|
||||
# result = limits[:ipv4][:tcp][:read].dup
|
||||
# else
|
||||
# result = limits[:ipv4][:tcp][:write].dup
|
||||
# end
|
||||
# when :tcp6
|
||||
# # TODO: @GxG::Networking::ZMQSocket.buffer_limits : GxG::SYSTEM.memory_limits : for now route to ipv4, need to expand system key set to include ipv6
|
||||
# if direction == :in
|
||||
# result = limits[:ipv4][:tcp][:read].dup
|
||||
# else
|
||||
# result = limits[:ipv4][:tcp][:write].dup
|
||||
# end
|
||||
# when :udp, :udp4, :udp6
|
||||
# if direction == :in
|
||||
# result = limits[:ipv4][:udp][:read].dup
|
||||
# else
|
||||
# result = limits[:ipv4][:udp][:write].dup
|
||||
# end
|
||||
# end
|
||||
# result
|
||||
# end
|
||||
# #
|
||||
# def self.passes_needed(size_used=0, container_limit=0)
|
||||
# needed_raw = size_used.to_f / container_limit.to_f
|
||||
# overhang = needed_raw - needed_raw.to_i.to_f
|
||||
# needed_raw = needed_raw.to_i.to_f
|
||||
# if overhang > 0.0
|
||||
# needed_raw += 1.0
|
||||
# end
|
||||
# needed_raw.to_i
|
||||
# end
|
||||
# #
|
||||
# # networking classes
|
||||
# class UNIXSocket < ::UNIXSocket
|
||||
# # when gem is pushed, subclass from Celluloid::IO::UNIXSocket
|
||||
# end
|
||||
# #
|
||||
# class BSDSocket < ::Socket
|
||||
# #
|
||||
# end
|
||||
# #
|
||||
# class UNIXServer < ::UNIXServer
|
||||
# # when gem is pushed, subclass from Celluloid::IO::UNIXServer
|
||||
# #
|
||||
# # def accept()
|
||||
# # ::GxG::Networking::UNIXSocket.new(self.path)
|
||||
# # end
|
||||
# # alias :accept_nonblock :accept
|
||||
# #
|
||||
# end
|
||||
# #
|
||||
# class TCPSocket < ::Celluloid::IO::TCPSocket
|
||||
# #
|
||||
# end
|
||||
# #
|
||||
# class TCPServer < ::Celluloid::IO::TCPServer
|
||||
# #
|
||||
# end
|
||||
# #
|
||||
# class UDPSocket < ::Celluloid::IO::UDPSocket
|
||||
# #
|
||||
# end
|
||||
# #
|
||||
# class UDPServer < ::UDPServer
|
||||
# #
|
||||
# end
|
||||
# #
|
||||
# class SOCKSocket < ::SOCKSocket
|
||||
# #
|
||||
# end
|
||||
# #
|
||||
# class DDPSocket
|
||||
# #
|
||||
# end
|
||||
# #
|
||||
# module Protocol
|
||||
# #
|
||||
# def register(*args)
|
||||
# # register(:proto, MyProtoClassPath)
|
||||
# end
|
||||
# #
|
||||
# end
|
||||
# #
|
||||
# # ### IPC Classes (via ZeroMQ)
|
||||
# # require(::File.expand_path(::File.dirname(__FILE__) << "/gxg_ipc.rb"))
|
||||
# #
|
||||
# #
|
||||
# end
|
||||
# #
|
||||
#end
|
||||
##
|
||||
1053
lib/gxg/gxg_transcode.rb
Normal file
1053
lib/gxg/gxg_transcode.rb
Normal file
File diff suppressed because it is too large
Load diff
122
lib/gxg/gxg_units.rb
Normal file
122
lib/gxg/gxg_units.rb
Normal file
|
|
@ -0,0 +1,122 @@
|
|||
|
||||
# ---------------------------------------------------------------------------------------------------------------------
|
||||
# Units and support element classes:
|
||||
module GxG
|
||||
module Units
|
||||
class << self
|
||||
@@interpreters = []
|
||||
end
|
||||
# this module is used for interpreting text into denominations and multipliers., and general support for various units of measure
|
||||
def self.unit_interpreters(categories=:any)
|
||||
unless categories == :any
|
||||
unless categories.is_a?(Array)
|
||||
categories = [(categories)]
|
||||
end
|
||||
end
|
||||
unit_list = []
|
||||
GxG::Units.constants.to_enum.each do |unit_handler|
|
||||
unit_handler = GxG::Units.const_get(unit_handler)
|
||||
if (unit_handler.is_any?([Class, Module]) && unit_handler.respond_to?(:interpret) && unit_handler.respond_to?(:categories))
|
||||
if categories == :any
|
||||
unit_list << unit_handler
|
||||
else
|
||||
categories.to_enum.each do |category|
|
||||
if unit_handler::categories.include?(category)
|
||||
unit_list << unit_handler
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
#
|
||||
unit_list
|
||||
end
|
||||
#
|
||||
def self.refresh_units_registry()
|
||||
# SOMEDAY: Thread-safety?
|
||||
@@interpreters = self.unit_interpreters()
|
||||
end
|
||||
#
|
||||
def self.interpret_units(params={})
|
||||
# {:text => quanta,:categories => categories,:locale => locale}
|
||||
quanta_string = (params[:text] || "")
|
||||
categories = (params[:categories] || :any)
|
||||
locale = (params[:locale] || :en_US)
|
||||
numeric_base = (params[:base] || 10)
|
||||
unless categories == :any
|
||||
unless categories.is_a?(Array)
|
||||
categories = [(categories)]
|
||||
end
|
||||
end
|
||||
results = []
|
||||
@@interpreters.to_enum.each do |interpreter|
|
||||
entry = nil
|
||||
if categories == :any
|
||||
entry = interpreter::interpret(quanta_string.to_s,locale,numeric_base)
|
||||
else
|
||||
categories.to_enum.each do |category|
|
||||
if interpreter::categories.include?(category)
|
||||
entry = interpreter.interpret(quanta_string.to_s,locale,numeric_base)
|
||||
end
|
||||
end
|
||||
end
|
||||
if entry
|
||||
results << entry
|
||||
end
|
||||
end
|
||||
{:result => results}
|
||||
end
|
||||
module Bits
|
||||
#
|
||||
end
|
||||
module Bytes
|
||||
def self.categories()
|
||||
[:numeric, :byte, :memory, :storage, :computer]
|
||||
end
|
||||
def self.interpret(quanta_string="",interpret_for_locale=:en_US,interpret_for_numeric_base=10)
|
||||
multiplier = nil
|
||||
#
|
||||
case quanta_string.to_s.downcase.to_sym
|
||||
# Attribution: http://whatsabyte.com/
|
||||
# Attribution: https://en.wikipedia.org/wiki/Exabyte
|
||||
# Note: I am electing to count along the 1024 (to the power) rule. Hard drive manufacturers can kiss my rosey-red,
|
||||
# I'll not bugger my enumeration standard for their bloody sales force. :P Thus:
|
||||
# I've attempted to include the IS and IEC terms and abbreviations.
|
||||
# LATER: add ability to distinguish case: Kb = kiloBIT, KB = KiloBYTE, etc
|
||||
when :byte, :bytes
|
||||
multiplier = 1
|
||||
when :kb, :kib, :kilobyte, :kilobytes, :kibibyte, :kibibytes
|
||||
multiplier = 1024 ** 1
|
||||
when :mb, :mib, :megabyte, :megabytes, :mebibyte, :mebibytes
|
||||
multiplier = 1024 ** 2
|
||||
when :gb, :gib, :gigabyte, :gigabytes, :gibibyte, :gibibytes
|
||||
multiplier = 1024 ** 3
|
||||
when :tb, :tib, :terabyte, :terabytes, :tebibyte, :tebibytes
|
||||
multiplier = 1024 ** 4
|
||||
when :pb, :pib, :petabyte, :petabytes, :pebibyte, :pebibytes
|
||||
multiplier = 1024 ** 5
|
||||
when :eb, :eib, :exobyte, :exobytes, :exbibyte, :exbibytes
|
||||
multiplier = 1024 ** 6
|
||||
when :zb, :zib, :zettabyte, :zettabytes, :zebibyte, :zebibytes
|
||||
multiplier = 1024 ** 7
|
||||
when :yb, :yib, :yottabyte, :yottabytes, :yobibyte, :yobibytes
|
||||
multiplier = 1024 ** 8
|
||||
when :bb, :bib, :brontobyte, :brontobytes
|
||||
multiplier = 1024 ** 9
|
||||
when :geopbyte, :geopbytes
|
||||
# TODO: GeopByte: need to find missing SI and IEC abbreviations
|
||||
multiplier = 1024 ** 10
|
||||
end
|
||||
#
|
||||
if multiplier
|
||||
{:quantum => {:byte => multiplier}, :attributes => nil}
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
# Initial setup:
|
||||
::GxG::Units::refresh_units_registry()
|
||||
#
|
||||
1220
lib/gxg/gxg_zmq.rb
Normal file
1220
lib/gxg/gxg_zmq.rb
Normal file
File diff suppressed because it is too large
Load diff
4797
lib/gxg/net_clients.rb
Normal file
4797
lib/gxg/net_clients.rb
Normal file
File diff suppressed because it is too large
Load diff
46
lib/gxg/net_tools.rb
Normal file
46
lib/gxg/net_tools.rb
Normal file
|
|
@ -0,0 +1,46 @@
|
|||
|
||||
#
|
||||
# ### Networking Section of GxG
|
||||
module GxG
|
||||
#
|
||||
module Networking
|
||||
def self.wget(the_url=nil, options={})
|
||||
result = false
|
||||
begin
|
||||
unless options.is_a?(::Hash)
|
||||
options = {}
|
||||
end
|
||||
if the_url.is_a?(::String)
|
||||
the_url = ::URI::parse(the_url)
|
||||
end
|
||||
if the_url.is_a?(::URI::Generic)
|
||||
if the_url.scheme.to_s.downcase.include?("https") || options[:use_ssl] == true
|
||||
client = ::GxG::Networking::HttpsClient.new(the_url, options)
|
||||
else
|
||||
client = ::GxG::Networking::HttpClient.new(the_url, options)
|
||||
end
|
||||
response = client.get(the_url, options.merge({:raw_response => true}))
|
||||
if response
|
||||
if response.is_a?(::File)
|
||||
result = response
|
||||
else
|
||||
if options[:raw_response]
|
||||
result = response
|
||||
else
|
||||
result = response.body
|
||||
end
|
||||
end
|
||||
else
|
||||
raise Exception, "Failed to get a response."
|
||||
end
|
||||
else
|
||||
raise ArgumentError, "You MUST specify a valid URI"
|
||||
end
|
||||
rescue Exception => the_error
|
||||
log_error({:error => the_error, :parameters => {:url => the_url, :options => options}})
|
||||
end
|
||||
result
|
||||
end
|
||||
end
|
||||
#
|
||||
end
|
||||
252
lib/gxg/tag_helpers.rb
Normal file
252
lib/gxg/tag_helpers.rb
Normal file
|
|
@ -0,0 +1,252 @@
|
|||
#
|
||||
require 'securerandom'
|
||||
module Padrino
|
||||
module Helpers
|
||||
module TagHelpers
|
||||
# See: https://github.com/padrino/padrino-framework/blob/master/padrino-helpers/lib/padrino-helpers/tag_helpers.rb
|
||||
def accordian_tag(the_id=nil, sections=nil)
|
||||
# id => <uuid>, :sections => [{:heading => "", :content => ""}]
|
||||
if the_id.is_a?(::Array)
|
||||
sections = the_id
|
||||
the_id = ::SecureRandom::uuid.to_s
|
||||
end
|
||||
unless the_id
|
||||
the_id = ::SecureRandom::uuid.to_s
|
||||
end
|
||||
output = SafeBuffer.new
|
||||
output.safe_concat "<div id='#{the_id.to_s}'>"
|
||||
sections.each do |the_section|
|
||||
output.safe_concat "<h3>#{the_section[:heading].to_s}</h3>"
|
||||
output.safe_concat "<div>"
|
||||
output.safe_concat the_section[:content].to_s
|
||||
output.safe_concat "</div>"
|
||||
end
|
||||
output.safe_concat "</div><script>$('##{the_id.to_s}').accordion();</script>"
|
||||
output
|
||||
end
|
||||
#
|
||||
def autocomplete_tag(the_id=nil, the_terms=nil)
|
||||
if the_id.is_a?(::Array)
|
||||
the_terms = the_id
|
||||
the_id = ::SecureRandom::uuid.to_s
|
||||
end
|
||||
unless the_id
|
||||
the_id = ::SecureRandom::uuid.to_s
|
||||
end
|
||||
output = SafeBuffer.new
|
||||
output.safe_concat( input_tag(:text, :name => the_id.to_s, :id => the_id.to_s) )
|
||||
# output.safe_concat "<input type='text' id='#{the_id.to_s}'>"
|
||||
output.safe_concat "<script>var terms#{the_id.to_s.gsub("-","")} = ["
|
||||
the_terms.each do |the_term|
|
||||
output.safe_concat ("'#{the_term.to_s}'")
|
||||
unless the_term == the_terms.last
|
||||
output.safe_concat(",")
|
||||
end
|
||||
end
|
||||
output.safe_concat "];"
|
||||
output.safe_concat "$( '##{the_id.to_s}' ).autocomplete({source: terms#{the_id.to_s.gsub("-","")}});</script>"
|
||||
end
|
||||
#
|
||||
def gxg_button_tag(the_id=nil, options={})
|
||||
# Options: :title => <string>,
|
||||
# :javascript => <string>,
|
||||
# :image => {:position => :full,:top,:left,:right,:bottom, :source => <path> :height => <int>, :width => <int>}
|
||||
if the_id.is_a?(::Hash)
|
||||
options = the_id
|
||||
the_id = ::SecureRandom::uuid.to_s
|
||||
end
|
||||
unless the_id
|
||||
the_id = ::SecureRandom::uuid.to_s
|
||||
end
|
||||
output = SafeBuffer.new
|
||||
if options[:image].is_a?(::Hash)
|
||||
output.safe_concat("<div id='#{the_id.to_s}'>")
|
||||
img_opts = {}
|
||||
if options[:image][:height]
|
||||
img_opts[:height] = options[:image][:height]
|
||||
end
|
||||
if options[:image][:width]
|
||||
img_opts[:width] = options[:image][:width]
|
||||
end
|
||||
if options[:image][:position] == :full
|
||||
output.safe_concat("<table><tr><td>" + image_tag(options[:image][:source], img_opts) + "</td></tr></table>")
|
||||
else
|
||||
# top, left, right, bottom of title text?
|
||||
case options[:image][:position]
|
||||
when :top
|
||||
output.safe_concat("<table><tr><td>" + image_tag(options[:image][:source], img_opts) + "</td></tr><tr><td>#{options[:title]}</td></tr></table>")
|
||||
when :bottom
|
||||
output.safe_concat("<table><tr><td>#{options[:title]}</td></tr><tr><td>" + image_tag(options[:image][:source], img_opts) + "</td></tr></table>")
|
||||
when :left
|
||||
output.safe_concat("<table><tr><td>" + image_tag(options[:image][:source], img_opts) + "</td><td>#{options[:title]}</td></tr></table>")
|
||||
when :right
|
||||
output.safe_concat("<table><tr><td>#{options[:title]}</td><td>" + image_tag(options[:image][:source], img_opts) + "</td></tr></table>")
|
||||
end
|
||||
end
|
||||
output.safe_concat("</div>")
|
||||
else
|
||||
output.safe_concat("<div id='#{the_id.to_s}'>#{options[:title].to_s}</div>")
|
||||
end
|
||||
output.safe_concat("<script>$('##{the_id.to_s}').button();</script>")
|
||||
if options[:javascript].is_a?(::String)
|
||||
output.safe_concat("<script>#{options[:javascript].to_s}</script>")
|
||||
end
|
||||
output
|
||||
end
|
||||
#
|
||||
def radio_tag(the_id=nil,title=nil)
|
||||
output = SafeBuffer.new
|
||||
unless the_id
|
||||
the_id = ::SecureRandom::uuid.to_s
|
||||
end
|
||||
output.safe_concat("<label for='#{the_id}'>#{title}</label>")
|
||||
output.safe_concat("<input type='radio' name='#{the_id}' id='#{the_id}'>")
|
||||
output
|
||||
end
|
||||
#
|
||||
def radio_group(legend=nil,button_names=nil)
|
||||
# Waiting on Fix: https://bugs.jqueryui.com/ticket/15308#comment:1
|
||||
output = SafeBuffer.new
|
||||
output.safe_concat("<fieldset><legend>#{legend.to_s}</legend>")
|
||||
button_names.each do |the_name|
|
||||
output.safe_concat(radio_tag(nil,the_name))
|
||||
end
|
||||
output.safe_concat("</fieldset>")
|
||||
output.safe_concat("<script>$('input[type=radio]').checkboxradio();</script>")
|
||||
output
|
||||
end
|
||||
#
|
||||
def control_group(content="", options={:vertical => false}, &block)
|
||||
#
|
||||
output = SafeBuffer.new
|
||||
if options[:vertical]
|
||||
output.safe_concat("<div class='controlgroup-verticle'>")
|
||||
else
|
||||
output.safe_concat("<div class='controlgroup'>")
|
||||
end
|
||||
if block.respond_to?(:call)
|
||||
output.safe_concat(block.call())
|
||||
else
|
||||
output.safe_concat(content)
|
||||
end
|
||||
output.safe_concat("</div>")
|
||||
if options[:vertical]
|
||||
output.safe_concat("<script>$('.controlgroup-verticle').controlgroup({'direction': 'vertical'});</script>")
|
||||
else
|
||||
output.safe_concat("<script>$('.controlgroup').controlgroup();</script>")
|
||||
end
|
||||
output
|
||||
end
|
||||
#
|
||||
def datepicker_tag(the_id=nil,title="")
|
||||
output = SafeBuffer.new
|
||||
unless the_id
|
||||
the_id = ::SecureRandom::uuid.to_s
|
||||
end
|
||||
output.safe_concat("#{title.to_s}<input type='text' id='#{the_id.to_s}'>")
|
||||
output.safe_concat("<script>$('##{the_id.to_s}').datepicker();</script>")
|
||||
output
|
||||
end
|
||||
#
|
||||
def dialog_tag(the_id=nil, title="", content="", &block)
|
||||
output = SafeBuffer.new
|
||||
unless the_id
|
||||
the_id = ::SecureRandom::uuid.to_s
|
||||
end
|
||||
output.safe_concat("<div title='#{title.to_s}' id='#{the_id.to_s}'>")
|
||||
if block.respond_to?(:call)
|
||||
output.safe_concat(block.call())
|
||||
else
|
||||
output.safe_concat(content)
|
||||
end
|
||||
output.safe_concat("</div>")
|
||||
output.safe_concat("<script>$('##{the_id.to_s}').dialog();</script>")
|
||||
output
|
||||
end
|
||||
#
|
||||
def slider_tag(the_id=nil, options={})
|
||||
output = SafeBuffer.new
|
||||
unless the_id
|
||||
the_id = ::SecureRandom::uuid.to_s
|
||||
end
|
||||
output.safe_concat("<div id='#{the_id.to_s}'>")
|
||||
if options[:content].is_a?(::String)
|
||||
output.safe_concat(options[:content].to_s)
|
||||
end
|
||||
output.safe_concat("</div>")
|
||||
if options[:javascript].is_a?(::String)
|
||||
output.safe_concat("<script>$('##{the_id.to_s}').slider(#{options[:javascript].to_s});</script>")
|
||||
else
|
||||
output.safe_concat("<script>$('##{the_id.to_s}').slider();</script>")
|
||||
end
|
||||
output
|
||||
end
|
||||
#
|
||||
def spinner_tab(the_id=nil, options={})
|
||||
output = SafeBuffer.new
|
||||
unless the_id
|
||||
the_id = ::SecureRandom::uuid.to_s
|
||||
end
|
||||
output.safe_concat("<input id='#{the_id.to_s}'")
|
||||
if options[:name].is_a?(::String)
|
||||
output.safe_concat(" name='#{options[:name].to_s}'")
|
||||
end
|
||||
if options[:value]
|
||||
output.safe_concat(" name='#{options[:value].to_s}'")
|
||||
end
|
||||
output.safe_concat(">")
|
||||
if options[:javascript].is_a?(::String)
|
||||
output.safe_concat("<script>$('##{the_id.to_s}').spinner(#{options[:javascript].to_s});</script>")
|
||||
else
|
||||
output.safe_concat("<script>$('##{the_id.to_s}').spinner();</script>")
|
||||
end
|
||||
output
|
||||
end
|
||||
#
|
||||
def tabs_tag(the_id=nil, sections=nil, options={})
|
||||
# id => <uuid>, :sections => [{:heading => "", :content => ""}]
|
||||
if the_id.is_a?(::Array)
|
||||
sections = the_id
|
||||
options = sections
|
||||
the_id = ::SecureRandom::uuid.to_s
|
||||
end
|
||||
unless the_id
|
||||
the_id = ::SecureRandom::uuid.to_s
|
||||
end
|
||||
output = SafeBuffer.new
|
||||
section_details = {}
|
||||
output.safe_concat "<div id='#{the_id.to_s}'>"
|
||||
sections.each do |the_section|
|
||||
section_id = ::SecureRandom::uuid.to_sym
|
||||
section_details[(section_id)] = {:heading => the_section[:heading], :content => the_section[:content]}
|
||||
end
|
||||
output.safe_concat "<ul>"
|
||||
section_details.each_key do |the_uuid|
|
||||
output.safe_concat "<li><a href='##{the_uuid.to_s}'>#{section_details[(the_uuid)][:heading].to_s}</a></li>"
|
||||
end
|
||||
output.safe_concat "</ul>"
|
||||
section_details.each_key do |the_uuid|
|
||||
output.safe_concat "<div id='#{the_uuid.to_s}'>#{section_details[(the_uuid)][:content].to_s}</div>"
|
||||
end
|
||||
output.safe_concat "</div>"
|
||||
if options[:javascript].is_a?(::String)
|
||||
output.safe_concat("<script>$('##{the_id.to_s}').tabs(#{options[:javascript].to_s});</script>")
|
||||
else
|
||||
output.safe_concat("<script>$('##{the_id.to_s}').tabs();</script>")
|
||||
end
|
||||
output
|
||||
end
|
||||
#
|
||||
def currency_string(amount=0.0)
|
||||
result = ""
|
||||
if amount.to_s.split(".")[1].size < 2
|
||||
result = ("$" << amount.to_s << "0")
|
||||
else
|
||||
result = ("$" << amount.to_s)
|
||||
end
|
||||
result
|
||||
end
|
||||
#
|
||||
end
|
||||
end
|
||||
end
|
||||
Loading…
Reference in a new issue