mirror of
https://github.com/mistergibson/gxg-server.git
synced 2026-08-15 02:15:59 -07:00
2459 lines
138 KiB
Ruby
2459 lines
138 KiB
Ruby
#
|
|
module GxGwww
|
|
#
|
|
RETAINED = {}
|
|
RETAINED_THREAD_SAFETY = ::Mutex.new
|
|
def self.get_retained(the_key)
|
|
result = nil
|
|
RETAINED_THREAD_SAFETY.synchronize do
|
|
result = ::GxGwww::RETAINED[(the_key)]
|
|
end
|
|
result
|
|
end
|
|
def self.set_retained(the_key, the_value=nil)
|
|
RETAINED_THREAD_SAFETY.synchronize do
|
|
::GxGwww::RETAINED[(the_key)] = the_value
|
|
end
|
|
the_value
|
|
end
|
|
# ### API toolbox
|
|
API = {}
|
|
API_SESSIONS = {}
|
|
API_THREAD_SAFETY = ::Mutex.new
|
|
def self.publish_api(the_service=nil, the_path=nil)
|
|
if the_service && the_path
|
|
the_controller = ::GxGwww::APIController.new(the_service, the_path)
|
|
if the_controller
|
|
::GxGwww::API_THREAD_SAFETY.synchronize {
|
|
::GxGwww::API[(the_path.to_sym)] = the_controller
|
|
}
|
|
true
|
|
else
|
|
false
|
|
end
|
|
else
|
|
false
|
|
end
|
|
end
|
|
#
|
|
def self.unpublish_api(the_path="/unknown")
|
|
if the_path
|
|
::GxGwww::API_THREAD_SAFETY.synchronize {
|
|
::GxGwww::API.delete(the_path.to_sym)
|
|
}
|
|
end
|
|
true
|
|
end
|
|
#
|
|
def self.api_login(session_id=nil, credential=:"00000000-0000-4000-0000-000000000000")
|
|
if session_id
|
|
::GxGwww::API_THREAD_SAFETY.synchronize {
|
|
::GxGwww::API_SESSIONS[(session_id.to_sym)] = credential
|
|
}
|
|
true
|
|
else
|
|
false
|
|
end
|
|
end
|
|
#
|
|
def self.api_logout(session_id=nil)
|
|
if session_id
|
|
::GxGwww::API_THREAD_SAFETY.synchronize {
|
|
::GxGwww::API_SESSIONS.delete(session_id.to_sym)
|
|
}
|
|
true
|
|
else
|
|
false
|
|
end
|
|
end
|
|
#
|
|
def self.api_credential(session_id=nil)
|
|
result = :"00000000-0000-4000-0000-000000000000"
|
|
if session_id
|
|
::GxGwww::API_THREAD_SAFETY.synchronize {
|
|
result = (::GxGwww::API_SESSIONS[(session_id.to_sym)] || :"00000000-0000-4000-0000-000000000000")
|
|
}
|
|
end
|
|
result
|
|
end
|
|
#
|
|
class APIController
|
|
def initialize(the_service=nil, the_path="/unknown")
|
|
@service = the_service
|
|
@path = the_path
|
|
end
|
|
def service
|
|
@service
|
|
end
|
|
def path
|
|
@path
|
|
end
|
|
#
|
|
def process(the_method=nil, the_request=nil, the_session=nil)
|
|
credential = ::GxGwww::api_credential(the_session['session_id'])
|
|
# Pre-processing
|
|
response = nil
|
|
operation = nil
|
|
begin
|
|
if the_method
|
|
case the_method
|
|
when :get
|
|
if the_request["details"].to_s == "eyJpbnRyb2R1Y3Rpb24iOnRydWV9"
|
|
response = [200, {"content-type" => "application/text"}, ({:csrf => the_session["csrf"]}.gxg_export.to_json.encode64)]
|
|
else
|
|
operation = (::JSON::parse(URI.unescape(URI.unescape(the_request.params["details"].to_s.decode64.decrypt(the_session["csrf"]))), {:symbolize_names => true}))
|
|
unless operation.is_a?(::Hash)
|
|
response = [500, {"content-type" => "application/text"}, "Malformed query."]
|
|
end
|
|
end
|
|
when :put
|
|
if the_request.body.respond_to?(:rewind) && the_request.body.respond_to?(:read)
|
|
the_request.body.rewind
|
|
operation = (::JSON::parse(URI.unescape(URI.unescape(the_request.body.read().to_s.decode64.decrypt(the_session["csrf"]))), {:symbolize_names => true}))
|
|
unless operation.is_a?(::Hash)
|
|
response = [500, {"content-type" => "application/text"}, "Malformed payload."]
|
|
end
|
|
else
|
|
log_warn("Abnormal PUT Body #{the_request.body.inspect}")
|
|
response = [500, {"content-type" => "application/text"}, "Malformed payload."]
|
|
end
|
|
else
|
|
response = [500, {"content-type" => "application/text"}, "Provide a get or put method."]
|
|
end
|
|
else
|
|
response = [500, {"content-type" => "application/text"}, "No http method provided."]
|
|
end
|
|
rescue Exception => the_error
|
|
response = [500, {"content-type" => "application/text"}, the_error.to_s]
|
|
end
|
|
# Processing
|
|
unless response
|
|
response = [403, {"content-type" => "application/text"}, "You don't have permissions to do that."]
|
|
# Operation formatting
|
|
if operation.is_a?(::Hash)
|
|
operation = ::Hash::gxg_import(operation)
|
|
operation.search do |the_value, the_selector, the_container|
|
|
if the_value.is_a?(::Hash)
|
|
if the_value[:formats].is_a?(::Hash) && the_value[:records].is_a?(::Array)
|
|
imported_list = ::GxG::Database::Database::detached_package_import(the_value)
|
|
if imported_list.size > 1
|
|
the_container[(the_selector)] = imported_list
|
|
else
|
|
the_container[(the_selector)] = imported_list[0]
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
#
|
|
if operation
|
|
case operation.keys[0].to_sym
|
|
when :upgrade_credential
|
|
new_credential = ::GxG::DB[:authority].user_credential(operation[:upgrade_credential][:username].to_s, operation[:upgrade_credential][:password].to_s)
|
|
if new_credential
|
|
response = [200, {"content-type" => "application/text"}, {:result => ::GxGwww::api_login(the_session['session_id'], new_credential), :error => nil}.gxg_export.to_json.encrypt(the_session["csrf"]).encode64]
|
|
else
|
|
response = [403, {"content-type" => "application/text"}, {:result => nil, :error => "Bad username or password."}.gxg_export.to_json.encrypt(the_session["csrf"]).encode64]
|
|
end
|
|
when :downgrade_credential
|
|
response = [200, {"content-type" => "application/text"}, {:result => ::GxGwww::api_logout(the_session['session_id']), :error => nil}.gxg_export.to_json.encrypt(the_session["csrf"]).encode64]
|
|
when :interface
|
|
response = [200, {"content-type" => "application/text"}, @service.interface(credential).gxg_export.to_json.encrypt(the_session["csrf"]).encode64]
|
|
else
|
|
begin
|
|
call_response = @service.call_event(operation, credential)
|
|
if call_response.is_a?(::Hash)
|
|
call_response.search do |the_value, the_selector, the_container|
|
|
if the_value.is_any?(::GxG::Database::PersistedHash, ::GxG::Database::DetachedHash)
|
|
the_container[(the_selector)] = the_value.export_package()
|
|
end
|
|
end
|
|
end
|
|
response = [200, {"content-type" => "application/text"}, call_response.gxg_export.to_json.encrypt(the_session["csrf"]).encode64]
|
|
rescue Exception => the_error
|
|
response = [500, {"content-type" => "application/text"}, the_error.to_s]
|
|
end
|
|
end
|
|
# the_manifest = GxG::SERVICES[:www][:manifests][(the_session['session_id'])]
|
|
end
|
|
end
|
|
#
|
|
response
|
|
# API ????
|
|
# @service.call_event(operation_envelope=nil, credential)
|
|
# GxG::SERVICES[:www][:manifests][(the_session['session_id'])]
|
|
# unless the_manifest
|
|
# the_manifest = ::GxGwww::Manifest.new({:credential => :'00000000-0000-4000-0000-000000000000'})
|
|
# # manifest format: {:credential => :'00000000-0000-4000-0000-000000000000', :displays => {}, :timers => {}, :connectors => {}, :status => :none}
|
|
# GxG::SERVICES[:www][:manifests][(the_session['session_id'])] = the_manifest
|
|
# end
|
|
# operations = []
|
|
# case the_method
|
|
# when :get
|
|
# if the_request.params["details"].to_s.size > 0
|
|
# operations = (::JSON::parse(URI.unescape(URI.unescape(the_request.params["details"].to_s.decode64)), {:symbolize_names => true}))
|
|
# end
|
|
# when :put
|
|
# if the_request.body.respond_to?(:rewind) && the_request.body.respond_to?(:read)
|
|
# the_request.body.rewind
|
|
# operations = (::JSON::parse(URI.unescape(URI.unescape(the_request.body.read())), {:symbolize_names => true}))
|
|
# else
|
|
# log_warn("Abnormal PUT Body #{the_request.body.inspect}")
|
|
# end
|
|
# end
|
|
end
|
|
end
|
|
# ### Application Support
|
|
module Applications
|
|
MENU = []
|
|
def self.refresh_application_menu()
|
|
result = false
|
|
GxGwww::Applications::MENU.clear
|
|
source_queue = ["/Public/www/software/applications"]
|
|
while source_queue.size > 0 do
|
|
the_item = source_queue.shift
|
|
if ::GxG::VFS.exist?(the_item.to_s)
|
|
profile = ::GxG::VFS.profile(the_item.to_s)
|
|
if profile.is_a?(::Hash)
|
|
#
|
|
if [:virtual_directory, :directory, :persisted_array].include?(profile[:type])
|
|
::GxG::VFS.entries(the_item.to_s).each do |entry|
|
|
source_queue << (the_item.to_s + "/" + entry[:title])
|
|
end
|
|
else
|
|
#
|
|
object = GxG::VFS.open(the_item)
|
|
if object[:component].to_s == "application"
|
|
record = {:location => (the_item[7..-1]), :application_icon_type => "", :application_icon => "", :application_name => "", :credentialed => false, :unique => true, :category => ""}
|
|
# TODO: camelize this title text
|
|
record[:application_name] = object.title.gsub("_"," ")
|
|
#
|
|
icon = nil
|
|
icon_type = nil
|
|
object[:content].each do |resource|
|
|
if resource.title() == "application_icon"
|
|
if resource[:options][:image_data]
|
|
icon = resource[:options][:image_data]
|
|
if icon.is_a?(::GxG::ByteArray)
|
|
icon = icon.to_s
|
|
end
|
|
if resource[:options][:image_type]
|
|
icon_type = resource[:options][:image_type]
|
|
else
|
|
mime_type = ::MimeMagic.by_magic(::StringIO.new(icon.to_s))
|
|
if mime_type
|
|
icon_type = mime_type.type
|
|
else
|
|
icon_type = "application/octet-stream"
|
|
end
|
|
end
|
|
icon = icon.encode64
|
|
else
|
|
if resource[:options][:src]
|
|
icon = resource[:options][:src]
|
|
end
|
|
end
|
|
if icon
|
|
break
|
|
end
|
|
end
|
|
end
|
|
if icon
|
|
if icon_type
|
|
record[:application_icon_type] = icon_type
|
|
end
|
|
record[:application_icon] = icon
|
|
else
|
|
cache_entry = GxGwww::CACHE.fetch("/themes/setup/icons/gxg_app.png",GxG::DB[:administrator])
|
|
if cache_entry
|
|
record[:application_icon_type] = cache_entry[:content_type]
|
|
record[:application_icon] = cache_entry[:data].to_s.encode64
|
|
end
|
|
end
|
|
#
|
|
the_options = (object[:options].unpersist || {})
|
|
if the_options[:credentialed] == true
|
|
record[:credentialed] = true
|
|
else
|
|
record[:credentialed] = false
|
|
end
|
|
if the_options[:unique] == true
|
|
record[:unique] = true
|
|
else
|
|
record[:unique] = false
|
|
end
|
|
record[:category] = (the_options[:category] || "Other")
|
|
#
|
|
GxGwww::Applications::MENU << record
|
|
end
|
|
#
|
|
end
|
|
#
|
|
end
|
|
end
|
|
#
|
|
end
|
|
result
|
|
end
|
|
end
|
|
#
|
|
module Storage
|
|
class UnifiedMemoryCache
|
|
# ONLY works with GxG::VFS
|
|
# TODO : re-organize to use UniversalResourceAccessor
|
|
# Access files and objects via: GxG::SERVICES[:core][:resources]
|
|
# returns ==> {:token => the_token, :path => the_path, :resource => the_resource}
|
|
def initialize()
|
|
@cache_configuration = {}
|
|
@cache_memory = {}
|
|
@thread_safety = ::Mutex.new
|
|
@cache_configuration[:cache_quota] = (GxG::SERVICES[:www].configuration[:cache_quota] || 1073741824)
|
|
@cache_configuration[:cache_max_item_size] = (GxG::SERVICES[:www].configuration[:cache_max_item_size] || 1073741824)
|
|
#
|
|
self
|
|
end
|
|
#
|
|
def flush_cache()
|
|
@thread_safety.synchronize { @cache_memory = {} }
|
|
end
|
|
#
|
|
def flush_cache_item(specifier=nil)
|
|
if specifier.is_any?(::String, ::Symbol)
|
|
@thread_safety.synchronize { @cache_memory.delete(specifier.to_s) }
|
|
true
|
|
else
|
|
false
|
|
end
|
|
end
|
|
#
|
|
# def public_vfs_fetch(the_vfs_path="", credential=:"00000000-0000-4000-0000-000000000000")
|
|
# # Does NOT fetch entire directories, only files/db_objects at specific path
|
|
# #
|
|
# log_info("Caching --> #{the_vfs_path}")
|
|
# result = nil
|
|
# unless GxG::SERVICES[:core][:resources].busy?(the_vfs_path)
|
|
# if GxG::SERVICES[:core][:resources].exist?(the_vfs_path)
|
|
# profile = GxG::SERVICES[:core][:resources].profile(the_vfs_path, credential)
|
|
# if profile
|
|
# case profile[:type]
|
|
# when :file, :application, :library, :symlink
|
|
# if profile[:size] <= @cache_configuration[:cache_max_item_size]
|
|
# handle = GxG::SERVICES[:core][:resources].open(the_vfs_path.to_s, credential)
|
|
# if handle
|
|
# handle[:resource].rewind
|
|
# #
|
|
# if (the_vfs_path.to_s[0..10]) == "/Public/www"
|
|
# location = the_vfs_path.to_s[11..-1]
|
|
# else
|
|
# location = the_vfs_path.to_s
|
|
# end
|
|
# #
|
|
# buffer = ::GxG::ByteArray.new(handle[:resource].read())
|
|
# GxG::SERVICES[:core][:resources].close(handle[:token])
|
|
# #
|
|
# result = {:location => location, :entry => {:content_type => profile[:mime], :data => buffer.to_s, :uuid => nil, :version => profile[:version], :database => nil, :profile => profile}}
|
|
# #
|
|
# end
|
|
# else
|
|
# log_warn "VFS file is too big to load (ignoring): #{the_vfs_path.to_s}"
|
|
# end
|
|
# when :persisted_hash
|
|
# handle = GxG::SERVICES[:core][:resources].open(the_vfs_path.to_s, credential)
|
|
# if handle
|
|
# uuid = handle[:resource].uuid
|
|
# version = handle[:resource].version
|
|
# database = handle[:resource].db_address()[:database]
|
|
# db_role = self.role_for_database(database)
|
|
# # Include format records in gxg_export format
|
|
# # This will trade bandwidth + memory for a speed gain later client side hopefully.
|
|
# # Review: replace with <db>.sync_export(credential,<uuid-array>).to_json.encode64
|
|
# format_records = {}
|
|
# object_record = handle[:resource].export
|
|
# object_record.search do |item,selector,container|
|
|
# if selector == :format || selector == :constraint
|
|
# if item.to_s.size > 0 && ::GxG::valid_uuid?(item.to_s)
|
|
# format_uuid = item
|
|
# unless format_records[(item.to_s.to_sym)].is_a?(::Hash)
|
|
# format_sample = database.format_load({:uuid => format_uuid.to_s.to_sym})
|
|
# format_sample[:content] = format_sample[:content].gxg_export()
|
|
# format_records[(format_uuid.to_s.to_sym)] = format_sample
|
|
# end
|
|
# end
|
|
# end
|
|
# end
|
|
# # buffer = ::GxG::ByteArray.new(::JSON.pretty_generate({:formats => format_records, :record => object_record}).encode64)
|
|
# buffer = {:formats => format_records, :record => object_record}.to_json.encode64
|
|
# if buffer.size <= @cache_configuration[:cache_max_item_size]
|
|
# #
|
|
# if (the_vfs_path.to_s[0..10]) == "/Public/www"
|
|
# location = the_vfs_path.to_s[11..-1]
|
|
# else
|
|
# location = the_vfs_path.to_s
|
|
# end
|
|
# #
|
|
# # xxx Set Public permissions on db object. (publication speedup)
|
|
# #
|
|
# # xxx profile[:permissions][:other] = database.effective_element_permission(handle[:resource].db_address[:table], handle[:resource].db_address[:dbid], :"00000000-0000-4000-0000-000000000000")
|
|
# result = {:location => location, :entry => {:content_type => "application/json+base64", :data => buffer.to_s, :uuid => uuid, :version => version, :database => db_role, :profile => profile}}
|
|
# #
|
|
# else
|
|
# log_warn "VFS object is too big to load (ignoring): #{the_vfs_path.to_s}"
|
|
# end
|
|
# GxG::SERVICES[:core][:resources].close(handle[:token])
|
|
# end
|
|
# end
|
|
# end
|
|
# end
|
|
# end
|
|
# result
|
|
# end
|
|
#
|
|
# def add_to_cache(the_vfs_path="")
|
|
# #
|
|
# source_queue = []
|
|
# if the_vfs_path.is_any?(::Array, ::GxG::Database::PersistedArray)
|
|
# source_list = the_vfs_path
|
|
# else
|
|
# source_list = [(the_vfs_path)]
|
|
# end
|
|
# source_list.each do |item|
|
|
# if item.to_s.valid_path?
|
|
# source_queue << item
|
|
# end
|
|
# end
|
|
# #
|
|
# while source_queue.size > 0 do
|
|
# the_item = source_queue.shift
|
|
# if GxG::SERVICES[:core][:resources].exist?(the_item.to_s)
|
|
# profile = GxG::SERVICES[:core][:resources].profile(the_item.to_s)
|
|
# if profile.is_a?(::Hash)
|
|
# #
|
|
# if [:virtual_directory, :directory, :persisted_array].include?(profile[:type])
|
|
# GxG::SERVICES[:core][:resources].entries(the_item.to_s).each do |entry|
|
|
# source_queue << (the_item.to_s + "/" + entry[:title])
|
|
# end
|
|
# else
|
|
# # Cache Item
|
|
# current_cache_size = @thread_safety.synchronize { @cache_memory.heap_used() }
|
|
# record = self.public_vfs_fetch(the_item)
|
|
# if record
|
|
# if (record[:entry][:data].size <= @cache_configuration[:cache_max_item_size] && (record[:entry][:data].size + current_cache_size) <= @cache_configuration[:cache_quota])
|
|
# # Padrino.cache[(record[:location])] = record[:entry]
|
|
# @thread_safety.synchronize { @cache_memory[(record[:location])] = record[:entry] }
|
|
# else
|
|
# log_warn "VFS item is too big to be cached (ignoring): #{the_item.to_s}"
|
|
# end
|
|
# end
|
|
# end
|
|
# #
|
|
# end
|
|
# end
|
|
# #
|
|
# end
|
|
# #
|
|
# end
|
|
#
|
|
def fetch_by_uuid(the_uuid=nil, credential=nil, auto_cache=true,search_only=false)
|
|
result = nil
|
|
# Search Cache first for matching entry
|
|
the_object = nil
|
|
found = nil
|
|
from_cache = false
|
|
unless search_only
|
|
@thread_safety.synchronize do
|
|
@cache_memory.keys.each do |the_key|
|
|
if @cache_memory[(the_key)][:uuid].to_s.to_sym == the_uuid.to_sym
|
|
found = @cache_memory[(the_key)]
|
|
from_cache = true
|
|
break
|
|
end
|
|
end
|
|
end
|
|
end
|
|
# Then search each db by role for the object with the uuid (slow)
|
|
unless found
|
|
already_searched = []
|
|
GxG::DB[:roles].keys.each do |the_db_role|
|
|
the_db = GxG::DB[:roles][(the_db_role)]
|
|
unless already_searched.index(the_db)
|
|
already_searched << the_db
|
|
the_object = the_db.retrieve_by_uuid(the_uuid,credential)
|
|
if the_object.is_a?(::GxG::Database::PersistedHash)
|
|
break
|
|
else
|
|
the_object = nil
|
|
end
|
|
end
|
|
#
|
|
end
|
|
#
|
|
if the_object
|
|
# prepare into Cache entry
|
|
uuid = the_object.uuid
|
|
version = the_object.version
|
|
database = the_object.db_address()[:database]
|
|
db_role = self.role_for_database(database)
|
|
# Include format records in gxg_export format
|
|
format_records = {}
|
|
object_record = the_object.export
|
|
object_record.search do |item,selector,container|
|
|
if selector == :format || selector == :constraint
|
|
if item.to_s.size > 0
|
|
format_uuid = item
|
|
unless format_records[(item.to_s.to_sym)].is_a?(::Hash)
|
|
format_sample = database.format_load({:uuid => format_uuid.to_s.to_sym})
|
|
format_sample[:content] = format_sample[:content].gxg_export()
|
|
format_records[(format_uuid.to_s.to_sym)] = format_sample
|
|
end
|
|
end
|
|
end
|
|
end
|
|
# buffer = ::GxG::ByteArray.new(::JSON.pretty_generate({:formats => format_records, :record => object_record}).encode64)
|
|
buffer = {:formats => format_records, :records => [(object_record)]}.to_json.encode64
|
|
if buffer.size <= @cache_configuration[:cache_max_item_size]
|
|
# Set Public permissions on db object. (publication speedup)
|
|
#
|
|
profile = {:title=> the_object.title, :type=>:persisted_hash, :owner_type=>:persisted_hash, :uuid=>uuid, :on_device=>nil, :on_device_major=>nil, :on_device_minor=>nil, :is_device=>nil, :is_device_major=>nil, :is_device_minor=>nil, :inode=>nil, :flags=>[:read], :hardlinks_to=>0, :user_id=>nil, :group_id=>nil, :size=>0, :block_size=>0, :blocks=>0, :accessed=>nil, :modified=>nil, :status_modified=>nil, :permissions=>{:effective=>{:execute=>false, :rename=>true, :move=>true, :destroy=>true, :create=>true, :write=>true, :read=>true}}, :mode=>nil}
|
|
profile[:permissions][:effective] = database.effective_element_permission(the_object.db_address[:table], the_object.db_address[:dbid], credential.to_s.to_sym)
|
|
#
|
|
profile[:permissions][:other] = database.effective_element_permission(the_object.db_address[:table], the_object.db_address[:dbid], :"00000000-0000-4000-0000-000000000000")
|
|
found = {:content_type => "application/json+base64", :data => buffer.to_s, :uuid => uuid, :version => version, :database => db_role, :profile => profile}
|
|
#
|
|
end
|
|
the_object.deactivate
|
|
end
|
|
end
|
|
# Cache if auto_cache=true
|
|
if found
|
|
unless from_cache
|
|
if auto_cache
|
|
@thread_safety.synchronize do
|
|
@cache_memory[(the_uuid.to_s)] = found
|
|
end
|
|
end
|
|
end
|
|
result = found
|
|
end
|
|
result
|
|
end
|
|
#
|
|
def role_for_database(the_db=nil)
|
|
result = :vfs
|
|
GxG::DB[:roles].keys.each do |the_db_role|
|
|
if the_db == GxG::DB[:roles][(the_db_role)]
|
|
result = the_db_role
|
|
break
|
|
end
|
|
end
|
|
result
|
|
end
|
|
#
|
|
def database_by_role(the_role=nil)
|
|
result = nil
|
|
GxG::DB[:roles].keys.each do |the_db_role|
|
|
if the_role == the_db_role
|
|
result = GxG::DB[:roles][(the_db_role)]
|
|
break
|
|
end
|
|
end
|
|
result
|
|
end
|
|
#
|
|
def update_cache_item(the_vfs_path="")
|
|
# Customizable later:
|
|
if ::GxG::valid_uuid?(the_vfs_path)
|
|
# This is kinda crack-monkey, but it will only search dbs for a fresh copy of the object and add it to Cache.
|
|
self.fetch_by_uuid(the_vfs_path, GxG::DB[:administrator], true, true)
|
|
else
|
|
self.add_to_cache(the_vfs_path)
|
|
end
|
|
true
|
|
end
|
|
#
|
|
def fetch(the_location="",credential=:"00000000-0000-4000-0000-000000000000",auto_cache=true)
|
|
result = nil
|
|
fits_in_cache = true
|
|
#
|
|
if auto_cache == true
|
|
@thread_safety.synchronize {
|
|
result = @cache_memory[(the_location.to_s)]
|
|
}
|
|
end
|
|
unless result.is_a?(::Hash)
|
|
if ::GxG::valid_uuid?(the_location.to_s)
|
|
# DB Object
|
|
result = self.fetch_by_uuid(the_location.to_s, credential, false, false)
|
|
else
|
|
# File or DB Object in VFS
|
|
handle = ::GxG::SERVICES[:core][:resources].open(the_location.to_s, credential)
|
|
#
|
|
profile = ::GxG::SERVICES[:core][:resources].profile(the_location.to_s, credential)
|
|
#
|
|
if handle.is_a?(::Hash) && profile.is_a?(::Hash)
|
|
if handle[:resource].is_a?(::GxG::Database::PersistedHash)
|
|
# DB Object
|
|
uuid = handle[:resource].uuid
|
|
version = handle[:resource].version
|
|
database = handle[:resource].db_address()[:database]
|
|
db_role = self.role_for_database(database)
|
|
# Include format records in gxg_export format
|
|
format_records = {}
|
|
object_record = handle[:resource].export
|
|
object_record.search do |item,selector,container|
|
|
if selector == :format || selector == :constraint
|
|
if item.to_s.size > 0
|
|
format_uuid = item
|
|
unless format_records[(item.to_s.to_sym)].is_a?(::Hash)
|
|
format_sample = database.format_load({:uuid => format_uuid.to_s.to_sym})
|
|
if format_sample.is_a?(::Hash)
|
|
format_sample[:content] = format_sample[:content].gxg_export()
|
|
format_records[(format_uuid.to_s.to_sym)] = format_sample
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
# buffer = ::GxG::ByteArray.new(::JSON.pretty_generate({:formats => format_records, :record => object_record}).encode64)
|
|
buffer = {:formats => format_records, :records => [(object_record)]}.to_json.encode64
|
|
result = {:content_type => "application/json+base64", :data => buffer.to_s, :uuid => uuid, :version => version, :database => db_role, :profile => profile}
|
|
unless buffer.size <= @cache_configuration[:cache_max_item_size]
|
|
fits_in_cache = false
|
|
log_warn("Item TOO BIG for CACHE : #{buffer.size} for #{handle[:path]}")
|
|
end
|
|
else
|
|
# File Object
|
|
if handle[:resource].is_a?(::File)
|
|
handle[:resource].rewind
|
|
buffer = ::GxG::ByteArray.new(handle[:resource].read().to_s)
|
|
result = {:content_type => profile[:mime], :data => buffer.to_s, :uuid => nil, :version => profile[:version], :database => nil, :profile => profile}
|
|
unless buffer.size <= @cache_configuration[:cache_max_item_size]
|
|
fits_in_cache = false
|
|
log_warn("Item TOO BIG for CACHE : #{buffer.size} for #{handle[:path]}")
|
|
end
|
|
end
|
|
end
|
|
#
|
|
::GxG::SERVICES[:core][:resources].close(handle[:token])
|
|
end
|
|
end
|
|
if result.is_a?(::Hash)
|
|
if auto_cache == true && fits_in_cache == true
|
|
# Store in CACHE
|
|
@thread_safety.synchronize {
|
|
@cache_memory[(the_location.to_s)] = result
|
|
}
|
|
end
|
|
end
|
|
end
|
|
#
|
|
result
|
|
end
|
|
end
|
|
end
|
|
# DisplayState
|
|
class Display
|
|
def initialize(settings={})
|
|
@resource_path = settings[:resource]
|
|
@session = settings[:session]
|
|
@uuid = (settings[:uuid] || GxG::uuid_generate)
|
|
@remote_uuid = nil
|
|
@socket = nil
|
|
self
|
|
end
|
|
#
|
|
def socket()
|
|
@socket
|
|
end
|
|
#
|
|
def set_socket(the_uuid)
|
|
the_socket = nil
|
|
GxGwww::SOCKETS_SAFETY.synchronize {
|
|
the_socket = GxGwww::SOCKETS[(the_uuid)]
|
|
if the_socket
|
|
the_socket.instance_variable_set(:@session, @session)
|
|
the_socket.instance_variable_set(:@display, @uuid)
|
|
end
|
|
}
|
|
if the_socket
|
|
@socket = the_socket
|
|
true
|
|
else
|
|
false
|
|
end
|
|
end
|
|
end
|
|
#
|
|
class Manifest
|
|
def initialize(settings={})
|
|
@thread_safety = ::Mutex.new
|
|
@credential = (settings[:credential] || :"00000000-0000-4000-0000-000000000000")
|
|
@displays ={}
|
|
@connectors = {}
|
|
@timers = {}
|
|
@state = :uncredentialed
|
|
self
|
|
end
|
|
#
|
|
def credential_set(the_credential=:"00000000-0000-4000-0000-000000000000")
|
|
if the_credential
|
|
@thread_safety.synchronize {
|
|
@credential = the_credential
|
|
}
|
|
end
|
|
end
|
|
#
|
|
def credential_get()
|
|
the_credential = :"00000000-0000-4000-0000-000000000000"
|
|
@thread_safety.synchronize {
|
|
the_credential = @credential
|
|
}
|
|
the_credential
|
|
end
|
|
#
|
|
def display_count()
|
|
the_count = 0
|
|
@thread_safety.synchronize {
|
|
the_count = @displays.keys.size
|
|
}
|
|
the_count
|
|
end
|
|
#
|
|
def display_keys()
|
|
the_keys = []
|
|
@thread_safety.synchronize {
|
|
the_keys = @displays.keys
|
|
}
|
|
the_keys
|
|
end
|
|
#
|
|
def display_exist?(the_display_key=nil)
|
|
result = false
|
|
if the_display_key
|
|
@thread_safety.synchronize {
|
|
if @displays[(the_display_key)]
|
|
result = true
|
|
end
|
|
}
|
|
end
|
|
result
|
|
end
|
|
#
|
|
def display_get(the_display_key=nil)
|
|
result = :available
|
|
if the_display_key
|
|
@thread_safety.synchronize {
|
|
result = @displays[(the_display_key)]
|
|
}
|
|
end
|
|
result
|
|
end
|
|
#
|
|
def display_set(the_display_key=nil, the_value=:available)
|
|
result = nil
|
|
if the_display_key
|
|
@thread_safety.synchronize {
|
|
@displays[(the_display_key)] = the_value
|
|
}
|
|
end
|
|
result
|
|
end
|
|
#
|
|
def state_set(the_state=:none)
|
|
@thread_safety.synchronize {
|
|
@state = the_state
|
|
}
|
|
end
|
|
#
|
|
def state_get()
|
|
the_state = :none
|
|
@thread_safety.synchronize {
|
|
the_state = @state
|
|
}
|
|
the_state
|
|
end
|
|
#
|
|
def timer_get(the_display_key=nil)
|
|
result = nil
|
|
if the_display_key
|
|
@thread_safety.synchronize {
|
|
result = @timers[(the_display_key)]
|
|
}
|
|
end
|
|
result
|
|
end
|
|
#
|
|
def timer_set(the_display_key=nil, timeout=0.0)
|
|
if the_display_key
|
|
@thread_safety.synchronize {
|
|
@timers[(the_display_key)] = timeout
|
|
}
|
|
timeout
|
|
else
|
|
nil
|
|
end
|
|
end
|
|
#
|
|
def connector_get(the_display_key=nil)
|
|
result = nil
|
|
if the_display_key
|
|
@thread_safety.synchronize {
|
|
result = @connectors[(the_display_key)]
|
|
}
|
|
end
|
|
result
|
|
end
|
|
#
|
|
def connector_set(the_display_key=nil, the_connector=nil)
|
|
if the_display_key && the_connector
|
|
@thread_safety.synchronize {
|
|
@connectors[(the_display_key)] = the_connector
|
|
}
|
|
end
|
|
end
|
|
end
|
|
# ---------------------------------------------------------------------
|
|
class Responder
|
|
#
|
|
def initialize(options={})
|
|
@thread_safety = ::Mutex.new
|
|
end
|
|
#
|
|
def handle_request(the_method=nil, the_request=nil, the_session=nil)
|
|
response = [404, {"content-type" => "application/text"}, "Not Found"]
|
|
begin
|
|
response[2] = "#{the_request.path} Not Found"
|
|
if the_request.xhr?
|
|
the_manifest = GxG::SERVICES[:www][:manifests][(the_session['session_id'])]
|
|
unless the_manifest
|
|
the_manifest = ::GxGwww::Manifest.new({:credential => :'00000000-0000-4000-0000-000000000000'})
|
|
# manifest format: {:credential => :'00000000-0000-4000-0000-000000000000', :displays => {}, :timers => {}, :connectors => {}, :status => :none}
|
|
GxG::SERVICES[:www][:manifests][(the_session['session_id'])] = the_manifest
|
|
end
|
|
# the_display = (the_request.params["display_path"] || the_request.env["GxG-Display"])
|
|
the_display = the_request.params["display"]
|
|
if the_display.is_a?(::String)
|
|
if the_display.match(/\/display\/[0-9]/) || the_display.match(/\/display\/[0-9][0-9]/)
|
|
if the_manifest
|
|
if the_manifest.display_count() > 0
|
|
unless (the_display.split("/").last.to_i + 1) <= the_manifest.display_count()
|
|
log_warn "Invalid Display Reference: #{the_display.inspect}"
|
|
end
|
|
end
|
|
end
|
|
else
|
|
the_display = nil
|
|
end
|
|
else
|
|
the_display = nil
|
|
end
|
|
#
|
|
operations = []
|
|
case the_method
|
|
when :get
|
|
if the_request.params["details"].to_s.size > 0
|
|
operations = (::JSON::parse(URI.unescape(URI.unescape(the_request.params["details"].to_s.decode64)), {:symbolize_names => true}))
|
|
end
|
|
when :put
|
|
if the_request.body.respond_to?(:rewind) && the_request.body.respond_to?(:read)
|
|
the_request.body.rewind
|
|
operations = (::JSON::parse(URI.unescape(URI.unescape(the_request.body.read())), {:symbolize_names => true}))
|
|
else
|
|
log_warn("Abnormal PUT Body #{the_request.body.inspect}")
|
|
end
|
|
when :post
|
|
#
|
|
if the_request.params["file"]
|
|
if the_request.params["file"][:tempfile]
|
|
temp_file = the_request.params["file"][:tempfile]
|
|
if the_request.params["file"][:filename]
|
|
file_name = the_request.params["file"][:filename]
|
|
if the_request.params["destination"]
|
|
destination = the_request.params["destination"]
|
|
operations = [{:upload_file => {:temp_file => temp_file, :file_name => file_name, :destination => destination}}]
|
|
end
|
|
end
|
|
end
|
|
#
|
|
end
|
|
#
|
|
end
|
|
unless operations.is_a?(::Array)
|
|
operations = [(operations)]
|
|
end
|
|
operations.each do |operation_frame|
|
|
if operation_frame.is_a?(::Hash)
|
|
the_operation = operation_frame.keys[0]
|
|
parameters = operation_frame[(the_operation)]
|
|
# Review : DEBUG:
|
|
puts "Operation: #{the_operation.inspect} => #{parameters.inspect}"
|
|
puts "Remote Host: #{the_request.env["HTTP_X_FORWARDED_FOR"].inspect}"
|
|
puts "Session: #{the_session['session_id'].inspect}"
|
|
#
|
|
case the_operation
|
|
when :heartbeat
|
|
# use display_path? reset timer info?
|
|
# pass server/credential status: :private or :public indicators only
|
|
if the_manifest.credential_get() == :"00000000-0000-4000-0000-000000000000"
|
|
status = {:status => "uncredentialed"}
|
|
status[:credential] = (the_manifest.state_get() || :uncredentialed)
|
|
else
|
|
status = {:status => "credentialed"}
|
|
status[:credential] = (the_manifest.state_get() || :credentialed)
|
|
end
|
|
if true
|
|
# TODO: track and return the running mode of the server - Expansion
|
|
status[:server] = :running
|
|
else
|
|
status[:server] = :maintainence
|
|
end
|
|
if the_display
|
|
the_manifest.timer_set(the_display, ::Chronic::parse("in 3 minutes").to_f)
|
|
end
|
|
#
|
|
response = [200, {"content-type" => "application/json"}, {:result => status}.to_json()]
|
|
break
|
|
#
|
|
when :attach_socket
|
|
if the_display
|
|
the_uuid = parameters.to_s.to_sym
|
|
if ::GxG::valid_uuid?(the_uuid)
|
|
GxGwww::SOCKETS_SAFETY.synchronize {
|
|
GxGwww::SOCKETS[(the_uuid)].instance_variable_set(:@session, the_session['session_id'])
|
|
GxGwww::SOCKETS[(the_uuid)].instance_variable_set(:@display, the_display)
|
|
}
|
|
if GxG::SERVICES[:www][:manifests][(the_session['session_id'])]
|
|
connector = GxG::SERVICES[:www][:manifests][(the_session['session_id'])].connector_get(the_display)
|
|
if connector
|
|
connector.set_socket_uuid(the_uuid)
|
|
else
|
|
raise Exception, "Connector Not Found."
|
|
end
|
|
else
|
|
raise Exception, "Manifest Not Found For Session."
|
|
end
|
|
puts "Websocket Attached: #{the_uuid.inspect}"
|
|
response = [200, {"content-type" => "application/json"}, {:result => true}.to_json()]
|
|
break
|
|
end
|
|
end
|
|
# Review : TODO: more follow up on internal socket messaging system
|
|
#
|
|
when :close
|
|
if the_display
|
|
if the_manifest.display_exist?(the_display)
|
|
the_manifest.display_set(the_display, :available)
|
|
unless the_manifest.connector_get(the_display).remote_closed?
|
|
the_manifest.connector_get(the_display).close_remote
|
|
end
|
|
end
|
|
response = [200, {"content-type" => "application/json"}, {:result => true}.to_json()]
|
|
break
|
|
end
|
|
when :introduction
|
|
# puts "Introduction Display: #{the_display.inspect}"
|
|
connection_uuid = nil
|
|
remote_uuid = parameters.to_s.to_sym
|
|
unless ::GxG::valid_uuid?(remote_uuid.to_s)
|
|
raise "Invalid Remote ID."
|
|
end
|
|
# xxx
|
|
unless the_display
|
|
# Expire old Displays and set to :available
|
|
the_manifest.display_keys.each do |display_key|
|
|
if the_manifest.timer_get(display_key).is_a?(::Numeric)
|
|
if Time.now.to_f > the_manifest.timer_get(display_key)
|
|
the_manifest.display_set(display_key, :available)
|
|
connector = the_manifest.connector_get(display_key)
|
|
if connector
|
|
unless connector.remote_closed?
|
|
connector.close_remote
|
|
end
|
|
end
|
|
end
|
|
else
|
|
the_manifest.timer_set(display_key, ::Chronic::parse("in 3 minutes").to_f)
|
|
the_manifest.display_set(display_key, :available)
|
|
connector = the_manifest.connector_get(display_key)
|
|
if connector
|
|
unless connector.remote_closed?
|
|
connector.close_remote
|
|
end
|
|
end
|
|
end
|
|
end
|
|
# Find available Display
|
|
the_manifest.display_keys.each do |display_key|
|
|
if the_manifest.display_get(display_key) == :available
|
|
the_manifest.display_set(display_key, :in_use)
|
|
the_manifest.timer_set(display_key, ::Chronic::parse("in 3 minutes").to_f)
|
|
connector = the_manifest.connector_get(display_key)
|
|
if connector
|
|
# re-open Connector
|
|
connector.open_remote(remote_uuid)
|
|
else
|
|
# puts "Connector Created."
|
|
# create Connector
|
|
connector_settings = {
|
|
:display => display_key,
|
|
:session_id => the_session['session_id'],
|
|
:remote_uuid => remote_uuid,
|
|
:credential => the_manifest.credential_get(),
|
|
:credential_status => :running
|
|
}
|
|
#
|
|
the_manifest.connector_set(display_key, ::GxGwww::Connector.new(connector_settings))
|
|
# Review: what are all the session-wide manifest states possible?
|
|
the_manifest.state_set(:running)
|
|
end
|
|
the_display = display_key
|
|
connection_uuid = connector.uuid()
|
|
break
|
|
end
|
|
end
|
|
# Add Display if needed
|
|
unless the_display
|
|
the_display = ("/display/" << the_manifest.display_count.to_s)
|
|
the_manifest.display_set(the_display, :in_use)
|
|
the_manifest.timer_set(the_display, ::Chronic::parse("in 3 minutes").to_f)
|
|
connector_settings = {
|
|
:display => the_display,
|
|
:session_id => the_session['session_id'],
|
|
:remote_uuid => remote_uuid,
|
|
:credential => the_manifest.credential_get(),
|
|
:credential_status => :running
|
|
}
|
|
connector = ::GxGwww::Connector.new(connector_settings)
|
|
# puts "Connector Created - 2nd Portion."
|
|
the_manifest.connector_set(the_display, connector)
|
|
connection_uuid = connector.uuid()
|
|
end
|
|
end
|
|
unless connection_uuid
|
|
connector = the_manifest.connector_get(the_display)
|
|
if connector
|
|
connection_uuid = connector.uuid()
|
|
end
|
|
end
|
|
#
|
|
if the_manifest.credential_get() == :"00000000-0000-4000-0000-000000000000"
|
|
current_status = "uncredentialed"
|
|
else
|
|
current_status = "credentialed"
|
|
end
|
|
#
|
|
response = [200, {"content-type" => "application/json"}, {:result => "OK", :csrf => the_session["csrf"], :display => the_display, :relative_url => GxG::SERVICES[:www].configuration[:relative_url], :remote_uuid => connection_uuid.to_s, :status => current_status}.to_json()]
|
|
#
|
|
break
|
|
when :downgrade_credential
|
|
the_manifest.state_set(:exiting)
|
|
the_manifest.display_keys.each do |display_key|
|
|
if the_manifest.connector_get(display_key)
|
|
the_manifest.connector_get(display_key).update_credential_status(the_manifest.state_get())
|
|
end
|
|
end
|
|
#
|
|
# manifest[:connectors][(the_display)].update_credential_status(status[:credential])
|
|
# check if the connectors are 'exitready'
|
|
if the_manifest.state_get() == :exiting
|
|
readyflag = true
|
|
the_manifest.display_keys.each do |display_key|
|
|
if the_manifest.connector_get(display_key)
|
|
unless the_manifest.connector_get(display_key).exitready?
|
|
readyflag = false
|
|
end
|
|
end
|
|
end
|
|
if readyflag == true
|
|
the_manifest.credential_set(:"00000000-0000-4000-0000-000000000000")
|
|
the_manifest.state_set(:uncredentialed)
|
|
the_manifest.display_keys.each do |display_key|
|
|
connector = the_manifest.connector_get(display_key)
|
|
if connector
|
|
connector.update_credential(:"00000000-0000-4000-0000-000000000000")
|
|
connector.update_credential_status(the_manifest.state_get())
|
|
end
|
|
end
|
|
end
|
|
end
|
|
#
|
|
response = [200, {"content-type" => "application/json"}, {:status => "uncredentialed"}.to_json()]
|
|
#
|
|
break
|
|
when :update_credential
|
|
response = [404, {"content-type" => "application/json"}, {:status => "Not Found"}.to_json()]
|
|
if parameters.base64?
|
|
parameters = parameters.decode64
|
|
end
|
|
parameters = parameters.decrypt(the_session["csrf"].to_s)
|
|
if parameters.json?
|
|
parameters = ::JSON::parse(parameters, {:symbolize_names => true})
|
|
new_credential = GxG::DB[:authority].user_credential(parameters[:user].to_s, parameters[:password].to_s)
|
|
if new_credential.is_any?(::String, ::Symbol)
|
|
the_manifest.credential_set(new_credential.to_s.to_sym)
|
|
# update connector credentials
|
|
the_manifest.display_keys.each do |display_key|
|
|
the_connector = the_manifest.connector_get(display_key)
|
|
if the_connector
|
|
the_connector.update_credential(new_credential.to_s.to_sym)
|
|
end
|
|
end
|
|
response = [200, {"content-type" => "application/json"}, {:status => "credentialed"}.to_json()]
|
|
#
|
|
break
|
|
else
|
|
# Failed login attempt
|
|
log_warn("Failed login attempt with: #{parameters.inspect}")
|
|
end
|
|
else
|
|
# Hack attempt maybe? Malformed certainly.
|
|
log_warn("Malformed payload on login attempt with: #{parameters.inspect}")
|
|
end
|
|
#
|
|
else
|
|
# Review : dispatch the_operation (operations not baked-in toward session/sockets) to the connector
|
|
if the_display
|
|
the_manifest.timer_set(the_display, ::Chronic::parse("in 3 minutes").to_f)
|
|
connector = the_manifest.connector_get(the_display)
|
|
if connector
|
|
if connector.respond_to?(the_operation)
|
|
if parameters
|
|
response = connector.send(the_operation, parameters)
|
|
else
|
|
response = connector.send(the_operation)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
#
|
|
end
|
|
# end the_operation case
|
|
end
|
|
end
|
|
# end .xhr?
|
|
else
|
|
# TODO : check for websocket here and place on the right display object/connector.
|
|
# Standard request
|
|
# Strip BASEURL if present
|
|
if GxG::SERVICES[:www].configuration[:relative_url].size > 0
|
|
request_path = the_request.path[((GxG::SERVICES[:www].configuration[:relative_url].size)..-1)]
|
|
else
|
|
request_path = the_request.path
|
|
end
|
|
#
|
|
# puts "Got Request Path: #{request_path}"
|
|
# ????
|
|
case the_method
|
|
when :get, :put
|
|
if request_path.to_s.downcase[(0..3)].include?("/api")
|
|
# Filter for API controller match
|
|
the_controller = nil
|
|
::GxGwww::API_THREAD_SAFETY.synchronize {
|
|
::GxGwww::API.each_pair do |the_path, the_handler|
|
|
if request_path.to_s[(4..-1)] == the_path.to_s
|
|
the_controller = the_handler
|
|
break
|
|
end
|
|
end
|
|
}
|
|
if the_controller
|
|
response = the_controller.process(the_method, the_request, the_session)
|
|
else
|
|
response = [404, {"content-type" => "application/text"}, "Endpoint Not Found"]
|
|
end
|
|
else
|
|
if ["", "/", "/index"].include?(request_path) || ::GxG::SERVICES[:core][:resources].exist?("/Public/www/content/pages#{request_path}")
|
|
# Send bootstrap html page and wait for xhr requests
|
|
# content = GxGwww::CACHE.fetch("/page.html",the_session[:credential])
|
|
response[0] = 200
|
|
# response[1]["content-type"] = content[:content_type]
|
|
response[1]["content-type"] = "text/html"
|
|
# response[2] = content[:data]
|
|
response[2] = self.default_page_content()
|
|
else
|
|
# Asset :get request
|
|
if ::GxG::SERVICES[:core][:resources].exist?(("/Public/www" << request_path))
|
|
content = GxGwww::CACHE.fetch(("/Public/www" << request_path), (the_session[:credential] || :"00000000-0000-4000-0000-000000000000"), true)
|
|
if content
|
|
response[0] = 200
|
|
response[1]["content-type"] = content[:content_type]
|
|
response[1]["X-Content-Type-Options"] = "nosniff"
|
|
response[2] = content[:data]
|
|
else
|
|
log_warn "Failed to fetch: #{request_path}"
|
|
end
|
|
end
|
|
end
|
|
end
|
|
when :post
|
|
# if the_request.path.include?("/display/")
|
|
# if the_request.params["operation"] == "close"
|
|
# puts "Close Attempt on #{the_request.path}"
|
|
# end
|
|
# end
|
|
when :delete
|
|
end
|
|
end
|
|
rescue Exception => the_error
|
|
log_error({:error => the_error, :parameters => {:method => the_method, :request => the_request, :session => the_session}})
|
|
response = [500, {"content-type" => "application/text"}, "Error"]
|
|
end
|
|
#
|
|
response
|
|
end
|
|
#
|
|
def default_page_content()
|
|
result = ""
|
|
#
|
|
result << "<html>\n"
|
|
result << "\t<head>\n"
|
|
result << "\t\t<meta charset=\"utf-8\">\n"
|
|
result << "\t\t<meta http-equiv=\"x-ua-compatible\" content=\"ie=edge\">\n"
|
|
result << "\t\t<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\n"
|
|
# result << ("\t\t<link rel=\"stylesheet\" href=\"http://fonts.googleapis.com/css?family=Varela\">\n")
|
|
result << ("\t\t<link rel=\"stylesheet\" type=\"text/css\" href=\"" + GxG::SERVICES[:www].configuration[:relative_url].to_s + "/themes/foundation.css\">\n")
|
|
# result << ("\t\t<link rel=\"stylesheet\" type=\"text/css\" href=\"" + $GxG::SERVICES[:www].configuration[:relative_url].to_s + "/themes/app.css\">\n")
|
|
result << ("\t\t<link rel=\"stylesheet\" type=\"text/css\" href=\"" + GxG::SERVICES[:www].configuration[:relative_url].to_s + "/themes/page.css\">\n")
|
|
result << "\t</head>\n"
|
|
result << "\t<body>\n"
|
|
result << ("\t\t<script id=\"jquery\" type=\"text/javascript\" src=\"" + GxG::SERVICES[:www].configuration[:relative_url].to_s + "/javascript/vendor/jquery.js\"></script>\n")
|
|
result << ("\t\t<script id=\"what.input\" type=\"text/javascript\" src=\"" + GxG::SERVICES[:www].configuration[:relative_url].to_s + "/javascript/vendor/what-input.js\"></script>\n")
|
|
result << ("\t\t<script id=\"foundation\" type=\"text/javascript\" src=\"" + GxG::SERVICES[:www].configuration[:relative_url].to_s + "/javascript/vendor/foundation.js\"></script>\n")
|
|
result << ("\t\t<script id=\"ponyfill\" type=\"text/javascript\" src=\"" + GxG::SERVICES[:www].configuration[:relative_url].to_s + "/javascript/vendor/ponyfill.min.js\"></script>\n")
|
|
result << ("\t\t<script id=\"streamsaver\" type=\"text/javascript\" src=\"" + GxG::SERVICES[:www].configuration[:relative_url].to_s + "/javascript/vendor/StreamSaver.min.js\"></script>\n")
|
|
result << ("\t\t<script>$(document).foundation();</script>\n")
|
|
result << ("\t\t<script id=\"kute.animation\" type=\"text/javascript\" src=\"" + GxG::SERVICES[:www].configuration[:relative_url].to_s + "/javascript/kute/kute.min.js\"></script>\n")
|
|
result << ("\t\t<script id=\"kute.attr\" type=\"text/javascript\" src=\"" + GxG::SERVICES[:www].configuration[:relative_url].to_s + "/javascript/kute/kute-attr.min.js\"></script>\n")
|
|
result << ("\t\t<script id=\"kute.css\" type=\"text/javascript\" src=\"" + GxG::SERVICES[:www].configuration[:relative_url].to_s + "/javascript/kute/kute-css.min.js\"></script>\n")
|
|
result << ("\t\t<script id=\"kute.text\" type=\"text/javascript\" src=\"" + GxG::SERVICES[:www].configuration[:relative_url].to_s + "/javascript/kute/kute-text.min.js\"></script>\n")
|
|
result << ("\t\t<script id=\"kute.svg\" type=\"text/javascript\" src=\"" + GxG::SERVICES[:www].configuration[:relative_url].to_s + "/javascript/kute/kute-svg.min.js\"></script>\n")
|
|
result << ("\t\t<script id=\"gxg\" type=\"text/javascript\" src=\"" + GxG::SERVICES[:www].configuration[:relative_url].to_s + "/javascript/gxg.js\"></script>\n")
|
|
result << "\t</body>\n"
|
|
result << "</html>"
|
|
#
|
|
result
|
|
end
|
|
#
|
|
end
|
|
#
|
|
class Connector
|
|
#
|
|
def initialize(settings={})
|
|
@uuid = ::GxG::uuid_generate().to_sym
|
|
@remote_uuid = settings[:remote_uuid].to_s.to_sym
|
|
@credential = settings[:credential]
|
|
@credential_status = settings[:credential_status]
|
|
@active = true
|
|
@application_states = []
|
|
@display = settings[:display]
|
|
@session_id = settings[:session_id]
|
|
@socket = nil
|
|
# ????
|
|
self
|
|
end
|
|
#
|
|
def socket_uuid()
|
|
@socket
|
|
end
|
|
#
|
|
def uuid()
|
|
@uuid
|
|
end
|
|
def update_credential(the_credential=nil)
|
|
if ::GxG::valid_uuid?(the_credential.to_s)
|
|
@credential = the_credential.to_s.to_sym
|
|
end
|
|
true
|
|
end
|
|
#
|
|
def update_credential_status(credential_status)
|
|
@credential_status = credential_status
|
|
end
|
|
#
|
|
def exitready?()
|
|
# When all applications acknowledge exiting status and set 'exitready' THEN downgrade the credential and return true.
|
|
exitready = true
|
|
@application_states.each do |the_record|
|
|
unless the_record[:status] == 'exitready'
|
|
exitready = false
|
|
break
|
|
end
|
|
end
|
|
exitready
|
|
end
|
|
#
|
|
def inspect()
|
|
"<Connector: :uuid => #{@uuid.inspect}, :remote_uuid => #{@remote_uuid.inspect}>"
|
|
end
|
|
#
|
|
def open_remote(remote_uuid=nil)
|
|
if remote_uuid
|
|
@remote_uuid = remote_uuid.to_s.to_sym
|
|
@active = true
|
|
end
|
|
end
|
|
#
|
|
def close_remote()
|
|
@remote_uuid = nil
|
|
@active = false
|
|
end
|
|
#
|
|
def remote_closed?
|
|
if @remote_uuid
|
|
false
|
|
else
|
|
true
|
|
end
|
|
end
|
|
#
|
|
def close()
|
|
close_remote
|
|
end
|
|
#
|
|
def closed?
|
|
! @active
|
|
end
|
|
# ---------------------------------------------
|
|
# Callable Toolbox
|
|
def set_socket_uuid(the_uuid)
|
|
@socket = the_uuid
|
|
end
|
|
#
|
|
def admin_get_roles()
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
if GxG::DB[:authority].role_member?(GxG::DB[:authority][:system_credentials][:administrators], @credential)
|
|
response = [200, {"content-type" => "application/json"}, ({:result => GxG::DB[:authority].role_manifest()}).to_json]
|
|
else
|
|
# err - Hack attempt ??
|
|
response = [404, {"content-type" => "application/json"}, ({:result => false, :error => "Not Found.", :parameters => false}).to_json()]
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def call_event(details={})
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
the_service = ::GxG::SERVICES[(details[:service].to_s.downcase.to_sym)]
|
|
if the_service
|
|
the_result = the_service.call_event(details[:op_frame], @credential)
|
|
if the_result[:error]
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => the_result[:error], :parameters => false}).to_json()]
|
|
else
|
|
response = [200, {"content-type" => "application/json"}, (the_result.to_json)]
|
|
end
|
|
else
|
|
# err - service not found
|
|
response = [404, {"content-type" => "application/json"}, ({:result => false, :error => "Service #{details[:service].to_s} Not Found.", :parameters => false}).to_json()]
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def upload_file(details={})
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Unknown Error."}).to_json()]
|
|
# {:temp_file => temp_file, :file_name => file_name, :destination => destination}
|
|
begin
|
|
temp_dir = "/Temporary/#{::GxG::uuid_generate().to_s}"
|
|
download_path = "#{temp_dir + "/" + (details[:file_name] || "Untitled").to_s}"
|
|
#
|
|
if details[:destination].to_s[0..4] == "/User"
|
|
if @credential == :"00000000-0000-4000-0000-000000000000"
|
|
details[:destination] = ("/Public/www/" << details[:destination].to_s[5..-1]).gsub("//","/")
|
|
else
|
|
details[:destination] = ("/Users/#{@credential.to_s}/" << details[:destination].to_s[5..-1]).gsub("//","/")
|
|
unless GxG::SERVICES[:core][:resources].home_mounted?(@credential)
|
|
GxG::SERVICES[:core][:resources].home_mount(@credential)
|
|
end
|
|
end
|
|
else
|
|
details[:destination] = ("/Public/www/" << details[:destination].to_s).gsub("//","/")
|
|
end
|
|
if GxG::SERVICES[:core][:resources].permissions(details[:destination], @credential)[:write] == true
|
|
#
|
|
final_path = "#{details[:destination].to_s + "/" + (details[:file_name] || "Untitled").to_s}".gsub("//","/")
|
|
GxG::SERVICES[:core][:resources].create_directory(temp_dir, ::GxG::DB[:administrator])
|
|
GxG::SERVICES[:core][:resources].create(download_path, ::GxG::DB[:administrator])
|
|
handle = GxG::SERVICES[:core][:resources].open_writable(download_path, ::GxG::DB[:administrator])
|
|
handle[:resource].write details[:temp_file].read
|
|
GxG::SERVICES[:core][:resources].close(handle[:token])
|
|
GxG::SERVICES[:core][:resources].move(download_path, ::GxG::DB[:administrator], final_path)
|
|
GxG::SERVICES[:core][:resources].set_permissions(final_path, @credential, {:execute => false, :rename => true, :move => true, :destroy => true, :create => true, :write => true, :read=>true})
|
|
GxG::SERVICES[:core][:resources].destroy(temp_dir, ::GxG::DB[:administrator])
|
|
#
|
|
response = [200, {"content-type" => "application/json"}, ({:result => true}).to_json()]
|
|
else
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "You lack permissions to write."}).to_json()]
|
|
end
|
|
rescue Exception => the_error
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => the_error.to_s}).to_json()]
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def download_file(details={})
|
|
# {:path => "/path/to/object"}
|
|
response = [404, {"content-type" => "application/json"}, ({:result => false, :error => "Object Not Found."}).to_json()]
|
|
puts "Download Got: #{details.inspect}"
|
|
begin
|
|
#
|
|
temp_dir = "/Temporary/#{::GxG::uuid_generate().to_s}"
|
|
final_path = "#{temp_dir}/#{File.basename(details[:path])}"
|
|
#
|
|
if details[:path].to_s[0..4] == "/User"
|
|
if @credential == :"00000000-0000-4000-0000-000000000000"
|
|
details[:path] = ("/Public/www/" << details[:path].to_s[5..-1]).gsub("//","/")
|
|
else
|
|
details[:path] = ("/Users/#{@credential.to_s}/" << details[:path].to_s[5..-1]).gsub("//","/")
|
|
unless GxG::SERVICES[:core][:resources].home_mounted?(@credential)
|
|
GxG::SERVICES[:core][:resources].home_mount(@credential)
|
|
end
|
|
end
|
|
else
|
|
details[:path] = ("/Public/www/" << details[:path].to_s).gsub("//","/")
|
|
end
|
|
#
|
|
puts "Download Path: #{details.inspect}"
|
|
# temp_file = "#{temp_dir}/#{File.basename((details[:path] || 'Untitled').to_s)}"
|
|
if GxG::SERVICES[:core][:resources].exist?(details[:path])
|
|
profile = GxG::SERVICES[:core][:resources].profile(details[:path], @credential)
|
|
if profile
|
|
if profile[:permissions][:effective][:read] == true
|
|
GxG::SERVICES[:core][:resources].create_directory(temp_dir, ::GxG::DB[:administrator])
|
|
if GxG::SERVICES[:core][:resources].copy(details[:path], ::GxG::DB[:administrator], final_path)
|
|
cache_profile = (GxG::SERVICES[:core][:resources].entries(temp_dir, ::GxG::DB[:administrator]) || []).first
|
|
if cache_profile
|
|
handle = GxG::SERVICES[:core][:resources].open((temp_dir + "/" + cache_profile[:title]), ::GxG::DB[:administrator])
|
|
if handle
|
|
# download_path = handle[:resource].path()
|
|
response = [200, {"content-type" => "application/json"}, ({:result => {:file_name => cache_profile[:title], :file_data => handle[:resource].read.encode64}}).to_json()]
|
|
GxG::SERVICES[:core][:resources].close(handle[:token])
|
|
GxG::SERVICES[:core][:resources].destroy(temp_dir, ::GxG::DB[:administrator])
|
|
# response = [-255, {"content-type" => "application/hash"}, {:result => {:file => download_path, :vfs_dir => temp_dir}}]
|
|
else
|
|
raise "Failed to get cache profile."
|
|
end
|
|
else
|
|
raise "Failed to get cache profile."
|
|
end
|
|
else
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Failed to cache file."}).to_json()]
|
|
end
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "You don't have read access."}).to_json()]
|
|
end
|
|
else
|
|
raise "Failed to get profile."
|
|
end
|
|
#
|
|
end
|
|
rescue Exception => the_error
|
|
log_error({:error => the_error})
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => the_error.to_s}).to_json()]
|
|
end
|
|
#
|
|
response
|
|
end
|
|
#
|
|
def vfs_mkfile(details={})
|
|
# Review : find correct cooresponding return codes for errors.
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
if details.is_a?(::Hash)
|
|
the_path = (GxG::SERVICES[:core][:resources].home_path(@credential).to_s + "/" + details[:path].to_s).gsub("//","/")
|
|
if GxG::SERVICES[:core][:resources].exist?(the_path)
|
|
response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Already Exists.", :parameters => details}).to_json()]
|
|
else
|
|
dir_profile = GxG::SERVICES[:core][:resources].profile(::File.dirname(the_path),@credential)
|
|
if dir_profile.is_a?(::Hash)
|
|
if dir_profile[:permissions][:effective][:create] == true
|
|
if details[:format]
|
|
result = GxG::SERVICES[:core][:resources].create(the_path, @credential, {:format => details[:format]})
|
|
else
|
|
result = GxG::SERVICES[:core][:resources].create(the_path, @credential)
|
|
end
|
|
response = [200, {"content-type" => "application/json"}, result.to_json()]
|
|
else
|
|
# err - Hack attempt ?? (user app SHOULD pre-screen!)
|
|
response = [404, {"content-type" => "application/json"}, ({:result => false, :error => "Not Found.", :parameters => false}).to_json()]
|
|
end
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Malformed Profile.", :parameters => details}).to_json()]
|
|
end
|
|
end
|
|
#
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Malformed Parameter.", :parameters => details}).to_json()]
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def vfs_mkdir(details={})
|
|
# Review : find correct cooresponding return codes for errors.
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
if details.is_a?(::Hash)
|
|
the_path = (GxG::SERVICES[:core][:resources].home_path(@credential).to_s + "/" + details[:path].to_s).gsub("//","/")
|
|
if GxG::SERVICES[:core][:resources].exist?(the_path)
|
|
response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Already Exists.", :parameters => details}).to_json()]
|
|
else
|
|
dir_profile = GxG::SERVICES[:core][:resources].profile(::File.dirname(the_path),@credential)
|
|
if dir_profile.is_a?(::Hash)
|
|
if dir_profile[:permissions][:effective][:create] == true
|
|
response = [200, {"content-type" => "application/json"}, GxG::SERVICES[:core][:resources].create_directory(the_path, @credential).to_json()]
|
|
else
|
|
# err - Hack attempt ?? (user app SHOULD pre-screen!)
|
|
response = [404, {"content-type" => "application/json"}, ({:result => false, :error => "Not Found.", :parameters => false}).to_json()]
|
|
end
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Malformed Profile.", :parameters => details}).to_json()]
|
|
end
|
|
end
|
|
#
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Malformed Parameter.", :parameters => details}).to_json()]
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def vfs_rename(details={})
|
|
# Review : find correct cooresponding return codes for errors.
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
if details.is_a?(::Hash)
|
|
error_response = nil
|
|
unless details[:path].to_s.size > 0
|
|
error_response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Invalid Path.", :parameters => details}).to_json()]
|
|
end
|
|
unless details[:new_name].to_s.size > 0
|
|
error_response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "New Name Not Specified.", :parameters => details}).to_json()]
|
|
end
|
|
if error_response
|
|
response = error_response
|
|
else
|
|
prefix = GxG::SERVICES[:core][:resources].home_path(@credential).to_s
|
|
container = (prefix + "/" + File.dirname(details[:path].to_s)).gsub("//","/")
|
|
the_path = (prefix + "/" + details[:path].to_s).gsub("//","/")
|
|
if GxG::SERVICES[:core][:resources].exist?((container + "/" + details[:new_name].to_s).gsub("//","/"))
|
|
response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Already Exists.", :parameters => details}).to_json()]
|
|
else
|
|
the_profile = GxG::SERVICES[:core][:resources].profile(the_path,@credential)
|
|
if the_profile.is_a?(::Hash)
|
|
if the_profile[:permissions][:effective][:rename] == true
|
|
result = GxG::SERVICES[:core][:resources].rename(the_path, @credential, details[:new_name].to_s)
|
|
if result[:result] == true
|
|
response = [200, {"content-type" => "application/json"}, GxG::SERVICES[:core][:resources].rename(the_path, @credential, details[:new_name].to_s).to_json()]
|
|
#
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, result.to_json()]
|
|
end
|
|
else
|
|
# err - Hack attempt ?? (user app SHOULD pre-screen!)
|
|
response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Permission Error.", :parameters => false}).to_json()]
|
|
end
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Malformed Input.", :parameters => details}).to_json()]
|
|
end
|
|
end
|
|
#
|
|
end
|
|
#
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Malformed Parameter.", :parameters => details}).to_json()]
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def vfs_destroy(detials={})
|
|
# Review : find correct cooresponding return codes for errors.
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
if details.is_a?(::Hash)
|
|
the_path = (GxG::SERVICES[:core][:resources].home_path(@credential).to_s + "/" + details[:path].to_s).gsub("//","/")
|
|
if GxG::SERVICES[:core][:resources].exist?(the_path)
|
|
the_profile = GxG::SERVICES[:core][:resources].profile(the_path, @credential)
|
|
if the_profile.is_a?(::Hash)
|
|
if the_profile[:permissions][:effective][:destroy] == true
|
|
result = GxG::SERVICES[:core][:resources].destroy(the_path, @credential)
|
|
if result[:result] == true
|
|
response = [200, {"content-type" => "application/json"}, result.to_json()]
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, result.to_json()]
|
|
end
|
|
else
|
|
# err - Hack attempt ?? (user app SHOULD pre-screen!)
|
|
response = [404, {"content-type" => "application/json"}, ({:result => false, :error => "Not Found.", :parameters => false}).to_json()]
|
|
end
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Malformed Profile.", :parameters => details}).to_json()]
|
|
end
|
|
else
|
|
response = [404, {"content-type" => "application/json"}, ({:result => false, :error => "Not Found.", :parameters => details}).to_json()]
|
|
end
|
|
#
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Malformed Parameter.", :parameters => details}).to_json()]
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def vfs_copy(details={})
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
error_response = nil
|
|
unless details[:source].to_s.size > 0
|
|
error_response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Invalid Source Path.", :parameters => details}).to_json()]
|
|
end
|
|
unless details[:destination].to_s.size > 0
|
|
error_response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Invalid Destination Path.", :parameters => details}).to_json()]
|
|
end
|
|
if error_response
|
|
response = error_response
|
|
else
|
|
source_path = (GxG::SERVICES[:core][:resources].home_path(@credential).to_s + "/" + details[:source].to_s).gsub("//","/")
|
|
destination_path = (GxG::SERVICES[:core][:resources].home_path(@credential).to_s + "/" + details[:destination].to_s).gsub("//","/")
|
|
result = GxG::SERVICES[:core][:resources].copy(source_path, @credential, destination_path)
|
|
if result[:result] == true
|
|
response = [200, {"content-type" => "application/json"}, result.to_json()]
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, result.to_json()]
|
|
end
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def vfs_move(details={})
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
error_response = nil
|
|
unless details[:source].to_s.size > 0
|
|
error_response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Invalid Source Path.", :parameters => details}).to_json()]
|
|
end
|
|
unless details[:destination].to_s.size > 0
|
|
error_response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Invalid Destination Path.", :parameters => details}).to_json()]
|
|
end
|
|
if error_response
|
|
response = error_response
|
|
else
|
|
source_path = (GxG::SERVICES[:core][:resources].home_path(@credential).to_s + "/" + details[:source].to_s).gsub("//","/")
|
|
destination_path = (GxG::SERVICES[:core][:resources].home_path(@credential).to_s + "/" + details[:destination].to_s).gsub("//","/")
|
|
result = GxG::SERVICES[:core][:resources].copy(source_path, @credential, destination_path)
|
|
if result[:result] == true
|
|
response = [200, {"content-type" => "application/json"}, result.to_json()]
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, result.to_json()]
|
|
end
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def set_permissions(details={})
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
# Review : at this point, since home_path is by credential class - open to anyone to alter permissions in their respective areas.
|
|
error_response = nil
|
|
unless details[:revocations].is_a?(::Array)
|
|
error_response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Invalid Source Path.", :parameters => details}).to_json()]
|
|
end
|
|
unless details[:alterations].is_a?(::Array)
|
|
error_response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Invalid Destination Path.", :parameters => details}).to_json()]
|
|
end
|
|
if error_response
|
|
response = error_response
|
|
else
|
|
the_path = (GxG::SERVICES[:core][:resources].home_path(@credential).to_s + "/" + details[:path].to_s).gsub("//","/")
|
|
if GxG::SERVICES[:core][:resources].exist?(the_path)
|
|
(details[:revocations] || []).each do |the_credential|
|
|
# credentials whos permissions are to be revoked.
|
|
GxG::SERVICES[:core][:resources].revoke_permissions(the_path, the_credential.to_s.to_sym)
|
|
end
|
|
(details[:alterations] || []).each do |the_record|
|
|
GxG::SERVICES[:core][:resources].set_permissions(the_path, the_record[:credential], the_record[:permissions])
|
|
end
|
|
response = [200, {"content-type" => "application/json"}, {:result => true}.to_json()]
|
|
else
|
|
response = [404, {"content-type" => "application/json"}, ({:result => false, :error => "Not Found.", :parameters => details}).to_json()]
|
|
end
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def get_format(details={})
|
|
importation_record = {:formats => {}, :records => []}
|
|
if details.is_a?(::Array)
|
|
format_list = []
|
|
details.each do |the_criteria|
|
|
if ::GxG::valid_uuid?(the_criteria)
|
|
::GxG::DB[:roles][:formats].format_list({:uuid => the_criteria.to_s.to_sym}).each do |the_format|
|
|
format_list << the_format
|
|
end
|
|
else
|
|
::GxG::DB[:roles][:formats].format_list({:ufs => the_criteria.to_s}).each do |the_format|
|
|
format_list << the_format
|
|
end
|
|
end
|
|
end
|
|
else
|
|
format_list = ::GxG::DB[:roles][:formats].format_list(details)
|
|
end
|
|
format_list.each do |the_format_header|
|
|
format_record = ::GxG::DB[:roles][:formats].format_load({:uuid => the_format_header[:uuid]})
|
|
format_record[:content] = format_record[:content].gxg_export
|
|
importation_record[:formats][(the_format_header[:uuid])] = format_record
|
|
end
|
|
[200, {"content-type" => "application/json"}, {:result => importation_record}.to_json()]
|
|
end
|
|
#
|
|
def put_format(details={})
|
|
if GxG::DB[:authority].role_member?(GxG::DB[:authority][:system_credentials][:administrators], @credential) || GxG::DB[:authority].role_member?(GxG::DB[:authority][:system_credentials][:developers], @credential)
|
|
result = ::GxG::DB[:roles][:formats].sync_import(GxG::DB[:administrator],details)
|
|
[200, {"content-type" => "application/json"}, {:result => result}.to_json()]
|
|
else
|
|
[403, {"content-type" => "application/json"}, ({:result => false, :error => "You do not have sufficient permissions to do this.", :parameters => details}).to_json()]
|
|
end
|
|
end
|
|
#
|
|
def get_object(details={})
|
|
if details[:path].to_s.size > 0
|
|
if details[:path].to_s.include?("/Public/www")
|
|
[200, {"content-type" => "application/json"}, {:result => (((GxGwww::CACHE.fetch(details[:path].to_s, @credential, true)) || {})[:data] || "")}.to_json()]
|
|
else
|
|
if details[:path].to_s[0..4] == "/User"
|
|
the_path = (GxG::SERVICES[:core][:resources].home_path(@credential).to_s + "/" + details[:path].to_s[5..-1]).gsub("//","/")
|
|
[200, {"content-type" => "application/json"}, {:result => (((GxGwww::CACHE.fetch(the_path, @credential, false)) || {})[:data] || "")}.to_json()]
|
|
else
|
|
if details[:path].to_s[0..6] == "/Shared"
|
|
# Review : Expansion --> work out a scheme for shared group folders/files/db-obj (WebDAV mounts??)
|
|
# [403, {"content-type" => "application/json"}, ({:result => false, :error => "Not Yet Implemented.", :parameters => details}).to_json()]
|
|
the_path = ("/Users/Shared/" + details[:path].to_s[7..-1]).gsub("//","/")
|
|
[200, {"content-type" => "application/json"}, {:result => (((GxGwww::CACHE.fetch(the_path, @credential, false)) || {})[:data] || "")}.to_json()]
|
|
else
|
|
[200, {"content-type" => "application/json"}, {:result => (((GxGwww::CACHE.fetch(details[:path].to_s, @credential, false)) || {})[:data] || "")}.to_json()]
|
|
end
|
|
end
|
|
end
|
|
else
|
|
if GxG::valid_uuid?(details[:uuid].to_s)
|
|
[200, {"content-type" => "application/json"}, {:result => (((GxGwww::CACHE.fetch_by_uuid(details[:uuid].to_s.to_sym, @credential, false)) || {})[:data] || "")}.to_json()]
|
|
else
|
|
[403, {"content-type" => "application/json"}, ({:result => false, :error => "Invalid Specifier.", :parameters => details}).to_json()]
|
|
end
|
|
end
|
|
end
|
|
#
|
|
def put_object(details={})
|
|
response = nil
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
if details[:object].is_a?(::Hash)
|
|
database = nil
|
|
the_object = ::GxG::DB[:roles][:data].retrieve_by_uuid(details[:uuid].to_s.to_sym, ::GxG::DB[:administrator])
|
|
if the_object
|
|
database = the_object.db_address()[:database]
|
|
the_object.deactivate
|
|
if details[:path].to_s.size > 0
|
|
handle = ::GxG::SERVICES[:core][:resources].open(details[:path].to_s, ::GxG::DB[:administrator])
|
|
if handle.is_a?(::Hash)
|
|
database = handle[:resource].db_address()[:database]
|
|
::GxG::SERVICES[:core][:resources].close(handle[:token])
|
|
else
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Error finding object database.", :parameters => false}).to_json()]
|
|
end
|
|
end
|
|
else
|
|
# needs to be created
|
|
if details[:path].to_s.size > 0
|
|
status = ::GxG::SERVICES[:core][:resources].create(details[:path].to_s, @credential, {:with_uuid => details[:uuid].to_s.to_sym})
|
|
unless status[:result] == true
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => status[:error], :parameters => false}).to_json()]
|
|
end
|
|
unless response
|
|
handle = ::GxG::SERVICES[:core][:resources].open(details[:path].to_s, ::GxG::DB[:administrator])
|
|
if handle.is_a?(::Hash)
|
|
database = handle[:resource].db_address()[:database]
|
|
::GxG::SERVICES[:core][:resources].close(handle[:token])
|
|
else
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Error finding object database.", :parameters => false}).to_json()]
|
|
end
|
|
end
|
|
else
|
|
database = ::GxG::DB[:roles][:data]
|
|
end
|
|
end
|
|
if database.is_a?(::GxG::Database::Database)
|
|
status = database.sync_import(@credential, details[:object])
|
|
if status == true
|
|
response = [200, {"content-type" => "application/json"}, {:result => true}.to_json()]
|
|
GxGwww::CACHE.flush_cache_item(details[:uuid].to_s)
|
|
if details[:path].to_s.size > 0
|
|
GxGwww::CACHE.flush_cache_item(details[:path].to_s)
|
|
end
|
|
else
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Error writing data.", :parameters => false}).to_json()]
|
|
end
|
|
else
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Unable to find a suitable database.", :parameters => false}).to_json()]
|
|
end
|
|
else
|
|
if details[:object].is_a?(::String)
|
|
if details[:path].to_s.size > 0
|
|
unless ::GxG::SERVICES[:core][:resources].exist?(details[:path].to_s)
|
|
status = ::GxG::SERVICES[:core][:resources].create(details[:path].to_s, @credential)
|
|
unless status[:result] == true
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => status[:error], :parameters => false}).to_json()]
|
|
end
|
|
end
|
|
unless response
|
|
handle = ::GxG::SERVICES[:core][:resources].open_writable(details[:path].to_s, @credential)
|
|
if handle.is_a?(::Hash)
|
|
handle[:resource].rewind
|
|
handle[:resource].write(details[:object].decode64)
|
|
::GxG::SERVICES[:core][:resources].close(handle[:token])
|
|
response = [200, {"content-type" => "application/json"}, {:result => true}.to_json()]
|
|
else
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Unable to open file.", :parameters => false}).to_json()]
|
|
end
|
|
end
|
|
else
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "You MUST specify a valid path.", :parameters => false}).to_json()]
|
|
end
|
|
else
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Invalid Object Type.", :parameters => false}).to_json()]
|
|
end
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def get_permissions(details={})
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
if details[:path].to_s.size > 0
|
|
the_path = (GxG::SERVICES[:core][:resources].home_path(@credential).to_s + "/" + details[:path].to_s).gsub("//","/")
|
|
result = []
|
|
if GxG::SERVICES[:core][:resources].exist?(the_path)
|
|
result = GxG::SERVICES[:core][:resources].get_permissions(the_path, @credential)
|
|
end
|
|
response = [200, {"content-type" => "application/json"}, {:result => result.to_json.encode64}.to_json()]
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Invalid Path.", :parameters => details}).to_json()]
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def search_database(details={})
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
search_result = {}
|
|
if details[:criteria].is_a?(::Hash)
|
|
details[:criteria].keys.each do |the_role|
|
|
if ::GxG::DB[:roles].keys.include?(the_role)
|
|
# Fix for string/symbol hoo-hah:
|
|
if details[:criteria][(the_role)][:select].is_a?(::Array)
|
|
new_selector = []
|
|
details[:criteria][(the_role)][:select].each do |the_selector|
|
|
new_selector << the_selector.to_s.to_sym
|
|
end
|
|
details[:criteria][(the_role)][:select] = new_selector
|
|
end
|
|
search_result[(the_role)] = ::GxG::DB[:roles][(the_role)].search_database(@credential, details[:criteria][(the_role)])
|
|
end
|
|
end
|
|
response = [200, {"content-type" => "application/json"}, {:result => search_result.to_json.encode64}.to_json()]
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Invalid Criteria.", :parameters => details}).to_json()]
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def search_pull(details={})
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
importation_record = {:formats => {}, :records => []}
|
|
pull_list = []
|
|
if details[:criteria].is_a?(::Hash)
|
|
details[:criteria].keys.each do |the_role|
|
|
if ::GxG::DB[:roles].keys.include?(the_role)
|
|
# Fix for string/symbol hoo-hah:
|
|
if details[:criteria][(the_role)][:select].is_a?(::Array)
|
|
new_selector = []
|
|
details[:criteria][(the_role)][:select].each do |the_selector|
|
|
new_selector << the_selector.to_s.to_sym
|
|
end
|
|
details[:criteria][(the_role)][:select] = new_selector
|
|
end
|
|
(::GxG::DB[:roles][(the_role)].search_database(@credential, details[:criteria][(the_role)]).map {|entry| entry[:uuid]}).each do |the_uuid|
|
|
unless pull_list.include?(the_uuid)
|
|
pull_list << the_uuid
|
|
end
|
|
end
|
|
end
|
|
end
|
|
#
|
|
pull_list.each do |the_uuid|
|
|
the_record = ::GxG::DB[:roles][:data].retrieve_by_uuid(the_uuid, @credential)
|
|
if the_record.is_a?(::GxG::Database::PersistedHash)
|
|
the_record.search do |value, selector, container|
|
|
format_uuid = nil
|
|
if value.is_a?(::GxG::Database::PersistedHash)
|
|
if value.format
|
|
format_uuid = value.format
|
|
end
|
|
end
|
|
if value.is_a?(::GxG::Database::PersistedArray)
|
|
if value.constraint
|
|
format_uuid = value.constraint
|
|
end
|
|
end
|
|
if format_uuid
|
|
unless importation_record[:formats].keys.include?(format_uuid)
|
|
format_record = ::GxG::DB[:roles][:formats].format_load({:uuid => format_uuid})
|
|
if format_record
|
|
format_record[:content] = format_record[:content].gxg_export
|
|
importation_record[:formats][(format_uuid)] = format_record
|
|
end
|
|
end
|
|
end
|
|
end
|
|
importation_record[:records] << the_record.export
|
|
end
|
|
end
|
|
#
|
|
response = [200, {"content-type" => "application/json"}, {:result => importation_record}.to_json()]
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Invalid Criteria.", :parameters => details}).to_json()]
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def entries(details={})
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
if details[:path].to_s.size > 0
|
|
the_path = (GxG::SERVICES[:core][:resources].home_path(@credential).to_s + "/" + details[:path].to_s).gsub("//","/")
|
|
if GxG::SERVICES[:core][:resources].exist?(the_path)
|
|
response = [200, {"content-type" => "application/json"}, {:result => GxG::SERVICES[:core][:resources].entries(the_path, @credential).to_json.encode64}.to_json()]
|
|
else
|
|
response = [404, {"content-type" => "application/json"}, ({:result => false, :error => "Not Found.", :parameters => details}).to_json()]
|
|
end
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, ({:result => false, :error => "Invalid Path.", :parameters => details}).to_json()]
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def destroy_object(details={})
|
|
# details[:uuid] : specifies uuid of db object to destroy.
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
success = false
|
|
GxG::DB[:roles].keys.each do |the_role|
|
|
the_permissions = GxG::DB[:roles][(the_role)].effective_uuid_permission(details[:uuid].to_s.to_sym, @credential)
|
|
if the_permissions.is_a?(::Hash)
|
|
if the_permissions[:destroy] == true
|
|
if GxG::DB[:roles][(the_role)].destroy_by_uuid(@credential, details[:uuid].to_s.to_sym) == true
|
|
unless success == true
|
|
success = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
response = [200, {"content-type" => "application/json"}, {:result => success}.to_json()]
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def get_library(details={})
|
|
# Supply: details => {:library => "lib-name", :manifest => true/false, :dependencies => true/false, :minimum => 0.0, :maximum => 0.0, :loaded => [<UUID>...]}
|
|
# Grab library by name and version params. optionally deliver full stack of in-order load deps.
|
|
minimum = details[:minimum] || 0.0
|
|
maximum = details[:maximum]
|
|
marshalled = []
|
|
if details[:loaded].is_a?(::Array)
|
|
details[:loaded].each do |the_uuid|
|
|
marshalled << the_uuid.to_s.to_sym
|
|
end
|
|
end
|
|
the_lib = nil
|
|
the_list = []
|
|
manifest = GxG::DB[:roles][:software].uuid_list(@credential, {:select => [:uuid, :version], :title => (details[:library]), :order => {:descending => :version}})
|
|
manifest.each do |the_record|
|
|
if maximum
|
|
if ((minimum)..(maximum)).include?(the_record[:version])
|
|
the_lib = the_record
|
|
break
|
|
end
|
|
else
|
|
if the_record[:version] >= minimum
|
|
the_lib = the_record
|
|
break
|
|
end
|
|
end
|
|
end
|
|
if the_lib
|
|
if details[:dependencies] == true
|
|
# calculate dependencies (in proper load order)
|
|
dep_template = {:library => "", :uuid => nil, :version => 0.0, :minimum => 0.0, :maximum => nil, :dependencies => []}
|
|
deps = {}
|
|
the_base_lib = GxG::DB[:roles][:software].retrieve_by_uuid(the_lib[:uuid].to_s.to_sym,@credential)
|
|
build_queue = [(the_base_lib)]
|
|
while build_queue.size > 0 do
|
|
entry = build_queue.shift
|
|
if entry
|
|
unless deps[(entry.uuid)]
|
|
new_dep = dep_template.clone
|
|
new_dep[:library] = entry.title
|
|
new_dep[:uuid] = entry.uuid
|
|
new_dep[:version] = entry.version
|
|
deps[(entry.uuid)] = new_dep
|
|
end
|
|
#
|
|
if entry[:requirements].is_a?(::GxG::Database::PersistedArray)
|
|
entry[:requirements].each do |the_dep|
|
|
# libarary requirement format: {:library => "", :type => "", :minimum => 0.0, :maximum => nil}
|
|
new_dep = nil
|
|
#
|
|
new_list = GxG::DB[:roles][:software].uuid_list(@credential, {:select => [:uuid, :version], :title => (the_dep[:library].to_s), :order => {:descending => :version}})
|
|
new_list.each do |the_item|
|
|
if the_dep[:maximum]
|
|
if ((the_dep[:minimum])..(the_dep[:maximum])).include?(the_item[:version])
|
|
new_dep = dep_template.clone
|
|
new_dep[:library] = the_dep[:library].to_s
|
|
new_dep[:uuid] = the_item[:uuid]
|
|
new_dep[:version] = the_item[:version]
|
|
new_dep[:minimum] = the_dep[:minimum].to_f
|
|
new_dep[:maximum] = the_dep[:maximum].to_f
|
|
break
|
|
end
|
|
else
|
|
if the_item[:version] >= the_dep[:minimum]
|
|
new_dep = dep_template.clone
|
|
new_dep[:library] = the_dep[:library].to_s
|
|
new_dep[:uuid] = the_item[:uuid]
|
|
new_dep[:version] = the_item[:version]
|
|
new_dep[:minimum] = the_dep[:minimum].to_f
|
|
break
|
|
end
|
|
end
|
|
end
|
|
#
|
|
if new_dep
|
|
deps[(entry.uuid)][:dependencies] << new_dep
|
|
build_queue << (GxG::DB[:roles][:software].retrieve_by_uuid(new_dep[:uuid].to_s.to_sym,@credential))
|
|
end
|
|
end
|
|
end
|
|
#
|
|
entry.deactivate
|
|
end
|
|
end
|
|
deps_pool = (deps.sort_by {|key,value| value[:dependencies].size}).to_h
|
|
deps_pool.each_pair do |the_uuid,the_record|
|
|
the_record[:dependencies].each do |the_dep|
|
|
unless marshalled.include?(the_dep[:uuid])
|
|
if details[:manifest] == true
|
|
the_list << {:library => the_record[:library], :uuid => the_dep[:uuid], :version => the_record[:version]}
|
|
else
|
|
data = GxGwww::CACHE.fetch(the_dep[:uuid].to_s,@credential)
|
|
the_list << {:library => the_record[:library], :uuid => the_dep[:uuid], :version => the_record[:version], :data => data[:data]}
|
|
end
|
|
marshalled << the_uuid
|
|
end
|
|
end
|
|
unless marshalled.include?(the_uuid)
|
|
if details[:manifest] == true
|
|
the_list << {:library => the_record[:library], :uuid => the_uuid, :version => the_record[:version]}
|
|
else
|
|
data = GxGwww::CACHE.fetch(the_uuid.to_s,@credential)
|
|
the_list << {:library => the_record[:library], :uuid => the_uuid, :version => the_record[:version], :data => data[:data]}
|
|
end
|
|
marshalled << the_uuid
|
|
end
|
|
end
|
|
else
|
|
# pull and append library object record to content[:data]
|
|
data = GxGwww::CACHE.fetch(the_lib[:uuid].to_s,@credential)
|
|
the_list << {:library => details[:library], :version => the_lib[:version], :data => data}
|
|
end
|
|
end
|
|
#
|
|
[200, {"content-type" => "application/json"}, {:result => the_list.to_json.encode64}.to_json()]
|
|
end
|
|
#
|
|
def application_menu()
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
results = []
|
|
app_menu = (GxGwww::Applications::MENU || [])
|
|
# entry: {:location => "", :application_icon => "", :application_name => "", :credentialed => false, :unique => true :category => ""}
|
|
# ...
|
|
app_menu.each do |entry|
|
|
begin
|
|
profile = ::GxG::VFS.profile(("/Public/www" << entry[:location].to_s), {:with_credential => @credential, :follow_symlinks => true})
|
|
if profile.is_a?(::Hash)
|
|
if profile[:permissions][:effective][:read] == true
|
|
results << entry
|
|
end
|
|
end
|
|
rescue Exception => the_error
|
|
log_warn("Cannot access application: #{"/Public/www" << entry[:location].to_s}")
|
|
end
|
|
end
|
|
response = [200, {"content-type" => "application/json"}, {:result => results.to_json.encode64}.to_json()]
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def application_list()
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
results = []
|
|
@application_states.each do |the_app|
|
|
results << {:application => the_app[:application].to_s, :credentialed => the_app[:credentialed], :unique => the_app[:unique], :location => the_app[:location].to_s}
|
|
end
|
|
response = [200, {"content-type" => "application/json"}, {:result => results.to_json.encode64}.to_json()]
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def application_close(details={})
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
found = nil
|
|
@application_states.each_with_index do |the_app, the_index|
|
|
if the_app[:application] == details[:application]
|
|
found = the_index
|
|
break
|
|
end
|
|
end
|
|
if found
|
|
record = @application_states.delete_at(found)
|
|
response = [200, {"content-type" => "application/json"}, {:result => true}.to_json()]
|
|
else
|
|
response = [200, {"content-type" => "application/json"}, {:result => false}.to_json()]
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def application_open(details={})
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
credentialed = false
|
|
unique = false
|
|
unless details[:path]
|
|
app_menu = (GxGwww::Applications::MENU || [])
|
|
# entry: {:location => "", :application_icon => "", :application_name => "", :credentialed => false, :unique => true :category => ""}
|
|
# ...
|
|
app_menu.each do |the_entry|
|
|
if details[:name] == File.basename(the_entry[:location])
|
|
details[:path] = the_entry[:location]
|
|
break
|
|
end
|
|
end
|
|
end
|
|
begin
|
|
# Review : switch over to new resource accessor??
|
|
# GxG::SERVICES[:core][:resources].open(the_path, @credential)
|
|
# token format : {:token => the_token, :path => the_path, :resource => the_resource}
|
|
# the_object = GxG::VFS.open("/Public/www" << details[:path].to_s)
|
|
the_object_token = GxG::SERVICES[:core][:resources].open(("/Public/www" << details[:path].to_s), @credential)
|
|
if the_object_token
|
|
the_object = the_object_token[:resource]
|
|
else
|
|
the_object = nil
|
|
end
|
|
rescue
|
|
the_object_token = nil
|
|
the_object = nil
|
|
end
|
|
if the_object.is_a?(::GxG::Database::PersistedHash)
|
|
# source_uuid = the_object.uuid
|
|
the_options = the_object[:options]
|
|
if the_options[:credentialed]
|
|
credentialed = the_options[:credentialed]
|
|
end
|
|
if the_options[:unique]
|
|
unique = the_options[:unique]
|
|
end
|
|
app_uuid = GxG::uuid_generate.to_s.to_sym
|
|
the_options = nil
|
|
the_object.deactivate
|
|
already_running = false
|
|
if unique || (details[:restore] == true)
|
|
@application_states.each do |the_app_record|
|
|
if the_app_record[:location] == details[:path].to_s
|
|
already_running = true
|
|
app_uuid = the_app_record[:application]
|
|
break
|
|
end
|
|
end
|
|
end
|
|
#
|
|
if already_running == true
|
|
if details[:restore] == true
|
|
response = [200, {"content-type" => "application/json"}, {:result => {:application => app_uuid.to_s, :location => details[:path].to_s}.to_json().encode64}.to_json()]
|
|
else
|
|
if unique
|
|
response = [403, {"content-type" => "application/json"}, {:result => false, :error => "Already Running"}.to_json()]
|
|
else
|
|
somedata = GxGwww::CACHE.fetch(details[:path].to_s,@credential)
|
|
if somedata
|
|
app_uuid = GxG::uuid_generate.to_s.to_sym
|
|
response = [200, {"content-type" => "application/json"}, {:result => {:application => app_uuid.to_s, :location => details[:path].to_s}.to_json().encode64}.to_json()]
|
|
@application_states << {:application => app_uuid.to_s, :credentialed => credentialed, :unique => unique, :location => details[:path].to_s, :status => "exitready", :data => nil}
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, {:result => false, :error => "Could not locate application in storage #{details.inspect}"}.to_json()]
|
|
end
|
|
end
|
|
end
|
|
else
|
|
somedata = GxGwww::CACHE.fetch(details[:path].to_s,@credential)
|
|
if somedata
|
|
response = [200, {"content-type" => "application/json"}, {:result => {:application => app_uuid.to_s, :location => details[:path].to_s}.to_json().encode64}.to_json()]
|
|
@application_states << {:application => app_uuid.to_s, :credentialed => credentialed, :unique => unique, :location => details[:path].to_s, :status => "exitready", :data => nil}
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, {:result => false, :error => "Could not locate application in storage #{details.inspect}"}.to_json()]
|
|
end
|
|
end
|
|
#
|
|
else
|
|
response = [403, {"content-type" => "application/json"}, {:result => false, :error => "Invalid name or path: #{details.inspect}"}.to_json()]
|
|
end
|
|
#
|
|
if the_object_token
|
|
GxG::SERVICES[:core][:resources].close(the_object_token[:token])
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def app_state_pull(details={})
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
record = nil
|
|
@application_states.each_with_index do |the_app, the_index|
|
|
if the_app[:application] == details[:application]
|
|
record = @application_states[(the_index)]
|
|
break
|
|
end
|
|
end
|
|
if record
|
|
response = [200, {"content-type" => "application/json"}, {:result => record.to_json().encode64}.to_json()]
|
|
else
|
|
response = [200, {"content-type" => "application/json"}, {:result => {}.to_json().encode64}.to_json()]
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def app_state_push(details={})
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
found = nil
|
|
@application_states.each_with_index do |the_app, the_index|
|
|
if the_app[:application] == details[:application]
|
|
found = index
|
|
break
|
|
end
|
|
end
|
|
# decode payload prior
|
|
content = details[:data]
|
|
if found
|
|
if content
|
|
# {:application => app_uuid.to_s, :credentialed => credentialed, :unique => unique, :location => details[:path].to_s, :status => "exitready", :data => nil}
|
|
@application_states[(found)][:data] = content
|
|
@application_states[(found)][:status] = "exitready"
|
|
response = [200, {"content-type" => "application/json"}, {:result => true}.to_json()]
|
|
else
|
|
# error
|
|
response = [500, {"content-type" => "application/json"}, {:result => false, :error => "State Data Missing.", :parameters => details[:data]}.to_json()]
|
|
end
|
|
else
|
|
response = [404, {"content-type" => "application/json"}, {:result => false, :error => "Application Not Found.", :parameters => details[:application]}.to_json()]
|
|
end
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def format_pull(details={})
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
# Uncredentialed applications might pull formats - no credential screening for now.
|
|
records = []
|
|
if details[:criteria].is_a?(::Hash)
|
|
criterias = [(details[:criteria])]
|
|
else
|
|
criterias = details[:criteria]
|
|
end
|
|
if criterias.is_a?(::Array)
|
|
criterias.each do |the_criteria|
|
|
GxG::DB[:roles][:formats].format_list(the_criteria).each do |the_format_stub|
|
|
if the_format_stub[:ufs].to_s.size > 0
|
|
records << (GxG::DB[:roles][:formats].format_load({:ufs => the_format_stub[:ufs]}))
|
|
else
|
|
if the_format_stub[:uuid].to_s.size > 0
|
|
records << (GxG::DB[:roles][:formats].format_load({:uuid => the_format_stub[:uuid].to_s.to_sym}))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
response = [200, {"content-type" => "application/json"}, {:result => records.to_json.encode64}.to_json()]
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def format_push(details={})
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
begin
|
|
unless GxG::DB[:authority].role_member?(GxG::DB[:authority][:system_credentials][:administrators], @credential) || GxG::DB[:authority].role_member?(GxG::DB[:authority][:system_credentials][:developers], @credential)
|
|
raise Exception, "You do not have permissions sufficient to write this format."
|
|
end
|
|
# Check inputs
|
|
unless ::GxG::valid_uuid?(details[:uuid].to_s.to_sym)
|
|
raise Exception, "Invalid UUID passed for the format"
|
|
end
|
|
unless details[:type].is_any?(::String, ::Symbol)
|
|
raise Exception, "You must pass the format_record[:type] as a String or Symbol"
|
|
end
|
|
unless details[:ufs].is_any?(::String, ::Symbol)
|
|
raise Exception, "You must pass the format_record[:ufs] as a String or Symbol"
|
|
end
|
|
unless details[:title].is_a?(::String)
|
|
raise Exception, "You must pass the format_record[:title] as a String"
|
|
end
|
|
unless details[:version].is_a?(::Float)
|
|
raise Exception, "You must pass the format_record[:version] as a Float"
|
|
end
|
|
unless details[:mime_types].is_any?(::String, ::Array)
|
|
raise Exception, "You must pass the format_record[:mime_types] as a String"
|
|
end
|
|
unless details[:content].is_a?(::Hash)
|
|
raise Exception, "You must pass the format_record[:content] as a Hash"
|
|
end
|
|
unless GxG::DB[:roles][:formats].persistable?(details[:content])
|
|
raise Exception, "You must pass the format_record[:content] as a Hash of persistable elements"
|
|
end
|
|
# prepare format record
|
|
format_record = GxG::DB[:roles][:formats].format_template(details[:type].to_s.to_sym)
|
|
unless format_record
|
|
raise ArgumentError, "Invalid format structural type"
|
|
end
|
|
format_record[:uuid] = details[:uuid].to_s.to_sym
|
|
format_record[:type] = details[:type].to_s.to_sym
|
|
format_record[:ufs] = details[:ufs].to_s
|
|
format_record[:title] = details[:title].to_s
|
|
format_record[:version] = details[:version].to_f
|
|
format_record[:mime_types] = details[:mime_types]
|
|
format_record[:content] = details[:content]
|
|
# If format exists, update, else create
|
|
if GxG::DB[:roles][:formats].format_list({:uuid => details[:uuid].to_s.to_sym}).size > 0
|
|
unless GxG::DB[:roles][:formats].format_update(format_record)
|
|
raise Exception, "Unkown Format Update Error"
|
|
end
|
|
else
|
|
unless GxG::DB[:roles][:formats].format_create(format_record)
|
|
raise Exception, "Unkown Format Creation Error"
|
|
end
|
|
end
|
|
response = [200, {"content-type" => "application/json"}, {:result => true}.to_json()]
|
|
rescue Exception => the_error
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => the_error.to_s, :parameters => details}).to_json()]
|
|
end
|
|
#
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def format_template(details={})
|
|
begin
|
|
format_record = GxG::DB[:roles][:formats].format_template(details[:type].to_s.to_sym)
|
|
unless format_record
|
|
raise ArgumentError, "Invalid format structural type"
|
|
end
|
|
response = [200, {"content-type" => "application/json"}, {:result => format_record.to_json.encode64}.to_json()]
|
|
rescue Exception => the_error
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => the_error.to_s, :parameters => details}).to_json()]
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def format_list(details={})
|
|
if self.closed?
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => "Connector Closed.", :parameters => false}).to_json()]
|
|
else
|
|
response = [200, {"content-type" => "application/json"}, {:result => GxG::DB[:roles][:formats].format_list(details).to_json.encode64}.to_json()]
|
|
end
|
|
response
|
|
end
|
|
#
|
|
def format_destroy(details={})
|
|
begin
|
|
unless GxG::DB[:authority].role_member?(GxG::DB[:authority][:system_credentials][:administrators], @credential) || GxG::DB[:authority].role_member?(GxG::DB[:authority][:system_credentials][:developers], @credential)
|
|
raise Exception, "You do not have permissions sufficient to destroy this format."
|
|
end
|
|
criteria={}
|
|
if GxG::valid_uuid?(details[:uuid])
|
|
criteria[:uuid] = details[:uuid].to_s.to_sym
|
|
else
|
|
if details[:ufs].is_a?(::String)
|
|
criteria[:ufs] = details[:ufs].to_s
|
|
end
|
|
end
|
|
unless criteria.keys.size > 0
|
|
raise ArgumentError, "You must specify which format to destroy with either :uuid or :ufs specifier."
|
|
end
|
|
response = [200, {"content-type" => "application/json"}, {:result => GxG::DB[:roles][:formats].format_destroy(criteria)}.to_json()]
|
|
rescue Exception => the_error
|
|
response = [500, {"content-type" => "application/json"}, ({:result => false, :error => the_error.to_s, :parameters => details}).to_json()]
|
|
end
|
|
response
|
|
end
|
|
# ---------------------------------------------
|
|
end
|
|
#
|
|
end
|
|
#
|
|
module GxGwww
|
|
# ---------------------------------------------------------------------
|
|
CACHE = ::GxGwww::Storage::UnifiedMemoryCache.new
|
|
# ---------------------------------------------------------------------
|
|
end
|
|
#
|