fonte 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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