aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Grid/NewAssetServer/Extensions
diff options
context:
space:
mode:
authorMike Mazur2009-02-16 02:24:57 +0000
committerMike Mazur2009-02-16 02:24:57 +0000
commit0e09b4a08beddb3b0239a3f088ab9a230b8f3979 (patch)
tree481d1cb9a60062dea6e646e0e6c5d9d87ce40b6e /OpenSim/Grid/NewAssetServer/Extensions
parentThank you, cmickeyb, for a patch to ass two string functions (diff)
downloadopensim-SC_OLD-0e09b4a08beddb3b0239a3f088ab9a230b8f3979.zip
opensim-SC_OLD-0e09b4a08beddb3b0239a3f088ab9a230b8f3979.tar.gz
opensim-SC_OLD-0e09b4a08beddb3b0239a3f088ab9a230b8f3979.tar.bz2
opensim-SC_OLD-0e09b4a08beddb3b0239a3f088ab9a230b8f3979.tar.xz
Adding
- NewAssetServer code - NewAssetServer addin manifest - example AssetServer.ini file
Diffstat (limited to 'OpenSim/Grid/NewAssetServer/Extensions')
-rw-r--r--OpenSim/Grid/NewAssetServer/Extensions/AuthorizeAll.cs78
-rw-r--r--OpenSim/Grid/NewAssetServer/Extensions/BrowseFrontend.cs125
-rw-r--r--OpenSim/Grid/NewAssetServer/Extensions/DBConnString.cs78
-rw-r--r--OpenSim/Grid/NewAssetServer/Extensions/NullAuthentication.cs68
-rw-r--r--OpenSim/Grid/NewAssetServer/Extensions/NullMetrics.cs124
-rw-r--r--OpenSim/Grid/NewAssetServer/Extensions/OpenSimFrontend.cs215
-rw-r--r--OpenSim/Grid/NewAssetServer/Extensions/OpenSimInventoryFrontend.cs636
-rw-r--r--OpenSim/Grid/NewAssetServer/Extensions/OpenSimMySQLInventory.cs804
-rw-r--r--OpenSim/Grid/NewAssetServer/Extensions/OpenSimMySQLStorage.cs311
-rw-r--r--OpenSim/Grid/NewAssetServer/Extensions/ReferenceFrontend.cs239
-rw-r--r--OpenSim/Grid/NewAssetServer/Extensions/SimpleInventory.cs602
-rw-r--r--OpenSim/Grid/NewAssetServer/Extensions/SimpleStorage.cs260
-rw-r--r--OpenSim/Grid/NewAssetServer/Extensions/SimpleUtils.cs44
13 files changed, 3584 insertions, 0 deletions
diff --git a/OpenSim/Grid/NewAssetServer/Extensions/AuthorizeAll.cs b/OpenSim/Grid/NewAssetServer/Extensions/AuthorizeAll.cs
new file mode 100644
index 0000000..f112c5e
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Extensions/AuthorizeAll.cs
@@ -0,0 +1,78 @@
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 ExtensionLoader;
32using OpenMetaverse;
33
34namespace AssetServer.Extensions
35{
36 public class AuthorizeAll : IExtension<AssetServer>, IAuthorizationProvider
37 {
38 AssetServer server;
39
40 public AuthorizeAll()
41 {
42 }
43
44 public void Start(AssetServer server)
45 {
46 this.server = server;
47 }
48
49 public void Stop()
50 {
51 }
52
53 public bool IsMetadataAuthorized(UUID authToken, UUID assetID)
54 {
55 return true;
56 }
57
58 public bool IsDataAuthorized(UUID authToken, UUID assetID)
59 {
60 return true;
61 }
62
63 public bool IsCreateAuthorized(UUID authToken)
64 {
65 return true;
66 }
67
68 public bool IsInventoryReadAuthorized(UUID authToken, Uri owner)
69 {
70 return true;
71 }
72
73 public bool IsInventoryWriteAuthorized(UUID authToken, Uri owner)
74 {
75 return true;
76 }
77 }
78}
diff --git a/OpenSim/Grid/NewAssetServer/Extensions/BrowseFrontend.cs b/OpenSim/Grid/NewAssetServer/Extensions/BrowseFrontend.cs
new file mode 100644
index 0000000..9f42722
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Extensions/BrowseFrontend.cs
@@ -0,0 +1,125 @@
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.Collections.Specialized;
33using System.Net;
34using System.Text;
35using System.Web;
36using ExtensionLoader;
37using OpenMetaverse;
38using HttpServer;
39
40namespace AssetServer.Extensions
41{
42 public class BrowseFrontend : IExtension<AssetServer>
43 {
44 AssetServer server;
45
46 public BrowseFrontend()
47 {
48 }
49
50 public void Start(AssetServer server)
51 {
52 this.server = server;
53
54 // Request for / or /?...
55 server.HttpServer.AddHandler("get", null, @"(^/$)|(^/\?.*)", BrowseRequestHandler);
56 }
57
58 public void Stop()
59 {
60 }
61
62 bool BrowseRequestHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
63 {
64 const int ASSETS_PER_PAGE = 25;
65 const string HEADER = "<html><head><title>Asset Server</title></head><body>";
66 const string TABLE_HEADER =
67 "<table><tr><th>Name</th><th>Description</th><th>Type</th><th>ID</th><th>Temporary</th><th>SHA-1</th></tr>";
68 const string TABLE_FOOTER = "</table>";
69 const string FOOTER = "</body></html>";
70
71 UUID authToken = Utils.GetAuthToken(request);
72
73 StringBuilder html = new StringBuilder();
74 int start = 0;
75 uint page = 0;
76
77 if (!String.IsNullOrEmpty(request.Uri.Query))
78 {
79 NameValueCollection query = HttpUtility.ParseQueryString(request.Uri.Query);
80 if (!String.IsNullOrEmpty(query["page"]) && UInt32.TryParse(query["page"], out page))
81 start = (int)page * ASSETS_PER_PAGE;
82 }
83
84 html.AppendLine(HEADER);
85
86 html.AppendLine("<p>");
87 if (page > 0)
88 html.AppendFormat("<a href=\"{0}?page={1}\">&lt; Previous Page</a> | ", request.Uri.AbsolutePath, page - 1);
89 html.AppendFormat("<a href=\"{0}?page={1}\">Next Page &gt;</a>", request.Uri.AbsolutePath, page + 1);
90 html.AppendLine("</p>");
91
92 html.AppendLine(TABLE_HEADER);
93
94 server.StorageProvider.ForEach(
95 delegate(Metadata data)
96 {
97 if (server.AuthorizationProvider.IsMetadataAuthorized(authToken, data.ID))
98 {
99 html.AppendLine(String.Format(
100 "<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td><td>{4}</td><td>{5}</td></tr>",
101 data.Name, data.Description, data.ContentType, data.ID, data.Temporary,
102 BitConverter.ToString(data.SHA1).Replace("-", String.Empty)));
103 }
104 else
105 {
106 html.AppendLine(String.Format(
107 "<tr><td>[Protected Asset]</td><td>&nbsp;</td><td>&nbsp;</td><td>{0}</td><td>{1}</td><td>&nbsp;</td></tr>",
108 data.ID, data.Temporary));
109 }
110 }, start, ASSETS_PER_PAGE
111 );
112
113 html.AppendLine(TABLE_FOOTER);
114
115 html.AppendLine(FOOTER);
116
117 byte[] responseData = System.Text.Encoding.UTF8.GetBytes(html.ToString());
118
119 response.Status = HttpStatusCode.OK;
120 response.Body.Write(responseData, 0, responseData.Length);
121 response.Body.Flush();
122 return true;
123 }
124 }
125}
diff --git a/OpenSim/Grid/NewAssetServer/Extensions/DBConnString.cs b/OpenSim/Grid/NewAssetServer/Extensions/DBConnString.cs
new file mode 100644
index 0000000..3c5f971
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Extensions/DBConnString.cs
@@ -0,0 +1,78 @@
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.Xml;
32using ExtensionLoader.Config;
33using MySql.Data.MySqlClient;
34
35namespace AssetServer.Extensions
36{
37 public static class DBConnString
38 {
39 private static string connectionString;
40
41 /// <summary>
42 /// Parses the MySQL connection string out of either the asset server
43 /// .ini or a OpenSim-style .xml file and caches the result for future
44 /// requests
45 /// </summary>
46 public static string GetConnectionString(IniConfigSource configFile)
47 {
48 if (connectionString == null)
49 {
50 // Try parsing from the ini file
51 try
52 {
53 // Load the extension list (and ordering) from our config file
54 IConfig extensionConfig = configFile.Configs["MySQL"];
55 connectionString = extensionConfig.GetString("database_connect", null);
56 }
57 catch (Exception) { }
58
59 if (connectionString != null)
60 {
61 // Force MySQL's broken connection pooling off
62 MySqlConnectionStringBuilder builder = new MySqlConnectionStringBuilder(connectionString);
63 builder.Pooling = false;
64 if (String.IsNullOrEmpty(builder.Database))
65 Logger.Log.Error("No database selected in the connectionString: " + connectionString);
66 connectionString = builder.ToString();
67 }
68 else
69 {
70 Logger.Log.Error("Database connection string is missing, check that the database_connect line is " +
71 "correct and uncommented in AssetServer.ini");
72 }
73 }
74
75 return connectionString;
76 }
77 }
78}
diff --git a/OpenSim/Grid/NewAssetServer/Extensions/NullAuthentication.cs b/OpenSim/Grid/NewAssetServer/Extensions/NullAuthentication.cs
new file mode 100644
index 0000000..9d38bf4
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Extensions/NullAuthentication.cs
@@ -0,0 +1,68 @@
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 ExtensionLoader;
32using OpenMetaverse;
33
34namespace AssetServer.Extensions
35{
36 public class NullAuthentication : IExtension<AssetServer>, IAuthenticationProvider
37 {
38 AssetServer server;
39
40 public NullAuthentication()
41 {
42 }
43
44 public void Start(AssetServer server)
45 {
46 this.server = server;
47 }
48
49 public void Stop()
50 {
51 }
52
53 public void AddIdentifier(UUID authToken, Uri identifier)
54 {
55 }
56
57 public bool RemoveIdentifier(UUID authToken)
58 {
59 return true;
60 }
61
62 public bool TryGetIdentifier(UUID authToken, out Uri identifier)
63 {
64 identifier = null;
65 return true;
66 }
67 }
68}
diff --git a/OpenSim/Grid/NewAssetServer/Extensions/NullMetrics.cs b/OpenSim/Grid/NewAssetServer/Extensions/NullMetrics.cs
new file mode 100644
index 0000000..84657c4
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Extensions/NullMetrics.cs
@@ -0,0 +1,124 @@
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 ExtensionLoader;
32using OpenMetaverse;
33
34namespace AssetServer.Extensions
35{
36 public class NullMetrics : IExtension<AssetServer>, IMetricsProvider
37 {
38 AssetServer server;
39
40 public NullMetrics()
41 {
42 }
43
44 public void Start(AssetServer server)
45 {
46 this.server = server;
47 }
48
49 public void Stop()
50 {
51 }
52
53 public void LogAssetMetadataFetch(string extension, BackendResponse response, UUID assetID, DateTime time)
54 {
55 Logger.Log.DebugFormat("[{0}] AssetMetadataFetch(): AssetID: {1}, Response: {2}", extension, assetID, response);
56 }
57
58 public void LogAssetDataFetch(string extension, BackendResponse response, UUID assetID, int dataSize, DateTime time)
59 {
60 Logger.Log.DebugFormat("[{0}] AssetDataFetch(): AssetID: {1}, DataSize: {2}, Response: {3}", extension, assetID,
61 dataSize, response);
62 }
63
64 public void LogAssetCreate(string extension, BackendResponse response, UUID assetID, int dataSize, DateTime time)
65 {
66 Logger.Log.DebugFormat("[{0}] AssetCreate(): AssetID: {1}, DataSize: {2}, Response: {3}", extension, assetID,
67 dataSize, response);
68 }
69
70 public void LogInventoryFetch(string extension, BackendResponse response, Uri owner, UUID objID, bool folder, DateTime time)
71 {
72 Logger.Log.DebugFormat("[{0}] InventoryFetch(): ObjID: {1}, Folder: {2}, OwnerID: {3}, Response: {4}", extension,
73 objID, folder, owner, response);
74 }
75
76 public void LogInventoryFetchFolderContents(string extension, BackendResponse response, Uri owner, UUID folderID, DateTime time)
77 {
78 Logger.Log.DebugFormat("[{0}] InventoryFetchFolderContents(): FolderID: {1}, OwnerID: {2}, Response: {3}", extension,
79 folderID, owner, response);
80 }
81
82 public void LogInventoryFetchFolderList(string extension, BackendResponse response, Uri owner, DateTime time)
83 {
84 Logger.Log.DebugFormat("[{0}] InventoryFetchFolderList(): OwnerID: {1}, Response: {2}", extension,
85 owner, response);
86 }
87
88 public void LogInventoryFetchInventory(string extension, BackendResponse response, Uri owner, DateTime time)
89 {
90 Logger.Log.DebugFormat("[{0}] InventoryFetchInventory(): OwnerID: {1}, Response: {2}", extension,
91 owner, response);
92 }
93
94 public void LogInventoryFetchActiveGestures(string extension, BackendResponse response, Uri owner, DateTime time)
95 {
96 Logger.Log.DebugFormat("[{0}] InventoryFetchActiveGestures(): OwnerID: {1}, Response: {2}", extension,
97 owner, response);
98 }
99
100 public void LogInventoryCreate(string extension, BackendResponse response, Uri owner, bool folder, DateTime time)
101 {
102 Logger.Log.DebugFormat("[{0}] InventoryCreate(): OwnerID: {1}, Response: {2}", extension,
103 owner, response);
104 }
105
106 public void LogInventoryCreateInventory(string extension, BackendResponse response, DateTime time)
107 {
108 Logger.Log.DebugFormat("[{0}] InventoryCreateInventory(): Response: {1}", extension,
109 response);
110 }
111
112 public void LogInventoryDelete(string extension, BackendResponse response, Uri owner, UUID objID, bool folder, DateTime time)
113 {
114 Logger.Log.DebugFormat("[{0}] InventoryDelete(): OwnerID: {1}, Folder: {2}, Response: {3}", extension,
115 owner, folder, response);
116 }
117
118 public void LogInventoryPurgeFolder(string extension, BackendResponse response, Uri owner, UUID folderID, DateTime time)
119 {
120 Logger.Log.DebugFormat("[{0}] InventoryPurgeFolder(): OwnerID: {1}, FolderID: {2}, Response: {3}", extension,
121 owner, response);
122 }
123 }
124}
diff --git a/OpenSim/Grid/NewAssetServer/Extensions/OpenSimFrontend.cs b/OpenSim/Grid/NewAssetServer/Extensions/OpenSimFrontend.cs
new file mode 100644
index 0000000..7a645b3
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Extensions/OpenSimFrontend.cs
@@ -0,0 +1,215 @@
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 AssetServer.Extensions
40{
41 public class OpenSimFrontend : IExtension<AssetServer>
42 {
43 AssetServer server;
44
45 public OpenSimFrontend()
46 {
47 }
48
49 public void Start(AssetServer 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/NewAssetServer/Extensions/OpenSimInventoryFrontend.cs b/OpenSim/Grid/NewAssetServer/Extensions/OpenSimInventoryFrontend.cs
new file mode 100644
index 0000000..a559f19
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Extensions/OpenSimInventoryFrontend.cs
@@ -0,0 +1,636 @@
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 OpenMetaverse.StructuredData;
38using HttpServer;
39
40namespace AssetServer.Extensions
41{
42 public class OpenSimInventoryFrontend : IExtension<AssetServer>
43 {
44 AssetServer server;
45 Utils.InventoryItemSerializer itemSerializer = new Utils.InventoryItemSerializer();
46 Utils.InventoryFolderSerializer folderSerializer = new Utils.InventoryFolderSerializer();
47 Utils.InventoryCollectionSerializer collectionSerializer = new Utils.InventoryCollectionSerializer();
48
49 public OpenSimInventoryFrontend()
50 {
51 }
52
53 public void Start(AssetServer server)
54 {
55 this.server = server;
56
57 server.HttpServer.AddHandler("post", null, @"^/GetInventory/", GetInventoryHandler);
58 server.HttpServer.AddHandler("post", null, @"^/CreateInventory/", CreateInventoryHandler);
59 server.HttpServer.AddHandler("post", null, @"^/NewFolder/", NewFolderHandler);
60 server.HttpServer.AddHandler("post", null, @"^/UpdateFolder/", UpdateFolderHandler);
61 server.HttpServer.AddHandler("post", null, @"^/MoveFolder/", MoveFolderHandler);
62 server.HttpServer.AddHandler("post", null, @"^/PurgeFolder/", PurgeFolderHandler);
63 server.HttpServer.AddHandler("post", null, @"^/NewItem/", NewItemHandler);
64 server.HttpServer.AddHandler("post", null, @"^/DeleteItem/", DeleteItemHandler);
65 server.HttpServer.AddHandler("post", null, @"^/RootFolders/", RootFoldersHandler);
66 server.HttpServer.AddHandler("post", null, @"^/ActiveGestures/", ActiveGesturesHandler);
67 }
68
69 public void Stop()
70 {
71 }
72
73 bool GetInventoryHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
74 {
75 UUID sessionID, agentID;
76 UUID ownerID = DeserializeUUID(request.Body, out agentID, out sessionID);
77
78 if (ownerID != UUID.Zero)
79 {
80 Logger.Log.Warn("GetInventory is not scalable on some inventory backends, avoid calling it wherever possible");
81
82 Uri owner = Utils.GetOpenSimUri(ownerID);
83 InventoryCollection inventory;
84 BackendResponse storageResponse = server.InventoryProvider.TryFetchInventory(owner, out inventory);
85
86 if (storageResponse == BackendResponse.Success)
87 {
88 collectionSerializer.Serialize(response.Body, inventory);
89 response.Body.Flush();
90 }
91 else if (storageResponse == BackendResponse.NotFound)
92 {
93 // Return an empty inventory set to mimic OpenSim.Grid.InventoryServer.exe
94 inventory = new InventoryCollection();
95 inventory.UserID = ownerID;
96 inventory.Folders = new Dictionary<UUID, InventoryFolder>();
97 inventory.Items = new Dictionary<UUID, InventoryItem>();
98 collectionSerializer.Serialize(response.Body, inventory);
99 response.Body.Flush();
100 }
101 else
102 {
103 response.Status = HttpStatusCode.InternalServerError;
104 }
105 }
106 else
107 {
108 response.Status = HttpStatusCode.BadRequest;
109 }
110
111 return true;
112 }
113
114 bool CreateInventoryHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
115 {
116 UUID ownerID = DeserializeUUID(request.Body);
117
118 if (ownerID != UUID.Zero)
119 {
120 Uri owner = Utils.GetOpenSimUri(ownerID);
121 Logger.Log.DebugFormat("Created URI {0} for inventory creation", owner);
122
123 InventoryFolder rootFolder = new InventoryFolder("My Inventory", ownerID, UUID.Zero, (short)AssetType.Folder);
124 BackendResponse storageResponse = server.InventoryProvider.TryCreateInventory(owner, rootFolder);
125 if (storageResponse == BackendResponse.Success)
126 {
127 CreateFolder("Animations", ownerID, rootFolder.ID, AssetType.Animation);
128 CreateFolder("Body Parts", ownerID, rootFolder.ID, AssetType.Bodypart);
129 CreateFolder("Calling Cards", ownerID, rootFolder.ID, AssetType.CallingCard);
130 CreateFolder("Clothing", ownerID, rootFolder.ID, AssetType.Clothing);
131 CreateFolder("Gestures", ownerID, rootFolder.ID, AssetType.Gesture);
132 CreateFolder("Landmarks", ownerID, rootFolder.ID, AssetType.Landmark);
133 CreateFolder("Lost and Found", ownerID, rootFolder.ID, AssetType.LostAndFoundFolder);
134 CreateFolder("Notecards", ownerID, rootFolder.ID, AssetType.Notecard);
135 CreateFolder("Objects", ownerID, rootFolder.ID, AssetType.Object);
136 CreateFolder("Photo Album", ownerID, rootFolder.ID, AssetType.SnapshotFolder);
137 CreateFolder("Scripts", ownerID, rootFolder.ID, AssetType.LSLText);
138 CreateFolder("Sounds", ownerID, rootFolder.ID, AssetType.Sound);
139 CreateFolder("Textures", ownerID, rootFolder.ID, AssetType.Texture);
140 CreateFolder("Trash", ownerID, rootFolder.ID, AssetType.TrashFolder);
141
142 SerializeBool(response.Body, true);
143 return true;
144 }
145 }
146
147 SerializeBool(response.Body, false);
148 return true;
149 }
150
151 bool NewFolderHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
152 {
153 UUID agentID, sessionID;
154 InventoryFolder folder = DeserializeFolder(request.Body, out agentID, out sessionID);
155
156 if (folder != null)
157 {
158 Uri owner = Utils.GetOpenSimUri(folder.Owner);
159
160 // Some calls that are moving or updating a folder instead of creating a new one
161 // will pass in an InventoryFolder without the name set. If this is the case we
162 // need to look up the name first
163 if (String.IsNullOrEmpty(folder.Name))
164 {
165 InventoryFolder oldFolder;
166 if (server.InventoryProvider.TryFetchFolder(owner, folder.ID, out oldFolder) == BackendResponse.Success)
167 folder.Name = oldFolder.Name;
168 }
169
170 BackendResponse storageResponse = server.InventoryProvider.TryCreateFolder(owner, folder);
171
172 if (storageResponse == BackendResponse.Success)
173 {
174 SerializeBool(response.Body, true);
175 return true;
176 }
177 }
178
179 SerializeBool(response.Body, false);
180 return true;
181 }
182
183 bool UpdateFolderHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
184 {
185 return NewFolderHandler(client, request, response);
186 }
187
188 bool MoveFolderHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
189 {
190 return NewFolderHandler(client, request, response);
191 }
192
193 bool PurgeFolderHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
194 {
195 UUID agentID, sessionID;
196 InventoryFolder folder = DeserializeFolder(request.Body, out agentID, out sessionID);
197
198 if (folder != null)
199 {
200 Uri owner = Utils.GetOpenSimUri(folder.Owner);
201 BackendResponse storageResponse = server.InventoryProvider.TryPurgeFolder(owner, folder.ID);
202
203 if (storageResponse == BackendResponse.Success)
204 {
205 SerializeBool(response.Body, true);
206 return true;
207 }
208 }
209
210 SerializeBool(response.Body, false);
211 return true;
212 }
213
214 bool NewItemHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
215 {
216 UUID agentID, sessionID;
217 InventoryItem item = DeserializeItem(request.Body, out agentID, out sessionID);
218
219 if (item != null)
220 {
221 Uri owner = Utils.GetOpenSimUri(agentID);
222 BackendResponse storageResponse = server.InventoryProvider.TryCreateItem(owner, item);
223
224 if (storageResponse == BackendResponse.Success)
225 {
226 SerializeBool(response.Body, true);
227 return true;
228 }
229 }
230
231 SerializeBool(response.Body, false);
232 return true;
233 }
234
235 bool DeleteItemHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
236 {
237 UUID agentID, sessionID;
238 InventoryItem item = DeserializeItem(request.Body, out agentID, out sessionID);
239
240 if (item != null)
241 {
242 Uri owner = Utils.GetOpenSimUri(item.Owner);
243 BackendResponse storageResponse = server.InventoryProvider.TryDeleteItem(owner, item.ID);
244
245 if (storageResponse == BackendResponse.Success)
246 {
247 SerializeBool(response.Body, true);
248 return true;
249 }
250 }
251
252 SerializeBool(response.Body, false);
253 return true;
254 }
255
256 bool RootFoldersHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
257 {
258 UUID ownerID = DeserializeUUID(request.Body);
259
260 if (ownerID != UUID.Zero)
261 {
262 Uri owner = Utils.GetOpenSimUri(ownerID);
263 List<InventoryFolder> skeleton;
264 BackendResponse storageResponse = server.InventoryProvider.TryFetchFolderList(owner, out skeleton);
265
266 if (storageResponse == BackendResponse.Success)
267 {
268 SerializeFolderList(response.Body, skeleton);
269 }
270 else if (storageResponse == BackendResponse.NotFound)
271 {
272 // Return an empty set of inventory so the requester knows that
273 // an inventory needs to be created for this agent
274 SerializeFolderList(response.Body, new List<InventoryFolder>(0));
275 }
276 else
277 {
278 response.Status = HttpStatusCode.InternalServerError;
279 }
280 }
281 else
282 {
283 response.Status = HttpStatusCode.BadRequest;
284 }
285
286 return true;
287 }
288
289 bool ActiveGesturesHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
290 {
291 UUID ownerID = DeserializeUUID(request.Body);
292
293 if (ownerID != UUID.Zero)
294 {
295 Uri owner = Utils.GetOpenSimUri(ownerID);
296 List<InventoryItem> gestures;
297 BackendResponse storageResponse = server.InventoryProvider.TryFetchActiveGestures(owner, out gestures);
298
299 if (storageResponse == BackendResponse.Success)
300 {
301 SerializeItemList(response.Body, gestures);
302 }
303 else if (storageResponse == BackendResponse.NotFound)
304 {
305 // Return an empty set of gestures to match OpenSim.Grid.InventoryServer.exe behavior
306 SerializeItemList(response.Body, new List<InventoryItem>(0));
307 }
308 else
309 {
310 response.Status = HttpStatusCode.InternalServerError;
311 }
312 }
313 else
314 {
315 response.Status = HttpStatusCode.BadRequest;
316 }
317
318 return true;
319 }
320
321 BackendResponse CreateFolder(string name, UUID ownerID, UUID parentID, AssetType assetType)
322 {
323 InventoryFolder folder = new InventoryFolder(name, ownerID, parentID, (short)assetType);
324 Uri owner = Utils.GetOpenSimUri(ownerID);
325 return server.InventoryProvider.TryCreateFolder(owner, folder);
326 }
327
328 UUID DeserializeUUID(Stream stream)
329 {
330 UUID id = UUID.Zero;
331
332 try
333 {
334 using (XmlReader reader = XmlReader.Create(stream))
335 {
336 reader.MoveToContent();
337 UUID.TryParse(reader.ReadElementContentAsString("guid", String.Empty), out id);
338 }
339 }
340 catch (Exception ex)
341 {
342 Logger.Log.Warn("Failed to parse POST data (expecting guid): " + ex.Message);
343 }
344
345 return id;
346 }
347
348 UUID DeserializeUUID(Stream stream, out UUID agentID, out UUID sessionID)
349 {
350 UUID id;
351
352 try
353 {
354 using (XmlReader reader = XmlReader.Create(stream))
355 {
356 reader.MoveToContent();
357 reader.ReadStartElement("RestSessionObjectOfGuid");
358 UUID.TryParse(reader.ReadElementContentAsString("SessionID", String.Empty), out sessionID);
359 UUID.TryParse(reader.ReadElementContentAsString("AvatarID", String.Empty), out agentID);
360 UUID.TryParse(reader.ReadElementContentAsString("Body", String.Empty), out id);
361 reader.ReadEndElement();
362 }
363 }
364 catch (Exception ex)
365 {
366 Logger.Log.Warn("Failed to parse GetInventory POST data: " + ex.Message);
367 agentID = UUID.Zero;
368 sessionID = UUID.Zero;
369 return UUID.Zero;
370 }
371
372 return id;
373 }
374
375 InventoryFolder DeserializeFolder(Stream stream, out UUID agentID, out UUID sessionID)
376 {
377 InventoryFolder folder = new InventoryFolder();
378
379 try
380 {
381 using (XmlReader reader = XmlReader.Create(stream))
382 {
383 reader.MoveToContent();
384 reader.ReadStartElement("RestSessionObjectOfInventoryFolderBase");
385 UUID.TryParse(reader.ReadElementContentAsString("SessionID", String.Empty), out sessionID);
386 UUID.TryParse(reader.ReadElementContentAsString("AvatarID", String.Empty), out agentID);
387 reader.ReadStartElement("Body");
388 if (reader.Name == "Name")
389 folder.Name = reader.ReadElementContentAsString("Name", String.Empty);
390 else
391 folder.Name = String.Empty;
392 ReadUUID(reader, "Owner", out folder.Owner);
393 ReadUUID(reader, "ParentID", out folder.ParentID);
394 ReadUUID(reader, "ID", out folder.ID);
395 Int16.TryParse(reader.ReadElementContentAsString("Type", String.Empty), out folder.Type);
396 UInt16.TryParse(reader.ReadElementContentAsString("Version", String.Empty), out folder.Version);
397 reader.ReadEndElement();
398 reader.ReadEndElement();
399 }
400 }
401 catch (Exception ex)
402 {
403 Logger.Log.Warn("Failed to parse POST data (expecting InventoryFolderBase): " + ex.Message);
404 agentID = UUID.Zero;
405 sessionID = UUID.Zero;
406 return null;
407 }
408
409 return folder;
410 }
411
412 InventoryItem DeserializeItem(Stream stream, out UUID agentID, out UUID sessionID)
413 {
414 InventoryItem item = new InventoryItem();
415
416 try
417 {
418 using (XmlReader reader = XmlReader.Create(stream))
419 {
420 reader.MoveToContent();
421 reader.ReadStartElement("RestSessionObjectOfInventoryItemBase");
422 UUID.TryParse(reader.ReadElementContentAsString("SessionID", String.Empty), out sessionID);
423 UUID.TryParse(reader.ReadElementContentAsString("AvatarID", String.Empty), out agentID);
424 reader.ReadStartElement("Body");
425 ReadUUID(reader, "ID", out item.ID);
426 Int32.TryParse(reader.ReadElementContentAsString("InvType", String.Empty), out item.InvType);
427 ReadUUID(reader, "Folder", out item.Folder);
428 ReadUUID(reader, "Owner", out item.Owner);
429 ReadUUID(reader, "Creator", out item.Creator);
430 item.Name = reader.ReadElementContentAsString("Name", String.Empty);
431 item.Description = reader.ReadElementContentAsString("Description", String.Empty);
432 UInt32.TryParse(reader.ReadElementContentAsString("NextPermissions", String.Empty), out item.NextPermissions);
433 UInt32.TryParse(reader.ReadElementContentAsString("CurrentPermissions", String.Empty), out item.CurrentPermissions);
434 UInt32.TryParse(reader.ReadElementContentAsString("BasePermissions", String.Empty), out item.BasePermissions);
435 UInt32.TryParse(reader.ReadElementContentAsString("EveryOnePermissions", String.Empty), out item.EveryOnePermissions);
436 UInt32.TryParse(reader.ReadElementContentAsString("GroupPermissions", String.Empty), out item.GroupPermissions);
437 Int32.TryParse(reader.ReadElementContentAsString("AssetType", String.Empty), out item.AssetType);
438 ReadUUID(reader, "AssetID", out item.AssetID);
439 ReadUUID(reader, "GroupID", out item.GroupID);
440 Boolean.TryParse(reader.ReadElementContentAsString("GroupOwned", String.Empty), out item.GroupOwned);
441 Int32.TryParse(reader.ReadElementContentAsString("SalePrice", String.Empty), out item.SalePrice);
442 Byte.TryParse(reader.ReadElementContentAsString("SaleType", String.Empty), out item.SaleType);
443 UInt32.TryParse(reader.ReadElementContentAsString("Flags", String.Empty), out item.Flags);
444 Int32.TryParse(reader.ReadElementContentAsString("CreationDate", String.Empty), out item.CreationDate);
445 reader.ReadEndElement();
446 reader.ReadEndElement();
447 }
448 }
449 catch (Exception ex)
450 {
451 Logger.Log.Warn("Failed to parse POST data (expecting InventoryItemBase): " + ex.Message);
452 agentID = UUID.Zero;
453 sessionID = UUID.Zero;
454 return null;
455 }
456
457 return item;
458 }
459
460 void SerializeBool(Stream stream, bool value)
461 {
462 using (XmlWriter writer = XmlWriter.Create(stream))
463 {
464 writer.WriteStartDocument();
465 writer.WriteStartElement("boolean");
466 writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
467 writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
468 writer.WriteString(value.ToString().ToLower());
469 writer.WriteEndElement();
470 writer.WriteEndDocument();
471 writer.Flush();
472 }
473
474 stream.Flush();
475 }
476
477 void SerializeFolderList(Stream stream, List<InventoryFolder> folders)
478 {
479 using (XmlWriter writer = XmlWriter.Create(stream))
480 {
481 writer.WriteStartDocument();
482 writer.WriteStartElement("ArrayOfInventoryFolderBase");
483 writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
484 writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
485
486 if (folders != null)
487 {
488 foreach (InventoryFolder folder in folders)
489 {
490 writer.WriteStartElement("InventoryFolderBase");
491 writer.WriteElementString("Name", folder.Name);
492 WriteUUID(writer, "Owner", folder.Owner);
493 WriteUUID(writer, "ParentID", folder.ParentID);
494 WriteUUID(writer, "ID", folder.ID);
495 writer.WriteElementString("Type", XmlConvert.ToString(folder.Type));
496 writer.WriteElementString("Version", XmlConvert.ToString(folder.Version));
497 writer.WriteEndElement();
498 }
499 }
500
501 writer.WriteEndElement();
502 writer.WriteEndDocument();
503
504 writer.Flush();
505 }
506
507 stream.Flush();
508 }
509
510 void SerializeItemList(Stream stream, List<InventoryItem> items)
511 {
512 using (XmlWriter writer = XmlWriter.Create(stream))
513 {
514 writer.WriteStartDocument();
515 writer.WriteStartElement("ArrayOfInventoryItemBase");
516 writer.WriteAttributeString("xmlns", "xsi", null, "http://www.w3.org/2001/XMLSchema-instance");
517 writer.WriteAttributeString("xmlns", "xsd", null, "http://www.w3.org/2001/XMLSchema");
518
519 if (items != null)
520 {
521 foreach (InventoryItem item in items)
522 {
523 writer.WriteStartElement("InventoryItemBase");
524 WriteUUID(writer, "ID", item.ID);
525 writer.WriteElementString("InvType", XmlConvert.ToString(item.InvType));
526 WriteUUID(writer, "Folder", item.Folder);
527 WriteUUID(writer, "Owner", item.Owner);
528 WriteUUID(writer, "Creator", item.Creator);
529 writer.WriteElementString("Name", item.Name);
530 writer.WriteElementString("Description", item.Description);
531 writer.WriteElementString("NextPermissions", XmlConvert.ToString(item.NextPermissions));
532 writer.WriteElementString("CurrentPermissions", XmlConvert.ToString(item.CurrentPermissions));
533 writer.WriteElementString("BasePermissions", XmlConvert.ToString(item.BasePermissions));
534 writer.WriteElementString("EveryOnePermissions", XmlConvert.ToString(item.EveryOnePermissions));
535 writer.WriteElementString("GroupPermissions", XmlConvert.ToString(item.GroupPermissions));
536 writer.WriteElementString("AssetType", XmlConvert.ToString(item.AssetType));
537 WriteUUID(writer, "AssetID", item.AssetID);
538 WriteUUID(writer, "GroupID", item.GroupID);
539 writer.WriteElementString("GroupOwned", XmlConvert.ToString(item.GroupOwned));
540 writer.WriteElementString("SalePrice", XmlConvert.ToString(item.SalePrice));
541 writer.WriteElementString("SaleType", XmlConvert.ToString(item.SaleType));
542 writer.WriteElementString("Flags", XmlConvert.ToString(item.Flags));
543 writer.WriteElementString("CreationDate", XmlConvert.ToString(item.CreationDate));
544 writer.WriteEndElement();
545 }
546 }
547
548 writer.WriteEndElement();
549 writer.WriteEndDocument();
550
551 writer.Flush();
552 }
553
554 stream.Flush();
555 }
556
557 void WriteUUID(XmlWriter writer, string name, UUID id)
558 {
559 writer.WriteStartElement(name);
560 writer.WriteElementString("Guid", XmlConvert.ToString(id.Guid));
561 writer.WriteEndElement();
562 }
563
564 void ReadUUID(XmlReader reader, string name, out UUID id)
565 {
566 reader.ReadStartElement(name);
567 UUID.TryParse(reader.ReadElementContentAsString("Guid", String.Empty), out id);
568 reader.ReadEndElement();
569 }
570 }
571
572 #region OpenSim AssetType
573
574 /// <summary>
575 /// The different types of grid assets
576 /// </summary>
577 public enum AssetType : sbyte
578 {
579 /// <summary>Unknown asset type</summary>
580 Unknown = -1,
581 /// <summary>Texture asset, stores in JPEG2000 J2C stream format</summary>
582 Texture = 0,
583 /// <summary>Sound asset</summary>
584 Sound = 1,
585 /// <summary>Calling card for another avatar</summary>
586 CallingCard = 2,
587 /// <summary>Link to a location in world</summary>
588 Landmark = 3,
589 // <summary>Legacy script asset, you should never see one of these</summary>
590 //[Obsolete]
591 //Script = 4,
592 /// <summary>Collection of textures and parameters that can be
593 /// worn by an avatar</summary>
594 Clothing = 5,
595 /// <summary>Primitive that can contain textures, sounds,
596 /// scripts and more</summary>
597 Object = 6,
598 /// <summary>Notecard asset</summary>
599 Notecard = 7,
600 /// <summary>Holds a collection of inventory items</summary>
601 Folder = 8,
602 /// <summary>Root inventory folder</summary>
603 RootFolder = 9,
604 /// <summary>Linden scripting language script</summary>
605 LSLText = 10,
606 /// <summary>LSO bytecode for a script</summary>
607 LSLBytecode = 11,
608 /// <summary>Uncompressed TGA texture</summary>
609 TextureTGA = 12,
610 /// <summary>Collection of textures and shape parameters that can
611 /// be worn</summary>
612 Bodypart = 13,
613 /// <summary>Trash folder</summary>
614 TrashFolder = 14,
615 /// <summary>Snapshot folder</summary>
616 SnapshotFolder = 15,
617 /// <summary>Lost and found folder</summary>
618 LostAndFoundFolder = 16,
619 /// <summary>Uncompressed sound</summary>
620 SoundWAV = 17,
621 /// <summary>Uncompressed TGA non-square image, not to be used as a
622 /// texture</summary>
623 ImageTGA = 18,
624 /// <summary>Compressed JPEG non-square image, not to be used as a
625 /// texture</summary>
626 ImageJPEG = 19,
627 /// <summary>Animation</summary>
628 Animation = 20,
629 /// <summary>Sequence of animations, sounds, chat, and pauses</summary>
630 Gesture = 21,
631 /// <summary>Simstate file</summary>
632 Simstate = 22,
633 }
634
635 #endregion OpenSim AssetType
636}
diff --git a/OpenSim/Grid/NewAssetServer/Extensions/OpenSimMySQLInventory.cs b/OpenSim/Grid/NewAssetServer/Extensions/OpenSimMySQLInventory.cs
new file mode 100644
index 0000000..1b5facd
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Extensions/OpenSimMySQLInventory.cs
@@ -0,0 +1,804 @@
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 AssetServer.Extensions
41{
42 public class OpenSimMySQLInventory : IExtension<AssetServer>, IInventoryProvider
43 {
44 const string EXTENSION_NAME = "OpenSimMySQLInventory"; // Used in metrics reporting
45
46 AssetServer server;
47
48 public OpenSimMySQLInventory()
49 {
50 }
51
52 #region Required Interfaces
53
54 public void Start(AssetServer 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 inventory backend: " + dbConnection.ServerVersion);
64 }
65 catch (MySqlException ex)
66 {
67 Logger.Log.Error("Connection to MySQL inventory backend failed: " + ex.Message);
68 }
69 }
70 }
71
72 public void Stop()
73 {
74 }
75
76 public BackendResponse TryFetchItem(Uri owner, UUID itemID, out InventoryItem item)
77 {
78 item = 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 assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions," +
91 "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," +
92 "creationDate,groupID,groupOwned,flags,avatarID,parentFolderID,inventoryGroupPermissions FROM inventoryitems WHERE inventoryID='{0}'",
93 itemID.ToString());
94 reader = command.ExecuteReader();
95
96 if (reader.Read())
97 {
98 item = new InventoryItem();
99 item.ID = itemID;
100 item.AssetID = UUID.Parse(reader.GetString(0));
101 item.AssetType = reader.GetInt32(1);
102 item.Name = reader.GetString(2);
103 item.Description = reader.GetString(3);
104 item.NextPermissions = (uint)reader.GetInt32(4);
105 item.CurrentPermissions = (uint)reader.GetInt32(5);
106 item.InvType = reader.GetInt32(6);
107 item.Creator = UUID.Parse(reader.GetString(7));
108 item.BasePermissions = (uint)reader.GetInt32(8);
109 item.EveryOnePermissions = (uint)reader.GetInt32(9);
110 item.SalePrice = reader.GetInt32(10);
111 item.SaleType = reader.GetByte(11);
112 item.CreationDate = reader.GetInt32(12);
113 item.GroupID = UUID.Parse(reader.GetString(13));
114 item.GroupOwned = reader.GetBoolean(14);
115 item.Flags = (uint)reader.GetInt32(15);
116 item.Owner = UUID.Parse(reader.GetString(16));
117 item.Folder = UUID.Parse(reader.GetString(17));
118 item.GroupPermissions = (uint)reader.GetInt32(18);
119
120 ret = BackendResponse.Success;
121 }
122 else
123 {
124 ret = BackendResponse.NotFound;
125 }
126 }
127 catch (MySqlException ex)
128 {
129 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
130 ret = BackendResponse.Failure;
131 }
132 }
133
134 server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, ret, owner, itemID, false, DateTime.Now);
135 return ret;
136 }
137
138 public BackendResponse TryFetchFolder(Uri owner, UUID folderID, out InventoryFolder folder)
139 {
140 folder = null;
141 BackendResponse ret;
142
143 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
144 {
145 IDataReader reader;
146
147 try
148 {
149 dbConnection.Open();
150
151 IDbCommand command = dbConnection.CreateCommand();
152 command.CommandText = String.Format("SELECT folderName,type,version,agentID,parentFolderID FROM inventoryfolders WHERE folderID='{0}'",
153 folderID.ToString());
154 reader = command.ExecuteReader();
155
156 if (reader.Read())
157 {
158 folder = new InventoryFolder();
159 folder.Children = null; // This call only returns data for the folder itself, no children data
160 folder.ID = folderID;
161 folder.Name = reader.GetString(0);
162 folder.Type = reader.GetInt16(1);
163 folder.Version = (ushort)reader.GetInt16(2);
164 folder.Owner = UUID.Parse(reader.GetString(3));
165 folder.ParentID = UUID.Parse(reader.GetString(4));
166
167 ret = BackendResponse.Success;
168 }
169 else
170 {
171 ret = BackendResponse.NotFound;
172 }
173 }
174 catch (MySqlException ex)
175 {
176 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
177 ret = BackendResponse.Failure;
178 }
179 }
180
181 server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, ret, owner, folderID, true, DateTime.Now);
182 return ret;
183 }
184
185 public BackendResponse TryFetchFolderContents(Uri owner, UUID folderID, out InventoryCollection contents)
186 {
187 contents = null;
188 BackendResponse ret;
189
190 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
191 {
192 IDataReader reader;
193
194 try
195 {
196 dbConnection.Open();
197
198 contents = new InventoryCollection();
199
200 #region Folder retrieval
201
202 IDbCommand command = dbConnection.CreateCommand();
203 command.CommandText = String.Format("SELECT folderName,type,version,agentID,folderID FROM inventoryfolders WHERE parentFolderID='{0}'",
204 folderID.ToString());
205 reader = command.ExecuteReader();
206
207 contents.Folders = new Dictionary<UUID, InventoryFolder>();
208
209 while (reader.Read())
210 {
211 InventoryFolder folder = new InventoryFolder();
212 folder.ParentID = folderID;
213 folder.Children = null; // This call doesn't do recursion
214 folder.Name = reader.GetString(0);
215 folder.Type = reader.GetInt16(1);
216 folder.Version = (ushort)reader.GetInt16(2);
217 folder.Owner = UUID.Parse(reader.GetString(3));
218 folder.ID = UUID.Parse(reader.GetString(4));
219
220 contents.Folders.Add(folder.ID, folder);
221 contents.UserID = folder.Owner;
222 }
223
224 reader.Close();
225
226 #endregion Folder retrieval
227
228 #region Item retrieval
229
230 command = dbConnection.CreateCommand();
231 command.CommandText = String.Format("SELECT assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions," +
232 "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," +
233 "creationDate,groupID,groupOwned,flags,avatarID,inventoryID,inventoryGroupPermissions FROM inventoryitems WHERE parentFolderID='{0}'",
234 folderID.ToString());
235 reader = command.ExecuteReader();
236
237 contents.Items = new Dictionary<UUID, InventoryItem>();
238
239 while (reader.Read())
240 {
241 InventoryItem item = new InventoryItem();
242 item.Folder = folderID;
243 item.AssetID = UUID.Parse(reader.GetString(0));
244 item.AssetType = reader.GetInt32(1);
245 item.Name = reader.GetString(2);
246 item.Description = reader.GetString(3);
247 item.NextPermissions = (uint)reader.GetInt32(4);
248 item.CurrentPermissions = (uint)reader.GetInt32(5);
249 item.InvType = reader.GetInt32(6);
250 item.Creator = UUID.Parse(reader.GetString(7));
251 item.BasePermissions = (uint)reader.GetInt32(8);
252 item.EveryOnePermissions = (uint)reader.GetInt32(9);
253 item.SalePrice = reader.GetInt32(10);
254 item.SaleType = reader.GetByte(11);
255 item.CreationDate = reader.GetInt32(12);
256 item.GroupID = UUID.Parse(reader.GetString(13));
257 item.GroupOwned = reader.GetBoolean(14);
258 item.Flags = (uint)reader.GetInt32(15);
259 item.Owner = UUID.Parse(reader.GetString(16));
260 item.ID = UUID.Parse(reader.GetString(17));
261 item.GroupPermissions = (uint)reader.GetInt32(18);
262
263 contents.Items.Add(item.ID, item);
264 contents.UserID = item.Owner;
265 }
266
267 #endregion Item retrieval
268
269 ret = BackendResponse.Success;
270 }
271 catch (MySqlException ex)
272 {
273 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
274 ret = BackendResponse.Failure;
275 }
276 }
277
278 server.MetricsProvider.LogInventoryFetchFolderContents(EXTENSION_NAME, ret, owner, folderID, DateTime.Now);
279 return ret;
280 }
281
282 public BackendResponse TryFetchFolderList(Uri owner, out List<InventoryFolder> folders)
283 {
284 folders = null;
285 BackendResponse ret;
286 UUID ownerID;
287
288 if (Utils.TryGetOpenSimUUID(owner, out ownerID))
289 {
290 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
291 {
292 IDataReader reader;
293
294 try
295 {
296 dbConnection.Open();
297 folders = new List<InventoryFolder>();
298
299 IDbCommand command = dbConnection.CreateCommand();
300 command.CommandText = String.Format("SELECT folderName,type,version,folderID,parentFolderID FROM inventoryfolders WHERE agentID='{0}'",
301 ownerID.ToString());
302 reader = command.ExecuteReader();
303
304 while (reader.Read())
305 {
306 InventoryFolder folder = new InventoryFolder();
307 folder.Owner = ownerID;
308 folder.Children = null; // This call does not create a folder hierarchy
309 folder.Name = reader.GetString(0);
310 folder.Type = reader.GetInt16(1);
311 folder.Version = (ushort)reader.GetInt16(2);
312 folder.ID = UUID.Parse(reader.GetString(3));
313 folder.ParentID = UUID.Parse(reader.GetString(4));
314
315 folders.Add(folder);
316 }
317
318 ret = BackendResponse.Success;
319 }
320 catch (MySqlException ex)
321 {
322 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
323 ret = BackendResponse.Failure;
324 }
325 }
326 }
327 else
328 {
329 ret = BackendResponse.NotFound;
330 }
331
332 server.MetricsProvider.LogInventoryFetchFolderList(EXTENSION_NAME, ret, owner, DateTime.Now);
333 return ret;
334 }
335
336 public BackendResponse TryFetchInventory(Uri owner, out InventoryCollection inventory)
337 {
338 inventory = null;
339 BackendResponse ret;
340 List<InventoryFolder> folders;
341 UUID ownerID;
342
343 ret = TryFetchFolderList(owner, out folders);
344
345 if (ret == BackendResponse.Success)
346 {
347 // Add the retrieved folders to the inventory collection
348 inventory = new InventoryCollection();
349 inventory.Folders = new Dictionary<UUID, InventoryFolder>(folders.Count);
350 foreach (InventoryFolder folder in folders)
351 inventory.Folders[folder.ID] = folder;
352
353 // Fetch inventory items
354 if (Utils.TryGetOpenSimUUID(owner, out ownerID))
355 {
356 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
357 {
358 IDataReader reader;
359
360 try
361 {
362 dbConnection.Open();
363
364 IDbCommand command = dbConnection.CreateCommand();
365 command.CommandText = String.Format("SELECT assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions," +
366 "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," +
367 "creationDate,groupID,groupOwned,flags,inventoryID,parentFolderID,inventoryGroupPermissions FROM inventoryitems WHERE " +
368 "avatarID='{0}'", ownerID.ToString());
369 reader = command.ExecuteReader();
370
371 inventory.UserID = ownerID;
372 inventory.Items = new Dictionary<UUID, InventoryItem>();
373
374 while (reader.Read())
375 {
376 InventoryItem item = new InventoryItem();
377 item.Owner = ownerID;
378 item.AssetID = UUID.Parse(reader.GetString(0));
379 item.AssetType = reader.GetInt32(1);
380 item.Name = reader.GetString(2);
381 item.Description = reader.GetString(3);
382 item.NextPermissions = (uint)reader.GetInt32(4);
383 item.CurrentPermissions = (uint)reader.GetInt32(5);
384 item.InvType = reader.GetInt32(6);
385 item.Creator = UUID.Parse(reader.GetString(7));
386 item.BasePermissions = (uint)reader.GetInt32(8);
387 item.EveryOnePermissions = (uint)reader.GetInt32(9);
388 item.SalePrice = reader.GetInt32(10);
389 item.SaleType = reader.GetByte(11);
390 item.CreationDate = reader.GetInt32(12);
391 item.GroupID = UUID.Parse(reader.GetString(13));
392 item.GroupOwned = reader.GetBoolean(14);
393 item.Flags = (uint)reader.GetInt32(15);
394 item.ID = UUID.Parse(reader.GetString(16));
395 item.Folder = UUID.Parse(reader.GetString(17));
396 item.GroupPermissions = (uint)reader.GetInt32(18);
397
398 inventory.Items.Add(item.ID, item);
399 }
400
401 ret = BackendResponse.Success;
402 }
403 catch (MySqlException ex)
404 {
405 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
406 ret = BackendResponse.Failure;
407 }
408 }
409 }
410 else
411 {
412 ret = BackendResponse.NotFound;
413 }
414 }
415
416 server.MetricsProvider.LogInventoryFetchInventory(EXTENSION_NAME, ret, owner, DateTime.Now);
417 return ret;
418 }
419
420 public BackendResponse TryFetchActiveGestures(Uri owner, out List<InventoryItem> gestures)
421 {
422 gestures = null;
423 BackendResponse ret;
424 UUID ownerID;
425
426 if (Utils.TryGetOpenSimUUID(owner, out ownerID))
427 {
428 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
429 {
430 IDataReader reader;
431
432 try
433 {
434 dbConnection.Open();
435
436 MySqlCommand command = new MySqlCommand("SELECT assetID,inventoryName,inventoryDescription,inventoryNextPermissions," +
437 "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," +
438 "creationDate,groupID,groupOwned,inventoryID,parentFolderID,inventoryGroupPermissions FROM inventoryitems WHERE " +
439 "avatarId=?uuid AND assetType=?type AND flags=1", dbConnection);
440 command.Parameters.AddWithValue("?uuid", ownerID.ToString());
441 command.Parameters.AddWithValue("?type", (int)AssetType.Gesture);
442 reader = command.ExecuteReader();
443
444 while (reader.Read())
445 {
446 InventoryItem item = new InventoryItem();
447 item.Owner = ownerID;
448 item.AssetType = (int)AssetType.Gesture;
449 item.Flags = (uint)1;
450 item.AssetID = UUID.Parse(reader.GetString(0));
451 item.Name = reader.GetString(1);
452 item.Description = reader.GetString(2);
453 item.NextPermissions = (uint)reader.GetInt32(3);
454 item.CurrentPermissions = (uint)reader.GetInt32(4);
455 item.InvType = reader.GetInt32(5);
456 item.Creator = UUID.Parse(reader.GetString(6));
457 item.BasePermissions = (uint)reader.GetInt32(7);
458 item.EveryOnePermissions = (uint)reader.GetInt32(8);
459 item.SalePrice = reader.GetInt32(9);
460 item.SaleType = reader.GetByte(10);
461 item.CreationDate = reader.GetInt32(11);
462 item.GroupID = UUID.Parse(reader.GetString(12));
463 item.GroupOwned = reader.GetBoolean(13);
464 item.ID = UUID.Parse(reader.GetString(14));
465 item.Folder = UUID.Parse(reader.GetString(15));
466 item.GroupPermissions = (uint)reader.GetInt32(16);
467
468 gestures.Add(item);
469 }
470
471 ret = BackendResponse.Success;
472 }
473 catch (MySqlException ex)
474 {
475 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
476 ret = BackendResponse.Failure;
477 }
478 }
479 }
480 else
481 {
482 ret = BackendResponse.NotFound;
483 }
484
485 server.MetricsProvider.LogInventoryFetchActiveGestures(EXTENSION_NAME, ret, owner, DateTime.Now);
486 return ret;
487 }
488
489 public BackendResponse TryCreateItem(Uri owner, InventoryItem item)
490 {
491 BackendResponse ret;
492
493 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
494 {
495 try
496 {
497 dbConnection.Open();
498
499 MySqlCommand command = new MySqlCommand(
500 "REPLACE INTO inventoryitems (assetID,assetType,inventoryName,inventoryDescription,inventoryNextPermissions," +
501 "inventoryCurrentPermissions,invType,creatorID,inventoryBasePermissions,inventoryEveryOnePermissions,salePrice,saleType," +
502 "creationDate,groupID,groupOwned,flags,inventoryID,avatarID,parentFolderID,inventoryGroupPermissions) VALUES " +
503
504 "(?assetID,?assetType,?inventoryName,?inventoryDescription,?inventoryNextPermissions,?inventoryCurrentPermissions,?invType," +
505 "?creatorID,?inventoryBasePermissions,?inventoryEveryOnePermissions,?salePrice,?saleType,?creationDate,?groupID,?groupOwned," +
506 "?flags,?inventoryID,?avatarID,?parentFolderID,?inventoryGroupPermissions)", dbConnection);
507
508 command.Parameters.AddWithValue("?assetID", item.AssetID.ToString());
509 command.Parameters.AddWithValue("?assetType", item.AssetType);
510 command.Parameters.AddWithValue("?inventoryName", item.Name);
511 command.Parameters.AddWithValue("?inventoryDescription", item.Description);
512 command.Parameters.AddWithValue("?inventoryNextPermissions", item.NextPermissions);
513 command.Parameters.AddWithValue("?inventoryCurrentPermissions", item.CurrentPermissions);
514 command.Parameters.AddWithValue("?invType", item.InvType);
515 command.Parameters.AddWithValue("?creatorID", item.Creator.ToString());
516 command.Parameters.AddWithValue("?inventoryBasePermissions", item.BasePermissions);
517 command.Parameters.AddWithValue("?inventoryEveryOnePermissions", item.EveryOnePermissions);
518 command.Parameters.AddWithValue("?salePrice", item.SalePrice);
519 command.Parameters.AddWithValue("?saleType", item.SaleType);
520 command.Parameters.AddWithValue("?creationDate", item.CreationDate);
521 command.Parameters.AddWithValue("?groupID", item.GroupID.ToString());
522 command.Parameters.AddWithValue("?groupOwned", item.GroupOwned);
523 command.Parameters.AddWithValue("?flags", item.Flags);
524 command.Parameters.AddWithValue("?inventoryID", item.ID);
525 command.Parameters.AddWithValue("?avatarID", item.Owner);
526 command.Parameters.AddWithValue("?parentFolderID", item.Folder);
527 command.Parameters.AddWithValue("?inventoryGroupPermissions", item.GroupPermissions);
528
529 int rowsAffected = command.ExecuteNonQuery();
530 if (rowsAffected == 1)
531 {
532 ret = BackendResponse.Success;
533 }
534 else if (rowsAffected == 2)
535 {
536 Logger.Log.Info("Replaced inventory item " + item.ID.ToString());
537 ret = BackendResponse.Success;
538 }
539 else
540 {
541 Logger.Log.ErrorFormat("MySQL REPLACE query affected {0} rows", rowsAffected);
542 ret = BackendResponse.Failure;
543 }
544 }
545 catch (MySqlException ex)
546 {
547 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
548 ret = BackendResponse.Failure;
549 }
550 }
551
552 server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, ret, owner, false, DateTime.Now);
553 return ret;
554 }
555
556 public BackendResponse TryCreateFolder(Uri owner, InventoryFolder folder)
557 {
558 BackendResponse ret;
559
560 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
561 {
562 try
563 {
564 dbConnection.Open();
565
566 MySqlCommand command = new MySqlCommand(
567 "REPLACE INTO inventoryfolders (folderName,type,version,folderID,agentID,parentFolderID) VALUES " +
568 "(?folderName,?type,?version,?folderID,?agentID,?parentFolderID)", dbConnection);
569
570 command.Parameters.AddWithValue("?folderName", folder.Name);
571 command.Parameters.AddWithValue("?type", folder.Type);
572 command.Parameters.AddWithValue("?version", folder.Version);
573 command.Parameters.AddWithValue("?folderID", folder.ID);
574 command.Parameters.AddWithValue("?agentID", folder.Owner);
575 command.Parameters.AddWithValue("?parentFolderID", folder.ParentID);
576
577 int rowsAffected = command.ExecuteNonQuery();
578 if (rowsAffected == 1)
579 {
580 ret = BackendResponse.Success;
581 }
582 else if (rowsAffected == 2)
583 {
584 Logger.Log.Info("Replaced inventory folder " + folder.ID.ToString());
585 ret = BackendResponse.Success;
586 }
587 else
588 {
589 Logger.Log.ErrorFormat("MySQL REPLACE query affected {0} rows", rowsAffected);
590 ret = BackendResponse.Failure;
591 }
592 }
593 catch (MySqlException ex)
594 {
595 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
596 ret = BackendResponse.Failure;
597 }
598 }
599
600 server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, ret, owner, true, DateTime.Now);
601 return ret;
602 }
603
604 public BackendResponse TryCreateInventory(Uri owner, InventoryFolder rootFolder)
605 {
606 return TryCreateFolder(owner, rootFolder);
607 }
608
609 public BackendResponse TryDeleteItem(Uri owner, UUID itemID)
610 {
611 BackendResponse ret;
612 UUID ownerID;
613
614 if (Utils.TryGetOpenSimUUID(owner, out ownerID))
615 {
616 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
617 {
618 try
619 {
620 dbConnection.Open();
621
622 MySqlCommand command = new MySqlCommand(
623 "DELETE FROM inventoryitems WHERE inventoryID=?inventoryID AND avatarID=?avatarID", dbConnection);
624
625 command.Parameters.AddWithValue("?inventoryID", itemID.ToString());
626 command.Parameters.AddWithValue("?avatarID", ownerID.ToString());
627
628 int rowsAffected = command.ExecuteNonQuery();
629 if (rowsAffected == 1)
630 {
631 ret = BackendResponse.Success;
632 }
633 else
634 {
635 Logger.Log.ErrorFormat("MySQL DELETE query affected {0} rows", rowsAffected);
636 ret = BackendResponse.NotFound;
637 }
638 }
639 catch (MySqlException ex)
640 {
641 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
642 ret = BackendResponse.Failure;
643 }
644 }
645 }
646 else
647 {
648 ret = BackendResponse.NotFound;
649 }
650
651 server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, ret, owner, itemID, false, DateTime.Now);
652 return ret;
653 }
654
655 public BackendResponse TryDeleteFolder(Uri owner, UUID folderID)
656 {
657 BackendResponse ret;
658 UUID ownerID;
659
660 if (Utils.TryGetOpenSimUUID(owner, out ownerID))
661 {
662 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
663 {
664 try
665 {
666 dbConnection.Open();
667
668 MySqlCommand command = new MySqlCommand(
669 "DELETE FROM inventoryfolders WHERE folderID=?folderID AND agentID=?agentID", dbConnection);
670
671 command.Parameters.AddWithValue("?folderID", folderID.ToString());
672 command.Parameters.AddWithValue("?agentID", ownerID.ToString());
673
674 int rowsAffected = command.ExecuteNonQuery();
675 if (rowsAffected == 1)
676 {
677 ret = BackendResponse.Success;
678 }
679 else
680 {
681 Logger.Log.ErrorFormat("MySQL DELETE query affected {0} rows", rowsAffected);
682 ret = BackendResponse.NotFound;
683 }
684 }
685 catch (MySqlException ex)
686 {
687 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
688 ret = BackendResponse.Failure;
689 }
690 }
691 }
692 else
693 {
694 ret = BackendResponse.NotFound;
695 }
696
697 server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, ret, owner, folderID, true, DateTime.Now);
698 return ret;
699 }
700
701 public BackendResponse TryPurgeFolder(Uri owner, UUID folderID)
702 {
703 BackendResponse ret;
704 UUID ownerID;
705
706 if (Utils.TryGetOpenSimUUID(owner, out ownerID))
707 {
708 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
709 {
710 try
711 {
712 dbConnection.Open();
713
714 #region Delete items
715
716 MySqlCommand command = new MySqlCommand(
717 "DELETE FROM inventoryitems WHERE parentFolderID=?parentFolderID AND avatarID=?avatarID", dbConnection);
718
719 command.Parameters.AddWithValue("?parentFolderID", folderID.ToString());
720 command.Parameters.AddWithValue("?avatarID", ownerID.ToString());
721
722 int rowsAffected = command.ExecuteNonQuery();
723
724 #endregion Delete items
725
726 #region Delete folders
727
728 command = new MySqlCommand(
729 "DELETE FROM inventoryfolders WHERE parentFolderID=?parentFolderID AND agentID=?agentID", dbConnection);
730
731 command.Parameters.AddWithValue("?parentFolderID", folderID.ToString());
732 command.Parameters.AddWithValue("?agentID", ownerID.ToString());
733
734 rowsAffected += command.ExecuteNonQuery();
735
736 #endregion Delete folders
737
738 Logger.Log.DebugFormat("Deleted {0} inventory objects from MySQL in a folder purge", rowsAffected);
739
740 ret = BackendResponse.Success;
741 }
742 catch (MySqlException ex)
743 {
744 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
745 ret = BackendResponse.Failure;
746 }
747 }
748 }
749 else
750 {
751 ret = BackendResponse.NotFound;
752 }
753
754 server.MetricsProvider.LogInventoryPurgeFolder(EXTENSION_NAME, ret, owner, folderID, DateTime.Now);
755 return ret;
756 }
757
758 public int ForEach(Action<Metadata> action, int start, int count)
759 {
760 int rowCount = 0;
761
762 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
763 {
764 MySqlDataReader reader;
765
766 try
767 {
768 dbConnection.Open();
769
770 MySqlCommand command = dbConnection.CreateCommand();
771 command.CommandText = String.Format("SELECT name,description,assetType,temporary,data,id FROM assets LIMIT {0}, {1}",
772 start, count);
773 reader = command.ExecuteReader();
774 }
775 catch (MySqlException ex)
776 {
777 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
778 return 0;
779 }
780
781 while (reader.Read())
782 {
783 Metadata metadata = new Metadata();
784 metadata.CreationDate = OpenMetaverse.Utils.Epoch;
785 metadata.Description = reader.GetString(1);
786 metadata.ID = UUID.Parse(reader.GetString(5));
787 metadata.Name = reader.GetString(0);
788 metadata.SHA1 = OpenMetaverse.Utils.SHA1((byte[])reader.GetValue(4));
789 metadata.Temporary = reader.GetBoolean(3);
790 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2));
791
792 action(metadata);
793 ++rowCount;
794 }
795
796 reader.Close();
797 }
798
799 return rowCount;
800 }
801
802 #endregion Required Interfaces
803 }
804}
diff --git a/OpenSim/Grid/NewAssetServer/Extensions/OpenSimMySQLStorage.cs b/OpenSim/Grid/NewAssetServer/Extensions/OpenSimMySQLStorage.cs
new file mode 100644
index 0000000..34f1ef0
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Extensions/OpenSimMySQLStorage.cs
@@ -0,0 +1,311 @@
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 AssetServer.Extensions
41{
42 public class OpenSimMySQLStorage : IExtension<AssetServer>, IStorageProvider
43 {
44 const string EXTENSION_NAME = "OpenSimMySQLStorage"; // Used in metrics reporting
45
46 AssetServer server;
47
48 public OpenSimMySQLStorage()
49 {
50 }
51
52 #region Required Interfaces
53
54 public void Start(AssetServer 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/NewAssetServer/Extensions/ReferenceFrontend.cs b/OpenSim/Grid/NewAssetServer/Extensions/ReferenceFrontend.cs
new file mode 100644
index 0000000..133f87c
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Extensions/ReferenceFrontend.cs
@@ -0,0 +1,239 @@
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.Xml;
34using ExtensionLoader;
35using OpenMetaverse;
36using OpenMetaverse.StructuredData;
37using HttpServer;
38
39namespace AssetServer.Extensions
40{
41 public class ReferenceFrontend : IExtension<AssetServer>
42 {
43 AssetServer server;
44
45 public ReferenceFrontend()
46 {
47 }
48
49 public void Start(AssetServer server)
50 {
51 this.server = server;
52
53 // Asset metadata request
54 server.HttpServer.AddHandler("get", null, @"^/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/metadata",
55 MetadataRequestHandler);
56
57 // Asset data request
58 server.HttpServer.AddHandler("get", null, @"^/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/data",
59 DataRequestHandler);
60
61 // Asset creation
62 server.HttpServer.AddHandler("post", null, "^/createasset", CreateRequestHandler);
63 }
64
65 public void Stop()
66 {
67 }
68
69 bool MetadataRequestHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
70 {
71 UUID assetID;
72 // Split the URL up into an AssetID and a method
73 string[] rawUrl = request.Uri.PathAndQuery.Split('/');
74
75 if (rawUrl.Length >= 3 && UUID.TryParse(rawUrl[1], out assetID))
76 {
77 UUID authToken = Utils.GetAuthToken(request);
78
79 if (server.AuthorizationProvider.IsMetadataAuthorized(authToken, assetID))
80 {
81 Metadata metadata;
82 BackendResponse storageResponse = server.StorageProvider.TryFetchMetadata(assetID, out metadata);
83
84 if (storageResponse == BackendResponse.Success)
85 {
86 // If the asset data location wasn't specified in the metadata, specify it
87 // manually here by pointing back to this asset server
88 if (!metadata.Methods.ContainsKey("data"))
89 {
90 metadata.Methods["data"] = new Uri(String.Format("{0}://{1}/{2}/data",
91 request.Uri.Scheme, request.Uri.Authority, assetID));
92 }
93
94 byte[] serializedData = metadata.SerializeToBytes();
95
96 response.Status = HttpStatusCode.OK;
97 response.ContentType = "application/json";
98 response.ContentLength = serializedData.Length;
99 response.Body.Write(serializedData, 0, serializedData.Length);
100
101 }
102 else if (storageResponse == BackendResponse.NotFound)
103 {
104 Logger.Log.Warn("Could not find metadata for asset " + assetID.ToString());
105 response.Status = HttpStatusCode.NotFound;
106 }
107 else
108 {
109 response.Status = HttpStatusCode.InternalServerError;
110 }
111 }
112 else
113 {
114 response.Status = HttpStatusCode.Forbidden;
115 }
116
117 return true;
118 }
119
120 response.Status = HttpStatusCode.NotFound;
121 return true;
122 }
123
124 bool DataRequestHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
125 {
126 UUID assetID;
127 // Split the URL up into an AssetID and a method
128 string[] rawUrl = request.Uri.PathAndQuery.Split('/');
129
130 if (rawUrl.Length >= 3 && UUID.TryParse(rawUrl[1], out assetID))
131 {
132 UUID authToken = Utils.GetAuthToken(request);
133
134 if (server.AuthorizationProvider.IsDataAuthorized(authToken, assetID))
135 {
136 byte[] assetData;
137 BackendResponse storageResponse = server.StorageProvider.TryFetchData(assetID, out assetData);
138
139 if (storageResponse == BackendResponse.Success)
140 {
141 response.Status = HttpStatusCode.OK;
142 response.Status = HttpStatusCode.OK;
143 response.ContentType = "application/octet-stream";
144 response.AddHeader("Content-Disposition", "attachment; filename=" + assetID.ToString());
145 response.ContentLength = assetData.Length;
146 response.Body.Write(assetData, 0, assetData.Length);
147 }
148 else if (storageResponse == BackendResponse.NotFound)
149 {
150 response.Status = HttpStatusCode.NotFound;
151 }
152 else
153 {
154 response.Status = HttpStatusCode.InternalServerError;
155 }
156 }
157 else
158 {
159 response.Status = HttpStatusCode.Forbidden;
160 }
161
162 return true;
163 }
164
165 response.Status = HttpStatusCode.BadRequest;
166 return true;
167 }
168
169 bool CreateRequestHandler(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
170 {
171 UUID authToken = Utils.GetAuthToken(request);
172
173 if (server.AuthorizationProvider.IsCreateAuthorized(authToken))
174 {
175 try
176 {
177 OSD osdata = OSDParser.DeserializeJson(request.Body);
178
179 if (osdata.Type == OSDType.Map)
180 {
181 OSDMap map = (OSDMap)osdata;
182 Metadata metadata = new Metadata();
183 metadata.Deserialize(map);
184
185 byte[] assetData = map["data"].AsBinary();
186
187 if (assetData != null && assetData.Length > 0)
188 {
189 BackendResponse storageResponse;
190
191 if (metadata.ID != UUID.Zero)
192 storageResponse = server.StorageProvider.TryCreateAsset(metadata, assetData);
193 else
194 storageResponse = server.StorageProvider.TryCreateAsset(metadata, assetData, out metadata.ID);
195
196 if (storageResponse == BackendResponse.Success)
197 {
198 response.Status = HttpStatusCode.Created;
199 OSDMap responseMap = new OSDMap(1);
200 responseMap["id"] = OSD.FromUUID(metadata.ID);
201 LitJson.JsonData jsonData = OSDParser.SerializeJson(responseMap);
202 byte[] responseData = System.Text.Encoding.UTF8.GetBytes(jsonData.ToJson());
203 response.Body.Write(responseData, 0, responseData.Length);
204 response.Body.Flush();
205 }
206 else if (storageResponse == BackendResponse.NotFound)
207 {
208 response.Status = HttpStatusCode.NotFound;
209 }
210 else
211 {
212 response.Status = HttpStatusCode.InternalServerError;
213 }
214 }
215 else
216 {
217 response.Status = HttpStatusCode.BadRequest;
218 }
219 }
220 else
221 {
222 response.Status = HttpStatusCode.BadRequest;
223 }
224 }
225 catch (Exception ex)
226 {
227 response.Status = HttpStatusCode.InternalServerError;
228 response.Reason = ex.Message;
229 }
230 }
231 else
232 {
233 response.Status = HttpStatusCode.Forbidden;
234 }
235
236 return true;
237 }
238 }
239}
diff --git a/OpenSim/Grid/NewAssetServer/Extensions/SimpleInventory.cs b/OpenSim/Grid/NewAssetServer/Extensions/SimpleInventory.cs
new file mode 100644
index 0000000..782b6b4
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Extensions/SimpleInventory.cs
@@ -0,0 +1,602 @@
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.Text;
35using ExtensionLoader;
36using OpenMetaverse;
37using OpenMetaverse.StructuredData;
38
39namespace AssetServer.Extensions
40{
41 public class SimpleInventory : IExtension<AssetServer>, IInventoryProvider
42 {
43 const string EXTENSION_NAME = "SimpleInventory"; // Used for metrics reporting
44 const string DEFAULT_INVENTORY_DIR = "SimpleInventory";
45
46 AssetServer server;
47 Dictionary<Uri, InventoryCollection> inventories = new Dictionary<Uri, InventoryCollection>();
48 Dictionary<Uri, List<InventoryItem>> activeGestures = new Dictionary<Uri, List<InventoryItem>>();
49 Utils.InventoryItemSerializer itemSerializer = new Utils.InventoryItemSerializer();
50 Utils.InventoryFolderSerializer folderSerializer = new Utils.InventoryFolderSerializer();
51
52 public SimpleInventory()
53 {
54 }
55
56 #region Required Interfaces
57
58 public void Start(AssetServer server)
59 {
60 this.server = server;
61
62 LoadFiles(DEFAULT_INVENTORY_DIR);
63
64 Logger.Log.InfoFormat("Initialized the inventory index with data for {0} avatars",
65 inventories.Count);
66 }
67
68 public void Stop()
69 {
70 }
71
72 public BackendResponse TryFetchItem(Uri owner, UUID itemID, out InventoryItem item)
73 {
74 item = null;
75 BackendResponse ret;
76
77 InventoryCollection collection;
78 if (inventories.TryGetValue(owner, out collection) && collection.Items.TryGetValue(itemID, out item))
79 ret = BackendResponse.Success;
80 else
81 ret = BackendResponse.NotFound;
82
83 server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, ret, owner, itemID, false, DateTime.Now);
84 return ret;
85 }
86
87 public BackendResponse TryFetchFolder(Uri owner, UUID folderID, out InventoryFolder folder)
88 {
89 folder = null;
90 BackendResponse ret;
91
92 InventoryCollection collection;
93 if (inventories.TryGetValue(owner, out collection) && collection.Folders.TryGetValue(folderID, out folder))
94 ret = BackendResponse.Success;
95 else
96 ret = BackendResponse.NotFound;
97
98 server.MetricsProvider.LogInventoryFetch(EXTENSION_NAME, ret, owner, folderID, true, DateTime.Now);
99 return ret;
100 }
101
102 public BackendResponse TryFetchFolderContents(Uri owner, UUID folderID, out InventoryCollection contents)
103 {
104 contents = null;
105 BackendResponse ret;
106
107 InventoryCollection collection;
108 InventoryFolder folder;
109
110 if (inventories.TryGetValue(owner, out collection) && collection.Folders.TryGetValue(folderID, out folder))
111 {
112 contents = new InventoryCollection();
113 contents.UserID = collection.UserID;
114 contents.Folders = new Dictionary<UUID, InventoryFolder>();
115 contents.Items = new Dictionary<UUID, InventoryItem>();
116
117 foreach (InventoryBase invBase in folder.Children.Values)
118 {
119 if (invBase is InventoryItem)
120 {
121 InventoryItem invItem = invBase as InventoryItem;
122 contents.Items.Add(invItem.ID, invItem);
123 }
124 else
125 {
126 InventoryFolder invFolder = invBase as InventoryFolder;
127 contents.Folders.Add(invFolder.ID, invFolder);
128 }
129 }
130
131 ret = BackendResponse.Success;
132 }
133 else
134 {
135 ret = BackendResponse.NotFound;
136 }
137
138 server.MetricsProvider.LogInventoryFetchFolderContents(EXTENSION_NAME, ret, owner, folderID, DateTime.Now);
139 return ret;
140 }
141
142 public BackendResponse TryFetchFolderList(Uri owner, out List<InventoryFolder> folders)
143 {
144 folders = null;
145 BackendResponse ret;
146
147 InventoryCollection collection;
148 if (inventories.TryGetValue(owner, out collection))
149 {
150 folders = new List<InventoryFolder>(collection.Folders.Values);
151 return BackendResponse.Success;
152 }
153 else
154 {
155 ret = BackendResponse.NotFound;
156 }
157
158 server.MetricsProvider.LogInventoryFetchFolderList(EXTENSION_NAME, ret, owner, DateTime.Now);
159 return ret;
160 }
161
162 public BackendResponse TryFetchInventory(Uri owner, out InventoryCollection inventory)
163 {
164 inventory = null;
165 BackendResponse ret;
166
167 if (inventories.TryGetValue(owner, out inventory))
168 ret = BackendResponse.Success;
169 else
170 ret = BackendResponse.NotFound;
171
172 server.MetricsProvider.LogInventoryFetchInventory(EXTENSION_NAME, ret, owner, DateTime.Now);
173 return ret;
174 }
175
176 public BackendResponse TryFetchActiveGestures(Uri owner, out List<InventoryItem> gestures)
177 {
178 gestures = null;
179 BackendResponse ret;
180
181 if (activeGestures.TryGetValue(owner, out gestures))
182 ret = BackendResponse.Success;
183 else
184 ret = BackendResponse.NotFound;
185
186 server.MetricsProvider.LogInventoryFetchActiveGestures(EXTENSION_NAME, ret, owner, DateTime.Now);
187 return ret;
188 }
189
190 public BackendResponse TryCreateItem(Uri owner, InventoryItem item)
191 {
192 BackendResponse ret;
193
194 InventoryCollection collection;
195 if (inventories.TryGetValue(owner, out collection))
196 {
197 // Delete this item first if it already exists
198 InventoryItem oldItem;
199 if (collection.Items.TryGetValue(item.ID, out oldItem))
200 TryDeleteItem(owner, item.ID);
201
202 try
203 {
204 // Create the file
205 SaveItem(item);
206
207 // Add the item to the collection
208 lock (collection) collection.Items[item.ID] = item;
209
210 // Add the item to its parent folder
211 InventoryFolder parent;
212 if (collection.Folders.TryGetValue(item.Folder, out parent))
213 lock (parent.Children) parent.Children.Add(item.ID, item);
214
215 // Add active gestures to our list
216 if (item.InvType == (int)InventoryType.Gesture && item.Flags == 1)
217 {
218 lock (activeGestures)
219 activeGestures[owner].Add(item);
220 }
221
222 ret = BackendResponse.Success;
223 }
224 catch (Exception ex)
225 {
226 Logger.Log.Error(ex.Message);
227 ret = BackendResponse.Failure;
228 }
229 }
230 else
231 {
232 return BackendResponse.NotFound;
233 }
234
235 server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, ret, owner, false, DateTime.Now);
236 return ret;
237 }
238
239 public BackendResponse TryCreateFolder(Uri owner, InventoryFolder folder)
240 {
241 BackendResponse ret;
242
243 InventoryCollection collection;
244 if (inventories.TryGetValue(owner, out collection))
245 {
246 // Delete this folder first if it already exists
247 InventoryFolder oldFolder;
248 if (collection.Folders.TryGetValue(folder.ID, out oldFolder))
249 TryDeleteFolder(owner, folder.ID);
250
251 try
252 {
253 // Create the file
254 SaveFolder(folder);
255
256 // Add the folder to the collection
257 lock (collection) collection.Folders[folder.ID] = folder;
258
259 // Add the folder to its parent folder
260 InventoryFolder parent;
261 if (collection.Folders.TryGetValue(folder.ParentID, out parent))
262 lock (parent.Children) parent.Children.Add(folder.ID, folder);
263
264 ret = BackendResponse.Success;
265 }
266 catch (Exception ex)
267 {
268 Logger.Log.Error(ex.Message);
269 ret = BackendResponse.Failure;
270 }
271 }
272 else
273 {
274 ret = BackendResponse.NotFound;
275 }
276
277 server.MetricsProvider.LogInventoryCreate(EXTENSION_NAME, ret, owner, true, DateTime.Now);
278 return ret;
279 }
280
281 public BackendResponse TryCreateInventory(Uri owner, InventoryFolder rootFolder)
282 {
283 BackendResponse ret;
284
285 lock (inventories)
286 {
287 if (!inventories.ContainsKey(owner))
288 {
289 InventoryCollection collection = new InventoryCollection();
290 collection.UserID = rootFolder.Owner;
291 collection.Folders = new Dictionary<UUID, InventoryFolder>();
292 collection.Folders.Add(rootFolder.ID, rootFolder);
293 collection.Items = new Dictionary<UUID, InventoryItem>();
294
295 inventories.Add(owner, collection);
296
297 ret = BackendResponse.Success;
298 }
299 else
300 {
301 ret = BackendResponse.Failure;
302 }
303 }
304
305 if (ret == BackendResponse.Success)
306 {
307 string path = Path.Combine(DEFAULT_INVENTORY_DIR, rootFolder.Owner.ToString());
308 try
309 {
310 // Create the directory for this agent
311 Directory.CreateDirectory(path);
312
313 // Create an index.txt containing the UUID and URI for this agent
314 string[] index = new string[] { rootFolder.Owner.ToString(), owner.ToString() };
315 File.WriteAllLines(Path.Combine(path, "index.txt"), index);
316
317 // Create the root folder file
318 SaveFolder(rootFolder);
319 }
320 catch (Exception ex)
321 {
322 Logger.Log.Error(ex.Message);
323 ret = BackendResponse.Failure;
324 }
325 }
326
327 server.MetricsProvider.LogInventoryCreateInventory(EXTENSION_NAME, ret, DateTime.Now);
328 return ret;
329 }
330
331 public BackendResponse TryDeleteItem(Uri owner, UUID itemID)
332 {
333 BackendResponse ret;
334
335 InventoryCollection collection;
336 InventoryItem item;
337 if (inventories.TryGetValue(owner, out collection) && collection.Items.TryGetValue(itemID, out item))
338 {
339 // Remove the item from its parent folder
340 InventoryFolder parent;
341 if (collection.Folders.TryGetValue(item.Folder, out parent))
342 lock (parent.Children) parent.Children.Remove(itemID);
343
344 // Remove the item from the collection
345 lock (collection) collection.Items.Remove(itemID);
346
347 // Remove from the active gestures list if applicable
348 if (item.InvType == (int)InventoryType.Gesture)
349 {
350 lock (activeGestures)
351 {
352 for (int i = 0; i < activeGestures[owner].Count; i++)
353 {
354 if (activeGestures[owner][i].ID == itemID)
355 {
356 activeGestures[owner].RemoveAt(i);
357 break;
358 }
359 }
360 }
361 }
362
363 // Delete the file. We don't know exactly what the file name is,
364 // so search for it
365 string path = PathFromURI(owner);
366 string[] matches = Directory.GetFiles(path, String.Format("*{0}.item", itemID), SearchOption.TopDirectoryOnly);
367 foreach (string match in matches)
368 {
369 try { File.Delete(match); }
370 catch (Exception ex) { Logger.Log.ErrorFormat("Failed to delete file {0}: {1}", match, ex.Message); }
371 }
372
373 ret = BackendResponse.Success;
374 }
375 else
376 {
377 ret = BackendResponse.NotFound;
378 }
379
380 server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, ret, owner, itemID, false, DateTime.Now);
381 return ret;
382 }
383
384 public BackendResponse TryDeleteFolder(Uri owner, UUID folderID)
385 {
386 BackendResponse ret;
387
388 InventoryCollection collection;
389 InventoryFolder folder;
390 if (inventories.TryGetValue(owner, out collection) && collection.Folders.TryGetValue(folderID, out folder))
391 {
392 // Remove the folder from its parent folder
393 InventoryFolder parent;
394 if (collection.Folders.TryGetValue(folder.ParentID, out parent))
395 lock (parent.Children) parent.Children.Remove(folderID);
396
397 // Remove the folder from the collection
398 lock (collection) collection.Items.Remove(folderID);
399
400 // Delete the folder file. We don't know exactly what the file name is,
401 // so search for it
402 string path = PathFromURI(owner);
403 string[] matches = Directory.GetFiles(path, String.Format("*{0}.folder", folderID), SearchOption.TopDirectoryOnly);
404 foreach (string match in matches)
405 {
406 try { File.Delete(match); }
407 catch (Exception ex) { Logger.Log.ErrorFormat("Failed to delete folder file {0}: {1}", match, ex.Message); }
408 }
409
410 ret = BackendResponse.Success;
411 }
412 else
413 {
414 ret = BackendResponse.NotFound;
415 }
416
417 server.MetricsProvider.LogInventoryDelete(EXTENSION_NAME, ret, owner, folderID, true, DateTime.Now);
418 return ret;
419 }
420
421 public BackendResponse TryPurgeFolder(Uri owner, UUID folderID)
422 {
423 BackendResponse ret;
424
425 InventoryCollection collection;
426 InventoryFolder folder;
427 if (inventories.TryGetValue(owner, out collection) && collection.Folders.TryGetValue(folderID, out folder))
428 {
429 // Delete all of the folder children
430 foreach (InventoryBase obj in new List<InventoryBase>(folder.Children.Values))
431 {
432 if (obj is InventoryItem)
433 {
434 TryDeleteItem(owner, (obj as InventoryItem).ID);
435 }
436 else
437 {
438 InventoryFolder childFolder = obj as InventoryFolder;
439 TryPurgeFolder(owner, childFolder.ID);
440 TryDeleteFolder(owner, childFolder.ID);
441 }
442 }
443
444 ret = BackendResponse.Success;
445 }
446 else
447 {
448 ret = BackendResponse.NotFound;
449 }
450
451 server.MetricsProvider.LogInventoryPurgeFolder(EXTENSION_NAME, ret, owner, folderID, DateTime.Now);
452 return ret;
453 }
454
455 #endregion Required Interfaces
456
457 void SaveItem(InventoryItem item)
458 {
459 string filename = String.Format("{0}-{1}.item", SanitizeFilename(item.Name), item.ID);
460
461 string path = Path.Combine(DEFAULT_INVENTORY_DIR, item.Owner.ToString());
462 path = Path.Combine(path, filename);
463
464 using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write))
465 {
466 itemSerializer.Serialize(stream, item);
467 stream.Flush();
468 }
469 }
470
471 void SaveFolder(InventoryFolder folder)
472 {
473 string filename = String.Format("{0}-{1}.folder", SanitizeFilename(folder.Name), folder.ID);
474
475 string path = Path.Combine(DEFAULT_INVENTORY_DIR, folder.Owner.ToString());
476 path = Path.Combine(path, filename);
477
478 using (FileStream stream = new FileStream(path, FileMode.Create, FileAccess.Write))
479 {
480 folderSerializer.Serialize(stream, folder);
481 stream.Flush();
482 }
483 }
484
485 string SanitizeFilename(string filename)
486 {
487 string output = filename;
488
489 if (output.Length > 64)
490 output = output.Substring(0, 64);
491
492 foreach (char i in Path.GetInvalidFileNameChars())
493 output = output.Replace(i, '_');
494
495 return output;
496 }
497
498 static string PathFromURI(Uri uri)
499 {
500 byte[] hash = OpenMetaverse.Utils.SHA1(Encoding.UTF8.GetBytes(uri.ToString()));
501 StringBuilder digest = new StringBuilder(40);
502
503 // Convert the hash to a hex string
504 foreach (byte b in hash)
505 digest.AppendFormat(OpenMetaverse.Utils.EnUsCulture, "{0:x2}", b);
506
507 return Path.Combine(DEFAULT_INVENTORY_DIR, digest.ToString());
508 }
509
510 void LoadFiles(string folder)
511 {
512 // Try to create the directory if it doesn't already exist
513 if (!Directory.Exists(folder))
514 {
515 try { Directory.CreateDirectory(folder); }
516 catch (Exception ex)
517 {
518 Logger.Log.Warn(ex.Message);
519 return;
520 }
521 }
522
523 try
524 {
525 string[] agentFolders = Directory.GetDirectories(DEFAULT_INVENTORY_DIR);
526
527 for (int i = 0; i < agentFolders.Length; i++)
528 {
529 string foldername = agentFolders[i];
530 string indexPath = Path.Combine(foldername, "index.txt");
531 UUID ownerID = UUID.Zero;
532 Uri owner = null;
533
534 try
535 {
536 string[] index = File.ReadAllLines(indexPath);
537 ownerID = UUID.Parse(index[0]);
538 owner = new Uri(index[1]);
539 }
540 catch (Exception ex)
541 {
542 Logger.Log.WarnFormat("Failed loading the index file {0}: {1}", indexPath, ex.Message);
543 }
544
545 if (ownerID != UUID.Zero && owner != null)
546 {
547 // Initialize the active gestures list for this agent
548 activeGestures.Add(owner, new List<InventoryItem>());
549
550 InventoryCollection collection = new InventoryCollection();
551 collection.UserID = ownerID;
552
553 // Load all of the folders for this agent
554 string[] folders = Directory.GetFiles(foldername, "*.folder", SearchOption.TopDirectoryOnly);
555 collection.Folders = new Dictionary<UUID,InventoryFolder>(folders.Length);
556
557 for (int j = 0; j < folders.Length; j++)
558 {
559 InventoryFolder invFolder = (InventoryFolder)folderSerializer.Deserialize(
560 new FileStream(folders[j], FileMode.Open, FileAccess.Read));
561 collection.Folders[invFolder.ID] = invFolder;
562 }
563
564 // Iterate over the folders collection, adding children to their parents
565 foreach (InventoryFolder invFolder in collection.Folders.Values)
566 {
567 InventoryFolder parent;
568 if (collection.Folders.TryGetValue(invFolder.ParentID, out parent))
569 parent.Children[invFolder.ID] = invFolder;
570 }
571
572 // Load all of the items for this agent
573 string[] files = Directory.GetFiles(foldername, "*.item", SearchOption.TopDirectoryOnly);
574 collection.Items = new Dictionary<UUID, InventoryItem>(files.Length);
575
576 for (int j = 0; j < files.Length; j++)
577 {
578 InventoryItem invItem = (InventoryItem)itemSerializer.Deserialize(
579 new FileStream(files[j], FileMode.Open, FileAccess.Read));
580 collection.Items[invItem.ID] = invItem;
581
582 // Add items to their parent folders
583 InventoryFolder parent;
584 if (collection.Folders.TryGetValue(invItem.Folder, out parent))
585 parent.Children[invItem.ID] = invItem;
586
587 // Add active gestures to our list
588 if (invItem.InvType == (int)InventoryType.Gesture && invItem.Flags != 0)
589 activeGestures[owner].Add(invItem);
590 }
591
592 inventories.Add(owner, collection);
593 }
594 }
595 }
596 catch (Exception ex)
597 {
598 Logger.Log.ErrorFormat("Failed loading inventory from {0}: {1}", folder, ex.Message);
599 }
600 }
601 }
602}
diff --git a/OpenSim/Grid/NewAssetServer/Extensions/SimpleStorage.cs b/OpenSim/Grid/NewAssetServer/Extensions/SimpleStorage.cs
new file mode 100644
index 0000000..1c0fe33
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Extensions/SimpleStorage.cs
@@ -0,0 +1,260 @@
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 AssetServer.Extensions
39{
40 public class SimpleStorage : IExtension<AssetServer>, 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 AssetServer 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(AssetServer 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}
diff --git a/OpenSim/Grid/NewAssetServer/Extensions/SimpleUtils.cs b/OpenSim/Grid/NewAssetServer/Extensions/SimpleUtils.cs
new file mode 100644
index 0000000..6642f90
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Extensions/SimpleUtils.cs
@@ -0,0 +1,44 @@
1using System;
2using System.IO;
3using OpenMetaverse;
4
5namespace AssetServer.Extensions
6{
7 public static class SimpleUtils
8 {
9 public static string ParseNameFromFilename(string filename)
10 {
11 filename = Path.GetFileName(filename);
12
13 int dot = filename.LastIndexOf('.');
14 int firstDash = filename.IndexOf('-');
15
16 if (dot - 37 > 0 && firstDash > 0)
17 return filename.Substring(0, firstDash);
18 else
19 return String.Empty;
20 }
21
22 public static UUID ParseUUIDFromFilename(string filename)
23 {
24 int dot = filename.LastIndexOf('.');
25
26 if (dot > 35)
27 {
28 // Grab the last 36 characters of the filename
29 string uuidString = filename.Substring(dot - 36, 36);
30 UUID uuid;
31 UUID.TryParse(uuidString, out uuid);
32 return uuid;
33 }
34 else
35 {
36 UUID uuid;
37 if (UUID.TryParse(Path.GetFileName(filename), out uuid))
38 return uuid;
39 else
40 return UUID.Zero;
41 }
42 }
43 }
44}