em_server.rb 40 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469
  1. #!/usr/bin/env ruby
  2. require 'eventmachine'
  3. require 'digest/md5'
  4. require 'fiber'
  5. require 'geoip'
  6. require 'socket'
  7. require 'timeout'
  8. # .. allowed commands .. ROLES = CAPABILITIES
  9. # normal users have ROLE broadcast. Roles are defined on a per-user basis .. in a config.
  10. $version = "0.6em_specservers_dupe_election"
  11. $debug = 0
  12. $role_commands = Hash[
  13. #noinspection RubyStringKeysInHashInspection
  14. 'everyone' => %w(PING WHO C PART),
  15. 'broadcast_admin' => %w(BC_ID BC BC_ENDCOUNT),
  16. 'broadcast' => %w(REQ_BC BC_RE),
  17. 'specbot_admin' => %w(REQ_ASSIGN REQ_UNASSIGN REQ_PING REQ_ASSIGNMENTS REQ_MAXSERVERS DUPECHECK ELECTION),
  18. 'specbot' => %w(ASSIGN_RE UNASSIGN_RE PING_RE ASSIGNMENTS_RE REQ_DNS MAXSERVERS_RE),
  19. ]
  20. $default_role = "everyone"
  21. # which role is talking to which role?
  22. # effectively it says: this (local) command is sent to that (remote) topic .. that certain topic is read by that user with that role.
  23. $role_dialogs = Hash[
  24. #noinspection RubyStringKeysInHashInspection
  25. 'everyone' => %w(everyone),
  26. 'broadcast_admin' => %w(broadcast),
  27. 'broadcast' => %w(broadcast_admin),
  28. 'specbot_admin' => %w(specbot),
  29. 'specbot' => %w(specbot_admin),
  30. ]
  31. $user_roles = Hash[
  32. #noinspection RubyStringKeysInHashInspection
  33. 'paul_tester' => %w(everyone broadcast specbot_admin),
  34. 'paul_dev_eggdrop' => %w(everyone broadcast),
  35. 'paul_eggdrop' => %w(everyone broadcast),
  36. 'paul_dev_specbot' => %w(everyone broadcast specbot),
  37. 'paul_specbot' => %w(everyone broadcast specbot),
  38. 'qw.nu' => %w(everyone broadcast),
  39. 'qw.nu_poster' => %w(everyone broadcast),
  40. 'mihawk_devA_specbot' => %w(everyone broadcast specbot),
  41. 'mihawk_devB_specbot' => %w(everyone broadcast specbot),
  42. 'mihawk_specbot' => %w(everyone broadcast specbot),
  43. 'armitage_specbot' => %w(everyone broadcast specbot),
  44. 'blaze_specbot' => %w(everyone broadcast specbot),
  45. ]
  46. $qw_list = Array.new
  47. $qw_list = [
  48. "89.149.194.72:27700",
  49. "84.200.47.113:30000",
  50. "89.149.194.72:27500",
  51. "84.200.47.113:28502",
  52. "89.149.194.72:30000",
  53. "89.149.194.72:27600",
  54. "93.186.192.16:28502",
  55. "84.200.47.113:28501",
  56. "93.186.192.16:28501",
  57. "188.40.130.10:27502",
  58. "93.186.192.16:30000",
  59. "188.40.130.10:27599",
  60. "188.40.130.10:27503",
  61. "194.109.69.75:28000",
  62. "194.109.69.75:27500",
  63. "194.109.69.75:27501",
  64. "194.109.69.76:28504",
  65. "188.165.243.56:30000",
  66. "188.40.130.10:27501",
  67. "194.109.69.76:28502",
  68. "194.109.69.76:28501",
  69. "194.109.69.76:28503",
  70. "62.24.64.11:27501",
  71. "62.24.64.11:44444",
  72. "188.40.103.81:27600",
  73. "62.24.64.11:30000",
  74. "194.109.69.75:27502",
  75. "91.121.69.201:30000",
  76. "37.59.63.97:28504",
  77. "188.40.130.10:27500",
  78. "188.165.243.56:28009",
  79. "37.59.63.97:28501",
  80. "62.24.64.11:27500",
  81. "37.59.63.97:28503",
  82. "194.109.69.76:30000",
  83. "188.165.243.56:28008",
  84. "188.165.243.56:28006",
  85. "188.165.243.56:28001",
  86. "188.165.243.56:28002",
  87. "93.186.192.16:27500",
  88. "91.121.69.201:27600",
  89. "37.59.63.97:28502",
  90. "91.121.223.163:28001",
  91. "188.165.243.56:28003",
  92. "109.74.195.224:30000",
  93. "178.79.183.178:27500",
  94. "77.74.194.189:27501",
  95. "91.121.69.201:27502",
  96. "188.165.243.56:28007",
  97. "109.74.195.224:27500",
  98. "213.5.176.135:27502",
  99. "77.74.194.189:27504",
  100. "178.79.172.251:27600",
  101. "77.74.194.189:27502",
  102. "77.74.194.189:27503",
  103. "213.5.176.135:27500",
  104. "109.74.195.224:27501",
  105. "89.104.194.146:27504",
  106. "89.104.194.146:27503",
  107. "89.104.194.146:27508",
  108. "213.5.176.136:27510",
  109. "213.5.176.135:27501",
  110. "213.5.176.135:27503",
  111. "77.74.194.189:30000",
  112. "89.149.194.72:27800",
  113. "89.104.194.146:27502",
  114. "89.104.194.146:27666",
  115. "89.104.194.146:27507",
  116. "89.104.194.146:27509",
  117. "89.104.194.146:30000",
  118. "188.165.243.56:28004",
  119. "89.104.194.146:27500",
  120. "89.104.194.146:27501",
  121. "194.109.69.76:27500",
  122. "89.104.194.146:27506",
  123. "94.236.92.49:27501",
  124. "91.121.69.201:27501",
  125. "213.239.214.134:27500",
  126. "89.104.194.146:27510",
  127. "95.131.48.86:27502",
  128. "94.236.92.49:27500",
  129. "94.236.92.49:30000",
  130. "95.131.48.86:27504",
  131. "78.137.161.109:27501",
  132. "188.165.243.56:28005",
  133. "178.217.185.104:27500",
  134. "178.217.185.104:27600",
  135. "178.217.185.104:30000",
  136. "87.102.202.23:27502",
  137. "78.137.161.109:27500",
  138. "89.104.194.146:27505",
  139. "87.102.202.23:27505",
  140. "178.217.185.104:27501",
  141. "91.121.69.201:27500",
  142. "82.141.152.3:27501",
  143. "82.141.152.3:27500",
  144. "83.179.23.16:28002",
  145. "109.74.7.60:27500",
  146. "212.62.234.153:27502",
  147. "83.179.23.16:28003",
  148. "195.54.182.34:27500",
  149. "83.179.23.16:28005",
  150. "212.62.234.153:27503",
  151. "95.143.243.24:27600",
  152. "83.179.23.16:28001",
  153. "212.62.234.153:27504",
  154. "78.137.161.109:27502",
  155. "83.179.23.16:28004",
  156. "212.62.234.153:27501",
  157. "95.143.243.24:27500",
  158. "109.228.137.161:28501",
  159. "95.143.243.24:27900",
  160. "83.226.149.218:27500",
  161. "83.226.149.218:28001",
  162. "83.226.149.218:28002",
  163. "83.226.149.218:28003",
  164. "193.1.40.166:27975",
  165. "87.237.112.11:30000",
  166. "217.30.184.104:27500",
  167. "78.108.53.19:27500",
  168. "78.108.53.19:27501",
  169. "195.54.142.7:28001",
  170. "193.1.40.166:27500",
  171. "87.237.112.11:27501",
  172. "195.54.142.7:30000",
  173. "195.54.142.7:28007",
  174. "217.119.36.79:30000",
  175. "95.131.48.86:27501",
  176. "195.54.142.7:28002",
  177. "195.54.142.7:28008",
  178. "80.101.105.103:27500",
  179. "87.237.112.11:27502",
  180. "217.119.36.79:27500",
  181. "81.170.128.75:28501",
  182. "217.119.36.79:28001",
  183. "193.1.40.167:27500",
  184. "217.119.36.79:28003",
  185. "217.119.36.79:28002",
  186. "81.170.128.75:30000",
  187. "81.170.128.75:28504",
  188. "195.54.142.7:28005",
  189. "195.54.142.7:28010",
  190. "81.170.128.75:28503",
  191. "93.81.254.63:27502",
  192. "212.42.38.88:27504",
  193. "81.170.128.75:28502",
  194. "93.81.254.63:27500",
  195. "81.170.128.75:28000",
  196. "212.42.38.88:27500",
  197. "82.203.213.117:28002",
  198. "212.42.38.88:30000",
  199. "93.81.254.63:30000",
  200. "82.203.213.117:28001",
  201. "212.42.38.88:27501",
  202. "212.42.38.88:27503",
  203. "93.81.254.63:27503",
  204. "93.81.254.63:27501",
  205. "82.203.213.117:30000",
  206. "95.131.48.86:27503",
  207. "83.252.244.76:27500",
  208. "212.42.38.88:27502",
  209. "195.54.142.7:28003",
  210. "95.31.4.132:30000",
  211. "83.252.244.76:27501",
  212. "93.81.254.63:30001",
  213. "195.54.142.7:28006",
  214. "82.203.213.117:28003",
  215. "95.143.243.24:27700",
  216. "84.234.185.215:27503",
  217. "84.234.185.215:27500",
  218. "84.234.185.215:27519",
  219. "84.234.185.215:27508",
  220. "84.234.185.215:27506",
  221. "84.234.185.215:27505",
  222. "195.54.142.7:28004",
  223. "84.234.185.215:27501",
  224. "195.54.142.7:28009",
  225. "212.109.128.148:27501",
  226. "84.234.185.215:27502",
  227. "31.209.7.104:28501",
  228. "194.79.85.66:27501",
  229. "194.79.85.66:30000",
  230. "95.84.164.245:27501",
  231. "194.79.85.66:27502",
  232. "83.222.112.157:30000",
  233. "212.109.128.148:27500",
  234. "94.100.6.66:27500",
  235. "129.241.205.153:28000",
  236. "84.234.185.215:27507",
  237. "129.241.205.153:27500",
  238. "95.84.164.245:27500",
  239. "69.31.82.226:27501",
  240. "69.31.82.226:30000",
  241. "130.240.207.177:30000",
  242. "69.31.82.226:28100",
  243. "69.31.82.226:27500",
  244. "69.31.82.226:28101",
  245. "69.31.82.226:28010",
  246. "69.31.82.226:30001",
  247. "69.31.82.226:28000",
  248. "69.31.82.226:28002",
  249. "93.186.192.16:28000",
  250. "195.222.130.83:27500",
  251. "84.200.47.113:28000",
  252. "130.85.56.131:27500",
  253. "108.174.51.73:28003",
  254. "96.8.113.36:27501",
  255. "96.8.113.36:27500",
  256. "68.100.130.114:27501",
  257. "65.31.69.75:27500",
  258. "108.174.51.73:28006",
  259. "65.31.69.75:27508",
  260. "108.174.51.73:30000",
  261. "67.81.59.41:27500",
  262. "108.174.51.73:28004",
  263. "217.18.138.23:27505",
  264. "108.174.51.73:28001",
  265. "68.100.130.114:27500",
  266. "174.49.198.60:27502",
  267. "174.49.198.60:27503",
  268. "209.239.113.236:27500",
  269. "174.49.198.60:27515",
  270. "217.119.36.79:28000",
  271. "108.174.51.73:28005",
  272. "74.91.115.244:28001",
  273. "174.49.198.60:27500",
  274. "74.91.115.244:28000",
  275. "199.101.96.48:27501",
  276. "96.8.113.36:30000",
  277. "174.101.185.59:27500",
  278. "67.228.69.114:27502",
  279. "199.101.96.48:27500",
  280. "108.174.51.73:28002",
  281. "199.192.229.74:28001",
  282. "74.86.171.201:27502",
  283. "67.228.69.114:27501",
  284. "74.86.171.201:27500",
  285. "67.228.69.114:26666",
  286. "199.192.228.71:27501",
  287. "199.192.229.74:28003",
  288. "74.86.171.201:27501",
  289. "199.192.229.74:30000",
  290. "199.192.229.74:28002",
  291. "74.91.115.244:28002",
  292. "199.192.228.71:27500",
  293. "199.101.96.48:30000",
  294. "199.101.96.48:28000",
  295. "199.192.229.74:28004",
  296. "199.192.228.71:30000",
  297. "65.31.238.37:27500",
  298. "31.209.7.104:28000",
  299. "208.131.136.169:27500",
  300. "66.212.17.78:27500",
  301. "200.177.229.11:27510",
  302. "200.177.229.11:27522",
  303. "200.177.229.11:27521",
  304. "200.177.229.11:27500",
  305. "190.96.80.67:27500",
  306. "200.177.229.11:27511",
  307. "200.177.229.11:27520",
  308. "190.96.80.67:27000",
  309. "202.37.129.186:27500",
  310. "202.37.129.186:27505",
  311. "202.37.129.186:27501",
  312. "219.88.241.81:27500",
  313. "202.172.99.2:28001",
  314. "202.172.99.2:28002",
  315. "202.172.99.2:28003",
  316. "202.172.99.2:27500",
  317. "210.50.4.11:27501",
  318. "202.172.99.2:27501",
  319. "210.50.4.11:27508",
  320. "210.50.4.11:27511",
  321. "210.50.4.11:27509",
  322. "210.50.4.11:27510",
  323. "122.99.118.2:28001",
  324. "210.50.4.11:27500",
  325. "210.50.4.11:27503",
  326. "210.50.4.11:27506",
  327. "210.50.4.11:27505",
  328. "210.50.4.11:27504",
  329. ]
  330. # for local dev usage ;)
  331. $qw_list = [
  332. "89.104.194.146:27501",
  333. "210.50.4.11:27504",
  334. "122.99.118.2:28001",
  335. ]
  336. class GameServers
  337. attr_accessor :gameservers # now, @gameservers is accessible via GameServers.gameservers
  338. def initialize
  339. @gameservers = Hash.new
  340. @gameservers.default = {
  341. :reverse_dns => "",
  342. :hostname_dns => "",
  343. :cool_dns => "",
  344. :type => "",
  345. :serverinfos => "",
  346. :timestamp => 0,
  347. }
  348. @gameservers["blah:blah"]
  349. wat = Hash.new(@gameservers["blah:blah"])
  350. wat
  351. wat.store(:reverse_dns, "6")
  352. @gameservers.merge(wat)
  353. p @gameservers
  354. p @gameservers.default
  355. wat = Hash.new(@gameservers["blah:blah"])
  356. wat
  357. wat.store(:hostname_dns, "12")
  358. @gameservers.merge(wat)
  359. p @gameservers
  360. p @gameservers.default
  361. end
  362. def scanserver(iphostport, type="qw", force=false)
  363. put_log "scanserver drin"
  364. if iphostport =~ /^(\d+\.\d+\.\d+\.\d+):(\d{1,5})/
  365. iphost = $1
  366. ipport = $2
  367. if type == "qw"
  368. #p current
  369. # check if it already exists
  370. #if @gameservers["#{iphost}:#{ipport}"][:timestamp] > 0
  371. # if old general data, then freshly get general data...
  372. # if @gameservers["#{iphost}:#{ipport}"][:timestamp] + 60 * 60 * 20 < Time.now.utc.to_i || force == true
  373. # end # of old
  374. #else
  375. current = Hash.new
  376. serverinfos = qwstatus(iphost, ipport)
  377. current.store(:serverinfos, serverinfos)
  378. current.store(:reverse_dns, find_reverse_dname(iphost))
  379. current.store(:hostname_dns, qw_find_dname_by_serverinfos(serverinfos))
  380. current.store(:type, "qw")
  381. # set new timestamp
  382. current.store(:timestamp, Time.now.utc.to_i)
  383. @gameservers.store("#{iphost}:#{ipport}", current) # save it all.
  384. current.store(:cool_dns, find_cooldns(iphost, ipport))
  385. @gameservers.store("#{iphost}:#{ipport}", current) # save it all.
  386. #put_log "the saved one: #{@gameservers.fetch("#{iphost}:#{ipport}").fetch(:cool_dns)}"
  387. #puts "ALL"
  388. #p @gameservers
  389. #puts "DEFAULT of the hash"
  390. #p @gameservers.default
  391. #end
  392. end # of type qw
  393. end # of check form of iphostport parameter
  394. end # of scan()
  395. def scanserverlist(gs_array, type="qw")
  396. put_log "scanserverlist drin"
  397. gs_array.each do
  398. |gserver|
  399. scanserver(gserver, type)
  400. end
  401. put_log "End of scanning."
  402. #put_log "foppa: #{@gameservers.fetch("89.104.194.146:27501")} "
  403. end # of scanserverlist()
  404. def get_cool_dns(iphost, ipport)
  405. put_log "get_cool_dns drin"
  406. cool_dns = @gameservers.fetch("#{iphost}:#{ipport}").fetch(:cool_dns)
  407. put_log "cool_dns for #{iphost}:#{ipport} is: #{cool_dns}"
  408. return cool_dns
  409. rescue
  410. scanserver("#{iphost}:#{ipport}", "qw")
  411. cool_dns = @gameservers.fetch("#{iphost}:#{ipport}").fetch(:cool_dns)
  412. put_log "cool_dns for #{iphost}:#{ipport} is: #{cool_dns}"
  413. return cool_dns
  414. end
  415. private # all following methods are private
  416. # returns serverinfo hash
  417. def qwstatus(iphost, ipport)
  418. put_log "qwstatus drin"
  419. udp_payload = [0xFF, 0xFF, 0xFF, 0xFF]
  420. udp_payload.concat(string2bytearray("status 23"))
  421. udp_payload.concat([0x0a]) # linefeed at the end
  422. udp_payload = udp_payload.pack("C*")
  423. #p udp_payload
  424. Timeout::timeout(2) do
  425. begin
  426. u2 = UDPSocket.new
  427. #put_log "#{iphost} #{ipport} #{udp_payload}"
  428. u2.send(udp_payload, 0, iphost, ipport)
  429. #put_log "sent"
  430. the_return = u2.recv(500)
  431. u2.close
  432. #put_log "muh #{the_return}"
  433. if the_return =~ /\W\W\W\Wn\\(.+)$/
  434. line = $1
  435. #put_log "line #{line}"
  436. matches = line.scan(/(.+?)\\(.+?)(\\|$)/)
  437. the_hash = Hash.new
  438. matches.each {
  439. |k, v, _|
  440. the_hash[k] = "#{v}"
  441. }
  442. return the_hash
  443. else
  444. return false
  445. end
  446. rescue Exception => e
  447. puts e.message
  448. end # of begin
  449. end # of Timeout
  450. end
  451. def find_cooldns_full(iphost, ipport)
  452. targetname = iphost
  453. # resolve it to a dns name (reverse lookup)
  454. if targetname == iphost # if it is still default
  455. put_log "Ip not resolved .. we try hostname dns finder"
  456. targetname = qw_find_dname_in_hostnames(iphost, ipport)
  457. end
  458. # resolve it to a dns name (reverse lookup)
  459. if targetname == iphost
  460. put_log "Still no resolve .. we try reverse dns lookup"
  461. targetname = find_reverse_dname(iphost)
  462. end
  463. return targetname
  464. end
  465. def find_cooldns(iphost, ipport)
  466. put_log "find_cooldns drin"
  467. current = @gameservers["#{iphost}:#{ipport}"] # only use this for reading...
  468. my_cooldns = iphost
  469. # we still haven't found a cool dns
  470. if (my_cooldns == iphost) && (not current[:hostname_dns].to_s.empty?)
  471. put_log "Try if #{current[:hostname_dns]} resolves to #{iphost}"
  472. begin
  473. ip_of_hostnamedns = Resolv.getaddress(current[:hostname_dns])
  474. if ip_of_hostnamedns && (ip_of_hostnamedns == iphost)
  475. # ok, we take it.
  476. put_log "Ok, we take #{current[:hostname_dns]} for #{iphost} here.."
  477. my_cooldns = current[:hostname_dns]
  478. else
  479. put_log "Found #{current[:hostname_dns]} but #{ip_of_hostnamedns} is not #{iphost}"
  480. end
  481. rescue Exception => e
  482. my_cooldns = iphost
  483. end
  484. end
  485. # we still haven't found a cool dns
  486. unless current[:reverse_dns].to_s.empty?
  487. if my_cooldns == iphost
  488. rdns = current[:reverse_dns]
  489. # if the resulting dns name...
  490. # .. is too long, use ip-address instead.
  491. # .. has too many dots, use ip-address instead.
  492. # .. has too many numbers, use ip-address instead.
  493. if rdns.length > 21 || rdns.split(".").size > 3 || rdns.scan(/\d/).size > 3
  494. put_log "cutting down host_name: #{rdns}, because:"
  495. put_log "length: #{rdns.length}"
  496. put_log "chunks count: #{rdns.split(".").size}"
  497. put_log "num count: #{rdns.scan(/\d/).size}"
  498. else
  499. my_cooldns = rdns
  500. end # of Resolv.getname
  501. end
  502. end
  503. put_log "COOOOOOOOOOOOLDNS: #{my_cooldns}"
  504. my_cooldns
  505. end
  506. def find_reverse_dname(iphost)
  507. put_log "find_reverse_dname drin"
  508. dname = Resolv.getname(iphost)
  509. ip_of_dname = Resolv.getaddress(dname)
  510. if ip_of_dname == iphost
  511. return dname
  512. end
  513. rescue
  514. iphost
  515. end
  516. def qw_find_dname_by_udp(iphost, ipport)
  517. targetname = iphost # set a default
  518. # get hostname from a qw status packet! perhaps there's a DNS name inside, which we can use!
  519. status = qwstatus(iphost, ipport)
  520. p status
  521. if status["hostname"] =~ /([\w\.-]{3,}\.\w{2,4})/
  522. hostnamedns = $1.downcase
  523. begin
  524. ip_of_hostnamedns = Resolv.getaddress(hostnamedns)
  525. if ip_of_hostnamedns && (ip_of_hostnamedns == iphost)
  526. # ok, we take it.
  527. put_log "Ok, we take #{hostnamedns} for #{iphost} here.."
  528. targetname = hostnamedns
  529. else
  530. put_log "Found #{hostnamedns} but #{ip_of_hostnamedns} is not #{iphost}"
  531. end
  532. rescue Exception => e
  533. targetname = iphost
  534. end
  535. end
  536. targetname
  537. end
  538. def qw_find_dname_by_serverinfos(serverinfos)
  539. hostnamedns = ""
  540. begin
  541. hostname = serverinfos.fetch("hostname")
  542. if hostname =~ /([\w\.-]{3,}\.\w{2,4})/
  543. hostnamedns = $1.downcase
  544. end
  545. return hostnamedns
  546. rescue
  547. return ""
  548. end
  549. end
  550. end # of Class GameServers!
  551. def string2bytearray(text)
  552. return_array = Array.new
  553. text.each_byte{
  554. |b|
  555. return_array.push(b)
  556. }
  557. return_array
  558. end
  559. def put_log(msg)
  560. puts "#{Time.now.utc.strftime("%Y-%m-%d %H:%M:%S")}: #{msg}"
  561. end
  562. module CentralProtocolHandler
  563. @@connected_clients = Array.new
  564. @@broadcasts = Hash.new
  565. put_log "Server started"
  566. # default method that is being run on connection!
  567. def post_init # connection of someone starts here...
  568. @username = nil
  569. @my_servers = Hash.new
  570. @my_servers.default = {
  571. "active" => 0,
  572. "s-p" => "false",
  573. "ping" => 8888,
  574. }
  575. end
  576. ### setters
  577. def set_my_servers(server, key, value)
  578. current = Hash.new
  579. current.store(key, value)
  580. @my_servers[server] = @my_servers[server].merge(current)
  581. end
  582. def specbot_set_sp(username, server, value)
  583. @@connected_clients.each {|c|
  584. if c.username == username
  585. c.set_my_servers(server, "s-p", value)
  586. end
  587. }
  588. end
  589. ### getters
  590. def entered_username?
  591. !@username.nil? && !@username.empty? # then it's true
  592. end
  593. def username
  594. @username
  595. end
  596. def my_active_servers(active = true)
  597. unless @my_servers.nil? || @my_servers.empty?
  598. if active
  599. rethash = Hash.new
  600. @my_servers.each_pair{|k, v|
  601. if v["active"] == 1
  602. rethash[k] = @my_servers[k]
  603. end
  604. }
  605. rethash
  606. else
  607. @my_servers
  608. end
  609. end
  610. end
  611. def specbot_servers(flat = true)
  612. the_servers = Hash.new
  613. @@connected_clients.each {|c|
  614. if flat
  615. unless c.my_active_servers.nil? || c.my_active_servers.empty?
  616. the_servers = the_servers.merge(c.my_active_servers)
  617. end
  618. else
  619. unless c.my_active_servers.nil? || c.my_active_servers.empty?
  620. the_servers[c.username] = c.my_active_servers
  621. end
  622. end
  623. }
  624. the_servers
  625. end
  626. def specbot_ping(server)
  627. ms = my_active_servers(false)
  628. unless ms.nil?
  629. si = ms[server]
  630. p1 = si.fetch("ping").to_s.to_i
  631. return p1
  632. else
  633. return 8888
  634. end
  635. end
  636. def specbot_active?(server)
  637. ms = my_active_servers(false)
  638. unless ms.nil?
  639. si = ms[server]
  640. a1 = si.fetch("active")
  641. else
  642. a1 = 0
  643. end
  644. if a1 == 1
  645. return 1
  646. else
  647. return 0
  648. end
  649. end
  650. def specbot_sp?(server)
  651. ms = my_active_servers(false)
  652. unless ms.nil?
  653. si = ms[server]
  654. a1 = si.fetch("s-p")
  655. else
  656. a1 = "false"
  657. end
  658. if a1 == "true"
  659. return true
  660. else
  661. return false
  662. end
  663. end
  664. def my_maxservers
  665. if @my_maxservers.nil? || @my_maxservers.empty?
  666. nil
  667. else
  668. @my_maxservers
  669. end
  670. end
  671. def my_roles
  672. $user_roles[@username]
  673. end
  674. def my_cmds
  675. my_roles.collect {|v| $role_commands[v]}.flatten
  676. end
  677. # returns online users by default by searching through saved connections
  678. def ousers
  679. users = Array.new
  680. @@connected_clients.each {|c| users.push(c.username)}
  681. users
  682. end # of ousers
  683. # returns online users by searching through saved connections that have the specified role
  684. def ousers_by_role(role)
  685. users = Array.new
  686. @@connected_clients.each {|c|
  687. if c.my_roles.include?(role)
  688. users.push(c.username)
  689. end
  690. }
  691. users
  692. end
  693. # returns connections by searching through saved connections that have the specified role
  694. def connections_by_role(role)
  695. conns = Array.new
  696. @@connected_clients.each {|c|
  697. if c.my_roles.include?(role)
  698. conns.push(c)
  699. end
  700. }
  701. conns
  702. end
  703. ### checkers
  704. def allowed_cmd(inputmessage)
  705. my_cmds.each{|c|
  706. #print "A #{c} B #{inputmessage}\n"
  707. if inputmessage =~ /^#{c}/
  708. return true
  709. end
  710. }
  711. false
  712. end
  713. def online(user)
  714. if ousers.include? user
  715. true
  716. else
  717. false
  718. end
  719. end
  720. ### actions
  721. def specbot_dupecheck()
  722. put_log "specbot_dupecheck drin"
  723. conns = connections_by_role("specbot")
  724. # if this connection has a same key than another connection
  725. # then fight .. which connection should have that server unassigned. REQ_PING
  726. # the one with the better ping will win and the one with the worse ping will get a new free server slot ;)
  727. # we have at least 2 bots... > 1
  728. conns.repeated_combination(2){|c|
  729. c1 = c[0]
  730. c2 = c[1]
  731. unless c1 == c2
  732. unless c1.my_active_servers.nil? || c2.my_active_servers.nil?
  733. dupes = c1.my_active_servers.keys & c2.my_active_servers.keys
  734. if dupes.size > 0
  735. # damn, there's dupes.
  736. put_log "the dupes are: #{dupes.join(", ")} on #{c1.username} and #{c2.username}"
  737. dupes.each{|d|
  738. write_user("REQ_PING #{d}", c1.username)
  739. write_user("REQ_PING #{d}", c2.username)
  740. EventMachine.add_timer 2, proc {
  741. p1 = c1.specbot_ping(d)
  742. p2 = c2.specbot_ping(d)
  743. a1 = c1.specbot_active?(d)
  744. a2 = c2.specbot_active?(d)
  745. if p1 <= p2
  746. unless a2 == 0
  747. write_user("REQ_UNASSIGN #{d}", c2.username)
  748. end
  749. else
  750. unless a1 == 0
  751. write_user("REQ_UNASSIGN #{d}", c1.username)
  752. end
  753. end
  754. }
  755. }
  756. end
  757. end
  758. end
  759. }
  760. end # of specbot_dupecheck
  761. # searches through our hash of saved connections and writes them a messages.
  762. def write_user(input, username = nil)
  763. if username.nil? || username.empty?
  764. username = @username
  765. end
  766. if @@connected_clients.find { |c| c.username == username }
  767. connection = @@connected_clients.find { |c| c.username == username }
  768. put_log("to #{username}: #{input}")
  769. sometime = "#{Time.now.utc.strftime("%Y-%m-%d %H:%M:%S %z")}"
  770. line = "#{sometime}: #{input}\n"
  771. connection.send_data line
  772. end
  773. end # of write_user
  774. # searches through roles and writes those users on their connections
  775. def write_role(role, input, *exempts)
  776. #find users with role
  777. users = Array.new
  778. $user_roles.each {|k, v|
  779. if v.include? role
  780. users.push(k)
  781. end
  782. }
  783. # find users that are online and inside Array "users"
  784. lala = Array.new
  785. users.each {|v|
  786. if ousers.include? v
  787. lala.push(v)
  788. end
  789. }
  790. # now write to them
  791. lala.each {|user|
  792. if not exempts.include? user
  793. write_user(input, user)
  794. end
  795. }
  796. end # of write_role()
  797. # what happens with what input?!
  798. def inputting(input)
  799. put_log("SYS #{@username} typed: #{input}")
  800. #write_user("SYS You typed: #{input}")
  801. if input =~ /^([A-Z_]+)/
  802. cmd = $1
  803. end
  804. # now we have the cmd .. or not ;)
  805. if input =~ /^[A-Z_]+ (.+)/
  806. payload = $1
  807. end
  808. # now we can use payload
  809. if allowed_cmd(cmd)
  810. ### typical system commands follow
  811. if cmd == "PING"
  812. write_user("PONG")
  813. elsif cmd == "C"
  814. if payload =~ /^(.+)$/
  815. write_role($default_role, "C #{@username}: #{$1}")
  816. else
  817. write_user("SYS Format is C <chattext>")
  818. end
  819. elsif cmd == "WHO"
  820. ousers.each {|ouser| write_user("WHO_RE #{ouser} ROLES: #{$user_roles[ouser].join(", ")}")}
  821. elsif cmd == "PART"
  822. write_user("SYS Goodbye '#{@username}'.")
  823. write_role($default_role, "PARTED User '#{@username}' leaves the party.", @username)
  824. return "bye"
  825. ### now for the good stuff, broadcasting role
  826. elsif cmd == "REQ_BC"
  827. # help with format .. but send the raw payload
  828. if payload =~ /^(.+),(.+),(.+),'(.+)','(.+)'$/
  829. # n f s ni txt
  830. error = 0
  831. # $&
  832. # 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
  833. network = $1
  834. freqname = $2
  835. source = $3
  836. nickname = $4
  837. text = $5
  838. if not network =~ /^(QWalt)|(QDEV)/
  839. write_user("SYS Network name #{network} is unknown: QWalt or QDEV allowed.")
  840. error = 1
  841. end
  842. if not freqname =~ /^(-qw-)|(-spam-)|(-dev-)/
  843. write_user("SYS Frequency name is unknown #{freqname}")
  844. error = 1
  845. end
  846. if source =~ /^(#.+)|(qw:\/\/)|(http:\/\/)/
  847. else
  848. write_user("SYS Source string is not in the form ^(#.+)|(qw:\/\/)|(http:\/\/) was: #{source}")
  849. error = 1
  850. end
  851. if not nickname =~ /^.+/
  852. write_user("SYS Nickname string is not in the form ^.+ #{nickname}")
  853. error = 1
  854. end
  855. if not text =~ /^.+/
  856. write_user("SYS Message string is not in the form ^.+ #{text}")
  857. error = 1
  858. end
  859. else # of payload has format
  860. write_user("SYS Command format is REQ_BC <network>,<frequency>,<source/channel>,'<nickname>','<message>'")
  861. error = 1
  862. end # of payload has format
  863. if error == 0
  864. # send REQ_BC to the corresponding role.
  865. bcid = Digest::MD5.hexdigest("%d %s %s %s %s %s" % [Time.now.utc.to_i, network, freqname, source, nickname, text])
  866. # so it only reaches the issuer of REQ_BC
  867. write_user("BC_ID #{bcid} for: #{network},#{freqname},#{source}")
  868. @@broadcasts[bcid] = @username
  869. # qw:// ip resolving
  870. if source =~ /^qw:\/\/(.+):(\d+)(.*)$/
  871. # ip address is 15 in length
  872. iphost = $1
  873. targetname = iphost # set a default
  874. ipport = $2
  875. rest = $3
  876. if iphost =~ /^\d+\.\d+\.\d+\.\d+/
  877. targetname = $gs.get_cool_dns(iphost, ipport)
  878. # find country code
  879. cc = GeoIP.new('GeoIP.dat').country(iphost)[3].to_s.downcase
  880. rest.prepend " #{cc}" unless cc.nil? || cc.empty? || targetname =~ /\.#{cc}$/
  881. end # if ip is x.x.x.x
  882. source = "qw://#{targetname}:#{ipport}#{rest}"
  883. end # of if source qw://x.x.x.x:portzzz
  884. # resolve
  885. finalmessage = "BC %s %s,%s,%s,'%s','%s'" % [bcid, network, freqname, source, nickname, text]
  886. write_role("broadcast", finalmessage, @username) # write to the role with the exempt of myself.
  887. end
  888. #end of REQ_BC here..
  889. elsif cmd == "BC_RE"
  890. if payload =~ /^(.+) (.+)=(\d+),(.+)=(\d+)$/
  891. bcid = $1
  892. user_string = $2
  893. user_count = $3
  894. item_string = $4
  895. item_count = $5
  896. payload = "%s %s=%d,%s=%d" % [bcid, user_string, user_count, item_string, item_count]
  897. # according bcid it is possible to get the originating user.. so send only to his topic!
  898. if @@broadcasts[bcid]
  899. to_user = @@broadcasts[bcid]
  900. write_user("SYS Broadcast reply bcid: #{bcid} underway to #{to_user}.")
  901. write_user("#{cmd} #{payload}", to_user)
  902. else
  903. write_user("SYS Broadcast reply bcid: #{bcid} underway.")
  904. write_role("broadcast", "#{cmd} #{payload}", @username)
  905. end
  906. else # of bc_re format check
  907. put_log "SYS Format is BC_RE <bcid> <userstring>=<usercount>,<itemstring>=<itemcount>"
  908. end
  909. ### the specbot-admin ROLE does ...
  910. elsif cmd == "REQ_ASSIGN"
  911. if payload =~ /^([a-zA-Z_\.]+) (\d+\.\d+\.\d+\.\d+:\d{1,5})[,]?(true|false)?/
  912. specbot = $1
  913. hostport = $2
  914. sp = $3
  915. if sp == "true"
  916. specbot_set_sp(specbot, hostport, sp)
  917. write_user("REQ_ASSIGN #{hostport},#{sp}", specbot)
  918. else
  919. write_user("REQ_ASSIGN #{hostport}", specbot)
  920. end
  921. else # of format check
  922. write_user("SYS Format is REQ_ASSIGN <specbot> <ip:port>[,<s-p;true or false>]")
  923. end
  924. elsif cmd == "REQ_UNASSIGN"
  925. if payload =~ /^([a-zA-Z_\.]+) (\d+\.\d+\.\d+\.\d+:\d{1,5})/
  926. specbot = $1
  927. hostport = $2
  928. write_user("REQ_UNASSIGN #{hostport}", specbot)
  929. else # of format check
  930. write_user("SYS Format is REQ_UNASSIGN <specbot> <ip:port>")
  931. end
  932. elsif cmd == "REQ_PING"
  933. if payload =~ /^([a-zA-Z_\.]+) (\d+\.\d+\.\d+\.\d+:\d{1,5})/
  934. specbot = $1
  935. hostport = $2
  936. write_user("REQ_PING #{hostport}", specbot)
  937. else # of format check
  938. write_user("SYS Format is REQ_PING <specbot> <ip:port>")
  939. end
  940. elsif cmd == "REQ_ASSIGNMENTS"
  941. if payload =~ /^([a-zA-Z_\.]+)/
  942. specbot = $1
  943. write_user("REQ_ASSIGNMENTS give me your assignments", specbot)
  944. else # of format check
  945. write_user("SYS Format is REQ_ASSIGNMENTS <specbot>")
  946. end
  947. elsif cmd == "REQ_MAXSERVERS"
  948. if payload =~ /^([a-zA-Z_\.]+)/
  949. specbot = $1
  950. write_user("REQ_MAXSERVERS how many do you do?", specbot)
  951. else # of format check
  952. write_user("SYS Format is REQ_MAXSERVERS <specbot>")
  953. end
  954. elsif cmd == "DUPECHECK"
  955. write_user("SYS specbot server monitoring dupecheck started")
  956. # start the central function for dupechecking:
  957. specbot_dupecheck()
  958. elsif cmd == "ELECTION"
  959. write_user("SYS specbot server ping election on global server list started")
  960. # start the central function for server election:
  961. all_servers = specbot_servers()
  962. put_log("#{all_servers}")
  963. write_user("SYS active unique server count: #{all_servers.size}")
  964. conns = connections_by_role("specbot")
  965. #für jeden server, jeden ping der einzelnen bots vergleichen..
  966. #falls ping info noch nicht vorhanden (>5000), dann einfordern
  967. all_servers.each_key{|k|
  968. put_log("SYS bots race for #{k} now..")
  969. conns.each{|c|
  970. ping = c.specbot_ping(k)
  971. if ping > 5000
  972. write_user("REQ_PING #{k}", c.username)
  973. end
  974. }
  975. EventMachine.add_timer 5, proc {
  976. lastbest = 5000
  977. winner = ""
  978. conns.each{|c|
  979. ping = c.specbot_ping(k)
  980. put_log("SYS #{ping} of #{c.username} to #{k}")
  981. if ping < lastbest
  982. lastbest = ping
  983. winner = c
  984. put_log("SYS - current best bot for #{k} is #{c.username}")
  985. end
  986. }
  987. put_log("SYS --> best bot for #{k} is #{winner.username}")
  988. conns.each{|c|
  989. a = c.specbot_active?(k)
  990. unless c == winner
  991. unless a == 0
  992. write_user("REQ_UNASSIGN #{k}", c.username)
  993. end
  994. end
  995. if c == winner
  996. unless a == 1
  997. as = all_servers[k]
  998. sp = as.fetch("s-p")
  999. if sp == "true" || sp == "1"
  1000. write_user("REQ_ASSIGN #{k},true", c.username)
  1001. else
  1002. write_user("REQ_ASSIGN #{k}", c.username)
  1003. end
  1004. end
  1005. end
  1006. }
  1007. } # end of timer
  1008. } # end of all active servers loop
  1009. ### the specbot ROLE does ...
  1010. elsif cmd == "ASSIGNMENTS_RE"
  1011. if payload =~ /^(\d+\.\d+\.\d+\.\d+:\d{1,5}),(.*),(.*)/
  1012. hostport = $1
  1013. sp = $2
  1014. ping = $3.chomp
  1015. p hostport
  1016. p sp
  1017. p ping
  1018. current = Hash.new()
  1019. current.store("active", 1)
  1020. current.store("s-p", sp)
  1021. current.store("ping", ping)
  1022. # save the hash current to the hash @my_servers
  1023. @my_servers[hostport] = @my_servers[hostport].merge(current)
  1024. p @my_servers
  1025. # save new hash to a config file or sth. fixme
  1026. end
  1027. #end of ASSIGNMENTS_RE here..
  1028. elsif cmd == "MAXSERVERS_RE"
  1029. if payload =~ /^(\d+)/
  1030. @my_maxservers = $1
  1031. end
  1032. #end of MAXSERVERS_RE here..
  1033. elsif cmd == "PING_RE"
  1034. if payload =~ /^(\d+\.\d+\.\d+\.\d+:\d{1,5}),(.*)/
  1035. hostport = $1
  1036. ping = $2
  1037. current = Hash.new()
  1038. current.store("ping", ping)
  1039. # save the hash current to the hash @my_servers
  1040. @my_servers[hostport] = @my_servers[hostport].merge(current)
  1041. p @my_servers
  1042. # save new hash to a config file or sth. fixme
  1043. end
  1044. #end of PING_RE here..
  1045. elsif cmd == "ASSIGN_RE"
  1046. #assign_re should only be issued when a req_assign was issued to the specbot before
  1047. if payload =~ /^(\d+\.\d+\.\d+\.\d+:\d{1,5}) ([A-Z]+)[\s]?(.*)/
  1048. hostport = $1
  1049. good = $2
  1050. reason = $3
  1051. if good == "OK"
  1052. current = Hash.new()
  1053. current.store("active", 1)
  1054. @my_servers[hostport] = @my_servers[hostport].merge(current) # this way it preserves previously saved ping values
  1055. write_user("REQ_PING #{hostport}")
  1056. put_log "SYS #{username} assigned to #{hostport} and asked ping for it."
  1057. write_role("specbot_admin", "SYS #{username} assigned to #{hostport} and asked ping for it.")
  1058. else
  1059. put_log "SYS #{username} failed to assign #{hostport}, reason: '#{reason}'"
  1060. write_role("specbot_admin", "SYS #{username} failed to assign #{hostport}, reason: '#{reason}'")
  1061. end
  1062. end
  1063. #end of ASSIGN_RE here..
  1064. elsif cmd == "UNASSIGN_RE"
  1065. if payload =~ /^(\d+\.\d+\.\d+\.\d+:\d{1,5}) ([A-Z]+)[\s]?(.*)/
  1066. hostport = $1
  1067. good = $2
  1068. reason = $3
  1069. if good == "OK"
  1070. current = Hash.new()
  1071. current.store("active", 0)
  1072. @my_servers[hostport] = @my_servers[hostport].merge(current) # this way it preserves previously saved ping values
  1073. put_log "SYS #{username} unassigned #{hostport}"
  1074. write_role("specbot_admin", "SYS #{username} unassigned #{hostport}")
  1075. else
  1076. put_log "SYS #{username} failed to unassign #{hostport}, reason: '#{reason}'"
  1077. write_role("specbot_admin", "SYS #{username} failed to unassign #{hostport}, reason: '#{reason}'")
  1078. end
  1079. end
  1080. #end of UNASSIGN_RE here..
  1081. elsif cmd == "REQ_DNS"
  1082. # help with format .. but send the raw payload
  1083. if payload =~ /^(\d+\.\d+\.\d+\.\d+):(\d{1,5})/
  1084. iphost = $1
  1085. ipport = $2
  1086. targetname = $gs.get_cool_dns(iphost, ipport)
  1087. write_user("DNS_RE #{iphost}:#{ipport} #{targetname}") # write back to asking user.
  1088. else # of payload has format
  1089. write_user("SYS Command format is REQ_DNS <serverip>:<serverport>")
  1090. error = 1
  1091. end # of if payload has format
  1092. #end of REQ_DNS here..
  1093. end
  1094. else # of if allowed command
  1095. if input.length > 15
  1096. input = input.slice(0,14) + ".."
  1097. end
  1098. write_user("SYS Command '#{input}' not allowed, your commands are: #{my_cmds.join(", ")}.")
  1099. end # of if allowed command
  1100. end # of inputting!
  1101. # default method that is being run on receiving data!
  1102. def receive_data(data) # connection receives a line on the server end
  1103. data = data.chomp unless data.chomp.nil?
  1104. data.each_line do |line|
  1105. unless line.empty?
  1106. if entered_username? # oh, it's a known user
  1107. # it's alive! kill ping timer, set a new one:
  1108. if @ping_timer
  1109. EventMachine.cancel_timer(@ping_timer)
  1110. end
  1111. @ping_timer = EventMachine.add_periodic_timer 180, proc { write_user("PING alive?") }
  1112. # work on input
  1113. inputter = inputting(line)
  1114. if inputter == "bye"
  1115. close_connection
  1116. end
  1117. else # of username known, then it seems to be the first connect
  1118. # and this line is the user name coming in!
  1119. username = line
  1120. if online(username)
  1121. put_log "SYS User '#{username}' tried to double connect. Say bye bye."
  1122. send_data "SYS Hey '#{username}', only one connection allowed. Bye.\n"
  1123. EventMachine.add_timer 1, proc {
  1124. write_user("PING check forced", username)
  1125. close_connection
  1126. }
  1127. return false
  1128. end
  1129. if $user_roles.any? {|k| k.include? username}
  1130. @username = username
  1131. @@connected_clients.push(self)
  1132. @ping_timer = EventMachine.add_periodic_timer 90, proc { write_user("PING alive?") }
  1133. # starting a pinger
  1134. put_log("SYS '#{@username}' connected. Online now: #{ousers.join(", ")}")
  1135. write_user("HELLO Hi user '#{@username}'! How are you? I'm '#{$version}'")
  1136. write_user("ROLES #{my_roles.join(", ")}")
  1137. write_user("COMMANDS #{my_cmds.join(", ")}")
  1138. write_role($default_role, "JOINED User '#{@username}' just joined the party.", @username)
  1139. # if that guy is a specbot, ask it for his current list
  1140. if my_roles.include?("specbot")
  1141. EventMachine.add_timer 2, proc {
  1142. write_user("REQ_MAXSERVERS how many can you do?")
  1143. write_user("REQ_ASSIGNMENTS gimme all your servers")
  1144. }
  1145. # if more than 1 specbots are connected, then we want to activate the dupe-check.
  1146. if connections_by_role("specbot").size > 1
  1147. # in 6 seconds we start it. by then, we should have the full serverlists of all bots
  1148. EventMachine.add_timer 6, proc {
  1149. put_log("this guy: #{username} triggers the dupecheck now")
  1150. specbot_dupecheck
  1151. }
  1152. end
  1153. end
  1154. else
  1155. put_log "SYS User '#{username}' unknown to me. Saying bye."
  1156. send_data "SYS User '#{username}' unknown to me. Bye.\n"
  1157. # disconnect him
  1158. close_connection
  1159. end
  1160. end # of username known
  1161. end # of unless line.empty?
  1162. end # of data.each_line
  1163. end # of receive data
  1164. # default method that is being run on disconnection!
  1165. def unbind # a connection goes bye bye
  1166. if @username
  1167. @@connected_clients.delete(self)
  1168. if @ping_timer
  1169. EventMachine.cancel_timer(@ping_timer)
  1170. end
  1171. put_log "SYS '#{@username}' disconnected."
  1172. write_role($default_role, "SYS User '#{@username}' disconnected.", @username)
  1173. end
  1174. put_log "SYS Online users now: #{ousers.join(", ")}"
  1175. end
  1176. end
  1177. def main
  1178. # #run: Note that this will block current thread.
  1179. $gs = GameServers.new
  1180. EventMachine.run do
  1181. # initial scan
  1182. EM.defer do
  1183. $gs.scanserverlist($qw_list, "qw") # initial scan
  1184. end
  1185. # periodic scan, 20 hours
  1186. EventMachine.add_periodic_timer( 60 * 60 * 20 ) {
  1187. EM.defer do
  1188. $gs.scanserverlist($qw_list, "qw") # initial scan
  1189. end
  1190. }
  1191. EventMachine.start_server("0.0.0.0", 7337, CentralProtocolHandler)
  1192. end
  1193. end # of main
  1194. main