forked from RocketMap/RocketMap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
runserver.py
executable file
·232 lines (185 loc) · 8.01 KB
/
runserver.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import sys
import shutil
import logging
import time
import re
import requests
import ssl
import json
from distutils.version import StrictVersion
from threading import Thread, Event
from queue import Queue
from flask_cors import CORS
from flask_cache_bust import init_cache_busting
from pogom import config
from pogom.app import Pogom
from pogom.utils import get_args, get_encryption_lib_path
from pogom.search import search_overseer_thread, search_overseer_thread_ss
from pogom.models import init_database, create_tables, drop_tables, Pokemon, db_updater, clean_db_loop
from pogom.webhook import wh_updater
# Currently supported pgoapi
pgoapi_version = "1.1.7"
# Moved here so logger is configured at load time
logging.basicConfig(format='%(asctime)s [%(threadName)16s][%(module)14s][%(levelname)8s] %(message)s')
log = logging.getLogger()
# Make sure pogom/pgoapi is actually removed if it is an empty directory
# This is a leftover directory from the time pgoapi was embedded in PokemonGo-Map
# The empty directory will cause problems with `import pgoapi` so it needs to go
oldpgoapiPath = os.path.join(os.path.dirname(__file__), "pogom/pgoapi")
if os.path.isdir(oldpgoapiPath):
log.info("I found %s, but its no longer used. Going to remove it...", oldpgoapiPath)
shutil.rmtree(oldpgoapiPath)
log.info("Done!")
# Assert pgoapi is installed
try:
import pgoapi
from pgoapi import utilities as util
except ImportError:
log.critical("It seems `pgoapi` is not installed. You must run pip install -r requirements.txt again")
sys.exit(1)
# Assert pgoapi >= pgoapi_version
if not hasattr(pgoapi, "__version__") or StrictVersion(pgoapi.__version__) < StrictVersion(pgoapi_version):
log.critical("It seems `pgoapi` is not up-to-date. You must run pip install -r requirements.txt again")
sys.exit(1)
def main():
args = get_args()
# Check if we have the proper encryption library file and get its path
encryption_lib_path = get_encryption_lib_path(args)
if encryption_lib_path is "":
sys.exit(1)
if args.debug:
log.setLevel(logging.DEBUG)
else:
log.setLevel(logging.INFO)
# Let's not forget to run Grunt / Only needed when running with webserver
if not args.no_server:
if not os.path.exists(os.path.join(os.path.dirname(__file__), 'static/dist')):
log.critical('Missing front-end assets (static/dist) -- please run "npm install && npm run build" before starting the server')
sys.exit()
# These are very noisey, let's shush them up a bit
logging.getLogger('peewee').setLevel(logging.INFO)
logging.getLogger('requests').setLevel(logging.WARNING)
logging.getLogger('pgoapi.pgoapi').setLevel(logging.WARNING)
logging.getLogger('pgoapi.rpc_api').setLevel(logging.INFO)
logging.getLogger('werkzeug').setLevel(logging.ERROR)
config['parse_pokemon'] = not args.no_pokemon
config['parse_pokestops'] = not args.no_pokestops
config['parse_gyms'] = not args.no_gyms
# Turn these back up if debugging
if args.debug:
logging.getLogger('requests').setLevel(logging.DEBUG)
logging.getLogger('pgoapi').setLevel(logging.DEBUG)
logging.getLogger('rpc_api').setLevel(logging.DEBUG)
# use lat/lng directly if matches such a pattern
prog = re.compile("^(\-?\d+\.\d+),?\s?(\-?\d+\.\d+)$")
res = prog.match(args.location)
if res:
log.debug('Using coordinates from CLI directly')
position = (float(res.group(1)), float(res.group(2)), 0)
else:
log.debug('Looking up coordinates in API')
position = util.get_pos_by_name(args.location)
# Use the latitude and longitude to get the local altitude from Google
try:
url = 'https://maps.googleapis.com/maps/api/elevation/json?locations={},{}'.format(
str(position[0]), str(position[1]))
altitude = requests.get(url).json()[u'results'][0][u'elevation']
log.debug('Local altitude is: %sm', altitude)
position = (position[0], position[1], altitude)
except (requests.exceptions.RequestException, IndexError, KeyError):
log.error('Unable to retrieve altitude from Google APIs; setting to 0')
if not any(position):
log.error('Could not get a position by name, aborting')
sys.exit()
log.info('Parsed location is: %.4f/%.4f/%.4f (lat/lng/alt)',
position[0], position[1], position[2])
if args.no_pokemon:
log.info('Parsing of Pokemon disabled')
if args.no_pokestops:
log.info('Parsing of Pokestops disabled')
if args.no_gyms:
log.info('Parsing of Gyms disabled')
config['LOCALE'] = args.locale
config['CHINA'] = args.china
app = Pogom(__name__)
db = init_database(app)
if args.clear_db:
log.info('Clearing database')
if args.db_type == 'mysql':
drop_tables(db)
elif os.path.isfile(args.db):
os.remove(args.db)
create_tables(db)
app.set_current_location(position)
# Control the search status (running or not) across threads
pause_bit = Event()
pause_bit.clear()
# Setup the location tracking queue and push the first location on
user_locations = {}
# DB Updates
db_updates_queue = Queue()
# Thread(s) to process database updates
for i in range(args.db_threads):
log.debug('Starting db-updater worker thread %d', i)
t = Thread(target=db_updater, name='db-updater-{}'.format(i), args=(args, db_updates_queue))
t.daemon = True
t.start()
# db clearner; really only need one ever
t = Thread(target=clean_db_loop, name='db-cleaner', args=(args,))
t.daemon = True
t.start()
# WH Updates
wh_updates_queue = Queue()
# Thread to process webhook updates
for i in range(args.wh_threads):
log.debug('Starting wh-updater worker thread %d', i)
t = Thread(target=wh_updater, name='wh-updater-{}'.format(i), args=(args, wh_updates_queue))
t.daemon = True
t.start()
if not args.only_server:
# Gather the pokemons!
argset = (args, user_locations, pause_bit, encryption_lib_path, db_updates_queue, wh_updates_queue)
# check the sort of scan
if not args.spawnpoint_scanning:
log.debug('Starting a hex search thread')
search_thread = Thread(target=search_overseer_thread, args=argset)
# using -ss
else:
log.debug('Starting a sp search thread')
if args.dump_spawnpoints:
with open(args.spawnpoint_scanning, 'w+') as file:
log.info('Exporting spawns')
spawns = Pokemon.get_spawnpoints_in_hex(position, args.step_limit)
file.write(json.dumps(spawns))
file.close()
log.info('Finished exporting spawns')
# start the scan sceduler
search_thread = Thread(target=search_overseer_thread_ss, args=argset)
search_thread.daemon = True
search_thread.name = 'search-overseer'
search_thread.start()
if args.cors:
CORS(app)
# No more stale JS
init_cache_busting(app)
app.set_search_control(pause_bit)
app.set_location_dict(user_locations)
config['ROOT_PATH'] = app.root_path
config['GMAPS_KEY'] = args.gmaps_key
if args.no_server:
# This loop allows for ctrl-c interupts to work since flask won't be holding the program open
while search_thread.is_alive():
time.sleep(60)
else:
ssl_context = None
if args.ssl_certificate and args.ssl_privatekey \
and os.path.exists(args.ssl_certificate) and os.path.exists(args.ssl_privatekey):
ssl_context = ssl.SSLContext(ssl.PROTOCOL_TLSv1_2)
ssl_context.load_cert_chain(args.ssl_certificate, args.ssl_privatekey)
log.info('Web server in SSL mode.')
app.run(threaded=True, use_reloader=False, debug=args.debug, host=args.host, port=args.port, ssl_context=ssl_context)
if __name__ == '__main__':
main()