aboutsummaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
authorMike Mazur2009-02-16 02:24:57 +0000
committerMike Mazur2009-02-16 02:24:57 +0000
commit0e09b4a08beddb3b0239a3f088ab9a230b8f3979 (patch)
tree481d1cb9a60062dea6e646e0e6c5d9d87ce40b6e
parentThank you, cmickeyb, for a patch to ass two string functions (diff)
downloadopensim-SC-0e09b4a08beddb3b0239a3f088ab9a230b8f3979.zip
opensim-SC-0e09b4a08beddb3b0239a3f088ab9a230b8f3979.tar.gz
opensim-SC-0e09b4a08beddb3b0239a3f088ab9a230b8f3979.tar.bz2
opensim-SC-0e09b4a08beddb3b0239a3f088ab9a230b8f3979.tar.xz
Adding
- NewAssetServer code - NewAssetServer addin manifest - example AssetServer.ini file
-rw-r--r--OpenSim/Grid/NewAssetServer/AssetServer.cs262
-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
-rw-r--r--OpenSim/Grid/NewAssetServer/Interfaces.cs157
-rw-r--r--OpenSim/Grid/NewAssetServer/InventoryObjects.cs107
-rw-r--r--OpenSim/Grid/NewAssetServer/Logger.cs62
-rw-r--r--OpenSim/Grid/NewAssetServer/Main.cs62
-rw-r--r--OpenSim/Grid/NewAssetServer/Metadata.cs85
-rw-r--r--OpenSim/Grid/NewAssetServer/Plugins/OpenSim/OpenSimAssetStoragePlugin.cs352
-rw-r--r--OpenSim/Grid/NewAssetServer/Plugins/OpenSim/Resources/AssetServerOpenSimPlugins.addin.xml14
-rw-r--r--OpenSim/Grid/NewAssetServer/Utils.cs1034
-rw-r--r--bin/AssetServer.ini.example153
-rw-r--r--bin/OpenSim.Grid.NewAssetServer.addin.xml21
24 files changed, 5893 insertions, 0 deletions
diff --git a/OpenSim/Grid/NewAssetServer/AssetServer.cs b/OpenSim/Grid/NewAssetServer/AssetServer.cs
new file mode 100644
index 0000000..c6864e7
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/AssetServer.cs
@@ -0,0 +1,262 @@
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.IO;
33using System.Net;
34using System.Reflection;
35using System.Security.Cryptography.X509Certificates;
36using System.ServiceProcess;
37using ExtensionLoader;
38using ExtensionLoader.Config;
39using HttpServer;
40using log4net;
41using OpenSim.Framework;
42
43namespace AssetServer
44{
45 public class AssetServer : ServiceBase
46 {
47 public const string CONFIG_FILE = "AssetServer.ini";
48
49 public WebServer HttpServer;
50 public IniConfigSource ConfigFile;
51
52 public IAssetStorageProvider StorageProvider;
53 public IInventoryProvider InventoryProvider;
54 public IAuthenticationProvider AuthenticationProvider;
55 public IAuthorizationProvider AuthorizationProvider;
56 public IMetricsProvider MetricsProvider;
57
58 public AssetServer()
59 {
60 this.ServiceName = "OpenSimAssetServer";
61 }
62
63 public bool Start()
64 {
65 Logger.Log.Info("Starting Asset Server");
66 List<string> extensionList = null;
67 int port = 0;
68 X509Certificate2 serverCert = null;
69
70 try { ConfigFile = new IniConfigSource(CONFIG_FILE); }
71 catch (Exception)
72 {
73 Logger.Log.Error("Failed to load the config file " + CONFIG_FILE);
74 return false;
75 }
76
77 try
78 {
79 IConfig extensionConfig = ConfigFile.Configs["Config"];
80
81 // Load the port number to listen on
82 port = extensionConfig.GetInt("ListenPort");
83
84 // Load the server certificate file
85 string certFile = extensionConfig.GetString("SSLCertFile");
86 if (!String.IsNullOrEmpty(certFile))
87 serverCert = new X509Certificate2(certFile);
88 }
89 catch (Exception)
90 {
91 Logger.Log.Error("Failed to load [Config] section from " + CONFIG_FILE);
92 return false;
93 }
94
95 try
96 {
97 // Load the extension list (and ordering) from our config file
98 IConfig extensionConfig = ConfigFile.Configs["Extensions"];
99 extensionList = new List<string>(extensionConfig.GetKeys());
100 }
101 catch (Exception)
102 {
103 Logger.Log.Error("Failed to load [Extensions] section from " + CONFIG_FILE);
104 return false;
105 }
106
107 //try
108 //{
109 // // Create a reference list for C# extensions compiled at runtime
110 // List<string> references = new List<string>();
111 // references.Add("OpenMetaverseTypes.dll");
112 // references.Add("OpenMetaverse.dll");
113 // references.Add("OpenMetaverse.StructuredData.dll");
114 // references.Add("OpenMetaverse.Http.dll");
115 // references.Add("ExtensionLoader.dll");
116 // references.Add("AssetServer.exe");
117
118 // // Get a list of all of the members of AssetServer that are interfaces
119 // List<FieldInfo> assignables = ExtensionLoader<AssetServer>.GetInterfaces(this);
120
121 // // Load all of the extensions
122 // ExtensionLoader<AssetServer>.LoadAllExtensions(
123 // Assembly.GetExecutingAssembly(),
124 // Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location),
125 // extensionList,
126 // references,
127 // "AssetServer.*.dll",
128 // "AssetServer.*.cs",
129 // this,
130 // assignables);
131 //}
132 //catch (ExtensionException ex)
133 //{
134 // Logger.Log.Error("Interface loading failed, shutting down: " + ex.Message);
135 // if (ex.InnerException != null)
136 // Logger.Log.Error(ex.InnerException.Message, ex.InnerException);
137 // Stop();
138 // return false;
139 //}
140
141 StorageProvider = LoadAssetServerPlugin() as IAssetStorageProvider;
142
143 try
144 {
145 InitHttpServer(port, serverCert);
146 }
147 catch (Exception ex)
148 {
149 Logger.Log.Error("Initializing the HTTP server failed, shutting down: " + ex.Message);
150 Stop();
151 return false;
152 }
153
154 // Start all of the extensions
155 //foreach (IExtension<AssetServer> extension in ExtensionLoader<AssetServer>.Extensions)
156 //{
157 // Logger.Log.Info("Starting extension " + extension.GetType().Name);
158 // extension.Start(this);
159 //}
160
161 return true;
162 }
163
164 public void Shutdown()
165 {
166 foreach (IExtension<AssetServer> extension in ExtensionLoader<AssetServer>.Extensions)
167 {
168 Logger.Log.Debug("Disposing extension " + extension.GetType().Name);
169 try { extension.Stop(); }
170 catch (Exception ex)
171 { Logger.Log.ErrorFormat("Failure shutting down extension {0}: {1}", extension.GetType().Name, ex.Message); }
172 }
173
174 if (HttpServer != null)
175 HttpServer.Stop();
176 }
177
178 void InitHttpServer(int port, X509Certificate serverCert)
179 {
180 if (serverCert != null)
181 HttpServer = new WebServer(IPAddress.Any, port, serverCert, null, false);
182 else
183 HttpServer = new WebServer(IPAddress.Any, port);
184
185 HttpServer.LogWriter = new log4netLogWriter(Logger.Log);
186
187 HttpServer.Set404Handler(
188 delegate(IHttpClientContext client, IHttpRequest request, IHttpResponse response)
189 {
190 Logger.Log.Warn("Requested page was not found: " + request.Uri.PathAndQuery);
191
192 string notFoundString = "<html><head><title>Page Not Found</title></head><body>The requested page or method was not found</body></html>";
193 byte[] buffer = System.Text.Encoding.UTF8.GetBytes(notFoundString);
194 response.Body.Write(buffer, 0, buffer.Length);
195 response.Status = HttpStatusCode.NotFound;
196 return true;
197 }
198 );
199
200 HttpServer.Start();
201
202 Logger.Log.Info("Asset server is listening on port " + port);
203 }
204
205 #region ServiceBase Overrides
206
207 protected override void OnStart(string[] args)
208 {
209 Start();
210 }
211 protected override void OnStop()
212 {
213 Shutdown();
214 }
215
216 #endregion
217
218 private IAssetServerPlugin LoadAssetServerPlugin()
219 {
220 PluginLoader<IAssetServerPlugin> loader = new PluginLoader<IAssetServerPlugin>(new AssetServerPluginInitialiser(this));
221
222 //loader.Add ("/OpenSim/AssetServer/StorageProvider", new PluginProviderFilter (provider));
223 loader.Add("/OpenSim/AssetServer/StorageProvider", new PluginCountConstraint(1));
224 loader.Load();
225
226 return loader.Plugin;
227 }
228 }
229
230 public class log4netLogWriter : ILogWriter
231 {
232 ILog Log;
233
234 public log4netLogWriter(ILog log)
235 {
236 Log = log;
237 }
238
239 public void Write(object source, LogPrio prio, string message)
240 {
241 switch (prio)
242 {
243 case LogPrio.Trace:
244 case LogPrio.Debug:
245 Log.DebugFormat("{0}: {1}", source, message);
246 break;
247 case LogPrio.Info:
248 Log.InfoFormat("{0}: {1}", source, message);
249 break;
250 case LogPrio.Warning:
251 Log.WarnFormat("{0}: {1}", source, message);
252 break;
253 case LogPrio.Error:
254 Log.ErrorFormat("{0}: {1}", source, message);
255 break;
256 case LogPrio.Fatal:
257 Log.FatalFormat("{0}: {1}", source, message);
258 break;
259 }
260 }
261 }
262}
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}
diff --git a/OpenSim/Grid/NewAssetServer/Interfaces.cs b/OpenSim/Grid/NewAssetServer/Interfaces.cs
new file mode 100644
index 0000000..8368922
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Interfaces.cs
@@ -0,0 +1,157 @@
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 OpenMetaverse;
34using OpenMetaverse.StructuredData;
35using OpenSim.Framework;
36
37namespace AssetServer
38{
39 /// <summary>
40 /// Response from a call to a backend provider
41 /// </summary>
42 public enum BackendResponse
43 {
44 /// <summary>The call succeeded</summary>
45 Success,
46 /// <summary>The resource requested was not found</summary>
47 NotFound,
48 /// <summary>A server failure prevented the call from
49 /// completing</summary>
50 Failure
51 }
52
53 public class AssetServerPluginInitialiser : PluginInitialiserBase
54 {
55 private AssetServer server;
56
57 public AssetServerPluginInitialiser (AssetServer server)
58 {
59 this.server = server;
60 }
61
62 public override void Initialise (IPlugin plugin)
63 {
64 IAssetServerPlugin p = plugin as IAssetServerPlugin;
65 p.Initialise (server);
66 }
67 }
68
69 #region Interfaces
70
71 public interface IAssetServerPlugin : IPlugin
72 {
73 void Initialise(AssetServer server);
74 }
75
76 public interface IStorageProvider
77 {
78 BackendResponse TryFetchMetadata(UUID assetID, out Metadata metadata);
79 BackendResponse TryFetchData(UUID assetID, out byte[] assetData);
80 BackendResponse TryFetchDataMetadata(UUID assetID, out Metadata metadata, out byte[] assetData);
81 BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData);
82 BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData, out UUID assetID);
83 int ForEach(Action<Metadata> action, int start, int count);
84 }
85
86 public interface IAssetStorageProvider : IAssetServerPlugin
87 {
88 BackendResponse TryFetchMetadata(UUID assetID, out Metadata metadata);
89 BackendResponse TryFetchData(UUID assetID, out byte[] assetData);
90 BackendResponse TryFetchDataMetadata(UUID assetID, out Metadata metadata, out byte[] assetData);
91 BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData);
92 BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData, out UUID assetID);
93 int ForEach(Action<Metadata> action, int start, int count);
94 }
95
96 public interface IInventoryProvider
97 {
98 BackendResponse TryFetchItem(Uri owner, UUID itemID, out InventoryItem item);
99 BackendResponse TryFetchFolder(Uri owner, UUID folderID, out InventoryFolder folder);
100 BackendResponse TryFetchFolderContents(Uri owner, UUID folderID, out InventoryCollection contents);
101 BackendResponse TryFetchFolderList(Uri owner, out List<InventoryFolder> folders);
102 BackendResponse TryFetchInventory(Uri owner, out InventoryCollection inventory);
103
104 BackendResponse TryFetchActiveGestures(Uri owner, out List<InventoryItem> gestures);
105
106 BackendResponse TryCreateItem(Uri owner, InventoryItem item);
107 BackendResponse TryCreateFolder(Uri owner, InventoryFolder folder);
108 BackendResponse TryCreateInventory(Uri owner, InventoryFolder rootFolder);
109
110 BackendResponse TryDeleteItem(Uri owner, UUID itemID);
111 BackendResponse TryDeleteFolder(Uri owner, UUID folderID);
112 BackendResponse TryPurgeFolder(Uri owner, UUID folderID);
113 }
114
115 public interface IAuthenticationProvider
116 {
117 void AddIdentifier(UUID authToken, Uri identifier);
118 bool RemoveIdentifier(UUID authToken);
119 bool TryGetIdentifier(UUID authToken, out Uri identifier);
120 }
121
122 public interface IAuthorizationProvider
123 {
124 bool IsMetadataAuthorized(UUID authToken, UUID assetID);
125 /// <summary>
126 /// Authorizes access to the data for an asset. Access to asset data
127 /// also implies access to the metadata for that asset
128 /// </summary>
129 /// <param name="authToken">Authentication token to check for access</param>
130 /// <param name="assetID">ID of the requested asset</param>
131 /// <returns>True if access is granted, otherwise false</returns>
132 bool IsDataAuthorized(UUID authToken, UUID assetID);
133 bool IsCreateAuthorized(UUID authToken);
134
135 bool IsInventoryReadAuthorized(UUID authToken, Uri owner);
136 bool IsInventoryWriteAuthorized(UUID authToken, Uri owner);
137 }
138
139 public interface IMetricsProvider
140 {
141 void LogAssetMetadataFetch(string extension, BackendResponse response, UUID assetID, DateTime time);
142 void LogAssetDataFetch(string extension, BackendResponse response, UUID assetID, int dataSize, DateTime time);
143 void LogAssetCreate(string extension, BackendResponse response, UUID assetID, int dataSize, DateTime time);
144
145 void LogInventoryFetch(string extension, BackendResponse response, Uri owner, UUID objID, bool folder, DateTime time);
146 void LogInventoryFetchFolderContents(string extension, BackendResponse response, Uri owner, UUID folderID, DateTime time);
147 void LogInventoryFetchFolderList(string extension, BackendResponse response, Uri owner, DateTime time);
148 void LogInventoryFetchInventory(string extension, BackendResponse response, Uri owner, DateTime time);
149 void LogInventoryFetchActiveGestures(string extension, BackendResponse response, Uri owner, DateTime time);
150 void LogInventoryCreate(string extension, BackendResponse response, Uri owner, bool folder, DateTime time);
151 void LogInventoryCreateInventory(string extension, BackendResponse response, DateTime time);
152 void LogInventoryDelete(string extension, BackendResponse response, Uri owner, UUID objID, bool folder, DateTime time);
153 void LogInventoryPurgeFolder(string extension, BackendResponse response, Uri owner, UUID folderID, DateTime time);
154 }
155
156 #endregion Interfaces
157}
diff --git a/OpenSim/Grid/NewAssetServer/InventoryObjects.cs b/OpenSim/Grid/NewAssetServer/InventoryObjects.cs
new file mode 100644
index 0000000..cffa643
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/InventoryObjects.cs
@@ -0,0 +1,107 @@
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 OpenMetaverse;
33
34namespace AssetServer
35{
36 public class InventoryBase
37 {
38 }
39
40 public class InventoryFolder : InventoryBase
41 {
42 public string Name;
43 public UUID Owner;
44 public UUID ParentID;
45 public UUID ID;
46 public short Type;
47 public ushort Version;
48
49 [NonSerialized]
50 public Dictionary<UUID, InventoryBase> Children = new Dictionary<UUID, InventoryBase>();
51
52 public InventoryFolder()
53 {
54 }
55
56 public InventoryFolder(string name, UUID ownerID, UUID parentID, short assetType)
57 {
58 ID = UUID.Random();
59 Name = name;
60 Owner = ownerID;
61 ParentID = parentID;
62 Type = assetType;
63 Version = 1;
64 }
65
66 public override string ToString()
67 {
68 return String.Format("{0} ({1})", Name, ID);
69 }
70 }
71
72 public class InventoryItem : InventoryBase
73 {
74 public UUID ID;
75 public int InvType;
76 public UUID Folder;
77 public UUID Owner;
78 public UUID Creator;
79 public string Name;
80 public string Description;
81 public uint NextPermissions;
82 public uint CurrentPermissions;
83 public uint BasePermissions;
84 public uint EveryOnePermissions;
85 public uint GroupPermissions;
86 public int AssetType;
87 public UUID AssetID;
88 public UUID GroupID;
89 public bool GroupOwned;
90 public int SalePrice;
91 public byte SaleType;
92 public uint Flags;
93 public int CreationDate;
94
95 public override string ToString()
96 {
97 return String.Format("{0} ({1})", Name, ID);
98 }
99 }
100
101 public class InventoryCollection
102 {
103 public Dictionary<UUID, InventoryFolder> Folders;
104 public Dictionary<UUID, InventoryItem> Items;
105 public UUID UserID;
106 }
107}
diff --git a/OpenSim/Grid/NewAssetServer/Logger.cs b/OpenSim/Grid/NewAssetServer/Logger.cs
new file mode 100644
index 0000000..dd40115
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Logger.cs
@@ -0,0 +1,62 @@
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 log4net;
32using log4net.Config;
33
34[assembly: log4net.Config.XmlConfigurator(ConfigFileExtension = "log4net")]
35
36namespace AssetServer
37{
38 /// <summary>
39 /// Singleton logging class for the entire library
40 /// </summary>
41 public static class Logger
42 {
43 /// <summary>log4net logging engine</summary>
44 public static ILog Log;
45
46 static Logger()
47 {
48 Log = LogManager.GetLogger(System.Reflection.Assembly.GetExecutingAssembly().FullName);
49
50 // If error level reporting isn't enabled we assume no logger is configured and initialize a default
51 // ConsoleAppender
52 if (!Log.Logger.IsEnabledFor(log4net.Core.Level.Error))
53 {
54 log4net.Appender.ConsoleAppender appender = new log4net.Appender.ConsoleAppender();
55 appender.Layout = new log4net.Layout.PatternLayout("%timestamp [%thread] %-5level - %message%newline");
56 BasicConfigurator.Configure(appender);
57
58 Log.Info("No log configuration found, defaulting to console logging");
59 }
60 }
61 }
62}
diff --git a/OpenSim/Grid/NewAssetServer/Main.cs b/OpenSim/Grid/NewAssetServer/Main.cs
new file mode 100644
index 0000000..9f7dd3e
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Main.cs
@@ -0,0 +1,62 @@
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.ServiceProcess;
32
33namespace AssetServer
34{
35 class MainEntry
36 {
37 static void Main(string[] args)
38 {
39#if DEBUG
40 AssetServer server = new AssetServer();
41 if (server.Start())
42 {
43 Console.WriteLine("Asset server is running. Press CTRL+C to quit");
44
45 Console.CancelKeyPress +=
46 delegate(object sender, ConsoleCancelEventArgs e)
47 {
48 Console.WriteLine("Asset server is shutting down...");
49 server.Shutdown();
50 Environment.Exit(0);
51 };
52
53 while (true)
54 Console.ReadLine();
55 }
56#else
57 ServiceBase[] servicesToRun = new ServiceBase[] { new AssetServer() };
58 ServiceBase.Run(servicesToRun);
59#endif
60 }
61 }
62}
diff --git a/OpenSim/Grid/NewAssetServer/Metadata.cs b/OpenSim/Grid/NewAssetServer/Metadata.cs
new file mode 100644
index 0000000..247a3e8
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Metadata.cs
@@ -0,0 +1,85 @@
1using System;
2using System.Collections.Generic;
3using System.Xml;
4using OpenMetaverse;
5using OpenMetaverse.StructuredData;
6
7namespace AssetServer
8{
9 public class Metadata
10 {
11 public UUID ID;
12 public string Name;
13 public string Description;
14 public DateTime CreationDate;
15 public string ContentType;
16 public byte[] SHA1;
17 public bool Temporary;
18 public Dictionary<string, Uri> Methods = new Dictionary<string, Uri>();
19 public OSDMap ExtraData;
20
21 public OSDMap SerializeToOSD()
22 {
23 OSDMap osdata = new OSDMap();
24
25 if (ID != UUID.Zero) osdata["id"] = OSD.FromUUID(ID);
26 osdata["name"] = OSD.FromString(Name);
27 osdata["description"] = OSD.FromString(Description);
28 osdata["creation_date"] = OSD.FromDate(CreationDate);
29 osdata["type"] = OSD.FromString(ContentType);
30 osdata["sha1"] = OSD.FromBinary(SHA1);
31 osdata["temporary"] = OSD.FromBoolean(Temporary);
32
33 OSDMap methods = new OSDMap(Methods.Count);
34 foreach (KeyValuePair<string, Uri> kvp in Methods)
35 methods.Add(kvp.Key, OSD.FromUri(kvp.Value));
36 osdata["methods"] = methods;
37
38 if (ExtraData != null) osdata["extra_data"] = ExtraData;
39
40 return osdata;
41 }
42
43 public byte[] SerializeToBytes()
44 {
45 LitJson.JsonData jsonData = OSDParser.SerializeJson(SerializeToOSD());
46 return System.Text.Encoding.UTF8.GetBytes(jsonData.ToJson());
47 }
48
49 public void Deserialize(byte[] data)
50 {
51 OSD osdata = OSDParser.DeserializeJson(System.Text.Encoding.UTF8.GetString(data));
52 Deserialize(osdata);
53 }
54
55 public void Deserialize(string data)
56 {
57 OSD osdata = OSDParser.DeserializeJson(data);
58 Deserialize(osdata);
59 }
60
61 public void Deserialize(OSD osdata)
62 {
63 if (osdata.Type == OSDType.Map)
64 {
65 OSDMap map = (OSDMap)osdata;
66 ID = map["id"].AsUUID();
67 Name = map["name"].AsString();
68 Description = map["description"].AsString();
69 CreationDate = map["creation_date"].AsDate();
70 ContentType = map["type"].AsString();
71 SHA1 = map["sha1"].AsBinary();
72 Temporary = map["temporary"].AsBoolean();
73
74 OSDMap methods = map["methods"] as OSDMap;
75 if (methods != null)
76 {
77 foreach (KeyValuePair<string, OSD> kvp in methods)
78 Methods.Add(kvp.Key, kvp.Value.AsUri());
79 }
80
81 ExtraData = map["extra_data"] as OSDMap;
82 }
83 }
84 }
85}
diff --git a/OpenSim/Grid/NewAssetServer/Plugins/OpenSim/OpenSimAssetStoragePlugin.cs b/OpenSim/Grid/NewAssetServer/Plugins/OpenSim/OpenSimAssetStoragePlugin.cs
new file mode 100644
index 0000000..dd05e5d
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Plugins/OpenSim/OpenSimAssetStoragePlugin.cs
@@ -0,0 +1,352 @@
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;
39using OpenSim.Framework;
40using AssetServer.Extensions;
41
42namespace AssetServer.Plugins
43{
44 public class OpenSimAssetStoragePlugin : IAssetStorageProvider
45 {
46 const string EXTENSION_NAME = "OpenSimAssetStorage"; // Used in metrics reporting
47
48 private AssetServer server;
49 private IAssetProviderPlugin m_assetProvider;
50
51 public OpenSimAssetStoragePlugin()
52 {
53 }
54
55 #region IAssetStorageProvider implementation
56
57 public BackendResponse TryFetchMetadata(UUID assetID, out Metadata metadata)
58 {
59 metadata = null;
60 BackendResponse ret;
61
62 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
63 {
64 IDataReader reader;
65
66 try
67 {
68 dbConnection.Open();
69
70 IDbCommand command = dbConnection.CreateCommand();
71 command.CommandText = String.Format("SELECT name,description,assetType,temporary FROM assets WHERE id='{0}'", assetID.ToString());
72 reader = command.ExecuteReader();
73
74 if (reader.Read())
75 {
76 metadata = new Metadata();
77 metadata.CreationDate = OpenMetaverse.Utils.Epoch;
78 metadata.SHA1 = null;
79 metadata.ID = assetID;
80 metadata.Name = reader.GetString(0);
81 metadata.Description = reader.GetString(1);
82 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2));
83 metadata.Temporary = reader.GetBoolean(3);
84
85 ret = BackendResponse.Success;
86 }
87 else
88 {
89 ret = BackendResponse.NotFound;
90 }
91 }
92 catch (MySqlException ex)
93 {
94 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
95 ret = BackendResponse.Failure;
96 }
97 }
98
99 server.MetricsProvider.LogAssetMetadataFetch(EXTENSION_NAME, ret, assetID, DateTime.Now);
100 return ret;
101 }
102
103 public BackendResponse TryFetchData(UUID assetID, out byte[] assetData)
104 {
105 assetData = null;
106 BackendResponse ret;
107
108 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
109 {
110 IDataReader reader;
111
112 try
113 {
114 dbConnection.Open();
115
116 IDbCommand command = dbConnection.CreateCommand();
117 command.CommandText = String.Format("SELECT data FROM assets WHERE id='{0}'", assetID.ToString());
118 reader = command.ExecuteReader();
119
120 if (reader.Read())
121 {
122 assetData = (byte[])reader.GetValue(0);
123 ret = BackendResponse.Success;
124 }
125 else
126 {
127 ret = BackendResponse.NotFound;
128 }
129 }
130 catch (MySqlException ex)
131 {
132 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
133 ret = BackendResponse.Failure;
134 }
135 }
136
137 server.MetricsProvider.LogAssetDataFetch(EXTENSION_NAME, ret, assetID, (assetData != null ? assetData.Length : 0), DateTime.Now);
138 return ret;
139 }
140
141 public BackendResponse TryFetchDataMetadata(UUID assetID, out Metadata metadata, out byte[] assetData)
142 {
143 metadata = null;
144 assetData = null;
145 BackendResponse ret;
146
147 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
148 {
149 IDataReader reader;
150
151 try
152 {
153 dbConnection.Open();
154
155 IDbCommand command = dbConnection.CreateCommand();
156 command.CommandText = String.Format("SELECT name,description,assetType,temporary,data FROM assets WHERE id='{0}'", assetID.ToString());
157 reader = command.ExecuteReader();
158
159 if (reader.Read())
160 {
161 metadata = new Metadata();
162 metadata.CreationDate = OpenMetaverse.Utils.Epoch;
163 metadata.SHA1 = null;
164 metadata.ID = assetID;
165 metadata.Name = reader.GetString(0);
166 metadata.Description = reader.GetString(1);
167 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2));
168 metadata.Temporary = reader.GetBoolean(3);
169
170 assetData = (byte[])reader.GetValue(4);
171
172 ret = BackendResponse.Success;
173 }
174 else
175 {
176 ret = BackendResponse.NotFound;
177 }
178 }
179 catch (MySqlException ex)
180 {
181 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
182 ret = BackendResponse.Failure;
183 }
184 }
185
186 server.MetricsProvider.LogAssetMetadataFetch(EXTENSION_NAME, ret, assetID, DateTime.Now);
187 server.MetricsProvider.LogAssetDataFetch(EXTENSION_NAME, ret, assetID, (assetData != null ? assetData.Length : 0), DateTime.Now);
188 return ret;
189 }
190
191 public BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData, out UUID assetID)
192 {
193 assetID = metadata.ID = UUID.Random();
194 return TryCreateAsset(metadata, assetData);
195 }
196
197 public BackendResponse TryCreateAsset(Metadata metadata, byte[] assetData)
198 {
199 BackendResponse ret;
200
201 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
202 {
203 try
204 {
205 dbConnection.Open();
206
207 MySqlCommand command = new MySqlCommand(
208 "REPLACE INTO assets (name,description,assetType,local,temporary,data,id) VALUES " +
209 "(?name,?description,?assetType,?local,?temporary,?data,?id)", dbConnection);
210
211 command.Parameters.AddWithValue("?name", metadata.Name);
212 command.Parameters.AddWithValue("?description", metadata.Description);
213 command.Parameters.AddWithValue("?assetType", Utils.ContentTypeToSLAssetType(metadata.ContentType));
214 command.Parameters.AddWithValue("?local", 0);
215 command.Parameters.AddWithValue("?temporary", metadata.Temporary);
216 command.Parameters.AddWithValue("?data", assetData);
217 command.Parameters.AddWithValue("?id", metadata.ID.ToString());
218
219 int rowsAffected = command.ExecuteNonQuery();
220 if (rowsAffected == 1)
221 {
222 ret = BackendResponse.Success;
223 }
224 else if (rowsAffected == 2)
225 {
226 Logger.Log.Info("Replaced asset " + metadata.ID.ToString());
227 ret = BackendResponse.Success;
228 }
229 else
230 {
231 Logger.Log.ErrorFormat("MySQL REPLACE query affected {0} rows", rowsAffected);
232 ret = BackendResponse.Failure;
233 }
234 }
235 catch (MySqlException ex)
236 {
237 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
238 ret = BackendResponse.Failure;
239 }
240 }
241
242 server.MetricsProvider.LogAssetCreate(EXTENSION_NAME, ret, metadata.ID, assetData.Length, DateTime.Now);
243 return ret;
244 }
245
246 public int ForEach(Action<Metadata> action, int start, int count)
247 {
248 int rowCount = 0;
249
250 using (MySqlConnection dbConnection = new MySqlConnection(DBConnString.GetConnectionString(server.ConfigFile)))
251 {
252 MySqlDataReader reader;
253
254 try
255 {
256 dbConnection.Open();
257
258 MySqlCommand command = dbConnection.CreateCommand();
259 command.CommandText = String.Format("SELECT name,description,assetType,temporary,data,id FROM assets LIMIT {0}, {1}",
260 start, count);
261 reader = command.ExecuteReader();
262 }
263 catch (MySqlException ex)
264 {
265 Logger.Log.Error("Connection to MySQL backend failed: " + ex.Message);
266 return 0;
267 }
268
269 while (reader.Read())
270 {
271 Metadata metadata = new Metadata();
272 metadata.CreationDate = OpenMetaverse.Utils.Epoch;
273 metadata.Description = reader.GetString(1);
274 metadata.ID = UUID.Parse(reader.GetString(5));
275 metadata.Name = reader.GetString(0);
276 metadata.SHA1 = OpenMetaverse.Utils.SHA1((byte[])reader.GetValue(4));
277 metadata.Temporary = reader.GetBoolean(3);
278 metadata.ContentType = Utils.SLAssetTypeToContentType(reader.GetInt32(2));
279
280 action(metadata);
281 ++rowCount;
282 }
283
284 reader.Close();
285 }
286
287 return rowCount;
288 }
289
290 #endregion IAssetStorageProvider implementation
291
292 #region IPlugin implementation
293
294 public void Initialise(AssetServer server)
295 {
296 this.server = server;
297
298 try
299 {
300 m_assetProvider = LoadDatabasePlugin("OpenSim.Data.MySQL.dll", server.ConfigFile.Configs["MySQL"].GetString("database_connect", null));
301 if (m_assetProvider == null)
302 {
303 Logger.Log.Error("[ASSET]: Failed to load a database plugin, server halting.");
304 Environment.Exit(-1);
305 }
306 else
307 Logger.Log.InfoFormat("[ASSET]: Loaded storage backend: {0}", Version);
308 }
309 catch (Exception e)
310 {
311 Logger.Log.WarnFormat("[ASSET]: Failure loading data plugin: {0}", e.ToString());
312 }
313 }
314
315 /// <summary>
316 /// <para>Initialises asset interface</para>
317 /// </summary>
318 public void Initialise()
319 {
320 Logger.Log.InfoFormat("[ASSET]: {0} cannot be default-initialized!", Name);
321 throw new PluginNotInitialisedException(Name);
322 }
323
324 public void Dispose()
325 {
326 }
327
328 public string Version
329 {
330 get { return m_assetProvider.Version; }
331 }
332
333 public string Name
334 {
335 get { return "AssetServer storage provider"; }
336 }
337
338 #endregion IPlugin implementation
339
340 private IAssetProviderPlugin LoadDatabasePlugin(string provider, string connect)
341 {
342 PluginLoader<IAssetProviderPlugin> loader = new PluginLoader<IAssetProviderPlugin>(new AssetDataInitialiser(connect));
343
344 // Loader will try to load all providers (MySQL, MSSQL, etc)
345 // unless it is constrainted to the correct "Provider" entry in the addin.xml
346 loader.Add("/OpenSim/AssetData", new PluginProviderFilter (provider));
347 loader.Load();
348
349 return loader.Plugin;
350 }
351 }
352}
diff --git a/OpenSim/Grid/NewAssetServer/Plugins/OpenSim/Resources/AssetServerOpenSimPlugins.addin.xml b/OpenSim/Grid/NewAssetServer/Plugins/OpenSim/Resources/AssetServerOpenSimPlugins.addin.xml
new file mode 100644
index 0000000..0e473ad
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Plugins/OpenSim/Resources/AssetServerOpenSimPlugins.addin.xml
@@ -0,0 +1,14 @@
1<Addin id="OpenSim.Grid.AssetServer.Plugins.OpenSim" version="0.1">
2 <Runtime>
3 <Import assembly="OpenSim.Grid.AssetServer.Plugins.OpenSim.dll"/>
4 </Runtime>
5 <Dependencies>
6 <Addin id="OpenSim.Grid.NewAssetServer" version="0.1" />
7 </Dependencies>
8 <ExtensionPoint path = "/OpenSim/AssetData">
9 <ExtensionNode name="Plugin" type="OpenSim.Framework.PluginExtensionNode" objectType="OpenSim.Framework.IAssetProviderPlugin"/>
10 </ExtensionPoint>
11 <Extension path="/OpenSim/AssetServer/StorageProvider">
12 <Plugin id="OpenSimAssetStorage" provider="OpenSim.Grid.AssetServer.Plugins.OpenSim.dll" type="AssetServer.Plugins.OpenSimAssetStoragePlugin" />
13 </Extension>
14</Addin>
diff --git a/OpenSim/Grid/NewAssetServer/Utils.cs b/OpenSim/Grid/NewAssetServer/Utils.cs
new file mode 100644
index 0000000..5499933
--- /dev/null
+++ b/OpenSim/Grid/NewAssetServer/Utils.cs
@@ -0,0 +1,1034 @@
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.Specialized;
32using System.Globalization;
33using System.Net;
34using System.Xml;
35using System.Xml.Serialization;
36using OpenMetaverse;
37using OpenMetaverse.StructuredData;
38using HttpServer;
39
40namespace AssetServer
41{
42 public static class Utils
43 {
44 public static UUID GetAuthToken(IHttpRequest request)
45 {
46 UUID authToken = UUID.Zero;
47
48 string[] authHeader = request.Headers.GetValues("Authorization");
49 if (authHeader != null && authHeader.Length == 1)
50 {
51 // Example header:
52 // Authorization: OpenGrid 65fda0b5-4446-42f5-b828-aaf644293646
53 string[] authHeaderParts = authHeader[0].Split(' ');
54 if (authHeaderParts.Length == 2 && authHeaderParts[0] == "OpenGrid")
55 UUID.TryParse(authHeaderParts[1], out authToken);
56 }
57
58 if (authToken == UUID.Zero && request.Cookies != null)
59 {
60 // Check for an authToken cookie to make logins browser-compatible
61 RequestCookie authCookie = request.Cookies["authToken"];
62 if (authCookie != null)
63 UUID.TryParse(authCookie.Value, out authToken);
64 }
65
66 return authToken;
67 }
68
69 public static Uri GetOpenSimUri(UUID avatarID)
70 {
71 return new Uri("http://opensim/" + avatarID.ToString());
72 }
73
74 public static bool TryGetOpenSimUUID(Uri avatarUri, out UUID avatarID)
75 {
76 string[] parts = avatarUri.Segments;
77 return UUID.TryParse(parts[parts.Length - 1], out avatarID);
78 }
79
80 #region SL / file extension / content-type conversions
81
82 public static string SLAssetTypeToContentType(int assetType)
83 {
84 switch (assetType)
85 {
86 case 0:
87 return "image/jp2";
88 case 1:
89 return "application/ogg";
90 case 2:
91 return "application/x-metaverse-callingcard";
92 case 3:
93 return "application/x-metaverse-landmark";
94 case 5:
95 return "application/x-metaverse-clothing";
96 case 6:
97 return "application/x-metaverse-primitive";
98 case 7:
99 return "application/x-metaverse-notecard";
100 case 8:
101 return "application/x-metaverse-folder";
102 case 10:
103 return "application/x-metaverse-lsl";
104 case 11:
105 return "application/x-metaverse-lso";
106 case 12:
107 return "image/tga";
108 case 13:
109 return "application/x-metaverse-bodypart";
110 case 17:
111 return "audio/x-wav";
112 case 19:
113 return "image/jpeg";
114 case 20:
115 return "application/x-metaverse-animation";
116 case 21:
117 return "application/x-metaverse-gesture";
118 case 22:
119 return "application/x-metaverse-simstate";
120 default:
121 return "application/octet-stream";
122 }
123 }
124
125 public static int ContentTypeToSLAssetType(string contentType)
126 {
127 switch (contentType)
128 {
129 case "image/jp2":
130 return 0;
131 case "application/ogg":
132 return 1;
133 case "application/x-metaverse-callingcard":
134 return 2;
135 case "application/x-metaverse-landmark":
136 return 3;
137 case "application/x-metaverse-clothing":
138 return 5;
139 case "application/x-metaverse-primitive":
140 return 6;
141 case "application/x-metaverse-notecard":
142 return 7;
143 case "application/x-metaverse-lsl":
144 return 10;
145 case "application/x-metaverse-lso":
146 return 11;
147 case "image/tga":
148 return 12;
149 case "application/x-metaverse-bodypart":
150 return 13;
151 case "audio/x-wav":
152 return 17;
153 case "image/jpeg":
154 return 19;
155 case "application/x-metaverse-animation":
156 return 20;
157 case "application/x-metaverse-gesture":
158 return 21;
159 case "application/x-metaverse-simstate":
160 return 22;
161 default:
162 return -1;
163 }
164 }
165
166 public static string ContentTypeToExtension(string contentType)
167 {
168 switch (contentType)
169 {
170 case "image/jp2":
171 return "texture";
172 case "application/ogg":
173 return "ogg";
174 case "application/x-metaverse-callingcard":
175 return "callingcard";
176 case "application/x-metaverse-landmark":
177 return "landmark";
178 case "application/x-metaverse-clothing":
179 return "clothing";
180 case "application/x-metaverse-primitive":
181 return "primitive";
182 case "application/x-metaverse-notecard":
183 return "notecard";
184 case "application/x-metaverse-lsl":
185 return "lsl";
186 case "application/x-metaverse-lso":
187 return "lso";
188 case "image/tga":
189 return "tga";
190 case "application/x-metaverse-bodypart":
191 return "bodypart";
192 case "audio/x-wav":
193 return "wav";
194 case "image/jpeg":
195 return "jpg";
196 case "application/x-metaverse-animation":
197 return "animation";
198 case "application/x-metaverse-gesture":
199 return "gesture";
200 case "application/x-metaverse-simstate":
201 return "simstate";
202 default:
203 return "bin";
204 }
205 }
206
207 public static string ExtensionToContentType(string extension)
208 {
209 switch (extension)
210 {
211 case "texture":
212 case "jp2":
213 case "j2c":
214 return "image/jp2";
215 case "sound":
216 case "ogg":
217 return "application/ogg";
218 case "callingcard":
219 return "application/x-metaverse-callingcard";
220 case "landmark":
221 return "application/x-metaverse-landmark";
222 case "clothing":
223 return "application/x-metaverse-clothing";
224 case "primitive":
225 return "application/x-metaverse-primitive";
226 case "notecard":
227 return "application/x-metaverse-notecard";
228 case "lsl":
229 return "application/x-metaverse-lsl";
230 case "lso":
231 return "application/x-metaverse-lso";
232 case "tga":
233 return "image/tga";
234 case "bodypart":
235 return "application/x-metaverse-bodypart";
236 case "wav":
237 return "audio/x-wav";
238 case "jpg":
239 case "jpeg":
240 return "image/jpeg";
241 case "animation":
242 return "application/x-metaverse-animation";
243 case "gesture":
244 return "application/x-metaverse-gesture";
245 case "simstate":
246 return "application/x-metaverse-simstate";
247 case "txt":
248 return "text/plain";
249 case "xml":
250 return "application/xml";
251 default:
252 return "application/octet-stream";
253 }
254 }
255
256 #endregion SL / file extension / content-type conversions
257
258 #region XML Serialization
259
260 public class GeneratedReader : XmlSerializationReader
261 {
262 public object ReadRoot_InventoryFolderBase()
263 {
264 Reader.MoveToContent();
265 if (Reader.LocalName != "InventoryFolderBase" || Reader.NamespaceURI != "")
266 throw CreateUnknownNodeException();
267 return ReadObject_InventoryFolder(true, true);
268 }
269
270 public object ReadRoot_InventoryItemBase()
271 {
272 Reader.MoveToContent();
273 if (Reader.LocalName != "InventoryItemBase" || Reader.NamespaceURI != "")
274 throw CreateUnknownNodeException();
275 return ReadObject_InventoryItem(true, true);
276 }
277
278 public object ReadRoot_InventoryCollection()
279 {
280 Reader.MoveToContent();
281 if (Reader.LocalName != "InventoryCollection" || Reader.NamespaceURI != "")
282 throw CreateUnknownNodeException();
283 return ReadObject_InventoryCollection(true, true);
284 }
285
286 public InventoryFolder ReadObject_InventoryFolder(bool isNullable, bool checkType)
287 {
288 InventoryFolder ob = null;
289 if (isNullable && ReadNull()) return null;
290
291 if (checkType)
292 {
293 System.Xml.XmlQualifiedName t = GetXsiType();
294 if (t == null)
295 { }
296 else if (t.Name != "InventoryFolderBase" || t.Namespace != "")
297 throw CreateUnknownTypeException(t);
298 }
299
300 ob = (InventoryFolder)Activator.CreateInstance(typeof(InventoryFolder), true);
301
302 Reader.MoveToElement();
303
304 while (Reader.MoveToNextAttribute())
305 {
306 if (IsXmlnsAttribute(Reader.Name))
307 {
308 }
309 else
310 {
311 UnknownNode(ob);
312 }
313 }
314
315 Reader.MoveToElement();
316 Reader.MoveToElement();
317 if (Reader.IsEmptyElement)
318 {
319 Reader.Skip();
320 return ob;
321 }
322
323 Reader.ReadStartElement();
324 Reader.MoveToContent();
325
326 bool b0 = false, b1 = false, b2 = false, b3 = false, b4 = false, b5 = false;
327
328 while (Reader.NodeType != System.Xml.XmlNodeType.EndElement)
329 {
330 if (Reader.NodeType == System.Xml.XmlNodeType.Element)
331 {
332 if (Reader.LocalName == "Owner" && Reader.NamespaceURI == "" && !b1)
333 {
334 b1 = true;
335 ob.@Owner = ReadObject_UUID(false, true);
336 }
337 else if (Reader.LocalName == "Version" && Reader.NamespaceURI == "" && !b5)
338 {
339 b5 = true;
340 string s6 = Reader.ReadElementString();
341 ob.@Version = UInt16.Parse(s6, CultureInfo.InvariantCulture);
342 }
343 else if (Reader.LocalName == "ID" && Reader.NamespaceURI == "" && !b3)
344 {
345 b3 = true;
346 ob.@ID = ReadObject_UUID(false, true);
347 }
348 else if (Reader.LocalName == "Type" && Reader.NamespaceURI == "" && !b4)
349 {
350 b4 = true;
351 string s7 = Reader.ReadElementString();
352 ob.@Type = Int16.Parse(s7, CultureInfo.InvariantCulture);
353 }
354 else if (Reader.LocalName == "Name" && Reader.NamespaceURI == "" && !b0)
355 {
356 b0 = true;
357 string s8 = Reader.ReadElementString();
358 ob.@Name = s8;
359 }
360 else if (Reader.LocalName == "ParentID" && Reader.NamespaceURI == "" && !b2)
361 {
362 b2 = true;
363 ob.@ParentID = ReadObject_UUID(false, true);
364 }
365 else
366 {
367 UnknownNode(ob);
368 }
369 }
370 else
371 UnknownNode(ob);
372
373 Reader.MoveToContent();
374 }
375
376 ReadEndElement();
377
378 return ob;
379 }
380
381 public InventoryItem ReadObject_InventoryItem(bool isNullable, bool checkType)
382 {
383 InventoryItem ob = null;
384 if (isNullable && ReadNull()) return null;
385
386 if (checkType)
387 {
388 System.Xml.XmlQualifiedName t = GetXsiType();
389 if (t == null)
390 { }
391 else if (t.Name != "InventoryItemBase" || t.Namespace != "")
392 throw CreateUnknownTypeException(t);
393 }
394
395 ob = (InventoryItem)Activator.CreateInstance(typeof(InventoryItem), true);
396
397 Reader.MoveToElement();
398
399 while (Reader.MoveToNextAttribute())
400 {
401 if (IsXmlnsAttribute(Reader.Name))
402 {
403 }
404 else
405 {
406 UnknownNode(ob);
407 }
408 }
409
410 Reader.MoveToElement();
411 Reader.MoveToElement();
412 if (Reader.IsEmptyElement)
413 {
414 Reader.Skip();
415 return ob;
416 }
417
418 Reader.ReadStartElement();
419 Reader.MoveToContent();
420
421 bool b9 = false, b10 = false, b11 = false, b12 = false, b13 = false, b14 = false, b15 = false, b16 = false, b17 = false, b18 = false, b19 = false, b20 = false, b21 = false, b22 = false, b23 = false, b24 = false, b25 = false, b26 = false, b27 = false, b28 = false;
422
423 while (Reader.NodeType != System.Xml.XmlNodeType.EndElement)
424 {
425 if (Reader.NodeType == System.Xml.XmlNodeType.Element)
426 {
427 if (Reader.LocalName == "GroupPermissions" && Reader.NamespaceURI == "" && !b20)
428 {
429 b20 = true;
430 string s29 = Reader.ReadElementString();
431 ob.@GroupPermissions = UInt32.Parse(s29, CultureInfo.InvariantCulture);
432 }
433 else if (Reader.LocalName == "AssetType" && Reader.NamespaceURI == "" && !b21)
434 {
435 b21 = true;
436 string s30 = Reader.ReadElementString();
437 ob.@AssetType = Int32.Parse(s30, CultureInfo.InvariantCulture);
438 }
439 else if (Reader.LocalName == "SalePrice" && Reader.NamespaceURI == "" && !b25)
440 {
441 b25 = true;
442 string s31 = Reader.ReadElementString();
443 ob.@SalePrice = Int32.Parse(s31, CultureInfo.InvariantCulture);
444 }
445 else if (Reader.LocalName == "AssetID" && Reader.NamespaceURI == "" && !b22)
446 {
447 b22 = true;
448 ob.@AssetID = ReadObject_UUID(false, true);
449 }
450 else if (Reader.LocalName == "Folder" && Reader.NamespaceURI == "" && !b11)
451 {
452 b11 = true;
453 ob.@Folder = ReadObject_UUID(false, true);
454 }
455 else if (Reader.LocalName == "Name" && Reader.NamespaceURI == "" && !b14)
456 {
457 b14 = true;
458 string s32 = Reader.ReadElementString();
459 ob.@Name = s32;
460 }
461 else if (Reader.LocalName == "NextPermissions" && Reader.NamespaceURI == "" && !b16)
462 {
463 b16 = true;
464 string s33 = Reader.ReadElementString();
465 ob.@NextPermissions = UInt32.Parse(s33, CultureInfo.InvariantCulture);
466 }
467 else if (Reader.LocalName == "BasePermissions" && Reader.NamespaceURI == "" && !b18)
468 {
469 b18 = true;
470 string s34 = Reader.ReadElementString();
471 ob.@BasePermissions = UInt32.Parse(s34, CultureInfo.InvariantCulture);
472 }
473 else if (Reader.LocalName == "ID" && Reader.NamespaceURI == "" && !b9)
474 {
475 b9 = true;
476 ob.@ID = ReadObject_UUID(false, true);
477 }
478 else if (Reader.LocalName == "Flags" && Reader.NamespaceURI == "" && !b27)
479 {
480 b27 = true;
481 string s35 = Reader.ReadElementString();
482 ob.@Flags = UInt32.Parse(s35, CultureInfo.InvariantCulture);
483 }
484 else if (Reader.LocalName == "GroupOwned" && Reader.NamespaceURI == "" && !b24)
485 {
486 b24 = true;
487 string s36 = Reader.ReadElementString();
488 ob.@GroupOwned = XmlConvert.ToBoolean(s36);
489 }
490 else if (Reader.LocalName == "InvType" && Reader.NamespaceURI == "" && !b10)
491 {
492 b10 = true;
493 string s37 = Reader.ReadElementString();
494 ob.@InvType = Int32.Parse(s37, CultureInfo.InvariantCulture);
495 }
496 else if (Reader.LocalName == "GroupID" && Reader.NamespaceURI == "" && !b23)
497 {
498 b23 = true;
499 ob.@GroupID = ReadObject_UUID(false, true);
500 }
501 else if (Reader.LocalName == "Description" && Reader.NamespaceURI == "" && !b15)
502 {
503 b15 = true;
504 string s38 = Reader.ReadElementString();
505 ob.@Description = s38;
506 }
507 else if (Reader.LocalName == "CreationDate" && Reader.NamespaceURI == "" && !b28)
508 {
509 b28 = true;
510 string s39 = Reader.ReadElementString();
511 ob.@CreationDate = Int32.Parse(s39, CultureInfo.InvariantCulture);
512 }
513 else if (Reader.LocalName == "EveryOnePermissions" && Reader.NamespaceURI == "" && !b19)
514 {
515 b19 = true;
516 string s40 = Reader.ReadElementString();
517 ob.@EveryOnePermissions = UInt32.Parse(s40, CultureInfo.InvariantCulture);
518 }
519 else if (Reader.LocalName == "Creator" && Reader.NamespaceURI == "" && !b13)
520 {
521 b13 = true;
522 ob.@Creator = ReadObject_UUID(false, true);
523 }
524 else if (Reader.LocalName == "Owner" && Reader.NamespaceURI == "" && !b12)
525 {
526 b12 = true;
527 ob.@Owner = ReadObject_UUID(false, true);
528 }
529 else if (Reader.LocalName == "SaleType" && Reader.NamespaceURI == "" && !b26)
530 {
531 b26 = true;
532 string s41 = Reader.ReadElementString();
533 ob.@SaleType = byte.Parse(s41, CultureInfo.InvariantCulture);
534 }
535 else if (Reader.LocalName == "CurrentPermissions" && Reader.NamespaceURI == "" && !b17)
536 {
537 b17 = true;
538 string s42 = Reader.ReadElementString();
539 ob.@CurrentPermissions = UInt32.Parse(s42, CultureInfo.InvariantCulture);
540 }
541 else
542 {
543 UnknownNode(ob);
544 }
545 }
546 else
547 UnknownNode(ob);
548
549 Reader.MoveToContent();
550 }
551
552 ReadEndElement();
553
554 return ob;
555 }
556
557 public InventoryCollection ReadObject_InventoryCollection(bool isNullable, bool checkType)
558 {
559 InventoryCollection ob = null;
560 if (isNullable && ReadNull()) return null;
561
562 if (checkType)
563 {
564 System.Xml.XmlQualifiedName t = GetXsiType();
565 if (t == null)
566 { }
567 else if (t.Name != "InventoryCollection" || t.Namespace != "")
568 throw CreateUnknownTypeException(t);
569 }
570
571 ob = (InventoryCollection)Activator.CreateInstance(typeof(InventoryCollection), true);
572
573 Reader.MoveToElement();
574
575 while (Reader.MoveToNextAttribute())
576 {
577 if (IsXmlnsAttribute(Reader.Name))
578 {
579 }
580 else
581 {
582 UnknownNode(ob);
583 }
584 }
585
586 Reader.MoveToElement();
587 Reader.MoveToElement();
588 if (Reader.IsEmptyElement)
589 {
590 Reader.Skip();
591 if (ob.@Folders == null)
592 {
593 ob.@Folders = new System.Collections.Generic.Dictionary<UUID, InventoryFolder>();
594 }
595 if (ob.@Items == null)
596 {
597 ob.@Items = new System.Collections.Generic.Dictionary<UUID, InventoryItem>();
598 }
599 return ob;
600 }
601
602 Reader.ReadStartElement();
603 Reader.MoveToContent();
604
605 bool b43 = false, b44 = false, b45 = false;
606
607 while (Reader.NodeType != System.Xml.XmlNodeType.EndElement)
608 {
609 if (Reader.NodeType == System.Xml.XmlNodeType.Element)
610 {
611 if (Reader.LocalName == "UserID" && Reader.NamespaceURI == "" && !b45)
612 {
613 b45 = true;
614 ob.@UserID = ReadObject_UUID(false, true);
615 }
616 else if (Reader.LocalName == "Items" && Reader.NamespaceURI == "" && !b44)
617 {
618 System.Collections.Generic.Dictionary<UUID, InventoryItem> o46 = ob.@Items;
619 if (((object)o46) == null)
620 {
621 o46 = new System.Collections.Generic.Dictionary<UUID, InventoryItem>();
622 ob.@Items = o46;
623 }
624 if (Reader.IsEmptyElement)
625 {
626 Reader.Skip();
627 }
628 else
629 {
630 int n47 = 0;
631 Reader.ReadStartElement();
632 Reader.MoveToContent();
633
634 while (Reader.NodeType != System.Xml.XmlNodeType.EndElement)
635 {
636 if (Reader.NodeType == System.Xml.XmlNodeType.Element)
637 {
638 if (Reader.LocalName == "InventoryItemBase" && Reader.NamespaceURI == "")
639 {
640 if (((object)o46) == null)
641 throw CreateReadOnlyCollectionException("System.Collections.Generic.List<InventoryItemBase>");
642 InventoryItem item = ReadObject_InventoryItem(true, true);
643 o46.Add(item.ID, item);
644 n47++;
645 }
646 else UnknownNode(null);
647 }
648 else UnknownNode(null);
649
650 Reader.MoveToContent();
651 }
652 ReadEndElement();
653 }
654 b44 = true;
655 }
656 else if (Reader.LocalName == "Folders" && Reader.NamespaceURI == "" && !b43)
657 {
658 System.Collections.Generic.Dictionary<UUID, InventoryFolder> o48 = ob.@Folders;
659 if (((object)o48) == null)
660 {
661 o48 = new System.Collections.Generic.Dictionary<UUID, InventoryFolder>();
662 ob.@Folders = o48;
663 }
664 if (Reader.IsEmptyElement)
665 {
666 Reader.Skip();
667 }
668 else
669 {
670 int n49 = 0;
671 Reader.ReadStartElement();
672 Reader.MoveToContent();
673
674 while (Reader.NodeType != System.Xml.XmlNodeType.EndElement)
675 {
676 if (Reader.NodeType == System.Xml.XmlNodeType.Element)
677 {
678 if (Reader.LocalName == "InventoryFolderBase" && Reader.NamespaceURI == "")
679 {
680 if (((object)o48) == null)
681 throw CreateReadOnlyCollectionException("System.Collections.Generic.List<InventoryFolderBase>");
682 InventoryFolder folder = ReadObject_InventoryFolder(true, true);
683 o48.Add(folder.ID, folder);
684 n49++;
685 }
686 else UnknownNode(null);
687 }
688 else UnknownNode(null);
689
690 Reader.MoveToContent();
691 }
692 ReadEndElement();
693 }
694 b43 = true;
695 }
696 else
697 {
698 UnknownNode(ob);
699 }
700 }
701 else
702 UnknownNode(ob);
703
704 Reader.MoveToContent();
705 }
706 if (ob.@Folders == null)
707 {
708 ob.@Folders = new System.Collections.Generic.Dictionary<UUID, InventoryFolder>();
709 }
710 if (ob.@Items == null)
711 {
712 ob.@Items = new System.Collections.Generic.Dictionary<UUID, InventoryItem>();
713 }
714
715 ReadEndElement();
716
717 return ob;
718 }
719
720 public OpenMetaverse.UUID ReadObject_UUID(bool isNullable, bool checkType)
721 {
722 OpenMetaverse.UUID ob = (OpenMetaverse.UUID)Activator.CreateInstance(typeof(OpenMetaverse.UUID), true);
723 System.Xml.XmlQualifiedName t = GetXsiType();
724 if (t == null)
725 { }
726 else if (t.Name != "UUID" || t.Namespace != "")
727 throw CreateUnknownTypeException(t);
728
729 Reader.MoveToElement();
730
731 while (Reader.MoveToNextAttribute())
732 {
733 if (IsXmlnsAttribute(Reader.Name))
734 {
735 }
736 else
737 {
738 UnknownNode(ob);
739 }
740 }
741
742 Reader.MoveToElement();
743 Reader.MoveToElement();
744 if (Reader.IsEmptyElement)
745 {
746 Reader.Skip();
747 return ob;
748 }
749
750 Reader.ReadStartElement();
751 Reader.MoveToContent();
752
753 bool b52 = false;
754
755 while (Reader.NodeType != System.Xml.XmlNodeType.EndElement)
756 {
757 if (Reader.NodeType == System.Xml.XmlNodeType.Element)
758 {
759 if (Reader.LocalName == "Guid" && Reader.NamespaceURI == "" && !b52)
760 {
761 b52 = true;
762 string s53 = Reader.ReadElementString();
763 ob.@Guid = XmlConvert.ToGuid(s53);
764 }
765 else
766 {
767 UnknownNode(ob);
768 }
769 }
770 else
771 UnknownNode(ob);
772
773 Reader.MoveToContent();
774 }
775
776 ReadEndElement();
777
778 return ob;
779 }
780
781 protected override void InitCallbacks()
782 {
783 }
784
785 protected override void InitIDs()
786 {
787 }
788 }
789
790 public class GeneratedWriter : XmlSerializationWriter
791 {
792 const string xmlNamespace = "http://www.w3.org/2000/xmlns/";
793 static readonly System.Reflection.MethodInfo toBinHexStringMethod = typeof(XmlConvert).GetMethod("ToBinHexString", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic, null, new Type[] { typeof(byte[]) }, null);
794 static string ToBinHexString(byte[] input)
795 {
796 return input == null ? null : (string)toBinHexStringMethod.Invoke(null, new object[] { input });
797 }
798 public void WriteRoot_InventoryFolder(object o)
799 {
800 WriteStartDocument();
801 InventoryFolder ob = (InventoryFolder)o;
802 TopLevelElement();
803 WriteObject_InventoryFolder(ob, "InventoryFolderBase", "", true, false, true);
804 }
805
806 public void WriteRoot_InventoryItem(object o)
807 {
808 WriteStartDocument();
809 InventoryItem ob = (InventoryItem)o;
810 TopLevelElement();
811 WriteObject_InventoryItem(ob, "InventoryItemBase", "", true, false, true);
812 }
813
814 public void WriteRoot_InventoryCollection(object o)
815 {
816 WriteStartDocument();
817 InventoryCollection ob = (InventoryCollection)o;
818 TopLevelElement();
819 WriteObject_InventoryCollection(ob, "InventoryCollection", "", true, false, true);
820 }
821
822 void WriteObject_InventoryFolder(InventoryFolder ob, string element, string namesp, bool isNullable, bool needType, bool writeWrappingElem)
823 {
824 if (((object)ob) == null)
825 {
826 if (isNullable)
827 WriteNullTagLiteral(element, namesp);
828 return;
829 }
830
831 System.Type type = ob.GetType();
832 if (type == typeof(InventoryFolder))
833 { }
834 else
835 {
836 throw CreateUnknownTypeException(ob);
837 }
838
839 if (writeWrappingElem)
840 {
841 WriteStartElement(element, namesp, ob);
842 }
843
844 if (needType) WriteXsiType("InventoryFolderBase", "");
845
846 WriteElementString("Name", "", ob.@Name);
847 WriteObject_UUID(ob.@Owner, "Owner", "", false, false, true);
848 WriteObject_UUID(ob.@ParentID, "ParentID", "", false, false, true);
849 WriteObject_UUID(ob.@ID, "ID", "", false, false, true);
850 WriteElementString("Type", "", ob.@Type.ToString(CultureInfo.InvariantCulture));
851 WriteElementString("Version", "", ob.@Version.ToString(CultureInfo.InvariantCulture));
852 if (writeWrappingElem) WriteEndElement(ob);
853 }
854
855 void WriteObject_InventoryItem(InventoryItem ob, string element, string namesp, bool isNullable, bool needType, bool writeWrappingElem)
856 {
857 if (((object)ob) == null)
858 {
859 if (isNullable)
860 WriteNullTagLiteral(element, namesp);
861 return;
862 }
863
864 System.Type type = ob.GetType();
865 if (type == typeof(InventoryItem))
866 { }
867 else
868 {
869 throw CreateUnknownTypeException(ob);
870 }
871
872 if (writeWrappingElem)
873 {
874 WriteStartElement(element, namesp, ob);
875 }
876
877 if (needType) WriteXsiType("InventoryItemBase", "");
878
879 WriteObject_UUID(ob.@ID, "ID", "", false, false, true);
880 WriteElementString("InvType", "", ob.@InvType.ToString(CultureInfo.InvariantCulture));
881 WriteObject_UUID(ob.@Folder, "Folder", "", false, false, true);
882 WriteObject_UUID(ob.@Owner, "Owner", "", false, false, true);
883 WriteObject_UUID(ob.@Creator, "Creator", "", false, false, true);
884 WriteElementString("Name", "", ob.@Name);
885 WriteElementString("Description", "", ob.@Description);
886 WriteElementString("NextPermissions", "", ob.@NextPermissions.ToString(CultureInfo.InvariantCulture));
887 WriteElementString("CurrentPermissions", "", ob.@CurrentPermissions.ToString(CultureInfo.InvariantCulture));
888 WriteElementString("BasePermissions", "", ob.@BasePermissions.ToString(CultureInfo.InvariantCulture));
889 WriteElementString("EveryOnePermissions", "", ob.@EveryOnePermissions.ToString(CultureInfo.InvariantCulture));
890 WriteElementString("GroupPermissions", "", ob.@GroupPermissions.ToString(CultureInfo.InvariantCulture));
891 WriteElementString("AssetType", "", ob.@AssetType.ToString(CultureInfo.InvariantCulture));
892 WriteObject_UUID(ob.@AssetID, "AssetID", "", false, false, true);
893 WriteObject_UUID(ob.@GroupID, "GroupID", "", false, false, true);
894 WriteElementString("GroupOwned", "", (ob.@GroupOwned ? "true" : "false"));
895 WriteElementString("SalePrice", "", ob.@SalePrice.ToString(CultureInfo.InvariantCulture));
896 WriteElementString("SaleType", "", ob.@SaleType.ToString(CultureInfo.InvariantCulture));
897 WriteElementString("Flags", "", ob.@Flags.ToString(CultureInfo.InvariantCulture));
898 WriteElementString("CreationDate", "", ob.@CreationDate.ToString(CultureInfo.InvariantCulture));
899 if (writeWrappingElem) WriteEndElement(ob);
900 }
901
902 void WriteObject_InventoryCollection(InventoryCollection ob, string element, string namesp, bool isNullable, bool needType, bool writeWrappingElem)
903 {
904 if (((object)ob) == null)
905 {
906 if (isNullable)
907 WriteNullTagLiteral(element, namesp);
908 return;
909 }
910
911 System.Type type = ob.GetType();
912 if (type == typeof(InventoryCollection))
913 { }
914 else
915 {
916 throw CreateUnknownTypeException(ob);
917 }
918
919 if (writeWrappingElem)
920 {
921 WriteStartElement(element, namesp, ob);
922 }
923
924 if (needType) WriteXsiType("InventoryCollection", "");
925
926 if (ob.@Folders != null)
927 {
928 WriteStartElement("Folders", "", ob.@Folders);
929 foreach (InventoryFolder folder in ob.Folders.Values)
930 {
931 WriteObject_InventoryFolder(folder, "InventoryFolderBase", "", true, false, true);
932 }
933 WriteEndElement(ob.@Folders);
934 }
935 if (ob.@Items != null)
936 {
937 WriteStartElement("Items", "", ob.@Items);
938 foreach (InventoryItem item in ob.Items.Values)
939 {
940 WriteObject_InventoryItem(item, "InventoryItemBase", "", true, false, true);
941 }
942 WriteEndElement(ob.@Items);
943 }
944 WriteObject_UUID(ob.@UserID, "UserID", "", false, false, true);
945 if (writeWrappingElem) WriteEndElement(ob);
946 }
947
948 void WriteObject_UUID(OpenMetaverse.UUID ob, string element, string namesp, bool isNullable, bool needType, bool writeWrappingElem)
949 {
950 System.Type type = ob.GetType();
951 if (type == typeof(OpenMetaverse.UUID))
952 { }
953 else
954 {
955 throw CreateUnknownTypeException(ob);
956 }
957
958 if (writeWrappingElem)
959 {
960 WriteStartElement(element, namesp, ob);
961 }
962
963 if (needType) WriteXsiType("UUID", "");
964
965 WriteElementString("Guid", "", XmlConvert.ToString(ob.@Guid));
966 if (writeWrappingElem) WriteEndElement(ob);
967 }
968
969 protected override void InitCallbacks()
970 {
971 }
972
973 }
974
975 public class BaseXmlSerializer : System.Xml.Serialization.XmlSerializer
976 {
977 protected override System.Xml.Serialization.XmlSerializationReader CreateReader()
978 {
979 return new GeneratedReader();
980 }
981
982 protected override System.Xml.Serialization.XmlSerializationWriter CreateWriter()
983 {
984 return new GeneratedWriter();
985 }
986
987 public override bool CanDeserialize(System.Xml.XmlReader xmlReader)
988 {
989 return true;
990 }
991 }
992
993 public sealed class InventoryFolderSerializer : BaseXmlSerializer
994 {
995 protected override void Serialize(object obj, System.Xml.Serialization.XmlSerializationWriter writer)
996 {
997 ((GeneratedWriter)writer).WriteRoot_InventoryFolder(obj);
998 }
999
1000 protected override object Deserialize(System.Xml.Serialization.XmlSerializationReader reader)
1001 {
1002 return ((GeneratedReader)reader).ReadRoot_InventoryFolderBase();
1003 }
1004 }
1005
1006 public sealed class InventoryItemSerializer : BaseXmlSerializer
1007 {
1008 protected override void Serialize(object obj, System.Xml.Serialization.XmlSerializationWriter writer)
1009 {
1010 ((GeneratedWriter)writer).WriteRoot_InventoryItem(obj);
1011 }
1012
1013 protected override object Deserialize(System.Xml.Serialization.XmlSerializationReader reader)
1014 {
1015 return ((GeneratedReader)reader).ReadRoot_InventoryItemBase();
1016 }
1017 }
1018
1019 public sealed class InventoryCollectionSerializer : BaseXmlSerializer
1020 {
1021 protected override void Serialize(object obj, System.Xml.Serialization.XmlSerializationWriter writer)
1022 {
1023 ((GeneratedWriter)writer).WriteRoot_InventoryCollection(obj);
1024 }
1025
1026 protected override object Deserialize(System.Xml.Serialization.XmlSerializationReader reader)
1027 {
1028 return ((GeneratedReader)reader).ReadRoot_InventoryCollection();
1029 }
1030 }
1031
1032 #endregion XML Serialization
1033 }
1034}
diff --git a/bin/AssetServer.ini.example b/bin/AssetServer.ini.example
new file mode 100644
index 0000000..f346624
--- /dev/null
+++ b/bin/AssetServer.ini.example
@@ -0,0 +1,153 @@
1[Config]
2
3; The port number for the asset server to listen on. If a valid SSL certificate
4; file is given for SSLCertFile, the HTTPS protocol will be used. Otherwise, the
5; HTTP protocol is used.
6ListenPort = 8003
7
8; An SSL certificate file for the server. If a valid raw certificate or PKCS#12
9; file is given the server will run in HTTPS mode.
10;SSLCertFile = server.p12
11
12[Extensions]
13
14;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
15; Storage Providers
16;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
17
18; Simple storage is a very basic storage system for the purposes of illustrating
19; a storage backend example. The assets are stored in SimpleAssets/ and
20; TempAssets/ (which is deleted when the server shuts down). Metadata is
21; generated for all of the files at startup and when new assets are uploaded.
22;SimpleStorage
23
24; OpenSimMySQL storage connects to a MySQL server that has an assets table created
25; by OpenSim. Open the AssetServer_Config.xml file from OpenSim and use the
26; database connection string for the database_connect option in the MySQL section
27; below. This backend combined with the OpenSimFrontend will allow the asset
28; server to be used as a drop-in replacement for OpenSim.Grid.AssetServer.exe,
29; while also allowing other frontends to run.
30OpenSimMySQLStorage
31
32; Uses Amazon.com's Simple Storage Service (http://aws.amazon.com/s3/) to store
33; asset data and metadata. This backend does not handle any data requests, as the
34; data is stored remotely and metadata replies will contain the amazon.com URL
35; holding the actual asset data. Your Access Key ID and Secret Access Key must be
36; set in the [Amazon] section below for this backend to function. If
37; UseCloudFront is true and your Amazon account has CloudFront enabled,
38; CloudFront URLs will be returned in metadata instead of normal S3 URLs.
39;AmazonS3Storage
40
41; Uses memcached (http://www.danga.com/memcached/) as a caching layer on top of
42; another storage backend. If you use this, make sure you enable another storage
43; provider as the actual backend, and that the MemcacheStorage line appears in
44; this config file after the other storage provider.
45;MemcachedStorage
46
47;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
48; Inventory Providers
49;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
50
51; Simple inventory is a very basic inventory storage system for the purposes of
52; illustrating an inventory backend example. The inventory is stored in
53; SimpleInventory/ by creating a folder for each agent that contains all of the
54; inventory items and folders serialized as XML files.
55;SimpleInventory
56
57; OpenSimMySQL inventory connects to a MySQL server that has an inventory table
58; created by OpenSim. If the OpenSimMySQLStorage backend is also being used, the
59; inventory and asset tables must be stored in the same database. The
60; database_connect string in the MySQL section below is used to connect to the
61; database. This backend combined with the OpenSimInventoryFrontend will allow
62; the server to be used as a drop-in replacement for
63; OpenSim.Grid.InventoryServer.exe, while also allowing other frontends to run.
64OpenSimMySQLInventory
65
66;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
67; Authentication Providers
68;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
69
70; OpenID provides a direct method of authenticating with the asset server. Users
71; can provide credentials and receive a session token directly from the asset
72; server. The OpenIdAuth module provides a browser-based form login and an
73; XML-based API, both accessible through the URL /authenticate.
74;OpenIdAuth
75NullAuthentication
76
77;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
78; Authorization Providers
79;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
80
81; Authorize all is a dummy authorization module that allows all requests for
82; metadata, data, and asset creation. Use this extension if your primary
83; storage provider or front-end interface does not support authentication.
84AuthorizeAll
85
86;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
87; Metrics Providers
88;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
89
90; NullMetrics contains empty logging functions. Use this metrics provider if
91; you want to disable metrics collection and reporting.
92NullMetrics
93
94;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
95; Frontends
96;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
97
98; A simple frontend that provides three basic REST methods. /assetid/metadata
99; will return the metadata for an asset (currently in LLSD format, that will
100; change soon). /assetid/data will return the raw asset data with proper
101; Content-Type and Content-Disposition headers to make downloading assets in a
102; web browser easy.
103ReferenceFrontend
104
105; A frontend that matches the existing OpenSim XML for transferring grid
106; assets. This will allow the asset server to function as a drop-in replacement
107; for OpenSim.Grid.AssetServer.exe, and can be combined with OpenSimMySQLStorage
108; to provide an identical replacement or any other storage backend.
109OpenSimFrontend
110
111; A frontend that matches the existing OpenSim XML for handling inventory
112; transactions. This will allow the asset server to function as a drop-in
113; replacement for OpenSim.Grid.InventoryServer.exe, and can be combined with
114; OpenSimMySQLInventory to provide an identical replacement or any other
115; inventory backend.
116OpenSimInventoryFrontend
117
118; An HTML interface for browsing through the asset store
119BrowseFrontend
120
121[MySQL]
122
123; Database connection string used by the OpenSim MySQL backend. If this line is
124; commented out or missing, the server will look for an AssetServer_Config.xml
125; in the current working directory. This file is generated by
126; OpenSim.Grid.AssetServer.exe and can be used without modification.
127database_connect = "Server=localhost; Database=opensim; User=changeme; Password=changeme;"
128
129[Amazon]
130
131; Get these values by logging in to your Amazon S3 account and going to
132; https://aws-portal.amazon.com/gp/aws/developer/account/index.html?ie=UTF8&action=access-key
133AccessKeyID = xxxxxxxxxxxxxxxxxxxx
134SecretAccessKey = xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
135
136; The bucket, or namespace, in your Amazon S3 account for storing assets in.
137; Bucket names on S3 are global identifiers, and must be unique. Think up
138; something clever or random.
139BucketName = changeme
140
141; Amazon CloudFront is a Content Distribution Network for S3 stores. If this is
142; set to true, AmazonS3Storage will try to locate the first available CloudFront
143; distribution tied to the active S3 bucket. If no usable distribution is found,
144; a new one will be created.
145UseCloudFront = true
146
147[Memcached]
148
149; A comma-separated list of the memcached servers that make up your caching
150; pool. Each server is a hostname or IP address, optionally followed by a
151; colon and port number if the server is not listening on the default 11211
152; port.
153Servers = localhost
diff --git a/bin/OpenSim.Grid.NewAssetServer.addin.xml b/bin/OpenSim.Grid.NewAssetServer.addin.xml
new file mode 100644
index 0000000..8d8a863
--- /dev/null
+++ b/bin/OpenSim.Grid.NewAssetServer.addin.xml
@@ -0,0 +1,21 @@
1<Addin id="OpenSim.Grid.NewAssetServer" isroot="true" version="0.1">
2 <Runtime>
3 <Import assembly="OpenSim.Grid.NewAssetServer.exe"/>
4 <Import assembly="OpenSim.Framework.dll"/>
5 </Runtime>
6 <ExtensionPoint path="/OpenSim/AssetServer/StorageProvider">
7 <ExtensionNode name="Plugin" type="OpenSim.Framework.PluginExtensionNode" objectType="AssetServer.IAssetStorageProvider"/>
8 </ExtensionPoint>
9 <ExtensionPoint path="/OpenSim/AssetServer/InventoryProvider">
10 <ExtensionNode name="Plugin" type="OpenSim.Framework.PluginExtensionNode" objectType="AssetServer.IInventoryProvider"/>
11 </ExtensionPoint>
12 <ExtensionPoint path="/OpenSim/AssetServer/AuthenticationProvider">
13 <ExtensionNode name="Plugin" type="OpenSim.Framework.PluginExtensionNode" objectType="AssetServer.IAuthenticationProvider"/>
14 </ExtensionPoint>
15 <ExtensionPoint path="/OpenSim/AssetServer/AuthorizationProvider">
16 <ExtensionNode name="Plugin" type="OpenSim.Framework.PluginExtensionNode" objectType="AssetServer.IAuthorizationProvider"/>
17 </ExtensionPoint>
18 <ExtensionPoint path="/OpenSim/AssetServer/MetricsProvider">
19 <ExtensionNode name="Plugin" type="OpenSim.Framework.PluginExtensionNode" objectType="AssetServer.IMetricsProvider"/>
20 </ExtensionPoint>
21</Addin>