iotas 0.0.4 → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,226 +0,0 @@
1
- #! /usr/bin/env ruby
2
- # -*- coding: UTF-8 -*-
3
- #
4
- # Copyright 2012 Jérémy Zurcher <jeremy@asynk.ch>
5
- #
6
- # This file is part of iotas.
7
- #
8
- # iotas is free software: you can redistribute it and/or modify
9
- # it under the terms of the GNU Affero General Public License as published by
10
- # the Free Software Foundation, either version 3 of the License, or
11
- # (at your option) any later version.
12
- #
13
- # iotas is distributed in the hope that it will be useful,
14
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- # GNU Affero General Public License for more details.
17
- #
18
- # You should have received a copy of the GNU Affero General Public License
19
- # along with iotas. If not, see <http://www.gnu.org/licenses/>.
20
-
21
- require 'time'
22
- #
23
- module Iotas
24
- #
25
- class Particle
26
- #
27
- def initialize o={}
28
- @ts = Time.now # creation time
29
- @src = nil # Iota where it's originated from
30
- @dst = nil # Iota where it's heading to
31
- @room = nil # Room path part of the current destination
32
- @door = nil # Door path part of the current destination
33
- @action = nil # action part of the current destination
34
- @link_value = nil # the value computed with the link_fields values extracted from the payload
35
- # used for pearing Particles in Boards and linking in routing process
36
- @dsts = [] # fifo of path?action strings where to travel to
37
- @link_fields = [] # the fields used to generate the link value
38
- @payload = {} # the actual data carried by this particle
39
- @merged = [] # list of merged particles
40
- #
41
- if not o.empty?
42
- @ts = Time.parse(o['ts']) if o['ts']
43
- @room = o['room']
44
- @door = o['door']
45
- @action = o['action']
46
- @payload = o['payload']||{}
47
- @src = o['spin'].search_down o['src'] if o['src']
48
- @dst = o['spin'].search_down o['dst'] if o['dst']
49
- o['dsts'].each do |dst| add_dsts dst end if o['dsts']
50
- set_link_fields *o['link_fields'] if o['link_fields']
51
- o['merged'].each do |particle|
52
- merge! Particle.json_create(particle.merge!('spin'=>o['spin']))
53
- end if o['merged']
54
- end
55
- end
56
- #
57
- def to_json *a
58
- {
59
- 'kls' => self.class.name,
60
- 'ts' => @ts,
61
- 'src' => (@src ? @src.path : nil ),
62
- 'dst' => (@dst ? @dst.path : nil ),
63
- 'room' => @room,
64
- 'door' => @door,
65
- 'action' => @action,
66
- 'dsts' => @dsts,
67
- 'link_fields' => @link_fields,
68
- 'payload' => @payload,
69
- 'merged' => @merged
70
- }.to_json *a
71
- end
72
- #
73
- def self.json_create o
74
- raise Iotas::Exception.new "JSON #{o['kls']} != #{self.name}" if o['kls'] != self.name
75
- self.new o
76
- end
77
- #
78
- def reset!
79
- @ts = @src = @dst = @room = @door = @action = @link_value = nil
80
- @dsts.clear
81
- @link_fields.clear
82
- @payload.clear
83
- @merged.clear
84
- end
85
- #
86
- def init! src
87
- @src = src
88
- @ts = Time.now
89
- end
90
- #
91
- attr_reader :ts, :src, :dst, :room, :door, :action, :link_value, :payload
92
- #
93
- # routing
94
- #
95
- def next_dst
96
- @dsts[0]
97
- end
98
- #
99
- def clear_dsts!
100
- @dsts.clear
101
- end
102
- #
103
- def add_dsts dsts
104
- dsts.split(Iotas::LINK_SEP).each do |dst|
105
- if dst.empty? or dst[0]==Iotas::PATH_SEP or dst[0]==Iotas::PATH_SEP or dst=~/\/\?/\
106
- or dst=~/\/{2,}/ or dst=~/\s+/ or dst==Iotas::ACT_SEP
107
- raise Iotas::Exception.new "destination #{dst} is not acceptable"
108
- end
109
- @dsts << dst
110
- end
111
- end
112
- #
113
- def add_dst a, d=''
114
- add_dsts d+Iotas::ACT_SEP+a
115
- end
116
- #
117
- def set_dst! a, d
118
- @room = @door = nil
119
- @action = a
120
- @dst = d
121
- end
122
- #
123
- def split_dst!
124
- @dst = @room = @door = @action = nil
125
- return if (n = next_dst).nil?
126
- p, @action = n.split Iotas::ACT_SEP
127
- i = p.rindex Iotas::PATH_SEP
128
- if i.nil?
129
- @room = nil
130
- @door = p
131
- else
132
- @room = p[0..i-1]
133
- @door = p[i+1..-1]
134
- end
135
- @door = nil if @door.empty?
136
- end
137
- #
138
- def dst_routed! dst
139
- @dst = dst
140
- @dsts.shift
141
- end
142
- #
143
- def dst_reached!
144
- d = @dst
145
- @dst = nil
146
- d
147
- end
148
- #
149
- def error! e, dst=nil
150
- @action = Iotas::ACT_ERROR
151
- @dst = dst||@src
152
- @payload[Iotas::FIELD_ERROR_MSG]=e
153
- end
154
- #
155
- def apply_link! lnk
156
- @src = lnk.door
157
- clear_dsts!
158
- add_dsts lnk.dsts
159
- set_link_fields lnk.fields
160
- end
161
- #
162
- # data manipulation
163
- #
164
- def []= k, v
165
- @payload[k]=v
166
- compute_link_value! if @link_fields.include? k
167
- end
168
- #
169
- def set_data k, v
170
- @payload[k] = v
171
- compute_link_value! if @link_fields.include? k
172
- end
173
- #
174
- def [] k
175
- @payload[k]
176
- end
177
- #
178
- def get_data k
179
- @payload[k]
180
- end
181
- alias :data :get_data
182
- #
183
- def clone_data p
184
- @payload = p.payload.clone
185
- end
186
- #
187
- # link value and fields
188
- #
189
- def set_link_fields *args
190
- @link_fields.clear if not @link_fields.empty?
191
- args.compact!
192
- args.each do |lfs|
193
- lfs.split(',').each do |lf|
194
- @link_fields << lf
195
- end
196
- end
197
- compute_link_value!
198
- end
199
- #
200
- def compute_link_value!
201
- @link_value = @link_fields.inject('') { |s,lf| s+=@payload[lf].to_s if @payload[lf]; s }
202
- end
203
- #
204
- # merge particles management
205
- #
206
- def merge! p
207
- @merged << p
208
- end
209
- #
210
- def merged i
211
- @merged[i]
212
- end
213
- #
214
- def merged_shift
215
- @merged.shift
216
- end
217
- #
218
- def clear_merged!
219
- @merged.clear
220
- end
221
- #
222
- end
223
- #
224
- end
225
- #
226
- # EOF
data/lib/iotas/room.rb DELETED
@@ -1,192 +0,0 @@
1
- #! /usr/bin/env ruby
2
- # -*- coding: UTF-8 -*-
3
- #
4
- # Copyright 2012 Jérémy Zurcher <jeremy@asynk.ch>
5
- #
6
- # This file is part of iotas.
7
- #
8
- # iotas is free software: you can redistribute it and/or modify
9
- # it under the terms of the GNU Affero General Public License as published by
10
- # the Free Software Foundation, either version 3 of the License, or
11
- # (at your option) any later version.
12
- #
13
- # iotas is distributed in the hope that it will be useful,
14
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- # GNU Affero General Public License for more details.
17
- #
18
- # You should have received a copy of the GNU Affero General Public License
19
- # along with iotas. If not, see <http://www.gnu.org/licenses/>.
20
-
21
- #
22
- module Iotas
23
- #
24
- ERROR_ROUTE_NS = 'routing error: no source'.freeze
25
- ERROR_ROUTE_RRWD = 'routing error: right room, wrong door'.freeze
26
- ERROR_ROUTE_DNE = 'routing error: does not exists'.freeze
27
- ERROR_ROUTE_NDNL = 'routing error: no destination, no link'.freeze
28
- ERROR_ROUTE_SND = 'routing error: system no destination'.freeze
29
- #
30
- class Room < Iota
31
- #
32
- def initialize n, p
33
- super n, p
34
- @iotas = {}
35
- @links = {}
36
- end
37
- #
38
- def to_json *a
39
- {
40
- 'kls' => self.class.name,
41
- 'name' => @name,
42
- 'iotas' => @iotas,
43
- 'links' => @links
44
- }.to_json *a
45
- end
46
- #
47
- def self.json_create o
48
- raise Iotas::Exception.new "JSON #{o['kls']} != #{self.name}" if o['kls'] != self.name
49
- room = self.new o['name'], o['parent']
50
- o['iotas'].each do |name,iota|
51
- eval( iota['kls'] ).json_create(iota.merge!('parent'=>room))
52
- end
53
- o['links'].each do |src,links|
54
- links.each do |link|
55
- room.add_link Iotas::Link.json_create(link)
56
- end
57
- end
58
- room
59
- end
60
- #
61
- def add_iota s
62
- raise Iotas::Exception.new "Iota #{s.name} already has #{s.parent.name} as parent" if not s.parent.nil? and s.parent!=self
63
- raise Iotas::Exception.new "Iota #{s.name} already exists in #{path}" if @iotas.has_key? s.name
64
- s.parent = self if s.parent.nil?
65
- @iotas[s.name]=s
66
- end
67
- #
68
- def add_link l
69
- l.door = @iotas[l.src]
70
- raise Iotas::Exception.new "Link source #{l.src} does not exist in #{path}" if l.door.nil?
71
- (@links[l.src] ||= [])<< l
72
- end
73
- #
74
- def start!
75
- puts " * start #{path}" if @spin.debug_routing
76
- @iotas.values.each do |iota| iota.start! end
77
- end
78
- #
79
- def stop!
80
- puts " * stop #{path}" if @spin.debug_routing
81
- @iotas.values.each do |iota| iota.stop! end
82
- end
83
- #
84
- def search_down spath
85
- return self if spath==path
86
- return nil if (spath=~/^#{path}\/(\w+)\/?/)!=0
87
- if iota = @iotas[$1]
88
- return iota if iota.path==spath # needed as Door doesn't implement #search_down
89
- return iota.search_down spath
90
- end
91
- nil
92
- end
93
- #
94
- def try_links p
95
- puts " -> try_links ..." if @spin.debug_routing
96
- links = @links[p.src.name]
97
- return false if links.nil?
98
- pending_link = nil
99
- apply_link = false
100
- links.each do |link|
101
- apply_link = link.cond_fields.nil? # unconditional link
102
- p.set_link_fields link.cond_fields if not apply_link
103
- if apply_link or (p.link_value==link.cond_value)
104
- # link matches !
105
- if pending_link
106
- p2 = @spin.require_p p.class
107
- p2.clone_data p
108
- p2.apply_link! link
109
- send_p p2
110
- end
111
- pending_link = link
112
- end
113
- end
114
- if pending_link
115
- p.apply_link! pending_link
116
- send_p p
117
- end
118
- (not pending_link.nil?)
119
- end
120
- #
121
- def route_p p
122
- if p.room.nil? or p.room==path
123
- if door = @iotas[p.door]
124
- p.dst_routed! door
125
- else
126
- p.error! Iotas::ERROR_ROUTE_RRWD
127
- end
128
- elsif door = @spin.search_world(p.room+Iotas::PATH_SEP+p.door)
129
- p.dst_routed! door
130
- else
131
- p.error! Iotas::ERROR_ROUTE_DNE
132
- end
133
- end
134
- #
135
- def send_p p
136
- puts " * send_p #{(p.next_dst.nil? ? 'no dst' : p.next_dst)} ..." if @spin.debug_routing
137
- if p.dst
138
- puts " -> #{p.dst.path}#{Iotas::ACT_SEP}#{p.action}" if @spin.debug_routing
139
- return @spin.post_p p
140
- end
141
- if p.src.nil?
142
- # do not route orphan particles !!
143
- p.error! Iotas::ERROR_ROUTE_NS, @spin
144
- elsif p.next_dst
145
- p.split_dst!
146
- if p.door
147
- route_p p
148
- else
149
- # boomerang
150
- p.dst_routed! p.src
151
- end
152
- elsif try_links p
153
- return
154
- else
155
- p.error! Iotas::ERROR_ROUTE_NDNL
156
- end
157
- puts " -> #{p.dst.path}#{Iotas::ACT_SEP}#{p.action}" if @spin.debug_routing
158
- @spin.post_p p
159
- end
160
- #
161
- def send_sys_p p
162
- puts " * send_sys_p #{(p.next_dst.nil? ? 'no dst' : p.next_dst)} ..." if @spin.debug_routing
163
- if p.dst
164
- puts " -> #{p.dst.path}#{Iotas::ACT_SEP}#{p.action}" if @spin.debug_routing
165
- return @spin.post_sys_p p
166
- end
167
- if p.next_dst
168
- p.split_dst!
169
- if p.door
170
- route_p p
171
- elsif p.action
172
- p.dst_routed! @spin
173
- end
174
- else
175
- p.error! Iotas::ERROR_ROUTE_SND
176
- end
177
- puts " -> #{p.dst.path}#{Iotas::ACT_SEP}#{p.action}" if @spin.debug_routing
178
- @spin.post_sys_p p
179
- end
180
- #
181
- def process_sys_p p
182
- if p.action==Iotas::SYS_ACT_ADD_LINK
183
- add_link Iotas::Link.from_particle_data p
184
- end
185
- @spin.release_p p
186
- end
187
- #
188
- end
189
- #
190
- end
191
- #
192
- # EOF
data/lib/iotas/spin.rb DELETED
@@ -1,159 +0,0 @@
1
- #! /usr/bin/env ruby
2
- # -*- coding: UTF-8 -*-
3
- #
4
- # Copyright 2012 Jérémy Zurcher <jeremy@asynk.ch>
5
- #
6
- # This file is part of iotas.
7
- #
8
- # iotas is free software: you can redistribute it and/or modify
9
- # it under the terms of the GNU Affero General Public License as published by
10
- # the Free Software Foundation, either version 3 of the License, or
11
- # (at your option) any later version.
12
- #
13
- # iotas is distributed in the hope that it will be useful,
14
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- # GNU Affero General Public License for more details.
17
- #
18
- # You should have received a copy of the GNU Affero General Public License
19
- # along with iotas. If not, see <http://www.gnu.org/licenses/>.
20
-
21
- #
22
- module Iotas
23
- #
24
- class Spin < Room
25
- #
26
- def initialize n, o={}
27
- super n, nil
28
- #
29
- @pool = {} # per particle class free list
30
- @world = {} # global iotas index
31
- @sys_fifo = [] # system particles fifo list
32
- @app_fifo = [] # application particles fifo list
33
- #
34
- @run = false
35
- @hibernation = o['hibernation']||false
36
- @hibernate_path = 'iotas-hibernate-'+n+'.json'
37
- @debug_errors = o[:debug_errors]||o['debug_errors']||false
38
- @debug_routing = o[:debug_routing]||o['debug_routing']||false
39
- #
40
- if not o.empty?
41
- o['iotas'].each do |name,iota|
42
- Iotas::Room.json_create(iota.merge!('parent'=>self))
43
- end if o['iotas']
44
- o['app_fifo'].each do |particle|
45
- @app_fifo << Iotas::Particle.json_create(particle.merge!('spin'=>self))
46
- end if o['app_fifo']
47
- o['sys_fifo'].each do |particle|
48
- @sys_fifo << Iotas::Particle.json_create(particle.merge!('spin'=>self))
49
- end if o['sys_fifo']
50
- end
51
- end
52
- #
53
- attr_accessor :run, :hibernate_path, :debug_errors, :debug_routing
54
- #
55
- def to_json *a
56
- {
57
- 'kls' => self.class.name,
58
- 'timestamp' => Time.now,
59
- 'name' => @name,
60
- 'hibernation' => @hibernation,
61
- 'iotas' => @iotas,
62
- 'sys_fifo' => @sys_fifo,
63
- 'app_fifo' => @app_fifo,
64
- 'debug_errors' => @debug_errors,
65
- 'debug_routing' => @debug_routing
66
- }.to_json(*a)
67
- end
68
- #
69
- def self.json_create o
70
- raise Iotas::Exception.new "JSON #{o['kls']} != #{self.name}" if o['kls'] != self.name
71
- self.new o['name'], o
72
- end
73
- #
74
- def add_to_world iota
75
- @world[iota.path] = iota
76
- end
77
- #
78
- def search_world path
79
- @world[path]
80
- end
81
- #
82
- def clear!
83
- @iotas.clear
84
- @pool.clear
85
- @sys_fifo.clear
86
- @app_fifo.clear
87
- end
88
- #
89
- #
90
- def release_p p
91
- # hope there is no circular loop
92
- while p2=p.merged_shift
93
- release_p p2
94
- end
95
- ( @pool[p.class] ||= [] ) << p
96
- end
97
- #
98
- def require_p p_kls
99
- l = @pool[p_kls]
100
- return p_kls.new if l.nil?
101
- p = l.pop
102
- return p_kls.new if p.nil?
103
- p.reset!
104
- p
105
- end
106
- #
107
- def post_p p
108
- @app_fifo << p
109
- end
110
- #
111
- def post_sys_p p
112
- @sys_fifo << p
113
- end
114
- #
115
- def process_sys_p p
116
- if p.action==Iotas::SYS_ACT_HIBERNATE
117
- stop!
118
- hibernate! p[FIELD_HIBERNATE_PATH]
119
- else
120
- super p
121
- end
122
- end
123
- #
124
- def spin!
125
- @iotas.values.each do |iota| iota.start! end unless @hibernation
126
- @run = true
127
- @hibernation = false
128
- while @run and (@sys_fifo.length>0 or @app_fifo.length>0)
129
- while @run and @sys_fifo.length>0
130
- p = @sys_fifo.shift
131
- p.dst_reached!.process_sys_p p
132
- end
133
- while @run and @app_fifo.length>0
134
- p = @app_fifo.shift
135
- p.dst_reached!.process_p p
136
- break
137
- end
138
- end
139
- @iotas.values.each do |iota| iota.stop! end unless @hibernation
140
- end
141
- #
142
- def stop!
143
- @run=false
144
- end
145
- #
146
- def hibernate! path=nil
147
- @hibernation = true
148
- File.open(path||@hibernate_path,'w') do |f| f << JSON.pretty_generate(self) end
149
- end
150
- #
151
- def self.resume! path
152
- self.json_create JSON.load File.open(path,'r') { |f| f.read }
153
- end
154
- #
155
- end
156
- #
157
- end
158
- #
159
- # EOF