<?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%2FConnector_Architecture%2FAsset_Connector</id>
	<title>OpenSimulator Internals/Connector Architecture/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%2FConnector_Architecture%2FAsset_Connector"/>
	<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/Asset_Connector&amp;action=history"/>
	<updated>2026-08-04T15:36:34Z</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/Connector_Architecture/Asset_Connector&amp;diff=69&amp;oldid=prev</id>
		<title>Jwbshaw: first</title>
		<link rel="alternate" type="text/html" href="http://osimdev.org/wiki/index.php?title=OpenSimulator_Internals/Connector_Architecture/Asset_Connector&amp;diff=69&amp;oldid=prev"/>
		<updated>2026-07-07T12:13:55Z</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/Connector Architecture/Asset Connector =&lt;br /&gt;
&lt;br /&gt;
== Overview ==&lt;br /&gt;
&lt;br /&gt;
The asset connector is the path between the region simulator and the ROBUST AssetService. It has two sides: the simulator-side modules that make outbound calls, and the ROBUST-side HTTP handlers that receive them.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== ROBUST Side ==&lt;br /&gt;
&lt;br /&gt;
=== AssetServiceConnector ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Server/Handlers/Asset/AssetServerConnector.cs&lt;br /&gt;
&lt;br /&gt;
The connector loaded by ROBUST from [ServiceList]. Instantiates the asset service implementation and registers all HTTP handlers.&lt;br /&gt;
&lt;br /&gt;
Config section defaults to &amp;quot;AssetService&amp;quot;; overridden by the configName argument from the connector string.&lt;br /&gt;
&lt;br /&gt;
Required config:&lt;br /&gt;
* LocalServiceModule -- DLL:class of the IAssetService implementation; throws if missing&lt;br /&gt;
&lt;br /&gt;
Optional config:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Key !! Default !! Notes&lt;br /&gt;
|-&lt;br /&gt;
| AllowRemoteDelete || false || If false, remote DELETE requests always return false&lt;br /&gt;
|-&lt;br /&gt;
| AllowRemoteDeleteAllTypes || false || If true (and AllowRemoteDelete = true), all asset types can be deleted remotely. If false, only Maptile assets&lt;br /&gt;
|-&lt;br /&gt;
| RedirectURL || (none) || If set, 404 GET responses redirect to this URL instead&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Handlers registered:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Handler !! Method !! Path&lt;br /&gt;
|-&lt;br /&gt;
| AssetServerGetHandler || GET || /assets&lt;br /&gt;
|-&lt;br /&gt;
| AssetServerPostHandler || POST || /assets&lt;br /&gt;
|-&lt;br /&gt;
| AssetServerDeleteHandler || DELETE || /assets&lt;br /&gt;
|-&lt;br /&gt;
| AssetsExistHandler || POST || /get_assets_exist&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
All handlers except AssetsExistHandler receive an IServiceAuth instance. AssetsExistHandler has no auth.&lt;br /&gt;
&lt;br /&gt;
Console commands registered:&lt;br /&gt;
* show asset &amp;lt;ID&amp;gt; -- displays metadata and first 80 bytes as hex&lt;br /&gt;
* delete asset &amp;lt;ID&amp;gt; -- deletes asset via IAssetService.Delete()&lt;br /&gt;
* dump asset &amp;lt;ID&amp;gt; -- writes raw asset data to a file named after the ID; refuses to overwrite existing files&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== AssetServerGetHandler ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Server/Handlers/Asset/AssetServerGetHandler.cs&lt;br /&gt;
&lt;br /&gt;
Handles: GET /assets&lt;br /&gt;
&lt;br /&gt;
URL patterns:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Path !! Calls !! Response&lt;br /&gt;
|-&lt;br /&gt;
| /assets/{id} || IAssetService.Get(id) || XML-serialized AssetBase; Content-Type: text/xml&lt;br /&gt;
|-&lt;br /&gt;
| /assets/{id}/data || IAssetService.GetData(id) || Raw binary data; Content-Type: application/octet-stream&lt;br /&gt;
|-&lt;br /&gt;
| /assets/{id}/metadata || IAssetService.GetMetadata(id) || XML-serialized AssetMetadata; Content-Type: SLUtil.SLAssetTypeToContentType(type)&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
404 handling: if RedirectURL is configured and the asset is not found, the response is an HTTP redirect to RedirectURL + original path rather than a 404. This allows chaining to a fallback asset server.&lt;br /&gt;
&lt;br /&gt;
Unknown path segments (anything other than &amp;quot;data&amp;quot; or &amp;quot;metadata&amp;quot; as the second segment) return 400 Bad Request.&lt;br /&gt;
&lt;br /&gt;
Note: the commented-out Content-Type line for the full asset GET shows the original intent was to use SLAssetTypeToContentType, but it was changed to always return &amp;quot;text/xml&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== AssetServerPostHandler ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Server/Handlers/Asset/AssetServerPostHandler.cs&lt;br /&gt;
&lt;br /&gt;
Handles: POST /assets&lt;br /&gt;
&lt;br /&gt;
Two behaviors depending on whether an ID is present in the path:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Path !! Behavior !! Calls !! Returns&lt;br /&gt;
|-&lt;br /&gt;
| POST /assets || Store new asset || IAssetService.Store(asset) || XML-serialized string (the assigned ID)&lt;br /&gt;
|-&lt;br /&gt;
| POST /assets/{id} || Update existing asset data || IAssetService.UpdateContent(id, asset.Data) || XML-serialized bool&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Request body: XML-serialized AssetBase in both cases. Returns 400 Bad Request if deserialization fails.&lt;br /&gt;
&lt;br /&gt;
The update path (with ID) only uses asset.Data from the deserialized body -- the rest of the AssetBase fields are ignored.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== AssetServerDeleteHandler ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Server/Handlers/Asset/AssetServerDeleteHandler.cs&lt;br /&gt;
&lt;br /&gt;
Handles: DELETE /assets&lt;br /&gt;
&lt;br /&gt;
AllowedRemoteDeleteTypes enum controls what can be deleted:&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Value !! Behavior&lt;br /&gt;
|-&lt;br /&gt;
| None || Always returns false; no delete attempted&lt;br /&gt;
|-&lt;br /&gt;
| MapTile || Fetches asset first; deletes only if AssetFlags.Maptile is set&lt;br /&gt;
|-&lt;br /&gt;
| All || Deletes any asset type&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
Sequence:&lt;br /&gt;
# If allowedTypes == None: skip, return false&lt;br /&gt;
# Fetch asset via IAssetService.Get(id) -- if not found, return false&lt;br /&gt;
# If allowedTypes == All OR asset has Maptile flag: call IAssetService.Delete(id)&lt;br /&gt;
# Otherwise: log debug message and return false&lt;br /&gt;
&lt;br /&gt;
Always returns XML-serialized bool.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== AssetsExistHandler ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Server/Handlers/Asset/AssetsExistHandler.cs&lt;br /&gt;
&lt;br /&gt;
Handles: POST /get_assets_exist&lt;br /&gt;
&lt;br /&gt;
Request body: XML-serialized string[] of asset IDs.&lt;br /&gt;
Response: XML-serialized bool[] -- one entry per ID, true if the asset exists.&lt;br /&gt;
&lt;br /&gt;
Calls IAssetService.AssetsExist(ids) directly. Returns 400 Bad Request if deserialization fails.&lt;br /&gt;
&lt;br /&gt;
No auth -- AssetsExistHandler is constructed without an IServiceAuth argument.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== Simulator Side ==&lt;br /&gt;
&lt;br /&gt;
=== RegionAssetConnectorModule ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Region/CoreModules/ServiceConnectorsOut/Asset/RegionAssetConnectorModule.cs&lt;br /&gt;
&lt;br /&gt;
The single region module replacing LocalAssetServiceConnector, RemoteAssetServiceConnector, and HGAssetBroker as of 0.9.2. Implements ISharedRegionModule.&lt;br /&gt;
&lt;br /&gt;
Acquires the asset cache in RegionLoaded(), not in AddRegion(). This is required because the cache module must be loaded first.&lt;br /&gt;
&lt;br /&gt;
Two worker queues:&lt;br /&gt;
* m_localRequestsQueue -- for local (non-HG) asset requests, 2 threads, capacity 2000&lt;br /&gt;
* m_remoteRequestsQueue -- for HG asset requests, 2 threads, capacity 2000&lt;br /&gt;
&lt;br /&gt;
Request deduplication via m_AssetHandlers dictionary -- multiple callers requesting the same ID share a single in-flight request.&lt;br /&gt;
&lt;br /&gt;
IsHG(id) check: inspects the first character of the asset ID. If &amp;#039;h&amp;#039; or &amp;#039;H&amp;#039;, the ID is an HTTP URI and the asset is foreign (HyperGrid). All other IDs are treated as local.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== AssetServicesConnector ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs&lt;br /&gt;
&lt;br /&gt;
The remote connector used for non-HG asset requests. Makes HTTP calls to the ROBUST asset service.&lt;br /&gt;
&lt;br /&gt;
URI pattern: m_ServerURI + &amp;quot;/assets/&amp;quot; + id&lt;br /&gt;
&lt;br /&gt;
Store() assigns a UUID client-side before sending if the asset has no ID. Routing is determined by the ID, so the UUID must be assigned before the request is dispatched.&lt;br /&gt;
&lt;br /&gt;
MaxAssetRequestConcurrency defaults to 8 -- limits parallel outbound GET requests.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
=== HGAssetServiceConnector ===&lt;br /&gt;
&lt;br /&gt;
 OpenSim/Services/Connectors/Asset/HGAssetServiceConnector.cs&lt;br /&gt;
&lt;br /&gt;
Wraps multiple AssetServicesConnector instances, one per foreign grid URL. Connectors are pooled and expire after 60 seconds of inactivity.&lt;br /&gt;
&lt;br /&gt;
IsHG(id) -- same first-character check as RegionAssetConnectorModule.&lt;br /&gt;
&lt;br /&gt;
AssetsExistHandler grouping: groups requested IDs by server URL, queries each foreign server separately.&lt;br /&gt;
&lt;br /&gt;
UpdateContent() and Delete() always return false -- foreign assets cannot be modified.&lt;br /&gt;
&lt;br /&gt;
----&lt;br /&gt;
&lt;br /&gt;
== HTTP API Summary ==&lt;br /&gt;
&lt;br /&gt;
{| class=&amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Method !! Path !! Purpose !! Auth&lt;br /&gt;
|-&lt;br /&gt;
| GET || /assets/{id} || Get full asset (metadata + data) as XML || Yes&lt;br /&gt;
|-&lt;br /&gt;
| GET || /assets/{id}/data || Get raw asset binary data || Yes&lt;br /&gt;
|-&lt;br /&gt;
| GET || /assets/{id}/metadata || Get asset metadata as XML || Yes&lt;br /&gt;
|-&lt;br /&gt;
| POST || /assets || Store new asset; returns assigned ID || Yes&lt;br /&gt;
|-&lt;br /&gt;
| POST || /assets/{id} || Update asset binary data || Yes&lt;br /&gt;
|-&lt;br /&gt;
| DELETE || /assets/{id} || Delete asset (subject to AllowedRemoteDeleteTypes) || Yes&lt;br /&gt;
|-&lt;br /&gt;
| POST || /get_assets_exist || Bulk existence check; returns bool[] || No&lt;br /&gt;
|}&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/Code Map/ROBUST]]&lt;br /&gt;
* [[OpenSimulator Internals/Code Map/Shared]]&lt;/div&gt;</summary>
		<author><name>Jwbshaw</name></author>
	</entry>
</feed>