Files
opensim/OpenSim/Region/OptionalModules/Avatar/XmlRpcGroups/SimianGroupsServicesConnectorModule.cs
Mic Bowman a9e8bd59a3 Fix a race condition in the simian groups connector. When requests were
too slow they would circumvent the cache (piling up on the network service
and making the problem even worse). This condition happens frequently
during permission checks.
2012-02-13 19:38:22 -08:00

1443 lines
60 KiB
C#

/*
* 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.Collections.Specialized;
using System.Reflection;
using System.Threading;
using Nwc.XmlRpc;
using log4net;
using Mono.Addins;
using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Framework.Communications;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Services.Interfaces;
/***************************************************************************
* Simian Data Map
* ===============
*
* OwnerID -> Type -> Key
* -----------------------
*
* UserID -> Group -> ActiveGroup
* + GroupID
*
* UserID -> GroupSessionDropped -> GroupID
* UserID -> GroupSessionInvited -> GroupID
*
* UserID -> GroupMember -> GroupID
* + SelectedRoleID [UUID]
* + AcceptNotices [bool]
* + ListInProfile [bool]
* + Contribution [int]
*
* UserID -> GroupRole[GroupID] -> RoleID
*
*
* GroupID -> Group -> GroupName
* + Charter
* + ShowInList
* + InsigniaID
* + MembershipFee
* + OpenEnrollment
* + AllowPublish
* + MaturePublish
* + FounderID
* + EveryonePowers
* + OwnerRoleID
* + OwnersPowers
*
* GroupID -> GroupRole -> RoleID
* + Name
* + Description
* + Title
* + Powers
*
* GroupID -> GroupMemberInvite -> InviteID
* + AgentID
* + RoleID
*
* GroupID -> GroupNotice -> NoticeID
* + TimeStamp [uint]
* + FromName [string]
* + Subject [string]
* + Message [string]
* + BinaryBucket [byte[]]
*
* */
namespace OpenSim.Region.OptionalModules.Avatar.XmlRpcGroups
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")]
public class SimianGroupsServicesConnectorModule : ISharedRegionModule, IGroupsServicesConnector
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public const GroupPowers m_DefaultEveryonePowers = GroupPowers.AllowSetHome |
GroupPowers.Accountable |
GroupPowers.JoinChat |
GroupPowers.AllowVoiceChat |
GroupPowers.ReceiveNotices |
GroupPowers.StartProposal |
GroupPowers.VoteOnProposal;
// Would this be cleaner as (GroupPowers)ulong.MaxValue;
public const GroupPowers m_DefaultOwnerPowers = GroupPowers.Accountable
| GroupPowers.AllowEditLand
| GroupPowers.AllowFly
| GroupPowers.AllowLandmark
| GroupPowers.AllowRez
| GroupPowers.AllowSetHome
| GroupPowers.AllowVoiceChat
| GroupPowers.AssignMember
| GroupPowers.AssignMemberLimited
| GroupPowers.ChangeActions
| GroupPowers.ChangeIdentity
| GroupPowers.ChangeMedia
| GroupPowers.ChangeOptions
| GroupPowers.CreateRole
| GroupPowers.DeedObject
| GroupPowers.DeleteRole
| GroupPowers.Eject
| GroupPowers.FindPlaces
| GroupPowers.Invite
| GroupPowers.JoinChat
| GroupPowers.LandChangeIdentity
| GroupPowers.LandDeed
| GroupPowers.LandDivideJoin
| GroupPowers.LandEdit
| GroupPowers.LandEjectAndFreeze
| GroupPowers.LandGardening
| GroupPowers.LandManageAllowed
| GroupPowers.LandManageBanned
| GroupPowers.LandManagePasses
| GroupPowers.LandOptions
| GroupPowers.LandRelease
| GroupPowers.LandSetSale
| GroupPowers.ModerateChat
| GroupPowers.ObjectManipulate
| GroupPowers.ObjectSetForSale
| GroupPowers.ReceiveNotices
| GroupPowers.RemoveMember
| GroupPowers.ReturnGroupOwned
| GroupPowers.ReturnGroupSet
| GroupPowers.ReturnNonGroup
| GroupPowers.RoleProperties
| GroupPowers.SendNotices
| GroupPowers.SetLandingPoint
| GroupPowers.StartProposal
| GroupPowers.VoteOnProposal;
private bool m_connectorEnabled = false;
private string m_groupsServerURI = string.Empty;
private bool m_debugEnabled = false;
private Dictionary<string, bool> m_pendingRequests = new Dictionary<string,bool>();
private ExpiringCache<string, OSDMap> m_memoryCache;
private int m_cacheTimeout = 30;
// private IUserAccountService m_accountService = null;
#region IRegionModuleBase Members
public string Name
{
get { return "SimianGroupsServicesConnector"; }
}
// this module is not intended to be replaced, but there should only be 1 of them.
public Type ReplaceableInterface
{
get { return null; }
}
public void Initialise(IConfigSource config)
{
IConfig groupsConfig = config.Configs["Groups"];
if (groupsConfig == null)
{
// Do not run this module by default.
return;
}
else
{
// if groups aren't enabled, we're not needed.
// if we're not specified as the connector to use, then we're not wanted
if ((groupsConfig.GetBoolean("Enabled", false) == false)
|| (groupsConfig.GetString("ServicesConnectorModule", "XmlRpcGroupsServicesConnector") != Name))
{
m_connectorEnabled = false;
return;
}
m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR]: Initializing {0}", this.Name);
m_groupsServerURI = groupsConfig.GetString("GroupsServerURI", string.Empty);
if ((m_groupsServerURI == null) ||
(m_groupsServerURI == string.Empty))
{
m_log.ErrorFormat("Please specify a valid Simian Server for GroupsServerURI in OpenSim.ini, [Groups]");
m_connectorEnabled = false;
return;
}
m_cacheTimeout = groupsConfig.GetInt("GroupsCacheTimeout", 30);
if (m_cacheTimeout == 0)
{
m_log.WarnFormat("[SIMIAN-GROUPS-CONNECTOR] Groups Cache Disabled.");
}
else
{
m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] Groups Cache Timeout set to {0}.", m_cacheTimeout);
}
m_memoryCache = new ExpiringCache<string,OSDMap>();
// If we got all the config options we need, lets start'er'up
m_connectorEnabled = true;
m_debugEnabled = groupsConfig.GetBoolean("DebugEnabled", true);
}
}
public void Close()
{
m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR]: Closing {0}", this.Name);
}
public void AddRegion(OpenSim.Region.Framework.Scenes.Scene scene)
{
if (m_connectorEnabled)
{
scene.RegisterModuleInterface<IGroupsServicesConnector>(this);
}
}
public void RemoveRegion(OpenSim.Region.Framework.Scenes.Scene scene)
{
if (scene.RequestModuleInterface<IGroupsServicesConnector>() == this)
{
scene.UnregisterModuleInterface<IGroupsServicesConnector>(this);
}
}
public void RegionLoaded(OpenSim.Region.Framework.Scenes.Scene scene)
{
// TODO: May want to consider listenning for Agent Connections so we can pre-cache group info
// scene.EventManager.OnNewClient += OnNewClient;
}
#endregion
#region ISharedRegionModule Members
public void PostInitialise()
{
// NoOp
}
#endregion
#region IGroupsServicesConnector Members
/// <summary>
/// Create a Group, including Everyone and Owners Role, place FounderID in both groups, select Owner as selected role, and newly created group as agent's active role.
/// </summary>
public UUID CreateGroup(UUID requestingAgentID, string name, string charter, bool showInList, UUID insigniaID,
int membershipFee, bool openEnrollment, bool allowPublish,
bool maturePublish, UUID founderID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
UUID GroupID = UUID.Random();
UUID OwnerRoleID = UUID.Random();
OSDMap GroupInfoMap = new OSDMap();
GroupInfoMap["Charter"] = OSD.FromString(charter);
GroupInfoMap["ShowInList"] = OSD.FromBoolean(showInList);
GroupInfoMap["InsigniaID"] = OSD.FromUUID(insigniaID);
GroupInfoMap["MembershipFee"] = OSD.FromInteger(0);
GroupInfoMap["OpenEnrollment"] = OSD.FromBoolean(openEnrollment);
GroupInfoMap["AllowPublish"] = OSD.FromBoolean(allowPublish);
GroupInfoMap["MaturePublish"] = OSD.FromBoolean(maturePublish);
GroupInfoMap["FounderID"] = OSD.FromUUID(founderID);
GroupInfoMap["EveryonePowers"] = OSD.FromULong((ulong)m_DefaultEveryonePowers);
GroupInfoMap["OwnerRoleID"] = OSD.FromUUID(OwnerRoleID);
GroupInfoMap["OwnersPowers"] = OSD.FromULong((ulong)m_DefaultOwnerPowers);
if (SimianAddGeneric(GroupID, "Group", name, GroupInfoMap))
{
AddGroupRole(requestingAgentID, GroupID, UUID.Zero, "Everyone", "Members of " + name, "Member of " + name, (ulong)m_DefaultEveryonePowers);
AddGroupRole(requestingAgentID, GroupID, OwnerRoleID, "Owners", "Owners of " + name, "Owner of " + name, (ulong)m_DefaultOwnerPowers);
AddAgentToGroup(requestingAgentID, requestingAgentID, GroupID, OwnerRoleID);
return GroupID;
}
else
{
return UUID.Zero;
}
}
public void UpdateGroup(UUID requestingAgentID, UUID groupID, string charter, bool showInList,
UUID insigniaID, int membershipFee, bool openEnrollment,
bool allowPublish, bool maturePublish)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
// TODO: Check to make sure requestingAgentID has permission to update group
string GroupName;
OSDMap GroupInfoMap;
if (SimianGetFirstGenericEntry(groupID, "GroupInfo", out GroupName, out GroupInfoMap))
{
GroupInfoMap["Charter"] = OSD.FromString(charter);
GroupInfoMap["ShowInList"] = OSD.FromBoolean(showInList);
GroupInfoMap["InsigniaID"] = OSD.FromUUID(insigniaID);
GroupInfoMap["MembershipFee"] = OSD.FromInteger(0);
GroupInfoMap["OpenEnrollment"] = OSD.FromBoolean(openEnrollment);
GroupInfoMap["AllowPublish"] = OSD.FromBoolean(allowPublish);
GroupInfoMap["MaturePublish"] = OSD.FromBoolean(maturePublish);
SimianAddGeneric(groupID, "Group", GroupName, GroupInfoMap);
}
}
public void AddGroupRole(UUID requestingAgentID, UUID groupID, UUID roleID, string name, string description,
string title, ulong powers)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
OSDMap GroupRoleInfo = new OSDMap();
GroupRoleInfo["Name"] = OSD.FromString(name);
GroupRoleInfo["Description"] = OSD.FromString(description);
GroupRoleInfo["Title"] = OSD.FromString(title);
GroupRoleInfo["Powers"] = OSD.FromULong((ulong)powers);
// TODO: Add security, make sure that requestingAgentID has permision to add roles
SimianAddGeneric(groupID, "GroupRole", roleID.ToString(), GroupRoleInfo);
}
public void RemoveGroupRole(UUID requestingAgentID, UUID groupID, UUID roleID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
// TODO: Add security
// Can't delete the Everyone Role
if (roleID != UUID.Zero)
{
// Remove all GroupRole Members from Role
Dictionary<UUID, OSDMap> GroupRoleMembers;
string GroupRoleMemberType = "GroupRole" + groupID.ToString();
if (SimianGetGenericEntries(GroupRoleMemberType, roleID.ToString(), out GroupRoleMembers))
{
foreach (UUID UserID in GroupRoleMembers.Keys)
{
EnsureRoleNotSelectedByMember(groupID, roleID, UserID);
SimianRemoveGenericEntry(UserID, GroupRoleMemberType, roleID.ToString());
}
}
// Remove role
SimianRemoveGenericEntry(groupID, "GroupRole", roleID.ToString());
}
}
public void UpdateGroupRole(UUID requestingAgentID, UUID groupID, UUID roleID, string name, string description,
string title, ulong powers)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
// TODO: Security, check that requestingAgentID is allowed to update group roles
OSDMap GroupRoleInfo;
if (SimianGetGenericEntry(groupID, "GroupRole", roleID.ToString(), out GroupRoleInfo))
{
if (name != null)
{
GroupRoleInfo["Name"] = OSD.FromString(name);
}
if (description != null)
{
GroupRoleInfo["Description"] = OSD.FromString(description);
}
if (title != null)
{
GroupRoleInfo["Title"] = OSD.FromString(title);
}
GroupRoleInfo["Powers"] = OSD.FromULong((ulong)powers);
}
SimianAddGeneric(groupID, "GroupRole", roleID.ToString(), GroupRoleInfo);
}
public GroupRecord GetGroupRecord(UUID requestingAgentID, UUID groupID, string groupName)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
OSDMap GroupInfoMap = null;
if (groupID != UUID.Zero)
{
if (!SimianGetFirstGenericEntry(groupID, "Group", out groupName, out GroupInfoMap))
{
return null;
}
}
else if ((groupName != null) && (groupName != string.Empty))
{
if (!SimianGetFirstGenericEntry("Group", groupName, out groupID, out GroupInfoMap))
{
return null;
}
}
GroupRecord GroupInfo = new GroupRecord();
GroupInfo.GroupID = groupID;
GroupInfo.GroupName = groupName;
GroupInfo.Charter = GroupInfoMap["Charter"].AsString();
GroupInfo.ShowInList = GroupInfoMap["ShowInList"].AsBoolean();
GroupInfo.GroupPicture = GroupInfoMap["InsigniaID"].AsUUID();
GroupInfo.MembershipFee = GroupInfoMap["MembershipFee"].AsInteger();
GroupInfo.OpenEnrollment = GroupInfoMap["OpenEnrollment"].AsBoolean();
GroupInfo.AllowPublish = GroupInfoMap["AllowPublish"].AsBoolean();
GroupInfo.MaturePublish = GroupInfoMap["MaturePublish"].AsBoolean();
GroupInfo.FounderID = GroupInfoMap["FounderID"].AsUUID();
GroupInfo.OwnerRoleID = GroupInfoMap["OwnerRoleID"].AsUUID();
return GroupInfo;
}
public GroupProfileData GetMemberGroupProfile(UUID requestingAgentID, UUID groupID, UUID memberID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
OSDMap groupProfile;
string groupName;
if (!SimianGetFirstGenericEntry(groupID, "Group", out groupName, out groupProfile))
{
// GroupProfileData is not nullable
return new GroupProfileData();
}
GroupProfileData MemberGroupProfile = new GroupProfileData();
MemberGroupProfile.GroupID = groupID;
MemberGroupProfile.Name = groupName;
if (groupProfile["Charter"] != null)
{
MemberGroupProfile.Charter = groupProfile["Charter"].AsString();
}
MemberGroupProfile.ShowInList = groupProfile["ShowInList"].AsString() == "1";
MemberGroupProfile.InsigniaID = groupProfile["InsigniaID"].AsUUID();
MemberGroupProfile.MembershipFee = groupProfile["MembershipFee"].AsInteger();
MemberGroupProfile.OpenEnrollment = groupProfile["OpenEnrollment"].AsBoolean();
MemberGroupProfile.AllowPublish = groupProfile["AllowPublish"].AsBoolean();
MemberGroupProfile.MaturePublish = groupProfile["MaturePublish"].AsBoolean();
MemberGroupProfile.FounderID = groupProfile["FounderID"].AsUUID();;
MemberGroupProfile.OwnerRole = groupProfile["OwnerRoleID"].AsUUID();
Dictionary<UUID, OSDMap> Members;
if (SimianGetGenericEntries("GroupMember",groupID.ToString(), out Members))
{
MemberGroupProfile.GroupMembershipCount = Members.Count;
}
Dictionary<string, OSDMap> Roles;
if (SimianGetGenericEntries(groupID, "GroupRole", out Roles))
{
MemberGroupProfile.GroupRolesCount = Roles.Count;
}
// TODO: Get Group Money balance from somewhere
// group.Money = 0;
GroupMembershipData MemberInfo = GetAgentGroupMembership(requestingAgentID, memberID, groupID);
MemberGroupProfile.MemberTitle = MemberInfo.GroupTitle;
MemberGroupProfile.PowersMask = MemberInfo.GroupPowers;
return MemberGroupProfile;
}
public void SetAgentActiveGroup(UUID requestingAgentID, UUID agentID, UUID groupID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
OSDMap ActiveGroup = new OSDMap();
ActiveGroup.Add("GroupID", OSD.FromUUID(groupID));
SimianAddGeneric(agentID, "Group", "ActiveGroup", ActiveGroup);
}
public void SetAgentActiveGroupRole(UUID requestingAgentID, UUID agentID, UUID groupID, UUID roleID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
OSDMap GroupMemberInfo;
if (!SimianGetGenericEntry(agentID, "GroupMember", groupID.ToString(), out GroupMemberInfo))
{
GroupMemberInfo = new OSDMap();
}
GroupMemberInfo["SelectedRoleID"] = OSD.FromUUID(roleID);
SimianAddGeneric(agentID, "GroupMember", groupID.ToString(), GroupMemberInfo);
}
public void SetAgentGroupInfo(UUID requestingAgentID, UUID agentID, UUID groupID, bool acceptNotices, bool listInProfile)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
OSDMap GroupMemberInfo;
if (!SimianGetGenericEntry(agentID, "GroupMember", groupID.ToString(), out GroupMemberInfo))
{
GroupMemberInfo = new OSDMap();
}
GroupMemberInfo["AcceptNotices"] = OSD.FromBoolean(acceptNotices);
GroupMemberInfo["ListInProfile"] = OSD.FromBoolean(listInProfile);
GroupMemberInfo["Contribution"] = OSD.FromInteger(0);
GroupMemberInfo["SelectedRole"] = OSD.FromUUID(UUID.Zero);
SimianAddGeneric(agentID, "GroupMember", groupID.ToString(), GroupMemberInfo);
}
public void AddAgentToGroupInvite(UUID requestingAgentID, UUID inviteID, UUID groupID, UUID roleID, UUID agentID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
OSDMap Invite = new OSDMap();
Invite["AgentID"] = OSD.FromUUID(agentID);
Invite["RoleID"] = OSD.FromUUID(roleID);
SimianAddGeneric(groupID, "GroupMemberInvite", inviteID.ToString(), Invite);
}
public GroupInviteInfo GetAgentToGroupInvite(UUID requestingAgentID, UUID inviteID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
OSDMap GroupMemberInvite;
UUID GroupID;
if (!SimianGetFirstGenericEntry("GroupMemberInvite", inviteID.ToString(), out GroupID, out GroupMemberInvite))
{
return null;
}
GroupInviteInfo inviteInfo = new GroupInviteInfo();
inviteInfo.InviteID = inviteID;
inviteInfo.GroupID = GroupID;
inviteInfo.AgentID = GroupMemberInvite["AgentID"].AsUUID();
inviteInfo.RoleID = GroupMemberInvite["RoleID"].AsUUID();
return inviteInfo;
}
public void RemoveAgentToGroupInvite(UUID requestingAgentID, UUID inviteID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
GroupInviteInfo invite = GetAgentToGroupInvite(requestingAgentID, inviteID);
SimianRemoveGenericEntry(invite.GroupID, "GroupMemberInvite", inviteID.ToString());
}
public void AddAgentToGroup(UUID requestingAgentID, UUID AgentID, UUID GroupID, UUID RoleID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
// Setup Agent/Group information
SetAgentGroupInfo(requestingAgentID, AgentID, GroupID, true, true);
// Add agent to Everyone Group
AddAgentToGroupRole(requestingAgentID, AgentID, GroupID, UUID.Zero);
// Add agent to Specified Role
AddAgentToGroupRole(requestingAgentID, AgentID, GroupID, RoleID);
// Set selected role in this group to specified role
SetAgentActiveGroupRole(requestingAgentID, AgentID, GroupID, RoleID);
}
public void RemoveAgentFromGroup(UUID requestingAgentID, UUID agentID, UUID groupID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
// If current active group is the group the agent is being removed from, change their group to UUID.Zero
GroupMembershipData memberActiveMembership = GetAgentActiveMembership(requestingAgentID, agentID);
if (memberActiveMembership.GroupID == groupID)
{
SetAgentActiveGroup(agentID, agentID, UUID.Zero);
}
// Remove Group Member information for this group
SimianRemoveGenericEntry(agentID, "GroupMember", groupID.ToString());
// By using a Simian Generics Type consisting of a prefix and a groupID,
// combined with RoleID as key allows us to get a list of roles a particular member
// of a group is assigned to.
string GroupRoleMemberType = "GroupRole" + groupID.ToString();
// Take Agent out of all other group roles
Dictionary<string, OSDMap> GroupRoles;
if (SimianGetGenericEntries(agentID, GroupRoleMemberType, out GroupRoles))
{
foreach (string roleID in GroupRoles.Keys)
{
SimianRemoveGenericEntry(agentID, GroupRoleMemberType, roleID);
}
}
}
public void AddAgentToGroupRole(UUID requestingAgentID, UUID agentID, UUID groupID, UUID roleID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
SimianAddGeneric(agentID, "GroupRole" + groupID.ToString(), roleID.ToString(), new OSDMap());
}
public void RemoveAgentFromGroupRole(UUID requestingAgentID, UUID agentID, UUID groupID, UUID roleID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
// Cannot remove members from the Everyone Role
if (roleID != UUID.Zero)
{
EnsureRoleNotSelectedByMember(groupID, roleID, agentID);
string GroupRoleMemberType = "GroupRole" + groupID.ToString();
SimianRemoveGenericEntry(agentID, GroupRoleMemberType, roleID.ToString());
}
}
public List<DirGroupsReplyData> FindGroups(UUID requestingAgentID, string search)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
List<DirGroupsReplyData> findings = new List<DirGroupsReplyData>();
NameValueCollection requestArgs = new NameValueCollection
{
{ "RequestMethod", "GetGenerics" },
{ "Type", "Group" },
{ "Key", search },
{ "Fuzzy", "1" }
};
OSDMap response = CachedPostRequest(requestArgs);
if (response["Success"].AsBoolean() && response["Entries"] is OSDArray)
{
OSDArray entryArray = (OSDArray)response["Entries"];
foreach (OSDMap entryMap in entryArray)
{
DirGroupsReplyData data = new DirGroupsReplyData();
data.groupID = entryMap["OwnerID"].AsUUID();
data.groupName = entryMap["Key"].AsString();
// TODO: is there a better way to do this?
Dictionary<UUID, OSDMap> Members;
if (SimianGetGenericEntries("GroupMember", data.groupID.ToString(), out Members))
{
data.members = Members.Count;
}
else
{
data.members = 0;
}
// TODO: sort results?
// data.searchOrder = order;
findings.Add(data);
}
}
return findings;
}
public GroupMembershipData GetAgentGroupMembership(UUID requestingAgentID, UUID agentID, UUID groupID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
GroupMembershipData data = null;
// bool foundData = false;
OSDMap UserGroupMemberInfo;
if (SimianGetGenericEntry(agentID, "GroupMember", groupID.ToString(), out UserGroupMemberInfo))
{
data = new GroupMembershipData();
data.AcceptNotices = UserGroupMemberInfo["AcceptNotices"].AsBoolean();
data.Contribution = UserGroupMemberInfo["Contribution"].AsInteger();
data.ListInProfile = UserGroupMemberInfo["ListInProfile"].AsBoolean();
data.ActiveRole = UserGroupMemberInfo["SelectedRoleID"].AsUUID();
///////////////////////////////
// Agent Specific Information:
//
OSDMap UserActiveGroup;
if (SimianGetGenericEntry(agentID, "Group", "ActiveGroup", out UserActiveGroup))
{
data.Active = UserActiveGroup["GroupID"].AsUUID().Equals(groupID);
}
///////////////////////////////
// Role Specific Information:
//
OSDMap GroupRoleInfo;
if (SimianGetGenericEntry(groupID, "GroupRole", data.ActiveRole.ToString(), out GroupRoleInfo))
{
data.GroupTitle = GroupRoleInfo["Title"].AsString();
data.GroupPowers = GroupRoleInfo["Powers"].AsULong();
}
///////////////////////////////
// Group Specific Information:
//
OSDMap GroupInfo;
string GroupName;
if (SimianGetFirstGenericEntry(groupID, "Group", out GroupName, out GroupInfo))
{
data.GroupID = groupID;
data.AllowPublish = GroupInfo["AllowPublish"].AsBoolean();
data.Charter = GroupInfo["Charter"].AsString();
data.FounderID = GroupInfo["FounderID"].AsUUID();
data.GroupName = GroupName;
data.GroupPicture = GroupInfo["InsigniaID"].AsUUID();
data.MaturePublish = GroupInfo["MaturePublish"].AsBoolean();
data.MembershipFee = GroupInfo["MembershipFee"].AsInteger();
data.OpenEnrollment = GroupInfo["OpenEnrollment"].AsBoolean();
data.ShowInList = GroupInfo["ShowInList"].AsBoolean();
}
}
return data;
}
public GroupMembershipData GetAgentActiveMembership(UUID requestingAgentID, UUID agentID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
UUID GroupID = UUID.Zero;
OSDMap UserActiveGroup;
if (SimianGetGenericEntry(agentID, "Group", "ActiveGroup", out UserActiveGroup))
{
GroupID = UserActiveGroup["GroupID"].AsUUID();
}
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] Active GroupID : {0}", GroupID.ToString());
return GetAgentGroupMembership(requestingAgentID, agentID, GroupID);
}
public List<GroupMembershipData> GetAgentGroupMemberships(UUID requestingAgentID, UUID agentID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
List<GroupMembershipData> memberships = new List<GroupMembershipData>();
Dictionary<string,OSDMap> GroupMemberShips;
if (SimianGetGenericEntries(agentID, "GroupMember", out GroupMemberShips))
{
foreach (string key in GroupMemberShips.Keys)
{
memberships.Add(GetAgentGroupMembership(requestingAgentID, agentID, UUID.Parse(key)));
}
}
return memberships;
}
public List<GroupRolesData> GetAgentGroupRoles(UUID requestingAgentID, UUID agentID, UUID groupID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
List<GroupRolesData> Roles = new List<GroupRolesData>();
Dictionary<string, OSDMap> GroupRoles;
if (SimianGetGenericEntries(groupID, "GroupRole", out GroupRoles))
{
Dictionary<string, OSDMap> MemberRoles;
if (SimianGetGenericEntries(agentID, "GroupRole" + groupID.ToString(), out MemberRoles))
{
foreach (KeyValuePair<string, OSDMap> kvp in MemberRoles)
{
GroupRolesData data = new GroupRolesData();
data.RoleID = UUID.Parse(kvp.Key);
data.Name = GroupRoles[kvp.Key]["Name"].AsString();
data.Description = GroupRoles[kvp.Key]["Description"].AsString();
data.Title = GroupRoles[kvp.Key]["Title"].AsString();
data.Powers = GroupRoles[kvp.Key]["Powers"].AsULong();
Roles.Add(data);
}
}
}
return Roles;
}
public List<GroupRolesData> GetGroupRoles(UUID requestingAgentID, UUID groupID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
List<GroupRolesData> Roles = new List<GroupRolesData>();
Dictionary<string, OSDMap> GroupRoles;
if (SimianGetGenericEntries(groupID, "GroupRole", out GroupRoles))
{
foreach (KeyValuePair<string, OSDMap> role in GroupRoles)
{
GroupRolesData data = new GroupRolesData();
data.RoleID = UUID.Parse(role.Key);
data.Name = role.Value["Name"].AsString();
data.Description = role.Value["Description"].AsString();
data.Title = role.Value["Title"].AsString();
data.Powers = role.Value["Powers"].AsULong();
Dictionary<UUID, OSDMap> GroupRoleMembers;
if (SimianGetGenericEntries("GroupRole" + groupID.ToString(), role.Key, out GroupRoleMembers))
{
data.Members = GroupRoleMembers.Count;
}
else
{
data.Members = 0;
}
Roles.Add(data);
}
}
return Roles;
}
public List<GroupMembersData> GetGroupMembers(UUID requestingAgentID, UUID GroupID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
List<GroupMembersData> members = new List<GroupMembersData>();
OSDMap GroupInfo;
string GroupName;
UUID GroupOwnerRoleID = UUID.Zero;
if (!SimianGetFirstGenericEntry(GroupID, "Group", out GroupName, out GroupInfo))
{
return members;
}
GroupOwnerRoleID = GroupInfo["OwnerRoleID"].AsUUID();
// Locally cache group roles, since we'll be needing this data for each member
Dictionary<string,OSDMap> GroupRoles;
SimianGetGenericEntries(GroupID, "GroupRole", out GroupRoles);
// Locally cache list of group owners
Dictionary<UUID, OSDMap> GroupOwners;
SimianGetGenericEntries("GroupRole" + GroupID.ToString(), GroupOwnerRoleID.ToString(), out GroupOwners);
Dictionary<UUID, OSDMap> GroupMembers;
if (SimianGetGenericEntries("GroupMember", GroupID.ToString(), out GroupMembers))
{
foreach (KeyValuePair<UUID, OSDMap> member in GroupMembers)
{
GroupMembersData data = new GroupMembersData();
data.AgentID = member.Key;
UUID SelectedRoleID = member.Value["SelectedRoleID"].AsUUID();
data.AcceptNotices = member.Value["AcceptNotices"].AsBoolean();
data.ListInProfile = member.Value["ListInProfile"].AsBoolean();
data.Contribution = member.Value["Contribution"].AsInteger();
data.IsOwner = GroupOwners.ContainsKey(member.Key);
OSDMap GroupRoleInfo = GroupRoles[SelectedRoleID.ToString()];
data.Title = GroupRoleInfo["Title"].AsString();
data.AgentPowers = GroupRoleInfo["Powers"].AsULong();
members.Add(data);
}
}
return members;
}
public List<GroupRoleMembersData> GetGroupRoleMembers(UUID requestingAgentID, UUID groupID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
List<GroupRoleMembersData> members = new List<GroupRoleMembersData>();
Dictionary<string, OSDMap> GroupRoles;
if (SimianGetGenericEntries(groupID, "GroupRole", out GroupRoles))
{
foreach (KeyValuePair<string, OSDMap> Role in GroupRoles)
{
Dictionary<UUID, OSDMap> GroupRoleMembers;
if (SimianGetGenericEntries("GroupRole"+groupID.ToString(), Role.Key, out GroupRoleMembers))
{
foreach (KeyValuePair<UUID, OSDMap> GroupRoleMember in GroupRoleMembers)
{
GroupRoleMembersData data = new GroupRoleMembersData();
data.MemberID = GroupRoleMember.Key;
data.RoleID = UUID.Parse(Role.Key);
members.Add(data);
}
}
}
}
return members;
}
public List<GroupNoticeData> GetGroupNotices(UUID requestingAgentID, UUID GroupID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
List<GroupNoticeData> values = new List<GroupNoticeData>();
Dictionary<string, OSDMap> Notices;
if (SimianGetGenericEntries(GroupID, "GroupNotice", out Notices))
{
foreach (KeyValuePair<string, OSDMap> Notice in Notices)
{
GroupNoticeData data = new GroupNoticeData();
data.NoticeID = UUID.Parse(Notice.Key);
data.Timestamp = Notice.Value["TimeStamp"].AsUInteger();
data.FromName = Notice.Value["FromName"].AsString();
data.Subject = Notice.Value["Subject"].AsString();
data.HasAttachment = Notice.Value["BinaryBucket"].AsBinary().Length > 0;
//TODO: Figure out how to get this
data.AssetType = 0;
values.Add(data);
}
}
return values;
}
public GroupNoticeInfo GetGroupNotice(UUID requestingAgentID, UUID noticeID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
OSDMap GroupNotice;
UUID GroupID;
if (SimianGetFirstGenericEntry("GroupNotice", noticeID.ToString(), out GroupID, out GroupNotice))
{
GroupNoticeInfo data = new GroupNoticeInfo();
data.GroupID = GroupID;
data.Message = GroupNotice["Message"].AsString();
data.BinaryBucket = GroupNotice["BinaryBucket"].AsBinary();
data.noticeData.NoticeID = noticeID;
data.noticeData.Timestamp = GroupNotice["TimeStamp"].AsUInteger();
data.noticeData.FromName = GroupNotice["FromName"].AsString();
data.noticeData.Subject = GroupNotice["Subject"].AsString();
data.noticeData.HasAttachment = data.BinaryBucket.Length > 0;
data.noticeData.AssetType = 0;
if (data.Message == null)
{
data.Message = string.Empty;
}
return data;
}
return null;
}
public void AddGroupNotice(UUID requestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message, byte[] binaryBucket)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
OSDMap Notice = new OSDMap();
Notice["TimeStamp"] = OSD.FromUInteger((uint)Util.UnixTimeSinceEpoch());
Notice["FromName"] = OSD.FromString(fromName);
Notice["Subject"] = OSD.FromString(subject);
Notice["Message"] = OSD.FromString(message);
Notice["BinaryBucket"] = OSD.FromBinary(binaryBucket);
SimianAddGeneric(groupID, "GroupNotice", noticeID.ToString(), Notice);
}
#endregion
#region GroupSessionTracking
public void ResetAgentGroupChatSessions(UUID agentID)
{
Dictionary<string, OSDMap> agentSessions;
if (SimianGetGenericEntries(agentID, "GroupSessionDropped", out agentSessions))
{
foreach (string GroupID in agentSessions.Keys)
{
SimianRemoveGenericEntry(agentID, "GroupSessionDropped", GroupID);
}
}
if (SimianGetGenericEntries(agentID, "GroupSessionInvited", out agentSessions))
{
foreach (string GroupID in agentSessions.Keys)
{
SimianRemoveGenericEntry(agentID, "GroupSessionInvited", GroupID);
}
}
}
public bool hasAgentDroppedGroupChatSession(UUID agentID, UUID groupID)
{
OSDMap session;
return SimianGetGenericEntry(agentID, "GroupSessionDropped", groupID.ToString(), out session);
}
public void AgentDroppedFromGroupChatSession(UUID agentID, UUID groupID)
{
SimianAddGeneric(agentID, "GroupSessionDropped", groupID.ToString(), new OSDMap());
}
public void AgentInvitedToGroupChatSession(UUID agentID, UUID groupID)
{
SimianAddGeneric(agentID, "GroupSessionInvited", groupID.ToString(), new OSDMap());
}
public bool hasAgentBeenInvitedToGroupChatSession(UUID agentID, UUID groupID)
{
OSDMap session;
return SimianGetGenericEntry(agentID, "GroupSessionDropped", groupID.ToString(), out session);
}
#endregion
private void EnsureRoleNotSelectedByMember(UUID groupID, UUID roleID, UUID userID)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
// If member's SelectedRole is roleID, change their selected role to Everyone
// before removing them from the role
OSDMap UserGroupInfo;
if (SimianGetGenericEntry(userID, "GroupMember", groupID.ToString(), out UserGroupInfo))
{
if (UserGroupInfo["SelectedRoleID"].AsUUID() == roleID)
{
UserGroupInfo["SelectedRoleID"] = OSD.FromUUID(UUID.Zero);
}
SimianAddGeneric(userID, "GroupMember", groupID.ToString(), UserGroupInfo);
}
}
#region Simian Util Methods
private bool SimianAddGeneric(UUID ownerID, string type, string key, OSDMap map)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called ({1},{2},{3})", System.Reflection.MethodBase.GetCurrentMethod().Name, ownerID, type, key);
string value = OSDParser.SerializeJsonString(map);
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] value: {0}", value);
NameValueCollection RequestArgs = new NameValueCollection
{
{ "RequestMethod", "AddGeneric" },
{ "OwnerID", ownerID.ToString() },
{ "Type", type },
{ "Key", key },
{ "Value", value}
};
OSDMap Response = CachedPostRequest(RequestArgs);
if (Response["Success"].AsBoolean())
{
return true;
}
else
{
m_log.WarnFormat("[SIMIAN GROUPS CONNECTOR]: Error {0}, {1}, {2}, {3}", ownerID, type, key, Response["Message"]);
return false;
}
}
/// <summary>
/// Returns the first of possibly many entries for Owner/Type pair
/// </summary>
private bool SimianGetFirstGenericEntry(UUID ownerID, string type, out string key, out OSDMap map)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called ({1},{2})", System.Reflection.MethodBase.GetCurrentMethod().Name, ownerID, type);
NameValueCollection RequestArgs = new NameValueCollection
{
{ "RequestMethod", "GetGenerics" },
{ "OwnerID", ownerID.ToString() },
{ "Type", type }
};
OSDMap Response = CachedPostRequest(RequestArgs);
if (Response["Success"].AsBoolean() && Response["Entries"] is OSDArray)
{
OSDArray entryArray = (OSDArray)Response["Entries"];
if (entryArray.Count >= 1)
{
OSDMap entryMap = entryArray[0] as OSDMap;
key = entryMap["Key"].AsString();
map = (OSDMap)OSDParser.DeserializeJson(entryMap["Value"].AsString());
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] Generics Result {0}", entryMap["Value"].AsString());
return true;
}
else
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] No Generics Results");
}
}
else
{
m_log.WarnFormat("[SIMIAN GROUPS CONNECTOR]: Error retrieving group info ({0})", Response["Message"]);
}
key = null;
map = null;
return false;
}
private bool SimianGetFirstGenericEntry(string type, string key, out UUID ownerID, out OSDMap map)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called ({1},{2})", System.Reflection.MethodBase.GetCurrentMethod().Name, type, key);
NameValueCollection RequestArgs = new NameValueCollection
{
{ "RequestMethod", "GetGenerics" },
{ "Type", type },
{ "Key", key}
};
OSDMap Response = CachedPostRequest(RequestArgs);
if (Response["Success"].AsBoolean() && Response["Entries"] is OSDArray)
{
OSDArray entryArray = (OSDArray)Response["Entries"];
if (entryArray.Count >= 1)
{
OSDMap entryMap = entryArray[0] as OSDMap;
ownerID = entryMap["OwnerID"].AsUUID();
map = (OSDMap)OSDParser.DeserializeJson(entryMap["Value"].AsString());
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] Generics Result {0}", entryMap["Value"].AsString());
return true;
}
else
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] No Generics Results");
}
}
else
{
m_log.WarnFormat("[SIMIAN GROUPS CONNECTOR]: Error retrieving group info ({0})", Response["Message"]);
}
ownerID = UUID.Zero;
map = null;
return false;
}
private bool SimianGetGenericEntry(UUID ownerID, string type, string key, out OSDMap map)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called ({1},{2},{3})", System.Reflection.MethodBase.GetCurrentMethod().Name, ownerID, type, key);
NameValueCollection RequestArgs = new NameValueCollection
{
{ "RequestMethod", "GetGenerics" },
{ "OwnerID", ownerID.ToString() },
{ "Type", type },
{ "Key", key}
};
OSDMap Response = CachedPostRequest(RequestArgs);
if (Response["Success"].AsBoolean() && Response["Entries"] is OSDArray)
{
OSDArray entryArray = (OSDArray)Response["Entries"];
if (entryArray.Count == 1)
{
OSDMap entryMap = entryArray[0] as OSDMap;
key = entryMap["Key"].AsString();
map = (OSDMap)OSDParser.DeserializeJson(entryMap["Value"].AsString());
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] Generics Result {0}", entryMap["Value"].AsString());
return true;
}
else
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] No Generics Results");
}
}
else
{
m_log.WarnFormat("[SIMIAN GROUPS CONNECTOR]: Error retrieving group info ({0})", Response["Message"]);
}
map = null;
return false;
}
private bool SimianGetGenericEntries(UUID ownerID, string type, out Dictionary<string, OSDMap> maps)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called ({1},{2})", System.Reflection.MethodBase.GetCurrentMethod().Name,ownerID, type);
NameValueCollection requestArgs = new NameValueCollection
{
{ "RequestMethod", "GetGenerics" },
{ "OwnerID", ownerID.ToString() },
{ "Type", type }
};
OSDMap response = CachedPostRequest(requestArgs);
if (response["Success"].AsBoolean() && response["Entries"] is OSDArray)
{
maps = new Dictionary<string, OSDMap>();
OSDArray entryArray = (OSDArray)response["Entries"];
foreach (OSDMap entryMap in entryArray)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] Generics Result {0}", entryMap["Value"].AsString());
maps.Add(entryMap["Key"].AsString(), (OSDMap)OSDParser.DeserializeJson(entryMap["Value"].AsString()));
}
if (maps.Count == 0)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] No Generics Results");
}
return true;
}
else
{
maps = null;
m_log.WarnFormat("[SIMIAN GROUPS CONNECTOR]: Error retrieving group info ({0})", response["Message"]);
}
return false;
}
private bool SimianGetGenericEntries(string type, string key, out Dictionary<UUID, OSDMap> maps)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called ({1},{2})", System.Reflection.MethodBase.GetCurrentMethod().Name, type, key);
NameValueCollection requestArgs = new NameValueCollection
{
{ "RequestMethod", "GetGenerics" },
{ "Type", type },
{ "Key", key }
};
OSDMap response = CachedPostRequest(requestArgs);
if (response["Success"].AsBoolean() && response["Entries"] is OSDArray)
{
maps = new Dictionary<UUID, OSDMap>();
OSDArray entryArray = (OSDArray)response["Entries"];
foreach (OSDMap entryMap in entryArray)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] Generics Result {0}", entryMap["Value"].AsString());
maps.Add(entryMap["OwnerID"].AsUUID(), (OSDMap)OSDParser.DeserializeJson(entryMap["Value"].AsString()));
}
if (maps.Count == 0)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] No Generics Results");
}
return true;
}
else
{
maps = null;
m_log.WarnFormat("[SIMIAN-GROUPS-CONNECTOR]: Error retrieving group info ({0})", response["Message"]);
}
return false;
}
private bool SimianRemoveGenericEntry(UUID ownerID, string type, string key)
{
if (m_debugEnabled) m_log.InfoFormat("[SIMIAN-GROUPS-CONNECTOR] {0} called ({1},{2},{3})", System.Reflection.MethodBase.GetCurrentMethod().Name, ownerID, type, key);
NameValueCollection requestArgs = new NameValueCollection
{
{ "RequestMethod", "RemoveGeneric" },
{ "OwnerID", ownerID.ToString() },
{ "Type", type },
{ "Key", key }
};
OSDMap response = CachedPostRequest(requestArgs);
if (response["Success"].AsBoolean())
{
return true;
}
else
{
m_log.WarnFormat("[SIMIAN GROUPS CONNECTOR]: Error {0}, {1}, {2}, {3}", ownerID, type, key, response["Message"]);
return false;
}
}
#endregion
#region CheesyCache
OSDMap CachedPostRequest(NameValueCollection requestArgs)
{
// Immediately forward the request if the cache is disabled.
if (m_cacheTimeout == 0)
{
m_log.WarnFormat("[SIMIAN GROUPS CONNECTOR]: cache is disabled");
return WebUtil.PostToService(m_groupsServerURI, requestArgs);
}
// Check if this is an update or a request
if (requestArgs["RequestMethod"] == "RemoveGeneric"
|| requestArgs["RequestMethod"] == "AddGeneric")
{
m_log.WarnFormat("[SIMIAN GROUPS CONNECTOR]: clearing generics cache");
// Any and all updates cause the cache to clear
m_memoryCache.Clear();
// Send update to server, return the response without caching it
return WebUtil.PostToService(m_groupsServerURI, requestArgs);
}
// If we're not doing an update, we must be requesting data
// Create the cache key for the request and see if we have it cached
string CacheKey = WebUtil.BuildQueryString(requestArgs);
// This code uses a leader/follower pattern. On a cache miss, the request is added
// to a queue; the first thread to add it to the queue completes the request while
// follow on threads busy wait for the results, this situation seems to happen
// often when checking permissions
while (true)
{
OSDMap response = null;
bool firstRequest = false;
lock (m_memoryCache)
{
if (m_memoryCache.TryGetValue(CacheKey, out response))
return response;
if (! m_pendingRequests.ContainsKey(CacheKey))
{
m_pendingRequests.Add(CacheKey,true);
firstRequest = true;
}
}
if (firstRequest)
{
// if it wasn't in the cache, pass the request to the Simian Grid Services
try
{
response = WebUtil.PostToService(m_groupsServerURI, requestArgs);
}
catch (Exception e)
{
m_log.InfoFormat("[SIMIAN GROUPS CONNECTOR] request failed {0}",CacheKey);
}
// and cache the response
lock (m_memoryCache)
{
m_memoryCache.AddOrUpdate(CacheKey, response, TimeSpan.FromSeconds(m_cacheTimeout));
m_pendingRequests.Remove(CacheKey);
}
return response;
}
Thread.Sleep(50); // waiting for a web request to complete, 50msecs is reasonable
}
// if (!m_memoryCache.TryGetValue(CacheKey, out response))
// {
// m_log.WarnFormat("[SIMIAN GROUPS CONNECTOR]: query not in the cache");
// Util.PrintCallStack();
// // if it wasn't in the cache, pass the request to the Simian Grid Services
// response = WebUtil.PostToService(m_groupsServerURI, requestArgs);
// // and cache the response
// m_memoryCache.AddOrUpdate(CacheKey, response, TimeSpan.FromSeconds(m_cacheTimeout));
// }
// // return cached response
// return response;
}
#endregion
}
}