From 5e7dba726896fcb84882b53952651742926e6efb Mon Sep 17 00:00:00 2001 From: Tleiades Hax Date: Fri, 26 Oct 2007 11:46:27 +0000 Subject: Very early first implementation of grid based assets. Run this on a major grid, and weep --- .../Framework/Communications/Cache/AssetCache.cs | 11 +- .../Communications/Cache/AssetServerBase.cs | 36 ++--- .../Communications/Cache/GridAssetClient.cs | 160 +++++++++++++++++++++ .../RestClient/GenericAsyncResult.cs | 2 +- .../Communications/RestClient/RestClient.cs | 101 +++++++++++-- OpenSim/Framework/Data.MySQL/MySQLAssetData.cs | 30 ++-- OpenSim/Framework/General/Types/AssetBase.cs | 2 + 7 files changed, 290 insertions(+), 52 deletions(-) create mode 100644 OpenSim/Framework/Communications/Cache/GridAssetClient.cs (limited to 'OpenSim/Framework') diff --git a/OpenSim/Framework/Communications/Cache/AssetCache.cs b/OpenSim/Framework/Communications/Cache/AssetCache.cs index 271934f..95183ad 100644 --- a/OpenSim/Framework/Communications/Cache/AssetCache.cs +++ b/OpenSim/Framework/Communications/Cache/AssetCache.cs @@ -36,6 +36,7 @@ using libsecondlife.Packets; using OpenSim.Framework.Interfaces; using OpenSim.Framework.Types; using OpenSim.Framework.Utilities; +using OpenSim.Framework.Console; namespace OpenSim.Framework.Communications.Cache { @@ -319,17 +320,19 @@ namespace OpenSim.Framework.Communications.Cache public void AssetNotFound(LLUUID assetID) { - /* if (this.RequestedTextures.ContainsKey(assetID)) { + MainLog.Instance.Warn("ASSET CACHE", "sending image not found for {0}", assetID); AssetRequest req = this.RequestedTextures[assetID]; ImageNotInDatabasePacket notFound = new ImageNotInDatabasePacket(); notFound.ImageID.ID = assetID; req.RequestUser.OutPacket(notFound); - //Console.WriteLine("sending image not found for " + assetID); - this.RequestedTextures.Remove(assetID); - }*/ + } + else + { + MainLog.Instance.Error("ASSET CACHE", "Cound not send image not found for {0}", assetID); + } } #region Assets diff --git a/OpenSim/Framework/Communications/Cache/AssetServerBase.cs b/OpenSim/Framework/Communications/Cache/AssetServerBase.cs index a3ec346..53efa16 100644 --- a/OpenSim/Framework/Communications/Cache/AssetServerBase.cs +++ b/OpenSim/Framework/Communications/Cache/AssetServerBase.cs @@ -108,23 +108,23 @@ namespace OpenSim.Framework.Communications.Cache public virtual List GetDefaultAssets() { List assets = new List(); - - assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000001", "Bricks", "bricks.jp2")); - assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000002", "Plywood", "plywood.jp2")); - assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000003", "Rocks", "rocks.jp2")); - assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000004", "Granite", "granite.jp2")); - assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000005", "Hardwood", "hardwood.jp2")); - assets.Add(CreateImageAsset("00000000-0000-0000-5005-000000000005", "Prim Base Texture", "plywood.jp2")); - assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000006", "Map Base Texture", "map_base.jp2")); - assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000007", "Map Texture", "map1.jp2")); - assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000010", "Female Body Texture", "femalebody.jp2")); - assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000011", "Female Bottom Texture", "femalebottom.jp2")); - assets.Add(CreateImageAsset("00000000-0000-0000-9999-000000000012", "Female Face Texture", "femaleface.jp2")); - - assets.Add(CreateAsset("77c41e39-38f9-f75a-024e-585989bbabbb", "Skin", "base_skin.dat", false)); - assets.Add(CreateAsset("66c41e39-38f9-f75a-024e-585989bfab73", "Shape", "base_shape.dat", false)); - assets.Add(CreateAsset("00000000-38f9-1111-024e-222222111110", "Shirt", "newshirt.dat", false)); - assets.Add(CreateAsset("00000000-38f9-1111-024e-222222111120", "Shirt", "newpants.dat", false)); + // These assets have been moved into the OpenSimAssetSet.XML file + //assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000001", "Bricks", "bricks.jp2")); + //assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000002", "Plywood", "plywood.jp2")); + //assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000003", "Rocks", "rocks.jp2")); + //assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000004", "Granite", "granite.jp2")); + //assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000005", "Hardwood", "hardwood.jp2")); + //assets.Add(CreateImageAsset("00000000-0000-1111-5005-000000000005", "Prim Base Texture", "plywood.jp2")); + //assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000006", "Map Base Texture", "map_base.jp2")); + //assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000007", "Map Texture", "map1.jp2")); + //assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000010", "Female Body Texture", "femalebody.jp2")); + //assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000011", "Female Bottom Texture", "femalebottom.jp2")); + //assets.Add(CreateImageAsset("00000000-0000-1111-9999-000000000012", "Female Face Texture", "femaleface.jp2")); + + //assets.Add(CreateAsset("77c41e39-38f9-f75a-024e-585989bbabbb", "Skin", "base_skin.dat", false)); + //assets.Add(CreateAsset("66c41e39-38f9-f75a-024e-585989bfab73", "Shape", "base_shape.dat", false)); + //assets.Add(CreateAsset("00000000-38f9-1111-024e-222222111110", "Shirt", "newshirt.dat", false)); + //assets.Add(CreateAsset("00000000-38f9-1111-024e-222222111120", "Shirt", "newpants.dat", false)); return assets; } @@ -185,4 +185,4 @@ namespace OpenSim.Framework.Communications.Cache } } } -} \ No newline at end of file +} diff --git a/OpenSim/Framework/Communications/Cache/GridAssetClient.cs b/OpenSim/Framework/Communications/Cache/GridAssetClient.cs new file mode 100644 index 0000000..fc77431 --- /dev/null +++ b/OpenSim/Framework/Communications/Cache/GridAssetClient.cs @@ -0,0 +1,160 @@ +/* +* Copyright (c) Contributors, http://www.openmetaverse.org/ +* See CONTRIBUTORS.TXT for a full list of copyright holders. +* +* Redistribution and use in source and binary forms, with or without +* modification, are permitted provided that the following conditions are met: +* * Redistributions of source code must retain the above copyright +* notice, this list of conditions and the following disclaimer. +* * Redistributions in binary form must reproduce the above copyright +* notice, this list of conditions and the following disclaimer in the +* documentation and/or other materials provided with the distribution. +* * Neither the name of the OpenSim Project nor the +* names of its contributors may be used to endorse or promote products +* derived from this software without specific prior written permission. +* +* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS AND ANY +* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +* +*/ +using System; +using System.IO; +using System.Threading; +using System.Reflection; +using System.Xml.Serialization; + +using libsecondlife; + +using Nini.Config; +using OpenSim.Framework.Console; +using OpenSim.Framework.Interfaces; +using OpenSim.Framework.Types; +using OpenSim.Framework.Utilities; +using OpenSim.Framework.Communications; + +namespace OpenSim.Framework.Communications.Cache +{ + public class GridAssetClient : IAssetServer + { + private string _assetServerUrl; + private IAssetReceiver _receiver; + + public GridAssetClient(string serverUrl) + { + _assetServerUrl = serverUrl; + } + + #region IAssetServer Members + + public void SetReceiver(IAssetReceiver receiver) + { + _receiver = receiver; + } + + public void FetchAsset(LLUUID assetID, bool isTexture) + { + Stream s = null; + try + { + + MainLog.Instance.Debug("ASSETCACHE", "Querying for {0}", assetID.ToString()); + + RestClient rc = new RestClient(_assetServerUrl); + rc.AddResourcePath("assets"); + rc.AddResourcePath(assetID.ToString()); + if (isTexture) + rc.AddQueryParameter("texture"); + + rc.RequestMethod = "GET"; + s = rc.Request(); + + if (s.Length > 0) + { + XmlSerializer xs = new XmlSerializer(typeof(AssetBase)); + AssetBase asset = (AssetBase)xs.Deserialize(s); + + _receiver.AssetReceived(asset, isTexture); + } + else + { + MainLog.Instance.Debug("ASSETCACHE", "Asset not found {0}", assetID.ToString()); + _receiver.AssetNotFound(assetID); + } + } + catch (Exception e) + { + MainLog.Instance.Error("ASSETCACHE", e.Message); + MainLog.Instance.Error("ASSETCACHE", e.StackTrace); + } + } + + public void UpdateAsset(AssetBase asset) + { + throw new Exception("The method or operation is not implemented."); + } + + public void StoreAndCommitAsset(AssetBase asset) + { + try + { + MemoryStream s = new MemoryStream(); + + XmlSerializer xs = new XmlSerializer(typeof(AssetBase)); + xs.Serialize(s, asset); + RestClient rc = new RestClient(_assetServerUrl); + rc.AddResourcePath("assets"); + rc.RequestMethod = "POST"; + rc.Request(s); + } + catch (Exception e) + { + MainLog.Instance.Error("ASSETS", e.Message); + } + } + + public void Close() + { + throw new Exception("The method or operation is not implemented."); + } + + public void LoadAsset(AssetBase info, bool image, string filename) + { + throw new Exception("The method or operation is not implemented."); + } + + public System.Collections.Generic.List GetDefaultAssets() + { + throw new Exception("The method or operation is not implemented."); + } + + public AssetBase CreateImageAsset(string assetIdStr, string name, string filename) + { + throw new Exception("The method or operation is not implemented."); + } + + public void ForEachDefaultAsset(Action action) + { + throw new Exception("The method or operation is not implemented."); + } + + public AssetBase CreateAsset(string assetIdStr, string name, string filename, bool isImage) + { + throw new Exception("The method or operation is not implemented."); + } + + public void ForEachXmlAsset(Action action) + { + throw new Exception("The method or operation is not implemented."); + } + + #endregion + } +} diff --git a/OpenSim/Framework/Communications/RestClient/GenericAsyncResult.cs b/OpenSim/Framework/Communications/RestClient/GenericAsyncResult.cs index 55456ae..c821fa4 100644 --- a/OpenSim/Framework/Communications/RestClient/GenericAsyncResult.cs +++ b/OpenSim/Framework/Communications/RestClient/GenericAsyncResult.cs @@ -3,7 +3,7 @@ using System.Collections.Generic; using System.Text; using System.Threading; -namespace OpenSim.Framework.RestClient +namespace OpenSim.Framework.Communications { internal class SimpleAsyncResult : IAsyncResult { diff --git a/OpenSim/Framework/Communications/RestClient/RestClient.cs b/OpenSim/Framework/Communications/RestClient/RestClient.cs index 25fc61a..392669f 100644 --- a/OpenSim/Framework/Communications/RestClient/RestClient.cs +++ b/OpenSim/Framework/Communications/RestClient/RestClient.cs @@ -6,7 +6,9 @@ using System.Text; using System.Collections.Generic; using System.Threading; -namespace OpenSim.Framework.RestClient +using OpenSim.Framework.Console; + +namespace OpenSim.Framework.Communications { /// /// Implementation of a generic REST client @@ -25,8 +27,11 @@ namespace OpenSim.Framework.RestClient /// other threads to execute, while it waits for a response from the web-service. RestClient it self, can be /// invoked by the caller in either synchroneous mode or asynchroneous mode. /// - public class RestClient + public class RestClient { + + string realuri; + #region member variables /// /// The base Uri of the web-service e.g. http://www.google.com /// @@ -55,7 +60,7 @@ namespace OpenSim.Framework.RestClient /// /// MemoryStream representing the resultiong resource /// - MemoryStream _resource; + Stream _resource; /// /// WebRequest object, held as a member variable @@ -89,6 +94,9 @@ namespace OpenSim.Framework.RestClient /// private Exception _asyncException; + #endregion member variables + + #region constructors /// /// Instantiate a new RestClient /// @@ -100,8 +108,12 @@ namespace OpenSim.Framework.RestClient _resource = new MemoryStream(); _request = null; _response = null; + _lock = new object(); } + object _lock; + #endregion constructors + /// /// Add a path element to the query, e.g. assets /// @@ -125,6 +137,15 @@ namespace OpenSim.Framework.RestClient } /// + /// Add a query parameter to the Url + /// + /// Name of the parameter, e.g. min + public void AddQueryParameter(string name) + { + _parameterElements.Add(HttpUtility.UrlEncode(name), null); + } + + /// /// Web-Request method, e.g. GET, PUT, POST, DELETE /// public string RequestMethod @@ -185,9 +206,10 @@ namespace OpenSim.Framework.RestClient sb.Append(kv.Value); } } + realuri = sb.ToString(); return new Uri(sb.ToString()); } - + #region Async communications with server /// /// Async method, invoked when a block of data has been received from the service /// @@ -199,7 +221,6 @@ namespace OpenSim.Framework.RestClient Stream s = (Stream)ar.AsyncState; int read = s.EndRead(ar); - // Read the HTML page and then print it to the console. if (read > 0) { _resource.Write(_readbuf, 0, read); @@ -207,7 +228,6 @@ namespace OpenSim.Framework.RestClient // TODO! Implement timeout, without killing the server //ThreadPool.RegisterWaitForSingleObject(asynchronousResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true); - return; } else { @@ -261,32 +281,83 @@ namespace OpenSim.Framework.RestClient } } } + #endregion Async communications with server /// /// Perform synchroneous request /// public Stream Request() { + lock (_lock) + { + _request = (HttpWebRequest)WebRequest.Create(buildUri()); + _request.KeepAlive = false; + _request.ContentType = "application/xml"; + _request.Timeout = 200000; + _asyncException = null; + +// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request); + _response = (HttpWebResponse)_request.GetResponse(); + Stream src = _response.GetResponseStream(); + int length = src.Read(_readbuf, 0, BufferSize); + while(length > 0) + { + _resource.Write(_readbuf, 0, length); + length = src.Read(_readbuf, 0, BufferSize); + } + + + // TODO! Implement timeout, without killing the server + // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted + //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true); + +// _allDone.WaitOne(); + if (_response != null) + _response.Close(); + if (_asyncException != null) + throw _asyncException; + + if (_resource != null) + { + _resource.Flush(); + _resource.Seek(0, SeekOrigin.Begin); + } + + return _resource; + } + } + + public Stream Request(Stream src) + { _request = (HttpWebRequest)WebRequest.Create(buildUri()); _request.KeepAlive = false; - _request.ContentType = "text/html"; - _request.Timeout = 200; + _request.ContentType = "application/xml"; + _request.Timeout = 900000; + _request.Method = RequestMethod; _asyncException = null; + _request.ContentLength = src.Length; - IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request); + src.Seek(0, SeekOrigin.Begin); + Stream dst = _request.GetRequestStream(); + byte[] buf = new byte[1024]; + int length = src.Read(buf,0, 1024); + while (length > 0) + { + dst.Write(buf, 0, length); + length = src.Read(buf, 0, 1024); + } + _response = (HttpWebResponse)_request.GetResponse(); + +// IAsyncResult responseAsyncResult = _request.BeginGetResponse(new AsyncCallback(ResponseIsReadyDelegate), _request); // TODO! Implement timeout, without killing the server // this line implements the timeout, if there is a timeout, the callback fires and the request becomes aborted //ThreadPool.RegisterWaitForSingleObject(responseAsyncResult.AsyncWaitHandle, new WaitOrTimerCallback(TimeoutCallback), _request, DefaultTimeout, true); - _allDone.WaitOne(); - if(_response != null) - _response.Close(); - if (_asyncException != null) - throw _asyncException; - return _resource; + return null; } + #region Async Invocation public IAsyncResult BeginRequest(AsyncCallback callback, object state) { diff --git a/OpenSim/Framework/Data.MySQL/MySQLAssetData.cs b/OpenSim/Framework/Data.MySQL/MySQLAssetData.cs index a8f0fdb..0112474 100644 --- a/OpenSim/Framework/Data.MySQL/MySQLAssetData.cs +++ b/OpenSim/Framework/Data.MySQL/MySQLAssetData.cs @@ -71,22 +71,24 @@ namespace OpenSim.Framework.Data.MySQL public AssetBase FetchAsset(LLUUID assetID) { AssetBase asset = null; - - MySqlCommand cmd = new MySqlCommand("SELECT name, description, assetType, invType, local, temporary, data FROM assets WHERE id=?id", _dbConnection.Connection); - MySqlParameter p = cmd.Parameters.Add("?id", MySqlDbType.Binary, 16); - p.Value = assetID.GetBytes(); - using (MySqlDataReader dbReader = cmd.ExecuteReader(System.Data.CommandBehavior.SingleRow)) + lock (_dbConnection) { - if (dbReader.Read()) + MySqlCommand cmd = new MySqlCommand("SELECT name, description, assetType, invType, local, temporary, data FROM assets WHERE id=?id", _dbConnection.Connection); + MySqlParameter p = cmd.Parameters.Add("?id", MySqlDbType.Binary, 16); + p.Value = assetID.GetBytes(); + using (MySqlDataReader dbReader = cmd.ExecuteReader(System.Data.CommandBehavior.SingleRow)) { - asset = new AssetBase(); - asset.Data = (byte[])dbReader["data"]; - asset.Description = (string)dbReader["description"]; - asset.FullID = assetID; - asset.InvType = (sbyte)dbReader["invType"]; - asset.Local = ((sbyte)dbReader["local"]) != 0 ? true : false; - asset.Name = (string)dbReader["name"]; - asset.Type = (sbyte)dbReader["assetType"]; + if (dbReader.Read()) + { + asset = new AssetBase(); + asset.Data = (byte[])dbReader["data"]; + asset.Description = (string)dbReader["description"]; + asset.FullID = assetID; + asset.InvType = (sbyte)dbReader["invType"]; + asset.Local = ((sbyte)dbReader["local"]) != 0 ? true : false; + asset.Name = (string)dbReader["name"]; + asset.Type = (sbyte)dbReader["assetType"]; + } } } return asset; diff --git a/OpenSim/Framework/General/Types/AssetBase.cs b/OpenSim/Framework/General/Types/AssetBase.cs index 628724d..c34887c 100644 --- a/OpenSim/Framework/General/Types/AssetBase.cs +++ b/OpenSim/Framework/General/Types/AssetBase.cs @@ -25,10 +25,12 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ +using System; using libsecondlife; namespace OpenSim.Framework.Types { + [Serializable] public class AssetBase { public byte[] Data; -- cgit v1.1