def __init__(self, args, id, last_known_state, websocket_handler, route_manager_daytime, route_manager_nighttime, devicesettings, db_wrapper, NoOcr=False): # self.thread_pool = ThreadPool(processes=2) self._route_manager_daytime = route_manager_daytime self._route_manager_nighttime = route_manager_nighttime self._websocket_handler = websocket_handler self._communicator = Communicator(websocket_handler, id, args.websocket_command_timeout) self._id = id self._applicationArgs = args self._last_known_state = last_known_state self._lastScreenshotTaken = 0 self._stop_worker_event = Event() self._db_wrapper = db_wrapper self._redErrorCount = 0 self._lastScreenHash = None self._lastScreenHashCount = 0 self._devicesettings = devicesettings if not NoOcr: from ocr.pogoWindows import PogoWindows self._pogoWindowManager = PogoWindows(self._communicator, args.temp_path)
def __init__(self, args, id, last_known_state, websocket_handler, route_manager_daytime, route_manager_nighttime, devicesettings, db_wrapper, timer, NoOcr=False): # self.thread_pool = ThreadPool(processes=2) self._route_manager_daytime = route_manager_daytime self._route_manager_nighttime = route_manager_nighttime self._websocket_handler = websocket_handler self._communicator = Communicator(websocket_handler, id, args.websocket_command_timeout) self._id = id self._applicationArgs = args self._last_known_state = last_known_state self._work_mutex = Lock() self.loop = None self.loop_started = Event() self.loop_tid = None self._async_io_looper_thread = None self._location_count = 0 self._timer = timer self._lastScreenshotTaken = 0 self._stop_worker_event = Event() self._db_wrapper = db_wrapper self._redErrorCount = 0 self._lastScreenHash = None self._lastScreenHashCount = 0 self._devicesettings = devicesettings self._resocalc = Resocalculator self._screen_x = 0 self._screen_y = 0 self._lastStart = "" self.current_location = self._last_known_state.get( "last_location", None) if self.current_location is None: self.current_location = Location(0.0, 0.0) self.last_location = Location(0.0, 0.0) self.last_processed_location = Location(0.0, 0.0) if not NoOcr: from ocr.pogoWindows import PogoWindows self._pogoWindowManager = PogoWindows(self._communicator, args.temp_path)
def __init__(self, args, id, last_known_state, websocket_handler, route_manager_daytime, route_manager_nighttime, devicesettings, db_wrapper, timer, mitm_mapper, NoOcr=False): WorkerBase.__init__(self, args, id, last_known_state, websocket_handler, route_manager_daytime, route_manager_nighttime, devicesettings, db_wrapper=db_wrapper, NoOcr=True, timer=timer) self._reboot_count = 0 self._restart_count = 0 self._rec_data_time = "" self._mitm_mapper = mitm_mapper if not NoOcr: from ocr.pogoWindows import PogoWindows self._pogoWindowManager = PogoWindows(self._communicator, args.temp_path)
else: if args.only_routes: logger.info("Done calculating routes!") # TODO: shutdown managers properly... sys.exit(0) pogoWindowManager = None jobstatus: dict = {} MitmMapperManager.register('MitmMapper', MitmMapper) mitm_mapper_manager = MitmMapperManager() mitm_mapper_manager.start() mitm_mapper: MitmMapper = mitm_mapper_manager.MitmMapper( mapping_manager, db_wrapper) from ocr.pogoWindows import PogoWindows pogoWindowManager = PogoWindows(args.temp_path, args.ocr_thread_count) mitm_receiver_process = MITMReceiver(args.mitmreceiver_ip, int(args.mitmreceiver_port), mitm_mapper, args, mapping_manager, db_wrapper) mitm_receiver_process.start() logger.info('Starting websocket server on port {}'.format( str(args.ws_port))) ws_server = WebsocketServer(args, mitm_mapper, db_wrapper, mapping_manager, pogoWindowManager) t_ws = Thread(name='scanner', target=ws_server.start_server) t_ws.daemon = False t_ws.start()
dbWrapper = DbWrapper(str(args.db_method), str(args.dbip), args.dbport, args.dbusername, args.dbpassword, args.dbname, args.timezone) if not args.only_ocr and not args.with_madmin: log.info("Starting Telnet MORE Client") telnMore = TelnetMore(str(args.tel_ip), args.tel_port, str(args.tel_password), args.tel_timeout_command, args.tel_timeout_socket) log.info("Starting ScreenWrapper") screenWrapper = ScreenWrapper(args.screen_method, telnMore, str(args.vnc_ip), args.vnc_port, args.vnc_password, args.vncscreen) log.info("Starting pogo window manager") pogoWindowManager = PogoWindows(screenWrapper, args.screen_width, args.screen_height, args.temp_path) def main(): global dbWrapper log.info("Starting TheRaidMap") sys.excepthook = handle_exception log.info("Parsing arguments") args = parseArgs() set_log_and_verbosity(log) dbWrapper.createHashDatabaseIfNotExists() if args.clean_hash_database: log.info('Cleanup Hash Database and www_hash folder') dbWrapper.deleteHashTable('999', '')
class WorkerBase(ABC): def __init__(self, args, id, last_known_state, websocket_handler, route_manager_daytime, route_manager_nighttime, devicesettings, db_wrapper, timer, NoOcr=False): # self.thread_pool = ThreadPool(processes=2) self._route_manager_daytime = route_manager_daytime self._route_manager_nighttime = route_manager_nighttime self._websocket_handler = websocket_handler self._communicator = Communicator(websocket_handler, id, args.websocket_command_timeout) self._id = id self._applicationArgs = args self._last_known_state = last_known_state self._work_mutex = Lock() self.loop = None self.loop_started = Event() self.loop_tid = None self._async_io_looper_thread = None self._location_count = 0 self._timer = timer self._lastScreenshotTaken = 0 self._stop_worker_event = Event() self._db_wrapper = db_wrapper self._redErrorCount = 0 self._lastScreenHash = None self._lastScreenHashCount = 0 self._devicesettings = devicesettings self._resocalc = Resocalculator self._screen_x = 0 self._screen_y = 0 self._lastStart = "" self.current_location = self._last_known_state.get( "last_location", None) if self.current_location is None: self.current_location = Location(0.0, 0.0) self.last_location = Location(0.0, 0.0) self.last_processed_location = Location(0.0, 0.0) if not NoOcr: from ocr.pogoWindows import PogoWindows self._pogoWindowManager = PogoWindows(self._communicator, args.temp_path) @abstractmethod def _pre_work_loop(self): """ Work to be done before the main while true work-loop Start off asyncio loops etc in here :return: """ pass @abstractmethod def _health_check(self): """ Health check before a location is grabbed. Internally, a self._start_pogo call is already executed since that usually includes a topmost check :return: """ pass @abstractmethod def _pre_location_update(self): """ Override to run stuff like update injections settings in MITM worker Runs before walk/teleport to the location previously grabbed :return: """ pass @abstractmethod def _move_to_location(self): """ Location has previously been grabbed, the overriden function will be called. You may teleport or walk by your choosing Any post walk/teleport delays/sleeps have to be run in the derived, override method :return: """ pass @abstractmethod def _post_move_location_routine(self, timestamp): """ Routine called after having moved to a new location. MITM worker e.g. has to wait_for_data :param timestamp: :return: """ @abstractmethod def _start_pogo(self): """ Routine to start pogo. Return the state as a boolean do indicate a successful start :return: """ pass @abstractmethod def _cleanup(self): """ Cleanup any threads you started in derived classes etc self.stop_worker() and self.loop.stop() will be called afterwards :return: """ @abstractmethod def _valid_modes(self): """ Return a list of valid modes for the health checks :return: """ def _start_asyncio_loop(self): self.loop = asyncio.new_event_loop() asyncio.set_event_loop(self.loop) self.loop_tid = current_thread() self.loop.call_soon(self.loop_started.set) self.loop.run_forever() def _add_task_to_loop(self, coro): f = functools.partial(self.loop.create_task, coro) if current_thread() == self.loop_tid: return f( ) # We can call directly if we're not going between threads. else: # We're in a non-event loop thread so we use a Future # to get the task from the event loop thread once # it's ready. return self.loop.call_soon_threadsafe(f) def start_worker(self): # async_result = self.thread_pool.apply_async(self._main_work_thread, ()) t_main_work = Thread(target=self._main_work_thread) t_main_work.daemon = False t_main_work.start() # do some other stuff in the main process while not self._stop_worker_event.isSet(): time.sleep(1) t_main_work.join() log.info("Worker %s stopping gracefully" % str(self._id)) # async_result.get() return self._last_known_state def stop_worker(self): self._stop_worker_event.set() log.warning("Worker %s stop called" % str(self._id)) def _internal_pre_work(self): current_thread().name = self._id self._work_mutex.acquire() try: self._turn_screen_on_and_start_pogo() except WebsocketWorkerRemovedException: log.error("Timeout during init of worker %s" % str(self._id)) # no cleanup required here? TODO: signal websocket server somehow self._stop_worker_event.set() return self._work_mutex.release() self._async_io_looper_thread = Thread(name=str(self._id) + '_asyncio_' + self._id, target=self._start_asyncio_loop) self._async_io_looper_thread.daemon = False self._async_io_looper_thread.start() self.loop_started.wait() self._pre_work_loop() def _internal_health_check(self): # check if pogo is topmost and start if necessary log.debug( "_internal_health_check: Calling _start_pogo routine to check if pogo is topmost" ) self._work_mutex.acquire() log.debug("_internal_health_check: worker lock acquired") log.debug("Checking if we need to restart pogo") # Restart pogo every now and then... if self._devicesettings.get("restart_pogo", 80) > 0: # log.debug("main: Current time - lastPogoRestart: %s" % str(curTime - lastPogoRestart)) # if curTime - lastPogoRestart >= (args.restart_pogo * 60): if self._location_count > self._devicesettings.get( "restart_pogo", 80): log.error("scanned " + str(self._devicesettings.get("restart_pogo", 80)) + " locations, restarting pogo") pogo_started = self._restart_pogo() self._location_count = 0 else: pogo_started = self._start_pogo() else: pogo_started = self._start_pogo() self._work_mutex.release() log.debug("_internal_health_check: worker lock released") return pogo_started def _internal_cleanup(self): # set the event just to make sure - in case of exceptions for example self._stop_worker_event.set() log.info("Internal cleanup of %s started" % str(self._id)) self._cleanup() log.info("Internal cleanup of %s signalling end to websocketserver" % str(self._id)) self._communicator.cleanup_websocket() # self.stop_worker() if self._async_io_looper_thread is not None: log.info("Stopping worker's asyncio loop") self.loop.call_soon_threadsafe(self.loop.stop) self._async_io_looper_thread.join() if self._timer is not None: log.info("Stopping switch timer") self._timer.stop_switch() log.info("Internal cleanup of %s finished" % str(self._id)) def _main_work_thread(self): # TODO: signal websocketserver the removal try: self._internal_pre_work() except (InternalStopWorkerException, WebsocketWorkerRemovedException, WebsocketWorkerTimeoutException) \ as e: log.error( "Failed initializing worker %s, connection terminated exceptionally" % str(self._id)) return while not self._stop_worker_event.isSet(): while self._timer.get_switch( ) and self._route_manager_nighttime is None: time.sleep(1) # check if stop_worker_event is set again since sleep may have taken ages ;) if self._stop_worker_event.is_set(): break try: # TODO: consider getting results of health checks and aborting the entire worker? self._internal_health_check() self._health_check() except (InternalStopWorkerException, WebsocketWorkerRemovedException, WebsocketWorkerTimeoutException) \ as e: log.error( "Websocket connection to %s lost while running healthchecks, " "connection terminated exceptionally" % str(self._id)) break try: settings = self._internal_grab_next_location() if settings is None and self._timer.get_switch(): continue except (InternalStopWorkerException, WebsocketWorkerRemovedException, WebsocketWorkerTimeoutException) \ as e: log.warning( "Worker of %s does not support mode that's to be run, " "connection terminated exceptionally" % str(self._id)) break try: log.debug('Checking if new location is valid') valid = self._check_location_is_valid() if not valid: break except (InternalStopWorkerException, WebsocketWorkerRemovedException, WebsocketWorkerTimeoutException) \ as e: log.warning("Worker %s get non valid coords!" % str(self._id)) break try: self._pre_location_update() except (InternalStopWorkerException, WebsocketWorkerRemovedException, WebsocketWorkerTimeoutException) \ as e: log.warning( "Worker of %s stopping because of stop signal in pre_location_update, " "connection terminated exceptionally" % str(self._id)) break self._add_task_to_loop(self._update_position_file()) try: log.debug( 'main worker %s: LastLat: %s, LastLng: %s, CurLat: %s, CurLng: %s' % (str(self._id), self.last_location.lat, self.last_location.lng, self.current_location.lat, self.current_location.lng)) time_snapshot, process_location = self._move_to_location() except (InternalStopWorkerException, WebsocketWorkerRemovedException, WebsocketWorkerTimeoutException) \ as e: log.warning( "Worker %s failed moving to new location, stopping worker, " "connection terminated exceptionally" % str(self._id)) break if process_location: self._location_count += 1 if self._applicationArgs.last_scanned: log.info('main: Set new scannedlocation in Database') # self.update_scanned_location(currentLocation.lat, currentLocation.lng, curTime) self._add_task_to_loop( self.update_scanned_location(self.current_location.lat, self.current_location.lng, time_snapshot)) try: self._post_move_location_routine(time_snapshot) except (InternalStopWorkerException, WebsocketWorkerRemovedException, WebsocketWorkerTimeoutException) \ as e: log.warning( "Worker %s failed running post_move_location_routine, stopping worker" % str(self._id)) break log.info("Worker %s finished iteration, continuing work" % str(self._id)) self._internal_cleanup() async def _update_position_file(self): log.debug("Updating .position file") if self.current_location is not None: with open(self._id + '.position', 'w') as outfile: outfile.write( str(self.current_location.lat) + ", " + str(self.current_location.lng)) async def update_scanned_location(self, latitude, longitude, timestamp): try: self._db_wrapper.set_scanned_location(str(latitude), str(longitude), str(timestamp)) except Exception as e: log.error("Failed updating scanned location: %s" % str(e)) return def _get_currently_valid_routemanager(self): valid_modes = self._valid_modes() switch_mode = self._timer.get_switch() if (switch_mode and self._route_manager_nighttime is not None and self._route_manager_nighttime.mode in valid_modes): return self._route_manager_nighttime elif switch_mode is True and self._route_manager_nighttime is None: return None elif not switch_mode and self._route_manager_daytime.mode in valid_modes: return self._route_manager_daytime else: # log.fatal("Raising internal worker exception") raise InternalStopWorkerException def _internal_grab_next_location(self): # TODO: consider adding runWarningThreadEvent.set() self.last_location = self.current_location self._last_known_state["last_location"] = self.last_location log.debug("Requesting next location from routemanager") # requesting a location is blocking (iv_mitm will wait for a prioQ item), we really need to clean # the workers up... routemanager = self._get_currently_valid_routemanager() if routemanager is None: return None else: self.current_location = routemanager.get_next_location() return routemanager.settings def _init_routine(self): if self._applicationArgs.initial_restart is False: self._turn_screen_on_and_start_pogo() else: if not self._start_pogo(): while not self._restart_pogo(): log.warning("failed starting pogo") # TODO: stop after X attempts def _check_location_is_valid(self): if self.current_location is None: log.info('Current Location is None') while self._timer.get_switch(): log.info('Sleeping - Route is finished') time.sleep(30) elif self.current_location is not None: log.debug('Coords are valid') return True def _turn_screen_on_and_start_pogo(self): if not self._communicator.isScreenOn(): self._communicator.startApp("de.grennith.rgc.remotegpscontroller") log.warning("Turning screen on") self._communicator.turnScreenOn() time.sleep(self._devicesettings.get("post_turn_screen_on_delay", 2)) # check if pogo is running and start it if necessary log.warning("turnScreenOnAndStartPogo: (Re-)Starting Pogo") self._start_pogo() def _check_screen_on(self): if not self._communicator.isScreenOn(): self._communicator.startApp("de.grennith.rgc.remotegpscontroller") log.warning("Turning screen on") self._communicator.turnScreenOn() time.sleep(self._devicesettings.get("post_turn_screen_on_delay", 2)) def _stop_pogo(self): attempts = 0 stop_result = self._communicator.stopApp("com.nianticlabs.pokemongo") pogoTopmost = self._communicator.isPogoTopmost() while pogoTopmost: attempts += 1 if attempts > 10: return False stop_result = self._communicator.stopApp( "com.nianticlabs.pokemongo") time.sleep(1) pogoTopmost = self._communicator.isPogoTopmost() return stop_result def _reboot(self): try: start_result = self._communicator.reboot() except WebsocketWorkerRemovedException as e: log.error( "Could not reboot due to client already having disconnected") start_result = False time.sleep(5) self.stop_worker() return start_result def _start_pogodroid(self): start_result = self._communicator.startApp("com.mad.pogodroid") time.sleep(5) return start_result def _stopPogoDroid(self): stopResult = self._communicator.stopApp("com.mad.pogodroid") return stopResult def _restart_pogo(self, clear_cache=True): successful_stop = self._stop_pogo() self._lastStart = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") log.debug("restartPogo: stop pogo resulted in %s" % str(successful_stop)) if successful_stop: if clear_cache: self._communicator.clearAppCache("com.nianticlabs.pokemongo") time.sleep(1) return self._start_pogo() else: return False def _restartPogoDroid(self): successfulStop = self._stopPogoDroid() time.sleep(1) log.debug("restartPogoDroid: stop pogodriud resulted in %s" % str(successfulStop)) if successfulStop: return self._start_pogodroid() else: return False def _reopenRaidTab(self): log.debug("_reopenRaidTab: Taking screenshot...") log.info( "reopenRaidTab: Attempting to retrieve screenshot before checking raidtab" ) if not self._takeScreenshot(): log.debug("_reopenRaidTab: Failed getting screenshot...") log.error( "reopenRaidTab: Failed retrieving screenshot before checking for closebutton" ) return log.debug("_reopenRaidTab: Checking close except nearby...") pathToPass = os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)) log.debug("Path: %s" % str(pathToPass)) self._pogoWindowManager.checkCloseExceptNearbyButton( pathToPass, self._id, 'True') log.debug("_reopenRaidTab: Getting to raidscreen...") self._getToRaidscreen(3) time.sleep(1) def _takeScreenshot(self, delayAfter=0.0, delayBefore=0.0): log.debug("Taking screenshot...") time.sleep(delayBefore) compareToTime = time.time() - self._lastScreenshotTaken log.debug("Last screenshot taken: %s" % str(self._lastScreenshotTaken)) if self._applicationArgs.use_media_projection: take_screenshot = self._communicator.getScreenshot( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id))) else: take_screenshot = self._communicator.get_screenshot_single( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id))) if self._lastScreenshotTaken and compareToTime < 0.5: log.debug( "takeScreenshot: screenshot taken recently, returning immediately" ) log.debug("Screenshot taken recently, skipping") return True # TODO: screenshot.png needs identifier in name elif not take_screenshot: log.error("takeScreenshot: Failed retrieving screenshot") log.debug("Failed retrieving screenshot") return False else: log.debug("Success retrieving screenshot") self._lastScreenshotTaken = time.time() time.sleep(delayAfter) return True def _checkPogoFreeze(self): log.debug("Checking if pogo froze") if not self._takeScreenshot(): log.debug("_checkPogoFreeze: failed retrieving screenshot") return from utils.image_utils import getImageHash screenHash = getImageHash( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id))) log.debug("checkPogoFreeze: Old Hash: " + str(self._lastScreenHash)) log.debug("checkPogoFreeze: New Hash: " + str(screenHash)) if hamming_dist(str(self._lastScreenHash), str(screenHash)) < 4 and str( self._lastScreenHash) != '0': log.debug( "checkPogoFreeze: New und old Screenshoot are the same - no processing" ) self._lastScreenHashCount += 1 log.debug("checkPogoFreeze: Same Screen Count: " + str(self._lastScreenHashCount)) if self._lastScreenHashCount >= 100: self._lastScreenHashCount = 0 self._restart_pogo() else: self._lastScreenHash = screenHash self._lastScreenHashCount = 0 log.debug("_checkPogoFreeze: done") def _check_pogo_main_screen(self, maxAttempts, again=False): log.debug( "_check_pogo_main_screen: Trying to get to the Mainscreen with %s max attempts..." % str(maxAttempts)) pogoTopmost = self._communicator.isPogoTopmost() if not pogoTopmost: return False self._checkPogoFreeze() if not self._takeScreenshot( delayBefore=self._applicationArgs.post_screenshot_delay): if again: log.error( "_check_pogo_main_screen: failed getting a screenshot again" ) return False log.debug("_check_pogo_main_screen: Got screenshot, checking GPS") attempts = 0 if os.path.isdir( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id))): log.error( "_check_pogo_main_screen: screenshot.png is not a file/corrupted" ) return False while self._pogoWindowManager.isGpsSignalLost( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), self._id): log.debug("_check_pogo_main_screen: GPS signal lost") time.sleep(1) self._takeScreenshot() log.warning("_check_pogo_main_screen: GPS signal error") self._redErrorCount += 1 if self._redErrorCount > 3: log.error( "_check_pogo_main_screen: Red error multiple times in a row, restarting" ) self._redErrorCount = 0 self._restart_pogo() return False self._redErrorCount = 0 log.info("_check_pogo_main_screen: checking mainscreen") while not self._pogoWindowManager.checkpogomainscreen( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), self._id): log.error("_check_pogo_main_screen: not on Mainscreen...") if attempts > maxAttempts: # could not reach raidtab in given maxAttempts log.error( "_check_pogo_main_screen: Could not get to Mainscreen within %s attempts" % str(maxAttempts)) return False self._checkPogoFreeze() # not using continue since we need to get a screen before the next round... found = self._pogoWindowManager.lookForButton( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), 2.20, 3.01) if found: log.info("_check_pogo_main_screen: Found button (small)") if not found and self._pogoWindowManager.checkCloseExceptNearbyButton( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), self._id, closeraid=True): log.info( "_check_pogo_main_screen: Found (X) button (except nearby)" ) found = True if not found and self._pogoWindowManager.lookForButton( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), 1.05, 2.20): log.info("_check_pogo_main_screen: Found button (big)") found = True log.info( "_check_pogo_main_screen: Previous checks found popups: %s" % str(found)) attempts += 1 log.info("_check_pogo_main_screen: done") return True def _checkPogoButton(self): log.debug("checkPogoButton: Trying to find buttons") pogoTopmost = self._communicator.isPogoTopmost() if not pogoTopmost: return False self._checkPogoFreeze() if not self._takeScreenshot( delayBefore=self._applicationArgs.post_screenshot_delay): # TODO: again? # if again: # log.error("checkPogoButton: failed getting a screenshot again") # return False # TODO: throw? log.debug("checkPogoButton: Failed getting screenshot") return False attempts = 0 if os.path.isdir( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id))): log.error( "checkPogoButton: screenshot.png is not a file/corrupted") return False log.info("checkPogoButton: checking for buttons") found = self._pogoWindowManager.lookForButton( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), 2.20, 3.01) if found: log.info("checkPogoButton: Found button (small)") log.info("checkPogoButton: done") return True log.info("checkPogoButton: done") return False def _checkPogoClose(self): log.debug("checkPogoClose: Trying to find closeX") pogoTopmost = self._communicator.isPogoTopmost() if not pogoTopmost: return False self._checkPogoFreeze() if not self._takeScreenshot( delayBefore=self._applicationArgs.post_screenshot_delay): # TODO: go again? # if again: # log.error("checkPogoClose: failed getting a screenshot again") # return False # TODO: consider throwing? log.debug("checkPogoClose: Could not get screenshot") return False attempts = 0 if os.path.isdir( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id))): log.error("checkPogoClose: screenshot.png is not a file/corrupted") return False log.info("checkPogoClose: checking for CloseX") found = self._pogoWindowManager.checkCloseExceptNearbyButton( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), self._id) if found: log.info("checkPogoClose: Found (X) button (except nearby)") log.info("checkPogoClose: done") return True log.info("checkPogoClose: done") return False def _getToRaidscreen(self, maxAttempts, again=False): # check for any popups (including post login OK) log.debug( "getToRaidscreen: Trying to get to the raidscreen with %s max attempts..." % str(maxAttempts)) pogoTopmost = self._communicator.isPogoTopmost() if not pogoTopmost: return False self._checkPogoFreeze() if not self._takeScreenshot( delayBefore=self._applicationArgs.post_screenshot_delay): if again: log.error("getToRaidscreen: failed getting a screenshot again") return False self._getToRaidscreen(maxAttempts, True) log.debug("getToRaidscreen: Got screenshot, checking GPS") attempts = 0 if os.path.isdir( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id))): log.error( "getToRaidscreen: screenshot.png is not a file/corrupted") return False # TODO: replace self._id with device ID while self._pogoWindowManager.isGpsSignalLost( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), self._id): log.debug("getToRaidscreen: GPS signal lost") time.sleep(1) self._takeScreenshot() log.warning("getToRaidscreen: GPS signal error") self._redErrorCount += 1 if self._redErrorCount > 3: log.error( "getToRaidscreen: Red error multiple times in a row, restarting" ) self._redErrorCount = 0 self._restart_pogo() return False self._redErrorCount = 0 log.debug("getToRaidscreen: checking raidscreen") while not self._pogoWindowManager.checkRaidscreen( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), self._id): log.debug("getToRaidscreen: not on raidscreen...") if attempts > maxAttempts: # could not reach raidtab in given maxAttempts log.error( "getToRaidscreen: Could not get to raidtab within %s attempts" % str(maxAttempts)) return False self._checkPogoFreeze() # not using continue since we need to get a screen before the next round... found = self._pogoWindowManager.lookForButton( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), 2.20, 3.01) if found: log.info("getToRaidscreen: Found button (small)") if not found and self._pogoWindowManager.checkCloseExceptNearbyButton( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), self._id): log.info("getToRaidscreen: Found (X) button (except nearby)") found = True if not found and self._pogoWindowManager.lookForButton( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), 1.05, 2.20): log.info("getToRaidscreen: Found button (big)") found = True log.info("getToRaidscreen: Previous checks found popups: %s" % str(found)) if not found: log.info( "getToRaidscreen: Previous checks found nothing. Checking nearby open" ) if self._pogoWindowManager.checkNearby( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), self._id): return self._takeScreenshot( delayBefore=self._applicationArgs.post_screenshot_delay ) if not self._takeScreenshot( delayBefore=self._applicationArgs.post_screenshot_delay): return False attempts += 1 log.debug("getToRaidscreen: done") return True def _get_screen_size(self): screen = self._communicator.getscreensize().split(' ') self._screen_x = screen[0] self._screen_y = screen[1] log.debug('Get Screensize of %s: X: %s, Y: %s' % (str(self._id), str(self._screen_x), str(self._screen_y))) self._resocalc.get_x_y_ratio(self, self._screen_x, self._screen_y)
try: (device_mappings, routemanagers, auths) = load_mappings(db_wrapper) except KeyError as e: log.fatal( "Could not parse mappings. Please check those. Description: %s" % str(e)) sys.exit(1) except RuntimeError as e: log.fatal( "There is something wrong with your mappings. Description: %s" % str(e)) sys.exit(1) pogoWindowManager = PogoWindows(args.temp_path) mitm_mapper = MitmMapper(device_mappings) ocr_enabled = False for routemanager in routemanagers.keys(): area = routemanagers.get(routemanager, None) if area is None: continue if "ocr" in area.get("mode", ""): ocr_enabled = True if ocr_enabled: from ocr.copyMons import MonRaidImages MonRaidImages.runAll(args.pogoasset, db_wrapper=db_wrapper) mitm_receiver = MITMReceiver(args.mitmreceiver_ip, int(args.mitmreceiver_port), mitm_mapper, args, auths, db_wrapper)
class WorkerBase(ABC): def __init__(self, args, id, last_known_state, websocket_handler, route_manager_daytime, route_manager_nighttime, devicesettings, db_wrapper, NoOcr=False): self.thread_pool = ThreadPool(processes=2) self._route_manager_daytime = route_manager_daytime self._route_manager_nighttime = route_manager_nighttime self._websocket_handler = websocket_handler self._communicator = Communicator(websocket_handler, id, args.websocket_command_timeout) self._id = id self._applicationArgs = args self._last_known_state = last_known_state self._lastScreenshotTaken = 0 self._stop_worker_event = Event() self._db_wrapper = db_wrapper self._redErrorCount = 0 self._lastScreenHash = None self._lastScreenHashCount = 0 self._devicesettings = devicesettings if not NoOcr: from ocr.pogoWindows import PogoWindows self._pogoWindowManager = PogoWindows(self._communicator, args.temp_path) def start_worker(self): # asyncio.ensure_future(self._main_work_thread()) async_result = self.thread_pool.apply_async(self._main_work_thread, ()) # tuple of args for foo # return_val = async_result.get() # get the return value from your function. # do some other stuff in the main process while not self._stop_worker_event.isSet(): time.sleep(1) async_result.get() return self._last_known_state def stop_worker(self): self._stop_worker_event.set() @abstractmethod def _main_work_thread(self): log.debug("Base called") pass @abstractmethod def _start_pogo(self): pass # routine to start pogo. Needs to be overriden since e.g. OCR worker uses screenshots for startup def _initRoutine(self): if self._applicationArgs.initial_restart is False: self._turnScreenOnAndStartPogo() else: if not self._start_pogo(): while not self._restartPogo(): log.warning("failed starting pogo") def _turnScreenOnAndStartPogo(self): if not self._communicator.isScreenOn(): self._communicator.startApp("de.grennith.rgc.remotegpscontroller") log.warning("Turning screen on") self._communicator.turnScreenOn() time.sleep(self._applicationArgs.post_turn_screen_on_delay) # check if pogo is running and start it if necessary log.warning("turnScreenOnAndStartPogo: (Re-)Starting Pogo") self._restartPogo() def _stopPogo(self): attempts = 0 stopResult = self._communicator.stopApp("com.nianticlabs.pokemongo") pogoTopmost = self._communicator.isPogoTopmost() while pogoTopmost: attempts += 1 if attempts > 10: return False stopResult = self._communicator.stopApp("com.nianticlabs.pokemongo") time.sleep(1) pogoTopmost = self._communicator.isPogoTopmost() return stopResult def _restartPogo(self, clear_cache=True): successfulStop = self._stopPogo() log.debug("restartPogo: stop pogo resulted in %s" % str(successfulStop)) if successfulStop: if clear_cache: self._communicator.clearAppCache("com.nianticlabs.pokemongo") time.sleep(1) return self._start_pogo() else: return False def _reopenRaidTab(self): log.debug("_reopenRaidTab: Taking screenshot...") log.info("reopenRaidTab: Attempting to retrieve screenshot before checking raidtab") if not self._takeScreenshot(): log.debug("_reopenRaidTab: Failed getting screenshot...") log.error("reopenRaidTab: Failed retrieving screenshot before checking for closebutton") return log.debug("_reopenRaidTab: Checking close except nearby...") pathToPass = os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)) log.debug("Path: %s" % str(pathToPass)) self._pogoWindowManager.checkCloseExceptNearbyButton(pathToPass, self._id, 'True') log.debug("_reopenRaidTab: Getting to raidscreen...") self._getToRaidscreen(3) time.sleep(1) def _takeScreenshot(self, delayAfter=0.0, delayBefore=0.0): log.debug("Taking screenshot...") time.sleep(delayBefore) compareToTime = time.time() - self._lastScreenshotTaken log.debug("Last screenshot taken: %s" % str(self._lastScreenshotTaken)) if self._lastScreenshotTaken and compareToTime < 0.5: log.debug("takeScreenshot: screenshot taken recently, returning immediately") log.debug("Screenshot taken recently, skipping") return True # TODO: screenshot.png needs identifier in name elif not self._communicator.getScreenshot(os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id))): log.error("takeScreenshot: Failed retrieving screenshot") log.debug("Failed retrieving screenshot") return False else: log.debug("Success retrieving screenshot") self._lastScreenshotTaken = time.time() time.sleep(delayAfter) return True def _checkPogoFreeze(self): log.debug("Checking if pogo froze") if not self._takeScreenshot(): log.debug("_checkPogoFreeze: failed retrieving screenshot") return from utils.image_utils import getImageHash screenHash = getImageHash(os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id))) log.debug("checkPogoFreeze: Old Hash: " + str(self._lastScreenHash)) log.debug("checkPogoFreeze: New Hash: " + str(screenHash)) if hamming_dist(str(self._lastScreenHash), str(screenHash)) < 4 and str(self._lastScreenHash) != '0': log.debug("checkPogoFreeze: New und old Screenshoot are the same - no processing") self._lastScreenHashCount += 1 log.debug("checkPogoFreeze: Same Screen Count: " + str(self._lastScreenHashCount)) if self._lastScreenHashCount >= 100: self._lastScreenHashCount = 0 self._restartPogo() else: self._lastScreenHash = screenHash self._lastScreenHashCount = 0 log.debug("_checkPogoFreeze: done") def _getToRaidscreen(self, maxAttempts, again=False): # check for any popups (including post login OK) log.debug("getToRaidscreen: Trying to get to the raidscreen with %s max attempts..." % str(maxAttempts)) pogoTopmost = self._communicator.isPogoTopmost() if not pogoTopmost: return False self._checkPogoFreeze() if not self._takeScreenshot(delayBefore=self._applicationArgs.post_screenshot_delay): if again: log.error("getToRaidscreen: failed getting a screenshot again") return False self._getToRaidscreen(maxAttempts, True) log.debug("getToRaidscreen: Got screenshot, checking GPS") attempts = 0 if os.path.isdir(os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id))): log.error("getToRaidscreen: screenshot.png is not a file/corrupted") return False # TODO: replace self._id with device ID while self._pogoWindowManager.isGpsSignalLost(os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), self._id): log.debug("getToRaidscreen: GPS signal lost") time.sleep(1) self._takeScreenshot() log.warning("getToRaidscreen: GPS signal error") self._redErrorCount += 1 if self._redErrorCount > 3: log.error("getToRaidscreen: Red error multiple times in a row, restarting") self._redErrorCount = 0 self._restartPogo() return False self._redErrorCount = 0 log.debug("getToRaidscreen: checking raidscreen") while not self._pogoWindowManager.checkRaidscreen(os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), self._id): log.debug("getToRaidscreen: not on raidscreen...") if attempts > maxAttempts: # could not reach raidtab in given maxAttempts log.error("getToRaidscreen: Could not get to raidtab within %s attempts" % str(maxAttempts)) return False self._checkPogoFreeze() # not using continue since we need to get a screen before the next round... found = self._pogoWindowManager.lookForButton(os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), 2.20, 3.01) if found: log.info("getToRaidscreen: Found button (small)") if not found and self._pogoWindowManager.checkCloseExceptNearbyButton( os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), self._id): log.info("getToRaidscreen: Found (X) button (except nearby)") found = True if not found and self._pogoWindowManager.lookForButton(os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), 1.05, 2.20): log.info("getToRaidscreen: Found button (big)") found = True log.info("getToRaidscreen: Previous checks found popups: %s" % str(found)) if not found: log.info("getToRaidscreen: Previous checks found nothing. Checking nearby open") if self._pogoWindowManager.checkNearby(os.path.join(self._applicationArgs.temp_path, 'screenshot%s.png' % str(self._id)), self._id): return self._takeScreenshot(delayBefore=self._applicationArgs.post_screenshot_delay) if not self._takeScreenshot(delayBefore=self._applicationArgs.post_screenshot_delay): return False attempts += 1 log.debug("getToRaidscreen: done") return True
def main_thread(): global nextRaidQueue global lastPogoRestart global telnMore global sleep log.info("Starting VNC client") vncWrapper = VncWrapper(str(args.vnc_ip, ), 1, args.vnc_port, args.vnc_password) log.info("Starting TelnetGeo Client") telnGeo = TelnetGeo(str(args.tel_ip), args.tel_port, str(args.tel_password)) #log.info("Starting Telnet MORE Client") #telnMore = TelnetMore(str(args.tel_ip), args.tel_port, str(args.tel_password)) log.info("Starting pogo window manager") pogoWindowManager = PogoWindows(str(args.vnc_ip, ), 1, args.vnc_port, args.vnc_password, args.screen_width, args.screen_height, args.temp_path) log.info("Starting dbWrapper") dbWrapper = DbWrapper(str(args.dbip), args.dbport, args.dbusername, args.dbpassword, args.dbname, args.timezone) updateRaidQueue(dbWrapper) route = getJsonRoute(args.file) lastPogoRestart = time.time() lastRaidQueueUpdate = time.time() log.info("Route to be taken: %s, amount of coords: %s" % (str(route), str(len(route)))) #sys.exit(0) log.info("Max_distance before teleporting: %s" % args.max_distance) log.info("Checking if screen is on and pogo is running") if not sleep: turnScreenOnAndStartPogo() #sys.exit(0) while True: log.info("Next round") lastLat = 0.0 lastLng = 0.0 curLat = 0.0 curLng = 0.0 #loop over gyms: #walk to next gym #check errors (anything not raidscreen) #get to raidscreen (with the above command) #take screenshot and store coords in exif with it #check time to restart pogo and reset google play services i = 0 #index, iterating with it to either get to the next gym or the priority of our queue failcount = 0 while i < len(route): while sleep: time.sleep(1) #TODO: check if not sleep -> start pogo, if sleep, stop it curTime = time.time() #update the raid queue every 5mins... if (curTime - lastRaidQueueUpdate) >= (5 * 60): updateRaidQueue(dbWrapper) lastRaidQueueUpdate = curTime #we got the latest raids. To avoid the mobile from killing apps, #let's restart pogo every 2hours or whatever TODO: consider args log.debug("Current time - lastPogoRestart: %s" % str(curTime - lastPogoRestart)) if (curTime - lastPogoRestart >= (120 * 60)): restartPogo() lastLat = curLat lastLng = curLng log.debug( "Checking for raidqueue priority. Current time: %s, Current queue: %s" % (str(time.time()), str(nextRaidQueue))) #determine whether we move to the next gym or to the top of our priority queue if (len(nextRaidQueue) > 0 and nextRaidQueue[0][0] < time.time()): #the topmost item in the queue lays in the past... log.info('An egg has hatched, get there asap. Location: %s' % str(nextRaidQueue[0])) nextStop = heapq.heappop(nextRaidQueue)[ 1] #gets the location tuple curLat = nextStop.latitude curLng = nextStop.longitude time.sleep(1) else: #continue as usual log.info('Moving on with gym at %s' % route[i]) curLat = route[i]['lat'] curLng = route[i]['lng'] #remove whitespaces that might be on either side... #curLat = curLat.strip() #curLng = curLng.strip() i += 1 log.debug("next stop: %s, %s" % (str(curLat), str(curLng))) log.debug('LastLat: %s, LastLng: %s, CurLat: %s, CurLng: %s' % (lastLat, lastLng, curLat, curLng)) #get the distance from our current position (last) to the next gym (cur) distance = getDistanceOfTwoPointsInMeters(float(lastLat), float(lastLng), float(curLat), float(curLng)) log.info('Moving %s meters to the next position' % distance) if (args.speed == 0 or (args.max_distance and distance > args.max_distance) or (lastLat == 0.0 and lastLng == 0.0)): log.info("Teleporting...") telnGeo.setLocation(curLat, curLng, 0) time.sleep(4) else: log.info('Walking...') telnGeo.walkFromTo(lastLat, lastLng, curLat, curLng, args.speed) time.sleep(2) #ok, we should be at the next gym, check for errors and stuff #TODO: improve errorhandling by checking results and trying again and again #not using continue to always take a new screenshot... #time.sleep(5) log.info( "Attempting to retrieve screenshot before checking windows") if (not vncWrapper.getScreenshot('screenshot.png')): log.error( "Failed retrieving screenshot before checking windows") break #failcount += 1 #TODO: consider proper errorhandling? #even restart entire thing? VNC dead means we won't be using the device #maybe send email? :D #break; attempts = 0 while (not pogoWindowManager.checkRaidscreen( 'screenshot.png', 123)): if (attempts >= 15): #weird count of failures... stop pogo, wait 5mins and try again, could be PTC login issue telnMore.stopApp("com.nianticlabs.pokemongo") time.sleep(360) turnScreenOnAndStartPogo() #restartPogo() attempts = 0 #not using continue since we need to get a screen before the next round... TODO: consider getting screen for checkRaidscreen within function found = pogoWindowManager.checkPostLoginOkButton( 'screenshot.png', 123) if not found and pogoWindowManager.checkCloseExceptNearbyButton( 'screenshot.png', 123): log.info( "Found close button (X) on a window other than nearby") found = True if not found and pogoWindowManager.checkSpeedwarning( 'screenshot.png', 123): log.info("Found speed warning") found = True if not found and pogoWindowManager.checkPostLoginNewsMessage( 'screenshot.png', 123): log.info("Found post login news message") found = True if not found and pogoWindowManager.checkGameQuitPopup( 'screenshot.png', 123): log.info("Found game quit popup") found = True log.info("Previous checks found popups: %s" % str(not found)) if not found: log.info( "Previous checks found nothing. Checking nearby open") pogoWindowManager.checkNearby('screenshot.png', 123) try: log.info( "Attempting to retrieve screenshot checking windows") vncWrapper.getScreenshot('screenshot.png') except: log.error( "Failed getting screenshot while checking windows") #failcount += 1 #TODO: consider proper errorhandling? #even restart entire thing? VNC dead means we won't be using the device #maybe send email? :D break vncWrapper.getScreenshot('screenshot.png') #TODO: take screenshot of raidscreen? #we should now see the raidscreen, let's take a screenshot of it time.sleep(1) attempts += 1 log.info("Saving raid screenshot") countOfRaids = pogoWindowManager.readAmountOfRaids( 'screenshot.png', 123) if countOfRaids > 0: curTime = time.time() copyfile( 'screenshot.png', args.raidscreen_path + '/raidscreen_' + str(curTime) + "_" + str(countOfRaids) + '.png')