1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030 |
- #!/usr/bin/env ruby
- require 'eventmachine'
- require 'digest/md5'
- require 'fiber'
- require 'geoip'
- require 'socket'
- require 'timeout'
- # .. allowed commands .. ROLES = CAPABILITIES
- # normal users have ROLE broadcast. Roles are defined on a per-user basis .. in a config.
- $version = "0.4em_cooldns_classes_for_caching"
- $debug = 0
- $role_commands = Hash[
- #noinspection RubyStringKeysInHashInspection
- 'everyone' => %w(PING WHO C PART),
- 'broadcast_admin' => %w(BC_ID BC BC_ENDCOUNT),
- 'broadcast' => %w(REQ_BC BC_RE),
-
- 'specbot_admin' => %w(REQ_ASSIGN REQ_UNASSIGN REQ_PING REQ_ASSIGNMENTS),
- 'specbot' => %w(ASSIGN_RE UNASSIGN_RE PING_RE ASSIGNMENTS_RE REQ_DNS),
- ]
- $default_role = "everyone"
- # which role is talking to which role?
- # effectively it says: this (local) command is sent to that (remote) topic .. that certain topic is read by that user with that role.
- $role_dialogs = Hash[
- #noinspection RubyStringKeysInHashInspection
- 'everyone' => %w(everyone),
-
- 'broadcast_admin' => %w(broadcast),
- 'broadcast' => %w(broadcast_admin),
-
- 'specbot_admin' => %w(specbot),
- 'specbot' => %w(specbot_admin),
- ]
- $user_roles = Hash[
- #noinspection RubyStringKeysInHashInspection
- 'paul_dev_eggdrop' => %w(everyone broadcast),
- 'paul_eggdrop' => %w(everyone broadcast),
-
- 'paul_dev_specbot' => %w(everyone broadcast specbot),
- 'paul_specbot' => %w(everyone broadcast specbot),
-
- 'qw.nu' => %w(everyone broadcast),
- 'qw.nu_poster' => %w(everyone broadcast),
-
- 'mihawk_dev_specbot' => %w(everyone broadcast specbot),
- 'mihawk_specbot' => %w(everyone broadcast specbot),
-
- 'central_brain' => %w(everyone broadcast_admin specbot_admin),
- ]
- $qw_list = Array.new
- $qw_list = [
- "89.149.194.72:27700",
- "84.200.47.113:30000",
- "89.149.194.72:27500",
- "84.200.47.113:28502",
- "89.149.194.72:30000",
- "89.149.194.72:27600",
- "93.186.192.16:28502",
- "84.200.47.113:28501",
- "93.186.192.16:28501",
- "188.40.130.10:27502",
- "93.186.192.16:30000",
- "188.40.130.10:27599",
- "188.40.130.10:27503",
- "194.109.69.75:28000",
- "194.109.69.75:27500",
- "194.109.69.75:27501",
- "194.109.69.76:28504",
- "188.165.243.56:30000",
- "188.40.130.10:27501",
- "194.109.69.76:28502",
- "194.109.69.76:28501",
- "194.109.69.76:28503",
- "62.24.64.11:27501",
- "62.24.64.11:44444",
- "188.40.103.81:27600",
- "62.24.64.11:30000",
- "194.109.69.75:27502",
- "91.121.69.201:30000",
- "37.59.63.97:28504",
- "188.40.130.10:27500",
- "188.165.243.56:28009",
- "37.59.63.97:28501",
- "62.24.64.11:27500",
- "37.59.63.97:28503",
- "194.109.69.76:30000",
- "188.165.243.56:28008",
- "188.165.243.56:28006",
- "188.165.243.56:28001",
- "188.165.243.56:28002",
- "93.186.192.16:27500",
- "91.121.69.201:27600",
- "37.59.63.97:28502",
- "91.121.223.163:28001",
- "188.165.243.56:28003",
- "109.74.195.224:30000",
- "178.79.183.178:27500",
- "77.74.194.189:27501",
- "91.121.69.201:27502",
- "188.165.243.56:28007",
- "109.74.195.224:27500",
- "213.5.176.135:27502",
- "77.74.194.189:27504",
- "178.79.172.251:27600",
- "77.74.194.189:27502",
- "77.74.194.189:27503",
- "213.5.176.135:27500",
- "109.74.195.224:27501",
- "89.104.194.146:27504",
- "89.104.194.146:27503",
- "89.104.194.146:27508",
- "213.5.176.136:27510",
- "213.5.176.135:27501",
- "213.5.176.135:27503",
- "77.74.194.189:30000",
- "89.149.194.72:27800",
- "89.104.194.146:27502",
- "89.104.194.146:27666",
- "89.104.194.146:27507",
- "89.104.194.146:27509",
- "89.104.194.146:30000",
- "188.165.243.56:28004",
- "89.104.194.146:27500",
- "89.104.194.146:27501",
- "194.109.69.76:27500",
- "89.104.194.146:27506",
- "94.236.92.49:27501",
- "91.121.69.201:27501",
- "213.239.214.134:27500",
- "89.104.194.146:27510",
- "95.131.48.86:27502",
- "94.236.92.49:27500",
- "94.236.92.49:30000",
- "95.131.48.86:27504",
- "78.137.161.109:27501",
- "188.165.243.56:28005",
- "178.217.185.104:27500",
- "178.217.185.104:27600",
- "178.217.185.104:30000",
- "87.102.202.23:27502",
- "78.137.161.109:27500",
- "89.104.194.146:27505",
- "87.102.202.23:27505",
- "178.217.185.104:27501",
- "91.121.69.201:27500",
- "82.141.152.3:27501",
- "82.141.152.3:27500",
- "83.179.23.16:28002",
- "109.74.7.60:27500",
- "212.62.234.153:27502",
- "83.179.23.16:28003",
- "195.54.182.34:27500",
- "83.179.23.16:28005",
- "212.62.234.153:27503",
- "95.143.243.24:27600",
- "83.179.23.16:28001",
- "212.62.234.153:27504",
- "78.137.161.109:27502",
- "83.179.23.16:28004",
- "212.62.234.153:27501",
- "95.143.243.24:27500",
- "109.228.137.161:28501",
- "95.143.243.24:27900",
- "83.226.149.218:27500",
- "83.226.149.218:28001",
- "83.226.149.218:28002",
- "83.226.149.218:28003",
- "193.1.40.166:27975",
- "87.237.112.11:30000",
- "217.30.184.104:27500",
- "78.108.53.19:27500",
- "78.108.53.19:27501",
- "195.54.142.7:28001",
- "193.1.40.166:27500",
- "87.237.112.11:27501",
- "195.54.142.7:30000",
- "195.54.142.7:28007",
- "217.119.36.79:30000",
- "95.131.48.86:27501",
- "195.54.142.7:28002",
- "195.54.142.7:28008",
- "80.101.105.103:27500",
- "87.237.112.11:27502",
- "217.119.36.79:27500",
- "81.170.128.75:28501",
- "217.119.36.79:28001",
- "193.1.40.167:27500",
- "217.119.36.79:28003",
- "217.119.36.79:28002",
- "81.170.128.75:30000",
- "81.170.128.75:28504",
- "195.54.142.7:28005",
- "195.54.142.7:28010",
- "81.170.128.75:28503",
- "93.81.254.63:27502",
- "212.42.38.88:27504",
- "81.170.128.75:28502",
- "93.81.254.63:27500",
- "81.170.128.75:28000",
- "212.42.38.88:27500",
- "82.203.213.117:28002",
- "212.42.38.88:30000",
- "93.81.254.63:30000",
- "82.203.213.117:28001",
- "212.42.38.88:27501",
- "212.42.38.88:27503",
- "93.81.254.63:27503",
- "93.81.254.63:27501",
- "82.203.213.117:30000",
- "95.131.48.86:27503",
- "83.252.244.76:27500",
- "212.42.38.88:27502",
- "195.54.142.7:28003",
- "95.31.4.132:30000",
- "83.252.244.76:27501",
- "93.81.254.63:30001",
- "195.54.142.7:28006",
- "82.203.213.117:28003",
- "95.143.243.24:27700",
- "84.234.185.215:27503",
- "84.234.185.215:27500",
- "84.234.185.215:27519",
- "84.234.185.215:27508",
- "84.234.185.215:27506",
- "84.234.185.215:27505",
- "195.54.142.7:28004",
- "84.234.185.215:27501",
- "195.54.142.7:28009",
- "212.109.128.148:27501",
- "84.234.185.215:27502",
- "31.209.7.104:28501",
- "194.79.85.66:27501",
- "194.79.85.66:30000",
- "95.84.164.245:27501",
- "194.79.85.66:27502",
- "83.222.112.157:30000",
- "212.109.128.148:27500",
- "94.100.6.66:27500",
- "129.241.205.153:28000",
- "84.234.185.215:27507",
- "129.241.205.153:27500",
- "95.84.164.245:27500",
- "69.31.82.226:27501",
- "69.31.82.226:30000",
- "130.240.207.177:30000",
- "69.31.82.226:28100",
- "69.31.82.226:27500",
- "69.31.82.226:28101",
- "69.31.82.226:28010",
- "69.31.82.226:30001",
- "69.31.82.226:28000",
- "69.31.82.226:28002",
- "93.186.192.16:28000",
- "195.222.130.83:27500",
- "84.200.47.113:28000",
- "130.85.56.131:27500",
- "108.174.51.73:28003",
- "96.8.113.36:27501",
- "96.8.113.36:27500",
- "68.100.130.114:27501",
- "65.31.69.75:27500",
- "108.174.51.73:28006",
- "65.31.69.75:27508",
- "108.174.51.73:30000",
- "67.81.59.41:27500",
- "108.174.51.73:28004",
- "217.18.138.23:27505",
- "108.174.51.73:28001",
- "68.100.130.114:27500",
- "174.49.198.60:27502",
- "174.49.198.60:27503",
- "209.239.113.236:27500",
- "174.49.198.60:27515",
- "217.119.36.79:28000",
- "108.174.51.73:28005",
- "74.91.115.244:28001",
- "174.49.198.60:27500",
- "74.91.115.244:28000",
- "199.101.96.48:27501",
- "96.8.113.36:30000",
- "174.101.185.59:27500",
- "67.228.69.114:27502",
- "199.101.96.48:27500",
- "108.174.51.73:28002",
- "199.192.229.74:28001",
- "74.86.171.201:27502",
- "67.228.69.114:27501",
- "74.86.171.201:27500",
- "67.228.69.114:26666",
- "199.192.228.71:27501",
- "199.192.229.74:28003",
- "74.86.171.201:27501",
- "199.192.229.74:30000",
- "199.192.229.74:28002",
- "74.91.115.244:28002",
- "199.192.228.71:27500",
- "199.101.96.48:30000",
- "199.101.96.48:28000",
- "199.192.229.74:28004",
- "199.192.228.71:30000",
- "65.31.238.37:27500",
- "31.209.7.104:28000",
- "208.131.136.169:27500",
- "66.212.17.78:27500",
- "200.177.229.11:27510",
- "200.177.229.11:27522",
- "200.177.229.11:27521",
- "200.177.229.11:27500",
- "190.96.80.67:27500",
- "200.177.229.11:27511",
- "200.177.229.11:27520",
- "190.96.80.67:27000",
- "202.37.129.186:27500",
- "202.37.129.186:27505",
- "202.37.129.186:27501",
- "219.88.241.81:27500",
- "202.172.99.2:28001",
- "202.172.99.2:28002",
- "202.172.99.2:28003",
- "202.172.99.2:27500",
- "210.50.4.11:27501",
- "202.172.99.2:27501",
- "210.50.4.11:27508",
- "210.50.4.11:27511",
- "210.50.4.11:27509",
- "210.50.4.11:27510",
- "122.99.118.2:28001",
- "210.50.4.11:27500",
- "210.50.4.11:27503",
- "210.50.4.11:27506",
- "210.50.4.11:27505",
- "210.50.4.11:27504",
- ]
- class GameServers
- attr_accessor :gameservers # now, @gameservers is accessible via GameServers.gameservers
- def initialize
- @gameservers = Hash.new
- @gameservers.default = {
- :reverse_dns => "",
- :hostname_dns => "",
- :cool_dns => "",
- :type => "",
- :serverinfos => "",
- :timestamp => 0,
- }
- @gameservers["blah:blah"]
- wat = Hash.new(@gameservers["blah:blah"])
- wat
- wat.store(:reverse_dns, "6")
- @gameservers.merge(wat)
- p @gameservers
- p @gameservers.default
- wat = Hash.new(@gameservers["blah:blah"])
- wat
- wat.store(:hostname_dns, "12")
- @gameservers.merge(wat)
- p @gameservers
- p @gameservers.default
- end
- def scanserver(iphostport, type="qw", force=false)
- put_log "scanserver drin"
- if iphostport =~ /^(\d+\.\d+\.\d+\.\d+):(\d{1,5})/
- iphost = $1
- ipport = $2
- if type == "qw"
- #p current
- # check if it already exists
- #if @gameservers["#{iphost}:#{ipport}"][:timestamp] > 0
- # if old general data, then freshly get general data...
- # if @gameservers["#{iphost}:#{ipport}"][:timestamp] + 60 * 60 * 20 < Time.now.utc.to_i || force == true
- # end # of old
- #else
- current = Hash.new
- serverinfos = qwstatus(iphost, ipport)
- current.store(:serverinfos, serverinfos)
- current.store(:reverse_dns, find_reverse_dname(iphost))
- current.store(:hostname_dns, qw_find_dname_by_serverinfos(serverinfos))
- current.store(:type, "qw")
- # set new timestamp
- current.store(:timestamp, Time.now.utc.to_i)
- @gameservers.store("#{iphost}:#{ipport}", current) # save it all.
- current.store(:cool_dns, find_cooldns(iphost, ipport))
- @gameservers.store("#{iphost}:#{ipport}", current) # save it all.
- #put_log "the saved one: #{@gameservers.fetch("#{iphost}:#{ipport}").fetch(:cool_dns)}"
- #puts "ALL"
- #p @gameservers
- #puts "DEFAULT of the hash"
- #p @gameservers.default
- #end
- end # of type qw
- end # of check form of iphostport parameter
- end # of scan()
- def scanserverlist(gs_array, type="qw")
- put_log "scanserverlist drin"
- gs_array.each do
- |gserver|
- scanserver(gserver, type)
- end
- put_log "End of scanning."
- put_log "foppa: #{@gameservers.fetch("89.104.194.146:27503")} "
- end # of scanserverlist()
- def get_cool_dns(iphost, ipport)
- put_log "get_cool_dns drin"
- @gameservers.fetch("#{iphost}:#{ipport}").fetch(:cool_dns)
- rescue
- scanserver("#{iphost}:#{ipport}", "qw")
- @gameservers.fetch("#{iphost}:#{ipport}").fetch(:cool_dns)
- end
- private # all following methods are private
- # returns serverinfo hash
- def qwstatus(iphost, ipport)
- put_log "qwstatus drin"
- udp_payload = [0xFF, 0xFF, 0xFF, 0xFF]
- udp_payload.concat(string2bytearray("status 23"))
- udp_payload.concat([0x0a]) # linefeed at the end
- udp_payload = udp_payload.pack("C*")
- #p udp_payload
- Timeout::timeout(2) do
- begin
- u2 = UDPSocket.new
- #put_log "#{iphost} #{ipport} #{udp_payload}"
- u2.send(udp_payload, 0, iphost, ipport)
- #put_log "sent"
- the_return = u2.recv(500)
- u2.close
- #put_log "muh #{the_return}"
- if the_return =~ /\W\W\W\Wn\\(.+)$/
- line = $1
- #put_log "line #{line}"
- matches = line.scan(/(.+?)\\(.+?)(\\|$)/)
- the_hash = Hash.new
- matches.each {
- |k, v, _|
- the_hash[k] = "#{v}"
- }
- return the_hash
- else
- return false
- end
- rescue Exception => e
- puts e.message
- end # of begin
- end # of Timeout
- end
- def find_cooldns_full(iphost, ipport)
- targetname = iphost
- # resolve it to a dns name (reverse lookup)
- if targetname == iphost # if it is still default
- put_log "Ip not resolved .. we try hostname dns finder"
- targetname = qw_find_dname_in_hostnames(iphost, ipport)
- end
- # resolve it to a dns name (reverse lookup)
- if targetname == iphost
- put_log "Still no resolve .. we try reverse dns lookup"
- targetname = find_reverse_dname(iphost)
- end
- return targetname
- end
- def find_cooldns(iphost, ipport)
- put_log "find_cooldns drin"
- current = @gameservers["#{iphost}:#{ipport}"] # only use this for reading...
- my_cooldns = iphost
- # we still haven't found a cool dns
- if (my_cooldns == iphost) && (not current[:hostname_dns].to_s.empty?)
- put_log "Try if #{current[:hostname_dns]} resolves to #{iphost}"
- begin
- ip_of_hostnamedns = Resolv.getaddress(current[:hostname_dns])
- if ip_of_hostnamedns && (ip_of_hostnamedns == iphost)
- # ok, we take it.
- put_log "Ok, we take #{current[:hostname_dns]} for #{iphost} here.."
- my_cooldns = current[:hostname_dns]
- else
- put_log "Found #{current[:hostname_dns]} but #{ip_of_hostnamedns} is not #{iphost}"
- end
- rescue Exception => e
- my_cooldns = iphost
- end
- end
- # we still haven't found a cool dns
- if (my_cooldns == iphost) && (not current[:reverse_dns].empty?)
- rdns = current[:reverse_dns]
- # if the resulting dns name...
- # .. is too long, use ip-address instead.
- # .. has too many dots, use ip-address instead.
- # .. has too many numbers, use ip-address instead.
- if rdns.length > 21 || rdns.split(".").size > 3 || rdns.scan(/\d/).size > 3
- put_log "cutting down host_name: #{rdns}, because:"
- put_log "length: #{rdns.length}"
- put_log "chunks count: #{rdns.split(".").size}"
- put_log "num count: #{rdns.scan(/\d/).size}"
- else
- my_cooldns = rdns
- end # of Resolv.getname
- end
- put_log "COOOOOOOOOOOOLDNS: #{my_cooldns}"
- my_cooldns
- end
- def find_reverse_dname(iphost)
- put_log "find_reverse_dname drin"
- Resolv.getname(iphost)
- rescue
- iphost
- end
- def qw_find_dname_by_udp(iphost, ipport)
- targetname = iphost # set a default
- # get hostname from a qw status packet! perhaps there's a DNS name inside, which we can use!
- status = qwstatus(iphost, ipport)
- p status
- if status["hostname"] =~ /([\w\.-]{3,}\.\w{2,4})/
- hostnamedns = $1.downcase
- begin
- ip_of_hostnamedns = Resolv.getaddress(hostnamedns)
- if ip_of_hostnamedns && (ip_of_hostnamedns == iphost)
- # ok, we take it.
- put_log "Ok, we take #{hostnamedns} for #{iphost} here.."
- targetname = hostnamedns
- else
- put_log "Found #{hostnamedns} but #{ip_of_hostnamedns} is not #{iphost}"
- end
- rescue Exception => e
- targetname = iphost
- end
- end
- targetname
- end
- def qw_find_dname_by_serverinfos(serverinfos)
- hostnamedns = ""
- begin
- hostname = serverinfos.fetch("hostname")
- if hostname =~ /([\w\.-]{3,}\.\w{2,4})/
- hostnamedns = $1.downcase
- end
- return hostnamedns
- rescue
- return ""
- end
- end
- end # of Class GameServers!
- def string2bytearray(text)
- return_array = Array.new
- text.each_byte{
- |b|
- return_array.push(b)
- }
- return_array
- end
- def put_log(msg)
- puts "#{Time.now.utc.strftime("%Y-%m-%d %H:%M:%S")}: #{msg}"
- end
- module CentralProtocolHandler
-
- @@connected_clients = Array.new
- @@broadcasts = Hash.new
- put_log "Server started"
- # 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
- $user_roles[@username]
- end
- def my_cmds
- my_roles.collect {|v| $role_commands[v]}.flatten
- end
- # returns online users by default by searching through saved connections
- def ousers
- users = Array.new
- @@connected_clients.each {|c| users.push(c.username)}
- users
- end # of ousers
- ### checkers
- def allowed_cmd(inputmessage)
- my_cmds.each{|c|
- #print "A #{c} B #{inputmessage}\n"
- if inputmessage =~ /^#{c}/
- return true
- end
- }
- false
- end
- def online(user)
- if ousers.include? user
- true
- else
- false
- end
- end
- ### actions
- # searches through our hash of saved connections and writes them a messages.
- def write_user(input, username = nil)
- if username.nil? || username.empty?
- username = @username
- end
- if @@connected_clients.find { |c| c.username == username }
- connection = @@connected_clients.find { |c| c.username == username }
- sometime = "#{Time.now.utc.strftime("%Y-%m-%d %H:%M:%S %z")}"
- line = "#{sometime}: #{input}\n"
- 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
- users = Array.new
- $user_roles.each {|k, v|
- 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
- lala.push(v)
- end
- }
- # now write to them
- lala.each {|user|
- if not exempts.include? user
- write_user(input, user)
- end
- }
- end # of write_role()
- # what happens with what input?!
- def inputting(input)
- put_log("to #{@username}: SYS You typed: #{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
- error = 0
- # $&
- # The string matched by the last successful pattern match in this scope, or nil if the last pattern match failed. (Mnemonic: like & in some editors.) This variable is r
- network = $1
- freqname = $2
- 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 source =~ /^(#.+)|(qw:\/\/)|(http:\/\/)/
- else
- write_user("SYS Source string is not in the form ^(#.+)|(qw:\/\/)|(http:\/\/) was: #{source}")
- error = 1
- end
- 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 payload has format
- write_user("SYS Command format is REQ_BC <network>,<frequency>,<source/channel>,'<nickname>','<message>'")
- error = 1
- end # of payload has format
- 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
- targetname = iphost # set a default
- ipport = $2
- rest = $3
- if iphost =~ /^\d+\.\d+\.\d+\.\d+/
- targetname = $gs.get_cool_dns(iphost, ipport)
- # find country code
- cc = GeoIP.new('GeoIP.dat').country(iphost)[3].to_s.downcase
- rest.prepend " #{cc}" unless cc.nil? || cc.empty? || targetname =~ /\.#{cc}$/
- end # if ip is x.x.x.x
- source = "qw://#{targetname}:#{ipport}#{rest}"
- 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 of REQ_BC here..
- elsif cmd == "REQ_DNS"
- # help with format .. but send the raw payload
- if payload =~ /^(\d+\.\d+\.\d+\.\d+):(\d{1,5})/
- iphost = $1
- ipport = $2
- put_log("to #{@username}: DNS_RE #{iphost}:#{ipport} #{targetname}")
- targetname = $gs.get_cool_dns(iphost, ipport)
- write_user("DNS_RE #{iphost}:#{ipport} #{targetname}") # write back to asking user.
- else # of payload has format
- write_user("SYS Command format is REQ_DNS <serverip>:<serverport>")
- error = 1
- end # of if payload has format
- #end of REQ_DNS 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
- data = data.chomp unless data.chomp.nil?
- data.each_line do |line|
- unless line.empty?
- if entered_username? # oh, it's a known user
- # it's alive! kill ping timer, set a new one:
- if @ping_timer
- EventMachine.cancel_timer(@ping_timer)
- end
- @ping_timer = EventMachine.add_periodic_timer 90, proc { write_user("PING alive?") }
- # work on input
- 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 {
- write_user("PING check forced", username)
- close_connection
- }
- return false
- end
- if $user_roles.any? {|k| k.include? username}
- @username = username
- @@connected_clients.push(self)
- @ping_timer = EventMachine.add_periodic_timer 90, proc { write_user("PING alive?") }
- # starting a pinger
- 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 unless line.empty?
- end # of data.each_line
- end # of receive data
- # default method that is being run on disconnection!
- def unbind # a connection goes bye bye
- if @username
- @@connected_clients.delete(self)
- if @ping_timer
- EventMachine.cancel_timer(@ping_timer)
- end
- put_log "SYS '#{@username}' disconnected."
- end
- put_log "SYS Online users now: #{ousers.join(", ")}"
- end
- end
- def main
- # #run: Note that this will block current thread.
- $gs = GameServers.new
- EventMachine.run do
- # initial scan
- EM.defer do
- $gs.scanserverlist($qw_list, "qw") # initial scan
- end
- # periodic scan, 20 hours
- EventMachine.add_periodic_timer( 60 * 60 * 20 ) {
- EM.defer do
- $gs.scanserverlist($qw_list, "qw") # initial scan
- end
- }
- EventMachine.start_server("0.0.0.0", 7337, CentralProtocolHandler)
- end
- end # of main
- main
|