def fullmap(self): args = get_args() return render_template('map.html', lat=config['ORIGINAL_LATITUDE'], lng=config['ORIGINAL_LONGITUDE'], gmaps_key=config['GMAPS_KEY'], lang=config['LOCALE'], isfixed = "inline")
def fullmap(self): args = get_args() display = "inline" if args.fixed_location: display = "none" return render_template('map.html', lat=config['ORIGINAL_LATITUDE'], lng=config['ORIGINAL_LONGITUDE'], gmaps_key=config['GMAPS_KEY'], lang=config['LOCALE'], is_fixed=display )
def set_step_range(self): args = get_args() if request.args: stepRange = request.args.get('step', type=int) if request.form: stepRange = request.args.get('step', type=int) if (not stepRange) or (stepRange < 1) or (stepRange > 5): log.warning('Invalid step range: %d' %stepRange) return 'bad parameters', 400 else: config['NEXT_STEP_RANGE'] = stepRange log.info('Changing the step range: %d' % stepRange) return 'ok'
def post_status(self): args = get_args() d = {} if args.status_page_password is None: abort(404) if request.form.get('password', None) == args.status_page_password: d['login'] = '******' d['main_workers'] = MainWorker.get_all() d['workers'] = WorkerStatus.get_all() else: d['login'] = '******' return jsonify(d)
def fullmap(self): args = get_args() fixed_display = "none" if args.fixed_location else "inline" search_display = "inline" if args.search_control else "none" return render_template('map.html', lat=self.current_location[0], lng=self.current_location[1], gmaps_key=config['GMAPS_KEY'], lang=config['LOCALE'], is_fixed=fixed_display, search_control=search_display )
def post_search_control(self): args = get_args() if not args.search_control: return 'Search control is disabled', 403 action = request.args.get('action', 'none') if action == 'on': self.search_control.clear() log.info('Search thread resumed') elif action == 'off': self.search_control.set() log.info('Search thread paused') else: return jsonify({'message': 'invalid use of api'}) return self.get_search_control()
def size_loc(self): args = get_args() # part of query string if request.args: size = request.args.get('size', type=int) if not (size): log.warning('Invalid size change: %s', size) return 'bad parameters', 400 else: self.location_queue.put((self.current_location[0], self.current_location[1], 0)) self.set_current_location((self.current_location[0], self.current_location[1], 0)) args.step_limit = size log.info('Changing size scan: %s', size) return 'ok'
def next_loc(self): args = get_args() if args.fixed_location: return 'Location changes are turned off', 403 # part of query string if request.args: lat = request.args.get('lat', type=float) lon = request.args.get('lon', type=float) # from post requests if request.form: lat = request.form.get('lat', type=float) lon = request.form.get('lon', type=float) if not (lat and lon): log.warning('Invalid next location: %s,%s', lat, lon) return 'bad parameters', 400 else: self.location_queue.put((lat, lon, 0)) log.info('Changing next location: %s,%s', lat, lon) return 'ok'
def next_loc(self): args = get_args() if args.fixed_location: return 'Location searching is turned off', 403 #part of query string if request.args: lat = request.args.get('lat', type=float) lon = request.args.get('lon', type=float) #from post requests if request.form: lat = request.form.get('lat', type=float) lon = request.form.get('lon', type=float) if not (lat and lon): log.warning('Invalid next location: %s,%s' % (lat, lon)) return 'bad parameters', 400 else: config['NEXT_LOCATION'] = {'lat': lat, 'lon': lon} log.info('Changing next location: %s,%s' % (lat, lon)) return 'ok'
def next_loc(self): args = get_args() if args.fixed_location: return 'Location changes are turned off', 403 # part of query string if request.args: lat = request.args.get('lat', type=float) lon = request.args.get('lon', type=float) # from post requests if request.form: lat = request.form.get('lat', type=float) lon = request.form.get('lon', type=float) if args.account_index == 1: lat = lat+(0.7*4.5*0.0009) lon = lon+(0.7*1*0.001280475) elif args.account_index == 2: lat = lat+(0.7*1.5*0.0009) lon = lon+(0.7*5*0.001280475) elif args.account_index == 3: lat = lat-(0.7*3*0.0009) lon = lon+(0.7*4*0.001280475) elif args.account_index == 4: lat = lat-(0.7*4.5*0.0009) lon = lon-(0.7*1*0.001280475) elif args.account_index == 5: lat = lat-(0.7*1.5*0.0009) lon = lon-(0.7*5*0.001280475) elif args.account_index == 6: lat = lat+(0.7*3*0.0009) lon = lon-(0.7*4*0.001280475) if not (lat and lon): log.warning('Invalid next location: %s,%s', lat, lon) return 'bad parameters', 400 else: self.location_queue.put((lat, lon, 0)) self.set_current_location((lat, lon, 0)) log.info('Changing next location: %s,%s', lat, lon) return 'ok'
def draw_gym_level(level, team): args = get_args() fill_col = "black" if args.black_white_badges else team_colors[team] return draw_badge(badge_lower_right, fill_col, "white", level)
def draw_raid_level(raidlevel): args = get_args() fill_col = ("white" if args.black_white_badges else raid_colors[int( (raidlevel - 1) / 2)]) text_col = "black" if args.black_white_badges else "white" return draw_badge(badge_upper_right, fill_col, text_col, raidlevel)
def get_gym_icon(team, level, raidlevel, pkm, pkm_form, is_in_battle, is_ex_raid_eligible, is_unknown): init_image_dir() level = int(level) args = get_args() if not args.generate_images: return default_gym_image(team, level, raidlevel, pkm) subject_lines = [] badge_lines = [] if pkm and pkm != 'null': # Gym with ongoing raid out_filename = os.path.join( path_generated, "{}_L{}_R{}_P{}_F{}.png".format(team, level, raidlevel, pkm, pkm_form)) iconname = str(pkm) if pkm_form > 0: if pkm_form >= 45 and pkm_form <= 80: if pkm_form % 2 == 0: iconname += '_A' else: iconname += '_' + str(pkm_form) iconname += '.png' subject_lines = draw_subject(os.path.join(path_icons, iconname), 64) badge_lines.extend(draw_badge(80, 15, 15, "white", "black", raidlevel)) if level > 0: badge_lines.extend(draw_badge(80, 80, 15, "black", "white", level)) elif raidlevel: # Gym with upcoming raid (egg) out_filename = os.path.join( path_generated, "{}_L{}_R{}.png".format(team, level, raidlevel)) subject_lines = draw_subject( os.path.join(path_raid, egg_images[raidlevel]), 36) badge_lines.extend(draw_badge(80, 15, 15, "white", "black", raidlevel)) if level > 0: badge_lines.extend(draw_badge(80, 80, 15, "black", "white", level)) elif level > 0: # Occupied gym out_filename = os.path.join(path_generated, '{}_L{}.png'.format(team, level)) badge_lines.extend(draw_badge(80, 80, 15, "black", "white", level)) else: # Neutral gym return os.path.join(path_gym, '{}.png'.format(team)) # Battle Badge if is_in_battle: subject_lines.append( '-gravity center ( {} -resize 84x84 ) -geometry +0+0 -composite'. format(os.path.join(path_images, 'boom.png'))) out_filename = out_filename.replace('.png', '_B.png') # Ex Raid Badge if is_ex_raid_eligible: subject_lines.append( '-gravity center ( {} -resize 50x50 ) -geometry +0+0 -composite'. format(os.path.join(path_images, 'exraid.png'))) out_filename = out_filename.replace('.png', '_Ex.png') if is_unknown: subject_lines.append( '-gravity center ( {} -resize 50x50 ) -geometry +0+0 -composite'. format(os.path.join(path_images, 'unknown.png'))) out_filename = out_filename.replace('.png', '_Unknown.png') if not os.path.isfile(out_filename): gym_image = os.path.join('static', 'images', 'gym', '{}.png'.format(team)) font = os.path.join('static', 'Arial Black.ttf') cmd = 'convert {} {} -gravity center -font "{}" -pointsize 25 {} {}'.format( gym_image, join(subject_lines), font, join(badge_lines), out_filename) if os.name != 'nt': cmd = cmd.replace(" ( ", " \( ").replace(" ) ", " \) ") subprocess.call(cmd, shell=True) return out_filename
def main(): # Patch threading to make exceptions catchable. install_thread_excepthook() # Make sure exceptions get logged. sys.excepthook = handle_exception args = get_args() # Add file logging if enabled. if args.verbose and args.verbose != 'nofile': filelog = logging.FileHandler(args.verbose) filelog.setFormatter( logging.Formatter( '%(asctime)s [%(threadName)16s][%(module)14s][%(levelname)8s] %(message)s' )) logging.getLogger('').addHandler(filelog) if args.very_verbose and args.very_verbose != 'nofile': filelog = logging.FileHandler(args.very_verbose) filelog.setFormatter( logging.Formatter( '%(asctime)s [%(threadName)16s][%(module)14s][%(levelname)8s] %(message)s' )) logging.getLogger('').addHandler(filelog) if args.verbose or args.very_verbose: 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 noisy, 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.verbose or args.very_verbose: logging.getLogger('pgoapi').setLevel(logging.DEBUG) if args.very_verbose: logging.getLogger('peewee').setLevel(logging.DEBUG) logging.getLogger('requests').setLevel(logging.DEBUG) logging.getLogger('pgoapi.pgoapi').setLevel(logging.DEBUG) logging.getLogger('pgoapi.rpc_api').setLevel(logging.DEBUG) logging.getLogger('rpc_api').setLevel(logging.DEBUG) logging.getLogger('werkzeug').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.') if args.encounter: log.info('Encountering pokemon enabled.') 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() if args.on_demand_timeout > 0: pause_bit.set() heartbeat = [now()] # Setup the location tracking queue and push the first location on. new_location_queue = Queue() new_location_queue.put(position) # 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 cleaner; really only need one ever. if not args.disable_clean: 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: # Check all proxies before continue so we know they are good. if args.proxy and not args.proxy_skip_check: # Overwrite old args.proxy with new working list. args.proxy = check_proxies(args) # Gather the Pokemon! # Attempt to dump the spawn points (do this before starting threads of endure the woe). if args.spawnpoint_scanning and args.spawnpoint_scanning != 'nofile' and args.dump_spawnpoints: with open(args.spawnpoint_scanning, 'w+') as file: log.info('Saving spawn points to %s', args.spawnpoint_scanning) spawns = Pokemon.get_spawnpoints_in_hex( position, args.step_limit) file.write(json.dumps(spawns)) log.info('Finished exporting spawn points') argset = (args, new_location_queue, pause_bit, heartbeat, db_updates_queue, wh_updates_queue) log.debug('Starting a %s search thread', args.scheduler) search_thread = Thread(target=search_overseer_thread, name='search-overseer', args=argset) search_thread.daemon = True search_thread.start() if args.cors: CORS(app) # No more stale JS. init_cache_busting(app) app.set_search_control(pause_bit) app.set_heartbeat_control(heartbeat) app.set_location_queue(new_location_queue) 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.') if args.verbose or args.very_verbose: app.run(threaded=True, use_reloader=False, debug=True, host=args.host, port=args.port, ssl_context=ssl_context) else: app.run(threaded=True, use_reloader=False, debug=False, host=args.host, port=args.port, ssl_context=ssl_context)
def main(): # Check if we have the proper encryption library file and get its path encryption_lib_path = get_encryption_lib_path() if encryption_lib_path is "": sys.exit(1) args = get_args() if args.debug: log.setLevel(logging.DEBUG) else: log.setLevel(logging.INFO) # 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) 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 new_location_queue = Queue() new_location_queue.put(position) if not args.only_server: # Gather the pokemons! if not args.mock: # check the sort of scan if not args.spawnpoint_scanning: log.debug('Starting a real search thread') search_thread = Thread(target=search_overseer_thread, args=(args, new_location_queue, pause_bit, encryption_lib_path)) # using -ss else: 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=(args, new_location_queue, pause_bit, encryption_lib_path)) else: log.debug('Starting a fake search thread') insert_mock_data(position) search_thread = Thread(target=fake_search_loop) search_thread.daemon = True search_thread.name = 'search_thread' 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_queue(new_location_queue) 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)
def raw_data(self): self.heartbeat[0] = now() args = get_args() if args.on_demand_timeout > 0: self.search_control.clear() d = {} swLat = request.args.get('swLat') swLng = request.args.get('swLng') neLat = request.args.get('neLat') neLng = request.args.get('neLng') if request.args.get('pokemon', 'true') == 'true': if request.args.get('ids'): ids = [int(x) for x in request.args.get('ids').split(',')] d['pokemons'] = Pokemon.get_active_by_id( ids, swLat, swLng, neLat, neLng) else: d['pokemons'] = Pokemon.get_active(swLat, swLng, neLat, neLng) if request.args.get('pokestops', 'true') == 'true': d['pokestops'] = Pokestop.get_stops(swLat, swLng, neLat, neLng) if request.args.get('gyms', 'true') == 'true': d['gyms'] = Gym.get_gyms(swLat, swLng, neLat, neLng) if request.args.get('scanned', 'true') == 'true': d['scanned'] = ScannedLocation.get_recent(swLat, swLng, neLat, neLng) selected_duration = None # for stats and changed nest points etc, limit pokemon queried for duration in self.get_valid_stat_input( )["duration"]["items"].values(): if duration["selected"] == "SELECTED": selected_duration = duration["value"] break if request.args.get('seen', 'false') == 'true': d['seen'] = Pokemon.get_seen(selected_duration) if request.args.get('appearances', 'false') == 'true': d['appearances'] = Pokemon.get_appearances( request.args.get('pokemonid'), selected_duration) if request.args.get('appearancesDetails', 'false') == 'true': d['appearancesTimes'] = Pokemon.get_appearances_times_by_spawnpoint( request.args.get('pokemonid'), request.args.get('spawnpoint_id'), selected_duration) if request.args.get('spawnpoints', 'false') == 'true': d['spawnpoints'] = Pokemon.get_spawnpoints(swLat, swLng, neLat, neLng) if request.args.get('status', 'false') == 'true': args = get_args() d = {} if args.status_page_password is None: d['error'] = 'Access denied' elif request.args.get('password', None) == args.status_page_password: d['main_workers'] = MainWorker.get_all() d['workers'] = WorkerStatus.get_all() return jsonify(d)
def set_log_and_verbosity(log): # Always write to log file. args = get_args() # Create directory for log files. if not os.path.exists(args.log_path): os.mkdir(args.log_path) if not args.no_file_logs: date = strftime('%Y%m%d_%H%M') filename = os.path.join(args.log_path, '{}_{}.log'.format(date, args.status_name)) filelog = logging.FileHandler(filename) filelog.setFormatter( logging.Formatter( '%(asctime)s [%(threadName)18s][%(module)14s][%(levelname)8s] ' + '%(message)s')) log.addHandler(filelog) if args.verbose: log.setLevel(logging.DEBUG) # Let's log some periodic resource usage stats. t = Thread(target=log_resource_usage_loop, name='res-usage') t.daemon = True t.start() else: log.setLevel(logging.INFO) # These are very noisy, 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) logging.getLogger('pogom.apiRequests').setLevel(logging.INFO) # This sneaky one calls log.warning() on every retry. urllib3_logger = logging.getLogger(requests.packages.urllib3.__package__) urllib3_logger.setLevel(logging.ERROR) # Turn these back up if debugging. if args.verbose >= 2: logging.getLogger('pgoapi').setLevel(logging.DEBUG) logging.getLogger('pgoapi.pgoapi').setLevel(logging.DEBUG) logging.getLogger('requests').setLevel(logging.DEBUG) urllib3_logger.setLevel(logging.INFO) if args.verbose >= 3: logging.getLogger('peewee').setLevel(logging.DEBUG) logging.getLogger('rpc_api').setLevel(logging.DEBUG) logging.getLogger('pgoapi.rpc_api').setLevel(logging.DEBUG) logging.getLogger('werkzeug').setLevel(logging.DEBUG) logging.addLevelName(5, 'TRACE') logging.getLogger('pogom.apiRequests').setLevel(5) # Web access logs. if args.access_logs: date = strftime('%Y%m%d_%H%M') filename = os.path.join( args.log_path, '{}_{}_access.log'.format(date, args.status_name)) logger = logging.getLogger('werkzeug') handler = logging.FileHandler(filename) logger.setLevel(logging.INFO) logger.addHandler(handler)
def render_inject_js(self): args = get_args() return render_template('inject.js', domain=args.manual_captcha_domain, timer=args.manual_captcha_refresh)
def main(): # Patch threading to make exceptions catchable. install_thread_excepthook() # Make sure exceptions get logged. sys.excepthook = handle_exception args = get_args() # Abort if status name is not valid. regexp = re.compile('^([\w\s\-.]+)$') if not regexp.match(args.status_name): log.critical('Status name contains illegal characters.') sys.exit(1) set_log_and_verbosity(log) args.root_path = os.path.dirname(os.path.abspath(__file__)) init_args(args) # Initialize Mr. Mime library mrmime_cfg = { # We don't want exceptions on captchas because we handle them differently. 'exception_on_captcha': False, # MrMime shouldn't jitter 'jitter_gmo': False, 'pgpool_system_id': args.status_name } # Don't clear PGPool URL if it's not given in config but set in MrMime config JSON if args.pgpool_url: mrmime_cfg['pgpool_url'] = args.pgpool_url mrmime_config_file = os.path.join(os.path.dirname(__file__), 'config/mrmime_config.json') init_mr_mime(config_file=mrmime_config_file, user_cfg=mrmime_cfg) # Abort if only-server and no-server are used together if args.only_server and args.no_server: log.critical( "You can't use no-server and only-server at the same time, silly.") sys.exit(1) # Stop if we're just looking for a debug dump. if args.dump: log.info('Retrieving environment info...') hastebin = get_debug_dump_link() log.info('Done! Your debug link: https://hastebin.com/%s.txt', hastebin) sys.exit(1) # Let's not forget to run Grunt / Only needed when running with webserver. if not args.no_server and not validate_assets(args): sys.exit(1) position = extract_coordinates(args.location) # Use the latitude and longitude to get the local altitude from Google. (altitude, status) = get_gmaps_altitude(position[0], position[1], args.gmaps_key) if altitude is not None: log.debug('Local altitude is: %sm', altitude) position = (position[0], position[1], altitude) else: if status == 'REQUEST_DENIED': log.error( 'Google API Elevation request was denied. You probably ' + 'forgot to enable elevation api in https://console.' + 'developers.google.com/apis/api/elevation_backend/') sys.exit() else: log.error('Unable to retrieve altitude from Google APIs' + 'setting to 0') 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.') if args.encounter: log.info('Encountering pokemon enabled.') app = None if not args.no_server and not args.clear_db: app = Pogom(__name__, root_path=os.path.dirname( os.path.abspath(__file__)).decode('utf8')) app.before_request(app.validate_request) app.set_current_location(position) db = startup_db(app, args.clear_db) # Control the search status (running or not) across threads. control_flags = { 'on_demand': Event(), 'api_watchdog': Event(), 'search_control': Event() } for flag in control_flags.values(): flag.clear() if args.on_demand_timeout > 0: control_flags['on_demand'].set() heartbeat = [now()] # Setup the location tracking queue and push the first location on. new_location_queue = Queue() new_location_queue.put(position) # DB Updates db_updates_queue = Queue() if app: app.set_db_updates_queue(db_updates_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=(db_updates_queue, db)) t.daemon = True t.start() # Database cleaner; really only need one ever. if args.enable_clean: t = Thread(target=clean_db_loop, name='db-cleaner', args=(args, )) t.daemon = True t.start() # WH updates queue & WH unique key LFU caches. # The LFU caches will stop the server from resending the same data an # infinite number of times. The caches will be instantiated in the # webhook's startup code. wh_updates_queue = Queue() wh_key_cache = {} if len(args.wh_types) == 0: log.info('Webhook disabled.') else: log.info('Webhook enabled for events: sending %s to %s.', args.wh_types, args.webhooks) # 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, wh_key_cache)) t.daemon = True t.start() if not args.only_server: # Check if we are able to scan. if not can_start_scanning(args): sys.exit(1) initialize_proxies(args) # Update player locale if not set correctly, yet. args.player_locale = PlayerLocale.get_locale(args.location) if not args.player_locale: args.player_locale = gmaps_reverse_geolocate( args.gmaps_key, args.locale, str(position[0]) + ', ' + str(position[1])) db_player_locale = { 'location': args.location, 'country': args.player_locale['country'], 'language': args.player_locale['country'], 'timezone': args.player_locale['timezone'], } db_updates_queue.put((PlayerLocale, {0: db_player_locale})) else: log.debug('Existing player locale has been retrieved from the DB.') # Gather the Pokemon! argset = (args, new_location_queue, control_flags, heartbeat, db_updates_queue, wh_updates_queue) log.debug('Starting a %s search thread', args.scheduler) search_thread = Thread(target=search_overseer_thread, name='search-overseer', args=argset) search_thread.daemon = True search_thread.start() 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: if args.cors: CORS(app) # No more stale JS. init_cache_busting(app) app.set_control_flags(control_flags) app.set_heartbeat_control(heartbeat) app.set_location_queue(new_location_queue) 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.') if args.verbose: app.run(threaded=True, use_reloader=False, debug=True, host=args.host, port=args.port, ssl_context=ssl_context) else: app.run(threaded=True, use_reloader=False, debug=False, host=args.host, port=args.port, ssl_context=ssl_context)
def get_bookmarklet(self): args = get_args() return render_template('bookmarklet.html', domain=args.manual_captcha_domain)
def main(): # Patch threading to make exceptions catchable. install_thread_excepthook() # Make sure exceptions get logged. sys.excepthook = handle_exception args = get_args() # Abort if status name is not valid. regexp = re.compile('^([\w\s\-.]+)$') if not regexp.match(args.status_name): log.critical('Status name contains illegal characters.') sys.exit(1) set_log_and_verbosity(log) args.root_path = os.path.dirname(os.path.abspath(__file__)) init_dynamic_images(args) # Stop if we're just looking for a debug dump. if args.dump: log.info('Retrieving environment info...') hastebin_id = get_debug_dump_link() log.info('Done! Your debug link: https://hastebin.com/%s.txt', hastebin_id) sys.exit(1) # Let's not forget to run Grunt. if not validate_assets(args): sys.exit(1) position = extract_coordinates(args.location) log.info('Parsed location is: %.4f/%.4f/%.4f (lat/lng/alt).', position[0], position[1], position[2]) # Scanning toggles. log.info('Parsing of Pokemon %s.', 'disabled' if args.no_pokemon else 'enabled') log.info('Parsing of Pokestops %s.', 'disabled' if args.no_pokestops else 'enabled') log.info('Parsing of Gyms %s.', 'disabled' if args.no_gyms else 'enabled') log.info('Pokemon encounters %s.', 'enabled' if args.encounter else 'disabled') app = None if not args.clear_db: app = Pogom(__name__, root_path=os.path.dirname(os.path.abspath(__file__))) app.before_request(app.validate_request) app.set_location(position) db = startup_db(app, args.clear_db) # Database cleaner; really only need one ever. if args.db_cleanup: t = Thread(target=clean_db_loop, name='db-cleaner', args=(args, )) t.daemon = True t.start() # Dynamic rarity. if args.rarity_update_frequency: t = Thread(target=dynamic_rarity_refresher, name='dynamic-rarity') t.daemon = True log.info('Dynamic rarity is enabled.') t.start() else: log.info('Dynamic rarity is disabled.') # Parks downloading if args.parks: t = Thread(target=download_all_parks, name='parks') t.daemon = True log.info('Parks downloading is enabled.') t.start() else: log.info('Parks downloading is disabled.') if args.cors: CORS(app) # No more stale JS. cache_buster = CacheBuster() cache_buster.init_app(app) 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.') if args.verbose: app.run(threaded=True, use_reloader=False, debug=True, host=args.host, port=args.port, ssl_context=ssl_context) else: app.run(threaded=True, use_reloader=False, debug=False, host=args.host, port=args.port, ssl_context=ssl_context)
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 new_location_queue = Queue() new_location_queue.put(position) # 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! # check the sort of scan if args.spawnpoint_scanning: mode = 'sps' else: mode = 'hex' # attempt to dump the spawn points (do this before starting threads of endure the woe) if args.spawnpoint_scanning and args.spawnpoint_scanning != 'nofile' and args.dump_spawnpoints: with open(args.spawnpoint_scanning, 'w+') as file: log.info('Sawing spawn points to %s', args.spawnpoint_scanning) spawns = Pokemon.get_spawnpoints_in_hex(position, args.step_limit) file.write(json.dumps(spawns)) log.info('Finished exporting spawn points') argset = (args, mode, new_location_queue, pause_bit, encryption_lib_path, db_updates_queue, wh_updates_queue) log.debug('Starting a %s search thread', mode) search_thread = Thread(target=search_overseer_thread, name='search-overseer', args=argset) search_thread.daemon = True 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_queue(new_location_queue) 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)
def get_status(self): args = get_args() if args.status_page_password is None: abort(404) return render_template('status.html')
def main(): # Patch threading to make exceptions catchable. install_thread_excepthook() # Make sure exceptions get logged. sys.excepthook = handle_exception args = get_args() set_log_and_verbosity(log) # Abort if only-server and no-server are used together if args.only_server and args.no_server: log.critical( "You can't use no-server and only-server at the same time, silly.") sys.exit(1) # Abort if status name is not valid. regexp = re.compile('^([\w\s\-.]+)$') if not regexp.match(args.status_name): log.critical('Status name contains illegal characters.') sys.exit(1) # Stop if we're just looking for a debug dump. if args.dump: log.info('Retrieving environment info...') hastebin = get_debug_dump_link() log.info('Done! Your debug link: https://hastebin.com/%s.txt', hastebin) sys.exit(1) # Let's not forget to run Grunt / Only needed when running with webserver. if not args.no_server and not validate_assets(args): sys.exit(1) # 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) if position is None or not any(position): log.error("Location not found: '{}'".format(args.location)) sys.exit() # Use the latitude and longitude to get the local altitude from Google. (altitude, status) = get_gmaps_altitude(position[0], position[1], args.gmaps_key) if altitude is not None: log.debug('Local altitude is: %sm', altitude) position = (position[0], position[1], altitude) else: if status == 'REQUEST_DENIED': log.error( 'Google API Elevation request was denied. You probably ' + 'forgot to enable elevation api in https://console.' + 'developers.google.com/apis/api/elevation_backend/') sys.exit() else: log.error('Unable to retrieve altitude from Google APIs' + 'setting to 0') 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.') if args.encounter: log.info('Encountering pokemon enabled.') app = None if not args.no_server and not args.clear_db: app = Pogom(__name__, root_path=os.path.dirname( os.path.abspath(__file__)).decode('utf8')) app.before_request(app.validate_request) app.set_current_location(position) 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) verify_database_schema(db) create_tables(db) # Fix encoding on present and future tables. verify_table_encoding(db) if args.clear_db: log.info('Drop and recreate is complete. Now remove -cd and restart.') sys.exit() args.root_path = os.path.dirname(os.path.abspath(__file__)) # Control the search status (running or not) across threads. control_flags = { 'on_demand': Event(), 'api_watchdog': Event(), 'search_control': Event() } for flag in control_flags.values(): flag.clear() if args.on_demand_timeout > 0: control_flags['on_demand'].set() heartbeat = [now()] # Setup the location tracking queue and push the first location on. new_location_queue = Queue() new_location_queue.put(position) # 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=(db_updates_queue, db)) t.daemon = True t.start() # Database cleaner; really only need one ever. if args.enable_clean: t = Thread(target=clean_db_loop, name='db-cleaner', args=(args, )) t.daemon = True t.start() # WH updates queue & WH unique key LFU caches. # The LFU caches will stop the server from resending the same data an # infinite number of times. The caches will be instantiated in the # webhook's startup code. wh_updates_queue = Queue() wh_key_cache = {} if len(args.wh_types) == 0: log.info('Webhook disabled.') else: log.info('Webhook enabled for events: sending %s to %s.', args.wh_types, args.webhooks) # 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, wh_key_cache)) t.daemon = True t.start() if not args.only_server: # Check if we are able to scan. if not can_start_scanning(args): sys.exit(1) # Processing proxies if set (load from file, check and overwrite old # args.proxy with new working list). args.proxy = load_proxies(args) if args.proxy and not args.proxy_skip_check: args.proxy = check_proxies(args, args.proxy) # Run periodical proxy refresh thread. if (args.proxy_file is not None) and (args.proxy_refresh > 0): t = Thread(target=proxies_refresher, name='proxy-refresh', args=(args, )) t.daemon = True t.start() else: log.info('Periodical proxies refresh disabled.') # Update player locale if not set correctly, yet. args.player_locale = PlayerLocale.get_locale(args.location) if not args.player_locale: args.player_locale = gmaps_reverse_geolocate( args.gmaps_key, args.locale, str(position[0]) + ', ' + str(position[1])) db_player_locale = { 'location': args.location, 'country': args.player_locale['country'], 'language': args.player_locale['country'], 'timezone': args.player_locale['timezone'], } db_updates_queue.put((PlayerLocale, {0: db_player_locale})) else: log.debug('Existing player locale has been retrieved from the DB.') # Gather the Pokemon! # Attempt to dump the spawn points (do this before starting threads of # endure the woe). if (args.spawnpoint_scanning and args.spawnpoint_scanning != 'nofile' and args.dump_spawnpoints): with open(args.spawnpoint_scanning, 'w+') as file: log.info('Saving spawn points to %s', args.spawnpoint_scanning) spawns = SpawnPoint.get_spawnpoints_in_hex( position, args.step_limit) file.write(json.dumps(spawns)) log.info('Finished exporting spawn points') argset = (args, new_location_queue, control_flags, heartbeat, db_updates_queue, wh_updates_queue) log.debug('Starting a %s search thread', args.scheduler) search_thread = Thread(target=search_overseer_thread, name='search-overseer', args=argset) search_thread.daemon = True search_thread.start() 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: if args.cors: CORS(app) # No more stale JS. init_cache_busting(app) app.set_control_flags(control_flags) app.set_heartbeat_control(heartbeat) app.set_location_queue(new_location_queue) 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.') if args.verbose: app.run(threaded=True, use_reloader=False, debug=True, host=args.host, port=args.port, ssl_context=ssl_context) else: app.run(threaded=True, use_reloader=False, debug=False, host=args.host, port=args.port, ssl_context=ssl_context)
def raw_data(self): self.heartbeat[0] = now() args = get_args() if args.on_demand_timeout > 0: self.search_control.clear() d = {} # Request time of this request. d['timestamp'] = datetime.utcnow() # Request time of previous request. if request.args.get('timestamp'): timestamp = int(request.args.get('timestamp')) timestamp -= 1000 # Overlap, for rounding errors. else: timestamp = 0 swLat = request.args.get('swLat') swLng = request.args.get('swLng') neLat = request.args.get('neLat') neLng = request.args.get('neLng') oSwLat = request.args.get('oSwLat') oSwLng = request.args.get('oSwLng') oNeLat = request.args.get('oNeLat') oNeLng = request.args.get('oNeLng') # Previous switch settings. lastgyms = request.args.get('lastgyms') lastpokestops = request.args.get('lastpokestops') lastpokemon = request.args.get('lastpokemon') lastslocs = request.args.get('lastslocs') lastspawns = request.args.get('lastspawns') if request.args.get('luredonly', 'true') == 'true': luredonly = True else: luredonly = False # Current switch settings saved for next request. if request.args.get('gyms', 'true') == 'true': d['lastgyms'] = request.args.get('gyms', 'true') if request.args.get('pokestops', 'true') == 'true': d['lastpokestops'] = request.args.get('pokestops', 'true') if request.args.get('pokemon', 'true') == 'true': d['lastpokemon'] = request.args.get('pokemon', 'true') if request.args.get('scanned', 'true') == 'true': d['lastslocs'] = request.args.get('scanned', 'true') if request.args.get('spawnpoints', 'false') == 'true': d['lastspawns'] = request.args.get('spawnpoints', 'false') # If old coords are not equal to current coords we have moved/zoomed! if (oSwLng < swLng and oSwLat < swLat and oNeLat > neLat and oNeLng > neLng): newArea = False # We zoomed in no new area uncovered. elif not (oSwLat == swLat and oSwLng == swLng and oNeLat == neLat and oNeLng == neLng): newArea = True else: newArea = False # Pass current coords as old coords. d['oSwLat'] = swLat d['oSwLng'] = swLng d['oNeLat'] = neLat d['oNeLng'] = neLng if (request.args.get('pokemon', 'true') == 'true' and not args.no_pokemon): if request.args.get('ids'): ids = [int(x) for x in request.args.get('ids').split(',')] d['pokemons'] = Pokemon.get_active_by_id( ids, swLat, swLng, neLat, neLng) elif lastpokemon != 'true': # If this is first request since switch on, load # all pokemon on screen. d['pokemons'] = Pokemon.get_active(swLat, swLng, neLat, neLng) else: # If map is already populated only request modified Pokemon # since last request time. d['pokemons'] = Pokemon.get_active(swLat, swLng, neLat, neLng, timestamp=timestamp) if newArea: # If screen is moved add newly uncovered Pokemon to the # ones that were modified since last request time. d['pokemons'] = d['pokemons'] + (Pokemon.get_active( swLat, swLng, neLat, neLng, oSwLat=oSwLat, oSwLng=oSwLng, oNeLat=oNeLat, oNeLng=oNeLng)) if request.args.get('eids'): # Exclude id's of pokemon that are hidden. eids = [int(x) for x in request.args.get('eids').split(',')] d['pokemons'] = [ x for x in d['pokemons'] if x['pokemon_id'] not in eids ] if request.args.get('reids'): reids = [int(x) for x in request.args.get('reids').split(',')] d['pokemons'] = d['pokemons'] + (Pokemon.get_active_by_id( reids, swLat, swLng, neLat, neLng)) d['reids'] = reids if (request.args.get('pokestops', 'true') == 'true' and not args.no_pokestops): if lastpokestops != 'true': d['pokestops'] = Pokestop.get_stops(swLat, swLng, neLat, neLng, lured=luredonly) else: d['pokestops'] = Pokestop.get_stops(swLat, swLng, neLat, neLng, timestamp=timestamp) if newArea: d['pokestops'] = d['pokestops'] + (Pokestop.get_stops( swLat, swLng, neLat, neLng, oSwLat=oSwLat, oSwLng=oSwLng, oNeLat=oNeLat, oNeLng=oNeLng, lured=luredonly)) if request.args.get('gyms', 'true') == 'true' and not args.no_gyms: if lastgyms != 'true': d['gyms'] = Gym.get_gyms(swLat, swLng, neLat, neLng) else: d['gyms'] = Gym.get_gyms(swLat, swLng, neLat, neLng, timestamp=timestamp) if newArea: d['gyms'].update( Gym.get_gyms(swLat, swLng, neLat, neLng, oSwLat=oSwLat, oSwLng=oSwLng, oNeLat=oNeLat, oNeLng=oNeLng)) if request.args.get('scanned', 'true') == 'true': if lastslocs != 'true': d['scanned'] = ScannedLocation.get_recent( swLat, swLng, neLat, neLng) else: d['scanned'] = ScannedLocation.get_recent(swLat, swLng, neLat, neLng, timestamp=timestamp) if newArea: d['scanned'] = d['scanned'] + ScannedLocation.get_recent( swLat, swLng, neLat, neLng, oSwLat=oSwLat, oSwLng=oSwLng, oNeLat=oNeLat, oNeLng=oNeLng) selected_duration = None # for stats and changed nest points etc, limit pokemon queried. for duration in ( self.get_valid_stat_input()["duration"]["items"].values()): if duration["selected"] == "SELECTED": selected_duration = duration["value"] break if request.args.get('seen', 'false') == 'true': d['seen'] = Pokemon.get_seen(selected_duration) if request.args.get('appearances', 'false') == 'true': d['appearances'] = Pokemon.get_appearances( request.args.get('pokemonid'), selected_duration) if request.args.get('appearancesDetails', 'false') == 'true': d['appearancesTimes'] = ( Pokemon.get_appearances_times_by_spawnpoint( request.args.get('pokemonid'), request.args.get('spawnpoint_id'), selected_duration)) if request.args.get('spawnpoints', 'false') == 'true': if lastspawns != 'true': d['spawnpoints'] = Pokemon.get_spawnpoints(swLat=swLat, swLng=swLng, neLat=neLat, neLng=neLng) else: d['spawnpoints'] = Pokemon.get_spawnpoints(swLat=swLat, swLng=swLng, neLat=neLat, neLng=neLng, timestamp=timestamp) if newArea: d['spawnpoints'] = d['spawnpoints'] + ( Pokemon.get_spawnpoints(swLat, swLng, neLat, neLng, oSwLat=oSwLat, oSwLng=oSwLng, oNeLat=oNeLat, oNeLng=oNeLng)) if request.args.get('status', 'false') == 'true': args = get_args() d = {} if args.status_page_password is None: d['error'] = 'Access denied' elif (request.args.get('password', None) == args.status_page_password): d['main_workers'] = MainWorker.get_all() d['workers'] = WorkerStatus.get_all() return jsonify(d)
def main(): args = get_args() # Check for depreciated argumented if args.debug: log.warning( '--debug is depreciated. Please use --verbose instead. Enabling --verbose' ) args.verbose = 'nofile' # Add file logging if enabled if args.verbose and args.verbose != 'nofile': filelog = logging.FileHandler(args.verbose) filelog.setFormatter( logging.Formatter( '%(asctime)s [%(threadName)16s][%(module)14s][%(levelname)8s] %(message)s' )) logging.getLogger('').addHandler(filelog) if args.very_verbose and args.very_verbose != 'nofile': filelog = logging.FileHandler(args.very_verbose) filelog.setFormatter( logging.Formatter( '%(asctime)s [%(threadName)16s][%(module)14s][%(levelname)8s] %(message)s' )) logging.getLogger('').addHandler(filelog) # 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.verbose or args.very_verbose: 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.verbose or args.very_verbose: logging.getLogger('pgoapi').setLevel(logging.DEBUG) if args.very_verbose: logging.getLogger('peewee').setLevel(logging.DEBUG) logging.getLogger('requests').setLevel(logging.DEBUG) logging.getLogger('pgoapi.pgoapi').setLevel(logging.DEBUG) logging.getLogger('pgoapi.rpc_api').setLevel(logging.DEBUG) logging.getLogger('rpc_api').setLevel(logging.DEBUG) logging.getLogger('werkzeug').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 new_location_queue = Queue() new_location_queue.put(position) # 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() # WH Updates catch_pokemon_queue = Queue() # Attach queue to Flask App app.catch_pokemon_queue = catch_pokemon_queue # Setup the message object message_obj = LogMessages() app.log_message_object = message_obj # Thread to process catch_pokemon requests log.debug('Starting catch_pokemon worker thread') t = Thread(target=catch_pokemon_worker, name='catch-pokemon', args=(args, catch_pokemon_queue, message_obj, encryption_lib_path)) t.daemon = True t.start() if not args.only_server: # Gather the pokemons! # check the sort of scan if args.spawnpoint_scanning: mode = 'sps' else: mode = 'hex' # attempt to dump the spawn points (do this before starting threads of endure the woe) if args.spawnpoint_scanning and args.spawnpoint_scanning != 'nofile' and args.dump_spawnpoints: with open(args.spawnpoint_scanning, 'w+') as file: log.info('Saving spawn points to %s', args.spawnpoint_scanning) spawns = Pokemon.get_spawnpoints_in_hex( position, args.step_limit) file.write(json.dumps(spawns)) log.info('Finished exporting spawn points') argset = (args, mode, new_location_queue, pause_bit, encryption_lib_path, db_updates_queue, wh_updates_queue) log.debug('Starting a %s search thread', mode) search_thread = Thread(target=search_overseer_thread, name='search-overseer', args=argset) search_thread.daemon = True 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_queue(new_location_queue) # Add login # set the secret key. keep this really secret: app.secret_key = 'DuEkd*7d83Df3@#$)9fkD(8Fd(&d^ @#4kllz3' # Prepare the LoginManager login_manager = LoginManager() login_manager.init_app(app) @login_manager.user_loader def load_user(uid): return User.get_user(uid) login_manager.login_view = 'login' 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 gevent won't be holding the program open while search_thread.is_alive(): time.sleep(60) else: # run gevent server gevent_log = None if args.verbose or args.very_verbose: gevent_log = log if args.ssl_certificate and args.ssl_privatekey \ and os.path.exists(args.ssl_certificate) and os.path.exists(args.ssl_privatekey): http_server = pywsgi.WSGIServer((args.host, args.port), app, log=gevent_log, error_log=log, keyfile=args.ssl_privatekey, certfile=args.ssl_certificate, ssl_version=ssl.PROTOCOL_TLSv1_2) log.info('Web server in SSL mode, listening at https://%s:%d', args.host, args.port) else: http_server = pywsgi.WSGIServer((args.host, args.port), app, log=gevent_log, error_log=log) log.info('Web server listening at http://%s:%d', args.host, args.port) # run it try: http_server.serve_forever() except KeyboardInterrupt: pass
def main(): # Patch threading to make exceptions catchable. install_thread_excepthook() # Make sure exceptions get logged. sys.excepthook = handle_exception args = get_args() # Add file logging if enabled. if args.verbose and args.verbose != 'nofile': filelog = logging.FileHandler(args.verbose) filelog.setFormatter( logging.Formatter( '%(asctime)s [%(threadName)16s][%(module)14s][%(levelname)8s] ' + '%(message)s')) logging.getLogger('').addHandler(filelog) if args.very_verbose and args.very_verbose != 'nofile': filelog = logging.FileHandler(args.very_verbose) filelog.setFormatter( logging.Formatter( '%(asctime)s [%(threadName)16s][%(module)14s][%(levelname)8s] ' + '%(message)s')) logging.getLogger('').addHandler(filelog) if args.verbose or args.very_verbose: 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() # You need custom image files now. if not os.path.isfile( os.path.join(os.path.dirname(__file__), 'static/icons-sprite.png')): log.info('Sprite files not present, extracting bundled ones...') extract_sprites() log.info('Done!') # These are very noisy, 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.verbose or args.very_verbose: logging.getLogger('pgoapi').setLevel(logging.DEBUG) if args.very_verbose: logging.getLogger('peewee').setLevel(logging.DEBUG) logging.getLogger('requests').setLevel(logging.DEBUG) logging.getLogger('pgoapi.pgoapi').setLevel(logging.DEBUG) logging.getLogger('pgoapi.rpc_api').setLevel(logging.DEBUG) logging.getLogger('rpc_api').setLevel(logging.DEBUG) logging.getLogger('werkzeug').setLevel(logging.DEBUG) # Web access logs. if args.access_logs: logger = logging.getLogger('werkzeug') handler = logging.FileHandler('access.log') logger.setLevel(logging.INFO) logger.addHandler(handler) # 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) if position is None or not any(position): log.error("Location not found: '{}'".format(args.location)) sys.exit() # Use the latitude and longitude to get the local altitude from Google. (altitude, status) = get_gmaps_altitude(position[0], position[1], args.gmaps_key) if altitude is not None: log.debug('Local altitude is: %sm', altitude) position = (position[0], position[1], altitude) else: if status == 'REQUEST_DENIED': log.error( 'Google API Elevation request was denied. You probably ' + 'forgot to enable elevation api in https://console.' + 'developers.google.com/apis/api/elevation_backend/') sys.exit() else: log.error('Unable to retrieve altitude from Google APIs' + 'setting to 0') 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.') if args.encounter: log.info('Encountering pokemon enabled.') config['LOCALE'] = args.locale config['CHINA'] = args.china app = Pogom(__name__) app.before_request(app.validate_request) db = init_database(app) if args.accountdb: accounts = Account.get_all() args.accounts = [] for account in accounts: if account['enabled']: args.accounts.append({ 'username': account['name'], 'password': account['password'], 'auth_service': account['login_type'] }) connections = args.db_max_connections if len(args.accounts) > 0: connections *= len(args.accounts) db.max_connections = connections 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() if args.on_demand_timeout > 0: pause_bit.set() heartbeat = [now()] # Setup the location tracking queue and push the first location on. new_location_queue = Queue() new_location_queue.put(position) # 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, db)) t.daemon = True t.start() # db cleaner; really only need one ever. if not args.disable_clean: t = Thread(target=clean_db_loop, name='db-cleaner', args=(args, )) t.daemon = True t.start() # WH updates queue & WH gym/pokéstop unique key LFU cache. # The LFU cache will stop the server from resending the same data an # infinite number of times. # TODO: Rework webhooks entirely so a LFU cache isn't necessary. wh_updates_queue = Queue() wh_key_cache = LFUCache(maxsize=args.wh_lfu_size) # 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, wh_key_cache)) t.daemon = True t.start() if not args.only_server: # Processing proxies if set (load from file, check and overwrite old # args.proxy with new working list) args.proxy = check_proxies(args) # Run periodical proxy refresh thread if (args.proxy_file is not None) and (args.proxy_refresh > 0): t = Thread(target=proxies_refresher, name='proxy-refresh', args=(args, )) t.daemon = True t.start() else: log.info('Periodical proxies refresh disabled.') # Gather the Pokemon! # Attempt to dump the spawn points (do this before starting threads of # endure the woe). if (args.spawnpoint_scanning and args.spawnpoint_scanning != 'nofile' and args.dump_spawnpoints): with open(args.spawnpoint_scanning, 'w+') as file: log.info('Saving spawn points to %s', args.spawnpoint_scanning) spawns = Pokemon.get_spawnpoints_in_hex( position, args.step_limit) file.write(json.dumps(spawns)) log.info('Finished exporting spawn points') argset = (args, new_location_queue, pause_bit, heartbeat, db_updates_queue, wh_updates_queue) log.debug('Starting a %s search thread', args.scheduler) search_thread = Thread(target=search_overseer_thread, name='search-overseer', args=argset) search_thread.daemon = True search_thread.start() if args.cors: CORS(app) # No more stale JS. init_cache_busting(app) app.set_search_control(pause_bit) app.set_heartbeat_control(heartbeat) app.set_location_queue(new_location_queue) 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.') if args.verbose or args.very_verbose: app.run(threaded=True, use_reloader=False, debug=True, host=args.host, port=args.port, ssl_context=ssl_context) else: app.run(threaded=True, use_reloader=False, debug=False, host=args.host, port=args.port, ssl_context=ssl_context)
def render_inject_js(self): args = get_args() return render_template("inject.js", domain=args.manual_captcha_solving_domain, password=args.manual_captcha_solving_password)
def start_locator_thread(self): search_thread = Thread(target=search_loop, args=(get_args(),)) search_thread.daemon = True search_thread.name = 'search_thread' search_thread.start()
def main(): # Check if we have the proper encryption library file and get its path encryption_lib_path = get_encryption_lib_path() if encryption_lib_path is "": sys.exit(1) args = get_args() 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 new_location_queue = Queue() new_location_queue.put(position) # 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, new_location_queue, 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_queue(new_location_queue) 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)
def raw_data(self): # Make sure fingerprint isn't blacklisted. # fingerprint_blacklisted = any([ # fingerprints['no_referrer'](request), # fingerprints['iPokeGo'](request) # ]) fingerprint_blacklisted = False if fingerprint_blacklisted: log.debug('User denied access: blacklisted fingerprint.') abort(403) self.heartbeat[0] = now() args = get_args() if args.on_demand_timeout > 0: self.control_flags['on_demand'].clear() d = {} # Request time of this request. d['timestamp'] = datetime.utcnow() # Request time of previous request. if request.args.get('timestamp'): timestamp = int(request.args.get('timestamp')) timestamp -= 1000 # Overlap, for rounding errors. else: timestamp = 0 swLat = request.args.get('swLat') swLng = request.args.get('swLng') neLat = request.args.get('neLat') neLng = request.args.get('neLng') oSwLat = request.args.get('oSwLat') oSwLng = request.args.get('oSwLng') oNeLat = request.args.get('oNeLat') oNeLng = request.args.get('oNeLng') # Previous switch settings. lastgyms = request.args.get('lastgyms') lastpokestops = request.args.get('lastpokestops') lastpokemon = request.args.get('lastpokemon') lastslocs = request.args.get('lastslocs') lastspawns = request.args.get('lastspawns') if request.args.get('luredonly', 'true') == 'true': luredonly = True else: luredonly = False # Current switch settings saved for next request. if request.args.get('gyms', 'true') == 'true': d['lastgyms'] = request.args.get('gyms', 'true') if request.args.get('pokestops', 'true') == 'true': d['lastpokestops'] = request.args.get('pokestops', 'true') if request.args.get('pokemon', 'true') == 'true': d['lastpokemon'] = request.args.get('pokemon', 'true') if request.args.get('scanned', 'true') == 'true': d['lastslocs'] = request.args.get('scanned', 'true') if request.args.get('spawnpoints', 'false') == 'true': d['lastspawns'] = request.args.get('spawnpoints', 'false') # If old coords are not equal to current coords we have moved/zoomed! if (oSwLng < swLng and oSwLat < swLat and oNeLat > neLat and oNeLng > neLng): newArea = False # We zoomed in no new area uncovered. elif not (oSwLat == swLat and oSwLng == swLng and oNeLat == neLat and oNeLng == neLng): newArea = True else: newArea = False # Pass current coords as old coords. d['oSwLat'] = swLat d['oSwLng'] = swLng d['oNeLat'] = neLat d['oNeLng'] = neLng if (request.args.get('pokemon', 'true') == 'true' and not args.no_pokemon): if request.args.get('ids'): ids = [int(x) for x in request.args.get('ids').split(',')] d['pokemons'] = convert_pokemon_list( Pokemon.get_active_by_id(ids, swLat, swLng, neLat, neLng)) elif lastpokemon != 'true': # If this is first request since switch on, load # all pokemon on screen. d['pokemons'] = convert_pokemon_list( Pokemon.get_active(swLat, swLng, neLat, neLng)) else: # If map is already populated only request modified Pokemon # since last request time. d['pokemons'] = convert_pokemon_list( Pokemon.get_active(swLat, swLng, neLat, neLng, timestamp=timestamp)) if newArea: # If screen is moved add newly uncovered Pokemon to the # ones that were modified since last request time. d['pokemons'] = d['pokemons'] + (convert_pokemon_list( Pokemon.get_active(swLat, swLng, neLat, neLng, oSwLat=oSwLat, oSwLng=oSwLng, oNeLat=oNeLat, oNeLng=oNeLng))) if request.args.get('eids'): # Exclude id's of pokemon that are hidden. eids = [int(x) for x in request.args.get('eids').split(',')] d['pokemons'] = [ x for x in d['pokemons'] if x['pokemon_id'] not in eids ] if request.args.get('reids'): reids = [int(x) for x in request.args.get('reids').split(',')] d['pokemons'] = d['pokemons'] + (convert_pokemon_list( Pokemon.get_active_by_id(reids, swLat, swLng, neLat, neLng))) d['reids'] = reids if (request.args.get('pokestops', 'true') == 'true' and not args.no_pokestops): if lastpokestops != 'true': d['pokestops'] = Pokestop.get_stops(swLat, swLng, neLat, neLng, lured=luredonly) else: d['pokestops'] = Pokestop.get_stops(swLat, swLng, neLat, neLng, timestamp=timestamp) if newArea: d['pokestops'] = d['pokestops'] + (Pokestop.get_stops( swLat, swLng, neLat, neLng, oSwLat=oSwLat, oSwLng=oSwLng, oNeLat=oNeLat, oNeLng=oNeLng, lured=luredonly)) if request.args.get('gyms', 'true') == 'true' and not args.no_gyms: if lastgyms != 'true': d['gyms'] = Gym.get_gyms(swLat, swLng, neLat, neLng) else: d['gyms'] = Gym.get_gyms(swLat, swLng, neLat, neLng, timestamp=timestamp) if newArea: d['gyms'].update( Gym.get_gyms(swLat, swLng, neLat, neLng, oSwLat=oSwLat, oSwLng=oSwLng, oNeLat=oNeLat, oNeLng=oNeLng)) if request.args.get('scanned', 'true') == 'true': if lastslocs != 'true': d['scanned'] = ScannedLocation.get_recent( swLat, swLng, neLat, neLng) else: d['scanned'] = ScannedLocation.get_recent(swLat, swLng, neLat, neLng, timestamp=timestamp) if newArea: d['scanned'] = d['scanned'] + ScannedLocation.get_recent( swLat, swLng, neLat, neLng, oSwLat=oSwLat, oSwLng=oSwLng, oNeLat=oNeLat, oNeLng=oNeLng) if request.args.get('seen', 'false') == 'true': d['seen'] = Pokemon.get_seen(int(request.args.get('duration'))) if request.args.get('appearances', 'false') == 'true': d['appearances'] = Pokemon.get_appearances( request.args.get('pokemonid'), int(request.args.get('duration'))) if request.args.get('appearancesDetails', 'false') == 'true': d['appearancesTimes'] = ( Pokemon.get_appearances_times_by_spawnpoint( request.args.get('pokemonid'), request.args.get('spawnpoint_id'), int(request.args.get('duration')))) if request.args.get('spawnpoints', 'false') == 'true': if lastspawns != 'true': d['spawnpoints'] = SpawnPoint.get_spawnpoints(swLat=swLat, swLng=swLng, neLat=neLat, neLng=neLng) else: d['spawnpoints'] = SpawnPoint.get_spawnpoints( swLat=swLat, swLng=swLng, neLat=neLat, neLng=neLng, timestamp=timestamp) if newArea: d['spawnpoints'] = d['spawnpoints'] + ( SpawnPoint.get_spawnpoints(swLat, swLng, neLat, neLng, oSwLat=oSwLat, oSwLng=oSwLng, oNeLat=oNeLat, oNeLng=oNeLng)) if request.args.get('status', 'false') == 'true': args = get_args() d = {} if args.status_page_password is None: d['error'] = 'Access denied' elif (request.args.get('password', None) == args.status_page_password): d['main_workers'] = MainWorker.get_all() d['workers'] = WorkerStatus.get_all() return jsonify(d)
def main(): # Patch threading to make exceptions catchable. install_thread_excepthook() # Make sure exceptions get logged. sys.excepthook = handle_exception args = get_args() set_log_and_verbosity(log) global db_updates_queue # Abort if status name is not valid. regexp = re.compile('^([\w\s\-.]+)$') if not regexp.match(args.status_name): log.critical('Status name contains illegal characters.') sys.exit(1) # Stop if we're just looking for a debug dump. if args.dump: log.info('Retrieving environment info...') hastebin_id = get_debug_dump_link() log.info('Done! Your debug link: https://hastebin.com/%s.txt', hastebin_id) sys.exit(1) # Let's not forget to run Grunt / Only needed when running with webserver. if not validate_assets(args): sys.exit(1) position = extract_coordinates(args.location) # Use the latitude and longitude to get the local altitude from Google. (altitude, status) = get_gmaps_altitude(position[0], position[1], args.gmaps_key) if altitude is not None: log.debug('Local altitude is: %sm.', altitude) position = (position[0], position[1], altitude) else: if status == 'REQUEST_DENIED': log.error( 'Google API Elevation request was denied. You probably ' + 'forgot to enable elevation api in https://console.' + 'developers.google.com/apis/api/elevation_backend/') sys.exit() else: log.error('Unable to retrieve altitude from Google APIs' + 'setting to 0') log.info('Parsed location is: %.4f/%.4f/%.4f (lat/lng/alt).', position[0], position[1], position[2]) # Scanning toggles. log.info('Parsing of Pokemon %s.', 'disabled' if args.no_pokemon else 'enabled') log.info('Parsing of Pokestops %s.', 'disabled' if args.no_pokestops else 'enabled') log.info('Parsing of Gyms %s.', 'disabled' if args.no_gyms else 'enabled') log.info('Pokemon encounters %s.', 'enabled' if args.encounter else 'disabled') app = None if not args.clear_db: app = Pogom(__name__, root_path=os.path.dirname( os.path.abspath(__file__)).decode('utf8'), db_update_queue=db_updates_queue, spawn_delay=args.spawn_delay, stepsize=args.stepsize, maxradius=args.maxradius, lure_duration=args.lure_duration) app.before_request(app.validate_request) app.set_current_location(position) db = startup_db(app, args.clear_db) args.root_path = os.path.dirname(os.path.abspath(__file__)) if args.ex_gyms: # Geofence is required. if not args.geofence_file: log.critical('A geofence is required to find EX-gyms.') sys.exit(1) update_ex_gyms(args.geofence_file) log.info('Finished checking gyms against OSM parks, exiting.') sys.exit(1) # Control the search status (running or not) across threads. control_flags = { 'on_demand': Event(), 'api_watchdog': Event(), 'search_control': Event() } for flag in control_flags.values(): flag.clear() if args.on_demand_timeout > 0: control_flags['on_demand'].set() heartbeat = [now()] # Setup the location tracking queue and push the first location on. new_location_queue = Queue() new_location_queue.put(position) # 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=(db_updates_queue, db)) t.daemon = True t.start() # Database cleaner; really only need one ever. if args.db_cleanup: t = Thread(target=clean_db_loop, name='db-cleaner', args=(args, )) t.daemon = True t.start() if args.rarity_update_frequency: t = Thread(target=dynamic_rarity_refresher, name='dynamic-rarity') t.daemon = True t.start() log.info('Dynamic rarity is enabled.') else: log.info('Dynamic rarity is disabled.') if args.cors: CORS(app) # No more stale JS. init_cache_busting(app) app.set_control_flags(control_flags) app.set_heartbeat_control(heartbeat) app.set_location_queue(new_location_queue) 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.') if args.verbose: app.run(threaded=True, use_reloader=False, debug=True, host=args.host, port=args.port, ssl_context=ssl_context) else: app.run(threaded=True, use_reloader=False, debug=False, host=args.host, port=args.port, ssl_context=ssl_context)
def main(): # Patch threading to make exceptions catchable. install_thread_excepthook() # Make sure exceptions get logged. sys.excepthook = handle_exception args = get_args() set_log_and_verbosity(log) # Abort if only-server and no-server are used together if args.only_server and args.no_server: log.critical( "You can't use no-server and only-server at the same time, silly.") sys.exit(1) # Abort if status name is not valid. regexp = re.compile('^([\w\s\-.]+)$') if not regexp.match(args.status_name): log.critical('Status name contains illegal characters.') sys.exit(1) # Stop if we're just looking for a debug dump. if args.dump: log.info('Retrieving environment info...') hastebin_id = get_debug_dump_link() log.info('Done! Your debug link: https://hastebin.com/%s.txt', hastebin_id) sys.exit(1) # Let's not forget to run Grunt / Only needed when running with webserver. if not args.no_server and not validate_assets(args): sys.exit(1) if args.no_version_check and not args.only_server: log.warning('You are running RocketMap in No Version Check mode. ' "If you don't know what you're doing, this mode " 'can have negative consequences, and you will not ' 'receive support running in NoVC mode. ' 'You have been warned.') position = extract_coordinates(args.location) # Use the latitude and longitude to get the local altitude from Google. (altitude, status) = get_gmaps_altitude(position[0], position[1], args.gmaps_key) if altitude is not None: log.debug('Local altitude is: %sm.', altitude) position = (position[0], position[1], altitude) else: if status == 'REQUEST_DENIED': log.error( 'Google API Elevation request was denied. You probably ' + 'forgot to enable elevation api in https://console.' + 'developers.google.com/apis/api/elevation_backend/') sys.exit() else: log.error('Unable to retrieve altitude from Google APIs' + 'setting to 0') log.info('Parsed location is: %.4f/%.4f/%.4f (lat/lng/alt).', position[0], position[1], position[2]) # Scanning toggles. log.info('Parsing of Pokemon %s.', 'disabled' if args.no_pokemon else 'enabled') log.info('Parsing of Pokestops %s.', 'disabled' if args.no_pokestops else 'enabled') log.info('Parsing of Gyms %s.', 'disabled' if args.no_gyms else 'enabled') log.info('Pokemon encounters %s.', 'enabled' if args.encounter else 'disabled') app = None if not args.no_server and not args.clear_db: app = Pogom(__name__, root_path=os.path.dirname( os.path.abspath(__file__)).decode('utf8')) app.before_request(app.validate_request) app.set_current_location(position) db = startup_db(app, args.clear_db) args.root_path = os.path.dirname(os.path.abspath(__file__)) # Control the search status (running or not) across threads. control_flags = { 'on_demand': Event(), 'api_watchdog': Event(), 'search_control': Event() } for flag in control_flags.values(): flag.clear() if args.on_demand_timeout > 0: control_flags['on_demand'].set() heartbeat = [now()] # Setup the location tracking queue and push the first location on. new_location_queue = Queue() new_location_queue.put(position) # 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=(db_updates_queue, db)) t.daemon = True t.start() # Database cleaner; really only need one ever. if args.enable_clean: t = Thread(target=clean_db_loop, name='db-cleaner', args=(args, )) t.daemon = True t.start() # WH updates queue & WH unique key LFU caches. # The LFU caches will stop the server from resending the same data an # infinite number of times. The caches will be instantiated in the # webhook's startup code. wh_updates_queue = Queue() wh_key_cache = {} if not args.wh_types: log.info('Webhook disabled.') else: log.info('Webhook enabled for events: sending %s to %s.', args.wh_types, args.webhooks) # 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, wh_key_cache)) t.daemon = True t.start() if not args.only_server: # Speed limit. log.info( 'Scanning speed limit %s.', 'set to {} km/h'.format(args.kph) if args.kph > 0 else 'disabled') log.info( 'High-level speed limit %s.', 'set to {} km/h'.format( args.hlvl_kph) if args.hlvl_kph > 0 else 'disabled') # Check if we are able to scan. if not can_start_scanning(args): sys.exit(1) initialize_proxies(args) # Monitor files, update data if they've changed recently. # Keys are 'args' object keys, values are filenames to load. files_to_monitor = {} if args.encounter: files_to_monitor['enc_whitelist'] = args.enc_whitelist_file log.info('Encounters are enabled.') else: log.info('Encounters are disabled.') if args.webhook_blacklist_file: files_to_monitor['webhook_blacklist'] = args.webhook_blacklist_file log.info('Webhook blacklist is enabled.') elif args.webhook_whitelist_file: files_to_monitor['webhook_whitelist'] = args.webhook_whitelist_file log.info('Webhook whitelist is enabled.') else: log.info('Webhook whitelist/blacklist is disabled.') if files_to_monitor: t = Thread(target=dynamic_loading_refresher, name='dynamic-enclist', args=(files_to_monitor, )) t.daemon = True t.start() log.info('Dynamic list refresher is enabled.') else: log.info('Dynamic list refresher is disabled.') # Update player locale if not set correctly yet. args.player_locale = PlayerLocale.get_locale(args.location) if not args.player_locale: args.player_locale = gmaps_reverse_geolocate( args.gmaps_key, args.locale, str(position[0]) + ', ' + str(position[1])) db_player_locale = { 'location': args.location, 'country': args.player_locale['country'], 'language': args.player_locale['country'], 'timezone': args.player_locale['timezone'], } db_updates_queue.put((PlayerLocale, {0: db_player_locale})) else: log.debug('Existing player locale has been retrieved from the DB.') # Gather the Pokemon! argset = (args, new_location_queue, control_flags, heartbeat, db_updates_queue, wh_updates_queue) log.debug('Starting a %s search thread', args.scheduler) search_thread = Thread(target=search_overseer_thread, name='search-overseer', args=argset) search_thread.daemon = True search_thread.start() 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: if args.cors: CORS(app) # No more stale JS. init_cache_busting(app) app.set_control_flags(control_flags) app.set_heartbeat_control(heartbeat) app.set_location_queue(new_location_queue) 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.') if args.verbose: app.run(threaded=True, use_reloader=False, debug=True, host=args.host, port=args.port, ssl_context=ssl_context) else: app.run(threaded=True, use_reloader=False, debug=False, host=args.host, port=args.port, ssl_context=ssl_context)
def main(): # Patch threading to make exceptions catchable. install_thread_excepthook() # Make sure exceptions get logged. sys.excepthook = handle_exception args = get_args() init_mr_mime(config_file='config/mrmime_config.json') # Add file logging if enabled. if args.verbose and args.verbose != 'nofile': filelog = logging.FileHandler(args.verbose) filelog.setFormatter( logging.Formatter( '%(asctime)s [%(threadName)16s][%(module)14s][%(levelname)8s] ' + '%(message)s')) logging.getLogger('').addHandler(filelog) if args.very_verbose and args.very_verbose != 'nofile': filelog = logging.FileHandler(args.very_verbose) filelog.setFormatter( logging.Formatter( '%(asctime)s [%(threadName)16s][%(module)14s][%(levelname)8s] ' + '%(message)s')) logging.getLogger('').addHandler(filelog) if args.verbose or args.very_verbose: 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: root_path = os.path.dirname(__file__) if not os.path.exists(os.path.join(root_path, 'static/dist')): log.critical( 'Missing front-end assets (static/dist) -- please run ' + '"npm install && npm run build" before starting the server.') sys.exit() # You need custom image files now. if not os.path.isfile( os.path.join(root_path, 'static/icons-sprite.png')): log.info('Sprite files not present, extracting bundled ones...') extract_sprites(root_path) log.info('Done!') # Check if custom.css is used otherwise fall back to default. if os.path.exists(os.path.join(root_path, 'static/css/custom.css')): args.custom_css = True log.info( 'File \"custom.css\" found, applying user-defined settings.') else: args.custom_css = False log.info('No file \"custom.css\" found, using default settings.') # These are very noisy, 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.verbose or args.very_verbose: logging.getLogger('pgoapi').setLevel(logging.DEBUG) if args.very_verbose: logging.getLogger('peewee').setLevel(logging.DEBUG) logging.getLogger('requests').setLevel(logging.DEBUG) logging.getLogger('pgoapi.pgoapi').setLevel(logging.DEBUG) logging.getLogger('pgoapi.rpc_api').setLevel(logging.DEBUG) logging.getLogger('rpc_api').setLevel(logging.DEBUG) logging.getLogger('werkzeug').setLevel(logging.DEBUG) # Web access logs. if args.access_logs: logger = logging.getLogger('werkzeug') handler = logging.FileHandler('access.log') logger.setLevel(logging.INFO) logger.addHandler(handler) # 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) if position is None or not any(position): log.error("Location not found: '{}'".format(args.location)) sys.exit() # Use the latitude and longitude to get the local altitude from Google. (altitude, status) = get_gmaps_altitude(position[0], position[1], args.gmaps_key) if altitude is not None: log.debug('Local altitude is: %sm', altitude) position = (position[0], position[1], altitude) else: if status == 'REQUEST_DENIED': log.error( 'Google API Elevation request was denied. You probably ' + 'forgot to enable elevation api in https://console.' + 'developers.google.com/apis/api/elevation_backend/') sys.exit() else: log.error('Unable to retrieve altitude from Google APIs' + 'setting to 0') 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.') if args.encounter: log.info('Encountering pokemon enabled.') config['LOCALE'] = args.locale config['CHINA'] = args.china # if we're clearing the db, do not bother with the blacklist if args.clear_db: args.disable_blacklist = True app = Pogom(__name__) app.before_request(app.validate_request) 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) verify_database_schema(db) create_tables(db) # fixing encoding on present and future tables verify_table_encoding(db) if args.clear_db: log.info("Drop and recreate is complete. Now remove -cd and restart.") sys.exit() app.set_current_location(position) # Control the search status (running or not) across threads. pause_bit = Event() pause_bit.clear() if args.on_demand_timeout > 0: pause_bit.set() heartbeat = [now()] # Setup the location tracking queue and push the first location on. new_location_queue = Queue() new_location_queue.put(position) # DB Updates db_updates_queue = Queue() app.set_db_updates_queue(db_updates_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, db)) t.daemon = True t.start() # db cleaner; really only need one ever. if not args.disable_clean: t = Thread(target=clean_db_loop, name='db-cleaner', args=(args, )) t.daemon = True t.start() # WH updates queue & WH unique key LFU caches. # The LFU caches will stop the server from resending the same data an # infinite number of times. The caches will be instantiated in the # webhook's startup code. wh_updates_queue = Queue() wh_key_cache = {} app.set_wh_updates_queue(wh_updates_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, wh_key_cache)) t.daemon = True t.start() config['ROOT_PATH'] = app.root_path config['GMAPS_KEY'] = args.gmaps_key if not args.only_server: # Abort if we don't have a hash key set if not args.hash_key: log.critical('Hash key is required for scanning. Exiting.') sys.exit() # Processing proxies if set (load from file, check and overwrite old # args.proxy with new working list) args.proxy = check_proxies(args) # Run periodical proxy refresh thread if (args.proxy_file is not None) and (args.proxy_refresh > 0): t = Thread(target=proxies_refresher, name='proxy-refresh', args=(args, )) t.daemon = True t.start() else: log.info('Periodical proxies refresh disabled.') # Find the reverse geolocation geolocator = GoogleV3(api_key=args.gmaps_key) args.player_locale = { 'country': 'US', 'language': args.locale, 'timezone': 'America/Denver' } try: location = geolocator.reverse(args.location) country = location[-1].raw['address_components'][-1]['short_name'] try: timezone = geolocator.timezone(args.location) args.player_locale.update({ 'country': country, 'timezone': str(timezone) }) except Exception as e: log.warning( 'Exception while obtaining Google Timezone. ' + 'Key probably not enabled: %s.', repr(e)) pass except Exception as e: log.warning('Exception while obtaining player locale: %s.', repr(e)) pass # Gather the Pokemon! # Attempt to dump the spawn points (do this before starting threads of # endure the woe). if (args.spawnpoint_scanning and args.spawnpoint_scanning != 'nofile' and args.dump_spawnpoints): with open(args.spawnpoint_scanning, 'w+') as file: log.info('Saving spawn points to %s', args.spawnpoint_scanning) spawns = Pokemon.get_spawnpoints_in_hex( position, args.step_limit) file.write(json.dumps(spawns)) log.info('Finished exporting spawn points') argset = (args, new_location_queue, pause_bit, heartbeat, db_updates_queue, wh_updates_queue) log.debug('Starting a %s search thread', args.scheduler) search_thread = Thread(target=search_overseer_thread, name='search-overseer', args=argset) search_thread.daemon = True search_thread.start() if args.cors: CORS(app) # No more stale JS. init_cache_busting(app) app.set_search_control(pause_bit) app.set_heartbeat_control(heartbeat) app.set_location_queue(new_location_queue) 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.') if args.verbose or args.very_verbose: app.run(threaded=True, use_reloader=False, debug=True, host=args.host, port=args.port, ssl_context=ssl_context) else: app.run(threaded=True, use_reloader=False, debug=False, host=args.host, port=args.port, ssl_context=ssl_context)
from pogom.proxy import initialize_proxies from pogom.search import search_overseer_thread from time import strftime class LogFilter(logging.Filter): def __init__(self, level): self.level = level def filter(self, record): return record.levelno < self.level # Moved here so logger is configured at load time. console = logging.StreamHandler() args = get_args() if not (args.verbose): console.setLevel(logging.INFO) formatter = ColoredFormatter( #'%(asctime)s [%(threadName)16s][%(levelname)8s] %(message)s', '%(log_color)s [%(asctime)s] [%(threadName)16s] [%(module)14s] [%(levelname)8s] %(message)s', datefmt='%m-%d %H:%M:%S', reset=True, log_colors={ 'DEBUG': 'purple', 'INFO': 'cyan', 'WARNING': 'yellow', 'ERROR': 'red', 'CRITICAL': 'red,bg_white', },
def main(): # Patch threading to make exceptions catchable. install_thread_excepthook() # Make sure exceptions get logged. sys.excepthook = handle_exception args = get_args() # Add file logging if enabled. if args.verbose and args.verbose != 'nofile': filelog = logging.FileHandler(args.verbose) filelog.setFormatter(logging.Formatter( '%(asctime)s [%(threadName)16s][%(module)14s][%(levelname)8s] ' + '%(message)s')) logging.getLogger('').addHandler(filelog) if args.very_verbose and args.very_verbose != 'nofile': filelog = logging.FileHandler(args.very_verbose) filelog.setFormatter(logging.Formatter( '%(asctime)s [%(threadName)16s][%(module)14s][%(levelname)8s] ' + '%(message)s')) logging.getLogger('').addHandler(filelog) if args.verbose or args.very_verbose: 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 and not validate_assets(args): sys.exit(1) # These are very noisy, 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 config['parse_raids'] = not args.no_raids # Turn these back up if debugging. if args.verbose or args.very_verbose: logging.getLogger('pgoapi').setLevel(logging.DEBUG) if args.very_verbose: logging.getLogger('peewee').setLevel(logging.DEBUG) logging.getLogger('requests').setLevel(logging.DEBUG) logging.getLogger('pgoapi.pgoapi').setLevel(logging.DEBUG) logging.getLogger('pgoapi.rpc_api').setLevel(logging.DEBUG) logging.getLogger('rpc_api').setLevel(logging.DEBUG) logging.getLogger('werkzeug').setLevel(logging.DEBUG) # Web access logs. if args.access_logs: logger = logging.getLogger('werkzeug') handler = logging.FileHandler('access.log') logger.setLevel(logging.INFO) logger.addHandler(handler) # 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) if position is None or not any(position): log.error("Location not found: '{}'".format(args.location)) sys.exit() # Use the latitude and longitude to get the local altitude from Google. (altitude, status) = get_gmaps_altitude(position[0], position[1], args.gmaps_key) if altitude is not None: log.debug('Local altitude is: %sm', altitude) position = (position[0], position[1], altitude) else: if status == 'REQUEST_DENIED': log.error( 'Google API Elevation request was denied. You probably ' + 'forgot to enable elevation api in https://console.' + 'developers.google.com/apis/api/elevation_backend/') sys.exit() else: log.error('Unable to retrieve altitude from Google APIs' + 'setting to 0') 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.') if args.encounter: log.info('Encountering pokemon enabled.') config['LOCALE'] = args.locale config['CHINA'] = args.china # if we're clearing the db, do not bother with the blacklist if args.clear_db: args.disable_blacklist = True app = Pogom(__name__) app.before_request(app.validate_request) 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) verify_database_schema(db) create_tables(db) # fixing encoding on present and future tables verify_table_encoding(db) if args.clear_db: log.info("Drop and recreate is complete. Now remove -cd and restart.") sys.exit() app.set_current_location(position) # Control the search status (running or not) across threads. control_flags = { 'on_demand': Event(), 'api_watchdog': Event(), 'search_control': Event() } for flag in control_flags.values(): flag.clear() if args.on_demand_timeout > 0: control_flags['on_demand'].set() heartbeat = [now()] # Setup the location tracking queue and push the first location on. new_location_queue = Queue() new_location_queue.put(position) # 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, db)) t.daemon = True t.start() # db cleaner; really only need one ever. if not args.disable_clean: t = Thread(target=clean_db_loop, name='db-cleaner', args=(args,)) t.daemon = True t.start() # WH updates queue & WH unique key LFU caches. # The LFU caches will stop the server from resending the same data an # infinite number of times. The caches will be instantiated in the # webhook's startup code. wh_updates_queue = Queue() wh_key_cache = {} # 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, wh_key_cache)) t.daemon = True t.start() config['ROOT_PATH'] = app.root_path config['GMAPS_KEY'] = args.gmaps_key if not args.only_server: # Check if we are able to scan. if not can_start_scanning(args): sys.exit(1) # Processing proxies if set (load from file, check and overwrite old # args.proxy with new working list). args.proxy = load_proxies(args) if args.proxy and not args.proxy_skip_check: args.proxy = check_proxies(args, args.proxy) # Run periodical proxy refresh thread. if (args.proxy_file is not None) and (args.proxy_refresh > 0): t = Thread(target=proxies_refresher, name='proxy-refresh', args=(args,)) t.daemon = True t.start() else: log.info('Periodical proxies refresh disabled.') # Update player locale if not set correctly, yet. args.player_locale = PlayerLocale.get_locale(args.location) if not args.player_locale: args.player_locale = gmaps_reverse_geolocate( args.gmaps_key, args.locale, str(position[0]) + ', ' + str(position[1])) db_player_locale = { 'location': args.location, 'country': args.player_locale['country'], 'language': args.player_locale['country'], 'timezone': args.player_locale['timezone'], } db_updates_queue.put((PlayerLocale, {0: db_player_locale})) else: log.debug('Existing player locale has been retrieved from the DB.') # Gather the Pokemon! # Attempt to dump the spawn points (do this before starting threads of # endure the woe). if (args.spawnpoint_scanning and args.spawnpoint_scanning != 'nofile' and args.dump_spawnpoints): with open(args.spawnpoint_scanning, 'w+') as file: log.info('Saving spawn points to %s', args.spawnpoint_scanning) spawns = SpawnPoint.get_spawnpoints_in_hex( position, args.step_limit) file.write(json.dumps(spawns)) log.info('Finished exporting spawn points') argset = (args, new_location_queue, control_flags, heartbeat, db_updates_queue, wh_updates_queue) log.debug('Starting a %s search thread', args.scheduler) search_thread = Thread(target=search_overseer_thread, name='search-overseer', args=argset) search_thread.daemon = True search_thread.start() if args.cors: CORS(app) # No more stale JS. init_cache_busting(app) app.set_search_control(control_flags['search_control']) app.set_heartbeat_control(heartbeat) app.set_location_queue(new_location_queue) 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.') if args.verbose or args.very_verbose: app.run(threaded=True, use_reloader=False, debug=True, host=args.host, port=args.port, ssl_context=ssl_context) else: app.run(threaded=True, use_reloader=False, debug=False, host=args.host, port=args.port, ssl_context=ssl_context)
search_thread = Thread(target=search_loop, args=(args,)) search_thread.daemon = True search_thread.name = 'search_thread' search_thread.start() if __name__ == '__main__': logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(module)11s] [%(levelname)7s] %(message)s') logging.getLogger("peewee").setLevel(logging.INFO) logging.getLogger("requests").setLevel(logging.WARNING) logging.getLogger("pogom.pgoapi.pgoapi").setLevel(logging.WARNING) logging.getLogger("pogom.pgoapi.rpc_api").setLevel(logging.INFO) logging.getLogger('werkzeug').setLevel(logging.ERROR) args = get_args() config['parse_pokemon'] = not args.no_pokemon config['parse_pokestops'] = not args.no_pokestops config['parse_gyms'] = not args.no_gyms if args.debug: logging.getLogger("requests").setLevel(logging.DEBUG) logging.getLogger("pgoapi").setLevel(logging.DEBUG) logging.getLogger("rpc_api").setLevel(logging.DEBUG) db = init_database() create_tables(db) position = get_pos_by_name(args.location) if not any(position):
def main(): # Patch threading to make exceptions catchable. install_thread_excepthook() # Make sure exceptions get logged. sys.excepthook = handle_exception args = get_args() # Add file logging if enabled. if args.verbose and args.verbose != 'nofile': filelog = logging.FileHandler(args.verbose) filelog.setFormatter( logging.Formatter( '%(asctime)s [%(threadName)16s][%(module)14s][%(levelname)8s] ' + '%(message)s')) logging.getLogger('').addHandler(filelog) if args.very_verbose and args.very_verbose != 'nofile': filelog = logging.FileHandler(args.very_verbose) filelog.setFormatter( logging.Formatter( '%(asctime)s [%(threadName)16s][%(module)14s][%(levelname)8s] ' + '%(message)s')) logging.getLogger('').addHandler(filelog) if args.verbose or args.very_verbose: 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() # You need custom image files now. if not os.path.isfile( os.path.join(os.path.dirname(__file__), 'static/icons-sprite.png')): log.info('Sprite files not present, extracting bundled ones...') extract_sprites() log.info('Done!') # Beehive configuration beehive_workers = [args.workers] if args.beehive > 0: beehive_size = 1 # Calculate number of hives required ( -bh 2 => i:1, i:2 ) for i in range(1, args.beehive + 1): beehive_size += i * 6 # Initialize worker distribution list beehive_workers = [0 for x in range(beehive_size)] skip_indexes = [] hives_ignored = 0 workers_forced = 0 log.debug('-bhw --beehive-workers: %s', args.beehive_workers) # Parse beehive configuration for i in range(0, len(args.beehive_workers)): bhw = args.beehive_workers[i].split(':') bhw_index = int(bhw[0]) bhw_workers = int(bhw[1]) if (bhw_index >= 0) and (bhw_index < beehive_size): if bhw_index in skip_indexes: log.warning( 'Duplicate hive index found in -bhw ' + '--beehive-workers: %d', bhw_index) continue if bhw_workers <= 0: skip_indexes.append(bhw_index) beehive_workers[bhw_index] = 0 hives_ignored += 1 else: skip_indexes.append(bhw_index) beehive_workers[bhw_index] = bhw_workers workers_forced += bhw_workers else: log.warning( 'Invalid hive index found in -bhw ' + '--beehive-workers: %d', bhw_index) # Check if we have enough workers for beehive setup. workers_required = workers_forced if args.workers_per_hive > 0: count = beehive_size - len(skip_indexes) workers_required += count * args.workers_per_hive log.info( 'Beehive size: %d (%d hives ignored). Workers forced: ' + '%d. Workers required: %d', beehive_size, hives_ignored, workers_forced, workers_required) if args.workers < workers_required: log.critical('Not enough workers to fill the beehive. ' + 'Increase -w --workers, decrease -bh --beehive ' + 'or decrease -wph --workers-per-hive') sys.exit() # Assign remaining workers to available hives. remaining_workers = args.workers - workers_forced populate_index = 0 while remaining_workers > 0: beehive_index = populate_index % beehive_size if beehive_index in skip_indexes: populate_index += 1 continue beehive_workers[beehive_index] += 1 populate_index += 1 remaining_workers -= 1 log.debug('Beehive worker distribution: %s', beehive_workers) # These are very noisy, 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.verbose or args.very_verbose: logging.getLogger('pgoapi').setLevel(logging.DEBUG) if args.very_verbose: logging.getLogger('peewee').setLevel(logging.DEBUG) logging.getLogger('requests').setLevel(logging.DEBUG) logging.getLogger('pgoapi.pgoapi').setLevel(logging.DEBUG) logging.getLogger('pgoapi.rpc_api').setLevel(logging.DEBUG) logging.getLogger('rpc_api').setLevel(logging.DEBUG) logging.getLogger('werkzeug').setLevel(logging.DEBUG) # Web access logs. if args.access_logs: logger = logging.getLogger('werkzeug') handler = logging.FileHandler('access.log') logger.setLevel(logging.INFO) logger.addHandler(handler) # 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) if position is None or not any(position): log.error("Location not found: '{}'".format(args.location)) sys.exit() # Use the latitude and longitude to get the local altitude from Google. (altitude, status) = get_gmaps_altitude(position[0], position[1], args.gmaps_key) if altitude is not None: log.debug('Local altitude is: %sm', altitude) position = (position[0], position[1], altitude) else: if status == 'REQUEST_DENIED': log.error( 'Google API Elevation request was denied. You probably ' + 'forgot to enable elevation api in https://console.' + 'developers.google.com/apis/api/elevation_backend/') sys.exit() else: log.error('Unable to retrieve altitude from Google APIs' + 'setting to 0') 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.') if args.encounter: log.info('Encountering pokemon enabled.') config['LOCALE'] = args.locale config['CHINA'] = args.china # if we're clearing the db, do not bother with the blacklist if args.clear_db: args.disable_blacklist = True app = Pogom(__name__) app.before_request(app.validate_request) 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) if args.clear_db: log.info("Drop and recreate is complete. Now remove -cd and restart.") sys.exit() app.set_current_location(position) # Control the search status (running or not) across threads. pause_bit = Event() pause_bit.clear() if args.on_demand_timeout > 0: pause_bit.set() heartbeat = [now()] # Setup the location tracking queue and push the first location on. new_location_queue = Queue() new_location_queue.put(position) # DB Updates db_updates_queue = Queue() app.set_db_updates_queue(db_updates_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, db)) t.daemon = True t.start() # db cleaner; really only need one ever. if not args.disable_clean: t = Thread(target=clean_db_loop, name='db-cleaner', args=(args, )) t.daemon = True t.start() # WH updates queue & WH unique key LFU caches. # The LFU caches will stop the server from resending the same data an # infinite number of times. The caches will be instantiated in the # webhook's startup code. wh_updates_queue = Queue() wh_key_cache = {} app.set_wh_updates_queue(wh_updates_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, wh_key_cache)) t.daemon = True t.start() if not args.only_server: # Abort if we don't have a hash key set if not args.hash_key: log.critical('Hash key is required for scanning. Exiting.') sys.exit() # Processing proxies if set (load from file, check and overwrite old # args.proxy with new working list) args.proxy = check_proxies(args) # Run periodical proxy refresh thread if (args.proxy_file is not None) and (args.proxy_refresh > 0): t = Thread(target=proxies_refresher, name='proxy-refresh', args=(args, )) t.daemon = True t.start() else: log.info('Periodical proxies refresh disabled.') # Gather the Pokemon! # Attempt to dump the spawn points (do this before starting threads of # endure the woe). if (args.spawnpoint_scanning and args.spawnpoint_scanning != 'nofile' and args.dump_spawnpoints): with open(args.spawnpoint_scanning, 'w+') as file: log.info('Saving spawn points to %s', args.spawnpoint_scanning) spawns = Pokemon.get_spawnpoints_in_hex( position, args.step_limit) file.write(json.dumps(spawns)) log.info('Finished exporting spawn points') argset = (args, beehive_workers, new_location_queue, pause_bit, heartbeat, db_updates_queue, wh_updates_queue) log.debug('Starting a %s search thread', args.scheduler) search_thread = Thread(target=search_overseer_thread, name='search-overseer', args=argset) search_thread.daemon = True search_thread.start() if args.cors: CORS(app) # No more stale JS. init_cache_busting(app) app.set_search_control(pause_bit) app.set_heartbeat_control(heartbeat) app.set_location_queue(new_location_queue) 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.') if args.verbose or args.very_verbose: app.run(threaded=True, use_reloader=False, debug=True, host=args.host, port=args.port, ssl_context=ssl_context) else: app.run(threaded=True, use_reloader=False, debug=False, host=args.host, port=args.port, ssl_context=ssl_context)