Merge branch 'master' into newmultiattach
Conflicts: OpenSim/Region/CoreModules/Avatar/Attachments/AttachmentsModule.csuser_profiles
commit
5e1f651e21
|
@ -155,6 +155,7 @@ what it is today.
|
||||||
* tglion
|
* tglion
|
||||||
* tlaukkan/Tommil (Tommi S. E. Laukkanen, Bubble Cloud)
|
* tlaukkan/Tommil (Tommi S. E. Laukkanen, Bubble Cloud)
|
||||||
* tyre
|
* tyre
|
||||||
|
* Vegaslon <vegaslon@gmail.com>
|
||||||
* VikingErik
|
* VikingErik
|
||||||
* Vytek
|
* Vytek
|
||||||
* webmage (IBM)
|
* webmage (IBM)
|
||||||
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
@ -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>
|
|
|
@ -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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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>"
|
|
||||||
;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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 "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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>
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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>
|
|
|
@ -50,6 +50,11 @@ namespace OpenSim.Data.MySQL
|
||||||
get { return GetType().Assembly; }
|
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 bool m_enableCompression = false;
|
||||||
private string m_connectionString;
|
private string m_connectionString;
|
||||||
private object m_dbLock = new object();
|
private object m_dbLock = new object();
|
||||||
|
@ -133,10 +138,10 @@ namespace OpenSim.Data.MySQL
|
||||||
dbcon.Open();
|
dbcon.Open();
|
||||||
|
|
||||||
using (MySqlCommand cmd = new MySqlCommand(
|
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))
|
dbcon))
|
||||||
{
|
{
|
||||||
cmd.Parameters.AddWithValue("?id", assetID.ToString());
|
cmd.Parameters.AddWithValue("?ID", assetID.ToString());
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -144,18 +149,18 @@ namespace OpenSim.Data.MySQL
|
||||||
{
|
{
|
||||||
if (dbReader.Read())
|
if (dbReader.Read())
|
||||||
{
|
{
|
||||||
asset = new AssetBase(assetID, (string)dbReader["name"], (sbyte)dbReader["asset_type"], dbReader["creator_id"].ToString());
|
asset = new AssetBase(assetID, (string)dbReader["Name"], (sbyte)dbReader["AssetType"], dbReader["CreatorID"].ToString());
|
||||||
asset.Data = (byte[])dbReader["data"];
|
asset.Data = (byte[])dbReader["Data"];
|
||||||
asset.Description = (string)dbReader["description"];
|
asset.Description = (string)dbReader["Description"];
|
||||||
|
|
||||||
string local = dbReader["local"].ToString();
|
string local = dbReader["Local"].ToString();
|
||||||
if (local.Equals("1") || local.Equals("true", StringComparison.InvariantCultureIgnoreCase))
|
if (local.Equals("1") || local.Equals("true", StringComparison.InvariantCultureIgnoreCase))
|
||||||
asset.Local = true;
|
asset.Local = true;
|
||||||
else
|
else
|
||||||
asset.Local = false;
|
asset.Local = false;
|
||||||
|
|
||||||
asset.Temporary = Convert.ToBoolean(dbReader["temporary"]);
|
asset.Temporary = Convert.ToBoolean(dbReader["Temporary"]);
|
||||||
asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]);
|
asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]);
|
||||||
|
|
||||||
if (m_enableCompression)
|
if (m_enableCompression)
|
||||||
{
|
{
|
||||||
|
@ -171,12 +176,14 @@ namespace OpenSim.Data.MySQL
|
||||||
// asset.ID, asset.Name, asset.Data.Length, compressedLength);
|
// asset.ID, asset.Name, asset.Data.Length, compressedLength);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UpdateAccessTime(asset.Metadata, (int)dbReader["AccessTime"]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
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 =
|
using (MySqlCommand cmd =
|
||||||
new MySqlCommand(
|
new MySqlCommand(
|
||||||
"replace INTO xassetsmeta(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, ?asset_type, ?local, ?temporary, ?create_time, ?access_time, ?asset_flags, ?creator_id)",
|
"VALUES(?ID, ?Hash, ?Name, ?Description, ?AssetType, ?Local, ?Temporary, ?CreateTime, ?AccessTime, ?AssetFlags, ?CreatorID)",
|
||||||
dbcon))
|
dbcon))
|
||||||
{
|
{
|
||||||
// create unix epoch time
|
// create unix epoch time
|
||||||
int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow);
|
int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow);
|
||||||
cmd.Parameters.AddWithValue("?id", asset.ID);
|
cmd.Parameters.AddWithValue("?ID", asset.ID);
|
||||||
cmd.Parameters.AddWithValue("?hash", hash);
|
cmd.Parameters.AddWithValue("?Hash", hash);
|
||||||
cmd.Parameters.AddWithValue("?name", assetName);
|
cmd.Parameters.AddWithValue("?Name", assetName);
|
||||||
cmd.Parameters.AddWithValue("?description", assetDescription);
|
cmd.Parameters.AddWithValue("?Description", assetDescription);
|
||||||
cmd.Parameters.AddWithValue("?asset_type", asset.Type);
|
cmd.Parameters.AddWithValue("?AssetType", asset.Type);
|
||||||
cmd.Parameters.AddWithValue("?local", asset.Local);
|
cmd.Parameters.AddWithValue("?Local", asset.Local);
|
||||||
cmd.Parameters.AddWithValue("?temporary", asset.Temporary);
|
cmd.Parameters.AddWithValue("?Temporary", asset.Temporary);
|
||||||
cmd.Parameters.AddWithValue("?create_time", now);
|
cmd.Parameters.AddWithValue("?CreateTime", now);
|
||||||
cmd.Parameters.AddWithValue("?access_time", now);
|
cmd.Parameters.AddWithValue("?AccessTime", now);
|
||||||
cmd.Parameters.AddWithValue("?creator_id", asset.Metadata.CreatorID);
|
cmd.Parameters.AddWithValue("?CreatorID", asset.Metadata.CreatorID);
|
||||||
cmd.Parameters.AddWithValue("?asset_flags", (int)asset.Flags);
|
cmd.Parameters.AddWithValue("?AssetFlags", (int)asset.Flags);
|
||||||
cmd.ExecuteNonQuery();
|
cmd.ExecuteNonQuery();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -278,11 +285,11 @@ namespace OpenSim.Data.MySQL
|
||||||
{
|
{
|
||||||
using (MySqlCommand cmd =
|
using (MySqlCommand cmd =
|
||||||
new MySqlCommand(
|
new MySqlCommand(
|
||||||
"INSERT INTO xassetsdata(hash, data) VALUES(?hash, ?data)",
|
"INSERT INTO XAssetsData(Hash, Data) VALUES(?Hash, ?Data)",
|
||||||
dbcon))
|
dbcon))
|
||||||
{
|
{
|
||||||
cmd.Parameters.AddWithValue("?hash", hash);
|
cmd.Parameters.AddWithValue("?Hash", hash);
|
||||||
cmd.Parameters.AddWithValue("?data", asset.Data);
|
cmd.Parameters.AddWithValue("?Data", asset.Data);
|
||||||
cmd.ExecuteNonQuery();
|
cmd.ExecuteNonQuery();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -303,41 +310,49 @@ namespace OpenSim.Data.MySQL
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// private void UpdateAccessTime(AssetBase asset)
|
/// <summary>
|
||||||
// {
|
/// Updates the access time of the asset if it was accessed above a given threshhold amount of time.
|
||||||
// lock (m_dbLock)
|
/// </summary>
|
||||||
// {
|
/// <remarks>
|
||||||
// using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
/// 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.
|
||||||
// dbcon.Open();
|
/// </remarks>
|
||||||
// MySqlCommand cmd =
|
/// <param name='asset'></param>
|
||||||
// new MySqlCommand("update assets set access_time=?access_time where id=?id",
|
/// <param name='accessTime'></param>
|
||||||
// dbcon);
|
private void UpdateAccessTime(AssetMetadata assetMetadata, int accessTime)
|
||||||
//
|
{
|
||||||
// // need to ensure we dispose
|
DateTime now = DateTime.UtcNow;
|
||||||
// try
|
|
||||||
// {
|
if ((now - Utils.UnixTimeToDateTime(accessTime)).TotalDays < DaysBetweenAccessTimeUpdates)
|
||||||
// using (cmd)
|
return;
|
||||||
// {
|
|
||||||
// // create unix epoch time
|
lock (m_dbLock)
|
||||||
// int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow);
|
{
|
||||||
// cmd.Parameters.AddWithValue("?id", asset.ID);
|
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
||||||
// cmd.Parameters.AddWithValue("?access_time", now);
|
{
|
||||||
// cmd.ExecuteNonQuery();
|
dbcon.Open();
|
||||||
// cmd.Dispose();
|
MySqlCommand cmd =
|
||||||
// }
|
new MySqlCommand("update XAssetsMeta set AccessTime=?AccessTime where ID=?ID", dbcon);
|
||||||
// }
|
|
||||||
// catch (Exception e)
|
try
|
||||||
// {
|
{
|
||||||
// m_log.ErrorFormat(
|
using (cmd)
|
||||||
// "[ASSETS DB]: " +
|
{
|
||||||
// "MySql failure updating access_time for asset {0} with name {1}" + Environment.NewLine + e.ToString()
|
// create unix epoch time
|
||||||
// + Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name);
|
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>
|
/// <summary>
|
||||||
/// We assume we already have the m_dbLock.
|
/// We assume we already have the m_dbLock.
|
||||||
|
@ -353,9 +368,9 @@ namespace OpenSim.Data.MySQL
|
||||||
|
|
||||||
bool exists = false;
|
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
|
try
|
||||||
{
|
{
|
||||||
|
@ -395,9 +410,9 @@ namespace OpenSim.Data.MySQL
|
||||||
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
||||||
{
|
{
|
||||||
dbcon.Open();
|
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
|
try
|
||||||
{
|
{
|
||||||
|
@ -412,8 +427,7 @@ namespace OpenSim.Data.MySQL
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
m_log.ErrorFormat(
|
m_log.Error(string.Format("[XASSETS DB]: MySql failure fetching asset {0}", uuid), e);
|
||||||
"[XASSETS DB]: MySql failure fetching asset {0}" + Environment.NewLine + e.ToString(), uuid);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -422,6 +436,7 @@ namespace OpenSim.Data.MySQL
|
||||||
return assetExists;
|
return assetExists;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns a list of AssetMetadata objects. The list is a subset of
|
/// Returns a list of AssetMetadata objects. The list is a subset of
|
||||||
/// the entire data set offset by <paramref name="start" /> containing
|
/// 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))
|
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
||||||
{
|
{
|
||||||
dbcon.Open();
|
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("?start", start);
|
||||||
cmd.Parameters.AddWithValue("?count", count);
|
cmd.Parameters.AddWithValue("?count", count);
|
||||||
|
|
||||||
|
@ -450,17 +465,19 @@ namespace OpenSim.Data.MySQL
|
||||||
while (dbReader.Read())
|
while (dbReader.Read())
|
||||||
{
|
{
|
||||||
AssetMetadata metadata = new AssetMetadata();
|
AssetMetadata metadata = new AssetMetadata();
|
||||||
metadata.Name = (string)dbReader["name"];
|
metadata.Name = (string)dbReader["Name"];
|
||||||
metadata.Description = (string)dbReader["description"];
|
metadata.Description = (string)dbReader["Description"];
|
||||||
metadata.Type = (sbyte)dbReader["asset_type"];
|
metadata.Type = (sbyte)dbReader["AssetType"];
|
||||||
metadata.Temporary = Convert.ToBoolean(dbReader["temporary"]); // Not sure if this is correct.
|
metadata.Temporary = Convert.ToBoolean(dbReader["Temporary"]); // Not sure if this is correct.
|
||||||
metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]);
|
metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]);
|
||||||
metadata.FullID = DBGuid.FromDB(dbReader["id"]);
|
metadata.FullID = DBGuid.FromDB(dbReader["ID"]);
|
||||||
metadata.CreatorID = dbReader["creator_id"].ToString();
|
metadata.CreatorID = dbReader["CreatorID"].ToString();
|
||||||
|
|
||||||
// We'll ignore this for now - it appears unused!
|
// We'll ignore this for now - it appears unused!
|
||||||
// metadata.SHA1 = dbReader["hash"]);
|
// metadata.SHA1 = dbReader["hash"]);
|
||||||
|
|
||||||
|
UpdateAccessTime(metadata, (int)dbReader["AccessTime"]);
|
||||||
|
|
||||||
retList.Add(metadata);
|
retList.Add(metadata);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -485,9 +502,9 @@ namespace OpenSim.Data.MySQL
|
||||||
{
|
{
|
||||||
dbcon.Open();
|
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();
|
cmd.ExecuteNonQuery();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -3,24 +3,24 @@
|
||||||
|
|
||||||
BEGIN;
|
BEGIN;
|
||||||
|
|
||||||
CREATE TABLE `xassetsmeta` (
|
CREATE TABLE `XAssetsMeta` (
|
||||||
`id` char(36) NOT NULL,
|
`ID` char(36) NOT NULL,
|
||||||
`hash` binary(32) NOT NULL,
|
`Hash` binary(32) NOT NULL,
|
||||||
`name` varchar(64) NOT NULL,
|
`Name` varchar(64) NOT NULL,
|
||||||
`description` varchar(64) NOT NULL,
|
`Description` varchar(64) NOT NULL,
|
||||||
`asset_type` tinyint(4) NOT NULL,
|
`AssetType` tinyint(4) NOT NULL,
|
||||||
`local` tinyint(1) NOT NULL,
|
`Local` tinyint(1) NOT NULL,
|
||||||
`temporary` tinyint(1) NOT NULL,
|
`Temporary` tinyint(1) NOT NULL,
|
||||||
`create_time` int(11) NOT NULL,
|
`CreateTime` int(11) NOT NULL,
|
||||||
`access_time` int(11) NOT NULL,
|
`AccessTime` int(11) NOT NULL,
|
||||||
`asset_flags` int(11) NOT NULL,
|
`AssetFlags` int(11) NOT NULL,
|
||||||
`creator_id` varchar(128) NOT NULL,
|
`CreatorID` varchar(128) NOT NULL,
|
||||||
PRIMARY KEY (`id`)
|
PRIMARY KEY (`id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1';
|
||||||
|
|
||||||
CREATE TABLE `xassetsdata` (
|
CREATE TABLE `XAssetsData` (
|
||||||
`hash` binary(32) NOT NULL,
|
`Hash` binary(32) NOT NULL,
|
||||||
`data` longblob NOT NULL,
|
`Data` longblob NOT NULL,
|
||||||
PRIMARY KEY (`hash`)
|
PRIMARY KEY (`hash`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1';
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1';
|
||||||
|
|
||||||
|
|
|
@ -180,7 +180,7 @@ namespace OpenSim.Framework
|
||||||
/// Validate the key used for storing separate data stores.
|
/// Validate the key used for storing separate data stores.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name='key'></param>
|
/// <param name='key'></param>
|
||||||
private static void ValidateKey(string key)
|
public static void ValidateKey(string key)
|
||||||
{
|
{
|
||||||
if (key.Length < MIN_STORE_NAME_LENGTH)
|
if (key.Length < MIN_STORE_NAME_LENGTH)
|
||||||
throw new Exception("Minimum store name length is " + MIN_STORE_NAME_LENGTH);
|
throw new Exception("Minimum store name length is " + MIN_STORE_NAME_LENGTH);
|
||||||
|
|
|
@ -25,48 +25,74 @@
|
||||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Xml;
|
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;
|
DAMap.ValidateKey(key);
|
||||||
Formatting = Formatting.Indented;
|
|
||||||
|
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)
|
/// <summary>
|
||||||
: this(stream, Encoding.UTF8)
|
/// 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)
|
||||||
{
|
{
|
||||||
|
lock (this)
|
||||||
|
{
|
||||||
|
if (m_map == null)
|
||||||
|
return false;
|
||||||
|
else
|
||||||
|
return m_map.Remove(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void WriteStartDocument()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void WriteStartDocument(bool standalone)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
public override string ToString()
|
|
||||||
{
|
|
||||||
Flush();
|
|
||||||
Close();
|
|
||||||
return m_sw.ToString();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -55,6 +55,13 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||||
/// <returns>Land object at the point supplied</returns>
|
/// <returns>Land object at the point supplied</returns>
|
||||||
ILandObject GetLandObject(float x, float y);
|
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>
|
/// <summary>
|
||||||
/// Get the parcels near the specified point
|
/// Get the parcels near the specified point
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -218,7 +218,7 @@ namespace OpenSim.Framework
|
||||||
Console.WriteLine ("Looking for updates...");
|
Console.WriteLine ("Looking for updates...");
|
||||||
Repositories.UpdateAllRepositories (ps);
|
Repositories.UpdateAllRepositories (ps);
|
||||||
Console.WriteLine ("Available add-in updates:");
|
Console.WriteLine ("Available add-in updates:");
|
||||||
bool found = false;
|
|
||||||
AddinRepositoryEntry[] entries = Repositories.GetAvailableUpdates();
|
AddinRepositoryEntry[] entries = Repositories.GetAvailableUpdates();
|
||||||
|
|
||||||
foreach (AddinRepositoryEntry entry in entries)
|
foreach (AddinRepositoryEntry entry in entries)
|
||||||
|
@ -541,7 +541,7 @@ namespace OpenSim.Framework
|
||||||
{
|
{
|
||||||
list.AddRange(PluginRegistry.GetAddins());
|
list.AddRange(PluginRegistry.GetAddins());
|
||||||
}
|
}
|
||||||
catch(Exception e)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
Addin[] x = xlist.ToArray(typeof(Addin)) as Addin[];
|
Addin[] x = xlist.ToArray(typeof(Addin)) as Addin[];
|
||||||
return x;
|
return x;
|
||||||
|
|
|
@ -134,16 +134,6 @@ namespace OpenSim.Framework.Servers
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public virtual void Startup()
|
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();
|
StartupSpecific();
|
||||||
|
|
||||||
TimeSpan timeTaken = DateTime.Now - m_startuptime;
|
TimeSpan timeTaken = DateTime.Now - m_startuptime;
|
||||||
|
|
|
@ -486,7 +486,9 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SendHTML500(response);
|
byte[] buffer500 = SendHTML500(response);
|
||||||
|
response.Body.Write(buffer500,0,buffer500.Length);
|
||||||
|
response.Body.Close();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -719,7 +721,15 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), 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
|
finally
|
||||||
{
|
{
|
||||||
|
@ -1747,6 +1757,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
response.ContentLength64 = buffer.Length;
|
response.ContentLength64 = buffer.Length;
|
||||||
response.ContentEncoding = Encoding.UTF8;
|
response.ContentEncoding = Encoding.UTF8;
|
||||||
|
|
||||||
|
|
||||||
return buffer;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1912,6 +1923,12 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
m_rpcHandlers.Remove(method);
|
m_rpcHandlers.Remove(method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RemoveJsonRPCHandler(string method)
|
||||||
|
{
|
||||||
|
lock(jsonRpcHandlers)
|
||||||
|
jsonRpcHandlers.Remove(method);
|
||||||
|
}
|
||||||
|
|
||||||
public bool RemoveLLSDHandler(string path, LLSDMethod handler)
|
public bool RemoveLLSDHandler(string path, LLSDMethod handler)
|
||||||
{
|
{
|
||||||
lock (m_llsdHandlers)
|
lock (m_llsdHandlers)
|
||||||
|
|
|
@ -141,6 +141,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||||
|
|
||||||
void RemoveXmlRPCHandler(string method);
|
void RemoveXmlRPCHandler(string method);
|
||||||
|
|
||||||
|
void RemoveJsonRPCHandler(string method);
|
||||||
|
|
||||||
string GetHTTP404(string host);
|
string GetHTTP404(string host);
|
||||||
|
|
||||||
string GetHTTP500();
|
string GetHTTP500();
|
||||||
|
|
|
@ -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)
|
public void RegisterCommonAppenders(IConfig startupConfig)
|
||||||
{
|
{
|
||||||
ILoggerRepository repository = LogManager.GetRepository();
|
ILoggerRepository repository = LogManager.GetRepository();
|
||||||
|
|
|
@ -303,12 +303,12 @@ namespace OpenSim.Framework
|
||||||
// Clamp the maximum magnitude of a vector
|
// Clamp the maximum magnitude of a vector
|
||||||
public static Vector3 ClampV(Vector3 x, float max)
|
public static Vector3 ClampV(Vector3 x, float max)
|
||||||
{
|
{
|
||||||
Vector3 ret = x;
|
|
||||||
float lenSq = x.LengthSquared();
|
float lenSq = x.LengthSquared();
|
||||||
if (lenSq > (max * max))
|
if (lenSq > (max * max))
|
||||||
{
|
{
|
||||||
x = x / x.Length() * max;
|
x = x / x.Length() * max;
|
||||||
}
|
}
|
||||||
|
|
||||||
return x;
|
return x;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,6 +159,7 @@ namespace OpenSim
|
||||||
|
|
||||||
MainConsole.Instance = m_console;
|
MainConsole.Instance = m_console;
|
||||||
|
|
||||||
|
LogEnvironmentInformation();
|
||||||
RegisterCommonAppenders(Config.Configs["Startup"]);
|
RegisterCommonAppenders(Config.Configs["Startup"]);
|
||||||
RegisterConsoleCommands();
|
RegisterConsoleCommands();
|
||||||
|
|
||||||
|
|
|
@ -134,10 +134,6 @@ namespace OpenSim
|
||||||
/// <param name="configSource"></param>
|
/// <param name="configSource"></param>
|
||||||
public OpenSimBase(IConfigSource configSource) : base()
|
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);
|
LoadConfigSettings(configSource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,10 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
|
||||||
private TestScene m_scene;
|
private TestScene m_scene;
|
||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void SetUp()
|
public override void SetUp()
|
||||||
{
|
{
|
||||||
|
base.SetUp();
|
||||||
|
|
||||||
uint port = 9999;
|
uint port = 9999;
|
||||||
uint sslPort = 9998;
|
uint sslPort = 9998;
|
||||||
|
|
||||||
|
|
|
@ -4581,7 +4581,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
rinfopack.AgentData = new RegionInfoPacket.AgentDataBlock();
|
rinfopack.AgentData = new RegionInfoPacket.AgentDataBlock();
|
||||||
rinfopack.AgentData.AgentID = AgentId;
|
rinfopack.AgentData.AgentID = AgentId;
|
||||||
rinfopack.AgentData.SessionID = SessionId;
|
rinfopack.AgentData.SessionID = SessionId;
|
||||||
|
rinfopack.RegionInfo3 = new RegionInfoPacket.RegionInfo3Block[0];
|
||||||
|
|
||||||
OutPacket(rinfopack, ThrottleOutPacketType.Task);
|
OutPacket(rinfopack, ThrottleOutPacketType.Task);
|
||||||
}
|
}
|
||||||
|
@ -7069,7 +7069,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
|
|
||||||
if (handlerUpdatePrimFlags != null)
|
if (handlerUpdatePrimFlags != null)
|
||||||
{
|
{
|
||||||
byte[] data = Pack.ToBytes();
|
// byte[] data = Pack.ToBytes();
|
||||||
// 46,47,48 are special positions within the packet
|
// 46,47,48 are special positions within the packet
|
||||||
// This may change so perhaps we need a better way
|
// This may change so perhaps we need a better way
|
||||||
// of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?)
|
// of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?)
|
||||||
|
|
|
@ -278,23 +278,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
m_shouldCollectStats = false;
|
m_shouldCollectStats = false;
|
||||||
if (config != null)
|
if (config != null)
|
||||||
{
|
{
|
||||||
if (config.Contains("enabled") && config.GetBoolean("enabled"))
|
m_shouldCollectStats = config.GetBoolean("Enabled", false);
|
||||||
{
|
binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("packet_headers_period_seconds", 300));
|
||||||
if (config.Contains("collect_packet_headers"))
|
binStatsDir = config.GetString("stats_dir", ".");
|
||||||
m_shouldCollectStats = config.GetBoolean("collect_packet_headers");
|
m_aggregatedBWStats = config.GetBoolean("aggregatedBWStats", false);
|
||||||
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
|
#endregion BinaryStats
|
||||||
|
|
||||||
|
@ -1266,8 +1253,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||||
static object binStatsLogLock = new object();
|
static object binStatsLogLock = new object();
|
||||||
static string binStatsDir = "";
|
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)
|
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;
|
if (!m_shouldCollectStats) return;
|
||||||
|
|
||||||
// Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size
|
// Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size
|
||||||
|
|
|
@ -289,21 +289,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
if (!Enabled)
|
if (!Enabled)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
if (AttachObjectInternal(sp, group, attachmentPt, silent, temp, append))
|
return AttachObjectInternal(sp, group, attachmentPt, silent, temp, append);
|
||||||
{
|
|
||||||
m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
/// <summary>
|
||||||
}
|
/// Internal method which actually does all the work for attaching an object.
|
||||||
|
/// </summary>
|
||||||
private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp, bool append)
|
/// <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)
|
if (group.GetSittingAvatarsCount() != 0)
|
||||||
{
|
{
|
||||||
// m_log.WarnFormat(
|
// m_log.WarnFormat(
|
||||||
|
@ -314,6 +315,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
}
|
}
|
||||||
|
|
||||||
List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
|
List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
|
||||||
|
|
||||||
if (attachments.Contains(group))
|
if (attachments.Contains(group))
|
||||||
{
|
{
|
||||||
// m_log.WarnFormat(
|
// m_log.WarnFormat(
|
||||||
|
@ -374,6 +376,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp, append);
|
UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp, append);
|
||||||
|
|
||||||
AttachToAgent(sp, group, attachmentPt, attachPos, silent);
|
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;
|
return true;
|
||||||
|
@ -400,8 +413,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
// m_log.DebugFormat(
|
// m_log.DebugFormat(
|
||||||
// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2}",
|
// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2} in {3}",
|
||||||
// (AttachmentPoint)AttachmentPt, itemID, sp.Name);
|
// (AttachmentPoint)AttachmentPt, itemID, sp.Name, m_scene.Name);
|
||||||
|
|
||||||
bool append = (AttachmentPt & 0x80) != 0;
|
bool append = (AttachmentPt & 0x80) != 0;
|
||||||
AttachmentPt &= 0x7f;
|
AttachmentPt &= 0x7f;
|
||||||
|
@ -533,6 +546,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
return;
|
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
|
// Scripts MUST be snapshotted before the object is
|
||||||
// removed from the scene because doing otherwise will
|
// removed from the scene because doing otherwise will
|
||||||
// clobber the run flag
|
// clobber the run flag
|
||||||
|
@ -854,16 +871,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
return null;
|
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(
|
// m_log.DebugFormat(
|
||||||
// "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}",
|
// "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}",
|
||||||
// objatt.Name, sp.Name, attachmentPt, m_scene.Name);
|
// objatt.Name, sp.Name, attachmentPt, m_scene.Name);
|
||||||
|
@ -899,17 +906,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||||
if (tainted)
|
if (tainted)
|
||||||
objatt.HasGroupChanged = true;
|
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;
|
return objatt;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Update the user inventory to reflect an attachment
|
/// Update the user inventory to reflect an attachment
|
||||||
|
|
|
@ -228,6 +228,120 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
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>
|
/// <summary>
|
||||||
/// Test that we do not attempt to attach an in-world object that someone else is sitting on.
|
/// Test that we do not attempt to attach an in-world object that someone else is sitting on.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -275,7 +389,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
|
|
||||||
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
|
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
|
||||||
|
|
||||||
m_numberOfAttachEventsFired = 0;
|
{
|
||||||
scene.AttachmentsModule.RezSingleAttachmentFromInventory(
|
scene.AttachmentsModule.RezSingleAttachmentFromInventory(
|
||||||
sp, attItem.ID, (uint)AttachmentPoint.Chest);
|
sp, attItem.ID, (uint)AttachmentPoint.Chest);
|
||||||
|
|
||||||
|
@ -293,13 +407,124 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||||
// Check appearance status
|
// Check appearance status
|
||||||
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
|
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
|
||||||
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
|
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
|
// Check events
|
||||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
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>
|
/// <summary>
|
||||||
/// Test specific conditions associated with rezzing a scripted attachment from inventory.
|
/// Test specific conditions associated with rezzing a scripted attachment from inventory.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
|
@ -39,7 +39,7 @@ using OpenSim.Region.Framework;
|
||||||
using OpenSim.Region.Framework.Interfaces;
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
using OpenSim.Region.Framework.Scenes;
|
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")]
|
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DAExampleModule")]
|
||||||
public class DAExampleModule : INonSharedRegionModule
|
public class DAExampleModule : INonSharedRegionModule
|
||||||
|
@ -48,6 +48,8 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule
|
||||||
|
|
||||||
private static readonly bool ENABLED = false; // enable for testing
|
private static readonly bool ENABLED = false; // enable for testing
|
||||||
|
|
||||||
|
public const string DANamespace = "DAExample Module";
|
||||||
|
|
||||||
protected Scene m_scene;
|
protected Scene m_scene;
|
||||||
protected IDialogModule m_dialogMod;
|
protected IDialogModule m_dialogMod;
|
||||||
|
|
||||||
|
@ -85,19 +87,29 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule
|
||||||
{
|
{
|
||||||
OSDMap attrs = null;
|
OSDMap attrs = null;
|
||||||
SceneObjectPart sop = m_scene.GetSceneObjectPart(groupId);
|
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();
|
attrs = new OSDMap();
|
||||||
|
|
||||||
OSDInteger newValue;
|
OSDInteger newValue;
|
||||||
|
|
||||||
|
// We have to lock on the entire dynamic attributes map to avoid race conditions with serialization code.
|
||||||
|
lock (sop.DynAttrs)
|
||||||
|
{
|
||||||
if (!attrs.ContainsKey("moves"))
|
if (!attrs.ContainsKey("moves"))
|
||||||
newValue = new OSDInteger(1);
|
newValue = new OSDInteger(1);
|
||||||
else
|
else
|
||||||
newValue = new OSDInteger(((OSDInteger)attrs["moves"]).AsInteger() + 1);
|
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));
|
m_dialogMod.SendGeneralAlert(string.Format("{0} {1} moved {2} times", sop.Name, sop.UUID, newValue));
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -66,6 +66,17 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool WaitForAgentArrivedAtDestination { get; set; }
|
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;
|
protected bool m_Enabled = false;
|
||||||
|
|
||||||
public Scene Scene { get; private set; }
|
public Scene Scene { get; private set; }
|
||||||
|
@ -116,6 +127,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
IConfig transferConfig = source.Configs["EntityTransfer"];
|
IConfig transferConfig = source.Configs["EntityTransfer"];
|
||||||
if (transferConfig != null)
|
if (transferConfig != null)
|
||||||
{
|
{
|
||||||
|
DisableInterRegionTeleportCancellation
|
||||||
|
= transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false);
|
||||||
|
|
||||||
WaitForAgentArrivedAtDestination
|
WaitForAgentArrivedAtDestination
|
||||||
= transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault);
|
= transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault);
|
||||||
|
|
||||||
|
@ -150,6 +164,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
{
|
{
|
||||||
client.OnTeleportHomeRequest += TeleportHome;
|
client.OnTeleportHomeRequest += TeleportHome;
|
||||||
client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
|
client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
|
||||||
|
|
||||||
|
if (!DisableInterRegionTeleportCancellation)
|
||||||
|
client.OnTeleportCancel += OnClientCancelTeleport;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual void Close() {}
|
public virtual void Close() {}
|
||||||
|
@ -168,6 +185,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
|
|
||||||
#region Agent Teleports
|
#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)
|
public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags)
|
||||||
{
|
{
|
||||||
if (sp.Scene.Permissions.IsGridGod(sp.UUID))
|
if (sp.Scene.Permissions.IsGridGod(sp.UUID))
|
||||||
|
@ -519,6 +544,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
if (sp.ParentID != (uint)0)
|
if (sp.ParentID != (uint)0)
|
||||||
sp.StandUp();
|
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
|
// 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).
|
// the viewer. However, it might mean that the viewer does not see the black teleport screen (untested).
|
||||||
sp.ControllingClient.SendTeleportStart(teleportFlags);
|
sp.ControllingClient.SendTeleportStart(teleportFlags);
|
||||||
|
@ -567,6 +595,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
return;
|
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.
|
// Past this point we have to attempt clean up if the teleport fails, so update transfer state.
|
||||||
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
|
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
|
||||||
|
|
||||||
|
@ -631,7 +668,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
return;
|
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(
|
m_log.DebugFormat(
|
||||||
"[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
|
"[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);
|
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;
|
sp.IsChildAgent = false;
|
||||||
ReInstantiateScripts(sp);
|
ReInstantiateScripts(sp);
|
||||||
|
|
||||||
|
@ -729,7 +780,20 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
|
|
||||||
// Finally, kill the agent we just created at the destination.
|
// Finally, kill the agent we just created at the destination.
|
||||||
Scene.SimulationService.CloseAgent(finalDestination, sp.UUID);
|
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);
|
sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1206,6 +1270,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
// region doesn't take it
|
// region doesn't take it
|
||||||
m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
|
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);
|
ReInstantiateScripts(agent);
|
||||||
agent.AddToPhysicalScene(isFlying);
|
agent.AddToPhysicalScene(isFlying);
|
||||||
|
|
||||||
|
@ -1225,6 +1293,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
neighbourRegion.RegionHandle);
|
neighbourRegion.RegionHandle);
|
||||||
return agent;
|
return agent;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No turning back
|
// No turning back
|
||||||
agent.IsChildAgent = true;
|
agent.IsChildAgent = true;
|
||||||
|
|
||||||
|
@ -2092,7 +2161,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
|
|
||||||
public bool IsInTransit(UUID id)
|
public bool IsInTransit(UUID id)
|
||||||
{
|
{
|
||||||
return m_entityTransferStateMachine.IsInTransit(id);
|
return m_entityTransferStateMachine.GetAgentTransferState(id) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ReInstantiateScripts(ScenePresence sp)
|
protected void ReInstantiateScripts(ScenePresence sp)
|
||||||
|
|
|
@ -51,8 +51,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
/// This is a state machine.
|
/// This is a state machine.
|
||||||
///
|
///
|
||||||
/// [Entry] => Preparing
|
/// [Entry] => Preparing
|
||||||
/// Preparing => { Transferring || CleaningUp || [Exit] }
|
/// Preparing => { Transferring || Cancelling || CleaningUp || [Exit] }
|
||||||
/// Transferring => { ReceivedAtDestination || CleaningUp }
|
/// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp }
|
||||||
|
/// Cancelling => CleaningUp
|
||||||
/// ReceivedAtDestination => CleaningUp
|
/// ReceivedAtDestination => CleaningUp
|
||||||
/// CleaningUp => [Exit]
|
/// CleaningUp => [Exit]
|
||||||
///
|
///
|
||||||
|
@ -64,7 +65,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
Preparing, // The agent is being prepared for transfer
|
Preparing, // The agent is being prepared for transfer
|
||||||
Transferring, // The agent is in the process of being transferred to a destination
|
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
|
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>
|
/// <summary>
|
||||||
|
@ -115,42 +117,110 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
/// <param name='newState'></param>
|
/// <param name='newState'></param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
/// <exception cref='Exception'>Illegal transitions will throw an Exception</exception>
|
/// <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)
|
lock (m_agentsInTransit)
|
||||||
{
|
{
|
||||||
// Illegal to try and update an agent that's not actually in transit.
|
// Illegal to try and update an agent that's not actually in transit.
|
||||||
if (!m_agentsInTransit.ContainsKey(id))
|
if (!m_agentsInTransit.ContainsKey(id))
|
||||||
throw new Exception(
|
{
|
||||||
string.Format(
|
if (newState != AgentTransferState.Cancelling)
|
||||||
|
failureMessage = string.Format(
|
||||||
"Agent with ID {0} is not registered as in transit in {1}",
|
"Agent with ID {0} is not registered as in transit in {1}",
|
||||||
id, m_mod.Scene.RegionInfo.RegionName));
|
id, m_mod.Scene.RegionInfo.RegionName);
|
||||||
|
else
|
||||||
AgentTransferState oldState = m_agentsInTransit[id];
|
failIfNotOkay = false;
|
||||||
|
}
|
||||||
bool transitionOkay = false;
|
else
|
||||||
|
{
|
||||||
|
oldState = m_agentsInTransit[id];
|
||||||
|
|
||||||
if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp)
|
if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp)
|
||||||
|
{
|
||||||
transitionOkay = true;
|
transitionOkay = true;
|
||||||
|
}
|
||||||
else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing)
|
else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing)
|
||||||
|
{
|
||||||
transitionOkay = true;
|
transitionOkay = true;
|
||||||
|
}
|
||||||
else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring)
|
else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring)
|
||||||
|
{
|
||||||
transitionOkay = true;
|
transitionOkay = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (newState == AgentTransferState.Cancelling
|
||||||
|
&& (oldState == AgentTransferState.Preparing || oldState == AgentTransferState.Transferring))
|
||||||
|
{
|
||||||
|
transitionOkay = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
failIfNotOkay = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
if (transitionOkay)
|
||||||
|
{
|
||||||
m_agentsInTransit[id] = newState;
|
m_agentsInTransit[id] = newState;
|
||||||
else
|
|
||||||
throw new Exception(
|
// m_log.DebugFormat(
|
||||||
string.Format(
|
// "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}",
|
||||||
"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.Name);
|
||||||
id, oldState, newState, m_mod.Scene.RegionInfo.RegionName));
|
|
||||||
}
|
}
|
||||||
|
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);
|
||||||
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
internal bool IsInTransit(UUID id)
|
return transitionOkay;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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)
|
lock (m_agentsInTransit)
|
||||||
return m_agentsInTransit.ContainsKey(id);
|
{
|
||||||
|
if (!m_agentsInTransit.ContainsKey(id))
|
||||||
|
return null;
|
||||||
|
else
|
||||||
|
return m_agentsInTransit[id];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -203,14 +273,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
||||||
|
|
||||||
lock (m_agentsInTransit)
|
lock (m_agentsInTransit)
|
||||||
{
|
{
|
||||||
if (!IsInTransit(id))
|
AgentTransferState? currentState = GetAgentTransferState(id);
|
||||||
|
|
||||||
|
if (currentState == null)
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
string.Format(
|
string.Format(
|
||||||
"Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit",
|
"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));
|
id, m_mod.Scene.RegionInfo.RegionName));
|
||||||
|
|
||||||
AgentTransferState currentState = m_agentsInTransit[id];
|
|
||||||
|
|
||||||
if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination)
|
if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination)
|
||||||
throw new Exception(
|
throw new Exception(
|
||||||
string.Format(
|
string.Format(
|
||||||
|
|
|
@ -414,8 +414,6 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
||||||
}
|
}
|
||||||
private void RegisterStatsManagerRegionStatistics()
|
private void RegisterStatsManagerRegionStatistics()
|
||||||
{
|
{
|
||||||
string regionName = m_scene.RegionInfo.RegionName;
|
|
||||||
|
|
||||||
MakeStat("RootAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetRootAgentCount(); });
|
MakeStat("RootAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetRootAgentCount(); });
|
||||||
MakeStat("ChildAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetChildAgentCount(); });
|
MakeStat("ChildAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetChildAgentCount(); });
|
||||||
MakeStat("TotalPrims", "objects", (s) => { s.Value = m_scene.SceneGraph.GetTotalObjectsCount(); });
|
MakeStat("TotalPrims", "objects", (s) => { s.Value = m_scene.SceneGraph.GetTotalObjectsCount(); });
|
||||||
|
|
|
@ -516,6 +516,9 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
|
||||||
foreach (string line in GetLines(data, dataDelim))
|
foreach (string line in GetLines(data, dataDelim))
|
||||||
{
|
{
|
||||||
string nextLine = line.Trim();
|
string nextLine = line.Trim();
|
||||||
|
|
||||||
|
// m_log.DebugFormat("[VECTOR RENDER MODULE]: Processing line '{0}'", nextLine);
|
||||||
|
|
||||||
//replace with switch, or even better, do some proper parsing
|
//replace with switch, or even better, do some proper parsing
|
||||||
if (nextLine.StartsWith("MoveTo"))
|
if (nextLine.StartsWith("MoveTo"))
|
||||||
{
|
{
|
||||||
|
@ -829,6 +832,8 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
|
||||||
float y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture);
|
float y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture);
|
||||||
PointF point = new PointF(x, y);
|
PointF point = new PointF(x, y);
|
||||||
points[i / 2] = point;
|
points[i / 2] = point;
|
||||||
|
|
||||||
|
// m_log.DebugFormat("[VECTOR RENDER MODULE]: Got point {0}", points[i / 2]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -219,12 +219,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat(
|
// m_log.DebugFormat(
|
||||||
// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate",
|
// "[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);
|
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;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -239,7 +242,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
|
||||||
// note that we really don't need the GridRegion for this call
|
// note that we really don't need the GridRegion for this call
|
||||||
foreach (Scene s in m_scenes.Values)
|
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);
|
s.IncomingChildAgentDataUpdate(cAgentData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -95,6 +95,11 @@ namespace OpenSim.Region.CoreModules.World.Land
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ILandObject GetLandObject(Vector3 position)
|
||||||
|
{
|
||||||
|
return GetLandObject(position.X, position.Y);
|
||||||
|
}
|
||||||
|
|
||||||
public ILandObject GetLandObject(int x, int y)
|
public ILandObject GetLandObject(int x, int y)
|
||||||
{
|
{
|
||||||
if (m_landManagementModule != null)
|
if (m_landManagementModule != null)
|
||||||
|
|
|
@ -41,6 +41,16 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||||
Value = 3
|
Value = 3
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public enum JsonStoreValueType
|
||||||
|
{
|
||||||
|
Undefined = 0,
|
||||||
|
Boolean = 1,
|
||||||
|
Integer = 2,
|
||||||
|
Float = 3,
|
||||||
|
String = 4,
|
||||||
|
UUID = 5
|
||||||
|
}
|
||||||
|
|
||||||
public delegate void TakeValueCallback(string s);
|
public delegate void TakeValueCallback(string s);
|
||||||
|
|
||||||
public interface IJsonStoreModule
|
public interface IJsonStoreModule
|
||||||
|
@ -49,7 +59,9 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||||
bool CreateStore(string value, ref UUID result);
|
bool CreateStore(string value, ref UUID result);
|
||||||
bool DestroyStore(UUID storeID);
|
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 TestStore(UUID storeID);
|
||||||
|
|
||||||
bool SetValue(UUID storeID, string path, string value, bool useJson);
|
bool SetValue(UUID storeID, string path, string value, bool useJson);
|
||||||
|
|
|
@ -130,6 +130,27 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public DAMap DynAttrs { get; set; }
|
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>
|
/// <value>
|
||||||
/// Is this a root part?
|
/// Is this a root part?
|
||||||
/// </value>
|
/// </value>
|
||||||
|
@ -4503,8 +4524,25 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
Changed changeFlags = 0;
|
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++)
|
for (int i = 0 ; i < GetNumberOfSides(); i++)
|
||||||
{
|
{
|
||||||
|
|
||||||
Primitive.TextureEntryFace newFace = newTex.DefaultTexture;
|
Primitive.TextureEntryFace newFace = newTex.DefaultTexture;
|
||||||
Primitive.TextureEntryFace oldFace = oldTex.DefaultTexture;
|
Primitive.TextureEntryFace oldFace = oldTex.DefaultTexture;
|
||||||
|
|
||||||
|
|
|
@ -559,16 +559,28 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
private Quaternion m_bodyRot = Quaternion.Identity;
|
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
|
public Quaternion Rotation
|
||||||
{
|
{
|
||||||
get { return m_bodyRot; }
|
get
|
||||||
|
{
|
||||||
|
return m_bodyRot;
|
||||||
|
}
|
||||||
|
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
m_bodyRot = value;
|
m_bodyRot = value;
|
||||||
|
|
||||||
if (PhysicsActor != null)
|
if (PhysicsActor != null)
|
||||||
{
|
|
||||||
PhysicsActor.Orientation = m_bodyRot;
|
PhysicsActor.Orientation = m_bodyRot;
|
||||||
}
|
|
||||||
// m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, 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; }
|
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()
|
public void AdjustKnownSeeds()
|
||||||
{
|
{
|
||||||
Dictionary<ulong, string> seeds;
|
Dictionary<ulong, string> seeds;
|
||||||
|
@ -709,8 +741,6 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#region Constructor(s)
|
#region Constructor(s)
|
||||||
|
|
||||||
public ScenePresence(
|
public ScenePresence(
|
||||||
|
@ -1613,33 +1643,29 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) ||
|
bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) ||
|
||||||
((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0));
|
((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0));
|
||||||
|
|
||||||
|
|
||||||
//m_log.Debug("[CONTROL]: " +flags);
|
//m_log.Debug("[CONTROL]: " +flags);
|
||||||
// Applies a satisfying roll effect to the avatar when flying.
|
// 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(
|
||||||
ApplyFlyingRoll(FLY_ROLL_RADIANS_PER_UPDATE, ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0), ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0));
|
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) &&
|
else if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) != 0 &&
|
||||||
((flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 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
|
else
|
||||||
{
|
{
|
||||||
if (m_AngularVelocity.Z != 0)
|
if (m_AngularVelocity.Z != 0)
|
||||||
m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE);
|
m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if (Flying && IsColliding && controlland)
|
if (Flying && IsColliding && controlland)
|
||||||
{
|
{
|
||||||
// nesting this check because LengthSquared() is expensive and we don't
|
// 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>
|
/// <param name="vec">The vector in which to move. This is relative to the rotation argument</param>
|
||||||
public void AddNewMovement(Vector3 vec)
|
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;
|
Vector3 direc = vec * Rotation;
|
||||||
direc.Normalize();
|
direc.Normalize();
|
||||||
|
@ -2420,6 +2447,8 @@ namespace OpenSim.Region.Framework.Scenes
|
||||||
|
|
||||||
direc *= 0.03f * 128f * SpeedModifier;
|
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 (PhysicsActor != null)
|
||||||
{
|
{
|
||||||
if (Flying)
|
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?
|
// TODO: Add the force instead of only setting it to support multiple forces per frame?
|
||||||
m_forceToApply = direc;
|
m_forceToApply = direc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,8 +110,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
|
|
||||||
Vector3 firstSize = new Vector3(2, 3, 4);
|
Vector3 firstSize = new Vector3(2, 3, 4);
|
||||||
Vector3 secondSize = new Vector3(5, 6, 7);
|
Vector3 secondSize = new Vector3(5, 6, 7);
|
||||||
Vector3 thirdSize = new Vector3(8, 9, 10);
|
// Vector3 thirdSize = new Vector3(8, 9, 10);
|
||||||
Vector3 fourthSize = new Vector3(11, 12, 13);
|
// Vector3 fourthSize = new Vector3(11, 12, 13);
|
||||||
|
|
||||||
Scene scene = new SceneHelpers().SetupScene();
|
Scene scene = new SceneHelpers().SetupScene();
|
||||||
scene.MaxUndoCount = 20;
|
scene.MaxUndoCount = 20;
|
||||||
|
|
|
@ -288,109 +288,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests
|
||||||
// ScenePresence presence = scene.GetScenePresence(agent1);
|
// ScenePresence presence = scene.GetScenePresence(agent1);
|
||||||
//
|
//
|
||||||
// Assert.That(presence, Is.Null, "presence is not null");
|
// 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.");
|
|
||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -140,9 +140,12 @@ public class ServerStats : ISharedRegionModule
|
||||||
}
|
}
|
||||||
#endregion 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);
|
StatsManager.RegisterStat(stat);
|
||||||
RegisteredStats.Add(pName, stat);
|
RegisteredStats.Add(pName, stat);
|
||||||
}
|
}
|
||||||
|
@ -166,16 +169,16 @@ public class ServerStats : ISharedRegionModule
|
||||||
StatsManager.RegisterStat(tempStat);
|
StatsManager.RegisterStat(tempStat);
|
||||||
RegisteredStats.Add(tempName, tempStat);
|
RegisteredStats.Add(tempName, tempStat);
|
||||||
|
|
||||||
MakeStat("TotalProcessorTime", "sec", ContainerProcessor,
|
MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor,
|
||||||
(s) => { s.Value = Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds; });
|
(s) => { s.Value = Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds; });
|
||||||
|
|
||||||
MakeStat("UserProcessorTime", "sec", ContainerProcessor,
|
MakeStat("UserProcessorTime", null, "sec", ContainerProcessor,
|
||||||
(s) => { s.Value = Process.GetCurrentProcess().UserProcessorTime.TotalSeconds; });
|
(s) => { s.Value = Process.GetCurrentProcess().UserProcessorTime.TotalSeconds; });
|
||||||
|
|
||||||
MakeStat("PrivilegedProcessorTime", "sec", ContainerProcessor,
|
MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor,
|
||||||
(s) => { s.Value = Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds; });
|
(s) => { s.Value = Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds; });
|
||||||
|
|
||||||
MakeStat("Threads", "threads", ContainerProcessor,
|
MakeStat("Threads", null, "threads", ContainerProcessor,
|
||||||
(s) => { s.Value = Process.GetCurrentProcess().Threads.Count; });
|
(s) => { s.Value = Process.GetCurrentProcess().Threads.Count; });
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -196,8 +199,10 @@ public class ServerStats : ISharedRegionModule
|
||||||
string nicInterfaceType = nic.NetworkInterfaceType.ToString();
|
string nicInterfaceType = nic.NetworkInterfaceType.ToString();
|
||||||
if (!okInterfaceTypes.Contains(nicInterfaceType))
|
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);
|
LogHeader, nic.Name, nicInterfaceType);
|
||||||
|
m_log.DebugFormat("{0} To include, add to comma separated list in [Monitoring]NetworkInterfaceTypes={1}",
|
||||||
|
LogHeader, NetworkInterfaceTypes);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,14 +211,15 @@ public class ServerStats : ISharedRegionModule
|
||||||
IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics();
|
IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics();
|
||||||
if (nicStats != null)
|
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); });
|
(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); });
|
(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); });
|
(s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: add IPv6 (it may actually happen someday)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
|
@ -221,13 +227,13 @@ public class ServerStats : ISharedRegionModule
|
||||||
m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e);
|
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; });
|
(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; });
|
(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); });
|
(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); });
|
(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 delegate double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat);
|
||||||
private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor)
|
private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor)
|
||||||
{
|
{
|
||||||
|
@ -275,7 +283,10 @@ public class ServerStats : ISharedRegionModule
|
||||||
{
|
{
|
||||||
IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics();
|
IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics();
|
||||||
if (intrStats != null)
|
if (intrStats != null)
|
||||||
stat.Value = Math.Round(getter(intrStats) / factor, 3);
|
{
|
||||||
|
double newVal = Math.Round(getter(intrStats) / factor, 3);
|
||||||
|
stat.Value = newVal;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -145,7 +145,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
public JsonStoreNodeType PathType(string expr)
|
public JsonStoreNodeType GetNodeType(string expr)
|
||||||
{
|
{
|
||||||
Stack<string> path;
|
Stack<string> path;
|
||||||
if (! ParsePathExpression(expr,out path))
|
if (! ParsePathExpression(expr,out path))
|
||||||
|
@ -168,6 +168,43 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
|
||||||
return JsonStoreNodeType.Undefined;
|
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>
|
/// <summary>
|
||||||
///
|
///
|
||||||
|
|
|
@ -270,7 +270,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
|
||||||
///
|
///
|
||||||
/// </summary>
|
/// </summary>
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
public JsonStoreNodeType GetPathType(UUID storeID, string path)
|
public JsonStoreNodeType GetNodeType(UUID storeID, string path)
|
||||||
{
|
{
|
||||||
if (! m_enabled) return JsonStoreNodeType.Undefined;
|
if (! m_enabled) return JsonStoreNodeType.Undefined;
|
||||||
|
|
||||||
|
@ -287,7 +287,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
lock (map)
|
lock (map)
|
||||||
return map.PathType(path);
|
return map.GetNodeType(path);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -297,6 +297,38 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
|
||||||
return JsonStoreNodeType.Undefined;
|
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>
|
/// <summary>
|
||||||
///
|
///
|
||||||
|
|
|
@ -192,16 +192,32 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
|
||||||
#region ScriptConstantsInterface
|
#region ScriptConstantsInterface
|
||||||
|
|
||||||
[ScriptConstant]
|
[ScriptConstant]
|
||||||
public static readonly int JSON_TYPE_UNDEF = (int)JsonStoreNodeType.Undefined;
|
public static readonly int JSON_NODETYPE_UNDEF = (int)JsonStoreNodeType.Undefined;
|
||||||
|
|
||||||
[ScriptConstant]
|
[ScriptConstant]
|
||||||
public static readonly int JSON_TYPE_OBJECT = (int)JsonStoreNodeType.Object;
|
public static readonly int JSON_NODETYPE_OBJECT = (int)JsonStoreNodeType.Object;
|
||||||
|
|
||||||
[ScriptConstant]
|
[ScriptConstant]
|
||||||
public static readonly int JSON_TYPE_ARRAY = (int)JsonStoreNodeType.Array;
|
public static readonly int JSON_NODETYPE_ARRAY = (int)JsonStoreNodeType.Array;
|
||||||
|
|
||||||
[ScriptConstant]
|
[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
|
#endregion
|
||||||
|
|
||||||
|
@ -310,9 +326,20 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
|
||||||
/// </summary>
|
/// </summary>
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
[ScriptInvocation]
|
[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);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------
|
// -----------------------------------------------------------------
|
||||||
|
|
|
@ -158,8 +158,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
|
||||||
|
|
||||||
Assert.That(dsrv, Is.EqualTo(1));
|
Assert.That(dsrv, Is.EqualTo(1));
|
||||||
|
|
||||||
int tprv = (int)InvokeOp("JsonGetPathType", storeId, "Hello");
|
int tprv = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
|
||||||
Assert.That(tprv, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
|
Assert.That(tprv, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
|
@ -277,8 +277,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
|
||||||
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
|
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
|
||||||
Assert.That(returnValue, Is.EqualTo(1));
|
Assert.That(returnValue, Is.EqualTo(1));
|
||||||
|
|
||||||
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello");
|
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
|
||||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
|
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
|
||||||
|
|
||||||
string returnValue2 = (string)InvokeOp("JsonGetValue", storeId, "Hello");
|
string returnValue2 = (string)InvokeOp("JsonGetValue", storeId, "Hello");
|
||||||
Assert.That(returnValue2, Is.EqualTo(""));
|
Assert.That(returnValue2, Is.EqualTo(""));
|
||||||
|
@ -291,8 +291,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
|
||||||
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
|
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
|
||||||
Assert.That(returnValue, Is.EqualTo(1));
|
Assert.That(returnValue, Is.EqualTo(1));
|
||||||
|
|
||||||
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello");
|
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
|
||||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
|
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
|
||||||
|
|
||||||
string returnValue2 = (string)InvokeOp("JsonGetJson", storeId, "Hello");
|
string returnValue2 = (string)InvokeOp("JsonGetJson", storeId, "Hello");
|
||||||
Assert.That(returnValue2, Is.EqualTo(""));
|
Assert.That(returnValue2, Is.EqualTo(""));
|
||||||
|
@ -306,11 +306,11 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
|
||||||
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello[0]");
|
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello[0]");
|
||||||
Assert.That(returnValue, Is.EqualTo(1));
|
Assert.That(returnValue, Is.EqualTo(1));
|
||||||
|
|
||||||
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello[0]");
|
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello[0]");
|
||||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE));
|
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE));
|
||||||
|
|
||||||
result = (int)InvokeOp("JsonGetPathType", storeId, "Hello[1]");
|
result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello[1]");
|
||||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
|
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
|
||||||
|
|
||||||
string stringReturnValue = (string)InvokeOp("JsonGetValue", storeId, "Hello[0]");
|
string stringReturnValue = (string)InvokeOp("JsonGetValue", storeId, "Hello[0]");
|
||||||
Assert.That(stringReturnValue, Is.EqualTo("value2"));
|
Assert.That(stringReturnValue, Is.EqualTo("value2"));
|
||||||
|
@ -433,7 +433,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
public void TestJsonGetPathType()
|
public void TestJsonGetNodeType()
|
||||||
{
|
{
|
||||||
TestHelpers.InMethod();
|
TestHelpers.InMethod();
|
||||||
// TestHelpers.EnableLogging();
|
// TestHelpers.EnableLogging();
|
||||||
|
@ -441,41 +441,41 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
|
||||||
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }");
|
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }");
|
||||||
|
|
||||||
{
|
{
|
||||||
int result = (int)InvokeOp("JsonGetPathType", storeId, ".");
|
int result = (int)InvokeOp("JsonGetNodeType", storeId, ".");
|
||||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_OBJECT));
|
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_OBJECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello");
|
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
|
||||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_OBJECT));
|
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_OBJECT));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World");
|
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World");
|
||||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_ARRAY));
|
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_ARRAY));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World[0]");
|
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World[0]");
|
||||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE));
|
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World[1]");
|
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World[1]");
|
||||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE));
|
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test for non-existant path
|
// Test for non-existant path
|
||||||
{
|
{
|
||||||
int result = (int)InvokeOp("JsonGetPathType", storeId, "foo");
|
int result = (int)InvokeOp("JsonGetNodeType", storeId, "foo");
|
||||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
|
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test for non-existant store
|
// Test for non-existant store
|
||||||
{
|
{
|
||||||
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
|
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
|
||||||
int result = (int)InvokeOp("JsonGetPathType", fakeStoreId, ".");
|
int result = (int)InvokeOp("JsonGetNodeType", fakeStoreId, ".");
|
||||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
|
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -102,6 +102,8 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
|
||||||
|
|
||||||
public override float Simulate(float timeStep)
|
public override float Simulate(float timeStep)
|
||||||
{
|
{
|
||||||
|
// Console.WriteLine("Simulating");
|
||||||
|
|
||||||
float fps = 0;
|
float fps = 0;
|
||||||
for (int i = 0; i < _actors.Count; ++i)
|
for (int i = 0; i < _actors.Count; ++i)
|
||||||
{
|
{
|
||||||
|
@ -109,8 +111,11 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
|
||||||
Vector3 actorPosition = actor.Position;
|
Vector3 actorPosition = actor.Position;
|
||||||
Vector3 actorVelocity = actor.Velocity;
|
Vector3 actorVelocity = actor.Velocity;
|
||||||
|
|
||||||
actorPosition.X += actor.Velocity.X*timeStep;
|
// Console.WriteLine(
|
||||||
actorPosition.Y += actor.Velocity.Y*timeStep;
|
// "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)
|
if (actor.Position.Y < 0)
|
||||||
{
|
{
|
||||||
|
|
|
@ -205,7 +205,7 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
// errors can creap in and the avatar will slowly float off in some direction.
|
// 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
|
// So, the problem is that, when an avatar is standing, we cannot tell creaping error
|
||||||
// from real pushing.
|
// 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);
|
_velocityMotor.Step(timeStep);
|
||||||
|
|
||||||
|
@ -244,6 +244,7 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// Supposed to be moving.
|
||||||
OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue;
|
OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue;
|
||||||
|
|
||||||
if (Friction != BSParam.AvatarFriction)
|
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
|
// Decide if 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.
|
// avatar up so it can walk up and over the low objects.
|
||||||
private OMV.Vector3 WalkUpStairs()
|
private OMV.Vector3 WalkUpStairs()
|
||||||
{
|
{
|
||||||
OMV.Vector3 ret = OMV.Vector3.Zero;
|
OMV.Vector3 ret = OMV.Vector3.Zero;
|
||||||
|
@ -476,17 +477,19 @@ public sealed class BSCharacter : BSPhysObject
|
||||||
if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
|
if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
|
||||||
{
|
{
|
||||||
// The character is out of the known/simulated area.
|
// The character is out of the known/simulated area.
|
||||||
// Upper levels of code will handle the transition to other areas so, for
|
// Force the avatar position to be within known. ScenePresence will use the position
|
||||||
// the time, we just ignore the position.
|
// plus the velocity to decide if the avatar is moving out of the region.
|
||||||
return ret;
|
RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
|
||||||
|
DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If below the ground, move the avatar up
|
// If below the ground, move the avatar up
|
||||||
float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
|
float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
|
||||||
if (Position.Z < terrainHeight)
|
if (Position.Z < terrainHeight)
|
||||||
{
|
{
|
||||||
DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
|
DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight);
|
||||||
_position.Z = terrainHeight + 2.0f;
|
_position.Z = terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters;
|
||||||
ret = true;
|
ret = true;
|
||||||
}
|
}
|
||||||
if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
|
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) {
|
private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
|
||||||
if (force.IsFinite())
|
if (force.IsFinite())
|
||||||
{
|
{
|
||||||
float magnitude = force.Length();
|
OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
|
||||||
if (magnitude > BSParam.MaxAddForceMagnitude)
|
|
||||||
{
|
|
||||||
// Force has a limit
|
|
||||||
force = force / magnitude * BSParam.MaxAddForceMagnitude;
|
|
||||||
}
|
|
||||||
|
|
||||||
OMV.Vector3 addForce = force;
|
|
||||||
// DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
|
// DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
|
||||||
|
|
||||||
PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
|
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.
|
// Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
|
||||||
if (PositionSanityCheck(true))
|
if (PositionSanityCheck(true))
|
||||||
{
|
{
|
||||||
|
DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position);
|
||||||
entprop.Position = _position;
|
entprop.Position = _position;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -143,7 +143,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
{
|
{
|
||||||
enableAngularVerticalAttraction = true;
|
enableAngularVerticalAttraction = true;
|
||||||
enableAngularDeflection = false;
|
enableAngularDeflection = false;
|
||||||
enableAngularBanking = false;
|
enableAngularBanking = true;
|
||||||
if (BSParam.VehicleDebuggingEnabled)
|
if (BSParam.VehicleDebuggingEnabled)
|
||||||
{
|
{
|
||||||
enableAngularVerticalAttraction = true;
|
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
|
// 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
|
// TODO: This is here because this is where ODE put it but documentation says it
|
||||||
// is a linear effect. Where should this check go?
|
// is a linear effect. Where should this check go?
|
||||||
if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
|
//if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
|
||||||
{
|
// {
|
||||||
angularMotorContributionV.X = 0f;
|
// angularMotorContributionV.X = 0f;
|
||||||
angularMotorContributionV.Y = 0f;
|
// angularMotorContributionV.Y = 0f;
|
||||||
}
|
// }
|
||||||
|
|
||||||
VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation;
|
VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation;
|
||||||
VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", Prim.LocalID, angularMotorContributionV);
|
VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", Prim.LocalID, angularMotorContributionV);
|
||||||
|
@ -1335,7 +1335,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
|
Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
|
||||||
vertContributionV /= m_verticalAttractionTimescale;
|
vertContributionV /= m_verticalAttractionTimescale;
|
||||||
|
|
||||||
VehicleRotationalVelocity += vertContributionV * VehicleOrientation;
|
VehicleRotationalVelocity += vertContributionV;
|
||||||
|
|
||||||
VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}",
|
VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}",
|
||||||
Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV,
|
Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV,
|
||||||
|
@ -1439,22 +1439,23 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
||||||
Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
|
Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
|
||||||
|
|
||||||
// Figure out the yaw value for this much roll.
|
// Figure out the yaw value for this much roll.
|
||||||
// Squared because that seems to give a good value
|
float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency;
|
||||||
float yawAngle = (float)Math.Asin(rollComponents.Y * rollComponents.Y) * m_bankingEfficiency;
|
|
||||||
|
|
||||||
// actual error = static turn error + dynamic turn error
|
// 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?
|
// 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
|
// Build the force vector to change rotation from what it is to what it should be
|
||||||
bankingContributionV.Z = -mixedYawAngle;
|
bankingContributionV.Z = -mixedYawAngle;
|
||||||
|
|
||||||
// Don't do it all at once.
|
// 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;
|
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}",
|
VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
|
||||||
Prim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV);
|
Prim.LocalID, rollComponents, VehicleForwardSpeed, rollComponents, yawAngle, mixedYawAngle, bankingContributionV);
|
||||||
|
|
|
@ -107,6 +107,7 @@ public static class BSParam
|
||||||
public static float AvatarCapsuleDepth { get; private set; }
|
public static float AvatarCapsuleDepth { get; private set; }
|
||||||
public static float AvatarCapsuleHeight { get; private set; }
|
public static float AvatarCapsuleHeight { get; private set; }
|
||||||
public static float AvatarContactProcessingThreshold { 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 AvatarStepHeight { get; private set; }
|
||||||
public static float AvatarStepApproachFactor { get; private set; }
|
public static float AvatarStepApproachFactor { get; private set; }
|
||||||
public static float AvatarStepForceFactor { 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 VehicleLinearFactor { get; private set; }
|
||||||
public static Vector3 VehicleAngularFactor { get; private set; }
|
public static Vector3 VehicleAngularFactor { get; private set; }
|
||||||
public static float VehicleGroundGravityFudge { get; private set; }
|
public static float VehicleGroundGravityFudge { get; private set; }
|
||||||
|
public static float VehicleAngularBankingTimescaleFudge { get; private set; }
|
||||||
public static bool VehicleDebuggingEnabled { get; private set; }
|
public static bool VehicleDebuggingEnabled { get; private set; }
|
||||||
|
|
||||||
// Linkset implementation parameters
|
// Linkset implementation parameters
|
||||||
|
@ -497,6 +499,10 @@ public static class BSParam
|
||||||
0.1f,
|
0.1f,
|
||||||
(s) => { return AvatarContactProcessingThreshold; },
|
(s) => { return AvatarContactProcessingThreshold; },
|
||||||
(s,v) => { AvatarContactProcessingThreshold = v; } ),
|
(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",
|
new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction",
|
||||||
0.3f,
|
0.3f,
|
||||||
(s) => { return AvatarStepHeight; },
|
(s) => { return AvatarStepHeight; },
|
||||||
|
@ -538,10 +544,14 @@ public static class BSParam
|
||||||
0.0f,
|
0.0f,
|
||||||
(s) => { return VehicleRestitution; },
|
(s) => { return VehicleRestitution; },
|
||||||
(s,v) => { VehicleRestitution = v; } ),
|
(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,
|
0.2f,
|
||||||
(s) => { return VehicleGroundGravityFudge; },
|
(s) => { return VehicleGroundGravityFudge; },
|
||||||
(s,v) => { VehicleGroundGravityFudge = v; } ),
|
(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",
|
new ParameterDefn<bool>("VehicleDebuggingEnable", "Turn on/off vehicle debugging",
|
||||||
false,
|
false,
|
||||||
(s) => { return VehicleDebuggingEnabled; },
|
(s) => { return VehicleDebuggingEnabled; },
|
||||||
|
|
|
@ -337,6 +337,54 @@ public sealed class BSTerrainManager : IDisposable
|
||||||
return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
|
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.
|
// Given an X and Y, find the height of the terrain.
|
||||||
// Since we could be handling multiple terrains for a mega-region,
|
// Since we could be handling multiple terrains for a mega-region,
|
||||||
// the base of the region is calcuated assuming all regions are
|
// the base of the region is calcuated assuming all regions are
|
||||||
|
@ -399,19 +447,61 @@ public sealed class BSTerrainManager : IDisposable
|
||||||
// Given an address, return 'true' of there is a description of that terrain and output
|
// Given an address, return 'true' of there is a description of that terrain and output
|
||||||
// the descriptor class and the 'base' fo the addresses therein.
|
// the descriptor class and the 'base' fo the addresses therein.
|
||||||
private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
|
private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
|
||||||
|
{
|
||||||
|
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 offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
|
||||||
int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
|
int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
|
||||||
Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
|
terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
|
||||||
|
}
|
||||||
|
|
||||||
BSTerrainPhys physTerrain = null;
|
BSTerrainPhys physTerrain = null;
|
||||||
lock (m_terrains)
|
lock (m_terrains)
|
||||||
{
|
{
|
||||||
m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
|
ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
|
||||||
}
|
}
|
||||||
outTerrainBase = terrainBaseXYZ;
|
outTerrainBase = terrainBaseXYZ;
|
||||||
outPhysTerrain = physTerrain;
|
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.
|
// Although no one seems to check this, I do support combining.
|
||||||
|
|
|
@ -215,6 +215,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
|
||||||
|
|
||||||
float magX = (float)sizeX / extentX;
|
float magX = (float)sizeX / extentX;
|
||||||
float magY = (float)sizeY / extentY;
|
float magY = (float)sizeY / extentY;
|
||||||
|
if (physicsScene != null)
|
||||||
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
|
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
|
||||||
BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
|
BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
|
||||||
float minHeight = float.MaxValue;
|
float minHeight = float.MaxValue;
|
||||||
|
@ -257,6 +258,7 @@ public sealed class BSTerrainMesh : BSTerrainPhys
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
if (physicsScene != null)
|
||||||
physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
|
physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
|
||||||
LogHeader, physicsScene.RegionName, extentBase, e);
|
LogHeader, physicsScene.RegionName, extentBase, e);
|
||||||
}
|
}
|
||||||
|
|
|
@ -68,6 +68,11 @@ public class RegionCombinerLargeLandChannel : ILandChannel
|
||||||
RootRegionLandChannel.Clear(setupDefaultParcel);
|
RootRegionLandChannel.Clear(setupDefaultParcel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ILandObject GetLandObject(Vector3 position)
|
||||||
|
{
|
||||||
|
return GetLandObject(position.X, position.Y);
|
||||||
|
}
|
||||||
|
|
||||||
public ILandObject GetLandObject(int x, int y)
|
public ILandObject GetLandObject(int x, int y)
|
||||||
{
|
{
|
||||||
//m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y);
|
//m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y);
|
||||||
|
|
|
@ -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)
|
public List<SceneObjectPart> GetLinkParts(int linkType)
|
||||||
{
|
{
|
||||||
return GetLinkParts(m_host, 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)
|
if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
|
||||||
q = avatar.CameraRotation; // Mouselook
|
q = avatar.CameraRotation; // Mouselook
|
||||||
else
|
else
|
||||||
q = avatar.Rotation; // Currently infrequently updated so may be inaccurate
|
q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
q = part.ParentGroup.GroupRotation; // Likely never get here but just in case
|
q = part.ParentGroup.GroupRotation; // Likely never get here but just in case
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
q = part.ParentGroup.GroupRotation; // just the group rotation
|
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()
|
public LSL_Rotation llGetLocalRot()
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
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)
|
public void llSetForce(LSL_Vector force, int local)
|
||||||
|
@ -2285,8 +2361,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
public LSL_Vector llGetTorque()
|
public LSL_Vector llGetTorque()
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
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)
|
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;
|
vel = m_host.Velocity;
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LSL_Vector(vel.X, vel.Y, vel.Z);
|
return new LSL_Vector(vel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public LSL_Vector llGetAccel()
|
public LSL_Vector llGetAccel()
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
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()
|
public LSL_Vector llGetOmega()
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
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()
|
public LSL_Float llGetTimeOfDay()
|
||||||
|
@ -3101,13 +3179,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
msg.ParentEstateID = 0; //ParentEstateID;
|
msg.ParentEstateID = 0; //ParentEstateID;
|
||||||
msg.Position = new Vector3(m_host.AbsolutePosition);
|
msg.Position = new Vector3(m_host.AbsolutePosition);
|
||||||
msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid;
|
msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid;
|
||||||
|
|
||||||
|
Vector3 pos = m_host.AbsolutePosition;
|
||||||
msg.binaryBucket
|
msg.binaryBucket
|
||||||
= Util.StringToBytes256(
|
= Util.StringToBytes256(
|
||||||
"{0}/{1}/{2}/{3}",
|
"{0}/{1}/{2}/{3}",
|
||||||
World.RegionInfo.RegionName,
|
World.RegionInfo.RegionName,
|
||||||
(int)Math.Floor(m_host.AbsolutePosition.X),
|
(int)Math.Floor(pos.X),
|
||||||
(int)Math.Floor(m_host.AbsolutePosition.Y),
|
(int)Math.Floor(pos.Y),
|
||||||
(int)Math.Floor(m_host.AbsolutePosition.Z));
|
(int)Math.Floor(pos.Z));
|
||||||
|
|
||||||
if (m_TransferModule != null)
|
if (m_TransferModule != null)
|
||||||
{
|
{
|
||||||
|
@ -3691,48 +3771,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
|
|
||||||
if (linknum < 0)
|
ISceneEntity entity = GetLinkEntity(linknum);
|
||||||
{
|
|
||||||
if (linknum == ScriptBaseClass.LINK_THIS)
|
|
||||||
return m_host.UUID.ToString();
|
|
||||||
else
|
|
||||||
return ScriptBaseClass.NULL_KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
int actualPrimCount = m_host.ParentGroup.PrimCount;
|
if (entity != null)
|
||||||
List<UUID> sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars();
|
return entity.UUID.ToString();
|
||||||
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
|
else
|
||||||
return ScriptBaseClass.NULL_KEY;
|
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();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ScriptBaseClass.NULL_KEY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Returns the name of the child prim or seated avatar matching the
|
/// Returns the name of the child prim or seated avatar matching the
|
||||||
|
@ -3777,56 +3822,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
|
|
||||||
if (linknum < 0)
|
ISceneEntity entity = GetLinkEntity(linknum);
|
||||||
{
|
|
||||||
if (linknum == ScriptBaseClass.LINK_THIS)
|
|
||||||
return m_host.Name;
|
|
||||||
else
|
|
||||||
return ScriptBaseClass.NULL_KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
int actualPrimCount = m_host.ParentGroup.PrimCount;
|
if (entity != null)
|
||||||
List<UUID> sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars();
|
return entity.Name;
|
||||||
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
|
else
|
||||||
return ScriptBaseClass.NULL_KEY;
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
return ScriptBaseClass.NULL_KEY;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public LSL_Integer llGetInventoryNumber(int type)
|
public LSL_Integer llGetInventoryNumber(int type)
|
||||||
{
|
{
|
||||||
|
@ -4170,13 +4172,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
if (presence != null)
|
if (presence != null)
|
||||||
{
|
{
|
||||||
// agent must be over the owners land
|
// agent must be over the owners land
|
||||||
if (m_host.OwnerID == World.LandChannel.GetLandObject(
|
if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
|
||||||
presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
|
|
||||||
{
|
{
|
||||||
World.TeleportClientHome(agentId, presence.ControllingClient);
|
World.TeleportClientHome(agentId, presence.ControllingClient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptSleep(5000);
|
ScriptSleep(5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4197,8 +4199,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
destination = World.RegionInfo.RegionName;
|
destination = World.RegionInfo.RegionName;
|
||||||
|
|
||||||
// agent must be over the owners land
|
// agent must be over the owners land
|
||||||
if (m_host.OwnerID == World.LandChannel.GetLandObject(
|
if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
|
||||||
presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
|
|
||||||
{
|
{
|
||||||
DoLLTeleport(presence, destination, targetPos, targetLookAt);
|
DoLLTeleport(presence, destination, targetPos, targetLookAt);
|
||||||
}
|
}
|
||||||
|
@ -4229,8 +4230,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
if (presence.GodLevel >= 200) return;
|
if (presence.GodLevel >= 200) return;
|
||||||
|
|
||||||
// agent must be over the owners land
|
// agent must be over the owners land
|
||||||
if (m_host.OwnerID == World.LandChannel.GetLandObject(
|
if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
|
||||||
presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
|
|
||||||
{
|
{
|
||||||
World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
|
World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
|
||||||
}
|
}
|
||||||
|
@ -4434,7 +4434,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
if (pushrestricted)
|
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
|
// We didn't find the parcel but region is push restricted so assume it is NOT ok
|
||||||
if (targetlandObj == null)
|
if (targetlandObj == null)
|
||||||
|
@ -4449,7 +4449,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos.X, PusheePos.Y);
|
ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos);
|
||||||
if (targetlandObj == null)
|
if (targetlandObj == null)
|
||||||
{
|
{
|
||||||
// We didn't find the parcel but region isn't push restricted so assume it's ok
|
// 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()
|
public LSL_Vector llGetCenterOfMass()
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
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)
|
public LSL_List llListSort(LSL_List src, int stride, int ascending)
|
||||||
|
@ -5703,12 +5703,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
}
|
}
|
||||||
|
|
||||||
ILandObject land;
|
ILandObject land;
|
||||||
Vector3 pos;
|
|
||||||
UUID id = UUID.Zero;
|
UUID id = UUID.Zero;
|
||||||
|
|
||||||
if (parcel || parcelOwned)
|
if (parcel || parcelOwned)
|
||||||
{
|
{
|
||||||
pos = m_host.ParentGroup.RootPart.GetWorldPosition();
|
land = World.LandChannel.GetLandObject(m_host.ParentGroup.RootPart.GetWorldPosition());
|
||||||
land = World.LandChannel.GetLandObject(pos.X, pos.Y);
|
|
||||||
if (land == null)
|
if (land == null)
|
||||||
{
|
{
|
||||||
id = UUID.Zero;
|
id = UUID.Zero;
|
||||||
|
@ -5734,8 +5733,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
if (!regionWide)
|
if (!regionWide)
|
||||||
{
|
{
|
||||||
pos = ssp.AbsolutePosition;
|
land = World.LandChannel.GetLandObject(ssp.AbsolutePosition);
|
||||||
land = World.LandChannel.GetLandObject(pos.X, pos.Y);
|
|
||||||
if (land != null)
|
if (land != null)
|
||||||
{
|
{
|
||||||
if (parcelOwned && land.LandData.OwnerID == id ||
|
if (parcelOwned && land.LandData.OwnerID == id ||
|
||||||
|
@ -5860,7 +5858,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
if (presence != null)
|
if (presence != null)
|
||||||
{
|
{
|
||||||
// agent must be over the owners land
|
// 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)
|
if (land == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -5882,21 +5880,20 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
ScenePresence presence = World.GetScenePresence(key);
|
ScenePresence presence = World.GetScenePresence(key);
|
||||||
if (presence != null) // object is an avatar
|
if (presence != null) // object is an avatar
|
||||||
{
|
{
|
||||||
if (m_host.OwnerID
|
if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
|
||||||
== World.LandChannel.GetLandObject(
|
|
||||||
presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
else // object is not an avatar
|
else // object is not an avatar
|
||||||
{
|
{
|
||||||
SceneObjectPart obj = World.GetSceneObjectPart(key);
|
SceneObjectPart obj = World.GetSceneObjectPart(key);
|
||||||
|
|
||||||
if (obj != null)
|
if (obj != null)
|
||||||
if (m_host.OwnerID
|
{
|
||||||
== World.LandChannel.GetLandObject(
|
if (m_host.OwnerID == World.LandChannel.GetLandObject(obj.AbsolutePosition).LandData.OwnerID)
|
||||||
obj.AbsolutePosition.X, obj.AbsolutePosition.Y).LandData.OwnerID)
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -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
|
// if the land is group owned and the object is group owned by the same group
|
||||||
// or
|
// or
|
||||||
// if the object is owned by a person with estate access.
|
// if the object is owned by a person with estate access.
|
||||||
|
ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition);
|
||||||
ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition.X, av.AbsolutePosition.Y);
|
|
||||||
if (parcel != null)
|
if (parcel != null)
|
||||||
{
|
{
|
||||||
if (m_host.OwnerID == parcel.LandData.OwnerID ||
|
if (m_host.OwnerID == parcel.LandData.OwnerID ||
|
||||||
|
@ -5985,14 +5981,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LSL_Vector llGroundSlope(LSL_Vector offset)
|
public LSL_Vector llGroundSlope(LSL_Vector offset)
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
|
|
||||||
//Get the slope normal. This gives us the equation of the plane tangent to the slope.
|
//Get the slope normal. This gives us the equation of the plane tangent to the slope.
|
||||||
LSL_Vector vsn = llGroundNormal(offset);
|
LSL_Vector vsn = llGroundNormal(offset);
|
||||||
|
|
||||||
|
@ -6003,7 +5998,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
vsl.Normalize();
|
vsl.Normalize();
|
||||||
//Normalization might be overkill here
|
//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)
|
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
|
//I believe the crossproduct of two normalized vectors is a normalized vector so
|
||||||
//this normalization may be overkill
|
//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)
|
public LSL_Vector llGroundContour(LSL_Vector offset)
|
||||||
|
@ -6069,7 +6068,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
return m_host.ParentGroup.AttachmentPoint;
|
return m_host.ParentGroup.AttachmentPoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LSL_Integer llGetFreeMemory()
|
public virtual LSL_Integer llGetFreeMemory()
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
// Make scripts designed for LSO happy
|
// Make scripts designed for LSO happy
|
||||||
|
@ -6553,7 +6552,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
UUID key;
|
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 (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
|
||||||
{
|
{
|
||||||
int expires = 0;
|
int expires = 0;
|
||||||
|
@ -7782,7 +7782,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
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)
|
if (land.LandData.OwnerID != m_host.OwnerID)
|
||||||
return;
|
return;
|
||||||
|
@ -7796,7 +7796,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
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)
|
if (land.LandData.OwnerID != m_host.OwnerID)
|
||||||
return String.Empty;
|
return String.Empty;
|
||||||
|
@ -7807,8 +7807,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
public LSL_Vector llGetRootPosition()
|
public LSL_Vector llGetRootPosition()
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
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>
|
/// <summary>
|
||||||
|
@ -7831,13 +7831,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
|
if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
|
||||||
q = avatar.CameraRotation; // Mouselook
|
q = avatar.CameraRotation; // Mouselook
|
||||||
else
|
else
|
||||||
q = avatar.Rotation; // Currently infrequently updated so may be inaccurate
|
q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate
|
||||||
else
|
else
|
||||||
q = m_host.ParentGroup.GroupRotation; // Likely never get here but just in case
|
q = m_host.ParentGroup.GroupRotation; // Likely never get here but just in case
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
q = m_host.ParentGroup.GroupRotation; // just the group rotation
|
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()
|
public LSL_String llGetObjectDesc()
|
||||||
|
@ -7944,7 +7945,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
|
|
||||||
public LSL_Vector llGetGeometricCenter()
|
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)
|
public LSL_List llGetPrimitiveParams(LSL_List rules)
|
||||||
|
@ -8031,23 +8032,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case (int)ScriptBaseClass.PRIM_POSITION:
|
case (int)ScriptBaseClass.PRIM_POSITION:
|
||||||
LSL_Vector v = new LSL_Vector(part.AbsolutePosition.X,
|
LSL_Vector v = new LSL_Vector(part.AbsolutePosition);
|
||||||
part.AbsolutePosition.Y,
|
|
||||||
part.AbsolutePosition.Z);
|
|
||||||
// For some reason, the part.AbsolutePosition.* values do not change if the
|
// For some reason, the part.AbsolutePosition.* values do not change if the
|
||||||
// linkset is rotated; they always reflect the child prim's world position
|
// 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
|
// 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
|
// 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).
|
// makes it more difficult to determine a child prim's actual inworld position).
|
||||||
if (part.ParentID != 0)
|
if (!part.IsRoot)
|
||||||
v = ((v - llGetRootPosition()) * llGetRootRotation()) + llGetRootPosition();
|
{
|
||||||
|
LSL_Vector rootPos = new LSL_Vector(m_host.ParentGroup.AbsolutePosition);
|
||||||
|
v = ((v - rootPos) * llGetRootRotation()) + rootPos;
|
||||||
|
}
|
||||||
|
|
||||||
res.Add(v);
|
res.Add(v);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case (int)ScriptBaseClass.PRIM_SIZE:
|
case (int)ScriptBaseClass.PRIM_SIZE:
|
||||||
res.Add(new LSL_Vector(part.Scale.X,
|
res.Add(new LSL_Vector(part.Scale));
|
||||||
part.Scale.Y,
|
|
||||||
part.Scale.Z));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case (int)ScriptBaseClass.PRIM_ROTATION:
|
case (int)ScriptBaseClass.PRIM_ROTATION:
|
||||||
|
@ -8362,7 +8364,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
res.Add(new LSL_String(part.Description));
|
res.Add(new LSL_String(part.Description));
|
||||||
break;
|
break;
|
||||||
case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
|
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;
|
break;
|
||||||
case (int)ScriptBaseClass.PRIM_POS_LOCAL:
|
case (int)ScriptBaseClass.PRIM_POS_LOCAL:
|
||||||
res.Add(new LSL_Vector(GetPartLocalPos(part)));
|
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
|
// 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.
|
// 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;
|
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)?
|
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);
|
m_host.AddScriptLPS(1);
|
||||||
|
|
||||||
if (m_item.PermsGranter == UUID.Zero)
|
if (m_item.PermsGranter == UUID.Zero)
|
||||||
return new LSL_Vector();
|
return Vector3.Zero;
|
||||||
|
|
||||||
if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
|
if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
|
||||||
{
|
{
|
||||||
ShoutError("No permissions to track the camera");
|
ShoutError("No permissions to track the camera");
|
||||||
return new LSL_Vector();
|
return Vector3.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
|
ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
|
||||||
if (presence != null)
|
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 pos;
|
||||||
}
|
}
|
||||||
return new LSL_Vector();
|
|
||||||
|
return Vector3.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LSL_Rotation llGetCameraRot()
|
public LSL_Rotation llGetCameraRot()
|
||||||
|
@ -9912,21 +9915,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
|
|
||||||
if (m_item.PermsGranter == UUID.Zero)
|
if (m_item.PermsGranter == UUID.Zero)
|
||||||
return new LSL_Rotation();
|
return Quaternion.Identity;
|
||||||
|
|
||||||
if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
|
if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
|
||||||
{
|
{
|
||||||
ShoutError("No permissions to track the camera");
|
ShoutError("No permissions to track the camera");
|
||||||
return new LSL_Rotation();
|
return Quaternion.Identity;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
|
ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
|
||||||
if (presence != null)
|
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>
|
/// <summary>
|
||||||
|
@ -9995,7 +9998,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
UUID key;
|
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 (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
|
||||||
{
|
{
|
||||||
int expires = 0;
|
int expires = 0;
|
||||||
|
@ -10036,7 +10039,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
UUID key;
|
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 (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageAllowed))
|
||||||
{
|
{
|
||||||
if (UUID.TryParse(avatar, out key))
|
if (UUID.TryParse(avatar, out key))
|
||||||
|
@ -10063,7 +10066,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
UUID key;
|
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 (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
|
||||||
{
|
{
|
||||||
if (UUID.TryParse(avatar, out key))
|
if (UUID.TryParse(avatar, out key))
|
||||||
|
@ -10325,7 +10328,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
public void llResetLandBanList()
|
public void llResetLandBanList()
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
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)
|
if (land.OwnerID == m_host.OwnerID)
|
||||||
{
|
{
|
||||||
foreach (LandAccessEntry entry in land.ParcelAccessList)
|
foreach (LandAccessEntry entry in land.ParcelAccessList)
|
||||||
|
@ -10342,7 +10345,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
public void llResetLandPassList()
|
public void llResetLandPassList()
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
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)
|
if (land.OwnerID == m_host.OwnerID)
|
||||||
{
|
{
|
||||||
foreach (LandAccessEntry entry in land.ParcelAccessList)
|
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));
|
ret.Add(new LSL_Vector((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z));
|
||||||
break;
|
break;
|
||||||
case ScriptBaseClass.OBJECT_ROT:
|
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;
|
break;
|
||||||
case ScriptBaseClass.OBJECT_VELOCITY:
|
case ScriptBaseClass.OBJECT_VELOCITY:
|
||||||
ret.Add(new LSL_Vector(av.Velocity.X, av.Velocity.Y, av.Velocity.Z));
|
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();
|
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);
|
LSL_List remaining = GetPrimParams(obj, rules, ref result);
|
||||||
|
|
||||||
|
@ -11021,7 +11024,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
World.ForEachScenePresence(delegate(ScenePresence sp)
|
World.ForEachScenePresence(delegate(ScenePresence sp)
|
||||||
{
|
{
|
||||||
Vector3 ac = sp.AbsolutePosition - rayStart;
|
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));
|
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 = Math.Abs(maxZ);
|
||||||
radius = radius*1.413f;
|
radius = radius*1.413f;
|
||||||
Vector3 ac = group.AbsolutePosition - rayStart;
|
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));
|
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));
|
list.Add(new LSL_Integer(linkNum));
|
||||||
|
|
||||||
if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL)
|
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++;
|
values++;
|
||||||
if (values >= count)
|
if (values >= count)
|
||||||
|
@ -11557,7 +11560,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
return 16384;
|
return 16384;
|
||||||
}
|
}
|
||||||
|
|
||||||
public LSL_Integer llGetUsedMemory()
|
public virtual LSL_Integer llGetUsedMemory()
|
||||||
{
|
{
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
// The value returned for LSO scripts in SL
|
// The value returned for LSO scripts in SL
|
||||||
|
|
|
@ -266,6 +266,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
llist[i] = new LSL_Float((float)result[i]);
|
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)
|
else if (result[i] is UUID)
|
||||||
{
|
{
|
||||||
llist[i] = new LSL_Key(result[i].ToString());
|
llist[i] = new LSL_Key(result[i].ToString());
|
||||||
|
|
|
@ -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
|
//OSSL only may be used if object is in the same group as the parcel
|
||||||
if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_GROUP_MEMBER"))
|
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)
|
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
|
//Only Parcelowners may use the function
|
||||||
if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_OWNER"))
|
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)
|
if (land.LandData.OwnerID == ownerID)
|
||||||
{
|
{
|
||||||
|
@ -1502,8 +1502,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
|
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
|
|
||||||
ILandObject land
|
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
|
||||||
= World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
|
|
||||||
|
|
||||||
if (land.LandData.OwnerID != m_host.OwnerID)
|
if (land.LandData.OwnerID != m_host.OwnerID)
|
||||||
return;
|
return;
|
||||||
|
@ -1519,8 +1518,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
|
|
||||||
m_host.AddScriptLPS(1);
|
m_host.AddScriptLPS(1);
|
||||||
|
|
||||||
ILandObject land
|
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
|
||||||
= World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
|
|
||||||
|
|
||||||
if (land.LandData.OwnerID != m_host.OwnerID)
|
if (land.LandData.OwnerID != m_host.OwnerID)
|
||||||
{
|
{
|
||||||
|
@ -2515,13 +2513,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
ScenePresence sp = World.GetScenePresence(npcId);
|
ScenePresence sp = World.GetScenePresence(npcId);
|
||||||
|
|
||||||
if (sp != null)
|
if (sp != null)
|
||||||
{
|
return new LSL_Vector(sp.AbsolutePosition);
|
||||||
Vector3 pos = sp.AbsolutePosition;
|
|
||||||
return new LSL_Vector(pos.X, pos.Y, pos.Z);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new LSL_Vector(0, 0, 0);
|
return Vector3.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void osNpcMoveTo(LSL_Key npc, LSL_Vector pos)
|
public void osNpcMoveTo(LSL_Key npc, LSL_Vector pos)
|
||||||
|
@ -2578,21 +2573,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
{
|
{
|
||||||
UUID npcId;
|
UUID npcId;
|
||||||
if (!UUID.TryParse(npc.m_string, out 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))
|
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);
|
ScenePresence sp = World.GetScenePresence(npcId);
|
||||||
|
|
||||||
if (sp != null)
|
if (sp != null)
|
||||||
{
|
return new LSL_Rotation(sp.GetWorldRotation());
|
||||||
Quaternion rot = sp.Rotation;
|
|
||||||
return new LSL_Rotation(rot.X, rot.Y, rot.Z, rot.W);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
public void osNpcSetRot(LSL_Key npc, LSL_Rotation rotation)
|
||||||
|
@ -3022,22 +3014,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
|
|
||||||
UUID avatarId = new UUID(avatar);
|
UUID avatarId = new UUID(avatar);
|
||||||
ScenePresence presence = World.GetScenePresence(avatarId);
|
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 (presence != null && World.ScriptDanger(m_host.LocalId, m_host.GetWorldPosition()))
|
||||||
if (result)
|
|
||||||
{
|
|
||||||
if (presence != null)
|
|
||||||
{
|
{
|
||||||
float health = presence.Health;
|
float health = presence.Health;
|
||||||
health += (float)healing;
|
health += (float)healing;
|
||||||
|
|
||||||
if (health >= 100)
|
if (health >= 100)
|
||||||
{
|
|
||||||
health = 100;
|
health = 100;
|
||||||
}
|
|
||||||
presence.setHealthWithUpdate(health);
|
presence.setHealthWithUpdate(health);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
public LSL_List osGetPrimitiveParams(LSL_Key prim, LSL_List rules)
|
public LSL_List osGetPrimitiveParams(LSL_Key prim, LSL_List rules)
|
||||||
{
|
{
|
||||||
|
@ -3112,8 +3100,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
||||||
if (avatar != null && avatar.UUID != m_host.OwnerID)
|
if (avatar != null && avatar.UUID != m_host.OwnerID)
|
||||||
{
|
{
|
||||||
result.Add(new LSL_String(avatar.UUID.ToString()));
|
result.Add(new LSL_String(avatar.UUID.ToString()));
|
||||||
OpenMetaverse.Vector3 ap = avatar.AbsolutePosition;
|
result.Add(new LSL_Vector(avatar.AbsolutePosition));
|
||||||
result.Add(new LSL_Vector(ap.X, ap.Y, ap.Z));
|
|
||||||
result.Add(new LSL_String(avatar.Name));
|
result.Add(new LSL_String(avatar.Name));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -353,7 +353,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
||||||
// Position of a sensor in a child prim attached to an avatar
|
// Position of a sensor in a child prim attached to an avatar
|
||||||
// will be still wrong.
|
// will be still wrong.
|
||||||
ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar);
|
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);
|
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
|
// Position of a sensor in a child prim attached to an avatar
|
||||||
// will be still wrong.
|
// will be still wrong.
|
||||||
ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar);
|
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);
|
LSL_Types.Quaternion r = new LSL_Types.Quaternion(q);
|
||||||
|
|
|
@ -662,13 +662,18 @@ namespace SecondLife
|
||||||
{
|
{
|
||||||
string severity = CompErr.IsWarning ? "Warning" : "Error";
|
string severity = CompErr.IsWarning ? "Warning" : "Error";
|
||||||
|
|
||||||
KeyValuePair<int, int> lslPos;
|
KeyValuePair<int, int> errorPos;
|
||||||
|
|
||||||
// Show 5 errors max, but check entire list for errors
|
// Show 5 errors max, but check entire list for errors
|
||||||
|
|
||||||
if (severity == "Error")
|
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;
|
string text = CompErr.ErrorText;
|
||||||
|
|
||||||
// Use LSL type names
|
// Use LSL type names
|
||||||
|
@ -678,7 +683,7 @@ namespace SecondLife
|
||||||
// The Second Life viewer's script editor begins
|
// The Second Life viewer's script editor begins
|
||||||
// countingn lines and columns at 0, so we subtract 1.
|
// countingn lines and columns at 0, so we subtract 1.
|
||||||
errtext += String.Format("({0},{1}): {4} {2}: {3}\n",
|
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);
|
CompErr.ErrorNumber, text, severity);
|
||||||
hadErrors = true;
|
hadErrors = true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -209,7 +209,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
|
||||||
+= (itemId, evp) => m_lslApi.llHTTPResponse(evp.Params[0].ToString(), 200, testResponse);
|
+= (itemId, evp) => m_lslApi.llHTTPResponse(evp.Params[0].ToString(), 200, testResponse);
|
||||||
|
|
||||||
// Console.WriteLine("Trying {0}", returnedUri);
|
// Console.WriteLine("Trying {0}", returnedUri);
|
||||||
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(returnedUri);
|
|
||||||
|
|
||||||
AssertHttpResponse(returnedUri, testResponse);
|
AssertHttpResponse(returnedUri, testResponse);
|
||||||
|
|
||||||
|
|
|
@ -138,17 +138,17 @@ namespace OpenSim.Server.Base
|
||||||
case ExtensionChange.Add:
|
case ExtensionChange.Add:
|
||||||
if (a.AddinFile.Contains(Registry.DefaultAddinsFolder))
|
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(',', '.')); }
|
connector.PluginPath = System.IO.Path.Combine(Registry.DefaultAddinsFolder,a.Name.Replace(',', '.')); }
|
||||||
else
|
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;
|
connector.PluginPath = a.AddinFile;
|
||||||
}
|
}
|
||||||
LoadPlugin(connector);
|
LoadPlugin(connector);
|
||||||
break;
|
break;
|
||||||
case ExtensionChange.Remove:
|
case ExtensionChange.Remove:
|
||||||
m_log.InfoFormat("[SERVER]: Removing {0}", a.Name);
|
m_log.InfoFormat("[SERVER UTILS]: Removing {0}", a.Name);
|
||||||
UnloadPlugin(connector);
|
UnloadPlugin(connector);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -166,13 +166,13 @@ namespace OpenSim.Server.Base
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_log.InfoFormat("[SERVER]: {0} Disabled.", connector.ConfigName);
|
m_log.InfoFormat("[SERVER UTILS]: {0} Disabled.", connector.ConfigName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UnloadPlugin(IRobustConnector connector)
|
private void UnloadPlugin(IRobustConnector connector)
|
||||||
{
|
{
|
||||||
m_log.InfoFormat("[Server]: Unloading {0}", connector.ConfigName);
|
m_log.InfoFormat("[SERVER UTILS]: Unloading {0}", connector.ConfigName);
|
||||||
|
|
||||||
connector.Unload();
|
connector.Unload();
|
||||||
}
|
}
|
||||||
|
@ -280,7 +280,7 @@ namespace OpenSim.Server.Base
|
||||||
{
|
{
|
||||||
if (!(e is System.MissingMethodException))
|
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,
|
interfaceName,
|
||||||
dllName,
|
dllName,
|
||||||
e.InnerException == null ? e.Message : e.InnerException.Message,
|
e.InnerException == null ? e.Message : e.InnerException.Message,
|
||||||
|
@ -298,14 +298,14 @@ namespace OpenSim.Server.Base
|
||||||
}
|
}
|
||||||
catch (ReflectionTypeLoadException rtle)
|
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()))),
|
String.Join("\n", Array.ConvertAll(rtle.LoaderExceptions, e => e.ToString()))),
|
||||||
rtle);
|
rtle);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
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;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -517,7 +517,7 @@ namespace OpenSim.Server.Base
|
||||||
public static IConfigSource LoadInitialConfig(string url)
|
public static IConfigSource LoadInitialConfig(string url)
|
||||||
{
|
{
|
||||||
IConfigSource source = new XmlConfigSource();
|
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
|
// The ini file path is a http URI
|
||||||
// Try to read it
|
// Try to read it
|
||||||
|
@ -529,7 +529,7 @@ namespace OpenSim.Server.Base
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
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);
|
Environment.Exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -186,10 +186,7 @@ namespace OpenSim.Server.Base
|
||||||
XmlConfigurator.Configure();
|
XmlConfigurator.Configure();
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: This should be done down in ServerBase but we need to sort out and refactor the log4net
|
LogEnvironmentInformation();
|
||||||
// XmlConfigurator calls first accross servers.
|
|
||||||
m_log.InfoFormat("[SERVER BASE]: Starting in {0}", m_startupDirectory);
|
|
||||||
|
|
||||||
RegisterCommonAppenders(startupConfig);
|
RegisterCommonAppenders(startupConfig);
|
||||||
|
|
||||||
if (startupConfig.GetString("PIDFile", String.Empty) != String.Empty)
|
if (startupConfig.GetString("PIDFile", String.Empty) != String.Empty)
|
||||||
|
|
|
@ -145,7 +145,7 @@ namespace OpenSim.Server
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
m_log.InfoFormat("[SERVER]: Failed to load {0}", conn);
|
m_log.ErrorFormat("[SERVER]: Failed to load {0}", conn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -124,15 +124,11 @@ namespace OpenSim.Services.AssetService
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat("[ASSET SERVICE]: Get asset metadata for {0}", id);
|
// 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)
|
if (asset != null)
|
||||||
return asset.Metadata;
|
return asset.Metadata;
|
||||||
|
else
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -140,29 +136,19 @@ namespace OpenSim.Services.AssetService
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat("[ASSET SERVICE]: Get asset data for {0}", 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 null;
|
|
||||||
|
|
||||||
AssetBase asset = m_Database.GetAsset(assetID);
|
|
||||||
return asset.Data;
|
return asset.Data;
|
||||||
|
else
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool Get(string id, Object sender, AssetRetrieved handler)
|
public virtual bool Get(string id, Object sender, AssetRetrieved handler)
|
||||||
{
|
{
|
||||||
//m_log.DebugFormat("[AssetService]: Get asset async {0}", id);
|
//m_log.DebugFormat("[AssetService]: Get asset async {0}", id);
|
||||||
|
|
||||||
UUID assetID;
|
handler(id, sender, Get(id));
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,8 +39,7 @@ using OpenMetaverse;
|
||||||
namespace OpenSim.Services.AssetService
|
namespace OpenSim.Services.AssetService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// This will be developed into a de-duplicating asset service.
|
/// 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.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class XAssetService : XAssetServiceBase, IAssetService
|
public class XAssetService : XAssetServiceBase, IAssetService
|
||||||
{
|
{
|
||||||
|
@ -48,7 +47,9 @@ namespace OpenSim.Services.AssetService
|
||||||
|
|
||||||
protected static XAssetService m_RootInstance;
|
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)
|
if (m_RootInstance == null)
|
||||||
{
|
{
|
||||||
|
@ -56,22 +57,21 @@ namespace OpenSim.Services.AssetService
|
||||||
|
|
||||||
if (m_AssetLoader != null)
|
if (m_AssetLoader != null)
|
||||||
{
|
{
|
||||||
IConfig assetConfig = config.Configs["AssetService"];
|
IConfig assetConfig = config.Configs[configName];
|
||||||
if (assetConfig == null)
|
if (assetConfig == null)
|
||||||
throw new Exception("No AssetService configuration");
|
throw new Exception("No AssetService configuration");
|
||||||
|
|
||||||
string loaderArgs = assetConfig.GetString("AssetLoaderArgs",
|
string loaderArgs = assetConfig.GetString("AssetLoaderArgs", String.Empty);
|
||||||
String.Empty);
|
|
||||||
|
|
||||||
bool assetLoaderEnabled = assetConfig.GetBoolean("AssetLoaderEnabled", true);
|
bool assetLoaderEnabled = assetConfig.GetBoolean("AssetLoaderEnabled", true);
|
||||||
|
|
||||||
if (assetLoaderEnabled)
|
if (assetLoaderEnabled && !HasChainedAssetService)
|
||||||
{
|
{
|
||||||
m_log.DebugFormat("[XASSET SERVICE]: Loading default asset set from {0}", loaderArgs);
|
m_log.DebugFormat("[XASSET SERVICE]: Loading default asset set from {0}", loaderArgs);
|
||||||
|
|
||||||
m_AssetLoader.ForEachDefaultXmlAsset(
|
m_AssetLoader.ForEachDefaultXmlAsset(
|
||||||
loaderArgs,
|
loaderArgs,
|
||||||
delegate(AssetBase a)
|
a =>
|
||||||
{
|
{
|
||||||
AssetBase existingAsset = Get(a.ID);
|
AssetBase existingAsset = Get(a.ID);
|
||||||
// AssetMetadata existingMetadata = GetMetadata(a.ID);
|
// AssetMetadata existingMetadata = GetMetadata(a.ID);
|
||||||
|
@ -103,7 +103,23 @@ namespace OpenSim.Services.AssetService
|
||||||
|
|
||||||
try
|
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)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
@ -121,15 +137,11 @@ namespace OpenSim.Services.AssetService
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat("[XASSET SERVICE]: Get asset metadata for {0}", id);
|
// 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)
|
if (asset != null)
|
||||||
return asset.Metadata;
|
return asset.Metadata;
|
||||||
|
else
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,13 +149,12 @@ namespace OpenSim.Services.AssetService
|
||||||
{
|
{
|
||||||
// m_log.DebugFormat("[XASSET SERVICE]: Get asset data for {0}", 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 null;
|
|
||||||
|
|
||||||
AssetBase asset = m_Database.GetAsset(assetID);
|
|
||||||
return asset.Data;
|
return asset.Data;
|
||||||
|
else
|
||||||
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual bool Get(string id, Object sender, AssetRetrieved handler)
|
public virtual bool Get(string id, Object sender, AssetRetrieved handler)
|
||||||
|
@ -155,7 +166,7 @@ namespace OpenSim.Services.AssetService
|
||||||
if (!UUID.TryParse(id, out assetID))
|
if (!UUID.TryParse(id, out assetID))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
AssetBase asset = m_Database.GetAsset(assetID);
|
AssetBase asset = Get(id);
|
||||||
|
|
||||||
//m_log.DebugFormat("[XASSET SERVICE]: Got asset {0}", asset);
|
//m_log.DebugFormat("[XASSET SERVICE]: Got asset {0}", asset);
|
||||||
|
|
||||||
|
@ -194,7 +205,15 @@ namespace OpenSim.Services.AssetService
|
||||||
if (!UUID.TryParse(id, out assetID))
|
if (!UUID.TryParse(id, out assetID))
|
||||||
return false;
|
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);
|
return m_Database.Delete(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void MigrateFromChainedService(AssetBase asset)
|
||||||
|
{
|
||||||
|
Util.FireAndForget(o => { Store(asset); m_ChainedAssetService.Delete(asset.ID); });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -27,9 +27,11 @@
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using log4net;
|
||||||
using Nini.Config;
|
using Nini.Config;
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
using OpenSim.Data;
|
using OpenSim.Data;
|
||||||
|
using OpenSim.Server.Base;
|
||||||
using OpenSim.Services.Interfaces;
|
using OpenSim.Services.Interfaces;
|
||||||
using OpenSim.Services.Base;
|
using OpenSim.Services.Base;
|
||||||
|
|
||||||
|
@ -37,10 +39,15 @@ namespace OpenSim.Services.AssetService
|
||||||
{
|
{
|
||||||
public class XAssetServiceBase : ServiceBase
|
public class XAssetServiceBase : ServiceBase
|
||||||
{
|
{
|
||||||
protected IXAssetDataPlugin m_Database = null;
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
protected IAssetLoader m_AssetLoader = null;
|
|
||||||
|
|
||||||
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 dllName = String.Empty;
|
||||||
string connString = String.Empty;
|
string connString = String.Empty;
|
||||||
|
@ -48,7 +55,7 @@ namespace OpenSim.Services.AssetService
|
||||||
//
|
//
|
||||||
// Try reading the [AssetService] section first, if it exists
|
// Try reading the [AssetService] section first, if it exists
|
||||||
//
|
//
|
||||||
IConfig assetConfig = config.Configs["AssetService"];
|
IConfig assetConfig = config.Configs[configName];
|
||||||
if (assetConfig != null)
|
if (assetConfig != null)
|
||||||
{
|
{
|
||||||
dllName = assetConfig.GetString("StorageProvider", dllName);
|
dllName = assetConfig.GetString("StorageProvider", dllName);
|
||||||
|
@ -77,8 +84,25 @@ namespace OpenSim.Services.AssetService
|
||||||
if (m_Database == null)
|
if (m_Database == null)
|
||||||
throw new Exception("Could not find a storage interface in the given module");
|
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);
|
m_Database.Initialise(connString);
|
||||||
|
|
||||||
|
if (HasChainedAssetService)
|
||||||
|
{
|
||||||
string loaderName = assetConfig.GetString("DefaultAssetLoader",
|
string loaderName = assetConfig.GetString("DefaultAssetLoader",
|
||||||
String.Empty);
|
String.Empty);
|
||||||
|
|
||||||
|
@ -91,4 +115,5 @@ namespace OpenSim.Services.AssetService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -60,6 +60,8 @@ namespace OpenSim.Tests.Common.Mock
|
||||||
public List<ImagePacketPacket> SentImagePacketPackets { get; private set; }
|
public List<ImagePacketPacket> SentImagePacketPackets { get; private set; }
|
||||||
public List<ImageNotInDatabasePacket> SentImageNotInDatabasePackets { 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
|
// disable warning: public events, part of the public API
|
||||||
#pragma warning disable 67
|
#pragma warning disable 67
|
||||||
|
|
||||||
|
@ -566,6 +568,8 @@ namespace OpenSim.Tests.Common.Mock
|
||||||
|
|
||||||
public virtual void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
|
public virtual void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
|
||||||
{
|
{
|
||||||
|
if (OnReceivedMoveAgentIntoRegion != null)
|
||||||
|
OnReceivedMoveAgentIntoRegion(regInfo, pos, look);
|
||||||
}
|
}
|
||||||
|
|
||||||
public virtual AgentCircuitData RequestClientInfo()
|
public virtual AgentCircuitData RequestClientInfo()
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -81,6 +81,11 @@ namespace OpenSim.Tests.Common.Mock
|
||||||
return obj;
|
return obj;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public ILandObject GetLandObject(Vector3 position)
|
||||||
|
{
|
||||||
|
return GetLandObject(position.X, position.Y);
|
||||||
|
}
|
||||||
|
|
||||||
public ILandObject GetLandObject(int x, int y)
|
public ILandObject GetLandObject(int x, int y)
|
||||||
{
|
{
|
||||||
return GetNoLand();
|
return GetNoLand();
|
||||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1669,6 +1669,65 @@
|
||||||
A header have been received.
|
A header have been received.
|
||||||
</summary>
|
</summary>
|
||||||
</member>
|
</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">
|
<member name="T:HttpServer.IHttpRequest">
|
||||||
<summary>
|
<summary>
|
||||||
Contains server side HTTP request information.
|
Contains server side HTTP request information.
|
||||||
|
@ -2825,6 +2884,11 @@
|
||||||
<param name="protocol">Kind of HTTPS protocol. Usually TLS or SSL.</param>
|
<param name="protocol">Kind of HTTPS protocol. Usually TLS or SSL.</param>
|
||||||
<returns>A created <see cref="T:HttpServer.IHttpClientContext"/>.</returns>
|
<returns>A created <see cref="T:HttpServer.IHttpClientContext"/>.</returns>
|
||||||
</member>
|
</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">
|
<member name="E:HttpServer.IHttpContextFactory.RequestReceived">
|
||||||
<summary>
|
<summary>
|
||||||
A request have been received from one of the contexts.
|
A request have been received from one of the contexts.
|
||||||
|
@ -2876,6 +2940,11 @@
|
||||||
A creates <see cref="T:HttpServer.IHttpClientContext"/>.
|
A creates <see cref="T:HttpServer.IHttpClientContext"/>.
|
||||||
</returns>
|
</returns>
|
||||||
</member>
|
</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">
|
<member name="P:HttpServer.HttpContextFactory.UseTraceLogs">
|
||||||
<summary>
|
<summary>
|
||||||
True if detailed trace logs should be written.
|
True if detailed trace logs should be written.
|
||||||
|
@ -4315,6 +4384,58 @@
|
||||||
</summary>
|
</summary>
|
||||||
<param name="message">message describing the error</param>
|
<param name="message">message describing the error</param>
|
||||||
</member>
|
</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">
|
<member name="T:HttpServer.Sessions.MemorySessionStore">
|
||||||
<summary>
|
<summary>
|
||||||
Session store using memory for each session.
|
Session store using memory for each session.
|
||||||
|
|
|
@ -210,13 +210,12 @@
|
||||||
;; Choose one of the physics engines below
|
;; Choose one of the physics engines below
|
||||||
;# {physics} {} {Select physics engine} {OpenDynamicsEngine BulletSim basicphysics POS} OpenDynamicsEngine
|
;# {physics} {} {Select physics engine} {OpenDynamicsEngine BulletSim basicphysics POS} OpenDynamicsEngine
|
||||||
;; OpenDynamicsEngine is by some distance the most developed physics engine
|
;; 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
|
;; basicphysics effectively does not model physics at all, making all
|
||||||
;; objects phantom.
|
;; objects phantom.
|
||||||
;; Default is OpenDynamicsEngine
|
;; Default is OpenDynamicsEngine
|
||||||
; physics = OpenDynamicsEngine
|
; physics = OpenDynamicsEngine
|
||||||
; physics = BulletSim
|
; physics = BulletSim
|
||||||
; physics = BulletSimN
|
|
||||||
; physics = basicphysics
|
; physics = basicphysics
|
||||||
; physics = POS
|
; physics = POS
|
||||||
|
|
||||||
|
@ -542,6 +541,13 @@
|
||||||
; shout_distance = 100
|
; 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]
|
[Messaging]
|
||||||
;# {OfflineMessageModule} {} {Module to use for offline message storage} {OfflineMessageModule "Offline Message Module V2" *}
|
;# {OfflineMessageModule} {} {Module to use for offline message storage} {OfflineMessageModule "Offline Message Module V2" *}
|
||||||
;; Module to handle offline messaging. The core module requires an external
|
;; Module to handle offline messaging. The core module requires an external
|
||||||
|
|
|
@ -628,6 +628,11 @@
|
||||||
; Minimum user level required for HyperGrid teleports
|
; Minimum user level required for HyperGrid teleports
|
||||||
LevelHGTeleport = 0
|
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]
|
[Messaging]
|
||||||
; Control which region module is used for instant messaging.
|
; Control which region module is used for instant messaging.
|
||||||
|
|
|
@ -26,12 +26,12 @@
|
||||||
; Set path to directory for plugin registry. Information
|
; Set path to directory for plugin registry. Information
|
||||||
; about the registered repositories and installed plugins
|
; about the registered repositories and installed plugins
|
||||||
; will be stored here
|
; 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 = "."
|
RegistryLocation = "."
|
||||||
|
|
||||||
; Modular configurations
|
; Modular configurations
|
||||||
; Set path to directory for modular ini files...
|
; 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"
|
ConfigDirectory = "/home/opensim/etc/Configs"
|
||||||
|
|
||||||
[ServiceList]
|
[ServiceList]
|
||||||
|
@ -171,7 +171,7 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
|
||||||
;; Allow Hyperlinks to be created at the console
|
;; Allow Hyperlinks to be created at the console
|
||||||
HypergridLinker = true
|
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"
|
; GatekeeperURI = "http://127.0.0.1:8002"
|
||||||
|
|
||||||
|
|
||||||
|
@ -326,7 +326,7 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
|
||||||
; HasProxy = false
|
; HasProxy = false
|
||||||
|
|
||||||
; Defaults for the users, if none is specified in the useraccounts table entry (ServiceURLs)
|
; 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"
|
; GatekeeperURI = "http://127.0.0.1:8002"
|
||||||
|
|
||||||
SRV_HomeURI = "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"
|
AuthenticationService = "OpenSim.Services.Connectors.dll:AuthenticationServicesConnector"
|
||||||
SimulationService ="OpenSim.Services.Connectors.dll:SimulationServiceConnector"
|
SimulationService ="OpenSim.Services.Connectors.dll:SimulationServiceConnector"
|
||||||
; how does the outside world reach me? This acts as public key too.
|
; 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"
|
; ExternalName = "http://127.0.0.1:8002"
|
||||||
|
|
||||||
; Does this grid allow incoming links to any region in it?
|
; 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"
|
UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
|
||||||
AvatarService = "OpenSim.Services.AvatarService.dll:AvatarService"
|
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"
|
; HomeURI = "http://127.0.0.1:8002"
|
||||||
|
|
||||||
; * The interface that local users get when they are in other grids.
|
; * 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"
|
LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGAssetService"
|
||||||
UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
|
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"
|
; HomeURI = "http://127.0.0.1:8002"
|
||||||
|
|
||||||
;; The asset types that this grid can export to / import from other grids.
|
;; 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"
|
UserAccountService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
|
||||||
|
|
||||||
;; What is the HomeURI of users associated with this grid?
|
;; 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"
|
; HomeURI = "http://127.0.0.1:8002"
|
||||||
|
|
||||||
|
|
||||||
|
|
117
prebuild.xml
117
prebuild.xml
|
@ -899,6 +899,7 @@
|
||||||
<Reference name="OpenSim.Framework"/>
|
<Reference name="OpenSim.Framework"/>
|
||||||
<Reference name="OpenSim.Framework.Console"/>
|
<Reference name="OpenSim.Framework.Console"/>
|
||||||
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
|
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
|
||||||
|
<Reference name="OpenSim.Server.Base"/>
|
||||||
<Reference name="OpenSim.Services.Interfaces"/>
|
<Reference name="OpenSim.Services.Interfaces"/>
|
||||||
<Reference name="OpenSim.Services.Base"/>
|
<Reference name="OpenSim.Services.Base"/>
|
||||||
<Reference name="OpenSim.Services.Connectors"/>
|
<Reference name="OpenSim.Services.Connectors"/>
|
||||||
|
@ -1913,121 +1914,6 @@
|
||||||
</Files>
|
</Files>
|
||||||
</Project>
|
</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 -->
|
<!-- Scene Server API Example Apps -->
|
||||||
|
|
||||||
<Project frameworkVersion="v3_5" name="OpenSim.Region.DataSnapshot" path="OpenSim/Region/DataSnapshot" type="Library">
|
<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="Nini" path="../../../bin/"/>
|
||||||
<Reference name="nunit.framework" path="../../../bin/"/>
|
<Reference name="nunit.framework" path="../../../bin/"/>
|
||||||
<Reference name="OpenMetaverse" path="../../../bin/"/>
|
<Reference name="OpenMetaverse" path="../../../bin/"/>
|
||||||
|
<Reference name="OpenMetaverse.StructuredData" path="../../../bin/"/>
|
||||||
<Reference name="OpenMetaverseTypes" path="../../../bin/"/>
|
<Reference name="OpenMetaverseTypes" path="../../../bin/"/>
|
||||||
<Reference name="OpenSim.Data"/>
|
<Reference name="OpenSim.Data"/>
|
||||||
<Reference name="OpenSim.Data.Null"/>
|
<Reference name="OpenSim.Data.Null"/>
|
||||||
|
|
Loading…
Reference in New Issue