QWebChannel 2019.1.4
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 +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: []
|