Merge branch 'master' into newmultiattach

Conflicts:
	OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.cs
user_profiles
Melanie 2013-03-18 23:31:27 +00:00
commit 5e1f651e21
88 changed files with 2112 additions and 9616 deletions

View File

@ -155,6 +155,7 @@ what it is today.
* tglion
* tlaukkan/Tommil (Tommi S. E. Laukkanen, Bubble Cloud)
* tyre
* Vegaslon <vegaslon@gmail.com>
* VikingErik
* Vytek
* webmage (IBM)

View File

@ -1,43 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
namespace OpenSim.ApplicationPlugins.Rest.Inventory
{
/// <summary>
/// This interface represents the boundary between the general purpose
/// REST plugin handling, and the functionally specific handlers. The
/// handler knows only to initialize and terminate all such handlers
/// that it finds. Implementing this interface identifies the class as
/// a REST handler implementation.
/// </summary>
internal interface IRest
{
void Initialize();
void Close();
}
}

View File

@ -1,59 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using OpenSim.Framework.Servers.HttpServer;
namespace OpenSim.ApplicationPlugins.Rest.Inventory
{
/// <remarks>
/// The handler delegates are not noteworthy. The allocator allows
/// a given handler to optionally subclass the base RequestData
/// structure to carry any locally required per-request state
/// needed.
/// </remarks>
public delegate void RestMethodHandler(RequestData rdata);
public delegate RequestData RestMethodAllocator(OSHttpRequest request, OSHttpResponse response, string path);
/// <summary>
/// This interface exports the generic plugin-handling services
/// available to each loaded REST services module (IRest implementation)
/// </summary>
internal interface IRestHandler
{
string MsgId { get; }
string RequestId { get; }
void AddPathHandler(RestMethodHandler mh, string path, RestMethodAllocator ma);
void AddStreamHandler(string httpMethod, string path, RestMethod method);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,11 +0,0 @@
<Addin id="OpenSim.ApplicationPlugins.Rest.Inventory" version="0.1">
<Runtime>
<Import assembly="OpenSim.ApplicationPlugins.Rest.Inventory.dll"/>
</Runtime>
<Dependencies>
<Addin id="OpenSim" version="0.5" />
</Dependencies>
<Extension path = "/OpenSim/Startup">
<Plugin id="RestInventory" type="OpenSim.ApplicationPlugins.Rest.Inventory.RestHandler" />
</Extension>
</Addin>

View File

@ -1,551 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
using log4net;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Framework.Communications;
using OpenSim.Services.Interfaces;
using IAvatarService = OpenSim.Services.Interfaces.IAvatarService;
namespace OpenSim.ApplicationPlugins.Rest.Inventory
{
public class Rest
{
internal static readonly ILog Log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
internal static bool DEBUG = Log.IsDebugEnabled;
/// <summary>
/// Supported authentication schemes
/// </summary>
public const string AS_BASIC = "Basic"; // simple user/password verification
public const string AS_DIGEST = "Digest"; // password safe authentication
/// Supported Digest algorithms
public const string Digest_MD5 = "MD5"; // assumed default if omitted
public const string Digest_MD5Sess = "MD5-sess"; // session-span - not good for REST?
public const string Qop_Auth = "auth"; // authentication only
public const string Qop_Int = "auth-int"; // TODO
/// <summary>
/// These values have a single value for the whole
/// domain and lifetime of the plugin handler. We
/// make them static for ease of reference within
/// the assembly. These are initialized by the
/// RestHandler class during start-up.
/// </summary>
internal static IRestHandler Plugin = null;
internal static OpenSimBase main = null;
internal static string Prefix = null;
internal static IConfig Config = null;
internal static string GodKey = null;
internal static bool Authenticate = true;
internal static bool Secure = true;
internal static bool ExtendedEscape = true;
internal static bool DumpAsset = false;
internal static bool Fill = true;
internal static bool FlushEnabled = true;
internal static string Realm = "OpenSim REST";
internal static string Scheme = AS_BASIC;
internal static int DumpLineSize = 32; // Should be a multiple of 16 or (possibly) 4
/// <summary>
/// These are all dependent upon the Comms manager
/// being initialized. So they have to be properties
/// because the comms manager is now a module and is
/// not guaranteed to be there when the rest handler
/// initializes.
/// </summary>
internal static IInventoryService InventoryServices
{
get { return main.SceneManager.CurrentOrFirstScene.InventoryService; }
}
internal static IUserAccountService UserServices
{
get { return main.SceneManager.CurrentOrFirstScene.UserAccountService; }
}
internal static IAuthenticationService AuthServices
{
get { return main.SceneManager.CurrentOrFirstScene.AuthenticationService; }
}
internal static IAvatarService AvatarServices
{
get { return main.SceneManager.CurrentOrFirstScene.AvatarService; }
}
internal static IAssetService AssetServices
{
get { return main.SceneManager.CurrentOrFirstScene.AssetService; }
}
/// <summary>
/// HTTP requires that status information be generated for PUT
/// and POST opertaions. This is in support of that. The
/// operation verb gets substituted into the first string,
/// and the completion code is inserted into the tail. The
/// strings are put here to encourage consistency.
/// </summary>
internal static string statusHead = "<html><body><title>{0} status</title><break>";
internal static string statusTail = "</body></html>";
internal static Dictionary<int,string> HttpStatusDesc;
static Rest()
{
HttpStatusDesc = new Dictionary<int,string>();
if (HttpStatusCodeArray.Length != HttpStatusDescArray.Length)
{
Log.ErrorFormat("{0} HTTP Status Code and Description arrays do not match");
throw new Exception("HTTP Status array discrepancy");
}
// Repackage the data into something more tractable. The sparse
// nature of HTTP return codes makes an array a bad choice.
for (int i=0; i<HttpStatusCodeArray.Length; i++)
{
HttpStatusDesc.Add(HttpStatusCodeArray[i], HttpStatusDescArray[i]);
}
}
internal static int CreationDate
{
get { return (int) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; }
}
internal static string MsgId
{
get { return Plugin.MsgId; }
}
internal static string RequestId
{
get { return Plugin.RequestId; }
}
internal static Encoding Encoding = Util.UTF8;
/// <summary>
/// Version control for REST implementation. This
/// refers to the overall infrastructure represented
/// by the following classes
/// RequestData
/// RequestInventoryPlugin
/// Rest
/// It does no describe implementation classes such as
/// RestInventoryServices, which may morph much more
/// often. Such classes ARE dependent upon this however
/// and should check it in their Initialize method.
/// </summary>
public static readonly float Version = 1.0F;
public const string Name = "REST 1.0";
/// <summary>
/// Currently defined HTTP methods.
/// Only GET and HEAD are required to be
/// supported by all servers. See Respond
/// to see how these are handled.
/// </summary>
// REST AGENT 1.0 interpretations
public const string GET = "get"; // information retrieval - server state unchanged
public const string HEAD = "head"; // same as get except only the headers are returned.
public const string POST = "post"; // Replace the URI designated resource with the entity.
public const string PUT = "put"; // Add the entity to the context represented by the URI
public const string DELETE = "delete"; // Remove the URI designated resource from the server.
public const string OPTIONS = "options"; //
public const string TRACE = "trace"; //
public const string CONNECT = "connect"; //
// Define this in one place...
public const string UrlPathSeparator = "/";
public const string UrlMethodSeparator = ":";
// Redirection qualifications
public const bool PERMANENT = false;
public const bool TEMPORARY = true;
// Constant arrays used by String.Split
public static readonly char C_SPACE = ' ';
public static readonly char C_SLASH = '/';
public static readonly char C_PATHSEP = '/';
public static readonly char C_COLON = ':';
public static readonly char C_PLUS = '+';
public static readonly char C_PERIOD = '.';
public static readonly char C_COMMA = ',';
public static readonly char C_DQUOTE = '"';
public static readonly string CS_SPACE = " ";
public static readonly string CS_SLASH = "/";
public static readonly string CS_PATHSEP = "/";
public static readonly string CS_COLON = ":";
public static readonly string CS_PLUS = "+";
public static readonly string CS_PERIOD = ".";
public static readonly string CS_COMMA = ",";
public static readonly string CS_DQUOTE = "\"";
public static readonly char[] CA_SPACE = { C_SPACE };
public static readonly char[] CA_SLASH = { C_SLASH };
public static readonly char[] CA_PATHSEP = { C_PATHSEP };
public static readonly char[] CA_COLON = { C_COLON };
public static readonly char[] CA_PERIOD = { C_PERIOD };
public static readonly char[] CA_PLUS = { C_PLUS };
public static readonly char[] CA_COMMA = { C_COMMA };
public static readonly char[] CA_DQUOTE = { C_DQUOTE };
// HTTP Code Values (in value order)
public const int HttpStatusCodeContinue = 100;
public const int HttpStatusCodeSwitchingProtocols = 101;
public const int HttpStatusCodeOK = 200;
public const int HttpStatusCodeCreated = 201;
public const int HttpStatusCodeAccepted = 202;
public const int HttpStatusCodeNonAuthoritative = 203;
public const int HttpStatusCodeNoContent = 204;
public const int HttpStatusCodeResetContent = 205;
public const int HttpStatusCodePartialContent = 206;
public const int HttpStatusCodeMultipleChoices = 300;
public const int HttpStatusCodePermanentRedirect = 301;
public const int HttpStatusCodeFound = 302;
public const int HttpStatusCodeSeeOther = 303;
public const int HttpStatusCodeNotModified = 304;
public const int HttpStatusCodeUseProxy = 305;
public const int HttpStatusCodeReserved306 = 306;
public const int HttpStatusCodeTemporaryRedirect = 307;
public const int HttpStatusCodeBadRequest = 400;
public const int HttpStatusCodeNotAuthorized = 401;
public const int HttpStatusCodePaymentRequired = 402;
public const int HttpStatusCodeForbidden = 403;
public const int HttpStatusCodeNotFound = 404;
public const int HttpStatusCodeMethodNotAllowed = 405;
public const int HttpStatusCodeNotAcceptable = 406;
public const int HttpStatusCodeProxyAuthenticate = 407;
public const int HttpStatusCodeTimeOut = 408;
public const int HttpStatusCodeConflict = 409;
public const int HttpStatusCodeGone = 410;
public const int HttpStatusCodeLengthRequired = 411;
public const int HttpStatusCodePreconditionFailed = 412;
public const int HttpStatusCodeEntityTooLarge = 413;
public const int HttpStatusCodeUriTooLarge = 414;
public const int HttpStatusCodeUnsupportedMedia = 415;
public const int HttpStatusCodeRangeNotSatsified = 416;
public const int HttpStatusCodeExpectationFailed = 417;
public const int HttpStatusCodeServerError = 500;
public const int HttpStatusCodeNotImplemented = 501;
public const int HttpStatusCodeBadGateway = 502;
public const int HttpStatusCodeServiceUnavailable = 503;
public const int HttpStatusCodeGatewayTimeout = 504;
public const int HttpStatusCodeHttpVersionError = 505;
public static readonly int[] HttpStatusCodeArray = {
HttpStatusCodeContinue,
HttpStatusCodeSwitchingProtocols,
HttpStatusCodeOK,
HttpStatusCodeCreated,
HttpStatusCodeAccepted,
HttpStatusCodeNonAuthoritative,
HttpStatusCodeNoContent,
HttpStatusCodeResetContent,
HttpStatusCodePartialContent,
HttpStatusCodeMultipleChoices,
HttpStatusCodePermanentRedirect,
HttpStatusCodeFound,
HttpStatusCodeSeeOther,
HttpStatusCodeNotModified,
HttpStatusCodeUseProxy,
HttpStatusCodeReserved306,
HttpStatusCodeTemporaryRedirect,
HttpStatusCodeBadRequest,
HttpStatusCodeNotAuthorized,
HttpStatusCodePaymentRequired,
HttpStatusCodeForbidden,
HttpStatusCodeNotFound,
HttpStatusCodeMethodNotAllowed,
HttpStatusCodeNotAcceptable,
HttpStatusCodeProxyAuthenticate,
HttpStatusCodeTimeOut,
HttpStatusCodeConflict,
HttpStatusCodeGone,
HttpStatusCodeLengthRequired,
HttpStatusCodePreconditionFailed,
HttpStatusCodeEntityTooLarge,
HttpStatusCodeUriTooLarge,
HttpStatusCodeUnsupportedMedia,
HttpStatusCodeRangeNotSatsified,
HttpStatusCodeExpectationFailed,
HttpStatusCodeServerError,
HttpStatusCodeNotImplemented,
HttpStatusCodeBadGateway,
HttpStatusCodeServiceUnavailable,
HttpStatusCodeGatewayTimeout,
HttpStatusCodeHttpVersionError
};
// HTTP Status Descriptions (in status code order)
// This array must be kept strictly consistent with respect
// to the status code array above.
public static readonly string[] HttpStatusDescArray = {
"Continue Request",
"Switching Protocols",
"OK",
"CREATED",
"ACCEPTED",
"NON-AUTHORITATIVE INFORMATION",
"NO CONTENT",
"RESET CONTENT",
"PARTIAL CONTENT",
"MULTIPLE CHOICES",
"PERMANENT REDIRECT",
"FOUND",
"SEE OTHER",
"NOT MODIFIED",
"USE PROXY",
"RESERVED CODE 306",
"TEMPORARY REDIRECT",
"BAD REQUEST",
"NOT AUTHORIZED",
"PAYMENT REQUIRED",
"FORBIDDEN",
"NOT FOUND",
"METHOD NOT ALLOWED",
"NOT ACCEPTABLE",
"PROXY AUTHENTICATION REQUIRED",
"TIMEOUT",
"CONFLICT",
"GONE",
"LENGTH REQUIRED",
"PRECONDITION FAILED",
"ENTITY TOO LARGE",
"URI TOO LARGE",
"UNSUPPORTED MEDIA",
"RANGE NOT SATISFIED",
"EXPECTATION FAILED",
"SERVER ERROR",
"NOT IMPLEMENTED",
"BAD GATEWAY",
"SERVICE UNAVAILABLE",
"GATEWAY TIMEOUT",
"HTTP VERSION NOT SUPPORTED"
};
// HTTP Headers
public const string HttpHeaderAccept = "Accept";
public const string HttpHeaderAcceptCharset = "Accept-Charset";
public const string HttpHeaderAcceptEncoding = "Accept-Encoding";
public const string HttpHeaderAcceptLanguage = "Accept-Language";
public const string HttpHeaderAcceptRanges = "Accept-Ranges";
public const string HttpHeaderAge = "Age";
public const string HttpHeaderAllow = "Allow";
public const string HttpHeaderAuthorization = "Authorization";
public const string HttpHeaderCacheControl = "Cache-Control";
public const string HttpHeaderConnection = "Connection";
public const string HttpHeaderContentEncoding = "Content-Encoding";
public const string HttpHeaderContentLanguage = "Content-Language";
public const string HttpHeaderContentLength = "Content-Length";
public const string HttpHeaderContentLocation = "Content-Location";
public const string HttpHeaderContentMD5 = "Content-MD5";
public const string HttpHeaderContentRange = "Content-Range";
public const string HttpHeaderContentType = "Content-Type";
public const string HttpHeaderDate = "Date";
public const string HttpHeaderETag = "ETag";
public const string HttpHeaderExpect = "Expect";
public const string HttpHeaderExpires = "Expires";
public const string HttpHeaderFrom = "From";
public const string HttpHeaderHost = "Host";
public const string HttpHeaderIfMatch = "If-Match";
public const string HttpHeaderIfModifiedSince = "If-Modified-Since";
public const string HttpHeaderIfNoneMatch = "If-None-Match";
public const string HttpHeaderIfRange = "If-Range";
public const string HttpHeaderIfUnmodifiedSince = "If-Unmodified-Since";
public const string HttpHeaderLastModified = "Last-Modified";
public const string HttpHeaderLocation = "Location";
public const string HttpHeaderMaxForwards = "Max-Forwards";
public const string HttpHeaderPragma = "Pragma";
public const string HttpHeaderProxyAuthenticate = "Proxy-Authenticate";
public const string HttpHeaderProxyAuthorization = "Proxy-Authorization";
public const string HttpHeaderRange = "Range";
public const string HttpHeaderReferer = "Referer";
public const string HttpHeaderRetryAfter = "Retry-After";
public const string HttpHeaderServer = "Server";
public const string HttpHeaderTE = "TE";
public const string HttpHeaderTrailer = "Trailer";
public const string HttpHeaderTransferEncoding = "Transfer-Encoding";
public const string HttpHeaderUpgrade = "Upgrade";
public const string HttpHeaderUserAgent = "User-Agent";
public const string HttpHeaderVary = "Vary";
public const string HttpHeaderVia = "Via";
public const string HttpHeaderWarning = "Warning";
public const string HttpHeaderWWWAuthenticate = "WWW-Authenticate";
/// Utility routines
public static string StringToBase64(string str)
{
try
{
byte[] encData_byte = new byte[str.Length];
encData_byte = Util.UTF8.GetBytes(str);
return Convert.ToBase64String(encData_byte);
}
catch
{
return String.Empty;
}
}
public static string Base64ToString(string str)
{
try
{
return Util.Base64ToString(str);
}
catch
{
return String.Empty;
}
}
private const string hvals = "0123456789abcdef";
public static int Hex2Int(string hex)
{
int val = 0;
int sum = 0;
string tmp = null;
if (hex != null)
{
tmp = hex.ToLower();
for (int i = 0; i < tmp.Length; i++)
{
val = hvals.IndexOf(tmp[i]);
if (val == -1)
break;
sum *= 16;
sum += val;
}
}
return sum;
}
// Nonce management
public static string NonceGenerator()
{
return StringToBase64(CreationDate + Guid.NewGuid().ToString());
}
// Dump the specified data stream
public static void Dump(byte[] data)
{
char[] buffer = new char[DumpLineSize];
int cc = 0;
for (int i = 0; i < data.Length; i++)
{
if (i % DumpLineSize == 0) Console.Write("\n{0}: ",i.ToString("d8"));
if (i % 4 == 0) Console.Write(" ");
Console.Write("{0}",data[i].ToString("x2"));
if (data[i] < 127 && data[i] > 31)
buffer[i % DumpLineSize] = (char) data[i];
else
buffer[i % DumpLineSize] = '.';
cc++;
if (i != 0 && (i + 1) % DumpLineSize == 0)
{
Console.Write(" |"+(new String(buffer))+"|");
cc = 0;
}
}
// Finish off any incomplete line
if (cc != 0)
{
for (int i = cc ; i < DumpLineSize; i++)
{
if (i % 4 == 0) Console.Write(" ");
Console.Write(" ");
buffer[i % DumpLineSize] = ' ';
}
Console.WriteLine(" |"+(new String(buffer))+"|");
}
else
{
Console.Write("\n");
}
}
}
// Local exception type
public class RestException : Exception
{
internal int statusCode;
internal string statusDesc;
internal string httpmethod;
internal string httppath;
public RestException(string msg) : base(msg)
{
}
}
}

View File

@ -1,860 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Services.Interfaces;
namespace OpenSim.ApplicationPlugins.Rest.Inventory
{
public class RestAppearanceServices : IRest
{
// private static readonly int PARM_USERID = 0;
// private static readonly int PARM_PATH = 1;
// private bool enabled = false;
private string qPrefix = "appearance";
/// <summary>
/// The constructor makes sure that the service prefix is absolute
/// and the registers the service handler and the allocator.
/// </summary>
public RestAppearanceServices()
{
Rest.Log.InfoFormat("{0} User appearance services initializing", MsgId);
Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
// If a relative path was specified for the handler's domain,
// add the standard prefix to make it absolute, e.g. /admin
if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
{
Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId);
qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix);
}
// Register interface using the absolute URI.
Rest.Plugin.AddPathHandler(DoAppearance,qPrefix,Allocate);
// Activate if everything went OK
// enabled = true;
Rest.Log.InfoFormat("{0} User appearance services initialization complete", MsgId);
}
/// <summary>
/// Post-construction, pre-enabled initialization opportunity
/// Not currently exploited.
/// </summary>
public void Initialize()
{
}
/// <summary>
/// Called by the plug-in to halt service processing. Local processing is
/// disabled.
/// </summary>
public void Close()
{
// enabled = false;
Rest.Log.InfoFormat("{0} User appearance services closing down", MsgId);
}
/// <summary>
/// This property is declared locally because it is used a lot and
/// brevity is nice.
/// </summary>
internal string MsgId
{
get { return Rest.MsgId; }
}
#region Interface
/// <summary>
/// The plugin (RestHandler) calls this method to allocate the request
/// state carrier for a new request. It is destroyed when the request
/// completes. All request-instance specific state is kept here. This
/// is registered when this service provider is registered.
/// </summary>
/// <param name=request>Inbound HTTP request information</param>
/// <param name=response>Outbound HTTP request information</param>
/// <param name=qPrefix>REST service domain prefix</param>
/// <returns>A RequestData instance suitable for this service</returns>
private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
{
return (RequestData) new AppearanceRequestData(request, response, prefix);
}
/// <summary>
/// This method is registered with the handler when this service provider
/// is initialized. It is called whenever the plug-in identifies this service
/// provider as the best match for a given request.
/// It handles all aspects of inventory REST processing, i.e. /admin/inventory
/// </summary>
/// <param name=hdata>A consolidated HTTP request work area</param>
private void DoAppearance(RequestData hdata)
{
// !!! REFACTORIMG PROBLEM. This needs rewriting for 0.7
//AppearanceRequestData rdata = (AppearanceRequestData) hdata;
//Rest.Log.DebugFormat("{0} DoAppearance ENTRY", MsgId);
//// If we're disabled, do nothing.
//if (!enabled)
//{
// return;
//}
//// Now that we know this is a serious attempt to
//// access inventory data, we should find out who
//// is asking, and make sure they are authorized
//// to do so. We need to validate the caller's
//// identity before revealing anything about the
//// status quo. Authenticate throws an exception
//// via Fail if no identity information is present.
////
//// With the present HTTP server we can't use the
//// builtin authentication mechanisms because they
//// would be enforced for all in-bound requests.
//// Instead we look at the headers ourselves and
//// handle authentication directly.
//try
//{
// if (!rdata.IsAuthenticated)
// {
// rdata.Fail(Rest.HttpStatusCodeNotAuthorized,String.Format("user \"{0}\" could not be authenticated", rdata.userName));
// }
//}
//catch (RestException e)
//{
// if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
// {
// Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
// Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
// }
// else
// {
// Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
// Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
// }
// throw (e);
//}
//Rest.Log.DebugFormat("{0} Authenticated {1}", MsgId, rdata.userName);
//// We can only get here if we are authorized
////
//// The requestor may have specified an UUID or
//// a conjoined FirstName LastName string. We'll
//// try both. If we fail with the first, UUID,
//// attempt, we try the other. As an example, the
//// URI for a valid inventory request might be:
////
//// http://<host>:<port>/admin/inventory/Arthur Dent
////
//// Indicating that this is an inventory request for
//// an avatar named Arthur Dent. This is ALL that is
//// required to designate a GET for an entire
//// inventory.
////
//// Do we have at least a user agent name?
//if (rdata.Parameters.Length < 1)
//{
// Rest.Log.WarnFormat("{0} Appearance: No user agent identifier specified", MsgId);
// rdata.Fail(Rest.HttpStatusCodeBadRequest, "no user identity specified");
//}
//// The first parameter MUST be the agent identification, either an UUID
//// or a space-separated First-name Last-Name specification. We check for
//// an UUID first, if anyone names their character using a valid UUID
//// that identifies another existing avatar will cause this a problem...
//try
//{
// rdata.uuid = new UUID(rdata.Parameters[PARM_USERID]);
// Rest.Log.DebugFormat("{0} UUID supplied", MsgId);
// rdata.userProfile = Rest.UserServices.GetUserProfile(rdata.uuid);
//}
//catch
//{
// string[] names = rdata.Parameters[PARM_USERID].Split(Rest.CA_SPACE);
// if (names.Length == 2)
// {
// Rest.Log.DebugFormat("{0} Agent Name supplied [2]", MsgId);
// rdata.userProfile = Rest.UserServices.GetUserProfile(names[0],names[1]);
// }
// else
// {
// Rest.Log.WarnFormat("{0} A Valid UUID or both first and last names must be specified", MsgId);
// rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid user identity");
// }
//}
//// If the user profile is null then either the server is broken, or the
//// user is not known. We always assume the latter case.
//if (rdata.userProfile != null)
//{
// Rest.Log.DebugFormat("{0} User profile obtained for agent {1} {2}",
// MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
//}
//else
//{
// Rest.Log.WarnFormat("{0} No user profile for {1}", MsgId, rdata.path);
// rdata.Fail(Rest.HttpStatusCodeNotFound, "unrecognized user identity");
//}
//// If we get to here, then we have effectively validated the user's
//switch (rdata.method)
//{
// case Rest.HEAD : // Do the processing, set the status code, suppress entity
// DoGet(rdata);
// rdata.buffer = null;
// break;
// case Rest.GET : // Do the processing, set the status code, return entity
// DoGet(rdata);
// break;
// case Rest.PUT : // Update named element
// DoUpdate(rdata);
// break;
// case Rest.POST : // Add new information to identified context.
// DoExtend(rdata);
// break;
// case Rest.DELETE : // Delete information
// DoDelete(rdata);
// break;
// default :
// Rest.Log.WarnFormat("{0} Method {1} not supported for {2}",
// MsgId, rdata.method, rdata.path);
// rdata.Fail(Rest.HttpStatusCodeMethodNotAllowed,
// String.Format("{0} not supported", rdata.method));
// break;
//}
}
#endregion Interface
#region method-specific processing
/// <summary>
/// This method implements GET processing for user's appearance.
/// </summary>
/// <param name=rdata>HTTP service request work area</param>
// private void DoGet(AppearanceRequestData rdata)
// {
// AvatarData adata = Rest.AvatarServices.GetAvatar(rdata.userProfile.ID);
//
// if (adata == null)
// {
// rdata.Fail(Rest.HttpStatusCodeNoContent,
// String.Format("appearance data not found for user {0} {1}",
// rdata.userProfile.FirstName, rdata.userProfile.SurName));
// }
// rdata.userAppearance = adata.ToAvatarAppearance(rdata.userProfile.ID);
//
// rdata.initXmlWriter();
//
// FormatUserAppearance(rdata);
//
// // Indicate a successful request
//
// rdata.Complete();
//
// // Send the response to the user. The body will be implicitly
// // constructed from the result of the XML writer.
//
// rdata.Respond(String.Format("Appearance {0} Normal completion", rdata.method));
// }
/// <summary>
/// POST adds NEW information to the user profile database.
/// This effectively resets the appearance before applying those
/// characteristics supplied in the request.
/// </summary>
// private void DoExtend(AppearanceRequestData rdata)
// {
//
// bool created = false;
// bool modified = false;
// string newnode = String.Empty;
//
// Rest.Log.DebugFormat("{0} POST ENTRY", MsgId);
//
// //AvatarAppearance old = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID);
//
// rdata.userAppearance = new AvatarAppearance();
//
// // Although the following behavior is admitted by HTTP I am becoming
// // increasingly doubtful that it is appropriate for REST. If I attempt to
// // add a new record, and it already exists, then it seems to me that the
// // attempt should fail, rather than update the existing record.
// AvatarData adata = null;
// if (GetUserAppearance(rdata))
// {
// modified = rdata.userAppearance != null;
// created = !modified;
// adata = new AvatarData(rdata.userAppearance);
// Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata);
// // Rest.UserServices.UpdateUserProfile(rdata.userProfile);
// }
// else
// {
// created = true;
// adata = new AvatarData(rdata.userAppearance);
// Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata);
// // Rest.UserServices.UpdateUserProfile(rdata.userProfile);
// }
//
// if (created)
// {
// newnode = String.Format("{0} {1}", rdata.userProfile.FirstName,
// rdata.userProfile.SurName);
// // Must include a location header with a URI that identifies the new resource.
//
// rdata.AddHeader(Rest.HttpHeaderLocation,String.Format("http://{0}{1}:{2}{3}{4}",
// rdata.hostname,rdata.port,rdata.path,Rest.UrlPathSeparator, newnode));
// rdata.Complete(Rest.HttpStatusCodeCreated);
//
// }
// else
// {
// if (modified)
// {
// rdata.Complete(Rest.HttpStatusCodeOK);
// }
// else
// {
// rdata.Complete(Rest.HttpStatusCodeNoContent);
// }
// }
//
// rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method));
//
// }
/// <summary>
/// This updates the user's appearance. not all aspects need to be provided,
/// only those supplied will be changed.
/// </summary>
// private void DoUpdate(AppearanceRequestData rdata)
// {
//
// // REFACTORING PROBLEM This was commented out. It doesn't work for 0.7
//
// //bool created = false;
// //bool modified = false;
//
//
// //rdata.userAppearance = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID);
//
// //// If the user exists then this is considered a modification regardless
// //// of what may, or may not be, specified in the payload.
//
// //if (rdata.userAppearance != null)
// //{
// // modified = true;
// // Rest.AvatarServices.UpdateUserAppearance(rdata.userProfile.ID, rdata.userAppearance);
// // Rest.UserServices.UpdateUserProfile(rdata.userProfile);
// //}
//
// //if (created)
// //{
// // rdata.Complete(Rest.HttpStatusCodeCreated);
// //}
// //else
// //{
// // if (modified)
// // {
// // rdata.Complete(Rest.HttpStatusCodeOK);
// // }
// // else
// // {
// // rdata.Complete(Rest.HttpStatusCodeNoContent);
// // }
// //}
//
// rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method));
//
// }
/// <summary>
/// Delete the specified user's appearance. This actually performs a reset
/// to the default avatar appearance, if the info is already there.
/// Existing ownership is preserved. All prior updates are lost and can not
/// be recovered.
/// </summary>
// private void DoDelete(AppearanceRequestData rdata)
// {
// AvatarData adata = Rest.AvatarServices.GetAvatar(rdata.userProfile.ID);
//
// if (adata != null)
// {
// AvatarAppearance old = adata.ToAvatarAppearance(rdata.userProfile.ID);
// rdata.userAppearance = new AvatarAppearance();
// rdata.userAppearance.Owner = old.Owner;
// adata = new AvatarData(rdata.userAppearance);
//
// Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata);
//
// rdata.Complete();
// }
// else
// {
//
// rdata.Complete(Rest.HttpStatusCodeNoContent);
// }
//
// rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method));
// }
#endregion method-specific processing
private bool GetUserAppearance(AppearanceRequestData rdata)
{
XmlReader xml;
bool indata = false;
rdata.initXmlReader();
xml = rdata.reader;
while (xml.Read())
{
switch (xml.NodeType)
{
case XmlNodeType.Element :
switch (xml.Name)
{
case "Appearance" :
if (xml.MoveToAttribute("Height"))
{
rdata.userAppearance.AvatarHeight = (float) Convert.ToDouble(xml.Value);
indata = true;
}
// if (xml.MoveToAttribute("Owner"))
// {
// rdata.userAppearance.Owner = (UUID)xml.Value;
// indata = true;
// }
if (xml.MoveToAttribute("Serial"))
{
rdata.userAppearance.Serial = Convert.ToInt32(xml.Value);
indata = true;
}
break;
/*
case "Body" :
if (xml.MoveToAttribute("Item"))
{
rdata.userAppearance.BodyItem = (UUID)xml.Value;
indata = true;
}
if (xml.MoveToAttribute("Asset"))
{
rdata.userAppearance.BodyAsset = (UUID)xml.Value;
indata = true;
}
break;
case "Skin" :
if (xml.MoveToAttribute("Item"))
{
rdata.userAppearance.SkinItem = (UUID)xml.Value;
indata = true;
}
if (xml.MoveToAttribute("Asset"))
{
rdata.userAppearance.SkinAsset = (UUID)xml.Value;
indata = true;
}
break;
case "Hair" :
if (xml.MoveToAttribute("Item"))
{
rdata.userAppearance.HairItem = (UUID)xml.Value;
indata = true;
}
if (xml.MoveToAttribute("Asset"))
{
rdata.userAppearance.HairAsset = (UUID)xml.Value;
indata = true;
}
break;
case "Eyes" :
if (xml.MoveToAttribute("Item"))
{
rdata.userAppearance.EyesItem = (UUID)xml.Value;
indata = true;
}
if (xml.MoveToAttribute("Asset"))
{
rdata.userAppearance.EyesAsset = (UUID)xml.Value;
indata = true;
}
break;
case "Shirt" :
if (xml.MoveToAttribute("Item"))
{
rdata.userAppearance.ShirtItem = (UUID)xml.Value;
indata = true;
}
if (xml.MoveToAttribute("Asset"))
{
rdata.userAppearance.ShirtAsset = (UUID)xml.Value;
indata = true;
}
break;
case "Pants" :
if (xml.MoveToAttribute("Item"))
{
rdata.userAppearance.PantsItem = (UUID)xml.Value;
indata = true;
}
if (xml.MoveToAttribute("Asset"))
{
rdata.userAppearance.PantsAsset = (UUID)xml.Value;
indata = true;
}
break;
case "Shoes" :
if (xml.MoveToAttribute("Item"))
{
rdata.userAppearance.ShoesItem = (UUID)xml.Value;
indata = true;
}
if (xml.MoveToAttribute("Asset"))
{
rdata.userAppearance.ShoesAsset = (UUID)xml.Value;
indata = true;
}
break;
case "Socks" :
if (xml.MoveToAttribute("Item"))
{
rdata.userAppearance.SocksItem = (UUID)xml.Value;
indata = true;
}
if (xml.MoveToAttribute("Asset"))
{
rdata.userAppearance.SocksAsset = (UUID)xml.Value;
indata = true;
}
break;
case "Jacket" :
if (xml.MoveToAttribute("Item"))
{
rdata.userAppearance.JacketItem = (UUID)xml.Value;
indata = true;
}
if (xml.MoveToAttribute("Asset"))
{
rdata.userAppearance.JacketAsset = (UUID)xml.Value;
indata = true;
}
break;
case "Gloves" :
if (xml.MoveToAttribute("Item"))
{
rdata.userAppearance.GlovesItem = (UUID)xml.Value;
indata = true;
}
if (xml.MoveToAttribute("Asset"))
{
rdata.userAppearance.GlovesAsset = (UUID)xml.Value;
indata = true;
}
break;
case "UnderShirt" :
if (xml.MoveToAttribute("Item"))
{
rdata.userAppearance.UnderShirtItem = (UUID)xml.Value;
indata = true;
}
if (xml.MoveToAttribute("Asset"))
{
rdata.userAppearance.UnderShirtAsset = (UUID)xml.Value;
indata = true;
}
break;
case "UnderPants" :
if (xml.MoveToAttribute("Item"))
{
rdata.userAppearance.UnderPantsItem = (UUID)xml.Value;
indata = true;
}
if (xml.MoveToAttribute("Asset"))
{
rdata.userAppearance.UnderPantsAsset = (UUID)xml.Value;
indata = true;
}
break;
case "Skirt" :
if (xml.MoveToAttribute("Item"))
{
rdata.userAppearance.SkirtItem = (UUID)xml.Value;
indata = true;
}
if (xml.MoveToAttribute("Asset"))
{
rdata.userAppearance.SkirtAsset = (UUID)xml.Value;
indata = true;
}
break;
*/
case "Attachment" :
{
int ap;
UUID asset;
UUID item;
if (xml.MoveToAttribute("AtPoint"))
{
ap = Convert.ToInt32(xml.Value);
if (xml.MoveToAttribute("Asset"))
{
asset = new UUID(xml.Value);
if (xml.MoveToAttribute("Asset"))
{
item = new UUID(xml.Value);
rdata.userAppearance.SetAttachment(ap, item, asset);
indata = true;
}
}
}
}
break;
case "Texture" :
if (xml.MoveToAttribute("Default"))
{
rdata.userAppearance.Texture = new Primitive.TextureEntry(new UUID(xml.Value));
indata = true;
}
break;
case "Face" :
{
uint index;
if (xml.MoveToAttribute("Index"))
{
index = Convert.ToUInt32(xml.Value);
if (xml.MoveToAttribute("Id"))
{
rdata.userAppearance.Texture.CreateFace(index).TextureID = new UUID(xml.Value);
indata = true;
}
}
}
break;
case "VisualParameters" :
{
xml.ReadContentAsBase64(rdata.userAppearance.VisualParams,
0, rdata.userAppearance.VisualParams.Length);
indata = true;
}
break;
}
break;
}
}
return indata;
}
private void FormatPart(AppearanceRequestData rdata, string part, UUID item, UUID asset)
{
if (item != UUID.Zero || asset != UUID.Zero)
{
rdata.writer.WriteStartElement(part);
if (item != UUID.Zero)
{
rdata.writer.WriteAttributeString("Item",item.ToString());
}
if (asset != UUID.Zero)
{
rdata.writer.WriteAttributeString("Asset",asset.ToString());
}
rdata.writer.WriteEndElement();
}
}
private void FormatUserAppearance(AppearanceRequestData rdata)
{
Rest.Log.DebugFormat("{0} FormatUserAppearance", MsgId);
if (rdata.userAppearance != null)
{
Rest.Log.DebugFormat("{0} FormatUserAppearance: appearance object exists", MsgId);
rdata.writer.WriteStartElement("Appearance");
rdata.writer.WriteAttributeString("Height", rdata.userAppearance.AvatarHeight.ToString());
// if (rdata.userAppearance.Owner != UUID.Zero)
// rdata.writer.WriteAttributeString("Owner", rdata.userAppearance.Owner.ToString());
rdata.writer.WriteAttributeString("Serial", rdata.userAppearance.Serial.ToString());
/*
FormatPart(rdata, "Body", rdata.userAppearance.BodyItem, rdata.userAppearance.BodyAsset);
FormatPart(rdata, "Skin", rdata.userAppearance.SkinItem, rdata.userAppearance.SkinAsset);
FormatPart(rdata, "Hair", rdata.userAppearance.HairItem, rdata.userAppearance.HairAsset);
FormatPart(rdata, "Eyes", rdata.userAppearance.EyesItem, rdata.userAppearance.EyesAsset);
FormatPart(rdata, "Shirt", rdata.userAppearance.ShirtItem, rdata.userAppearance.ShirtAsset);
FormatPart(rdata, "Pants", rdata.userAppearance.PantsItem, rdata.userAppearance.PantsAsset);
FormatPart(rdata, "Skirt", rdata.userAppearance.SkirtItem, rdata.userAppearance.SkirtAsset);
FormatPart(rdata, "Shoes", rdata.userAppearance.ShoesItem, rdata.userAppearance.ShoesAsset);
FormatPart(rdata, "Socks", rdata.userAppearance.SocksItem, rdata.userAppearance.SocksAsset);
FormatPart(rdata, "Jacket", rdata.userAppearance.JacketItem, rdata.userAppearance.JacketAsset);
FormatPart(rdata, "Gloves", rdata.userAppearance.GlovesItem, rdata.userAppearance.GlovesAsset);
FormatPart(rdata, "UnderShirt", rdata.userAppearance.UnderShirtItem, rdata.userAppearance.UnderShirtAsset);
FormatPart(rdata, "UnderPants", rdata.userAppearance.UnderPantsItem, rdata.userAppearance.UnderPantsAsset);
*/
Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting attachments", MsgId);
rdata.writer.WriteStartElement("Attachments");
List<AvatarAttachment> attachments = rdata.userAppearance.GetAttachments();
foreach (AvatarAttachment attach in attachments)
{
rdata.writer.WriteStartElement("Attachment");
rdata.writer.WriteAttributeString("AtPoint", attach.AttachPoint.ToString());
rdata.writer.WriteAttributeString("Item", attach.ItemID.ToString());
rdata.writer.WriteAttributeString("Asset", attach.AssetID.ToString());
rdata.writer.WriteEndElement();
}
rdata.writer.WriteEndElement();
Primitive.TextureEntry texture = rdata.userAppearance.Texture;
if (texture != null && (texture.DefaultTexture != null || texture.FaceTextures != null))
{
Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting textures", MsgId);
rdata.writer.WriteStartElement("Texture");
if (texture.DefaultTexture != null)
{
Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting default texture", MsgId);
rdata.writer.WriteAttributeString("Default",
texture.DefaultTexture.TextureID.ToString());
}
if (texture.FaceTextures != null)
{
Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting face textures", MsgId);
for (int i=0; i<texture.FaceTextures.Length;i++)
{
if (texture.FaceTextures[i] != null)
{
rdata.writer.WriteStartElement("Face");
rdata.writer.WriteAttributeString("Index", i.ToString());
rdata.writer.WriteAttributeString("Id",
texture.FaceTextures[i].TextureID.ToString());
rdata.writer.WriteEndElement();
}
}
}
rdata.writer.WriteEndElement();
}
Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting visual parameters", MsgId);
rdata.writer.WriteStartElement("VisualParameters");
rdata.writer.WriteBase64(rdata.userAppearance.VisualParams,0,
rdata.userAppearance.VisualParams.Length);
rdata.writer.WriteEndElement();
rdata.writer.WriteFullEndElement();
}
Rest.Log.DebugFormat("{0} FormatUserAppearance: completed", MsgId);
return;
}
#region appearance RequestData extension
internal class AppearanceRequestData : RequestData
{
/// <summary>
/// These are the inventory specific request/response state
/// extensions.
/// </summary>
internal UUID uuid = UUID.Zero;
internal UserProfileData userProfile = null;
internal AvatarAppearance userAppearance = null;
internal AppearanceRequestData(OSHttpRequest request, OSHttpResponse response, string prefix)
: base(request, response, prefix)
{
}
}
#endregion Appearance RequestData extension
}
}

View File

@ -1,383 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Xml;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
namespace OpenSim.ApplicationPlugins.Rest.Inventory
{
public class RestAssetServices : IRest
{
private bool enabled = false;
private string qPrefix = "assets";
// A simple constructor is used to handle any once-only
// initialization of working classes.
public RestAssetServices()
{
Rest.Log.InfoFormat("{0} Asset services initializing", MsgId);
Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
// If the handler specifies a relative path for its domain
// then we must add the standard absolute prefix, e.g. /admin
if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
{
Rest.Log.InfoFormat("{0} Prefixing domain name ({1})", MsgId, qPrefix);
qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
Rest.Log.InfoFormat("{0} Fully qualified domain name is <{1}>", MsgId, qPrefix);
}
// Register interface using the fully-qualified prefix
Rest.Plugin.AddPathHandler(DoAsset, qPrefix, Allocate);
// Activate if all went OK
enabled = true;
Rest.Log.InfoFormat("{0} Asset services initialization complete", MsgId);
}
// Post-construction, pre-enabled initialization opportunity
// Not currently exploited.
public void Initialize()
{
}
// Called by the plug-in to halt REST processing. Local processing is
// disabled, and control blocks until all current processing has
// completed. No new processing will be started
public void Close()
{
enabled = false;
Rest.Log.InfoFormat("{0} Asset services ({1}) closing down", MsgId, qPrefix);
}
// Properties
internal string MsgId
{
get { return Rest.MsgId; }
}
#region Interface
private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
{
return (RequestData) new AssetRequestData(request, response, prefix);
}
// Asset Handler
private void DoAsset(RequestData rparm)
{
if (!enabled) return;
AssetRequestData rdata = (AssetRequestData) rparm;
Rest.Log.DebugFormat("{0} REST Asset handler ({1}) ENTRY", MsgId, qPrefix);
// Now that we know this is a serious attempt to
// access inventory data, we should find out who
// is asking, and make sure they are authorized
// to do so. We need to validate the caller's
// identity before revealing anything about the
// status quo. Authenticate throws an exception
// via Fail if no identity information is present.
//
// With the present HTTP server we can't use the
// builtin authentication mechanisms because they
// would be enforced for all in-bound requests.
// Instead we look at the headers ourselves and
// handle authentication directly.
try
{
if (!rdata.IsAuthenticated)
{
rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated"));
}
}
catch (RestException e)
{
if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
{
Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId,
rdata.request.Headers.Get("Authorization"));
}
else
{
Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId,
rdata.request.Headers.Get("Authorization"));
}
throw (e);
}
// Remove the prefix and what's left are the parameters. If we don't have
// the parameters we need, fail the request. Parameters do NOT include
// any supplied query values.
if (rdata.Parameters.Length > 0)
{
switch (rdata.method)
{
case "get" :
DoGet(rdata);
break;
case "put" :
DoPut(rdata);
break;
case "post" :
DoPost(rdata);
break;
case "delete" :
default :
Rest.Log.WarnFormat("{0} Asset: Method not supported: {1}",
MsgId, rdata.method);
rdata.Fail(Rest.HttpStatusCodeBadRequest,String.Format("method <{0}> not supported", rdata.method));
break;
}
}
else
{
Rest.Log.WarnFormat("{0} Asset: No agent information provided", MsgId);
rdata.Fail(Rest.HttpStatusCodeBadRequest, "no agent information provided");
}
Rest.Log.DebugFormat("{0} REST Asset handler EXIT", MsgId);
}
#endregion Interface
/// <summary>
/// The only parameter we recognize is a UUID.If an asset with this identification is
/// found, it's content, base-64 encoded, is returned to the client.
/// </summary>
private void DoGet(AssetRequestData rdata)
{
Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method);
if (rdata.Parameters.Length == 1)
{
UUID uuid = new UUID(rdata.Parameters[0]);
AssetBase asset = Rest.AssetServices.Get(uuid.ToString());
if (asset != null)
{
Rest.Log.DebugFormat("{0} Asset located <{1}>", MsgId, rdata.Parameters[0]);
rdata.initXmlWriter();
rdata.writer.WriteStartElement(String.Empty,"Asset",String.Empty);
rdata.writer.WriteAttributeString("id", asset.ID);
rdata.writer.WriteAttributeString("name", asset.Name);
rdata.writer.WriteAttributeString("desc", asset.Description);
rdata.writer.WriteAttributeString("type", asset.Type.ToString());
rdata.writer.WriteAttributeString("local", asset.Local.ToString());
rdata.writer.WriteAttributeString("temporary", asset.Temporary.ToString());
rdata.writer.WriteBase64(asset.Data,0,asset.Data.Length);
rdata.writer.WriteFullEndElement();
}
else
{
Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
}
}
rdata.Complete();
rdata.Respond(String.Format("Asset <{0}> : Normal completion", rdata.method));
}
/// <summary>
/// UPDATE existing item, if it exists. URI identifies the item in question.
/// The only parameter we recognize is a UUID. The enclosed asset data (base-64 encoded)
/// is decoded and stored in the database, identified by the supplied UUID.
/// </summary>
private void DoPut(AssetRequestData rdata)
{
bool modified = false;
bool created = false;
AssetBase asset = null;
Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method);
if (rdata.Parameters.Length == 1)
{
rdata.initXmlReader();
XmlReader xml = rdata.reader;
if (!xml.ReadToFollowing("Asset"))
{
Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path);
rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data");
}
UUID uuid = new UUID(rdata.Parameters[0]);
asset = Rest.AssetServices.Get(uuid.ToString());
modified = (asset != null);
created = !modified;
asset = new AssetBase(uuid, xml.GetAttribute("name"), SByte.Parse(xml.GetAttribute("type")), UUID.Zero.ToString());
asset.Description = xml.GetAttribute("desc");
asset.Local = Int32.Parse(xml.GetAttribute("local")) != 0;
asset.Temporary = Int32.Parse(xml.GetAttribute("temporary")) != 0;
asset.Data = Convert.FromBase64String(xml.ReadElementContentAsString("Asset", ""));
if (asset.ID != rdata.Parameters[0])
{
Rest.Log.WarnFormat("{0} URI and payload disagree on UUID U:{1} vs P:{2}",
MsgId, rdata.Parameters[0], asset.ID);
}
Rest.AssetServices.Store(asset);
}
else
{
Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
}
if (created)
{
rdata.appendStatus(String.Format("<p> Created asset {0}, UUID {1} <p>", asset.Name, asset.FullID));
rdata.Complete(Rest.HttpStatusCodeCreated);
}
else
{
if (modified)
{
rdata.appendStatus(String.Format("<p> Modified asset {0}, UUID {1} <p>", asset.Name, asset.FullID));
rdata.Complete(Rest.HttpStatusCodeOK);
}
else
{
rdata.Complete(Rest.HttpStatusCodeNoContent);
}
}
rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method));
}
/// <summary>
/// CREATE new item, replace if it exists. URI identifies the context for the item in question.
/// No parameters are required for POST, just thepayload.
/// </summary>
private void DoPost(AssetRequestData rdata)
{
bool modified = false;
bool created = false;
Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method);
if (rdata.Parameters.Length != 0)
{
Rest.Log.WarnFormat("{0} Parameters ignored <{1}>", MsgId, rdata.path);
Rest.Log.InfoFormat("{0} POST of an asset has no parameters", MsgId, rdata.path);
}
rdata.initXmlReader();
XmlReader xml = rdata.reader;
if (!xml.ReadToFollowing("Asset"))
{
Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path);
rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data");
}
UUID uuid = new UUID(xml.GetAttribute("id"));
AssetBase asset = Rest.AssetServices.Get(uuid.ToString());
modified = (asset != null);
created = !modified;
asset = new AssetBase(uuid, xml.GetAttribute("name"), SByte.Parse(xml.GetAttribute("type")), UUID.Zero.ToString());
asset.Description = xml.GetAttribute("desc");
asset.Local = Int32.Parse(xml.GetAttribute("local")) != 0;
asset.Temporary = Int32.Parse(xml.GetAttribute("temporary")) != 0;
asset.Data = Convert.FromBase64String(xml.ReadElementContentAsString("Asset", ""));
Rest.AssetServices.Store(asset);
if (created)
{
rdata.appendStatus(String.Format("<p> Created asset {0}, UUID {1} <p>", asset.Name, asset.FullID));
rdata.Complete(Rest.HttpStatusCodeCreated);
}
else
{
if (modified)
{
rdata.appendStatus(String.Format("<p> Modified asset {0}, UUID {1} <p>", asset.Name, asset.FullID));
rdata.Complete(Rest.HttpStatusCodeOK);
}
else
{
rdata.Complete(Rest.HttpStatusCodeNoContent);
}
}
rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method));
}
/// <summary>
/// Asset processing has no special data area requirements.
/// </summary>
internal class AssetRequestData : RequestData
{
internal AssetRequestData(OSHttpRequest request, OSHttpResponse response, string prefix)
: base(request, response, prefix)
{
}
}
}
}

View File

@ -1,448 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Xml;
using System.IO;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
namespace OpenSim.ApplicationPlugins.Rest.Inventory
{
public class RestFileServices : IRest
{
private bool enabled = false;
private string qPrefix = "files";
// A simple constructor is used to handle any once-only
// initialization of working classes.
public RestFileServices()
{
Rest.Log.InfoFormat("{0} File services initializing", MsgId);
Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
// If the handler specifies a relative path for its domain
// then we must add the standard absolute prefix, e.g. /admin
if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
{
Rest.Log.InfoFormat("{0} Prefixing domain name ({1})", MsgId, qPrefix);
qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
Rest.Log.InfoFormat("{0} Fully qualified domain name is <{1}>", MsgId, qPrefix);
}
// Register interface using the fully-qualified prefix
Rest.Plugin.AddPathHandler(DoFile, qPrefix, Allocate);
// Activate if all went OK
enabled = true;
Rest.Log.InfoFormat("{0} File services initialization complete", MsgId);
}
// Post-construction, pre-enabled initialization opportunity
// Not currently exploited.
public void Initialize()
{
}
// Called by the plug-in to halt REST processing. Local processing is
// disabled, and control blocks until all current processing has
// completed. No new processing will be started
public void Close()
{
enabled = false;
Rest.Log.InfoFormat("{0} File services ({1}) closing down", MsgId, qPrefix);
}
// Properties
internal string MsgId
{
get { return Rest.MsgId; }
}
#region Interface
private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
{
return (RequestData) new FileRequestData(request, response, prefix);
}
// Asset Handler
private void DoFile(RequestData rparm)
{
if (!enabled) return;
FileRequestData rdata = (FileRequestData) rparm;
Rest.Log.DebugFormat("{0} REST File handler ({1}) ENTRY", MsgId, qPrefix);
// Now that we know this is a serious attempt to
// access file data, we should find out who
// is asking, and make sure they are authorized
// to do so. We need to validate the caller's
// identity before revealing anything about the
// status quo. Authenticate throws an exception
// via Fail if no identity information is present.
//
// With the present HTTP server we can't use the
// builtin authentication mechanisms because they
// would be enforced for all in-bound requests.
// Instead we look at the headers ourselves and
// handle authentication directly.
try
{
if (!rdata.IsAuthenticated)
{
rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated"));
}
}
catch (RestException e)
{
if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
{
Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId,
rdata.request.Headers.Get("Authorization"));
}
else
{
Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId,
rdata.request.Headers.Get("Authorization"));
}
throw (e);
}
// Remove the prefix and what's left are the parameters. If we don't have
// the parameters we need, fail the request. Parameters do NOT include
// any supplied query values.
if (rdata.Parameters.Length > 0)
{
switch (rdata.method)
{
case "get" :
DoGet(rdata);
break;
case "put" :
DoPut(rdata);
break;
case "post" :
DoPost(rdata);
break;
case "delete" :
DoDelete(rdata);
break;
default :
Rest.Log.WarnFormat("{0} File: Method not supported: {1}",
MsgId, rdata.method);
rdata.Fail(Rest.HttpStatusCodeBadRequest,String.Format("method <{0}> not supported", rdata.method));
break;
}
}
else
{
Rest.Log.WarnFormat("{0} File: No agent information provided", MsgId);
rdata.Fail(Rest.HttpStatusCodeBadRequest, "no agent information provided");
}
Rest.Log.DebugFormat("{0} REST File handler EXIT", MsgId);
}
#endregion Interface
/// <summary>
/// The only parameter we recognize is a UUID.If an asset with this identification is
/// found, it's content, base-64 encoded, is returned to the client.
/// </summary>
private void DoGet(FileRequestData rdata)
{
string path = String.Empty;
Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method);
if (rdata.Parameters.Length > 1)
{
try
{
path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2);
if (File.Exists(path))
{
Rest.Log.DebugFormat("{0} File located <{1}>", MsgId, path);
Byte[] data = File.ReadAllBytes(path);
rdata.initXmlWriter();
rdata.writer.WriteStartElement(String.Empty,"File",String.Empty);
rdata.writer.WriteAttributeString("name", path);
rdata.writer.WriteBase64(data,0,data.Length);
rdata.writer.WriteFullEndElement();
}
else
{
Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, path);
rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0}", path));
}
}
catch (Exception e)
{
Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, e.Message);
rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0} {1}",
path, e.Message));
}
}
rdata.Complete();
rdata.Respond(String.Format("File <{0}> : Normal completion", rdata.method));
}
/// <summary>
/// UPDATE existing item, if it exists. URI identifies the item in question.
/// The only parameter we recognize is a UUID. The enclosed asset data (base-64 encoded)
/// is decoded and stored in the database, identified by the supplied UUID.
/// </summary>
private void DoPut(FileRequestData rdata)
{
bool modified = false;
bool created = false;
string path = String.Empty;
Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method);
if (rdata.Parameters.Length > 1)
{
try
{
path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2);
bool maymod = File.Exists(path);
rdata.initXmlReader();
XmlReader xml = rdata.reader;
if (!xml.ReadToFollowing("File"))
{
Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path);
rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data");
}
Byte[] data = Convert.FromBase64String(xml.ReadElementContentAsString("File", ""));
File.WriteAllBytes(path,data);
modified = maymod;
created = ! maymod;
}
catch (Exception e)
{
Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId,
e.Message);
}
}
else
{
Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
}
if (created)
{
rdata.appendStatus(String.Format("<p> Created file {0} <p>", path));
rdata.Complete(Rest.HttpStatusCodeCreated);
}
else
{
if (modified)
{
rdata.appendStatus(String.Format("<p> Modified file {0} <p>", path));
rdata.Complete(Rest.HttpStatusCodeOK);
}
else
{
rdata.Complete(Rest.HttpStatusCodeNoContent);
}
}
rdata.Respond(String.Format("File {0} : Normal completion", rdata.method));
}
/// <summary>
/// CREATE new item, replace if it exists. URI identifies the context for the item in question.
/// No parameters are required for POST, just thepayload.
/// </summary>
private void DoPost(FileRequestData rdata)
{
bool modified = false;
bool created = false;
string path = String.Empty;
Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method);
if (rdata.Parameters.Length > 1)
{
try
{
path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2);
bool maymod = File.Exists(path);
rdata.initXmlReader();
XmlReader xml = rdata.reader;
if (!xml.ReadToFollowing("File"))
{
Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path);
rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data");
}
Byte[] data = Convert.FromBase64String(xml.ReadElementContentAsString("File", ""));
File.WriteAllBytes(path,data);
modified = maymod;
created = ! maymod;
}
catch (Exception e)
{
Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId,
e.Message);
}
}
else
{
Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
}
if (created)
{
rdata.appendStatus(String.Format("<p> Created file {0} <p>", path));
rdata.Complete(Rest.HttpStatusCodeCreated);
}
else
{
if (modified)
{
rdata.appendStatus(String.Format("<p> Modified file {0} <p>", path));
rdata.Complete(Rest.HttpStatusCodeOK);
}
else
{
rdata.Complete(Rest.HttpStatusCodeNoContent);
}
}
rdata.Respond(String.Format("File {0} : Normal completion", rdata.method));
}
/// <summary>
/// CREATE new item, replace if it exists. URI identifies the context for the item in question.
/// No parameters are required for POST, just thepayload.
/// </summary>
private void DoDelete(FileRequestData rdata)
{
bool modified = false;
bool created = false;
string path = String.Empty;
Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method);
if (rdata.Parameters.Length > 1)
{
try
{
path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2);
if (File.Exists(path))
{
File.Delete(path);
}
}
catch (Exception e)
{
Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId,
e.Message);
rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0} {1}",
path, e.Message));
}
}
else
{
Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
}
if (created)
{
rdata.appendStatus(String.Format("<p> Created file {0} <p>", path));
rdata.Complete(Rest.HttpStatusCodeCreated);
}
else
{
if (modified)
{
rdata.appendStatus(String.Format("<p> Modified file {0} <p>", path));
rdata.Complete(Rest.HttpStatusCodeOK);
}
else
{
rdata.Complete(Rest.HttpStatusCodeNoContent);
}
}
rdata.Respond(String.Format("File {0} : Normal completion", rdata.method));
}
/// <summary>
/// File processing has no special data area requirements.
/// </summary>
internal class FileRequestData : RequestData
{
internal FileRequestData(OSHttpRequest request, OSHttpResponse response, string prefix)
: base(request, response, prefix)
{
}
}
}
}

View File

@ -1,662 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
namespace OpenSim.ApplicationPlugins.Rest.Inventory
{
/// <remarks>
/// The class signature reveals the roles that RestHandler plays.
///
/// [1] It is a sub-class of RestPlugin. It inherits and extends
/// the functionality of this class, constraining it to the
/// specific needs of this REST implementation. This relates
/// to the plug-in mechanism supported by OpenSim, the specifics
/// of which are mostly hidden by RestPlugin.
/// [2] IRestHandler describes the interface that this class
/// exports to service implementations. This is the services
/// management interface.
/// [3] IHttpAgentHandler describes the interface that is exported
/// to the BaseHttpServer in support of this particular HTTP
/// processing model. This is the request interface of the
/// handler.
/// </remarks>
public class RestHandler : RestPlugin, IRestHandler, IHttpAgentHandler
{
// Handler tables: both stream and REST are supported. The path handlers and their
// respective allocators are stored in separate tables.
internal Dictionary<string,RestMethodHandler> pathHandlers = new Dictionary<string,RestMethodHandler>();
internal Dictionary<string,RestMethodAllocator> pathAllocators = new Dictionary<string,RestMethodAllocator>();
internal Dictionary<string,RestStreamHandler> streamHandlers = new Dictionary<string,RestStreamHandler>();
#region local static state
private static bool handlersLoaded = false;
private static List<Type> classes = new List<Type>();
private static List<IRest> handlers = new List<IRest>();
private static Type[] parms = new Type[0];
private static Object[] args = new Object[0];
/// <summary>
/// This static initializer scans the ASSEMBLY for classes that
/// export the IRest interface and builds a list of them. These
/// are later activated by the handler. To add a new handler it
/// is only necessary to create a new services class that implements
/// the IRest interface, and recompile the handler. This gives
/// all of the build-time flexibility of a modular approach
/// while not introducing yet-another module loader. Note that
/// multiple assembles can still be built, each with its own set
/// of handlers. Examples of services classes are RestInventoryServices
/// and RestSkeleton.
/// </summary>
static RestHandler()
{
Module[] mods = Assembly.GetExecutingAssembly().GetModules();
foreach (Module m in mods)
{
Type[] types = m.GetTypes();
foreach (Type t in types)
{
try
{
if (t.GetInterface("IRest") != null)
{
classes.Add(t);
}
}
catch (Exception)
{
Rest.Log.WarnFormat("[STATIC-HANDLER]: #0 Error scanning {1}", t);
Rest.Log.InfoFormat("[STATIC-HANDLER]: #0 {1} is not included", t);
}
}
}
}
#endregion local static state
#region local instance state
/// <summary>
/// This routine loads all of the handlers discovered during
/// instance initialization.
/// A table of all loaded and successfully constructed handlers
/// is built, and this table is then used by the constructor to
/// initialize each of the handlers in turn.
/// NOTE: The loading process does not automatically imply that
/// the handler has registered any kind of an interface, that
/// may be (optionally) done by the handler either during
/// construction, or during initialization.
///
/// I was not able to make this code work within a constructor
/// so it is isolated within this method.
/// </summary>
private void LoadHandlers()
{
lock (handlers)
{
if (!handlersLoaded)
{
ConstructorInfo ci;
Object ht;
foreach (Type t in classes)
{
try
{
ci = t.GetConstructor(parms);
ht = ci.Invoke(args);
handlers.Add((IRest)ht);
}
catch (Exception e)
{
Rest.Log.WarnFormat("{0} Unable to load {1} : {2}", MsgId, t, e.Message);
}
}
handlersLoaded = true;
}
}
}
#endregion local instance state
#region overriding properties
// These properties override definitions
// in the base class.
// Name is used to differentiate the message header.
public override string Name
{
get { return "HANDLER"; }
}
// Used to partition the .ini configuration space.
public override string ConfigName
{
get { return "RestHandler"; }
}
// We have to rename these because we want
// to be able to share the values with other
// classes in our assembly and the base
// names are protected.
public string MsgId
{
get { return base.MsgID; }
}
public string RequestId
{
get { return base.RequestID; }
}
#endregion overriding properties
#region overriding methods
/// <summary>
/// This method is called by OpenSimMain immediately after loading the
/// plugin and after basic server setup, but before running any server commands.
/// </summary>
/// <remarks>
/// Note that entries MUST be added to the active configuration files before
/// the plugin can be enabled.
/// </remarks>
public override void Initialise(OpenSimBase openSim)
{
try
{
// This plugin will only be enabled if the broader
// REST plugin mechanism is enabled.
//Rest.Log.InfoFormat("{0} Plugin is initializing", MsgId);
base.Initialise(openSim);
// IsEnabled is implemented by the base class and
// reflects an overall RestPlugin status
if (!IsEnabled)
{
//Rest.Log.WarnFormat("{0} Plugins are disabled", MsgId);
return;
}
Rest.Log.InfoFormat("{0} Rest <{1}> plugin will be enabled", MsgId, Name);
Rest.Log.InfoFormat("{0} Configuration parameters read from <{1}>", MsgId, ConfigName);
// These are stored in static variables to make
// them easy to reach from anywhere in the assembly.
Rest.main = openSim;
if (Rest.main == null)
throw new Exception("OpenSim base pointer is null");
Rest.Plugin = this;
Rest.Config = Config;
Rest.Prefix = Prefix;
Rest.GodKey = GodKey;
Rest.Authenticate = Rest.Config.GetBoolean("authenticate", Rest.Authenticate);
Rest.Scheme = Rest.Config.GetString("auth-scheme", Rest.Scheme);
Rest.Secure = Rest.Config.GetBoolean("secured", Rest.Secure);
Rest.ExtendedEscape = Rest.Config.GetBoolean("extended-escape", Rest.ExtendedEscape);
Rest.Realm = Rest.Config.GetString("realm", Rest.Realm);
Rest.DumpAsset = Rest.Config.GetBoolean("dump-asset", Rest.DumpAsset);
Rest.Fill = Rest.Config.GetBoolean("path-fill", Rest.Fill);
Rest.DumpLineSize = Rest.Config.GetInt("dump-line-size", Rest.DumpLineSize);
Rest.FlushEnabled = Rest.Config.GetBoolean("flush-on-error", Rest.FlushEnabled);
// Note: Odd spacing is required in the following strings
Rest.Log.InfoFormat("{0} Authentication is {1}required", MsgId,
(Rest.Authenticate ? "" : "not "));
Rest.Log.InfoFormat("{0} Security is {1}enabled", MsgId,
(Rest.Secure ? "" : "not "));
Rest.Log.InfoFormat("{0} Extended URI escape processing is {1}enabled", MsgId,
(Rest.ExtendedEscape ? "" : "not "));
Rest.Log.InfoFormat("{0} Dumping of asset data is {1}enabled", MsgId,
(Rest.DumpAsset ? "" : "not "));
// The supplied prefix MUST be absolute
if (Rest.Prefix.Substring(0,1) != Rest.UrlPathSeparator)
{
Rest.Log.WarnFormat("{0} Prefix <{1}> is not absolute and must be", MsgId, Rest.Prefix);
Rest.Log.InfoFormat("{0} Prefix changed to </{1}>", MsgId, Rest.Prefix);
Rest.Prefix = String.Format("{0}{1}", Rest.UrlPathSeparator, Rest.Prefix);
}
// If data dumping is requested, report on the chosen line
// length.
if (Rest.DumpAsset)
{
Rest.Log.InfoFormat("{0} Dump {1} bytes per line", MsgId, Rest.DumpLineSize);
}
// Load all of the handlers present in the
// assembly
// In principle, as we're an application plug-in,
// most of what needs to be done could be done using
// static resources, however the Open Sim plug-in
// model makes this an instance, so that's what we
// need to be.
// There is only one Communications manager per
// server, and by inference, only one each of the
// user, asset, and inventory servers. So we can cache
// those using a static initializer.
// We move all of this processing off to another
// services class to minimize overlap between function
// and infrastructure.
LoadHandlers();
// The intention of a post construction initializer
// is to allow for setup that is dependent upon other
// activities outside of the agency.
foreach (IRest handler in handlers)
{
try
{
handler.Initialize();
}
catch (Exception e)
{
Rest.Log.ErrorFormat("{0} initialization error: {1}", MsgId, e.Message);
}
}
// Now that everything is setup we can proceed to
// add THIS agent to the HTTP server's handler list
// FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
// have to be handled through the AddHttpHandler interface.
// if (!AddAgentHandler(Rest.Name,this))
// {
// Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId);
// foreach (IRest handler in handlers)
// {
// handler.Close();
// }
// }
}
catch (Exception e)
{
Rest.Log.ErrorFormat("{0} Plugin initialization has failed: {1}", MsgId, e.Message);
}
}
/// <summary>
/// In the interests of efficiency, and because we cannot determine whether
/// or not this instance will actually be harvested, we clobber the only
/// anchoring reference to the working state for this plug-in. What the
/// call to close does is irrelevant to this class beyond knowing that it
/// can nullify the reference when it returns.
/// To make sure everything is copacetic we make sure the primary interface
/// is disabled by deleting the handler from the HTTP server tables.
/// </summary>
public override void Close()
{
Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId);
// FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
// have to be handled through the AddHttpHandler interface.
// try
// {
// RemoveAgentHandler(Rest.Name, this);
// }
// catch (KeyNotFoundException){}
foreach (IRest handler in handlers)
{
handler.Close();
}
}
#endregion overriding methods
#region interface methods
/// <summary>
/// This method is called by the HTTP server to match an incoming
/// request. It scans all of the strings registered by the
/// underlying handlers and looks for the best match. It returns
/// true if a match is found.
/// The matching process could be made arbitrarily complex.
/// Note: The match is case-insensitive.
/// </summary>
public bool Match(OSHttpRequest request, OSHttpResponse response)
{
string path = request.RawUrl.ToLower();
// Rest.Log.DebugFormat("{0} Match ENTRY", MsgId);
try
{
foreach (string key in pathHandlers.Keys)
{
// Rest.Log.DebugFormat("{0} Match testing {1} against agent prefix <{2}>", MsgId, path, key);
// Note that Match will not necessarily find the handler that will
// actually be used - it does no test for the "closest" fit. It
// simply reflects that at least one possible handler exists.
if (path.StartsWith(key))
{
// Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key);
// This apparently odd evaluation is needed to prevent a match
// on anything other than a URI token boundary. Otherwise we
// may match on URL's that were not intended for this handler.
return (path.Length == key.Length ||
path.Substring(key.Length, 1) == Rest.UrlPathSeparator);
}
}
path = String.Format("{0}{1}{2}", request.HttpMethod, Rest.UrlMethodSeparator, path);
foreach (string key in streamHandlers.Keys)
{
// Rest.Log.DebugFormat("{0} Match testing {1} against stream prefix <{2}>", MsgId, path, key);
// Note that Match will not necessarily find the handler that will
// actually be used - it does no test for the "closest" fit. It
// simply reflects that at least one possible handler exists.
if (path.StartsWith(key))
{
// Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key);
// This apparently odd evaluation is needed to prevent a match
// on anything other than a URI token boundary. Otherwise we
// may match on URL's that were not intended for this handler.
return (path.Length == key.Length ||
path.Substring(key.Length, 1) == Rest.UrlPathSeparator);
}
}
}
catch (Exception e)
{
Rest.Log.ErrorFormat("{0} matching exception for path <{1}> : {2}", MsgId, path, e.Message);
}
return false;
}
/// <summary>
/// This is called by the HTTP server once the handler has indicated
/// that it is able to handle the request.
/// Preconditions:
/// [1] request != null and is a valid request object
/// [2] response != null and is a valid response object
/// Behavior is undefined if preconditions are not satisfied.
/// </summary>
public bool Handle(OSHttpRequest request, OSHttpResponse response)
{
bool handled;
base.MsgID = base.RequestID;
// Debug only
if (Rest.DEBUG)
{
Rest.Log.DebugFormat("{0} ENTRY", MsgId);
Rest.Log.DebugFormat("{0} Agent: {1}", MsgId, request.UserAgent);
Rest.Log.DebugFormat("{0} Method: {1}", MsgId, request.HttpMethod);
for (int i = 0; i < request.Headers.Count; i++)
{
Rest.Log.DebugFormat("{0} Header [{1}] : <{2}> = <{3}>",
MsgId, i, request.Headers.GetKey(i), request.Headers.Get(i));
}
Rest.Log.DebugFormat("{0} URI: {1}", MsgId, request.RawUrl);
}
// If a path handler worked we're done, otherwise try any
// available stream handlers too.
try
{
handled = (FindPathHandler(request, response) ||
FindStreamHandler(request, response));
}
catch (Exception e)
{
// A raw exception indicates that something we weren't expecting has
// happened. This should always reflect a shortcoming in the plugin,
// or a failure to satisfy the preconditions. It should not reflect
// an error in the request itself. Under such circumstances the state
// of the request cannot be determined and we are obliged to mark it
// as 'handled'.
Rest.Log.ErrorFormat("{0} Plugin error: {1}", MsgId, e.Message);
handled = true;
}
Rest.Log.DebugFormat("{0} EXIT", MsgId);
return handled;
}
#endregion interface methods
/// <summary>
/// If there is a stream handler registered that can handle the
/// request, then fine. If the request is not matched, do
/// nothing.
/// Note: The selection is case-insensitive
/// </summary>
private bool FindStreamHandler(OSHttpRequest request, OSHttpResponse response)
{
RequestData rdata = new RequestData(request, response, String.Empty);
string bestMatch = String.Empty;
string path = String.Format("{0}:{1}", rdata.method, rdata.path).ToLower();
Rest.Log.DebugFormat("{0} Checking for stream handler for <{1}>", MsgId, path);
if (!IsEnabled)
{
return false;
}
foreach (string pattern in streamHandlers.Keys)
{
if (path.StartsWith(pattern))
{
if (pattern.Length > bestMatch.Length)
{
bestMatch = pattern;
}
}
}
// Handle using the best match available
if (bestMatch.Length > 0)
{
Rest.Log.DebugFormat("{0} Stream-based handler matched with <{1}>", MsgId, bestMatch);
RestStreamHandler handler = streamHandlers[bestMatch];
rdata.buffer = handler.Handle(rdata.path, rdata.request.InputStream, rdata.request, rdata.response);
rdata.AddHeader(rdata.response.ContentType,handler.ContentType);
rdata.Respond("FindStreamHandler Completion");
}
return rdata.handled;
}
/// <summary>
/// Add a stream handler for the designated HTTP method and path prefix.
/// If the handler is not enabled, the request is ignored. If the path
/// does not start with the REST prefix, it is added. If method-qualified
/// path has not already been registered, the method is added to the active
/// handler table.
/// </summary>
public void AddStreamHandler(string httpMethod, string path, RestMethod method)
{
if (!IsEnabled)
{
return;
}
if (!path.StartsWith(Rest.Prefix))
{
path = String.Format("{0}{1}", Rest.Prefix, path);
}
path = String.Format("{0}{1}{2}", httpMethod, Rest.UrlMethodSeparator, path);
// Conditionally add to the list
if (!streamHandlers.ContainsKey(path))
{
streamHandlers.Add(path, new RestStreamHandler(httpMethod, path, method));
Rest.Log.DebugFormat("{0} Added handler for {1}", MsgId, path);
}
else
{
Rest.Log.WarnFormat("{0} Ignoring duplicate handler for {1}", MsgId, path);
}
}
/// <summary>
/// Given the supplied request/response, if the handler is enabled, the inbound
/// information is used to match an entry in the active path handler tables, using
/// the method-qualified path information. If a match is found, then the handler is
/// invoked. The result is the boolean result of the handler, or false if no
/// handler was located. The boolean indicates whether or not the request has been
/// handled, not whether or not the request was successful - that information is in
/// the response.
/// Note: The selection process is case-insensitive
/// </summary>
internal bool FindPathHandler(OSHttpRequest request, OSHttpResponse response)
{
RequestData rdata = null;
string bestMatch = null;
if (!IsEnabled)
{
return false;
}
// Conditionally add to the list
Rest.Log.DebugFormat("{0} Checking for path handler for <{1}>", MsgId, request.RawUrl);
foreach (string pattern in pathHandlers.Keys)
{
if (request.RawUrl.ToLower().StartsWith(pattern))
{
if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
{
bestMatch = pattern;
}
}
}
if (!String.IsNullOrEmpty(bestMatch))
{
rdata = pathAllocators[bestMatch](request, response, bestMatch);
Rest.Log.DebugFormat("{0} Path based REST handler matched with <{1}>", MsgId, bestMatch);
try
{
pathHandlers[bestMatch](rdata);
}
// A plugin generated error indicates a request-related error
// that has been handled by the plugin.
catch (RestException r)
{
Rest.Log.WarnFormat("{0} Request failed: {1}", MsgId, r.Message);
}
}
return (rdata == null) ? false : rdata.handled;
}
/// <summary>
/// A method handler and a request allocator are stored using the designated
/// path as a key. If an entry already exists, it is replaced by the new one.
/// </summary>
public void AddPathHandler(RestMethodHandler mh, string path, RestMethodAllocator ra)
{
if (!IsEnabled)
{
return;
}
if (pathHandlers.ContainsKey(path))
{
Rest.Log.DebugFormat("{0} Replacing handler for <${1}>", MsgId, path);
pathHandlers.Remove(path);
}
if (pathAllocators.ContainsKey(path))
{
Rest.Log.DebugFormat("{0} Replacing allocator for <${1}>", MsgId, path);
pathAllocators.Remove(path);
}
Rest.Log.DebugFormat("{0} Adding path handler for {1}", MsgId, path);
pathHandlers.Add(path, mh);
pathAllocators.Add(path, ra);
}
}
}

View File

@ -1,246 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
namespace OpenSim.ApplicationPlugins.Rest.Inventory
{
public class RestTestServices : IRest
{
private bool enabled = false;
private string qPrefix = "test";
// A simple constructor is used to handle any once-only
// initialization of working classes.
public RestTestServices()
{
Rest.Log.InfoFormat("{0} Test services initializing", MsgId);
Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
// If a relative path was specified, make it absolute by adding
// the standard prefix, e.g. /admin
if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
{
Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId);
qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix);
}
// Load test cases
loadTests();
foreach (ITest test in tests)
{
test.Initialize();
}
// Register interface
Rest.Plugin.AddPathHandler(DoTests,qPrefix,Allocate);
// Activate
enabled = true;
Rest.Log.InfoFormat("{0} Test services initialization complete", MsgId);
}
// Post-construction, pre-enabled initialization opportunity
// Not currently exploited.
public void Initialize()
{
}
// Called by the plug-in to halt REST processing. Local processing is
// disabled, and control blocks until all current processing has
// completed. No new processing will be started
public void Close()
{
enabled = false;
foreach (ITest test in tests)
{
test.Close();
}
Rest.Log.InfoFormat("{0} Test services closing down", MsgId);
}
// Properties
internal string MsgId
{
get { return Rest.MsgId; }
}
#region Interface
private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
{
return new RequestData(request, response, prefix);
}
// Inventory Handler
private void DoTests(RequestData rdata)
{
if (!enabled)
return;
// Now that we know this is a serious attempt to
// access inventory data, we should find out who
// is asking, and make sure they are authorized
// to do so. We need to validate the caller's
// identity before revealing anything about the
// status quo. Authenticate throws an exception
// via Fail if no identity information is present.
//
// With the present HTTP server we can't use the
// builtin authentication mechanisms because they
// would be enforced for all in-bound requests.
// Instead we look at the headers ourselves and
// handle authentication directly.
try
{
if (!rdata.IsAuthenticated)
{
rdata.Fail(Rest.HttpStatusCodeNotAuthorized,
String.Format("user \"{0}\" could not be authenticated", rdata.userName));
}
}
catch (RestException e)
{
if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
{
Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
}
else
{
Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
}
throw (e);
}
// Check that a test was specified
if (rdata.Parameters.Length < 1)
{
Rest.Log.DebugFormat("{0} Insufficient parameters", MsgId);
rdata.Fail(Rest.HttpStatusCodeBadRequest, "not enough parameters");
}
// Select the test
foreach (ITest test in tests)
{
if (!rdata.handled)
test.Execute(rdata);
}
}
#endregion Interface
private static bool testsLoaded = false;
private static List<Type> classes = new List<Type>();
private static List<ITest> tests = new List<ITest>();
private static Type[] parms = new Type[0];
private static Object[] args = new Object[0];
static RestTestServices()
{
Module[] mods = Assembly.GetExecutingAssembly().GetModules();
foreach (Module m in mods)
{
Type[] types = m.GetTypes();
foreach (Type t in types)
{
try
{
if (t.GetInterface("ITest") != null)
{
classes.Add(t);
}
}
catch (Exception e)
{
Rest.Log.WarnFormat("[STATIC-TEST] Unable to include test {0} : {1}", t, e.Message);
}
}
}
}
/// <summary>
/// This routine loads all of the handlers discovered during
/// instance initialization. Each handler is responsible for
/// registering itself with this handler.
/// I was not able to make this code work in a constructor.
/// </summary>
private void loadTests()
{
lock (tests)
{
if (!testsLoaded)
{
ConstructorInfo ci;
Object ht;
foreach (Type t in classes)
{
try
{
if (t.GetInterface("ITest") != null)
{
ci = t.GetConstructor(parms);
ht = ci.Invoke(args);
tests.Add((ITest)ht);
Rest.Log.InfoFormat("{0} Test {1} added", MsgId, t);
}
}
catch (Exception e)
{
Rest.Log.WarnFormat("{0} Unable to load test {1} : {2}", MsgId, t, e.Message);
}
}
testsLoaded = true;
}
}
}
}
}

View File

@ -1,46 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
namespace OpenSim.ApplicationPlugins.Rest.Inventory
{
/// <summary>
/// This interface represents the boundary between the general purpose
/// REST plugin handling, and the functionally specific handlers. The
/// handler knows only to initialzie and terminate all such handlers
/// that it finds.
/// </summary>
internal interface ITest
{
void Initialize();
void Execute(RequestData rdata);
void Close();
}
}

View File

@ -1,204 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using OpenMetaverse;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.ApplicationPlugins.Rest.Inventory.Tests
{
public class Remote : ITest
{
private static readonly int PARM_TESTID = 0;
private static readonly int PARM_COMMAND = 1;
private static readonly int PARM_MOVE_AVATAR = 2;
private static readonly int PARM_MOVE_X = 3;
private static readonly int PARM_MOVE_Y = 4;
private static readonly int PARM_MOVE_Z = 5;
private bool enabled = false;
// No constructor code is required.
public Remote()
{
Rest.Log.InfoFormat("{0} Remote services constructor", MsgId);
}
// Post-construction, pre-enabled initialization opportunity
// Not currently exploited.
public void Initialize()
{
enabled = true;
Rest.Log.InfoFormat("{0} Remote services initialized", MsgId);
}
// Called by the plug-in to halt REST processing. Local processing is
// disabled, and control blocks until all current processing has
// completed. No new processing will be started
public void Close()
{
enabled = false;
Rest.Log.InfoFormat("{0} Remote services closing down", MsgId);
}
// Properties
internal string MsgId
{
get { return Rest.MsgId; }
}
// Remote Handler
// Key information of interest here is the Parameters array, each
// entry represents an element of the URI, with element zero being
// the
public void Execute(RequestData rdata)
{
if (!enabled) return;
// If we can't relate to what's there, leave it for others.
if (rdata.Parameters.Length == 0 || rdata.Parameters[PARM_TESTID] != "remote")
return;
Rest.Log.DebugFormat("{0} REST Remote handler ENTRY", MsgId);
// Remove the prefix and what's left are the parameters. If we don't have
// the parameters we need, fail the request. Parameters do NOT include
// any supplied query values.
if (rdata.Parameters.Length > 1)
{
switch (rdata.Parameters[PARM_COMMAND].ToLower())
{
case "move" :
DoMove(rdata);
break;
default :
DoHelp(rdata);
break;
}
}
else
{
DoHelp(rdata);
}
}
private void DoHelp(RequestData rdata)
{
rdata.body = Help;
rdata.Complete();
rdata.Respond("Help");
}
private void DoMove(RequestData rdata)
{
if (rdata.Parameters.Length < 6)
{
Rest.Log.WarnFormat("{0} Move: No movement information provided", MsgId);
rdata.Fail(Rest.HttpStatusCodeBadRequest, "no movement information provided");
}
else
{
string[] names = rdata.Parameters[PARM_MOVE_AVATAR].Split(Rest.CA_SPACE);
ScenePresence presence = null;
Scene scene = null;
if (names.Length != 2)
{
rdata.Fail(Rest.HttpStatusCodeBadRequest,
String.Format("invalid avatar name: <{0}>",rdata.Parameters[PARM_MOVE_AVATAR]));
}
Rest.Log.WarnFormat("{0} '{1}' command received for {2} {3}",
MsgId, rdata.Parameters[0], names[0], names[1]);
// The first parameter should be an avatar name, look for the
// avatar in the known regions first.
Rest.main.SceneManager.ForEachScene(delegate(Scene s)
{
s.ForEachRootScenePresence(delegate(ScenePresence sp)
{
if (sp.Firstname == names[0] && sp.Lastname == names[1])
{
scene = s;
presence = sp;
}
});
});
if (presence != null)
{
Rest.Log.DebugFormat("{0} Move : Avatar {1} located in region {2}",
MsgId, rdata.Parameters[PARM_MOVE_AVATAR], scene.RegionInfo.RegionName);
try
{
float x = Convert.ToSingle(rdata.Parameters[PARM_MOVE_X]);
float y = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Y]);
float z = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Z]);
Vector3 vector = new Vector3(x, y, z);
presence.MoveToTarget(vector, false, false);
}
catch (Exception e)
{
rdata.Fail(Rest.HttpStatusCodeBadRequest,
String.Format("invalid parameters: {0}", e.Message));
}
}
else
{
rdata.Fail(Rest.HttpStatusCodeBadRequest,
String.Format("avatar {0} not present", rdata.Parameters[PARM_MOVE_AVATAR]));
}
rdata.Complete();
rdata.Respond("OK");
}
}
private static readonly string Help =
"<html>"
+ "<head><title>Remote Command Usage</title></head>"
+ "<body>"
+ "<p>Supported commands are:</p>"
+ "<dl>"
+ "<dt>move/avatar-name/x/y/z</dt>"
+ "<dd>moves the specified avatar to another location</dd>"
+ "</dl>"
+ "</body>"
+ "</html>"
;
}
}

View File

@ -1,228 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.IO;
using System.Xml.Serialization;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.ApplicationPlugins.Rest.Regions
{
public partial class RestRegionPlugin : RestPlugin
{
#region GET methods
public string GetHandler(string request, string path, string param,
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
// foreach (string h in httpRequest.Headers.AllKeys)
// foreach (string v in httpRequest.Headers.GetValues(h))
// m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v);
MsgID = RequestID;
m_log.DebugFormat("{0} GET path {1} param {2}", MsgID, path, param);
try
{
// param empty: regions list
if (String.IsNullOrEmpty(param)) return GetHandlerRegions(httpResponse);
// param not empty: specific region
return GetHandlerRegion(httpResponse, param);
}
catch (Exception e)
{
return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "GET", e);
}
}
public string GetHandlerRegions(IOSHttpResponse httpResponse)
{
RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
rxw.WriteStartElement(String.Empty, "regions", String.Empty);
foreach (Scene s in App.SceneManager.Scenes)
{
rxw.WriteStartElement(String.Empty, "uuid", String.Empty);
rxw.WriteString(s.RegionInfo.RegionID.ToString());
rxw.WriteEndElement();
}
rxw.WriteEndElement();
return rxw.ToString();
}
protected string ShortRegionInfo(string key, string value)
{
RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
if (String.IsNullOrEmpty(value) ||
String.IsNullOrEmpty(key)) return null;
rxw.WriteStartElement(String.Empty, "region", String.Empty);
rxw.WriteStartElement(String.Empty, key, String.Empty);
rxw.WriteString(value);
rxw.WriteEndDocument();
return rxw.ToString();
}
public string GetHandlerRegion(IOSHttpResponse httpResponse, string param)
{
// be resilient and don't get confused by a terminating '/'
param = param.TrimEnd(new char[]{'/'});
string[] comps = param.Split('/');
UUID regionID = (UUID)comps[0];
m_log.DebugFormat("{0} GET region UUID {1}", MsgID, regionID.ToString());
if (UUID.Zero == regionID) throw new Exception("missing region ID");
Scene scene = null;
App.SceneManager.TryGetScene(regionID, out scene);
if (null == scene) return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound,
"GET", "cannot find region {0}", regionID.ToString());
RegionDetails details = new RegionDetails(scene.RegionInfo);
// m_log.DebugFormat("{0} GET comps {1}", MsgID, comps.Length);
// for (int i = 0; i < comps.Length; i++) m_log.DebugFormat("{0} GET comps[{1}] >{2}<", MsgID, i, comps[i]);
if (1 == comps.Length)
{
// complete region details requested
RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
XmlSerializer xs = new XmlSerializer(typeof(RegionDetails));
xs.Serialize(rxw, details, _xmlNs);
return rxw.ToString();
}
if (2 == comps.Length)
{
string resp = ShortRegionInfo(comps[1], details[comps[1]]);
if (null != resp) return resp;
// m_log.DebugFormat("{0} GET comps advanced: >{1}<", MsgID, comps[1]);
// check for {terrain,stats,prims}
switch (comps[1].ToLower())
{
case "terrain":
return RegionTerrain(httpResponse, scene);
case "stats":
return RegionStats(httpResponse, scene);
case "prims":
return RegionPrims(httpResponse, scene, Vector3.Zero, Vector3.Zero);
}
}
if (3 == comps.Length)
{
switch (comps[1].ToLower())
{
case "prims":
string[] subregion = comps[2].Split(',');
if (subregion.Length == 6)
{
Vector3 min, max;
try
{
min = new Vector3((float)Double.Parse(subregion[0], Culture.NumberFormatInfo), (float)Double.Parse(subregion[1], Culture.NumberFormatInfo), (float)Double.Parse(subregion[2], Culture.NumberFormatInfo));
max = new Vector3((float)Double.Parse(subregion[3], Culture.NumberFormatInfo), (float)Double.Parse(subregion[4], Culture.NumberFormatInfo), (float)Double.Parse(subregion[5], Culture.NumberFormatInfo));
}
catch (Exception)
{
return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest,
"GET", "invalid subregion parameter");
}
return RegionPrims(httpResponse, scene, min, max);
}
else
{
return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest,
"GET", "invalid subregion parameter");
}
}
}
return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest,
"GET", "too many parameters {0}", param);
}
#endregion GET methods
protected string RegionTerrain(IOSHttpResponse httpResponse, Scene scene)
{
httpResponse.SendChunked = true;
httpResponse.ContentType = "text/xml";
return scene.Heightmap.SaveToXmlString();
//return Failure(httpResponse, OSHttpStatusCode.ServerErrorNotImplemented,
// "GET", "terrain not implemented");
}
protected string RegionStats(IOSHttpResponse httpResponse, Scene scene)
{
int users = scene.GetRootAgentCount();
int objects = scene.Entities.Count - users;
RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
rxw.WriteStartElement(String.Empty, "region", String.Empty);
rxw.WriteStartElement(String.Empty, "stats", String.Empty);
rxw.WriteStartElement(String.Empty, "users", String.Empty);
rxw.WriteString(users.ToString());
rxw.WriteEndElement();
rxw.WriteStartElement(String.Empty, "objects", String.Empty);
rxw.WriteString(objects.ToString());
rxw.WriteEndElement();
rxw.WriteEndDocument();
return rxw.ToString();
}
protected string RegionPrims(IOSHttpResponse httpResponse, Scene scene, Vector3 min, Vector3 max)
{
httpResponse.SendChunked = true;
httpResponse.ContentType = "text/xml";
IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>();
if (serialiser != null)
serialiser.SavePrimsToXml2(scene, new StreamWriter(httpResponse.OutputStream), min, max);
return "";
}
}
}

View File

@ -1,136 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.IO;
using System.Xml.Serialization;
using OpenMetaverse;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.ApplicationPlugins.Rest.Regions
{
public partial class RestRegionPlugin : RestPlugin
{
#region GET methods
public string GetRegionInfoHandler(string request, string path, string param,
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
// foreach (string h in httpRequest.Headers.AllKeys)
// foreach (string v in httpRequest.Headers.GetValues(h))
// m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v);
MsgID = RequestID;
m_log.DebugFormat("{0} GET path {1} param {2}", MsgID, path, param);
try
{
// param empty: regions list
// if (String.IsNullOrEmpty(param))
return GetRegionInfoHandlerRegions(httpResponse);
// // param not empty: specific region
// return GetRegionInfoHandlerRegion(httpResponse, param);
}
catch (Exception e)
{
return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "GET", e);
}
}
public string GetRegionInfoHandlerRegions(IOSHttpResponse httpResponse)
{
RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
// regions info
rxw.WriteStartElement(String.Empty, "regions", String.Empty);
{
// regions info: number of regions
rxw.WriteStartAttribute(String.Empty, "number", String.Empty);
rxw.WriteValue(App.SceneManager.Scenes.Count);
rxw.WriteEndAttribute();
// regions info: max number of regions
rxw.WriteStartAttribute(String.Empty, "max", String.Empty);
if (App.ConfigSource.Source.Configs["RemoteAdmin"] != null)
{
rxw.WriteValue(App.ConfigSource.Source.Configs["RemoteAdmin"].GetInt("region_limit", -1));
}
else
{
rxw.WriteValue(-1);
}
rxw.WriteEndAttribute();
// regions info: region
foreach (Scene s in App.SceneManager.Scenes)
{
rxw.WriteStartElement(String.Empty, "region", String.Empty);
rxw.WriteStartAttribute(String.Empty, "uuid", String.Empty);
rxw.WriteString(s.RegionInfo.RegionID.ToString());
rxw.WriteEndAttribute();
rxw.WriteStartAttribute(String.Empty, "name", String.Empty);
rxw.WriteString(s.RegionInfo.RegionName);
rxw.WriteEndAttribute();
rxw.WriteStartAttribute(String.Empty, "x", String.Empty);
rxw.WriteValue(s.RegionInfo.RegionLocX);
rxw.WriteEndAttribute();
rxw.WriteStartAttribute(String.Empty, "y", String.Empty);
rxw.WriteValue(s.RegionInfo.RegionLocY);
rxw.WriteEndAttribute();
rxw.WriteStartAttribute(String.Empty, "external_hostname", String.Empty);
rxw.WriteString(s.RegionInfo.ExternalHostName);
rxw.WriteEndAttribute();
rxw.WriteStartAttribute(String.Empty, "ip", String.Empty);
rxw.WriteString(s.RegionInfo.InternalEndPoint.ToString());
rxw.WriteEndAttribute();
int users = s.GetRootAgentCount();
rxw.WriteStartAttribute(String.Empty, "avatars", String.Empty);
rxw.WriteValue(users);
rxw.WriteEndAttribute();
rxw.WriteStartAttribute(String.Empty, "objects", String.Empty);
rxw.WriteValue(s.Entities.Count - users);
rxw.WriteEndAttribute();
rxw.WriteEndElement();
}
}
return rxw.ToString();
}
#endregion GET methods
}
}

View File

@ -1,122 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.IO;
using OpenMetaverse;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.ApplicationPlugins.Rest.Regions
{
public partial class RestRegionPlugin : RestPlugin
{
#region POST methods
public string PostHandler(string request, string path, string param,
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
// foreach (string h in httpRequest.Headers.AllKeys)
// foreach (string v in httpRequest.Headers.GetValues(h))
// m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v);
MsgID = RequestID;
m_log.DebugFormat("{0} POST path {1} param {2}", MsgID, path, param);
try
{
// param empty: new region post
if (!IsGod(httpRequest))
// XXX: this needs to be turned into a FailureUnauthorized(...)
return Failure(httpResponse, OSHttpStatusCode.ClientErrorUnauthorized,
"GET", "you are not god");
if (String.IsNullOrEmpty(param)) return CreateRegion(httpRequest, httpResponse);
// Parse region ID and other parameters
param = param.TrimEnd(new char[] {'/'});
string[] comps = param.Split('/');
UUID regionID = (UUID) comps[0];
m_log.DebugFormat("{0} POST region UUID {1}", MsgID, regionID.ToString());
if (UUID.Zero == regionID) throw new Exception("missing region ID");
Scene scene = null;
App.SceneManager.TryGetScene(regionID, out scene);
if (null == scene)
return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound,
"POST", "cannot find region {0}", regionID.ToString());
if (2 == comps.Length)
{
// check for {prims}
switch (comps[1].ToLower())
{
case "prims":
return LoadPrims(request, httpRequest, httpResponse, scene);
}
}
return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound,
"POST", "url {0} not supported", param);
}
catch (Exception e)
{
return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "POST", e);
}
}
public string CreateRegion(IOSHttpRequest request, IOSHttpResponse response)
{
RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
rxw.WriteStartElement(String.Empty, "regions", String.Empty);
foreach (Scene s in App.SceneManager.Scenes)
{
rxw.WriteStartElement(String.Empty, "uuid", String.Empty);
rxw.WriteString(s.RegionInfo.RegionID.ToString());
rxw.WriteEndElement();
}
rxw.WriteEndElement();
return rxw.ToString();
}
public string LoadPrims(string requestBody, IOSHttpRequest request, IOSHttpResponse response, Scene scene)
{
IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>();
if (serialiser != null)
serialiser.LoadPrimsFromXml2(scene, new StringReader(requestBody), true);
return "";
}
#endregion POST methods
}
}

View File

@ -1,98 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Xml.Serialization;
using OpenMetaverse;
using OpenSim.Framework;
namespace OpenSim.ApplicationPlugins.Rest.Regions
{
[XmlRoot(ElementName="region", IsNullable = false)]
public class RegionDetails
{
public string region_name;
public string region_id;
public uint region_x;
public uint region_y;
public string region_owner;
public string region_owner_id;
public uint region_http_port;
public uint region_port;
public string region_server_uri;
public string region_external_hostname;
public RegionDetails()
{
}
public RegionDetails(RegionInfo regInfo)
{
region_name = regInfo.RegionName;
region_id = regInfo.RegionID.ToString();
region_x = regInfo.RegionLocX;
region_y = regInfo.RegionLocY;
region_owner_id = regInfo.EstateSettings.EstateOwner.ToString();
region_http_port = regInfo.HttpPort;
region_server_uri = regInfo.ServerURI;
region_external_hostname = regInfo.ExternalHostName;
Uri uri = new Uri(region_server_uri);
region_port = (uint)uri.Port;
}
public string this[string idx]
{
get
{
switch (idx.ToLower())
{
case "name":
return region_name;
case "id":
return region_id;
case "location":
return String.Format("<x>{0}</x><y>{1}</y>", region_x, region_y);
case "owner":
return region_owner;
case "owner_id":
return region_owner_id;
case "http_port":
return region_http_port.ToString();
case "server_uri":
return region_server_uri;
case "external_hostname":
case "hostname":
return region_external_hostname;
default:
return null;
}
}
}
}
}

View File

@ -1,11 +0,0 @@
<Addin id="OpenSim.ApplicationPlugins.Rest.Regions" version="0.1">
<Runtime>
<Import assembly="OpenSim.ApplicationPlugins.Rest.Regions.dll"/>
</Runtime>
<Dependencies>
<Addin id="OpenSim" version="0.5" />
</Dependencies>
<Extension path = "/OpenSim/Startup">
<Plugin id="RestRegions" type="OpenSim.ApplicationPlugins.Rest.Regions.RestRegionPlugin" />
</Extension>
</Addin>

View File

@ -1,94 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Xml.Serialization;
namespace OpenSim.ApplicationPlugins.Rest.Regions
{
public partial class RestRegionPlugin : RestPlugin
{
private static XmlSerializerNamespaces _xmlNs;
static RestRegionPlugin()
{
_xmlNs = new XmlSerializerNamespaces();
_xmlNs.Add(String.Empty, String.Empty);
}
#region overriding properties
public override string Name
{
get { return "REGION"; }
}
public override string ConfigName
{
get { return "RestRegionPlugin"; }
}
#endregion overriding properties
#region overriding methods
/// <summary>
/// This method is called by OpenSimMain immediately after loading the
/// plugin and after basic server setup, but before running any server commands.
/// </summary>
/// <remarks>
/// Note that entries MUST be added to the active configuration files before
/// the plugin can be enabled.
/// </remarks>
public override void Initialise(OpenSimBase openSim)
{
try
{
base.Initialise(openSim);
if (!IsEnabled)
{
//m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID);
return;
}
m_log.InfoFormat("{0} REST region plugin enabled", MsgID);
// add REST method handlers
AddRestStreamHandler("GET", "/regions/", GetHandler);
AddRestStreamHandler("POST", "/regions/", PostHandler);
AddRestStreamHandler("GET", "/regioninfo/", GetRegionInfoHandler);
}
catch (Exception e)
{
m_log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message);
m_log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString());
}
}
public override void Close()
{
}
#endregion overriding methods
}
}

View File

@ -1,417 +0,0 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Xml;
using log4net;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
namespace OpenSim.ApplicationPlugins.Rest
{
public abstract class RestPlugin : IApplicationPlugin
{
#region properties
protected static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IConfig _config; // Configuration source: Rest Plugins
private IConfig _pluginConfig; // Configuration source: Plugin specific
private OpenSimBase _app; // The 'server'
private BaseHttpServer _httpd; // The server's RPC interface
private string _prefix; // URL prefix below
// which all REST URLs
// are living
// private StringWriter _sw = null;
// private RestXmlWriter _xw = null;
private string _godkey;
private int _reqk;
[ThreadStatic]
private static string _threadRequestID = String.Empty;
/// <summary>
/// Return an ever increasing request ID for logging
/// </summary>
protected string RequestID
{
get { return _reqk++.ToString(); }
set { _reqk = Convert.ToInt32(value); }
}
/// <summary>
/// Thread-constant message IDs for logging.
/// </summary>
protected string MsgID
{
get { return String.Format("[REST-{0}] #{1}", Name, _threadRequestID); }
set { _threadRequestID = value; }
}
/// <summary>
/// Returns true if Rest Plugins are enabled.
/// </summary>
public bool PluginsAreEnabled
{
get { return null != _config; }
}
/// <summary>
/// Returns true if specific Rest Plugin is enabled.
/// </summary>
public bool IsEnabled
{
get
{
return (null != _pluginConfig) && _pluginConfig.GetBoolean("enabled", false);
}
}
/// <summary>
/// OpenSimMain application
/// </summary>
public OpenSimBase App
{
get { return _app; }
}
/// <summary>
/// RPC server
/// </summary>
public BaseHttpServer HttpServer
{
get { return _httpd; }
}
/// <summary>
/// URL prefix to use for all REST handlers
/// </summary>
public string Prefix
{
get { return _prefix; }
}
/// <summary>
/// Access to GOD password string
/// </summary>
protected string GodKey
{
get { return _godkey; }
}
/// <summary>
/// Configuration of the plugin
/// </summary>
public IConfig Config
{
get { return _pluginConfig; }
}
/// <summary>
/// Name of the plugin
/// </summary>
public abstract string Name { get; }
/// <summary>
/// Return the config section name
/// </summary>
public abstract string ConfigName { get; }
// public XmlTextWriter XmlWriter
// {
// get
// {
// if (null == _xw)
// {
// _sw = new StringWriter();
// _xw = new RestXmlWriter(_sw);
// _xw.Formatting = Formatting.Indented;
// }
// return _xw;
// }
// }
// public string XmlWriterResult
// {
// get
// {
// _xw.Flush();
// _xw.Close();
// _xw = null;
// return _sw.ToString();
// }
// }
#endregion properties
#region methods
// TODO: required by IPlugin, but likely not at all right
private string m_version = "0.0";
public string Version
{
get { return m_version; }
}
public void Initialise()
{
m_log.Info("[RESTPLUGIN]: " + Name + " cannot be default-initialized!");
throw new PluginNotInitialisedException(Name);
}
/// <summary>
/// This method is called by OpenSimMain immediately after loading the
/// plugin and after basic server setup, but before running any server commands.
/// </summary>
/// <remarks>
/// Note that entries MUST be added to the active configuration files before
/// the plugin can be enabled.
/// </remarks>
public virtual void Initialise(OpenSimBase openSim)
{
RequestID = "0";
MsgID = RequestID;
try
{
if ((_config = openSim.ConfigSource.Source.Configs["RestPlugins"]) == null)
{
m_log.WarnFormat("{0} Rest Plugins not configured", MsgID);
return;
}
if (!_config.GetBoolean("enabled", false))
{
//m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID);
return;
}
_app = openSim;
_httpd = openSim.HttpServer;
// Retrieve GOD key value, if any.
_godkey = _config.GetString("god_key", String.Empty);
// Retrive prefix if any.
_prefix = _config.GetString("prefix", "/admin");
// Get plugin specific config
_pluginConfig = openSim.ConfigSource.Source.Configs[ConfigName];
m_log.InfoFormat("{0} Rest Plugins Enabled", MsgID);
}
catch (Exception e)
{
// we can safely ignore this, as it just means that
// the key lookup in Configs failed, which signals to
// us that noone is interested in our services...they
// don't know what they are missing out on...
// NOTE: Under the present OpenSimulator implementation it is
// not possible for the openSimulator pointer to be null. However
// were the implementation to be changed, this could
// result in a silent initialization failure. Harmless
// except for lack of function and lack of any
// diagnostic indication as to why. The same is true if
// the HTTP server reference is bad.
// We should at least issue a message...
m_log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message);
m_log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString());
}
}
public virtual void PostInitialise()
{
}
private List<RestStreamHandler> _handlers = new List<RestStreamHandler>();
private Dictionary<string, IHttpAgentHandler> _agents = new Dictionary<string, IHttpAgentHandler>();
/// <summary>
/// Add a REST stream handler to the underlying HTTP server.
/// </summary>
/// <param name="httpMethod">GET/PUT/POST/DELETE or
/// similar</param>
/// <param name="path">URL prefix</param>
/// <param name="method">RestMethod handler doing the actual work</param>
public virtual void AddRestStreamHandler(string httpMethod, string path, RestMethod method)
{
if (!IsEnabled) return;
if (!path.StartsWith(_prefix))
{
path = String.Format("{0}{1}", _prefix, path);
}
RestStreamHandler h = new RestStreamHandler(httpMethod, path, method);
_httpd.AddStreamHandler(h);
_handlers.Add(h);
m_log.DebugFormat("{0} Added REST handler {1} {2}", MsgID, httpMethod, path);
}
/// <summary>
/// Add a powerful Agent handler to the underlying HTTP
/// server.
/// </summary>
/// <param name="agentName">name of agent handler</param>
/// <param name="handler">agent handler method</param>
/// <returns>false when the plugin is disabled or the agent
/// handler could not be added. Any generated exceptions are
/// allowed to drop through to the caller, i.e. ArgumentException.
/// </returns>
public bool AddAgentHandler(string agentName, IHttpAgentHandler handler)
{
if (!IsEnabled) return false;
_agents.Add(agentName, handler);
// return _httpd.AddAgentHandler(agentName, handler);
return false;
}
/// <summary>
/// Remove a powerful Agent handler from the underlying HTTP
/// server.
/// </summary>
/// <param name="agentName">name of agent handler</param>
/// <param name="handler">agent handler method</param>
/// <returns>false when the plugin is disabled or the agent
/// handler could not be removed. Any generated exceptions are
/// allowed to drop through to the caller, i.e. KeyNotFound.
/// </returns>
public bool RemoveAgentHandler(string agentName, IHttpAgentHandler handler)
{
if (!IsEnabled) return false;
if (_agents[agentName] == handler)
{
_agents.Remove(agentName);
// return _httpd.RemoveAgentHandler(agentName, handler);
}
return false;
}
/// <summary>
/// Check whether the HTTP request came from god; that is, is
/// the god_key as configured in the config section supplied
/// via X-OpenSim-Godkey?
/// </summary>
/// <param name="request">HTTP request header</param>
/// <returns>true when the HTTP request came from god.</returns>
protected bool IsGod(IOSHttpRequest request)
{
string[] keys = request.Headers.GetValues("X-OpenSim-Godkey");
if (null == keys) return false;
// we take the last key supplied
return keys[keys.Length - 1] == _godkey;
}
/// <summary>
/// Checks wether the X-OpenSim-Password value provided in the
/// HTTP header is indeed the password on file for the avatar
/// specified by the UUID
/// </summary>
protected bool IsVerifiedUser(IOSHttpRequest request, UUID uuid)
{
// XXX under construction
return false;
}
/// <summary>
/// Clean up and remove all handlers that were added earlier.
/// </summary>
public virtual void Close()
{
foreach (RestStreamHandler h in _handlers)
{
_httpd.RemoveStreamHandler(h.HttpMethod, h.Path);
}
_handlers = null;
// foreach (KeyValuePair<string, IHttpAgentHandler> h in _agents)
// {
// _httpd.RemoveAgentHandler(h.Key, h.Value);
// }
_agents = null;
}
public virtual void Dispose()
{
Close();
}
/// <summary>
/// Return a failure message.
/// </summary>
/// <param name="method">origin of the failure message</param>
/// <param name="message">failure message</param>
/// <remarks>This should probably set a return code as
/// well. (?)</remarks>
protected string Failure(IOSHttpResponse response, OSHttpStatusCode status,
string method, string format, params string[] msg)
{
string m = String.Format(format, msg);
response.StatusCode = (int) status;
response.StatusDescription = m;
m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, m);
return String.Format("<error>{0}</error>", m);
}
/// <summary>
/// Return a failure message.
/// </summary>
/// <param name="method">origin of the failure message</param>
/// <param name="e">exception causing the failure message</param>
/// <remarks>This should probably set a return code as
/// well. (?)</remarks>
public string Failure(IOSHttpResponse response, OSHttpStatusCode status,
string method, Exception e)
{
string m = String.Format("exception occurred: {0}", e.Message);
response.StatusCode = (int) status;
response.StatusDescription = m;
m_log.DebugFormat("{0} {1} failed: {2}", MsgID, method, e.ToString());
m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, e.Message);
return String.Format("<error>{0}</error>", e.Message);
}
#endregion methods
}
}

View File

@ -1,276 +0,0 @@
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:annotation>
<xsd:documentation xml:lang="en">
Open Simulator Export/Import XML schema
August 2008
</xsd:documentation>
</xsd:annotation>
<!-- WARNING!!!
This is currently a draft, it does not reflect
what is exported, nor what will be understood
on import. It is included as a working document
and this comment will be removed at such time as
the schema corresponds to reality.
-->
<!--
REST-related information
Inventory data is always framed by an
inventory element. Consists of zero or
more elements representing either folders
or items within those folders. The inventory
element represents the "real" root folder.
-->
<xsd:element name="inventory" type="inventory_ct" />
<!--
The inventory complex type is just an arbitrary
sequence of folders and items. In reality it is
typically just folders. Both item and folder
have corresponding complex types. It is distinct
from folders insofar as it has no other defining
attributes.
-->
<xsd:complexType name="inventory_ct">
<xsd:element name="folder" type="folder_ct" maxOccurs="unbounded"/>
<xsd:element name="item" type="item_ct" maxOccurs="unbounded" />
</xsd:complexType>
<xsd:complexType name="folder_ct">
<xsd:attribute name="UUID" type="uuid_st" />
<xsd:attribute name="name" type="name_st" />
<xsd:attribute name="type" type="folder_type_st" />
<xsd:attribute name="description" type="xsd:string" /> <!-- added -->
<xsd:attribute name="version" type="unsignedShort" />
<xsd:attribute name="owner" type="uuid_st" />
<xsd:attribute name="creator" type="uuid_st" /> <!-- added -->
<xsd:attribute name="creationdate" type="date_st" /> <!-- added -->
<xsd:attribute name="parent" type="uuid_st" />
<xsd:element name="permissions" type="permissions_ct" maxOccurs="unbounded" /> <!-- added -->
<xsd:element name="folder" type="folder_ct" maxOccurs="unbounded" />
<xsd:element name="item" type="item_ct" maxOccurs="unbounded" />
</xsd:complexType>
<xsd:complexType name="item_ct">
<xsd:attribute name="UUID" type="uuid_st" />
<xsd:attribute name="name" type="name_st" />
<xsd:attribute name="type" type="inventory_type_st" />
<xsd:attribute name="description" type="xsd:string" />
<xsd:attribute name="version" type="unsignedShort" /> <!-- added -->
<xsd:attribute name="owner" type="uuid_st" />
<xsd:attribute name="creator" type="uuid_st" />
<xsd:attribute name="creationdate" type="date_st" />
<xsd:attribute name="folder" type="uuid_st" />
<xsd:attribute name="groupid" type="uuid_st" />
<xsd:attribute name="groupowned" type="xsd:boolean" />
<xsd:attribute name="saletype" type="sale_st" />
<xsd:attribute name="saleprice" type="xsd:decimal" />
<xsd:element name="permissions" type="permissions_ct" maxOccurs="unbounded" />
</xsd:complexType>
<xsd:complexType name="asset_ct">
<xsd:attribute name="UUID" type="uuid_st" />
<xsd:attribute name="name" type="name_st" />
<xsd:attribute name="type" type="asset_type_st" />
<xsd:attribute name="description" type="xsd:string" />
<xsd:attribute name="version" type="unsignedShort" /> <!-- added -->
<xsd:attribute name="owner" type="uuid_st" />
<xsd:attribute name="creator" type="uuid_st" />
<xsd:attribute name="creationdate" type="date_st" />
<xsd:attribute name="temporary" type="xsd:boolean" />
<xsd:attribute name="local" type="xsd:boolean" />
<xsd:attribute name="inline" type="xsd:boolean" />
</xsd:complexType>
<!-- Constrained Simple Data types -->
<!--
We need to specify name as a simple type because on
some platforms it is constrained by a certain length
limitation. For completeness we indicate that whitespace
should be preserved exactly as specified.
-->
<xsd:simpleType name="name_st">
<xsd:restriction base="xsd:string">
<whiteSpace value="preserve" />
<minLength value="0" />
<maxLength value="64" />
</xsd:restriction>
</xsd:simpleType>
<!--
Type information in the folder is meant to indicate
the preferred asset type for this folder. As such, that
currently corresponds to the type values allowed for
assets, however that is not mandated, so for
now at least I'll represent this as a distinct
enumeration.
This seems inappropriate; it seems like the folder's
content should reflect the InventoryType classifications
rather than the asset types.
-->
<xsd:simpleType name="folder_type_st">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Texture" />
<xsd:enumeration value="Sound" />
<xsd:enumeration value="CallingCard" />
<xsd:enumeration value="Landmark" />
<xsd:enumeration value="Script" />
<xsd:enumeration value="Clothing" />
<xsd:enumeration value="Object" />
<xsd:enumeration value="Notecard" />
<xsd:enumeration value="LSLText" />
<xsd:enumeration value="LSLByteCode" />
<xsd:enumeration value="TextureTGA" />
<xsd:enumeration value="BodyPart" />
<xsd:enumeration value="SoundWAV" />
<xsd:enumeration value="ImageTGA" />
<xsd:enumeration value="ImageJPEG" />
<xsd:enumeration value="Animation" />
<xsd:enumeration value="Gesture" />
<xsd:enumeration value="Simstate" />
<xsd:enumeration value="Unknown" />
<xsd:enumeration value="LostAndFoundFolder" />
<xsd:enumeration value="SnapshotFolder" />
<xsd:enumeration value="TrashFolder" />
<xsd:enumeration value="Folder" />
<xsd:enumeration value="RootFolder" />
</xsd:restriction>
</xsd:simpleType>
<!--
Inventory item type designates an asset class, rather
than a specific asset type. For example, "SnapShot"
might include a number of asset types such as JPEG,
TGA, etc.. This is not a consistent interpretation,
classifications such as LostAndFound are meta-types
relative to asset classes.
These types should be abstract and not be tied to a
specific platform. A world's import facility should be
responsible for mapping these to meaningful internal
representations.
These types were based on information in:
libsecondlife/InventoryManager.cs
-->
<xsd:simpleType name="inventory_type_st">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Texture" />
<xsd:enumeration value="Sound" />
<xsd:enumeration value="CallingCard" />
<xsd:enumeration value="Landmark" />
<xsd:enumeration value="Script" />
<xsd:enumeration value="Clothing" />
<xsd:enumeration value="Object" />
<xsd:enumeration value="Notecard" />
<xsd:enumeration value="LSL" />
<xsd:enumeration value="LSLBytecode" />
<xsd:enumeration value="TextureTGA" />
<xsd:enumeration value="BodyPart" />
<xsd:enumeration value="Snapshot" />
<xsd:enumeration value="Attachment" />
<xsd:enumeration value="Wearable" />
<xsd:enumeration value="Animation" />
<xsd:enumeration value="Gesture" />
<xsd:enumeration value="Folder" />
<xsd:enumeration value="Unknown" />
<xsd:enumeration value="LostAndFound" />
<xsd:enumeration value="Trash" />
<xsd:enumeration value="Root" />
</xsd:restriction>
</xsd:simpleType>
<!--
The asset types seem to be even more disarrayed than
the inventory types. It seems to be little more than
a reiteration of the inventory type information,
which adds little or nothing to the overall data
model.
Of course, given that these are drawn from the
libsecondlife definitions, we aren't at liberty to
simply redefine them in place. But the XML definitions
here could be made more useful.
These types were based on information in:
libsecondlife/AssetManager.cs
-->
<xsd:simpleType name="asset_type_st">
<xsd:restriction base="xsd:string">
<xsd:enumeration value="Texture" />
<xsd:enumeration value="Sound" />
<xsd:enumeration value="CallingCard" />
<xsd:enumeration value="Landmark" />
<xsd:enumeration value="Script" />
<xsd:enumeration value="Clothing" />
<xsd:enumeration value="Object" />
<xsd:enumeration value="Notecard" />
<xsd:enumeration value="LSLText" />
<xsd:enumeration value="LSLByteCode" />
<xsd:enumeration value="TextureTGA" />
<xsd:enumeration value="BodyPart" />
<xsd:enumeration value="SoundWAV" />
<xsd:enumeration value="ImageTGA" />
<xsd:enumeration value="ImageJPEG" />
<xsd:enumeration value="Animation" />
<xsd:enumeration value="Gesture" />
<xsd:enumeration value="Simstate" />
<xsd:enumeration value="Unknown" />
<xsd:enumeration value="LostAndFoundFolder" />
<xsd:enumeration value="SnapshotFolder" />
<xsd:enumeration value="TrashFolder" />
<xsd:enumeration value="Folder" />
<xsd:enumeration value="RootFolder" />
</xsd:restriction>
</xsd:simpleType>
<!-- This is describing the apparent form of a UUID. If
we ever want a more metaphysical definition we'll
need to add to it.
-->
<xsd:simpleType name="uuid_st">
<xsd:restriction base="xsd:string">
<xsd:pattern value="[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"/>
</xsd:restriction>
</xsd:simpleType>
<!-- This constrains the date representation. Currently
it is simply an integer representing the elapsed
?? since ??.
-->
<xsd:simpleType name="date_st">
<xsd:restriction base="xsd:positiveInteger">
</xsd:restriction>
</xsd:simpleType>
<!-- This constrains the representation of sale price.
Currently it is a simple decimal with no unit
specified.
Issues: interoperability.
-->
<xsd:simpleType name="sale_st">
<xsd:restriction base="xsd:decimal">
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>

View File

@ -50,6 +50,11 @@ namespace OpenSim.Data.MySQL
get { return GetType().Assembly; }
}
/// <summary>
/// Number of days that must pass before we update the access time on an asset when it has been fetched.
/// </summary>
private const int DaysBetweenAccessTimeUpdates = 30;
private bool m_enableCompression = false;
private string m_connectionString;
private object m_dbLock = new object();
@ -133,10 +138,10 @@ namespace OpenSim.Data.MySQL
dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand(
"SELECT name, description, asset_type, local, temporary, asset_flags, creator_id, data FROM xassetsmeta JOIN xassetsdata ON xassetsmeta.hash = xassetsdata.hash WHERE id=?id",
"SELECT Name, Description, AccessTime, AssetType, Local, Temporary, AssetFlags, CreatorID, Data FROM XAssetsMeta JOIN XAssetsData ON XAssetsMeta.Hash = XAssetsData.Hash WHERE ID=?ID",
dbcon))
{
cmd.Parameters.AddWithValue("?id", assetID.ToString());
cmd.Parameters.AddWithValue("?ID", assetID.ToString());
try
{
@ -144,18 +149,18 @@ namespace OpenSim.Data.MySQL
{
if (dbReader.Read())
{
asset = new AssetBase(assetID, (string)dbReader["name"], (sbyte)dbReader["asset_type"], dbReader["creator_id"].ToString());
asset.Data = (byte[])dbReader["data"];
asset.Description = (string)dbReader["description"];
asset = new AssetBase(assetID, (string)dbReader["Name"], (sbyte)dbReader["AssetType"], dbReader["CreatorID"].ToString());
asset.Data = (byte[])dbReader["Data"];
asset.Description = (string)dbReader["Description"];
string local = dbReader["local"].ToString();
string local = dbReader["Local"].ToString();
if (local.Equals("1") || local.Equals("true", StringComparison.InvariantCultureIgnoreCase))
asset.Local = true;
else
asset.Local = false;
asset.Temporary = Convert.ToBoolean(dbReader["temporary"]);
asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]);
asset.Temporary = Convert.ToBoolean(dbReader["Temporary"]);
asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]);
if (m_enableCompression)
{
@ -171,12 +176,14 @@ namespace OpenSim.Data.MySQL
// asset.ID, asset.Name, asset.Data.Length, compressedLength);
}
}
UpdateAccessTime(asset.Metadata, (int)dbReader["AccessTime"]);
}
}
}
catch (Exception e)
{
m_log.Error("[MYSQL XASSET DATA]: MySql failure fetching asset " + assetID + ": " + e.Message);
m_log.Error(string.Format("[MYSQL XASSET DATA]: Failure fetching asset {0}", assetID), e);
}
}
}
@ -242,23 +249,23 @@ namespace OpenSim.Data.MySQL
{
using (MySqlCommand cmd =
new MySqlCommand(
"replace INTO xassetsmeta(id, hash, name, description, asset_type, local, temporary, create_time, access_time, asset_flags, creator_id)" +
"VALUES(?id, ?hash, ?name, ?description, ?asset_type, ?local, ?temporary, ?create_time, ?access_time, ?asset_flags, ?creator_id)",
"replace INTO XAssetsMeta(ID, Hash, Name, Description, AssetType, Local, Temporary, CreateTime, AccessTime, AssetFlags, CreatorID)" +
"VALUES(?ID, ?Hash, ?Name, ?Description, ?AssetType, ?Local, ?Temporary, ?CreateTime, ?AccessTime, ?AssetFlags, ?CreatorID)",
dbcon))
{
// create unix epoch time
int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow);
cmd.Parameters.AddWithValue("?id", asset.ID);
cmd.Parameters.AddWithValue("?hash", hash);
cmd.Parameters.AddWithValue("?name", assetName);
cmd.Parameters.AddWithValue("?description", assetDescription);
cmd.Parameters.AddWithValue("?asset_type", asset.Type);
cmd.Parameters.AddWithValue("?local", asset.Local);
cmd.Parameters.AddWithValue("?temporary", asset.Temporary);
cmd.Parameters.AddWithValue("?create_time", now);
cmd.Parameters.AddWithValue("?access_time", now);
cmd.Parameters.AddWithValue("?creator_id", asset.Metadata.CreatorID);
cmd.Parameters.AddWithValue("?asset_flags", (int)asset.Flags);
cmd.Parameters.AddWithValue("?ID", asset.ID);
cmd.Parameters.AddWithValue("?Hash", hash);
cmd.Parameters.AddWithValue("?Name", assetName);
cmd.Parameters.AddWithValue("?Description", assetDescription);
cmd.Parameters.AddWithValue("?AssetType", asset.Type);
cmd.Parameters.AddWithValue("?Local", asset.Local);
cmd.Parameters.AddWithValue("?Temporary", asset.Temporary);
cmd.Parameters.AddWithValue("?CreateTime", now);
cmd.Parameters.AddWithValue("?AccessTime", now);
cmd.Parameters.AddWithValue("?CreatorID", asset.Metadata.CreatorID);
cmd.Parameters.AddWithValue("?AssetFlags", (int)asset.Flags);
cmd.ExecuteNonQuery();
}
}
@ -278,11 +285,11 @@ namespace OpenSim.Data.MySQL
{
using (MySqlCommand cmd =
new MySqlCommand(
"INSERT INTO xassetsdata(hash, data) VALUES(?hash, ?data)",
"INSERT INTO XAssetsData(Hash, Data) VALUES(?Hash, ?Data)",
dbcon))
{
cmd.Parameters.AddWithValue("?hash", hash);
cmd.Parameters.AddWithValue("?data", asset.Data);
cmd.Parameters.AddWithValue("?Hash", hash);
cmd.Parameters.AddWithValue("?Data", asset.Data);
cmd.ExecuteNonQuery();
}
}
@ -303,41 +310,49 @@ namespace OpenSim.Data.MySQL
}
}
// private void UpdateAccessTime(AssetBase asset)
// {
// lock (m_dbLock)
// {
// using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
// {
// dbcon.Open();
// MySqlCommand cmd =
// new MySqlCommand("update assets set access_time=?access_time where id=?id",
// dbcon);
//
// // need to ensure we dispose
// try
// {
// using (cmd)
// {
// // create unix epoch time
// int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow);
// cmd.Parameters.AddWithValue("?id", asset.ID);
// cmd.Parameters.AddWithValue("?access_time", now);
// cmd.ExecuteNonQuery();
// cmd.Dispose();
// }
// }
// catch (Exception e)
// {
// m_log.ErrorFormat(
// "[ASSETS DB]: " +
// "MySql failure updating access_time for asset {0} with name {1}" + Environment.NewLine + e.ToString()
// + Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name);
// }
// }
// }
//
// }
/// <summary>
/// Updates the access time of the asset if it was accessed above a given threshhold amount of time.
/// </summary>
/// <remarks>
/// This gives us some insight into assets which haven't ben accessed for a long period. This is only done
/// over the threshold time to avoid excessive database writes as assets are fetched.
/// </remarks>
/// <param name='asset'></param>
/// <param name='accessTime'></param>
private void UpdateAccessTime(AssetMetadata assetMetadata, int accessTime)
{
DateTime now = DateTime.UtcNow;
if ((now - Utils.UnixTimeToDateTime(accessTime)).TotalDays < DaysBetweenAccessTimeUpdates)
return;
lock (m_dbLock)
{
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
MySqlCommand cmd =
new MySqlCommand("update XAssetsMeta set AccessTime=?AccessTime where ID=?ID", dbcon);
try
{
using (cmd)
{
// create unix epoch time
cmd.Parameters.AddWithValue("?ID", assetMetadata.ID);
cmd.Parameters.AddWithValue("?AccessTime", (int)Utils.DateTimeToUnixTime(now));
cmd.ExecuteNonQuery();
}
}
catch (Exception e)
{
m_log.ErrorFormat(
"[XASSET MYSQL DB]: Failure updating access_time for asset {0} with name {1}",
assetMetadata.ID, assetMetadata.Name);
}
}
}
}
/// <summary>
/// We assume we already have the m_dbLock.
@ -353,9 +368,9 @@ namespace OpenSim.Data.MySQL
bool exists = false;
using (MySqlCommand cmd = new MySqlCommand("SELECT hash FROM xassetsdata WHERE hash=?hash", dbcon))
using (MySqlCommand cmd = new MySqlCommand("SELECT Hash FROM XAssetsData WHERE Hash=?Hash", dbcon))
{
cmd.Parameters.AddWithValue("?hash", hash);
cmd.Parameters.AddWithValue("?Hash", hash);
try
{
@ -395,9 +410,9 @@ namespace OpenSim.Data.MySQL
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand("SELECT id FROM xassetsmeta WHERE id=?id", dbcon))
using (MySqlCommand cmd = new MySqlCommand("SELECT ID FROM XAssetsMeta WHERE ID=?ID", dbcon))
{
cmd.Parameters.AddWithValue("?id", uuid.ToString());
cmd.Parameters.AddWithValue("?ID", uuid.ToString());
try
{
@ -412,8 +427,7 @@ namespace OpenSim.Data.MySQL
}
catch (Exception e)
{
m_log.ErrorFormat(
"[XASSETS DB]: MySql failure fetching asset {0}" + Environment.NewLine + e.ToString(), uuid);
m_log.Error(string.Format("[XASSETS DB]: MySql failure fetching asset {0}", uuid), e);
}
}
}
@ -422,6 +436,7 @@ namespace OpenSim.Data.MySQL
return assetExists;
}
/// <summary>
/// Returns a list of AssetMetadata objects. The list is a subset of
/// the entire data set offset by <paramref name="start" /> containing
@ -439,7 +454,7 @@ namespace OpenSim.Data.MySQL
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
{
dbcon.Open();
MySqlCommand cmd = new MySqlCommand("SELECT name,description,asset_type,temporary,id,asset_flags,creator_id FROM xassetsmeta LIMIT ?start, ?count", dbcon);
MySqlCommand cmd = new MySqlCommand("SELECT Name, Description, AccessTime, AssetType, Temporary, ID, AssetFlags, CreatorID FROM XAssetsMeta LIMIT ?start, ?count", dbcon);
cmd.Parameters.AddWithValue("?start", start);
cmd.Parameters.AddWithValue("?count", count);
@ -450,17 +465,19 @@ namespace OpenSim.Data.MySQL
while (dbReader.Read())
{
AssetMetadata metadata = new AssetMetadata();
metadata.Name = (string)dbReader["name"];
metadata.Description = (string)dbReader["description"];
metadata.Type = (sbyte)dbReader["asset_type"];
metadata.Temporary = Convert.ToBoolean(dbReader["temporary"]); // Not sure if this is correct.
metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]);
metadata.FullID = DBGuid.FromDB(dbReader["id"]);
metadata.CreatorID = dbReader["creator_id"].ToString();
metadata.Name = (string)dbReader["Name"];
metadata.Description = (string)dbReader["Description"];
metadata.Type = (sbyte)dbReader["AssetType"];
metadata.Temporary = Convert.ToBoolean(dbReader["Temporary"]); // Not sure if this is correct.
metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]);
metadata.FullID = DBGuid.FromDB(dbReader["ID"]);
metadata.CreatorID = dbReader["CreatorID"].ToString();
// We'll ignore this for now - it appears unused!
// metadata.SHA1 = dbReader["hash"]);
UpdateAccessTime(metadata, (int)dbReader["AccessTime"]);
retList.Add(metadata);
}
}
@ -485,9 +502,9 @@ namespace OpenSim.Data.MySQL
{
dbcon.Open();
using (MySqlCommand cmd = new MySqlCommand("delete from xassetsmeta where id=?id", dbcon))
using (MySqlCommand cmd = new MySqlCommand("delete from XAssetsMeta where ID=?ID", dbcon))
{
cmd.Parameters.AddWithValue("?id", id);
cmd.Parameters.AddWithValue("?ID", id);
cmd.ExecuteNonQuery();
}

View File

@ -3,24 +3,24 @@
BEGIN;
CREATE TABLE `xassetsmeta` (
`id` char(36) NOT NULL,
`hash` binary(32) NOT NULL,
`name` varchar(64) NOT NULL,
`description` varchar(64) NOT NULL,
`asset_type` tinyint(4) NOT NULL,
`local` tinyint(1) NOT NULL,
`temporary` tinyint(1) NOT NULL,
`create_time` int(11) NOT NULL,
`access_time` int(11) NOT NULL,
`asset_flags` int(11) NOT NULL,
`creator_id` varchar(128) NOT NULL,
CREATE TABLE `XAssetsMeta` (
`ID` char(36) NOT NULL,
`Hash` binary(32) NOT NULL,
`Name` varchar(64) NOT NULL,
`Description` varchar(64) NOT NULL,
`AssetType` tinyint(4) NOT NULL,
`Local` tinyint(1) NOT NULL,
`Temporary` tinyint(1) NOT NULL,
`CreateTime` int(11) NOT NULL,
`AccessTime` int(11) NOT NULL,
`AssetFlags` int(11) NOT NULL,
`CreatorID` varchar(128) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1';
CREATE TABLE `xassetsdata` (
`hash` binary(32) NOT NULL,
`data` longblob NOT NULL,
CREATE TABLE `XAssetsData` (
`Hash` binary(32) NOT NULL,
`Data` longblob NOT NULL,
PRIMARY KEY (`hash`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1';

View File

@ -180,7 +180,7 @@ namespace OpenSim.Framework
/// Validate the key used for storing separate data stores.
/// </summary>
/// <param name='key'></param>
private static void ValidateKey(string key)
public static void ValidateKey(string key)
{
if (key.Length < MIN_STORE_NAME_LENGTH)
throw new Exception("Minimum store name length is " + MIN_STORE_NAME_LENGTH);

View File

@ -25,48 +25,74 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
namespace OpenSim.ApplicationPlugins.Rest
namespace OpenSim.Framework
{
public class RestXmlWriter: XmlTextWriter
/// <summary>
/// This class stores and retrieves dynamic objects.
/// </summary>
/// <remarks>
/// Experimental - DO NOT USE.
/// </remarks>
public class DOMap
{
private StringWriter m_sw = null;
private IDictionary<string, object> m_map;
public RestXmlWriter(StringWriter sw) : base(sw)
public void Add(string key, object dynObj)
{
m_sw = sw;
Formatting = Formatting.Indented;
DAMap.ValidateKey(key);
lock (this)
{
if (m_map == null)
m_map = new Dictionary<string, object>();
m_map.Add(key, dynObj);
}
}
public RestXmlWriter(TextWriter textWriter) : base(textWriter)
public bool ContainsKey(string key)
{
return Get(key) != null;
}
public RestXmlWriter(Stream stream)
: this(stream, Encoding.UTF8)
/// <summary>
/// Get a dynamic object
/// </summary>
/// <remarks>
/// Not providing an index method so that users can't casually overwrite each other's objects.
/// </remarks>
/// <param name='key'></param>
public object Get(string key)
{
lock (this)
{
if (m_map == null)
return null;
else
return m_map[key];
}
}
public RestXmlWriter(Stream stream, Encoding enc) : base(stream, enc)
public bool Remove(string key)
{
}
public override void WriteStartDocument()
{
}
public override void WriteStartDocument(bool standalone)
{
}
public override string ToString()
{
Flush();
Close();
return m_sw.ToString();
lock (this)
{
if (m_map == null)
return false;
else
return m_map.Remove(key);
}
}
}
}

View File

@ -55,6 +55,13 @@ namespace OpenSim.Region.Framework.Interfaces
/// <returns>Land object at the point supplied</returns>
ILandObject GetLandObject(float x, float y);
/// <summary>
/// Get the parcel at the specified point
/// </summary>
/// <param name="position">Vector where x and y components are between 0 and 256. z component is ignored.</param>
/// <returns>Land object at the point supplied</returns>
ILandObject GetLandObject(Vector3 position);
/// <summary>
/// Get the parcels near the specified point
/// </summary>

View File

@ -218,7 +218,7 @@ namespace OpenSim.Framework
Console.WriteLine ("Looking for updates...");
Repositories.UpdateAllRepositories (ps);
Console.WriteLine ("Available add-in updates:");
bool found = false;
AddinRepositoryEntry[] entries = Repositories.GetAvailableUpdates();
foreach (AddinRepositoryEntry entry in entries)
@ -541,7 +541,7 @@ namespace OpenSim.Framework
{
list.AddRange(PluginRegistry.GetAddins());
}
catch(Exception e)
catch (Exception)
{
Addin[] x = xlist.ToArray(typeof(Addin)) as Addin[];
return x;

View File

@ -134,16 +134,6 @@ namespace OpenSim.Framework.Servers
/// </summary>
public virtual void Startup()
{
m_log.Info("[STARTUP]: Beginning startup processing");
m_log.Info("[STARTUP]: OpenSimulator version: " + m_version + Environment.NewLine);
// clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and
// the clr version number doesn't match the project version number under Mono.
//m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine);
m_log.InfoFormat(
"[STARTUP]: Operating system version: {0}, .NET platform {1}, {2}-bit\n",
Environment.OSVersion, Environment.OSVersion.Platform, Util.Is64BitProcess() ? "64" : "32");
StartupSpecific();
TimeSpan timeTaken = DateTime.Now - m_startuptime;

View File

@ -486,7 +486,9 @@ namespace OpenSim.Framework.Servers.HttpServer
{
try
{
SendHTML500(response);
byte[] buffer500 = SendHTML500(response);
response.Body.Write(buffer500,0,buffer500.Length);
response.Body.Close();
}
catch
{
@ -719,7 +721,15 @@ namespace OpenSim.Framework.Servers.HttpServer
catch (Exception e)
{
m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e);
SendHTML500(response);
try
{
byte[] buffer500 = SendHTML500(response);
response.Body.Write(buffer500, 0, buffer500.Length);
response.Body.Close();
}
catch
{
}
}
finally
{
@ -1747,6 +1757,7 @@ namespace OpenSim.Framework.Servers.HttpServer
response.ContentLength64 = buffer.Length;
response.ContentEncoding = Encoding.UTF8;
return buffer;
}
@ -1912,6 +1923,12 @@ namespace OpenSim.Framework.Servers.HttpServer
m_rpcHandlers.Remove(method);
}
public void RemoveJsonRPCHandler(string method)
{
lock(jsonRpcHandlers)
jsonRpcHandlers.Remove(method);
}
public bool RemoveLLSDHandler(string path, LLSDMethod handler)
{
lock (m_llsdHandlers)

View File

@ -141,6 +141,8 @@ namespace OpenSim.Framework.Servers.HttpServer
void RemoveXmlRPCHandler(string method);
void RemoveJsonRPCHandler(string method);
string GetHTTP404(string host);
string GetHTTP500();

View File

@ -113,6 +113,26 @@ namespace OpenSim.Framework.Servers
}
}
/// <summary>
/// Log information about the circumstances in which we're running (OpenSimulator version number, CLR details,
/// etc.).
/// </summary>
public void LogEnvironmentInformation()
{
// FIXME: This should be done down in ServerBase but we need to sort out and refactor the log4net
// XmlConfigurator calls first accross servers.
m_log.InfoFormat("[SERVER BASE]: Starting in {0}", m_startupDirectory);
m_log.InfoFormat("[SERVER BASE]: OpenSimulator version: {0}", m_version);
// clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and
// the clr version number doesn't match the project version number under Mono.
//m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine);
m_log.InfoFormat(
"[SERVER BASE]: Operating system version: {0}, .NET platform {1}, {2}-bit",
Environment.OSVersion, Environment.OSVersion.Platform, Util.Is64BitProcess() ? "64" : "32");
}
public void RegisterCommonAppenders(IConfig startupConfig)
{
ILoggerRepository repository = LogManager.GetRepository();

View File

@ -303,12 +303,12 @@ namespace OpenSim.Framework
// Clamp the maximum magnitude of a vector
public static Vector3 ClampV(Vector3 x, float max)
{
Vector3 ret = x;
float lenSq = x.LengthSquared();
if (lenSq > (max * max))
{
x = x / x.Length() * max;
}
return x;
}

View File

@ -159,6 +159,7 @@ namespace OpenSim
MainConsole.Instance = m_console;
LogEnvironmentInformation();
RegisterCommonAppenders(Config.Configs["Startup"]);
RegisterConsoleCommands();

View File

@ -134,10 +134,6 @@ namespace OpenSim
/// <param name="configSource"></param>
public OpenSimBase(IConfigSource configSource) : base()
{
// FIXME: This should be done down in ServerBase but we need to sort out and refactor the log4net
// XmlConfigurator calls first accross servers.
m_log.InfoFormat("[SERVER BASE]: Starting in {0}", m_startupDirectory);
LoadConfigSettings(configSource);
}

View File

@ -49,8 +49,10 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
private TestScene m_scene;
[SetUp]
public void SetUp()
public override void SetUp()
{
base.SetUp();
uint port = 9999;
uint sslPort = 9998;

View File

@ -4581,7 +4581,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
rinfopack.AgentData = new RegionInfoPacket.AgentDataBlock();
rinfopack.AgentData.AgentID = AgentId;
rinfopack.AgentData.SessionID = SessionId;
rinfopack.RegionInfo3 = new RegionInfoPacket.RegionInfo3Block[0];
OutPacket(rinfopack, ThrottleOutPacketType.Task);
}
@ -7069,7 +7069,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
if (handlerUpdatePrimFlags != null)
{
byte[] data = Pack.ToBytes();
// byte[] data = Pack.ToBytes();
// 46,47,48 are special positions within the packet
// This may change so perhaps we need a better way
// of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?)

View File

@ -278,25 +278,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
m_shouldCollectStats = false;
if (config != null)
{
if (config.Contains("enabled") && config.GetBoolean("enabled"))
{
if (config.Contains("collect_packet_headers"))
m_shouldCollectStats = config.GetBoolean("collect_packet_headers");
if (config.Contains("packet_headers_period_seconds"))
{
binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("region_stats_period_seconds"));
}
if (config.Contains("stats_dir"))
{
binStatsDir = config.GetString("stats_dir");
}
}
else
{
m_shouldCollectStats = false;
}
}
#endregion BinaryStats
m_shouldCollectStats = config.GetBoolean("Enabled", false);
binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("packet_headers_period_seconds", 300));
binStatsDir = config.GetString("stats_dir", ".");
m_aggregatedBWStats = config.GetBoolean("aggregatedBWStats", false);
}
#endregion BinaryStats
m_throttle = new TokenBucket(null, sceneThrottleBps);
ThrottleRates = new ThrottleRates(configSource);
@ -1266,8 +1253,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
static object binStatsLogLock = new object();
static string binStatsDir = "";
//for Aggregated In/Out BW logging
static bool m_aggregatedBWStats = false;
static long m_aggregatedBytesIn = 0;
static long m_aggregatedByestOut = 0;
static object aggBWStatsLock = new object();
public static long AggregatedLLUDPBytesIn
{
get { return m_aggregatedBytesIn; }
}
public static long AggregatedLLUDPBytesOut
{
get {return m_aggregatedByestOut;}
}
public static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size)
{
if (m_aggregatedBWStats)
{
lock (aggBWStatsLock)
{
if (incoming)
m_aggregatedBytesIn += size;
else
m_aggregatedByestOut += size;
}
}
if (!m_shouldCollectStats) return;
// Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size

View File

@ -289,21 +289,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
if (!Enabled)
return false;
if (AttachObjectInternal(sp, group, attachmentPt, silent, temp, append))
{
m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
return true;
}
return false;
return AttachObjectInternal(sp, group, attachmentPt, silent, temp, append);
}
private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp, bool append)
/// <summary>
/// Internal method which actually does all the work for attaching an object.
/// </summary>
/// <returns>The object attached.</returns>
/// <param name='sp'></param>
/// <param name='group'>The object to attach.</param>
/// <param name='attachmentPt'></param>
/// <param name='silent'></param>
/// <param name='temp'></param>
/// <param name='resumeScripts'>If true then scripts are resumed on the attached object.</param>
private bool AttachObjectInternal(
IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp, bool resumeScripts)
{
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})",
// group.Name, group.LocalId, sp.Name, attachmentPt, silent);
if (group.GetSittingAvatarsCount() != 0)
{
// m_log.WarnFormat(
@ -314,6 +315,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
}
List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
if (attachments.Contains(group))
{
// m_log.WarnFormat(
@ -374,6 +376,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp, append);
AttachToAgent(sp, group, attachmentPt, attachPos, silent);
if (resumeScripts)
{
// Fire after attach, so we don't get messy perms dialogs
// 4 == AttachedRez
group.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
group.ResumeScripts();
}
// Do this last so that event listeners have access to all the effects of the attachment
m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
}
return true;
@ -400,8 +413,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return null;
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2}",
// (AttachmentPoint)AttachmentPt, itemID, sp.Name);
// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2} in {3}",
// (AttachmentPoint)AttachmentPt, itemID, sp.Name, m_scene.Name);
bool append = (AttachmentPt & 0x80) != 0;
AttachmentPt &= 0x7f;
@ -533,6 +546,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return;
}
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Detaching object {0} {1} for {2} in {3}",
// so.Name, so.LocalId, sp.Name, m_scene.Name);
// Scripts MUST be snapshotted before the object is
// removed from the scene because doing otherwise will
// clobber the run flag
@ -854,61 +871,42 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
return null;
}
// Remove any previous attachments
List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
string previousAttachmentScriptedState = null;
// At the moment we can only deal with a single attachment
if (attachments.Count != 0)
DetachSingleAttachmentToInv(sp, attachments[0]);
lock (sp.AttachmentsSyncLock)
{
// m_log.DebugFormat(
// "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}",
// objatt.Name, sp.Name, attachmentPt, m_scene.Name);
// HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
objatt.HasGroupChanged = false;
bool tainted = false;
if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
tainted = true;
// HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
objatt.HasGroupChanged = false;
bool tainted = false;
if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
tainted = true;
// FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal
// course of events. If not, then it's probably not worth trying to recover the situation
// since this is more likely to trigger further exceptions and confuse later debugging. If
// exceptions can be thrown in expected error conditions (not NREs) then make this consistent
// since other normal error conditions will simply return false instead.
// This will throw if the attachment fails
try
{
AttachObjectInternal(sp, objatt, attachmentPt, false, false, append);
}
catch (Exception e)
{
m_log.ErrorFormat(
"[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
// Make sure the object doesn't stick around and bail
sp.RemoveAttachment(objatt);
m_scene.DeleteSceneObject(objatt, false);
return null;
}
if (tainted)
objatt.HasGroupChanged = true;
// Fire after attach, so we don't get messy perms dialogs
// 4 == AttachedRez
objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
objatt.ResumeScripts();
// Do this last so that event listeners have access to all the effects of the attachment
m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID);
return objatt;
// FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal
// course of events. If not, then it's probably not worth trying to recover the situation
// since this is more likely to trigger further exceptions and confuse later debugging. If
// exceptions can be thrown in expected error conditions (not NREs) then make this consistent
// since other normal error conditions will simply return false instead.
// This will throw if the attachment fails
try
{
AttachObjectInternal(sp, objatt, attachmentPt, false, false, append);
}
catch (Exception e)
{
m_log.ErrorFormat(
"[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
// Make sure the object doesn't stick around and bail
sp.RemoveAttachment(objatt);
m_scene.DeleteSceneObject(objatt, false);
return null;
}
if (tainted)
objatt.HasGroupChanged = true;
return objatt;
}
/// <summary>

View File

@ -228,6 +228,120 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
}
[Test]
public void TestWearAttachmentFromGround()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
Scene scene = CreateTestScene();
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
SceneObjectGroup so2 = SceneHelpers.AddSceneObject(scene, "att2", sp.UUID);
{
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "att1", sp.UUID);
m_numberOfAttachEventsFired = 0;
scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Default, false, false);
// Check status on scene presence
Assert.That(sp.HasAttachments(), Is.True);
List<SceneObjectGroup> attachments = sp.GetAttachments();
Assert.That(attachments.Count, Is.EqualTo(1));
SceneObjectGroup attSo = attachments[0];
Assert.That(attSo.Name, Is.EqualTo(so.Name));
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
Assert.That(attSo.IsAttachment);
Assert.That(attSo.UsesPhysics, Is.False);
Assert.That(attSo.IsTemporary, Is.False);
// Check item status
Assert.That(
sp.Appearance.GetAttachpoint(attSo.FromItemID),
Is.EqualTo((int)AttachmentPoint.LeftHand));
InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
Assert.That(attachmentItem, Is.Not.Null);
Assert.That(attachmentItem.Name, Is.EqualTo(so.Name));
InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object);
Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(2));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
}
// Test wearing a different attachment from the ground.
{
scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, false);
// Check status on scene presence
Assert.That(sp.HasAttachments(), Is.True);
List<SceneObjectGroup> attachments = sp.GetAttachments();
Assert.That(attachments.Count, Is.EqualTo(1));
SceneObjectGroup attSo = attachments[0];
Assert.That(attSo.Name, Is.EqualTo(so2.Name));
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
Assert.That(attSo.IsAttachment);
Assert.That(attSo.UsesPhysics, Is.False);
Assert.That(attSo.IsTemporary, Is.False);
// Check item status
Assert.That(
sp.Appearance.GetAttachpoint(attSo.FromItemID),
Is.EqualTo((int)AttachmentPoint.LeftHand));
InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
Assert.That(attachmentItem, Is.Not.Null);
Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name));
InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object);
Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
}
// Test rewearing an already worn attachment from ground. Nothing should happen.
{
scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, false);
// Check status on scene presence
Assert.That(sp.HasAttachments(), Is.True);
List<SceneObjectGroup> attachments = sp.GetAttachments();
Assert.That(attachments.Count, Is.EqualTo(1));
SceneObjectGroup attSo = attachments[0];
Assert.That(attSo.Name, Is.EqualTo(so2.Name));
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
Assert.That(attSo.IsAttachment);
Assert.That(attSo.UsesPhysics, Is.False);
Assert.That(attSo.IsTemporary, Is.False);
// Check item status
Assert.That(
sp.Appearance.GetAttachpoint(attSo.FromItemID),
Is.EqualTo((int)AttachmentPoint.LeftHand));
InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
Assert.That(attachmentItem, Is.Not.Null);
Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name));
InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object);
Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
}
}
/// <summary>
/// Test that we do not attempt to attach an in-world object that someone else is sitting on.
/// </summary>
@ -275,29 +389,140 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
m_numberOfAttachEventsFired = 0;
scene.AttachmentsModule.RezSingleAttachmentFromInventory(
sp, attItem.ID, (uint)AttachmentPoint.Chest);
{
scene.AttachmentsModule.RezSingleAttachmentFromInventory(
sp, attItem.ID, (uint)AttachmentPoint.Chest);
// Check scene presence status
Assert.That(sp.HasAttachments(), Is.True);
List<SceneObjectGroup> attachments = sp.GetAttachments();
Assert.That(attachments.Count, Is.EqualTo(1));
SceneObjectGroup attSo = attachments[0];
Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
Assert.That(attSo.IsAttachment);
Assert.That(attSo.UsesPhysics, Is.False);
Assert.That(attSo.IsTemporary, Is.False);
// Check scene presence status
Assert.That(sp.HasAttachments(), Is.True);
List<SceneObjectGroup> attachments = sp.GetAttachments();
Assert.That(attachments.Count, Is.EqualTo(1));
SceneObjectGroup attSo = attachments[0];
Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
Assert.That(attSo.IsAttachment);
Assert.That(attSo.UsesPhysics, Is.False);
Assert.That(attSo.IsTemporary, Is.False);
// Check appearance status
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
// Check appearance status
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
}
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
// Test attaching an already attached attachment
{
scene.AttachmentsModule.RezSingleAttachmentFromInventory(
sp, attItem.ID, (uint)AttachmentPoint.Chest);
// Check scene presence status
Assert.That(sp.HasAttachments(), Is.True);
List<SceneObjectGroup> attachments = sp.GetAttachments();
Assert.That(attachments.Count, Is.EqualTo(1));
SceneObjectGroup attSo = attachments[0];
Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
Assert.That(attSo.IsAttachment);
Assert.That(attSo.UsesPhysics, Is.False);
Assert.That(attSo.IsTemporary, Is.False);
// Check appearance status
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
}
}
/// <summary>
/// Test wearing an attachment from inventory, as opposed to explicit choosing the rez point
/// </summary>
[Test]
public void TestWearAttachmentFromInventory()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
Scene scene = CreateTestScene();
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID);
InventoryItemBase attItem1 = CreateAttachmentItem(scene, ua1.PrincipalID, "att1", 0x10, 0x20);
InventoryItemBase attItem2 = CreateAttachmentItem(scene, ua1.PrincipalID, "att2", 0x11, 0x21);
{
m_numberOfAttachEventsFired = 0;
scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem1.ID, (uint)AttachmentPoint.Default);
// default attachment point is currently the left hand.
Assert.That(sp.HasAttachments(), Is.True);
List<SceneObjectGroup> attachments = sp.GetAttachments();
Assert.That(attachments.Count, Is.EqualTo(1));
SceneObjectGroup attSo = attachments[0];
Assert.That(attSo.Name, Is.EqualTo(attItem1.Name));
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
Assert.That(attSo.IsAttachment);
// Check appearance status
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
Assert.That(sp.Appearance.GetAttachpoint(attItem1.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
}
// Test wearing a second attachment at the same position
// Until multiple attachments at one point is implemented, this will remove the first attachment
// This test relies on both attachments having the same default attachment point (in this case LeftHand
// since none other has been set).
{
scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default);
// default attachment point is currently the left hand.
Assert.That(sp.HasAttachments(), Is.True);
List<SceneObjectGroup> attachments = sp.GetAttachments();
Assert.That(attachments.Count, Is.EqualTo(1));
SceneObjectGroup attSo = attachments[0];
Assert.That(attSo.Name, Is.EqualTo(attItem2.Name));
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
Assert.That(attSo.IsAttachment);
// Check appearance status
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
}
// Test wearing an already attached attachment
{
scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default);
// default attachment point is currently the left hand.
Assert.That(sp.HasAttachments(), Is.True);
List<SceneObjectGroup> attachments = sp.GetAttachments();
Assert.That(attachments.Count, Is.EqualTo(1));
SceneObjectGroup attSo = attachments[0];
Assert.That(attSo.Name, Is.EqualTo(attItem2.Name));
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
Assert.That(attSo.IsAttachment);
// Check appearance status
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
// Check events
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
}
}
/// <summary>

View File

@ -39,7 +39,7 @@ using OpenSim.Region.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule
namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DAExampleModule")]
public class DAExampleModule : INonSharedRegionModule
@ -48,6 +48,8 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule
private static readonly bool ENABLED = false; // enable for testing
public const string DANamespace = "DAExample Module";
protected Scene m_scene;
protected IDialogModule m_dialogMod;
@ -85,19 +87,29 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule
{
OSDMap attrs = null;
SceneObjectPart sop = m_scene.GetSceneObjectPart(groupId);
if (!sop.DynAttrs.TryGetValue(Name, out attrs))
if (sop == null)
return true;
if (!sop.DynAttrs.TryGetValue(DANamespace, out attrs))
attrs = new OSDMap();
OSDInteger newValue;
if (!attrs.ContainsKey("moves"))
newValue = new OSDInteger(1);
else
newValue = new OSDInteger(((OSDInteger)attrs["moves"]).AsInteger() + 1);
// We have to lock on the entire dynamic attributes map to avoid race conditions with serialization code.
lock (sop.DynAttrs)
{
if (!attrs.ContainsKey("moves"))
newValue = new OSDInteger(1);
else
newValue = new OSDInteger(attrs["moves"].AsInteger() + 1);
attrs["moves"] = newValue;
attrs["moves"] = newValue;
sop.DynAttrs[Name] = attrs;
sop.DynAttrs[DANamespace] = attrs;
}
sop.ParentGroup.HasGroupChanged = true;
m_dialogMod.SendGeneralAlert(string.Format("{0} {1} moved {2} times", sop.Name, sop.UUID, newValue));

View File

@ -0,0 +1,139 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using log4net;
using Mono.Addins;
using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.Packets;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Region.Framework;
using OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Region.Framework.DynamicAttributes.DOExampleModule
{
/// <summary>
/// Example module for experimenting with and demonstrating dynamic object ideas.
/// </summary>
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DOExampleModule")]
public class DOExampleModule : INonSharedRegionModule
{
public class MyObject
{
public int Moves { get; set; }
public MyObject(int moves)
{
Moves = moves;
}
}
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly bool ENABLED = false; // enable for testing
private Scene m_scene;
private IDialogModule m_dialogMod;
public string Name { get { return "DOExample Module"; } }
public Type ReplaceableInterface { get { return null; } }
public void Initialise(IConfigSource source) {}
public void AddRegion(Scene scene)
{
if (ENABLED)
{
m_scene = scene;
m_scene.EventManager.OnObjectAddedToScene += OnObjectAddedToScene;
m_scene.EventManager.OnSceneGroupMove += OnSceneGroupMove;
m_dialogMod = m_scene.RequestModuleInterface<IDialogModule>();
}
}
public void RemoveRegion(Scene scene)
{
if (ENABLED)
{
m_scene.EventManager.OnSceneGroupMove -= OnSceneGroupMove;
}
}
public void RegionLoaded(Scene scene) {}
public void Close()
{
RemoveRegion(m_scene);
}
private void OnObjectAddedToScene(SceneObjectGroup so)
{
SceneObjectPart rootPart = so.RootPart;
OSDMap attrs;
int movesSoFar = 0;
// Console.WriteLine("Here for {0}", so.Name);
if (rootPart.DynAttrs.TryGetValue(DAExampleModule.DANamespace, out attrs))
{
movesSoFar = attrs["moves"].AsInteger();
m_log.DebugFormat(
"[DO EXAMPLE MODULE]: Found saved moves {0} for {1} in {2}", movesSoFar, so.Name, m_scene.Name);
}
rootPart.DynObjs.Add(Name, new MyObject(movesSoFar));
}
private bool OnSceneGroupMove(UUID groupId, Vector3 delta)
{
SceneObjectGroup so = m_scene.GetSceneObjectGroup(groupId);
if (so == null)
return true;
object rawObj = so.RootPart.DynObjs.Get(Name);
if (rawObj != null)
{
MyObject myObj = (MyObject)rawObj;
m_dialogMod.SendGeneralAlert(string.Format("{0} {1} moved {2} times", so.Name, so.UUID, ++myObj.Moves));
}
return true;
}
}
}

View File

@ -66,6 +66,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
/// </summary>
public bool WaitForAgentArrivedAtDestination { get; set; }
/// <summary>
/// If true then we ask the viewer to disable teleport cancellation and ignore teleport requests.
/// </summary>
/// <remarks>
/// This is useful in situations where teleport is very likely to always succeed and we want to avoid a
/// situation where avatars can be come 'stuck' due to a failed teleport cancellation. Unfortunately, the
/// nature of the teleport protocol makes it extremely difficult (maybe impossible) to make teleport
/// cancellation consistently suceed.
/// </remarks>
public bool DisableInterRegionTeleportCancellation { get; set; }
protected bool m_Enabled = false;
public Scene Scene { get; private set; }
@ -116,6 +127,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
IConfig transferConfig = source.Configs["EntityTransfer"];
if (transferConfig != null)
{
DisableInterRegionTeleportCancellation
= transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false);
WaitForAgentArrivedAtDestination
= transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault);
@ -150,6 +164,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
{
client.OnTeleportHomeRequest += TeleportHome;
client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
if (!DisableInterRegionTeleportCancellation)
client.OnTeleportCancel += OnClientCancelTeleport;
}
public virtual void Close() {}
@ -168,6 +185,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
#region Agent Teleports
private void OnClientCancelTeleport(IClientAPI client)
{
m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling);
m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name);
}
public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags)
{
if (sp.Scene.Permissions.IsGridGod(sp.UUID))
@ -519,6 +544,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
if (sp.ParentID != (uint)0)
sp.StandUp();
if (DisableInterRegionTeleportCancellation)
teleportFlags |= (uint)TeleportFlags.DisableCancel;
// At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to
// the viewer. However, it might mean that the viewer does not see the black teleport screen (untested).
sp.ControllingClient.SendTeleportStart(teleportFlags);
@ -567,6 +595,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
return;
}
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
{
m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
sp.Name, finalDestination.RegionName, sp.Scene.Name);
return;
}
// Past this point we have to attempt clean up if the teleport fails, so update transfer state.
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
@ -631,7 +668,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
return;
}
sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest");
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
{
m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request",
sp.Name, finalDestination.RegionName, sp.Scene.Name);
CleanupAbortedInterRegionTeleport(sp, finalDestination);
return;
}
m_log.DebugFormat(
"[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
@ -714,14 +760,19 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// }
}
protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout)
/// <summary>
/// Clean up an inter-region teleport that did not complete, either because of simulator failure or cancellation.
/// </summary>
/// <remarks>
/// All operations here must be idempotent so that we can call this method at any point in the teleport process
/// up until we send the TeleportFinish event quene event to the viewer.
/// <remarks>
/// <param name='sp'> </param>
/// <param name='finalDestination'></param>
protected virtual void CleanupAbortedInterRegionTeleport(ScenePresence sp, GridRegion finalDestination)
{
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
// Client never contacted destination. Let's restore everything back
sp.ControllingClient.SendTeleportFailed("Problems connecting to destination.");
// Fail. Reset it back
sp.IsChildAgent = false;
ReInstantiateScripts(sp);
@ -729,7 +780,20 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// Finally, kill the agent we just created at the destination.
Scene.SimulationService.CloseAgent(finalDestination, sp.UUID);
}
/// <summary>
/// Signal that the inter-region teleport failed and perform cleanup.
/// </summary>
/// <param name='sp'></param>
/// <param name='finalDestination'></param>
/// <param name='logout'></param>
protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout)
{
CleanupAbortedInterRegionTeleport(sp, finalDestination);
sp.ControllingClient.SendTeleportFailed(
string.Format("Problems connecting to destination {0}", finalDestination.RegionName));
sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout);
}
@ -1206,6 +1270,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
// region doesn't take it
m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
m_log.WarnFormat(
"[ENTITY TRANSFER MODULE]: Region {0} would not accept update for agent {1} on cross attempt. Returning to original region.",
neighbourRegion.RegionName, agent.Name);
ReInstantiateScripts(agent);
agent.AddToPhysicalScene(isFlying);
@ -1225,6 +1293,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
neighbourRegion.RegionHandle);
return agent;
}
// No turning back
agent.IsChildAgent = true;
@ -2092,7 +2161,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
public bool IsInTransit(UUID id)
{
return m_entityTransferStateMachine.IsInTransit(id);
return m_entityTransferStateMachine.GetAgentTransferState(id) != null;
}
protected void ReInstantiateScripts(ScenePresence sp)

View File

@ -51,8 +51,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
/// This is a state machine.
///
/// [Entry] => Preparing
/// Preparing => { Transferring || CleaningUp || [Exit] }
/// Transferring => { ReceivedAtDestination || CleaningUp }
/// Preparing => { Transferring || Cancelling || CleaningUp || [Exit] }
/// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp }
/// Cancelling => CleaningUp
/// ReceivedAtDestination => CleaningUp
/// CleaningUp => [Exit]
///
@ -64,7 +65,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
Preparing, // The agent is being prepared for transfer
Transferring, // The agent is in the process of being transferred to a destination
ReceivedAtDestination, // The destination has notified us that the agent has been successfully received
CleaningUp // The agent is being changed to child/removed after a transfer
CleaningUp, // The agent is being changed to child/removed after a transfer
Cancelling // The user has cancelled the teleport but we have yet to act upon this.
}
/// <summary>
@ -115,42 +117,110 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
/// <param name='newState'></param>
/// <returns></returns>
/// <exception cref='Exception'>Illegal transitions will throw an Exception</exception>
internal void UpdateInTransit(UUID id, AgentTransferState newState)
internal bool UpdateInTransit(UUID id, AgentTransferState newState)
{
bool transitionOkay = false;
// We don't want to throw an exception on cancel since this can come it at any time.
bool failIfNotOkay = true;
// Should be a failure message if failure is not okay.
string failureMessage = null;
AgentTransferState? oldState = null;
lock (m_agentsInTransit)
{
// Illegal to try and update an agent that's not actually in transit.
if (!m_agentsInTransit.ContainsKey(id))
throw new Exception(
string.Format(
"Agent with ID {0} is not registered as in transit in {1}",
id, m_mod.Scene.RegionInfo.RegionName));
{
if (newState != AgentTransferState.Cancelling)
failureMessage = string.Format(
"Agent with ID {0} is not registered as in transit in {1}",
id, m_mod.Scene.RegionInfo.RegionName);
else
failIfNotOkay = false;
}
else
{
oldState = m_agentsInTransit[id];
AgentTransferState oldState = m_agentsInTransit[id];
if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp)
{
transitionOkay = true;
}
else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing)
{
transitionOkay = true;
}
else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring)
{
transitionOkay = true;
}
else
{
if (newState == AgentTransferState.Cancelling
&& (oldState == AgentTransferState.Preparing || oldState == AgentTransferState.Transferring))
{
transitionOkay = true;
}
else
{
failIfNotOkay = false;
}
}
bool transitionOkay = false;
if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp)
transitionOkay = true;
else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing)
transitionOkay = true;
else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring)
transitionOkay = true;
if (!transitionOkay)
failureMessage
= string.Format(
"Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}",
id, oldState, newState, m_mod.Scene.RegionInfo.RegionName);
}
if (transitionOkay)
{
m_agentsInTransit[id] = newState;
else
throw new Exception(
string.Format(
"Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}",
id, oldState, newState, m_mod.Scene.RegionInfo.RegionName));
// m_log.DebugFormat(
// "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}",
// id, oldState, newState, m_mod.Scene.Name);
}
else if (failIfNotOkay)
{
throw new Exception(failureMessage);
}
// else
// {
// if (oldState != null)
// m_log.DebugFormat(
// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} from state {1} to {2} in {3}",
// id, oldState, newState, m_mod.Scene.Name);
// else
// m_log.DebugFormat(
// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} to state {1} in {2} since agent not in transit",
// id, newState, m_mod.Scene.Name);
// }
}
return transitionOkay;
}
internal bool IsInTransit(UUID id)
/// <summary>
/// Gets the current agent transfer state.
/// </summary>
/// <returns>Null if the agent is not in transit</returns>
/// <param name='id'>
/// Identifier.
/// </param>
internal AgentTransferState? GetAgentTransferState(UUID id)
{
lock (m_agentsInTransit)
return m_agentsInTransit.ContainsKey(id);
{
if (!m_agentsInTransit.ContainsKey(id))
return null;
else
return m_agentsInTransit[id];
}
}
/// <summary>
@ -203,14 +273,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
lock (m_agentsInTransit)
{
if (!IsInTransit(id))
AgentTransferState? currentState = GetAgentTransferState(id);
if (currentState == null)
throw new Exception(
string.Format(
"Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit",
id, m_mod.Scene.RegionInfo.RegionName));
AgentTransferState currentState = m_agentsInTransit[id];
if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination)
throw new Exception(
string.Format(

View File

@ -414,8 +414,6 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
}
private void RegisterStatsManagerRegionStatistics()
{
string regionName = m_scene.RegionInfo.RegionName;
MakeStat("RootAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetRootAgentCount(); });
MakeStat("ChildAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetChildAgentCount(); });
MakeStat("TotalPrims", "objects", (s) => { s.Value = m_scene.SceneGraph.GetTotalObjectsCount(); });

View File

@ -516,6 +516,9 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
foreach (string line in GetLines(data, dataDelim))
{
string nextLine = line.Trim();
// m_log.DebugFormat("[VECTOR RENDER MODULE]: Processing line '{0}'", nextLine);
//replace with switch, or even better, do some proper parsing
if (nextLine.StartsWith("MoveTo"))
{
@ -829,6 +832,8 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
float y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture);
PointF point = new PointF(x, y);
points[i / 2] = point;
// m_log.DebugFormat("[VECTOR RENDER MODULE]: Got point {0}", points[i / 2]);
}
}
}

View File

@ -219,12 +219,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
{
// m_log.DebugFormat(
// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate",
// s.RegionInfo.RegionName, destination.RegionHandle);
// destination.RegionName, destination.RegionID);
return m_scenes[destination.RegionID].IncomingChildAgentDataUpdate(cAgentData);
}
// m_log.DebugFormat("[LOCAL COMMS]: Did not find region {0} for ChildAgentUpdate", regionHandle);
// m_log.DebugFormat(
// "[LOCAL COMMS]: Did not find region {0} {1} for ChildAgentUpdate",
// destination.RegionName, destination.RegionID);
return false;
}
@ -239,7 +242,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
// note that we really don't need the GridRegion for this call
foreach (Scene s in m_scenes.Values)
{
//m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate");
// m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate");
s.IncomingChildAgentDataUpdate(cAgentData);
}

View File

@ -95,6 +95,11 @@ namespace OpenSim.Region.CoreModules.World.Land
return null;
}
public ILandObject GetLandObject(Vector3 position)
{
return GetLandObject(position.X, position.Y);
}
public ILandObject GetLandObject(int x, int y)
{
if (m_landManagementModule != null)

View File

@ -41,6 +41,16 @@ namespace OpenSim.Region.Framework.Interfaces
Value = 3
}
public enum JsonStoreValueType
{
Undefined = 0,
Boolean = 1,
Integer = 2,
Float = 3,
String = 4,
UUID = 5
}
public delegate void TakeValueCallback(string s);
public interface IJsonStoreModule
@ -49,7 +59,9 @@ namespace OpenSim.Region.Framework.Interfaces
bool CreateStore(string value, ref UUID result);
bool DestroyStore(UUID storeID);
JsonStoreNodeType GetPathType(UUID storeID, string path);
JsonStoreNodeType GetNodeType(UUID storeID, string path);
JsonStoreValueType GetValueType(UUID storeID, string path);
bool TestStore(UUID storeID);
bool SetValue(UUID storeID, string path, string value, bool useJson);

View File

@ -130,6 +130,27 @@ namespace OpenSim.Region.Framework.Scenes
/// </summary>
public DAMap DynAttrs { get; set; }
private DOMap m_dynObjs;
/// <summary>
/// Dynamic objects that can be created and deleted as required.
/// </summary>
public DOMap DynObjs
{
get
{
if (m_dynObjs == null)
m_dynObjs = new DOMap();
return m_dynObjs;
}
set
{
m_dynObjs = value;
}
}
/// <value>
/// Is this a root part?
/// </value>
@ -4503,8 +4524,25 @@ namespace OpenSim.Region.Framework.Scenes
Changed changeFlags = 0;
Primitive.TextureEntryFace fallbackNewFace = newTex.DefaultTexture;
Primitive.TextureEntryFace fallbackOldFace = oldTex.DefaultTexture;
// On Incoming packets, sometimes newText.DefaultTexture is null. The assumption is that all
// other prim-sides are set, but apparently that's not always the case. Lets assume packet/data corruption at this point.
if (fallbackNewFace == null)
{
fallbackNewFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0);
newTex.DefaultTexture = fallbackNewFace;
}
if (fallbackOldFace == null)
{
fallbackOldFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0);
oldTex.DefaultTexture = fallbackOldFace;
}
for (int i = 0 ; i < GetNumberOfSides(); i++)
{
Primitive.TextureEntryFace newFace = newTex.DefaultTexture;
Primitive.TextureEntryFace oldFace = oldTex.DefaultTexture;

View File

@ -559,16 +559,28 @@ namespace OpenSim.Region.Framework.Scenes
private Quaternion m_bodyRot = Quaternion.Identity;
/// <summary>
/// The rotation of the avatar.
/// </summary>
/// <remarks>
/// If the avatar is not sitting, this is with respect to the world
/// If the avatar is sitting, this is a with respect to the part that it's sitting upon (a local rotation).
/// If you always want the world rotation, use GetWorldRotation()
/// </remarks>
public Quaternion Rotation
{
get { return m_bodyRot; }
get
{
return m_bodyRot;
}
set
{
m_bodyRot = value;
if (PhysicsActor != null)
{
PhysicsActor.Orientation = m_bodyRot;
}
// m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot);
}
}
@ -608,6 +620,26 @@ namespace OpenSim.Region.Framework.Scenes
set { m_health = value; }
}
/// <summary>
/// Gets the world rotation of this presence.
/// </summary>
/// <remarks>
/// Unlike Rotation, this returns the world rotation no matter whether the avatar is sitting on a prim or not.
/// </remarks>
/// <returns></returns>
public Quaternion GetWorldRotation()
{
if (IsSatOnObject)
{
SceneObjectPart sitPart = ParentPart;
if (sitPart != null)
return sitPart.GetWorldRotation() * Rotation;
}
return Rotation;
}
public void AdjustKnownSeeds()
{
Dictionary<ulong, string> seeds;
@ -709,8 +741,6 @@ namespace OpenSim.Region.Framework.Scenes
#endregion
#region Constructor(s)
public ScenePresence(
@ -1613,33 +1643,29 @@ namespace OpenSim.Region.Framework.Scenes
bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) ||
((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0));
//m_log.Debug("[CONTROL]: " +flags);
// Applies a satisfying roll effect to the avatar when flying.
if (((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) != 0) && ((flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0))
if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) != 0 && (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0)
{
ApplyFlyingRoll(FLY_ROLL_RADIANS_PER_UPDATE, ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0), ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0));
ApplyFlyingRoll(
FLY_ROLL_RADIANS_PER_UPDATE,
(flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0,
(flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0);
}
else if (((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) != 0) &&
((flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0))
else if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) != 0 &&
(flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0)
{
ApplyFlyingRoll(-FLY_ROLL_RADIANS_PER_UPDATE, ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0), ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0));
ApplyFlyingRoll(
-FLY_ROLL_RADIANS_PER_UPDATE,
(flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0,
(flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0);
}
else
{
if (m_AngularVelocity.Z != 0)
m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE);
}
if (Flying && IsColliding && controlland)
{
// nesting this check because LengthSquared() is expensive and we don't
@ -2400,7 +2426,8 @@ namespace OpenSim.Region.Framework.Scenes
/// <param name="vec">The vector in which to move. This is relative to the rotation argument</param>
public void AddNewMovement(Vector3 vec)
{
// m_log.DebugFormat("[SCENE PRESENCE]: Adding new movement {0} for {1}", vec, Name);
// m_log.DebugFormat(
// "[SCENE PRESENCE]: Adding new movement {0} with rotation {1} for {2}", vec, Rotation, Name);
Vector3 direc = vec * Rotation;
direc.Normalize();
@ -2420,6 +2447,8 @@ namespace OpenSim.Region.Framework.Scenes
direc *= 0.03f * 128f * SpeedModifier;
// m_log.DebugFormat("[SCENE PRESENCE]: Force to apply before modification was {0} for {1}", direc, Name);
if (PhysicsActor != null)
{
if (Flying)
@ -2453,6 +2482,8 @@ namespace OpenSim.Region.Framework.Scenes
}
}
// m_log.DebugFormat("[SCENE PRESENCE]: Setting force to apply to {0} for {1}", direc, Name);
// TODO: Add the force instead of only setting it to support multiple forces per frame?
m_forceToApply = direc;
}

View File

@ -110,8 +110,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
Vector3 firstSize = new Vector3(2, 3, 4);
Vector3 secondSize = new Vector3(5, 6, 7);
Vector3 thirdSize = new Vector3(8, 9, 10);
Vector3 fourthSize = new Vector3(11, 12, 13);
// Vector3 thirdSize = new Vector3(8, 9, 10);
// Vector3 fourthSize = new Vector3(11, 12, 13);
Scene scene = new SceneHelpers().SetupScene();
scene.MaxUndoCount = 20;

View File

@ -288,109 +288,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests
// ScenePresence presence = scene.GetScenePresence(agent1);
//
// Assert.That(presence, Is.Null, "presence is not null");
// }
// I'm commenting this test because it does not represent
// crossings. The Thread.Sleep's in here are not meaningful mocks,
// and they sometimes fail in panda.
// We need to talk in order to develop a test
// that really tests region crossings. There are 3 async components,
// but things are synchronous among them. So there should be
// 3 threads in here.
//[Test]
// public void T021_TestCrossToNewRegion()
// {
// TestHelpers.InMethod();
//
// scene.RegisterRegionWithGrid();
// scene2.RegisterRegionWithGrid();
//
// // Adding child agent to region 1001
// string reason;
// scene2.NewUserConnection(acd1,0, out reason);
// scene2.AddNewClient(testclient, PresenceType.User);
//
// ScenePresence presence = scene.GetScenePresence(agent1);
// presence.MakeRootAgent(new Vector3(0,unchecked(Constants.RegionSize-1),0), true);
//
// ScenePresence presence2 = scene2.GetScenePresence(agent1);
//
// // Adding neighbour region caps info to presence2
//
// string cap = presence.ControllingClient.RequestClientInfo().CapsPath;
// presence2.AddNeighbourRegion(region1, cap);
//
// Assert.That(presence.IsChildAgent, Is.False, "Did not start root in origin region.");
// Assert.That(presence2.IsChildAgent, Is.True, "Is not a child on destination region.");
//
// // Cross to x+1
// presence.AbsolutePosition = new Vector3(Constants.RegionSize+1,3,100);
// presence.Update();
//
// EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing");
//
// // Mimicking communication between client and server, by waiting OK from client
// // sent by TestClient.CrossRegion call. Originally, this is network comm.
// if (!wh.WaitOne(5000,false))
// {
// presence.Update();
// if (!wh.WaitOne(8000,false))
// throw new ArgumentException("1 - Timeout waiting for signal/variable.");
// }
//
// // This is a TestClient specific method that fires OnCompleteMovementToRegion event, which
// // would normally be fired after receiving the reply packet from comm. done on the last line.
// testclient.CompleteMovement();
//
// // Crossings are asynchronous
// int timer = 10;
//
// // Make sure cross hasn't already finished
// if (!presence.IsInTransit && !presence.IsChildAgent)
// {
// // If not and not in transit yet, give it some more time
// Thread.Sleep(5000);
// }
//
// // Enough time, should at least be in transit by now.
// while (presence.IsInTransit && timer > 0)
// {
// Thread.Sleep(1000);
// timer-=1;
// }
//
// Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 2->1.");
// Assert.That(presence.IsChildAgent, Is.True, "Did not complete region cross as expected.");
// Assert.That(presence2.IsChildAgent, Is.False, "Did not receive root status after receiving agent.");
//
// // Cross Back
// presence2.AbsolutePosition = new Vector3(-10, 3, 100);
// presence2.Update();
//
// if (!wh.WaitOne(5000,false))
// {
// presence2.Update();
// if (!wh.WaitOne(8000,false))
// throw new ArgumentException("2 - Timeout waiting for signal/variable.");
// }
// testclient.CompleteMovement();
//
// if (!presence2.IsInTransit && !presence2.IsChildAgent)
// {
// // If not and not in transit yet, give it some more time
// Thread.Sleep(5000);
// }
//
// // Enough time, should at least be in transit by now.
// while (presence2.IsInTransit && timer > 0)
// {
// Thread.Sleep(1000);
// timer-=1;
// }
//
// Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 1->2.");
// Assert.That(presence2.IsChildAgent, Is.True, "Did not return from region as expected.");
// Assert.That(presence.IsChildAgent, Is.False, "Presence was not made root in old region again.");
// }
}
}

View File

@ -0,0 +1,157 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections.Generic;
using System.Reflection;
using Nini.Config;
using NUnit.Framework;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Communications;
using OpenSim.Framework.Servers;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.CoreModules.Framework;
using OpenSim.Region.CoreModules.Framework.EntityTransfer;
using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
using OpenSim.Tests.Common;
using OpenSim.Tests.Common.Mock;
namespace OpenSim.Region.Framework.Scenes.Tests
{
[TestFixture]
public class ScenePresenceCrossingTests : OpenSimTestCase
{
[TestFixtureSetUp]
public void FixtureInit()
{
// Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
}
[TestFixtureTearDown]
public void TearDown()
{
// We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
// threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
// tests really shouldn't).
Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
}
[Test]
public void TestCrossOnSameSimulator()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
UUID userId = TestHelpers.ParseTail(0x1);
// TestEventQueueGetModule eqmA = new TestEventQueueGetModule();
EntityTransferModule etmA = new EntityTransferModule();
EntityTransferModule etmB = new EntityTransferModule();
LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
IConfigSource config = new IniConfigSource();
IConfig modulesConfig = config.AddConfig("Modules");
modulesConfig.Set("EntityTransferModule", etmA.Name);
modulesConfig.Set("SimulationServices", lscm.Name);
// IConfig entityTransferConfig = config.AddConfig("EntityTransfer");
// In order to run a single threaded regression test we do not want the entity transfer module waiting
// for a callback from the destination scene before removing its avatar data.
// entityTransferConfig.Set("wait_for_callback", false);
SceneHelpers sh = new SceneHelpers();
TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1000, 999);
SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA);
// SceneHelpers.SetupSceneModules(sceneA, config, new CapabilitiesModule(), etmA, eqmA);
SceneHelpers.SetupSceneModules(sceneB, config, new CapabilitiesModule(), etmB);
ScenePresence originalSp = SceneHelpers.AddScenePresence(sceneA, userId, sh.SceneManager);
originalSp.AbsolutePosition = new Vector3(128, 32, 10);
// originalSp.Flying = true;
// Console.WriteLine("First pos {0}", originalSp.AbsolutePosition);
// eqmA.ClearEvents();
AgentUpdateArgs moveArgs = new AgentUpdateArgs();
//moveArgs.BodyRotation = Quaternion.CreateFromEulers(Vector3.Zero);
moveArgs.BodyRotation = Quaternion.CreateFromEulers(new Vector3(0, 0, (float)-(Math.PI / 2)));
moveArgs.ControlFlags = (uint)AgentManager.ControlFlags.AGENT_CONTROL_AT_POS;
originalSp.HandleAgentUpdate(originalSp.ControllingClient, moveArgs);
sceneA.Update(1);
// Console.WriteLine("Second pos {0}", originalSp.AbsolutePosition);
// FIXME: This is a sufficient number of updates to for the presence to reach the northern border.
// But really we want to do this in a more robust way.
for (int i = 0; i < 100; i++)
{
sceneA.Update(1);
// Console.WriteLine("Pos {0}", originalSp.AbsolutePosition);
}
// Need to sort processing of EnableSimulator message on adding scene presences before we can test eqm
// messages
// Dictionary<UUID, List<TestEventQueueGetModule.Event>> eqmEvents = eqmA.Events;
//
// Assert.That(eqmEvents.Count, Is.EqualTo(1));
// Assert.That(eqmEvents.ContainsKey(originalSp.UUID), Is.True);
//
// List<TestEventQueueGetModule.Event> spEqmEvents = eqmEvents[originalSp.UUID];
//
// Assert.That(spEqmEvents.Count, Is.EqualTo(1));
// Assert.That(spEqmEvents[0].Name, Is.EqualTo("CrossRegion"));
// sceneA should now only have a child agent
ScenePresence spAfterCrossSceneA = sceneA.GetScenePresence(originalSp.UUID);
Assert.That(spAfterCrossSceneA.IsChildAgent, Is.True);
ScenePresence spAfterCrossSceneB = sceneB.GetScenePresence(originalSp.UUID);
// Agent remains a child until the client triggers complete movement
Assert.That(spAfterCrossSceneB.IsChildAgent, Is.True);
TestClient sceneBTc = ((TestClient)spAfterCrossSceneB.ControllingClient);
int agentMovementCompleteReceived = 0;
sceneBTc.OnReceivedMoveAgentIntoRegion += (ri, pos, look) => agentMovementCompleteReceived++;
sceneBTc.CompleteMovement();
Assert.That(agentMovementCompleteReceived, Is.EqualTo(1));
Assert.That(spAfterCrossSceneB.IsChildAgent, Is.False);
}
}
}

View File

@ -140,9 +140,12 @@ public class ServerStats : ISharedRegionModule
}
#endregion ISharedRegionModule
private void MakeStat(string pName, string pUnit, string pContainer, Action<Stat> act)
private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action<Stat> act)
{
Stat stat = new Stat(pName, pName, "", pUnit, CategoryServer, pContainer, StatType.Pull, act, StatVerbosity.Info);
string desc = pDesc;
if (desc == null)
desc = pName;
Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, act, StatVerbosity.Info);
StatsManager.RegisterStat(stat);
RegisteredStats.Add(pName, stat);
}
@ -166,16 +169,16 @@ public class ServerStats : ISharedRegionModule
StatsManager.RegisterStat(tempStat);
RegisteredStats.Add(tempName, tempStat);
MakeStat("TotalProcessorTime", "sec", ContainerProcessor,
MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor,
(s) => { s.Value = Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds; });
MakeStat("UserProcessorTime", "sec", ContainerProcessor,
MakeStat("UserProcessorTime", null, "sec", ContainerProcessor,
(s) => { s.Value = Process.GetCurrentProcess().UserProcessorTime.TotalSeconds; });
MakeStat("PrivilegedProcessorTime", "sec", ContainerProcessor,
MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor,
(s) => { s.Value = Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds; });
MakeStat("Threads", "threads", ContainerProcessor,
MakeStat("Threads", null, "threads", ContainerProcessor,
(s) => { s.Value = Process.GetCurrentProcess().Threads.Count; });
}
catch (Exception e)
@ -196,8 +199,10 @@ public class ServerStats : ISharedRegionModule
string nicInterfaceType = nic.NetworkInterfaceType.ToString();
if (!okInterfaceTypes.Contains(nicInterfaceType))
{
m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'. To include, add to [Monitoring]NetworkInterfaceTypes='Ethernet,Loopback'",
m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'.",
LogHeader, nic.Name, nicInterfaceType);
m_log.DebugFormat("{0} To include, add to comma separated list in [Monitoring]NetworkInterfaceTypes={1}",
LogHeader, NetworkInterfaceTypes);
continue;
}
@ -206,14 +211,15 @@ public class ServerStats : ISharedRegionModule
IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics();
if (nicStats != null)
{
MakeStat("BytesRcvd/" + nic.Name, "KB", ContainerNetwork,
MakeStat("BytesRcvd/" + nic.Name, nic.Name, "KB", ContainerNetwork,
(s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); });
MakeStat("BytesSent/" + nic.Name, "KB", ContainerNetwork,
MakeStat("BytesSent/" + nic.Name, nic.Name, "KB", ContainerNetwork,
(s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); });
MakeStat("TotalBytes/" + nic.Name, "KB", ContainerNetwork,
MakeStat("TotalBytes/" + nic.Name, nic.Name, "KB", ContainerNetwork,
(s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); });
}
}
// TODO: add IPv6 (it may actually happen someday)
}
}
catch (Exception e)
@ -221,13 +227,13 @@ public class ServerStats : ISharedRegionModule
m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e);
}
MakeStat("ProcessMemory", "MB", ContainerMemory,
MakeStat("ProcessMemory", null, "MB", ContainerMemory,
(s) => { s.Value = Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d; });
MakeStat("ObjectMemory", "MB", ContainerMemory,
MakeStat("ObjectMemory", null, "MB", ContainerMemory,
(s) => { s.Value = GC.GetTotalMemory(false) / 1024d / 1024d; });
MakeStat("LastMemoryChurn", "MB/sec", ContainerMemory,
MakeStat("LastMemoryChurn", null, "MB/sec", ContainerMemory,
(s) => { s.Value = Math.Round(MemoryWatchdog.LastMemoryChurn * 1000d / 1024d / 1024d, 3); });
MakeStat("AverageMemoryChurn", "MB/sec", ContainerMemory,
MakeStat("AverageMemoryChurn", null, "MB/sec", ContainerMemory,
(s) => { s.Value = Math.Round(MemoryWatchdog.AverageMemoryChurn * 1000d / 1024d / 1024d, 3); });
}
@ -263,6 +269,8 @@ public class ServerStats : ISharedRegionModule
}
}
// Lookup the nic that goes with this stat and set the value by using a fetch action.
// Not sure about closure with delegates inside delegates.
private delegate double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat);
private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor)
{
@ -275,7 +283,10 @@ public class ServerStats : ISharedRegionModule
{
IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics();
if (intrStats != null)
stat.Value = Math.Round(getter(intrStats) / factor, 3);
{
double newVal = Math.Round(getter(intrStats) / factor, 3);
stat.Value = newVal;
}
break;
}
}

View File

@ -145,7 +145,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
///
/// </summary>
// -----------------------------------------------------------------
public JsonStoreNodeType PathType(string expr)
public JsonStoreNodeType GetNodeType(string expr)
{
Stack<string> path;
if (! ParsePathExpression(expr,out path))
@ -168,6 +168,43 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
return JsonStoreNodeType.Undefined;
}
// -----------------------------------------------------------------
/// <summary>
///
/// </summary>
// -----------------------------------------------------------------
public JsonStoreValueType GetValueType(string expr)
{
Stack<string> path;
if (! ParsePathExpression(expr,out path))
return JsonStoreValueType.Undefined;
OSD result = ProcessPathExpression(ValueStore,path);
if (result == null)
return JsonStoreValueType.Undefined;
if (result is OSDMap)
return JsonStoreValueType.Undefined;
if (result is OSDArray)
return JsonStoreValueType.Undefined;
if (result is OSDBoolean)
return JsonStoreValueType.Boolean;
if (result is OSDInteger)
return JsonStoreValueType.Integer;
if (result is OSDReal)
return JsonStoreValueType.Float;
if (result is OSDString)
return JsonStoreValueType.String;
return JsonStoreValueType.Undefined;
}
// -----------------------------------------------------------------
/// <summary>
///

View File

@ -270,7 +270,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
///
/// </summary>
// -----------------------------------------------------------------
public JsonStoreNodeType GetPathType(UUID storeID, string path)
public JsonStoreNodeType GetNodeType(UUID storeID, string path)
{
if (! m_enabled) return JsonStoreNodeType.Undefined;
@ -287,7 +287,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
try
{
lock (map)
return map.PathType(path);
return map.GetNodeType(path);
}
catch (Exception e)
{
@ -297,6 +297,38 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
return JsonStoreNodeType.Undefined;
}
// -----------------------------------------------------------------
/// <summary>
///
/// </summary>
// -----------------------------------------------------------------
public JsonStoreValueType GetValueType(UUID storeID, string path)
{
if (! m_enabled) return JsonStoreValueType.Undefined;
JsonStore map = null;
lock (m_JsonValueStore)
{
if (! m_JsonValueStore.TryGetValue(storeID,out map))
{
m_log.InfoFormat("[JsonStore] Missing store {0}",storeID);
return JsonStoreValueType.Undefined;
}
}
try
{
lock (map)
return map.GetValueType(path);
}
catch (Exception e)
{
m_log.Error(string.Format("[JsonStore]: Path test failed for {0} in {1}", path, storeID), e);
}
return JsonStoreValueType.Undefined;
}
// -----------------------------------------------------------------
/// <summary>
///

View File

@ -192,16 +192,32 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
#region ScriptConstantsInterface
[ScriptConstant]
public static readonly int JSON_TYPE_UNDEF = (int)JsonStoreNodeType.Undefined;
public static readonly int JSON_NODETYPE_UNDEF = (int)JsonStoreNodeType.Undefined;
[ScriptConstant]
public static readonly int JSON_TYPE_OBJECT = (int)JsonStoreNodeType.Object;
public static readonly int JSON_NODETYPE_OBJECT = (int)JsonStoreNodeType.Object;
[ScriptConstant]
public static readonly int JSON_TYPE_ARRAY = (int)JsonStoreNodeType.Array;
public static readonly int JSON_NODETYPE_ARRAY = (int)JsonStoreNodeType.Array;
[ScriptConstant]
public static readonly int JSON_TYPE_VALUE = (int)JsonStoreNodeType.Value;
public static readonly int JSON_NODETYPE_VALUE = (int)JsonStoreNodeType.Value;
[ScriptConstant]
public static readonly int JSON_VALUETYPE_UNDEF = (int)JsonStoreValueType.Undefined;
[ScriptConstant]
public static readonly int JSON_VALUETYPE_BOOLEAN = (int)JsonStoreValueType.Boolean;
[ScriptConstant]
public static readonly int JSON_VALUETYPE_INTEGER = (int)JsonStoreValueType.Integer;
[ScriptConstant]
public static readonly int JSON_VALUETYPE_FLOAT = (int)JsonStoreValueType.Float;
[ScriptConstant]
public static readonly int JSON_VALUETYPE_STRING = (int)JsonStoreValueType.String;
#endregion
@ -310,9 +326,20 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
/// </summary>
// -----------------------------------------------------------------
[ScriptInvocation]
public int JsonGetPathType(UUID hostID, UUID scriptID, UUID storeID, string path)
public int JsonGetNodeType(UUID hostID, UUID scriptID, UUID storeID, string path)
{
return (int)m_store.GetPathType(storeID,path);
return (int)m_store.GetNodeType(storeID,path);
}
// -----------------------------------------------------------------
/// <summary>
///
/// </summary>
// -----------------------------------------------------------------
[ScriptInvocation]
public int JsonGetValueType(UUID hostID, UUID scriptID, UUID storeID, string path)
{
return (int)m_store.GetValueType(storeID,path);
}
// -----------------------------------------------------------------

View File

@ -158,8 +158,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
Assert.That(dsrv, Is.EqualTo(1));
int tprv = (int)InvokeOp("JsonGetPathType", storeId, "Hello");
Assert.That(tprv, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
int tprv = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
Assert.That(tprv, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
}
[Test]
@ -277,8 +277,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
Assert.That(returnValue, Is.EqualTo(1));
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
string returnValue2 = (string)InvokeOp("JsonGetValue", storeId, "Hello");
Assert.That(returnValue2, Is.EqualTo(""));
@ -291,8 +291,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
Assert.That(returnValue, Is.EqualTo(1));
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
string returnValue2 = (string)InvokeOp("JsonGetJson", storeId, "Hello");
Assert.That(returnValue2, Is.EqualTo(""));
@ -306,11 +306,11 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello[0]");
Assert.That(returnValue, Is.EqualTo(1));
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello[0]");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE));
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello[0]");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE));
result = (int)InvokeOp("JsonGetPathType", storeId, "Hello[1]");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello[1]");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
string stringReturnValue = (string)InvokeOp("JsonGetValue", storeId, "Hello[0]");
Assert.That(stringReturnValue, Is.EqualTo("value2"));
@ -433,7 +433,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
}
[Test]
public void TestJsonGetPathType()
public void TestJsonGetNodeType()
{
TestHelpers.InMethod();
// TestHelpers.EnableLogging();
@ -441,41 +441,41 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }");
{
int result = (int)InvokeOp("JsonGetPathType", storeId, ".");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_OBJECT));
int result = (int)InvokeOp("JsonGetNodeType", storeId, ".");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_OBJECT));
}
{
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_OBJECT));
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_OBJECT));
}
{
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_ARRAY));
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_ARRAY));
}
{
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World[0]");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE));
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World[0]");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE));
}
{
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World[1]");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE));
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World[1]");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE));
}
// Test for non-existant path
{
int result = (int)InvokeOp("JsonGetPathType", storeId, "foo");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
int result = (int)InvokeOp("JsonGetNodeType", storeId, "foo");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
}
// Test for non-existant store
{
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
int result = (int)InvokeOp("JsonGetPathType", fakeStoreId, ".");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
int result = (int)InvokeOp("JsonGetNodeType", fakeStoreId, ".");
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
}
}

View File

@ -102,6 +102,8 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
public override float Simulate(float timeStep)
{
// Console.WriteLine("Simulating");
float fps = 0;
for (int i = 0; i < _actors.Count; ++i)
{
@ -109,8 +111,11 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
Vector3 actorPosition = actor.Position;
Vector3 actorVelocity = actor.Velocity;
actorPosition.X += actor.Velocity.X*timeStep;
actorPosition.Y += actor.Velocity.Y*timeStep;
// Console.WriteLine(
// "Processing actor {0}, starting pos {1}, starting vel {2}", i, actorPosition, actorVelocity);
actorPosition.X += actor.Velocity.X * timeStep;
actorPosition.Y += actor.Velocity.Y * timeStep;
if (actor.Position.Y < 0)
{

View File

@ -205,7 +205,7 @@ public sealed class BSCharacter : BSPhysObject
// errors can creap in and the avatar will slowly float off in some direction.
// So, the problem is that, when an avatar is standing, we cannot tell creaping error
// from real pushing.
// The code below keeps setting the velocity to zero hoping the world will keep pushing.
// The code below uses whether the collider is static or moving to decide whether to zero motion.
_velocityMotor.Step(timeStep);
@ -244,6 +244,7 @@ public sealed class BSCharacter : BSPhysObject
}
else
{
// Supposed to be moving.
OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue;
if (Friction != BSParam.AvatarFriction)
@ -276,8 +277,8 @@ public sealed class BSCharacter : BSPhysObject
});
}
// Decide of the character is colliding with a low object and compute a force to pop the
// avatar up so it has a chance of walking up and over the low object.
// Decide if the character is colliding with a low object and compute a force to pop the
// avatar up so it can walk up and over the low objects.
private OMV.Vector3 WalkUpStairs()
{
OMV.Vector3 ret = OMV.Vector3.Zero;
@ -476,17 +477,19 @@ public sealed class BSCharacter : BSPhysObject
if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
{
// The character is out of the known/simulated area.
// Upper levels of code will handle the transition to other areas so, for
// the time, we just ignore the position.
return ret;
// Force the avatar position to be within known. ScenePresence will use the position
// plus the velocity to decide if the avatar is moving out of the region.
RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
return true;
}
// If below the ground, move the avatar up
float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
if (Position.Z < terrainHeight)
{
DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
_position.Z = terrainHeight + 2.0f;
DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight);
_position.Z = terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters;
ret = true;
}
if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
@ -806,14 +809,7 @@ public sealed class BSCharacter : BSPhysObject
private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
if (force.IsFinite())
{
float magnitude = force.Length();
if (magnitude > BSParam.MaxAddForceMagnitude)
{
// Force has a limit
force = force / magnitude * BSParam.MaxAddForceMagnitude;
}
OMV.Vector3 addForce = force;
OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
// DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
@ -902,6 +898,7 @@ public sealed class BSCharacter : BSPhysObject
// Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
if (PositionSanityCheck(true))
{
DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position);
entprop.Position = _position;
}

View File

@ -143,7 +143,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
{
enableAngularVerticalAttraction = true;
enableAngularDeflection = false;
enableAngularBanking = false;
enableAngularBanking = true;
if (BSParam.VehicleDebuggingEnabled)
{
enableAngularVerticalAttraction = true;
@ -1280,11 +1280,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
// That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
// TODO: This is here because this is where ODE put it but documentation says it
// is a linear effect. Where should this check go?
if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
{
angularMotorContributionV.X = 0f;
angularMotorContributionV.Y = 0f;
}
//if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
// {
// angularMotorContributionV.X = 0f;
// angularMotorContributionV.Y = 0f;
// }
VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation;
VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", Prim.LocalID, angularMotorContributionV);
@ -1335,7 +1335,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
vertContributionV /= m_verticalAttractionTimescale;
VehicleRotationalVelocity += vertContributionV * VehicleOrientation;
VehicleRotationalVelocity += vertContributionV;
VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}",
Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV,
@ -1439,22 +1439,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin
Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
// Figure out the yaw value for this much roll.
// Squared because that seems to give a good value
float yawAngle = (float)Math.Asin(rollComponents.Y * rollComponents.Y) * m_bankingEfficiency;
float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency;
// actual error = static turn error + dynamic turn error
float mixedYawAngle = yawAngle * (1f - m_bankingMix) + yawAngle * m_bankingMix * VehicleForwardSpeed;
float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed);
// TODO: the banking effect should not go to infinity but what to limit it to?
mixedYawAngle = ClampInRange(-20f, mixedYawAngle, 20f);
// And what should happen when this is being added to a user defined yaw that is already PI*4?
mixedYawAngle = ClampInRange(-12, mixedYawAngle, 12);
// Build the force vector to change rotation from what it is to what it should be
bankingContributionV.Z = -mixedYawAngle;
// Don't do it all at once.
bankingContributionV /= m_bankingTimescale;
// Don't do it all at once. Fudge because 1 second is too fast with most user defined roll as PI*4.
bankingContributionV /= m_bankingTimescale * BSParam.VehicleAngularBankingTimescaleFudge;
//VehicleRotationalVelocity += bankingContributionV * VehicleOrientation;
VehicleRotationalVelocity += bankingContributionV;
VehicleRotationalVelocity += bankingContributionV * VehicleOrientation;
VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
Prim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV);

View File

@ -107,6 +107,7 @@ public static class BSParam
public static float AvatarCapsuleDepth { get; private set; }
public static float AvatarCapsuleHeight { get; private set; }
public static float AvatarContactProcessingThreshold { get; private set; }
public static float AvatarBelowGroundUpCorrectionMeters { get; private set; }
public static float AvatarStepHeight { get; private set; }
public static float AvatarStepApproachFactor { get; private set; }
public static float AvatarStepForceFactor { get; private set; }
@ -122,6 +123,7 @@ public static class BSParam
public static Vector3 VehicleLinearFactor { get; private set; }
public static Vector3 VehicleAngularFactor { get; private set; }
public static float VehicleGroundGravityFudge { get; private set; }
public static float VehicleAngularBankingTimescaleFudge { get; private set; }
public static bool VehicleDebuggingEnabled { get; private set; }
// Linkset implementation parameters
@ -497,6 +499,10 @@ public static class BSParam
0.1f,
(s) => { return AvatarContactProcessingThreshold; },
(s,v) => { AvatarContactProcessingThreshold = v; } ),
new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground",
1.0f,
(s) => { return AvatarBelowGroundUpCorrectionMeters; },
(s,v) => { AvatarBelowGroundUpCorrectionMeters = v; } ),
new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction",
0.3f,
(s) => { return AvatarStepHeight; },
@ -538,10 +544,14 @@ public static class BSParam
0.0f,
(s) => { return VehicleRestitution; },
(s,v) => { VehicleRestitution = v; } ),
new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiple gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
0.2f,
(s) => { return VehicleGroundGravityFudge; },
(s,v) => { VehicleGroundGravityFudge = v; } ),
new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.",
60.0f,
(s) => { return VehicleAngularBankingTimescaleFudge; },
(s,v) => { VehicleAngularBankingTimescaleFudge = v; } ),
new ParameterDefn<bool>("VehicleDebuggingEnable", "Turn on/off vehicle debugging",
false,
(s) => { return VehicleDebuggingEnabled; },

View File

@ -337,6 +337,54 @@ public sealed class BSTerrainManager : IDisposable
return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
}
// Return a new position that is over known terrain if the position is outside our terrain.
public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos)
{
Vector3 ret = pPos;
// Can't do this function if we don't know about any terrain.
if (m_terrains.Count == 0)
return ret;
int loopPrevention = 5;
Vector3 terrainBaseXYZ;
BSTerrainPhys physTerrain;
while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ))
{
// The passed position is not within a known terrain area.
// First, base addresses are never negative so correct for that possible problem.
if (ret.X < 0f || ret.Y < 0f)
{
if (ret.X < 0f)
ret.X = 0f;
if (ret.Y < 0f)
ret.Y = 0f;
DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}",
BSScene.DetailLogZero, pPos, ret);
}
else
{
// Must be off the top of a region. Find an adjacent region to move into.
Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
ret.X = Math.Min(ret.X, adjacentTerrainBase.X + DefaultRegionSize.X);
ret.Y = Math.Min(ret.Y, adjacentTerrainBase.Y + DefaultRegionSize.Y);
DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
}
if (loopPrevention-- < 0f)
{
// The 'while' is a little dangerous so this prevents looping forever if the
// mapping of the terrains ever gets messed up (like nothing at <0,0>) or
// the list of terrains is in transition.
DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero);
break;
}
}
return ret;
}
// Given an X and Y, find the height of the terrain.
// Since we could be handling multiple terrains for a mega-region,
// the base of the region is calcuated assuming all regions are
@ -400,18 +448,60 @@ public sealed class BSTerrainManager : IDisposable
// the descriptor class and the 'base' fo the addresses therein.
private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
{
int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
bool ret = false;
Vector3 terrainBaseXYZ = Vector3.Zero;
if (pos.X < 0f || pos.Y < 0f)
{
// We don't handle negative addresses so just make up a base that will not be found.
terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f);
}
else
{
int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
}
BSTerrainPhys physTerrain = null;
lock (m_terrains)
{
m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
}
outTerrainBase = terrainBaseXYZ;
outPhysTerrain = physTerrain;
return (physTerrain != null);
return ret;
}
// Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than
// this one. Usually used to return an out of bounds object to a known place.
private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase)
{
Vector3 ret = pTerrainBase;
ret.Z = 0f;
lock (m_terrains)
{
// Once down to the <0,0> region, we have to be done.
while (ret.X > 0f && ret.Y > 0f)
{
if (ret.X > 0f)
{
ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X);
DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret);
if (m_terrains.ContainsKey(ret))
break;
}
if (ret.Y > 0f)
{
ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y);
DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret);
if (m_terrains.ContainsKey(ret))
break;
}
}
}
return ret;
}
// Although no one seems to check this, I do support combining.

View File

@ -215,7 +215,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys
float magX = (float)sizeX / extentX;
float magY = (float)sizeY / extentY;
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
if (physicsScene != null)
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
float minHeight = float.MaxValue;
// Note that sizeX+1 vertices are created since there is land between this and the next region.
@ -257,7 +258,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys
}
catch (Exception e)
{
physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
if (physicsScene != null)
physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
LogHeader, physicsScene.RegionName, extentBase, e);
}

View File

@ -68,6 +68,11 @@ public class RegionCombinerLargeLandChannel : ILandChannel
RootRegionLandChannel.Clear(setupDefaultParcel);
}
public ILandObject GetLandObject(Vector3 position)
{
return GetLandObject(position.X, position.Y);
}
public ILandObject GetLandObject(int x, int y)
{
//m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y);

View File

@ -283,6 +283,80 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
}
}
/// <summary>
/// Get a given link entity from a linkset (linked objects and any sitting avatars).
/// </summary>
/// <remarks>
/// If there are any ScenePresence's in the linkset (i.e. because they are sat upon one of the prims), then
/// these are counted as extra entities that correspond to linknums beyond the number of prims in the linkset.
/// The ScenePresences receive linknums in the order in which they sat.
/// </remarks>
/// <returns>
/// The link entity. null if not found.
/// </returns>
/// <param name='linknum'>
/// Can be either a non-negative integer or ScriptBaseClass.LINK_THIS (-4).
/// If ScriptBaseClass.LINK_THIS then the entity containing the script is returned.
/// If the linkset has one entity and a linknum of zero is given, then the single entity is returned. If any
/// positive integer is given in this case then null is returned.
/// If the linkset has more than one entity and a linknum greater than zero but equal to or less than the number
/// of entities, then the entity which corresponds to that linknum is returned.
/// Otherwise, if a positive linknum is given which is greater than the number of entities in the linkset, then
/// null is returned.
/// </param>
public ISceneEntity GetLinkEntity(int linknum)
{
if (linknum < 0)
{
if (linknum == ScriptBaseClass.LINK_THIS)
return m_host;
else
return null;
}
int actualPrimCount = m_host.ParentGroup.PrimCount;
List<UUID> sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars();
int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count;
// Special case for a single prim. In this case the linknum is zero. However, this will not match a single
// prim that has any avatars sat upon it (in which case the root prim is link 1).
if (linknum == 0)
{
if (actualPrimCount == 1 && sittingAvatarIds.Count == 0)
return m_host;
return null;
}
// Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but
// here we must match 1 (ScriptBaseClass.LINK_ROOT).
else if (linknum == ScriptBaseClass.LINK_ROOT && actualPrimCount == 1)
{
if (sittingAvatarIds.Count > 0)
return m_host.ParentGroup.RootPart;
else
return null;
}
else if (linknum <= adjustedPrimCount)
{
if (linknum <= actualPrimCount)
{
return m_host.ParentGroup.GetLinkNumPart(linknum);
}
else
{
ScenePresence sp = World.GetScenePresence(sittingAvatarIds[linknum - actualPrimCount - 1]);
if (sp != null)
return sp;
else
return null;
}
}
else
{
return null;
}
}
public List<SceneObjectPart> GetLinkParts(int linkType)
{
return GetLinkParts(m_host, linkType);
@ -2174,23 +2248,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
q = avatar.CameraRotation; // Mouselook
else
q = avatar.Rotation; // Currently infrequently updated so may be inaccurate
q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate
}
else
q = part.ParentGroup.GroupRotation; // Likely never get here but just in case
}
else
q = part.ParentGroup.GroupRotation; // just the group rotation
return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
return new LSL_Rotation(q);
}
q = part.GetWorldRotation();
return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
return new LSL_Rotation(part.GetWorldRotation());
}
public LSL_Rotation llGetLocalRot()
{
m_host.AddScriptLPS(1);
return new LSL_Rotation(m_host.RotationOffset.X, m_host.RotationOffset.Y, m_host.RotationOffset.Z, m_host.RotationOffset.W);
return new LSL_Rotation(m_host.RotationOffset);
}
public void llSetForce(LSL_Vector force, int local)
@ -2285,8 +2361,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
public LSL_Vector llGetTorque()
{
m_host.AddScriptLPS(1);
Vector3 torque = m_host.ParentGroup.GetTorque();
return new LSL_Vector(torque.X,torque.Y,torque.Z);
return new LSL_Vector(m_host.ParentGroup.GetTorque());
}
public void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local)
@ -2312,19 +2388,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
vel = m_host.Velocity;
}
return new LSL_Vector(vel.X, vel.Y, vel.Z);
return new LSL_Vector(vel);
}
public LSL_Vector llGetAccel()
{
m_host.AddScriptLPS(1);
return new LSL_Vector(m_host.Acceleration.X, m_host.Acceleration.Y, m_host.Acceleration.Z);
return new LSL_Vector(m_host.Acceleration);
}
public LSL_Vector llGetOmega()
{
m_host.AddScriptLPS(1);
return new LSL_Vector(m_host.AngularVelocity.X, m_host.AngularVelocity.Y, m_host.AngularVelocity.Z);
return new LSL_Vector(m_host.AngularVelocity);
}
public LSL_Float llGetTimeOfDay()
@ -3101,13 +3179,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
msg.ParentEstateID = 0; //ParentEstateID;
msg.Position = new Vector3(m_host.AbsolutePosition);
msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid;
Vector3 pos = m_host.AbsolutePosition;
msg.binaryBucket
= Util.StringToBytes256(
"{0}/{1}/{2}/{3}",
World.RegionInfo.RegionName,
(int)Math.Floor(m_host.AbsolutePosition.X),
(int)Math.Floor(m_host.AbsolutePosition.Y),
(int)Math.Floor(m_host.AbsolutePosition.Z));
(int)Math.Floor(pos.X),
(int)Math.Floor(pos.Y),
(int)Math.Floor(pos.Z));
if (m_TransferModule != null)
{
@ -3691,47 +3771,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
m_host.AddScriptLPS(1);
if (linknum < 0)
{
if (linknum == ScriptBaseClass.LINK_THIS)
return m_host.UUID.ToString();
else
return ScriptBaseClass.NULL_KEY;
}
ISceneEntity entity = GetLinkEntity(linknum);
int actualPrimCount = m_host.ParentGroup.PrimCount;
List<UUID> sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars();
int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count;
// Special case for a single prim. In this case the linknum is zero. However, this will not match a single
// prim that has any avatars sat upon it (in which case the root prim is link 1).
if (linknum == 0)
{
if (actualPrimCount == 1 && sittingAvatarIds.Count == 0)
return m_host.UUID.ToString();
return ScriptBaseClass.NULL_KEY;
}
// Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but
// here we must match 1 (ScriptBaseClass.LINK_ROOT).
else if (linknum == 1 && actualPrimCount == 1)
{
if (sittingAvatarIds.Count > 0)
return m_host.ParentGroup.RootPart.UUID.ToString();
else
return ScriptBaseClass.NULL_KEY;
}
else if (linknum <= adjustedPrimCount)
{
if (linknum <= actualPrimCount)
return m_host.ParentGroup.GetLinkNumPart(linknum).UUID.ToString();
else
return sittingAvatarIds[linknum - actualPrimCount - 1].ToString();
}
if (entity != null)
return entity.UUID.ToString();
else
{
return ScriptBaseClass.NULL_KEY;
}
}
/// <summary>
@ -3777,55 +3822,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
m_host.AddScriptLPS(1);
if (linknum < 0)
{
if (linknum == ScriptBaseClass.LINK_THIS)
return m_host.Name;
else
return ScriptBaseClass.NULL_KEY;
}
ISceneEntity entity = GetLinkEntity(linknum);
int actualPrimCount = m_host.ParentGroup.PrimCount;
List<UUID> sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars();
int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count;
// Special case for a single prim. In this case the linknum is zero. However, this will not match a single
// prim that has any avatars sat upon it (in which case the root prim is link 1).
if (linknum == 0)
{
if (actualPrimCount == 1 && sittingAvatarIds.Count == 0)
return m_host.Name;
return ScriptBaseClass.NULL_KEY;
}
// Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but
// here we must match 1 (ScriptBaseClass.LINK_ROOT).
else if (linknum == 1 && actualPrimCount == 1)
{
if (sittingAvatarIds.Count > 0)
return m_host.ParentGroup.RootPart.Name;
else
return ScriptBaseClass.NULL_KEY;
}
else if (linknum <= adjustedPrimCount)
{
if (linknum <= actualPrimCount)
{
return m_host.ParentGroup.GetLinkNumPart(linknum).Name;
}
else
{
ScenePresence sp = World.GetScenePresence(sittingAvatarIds[linknum - actualPrimCount - 1]);
if (sp != null)
return sp.Name;
else
return ScriptBaseClass.NULL_KEY;
}
}
if (entity != null)
return entity.Name;
else
{
return ScriptBaseClass.NULL_KEY;
}
}
public LSL_Integer llGetInventoryNumber(int type)
@ -4170,13 +4172,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
if (presence != null)
{
// agent must be over the owners land
if (m_host.OwnerID == World.LandChannel.GetLandObject(
presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
{
World.TeleportClientHome(agentId, presence.ControllingClient);
}
}
}
ScriptSleep(5000);
}
@ -4197,8 +4199,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
destination = World.RegionInfo.RegionName;
// agent must be over the owners land
if (m_host.OwnerID == World.LandChannel.GetLandObject(
presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
{
DoLLTeleport(presence, destination, targetPos, targetLookAt);
}
@ -4229,8 +4230,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
if (presence.GodLevel >= 200) return;
// agent must be over the owners land
if (m_host.OwnerID == World.LandChannel.GetLandObject(
presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
{
World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
}
@ -4434,7 +4434,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
if (pushrestricted)
{
ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos.X, PusheePos.Y);
ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos);
// We didn't find the parcel but region is push restricted so assume it is NOT ok
if (targetlandObj == null)
@ -4449,7 +4449,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
}
else
{
ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos.X, PusheePos.Y);
ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos);
if (targetlandObj == null)
{
// We didn't find the parcel but region isn't push restricted so assume it's ok
@ -4871,8 +4871,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
public LSL_Vector llGetCenterOfMass()
{
m_host.AddScriptLPS(1);
Vector3 center = m_host.GetCenterOfMass();
return new LSL_Vector(center.X,center.Y,center.Z);
return new LSL_Vector(m_host.GetCenterOfMass());
}
public LSL_List llListSort(LSL_List src, int stride, int ascending)
@ -5703,12 +5703,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
}
ILandObject land;
Vector3 pos;
UUID id = UUID.Zero;
if (parcel || parcelOwned)
{
pos = m_host.ParentGroup.RootPart.GetWorldPosition();
land = World.LandChannel.GetLandObject(pos.X, pos.Y);
land = World.LandChannel.GetLandObject(m_host.ParentGroup.RootPart.GetWorldPosition());
if (land == null)
{
id = UUID.Zero;
@ -5734,8 +5733,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
if (!regionWide)
{
pos = ssp.AbsolutePosition;
land = World.LandChannel.GetLandObject(pos.X, pos.Y);
land = World.LandChannel.GetLandObject(ssp.AbsolutePosition);
if (land != null)
{
if (parcelOwned && land.LandData.OwnerID == id ||
@ -5860,7 +5858,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
if (presence != null)
{
// agent must be over the owners land
ILandObject land = World.LandChannel.GetLandObject(presence.AbsolutePosition.X, presence.AbsolutePosition.Y);
ILandObject land = World.LandChannel.GetLandObject(presence.AbsolutePosition);
if (land == null)
return;
@ -5882,19 +5880,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
ScenePresence presence = World.GetScenePresence(key);
if (presence != null) // object is an avatar
{
if (m_host.OwnerID
== World.LandChannel.GetLandObject(
presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
return 1;
}
else // object is not an avatar
{
SceneObjectPart obj = World.GetSceneObjectPart(key);
if (obj != null)
if (m_host.OwnerID
== World.LandChannel.GetLandObject(
obj.AbsolutePosition.X, obj.AbsolutePosition.Y).LandData.OwnerID)
{
if (m_host.OwnerID == World.LandChannel.GetLandObject(obj.AbsolutePosition).LandData.OwnerID)
return 1;
}
}
}
@ -5972,8 +5969,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
// if the land is group owned and the object is group owned by the same group
// or
// if the object is owned by a person with estate access.
ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition.X, av.AbsolutePosition.Y);
ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition);
if (parcel != null)
{
if (m_host.OwnerID == parcel.LandData.OwnerID ||
@ -5985,14 +5981,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
}
}
}
}
}
public LSL_Vector llGroundSlope(LSL_Vector offset)
{
m_host.AddScriptLPS(1);
//Get the slope normal. This gives us the equation of the plane tangent to the slope.
LSL_Vector vsn = llGroundNormal(offset);
@ -6003,7 +5998,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
vsl.Normalize();
//Normalization might be overkill here
return new LSL_Vector(vsl.X, vsl.Y, vsl.Z);
vsn.x = vsl.X;
vsn.y = vsl.Y;
vsn.z = vsl.Z;
return vsn;
}
public LSL_Vector llGroundNormal(LSL_Vector offset)
@ -6053,7 +6052,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
//I believe the crossproduct of two normalized vectors is a normalized vector so
//this normalization may be overkill
return new LSL_Vector(vsn.X, vsn.Y, vsn.Z);
return new LSL_Vector(vsn);
}
public LSL_Vector llGroundContour(LSL_Vector offset)
@ -6069,7 +6068,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
return m_host.ParentGroup.AttachmentPoint;
}
public LSL_Integer llGetFreeMemory()
public virtual LSL_Integer llGetFreeMemory()
{
m_host.AddScriptLPS(1);
// Make scripts designed for LSO happy
@ -6553,7 +6552,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
m_host.AddScriptLPS(1);
UUID key;
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
{
int expires = 0;
@ -7782,7 +7782,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
m_host.AddScriptLPS(1);
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
if (land.LandData.OwnerID != m_host.OwnerID)
return;
@ -7796,7 +7796,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
m_host.AddScriptLPS(1);
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
if (land.LandData.OwnerID != m_host.OwnerID)
return String.Empty;
@ -7807,8 +7807,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
public LSL_Vector llGetRootPosition()
{
m_host.AddScriptLPS(1);
return new LSL_Vector(m_host.ParentGroup.AbsolutePosition.X, m_host.ParentGroup.AbsolutePosition.Y,
m_host.ParentGroup.AbsolutePosition.Z);
return new LSL_Vector(m_host.ParentGroup.AbsolutePosition);
}
/// <summary>
@ -7831,13 +7831,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
q = avatar.CameraRotation; // Mouselook
else
q = avatar.Rotation; // Currently infrequently updated so may be inaccurate
q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate
else
q = m_host.ParentGroup.GroupRotation; // Likely never get here but just in case
}
else
q = m_host.ParentGroup.GroupRotation; // just the group rotation
return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
return new LSL_Rotation(q);
}
public LSL_String llGetObjectDesc()
@ -7944,7 +7945,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
public LSL_Vector llGetGeometricCenter()
{
return new LSL_Vector(m_host.GetGeometricCenter().X, m_host.GetGeometricCenter().Y, m_host.GetGeometricCenter().Z);
return new LSL_Vector(m_host.GetGeometricCenter());
}
public LSL_List llGetPrimitiveParams(LSL_List rules)
@ -8031,23 +8032,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
break;
case (int)ScriptBaseClass.PRIM_POSITION:
LSL_Vector v = new LSL_Vector(part.AbsolutePosition.X,
part.AbsolutePosition.Y,
part.AbsolutePosition.Z);
LSL_Vector v = new LSL_Vector(part.AbsolutePosition);
// For some reason, the part.AbsolutePosition.* values do not change if the
// linkset is rotated; they always reflect the child prim's world position
// as though the linkset is unrotated. This is incompatible behavior with SL's
// implementation, so will break scripts imported from there (not to mention it
// makes it more difficult to determine a child prim's actual inworld position).
if (part.ParentID != 0)
v = ((v - llGetRootPosition()) * llGetRootRotation()) + llGetRootPosition();
if (!part.IsRoot)
{
LSL_Vector rootPos = new LSL_Vector(m_host.ParentGroup.AbsolutePosition);
v = ((v - rootPos) * llGetRootRotation()) + rootPos;
}
res.Add(v);
break;
case (int)ScriptBaseClass.PRIM_SIZE:
res.Add(new LSL_Vector(part.Scale.X,
part.Scale.Y,
part.Scale.Z));
res.Add(new LSL_Vector(part.Scale));
break;
case (int)ScriptBaseClass.PRIM_ROTATION:
@ -8362,7 +8364,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
res.Add(new LSL_String(part.Description));
break;
case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
res.Add(new LSL_Rotation(part.RotationOffset.X, part.RotationOffset.Y, part.RotationOffset.Z, part.RotationOffset.W));
res.Add(new LSL_Rotation(part.RotationOffset));
break;
case (int)ScriptBaseClass.PRIM_POS_LOCAL:
res.Add(new LSL_Vector(GetPartLocalPos(part)));
@ -9571,7 +9573,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
// according to the docs, this command only works if script owner and land owner are the same
// lets add estate owners and gods, too, and use the generic permission check.
ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, landObject, GroupPowers.ChangeMedia)) return;
bool update = false; // send a ParcelMediaUpdate (and possibly change the land's media URL)?
@ -9890,21 +9892,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
m_host.AddScriptLPS(1);
if (m_item.PermsGranter == UUID.Zero)
return new LSL_Vector();
return Vector3.Zero;
if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
{
ShoutError("No permissions to track the camera");
return new LSL_Vector();
return Vector3.Zero;
}
ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
if (presence != null)
{
LSL_Vector pos = new LSL_Vector(presence.CameraPosition.X, presence.CameraPosition.Y, presence.CameraPosition.Z);
LSL_Vector pos = new LSL_Vector(presence.CameraPosition);
return pos;
}
return new LSL_Vector();
return Vector3.Zero;
}
public LSL_Rotation llGetCameraRot()
@ -9912,21 +9915,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
m_host.AddScriptLPS(1);
if (m_item.PermsGranter == UUID.Zero)
return new LSL_Rotation();
return Quaternion.Identity;
if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
{
ShoutError("No permissions to track the camera");
return new LSL_Rotation();
return Quaternion.Identity;
}
ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
if (presence != null)
{
return new LSL_Rotation(presence.CameraRotation.X, presence.CameraRotation.Y, presence.CameraRotation.Z, presence.CameraRotation.W);
return new LSL_Rotation(presence.CameraRotation);
}
return new LSL_Rotation();
return Quaternion.Identity;
}
/// <summary>
@ -9995,7 +9998,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
m_host.AddScriptLPS(1);
UUID key;
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
{
int expires = 0;
@ -10036,7 +10039,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
m_host.AddScriptLPS(1);
UUID key;
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageAllowed))
{
if (UUID.TryParse(avatar, out key))
@ -10063,7 +10066,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
m_host.AddScriptLPS(1);
UUID key;
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
{
if (UUID.TryParse(avatar, out key))
@ -10325,7 +10328,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
public void llResetLandBanList()
{
m_host.AddScriptLPS(1);
LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).LandData;
LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData;
if (land.OwnerID == m_host.OwnerID)
{
foreach (LandAccessEntry entry in land.ParcelAccessList)
@ -10342,7 +10345,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
public void llResetLandPassList()
{
m_host.AddScriptLPS(1);
LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).LandData;
LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData;
if (land.OwnerID == m_host.OwnerID)
{
foreach (LandAccessEntry entry in land.ParcelAccessList)
@ -10518,7 +10521,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
ret.Add(new LSL_Vector((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z));
break;
case ScriptBaseClass.OBJECT_ROT:
ret.Add(new LSL_Rotation((double)av.Rotation.X, (double)av.Rotation.Y, (double)av.Rotation.Z, (double)av.Rotation.W));
ret.Add(new LSL_Rotation(av.GetWorldRotation()));
break;
case ScriptBaseClass.OBJECT_VELOCITY:
ret.Add(new LSL_Vector(av.Velocity.X, av.Velocity.Y, av.Velocity.Z));
@ -10920,7 +10923,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
LSL_List result = new LSL_List();
if (obj != null && obj.OwnerID != m_host.OwnerID)
if (obj != null && obj.OwnerID == m_host.OwnerID)
{
LSL_List remaining = GetPrimParams(obj, rules, ref result);
@ -11021,7 +11024,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
World.ForEachScenePresence(delegate(ScenePresence sp)
{
Vector3 ac = sp.AbsolutePosition - rayStart;
Vector3 bc = sp.AbsolutePosition - rayEnd;
// Vector3 bc = sp.AbsolutePosition - rayEnd;
double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd));
@ -11111,7 +11114,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
radius = Math.Abs(maxZ);
radius = radius*1.413f;
Vector3 ac = group.AbsolutePosition - rayStart;
Vector3 bc = group.AbsolutePosition - rayEnd;
// Vector3 bc = group.AbsolutePosition - rayEnd;
double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd));
@ -11455,7 +11458,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
list.Add(new LSL_Integer(linkNum));
if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL)
list.Add(new LSL_Vector(result.Normal.X, result.Normal.Y, result.Normal.Z));
list.Add(new LSL_Vector(result.Normal));
values++;
if (values >= count)
@ -11557,7 +11560,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
return 16384;
}
public LSL_Integer llGetUsedMemory()
public virtual LSL_Integer llGetUsedMemory()
{
m_host.AddScriptLPS(1);
// The value returned for LSO scripts in SL

View File

@ -266,6 +266,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
llist[i] = new LSL_Float((float)result[i]);
}
else if (result[i] is double)
{
llist[i] = new LSL_Float((double)result[i]);
}
else if (result[i] is UUID)
{
llist[i] = new LSL_Key(result[i].ToString());

View File

@ -363,7 +363,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
//OSSL only may be used if object is in the same group as the parcel
if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_GROUP_MEMBER"))
{
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
if (land.LandData.GroupID == m_item.GroupID && land.LandData.GroupID != UUID.Zero)
{
@ -374,7 +374,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
//Only Parcelowners may use the function
if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_OWNER"))
{
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
if (land.LandData.OwnerID == ownerID)
{
@ -1502,8 +1502,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
m_host.AddScriptLPS(1);
ILandObject land
= World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
if (land.LandData.OwnerID != m_host.OwnerID)
return;
@ -1519,8 +1518,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
m_host.AddScriptLPS(1);
ILandObject land
= World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
if (land.LandData.OwnerID != m_host.OwnerID)
{
@ -2515,13 +2513,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
ScenePresence sp = World.GetScenePresence(npcId);
if (sp != null)
{
Vector3 pos = sp.AbsolutePosition;
return new LSL_Vector(pos.X, pos.Y, pos.Z);
}
return new LSL_Vector(sp.AbsolutePosition);
}
return new LSL_Vector(0, 0, 0);
return Vector3.Zero;
}
public void osNpcMoveTo(LSL_Key npc, LSL_Vector pos)
@ -2578,21 +2573,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
{
UUID npcId;
if (!UUID.TryParse(npc.m_string, out npcId))
return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W);
return new LSL_Rotation(Quaternion.Identity);
if (!npcModule.CheckPermissions(npcId, m_host.OwnerID))
return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W);
return new LSL_Rotation(Quaternion.Identity);
ScenePresence sp = World.GetScenePresence(npcId);
if (sp != null)
{
Quaternion rot = sp.Rotation;
return new LSL_Rotation(rot.X, rot.Y, rot.Z, rot.W);
}
return new LSL_Rotation(sp.GetWorldRotation());
}
return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W);
return Quaternion.Identity;
}
public void osNpcSetRot(LSL_Key npc, LSL_Rotation rotation)
@ -3022,20 +3014,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
UUID avatarId = new UUID(avatar);
ScenePresence presence = World.GetScenePresence(avatarId);
Vector3 pos = m_host.GetWorldPosition();
bool result = World.ScriptDanger(m_host.LocalId, new Vector3((float)pos.X, (float)pos.Y, (float)pos.Z));
if (result)
if (presence != null && World.ScriptDanger(m_host.LocalId, m_host.GetWorldPosition()))
{
if (presence != null)
{
float health = presence.Health;
health += (float)healing;
if (health >= 100)
{
health = 100;
}
presence.setHealthWithUpdate(health);
}
float health = presence.Health;
health += (float)healing;
if (health >= 100)
health = 100;
presence.setHealthWithUpdate(health);
}
}
@ -3112,8 +3100,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
if (avatar != null && avatar.UUID != m_host.OwnerID)
{
result.Add(new LSL_String(avatar.UUID.ToString()));
OpenMetaverse.Vector3 ap = avatar.AbsolutePosition;
result.Add(new LSL_Vector(ap.X, ap.Y, ap.Z));
result.Add(new LSL_Vector(avatar.AbsolutePosition));
result.Add(new LSL_String(avatar.Name));
}
});

View File

@ -353,7 +353,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
// Position of a sensor in a child prim attached to an avatar
// will be still wrong.
ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar);
q = avatar.Rotation * q;
q = avatar.GetWorldRotation() * q;
}
LSL_Types.Quaternion r = new LSL_Types.Quaternion(q);
@ -480,7 +480,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
// Position of a sensor in a child prim attached to an avatar
// will be still wrong.
ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar);
q = avatar.Rotation * q;
q = avatar.GetWorldRotation() * q;
}
LSL_Types.Quaternion r = new LSL_Types.Quaternion(q);

View File

@ -662,13 +662,18 @@ namespace SecondLife
{
string severity = CompErr.IsWarning ? "Warning" : "Error";
KeyValuePair<int, int> lslPos;
KeyValuePair<int, int> errorPos;
// Show 5 errors max, but check entire list for errors
if (severity == "Error")
{
lslPos = FindErrorPosition(CompErr.Line, CompErr.Column, m_lineMaps[assembly]);
// C# scripts will not have a linemap since theres no line translation involved.
if (!m_lineMaps.ContainsKey(assembly))
errorPos = new KeyValuePair<int, int>(CompErr.Line, CompErr.Column);
else
errorPos = FindErrorPosition(CompErr.Line, CompErr.Column, m_lineMaps[assembly]);
string text = CompErr.ErrorText;
// Use LSL type names
@ -678,7 +683,7 @@ namespace SecondLife
// The Second Life viewer's script editor begins
// countingn lines and columns at 0, so we subtract 1.
errtext += String.Format("({0},{1}): {4} {2}: {3}\n",
lslPos.Key - 1, lslPos.Value - 1,
errorPos.Key - 1, errorPos.Value - 1,
CompErr.ErrorNumber, text, severity);
hadErrors = true;
}

View File

@ -209,7 +209,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
+= (itemId, evp) => m_lslApi.llHTTPResponse(evp.Params[0].ToString(), 200, testResponse);
// Console.WriteLine("Trying {0}", returnedUri);
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(returnedUri);
AssertHttpResponse(returnedUri, testResponse);

View File

@ -138,17 +138,17 @@ namespace OpenSim.Server.Base
case ExtensionChange.Add:
if (a.AddinFile.Contains(Registry.DefaultAddinsFolder))
{
m_log.InfoFormat("[SERVER]: Adding {0} from registry", a.Name);
m_log.InfoFormat("[SERVER UTILS]: Adding {0} from registry", a.Name);
connector.PluginPath = System.IO.Path.Combine(Registry.DefaultAddinsFolder,a.Name.Replace(',', '.')); }
else
{
m_log.InfoFormat("[SERVER]: Adding {0} from ./bin", a.Name);
m_log.InfoFormat("[SERVER UTILS]: Adding {0} from ./bin", a.Name);
connector.PluginPath = a.AddinFile;
}
LoadPlugin(connector);
break;
case ExtensionChange.Remove:
m_log.InfoFormat("[SERVER]: Removing {0}", a.Name);
m_log.InfoFormat("[SERVER UTILS]: Removing {0}", a.Name);
UnloadPlugin(connector);
break;
}
@ -166,13 +166,13 @@ namespace OpenSim.Server.Base
}
else
{
m_log.InfoFormat("[SERVER]: {0} Disabled.", connector.ConfigName);
m_log.InfoFormat("[SERVER UTILS]: {0} Disabled.", connector.ConfigName);
}
}
private void UnloadPlugin(IRobustConnector connector)
{
m_log.InfoFormat("[Server]: Unloading {0}", connector.ConfigName);
m_log.InfoFormat("[SERVER UTILS]: Unloading {0}", connector.ConfigName);
connector.Unload();
}
@ -280,7 +280,7 @@ namespace OpenSim.Server.Base
{
if (!(e is System.MissingMethodException))
{
m_log.ErrorFormat("Error loading plugin {0} from {1}. Exception: {2}, {3}",
m_log.ErrorFormat("[SERVER UTILS]: Error loading plugin {0} from {1}. Exception: {2}, {3}",
interfaceName,
dllName,
e.InnerException == null ? e.Message : e.InnerException.Message,
@ -298,14 +298,14 @@ namespace OpenSim.Server.Base
}
catch (ReflectionTypeLoadException rtle)
{
m_log.Error(string.Format("Error loading plugin from {0}:\n{1}", dllName,
m_log.Error(string.Format("[SERVER UTILS]: Error loading plugin from {0}:\n{1}", dllName,
String.Join("\n", Array.ConvertAll(rtle.LoaderExceptions, e => e.ToString()))),
rtle);
return null;
}
catch (Exception e)
{
m_log.Error(string.Format("Error loading plugin from {0}", dllName), e);
m_log.Error(string.Format("[SERVER UTILS]: Error loading plugin from {0}", dllName), e);
return null;
}
}
@ -517,7 +517,7 @@ namespace OpenSim.Server.Base
public static IConfigSource LoadInitialConfig(string url)
{
IConfigSource source = new XmlConfigSource();
m_log.InfoFormat("[CONFIG]: {0} is a http:// URI, fetching ...", url);
m_log.InfoFormat("[SERVER UTILS]: {0} is a http:// URI, fetching ...", url);
// The ini file path is a http URI
// Try to read it
@ -529,7 +529,7 @@ namespace OpenSim.Server.Base
}
catch (Exception e)
{
m_log.FatalFormat("[CONFIG]: Exception reading config from URI {0}\n" + e.ToString(), url);
m_log.FatalFormat("[SERVER UTILS]: Exception reading config from URI {0}\n" + e.ToString(), url);
Environment.Exit(1);
}

View File

@ -186,10 +186,7 @@ namespace OpenSim.Server.Base
XmlConfigurator.Configure();
}
// FIXME: This should be done down in ServerBase but we need to sort out and refactor the log4net
// XmlConfigurator calls first accross servers.
m_log.InfoFormat("[SERVER BASE]: Starting in {0}", m_startupDirectory);
LogEnvironmentInformation();
RegisterCommonAppenders(startupConfig);
if (startupConfig.GetString("PIDFile", String.Empty) != String.Empty)

View File

@ -145,7 +145,7 @@ namespace OpenSim.Server
}
else
{
m_log.InfoFormat("[SERVER]: Failed to load {0}", conn);
m_log.ErrorFormat("[SERVER]: Failed to load {0}", conn);
}
}

View File

@ -124,45 +124,31 @@ namespace OpenSim.Services.AssetService
{
// m_log.DebugFormat("[ASSET SERVICE]: Get asset metadata for {0}", id);
UUID assetID;
AssetBase asset = Get(id);
if (!UUID.TryParse(id, out assetID))
return null;
AssetBase asset = m_Database.GetAsset(assetID);
if (asset != null)
return asset.Metadata;
return null;
else
return null;
}
public virtual byte[] GetData(string id)
{
// m_log.DebugFormat("[ASSET SERVICE]: Get asset data for {0}", id);
UUID assetID;
AssetBase asset = Get(id);
if (!UUID.TryParse(id, out assetID))
if (asset != null)
return asset.Data;
else
return null;
AssetBase asset = m_Database.GetAsset(assetID);
return asset.Data;
}
public virtual bool Get(string id, Object sender, AssetRetrieved handler)
{
//m_log.DebugFormat("[AssetService]: Get asset async {0}", id);
UUID assetID;
if (!UUID.TryParse(id, out assetID))
return false;
AssetBase asset = m_Database.GetAsset(assetID);
//m_log.DebugFormat("[AssetService]: Got asset {0}", asset);
handler(id, sender, asset);
handler(id, sender, Get(id));
return true;
}

View File

@ -39,8 +39,7 @@ using OpenMetaverse;
namespace OpenSim.Services.AssetService
{
/// <summary>
/// This will be developed into a de-duplicating asset service.
/// XXX: Currently it's a just a copy of the existing AssetService. so please don't attempt to use it.
/// A de-duplicating asset service.
/// </summary>
public class XAssetService : XAssetServiceBase, IAssetService
{
@ -48,7 +47,9 @@ namespace OpenSim.Services.AssetService
protected static XAssetService m_RootInstance;
public XAssetService(IConfigSource config) : base(config)
public XAssetService(IConfigSource config) : this(config, "AssetService") {}
public XAssetService(IConfigSource config, string configName) : base(config, configName)
{
if (m_RootInstance == null)
{
@ -56,22 +57,21 @@ namespace OpenSim.Services.AssetService
if (m_AssetLoader != null)
{
IConfig assetConfig = config.Configs["AssetService"];
IConfig assetConfig = config.Configs[configName];
if (assetConfig == null)
throw new Exception("No AssetService configuration");
string loaderArgs = assetConfig.GetString("AssetLoaderArgs",
String.Empty);
string loaderArgs = assetConfig.GetString("AssetLoaderArgs", String.Empty);
bool assetLoaderEnabled = assetConfig.GetBoolean("AssetLoaderEnabled", true);
if (assetLoaderEnabled)
if (assetLoaderEnabled && !HasChainedAssetService)
{
m_log.DebugFormat("[XASSET SERVICE]: Loading default asset set from {0}", loaderArgs);
m_AssetLoader.ForEachDefaultXmlAsset(
loaderArgs,
delegate(AssetBase a)
a =>
{
AssetBase existingAsset = Get(a.ID);
// AssetMetadata existingMetadata = GetMetadata(a.ID);
@ -103,7 +103,23 @@ namespace OpenSim.Services.AssetService
try
{
return m_Database.GetAsset(assetID);
AssetBase asset = m_Database.GetAsset(assetID);
if (asset != null)
{
return asset;
}
else if (HasChainedAssetService)
{
asset = m_ChainedAssetService.Get(id);
if (asset != null)
MigrateFromChainedService(asset);
return asset;
}
return null;
}
catch (Exception e)
{
@ -121,29 +137,24 @@ namespace OpenSim.Services.AssetService
{
// m_log.DebugFormat("[XASSET SERVICE]: Get asset metadata for {0}", id);
UUID assetID;
AssetBase asset = Get(id);
if (!UUID.TryParse(id, out assetID))
return null;
AssetBase asset = m_Database.GetAsset(assetID);
if (asset != null)
return asset.Metadata;
return null;
else
return null;
}
public virtual byte[] GetData(string id)
{
// m_log.DebugFormat("[XASSET SERVICE]: Get asset data for {0}", id);
UUID assetID;
AssetBase asset = Get(id);
if (!UUID.TryParse(id, out assetID))
if (asset != null)
return asset.Data;
else
return null;
AssetBase asset = m_Database.GetAsset(assetID);
return asset.Data;
}
public virtual bool Get(string id, Object sender, AssetRetrieved handler)
@ -155,7 +166,7 @@ namespace OpenSim.Services.AssetService
if (!UUID.TryParse(id, out assetID))
return false;
AssetBase asset = m_Database.GetAsset(assetID);
AssetBase asset = Get(id);
//m_log.DebugFormat("[XASSET SERVICE]: Got asset {0}", asset);
@ -194,7 +205,15 @@ namespace OpenSim.Services.AssetService
if (!UUID.TryParse(id, out assetID))
return false;
// Don't bother deleting from a chained asset service. This isn't a big deal since deleting happens
// very rarely.
return m_Database.Delete(id);
}
private void MigrateFromChainedService(AssetBase asset)
{
Util.FireAndForget(o => { Store(asset); m_ChainedAssetService.Delete(asset.ID); });
}
}
}

View File

@ -27,9 +27,11 @@
using System;
using System.Reflection;
using log4net;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Data;
using OpenSim.Server.Base;
using OpenSim.Services.Interfaces;
using OpenSim.Services.Base;
@ -37,10 +39,15 @@ namespace OpenSim.Services.AssetService
{
public class XAssetServiceBase : ServiceBase
{
protected IXAssetDataPlugin m_Database = null;
protected IAssetLoader m_AssetLoader = null;
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public XAssetServiceBase(IConfigSource config) : base(config)
protected IXAssetDataPlugin m_Database;
protected IAssetLoader m_AssetLoader;
protected IAssetService m_ChainedAssetService;
protected bool HasChainedAssetService { get { return m_ChainedAssetService != null; } }
public XAssetServiceBase(IConfigSource config, string configName) : base(config)
{
string dllName = String.Empty;
string connString = String.Empty;
@ -48,7 +55,7 @@ namespace OpenSim.Services.AssetService
//
// Try reading the [AssetService] section first, if it exists
//
IConfig assetConfig = config.Configs["AssetService"];
IConfig assetConfig = config.Configs[configName];
if (assetConfig != null)
{
dllName = assetConfig.GetString("StorageProvider", dllName);
@ -77,17 +84,35 @@ namespace OpenSim.Services.AssetService
if (m_Database == null)
throw new Exception("Could not find a storage interface in the given module");
string chainedAssetServiceDesignator = assetConfig.GetString("ChainedServiceModule", null);
if (chainedAssetServiceDesignator != null)
{
m_log.InfoFormat(
"[XASSET SERVICE BASE]: Loading chained asset service from {0}", chainedAssetServiceDesignator);
Object[] args = new Object[] { config, configName };
m_ChainedAssetService = ServerUtils.LoadPlugin<IAssetService>(chainedAssetServiceDesignator, args);
if (!HasChainedAssetService)
throw new Exception(
String.Format("Failed to load ChainedAssetService from {0}", chainedAssetServiceDesignator));
}
m_Database.Initialise(connString);
string loaderName = assetConfig.GetString("DefaultAssetLoader",
String.Empty);
if (loaderName != String.Empty)
if (HasChainedAssetService)
{
m_AssetLoader = LoadPlugin<IAssetLoader>(loaderName);
string loaderName = assetConfig.GetString("DefaultAssetLoader",
String.Empty);
if (m_AssetLoader == null)
throw new Exception("Asset loader could not be loaded");
if (loaderName != String.Empty)
{
m_AssetLoader = LoadPlugin<IAssetLoader>(loaderName);
if (m_AssetLoader == null)
throw new Exception("Asset loader could not be loaded");
}
}
}
}

View File

@ -60,6 +60,8 @@ namespace OpenSim.Tests.Common.Mock
public List<ImagePacketPacket> SentImagePacketPackets { get; private set; }
public List<ImageNotInDatabasePacket> SentImageNotInDatabasePackets { get; private set; }
public event Action<RegionInfo, Vector3, Vector3> OnReceivedMoveAgentIntoRegion;
// disable warning: public events, part of the public API
#pragma warning disable 67
@ -566,6 +568,8 @@ namespace OpenSim.Tests.Common.Mock
public virtual void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
{
if (OnReceivedMoveAgentIntoRegion != null)
OnReceivedMoveAgentIntoRegion(regInfo, pos, look);
}
public virtual AgentCircuitData RequestClientInfo()

View File

@ -0,0 +1,178 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Reflection;
using System.Threading;
using log4net;
using Nini.Config;
using Mono.Addins;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.Tests.Common
{
public class TestEventQueueGetModule : IEventQueue, INonSharedRegionModule
{
public class Event
{
public string Name { get; set; }
public object[] Args { get; set; }
public Event(string name, object[] args)
{
name = Name;
args = Args;
}
}
public Dictionary<UUID, List<Event>> Events { get; set; }
public void Initialise(IConfigSource source) {}
public void Close() {}
public void AddRegion(Scene scene)
{
Events = new Dictionary<UUID, List<Event>>();
scene.RegisterModuleInterface<IEventQueue>(this);
}
public void RemoveRegion (Scene scene) {}
public void RegionLoaded (Scene scene) {}
public string Name { get { return "TestEventQueueGetModule"; } }
public Type ReplaceableInterface { get { return null; } }
private void AddEvent(UUID avatarID, string name, params object[] args)
{
Console.WriteLine("Adding event {0} for {1}", name, avatarID);
List<Event> avEvents;
if (!Events.ContainsKey(avatarID))
{
avEvents = new List<Event>();
Events[avatarID] = avEvents;
}
else
{
avEvents = Events[avatarID];
}
avEvents.Add(new Event(name, args));
}
public void ClearEvents()
{
if (Events != null)
Events.Clear();
}
public bool Enqueue(OSD o, UUID avatarID)
{
AddEvent(avatarID, "Enqueue", o);
return true;
}
public void DisableSimulator(ulong handle, UUID avatarID)
{
AddEvent(avatarID, "DisableSimulator", handle);
}
public void EnableSimulator (ulong handle, IPEndPoint endPoint, UUID avatarID)
{
AddEvent(avatarID, "EnableSimulator", handle);
}
public void EstablishAgentCommunication (UUID avatarID, IPEndPoint endPoint, string capsPath)
{
AddEvent(avatarID, "EstablishAgentCommunication", endPoint, capsPath);
}
public void TeleportFinishEvent (ulong regionHandle, byte simAccess, IPEndPoint regionExternalEndPoint, uint locationID, uint flags, string capsURL, UUID agentID)
{
AddEvent(agentID, "TeleportFinishEvent", regionHandle, simAccess, regionExternalEndPoint, locationID, flags, capsURL);
}
public void CrossRegion (ulong handle, Vector3 pos, Vector3 lookAt, IPEndPoint newRegionExternalEndPoint, string capsURL, UUID avatarID, UUID sessionID)
{
AddEvent(avatarID, "CrossRegion", handle, pos, lookAt, newRegionExternalEndPoint, capsURL, sessionID);
}
public void ChatterboxInvitation(
UUID sessionID, string sessionName, UUID fromAgent, string message, UUID toAgent, string fromName,
byte dialog, uint timeStamp, bool offline, int parentEstateID, Vector3 position, uint ttl,
UUID transactionID, bool fromGroup, byte[] binaryBucket)
{
AddEvent(
toAgent, "ChatterboxInvitation", sessionID, sessionName, fromAgent, message, toAgent, fromName, dialog,
timeStamp, offline, parentEstateID, position, ttl, transactionID, fromGroup, binaryBucket);
}
public void ChatterBoxSessionAgentListUpdates (UUID sessionID, UUID fromAgent, UUID toAgent, bool canVoiceChat, bool isModerator, bool textMute)
{
AddEvent(toAgent, "ChatterBoxSessionAgentListUpdates", sessionID, fromAgent, canVoiceChat, isModerator, textMute);
}
public void ParcelProperties (OpenMetaverse.Messages.Linden.ParcelPropertiesMessage parcelPropertiesMessage, UUID avatarID)
{
AddEvent(avatarID, "ParcelProperties", parcelPropertiesMessage);
}
public void GroupMembership (OpenMetaverse.Packets.AgentGroupDataUpdatePacket groupUpdate, UUID avatarID)
{
AddEvent(avatarID, "GroupMembership", groupUpdate);
}
public OSD ScriptRunningEvent (UUID objectID, UUID itemID, bool running, bool mono)
{
Console.WriteLine("ONE");
throw new System.NotImplementedException ();
}
public OSD BuildEvent (string eventName, OSD eventBody)
{
Console.WriteLine("TWO");
throw new System.NotImplementedException ();
}
public void partPhysicsProperties (uint localID, byte physhapetype, float density, float friction, float bounce, float gravmod, UUID avatarID)
{
AddEvent(avatarID, "partPhysicsProperties", localID, physhapetype, density, friction, bounce, gravmod);
}
}
}

View File

@ -81,6 +81,11 @@ namespace OpenSim.Tests.Common.Mock
return obj;
}
public ILandObject GetLandObject(Vector3 position)
{
return GetLandObject(position.X, position.Y);
}
public ILandObject GetLandObject(int x, int y)
{
return GetNoLand();

Binary file not shown.

Binary file not shown.

View File

@ -1669,6 +1669,65 @@
A header have been received.
</summary>
</member>
<member name="T:HttpServer.LocklessQueue`1">
<summary>
A thread-safe lockless queue that supports multiple readers and
multiple writers
</summary>
</member>
<member name="F:HttpServer.LocklessQueue`1.head">
<summary>Queue head</summary>
</member>
<member name="F:HttpServer.LocklessQueue`1.tail">
<summary>Queue tail</summary>
</member>
<member name="F:HttpServer.LocklessQueue`1.count">
<summary>Queue item count</summary>
</member>
<member name="M:HttpServer.LocklessQueue`1.#ctor">
<summary>
Constructor
</summary>
</member>
<member name="M:HttpServer.LocklessQueue`1.Enqueue(`0)">
<summary>
Enqueue an item
</summary>
<param name="item">Item to enqeue</param>
</member>
<member name="M:HttpServer.LocklessQueue`1.TryDequeue(`0@)">
<summary>
Try to dequeue an item
</summary>
<param name="item">Dequeued item if the dequeue was successful</param>
<returns>True if an item was successfully deqeued, otherwise false</returns>
</member>
<member name="P:HttpServer.LocklessQueue`1.Count">
<summary>Gets the current number of items in the queue. Since this
is a lockless collection this value should be treated as a close
estimate</summary>
</member>
<member name="T:HttpServer.LocklessQueue`1.SingleLinkNode">
<summary>
Provides a node container for data in a singly linked list
</summary>
</member>
<member name="F:HttpServer.LocklessQueue`1.SingleLinkNode.Next">
<summary>Pointer to the next node in list</summary>
</member>
<member name="F:HttpServer.LocklessQueue`1.SingleLinkNode.Item">
<summary>The data contained by the node</summary>
</member>
<member name="M:HttpServer.LocklessQueue`1.SingleLinkNode.#ctor">
<summary>
Constructor
</summary>
</member>
<member name="M:HttpServer.LocklessQueue`1.SingleLinkNode.#ctor(`0)">
<summary>
Constructor
</summary>
</member>
<member name="T:HttpServer.IHttpRequest">
<summary>
Contains server side HTTP request information.
@ -2825,6 +2884,11 @@
<param name="protocol">Kind of HTTPS protocol. Usually TLS or SSL.</param>
<returns>A created <see cref="T:HttpServer.IHttpClientContext"/>.</returns>
</member>
<member name="M:HttpServer.IHttpContextFactory.Shutdown">
<summary>
Server is shutting down so shut down the factory
</summary>
</member>
<member name="E:HttpServer.IHttpContextFactory.RequestReceived">
<summary>
A request have been received from one of the contexts.
@ -2876,6 +2940,11 @@
A creates <see cref="T:HttpServer.IHttpClientContext"/>.
</returns>
</member>
<member name="M:HttpServer.HttpContextFactory.Shutdown">
<summary>
Server is shutting down so shut down the factory
</summary>
</member>
<member name="P:HttpServer.HttpContextFactory.UseTraceLogs">
<summary>
True if detailed trace logs should be written.
@ -4315,6 +4384,58 @@
</summary>
<param name="message">message describing the error</param>
</member>
<member name="T:HttpServer.ContextTimeoutManager">
<summary>
Timeout Manager. Checks for dead clients. Clients with open connections that are not doing anything. Closes sessions opened with keepalive.
</summary>
</member>
<member name="M:HttpServer.ContextTimeoutManager.ProcessContextTimeouts">
<summary>
Causes the watcher to immediately check the connections.
</summary>
</member>
<member name="M:HttpServer.ContextTimeoutManager.EnvironmentTickCount">
<summary>
Environment.TickCount is an int but it counts all 32 bits so it goes positive
and negative every 24.9 days. This trims down TickCount so it doesn't wrap
for the callers.
This trims it to a 12 day interval so don't let your frame time get too long.
</summary>
<returns></returns>
</member>
<member name="M:HttpServer.ContextTimeoutManager.EnvironmentTickCountSubtract(System.Int32,System.Int32)">
<summary>
Environment.TickCount is an int but it counts all 32 bits so it goes positive
and negative every 24.9 days. Subtracts the passed value (previously fetched by
'EnvironmentTickCount()') and accounts for any wrapping.
</summary>
<param name="newValue"></param>
<param name="prevValue"></param>
<returns>subtraction of passed prevValue from current Environment.TickCount</returns>
</member>
<member name="M:HttpServer.ContextTimeoutManager.EnvironmentTickCountAdd(System.Int32,System.Int32)">
<summary>
Environment.TickCount is an int but it counts all 32 bits so it goes positive
and negative every 24.9 days. Subtracts the passed value (previously fetched by
'EnvironmentTickCount()') and accounts for any wrapping.
</summary>
<param name="newValue"></param>
<param name="prevValue"></param>
<returns>subtraction of passed prevValue from current Environment.TickCount</returns>
</member>
<member name="M:HttpServer.ContextTimeoutManager.EnvironmentTickCountSubtract(System.Int32)">
<summary>
Environment.TickCount is an int but it counts all 32 bits so it goes positive
and negative every 24.9 days. Subtracts the passed value (previously fetched by
'EnvironmentTickCount()') and accounts for any wrapping.
</summary>
<returns>subtraction of passed prevValue from current Environment.TickCount</returns>
</member>
<member name="T:HttpServer.ContextTimeoutManager.MonitorType">
<summary>
Use a Thread or a Timer to monitor the ugly
</summary>
</member>
<member name="T:HttpServer.Sessions.MemorySessionStore">
<summary>
Session store using memory for each session.

View File

@ -210,13 +210,12 @@
;; Choose one of the physics engines below
;# {physics} {} {Select physics engine} {OpenDynamicsEngine BulletSim basicphysics POS} OpenDynamicsEngine
;; OpenDynamicsEngine is by some distance the most developed physics engine
;; BulletSim is incomplete and experimental but in active development. BulletSimN is a purely C# version of BulletSim.
;; BulletSim is experimental and in active development.
;; basicphysics effectively does not model physics at all, making all
;; objects phantom.
;; Default is OpenDynamicsEngine
; physics = OpenDynamicsEngine
; physics = BulletSim
; physics = BulletSimN
; physics = basicphysics
; physics = POS
@ -542,6 +541,13 @@
; shout_distance = 100
[EntityTransfer]
;# {DisableInterRegionTeleportCancellation} {} {Determine whether the cancel button is shown at all during teleports.} {false true} false
;; This option exists because cancelling at certain points can result in an unuseable session (frozen avatar, etc.)
;; Disabling cancellation can be okay in small closed grids where all teleports are highly likely to suceed.
;DisableInterRegionTeleportCancellation = false
[Messaging]
;# {OfflineMessageModule} {} {Module to use for offline message storage} {OfflineMessageModule "Offline Message Module V2" *}
;; Module to handle offline messaging. The core module requires an external

View File

@ -628,6 +628,11 @@
; Minimum user level required for HyperGrid teleports
LevelHGTeleport = 0
; Determine whether the cancel button is shown at all during teleports.
; This option exists because cancelling at certain points can result in an unuseable session (frozen avatar, etc.)
; Disabling cancellation can be okay in small closed grids where all teleports are highly likely to suceed.
DisableInterRegionTeleportCancellation = false
[Messaging]
; Control which region module is used for instant messaging.

View File

@ -26,12 +26,12 @@
; Set path to directory for plugin registry. Information
; about the registered repositories and installed plugins
; will be stored here
; The Robust.exe process must hvae R/W access to the location
; The Robust.exe process must have R/W access to the location
RegistryLocation = "."
; Modular configurations
; Set path to directory for modular ini files...
; The Robust.exe process must hvae R/W access to the location
; The Robust.exe process must have R/W access to the location
ConfigDirectory = "/home/opensim/etc/Configs"
[ServiceList]
@ -171,7 +171,7 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
;; Allow Hyperlinks to be created at the console
HypergridLinker = true
;; If you have this set under [Startup], no need to set it here, leave it commented
;; If you have this set under [Hypergrid], no need to set it here, leave it commented
; GatekeeperURI = "http://127.0.0.1:8002"
@ -326,7 +326,7 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
; HasProxy = false
; Defaults for the users, if none is specified in the useraccounts table entry (ServiceURLs)
;; If you have Gatekeeper set under [Startup], no need to set it here, leave it commented
;; If you have GatekeeperURI set under [Hypergrid], no need to set it here, leave it commented
; GatekeeperURI = "http://127.0.0.1:8002"
SRV_HomeURI = "http://127.0.0.1:8002"
@ -436,7 +436,7 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
AuthenticationService = "OpenSim.Services.Connectors.dll:AuthenticationServicesConnector"
SimulationService ="OpenSim.Services.Connectors.dll:SimulationServiceConnector"
; how does the outside world reach me? This acts as public key too.
;; If you have GatekeeperURI set under [Startup], no need to set it here, leave it commented
;; If you have GatekeeperURI set under [Hypergrid], no need to set it here, leave it commented
; ExternalName = "http://127.0.0.1:8002"
; Does this grid allow incoming links to any region in it?
@ -531,7 +531,7 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
AvatarService = "OpenSim.Services.AvatarService.dll:AvatarService"
;; Can overwrite the default in [Startup], but probably shouldn't
;; Can overwrite the default in [Hypergrid], but probably shouldn't
; HomeURI = "http://127.0.0.1:8002"
; * The interface that local users get when they are in other grids.
@ -542,7 +542,7 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGAssetService"
UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
;; Can overwrite the default in [Startup], but probably shouldn't
;; Can overwrite the default in [Hypergrid], but probably shouldn't
; HomeURI = "http://127.0.0.1:8002"
;; The asset types that this grid can export to / import from other grids.
@ -583,7 +583,7 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
UserAccountService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
;; What is the HomeURI of users associated with this grid?
;; Can overwrite the default in [Startup], but probably shouldn't
;; Can overwrite the default in [Hypergrid], but probably shouldn't
; HomeURI = "http://127.0.0.1:8002"

View File

@ -899,6 +899,7 @@
<Reference name="OpenSim.Framework"/>
<Reference name="OpenSim.Framework.Console"/>
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
<Reference name="OpenSim.Server.Base"/>
<Reference name="OpenSim.Services.Interfaces"/>
<Reference name="OpenSim.Services.Base"/>
<Reference name="OpenSim.Services.Connectors"/>
@ -1913,121 +1914,6 @@
</Files>
</Project>
<!-- REST plugins -->
<Project frameworkVersion="v3_5" name="OpenSim.ApplicationPlugins.Rest" path="OpenSim/ApplicationPlugins/Rest" type="Library">
<Configuration name="Debug">
<Options>
<OutputPath>../../../bin/</OutputPath>
</Options>
</Configuration>
<Configuration name="Release">
<Options>
<OutputPath>../../../bin/</OutputPath>
</Options>
</Configuration>
<ReferencePath>../../../bin/</ReferencePath>
<Reference name="Mono.Addins" path="../../../bin/"/>
<Reference name="System"/>
<Reference name="System.Xml"/>
<Reference name="OpenMetaverseTypes" path="../../../bin/"/>
<Reference name="Nini" path="../../../bin/"/>
<Reference name="XMLRPC" path="../../../bin/"/>
<Reference name="OpenSim"/>
<Reference name="OpenSim.Region.ClientStack"/>
<Reference name="OpenSim.Region.Framework"/>
<Reference name="OpenSim.Region.CoreModules"/>
<Reference name="OpenSim.Framework.Communications"/>
<Reference name="OpenSim.Framework"/>
<Reference name="OpenSim.Framework.Servers"/>
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
<Reference name="OpenSim.Framework.Console"/>
<Reference name="log4net" path="../../../bin/"/>
<Files>
<Match pattern="*.cs" recurse="false"/>
</Files>
</Project>
<Project frameworkVersion="v3_5" name="OpenSim.ApplicationPlugins.Rest.Regions" path="OpenSim/ApplicationPlugins/Rest/Regions" type="Library">
<Configuration name="Debug">
<Options>
<OutputPath>../../../../bin/</OutputPath>
</Options>
</Configuration>
<Configuration name="Release">
<Options>
<OutputPath>../../../../bin/</OutputPath>
</Options>
</Configuration>
<ReferencePath>../../../../bin/</ReferencePath>
<Reference name="Mono.Addins" path="../../../../bin/"/>
<Reference name="System"/>
<Reference name="System.Xml"/>
<Reference name="OpenMetaverseTypes" path="../../../../bin/"/>
<Reference name="Nini" path="../../../../bin/"/>
<Reference name="XMLRPC" path="../../../../bin/"/>
<Reference name="OpenSim"/>
<Reference name="OpenSim.Region.Framework"/>
<Reference name="OpenSim.Region.ClientStack"/>
<Reference name="OpenSim.Region.CoreModules"/>
<Reference name="OpenSim.Framework.Communications"/>
<Reference name="OpenSim.Framework"/>
<Reference name="OpenSim.Framework.Servers"/>
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
<Reference name="OpenSim.Framework.Console"/>
<Reference name="OpenSim.ApplicationPlugins.Rest"/>
<Reference name="log4net" path="../../../../bin/"/>
<Files>
<Match pattern="*.cs" recurse="true"/>
<Match buildAction="EmbeddedResource" path="Resources" pattern="*.addin.xml" recurse="true"/>
</Files>
</Project>
<Project frameworkVersion="v3_5" name="OpenSim.ApplicationPlugins.Rest.Inventory" path="OpenSim/ApplicationPlugins/Rest/Inventory" type="Library">
<Configuration name="Debug">
<Options>
<OutputPath>../../../../bin/</OutputPath>
</Options>
</Configuration>
<Configuration name="Release">
<Options>
<OutputPath>../../../../bin/</OutputPath>
</Options>
</Configuration>
<ReferencePath>../../../../bin/</ReferencePath>
<Reference name="Mono.Addins" path="../../../../bin/"/>
<Reference name="System"/>
<Reference name="System.Xml"/>
<Reference name="System.Drawing"/>
<Reference name="OpenMetaverseTypes" path="../../../../bin/"/>
<Reference name="OpenMetaverse" path="../../../../bin/"/>
<Reference name="Nini" path="../../../../bin/"/>
<Reference name="XMLRPC" path="../../../../bin/"/>
<Reference name="OpenSim"/>
<Reference name="OpenSim.Region.Framework"/>
<Reference name="OpenSim.Region.ClientStack"/>
<Reference name="OpenSim.Region.CoreModules"/>
<Reference name="OpenSim.Framework.Communications"/>
<Reference name="OpenSim.Framework"/>
<Reference name="OpenSim.Framework.Servers"/>
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
<Reference name="OpenSim.Framework.Console"/>
<Reference name="OpenSim.Services.Interfaces"/>
<Reference name="OpenSim.ApplicationPlugins.Rest"/>
<Reference name="log4net" path="../../../../bin/"/>
<Files>
<Match pattern="*.cs" recurse="true"/>
<Match buildAction="EmbeddedResource" path="Resources" pattern="*.addin.xml" recurse="true"/>
</Files>
</Project>
<!-- /REST plugins -->
<!-- Scene Server API Example Apps -->
<Project frameworkVersion="v3_5" name="OpenSim.Region.DataSnapshot" path="OpenSim/Region/DataSnapshot" type="Library">
@ -2833,6 +2719,7 @@
<Reference name="Nini" path="../../../bin/"/>
<Reference name="nunit.framework" path="../../../bin/"/>
<Reference name="OpenMetaverse" path="../../../bin/"/>
<Reference name="OpenMetaverse.StructuredData" path="../../../bin/"/>
<Reference name="OpenMetaverseTypes" path="../../../bin/"/>
<Reference name="OpenSim.Data"/>
<Reference name="OpenSim.Data.Null"/>