riddl 0.99.218 → 0.99.219

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e2ea540548ddd792ec444fec0648dc10c0ed8cfb
4
- data.tar.gz: 72eb21e4bc237319f5734f4247760404c11279f0
3
+ metadata.gz: f5a7fd98e32be12a9b153657c3959ac670be0e3f
4
+ data.tar.gz: d743380ae7ebab04a1c4d8ddcdb1d3acfdb156c9
5
5
  SHA512:
6
- metadata.gz: 1fdc06a909c934f12169de63e9c30d0182c971daebe3ff42b1eb8be8d90ea4dc6b3780b7db663a92e7947f23864b40c5ce3857ae2c58d41353fa44eb79a5d3ec
7
- data.tar.gz: 58b256db07facc0bafa349b8c004fa89ee2a89d87112665cdfe4cb80cc79508a2d5eb0c6dbd273f752062760541df1f216165a20c9aa27266152f5176b091f20
6
+ metadata.gz: a1e1424f7bb9820af80dbfe314071f8a9f81584eb7ee13579c5571e0bcb63909a506f6c5ed12f9d78372bc1e8233dc5ce7f37fce2b273801faf029f2557ffc86
7
+ data.tar.gz: 454f78db0320ad93dece4b885ec3796ae267f40cad9f3061d5fe9676658a983624bb49d93e28ad05b7f5b9bc1acf9fc20bbd74bbd3a9054825ea8957992db0f3
@@ -0,0 +1,33 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../client')
2
+
3
+ module Riddl
4
+ module Utils
5
+ module Description
6
+
7
+ class RDR < Riddl::Implementation
8
+ def response
9
+ @headers << Riddl::Header.new("RIDDL_DESCRIPTION", 'oh my, a riddl description')
10
+ return Riddl::Parameter::Complex.new("riddl-description","text/xml",@a[0])
11
+ end
12
+ end
13
+
14
+ class Call < Riddl::Implementation
15
+ def response
16
+ client = Riddl::Client.new @a[3]
17
+
18
+ path = client.resource "/" + @a[4]
19
+ @status, result, headers = if @a[0].nil?
20
+ path.request @m => [ Riddl::Header.new("RIDDL_DECLARATION_RESOURCE", @a[2]), Riddl::Header.new("RIDDL-DECLARATION-PATH", @a[1]) ] + @h.map{|a,b| Riddl::Header.new(a,b)} + @p
21
+ else
22
+ path.request @m => [ Riddl::Header.new("RIDDL_DECLARATION_RESOURCE", @a[2]), Riddl::Header.new("RIDDL-DECLARATION-PATH", @a[1]) ] + @a[0].headers.map{|a,b| Riddl::Header.new(a,b)} + @a[0].response
23
+ end
24
+ headers.each do |k,v|
25
+ @headers << Riddl::Header.new(k,v) unless ["CONTENT_TYPE", "CONTENT_DISPOSITION", "RIDDL_TYPE", "CONTENT_ID", "CONTENT_LENGTH", "CONNECTION", "SERVER"].include?(k)
26
+ end
27
+ result
28
+ end
29
+ end
30
+
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,255 @@
1
+ <!DOCTYPE html>
2
+ <html>
3
+ <head>
4
+ <meta charset="UTF-8"/>
5
+ <meta http-equiv="X-UA-Compatible" content="IE=EDGE"/>
6
+
7
+ <title>Documentation</title>
8
+
9
+ <style>
10
+ body {
11
+ counter-reset: h1counter;
12
+ }
13
+ h1 { font-size: 1.5em; counter-reset: h2counter; }
14
+ h2 { font-size: 1.2em; }
15
+ h3 { font-size: 1.0em }
16
+ h1:before {
17
+ content: counter(h1counter) ".\0000a0\0000a0";
18
+ counter-increment: h1counter;
19
+ }
20
+ h2:before {
21
+ content: counter(h1counter) "." counter(h2counter) ".\0000a0\0000a0";
22
+ counter-increment: h2counter;
23
+ }
24
+ .code {
25
+ border: 1px dashed #425d73; background-color: #DEE6EE; margin:0px; padding: 0.5em 1em; font-family: monospace; font-size:0.9em;
26
+ }
27
+ </style>
28
+
29
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
30
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.5.0/lodash.min.js"></script>
31
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script>
32
+ <script src="https://cdn.rawgit.com/vkiryukhin/vkBeautify/master/vkbeautify.js"></script>
33
+ <script>//<![CDATA[
34
+ $.fn.serializeXML = function(){
35
+ var out = '';
36
+ if (typeof XMLSerializer == 'function') {
37
+ var xs = new XMLSerializer();
38
+ this.each(function() {
39
+ out += xs.serializeToString(this);
40
+ });
41
+ } else if (this[0] && this[0].xml != 'undefined') {
42
+ this.each(function() {
43
+ out += this.xml;
44
+ });
45
+ }
46
+ return out;
47
+ };
48
+
49
+ function docChildren(path,name,data){
50
+ var ret= [];
51
+ var subject = path ? $(path,data) : $(data);
52
+ subject.children().each(function(k,ele){
53
+ if (ele.localName == name && ele.namespaceURI == "http://riddl.org/ns/documentation/1.0") {
54
+ ret.push(ele);
55
+ }
56
+ });
57
+ return $(ret);
58
+ }
59
+
60
+ function codeFormat(temp) {
61
+ temp = temp.replace(/\&/g,"&amp;").replace(/\"/g,"&quot;").replace(/>/g,"&gt;").replace(/</g,"&lt;").replace(/'/g,"&apos;");
62
+ temp = temp.replace(/\t/g,' ');
63
+ temp = temp.replace(/\r/g,'');
64
+ temp = temp.replace(/^$/g,' ');
65
+ temp = temp.replace(/^ */gm,function mf(m){
66
+ var tm = (m.length + 2) * 0.6 + 2 * 0.6;
67
+ return "<div style='text-indent:-" + tm + "em;margin-left:" + tm + "em'>" + (Array(m.length + 1).join("&#160;"));
68
+ });
69
+ temp = temp.replace(/ /g," &#160;");
70
+ temp = temp.replace(/\n/g,"</div>\n");
71
+ temp += "</div>\n";
72
+ temp = temp.replace(/href=&quot;([^&]+)&quot;/g,'href=&quot;<a href="/__doc_includes/$1">$1</a>&quot;')
73
+ return temp;
74
+ }
75
+
76
+ $(document).ready(function(){
77
+ var rpath = "<%= @h['RIDDL_DECLARATION_PATH'] %>";
78
+ var pathele = _.compact(rpath.split('/'));
79
+
80
+ var t = $('#breadcrumblink')[0];
81
+ var link = "";
82
+ _.each(pathele,function(e){
83
+ link = link + "/" + e;
84
+ var clone = document.importNode(t.content, true);
85
+ $('a',clone).attr('href',link + "/?doc=true");
86
+ $('a',clone).text(e);
87
+ $('#breadcrumb').append(clone);
88
+ });
89
+
90
+ $.ajax({
91
+ url: rpath + "?riddl-resource-description",
92
+ success: function(data){
93
+ $('#main').append(marked(docChildren('description > resource','documentation',data).text()));
94
+
95
+ var subr = $('description > resource > resource',data);
96
+ if (subr.length == 0) {
97
+ $('#subresources').remove();
98
+ } else {
99
+ $('description > resource > resource',data).each(function(k,ele){
100
+ var sum = docChildren(null,'documentation',ele).attr('summary');
101
+ var exa = docChildren(null,'example',ele);
102
+ exa = exa.length == 0 ? null : exa.text();
103
+ if (exa) {
104
+ var rell = exa;
105
+ if ($(ele).attr('relative')) {
106
+ var relt = exa + ' (' + $(ele).attr('relative') + ')';
107
+ } else {
108
+ var relt = '{} (any string possible)';
109
+ }
110
+ } else {
111
+ var rell = $(ele).attr('relative');
112
+ var relt = _.trim(rell);
113
+ }
114
+ var t = $('#subresourceitem')[0];
115
+ var clone = document.importNode(t.content, true);
116
+ $('a',clone).attr('href','./' + rell + '/?doc=true');
117
+ if (relt != "") {
118
+ $('a',clone).text(relt);
119
+ }
120
+ if (sum) { $('.content',clone).text(sum); }
121
+ $('#subresources .anchor').append(clone);
122
+ });
123
+ }
124
+
125
+ var oprs = $('description > resource > get, description > resource > post, description > resource > put, description > resource > delete, description > resource > request',data);
126
+ if (oprs.length == 0) {
127
+ $('#operations').remove();
128
+ } else {
129
+ oprs.each(function(k,ele){
130
+ var sum = docChildren(null,'documentation',ele).attr('summary');
131
+ var details = docChildren(null,'documentation',ele).text();
132
+ var example = docChildren(null,'example',ele);
133
+ var ex = null;
134
+
135
+ var tin = $(ele).attr('in');
136
+ var tout = $(ele).attr('out');
137
+ var whatl = $(ele).prop('tagName');
138
+ var whatd = tin == "*" ? '' : '( ' + tin + ' )';
139
+ whatd += tout ? ' : ' + tout : '';
140
+
141
+ var tinmess = "";
142
+ if (tin && tin != "*") {
143
+ $('description > message[name="' + tin + '"]',data).each(function(k,mess){
144
+ tinmess = mess;
145
+ _.each(mess.attributes,function(attr){
146
+ if (attr.localName == 'example' && attr.namespaceURI == "http://riddl.org/ns/documentation/1.0") {
147
+ ex = attr.nodeValue;
148
+ }
149
+ });
150
+ });
151
+ }
152
+ if (example.length > 0) { ex = example.text(); }
153
+
154
+ var toutmess = "";
155
+ if (tout && tout != "*") {
156
+ $('description > message[name="' + tout + '"]',data).each(function(k,mess){
157
+ toutmess = mess;
158
+ });
159
+ }
160
+
161
+ // Overview
162
+ var t = $('#operationitem')[0];
163
+ var clone = document.importNode(t.content, true);
164
+ $('.what .link',clone).text(whatl);
165
+ $('.what .link',clone).attr('href','#' + (whatl + '_' + whatd).replace(/ /g,'_'));
166
+ $('.what .details',clone).text(whatd);
167
+ if (ex != null) {
168
+ if (ex == "")
169
+ $('.what .try a',clone).attr('href',window.location.pathname);
170
+ else
171
+ $('.what .try a',clone).attr('href','?' + ex);
172
+ } else {
173
+ $('.what .try',clone).remove();
174
+ }
175
+ if (sum) { $('.content',clone).text(sum); }
176
+ $('#operations .anchor').append(clone);
177
+
178
+ //Details
179
+ var t = $('#operationsec')[0];
180
+ var clone = document.importNode(t.content, true);
181
+ $('.what',clone).text(whatl + ' ' + whatd);
182
+ $('.what',clone).attr('id',(whatl + '_' + whatd).replace(/ /g,'_'));
183
+ if (_.trim(details) == "") {
184
+ $('.text',clone).text(sum);
185
+ } else {
186
+ $('.text',clone).append(marked(details));
187
+ }
188
+ if (ex != null) {
189
+ if (ex == "") {
190
+ $('.try a',clone).attr('href',window.location.pathname);
191
+ } else {
192
+ $('.try a',clone).attr('href','?' + ex);
193
+ $('.try a',clone).text('?' + ex);
194
+ }
195
+ } else {
196
+ $('.try',clone).remove();
197
+ }
198
+
199
+ if (tin && tin != "*") {
200
+ $('.input .message',clone).html(codeFormat(vkbeautify.xml($(tinmess).serializeXML(),' ')));
201
+ } else {
202
+ $('.input',clone).remove();
203
+ }
204
+ if (tout) {
205
+ $('.output .message',clone).html(codeFormat(vkbeautify.xml($(toutmess).serializeXML(),' ')));
206
+ } else {
207
+ $('.output',clone).remove();
208
+ }
209
+ $('#operations').append(clone);
210
+ });
211
+ }
212
+ }
213
+ });
214
+ });
215
+ //]]></script>
216
+ </head>
217
+ <body>
218
+ <template id="breadcrumblink"><span> / </span><a href=""></a></template>
219
+ <template id="subresourceitem"><li><div class='what'><a class='details' href=''>Example missing</a></div><div class="content"></div></li></template>
220
+ <template id="operationitem"><li><div class='what'><a class='link' href=''></a> <span class='details'></span> <span class='try'>(<a href=''>Try it!</a>)</span></div><div class="content"></div></li></template>
221
+ <template id="operationsec">
222
+ <section>
223
+ <h2 class="what" id=""></h2>
224
+ <p class="try">Example: <a href=""><i>no parameters</i></a></p>
225
+ <p class="text"></p>
226
+ <div class="input">
227
+ <h3>Input</h3>
228
+ <div class='message code'></div>
229
+ </div>
230
+ <div class="output">
231
+ <h3>Output</h3>
232
+ <div class='message code'></div>
233
+ </div>
234
+ </section>
235
+ </template>
236
+
237
+ <nav id="breadcrumb">[<a href="/">TOP</a>]</nav>
238
+ <section id="main"></section>
239
+ <section id="subresources">
240
+ <h1>Sub-Resources</h1>
241
+ <p>From here on you can go to the following sub resources:</p>
242
+ <ul class="anchor"></ul>
243
+ </section>
244
+ <section id="operations">
245
+ <h1>Operations</h1>
246
+ <section>
247
+ <p>For this resource the following operations are possible:</p>
248
+ <ul class="anchor"></ul>
249
+ </section>
250
+ </section>
251
+ </body>
252
+ </html>
253
+
254
+
255
+
@@ -0,0 +1,14 @@
1
+ require 'erb'
2
+
3
+ module Riddl
4
+ module Utils
5
+
6
+ class DocOverlay < Riddl::Implementation
7
+ def response
8
+ rval = ERB.new(File.read(File.dirname(__FILE__) + '/docoverlay.html'), 0, "%<>")
9
+ Riddl::Parameter::Complex.new('documentationresponse','text/html',rval.result(binding))
10
+ end
11
+ end
12
+
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ require 'mime/types'
2
+ require 'digest/md5'
3
+
4
+ module Riddl
5
+ module Utils
6
+ class Downloadify < Riddl::Implementation
7
+ def response
8
+ mimetype = @p.find{|e|e.name == 'mimetype'}.value
9
+ content = @p.find{|e|e.name == 'content'}.value
10
+ Riddl::Parameter::Complex.new("content",mimetype,content,@r.last)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,24 @@
1
+ require 'mime/types'
2
+ require 'erb'
3
+
4
+ module Riddl
5
+ module Utils
6
+ class ERBServe < Riddl::Implementation
7
+ def response
8
+ path = File.file?(@a[0]) ? @a[0] : "#{@a[0]}/#{@r[@match.length..-1].join('/')}".gsub(/\/+/,'/')
9
+ input = @a[1]
10
+ if File.directory?(path)
11
+ @status = 404
12
+ return []
13
+ end
14
+ if File.exists?(path)
15
+ __ERB_FILE__ = path
16
+ rval = ERB.new(File.read(path), 0, "%<>")
17
+ return Riddl::Parameter::Complex.new("data",MIME::Types.type_for(path)[0].to_s,rval.result(binding))
18
+ end
19
+ @status = 404
20
+ []
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,45 @@
1
+ require 'mime/types'
2
+ require 'charlock_holmes'
3
+ require 'digest/md5'
4
+
5
+ module Riddl
6
+ module Utils
7
+ class FileServe < Riddl::Implementation
8
+ def response
9
+ path = File.file?(@a[0]) ? @a[0] : "#{@a[0]}/#{@r[@match.length-1..-1].join('/')}".gsub(/\/+/,'/')
10
+
11
+ if File.directory?(path)
12
+ @status = 404
13
+ return []
14
+ end
15
+ if File.exists?(path)
16
+ mtime = File.mtime(path)
17
+ @headers << Riddl::Header.new("Last-Modified",mtime.httpdate)
18
+ @headers << Riddl::Header.new("ETag",Digest::MD5.hexdigest(mtime.httpdate))
19
+ htime = @env["HTTP_IF_MODIFIED_SINCE"].nil? ? Time.at(0) : Time.parse(@env["HTTP_IF_MODIFIED_SINCE"])
20
+ if htime == mtime
21
+ @headers << Riddl::Header.new("Connection","close")
22
+ @status = 304 # Not modified
23
+ return []
24
+ else
25
+ fmt = @a[1] || begin
26
+ mt = MIME::Types.type_for(path).first
27
+ if mt.nil?
28
+ 'text/plain;charset=utf-8'
29
+ else
30
+ apx = ''
31
+ if mt.ascii?
32
+ tstr = File.read(path,CharlockHolmes::EncodingDetector::DEFAULT_BINARY_SCAN_LEN)
33
+ apx = ';charset=' + CharlockHolmes::EncodingDetector.detect(tstr)[:encoding]
34
+ end
35
+ mt.to_s + apx
36
+ end
37
+ end
38
+ return Riddl::Parameter::Complex.new('file',fmt,File.open(path,'r'))
39
+ end
40
+ end
41
+ @status = 404
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,328 @@
1
+ module Riddl
2
+ module Utils
3
+ module Notifications
4
+
5
+ module Producer
6
+
7
+ def self::implementation(backend,handler=nil,details=:production)
8
+ unless handler.nil? || (handler.is_a? Riddl::Utils::Notifications::Producer::HandlerBase)
9
+ raise "handler not a subclass of HandlerBase"
10
+ end
11
+ Proc.new do
12
+ on resource "notifications" do
13
+ run Riddl::Utils::Notifications::Producer::Overview if get
14
+ on resource "topics" do
15
+ run Riddl::Utils::Notifications::Producer::Topics, backend if get
16
+ end
17
+ on resource "subscriptions" do
18
+ run Riddl::Utils::Notifications::Producer::Subscriptions, backend, details if get
19
+ run Riddl::Utils::Notifications::Producer::CreateSubscription, backend, handler if post 'subscribe'
20
+ on resource do
21
+ run Riddl::Utils::Notifications::Producer::Subscription, backend, details if get 'request'
22
+ run Riddl::Utils::Notifications::Producer::UpdateSubscription, backend, handler if put 'details'
23
+ run Riddl::Utils::Notifications::Producer::DeleteSubscription, backend, handler if delete 'delete'
24
+ on resource 'ws' do
25
+ run Riddl::Utils::Notifications::Producer::WS, backend, handler if websocket
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ class HandlerBase #{{{
34
+ def initialize(data)
35
+ @data = data
36
+ @key = nil
37
+ @topics = []
38
+ end
39
+ def key(k)
40
+ @key = k
41
+ self
42
+ end
43
+ def topics(t)
44
+ @topics = t
45
+ self
46
+ end
47
+ def ws_open(socket); end
48
+ def ws_close; end
49
+ def ws_message(socket,data); end
50
+ def create; end
51
+ def delete; end
52
+ def update; end
53
+ end #}}}
54
+
55
+ class Backend #{{{
56
+ attr_reader :topics
57
+
58
+ class Sub #{{{
59
+ def initialize(name)
60
+ @name = name
61
+ end
62
+ def modify(&block)
63
+ XML::Smart.modify(@name,"<subscription xmlns='http://riddl.org/ns/common-patterns/notifications-producer/1.0'/>") do |doc|
64
+ doc.register_namespace 'n', 'http://riddl.org/ns/common-patterns/notifications-producer/1.0'
65
+ block.call doc
66
+ end
67
+ end
68
+ def delete
69
+ FileUtils::rm_rf(File.dirname(@name))
70
+ end
71
+ def to_s
72
+ File.read(@name)
73
+ end
74
+ def read(&block)
75
+ XML::Smart.open_unprotected(@name) do |doc|
76
+ doc.register_namespace 'n', 'http://riddl.org/ns/common-patterns/notifications-producer/1.0'
77
+ block.call doc
78
+ end
79
+ end
80
+ end #}}}
81
+
82
+ class Subs #{{{
83
+ def initialize(target)
84
+ @target = target
85
+ end
86
+
87
+ def each(&block)
88
+ keys.each do |key|
89
+ f = @target + '/' + key + '/subscription.xml'
90
+ block.call Sub.new(f), key if File.exists? f
91
+ end
92
+ end
93
+
94
+ def include?(key)
95
+ f = @target + '/' + key + '/subscription.xml'
96
+ File.exists?(f)
97
+ end
98
+
99
+ def [](key)
100
+ f = @target + '/' + key + '/subscription.xml'
101
+ File.exists?(f) ? Sub.new(f) : nil
102
+ end
103
+
104
+ def create(&block)
105
+ key = nil
106
+ begin
107
+ continue = true
108
+ key = Digest::MD5.hexdigest(Kernel::rand().to_s)
109
+ Dir.mkdir(@target + '/' + key) rescue continue = false
110
+ end until continue
111
+ producer_secret = Digest::MD5.hexdigest(Kernel::rand().to_s)
112
+ consumer_secret = Digest::MD5.hexdigest(Kernel::rand().to_s)
113
+ File.open(@target + '/' + key + '/producer-secret','w') { |f| f.write producer_secret }
114
+ File.open(@target + '/' + key + '/consumer-secret','w') { |f| f.write consumer_secret }
115
+ XML::Smart::modify(@target + '/' + key + '/subscription.xml',"<subscription xmlns='http://riddl.org/ns/common-patterns/notifications-producer/1.0'/>") do |doc|
116
+ doc.register_namespace 'n', 'http://riddl.org/ns/common-patterns/notifications-producer/1.0'
117
+ block.call doc, key
118
+ end
119
+ [key, producer_secret, consumer_secret]
120
+ end
121
+
122
+ def keys
123
+ if File.directory?(@target)
124
+ Dir[@target + '/*'].map do |d|
125
+ File.directory?(d) ? File.basename(d) : nil
126
+ end.compact
127
+ else
128
+ []
129
+ end
130
+ end
131
+ end #}}}
132
+
133
+ def initialize(topics,target)
134
+ @target = target.gsub(/^\/+/,'/')
135
+
136
+ FileUtils::mkdir_p(@target) unless File.exists?(@target)
137
+
138
+ raise "topics file not found" unless File.exists?(topics)
139
+ @topics = XML::Smart.open_unprotected(topics.gsub(/^\/+/,'/'))
140
+ @topics.register_namespace 'n', 'http://riddl.org/ns/common-patterns/notifications-producer/1.0'
141
+
142
+ subscriptions.each do |sub,key|
143
+ sub.read do |doc|
144
+ if doc.find('/*[@url]').empty?
145
+ sub.delete
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ def subscriptions
152
+ Subs.new(@target)
153
+ end
154
+
155
+ end #}}}
156
+
157
+ class Overview < Riddl::Implementation #{{{
158
+ def response
159
+ Riddl::Parameter::Complex.new("overview","text/xml") do
160
+ <<-END
161
+ <overview xmlns='http://riddl.org/ns/common-patterns/notifications-producer/1.0'>
162
+ <topics/>
163
+ <subscriptions/>
164
+ </overview>
165
+ END
166
+ end
167
+
168
+ end
169
+ end #}}}
170
+
171
+ class Topics < Riddl::Implementation #{{{
172
+ def response
173
+ backend = @a[0]
174
+ Riddl::Parameter::Complex.new("overview","text/xml") do
175
+ backend.topics.to_s
176
+ end
177
+ end
178
+ end #}}}
179
+
180
+ class Subscriptions < Riddl::Implementation #{{{
181
+ def response
182
+ backend = @a[0]
183
+ details = @a[1]
184
+ Riddl::Parameter::Complex.new("subscriptions","text/xml") do
185
+ ret = XML::Smart::string <<-END
186
+ <subscriptions details='#{details}' xmlns='http://riddl.org/ns/common-patterns/notifications-producer/1.0'/>
187
+ END
188
+ backend.subscriptions.each do |sub,key|
189
+ sub.read do |doc|
190
+ if doc.root.attributes['url']
191
+ ret.root.add('subscription', :id => key, :url => doc.root.attributes['url'])
192
+ else
193
+ ret.root.add('subscription', :id => key)
194
+ end
195
+ end
196
+ end
197
+ ret.to_s
198
+ end
199
+ end
200
+ end #}}}
201
+
202
+ class Subscription < Riddl::Implementation #{{{
203
+ def response
204
+ backend = @a[0]
205
+ if(backend.subscriptions.include?(@r.last))
206
+ Riddl::Parameter::Complex.new("subscription","text/xml") do
207
+ backend.subscriptions[@r.last].to_s
208
+ end
209
+ else
210
+ @status = 404
211
+ end
212
+ end
213
+ end #}}}
214
+
215
+ class CreateSubscription < Riddl::Implementation #{{{
216
+ def response
217
+ backend = @a[0]
218
+ handler = @a[1]
219
+
220
+ url = @p[0].name == 'url' ? @p.shift.value : nil
221
+
222
+ topics = []
223
+ key, consumer_secret, producer_secret = backend.subscriptions.create do |doc,key|
224
+ doc.root.attributes['url'] = url if url
225
+ while @p.length > 0
226
+ topic = @p.shift.value
227
+ base = @p.shift
228
+ type = base.name
229
+ items = base.value.split(',')
230
+ t = if topics.include?(topic)
231
+ doc.find("/n:subscription/n:topic[@id='#{topic}']").first
232
+ else
233
+ topics << topic
234
+ doc.root.add('topic', :id => topic)
235
+ end
236
+ items.each do |i|
237
+ t.add(type[0..-2], i)
238
+ end
239
+ end
240
+ end
241
+
242
+ handler.key(key).topics(topics).create unless handler.nil?
243
+ [
244
+ Riddl::Parameter::Simple.new('key',key),
245
+ Riddl::Parameter::Simple.new('producer-secret',producer_secret),
246
+ Riddl::Parameter::Simple.new('consumer-secret',consumer_secret)
247
+ ]
248
+ end
249
+ end #}}}
250
+
251
+ class DeleteSubscription < Riddl::Implementation #{{{
252
+ def response
253
+ backend = @a[0]
254
+ handler = @a[1]
255
+ key = @r.last
256
+
257
+ backend.subscriptions[key].delete
258
+ handler.key(key).delete unless handler.nil?
259
+ return
260
+ end
261
+ end #}}}
262
+
263
+ class UpdateSubscription < Riddl::Implementation #{{{
264
+ def response
265
+ backend = @a[0]
266
+ handler = @a[1]
267
+ key = @r.last
268
+
269
+ url = @p[0].name == 'url' ? @p.shift.value : nil
270
+
271
+ # TODO check if message is valid (with producer secret)
272
+ unless backend.subscriptions[key]
273
+ @status = 404
274
+ return # subscription not found
275
+ end
276
+
277
+ topics = []
278
+ backend.subscriptions[key].modify do |doc|
279
+ if url.nil?
280
+ doc.find('/n:subscription/@url').delete_all!
281
+ else
282
+ doc.root.attributes['url'] = url
283
+ end
284
+ doc.root.children.delete_all!
285
+ while @p.length > 1
286
+ topic = @p.shift.value
287
+ base = @p.shift
288
+ type = base.name
289
+ items = base.value.split(',')
290
+ t = if topics.include?(topic)
291
+ doc.find("/n:subscription/n:topic[@id='#{topic}']").first
292
+ else
293
+ topics << topic
294
+ doc.root.add('topic', :id => topic)
295
+ end
296
+ items.each do |i|
297
+ t.add(type[0..-2], i)
298
+ end
299
+ end
300
+ end
301
+
302
+ handler.key(key).topics(topics).update unless handler.nil?
303
+ nil
304
+ end
305
+ end #}}}
306
+
307
+ class WS < Riddl::WebSocketImplementation #{{{
308
+ def onopen
309
+ @backend = @a[0]
310
+ @handler = @a[1]
311
+ @key = @r[-2]
312
+ @handler.key(@key).ws_open(self) unless @handler.nil?
313
+ end
314
+
315
+ def onmessage(data)
316
+ @handler.key(@key).ws_message(data) unless @handler.nil?
317
+ end
318
+
319
+ def onclose
320
+ @handler.key(@key).ws_close() unless @handler.nil?
321
+ end
322
+ end #}}}
323
+
324
+ end
325
+
326
+ end
327
+ end
328
+ end