globalchat 1.0.0

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/server.rb ADDED
@@ -0,0 +1,308 @@
1
+ #!/usr/bin/env ruby
2
+ require 'gserver'
3
+ require 'net/http'
4
+ require 'uri'
5
+ require 'securerandom'
6
+ require 'pstore'
7
+
8
+ class GlobalChatServer < GServer
9
+
10
+ attr_accessor :handles, :buffer, :handle_keys, :sockets, :password, :socket_keys, :scrollback, :server_name
11
+
12
+ def initialize(port=9994, *args)
13
+ super(port, *args)
14
+ self.audit = true
15
+ self.debug = true
16
+ @pstore = PStore.new("gchat.pstore")
17
+ @handle_keys = {} # stores handle
18
+ @socket_keys = {} # stores chat_token
19
+ # @port_keys = {} # unnecessary in PING design
20
+ @handle_last_pinged = {} # used for clone removal
21
+ @handles = []
22
+ @sockets = []
23
+ @buffer = []
24
+ @server_name = "GlobalChatNet"
25
+ load_chat_log
26
+ @mutex = Mutex.new
27
+ end
28
+
29
+ def broadcast(message, sender=nil)
30
+ @mutex.synchronize do
31
+ @sockets.each do |socket|
32
+ begin
33
+ sock_send(socket, message) unless socket == sender
34
+ rescue
35
+ log "broadcast fail removal event"
36
+ remove_dead_socket socket
37
+ end
38
+ end
39
+ end
40
+ end
41
+
42
+ def remove_dead_socket(socket)
43
+ @sockets.delete socket
44
+ ct = @socket_keys[socket]
45
+ handle = @handle_keys[ct]
46
+ @handles.delete handle
47
+ @handle_keys.delete ct
48
+ @socket_keys.delete socket
49
+ end
50
+
51
+ def remove_user_by_handle(handle)
52
+ ct = @handle_keys.key(handle)
53
+ handle = @handle_keys[ct]
54
+ socket = @socket_keys.key(ct)
55
+ @sockets.delete socket
56
+
57
+ @handles.delete handle
58
+ @handle_keys.delete ct
59
+ @socket_keys.delete socket
60
+ begin
61
+ broadcast_message(socket, "LEAVE", [handle])
62
+ rescue
63
+ log "failed to broadcast LEAVE for clone handle #{handle}"
64
+ end
65
+ end
66
+
67
+ def check_token(chat_token)
68
+ sender = @handle_keys[chat_token]
69
+ return !sender.nil?
70
+ end
71
+
72
+ def get_handle(chat_token)
73
+ sender = @handle_keys[chat_token]
74
+ return sender
75
+ end
76
+
77
+ # server tell a single socket
78
+ def send_message(io, opcode, args)
79
+ msg = opcode + "::!!::" + args.join("::!!::")
80
+ sock_send io, msg
81
+ end
82
+
83
+ def sock_send io, msg
84
+ msg = "#{msg}\0"
85
+ log msg
86
+ io.send msg, 0
87
+ end
88
+
89
+ # server tell all sockets except
90
+ # if sender is nil then everyone
91
+ def broadcast_message(sender, opcode, args)
92
+ msg = opcode + "::!!::" + args.join("::!!::")
93
+ broadcast msg, sender
94
+ end
95
+
96
+ def build_chat_log
97
+ return "" unless @scrollback
98
+ out = ""
99
+ @buffer.each do |msg|
100
+ out += "#{msg[0]}: #{msg[1]}\n"
101
+ end
102
+ out
103
+ end
104
+
105
+
106
+ def clean_handles
107
+ @handle_keys.each do |k, v|
108
+ if @handle_last_pinged[v] && @handle_last_pinged[v] < Time.now - 30
109
+ log "removed clone handle: #{v}"
110
+ remove_user_by_handle(v)
111
+ end
112
+ end
113
+ end
114
+
115
+ def build_handle_list
116
+ return @handles.join("\n")
117
+ end
118
+
119
+ # react to allowed commands
120
+ def parse_line(line, io)
121
+ parr = line.split("::!!::")
122
+ command = parr[0]
123
+ if command == "SIGNON"
124
+ handle = parr[1]
125
+ password = parr[2]
126
+
127
+ if !@handles.length == 0 && @handles.include?(handle)
128
+ send_message(io, "ALERT", ["Your handle is in use."])
129
+ io.close
130
+ return
131
+ end
132
+
133
+ if handle == nil || handle == ""
134
+ send_message(io, "ALERT", ["You cannot have a blank name."])
135
+ #remove_dead_socket io
136
+ io.close
137
+ return
138
+ end
139
+
140
+ if ((@password == password) || ((password === nil) && (@password == "")))
141
+ # uuid are guaranteed unique
142
+ chat_token = rand(36**8).to_s(36)
143
+ @mutex.synchronize do
144
+ @handle_keys[chat_token] = handle
145
+ @socket_keys[io] = chat_token
146
+ # @port_keys[io.peeraddr[1]] = chat_token
147
+ # not on list until pinged.
148
+ @handles << handle
149
+ @sockets << io
150
+ end
151
+ send_message(io, "TOKEN", [chat_token, handle, @server_name])
152
+ broadcast_message(io, "JOIN", [handle])
153
+ else
154
+
155
+ send_message(io, "ALERT", ["Password is incorrect."])
156
+ io.close
157
+
158
+ end
159
+
160
+ return
161
+
162
+ end
163
+
164
+ # auth
165
+ chat_token = parr.last
166
+
167
+ if check_token(chat_token)
168
+ handle = get_handle(chat_token)
169
+ if command == "GETHANDLES"
170
+ send_message(io, "HANDLES", [build_handle_list])
171
+ elsif command == "GETBUFFER"
172
+ buffer = build_chat_log
173
+ send_message(io, "BUFFER", [buffer])
174
+ elsif command == "MESSAGE"
175
+ msg = parr[1]
176
+ message = "#{handle}: #{msg}\n"
177
+ @buffer << [handle, msg]
178
+ broadcast_message(io, "SAY", [handle, msg])
179
+ elsif command == "PING"
180
+ unless @handles.include?(handle)
181
+ @handles << handle
182
+ end
183
+ @handle_last_pinged[handle] = Time.now
184
+ elsif command == "SIGNOFF"
185
+ broadcast_message(nil, "LEAVE", [handle])
186
+ end
187
+ end
188
+ end
189
+
190
+ def pong_everyone
191
+ #log "trying to pong"
192
+ unless @sockets.length == 0 && !self.stopped?
193
+ #log "ponging"
194
+ broadcast_message(nil, "PONG", [build_handle_list])
195
+ sleep 5
196
+ clean_handles
197
+ end
198
+ end
199
+
200
+ def start_pong_loop
201
+ Thread.new do
202
+ loop do
203
+ sleep 5
204
+ pong_everyone
205
+ end
206
+ end
207
+ end
208
+
209
+ # def disconnecting(clientPort)
210
+ # log "disconnect event"
211
+ # ct = @port_keys[clientPort]
212
+ # handle = @handle_keys[ct]
213
+ # if handle
214
+ # log "disconnect removal event"
215
+ # remove_dead_socket ct
216
+ # end
217
+ # super(clientPort)
218
+ # end
219
+ def starting
220
+ log("GlobalChat2 Server Running")
221
+ start_pong_loop
222
+ end
223
+
224
+ def serve(io)
225
+ loop do
226
+ data = ""
227
+ begin
228
+ while line = io.recv(1)
229
+ break if line == "\0"
230
+ data += line
231
+ end
232
+ rescue
233
+ log "recv break removal event"
234
+ remove_dead_socket io #, true
235
+ break
236
+ end
237
+ unless data == ""
238
+ log "#{data}"
239
+ parse_line(data, io)
240
+ end
241
+ end
242
+ end
243
+
244
+ def status
245
+ passworded = (self.password != "")
246
+ scrollback = self.scrollback
247
+ log "#{@server_name} running on GlobalChat2 3.0 platform Replay:#{scrollback} Passworded:#{passworded}"
248
+ end
249
+
250
+ def log(msg)
251
+ puts msg
252
+ end
253
+
254
+
255
+ def save_chat_log
256
+ log "saving chatlog"
257
+ @pstore.transaction do
258
+ @pstore[:log] = @buffer
259
+ #p @pstore[:log]
260
+ end
261
+
262
+ end
263
+
264
+ def load_chat_log
265
+ log "loading chatlog"
266
+ @pstore.transaction(true) do
267
+ @buffer = @pstore[:log] || []
268
+ #p @buffer
269
+ end
270
+ end
271
+
272
+ end
273
+
274
+
275
+ def ping_nexus(chatnet_name, host, port)
276
+ puts "Pinging NexusNet that I'm Online!!"
277
+ uri = URI.parse("http://nexusnet.herokuapp.com/online")
278
+ query = {:name => chatnet_name, :port => port, :host => host}
279
+ uri.query = URI.encode_www_form( query )
280
+ Net::HTTP.get(uri)
281
+ $published = true
282
+ end
283
+
284
+ def nexus_offline
285
+ puts "Informing NexusNet that I have exited!!!"
286
+ Net::HTTP.get_print("nexusnet.herokuapp.com", "/offline")
287
+ end
288
+
289
+ at_exit do
290
+ nexus_offline
291
+ $gc.save_chat_log
292
+ end
293
+
294
+ $gc = GlobalChatServer.new(9994, '0.0.0.0', 1000, $stderr, true)
295
+ $gc.password = "" # set a password here
296
+ $gc.scrollback = true
297
+ $gc.start
298
+
299
+ if ENV["RUBY_VERSION"] && ENV["RUBY_VERSION"].include?("1.9")
300
+ ping_nexus("GlobalChatNet2", "localhost", $gc.port)
301
+ end
302
+
303
+ $gc.status
304
+
305
+ $gc.join
306
+
307
+
308
+
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: globalchat
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jonathan "jsilver1er" Silverman
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-11-25 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: qtbindings
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 4.8.3.0
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 4.8.3.0
30
+ description: GlobalChat 2 Pro Chat Client
31
+ email:
32
+ - jsilverone@me.com
33
+ executables:
34
+ - globalchat
35
+ extensions: []
36
+ extra_rdoc_files: []
37
+ files:
38
+ - .DS_Store
39
+ - .gitignore
40
+ - .rvmrc
41
+ - Gemfile
42
+ - GlobalChat.ui
43
+ - LICENSE
44
+ - LICENSE.rtf
45
+ - README.md
46
+ - Rakefile
47
+ - ServerList.ui
48
+ - gc2-qtruby.gemspec
49
+ - gchat2pro.pstore
50
+ - global_chat_2_pro.rb
51
+ - globalchat2.ico
52
+ - lib/gc2-qtruby.rb
53
+ - lib/gc2-qtruby/version.rb
54
+ - server.rb
55
+ - bin/globalchat
56
+ homepage: http://globalchat2.net
57
+ licenses: []
58
+ post_install_message:
59
+ rdoc_options: []
60
+ require_paths:
61
+ - .
62
+ required_ruby_version: !ruby/object:Gem::Requirement
63
+ none: false
64
+ requirements:
65
+ - - ! '>='
66
+ - !ruby/object:Gem::Version
67
+ version: '0'
68
+ required_rubygems_version: !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ! '>='
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ requirements: []
75
+ rubyforge_project:
76
+ rubygems_version: 1.8.24
77
+ signing_key:
78
+ specification_version: 3
79
+ summary: QTRuby crossplatform version
80
+ test_files: []