Start improving InventoryManager
This commit is contained in:
@@ -304,6 +304,9 @@ class JankStringyBytes(bytes):
|
||||
def __str__(self):
|
||||
return self.rstrip(b"\x00").decode("utf8", errors="replace")
|
||||
|
||||
def __bool__(self):
|
||||
return not (super().__eq__(b"") or super().__eq__(b"\x00"))
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(other, str):
|
||||
return str(self) == other
|
||||
|
||||
@@ -294,7 +294,7 @@ class InventoryModel(InventoryBase):
|
||||
|
||||
if not update_fields:
|
||||
# Update everything but the model parameter
|
||||
update_fields = set(node._get_fields_dict().keys()) - {"model"}
|
||||
update_fields = node.get_field_names()
|
||||
for field_name in update_fields:
|
||||
setattr(orig_node, field_name, getattr(node, field_name))
|
||||
return orig_node
|
||||
@@ -402,6 +402,10 @@ class InventoryNodeBase(InventoryBase, _HasName):
|
||||
default=None, init=False, hash=False, compare=False, repr=False
|
||||
)
|
||||
|
||||
@classmethod
|
||||
def get_field_names(cls) -> Set[str]:
|
||||
return set(cls._get_fields_dict().keys()) - {"model"}
|
||||
|
||||
@property
|
||||
def node_id(self) -> UUID:
|
||||
return getattr(self, self.ID_ATTR)
|
||||
@@ -602,6 +606,8 @@ class InventoryItem(InventoryNodeBase):
|
||||
permissions=InventoryPermissions(
|
||||
creator_id=block["CreatorID"],
|
||||
owner_id=block["OwnerID"],
|
||||
# Unknown, not sent in this schema
|
||||
last_owner_id=block.get("LastOwnerID", UUID.ZERO),
|
||||
group_id=block["GroupID"],
|
||||
base_mask=block["BaseMask"],
|
||||
owner_mask=block["OwnerMask"],
|
||||
@@ -628,7 +634,43 @@ class InventoryItem(InventoryNodeBase):
|
||||
if flavor == "ais":
|
||||
# There's little chance this differs from owner ID, just place it.
|
||||
val["agent_id"] = val["permissions"]["owner_id"]
|
||||
if val["type"] == AssetType.LINK:
|
||||
# For link items, there is no asset, only a linked ID.
|
||||
val["linked_id"] = val.pop("asset_id")
|
||||
# These don't exist either
|
||||
val.pop("permissions", None)
|
||||
val.pop("sale_info", None)
|
||||
return val
|
||||
|
||||
@classmethod
|
||||
def from_llsd(cls, inv_dict: Dict, flavor: str = "legacy"):
|
||||
if flavor == "ais" and inv_dict["type"] == AssetType.LINK:
|
||||
# Links get represented differently than other items for whatever reason.
|
||||
# This is incredibly annoying, under *NIX there's nothing really special about symlinks.
|
||||
inv_dict = inv_dict.copy()
|
||||
# Fill this in since it needs to be there
|
||||
if "permissions" not in inv_dict:
|
||||
inv_dict["permissions"] = InventoryPermissions(
|
||||
base_mask=0xFFffFFff,
|
||||
owner_mask=0xFFffFFff,
|
||||
group_mask=0xFFffFFff,
|
||||
everyone_mask=0,
|
||||
next_owner_mask=0xFFffFFff,
|
||||
creator_id=UUID.ZERO,
|
||||
owner_id=UUID.ZERO,
|
||||
last_owner_id=UUID.ZERO,
|
||||
group_id=UUID.ZERO,
|
||||
).to_llsd("ais")
|
||||
if "sale_info" not in inv_dict:
|
||||
inv_dict["sale_info"] = InventorySaleInfo(
|
||||
sale_type=SaleType.NOT,
|
||||
sale_price=0,
|
||||
).to_llsd("ais")
|
||||
# In the context of symlinks, asset id means linked item ID.
|
||||
# This is also how indra stores symlinks. Why the asymmetry in AIS if none of the
|
||||
# consumers actually want it? Who knows.
|
||||
inv_dict["asset_id"] = inv_dict.pop("linked_id")
|
||||
return super().from_llsd(inv_dict, flavor)
|
||||
|
||||
|
||||
INVENTORY_TYPES: Tuple[Type[InventoryNodeBase], ...] = (InventoryCategory, InventoryObject, InventoryItem)
|
||||
|
||||
@@ -23,8 +23,8 @@ class InventoryManager:
|
||||
self._load_skeleton()
|
||||
self._session.message_handler.subscribe("BulkUpdateInventory", self._handle_bulk_update_inventory)
|
||||
self._session.message_handler.subscribe("UpdateCreateInventoryItem", self._handle_update_create_inventory_item)
|
||||
self._session.message_handler.subscribe("UpdateInventoryItem", self._handle_update_inventory_item)
|
||||
self._session.message_handler.subscribe("RemoveInventoryItem", self._handle_remove_inventory_item)
|
||||
self._session.message_handler.subscribe("MoveInventoryItem", self._handle_move_inventory_item)
|
||||
|
||||
def _load_skeleton(self):
|
||||
assert not self.model.nodes
|
||||
@@ -148,14 +148,26 @@ class InventoryManager:
|
||||
for inventory_block in msg["InventoryData"]:
|
||||
self.model.upsert(InventoryItem.from_inventory_data(inventory_block))
|
||||
|
||||
def _handle_update_inventory_item(self, msg: Message):
|
||||
self._validate_recipient(msg["AgentData"]["AgentID"])
|
||||
for inventory_block in msg["InventoryData"]:
|
||||
self.model.update(InventoryItem.from_inventory_data(inventory_block))
|
||||
|
||||
def _handle_remove_inventory_item(self, msg: Message):
|
||||
self._validate_recipient(msg["AgentData"]["AgentID"])
|
||||
for inventory_block in msg["InventoryData"]:
|
||||
node = self.model.get(inventory_block["ItemID"])
|
||||
if node:
|
||||
self.model.unlink(node)
|
||||
|
||||
def _handle_remove_inventory_folder(self, msg: Message):
|
||||
self._validate_recipient(msg["AgentData"]["AgentID"])
|
||||
for folder_block in msg["FolderData"]:
|
||||
node = self.model.get(folder_block["FolderID"])
|
||||
if node:
|
||||
self.model.unlink(node)
|
||||
|
||||
def _handle_move_inventory_item(self, msg: Message):
|
||||
for inventory_block in msg["InventoryData"]:
|
||||
node = self.model.get(inventory_block["ItemID"])
|
||||
if not node:
|
||||
LOG.warning(f"Missing inventory item {inventory_block['ItemID']}")
|
||||
continue
|
||||
if inventory_block["NewName"]:
|
||||
node.name = str(inventory_block["NewName"])
|
||||
node.parent_id = inventory_block['FolderID']
|
||||
|
||||
Reference in New Issue
Block a user