def get_character_location(char_id): char = EVEPlayerCharacter.get_object(char_id) if not char.has_esi_scope('esi-location.read_location.v1'): return None client = EsiClient(authenticating_character=char) location, _ = client.get("/v1/characters/%s/location/" % char.pk) system_id = location["solar_system_id"] actual_type = CcpIdTypeResolver.get_id_type(system_id) # fix for CCP-side bug if actual_type != "system": structure_id = system_id structure = Structure.get_object(structure_id, char.pk) system = structure.location.system if structure.location else None else: system = System.get_object(system_id) # both structures and stations can be handled by structure.getobject if "structure_id" in location: structure = Structure.get_object(location["structure_id"], char.pk) elif "station_id" in location: structure = Structure.get_object(location["station_id"], char.pk) else: structure = None return {"system": system, "structure": structure}
def structure_search(char_id, search_string): char = EVEPlayerCharacter.get_object(char_id) client = EsiClient(authenticating_character=char, raise_application_errors=False) logger.info("search string {}".format(search_string)) search_param = urllib.parse.urlencode({"search": search_string}) logger.info("search param {}".format(search_param)) res, err = client.get( "/v3/characters/{}/search/?categories=structure,station&language=en-us&{}&strict=false" .format(char_id, search_param)) if err == EsiError.EsiApplicationError: return [] results = [] if "structure" in res: if res["structure"]: Structure.load_citadels_async(res["structure"], client) results.extend(res["structure"]) if "station" in res: if res["station"]: stations_to_load = [] for station_id in res["station"]: if not Structure.exists(station_id): stations_to_load.append(station_id) else: results.append(station_id) Structure.load_stations_async(stations_to_load, client) results.extend(stations_to_load) return results
def resolve_extra_info_object(character, key, value): if key == "structure_id" or key == "station_id": Structure.verify_object_exists(value, character.pk) elif key == "type_id": ObjectType.verify_object_exists(value) elif key == "character_id": # fix inaccurate CCP data # CCP uses character_id as a catch-all key for special extra_info types that aren't defined. actual_type = CcpIdTypeResolver.get_id_type(value) if actual_type == "character": EVEPlayerCharacter.verify_object_exists(value) else: logger.error("getting incorrect character_id journal thing for type id %s actual_Type: %s" % (value, actual_type)) return None,None elif key == "corporation_id": EVEPlayerCorporation.verify_object_exists(value) elif key == "alliance_id": EVEPlayerAlliance.verify_object_exists(value) elif key == "system_id": System.verify_object_exists(value) elif key == "market_transaction_id" or key == "industry_job_id" or key == "contract_id" or key == "planet_id" or key == "eve_system": #idgaf pass else: raise Exception("ccp returning some fancy new key object? %s %s" % (key,value) ) return (key,value)
def sort_assets_into_structures(assets, item_id_hashtable, container_candidate_hashtable, character): """ Returns a list of assets that sitting DIRECTLY inside a structure. Items in containers or ships are excluded. Returns an updated container_candidate_hashtable & item_id hashtable & assets list that excludes pocos, which tend to cause a shit ton of problems else where. :param assets: :param item_id_hashtable: :param container_candidate_hashtable: :param character: :return: """ items_in_structures = [] for asset in assets: if asset["location_id"] not in item_id_hashtable: items_in_structures.append(asset) # Handle side case when the "structure" an asset is inside is actually the character's pod if asset["location_id"] == character.pk: continue else: if asset["location_id"] > 60000000 and asset[ "location_id"] < 64000000: # station Structure.verify_object_exists(asset["location_id"], character.pk) elif asset["location_id"] > 30000000 and asset[ "location_id"] <= 32000000: # it's a system id Location.verify_object_exists(asset["location_id"], character.pk) else: # it's either a structure or a poco try: Structure.verify_object_exists(asset["location_id"], character.pk) except Exception as e: # it's a poco and there's nothing we can do about it del item_id_hashtable[asset["item_id"]] try: del container_candidate_hashtable[ asset["location_id"]] except KeyError: pass items_in_structures.remove(asset) assets.remove(asset) continue return items_in_structures, container_candidate_hashtable, item_id_hashtable, assets
def resolve_container_locations(assets, item_id_hashtable, items_in_structures, container_candidate_hashtable, character): """ Resolves the Location of any containers in the assets :param assets: :param item_id_hashtable: :param items_in_structures: :param container_candidate_hashtable: :return: """ for asset in items_in_structures: if asset["item_id"] in container_candidate_hashtable: # This asset has children. It needs a Location created for it. # we've got three possibilities at this point: # 1. The object is sitting inside a structure, and its root location is the structure # 2. The object is sitting inside another container, and its root location is that container # 3. The object is sitting in space, and its root location is that star system. # If the object is inside another container, then we still don't know if the whole shebang is in space, # inside a structure, or what. We only want to call resolve_location_tree for a single "tree" of containers, # so if this container isn't at the top of the stack, we skip it. if asset["location_id"] in item_id_hashtable: continue # need to figure out if root location is a Structure or a System if asset["location_id"] > 30000000 and asset[ "location_id"] <= 32000000: base_system = System.get_object(ccp_id=asset["location_id"]) root_location_id = base_system.ccp_id root_location = Location.get_object(root_location_id, character.pk) else: if Structure.exists(ccp_id=asset["location_id"]): base_structure = Structure.get_object( asset["location_id"], character.pk) root_location_id = base_structure.ccp_id root_location = base_structure.location else: msg = "The asset is located in an unknown entity type, unable to resolve root location. Asset Location ID: %s Asset Item ID: %s, Character Trigger: %s" % ( asset["location_id"], asset["item_id"], character.pk) logger.critical(msg) raise Exception(msg) resolve_location_tree(root_location_id, root_location, asset, assets, container_candidate_hashtable)
def extract_order(character, order): return { "duration": order["duration"], "escrow": float(order.get("escrow")) if order.get("escrow") is not None else None, "is_buy_order": False if order.get("is_buy_order") is None else order["is_buy_order"], "is_corporation": order["is_corporation"], "issued": dateutil.parser.parse(order["issued"]), "location": Structure.get_object(order["location_id"], character.pk), "min_volume": order.get("min_volume"), "order_id": int(order["order_id"]), "price": float(order["price"]), "range": order["range"], "type": ObjectType.get_object(order["type_id"]), "volume_remain": order["volume_remain"], "volume_total": order["volume_total"], "region": Region.get_object(order["region_id"]) }
def heat_price_cache(structure_id=None, object_ids=None): if structure_id: structures = [Structure.get_object(structure_id, None)] else: structures = get_structures_we_have_keys_for() structures = [Structure.get_object(s, None) for s in structures] if not object_ids: object_ids = ObjectType.get_all_tradeable_items() logger.info("Heating object_id lowest sell price") for s in structures: MarketPriceDAO.get_lowest_sell_price_multi(object_ids, s) logger.info("Heating object_id volume posted") for s in structures: MarketPriceDAO.get_sell_volume_posted_multi(object_ids, s) logger.info("Heating object_id lowest order") for s in structures: MarketPriceDAO.get_lowest_sell_order_multi(object_ids, s)
def extract_transaction(character, transaction): # CCP doesnt tell us what the client is, so try to resolve it ourselves client_type = CcpIdTypeResolver.get_id_type(transaction["client_id"]) util.verify_generic_object_exists(client_type, transaction["client_id"]) Structure.verify_object_exists(transaction["location_id"], character.pk) type_obj = ObjectType.get_object(transaction["type_id"]) return { "client_type": client_type, "transaction_id": transaction["transaction_id"], "date": transaction["date"], "location_id": transaction["location_id"], "type": type_obj, "unit_price": transaction["unit_price"], "quantity": transaction["quantity"], "client_id": transaction["client_id"], "is_buy": transaction["is_buy"], "is_personal": transaction["is_personal"], "journal_ref_id": transaction["journal_ref_id"] }
def _get_station_orders(station_id): client = EsiClient() station = Structure.get_object(station_id, origin_character_id=None) results = client.get_multiple_paginated("/v1/markets/" + str(station.location.region.pk) + "/orders/") # filter out orders not in our target station filtered_orders = [] for order in results: if order["location_id"] == station_id: filtered_orders.append(order) return filtered_orders
def update_structure_orders(structure_id): with general_queue.lock_task( 'update-structure-orders-{}'.format(structure_id)): logger.info("LAUNCH_TASK {} {}".format("update_structure_orders", structure_id)) structure = Structure.get_object(structure_id, None) scan_log = StructureMarketScanLog(structure=structure) scan_log.save() key_gen = _get_key_for_structure(structure_id) orders = [] for character in key_gen: try: orders = _get_orders(structure_id, character) break except Exception as e: # generic catch all because there's so many things that can go wrong logger.warning( "Failed to retrieve market data for {} using character {}. Error: {}" .format(structure_id, character, e)) if settings.DEBUG: raise e continue logger.info("orders downloaded successfully for structure {}".format( structure_id)) # update db _update_orders_database(structure_id, orders) logger.info("done updating structure {} orders".format(structure_id)) s = Structure.get_object(structure_id, None) s.market_last_updated = timezone.now() s.market_data_expires = timezone.now() + timedelta(minutes=5) s.save() scan_log.scan_complete = timezone.now() scan_log.save()
def _insert_new_db_orders(structure_id, orders): orders_to_create = [] total_ctr = 0 group_ctr = 0 order_ids = [o["order_id"] for o in orders] logger.info("Processing {} orders retreived from ESI".format( len(order_ids))) already_existing_orders = \ set( MarketOrder.objects.filter( location_id=structure_id, order_active=True, ccp_id__in=order_ids ).values_list('ccp_id', flat=True) ) orders_to_add = set(order_ids).difference(already_existing_orders) # check for orders that were falsely inactivated orders_to_reactivate = \ MarketOrder.objects.filter( location_id=structure_id, order_active=False, ccp_id__in=orders_to_add ) # this is what gets returned object_ids_updated = set() if orders_to_reactivate: logger.info( "{} orders were set to inactive that are actually still alive. Reactivating." .format(len(orders_to_reactivate))) orders_to_add = orders_to_add.difference( orders_to_reactivate.values_list('ccp_id', flat=True)) # save all the object_ids impacted by reactivation object_ids_reactivated = orders_to_reactivate.values_list( 'object_type_id', flat=True) object_ids_updated.update(object_ids_reactivated) orders_to_reactivate.update(order_active=True) # do not use this variable again, .update vs .save shennagians for order in orders: if order["order_id"] in orders_to_add: # save object_id impacted by new order object_ids_updated.add(order["type_id"]) # create order o = MarketOrder( ccp_id=order["order_id"], duration=order["duration"], is_buy_order=order["is_buy_order"], issued=dateutil.parser.parse(order["issued"]), location=Structure.get_object(order["location_id"], None), min_volume=order["min_volume"], price=order["price"], range=order["range"], object_type=ObjectType.get_object(order["type_id"]), volume_remain=order["volume_remain"], volume_total=order["volume_total"]) orders_to_create.append(o) total_ctr += 1 group_ctr += 1 if group_ctr >= 10000: logger.info( "10000 objects to be committed, running bulk create early") _insert_bulk_orders(orders_to_create) logger.info("commit completed") group_ctr = 0 orders_to_create = [] if group_ctr: _insert_bulk_orders(orders_to_create) logger.info("{} new market orders inserted into db".format(total_ctr)) return list(object_ids_updated)
def update_player_assets(character_id): logger.info("LAUNCH TASK update_player_assets {}".format(character_id)) with player_queue.lock_task( 'update-player-assets-{}'.format(character_id)): char = EVEPlayerCharacter.get_object(character_id) # double check to verify we actually need to scan this character right now oldest_allowable_update = timezone.now() - player_assets_timedelta if char.assets_last_updated and char.assets_last_updated > oldest_allowable_update: logger.warning( "{} was queued for assets update quickly over a given interval. killing followup task" .format(character_id)) return scan_log = PlayerAssetsScanLog.start_scan_log(char) assets, containers = _get_player_assets_and_containers(char) # extract hashes to figure out current configuration current_assets_hash = AssetEntry.generate_hash(character_id) new_assets_hash = AssetEntry.generate_has_from_list(assets) force = False if new_assets_hash != current_assets_hash or force: logger.info("Assets hash changed for {}, updating assets".format( character_id)) with transaction.atomic(): AssetEntry.objects.filter(character_id=character_id).delete() AssetContainer.objects.filter( character_id=character_id).delete() container_objs = [] asset_objs = [] for c in containers: container_objs.append( AssetContainer(ccp_id=c["item_id"], character=char, structure=Structure.get_object( c["location"].root_location_id, char.pk), name=c["name"])) AssetContainer.objects.bulk_create(container_objs) for a in assets: asset_objs.append( AssetEntry( ccp_id=a["item_id"], character=char, structure=Structure.get_object( a["location"].root_location_id, char.pk), container_id=None if not a["is_in_container"] else a["location"].pk, quantity=a["quantity"], object_type=a["type"])) AssetEntry.objects.bulk_create(asset_objs) char.assets_last_updated = timezone.now() char.save() scan_log.stop_scan_log() logger.info("COMPLETE TASK update_player_assets {}".format(character_id)) return
def _verify_transaction_models_exist(transactions, character): for transaction in transactions: Structure.verify_object_exists(transaction["location_id"], character.pk) ObjectType.verify_object_exists(transaction["type_id"])