|
@@ -2,6 +2,7 @@
|
|
|
|
|
|
require 'eventmachine'
|
|
|
require 'digest/md5'
|
|
|
+require 'fiber'
|
|
|
|
|
|
|
|
|
|
|
@@ -57,26 +58,26 @@ module InterconnectionPointProtocolHandler
|
|
|
|
|
|
@@connected_clients = Array.new
|
|
|
@@broadcasts = Hash.new
|
|
|
-
|
|
|
+
|
|
|
# default method that is being run on connection!
|
|
|
def post_init # connection of someone starts here...
|
|
|
@username = nil
|
|
|
end
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
### getters
|
|
|
def entered_username?
|
|
|
!@username.nil? && !@username.empty? # then it's true
|
|
|
end
|
|
|
-
|
|
|
+
|
|
|
def username
|
|
|
@username
|
|
|
end
|
|
|
-
|
|
|
+
|
|
|
def my_roles
|
|
|
return $user_roles[@username]
|
|
|
end
|
|
|
-
|
|
|
+
|
|
|
def my_cmds
|
|
|
return my_roles.collect {|v| $role_commands[v]}.flatten
|
|
|
end
|
|
@@ -87,7 +88,7 @@ module InterconnectionPointProtocolHandler
|
|
|
@@connected_clients.each {|c| users.push(c.username)}
|
|
|
return users
|
|
|
end # of ousers
|
|
|
-
|
|
|
+
|
|
|
### checkers
|
|
|
def allowed_cmd(inputmessage)
|
|
|
my_cmds.each{|c|
|
|
@@ -106,17 +107,17 @@ module InterconnectionPointProtocolHandler
|
|
|
return false
|
|
|
end
|
|
|
end
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
|
|
|
### actions
|
|
|
def put_log(msg)
|
|
|
puts "#{Time.now.utc.strftime("%Y-%m-%d %H:%M:%S")}: #{msg}"
|
|
|
end
|
|
|
-
|
|
|
+
|
|
|
# searches through our hash of saved connections and writes them a messages.
|
|
|
def write_user(input, username = nil)
|
|
|
- if not username
|
|
|
+ if not username
|
|
|
username = @username
|
|
|
end
|
|
|
if connection = @@connected_clients.find { |c| c.username == username }
|
|
@@ -125,7 +126,7 @@ module InterconnectionPointProtocolHandler
|
|
|
connection.send_data line
|
|
|
end
|
|
|
end # of write_user
|
|
|
-
|
|
|
+
|
|
|
# searches through roles and writes those users on their connections
|
|
|
def write_role(role, input, *exempts)
|
|
|
#find users with role
|
|
@@ -134,16 +135,16 @@ module InterconnectionPointProtocolHandler
|
|
|
if v.include? role
|
|
|
users.push(k)
|
|
|
end
|
|
|
- }
|
|
|
-
|
|
|
+ }
|
|
|
+
|
|
|
# find users that are online and inside Array "users"
|
|
|
lala = Array.new
|
|
|
- users.each {|v|
|
|
|
- if ousers.include? v
|
|
|
+ users.each {|v|
|
|
|
+ if ousers.include? v
|
|
|
lala.push(v)
|
|
|
end
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
# now write to them
|
|
|
lala.each {|user|
|
|
|
if not exempts.include? user
|
|
@@ -151,51 +152,51 @@ module InterconnectionPointProtocolHandler
|
|
|
end
|
|
|
}
|
|
|
end # of write_role()
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
# what happens with what input?!
|
|
|
def inputting(input)
|
|
|
-
|
|
|
+
|
|
|
write_user("SYS You typed: #{input}")
|
|
|
-
|
|
|
+
|
|
|
if input =~ /^([A-Z_]+)/
|
|
|
cmd = $1
|
|
|
end
|
|
|
# now we have the cmd .. or not ;)
|
|
|
-
|
|
|
+
|
|
|
if input =~ /^[A-Z_]+ (.+)/
|
|
|
payload = $1
|
|
|
end
|
|
|
# now we can use payload
|
|
|
|
|
|
if allowed_cmd(cmd)
|
|
|
-
|
|
|
+
|
|
|
### typical system commands follow
|
|
|
if cmd == "PING"
|
|
|
write_user("PONG")
|
|
|
-
|
|
|
+
|
|
|
elsif cmd == "C"
|
|
|
-
|
|
|
+
|
|
|
if payload =~ /^(.+)$/
|
|
|
write_role($default_role, "C #{@username}: #{$1}")
|
|
|
-
|
|
|
+
|
|
|
else
|
|
|
write_user("SYS Format is C <chattext>")
|
|
|
end
|
|
|
-
|
|
|
+
|
|
|
elsif cmd == "WHO"
|
|
|
ousers.each {|ouser| write_user("WHO_RE #{ouser} ROLES: #{$user_roles[ouser].join(", ")}")}
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
elsif cmd == "PART"
|
|
|
write_user("SYS Goodbye '#{@username}'.")
|
|
|
write_role($default_role, "PARTED User '#{@username}' just left the party.", @username)
|
|
|
return "bye"
|
|
|
-
|
|
|
+
|
|
|
###now for the good stuff, broadcasting
|
|
|
elsif cmd == "REQ_BC"
|
|
|
-
|
|
|
+
|
|
|
# help with format .. but send the raw payload
|
|
|
if payload =~ /^(.+),(.+),(.+),'(.+)','(.+)'$/
|
|
|
# n f s ni txt
|
|
@@ -207,136 +208,174 @@ module InterconnectionPointProtocolHandler
|
|
|
source = $3
|
|
|
nickname = $4
|
|
|
text = $5
|
|
|
-
|
|
|
+
|
|
|
if not network =~ /^(QWalt)|(QDEV)/
|
|
|
write_user("SYS Network name #{network} is unknown: QWalt or QDEV allowed.")
|
|
|
error = 1
|
|
|
end
|
|
|
-
|
|
|
+
|
|
|
if not freqname =~ /^(-qw-)|(-spam-)|(-dev-)/
|
|
|
write_user("SYS Frequency name is unknown #{freqname}")
|
|
|
error = 1
|
|
|
end
|
|
|
-
|
|
|
- if not source =~ /^(#.+)|(qw:\/\/)|(http:\/\/)/
|
|
|
+
|
|
|
+ if source =~ /^(#.+)|(qw:\/\/)|(http:\/\/)/
|
|
|
+
|
|
|
+ else
|
|
|
write_user("SYS Source string is not in the form ^(#.+)|(qw:\/\/)|(http:\/\/) was: #{source}")
|
|
|
error = 1
|
|
|
end
|
|
|
-
|
|
|
- if not nickname =~ /^.+/
|
|
|
+
|
|
|
+ if not nickname =~ /^.+/
|
|
|
write_user("SYS Nickname string is not in the form ^.+ #{nickname}")
|
|
|
error = 1
|
|
|
end
|
|
|
-
|
|
|
+
|
|
|
if not text =~ /^.+/
|
|
|
write_user("SYS Message string is not in the form ^.+ #{text}")
|
|
|
error = 1
|
|
|
end
|
|
|
-
|
|
|
+
|
|
|
else # of check syntax
|
|
|
write_user("SYS Command format is REQ_BC <network>,<frequency>,<source/channel>,'<nickname>','<message>'")
|
|
|
error = 1
|
|
|
end
|
|
|
-
|
|
|
+
|
|
|
if error == 0
|
|
|
-
|
|
|
+
|
|
|
# send REQ_BC to the corresponding role.
|
|
|
bcid = Digest::MD5.hexdigest("%d %s %s %s %s %s" % [Time.now.utc.to_i, network, freqname, source, nickname, text])
|
|
|
-
|
|
|
+
|
|
|
# so it only reaches the issuer of REQ_BC
|
|
|
write_user("BC_ID #{bcid} for: #{network},#{freqname},#{source}")
|
|
|
@@broadcasts[bcid] = @username
|
|
|
-
|
|
|
+
|
|
|
+ # qw:// ip resolving
|
|
|
+ if source =~ /^qw:\/\/(.+):(\d+)(.*)$/
|
|
|
+ # ip address is 15 in length
|
|
|
+ iphost = $1
|
|
|
+ ipport = $2
|
|
|
+ rest = $3
|
|
|
+
|
|
|
+ if iphost =~ /^\d+\.\d+\.\d+\.\d+/
|
|
|
+ # resolve it to a dns name
|
|
|
+
|
|
|
+ f = Fiber.new do
|
|
|
+ Fiber.yield Resolv.getname(iphost)
|
|
|
+ end
|
|
|
+ host_name = f.resume
|
|
|
+ #host_name = ""
|
|
|
+
|
|
|
+ if host_name.nil? || host_name.empty?
|
|
|
+ host_name = iphost
|
|
|
+ else
|
|
|
+ # if the resulting dns is too long, use ip-address instead.
|
|
|
+ # if the resulting dns has too many dots, use ip-address instead.
|
|
|
+ if host_name.length > 23 || host_name.split(".").size >= 4
|
|
|
+ #put_log "cutting down host_name #{host_name} #{host_name.size} #{host_name.split(".").size}"
|
|
|
+ host_name = iphost
|
|
|
+ end
|
|
|
+ end
|
|
|
+ source = "qw://#{host_name}:#{ipport}#{rest}"
|
|
|
+ end
|
|
|
+ end # of if source qw://x.x.x.x:portzzz
|
|
|
+
|
|
|
+ # resolve
|
|
|
finalmessage = "BC %s %s,%s,%s,'%s','%s'" % [bcid, network, freqname, source, nickname, text]
|
|
|
write_role("broadcast", finalmessage, @username) # write to the role with the exempt of myself.
|
|
|
-
|
|
|
-
|
|
|
- end
|
|
|
+
|
|
|
+
|
|
|
+ end
|
|
|
#end of REQ_BC here..
|
|
|
-
|
|
|
+
|
|
|
elsif cmd == "BC_RE"
|
|
|
-
|
|
|
+
|
|
|
if payload =~ /^(.+) (.+)=(\d+),(.+)=(\d+)$/
|
|
|
-
|
|
|
+
|
|
|
bcid = $1
|
|
|
user_string = $2
|
|
|
user_count = $3
|
|
|
item_string = $4
|
|
|
item_count = $5
|
|
|
-
|
|
|
+
|
|
|
payload = "%s %s=%d,%s=%d" % [bcid, user_string, user_count, item_string, item_count]
|
|
|
# according bcid it is possible to get the originating user.. so send only to his topic!
|
|
|
-
|
|
|
+
|
|
|
if @@broadcasts[bcid]
|
|
|
to_user = @@broadcasts[bcid]
|
|
|
-
|
|
|
+
|
|
|
write_user("SYS Broadcast reply bcid: #{bcid} underway to #{to_user}.")
|
|
|
write_user("#{cmd} #{payload}", to_user)
|
|
|
else
|
|
|
write_user("SYS Broadcast reply bcid: #{bcid} underway.")
|
|
|
write_role("broadcast", "#{cmd} #{payload}", @username)
|
|
|
end
|
|
|
-
|
|
|
+
|
|
|
else # of bc_re format check
|
|
|
put_log "SYS Format is BC_RE <bcid> <userstring>=<usercount>,<itemstring>=<itemcount>"
|
|
|
end
|
|
|
-
|
|
|
+
|
|
|
end
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
else # of if allowed command
|
|
|
write_user("SYS Command #{input} not allowed, your commands are: #{my_cmds.join(", ")}.")
|
|
|
end # of if allowed command
|
|
|
-
|
|
|
+
|
|
|
end # of inputting!
|
|
|
-
|
|
|
-
|
|
|
-
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
# default method that is being run on receiving data!
|
|
|
def receive_data(data) # connection receives a line on the server end
|
|
|
-
|
|
|
- if not entered_username? # oh, it seems, it's a new user
|
|
|
- # this is the user name coming in!
|
|
|
- username = data.chomp
|
|
|
-
|
|
|
- if online(username)
|
|
|
- put_log "SYS User '#{username}' tried to double connect. Say bye bye."
|
|
|
- send_data "SYS Hey '#{username}', only one connection allowed. Bye.\n"
|
|
|
- EventMachine.add_timer 1, proc { close_connection }
|
|
|
-
|
|
|
- return false
|
|
|
- end
|
|
|
-
|
|
|
- if not $user_roles.any? {|k, v| k.include? username}
|
|
|
- put_log "SYS User '#{username}' unknown to me. Saying bye."
|
|
|
- send_data "SYS User '#{username}' unknown to me. Bye.\n"
|
|
|
-
|
|
|
- # disconnect him
|
|
|
- close_connection
|
|
|
- else
|
|
|
-
|
|
|
- @username = username
|
|
|
-
|
|
|
- @@connected_clients.push(self)
|
|
|
-
|
|
|
- put_log("SYS '#{@username}' connected. Online now: #{ousers.join(", ")}")
|
|
|
-
|
|
|
- write_user("HELLO Hi user '#{@username}'! How are you? I'm '#{$version}'")
|
|
|
- write_user("ROLES #{my_roles.join(", ")}")
|
|
|
- write_user("COMMANDS #{my_cmds.join(", ")}")
|
|
|
- write_role($default_role, "JOINED User '#{@username}' just joined the party.", @username)
|
|
|
-
|
|
|
- end
|
|
|
- else # of username not known (first connect)
|
|
|
- # it's alive!
|
|
|
- inputter = inputting(data.chomp)
|
|
|
-
|
|
|
- if inputter == "bye"
|
|
|
- close_connection
|
|
|
- end
|
|
|
-
|
|
|
- end # of username not known
|
|
|
-
|
|
|
+
|
|
|
+ line = data.chomp unless data.chomp.nil?
|
|
|
+
|
|
|
+ if line
|
|
|
+
|
|
|
+ if entered_username? # oh, it's a known user
|
|
|
+ # it's alive!
|
|
|
+ inputter = inputting(line)
|
|
|
+
|
|
|
+ if inputter == "bye"
|
|
|
+ close_connection
|
|
|
+ end
|
|
|
+
|
|
|
+ else # of username known, then it seems to be the first connect
|
|
|
+
|
|
|
+ # and this line is the user name coming in!
|
|
|
+ username = line
|
|
|
+
|
|
|
+ if online(username)
|
|
|
+ put_log "SYS User '#{username}' tried to double connect. Say bye bye."
|
|
|
+ send_data "SYS Hey '#{username}', only one connection allowed. Bye.\n"
|
|
|
+ EventMachine.add_timer 1, proc { close_connection }
|
|
|
+
|
|
|
+ return false
|
|
|
+ end
|
|
|
+
|
|
|
+ if $user_roles.any? {|k| k.include? username}
|
|
|
+ @username = username
|
|
|
+
|
|
|
+ @@connected_clients.push(self)
|
|
|
+
|
|
|
+ put_log("SYS '#{@username}' connected. Online now: #{ousers.join(", ")}")
|
|
|
+
|
|
|
+ write_user("HELLO Hi user '#{@username}'! How are you? I'm '#{$version}'")
|
|
|
+ write_user("ROLES #{my_roles.join(", ")}")
|
|
|
+ write_user("COMMANDS #{my_cmds.join(", ")}")
|
|
|
+ write_role($default_role, "JOINED User '#{@username}' just joined the party.", @username)
|
|
|
+ else
|
|
|
+ put_log "SYS User '#{username}' unknown to me. Saying bye."
|
|
|
+ send_data "SYS User '#{username}' unknown to me. Bye.\n"
|
|
|
+
|
|
|
+ # disconnect him
|
|
|
+ close_connection
|
|
|
+ end
|
|
|
+
|
|
|
+ end # of username known
|
|
|
+ end # of line
|
|
|
+
|
|
|
end
|
|
|
|
|
|
# default method that is being run on disconnection!
|
|
@@ -345,18 +384,19 @@ module InterconnectionPointProtocolHandler
|
|
|
@@connected_clients.delete(self)
|
|
|
put_log "SYS '#{@username}' disconnected. Online now: #{ousers.join(", ")}"
|
|
|
end
|
|
|
-
|
|
|
+
|
|
|
end
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
def main
|
|
|
-
|
|
|
# #run: Note that this will block current thread.
|
|
|
- EventMachine.run {
|
|
|
- EventMachine.start_server "0.0.0.0", 7337, InterconnectionPointProtocolHandler
|
|
|
- }
|
|
|
+ EventMachine.run do
|
|
|
+
|
|
|
+ EventMachine.start_server("0.0.0.0", 7337, InterconnectionPointProtocolHandler)
|
|
|
+
|
|
|
+ end
|
|
|
end
|
|
|
|
|
|
main
|