|
1 | | -import datetime |
2 | 1 | import json |
3 | 2 | import pickle |
| 3 | +from datetime import datetime, timedelta |
4 | 4 | from multiprocessing.pool import ThreadPool |
5 | 5 |
|
6 | | - |
7 | 6 | import redis |
8 | 7 | import requests |
9 | 8 |
|
|
13 | 12 | red_string = redis.StrictRedis.from_url( |
14 | 13 | url=config.REDIS_URL, db=4, charset="utf-8", decode_responses=True) |
15 | 14 | red_bin = redis.StrictRedis.from_url(url=config.REDIS_URL, db=3) |
| 15 | +pool = ThreadPool() |
16 | 16 |
|
17 | 17 |
|
18 | 18 | def login(username, password): |
@@ -75,54 +75,50 @@ def bus_query(username, year, month, day): |
75 | 75 |
|
76 | 76 | if not red_bin.exists('bus_cookie_%s' % username): |
77 | 77 | return error_code.CACHE_BUS_COOKIE_ERROR |
78 | | - |
79 | | - redis_name = "bus_timetable_{username}_{year}_{month}_{day}".format( |
80 | | - username=username, |
| 78 | + redis_name = "bus_timetable_{year}_{month}_{day}".format( |
81 | 79 | year=year, |
82 | 80 | month=month, |
83 | 81 | day=day) |
84 | 82 |
|
85 | | - if red_string.exists(redis_name): |
86 | | - return red_string.get(redis_name) |
87 | | - |
88 | 83 | session = requests.session() |
89 | 84 | session.cookies = pickle.loads(red_bin.get('bus_cookie_%s' % username)) |
90 | | - pool = ThreadPool(processes=1) |
91 | | - async_result = pool.apply_async(bus_reservations_record, (username,)) |
92 | | - |
93 | | - result = bus_crawler.query( |
94 | | - session=session, year=year, month=month, day=day) |
95 | | - |
96 | | - if isinstance(result, list): |
| 85 | + user_book_data = pool.apply_async(bus_reservations_record, (username,)) |
97 | 86 |
|
98 | | - if not isinstance(async_result.get(), str): |
| 87 | + if red_string.exists(redis_name): |
| 88 | + main_timetable = json.loads(red_string.get(redis_name)) |
| 89 | + else: |
| 90 | + main_timetable = get_and_update_timetable_cache( |
| 91 | + session, year, month, day) |
| 92 | + |
| 93 | + if isinstance(main_timetable, list): |
| 94 | + user_book_data = user_book_data.get() |
| 95 | + if not isinstance(user_book_data, str): |
99 | 96 | return error_code.BUS_ERROR |
100 | | - # mix cancelKey in timetable |
101 | | - user_reservation = json.loads(async_result.get()) |
102 | | - for bus_data in result: |
| 97 | + # mix cancelKey and add 'isReserve' in timetable |
| 98 | + user_reservation = json.loads(user_book_data) |
| 99 | + for bus_data in main_timetable: |
103 | 100 | bus_data['cancelKey'] = '' |
104 | | - if bus_data['isReserve']: |
105 | | - for reservation_data in user_reservation['data']: |
106 | | - if reservation_data['dateTime'] == bus_data['departureTime']: |
107 | | - bus_data['cancelKey'] = reservation_data['cancelKey'] |
| 101 | + bus_data['isReserve'] = False |
| 102 | + for reservation_data in user_reservation['data']: |
| 103 | + if reservation_data['dateTime'] == bus_data['departureTime'] and \ |
| 104 | + reservation_data['start'] == bus_data['startStation']: |
| 105 | + bus_data['isReserve'] = True |
| 106 | + bus_data['cancelKey'] = reservation_data['cancelKey'] |
108 | 107 |
|
109 | 108 | return_data = { |
110 | | - "date": datetime.datetime.utcnow().isoformat(timespec='seconds')+"Z", |
111 | | - "data": result |
| 109 | + "date": datetime.utcnow().isoformat(timespec='seconds')+"Z", |
| 110 | + "data": main_timetable |
112 | 111 | } |
113 | | - json_dumps_data = json.dumps(return_data, ensure_ascii=False) |
114 | | - red_string.set( |
115 | | - name=redis_name, |
116 | | - value=json_dumps_data, |
117 | | - ex=config.CACHE_BUS_TIMETABLE_EXPIRE_TIME) |
118 | | - return json_dumps_data |
119 | 112 |
|
120 | | - elif result == error_code.BUS_USER_WRONG_CAMPUS_OR_NOT_FOUND_USER: |
| 113 | + return json.dumps(return_data, ensure_ascii=False) |
| 114 | + |
| 115 | + elif main_timetable == error_code.BUS_USER_WRONG_CAMPUS_OR_NOT_FOUND_USER: |
121 | 116 | # clear user cache cookie |
122 | 117 | red_bin.delete('bus_cookie_%s' % username) |
| 118 | + red_bin.delete(redis_name) |
123 | 119 | return error_code.CACHE_BUS_USER_ERROR |
124 | 120 | # return error code |
125 | | - return result |
| 121 | + return error_code.BUS_ERROR |
126 | 122 |
|
127 | 123 |
|
128 | 124 | def bus_reservations_record(username): |
@@ -193,8 +189,24 @@ def bus_reserve_book(username, kid, action): |
193 | 189 | if isinstance(result, dict): |
194 | 190 | if result['success']: |
195 | 191 | # clear all bus cache, because data changed. |
196 | | - for key in red_string.scan_iter('bus_*_{username}*'.format(username=username)): |
| 192 | + for key in red_string.scan_iter('bus_reservations_{username}*'.format(username=username)): |
197 | 193 | red_string.delete(key) |
| 194 | + # remake redis user cache |
| 195 | + pool.apply_async(func=bus_reservations_record, args=(username,)) |
| 196 | + # delete old main timetable |
| 197 | + if result.get("busTime"): |
| 198 | + book_time = datetime.fromtimestamp( |
| 199 | + int(result.get("busTime"))/1000) |
| 200 | + for key in red_string.scan_iter( |
| 201 | + 'bus_timetable_{year}_{month}_{day}'.format( |
| 202 | + year=book_time.year, |
| 203 | + month=book_time.month, |
| 204 | + day=book_time.day)): |
| 205 | + red_string.delete(key) |
| 206 | + # update new main timetable |
| 207 | + pool.apply_async(func=get_and_update_timetable_cache, args=( |
| 208 | + session, book_time.year, book_time.month, book_time.day,)) |
| 209 | + |
198 | 210 | return result |
199 | 211 | else: |
200 | 212 | return result |
@@ -245,3 +257,31 @@ def bus_violation(username): |
245 | 257 |
|
246 | 258 | # return error code |
247 | 259 | return result |
| 260 | + |
| 261 | + |
| 262 | +def get_and_update_timetable_cache(session: requests.session, year: int, month: int, day: int): |
| 263 | + "Just update redis bus timetable" |
| 264 | + redis_name = "bus_timetable_{year}_{month}_{day}".format( |
| 265 | + year=year, |
| 266 | + month=month, |
| 267 | + day=day) |
| 268 | + |
| 269 | + main_timetable = bus_crawler.query( |
| 270 | + session=session, year=year, month=month, day=day) |
| 271 | + |
| 272 | + if isinstance(main_timetable, list): |
| 273 | + red_string.set( |
| 274 | + name=redis_name, |
| 275 | + value=json.dumps(main_timetable, ensure_ascii=False), |
| 276 | + ex=config.CACHE_BUS_TIMETABLE_EXPIRE_TIME) |
| 277 | + if isinstance(main_timetable, list) and len(main_timetable) > 0: |
| 278 | + expire_seconds = ((datetime.strptime( |
| 279 | + main_timetable[0]['departureTime'], "%Y-%m-%dT%H:%M:%SZ") |
| 280 | + + timedelta(days=1))-datetime.now()).total_seconds() |
| 281 | + |
| 282 | + if expire_seconds > 0: |
| 283 | + red_string.set( |
| 284 | + name=redis_name, |
| 285 | + value=json.dumps(main_timetable, ensure_ascii=False), |
| 286 | + ex=round(expire_seconds)) |
| 287 | + return main_timetable |
0 commit comments