minestat 3.0.0 → 3.0.1

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.
Files changed (6) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog.md +6 -0
  3. data/ReadMe.md +9 -5
  4. data/example.rb +1 -1
  5. data/lib/minestat.rb +84 -54
  6. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 82717df75838b6ad324792fe9a77d2546de09ac67d4f29df16d9d5ccdadc7b86
4
- data.tar.gz: ebc141d36e1e8873794c1c1f6945b77bdb3578a28ab04098b939725ba2af18a1
3
+ metadata.gz: e8a29b7c1a834e40e6a63b451abc0cd67018ca48b8efcdcd04a6ca365390cec0
4
+ data.tar.gz: 609d3ed8ccfdff65d6c317b25066012eeafb7e206dd347923088fe4108588add
5
5
  SHA512:
6
- metadata.gz: 1813f254761c46b13d6137fbe992e3deca495ecc3d02d134382970f47a968014806e2076f04ea7258fca05f27b88ae7aa0087de7f3ea1cc137d260694dccbc28
7
- data.tar.gz: 04c3aa462ab0ae42d822aa9b67290809c14a9789d7a9adc42a6c7c32bedfb6340e13ed9dc4528577fa1a176fe856ff43f470108acafec21eba5d996d42ccc8db
6
+ metadata.gz: 5b27f9e97df7fc7f2f38d0d18ae1f4c14015845ca0590cc8a33d269642697d41001c130ba36b6c7e0c39a5e39020b28b64bc02b78333ecfd1c3047a430d43555
7
+ data.tar.gz: f7e487a9a821c8b2aa83b8120c55eeb08b7229797bf6f62aff18937c4875db238ad88e3b6be08e6948303b79f74494d5ae60725fb9917d58729535d57aa33175
data/ChangeLog.md CHANGED
@@ -1,5 +1,11 @@
1
+ ## 3.0.1 (February 5, 2023)
2
+ - Added configurable DNS SRV resolution
3
+ - Added request type that attempts all SLP protocols
4
+ - Improved debug messages
5
+
1
6
  ## 3.0.0 (January 31, 2023)
2
7
  - Added UT3/GS4 query support
8
+ - Added debug mode
3
9
  - Refactored code
4
10
  - Added YARD documentation
5
11
 
data/ReadMe.md CHANGED
@@ -18,7 +18,7 @@ To install the gem: `gem install minestat`
18
18
  ```ruby
19
19
  require 'minestat'
20
20
 
21
- ms = MineStat.new("minecraft.frag.land", 25565)
21
+ ms = MineStat.new("frag.land")
22
22
  puts "Minecraft server status of #{ms.address} on port #{ms.port}:"
23
23
  if ms.online
24
24
  puts "Server is online running version #{ms.version} with #{ms.current_players} out of #{ms.max_players} players."
@@ -36,24 +36,28 @@ end
36
36
 
37
37
  To simply connect to an address:
38
38
  ```ruby
39
- ms = MineStat.new("minecraft.frag.land")
39
+ ms = MineStat.new("frag.land")
40
40
  ```
41
41
  Connect to an address on a certain TCP or UDP port:
42
42
  ```ruby
43
- ms = MineStat.new("minecraft.frag.land", 25567)
43
+ ms = MineStat.new("frag.land", 25565)
44
44
  ```
45
45
  Same as above example and additionally includes a timeout in seconds:
46
46
  ```ruby
47
- ms = MineStat.new("minecraft.frag.land", 25567, 3)
47
+ ms = MineStat.new("frag.land", 25565, 3)
48
48
  ```
49
49
  Same as above example and additionally includes an explicit protocol to use:
50
50
  ```ruby
51
- ms = MineStat.new("minecraft.frag.land", 25567, 3, MineStat::Request::QUERY)
51
+ ms = MineStat.new("frag.land", 25565, 3, MineStat::Request::QUERY)
52
52
  ```
53
53
  Connect to a Bedrock server and enable debug mode:
54
54
  ```ruby
55
55
  ms = MineStat.new("minecraft.frag.land", 19132, 3, MineStat::Request::BEDROCK, true)
56
56
  ```
57
+ Attempt all SLP protocols, disable debug mode, and disable DNS SRV resolution:
58
+ ```ruby
59
+ ms = MineStat.new("minecraft.frag.land", 25565, 3, MineStat::Request::SLP, false, false)
60
+ ```
57
61
 
58
62
  ### Support
59
63
  * Discord: https://discord.frag.land
data/example.rb CHANGED
@@ -2,7 +2,7 @@ require 'minestat'
2
2
 
3
3
  # Below is an example using the MineStat class.
4
4
  # If server is offline, other instance members will be nil.
5
- ms = MineStat.new("minecraft.frag.land")
5
+ ms = MineStat.new("frag.land")
6
6
  # Bedrock/Pocket Edition explicit query example with debug enabled
7
7
  #ms = MineStat.new("minecraft.frag.land", 19132, 5, MineStat::Request::BEDROCK, true)
8
8
  puts "Minecraft server status of #{ms.address} on port #{ms.port}:"
data/lib/minestat.rb CHANGED
@@ -27,7 +27,7 @@ require 'timeout'
27
27
  # Provides a Ruby interface for polling the status of Minecraft servers
28
28
  class MineStat
29
29
  # MineStat version
30
- VERSION = "3.0.0"
30
+ VERSION = "3.0.1"
31
31
 
32
32
  # Number of values expected from server
33
33
  NUM_FIELDS = 6
@@ -116,6 +116,10 @@ class MineStat
116
116
 
117
117
  # Unreal Tournament 3/GameSpy 4 query
118
118
  QUERY = 5
119
+
120
+ # SLP only
121
+ # @since 3.0.1
122
+ SLP = 6
119
123
  end
120
124
 
121
125
  # Instantiates a MineStat object and polls the specified server for information
@@ -126,59 +130,60 @@ class MineStat
126
130
  # @param debug [Boolean] Enable or disable error output
127
131
  # @return [MineStat] A MineStat object
128
132
  # @example Simply connect to an address
129
- # ms = MineStat.new("minecraft.frag.land")
133
+ # ms = MineStat.new("frag.land")
130
134
  # @example Connect to an address on a certain TCP or UDP port
131
- # ms = MineStat.new("minecraft.frag.land", 25567)
135
+ # ms = MineStat.new("frag.land", 25565)
132
136
  # @example Same as above example and additionally includes a timeout in seconds
133
- # ms = MineStat.new("minecraft.frag.land", 25567, 3)
137
+ # ms = MineStat.new("frag.land", 25565, 3)
134
138
  # @example Same as above example and additionally includes an explicit protocol to use
135
- # ms = MineStat.new("minecraft.frag.land", 25567, 3, MineStat::Request::QUERY)
139
+ # ms = MineStat.new("frag.land", 25565, 3, MineStat::Request::QUERY)
136
140
  # @example Connect to a Bedrock server and enable debug mode
137
141
  # ms = MineStat.new("minecraft.frag.land", 19132, 3, MineStat::Request::BEDROCK, true)
138
- def initialize(address, port = DEFAULT_TCP_PORT, timeout = DEFAULT_TIMEOUT, request_type = Request::NONE, debug = false)
139
- @address = address # address of server
140
- @port = port # TCP/UDP port of server
141
- @online # online or offline?
142
- @version # server version
143
- @mode # game mode (Bedrock/Pocket Edition only)
144
- @motd # message of the day
145
- @stripped_motd # message of the day without formatting
146
- @current_players # current number of players online
147
- @max_players # maximum player capacity
148
- @player_list # list of players (UT3/GS4 query only)
149
- @plugin_list # list of plugins (UT3/GS4 query only)
150
- @protocol # protocol level
151
- @json_data # JSON data for 1.7 queries
152
- @favicon_b64 # base64-encoded favicon possibly contained in JSON 1.7 responses
153
- @favicon # decoded favicon data
154
- @latency # ping time to server in milliseconds
155
- @timeout = timeout # TCP/UDP timeout
156
- @server # server socket
157
- @request_type # protocol version
158
- @connection_status # status of connection ("Success", "Fail", "Timeout", or "Unknown")
159
- @try_all = false # try all protocols?
160
- @debug = debug # debug mode
142
+ # @example Attempt all SLP protocols, disable debug mode, and disable DNS SRV resolution
143
+ # ms = MineStat.new("minecraft.frag.land", 25565, 3, MineStat::Request::SLP, false, false)
144
+ def initialize(address, port = DEFAULT_TCP_PORT, timeout = DEFAULT_TIMEOUT, request_type = Request::NONE, debug = false, srv_enabled = true)
145
+ @address = address # address of server
146
+ @port = port # TCP/UDP port of server
147
+ @srv_address # server address from DNS SRV record
148
+ @srv_port # server TCP port from DNS SRV record
149
+ @online # online or offline?
150
+ @version # server version
151
+ @mode # game mode (Bedrock/Pocket Edition only)
152
+ @motd # message of the day
153
+ @stripped_motd # message of the day without formatting
154
+ @current_players # current number of players online
155
+ @max_players # maximum player capacity
156
+ @player_list # list of players (UT3/GS4 query only)
157
+ @plugin_list # list of plugins (UT3/GS4 query only)
158
+ @protocol # protocol level
159
+ @json_data # JSON data for 1.7 queries
160
+ @favicon_b64 # base64-encoded favicon possibly contained in JSON 1.7 responses
161
+ @favicon # decoded favicon data
162
+ @latency # ping time to server in milliseconds
163
+ @timeout = timeout # TCP/UDP timeout
164
+ @server # server socket
165
+ @request_type # protocol version
166
+ @connection_status # status of connection ("Success", "Fail", "Timeout", or "Unknown")
167
+ @try_all = false # try all protocols?
168
+ @debug = debug # debug mode
169
+ @srv_enabled = srv_enabled # enable SRV resolution?
161
170
 
162
171
  @try_all = true if request_type == Request::NONE
163
- resolve_srv(address, port)
172
+ resolve_srv() if @srv_enabled
164
173
  set_connection_status(attempt_protocols(request_type))
165
174
  end
166
175
 
167
- # Attempts to resolve SRV records
168
- # @param address [String] Minecraft server address
169
- # @param port [Integer] Minecraft server TCP or UDP port
176
+ # Attempts to resolve DNS SRV records
170
177
  # @return [Boolean] Whether or not SRV resolution was successful
171
178
  # @since 2.3.0
172
- def resolve_srv(address, port)
179
+ def resolve_srv()
173
180
  begin
174
181
  resolver = Resolv::DNS.new
175
182
  res = resolver.getresource("_minecraft._tcp.#{@address}", Resolv::DNS::Resource::IN::SRV)
176
- @address = res.target.to_s # SRV target
177
- @port = res.port.to_i # SRV port
178
- rescue => exception # primarily catch Resolv::ResolvError and revert if unable to resolve SRV record(s)
179
- $stderr.puts exception if @debug
180
- @address = address
181
- @port = port
183
+ @srv_address = res.target.to_s # SRV target
184
+ @srv_port = res.port.to_i # SRV port
185
+ rescue => exception # primarily catch Resolv::ResolvError and revert if unable to resolve SRV record(s)
186
+ $stderr.puts "resolve_srv(): #{exception}" if @debug
182
187
  return false
183
188
  end
184
189
  return true
@@ -222,6 +227,7 @@ class MineStat
222
227
  unless retval == Retval::CONNFAIL
223
228
  retval = json_request()
224
229
  end
230
+ return retval if request_type == Request::SLP
225
231
  # Bedrock/Pocket Edition
226
232
  unless @online || retval == Retval::SUCCESS
227
233
  retval = bedrock_request()
@@ -275,13 +281,18 @@ class MineStat
275
281
  @server.connect(@address, @port)
276
282
  else
277
283
  start_time = Time.now
278
- @server = TCPSocket.new(@address, @port)
284
+ if @srv_enabled
285
+ @server = TCPSocket.new(@srv_address, @srv_port)
286
+ else
287
+ @server = TCPSocket.new(@address, @port)
288
+ end
279
289
  end
280
290
  @latency = ((Time.now - start_time) * 1000).round
281
291
  rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
292
+ $stderr.puts "connect(): Host unreachable or connection refused" if @debug
282
293
  return Retval::CONNFAIL
283
294
  rescue => exception
284
- $stderr.puts exception if @debug
295
+ $stderr.puts "connect(): #{exception}" if @debug
285
296
  return Retval::UNKNOWN
286
297
  end
287
298
  return Retval::SUCCESS
@@ -322,7 +333,7 @@ class MineStat
322
333
  end
323
334
  end
324
335
  rescue => exception
325
- $stderr.puts exception if @debug
336
+ $stderr.puts "check_response(): #{exception}" if @debug
326
337
  return nil, Retval::UNKNOWN
327
338
  end
328
339
  retval = Retval::UNKNOWN if data == nil || data.empty?
@@ -347,7 +358,7 @@ class MineStat
347
358
  if server_info != nil && server_info.length >= NUM_FIELDS_BETA
348
359
  @version = ">=1.8b/1.3" # since server does not return version, set it
349
360
  @motd = server_info[0]
350
- strip_motd
361
+ strip_motd()
351
362
  @current_players = server_info[1].to_i
352
363
  @max_players = server_info[2].to_i
353
364
  @online = true
@@ -360,7 +371,7 @@ class MineStat
360
371
  @version = "#{server_info[3]} #{server_info[7]} (#{server_info[0]})"
361
372
  @mode = server_info[8]
362
373
  @motd = server_info[1]
363
- strip_motd
374
+ strip_motd()
364
375
  @current_players = server_info[4].to_i
365
376
  @max_players = server_info[5].to_i
366
377
  @online = true
@@ -373,7 +384,7 @@ class MineStat
373
384
  server_info = Hash[*server_info[0].split(delimiter).flatten(1)]
374
385
  @version = server_info["version"]
375
386
  @motd = server_info["hostname"]
376
- strip_motd
387
+ strip_motd()
377
388
  @current_players = server_info["numplayers"].to_i
378
389
  @max_players = server_info["maxplayers"].to_i
379
390
  unless server_info["plugins"].nil? || server_info["plugins"].empty?
@@ -392,7 +403,7 @@ class MineStat
392
403
  @protocol = server_info[1].to_i # contains the protocol version (51 for 1.9 or 78 for 1.6.4 for example)
393
404
  @version = server_info[2]
394
405
  @motd = server_info[3]
395
- strip_motd
406
+ strip_motd()
396
407
  @current_players = server_info[4].to_i
397
408
  @max_players = server_info[5].to_i
398
409
  @online = true
@@ -429,9 +440,10 @@ class MineStat
429
440
  retval = parse_data("\u00A7", true) # section symbol
430
441
  end
431
442
  rescue Timeout::Error
443
+ $stderr.puts "beta_request(): Connection timed out" if @debug
432
444
  return Retval::TIMEOUT
433
445
  rescue => exception
434
- $stderr.puts exception if @debug
446
+ $stderr.puts "beta_request(): #{exception}" if @debug
435
447
  return Retval::UNKNOWN
436
448
  end
437
449
  if retval == Retval::SUCCESS
@@ -474,9 +486,10 @@ class MineStat
474
486
  retval = parse_data("\x00") # null
475
487
  end
476
488
  rescue Timeout::Error
489
+ $stderr.puts "legacy_request(): Connection timed out" if @debug
477
490
  return Retval::TIMEOUT
478
491
  rescue => exception
479
- $stderr.puts exception if @debug
492
+ $stderr.puts "legacy_request(): #{exception}" if @debug
480
493
  return Retval::UNKNOWN
481
494
  end
482
495
  if retval == Retval::SUCCESS
@@ -535,9 +548,10 @@ class MineStat
535
548
  retval = parse_data("\x00") # null
536
549
  end
537
550
  rescue Timeout::Error
551
+ $stderr.puts "extended_legacy_request(): Connection timed out" if @debug
538
552
  return Retval::TIMEOUT
539
553
  rescue => exception
540
- $stderr.puts exception if @debug
554
+ $stderr.puts "extended_legacy_request(): #{exception}" if @debug
541
555
  return Retval::UNKNOWN
542
556
  end
543
557
  if retval == Retval::SUCCESS
@@ -596,7 +610,7 @@ class MineStat
596
610
  @protocol = json_data['version']['protocol'].to_i
597
611
  @version = json_data['version']['name']
598
612
  @motd = json_data['description']
599
- strip_motd
613
+ strip_motd()
600
614
  @current_players = json_data['players']['online'].to_i
601
615
  @max_players = json_data['players']['max'].to_i
602
616
  @favicon_b64 = json_data['favicon']
@@ -611,11 +625,13 @@ class MineStat
611
625
  end
612
626
  end
613
627
  rescue Timeout::Error
628
+ $stderr.puts "json_request(): Connection timed out" if @debug
614
629
  return Retval::TIMEOUT
615
630
  rescue JSON::ParserError
631
+ $stderr.puts "json_request(): JSON parse error" if @debug
616
632
  return Retval::UNKNOWN
617
633
  rescue => exception
618
- $stderr.puts exception if @debug
634
+ $stderr.puts "json_request(): #{exception}" if @debug
619
635
  return Retval::UNKNOWN
620
636
  end
621
637
  if retval == Retval::SUCCESS
@@ -640,7 +656,7 @@ class MineStat
640
656
  break if json_data.length >= json_len
641
657
  end
642
658
  rescue => exception
643
- $stderr.puts exception if @debug
659
+ $stderr.puts "recv_json(): #{exception}" if @debug
644
660
  end
645
661
  return json_data
646
662
  end
@@ -711,9 +727,10 @@ class MineStat
711
727
  retval = parse_data("\x3B") # semicolon
712
728
  end
713
729
  rescue Timeout::Error
730
+ $stderr.puts "bedrock_request(): Connection timed out" if @debug
714
731
  return Retval::TIMEOUT
715
732
  rescue => exception
716
- $stderr.puts exception if @debug
733
+ $stderr.puts "bedrock_request(): #{exception}" if @debug
717
734
  return Retval::UNKNOWN
718
735
  end
719
736
  if retval == Retval::SUCCESS
@@ -777,9 +794,10 @@ class MineStat
777
794
  retval = parse_data("\x00") # null
778
795
  end
779
796
  rescue Timeout::Error
797
+ $stderr.puts "query_request(): Connection timed out" if @debug
780
798
  return Retval::TIMEOUT
781
799
  rescue => exception
782
- $stderr.puts exception if @debug
800
+ $stderr.puts "query_request(): #{exception}" if @debug
783
801
  return Retval::UNKNOWN
784
802
  end
785
803
  if retval == Retval::SUCCESS
@@ -795,6 +813,14 @@ class MineStat
795
813
  # Port (TCP or UDP) of the Minecraft server
796
814
  attr_reader :port
797
815
 
816
+ # Address of the Minecraft server from a DNS SRV record
817
+ # @since 3.0.1
818
+ attr_reader :srv_address
819
+
820
+ # TCP port of the Minecraft server from a DNS SRV record
821
+ # @since 3.0.1
822
+ attr_reader :srv_port
823
+
798
824
  # Whether or not the Minecraft server is online
799
825
  attr_reader :online
800
826
 
@@ -872,4 +898,8 @@ class MineStat
872
898
  # Whether or not debug mode is enabled
873
899
  # @since 3.0.0
874
900
  attr_reader :debug
901
+
902
+ # Whether or not DNS SRV resolution is enabled
903
+ # @since 3.0.1
904
+ attr_reader :srv_enabled
875
905
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minestat
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Lloyd Dilley
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-02-01 00:00:00.000000000 Z
11
+ date: 2023-02-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: MineStat polls Minecraft server data such as version, motd, current players,
14
14
  and max players.