1
0
mirror of https://github.com/EDCD/EDMarketConnector.git synced 2025-04-21 11:27:38 +03:00

Merge pull request from EDCD/enhancement/1595/eddn-fcmaterials-journal

EDDN: Implement Journal-based `fcmaterials/1` schema
This commit is contained in:
Athanasius 2022-09-06 15:14:42 +01:00 committed by GitHub
commit 3c30b34d39
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -88,6 +88,10 @@ class This:
self.commodities: Optional[List[OrderedDictT[str, Any]]] = None
self.outfitting: Optional[Tuple[bool, List[str]]] = None
self.shipyard: Optional[Tuple[bool, List[Mapping[str, Any]]]] = None
self.fcmaterials_marketid: int = 0
self.fcmaterials: Optional[List[OrderedDictT[str, Any]]] = None
self.fcmaterials_capi_marketid: int = 0
self.fcmaterials_capi: Optional[List[OrderedDictT[str, Any]]] = None
# For the tkinter parent window, so we can call update_idletasks()
self.parent: tk.Tk
@ -145,6 +149,7 @@ class EDDN:
r"https://eddn.edcd.io/schemas/(?P<schema_name>.+)/(?P<schema_version>[0-9]+) is unknown, "
r"unable to validate.',\)\]$"
)
CAPI_LOCALISATION_RE = re.compile(r'^loc[A-Z].+')
def __init__(self, parent: tk.Tk):
self.parent: tk.Tk = parent
@ -488,6 +493,9 @@ class EDDN:
this.commodities = commodities
# Send any FCMaterials.json-equivalent 'orders' as well
self.export_capi_fcmaterials(data, is_beta, horizons)
def safe_modules_and_ships(self, data: Mapping[str, Any]) -> Tuple[Dict, Dict]:
"""
Produce a sanity-checked version of ships and modules from CAPI data.
@ -1079,7 +1087,6 @@ class EDDN:
Send a NavRoute to EDDN on the correct schema.
:param cmdr: the commander under which this upload is made
:param system_starpos: Coordinates of current star system
:param is_beta: whether or not we are in beta mode
:param entry: the journal entry to send
"""
@ -1146,6 +1153,145 @@ class EDDN:
this.eddn.export_journal_entry(cmdr, entry, msg)
return None
def export_journal_fcmaterials(
self, cmdr: str, is_beta: bool, entry: MutableMapping[str, Any]
) -> Optional[str]:
"""
Send an FCMaterials message to EDDN on the correct schema.
:param cmdr: the commander under which this upload is made
:param is_beta: whether or not we are in beta mode
:param entry: the journal entry to send
"""
# {
# "timestamp":"2022-06-08T12:44:19Z",
# "event":"FCMaterials",
# "MarketID":3700710912,
# "CarrierName":"PSI RORSCHACH",
# "CarrierID":"K4X-33F",
# "Items":[
# {
# "id":128961533,
# "Name":"$encryptedmemorychip_name;",
# "Name_Localised":"Encrypted Memory Chip",
# "Price":500,
# "Stock":0,
# "Demand":5
# },
#
# { "id":128961537,
# "Name":"$memorychip_name;",
# "Name_Localised":"Memory Chip",
# "Price":600,
# "Stock":0,
# "Demand":5
# },
#
# { "id":128972290,
# "Name":"$campaignplans_name;",
# "Name_Localised":"Campaign Plans",
# "Price":600,
# "Stock":5,
# "Demand":0
# }
# ]
# }
# Sanity check
if 'Items' not in entry:
logger.warning(f"FCMaterials didn't contain an Items array!\n{entry!r}")
# This can happen if first-load of the file failed, and we're simply
# passing through the bare Journal event, so no need to alert
# the user.
return None
if this.fcmaterials_marketid == entry['MarketID']:
if this.fcmaterials == entry['Items']:
# Same FC, no change in Stock/Demand/Prices, so don't send
return None
this.fcmaterials_marketid = entry['MarketID']
this.fcmaterials = entry['Items']
#######################################################################
# Elisions
#######################################################################
# There are Name_Localised key/values in the Items array members
entry = filter_localised(entry)
#######################################################################
#######################################################################
# Augmentations
#######################################################################
# None
#######################################################################
msg = {
'$schemaRef': f'https://eddn.edcd.io/schemas/fcmaterials_journal/1{"/test" if is_beta else ""}',
'message': entry
}
this.eddn.export_journal_entry(cmdr, entry, msg)
return None
def export_capi_fcmaterials(
self, data: Mapping[str, Any], is_beta: bool, horizons: bool
) -> Optional[str]:
"""
Send CAPI-sourced 'onfootmicroresources' data on `fcmaterials/1` schema.
:param data: the CAPI `/market` data
:param is_beta: whether, or not we are in beta mode
:param horizons: whether player is in Horizons
"""
# Sanity check
if 'lastStarport' not in data:
return None
if 'orders' not in data['lastStarport']:
return None
if 'onfootmicroresources' not in data['lastStarport']['orders']:
return None
items = data['lastStarport']['orders']['onfootmicroresources']
if this.fcmaterials_capi_marketid == data['lastStarport']['id']:
if this.fcmaterials_capi == items:
# Same FC, no change in orders, so don't send
return None
this.fcmaterials_capi_marketid = data['lastStarport']['id']
this.fcmaterials_capi = items
#######################################################################
# Elisions
#######################################################################
# There are localised key names for the resources
items = capi_filter_localised(items)
#######################################################################
#######################################################################
# EDDN `'message'` creation, and augmentations
#######################################################################
entry = {
'timestamp': data['timestamp'],
'event': 'FCMaterials',
'horizons': horizons,
'odyssey': this.odyssey,
'MarketID': data['lastStarport']['id'],
'CarrierID': data['lastStarport']['name'],
'Items': items,
}
#######################################################################
msg = {
'$schemaRef': f'https://eddn.edcd.io/schemas/fcmaterials_capi/1{"/test" if is_beta else ""}',
'message': entry
}
this.eddn.export_journal_entry(data['commander']['name'], entry, msg)
return None
def export_journal_approachsettlement(
self, cmdr: str, system_name: str, system_starpos: list, is_beta: bool, entry: MutableMapping[str, Any]
) -> Optional[str]:
@ -1624,10 +1770,9 @@ def plugin_stop() -> None:
logger.debug('Done.')
# Recursively filter '*_Localised' keys from dict
def filter_localised(d: Mapping[str, Any]) -> OrderedDictT[str, Any]:
"""
Remove any dict keys with names ending `_Localised` from a dict.
Recursively remove any dict keys with names ending `_Localised` from a dict.
:param d: Dict to filter keys of.
:return: The filtered dict.
@ -1649,6 +1794,30 @@ def filter_localised(d: Mapping[str, Any]) -> OrderedDictT[str, Any]:
return filtered
def capi_filter_localised(d: Mapping[str, Any]) -> OrderedDictT[str, Any]:
"""
Recursively remove any dict keys for known CAPI 'localised' names.
:param d: Dict to filter keys of.
:return: The filtered dict.
"""
filtered: OrderedDictT[str, Any] = OrderedDict()
for k, v in d.items():
if EDDN.CAPI_LOCALISATION_RE.search(k):
pass
elif hasattr(v, 'items'): # dict -> recurse
filtered[k] = capi_filter_localised(v)
elif isinstance(v, list): # list of dicts -> recurse
filtered[k] = [capi_filter_localised(x) if hasattr(x, 'items') else x for x in v]
else:
filtered[k] = v
return filtered
def journal_entry( # noqa: C901, CCR001
cmdr: str,
is_beta: bool,
@ -1776,6 +1945,9 @@ def journal_entry( # noqa: C901, CCR001
elif event_name == 'navroute':
return this.eddn.export_journal_navroute(cmdr, is_beta, entry)
elif event_name == 'fcmaterials':
return this.eddn.export_journal_fcmaterials(cmdr, is_beta, entry)
elif event_name == 'approachsettlement':
# An `ApproachSettlement` can appear *before* `Location` if you
# logged at one. We won't have necessary augmentation data