jschat 0.1.2 → 0.1.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|