예제 #1
0
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}
예제 #2
0
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
예제 #3
0
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)
예제 #4
0
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
예제 #5
0
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)
예제 #6
0
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"])
    }
예제 #7
0
    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)
예제 #8
0
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"]
    }
예제 #9
0
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
예제 #10
0
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()
예제 #11
0
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)
예제 #12
0
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
예제 #13
0
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"])