Please disable Adblockers and enable JavaScript for domain CEWebS.cs.univie.ac.at! We have NO ADS, but they may interfere with some of our course material.
Name: server/engine/implementation.rb
1: | require ::File.dirname(__FILE__) + '/controller' |
2: | |
3: | class Callback #{{{ |
4: | def initialize(info,handler,method,event,key,protocol,*context) |
5: | @info = info |
6: | @event = event |
7: | @key = key |
8: | @context = context |
9: | @handler = handler |
10: | @protocol = protocol |
11: | @method = method.class == Symbol ? method : :callback |
12: | end |
13: | |
14: | attr_reader :info, :protocol |
15: | |
16: | def delete_if!(event,key) |
17: | @handler.send @method, :DELETE, *@context if @key == key && @event == event |
18: | nil |
19: | end |
20: | |
21: | def callback(result) |
22: | @handler.send @method, result, *@context |
23: | end |
24: | end #}}} |
25: | |
26: | class ExCallback < Riddl::Implementation #{{{ |
27: | def response |
28: | controller = @a[0] |
29: | id = @r[0].to_i |
30: | callback = @r[2] |
31: | controller[id].mutex.synchronize do |
32: | if controller[id].callbacks.has_key?(callback) |
33: | controller[id].callbacks[callback].callback(@p) |
34: | end |
35: | end |
36: | end |
37: | end #}}} |
38: | |
39: | class Callbacks < Riddl::Implementation #{{{ |
40: | def response |
41: | controller = @a[0] |
42: | unless File.exists?("instances/#{@r[0]}") |
43: | @status = 400 |
44: | return |
45: | end |
46: | Riddl::Parameter::Complex.new("info","text/xml") do |
47: | cb = XML::Smart::string("<?xml-stylesheet href='/xsls/callbacks.xsl' type='text/xsl'?><callbacks details='#{@a[0]}'/>") |
48: | id = @r[0].to_i |
49: | controller[id].callbacks.each do |k,v| |
50: | cb.root.add("callback",{"id" => k},"[#{v.protocol.to_s}] #{v.info}") |
51: | end |
52: | cb.to_s |
53: | end |
54: | end |
55: | end #}}} |
56: | |
57: | class Instances < Riddl::Implementation #{{{ |
58: | def response |
59: | controller = @a[0] |
60: | Riddl::Parameter::Complex.new("wis","text/xml") do |
61: | ins = XML::Smart::string('<instances/>') |
62: | controller.each do |k,v| |
63: | name = v.properties.data.find("string(/p:properties/p:name)") |
64: | state = v.properties.data.find("string(/p:properties/p:state)") |
65: | ins.root.add('instance',name, 'id' => k, 'state' => state) |
66: | end |
67: | ins.to_s |
68: | end |
69: | end |
70: | end #}}} |
71: | |
72: | class NewInstance < Riddl::Implementation #{{{ |
73: | def response |
74: | controller = @a[0] |
75: | opts = @a[1] |
76: | name = @p[0].value |
77: | id = controller.keys.sort.last.to_i |
78: | |
79: | while true |
80: | id += 1 |
81: | Dir.mkdir(opts[:instances] + "/#{id}") rescue nil |
82: | break |
83: | end |
84: | controller[id] = Controller.new(id,opts) |
85: | controller[id].properties.data.find("/p:properties/p:name").first.text = name |
86: | |
87: | Riddl::Parameter::Simple.new("id", id) |
88: | end |
89: | end #}}} |
90: | |
91: | class Info < Riddl::Implementation #{{{ |
92: | def response |
93: | controller = @a[0] |
94: | id = @r[0].to_i |
95: | unless controller[id] |
96: | @status = 400 |
97: | return |
98: | end |
99: | Riddl::Parameter::Complex.new("info","text/xml") do |
100: | i = XML::Smart::string <<-END |
101: | <?xml-stylesheet href="../xsls/info.xsl" type="text/xsl"?> |
102: | <info instance='#{@r[0]}'> |
103: | <events/> |
104: | <notifications/> |
105: | <properties/> |
106: | <callbacks/> |
107: | </info> |
108: | END |
109: | i.to_s |
110: | end |
111: | end |
112: | end #}}} |
113: | |
114: | class DeleteInstance < Riddl::Implementation #{{{ |
115: | def response |
116: | controller = @a[0] |
117: | unless File.exists?("instances/#{@r[0]}") |
118: | @status = 400 |
119: | return |
120: | end |
121: | FileUtils.rm_r("instances/#{@r[0]}") |
122: | controller.delete(@r[0]) |
123: | end |
124: | end #}}} |
125: | |
126: | class Event < Riddl::Implementation #{{{ |
127: | def response |
128: | controller = @a[0] |
129: | id = @r[0].to_i |
130: | topic = @p.find{|e|e.name=='topic'}.value |
131: | event = @p.find{|e|e.name=='vote'}.value |
132: | parameters = JSON::parse(@p.find{|e|e.name=='notification'}.value) |
133: | |
134: | name = "#{topic}_#{event}" |
135: | para = {} |
136: | parameters.each do |k,v| |
137: | para[k.to_sym] = v |
138: | end |
139: | ret = [] |
140: | if controller[id].test_push(name,para) |
141: | @headers << Riddl::Header.new("CPEE-CALLBACK",'true') |
142: | ret << Riddl::Parameter::Simple.new('continue','callback') |
143: | else |
144: | @headers << Riddl::Header.new("CPEE-CALLBACK",'false') |
145: | ret << Riddl::Parameter::Simple.new('continue','true') |
146: | end |
147: | Thread.new { controller[id].push(name,para) } |
148: | ret |
149: | end |
150: | end #}}} |
151: | |
152: | class PropertiesHandler < Riddl::Utils::Properties::HandlerBase #{{{ |
153: | def sync |
154: | if @property == 'state' |
155: | state = @data.state |
156: | if state == 'stopped' |
157: | @data.stop |
158: | @data.notify("properties/#{@property}/change") |
159: | end |
160: | if state == 'running' |
161: | if @data.call_vote("properties/#{@property}/running") |
162: | @data.start |
163: | @data.notify("properties/#{@property}/change") |
164: | else |
165: | @data.serialize_state!('stopped') |
166: | end |
167: | end |
168: | else |
169: | @data.unserialize_context!(@property) |
170: | @data.notify("properties/#{@property}/change") |
171: | end |
172: | end |
173: | |
174: | def create; sync; end |
175: | def update; sync; end |
176: | def delete; sync; end |
177: | end #}}} |
178: | |
179: | class NotificationsHandler < Riddl::Utils::Notifications::Producer::HandlerBase #{{{ |
180: | def ws_open(socket) |
181: | @data.add_ws(@key,socket) |
182: | end |
183: | def ws_close |
184: | @data.del_ws(@key) |
185: | end |
186: | def ws_message(socket,data) |
187: | begin |
188: | doc = XML::Smart::string(data) |
189: | callback = doc.find("string(/vote/@id)") |
190: | result = doc.find("string(/vote)") |
191: | @data.callbacks[callback].callback(result == 'true' ? true : false) |
192: | @data.callbacks.delete(callback) |
193: | rescue |
194: | puts "Invalid message over websocket" |
195: | end |
196: | end |
197: | |
198: | def create |
199: | @data.unserialize_event!(:cre,@key) |
200: | @data.notify('properties/handlers/change') |
201: | end |
202: | def delete |
203: | @data.unserialize_event!(:del,@key) |
204: | @data.notify('properties/handlers/change') |
205: | end |
206: | def update |
207: | @data.unserialize_event!(:upd,@key) |
208: | @data.notify('properties/handlers/change') |
209: | end |
210: | end #}}} |