aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Grid/AssetInventoryServer/Extensions
diff options
context:
space:
mode:
authorMike Mazur2009-02-16 02:26:18 +0000
committerMike Mazur2009-02-16 02:26:18 +0000
commit3f3dfd7ac1c6c859a1d0db7315eeb0fb144b0ace (patch)
treedcde45e6974068d76004afea613adde1f725916f /OpenSim/Grid/AssetInventoryServer/Extensions
parent- implement and load NullMetrics module in AssetInventoryServer (diff)
downloadopensim-SC-3f3dfd7ac1c6c859a1d0db7315eeb0fb144b0ace.zip
opensim-SC-3f3dfd7ac1c6c859a1d0db7315eeb0fb144b0ace.tar.gz
opensim-SC-3f3dfd7ac1c6c859a1d0db7315eeb0fb144b0ace.tar.bz2
opensim-SC-3f3dfd7ac1c6c859a1d0db7315eeb0fb144b0ace.tar.xz
- added Simple AssetInventoryServer plugin (asset storage only)
- removed OpenSim storage and frontend classes in Extensions dir - put OpenSim plugins in OpenSim.Grid.AssetInventoryServer.Plugins.OpenSim namespace
Diffstat (limited to 'OpenSim/Grid/AssetInventoryServer/Extensions')
-rw-r--r--OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimFrontend.cs215
-rw-r--r--OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimMySQLStorage.cs311
-rw-r--r--OpenSim/Grid/AssetInventoryServer/Extensions/SimpleStorage.cs260
3 files changed, 0 insertions, 786 deletions
diff --git a/OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimFrontend.cs b/OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimFrontend.cs
deleted file mode 100644
index e34a235..0000000
--- a/OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimFrontend.cs
+++ /dev/null
@@ -1,215 +0,0 @@
1/*
2 * Copyright (c) 2008 Intel Corporation
3 * All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * -- Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * -- Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * -- Neither the name of the Intel Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30using System;
31using System.Collections.Generic;
32using System.Net;
33using System.IO;
34using System.Xml;
35using ExtensionLoader;
36using OpenMetaverse;
37using HttpServer;
38
39namespace OpenSim.Grid.AssetInventoryServer.Extensions
40{
41 public class OpenSimFrontend : IExtension<AssetInventoryServer>
42 {
43 AssetInventoryServer server;
44
45 public OpenSimFrontend()
46 {
47 }
48
49 public void Start(AssetInventoryServer server)
50 {
51 this.server = server;
52
53 // Asset request
54 server.HttpServer.AddHandler("get", null, @"^/assets/", AssetRequestHandler);
55
56 // Asset creation
57 server.HttpServer.AddHandler("post", null, @"^/assets/", AssetPostHandler);
58 }
59
60 public void Stop()
61 {
62 }
63
64 bool AssetRequestHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
65 {
66 UUID assetID;
67 // Split the URL up to get the asset ID out
68 string[] rawUrl = request.Uri.PathAndQuery.Split('/');
69
70 if (rawUrl.Length >= 3 && rawUrl[2].Length >= 36 && UUID.TryParse(rawUrl[2].Substring(0, 36), out assetID))
71 {
72 Metadata metadata;
73 byte[] assetData;
74 BackendResponse dataResponse;
75
76 if ((dataResponse = server.StorageProvider.TryFetchDataMetadata(assetID, out metadata, out assetData)) == BackendResponse.Success)
77 {
78 MemoryStream stream = new MemoryStream();
79
80 XmlWriterSettings settings = new XmlWriterSettings();
81 settings.Indent = true;
82 XmlWriter writer = XmlWriter.Create(stream, settings);
83
84 writer.WriteStartDocument();
85 writer.WriteStartElement("AssetBase");
86 writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
87 writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
88 writer.WriteStartElement("FullID");
89 writer.WriteStartElement("Guid");
90 writer.WriteString(assetID.ToString());
91 writer.WriteEndElement();
92 writer.WriteEndElement();
93 writer.WriteStartElement("ID");
94 writer.WriteString(assetID.ToString());
95 writer.WriteEndElement();
96 writer.WriteStartElement("Data");
97 writer.WriteBase64(assetData, 0, assetData.Length);
98 writer.WriteEndElement();
99 writer.WriteStartElement("Type");
100 writer.WriteValue(Utils.ContentTypeToSLAssetType(metadata.ContentType));
101 writer.WriteEndElement();
102 writer.WriteStartElement("Name");
103 writer.WriteString(metadata.Name);
104 writer.WriteEndElement();
105 writer.WriteStartElement("Description");
106 writer.WriteString(metadata.Description);
107 writer.WriteEndElement();
108 writer.WriteStartElement("Local");
109 writer.WriteValue(false);
110 writer.WriteEndElement();
111 writer.WriteStartElement("Temporary");
112 writer.WriteValue(metadata.Temporary);
113 writer.WriteEndElement();
114 writer.WriteEndElement();
115 writer.WriteEndDocument();
116
117 writer.Flush();
118 byte[] buffer = stream.GetBuffer();
119
120 response.Status = HttpStatusCode.OK;
121 response.ContentType = "application/xml";
122 response.ContentLength = stream.Length;
123 response.Body.Write(buffer, 0, (int)stream.Length);
124 response.Body.Flush();
125 }
126 else
127 {
128 Logger.Log.WarnFormat("Failed to fetch asset data or metadata for {0}: {1}", assetID, dataResponse);
129 response.Status = HttpStatusCode.NotFound;
130 }
131 }
132 else
133 {
134 Logger.Log.Warn("Unrecognized OpenSim asset request: " + request.Uri.PathAndQuery);
135 }
136
137 return true;
138 }
139
140 bool AssetPostHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
141 {
142 byte[] assetData = null;
143 Metadata metadata = new Metadata();
144
145 Logger.Log.Debug("Handling OpenSim asset upload");
146
147 try
148 {
149 using (XmlReader reader = XmlReader.Create(request.Body))
150 {
151 reader.MoveToContent();
152 reader.ReadStartElement("AssetBase");
153
154 reader.ReadStartElement("FullID");
155 UUID.TryParse(reader.ReadElementContentAsString("Guid", String.Empty), out metadata.ID);
156 reader.ReadEndElement();
157 reader.ReadStartElement("ID");
158 reader.Skip();
159 reader.ReadEndElement();
160
161 // HACK: Broken on Mono. https://bugzilla.novell.com/show_bug.cgi?id=464229
162 //int readBytes = 0;
163 //byte[] buffer = new byte[1024];
164 //MemoryStream stream = new MemoryStream();
165 //BinaryWriter writer = new BinaryWriter(stream);
166 //while ((readBytes = reader.ReadElementContentAsBase64(buffer, 0, buffer.Length)) > 0)
167 // writer.Write(buffer, 0, readBytes);
168 //writer.Flush();
169 //assetData = stream.GetBuffer();
170 //Array.Resize<byte>(ref assetData, (int)stream.Length);
171
172 assetData = Convert.FromBase64String(reader.ReadElementContentAsString());
173
174 int type;
175 Int32.TryParse(reader.ReadElementContentAsString("Type", String.Empty), out type);
176 metadata.ContentType = Utils.SLAssetTypeToContentType(type);
177 metadata.Name = reader.ReadElementContentAsString("Name", String.Empty);
178 metadata.Description = reader.ReadElementContentAsString("Description", String.Empty);
179 Boolean.TryParse(reader.ReadElementContentAsString("Local", String.Empty), out metadata.Temporary);
180 Boolean.TryParse(reader.ReadElementContentAsString("Temporary", String.Empty), out metadata.Temporary);
181
182 reader.ReadEndElement();
183 }
184
185 if (assetData != null && assetData.Length > 0)
186 {
187 metadata.SHA1 = OpenMetaverse.Utils.SHA1(assetData);
188 metadata.CreationDate = DateTime.Now;
189
190 BackendResponse storageResponse = server.StorageProvider.TryCreateAsset(metadata, assetData);
191
192 if (storageResponse == BackendResponse.Success)
193 response.Status = HttpStatusCode.Created;
194 else if (storageResponse == BackendResponse.NotFound)
195 response.Status = HttpStatusCode.NotFound;
196 else
197 response.Status = HttpStatusCode.InternalServerError;
198 }
199 else
200 {
201 Logger.Log.Warn("AssetPostHandler called with no asset data");
202 response.Status = HttpStatusCode.BadRequest;
203 }
204 }
205 catch (Exception ex)
206 {
207 Logger.Log.Warn("Failed to parse POST data (expecting AssetBase): " + ex.Message);
208 response.Status = HttpStatusCode.BadRequest;
209 }
210
211 Logger.Log.Debug("Finished handling OpenSim asset upload, Status: " + response.Status.ToString());
212 return true;
213 }
214 }
215}
diff --git a/OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimMySQLStorage.cs b/OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimMySQLStorage.cs
deleted file mode 100644
index 48fa25b..0000000
--- a/OpenSim/Grid/AssetInventoryServer/Extensions/OpenSimMySQLStorage.cs
+++ /dev/null
@@ -1,311 +0,0 @@
1/*
2 * Copyright (c) 2008 Intel Corporation
3 * All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * -- Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * -- Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * -- Neither the name of the Intel Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30using System;
31using System.Collections.Generic;
32using System.Net;
33using System.Data;
34using MySql.Data.MySqlClient;
35using ExtensionLoader;
36using ExtensionLoader.Config;
37using OpenMetaverse;
38using OpenMetaverse.StructuredData;
39
40namespace OpenSim.Grid.AssetInventoryServer.Extensions
41{
42 public class OpenSimMySQLStorage : IExtension<AssetInventoryServer>, IStorageProvider
43 {
44 const string EXTENSION_NAME = "OpenSimMySQLStorage"; // Used in metrics reporting
45
46 AssetInventoryServer server;
47
48 public OpenSimMySQLStorage()
49 {
50 }
51
52 #region Required Interfaces
53
54 public void Start(AssetInventoryServer server)
55 {
56 this.server = server;
57
58 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
59 {
60 try
61 {
62 dbConnection.Open();
63 Logger.Log.Info("Connected to MySQL storage backend: " + dbConnection.ServerVersion);
64 }
65 catch (MySqlException ex)
66 {
67 Logger.Log.Error("Connection to MySQL storage backend failed: " + ex.Message);
68 }
69 }
70 }
71
72 public void Stop()
73 {
74 }
75
76 public BackendResponse TryFetchMetadata(UUID assetID, out Metadata metadata)
77 {
78 metadata = null;
79 BackendResponse ret;
80
81 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
82 {
83 IDataReader reader;
84
85 try
86 {
87 dbConnection.Open();
88
89 IDbCommand command = dbConnection.CreateCommand();
90 command.CommandText = String.Format("SELECT name,description,assetType,temporary FROM assets WHERE id='{0}'", assetID.ToString());
91 reader = command.ExecuteReader();
92
93 if (reader.Read())
94 {
95 metadata = new Metadata();
96 metadata.CreationDate = OpenMetaverse.Utils.Epoch;
97 metadata.SHA1 = null;
98 metadata.ID = assetID;
99 metadata.Name = reader.GetString(0);
100 metadata.Description = reader.GetString(1);
101 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2));
102 metadata.Temporary = reader.GetBoolean(3);
103
104 ret = BackendResponse.Success;
105 }
106 else
107 {
108 ret = BackendResponse.NotFound;
109 }
110 }
111 catch (MySqlException ex)
112 {
113 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
114 ret = BackendResponse.Failure;
115 }
116 }
117
118 server.MetricsProvider.LogAssetMetadataFetch(EXTENSION_NAME, ret, assetID, DateTime.Now);
119 return ret;
120 }
121
122 public BackendResponse TryFetchData(UUID assetID, out byte[] assetData)
123 {
124 assetData = null;
125 BackendResponse ret;
126
127 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
128 {
129 IDataReader reader;
130
131 try
132 {
133 dbConnection.Open();
134
135 IDbCommand command = dbConnection.CreateCommand();
136 command.CommandText = String.Format("SELECT data FROM assets WHERE id='{0}'", assetID.ToString());
137 reader = command.ExecuteReader();
138
139 if (reader.Read())
140 {
141 assetData = (byte[])reader.GetValue(0);
142 ret = BackendResponse.Success;
143 }
144 else
145 {
146 ret = BackendResponse.NotFound;
147 }
148 }
149 catch (MySqlException ex)
150 {
151 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
152 ret = BackendResponse.Failure;
153 }
154 }
155
156 server.MetricsProvider.LogAssetDataFetch(EXTENSION_NAME, ret, assetID, (assetData != null ? assetData.Length : 0), DateTime.Now);
157 return ret;
158 }
159
160 public BackendResponse TryFetchDataMetadata(UUID assetID, out Metadata metadata, out byte[] assetData)
161 {
162 metadata = null;
163 assetData = null;
164 BackendResponse ret;
165
166 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
167 {
168 IDataReader reader;
169
170 try
171 {
172 dbConnection.Open();
173
174 IDbCommand command = dbConnection.CreateCommand();
175 command.CommandText = String.Format("SELECT name,description,assetType,temporary,data FROM assets WHERE id='{0}'", assetID.ToString());
176 reader = command.ExecuteReader();
177
178 if (reader.Read())
179 {
180 metadata = new Metadata();
181 metadata.CreationDate = OpenMetaverse.Utils.Epoch;
182 metadata.SHA1 = null;
183 metadata.ID = assetID;
184 metadata.Name = reader.GetString(0);
185 metadata.Description = reader.GetString(1);
186 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2));
187 metadata.Temporary = reader.GetBoolean(3);
188
189 assetData = (byte[])reader.GetValue(4);
190
191 ret = BackendResponse.Success;
192 }
193 else
194 {
195 ret = BackendResponse.NotFound;
196 }
197 }
198 catch (MySqlException ex)
199 {
200 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
201 ret = BackendResponse.Failure;
202 }
203 }
204
205 server.MetricsProvider.LogAssetMetadataFetch(EXTENSION_NAME, ret, assetID, DateTime.Now);
206 server.MetricsProvider.LogAssetDataFetch(EXTENSION_NAME, ret, assetID, (assetData != null ? assetData.Length : 0), DateTime.Now);
207 return ret;
208 }
209
210 public BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData, out UUID assetID)
211 {
212 assetID = metadata.ID = UUID.Random();
213 return TryCreateAsset(metadata, assetData);
214 }
215
216 public BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData)
217 {
218 BackendResponse ret;
219
220 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
221 {
222 try
223 {
224 dbConnection.Open();
225
226 MySqlCommand command = new MySqlCommand(
227 "REPLACE INTO assets (name,description,assetType,local,temporary,data,id) VALUES " +
228 "(?name,?description,?assetType,?local,?temporary,?data,?id)", dbConnection);
229
230 command.Parameters.AddWithValue("?name", metadata.Name);
231 command.Parameters.AddWithValue("?description", metadata.Description);
232 command.Parameters.AddWithValue("?assetType", Utils.ContentTypeToSLAssetType(metadata.ContentType));
233 command.Parameters.AddWithValue("?local", 0);
234 command.Parameters.AddWithValue("?temporary", metadata.Temporary);
235 command.Parameters.AddWithValue("?data", assetData);
236 command.Parameters.AddWithValue("?id", metadata.ID.ToString());
237
238 int rowsAffected = command.ExecuteNonQuery();
239 if (rowsAffected == 1)
240 {
241 ret = BackendResponse.Success;
242 }
243 else if (rowsAffected == 2)
244 {
245 Logger.Log.Info("Replaced asset " + metadata.ID.ToString());
246 ret = BackendResponse.Success;
247 }
248 else
249 {
250 Logger.Log.ErrorFormat("MySQL REPLACE query affected {0} rows", rowsAffected);
251 ret = BackendResponse.Failure;
252 }
253 }
254 catch (MySqlException ex)
255 {
256 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
257 ret = BackendResponse.Failure;
258 }
259 }
260
261 server.MetricsProvider.LogAssetCreate(EXTENSION_NAME, ret, metadata.ID, assetData.Length, DateTime.Now);
262 return ret;
263 }
264
265 public int ForEach(Action<Metadata> action, int start, int count)
266 {
267 int rowCount = 0;
268
269 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
270 {
271 MySqlDataReader reader;
272
273 try
274 {
275 dbConnection.Open();
276
277 MySqlCommand command = dbConnection.CreateCommand();
278 command.CommandText = String.Format("SELECT name,description,assetType,temporary,data,id FROM assets LIMIT {0}, {1}",
279 start, count);
280 reader = command.ExecuteReader();
281 }
282 catch (MySqlException ex)
283 {
284 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
285 return 0;
286 }
287
288 while (reader.Read())
289 {
290 Metadata metadata = new Metadata();
291 metadata.CreationDate = OpenMetaverse.Utils.Epoch;
292 metadata.Description = reader.GetString(1);
293 metadata.ID = UUID.Parse(reader.GetString(5));
294 metadata.Name = reader.GetString(0);
295 metadata.SHA1 = OpenMetaverse.Utils.SHA1((byte[])reader.GetValue(4));
296 metadata.Temporary = reader.GetBoolean(3);
297 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2));
298
299 action(metadata);
300 ++rowCount;
301 }
302
303 reader.Close();
304 }
305
306 return rowCount;
307 }
308
309 #endregion Required Interfaces
310 }
311}
diff --git a/OpenSim/Grid/AssetInventoryServer/Extensions/SimpleStorage.cs b/OpenSim/Grid/AssetInventoryServer/Extensions/SimpleStorage.cs
deleted file mode 100644
index 9456ef5..0000000
--- a/OpenSim/Grid/AssetInventoryServer/Extensions/SimpleStorage.cs
+++ /dev/null
@@ -1,260 +0,0 @@
1/*
2 * Copyright (c) 2008 Intel Corporation
3 * All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 *
8 * -- Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * -- Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * -- Neither the name of the Intel Corporation nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
20 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE INTEL OR ITS
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
24 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
25 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
26 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30using System;
31using System.Collections.Generic;
32using System.Net;
33using System.IO;
34using ExtensionLoader;
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37
38namespace OpenSim.Grid.AssetInventoryServer.Extensions
39{
40 public class SimpleStorage : IExtension<AssetInventoryServer>, IStorageProvider
41 {
42 const string EXTENSION_NAME = ""; // Used in metrics reporting
43 const string DEFAULT_DATA_DIR = "SimpleAssets";
44 const string TEMP_DATA_DIR = "SimpleAssetsTemp";
45
46 AssetInventoryServer server;
47 Dictionary<UUID, Metadata> metadataStorage;
48 Dictionary<UUID, string> filenames;
49
50 public SimpleStorage()
51 {
52 }
53
54 #region Required Interfaces
55
56 public void Start(AssetInventoryServer server)
57 {
58 this.server = server;
59 metadataStorage = new Dictionary<UUID, Metadata>();
60 filenames = new Dictionary<UUID, string>();
61
62 LoadFiles(DEFAULT_DATA_DIR, false);
63 LoadFiles(TEMP_DATA_DIR, true);
64
65 Logger.Log.InfoFormat("Initialized the store index with metadata for {0} assets",
66 metadataStorage.Count);
67 }
68
69 public void Stop()
70 {
71 WipeTemporary();
72 }
73
74 public BackendResponse TryFetchMetadata(UUID assetID, out Metadata metadata)
75 {
76 metadata = null;
77 BackendResponse ret;
78
79 if (metadataStorage.TryGetValue(assetID, out metadata))
80 ret = BackendResponse.Success;
81 else
82 ret = BackendResponse.NotFound;
83
84 server.MetricsProvider.LogAssetMetadataFetch(EXTENSION_NAME, ret, assetID, DateTime.Now);
85 return ret;
86 }
87
88 public BackendResponse TryFetchData(UUID assetID, out byte[] assetData)
89 {
90 assetData = null;
91 string filename;
92 BackendResponse ret;
93
94 if (filenames.TryGetValue(assetID, out filename))
95 {
96 try
97 {
98 assetData = File.ReadAllBytes(filename);
99 ret = BackendResponse.Success;
100 }
101 catch (Exception ex)
102 {
103 Logger.Log.ErrorFormat("Failed reading data for asset {0} from {1}: {2}", assetID, filename, ex.Message);
104 ret = BackendResponse.Failure;
105 }
106 }
107 else
108 {
109 ret = BackendResponse.NotFound;
110 }
111
112 server.MetricsProvider.LogAssetDataFetch(EXTENSION_NAME, ret, assetID, (assetData != null ? assetData.Length : 0), DateTime.Now);
113 return ret;
114 }
115
116 public BackendResponse TryFetchDataMetadata(UUID assetID, out Metadata metadata, out byte[] assetData)
117 {
118 metadata = null;
119 assetData = null;
120 string filename;
121 BackendResponse ret;
122
123 if (metadataStorage.TryGetValue(assetID, out metadata) &&
124 filenames.TryGetValue(assetID, out filename))
125 {
126 try
127 {
128 assetData = File.ReadAllBytes(filename);
129 ret = BackendResponse.Success;
130 }
131 catch (Exception ex)
132 {
133 Logger.Log.ErrorFormat("Failed reading data for asset {0} from {1}: {2}", assetID, filename, ex.Message);
134 ret = BackendResponse.Failure;
135 }
136 }
137 else
138 {
139 ret = BackendResponse.NotFound;
140 }
141
142 server.MetricsProvider.LogAssetMetadataFetch(EXTENSION_NAME, ret, assetID, DateTime.Now);
143 server.MetricsProvider.LogAssetDataFetch(EXTENSION_NAME, ret, assetID, (assetData != null ? assetData.Length : 0), DateTime.Now);
144 return ret;
145 }
146
147 public BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData, out UUID assetID)
148 {
149 assetID = metadata.ID = UUID.Random();
150 return TryCreateAsset(metadata, assetData);
151 }
152
153 public BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData)
154 {
155 BackendResponse ret;
156
157 string path;
158 string filename = String.Format("{0}.{1}", metadata.ID, Utils.ContentTypeToExtension(metadata.ContentType));
159
160 if (metadata.Temporary)
161 path = Path.Combine(TEMP_DATA_DIR, filename);
162 else
163 path = Path.Combine(DEFAULT_DATA_DIR, filename);
164
165 try
166 {
167 File.WriteAllBytes(path, assetData);
168 lock (filenames) filenames[metadata.ID] = path;
169
170 // Set the creation date to right now
171 metadata.CreationDate = DateTime.Now;
172
173 lock (metadataStorage)
174 metadataStorage[metadata.ID] = metadata;
175
176 ret = BackendResponse.Success;
177 }
178 catch (Exception ex)
179 {
180 Logger.Log.ErrorFormat("Failed writing data for asset {0} to {1}: {2}", metadata.ID, filename, ex.Message);
181 ret = BackendResponse.Failure;
182 }
183
184 server.MetricsProvider.LogAssetCreate(EXTENSION_NAME, ret, metadata.ID, assetData.Length, DateTime.Now);
185 return ret;
186 }
187
188 public int ForEach(Action<Metadata> action, int start, int count)
189 {
190 int rowCount = 0;
191
192 lock (metadataStorage)
193 {
194 foreach (Metadata metadata in metadataStorage.Values)
195 {
196 action(metadata);
197 ++rowCount;
198 }
199 }
200
201 return rowCount;
202 }
203
204 #endregion Required Interfaces
205
206 public void WipeTemporary()
207 {
208 if (Directory.Exists(TEMP_DATA_DIR))
209 {
210 try { Directory.Delete(TEMP_DATA_DIR); }
211 catch (Exception ex) { Logger.Log.Error(ex.Message); }
212 }
213 }
214
215 void LoadFiles(string folder, bool temporary)
216 {
217 // Try to create the directory if it doesn't already exist
218 if (!Directory.Exists(folder))
219 {
220 try { Directory.CreateDirectory(folder); }
221 catch (Exception ex)
222 {
223 Logger.Log.Warn(ex.Message);
224 return;
225 }
226 }
227
228 lock (metadataStorage)
229 {
230 try
231 {
232 string[] assets = Directory.GetFiles(folder);
233
234 for (int i = 0; i < assets.Length; i++)
235 {
236 string filename = assets[i];
237 byte[] data = File.ReadAllBytes(filename);
238
239 Metadata metadata = new Metadata();
240 metadata.CreationDate = File.GetCreationTime(filename);
241 metadata.Description = String.Empty;
242 metadata.ID = SimpleUtils.ParseUUIDFromFilename(filename);
243 metadata.Name = SimpleUtils.ParseNameFromFilename(filename);
244 metadata.SHA1 = OpenMetaverse.Utils.SHA1(data);
245 metadata.Temporary = false;
246 metadata.ContentType = Utils.ExtensionToContentType(Path.GetExtension(filename).TrimStart('.'));
247
248 // Store the loaded data
249 metadataStorage[metadata.ID] = metadata;
250 filenames[metadata.ID] = filename;
251 }
252 }
253 catch (Exception ex)
254 {
255 Logger.Log.Warn(ex.Message);
256 }
257 }
258 }
259 }
260}