QWebChannel 2019.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/QWebChannel.rb +137 -0
- data/lib/QWebChannel/HearchIndexEntry_pb.rb +19 -0
- data/lib/QWebChannel/MulticastHandler.rb +27 -0
- data/lib/QWebChannel/QObject.rb +214 -0
- data/lib/QWebChannel/QSignal.rb +31 -0
- metadata +68 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: ce07be00157d3eee912b213bf18e2b92d1448aa8
|
4
|
+
data.tar.gz: 5084ac99eceb709a464ff0fafe5045fc9c0ec65c
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: cdb5fb1f2450cf76ed90094b43e3fdc3acd65a76f89fe3c610dd8c7a1d993ebf889045ebd584aa76a499bd7eda394e1b66ff4dbb3f854175d364058d156d5c78
|
7
|
+
data.tar.gz: 784b99bf85a8d6c6f3a191ade87623ad2da6cf35f885aa5ada5b7f20383eee0f6383e5d16ee297485ea40394090ef9fe7af5f243a9133f04398d1f0968be893a
|
data/lib/QWebChannel.rb
ADDED
@@ -0,0 +1,137 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.expand_path('../QWebChannel', __FILE__)
|
4
|
+
|
5
|
+
# require 'Hearch/HearchIndexEntry_pb'
|
6
|
+
require 'QWebChannel/QSignal'
|
7
|
+
require 'QWebChannel/QObject'
|
8
|
+
require 'set'
|
9
|
+
require 'oj' #optimized json
|
10
|
+
require 'json' #json解析库。
|
11
|
+
|
12
|
+
module QWebChannelMessageTypes
|
13
|
+
SIGNAL=1
|
14
|
+
PROPERTYUPDATE=2
|
15
|
+
INIT=3
|
16
|
+
IDLE=4
|
17
|
+
DEBUG=5
|
18
|
+
INVOKEMETHOD=6
|
19
|
+
CONNECTTOSIGNAL=7
|
20
|
+
DISCONNECTFROMSIGNAL=8
|
21
|
+
SETPROPERTY=9
|
22
|
+
RESPONSE=10
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
class QWebChannel
|
27
|
+
attr_reader :execId
|
28
|
+
attr_writer :execId
|
29
|
+
attr_reader :execCallbacks
|
30
|
+
attr_writer :execCallbacks
|
31
|
+
attr_reader :transport
|
32
|
+
attr_writer :transport
|
33
|
+
attr_reader :objects
|
34
|
+
attr_writer :objects
|
35
|
+
|
36
|
+
def send(data)
|
37
|
+
if ( !( data.is_a?(String) ) )
|
38
|
+
data=Oj.dump(data)
|
39
|
+
end
|
40
|
+
|
41
|
+
puts "Sending: #{data}"
|
42
|
+
|
43
|
+
@channel.transport.send(data)
|
44
|
+
end
|
45
|
+
|
46
|
+
def exec(data, &block)
|
47
|
+
if !(block_given?)
|
48
|
+
@channel.send(data)
|
49
|
+
end
|
50
|
+
|
51
|
+
@channel.execId=@channel.execId+1
|
52
|
+
data['id']=@channel.execId
|
53
|
+
|
54
|
+
puts "data id: #{data['id']}"
|
55
|
+
|
56
|
+
@channel.execCallbacks[data['id']]=block
|
57
|
+
@channel.send(data)
|
58
|
+
end
|
59
|
+
|
60
|
+
def handleResponse(message)
|
61
|
+
@channel.execCallbacks[message['id']].call(message['data'])
|
62
|
+
|
63
|
+
@channel.execCallbacks[message['id']]=nil
|
64
|
+
end
|
65
|
+
|
66
|
+
def handleSignal(message)
|
67
|
+
object=@channel.objects[message['object']]
|
68
|
+
|
69
|
+
if (object)
|
70
|
+
object.signalEmitted(message['signal'], message['args'])
|
71
|
+
end
|
72
|
+
end #def handleSignal(message)
|
73
|
+
|
74
|
+
|
75
|
+
def initialize(websocket, &block)
|
76
|
+
@index = nil #索引对象。
|
77
|
+
@execId=0
|
78
|
+
@execCallbacks={}
|
79
|
+
@objects={}
|
80
|
+
|
81
|
+
@transport=websocket
|
82
|
+
@channel = self
|
83
|
+
|
84
|
+
|
85
|
+
@transport.onmessage do |msg, type|
|
86
|
+
# puts "Received message: #{msg}"
|
87
|
+
|
88
|
+
puts "msg type: #{msg.class}"
|
89
|
+
|
90
|
+
data =msg.to_s
|
91
|
+
|
92
|
+
puts "data: #{data}"
|
93
|
+
|
94
|
+
if (data.is_a?(String))
|
95
|
+
data=JSON.parse(data)
|
96
|
+
end
|
97
|
+
|
98
|
+
puts "type: #{data.class}"
|
99
|
+
|
100
|
+
case(data['type'])
|
101
|
+
when QWebChannelMessageTypes::SIGNAL
|
102
|
+
@channel.handleSignal(data)
|
103
|
+
when QWebChannelMessageTypes::RESPONSE
|
104
|
+
@channel.handleResponse(data)
|
105
|
+
when QWebChannelMessageTypes::PROPERTYUPDATE
|
106
|
+
@channel.handlePropertyUpdate(data)
|
107
|
+
else
|
108
|
+
puts("Invalid message arrived: #{data}")
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
|
113
|
+
@channel.exec({'type' => QWebChannelMessageTypes::INIT}) do |data|
|
114
|
+
|
115
|
+
puts "data type: #{data.class}"
|
116
|
+
puts "data content: #{data}"
|
117
|
+
|
118
|
+
data.each do |objectName, objectContent|
|
119
|
+
puts "objectName type: #{objectName.class}"
|
120
|
+
|
121
|
+
object=QObject.new(objectName, data[objectName], @channel)
|
122
|
+
end
|
123
|
+
|
124
|
+
@channel.objects.each do |objectName, objectObject|
|
125
|
+
@channel.objects[objectName].unwrapProperties()
|
126
|
+
end
|
127
|
+
|
128
|
+
|
129
|
+
puts "Self: #{self}"
|
130
|
+
yield(self)
|
131
|
+
|
132
|
+
|
133
|
+
@channel.exec({ "type" => QWebChannelMessageTypes::IDLE})
|
134
|
+
end #@channel.exec({'type' => QWebChannelMessageTypes::INIT}) do |data|
|
135
|
+
end #def initialize(websocket, &block)
|
136
|
+
|
137
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
2
|
+
# source: HearchIndexEntry.proto
|
3
|
+
|
4
|
+
require 'google/protobuf'
|
5
|
+
|
6
|
+
Google::Protobuf::DescriptorPool.generated_pool.build do
|
7
|
+
add_message "com.stupidbeauty.hearch.HearchIndexEntry" do
|
8
|
+
optional :keyword, :string, 1
|
9
|
+
repeated :articleId, :int32, 2
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module Com
|
14
|
+
module Stupidbeauty
|
15
|
+
module Hearch
|
16
|
+
HearchIndexEntry = Google::Protobuf::DescriptorPool.generated_pool.lookup("com.stupidbeauty.hearch.HearchIndexEntry").msgclass
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'eventmachine'
|
4
|
+
require 'ipaddr'
|
5
|
+
|
6
|
+
class MulticastHandler < EventMachine::Connection
|
7
|
+
def castData(packageString)
|
8
|
+
multicastHost = '239.173.40.5' #组播组主机地址。
|
9
|
+
multicastPort = 11500 #组播组端口。
|
10
|
+
|
11
|
+
# print("castData\n") #Debug.
|
12
|
+
# send_data(packageString)
|
13
|
+
send_datagram(packageString, multicastHost, multicastPort) #发送组播数据包。
|
14
|
+
end
|
15
|
+
|
16
|
+
def receive_data(data)
|
17
|
+
# puts data
|
18
|
+
end
|
19
|
+
|
20
|
+
def post_init
|
21
|
+
# print("post_init\n") #Debug.
|
22
|
+
port, host = Socket::unpack_sockaddr_in( get_sockname() )
|
23
|
+
ip = IPAddr.new( host ).hton + IPAddr.new("0.0.0.0").hton
|
24
|
+
set_sock_opt( Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, ip )
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
@@ -0,0 +1,214 @@
|
|
1
|
+
class QObject
|
2
|
+
attr_accessor :__propertyCache__
|
3
|
+
attr_accessor :__id__
|
4
|
+
attr_accessor :__objectSignals__
|
5
|
+
attr_accessor :webChannel
|
6
|
+
|
7
|
+
def unwrapQObject(response)
|
8
|
+
puts "response class: #{response.class}" #debug
|
9
|
+
if (response.is_a?(Array))
|
10
|
+
ret = []
|
11
|
+
|
12
|
+
response.each do |responseI|
|
13
|
+
ret << @object.unwrapQObject(responseI)
|
14
|
+
end
|
15
|
+
|
16
|
+
return ret
|
17
|
+
end #if (response.is_a?(Array))
|
18
|
+
|
19
|
+
|
20
|
+
if (!response || response.is_a?(Fixnum) || response.is_a?(TrueClass) || !response["__QObject*__"] || response.id == nil)
|
21
|
+
return response
|
22
|
+
end
|
23
|
+
|
24
|
+
objectId=response.id
|
25
|
+
|
26
|
+
if (@webChannel.objects[objectId])
|
27
|
+
return @webChannel.objects[objectId]
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
qObject=QObject.new(objectId, response.data, @webChannel)
|
32
|
+
|
33
|
+
qObject.destroyed.connect() do
|
34
|
+
if (@webChannel.objects[objectId]==qObject)
|
35
|
+
@webChannel.objects.delete(objectId)
|
36
|
+
|
37
|
+
propertyNames=[]
|
38
|
+
|
39
|
+
qObject.each do |propertyName|
|
40
|
+
propertyNames << propertyName
|
41
|
+
end
|
42
|
+
|
43
|
+
propertyNames.each do |propertyName|
|
44
|
+
qObject.delete(propertyName)
|
45
|
+
end
|
46
|
+
end #if (@webChannel.objects[objectId]==qObject)
|
47
|
+
end #qObject.destroyed.connect() do
|
48
|
+
|
49
|
+
qObject.unwrapProperties()
|
50
|
+
|
51
|
+
return qObject
|
52
|
+
end #def unwrapQObject(response)
|
53
|
+
|
54
|
+
def unwrapProperties()
|
55
|
+
@object.__propertyCache__.each do |propertyIdx, propertyObject|
|
56
|
+
@object.__propertyCache__[propertyIdx]=@object.unwrapQObject(@object.__propertyCache__[propertyIdx])
|
57
|
+
end
|
58
|
+
end #def unwrapProperties()
|
59
|
+
|
60
|
+
def []=(signalName, signalObject)
|
61
|
+
@signalNameObjectHash[signalName]=signalObject
|
62
|
+
end #def []=(signalName, signalObject)
|
63
|
+
|
64
|
+
def [](signalName)
|
65
|
+
@signalNameObjectHash[signalName]
|
66
|
+
end #def [](signalName)
|
67
|
+
|
68
|
+
def bindGetterSetter(propertyInfo)
|
69
|
+
propertyIndex=propertyInfo[0]
|
70
|
+
propertyName=propertyInfo[1]
|
71
|
+
notifySignalData=propertyInfo[2]
|
72
|
+
|
73
|
+
@object.__propertyCache__[propertyIndex]=propertyInfo[3]
|
74
|
+
|
75
|
+
if (notifySignalData)
|
76
|
+
if (notifySignalData[0] == 1)
|
77
|
+
notifySignalData[0]=propertyName+"Changed"
|
78
|
+
end
|
79
|
+
addSignal(notifySignalData, true)
|
80
|
+
end #if (notifySignalData)
|
81
|
+
|
82
|
+
defineProperty(propertyName) #定义属性。对应于Object.defineProperty.
|
83
|
+
end #def bindGetterSetter(propertyInfo)
|
84
|
+
|
85
|
+
def defineProperty(propertyName)
|
86
|
+
# define_property_by_prototype(propertyName)
|
87
|
+
|
88
|
+
|
89
|
+
#getter
|
90
|
+
# self.class_eval( " def #{attr_name}; @#{attr_name}; end " )
|
91
|
+
self.instance_eval %Q{
|
92
|
+
def #{propertyName}
|
93
|
+
@object.__propertyCache__[propertyIndex]
|
94
|
+
end
|
95
|
+
}
|
96
|
+
|
97
|
+
#setter
|
98
|
+
self.instance_eval %Q{
|
99
|
+
def #{propertyName}=(val)
|
100
|
+
|
101
|
+
@object.__propertyCache__[propertyIndex]=val
|
102
|
+
|
103
|
+
valueToSend=val
|
104
|
+
|
105
|
+
if (valueToSend.is_a?(QObject) && @webChannel.objects[valueToSend.__id__] != nil)
|
106
|
+
valueToSend={"id" => valueToSend.__id__}
|
107
|
+
|
108
|
+
@webChannel.exec( {"type" => QWebChannelMessageTypes::SETPROPERTY, "object" => @object.__id__ , "property" => propertyIndex, "value" => valueToSend } )
|
109
|
+
end
|
110
|
+
|
111
|
+
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
}
|
117
|
+
|
118
|
+
end #def defineProperty(propertyName)
|
119
|
+
|
120
|
+
def invokeSignalCallbacks(signalName, signalArgs)
|
121
|
+
connections=@object.__objectSignals__[signalName]
|
122
|
+
|
123
|
+
if (connections) #存在连接。
|
124
|
+
connections.each do |callback| #一个个连接地处理。
|
125
|
+
callback.call(*signalArgs) #抹平数组。
|
126
|
+
end #connections.each do |callback| #一个个连接地处理。
|
127
|
+
end #if (connections)
|
128
|
+
end #def invokeSignalCallbacks(signalName, signalArgs)
|
129
|
+
|
130
|
+
def signalEmitted(signalName, signalArgs)
|
131
|
+
puts "signalArgs: #{signalArgs}" #debug.
|
132
|
+
invokeSignalCallbacks(signalName, self.unwrapQObject(signalArgs))
|
133
|
+
end #def signalEmitted(signalName, signalArgs)
|
134
|
+
|
135
|
+
def addSignal(signalData, isPropertyNotifySignal)
|
136
|
+
signalName=signalData[0]
|
137
|
+
signalIndex=signalData[1]
|
138
|
+
|
139
|
+
@object[signalName]=QSignal.new(signalName, signalIndex, @object, isPropertyNotifySignal) #添加信号。
|
140
|
+
end #def addSignal(signalData, isPropertyNotifySignal)
|
141
|
+
|
142
|
+
def addMethod(methodData)
|
143
|
+
methodName=methodData[0]
|
144
|
+
methodIdx=methodData[1]
|
145
|
+
|
146
|
+
@object.define_singleton_method(methodName) do |*arguments|
|
147
|
+
args=[]
|
148
|
+
callback=nil
|
149
|
+
|
150
|
+
arguments.each do |argument|
|
151
|
+
puts "argument class: #{argument.class}" #debug.
|
152
|
+
if (argument.is_a?(Proc))
|
153
|
+
callback=argument
|
154
|
+
elsif ( (argument.is_a?(QObject)) && (@webChannel.objects[argument.__id__] !=nil ) )
|
155
|
+
args << ({"id" => argument.__id__})
|
156
|
+
else
|
157
|
+
args << argument
|
158
|
+
end
|
159
|
+
end #arguments.each do |argument|
|
160
|
+
|
161
|
+
puts "__id__: #{@object.__id__}" #debug.
|
162
|
+
|
163
|
+
|
164
|
+
@webChannel.exec({ "type" => QWebChannelMessageTypes::INVOKEMETHOD, "object" => @object.__id__, "method" => methodIdx, "args" => args }) do |response|
|
165
|
+
if (response!=nil)
|
166
|
+
result = @object.unwrapQObject(response)
|
167
|
+
|
168
|
+
if (callback)
|
169
|
+
callback.call(result)
|
170
|
+
end
|
171
|
+
end #if (response!=nil)
|
172
|
+
end #@webChannel.exec() do |response|
|
173
|
+
|
174
|
+
|
175
|
+
end #@object.define_singleton_method(methodName) do |*arguments|
|
176
|
+
end #def addMethod(methodData)
|
177
|
+
|
178
|
+
def initialize(name, data, webChannel)
|
179
|
+
@signalNameObjectHash={} #信号名字与信号对象的映射。
|
180
|
+
@__id__=name
|
181
|
+
@webChannel=webChannel
|
182
|
+
webChannel.objects[name]=self
|
183
|
+
|
184
|
+
puts "__id__: #{@__id__}" #debug.
|
185
|
+
|
186
|
+
|
187
|
+
@__objectSignals__ = {}
|
188
|
+
|
189
|
+
@__propertyCache__ = {}
|
190
|
+
|
191
|
+
@object=self
|
192
|
+
|
193
|
+
data['methods'].each do |method|
|
194
|
+
puts "current method: #{method}" #debug
|
195
|
+
addMethod(method)
|
196
|
+
end
|
197
|
+
|
198
|
+
data['properties'].each do |property|
|
199
|
+
bindGetterSetter(property)
|
200
|
+
end
|
201
|
+
|
202
|
+
data['signals'].each do |signal|
|
203
|
+
addSignal(signal, false)
|
204
|
+
end
|
205
|
+
|
206
|
+
puts "enums: #{data['enums']}" #Debug.
|
207
|
+
|
208
|
+
if data['enums']
|
209
|
+
data['enums'].each do |name|
|
210
|
+
@object[name]=data['enums'][name]
|
211
|
+
end #data['enums'].each do |name|
|
212
|
+
end #if data['enums']
|
213
|
+
end
|
214
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
class QSignal
|
2
|
+
def initialize(signalName, signalIndex, object, isPropertyNotifySignal)
|
3
|
+
@signalName=signalName
|
4
|
+
@signalIndex=signalIndex
|
5
|
+
@object=object
|
6
|
+
@webChannel=@object.webChannel
|
7
|
+
@isPropertyNotifySignal=isPropertyNotifySignal
|
8
|
+
end
|
9
|
+
|
10
|
+
def connect(callback)
|
11
|
+
@object.__objectSignals__[@signalIndex]=@object.__objectSignals__[@signalIndex] || []
|
12
|
+
@object.__objectSignals__[@signalIndex] << callback
|
13
|
+
|
14
|
+
if (!@isPropertyNotifySignal && @signalName!= "destroyed")
|
15
|
+
@webChannel.exec( { "type" => QWebChannelMessageTypes::CONNECTTOSIGNAL, "object" => @object.__id__, "signal" => @signalIndex } )
|
16
|
+
end
|
17
|
+
end #def connect(callback)
|
18
|
+
|
19
|
+
def disconnect(callback)
|
20
|
+
@object.__objectSignals__[signalIndex]=@object.__objectSignals__[signalIndex] || []
|
21
|
+
idx=@object.__objectSignals__[signalIndex].indexOf(callback)
|
22
|
+
|
23
|
+
|
24
|
+
@object.__objectSignals__[signalIndex].delete_at(idx)
|
25
|
+
|
26
|
+
if (!isPropertyNotifySignal && @object.__objectSignals__[signalIndex].length == 0)
|
27
|
+
@webChannel.exec( { "type" => QWebChannelMessageTypes::DISCONNECTFROMSIGNAL, "object" => @object.__id__, "signal" => signalIndex } )
|
28
|
+
end #if (!isPropertyNotifySignal && @object.__objectSignals__[signalIndex].length == 0)
|
29
|
+
end #def disconnect(callback)
|
30
|
+
end #class QSignal
|
31
|
+
|
metadata
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: QWebChannel
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2019.1.4
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Hxcan Cai
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-01-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: websocket-eventmachine-client
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.2'
|
20
|
+
- - ">="
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.2.0
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - "~>"
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.2'
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.2.0
|
33
|
+
description: QWebChannel ruby. Work with QWebChannel in pure ruby.
|
34
|
+
email: caihuosheng@gmail.com
|
35
|
+
executables: []
|
36
|
+
extensions: []
|
37
|
+
extra_rdoc_files: []
|
38
|
+
files:
|
39
|
+
- lib/QWebChannel.rb
|
40
|
+
- lib/QWebChannel/HearchIndexEntry_pb.rb
|
41
|
+
- lib/QWebChannel/MulticastHandler.rb
|
42
|
+
- lib/QWebChannel/QObject.rb
|
43
|
+
- lib/QWebChannel/QSignal.rb
|
44
|
+
homepage: http://rubygems.org/gems/QWebChannel
|
45
|
+
licenses:
|
46
|
+
- MIT
|
47
|
+
metadata: {}
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options: []
|
50
|
+
require_paths:
|
51
|
+
- lib
|
52
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
53
|
+
requirements:
|
54
|
+
- - ">="
|
55
|
+
- !ruby/object:Gem::Version
|
56
|
+
version: '0'
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
requirements: []
|
63
|
+
rubyforge_project:
|
64
|
+
rubygems_version: 2.5.2.3
|
65
|
+
signing_key:
|
66
|
+
specification_version: 4
|
67
|
+
summary: QWebChannel ruby.
|
68
|
+
test_files: []
|