├── .gitignore
├── .idea
├── ht-candywebcache-demo-server.iml
└── vcs.xml
├── packages_dema
├── .gitignore
├── .idea
│ └── packages_dema.iml
├── __init__.py
├── db.py
├── http_server.py
└── res.db
├── readme.md
├── test_packages
├── login_20160702.zip
├── login_20160703.zip
└── login_20160704.zip
└── upload_tools
├── bsdiff
├── packages
├── login.diff
├── login_20160702.zip
├── login_20160703.zip
├── login_20160704.zip
└── readme.md
└── upload.py
/.gitignore:
--------------------------------------------------------------------------------
1 | CCDemo/CCDemo.xcworkspace/xcshareddata/
2 | CCDemo/Pods/Pods.xcodeproj/xcuserdata/
3 | #########################
4 | # .gitignore file for Xcode4 and Xcode5 Source projects
5 | #
6 | # Apple bugs, waiting for Apple to fix/respond:
7 | #
8 | # 15564624 - what does the xccheckout file in Xcode5 do? Where's the documentation?
9 | #
10 | # Version 2.6
11 | # For latest version, see: http://stackoverflow.com/questions/49478/git-ignore-file-for-xcode-projects
12 | #
13 | # 2015 updates:
14 | # - Fixed typo in "xccheckout" line - thanks to @lyck for pointing it out!
15 | # - Fixed the .idea optional ignore. Thanks to @hashier for pointing this out
16 | # - Finally added "xccheckout" to the ignore. Apple still refuses to answer support requests about this, but in practice it seems you should ignore it.
17 | # - minor tweaks from Jona and Coeur (slightly more precise xc* filtering/names)
18 | # 2014 updates:
19 | # - appended non-standard items DISABLED by default (uncomment if you use those tools)
20 | # - removed the edit that an SO.com moderator made without bothering to ask me
21 | # - researched CocoaPods .lock more carefully, thanks to Gokhan Celiker
22 | # 2013 updates:
23 | # - fixed the broken "save personal Schemes"
24 | # - added line-by-line explanations for EVERYTHING (some were missing)
25 | #
26 | # NB: if you are storing "built" products, this WILL NOT WORK,
27 | # and you should use a different .gitignore (or none at all)
28 | # This file is for SOURCE projects, where there are many extra
29 | # files that we want to exclude
30 | #
31 | #########################
32 |
33 | #####
34 | # OS X temporary files that should never be committed
35 | #
36 | # c.f. http://www.westwind.com/reference/os-x/invisibles.html
37 |
38 | .DS_Store
39 |
40 | # c.f. http://www.westwind.com/reference/os-x/invisibles.html
41 |
42 | .Trashes
43 |
44 | # c.f. http://www.westwind.com/reference/os-x/invisibles.html
45 |
46 | *.swp
47 |
48 | #
49 | # *.lock - this is used and abused by many editors for many different things.
50 | # For the main ones I use (e.g. Eclipse), it should be excluded
51 | # from source-control, but YMMV.
52 | # (lock files are usually local-only file-synchronization on the local FS that should NOT go in git)
53 | # c.f. the "OPTIONAL" section at bottom though, for tool-specific variations!
54 | #
55 | # In particular, if you're using CocoaPods, you'll want to comment-out this line:
56 | *.lock
57 |
58 |
59 | #
60 | # profile - REMOVED temporarily (on double-checking, I can't find it in OS X docs?)
61 | #profile
62 |
63 |
64 | ####
65 | # Xcode temporary files that should never be committed
66 | #
67 | # NB: NIB/XIB files still exist even on Storyboard projects, so we want this...
68 |
69 | *~.nib
70 |
71 |
72 | ####
73 | # Xcode build files -
74 | #
75 | # NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "DerivedData"
76 |
77 | DerivedData/
78 |
79 | # NB: slash on the end, so we only remove the FOLDER, not any files that were badly named "build"
80 |
81 | build/
82 |
83 |
84 | #####
85 | # Xcode private settings (window sizes, bookmarks, breakpoints, custom executables, smart groups)
86 | #
87 | # This is complicated:
88 | #
89 | # SOMETIMES you need to put this file in version control.
90 | # Apple designed it poorly - if you use "custom executables", they are
91 | # saved in this file.
92 | # 99% of projects do NOT use those, so they do NOT want to version control this file.
93 | # ..but if you're in the 1%, comment out the line "*.pbxuser"
94 |
95 | # .pbxuser: http://lists.apple.com/archives/xcode-users/2004/Jan/msg00193.html
96 |
97 | *.pbxuser
98 |
99 | # .mode1v3: http://lists.apple.com/archives/xcode-users/2007/Oct/msg00465.html
100 |
101 | *.mode1v3
102 |
103 | # .mode2v3: http://lists.apple.com/archives/xcode-users/2007/Oct/msg00465.html
104 |
105 | *.mode2v3
106 |
107 | # .perspectivev3: http://stackoverflow.com/questions/5223297/xcode-projects-what-is-a-perspectivev3-file
108 |
109 | *.perspectivev3
110 |
111 | # NB: also, whitelist the default ones, some projects need to use these
112 | !default.pbxuser
113 | !default.mode1v3
114 | !default.mode2v3
115 | !default.perspectivev3
116 |
117 |
118 | ####
119 | # Xcode 4 - semi-personal settings
120 | #
121 | # Apple Shared data that Apple put in the wrong folder
122 | # c.f. http://stackoverflow.com/a/19260712/153422
123 | # FROM ANSWER: Apple says "don't ignore it"
124 | # FROM COMMENTS: Apple is wrong; Apple code is too buggy to trust; there are no known negative side-effects to ignoring Apple's unofficial advice and instead doing the thing that actively fixes bugs in Xcode
125 | # Up to you, but ... current advice: ignore it.
126 | *.xccheckout
127 |
128 | #
129 | #
130 | # OPTION 1: ---------------------------------
131 | # throw away ALL personal settings (including custom schemes!
132 | # - unless they are "shared")
133 | # As per build/ and DerivedData/, this ought to have a trailing slash
134 | #
135 | # NB: this is exclusive with OPTION 2 below
136 | xcuserdata/
137 |
138 | # OPTION 2: ---------------------------------
139 | # get rid of ALL personal settings, but KEEP SOME OF THEM
140 | # - NB: you must manually uncomment the bits you want to keep
141 | #
142 | # NB: this *requires* git v1.8.2 or above; you may need to upgrade to latest OS X,
143 | # or manually install git over the top of the OS X version
144 | # NB: this is exclusive with OPTION 1 above
145 | #
146 | #xcuserdata/**/*
147 |
148 | # (requires option 2 above): Personal Schemes
149 | #
150 | #!xcuserdata/**/xcschemes/*
151 |
152 | ####
153 | # XCode 4 workspaces - more detailed
154 | #
155 | # Workspaces are important! They are a core feature of Xcode - don't exclude them :)
156 | #
157 | # Workspace layout is quite spammy. For reference:
158 | #
159 | # /(root)/
160 | # /(project-name).xcodeproj/
161 | # project.pbxproj
162 | # /project.xcworkspace/
163 | # contents.xcworkspacedata
164 | # /xcuserdata/
165 | # /(your name)/xcuserdatad/
166 | # UserInterfaceState.xcuserstate
167 | # /xcshareddata/
168 | # /xcschemes/
169 | # (shared scheme name).xcscheme
170 | # /xcuserdata/
171 | # /(your name)/xcuserdatad/
172 | # (private scheme).xcscheme
173 | # xcschememanagement.plist
174 | #
175 | #
176 |
177 | ####
178 | # Xcode 4 - Deprecated classes
179 | #
180 | # Allegedly, if you manually "deprecate" your classes, they get moved here.
181 | #
182 | # We're using source-control, so this is a "feature" that we do not want!
183 |
184 | *.moved-aside
185 |
186 | ####
187 | # OPTIONAL: Some well-known tools that people use side-by-side with Xcode / iOS development
188 | #
189 | # NB: I'd rather not include these here, but gitignore's design is weak and doesn't allow
190 | # modular gitignore: you have to put EVERYTHING in one file.
191 | #
192 | # COCOAPODS:
193 | #
194 | # c.f. http://guides.cocoapods.org/using/using-cocoapods.html#what-is-a-podfilelock
195 | # c.f. http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
196 | #
197 | #!Podfile.lock
198 | #
199 | # RUBY:
200 | #
201 | # c.f. http://yehudakatz.com/2010/12/16/clarifying-the-roles-of-the-gemspec-and-gemfile/
202 | #
203 | #!Gemfile.lock
204 | #
205 | # IDEA:
206 | #
207 | # c.f. https://www.jetbrains.com/objc/help/managing-projects-under-version-control.html?search=workspace.xml
208 | #
209 | #.idea/workspace.xml
210 | #
211 | # TEXTMATE:
212 | #
213 | # -- UNVERIFIED: c.f. http://stackoverflow.com/a/50283/153422
214 | #
215 | #tm_build_errors
216 |
217 | ####
218 | # UNKNOWN: recommended by others, but I can't discover what these files are
219 | #
220 |
--------------------------------------------------------------------------------
/.idea/ht-candywebcache-demo-server.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/packages_dema/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 |
--------------------------------------------------------------------------------
/packages_dema/.idea/packages_dema.iml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/packages_dema/__init__.py:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NEYouFan/ht-candywebcache-demo-server/b3a51bf8d2477cc0cd116546bdd15c6d3e9b1f72/packages_dema/__init__.py
--------------------------------------------------------------------------------
/packages_dema/db.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | import sqlite3
4 |
5 |
6 | class SqLiteCtrl(object):
7 | """
8 | 数据库操作的基础接口封装
9 | """
10 | def __init__(self):
11 | self.db = r"./res.db" # 在当前目录下创建隐藏的db文件
12 |
13 | def drop_table(self, drp_tb_sql):
14 | """
15 |
16 | :return:
17 | """
18 | con = sqlite3.connect(self.db)
19 | cur = con.cursor()
20 |
21 | cur.execute(drp_tb_sql)
22 |
23 | con.commit()
24 |
25 | cur.close()
26 | con.close()
27 |
28 | def create_table(self, crt_tb_sql):
29 | """
30 | 对DB中的表versionInfo进行重设处理,仅在重设的时候被调用
31 | :return:
32 | """
33 | con = sqlite3.connect(self.db)
34 | cur = con.cursor()
35 |
36 | cur.execute(crt_tb_sql)
37 |
38 | con.commit()
39 |
40 | cur.close()
41 | con.close()
42 |
43 | def do_insert(self, insert_sql, params_tuples):
44 | """
45 | insert操作
46 | :param insert_sql: insert操作的sql语句
47 | :param params_tuples: [(), (), (), ......] 待插入的参数元组列表
48 | :return:
49 | """
50 | con = sqlite3.connect(self.db)
51 | cur = con.cursor()
52 |
53 | for one in params_tuples:
54 | cur.execute(insert_sql, one)
55 |
56 | con.commit()
57 |
58 | cur.close()
59 | con.close()
60 | return
61 |
62 | def do_select(self, select_sql):
63 | """
64 | 根据执行的sql语句执行select操作
65 | :param select_sql:
66 | :return:
67 | """
68 | con = sqlite3.connect(self.db)
69 | cur = con.cursor()
70 |
71 | cur.execute(select_sql)
72 |
73 | date_set = cur.fetchall()
74 |
75 | cur.close()
76 | con.close()
77 | return date_set
78 |
79 |
80 | class VersionInfoTable(object):
81 | """
82 | 业务表相关的处理
83 | """
84 | table_name = "versionInfo"
85 |
86 | appID = "appID"
87 | appVersion = "appVersion"
88 | resID = "resID"
89 | resVersion = "resVersion"
90 | diffUrl = "diffUrl"
91 | diffMd5 = "diffMd5"
92 | fullUrl = "fullUrl"
93 | fullMd5 = "fullMd5"
94 | domain = "domain"
95 |
96 | fields = ("id", appID, appVersion, resID, resVersion, diffUrl, diffMd5, fullUrl, fullMd5, domain)
97 |
98 | drp_tb_sql = "drop table if exists versionInfo"
99 | crt_tb_sql = """
100 | create table if not exists versionInfo(
101 | id integer primary key autoincrement unique not null,
102 | appID varchar(128),
103 | appVersion varchar(128),
104 | resID varchar(128),
105 | resVersion varchar(128),
106 | diffUrl varchar(128),
107 | diffMd5 varchar(128),
108 | fullUrl varchar(128),
109 | fullMd5 varchar(128),
110 | domain varchar(256)
111 | );
112 | """
113 |
114 | insert_sql = "insert into versionInfo " \
115 | "(appID, appVersion, resID, resVersion, diffUrl, diffMd5, fullUrl, fullMd5, domain) " \
116 | "values (?, ?, ?, ?, ?, ?, ?, ?, ?)" # ?为占位符
117 |
118 | select_all_sql = "select * from versionInfo"
119 |
120 | db_sqlite = SqLiteCtrl()
121 |
122 | ORDER_KEY = "ORDER_KEY"
123 | ORDER_TYPE = "ORDER_TYPE"
124 | LIMIT = "LIMIT"
125 |
126 | def __init__(self):
127 | self.order_key = ""
128 | self.order_type = ""
129 | self.limit = 0
130 |
131 | def drop_table(self):
132 | self.db_sqlite.drop_table(self.drp_tb_sql)
133 | return
134 |
135 | def create_table(self):
136 | """
137 | 创建表信息
138 | :return:
139 | """
140 | self.db_sqlite.create_table(self.crt_tb_sql)
141 | return
142 |
143 | def add_new_versions(self, new_versions):
144 | """
145 | 向表中增加version数据信息
146 | :return:
147 | """
148 | insert_params = []
149 | for one in new_versions:
150 | insert_params.append((one[self.appID], one[self.appVersion], one[self.resID], one[self.resVersion],
151 | one[self.diffUrl], one[self.diffMd5], one[self.fullUrl], one[self.fullMd5],
152 | one[self.domain]))
153 | self.db_sqlite.do_insert(self.insert_sql, insert_params)
154 | return
155 |
156 | def get_latest_version(self, *args, **kw):
157 | """
158 | 查询表中的version信息,查询最新版本的信息
159 | :param args:
160 | :param kw:
161 | :return:
162 | 说明:排序/limit部分其实可以采用对象式编程实现的,但是时间来不及了,先这样吧.
163 | """
164 |
165 | # select部分
166 | select_part = "select "
167 | if len(args) == 0:
168 | select_part += "* "
169 | else:
170 | for one in args:
171 | select_part = select_part + one + ", "
172 |
173 | select_part = select_part[:-2]
174 |
175 | # where部分
176 | where_part = ""
177 | if len(kw):
178 | for (k, v) in kw.items():
179 | if k == self.ORDER_KEY:
180 | self.order_key = v
181 | elif k == self.ORDER_TYPE:
182 | self.order_type = v
183 | elif k == self.LIMIT:
184 | self.limit = v
185 | elif 'tuple' in str(type(v)):
186 | where_part += k + " in " + str(v) + " and "
187 | else:
188 | where_part += k + "='" + v + "' and "
189 |
190 | where_part = "where " + where_part[:-4]
191 |
192 | # 连接起来
193 | select_sql = select_part + " from " + self.table_name + " " + where_part
194 |
195 | if len(self.order_key):
196 | select_sql += " order by " + self.order_key
197 | if len(self.order_type):
198 | select_sql += " " + self.order_type
199 | if self.limit:
200 | select_sql += " limit " + str(self.limit)
201 |
202 | print(select_sql)
203 |
204 | date_set = self.db_sqlite.do_select(select_sql)
205 |
206 | # 将结果取出
207 | result = []
208 | for one in date_set:
209 | if len(args):
210 | result_item = {}
211 | for idx in range(len(args)):
212 | result_item[args[idx]] = one[idx]
213 |
214 | result.append(result_item)
215 | else:
216 | result_item = {}
217 | for idx in range(len(self.fields)):
218 | result_item[self.fields[idx]] = one[idx]
219 |
220 | result.append(result_item)
221 |
222 | return result
223 |
224 | def get_versions(self, *args, **kw):
225 | """
226 | 查询表中的version信息
227 | :param args:
228 | :param kw:
229 | :return:
230 | select_all_sql = "select * from versionInfo"
231 | """
232 | # select部分
233 | select_part = "select "
234 | if len(args) == 0:
235 | select_part += "* "
236 | else:
237 | for one in args:
238 | select_part = select_part + one + ", "
239 |
240 | select_part = select_part[:-2]
241 |
242 | # where部分
243 | where_part = ""
244 | if len(kw):
245 | for (k, v) in kw.items():
246 | if 'tuple' in str(type(v)):
247 | where_part += k + " in " + str(v) + " and "
248 | else:
249 | where_part += k + "='" + v + "' and "
250 |
251 | where_part = "where " + where_part[:-4]
252 |
253 | # 连接起来
254 | select_sql = select_part + " from " + self.table_name + " " + where_part
255 |
256 | date_set = self.db_sqlite.do_select(select_sql)
257 |
258 | # 将结果取出
259 | result = []
260 | for one in date_set:
261 | if len(args):
262 | result_item = {}
263 | for idx in range(len(args)):
264 | result_item[args[idx]] = one[idx]
265 |
266 | result.append(result_item)
267 | else:
268 | result_item = {}
269 | for idx in range(len(self.fields)):
270 | result_item[self.fields[idx]] = one[idx]
271 |
272 | result.append(result_item)
273 |
274 | return result
275 |
276 |
277 | if __name__ == "__main__":
278 | version_table = VersionInfoTable()
279 | version_table.create_table()
280 | # version_table.get_versions(appID="kaola")
281 | # version_table.get_versions(appID=("kaola", "kaola11"))
282 | # version_table.get_versions(VersionInfoTable.appVersion, appID=("kaola", "kaola11"), appVersion="1.0.0")
283 | # version_table.get_versions()
284 | #
285 | # new_versions = []
286 | # version_table.add_new_versions(new_versions)
287 |
288 | result = VersionInfoTable().get_latest_version(appID="kaola", resID="login",
289 | ORDER_KEY="resVersion", ORDER_TYPE="DESC", LIMIT=1)
290 |
291 | result = version_table.get_versions()
292 | print(result)
293 |
294 |
295 |
296 |
297 |
298 |
299 |
300 |
301 |
302 |
303 |
--------------------------------------------------------------------------------
/packages_dema/http_server.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | # 1. 完成http模块;
4 | # 2. 完成DB模块;
5 | # - SQL操作;
6 | # - 检测sqllite存在性,并提示对应的信息(安装sqllite、启动sqllite server等)
7 | # - 检测表的存在,并提示对应信息(创建表等信息)
8 | # 3. 完成逻辑模块;
9 | # 4. 诊断模块
10 | # - 提供DB中version信息查询的处理功能
11 |
12 | # http server实现功能包括:
13 | # 1. 实现check_version的两个方式的post请求处理
14 | # 2. 资源包的上传处理
15 | # 3. 诊断模块的get处理
16 |
17 | import sys
18 | import http.server
19 | import socketserver
20 | import getopt
21 | import json
22 |
23 | from db import VersionInfoTable
24 |
25 |
26 | CODE_OK = 200 # 请求成功响应
27 | CODE_PROTOCOL_INVALID = 401 # 协议版本不支持
28 | CODE_APP_ID_INVALID = 402 # appID不支持
29 | CODE_SERVER_ERROR = 501 # 服务器错误
30 | CODE_OTHER_ERROR = 601 # 其他错误
31 |
32 | STATE_IS_LATEST = 0 # 提示本地资源已经是最新
33 | STATE_NEED_UPDATE = 1 # 提示需要更新
34 | STATE_NOT_THIS_RES = 2 # 请求资源不存在
35 | STATE_AUTO_RES = 3 # 自动补全的资源信息,请求中未携带资源信息
36 |
37 |
38 | class VersionCheck(object):
39 |
40 | resID = "resID"
41 | resVersion = "resVersion"
42 |
43 | """
44 | 必填项,放在功能函数构造的时候
45 | """
46 | def __init__(self, version, appID, appVersion, platform):
47 | self.version = version
48 | self.app_id = appID
49 | self.app_version = appVersion
50 | self.platform = platform
51 |
52 | self.res_infos = []
53 | self.id_diff = False
54 | self.auto_fill = False
55 |
56 | self.res_latest_version = {}
57 |
58 | def set_option(self, resInfos, isDiff, autoFill):
59 | self.res_infos = resInfos
60 | self.id_diff = isDiff
61 | self.auto_fill = autoFill
62 |
63 | def all_res_version(self):
64 | """
65 | 检查appid是否存在
66 | """
67 | result = VersionInfoTable().get_versions("resID", "resVersion", appID=self.app_id)
68 | if len(result) == 0:
69 | return False
70 | else:
71 | for one in result:
72 | try:
73 | if self.res_latest_version[one["resID"]] < one["resVersion"]:
74 | self.res_latest_version[one["resID"]] = one["resVersion"]
75 | except:
76 | self.res_latest_version[one["resID"]] = one["resVersion"] # 第一次,那么就讲version赋值过去作为key的value
77 |
78 | return True
79 |
80 | def deal_noinput_res(self):
81 | """
82 | 没有传入res的,补全全部的latest version的res资源
83 | :return:
84 | """
85 | res_json = {"resInfos": []}
86 |
87 | if self.auto_fill:
88 | for k,v in self.res_latest_version.items():
89 | result = VersionInfoTable().get_versions(appID=self.app_id, resID=k, resVersion=v)
90 |
91 | for one_result in result:
92 | one_item = {}
93 | one_item[VersionInfoTable.resID] = one_result[VersionInfoTable.resID]
94 | one_item[VersionInfoTable.resVersion] = one_result[VersionInfoTable.resVersion]
95 | one_item[VersionInfoTable.fullUrl] = one_result[VersionInfoTable.fullUrl]
96 | one_item[VersionInfoTable.fullMd5] = one_result[VersionInfoTable.fullMd5]
97 |
98 | one_item["state"] = 3
99 | domains = one_result[VersionInfoTable.domain].split(",")
100 | one_item["userData"] = json.dumps({"domains": domains})
101 |
102 | res_json["resInfos"].append(one_item)
103 | else:
104 | pass
105 |
106 | return res_json
107 |
108 | def deal_withinput_res(self):
109 | """
110 | 有传入res的处理方式
111 | :return:
112 | """
113 | code = CODE_OK
114 | code_msg = "OK"
115 | res_json = {"resInfos": []}
116 | no_the_res = False
117 |
118 | # 先查找传入res的
119 | for input_one in self.res_infos:
120 | try:
121 | tmp_resID = input_one[self.resID]
122 | input_one[self.resVersion]
123 |
124 | if tmp_resID in self.res_latest_version:
125 | self.res_latest_version.pop(tmp_resID)
126 | else:
127 | no_the_res = True
128 |
129 | except Exception as e:
130 | continue
131 |
132 | one_item = {}
133 |
134 | result = VersionInfoTable().get_latest_version(appID=self.app_id, resID=input_one[self.resID],
135 | ORDER_KEY="resVersion", ORDER_TYPE="DESC", LIMIT=1)
136 | if len(result) == 0:
137 | one_item["state"] = 2
138 | one_item[VersionInfoTable.resID] = input_one[self.resID]
139 | else:
140 | for result_one in result:
141 | if result_one[VersionInfoTable.resVersion] == input_one[self.resVersion]:
142 | one_item["state"] = 0
143 | one_item[VersionInfoTable.resID] = input_one[self.resID]
144 | break
145 |
146 | elif result_one[VersionInfoTable.resVersion] > input_one[self.resVersion]:
147 | # 否则返回服务端最新的
148 | one_item[VersionInfoTable.resID] = result_one[VersionInfoTable.resID]
149 | one_item[VersionInfoTable.resVersion] = result_one[VersionInfoTable.resVersion]
150 | one_item[VersionInfoTable.fullUrl] = result_one[VersionInfoTable.fullUrl]
151 | one_item[VersionInfoTable.fullMd5] = result_one[VersionInfoTable.fullMd5]
152 | one_item[VersionInfoTable.diffUrl] = result_one[VersionInfoTable.diffUrl]
153 | one_item[VersionInfoTable.diffMd5] = result_one[VersionInfoTable.diffMd5]
154 |
155 | one_item["state"] = 1
156 | domains = result_one[VersionInfoTable.domain].split(",")
157 | one_item["userData"] = json.dumps({"domains": domains})
158 | break
159 |
160 | else:
161 | # 说明传入的版本是更新的,暂时回复不用更新处理即可
162 | one_item["state"] = 0
163 | one_item[VersionInfoTable.resID] = input_one[self.resID]
164 | break
165 |
166 | res_json["resInfos"].append(one_item)
167 |
168 | # 然后执行需要补全的
169 | if self.auto_fill:
170 | for k,v in self.res_latest_version.items():
171 | result = VersionInfoTable().get_versions(appID=self.app_id, resID=k, resVersion=v)
172 |
173 | for one_result in result:
174 | one_item = {}
175 | one_item[VersionInfoTable.resID] = one_result[VersionInfoTable.resID]
176 | one_item[VersionInfoTable.resVersion] = one_result[VersionInfoTable.resVersion]
177 | one_item[VersionInfoTable.fullUrl] = one_result[VersionInfoTable.fullUrl]
178 | one_item[VersionInfoTable.fullMd5] = one_result[VersionInfoTable.fullMd5]
179 | one_item[VersionInfoTable.diffUrl] = result_one[VersionInfoTable.diffUrl]
180 | one_item[VersionInfoTable.diffMd5] = result_one[VersionInfoTable.diffMd5]
181 |
182 | one_item["state"] = 3
183 | domains = one_result[VersionInfoTable.domain].split(",")
184 | one_item["userData"] = json.dumps({"domains": domains})
185 |
186 | res_json["resInfos"].append(one_item)
187 | else:
188 | # if no_the_res:
189 | # code = CODE_OTHER_ERROR
190 | # code_msg = "The Input Res is No In Server"
191 | pass
192 |
193 | return res_json, code, code_msg
194 |
195 |
196 | def do_check(self):
197 | """
198 | 实际的业务处理
199 | """
200 | code = CODE_OK
201 | code_msg = "OK"
202 |
203 | if len(self.res_infos):
204 | res_json, code, code_msg = self.deal_withinput_res()
205 | else:
206 | res_json = self.deal_noinput_res()
207 |
208 | return res_json, code, code_msg
209 |
210 |
211 | """
212 | Http业务处理的模块
213 | """
214 | class PackageHttpHandler(http.server.BaseHTTPRequestHandler):
215 | """
216 | 继承BaseHTTPRequestHandler用于http request的自定义处理相关
217 | """
218 |
219 | """
220 | get类reques的处理
221 | """
222 | def do_GET(self):
223 | try:
224 | if self.path in "/api/version_infos":
225 | self.do_response(CODE_OK, "ok", self.do_get_all_versions_url())
226 |
227 | except Exception as e:
228 | print("do_GET: "+ str(e))
229 | self.do_response(CODE_OTHER_ERROR, str(e))
230 |
231 | return
232 |
233 | """
234 | post类request的处理
235 | """
236 | def do_POST(self):
237 | try:
238 | if self.path in "/api/version_check/webapp":
239 | # 指定check version的url的操作
240 | self.do_checkversion_url()
241 | elif self.path in "/api/upload_version":
242 | # 执行版本信息的提交
243 | self.do_upload_version_url()
244 | elif self.path in "/api/get_latest_version":
245 | self.get_latest_version_url()
246 |
247 | except Exception as e:
248 | print("do_POST" + str(e))
249 | self.do_response(CODE_OTHER_ERROR, str(e))
250 |
251 | return
252 |
253 | """
254 | 获取http Reques的内容
255 | """
256 | def get_content_json(self):
257 | content_length = int(self.headers["Content-Length"])
258 | content_str = self.rfile.read(content_length).decode('utf-8')
259 | content_json = json.loads(content_str)
260 |
261 | return content_json
262 |
263 | """
264 | 返回值的处理
265 | """
266 | def do_response(self, code, err_msg, data_json={}):
267 |
268 | res_json = {"code": code, "errMsg": err_msg, "data": data_json}
269 | res = json.dumps(res_json).encode('utf-8')
270 |
271 | self.protocol_version = 'HTTP/1.1'
272 | self.send_response(200)
273 | self.end_headers()
274 | self.wfile.write(res)
275 |
276 | return
277 |
278 | #############################################################################
279 | def do_get_all_versions_url(self):
280 | """
281 | 获取所有的版本信息
282 | :return:
283 | """
284 | res_json = VersionInfoTable().get_versions()
285 | return res_json
286 |
287 | def do_upload_version_url(self):
288 | """
289 | /api/upload_version
290 | """
291 | content_json = self.get_content_json()
292 | new_versions = []
293 | for one in content_json:
294 | try:
295 | one_version = {}
296 | one_version[VersionInfoTable.appID] = one[VersionInfoTable.appID]
297 | one_version[VersionInfoTable.appVersion] = one[VersionInfoTable.appVersion]
298 | one_version[VersionInfoTable.resID] = one[VersionInfoTable.resID]
299 | one_version[VersionInfoTable.resVersion] = one[VersionInfoTable.resVersion]
300 | one_version[VersionInfoTable.diffUrl] = one[VersionInfoTable.diffUrl]
301 | one_version[VersionInfoTable.diffMd5] = one[VersionInfoTable.diffMd5]
302 | one_version[VersionInfoTable.fullUrl] = one[VersionInfoTable.fullUrl]
303 | one_version[VersionInfoTable.fullMd5] = one[VersionInfoTable.fullMd5]
304 | one_version[VersionInfoTable.domain] = one[VersionInfoTable.domain]
305 |
306 | new_versions.append(one_version)
307 | except Exception as e:
308 | new_versions = []
309 | print("do_upload_version: " + str(e))
310 |
311 | VersionInfoTable().add_new_versions(new_versions)
312 |
313 | res_json = {"insert_cnt": len(new_versions)}
314 |
315 | self.do_response(CODE_OK, "ok", res_json)
316 | return
317 |
318 | def get_latest_version_url(self):
319 | """
320 | /api/get_latest_version
321 | :return:
322 | """
323 | content_json = self.get_content_json()
324 | latest_versions = []
325 |
326 | try:
327 | appID = content_json["appID"]
328 | resID = content_json["resID"]
329 |
330 | result = VersionInfoTable().get_latest_version(appID=appID, resID=resID,
331 | ORDER_KEY="resVersion", ORDER_TYPE="DESC", LIMIT=1)
332 | for one in result:
333 | one_item = {}
334 | one_item[VersionInfoTable.resID] = one[VersionInfoTable.resID]
335 | one_item[VersionInfoTable.resVersion] = one[VersionInfoTable.resVersion]
336 | one_item[VersionInfoTable.fullUrl] = one[VersionInfoTable.fullUrl]
337 | one_item[VersionInfoTable.fullMd5] = one[VersionInfoTable.fullMd5]
338 | one_item[VersionInfoTable.diffUrl] = one[VersionInfoTable.diffUrl]
339 | one_item[VersionInfoTable.diffMd5] = one[VersionInfoTable.diffMd5]
340 | latest_versions.append(one_item)
341 |
342 | except Exception as e:
343 | print("get_latest_version_url: " + str(e))
344 | self.do_response(CODE_OTHER_ERROR, "get latest version error.")
345 | return
346 |
347 | self.do_response(CODE_OK, "ok", latest_versions)
348 | return
349 |
350 | def do_checkversion_url(self):
351 | """
352 | /api/version_check/webapp
353 | """
354 | content_json = self.get_content_json()
355 |
356 | # 必选项
357 | version = content_json["version"]
358 | appID = content_json["appID"]
359 | appVersion = content_json["appVersion"]
360 | platform = content_json["platform"]
361 |
362 | resInfos = []
363 | isDiff = False
364 | autoFill = False
365 | try:
366 | # 可选项
367 | resInfos = content_json["resInfos"]
368 | # resInfos = json.JSONDecoder().decode(tmp)
369 | except Exception as e:
370 | print("resInfos: " + str(e))
371 | try:
372 | isDiff = bool(content_json['isDiff'])
373 | except Exception as e:
374 | print("isDiff: " + str(e))
375 | try:
376 | autoFill = bool(content_json["autoFill"])
377 | except Exception as e:
378 | print("autoFill: " + str(e))
379 |
380 | # 准备执行业务处理
381 | check_version = VersionCheck(version, appID, appVersion, platform)
382 | check_version.set_option(resInfos, isDiff, autoFill)
383 |
384 | if check_version.all_res_version():
385 | res_json, code, code_msg = check_version.do_check()
386 | self.do_response(code, code_msg, res_json)
387 | else:
388 | self.do_response(CODE_APP_ID_INVALID, "The appID is invalid.")
389 | return
390 |
391 |
392 | class Server(object):
393 | """
394 | 服务类
395 | """
396 | def __init__(self):
397 | self.host = "127.0.0.1"
398 | self.port = 8080
399 | self.is_clear = False
400 |
401 | def get_args(self):
402 | """
403 | 服务执行的方式为:script -h host -p port
404 | :return:
405 | """
406 | try:
407 | opt_list, args = getopt.getopt(sys.argv[1: ], "h: p: ")
408 | for opt, value in opt_list:
409 | if opt == '-h':
410 | self.host = value
411 | elif opt == '-p':
412 | self.port == int(value)
413 | elif opt == '-c':
414 | self.is_clear = True
415 | else:
416 | print("Usage:\tscript [-h host] [-p port] [-c]\n"
417 | " \t-c\t\tclear db table")
418 | except getopt.GetoptError as e:
419 | print(str(e))
420 |
421 | def run(self):
422 | """
423 | 启动服务并执行
424 | :return:
425 | """
426 | self.get_args()
427 |
428 | if self.is_clear:
429 | VersionInfoTable().drop_table()
430 |
431 | VersionInfoTable().create_table()
432 |
433 | http_server = socketserver.TCPServer((self.host, self.port), PackageHttpHandler)
434 |
435 | http_server.serve_forever()
436 |
437 | return
438 |
439 |
440 | if __name__ == "__main__":
441 | server = Server()
442 | print('Start demo server on %s port %d' % (server.host, server.port))
443 | server.run()
444 |
--------------------------------------------------------------------------------
/packages_dema/res.db:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NEYouFan/ht-candywebcache-demo-server/b3a51bf8d2477cc0cd116546bdd15c6d3e9b1f72/packages_dema/res.db
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | # WebCache-Server(Demo版)
2 | ## OverView
3 |
4 | WebCache Demo Server是WebCache项目自带的一个简单的本地测试服务器,包含资源“上传”、“下载”、检查更新等主要功能。WebCache Demo Server主要服务于在应用WebCache SDK时,验证SDK应用是否成功,以及检验各项功能是否正常。下图简单描述了适应于些Demo Server的WebCache框架结构图:
5 |
6 | 
7 |
8 | ## 环境说明
9 |
10 | * 安装python3.5
11 |
12 | Mac OS上自带python解析器,但需确保是python3.x,如果不是,需要更新至python3.x版本
13 |
14 | 这里不建议直接更新系统自带的python版本,可能会影响到你后续在使用python执行其他脚本时,出现python2.x与python3.x不兼容的问题。所以,简单点,直接安装python3.5后,不去更改原python的链接,而是新建一个链接指向可执行文件,如:python3,这样通过python3我们可以直接链向pytho3.5的目录,同时python命令仍然指向原系统版本。操作如下:
15 |
16 |
17 | ```
18 | /Library/Frameworks/Python.framework/Versions/3.5
19 | 是它的默认安装路径,如果你的安装路径不是这个,需要相应改成你自己的安装路径
20 |
21 | sudo ln -s /Library/Frameworks/Python.framework/Versions/3.5/bin/pydoc3.5 /usr/bin/pydoc3
22 | sudo ln -s /Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5 /usr/bin/python3
23 | sudo ln -s /Library/Frameworks/Python.framework/Versions/3.5/bin/pythonw3.5 /usr/bin/pythonw3
24 | sudo ln -s /Library/Frameworks/Python.framework/Versions/3.5/bin/python3.5m-config /usr/bin/python-config3
25 | ```
26 |
27 |
28 | * 下载Demo-Webcache-Server包。解压之后目录结构如下:
29 |
30 | 
31 |
32 | * packages_dema目录下是webcache-server相关的python脚本。可以进入此目录,直接通过下面命令启动server:
33 |
34 | ```
35 | python3 http_server.py
36 | ```
37 |
38 | 同时,需要更改测试的App(CCDemo)中的webcache server地址
39 |
40 | ```
41 | config.serverAddress = @"127.0.0.1:8080";
42 | ```
43 |
44 | 首次启动server,会在此目录下创建一个本地的DB文件,此DB是用来存储上传res的版本信息的
45 |
46 | * upload_tools目录下面,包含upload.py,用来模拟本地“上传”操作
47 |
48 | ```
49 | python3 upload.py
50 | ```
51 |
52 | 如果之前没有安装过python的**requests**和**pycrypto**模块的话,需要先安装这两个模块。
53 |
54 | ```
55 | sudo python3 -m pip install requests
56 | sudo python3 -m pip install pycrypto
57 | ```
58 |
59 | 如果在使用pip安装时,有问题,可以参考[同时装了Python3和Python2,怎么用pip](https://www.zhihu.com/question/21653286)
60 |
61 | * test_packages目录下,包含几个测试用的资源包。
62 |
63 | * 文件下载server。通过python提供的SimpleHTTPServer module,直接在本地启动一个httpServer,将文件目录映射到本地的某一目录,这里为了统一和方便,请确保运行SimpleHTTPServer的目录与upload.py保持在同一路径
64 |
65 | ```
66 | cd .../upload_tools
67 | python -m SimpleHTTPServer
68 | ```
69 |
70 | ## upload-tool使用说明
71 |
72 | 这里,“上传”只是模拟的本地上传行为,即资源包会拷到SimpleHttpServer所映射的文件目录下,然后执行一次upload的http请求,将对应res包的版本信息更新到DB里面去。
73 |
74 | * 在upload-tool文件夹下,运行**python -m SimpleHTTPServer**(确保在SimpleHTTPServer的运行路径与upload-tool相同,否则不保证后续操作的正确性)
75 | * 在Demo-Webcache-Server/packages_dema下,运行**python http\_server.py**
76 | * 生成资源zip包
77 | * 修改upload.py脚本,指明需要“上传”的本地资源zip包的路径,resID,resVersion(请自行确保resID,resVersion, zipPath,domain的正确性)。
78 |
79 | ```
80 | config_items = {
81 | "resID": "login", //资源ID,可根据自己的res进行修改
82 | "resVersion": "20160321", //资源版本,每次更新版本上传时要修改
83 | "appID": "kaola", //资源所在的appID,首次配置app资源时修改
84 | "domain": "www.baidu.com,www.163.com", //资源命中的domains,每次改变都需要修改
85 | "zipPath": "/Users/hzhehui/workspace/web-cache/test/login_20160321.zip", //待上传资源包的本地地址
86 | }
87 | ```
88 | * 执行python3 upload.py,完成上传“请求”
89 |
90 | 上传成功的结果描述:
91 |
92 | * upload.py输出打印信息:{"data": {"insert_cnt": 1}, "errMsg": "ok", "code": 200}
93 | * upload_tools/packages目录下出现对应的资源包以及diff包
94 | * DB中的versionInfo表中会增加一条新的记录
95 |
96 | ## Demo-Server测试
97 |
98 | 运行集成web-Cache的App,通过上述upload-tool一节描述的资源上传方式,进行一次资源的上传(红色标注表明在执行上传upload脚本时,需要更改的项)。
99 |
100 | 如:
101 |
102 | ```
103 | config_items = {
104 | "resID": "login",
105 | "resVersion": "20160702",
106 | "appID": "kaola",
107 | "domain": "www.baidu.com,www.163.com",
108 | "zipPath": "/Users/h zhehui/workspace/web-cache/test/login_20160702.zip"
109 | }
110 | ```
111 |
112 |
113 | 1.配好上述资源包login_20160702.zip后,更改resID、resVersion、appID、domain、zipPath,通过upload.py模拟上传。
114 |
115 | 2.打开类似Charles等抓包工具抓包。启动App。这时可以看到api/version_check/webapp的请求,对应的response:
116 |
117 | ```
118 | {
119 | "data": {
120 | "resInfos": [
121 | {
122 | "userData": "{\"domains\": [\"www.baidu.com\", \"www.163.com\"]}",
123 | "fullMd5": "13c118e8c0284c0f968883a554bb9dd0",
124 | "resID": "login",
125 | "state": 3,
126 | "resVersion": "20160702",
127 | "fullUrl": "http://localhost:8000/packages/login_20160702.zip"
128 | }]
129 | },
130 | "code": 200,
131 | "errMsg": "OK"
132 | }
133 |
134 | ```
135 |
136 | 3.可以再进行一次资源更新的测试:
137 |
138 | ```
139 | config_items = {
140 | "resID": "login",
141 | "resVersion": "20160703",
142 | "appID": "kaola",
143 | "domain": "www.baidu.com,www.163.com",
144 | "zipPath": "/Users/hzhehui/workspace/web-cache/test/login_20160703.zip",
145 | "root_url": "http://localhost:8000/packages"
146 | }
147 | ```
148 |
149 | 配好新的资源包login_20160703.zip,更改resID、resVersion、appID、domain、zipPath,执行upload.py,模拟上传。
150 |
151 |
152 | 4.可再次启动App,这时可以看到api/version_check/webapp的请求,对应的response:
153 |
154 | ```
155 | {
156 | "data": {
157 | "resInfos": [
158 | {
159 | "userData": "{\"domains\": [\"www.baidu.com\", \"www.163.com\"]}",
160 | "fullMd5": "9c5a25ced1728d78518e096e9a00bdfb",
161 | "resID": "login",
162 | "diffMd5": "5250bcf52d7e259bc4cdd0a12cc059e9",
163 | "resVersion": "20160703",
164 | "fullUrl": "http://localhost:8000/packages/login_20160703.zip",
165 | "diffUrl": "http://localhost:8000/packages/login.diff",
166 | "state": 1
167 | }
168 | ]
169 | },
170 | "code": 200,
171 | "errMsg": "OK"
172 | }
173 | ```
174 |
175 |
--------------------------------------------------------------------------------
/test_packages/login_20160702.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NEYouFan/ht-candywebcache-demo-server/b3a51bf8d2477cc0cd116546bdd15c6d3e9b1f72/test_packages/login_20160702.zip
--------------------------------------------------------------------------------
/test_packages/login_20160703.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NEYouFan/ht-candywebcache-demo-server/b3a51bf8d2477cc0cd116546bdd15c6d3e9b1f72/test_packages/login_20160703.zip
--------------------------------------------------------------------------------
/test_packages/login_20160704.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NEYouFan/ht-candywebcache-demo-server/b3a51bf8d2477cc0cd116546bdd15c6d3e9b1f72/test_packages/login_20160704.zip
--------------------------------------------------------------------------------
/upload_tools/bsdiff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NEYouFan/ht-candywebcache-demo-server/b3a51bf8d2477cc0cd116546bdd15c6d3e9b1f72/upload_tools/bsdiff
--------------------------------------------------------------------------------
/upload_tools/packages/login.diff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NEYouFan/ht-candywebcache-demo-server/b3a51bf8d2477cc0cd116546bdd15c6d3e9b1f72/upload_tools/packages/login.diff
--------------------------------------------------------------------------------
/upload_tools/packages/login_20160702.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NEYouFan/ht-candywebcache-demo-server/b3a51bf8d2477cc0cd116546bdd15c6d3e9b1f72/upload_tools/packages/login_20160702.zip
--------------------------------------------------------------------------------
/upload_tools/packages/login_20160703.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NEYouFan/ht-candywebcache-demo-server/b3a51bf8d2477cc0cd116546bdd15c6d3e9b1f72/upload_tools/packages/login_20160703.zip
--------------------------------------------------------------------------------
/upload_tools/packages/login_20160704.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NEYouFan/ht-candywebcache-demo-server/b3a51bf8d2477cc0cd116546bdd15c6d3e9b1f72/upload_tools/packages/login_20160704.zip
--------------------------------------------------------------------------------
/upload_tools/packages/readme.md:
--------------------------------------------------------------------------------
1 | SimpleHTTPServer映射的文件目录
--------------------------------------------------------------------------------
/upload_tools/upload.py:
--------------------------------------------------------------------------------
1 | # -*- coding:utf-8 -*-
2 |
3 | import requests
4 | import sys
5 | import json
6 | import os
7 | import hashlib
8 | import base64
9 | import pyDes
10 |
11 | SERVER_IS_LATEST = 0 # 服务端已经是最新的
12 | SERVER_NEED_UPLOAD = 1 # 服务端有这个资源,但是版本较旧,可以更新
13 | SERVER_NOT_THIS_RES = 2 # 服务端没有这个资源
14 | SERVER_OTHER_ERROR = 3 # 服务端有错误,不执行上传
15 |
16 |
17 | # 用于设置相关信息的config项
18 | config_items = {
19 | "resID": "login",
20 | "resVersion": "20160702",
21 | "appID": "kaola",
22 | "domain": "www.baidu.com,www.163.com",
23 | "zipPath": "/Users/hzhehui/workspace/web-cache/NEYouFan/ht-candywebcache-demo-server/test_packages/login_20160702.zip"
24 | }
25 | #################### 配置项
26 |
27 |
28 | base_version_info = {
29 | "appVersion": "1.0.0",
30 | "appID": config_items["appID"],
31 | "resID": config_items["resID"],
32 | "resVersion": config_items["resVersion"],
33 | "domain": config_items["domain"],
34 | "zipPath": config_items["zipPath"],
35 | "fileServerPath": ".",
36 | "root_url": "http://localhost:8000/packages/"
37 | }
38 |
39 | post_data = {
40 | "appID": config_items["appID"],
41 | "resID": config_items["resID"]
42 | }
43 |
44 |
45 | def get_zippath():
46 | """
47 | 执行脚本参数处理
48 | :return:
49 | """
50 | if len(sys.argv) == 2:
51 | base_version_info["zipPath"] = sys.argv[1]
52 | return True
53 | else:
54 | print("Usage:\t\tpython upload.py zip_file_path")
55 | return False
56 |
57 |
58 | def upload_package_file(old_file):
59 | """
60 | 执行上传
61 | :param old_file:
62 | :return:
63 | """
64 | url_path = "http://localhost:8080/api/upload_version"
65 | version_item = {}
66 | if create_version_info(version_item, old_file):
67 | post_json = []
68 | # post_data = json.dumps(post_json.append(version_item))
69 | post_json.append(version_item)
70 |
71 | ret = do_post(url_path, post_json)
72 | print(ret)
73 | else:
74 | print("upload_package_file: create_version_info Failed.")
75 |
76 | return
77 |
78 | def des_encrypt(data_src):
79 | des = pyDes.des("12344321", pyDes.ECB, padmode=pyDes.PAD_PKCS5)
80 | encrypt_data = des.encrypt(data_src)
81 | return encrypt_data
82 |
83 | def cal_md5(diff_file_name):
84 | md5 = hashlib.md5()
85 | diff_file = open(diff_file_name, 'rb')
86 | while True:
87 | data = diff_file.read(8192)
88 | if not data:
89 | break
90 |
91 | md5.update(data)
92 | md5_value = md5.hexdigest()
93 | return md5_value
94 |
95 | def create_md5(diff_file_name):
96 | """
97 | 加密处理的
98 | :param diff_file_name:
99 | :return:
100 | """
101 | md5_value = cal_md5(diff_file_name)
102 |
103 | desedData = des_encrypt(md5_value)
104 | output_value = base64.b64encode(desedData)
105 |
106 | retStr = str(output_value, encoding="utf-8")
107 |
108 | return retStr
109 |
110 |
111 | def create_version_info(version_item, old_file):
112 | """
113 | 生成其他信息
114 | :return:
115 | """
116 | try:
117 | # 文件拷贝
118 | copy_cmd = "cp " + base_version_info["zipPath"] + " " + base_version_info["fileServerPath"] + "/packages/"
119 | full_zip_md5 = create_md5(base_version_info["zipPath"])
120 | if os.system(copy_cmd) != 0:
121 | return False
122 |
123 | # 生成相关信息
124 | tmp, package_name = os.path.split(base_version_info["zipPath"])
125 | diff_name = package_name.split("_")[0]
126 |
127 | if old_file != "":
128 | # 生成diff文件的格式: ./bsdiff packages/login_20160703.zip packages/login_20160803.zip packages/login.diff
129 | p, file_name = os.path.split(old_file)
130 | cmd = "./bsdiff " + "packages/" + file_name + " packages/" + package_name + " packages/" + diff_name + ".diff"
131 | os.system(cmd)
132 | diff_file_name = "packages/" + diff_name + ".diff"
133 | #version_item["diffMd5"] = hashlib.md5(diff_file_name.encode()).hexdigest()
134 | version_item["diffMd5"] = create_md5(diff_file_name)
135 | version_item["diffUrl"] = base_version_info["root_url"] + diff_name + ".diff"
136 | else:
137 | version_item["diffMd5"] = "" # 首包,然后diff为空
138 | version_item["diffUrl"] = ""
139 |
140 | version_item["appVersion"] = base_version_info["appVersion"] # 该值待定
141 | version_item["appID"] = base_version_info["appID"]
142 | version_item["domain"] = base_version_info["domain"]
143 | version_item["resID"] = base_version_info["resID"]
144 | version_item["resVersion"] = base_version_info["resVersion"]
145 |
146 | version_item["fullUrl"] = base_version_info["root_url"] + package_name
147 | version_item["fullMd5"] = full_zip_md5
148 |
149 | except Exception as e:
150 | print("create_version_info: " + str(e))
151 | return False
152 |
153 | return True
154 |
155 |
156 | def try_get_latest_version():
157 | """
158 | 尝试获取执行resID的最新的版本信息,用于和即将上传的做比较
159 | :param old_file:
160 | :return:
161 | """
162 |
163 | url_path = "http://localhost:8080/api/get_latest_version"
164 |
165 | code, old_file = SERVER_OTHER_ERROR, ""
166 |
167 | try:
168 | result = do_post(url_path, post_data)
169 | result_json = json.loads(result)
170 |
171 | if result_json["code"] != 200:
172 | code = SERVER_OTHER_ERROR
173 |
174 | else:
175 | if len(result_json["data"]) == 0:
176 | code = SERVER_NOT_THIS_RES
177 |
178 | else:
179 | server_version = result_json["data"][0]["resVersion"]
180 | if server_version >= base_version_info["resVersion"]:
181 | print("server_version=====> " + result_json["data"][0]["resID"] + ": " + server_version)
182 | code = SERVER_IS_LATEST
183 | else:
184 | code = SERVER_NEED_UPLOAD
185 | old_file = result_json["data"][0]["fullUrl"]
186 |
187 | except Exception as e:
188 | print(e)
189 | code, old_file = SERVER_OTHER_ERROR, ""
190 |
191 | return code, old_file
192 |
193 |
194 | def do_post(url_path, data_json):
195 | """
196 | 执行http的post请求
197 | :param url:
198 | :param post_data:
199 | :return:
200 | """
201 | ret = requests.post(url_path, data=json.dumps(data_json))
202 | return ret.text
203 |
204 |
205 | def do_get(url_path):
206 | """
207 | 执行http的get请求
208 | :param url:
209 | :return:
210 | """
211 | ret = requests.get(url_path)
212 | return ret.text
213 |
214 |
215 | def do_main():
216 | old_file = ""
217 | state, old_file = try_get_latest_version()
218 | if state == SERVER_OTHER_ERROR:
219 | print("SERVER_OTHER_ERROR!!!!!.")
220 | return
221 | elif state == SERVER_IS_LATEST:
222 | print("SERVER_IS_LATEST!!!!!.")
223 | return
224 |
225 | upload_package_file(old_file)
226 |
227 |
228 | if __name__ == '__main__':
229 | # if get_zippath():
230 | # pass
231 | do_main()
232 |
233 |
234 |
235 |
236 |
237 | # "resInfos": [
238 | # {
239 | # "state": 0,
240 | # "resID": "login"
241 | # }
242 | # ]
243 | #
244 | # "resInfos": []
245 | #
246 | # "resInfos": [
247 | # {
248 | # "diffMd5": "45217d0f79ce7bd18b2e7e26466bfce8",
249 | # "fullUrl": "http://10.242.27.37:8000/test/login_20160703.zip",
250 | # "state": 1,
251 | # "diffUrl": "http://10.242.27.37:8000/test/login.diff",
252 | # "userData": {
253 | # "domains": [
254 | # "m.kaola.com"
255 | # ]
256 | # },
257 | # "resVersion": "20160703",
258 | # "resID": "login",
259 | # "fullMd5": "167ba73e342d67ee9549664dc82adaa9"
260 | # }
261 | # ]
262 |
263 |
264 | # [
265 | # {
266 | # "diffMd5": "45217d0f79ce7bd18b2e7e26466bfce8",
267 | # "appID": "kaola",
268 | # "domain": "m.kaola.com",
269 | # "diffUrl": "http://10.242.27.37:8000/test/exit.diff",
270 | # "resVersion": "20160703",
271 | # "fullUrl": "http://10.242.27.37:8000/test/exit_20160703.zip",
272 | # "appVersion": "1.0.0",
273 | # "resID": "exit",
274 | # "fullMd5": "167ba73e342d67ee9549664dc82adaa9"
275 | # }
276 | # ]
277 |
--------------------------------------------------------------------------------