policy-node/create-item: fix handling of linkables pending activation

Policies need to know if there are session items that are pending
activation. Linkables are not activated in the same order as nodes
appear, which causes problems for e.g. resolving target nodes, if some
of the linkables are pending.

Register linkables in create-items before they are activated.  When
activation completes, remove those that did not activate successfully.
Policies can filter out inactive items by tracking active-features
flags.

If there are existing linkables that are not ready, suspend policy-node
processing, and continue it only after all linkables are ready.
This commit is contained in:
Pauli Virtanen
2022-02-20 20:19:42 +02:00
parent edf0dc69d1
commit c6aa44ca26
4 changed files with 77 additions and 6 deletions

View File

@@ -58,24 +58,36 @@ end
function addItem (node, item_type)
local id = node["bound-id"]
local item
-- create item
items[id] = SessionItem ( item_type )
item = SessionItem ( item_type )
items[id] = item
-- configure item
if not items[id]:configure(configProperties(node)) then
Log.warning(items[id], "failed to configure item for node " .. tostring(id))
if not item:configure(configProperties(node)) then
Log.warning(item, "failed to configure item for node " .. tostring(id))
return
end
item:register ()
-- activate item
items[id]:activate (Features.ALL, function (item, e)
if e then
Log.message(item, "failed to activate item: " .. tostring(e));
if item then
item:remove ()
end
else
Log.info(item, "activated item for node " .. tostring(id))
-- Trigger object managers to update status
item:remove ()
if item["active-features"] ~= 0 then
item:register ()
end
end
end)
end

View File

@@ -237,6 +237,8 @@ linkables_om = ObjectManager { Interest { type = "SiLinkable",
-- only handle si-audio-adapter and si-node
Constraint {
"item.factory.name", "=", "si-audio-adapter", type = "pw-global" },
Constraint {
"active-features", "!", 0, type = "gobject" },
}
}
links_om = ObjectManager { Interest { type = "SiLink",

View File

@@ -199,6 +199,7 @@ linkables_om = ObjectManager {
-- only handle device si-audio-adapter items
Constraint { "item.factory.name", "=", "si-audio-adapter", type = "pw-global" },
Constraint { "item.node.type", "=", "device", type = "pw-global" },
Constraint { "active-features", "!", 0, type = "gobject" },
}
}
links_om = ObjectManager {

View File

@@ -15,6 +15,8 @@ config.follow = config.follow or false
local self = {}
self.scanning = false
self.pending_rescan = false
self.events_skipped = false
self.pending_error_timer = nil
function rescan()
for si in linkables_om:iterate() do
@@ -526,7 +528,51 @@ end
si_flags = {}
function checkPending ()
local pending_linkables = pending_linkables_om:get_n_objects ()
-- We cannot process linkables if some of them are pending activation,
-- because linkables do not appear in the same order as nodes,
-- and we cannot resolve target node references until all linkables
-- have appeared.
if self.pending_error_timer then
self.pending_error_timer:destroy ()
self.pending_error_timer = nil
end
if pending_linkables ~= 0 then
-- Wait for linkables to get it sync
Log.debug(string.format("pending %d linkable not ready",
pending_linkables))
self.events_skipped = true
-- To make bugs in activation easier to debug, emit an error message
-- if they occur. policy-node should never be suspended for 20sec.
self.pending_error_timer = Core.timeout_add(20000, function()
self.pending_error_timer = nil
if pending_linkables ~= 0 then
Log.message(string.format("%d pending linkable(s) not activated in 20sec. "
.. "This should never happen.", pending_linkables))
end
end)
return true
elseif self.events_skipped then
Log.debug("pending linkables ready")
self.events_skipped = false
scheduleRescan ()
return true
end
return false
end
function handleLinkable (si)
if checkPending () then
return
end
local valid, si_props = checkLinkable(si)
if not valid then
return
@@ -697,12 +743,21 @@ clients_om = ObjectManager { Interest { type = "client" } }
devices_om = ObjectManager { Interest { type = "device" } }
linkables_om = ObjectManager {
Interest {
type = "SiLinkable",
-- only handle si-audio-adapter and si-node
Constraint { "item.factory.name", "c", "si-audio-adapter", "si-node" },
Constraint { "active-features", "!", 0, type = "gobject" },
}
}
pending_linkables_om = ObjectManager {
Interest {
type = "SiLinkable",
-- only handle si-audio-adapter and si-node
Constraint { "item.factory.name", "c", "si-audio-adapter", "si-node" },
Constraint { "active-features", "=", 0, type = "gobject" },
}
}
@@ -786,5 +841,6 @@ metadata_om:activate()
endpoints_om:activate()
clients_om:activate()
linkables_om:activate()
pending_linkables_om:activate()
links_om:activate()
devices_om:activate()