30 using System.Threading;
31 using System.Collections.Generic;
33 using System.Reflection;
36 using OpenSim.Framework;
37 using OpenSim.Framework.Console;
38 using OpenSim.Services.Interfaces;
41 namespace OpenSim.Services.Connectors
45 private static readonly ILog m_log =
47 MethodBase.GetCurrentMethod().DeclaringType);
49 private string m_ServerURI = String.Empty;
51 private int m_retryCounter;
52 private Dictionary<int, List<AssetBase>> m_retryQueue =
new Dictionary<int, List<AssetBase>>();
53 private System.Timers.Timer m_retryTimer;
54 private int m_maxAssetRequestConcurrency = 30;
56 private delegate
void AssetRetrievedEx(
AssetBase asset);
62 private Dictionary<string, List<AssetRetrievedEx>> m_AssetHandlers =
new Dictionary<string, List<AssetRetrievedEx>>();
64 private Dictionary<string, string> m_UriMap =
new Dictionary<string, string>();
66 private Thread[] m_fetchThreads;
68 public int MaxAssetRequestConcurrency
70 get {
return m_maxAssetRequestConcurrency; }
71 set { m_maxAssetRequestConcurrency = value; }
80 m_ServerURI = serverURI.TrimEnd(
'/');
84 : base(source,
"AssetService")
91 IConfig netconfig = source.Configs[
"Network"];
92 if (netconfig != null)
93 m_maxAssetRequestConcurrency = netconfig.GetInt(
"MaxRequestConcurrency",m_maxAssetRequestConcurrency);
95 IConfig assetConfig = source.Configs[
"AssetService"];
96 if (assetConfig == null)
98 m_log.Error(
"[ASSET CONNECTOR]: AssetService missing from OpenSim.ini");
99 throw new Exception(
"Asset connector init error");
102 string serviceURI = assetConfig.GetString(
"AssetServerURI",
105 m_ServerURI = serviceURI;
107 if (serviceURI == String.Empty)
109 m_log.Error(
"[ASSET CONNECTOR]: No Server URI named in section AssetService");
110 throw new Exception(
"Asset connector init error");
114 m_retryTimer =
new System.Timers.Timer();
115 m_retryTimer.Elapsed +=
new ElapsedEventHandler(retryCheck);
116 m_retryTimer.Interval = 60000;
118 Uri serverUri =
new Uri(m_ServerURI);
120 string groupHost = serverUri.Host;
122 for (
int i = 0 ; i < 256 ; i++)
124 string prefix = i.ToString(
"x2");
125 groupHost = assetConfig.GetString(
"AssetServerHost_"+prefix, groupHost);
127 m_UriMap[prefix] = groupHost;
131 m_fetchThreads =
new Thread[2];
133 for (
int i = 0 ; i < 2 ; i++)
135 m_fetchThreads[i] =
new Thread(AssetRequestProcessor);
136 m_fetchThreads[i].Start();
140 private string MapServer(
string id)
142 if (m_UriMap.Count == 0)
145 UriBuilder serverUri =
new UriBuilder(m_ServerURI);
147 string prefix = id.Substring(0, 2).ToLower();
152 if (m_UriMap.ContainsKey(prefix))
153 host = m_UriMap[prefix];
155 host = m_UriMap[
"00"];
157 serverUri.Host = host;
161 string ret = serverUri.Uri.AbsoluteUri;
162 if (ret.EndsWith(
"/"))
163 ret = ret.Substring(0, ret.Length - 1);
170 if (m_retryCounter > 60)
171 m_retryCounter -= 60;
173 List<int> keys =
new List<int>();
174 foreach (
int a
in m_retryQueue.Keys)
178 foreach (
int a
in keys)
185 int timefactor = a ^ 2;
192 if (timefactor % a == 0)
195 List<AssetBase> retrylist = m_retryQueue[a];
196 m_retryQueue.Remove(a);
205 if (m_retryQueue.Count == 0)
221 string uri = MapServer(
id) +
"/assets/" + id;
225 asset = m_Cache.Get(id);
227 if (asset == null || asset.
Data == null || asset.
Data.Length == 0)
238 asset = SynchronousRestObjectRequester.MakeRequest<int,
AssetBase>(
"GET", uri, 0, m_Auth);
241 m_Cache.Cache(asset);
251 return m_Cache.Get(id);
262 if (fullAsset != null)
263 return fullAsset.Metadata;
266 string uri = MapServer(
id) +
"/assets/" +
id +
"/metadata";
278 if (fullAsset != null)
279 return fullAsset.Data;
284 rc.AddResourcePath(
"assets");
285 rc.AddResourcePath(id);
286 rc.AddResourcePath(
"data");
288 rc.RequestMethod =
"GET";
290 using (Stream s = rc.Request(m_Auth))
297 byte[] ret =
new byte[s.Length];
298 s.Read(ret, 0, (int)s.Length);
307 private class QueuedAssetRequest
313 private OpenMetaverse.BlockingQueue<QueuedAssetRequest> m_requestQueue =
314 new OpenMetaverse.BlockingQueue<QueuedAssetRequest>();
316 private void AssetRequestProcessor()
318 QueuedAssetRequest r;
322 r = m_requestQueue.Dequeue();
327 bool success =
false;
330 AssetBase a = SynchronousRestObjectRequester.MakeRequest<int,
AssetBase>(
"GET", uri, 0, 30000, m_Auth);
336 List<AssetRetrievedEx> handlers;
337 lock (m_AssetHandlers)
339 handlers = m_AssetHandlers[id];
340 m_AssetHandlers.Remove(id);
343 Util.FireAndForget(x =>
346 foreach (AssetRetrievedEx h
in handlers)
355 if (handlers != null)
369 List<AssetRetrievedEx> handlers;
370 lock (m_AssetHandlers)
372 handlers = m_AssetHandlers[id];
373 m_AssetHandlers.Remove(id);
375 if (handlers != null)
384 string uri = MapServer(
id) +
"/assets/" + id;
386 AssetBase asset = null;
388 asset = m_Cache.Get(id);
390 if (asset == null || asset.
Data == null || asset.
Data.Length == 0)
392 lock (m_AssetHandlers)
394 AssetRetrievedEx handlerEx =
new AssetRetrievedEx(delegate(AssetBase _asset) { handler(
id, sender, _asset); });
397 List<AssetRetrievedEx> handlers;
398 if (m_AssetHandlers.TryGetValue(
id, out handlers))
402 handlers.Add(handlerEx);
408 handlers =
new List<AssetRetrievedEx>();
409 handlers.Add(handlerEx);
411 m_AssetHandlers.Add(id, handlers);
414 QueuedAssetRequest request =
new QueuedAssetRequest();
418 m_requestQueue.Enqueue(request);
422 handler(
id, sender, asset);
430 string uri = m_ServerURI +
"/get_assets_exist";
435 exist = SynchronousRestObjectRequester.MakeRequest<
string[],
bool[]>(
"POST", uri, ids, m_Auth);
444 exist =
new bool[ids.Length];
449 string stringUUIDZero = UUID.Zero.ToString();
451 public string Store(AssetBase asset)
457 if (asset.
ID ==
string.Empty || asset.
ID == stringUUIDZero)
459 if (asset.
FullID == UUID.Zero)
461 asset.FullID = UUID.Random();
463 m_log.WarnFormat(
"[Assets] Zero ID: {0}",asset.Name);
464 asset.ID = asset.FullID.ToString();
467 if (asset.
FullID == UUID.Zero)
469 UUID uuid = UUID.Zero;
470 if (UUID.TryParse(asset.
ID, out uuid))
474 if(asset.
FullID == UUID.Zero)
476 m_log.WarnFormat(
"[Assets] Zero IDs: {0}",asset.Name);
477 asset.FullID = UUID.Random();
478 asset.ID = asset.FullID.ToString();
483 m_Cache.Cache(asset);
490 string uri = MapServer(asset.
FullID.ToString()) +
"/assets/";
495 newID = SynchronousRestObjectRequester.
496 MakeRequest<AssetBase,
string>(
"POST", uri, asset, 100000, m_Auth);
500 if (newID == null || newID == String.Empty || newID == stringUUIDZero)
503 asset.UploadAttempts++;
508 m_log.ErrorFormat(
"[Assets] Dropping asset {0} - Upload has been in the queue for too long.", asset.ID.ToString());
514 m_retryQueue.Add(asset.UploadAttempts,
new List<AssetBase>());
516 List<AssetBase> m_queue = m_retryQueue[asset.UploadAttempts];
518 m_log.WarnFormat(
"[Assets] Upload failed: {0} - Requeuing asset for another run.", asset.ID.ToString());
519 m_retryTimer.Start();
526 m_log.InfoFormat(
"[Assets] Upload of {0} succeeded after {1} failed attempts", asset.ID.ToString(), asset.
UploadAttempts.ToString());
528 if (newID != asset.
ID)
536 m_Cache.Cache(asset);
544 AssetBase asset = null;
547 asset = m_Cache.Get(id);
552 if (metadata == null)
555 asset =
new AssetBase(metadata.
FullID, metadata.
Name, metadata.
Type, UUID.Zero.ToString());
556 asset.Metadata = metadata;
560 string uri = MapServer(
id) +
"/assets/" + id;
565 m_Cache.Cache(asset);
574 string uri = MapServer(
id) +
"/assets/" + id;
AssetBase Get(string id)
Get an asset synchronously.
bool Get(string id, Object sender, AssetRetrieved handler)
Get an asset synchronously or asynchronously (depending on whether it is locally cached) and fire a c...
AssetServicesConnector(string serverURI)
bool Delete(string id)
Delete an asset
string Store(AssetBase asset)
Creates a new asset
virtual bool[] AssetsExist(string[] ids)
Check if assets exist in the database.
AssetServicesConnector(IConfigSource source)
AssetMetadata GetMetadata(string id)
Get an asset's metadata
bool Local
Is this a region only asset, or does this exist on the asset server also
void SetCache(IImprovedAssetCache cache)
Asset class. All Assets are reference by this class or a class derived from this class ...
virtual void Initialise(IConfigSource source)
bool UpdateContent(string id, byte[] data)
Update an asset's content
byte[] GetData(string id)
Get an asset's data, ignoring the metadata.
Implementation of a generic REST client
void retryCheck(object source, ElapsedEventArgs e)
delegate void AssetRetrieved(string id, Object sender, AssetBase asset)
string ID
Asset MetaData ID (transferring from UUID to string ID)
bool Temporary
Is this asset going to be saved to the asset database?
AssetBase GetCached(string id)
Synchronously fetches an asset from the local cache only.