rails_chat 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Ryan Bates
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,155 @@
1
+ # RailsChat
2
+ Refrence gem: [Private pub](https://github.com/ryanb/private_pub)
3
+
4
+ RailsChat is a Ruby gem for use with Rails to publish and subscribe to messages through [Faye](http://faye.jcoglan.com/). It allows you to easily provide real-time updates through an open socket without tying up a Rails process. All channels are private so users can only listen to events you subscribe them to.
5
+
6
+ ## Setup
7
+
8
+ Add the gem to your Gemfile and run the `bundle` command to install it.
9
+
10
+ ```ruby
11
+ gem "rails_chat"
12
+ ```
13
+
14
+ Run the generator to create the initial files.
15
+
16
+ ```
17
+ rails g rails_chat:install
18
+ ```
19
+
20
+ Next, start up Faye using the rackup file that was generated.
21
+
22
+ ```
23
+ rackup rails_chat.ru -s thin -E production
24
+ ```
25
+
26
+ **In Rails 3.1** add the JavaScript file to your application.js file manifest.
27
+
28
+ ```javascript
29
+ //= require rails_chat
30
+ ```
31
+ The other emoticons js are rendered in the assests via generator. If you are not using the `require_tree .` then please add emoticons JavaScript to your application.js file manifest.
32
+
33
+ ```javascript
34
+ //= require emoticons
35
+ //= require emoticons_defination
36
+ ```
37
+
38
+ **In Rails 3.0** add the generated rails_chat.js,emoticons.js,emoticons_defination files to your layout.
39
+
40
+ ```rhtml
41
+ <%= javascript_include_tag "rails_chat","emoticons","emoticons_defination" %>
42
+ ```
43
+
44
+ **In Rails 3.1** add the emoticons StyleSheet file to your application.css file manifest.
45
+
46
+ The emoticons css is rendered to your assests via generator. If you are not using the `require_tree .` then please add emoticons StyleSheet to your application.css file manifest.
47
+
48
+ ```stylesheet
49
+ *= require emoticons
50
+ ```
51
+
52
+ **In Rails 3.0** add the generated rails_chat.js file to your layout.
53
+
54
+ ```rhtml
55
+ <%= stylesheet_include_tag "emoticons" %>
56
+ ```
57
+
58
+
59
+ It's not necessary to include faye.js since that will be handled automatically for you.
60
+
61
+ ## Serving Faye over HTTPS (with Thin)
62
+
63
+ To server Faye over HTTPS you could create a thin configuration file `config/rails_chat_thin.yml` similar to the following:
64
+
65
+ ```yaml
66
+ ---
67
+ port: 4443
68
+ ssl: true
69
+ ssl_key_file: /path/to/server.pem
70
+ ssl_cert_file: /path/to/certificate_chain.pem
71
+ environment: production
72
+ rackup: rails_chat.ru
73
+ ```
74
+
75
+ The `certificate_chain.pem` file should contain your signed certificate, followed by intermediate certificates (if any) and the root certificate of the CA that signed the key.
76
+
77
+ Next reconfigure the URL in `config/rails_chat.yml` to look like `https://your.hostname.com:4443/faye`
78
+
79
+ Finally start up Thin from the project root.
80
+
81
+ ```
82
+ thin -C config/rails_chat_thin.yml start
83
+ ```
84
+
85
+ ## Usage
86
+
87
+ Use the `subscribe_to` helper method on any page to subscribe to a channel.
88
+
89
+ ```rhtml
90
+ <%= subscribe_to "/messages/new" %>
91
+ ```
92
+
93
+ Use the `publish_to` helper method to send JavaScript to that channel. This is usually done in a JavaScript AJAX template (such as a create.js.erb file).
94
+
95
+ ```rhtml
96
+ <% publish_to "/messages/new" do %>
97
+ $("#chat").append("<%= j render(@messages) %>");
98
+ <% end %>
99
+ ```
100
+
101
+ This JavaScript will be immediately evaluated on all clients who have subscribed to that channel. In this example they will see the new chat message appear in real-time without reloading the browser.
102
+
103
+
104
+ ## Alternative Usage
105
+
106
+ If you prefer to work through JSON instead of `.js.erb` templates, you can pass a hash to `publish_to` instead of a block and it will be converted `to_json` behind the scenes. This can be done anywhere (such as the controller).
107
+
108
+ ```ruby
109
+ RailsChat.publish_to "/messages/new", :chat_message => "Hello, world!"
110
+ ```
111
+
112
+ And then handle this through JavaScript on the client side.
113
+
114
+ ```javascript
115
+ RailsChat.subscribe("/messages/new", function(data, channel) {
116
+ $("#chat").append($.emoticons.replace(data.chat_message));
117
+ });
118
+ ```
119
+
120
+ The Ruby `subscribe_to` helper call is still necessary with this approach to grant the user access to the channel. The JavaScript is just a callback for any custom behavior.
121
+
122
+ NOTE: To use the emoticons in your chat you have to pass your message like `$.emoticons.replace(data.chat_message)`. This line will convert the emoticons signs into the real emoticons.
123
+
124
+ ## Configuration
125
+
126
+ The configuration is set separately for each environment in the generated `config/rails_chat.yml` file. Here are the options.
127
+
128
+ * `server`: The URL to use for the Faye server such as `http://localhost:9292/faye`.
129
+ * `secret_token`: A secret hash to secure the server. Can be any string.
130
+ * `signature_expiration`: The length of time in seconds before a subscription signature expires. If this is not set there is no expiration. Note: if Faye is on a separate server from the Rails app, the system clocks must be in sync for the expiration to work properly.
131
+
132
+
133
+ ## How It Works
134
+
135
+ The `subscribe_to` helper will output the following script which subscribes the user to a specific channel and server.
136
+
137
+ ```html
138
+ <script type="text/javascript">
139
+ RailsChat.sign({
140
+ channel: "/messages/new",
141
+ timestamp: 1302306682972,
142
+ signature: "dc1c71d3e959ebb6f49aa6af0c86304a0740088d",
143
+ server: "http://localhost:9292/faye"
144
+ });
145
+ </script>
146
+ ```
147
+
148
+ The signature and timestamp checked on the Faye server to ensure users are only able to access channels you subscribe them to. The signature will automatically expire after the time specified in the configuration.
149
+
150
+ The `publish_to` method will send a post request to the Faye server (using `Net::HTTP`) instructing it to send the given data back to the browser.
151
+
152
+
153
+ ## Development & Feedback
154
+
155
+ Questions or comments? Please use the [issue tracker](https://github.com/ciserfan/rails_chat/issues). Tests can be run with `bundle` and `rake` commands.
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+ require 'rspec/core/rake_task'
4
+ require 'jasmine'
5
+ load 'jasmine/tasks/jasmine.rake'
6
+
7
+ desc "Run RSpec"
8
+ RSpec::Core::RakeTask.new do |t|
9
+ t.verbose = false
10
+ end
11
+
12
+ task :default => [:spec, "jasmine:ci"]
Binary file
@@ -0,0 +1,127 @@
1
+ (function($, exports, window, name) {
2
+
3
+ if (!exports) {
4
+ exports = {};
5
+
6
+ if ($) {
7
+ $[name] = exports;
8
+ } else {
9
+ window[name] = exports;
10
+ }
11
+ }
12
+
13
+ var emoticons,
14
+ codesMap = {},
15
+ primaryCodesMap = {},
16
+ regexp,
17
+ metachars = /[[\]{}()*+?.\\|^$\-,&#\s]/g,
18
+ entityMap;
19
+
20
+ entityMap = {
21
+ '&': '&amp;',
22
+ '<': '&lt;',
23
+ '>': '&gt;',
24
+ '"': '&quot;',
25
+ "'": '&#39;',
26
+ '/': '&#x2F;'
27
+ };
28
+
29
+ function escape(string) {
30
+ return String(string).replace(/[&<>"'\/]/g, function(s) {
31
+ return entityMap[s];
32
+ });
33
+ }
34
+
35
+ /**
36
+ * Define emoticons set.
37
+ *
38
+ * @param {Object} data
39
+ */
40
+ exports.define = function(data) {
41
+ var name, i, codes, code,
42
+ patterns = [];
43
+
44
+ for (name in data) {
45
+ codes = data[name].codes;
46
+ for (i in codes) {
47
+ code = codes[i];
48
+ codesMap[code] = name;
49
+
50
+ // Create escaped variants, because mostly you want to parse escaped
51
+ // user text.
52
+ codesMap[escape(code)] = name;
53
+ if (i == 0) {
54
+ primaryCodesMap[code] = name;
55
+ }
56
+ }
57
+ }
58
+
59
+ for (code in codesMap) {
60
+ patterns.push('(' + code.replace(metachars, "\\$&") + ')');
61
+ }
62
+
63
+ regexp = new RegExp(patterns.join('|'), 'g');
64
+ emoticons = data;
65
+ };
66
+
67
+ /**
68
+ * Replace emoticons in text.
69
+ *
70
+ * @param {String} text
71
+ * @param {Function} [fn] optional template builder function.
72
+ */
73
+ exports.replace = function(text, fn) {
74
+ return text.replace(regexp, function(code) {
75
+ var name = codesMap[code];
76
+ return (fn || exports.tpl)(name, code, emoticons[name].title);
77
+ });
78
+ };
79
+
80
+ /**
81
+ * Get primary emoticons as html string in order to display them later as overview.
82
+ *
83
+ * @param {Function} [fn] optional template builder function.
84
+ * @return {String}
85
+ */
86
+ exports.toString = function(fn) {
87
+ var code,
88
+ str = '',
89
+ name;
90
+
91
+ for (code in primaryCodesMap) {
92
+ name = primaryCodesMap[code];
93
+ str += (fn || exports.tpl)(name, code, emoticons[name].title);
94
+ }
95
+
96
+ return str;
97
+ };
98
+
99
+ /**
100
+ * Build html string for emoticons.
101
+ *
102
+ * @param {String} name
103
+ * @param {String} code
104
+ * @param {String} title
105
+ * @return {String}
106
+ */
107
+ exports.tpl = function(name, code, title) {
108
+ return '<span class="emoticon emoticon-' + name + '" title="' + title + '">' +
109
+ code + '</span>';
110
+ };
111
+
112
+ /**
113
+ * Build html string for emoticons.
114
+ *
115
+ * @param {String} name
116
+ * @param {String} code
117
+ * @param {String} title
118
+ * @return {String}
119
+ */
120
+ exports.img = function(name, code, title) {
121
+ return '<img src="assets/' + name + '.gif" title="' + title + '" alt="'+ code +'"/>';
122
+ };
123
+
124
+ }(typeof jQuery != 'undefined' ? jQuery : null,
125
+ typeof exports != 'undefined' ? exports : null,
126
+ window,
127
+ 'emoticons'));
@@ -0,0 +1,365 @@
1
+ (function () {
2
+ var definition = {
3
+ smile: {
4
+ title: "Smile",
5
+ codes: [":)", ":=)", ":-)"]
6
+ },
7
+ "sad-smile": {
8
+ title: "Sad Smile",
9
+ codes: [":(", ":=(", ":-("]
10
+ },
11
+ "big-smile": {
12
+ title: "Big Smile",
13
+ codes: [":D", ":=D", ":-D", ":d", ":=d", ":-d"]
14
+ },
15
+ cool: {
16
+ title: "Cool",
17
+ codes: ["8)", "8=)", "8-)", "B)", "B=)", "B-)", "(cool)"]
18
+ },
19
+ surprised:{
20
+ title: "Surprised",
21
+ codes: [":o", ":=o", ":-o", ":O", ":=O", ":-O"]
22
+ },
23
+ wink: {
24
+ title: "Wink",
25
+ codes: [";)", ";=)", ";-)"]
26
+ },
27
+ crying: {
28
+ title: "Crying",
29
+ codes: [";(", ";-(", ";=("]
30
+ },
31
+ sweating: {
32
+ title: "Sweating",
33
+ codes: ["(sweat)", "(:|"]
34
+ },
35
+ speechless: {
36
+ title: "Speechless",
37
+ codes: [":|", ":=|", ":-|"]
38
+ },
39
+ kiss: {
40
+ title: "Kiss",
41
+ codes: [":*", ":=*", ":-*"]
42
+ },
43
+ "tongue-out": {
44
+ title: "Tongue Out",
45
+ codes: [":P", ":=P", ":-P", ":p", ":=p", ":-p"]
46
+ },
47
+ blush: {
48
+ title: "Blush",
49
+ codes: ["(blush)", ":$", ":-$", ":=$", ':">']
50
+ },
51
+ wondering: {
52
+ title: "Wondering",
53
+ codes: [":^)"]
54
+ },
55
+ sleepy: {
56
+ title: "Sleepy",
57
+ codes: ["|-)", "I-)", "I=)", "(snooze)"]
58
+ },
59
+ dull: {
60
+ title: "Dull",
61
+ codes: ["|(", "|-(", "|=("]
62
+ },
63
+ "in-love": {
64
+ title: "In love",
65
+ codes: ["(inlove)"]
66
+ },
67
+ "evil-grin": {
68
+ title: "Evil grin",
69
+ codes: ["]:)", ">:)", "(grin)"]
70
+ },
71
+ talking: {
72
+ title: "Talking",
73
+ codes: ["(talk)"]
74
+ },
75
+ yawn: {
76
+ title: "Yawn",
77
+ codes: ["(yawn)", "|-()"]
78
+ },
79
+ puke: {
80
+ title: "Puke",
81
+ codes: ["(puke)", ":&", ":-&", ":=&"]
82
+ },
83
+ "doh!": {
84
+ title: "Doh!",
85
+ codes: ["(doh)"]
86
+ },
87
+ angry: {
88
+ title: "Angry",
89
+ codes: [":@", ":-@", ":=@", "x(", "x-(", "x=(", "X(", "X-(", "X=("]
90
+ },
91
+ "it-wasnt-me": {
92
+ title: "It wasn't me",
93
+ codes: ["(wasntme)"]
94
+ },
95
+ party: {
96
+ title: "Party!!!",
97
+ codes: ["(party)"]
98
+ },
99
+ worried: {
100
+ title: "Worried",
101
+ codes: [":S", ":-S", ":=S", ":s", ":-s", ":=s"]
102
+ },
103
+ mmm: {
104
+ title: "Mmm...",
105
+ codes: ["(mm)"]
106
+ },
107
+ nerd: {
108
+ title: "Nerd",
109
+ codes: ["8-|", "B-|", "8|", "B|", "8=|", "B=|", "(nerd)"]
110
+ },
111
+ "lips-sealed": {
112
+ title: "Lips Sealed",
113
+ codes: [":x", ":-x", ":X", ":-X", ":#", ":-#", ":=x", ":=X", ":=#"]
114
+ },
115
+ hi: {
116
+ title: "Hi",
117
+ codes: ["(hi)"]
118
+ },
119
+ call: {
120
+ title: "Call",
121
+ codes: ["(call)"]
122
+ },
123
+ devil: {
124
+ title: "Devil",
125
+ codes: ["(devil)"]
126
+ },
127
+ angel: {
128
+ title: "Angel",
129
+ codes: ["(angel)"]
130
+ },
131
+ envy: {
132
+ title: "Envy",
133
+ codes: ["(envy)"]
134
+ },
135
+ wait: {
136
+ title: "Wait",
137
+ codes: ["(wait)"]
138
+ },
139
+ bear: {
140
+ title: "Bear",
141
+ codes: ["(bear)", "(hug)"]
142
+ },
143
+ "make-up": {
144
+ title: "Make-up",
145
+ codes: ["(makeup)", "(kate)"]
146
+ },
147
+ "covered-laugh": {
148
+ title: "Covered Laugh",
149
+ codes: ["(giggle)", "(chuckle)"]
150
+ },
151
+ "clapping-hands": {
152
+ title: "Clapping Hands",
153
+ codes: ["(clap)"]
154
+ },
155
+ thinking: {
156
+ title: "Thinking",
157
+ codes: ["(think)", ":?", ":-?", ":=?"]
158
+ },
159
+ bow: {
160
+ title: "Bow",
161
+ codes: ["(bow)"]
162
+ },
163
+ rofl: {
164
+ title: "Rolling on the floor laughing",
165
+ codes: ["(rofl)"]
166
+ },
167
+ whew: {
168
+ title: "Whew",
169
+ codes: ["(whew)"]
170
+ },
171
+ happy: {
172
+ title: "Happy",
173
+ codes: ["(happy)"]
174
+ },
175
+ smirking: {
176
+ title: "Smirking",
177
+ codes: ["(smirk)"]
178
+ },
179
+ nodding: {
180
+ title: "Nodding",
181
+ codes: ["(nod)"]
182
+ },
183
+ shaking: {
184
+ title: "Shaking",
185
+ codes: ["(shake)"]
186
+ },
187
+ punch: {
188
+ title: "Punch",
189
+ codes: ["(punch)"]
190
+ },
191
+ emo: {
192
+ title: "Emo",
193
+ codes: ["(emo)"]
194
+ },
195
+ yes: {
196
+ title: "Yes",
197
+ codes: ["(y)", "(Y)", "(ok)"]
198
+ },
199
+ no: {
200
+ title: "No",
201
+ codes: ["(n)", "(N)"]
202
+ },
203
+ handshake: {
204
+ title: "Shaking Hands",
205
+ codes: ["(handshake)"]
206
+ },
207
+ skype: {
208
+ title: "Skype",
209
+ codes: ["(skype)", "(ss)"]
210
+ },
211
+ heart: {
212
+ title: "Heart",
213
+ codes: ["(h)", "<3", "(H)", "(l)", "(L)"]
214
+ },
215
+ "broken-heart": {
216
+ title: "Broken heart",
217
+ codes: ["(u)", "(U)"]
218
+ },
219
+ mail: {
220
+ title: "Mail",
221
+ codes: ["(e)", "(m)"]
222
+ },
223
+ flower: {
224
+ title: "Flower",
225
+ codes: ["(f)", "(F)"]
226
+ },
227
+ rain: {
228
+ title: "Rain",
229
+ codes: ["(rain)", "(london)", "(st)"]
230
+ },
231
+ sun: {
232
+ title: "Sun",
233
+ codes: ["(sun)"]
234
+ },
235
+ time: {
236
+ title: "Time",
237
+ codes: ["(o)", "(O)", "(time)"]
238
+ },
239
+ music: {
240
+ title: "Music",
241
+ codes: ["(music)"]
242
+ },
243
+ movie: {
244
+ title: "Movie",
245
+ codes: ["(~)", "(film)", "(movie)"]
246
+ },
247
+ phone: {
248
+ title: "Phone",
249
+ codes: ["(mp)", "(ph)"]
250
+ },
251
+ coffee: {
252
+ title: "Coffee",
253
+ codes: ["(coffee)"]
254
+ },
255
+ pizza: {
256
+ title: "Pizza",
257
+ codes: ["(pizza)", "(pi)"]
258
+ },
259
+ cash: {
260
+ title: "Cash",
261
+ codes: ["(cash)", "(mo)", "($)"]
262
+ },
263
+ muscle: {
264
+ title: "Muscle",
265
+ codes: ["(muscle)", "(flex)"]
266
+ },
267
+ cake: {
268
+ title: "Cake",
269
+ codes: ["(^)", "(cake)"]
270
+ },
271
+ beer: {
272
+ title: "Beer",
273
+ codes: ["(beer)"]
274
+ },
275
+ drink: {
276
+ title: "Drink",
277
+ codes: ["(d)", "(D)"]
278
+ },
279
+ dance: {
280
+ title: "Dance",
281
+ codes: ["(dance)", "\\o/", "\\:D/", "\\:d/"]
282
+ },
283
+ ninja: {
284
+ title: "Ninja",
285
+ codes: ["(ninja)"]
286
+ },
287
+ star: {
288
+ title: "Star",
289
+ codes: ["(*)"]
290
+ },
291
+ mooning: {
292
+ title: "Mooning",
293
+ codes: ["(mooning)"]
294
+ },
295
+ finger: {
296
+ title: "Finger",
297
+ codes: ["(finger)"]
298
+ },
299
+ bandit: {
300
+ title: "Bandit",
301
+ codes: ["(bandit)"]
302
+ },
303
+ drunk: {
304
+ title: "Drunk",
305
+ codes: ["(drunk)"]
306
+ },
307
+ smoking: {
308
+ title: "Smoking",
309
+ codes: ["(smoking)", "(smoke)", "(ci)"]
310
+ },
311
+ toivo: {
312
+ title: "Toivo",
313
+ codes: ["(toivo)"]
314
+ },
315
+ rock: {
316
+ title: "Rock",
317
+ codes: ["(rock)"]
318
+ },
319
+ headbang: {
320
+ title: "Headbang",
321
+ codes: ["(headbang)", "(banghead)"]
322
+ },
323
+ bug: {
324
+ title: "Bug",
325
+ codes: ["(bug)"]
326
+ },
327
+ fubar: {
328
+ title: "Fubar",
329
+ codes: ["(fubar)"]
330
+ },
331
+ poolparty: {
332
+ title: "Poolparty",
333
+ codes: ["(poolparty)"]
334
+ },
335
+ swearing: {
336
+ title: "Swearing",
337
+ codes: ["(swear)"]
338
+ },
339
+ tmi: {
340
+ title: "TMI",
341
+ codes: ["(tmi)"]
342
+ },
343
+ heidy: {
344
+ title: "Heidy",
345
+ codes: ["(heidy)"]
346
+ },
347
+ myspace: {
348
+ title: "MySpace",
349
+ codes: ["(MySpace)"]
350
+ },
351
+ malthe: {
352
+ title: "Malthe",
353
+ codes: ["(malthe)"]
354
+ },
355
+ tauri: {
356
+ title: "Tauri",
357
+ codes: ["(tauri)"]
358
+ },
359
+ priidu: {
360
+ title: "Priidu",
361
+ codes: ["(priidu)"]
362
+ }
363
+ };
364
+ $.emoticons.define(definition);
365
+ }());