forked from travis-ci/travis-chat
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathapp.rb
More file actions
114 lines (91 loc) · 2.32 KB
/
app.rb
File metadata and controls
114 lines (91 loc) · 2.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
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
104
105
106
107
108
109
110
111
112
113
114
require 'travis/sso'
require 'rack/ssl'
require 'sinatra'
require 'slim'
require 'rinku'
class Connection
attr_reader :user, :streams, :id
def self.all
@all ||= []
end
def self.each(&block)
all.each(&block)
end
def self.find(args)
args = { id: args } unless args.is_a? Hash
all.detect { |c| args.all? { |k,v| c.send(k) == v } }
end
def self.new(user)
find(user: user) or super.tap { |c| all << c }
end
def initialize(user)
@user, @streams, @id = user, [], SecureRandom.hex
end
def delete(stream)
streams.delete(stream)
end
def <<(data)
streams.each do |out|
out << data
end
end
def active?
streams.any?
end
end
use Rack::SSL if production?
helpers Travis::SSO::Helpers
use Travis::SSO, mode: :single_page,
authenticated?: -> r { Connection.find(r.params['id']) or super(r) }
set(history: [], history_size: 100, count: 0)
helpers do
attr_reader :connection
def sse(type, locals = {})
content = Rinku.auto_link(slim(type, locals: locals))
payload = [type, content, settings.count]
settings.count += 1
settings.history << payload
settings.history.shift until settings.history.size < settings.history_size
send_sse(payload)
end
def send_sse(payload, to = Connection.all)
type, content, id = payload
send_line("event: #{type}", to)
content.each_line { |l| send_line("data: #{l}", to) }
send_line "id: #{id}", to
send_line "", to
end
def send_line(data, to)
line = data.gsub(/\r\n/, '') + "\n"
Array(to).each { |c| c << line }
end
def users
Connection.all.select(&:active?).map(&:user)
end
end
before do
@connection ||= Connection.find(id: params[:id]) if params[:id]
@connection ||= Connection.new(current_user)
@current_user = connection.user
end
get '/' do
slim :index, {}, users: slim(:user_list)
end
get '/stream', provides: 'text/event-stream' do
stream :keep_open do |out|
connection.streams << out
sse(:user_list)
last_seen = env["HTTP_LAST_EVENT_ID"].to_i
settings.history.each do |payload|
send_sse(payload, out) if payload.last > last_seen and payload.first != :user_list
end
out.callback do
connection.delete(out)
sse(:user_list)
end
end
end
post '/' do
sse(:message, message: params[:msg]) unless params[:msg] =~ /^\s*$/
204
end