mirror of
https://github.com/EDCD/EDMarketConnector.git
synced 2025-04-21 11:27:38 +03:00
Merge pull request #1653 from EDCD/enhancement/1595/eddn-fcmaterials-journal
EDDN: Implement Journal-based `fcmaterials/1` schema
This commit is contained in:
commit
3c30b34d39
178
plugins/eddn.py
178
plugins/eddn.py
@ -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
|
||||
|
Loading…
x
Reference in New Issue
Block a user