Module: Earthquake::Core

Included in:
Earthquake
Defined in:
lib/earthquake/core.rb

Instance Method Summary collapse

Instance Method Details

#__init(options) ⇒ Object



115
116
117
118
119
# File 'lib/earthquake/core.rb', line 115

def __init(options)
  config.merge!(options)
  _init
  _once
end

#_initObject



38
39
40
41
42
43
# File 'lib/earthquake/core.rb', line 38

def _init
  load_config
  load_plugins
  inits.each { |block| class_eval(&block) }
  inits.clear
end

#_onceObject



34
35
36
# File 'lib/earthquake/core.rb', line 34

def _once
  onces.each { |block| class_eval(&block) }
end

#async(&block) ⇒ Object



238
239
240
241
242
243
244
245
246
# File 'lib/earthquake/core.rb', line 238

def async(&block)
  Thread.start do
    begin
      block.call
    rescue Exception => e
      error e
    end
  end
end

#browse(url) ⇒ Object



264
265
266
# File 'lib/earthquake/core.rb', line 264

def browse(url)
  Launchy.open(url)
end

#configObject



6
7
8
# File 'lib/earthquake/core.rb', line 6

def config
  @config ||= {}
end

#default_configObject



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# File 'lib/earthquake/core.rb', line 56

def default_config
  consumer = YAML.load_file(File.expand_path('../../../consumer.yml', __FILE__))
  dir = config[:dir] || File.expand_path('~/.earthquake')
  {
    dir:             dir,
    time_format:     Time::DATE_FORMATS[:short],
    plugin_dir:      File.join(dir, 'plugin'),
    file:            File.join(dir, 'config'),
    prompt:          '',
    consumer_key:    consumer['key'],
    consumer_secret: consumer['secret'],
    api_version:     '1.1',
    secure:          true,
    output_interval: 1,
    history_size:    1000,
    api:             { :host => 'userstream.twitter.com', :path => '/2/user.json', :ssl => true },
    confirm_type:    :y,
    expand_url:      false,
    thread_indent:   "  ",
    no_data_timeout: 30
  }
end

#error(e) ⇒ Object



248
249
250
251
252
253
254
255
# File 'lib/earthquake/core.rb', line 248

def error(e)
  case e
  when Exception
    insert "[ERROR] #{e.message}\n    #{e.backtrace.join("\n    ")}".c(:notice)
  else
    insert "[ERROR] #{e}".c(:notice)
  end
end

#init(&block) ⇒ Object



22
23
24
# File 'lib/earthquake/core.rb', line 22

def init(&block)
  inits << block
end

#initsObject



18
19
20
# File 'lib/earthquake/core.rb', line 18

def inits
  @inits ||= []
end

#invoke(command, options = {}) ⇒ Object



121
122
123
124
# File 'lib/earthquake/core.rb', line 121

def invoke(command, options = {})
  __init(options)
  input(command)
end

#item_queueObject



14
15
16
# File 'lib/earthquake/core.rb', line 14

def item_queue
  @item_queue ||= []
end

#load_configObject



79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/earthquake/core.rb', line 79

def load_config
  config.reverse_update(default_config)

  [config[:dir], config[:plugin_dir]].each do |dir|
    unless File.exists?(dir)
      FileUtils.mkdir_p(dir)
    end
  end

  if File.exists?(config[:file])
    load config[:file]
  else
    File.open(config[:file], mode: 'w', perm: 0600).close
  end

  config.update(preferred_config) do |key, cur, new|
    if Hash === cur and Hash === new
      cur.merge(new)
    else
      new
    end
  end

  get_access_token unless self.config[:token] && self.config[:secret]
end

#load_pluginsObject



105
106
107
108
109
110
111
112
113
# File 'lib/earthquake/core.rb', line 105

def load_plugins
  Dir[File.join(config[:plugin_dir], '*.rb')].each do |lib|
    begin
      require_dependency lib
    rescue Exception => e
      error e
    end
  end
end

#mutexObject



228
229
230
# File 'lib/earthquake/core.rb', line 228

def mutex
  @mutex ||= Mutex.new
end

#notify(message, options = {}) ⇒ Object Also known as: n



257
258
259
260
261
# File 'lib/earthquake/core.rb', line 257

def notify(message, options = {})
  title = options.delete(:title) || 'earthquake'
  message = message.is_a?(String) ? message : message.inspect
  Notify.notify title, message, options
end

#once(&block) ⇒ Object



30
31
32
# File 'lib/earthquake/core.rb', line 30

def once(&block)
  onces << block
end

#oncesObject



26
27
28
# File 'lib/earthquake/core.rb', line 26

def onces
  @once ||= []
end

#preferred_configObject



10
11
12
# File 'lib/earthquake/core.rb', line 10

def preferred_config
  @preferred_config ||= {}
end

#reconnectObject



161
162
163
164
165
166
# File 'lib/earthquake/core.rb', line 161

def reconnect
  item_queue.clear
  start_stream(config[:api])
rescue EventMachine::ConnectionError => e
  # ignore
end

#reloadObject



45
46
47
48
49
50
51
52
53
54
# File 'lib/earthquake/core.rb', line 45

def reload
  Gem.refresh
  loaded = ActiveSupport::Dependencies.loaded.dup
  ActiveSupport::Dependencies.clear
  loaded.each { |lib| require_dependency lib }
rescue Exception => e
  error e
ensure
  _init
end

#restore_historyObject



215
216
217
218
219
220
221
222
223
224
225
226
# File 'lib/earthquake/core.rb', line 215

def restore_history
  history_file = File.join(config[:dir], 'history')
  begin
    File.read(history_file, :encoding => "BINARY").
      encode!(:invalid => :replace, :undef => :replace).
      split(/\n/).
      each { |line| Readline::HISTORY << line }
  rescue Errno::ENOENT
  rescue Errno::EACCES => e
    error(e)
  end
end

#start(options = {}) ⇒ Object



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
# File 'lib/earthquake/core.rb', line 126

def start(options = {})
  __init(options)
  restore_history

  EM.run do
    Thread.start do
      while buf = Readline.readline(config[:prompt], true)
        unless Readline::HISTORY.count == 1
          Readline::HISTORY.pop if buf.empty? || Readline::HISTORY[-1] == Readline::HISTORY[-2]
        end
        sync {
          reload unless config[:reload] == false
          store_history
          input(buf.strip)
        }
      end
      # unexpected
      stop
    end

    EM.add_periodic_timer(config[:output_interval]) do
      if @last_data_received_at && Time.now - @last_data_received_at > config[:no_data_timeout]
        reconnect
      end
      if Readline.line_buffer.nil? || Readline.line_buffer.empty?
        sync { output }
      end
    end

    reconnect unless options[:'no-stream'] == true

    trap('INT') { stop }
  end
end

#start_stream(options) ⇒ Object



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/earthquake/core.rb', line 168

def start_stream(options)
  stop_stream

  options = {
    :oauth => config.slice(:consumer_key, :consumer_secret).merge(
      :access_key => config[:token], :access_secret => config[:secret],
      :proxy => ENV['http_proxy']
    )
  }.merge(options)

  @stream = ::Twitter::JSONStream.connect(options)

  @stream.each_item do |item|
    @last_data_received_at = Time.now # for reconnect when no data
    item_queue << JSON.parse(item)
  end

  @stream.on_error do |message|
    notify "error: #{message}"
  end

  @stream.on_reconnect do |timeout, retries|
    notify "reconnecting in: #{timeout} seconds"
  end

  @stream.on_max_reconnects do |timeout, retries|
    notify "Failed after #{retries} failed reconnects"
  end
end

#stopObject



202
203
204
205
# File 'lib/earthquake/core.rb', line 202

def stop
  stop_stream
  EM.stop_event_loop
end

#stop_streamObject



198
199
200
# File 'lib/earthquake/core.rb', line 198

def stop_stream
  @stream.stop if @stream
end

#store_historyObject



207
208
209
210
211
212
213
# File 'lib/earthquake/core.rb', line 207

def store_history
  history_size = config[:history_size]
  File.open(File.join(config[:dir], 'history'), 'w') do |file|
    lines = Readline::HISTORY.to_a[([Readline::HISTORY.size - history_size, 0].max)..-1]
    file.print(lines.join("\n"))
  end
end

#sync(&block) ⇒ Object



232
233
234
235
236
# File 'lib/earthquake/core.rb', line 232

def sync(&block)
  mutex.synchronize do
    block.call
  end
end