diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/evendoors.rb | 37 | ||||
-rw-r--r-- | lib/evendoors/door.rb | 54 | ||||
-rw-r--r-- | lib/evendoors/link.rb | 31 | ||||
-rw-r--r-- | lib/evendoors/particle.rb | 138 | ||||
-rw-r--r-- | lib/evendoors/room.rb | 123 | ||||
-rw-r--r-- | lib/evendoors/space.rb | 24 | ||||
-rw-r--r-- | lib/evendoors/spot.rb | 28 | ||||
-rw-r--r-- | lib/evendoors/twirl.rb | 59 |
8 files changed, 494 insertions, 0 deletions
diff --git a/lib/evendoors.rb b/lib/evendoors.rb new file mode 100644 index 0000000..16504b6 --- /dev/null +++ b/lib/evendoors.rb @@ -0,0 +1,37 @@ +#! /usr/bin/env ruby +# -*- coding: UTF-8 -*- +# +module EvenDoors + # + PATH_SEP = '/'.freeze + LINK_SEP = ','.freeze + ACT_SEP = '?'.freeze + ACT_GET = 'get'.freeze + ACT_ADD_LINK = 'add_link'.freeze + ACT_ERROR = 'error'.freeze + # + LNK_SRC = 'edoors_lnk_src'.freeze + LNK_DSTS = 'edoors_lnk_dsts'.freeze + LNK_FIELDS = 'edoors_lnk_fields'.freeze + LNK_CONDF = 'edoors_lnk_condf'.freeze + LNK_CONDV = 'edoors_lnk_condv'.freeze + # + ERROR_FIELD = 'edoors_error'.freeze + ERROR_ROUTE_RRWD = 'routing error: right room, wrong door'.freeze + ERROR_ROUTE_TRWR = 'routing error: top room, wrong room'.freeze + ERROR_ROUTE_NDNL = 'routing error: no destination, no link'.freeze + ERROR_ROUTE_SND = 'routing error: system no destination'.freeze + # + class Exception < ::Exception; end + # +end +# +require 'evendoors/particle' +require 'evendoors/spot' +require 'evendoors/twirl' +require 'evendoors/room' +require 'evendoors/space' +require 'evendoors/door' +require 'evendoors/link' +# +# EOF diff --git a/lib/evendoors/door.rb b/lib/evendoors/door.rb new file mode 100644 index 0000000..9807d46 --- /dev/null +++ b/lib/evendoors/door.rb @@ -0,0 +1,54 @@ +#! /usr/bin/env ruby +# -*- coding: UTF-8 -*- + +# +module EvenDoors + # + class Door < Spot + # + def initialize n, p=nil + super n, p + @saved = nil + @parent.add_spot self if @parent + end + # + def require_p p_kls + p = EvenDoors::Twirl.require_p p_kls + p.src = self + p + end + # + def release_p p + @saved=nil if @saved==p # particle is released, all is good + EvenDoors::Twirl.release_p p + end + # + def process p + @viewer.receive p if @viewer + @saved = p + receive p + if not @saved.nil? + puts "application didn't give that particle back #{p}" if EvenDoors::Twirl.debug + puts "\t#{p.data EvenDoors::ERROR_FIELD}" if p.action==EvenDoors::ACT_ERROR + release_p @saved + @saved = nil + end + end + # + def send_p p + p.src = self + @saved=nil if @saved==p # particle is sent back the data, all is good + @parent.send_p p # daddy will know what to do + end + # + def send_sys_p p + p.src = self + @saved=nil if @saved==p # particle is sent back the data, all is good + @parent.send_sys_p p # daddy will know what to do + end + # + end + # +end +# +# EOF diff --git a/lib/evendoors/link.rb b/lib/evendoors/link.rb new file mode 100644 index 0000000..b2a9bba --- /dev/null +++ b/lib/evendoors/link.rb @@ -0,0 +1,31 @@ +#! /usr/bin/env ruby +# -*- coding: UTF-8 -*- + +# +module EvenDoors + # + class Link + # + def initialize src, dsts, fields, cond_fields, cond_value + @src = src # link source name + @dsts = dsts # , separated destinations to apply to the particle on linking success + @fields = fields # , separated fields to apply to the particle on linking success + @cond_fields = cond_fields # , separated fields used to generate the link value with particle payload + @cond_value = cond_value # value which will be compared to the particle link value to link or not + @door = nil # pointer to the source + end + # + def self.from_particle_data p + EvenDoors::Link.new(p.get_data(EvenDoors::LNK_SRC), p.get_data(EvenDoors::LNK_DSTS), + p.get_data(EvenDoors::LNK_FIELDS), p.get_data(EvenDoors::LNK_CONDF), + p.get_data(EvenDoors::LNK_CONDV)) + end + # + attr_accessor :door + attr_reader :src, :dsts, :fields, :cond_fields, :cond_value + # + end + # +end +# +# EOF diff --git a/lib/evendoors/particle.rb b/lib/evendoors/particle.rb new file mode 100644 index 0000000..7b951f9 --- /dev/null +++ b/lib/evendoors/particle.rb @@ -0,0 +1,138 @@ +#! /usr/bin/env ruby +# -*- coding: UTF-8 -*- + +# +module EvenDoors + # + class Particle + # + def initialize + reset! + end + # + def reset! + @ts = Time.now # creation time + @src = nil # Spot.path where it's originated from + @room = nil + @door = nil # Door where it's currently heading to + @action = nil # action to perform on the Door + @dsts = [] # fifo of Spot.path where to travel to + @link_fields = [] # the fields used to generate the link value + @link_value = nil # the value computed with the link_fields values extracted from the payload + # used for pearing in Door and linking in routing process + @payload = {} # the actual data carried by this particle + @merged = [] # list of merged particles + end + # + attr_accessor :src + attr_reader :ts, :room, :door, :action, :link_value + # + # routing + # + def dst + @dsts[0] + end + # + def split_dst! + p, @action = @dsts[0].split EvenDoors::ACT_SEP + i = p.rindex EvenDoors::PATH_SEP + if i.nil? + @room = nil + door_name = p + else + @room = p[0..i-1] + door_name = p[i+1..-1] + end + door_name + end + # + def dst_done! door + @dsts.shift + @door = door + end + # + def error! e + @action = EvenDoors::ACT_ERROR + @door = @src + @payload[EvenDoors::ERROR_FIELD]=e + end + # + def clear_dsts! + @dsts.clear + end + # + def add_dsts paths + paths.split(EvenDoors::LINK_SEP).each do |path| + @dsts << path + end + end + # + def set_dst a, l=nil + @room = nil + @door = nil + @action = nil + clear_dsts! + @dsts << ( l ? l.to_str : '' )+EvenDoors::ACT_SEP+a.to_str + end + # + # data manipulation + # + def set_data k, v + @payload[k] = v + compute_link_value! if @link_fields.include? k + end + # + def get_data k + @payload[k] + end + alias :data :get_data + # + def data k + @payload[k] + end + # + def clone_data p + @payload = p.payload.clone + end + # + # link value and fields + # + def clear_link_fields! + @link_fields.clear + compute_link_value! + end + # + def set_link_fields *args + @link_fields.clear if not @link_fields.empty? + args.compact! + args.each do |lfs| + lfs.split(',').each do |lf| + @link_fields << lf + end + end + compute_link_value! + end + # + def compute_link_value! + @link_value = @link_fields.inject('') { |s,lf| s+=@payload[lf].to_s if @payload[lf]; s } + end + # + # merge particles management + # + def merged_count + @merged.length + end + # + def merge p + @merged << p + end + # + def merged i + @merged[i] + end + # + end + # +end +# +# EOF diff --git a/lib/evendoors/room.rb b/lib/evendoors/room.rb new file mode 100644 index 0000000..671b529 --- /dev/null +++ b/lib/evendoors/room.rb @@ -0,0 +1,123 @@ +#! /usr/bin/env ruby +# -*- coding: UTF-8 -*- + +# +module EvenDoors + # + class Room < Spot + # + def initialize n, p=nil + super n, p + @spots = {} + @links = {} + @cache = {} + @parent.add_spot self if @parent + end + # + def add_spot s + raise EvenDoors::Exception.new "Spot #{s.name} already has #{s.parent.name} as parent" if not s.parent.nil? and s.parent!=self + raise EvenDoors::Exception.new "Spot #{s.name} already exists in #{path}" if @spots.has_key? s.name + s.parent = self if s.parent.nil? + @spots[s.name]=s + end + # + def add_link l + l.door = @spots[l.src] + raise EvenDoors::Exception.new "Link source #{l.src} does not exist in #{path}" if l.door.nil? + (@links[l.src] ||= [])<< l + end + # + def start! + puts " * start #{path}" if EvenDoors::Twirl.debug + @spots.values.each do |spot| spot.start! if spot.respond_to? :start! end + end + # + def stop! + puts " * stop #{path}" if EvenDoors::Twirl.debug + @spots.values.each do |spot| spot.stop! if spot.respond_to? :stop! end + end + # + def try_links p + pending_link = nil + apply_link = false + links = @links[p.src.name] + return false if links.nil? + links.each do |link| + apply_link = link.cond_fields.nil? # unconditional link + p.set_link_fields link.cond_fields if not apply_link + if apply_link or (p.link_value==link.cond_value) + # link matches ! + if not pending_link.nil? + p2 = require_p p.class + p2.clone_data p + p2.src = link.door + p2.clear_dsts! + p2.add_dsts link.dsts + p2.set_link_fields link.fields + send_p p2 + end + pending_link = link + end + end + if pending_link + p.src = pending_link.door + p.clear_dsts! + p.add_dsts pending_link.dsts + p.set_link_fields pending_link.fields + send_p p + end + (not pending_link.nil?) + end + # + def route_p p, door_name + if p.room.nil? or p.room==path + if door = @spots[door_name] + p.dst_done! door + else + p.error! EvenDoors::ERROR_ROUTE_RRWD + end + elsif @parent + @parent.route_p p, door_name + else + p.error! EvenDoors::ERROR_ROUTE_TRWR + end + end + # + def send_p p + if d = p.dst + puts " * send #{d.to_str} ..." if EvenDoors::Twirl.debug + route_p p, p.split_dst! + puts " -> #{p.door.path}:#{p.action}" if EvenDoors::Twirl.debug + EvenDoors::Twirl.send_p p + elsif not try_links p + p.error! EvenDoors::ERROR_ROUTE_NDNL + puts " -> #{p.door.path}:#{p.action}" if EvenDoors::Twirl.debug + EvenDoors::Twirl.send_p p + end + end + # + def send_sys_p p + if d = p.dst + puts " * send_sys #{d.to_str} ..." if EvenDoors::Twirl.debug + route_p p, p.split_dst! + puts " -> #{p.door.path}:#{p.action}" if EvenDoors::Twirl.debug + EvenDoors::Twirl.send_sys_p p + else + p.error! EvenDoors::ERROR_ROUTE_SND + puts " -> #{p.door.path}:#{p.action}" if EvenDoors::Twirl.debug + EvenDoors::Twirl.send_sys_p p + end + end + # + def process_sys p + if p.action==ACT_ADD_LINK + add_link EvenDoors::Link.from_particle_data p + end + EvenDoors::Twirl.release_p p + end + # + end + # +end +# +# EOF diff --git a/lib/evendoors/space.rb b/lib/evendoors/space.rb new file mode 100644 index 0000000..6579003 --- /dev/null +++ b/lib/evendoors/space.rb @@ -0,0 +1,24 @@ +#! /usr/bin/env ruby +# -*- coding: UTF-8 -*- + +# +module EvenDoors + # + class Space < Room + # + def initialize n, args={} + super n, nil + EvenDoors::Twirl.debug = args[:debug] || false + end + # + def twirl! + @spots.values.each do |spot| spot.start! end + EvenDoors::Twirl.twirl! + @spots.values.each do |spot| spot.stop! end + end + # + end + # +end +# +# EOF diff --git a/lib/evendoors/spot.rb b/lib/evendoors/spot.rb new file mode 100644 index 0000000..e88bac7 --- /dev/null +++ b/lib/evendoors/spot.rb @@ -0,0 +1,28 @@ +#! /usr/bin/env ruby +# -*- coding: UTF-8 -*- + +# +module EvenDoors + # + class Spot + # + def initialize n, p + @name = n # unique in it's room + @parent = p # single direct parent + @viewer = nil # particle going through that position will be sent there readonly + end + # + attr_reader :name + attr_accessor :viewer, :parent + # + def path + return @path if @path + p = ( @parent ? @parent.path+'/' : '') + name + @path = p.sub(/^\/+/,'').gsub(/\/{2,}/,'/').sub(/\/+$/,'') + end + # + end + # +end +# +# EOF diff --git a/lib/evendoors/twirl.rb b/lib/evendoors/twirl.rb new file mode 100644 index 0000000..30ef169 --- /dev/null +++ b/lib/evendoors/twirl.rb @@ -0,0 +1,59 @@ +#! /usr/bin/env ruby +# -*- coding: UTF-8 -*- + +# +module EvenDoors + # + class Twirl + # + @debug = false + @pool = {} # per particle class free list + @sys_fifo = [] # system particles fifo list + @app_fifo = [] # application particles fifo list + # + # + class << self + # + attr_accessor :debug + # + def release_p p + ( @pool[p.class] ||= [] ) << p + end + # + def require_p p_kls + l = @pool[p_kls] + return p_kls.new if l.nil? + p = l.pop + return p_kls.new if p.nil? + p.reset! + p + end + # + def send_p p + @app_fifo << p + end + # + def send_sys_p p + @sys_fifo << p + end + # + def twirl! + while @sys_fifo.length>0 or @app_fifo.length>0 + while @sys_fifo.length>0 + p = @sys_fifo.shift + p.door.process_sys p + end + while @app_fifo.length>0 + p = @app_fifo.shift + p.door.process p + end + end + end + # + end + # + end + # +end +# +# EOF |