<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
	<id>http://osimdev.org/wiki/index.php?action=history&amp;feed=atom&amp;title=OpenSimulator_Internals%2FAsset_Connector</id>
	<title>OpenSimulator Internals/Asset Connector - Revision history</title>
	<link rel="self" type="application/atom+xml" href="http://osimdev.org/wiki/index.php?action=history&amp;feed=atom&amp;title=OpenSimulator_Internals%2FAsset_Connector"/>
	<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Asset_Connector&amp;action=history"/>
	<updated>2026-08-04T15:40:35Z</updated>
	<subtitle>Revision history for this page on the wiki</subtitle>
	<generator>MediaWiki 1.45.3</generator>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Asset_Connector&amp;diff=28&amp;oldid=prev</id>
		<title>Jwbshaw: update with more info</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Asset_Connector&amp;diff=28&amp;oldid=prev"/>
		<updated>2026-06-22T08:59:00Z</updated>

		<summary type="html">&lt;p&gt;update with more info&lt;/p&gt;
&lt;a href=&quot;http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Asset_Connector&amp;amp;diff=28&amp;amp;oldid=27&quot;&gt;Show changes&lt;/a&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
	<entry>
		<id>http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Asset_Connector&amp;diff=27&amp;oldid=prev</id>
		<title>Jwbshaw: first</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Asset_Connector&amp;diff=27&amp;oldid=prev"/>
		<updated>2026-06-21T17:47:06Z</updated>

		<summary type="html">&lt;p&gt;first&lt;/p&gt;
&lt;p&gt;&lt;b&gt;New page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;= OpenSimulator Internals/Asset Connector =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
The asset connector chain connects simulator code to the asset service. It handles local, grid, and HyperGrid asset retrieval transparently through a single interface.&lt;br /&gt;
&lt;br /&gt;
In OpenSimulator 0.9.2, LocalAssetServiceConnector, RemoteAssetServiceConnector, and HGAssetBroker were consolidated into a single module: RegionAssetConnector.&lt;br /&gt;
&lt;br /&gt;
See [[OpenSimulator Internals/Connector Architecture]] for the general connector pattern.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Source Files ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! File !! Location&lt;br /&gt;
|-&lt;br /&gt;
| RegionAssetConnectorModule.cs || OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/&lt;br /&gt;
|-&lt;br /&gt;
| LocalAssetServiceConnector.cs || OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/ (tests only)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Configuration ==&lt;br /&gt;
&lt;br /&gt;
RegionAssetConnector is selected via [Modules] in OpenSim.ini:&lt;br /&gt;
&lt;br /&gt;
 [Modules]&lt;br /&gt;
 AssetServices = &amp;quot;RegionAssetConnector&amp;quot;&lt;br /&gt;
 &lt;br /&gt;
 [AssetService]&lt;br /&gt;
 LocalGridAssetService = &amp;quot;OpenSim.Services.AssetService.dll:AssetService&amp;quot;&lt;br /&gt;
 HypergridAssetService = &amp;quot;OpenSim.Services.AssetService.dll:HGAssetService&amp;quot;&lt;br /&gt;
&lt;br /&gt;
LocalGridAssetService is required -- connector throws on startup if missing.&lt;br /&gt;
&lt;br /&gt;
HypergridAssetService is optional -- HyperGrid asset transfer is disabled if not configured.&lt;br /&gt;
&lt;br /&gt;
HyperGrid import/export permissions are configured in [HGAssetService].&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Initialisation Sequence ==&lt;br /&gt;
&lt;br /&gt;
# Reads AssetServices from [Modules] -- exits if name does not match&lt;br /&gt;
# Loads LocalGridAssetService plugin -- throws if missing or fails to load&lt;br /&gt;
# Loads HypergridAssetService plugin -- optional, skipped if not configured&lt;br /&gt;
# Loads AssetPermissions from [HGAssetService] if HyperGrid enabled&lt;br /&gt;
# Creates two worker queues:&lt;br /&gt;
#* m_localRequestsQueue (&amp;quot;GetAssetsWorkers&amp;quot;, 2 threads, 2000 capacity)&lt;br /&gt;
#* m_remoteRequestsQueue (&amp;quot;GetRemoteAssetsWorkers&amp;quot;, 2 threads, 2000 capacity)&lt;br /&gt;
# Cache (m_Cache) is acquired in RegionLoaded(), not Initialise(). Must implement ISharedRegionModule or is rejected.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== HyperGrid ID Detection ==&lt;br /&gt;
&lt;br /&gt;
 private bool IsHG(string id)&lt;br /&gt;
 {&lt;br /&gt;
     return id.Length &amp;gt; 0 &amp;amp;&amp;amp; (id[0] == &amp;#039;h&amp;#039; || id[0] == &amp;#039;H&amp;#039;);&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
HyperGrid asset IDs are HTTP URIs. IsHG() checks only the first character. All routing decisions flow from this check.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Call Paths ==&lt;br /&gt;
&lt;br /&gt;
=== Synchronous Get -- local asset ===&lt;br /&gt;
&lt;br /&gt;
# Scene.AssetService.Get(id)&lt;br /&gt;
# IsHG(id) = false&lt;br /&gt;
# Check m_Cache.Get() -- return asset if hit, return null if negatively cached&lt;br /&gt;
# GetFromLocal(id) -- calls m_localConnector.Get(id) directly (inlined)&lt;br /&gt;
# On miss: m_Cache.CacheNegative(id)&lt;br /&gt;
# On hit: m_Cache.Cache(asset), return asset&lt;br /&gt;
&lt;br /&gt;
=== Synchronous Get -- HyperGrid asset ===&lt;br /&gt;
&lt;br /&gt;
# Scene.AssetService.Get(id)&lt;br /&gt;
# IsHG(id) = true&lt;br /&gt;
# GetForeign(id):&lt;br /&gt;
#* Util.ParseForeignAssetID(id) -- extracts URI and UUID string&lt;br /&gt;
#* Check m_Cache.GetCached(uuidstr)&lt;br /&gt;
#* GetFromLocal(uuidstr) -- check local store first&lt;br /&gt;
#* If not found locally: GetFromForeign(uuidstr, uri) via m_HGConnector&lt;br /&gt;
# Check m_AssetPerms.AllowedImport() -- return null if not permitted&lt;br /&gt;
# Store(asset) -- persist to local grid if permitted&lt;br /&gt;
# Return asset&lt;br /&gt;
&lt;br /&gt;
=== Synchronous Get -- with known foreign service URI ===&lt;br /&gt;
&lt;br /&gt;
# Get(id, ForeignAssetService, StoreOnLocalGrid)&lt;br /&gt;
# Check m_Cache.GetCached(id)&lt;br /&gt;
# GetFromLocal(id)&lt;br /&gt;
# On local miss: GetFromForeign(id, ForeignAssetService)&lt;br /&gt;
#* Check AssetPerms.AllowedImport() -- CacheNegative and return null if denied&lt;br /&gt;
#* StoreLocal(asset) if StoreOnLocalGrid=true&lt;br /&gt;
#* Cache(asset)&lt;br /&gt;
# On foreign miss: CacheNegative(id)&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous Get -- local ===&lt;br /&gt;
&lt;br /&gt;
# Get(id, sender, callBack)&lt;br /&gt;
# Check m_Cache.GetFromMemory() -- invoke callback immediately if found or negatively cached&lt;br /&gt;
# UUID.Zero check -- invoke callback with null and return false&lt;br /&gt;
# Lock m_AssetHandlers:&lt;br /&gt;
#* If request already in-flight for this id: append callback to handler list, return&lt;br /&gt;
#* Otherwise: create handler list, add to m_AssetHandlers, enqueue id to m_localRequestsQueue&lt;br /&gt;
# AssetRequestProcessor dequeues, calls Get(id), notifies all handlers via FireAndForget&lt;br /&gt;
&lt;br /&gt;
=== Asynchronous Get -- HyperGrid ===&lt;br /&gt;
&lt;br /&gt;
# Get(id, ForeignAssetService, StoreOnLocalGrid, callBack)&lt;br /&gt;
# Same cache and deduplication logic as async local&lt;br /&gt;
# If ForeignAssetService is empty: enqueue to m_localRequestsQueue&lt;br /&gt;
# Otherwise: enqueue ForeignAssetServiceGetData struct to m_remoteRequestsQueue&lt;br /&gt;
# AssetRequestProcessor calls Get(id, ForeignAssetService, StoreOnLocalGrid)&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Request Deduplication ==&lt;br /&gt;
&lt;br /&gt;
m_AssetHandlers (Dictionary&amp;lt;string, List&amp;lt;SimpleAssetRetrieved&amp;gt;&amp;gt;) prevents duplicate in-flight requests for the same asset ID. If a second async request arrives for an asset already being fetched, its callback is appended to the existing handler list. When the fetch completes, all waiting callbacks are notified via FireAndForget.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Store Paths ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Condition !! Behaviour&lt;br /&gt;
|-&lt;br /&gt;
| HyperGrid asset, Local or Temporary flag set || Return null -- not stored&lt;br /&gt;
|-&lt;br /&gt;
| HyperGrid asset, export not permitted by AssetPermissions || Return empty string&lt;br /&gt;
|-&lt;br /&gt;
| HyperGrid asset, permitted || StoreForeign() via m_HGConnector, cache on success&lt;br /&gt;
|-&lt;br /&gt;
| Local asset, Local or Temporary flag set || Cache only, not persisted to database&lt;br /&gt;
|-&lt;br /&gt;
| Local asset, normal || Cache and StoreLocal() via m_localConnector&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
UpdateContent() and Delete() always return false for HyperGrid assets.&lt;br /&gt;
&lt;br /&gt;
AssetsExist() routes entirely to m_localConnector if no HG IDs present, entirely to m_HGConnector if any HG IDs present.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Shutdown ==&lt;br /&gt;
&lt;br /&gt;
Close() disposes both worker queues and sets them to null.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== See Also ==&lt;br /&gt;
&lt;br /&gt;
* [[OpenSimulator Internals/Connector Architecture]]&lt;br /&gt;
* [[OpenSimulator Internals/AssetService]]&lt;br /&gt;
* [[OpenSimulator Internals/Data Dictionaries#assets|assets table]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
</feed>