Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Update (no new features)

  • Loading branch information...
commit 2c56dbdb9b19584c5f3bc2ced20c684bd84fa46f 1 parent 5d2a13a
rhenium rhenium authored
1  .gitignore
@@ -24,6 +24,7 @@
24 24
25 25 # local scripts
26 26 /client/worker.sh
  27 +/client/Procfile
27 28 /client/settings.yml
28 29 /server.sh
29 30
1  Gemfile
@@ -5,6 +5,7 @@ gem 'rails', '4.0.0.beta1'
5 5 gem 'mysql2'
6 6
7 7 gem 'unicorn'
  8 +gem 'daemon-spawn', :require => 'daemon_spawn'
8 9
9 10 gem 'rails_config'
10 11 gem 'kaminari'
2  Gemfile.lock
@@ -43,6 +43,7 @@ GEM
43 43 coffee-script-source
44 44 execjs
45 45 coffee-script-source (1.6.1)
  46 + daemon-spawn (0.4.2)
46 47 em-twitter (0.2.1)
47 48 eventmachine (~> 1.0)
48 49 http_parser.rb (~> 0.5)
@@ -153,6 +154,7 @@ PLATFORMS
153 154
154 155 DEPENDENCIES
155 156 coffee-rails (~> 4.0.0.beta1)
  157 + daemon-spawn
156 158 em-twitter
157 159 em-work_queue
158 160 haml-rails
9 app/helpers/application_helper.rb
@@ -7,14 +7,15 @@ def format_tweet_created_at(dt)
7 7
8 8 def format_tweet_text(text)
9 9 text
10   - .gsub(/<url:((?:https?|ftp).+?):(.+?)>/){link_to($2, $1, :target => "_blank")}
11   - .gsub(/<hashtag:(.+?)>/){link_to("##{URI.decode($1)}", "https://twitter.com/search?q=%23#{$1}")}
12   - .gsub(/<mention:(.+?)>/){link_to("@#{$1}", "/#{$1}")}
  10 + .gsub(/<url:(.+?):(.+?)>/){link_to(CGI.unescape($2), CGI.unescape($1), :target => "_blank")}
  11 + .gsub(/<hashtag:(.+?)>/){link_to("##{CGI.unescape($1)}", "https://twitter.com/search?q=%23#{$1}")}
  12 + .gsub(/<cashtag:(.+?)>/){link_to("$#{CGI.unescape($1)}", "https://twitter.com/search?q=%23#{$1}")}
  13 + .gsub(/<mention:(.+?)>/){link_to("@#{CGI.unescape($1)}", "/#{$1}")}
13 14 .gsub(/\r\n|\r|\n/, "<br />")
14 15 end
15 16
16 17 def format_source_text(text)
17   - text.gsub("&", "&amp;")
  18 + format_tweet_text(text)
18 19 end
19 20
20 21 def status_url(tweet)
14 app/views/main/index.haml
@@ -3,21 +3,27 @@
3 3 %p
4 4 Favstar クローンです。UserStreams つかってます。
5 5 = link_to "@KOBA789", "https://twitter.com/KOBA789"
6   - さんにサーバーを貸していただけることになりました…!!
  6 + さんにサーバーを貸していただけることになりました…!!ありがとうございます!
7 7 %strong まだ開発途中段階のものですがとりあえず動いています。登録後接続まで最大30分かかります。
8 8 %strong 動作のテスト中ですので、途中で登録をうちきったりあまりにふぁぼられ・ふぁぼりが多いユーザーの登録を削除する可能性もあります。
9 9 %div
10 10 URLとかについて
11 11 %div
12 12 best:
13   - = link_to "(/users)/re4k", "/re4k"
  13 + = link_to "/cat", "/cat"
14 14 %div
15 15 recent:
16   - = link_to "(/users)/re4k/recent", "/re4k/recent"
  16 + = link_to "/cat/recent", "/cat/recent"
  17 + %div
  18 + timeline(exclude RTs):
  19 + = link_to "/cat/timeline", "/cat/timeline"
  20 + %div
  21 + discovery:
  22 + = link_to "/cat/my", "/cat/my"
17 23 %div
18 24 こんどほかのところもFavstar互換にする
19 25 %div
20 26 デザインなんとかしないと...
21 27 %div
22   - = link_to "@re4k", "https://twitter.com/re4k"
  28 + = link_to "@cat", "https://twitter.com/cat"
23 29
4 client/Gemfile
... ... @@ -1,6 +1,8 @@
1 1 ruby '1.9.3'
2 2 source 'https://rubygems.org'
3 3
  4 +gem 'foreman'
  5 +
4 6 gem 'settingslogic'
5   -gem 'em-twitter'
  7 +gem 'tweetstream'
6 8 gem 'yajl-ruby', :require => "yajl"
31 client/Gemfile.lock
... ... @@ -1,20 +1,49 @@
1 1 GEM
2 2 remote: https://rubygems.org/
3 3 specs:
  4 + addressable (2.3.3)
  5 + cookiejar (0.3.0)
  6 + daemons (1.1.9)
  7 + em-http-request (1.0.3)
  8 + addressable (>= 2.2.3)
  9 + cookiejar
  10 + em-socksify
  11 + eventmachine (>= 1.0.0.beta.4)
  12 + http_parser.rb (>= 0.5.3)
  13 + em-socksify (0.2.1)
  14 + eventmachine (>= 1.0.0.beta.4)
4 15 em-twitter (0.2.1)
5 16 eventmachine (~> 1.0)
6 17 http_parser.rb (~> 0.5)
7 18 simple_oauth (~> 0.1)
8 19 eventmachine (1.0.3)
  20 + faraday (0.8.6)
  21 + multipart-post (~> 1.1)
  22 + foreman (0.62.0)
  23 + thor (>= 0.13.6)
9 24 http_parser.rb (0.5.3)
  25 + multi_json (1.6.1)
  26 + multipart-post (1.2.0)
10 27 settingslogic (2.0.9)
11 28 simple_oauth (0.2.0)
  29 + thor (0.17.0)
  30 + tweetstream (2.4.0)
  31 + daemons (~> 1.1)
  32 + em-http-request (~> 1.0.2)
  33 + em-twitter (~> 0.2)
  34 + twitter (~> 4.0)
  35 + yajl-ruby (~> 1.1)
  36 + twitter (4.6.0)
  37 + faraday (~> 0.8, < 0.10)
  38 + multi_json (~> 1.0)
  39 + simple_oauth (~> 0.2)
12 40 yajl-ruby (1.1.0)
13 41
14 42 PLATFORMS
15 43 ruby
16 44
17 45 DEPENDENCIES
18   - em-twitter
  46 + foreman
19 47 settingslogic
  48 + tweetstream
20 49 yajl-ruby
10 client/start.rb
... ... @@ -0,0 +1,10 @@
  1 +#!/usr/bin/env ruby
  2 +require "./worker"
  3 +
  4 +$stdout.sync = true
  5 +$stderr.sync = true
  6 +
  7 +worker = Worker.new
  8 +worker.start
  9 +
  10 +
306 client/worker.rb
... ... @@ -1,105 +1,135 @@
1 1 require "time"
2   -require "cgi"
3   -require "em-twitter"
  2 +require "tweetstream"
4 3 require "yajl"
5 4 require "./settings"
6 5 require "./logger"
7 6
  7 +module EM
  8 + class Connection
  9 + def send_chunk(data)
  10 + send_data(data + "\r\n")
  11 + end
  12 + end
  13 +end
  14 +
  15 +module TweetStream
  16 + class Client
  17 + attr_reader :user_id, :row_id
  18 +
  19 + def _set_aclog(user_id, row_id)
  20 + @user_id = user_id
  21 + @row_id = row_id
  22 + end
  23 + end
  24 +end
  25 +
8 26 class Worker
9 27 class DBProxyClient < EM::Connection
10 28 def initialize
11   - super
12   - @connections = []
  29 + @clients = []
13 30 @receive_buf = ""
14 31 end
15 32
16   - def format_text_from_hash(hash)
17   - text = hash[:text]
18   - entities = hash[:entities]
19   -
20   - return text unless entities
21   -
22   - gaps = {}
23   - replace = -> ents, bl do
24   - ents.each do |entity|
25   - starts = entity[:indices].first
26   - ends = entity[:indices].last
27   - rep = bl.call(entity)
28   - gaps[starts] = rep.size - (ends - starts)
29   - bgap = gaps.select{|k, v| k < starts}.values.inject(0){|s, m| s += m}
30   - text[starts + bgap...ends + bgap] = rep
31   - end
  33 + def format_text(status)
  34 + chars = status.text.to_s.split(//)
  35 +
  36 + entities = status.attrs[:entities].values.flatten.map do |entity|
  37 + entity[:hashtag] = entity[:text] if entity[:text]
  38 + entity
  39 + end.sort_by{|entity| entity[:indices].first}
  40 +
  41 + result = []
  42 + last_index = entities.inject(0) do |last_index, entity|
  43 + result << chars[last_index...entity[:indices].first]
  44 + result << if entity[:url]
  45 + "<url:#{CGI.escape(entity[:expanded_url])}:#{CGI.escape(entity[:display_url])}>"
  46 + elsif entity[:hashtag]
  47 + "<hashtag:#{CGI.escape(entity[:hashtag])}>"
  48 + elsif entity[:screen_name]
  49 + "<mention:#{CGI.escape(entity[:screen_name])}>"
  50 + elsif entity[:cashtag]
  51 + "<cashtag:#{CGI.escape(entity[:cashtag])}>"
  52 + end
  53 + entity[:indices].last
32 54 end
  55 + result << chars[last_index..-1]
33 56
34   - replace.call((entities[:media] || []) + (entities[:urls] || []),
35   - -> entity {"<url:#{CGI.escapeHTML(entity[:expanded_url])}:#{CGI.escapeHTML(entity[:display_url])}>"})
36   - replace.call(entities[:hashtags] || [],
37   - -> entity {"<hashtag:#{CGI.escapeHTML(URI.encode(entity[:text]))}>"})
38   - replace.call(entities[:user_mentions] || [],
39   - -> entity {"<mention:#{CGI.escapeHTML(URI.encode(entity[:screen_name]))}>"})
40   -
41   - return text
  57 + result.flatten.join
42 58 end
43 59
44   - def format_source(source)
45   - source
  60 + def format_source(status)
  61 + if status.source.index("<a")
  62 + url = status.source.scan(/href="(.+?)"/).flatten.first
  63 + name = status.source.scan(/>(.+?)</).flatten.first
  64 + "<url:#{CGI.escape(url)}:#{CGI.escape(name)}>"
  65 + else
  66 + status.source
  67 + end
46 68 end
47 69
48   - def send_user(hash)
49   - out = {:id => hash[:id],
50   - :screen_name => hash[:screen_name],
51   - :name => hash[:name],
52   - :profile_image_url => hash[:profile_image_url_https]}
53   - send_data("USER #{Yajl::Encoder.encode(out)}\r\n")
  70 + def send_user(user)
  71 + out = {:id => user.id,
  72 + :screen_name => user.screen_name,
  73 + :name => user.name,
  74 + :profile_image_url => user.profile_image_url_https}
  75 + send_chunk("USER #{Yajl::Encoder.encode(out)}")
54 76 end
55 77
56   - def send_tweet(hash)
57   - send_user(hash[:user])
58   - out = {:id => hash[:id],
59   - :text => format_text_from_hash(hash),
60   - :source => format_source(hash[:source]),
61   - :tweeted_at => hash[:created_at],
62   - :user_id => hash[:user][:id]}
63   - send_data("TWEET #{Yajl::Encoder.encode(out)}\r\n")
  78 + def send_tweet(status)
  79 + send_user(status.user)
  80 + out = {:id => status.id,
  81 + :text => format_text(status),
  82 + :source => format_source(status),
  83 + :tweeted_at => status.created_at,
  84 + :user_id => status.user.id}
  85 + send_chunk("TWEET #{Yajl::Encoder.encode(out)}")
  86 + $logger.debug("Sent Tweet: #{status.id}")
64 87 end
65 88
66   - def send_favorite(hash)
67   - send_tweet(hash[:target_object])
68   - send_user(hash[:source])
69   - out = {:tweet_id => hash[:target_object][:id],
70   - :user_id => hash[:source][:id]}
71   - send_data("FAVORITE #{Yajl::Encoder.encode(out)}\r\n")
  89 + def send_favorite(source, target_object)
  90 + send_tweet(target_object)
  91 + send_user(source)
  92 + out = {:tweet_id => target_object.id,
  93 + :user_id => source.id}
  94 + send_chunk("FAVORITE #{Yajl::Encoder.encode(out)}")
  95 + $logger.debug("Sent Favorite: #{source.id} => #{target_object.id}")
72 96 end
73 97
74   - def send_unfavorite(hash)
75   - send_tweet(hash[:target_object])
76   - send_user(hash[:source])
77   - out = {:tweet_id => hash[:target_object][:id],
78   - :user_id => hash[:source][:id]}
79   - send_data("UNFAVORITE #{Yajl::Encoder.encode(out)}\r\n")
  98 + def send_unfavorite(source, target_object)
  99 + send_tweet(target_object)
  100 + send_user(source)
  101 + out = {:tweet_id => target_object.id,
  102 + :user_id => source.id}
  103 + send_chunk("UNFAVORITE #{Yajl::Encoder.encode(out)}")
  104 + $logger.debug("Sent Unfavorite: #{source.id} => #{target_object.id}")
80 105 end
81 106
82   - def send_retweet(hash)
83   - send_tweet(hash[:retweeted_status])
84   - out = {:id => hash[:id],
85   - :tweet_id => hash[:id],
86   - :user_id => hash[:user][:id]}
87   - send_data("RETWEET #{Yajl::Encoder.encode(out)}\r\n")
  107 + def send_retweet(status)
  108 + send_tweet(status.retweeted_status)
  109 + out = {:id => status.id,
  110 + :tweet_id => status.retweeted_status.id,
  111 + :user_id => status.user.id}
  112 + send_chunk("RETWEET #{Yajl::Encoder.encode(out)}")
  113 + $logger.debug("Sent Retweet: #{status.user.id} => #{status.retweeted_status.id}")
88 114 end
89 115
90   - def send_delete(hash)
91   - out = {:tweet_id => hash[:delete][:status][:id],
92   - :user_id => hash[:delete][:status][:user_id]}
93   - send_data("DELETE #{Yajl::Encoder.encode(out)}\r\n")
  116 + def send_delete(status_id, user_id)
  117 + out = {:tweet_id => status_id,
  118 + :user_id => user_id}
  119 + send_chunk("DELETE #{Yajl::Encoder.encode(out)}")
  120 + $logger.debug("Sent Delete: #{user_id} => #{status_id}")
94 121 end
95 122
96 123 def post_init
97   - send_data("CONNECT #{Settings.secret_key}&#{Settings.worker_number}&#{Settings.worker_count}\r\n")
  124 + send_chunk("CONNECT #{Settings.secret_key}&#{Settings.worker_number}&#{Settings.worker_count}")
98 125 end
99 126
100 127 def unbind
101 128 $logger.info("Connection closed")
102   - reconnect(@options[:host], @options[:port])
  129 + EM.add_timer(5) do
  130 + reconnect(Settings.db_proxy_host, Settings.db_proxy_port)
  131 + post_init
  132 + end
103 133 end
104 134
105 135 def receive_data(data)
@@ -115,114 +145,75 @@ def receive_data(data)
115 145 $logger.error("Error: #{arg.last}")
116 146 when "ACCOUNT"
117 147 begin
118   - p arg
119 148 hash = ::Yajl::Parser.parse(arg.last, :symbolize_keys => true)
120   - con = EM::Twitter::Client.connect({
121   - :host => "userstream.twitter.com",
122   - :path => "/1.1/user.json",
123   - :oauth => {:consumer_key => Settings.consumer_key,
124   - :consumer_secret => Settings.consumer_secret,
125   - :token => hash[:oauth_token],
126   - :token_secret => hash[:oauth_token_secret]},
127   - :method => "GET",
128   - # user data
129   - :user_id => hash[:user_id]
130   - })
131   -
132   - con.on_reconnect do |timeout, count|
133   - $logger.warn("Reconnected: #{con.options[:user_id]}/#{count}")
  149 +
  150 + @clients << client = TweetStream::Client.new(
  151 + :consumer_key => Settings.consumer_key,
  152 + :consumer_secret => Settings.consumer_secret,
  153 + :oauth_token => hash[:oauth_token],
  154 + :oauth_token_secret => hash[:oauth_token_secret],
  155 + :auth_method => :oauth)
  156 + client._set_aclog(hash[:user_id], hash[:id])
  157 +
  158 + client.on_error do |message|
  159 + $logger.warn("UserStreams Error(##{client.user_id}): #{message}")
134 160 end
135 161
136   - con.on_max_reconnects do |timeout, count|
137   - $logger.error("Reached Max Reconnects: #{con.options[:user_id]}")
  162 + client.on_limit do |discarded_count|
  163 + $logger.warn("UserStreams Limit Event(##{client.user_id}): #{discarded_count}")
138 164 end
139 165
140   - con.on_unauthorized do
141   - $logger.error("Unauthorized: #{con.options[:user_id]}")
142   - @connections.delete(con)
143   - con.stop
  166 + client.on_unauthorized do
  167 + # revoked?
  168 + $logger.warn("Unauthorized(##{client.user_id})")
  169 + send_chunk("UNAUTHORISED #{client.row_id}&#{client.user_id}")
  170 + client.stop_stream
  171 + @clients.delete(client)
144 172 end
145 173
146   - con.on_forbidden do
147   - $logger.error("Forbidden: #{con.options[:user_id]}")
148   - @connections.delete(con)
  174 + client.on_enhance_your_calm do
  175 + # limit?
  176 + $logger.warn("Enhance your calm(##{client.user_id})")
149 177 end
150 178
151   - con.on_not_found do
152   - $logger.error("Not Found: #{con.options[:user_id]}")
153   - @connections.delete(con)
  179 + client.on_no_data_received do
  180 + # (?)
  181 + $logger.warn("No data received(##{client.user_id})")
  182 + client.close_connection
154 183 end
155 184
156   - con.on_not_acceptable do
157   - $logger.error("Not Acceptable: #{con.options[:user_id]}")
  185 + client.on_reconnect do |timeout, retries|
  186 + $logger.warn("Reconnected(##{client.user_id}): #{retries}")
158 187 end
159 188
160   - con.on_too_long do
161   - $logger.error("Too Long: #{con.options[:user_id]}")
  189 + client.on_stall_warning do |warning|
  190 + $logger.info("Stall warning(##{client.user_id}): #{warning}")
162 191 end
163 192
164   - con.on_range_unacceptable do
165   - $logger.error("Range Unacceptable: #{con.options[:user_id]}")
  193 + client.on_timeline_status do |status|
  194 + # tweets. includes retweets
  195 + if status.retweeted_status && (status.retweeted_status.user.id == client.user_id ||
  196 + status.user.id == client.user_id)
  197 + send_retweet(status)
  198 + elsif status.user.id == client.user_id
  199 + send_tweet(status)
  200 + end
166 201 end
167 202
168   - con.on_enhance_your_calm do
169   - $logger.error("Enhance Your Calm: #{con.options[:user_id]}")
170   - @connections.delete(con)
  203 + client.on_event(:favorite) do |event|
  204 + send_favorite(Twitter::User.new(event[:source]), Twitter::Tweet.new(event[:target_object]))
171 205 end
172 206
173   - con.on_error do |message|
174   - $logger.error("Unknown: #{con.options[:user_id]}/#{message}")
  207 + client.on_event(:unfavorite) do |event|
  208 + send_unfavorite(Twitter::User.new(event[:source]), Twitter::Tweet.new(event[:target_object]))
175 209 end
176 210
177   - con.each do |chunk|
178   - begin # convert error
179   - begin
180   - status = ::Yajl::Parser.parse(chunk, :symbolize_keys => true)
181   - rescue ::Yajl::ParseError
182   - $logger.warn("::Yajl::ParseError in stream: #{chunk}")
183   - next
184   - end
185   -
186   - if status.is_a?(::Hash)
187   - if status.key?(:user)
188   - if status[:user][:id] == con.options[:user_id] &&
189   - !status.key?(:retweeted_status)
190   - send_tweet(status)
191   - $logger.debug("Created Tweet")
192   - elsif status.key?(:retweeted_status) &&
193   - (status[:retweeted_status][:user][:id] == con.options[:user_id] ||
194   - status[:user][:id] == con.options[:user_id])
195   - send_retweet(status)
196   - $logger.debug("Created Retweet")
197   - end
198   - elsif status[:event] == "favorite"
199   - if status[:target_object][:user] &&
200   - (!status[:target_object][:user][:protected] ||
201   - status[:target_object][:user][:id] == con.options[:user_id])
202   - send_favorite(status)
203   - $logger.debug("Created Favorite")
204   - end
205   - elsif status[:event] == "unfavorite"
206   - send_unfavorite(status)
207   - $logger.debug("Destroyed Favorite")
208   - elsif status.key?(:delete) && status[:delete].key?(:status)
209   - send_delete(status)
210   - $logger.debug("Destroyed Tweet: #{status[:delete][:status][:id]}/#{status[:delete][:status][:user_id]}")
211   - else
212   - # monyo
213   - end
214   - else
215   - $logger.warn("Unexpected object in stream: #{status}")
216   - next
217   - end
218   - rescue # debug
219   - $logger.error($!)
220   - $logger.error($@)
221   - end
  211 + client.on_delete do |status_id, user_id|
  212 + send_delete(status_id, user_id)
222 213 end
223 214
224   - $logger.info("User connected: #{con.options[:user_id]}")
225   - @connections << con
  215 + client.userstream
  216 + $logger.info("Connected(##{client.user_id})")
226 217 rescue ::Yajl::ParseError
227 218 $logger.error("JSON Parse Error: #{json}")
228 219 end
@@ -231,8 +222,8 @@ def receive_data(data)
231 222 end
232 223
233 224 def stop_all
234   - @connections.map(&:stop)
235   - send_data("QUIT\r\n")
  225 + @clients.map(&:stop_stream)
  226 + send_chunk("QUIT")
236 227 end
237 228 end
238 229
@@ -243,13 +234,14 @@ def initialize
243 234 def start
244 235 $logger.info("Worker ##{Settings.worker_number} started")
245 236 EM.run do
  237 + connection = EM.connect(Settings.db_proxy_host, Settings.db_proxy_port, DBProxyClient)
  238 +
246 239 stop = Proc.new do
  240 + connection.stop_all
247 241 EM.stop
248 242 end
249 243 Signal.trap(:INT, &stop)
250 244 Signal.trap(:TERM, &stop)
251   -
252   - EM.connect(Settings.db_proxy_host, Settings.db_proxy_port, DBProxyClient)
253 245 end
254 246 end
255 247 end
63 config/database.yml
... ... @@ -1,13 +1,52 @@
1   -<% #development:
2   - #test:
3   - #production:
4   - # adapter: mysql2
5   - # encoding: utf8
6   - # reconnect: true
7   - # database: production
8   - # pool: 5
9   - # username: <%= ENV["DOTCLOUD_DB_MYSQL_LOGIN"] %>
10   - # password: <%= ENV["DOTCLOUD_DB_MYSQL_PASSWORD"] %>
11   - # host: <%= ENV["DOTCLOUD_DB_MYSQL_HOST"] %>
12   - # port: <%= ENV["DOTCLOUD_DB_MYSQL_PORT"] %>
  1 +<%
  2 +require 'cgi'
  3 +require 'uri'
  4 +
  5 +begin
  6 + uri = URI.parse(ENV["DATABASE_URL"])
  7 +rescue URI::InvalidURIError
  8 + raise "Invalid DATABASE_URL"
  9 +end
  10 +
  11 +raise "No RACK_ENV or RAILS_ENV found" unless ENV["RAILS_ENV"] || ENV["RACK_ENV"]
  12 +
  13 +def attribute(name, value, force_string = false)
  14 + if value
  15 + value_string =
  16 + if force_string
  17 + '"' + value + '"'
  18 + else
  19 + value
  20 + end
  21 + "#{name}: #{value_string}"
  22 + else
  23 + ""
  24 + end
  25 +end
  26 +
  27 +adapter = uri.scheme
  28 +adapter = "postgresql" if adapter == "postgres"
  29 +
  30 +database = (uri.path || "").split("/")[1]
  31 +
  32 +username = uri.user
  33 +password = uri.password
  34 +
  35 +host = uri.host
  36 +port = uri.port
  37 +
  38 +params = CGI.parse(uri.query || "")
  39 +
13 40 %>
  41 +
  42 +<%= ENV["RAILS_ENV"] || ENV["RACK_ENV"] %>:
  43 + <%= attribute "adapter", adapter %>
  44 + <%= attribute "database", database %>
  45 + <%= attribute "username", username %>
  46 + <%= attribute "password", password, true %>
  47 + <%= attribute "host", host %>
  48 + <%= attribute "port", port %>
  49 +
  50 +<% params.each do |key, value| %>
  51 + <%= key %>: <%= value.first %>
  52 +<% end %>
14 config/routes.rb
@@ -10,12 +10,12 @@
10 10 get "i/logout" => "sessions#destroy"
11 11
12 12 get "i/:id" => "i#show", :constraints => constraints
13   - get "(users)/:screen_name/status(es)/:id" => "i#show", :constraints => constraints
  13 + get ":screen_name/status(es)/:id" => "i#show", :constraints => constraints
14 14
15   - get "(users)/:screen_name(/:page)" => "users#best", :constraints => constraints
16   - get "(users)/:screen_name/my(/:page)" => "users#my", :constraints => constraints
17   - get "(users)/:screen_name/discovered(/:page)" => "users#my", :constraints => constraints
18   - get "(users)/:screen_name/timeline(/:page)" => "users#timeline", :constraints => constraints
19   - get "(users)/:screen_name/recent(/:page)" => "users#recent", :constraints => constraints
20   - get "(users)/:screen_name/info(/:page)" => "users#info", :constraints => constraints
  15 + get ":screen_name(/:page)" => "users#best", :constraints => constraints
  16 + get ":screen_name/my(/:page)" => "users#my", :constraints => constraints
  17 + get ":screen_name/discovered(/:page)" => "users#my", :constraints => constraints
  18 + get ":screen_name/timeline(/:page)" => "users#timeline", :constraints => constraints
  19 + get ":screen_name/recent(/:page)" => "users#recent", :constraints => constraints
  20 + get ":screen_name/info(/:page)" => "users#info", :constraints => constraints
21 21 end
6 lib/receiver/start.rb
... ... @@ -0,0 +1,6 @@
  1 +Receiver::Worker.spawn!({:working_dir => Rails.root,
  2 + :pid_file => File.join(Rails.root, "tmp", "pids", "receiver.pid"),
  3 + :log_file => File.join(Rails.root, "log", "receiver.log"),
  4 + :sync_log => true,
  5 + :singleton => true})
  6 +
23 lib/receiver/worker.rb
@@ -8,11 +8,12 @@ def send_chunk(data)
8 8 end
9 9 end
10 10
11   -class Receiver::Worker
  11 +class Receiver::Worker < DaemonSpawn::Base
12 12 class DBProxyServer < EM::Connection
13 13 $worker_count = nil
14 14 @@wq = EM::WorkQueue::WorkQueue.new do |arg|
15 15 begin
  16 + begin
16 17 json = ::Yajl::Parser.parse(arg.last, :symbolize_keys => true)
17 18 rescue ::Yajl::ParseError
18 19 # JSON parse error....??
@@ -69,6 +70,10 @@ class DBProxyServer < EM::Connection
69 70 # ???
70 71 puts "???????"
71 72 end
  73 + rescue
  74 + $logger.error($!)
  75 + $logger.error($@)
  76 + end
72 77 end
73 78 @@wq.start
74 79
@@ -102,7 +107,6 @@ def receive_data(data)
102 107 while line = @receive_buf.slice!(/.+?\r\n/)
103 108 line.chomp!
104 109 next if line == ""
105   - p line
106 110 arg = line.split(/ /, 2)
107 111 case arg.first
108 112 when "CONNECT"
@@ -129,6 +133,7 @@ def receive_data(data)
129 133 close_connection_after_writing
130 134 end
131 135 when "QUIT"
  136 + $logger.info("Quit: #{@worker_number}")
132 137 send_chunk("BYE")
133 138 close_connection_after_writing
134 139 else
@@ -144,7 +149,6 @@ def initialize
144 149 end
145 150
146 151 def post_init
147   - p "connected"
148 152 end
149 153
150 154 def receive_data(data)
@@ -182,23 +186,30 @@ def receive_data(data)
182 186 end
183 187 end
184 188
185   - def initialize
186   - $logger = Receiver::Logger.new(:info)
  189 + def initialize(opts = {})
  190 + super(opts)
  191 + $logger = Receiver::Logger.new(:warn)
187 192 $connections = {}
188 193 end
189 194
190   - def start
  195 + def start(args)
191 196 $logger.info("Database Proxy Started")
192 197 EM.run do
193 198 stop = Proc.new do
194 199 EM.stop
195 200 end
196 201 Signal.trap(:INT, &stop)
  202 + Signal.trap(:QUIT, &stop)
197 203 Signal.trap(:TERM, &stop)
198 204
199 205 EM.start_server("0.0.0.0", Settings.db_proxy_port, DBProxyServer)
200 206 EM.start_unix_domain_server(Settings.register_server_path, RegisterServer)
201 207 end
202 208 end
  209 +
  210 + def stop
  211 + end
203 212 end
204 213
  214 +
  215 +

0 comments on commit 2c56dbd

Please sign in to comment.
Something went wrong with that request. Please try again.