Merge branch 'master' into httptests

httptests
UbitUmarov 2017-11-12 03:18:02 +00:00
commit ca4804b758
8 changed files with 391 additions and 54 deletions

View File

@ -114,7 +114,6 @@ namespace OpenSim.OfflineIM
scene.ForEachClient(delegate(IClientAPI client) scene.ForEachClient(delegate(IClientAPI client)
{ {
client.OnRetrieveInstantMessages -= RetrieveInstantMessages; client.OnRetrieveInstantMessages -= RetrieveInstantMessages;
client.OnMuteListRequest -= OnMuteListRequest;
}); });
} }
@ -162,7 +161,6 @@ namespace OpenSim.OfflineIM
private void OnNewClient(IClientAPI client) private void OnNewClient(IClientAPI client)
{ {
client.OnRetrieveInstantMessages += RetrieveInstantMessages; client.OnRetrieveInstantMessages += RetrieveInstantMessages;
client.OnMuteListRequest += OnMuteListRequest;
} }
private void RetrieveInstantMessages(IClientAPI client) private void RetrieveInstantMessages(IClientAPI client)
@ -194,20 +192,6 @@ namespace OpenSim.OfflineIM
} }
} }
// Apparently this is needed in order for the viewer to request the IMs.
private void OnMuteListRequest(IClientAPI client, uint crc)
{
m_log.DebugFormat("[OfflineIM.V2] Got mute list request for crc {0}", crc);
string filename = "mutes" + client.AgentId.ToString();
IXfer xfer = client.Scene.RequestModuleInterface<IXfer>();
if (xfer != null)
{
xfer.AddNewFile(filename, new Byte[0]);
client.SendMuteListUpdate(filename);
}
}
private void UndeliveredMessage(GridInstantMessage im) private void UndeliveredMessage(GridInstantMessage im)
{ {
if (im.dialog != (byte)InstantMessageDialog.MessageFromObject && if (im.dialog != (byte)InstantMessageDialog.MessageFromObject &&

View File

@ -0,0 +1,316 @@
/*
* 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.Reflection;
using System.Collections.Generic;
using System.Data;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using log4net;
using OpenMetaverse;
using Npgsql;
using NpgsqlTypes;
namespace OpenSim.Data.PGSQL
{
public class PGSQLFSAssetData : IFSAssetDataPlugin
{
private const string _migrationStore = "FSAssetStore";
private static string m_Table = "fsassets";
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private long m_ticksToEpoch;
private PGSQLManager m_database;
private string m_connectionString;
public PGSQLFSAssetData()
{
}
public void Initialise(string connect, string realm, int UpdateAccessTime)
{
DaysBetweenAccessTimeUpdates = UpdateAccessTime;
m_ticksToEpoch = new System.DateTime(1970, 1, 1).Ticks;
m_connectionString = connect;
m_database = new PGSQLManager(m_connectionString);
//New migration to check for DB changes
m_database.CheckMigration(_migrationStore);
}
public void Initialise()
{
throw new NotImplementedException();
}
/// <summary>
/// Number of days that must pass before we update the access time on an asset when it has been fetched
/// Config option to change this is "DaysBetweenAccessTimeUpdates"
/// </summary>
private int DaysBetweenAccessTimeUpdates = 0;
protected virtual Assembly Assembly
{
get { return GetType().Assembly; }
}
#region IPlugin Members
public string Version { get { return "1.0.0.0"; } }
public void Dispose() { }
public string Name
{
get { return "PGSQL FSAsset storage engine"; }
}
#endregion
#region IFSAssetDataPlugin Members
public AssetMetadata Get(string id, out string hash)
{
hash = String.Empty;
AssetMetadata meta = null;
UUID uuid = new UUID(id);
string query = String.Format("select \"id\", \"type\", \"hash\", \"create_time\", \"access_time\", \"asset_flags\" from {0} where \"id\" = :id", m_Table);
using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon))
{
dbcon.Open();
cmd.Parameters.Add(m_database.CreateParameter("id", uuid));
using (NpgsqlDataReader reader = cmd.ExecuteReader(CommandBehavior.Default))
{
if (reader.Read())
{
meta = new AssetMetadata();
hash = reader["hash"].ToString();
meta.ID = id;
meta.FullID = uuid;
meta.Name = String.Empty;
meta.Description = String.Empty;
meta.Type = (sbyte)Convert.ToInt32(reader["type"]);
meta.ContentType = SLUtil.SLAssetTypeToContentType(meta.Type);
meta.CreationDate = Util.ToDateTime(Convert.ToInt32(reader["create_time"]));
meta.Flags = (AssetFlags)Convert.ToInt32(reader["asset_flags"]);
int atime = Convert.ToInt32(reader["access_time"]);
UpdateAccessTime(atime, uuid);
}
}
}
return meta;
}
private void UpdateAccessTime(int AccessTime, UUID id)
{
// Reduce DB work by only updating access time if asset hasn't recently been accessed
// 0 By Default, Config option is "DaysBetweenAccessTimeUpdates"
if (DaysBetweenAccessTimeUpdates > 0 && (DateTime.UtcNow - Utils.UnixTimeToDateTime(AccessTime)).TotalDays < DaysBetweenAccessTimeUpdates)
return;
string query = String.Format("UPDATE {0} SET \"access_time\" = :access_time WHERE \"id\" = :id", m_Table);
using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon))
{
dbcon.Open();
int now = (int)((System.DateTime.Now.Ticks - m_ticksToEpoch) / 10000000);
cmd.Parameters.Add(m_database.CreateParameter("id", id));
cmd.Parameters.Add(m_database.CreateParameter("access_time", now));
cmd.ExecuteNonQuery();
}
}
public bool Store(AssetMetadata meta, string hash)
{
try
{
bool found = false;
string oldhash;
AssetMetadata existingAsset = Get(meta.ID, out oldhash);
string query = String.Format("UPDATE {0} SET \"access_time\" = :access_time WHERE \"id\" = :id", m_Table);
if (existingAsset == null)
{
query = String.Format("insert into {0} (\"id\", \"type\", \"hash\", \"asset_flags\", \"create_time\", \"access_time\") values ( :id, :type, :hash, :asset_flags, :create_time, :access_time)", m_Table);
found = true;
}
using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon))
{
dbcon.Open();
int now = (int)((System.DateTime.Now.Ticks - m_ticksToEpoch) / 10000000);
cmd.Parameters.Add(m_database.CreateParameter("id", meta.FullID));
cmd.Parameters.Add(m_database.CreateParameter("type", meta.Type));
cmd.Parameters.Add(m_database.CreateParameter("hash", hash));
cmd.Parameters.Add(m_database.CreateParameter("asset_flags", Convert.ToInt32(meta.Flags)));
cmd.Parameters.Add(m_database.CreateParameter("create_time", now));
cmd.Parameters.Add(m_database.CreateParameter("access_time", now));
cmd.ExecuteNonQuery();
}
return found;
}
catch(Exception e)
{
m_log.Error("[PGSQL FSASSETS] Failed to store asset with ID " + meta.ID);
m_log.Error(e.ToString());
return false;
}
}
/// <summary>
/// Check if the assets exist in the database.
/// </summary>
/// <param name="uuids">The asset UUID's</param>
/// <returns>For each asset: true if it exists, false otherwise</returns>
public bool[] AssetsExist(UUID[] uuids)
{
if (uuids.Length == 0)
return new bool[0];
HashSet<UUID> exists = new HashSet<UUID>();
string ids = "'" + string.Join("','", uuids) + "'";
string query = string.Format("select \"id\" from {1} where id in ({0})", ids, m_Table);
using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon))
{
dbcon.Open();
using (NpgsqlDataReader reader = cmd.ExecuteReader(CommandBehavior.Default))
{
while (reader.Read())
{
UUID id = DBGuid.FromDB(reader["id"]);;
exists.Add(id);
}
}
}
bool[] results = new bool[uuids.Length];
for (int i = 0; i < uuids.Length; i++)
results[i] = exists.Contains(uuids[i]);
return results;
}
public int Count()
{
int count = 0;
string query = String.Format("select count(*) as count from {0}", m_Table);
using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon))
{
dbcon.Open();
IDataReader reader = cmd.ExecuteReader();
reader.Read();
count = Convert.ToInt32(reader["count"]);
reader.Close();
}
return count;
}
public bool Delete(string id)
{
string query = String.Format("delete from {0} where \"id\" = :id", m_Table);
using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(query, dbcon))
{
dbcon.Open();
cmd.Parameters.Add(m_database.CreateParameter("id", new UUID(id)));
cmd.ExecuteNonQuery();
}
return true;
}
public void Import(string conn, string table, int start, int count, bool force, FSStoreDelegate store)
{
int imported = 0;
string limit = String.Empty;
if(count != -1)
{
limit = String.Format(" limit {0} offset {1}", start, count);
}
string query = String.Format("select * from {0}{1}", table, limit);
try
{
using (NpgsqlConnection remote = new NpgsqlConnection(conn))
using (NpgsqlCommand cmd = new NpgsqlCommand(query, remote))
{
remote.Open();
MainConsole.Instance.Output("Querying database");
MainConsole.Instance.Output("Reading data");
using (NpgsqlDataReader reader = cmd.ExecuteReader(CommandBehavior.Default))
{
while (reader.Read())
{
if ((imported % 100) == 0)
{
MainConsole.Instance.Output(String.Format("{0} assets imported so far", imported));
}
AssetBase asset = new AssetBase();
AssetMetadata meta = new AssetMetadata();
meta.ID = reader["id"].ToString();
meta.FullID = new UUID(meta.ID);
meta.Name = String.Empty;
meta.Description = String.Empty;
meta.Type = (sbyte)Convert.ToInt32(reader["assetType"]);
meta.ContentType = SLUtil.SLAssetTypeToContentType(meta.Type);
meta.CreationDate = Util.ToDateTime(Convert.ToInt32(reader["create_time"]));
asset.Metadata = meta;
asset.Data = (byte[])reader["data"];
store(asset, force);
imported++;
}
}
}
}
catch (Exception e)
{
m_log.ErrorFormat("[PGSQL FSASSETS]: Error importing assets: {0}",
e.Message.ToString());
return;
}
MainConsole.Instance.Output(String.Format("Import done, {0} assets imported", imported));
}
#endregion
}
}

View File

@ -0,0 +1,14 @@
:VERSION 1
BEGIN TRANSACTION;
CREATE TABLE fsassets (
"id" uuid NOT NULL PRIMARY KEY,
"type" integer NOT NULL,
"hash" char(64) NOT NULL,
"create_time" integer NOT NULL DEFAULT '0',
"access_time" integer NOT NULL DEFAULT '0',
"asset_flags" integer NOT NULL DEFAULT '0'
);
COMMIT;

View File

@ -1209,10 +1209,10 @@ namespace OpenSim.Region.Framework.Scenes
if (group.GetInventoryItem(localID, itemID) != null) if (group.GetInventoryItem(localID, itemID) != null)
{ {
if (item.Type == 10) if (item.Type == (int)InventoryType.LSL)
{ {
part.RemoveScriptEvents(itemID); part.RemoveScriptEvents(itemID);
EventManager.TriggerRemoveScript(localID, itemID); part.ParentGroup.AddActiveScriptCount(-1);
} }
group.RemoveInventoryItem(localID, itemID); group.RemoveInventoryItem(localID, itemID);
@ -1317,7 +1317,7 @@ namespace OpenSim.Region.Framework.Scenes
if (taskItem.Type == (int)AssetType.LSLText) if (taskItem.Type == (int)AssetType.LSLText)
{ {
part.RemoveScriptEvents(itemId); part.RemoveScriptEvents(itemId);
EventManager.TriggerRemoveScript(part.LocalId, itemId); part.ParentGroup.AddActiveScriptCount(-1);
} }
part.Inventory.RemoveInventoryItem(itemId); part.Inventory.RemoveInventoryItem(itemId);

View File

@ -358,7 +358,7 @@ namespace OpenSim.Region.Framework.Scenes
SceneObjectPart part = parts[i]; SceneObjectPart part = parts[i];
if(m_DeepEffectivePermsInvalid) if(m_DeepEffectivePermsInvalid)
part.AggregateInnerPerms(); part.AggregatedInnerPermsForGroup();
owner &= part.AggregatedInnerOwnerPerms; owner &= part.AggregatedInnerOwnerPerms;
group &= part.AggregatedInnerGroupPerms; group &= part.AggregatedInnerGroupPerms;

View File

@ -2579,8 +2579,30 @@ namespace OpenSim.Region.Framework.Scenes
AggregatedInnerOwnerPerms = owner & mask; AggregatedInnerOwnerPerms = owner & mask;
AggregatedInnerGroupPerms = group & mask; AggregatedInnerGroupPerms = group & mask;
AggregatedInnerEveryonePerms = everyone & mask; AggregatedInnerEveryonePerms = everyone & mask;
if(ParentGroup != null) }
ParentGroup.InvalidateEffectivePerms(); if(ParentGroup != null)
ParentGroup.InvalidateEffectivePerms();
}
// same as above but called during group Effective Permission validation
public void AggregatedInnerPermsForGroup()
{
// assuming child prims permissions masks are irrelevant on a linkset
// root part is handle at SOG since its masks are the sog masks
const uint mask = (uint)PermissionMask.AllEffective;
uint owner = mask;
uint group = mask;
uint everyone = mask;
lock(InnerPermsLock) // do we really need this?
{
if(Inventory != null)
Inventory.AggregateInnerPerms(ref owner, ref group, ref everyone);
AggregatedInnerOwnerPerms = owner & mask;
AggregatedInnerGroupPerms = group & mask;
AggregatedInnerEveryonePerms = everyone & mask;
} }
} }
@ -3817,7 +3839,8 @@ namespace OpenSim.Region.Framework.Scenes
Byte[] buf = Shape.Textures.GetBytes(); Byte[] buf = Shape.Textures.GetBytes();
Primitive.TextureEntry tex = new Primitive.TextureEntry(buf, 0, buf.Length); Primitive.TextureEntry tex = new Primitive.TextureEntry(buf, 0, buf.Length);
Color4 texcolor; Color4 texcolor;
if (face >= 0 && face < GetNumberOfSides()) int nsides = GetNumberOfSides();
if (face >= 0 && face < nsides)
{ {
texcolor = tex.CreateFace((uint)face).RGBA; texcolor = tex.CreateFace((uint)face).RGBA;
texcolor.R = clippedColor.X; texcolor.R = clippedColor.X;
@ -3833,7 +3856,7 @@ namespace OpenSim.Region.Framework.Scenes
} }
else if (face == ALL_SIDES) else if (face == ALL_SIDES)
{ {
for (uint i = 0; i < GetNumberOfSides(); i++) for (uint i = 0; i < nsides; i++)
{ {
if (tex.FaceTextures[i] != null) if (tex.FaceTextures[i] != null)
{ {
@ -5138,20 +5161,20 @@ namespace OpenSim.Region.Framework.Scenes
Changed changeFlags = 0; Changed changeFlags = 0;
Primitive.TextureEntryFace fallbackNewFace = newTex.DefaultTexture; Primitive.TextureEntryFace defaultNewFace = newTex.DefaultTexture;
Primitive.TextureEntryFace fallbackOldFace = oldTex.DefaultTexture; Primitive.TextureEntryFace defaultOldFace = oldTex.DefaultTexture;
// On Incoming packets, sometimes newText.DefaultTexture is null. The assumption is that all // 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. // other prim-sides are set, but apparently that's not always the case. Lets assume packet/data corruption at this point.
if (fallbackNewFace == null) if (defaultNewFace == null)
{ {
fallbackNewFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0); defaultNewFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0);
newTex.DefaultTexture = fallbackNewFace; newTex.DefaultTexture = defaultNewFace;
} }
if (fallbackOldFace == null) if (defaultOldFace == null)
{ {
fallbackOldFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0); defaultOldFace = new Primitive.TextureEntry(Util.BLANK_TEXTURE_UUID).CreateFace(0);
oldTex.DefaultTexture = fallbackOldFace; oldTex.DefaultTexture = defaultOldFace;
} }
// Materials capable viewers can send a ObjectImage packet // Materials capable viewers can send a ObjectImage packet
@ -5161,13 +5184,11 @@ namespace OpenSim.Region.Framework.Scenes
// we should ignore any changes and not update Shape.TextureEntry // we should ignore any changes and not update Shape.TextureEntry
bool otherFieldsChanged = false; bool otherFieldsChanged = false;
int nsides = GetNumberOfSides();
for (int i = 0 ; i < GetNumberOfSides(); i++) for (int i = 0 ; i < nsides; i++)
{ {
Primitive.TextureEntryFace newFace = defaultNewFace;
Primitive.TextureEntryFace newFace = newTex.DefaultTexture; Primitive.TextureEntryFace oldFace = defaultOldFace;
Primitive.TextureEntryFace oldFace = oldTex.DefaultTexture;
if (oldTex.FaceTextures[i] != null) if (oldTex.FaceTextures[i] != null)
oldFace = oldTex.FaceTextures[i]; oldFace = oldTex.FaceTextures[i];
if (newTex.FaceTextures[i] != null) if (newTex.FaceTextures[i] != null)
@ -5202,17 +5223,17 @@ namespace OpenSim.Region.Framework.Scenes
if (oldFace.Rotation != newFace.Rotation) otherFieldsChanged = true; if (oldFace.Rotation != newFace.Rotation) otherFieldsChanged = true;
if (oldFace.Shiny != newFace.Shiny) otherFieldsChanged = true; if (oldFace.Shiny != newFace.Shiny) otherFieldsChanged = true;
if (oldFace.TexMapType != newFace.TexMapType) otherFieldsChanged = true; if (oldFace.TexMapType != newFace.TexMapType) otherFieldsChanged = true;
if(otherFieldsChanged)
changeFlags |= Changed.TEXTURE;
} }
} }
if (changeFlags != 0 || otherFieldsChanged) if (changeFlags == 0)
{ return;
m_shape.TextureEntry = newTex.GetBytes(); m_shape.TextureEntry = newTex.GetBytes();
if (changeFlags != 0) TriggerScriptChangedEvent(changeFlags);
TriggerScriptChangedEvent(changeFlags); ParentGroup.HasGroupChanged = true;
ParentGroup.HasGroupChanged = true; ScheduleFullUpdate();
ScheduleFullUpdate();
}
} }
internal void UpdatePhysicsSubscribedEvents() internal void UpdatePhysicsSubscribedEvents()

View File

@ -1081,7 +1081,7 @@ namespace OpenSim.Region.Framework.Scenes
{ {
int type = m_items[itemID].InvType; int type = m_items[itemID].InvType;
m_items.LockItemsForRead(false); m_items.LockItemsForRead(false);
if (type == 10) // Script if (type == (int)InventoryType.LSL) // Script
{ {
m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID); m_part.ParentGroup.Scene.EventManager.TriggerRemoveScript(m_part.LocalId, itemID);
} }
@ -1101,7 +1101,7 @@ namespace OpenSim.Region.Framework.Scenes
m_items.LockItemsForRead(true); m_items.LockItemsForRead(true);
foreach (TaskInventoryItem item in m_items.Values) foreach (TaskInventoryItem item in m_items.Values)
{ {
if (item.Type == 10) if (item.Type == (int)InventoryType.LSL)
{ {
scriptcount++; scriptcount++;
} }

View File

@ -706,14 +706,16 @@
;; For standalones, this is the storage dll. ;; For standalones, this is the storage dll.
; StorageProvider = OpenSim.Data.MySQL.dll ; StorageProvider = OpenSim.Data.MySQL.dll
;# {MuteListModule} {OfflineMessageModule:OfflineMessageModule} {} {} None ; Mute list handler
;; Mute list handler (not yet implemented). MUST BE SET to allow offline ; the provided MuteListModule is just a Dummy
;; messages to work ; you will need a external module for proper suport.
; if you keep both 2 following settings comment, viewers will use mutes in their caches
; if you uncoment both (url is ignored) the mutes will be deleted at login.
;# {MuteListModule} {MuteListModule:MuteListModule} {} {} None
; MuteListModule = MuteListModule ; MuteListModule = MuteListModule
;# {MuteListURL} {OfflineMessageModule:OfflineMessageModule} {} {} http://yourserver/Mute.php ;# {MuteListURL} {MuteListModule:MuteListModule} {} {} http://yourserver/Mute.php
;; URL of the web service that serves mute lists. Not currently used, but
;; must be set to allow offline messaging to work.
; MuteListURL = http://yourserver/Mute.php ; MuteListURL = http://yourserver/Mute.php
;; Control whether group invites and notices are stored for offline users. ;; Control whether group invites and notices are stored for offline users.