live_f1-core 0.0.1 → 0.0.2

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