fonte 0.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.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ script: bundle exec rspec -bfd spec
3
+ rvm:
4
+ - 1.9.2
5
+ - 1.9.3
6
+ - jruby
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in fonte.gemspec
4
+ gemspec
data/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # Fonte
2
+ Fonte is a Valve Source engine log parser. Currently supporting only the basic HL Engine commands.
3
+
4
+ More info can be found at [HL Engine Log Standard documentation](https://developer.valvesoftware.com/wiki/HL_Log_Standard)
5
+
6
+ [![Build Status](https://secure.travis-ci.org/reu/fonte.png)](http://travis-ci.org/reu/fonte)
7
+
8
+ ## Examples
9
+
10
+ Fonte comes with a bunch of parsers that can be used individually. Also, there is the `LogParser` which will then includes all the other `_*Parser_` to parse a full log file.
11
+
12
+ For example, if you wish to parse only a player informaton, you could use the PlayerParser:
13
+
14
+ ```ruby
15
+ player = Fonte::Parsers::PlayerParser.new.parse("Reu<2><STEAM_1:1:24968171><Red>")
16
+
17
+ player.nickname.value # => "Reu"
18
+ player.steam_id.value # => "STEAM_1:1:24968171"
19
+ player.steam_id.account_number.value # => 24968171
20
+ player.team.value # => "Red"
21
+ ```
22
+
23
+ Or you could parse a rcon authentication individually or within a log:
24
+
25
+ ```ruby
26
+ rcon_authentication = Fonte::Parsers::PlayerParser.new.parse('Rcon: "rcon challenge "super secret" command" from "192.168.10.1:17015"')
27
+ rcon_authentication.password.value # => "super secret"
28
+ ```
29
+
30
+ ```ruby
31
+ log = Fonte::Parsers::LogParser.new.parse('L 12/26/2011 - 02:14:33: Rcon: "rcon challenge "super secret" command" from "192.168.10.1:17015"')
32
+
33
+ log.command.password.value # => "super secret"
34
+ log.date_time.day # => 26
35
+ ```
36
+
37
+ ## Disclaimer
38
+
39
+ This is a very early approach and can be a considered a proof of concept in the current version. Lots of things should (and will) be changed. For instance, I am not quite happy with the forced _".value"_ API, but for now, it was the easiest way to implement. Also, it doesn't support real games log yet, so, there should be a way to easily "plug" specific game "log commands".
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/fonte.gemspec ADDED
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "fonte/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "fonte"
7
+ s.version = Fonte::VERSION
8
+ s.authors = ["Rodrigo Navarro"]
9
+ s.email = ["rnavarro1@gmail.com"]
10
+ s.homepage = "https://github.com/reu/fonte"
11
+ s.summary = "Valve Source Engine log parser"
12
+
13
+ s.rubyforge_project = "fonte"
14
+
15
+ s.files = `git ls-files`.split("\n")
16
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
17
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
18
+ s.require_paths = ["lib"]
19
+
20
+ s.add_development_dependency "rspec"
21
+ s.add_runtime_dependency "treetop"
22
+ end
@@ -0,0 +1,14 @@
1
+ module Fonte
2
+ module Nodes
3
+ class DateTimeNode < Treetop::Runtime::SyntaxNode
4
+ def value
5
+ DateTime.new date.year.value,
6
+ date.month.value,
7
+ date.day.value,
8
+ time.hours.value,
9
+ time.minutes.value,
10
+ time.seconds.value
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ module Fonte
2
+ module Nodes
3
+ class IntegerNode < Treetop::Runtime::SyntaxNode
4
+ def value
5
+ Integer(text_value)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,9 @@
1
+ module Fonte
2
+ module Nodes
3
+ class IpNode < Treetop::Runtime::SyntaxNode
4
+ def value
5
+ URI.parse("//" + text_value)
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,13 @@
1
+ module Fonte
2
+ module Nodes
3
+ class RconCommandNode < Treetop::Runtime::SyntaxNode
4
+ def password
5
+ rcon_challenge.rcon_password
6
+ end
7
+
8
+ def origin
9
+ rcon_challenge.rcon_origin
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,9 @@
1
+ module Fonte
2
+ module Nodes
3
+ class SingleWordNode < Treetop::Runtime::SyntaxNode
4
+ def value
5
+ quoted_word.value
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,29 @@
1
+ module Fonte
2
+ module Nodes
3
+ class SteamIDNode < Treetop::Runtime::SyntaxNode
4
+ def value
5
+ nil
6
+ end
7
+
8
+ def real_player?
9
+ !unknown? && !bot? && !pending? && !console?
10
+ end
11
+
12
+ def unknown?
13
+ false
14
+ end
15
+
16
+ def bot?
17
+ false
18
+ end
19
+
20
+ def pending?
21
+ false
22
+ end
23
+
24
+ def console?
25
+ false
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,46 @@
1
+ module Fonte
2
+ module Nodes
3
+ class SteamIDUniverseNode < Treetop::Runtime::SyntaxNode
4
+ def value
5
+ case universe.text_value.to_i
6
+ when 0
7
+ "Unspecified"
8
+ when 1
9
+ "Public"
10
+ when 2
11
+ "Beta"
12
+ when 3
13
+ "Internal"
14
+ when 4
15
+ "Dev"
16
+ when 5
17
+ "RC"
18
+ end
19
+ end
20
+
21
+ def unspecified?
22
+ value == "Unspecified"
23
+ end
24
+
25
+ def public?
26
+ value == "Public"
27
+ end
28
+
29
+ def beta?
30
+ value == "Beta"
31
+ end
32
+
33
+ def internal?
34
+ value == "Internal"
35
+ end
36
+
37
+ def developer?
38
+ value = "Dev"
39
+ end
40
+
41
+ def rc?
42
+ value == "RC"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,11 @@
1
+ module Fonte
2
+ module Nodes
3
+ autoload :IntegerNode, "fonte/nodes/integer_node"
4
+ autoload :SingleWordNode, "fonte/nodes/single_word_node"
5
+ autoload :DateTimeNode, "fonte/nodes/date_time_node"
6
+ autoload :IpNode, "fonte/nodes/ip_node"
7
+ autoload :SteamIDNode, "fonte/nodes/steam_id_node"
8
+ autoload :SteamIDUniverseNode, "fonte/nodes/steam_id_universe_node"
9
+ autoload :RconCommandNode, "fonte/nodes/rcon_command_node"
10
+ end
11
+ end
@@ -0,0 +1,23 @@
1
+ module Fonte
2
+ module Parsers
3
+ grammar Address
4
+ include Number
5
+
6
+ rule ip
7
+ octet "." octet "." octet "." octet port:port? <Fonte::Nodes::IpNode>
8
+ end
9
+
10
+ rule octet
11
+ [0-9] 1..3
12
+ end
13
+
14
+ rule port
15
+ ":" integer {
16
+ def value
17
+ integer.value
18
+ end
19
+ }
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,90 @@
1
+ module Fonte
2
+ module Parsers
3
+ grammar Log
4
+ include Word
5
+ include Temporal
6
+ include Rcon
7
+
8
+ rule entry
9
+ "L" SPACE date_time ":" SPACE command
10
+ end
11
+
12
+ rule command
13
+ log_started
14
+ / log_ended
15
+ / cvar_start
16
+ / cvar_end
17
+ / cvar_set
18
+ / map_loading
19
+ / map_started
20
+ / server_name
21
+ / server_say
22
+ / rcon_command
23
+ end
24
+
25
+ rule log_ended
26
+ "Log file closed"
27
+ end
28
+
29
+ rule log_started
30
+ "Log file started" SPACE log_filename SPACE log_game_path SPACE log_game_version
31
+ end
32
+
33
+ rule log_filename
34
+ "(file" SPACE quoted_word ")" <Fonte::Nodes::SingleWordNode>
35
+ end
36
+
37
+ rule log_game_path
38
+ "(game" SPACE quoted_word ")" <Fonte::Nodes::SingleWordNode>
39
+ end
40
+
41
+ rule log_game_version
42
+ "(version" SPACE quoted_word ")" <Fonte::Nodes::SingleWordNode>
43
+ end
44
+
45
+ rule cvar_start
46
+ [Ss] "erver cvars start"
47
+ end
48
+
49
+ rule cvar_end
50
+ [Ss] "erver cvars end"
51
+ end
52
+
53
+ rule cvar_set
54
+ ([Ss] "erver cvar" SPACE)? key:quoted_word SPACE "=" SPACE val:quoted_word {
55
+ def name
56
+ key.value
57
+ end
58
+
59
+ def value
60
+ val.value
61
+ end
62
+ }
63
+ end
64
+
65
+ rule map_loading
66
+ "Loading map" SPACE map_name
67
+ end
68
+
69
+ rule map_started
70
+ "Started map" SPACE map_name SPACE "(" map_crc ")"
71
+ end
72
+
73
+ rule map_name
74
+ quoted_word
75
+ end
76
+
77
+ rule map_crc
78
+ "CRC" SPACE quoted_word <Fonte::Nodes::SingleWordNode>
79
+ end
80
+
81
+ rule server_name
82
+ "Server name is" SPACE server_name:quoted_word <Fonte::Nodes::SingleWordNode>
83
+ end
84
+
85
+ rule server_say
86
+ "Server say" SPACE server_say:quoted_word <Fonte::Nodes::SingleWordNode>
87
+ end
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,40 @@
1
+ module Fonte
2
+ module Parsers
3
+ grammar Number
4
+ rule number
5
+ float / integer
6
+ end
7
+
8
+ rule float
9
+ (
10
+ # Scientific notation (eg 5e7, 2.2E-4)
11
+ [+-]? ([0-9]* '.')? [0-9]+ [eE] [+-]? [0-9]+
12
+ /
13
+ # Standard float (eg -43.21, .05)
14
+ [+-]? [0-9]* '.' [0-9]+
15
+ ) {
16
+ def value
17
+ Float(text_value)
18
+ end
19
+ }
20
+ end
21
+
22
+ rule integer
23
+ (
24
+ # Binary (eg 0b101, -0B0010)
25
+ [+-]? '0' [bB] [01]+
26
+ /
27
+ # Hex (eg 0xfff, +0XA30)
28
+ [+-]? '0' [xX] [0-9a-fA-F]+
29
+ /
30
+ # Decimal (eg 27, -421)
31
+ [+-]? [0-9]+
32
+ ) {
33
+ def value
34
+ Integer(text_value)
35
+ end
36
+ }
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,33 @@
1
+ module Fonte
2
+ module Parsers
3
+ grammar Player
4
+ include Number
5
+ include Word
6
+ include SteamID
7
+
8
+ rule player
9
+ nickname "<" uid ">" "<" steam_id ">" "<" team ">"
10
+ end
11
+
12
+ rule nickname
13
+ (![<>] .)* {
14
+ def value
15
+ text_value
16
+ end
17
+ }
18
+ end
19
+
20
+ rule uid
21
+ integer
22
+ end
23
+
24
+ rule team
25
+ (![<>] .)* {
26
+ def value
27
+ text_value == "Unassigned" || text_value == "Console" || text_value == "" ? nil : text_value
28
+ end
29
+ }
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,36 @@
1
+ module Fonte
2
+ module Parsers
3
+ grammar Rcon
4
+ include Word
5
+ include Address
6
+
7
+ rule rcon_command
8
+ rcon_failure / rcon_success
9
+ end
10
+
11
+ rule rcon_success
12
+ "Rcon:" SPACE rcon_challenge <Fonte::Nodes::RconCommandNode>
13
+ end
14
+
15
+ rule rcon_failure
16
+ "Bad Rcon:" SPACE rcon_challenge <Fonte::Nodes::RconCommandNode>
17
+ end
18
+
19
+ rule rcon_challenge
20
+ QUOTE "rcon challenge" SPACE rcon_password SPACE "command" QUOTE SPACE rcon_origin
21
+ end
22
+
23
+ rule rcon_password
24
+ quoted_word
25
+ end
26
+
27
+ rule rcon_origin
28
+ "from" SPACE QUOTE ip QUOTE {
29
+ def value
30
+ ip.value
31
+ end
32
+ }
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,67 @@
1
+ module Fonte
2
+ module Parsers
3
+ grammar SteamID
4
+ include Number
5
+
6
+ rule steam_id
7
+ steam_id_pending
8
+ / steam_id_bot
9
+ / steam_id_console
10
+ / steam_id_invalid
11
+ / universe:steam_universe ":" id_part:steam_id_part ":" account_number:steam_account_number <Fonte::Nodes::SteamIDNode> {
12
+ def value
13
+ text_value
14
+ end
15
+ }
16
+ end
17
+
18
+ rule steam_id_pending
19
+ "STEAM_ID_PENDING" <Fonte::Nodes::SteamIDNode> {
20
+ def pending?
21
+ true
22
+ end
23
+ }
24
+ end
25
+
26
+ rule steam_id_bot
27
+ "Bot" <Fonte::Nodes::SteamIDNode> {
28
+ def bot?
29
+ true
30
+ end
31
+ }
32
+ end
33
+
34
+ rule steam_id_console
35
+ "Console" <Fonte::Nodes::SteamIDNode> {
36
+ def console?
37
+ true
38
+ end
39
+ }
40
+ end
41
+
42
+ rule steam_id_invalid
43
+ "UNKNOWN" <Fonte::Nodes::SteamIDNode> {
44
+ def unknown?
45
+ true
46
+ end
47
+ }
48
+ end
49
+
50
+ rule steam_universe
51
+ "STEAM_" universe:[0-9] <Fonte::Nodes::SteamIDUniverseNode>
52
+ end
53
+
54
+ rule steam_id_part
55
+ [01] {
56
+ def value
57
+ text_value.to_i
58
+ end
59
+ }
60
+ end
61
+
62
+ rule steam_account_number
63
+ integer
64
+ end
65
+ end
66
+ end
67
+ end
@@ -0,0 +1,43 @@
1
+ module Fonte
2
+ module Parsers
3
+ grammar Temporal
4
+ include Word
5
+
6
+ rule date_time
7
+ date SPACE "-" SPACE time <Fonte::Nodes::DateTimeNode>
8
+ end
9
+
10
+ rule date
11
+ month "/" day "/" year
12
+ end
13
+
14
+ rule day
15
+ [0-3] [0-9] <Fonte::Nodes::IntegerNode>
16
+ end
17
+
18
+ rule month
19
+ [0-1] [0-9] <Fonte::Nodes::IntegerNode>
20
+ end
21
+
22
+ rule year
23
+ [0-9] [0-9] [0-9] [0-9] <Fonte::Nodes::IntegerNode>
24
+ end
25
+
26
+ rule time
27
+ hours ":" minutes ":" seconds
28
+ end
29
+
30
+ rule hours
31
+ [0-9] [0-9] <Fonte::Nodes::IntegerNode>
32
+ end
33
+
34
+ rule minutes
35
+ [0-9] [0-9] <Fonte::Nodes::IntegerNode>
36
+ end
37
+
38
+ rule seconds
39
+ [0-9] [0-9] <Fonte::Nodes::IntegerNode>
40
+ end
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,33 @@
1
+ module Fonte
2
+ module Parsers
3
+ grammar Word
4
+ rule quoted_word
5
+ QUOTE word:word? QUOTE {
6
+ def value
7
+ word.value
8
+ end
9
+ }
10
+ end
11
+
12
+ rule word
13
+ (ESCAPED_QUOTE / !QUOTE .)* {
14
+ def value
15
+ text_value
16
+ end
17
+ }
18
+ end
19
+
20
+ rule SPACE
21
+ " "+
22
+ end
23
+
24
+ rule QUOTE
25
+ '"'
26
+ end
27
+
28
+ rule ESCAPED_QUOTE
29
+ '\"'
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,7 @@
1
+ module Fonte
2
+ module Parsers
3
+ %w(number word temporal address rcon steam_id player log).each do |parser|
4
+ Treetop.load File.join(File.dirname(__FILE__), "parsers", parser)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,3 @@
1
+ module Fonte
2
+ VERSION = "0.0.1"
3
+ end
data/lib/fonte.rb ADDED
@@ -0,0 +1,8 @@
1
+ require "fonte/version"
2
+ require "treetop"
3
+ require "polyglot"
4
+ require "fonte/nodes"
5
+ require "fonte/parsers"
6
+
7
+ module Fonte
8
+ end
@@ -0,0 +1,47 @@
1
+ require "spec_helper"
2
+
3
+ module Fonte
4
+ module Parsers
5
+ describe AddressParser do
6
+ let(:parser) { described_class.new }
7
+
8
+ subject { parser.parse(ip) }
9
+
10
+ context "with a valid ip number" do
11
+ let(:ip) { "192.168.10.1" }
12
+ it { should be }
13
+ end
14
+
15
+ context "with a valid ip number and port" do
16
+ let(:ip) { "192.168.10.1:3000" }
17
+ it { should be }
18
+ its(:"port.value") { should == 3000 }
19
+ end
20
+
21
+ context "with a missing octet" do
22
+ let(:ip) { "192.10.1" }
23
+ it { should_not be }
24
+ end
25
+
26
+ context "first octet with more than 8 bits" do
27
+ let(:ip) { "1929.10.1.1" }
28
+ it { should_not be }
29
+ end
30
+
31
+ context "second octet with more than 8 bits" do
32
+ let(:ip) { "192.1110.1.1" }
33
+ it { should_not be }
34
+ end
35
+
36
+ context "first octet with more than 8 bits" do
37
+ let(:ip) { "192.10.1212.1" }
38
+ it { should_not be }
39
+ end
40
+
41
+ context "first octet with more than 8 bits" do
42
+ let(:ip) { "192.10.1.1123" }
43
+ it { should_not be }
44
+ end
45
+ end
46
+ end
47
+ end