iotas 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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