steam_hlds_log_parser 0.4.0

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 30af9317dcddbf6bebd31d3bb02ff5df117db707
4
+ data.tar.gz: ab06662bf153b61c2cdab5b9d64209ced673e4e9
5
+ SHA512:
6
+ metadata.gz: 774c7685110aca35822f3642a5a93bbca4bd196f6ddad776345938e29a76df62f3f3b72c866898925f64ed0128a064b8046e9581db9553e6eb4719ea200a07aa
7
+ data.tar.gz: 5b8c66867b180997d6769fbff9f047346a270bddfce355fc842eafe55c3af72df5a4ab0deaf3f21112704609393682cba8e5b064a9c2e97420e7631d10ece3f9
data/.coveralls.yml ADDED
@@ -0,0 +1 @@
1
+ repo_token: WVARN24eiGJQ6GenqWAsqNQEZroHGj2SP
data/.gitignore ADDED
@@ -0,0 +1,20 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .DS_Store
19
+
20
+
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
data/.travis.yml ADDED
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in steam_hlds_log_parser.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Thomas VIAL
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,69 @@
1
+ # Steam Hlds Log Parser
2
+
3
+ Creates a server with EventMachine which listens to HLDS logs, parse and returns readable content from your game server.
4
+ The returned content can be sent to a website, IRC or flowdock for match live streaming.
5
+
6
+ Mostly tested on Steam HLDS for Counter-Strike.
7
+
8
+ Note : content is sent in english or french at this time. Need i18n contributors!
9
+
10
+ ## Build Status
11
+
12
+ [![Build Status](https://travis-ci.org/tomav/steam_hlds_log_parser.png?branch=master)](https://travis-ci.org/tomav/steam_hlds_log_parser)
13
+ [![Gem Version](https://badge.fury.io/rb/steam_hlds_log_parser.png)](http://badge.fury.io/rb/steam_hlds_log_parser)
14
+ [![Coverage Status](https://coveralls.io/repos/tomav/steam_hlds_log_parser/badge.png)](https://coveralls.io/r/tomav/steam_hlds_log_parser)
15
+
16
+ ## Installation
17
+
18
+ Add this line to your application's Gemfile:
19
+
20
+ gem 'steam_hlds_log_parser'
21
+
22
+ And then execute:
23
+
24
+ $ bundle
25
+
26
+ Or install it yourself as:
27
+
28
+ $ gem install steam_hlds_log_parser
29
+
30
+ ## Usage
31
+
32
+ 1. Create your own displayer callback `class` which will receive parsed data
33
+ Ask this `class` to write a file, send content to IRC or flowdock... whatever... and give it as `:displayer` Hash option
34
+ 2. Create a new client on desired IP / Port / Options
35
+ 3. In your HLDS server: `logaddress 127.0.0.1 27035`
36
+
37
+ ## Example
38
+
39
+ require "rubygems"
40
+ require "steam_hlds_log_parser"
41
+
42
+ class Formatter
43
+ def initialize(data)
44
+ # will 'puts' the translated content
45
+ SteamHldsLogParser::Displayer.new(data).display_translation
46
+ end
47
+ end
48
+
49
+
50
+ ## These are default options
51
+ options = {
52
+ :locale => :en,
53
+ :display_kills => true,
54
+ :display_actions => true,
55
+ :display_changelevel => true,
56
+ :displayer => Formatter
57
+ }
58
+
59
+ parser = SteamHldsLogParser::Client.new("127.0.0.1", 27035, options)
60
+ parser.start
61
+
62
+
63
+ ## Contributing
64
+
65
+ 1. Fork it
66
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
67
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
68
+ 4. Push to the branch (`git push origin my-new-feature`)
69
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "rubygems"
2
+ require "bundler/gem_tasks"
3
+ require "rspec/core/rake_task"
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ task :default => [:spec]
@@ -0,0 +1,22 @@
1
+ require "rubygems"
2
+ require "steam_hlds_log_parser"
3
+
4
+ class Formatter
5
+ def initialize(data)
6
+ # will 'puts' the translated content
7
+ SteamHldsLogParser::Displayer.new(data).display_translation
8
+ end
9
+ end
10
+
11
+
12
+ ## These are default options
13
+ options = {
14
+ :locale => :en,
15
+ :display_kills => true,
16
+ :display_actions => true,
17
+ :display_changelevel => true,
18
+ :displayer => Formatter
19
+ }
20
+
21
+ parser = SteamHldsLogParser::Client.new("127.0.0.1", 27035, options)
22
+ parser.start
@@ -0,0 +1,24 @@
1
+ require "rubygems"
2
+ require "steam_hlds_log_parser"
3
+ # require "flowdock"
4
+
5
+ ## The displayer class that will be used to send content to Flowdock
6
+ class FlowdockPusher
7
+ def initialize(data)
8
+ # Get translated data
9
+ content = SteamHldsLogParser::Displayer.new(data).get_translation
10
+ # Source: https://github.com/flowdock/flowdock-api
11
+ flow = Flowdock::Flow.new(:api_token => "12345678901234567890123456789012", :external_user_name => "HLDS-Live")
12
+ flow.push_to_chat(:content => content)
13
+ end
14
+ end
15
+
16
+ options = {
17
+ :locale => :fr,
18
+ :display_kills => true,
19
+ :display_actions => true,
20
+ :display_changelevel => true,
21
+ :displayer => FlowdockPusher
22
+ }
23
+
24
+ SteamHldsLogParser::Client.new("127.0.0.1", 27035, options).start
data/lib/.DS_Store ADDED
Binary file
@@ -0,0 +1,42 @@
1
+ en:
2
+ # client
3
+ client_connect: "HLDS connected and sending data"
4
+ client_disconnect: "HLDS disconnected? No data is received."
5
+ client_stop: "HLDS Log Parser stopped."
6
+ # team
7
+ full_team_name_te: "Terrorist"
8
+ full_team_name_ct: "Counter-Terrorist"
9
+ short_team_name_te: "TE"
10
+ short_team_name_ct: "CT"
11
+ # round conclusion types
12
+ all_hostages_rescued: "All hostages have been rescued"
13
+ bomb_defused: "Bomb has been defused"
14
+ cts_preventescape: "The CT's have prevented most of the terrorists from escaping"
15
+ cts_win: "Counter-Terrorists Win"
16
+ hostages_not_rescued: "Hostages have not been rescued"
17
+ target_bombed: "Target Successfully Bombed!"
18
+ target_saved: "Target has been saved"
19
+ terrorists_escaped: "Terrorists have escaped"
20
+ terrorists_not_escaped: "Terrorists have not escaped"
21
+ terrorists_win: "Terrorists Win"
22
+ vip_assassinated: "The VIP has been assassinated"
23
+ vip_escaped: "The VIP has escaped"
24
+ vip_not_escaped: "VIP has not escaped"
25
+ # user actions
26
+ begin_bomb_defuse_with_kit: "begin bomb defuse with kit"
27
+ begin_bomb_defuse_without_kit: "begin bomb defuse without kit"
28
+ defused_the_bomb: "defused the bomb"
29
+ dropped_the_bomb: "dropped the bomb"
30
+ got_the_bomb: "got the bomb"
31
+ killed_a_hostage: "killed a hostage"
32
+ planted_the_bomb: "planted the bom"
33
+ rescued_a_hostage: "rescued a hostage"
34
+ spawned_with_the_bomb: "spawned with the bomb"
35
+ touched_a_hostage: "touched a hostage"
36
+ # events
37
+ map_ends: "Map ends: %{winner} => %{score}"
38
+ victory: "[CT] %{score_ct} - %{score_t} [T]"
39
+ kill: "[%{killer_team}] %{killer} killed [%{killed_team}] %{killed} with %{weapon}"
40
+ suicide: "%{killed} commited suicide"
41
+ event: "[%{person_team}] %{person} %{event_i18n}"
42
+ loading_map: "Loading %{map}"
@@ -0,0 +1,42 @@
1
+ fr:
2
+ # client
3
+ client_connect: "HLDS vient de se connecter et transmets des données."
4
+ client_disconnect: "HLDS s'est déconnecté ?"
5
+ client_stop: "HLDS Log Parser stoppé."
6
+ # team
7
+ full_team_name_te: "Terroriste"
8
+ full_team_name_ct: "Anti-Terroriste"
9
+ short_team_name_te: "TE"
10
+ short_team_name_ct: "CT"
11
+ # round conclusion types
12
+ all_hostages_rescued: "Tous les otages ont été sauvés"
13
+ bomb_defused: "La bombe a été désamorçée"
14
+ cts_preventescape: "Les CT ont empéché l'évasion des Terroristes"
15
+ cts_win: "Victoire des Anti-Terroristes"
16
+ hostages_not_rescued: "Les otages n'ont pas été sauvés"
17
+ target_bombed: "La cible a été détruite !"
18
+ target_saved: "La cible a été protégée"
19
+ terrorists_escaped: "Les Terroristes se sont échappés"
20
+ terrorists_not_escaped: "Les Terroristes ne se sont pas échappés"
21
+ terrorists_win: "Victoire des Terroristes"
22
+ vip_assassinated: "Le VIP a été assassiné"
23
+ vip_escaped: "Le VIP s'est échappé"
24
+ vip_not_escaped: "Le VIP ne s'est pas échappé"
25
+ # user actions
26
+ begin_bomb_defuse_with_kit: "commence à désamorcer la bombe avec un kit"
27
+ begin_bomb_defuse_without_kit: "commence à désamorcer la bombe sans kit"
28
+ defused_the_bomb: "a désamorcé la bombe"
29
+ dropped_the_bomb: "a perdu la bombe"
30
+ got_the_bomb: "a récupéré la bombe"
31
+ killed_a_hostage: "a tué un otage"
32
+ planted_the_bomb: "a posé la bombe"
33
+ rescued_a_hostage: "a sauvé un otage"
34
+ spawned_with_the_bomb: "a la bombe"
35
+ touched_a_hostage: "a récupéré un otage"
36
+ # events
37
+ map_ends: "Fin de partie : Score des %{winner} => %{score}"
38
+ victory: "[CT] %{score_ct} - %{score_t} [TE]"
39
+ kill: "[%{killer_team}] %{killer} a tué [%{killed_team}] %{killed} au %{weapon}"
40
+ suicide: "%{killed} s'est tué"
41
+ event: "[%{person_team}] %{person} %{event_i18n}"
42
+ loading_map: "Chargement de %{map}"
@@ -0,0 +1,52 @@
1
+ module SteamHldsLogParser
2
+
3
+ class Client
4
+
5
+ attr_reader :host, :port, :options
6
+
7
+ # Creates a new client
8
+ #
9
+ # @host [String] Hostname / IP Address the server will be running
10
+ # @port [Integer] Port to listen to
11
+ # @options [Hash] Other options
12
+ #
13
+ # ==== Options
14
+ #
15
+ # * +locale+ - Set the language of returned content
16
+ # * +display_kills+ Enable kills / frags detail (default=true)
17
+ # * +display_actions+ Enable players actions / defuse / ... detail (default=true)
18
+ # * +display_changelevel+ Enable changelevel (map) display (default=true)
19
+ # * +displayer+ Class that will be use to display content (default=HldsReturnDisplayer)
20
+ #
21
+ def initialize(host, port, options = {})
22
+ default_options = {
23
+ :locale => :en,
24
+ :display_kills => true,
25
+ :display_actions => true,
26
+ :display_changelevel => true
27
+ }
28
+ @host, @port = host, port
29
+ @options = default_options.merge(options)
30
+ end
31
+
32
+ # Starts the client which will receive HLDS logs (using UDP)
33
+ def start
34
+ # setting locale
35
+ I18n.locale = @options[:locale] || I18n.default_locale
36
+ EM.run {
37
+ # catch CTRL+C
38
+ Signal.trap("INT") { EM.stop }
39
+ Signal.trap("TERM") { EM.stop }
40
+ # Let's start
41
+ EM::open_datagram_socket(@host, @port, Handler, @host, @port, @options)
42
+ }
43
+ end
44
+
45
+ # Stops the client
46
+ def stop
47
+ puts "## #{@host}:#{@port} => #{I18n.t('client_stop')}"
48
+ EM::stop_event_loop
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,37 @@
1
+ module SteamHldsLogParser
2
+
3
+ # Default Displayer
4
+ #
5
+ # @data [Hash] Data returned by 'receive_data'
6
+ #
7
+ class Displayer
8
+
9
+ attr_reader :data
10
+
11
+ def initialize(data)
12
+ @data = data
13
+ end
14
+
15
+ # Return data
16
+ def get_data
17
+ return @data
18
+ end
19
+
20
+ # Display data
21
+ def display_data
22
+ puts get_data
23
+ end
24
+
25
+ # Return data translation
26
+ def get_translation
27
+ return I18n.t(@data[:type], @data[:params]) unless @data[:type].nil?
28
+ end
29
+
30
+ # Display data translation
31
+ def display_translation
32
+ puts get_translation
33
+ end
34
+
35
+ end
36
+
37
+ end
@@ -0,0 +1,103 @@
1
+ module SteamHldsLogParser
2
+
3
+ class Handler < EM::Connection
4
+
5
+ attr_reader :host, :port, :options
6
+
7
+ # Initialize Handler from Client options
8
+ #
9
+ # @host [String] Hostname / IP Address the server will be running
10
+ # @port [Integer] Port to listen to
11
+ # @options [Hash] Other options
12
+ #
13
+ def initialize(host, port, options)
14
+ @host, @port, @options = host, port, options
15
+ end
16
+
17
+ # Triggered when HLDS connects
18
+ def post_init
19
+ puts "## #{@host}:#{@port} => #{I18n.t('client_connect')}"
20
+ end
21
+
22
+ # Triggered when HLDS disconnects
23
+ def unbind
24
+ puts "## #{@host}:#{@port} => #{I18n.t('client_disconnect')}"
25
+ end
26
+
27
+ # Get data from Client and parse using Regexp
28
+ #
29
+ # * match end of map, with winner team and score
30
+ # * match the end of round, with score and victory type
31
+ # * match who killed who with what (frags)
32
+ # * match suicides
33
+ # * match who did what (defuse, drop the bomb...)
34
+ # * match changelevel
35
+ #
36
+ # @data [String] Data received by Client from HLDS server (a line of log)
37
+ #
38
+ def receive_data(data)
39
+
40
+ # L 05/10/2000 - 12:34:56: Team "CT" scored "17" with "0" players
41
+ if data.gsub(/Team "(.+)" scored "(\d+)" with "(\d+)"/).count > 0
42
+ winner, winner_score = data.match(/Team "(.+)" scored "(\d+)" with/).captures
43
+ content = { :type => 'map_ends', :params => { :winner => get_short_team_name(winner), :score => winner_score } }
44
+
45
+ # L 05/10/2000 - 12:34:56: Team "CT" triggered "CTs_Win" (CT "3") (T "0")
46
+ elsif data.gsub(/(: Team ")/).count > 0
47
+ winner, type, score_ct, score_t = data.match(/Team "([A-Z]+)" triggered "([A-Za-z_]+)" \(CT "(\d+)"\) \(T "(\d+)"\)/i).captures
48
+ content = { :type => 'victory', :params => { :score_ct => score_ct, :score_t => score_t } }
49
+
50
+ # L 05/10/2000 - 12:34:56: "Killer | Player<66><STEAM_ID_LAN><TERRORIST>" killed "Killed | Player<60><STEAM_ID_LAN><CT>" with "ak47"
51
+ elsif @options[:display_kills] && data.gsub(/(\>" killed ")/).count > 0
52
+ killer, killer_team, killed, killed_team, weapon = data.match(/"(.+)<\d+><STEAM_ID_LAN><(.+)>" killed "(.+)<\d+><STEAM_ID_LAN><(.+)>" with "(.+)"/i).captures
53
+ content = { :type => 'kill', :params => { :killer_team => get_short_team_name(killer_team), :killer => killer, :killed_team => get_short_team_name(killed_team), :killed => killed, :weapon => weapon } }
54
+
55
+ # L 05/10/2000 - 12:34:56: "Player<66><STEAM_ID_LAN><TERRORIST>" committed suicide with "worldspawn" (world)
56
+ elsif @options[:display_kills] && data.gsub(/>" committed suicide/).count > 0
57
+ killed = data.match(/: "(.+)<\d+>/).captures.first
58
+ content = { :type => 'suicide', :params => { :killed => killed } }
59
+
60
+ # L 05/10/2000 - 12:34:56: "Killer | Player<66><STEAM_ID_LAN><CT>" triggered "Defused_The_Bomb"
61
+ elsif @options[:display_actions] && data.gsub(/<STEAM_ID_LAN><.+>" triggered "(.+)"$/).count > 0
62
+ person, person_team, event = data.match(/: "(.+)<\d+><STEAM_ID_LAN><(.+)>" triggered "(.+)"/i).captures
63
+ content = { :type => 'event', :params => { :person_team => get_short_team_name(person_team), :person => person, :event_item => event, :event_i18n => I18n.t(event.downcase)} }
64
+
65
+ # L 05/10/2000 - 12:34:56: Loading map "de_dust2"
66
+ elsif @options[:display_changelevel] && data.gsub(/: Loading map "(.+)"/).count > 0
67
+ map = data.match(/: Loading map "(.+)"/i).captures.first
68
+ content = { :type => 'loading_map', :params => { :map => map } }
69
+
70
+ end
71
+
72
+ if @options[:displayer].nil?; return(content) else @options[:displayer].new(content) end
73
+
74
+ end
75
+
76
+ # Format team name with long format (textual)
77
+ #
78
+ # @winner [String] Round winner (+CT+ or +T+) from logs
79
+ #
80
+ def get_full_team_name(winner)
81
+ case winner
82
+ when "T"
83
+ return "#{I18n.t('full_team_name_te')}"
84
+ else
85
+ return "#{I18n.t('full_team_name_ct')}"
86
+ end
87
+ end
88
+
89
+ # Format team name with short format (initials)
90
+ #
91
+ # @team [String] Round winner (+CT+ or +TERRORIST+) from logs
92
+ #
93
+ def get_short_team_name(team)
94
+ case team
95
+ when "TERRORIST"
96
+ return "#{I18n.t('short_team_name_te')}"
97
+ else
98
+ return "#{I18n.t('short_team_name_ct')}"
99
+ end
100
+ end
101
+
102
+ end
103
+ end
@@ -0,0 +1,3 @@
1
+ module SteamHldsLogParser
2
+ VERSION = "0.4.0"
3
+ end
@@ -0,0 +1,16 @@
1
+ require "rubygems"
2
+ require "eventmachine"
3
+ require "i18n"
4
+ require "rdoc"
5
+
6
+ require "steam_hlds_log_parser/version"
7
+ require "steam_hlds_log_parser/client"
8
+ require "steam_hlds_log_parser/handler"
9
+ require "steam_hlds_log_parser/displayer"
10
+
11
+ module SteamHldsLogParser
12
+
13
+ I18n.load_path = Dir.glob( File.dirname(__FILE__) + "/locales/*.yml" )
14
+ I18n.default_locale = :en
15
+
16
+ end
@@ -0,0 +1,69 @@
1
+ require "helper_spec"
2
+
3
+ module SteamHldsLogParser
4
+
5
+ describe "SteamHldsLogParser" do
6
+
7
+ before :all do
8
+ @client = Client.new("0.0.0.0", 27035)
9
+ @options = @client.options
10
+ @custom_options = custom_options
11
+ @custom_client = Client.new("127.0.0.1", 27045, @custom_options)
12
+ end
13
+
14
+ describe "Client" do
15
+
16
+ it "raises an exception when parameters are missing" do
17
+ expect { Client.new }.to raise_error(ArgumentError)
18
+ end
19
+
20
+ subject { @client }
21
+ context "when a 'Client' is created without options"
22
+ it { should be_an_instance_of Client }
23
+ it "has a 'host'" do
24
+ @client.host.should_not be_nil
25
+ @client.host.should eq("0.0.0.0")
26
+ end
27
+ it "has a 'port'" do
28
+ @client.port.should_not be_nil
29
+ @client.port.should eq(27035)
30
+ end
31
+ it "has a default 'options' Hash" do
32
+ @client.options.should_not be_nil
33
+ @client.options.should_not be(nil)
34
+ @client.options.class.should be(Hash)
35
+ @client.options.should eq(@options)
36
+ end
37
+
38
+ subject(:custom_client) { @custom_client }
39
+ context "when custom options are given"
40
+ it "can get a custom 'options' Hash" do
41
+ @custom_client.options.should_not be_nil
42
+ @custom_client.options.class.should be(Hash)
43
+ @custom_client.options.should eq(@custom_options)
44
+ @custom_client.options[:displayer].should eq(RSpecDisplayer)
45
+ @custom_client.options[:locale].should be(:fr)
46
+ @custom_client.options[:display_kills].should be(false)
47
+ @custom_client.options[:display_actions].should be(false)
48
+ @custom_client.options[:display_changelevel].should be(false)
49
+ end
50
+
51
+ describe "#start and #stop" do
52
+
53
+ context "when 'start' and 'stop' are triggered one after the other"
54
+ it "starts then stops an eventmachine with appropriate messages" do
55
+ EM.run {
56
+ capture_stdout { @client.start }.should eq("## 0.0.0.0:27035 => HLDS connected and sending data\n")
57
+ EM.add_timer(0.2) {
58
+ capture_stdout { @client.stop }.should eq("## 0.0.0.0:27035 => HLDS Log Parser stopped.\n")
59
+ }
60
+ }
61
+ end
62
+
63
+ end
64
+
65
+ end
66
+
67
+ end
68
+
69
+ end
@@ -0,0 +1,59 @@
1
+ require "helper_spec"
2
+
3
+ module SteamHldsLogParser
4
+
5
+ describe "SteamHldsLogParser" do
6
+
7
+ before :all do
8
+ @data = {:type=>"victory", :params=>{:score_ct=>"3", :score_t=>"0"}}
9
+ @displayer = Displayer.new(@data)
10
+ end
11
+
12
+ describe "Displayer" do
13
+
14
+ context "when 'data' is missing" do
15
+ it "raises an exception" do
16
+ expect { Displayer.new }.to raise_error(ArgumentError)
17
+ end
18
+ end
19
+
20
+ context "when 'data' is given" do
21
+
22
+ it "creates a 'Displayer'" do
23
+ @displayer.should be_an_instance_of Displayer
24
+ end
25
+
26
+ describe "#get_data" do
27
+ it "returns 'data' given as argument" do
28
+ @displayer.get_data.should_not be_nil
29
+ @displayer.get_data.should be(@data)
30
+ end
31
+ end
32
+
33
+ describe "#display_data" do
34
+ it "displays 'data' given as argument" do
35
+ eval(capture_stdout { @displayer.display_data }).should eq(@data)
36
+ end
37
+ end
38
+
39
+ describe "#get_translation" do
40
+ it "returns translated 'data' given as argument" do
41
+ @displayer.get_translation.should_not be_nil
42
+ @displayer.get_translation.class.should be(String)
43
+ @displayer.get_translation.should eq("[CT] 3 - 0 [T]")
44
+ end
45
+ end
46
+
47
+ describe "#display_translation" do
48
+ it "displays translated 'data' given as argument" do
49
+ capture_stdout { @displayer.display_translation }.should eq("[CT] 3 - 0 [T]\n")
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+
59
+ end
@@ -0,0 +1,138 @@
1
+ require "helper_spec"
2
+
3
+ module SteamHldsLogParser
4
+
5
+ describe "SteamHldsLogParser" do
6
+
7
+ before :all do
8
+ @client = Client.new("0.0.0.0", 27035)
9
+ @options = @client.options
10
+ @handler = Handler.new("", "0.0.0.0", 27035, @options)
11
+ end
12
+
13
+ describe "Handler" do
14
+
15
+ context "when parameters are missing" do
16
+ it "raises an exception" do
17
+ expect { Handler.new }.to raise_error(ArgumentError)
18
+ end
19
+ end
20
+
21
+ context "when parameters are given" do
22
+ subject { @handler }
23
+
24
+ context "when 'host' and 'port' are given"
25
+ it { should be_an_instance_of Handler }
26
+ it "has a 'host'" do
27
+ @handler.host.should_not be_nil
28
+ @handler.host.should eq("0.0.0.0")
29
+ end
30
+ it "has a 'port'" do
31
+ @handler.port.should_not be_nil
32
+ @handler.port.should eq(27035)
33
+ end
34
+
35
+ describe "#post_init" do
36
+ it "displays a console message when hlds connects" do
37
+ capture_stdout { @handler.post_init }.should eq("## 0.0.0.0:27035 => HLDS connected and sending data\n")
38
+ end
39
+ end
40
+
41
+ describe "#unbind" do
42
+ it "displays a console message when hlds disconnects" do
43
+ capture_stdout { @handler.unbind }.should eq("## 0.0.0.0:27035 => HLDS disconnected? No data is received.\n")
44
+ end
45
+ end
46
+
47
+ describe "#receive_data" do
48
+
49
+ context "when data is not supported" do
50
+ it "returns anything" do
51
+ data = '# L 05/10/2000 - 12:34:56: I am a fake line of log'
52
+ @handler.receive_data(data).should eq(nil)
53
+ end
54
+ end
55
+
56
+ context "when data is 'map_ends'" do
57
+ it "returns Hash on map_ends" do
58
+ data = '# L 05/10/2000 - 12:34:56: Team "CT" scored "17" with "0" players"'
59
+ expected = {:type=>"map_ends", :params=>{:winner=>"CT", :score=>"17"}}
60
+ @handler.receive_data(data).class.should eq(Hash)
61
+ @handler.receive_data(data).should eq(expected)
62
+ end
63
+ end
64
+
65
+ context "when data is 'victory'" do
66
+ it "returns Hash on victory" do
67
+ data = '# L 05/10/2000 - 12:34:56: Team "CT" triggered "CTs_Win" (CT "3") (T "0")'
68
+ expected = {:type=>"victory", :params=>{:score_ct=>"3", :score_t=>"0"}}
69
+ @handler.receive_data(data).class.should eq(Hash)
70
+ @handler.receive_data(data).should eq(expected)
71
+ end
72
+ end
73
+
74
+ context "when data is 'killed'" do
75
+ it "returns Hash on killed" do
76
+ data = '# L 05/10/2000 - 12:34:56: "Killer | Player<66><STEAM_ID_LAN><TERRORIST>" killed "Killed | Player<60><STEAM_ID_LAN><CT>" with "ak47"'
77
+ expected = {:type=>"kill", :params => {:killer_team=>"TE", :killer=>"Killer | Player", :killed_team=>"CT", :killed=>"Killed | Player", :weapon=>"ak47"}}
78
+ @handler.receive_data(data).class.should eq(Hash)
79
+ @handler.receive_data(data).should eq(expected)
80
+ end
81
+ end
82
+
83
+ context "when data is 'suicide'" do
84
+ it "returns Hash on suicide" do
85
+ data = '# L 05/10/2000 - 12:34:56: "Player<66><STEAM_ID_LAN><TERRORIST>" committed suicide with "worldspawn" (world)'
86
+ expected = {:type=>"suicide", :params=>{:killed=>"Player"}}
87
+ @handler.receive_data(data).class.should eq(Hash)
88
+ @handler.receive_data(data).should eq(expected)
89
+ end
90
+ end
91
+
92
+ context "when data is 'event'" do
93
+ it "returns Hash on event" do
94
+ data = '# L 05/10/2000 - 12:34:56: "Killer | Player<66><STEAM_ID_LAN><CT>" triggered "Defused_The_Bomb"'
95
+ expected = {:type=>"event", :params=> {:person_team=>"CT", :person=>"Killer | Player", :event_item=>"Defused_The_Bomb", :event_i18n=>"defused the bomb"}}
96
+ @handler.receive_data(data).class.should eq(Hash)
97
+ @handler.receive_data(data).should eq(expected)
98
+ end
99
+ end
100
+
101
+ context "when data is 'changelevel'" do
102
+ it "returns Hash on changelevel" do
103
+ data = '# L 05/10/2000 - 12:34:56: Loading map "de_dust2"'
104
+ expected = {:type=>"loading_map", :params=>{:map=>"de_dust2"}}
105
+ @handler.receive_data(data).class.should eq(Hash)
106
+ @handler.receive_data(data).should eq(expected)
107
+ end
108
+ end
109
+
110
+ end
111
+
112
+ describe "#get_full_team_name" do
113
+
114
+ context "when short name is given"
115
+ it "returns full name" do
116
+ @handler.get_full_team_name("T").should eq("Terrorist")
117
+ @handler.get_full_team_name("CT").should eq("Counter-Terrorist")
118
+ end
119
+
120
+ end
121
+
122
+ describe "#get_short_team_name" do
123
+
124
+ context "when full name is given"
125
+ it "returns short name" do
126
+ @handler.get_short_team_name("TERRORIST").should eq("TE")
127
+ @handler.get_short_team_name("CT").should eq("CT")
128
+ end
129
+
130
+ end
131
+
132
+ end
133
+
134
+ end
135
+
136
+ end
137
+
138
+ end
@@ -0,0 +1,39 @@
1
+ require "simplecov"
2
+ require "coveralls"
3
+ require "rspec"
4
+
5
+ # Simplecov / Coverall configuration
6
+ SimpleCov.formatter = Coveralls::SimpleCov::Formatter
7
+ SimpleCov.start do
8
+ add_filter "/example/"
9
+ add_filter "/spec/"
10
+ end
11
+
12
+ # Get ouput content of the given block
13
+ # Source: https://github.com/cldwalker/hirb/blob/master/test/test_helper.rb
14
+ def capture_stdout(&block)
15
+ original_stdout = $stdout
16
+ $stdout = fake = StringIO.new
17
+ begin
18
+ yield
19
+ ensure
20
+ $stdout = original_stdout
21
+ end
22
+ fake.string
23
+ end
24
+
25
+ class RSpecDisplayer
26
+ end
27
+
28
+ require "steam_hlds_log_parser"
29
+
30
+ # Returns custom options as a Hash
31
+ def custom_options
32
+ options = {
33
+ :locale => :fr,
34
+ :display_kills => false,
35
+ :display_actions => false,
36
+ :display_changelevel => false,
37
+ :displayer => RSpecDisplayer
38
+ }
39
+ end
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'steam_hlds_log_parser/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "steam_hlds_log_parser"
8
+ spec.version = SteamHldsLogParser::VERSION
9
+ spec.authors = ["Thomas VIAL"]
10
+ spec.email = ["github@ifusio.com"]
11
+ spec.description = %q{Steam HLDS Log Parser receives logs from your Steam game server and parses them in real time to give you usable content for your website, irc channel / flowdock... Works well with Counter-Strike and others Half-life based games.}
12
+ spec.summary = %q{Steam HLDS Log Parser receives logs from your Steam game server and parses them in real time to give you usable content for your website, irc channel / flowdock... Works well with Counter-Strike and others Half-life based games.}
13
+ spec.homepage = "https://github.com/tomav/steam_hlds_log_parser"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "bundler", "~> 1.3"
22
+ spec.add_dependency "rake"
23
+ spec.add_dependency "eventmachine", "~> 1.0.3"
24
+ spec.add_dependency "i18n"
25
+
26
+ spec.add_development_dependency "simplecov"
27
+ spec.add_development_dependency "coveralls"
28
+ spec.add_development_dependency "rspec-core"
29
+ spec.add_development_dependency "rspec"
30
+
31
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: steam_hlds_log_parser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0
5
+ platform: ruby
6
+ authors:
7
+ - Thomas VIAL
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2013-08-13 00:00:00 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: bundler
16
+ prerelease: false
17
+ requirement: &id001 !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ~>
20
+ - !ruby/object:Gem::Version
21
+ version: "1.3"
22
+ type: :runtime
23
+ version_requirements: *id001
24
+ - !ruby/object:Gem::Dependency
25
+ name: rake
26
+ prerelease: false
27
+ requirement: &id002 !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - &id004
30
+ - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id002
35
+ - !ruby/object:Gem::Dependency
36
+ name: eventmachine
37
+ prerelease: false
38
+ requirement: &id003 !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ~>
41
+ - !ruby/object:Gem::Version
42
+ version: 1.0.3
43
+ type: :runtime
44
+ version_requirements: *id003
45
+ - !ruby/object:Gem::Dependency
46
+ name: i18n
47
+ prerelease: false
48
+ requirement: &id005 !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - *id004
51
+ type: :runtime
52
+ version_requirements: *id005
53
+ - !ruby/object:Gem::Dependency
54
+ name: simplecov
55
+ prerelease: false
56
+ requirement: &id006 !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - *id004
59
+ type: :development
60
+ version_requirements: *id006
61
+ - !ruby/object:Gem::Dependency
62
+ name: coveralls
63
+ prerelease: false
64
+ requirement: &id007 !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - *id004
67
+ type: :development
68
+ version_requirements: *id007
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec-core
71
+ prerelease: false
72
+ requirement: &id008 !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - *id004
75
+ type: :development
76
+ version_requirements: *id008
77
+ - !ruby/object:Gem::Dependency
78
+ name: rspec
79
+ prerelease: false
80
+ requirement: &id009 !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - *id004
83
+ type: :development
84
+ version_requirements: *id009
85
+ description: Steam HLDS Log Parser receives logs from your Steam game server and parses them in real time to give you usable content for your website, irc channel / flowdock... Works well with Counter-Strike and others Half-life based games.
86
+ email:
87
+ - github@ifusio.com
88
+ executables: []
89
+
90
+ extensions: []
91
+
92
+ extra_rdoc_files: []
93
+
94
+ files:
95
+ - .coveralls.yml
96
+ - .gitignore
97
+ - .rspec
98
+ - .travis.yml
99
+ - Gemfile
100
+ - LICENSE.txt
101
+ - README.md
102
+ - Rakefile
103
+ - example/example-1.rb
104
+ - example/example-2.rb
105
+ - lib/.DS_Store
106
+ - lib/locales/en.yml
107
+ - lib/locales/fr.yml
108
+ - lib/steam_hlds_log_parser.rb
109
+ - lib/steam_hlds_log_parser/client.rb
110
+ - lib/steam_hlds_log_parser/displayer.rb
111
+ - lib/steam_hlds_log_parser/handler.rb
112
+ - lib/steam_hlds_log_parser/version.rb
113
+ - spec/client_spec.rb
114
+ - spec/displayer_spec.rb
115
+ - spec/handler_spec.rb
116
+ - spec/helper_spec.rb
117
+ - steam_hlds_log_parser.gemspec
118
+ homepage: https://github.com/tomav/steam_hlds_log_parser
119
+ licenses:
120
+ - MIT
121
+ metadata: {}
122
+
123
+ post_install_message:
124
+ rdoc_options: []
125
+
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - *id004
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - *id004
134
+ requirements: []
135
+
136
+ rubyforge_project:
137
+ rubygems_version: 2.0.3
138
+ signing_key:
139
+ specification_version: 4
140
+ summary: Steam HLDS Log Parser receives logs from your Steam game server and parses them in real time to give you usable content for your website, irc channel / flowdock... Works well with Counter-Strike and others Half-life based games.
141
+ test_files:
142
+ - spec/client_spec.rb
143
+ - spec/displayer_spec.rb
144
+ - spec/handler_spec.rb
145
+ - spec/helper_spec.rb