本脚本用于游戏服务器端的自动更新,主要流程就是把更新包和脚本的配置文件放在一个中心端center,分支机房client去中心端center下载更新包,并验证MD5,分支机房的游戏服务器根据自身需求通过rsync下载相应的更新包,游戏服务器通过解压、拷贝、验证部分重要文件的MD5来确保更新正确完成,目前此脚本已经用于更新本公司多款游戏,兼容windows、linux系统(根据自身需要更改相关路径),可以用页面去调用,已经写了post页面返回值。

  1. #!/usr/bin/env python  
  2. # -*- coding: utf-8 -*-  
  3. #Used update game path to server  
  4. import os,re,sys,urllib,urllib2,hashlib,time,shutil,platform  
  5.  
  6. def post(status, type, info, err_info=""):  
  7.     post_url = args["post_url"]  
  8.     aid = args["aid"]  
  9.     data = {"aid": aid, "status": status, "type": type, "info": info}  
  10.     if err_info:  
  11.         data = {"aid": aid, "status": status, "type": type, "info": info, "err_info": err_info}  
  12.     print data  
  13.     f = urllib2.urlopen(url=post_url, data=urllib.urlencode(data))  
  14.  
  15. def md5sum(file_name):  
  16.     if os.path.isfile(file_name):  
  17.         f = open(file_name,'rb')  
  18.         py_ver = sys.version[:3]  
  19.         if py_ver == "2.4":  
  20.             import md5 as hashlib  
  21.         else:  
  22.             import hashlib  
  23.             md5 = hashlib.md5(f.read()).hexdigest()  
  24.             f.close()  
  25.             return md5  
  26.     else:  
  27.         return 0 
  28.  
  29. def config(args,files):  
  30.     try:  
  31.         game = args["main_prefix"]  
  32.         url = "http://208.asktao.com/autoupdate/%s/config.ini" % game  
  33.         get = urllib.urlopen(url)  
  34.         aa = get.readlines()  
  35.         w = {}  
  36.         for i in aa:  
  37.             a = i.strip().split()[0]  
  38.             if "[" in a:  
  39.                 x = a.strip("[]")  
  40.                 w[x] = {}  
  41.                 continue 
  42.             w[x][i.strip().split()[1].strip()] = i.strip().split()[0].strip()  
  43.         for key in w:  
  44.             if key == files:  
  45.                 return w[key]  
  46.     except Exception,e:  
  47.         return 0 
  48.  
  49. class down_start():  
  50.  
  51.     def work(self,args):  
  52.         aa = config(args,"path_md5")  
  53.         game = args["main_prefix"]  
  54.         if aa == 0:  
  55.             post(2,"read update config","Not find %s config file" % game)  
  56.             sys.exit()  
  57.         local = '/data/autoupdate/' 
  58.         url = "http://208.asktao.com/autoupdate/%s/" % game  
  59.         for f in aa:  
  60.             md5_r = f.strip().split()[0]  
  61.             pkg_name = f.strip().split()[1]  
  62.             get = urllib.urlopen(os.path.join(url,pkg_name))  
  63.             status = get.getcode()  
  64.             if status == 200:#验证MD5,MD5错误的话重新下载一次,再次错误就提示失败,退出程序  
  65.                 urllib.urlretrieve(os.path.join(url,pkg_name),os.path.join(local,pkg_name),)  
  66.                 md5_l = md5sum(os.path.join(local,pkg_name))  
  67.                 if md5_l == md5_r:  
  68.                     post(1,"down",pkg_name)  
  69.                 else:  
  70.                     urllib.urlretrieve(os.path.join(url,pkg_name),os.path.join(local,pkg_name),)  
  71.                     md5_l = md5sum(os.path.join(local,pkg_name))  
  72.                     if md5_l == md5_r:  
  73.                         post(1,"down",pkg_name)  
  74.                     else:  
  75.                         post(2,"down",pkg_name,"Download %s,MD5 not right" % pkg_name)  
  76.                         sys.exit()  
  77.             else:  
  78.                 post(2,"down",pkg_name,"Not find %s path file" % pkg_name)  
  79.         # 检查rsync服务是否启动  
  80.         while True:  
  81.             pid = os.popen("ps auxww | grep 'rsync --daemon' | grep -v grep").read()  
  82.             if not pid:  
  83.                 getso("/usr/bin/rsync --daemon")  
  84.                 continue 
  85.             break 
  86.         #全部完成,更新中心状态  
  87.         post(1,"down","down_done")  
  88.  
  89. class sync_start():  
  90.  
  91.     def rsync(self,update_pkg,args):  
  92.         node_ip = args["node_ip"]  
  93.         game = args["main_prefix"]  
  94.         os_type = platform.system()  
  95.         if os_type == "Windows":  
  96.             local = "C:\\update\\" 
  97.         elif os_type == "Linux":  
  98.             local = "/home/update/tmp/" 
  99.         if not os.path.isdir(local):  
  100.             os.mkdir(local)  
  101.         for f in os.listdir(local):  
  102.             if os.path.isfile(f):  
  103.                 os.remove(os.path.join(local,f))  
  104.             elif os.path.isdir(f):  
  105.                 shutil.rmtree(os.path.join(local,f))  
  106.         aa = config(args,"path")  
  107.         if aa == 0:  
  108.             post(2,"read update config","Not find %s config file" % game)  
  109.             sys.exit()  
  110.         for f in aa:  
  111.             if update_pkg in f:  
  112.                 md5_r = aa[f]  
  113.                 pkg_name = f  
  114.                 if os_type == "Windows":  
  115.                     sync = "rsync -avz %s::update/*%s* /cygdrive/c/update/" % (node_ip,update_pkg)  
  116.                 elif os_type == "Linux":  
  117.                     sync = "rsync -avz %s::update/*%s* /home/update/tmp/" % (node_ip,update_pkg)  
  118.                 result = os.popen(sync).readlines()  
  119.                 md5_l = md5sum(os.path.join(local,pkg_name))  
  120.                 if md5_l == md5_r:  
  121.                     post(1,"sync",pkg_name)  
  122.                 else:  
  123.                     if os_type == "Windows":  
  124.                         sync = "rsync -avz %s::update/*%s* /cygdrive/c/update/" % (node_ip,update_pkg)  
  125.                     elif os_type == "Linux":  
  126.                         sync = "rsync -avz %s::update/*%s* /home/update/tmp/" % (node_ip,update_pkg)  
  127.                     result = os.popen(sync).readlines()  
  128.                     md5_l = md5sum(os.path.join(local,pkg_name))  
  129.                     if md5_l == md5_r:  
  130.                         post(1,"sync",pkg_name)  
  131.                     else:  
  132.                         post(2,"rsync",pkg_name,"sync Error,%s not find or file's md5 wrong" % pkg_name)  
  133.                         sys.exit()  
  134.  
  135.     def work(self,args):  
  136.         update_pkg = args["update_pkg"].split(',')  
  137.         for i in range(len(update_pkg)):  
  138.             self.rsync(update_pkg[i],args)  
  139.         post(1,"sync","sync_done")  
  140.  
  141. class update_start():  
  142.  
  143.     def copy(self,src, dst):  
  144.         if os.path.isdir(src):  
  145.             base = os.path.basename(src)  
  146.             if os.path.exists(dst):  
  147.                 dst = os.path.join(dst, base)  
  148.             if not os.path.exists(dst):  
  149.                 os.makedirs(dst)  
  150.             names = os.listdir(src)  
  151.             for name in names:  
  152.                 srcname = os.path.join(src, name)  
  153.                 self.copy(srcname, dst)  
  154.         else:  
  155.             shutil.copy2(src, dst)  
  156.  
  157.     def unrar(self,src,dst,args):  
  158.         os_type = platform.system()  
  159.         try:  
  160.             if not os.path.exists(dst) or not os.path.exists(src):  
  161.                 raise Exception, "%s or %s not exist!" % (src, dst)  
  162.             if os_type == "Windows":  
  163.                 os.system(r'C:\Progra~1\WinRAR\rar x -o+ -inul %s %s' % (src, dst))  
  164.             elif os_type == "Linux":  
  165.                 if os.path.splitext(src)[1] == ".tgz":  
  166.                     os.system("tar -zxf %s -C %s" % (src, dst))  
  167.                 elif os.path.splitext(src)[1] == ".zip":  
  168.                     os.system("unzip -oq %s -d %s" % (src, dst))  
  169.             return 0 
  170.         except Exception,e:  
  171.             return e  
  172.  
  173.     def work(self,args):  
  174.         os_type = platform.system()  
  175.         if os_type == "Windows":  
  176.             update = "C:\\update\\" 
  177.         elif os_type == "Linux":  
  178.             update = "/home/update/tmp/" 
  179.         server_dir = {"tmcs":"C:\\Server\\","wd":"/home/asktao/"}  
  180.         server = server_dir[args["main_prefix"]]  
  181.         update_pkg = args["update_pkg"].split(',')  
  182.         game = args["main_prefix"]  
  183.         for i in range(len(update_pkg)):   
  184. #####################解压更新包  
  185.             for tgz in os.listdir(update):  
  186.                 if update_pkg[i] in tgz:  
  187.                     src = os.path.join(update,tgz)  
  188.                     r = self.unrar(src,update,args)  
  189.                     if r == 0:  
  190.                         post(1,"update","%s unzip success" % src)  
  191.                     else:  
  192.                         post(2,"update",src,"unzip fail:%s" % r)  
  193. #####################拷贝更新文件到游戏目录  
  194.             ser_list = os.listdir(server)  
  195.             up_list = os.listdir(update)  
  196.             for dir in up_list:  
  197.                 for line in ser_list:  
  198.                     filepath = os.path.join(update,dir+"\\")  
  199.                     serv = os.path.join(server,line+"\\")  
  200.                     if dir in line:  
  201.                         self.copy(filepath,serv)  
  202.                         post(1,"update","%s files copy success" % line)  
  203. #####################验证重要文件MD5  
  204.         aa = config(args,"files")  
  205.         if aa == 0:  
  206.             post(2,"read update config","Not find %s config file" % game)  
  207.             sys.exit()  
  208.         for f in aa:  
  209.             md5_r = aa[f]  
  210.             pkg_name = f  
  211.             if os.path.exists(pkg_name):  
  212.                 md5_s = md5sum(pkg_name)  
  213.                 if md5_r == md5_s:  
  214.                     post(1,"update","%s md5 Ok,update success" % pkg_name)  
  215.                 else:  
  216.                     post(2,"update","%s md5 Error,update fail" % pkg_name)  
  217.                     sys.exit()  
  218.         shutil.rmtree(update)  
  219.         os.mkdir(update)  
  220.         post(1,"update","All_done")  
  221.  
  222. if __name__ == "__main__":  
  223.     args = {"pack":"auto_update","func1":"down_start","url":"http://208.2222.com/manage/auto_update","post_url":"http://192.168.50.209/reg.php","update_pkg":"up,up","node_ip":"192.168.50.208","main_prefix":"tmcs","aid":"123"}  
  224.     #down = down_start()  
  225.     #down.work(args)  
  226.     sync = sync_start()  
  227.     sync.work(args)  
  228.     update = update_start()  
  229.     update.work(args)  
  230.  
  231.  
  232. '''''config.ini内容  
  233. [files]#需要验证MD5的重要文件绝对路径和MD5  
  234. 15a6605156e29f68fdfd637e73a889d4  C:\Server\Line1\SAFlashPlayer.exe  
  235. 15a6605156e29f68fdfd637e73a889d4  C:\Server\Line2\SAFlashPlayer.exe  
  236. [path]#更新包名字和MD5  
  237. 32fcb8932799aa553db13b5b9b41e5e9  auto.rar  
  238. 32fcb8932799aa553db13b5b9b41e5e9  update.rar  
  239. '''