jschat 0.1.2 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +11 -1
- data/bin/jschat-server +2 -4
- data/lib/jschat/http/jschat.rb +26 -2
- data/lib/jschat/http/public/javascripts/app/controllers/chat_controller.js +134 -5
- data/lib/jschat/http/public/javascripts/app/helpers/page_helper.js +13 -0
- data/lib/jschat/http/public/javascripts/app/ui/commands.js +21 -0
- data/lib/jschat/http/public/stylesheets/iphone.css +2 -0
- data/lib/jschat/http/public/stylesheets/screen.css +7 -0
- data/lib/jschat/http/views/iphone.erb +3 -0
- data/lib/jschat/http/views/layout.erb +3 -0
- data/lib/jschat/server.rb +62 -9
- data/lib/jschat/{server-options.rb → server_options.rb} +20 -2
- data/lib/jschat/storage/init.rb +19 -0
- data/lib/jschat/storage/mongo.rb +41 -0
- data/lib/jschat/storage/null.rb +21 -0
- metadata +6 -3
data/README.textile
CHANGED
@@ -43,7 +43,7 @@ The web app must be run alongside the server. The web app must be started in pr
|
|
43
43
|
|
44
44
|
The web app currently has no database dependencies, it's a wrapper that links cookies to JsChat server proxies. You can run it on port 80 by configuring Rack or an Apache proxy. I have Apache set up this way on "jschat.org":http://jschat.org.
|
45
45
|
|
46
|
-
h3. Configuration
|
46
|
+
h3. Configuration Files
|
47
47
|
|
48
48
|
These are the default locations of the configuration files. You can override them with <code>--config=PATH</code>:
|
49
49
|
|
@@ -58,6 +58,16 @@ The file format is JSON, like this:
|
|
58
58
|
{ "port": 3001 }
|
59
59
|
</pre>
|
60
60
|
|
61
|
+
h3. Server Configuration Options
|
62
|
+
|
63
|
+
<pre>
|
64
|
+
{
|
65
|
+
"port": integer,
|
66
|
+
"ip": "string: IP address to bind to",
|
67
|
+
"tmp_files": "string: path to tmp files (including PID file)"
|
68
|
+
}
|
69
|
+
</pre>
|
70
|
+
|
61
71
|
h3. Client Commands
|
62
72
|
|
63
73
|
* Change name or identify: <code>/nick name</code>
|
data/bin/jschat-server
CHANGED
data/lib/jschat/http/jschat.rb
CHANGED
@@ -3,7 +3,7 @@ require 'sinatra'
|
|
3
3
|
require 'sha1'
|
4
4
|
require 'json'
|
5
5
|
require 'sprockets'
|
6
|
-
require 'jschat/
|
6
|
+
require 'jschat/server_options'
|
7
7
|
|
8
8
|
set :public, File.join(File.dirname(__FILE__), 'public')
|
9
9
|
set :views, File.join(File.dirname(__FILE__), 'views')
|
@@ -39,6 +39,10 @@ class JsChat::Bridge
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
+
def rooms
|
43
|
+
send_json({ :list => 'rooms' })
|
44
|
+
end
|
45
|
+
|
42
46
|
def lastlog(room)
|
43
47
|
response = send_json({ :lastlog => room })
|
44
48
|
response['messages']
|
@@ -52,6 +56,10 @@ class JsChat::Bridge
|
|
52
56
|
send_json({ :join => room }, false)
|
53
57
|
end
|
54
58
|
|
59
|
+
def part(room)
|
60
|
+
send_json({ :part => room })
|
61
|
+
end
|
62
|
+
|
55
63
|
def send_message(message, to)
|
56
64
|
send_json({ :send => message, :to => to }, false)
|
57
65
|
end
|
@@ -212,7 +220,18 @@ post '/join' do
|
|
212
220
|
load_bridge
|
213
221
|
@bridge.join params['room']
|
214
222
|
save_last_room params['room']
|
215
|
-
|
223
|
+
'OK'
|
224
|
+
end
|
225
|
+
|
226
|
+
get '/part' do
|
227
|
+
load_bridge
|
228
|
+
@bridge.part params['room']
|
229
|
+
|
230
|
+
if @bridge.last_error
|
231
|
+
error 500, [@bridge.last_error].to_json
|
232
|
+
else
|
233
|
+
'OK'
|
234
|
+
end
|
216
235
|
end
|
217
236
|
|
218
237
|
get '/chat/' do
|
@@ -249,6 +268,11 @@ get '/quit' do
|
|
249
268
|
redirect '/'
|
250
269
|
end
|
251
270
|
|
271
|
+
get '/rooms' do
|
272
|
+
load_bridge
|
273
|
+
@bridge.rooms.to_json
|
274
|
+
end
|
275
|
+
|
252
276
|
# This serves the JavaScript concat'd by Sprockets
|
253
277
|
# run script/sprocket.rb to cache this
|
254
278
|
get '/javascripts/all.js' do
|
@@ -12,6 +12,24 @@ JsChat.ChatController = Class.create({
|
|
12
12
|
|
13
13
|
$('post_message').observe('submit', this.postMessageFormEvent.bindAsEventListener(this));
|
14
14
|
$('messages').observe('scroll', this.messagesScrolled.bindAsEventListener(this));
|
15
|
+
$$('#rooms li.join a').first().observe('click', this.joinRoomClicked.bindAsEventListener(this));
|
16
|
+
Event.observe(document, 'click', this.roomTabClick.bindAsEventListener(this));
|
17
|
+
},
|
18
|
+
|
19
|
+
joinRoomClicked: function(e) {
|
20
|
+
this.addRoomPrompt(e);
|
21
|
+
Event.stop(e);
|
22
|
+
return false;
|
23
|
+
},
|
24
|
+
|
25
|
+
roomTabClick: function(e) {
|
26
|
+
var element = Event.element(e);
|
27
|
+
|
28
|
+
if (element.tagName == 'A' && element.up('#rooms') && !element.up('li').hasClassName('join')) {
|
29
|
+
this.switchRoom(element.innerHTML);
|
30
|
+
Event.stop(e);
|
31
|
+
return false;
|
32
|
+
}
|
15
33
|
},
|
16
34
|
|
17
35
|
messagesScrolled: function() {
|
@@ -80,8 +98,7 @@ JsChat.ChatController = Class.create({
|
|
80
98
|
Display.show_unread = false;
|
81
99
|
Display.ignore_notices = false;
|
82
100
|
|
83
|
-
|
84
|
-
$('room-name').title = PageHelper.currentRoom();
|
101
|
+
PageHelper.setCurrentRoomName(window.location.hash);
|
85
102
|
$('message').activate();
|
86
103
|
$$('.header .navigation li').invoke('hide');
|
87
104
|
$('quit-nav').show();
|
@@ -95,13 +112,26 @@ JsChat.ChatController = Class.create({
|
|
95
112
|
});
|
96
113
|
|
97
114
|
this.createPollers();
|
98
|
-
this.joinRoom();
|
115
|
+
this.joinRoom(PageHelper.currentRoom());
|
116
|
+
this.getRoomList(this.addRoomToNav);
|
117
|
+
},
|
118
|
+
|
119
|
+
getRoomList: function(callback) {
|
120
|
+
new Ajax.Request('/rooms', {
|
121
|
+
method: 'get',
|
122
|
+
parameters: { time: new Date().getTime() },
|
123
|
+
onComplete: function(response) {
|
124
|
+
response.responseText.evalJSON().each(function(roomName) {
|
125
|
+
callback(roomName);
|
126
|
+
}.bind(this));
|
127
|
+
}.bind(this)
|
128
|
+
});
|
99
129
|
},
|
100
130
|
|
101
|
-
joinRoom: function() {
|
131
|
+
joinRoom: function(roomName) {
|
102
132
|
new Ajax.Request('/join', {
|
103
133
|
method: 'post',
|
104
|
-
parameters: { time: new Date().getTime(), room:
|
134
|
+
parameters: { time: new Date().getTime(), room: roomName },
|
105
135
|
onFailure: function() {
|
106
136
|
Display.add_message("Error: Couldn't join channel", 'server');
|
107
137
|
$('loading').hide();
|
@@ -112,10 +142,109 @@ JsChat.ChatController = Class.create({
|
|
112
142
|
document.title = PageHelper.title();
|
113
143
|
UserCommands['/lastlog'].apply(this);
|
114
144
|
$('loading').hide();
|
145
|
+
$('rooms').show();
|
146
|
+
this.addRoomToNav(roomName, true);
|
115
147
|
}.bind(this)
|
116
148
|
});
|
117
149
|
},
|
118
150
|
|
151
|
+
isValidRoom: function(roomName) {
|
152
|
+
if (PageHelper.allRoomNames().include(roomName)) {
|
153
|
+
return false;
|
154
|
+
}
|
155
|
+
return true;
|
156
|
+
},
|
157
|
+
|
158
|
+
validateAndJoinRoom: function(roomName) {
|
159
|
+
if (roomName === null || roomName.length == 0) {
|
160
|
+
return;
|
161
|
+
}
|
162
|
+
|
163
|
+
if (!roomName.match(/^#/)) {
|
164
|
+
roomName = '#' + roomName;
|
165
|
+
}
|
166
|
+
|
167
|
+
if (this.isValidRoom(roomName)) {
|
168
|
+
this.joinRoomInTab(roomName);
|
169
|
+
}
|
170
|
+
},
|
171
|
+
|
172
|
+
addRoomPrompt: function() {
|
173
|
+
var roomName = prompt('Enter a room name:');
|
174
|
+
this.validateAndJoinRoom(roomName);
|
175
|
+
},
|
176
|
+
|
177
|
+
addRoomToNav: function(roomName, selected) {
|
178
|
+
if (PageHelper.allRoomNames().include(roomName)) return;
|
179
|
+
|
180
|
+
var classAttribute = selected ? ' class="selected"' : '';
|
181
|
+
$('rooms').insert({ bottom: '<li#{classAttribute}><a href="#{roomName}">#{roomName}</a></li>'.interpolate({ classAttribute: classAttribute, roomName: roomName }) });
|
182
|
+
},
|
183
|
+
|
184
|
+
removeSelectedTab: function() {
|
185
|
+
$$('#rooms .selected').invoke('removeClassName', 'selected');
|
186
|
+
},
|
187
|
+
|
188
|
+
selectRoomTab: function(roomName) {
|
189
|
+
$$('#rooms a').each(function(a) {
|
190
|
+
if (a.innerHTML == roomName) {
|
191
|
+
a.up('li').addClassName('selected');
|
192
|
+
}
|
193
|
+
});
|
194
|
+
},
|
195
|
+
|
196
|
+
joinRoomInTab: function(roomName) {
|
197
|
+
this.removeSelectedTab();
|
198
|
+
PageHelper.setCurrentRoomName(roomName);
|
199
|
+
this.joinRoom(roomName);
|
200
|
+
},
|
201
|
+
|
202
|
+
switchRoom: function(roomName) {
|
203
|
+
if (PageHelper.currentRoom() == roomName) {
|
204
|
+
return;
|
205
|
+
}
|
206
|
+
|
207
|
+
this.removeSelectedTab();
|
208
|
+
this.selectRoomTab(roomName);
|
209
|
+
PageHelper.setCurrentRoomName(roomName);
|
210
|
+
UserCommands['/lastlog'].apply(this);
|
211
|
+
},
|
212
|
+
|
213
|
+
rooms: function() {
|
214
|
+
return $$('#rooms li a').slice(1).collect(function(element) {
|
215
|
+
return element.innerHTML;
|
216
|
+
});
|
217
|
+
},
|
218
|
+
|
219
|
+
partRoom: function(roomName) {
|
220
|
+
if (this.rooms().length == 1) {
|
221
|
+
return UserCommands['/quit']();
|
222
|
+
}
|
223
|
+
|
224
|
+
new Ajax.Request('/part', {
|
225
|
+
method: 'get',
|
226
|
+
parameters: { room: roomName },
|
227
|
+
onSuccess: function(request) {
|
228
|
+
this.removeTab(roomName);
|
229
|
+
}.bind(this),
|
230
|
+
onFailure: function(request) {
|
231
|
+
Display.add_message('Error: ' + request.responseText, 'server');
|
232
|
+
}
|
233
|
+
});
|
234
|
+
},
|
235
|
+
|
236
|
+
removeTab: function(roomName) {
|
237
|
+
$$('#rooms li').each(function(element) {
|
238
|
+
if (element.down('a').innerHTML == roomName) {
|
239
|
+
element.remove();
|
240
|
+
|
241
|
+
if (roomName == PageHelper.currentRoom()) {
|
242
|
+
this.switchRoom($$('#rooms li a')[1].innerHTML);
|
243
|
+
}
|
244
|
+
}
|
245
|
+
}.bind(this));
|
246
|
+
},
|
247
|
+
|
119
248
|
updateNames: function() {
|
120
249
|
UserCommands['/names'].apply(this);
|
121
250
|
},
|
@@ -3,6 +3,19 @@ var PageHelper = {
|
|
3
3
|
return window.location.hash;
|
4
4
|
},
|
5
5
|
|
6
|
+
setCurrentRoomName: function(roomName) {
|
7
|
+
window.location.hash = roomName;
|
8
|
+
$('room-name').innerHTML = TextHelper.truncateRoomName(PageHelper.currentRoom());
|
9
|
+
$('room-name').title = PageHelper.currentRoom();
|
10
|
+
document.title = PageHelper.title();
|
11
|
+
},
|
12
|
+
|
13
|
+
allRoomNames: function() {
|
14
|
+
return $$('#rooms li a').collect(function(link) {
|
15
|
+
return link.innerHTML;
|
16
|
+
});
|
17
|
+
},
|
18
|
+
|
6
19
|
nickname: function() {
|
7
20
|
return Cookie.find('jschat-name');
|
8
21
|
},
|
@@ -9,9 +9,12 @@ var UserCommands = {
|
|
9
9
|
var help = [];
|
10
10
|
Display.add_message('<strong>JsChat Help</strong> — Type the following commands into the message field:', 'help')
|
11
11
|
help.push(['/clear', 'Clears messages']);
|
12
|
+
help.push(['/join #room_name', 'Joins a room']);
|
13
|
+
help.push(['/part #room_name', 'Leaves a room. Leave room_name blank for the current room']);
|
12
14
|
help.push(['/lastlog', 'Shows recent activity']);
|
13
15
|
help.push(['/names', 'Refreshes the names list']);
|
14
16
|
help.push(['/name new_name', 'Changes your name']);
|
17
|
+
help.push(['/quit', 'Quit']);
|
15
18
|
help.push(['/emotes', 'Shows available emotes']);
|
16
19
|
$A(help).each(function(options) {
|
17
20
|
var help_text = '<span class="command">#{command}</span><span class="command_help">#{text}</span>'.interpolate({ command: options[0], text: options[1]});
|
@@ -51,5 +54,23 @@ var UserCommands = {
|
|
51
54
|
|
52
55
|
'/names': function() {
|
53
56
|
JsChat.Request.get('/names', function(t) { this.displayMessages(t.responseText); }.bind(this));
|
57
|
+
},
|
58
|
+
|
59
|
+
'/(join)\\s+(.*)': function() {
|
60
|
+
var room = arguments[0][2];
|
61
|
+
this.validateAndJoinRoom(room);
|
62
|
+
},
|
63
|
+
|
64
|
+
'/(part|leave)': function() {
|
65
|
+
this.partRoom(PageHelper.currentRoom());
|
66
|
+
},
|
67
|
+
|
68
|
+
'/(part|leave)\\s+(.*)': function() {
|
69
|
+
var room = arguments[0][2];
|
70
|
+
this.partRoom(room);
|
71
|
+
},
|
72
|
+
|
73
|
+
'/quit': function() {
|
74
|
+
window.location = '/quit';
|
54
75
|
}
|
55
76
|
};
|
@@ -16,6 +16,13 @@ h1 { text-align: left; margin-left: 20px }
|
|
16
16
|
.header .navigation li#quit-nav a:hover { color: #990000; background-color: #fff }
|
17
17
|
.header-shadow { width: 100%; height: 6px; position: absolute; top: 59px; left: 0; background-image: url('/images/shadow.png'); background-repeat: repeat-x }
|
18
18
|
|
19
|
+
.header .rooms { position: absolute; left: 200px; top: 35px; list-style-type: none; margin: 0; padding: 0 }
|
20
|
+
.header .rooms li { float: left; margin: 0 1px 0 0; padding: 2px 6px 3px 6px; background-color: #f0f0f0; border: 1px solid #aaa; border-bottom: #fff; font-size: 90%; height: 18px }
|
21
|
+
.header .rooms li.selected { background-color: #fff; border: 1px solid #ccc; border-bottom: #fff }
|
22
|
+
.header .rooms li a { color: #777; text-decoration: none }
|
23
|
+
.header .rooms li a:hover { color: #000 }
|
24
|
+
.header .rooms li.selected a { color: #444 }
|
25
|
+
|
19
26
|
.page { margin-top: 60px }
|
20
27
|
|
21
28
|
#messages { width: 500px; height: 300px; margin: 0 20px 10px 20px; padding: 0; overflow: auto; background-color: #fff; float: left; text-align: left; display: inline; }
|
@@ -14,6 +14,9 @@
|
|
14
14
|
<div id="loading" style="display: none">Loading...</div>
|
15
15
|
<div class="header">
|
16
16
|
<h1><a href="/"><img src="/images/jschat.gif" alt="JsChat" /></a></h1>
|
17
|
+
<ul id="rooms" class="rooms" style="display: none">
|
18
|
+
<li class="join"><a href="#">+</a></li>
|
19
|
+
</ul>
|
17
20
|
<ul class="navigation">
|
18
21
|
<li><a href="/">Home</a></li>
|
19
22
|
<li><a href="http://github.com/alexyoung/jschat">Download</a>
|
@@ -13,6 +13,9 @@
|
|
13
13
|
<div id="loading" style="display: none">Loading...</div>
|
14
14
|
<div class="header">
|
15
15
|
<h1><a href="/"><img src="/images/jschat.gif" alt="JsChat" /></a></h1>
|
16
|
+
<ul id="rooms" class="rooms" style="display: none">
|
17
|
+
<li class="join"><a href="#">+</a></li>
|
18
|
+
</ul>
|
16
19
|
<ul class="navigation">
|
17
20
|
<li><a href="/">Home</a></li>
|
18
21
|
<li><a href="http://github.com/alexyoung/jschat">Download</a>
|
data/lib/jschat/server.rb
CHANGED
@@ -7,10 +7,53 @@ require 'socket'
|
|
7
7
|
# JsChat libraries
|
8
8
|
require 'jschat/errors'
|
9
9
|
require 'jschat/flood_protection'
|
10
|
+
require 'jschat/storage/init'
|
10
11
|
|
11
12
|
module JsChat
|
12
13
|
STATELESS_TIMEOUT = 60
|
13
14
|
|
15
|
+
module Server
|
16
|
+
def self.pid_file_name
|
17
|
+
File.join(ServerConfig['tmp_files'], 'jschat.pid')
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.write_pid_file
|
21
|
+
return unless ServerConfig['use_tmp_files']
|
22
|
+
File.open(pid_file_name, 'w') { |f| f << Process.pid }
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.rm_pid_file
|
26
|
+
FileUtils.rm pid_file_name
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.init_storage
|
30
|
+
if JsChat::Storage::MongoDriver.available?
|
31
|
+
JsChat::Storage.enabled = true
|
32
|
+
JsChat::Storage.driver = JsChat::Storage::MongoDriver
|
33
|
+
else
|
34
|
+
JsChat::Storage.enabled = false
|
35
|
+
JsChat::Storage.driver = JsChat::Storage::NullDriver
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def self.stop
|
40
|
+
rm_pid_file
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.run!
|
44
|
+
write_pid_file
|
45
|
+
init_storage
|
46
|
+
|
47
|
+
at_exit do
|
48
|
+
stop
|
49
|
+
end
|
50
|
+
|
51
|
+
EM.run do
|
52
|
+
EM.start_server ServerConfig['ip'], ServerConfig['port'], JsChat
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
14
57
|
class User
|
15
58
|
include JsChat::FloodProtection
|
16
59
|
|
@@ -105,10 +148,11 @@ module JsChat
|
|
105
148
|
end
|
106
149
|
|
107
150
|
def messages_since(since)
|
151
|
+
messages = JsChat::Storage.driver.lastlog(100)
|
108
152
|
if since.nil?
|
109
|
-
|
153
|
+
messages
|
110
154
|
else
|
111
|
-
|
155
|
+
messages.select { |m| message_time(m) > since }
|
112
156
|
end
|
113
157
|
end
|
114
158
|
|
@@ -117,19 +161,19 @@ module JsChat
|
|
117
161
|
message[message['display']]['time']
|
118
162
|
elsif message.has_key? 'change'
|
119
163
|
message[message['change']]['time']
|
164
|
+
else
|
165
|
+
Time.now
|
120
166
|
end
|
121
167
|
end
|
122
168
|
|
123
169
|
def add_to_lastlog(message)
|
124
|
-
@messages ||= []
|
125
170
|
if message
|
126
171
|
if message.has_key? 'display'
|
127
172
|
message[message['display']]['time'] = Time.now.utc
|
128
173
|
elsif message.has_key? 'change'
|
129
174
|
message[message['change']]['time'] = Time.now.utc
|
130
175
|
end
|
131
|
-
|
132
|
-
@messages = @messages[-100..-1] if @messages.size > 100
|
176
|
+
JsChat::Storage.driver.log message
|
133
177
|
end
|
134
178
|
end
|
135
179
|
|
@@ -401,12 +445,21 @@ module JsChat
|
|
401
445
|
field, value = @user.send :change, options[change]
|
402
446
|
{ 'display' => 'notice', 'notice' => "Your #{field} has been changed to: #{value}" }
|
403
447
|
else
|
404
|
-
Error.new(:invalid_request,
|
448
|
+
Error.new(:invalid_request, 'Invalid change request')
|
405
449
|
end
|
406
450
|
rescue JsChat::Errors::InvalidName => exception
|
407
451
|
exception
|
408
452
|
end
|
409
453
|
|
454
|
+
def list(list, options = {})
|
455
|
+
case list
|
456
|
+
when 'rooms'
|
457
|
+
@user.rooms.collect { |room| room.name }
|
458
|
+
else
|
459
|
+
Error.new(:invalid_request, 'Invalid list command')
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
410
463
|
def send_response(data)
|
411
464
|
response = ''
|
412
465
|
case data
|
@@ -459,9 +512,9 @@ module JsChat
|
|
459
512
|
input['ip'] ||= get_remote_ip
|
460
513
|
response << send_response(identify(input['identify'], input['ip']))
|
461
514
|
else
|
462
|
-
|
515
|
+
%w{lastlog change send join names part since ping list quit}.each do |command|
|
463
516
|
if @user.name.nil?
|
464
|
-
response << send_response(Error.new(:identity_required,
|
517
|
+
response << send_response(Error.new(:identity_required, 'Identify first'))
|
465
518
|
return response
|
466
519
|
end
|
467
520
|
|
@@ -494,7 +547,7 @@ module JsChat
|
|
494
547
|
print_call_stack
|
495
548
|
end
|
496
549
|
|
497
|
-
def print_call_stack(from =
|
550
|
+
def print_call_stack(from = 0, to = 10)
|
498
551
|
puts "Stack:"
|
499
552
|
(from..to).each do |index|
|
500
553
|
puts "\t#{caller[index]}"
|
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'optparse'
|
2
|
+
require 'tmpdir'
|
2
3
|
|
3
4
|
logger = nil
|
4
5
|
|
@@ -11,7 +12,11 @@ ServerConfigDefaults = {
|
|
11
12
|
'port' => 6789,
|
12
13
|
'ip' => '0.0.0.0',
|
13
14
|
'logger' => logger,
|
14
|
-
'max_message_length' => 500
|
15
|
+
'max_message_length' => 500,
|
16
|
+
'tmp_files' => File.join(Dir::tmpdir, 'jschat'),
|
17
|
+
'db_name' => 'jschat',
|
18
|
+
'db_host' => 'localhost',
|
19
|
+
'db_port' => 27017
|
15
20
|
}
|
16
21
|
|
17
22
|
# Command line options will overrides these
|
@@ -24,6 +29,17 @@ def load_options(path)
|
|
24
29
|
end
|
25
30
|
end
|
26
31
|
|
32
|
+
def make_tmp_files
|
33
|
+
ServerConfig['use_tmp_files'] = false
|
34
|
+
if File.exists? ServerConfig['tmp_files']
|
35
|
+
ServerConfig['use_tmp_files'] = true
|
36
|
+
else
|
37
|
+
if Dir.mkdir ServerConfig['tmp_files']
|
38
|
+
ServerConfig['use_tmp_files'] = true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
27
43
|
options = {}
|
28
44
|
default_config_file = '/etc/jschat/config.json'
|
29
45
|
|
@@ -34,7 +50,8 @@ ARGV.clone.options do |opts|
|
|
34
50
|
opts.separator ""
|
35
51
|
|
36
52
|
opts.on("-c", "--config=PATH", String, "Configuration file location (#{default_config_file}") { |o| options['config'] = o }
|
37
|
-
opts.on("-p", "--port=
|
53
|
+
opts.on("-p", "--port=PORT", String, "Port number") { |o| options['port'] = o }
|
54
|
+
opts.on("-t", "--tmp_files=PATH", String, "Temporary files location (including pid file)") { |o| options['tmp_files'] = o }
|
38
55
|
opts.on("--help", "-H", "This text") { puts opts; exit 0 }
|
39
56
|
|
40
57
|
opts.parse!
|
@@ -43,3 +60,4 @@ end
|
|
43
60
|
options = load_options(options['config'] || default_config_file).merge options
|
44
61
|
|
45
62
|
ServerConfig = ServerConfigDefaults.merge options
|
63
|
+
make_tmp_files
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'mongo')
|
2
|
+
require File.join(File.dirname(__FILE__), 'null')
|
3
|
+
|
4
|
+
module JsChat::Storage
|
5
|
+
def self.driver=(driver)
|
6
|
+
@driver = driver
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.driver ; @driver ; end
|
10
|
+
|
11
|
+
def self.enabled=(enabled)
|
12
|
+
@enabled = enabled
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.enabled?
|
16
|
+
@enabled
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
begin
|
2
|
+
require 'mongo'
|
3
|
+
rescue LoadError
|
4
|
+
end
|
5
|
+
|
6
|
+
module JsChat::Storage
|
7
|
+
module MongoDriver
|
8
|
+
def self.connect!
|
9
|
+
@db = Mongo::Connection.new(ServerConfig['db_host'], ServerConfig['db_port']).db(ServerConfig['db_name'])
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.log(message)
|
13
|
+
message['time_index'] = Time.now.to_i
|
14
|
+
@db['events'].insert(message)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.lastlog(number)
|
18
|
+
@db['events'].find({}, { :limit => number, :sort => ['time_index', Mongo::ASCENDING] }).to_a
|
19
|
+
end
|
20
|
+
|
21
|
+
# TODO: use twitter oauth for the key
|
22
|
+
def self.find_user(name)
|
23
|
+
@db['users'].find_one('name' => name)
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.set_rooms(name, rooms)
|
27
|
+
user = find_user name
|
28
|
+
user ||= { 'name' => name }
|
29
|
+
user['rooms'] = rooms
|
30
|
+
@db['users'].save user
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.available?
|
34
|
+
return unless Object.const_defined?(:Mongo)
|
35
|
+
connect!
|
36
|
+
rescue
|
37
|
+
puts 'Failed to connect to mongo'
|
38
|
+
false
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module JsChat::Storage
|
2
|
+
module NullDriver
|
3
|
+
def self.log(message)
|
4
|
+
@messages ||= []
|
5
|
+
@messages.push message
|
6
|
+
@messages = @messages[-100..-1] if @messages.size > 100
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.lastlog(number)
|
10
|
+
@messages ||= []
|
11
|
+
@messages[0..number]
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.find_user(name)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.set_rooms(name, rooms)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 5
|
9
|
+
version: 0.1.5
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Alex R. Young
|
@@ -183,8 +183,11 @@ files:
|
|
183
183
|
- lib/jschat/http/views/iphone.erb
|
184
184
|
- lib/jschat/http/views/layout.erb
|
185
185
|
- lib/jschat/http/views/message_form.erb
|
186
|
-
- lib/jschat/server-options.rb
|
187
186
|
- lib/jschat/server.rb
|
187
|
+
- lib/jschat/server_options.rb
|
188
|
+
- lib/jschat/storage/init.rb
|
189
|
+
- lib/jschat/storage/mongo.rb
|
190
|
+
- lib/jschat/storage/null.rb
|
188
191
|
- test/server_test.rb
|
189
192
|
- test/stateless_test.rb
|
190
193
|
- test/test_helper.rb
|