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
|
||||
* tlaukkan/Tommil (Tommi S. E. Laukkanen, Bubble Cloud)
|
||||
* tyre
|
||||
* Vegaslon <vegaslon@gmail.com>
|
||||
* VikingErik
|
||||
* Vytek
|
||||
* 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; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Number of days that must pass before we update the access time on an asset when it has been fetched.
|
||||
/// </summary>
|
||||
private const int DaysBetweenAccessTimeUpdates = 30;
|
||||
|
||||
private bool m_enableCompression = false;
|
||||
private string m_connectionString;
|
||||
private object m_dbLock = new object();
|
||||
|
@ -133,10 +138,10 @@ namespace OpenSim.Data.MySQL
|
|||
dbcon.Open();
|
||||
|
||||
using (MySqlCommand cmd = new MySqlCommand(
|
||||
"SELECT name, description, asset_type, local, temporary, asset_flags, creator_id, data FROM xassetsmeta JOIN xassetsdata ON xassetsmeta.hash = xassetsdata.hash WHERE id=?id",
|
||||
"SELECT Name, Description, AccessTime, AssetType, Local, Temporary, AssetFlags, CreatorID, Data FROM XAssetsMeta JOIN XAssetsData ON XAssetsMeta.Hash = XAssetsData.Hash WHERE ID=?ID",
|
||||
dbcon))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("?id", assetID.ToString());
|
||||
cmd.Parameters.AddWithValue("?ID", assetID.ToString());
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -144,18 +149,18 @@ namespace OpenSim.Data.MySQL
|
|||
{
|
||||
if (dbReader.Read())
|
||||
{
|
||||
asset = new AssetBase(assetID, (string)dbReader["name"], (sbyte)dbReader["asset_type"], dbReader["creator_id"].ToString());
|
||||
asset.Data = (byte[])dbReader["data"];
|
||||
asset.Description = (string)dbReader["description"];
|
||||
asset = new AssetBase(assetID, (string)dbReader["Name"], (sbyte)dbReader["AssetType"], dbReader["CreatorID"].ToString());
|
||||
asset.Data = (byte[])dbReader["Data"];
|
||||
asset.Description = (string)dbReader["Description"];
|
||||
|
||||
string local = dbReader["local"].ToString();
|
||||
string local = dbReader["Local"].ToString();
|
||||
if (local.Equals("1") || local.Equals("true", StringComparison.InvariantCultureIgnoreCase))
|
||||
asset.Local = true;
|
||||
else
|
||||
asset.Local = false;
|
||||
|
||||
asset.Temporary = Convert.ToBoolean(dbReader["temporary"]);
|
||||
asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]);
|
||||
asset.Temporary = Convert.ToBoolean(dbReader["Temporary"]);
|
||||
asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]);
|
||||
|
||||
if (m_enableCompression)
|
||||
{
|
||||
|
@ -171,12 +176,14 @@ namespace OpenSim.Data.MySQL
|
|||
// asset.ID, asset.Name, asset.Data.Length, compressedLength);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateAccessTime(asset.Metadata, (int)dbReader["AccessTime"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Error("[MYSQL XASSET DATA]: MySql failure fetching asset " + assetID + ": " + e.Message);
|
||||
m_log.Error(string.Format("[MYSQL XASSET DATA]: Failure fetching asset {0}", assetID), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -242,23 +249,23 @@ namespace OpenSim.Data.MySQL
|
|||
{
|
||||
using (MySqlCommand cmd =
|
||||
new MySqlCommand(
|
||||
"replace INTO xassetsmeta(id, hash, name, description, asset_type, local, temporary, create_time, access_time, asset_flags, creator_id)" +
|
||||
"VALUES(?id, ?hash, ?name, ?description, ?asset_type, ?local, ?temporary, ?create_time, ?access_time, ?asset_flags, ?creator_id)",
|
||||
"replace INTO XAssetsMeta(ID, Hash, Name, Description, AssetType, Local, Temporary, CreateTime, AccessTime, AssetFlags, CreatorID)" +
|
||||
"VALUES(?ID, ?Hash, ?Name, ?Description, ?AssetType, ?Local, ?Temporary, ?CreateTime, ?AccessTime, ?AssetFlags, ?CreatorID)",
|
||||
dbcon))
|
||||
{
|
||||
// create unix epoch time
|
||||
int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow);
|
||||
cmd.Parameters.AddWithValue("?id", asset.ID);
|
||||
cmd.Parameters.AddWithValue("?hash", hash);
|
||||
cmd.Parameters.AddWithValue("?name", assetName);
|
||||
cmd.Parameters.AddWithValue("?description", assetDescription);
|
||||
cmd.Parameters.AddWithValue("?asset_type", asset.Type);
|
||||
cmd.Parameters.AddWithValue("?local", asset.Local);
|
||||
cmd.Parameters.AddWithValue("?temporary", asset.Temporary);
|
||||
cmd.Parameters.AddWithValue("?create_time", now);
|
||||
cmd.Parameters.AddWithValue("?access_time", now);
|
||||
cmd.Parameters.AddWithValue("?creator_id", asset.Metadata.CreatorID);
|
||||
cmd.Parameters.AddWithValue("?asset_flags", (int)asset.Flags);
|
||||
cmd.Parameters.AddWithValue("?ID", asset.ID);
|
||||
cmd.Parameters.AddWithValue("?Hash", hash);
|
||||
cmd.Parameters.AddWithValue("?Name", assetName);
|
||||
cmd.Parameters.AddWithValue("?Description", assetDescription);
|
||||
cmd.Parameters.AddWithValue("?AssetType", asset.Type);
|
||||
cmd.Parameters.AddWithValue("?Local", asset.Local);
|
||||
cmd.Parameters.AddWithValue("?Temporary", asset.Temporary);
|
||||
cmd.Parameters.AddWithValue("?CreateTime", now);
|
||||
cmd.Parameters.AddWithValue("?AccessTime", now);
|
||||
cmd.Parameters.AddWithValue("?CreatorID", asset.Metadata.CreatorID);
|
||||
cmd.Parameters.AddWithValue("?AssetFlags", (int)asset.Flags);
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
@ -278,11 +285,11 @@ namespace OpenSim.Data.MySQL
|
|||
{
|
||||
using (MySqlCommand cmd =
|
||||
new MySqlCommand(
|
||||
"INSERT INTO xassetsdata(hash, data) VALUES(?hash, ?data)",
|
||||
"INSERT INTO XAssetsData(Hash, Data) VALUES(?Hash, ?Data)",
|
||||
dbcon))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("?hash", hash);
|
||||
cmd.Parameters.AddWithValue("?data", asset.Data);
|
||||
cmd.Parameters.AddWithValue("?Hash", hash);
|
||||
cmd.Parameters.AddWithValue("?Data", asset.Data);
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
|
@ -303,41 +310,49 @@ namespace OpenSim.Data.MySQL
|
|||
}
|
||||
}
|
||||
|
||||
// private void UpdateAccessTime(AssetBase asset)
|
||||
// {
|
||||
// lock (m_dbLock)
|
||||
// {
|
||||
// using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
||||
// {
|
||||
// dbcon.Open();
|
||||
// MySqlCommand cmd =
|
||||
// new MySqlCommand("update assets set access_time=?access_time where id=?id",
|
||||
// dbcon);
|
||||
//
|
||||
// // need to ensure we dispose
|
||||
// try
|
||||
// {
|
||||
// using (cmd)
|
||||
// {
|
||||
// // create unix epoch time
|
||||
// int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow);
|
||||
// cmd.Parameters.AddWithValue("?id", asset.ID);
|
||||
// cmd.Parameters.AddWithValue("?access_time", now);
|
||||
// cmd.ExecuteNonQuery();
|
||||
// cmd.Dispose();
|
||||
// }
|
||||
// }
|
||||
// catch (Exception e)
|
||||
// {
|
||||
// m_log.ErrorFormat(
|
||||
// "[ASSETS DB]: " +
|
||||
// "MySql failure updating access_time for asset {0} with name {1}" + Environment.NewLine + e.ToString()
|
||||
// + Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
/// <summary>
|
||||
/// Updates the access time of the asset if it was accessed above a given threshhold amount of time.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This gives us some insight into assets which haven't ben accessed for a long period. This is only done
|
||||
/// over the threshold time to avoid excessive database writes as assets are fetched.
|
||||
/// </remarks>
|
||||
/// <param name='asset'></param>
|
||||
/// <param name='accessTime'></param>
|
||||
private void UpdateAccessTime(AssetMetadata assetMetadata, int accessTime)
|
||||
{
|
||||
DateTime now = DateTime.UtcNow;
|
||||
|
||||
if ((now - Utils.UnixTimeToDateTime(accessTime)).TotalDays < DaysBetweenAccessTimeUpdates)
|
||||
return;
|
||||
|
||||
lock (m_dbLock)
|
||||
{
|
||||
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
||||
{
|
||||
dbcon.Open();
|
||||
MySqlCommand cmd =
|
||||
new MySqlCommand("update XAssetsMeta set AccessTime=?AccessTime where ID=?ID", dbcon);
|
||||
|
||||
try
|
||||
{
|
||||
using (cmd)
|
||||
{
|
||||
// create unix epoch time
|
||||
cmd.Parameters.AddWithValue("?ID", assetMetadata.ID);
|
||||
cmd.Parameters.AddWithValue("?AccessTime", (int)Utils.DateTimeToUnixTime(now));
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[XASSET MYSQL DB]: Failure updating access_time for asset {0} with name {1}",
|
||||
assetMetadata.ID, assetMetadata.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We assume we already have the m_dbLock.
|
||||
|
@ -353,9 +368,9 @@ namespace OpenSim.Data.MySQL
|
|||
|
||||
bool exists = false;
|
||||
|
||||
using (MySqlCommand cmd = new MySqlCommand("SELECT hash FROM xassetsdata WHERE hash=?hash", dbcon))
|
||||
using (MySqlCommand cmd = new MySqlCommand("SELECT Hash FROM XAssetsData WHERE Hash=?Hash", dbcon))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("?hash", hash);
|
||||
cmd.Parameters.AddWithValue("?Hash", hash);
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -395,9 +410,9 @@ namespace OpenSim.Data.MySQL
|
|||
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
||||
{
|
||||
dbcon.Open();
|
||||
using (MySqlCommand cmd = new MySqlCommand("SELECT id FROM xassetsmeta WHERE id=?id", dbcon))
|
||||
using (MySqlCommand cmd = new MySqlCommand("SELECT ID FROM XAssetsMeta WHERE ID=?ID", dbcon))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("?id", uuid.ToString());
|
||||
cmd.Parameters.AddWithValue("?ID", uuid.ToString());
|
||||
|
||||
try
|
||||
{
|
||||
|
@ -412,8 +427,7 @@ namespace OpenSim.Data.MySQL
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[XASSETS DB]: MySql failure fetching asset {0}" + Environment.NewLine + e.ToString(), uuid);
|
||||
m_log.Error(string.Format("[XASSETS DB]: MySql failure fetching asset {0}", uuid), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -422,6 +436,7 @@ namespace OpenSim.Data.MySQL
|
|||
return assetExists;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of AssetMetadata objects. The list is a subset of
|
||||
/// the entire data set offset by <paramref name="start" /> containing
|
||||
|
@ -439,7 +454,7 @@ namespace OpenSim.Data.MySQL
|
|||
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
||||
{
|
||||
dbcon.Open();
|
||||
MySqlCommand cmd = new MySqlCommand("SELECT name,description,asset_type,temporary,id,asset_flags,creator_id FROM xassetsmeta LIMIT ?start, ?count", dbcon);
|
||||
MySqlCommand cmd = new MySqlCommand("SELECT Name, Description, AccessTime, AssetType, Temporary, ID, AssetFlags, CreatorID FROM XAssetsMeta LIMIT ?start, ?count", dbcon);
|
||||
cmd.Parameters.AddWithValue("?start", start);
|
||||
cmd.Parameters.AddWithValue("?count", count);
|
||||
|
||||
|
@ -450,17 +465,19 @@ namespace OpenSim.Data.MySQL
|
|||
while (dbReader.Read())
|
||||
{
|
||||
AssetMetadata metadata = new AssetMetadata();
|
||||
metadata.Name = (string)dbReader["name"];
|
||||
metadata.Description = (string)dbReader["description"];
|
||||
metadata.Type = (sbyte)dbReader["asset_type"];
|
||||
metadata.Temporary = Convert.ToBoolean(dbReader["temporary"]); // Not sure if this is correct.
|
||||
metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]);
|
||||
metadata.FullID = DBGuid.FromDB(dbReader["id"]);
|
||||
metadata.CreatorID = dbReader["creator_id"].ToString();
|
||||
metadata.Name = (string)dbReader["Name"];
|
||||
metadata.Description = (string)dbReader["Description"];
|
||||
metadata.Type = (sbyte)dbReader["AssetType"];
|
||||
metadata.Temporary = Convert.ToBoolean(dbReader["Temporary"]); // Not sure if this is correct.
|
||||
metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]);
|
||||
metadata.FullID = DBGuid.FromDB(dbReader["ID"]);
|
||||
metadata.CreatorID = dbReader["CreatorID"].ToString();
|
||||
|
||||
// We'll ignore this for now - it appears unused!
|
||||
// metadata.SHA1 = dbReader["hash"]);
|
||||
|
||||
UpdateAccessTime(metadata, (int)dbReader["AccessTime"]);
|
||||
|
||||
retList.Add(metadata);
|
||||
}
|
||||
}
|
||||
|
@ -485,9 +502,9 @@ namespace OpenSim.Data.MySQL
|
|||
{
|
||||
dbcon.Open();
|
||||
|
||||
using (MySqlCommand cmd = new MySqlCommand("delete from xassetsmeta where id=?id", dbcon))
|
||||
using (MySqlCommand cmd = new MySqlCommand("delete from XAssetsMeta where ID=?ID", dbcon))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("?id", id);
|
||||
cmd.Parameters.AddWithValue("?ID", id);
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
|
|
|
@ -3,24 +3,24 @@
|
|||
|
||||
BEGIN;
|
||||
|
||||
CREATE TABLE `xassetsmeta` (
|
||||
`id` char(36) NOT NULL,
|
||||
`hash` binary(32) NOT NULL,
|
||||
`name` varchar(64) NOT NULL,
|
||||
`description` varchar(64) NOT NULL,
|
||||
`asset_type` tinyint(4) NOT NULL,
|
||||
`local` tinyint(1) NOT NULL,
|
||||
`temporary` tinyint(1) NOT NULL,
|
||||
`create_time` int(11) NOT NULL,
|
||||
`access_time` int(11) NOT NULL,
|
||||
`asset_flags` int(11) NOT NULL,
|
||||
`creator_id` varchar(128) NOT NULL,
|
||||
CREATE TABLE `XAssetsMeta` (
|
||||
`ID` char(36) NOT NULL,
|
||||
`Hash` binary(32) NOT NULL,
|
||||
`Name` varchar(64) NOT NULL,
|
||||
`Description` varchar(64) NOT NULL,
|
||||
`AssetType` tinyint(4) NOT NULL,
|
||||
`Local` tinyint(1) NOT NULL,
|
||||
`Temporary` tinyint(1) NOT NULL,
|
||||
`CreateTime` int(11) NOT NULL,
|
||||
`AccessTime` int(11) NOT NULL,
|
||||
`AssetFlags` int(11) NOT NULL,
|
||||
`CreatorID` varchar(128) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1';
|
||||
|
||||
CREATE TABLE `xassetsdata` (
|
||||
`hash` binary(32) NOT NULL,
|
||||
`data` longblob NOT NULL,
|
||||
CREATE TABLE `XAssetsData` (
|
||||
`Hash` binary(32) NOT NULL,
|
||||
`Data` longblob NOT NULL,
|
||||
PRIMARY KEY (`hash`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1';
|
||||
|
||||
|
|
|
@ -180,7 +180,7 @@ namespace OpenSim.Framework
|
|||
/// Validate the key used for storing separate data stores.
|
||||
/// </summary>
|
||||
/// <param name='key'></param>
|
||||
private static void ValidateKey(string key)
|
||||
public static void ValidateKey(string key)
|
||||
{
|
||||
if (key.Length < MIN_STORE_NAME_LENGTH)
|
||||
throw new Exception("Minimum store name length is " + MIN_STORE_NAME_LENGTH);
|
||||
|
|
|
@ -25,48 +25,74 @@
|
|||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using System.Xml.Serialization;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.StructuredData;
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.Rest
|
||||
namespace OpenSim.Framework
|
||||
{
|
||||
public class RestXmlWriter: XmlTextWriter
|
||||
/// <summary>
|
||||
/// This class stores and retrieves dynamic objects.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Experimental - DO NOT USE.
|
||||
/// </remarks>
|
||||
public class DOMap
|
||||
{
|
||||
private StringWriter m_sw = null;
|
||||
|
||||
public RestXmlWriter(StringWriter sw) : base(sw)
|
||||
private IDictionary<string, object> m_map;
|
||||
|
||||
public void Add(string key, object dynObj)
|
||||
{
|
||||
m_sw = sw;
|
||||
Formatting = Formatting.Indented;
|
||||
DAMap.ValidateKey(key);
|
||||
|
||||
lock (this)
|
||||
{
|
||||
if (m_map == null)
|
||||
m_map = new Dictionary<string, object>();
|
||||
|
||||
m_map.Add(key, dynObj);
|
||||
}
|
||||
}
|
||||
|
||||
public RestXmlWriter(TextWriter textWriter) : base(textWriter)
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
return Get(key) != null;
|
||||
}
|
||||
|
||||
public RestXmlWriter(Stream stream)
|
||||
: this(stream, Encoding.UTF8)
|
||||
/// <summary>
|
||||
/// Get a dynamic object
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Not providing an index method so that users can't casually overwrite each other's objects.
|
||||
/// </remarks>
|
||||
/// <param name='key'></param>
|
||||
public object Get(string key)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (m_map == null)
|
||||
return null;
|
||||
else
|
||||
return m_map[key];
|
||||
}
|
||||
}
|
||||
|
||||
public RestXmlWriter(Stream stream, Encoding enc) : base(stream, enc)
|
||||
public bool Remove(string key)
|
||||
{
|
||||
}
|
||||
|
||||
public override void WriteStartDocument()
|
||||
{
|
||||
}
|
||||
|
||||
public override void WriteStartDocument(bool standalone)
|
||||
{
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
Flush();
|
||||
Close();
|
||||
return m_sw.ToString();
|
||||
lock (this)
|
||||
{
|
||||
if (m_map == null)
|
||||
return false;
|
||||
else
|
||||
return m_map.Remove(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -55,6 +55,13 @@ namespace OpenSim.Region.Framework.Interfaces
|
|||
/// <returns>Land object at the point supplied</returns>
|
||||
ILandObject GetLandObject(float x, float y);
|
||||
|
||||
/// <summary>
|
||||
/// Get the parcel at the specified point
|
||||
/// </summary>
|
||||
/// <param name="position">Vector where x and y components are between 0 and 256. z component is ignored.</param>
|
||||
/// <returns>Land object at the point supplied</returns>
|
||||
ILandObject GetLandObject(Vector3 position);
|
||||
|
||||
/// <summary>
|
||||
/// Get the parcels near the specified point
|
||||
/// </summary>
|
||||
|
|
|
@ -218,7 +218,7 @@ namespace OpenSim.Framework
|
|||
Console.WriteLine ("Looking for updates...");
|
||||
Repositories.UpdateAllRepositories (ps);
|
||||
Console.WriteLine ("Available add-in updates:");
|
||||
bool found = false;
|
||||
|
||||
AddinRepositoryEntry[] entries = Repositories.GetAvailableUpdates();
|
||||
|
||||
foreach (AddinRepositoryEntry entry in entries)
|
||||
|
@ -541,7 +541,7 @@ namespace OpenSim.Framework
|
|||
{
|
||||
list.AddRange(PluginRegistry.GetAddins());
|
||||
}
|
||||
catch(Exception e)
|
||||
catch (Exception)
|
||||
{
|
||||
Addin[] x = xlist.ToArray(typeof(Addin)) as Addin[];
|
||||
return x;
|
||||
|
|
|
@ -133,17 +133,7 @@ namespace OpenSim.Framework.Servers
|
|||
/// Performs initialisation of the scene, such as loading configuration from disk.
|
||||
/// </summary>
|
||||
public virtual void Startup()
|
||||
{
|
||||
m_log.Info("[STARTUP]: Beginning startup processing");
|
||||
|
||||
m_log.Info("[STARTUP]: OpenSimulator version: " + m_version + Environment.NewLine);
|
||||
// clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and
|
||||
// the clr version number doesn't match the project version number under Mono.
|
||||
//m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine);
|
||||
m_log.InfoFormat(
|
||||
"[STARTUP]: Operating system version: {0}, .NET platform {1}, {2}-bit\n",
|
||||
Environment.OSVersion, Environment.OSVersion.Platform, Util.Is64BitProcess() ? "64" : "32");
|
||||
|
||||
{
|
||||
StartupSpecific();
|
||||
|
||||
TimeSpan timeTaken = DateTime.Now - m_startuptime;
|
||||
|
|
|
@ -486,7 +486,9 @@ namespace OpenSim.Framework.Servers.HttpServer
|
|||
{
|
||||
try
|
||||
{
|
||||
SendHTML500(response);
|
||||
byte[] buffer500 = SendHTML500(response);
|
||||
response.Body.Write(buffer500,0,buffer500.Length);
|
||||
response.Body.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
@ -719,7 +721,15 @@ namespace OpenSim.Framework.Servers.HttpServer
|
|||
catch (Exception e)
|
||||
{
|
||||
m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e);
|
||||
SendHTML500(response);
|
||||
try
|
||||
{
|
||||
byte[] buffer500 = SendHTML500(response);
|
||||
response.Body.Write(buffer500, 0, buffer500.Length);
|
||||
response.Body.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
|
@ -1746,7 +1756,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
|||
response.SendChunked = false;
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.ContentEncoding = Encoding.UTF8;
|
||||
|
||||
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
@ -1912,6 +1923,12 @@ namespace OpenSim.Framework.Servers.HttpServer
|
|||
m_rpcHandlers.Remove(method);
|
||||
}
|
||||
|
||||
public void RemoveJsonRPCHandler(string method)
|
||||
{
|
||||
lock(jsonRpcHandlers)
|
||||
jsonRpcHandlers.Remove(method);
|
||||
}
|
||||
|
||||
public bool RemoveLLSDHandler(string path, LLSDMethod handler)
|
||||
{
|
||||
lock (m_llsdHandlers)
|
||||
|
|
|
@ -140,6 +140,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
|||
void RemoveStreamHandler(string httpMethod, string path);
|
||||
|
||||
void RemoveXmlRPCHandler(string method);
|
||||
|
||||
void RemoveJsonRPCHandler(string method);
|
||||
|
||||
string GetHTTP404(string host);
|
||||
|
||||
|
|
|
@ -113,6 +113,26 @@ namespace OpenSim.Framework.Servers
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log information about the circumstances in which we're running (OpenSimulator version number, CLR details,
|
||||
/// etc.).
|
||||
/// </summary>
|
||||
public void LogEnvironmentInformation()
|
||||
{
|
||||
// FIXME: This should be done down in ServerBase but we need to sort out and refactor the log4net
|
||||
// XmlConfigurator calls first accross servers.
|
||||
m_log.InfoFormat("[SERVER BASE]: Starting in {0}", m_startupDirectory);
|
||||
|
||||
m_log.InfoFormat("[SERVER BASE]: OpenSimulator version: {0}", m_version);
|
||||
|
||||
// clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and
|
||||
// the clr version number doesn't match the project version number under Mono.
|
||||
//m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine);
|
||||
m_log.InfoFormat(
|
||||
"[SERVER BASE]: Operating system version: {0}, .NET platform {1}, {2}-bit",
|
||||
Environment.OSVersion, Environment.OSVersion.Platform, Util.Is64BitProcess() ? "64" : "32");
|
||||
}
|
||||
|
||||
public void RegisterCommonAppenders(IConfig startupConfig)
|
||||
{
|
||||
ILoggerRepository repository = LogManager.GetRepository();
|
||||
|
|
|
@ -303,12 +303,12 @@ namespace OpenSim.Framework
|
|||
// Clamp the maximum magnitude of a vector
|
||||
public static Vector3 ClampV(Vector3 x, float max)
|
||||
{
|
||||
Vector3 ret = x;
|
||||
float lenSq = x.LengthSquared();
|
||||
if (lenSq > (max * max))
|
||||
{
|
||||
x = x / x.Length() * max;
|
||||
}
|
||||
|
||||
return x;
|
||||
}
|
||||
|
||||
|
|
|
@ -159,6 +159,7 @@ namespace OpenSim
|
|||
|
||||
MainConsole.Instance = m_console;
|
||||
|
||||
LogEnvironmentInformation();
|
||||
RegisterCommonAppenders(Config.Configs["Startup"]);
|
||||
RegisterConsoleCommands();
|
||||
|
||||
|
|
|
@ -134,10 +134,6 @@ namespace OpenSim
|
|||
/// <param name="configSource"></param>
|
||||
public OpenSimBase(IConfigSource configSource) : base()
|
||||
{
|
||||
// FIXME: This should be done down in ServerBase but we need to sort out and refactor the log4net
|
||||
// XmlConfigurator calls first accross servers.
|
||||
m_log.InfoFormat("[SERVER BASE]: Starting in {0}", m_startupDirectory);
|
||||
|
||||
LoadConfigSettings(configSource);
|
||||
}
|
||||
|
||||
|
|
|
@ -49,8 +49,10 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
|
|||
private TestScene m_scene;
|
||||
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
public override void SetUp()
|
||||
{
|
||||
base.SetUp();
|
||||
|
||||
uint port = 9999;
|
||||
uint sslPort = 9998;
|
||||
|
||||
|
|
|
@ -4581,7 +4581,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
rinfopack.AgentData = new RegionInfoPacket.AgentDataBlock();
|
||||
rinfopack.AgentData.AgentID = AgentId;
|
||||
rinfopack.AgentData.SessionID = SessionId;
|
||||
|
||||
rinfopack.RegionInfo3 = new RegionInfoPacket.RegionInfo3Block[0];
|
||||
|
||||
OutPacket(rinfopack, ThrottleOutPacketType.Task);
|
||||
}
|
||||
|
@ -7069,7 +7069,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
|
||||
if (handlerUpdatePrimFlags != null)
|
||||
{
|
||||
byte[] data = Pack.ToBytes();
|
||||
// byte[] data = Pack.ToBytes();
|
||||
// 46,47,48 are special positions within the packet
|
||||
// This may change so perhaps we need a better way
|
||||
// of storing this (OMV.FlagUpdatePacket.UsePhysics,etc?)
|
||||
|
|
|
@ -278,25 +278,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
m_shouldCollectStats = false;
|
||||
if (config != null)
|
||||
{
|
||||
if (config.Contains("enabled") && config.GetBoolean("enabled"))
|
||||
{
|
||||
if (config.Contains("collect_packet_headers"))
|
||||
m_shouldCollectStats = config.GetBoolean("collect_packet_headers");
|
||||
if (config.Contains("packet_headers_period_seconds"))
|
||||
{
|
||||
binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("region_stats_period_seconds"));
|
||||
}
|
||||
if (config.Contains("stats_dir"))
|
||||
{
|
||||
binStatsDir = config.GetString("stats_dir");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_shouldCollectStats = false;
|
||||
}
|
||||
}
|
||||
#endregion BinaryStats
|
||||
m_shouldCollectStats = config.GetBoolean("Enabled", false);
|
||||
binStatsMaxFilesize = TimeSpan.FromSeconds(config.GetInt("packet_headers_period_seconds", 300));
|
||||
binStatsDir = config.GetString("stats_dir", ".");
|
||||
m_aggregatedBWStats = config.GetBoolean("aggregatedBWStats", false);
|
||||
}
|
||||
#endregion BinaryStats
|
||||
|
||||
m_throttle = new TokenBucket(null, sceneThrottleBps);
|
||||
ThrottleRates = new ThrottleRates(configSource);
|
||||
|
@ -1266,8 +1253,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
|||
static object binStatsLogLock = new object();
|
||||
static string binStatsDir = "";
|
||||
|
||||
//for Aggregated In/Out BW logging
|
||||
static bool m_aggregatedBWStats = false;
|
||||
static long m_aggregatedBytesIn = 0;
|
||||
static long m_aggregatedByestOut = 0;
|
||||
static object aggBWStatsLock = new object();
|
||||
|
||||
public static long AggregatedLLUDPBytesIn
|
||||
{
|
||||
get { return m_aggregatedBytesIn; }
|
||||
}
|
||||
public static long AggregatedLLUDPBytesOut
|
||||
{
|
||||
get {return m_aggregatedByestOut;}
|
||||
}
|
||||
|
||||
public static void LogPacketHeader(bool incoming, uint circuit, byte flags, PacketType packetType, ushort size)
|
||||
{
|
||||
if (m_aggregatedBWStats)
|
||||
{
|
||||
lock (aggBWStatsLock)
|
||||
{
|
||||
if (incoming)
|
||||
m_aggregatedBytesIn += size;
|
||||
else
|
||||
m_aggregatedByestOut += size;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_shouldCollectStats) return;
|
||||
|
||||
// Binary logging format is TTTTTTTTCCCCFPPPSS, T=Time, C=Circuit, F=Flags, P=PacketType, S=size
|
||||
|
|
|
@ -289,21 +289,22 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
|||
if (!Enabled)
|
||||
return false;
|
||||
|
||||
if (AttachObjectInternal(sp, group, attachmentPt, silent, temp, append))
|
||||
{
|
||||
m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
return AttachObjectInternal(sp, group, attachmentPt, silent, temp, append);
|
||||
}
|
||||
|
||||
private bool AttachObjectInternal(IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp, bool append)
|
||||
{
|
||||
// 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);
|
||||
|
||||
/// <summary>
|
||||
/// Internal method which actually does all the work for attaching an object.
|
||||
/// </summary>
|
||||
/// <returns>The object attached.</returns>
|
||||
/// <param name='sp'></param>
|
||||
/// <param name='group'>The object to attach.</param>
|
||||
/// <param name='attachmentPt'></param>
|
||||
/// <param name='silent'></param>
|
||||
/// <param name='temp'></param>
|
||||
/// <param name='resumeScripts'>If true then scripts are resumed on the attached object.</param>
|
||||
private bool AttachObjectInternal(
|
||||
IScenePresence sp, SceneObjectGroup group, uint attachmentPt, bool silent, bool temp, bool resumeScripts)
|
||||
{
|
||||
if (group.GetSittingAvatarsCount() != 0)
|
||||
{
|
||||
// m_log.WarnFormat(
|
||||
|
@ -314,6 +315,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
|||
}
|
||||
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
|
||||
|
||||
if (attachments.Contains(group))
|
||||
{
|
||||
// m_log.WarnFormat(
|
||||
|
@ -374,6 +376,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
|||
UpdateUserInventoryWithAttachment(sp, group, attachmentPt, temp, append);
|
||||
|
||||
AttachToAgent(sp, group, attachmentPt, attachPos, silent);
|
||||
|
||||
if (resumeScripts)
|
||||
{
|
||||
// Fire after attach, so we don't get messy perms dialogs
|
||||
// 4 == AttachedRez
|
||||
group.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
|
||||
group.ResumeScripts();
|
||||
}
|
||||
|
||||
// Do this last so that event listeners have access to all the effects of the attachment
|
||||
m_scene.EventManager.TriggerOnAttach(group.LocalId, group.FromItemID, sp.UUID);
|
||||
}
|
||||
|
||||
return true;
|
||||
|
@ -400,8 +413,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
|||
return null;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2}",
|
||||
// (AttachmentPoint)AttachmentPt, itemID, sp.Name);
|
||||
// "[ATTACHMENTS MODULE]: RezSingleAttachmentFromInventory to point {0} from item {1} for {2} in {3}",
|
||||
// (AttachmentPoint)AttachmentPt, itemID, sp.Name, m_scene.Name);
|
||||
|
||||
bool append = (AttachmentPt & 0x80) != 0;
|
||||
AttachmentPt &= 0x7f;
|
||||
|
@ -533,6 +546,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
|||
return;
|
||||
}
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[ATTACHMENTS MODULE]: Detaching object {0} {1} for {2} in {3}",
|
||||
// so.Name, so.LocalId, sp.Name, m_scene.Name);
|
||||
|
||||
// Scripts MUST be snapshotted before the object is
|
||||
// removed from the scene because doing otherwise will
|
||||
// clobber the run flag
|
||||
|
@ -854,61 +871,42 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
|||
return null;
|
||||
}
|
||||
|
||||
// Remove any previous attachments
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
|
||||
string previousAttachmentScriptedState = null;
|
||||
|
||||
// At the moment we can only deal with a single attachment
|
||||
if (attachments.Count != 0)
|
||||
DetachSingleAttachmentToInv(sp, attachments[0]);
|
||||
|
||||
lock (sp.AttachmentsSyncLock)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}",
|
||||
// objatt.Name, sp.Name, attachmentPt, m_scene.Name);
|
||||
|
||||
// HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
|
||||
objatt.HasGroupChanged = false;
|
||||
bool tainted = false;
|
||||
if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
|
||||
tainted = true;
|
||||
// HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
|
||||
objatt.HasGroupChanged = false;
|
||||
bool tainted = false;
|
||||
if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
|
||||
tainted = true;
|
||||
|
||||
// FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal
|
||||
// course of events. If not, then it's probably not worth trying to recover the situation
|
||||
// since this is more likely to trigger further exceptions and confuse later debugging. If
|
||||
// exceptions can be thrown in expected error conditions (not NREs) then make this consistent
|
||||
// since other normal error conditions will simply return false instead.
|
||||
// This will throw if the attachment fails
|
||||
try
|
||||
{
|
||||
AttachObjectInternal(sp, objatt, attachmentPt, false, false, append);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
|
||||
objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
|
||||
|
||||
// Make sure the object doesn't stick around and bail
|
||||
sp.RemoveAttachment(objatt);
|
||||
m_scene.DeleteSceneObject(objatt, false);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (tainted)
|
||||
objatt.HasGroupChanged = true;
|
||||
|
||||
// Fire after attach, so we don't get messy perms dialogs
|
||||
// 4 == AttachedRez
|
||||
objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
|
||||
objatt.ResumeScripts();
|
||||
|
||||
// Do this last so that event listeners have access to all the effects of the attachment
|
||||
m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID);
|
||||
|
||||
return objatt;
|
||||
// FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal
|
||||
// course of events. If not, then it's probably not worth trying to recover the situation
|
||||
// since this is more likely to trigger further exceptions and confuse later debugging. If
|
||||
// exceptions can be thrown in expected error conditions (not NREs) then make this consistent
|
||||
// since other normal error conditions will simply return false instead.
|
||||
// This will throw if the attachment fails
|
||||
try
|
||||
{
|
||||
AttachObjectInternal(sp, objatt, attachmentPt, false, false, append);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
|
||||
objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
|
||||
|
||||
// Make sure the object doesn't stick around and bail
|
||||
sp.RemoveAttachment(objatt);
|
||||
m_scene.DeleteSceneObject(objatt, false);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (tainted)
|
||||
objatt.HasGroupChanged = true;
|
||||
|
||||
return objatt;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -228,6 +228,120 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
|||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestWearAttachmentFromGround()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
Scene scene = CreateTestScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
||||
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
|
||||
|
||||
SceneObjectGroup so2 = SceneHelpers.AddSceneObject(scene, "att2", sp.UUID);
|
||||
|
||||
{
|
||||
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, "att1", sp.UUID);
|
||||
|
||||
m_numberOfAttachEventsFired = 0;
|
||||
scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Default, false, false);
|
||||
|
||||
// Check status on scene presence
|
||||
Assert.That(sp.HasAttachments(), Is.True);
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments();
|
||||
Assert.That(attachments.Count, Is.EqualTo(1));
|
||||
SceneObjectGroup attSo = attachments[0];
|
||||
Assert.That(attSo.Name, Is.EqualTo(so.Name));
|
||||
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
|
||||
Assert.That(attSo.IsAttachment);
|
||||
Assert.That(attSo.UsesPhysics, Is.False);
|
||||
Assert.That(attSo.IsTemporary, Is.False);
|
||||
|
||||
// Check item status
|
||||
Assert.That(
|
||||
sp.Appearance.GetAttachpoint(attSo.FromItemID),
|
||||
Is.EqualTo((int)AttachmentPoint.LeftHand));
|
||||
|
||||
InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
|
||||
Assert.That(attachmentItem, Is.Not.Null);
|
||||
Assert.That(attachmentItem.Name, Is.EqualTo(so.Name));
|
||||
|
||||
InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object);
|
||||
Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
|
||||
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(2));
|
||||
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
// Test wearing a different attachment from the ground.
|
||||
{
|
||||
scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, false);
|
||||
|
||||
// Check status on scene presence
|
||||
Assert.That(sp.HasAttachments(), Is.True);
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments();
|
||||
Assert.That(attachments.Count, Is.EqualTo(1));
|
||||
SceneObjectGroup attSo = attachments[0];
|
||||
Assert.That(attSo.Name, Is.EqualTo(so2.Name));
|
||||
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
|
||||
Assert.That(attSo.IsAttachment);
|
||||
Assert.That(attSo.UsesPhysics, Is.False);
|
||||
Assert.That(attSo.IsTemporary, Is.False);
|
||||
|
||||
// Check item status
|
||||
Assert.That(
|
||||
sp.Appearance.GetAttachpoint(attSo.FromItemID),
|
||||
Is.EqualTo((int)AttachmentPoint.LeftHand));
|
||||
|
||||
InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
|
||||
Assert.That(attachmentItem, Is.Not.Null);
|
||||
Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name));
|
||||
|
||||
InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object);
|
||||
Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
|
||||
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
|
||||
}
|
||||
|
||||
// Test rewearing an already worn attachment from ground. Nothing should happen.
|
||||
{
|
||||
scene.AttachmentsModule.AttachObject(sp, so2, (uint)AttachmentPoint.Default, false, false);
|
||||
|
||||
// Check status on scene presence
|
||||
Assert.That(sp.HasAttachments(), Is.True);
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments();
|
||||
Assert.That(attachments.Count, Is.EqualTo(1));
|
||||
SceneObjectGroup attSo = attachments[0];
|
||||
Assert.That(attSo.Name, Is.EqualTo(so2.Name));
|
||||
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
|
||||
Assert.That(attSo.IsAttachment);
|
||||
Assert.That(attSo.UsesPhysics, Is.False);
|
||||
Assert.That(attSo.IsTemporary, Is.False);
|
||||
|
||||
// Check item status
|
||||
Assert.That(
|
||||
sp.Appearance.GetAttachpoint(attSo.FromItemID),
|
||||
Is.EqualTo((int)AttachmentPoint.LeftHand));
|
||||
|
||||
InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
|
||||
Assert.That(attachmentItem, Is.Not.Null);
|
||||
Assert.That(attachmentItem.Name, Is.EqualTo(so2.Name));
|
||||
|
||||
InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object);
|
||||
Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
|
||||
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test that we do not attempt to attach an in-world object that someone else is sitting on.
|
||||
/// </summary>
|
||||
|
@ -275,29 +389,140 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
|||
|
||||
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
|
||||
|
||||
m_numberOfAttachEventsFired = 0;
|
||||
scene.AttachmentsModule.RezSingleAttachmentFromInventory(
|
||||
sp, attItem.ID, (uint)AttachmentPoint.Chest);
|
||||
{
|
||||
scene.AttachmentsModule.RezSingleAttachmentFromInventory(
|
||||
sp, attItem.ID, (uint)AttachmentPoint.Chest);
|
||||
|
||||
// Check scene presence status
|
||||
Assert.That(sp.HasAttachments(), Is.True);
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments();
|
||||
Assert.That(attachments.Count, Is.EqualTo(1));
|
||||
SceneObjectGroup attSo = attachments[0];
|
||||
Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
|
||||
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
|
||||
Assert.That(attSo.IsAttachment);
|
||||
Assert.That(attSo.UsesPhysics, Is.False);
|
||||
Assert.That(attSo.IsTemporary, Is.False);
|
||||
// Check scene presence status
|
||||
Assert.That(sp.HasAttachments(), Is.True);
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments();
|
||||
Assert.That(attachments.Count, Is.EqualTo(1));
|
||||
SceneObjectGroup attSo = attachments[0];
|
||||
Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
|
||||
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
|
||||
Assert.That(attSo.IsAttachment);
|
||||
Assert.That(attSo.UsesPhysics, Is.False);
|
||||
Assert.That(attSo.IsTemporary, Is.False);
|
||||
|
||||
// Check appearance status
|
||||
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
|
||||
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
|
||||
// Check appearance status
|
||||
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
|
||||
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
||||
// Test attaching an already attached attachment
|
||||
{
|
||||
scene.AttachmentsModule.RezSingleAttachmentFromInventory(
|
||||
sp, attItem.ID, (uint)AttachmentPoint.Chest);
|
||||
|
||||
// Check scene presence status
|
||||
Assert.That(sp.HasAttachments(), Is.True);
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments();
|
||||
Assert.That(attachments.Count, Is.EqualTo(1));
|
||||
SceneObjectGroup attSo = attachments[0];
|
||||
Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
|
||||
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
|
||||
Assert.That(attSo.IsAttachment);
|
||||
Assert.That(attSo.UsesPhysics, Is.False);
|
||||
Assert.That(attSo.IsTemporary, Is.False);
|
||||
|
||||
// Check appearance status
|
||||
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
|
||||
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test wearing an attachment from inventory, as opposed to explicit choosing the rez point
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestWearAttachmentFromInventory()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
Scene scene = CreateTestScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
||||
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID);
|
||||
|
||||
InventoryItemBase attItem1 = CreateAttachmentItem(scene, ua1.PrincipalID, "att1", 0x10, 0x20);
|
||||
InventoryItemBase attItem2 = CreateAttachmentItem(scene, ua1.PrincipalID, "att2", 0x11, 0x21);
|
||||
|
||||
{
|
||||
m_numberOfAttachEventsFired = 0;
|
||||
scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem1.ID, (uint)AttachmentPoint.Default);
|
||||
|
||||
// default attachment point is currently the left hand.
|
||||
Assert.That(sp.HasAttachments(), Is.True);
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments();
|
||||
Assert.That(attachments.Count, Is.EqualTo(1));
|
||||
SceneObjectGroup attSo = attachments[0];
|
||||
Assert.That(attSo.Name, Is.EqualTo(attItem1.Name));
|
||||
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
|
||||
Assert.That(attSo.IsAttachment);
|
||||
|
||||
// Check appearance status
|
||||
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
|
||||
Assert.That(sp.Appearance.GetAttachpoint(attItem1.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
// Test wearing a second attachment at the same position
|
||||
// Until multiple attachments at one point is implemented, this will remove the first attachment
|
||||
// This test relies on both attachments having the same default attachment point (in this case LeftHand
|
||||
// since none other has been set).
|
||||
{
|
||||
scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default);
|
||||
|
||||
// default attachment point is currently the left hand.
|
||||
Assert.That(sp.HasAttachments(), Is.True);
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments();
|
||||
Assert.That(attachments.Count, Is.EqualTo(1));
|
||||
SceneObjectGroup attSo = attachments[0];
|
||||
Assert.That(attSo.Name, Is.EqualTo(attItem2.Name));
|
||||
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
|
||||
Assert.That(attSo.IsAttachment);
|
||||
|
||||
// Check appearance status
|
||||
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
|
||||
Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
|
||||
}
|
||||
|
||||
// Test wearing an already attached attachment
|
||||
{
|
||||
scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, attItem2.ID, (uint)AttachmentPoint.Default);
|
||||
|
||||
// default attachment point is currently the left hand.
|
||||
Assert.That(sp.HasAttachments(), Is.True);
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments();
|
||||
Assert.That(attachments.Count, Is.EqualTo(1));
|
||||
SceneObjectGroup attSo = attachments[0];
|
||||
Assert.That(attSo.Name, Is.EqualTo(attItem2.Name));
|
||||
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.LeftHand));
|
||||
Assert.That(attSo.IsAttachment);
|
||||
|
||||
// Check appearance status
|
||||
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
|
||||
Assert.That(sp.Appearance.GetAttachpoint(attItem2.ID), Is.EqualTo((int)AttachmentPoint.LeftHand));
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
|
||||
// Check events
|
||||
Assert.That(m_numberOfAttachEventsFired, Is.EqualTo(3));
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
|
@ -39,7 +39,7 @@ using OpenSim.Region.Framework;
|
|||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
|
||||
namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule
|
||||
namespace OpenSim.Region.CoreModules.Framework.DynamicAttributes.DAExampleModule
|
||||
{
|
||||
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DAExampleModule")]
|
||||
public class DAExampleModule : INonSharedRegionModule
|
||||
|
@ -48,6 +48,8 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule
|
|||
|
||||
private static readonly bool ENABLED = false; // enable for testing
|
||||
|
||||
public const string DANamespace = "DAExample Module";
|
||||
|
||||
protected Scene m_scene;
|
||||
protected IDialogModule m_dialogMod;
|
||||
|
||||
|
@ -85,19 +87,29 @@ namespace OpenSim.Region.Framework.DynamicAttributes.DAExampleModule
|
|||
{
|
||||
OSDMap attrs = null;
|
||||
SceneObjectPart sop = m_scene.GetSceneObjectPart(groupId);
|
||||
if (!sop.DynAttrs.TryGetValue(Name, out attrs))
|
||||
|
||||
if (sop == null)
|
||||
return true;
|
||||
|
||||
if (!sop.DynAttrs.TryGetValue(DANamespace, out attrs))
|
||||
attrs = new OSDMap();
|
||||
|
||||
OSDInteger newValue;
|
||||
|
||||
if (!attrs.ContainsKey("moves"))
|
||||
newValue = new OSDInteger(1);
|
||||
else
|
||||
newValue = new OSDInteger(((OSDInteger)attrs["moves"]).AsInteger() + 1);
|
||||
|
||||
attrs["moves"] = newValue;
|
||||
|
||||
sop.DynAttrs[Name] = attrs;
|
||||
// We have to lock on the entire dynamic attributes map to avoid race conditions with serialization code.
|
||||
lock (sop.DynAttrs)
|
||||
{
|
||||
if (!attrs.ContainsKey("moves"))
|
||||
newValue = new OSDInteger(1);
|
||||
else
|
||||
newValue = new OSDInteger(attrs["moves"].AsInteger() + 1);
|
||||
|
||||
attrs["moves"] = newValue;
|
||||
|
||||
sop.DynAttrs[DANamespace] = attrs;
|
||||
}
|
||||
|
||||
sop.ParentGroup.HasGroupChanged = true;
|
||||
|
||||
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>
|
||||
public bool WaitForAgentArrivedAtDestination { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// If true then we ask the viewer to disable teleport cancellation and ignore teleport requests.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is useful in situations where teleport is very likely to always succeed and we want to avoid a
|
||||
/// situation where avatars can be come 'stuck' due to a failed teleport cancellation. Unfortunately, the
|
||||
/// nature of the teleport protocol makes it extremely difficult (maybe impossible) to make teleport
|
||||
/// cancellation consistently suceed.
|
||||
/// </remarks>
|
||||
public bool DisableInterRegionTeleportCancellation { get; set; }
|
||||
|
||||
protected bool m_Enabled = false;
|
||||
|
||||
public Scene Scene { get; private set; }
|
||||
|
@ -116,6 +127,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
IConfig transferConfig = source.Configs["EntityTransfer"];
|
||||
if (transferConfig != null)
|
||||
{
|
||||
DisableInterRegionTeleportCancellation
|
||||
= transferConfig.GetBoolean("DisableInterRegionTeleportCancellation", false);
|
||||
|
||||
WaitForAgentArrivedAtDestination
|
||||
= transferConfig.GetBoolean("wait_for_callback", WaitForAgentArrivedAtDestinationDefault);
|
||||
|
||||
|
@ -150,6 +164,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
{
|
||||
client.OnTeleportHomeRequest += TeleportHome;
|
||||
client.OnTeleportLandmarkRequest += RequestTeleportLandmark;
|
||||
|
||||
if (!DisableInterRegionTeleportCancellation)
|
||||
client.OnTeleportCancel += OnClientCancelTeleport;
|
||||
}
|
||||
|
||||
public virtual void Close() {}
|
||||
|
@ -168,6 +185,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
|
||||
#region Agent Teleports
|
||||
|
||||
private void OnClientCancelTeleport(IClientAPI client)
|
||||
{
|
||||
m_entityTransferStateMachine.UpdateInTransit(client.AgentId, AgentTransferState.Cancelling);
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[ENTITY TRANSFER MODULE]: Received teleport cancel request from {0} in {1}", client.Name, Scene.Name);
|
||||
}
|
||||
|
||||
public void Teleport(ScenePresence sp, ulong regionHandle, Vector3 position, Vector3 lookAt, uint teleportFlags)
|
||||
{
|
||||
if (sp.Scene.Permissions.IsGridGod(sp.UUID))
|
||||
|
@ -519,6 +544,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
if (sp.ParentID != (uint)0)
|
||||
sp.StandUp();
|
||||
|
||||
if (DisableInterRegionTeleportCancellation)
|
||||
teleportFlags |= (uint)TeleportFlags.DisableCancel;
|
||||
|
||||
// At least on LL 3.3.4, this is not strictly necessary - a teleport will succeed without sending this to
|
||||
// the viewer. However, it might mean that the viewer does not see the black teleport screen (untested).
|
||||
sp.ControllingClient.SendTeleportStart(teleportFlags);
|
||||
|
@ -567,6 +595,15 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
return;
|
||||
}
|
||||
|
||||
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after CreateAgent on client request",
|
||||
sp.Name, finalDestination.RegionName, sp.Scene.Name);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Past this point we have to attempt clean up if the teleport fails, so update transfer state.
|
||||
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.Transferring);
|
||||
|
||||
|
@ -631,7 +668,16 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
return;
|
||||
}
|
||||
|
||||
sp.ControllingClient.SendTeleportProgress(teleportFlags | (uint)TeleportFlags.DisableCancel, "sending_dest");
|
||||
if (m_entityTransferStateMachine.GetAgentTransferState(sp.UUID) == AgentTransferState.Cancelling)
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[ENTITY TRANSFER MODULE]: Cancelled teleport of {0} to {1} from {2} after UpdateAgent on client request",
|
||||
sp.Name, finalDestination.RegionName, sp.Scene.Name);
|
||||
|
||||
CleanupAbortedInterRegionTeleport(sp, finalDestination);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[ENTITY TRANSFER MODULE]: Sending new CAPS seed url {0} from {1} to {2}",
|
||||
|
@ -714,14 +760,19 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
// }
|
||||
}
|
||||
|
||||
protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout)
|
||||
/// <summary>
|
||||
/// Clean up an inter-region teleport that did not complete, either because of simulator failure or cancellation.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// All operations here must be idempotent so that we can call this method at any point in the teleport process
|
||||
/// up until we send the TeleportFinish event quene event to the viewer.
|
||||
/// <remarks>
|
||||
/// <param name='sp'> </param>
|
||||
/// <param name='finalDestination'></param>
|
||||
protected virtual void CleanupAbortedInterRegionTeleport(ScenePresence sp, GridRegion finalDestination)
|
||||
{
|
||||
m_entityTransferStateMachine.UpdateInTransit(sp.UUID, AgentTransferState.CleaningUp);
|
||||
|
||||
// Client never contacted destination. Let's restore everything back
|
||||
sp.ControllingClient.SendTeleportFailed("Problems connecting to destination.");
|
||||
|
||||
// Fail. Reset it back
|
||||
sp.IsChildAgent = false;
|
||||
ReInstantiateScripts(sp);
|
||||
|
||||
|
@ -729,7 +780,20 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
|
||||
// Finally, kill the agent we just created at the destination.
|
||||
Scene.SimulationService.CloseAgent(finalDestination, sp.UUID);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Signal that the inter-region teleport failed and perform cleanup.
|
||||
/// </summary>
|
||||
/// <param name='sp'></param>
|
||||
/// <param name='finalDestination'></param>
|
||||
/// <param name='logout'></param>
|
||||
protected virtual void Fail(ScenePresence sp, GridRegion finalDestination, bool logout)
|
||||
{
|
||||
CleanupAbortedInterRegionTeleport(sp, finalDestination);
|
||||
|
||||
sp.ControllingClient.SendTeleportFailed(
|
||||
string.Format("Problems connecting to destination {0}", finalDestination.RegionName));
|
||||
sp.Scene.EventManager.TriggerTeleportFail(sp.ControllingClient, logout);
|
||||
}
|
||||
|
||||
|
@ -1206,6 +1270,10 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
// region doesn't take it
|
||||
m_entityTransferStateMachine.UpdateInTransit(agent.UUID, AgentTransferState.CleaningUp);
|
||||
|
||||
m_log.WarnFormat(
|
||||
"[ENTITY TRANSFER MODULE]: Region {0} would not accept update for agent {1} on cross attempt. Returning to original region.",
|
||||
neighbourRegion.RegionName, agent.Name);
|
||||
|
||||
ReInstantiateScripts(agent);
|
||||
agent.AddToPhysicalScene(isFlying);
|
||||
|
||||
|
@ -1225,6 +1293,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
neighbourRegion.RegionHandle);
|
||||
return agent;
|
||||
}
|
||||
|
||||
// No turning back
|
||||
agent.IsChildAgent = true;
|
||||
|
||||
|
@ -2092,7 +2161,7 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
|
||||
public bool IsInTransit(UUID id)
|
||||
{
|
||||
return m_entityTransferStateMachine.IsInTransit(id);
|
||||
return m_entityTransferStateMachine.GetAgentTransferState(id) != null;
|
||||
}
|
||||
|
||||
protected void ReInstantiateScripts(ScenePresence sp)
|
||||
|
|
|
@ -51,8 +51,9 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
/// This is a state machine.
|
||||
///
|
||||
/// [Entry] => Preparing
|
||||
/// Preparing => { Transferring || CleaningUp || [Exit] }
|
||||
/// Transferring => { ReceivedAtDestination || CleaningUp }
|
||||
/// Preparing => { Transferring || Cancelling || CleaningUp || [Exit] }
|
||||
/// Transferring => { ReceivedAtDestination || Cancelling || CleaningUp }
|
||||
/// Cancelling => CleaningUp
|
||||
/// ReceivedAtDestination => CleaningUp
|
||||
/// CleaningUp => [Exit]
|
||||
///
|
||||
|
@ -64,7 +65,8 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
Preparing, // The agent is being prepared for transfer
|
||||
Transferring, // The agent is in the process of being transferred to a destination
|
||||
ReceivedAtDestination, // The destination has notified us that the agent has been successfully received
|
||||
CleaningUp // The agent is being changed to child/removed after a transfer
|
||||
CleaningUp, // The agent is being changed to child/removed after a transfer
|
||||
Cancelling // The user has cancelled the teleport but we have yet to act upon this.
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -115,42 +117,110 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
/// <param name='newState'></param>
|
||||
/// <returns></returns>
|
||||
/// <exception cref='Exception'>Illegal transitions will throw an Exception</exception>
|
||||
internal void UpdateInTransit(UUID id, AgentTransferState newState)
|
||||
internal bool UpdateInTransit(UUID id, AgentTransferState newState)
|
||||
{
|
||||
bool transitionOkay = false;
|
||||
|
||||
// We don't want to throw an exception on cancel since this can come it at any time.
|
||||
bool failIfNotOkay = true;
|
||||
|
||||
// Should be a failure message if failure is not okay.
|
||||
string failureMessage = null;
|
||||
|
||||
AgentTransferState? oldState = null;
|
||||
|
||||
lock (m_agentsInTransit)
|
||||
{
|
||||
// Illegal to try and update an agent that's not actually in transit.
|
||||
if (!m_agentsInTransit.ContainsKey(id))
|
||||
throw new Exception(
|
||||
string.Format(
|
||||
"Agent with ID {0} is not registered as in transit in {1}",
|
||||
id, m_mod.Scene.RegionInfo.RegionName));
|
||||
{
|
||||
if (newState != AgentTransferState.Cancelling)
|
||||
failureMessage = string.Format(
|
||||
"Agent with ID {0} is not registered as in transit in {1}",
|
||||
id, m_mod.Scene.RegionInfo.RegionName);
|
||||
else
|
||||
failIfNotOkay = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
oldState = m_agentsInTransit[id];
|
||||
|
||||
AgentTransferState oldState = m_agentsInTransit[id];
|
||||
if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp)
|
||||
{
|
||||
transitionOkay = true;
|
||||
}
|
||||
else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing)
|
||||
{
|
||||
transitionOkay = true;
|
||||
}
|
||||
else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring)
|
||||
{
|
||||
transitionOkay = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newState == AgentTransferState.Cancelling
|
||||
&& (oldState == AgentTransferState.Preparing || oldState == AgentTransferState.Transferring))
|
||||
{
|
||||
transitionOkay = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
failIfNotOkay = false;
|
||||
}
|
||||
}
|
||||
|
||||
bool transitionOkay = false;
|
||||
|
||||
if (newState == AgentTransferState.CleaningUp && oldState != AgentTransferState.CleaningUp)
|
||||
transitionOkay = true;
|
||||
else if (newState == AgentTransferState.Transferring && oldState == AgentTransferState.Preparing)
|
||||
transitionOkay = true;
|
||||
else if (newState == AgentTransferState.ReceivedAtDestination && oldState == AgentTransferState.Transferring)
|
||||
transitionOkay = true;
|
||||
if (!transitionOkay)
|
||||
failureMessage
|
||||
= string.Format(
|
||||
"Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}",
|
||||
id, oldState, newState, m_mod.Scene.RegionInfo.RegionName);
|
||||
}
|
||||
|
||||
if (transitionOkay)
|
||||
{
|
||||
m_agentsInTransit[id] = newState;
|
||||
else
|
||||
throw new Exception(
|
||||
string.Format(
|
||||
"Agent with ID {0} is not allowed to move from old transit state {1} to new state {2} in {3}",
|
||||
id, oldState, newState, m_mod.Scene.RegionInfo.RegionName));
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[ENTITY TRANSFER STATE MACHINE]: Changed agent with id {0} from state {1} to {2} in {3}",
|
||||
// id, oldState, newState, m_mod.Scene.Name);
|
||||
}
|
||||
else if (failIfNotOkay)
|
||||
{
|
||||
throw new Exception(failureMessage);
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// if (oldState != null)
|
||||
// m_log.DebugFormat(
|
||||
// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} from state {1} to {2} in {3}",
|
||||
// id, oldState, newState, m_mod.Scene.Name);
|
||||
// else
|
||||
// m_log.DebugFormat(
|
||||
// "[ENTITY TRANSFER STATE MACHINE]: Ignored change of agent with id {0} to state {1} in {2} since agent not in transit",
|
||||
// id, newState, m_mod.Scene.Name);
|
||||
// }
|
||||
}
|
||||
|
||||
return transitionOkay;
|
||||
}
|
||||
|
||||
internal bool IsInTransit(UUID id)
|
||||
/// <summary>
|
||||
/// Gets the current agent transfer state.
|
||||
/// </summary>
|
||||
/// <returns>Null if the agent is not in transit</returns>
|
||||
/// <param name='id'>
|
||||
/// Identifier.
|
||||
/// </param>
|
||||
internal AgentTransferState? GetAgentTransferState(UUID id)
|
||||
{
|
||||
lock (m_agentsInTransit)
|
||||
return m_agentsInTransit.ContainsKey(id);
|
||||
{
|
||||
if (!m_agentsInTransit.ContainsKey(id))
|
||||
return null;
|
||||
else
|
||||
return m_agentsInTransit[id];
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -203,14 +273,14 @@ namespace OpenSim.Region.CoreModules.Framework.EntityTransfer
|
|||
|
||||
lock (m_agentsInTransit)
|
||||
{
|
||||
if (!IsInTransit(id))
|
||||
AgentTransferState? currentState = GetAgentTransferState(id);
|
||||
|
||||
if (currentState == null)
|
||||
throw new Exception(
|
||||
string.Format(
|
||||
"Asked to wait for destination callback for agent with ID {0} in {1} but agent is not in transit",
|
||||
id, m_mod.Scene.RegionInfo.RegionName));
|
||||
|
||||
AgentTransferState currentState = m_agentsInTransit[id];
|
||||
|
||||
if (currentState != AgentTransferState.Transferring && currentState != AgentTransferState.ReceivedAtDestination)
|
||||
throw new Exception(
|
||||
string.Format(
|
||||
|
|
|
@ -414,8 +414,6 @@ namespace OpenSim.Region.CoreModules.Framework.Monitoring
|
|||
}
|
||||
private void RegisterStatsManagerRegionStatistics()
|
||||
{
|
||||
string regionName = m_scene.RegionInfo.RegionName;
|
||||
|
||||
MakeStat("RootAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetRootAgentCount(); });
|
||||
MakeStat("ChildAgents", "avatars", (s) => { s.Value = m_scene.SceneGraph.GetChildAgentCount(); });
|
||||
MakeStat("TotalPrims", "objects", (s) => { s.Value = m_scene.SceneGraph.GetTotalObjectsCount(); });
|
||||
|
|
|
@ -516,6 +516,9 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
|
|||
foreach (string line in GetLines(data, dataDelim))
|
||||
{
|
||||
string nextLine = line.Trim();
|
||||
|
||||
// m_log.DebugFormat("[VECTOR RENDER MODULE]: Processing line '{0}'", nextLine);
|
||||
|
||||
//replace with switch, or even better, do some proper parsing
|
||||
if (nextLine.StartsWith("MoveTo"))
|
||||
{
|
||||
|
@ -829,6 +832,8 @@ namespace OpenSim.Region.CoreModules.Scripting.VectorRender
|
|||
float y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture);
|
||||
PointF point = new PointF(x, y);
|
||||
points[i / 2] = point;
|
||||
|
||||
// m_log.DebugFormat("[VECTOR RENDER MODULE]: Got point {0}", points[i / 2]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -219,12 +219,15 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
|
|||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[LOCAL SIMULATION CONNECTOR]: Found region {0} {1} to send AgentUpdate",
|
||||
// s.RegionInfo.RegionName, destination.RegionHandle);
|
||||
// destination.RegionName, destination.RegionID);
|
||||
|
||||
return m_scenes[destination.RegionID].IncomingChildAgentDataUpdate(cAgentData);
|
||||
}
|
||||
|
||||
// m_log.DebugFormat("[LOCAL COMMS]: Did not find region {0} for ChildAgentUpdate", regionHandle);
|
||||
// m_log.DebugFormat(
|
||||
// "[LOCAL COMMS]: Did not find region {0} {1} for ChildAgentUpdate",
|
||||
// destination.RegionName, destination.RegionID);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -239,7 +242,7 @@ namespace OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation
|
|||
// note that we really don't need the GridRegion for this call
|
||||
foreach (Scene s in m_scenes.Values)
|
||||
{
|
||||
//m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate");
|
||||
// m_log.Debug("[LOCAL COMMS]: Found region to send ChildAgentUpdate");
|
||||
s.IncomingChildAgentDataUpdate(cAgentData);
|
||||
}
|
||||
|
||||
|
|
|
@ -95,6 +95,11 @@ namespace OpenSim.Region.CoreModules.World.Land
|
|||
return null;
|
||||
}
|
||||
|
||||
public ILandObject GetLandObject(Vector3 position)
|
||||
{
|
||||
return GetLandObject(position.X, position.Y);
|
||||
}
|
||||
|
||||
public ILandObject GetLandObject(int x, int y)
|
||||
{
|
||||
if (m_landManagementModule != null)
|
||||
|
|
|
@ -41,6 +41,16 @@ namespace OpenSim.Region.Framework.Interfaces
|
|||
Value = 3
|
||||
}
|
||||
|
||||
public enum JsonStoreValueType
|
||||
{
|
||||
Undefined = 0,
|
||||
Boolean = 1,
|
||||
Integer = 2,
|
||||
Float = 3,
|
||||
String = 4,
|
||||
UUID = 5
|
||||
}
|
||||
|
||||
public delegate void TakeValueCallback(string s);
|
||||
|
||||
public interface IJsonStoreModule
|
||||
|
@ -49,7 +59,9 @@ namespace OpenSim.Region.Framework.Interfaces
|
|||
bool CreateStore(string value, ref UUID result);
|
||||
bool DestroyStore(UUID storeID);
|
||||
|
||||
JsonStoreNodeType GetPathType(UUID storeID, string path);
|
||||
JsonStoreNodeType GetNodeType(UUID storeID, string path);
|
||||
JsonStoreValueType GetValueType(UUID storeID, string path);
|
||||
|
||||
bool TestStore(UUID storeID);
|
||||
|
||||
bool SetValue(UUID storeID, string path, string value, bool useJson);
|
||||
|
|
|
@ -129,6 +129,27 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
/// Dynamic attributes can be created and deleted as required.
|
||||
/// </summary>
|
||||
public DAMap DynAttrs { get; set; }
|
||||
|
||||
private DOMap m_dynObjs;
|
||||
|
||||
/// <summary>
|
||||
/// Dynamic objects that can be created and deleted as required.
|
||||
/// </summary>
|
||||
public DOMap DynObjs
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_dynObjs == null)
|
||||
m_dynObjs = new DOMap();
|
||||
|
||||
return m_dynObjs;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
m_dynObjs = value;
|
||||
}
|
||||
}
|
||||
|
||||
/// <value>
|
||||
/// Is this a root part?
|
||||
|
@ -4503,8 +4524,25 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
|
||||
Changed changeFlags = 0;
|
||||
|
||||
Primitive.TextureEntryFace fallbackNewFace = newTex.DefaultTexture;
|
||||
Primitive.TextureEntryFace fallbackOldFace = oldTex.DefaultTexture;
|
||||
|
||||
// On Incoming packets, sometimes newText.DefaultTexture is null. The assumption is that all
|
||||
// other prim-sides are set, but apparently that's not always the case. Lets assume packet/data corruption at this point.
|
||||
if (fallbackNewFace == null)
|
||||
{
|
||||
fallbackNewFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0);
|
||||
newTex.DefaultTexture = fallbackNewFace;
|
||||
}
|
||||
if (fallbackOldFace == null)
|
||||
{
|
||||
fallbackOldFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0);
|
||||
oldTex.DefaultTexture = fallbackOldFace;
|
||||
}
|
||||
|
||||
for (int i = 0 ; i < GetNumberOfSides(); i++)
|
||||
{
|
||||
|
||||
Primitive.TextureEntryFace newFace = newTex.DefaultTexture;
|
||||
Primitive.TextureEntryFace oldFace = oldTex.DefaultTexture;
|
||||
|
||||
|
|
|
@ -559,16 +559,28 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
|
||||
private Quaternion m_bodyRot = Quaternion.Identity;
|
||||
|
||||
/// <summary>
|
||||
/// The rotation of the avatar.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the avatar is not sitting, this is with respect to the world
|
||||
/// If the avatar is sitting, this is a with respect to the part that it's sitting upon (a local rotation).
|
||||
/// If you always want the world rotation, use GetWorldRotation()
|
||||
/// </remarks>
|
||||
public Quaternion Rotation
|
||||
{
|
||||
get { return m_bodyRot; }
|
||||
get
|
||||
{
|
||||
return m_bodyRot;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
m_bodyRot = value;
|
||||
|
||||
if (PhysicsActor != null)
|
||||
{
|
||||
PhysicsActor.Orientation = m_bodyRot;
|
||||
}
|
||||
|
||||
// m_log.DebugFormat("[SCENE PRESENCE]: Body rot for {0} set to {1}", Name, m_bodyRot);
|
||||
}
|
||||
}
|
||||
|
@ -608,6 +620,26 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
set { m_health = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the world rotation of this presence.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Unlike Rotation, this returns the world rotation no matter whether the avatar is sitting on a prim or not.
|
||||
/// </remarks>
|
||||
/// <returns></returns>
|
||||
public Quaternion GetWorldRotation()
|
||||
{
|
||||
if (IsSatOnObject)
|
||||
{
|
||||
SceneObjectPart sitPart = ParentPart;
|
||||
|
||||
if (sitPart != null)
|
||||
return sitPart.GetWorldRotation() * Rotation;
|
||||
}
|
||||
|
||||
return Rotation;
|
||||
}
|
||||
|
||||
public void AdjustKnownSeeds()
|
||||
{
|
||||
Dictionary<ulong, string> seeds;
|
||||
|
@ -709,8 +741,6 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
|
||||
#endregion
|
||||
|
||||
|
||||
|
||||
#region Constructor(s)
|
||||
|
||||
public ScenePresence(
|
||||
|
@ -1613,32 +1643,28 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
bool controlland = (((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0) ||
|
||||
((flags & AgentManager.ControlFlags.AGENT_CONTROL_NUDGE_UP_NEG) != 0));
|
||||
|
||||
|
||||
//m_log.Debug("[CONTROL]: " +flags);
|
||||
// Applies a satisfying roll effect to the avatar when flying.
|
||||
if (((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) != 0) && ((flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0))
|
||||
if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_LEFT) != 0 && (flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_POS) != 0)
|
||||
{
|
||||
|
||||
ApplyFlyingRoll(FLY_ROLL_RADIANS_PER_UPDATE, ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0), ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0));
|
||||
|
||||
|
||||
ApplyFlyingRoll(
|
||||
FLY_ROLL_RADIANS_PER_UPDATE,
|
||||
(flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0,
|
||||
(flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0);
|
||||
}
|
||||
else if (((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) != 0) &&
|
||||
((flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0))
|
||||
else if ((flags & AgentManager.ControlFlags.AGENT_CONTROL_TURN_RIGHT) != 0 &&
|
||||
(flags & AgentManager.ControlFlags.AGENT_CONTROL_YAW_NEG) != 0)
|
||||
{
|
||||
ApplyFlyingRoll(-FLY_ROLL_RADIANS_PER_UPDATE, ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0), ((flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0));
|
||||
|
||||
|
||||
ApplyFlyingRoll(
|
||||
-FLY_ROLL_RADIANS_PER_UPDATE,
|
||||
(flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_POS) != 0,
|
||||
(flags & AgentManager.ControlFlags.AGENT_CONTROL_UP_NEG) != 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_AngularVelocity.Z != 0)
|
||||
m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE);
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
m_AngularVelocity.Z += CalculateFlyingRollResetToZero(FLY_ROLL_RESET_RADIANS_PER_UPDATE);
|
||||
}
|
||||
|
||||
if (Flying && IsColliding && controlland)
|
||||
{
|
||||
|
@ -2400,7 +2426,8 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
/// <param name="vec">The vector in which to move. This is relative to the rotation argument</param>
|
||||
public void AddNewMovement(Vector3 vec)
|
||||
{
|
||||
// m_log.DebugFormat("[SCENE PRESENCE]: Adding new movement {0} for {1}", vec, Name);
|
||||
// m_log.DebugFormat(
|
||||
// "[SCENE PRESENCE]: Adding new movement {0} with rotation {1} for {2}", vec, Rotation, Name);
|
||||
|
||||
Vector3 direc = vec * Rotation;
|
||||
direc.Normalize();
|
||||
|
@ -2420,6 +2447,8 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
|
||||
direc *= 0.03f * 128f * SpeedModifier;
|
||||
|
||||
// m_log.DebugFormat("[SCENE PRESENCE]: Force to apply before modification was {0} for {1}", direc, Name);
|
||||
|
||||
if (PhysicsActor != null)
|
||||
{
|
||||
if (Flying)
|
||||
|
@ -2453,6 +2482,8 @@ namespace OpenSim.Region.Framework.Scenes
|
|||
}
|
||||
}
|
||||
|
||||
// m_log.DebugFormat("[SCENE PRESENCE]: Setting force to apply to {0} for {1}", direc, Name);
|
||||
|
||||
// TODO: Add the force instead of only setting it to support multiple forces per frame?
|
||||
m_forceToApply = direc;
|
||||
}
|
||||
|
|
|
@ -110,8 +110,8 @@ namespace OpenSim.Region.Framework.Scenes.Tests
|
|||
|
||||
Vector3 firstSize = new Vector3(2, 3, 4);
|
||||
Vector3 secondSize = new Vector3(5, 6, 7);
|
||||
Vector3 thirdSize = new Vector3(8, 9, 10);
|
||||
Vector3 fourthSize = new Vector3(11, 12, 13);
|
||||
// Vector3 thirdSize = new Vector3(8, 9, 10);
|
||||
// Vector3 fourthSize = new Vector3(11, 12, 13);
|
||||
|
||||
Scene scene = new SceneHelpers().SetupScene();
|
||||
scene.MaxUndoCount = 20;
|
||||
|
|
|
@ -288,109 +288,6 @@ namespace OpenSim.Region.Framework.Scenes.Tests
|
|||
// ScenePresence presence = scene.GetScenePresence(agent1);
|
||||
//
|
||||
// Assert.That(presence, Is.Null, "presence is not null");
|
||||
// }
|
||||
|
||||
// I'm commenting this test because it does not represent
|
||||
// crossings. The Thread.Sleep's in here are not meaningful mocks,
|
||||
// and they sometimes fail in panda.
|
||||
// We need to talk in order to develop a test
|
||||
// that really tests region crossings. There are 3 async components,
|
||||
// but things are synchronous among them. So there should be
|
||||
// 3 threads in here.
|
||||
//[Test]
|
||||
// public void T021_TestCrossToNewRegion()
|
||||
// {
|
||||
// TestHelpers.InMethod();
|
||||
//
|
||||
// scene.RegisterRegionWithGrid();
|
||||
// scene2.RegisterRegionWithGrid();
|
||||
//
|
||||
// // Adding child agent to region 1001
|
||||
// string reason;
|
||||
// scene2.NewUserConnection(acd1,0, out reason);
|
||||
// scene2.AddNewClient(testclient, PresenceType.User);
|
||||
//
|
||||
// ScenePresence presence = scene.GetScenePresence(agent1);
|
||||
// presence.MakeRootAgent(new Vector3(0,unchecked(Constants.RegionSize-1),0), true);
|
||||
//
|
||||
// ScenePresence presence2 = scene2.GetScenePresence(agent1);
|
||||
//
|
||||
// // Adding neighbour region caps info to presence2
|
||||
//
|
||||
// string cap = presence.ControllingClient.RequestClientInfo().CapsPath;
|
||||
// presence2.AddNeighbourRegion(region1, cap);
|
||||
//
|
||||
// Assert.That(presence.IsChildAgent, Is.False, "Did not start root in origin region.");
|
||||
// Assert.That(presence2.IsChildAgent, Is.True, "Is not a child on destination region.");
|
||||
//
|
||||
// // Cross to x+1
|
||||
// presence.AbsolutePosition = new Vector3(Constants.RegionSize+1,3,100);
|
||||
// presence.Update();
|
||||
//
|
||||
// EventWaitHandle wh = new EventWaitHandle (false, EventResetMode.AutoReset, "Crossing");
|
||||
//
|
||||
// // Mimicking communication between client and server, by waiting OK from client
|
||||
// // sent by TestClient.CrossRegion call. Originally, this is network comm.
|
||||
// if (!wh.WaitOne(5000,false))
|
||||
// {
|
||||
// presence.Update();
|
||||
// if (!wh.WaitOne(8000,false))
|
||||
// throw new ArgumentException("1 - Timeout waiting for signal/variable.");
|
||||
// }
|
||||
//
|
||||
// // This is a TestClient specific method that fires OnCompleteMovementToRegion event, which
|
||||
// // would normally be fired after receiving the reply packet from comm. done on the last line.
|
||||
// testclient.CompleteMovement();
|
||||
//
|
||||
// // Crossings are asynchronous
|
||||
// int timer = 10;
|
||||
//
|
||||
// // Make sure cross hasn't already finished
|
||||
// if (!presence.IsInTransit && !presence.IsChildAgent)
|
||||
// {
|
||||
// // If not and not in transit yet, give it some more time
|
||||
// Thread.Sleep(5000);
|
||||
// }
|
||||
//
|
||||
// // Enough time, should at least be in transit by now.
|
||||
// while (presence.IsInTransit && timer > 0)
|
||||
// {
|
||||
// Thread.Sleep(1000);
|
||||
// timer-=1;
|
||||
// }
|
||||
//
|
||||
// Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 2->1.");
|
||||
// Assert.That(presence.IsChildAgent, Is.True, "Did not complete region cross as expected.");
|
||||
// Assert.That(presence2.IsChildAgent, Is.False, "Did not receive root status after receiving agent.");
|
||||
//
|
||||
// // Cross Back
|
||||
// presence2.AbsolutePosition = new Vector3(-10, 3, 100);
|
||||
// presence2.Update();
|
||||
//
|
||||
// if (!wh.WaitOne(5000,false))
|
||||
// {
|
||||
// presence2.Update();
|
||||
// if (!wh.WaitOne(8000,false))
|
||||
// throw new ArgumentException("2 - Timeout waiting for signal/variable.");
|
||||
// }
|
||||
// testclient.CompleteMovement();
|
||||
//
|
||||
// if (!presence2.IsInTransit && !presence2.IsChildAgent)
|
||||
// {
|
||||
// // If not and not in transit yet, give it some more time
|
||||
// Thread.Sleep(5000);
|
||||
// }
|
||||
//
|
||||
// // Enough time, should at least be in transit by now.
|
||||
// while (presence2.IsInTransit && timer > 0)
|
||||
// {
|
||||
// Thread.Sleep(1000);
|
||||
// timer-=1;
|
||||
// }
|
||||
//
|
||||
// Assert.That(timer,Is.GreaterThan(0),"Timed out waiting to cross 1->2.");
|
||||
// Assert.That(presence2.IsChildAgent, Is.True, "Did not return from region as expected.");
|
||||
// Assert.That(presence.IsChildAgent, Is.False, "Presence was not made root in old region again.");
|
||||
// }
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
||||
private void MakeStat(string pName, string pUnit, string pContainer, Action<Stat> act)
|
||||
private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action<Stat> act)
|
||||
{
|
||||
Stat stat = new Stat(pName, pName, "", pUnit, CategoryServer, pContainer, StatType.Pull, act, StatVerbosity.Info);
|
||||
string desc = pDesc;
|
||||
if (desc == null)
|
||||
desc = pName;
|
||||
Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, act, StatVerbosity.Info);
|
||||
StatsManager.RegisterStat(stat);
|
||||
RegisteredStats.Add(pName, stat);
|
||||
}
|
||||
|
@ -166,16 +169,16 @@ public class ServerStats : ISharedRegionModule
|
|||
StatsManager.RegisterStat(tempStat);
|
||||
RegisteredStats.Add(tempName, tempStat);
|
||||
|
||||
MakeStat("TotalProcessorTime", "sec", ContainerProcessor,
|
||||
MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor,
|
||||
(s) => { s.Value = Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds; });
|
||||
|
||||
MakeStat("UserProcessorTime", "sec", ContainerProcessor,
|
||||
MakeStat("UserProcessorTime", null, "sec", ContainerProcessor,
|
||||
(s) => { s.Value = Process.GetCurrentProcess().UserProcessorTime.TotalSeconds; });
|
||||
|
||||
MakeStat("PrivilegedProcessorTime", "sec", ContainerProcessor,
|
||||
MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor,
|
||||
(s) => { s.Value = Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds; });
|
||||
|
||||
MakeStat("Threads", "threads", ContainerProcessor,
|
||||
MakeStat("Threads", null, "threads", ContainerProcessor,
|
||||
(s) => { s.Value = Process.GetCurrentProcess().Threads.Count; });
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -196,8 +199,10 @@ public class ServerStats : ISharedRegionModule
|
|||
string nicInterfaceType = nic.NetworkInterfaceType.ToString();
|
||||
if (!okInterfaceTypes.Contains(nicInterfaceType))
|
||||
{
|
||||
m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'. To include, add to [Monitoring]NetworkInterfaceTypes='Ethernet,Loopback'",
|
||||
m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'.",
|
||||
LogHeader, nic.Name, nicInterfaceType);
|
||||
m_log.DebugFormat("{0} To include, add to comma separated list in [Monitoring]NetworkInterfaceTypes={1}",
|
||||
LogHeader, NetworkInterfaceTypes);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -206,14 +211,15 @@ public class ServerStats : ISharedRegionModule
|
|||
IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics();
|
||||
if (nicStats != null)
|
||||
{
|
||||
MakeStat("BytesRcvd/" + nic.Name, "KB", ContainerNetwork,
|
||||
MakeStat("BytesRcvd/" + nic.Name, nic.Name, "KB", ContainerNetwork,
|
||||
(s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); });
|
||||
MakeStat("BytesSent/" + nic.Name, "KB", ContainerNetwork,
|
||||
MakeStat("BytesSent/" + nic.Name, nic.Name, "KB", ContainerNetwork,
|
||||
(s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); });
|
||||
MakeStat("TotalBytes/" + nic.Name, "KB", ContainerNetwork,
|
||||
MakeStat("TotalBytes/" + nic.Name, nic.Name, "KB", ContainerNetwork,
|
||||
(s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); });
|
||||
}
|
||||
}
|
||||
// TODO: add IPv6 (it may actually happen someday)
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
|
@ -221,13 +227,13 @@ public class ServerStats : ISharedRegionModule
|
|||
m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e);
|
||||
}
|
||||
|
||||
MakeStat("ProcessMemory", "MB", ContainerMemory,
|
||||
MakeStat("ProcessMemory", null, "MB", ContainerMemory,
|
||||
(s) => { s.Value = Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d; });
|
||||
MakeStat("ObjectMemory", "MB", ContainerMemory,
|
||||
MakeStat("ObjectMemory", null, "MB", ContainerMemory,
|
||||
(s) => { s.Value = GC.GetTotalMemory(false) / 1024d / 1024d; });
|
||||
MakeStat("LastMemoryChurn", "MB/sec", ContainerMemory,
|
||||
MakeStat("LastMemoryChurn", null, "MB/sec", ContainerMemory,
|
||||
(s) => { s.Value = Math.Round(MemoryWatchdog.LastMemoryChurn * 1000d / 1024d / 1024d, 3); });
|
||||
MakeStat("AverageMemoryChurn", "MB/sec", ContainerMemory,
|
||||
MakeStat("AverageMemoryChurn", null, "MB/sec", ContainerMemory,
|
||||
(s) => { s.Value = Math.Round(MemoryWatchdog.AverageMemoryChurn * 1000d / 1024d / 1024d, 3); });
|
||||
}
|
||||
|
||||
|
@ -263,6 +269,8 @@ public class ServerStats : ISharedRegionModule
|
|||
}
|
||||
}
|
||||
|
||||
// Lookup the nic that goes with this stat and set the value by using a fetch action.
|
||||
// Not sure about closure with delegates inside delegates.
|
||||
private delegate double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat);
|
||||
private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor)
|
||||
{
|
||||
|
@ -275,7 +283,10 @@ public class ServerStats : ISharedRegionModule
|
|||
{
|
||||
IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics();
|
||||
if (intrStats != null)
|
||||
stat.Value = Math.Round(getter(intrStats) / factor, 3);
|
||||
{
|
||||
double newVal = Math.Round(getter(intrStats) / factor, 3);
|
||||
stat.Value = newVal;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -145,7 +145,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
|
|||
///
|
||||
/// </summary>
|
||||
// -----------------------------------------------------------------
|
||||
public JsonStoreNodeType PathType(string expr)
|
||||
public JsonStoreNodeType GetNodeType(string expr)
|
||||
{
|
||||
Stack<string> path;
|
||||
if (! ParsePathExpression(expr,out path))
|
||||
|
@ -168,6 +168,43 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
|
|||
return JsonStoreNodeType.Undefined;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
// -----------------------------------------------------------------
|
||||
public JsonStoreValueType GetValueType(string expr)
|
||||
{
|
||||
Stack<string> path;
|
||||
if (! ParsePathExpression(expr,out path))
|
||||
return JsonStoreValueType.Undefined;
|
||||
|
||||
OSD result = ProcessPathExpression(ValueStore,path);
|
||||
|
||||
if (result == null)
|
||||
return JsonStoreValueType.Undefined;
|
||||
|
||||
if (result is OSDMap)
|
||||
return JsonStoreValueType.Undefined;
|
||||
|
||||
if (result is OSDArray)
|
||||
return JsonStoreValueType.Undefined;
|
||||
|
||||
if (result is OSDBoolean)
|
||||
return JsonStoreValueType.Boolean;
|
||||
|
||||
if (result is OSDInteger)
|
||||
return JsonStoreValueType.Integer;
|
||||
|
||||
if (result is OSDReal)
|
||||
return JsonStoreValueType.Float;
|
||||
|
||||
if (result is OSDString)
|
||||
return JsonStoreValueType.String;
|
||||
|
||||
return JsonStoreValueType.Undefined;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
/// <summary>
|
||||
///
|
||||
|
|
|
@ -270,7 +270,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
|
|||
///
|
||||
/// </summary>
|
||||
// -----------------------------------------------------------------
|
||||
public JsonStoreNodeType GetPathType(UUID storeID, string path)
|
||||
public JsonStoreNodeType GetNodeType(UUID storeID, string path)
|
||||
{
|
||||
if (! m_enabled) return JsonStoreNodeType.Undefined;
|
||||
|
||||
|
@ -287,7 +287,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
|
|||
try
|
||||
{
|
||||
lock (map)
|
||||
return map.PathType(path);
|
||||
return map.GetNodeType(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -297,6 +297,38 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
|
|||
return JsonStoreNodeType.Undefined;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
// -----------------------------------------------------------------
|
||||
public JsonStoreValueType GetValueType(UUID storeID, string path)
|
||||
{
|
||||
if (! m_enabled) return JsonStoreValueType.Undefined;
|
||||
|
||||
JsonStore map = null;
|
||||
lock (m_JsonValueStore)
|
||||
{
|
||||
if (! m_JsonValueStore.TryGetValue(storeID,out map))
|
||||
{
|
||||
m_log.InfoFormat("[JsonStore] Missing store {0}",storeID);
|
||||
return JsonStoreValueType.Undefined;
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
lock (map)
|
||||
return map.GetValueType(path);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Error(string.Format("[JsonStore]: Path test failed for {0} in {1}", path, storeID), e);
|
||||
}
|
||||
|
||||
return JsonStoreValueType.Undefined;
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
/// <summary>
|
||||
///
|
||||
|
|
|
@ -192,16 +192,32 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
|
|||
#region ScriptConstantsInterface
|
||||
|
||||
[ScriptConstant]
|
||||
public static readonly int JSON_TYPE_UNDEF = (int)JsonStoreNodeType.Undefined;
|
||||
public static readonly int JSON_NODETYPE_UNDEF = (int)JsonStoreNodeType.Undefined;
|
||||
|
||||
[ScriptConstant]
|
||||
public static readonly int JSON_TYPE_OBJECT = (int)JsonStoreNodeType.Object;
|
||||
public static readonly int JSON_NODETYPE_OBJECT = (int)JsonStoreNodeType.Object;
|
||||
|
||||
[ScriptConstant]
|
||||
public static readonly int JSON_TYPE_ARRAY = (int)JsonStoreNodeType.Array;
|
||||
public static readonly int JSON_NODETYPE_ARRAY = (int)JsonStoreNodeType.Array;
|
||||
|
||||
[ScriptConstant]
|
||||
public static readonly int JSON_TYPE_VALUE = (int)JsonStoreNodeType.Value;
|
||||
public static readonly int JSON_NODETYPE_VALUE = (int)JsonStoreNodeType.Value;
|
||||
|
||||
[ScriptConstant]
|
||||
public static readonly int JSON_VALUETYPE_UNDEF = (int)JsonStoreValueType.Undefined;
|
||||
|
||||
[ScriptConstant]
|
||||
public static readonly int JSON_VALUETYPE_BOOLEAN = (int)JsonStoreValueType.Boolean;
|
||||
|
||||
[ScriptConstant]
|
||||
public static readonly int JSON_VALUETYPE_INTEGER = (int)JsonStoreValueType.Integer;
|
||||
|
||||
[ScriptConstant]
|
||||
public static readonly int JSON_VALUETYPE_FLOAT = (int)JsonStoreValueType.Float;
|
||||
|
||||
[ScriptConstant]
|
||||
public static readonly int JSON_VALUETYPE_STRING = (int)JsonStoreValueType.String;
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
|
@ -310,9 +326,20 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore
|
|||
/// </summary>
|
||||
// -----------------------------------------------------------------
|
||||
[ScriptInvocation]
|
||||
public int JsonGetPathType(UUID hostID, UUID scriptID, UUID storeID, string path)
|
||||
public int JsonGetNodeType(UUID hostID, UUID scriptID, UUID storeID, string path)
|
||||
{
|
||||
return (int)m_store.GetPathType(storeID,path);
|
||||
return (int)m_store.GetNodeType(storeID,path);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
// -----------------------------------------------------------------
|
||||
[ScriptInvocation]
|
||||
public int JsonGetValueType(UUID hostID, UUID scriptID, UUID storeID, string path)
|
||||
{
|
||||
return (int)m_store.GetValueType(storeID,path);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------
|
||||
|
|
|
@ -158,8 +158,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
|
|||
|
||||
Assert.That(dsrv, Is.EqualTo(1));
|
||||
|
||||
int tprv = (int)InvokeOp("JsonGetPathType", storeId, "Hello");
|
||||
Assert.That(tprv, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
|
||||
int tprv = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
|
||||
Assert.That(tprv, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -277,8 +277,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
|
|||
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
|
||||
Assert.That(returnValue, Is.EqualTo(1));
|
||||
|
||||
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
|
||||
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
|
||||
|
||||
string returnValue2 = (string)InvokeOp("JsonGetValue", storeId, "Hello");
|
||||
Assert.That(returnValue2, Is.EqualTo(""));
|
||||
|
@ -291,8 +291,8 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
|
|||
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello");
|
||||
Assert.That(returnValue, Is.EqualTo(1));
|
||||
|
||||
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
|
||||
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
|
||||
|
||||
string returnValue2 = (string)InvokeOp("JsonGetJson", storeId, "Hello");
|
||||
Assert.That(returnValue2, Is.EqualTo(""));
|
||||
|
@ -306,11 +306,11 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
|
|||
int returnValue = (int)InvokeOp( "JsonRemoveValue", storeId, "Hello[0]");
|
||||
Assert.That(returnValue, Is.EqualTo(1));
|
||||
|
||||
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello[0]");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE));
|
||||
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello[0]");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE));
|
||||
|
||||
result = (int)InvokeOp("JsonGetPathType", storeId, "Hello[1]");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
|
||||
result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello[1]");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
|
||||
|
||||
string stringReturnValue = (string)InvokeOp("JsonGetValue", storeId, "Hello[0]");
|
||||
Assert.That(stringReturnValue, Is.EqualTo("value2"));
|
||||
|
@ -433,7 +433,7 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
|
|||
}
|
||||
|
||||
[Test]
|
||||
public void TestJsonGetPathType()
|
||||
public void TestJsonGetNodeType()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
@ -441,41 +441,41 @@ namespace OpenSim.Region.OptionalModules.Scripting.JsonStore.Tests
|
|||
UUID storeId = (UUID)InvokeOp("JsonCreateStore", "{ 'Hello' : { 'World' : [ 'one', 2 ] } }");
|
||||
|
||||
{
|
||||
int result = (int)InvokeOp("JsonGetPathType", storeId, ".");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_OBJECT));
|
||||
int result = (int)InvokeOp("JsonGetNodeType", storeId, ".");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_OBJECT));
|
||||
}
|
||||
|
||||
{
|
||||
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_OBJECT));
|
||||
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_OBJECT));
|
||||
}
|
||||
|
||||
{
|
||||
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_ARRAY));
|
||||
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_ARRAY));
|
||||
}
|
||||
|
||||
{
|
||||
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World[0]");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE));
|
||||
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World[0]");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE));
|
||||
}
|
||||
|
||||
{
|
||||
int result = (int)InvokeOp("JsonGetPathType", storeId, "Hello.World[1]");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_VALUE));
|
||||
int result = (int)InvokeOp("JsonGetNodeType", storeId, "Hello.World[1]");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_VALUE));
|
||||
}
|
||||
|
||||
// Test for non-existant path
|
||||
{
|
||||
int result = (int)InvokeOp("JsonGetPathType", storeId, "foo");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
|
||||
int result = (int)InvokeOp("JsonGetNodeType", storeId, "foo");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
|
||||
}
|
||||
|
||||
// Test for non-existant store
|
||||
{
|
||||
UUID fakeStoreId = TestHelpers.ParseTail(0x500);
|
||||
int result = (int)InvokeOp("JsonGetPathType", fakeStoreId, ".");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_TYPE_UNDEF));
|
||||
int result = (int)InvokeOp("JsonGetNodeType", fakeStoreId, ".");
|
||||
Assert.That(result, Is.EqualTo(JsonStoreScriptModule.JSON_NODETYPE_UNDEF));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -102,6 +102,8 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
|
|||
|
||||
public override float Simulate(float timeStep)
|
||||
{
|
||||
// Console.WriteLine("Simulating");
|
||||
|
||||
float fps = 0;
|
||||
for (int i = 0; i < _actors.Count; ++i)
|
||||
{
|
||||
|
@ -109,8 +111,11 @@ namespace OpenSim.Region.Physics.BasicPhysicsPlugin
|
|||
Vector3 actorPosition = actor.Position;
|
||||
Vector3 actorVelocity = actor.Velocity;
|
||||
|
||||
actorPosition.X += actor.Velocity.X*timeStep;
|
||||
actorPosition.Y += actor.Velocity.Y*timeStep;
|
||||
// Console.WriteLine(
|
||||
// "Processing actor {0}, starting pos {1}, starting vel {2}", i, actorPosition, actorVelocity);
|
||||
|
||||
actorPosition.X += actor.Velocity.X * timeStep;
|
||||
actorPosition.Y += actor.Velocity.Y * timeStep;
|
||||
|
||||
if (actor.Position.Y < 0)
|
||||
{
|
||||
|
|
|
@ -205,7 +205,7 @@ public sealed class BSCharacter : BSPhysObject
|
|||
// errors can creap in and the avatar will slowly float off in some direction.
|
||||
// So, the problem is that, when an avatar is standing, we cannot tell creaping error
|
||||
// from real pushing.
|
||||
// The code below keeps setting the velocity to zero hoping the world will keep pushing.
|
||||
// The code below uses whether the collider is static or moving to decide whether to zero motion.
|
||||
|
||||
_velocityMotor.Step(timeStep);
|
||||
|
||||
|
@ -244,6 +244,7 @@ public sealed class BSCharacter : BSPhysObject
|
|||
}
|
||||
else
|
||||
{
|
||||
// Supposed to be moving.
|
||||
OMV.Vector3 stepVelocity = _velocityMotor.CurrentValue;
|
||||
|
||||
if (Friction != BSParam.AvatarFriction)
|
||||
|
@ -276,8 +277,8 @@ public sealed class BSCharacter : BSPhysObject
|
|||
});
|
||||
}
|
||||
|
||||
// Decide of the character is colliding with a low object and compute a force to pop the
|
||||
// avatar up so it has a chance of walking up and over the low object.
|
||||
// Decide if the character is colliding with a low object and compute a force to pop the
|
||||
// avatar up so it can walk up and over the low objects.
|
||||
private OMV.Vector3 WalkUpStairs()
|
||||
{
|
||||
OMV.Vector3 ret = OMV.Vector3.Zero;
|
||||
|
@ -476,17 +477,19 @@ public sealed class BSCharacter : BSPhysObject
|
|||
if (!PhysicsScene.TerrainManager.IsWithinKnownTerrain(RawPosition))
|
||||
{
|
||||
// The character is out of the known/simulated area.
|
||||
// Upper levels of code will handle the transition to other areas so, for
|
||||
// the time, we just ignore the position.
|
||||
return ret;
|
||||
// Force the avatar position to be within known. ScenePresence will use the position
|
||||
// plus the velocity to decide if the avatar is moving out of the region.
|
||||
RawPosition = PhysicsScene.TerrainManager.ClampPositionIntoKnownTerrain(RawPosition);
|
||||
DetailLog("{0},BSCharacter.PositionSanityCheck,notWithinKnownTerrain,clampedPos={1}", LocalID, RawPosition);
|
||||
return true;
|
||||
}
|
||||
|
||||
// If below the ground, move the avatar up
|
||||
float terrainHeight = PhysicsScene.TerrainManager.GetTerrainHeightAtXYZ(RawPosition);
|
||||
if (Position.Z < terrainHeight)
|
||||
{
|
||||
DetailLog("{0},BSCharacter.PositionAdjustUnderGround,call,pos={1},terrain={2}", LocalID, _position, terrainHeight);
|
||||
_position.Z = terrainHeight + 2.0f;
|
||||
DetailLog("{0},BSCharacter.PositionSanityCheck,adjustForUnderGround,pos={1},terrain={2}", LocalID, _position, terrainHeight);
|
||||
_position.Z = terrainHeight + BSParam.AvatarBelowGroundUpCorrectionMeters;
|
||||
ret = true;
|
||||
}
|
||||
if ((CurrentCollisionFlags & CollisionFlags.BS_FLOATS_ON_WATER) != 0)
|
||||
|
@ -806,14 +809,7 @@ public sealed class BSCharacter : BSPhysObject
|
|||
private void AddForce(OMV.Vector3 force, bool pushforce, bool inTaintTime) {
|
||||
if (force.IsFinite())
|
||||
{
|
||||
float magnitude = force.Length();
|
||||
if (magnitude > BSParam.MaxAddForceMagnitude)
|
||||
{
|
||||
// Force has a limit
|
||||
force = force / magnitude * BSParam.MaxAddForceMagnitude;
|
||||
}
|
||||
|
||||
OMV.Vector3 addForce = force;
|
||||
OMV.Vector3 addForce = Util.ClampV(force, BSParam.MaxAddForceMagnitude);
|
||||
// DetailLog("{0},BSCharacter.addForce,call,force={1}", LocalID, addForce);
|
||||
|
||||
PhysicsScene.TaintedObject(inTaintTime, "BSCharacter.AddForce", delegate()
|
||||
|
@ -902,6 +898,7 @@ public sealed class BSCharacter : BSPhysObject
|
|||
// Do some sanity checking for the avatar. Make sure it's above ground and inbounds.
|
||||
if (PositionSanityCheck(true))
|
||||
{
|
||||
DetailLog("{0},BSCharacter.UpdateProperties,updatePosForSanity,pos={1}", LocalID, _position);
|
||||
entprop.Position = _position;
|
||||
}
|
||||
|
||||
|
|
|
@ -143,7 +143,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
{
|
||||
enableAngularVerticalAttraction = true;
|
||||
enableAngularDeflection = false;
|
||||
enableAngularBanking = false;
|
||||
enableAngularBanking = true;
|
||||
if (BSParam.VehicleDebuggingEnabled)
|
||||
{
|
||||
enableAngularVerticalAttraction = true;
|
||||
|
@ -1280,11 +1280,11 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
// That is, NO_DEFLECTION_UP says angular motion should not add any pitch or roll movement
|
||||
// TODO: This is here because this is where ODE put it but documentation says it
|
||||
// is a linear effect. Where should this check go?
|
||||
if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
|
||||
{
|
||||
angularMotorContributionV.X = 0f;
|
||||
angularMotorContributionV.Y = 0f;
|
||||
}
|
||||
//if ((m_flags & (VehicleFlag.NO_DEFLECTION_UP)) != 0)
|
||||
// {
|
||||
// angularMotorContributionV.X = 0f;
|
||||
// angularMotorContributionV.Y = 0f;
|
||||
// }
|
||||
|
||||
VehicleRotationalVelocity += angularMotorContributionV * VehicleOrientation;
|
||||
VDetailLog("{0}, MoveAngular,angularTurning,angularMotorContrib={1}", Prim.LocalID, angularMotorContributionV);
|
||||
|
@ -1335,7 +1335,7 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
Vector3 unscaledContribVerticalErrorV = vertContributionV; // DEBUG DEBUG
|
||||
vertContributionV /= m_verticalAttractionTimescale;
|
||||
|
||||
VehicleRotationalVelocity += vertContributionV * VehicleOrientation;
|
||||
VehicleRotationalVelocity += vertContributionV;
|
||||
|
||||
VDetailLog("{0}, MoveAngular,verticalAttraction,,origRotVW={1},vertError={2},unscaledV={3},eff={4},ts={5},vertContribV={6}",
|
||||
Prim.LocalID, origRotVelW, verticalError, unscaledContribVerticalErrorV,
|
||||
|
@ -1437,24 +1437,25 @@ namespace OpenSim.Region.Physics.BulletSPlugin
|
|||
// As the vehicle rolls to the right or left, the Y value will increase from
|
||||
// zero (straight up) to 1 or -1 (full tilt right or left)
|
||||
Vector3 rollComponents = Vector3.UnitZ * VehicleOrientation;
|
||||
|
||||
// Figure out the yaw value for this much roll.
|
||||
// Squared because that seems to give a good value
|
||||
float yawAngle = (float)Math.Asin(rollComponents.Y * rollComponents.Y) * m_bankingEfficiency;
|
||||
|
||||
// Figure out the yaw value for this much roll.
|
||||
float yawAngle = m_angularMotorDirection.X * m_bankingEfficiency;
|
||||
// actual error = static turn error + dynamic turn error
|
||||
float mixedYawAngle = yawAngle * (1f - m_bankingMix) + yawAngle * m_bankingMix * VehicleForwardSpeed;
|
||||
float mixedYawAngle =(yawAngle * (1f - m_bankingMix)) + ((yawAngle * m_bankingMix) * VehicleForwardSpeed);
|
||||
|
||||
// TODO: the banking effect should not go to infinity but what to limit it to?
|
||||
mixedYawAngle = ClampInRange(-20f, mixedYawAngle, 20f);
|
||||
// And what should happen when this is being added to a user defined yaw that is already PI*4?
|
||||
mixedYawAngle = ClampInRange(-12, mixedYawAngle, 12);
|
||||
|
||||
// Build the force vector to change rotation from what it is to what it should be
|
||||
bankingContributionV.Z = -mixedYawAngle;
|
||||
|
||||
// Don't do it all at once.
|
||||
bankingContributionV /= m_bankingTimescale;
|
||||
// Don't do it all at once. Fudge because 1 second is too fast with most user defined roll as PI*4.
|
||||
bankingContributionV /= m_bankingTimescale * BSParam.VehicleAngularBankingTimescaleFudge;
|
||||
|
||||
VehicleRotationalVelocity += bankingContributionV * VehicleOrientation;
|
||||
//VehicleRotationalVelocity += bankingContributionV * VehicleOrientation;
|
||||
VehicleRotationalVelocity += bankingContributionV;
|
||||
|
||||
|
||||
VDetailLog("{0}, MoveAngular,Banking,rollComp={1},speed={2},rollComp={3},yAng={4},mYAng={5},ret={6}",
|
||||
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 AvatarCapsuleHeight { get; private set; }
|
||||
public static float AvatarContactProcessingThreshold { get; private set; }
|
||||
public static float AvatarBelowGroundUpCorrectionMeters { get; private set; }
|
||||
public static float AvatarStepHeight { get; private set; }
|
||||
public static float AvatarStepApproachFactor { get; private set; }
|
||||
public static float AvatarStepForceFactor { get; private set; }
|
||||
|
@ -122,6 +123,7 @@ public static class BSParam
|
|||
public static Vector3 VehicleLinearFactor { get; private set; }
|
||||
public static Vector3 VehicleAngularFactor { get; private set; }
|
||||
public static float VehicleGroundGravityFudge { get; private set; }
|
||||
public static float VehicleAngularBankingTimescaleFudge { get; private set; }
|
||||
public static bool VehicleDebuggingEnabled { get; private set; }
|
||||
|
||||
// Linkset implementation parameters
|
||||
|
@ -497,6 +499,10 @@ public static class BSParam
|
|||
0.1f,
|
||||
(s) => { return AvatarContactProcessingThreshold; },
|
||||
(s,v) => { AvatarContactProcessingThreshold = v; } ),
|
||||
new ParameterDefn<float>("AvatarBelowGroundUpCorrectionMeters", "Meters to move avatar up if it seems to be below ground",
|
||||
1.0f,
|
||||
(s) => { return AvatarBelowGroundUpCorrectionMeters; },
|
||||
(s,v) => { AvatarBelowGroundUpCorrectionMeters = v; } ),
|
||||
new ParameterDefn<float>("AvatarStepHeight", "Height of a step obstacle to consider step correction",
|
||||
0.3f,
|
||||
(s) => { return AvatarStepHeight; },
|
||||
|
@ -538,10 +544,14 @@ public static class BSParam
|
|||
0.0f,
|
||||
(s) => { return VehicleRestitution; },
|
||||
(s,v) => { VehicleRestitution = v; } ),
|
||||
new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiple gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
|
||||
new ParameterDefn<float>("VehicleGroundGravityFudge", "Factor to multiply gravity if a ground vehicle is probably on the ground (0.0 - 1.0)",
|
||||
0.2f,
|
||||
(s) => { return VehicleGroundGravityFudge; },
|
||||
(s,v) => { VehicleGroundGravityFudge = v; } ),
|
||||
new ParameterDefn<float>("VehicleAngularBankingTimescaleFudge", "Factor to multiple angular banking timescale. Tune to increase realism.",
|
||||
60.0f,
|
||||
(s) => { return VehicleAngularBankingTimescaleFudge; },
|
||||
(s,v) => { VehicleAngularBankingTimescaleFudge = v; } ),
|
||||
new ParameterDefn<bool>("VehicleDebuggingEnable", "Turn on/off vehicle debugging",
|
||||
false,
|
||||
(s) => { return VehicleDebuggingEnabled; },
|
||||
|
|
|
@ -337,6 +337,54 @@ public sealed class BSTerrainManager : IDisposable
|
|||
return GetTerrainPhysicalAtXYZ(pos, out physTerrain, out terrainBaseXYZ);
|
||||
}
|
||||
|
||||
// Return a new position that is over known terrain if the position is outside our terrain.
|
||||
public Vector3 ClampPositionIntoKnownTerrain(Vector3 pPos)
|
||||
{
|
||||
Vector3 ret = pPos;
|
||||
|
||||
// Can't do this function if we don't know about any terrain.
|
||||
if (m_terrains.Count == 0)
|
||||
return ret;
|
||||
|
||||
int loopPrevention = 5;
|
||||
Vector3 terrainBaseXYZ;
|
||||
BSTerrainPhys physTerrain;
|
||||
while (!GetTerrainPhysicalAtXYZ(ret, out physTerrain, out terrainBaseXYZ))
|
||||
{
|
||||
// The passed position is not within a known terrain area.
|
||||
|
||||
// First, base addresses are never negative so correct for that possible problem.
|
||||
if (ret.X < 0f || ret.Y < 0f)
|
||||
{
|
||||
if (ret.X < 0f)
|
||||
ret.X = 0f;
|
||||
if (ret.Y < 0f)
|
||||
ret.Y = 0f;
|
||||
DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,zeroingNegXorY,oldPos={1},newPos={2}",
|
||||
BSScene.DetailLogZero, pPos, ret);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Must be off the top of a region. Find an adjacent region to move into.
|
||||
Vector3 adjacentTerrainBase = FindAdjacentTerrainBase(terrainBaseXYZ);
|
||||
|
||||
ret.X = Math.Min(ret.X, adjacentTerrainBase.X + DefaultRegionSize.X);
|
||||
ret.Y = Math.Min(ret.Y, adjacentTerrainBase.Y + DefaultRegionSize.Y);
|
||||
DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,findingAdjacentRegion,adjacentRegBase={1},oldPos={2},newPos={3}",
|
||||
BSScene.DetailLogZero, adjacentTerrainBase, pPos, ret);
|
||||
}
|
||||
if (loopPrevention-- < 0f)
|
||||
{
|
||||
// The 'while' is a little dangerous so this prevents looping forever if the
|
||||
// mapping of the terrains ever gets messed up (like nothing at <0,0>) or
|
||||
// the list of terrains is in transition.
|
||||
DetailLog("{0},BSTerrainManager.ClampPositionToKnownTerrain,suppressingFindAdjacentRegionLoop", BSScene.DetailLogZero);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Given an X and Y, find the height of the terrain.
|
||||
// Since we could be handling multiple terrains for a mega-region,
|
||||
// the base of the region is calcuated assuming all regions are
|
||||
|
@ -400,18 +448,60 @@ public sealed class BSTerrainManager : IDisposable
|
|||
// the descriptor class and the 'base' fo the addresses therein.
|
||||
private bool GetTerrainPhysicalAtXYZ(Vector3 pos, out BSTerrainPhys outPhysTerrain, out Vector3 outTerrainBase)
|
||||
{
|
||||
int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
|
||||
int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
|
||||
Vector3 terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
|
||||
bool ret = false;
|
||||
|
||||
Vector3 terrainBaseXYZ = Vector3.Zero;
|
||||
if (pos.X < 0f || pos.Y < 0f)
|
||||
{
|
||||
// We don't handle negative addresses so just make up a base that will not be found.
|
||||
terrainBaseXYZ = new Vector3(-DefaultRegionSize.X, -DefaultRegionSize.Y, 0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
int offsetX = ((int)(pos.X / (int)DefaultRegionSize.X)) * (int)DefaultRegionSize.X;
|
||||
int offsetY = ((int)(pos.Y / (int)DefaultRegionSize.Y)) * (int)DefaultRegionSize.Y;
|
||||
terrainBaseXYZ = new Vector3(offsetX, offsetY, 0f);
|
||||
}
|
||||
|
||||
BSTerrainPhys physTerrain = null;
|
||||
lock (m_terrains)
|
||||
{
|
||||
m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
|
||||
ret = m_terrains.TryGetValue(terrainBaseXYZ, out physTerrain);
|
||||
}
|
||||
outTerrainBase = terrainBaseXYZ;
|
||||
outPhysTerrain = physTerrain;
|
||||
return (physTerrain != null);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Given a terrain base, return a terrain base for a terrain that is closer to <0,0> than
|
||||
// this one. Usually used to return an out of bounds object to a known place.
|
||||
private Vector3 FindAdjacentTerrainBase(Vector3 pTerrainBase)
|
||||
{
|
||||
Vector3 ret = pTerrainBase;
|
||||
ret.Z = 0f;
|
||||
lock (m_terrains)
|
||||
{
|
||||
// Once down to the <0,0> region, we have to be done.
|
||||
while (ret.X > 0f && ret.Y > 0f)
|
||||
{
|
||||
if (ret.X > 0f)
|
||||
{
|
||||
ret.X = Math.Max(0f, ret.X - DefaultRegionSize.X);
|
||||
DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingX,terrainBase={1}", BSScene.DetailLogZero, ret);
|
||||
if (m_terrains.ContainsKey(ret))
|
||||
break;
|
||||
}
|
||||
if (ret.Y > 0f)
|
||||
{
|
||||
ret.Y = Math.Max(0f, ret.Y - DefaultRegionSize.Y);
|
||||
DetailLog("{0},BSTerrainManager.FindAdjacentTerrainBase,reducingY,terrainBase={1}", BSScene.DetailLogZero, ret);
|
||||
if (m_terrains.ContainsKey(ret))
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Although no one seems to check this, I do support combining.
|
||||
|
|
|
@ -215,7 +215,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys
|
|||
|
||||
float magX = (float)sizeX / extentX;
|
||||
float magY = (float)sizeY / extentY;
|
||||
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
|
||||
if (physicsScene != null)
|
||||
physicsScene.DetailLog("{0},BSTerrainMesh.ConvertHeightMapToMesh,totVert={1},totInd={2},extentBase={3},magX={4},magY={5}",
|
||||
BSScene.DetailLogZero, totalVertices, totalIndices, extentBase, magX, magY);
|
||||
float minHeight = float.MaxValue;
|
||||
// Note that sizeX+1 vertices are created since there is land between this and the next region.
|
||||
|
@ -257,7 +258,8 @@ public sealed class BSTerrainMesh : BSTerrainPhys
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
|
||||
if (physicsScene != null)
|
||||
physicsScene.Logger.ErrorFormat("{0} Failed conversion of heightmap to mesh. For={1}/{2}, e={3}",
|
||||
LogHeader, physicsScene.RegionName, extentBase, e);
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,11 @@ public class RegionCombinerLargeLandChannel : ILandChannel
|
|||
RootRegionLandChannel.Clear(setupDefaultParcel);
|
||||
}
|
||||
|
||||
public ILandObject GetLandObject(Vector3 position)
|
||||
{
|
||||
return GetLandObject(position.X, position.Y);
|
||||
}
|
||||
|
||||
public ILandObject GetLandObject(int x, int y)
|
||||
{
|
||||
//m_log.DebugFormat("[BIGLANDTESTINT]: <{0},{1}>", x, y);
|
||||
|
|
|
@ -283,6 +283,80 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a given link entity from a linkset (linked objects and any sitting avatars).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If there are any ScenePresence's in the linkset (i.e. because they are sat upon one of the prims), then
|
||||
/// these are counted as extra entities that correspond to linknums beyond the number of prims in the linkset.
|
||||
/// The ScenePresences receive linknums in the order in which they sat.
|
||||
/// </remarks>
|
||||
/// <returns>
|
||||
/// The link entity. null if not found.
|
||||
/// </returns>
|
||||
/// <param name='linknum'>
|
||||
/// Can be either a non-negative integer or ScriptBaseClass.LINK_THIS (-4).
|
||||
/// If ScriptBaseClass.LINK_THIS then the entity containing the script is returned.
|
||||
/// If the linkset has one entity and a linknum of zero is given, then the single entity is returned. If any
|
||||
/// positive integer is given in this case then null is returned.
|
||||
/// If the linkset has more than one entity and a linknum greater than zero but equal to or less than the number
|
||||
/// of entities, then the entity which corresponds to that linknum is returned.
|
||||
/// Otherwise, if a positive linknum is given which is greater than the number of entities in the linkset, then
|
||||
/// null is returned.
|
||||
/// </param>
|
||||
public ISceneEntity GetLinkEntity(int linknum)
|
||||
{
|
||||
if (linknum < 0)
|
||||
{
|
||||
if (linknum == ScriptBaseClass.LINK_THIS)
|
||||
return m_host;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
int actualPrimCount = m_host.ParentGroup.PrimCount;
|
||||
List<UUID> sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars();
|
||||
int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count;
|
||||
|
||||
// Special case for a single prim. In this case the linknum is zero. However, this will not match a single
|
||||
// prim that has any avatars sat upon it (in which case the root prim is link 1).
|
||||
if (linknum == 0)
|
||||
{
|
||||
if (actualPrimCount == 1 && sittingAvatarIds.Count == 0)
|
||||
return m_host;
|
||||
|
||||
return null;
|
||||
}
|
||||
// Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but
|
||||
// here we must match 1 (ScriptBaseClass.LINK_ROOT).
|
||||
else if (linknum == ScriptBaseClass.LINK_ROOT && actualPrimCount == 1)
|
||||
{
|
||||
if (sittingAvatarIds.Count > 0)
|
||||
return m_host.ParentGroup.RootPart;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
else if (linknum <= adjustedPrimCount)
|
||||
{
|
||||
if (linknum <= actualPrimCount)
|
||||
{
|
||||
return m_host.ParentGroup.GetLinkNumPart(linknum);
|
||||
}
|
||||
else
|
||||
{
|
||||
ScenePresence sp = World.GetScenePresence(sittingAvatarIds[linknum - actualPrimCount - 1]);
|
||||
if (sp != null)
|
||||
return sp;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public List<SceneObjectPart> GetLinkParts(int linkType)
|
||||
{
|
||||
return GetLinkParts(m_host, linkType);
|
||||
|
@ -2174,23 +2248,25 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
|
||||
q = avatar.CameraRotation; // Mouselook
|
||||
else
|
||||
q = avatar.Rotation; // Currently infrequently updated so may be inaccurate
|
||||
q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate
|
||||
}
|
||||
else
|
||||
q = part.ParentGroup.GroupRotation; // Likely never get here but just in case
|
||||
}
|
||||
else
|
||||
q = part.ParentGroup.GroupRotation; // just the group rotation
|
||||
return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
|
||||
|
||||
return new LSL_Rotation(q);
|
||||
}
|
||||
q = part.GetWorldRotation();
|
||||
return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
|
||||
|
||||
return new LSL_Rotation(part.GetWorldRotation());
|
||||
}
|
||||
|
||||
public LSL_Rotation llGetLocalRot()
|
||||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
return new LSL_Rotation(m_host.RotationOffset.X, m_host.RotationOffset.Y, m_host.RotationOffset.Z, m_host.RotationOffset.W);
|
||||
|
||||
return new LSL_Rotation(m_host.RotationOffset);
|
||||
}
|
||||
|
||||
public void llSetForce(LSL_Vector force, int local)
|
||||
|
@ -2285,8 +2361,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
public LSL_Vector llGetTorque()
|
||||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
Vector3 torque = m_host.ParentGroup.GetTorque();
|
||||
return new LSL_Vector(torque.X,torque.Y,torque.Z);
|
||||
|
||||
return new LSL_Vector(m_host.ParentGroup.GetTorque());
|
||||
}
|
||||
|
||||
public void llSetForceAndTorque(LSL_Vector force, LSL_Vector torque, int local)
|
||||
|
@ -2312,19 +2388,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
vel = m_host.Velocity;
|
||||
}
|
||||
|
||||
return new LSL_Vector(vel.X, vel.Y, vel.Z);
|
||||
return new LSL_Vector(vel);
|
||||
}
|
||||
|
||||
public LSL_Vector llGetAccel()
|
||||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
return new LSL_Vector(m_host.Acceleration.X, m_host.Acceleration.Y, m_host.Acceleration.Z);
|
||||
|
||||
return new LSL_Vector(m_host.Acceleration);
|
||||
}
|
||||
|
||||
public LSL_Vector llGetOmega()
|
||||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
return new LSL_Vector(m_host.AngularVelocity.X, m_host.AngularVelocity.Y, m_host.AngularVelocity.Z);
|
||||
|
||||
return new LSL_Vector(m_host.AngularVelocity);
|
||||
}
|
||||
|
||||
public LSL_Float llGetTimeOfDay()
|
||||
|
@ -3101,13 +3179,15 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
msg.ParentEstateID = 0; //ParentEstateID;
|
||||
msg.Position = new Vector3(m_host.AbsolutePosition);
|
||||
msg.RegionID = World.RegionInfo.RegionID.Guid;//RegionID.Guid;
|
||||
|
||||
Vector3 pos = m_host.AbsolutePosition;
|
||||
msg.binaryBucket
|
||||
= Util.StringToBytes256(
|
||||
"{0}/{1}/{2}/{3}",
|
||||
World.RegionInfo.RegionName,
|
||||
(int)Math.Floor(m_host.AbsolutePosition.X),
|
||||
(int)Math.Floor(m_host.AbsolutePosition.Y),
|
||||
(int)Math.Floor(m_host.AbsolutePosition.Z));
|
||||
(int)Math.Floor(pos.X),
|
||||
(int)Math.Floor(pos.Y),
|
||||
(int)Math.Floor(pos.Z));
|
||||
|
||||
if (m_TransferModule != null)
|
||||
{
|
||||
|
@ -3691,47 +3771,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
|
||||
if (linknum < 0)
|
||||
{
|
||||
if (linknum == ScriptBaseClass.LINK_THIS)
|
||||
return m_host.UUID.ToString();
|
||||
else
|
||||
return ScriptBaseClass.NULL_KEY;
|
||||
}
|
||||
ISceneEntity entity = GetLinkEntity(linknum);
|
||||
|
||||
int actualPrimCount = m_host.ParentGroup.PrimCount;
|
||||
List<UUID> sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars();
|
||||
int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count;
|
||||
|
||||
// Special case for a single prim. In this case the linknum is zero. However, this will not match a single
|
||||
// prim that has any avatars sat upon it (in which case the root prim is link 1).
|
||||
if (linknum == 0)
|
||||
{
|
||||
if (actualPrimCount == 1 && sittingAvatarIds.Count == 0)
|
||||
return m_host.UUID.ToString();
|
||||
|
||||
return ScriptBaseClass.NULL_KEY;
|
||||
}
|
||||
// Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but
|
||||
// here we must match 1 (ScriptBaseClass.LINK_ROOT).
|
||||
else if (linknum == 1 && actualPrimCount == 1)
|
||||
{
|
||||
if (sittingAvatarIds.Count > 0)
|
||||
return m_host.ParentGroup.RootPart.UUID.ToString();
|
||||
else
|
||||
return ScriptBaseClass.NULL_KEY;
|
||||
}
|
||||
else if (linknum <= adjustedPrimCount)
|
||||
{
|
||||
if (linknum <= actualPrimCount)
|
||||
return m_host.ParentGroup.GetLinkNumPart(linknum).UUID.ToString();
|
||||
else
|
||||
return sittingAvatarIds[linknum - actualPrimCount - 1].ToString();
|
||||
}
|
||||
if (entity != null)
|
||||
return entity.UUID.ToString();
|
||||
else
|
||||
{
|
||||
return ScriptBaseClass.NULL_KEY;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -3777,55 +3822,12 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
|
||||
if (linknum < 0)
|
||||
{
|
||||
if (linknum == ScriptBaseClass.LINK_THIS)
|
||||
return m_host.Name;
|
||||
else
|
||||
return ScriptBaseClass.NULL_KEY;
|
||||
}
|
||||
ISceneEntity entity = GetLinkEntity(linknum);
|
||||
|
||||
int actualPrimCount = m_host.ParentGroup.PrimCount;
|
||||
List<UUID> sittingAvatarIds = m_host.ParentGroup.GetSittingAvatars();
|
||||
int adjustedPrimCount = actualPrimCount + sittingAvatarIds.Count;
|
||||
|
||||
// Special case for a single prim. In this case the linknum is zero. However, this will not match a single
|
||||
// prim that has any avatars sat upon it (in which case the root prim is link 1).
|
||||
if (linknum == 0)
|
||||
{
|
||||
if (actualPrimCount == 1 && sittingAvatarIds.Count == 0)
|
||||
return m_host.Name;
|
||||
|
||||
return ScriptBaseClass.NULL_KEY;
|
||||
}
|
||||
// Special case to handle a single prim with sitting avatars. GetLinkPart() would only match zero but
|
||||
// here we must match 1 (ScriptBaseClass.LINK_ROOT).
|
||||
else if (linknum == 1 && actualPrimCount == 1)
|
||||
{
|
||||
if (sittingAvatarIds.Count > 0)
|
||||
return m_host.ParentGroup.RootPart.Name;
|
||||
else
|
||||
return ScriptBaseClass.NULL_KEY;
|
||||
}
|
||||
else if (linknum <= adjustedPrimCount)
|
||||
{
|
||||
if (linknum <= actualPrimCount)
|
||||
{
|
||||
return m_host.ParentGroup.GetLinkNumPart(linknum).Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
ScenePresence sp = World.GetScenePresence(sittingAvatarIds[linknum - actualPrimCount - 1]);
|
||||
if (sp != null)
|
||||
return sp.Name;
|
||||
else
|
||||
return ScriptBaseClass.NULL_KEY;
|
||||
}
|
||||
}
|
||||
if (entity != null)
|
||||
return entity.Name;
|
||||
else
|
||||
{
|
||||
return ScriptBaseClass.NULL_KEY;
|
||||
}
|
||||
}
|
||||
|
||||
public LSL_Integer llGetInventoryNumber(int type)
|
||||
|
@ -4170,13 +4172,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
if (presence != null)
|
||||
{
|
||||
// agent must be over the owners land
|
||||
if (m_host.OwnerID == World.LandChannel.GetLandObject(
|
||||
presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
|
||||
if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
|
||||
{
|
||||
World.TeleportClientHome(agentId, presence.ControllingClient);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ScriptSleep(5000);
|
||||
}
|
||||
|
||||
|
@ -4197,8 +4199,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
destination = World.RegionInfo.RegionName;
|
||||
|
||||
// agent must be over the owners land
|
||||
if (m_host.OwnerID == World.LandChannel.GetLandObject(
|
||||
presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
|
||||
if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
|
||||
{
|
||||
DoLLTeleport(presence, destination, targetPos, targetLookAt);
|
||||
}
|
||||
|
@ -4229,8 +4230,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
if (presence.GodLevel >= 200) return;
|
||||
|
||||
// agent must be over the owners land
|
||||
if (m_host.OwnerID == World.LandChannel.GetLandObject(
|
||||
presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
|
||||
if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
|
||||
{
|
||||
World.RequestTeleportLocation(presence.ControllingClient, regionHandle, targetPos, targetLookAt, (uint)TeleportFlags.ViaLocation);
|
||||
}
|
||||
|
@ -4434,7 +4434,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
{
|
||||
if (pushrestricted)
|
||||
{
|
||||
ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos.X, PusheePos.Y);
|
||||
ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos);
|
||||
|
||||
// We didn't find the parcel but region is push restricted so assume it is NOT ok
|
||||
if (targetlandObj == null)
|
||||
|
@ -4449,7 +4449,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
}
|
||||
else
|
||||
{
|
||||
ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos.X, PusheePos.Y);
|
||||
ILandObject targetlandObj = World.LandChannel.GetLandObject(PusheePos);
|
||||
if (targetlandObj == null)
|
||||
{
|
||||
// We didn't find the parcel but region isn't push restricted so assume it's ok
|
||||
|
@ -4871,8 +4871,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
public LSL_Vector llGetCenterOfMass()
|
||||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
Vector3 center = m_host.GetCenterOfMass();
|
||||
return new LSL_Vector(center.X,center.Y,center.Z);
|
||||
|
||||
return new LSL_Vector(m_host.GetCenterOfMass());
|
||||
}
|
||||
|
||||
public LSL_List llListSort(LSL_List src, int stride, int ascending)
|
||||
|
@ -5703,12 +5703,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
}
|
||||
|
||||
ILandObject land;
|
||||
Vector3 pos;
|
||||
UUID id = UUID.Zero;
|
||||
|
||||
if (parcel || parcelOwned)
|
||||
{
|
||||
pos = m_host.ParentGroup.RootPart.GetWorldPosition();
|
||||
land = World.LandChannel.GetLandObject(pos.X, pos.Y);
|
||||
land = World.LandChannel.GetLandObject(m_host.ParentGroup.RootPart.GetWorldPosition());
|
||||
if (land == null)
|
||||
{
|
||||
id = UUID.Zero;
|
||||
|
@ -5734,8 +5733,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
{
|
||||
if (!regionWide)
|
||||
{
|
||||
pos = ssp.AbsolutePosition;
|
||||
land = World.LandChannel.GetLandObject(pos.X, pos.Y);
|
||||
land = World.LandChannel.GetLandObject(ssp.AbsolutePosition);
|
||||
if (land != null)
|
||||
{
|
||||
if (parcelOwned && land.LandData.OwnerID == id ||
|
||||
|
@ -5860,7 +5858,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
if (presence != null)
|
||||
{
|
||||
// agent must be over the owners land
|
||||
ILandObject land = World.LandChannel.GetLandObject(presence.AbsolutePosition.X, presence.AbsolutePosition.Y);
|
||||
ILandObject land = World.LandChannel.GetLandObject(presence.AbsolutePosition);
|
||||
if (land == null)
|
||||
return;
|
||||
|
||||
|
@ -5882,19 +5880,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
ScenePresence presence = World.GetScenePresence(key);
|
||||
if (presence != null) // object is an avatar
|
||||
{
|
||||
if (m_host.OwnerID
|
||||
== World.LandChannel.GetLandObject(
|
||||
presence.AbsolutePosition.X, presence.AbsolutePosition.Y).LandData.OwnerID)
|
||||
if (m_host.OwnerID == World.LandChannel.GetLandObject(presence.AbsolutePosition).LandData.OwnerID)
|
||||
return 1;
|
||||
}
|
||||
else // object is not an avatar
|
||||
{
|
||||
SceneObjectPart obj = World.GetSceneObjectPart(key);
|
||||
|
||||
if (obj != null)
|
||||
if (m_host.OwnerID
|
||||
== World.LandChannel.GetLandObject(
|
||||
obj.AbsolutePosition.X, obj.AbsolutePosition.Y).LandData.OwnerID)
|
||||
{
|
||||
if (m_host.OwnerID == World.LandChannel.GetLandObject(obj.AbsolutePosition).LandData.OwnerID)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5972,8 +5969,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
// if the land is group owned and the object is group owned by the same group
|
||||
// or
|
||||
// if the object is owned by a person with estate access.
|
||||
|
||||
ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition.X, av.AbsolutePosition.Y);
|
||||
ILandObject parcel = World.LandChannel.GetLandObject(av.AbsolutePosition);
|
||||
if (parcel != null)
|
||||
{
|
||||
if (m_host.OwnerID == parcel.LandData.OwnerID ||
|
||||
|
@ -5985,14 +5981,13 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public LSL_Vector llGroundSlope(LSL_Vector offset)
|
||||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
|
||||
//Get the slope normal. This gives us the equation of the plane tangent to the slope.
|
||||
LSL_Vector vsn = llGroundNormal(offset);
|
||||
|
||||
|
@ -6003,7 +5998,11 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
vsl.Normalize();
|
||||
//Normalization might be overkill here
|
||||
|
||||
return new LSL_Vector(vsl.X, vsl.Y, vsl.Z);
|
||||
vsn.x = vsl.X;
|
||||
vsn.y = vsl.Y;
|
||||
vsn.z = vsl.Z;
|
||||
|
||||
return vsn;
|
||||
}
|
||||
|
||||
public LSL_Vector llGroundNormal(LSL_Vector offset)
|
||||
|
@ -6053,7 +6052,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
//I believe the crossproduct of two normalized vectors is a normalized vector so
|
||||
//this normalization may be overkill
|
||||
|
||||
return new LSL_Vector(vsn.X, vsn.Y, vsn.Z);
|
||||
return new LSL_Vector(vsn);
|
||||
}
|
||||
|
||||
public LSL_Vector llGroundContour(LSL_Vector offset)
|
||||
|
@ -6069,7 +6068,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
return m_host.ParentGroup.AttachmentPoint;
|
||||
}
|
||||
|
||||
public LSL_Integer llGetFreeMemory()
|
||||
public virtual LSL_Integer llGetFreeMemory()
|
||||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
// Make scripts designed for LSO happy
|
||||
|
@ -6553,7 +6552,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
UUID key;
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
|
||||
|
||||
if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
|
||||
{
|
||||
int expires = 0;
|
||||
|
@ -7782,7 +7782,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
|
||||
|
||||
if (land.LandData.OwnerID != m_host.OwnerID)
|
||||
return;
|
||||
|
@ -7796,7 +7796,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
|
||||
|
||||
if (land.LandData.OwnerID != m_host.OwnerID)
|
||||
return String.Empty;
|
||||
|
@ -7807,8 +7807,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
public LSL_Vector llGetRootPosition()
|
||||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
return new LSL_Vector(m_host.ParentGroup.AbsolutePosition.X, m_host.ParentGroup.AbsolutePosition.Y,
|
||||
m_host.ParentGroup.AbsolutePosition.Z);
|
||||
|
||||
return new LSL_Vector(m_host.ParentGroup.AbsolutePosition);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -7831,13 +7831,14 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
if ((avatar.AgentControlFlags & (uint)AgentManager.ControlFlags.AGENT_CONTROL_MOUSELOOK) != 0)
|
||||
q = avatar.CameraRotation; // Mouselook
|
||||
else
|
||||
q = avatar.Rotation; // Currently infrequently updated so may be inaccurate
|
||||
q = avatar.GetWorldRotation(); // Currently infrequently updated so may be inaccurate
|
||||
else
|
||||
q = m_host.ParentGroup.GroupRotation; // Likely never get here but just in case
|
||||
}
|
||||
else
|
||||
q = m_host.ParentGroup.GroupRotation; // just the group rotation
|
||||
return new LSL_Rotation(q.X, q.Y, q.Z, q.W);
|
||||
|
||||
return new LSL_Rotation(q);
|
||||
}
|
||||
|
||||
public LSL_String llGetObjectDesc()
|
||||
|
@ -7944,7 +7945,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
|
||||
public LSL_Vector llGetGeometricCenter()
|
||||
{
|
||||
return new LSL_Vector(m_host.GetGeometricCenter().X, m_host.GetGeometricCenter().Y, m_host.GetGeometricCenter().Z);
|
||||
return new LSL_Vector(m_host.GetGeometricCenter());
|
||||
}
|
||||
|
||||
public LSL_List llGetPrimitiveParams(LSL_List rules)
|
||||
|
@ -8031,23 +8032,24 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
break;
|
||||
|
||||
case (int)ScriptBaseClass.PRIM_POSITION:
|
||||
LSL_Vector v = new LSL_Vector(part.AbsolutePosition.X,
|
||||
part.AbsolutePosition.Y,
|
||||
part.AbsolutePosition.Z);
|
||||
LSL_Vector v = new LSL_Vector(part.AbsolutePosition);
|
||||
|
||||
// For some reason, the part.AbsolutePosition.* values do not change if the
|
||||
// linkset is rotated; they always reflect the child prim's world position
|
||||
// as though the linkset is unrotated. This is incompatible behavior with SL's
|
||||
// implementation, so will break scripts imported from there (not to mention it
|
||||
// makes it more difficult to determine a child prim's actual inworld position).
|
||||
if (part.ParentID != 0)
|
||||
v = ((v - llGetRootPosition()) * llGetRootRotation()) + llGetRootPosition();
|
||||
if (!part.IsRoot)
|
||||
{
|
||||
LSL_Vector rootPos = new LSL_Vector(m_host.ParentGroup.AbsolutePosition);
|
||||
v = ((v - rootPos) * llGetRootRotation()) + rootPos;
|
||||
}
|
||||
|
||||
res.Add(v);
|
||||
break;
|
||||
|
||||
case (int)ScriptBaseClass.PRIM_SIZE:
|
||||
res.Add(new LSL_Vector(part.Scale.X,
|
||||
part.Scale.Y,
|
||||
part.Scale.Z));
|
||||
res.Add(new LSL_Vector(part.Scale));
|
||||
break;
|
||||
|
||||
case (int)ScriptBaseClass.PRIM_ROTATION:
|
||||
|
@ -8361,8 +8363,8 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
case (int)ScriptBaseClass.PRIM_DESC:
|
||||
res.Add(new LSL_String(part.Description));
|
||||
break;
|
||||
case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
|
||||
res.Add(new LSL_Rotation(part.RotationOffset.X, part.RotationOffset.Y, part.RotationOffset.Z, part.RotationOffset.W));
|
||||
case (int)ScriptBaseClass.PRIM_ROT_LOCAL:
|
||||
res.Add(new LSL_Rotation(part.RotationOffset));
|
||||
break;
|
||||
case (int)ScriptBaseClass.PRIM_POS_LOCAL:
|
||||
res.Add(new LSL_Vector(GetPartLocalPos(part)));
|
||||
|
@ -9571,7 +9573,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
|
||||
// according to the docs, this command only works if script owner and land owner are the same
|
||||
// lets add estate owners and gods, too, and use the generic permission check.
|
||||
ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
|
||||
ILandObject landObject = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
|
||||
if (!World.Permissions.CanEditParcelProperties(m_host.OwnerID, landObject, GroupPowers.ChangeMedia)) return;
|
||||
|
||||
bool update = false; // send a ParcelMediaUpdate (and possibly change the land's media URL)?
|
||||
|
@ -9890,21 +9892,22 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
m_host.AddScriptLPS(1);
|
||||
|
||||
if (m_item.PermsGranter == UUID.Zero)
|
||||
return new LSL_Vector();
|
||||
return Vector3.Zero;
|
||||
|
||||
if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
|
||||
{
|
||||
ShoutError("No permissions to track the camera");
|
||||
return new LSL_Vector();
|
||||
return Vector3.Zero;
|
||||
}
|
||||
|
||||
ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
|
||||
if (presence != null)
|
||||
{
|
||||
LSL_Vector pos = new LSL_Vector(presence.CameraPosition.X, presence.CameraPosition.Y, presence.CameraPosition.Z);
|
||||
LSL_Vector pos = new LSL_Vector(presence.CameraPosition);
|
||||
return pos;
|
||||
}
|
||||
return new LSL_Vector();
|
||||
|
||||
return Vector3.Zero;
|
||||
}
|
||||
|
||||
public LSL_Rotation llGetCameraRot()
|
||||
|
@ -9912,21 +9915,21 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
m_host.AddScriptLPS(1);
|
||||
|
||||
if (m_item.PermsGranter == UUID.Zero)
|
||||
return new LSL_Rotation();
|
||||
return Quaternion.Identity;
|
||||
|
||||
if ((m_item.PermsMask & ScriptBaseClass.PERMISSION_TRACK_CAMERA) == 0)
|
||||
{
|
||||
ShoutError("No permissions to track the camera");
|
||||
return new LSL_Rotation();
|
||||
return Quaternion.Identity;
|
||||
}
|
||||
|
||||
ScenePresence presence = World.GetScenePresence(m_host.OwnerID);
|
||||
if (presence != null)
|
||||
{
|
||||
return new LSL_Rotation(presence.CameraRotation.X, presence.CameraRotation.Y, presence.CameraRotation.Z, presence.CameraRotation.W);
|
||||
return new LSL_Rotation(presence.CameraRotation);
|
||||
}
|
||||
|
||||
return new LSL_Rotation();
|
||||
return Quaternion.Identity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -9995,7 +9998,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
UUID key;
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
|
||||
if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
|
||||
{
|
||||
int expires = 0;
|
||||
|
@ -10036,7 +10039,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
UUID key;
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
|
||||
if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageAllowed))
|
||||
{
|
||||
if (UUID.TryParse(avatar, out key))
|
||||
|
@ -10063,7 +10066,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
UUID key;
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
|
||||
if (World.Permissions.CanEditParcelProperties(m_host.OwnerID, land, GroupPowers.LandManageBanned))
|
||||
{
|
||||
if (UUID.TryParse(avatar, out key))
|
||||
|
@ -10325,7 +10328,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
public void llResetLandBanList()
|
||||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).LandData;
|
||||
LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData;
|
||||
if (land.OwnerID == m_host.OwnerID)
|
||||
{
|
||||
foreach (LandAccessEntry entry in land.ParcelAccessList)
|
||||
|
@ -10342,7 +10345,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
public void llResetLandPassList()
|
||||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y).LandData;
|
||||
LandData land = World.LandChannel.GetLandObject(m_host.AbsolutePosition).LandData;
|
||||
if (land.OwnerID == m_host.OwnerID)
|
||||
{
|
||||
foreach (LandAccessEntry entry in land.ParcelAccessList)
|
||||
|
@ -10518,7 +10521,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
ret.Add(new LSL_Vector((double)av.AbsolutePosition.X, (double)av.AbsolutePosition.Y, (double)av.AbsolutePosition.Z));
|
||||
break;
|
||||
case ScriptBaseClass.OBJECT_ROT:
|
||||
ret.Add(new LSL_Rotation((double)av.Rotation.X, (double)av.Rotation.Y, (double)av.Rotation.Z, (double)av.Rotation.W));
|
||||
ret.Add(new LSL_Rotation(av.GetWorldRotation()));
|
||||
break;
|
||||
case ScriptBaseClass.OBJECT_VELOCITY:
|
||||
ret.Add(new LSL_Vector(av.Velocity.X, av.Velocity.Y, av.Velocity.Z));
|
||||
|
@ -10920,7 +10923,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
|
||||
LSL_List result = new LSL_List();
|
||||
|
||||
if (obj != null && obj.OwnerID != m_host.OwnerID)
|
||||
if (obj != null && obj.OwnerID == m_host.OwnerID)
|
||||
{
|
||||
LSL_List remaining = GetPrimParams(obj, rules, ref result);
|
||||
|
||||
|
@ -11021,7 +11024,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
World.ForEachScenePresence(delegate(ScenePresence sp)
|
||||
{
|
||||
Vector3 ac = sp.AbsolutePosition - rayStart;
|
||||
Vector3 bc = sp.AbsolutePosition - rayEnd;
|
||||
// Vector3 bc = sp.AbsolutePosition - rayEnd;
|
||||
|
||||
double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd));
|
||||
|
||||
|
@ -11111,7 +11114,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
radius = Math.Abs(maxZ);
|
||||
radius = radius*1.413f;
|
||||
Vector3 ac = group.AbsolutePosition - rayStart;
|
||||
Vector3 bc = group.AbsolutePosition - rayEnd;
|
||||
// Vector3 bc = group.AbsolutePosition - rayEnd;
|
||||
|
||||
double d = Math.Abs(Vector3.Mag(Vector3.Cross(ab, ac)) / Vector3.Distance(rayStart, rayEnd));
|
||||
|
||||
|
@ -11455,7 +11458,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
list.Add(new LSL_Integer(linkNum));
|
||||
|
||||
if ((dataFlags & ScriptBaseClass.RC_GET_NORMAL) == ScriptBaseClass.RC_GET_NORMAL)
|
||||
list.Add(new LSL_Vector(result.Normal.X, result.Normal.Y, result.Normal.Z));
|
||||
list.Add(new LSL_Vector(result.Normal));
|
||||
|
||||
values++;
|
||||
if (values >= count)
|
||||
|
@ -11557,7 +11560,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
return 16384;
|
||||
}
|
||||
|
||||
public LSL_Integer llGetUsedMemory()
|
||||
public virtual LSL_Integer llGetUsedMemory()
|
||||
{
|
||||
m_host.AddScriptLPS(1);
|
||||
// The value returned for LSO scripts in SL
|
||||
|
|
|
@ -266,6 +266,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
{
|
||||
llist[i] = new LSL_Float((float)result[i]);
|
||||
}
|
||||
else if (result[i] is double)
|
||||
{
|
||||
llist[i] = new LSL_Float((double)result[i]);
|
||||
}
|
||||
else if (result[i] is UUID)
|
||||
{
|
||||
llist[i] = new LSL_Key(result[i].ToString());
|
||||
|
|
|
@ -363,7 +363,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
//OSSL only may be used if object is in the same group as the parcel
|
||||
if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_GROUP_MEMBER"))
|
||||
{
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
|
||||
|
||||
if (land.LandData.GroupID == m_item.GroupID && land.LandData.GroupID != UUID.Zero)
|
||||
{
|
||||
|
@ -374,7 +374,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
//Only Parcelowners may use the function
|
||||
if (m_FunctionPerms[function].AllowedOwnerClasses.Contains("PARCEL_OWNER"))
|
||||
{
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
|
||||
|
||||
if (land.LandData.OwnerID == ownerID)
|
||||
{
|
||||
|
@ -1502,8 +1502,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
|
||||
m_host.AddScriptLPS(1);
|
||||
|
||||
ILandObject land
|
||||
= World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
|
||||
|
||||
if (land.LandData.OwnerID != m_host.OwnerID)
|
||||
return;
|
||||
|
@ -1519,8 +1518,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
|
||||
m_host.AddScriptLPS(1);
|
||||
|
||||
ILandObject land
|
||||
= World.LandChannel.GetLandObject(m_host.AbsolutePosition.X, m_host.AbsolutePosition.Y);
|
||||
ILandObject land = World.LandChannel.GetLandObject(m_host.AbsolutePosition);
|
||||
|
||||
if (land.LandData.OwnerID != m_host.OwnerID)
|
||||
{
|
||||
|
@ -2515,13 +2513,10 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
ScenePresence sp = World.GetScenePresence(npcId);
|
||||
|
||||
if (sp != null)
|
||||
{
|
||||
Vector3 pos = sp.AbsolutePosition;
|
||||
return new LSL_Vector(pos.X, pos.Y, pos.Z);
|
||||
}
|
||||
return new LSL_Vector(sp.AbsolutePosition);
|
||||
}
|
||||
|
||||
return new LSL_Vector(0, 0, 0);
|
||||
return Vector3.Zero;
|
||||
}
|
||||
|
||||
public void osNpcMoveTo(LSL_Key npc, LSL_Vector pos)
|
||||
|
@ -2578,21 +2573,18 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
{
|
||||
UUID npcId;
|
||||
if (!UUID.TryParse(npc.m_string, out npcId))
|
||||
return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W);
|
||||
return new LSL_Rotation(Quaternion.Identity);
|
||||
|
||||
if (!npcModule.CheckPermissions(npcId, m_host.OwnerID))
|
||||
return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W);
|
||||
return new LSL_Rotation(Quaternion.Identity);
|
||||
|
||||
ScenePresence sp = World.GetScenePresence(npcId);
|
||||
|
||||
if (sp != null)
|
||||
{
|
||||
Quaternion rot = sp.Rotation;
|
||||
return new LSL_Rotation(rot.X, rot.Y, rot.Z, rot.W);
|
||||
}
|
||||
return new LSL_Rotation(sp.GetWorldRotation());
|
||||
}
|
||||
|
||||
return new LSL_Rotation(Quaternion.Identity.X, Quaternion.Identity.Y, Quaternion.Identity.Z, Quaternion.Identity.W);
|
||||
return Quaternion.Identity;
|
||||
}
|
||||
|
||||
public void osNpcSetRot(LSL_Key npc, LSL_Rotation rotation)
|
||||
|
@ -3022,20 +3014,16 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
|
||||
UUID avatarId = new UUID(avatar);
|
||||
ScenePresence presence = World.GetScenePresence(avatarId);
|
||||
Vector3 pos = m_host.GetWorldPosition();
|
||||
bool result = World.ScriptDanger(m_host.LocalId, new Vector3((float)pos.X, (float)pos.Y, (float)pos.Z));
|
||||
if (result)
|
||||
|
||||
if (presence != null && World.ScriptDanger(m_host.LocalId, m_host.GetWorldPosition()))
|
||||
{
|
||||
if (presence != null)
|
||||
{
|
||||
float health = presence.Health;
|
||||
health += (float)healing;
|
||||
if (health >= 100)
|
||||
{
|
||||
health = 100;
|
||||
}
|
||||
presence.setHealthWithUpdate(health);
|
||||
}
|
||||
float health = presence.Health;
|
||||
health += (float)healing;
|
||||
|
||||
if (health >= 100)
|
||||
health = 100;
|
||||
|
||||
presence.setHealthWithUpdate(health);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3112,8 +3100,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api
|
|||
if (avatar != null && avatar.UUID != m_host.OwnerID)
|
||||
{
|
||||
result.Add(new LSL_String(avatar.UUID.ToString()));
|
||||
OpenMetaverse.Vector3 ap = avatar.AbsolutePosition;
|
||||
result.Add(new LSL_Vector(ap.X, ap.Y, ap.Z));
|
||||
result.Add(new LSL_Vector(avatar.AbsolutePosition));
|
||||
result.Add(new LSL_String(avatar.Name));
|
||||
}
|
||||
});
|
||||
|
|
|
@ -353,7 +353,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
|||
// Position of a sensor in a child prim attached to an avatar
|
||||
// will be still wrong.
|
||||
ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar);
|
||||
q = avatar.Rotation * q;
|
||||
q = avatar.GetWorldRotation() * q;
|
||||
}
|
||||
|
||||
LSL_Types.Quaternion r = new LSL_Types.Quaternion(q);
|
||||
|
@ -480,7 +480,7 @@ namespace OpenSim.Region.ScriptEngine.Shared.Api.Plugins
|
|||
// Position of a sensor in a child prim attached to an avatar
|
||||
// will be still wrong.
|
||||
ScenePresence avatar = m_CmdManager.m_ScriptEngine.World.GetScenePresence(SensePoint.ParentGroup.AttachedAvatar);
|
||||
q = avatar.Rotation * q;
|
||||
q = avatar.GetWorldRotation() * q;
|
||||
}
|
||||
|
||||
LSL_Types.Quaternion r = new LSL_Types.Quaternion(q);
|
||||
|
|
|
@ -662,13 +662,18 @@ namespace SecondLife
|
|||
{
|
||||
string severity = CompErr.IsWarning ? "Warning" : "Error";
|
||||
|
||||
KeyValuePair<int, int> lslPos;
|
||||
KeyValuePair<int, int> errorPos;
|
||||
|
||||
// Show 5 errors max, but check entire list for errors
|
||||
|
||||
if (severity == "Error")
|
||||
{
|
||||
lslPos = FindErrorPosition(CompErr.Line, CompErr.Column, m_lineMaps[assembly]);
|
||||
// C# scripts will not have a linemap since theres no line translation involved.
|
||||
if (!m_lineMaps.ContainsKey(assembly))
|
||||
errorPos = new KeyValuePair<int, int>(CompErr.Line, CompErr.Column);
|
||||
else
|
||||
errorPos = FindErrorPosition(CompErr.Line, CompErr.Column, m_lineMaps[assembly]);
|
||||
|
||||
string text = CompErr.ErrorText;
|
||||
|
||||
// Use LSL type names
|
||||
|
@ -678,7 +683,7 @@ namespace SecondLife
|
|||
// The Second Life viewer's script editor begins
|
||||
// countingn lines and columns at 0, so we subtract 1.
|
||||
errtext += String.Format("({0},{1}): {4} {2}: {3}\n",
|
||||
lslPos.Key - 1, lslPos.Value - 1,
|
||||
errorPos.Key - 1, errorPos.Value - 1,
|
||||
CompErr.ErrorNumber, text, severity);
|
||||
hadErrors = true;
|
||||
}
|
||||
|
|
|
@ -209,7 +209,6 @@ namespace OpenSim.Region.ScriptEngine.Shared.Tests
|
|||
+= (itemId, evp) => m_lslApi.llHTTPResponse(evp.Params[0].ToString(), 200, testResponse);
|
||||
|
||||
// Console.WriteLine("Trying {0}", returnedUri);
|
||||
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(returnedUri);
|
||||
|
||||
AssertHttpResponse(returnedUri, testResponse);
|
||||
|
||||
|
|
|
@ -138,17 +138,17 @@ namespace OpenSim.Server.Base
|
|||
case ExtensionChange.Add:
|
||||
if (a.AddinFile.Contains(Registry.DefaultAddinsFolder))
|
||||
{
|
||||
m_log.InfoFormat("[SERVER]: Adding {0} from registry", a.Name);
|
||||
m_log.InfoFormat("[SERVER UTILS]: Adding {0} from registry", a.Name);
|
||||
connector.PluginPath = System.IO.Path.Combine(Registry.DefaultAddinsFolder,a.Name.Replace(',', '.')); }
|
||||
else
|
||||
{
|
||||
m_log.InfoFormat("[SERVER]: Adding {0} from ./bin", a.Name);
|
||||
m_log.InfoFormat("[SERVER UTILS]: Adding {0} from ./bin", a.Name);
|
||||
connector.PluginPath = a.AddinFile;
|
||||
}
|
||||
LoadPlugin(connector);
|
||||
break;
|
||||
case ExtensionChange.Remove:
|
||||
m_log.InfoFormat("[SERVER]: Removing {0}", a.Name);
|
||||
m_log.InfoFormat("[SERVER UTILS]: Removing {0}", a.Name);
|
||||
UnloadPlugin(connector);
|
||||
break;
|
||||
}
|
||||
|
@ -166,13 +166,13 @@ namespace OpenSim.Server.Base
|
|||
}
|
||||
else
|
||||
{
|
||||
m_log.InfoFormat("[SERVER]: {0} Disabled.", connector.ConfigName);
|
||||
m_log.InfoFormat("[SERVER UTILS]: {0} Disabled.", connector.ConfigName);
|
||||
}
|
||||
}
|
||||
|
||||
private void UnloadPlugin(IRobustConnector connector)
|
||||
{
|
||||
m_log.InfoFormat("[Server]: Unloading {0}", connector.ConfigName);
|
||||
m_log.InfoFormat("[SERVER UTILS]: Unloading {0}", connector.ConfigName);
|
||||
|
||||
connector.Unload();
|
||||
}
|
||||
|
@ -280,7 +280,7 @@ namespace OpenSim.Server.Base
|
|||
{
|
||||
if (!(e is System.MissingMethodException))
|
||||
{
|
||||
m_log.ErrorFormat("Error loading plugin {0} from {1}. Exception: {2}, {3}",
|
||||
m_log.ErrorFormat("[SERVER UTILS]: Error loading plugin {0} from {1}. Exception: {2}, {3}",
|
||||
interfaceName,
|
||||
dllName,
|
||||
e.InnerException == null ? e.Message : e.InnerException.Message,
|
||||
|
@ -298,14 +298,14 @@ namespace OpenSim.Server.Base
|
|||
}
|
||||
catch (ReflectionTypeLoadException rtle)
|
||||
{
|
||||
m_log.Error(string.Format("Error loading plugin from {0}:\n{1}", dllName,
|
||||
m_log.Error(string.Format("[SERVER UTILS]: Error loading plugin from {0}:\n{1}", dllName,
|
||||
String.Join("\n", Array.ConvertAll(rtle.LoaderExceptions, e => e.ToString()))),
|
||||
rtle);
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Error(string.Format("Error loading plugin from {0}", dllName), e);
|
||||
m_log.Error(string.Format("[SERVER UTILS]: Error loading plugin from {0}", dllName), e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -517,7 +517,7 @@ namespace OpenSim.Server.Base
|
|||
public static IConfigSource LoadInitialConfig(string url)
|
||||
{
|
||||
IConfigSource source = new XmlConfigSource();
|
||||
m_log.InfoFormat("[CONFIG]: {0} is a http:// URI, fetching ...", url);
|
||||
m_log.InfoFormat("[SERVER UTILS]: {0} is a http:// URI, fetching ...", url);
|
||||
|
||||
// The ini file path is a http URI
|
||||
// Try to read it
|
||||
|
@ -529,7 +529,7 @@ namespace OpenSim.Server.Base
|
|||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.FatalFormat("[CONFIG]: Exception reading config from URI {0}\n" + e.ToString(), url);
|
||||
m_log.FatalFormat("[SERVER UTILS]: Exception reading config from URI {0}\n" + e.ToString(), url);
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -186,10 +186,7 @@ namespace OpenSim.Server.Base
|
|||
XmlConfigurator.Configure();
|
||||
}
|
||||
|
||||
// FIXME: This should be done down in ServerBase but we need to sort out and refactor the log4net
|
||||
// XmlConfigurator calls first accross servers.
|
||||
m_log.InfoFormat("[SERVER BASE]: Starting in {0}", m_startupDirectory);
|
||||
|
||||
LogEnvironmentInformation();
|
||||
RegisterCommonAppenders(startupConfig);
|
||||
|
||||
if (startupConfig.GetString("PIDFile", String.Empty) != String.Empty)
|
||||
|
|
|
@ -145,7 +145,7 @@ namespace OpenSim.Server
|
|||
}
|
||||
else
|
||||
{
|
||||
m_log.InfoFormat("[SERVER]: Failed to load {0}", conn);
|
||||
m_log.ErrorFormat("[SERVER]: Failed to load {0}", conn);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -123,46 +123,32 @@ namespace OpenSim.Services.AssetService
|
|||
public virtual AssetMetadata GetMetadata(string id)
|
||||
{
|
||||
// m_log.DebugFormat("[ASSET SERVICE]: Get asset metadata for {0}", id);
|
||||
|
||||
UUID assetID;
|
||||
|
||||
if (!UUID.TryParse(id, out assetID))
|
||||
return null;
|
||||
AssetBase asset = Get(id);
|
||||
|
||||
AssetBase asset = m_Database.GetAsset(assetID);
|
||||
if (asset != null)
|
||||
return asset.Metadata;
|
||||
|
||||
return null;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual byte[] GetData(string id)
|
||||
{
|
||||
// m_log.DebugFormat("[ASSET SERVICE]: Get asset data for {0}", id);
|
||||
|
||||
UUID assetID;
|
||||
|
||||
if (!UUID.TryParse(id, out assetID))
|
||||
AssetBase asset = Get(id);
|
||||
|
||||
if (asset != null)
|
||||
return asset.Data;
|
||||
else
|
||||
return null;
|
||||
|
||||
AssetBase asset = m_Database.GetAsset(assetID);
|
||||
return asset.Data;
|
||||
}
|
||||
|
||||
public virtual bool Get(string id, Object sender, AssetRetrieved handler)
|
||||
{
|
||||
//m_log.DebugFormat("[AssetService]: Get asset async {0}", id);
|
||||
|
||||
UUID assetID;
|
||||
|
||||
if (!UUID.TryParse(id, out assetID))
|
||||
return false;
|
||||
|
||||
AssetBase asset = m_Database.GetAsset(assetID);
|
||||
|
||||
//m_log.DebugFormat("[AssetService]: Got asset {0}", asset);
|
||||
|
||||
handler(id, sender, asset);
|
||||
handler(id, sender, Get(id));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -39,8 +39,7 @@ using OpenMetaverse;
|
|||
namespace OpenSim.Services.AssetService
|
||||
{
|
||||
/// <summary>
|
||||
/// This will be developed into a de-duplicating asset service.
|
||||
/// XXX: Currently it's a just a copy of the existing AssetService. so please don't attempt to use it.
|
||||
/// A de-duplicating asset service.
|
||||
/// </summary>
|
||||
public class XAssetService : XAssetServiceBase, IAssetService
|
||||
{
|
||||
|
@ -48,7 +47,9 @@ namespace OpenSim.Services.AssetService
|
|||
|
||||
protected static XAssetService m_RootInstance;
|
||||
|
||||
public XAssetService(IConfigSource config) : base(config)
|
||||
public XAssetService(IConfigSource config) : this(config, "AssetService") {}
|
||||
|
||||
public XAssetService(IConfigSource config, string configName) : base(config, configName)
|
||||
{
|
||||
if (m_RootInstance == null)
|
||||
{
|
||||
|
@ -56,22 +57,21 @@ namespace OpenSim.Services.AssetService
|
|||
|
||||
if (m_AssetLoader != null)
|
||||
{
|
||||
IConfig assetConfig = config.Configs["AssetService"];
|
||||
IConfig assetConfig = config.Configs[configName];
|
||||
if (assetConfig == null)
|
||||
throw new Exception("No AssetService configuration");
|
||||
|
||||
string loaderArgs = assetConfig.GetString("AssetLoaderArgs",
|
||||
String.Empty);
|
||||
string loaderArgs = assetConfig.GetString("AssetLoaderArgs", String.Empty);
|
||||
|
||||
bool assetLoaderEnabled = assetConfig.GetBoolean("AssetLoaderEnabled", true);
|
||||
|
||||
if (assetLoaderEnabled)
|
||||
if (assetLoaderEnabled && !HasChainedAssetService)
|
||||
{
|
||||
m_log.DebugFormat("[XASSET SERVICE]: Loading default asset set from {0}", loaderArgs);
|
||||
|
||||
m_AssetLoader.ForEachDefaultXmlAsset(
|
||||
loaderArgs,
|
||||
delegate(AssetBase a)
|
||||
a =>
|
||||
{
|
||||
AssetBase existingAsset = Get(a.ID);
|
||||
// AssetMetadata existingMetadata = GetMetadata(a.ID);
|
||||
|
@ -103,7 +103,23 @@ namespace OpenSim.Services.AssetService
|
|||
|
||||
try
|
||||
{
|
||||
return m_Database.GetAsset(assetID);
|
||||
AssetBase asset = m_Database.GetAsset(assetID);
|
||||
|
||||
if (asset != null)
|
||||
{
|
||||
return asset;
|
||||
}
|
||||
else if (HasChainedAssetService)
|
||||
{
|
||||
asset = m_ChainedAssetService.Get(id);
|
||||
|
||||
if (asset != null)
|
||||
MigrateFromChainedService(asset);
|
||||
|
||||
return asset;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
@ -120,30 +136,25 @@ namespace OpenSim.Services.AssetService
|
|||
public virtual AssetMetadata GetMetadata(string id)
|
||||
{
|
||||
// m_log.DebugFormat("[XASSET SERVICE]: Get asset metadata for {0}", id);
|
||||
|
||||
UUID assetID;
|
||||
|
||||
if (!UUID.TryParse(id, out assetID))
|
||||
return null;
|
||||
AssetBase asset = Get(id);
|
||||
|
||||
AssetBase asset = m_Database.GetAsset(assetID);
|
||||
if (asset != null)
|
||||
return asset.Metadata;
|
||||
|
||||
return null;
|
||||
else
|
||||
return null;
|
||||
}
|
||||
|
||||
public virtual byte[] GetData(string id)
|
||||
{
|
||||
// m_log.DebugFormat("[XASSET SERVICE]: Get asset data for {0}", id);
|
||||
|
||||
UUID assetID;
|
||||
AssetBase asset = Get(id);
|
||||
|
||||
if (!UUID.TryParse(id, out assetID))
|
||||
if (asset != null)
|
||||
return asset.Data;
|
||||
else
|
||||
return null;
|
||||
|
||||
AssetBase asset = m_Database.GetAsset(assetID);
|
||||
return asset.Data;
|
||||
}
|
||||
|
||||
public virtual bool Get(string id, Object sender, AssetRetrieved handler)
|
||||
|
@ -155,7 +166,7 @@ namespace OpenSim.Services.AssetService
|
|||
if (!UUID.TryParse(id, out assetID))
|
||||
return false;
|
||||
|
||||
AssetBase asset = m_Database.GetAsset(assetID);
|
||||
AssetBase asset = Get(id);
|
||||
|
||||
//m_log.DebugFormat("[XASSET SERVICE]: Got asset {0}", asset);
|
||||
|
||||
|
@ -194,7 +205,15 @@ namespace OpenSim.Services.AssetService
|
|||
if (!UUID.TryParse(id, out assetID))
|
||||
return false;
|
||||
|
||||
// Don't bother deleting from a chained asset service. This isn't a big deal since deleting happens
|
||||
// very rarely.
|
||||
|
||||
return m_Database.Delete(id);
|
||||
}
|
||||
|
||||
private void MigrateFromChainedService(AssetBase asset)
|
||||
{
|
||||
Util.FireAndForget(o => { Store(asset); m_ChainedAssetService.Delete(asset.ID); });
|
||||
}
|
||||
}
|
||||
}
|
|
@ -27,9 +27,11 @@
|
|||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using log4net;
|
||||
using Nini.Config;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Data;
|
||||
using OpenSim.Server.Base;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using OpenSim.Services.Base;
|
||||
|
||||
|
@ -37,10 +39,15 @@ namespace OpenSim.Services.AssetService
|
|||
{
|
||||
public class XAssetServiceBase : ServiceBase
|
||||
{
|
||||
protected IXAssetDataPlugin m_Database = null;
|
||||
protected IAssetLoader m_AssetLoader = null;
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
public XAssetServiceBase(IConfigSource config) : base(config)
|
||||
protected IXAssetDataPlugin m_Database;
|
||||
protected IAssetLoader m_AssetLoader;
|
||||
protected IAssetService m_ChainedAssetService;
|
||||
|
||||
protected bool HasChainedAssetService { get { return m_ChainedAssetService != null; } }
|
||||
|
||||
public XAssetServiceBase(IConfigSource config, string configName) : base(config)
|
||||
{
|
||||
string dllName = String.Empty;
|
||||
string connString = String.Empty;
|
||||
|
@ -48,7 +55,7 @@ namespace OpenSim.Services.AssetService
|
|||
//
|
||||
// Try reading the [AssetService] section first, if it exists
|
||||
//
|
||||
IConfig assetConfig = config.Configs["AssetService"];
|
||||
IConfig assetConfig = config.Configs[configName];
|
||||
if (assetConfig != null)
|
||||
{
|
||||
dllName = assetConfig.GetString("StorageProvider", dllName);
|
||||
|
@ -77,17 +84,35 @@ namespace OpenSim.Services.AssetService
|
|||
if (m_Database == null)
|
||||
throw new Exception("Could not find a storage interface in the given module");
|
||||
|
||||
string chainedAssetServiceDesignator = assetConfig.GetString("ChainedServiceModule", null);
|
||||
|
||||
if (chainedAssetServiceDesignator != null)
|
||||
{
|
||||
m_log.InfoFormat(
|
||||
"[XASSET SERVICE BASE]: Loading chained asset service from {0}", chainedAssetServiceDesignator);
|
||||
|
||||
Object[] args = new Object[] { config, configName };
|
||||
m_ChainedAssetService = ServerUtils.LoadPlugin<IAssetService>(chainedAssetServiceDesignator, args);
|
||||
|
||||
if (!HasChainedAssetService)
|
||||
throw new Exception(
|
||||
String.Format("Failed to load ChainedAssetService from {0}", chainedAssetServiceDesignator));
|
||||
}
|
||||
|
||||
m_Database.Initialise(connString);
|
||||
|
||||
string loaderName = assetConfig.GetString("DefaultAssetLoader",
|
||||
String.Empty);
|
||||
|
||||
if (loaderName != String.Empty)
|
||||
if (HasChainedAssetService)
|
||||
{
|
||||
m_AssetLoader = LoadPlugin<IAssetLoader>(loaderName);
|
||||
string loaderName = assetConfig.GetString("DefaultAssetLoader",
|
||||
String.Empty);
|
||||
|
||||
if (m_AssetLoader == null)
|
||||
throw new Exception("Asset loader could not be loaded");
|
||||
if (loaderName != String.Empty)
|
||||
{
|
||||
m_AssetLoader = LoadPlugin<IAssetLoader>(loaderName);
|
||||
|
||||
if (m_AssetLoader == null)
|
||||
throw new Exception("Asset loader could not be loaded");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,8 @@ namespace OpenSim.Tests.Common.Mock
|
|||
public List<ImagePacketPacket> SentImagePacketPackets { get; private set; }
|
||||
public List<ImageNotInDatabasePacket> SentImageNotInDatabasePackets { get; private set; }
|
||||
|
||||
public event Action<RegionInfo, Vector3, Vector3> OnReceivedMoveAgentIntoRegion;
|
||||
|
||||
// disable warning: public events, part of the public API
|
||||
#pragma warning disable 67
|
||||
|
||||
|
@ -566,6 +568,8 @@ namespace OpenSim.Tests.Common.Mock
|
|||
|
||||
public virtual void MoveAgentIntoRegion(RegionInfo regInfo, Vector3 pos, Vector3 look)
|
||||
{
|
||||
if (OnReceivedMoveAgentIntoRegion != null)
|
||||
OnReceivedMoveAgentIntoRegion(regInfo, pos, look);
|
||||
}
|
||||
|
||||
public virtual AgentCircuitData RequestClientInfo()
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
public ILandObject GetLandObject(Vector3 position)
|
||||
{
|
||||
return GetLandObject(position.X, position.Y);
|
||||
}
|
||||
|
||||
public ILandObject GetLandObject(int x, int y)
|
||||
{
|
||||
return GetNoLand();
|
||||
|
|
Binary file not shown.
Binary file not shown.
|
@ -1669,6 +1669,65 @@
|
|||
A header have been received.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:HttpServer.LocklessQueue`1">
|
||||
<summary>
|
||||
A thread-safe lockless queue that supports multiple readers and
|
||||
multiple writers
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:HttpServer.LocklessQueue`1.head">
|
||||
<summary>Queue head</summary>
|
||||
</member>
|
||||
<member name="F:HttpServer.LocklessQueue`1.tail">
|
||||
<summary>Queue tail</summary>
|
||||
</member>
|
||||
<member name="F:HttpServer.LocklessQueue`1.count">
|
||||
<summary>Queue item count</summary>
|
||||
</member>
|
||||
<member name="M:HttpServer.LocklessQueue`1.#ctor">
|
||||
<summary>
|
||||
Constructor
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:HttpServer.LocklessQueue`1.Enqueue(`0)">
|
||||
<summary>
|
||||
Enqueue an item
|
||||
</summary>
|
||||
<param name="item">Item to enqeue</param>
|
||||
</member>
|
||||
<member name="M:HttpServer.LocklessQueue`1.TryDequeue(`0@)">
|
||||
<summary>
|
||||
Try to dequeue an item
|
||||
</summary>
|
||||
<param name="item">Dequeued item if the dequeue was successful</param>
|
||||
<returns>True if an item was successfully deqeued, otherwise false</returns>
|
||||
</member>
|
||||
<member name="P:HttpServer.LocklessQueue`1.Count">
|
||||
<summary>Gets the current number of items in the queue. Since this
|
||||
is a lockless collection this value should be treated as a close
|
||||
estimate</summary>
|
||||
</member>
|
||||
<member name="T:HttpServer.LocklessQueue`1.SingleLinkNode">
|
||||
<summary>
|
||||
Provides a node container for data in a singly linked list
|
||||
</summary>
|
||||
</member>
|
||||
<member name="F:HttpServer.LocklessQueue`1.SingleLinkNode.Next">
|
||||
<summary>Pointer to the next node in list</summary>
|
||||
</member>
|
||||
<member name="F:HttpServer.LocklessQueue`1.SingleLinkNode.Item">
|
||||
<summary>The data contained by the node</summary>
|
||||
</member>
|
||||
<member name="M:HttpServer.LocklessQueue`1.SingleLinkNode.#ctor">
|
||||
<summary>
|
||||
Constructor
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:HttpServer.LocklessQueue`1.SingleLinkNode.#ctor(`0)">
|
||||
<summary>
|
||||
Constructor
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:HttpServer.IHttpRequest">
|
||||
<summary>
|
||||
Contains server side HTTP request information.
|
||||
|
@ -2825,6 +2884,11 @@
|
|||
<param name="protocol">Kind of HTTPS protocol. Usually TLS or SSL.</param>
|
||||
<returns>A created <see cref="T:HttpServer.IHttpClientContext"/>.</returns>
|
||||
</member>
|
||||
<member name="M:HttpServer.IHttpContextFactory.Shutdown">
|
||||
<summary>
|
||||
Server is shutting down so shut down the factory
|
||||
</summary>
|
||||
</member>
|
||||
<member name="E:HttpServer.IHttpContextFactory.RequestReceived">
|
||||
<summary>
|
||||
A request have been received from one of the contexts.
|
||||
|
@ -2876,6 +2940,11 @@
|
|||
A creates <see cref="T:HttpServer.IHttpClientContext"/>.
|
||||
</returns>
|
||||
</member>
|
||||
<member name="M:HttpServer.HttpContextFactory.Shutdown">
|
||||
<summary>
|
||||
Server is shutting down so shut down the factory
|
||||
</summary>
|
||||
</member>
|
||||
<member name="P:HttpServer.HttpContextFactory.UseTraceLogs">
|
||||
<summary>
|
||||
True if detailed trace logs should be written.
|
||||
|
@ -4315,6 +4384,58 @@
|
|||
</summary>
|
||||
<param name="message">message describing the error</param>
|
||||
</member>
|
||||
<member name="T:HttpServer.ContextTimeoutManager">
|
||||
<summary>
|
||||
Timeout Manager. Checks for dead clients. Clients with open connections that are not doing anything. Closes sessions opened with keepalive.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:HttpServer.ContextTimeoutManager.ProcessContextTimeouts">
|
||||
<summary>
|
||||
Causes the watcher to immediately check the connections.
|
||||
</summary>
|
||||
</member>
|
||||
<member name="M:HttpServer.ContextTimeoutManager.EnvironmentTickCount">
|
||||
<summary>
|
||||
Environment.TickCount is an int but it counts all 32 bits so it goes positive
|
||||
and negative every 24.9 days. This trims down TickCount so it doesn't wrap
|
||||
for the callers.
|
||||
This trims it to a 12 day interval so don't let your frame time get too long.
|
||||
</summary>
|
||||
<returns></returns>
|
||||
</member>
|
||||
<member name="M:HttpServer.ContextTimeoutManager.EnvironmentTickCountSubtract(System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Environment.TickCount is an int but it counts all 32 bits so it goes positive
|
||||
and negative every 24.9 days. Subtracts the passed value (previously fetched by
|
||||
'EnvironmentTickCount()') and accounts for any wrapping.
|
||||
</summary>
|
||||
<param name="newValue"></param>
|
||||
<param name="prevValue"></param>
|
||||
<returns>subtraction of passed prevValue from current Environment.TickCount</returns>
|
||||
</member>
|
||||
<member name="M:HttpServer.ContextTimeoutManager.EnvironmentTickCountAdd(System.Int32,System.Int32)">
|
||||
<summary>
|
||||
Environment.TickCount is an int but it counts all 32 bits so it goes positive
|
||||
and negative every 24.9 days. Subtracts the passed value (previously fetched by
|
||||
'EnvironmentTickCount()') and accounts for any wrapping.
|
||||
</summary>
|
||||
<param name="newValue"></param>
|
||||
<param name="prevValue"></param>
|
||||
<returns>subtraction of passed prevValue from current Environment.TickCount</returns>
|
||||
</member>
|
||||
<member name="M:HttpServer.ContextTimeoutManager.EnvironmentTickCountSubtract(System.Int32)">
|
||||
<summary>
|
||||
Environment.TickCount is an int but it counts all 32 bits so it goes positive
|
||||
and negative every 24.9 days. Subtracts the passed value (previously fetched by
|
||||
'EnvironmentTickCount()') and accounts for any wrapping.
|
||||
</summary>
|
||||
<returns>subtraction of passed prevValue from current Environment.TickCount</returns>
|
||||
</member>
|
||||
<member name="T:HttpServer.ContextTimeoutManager.MonitorType">
|
||||
<summary>
|
||||
Use a Thread or a Timer to monitor the ugly
|
||||
</summary>
|
||||
</member>
|
||||
<member name="T:HttpServer.Sessions.MemorySessionStore">
|
||||
<summary>
|
||||
Session store using memory for each session.
|
||||
|
|
|
@ -210,13 +210,12 @@
|
|||
;; Choose one of the physics engines below
|
||||
;# {physics} {} {Select physics engine} {OpenDynamicsEngine BulletSim basicphysics POS} OpenDynamicsEngine
|
||||
;; OpenDynamicsEngine is by some distance the most developed physics engine
|
||||
;; BulletSim is incomplete and experimental but in active development. BulletSimN is a purely C# version of BulletSim.
|
||||
;; BulletSim is experimental and in active development.
|
||||
;; basicphysics effectively does not model physics at all, making all
|
||||
;; objects phantom.
|
||||
;; Default is OpenDynamicsEngine
|
||||
; physics = OpenDynamicsEngine
|
||||
; physics = BulletSim
|
||||
; physics = BulletSimN
|
||||
; physics = basicphysics
|
||||
; physics = POS
|
||||
|
||||
|
@ -542,6 +541,13 @@
|
|||
; shout_distance = 100
|
||||
|
||||
|
||||
[EntityTransfer]
|
||||
;# {DisableInterRegionTeleportCancellation} {} {Determine whether the cancel button is shown at all during teleports.} {false true} false
|
||||
;; This option exists because cancelling at certain points can result in an unuseable session (frozen avatar, etc.)
|
||||
;; Disabling cancellation can be okay in small closed grids where all teleports are highly likely to suceed.
|
||||
;DisableInterRegionTeleportCancellation = false
|
||||
|
||||
|
||||
[Messaging]
|
||||
;# {OfflineMessageModule} {} {Module to use for offline message storage} {OfflineMessageModule "Offline Message Module V2" *}
|
||||
;; Module to handle offline messaging. The core module requires an external
|
||||
|
|
|
@ -628,6 +628,11 @@
|
|||
; Minimum user level required for HyperGrid teleports
|
||||
LevelHGTeleport = 0
|
||||
|
||||
; Determine whether the cancel button is shown at all during teleports.
|
||||
; This option exists because cancelling at certain points can result in an unuseable session (frozen avatar, etc.)
|
||||
; Disabling cancellation can be okay in small closed grids where all teleports are highly likely to suceed.
|
||||
DisableInterRegionTeleportCancellation = false
|
||||
|
||||
|
||||
[Messaging]
|
||||
; Control which region module is used for instant messaging.
|
||||
|
|
|
@ -26,12 +26,12 @@
|
|||
; Set path to directory for plugin registry. Information
|
||||
; about the registered repositories and installed plugins
|
||||
; will be stored here
|
||||
; The Robust.exe process must hvae R/W access to the location
|
||||
; The Robust.exe process must have R/W access to the location
|
||||
RegistryLocation = "."
|
||||
|
||||
; Modular configurations
|
||||
; Set path to directory for modular ini files...
|
||||
; The Robust.exe process must hvae R/W access to the location
|
||||
; The Robust.exe process must have R/W access to the location
|
||||
ConfigDirectory = "/home/opensim/etc/Configs"
|
||||
|
||||
[ServiceList]
|
||||
|
@ -171,7 +171,7 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
|
|||
;; Allow Hyperlinks to be created at the console
|
||||
HypergridLinker = true
|
||||
|
||||
;; If you have this set under [Startup], no need to set it here, leave it commented
|
||||
;; If you have this set under [Hypergrid], no need to set it here, leave it commented
|
||||
; GatekeeperURI = "http://127.0.0.1:8002"
|
||||
|
||||
|
||||
|
@ -326,7 +326,7 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
|
|||
; HasProxy = false
|
||||
|
||||
; Defaults for the users, if none is specified in the useraccounts table entry (ServiceURLs)
|
||||
;; If you have Gatekeeper set under [Startup], no need to set it here, leave it commented
|
||||
;; If you have GatekeeperURI set under [Hypergrid], no need to set it here, leave it commented
|
||||
; GatekeeperURI = "http://127.0.0.1:8002"
|
||||
|
||||
SRV_HomeURI = "http://127.0.0.1:8002"
|
||||
|
@ -436,7 +436,7 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
|
|||
AuthenticationService = "OpenSim.Services.Connectors.dll:AuthenticationServicesConnector"
|
||||
SimulationService ="OpenSim.Services.Connectors.dll:SimulationServiceConnector"
|
||||
; how does the outside world reach me? This acts as public key too.
|
||||
;; If you have GatekeeperURI set under [Startup], no need to set it here, leave it commented
|
||||
;; If you have GatekeeperURI set under [Hypergrid], no need to set it here, leave it commented
|
||||
; ExternalName = "http://127.0.0.1:8002"
|
||||
|
||||
; Does this grid allow incoming links to any region in it?
|
||||
|
@ -531,7 +531,7 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
|
|||
UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
|
||||
AvatarService = "OpenSim.Services.AvatarService.dll:AvatarService"
|
||||
|
||||
;; Can overwrite the default in [Startup], but probably shouldn't
|
||||
;; Can overwrite the default in [Hypergrid], but probably shouldn't
|
||||
; HomeURI = "http://127.0.0.1:8002"
|
||||
|
||||
; * The interface that local users get when they are in other grids.
|
||||
|
@ -542,7 +542,7 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
|
|||
LocalServiceModule = "OpenSim.Services.HypergridService.dll:HGAssetService"
|
||||
UserAccountsService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
|
||||
|
||||
;; Can overwrite the default in [Startup], but probably shouldn't
|
||||
;; Can overwrite the default in [Hypergrid], but probably shouldn't
|
||||
; HomeURI = "http://127.0.0.1:8002"
|
||||
|
||||
;; The asset types that this grid can export to / import from other grids.
|
||||
|
@ -583,7 +583,7 @@ HGAssetServiceConnector = "HGAssetService@8002/OpenSim.Server.Handlers.dll:Asset
|
|||
UserAccountService = "OpenSim.Services.UserAccountService.dll:UserAccountService"
|
||||
|
||||
;; What is the HomeURI of users associated with this grid?
|
||||
;; Can overwrite the default in [Startup], but probably shouldn't
|
||||
;; Can overwrite the default in [Hypergrid], but probably shouldn't
|
||||
; HomeURI = "http://127.0.0.1:8002"
|
||||
|
||||
|
||||
|
|
117
prebuild.xml
117
prebuild.xml
|
@ -899,6 +899,7 @@
|
|||
<Reference name="OpenSim.Framework"/>
|
||||
<Reference name="OpenSim.Framework.Console"/>
|
||||
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
|
||||
<Reference name="OpenSim.Server.Base"/>
|
||||
<Reference name="OpenSim.Services.Interfaces"/>
|
||||
<Reference name="OpenSim.Services.Base"/>
|
||||
<Reference name="OpenSim.Services.Connectors"/>
|
||||
|
@ -1913,121 +1914,6 @@
|
|||
</Files>
|
||||
</Project>
|
||||
|
||||
<!-- REST plugins -->
|
||||
<Project frameworkVersion="v3_5" name="OpenSim.ApplicationPlugins.Rest" path="OpenSim/ApplicationPlugins/Rest" type="Library">
|
||||
<Configuration name="Debug">
|
||||
<Options>
|
||||
<OutputPath>../../../bin/</OutputPath>
|
||||
</Options>
|
||||
</Configuration>
|
||||
<Configuration name="Release">
|
||||
<Options>
|
||||
<OutputPath>../../../bin/</OutputPath>
|
||||
</Options>
|
||||
</Configuration>
|
||||
|
||||
<ReferencePath>../../../bin/</ReferencePath>
|
||||
<Reference name="Mono.Addins" path="../../../bin/"/>
|
||||
<Reference name="System"/>
|
||||
<Reference name="System.Xml"/>
|
||||
<Reference name="OpenMetaverseTypes" path="../../../bin/"/>
|
||||
<Reference name="Nini" path="../../../bin/"/>
|
||||
<Reference name="XMLRPC" path="../../../bin/"/>
|
||||
<Reference name="OpenSim"/>
|
||||
<Reference name="OpenSim.Region.ClientStack"/>
|
||||
<Reference name="OpenSim.Region.Framework"/>
|
||||
<Reference name="OpenSim.Region.CoreModules"/>
|
||||
<Reference name="OpenSim.Framework.Communications"/>
|
||||
<Reference name="OpenSim.Framework"/>
|
||||
<Reference name="OpenSim.Framework.Servers"/>
|
||||
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
|
||||
<Reference name="OpenSim.Framework.Console"/>
|
||||
<Reference name="log4net" path="../../../bin/"/>
|
||||
|
||||
<Files>
|
||||
<Match pattern="*.cs" recurse="false"/>
|
||||
</Files>
|
||||
</Project>
|
||||
|
||||
<Project frameworkVersion="v3_5" name="OpenSim.ApplicationPlugins.Rest.Regions" path="OpenSim/ApplicationPlugins/Rest/Regions" type="Library">
|
||||
<Configuration name="Debug">
|
||||
<Options>
|
||||
<OutputPath>../../../../bin/</OutputPath>
|
||||
</Options>
|
||||
</Configuration>
|
||||
<Configuration name="Release">
|
||||
<Options>
|
||||
<OutputPath>../../../../bin/</OutputPath>
|
||||
</Options>
|
||||
</Configuration>
|
||||
|
||||
<ReferencePath>../../../../bin/</ReferencePath>
|
||||
<Reference name="Mono.Addins" path="../../../../bin/"/>
|
||||
<Reference name="System"/>
|
||||
<Reference name="System.Xml"/>
|
||||
<Reference name="OpenMetaverseTypes" path="../../../../bin/"/>
|
||||
<Reference name="Nini" path="../../../../bin/"/>
|
||||
<Reference name="XMLRPC" path="../../../../bin/"/>
|
||||
<Reference name="OpenSim"/>
|
||||
<Reference name="OpenSim.Region.Framework"/>
|
||||
<Reference name="OpenSim.Region.ClientStack"/>
|
||||
<Reference name="OpenSim.Region.CoreModules"/>
|
||||
<Reference name="OpenSim.Framework.Communications"/>
|
||||
<Reference name="OpenSim.Framework"/>
|
||||
<Reference name="OpenSim.Framework.Servers"/>
|
||||
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
|
||||
<Reference name="OpenSim.Framework.Console"/>
|
||||
<Reference name="OpenSim.ApplicationPlugins.Rest"/>
|
||||
<Reference name="log4net" path="../../../../bin/"/>
|
||||
|
||||
<Files>
|
||||
<Match pattern="*.cs" recurse="true"/>
|
||||
<Match buildAction="EmbeddedResource" path="Resources" pattern="*.addin.xml" recurse="true"/>
|
||||
</Files>
|
||||
</Project>
|
||||
|
||||
<Project frameworkVersion="v3_5" name="OpenSim.ApplicationPlugins.Rest.Inventory" path="OpenSim/ApplicationPlugins/Rest/Inventory" type="Library">
|
||||
<Configuration name="Debug">
|
||||
<Options>
|
||||
<OutputPath>../../../../bin/</OutputPath>
|
||||
</Options>
|
||||
</Configuration>
|
||||
<Configuration name="Release">
|
||||
<Options>
|
||||
<OutputPath>../../../../bin/</OutputPath>
|
||||
</Options>
|
||||
</Configuration>
|
||||
|
||||
<ReferencePath>../../../../bin/</ReferencePath>
|
||||
<Reference name="Mono.Addins" path="../../../../bin/"/>
|
||||
<Reference name="System"/>
|
||||
<Reference name="System.Xml"/>
|
||||
<Reference name="System.Drawing"/>
|
||||
<Reference name="OpenMetaverseTypes" path="../../../../bin/"/>
|
||||
<Reference name="OpenMetaverse" path="../../../../bin/"/>
|
||||
<Reference name="Nini" path="../../../../bin/"/>
|
||||
<Reference name="XMLRPC" path="../../../../bin/"/>
|
||||
<Reference name="OpenSim"/>
|
||||
<Reference name="OpenSim.Region.Framework"/>
|
||||
<Reference name="OpenSim.Region.ClientStack"/>
|
||||
<Reference name="OpenSim.Region.CoreModules"/>
|
||||
<Reference name="OpenSim.Framework.Communications"/>
|
||||
<Reference name="OpenSim.Framework"/>
|
||||
<Reference name="OpenSim.Framework.Servers"/>
|
||||
<Reference name="OpenSim.Framework.Servers.HttpServer"/>
|
||||
<Reference name="OpenSim.Framework.Console"/>
|
||||
<Reference name="OpenSim.Services.Interfaces"/>
|
||||
<Reference name="OpenSim.ApplicationPlugins.Rest"/>
|
||||
<Reference name="log4net" path="../../../../bin/"/>
|
||||
|
||||
<Files>
|
||||
<Match pattern="*.cs" recurse="true"/>
|
||||
<Match buildAction="EmbeddedResource" path="Resources" pattern="*.addin.xml" recurse="true"/>
|
||||
</Files>
|
||||
</Project>
|
||||
|
||||
<!-- /REST plugins -->
|
||||
|
||||
<!-- Scene Server API Example Apps -->
|
||||
|
||||
<Project frameworkVersion="v3_5" name="OpenSim.Region.DataSnapshot" path="OpenSim/Region/DataSnapshot" type="Library">
|
||||
|
@ -2833,6 +2719,7 @@
|
|||
<Reference name="Nini" path="../../../bin/"/>
|
||||
<Reference name="nunit.framework" path="../../../bin/"/>
|
||||
<Reference name="OpenMetaverse" path="../../../bin/"/>
|
||||
<Reference name="OpenMetaverse.StructuredData" path="../../../bin/"/>
|
||||
<Reference name="OpenMetaverseTypes" path="../../../bin/"/>
|
||||
<Reference name="OpenSim.Data"/>
|
||||
<Reference name="OpenSim.Data.Null"/>
|
||||
|
|
Loading…
Reference in New Issue