SimianAssetServiceConnector.cs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693
  1. /*
  2. * Copyright (c) Contributors, http://opensimulator.org/
  3. * See CONTRIBUTORS.TXT for a full list of copyright holders.
  4. *
  5. * Redistribution and use in source and binary forms, with or without
  6. * modification, are permitted provided that the following conditions are met:
  7. * * Redistributions of source code must retain the above copyright
  8. * notice, this list of conditions and the following disclaimer.
  9. * * Redistributions in binary form must reproduce the above copyright
  10. * notice, this list of conditions and the following disclaimer in the
  11. * documentation and/or other materials provided with the distribution.
  12. * * Neither the name of the OpenSimulator Project nor the
  13. * names of its contributors may be used to endorse or promote products
  14. * derived from this software without specific prior written permission.
  15. *
  16. * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
  17. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  18. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  19. * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
  20. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  21. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  22. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  23. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  24. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  25. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  26. */
  27. using System;
  28. using System.Collections.Generic;
  29. using System.Collections.Specialized;
  30. using System.IO;
  31. using System.Net;
  32. using System.Reflection;
  33. using log4net;
  34. using Mono.Addins;
  35. using Nini.Config;
  36. using OpenSim.Framework;
  37. using OpenSim.Region.Framework.Interfaces;
  38. using OpenSim.Region.Framework.Scenes;
  39. using OpenSim.Services.Interfaces;
  40. using OpenMetaverse;
  41. using OpenMetaverse.StructuredData;
  42. namespace OpenSim.Services.Connectors.SimianGrid
  43. {
  44. /// <summary>
  45. /// Connects to the SimianGrid asset service
  46. /// </summary>
  47. [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianAssetServiceConnector")]
  48. public class SimianAssetServiceConnector : IAssetService, ISharedRegionModule
  49. {
  50. private static readonly ILog m_log =
  51. LogManager.GetLogger(
  52. MethodBase.GetCurrentMethod().DeclaringType);
  53. private static string ZeroID = UUID.Zero.ToString();
  54. private string m_serverUrl = String.Empty;
  55. private IAssetCache m_cache;
  56. private bool m_Enabled = false;
  57. #region ISharedRegionModule
  58. public Type ReplaceableInterface { get { return null; } }
  59. public void RegionLoaded(Scene scene)
  60. {
  61. if (m_cache == null)
  62. {
  63. IAssetCache cache = scene.RequestModuleInterface<IAssetCache>();
  64. if (cache is ISharedRegionModule)
  65. m_cache = cache;
  66. }
  67. }
  68. public void PostInitialise() { }
  69. public void Close() { }
  70. public SimianAssetServiceConnector() { }
  71. public string Name { get { return "SimianAssetServiceConnector"; } }
  72. public void AddRegion(Scene scene) { if (m_Enabled) { scene.RegisterModuleInterface<IAssetService>(this); } }
  73. public void RemoveRegion(Scene scene) { if (m_Enabled) { scene.UnregisterModuleInterface<IAssetService>(this); } }
  74. #endregion ISharedRegionModule
  75. public SimianAssetServiceConnector(IConfigSource source)
  76. {
  77. CommonInit(source);
  78. }
  79. public SimianAssetServiceConnector(string url)
  80. {
  81. if (!url.EndsWith("/") && !url.EndsWith("="))
  82. url = url + '/';
  83. m_serverUrl = url;
  84. }
  85. public void Initialise(IConfigSource source)
  86. {
  87. IConfig moduleConfig = source.Configs["Modules"];
  88. if (moduleConfig != null)
  89. {
  90. string name = moduleConfig.GetString("AssetServices", "");
  91. if (name == Name)
  92. CommonInit(source);
  93. }
  94. }
  95. private void CommonInit(IConfigSource source)
  96. {
  97. IConfig gridConfig = source.Configs["AssetService"];
  98. if (gridConfig != null)
  99. {
  100. string serviceUrl = gridConfig.GetString("AssetServerURI");
  101. if (!String.IsNullOrEmpty(serviceUrl))
  102. {
  103. if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("="))
  104. serviceUrl = serviceUrl + '/';
  105. m_serverUrl = serviceUrl;
  106. }
  107. }
  108. if (String.IsNullOrEmpty(m_serverUrl))
  109. m_log.Info("[SIMIAN ASSET CONNECTOR]: No AssetServerURI specified, disabling connector");
  110. else
  111. m_Enabled = true;
  112. }
  113. #region IAssetService
  114. public AssetBase Get(string id)
  115. {
  116. if (String.IsNullOrEmpty(m_serverUrl))
  117. {
  118. m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
  119. throw new InvalidOperationException();
  120. }
  121. // Cache fetch
  122. if (m_cache != null)
  123. {
  124. AssetBase asset;
  125. if (!m_cache.Get(id, out asset))
  126. return null;
  127. if (asset != null)
  128. return asset;
  129. }
  130. return SimianGetOperation(id);
  131. }
  132. public AssetBase GetCached(string id)
  133. {
  134. AssetBase asset;
  135. if (m_cache != null)
  136. m_cache.Get(id, out asset);
  137. return null;
  138. }
  139. /// <summary>
  140. /// Get an asset's metadata
  141. /// </summary>
  142. /// <param name="id"></param>
  143. /// <returns></returns>
  144. public AssetMetadata GetMetadata(string id)
  145. {
  146. if (String.IsNullOrEmpty(m_serverUrl))
  147. {
  148. m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
  149. throw new InvalidOperationException();
  150. }
  151. // Cache fetch
  152. if (m_cache != null)
  153. {
  154. AssetBase asset;
  155. if (!m_cache.Get(id, out asset))
  156. return null;
  157. if (asset != null)
  158. return asset.Metadata;
  159. }
  160. // return GetRemoteMetadata(id);
  161. return SimianGetMetadataOperation(id);
  162. }
  163. public byte[] GetData(string id)
  164. {
  165. if (String.IsNullOrEmpty(m_serverUrl))
  166. {
  167. m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
  168. throw new InvalidOperationException();
  169. }
  170. AssetBase asset = Get(id);
  171. if (asset != null)
  172. return asset.Data;
  173. return null;
  174. }
  175. /// <summary>
  176. /// Get an asset asynchronously
  177. /// </summary>
  178. /// <param name="id">The asset id</param>
  179. /// <param name="sender">Represents the requester. Passed back via the handler</param>
  180. /// <param name="handler">The handler to call back once the asset has been retrieved</param>
  181. /// <returns>True if the id was parseable, false otherwise</returns>
  182. public bool Get(string id, Object sender, AssetRetrieved handler)
  183. {
  184. if (String.IsNullOrEmpty(m_serverUrl))
  185. {
  186. m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
  187. throw new InvalidOperationException();
  188. }
  189. // Cache fetch
  190. if (m_cache != null)
  191. {
  192. AssetBase asset;
  193. if (!m_cache.Get(id, out asset))
  194. return false;
  195. if (asset != null)
  196. {
  197. handler(id, sender, asset);
  198. return true;
  199. }
  200. }
  201. Util.FireAndForget(
  202. delegate(object o)
  203. {
  204. AssetBase asset = SimianGetOperation(id);
  205. handler(id, sender, asset);
  206. }, null, "SimianAssetServiceConnector.GetFromService"
  207. );
  208. return true;
  209. }
  210. public bool[] AssetsExist(string[] ids)
  211. {
  212. if (String.IsNullOrEmpty(m_serverUrl))
  213. {
  214. m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
  215. throw new InvalidOperationException();
  216. }
  217. bool[] exist = new bool[ids.Length];
  218. for (int i = 0; i < ids.Length; i++)
  219. {
  220. AssetMetadata metadata = GetMetadata(ids[i]);
  221. if (metadata != null)
  222. exist[i] = true;
  223. }
  224. return exist;
  225. }
  226. /// <summary>
  227. /// Creates a new asset
  228. /// </summary>
  229. /// Returns a random ID if none is passed into it
  230. /// <param name="asset"></param>
  231. /// <returns></returns>
  232. public string Store(AssetBase asset)
  233. {
  234. if (String.IsNullOrEmpty(m_serverUrl))
  235. {
  236. m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
  237. throw new InvalidOperationException();
  238. }
  239. bool storedInCache = false;
  240. // AssetID handling
  241. if (String.IsNullOrEmpty(asset.ID) || asset.ID == ZeroID)
  242. {
  243. asset.FullID = UUID.Random();
  244. asset.ID = asset.FullID.ToString();
  245. }
  246. // Cache handling
  247. if (m_cache != null)
  248. {
  249. m_cache.Cache(asset);
  250. storedInCache = true;
  251. }
  252. // Local asset handling
  253. if (asset.Local)
  254. {
  255. if (!storedInCache)
  256. {
  257. m_log.Error("Cannot store local " + asset.Metadata.ContentType + " asset without an asset cache");
  258. asset.ID = null;
  259. asset.FullID = UUID.Zero;
  260. }
  261. return asset.ID;
  262. }
  263. return SimianStoreOperation(asset);
  264. }
  265. /// <summary>
  266. /// Update an asset's content
  267. /// </summary>
  268. /// Attachments and bare scripts need this!!
  269. /// <param name="id"> </param>
  270. /// <param name="data"></param>
  271. /// <returns></returns>
  272. public bool UpdateContent(string id, byte[] data)
  273. {
  274. if (String.IsNullOrEmpty(m_serverUrl))
  275. {
  276. m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
  277. throw new InvalidOperationException();
  278. }
  279. AssetBase asset = Get(id);
  280. if (asset == null)
  281. {
  282. m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to fetch asset {0} for updating", id);
  283. return false;
  284. }
  285. asset.Data = data;
  286. string result = Store(asset);
  287. return !String.IsNullOrEmpty(result);
  288. }
  289. /// <summary>
  290. /// Delete an asset
  291. /// </summary>
  292. /// <param name="id"></param>
  293. /// <returns></returns>
  294. public bool Delete(string id)
  295. {
  296. if (String.IsNullOrEmpty(m_serverUrl))
  297. {
  298. m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured");
  299. throw new InvalidOperationException();
  300. }
  301. if (m_cache != null)
  302. m_cache.Expire(id);
  303. return SimianDeleteOperation(id);
  304. }
  305. #endregion IAssetService
  306. #region SimianOperations
  307. /// <summary>
  308. /// Invokes the xRemoveAsset operation on the simian server to delete an asset
  309. /// </summary>
  310. /// <param name="id"></param>
  311. /// <returns></returns>
  312. private bool SimianDeleteOperation(string id)
  313. {
  314. try
  315. {
  316. NameValueCollection requestArgs = new NameValueCollection
  317. {
  318. { "RequestMethod", "xRemoveAsset" },
  319. { "AssetID", id }
  320. };
  321. OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs);
  322. if (! response["Success"].AsBoolean())
  323. {
  324. m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: failed to delete asset; {0}",response["Message"].AsString());
  325. return false;
  326. }
  327. return true;
  328. }
  329. catch (Exception ex)
  330. {
  331. m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: failed to delete asset {0}; {1}", id, ex.Message);
  332. }
  333. return false;
  334. }
  335. /// <summary>
  336. /// Invokes the xAddAsset operation on the simian server to create or update an asset
  337. /// </summary>
  338. /// <param name="id"></param>
  339. /// <returns></returns>
  340. private string SimianStoreOperation(AssetBase asset)
  341. {
  342. try
  343. {
  344. NameValueCollection requestArgs = new NameValueCollection
  345. {
  346. { "RequestMethod", "xAddAsset" },
  347. { "ContentType", asset.Metadata.ContentType },
  348. { "EncodedData", Convert.ToBase64String(asset.Data) },
  349. { "AssetID", asset.FullID.ToString() },
  350. { "CreatorID", asset.Metadata.CreatorID },
  351. { "Temporary", asset.Temporary ? "1" : "0" },
  352. { "Name", asset.Name }
  353. };
  354. OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs);
  355. if (! response["Success"].AsBoolean())
  356. {
  357. m_log.WarnFormat("[SIMIAN ASSET CONNECTOR] failed to store asset; {0}",response["Message"].AsString());
  358. return null;
  359. }
  360. // asset.ID is always set before calling this function
  361. return asset.ID;
  362. }
  363. catch (Exception ex)
  364. {
  365. m_log.ErrorFormat("[SIMIAN ASSET CONNECTOR] failed to store asset; {0}",ex.Message);
  366. }
  367. return null;
  368. }
  369. /// <summary>
  370. /// Invokes the xGetAsset operation on the simian server to get data associated with an asset
  371. /// </summary>
  372. /// <param name="id"></param>
  373. /// <returns></returns>
  374. private AssetBase SimianGetOperation(string id)
  375. {
  376. try
  377. {
  378. NameValueCollection requestArgs = new NameValueCollection
  379. {
  380. { "RequestMethod", "xGetAsset" },
  381. { "ID", id }
  382. };
  383. OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs);
  384. if (! response["Success"].AsBoolean())
  385. {
  386. m_log.WarnFormat("[SIMIAN ASSET CONNECTOR] Failed to get asset; {0}",response["Message"].AsString());
  387. return null;
  388. }
  389. AssetBase asset = new AssetBase();
  390. asset.ID = id;
  391. asset.Name = String.Empty;
  392. asset.Metadata.ContentType = response["ContentType"].AsString(); // this will also set the asset Type property
  393. asset.CreatorID = response["CreatorID"].AsString();
  394. asset.Data = System.Convert.FromBase64String(response["EncodedData"].AsString());
  395. asset.Local = false;
  396. asset.Temporary = response["Temporary"];
  397. return asset;
  398. }
  399. catch (Exception ex)
  400. {
  401. m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: failed to retrieve asset {0}; {1}", id, ex.Message);
  402. }
  403. return null;
  404. }
  405. /// <summary>
  406. /// Invokes the xGetAssetMetadata operation on the simian server to retrieve metadata for an asset
  407. /// This operation is generally used to determine if an asset exists in the database
  408. /// </summary>
  409. /// <param name="id"></param>
  410. /// <returns></returns>
  411. private AssetMetadata SimianGetMetadataOperation(string id)
  412. {
  413. try
  414. {
  415. NameValueCollection requestArgs = new NameValueCollection
  416. {
  417. { "RequestMethod", "xGetAssetMetadata" },
  418. { "ID", id }
  419. };
  420. OSDMap response = SimianGrid.PostToService(m_serverUrl,requestArgs);
  421. if (! response["Success"].AsBoolean())
  422. {
  423. // this is not really an error, this call is used to test existence
  424. // m_log.DebugFormat("[SIMIAN ASSET CONNECTOR] Failed to get asset metadata; {0}",response["Message"].AsString());
  425. return null;
  426. }
  427. AssetMetadata metadata = new AssetMetadata();
  428. metadata.ID = id;
  429. metadata.ContentType = response["ContentType"].AsString();
  430. metadata.CreatorID = response["CreatorID"].AsString();
  431. metadata.Local = false;
  432. metadata.Temporary = response["Temporary"];
  433. string lastModifiedStr = response["Last-Modified"].AsString();
  434. if (! String.IsNullOrEmpty(lastModifiedStr))
  435. {
  436. DateTime lastModified;
  437. if (DateTime.TryParse(lastModifiedStr, out lastModified))
  438. metadata.CreationDate = lastModified;
  439. }
  440. return metadata;
  441. }
  442. catch (Exception ex)
  443. {
  444. m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to get asset metadata; {0}", ex.Message);
  445. }
  446. return null;
  447. }
  448. #endregion
  449. // private AssetMetadata GetRemoteMetadata(string id)
  450. // {
  451. // Uri url;
  452. // AssetMetadata metadata = null;
  453. // // Determine if id is an absolute URL or a grid-relative UUID
  454. // if (!Uri.TryCreate(id, UriKind.Absolute, out url))
  455. // url = new Uri(m_serverUrl + id);
  456. // try
  457. // {
  458. // HttpWebRequest request = UntrustedHttpWebRequest.Create(url);
  459. // request.Method = "HEAD";
  460. // using (WebResponse response = request.GetResponse())
  461. // {
  462. // using (Stream responseStream = response.GetResponseStream())
  463. // {
  464. // // Create the metadata object
  465. // metadata = new AssetMetadata();
  466. // metadata.ContentType = response.ContentType;
  467. // metadata.ID = id;
  468. // UUID uuid;
  469. // if (UUID.TryParse(id, out uuid))
  470. // metadata.FullID = uuid;
  471. // string lastModifiedStr = response.Headers.Get("Last-Modified");
  472. // if (!String.IsNullOrEmpty(lastModifiedStr))
  473. // {
  474. // DateTime lastModified;
  475. // if (DateTime.TryParse(lastModifiedStr, out lastModified))
  476. // metadata.CreationDate = lastModified;
  477. // }
  478. // }
  479. // }
  480. // }
  481. // catch (Exception ex)
  482. // {
  483. // m_log.Warn("[SIMIAN ASSET CONNECTOR]: Asset HEAD from " + url + " failed: " + ex.Message);
  484. // }
  485. // return metadata;
  486. // }
  487. // private AssetBase GetRemote(string id)
  488. // {
  489. // AssetBase asset = null;
  490. // Uri url;
  491. // // Determine if id is an absolute URL or a grid-relative UUID
  492. // if (!Uri.TryCreate(id, UriKind.Absolute, out url))
  493. // url = new Uri(m_serverUrl + id);
  494. // try
  495. // {
  496. // HttpWebRequest request = UntrustedHttpWebRequest.Create(url);
  497. // using (WebResponse response = request.GetResponse())
  498. // {
  499. // using (Stream responseStream = response.GetResponseStream())
  500. // {
  501. // string creatorID = response.Headers.GetOne("X-Asset-Creator-Id") ?? String.Empty;
  502. // // Create the asset object
  503. // asset = new AssetBase(id, String.Empty, SLUtil.ContentTypeToSLAssetType(response.ContentType), creatorID);
  504. // UUID assetID;
  505. // if (UUID.TryParse(id, out assetID))
  506. // asset.FullID = assetID;
  507. // // Grab the asset data from the response stream
  508. // using (MemoryStream stream = new MemoryStream())
  509. // {
  510. // responseStream.CopyStream(stream, Int32.MaxValue);
  511. // asset.Data = stream.ToArray();
  512. // }
  513. // }
  514. // }
  515. // // Cache store
  516. // if (m_cache != null && asset != null)
  517. // m_cache.Cache(asset);
  518. // return asset;
  519. // }
  520. // catch (Exception ex)
  521. // {
  522. // m_log.Warn("[SIMIAN ASSET CONNECTOR]: Asset GET from " + url + " failed: " + ex.Message);
  523. // return null;
  524. // }
  525. // }
  526. // private string StoreRemote(AssetBase asset)
  527. // {
  528. // // Distinguish public and private assets
  529. // bool isPublic = true;
  530. // switch ((AssetType)asset.Type)
  531. // {
  532. // case AssetType.CallingCard:
  533. // case AssetType.Gesture:
  534. // case AssetType.LSLBytecode:
  535. // case AssetType.LSLText:
  536. // isPublic = false;
  537. // break;
  538. // }
  539. // string errorMessage = null;
  540. // // Build the remote storage request
  541. // List<MultipartForm.Element> postParameters = new List<MultipartForm.Element>()
  542. // {
  543. // new MultipartForm.Parameter("AssetID", asset.FullID.ToString()),
  544. // new MultipartForm.Parameter("CreatorID", asset.Metadata.CreatorID),
  545. // new MultipartForm.Parameter("Temporary", asset.Temporary ? "1" : "0"),
  546. // new MultipartForm.Parameter("Public", isPublic ? "1" : "0"),
  547. // new MultipartForm.File("Asset", asset.Name, asset.Metadata.ContentType, asset.Data)
  548. // };
  549. // // Make the remote storage request
  550. // try
  551. // {
  552. // // Simian does not require the asset ID to be in the URL because it's in the post data.
  553. // // By appending it to the URL also, we allow caching proxies (squid) to invalidate asset URLs
  554. // HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl + asset.FullID.ToString());
  555. // using (HttpWebResponse response = MultipartForm.Post(request, postParameters))
  556. // {
  557. // using (Stream responseStream = response.GetResponseStream())
  558. // {
  559. // string responseStr = null;
  560. // try
  561. // {
  562. // responseStr = responseStream.GetStreamString();
  563. // OSD responseOSD = OSDParser.Deserialize(responseStr);
  564. // if (responseOSD.Type == OSDType.Map)
  565. // {
  566. // OSDMap responseMap = (OSDMap)responseOSD;
  567. // if (responseMap["Success"].AsBoolean())
  568. // return asset.ID;
  569. // else
  570. // errorMessage = "Upload failed: " + responseMap["Message"].AsString();
  571. // }
  572. // else
  573. // {
  574. // errorMessage = "Response format was invalid:\n" + responseStr;
  575. // }
  576. // }
  577. // catch (Exception ex)
  578. // {
  579. // if (!String.IsNullOrEmpty(responseStr))
  580. // errorMessage = "Failed to parse the response:\n" + responseStr;
  581. // else
  582. // errorMessage = "Failed to retrieve the response: " + ex.Message;
  583. // }
  584. // }
  585. // }
  586. // }
  587. // catch (WebException ex)
  588. // {
  589. // errorMessage = ex.Message;
  590. // }
  591. // m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to store asset \"{0}\" ({1}, {2}): {3}",
  592. // asset.Name, asset.ID, asset.Metadata.ContentType, errorMessage);
  593. // return null;
  594. // }
  595. }
  596. }