live_f1-core 0.0.1 → 0.0.2

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/CHANGELOG.rdoc ADDED
@@ -0,0 +1,12 @@
1
+ = LiveF1 Changelog
2
+
3
+ == 0.0.2
4
+
5
+ * Removed example binary to separate repo at http://github.com/gareth/live_f1-stream
6
+ * Fixed data logging issue so data will be saved into a replayable file if Source::LiveF1#log_dir is set
7
+ * Handled error which appeared when streaming in the run-up to a session
8
+ * Other bugfixes and refactoring
9
+
10
+ == 0.0.1
11
+
12
+ * Birthday!
data/Gemfile CHANGED
@@ -1,3 +1,15 @@
1
1
  source :gemcutter
2
2
 
3
3
  gemspec
4
+
5
+ # Guard dependencies are here rather than in the gemspec, as gemspec doesn't
6
+ # offer a way to conditionally require gems per platform, like below
7
+ #
8
+ # They aren't development-critical enough to worry about, anyway
9
+ gem 'guard-rspec'
10
+ gem 'guard-cucumber'
11
+
12
+ # `:require => ...` will evaluate to either `false` or the correct library string depending on the platform
13
+ gem 'growl', :require => RUBY_PLATFORM.include?('darwin') && 'growl'
14
+ gem 'rb-fsevent', :require => RUBY_PLATFORM.include?('darwin') && 'rb-fsevent'
15
+ gem 'rb-inotify', :require => RUBY_PLATFORM.include?('linux') && 'rb-inotify'
data/Gemfile.lock CHANGED
@@ -15,6 +15,7 @@ GEM
15
15
  json (>= 1.4.6)
16
16
  diff-lcs (1.1.3)
17
17
  fakeweb (1.3.0)
18
+ ffi (1.1.5)
18
19
  gherkin (2.11.5)
19
20
  json (>= 1.4.6)
20
21
  growl (1.0.3)
@@ -29,7 +30,6 @@ GEM
29
30
  guard-rspec (2.1.0)
30
31
  guard (>= 1.1)
31
32
  rspec (~> 2.11)
32
- hpricot (0.8.6)
33
33
  json (1.7.5)
34
34
  listen (0.5.3)
35
35
  lumberjack (1.0.2)
@@ -38,7 +38,10 @@ GEM
38
38
  coderay (~> 1.0.5)
39
39
  method_source (~> 0.8)
40
40
  slop (~> 3.3.1)
41
+ rake (0.9.2.2)
41
42
  rb-fsevent (0.9.2)
43
+ rb-inotify (0.8.8)
44
+ ffi (>= 0.5.0)
42
45
  rspec (2.11.0)
43
46
  rspec-core (~> 2.11.0)
44
47
  rspec-expectations (~> 2.11.0)
@@ -54,12 +57,13 @@ PLATFORMS
54
57
  ruby
55
58
 
56
59
  DEPENDENCIES
57
- cucumber
58
- fakeweb
60
+ cucumber (~> 1.0)
61
+ fakeweb (~> 1.2, >= 1.2.4)
59
62
  growl
60
63
  guard-cucumber
61
64
  guard-rspec
62
- hpricot
63
65
  live_f1-core!
66
+ rake (>= 0.9)
64
67
  rb-fsevent
65
- rspec
68
+ rb-inotify
69
+ rspec (~> 2.7)
data/README.rdoc CHANGED
@@ -24,10 +24,6 @@ The project uses Bundler, so get all the development dependencies with a simple
24
24
 
25
25
  $ bundle install
26
26
 
27
- == KNOWN ISSUES
28
-
29
- * Currently live binary data is not being logged for playback
30
-
31
27
  == LICENSE
32
28
 
33
29
  (The MIT License)
data/Rakefile CHANGED
@@ -1,6 +1,9 @@
1
+ require 'bundler'
1
2
  require 'cucumber/rake/task'
2
3
  require 'rspec/core/rake_task'
3
4
 
5
+ Bundler::GemHelper.install_tasks
6
+
4
7
  Cucumber::Rake::Task.new(:features) do |t|
5
8
  t.cucumber_opts = "--format progress"
6
9
  end
@@ -20,7 +20,7 @@ module LiveF1
20
20
 
21
21
  def self.from_source source, event_type
22
22
  bytes = source.read_bytes(2)
23
- raise "No data from #{source.inspect}" unless bytes.to_s.length == 2
23
+ raise MissingData, "No data from #{source.inspect}" unless bytes.to_s.length == 2
24
24
  bits = bytes.to_s.reverse.unpack("B*").first
25
25
  _, data, packet_type, car = bits.match(/^(.{7})(.{4})(.{5})$/).to_a.map { |s| s.to_i(2) }
26
26
 
@@ -122,6 +122,9 @@ module LiveF1
122
122
  # An unknown packet is one that we expect (from experience) to appear in the data stream but don't know its purpose
123
123
  class UnknownPacket < RuntimeError
124
124
  end
125
+
126
+ class MissingData < EOFError
127
+ end
125
128
  end
126
129
  end
127
130
  end
@@ -25,7 +25,6 @@ module LiveF1
25
25
  socket.read(num) or raise EOFError
26
26
  end
27
27
  rescue Timeout::Error, Errno::ETIMEDOUT => e
28
- log.flush
29
28
  socket.write("\n")
30
29
  socket.flush
31
30
  retry
@@ -35,6 +34,7 @@ module LiveF1
35
34
  def keyframe number = nil
36
35
  io = open("http://#{HOST}/#{keyframe_filename(number)}")
37
36
  log.keyframe(number, io.read) if number
37
+ log.flush
38
38
  io.rewind
39
39
  Source::Keyframe.new io, self
40
40
  rescue SocketError
@@ -42,6 +42,7 @@ module LiveF1
42
42
  end
43
43
 
44
44
  def decryption_key session_number
45
+ return if session_number.zero?
45
46
  key = open("http://#{HOST}/reg/getkey/#{session_number}.asp?auth=#{auth}").read.to_i(16)
46
47
  raise ConnectionError, "Unable to access session key for session #{session_number}. This could indicate incorrect credentials or an issue with the formula1.com key server" if key.zero?
47
48
  key
@@ -67,10 +68,10 @@ module LiveF1
67
68
  yield packet
68
69
  end
69
70
  rescue Errno::ECONNRESET
70
- log.flush
71
+ log.reset
71
72
  retry
72
73
  rescue Exception
73
- log.flush
74
+ log.reset
74
75
  raise
75
76
  end
76
77
 
@@ -96,11 +97,13 @@ module LiveF1
96
97
  "keyframe#{ "_%05d" % number if number}.bin"
97
98
  end
98
99
 
99
- class LogProxy
100
+ # Wraps a logfile in methods which mean the caller doesn't need to know
101
+ # if a log is currently open or not
102
+ class LogProxy # :nodoc:
100
103
  class << self
101
104
  def start session_number
102
- flush
103
- @log = Log.new session_number
105
+ reset
106
+ @log = Log.new session_number unless session_number.zero?
104
107
  end
105
108
 
106
109
  [:key, :packet, :keyframe].each do |m|
@@ -109,8 +112,14 @@ module LiveF1
109
112
  end
110
113
  end
111
114
 
115
+ # Writes the current logfile to disk
112
116
  def flush
113
117
  @log.flush if @log
118
+ end
119
+
120
+ # Writes the current logfile to disk and then closes the log
121
+ def reset
122
+ flush
114
123
  @log = nil
115
124
  end
116
125
  end
@@ -118,13 +127,14 @@ module LiveF1
118
127
 
119
128
  class Log
120
129
  class << self
121
- attr_reader :dir
130
+ attr_accessor :dir
122
131
 
123
132
  def dir= log_directory
124
133
  @dir = Pathname.new(log_directory).join(Date.today.strftime("%Y%m%d"))
125
134
  FileUtils.mkdir_p(@dir)
126
135
  end
127
136
 
137
+ # Has logging been set up (do we have a log directory to write to)?
128
138
  def active?
129
139
  !!@dir
130
140
  end
@@ -139,18 +149,22 @@ module LiveF1
139
149
  }
140
150
  end
141
151
 
142
- def key k
143
- @data[:key] = k
152
+ # Adds a decryption key to this log
153
+ def key key
154
+ @data[:key] = key
144
155
  end
145
156
 
146
- def packet p
147
- @data[:bytes] << p.header.bytes << p.bytes
157
+ # Adds a packet to this log's bytestream
158
+ def packet packet
159
+ @data[:bytes] << packet.header.bytes << packet.bytes
148
160
  end
149
161
 
150
- def keyframe n, k
151
- @data[:keyframes][n] = k
162
+ # Adds keyframe `n` to this log
163
+ def keyframe number, keyframe_bytes
164
+ @data[:keyframes][number] = keyframe_bytes
152
165
  end
153
166
 
167
+ # Writes this logfile to disk
154
168
  def flush
155
169
  File.open(@filename, "w") { |f| f.write YAML.dump(@data) } if @filename
156
170
  end
@@ -27,6 +27,9 @@ module LiveF1
27
27
  # Decrypts the given string using this session's decryption_key and the
28
28
  # current state of the decryption_salt.
29
29
  def decrypt input
30
+ # Sometimes we don't have a decryption key, e.g. Notice is a
31
+ # decryptable packet but sometimes appears between sessions
32
+ return input unless decryption_key
30
33
  input.bytes.map do |b|
31
34
  self.decryption_salt = (decryption_salt >> 1) ^ ((decryption_salt & 0x01).zero? ? 0 : decryption_key)
32
35
  b ^ (decryption_salt & 0xff)
@@ -1,3 +1,3 @@
1
1
  module LiveF1
2
- VERSION = '0.0.1'
2
+ VERSION = '0.0.2'
3
3
  end
data/live_f1-core.gemspec CHANGED
@@ -15,12 +15,9 @@ Gem::Specification.new do |gem|
15
15
  gem.require_paths = ["lib"]
16
16
  gem.version = LiveF1::VERSION
17
17
 
18
- gem.add_development_dependency "hpricot"
19
- gem.add_development_dependency "rspec"
20
- gem.add_development_dependency "cucumber"
21
- gem.add_development_dependency "guard-rspec"
22
- gem.add_development_dependency "guard-cucumber"
23
- gem.add_development_dependency "growl"
24
- gem.add_development_dependency "fakeweb"
25
- gem.add_development_dependency "rb-fsevent"
18
+ gem.add_development_dependency 'rspec', '~> 2.7'
19
+ gem.add_development_dependency 'cucumber', '~> 1.0'
20
+
21
+ gem.add_development_dependency 'rake', '>= 0.9'
22
+ gem.add_development_dependency 'fakeweb', '~> 1.2', '>= 1.2.4'
26
23
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: live_f1-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,96 +9,48 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-10-24 00:00:00.000000000 Z
12
+ date: 2012-11-02 00:00:00.000000000 Z
13
13
  dependencies:
14
- - !ruby/object:Gem::Dependency
15
- name: hpricot
16
- requirement: !ruby/object:Gem::Requirement
17
- none: false
18
- requirements:
19
- - - ! '>='
20
- - !ruby/object:Gem::Version
21
- version: '0'
22
- type: :development
23
- prerelease: false
24
- version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
- requirements:
27
- - - ! '>='
28
- - !ruby/object:Gem::Version
29
- version: '0'
30
14
  - !ruby/object:Gem::Dependency
31
15
  name: rspec
32
16
  requirement: !ruby/object:Gem::Requirement
33
17
  none: false
34
18
  requirements:
35
- - - ! '>='
19
+ - - ~>
36
20
  - !ruby/object:Gem::Version
37
- version: '0'
21
+ version: '2.7'
38
22
  type: :development
39
23
  prerelease: false
40
24
  version_requirements: !ruby/object:Gem::Requirement
41
25
  none: false
42
26
  requirements:
43
- - - ! '>='
27
+ - - ~>
44
28
  - !ruby/object:Gem::Version
45
- version: '0'
29
+ version: '2.7'
46
30
  - !ruby/object:Gem::Dependency
47
31
  name: cucumber
48
32
  requirement: !ruby/object:Gem::Requirement
49
33
  none: false
50
34
  requirements:
51
- - - ! '>='
52
- - !ruby/object:Gem::Version
53
- version: '0'
54
- type: :development
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
- requirements:
59
- - - ! '>='
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- - !ruby/object:Gem::Dependency
63
- name: guard-rspec
64
- requirement: !ruby/object:Gem::Requirement
65
- none: false
66
- requirements:
67
- - - ! '>='
68
- - !ruby/object:Gem::Version
69
- version: '0'
70
- type: :development
71
- prerelease: false
72
- version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
- requirements:
75
- - - ! '>='
76
- - !ruby/object:Gem::Version
77
- version: '0'
78
- - !ruby/object:Gem::Dependency
79
- name: guard-cucumber
80
- requirement: !ruby/object:Gem::Requirement
81
- none: false
82
- requirements:
83
- - - ! '>='
35
+ - - ~>
84
36
  - !ruby/object:Gem::Version
85
- version: '0'
37
+ version: '1.0'
86
38
  type: :development
87
39
  prerelease: false
88
40
  version_requirements: !ruby/object:Gem::Requirement
89
41
  none: false
90
42
  requirements:
91
- - - ! '>='
43
+ - - ~>
92
44
  - !ruby/object:Gem::Version
93
- version: '0'
45
+ version: '1.0'
94
46
  - !ruby/object:Gem::Dependency
95
- name: growl
47
+ name: rake
96
48
  requirement: !ruby/object:Gem::Requirement
97
49
  none: false
98
50
  requirements:
99
51
  - - ! '>='
100
52
  - !ruby/object:Gem::Version
101
- version: '0'
53
+ version: '0.9'
102
54
  type: :development
103
55
  prerelease: false
104
56
  version_requirements: !ruby/object:Gem::Requirement
@@ -106,56 +58,45 @@ dependencies:
106
58
  requirements:
107
59
  - - ! '>='
108
60
  - !ruby/object:Gem::Version
109
- version: '0'
61
+ version: '0.9'
110
62
  - !ruby/object:Gem::Dependency
111
63
  name: fakeweb
112
64
  requirement: !ruby/object:Gem::Requirement
113
65
  none: false
114
66
  requirements:
115
- - - ! '>='
116
- - !ruby/object:Gem::Version
117
- version: '0'
118
- type: :development
119
- prerelease: false
120
- version_requirements: !ruby/object:Gem::Requirement
121
- none: false
122
- requirements:
123
- - - ! '>='
67
+ - - ~>
124
68
  - !ruby/object:Gem::Version
125
- version: '0'
126
- - !ruby/object:Gem::Dependency
127
- name: rb-fsevent
128
- requirement: !ruby/object:Gem::Requirement
129
- none: false
130
- requirements:
69
+ version: '1.2'
131
70
  - - ! '>='
132
71
  - !ruby/object:Gem::Version
133
- version: '0'
72
+ version: 1.2.4
134
73
  type: :development
135
74
  prerelease: false
136
75
  version_requirements: !ruby/object:Gem::Requirement
137
76
  none: false
138
77
  requirements:
78
+ - - ~>
79
+ - !ruby/object:Gem::Version
80
+ version: '1.2'
139
81
  - - ! '>='
140
82
  - !ruby/object:Gem::Version
141
- version: '0'
83
+ version: 1.2.4
142
84
  description: Parses raw events from the Formula1.com live timing stream
143
85
  email:
144
86
  - g@rethada.ms
145
- executables:
146
- - live_f1_example
87
+ executables: []
147
88
  extensions: []
148
89
  extra_rdoc_files: []
149
90
  files:
150
91
  - .autotest
151
92
  - .gitignore
152
93
  - .rspec
94
+ - CHANGELOG.rdoc
153
95
  - Gemfile
154
96
  - Gemfile.lock
155
97
  - Guardfile
156
98
  - README.rdoc
157
99
  - Rakefile
158
- - bin/live_f1_example
159
100
  - features/fixtures/sessions/2012.03.china.qualifying/7136/keyframes.yaml
160
101
  - features/fixtures/sessions/2012.03.china.qualifying/7136/session.key
161
102
  - features/fixtures/sessions/2012.03.china.qualifying/session.bin
@@ -334,4 +275,3 @@ test_files:
334
275
  - spec/live_f1/source_spec.rb
335
276
  - spec/spec_helper.rb
336
277
  - spec/support/packet_type_examples.rb
337
- has_rdoc:
data/bin/live_f1_example DELETED
@@ -1,74 +0,0 @@
1
- #!/usr/bin/env ruby
2
- require 'rubygems'
3
- require 'optparse'
4
- require 'highline'
5
-
6
- $: << File.join(File.dirname(__FILE__), '..', 'lib')
7
- require 'live_f1'
8
-
9
- options = {}
10
- OptionParser.new do |opts|
11
- opts.separator ""
12
- opts.separator "Specific options:"
13
-
14
- opts.on("-f LOGFILE", "--file", "Replays the given previously recorded .f1 data file (if not specified, will attempt to connect to the live timing server)") do |logfile|
15
- options[:logfile] = logfile
16
- end
17
- opts.on("-u USERNAME", "--username", "For live connections, specify the formula1.com live timing username") do |username|
18
- options[:username] = username
19
- end
20
- opts.on("-p [PASSWORD]", "--password", "For live connections, specify the formula1.com live timing password. Omitting the password will cause live-f1 to prompt for it.") do |password|
21
- unless password
22
- prompt = HighLine.new
23
- password = prompt.ask("Password: ") { |q| q.echo = false }
24
- end
25
- options[:password] = password
26
- end
27
- opts.on("-d", "--debug", "Display bit data from each data packet's header") do
28
- LiveF1.debug = true
29
- end
30
-
31
- opts.on_tail("-h", "--help", "Show this message") do
32
- puts opts
33
- exit
34
- end
35
-
36
- end.parse!
37
-
38
- if options[:logfile]
39
-
40
- timestamp = nil
41
- packets = []
42
-
43
- source = LiveF1::Source::Log.new(File.open(options[:logfile]))
44
- source.run do |packet|
45
- packets << packet
46
- case packet
47
- when LiveF1::Packet::Sys::Timestamp
48
- t_start = timestamp || packet.number
49
- t_end = packet.number
50
- t_diff = t_end - t_start
51
-
52
- # The interval is the difference in time between the last 2 timestamps, divided
53
- # by the number of packets between the timestamps. This is then divided by 4 to
54
- # speed up the replay
55
- interval = t_diff.to_f / (packets.length) / 8
56
- packets.pop # Remove the timestamp packet from the output queue
57
- while p = packets.shift
58
- puts p.inspect
59
- sleep interval
60
- end
61
- timestamp = packet.number
62
- end
63
- end
64
-
65
- else
66
-
67
- source = LiveF1::Source::Live.new(options[:username], options[:password])
68
- source.log_dir = "./data"
69
- source.run do |packet|
70
- puts packet.inspect
71
- end
72
-
73
- end
74
-