OpenSim.Modules.DataValue/src/DataValue.cs

265 lines
7.9 KiB
C#

using log4net;
using Mono.Addins;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Modules.DataValue.Storage;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using System.Timers;
[assembly: Addin("DataValueModule", "0.1")]
[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]
namespace OpenSim.Modules.DataValue
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "DataValueModule")]
public class DataValue : INonSharedRegionModule
{
#region Region Module
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private Scene m_scene = null;
private IConfig m_config = null;
private IScriptModuleComms m_scriptModule;
private String m_storageTyp = null;
private iStorage m_storage = null;
private List<StorageElement> m_cache = new List<StorageElement>();
private Timer m_timer = null;
private int m_rateLimit = 0;
public string Name
{
get { return "DataValueModule"; }
}
public Type ReplaceableInterface
{
get { return null; }
}
public void AddRegion(Scene scene)
{
}
public void Close()
{
}
public void Initialise(IConfigSource source)
{
try
{
m_config = source.Configs["XEngine"];
m_storageTyp = m_config.GetString("DataStorageTyp", "Memory").ToUpper().Trim();
}
catch (Exception e)
{
m_log.ErrorFormat("[" + Name + "]: initialization error: {0}", e.Message);
return;
}
m_timer = new Timer();
m_timer.Interval = 1000;
m_timer.Elapsed += cleanUp;
m_timer.Start();
}
public void RegionLoaded(Scene scene)
{
m_log.Info("[" + Name + "]: Load region " + scene.Name);
m_scene = scene;
if (m_storageTyp == "REGIONEXTRAS")
m_storage = new RegionExtras(m_scene, m_config);
if (m_storageTyp == "FILESYSTEM")
m_storage = new FileSystem(m_scene, m_config);
if (m_storageTyp == "MYSQL")
m_storage = new MySQL(m_scene, m_config);
if (m_storageTyp == "MEMORY")
m_storage = new Memory();
if (m_storage == null)
m_storage = new Memory();
m_log.Info("[" + Name + "] Using '" + m_storageTyp + "' as Storage.");
m_scriptModule = m_scene.RequestModuleInterface<IScriptModuleComms>();
if (m_scriptModule != null)
{
m_scriptModule.RegisterScriptInvocation(this, "osGetDataValue");
m_scriptModule.RegisterScriptInvocation(this, "osSetDataValue");
m_scriptModule.RegisterScriptInvocation(this, "osDeleteDataValue");
m_scriptModule.RegisterScriptInvocation(this, "osCheckDataValue");
}
}
public void RemoveRegion(Scene scene)
{
}
#endregion
#region Script Funktions
[ScriptInvocation]
public string osGetDataValue(UUID hostID, UUID scriptID, string key)
{
if(m_storage != null)
{
SceneObjectPart _host = m_scene.GetSceneObjectPart(hostID);
StorageElement _element = m_cache.Find(X => X.Group == _host.GroupID.ToString() && X.Index == key);
if (_element != null)
return _element.get();
checkRateLimit();
try
{
String _data = m_storage.get(_host.GroupID.ToString(), key);
if (_data == null)
return "";
m_cache.Add(new StorageElement(_host.GroupID.ToString(), key, _data, m_storage));
return _data;
}catch(Exception _error)
{
m_log.Error("[" + Name + "] osGetDataValue: " + _error.Message);
return "";
}
}
throw new Exception("No data Storage aviable.");
}
[ScriptInvocation]
public void osSetDataValue(UUID hostID, UUID scriptID, string key, string value)
{
if (m_storage != null)
{
SceneObjectPart _host = m_scene.GetSceneObjectPart(hostID);
StorageElement _element = m_cache.Find(X => X.Group == _host.GroupID.ToString() && X.Index == key);
if (_element != null)
{
_element.save(value);
return;
}
checkRateLimit();
try
{
m_cache.Add(new StorageElement(_host.GroupID.ToString(), key, value, m_storage));
m_storage.save(_host.GroupID.ToString(), key, value);
return;
}
catch (Exception _error)
{
m_log.Error("[" + Name + "] osSetDataValue: " + _error.Message);
}
}
throw new Exception("No data Storage aviable.");
}
[ScriptInvocation]
public void osDeleteDataValue(UUID hostID, UUID scriptID, string key, string value)
{
SceneObjectPart _host = m_scene.GetSceneObjectPart(hostID);
StorageElement _element = m_cache.Find(X => X.Group == _host.GroupID.ToString() && X.Index == key);
checkRateLimit();
if (m_storage != null)
{
try
{
if (_element != null)
m_cache.Remove(_element);
m_storage.remove(_host.GroupID.ToString(), key);
}
catch (Exception _error)
{
m_log.Error("[" + Name + "] osDeleteDataValue: " + _error.Message);
}
}
throw new Exception("No data Storage aviable.");
}
[ScriptInvocation]
public int osCheckDataValue(UUID hostID, UUID scriptID, string key)
{
if (m_storage != null)
{
SceneObjectPart _host = m_scene.GetSceneObjectPart(hostID);
StorageElement _element = m_cache.Find(X => X.Group == _host.GroupID.ToString() && X.Index == key);
if (_element != null)
return 1;
checkRateLimit();
try
{
if (m_storage.check(_host.GroupID.ToString(), key))
return 1;
return 0;
}
catch (Exception _error)
{
m_log.Error("[" + Name + "] osCheckDataValue: " + _error.Message);
return 0;
}
}
throw new Exception("No data Storage aviable.");
}
private void cleanUp(object sender, ElapsedEventArgs e)
{
if(m_rateLimit >= 0)
m_rateLimit = m_rateLimit - 100;
List<StorageElement> _allStorageElements = m_cache.FindAll(X => X.LastUse + 10 <= (Int32)(DateTime.UtcNow.Subtract(new DateTime(1970, 1, 1))).TotalSeconds);
foreach(StorageElement _element in _allStorageElements)
m_cache.Remove(_element);
}
private void checkRateLimit()
{
m_rateLimit++;
if (m_rateLimit >= 1000)
throw new Exception("Data storage rate limit reached!");
}
#endregion
}
}