mumble-ruby2 1.1.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,48 @@
1
+ module Mumble
2
+ class Channel < Model
3
+ attribute :channel_id do
4
+ self.data.fetch('channel_id', 0)
5
+ end
6
+ attribute :name
7
+ attribute :parent_id do
8
+ self.data['parent']
9
+ end
10
+ attribute :links do
11
+ self.data.fetch('links', [])
12
+ end
13
+
14
+ def parent
15
+ client.channels[parent_id]
16
+ end
17
+
18
+ def children
19
+ client.channels.values.select do |channel|
20
+ channel.parent_id == channel_id
21
+ end
22
+ end
23
+
24
+ def linked_channels
25
+ links.map do |channel_id|
26
+ client.channels[channel_id]
27
+ end
28
+ end
29
+
30
+ def users
31
+ client.users.values.select do |user|
32
+ user.channel_id == channel_id
33
+ end
34
+ end
35
+
36
+ def join
37
+ client.join_channel(self)
38
+ end
39
+
40
+ def send_text(string)
41
+ client.text_channel(self, string)
42
+ end
43
+
44
+ def send_image(file)
45
+ client.text_channel_img(self, file)
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,218 @@
1
+ require 'hashie'
2
+
3
+ module Mumble
4
+ class ChannelNotFound < StandardError; end
5
+ class UserNotFound < StandardError; end
6
+ class NoSupportedCodec < StandardError; end
7
+
8
+ class Client
9
+ include ThreadTools
10
+ attr_reader :users, :channels
11
+
12
+ CODEC_OPUS = 4
13
+
14
+ def initialize(host, port=64738, username="RubyClient", password="")
15
+ @users, @channels = {}, {}
16
+ @callbacks = Hash.new { |h, k| h[k] = [] }
17
+
18
+ @config = Mumble.configuration.dup.tap do |c|
19
+ c.host = host
20
+ c.port = port
21
+ c.username = username
22
+ c.password = password
23
+ end
24
+ yield(@config) if block_given?
25
+ end
26
+
27
+ def connect
28
+ @conn = Connection.new @config.host, @config.port, cert_manager
29
+ @conn.connect
30
+
31
+ init_callbacks
32
+ version_exchange
33
+ authenticate
34
+
35
+ spawn_threads :read, :ping
36
+ connected? # just to get a nice return value
37
+ end
38
+
39
+ def disconnect
40
+ kill_threads
41
+ @conn.disconnect
42
+ @connected = false
43
+ end
44
+
45
+ def connected?
46
+ @connected ||= false
47
+ end
48
+
49
+ def cert_manager
50
+ @cert_manager ||= CertManager.new @config.username, @config.ssl_cert_opts
51
+ end
52
+
53
+ def recorder
54
+ raise NoSupportedCodec unless @codec
55
+ @recorder ||= AudioRecorder.new self, @config.sample_rate
56
+ end
57
+
58
+ def player
59
+ raise NoSupportedCodec unless @codec
60
+ @audio_streamer ||= AudioPlayer.new @codec, @conn, @config.sample_rate, @config.bitrate
61
+ end
62
+
63
+ def me
64
+ users[@session]
65
+ end
66
+
67
+ def set_comment(comment="")
68
+ send_user_state(comment: comment)
69
+ end
70
+
71
+ def join_channel(channel)
72
+ id = channel_id channel
73
+ send_user_state(session: @session, channel_id: id)
74
+ channels[id]
75
+ end
76
+
77
+ def move_user(user, channel)
78
+ cid = channel_id channel
79
+ uid = user_session user
80
+ send_user_state(session: uid, channel_id: cid)
81
+ channels[cid]
82
+ end
83
+
84
+ def text_user(user, string)
85
+ session = user_session user
86
+ send_text_message(session: [user_session(user)], message: string)
87
+ users[session]
88
+ end
89
+
90
+ def text_user_img(user, file)
91
+ text_user(user, ImgReader.msg_from_file(file))
92
+ end
93
+
94
+ def text_channel(channel, string)
95
+ id = channel_id channel
96
+ send_text_message(channel_id: [id], message: string)
97
+ channels[id]
98
+ end
99
+
100
+ def text_channel_img(channel, file)
101
+ text_channel(channel, ImgReader.msg_from_file(file))
102
+ end
103
+
104
+ def find_user(name)
105
+ users.values.find { |u| u.name == name }
106
+ end
107
+
108
+ def find_channel(name)
109
+ channels.values.find { |c| c.name == name }
110
+ end
111
+
112
+ def on_connected(&block)
113
+ @callbacks[:connected] << block
114
+ end
115
+
116
+ def remove_callback(symbol, callback)
117
+ @callbacks[symbol].delete callback
118
+ end
119
+
120
+ Messages.all_types.each do |msg_type|
121
+ define_method "on_#{msg_type}" do |&block|
122
+ @callbacks[msg_type] << block
123
+ end
124
+
125
+ define_method "send_#{msg_type}" do |opts|
126
+ @conn.send_message(msg_type, opts)
127
+ end
128
+ end
129
+
130
+ private
131
+ def read
132
+ message = @conn.read_message
133
+ sym = message.class.to_s.demodulize.underscore.to_sym
134
+ run_callbacks sym, Hashie::Mash.new(message.to_hash)
135
+ end
136
+
137
+ def ping
138
+ send_ping timestamp: Time.now.to_i
139
+ sleep(20)
140
+ end
141
+
142
+ def run_callbacks(sym, *args)
143
+ @callbacks[sym].each { |c| c.call *args }
144
+ end
145
+
146
+ def init_callbacks
147
+ on_server_sync do |message|
148
+ @session = message.session
149
+ @connected = true
150
+ @callbacks[:connected].each { |c| c.call }
151
+ end
152
+ on_channel_state do |message|
153
+ if channel = channels[message.channel_id]
154
+ channel.update message.to_hash
155
+ else
156
+ channels[message.channel_id] = Channel.new(self, message.to_hash)
157
+ end
158
+ end
159
+ on_channel_remove do |message|
160
+ channels.delete(message.channel_id)
161
+ end
162
+ on_user_state do |message|
163
+ if user = users[message.session]
164
+ user.update(message.to_hash)
165
+ else
166
+ users[message.session] = User.new(self, message.to_hash)
167
+ end
168
+ end
169
+ on_user_remove do |message|
170
+ users.delete(message.session)
171
+ end
172
+ on_codec_version do |message|
173
+ codec_negotiation(message)
174
+ end
175
+ end
176
+
177
+ def version_exchange
178
+ send_version({
179
+ version: encode_version(1, 2, 10),
180
+ release: "mumble-ruby2 #{Mumble::VERSION}",
181
+ os: %x{uname -s}.strip,
182
+ os_version: %x{uname -v}.strip
183
+ })
184
+ end
185
+
186
+ def authenticate
187
+ send_authenticate({
188
+ username: @config.username,
189
+ password: @config.password,
190
+ opus: true
191
+ })
192
+ end
193
+
194
+ def codec_negotiation(message)
195
+ @codec = CODEC_OPUS if message.opus
196
+ end
197
+
198
+ def channel_id(channel)
199
+ channel = find_channel(channel) if channel.is_a? String
200
+ id = channel.respond_to?(:channel_id) ? channel.channel_id : channel
201
+
202
+ raise ChannelNotFound unless @channels.has_key? id
203
+ id
204
+ end
205
+
206
+ def user_session(user)
207
+ user = find_user(user) if user.is_a? String
208
+ id = user.respond_to?(:session) ? user.session : user
209
+
210
+ raise UserNotFound unless @users.has_key? id
211
+ id
212
+ end
213
+
214
+ def encode_version(major, minor, patch)
215
+ (major << 16) | (minor << 8) | (patch & 0xFF)
216
+ end
217
+ end
218
+ end
@@ -0,0 +1,85 @@
1
+ require 'socket'
2
+ require 'openssl'
3
+ require 'thread'
4
+
5
+ module Mumble
6
+ class Connection
7
+ def initialize(host, port, cert_manager)
8
+ @host = host
9
+ @port = port
10
+ @cert_manager = cert_manager
11
+ @write_lock = Mutex.new
12
+ end
13
+
14
+ def connect
15
+ context = OpenSSL::SSL::SSLContext.new(:TLSv1)
16
+ context.verify_mode = OpenSSL::SSL::VERIFY_NONE
17
+ [:key, :cert].each { |s| context.send("#{s}=", @cert_manager.send(s)) }
18
+ tcp_sock = TCPSocket.new @host, @port
19
+ @sock = OpenSSL::SSL::SSLSocket.new tcp_sock, context
20
+ @sock.connect
21
+ end
22
+
23
+ def disconnect
24
+ @sock.close
25
+ end
26
+
27
+ def read_message
28
+ header = read_data 6
29
+ type, len = header.unpack Messages::HEADER_FORMAT
30
+ data = read_data len
31
+ if type == message_type(:udp_tunnel)
32
+ # UDP Packet -- No Protobuf
33
+ message = message_class(:udp_tunnel).new
34
+ message.packet = data
35
+ else
36
+ message = message_raw type, data
37
+ end
38
+ message
39
+ end
40
+
41
+ def send_udp_packet(packet)
42
+ header = [message_type(:udp_tunnel), packet.length].pack Messages::HEADER_FORMAT
43
+ send_data(header + packet)
44
+ end
45
+
46
+ def send_message(sym, attrs)
47
+ type, klass = message(sym)
48
+ message = klass.new
49
+ attrs.each { |k, v| message.send("#{k}=", v) }
50
+ serial = message.serialize_to_string
51
+ header = [type, serial.size].pack Messages::HEADER_FORMAT
52
+ send_data(header + serial)
53
+ end
54
+
55
+ private
56
+ def send_data(data)
57
+ @write_lock.synchronize do
58
+ @sock.write data
59
+ end
60
+ end
61
+
62
+ def read_data(len)
63
+ @sock.read len
64
+ end
65
+
66
+ def message(obj)
67
+ return message_type(obj), message_class(obj)
68
+ end
69
+
70
+ def message_type(obj)
71
+ if obj.is_a? Protobuf::Message
72
+ obj = obj.class.to_s.demodulize.underscore.to_sym
73
+ end
74
+ Messages.sym_to_type(obj)
75
+ end
76
+
77
+ def message_class(obj)
78
+ Messages.type_to_class(message_type(obj))
79
+ end
80
+
81
+ def message_raw(type, data)
82
+ Messages.raw_to_obj(type, data)
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,37 @@
1
+ require 'base64'
2
+
3
+ module Mumble
4
+ class UnsupportedImgFormat < StandardError
5
+ def initialize
6
+ super "Image format must be one of the following: #{ImgReader::FORMATS}"
7
+ end
8
+ end
9
+
10
+ class ImgTooLarge < StandardError
11
+ def initialize
12
+ super "Image must be smaller than 128 kB"
13
+ end
14
+ end
15
+
16
+ class ImgReader
17
+ class << self
18
+ FORMATS = %w(png jpg jpeg svg)
19
+
20
+ def msg_from_file(file)
21
+ @@file = file
22
+ @@ext = File.extname(@@file)[1..-1]
23
+ validate_file
24
+
25
+ data = File.read @@file
26
+ "<img src='data:image/#{@@ext};base64,#{Base64.encode64(data)}'/>"
27
+ end
28
+
29
+ private
30
+ def validate_file
31
+ raise LoadError.new("#{@@file} not found") unless File.exists? @@file
32
+ raise UnsupportedImgFormat unless FORMATS.include? @@ext
33
+ raise ImgTooLarge unless File.size(@@file) <= 128 * 1024
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,361 @@
1
+ ### Generated by rprotoc. DO NOT EDIT!
2
+ ### <proto file: mumble.proto>
3
+
4
+ require 'protobuf/message/message'
5
+ require 'protobuf/message/enum'
6
+ require 'protobuf/message/service'
7
+ require 'protobuf/message/extend'
8
+
9
+ module Mumble
10
+ module Messages
11
+ ::Protobuf::OPTIONS[:"optimize_for"] = :SPEED
12
+ HEADER_FORMAT = "nN"
13
+
14
+ @@sym_to_type = {
15
+ version: 0,
16
+ udp_tunnel: 1,
17
+ authenticate: 2,
18
+ ping: 3,
19
+ reject: 4,
20
+ server_sync: 5,
21
+ channel_remove: 6,
22
+ channel_state: 7,
23
+ user_remove: 8,
24
+ user_state: 9,
25
+ ban_list: 10,
26
+ text_message: 11,
27
+ permission_denied: 12,
28
+ acl: 13,
29
+ query_users: 14,
30
+ crypt_setup: 15,
31
+ context_action_add: 16,
32
+ context_action: 17,
33
+ user_list: 18,
34
+ voice_target: 19,
35
+ permission_query: 20,
36
+ codec_version: 21,
37
+ user_stats: 22,
38
+ request_blob: 23,
39
+ server_config: 24,
40
+ suggest_config: 25
41
+ }
42
+
43
+ @@type_to_sym = @@sym_to_type.invert
44
+
45
+ class << self
46
+ def all_types
47
+ return @@sym_to_type.keys
48
+ end
49
+
50
+ def sym_to_type(sym)
51
+ @@sym_to_type[sym]
52
+ end
53
+
54
+ def type_to_class(type)
55
+ const_get(@@type_to_sym[type].to_s.camelcase)
56
+ end
57
+
58
+ def raw_to_obj(type, data)
59
+ message = type_to_class(type).new
60
+ message.parse_from_string(data)
61
+ message
62
+ end
63
+ end
64
+
65
+ class Version < ::Protobuf::Message
66
+ defined_in __FILE__
67
+ optional :uint32, :version, 1
68
+ optional :string, :release, 2
69
+ optional :string, :os, 3
70
+ optional :string, :os_version, 4
71
+ end
72
+ class UdpTunnel < ::Protobuf::Message
73
+ defined_in __FILE__
74
+ required :bytes, :packet, 1
75
+ end
76
+ class Authenticate < ::Protobuf::Message
77
+ defined_in __FILE__
78
+ optional :string, :username, 1
79
+ optional :string, :password, 2
80
+ repeated :string, :tokens, 3
81
+ repeated :int32, :celt_versions, 4
82
+ optional :bool, :opus, 5, :default => false
83
+ end
84
+ class Ping < ::Protobuf::Message
85
+ defined_in __FILE__
86
+ optional :uint64, :timestamp, 1
87
+ optional :uint32, :good, 2
88
+ optional :uint32, :late, 3
89
+ optional :uint32, :lost, 4
90
+ optional :uint32, :resync, 5
91
+ optional :uint32, :udp_packets, 6
92
+ optional :uint32, :tcp_packets, 7
93
+ optional :float, :udp_ping_avg, 8
94
+ optional :float, :udp_ping_var, 9
95
+ optional :float, :tcp_ping_avg, 10
96
+ optional :float, :tcp_ping_var, 11
97
+ end
98
+ class Reject < ::Protobuf::Message
99
+ defined_in __FILE__
100
+ class RejectType < ::Protobuf::Enum
101
+ defined_in __FILE__
102
+ None = value(:None, 0)
103
+ WrongVersion = value(:WrongVersion, 1)
104
+ InvalidUsername = value(:InvalidUsername, 2)
105
+ WrongUserPW = value(:WrongUserPW, 3)
106
+ WrongServerPW = value(:WrongServerPW, 4)
107
+ UsernameInUse = value(:UsernameInUse, 5)
108
+ ServerFull = value(:ServerFull, 6)
109
+ NoCertificate = value(:NoCertificate, 7)
110
+ end
111
+ optional :RejectType, :type, 1
112
+ optional :string, :reason, 2
113
+ end
114
+ class ServerConfig < ::Protobuf::Message
115
+ defined_in __FILE__
116
+ optional :uint32, :max_bandwidth, 1
117
+ optional :string, :welcome_text, 2
118
+ optional :bool, :allow_html, 3
119
+ optional :uint32, :message_length, 4
120
+ optional :uint32, :image_message_length, 5
121
+ end
122
+ class ServerSync < ::Protobuf::Message
123
+ defined_in __FILE__
124
+ optional :uint32, :session, 1
125
+ optional :uint32, :max_bandwidth, 2
126
+ optional :string, :welcome_text, 3
127
+ optional :uint64, :permissions, 4
128
+ end
129
+ class SuggestConfig < ::Protobuf::Message
130
+ defined_in __FILE__
131
+ optional :uint32, :version, 1
132
+ optional :bool, :positional, 2
133
+ optional :bool, :push_to_talk, 3
134
+ end
135
+ class ChannelRemove < ::Protobuf::Message
136
+ defined_in __FILE__
137
+ required :uint32, :channel_id, 1
138
+ end
139
+ class ChannelState < ::Protobuf::Message
140
+ defined_in __FILE__
141
+ optional :uint32, :channel_id, 1
142
+ optional :uint32, :parent, 2
143
+ optional :string, :name, 3
144
+ repeated :uint32, :links, 4
145
+ optional :string, :description, 5
146
+ repeated :uint32, :links_add, 6
147
+ repeated :uint32, :links_remove, 7
148
+ optional :bool, :temporary, 8, :default => false
149
+ optional :int32, :position, 9, :default => 0
150
+ optional :bytes, :description_hash, 10
151
+ end
152
+ class UserRemove < ::Protobuf::Message
153
+ defined_in __FILE__
154
+ required :uint32, :session, 1
155
+ optional :uint32, :actor, 2
156
+ optional :string, :reason, 3
157
+ optional :bool, :ban, 4
158
+ end
159
+ class UserState < ::Protobuf::Message
160
+ defined_in __FILE__
161
+ optional :uint32, :session, 1
162
+ optional :uint32, :actor, 2
163
+ optional :string, :name, 3
164
+ optional :uint32, :user_id, 4
165
+ optional :uint32, :channel_id, 5
166
+ optional :bool, :mute, 6
167
+ optional :bool, :deaf, 7
168
+ optional :bool, :suppress, 8
169
+ optional :bool, :self_mute, 9
170
+ optional :bool, :self_deaf, 10
171
+ optional :bytes, :texture, 11
172
+ optional :bytes, :plugin_context, 12
173
+ optional :string, :plugin_identity, 13
174
+ optional :string, :comment, 14
175
+ optional :string, :hash, 15
176
+ optional :bytes, :comment_hash, 16
177
+ optional :bytes, :texture_hash, 17
178
+ optional :bool, :priority_speaker, 18
179
+ optional :bool, :recording, 19
180
+ end
181
+ class BanList < ::Protobuf::Message
182
+ defined_in __FILE__
183
+ class BanEntry < ::Protobuf::Message
184
+ defined_in __FILE__
185
+ required :bytes, :address, 1
186
+ required :uint32, :mask, 2
187
+ optional :string, :name, 3
188
+ optional :string, :hash, 4
189
+ optional :string, :reason, 5
190
+ optional :string, :start, 6
191
+ optional :uint32, :duration, 7
192
+ end
193
+ repeated :BanEntry, :bans, 1
194
+ optional :bool, :query, 2, :default => false
195
+ end
196
+ class TextMessage < ::Protobuf::Message
197
+ defined_in __FILE__
198
+ optional :uint32, :actor, 1
199
+ repeated :uint32, :session, 2
200
+ repeated :uint32, :channel_id, 3
201
+ repeated :uint32, :tree_id, 4
202
+ required :string, :message, 5
203
+ end
204
+ class PermissionDenied < ::Protobuf::Message
205
+ defined_in __FILE__
206
+ class DenyType < ::Protobuf::Enum
207
+ defined_in __FILE__
208
+ Text = value(:Text, 0)
209
+ Permission = value(:Permission, 1)
210
+ SuperUser = value(:SuperUser, 2)
211
+ ChannelName = value(:ChannelName, 3)
212
+ TextTooLong = value(:TextTooLong, 4)
213
+ H9K = value(:H9K, 5)
214
+ TemporaryChannel = value(:TemporaryChannel, 6)
215
+ MissingCertificate = value(:MissingCertificate, 7)
216
+ UserName = value(:UserName, 8)
217
+ ChannelFull = value(:ChannelFull, 9)
218
+ NestingLimit = value(:NestingLimit, 10)
219
+ end
220
+ optional :uint32, :permission, 1
221
+ optional :uint32, :channel_id, 2
222
+ optional :uint32, :session, 3
223
+ optional :string, :reason, 4
224
+ optional :DenyType, :type, 5
225
+ optional :string, :name, 6
226
+ end
227
+ class Acl < ::Protobuf::Message
228
+ defined_in __FILE__
229
+ class ChanGroup < ::Protobuf::Message
230
+ defined_in __FILE__
231
+ required :string, :name, 1
232
+ optional :bool, :inherited, 2, :default => true
233
+ optional :bool, :inherit, 3, :default => true
234
+ optional :bool, :inheritable, 4, :default => true
235
+ repeated :uint32, :add, 5
236
+ repeated :uint32, :remove, 6
237
+ repeated :uint32, :inherited_members, 7
238
+ end
239
+ class ChanACL < ::Protobuf::Message
240
+ defined_in __FILE__
241
+ optional :bool, :apply_here, 1, :default => true
242
+ optional :bool, :apply_subs, 2, :default => true
243
+ optional :bool, :inherited, 3, :default => true
244
+ optional :uint32, :user_id, 4
245
+ optional :string, :group, 5
246
+ optional :uint32, :grant, 6
247
+ optional :uint32, :deny, 7
248
+ end
249
+ required :uint32, :channel_id, 1
250
+ optional :bool, :inherit_acls, 2, :default => true
251
+ repeated :ChanGroup, :groups, 3
252
+ repeated :ChanACL, :acls, 4
253
+ optional :bool, :query, 5, :default => false
254
+ end
255
+ class QueryUsers < ::Protobuf::Message
256
+ defined_in __FILE__
257
+ repeated :uint32, :ids, 1
258
+ repeated :string, :names, 2
259
+ end
260
+ class CryptSetup < ::Protobuf::Message
261
+ defined_in __FILE__
262
+ optional :bytes, :key, 1
263
+ optional :bytes, :client_nonce, 2
264
+ optional :bytes, :server_nonce, 3
265
+ end
266
+ class ContextActionModify < ::Protobuf::Message
267
+ defined_in __FILE__
268
+ class Context < ::Protobuf::Enum
269
+ defined_in __FILE__
270
+ Server = value(:Server, 1)
271
+ Channel = value(:Channel, 2)
272
+ User = value(:User, 4)
273
+ end
274
+ class Operation < ::Protobuf::Enum
275
+ defined_in __FILE__
276
+ Add = value(:Add, 0)
277
+ Remove = value(:Remove, 1)
278
+ end
279
+ required :string, :action, 1
280
+ optional :string, :text, 2
281
+ optional :uint32, :context, 3
282
+ optional :Operation, :operation, 4
283
+ end
284
+ class ContextAction < ::Protobuf::Message
285
+ defined_in __FILE__
286
+ optional :uint32, :session, 1
287
+ optional :uint32, :channel_id, 2
288
+ required :string, :action, 3
289
+ end
290
+ class UserList < ::Protobuf::Message
291
+ defined_in __FILE__
292
+ class User < ::Protobuf::Message
293
+ defined_in __FILE__
294
+ required :uint32, :user_id, 1
295
+ optional :string, :name, 2
296
+ end
297
+ repeated :User, :users, 1
298
+ end
299
+ class VoiceTarget < ::Protobuf::Message
300
+ defined_in __FILE__
301
+ class Target < ::Protobuf::Message
302
+ defined_in __FILE__
303
+ repeated :uint32, :session, 1
304
+ optional :uint32, :channel_id, 2
305
+ optional :string, :group, 3
306
+ optional :bool, :links, 4, :default => false
307
+ optional :bool, :children, 5, :default => false
308
+ end
309
+ optional :uint32, :id, 1
310
+ repeated :Target, :targets, 2
311
+ end
312
+ class PermissionQuery < ::Protobuf::Message
313
+ defined_in __FILE__
314
+ optional :uint32, :channel_id, 1
315
+ optional :uint32, :permissions, 2
316
+ optional :bool, :flush, 3, :default => false
317
+ end
318
+ class CodecVersion < ::Protobuf::Message
319
+ defined_in __FILE__
320
+ required :int32, :alpha, 1
321
+ required :int32, :beta, 2
322
+ required :bool, :prefer_alpha, 3, :default => true
323
+ optional :bool, :opus, 4, :default => false
324
+ end
325
+ class UserStats < ::Protobuf::Message
326
+ defined_in __FILE__
327
+ class Stats < ::Protobuf::Message
328
+ defined_in __FILE__
329
+ optional :uint32, :good, 1
330
+ optional :uint32, :late, 2
331
+ optional :uint32, :lost, 3
332
+ optional :uint32, :resync, 4
333
+ end
334
+ optional :uint32, :session, 1
335
+ optional :bool, :stats_only, 2, :default => false
336
+ repeated :bytes, :certificates, 3
337
+ optional :Stats, :from_client, 4
338
+ optional :Stats, :from_server, 5
339
+ optional :uint32, :udp_packets, 6
340
+ optional :uint32, :tcp_packets, 7
341
+ optional :float, :udp_ping_avg, 8
342
+ optional :float, :udp_ping_var, 9
343
+ optional :float, :tcp_ping_avg, 10
344
+ optional :float, :tcp_ping_var, 11
345
+ optional :Version, :version, 12
346
+ repeated :int32, :celt_versions, 13
347
+ optional :bytes, :address, 14
348
+ optional :uint32, :bandwidth, 15
349
+ optional :uint32, :onlinesecs, 16
350
+ optional :uint32, :idlesecs, 17
351
+ optional :bool, :strong_certificate, 18, :default => false
352
+ optional :bool, :opus, 19, :default => false
353
+ end
354
+ class RequestBlob < ::Protobuf::Message
355
+ defined_in __FILE__
356
+ repeated :uint32, :session_texture, 1
357
+ repeated :uint32, :session_comment, 2
358
+ repeated :uint32, :channel_description, 3
359
+ end
360
+ end
361
+ end