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



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

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

#browse(url) ⇒ Object



266
267
268
# File 'lib/earthquake/core.rb', line 266

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



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

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



230
231
232
# File 'lib/earthquake/core.rb', line 230

def mutex
  @mutex ||= Mutex.new
end

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



259
260
261
262
263
# File 'lib/earthquake/core.rb', line 259

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



165
166
167
168
# File 'lib/earthquake/core.rb', line 165

def reconnect
  item_queue.clear
  start_stream(config[:api])
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



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

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
160
161
162
163
# 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]
        begin
          reconnect
        rescue EventMachine::ConnectionError => e
          # ignore
        end
      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



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
197
198
# File 'lib/earthquake/core.rb', line 170

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



204
205
206
207
# File 'lib/earthquake/core.rb', line 204

def stop
  stop_stream
  EM.stop_event_loop
end

#stop_streamObject



200
201
202
# File 'lib/earthquake/core.rb', line 200

def stop_stream
  @stream.stop if @stream
end

#store_historyObject



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

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



234
235
236
237
238
# File 'lib/earthquake/core.rb', line 234

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