mumble-ruby2 1.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.
@@ -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