globalchat 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,439 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'bundler/setup'
5
+
6
+ require 'Qt4'
7
+ require 'qtuitools'
8
+ require 'net/http'
9
+ require 'socket'
10
+ require 'thread'
11
+ require 'pstore'
12
+
13
+
14
+ class GlobalChatController < Qt::Object
15
+
16
+ attr_accessor :chat_token,
17
+ :chat_buffer,
18
+ :handles_list,
19
+ :nicks,
20
+ :handle,
21
+ :handle_text_field,
22
+ :connect_button,
23
+ :server_list_window,
24
+ :chat_window,
25
+ :chat_window_text,
26
+ :chat_message,
27
+ :application,
28
+ :scroll_view,
29
+ :last_scroll_view_height,
30
+ :host,
31
+ :port,
32
+ :password,
33
+ :ts,
34
+ :server_name
35
+
36
+ signals :updateChatViews, :updateTitles, :beep
37
+
38
+
39
+ def sendMessage
40
+ begin
41
+ @message = self.chat_message.text
42
+ if @message != ""
43
+ post_message(@message)
44
+ self.chat_message.text = ''
45
+ end
46
+ rescue
47
+ autoreconnect
48
+ end
49
+ end
50
+
51
+ def sign_on
52
+ #log "Connecting to: #{@host} #{@port}"
53
+ begin
54
+ @ts = TCPSocket.open(@host, @port)
55
+ rescue
56
+ log("Could not connect to GlobalChat server. Will retry in 5 seconds.")
57
+ return false
58
+ end
59
+ @last_ping = Time.now # fake ping
60
+ sign_on_array = @password == "" ? [@handle] : [@handle, @password]
61
+ send_message("SIGNON", sign_on_array)
62
+ begin_async_read_queue
63
+ $autoreconnect = true
64
+ true
65
+ end
66
+
67
+ def autoreconnect
68
+ unless $autoreconnect == false
69
+ loop do
70
+ sleep 5
71
+ if sign_on
72
+ break
73
+ end
74
+ end
75
+ end
76
+ end
77
+
78
+ def return_to_server_list
79
+ #@mutex.synchronize do
80
+ alert "GlobalChat connection crashed."
81
+ $gc.hide
82
+ $sl.show
83
+ #end
84
+ end
85
+
86
+ def update_and_scroll
87
+ emit updateChatViews
88
+ end
89
+
90
+ def begin_async_read_queue
91
+ @mutex = Mutex.new
92
+ Thread.new do
93
+ loop do
94
+ #sleep 0.1
95
+ data = ""
96
+ begin
97
+ while line = @ts.recv(1)
98
+ # pongout disconnect reconnect below...
99
+ #raise if @last_ping < Time.now - 120 # opted out
100
+ break if line == "\0"
101
+ data += line
102
+ end
103
+ rescue
104
+ autoreconnect
105
+ break
106
+ end
107
+ data = data.force_encoding("UTF-8")
108
+ parse_line(data)
109
+ end
110
+ end
111
+ end
112
+
113
+ def parse_line(line)
114
+ $stderr.print "#{line}\n"
115
+ parr = line.split("::!!::")
116
+ command = parr.first
117
+ if command == "TOKEN"
118
+ @chat_token = parr[1]
119
+ @handle = parr[2]
120
+ @server_name = parr[3]
121
+ emit updateTitles
122
+ output_to_chat_window "Connected to #{@server_name} \n"
123
+ ping
124
+ get_handles
125
+ $connected = true
126
+ elsif command == "PONG"
127
+ @nicks = parr.last.split("\n").uniq
128
+ @handles_list.clear
129
+ @nicks.each do |nick|
130
+ @handles_list.add_item(nick)
131
+ end
132
+ ping
133
+ elsif command == "HANDLES"
134
+ @nicks = parr.last.split("\n").uniq
135
+ @handles_list.clear
136
+ @nicks.each do |nick|
137
+ @handles_list.add_item(nick)
138
+ end
139
+ get_log
140
+ elsif command == "BUFFER"
141
+ puts "got log"
142
+ buffer = parr[1]
143
+ unless buffer == "" || buffer == nil
144
+ @chat_buffer = buffer
145
+ update_and_scroll
146
+ #output_to_chat_window(buffer)
147
+ end
148
+ elsif command == "SAY"
149
+ handle = parr[1]
150
+ msg = parr[2]
151
+ add_msg(handle, msg)
152
+ elsif command == "JOIN"
153
+ handle = parr[1]
154
+ self.nicks << handle
155
+ output_to_chat_window("#{handle} has entered\n")
156
+ @handles_list.add_item(handle)
157
+ elsif command == "LEAVE"
158
+ handle = parr[1]
159
+ output_to_chat_window("#{handle} has exited\n")
160
+ self.nicks.delete(handle)
161
+ @handles_list.remove_item(handle)
162
+ elsif command == "ALERT"
163
+ # if you get an alert
164
+ # you logged in wrong
165
+ # native alerts
166
+ # are not part of
167
+ # chat experience
168
+ text = parr[1]
169
+ alert(text)
170
+
171
+ return_to_server_list
172
+ end
173
+ end
174
+
175
+
176
+ def send_message(opcode, args)
177
+ msg = opcode + "::!!::" + args.join("::!!::")
178
+ msg = msg.force_encoding("UTF-8")
179
+ sock_send @ts, msg
180
+ end
181
+
182
+ def alert(msg)
183
+ Qt::MessageBox.critical(self, "Alert!", msg)
184
+ end
185
+
186
+ def sock_send io, msg
187
+ begin
188
+ $stderr.print "#{msg}\n"
189
+ msg = "#{msg}\0"
190
+ io.send msg, 0
191
+ rescue
192
+ autoreconnect
193
+ end
194
+ end
195
+
196
+ def post_message(message)
197
+ send_message "MESSAGE", [message, @chat_token]
198
+ add_msg(self.handle, message)
199
+ end
200
+
201
+ def add_msg(handle, message)
202
+ if @handle != handle && message.include?(@handle)
203
+ emit beep
204
+ end
205
+ msg = "#{handle}: #{message}\n"
206
+ output_to_chat_window(msg)
207
+ end
208
+
209
+ def get_log
210
+ send_message "GETBUFFER", [@chat_token]
211
+ end
212
+
213
+ def get_handles
214
+ send_message "GETHANDLES", [@chat_token]
215
+ end
216
+
217
+ def sign_out
218
+ send_message "SIGNOFF", [@chat_token]
219
+ @ts.close
220
+ end
221
+
222
+ def ping
223
+ @last_ping = Time.now
224
+ send_message("PING", [@chat_token])
225
+ end
226
+
227
+ def log str
228
+ puts str
229
+ #output_to_chat_window(str)
230
+ end
231
+
232
+ def output_to_chat_window str
233
+ @mutex.synchronize do
234
+ @chat_buffer += "#{str}"
235
+ update_and_scroll
236
+ end
237
+ end
238
+
239
+ end
240
+
241
+
242
+
243
+ class ServerList < Qt::Widget
244
+
245
+ signals :updateTitle
246
+
247
+ def initialize(parent=nil)
248
+ super parent
249
+ loader = Qt::UiLoader.new
250
+ file = Qt::File.new 'ServerList.ui' do
251
+ open Qt::File::ReadOnly
252
+ end
253
+ window = loader.load file
254
+ file.close
255
+
256
+ @pstore = PStore.new("gchat2pro.pstore")
257
+
258
+ @sl = window.findChild(Qt::ListWidget, "listWidget")
259
+ @handle = window.findChild(Qt::LineEdit, "lineEdit")
260
+ @host = window.findChild(Qt::LineEdit, "lineEdit_2")
261
+ @port = window.findChild(Qt::LineEdit, "lineEdit_3")
262
+ @password = window.findChild(Qt::LineEdit, "lineEdit_4")
263
+ @refresh = window.findChild(Qt::PushButton, "pushButton")
264
+ @connect = window.findChild(Qt::PushButton, "pushButton_2")
265
+
266
+ @sl.connect(SIGNAL "currentTextChanged(const QString&)") { |item| get_info(item) }
267
+ @refresh.connect(SIGNAL :clicked) { refresh }
268
+ @connect.connect(SIGNAL :clicked) { connect }
269
+
270
+ self.layout = Qt::VBoxLayout.new do |l|
271
+ l.addWidget(window)
272
+ end
273
+
274
+ self.windowTitle = tr("Server List")
275
+
276
+ get_servers
277
+
278
+ load_prefs
279
+ end
280
+
281
+ def refresh
282
+ @sl.clear
283
+ get_servers
284
+ end
285
+
286
+ def load_prefs
287
+ begin
288
+ @pstore.transaction do
289
+ @handle.text = @pstore["handle"] || ""
290
+ @host.text = @pstore["host"] || ""
291
+ @port.text = @pstore["port"] || ""
292
+ end
293
+ rescue
294
+ puts "no pstore yet"
295
+ end
296
+ end
297
+
298
+ def save_prefs
299
+ @pstore.transaction do
300
+ @pstore["handle"] = @handle.text
301
+ @pstore["host"] = @host.text
302
+ @pstore["port"] = @port.text
303
+ end
304
+ end
305
+
306
+ def get_info(name)
307
+ if name != "" && name != nil
308
+ row = @names.index(name)
309
+ @host.text = @server_list_hash[row][:host]
310
+ @port.text = @server_list_hash[row][:port]
311
+ end
312
+ end
313
+
314
+
315
+ def get_servers
316
+
317
+ Thread.new do
318
+ @server_list_hash = Net::HTTP.get('nexusnet.herokuapp.com', '/msl').
319
+ split("\n").
320
+ collect do |s|
321
+ par = s.split("-!!!-")
322
+ {:host => par[1], :name => par[0], :port => par[2]}
323
+ end
324
+
325
+
326
+ @names = @server_list_hash.map { |i| i[:name] }
327
+
328
+ update_servers
329
+ end
330
+
331
+ end
332
+
333
+ def update_servers
334
+ @sl.clear
335
+ @names.each do |name|
336
+ @sl.add_item(name)
337
+ end
338
+ end
339
+
340
+
341
+ def connect
342
+ # save defaults
343
+ save_prefs
344
+ self.hide
345
+ gc = GlobalChat.new(@handle.text, @host.text, @port.text, @password.text)
346
+ gc.show
347
+ end
348
+
349
+ end
350
+
351
+
352
+ class GlobalChat < Qt::Widget
353
+
354
+ attr_accessor :handles, :chat_window_text, :chat_message, :gcc
355
+
356
+ def initialize(handle, host, port, password, parent=nil)
357
+ super parent
358
+
359
+ block=Proc.new{ Thread.pass }
360
+ timer=Qt::Timer.new(window)
361
+ invoke=Qt::BlockInvocation.new(timer, block, "invoke()")
362
+ Qt::Object.connect(timer, SIGNAL("timeout()"), invoke, SLOT("invoke()"))
363
+ timer.start(1)
364
+
365
+ loader = Qt::UiLoader.new
366
+ file = Qt::File.new 'GlobalChat.ui' do
367
+ open Qt::File::ReadOnly
368
+ end
369
+ window = loader.load file
370
+ file.close
371
+
372
+ @handles_list = window.findChild(Qt::ListWidget, "listWidget")
373
+ @chat_window_text = window.findChild(Qt::TextEdit, "textEdit")
374
+ @chat_message = window.findChild(Qt::LineEdit, "lineEdit")
375
+
376
+ self.layout = Qt::VBoxLayout.new do |l|
377
+ l.addWidget(window)
378
+ end
379
+
380
+ self.windowTitle = tr("GlobalChat")
381
+
382
+ # UI ETC
383
+ @chat_message.connect(SIGNAL :returnPressed) { @gcc.sendMessage }
384
+ @handles_list.connect(SIGNAL "currentTextChanged(const QString&)") { |item| foghornMe(item) }
385
+
386
+ @gcc = GlobalChatController.new
387
+
388
+ @gcc.connect(SIGNAL :updateChatViews) { updateChatViews }
389
+ @gcc.connect(SIGNAL :updateTitles) { updateTitles }
390
+ @gcc.connect(SIGNAL :beep) { beep }
391
+
392
+ at_exit do
393
+ @gcc.sign_out
394
+ end
395
+
396
+ # binding.pry
397
+ Thread.new do
398
+ @gcc.handle = handle
399
+ @gcc.host = host
400
+ @gcc.port = port
401
+ @gcc.password = password
402
+ @gcc.nicks = []
403
+ @gcc.chat_buffer = ""
404
+ @gcc.handles_list = @handles_list
405
+ @gcc.chat_message = @chat_message
406
+ @gcc.chat_window_text = @chat_window_text
407
+ @gcc.autoreconnect unless @gcc.sign_on
408
+ end
409
+
410
+ end
411
+
412
+ def foghornMe(name)
413
+ if !(name == "") && !(name == nil)
414
+ @chat_message.text = "#{name}: "
415
+ @chat_message.setFocus
416
+ end
417
+ end
418
+
419
+ def beep
420
+ puts "\a"
421
+ end
422
+
423
+ def updateTitles
424
+ self.windowTitle = @gcc.server_name
425
+ end
426
+
427
+ def updateChatViews
428
+ @chat_window_text.text = @gcc.chat_buffer
429
+ @chat_window_text.verticalScrollBar.setSliderPosition(@chat_window_text.verticalScrollBar.maximum)
430
+ end
431
+
432
+ end
433
+
434
+
435
+ app = Qt::Application.new ARGV
436
+ # Qt.debug_level = Qt::DebugLevel::High
437
+ sl = ServerList.new
438
+ sl.show
439
+ app.exec
data/globalchat2.ico ADDED
Binary file
@@ -0,0 +1,5 @@
1
+ module Gc2
2
+ module Qtruby
3
+ VERSION = "1.0.0"
4
+ end
5
+ end
data/lib/gc2-qtruby.rb ADDED
@@ -0,0 +1,7 @@
1
+ require "gc2-qtruby/version"
2
+
3
+ module Gc2
4
+ module Qtruby
5
+ # Your code goes here...
6
+ end
7
+ end