datawire_mdk 2.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.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b898e0f72fd506802a43a6ad9972043b933c2092
4
+ data.tar.gz: 126e7d6be42af520468d4477cca660a0a11d4160
5
+ SHA512:
6
+ metadata.gz: 8f29db7b0ab84f7c5b02d3e827b9c1a752a9870d082d1fe93360d9205e43fa82152a5e8d0641e8eabf44999c935c9d661dbd74b2807a8feafb11d775c07ab3fb
7
+ data.tar.gz: cba352b068fdb7558d57ef6f40b43c49abf443e305dc40dae8a10b9fdbb3216e614bb252ee4ba558f81c0ba67106643920e74e4c3578fe1dc8c30ceb4e4e9901
@@ -0,0 +1,1213 @@
1
+ module DatawireQuarkCore
2
+ require 'net/http'
3
+ require 'uri'
4
+ require 'json'
5
+ require 'thread'
6
+
7
+ require 'concurrent'
8
+ require 'celluloid/current'
9
+ require 'reel'
10
+ require 'logging'
11
+ require 'event_emitter'
12
+ require 'securerandom'
13
+
14
+ module GettersSetters
15
+ # Generate Java/Quark-style getters and setters for
16
+ # instance variables.
17
+ #
18
+ # Example:
19
+ #
20
+ # class Foo
21
+ # extend GettersSetters
22
+ #
23
+ # getters :fooBar, :bazQux
24
+ # setters :fooBar
25
+ # end
26
+ #
27
+ # The above equivalent to:
28
+ #
29
+ # class Foo
30
+ # extend GettersAndSetters
31
+ #
32
+ # def getFooBar
33
+ # @fooBar
34
+ # end
35
+ #
36
+ # def getBazQux
37
+ # @bazQux
38
+ # end
39
+ #
40
+ # def setFooBar(value)
41
+ # @fooBar = value
42
+ #
43
+ # nil
44
+ # end
45
+ # end
46
+
47
+ def getters(*names)
48
+ names.each do |name|
49
+ define_method('get' + capitalize(name)) do
50
+ instance_variable_get("@#{name}")
51
+ end
52
+ end
53
+ end
54
+
55
+ def setters(*names)
56
+ names.each do |name|
57
+ define_method('set' + capitalize(name)) do |value|
58
+ instance_variable_set("@#{name}", value)
59
+
60
+ nil
61
+ end
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ def capitalize(string)
68
+ string[0].upcase + string[1..-1]
69
+ end
70
+ end
71
+
72
+ module Static
73
+ Unassigned = Class.new
74
+
75
+ def unlazy_statics
76
+ names = _lazy_statics
77
+ # puts "unlazying #{self.name} fields #{names}"
78
+ names.each do |name|
79
+ self.send(name)
80
+ end
81
+ end
82
+ def _lazy_statics
83
+ lazy = :@_lazy_statics
84
+ if not self.instance_variable_defined? lazy
85
+ # puts "Bootstrap #{self.name}"
86
+ l = self.instance_variable_set(lazy, {:__owner__ => self.name})
87
+ else
88
+ l = self.instance_variable_get(lazy)
89
+ end
90
+ if not l.has_key? self.name
91
+ o = l[:__owner__]
92
+ # puts "Adding slot for #{self.name} to lazy of #{o}"
93
+ l[self.name] = []
94
+ end
95
+ l[self.name]
96
+ end
97
+ def static(pairs)
98
+ pairs.each do |name, default|
99
+ _lazy_statics << name
100
+ self.instance_variable_set("@#{name}", Unassigned)
101
+
102
+ define_singleton_method(name) do
103
+ value = self.instance_variable_get("@#{name}")
104
+
105
+ if value == Unassigned
106
+ value = default.call
107
+ self.instance_variable_set("@#{name}", value)
108
+ end
109
+
110
+ value
111
+ end
112
+
113
+ define_singleton_method("#{name}=") do |value|
114
+ self.instance_variable_set("@#{name}", value)
115
+ end
116
+
117
+ define_method(name) do
118
+ self.class.send(name)
119
+ end
120
+
121
+ define_method("#{name}=") do |value|
122
+ self.class.send("#{name}=", value)
123
+ end
124
+ end
125
+ end
126
+ end
127
+
128
+ def self.print(message)
129
+ Kernel.print message == nil ? 'null' : message, "\n"
130
+ end
131
+
132
+ def self.urlencode(hash)
133
+ URI.encode_www_form hash
134
+ end
135
+
136
+ def self.split(string, separator)
137
+ return ['', ''] if string == separator
138
+ result = string.split(separator)
139
+ result = result + [''] if string.end_with? separator
140
+
141
+ result
142
+ end
143
+
144
+ def self.getFileContents(path, result)
145
+ begin
146
+ result.value = File.read(path, {"encoding": "UTF-8"})
147
+ result.finish(nil)
148
+ rescue => ex
149
+ result.finish(::Quark.quark.os.OSError.new(ex.message))
150
+ end
151
+ end
152
+
153
+ def self._getClass obj
154
+ clz = __getClass obj
155
+ # puts "runtime _getClass for #{obj} is #{clz}"
156
+ clz
157
+ end
158
+ def self.__getClass obj
159
+ return nil if obj.nil?
160
+ return "quark.bool" if (obj == true) or (obj == false)
161
+ return "quark.String" if obj.is_a? String
162
+ return "quark.int" if obj.is_a? Fixnum
163
+ return "quark.float" if obj.is_a? Float
164
+ return "quark.List<quark.Object>" if obj.is_a? Array
165
+ return "quark.Map<quark.Object,quark.Object>" if obj.is_a? Hash
166
+ if obj.respond_to? "_getClass" then
167
+ return obj._getClass
168
+ else
169
+ return "quark.Object"
170
+ end
171
+ end
172
+
173
+ class QuarkObject
174
+
175
+ def to_s
176
+ return self.toString() if self.respond_to? :toString
177
+ return super()
178
+ end
179
+
180
+ end
181
+
182
+ class List < Array
183
+ def to_s
184
+ '[' + map(&:to_s).join(', ') + ']'
185
+ end
186
+ end
187
+
188
+ class JSONObject
189
+ attr_accessor :value
190
+
191
+ def initialize(value=nil)
192
+ @value = value
193
+ end
194
+
195
+ def self.parse(json)
196
+ new JSON.parse("[#{json}]")[0]
197
+ end
198
+
199
+ def ==(other)
200
+ not other.nil? and value == other.value
201
+ end
202
+
203
+ def toString
204
+ value.to_json
205
+ end
206
+
207
+ def size
208
+ isList || isObject ? value.size : 1
209
+ end
210
+
211
+ def getType
212
+ case @value
213
+ when Hash
214
+ 'object'
215
+ when Array
216
+ 'list'
217
+ when String
218
+ 'string'
219
+ when Numeric
220
+ 'number'
221
+ when true, false
222
+ 'bool'
223
+ when nil
224
+ 'null'
225
+ else
226
+ raise RuntimeError, "Unknown JSONObject type #{@value.inspect}"
227
+ end
228
+ end
229
+
230
+ def set(value)
231
+ @value = value
232
+
233
+ self
234
+ end
235
+
236
+ # Object
237
+
238
+ def isObject
239
+ value.is_a? Hash
240
+ end
241
+
242
+ def setObject
243
+ @value = {}
244
+
245
+ self
246
+ end
247
+
248
+ def getObjectItem(key)
249
+ return undefined unless isObject and value.key? key
250
+
251
+ self.class.new value[key]
252
+ end
253
+
254
+ def setObjectItem(key, item)
255
+ setObject unless isObject
256
+ value[key] = item.value
257
+
258
+ self
259
+ end
260
+
261
+ def keys
262
+ return undefined unless isObject
263
+
264
+ List.new value.keys
265
+ end
266
+
267
+ # List
268
+
269
+ def isList
270
+ value.is_a? Array
271
+ end
272
+
273
+ def setList
274
+ @value = List.new
275
+
276
+ self
277
+ end
278
+
279
+ def getListItem(index)
280
+ return undefined unless isList and (0...size).include? index
281
+
282
+ self.class.new value[index]
283
+ end
284
+
285
+ def setListItem(index, item)
286
+ setList unless isList
287
+ value[index] = item.value
288
+
289
+ self
290
+ end
291
+
292
+ # String
293
+
294
+ def isString
295
+ value.is_a? String
296
+ end
297
+
298
+ def getString
299
+ return nil unless isString
300
+
301
+ value
302
+ end
303
+
304
+ alias_method :setString, :set
305
+
306
+ # Number
307
+
308
+ def isNumber
309
+ value.is_a? Numeric
310
+ end
311
+
312
+ def getNumber
313
+ return nil unless isNumber
314
+
315
+ value
316
+ end
317
+
318
+ alias_method :setNumber, :set
319
+
320
+ # Bool
321
+
322
+ def getBool
323
+ return nil unless isBool
324
+
325
+ value
326
+ end
327
+
328
+ def isBool
329
+ [true, false].include? value
330
+ end
331
+
332
+ alias_method :setBool, :set
333
+
334
+ # Null
335
+
336
+ def isNull
337
+ value == nil
338
+ end
339
+
340
+ def setNull
341
+ @value = nil
342
+
343
+ self
344
+ end
345
+
346
+ # Undefined
347
+
348
+ UNDEFINED = Class.new
349
+
350
+ def isUndefined
351
+ UNDEFINED.equal? value
352
+ end
353
+
354
+ def isDefined
355
+ not isUndefined
356
+ end
357
+
358
+ def undefined
359
+ self.class.new UNDEFINED
360
+ end
361
+ end
362
+
363
+ module HTTP
364
+ class Base
365
+ def setHeader(key, value)
366
+ @headers[key.downcase] = value
367
+
368
+ nil
369
+ end
370
+
371
+ def getHeader(key)
372
+ @headers[key.downcase]
373
+ end
374
+
375
+ def getHeaders
376
+ @headers.keys
377
+ end
378
+ end
379
+
380
+ class Request < Base
381
+ extend GettersSetters
382
+
383
+ getters :body, :method, :url
384
+ setters :body, :method
385
+
386
+ def initialize(url)
387
+ @url = url
388
+ @method = 'GET'
389
+ @body = nil
390
+ @headers = {}
391
+ end
392
+ end
393
+
394
+ class Response < Base
395
+ extend GettersSetters
396
+
397
+ getters :code, :body
398
+ setters :code, :body
399
+
400
+ def initialize
401
+ @code = 500
402
+ @body = ''
403
+ @headers = {}
404
+ @responded = false
405
+ end
406
+ end
407
+ end
408
+
409
+ class Sources
410
+ def initialize()
411
+ @sources = Concurrent::Map.new
412
+ @seq = Concurrent::AtomicFixnum.new
413
+ @log = Logger.new "quark.runtime.sources"
414
+ end
415
+
416
+ def add (topic)
417
+ key = "%s-%s" % [ @seq.increment, topic ]
418
+ @sources.put_if_absent(key, Time.new)
419
+ key
420
+ end
421
+
422
+ def remove (key)
423
+ @sources.delete(key)
424
+ end
425
+
426
+ def empty?
427
+ @sources.empty?
428
+ end
429
+
430
+ def explain
431
+ @sources.each_key { |k|
432
+ @log.trace "Waiting for %s from %s" % [k, @sources[k]]
433
+ }
434
+ end
435
+ end
436
+
437
+
438
+ if not Logging.initialized?
439
+ Logging.init %w(trace debug info warn error fatal)
440
+ end
441
+ class QuarkLayout < ::Logging::Layout
442
+ def initialize
443
+ @namecache = {}
444
+ end
445
+ def format( event )
446
+ level = ::Logging::LNAMES[event.level].upcase
447
+ topic = topic_of(event)
448
+ obj = format_obj(event.data)
449
+ sprintf("%s %s %s\n", level, topic, obj)
450
+ end
451
+ def topic_of(event)
452
+ name = event.logger
453
+ topic = @namecache[name]
454
+ if topic.nil?
455
+ @namecache[name] = topic = name.gsub("::",".")
456
+ end
457
+ topic
458
+ end
459
+ end
460
+
461
+ def self.configureLogging(appender, level)
462
+ root = Logging.logger["quark"]
463
+ if appender.name == ":STDOUT"
464
+ app = Logging.appenders.stdout
465
+ elsif appender.name == ":STDERR"
466
+ app = Logging.appenders.stderr
467
+ else
468
+ app = Logging.appenders.file(appender.name)
469
+ end
470
+ app.layout = QuarkLayout.new
471
+ root.appenders = app
472
+ root.level = level
473
+ end
474
+
475
+ class Logger
476
+ extend Forwardable
477
+ @@init = false
478
+ def initialize(topic)
479
+ @log = Logging.logger["quark::" + topic.gsub(".","::")]
480
+ end
481
+ if Logging.level_num(:trace).nil?
482
+ def_delegator :@log, :debug, :trace
483
+ else
484
+ def_delegator :@log, :trace, :trace
485
+ end
486
+ def_delegators :@log, :debug, :info, :warn, :error
487
+ end
488
+
489
+ class Eventor
490
+ def initialize(runtime)
491
+ @executor = Concurrent::SingleThreadExecutor.new
492
+ @timers = Concurrent::TimerSet.new(:executor => @executor)
493
+ @sources = Sources.new
494
+ @runtime = runtime
495
+ at_exit { wait_for_sources }
496
+ @log = Logger.new "quark.runtime"
497
+ end
498
+
499
+ attr_reader :runtime
500
+
501
+ def add(source)
502
+ @sources.add source
503
+ end
504
+
505
+ def event(final:nil, &block)
506
+ @executor.post { execute(final, block) }
507
+ end
508
+
509
+ def execute(final, block)
510
+ begin
511
+ block.call()
512
+ rescue => ex
513
+ puts "aieee", ex, ex.backtrace
514
+ @log.error ex
515
+ ensure
516
+ @sources.remove final if final
517
+ end
518
+ end
519
+
520
+ def schedule(delay, &block)
521
+ @timers.post(delay, &block)
522
+ end
523
+
524
+ def wait_for_sources
525
+ last = Time.new - 10
526
+ delta = 1
527
+ while not @sources.empty?
528
+ now = Time.new
529
+ if now - last > delta
530
+ @sources.explain
531
+ last = now
532
+ if delta < 60
533
+ delta = delta * 1.41
534
+ end
535
+ end
536
+ sleep 0.1
537
+ end
538
+ rescue Interrupt
539
+ #@log.warn "Interrupted"
540
+ end
541
+
542
+ end
543
+
544
+ class Runtime
545
+ def initialize()
546
+ @events = Eventor.new self
547
+ @log = Logger.new "quark.runtime"
548
+ @servers = Servers.new(@events)
549
+ end
550
+ def schedule(task, delay)
551
+ src = @events.add "timer"
552
+ @events.schedule(delay) { @events.event(final:src) { task.onExecute self } }
553
+ end
554
+ def request(request, handler)
555
+ src = @events.add "http request"
556
+ t = Thread.new do
557
+ begin
558
+ url = request.getUrl
559
+ @events.event { handler.onHTTPInit url }
560
+ headers = {}
561
+ request.getHeaders.each { |k| headers[k] = request.getHeader k }
562
+ uri = URI(url)
563
+ req = Net::HTTPGenericRequest.new(request.getMethod.upcase, 1, 1, uri, headers)
564
+ req.body = request.getBody
565
+ res = Net::HTTP.start(uri.host, uri.port,
566
+ :use_ssl => uri.scheme == 'https') do | http |
567
+ http.request(req)
568
+ end
569
+ response = HTTP::Response.new
570
+ response.setCode(res.code.to_i)
571
+ response.setBody(res.body)
572
+ @events.event { handler.onHTTPResponse request, response }
573
+ rescue Exception => e
574
+ #@log.warn "EXCEPTION: #{e.inspect}"
575
+ #@log.warn "MESSAGE: #{e.message}"
576
+ @events.event { handler.onHTTPError request, ::Quark.quark.HTTPError.new(e.message) }
577
+ ensure
578
+ @events.event(final:src) { handler.onHTTPFinal request }
579
+ end
580
+ end
581
+ end
582
+
583
+ def serveHTTP(url, servlet)
584
+ @servers.add(HTTPAdapter.new(url, servlet, @events))
585
+ end
586
+
587
+ def serveWS(url, servlet)
588
+ @servers.add(WSAdapter.new(url, servlet, @events))
589
+ end
590
+
591
+ def respond(request, response)
592
+ if request.rs == response
593
+ request.respond :http_response
594
+ else
595
+ request.fail! 500, "servlet failed to pair up request and response\r\n"
596
+ end
597
+ end
598
+
599
+ def open(url, handler)
600
+ begin
601
+ src = @events.add "ws client"
602
+ client = WebsocketClient.new(url)
603
+ sock = WebsocketAdapter.new(client)
604
+ events = @events
605
+ events.event { handler.onWSInit(sock) }
606
+ client.on_client(:open) do |wsevt|
607
+ # puts "open"
608
+ sock.opened = true
609
+ events.event { handler.onWSConnected(sock) }
610
+ end
611
+ client.on_client(:message) do |wsevt|
612
+ # puts "message"
613
+ case wsevt.data
614
+ when Array then
615
+ buffer = Buffer.new(wsevt.data.pack("C*"))
616
+ events.event { handler.onWSBinary(sock, buffer) }
617
+ when String then
618
+ events.event { handler.onWSMessage(sock, wsevt.data) }
619
+ end
620
+ end
621
+ client.on_client(:close) do |wsevt|
622
+ # puts "close"
623
+ if sock.opened
624
+ events.event { handler.onWSClosed(sock) }
625
+ end
626
+ events.event(final:src) { handler.onWSFinal(sock) }
627
+ end
628
+ client.on_client(:error) do |wsevt|
629
+ # puts self
630
+ events.event { handler.onWSError(sock, ::Quark.quark.WSError.new(wsevt.message)) }
631
+ end
632
+ client.issues.on(:start_failed) do |err|
633
+ events.event { handler.onWSError(sock, ::Quark.quark.WSError.new(err.to_s)) }
634
+ events.event(final:src) { handler.onWSFinal(sock) }
635
+ end
636
+ Thread.new { client.run }
637
+ rescue ::Exception => err
638
+ puts "AIEEE", err, err.backtrace
639
+ end
640
+ end
641
+
642
+ def fail(message)
643
+ @log.error message
644
+ exit! 1
645
+ end
646
+
647
+ def logger(topic)
648
+ return Logger.new topic
649
+ end
650
+
651
+ def codec
652
+ return Codec.new
653
+ end
654
+
655
+ def now
656
+ (Time.now.to_f * 1000).round
657
+ end
658
+
659
+ def sleep(seconds)
660
+ Kernel.sleep seconds
661
+ end
662
+
663
+ def uuid
664
+ SecureRandom.uuid
665
+ end
666
+
667
+ def callSafely(unary_callable, default)
668
+ begin
669
+ ::Quark.quark.callUnaryCallable(unary_callable, nil)
670
+ rescue
671
+ @log.error("Exception while calling safely: #{$!}")
672
+ default
673
+ end
674
+ end
675
+ end
676
+
677
+ class WebsocketAdapter
678
+ attr_accessor :opened
679
+ def initialize(client)
680
+ @client = client
681
+ @opened = false
682
+ end
683
+
684
+ def send (message)
685
+ @client.text message
686
+ end
687
+
688
+ def sendBinary (message)
689
+ @client.binary message.data
690
+ end
691
+
692
+ def close
693
+ @client.close
694
+ end
695
+ end
696
+
697
+ class WebscketIssues
698
+ include EventEmitter
699
+ end
700
+ class WebsocketClient
701
+ extend Forwardable
702
+ def initialize(url)
703
+ @url = url
704
+ @client = ::WebSocket::Driver.client(self)
705
+ @issues = WebscketIssues.new
706
+ end
707
+ attr_reader :url
708
+
709
+
710
+ def issues
711
+ @issues
712
+ end
713
+
714
+ def run
715
+ begin
716
+ uri = URI(url)
717
+ port = uri.port || (uri.scheme == "ws" ? 80 : 443)
718
+ tcp = Celluloid::IO::TCPSocket.new(uri.host, port)
719
+ if uri.scheme == "wss"
720
+ @socket = Celluloid::IO::SSLSocket.new(tcp)
721
+ @socket.connect
722
+ else
723
+ @socket = tcp
724
+ end
725
+ @client.start
726
+ rescue ::Exception => err
727
+ @issues.emit(:start_failed, err)
728
+ else
729
+ loop do
730
+ begin
731
+ @client.parse(@socket.readpartial(1024))
732
+ rescue EOFError
733
+ break
734
+ end
735
+ end
736
+ end
737
+ end
738
+
739
+ def_delegators :@client, :text, :binary, :ping, :close, :protocol
740
+ def_delegator :@client, :on, :on_client
741
+
742
+ def write(buffer)
743
+ @socket.write buffer
744
+ end
745
+
746
+ end
747
+
748
+ class IncomingRequest < HTTP::Request
749
+ attr_accessor :rs
750
+ attr_accessor :fut
751
+ attr_accessor :request
752
+ attr_accessor :svr
753
+ attr_accessor :action
754
+ attr_accessor :ws_handler
755
+
756
+ def fail! (code, body)
757
+ @rs.setCode(code)
758
+ @rs.setBody(body)
759
+ respond :http_response
760
+ end
761
+
762
+ def respond(action)
763
+ @svr.respond(self, action)
764
+ end
765
+ end
766
+
767
+ class Servers
768
+ include Celluloid
769
+ def initialize(events)
770
+ @servers = {}
771
+ @events= events
772
+ end
773
+ def add(adapter)
774
+ if not adapter.scheme_supported?
775
+ error = "${adapter.uri.scheme} is not supported"
776
+ @events.event { adapter.servlet.onServletError(adapter.url, ::Quark.quark.ServletError.new(error)) }
777
+ return
778
+ end
779
+ if adapter.secure?
780
+ error = "${adapter.uri.scheme} is not yet supported"
781
+ @events.event { adapter.servlet.onServletError(adapter.url, ::Quark.quark.ServletError.new(error)) }
782
+ return
783
+ end
784
+ server = @servers[adapter.key]
785
+ if server.nil?
786
+ if adapter.secure?
787
+ server = HTTPSServer.new(adapter.uri.hostname, adapter.uri.port, @events)
788
+ else
789
+ server = HTTPServer.new(adapter.uri.hostname, adapter.uri.port, @events)
790
+ end
791
+ # in case the port was 0 this will mutate the #effective_url, and #key of adapter
792
+ adapter.uri.port = server.local_address.ip_port
793
+ @servers[adapter.key] = server
794
+ end
795
+ server.add(adapter)
796
+ end
797
+ end
798
+
799
+ class Adapter
800
+ def initialize(url, servlet, events)
801
+ @url = url
802
+ @uri = URI(url)
803
+ @servlet = servlet
804
+ @events = events
805
+ end
806
+ attr_reader :servlet, :uri, :url
807
+ attr_accessor :source
808
+
809
+ def scheme_supported?
810
+ self.schemes.values.include? @uri.scheme
811
+ end
812
+
813
+ def secure?
814
+ self.schemes[:secure] == @uri.scheme
815
+ end
816
+
817
+ def key
818
+ "#{@uri.host}:#{@uri.port}"
819
+ end
820
+
821
+ def effective_url
822
+ @uri.to_s
823
+ end
824
+
825
+ end
826
+
827
+ class HTTPAdapter < Adapter
828
+ def schemes
829
+ {plain: "http", secure: "https"}
830
+ end
831
+
832
+ def process_request(rq)
833
+ if rq.request.websocket?
834
+ rq.fail! 400, "http here, move along\r\n"
835
+ else
836
+ @events.event { servlet.onHTTPRequest(rq, rq.rs) }
837
+ end
838
+ end
839
+
840
+ def process_response(rq)
841
+ end
842
+ end
843
+
844
+ class ServerWebsocketAdapter
845
+ def initialize(sock)
846
+ @sock = sock
847
+ end
848
+ def send (message)
849
+ @sock.write message
850
+ end
851
+
852
+ def sendBinary (message)
853
+ @sock.write message.data.unpack("C*")
854
+ end
855
+
856
+ def close
857
+ @sock.close
858
+ end
859
+ end
860
+
861
+ class WSAdapter < Adapter
862
+ def schemes
863
+ {plain: "ws", secure: "wss"}
864
+ end
865
+
866
+ def process_request(rq)
867
+ if rq.request.websocket?
868
+ @events.event { rq.ws_handler = servlet.onWSConnect(rq); rq.respond :detach }
869
+ else
870
+ rq.fail! 400, "websockets here, move along\r\n"
871
+ end
872
+ end
873
+ def process_response(rq)
874
+ if rq.ws_handler.nil?
875
+ rq.fail 403, "Forbidden\r\n"
876
+ else
877
+ websocket = rq.request.websocket
878
+ sock = ServerWebsocketAdapter.new(websocket)
879
+ handler = rq.ws_handler
880
+ src = @events.add ("server websocket")
881
+ events = @events
882
+ @events.event { handler.onWSInit(sock) }
883
+ @events.event { handler.onWSConnected(sock) }
884
+ websocket.on_close do |wsevent|
885
+ events.event { handler.onWSClosed(sock) }
886
+ events.event(final:src) { handler.onWSFinal(sock) }
887
+ end
888
+ websocket.on_error do |wsevt|
889
+ events.event { handler.onWSError(sock, ::Quark.quark.WSError.new(wsevt.message)) }
890
+ end
891
+ Thread.new do
892
+ while not websocket.closed?
893
+ data = websocket.read
894
+ case data
895
+ when Array then
896
+ buffer = Buffer.new(data.pack("C*"))
897
+ events.event { handler.onWSBinary(sock, buffer) }
898
+ when String then
899
+ events.event { handler.onWSMessage(sock, data) }
900
+ end
901
+ end
902
+ end
903
+ end
904
+ rescue => ex
905
+ puts "aieieie", ex
906
+ end
907
+ end
908
+
909
+ module MyServer
910
+ def initialize(host = "127.0.0.1", port = 3000, events)
911
+ super(host, port, &method(:on_connection))
912
+ @events = events
913
+ @paths = {}
914
+ @log = Logger.new "quark.runtime.server"
915
+ end
916
+
917
+
918
+ def local_address
919
+ Addrinfo.new(@server.getsockname)
920
+ end
921
+
922
+ def add(adapter)
923
+ old = @paths[adapter.uri.path]
924
+ if not adapter.nil?
925
+ @paths[adapter.uri.path] = adapter
926
+ adapter.source = @events.add(adapter.effective_url)
927
+ @events.event { adapter.servlet.onServletInit(adapter.effective_url, @events.runtime) }
928
+ end
929
+ if not old.nil?
930
+ # XXX: servlet is not quiesced
931
+ @events.event(final: adapter.source) { adapter.servlet.onServletFinal(adapter.effective_url) }
932
+ end
933
+ end
934
+
935
+ def on_connection(connection)
936
+ connection.each_request do |request|
937
+ begin
938
+ rq = IncomingRequest.new(request.url)
939
+ rq.setBody(request.body)
940
+ request.headers.each {|key, value| rq.setHeader(key, value)}
941
+ rq.setMethod(request.method)
942
+ rq.request = request
943
+ rq.rs = HTTP::Response.new
944
+ rq.fut = Celluloid::Condition.new
945
+ rq.svr = self
946
+ rq.action = :wait
947
+ adapter = @paths[request.uri.path]
948
+ if adapter.nil?
949
+ rq.fail! 404, "not found\r\n"
950
+ else
951
+ adapter.process_request(rq)
952
+ end
953
+ if rq.action == :wait
954
+ rq.fut.wait
955
+ end
956
+ adapter.process_response(rq)
957
+ case rq.action
958
+ when :http_response
959
+ http_response(rq)
960
+ when :detach
961
+ connection.detach
962
+ else
963
+ @log.error "Unknown action #{rq.action} for HTTP request"
964
+ rq.fail! 500, "quark runtime is confused, unknown http request action\r\n"
965
+ http_response(rq)
966
+ end
967
+ rescue => ex
968
+ @log.error ex
969
+ end
970
+ end
971
+ end
972
+
973
+ def http_response(rq)
974
+ rs = rq.rs
975
+ headers = {}
976
+ rs.getHeaders.each { |k| headers[k] = rs.getHeader k }
977
+ response = Reel::Response::new(rs.getCode, headers, rs.getBody)
978
+ rq.request.respond response
979
+ end
980
+
981
+ def respond(rq, action)
982
+ waiting = rq.action == :wait
983
+ rq.action = action
984
+ if waiting
985
+ # condition is race-free only in the context of the originating actor
986
+ rq.fut.signal
987
+ end
988
+ end
989
+ end
990
+
991
+ class HTTPServer < Reel::Server::HTTP
992
+ include MyServer
993
+ end
994
+
995
+ class HTTPSServer < Reel::Server::HTTPS
996
+ include MyServer
997
+ end
998
+
999
+
1000
+ HTTPRequest = HTTP::Request
1001
+
1002
+ class Servlet
1003
+ def onServletInit(url, rt)
1004
+ end
1005
+ def onServletError(url, error)
1006
+ end
1007
+ def onServletEnd(url)
1008
+ end
1009
+ end
1010
+
1011
+ class HTTPServlet < Servlet
1012
+ def onHTTPRequest(request, response)
1013
+ end
1014
+ end
1015
+
1016
+ class WSServlet < Servlet
1017
+ def onWSConnect(request)
1018
+ end
1019
+ end
1020
+
1021
+ def self.url_get(url)
1022
+ Net::HTTP.get(URI(url))
1023
+ end
1024
+
1025
+ def self.default_codec
1026
+ Codec.new
1027
+ end
1028
+
1029
+ def self.cast(value, &block)
1030
+ # For now there is no easy way to check in Ruby that Quark class C is
1031
+ # subclass of of Quark class B, so don't check anything until that's fixed.
1032
+ # The correct way to do so would be via reflect.Class.hasInstance, probably,
1033
+ # but that doesn't support interfaces yet.
1034
+ value
1035
+ end
1036
+
1037
+ class Mutex
1038
+ end
1039
+
1040
+ class Lock < Mutex
1041
+ def initialize
1042
+ @lock = ::Thread::Mutex.new
1043
+ end
1044
+
1045
+ def acquire
1046
+ if @lock.owned?
1047
+ fail "Illegal re-acquisition of a quark lock"
1048
+ end
1049
+ @lock.lock
1050
+ end
1051
+
1052
+ def release
1053
+ if !@lock.owned?
1054
+ fail "Illegal release of a not-acquired quark lock"
1055
+ end
1056
+ @lock.unlock
1057
+ end
1058
+
1059
+ private
1060
+
1061
+ def fail(reason)
1062
+ @log.fatal reason
1063
+ exit! 1 # XXX: we should go via Quark runtime, but need to develop a method to query it, Context is not yet exposed to the native code...
1064
+ end
1065
+ end
1066
+
1067
+ class Condition < Lock
1068
+ def initialize
1069
+ super
1070
+ @condition = ::Thread::ConditionVariable.new
1071
+ end
1072
+ def waitWakeup(timeout)
1073
+ if !@lock.owned?
1074
+ fail "Illegal waitWakeup of a not-acquired quark Condition"
1075
+ end
1076
+ @condition.wait(@lock, timeout / 1000.0)
1077
+ end
1078
+
1079
+ def wakeup
1080
+ if !@lock.owned?
1081
+ fail "Illegal wakeup of a not-acquired quark Condition"
1082
+ end
1083
+ @condition.signal
1084
+ end
1085
+ end
1086
+
1087
+ class TLS
1088
+ UNINITIALIZED = []
1089
+ private_constant :UNINITIALIZED
1090
+ def initialize(initializer)
1091
+ @initializer = initializer
1092
+ @var = Concurrent::ThreadLocalVar.new UNINITIALIZED
1093
+ end
1094
+
1095
+ def getValue
1096
+ value = @var.value
1097
+ if UNINITIALIZED.equal?(value)
1098
+ @var.value = value = @initializer.getValue
1099
+ end
1100
+ value
1101
+ end
1102
+
1103
+ def setValue(value)
1104
+ @var.value = value
1105
+ end
1106
+ end
1107
+
1108
+ class Codec
1109
+ ZERO = "\0".encode Encoding::ASCII_8BIT
1110
+ def buffer(size)
1111
+ Buffer.new ZERO * size
1112
+ end
1113
+
1114
+ def toHexdump(buffer, index, size, spaceScale)
1115
+ hex = buffer.data[index...index+size].unpack("H*")[0]
1116
+ (0...hex.size).each_slice(2**(spaceScale+1)).map {|i|
1117
+ hex[i[0]..i[-1]]
1118
+ }.join " "
1119
+ end
1120
+
1121
+ def toBase64(buffer, index, size)
1122
+ Base64.encode64(buffer.data[index...index+size]).strip
1123
+ end
1124
+
1125
+ def fromHexdump(value)
1126
+ value = value.split(" ").join
1127
+ if value[0...2].downcase == "0x"
1128
+ value[0...2] = ""
1129
+ end
1130
+ Buffer.new ((0...value.length).each_slice(2).map { |i|
1131
+ value[i[0]..i[1]].to_i(16)
1132
+ }.pack("C*"))
1133
+ end
1134
+
1135
+ def fromBase64(value)
1136
+ Buffer.new Base64.decode64 value
1137
+ end
1138
+ end
1139
+
1140
+ class Buffer
1141
+ BIN = Encoding::ASCII_8BIT
1142
+ UTF8 = Encoding::UTF_8
1143
+ module BE
1144
+ SHORT = "s>"
1145
+ INT = "l>"
1146
+ LONG = "q>"
1147
+ FLOAT = "G"
1148
+ end
1149
+ module LE
1150
+ SHORT = "s<"
1151
+ INT = "l<"
1152
+ LONG = "q<"
1153
+ FLOAT = "E"
1154
+ end
1155
+ attr_reader :data
1156
+ def initialize(data)
1157
+ @data = data.dup.force_encoding BIN
1158
+ @ord = BE
1159
+ end
1160
+ def capacity
1161
+ @data.length
1162
+ end
1163
+ def putStringUTF8(index, value)
1164
+ value = value.dup.force_encoding BIN
1165
+ len = value.length
1166
+ @data[index...index+len] = value
1167
+ len
1168
+ end
1169
+ def getStringUTF8(index, length)
1170
+ @data[index...index+length].force_encoding UTF8
1171
+ end
1172
+ def getByte(index)
1173
+ @data[index].bytes[0]
1174
+ end
1175
+ def putByte(index, value)
1176
+ @data[index] = [value].pack("C")
1177
+ end
1178
+ def littleEndian
1179
+ @ord = LE
1180
+ self
1181
+ end
1182
+ def getShort(index)
1183
+ @data[index..-1].unpack(@ord::SHORT)[0]
1184
+ end
1185
+ def putShort(index, value)
1186
+ @data[index...index+2] = [value].pack(@ord::SHORT)
1187
+ end
1188
+ def getInt(index)
1189
+ @data[index..-1].unpack(@ord::INT)[0]
1190
+ end
1191
+ def putInt(index, value)
1192
+ @data[index...index+4] = [value].pack(@ord::INT)
1193
+ end
1194
+ def getLong(index)
1195
+ @data[index..-1].unpack(@ord::LONG)[0]
1196
+ end
1197
+ def putLong(index, value)
1198
+ @data[index...index+8] = [value].pack(@ord::LONG)
1199
+ end
1200
+ def getFloat(index)
1201
+ @data[index..-1].unpack(@ord::FLOAT)[0]
1202
+ end
1203
+ def putFloat(index, value)
1204
+ @data[index...index+8] = [value].pack(@ord::FLOAT)
1205
+ end
1206
+ def getSlice(index, length)
1207
+ return Buffer.new(@data[index...index+length])
1208
+ end
1209
+ def inspect
1210
+ "Buffer(%s)" % Codec.new.toHexdump(self, 0, @data.length, 3)
1211
+ end
1212
+ end
1213
+ end