Compare commits

..

4 Commits

Author SHA1 Message Date
Justin Clarke Casey 6686040e76 * Apply mantis patches 2939, 2980 and 2995
* All these are necessary to get MSSQL working again
* Thanks to StrawberryFride for pointing this out
2009-01-14 15:15:10 +00:00
lbsa71 ce6fecbc93 * Created the post fixes branch for 0.6.1 (formerly known as 'stable') 2009-01-05 08:58:42 +00:00
Teravus Ovares e63c768973 * Back porting the LLSD Login Service Method fix to stable. 2008-12-27 22:09:32 +00:00
Charles Krinke 7b60e2c93f made a copy 2008-12-20 19:13:39 +00:00
3048 changed files with 262610 additions and 624502 deletions

90
.gitignore vendored
View File

@ -1,116 +1,36 @@
.project .project
.settings .settings
.gitignore
*.csproj *.csproj
*.csproj.user *.csproj.user
*.build *.build
*.mdb *.mdb
*.mdp *.mdp
*.mds *.mds
*.pdb
*.pidb *.pidb
*.dll.build *.dll.build
*.dll
*.log
# Ignore .user and .suo files as these are user preference specific
# http://stackoverflow.com/questions/72298/should-i-add-the-visual-studio-suo-and-user-files-to-source-control
*.suo
*.user
*.VisualState.xml
*/*/obj
*/*/*/obj
*/*/*/*/obj
*/*/*/*/*/obj
*/*/*/*/*/*/obj
*/*/*/*/*/*/*/obj
*/*/bin */*/bin
*/*/*/bin */*/*/bin
*/*/*/*/bin */*/*/*/bin
*/*/*/*/*/bin */*/*/*/*/bin
*/*/*/*/*/*/bin */*/*/*/*/*/bin
*/*/*/*/*/*/*/bin */*/*/*/*/*/*/bin
.vs/
addon-modules/
bin/Debug/*.dll bin/Debug/*.dll
bin/*.dll.mdb bin/*.dll.mdb
bin/*.db
bin/*.db-journal
bin/addin-db-* bin/addin-db-*
bin/*.dll bin/*.dll
bin/OpenSim.vshost.exe.config
bin/OpenSim.32BitLaunch.vshost.exe.config
bin/OpenSim.32BitLaunch.log
UpgradeLog.XML
_UpgradeReport_Files/
bin/ScriptEngines/*-*-*-*-*
bin/ScriptEngines/*.dll bin/ScriptEngines/*.dll
bin/ScriptEngines/*/*.dll
bin/ScriptEngines/*/*.state
bin/*.maddin bin/*.maddin
bin/*.exe
bin/*.ini
bin/j2kDecodeCache
bin/Physics*
bin/Terrain*
bin/Regions/*
bin/UserAssets
bin/assetcache
bin/maptiles
bin/bakes
bin/estate_settings.xml
bin/config-include/CenomeCache.ini
bin/config-include/FlotsamCache.ini
bin/config-include/GridCommon.ini
bin/config-include/StandaloneCommon.ini
bin/OpenSim.Grid.AssetInventoryServer.log
bin/OpenSim.Grid.AssetServer.log
bin/OpenSim.Grid.GridServer.log
bin/OpenSim.Grid.InventoryServer.log
bin/OpenSim.Grid.MessagingServer.log
bin/OpenSim.Grid.UserServer.log
bin/OpenSim.log
bin/OpenSimStats.log
bin/Robust.log
bin/RobustStats.log
bin/OpenSimConsoleHistory.txt
bin/RobustConsoleHistory.txt
bin/*.Tests.log
bin/*.manifest
bin/crashes/
Examples/*.dll Examples/*.dll
bin/*.exe
OpenSim.build OpenSim.build
OpenSim.sln OpenSim.sln
OpenSim.userprefs
Prebuild/Prebuild.build Prebuild/Prebuild.build
Prebuild/Prebuild.sln Prebuild/Prebuild.sln
TestResult.xml bin/OpenSim.log
bin/Physics*
bin/Terrain*
bin/estate_settings.xml
cov/* cov/*
OpenSim/OpenSim.userprefs OpenSim/OpenSim.userprefs
OpenSim/OpenSim.usertasks OpenSim/OpenSim.usertasks
TAGS
*~ *~
Makefile.local
bin/.version
compile.bat
OpenSim/Data/Tests/test-results/
OpenSim/Framework/Serialization/Tests/test-results/
OpenSim/Framework/Servers/Tests/test-results/
OpenSim/Framework/Tests/test-results/
OpenSim/Region/ClientStack/Linden/Caps/test-results/
OpenSim/Region/ClientStack/Linden/UDP/Tests/test-results/
OpenSim/Region/CoreModules/test-results/
OpenSim/Region/Framework/test-results/
OpenSim/Region/OptionalModules/test-results/
OpenSim/Region/Physics/BulletDotNETPlugin/
OpenSim/Region/Physics/Manager/test-results/
OpenSim/Region/Physics/OdePlugin/Tests/test-results/
OpenSim/Region/ScriptEngine/test-results/
OpenSim/Tests/Common/test-results/
OpenSim/Tests/test-results/
test-results/
doc/html
doc/doxygen.error.log
*.patch

72
.nant/bamboo.build Normal file
View File

@ -0,0 +1,72 @@
<?xml version="1.0" ?>
<project name="OpenSim" default="build">
<target name="build">
<exec program="mono" commandline="../bin/Prebuild.exe /target nant" />
<nant buildfile="../OpenSim.build" target="build" />
</target>
<target name="cibuild">
<property name="projectdir" value="opensim-0.6.1" />
<exec program="mono" commandline="bin/Prebuild.exe /target nant" workingdir="../" />
<nant buildfile="../OpenSim.build" target="clean" />
<nant buildfile="../OpenSim.build" target="build" />
<delete dir="../${projectdir}" />
<copy todir="../${projectdir}">
<fileset basedir="../">
<include name="ThirdPartyLicenses/**" />
<include name="CONTRIBUTORS.txt" />
<include name="README" />
<include name="bin/**" />
</fileset>
</copy>
<exec program="svn" commandline="info" workingdir="../" output="../${projectdir}/svn.info" />
<touch file="../${projectdir}/bin/startup_commands.txt" />
<!-- Re-create the directory containig test results. -->
<delete dir="../test-results" />
<mkdir dir="../test-results" />
<!-- Copy the OdePlugin dll to bin/ for testing. -->
<copy file="../bin/Physics/OpenSim.Region.Physics.OdePlugin.dll" tofile="../bin/OpenSim.Region.Physics.OdePlugin.dll" />
<!-- Run the tests. -->
<nunit2 failonerror="false" verbose="true">
<formatter type="Xml" usefile="true" extension=".xml" outputdir="../test-results" />
<test>
<assemblies>
<include name="../bin/OpenSim.Framework.Tests.dll" />
<include name="../bin/OpenSim.Framework.Communications.Tests.dll"/>
<include name="../bin/OpenSim.Framework.Servers.Tests.dll" />
<include name="../bin/OpenSim.Region.ScriptEngine.Common.Tests.dll" />
<include name="../bin/OpenSim.Region.ScriptEngine.Shared.Tests.dll" />
<include name="../bin/OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests.dll" />
<include name="../bin/OpenSim.Region.Environment.Tests.dll" />
<include name="../bin/OpenSim.Data.SQLite.Tests.dll" />
<include name="../bin/OpenSim.Data.MySQL.Tests.dll" />
</assemblies>
</test>
</nunit2>
<zip zipfile="../${projectdir}.zip">
<fileset basedir="../${projectdir}" prefix="${projectdir}">
<include name="**/*" />
</fileset>
</zip>
<tar destfile="../${projectdir}.tar.gz" compression="GZip">
<fileset basedir="../${projectdir}" prefix="${projectdir}">
<include name="**/*" />
</fileset>
</tar>
<copy file="../${projectdir}.zip" tofile="/home/buildsystem/public_html/${projectdir}-TRUNK.zip" overwrite="true" />
<copy file="../${projectdir}.tar.gz" tofile="/home/buildsystem/public_html/${projectdir}-TRUNK.tar.gz" overwrite="true" />
<!--
<echo message="Generating Doxygen documentation" />
<exec program="doxygen" workingdir="../doc" commandline="doxygen.conf" />
<exec program="rsync" workingdir="../doc" commandline="-az - - delete html/ /home/afrisby/public_html/docs/html/" />
-->
<!-- ensure a clean checkout each time -->
</target>
</project>

View File

@ -1,289 +1,181 @@
<!-- -*- xml -*- --> <!-- -*- xml -*- -->
<!-- please leave the top comment for us emacs folks --> <!-- please leve the top comment for us emacs folks -->
<property name="nunitcmd" value="nunit-console" /> <property name="projectdir" value="opensim-0.5.5" />
<!-- This target produces a source distribution of OpenSimulator --> <target name="distdir">
<!-- TODO: A few parameters still need to be tweaked after running this - need to do this automatically with sed or similar --> <delete dir="${projectdir}" />
<target name="distsrc"> <copy todir="${projectdir}">
<copy file="bin/OpenSim.ini.example" tofile="bin/OpenSim.ini"/> <fileset basedir=".">
<copy file="bin/config-include/StandaloneCommon.ini.example" tofile="bin/config-include/StandaloneCommon.ini"/> <include name="ThirdPartyLicenses/**" />
<copy file="bin/config-include/FlotsamCache.ini.example" tofile="bin/config-include/FlotsamCache.ini"/> <include name="CONTRIBUTORS.txt" />
<!-- delete files generated by runprebuild.sh which had to be run in order to generate the build file for this target--> <include name="README" />
<delete> <include name="OpenSim/**/*.cs" />
<fileset basedir="OpenSim"> <include name="**/*.build" />
<include name="**/*.build"/> <include name="**/*.csproj" />
<include name="**/*.csproj*"/> <include name="**/*.csproj.user" />
<include name="**/*.dll.build"/> <include name="**/*.sln" />
<include name="**/*.pidb"/> <include name="bin/*.dll" />
<exclude name="Tools/OpenSim.32BitLaunch/**"/> <include name="bin/*.so" />
<exclude name="Tools/Robust.32BitLaunch/**"/> <include name="bin/*.config" />
<exclude name="Tools/LaunchSLClient/**"/> <include name="bin/assets/**" />
</fileset> <include name="bin/data/**" />
</delete> <include name="bin/OpenSim*xml" />
<delete> <!-- the next is to exclude built libs -->
<fileset> <exclude name="bin/OpenSim.*dll" />
<include name="OpenSim.build"/> <include name="bin/OpenSim.ini" />
<include name="OpenSim.sln"/> <include name="bin/defaultstripe.png" />
</fileset>
</delete>
</target>
<property name="distbindir" value="distbin" />
<!-- This target produces a binary directory called distbin/ in OpenSim/bin which contains everything needed for binary distribution -->
<!-- For safety/laziness sake, we're going to take the approach of deleting known extraneous files here rather than
trying to copy across only the essential ones -->
<target name="distbin">
<delete dir="${distbindir}"/>
<copy todir="${distbindir}">
<fileset>
<include name="**"/>
</fileset> </fileset>
</copy> </copy>
<delete dir="${distbindir}/OpenSim"/> <touch file="${projectdir}/bin/startup_commands.txt" />
<delete dir="${distbindir}/Prebuild"/>
<delete dir="${distbindir}/%temp%"/>
<delete dir="${distbindir}/.nant"/>
<delete dir="${distbindir}/ThirdParty"/>
<delete>
<fileset basedir="${distbindir}">
<include name="compile.bat"/>
<include name="BUILDING.md"/>
<include name="Makefile"/>
<include name="nant-color"/>
<include name="OpenSim.*"/>
<include name="prebuild.xml"/>
<include name="runprebuild*"/>
<include name="TESTING.txt"/>
<include name="TestResult.xml"/>
<include name="bin/OpenSim.Server.ini"/>
<include name="bin/Regions/Regions.ini"/>
<include name="bin/*.db"/>
<include name="**/.git/**"/>
<include name=".gitignore"/>
<include name=".hgignore"/>
</fileset>
</delete>
</target> </target>
<target name="test" depends="build, find-nunit"> <target name="test" depends="build">
<setenv name="MONO_THREADS_PER_CPU" value="100" /> <nunit2 failonerror="true" verbose="true">
<formatter type="Plain" />
<test>
<assemblies>
<include name="./bin/OpenSim.Framework.Tests.dll" />
<include name="./bin/OpenSim.Framework.Communications.Tests.dll"/>
<include name="./bin/OpenSim.Framework.Servers.Tests.dll" />
<include name="./bin/OpenSim.Region.ClientStack.LindenUDP.Tests.dll" />
<include name="./bin/OpenSim.Region.ScriptEngine.Shared.Tests.dll" />
<include name="./bin/OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests.dll" />
<include name="./bin/OpenSim.Region.Environment.Tests.dll" />
<include name="./bin/OpenSim.Data.SQLite.Tests.dll" />
<include name="./bin/OpenSim.Data.MySQL.Tests.dll" />
</assemblies>
</test>
</nunit2>
</target>
<!-- Unit Test Assembly --> <target name="test-cov" depends="build">
<!-- if you want to add more unit tests it's important that you add <!-- Code Coverage Test. Prototype, only works with mono 1.2. Instructions in http://opensimulator.org/wiki/Automated_Testing -->
the assembly here as an exec, and you add the fail clause later. <mkdir dir="cov" failonerror="false" />
This lets all the unit tests run and tells you if they fail at the <exec program="mono">
end, instead of stopping short --> <arg value="--debug" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests"> <arg value="--profile=monocov:outfile=./cov/OpenSim.Framework.Servers.cov,+[OpenSim.Framework.Servers]" />
<arg value="./bin/OpenSim.Tests.dll" /> <arg value="/usr/lib/nunit/nunit-console.exe" />
</exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.tests)==0}" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.framework.tests">
<arg value="./bin/OpenSim.Framework.Tests.dll" />
</exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.framework.tests)==0}" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.framework.servers.tests">
<arg value="./bin/OpenSim.Framework.Servers.Tests.dll" /> <arg value="./bin/OpenSim.Framework.Servers.Tests.dll" />
</exec> </exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.framework.servers.tests)==0}" /> <delete dir="./cov/OpenSim.Framework.Servers" />
<exec program="monocov">
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.framework.serialization.tests"> <arg value="--export-html=./cov/OpenSim.Framework.Servers ./cov/OpenSim.Framework.Servers.cov" />
<arg value="./bin/OpenSim.Framework.Serialization.Tests.dll" />
</exec> </exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.framework.serialization.tests)==0}" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.region.clientstack.lindencaps.tests"> <exec program="mono">
<arg value="./bin/OpenSim.Region.ClientStack.LindenCaps.Tests.dll" /> <arg value="--debug" />
<arg value="--profile=monocov:outfile=./cov/OpenSim.Framework.Communications.cov,+[OpenSim.Framework.Communications]" />
<arg value="/usr/lib/nunit/nunit-console.exe" />
<arg value="./bin/OpenSim.Framework.Communications.Tests.dll" />
</exec>
<delete dir="./cov/OpenSim.Framework.Communications" />
<exec program="monocov">
<arg value="--export-html=./cov/OpenSim.Framework.Servers ./cov/OpenSim.Framework.Communications.cov" />
</exec> </exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.clientstack.lindencaps.tests)==0}" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.region.clientstack.lindenudp.tests"> <exec program="mono">
<arg value="--debug" />
<arg value="--profile=monocov:outfile=./cov/OpenSim.Region.ClientStack.LindenUDP.cov,+[OpenSim.Region.ClientStack.LindenUDP]" />
<arg value="/usr/lib/nunit/nunit-console.exe" />
<arg value="./bin/OpenSim.Region.ClientStack.LindenUDP.Tests.dll" /> <arg value="./bin/OpenSim.Region.ClientStack.LindenUDP.Tests.dll" />
</exec> </exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.clientstack.lindenudp.tests)==0}" /> <delete dir="./cov/OpenSim.Region.ClientStack.LindenUDP" />
<exec program="monocov">
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.region.scriptengine.tests"> <arg value="--export-html=./cov/OpenSim.Region.ClientStack.LindenUDP ./cov/OpenSim.Region.ClientStack.LindenUDP.cov" />
<arg value="./bin/OpenSim.Region.ScriptEngine.Tests.dll" />
</exec> </exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.scriptengine.tests)==0}" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.region.coremodules.tests"> <exec program="mono">
<arg value="./bin/OpenSim.Region.CoreModules.Tests.dll" /> <arg value="--debug" />
<arg value="--profile=monocov:outfile=./cov/OpenSim.Region.ScriptEngine.Shared.cov,+[OpenSim.Region.ScriptEngine.Shared]" />
<arg value="/usr/lib/nunit/nunit-console.exe" />
<arg value="./bin/OpenSim.Region.ScriptEngine.Shared.Tests.dll" />
</exec> </exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.coremodules.tests)==0}" /> <delete dir="./cov/OpenSim.Region.ScriptEngine.Shared" />
<exec program="monocov">
<!-- <arg value="--export-html=./cov/OpenSim.Region.ScriptEngine.Shared ./cov/OpenSim.Region.ScriptEngine.Shared.cov" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.region.optionalmodules.tests">
<arg value="./bin/OpenSim.Region.OptionalModules.Tests.dll" />
</exec> </exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.optionalmodules.tests)==0}" />
-->
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.region.framework.tests"> <exec program="mono">
<arg value="./bin/OpenSim.Region.Framework.Tests.dll" /> <arg value="--debug" />
<arg value="--profile=monocov:outfile=./cov/OpenSim.Region.ScriptEngine.Shared.CodeTools.cov,+[OpenSim.Region.ScriptEngine.Shared.CodeTools]" />
<arg value="/usr/lib/nunit/nunit-console.exe" />
<arg value="./bin/OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests.dll" />
</exec> </exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.framework.tests)==0}" /> <delete dir="./cov/OpenSim.Region.ScriptEngine.Shared.CodeTools" />
<exec program="monocov">
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.data.tests"> <arg value="--export-html=./cov/OpenSim.Region.ScriptEngine.Shared.CodeTools ./cov/OpenSim.Region.ScriptEngine.Shared.CodeTools.cov" />
<arg value="./bin/OpenSim.Data.Tests.dll" />
</exec> </exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.data.tests)==0}" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.capabilities.handlers.tests"> <exec program="mono">
<arg value="./bin/OpenSim.Capabilities.Handlers.Tests.dll" /> <arg value="--debug" />
<arg value="--profile=monocov:outfile=./cov/OpenSim.Region.Environment.cov,+[OpenSim.Region.Environment]" />
<arg value="/usr/lib/nunit/nunit-console.exe" />
<arg value="./bin/OpenSim.Region.Environment.Tests.dll" />
</exec> </exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.capabilities.handlers.tests)==0}" /> <delete dir="./cov/OpenSim.Region.Environment" />
<exec program="monocov">
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.server.handlers.tests"> <arg value="--export-html=./cov/OpenSim.Region.Environment ./cov/OpenSim.Region.Environment.cov" />
<arg value="./bin/OpenSim.Server.Handlers.Tests.dll" />
</exec> </exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.server.handlers.tests)==0}" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.services.inventoryservice.tests"> <exec program="mono">
<arg value="./bin/OpenSim.Services.InventoryService.Tests.dll" /> <arg value="--debug" />
<arg value="--profile=monocov:outfile=./cov/OpenSim.Data.SQLite.cov,+[OpenSim.Data.SQLite]" />
<arg value="/usr/lib/nunit/nunit-console.exe" />
<arg value="./bin/OpenSim.Data.SQLite.Tests.dll" />
</exec> </exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.services.inventoryservice.tests)==0}" /> <delete dir="./cov/OpenSim.Data.SQLite" />
<exec program="monocov">
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests.permissions"> <arg value="--export-html=./cov/OpenSim.Data.SQLite ./cov/OpenSim.Data.SQLite.cov" />
<arg value="./bin/OpenSim.Tests.Permissions.dll" />
</exec> </exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.tests.permissions)==0}" />
<delete dir="%temp%"/> <exec program="mono">
<arg value="--debug" />
<arg value="--profile=monocov:outfile=./cov/OpenSim.Data.MySQL.cov,+[OpenSim.Data.MySQL.Tests]" />
<arg value="/usr/lib/nunit/nunit-console.exe" />
<arg value="./bin/OpenSim.Data.MySQL.Tests.dll" />
</exec>
<delete dir="./cov/OpenSim.Data.MySQL" />
<exec program="monocov">
<arg value="--export-html=./cov/OpenSim.Data.MySQL ./cov/OpenSim.Data.MySQL.cov" />
</exec>
<delete file="C:\NUnitPrimaryTrace.txt" failonerror="false" />
<delete file="TestResult.xml" failonerror="false" />
</target> </target>
<target name="test-stress" depends="build, find-nunit">
<setenv name="MONO_THREADS_PER_CPU" value="100" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests.stress"> <target name="test-xml" depends="build">
<arg value="./bin/OpenSim.Tests.Stress.dll" /> <nunit2 failonerror="true" verbose="true">
</exec> <formatter type="Xml" usefile="true" extension=".xml" outputdir="./test-results" />
<test>
<fail message="Failures reported in stress tests." unless="${int::parse(testresult.opensim.tests.stress)==0}" /> <assemblies>
<delete dir="%temp%"/> <include name="./bin/OpenSim.Framework.Tests.dll" />
</target> <include name="./bin/OpenSim.Framework.Communications.Tests.dll"/>
<include name="./bin/OpenSim.Framework.Servers.Tests.dll" />
<target name="test-perf" depends="build, find-nunit"> <include name="./bin/OpenSim.Region.ClientStack.LindenUDP.Tests.dll" />
<setenv name="MONO_THREADS_PER_CPU" value="100" /> <include name="./bin/OpenSim.Region.ScriptEngine.Shared.Tests.dll" />
<include name="./bin/OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests.dll" />
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests.performance"> <include name="./bin/OpenSim.Region.Environment.Tests.dll" />
<arg value="./bin/OpenSim.Tests.Performance.dll" /> <include name="./bin/OpenSim.Data.SQLite.Tests.dll" />
</exec> <include name="./bin/OpenSim.Data.MySQL.Tests.dll" />
</assemblies>
<fail message="Failures reported in performance tests." unless="${int::parse(testresult.opensim.tests.performance)==0}" /> </test>
<delete dir="%temp%"/> </nunit2>
</target>
<target name="find-nunit">
<exec program="which" failonerror="false"
resultproperty="hasnunit2">
<arg value="nunit-console2" />
</exec>
<property name="nunitcmd" value="nunit-console2"
if="${int::parse(hasnunit2)==0}" />
<property name="nunitcmd" value="nunit-console"
if="${int::parse(hasnunit2)==1}" />
</target>
<!-- this is used for panda test execution -->
<!-- work in progress -->
<target name="test-xml" depends="build, find-nunit">
<mkdir dir="test-results" failonerror="false" />
<!-- Unit Test Assembly -->
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.tests">
<arg value="./bin/OpenSim.Tests.dll" />
<arg value="-xml=test-results/OpenSim.Tests.dll-Results.xml" />
</exec>
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.framework.tests">
<arg value="./bin/OpenSim.Framework.Tests.dll" />
<arg value="-xml=test-results/OpenSim.Framework.Tests.dll-Results.xml" />
</exec>
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.framework.serialization.tests">
<arg value="./bin/OpenSim.Framework.Serialization.Tests.dll" />
<arg value="-xml=test-results/OpenSim.Framework.Serialization.Tests.dll-Results.xml" />
</exec>
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.framework.servers.tests">
<arg value="./bin/OpenSim.Framework.Servers.Tests.dll" />
<arg value="-xml=test-results/OpenSim.Framework.Servers.Tests.dll-Results.xml" />
</exec>
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.region.clientstack.lindencaps.tests">
<arg value="./bin/OpenSim.Region.ClientStack.LindenCaps.Tests.dll" />
<arg value="-xml=test-results/OpenSim.Region.ClientStack.LindenCaps.Tests.dll-Results.xml" />
</exec>
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.region.clientstack.lindenudp.tests">
<arg value="./bin/OpenSim.Region.ClientStack.LindenUDP.Tests.dll" />
<arg value="-xml=test-results/OpenSim.Region.ClientStack.LindenUDP.Tests.dll-Results.xml" />
</exec>
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.region.scriptengine.tests">
<arg value="./bin/OpenSim.Region.ScriptEngine.Tests.dll" />
<arg value="-xml=test-results/OpenSim.Region.ScriptEngine.Tests.dll-Results.xml" />
</exec>
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.region.coremodules.tests">
<arg value="./bin/OpenSim.Region.CoreModules.Tests.dll" />
<arg value="-xml=test-results/OpenSim.Region.CoreModules.Tests.dll-Results.xml" />
</exec>
<!--
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.region.optionalmodules.tests">
<arg value="./bin/OpenSim.Region.OptionalModules.Tests.dll" />
<arg value="-xml=test-results/OpenSim.Region.OptionalModules.Tests.dll-Results.xml" />
</exec>
-->
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.region.framework.tests">
<arg value="./bin/OpenSim.Region.Framework.Tests.dll" />
<arg value="-xml=test-results/OpenSim.Region.Framework.Tests.dll-Results.xml" />
</exec>
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.data.tests">
<arg value="./bin/OpenSim.Data.Tests.dll" />
<arg value="-xml=test-results/OpenSim.Data.Tests.dll-Results.xml" />
</exec>
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.capabilities.handlers.tests">
<arg value="./bin/OpenSim.Capabilities.Handlers.Tests.dll" />
<arg value="-xml=test-results/OpenSim.Capabilities.Handlers.Tests.dll-Results.xml" />
</exec>
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.server.handlers.tests">
<arg value="./bin/OpenSim.Server.Handlers.Tests.dll" />
<arg value="-xml=test-results/OpenSim.Server.Handlers.Tests.dll-Results.xml" />
</exec>
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.services.inventoryservice.tests">
<arg value="./bin/OpenSim.Services.InventoryService.Tests.dll" />
<arg value="-xml=test-results/OpenSim.Services.InventoryService.Tests.dll-Results.xml" />
</exec>
<exec program="${nunitcmd}" failonerror="false" resultproperty="testresult.opensim.tests.permissions">
<arg value="./bin/OpenSim.Tests.Permissions.dll" />
<arg value="-xml=test-results/OpenSim.Tests.Permissions.dll-Results.xml" />
</exec>
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.tests)==0}" />
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.framework.tests)==0}" />
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.framework.servers.tests)==0}" />
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.clientstack.lindenudp.tests)==0}" />
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.scriptengine.tests)==0}" />
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.coremodules.tests)==0}" />
<!-- <fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.optionalmodules.tests)==0}" /> -->
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.framework.tests)==0}" />
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.data.tests)==0}" />
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.capabilities.handlers.tests)==0}" />
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.services.inventoryservice.tests)==0}" />
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.tests.permissions)==0}" />
</target> </target>
<target name="doxygen"> <target name="doxygen">
<exec program="doxygen" workingdir="doc" commandline="doxygen.conf" /> <exec program="doxygen" workingdir="doc" commandline="doxygen.conf" />
</target> </target>
<target name="dist" depends="distdir">
<zip zipfile="${projectdir}.zip">
<fileset basedir=".">
<include name="${projectdir}/**" />
</fileset>
</zip>
<tar destfile="${projectdir}.tar.gz" compression="GZip">
<fileset basedir=".">
<include name="${projectdir}/**" />
</fileset>
</tar>
</target>

View File

@ -1,37 +0,0 @@
# Building on Windows
Steps:
* runprebuild.bat
* Load OpenSim.sln into Visual Studio .NET and build the solution.
* chdir bin
* copy OpenSim.ini.example to OpenSim.ini and other appropriate files in bin/config-include
* run OpenSim.exe
# Building on Linux / Mac
Prereqs:
* Mono > 5.0
* On some Linux distributions you may need to install additional packages.
* msbuild or xbuild if still supported by the mono version
* See http://opensimulator.org/wiki/Dependencies for more information.
From the distribution type:
* ./runprebuild.sh
* type msbuild or xbuild
* cd bin
* copy OpenSim.ini.example to OpenSim.ini and other appropriate files in bin/config-include
* review and change those ini files according to your needs
* windows: execute opensim.exe or opensim32.exe for small regions
* linux: run ./opensim.sh
* msbuild (xbuild) option switches
* clean: msbuild /target:clean
* debug: (default) msbuild /property:Configuration=Debug
* release: msbuild /property:Configuration=Release
# References
Helpful resources:
* http://opensimulator.org/wiki/Build_Instructions

View File

@ -1,252 +1,119 @@
The following people have contributed to OpenSim (Thank you for your effort!) The following people have contributed to OpenSim (Thank you
for your effort!)
= Current OpenSim Developers (in very rough order of appearance) = Add your name in here if you have committed to OpenSim
These folks represent the current core team for OpenSim, and are the
people that make the day to day of OpenSim happen.
* Melanie Thielker OpenSim Developers
* Diva (Crista Lopes, University of California, Irvine)
* Robert Adams (MisterBlue)
* Kevin Cozens
* Leal Duarte (Ubit Umarov)
= Core Developers Following the White Rabbit = * MW (Tribal Media AB)
Core developers who have temporarily (we hope) gone chasing the white rabbit. * Adam Frisby (DeepThink Pty Ltd)
They are in all similar to the active core developers, except that they haven't * MingChen (DeepThink Pty Ltd)
been that active lately, so their voting rights are awaiting their come back. * lbsa71 (Tribal Media AB)
* sdague (IBM)
* Nebadon Izumi (Michael Cerquoni, OSgrid)
* Alicia Raven
= Past Open Sim Developers =
These folks are alumns of the OpenSim core group, but are now
currently not active. Their great contributions helped get us to
where we are today.
* Gareth
* Andy- * Andy-
* Gareth
* MorphW * MorphW
* CW * CW
* Babblefrog * Babblefrog
* Tedd
* justincc (Black Dress Technology)
* Teravus (w3z)
* Johan Berntsson (3Di)
* Ckrinke (Charles Krinke)
* Danx0r * Danx0r
* Dalien * Dalien
* Darok * Darok
* Alondria
* Sean Dague / sdague (IBM)
* Tedd
* MingChen (DeepThink Pty Ltd)
* adjohn (Genkii)
* idb (Ian Brown)
* Johan Berntsson (3Di)
* MW (Tribal Media AB)
* Adam Frisby (DeepThink Pty Ltd)
* lbsa71 (Tribal Media AB)
* Ckrinke (Charles Krinke)
* Dr Scofield aka Dirk Husemann (IBM Research - Zurich)
* mikem (3Di)
* Homer_Horwitz
* nlin (3Di)
* John Hurliman
* chi11ken (Genkii) * chi11ken (Genkii)
* adjohn (Genkii)
* Alondria
* Dr Scofield (IBM)
* dahlia * dahlia
* justincc (OSVW Consulting, justincc.org) * mikem (3Di)
* Arthur Rodrigo S Valadares (IBM) * Melanie Thielker
* BlueWall (James Hughes) * Homer_Horwitz
* Dan Lake * idb (Ian Brown)
* Marck * Diva (Crista Lopes, University of California, Irvine)
* Mic Bowman
* Oren Hurvitz (Kitely)
* Snoopy Pfeffer
* Teravus (w3z)
= Additional OpenSim Contributors =
These folks have contributed code patches or content to OpenSimulator to help make it Patches
what it is today.
* A_Biondi * A_Biondi
* aduffy70
* Ai Austin
* alex_carnell * alex_carnell
* Alan Webb (IBM) * awebb (IBM)
* Aleric
* Allen Kerensky
* BigFootAg * BigFootAg
* Bill Blight
* BlueWall Slade
* bobshaffer2
* brianw/Sir_Ahzz * brianw/Sir_Ahzz
* CharlieO * CharlieO
* ChrisDown * ChrisDown
* Chris Yeoh (IBM) * Chris Yeoh
* cinderblocks
* controlbreak
* coyled
* ctrlaltdavid (David Rowe)
* Daedius * Daedius
* daTwitch * daTwitch
* Dev Random
* devalnor-#708 * devalnor-#708
* dmiles (Daxtron Labs) * dmiles (Daxtron Labs)
* Dong Jun Lan (IBM)
* DoranZemlja
* Drake Arconis
* dr0b3rts
* dslake
* eeyore
* FredoChaplin
* FreakyTech
* Garmin Kawaguichi
* Gavin Hird
* Gerhard * Gerhard
* Godfrey * Godfrey
* Greg C.
* Grumly57 * Grumly57
* GuduleLapointe
* Ewe Loon
* Fernando Oliveira
* Fly-Man * Fly-Man
* Flyte Xevious
* Freaky Tech
* Garmin Kawaguichi
* Geir Noklebye
* Glenn Martin (MOSES)
* Gryc Ueusp
* H-H-H (ginge264)
* Hiro Lecker
* Iain Oliver
* Imaze Rhiano
* Intimidated
* Jak Daniels
* Jeff Kelly
* Jeremy Bongio (IBM)
* jhurliman * jhurliman
* jimbo2120 (IBM)
* John R Sohn (XenReborn) * John R Sohn (XenReborn)
* jonc * jonc
* Jon Cundill
* Junta Kohime * Junta Kohime
* Kayne * Kayne
* Kevin Cozens
* kinoc (Daxtron Labs) * kinoc (Daxtron Labs)
* Kira * krtaylor (IBM)
* Kitto Flora
* KittyLiu
* Kurt Taylor (IBM)
* Lani Global
* lickx
* lillith_xue
* lkalif
* LuciusSirnah
* lulurun * lulurun
* M.Igarashi * M.Igarashi
* Magnuz Binder
* maimedleech
* Mana Janus
* Mandarinka Tasty
* MarcelEdward
* Matt Lehmann
* mewtwo0641
* Mic Bowman * Mic Bowman
* Michelle Argus
* Michael Cortez (The Flotsam Project, http://osflotsam.org/)
* Michael Heilmann (MOSES)
* Micheil Merlin
* Mike Osias (IBM)
* Mike Pitman (IBM)
* Mike Rieker (Dreamnation)
* mikemig
* mikkopa/_someone - RealXtend * mikkopa/_someone - RealXtend
* Misterblue
* Mircea Kitsune * Mircea Kitsune
* mpallari * nlin
* MrMonkE
* Nebadon Izumi (Michael Cerquoni - http://OSgrid.org)
* Neil Canham
* nornalbion * nornalbion
* Omar Vera Ustariz (IBM)
* openlifegrid.com * openlifegrid.com
* otakup0pe
* Pixel Tomsen
* Quill Littlefeather
* ralphos * ralphos
* RemedyTomm
* Revolution
* Richard Alimi (IBM)
* Rick Alther (IBM)
* Rob Smart (IBM)
* Robert Louden (MOSES)
* Roger Kirkman (zadark)
* rtomita
* Ruud Lathorp * Ruud Lathorp
* SachaMagne * SachaMagne
* Salahzar Stenvaag * Salahzar Stenvaag
* satguru p srivastava
* sempuki * sempuki
* Shy Robbiani
* SignpostMarv
* SpotOn3D
* Stefan_Boom / stoehr
* Steven Zielinski (MOSES)
* Stolen Ruby
* Strawberry Fride
* Talun
* TechplexEngineer (Blake Bourque)
* TBG Renfold
* Terry Ford
* tglion * tglion
* tlaukkan/Tommil (Tommi S. E. Laukkanen, Bubble Cloud)
* TomDataWorks
* TomTheDragon (muckwaddle)
* tyre * tyre
* uriesk
* Vegaslon <vegaslon@gmail.com>
* Vincent Sylvester
* VikingErik
* Vytek * Vytek
* webmage (IBM) * webmage (IBM)
* Xantor * Xantor
* Y. Nitta * Y. Nitta
* YoshikoFazuku
* YZh * YZh
* Zackary Geers aka Kunnis Basiat
* Zha Ewry * Zha Ewry
* ziah
= LSL Devs =
LSL Devs
* Alondria * Alondria
* CharlieO * CharlieO
* Tedd * Tedd
* Melanie Thielker * Melanie Thielker
= Testers =
Testers
* Ai Austin * Ai Austin
* CharlieO (LSL) * CharlieO (LSL)
* Ckrinke * Ckrinke
* openlifegrid.com * openlifegrid.com
This software uses components from the following developers: This software uses components from the following developers:
* Sleepycat Software (Berkeley DB) * Sleepycat Software (Berkeley DB)
* Aurora-Sim (http://aurora-sim.org) * DB4objects, Inc. (DB4o)
* SQLite (Public Domain) * SQLite (Public Domain)
* XmlRpcCS (http://xmlrpccs.sf.net/) * XmlRpcCS (http://xmlrpccs.sf.net/)
* MySQL, Inc. (MySQL Connector/NET) * MySQL, Inc. (MySQL Connector/NET)
* NUnit (http://www.nunit.org) * NUnit (http://www.nunit.org)
* AGEIA Inc. (PhysX) * AGEIA Inc. (PhysX)
* Russel L. Smith (ODE) * Russel L. Smith (ODE)
* Erwin Coumans (Bullet)
* Prebuild (http://sourceforge.net/projects/dnpb/) * Prebuild (http://sourceforge.net/projects/dnpb/)
* LibOpenMetaverse (http://lib.openmetaverse.org/) * LibSecondLife (http://www.libsecondlife.org/wiki/Main_Page)
* DotNetOpenMail v0.5.8b (http://dotnetopenmail.sourceforge.net) * DotNetOpenMail v0.5.8b (http://dotnetopenmail.sourceforge.net)
* Prototype JavaScript Framework ajax (http://www.prototypejs.org/)
* C5 GENERIC COLLECTION LIBRARY FOR C#/CLI
* Nini (http://nini.sourceforge.net/)
* log4net (http://logging.apache.org/log4net/)
* GlynnTucker.Cache (http://gtcache.sourceforge.net/)
* NDesk.Options 0.2.1 (http://www.ndesk.org/Options)
* Json.NET 3.5 Release 6. The binary used is actually Newtonsoft.Json.Net20.dll for Mono 2.4 compatability (http://james.newtonking.com/projects/json-net.aspx)
* zlib.net for C# 1.0.4 (http://www.componentace.com/zlib_.NET.htm)
Some plugins are based on Cable Beach
Cable Beach is Copyright (c) 2008 Intel Corporation
see http://forge.opensimulator.org/gf/project/assetserver/
In addition, we would like to thank: In addition, we would like to thank:
* The Mono Project * The Mono Project

View File

@ -8,7 +8,7 @@ modification, are permitted provided that the following conditions are met:
* Redistributions in binary form must reproduce the above copyright * Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution. documentation and/or other materials provided with the distribution.
* Neither the name of the OpenSimulator Project nor the * Neither the name of the OpenSim Project nor the
names of its contributors may be used to endorse or promote products names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission. derived from this software without specific prior written permission.

View File

@ -1,30 +1,16 @@
# hey, emacs! this is a -*- makefile -*-
#
# OpenSim makefile
#
RUBY = $(strip $(shell which ruby 2>/dev/null))
ifeq ($(RUBY),)
NANT = nant
else
NANT = $(shell if test "$$EMACS" = "t" ; then echo "nant"; else echo "./nant-color"; fi) NANT = $(shell if test "$$EMACS" = "t" ; then echo "nant"; else echo "./nant-color"; fi)
endif
all: prebuild all: prebuild
# @export PATH=/usr/local/bin:$(PATH) # @export PATH=/usr/local/bin:$(PATH)
${NANT} ${NANT}
find OpenSim -name \*.mdb -exec cp {} bin \; find OpenSim -name \*.mdb -exec cp {} bin \;
release: prebuild
${NANT} -D:project.config=Release
find OpenSim -name \*.mdb -exec cp {} bin \;
prebuild: prebuild:
./runprebuild.sh ./runprebuild.sh
clean: clean:
# @export PATH=/usr/local/bin:$(PATH) # @export PATH=/usr/local/bin:$(PATH)
-${NANT} clean ${NANT} clean
test: prebuild test: prebuild
${NANT} test ${NANT} test
@ -35,9 +21,3 @@ test-xml: prebuild
tags: tags:
find OpenSim -name \*\.cs | xargs etags find OpenSim -name \*\.cs | xargs etags
cscope-tags:
find OpenSim -name \*\.cs -fprint cscope.files
cscope -b
include $(wildcard Makefile.local)

7241
OpenSim.FxCop Normal file

File diff suppressed because it is too large Load Diff

View File

@ -1,78 +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 OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Services.Interfaces;
namespace OpenSim.Groups
{
public class ForeignImporter
{
IUserManagement m_UserManagement;
public ForeignImporter(IUserManagement uman)
{
m_UserManagement = uman;
}
public GroupMembersData ConvertGroupMembersData(ExtendedGroupMembersData _m)
{
GroupMembersData m = new GroupMembersData();
m.AcceptNotices = _m.AcceptNotices;
m.AgentPowers = _m.AgentPowers;
m.Contribution = _m.Contribution;
m.IsOwner = _m.IsOwner;
m.ListInProfile = _m.ListInProfile;
m.OnlineStatus = _m.OnlineStatus;
m.Title = _m.Title;
string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty;
Util.ParseUniversalUserIdentifier(_m.AgentID, out m.AgentID, out url, out first, out last, out tmp);
if (url != string.Empty)
m_UserManagement.AddUser(m.AgentID, first, last, url);
return m;
}
public GroupRoleMembersData ConvertGroupRoleMembersData(ExtendedGroupRoleMembersData _rm)
{
GroupRoleMembersData rm = new GroupRoleMembersData();
rm.RoleID = _rm.RoleID;
string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty;
Util.ParseUniversalUserIdentifier(_rm.MemberID, out rm.MemberID, out url, out first, out last, out tmp);
if (url != string.Empty)
m_UserManagement.AddUser(rm.MemberID, first, last, url);
return rm;
}
}
}

View File

@ -1,533 +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 OpenSim.Framework;
using OpenMetaverse;
namespace OpenSim.Groups
{
public class ExtendedGroupRecord : GroupRecord
{
public int MemberCount;
public int RoleCount;
public string ServiceLocation;
public string FounderUUI;
}
public class ExtendedGroupMembershipData : GroupMembershipData
{
public string AccessToken;
}
public class ExtendedGroupMembersData
{
// This is the only difference: this is a string
public string AgentID;
public int Contribution;
public string OnlineStatus;
public ulong AgentPowers;
public string Title;
public bool IsOwner;
public bool ListInProfile;
public bool AcceptNotices;
public string AccessToken;
}
public class ExtendedGroupRoleMembersData
{
public UUID RoleID;
// This is the only difference: this is a string
public string MemberID;
}
public struct ExtendedGroupNoticeData
{
public UUID NoticeID;
public uint Timestamp;
public string FromName;
public string Subject;
public bool HasAttachment;
public byte AttachmentType;
public string AttachmentName;
public UUID AttachmentItemID;
public string AttachmentOwnerID;
public GroupNoticeData ToGroupNoticeData()
{
GroupNoticeData n = new GroupNoticeData();
n.FromName = this.FromName;
n.AssetType = this.AttachmentType;
n.HasAttachment = this.HasAttachment;
n.NoticeID = this.NoticeID;
n.Subject = this.Subject;
n.Timestamp = this.Timestamp;
return n;
}
}
public class GroupsDataUtils
{
public static string Sanitize(string s)
{
return s == null ? string.Empty : s;
}
public static Dictionary<string, object> GroupRecord(ExtendedGroupRecord grec)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
if (grec == null)
return dict;
dict["AllowPublish"] = grec.AllowPublish.ToString();
dict["Charter"] = Sanitize(grec.Charter);
dict["FounderID"] = grec.FounderID.ToString();
dict["FounderUUI"] = Sanitize(grec.FounderUUI);
dict["GroupID"] = grec.GroupID.ToString();
dict["GroupName"] = Sanitize(grec.GroupName);
dict["InsigniaID"] = grec.GroupPicture.ToString();
dict["MaturePublish"] = grec.MaturePublish.ToString();
dict["MembershipFee"] = grec.MembershipFee.ToString();
dict["OpenEnrollment"] = grec.OpenEnrollment.ToString();
dict["OwnerRoleID"] = grec.OwnerRoleID.ToString();
dict["ServiceLocation"] = Sanitize(grec.ServiceLocation);
dict["ShownInList"] = grec.ShowInList.ToString();
dict["MemberCount"] = grec.MemberCount.ToString();
dict["RoleCount"] = grec.RoleCount.ToString();
return dict;
}
public static ExtendedGroupRecord GroupRecord(Dictionary<string, object> dict)
{
if (dict == null)
return null;
ExtendedGroupRecord grec = new ExtendedGroupRecord();
if (dict.ContainsKey("AllowPublish") && dict["AllowPublish"] != null)
grec.AllowPublish = bool.Parse(dict["AllowPublish"].ToString());
if (dict.ContainsKey("Charter") && dict["Charter"] != null)
grec.Charter = dict["Charter"].ToString();
else
grec.Charter = string.Empty;
if (dict.ContainsKey("FounderID") && dict["FounderID"] != null)
grec.FounderID = UUID.Parse(dict["FounderID"].ToString());
if (dict.ContainsKey("FounderUUI") && dict["FounderUUI"] != null)
grec.FounderUUI = dict["FounderUUI"].ToString();
else
grec.FounderUUI = string.Empty;
if (dict.ContainsKey("GroupID") && dict["GroupID"] != null)
grec.GroupID = UUID.Parse(dict["GroupID"].ToString());
if (dict.ContainsKey("GroupName") && dict["GroupName"] != null)
grec.GroupName = dict["GroupName"].ToString();
else
grec.GroupName = string.Empty;
if (dict.ContainsKey("InsigniaID") && dict["InsigniaID"] != null)
grec.GroupPicture = UUID.Parse(dict["InsigniaID"].ToString());
if (dict.ContainsKey("MaturePublish") && dict["MaturePublish"] != null)
grec.MaturePublish = bool.Parse(dict["MaturePublish"].ToString());
if (dict.ContainsKey("MembershipFee") && dict["MembershipFee"] != null)
grec.MembershipFee = Int32.Parse(dict["MembershipFee"].ToString());
if (dict.ContainsKey("OpenEnrollment") && dict["OpenEnrollment"] != null)
grec.OpenEnrollment = bool.Parse(dict["OpenEnrollment"].ToString());
if (dict.ContainsKey("OwnerRoleID") && dict["OwnerRoleID"] != null)
grec.OwnerRoleID = UUID.Parse(dict["OwnerRoleID"].ToString());
if (dict.ContainsKey("ServiceLocation") && dict["ServiceLocation"] != null)
grec.ServiceLocation = dict["ServiceLocation"].ToString();
else
grec.ServiceLocation = string.Empty;
if (dict.ContainsKey("ShownInList") && dict["ShownInList"] != null)
grec.ShowInList = bool.Parse(dict["ShownInList"].ToString());
if (dict.ContainsKey("MemberCount") && dict["MemberCount"] != null)
grec.MemberCount = Int32.Parse(dict["MemberCount"].ToString());
if (dict.ContainsKey("RoleCount") && dict["RoleCount"] != null)
grec.RoleCount = Int32.Parse(dict["RoleCount"].ToString());
return grec;
}
public static Dictionary<string, object> GroupMembershipData(ExtendedGroupMembershipData membership)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
if (membership == null)
return dict;
dict["AcceptNotices"] = membership.AcceptNotices.ToString();
dict["AccessToken"] = Sanitize(membership.AccessToken);
dict["Active"] = membership.Active.ToString();
dict["ActiveRole"] = membership.ActiveRole.ToString();
dict["AllowPublish"] = membership.AllowPublish.ToString();
dict["Charter"] = Sanitize(membership.Charter);
dict["Contribution"] = membership.Contribution.ToString();
dict["FounderID"] = membership.FounderID.ToString();
dict["GroupID"] = membership.GroupID.ToString();
dict["GroupName"] = Sanitize(membership.GroupName);
dict["GroupPicture"] = membership.GroupPicture.ToString();
dict["GroupPowers"] = membership.GroupPowers.ToString();
dict["GroupTitle"] = Sanitize(membership.GroupTitle);
dict["ListInProfile"] = membership.ListInProfile.ToString();
dict["MaturePublish"] = membership.MaturePublish.ToString();
dict["MembershipFee"] = membership.MembershipFee.ToString();
dict["OpenEnrollment"] = membership.OpenEnrollment.ToString();
dict["ShowInList"] = membership.ShowInList.ToString();
return dict;
}
public static ExtendedGroupMembershipData GroupMembershipData(Dictionary<string, object> dict)
{
if (dict == null)
return null;
ExtendedGroupMembershipData membership = new ExtendedGroupMembershipData();
if (dict.ContainsKey("AcceptNotices") && dict["AcceptNotices"] != null)
membership.AcceptNotices = bool.Parse(dict["AcceptNotices"].ToString());
if (dict.ContainsKey("AccessToken") && dict["AccessToken"] != null)
membership.AccessToken = dict["AccessToken"].ToString();
else
membership.AccessToken = string.Empty;
if (dict.ContainsKey("Active") && dict["Active"] != null)
membership.Active = bool.Parse(dict["Active"].ToString());
if (dict.ContainsKey("ActiveRole") && dict["ActiveRole"] != null)
membership.ActiveRole = UUID.Parse(dict["ActiveRole"].ToString());
if (dict.ContainsKey("AllowPublish") && dict["AllowPublish"] != null)
membership.AllowPublish = bool.Parse(dict["AllowPublish"].ToString());
if (dict.ContainsKey("Charter") && dict["Charter"] != null)
membership.Charter = dict["Charter"].ToString();
else
membership.Charter = string.Empty;
if (dict.ContainsKey("Contribution") && dict["Contribution"] != null)
membership.Contribution = Int32.Parse(dict["Contribution"].ToString());
if (dict.ContainsKey("FounderID") && dict["FounderID"] != null)
membership.FounderID = UUID.Parse(dict["FounderID"].ToString());
if (dict.ContainsKey("GroupID") && dict["GroupID"] != null)
membership.GroupID = UUID.Parse(dict["GroupID"].ToString());
if (dict.ContainsKey("GroupName") && dict["GroupName"] != null)
membership.GroupName = dict["GroupName"].ToString();
else
membership.GroupName = string.Empty;
if (dict.ContainsKey("GroupPicture") && dict["GroupPicture"] != null)
membership.GroupPicture = UUID.Parse(dict["GroupPicture"].ToString());
if (dict.ContainsKey("GroupPowers") && dict["GroupPowers"] != null)
membership.GroupPowers = UInt64.Parse(dict["GroupPowers"].ToString());
if (dict.ContainsKey("GroupTitle") && dict["GroupTitle"] != null)
membership.GroupTitle = dict["GroupTitle"].ToString();
else
membership.GroupTitle = string.Empty;
if (dict.ContainsKey("ListInProfile") && dict["ListInProfile"] != null)
membership.ListInProfile = bool.Parse(dict["ListInProfile"].ToString());
if (dict.ContainsKey("MaturePublish") && dict["MaturePublish"] != null)
membership.MaturePublish = bool.Parse(dict["MaturePublish"].ToString());
if (dict.ContainsKey("MembershipFee") && dict["MembershipFee"] != null)
membership.MembershipFee = Int32.Parse(dict["MembershipFee"].ToString());
if (dict.ContainsKey("OpenEnrollment") && dict["OpenEnrollment"] != null)
membership.OpenEnrollment = bool.Parse(dict["OpenEnrollment"].ToString());
if (dict.ContainsKey("ShowInList") && dict["ShowInList"] != null)
membership.ShowInList = bool.Parse(dict["ShowInList"].ToString());
return membership;
}
public static Dictionary<string, object> GroupMembersData(ExtendedGroupMembersData member)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
dict["AcceptNotices"] = member.AcceptNotices.ToString();
dict["AccessToken"] = Sanitize(member.AccessToken);
dict["AgentID"] = Sanitize(member.AgentID);
dict["AgentPowers"] = member.AgentPowers.ToString();
dict["Contribution"] = member.Contribution.ToString();
dict["IsOwner"] = member.IsOwner.ToString();
dict["ListInProfile"] = member.ListInProfile.ToString();
dict["OnlineStatus"] = Sanitize(member.OnlineStatus);
dict["Title"] = Sanitize(member.Title);
return dict;
}
public static ExtendedGroupMembersData GroupMembersData(Dictionary<string, object> dict)
{
ExtendedGroupMembersData member = new ExtendedGroupMembersData();
if (dict == null)
return member;
if (dict.ContainsKey("AcceptNotices") && dict["AcceptNotices"] != null)
member.AcceptNotices = bool.Parse(dict["AcceptNotices"].ToString());
if (dict.ContainsKey("AccessToken") && dict["AccessToken"] != null)
member.AccessToken = Sanitize(dict["AccessToken"].ToString());
else
member.AccessToken = string.Empty;
if (dict.ContainsKey("AgentID") && dict["AgentID"] != null)
member.AgentID = Sanitize(dict["AgentID"].ToString());
else
member.AgentID = UUID.Zero.ToString();
if (dict.ContainsKey("AgentPowers") && dict["AgentPowers"] != null)
member.AgentPowers = UInt64.Parse(dict["AgentPowers"].ToString());
if (dict.ContainsKey("Contribution") && dict["Contribution"] != null)
member.Contribution = Int32.Parse(dict["Contribution"].ToString());
if (dict.ContainsKey("IsOwner") && dict["IsOwner"] != null)
member.IsOwner = bool.Parse(dict["IsOwner"].ToString());
if (dict.ContainsKey("ListInProfile") && dict["ListInProfile"] != null)
member.ListInProfile = bool.Parse(dict["ListInProfile"].ToString());
if (dict.ContainsKey("OnlineStatus") && dict["OnlineStatus"] != null)
member.OnlineStatus = Sanitize(dict["OnlineStatus"].ToString());
else
member.OnlineStatus = string.Empty;
if (dict.ContainsKey("Title") && dict["Title"] != null)
member.Title = Sanitize(dict["Title"].ToString());
else
member.Title = string.Empty;
return member;
}
public static Dictionary<string, object> GroupRolesData(GroupRolesData role)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
dict["Description"] = Sanitize(role.Description);
dict["Members"] = role.Members.ToString();
dict["Name"] = Sanitize(role.Name);
dict["Powers"] = role.Powers.ToString();
dict["RoleID"] = role.RoleID.ToString();
dict["Title"] = Sanitize(role.Title);
return dict;
}
public static GroupRolesData GroupRolesData(Dictionary<string, object> dict)
{
GroupRolesData role = new GroupRolesData();
if (dict == null)
return role;
if (dict.ContainsKey("Description") && dict["Description"] != null)
role.Description = Sanitize(dict["Description"].ToString());
else
role.Description = string.Empty;
if (dict.ContainsKey("Members") && dict["Members"] != null)
role.Members = Int32.Parse(dict["Members"].ToString());
if (dict.ContainsKey("Name") && dict["Name"] != null)
role.Name = Sanitize(dict["Name"].ToString());
else
role.Name = string.Empty;
if (dict.ContainsKey("Powers") && dict["Powers"] != null)
role.Powers = UInt64.Parse(dict["Powers"].ToString());
if (dict.ContainsKey("Title") && dict["Title"] != null)
role.Title = Sanitize(dict["Title"].ToString());
else
role.Title = string.Empty;
if (dict.ContainsKey("RoleID") && dict["RoleID"] != null)
role.RoleID = UUID.Parse(dict["RoleID"].ToString());
return role;
}
public static Dictionary<string, object> GroupRoleMembersData(ExtendedGroupRoleMembersData rmember)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
dict["RoleID"] = rmember.RoleID.ToString();
dict["MemberID"] = rmember.MemberID;
return dict;
}
public static ExtendedGroupRoleMembersData GroupRoleMembersData(Dictionary<string, object> dict)
{
ExtendedGroupRoleMembersData rmember = new ExtendedGroupRoleMembersData();
if (dict.ContainsKey("RoleID") && dict["RoleID"] != null)
rmember.RoleID = new UUID(dict["RoleID"].ToString());
if (dict.ContainsKey("MemberID") && dict["MemberID"] != null)
rmember.MemberID = dict["MemberID"].ToString();
return rmember;
}
public static Dictionary<string, object> GroupInviteInfo(GroupInviteInfo invite)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
dict["InviteID"] = invite.InviteID.ToString();
dict["GroupID"] = invite.GroupID.ToString();
dict["RoleID"] = invite.RoleID.ToString();
dict["AgentID"] = invite.AgentID;
return dict;
}
public static GroupInviteInfo GroupInviteInfo(Dictionary<string, object> dict)
{
if (dict == null)
return null;
GroupInviteInfo invite = new GroupInviteInfo();
invite.InviteID = new UUID(dict["InviteID"].ToString());
invite.GroupID = new UUID(dict["GroupID"].ToString());
invite.RoleID = new UUID(dict["RoleID"].ToString());
invite.AgentID = Sanitize(dict["AgentID"].ToString());
return invite;
}
public static Dictionary<string, object> GroupNoticeData(ExtendedGroupNoticeData notice)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
dict["NoticeID"] = notice.NoticeID.ToString();
dict["Timestamp"] = notice.Timestamp.ToString();
dict["FromName"] = Sanitize(notice.FromName);
dict["Subject"] = Sanitize(notice.Subject);
dict["HasAttachment"] = notice.HasAttachment.ToString();
dict["AttachmentItemID"] = notice.AttachmentItemID.ToString();
dict["AttachmentName"] = Sanitize(notice.AttachmentName);
dict["AttachmentType"] = notice.AttachmentType.ToString();
dict["AttachmentOwnerID"] = Sanitize(notice.AttachmentOwnerID);
return dict;
}
public static ExtendedGroupNoticeData GroupNoticeData(Dictionary<string, object> dict)
{
ExtendedGroupNoticeData notice = new ExtendedGroupNoticeData();
if (dict == null)
return notice;
notice.NoticeID = new UUID(dict["NoticeID"].ToString());
notice.Timestamp = UInt32.Parse(dict["Timestamp"].ToString());
notice.FromName = Sanitize(dict["FromName"].ToString());
notice.Subject = Sanitize(dict["Subject"].ToString());
notice.HasAttachment = bool.Parse(dict["HasAttachment"].ToString());
notice.AttachmentItemID = new UUID(dict["AttachmentItemID"].ToString());
notice.AttachmentName = dict["AttachmentName"].ToString();
notice.AttachmentType = byte.Parse(dict["AttachmentType"].ToString());
notice.AttachmentOwnerID = dict["AttachmentOwnerID"].ToString();
return notice;
}
public static Dictionary<string, object> GroupNoticeInfo(GroupNoticeInfo notice)
{
Dictionary<string, object> dict = GroupNoticeData(notice.noticeData);
dict["GroupID"] = notice.GroupID.ToString();
dict["Message"] = Sanitize(notice.Message);
return dict;
}
public static GroupNoticeInfo GroupNoticeInfo(Dictionary<string, object> dict)
{
GroupNoticeInfo notice = new GroupNoticeInfo();
notice.noticeData = GroupNoticeData(dict);
notice.GroupID = new UUID(dict["GroupID"].ToString());
notice.Message = Sanitize(dict["Message"].ToString());
return notice;
}
public static Dictionary<string, object> DirGroupsReplyData(DirGroupsReplyData g)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
dict["GroupID"] = g.groupID;
dict["Name"] = g.groupName;
dict["NMembers"] = g.members;
dict["SearchOrder"] = g.searchOrder;
return dict;
}
public static DirGroupsReplyData DirGroupsReplyData(Dictionary<string, object> dict)
{
DirGroupsReplyData g;
g.groupID = new UUID(dict["GroupID"].ToString());
g.groupName = dict["Name"].ToString();
Int32.TryParse(dict["NMembers"].ToString(), out g.members);
float.TryParse(dict["SearchOrder"].ToString(), out g.searchOrder);
return g;
}
}
}

View File

@ -1,841 +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.Linq;
using System.Reflection;
using log4net;
using Mono.Addins;
using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces;
using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
using GridRegion = OpenSim.Services.Interfaces.GridRegion;
namespace OpenSim.Groups
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsMessagingModule")]
public class GroupsMessagingModule : ISharedRegionModule, IGroupsMessagingModule
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private List<Scene> m_sceneList = new List<Scene>();
private IPresenceService m_presenceService;
private IMessageTransferModule m_msgTransferModule = null;
private IUserManagement m_UserManagement = null;
private IGroupsServicesConnector m_groupData = null;
// Config Options
private bool m_groupMessagingEnabled;
private bool m_debugEnabled;
/// <summary>
/// If enabled, module only tries to send group IMs to online users by querying cached presence information.
/// </summary>
private bool m_messageOnlineAgentsOnly;
/// <summary>
/// Cache for online users.
/// </summary>
/// <remarks>
/// Group ID is key, presence information for online members is value.
/// Will only be non-null if m_messageOnlineAgentsOnly = true
/// We cache here so that group messages don't constantly have to re-request the online user list to avoid
/// attempted expensive sending of messages to offline users.
/// The tradeoff is that a user that comes online will not receive messages consistently from all other users
/// until caches have updated.
/// Therefore, we set the cache expiry to just 20 seconds.
/// </remarks>
private ExpiringCache<UUID, PresenceInfo[]> m_usersOnlineCache;
private int m_usersOnlineCacheExpirySeconds = 20;
private Dictionary<UUID, List<string>> m_groupsAgentsDroppedFromChatSession = new Dictionary<UUID, List<string>>();
private Dictionary<UUID, List<string>> m_groupsAgentsInvitedToChatSession = new Dictionary<UUID, List<string>>();
#region Region Module interfaceBase Members
public void Initialise(IConfigSource config)
{
IConfig groupsConfig = config.Configs["Groups"];
if (groupsConfig == null)
// Do not run this module by default.
return;
// 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("MessagingModule", "") != Name))
{
m_groupMessagingEnabled = false;
return;
}
m_groupMessagingEnabled = groupsConfig.GetBoolean("MessagingEnabled", true);
if (!m_groupMessagingEnabled)
return;
m_messageOnlineAgentsOnly = groupsConfig.GetBoolean("MessageOnlineUsersOnly", false);
if (m_messageOnlineAgentsOnly)
{
m_usersOnlineCache = new ExpiringCache<UUID, PresenceInfo[]>();
}
else
{
m_log.Error("[Groups.Messaging]: GroupsMessagingModule V2 requires MessageOnlineUsersOnly = true");
m_groupMessagingEnabled = false;
return;
}
m_debugEnabled = groupsConfig.GetBoolean("MessagingDebugEnabled", m_debugEnabled);
m_log.InfoFormat(
"[Groups.Messaging]: GroupsMessagingModule enabled with MessageOnlineOnly = {0}, DebugEnabled = {1}",
m_messageOnlineAgentsOnly, m_debugEnabled);
}
public void AddRegion(Scene scene)
{
if (!m_groupMessagingEnabled)
return;
scene.RegisterModuleInterface<IGroupsMessagingModule>(this);
m_sceneList.Add(scene);
scene.EventManager.OnNewClient += OnNewClient;
scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
scene.EventManager.OnMakeChildAgent += OnMakeChildAgent;
scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
scene.EventManager.OnClientLogin += OnClientLogin;
scene.AddCommand(
"Debug",
this,
"debug groups messaging verbose",
"debug groups messaging verbose <true|false>",
"This setting turns on very verbose groups messaging debugging",
HandleDebugGroupsMessagingVerbose);
}
public void RegionLoaded(Scene scene)
{
if (!m_groupMessagingEnabled)
return;
if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
m_groupData = scene.RequestModuleInterface<IGroupsServicesConnector>();
// No groups module, no groups messaging
if (m_groupData == null)
{
m_log.Error("[Groups.Messaging]: Could not get IGroupsServicesConnector, GroupsMessagingModule is now disabled.");
RemoveRegion(scene);
return;
}
m_msgTransferModule = scene.RequestModuleInterface<IMessageTransferModule>();
// No message transfer module, no groups messaging
if (m_msgTransferModule == null)
{
m_log.Error("[Groups.Messaging]: Could not get MessageTransferModule");
RemoveRegion(scene);
return;
}
m_UserManagement = scene.RequestModuleInterface<IUserManagement>();
// No groups module, no groups messaging
if (m_UserManagement == null)
{
m_log.Error("[Groups.Messaging]: Could not get IUserManagement, GroupsMessagingModule is now disabled.");
RemoveRegion(scene);
return;
}
if (m_presenceService == null)
m_presenceService = scene.PresenceService;
}
public void RemoveRegion(Scene scene)
{
if (!m_groupMessagingEnabled)
return;
if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
m_sceneList.Remove(scene);
scene.EventManager.OnNewClient -= OnNewClient;
scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
scene.EventManager.OnClientLogin -= OnClientLogin;
scene.UnregisterModuleInterface<IGroupsMessagingModule>(this);
}
public void Close()
{
if (!m_groupMessagingEnabled)
return;
if (m_debugEnabled) m_log.Debug("[Groups.Messaging]: Shutting down GroupsMessagingModule module.");
m_sceneList.Clear();
m_groupData = null;
m_msgTransferModule = null;
}
public Type ReplaceableInterface
{
get { return null; }
}
public string Name
{
get { return "Groups Messaging Module V2"; }
}
public void PostInitialise()
{
// NoOp
}
#endregion
private void HandleDebugGroupsMessagingVerbose(object modules, string[] args)
{
if (args.Length < 5)
{
MainConsole.Instance.Output("Usage: debug groups messaging verbose <true|false>");
return;
}
bool verbose = false;
if (!bool.TryParse(args[4], out verbose))
{
MainConsole.Instance.Output("Usage: debug groups messaging verbose <true|false>");
return;
}
m_debugEnabled = verbose;
MainConsole.Instance.Output("{0} verbose logging set to {1}", Name, m_debugEnabled);
}
/// <summary>
/// Not really needed, but does confirm that the group exists.
/// </summary>
public bool StartGroupChatSession(UUID agentID, UUID groupID)
{
if (m_debugEnabled)
m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
GroupRecord groupInfo = m_groupData.GetGroupRecord(agentID.ToString(), groupID, null);
if (groupInfo != null)
{
return true;
}
else
{
return false;
}
}
public void SendMessageToGroup(GridInstantMessage im, UUID groupID)
{
SendMessageToGroup(im, groupID, UUID.Zero, null);
}
public void SendMessageToGroup(
GridInstantMessage im, UUID groupID, UUID sendingAgentForGroupCalls, Func<GroupMembersData, bool> sendCondition)
{
int requestStartTick = Environment.TickCount;
UUID fromAgentID = new UUID(im.fromAgentID);
// Unlike current XmlRpcGroups, Groups V2 can accept UUID.Zero when a perms check for the requesting agent
// is not necessary.
List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(UUID.Zero.ToString(), groupID);
int groupMembersCount = groupMembers.Count;
PresenceInfo[] onlineAgents = null;
// In V2 we always only send to online members.
// Sending to offline members is not an option.
string[] t1 = groupMembers.ConvertAll<string>(gmd => gmd.AgentID.ToString()).ToArray();
// We cache in order not to overwhelm the presence service on large grids with many groups. This does
// mean that members coming online will not see all group members until after m_usersOnlineCacheExpirySeconds has elapsed.
// (assuming this is the same across all grid simulators).
if (!m_usersOnlineCache.TryGetValue(groupID, out onlineAgents))
{
onlineAgents = m_presenceService.GetAgents(t1);
m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds);
}
HashSet<string> onlineAgentsUuidSet = new HashSet<string>();
Array.ForEach<PresenceInfo>(onlineAgents, pi => onlineAgentsUuidSet.Add(pi.UserID));
groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList();
// if (m_debugEnabled)
// m_log.DebugFormat(
// "[Groups.Messaging]: SendMessageToGroup called for group {0} with {1} visible members, {2} online",
// groupID, groupMembersCount, groupMembers.Count());
im.imSessionID = groupID.Guid;
im.fromGroup = true;
IClientAPI thisClient = GetActiveClient(fromAgentID);
if (thisClient != null)
{
im.RegionID = thisClient.Scene.RegionInfo.RegionID.Guid;
}
if ((im.binaryBucket == null) || (im.binaryBucket.Length == 0) || ((im.binaryBucket.Length == 1 && im.binaryBucket[0] == 0)))
{
ExtendedGroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), groupID, null);
if (groupInfo != null)
im.binaryBucket = Util.StringToBytes256(groupInfo.GroupName);
}
// Send to self first of all
im.toAgentID = im.fromAgentID;
im.fromGroup = true;
ProcessMessageFromGroupSession(im);
List<UUID> regions = new List<UUID>();
List<UUID> clientsAlreadySent = new List<UUID>();
// Then send to everybody else
foreach (GroupMembersData member in groupMembers)
{
if (member.AgentID.Guid == im.fromAgentID)
continue;
if (clientsAlreadySent.Contains(member.AgentID))
continue;
clientsAlreadySent.Add(member.AgentID);
if (sendCondition != null)
{
if (!sendCondition(member))
{
if (m_debugEnabled)
m_log.DebugFormat(
"[Groups.Messaging]: Not sending to {0} as they do not fulfill send condition",
member.AgentID);
continue;
}
}
else if (hasAgentDroppedGroupChatSession(member.AgentID.ToString(), groupID))
{
// Don't deliver messages to people who have dropped this session
if (m_debugEnabled)
m_log.DebugFormat("[Groups.Messaging]: {0} has dropped session, not delivering to them", member.AgentID);
continue;
}
im.toAgentID = member.AgentID.Guid;
IClientAPI client = GetActiveClient(member.AgentID);
if (client == null)
{
// If they're not local, forward across the grid
// BUT do it only once per region, please! Sim would be even better!
if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Delivering to {0} via Grid", member.AgentID);
bool reallySend = true;
if (onlineAgents != null)
{
PresenceInfo presence = onlineAgents.First(p => p.UserID == member.AgentID.ToString());
if (regions.Contains(presence.RegionID))
reallySend = false;
else
regions.Add(presence.RegionID);
}
if (reallySend)
{
// We have to create a new IM structure because the transfer module
// uses async send
GridInstantMessage msg = new GridInstantMessage(im, true);
m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { });
}
}
else
{
// Deliver locally, directly
if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", client.Name);
ProcessMessageFromGroupSession(im);
}
}
if (m_debugEnabled)
m_log.DebugFormat(
"[Groups.Messaging]: SendMessageToGroup for group {0} with {1} visible members, {2} online took {3}ms",
groupID, groupMembersCount, groupMembers.Count(), Environment.TickCount - requestStartTick);
}
#region SimGridEventHandlers
void OnClientLogin(IClientAPI client)
{
if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: OnInstantMessage registered for {0}", client.Name);
}
private void OnNewClient(IClientAPI client)
{
if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: OnInstantMessage registered for {0}", client.Name);
ResetAgentGroupChatSessions(client.AgentId.ToString());
}
void OnMakeRootAgent(ScenePresence sp)
{
sp.ControllingClient.OnInstantMessage += OnInstantMessage;
}
void OnMakeChildAgent(ScenePresence sp)
{
sp.ControllingClient.OnInstantMessage -= OnInstantMessage;
}
private void OnGridInstantMessage(GridInstantMessage msg)
{
// The instant message module will only deliver messages of dialog types:
// MessageFromAgent, StartTyping, StopTyping, MessageFromObject
//
// Any other message type will not be delivered to a client by the
// Instant Message Module
UUID regionID = new UUID(msg.RegionID);
if (m_debugEnabled)
{
m_log.DebugFormat("[Groups.Messaging]: {0} called, IM from region {1}",
System.Reflection.MethodBase.GetCurrentMethod().Name, regionID);
DebugGridInstantMessage(msg);
}
// Incoming message from a group
if ((msg.fromGroup == true) && (msg.dialog == (byte)InstantMessageDialog.SessionSend))
{
// We have to redistribute the message across all members of the group who are here
// on this sim
UUID GroupID = new UUID(msg.imSessionID);
Scene aScene = m_sceneList[0];
GridRegion regionOfOrigin = aScene.GridService.GetRegionByUUID(aScene.RegionInfo.ScopeID, regionID);
List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(UUID.Zero.ToString(), GroupID);
//if (m_debugEnabled)
// foreach (GroupMembersData m in groupMembers)
// m_log.DebugFormat("[Groups.Messaging]: member {0}", m.AgentID);
foreach (Scene s in m_sceneList)
{
s.ForEachScenePresence(sp =>
{
// If we got this via grid messaging, it's because the caller thinks
// that the root agent is here. We should only send the IM to root agents.
if (sp.IsChildAgent)
return;
GroupMembersData m = groupMembers.Find(gmd =>
{
return gmd.AgentID == sp.UUID;
});
if (m.AgentID == UUID.Zero)
{
if (m_debugEnabled)
m_log.DebugFormat("[Groups.Messaging]: skipping agent {0} because he is not a member of the group", sp.UUID);
return;
}
// Check if the user has an agent in the region where
// the IM came from, and if so, skip it, because the IM
// was already sent via that agent
if (regionOfOrigin != null)
{
AgentCircuitData aCircuit = s.AuthenticateHandler.GetAgentCircuitData(sp.UUID);
if (aCircuit != null)
{
if (aCircuit.ChildrenCapSeeds.Keys.Contains(regionOfOrigin.RegionHandle))
{
if (m_debugEnabled)
m_log.DebugFormat("[Groups.Messaging]: skipping agent {0} because he has an agent in region of origin", sp.UUID);
return;
}
else
{
if (m_debugEnabled)
m_log.DebugFormat("[Groups.Messaging]: not skipping agent {0}", sp.UUID);
}
}
}
UUID AgentID = sp.UUID;
msg.toAgentID = AgentID.Guid;
if (!hasAgentDroppedGroupChatSession(AgentID.ToString(), GroupID))
{
if (!hasAgentBeenInvitedToGroupChatSession(AgentID.ToString(), GroupID))
AddAgentToSession(AgentID, GroupID, msg);
else
{
if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Passing to ProcessMessageFromGroupSession to deliver to {0} locally", sp.Name);
ProcessMessageFromGroupSession(msg);
}
}
});
}
}
}
private void ProcessMessageFromGroupSession(GridInstantMessage msg)
{
if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Session message from {0} going to agent {1}", msg.fromAgentName, msg.toAgentID);
UUID AgentID = new UUID(msg.fromAgentID);
UUID GroupID = new UUID(msg.imSessionID);
UUID toAgentID = new UUID(msg.toAgentID);
switch (msg.dialog)
{
case (byte)InstantMessageDialog.SessionAdd:
AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
break;
case (byte)InstantMessageDialog.SessionDrop:
AgentDroppedFromGroupChatSession(AgentID.ToString(), GroupID);
break;
case (byte)InstantMessageDialog.SessionSend:
// User hasn't dropped, so they're in the session,
// maybe we should deliver it.
IClientAPI client = GetActiveClient(new UUID(msg.toAgentID));
if (client != null)
{
// Deliver locally, directly
if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Delivering to {0} locally", client.Name);
if (!hasAgentDroppedGroupChatSession(toAgentID.ToString(), GroupID))
{
if (!hasAgentBeenInvitedToGroupChatSession(toAgentID.ToString(), GroupID))
// This actually sends the message too, so no need to resend it
// with client.SendInstantMessage
AddAgentToSession(toAgentID, GroupID, msg);
else
client.SendInstantMessage(msg);
}
}
else
{
m_log.WarnFormat("[Groups.Messaging]: Received a message over the grid for a client that isn't here: {0}", msg.toAgentID);
}
break;
default:
m_log.WarnFormat("[Groups.Messaging]: I don't know how to proccess a {0} message.", ((InstantMessageDialog)msg.dialog).ToString());
break;
}
}
private void AddAgentToSession(UUID AgentID, UUID GroupID, GridInstantMessage msg)
{
// Agent not in session and hasn't dropped from session
// Add them to the session for now, and Invite them
AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
IClientAPI activeClient = GetActiveClient(AgentID);
if (activeClient != null)
{
GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null);
if (groupInfo != null)
{
if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Sending chatterbox invite instant message");
UUID fromAgent = new UUID(msg.fromAgentID);
// Force? open the group session dialog???
// and simultanously deliver the message, so we don't need to do a seperate client.SendInstantMessage(msg);
IEventQueue eq = activeClient.Scene.RequestModuleInterface<IEventQueue>();
if (eq != null)
{
eq.ChatterboxInvitation(
GroupID
, groupInfo.GroupName
, fromAgent
, msg.message
, AgentID
, msg.fromAgentName
, msg.dialog
, msg.timestamp
, msg.offline == 1
, (int)msg.ParentEstateID
, msg.Position
, 1
, new UUID(msg.imSessionID)
, msg.fromGroup
, OpenMetaverse.Utils.StringToBytes(groupInfo.GroupName)
);
var update = new GroupChatListAgentUpdateData(AgentID);
var updates = new List<GroupChatListAgentUpdateData> { update };
eq.ChatterBoxSessionAgentListUpdates(GroupID, new UUID(msg.toAgentID), updates);
}
}
}
}
#endregion
#region ClientEvents
private void OnInstantMessage(IClientAPI remoteClient, GridInstantMessage im)
{
if (m_debugEnabled)
{
m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
DebugGridInstantMessage(im);
}
// Start group IM session
if ((im.dialog == (byte)InstantMessageDialog.SessionGroupStart))
{
if (m_debugEnabled) m_log.InfoFormat("[Groups.Messaging]: imSessionID({0}) toAgentID({1})", im.imSessionID, im.toAgentID);
UUID GroupID = new UUID(im.imSessionID);
UUID AgentID = new UUID(im.fromAgentID);
GroupRecord groupInfo = m_groupData.GetGroupRecord(UUID.Zero.ToString(), GroupID, null);
if (groupInfo != null)
{
AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
ChatterBoxSessionStartReplyViaCaps(remoteClient, groupInfo.GroupName, GroupID);
IEventQueue queue = remoteClient.Scene.RequestModuleInterface<IEventQueue>();
if (queue != null)
{
var update = new GroupChatListAgentUpdateData(AgentID);
var updates = new List<GroupChatListAgentUpdateData> { update };
queue.ChatterBoxSessionAgentListUpdates(GroupID, remoteClient.AgentId, updates);
}
}
}
// Send a message from locally connected client to a group
if ((im.dialog == (byte)InstantMessageDialog.SessionSend))
{
UUID GroupID = new UUID(im.imSessionID);
UUID AgentID = new UUID(im.fromAgentID);
if (m_debugEnabled)
m_log.DebugFormat("[Groups.Messaging]: Send message to session for group {0} with session ID {1}", GroupID, im.imSessionID.ToString());
//If this agent is sending a message, then they want to be in the session
AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
SendMessageToGroup(im, GroupID);
}
}
#endregion
void ChatterBoxSessionStartReplyViaCaps(IClientAPI remoteClient, string groupName, UUID groupID)
{
if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
OSDMap moderatedMap = new OSDMap(4);
moderatedMap.Add("voice", OSD.FromBoolean(false));
OSDMap sessionMap = new OSDMap(4);
sessionMap.Add("moderated_mode", moderatedMap);
sessionMap.Add("session_name", OSD.FromString(groupName));
sessionMap.Add("type", OSD.FromInteger(0));
sessionMap.Add("voice_enabled", OSD.FromBoolean(false));
OSDMap bodyMap = new OSDMap(4);
bodyMap.Add("session_id", OSD.FromUUID(groupID));
bodyMap.Add("temp_session_id", OSD.FromUUID(groupID));
bodyMap.Add("success", OSD.FromBoolean(true));
bodyMap.Add("session_info", sessionMap);
IEventQueue queue = remoteClient.Scene.RequestModuleInterface<IEventQueue>();
queue?.Enqueue(queue.BuildEvent("ChatterBoxSessionStartReply", bodyMap), remoteClient.AgentId);
}
private void DebugGridInstantMessage(GridInstantMessage im)
{
// Don't log any normal IMs (privacy!)
if (m_debugEnabled && im.dialog != (byte)InstantMessageDialog.MessageFromAgent)
{
m_log.WarnFormat("[Groups.Messaging]: IM: fromGroup({0})", im.fromGroup ? "True" : "False");
m_log.WarnFormat("[Groups.Messaging]: IM: Dialog({0})", ((InstantMessageDialog)im.dialog).ToString());
m_log.WarnFormat("[Groups.Messaging]: IM: fromAgentID({0})", im.fromAgentID.ToString());
m_log.WarnFormat("[Groups.Messaging]: IM: fromAgentName({0})", im.fromAgentName.ToString());
m_log.WarnFormat("[Groups.Messaging]: IM: imSessionID({0})", im.imSessionID.ToString());
m_log.WarnFormat("[Groups.Messaging]: IM: message({0})", im.message.ToString());
m_log.WarnFormat("[Groups.Messaging]: IM: offline({0})", im.offline.ToString());
m_log.WarnFormat("[Groups.Messaging]: IM: toAgentID({0})", im.toAgentID.ToString());
m_log.WarnFormat("[Groups.Messaging]: IM: binaryBucket({0})", OpenMetaverse.Utils.BytesToHexString(im.binaryBucket, "BinaryBucket"));
}
}
#region Client Tools
/// <summary>
/// Try to find an active IClientAPI reference for agentID giving preference to root connections
/// </summary>
private IClientAPI GetActiveClient(UUID agentID)
{
if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Looking for local client {0}", agentID);
IClientAPI child = null;
// Try root avatar first
foreach (Scene scene in m_sceneList)
{
ScenePresence sp = scene.GetScenePresence(agentID);
if (sp != null)
{
if (!sp.IsChildAgent)
{
if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Found root agent for client : {0}", sp.ControllingClient.Name);
return sp.ControllingClient;
}
else
{
if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Found child agent for client : {0}", sp.ControllingClient.Name);
child = sp.ControllingClient;
}
}
}
// If we didn't find a root, then just return whichever child we found, or null if none
if (child == null)
{
if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Could not find local client for agent : {0}", agentID);
}
else
{
if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Returning child agent for client : {0}", child.Name);
}
return child;
}
#endregion
#region GroupSessionTracking
public void ResetAgentGroupChatSessions(string agentID)
{
foreach (List<string> agentList in m_groupsAgentsDroppedFromChatSession.Values)
agentList.Remove(agentID);
foreach (List<string> agentList in m_groupsAgentsInvitedToChatSession.Values)
agentList.Remove(agentID);
}
public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID)
{
// If we're tracking this group, and we can find them in the tracking, then they've been invited
return m_groupsAgentsInvitedToChatSession.ContainsKey(groupID)
&& m_groupsAgentsInvitedToChatSession[groupID].Contains(agentID);
}
public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID)
{
// If we're tracking drops for this group,
// and we find them, well... then they've dropped
return m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID)
&& m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID);
}
public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID)
{
if (m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID))
{
// If not in dropped list, add
if (!m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID))
{
m_groupsAgentsDroppedFromChatSession[groupID].Add(agentID);
}
}
}
public void AgentInvitedToGroupChatSession(string agentID, UUID groupID)
{
// Add Session Status if it doesn't exist for this session
CreateGroupChatSessionTracking(groupID);
// If nessesary, remove from dropped list
if (m_groupsAgentsDroppedFromChatSession[groupID].Contains(agentID))
{
m_groupsAgentsDroppedFromChatSession[groupID].Remove(agentID);
}
// Add to invited
if (!m_groupsAgentsInvitedToChatSession[groupID].Contains(agentID))
m_groupsAgentsInvitedToChatSession[groupID].Add(agentID);
}
private void CreateGroupChatSessionTracking(UUID groupID)
{
if (!m_groupsAgentsDroppedFromChatSession.ContainsKey(groupID))
{
m_groupsAgentsDroppedFromChatSession.Add(groupID, new List<string>());
m_groupsAgentsInvitedToChatSession.Add(groupID, new List<string>());
}
}
#endregion
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,289 +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.Linq;
using System.Reflection;
using System.Text;
using OpenSim.Framework;
using OpenSim.Server.Base;
using OpenMetaverse;
using log4net;
namespace OpenSim.Groups
{
public class GroupsServiceHGConnector
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private string m_ServerURI;
private object m_Lock = new object();
public GroupsServiceHGConnector(string url)
{
m_ServerURI = url;
if (!m_ServerURI.EndsWith("/"))
m_ServerURI += "/";
m_log.DebugFormat("[Groups.HGConnector]: Groups server at {0}", m_ServerURI);
}
public bool CreateProxy(string RequestingAgentID, string AgentID, string accessToken, UUID groupID, string url, string name, out string reason)
{
reason = string.Empty;
Dictionary<string, object> sendData = new Dictionary<string,object>();
sendData["RequestingAgentID"] = RequestingAgentID;
sendData["AgentID"] = AgentID.ToString();
sendData["AccessToken"] = accessToken;
sendData["GroupID"] = groupID.ToString();
sendData["Location"] = url;
sendData["Name"] = name;
Dictionary<string, object> ret = MakeRequest("POSTGROUP", sendData);
if (ret == null)
return false;
if (!ret.ContainsKey("RESULT"))
return false;
if (ret["RESULT"].ToString().ToLower() != "true")
{
reason = ret["REASON"].ToString();
return false;
}
return true;
}
public void RemoveAgentFromGroup(string AgentID, UUID GroupID, string token)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["AgentID"] = AgentID;
sendData["GroupID"] = GroupID.ToString();
sendData["AccessToken"] = GroupsDataUtils.Sanitize(token);
MakeRequest("REMOVEAGENTFROMGROUP", sendData);
}
public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName, string token)
{
if (GroupID == UUID.Zero && (GroupName == null || (GroupName != null && GroupName == string.Empty)))
return null;
Dictionary<string, object> sendData = new Dictionary<string, object>();
if (GroupID != UUID.Zero)
sendData["GroupID"] = GroupID.ToString();
if (!string.IsNullOrEmpty(GroupName))
sendData["Name"] = GroupsDataUtils.Sanitize(GroupName);
sendData["RequestingAgentID"] = RequestingAgentID;
sendData["AccessToken"] = GroupsDataUtils.Sanitize(token);
Dictionary<string, object> ret = MakeRequest("GETGROUP", sendData);
if (ret == null)
return null;
if (!ret.ContainsKey("RESULT"))
return null;
if (ret["RESULT"].ToString() == "NULL")
return null;
return GroupsDataUtils.GroupRecord((Dictionary<string, object>)ret["RESULT"]);
}
public List<ExtendedGroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID, string token)
{
List<ExtendedGroupMembersData> members = new List<ExtendedGroupMembersData>();
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["GroupID"] = GroupID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
sendData["AccessToken"] = GroupsDataUtils.Sanitize(token);
Dictionary<string, object> ret = MakeRequest("GETGROUPMEMBERS", sendData);
if (ret == null)
return members;
if (!ret.ContainsKey("RESULT"))
return members;
if (ret["RESULT"].ToString() == "NULL")
return members;
foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
{
ExtendedGroupMembersData m = GroupsDataUtils.GroupMembersData((Dictionary<string, object>)v);
members.Add(m);
}
return members;
}
public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID, string token)
{
List<GroupRolesData> roles = new List<GroupRolesData>();
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["GroupID"] = GroupID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
sendData["AccessToken"] = GroupsDataUtils.Sanitize(token);
Dictionary<string, object> ret = MakeRequest("GETGROUPROLES", sendData);
if (ret == null)
return roles;
if (!ret.ContainsKey("RESULT"))
return roles;
if (ret["RESULT"].ToString() == "NULL")
return roles;
foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
{
GroupRolesData m = GroupsDataUtils.GroupRolesData((Dictionary<string, object>)v);
roles.Add(m);
}
return roles;
}
public List<ExtendedGroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID, string token)
{
List<ExtendedGroupRoleMembersData> rmembers = new List<ExtendedGroupRoleMembersData>();
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["GroupID"] = GroupID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
sendData["AccessToken"] = GroupsDataUtils.Sanitize(token);
Dictionary<string, object> ret = MakeRequest("GETROLEMEMBERS", sendData);
if (ret == null)
return rmembers;
if (!ret.ContainsKey("RESULT"))
return rmembers;
if (ret["RESULT"].ToString() == "NULL")
return rmembers;
foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
{
ExtendedGroupRoleMembersData m = GroupsDataUtils.GroupRoleMembersData((Dictionary<string, object>)v);
rmembers.Add(m);
}
return rmembers;
}
public bool AddNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["GroupID"] = groupID.ToString();
sendData["NoticeID"] = noticeID.ToString();
sendData["FromName"] = GroupsDataUtils.Sanitize(fromName);
sendData["Subject"] = GroupsDataUtils.Sanitize(subject);
sendData["Message"] = GroupsDataUtils.Sanitize(message);
sendData["HasAttachment"] = hasAttachment.ToString();
if (hasAttachment)
{
sendData["AttachmentType"] = attType.ToString();
sendData["AttachmentName"] = attName.ToString();
sendData["AttachmentItemID"] = attItemID.ToString();
sendData["AttachmentOwnerID"] = attOwnerID;
}
sendData["RequestingAgentID"] = RequestingAgentID;
Dictionary<string, object> ret = MakeRequest("ADDNOTICE", sendData);
if (ret == null)
return false;
if (!ret.ContainsKey("RESULT"))
return false;
if (ret["RESULT"].ToString().ToLower() != "true")
return false;
return true;
}
public bool VerifyNotice(UUID noticeID, UUID groupID)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["NoticeID"] = noticeID.ToString();
sendData["GroupID"] = groupID.ToString();
Dictionary<string, object> ret = MakeRequest("VERIFYNOTICE", sendData);
if (ret == null)
return false;
if (!ret.ContainsKey("RESULT"))
return false;
if (ret["RESULT"].ToString().ToLower() != "true")
return false;
return true;
}
//
//
//
//
//
#region Make Request
private Dictionary<string, object> MakeRequest(string method, Dictionary<string, object> sendData)
{
sendData["METHOD"] = method;
string reply = string.Empty;
lock (m_Lock)
reply = SynchronousRestFormsRequester.MakeRequest("POST",
m_ServerURI + "hg-groups",
ServerUtils.BuildQueryString(sendData));
//m_log.DebugFormat("[XXX]: reply was {0}", reply);
if (string.IsNullOrEmpty(reply))
return null;
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(
reply);
return replyData;
}
#endregion
}
}

View File

@ -1,695 +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.Linq;
using System.Reflection;
using System.Text;
using OpenSim.Framework;
using OpenSim.Framework.Monitoring;
using OpenSim.Framework.Servers;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Services.Interfaces;
using OpenMetaverse;
using Mono.Addins;
using log4net;
using Nini.Config;
namespace OpenSim.Groups
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsServiceHGConnectorModule")]
public class GroupsServiceHGConnectorModule : ISharedRegionModule, IGroupsServicesConnector
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private bool m_Enabled = false;
private IGroupsServicesConnector m_LocalGroupsConnector;
private string m_LocalGroupsServiceLocation;
private IUserManagement m_UserManagement;
private IOfflineIMService m_OfflineIM;
private IMessageTransferModule m_Messaging;
private List<Scene> m_Scenes;
private ForeignImporter m_ForeignImporter;
private string m_ServiceLocation;
private IConfigSource m_Config;
private Dictionary<string, GroupsServiceHGConnector> m_NetworkConnectors = new Dictionary<string, GroupsServiceHGConnector>();
private RemoteConnectorCacheWrapper m_CacheWrapper; // for caching info of external group services
#region ISharedRegionModule
public void Initialise(IConfigSource config)
{
IConfig groupsConfig = config.Configs["Groups"];
if (groupsConfig == null)
return;
if ((groupsConfig.GetBoolean("Enabled", false) == false)
|| (groupsConfig.GetString("ServicesConnectorModule", string.Empty) != Name))
{
return;
}
m_Config = config;
m_ServiceLocation = groupsConfig.GetString("LocalService", "local"); // local or remote
m_LocalGroupsServiceLocation = groupsConfig.GetString("GroupsExternalURI", "http://127.0.0.1");
m_Scenes = new List<Scene>();
m_Enabled = true;
m_log.DebugFormat("[Groups]: Initializing {0} with LocalService {1}", this.Name, m_ServiceLocation);
}
public string Name
{
get { return "Groups HG Service Connector"; }
}
public Type ReplaceableInterface
{
get { return null; }
}
public void AddRegion(Scene scene)
{
if (!m_Enabled)
return;
m_log.DebugFormat("[Groups]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName);
scene.RegisterModuleInterface<IGroupsServicesConnector>(this);
m_Scenes.Add(scene);
scene.EventManager.OnNewClient += OnNewClient;
}
public void RemoveRegion(Scene scene)
{
if (!m_Enabled)
return;
scene.UnregisterModuleInterface<IGroupsServicesConnector>(this);
m_Scenes.Remove(scene);
}
public void RegionLoaded(Scene scene)
{
if (!m_Enabled)
return;
if (m_UserManagement == null)
{
m_UserManagement = scene.RequestModuleInterface<IUserManagement>();
m_OfflineIM = scene.RequestModuleInterface<IOfflineIMService>();
m_Messaging = scene.RequestModuleInterface<IMessageTransferModule>();
m_ForeignImporter = new ForeignImporter(m_UserManagement);
if (m_ServiceLocation.Equals("local"))
{
m_LocalGroupsConnector = new GroupsServiceLocalConnectorModule(m_Config, m_UserManagement);
// Also, if local, create the endpoint for the HGGroupsService
new HGGroupsServiceRobustConnector(m_Config, MainServer.Instance, string.Empty,
scene.RequestModuleInterface<IOfflineIMService>(), scene.RequestModuleInterface<IUserAccountService>());
}
else
m_LocalGroupsConnector = new GroupsServiceRemoteConnectorModule(m_Config, m_UserManagement);
m_CacheWrapper = new RemoteConnectorCacheWrapper(m_UserManagement);
}
}
public void PostInitialise()
{
}
public void Close()
{
}
#endregion
private void OnNewClient(IClientAPI client)
{
client.OnCompleteMovementToRegion += OnCompleteMovementToRegion;
}
void OnCompleteMovementToRegion(IClientAPI client, bool arg2)
{
object sp = null;
if (client.Scene.TryGetScenePresence(client.AgentId, out sp))
{
if (sp is ScenePresence && ((ScenePresence)sp).PresenceType != PresenceType.Npc)
{
AgentCircuitData aCircuit = ((ScenePresence)sp).Scene.AuthenticateHandler.GetAgentCircuitData(client.AgentId);
if (aCircuit != null && (aCircuit.teleportFlags & (uint)Constants.TeleportFlags.ViaHGLogin) != 0 &&
m_OfflineIM != null && m_Messaging != null)
{
List<GridInstantMessage> ims = m_OfflineIM.GetMessages(aCircuit.AgentID);
if (ims != null && ims.Count > 0)
foreach (GridInstantMessage im in ims)
m_Messaging.SendInstantMessage(im, delegate(bool success) { });
}
}
}
}
#region IGroupsServicesConnector
public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment,
bool allowPublish, bool maturePublish, UUID founderID, out string reason)
{
reason = string.Empty;
if (m_UserManagement.IsLocalGridUser(RequestingAgentID))
return m_LocalGroupsConnector.CreateGroup(RequestingAgentID, name, charter, showInList, insigniaID,
membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out reason);
else
{
reason = "Only local grid users are allowed to create a new group";
return UUID.Zero;
}
}
public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee,
bool openEnrollment, bool allowPublish, bool maturePublish, out string reason)
{
reason = string.Empty;
string url = string.Empty;
string name = string.Empty;
if (IsLocal(groupID, out url, out name))
return m_LocalGroupsConnector.UpdateGroup(AgentUUI(RequestingAgentID), groupID, charter, showInList, insigniaID, membershipFee,
openEnrollment, allowPublish, maturePublish, out reason);
else
{
reason = "Changes to remote group not allowed. Please go to the group's original world.";
return false;
}
}
public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName)
{
string url = string.Empty;
string name = string.Empty;
if (IsLocal(GroupID, out url, out name))
return m_LocalGroupsConnector.GetGroupRecord(AgentUUI(RequestingAgentID), GroupID, GroupName);
else if (url != string.Empty)
{
ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, GroupID);
string accessToken = string.Empty;
if (membership != null)
accessToken = membership.AccessToken;
else
return null;
GroupsServiceHGConnector c = GetConnector(url);
if (c != null)
{
ExtendedGroupRecord grec = m_CacheWrapper.GetGroupRecord(RequestingAgentID, GroupID, GroupName, delegate
{
return c.GetGroupRecord(AgentUUIForOutside(RequestingAgentID), GroupID, GroupName, accessToken);
});
if (grec != null)
ImportForeigner(grec.FounderUUI);
return grec;
}
}
return null;
}
public List<DirGroupsReplyData> FindGroups(string RequestingAgentIDstr, string search)
{
return m_LocalGroupsConnector.FindGroups(RequestingAgentIDstr, search);
}
public List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID)
{
string url = string.Empty, gname = string.Empty;
if (IsLocal(GroupID, out url, out gname))
{
string agentID = AgentUUI(RequestingAgentID);
return m_LocalGroupsConnector.GetGroupMembers(agentID, GroupID);
}
else if (!string.IsNullOrEmpty(url))
{
ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, GroupID);
string accessToken = string.Empty;
if (membership != null)
accessToken = membership.AccessToken;
else
return null;
GroupsServiceHGConnector c = GetConnector(url);
if (c != null)
{
return m_CacheWrapper.GetGroupMembers(RequestingAgentID, GroupID, delegate
{
return c.GetGroupMembers(AgentUUIForOutside(RequestingAgentID), GroupID, accessToken);
});
}
}
return new List<GroupMembersData>();
}
public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason)
{
reason = string.Empty;
string url = string.Empty, gname = string.Empty;
if (IsLocal(groupID, out url, out gname))
return m_LocalGroupsConnector.AddGroupRole(AgentUUI(RequestingAgentID), groupID, roleID, name, description, title, powers, out reason);
else
{
reason = "Operation not allowed outside this group's origin world.";
return false;
}
}
public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers)
{
string url = string.Empty, gname = string.Empty;
if (IsLocal(groupID, out url, out gname))
return m_LocalGroupsConnector.UpdateGroupRole(AgentUUI(RequestingAgentID), groupID, roleID, name, description, title, powers);
else
{
return false;
}
}
public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID)
{
string url = string.Empty, gname = string.Empty;
if (IsLocal(groupID, out url, out gname))
m_LocalGroupsConnector.RemoveGroupRole(AgentUUI(RequestingAgentID), groupID, roleID);
else
{
return;
}
}
public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID groupID)
{
string url = string.Empty, gname = string.Empty;
if (IsLocal(groupID, out url, out gname))
return m_LocalGroupsConnector.GetGroupRoles(AgentUUI(RequestingAgentID), groupID);
else if (!string.IsNullOrEmpty(url))
{
ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, groupID);
string accessToken = string.Empty;
if (membership != null)
accessToken = membership.AccessToken;
else
return null;
GroupsServiceHGConnector c = GetConnector(url);
if (c != null)
{
return m_CacheWrapper.GetGroupRoles(RequestingAgentID, groupID, delegate
{
return c.GetGroupRoles(AgentUUIForOutside(RequestingAgentID), groupID, accessToken);
});
}
}
return new List<GroupRolesData>();
}
public List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID groupID)
{
string url = string.Empty, gname = string.Empty;
if (IsLocal(groupID, out url, out gname))
return m_LocalGroupsConnector.GetGroupRoleMembers(AgentUUI(RequestingAgentID), groupID);
else if (!string.IsNullOrEmpty(url))
{
ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, groupID);
string accessToken = string.Empty;
if (membership != null)
accessToken = membership.AccessToken;
else
return null;
GroupsServiceHGConnector c = GetConnector(url);
if (c != null)
{
return m_CacheWrapper.GetGroupRoleMembers(RequestingAgentID, groupID, delegate
{
return c.GetGroupRoleMembers(AgentUUIForOutside(RequestingAgentID), groupID, accessToken);
});
}
}
return new List<GroupRoleMembersData>();
}
public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason)
{
string url = string.Empty;
string name = string.Empty;
reason = string.Empty;
UUID uid = new UUID(AgentID);
if (IsLocal(GroupID, out url, out name))
{
if (m_UserManagement.IsLocalGridUser(uid)) // local user
{
// normal case: local group, local user
return m_LocalGroupsConnector.AddAgentToGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID, token, out reason);
}
else // local group, foreign user
{
// the user is accepting the invitation, or joining, where the group resides
token = UUID.Random().ToString();
bool success = m_LocalGroupsConnector.AddAgentToGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID, token, out reason);
if (success)
{
// Here we always return true. The user has been added to the local group,
// independent of whether the remote operation succeeds or not
url = m_UserManagement.GetUserServerURL(uid, "GroupsServerURI");
if (url == string.Empty)
{
reason = "You don't have an accessible groups server in your home world. You membership to this group in only within this grid.";
return true;
}
GroupsServiceHGConnector c = GetConnector(url);
if (c != null)
c.CreateProxy(AgentUUI(RequestingAgentID), AgentID, token, GroupID, m_LocalGroupsServiceLocation, name, out reason);
return true;
}
return false;
}
}
else if (m_UserManagement.IsLocalGridUser(uid)) // local user
{
// foreign group, local user. She's been added already by the HG service.
// Let's just check
if (m_LocalGroupsConnector.GetAgentGroupMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID) != null)
return true;
}
reason = "Operation not allowed outside this group's origin world";
return false;
}
public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
{
string url = string.Empty, name = string.Empty;
if (!IsLocal(GroupID, out url, out name) && url != string.Empty)
{
ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID);
if (membership != null)
{
GroupsServiceHGConnector c = GetConnector(url);
if (c != null)
c.RemoveAgentFromGroup(AgentUUIForOutside(AgentID), GroupID, membership.AccessToken);
}
}
// remove from local service
m_LocalGroupsConnector.RemoveAgentFromGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID);
}
public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID)
{
string url = string.Empty, gname = string.Empty;
if (IsLocal(groupID, out url, out gname))
return m_LocalGroupsConnector.AddAgentToGroupInvite(AgentUUI(RequestingAgentID), inviteID, groupID, roleID, AgentUUI(agentID));
else
return false;
}
public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
{
return m_LocalGroupsConnector.GetAgentToGroupInvite(AgentUUI(RequestingAgentID), inviteID); ;
}
public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
{
m_LocalGroupsConnector.RemoveAgentToGroupInvite(AgentUUI(RequestingAgentID), inviteID);
}
public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
{
string url = string.Empty, gname = string.Empty;
if (IsLocal(GroupID, out url, out gname))
m_LocalGroupsConnector.AddAgentToGroupRole(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID);
}
public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
{
string url = string.Empty, gname = string.Empty;
if (IsLocal(GroupID, out url, out gname))
m_LocalGroupsConnector.RemoveAgentFromGroupRole(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID);
}
public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID)
{
string url = string.Empty, gname = string.Empty;
if (IsLocal(GroupID, out url, out gname))
return m_LocalGroupsConnector.GetAgentGroupRoles(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID);
else
return new List<GroupRolesData>();
}
public void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID)
{
string url = string.Empty, gname = string.Empty;
if (IsLocal(GroupID, out url, out gname))
m_LocalGroupsConnector.SetAgentActiveGroup(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID);
}
public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID)
{
return m_LocalGroupsConnector.GetAgentActiveMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID));
}
public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
{
string url = string.Empty, gname = string.Empty;
if (IsLocal(GroupID, out url, out gname))
m_LocalGroupsConnector.SetAgentActiveGroupRole(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, RoleID);
}
public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile)
{
m_LocalGroupsConnector.UpdateMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID, AcceptNotices, ListInProfile);
}
public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID)
{
string url = string.Empty, gname = string.Empty;
if (IsLocal(GroupID, out url, out gname))
return m_LocalGroupsConnector.GetAgentGroupMembership(AgentUUI(RequestingAgentID), AgentUUI(AgentID), GroupID);
else
return null;
}
public List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID)
{
return m_LocalGroupsConnector.GetAgentGroupMemberships(AgentUUI(RequestingAgentID), AgentUUI(AgentID));
}
public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
{
string url = string.Empty, gname = string.Empty;
if (IsLocal(groupID, out url, out gname))
{
if (m_LocalGroupsConnector.AddGroupNotice(AgentUUI(RequestingAgentID), groupID, noticeID, fromName, subject, message,
hasAttachment, attType, attName, attItemID, AgentUUI(attOwnerID)))
{
// then send the notice to every grid for which there are members in this group
List<GroupMembersData> members = m_LocalGroupsConnector.GetGroupMembers(AgentUUI(RequestingAgentID), groupID);
List<string> urls = new List<string>();
foreach (GroupMembersData m in members)
{
if (!m_UserManagement.IsLocalGridUser(m.AgentID))
{
string gURL = m_UserManagement.GetUserServerURL(m.AgentID, "GroupsServerURI");
if (!urls.Contains(gURL))
urls.Add(gURL);
}
}
// so we have the list of urls to send the notice to
// this may take a long time...
WorkManager.RunInThread(delegate
{
foreach (string u in urls)
{
GroupsServiceHGConnector c = GetConnector(u);
if (c != null)
{
c.AddNotice(AgentUUIForOutside(RequestingAgentID), groupID, noticeID, fromName, subject, message,
hasAttachment, attType, attName, attItemID, AgentUUIForOutside(attOwnerID));
}
}
}, null, string.Format("AddGroupNotice (agent {0}, group {1})", RequestingAgentID, groupID));
return true;
}
return false;
}
else
return false;
}
public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID)
{
GroupNoticeInfo notice = m_LocalGroupsConnector.GetGroupNotice(AgentUUI(RequestingAgentID), noticeID);
if (notice != null && notice.noticeData.HasAttachment && notice.noticeData.AttachmentOwnerID != null)
ImportForeigner(notice.noticeData.AttachmentOwnerID);
return notice;
}
public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID)
{
return m_LocalGroupsConnector.GetGroupNotices(AgentUUI(RequestingAgentID), GroupID);
}
#endregion
#region hypergrid groups
private string AgentUUI(string AgentIDStr)
{
UUID AgentID = UUID.Zero;
if (!UUID.TryParse(AgentIDStr, out AgentID) || AgentID == UUID.Zero)
return UUID.Zero.ToString();
if (m_UserManagement.IsLocalGridUser(AgentID))
return AgentID.ToString();
AgentCircuitData agent = null;
foreach (Scene scene in m_Scenes)
{
agent = scene.AuthenticateHandler.GetAgentCircuitData(AgentID);
if (agent != null)
break;
}
if (agent != null)
return Util.ProduceUserUniversalIdentifier(agent);
// we don't know anything about this foreign user
// try asking the user management module, which may know more
return m_UserManagement.GetUserUUI(AgentID);
}
private string AgentUUIForOutside(string AgentIDStr)
{
UUID AgentID = UUID.Zero;
if (!UUID.TryParse(AgentIDStr, out AgentID) || AgentID == UUID.Zero)
return UUID.Zero.ToString();
AgentCircuitData agent = null;
foreach (Scene scene in m_Scenes)
{
agent = scene.AuthenticateHandler.GetAgentCircuitData(AgentID);
if (agent != null)
break;
}
if (agent == null) // oops
return AgentID.ToString();
return Util.ProduceUserUniversalIdentifier(agent);
}
private UUID ImportForeigner(string uID)
{
UUID userID = UUID.Zero;
string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty;
if (Util.ParseUniversalUserIdentifier(uID, out userID, out url, out first, out last, out tmp))
m_UserManagement.AddUser(userID, first, last, url);
return userID;
}
private bool IsLocal(UUID groupID, out string serviceLocation, out string name)
{
serviceLocation = string.Empty;
name = string.Empty;
if (groupID.Equals(UUID.Zero))
return true;
ExtendedGroupRecord group = m_LocalGroupsConnector.GetGroupRecord(UUID.Zero.ToString(), groupID, string.Empty);
if (group == null)
{
//m_log.DebugFormat("[XXX]: IsLocal? group {0} not found -- no.", groupID);
return false;
}
serviceLocation = group.ServiceLocation;
name = group.GroupName;
bool isLocal = (group.ServiceLocation == string.Empty);
//m_log.DebugFormat("[XXX]: IsLocal? {0}", isLocal);
return isLocal;
}
private GroupsServiceHGConnector GetConnector(string url)
{
lock (m_NetworkConnectors)
{
if (m_NetworkConnectors.ContainsKey(url))
return m_NetworkConnectors[url];
GroupsServiceHGConnector c = new GroupsServiceHGConnector(url);
m_NetworkConnectors[url] = c;
}
return m_NetworkConnectors[url];
}
#endregion
}
}

View File

@ -1,445 +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.Reflection;
using System.Text;
using System.Xml;
using System.Collections.Generic;
using System.IO;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Server.Base;
using OpenSim.Services.Interfaces;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Server.Handlers.Base;
using log4net;
using OpenMetaverse;
namespace OpenSim.Groups
{
public class HGGroupsServiceRobustConnector : ServiceConnector
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private HGGroupsService m_GroupsService;
private string m_ConfigName = "Groups";
// Called by Robust shell
public HGGroupsServiceRobustConnector(IConfigSource config, IHttpServer server, string configName) :
this(config, server, configName, null, null)
{
}
// Called by the sim-bound module
public HGGroupsServiceRobustConnector(IConfigSource config, IHttpServer server, string configName, IOfflineIMService im, IUserAccountService users) :
base(config, server, configName)
{
if (configName != String.Empty)
m_ConfigName = configName;
m_log.DebugFormat("[Groups.RobustHGConnector]: Starting with config name {0}", m_ConfigName);
string homeURI = Util.GetConfigVarFromSections<string>(config, "HomeURI",
new string[] { "Startup", "Hypergrid", m_ConfigName}, string.Empty);
if (homeURI == string.Empty)
throw new Exception(String.Format("[Groups.RobustHGConnector]: please provide the HomeURI [Startup] or in section {0}", m_ConfigName));
IConfig cnf = config.Configs[m_ConfigName];
if (cnf == null)
throw new Exception(String.Format("[Groups.RobustHGConnector]: {0} section does not exist", m_ConfigName));
if (im == null)
{
string imDll = cnf.GetString("OfflineIMService", string.Empty);
if (imDll == string.Empty)
throw new Exception(String.Format("[Groups.RobustHGConnector]: please provide OfflineIMService in section {0}", m_ConfigName));
Object[] args = new Object[] { config };
im = ServerUtils.LoadPlugin<IOfflineIMService>(imDll, args);
}
if (users == null)
{
string usersDll = cnf.GetString("UserAccountService", string.Empty);
if (usersDll == string.Empty)
throw new Exception(String.Format("[Groups.RobustHGConnector]: please provide UserAccountService in section {0}", m_ConfigName));
Object[] args = new Object[] { config };
users = ServerUtils.LoadPlugin<IUserAccountService>(usersDll, args);
}
m_GroupsService = new HGGroupsService(config, im, users, homeURI);
server.AddStreamHandler(new HGGroupsServicePostHandler(m_GroupsService));
}
}
public class HGGroupsServicePostHandler : BaseStreamHandler
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private HGGroupsService m_GroupsService;
public HGGroupsServicePostHandler(HGGroupsService service) :
base("POST", "/hg-groups")
{
m_GroupsService = service;
}
protected override byte[] ProcessRequest(string path, Stream requestData,
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
string body;
using(StreamReader sr = new StreamReader(requestData))
body = sr.ReadToEnd();
body = body.Trim();
//m_log.DebugFormat("[XXX]: query String: {0}", body);
try
{
Dictionary<string, object> request =
ServerUtils.ParseQueryString(body);
if (!request.ContainsKey("METHOD"))
return FailureResult();
string method = request["METHOD"].ToString();
request.Remove("METHOD");
m_log.DebugFormat("[Groups.RobustHGConnector]: {0}", method);
switch (method)
{
case "POSTGROUP":
return HandleAddGroupProxy(request);
case "REMOVEAGENTFROMGROUP":
return HandleRemoveAgentFromGroup(request);
case "GETGROUP":
return HandleGetGroup(request);
case "ADDNOTICE":
return HandleAddNotice(request);
case "VERIFYNOTICE":
return HandleVerifyNotice(request);
case "GETGROUPMEMBERS":
return HandleGetGroupMembers(request);
case "GETGROUPROLES":
return HandleGetGroupRoles(request);
case "GETROLEMEMBERS":
return HandleGetRoleMembers(request);
}
m_log.DebugFormat("[Groups.RobustHGConnector]: unknown method request: {0}", method);
}
catch (Exception e)
{
m_log.Error(string.Format("[Groups.RobustHGConnector]: Exception {0} ", e.Message), e);
}
return FailureResult();
}
byte[] HandleAddGroupProxy(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID")
|| !request.ContainsKey("AgentID")
|| !request.ContainsKey("AccessToken") || !request.ContainsKey("Location"))
NullResult(result, "Bad network data");
else
{
string RequestingAgentID = request["RequestingAgentID"].ToString();
string agentID = request["AgentID"].ToString();
UUID groupID = new UUID(request["GroupID"].ToString());
string accessToken = request["AccessToken"].ToString();
string location = request["Location"].ToString();
string name = string.Empty;
if (request.ContainsKey("Name"))
name = request["Name"].ToString();
string reason = string.Empty;
bool success = m_GroupsService.CreateGroupProxy(RequestingAgentID, agentID, accessToken, groupID, location, name, out reason);
result["REASON"] = reason;
result["RESULT"] = success.ToString();
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleRemoveAgentFromGroup(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("AccessToken") || !request.ContainsKey("AgentID") ||
!request.ContainsKey("GroupID"))
NullResult(result, "Bad network data");
else
{
UUID groupID = new UUID(request["GroupID"].ToString());
string agentID = request["AgentID"].ToString();
string token = request["AccessToken"].ToString();
if (!m_GroupsService.RemoveAgentFromGroup(agentID, agentID, groupID, token))
NullResult(result, "Internal error");
else
result["RESULT"] = "true";
}
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
}
byte[] HandleGetGroup(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AccessToken"))
NullResult(result, "Bad network data");
else
{
string RequestingAgentID = request["RequestingAgentID"].ToString();
string token = request["AccessToken"].ToString();
UUID groupID = UUID.Zero;
string groupName = string.Empty;
if (request.ContainsKey("GroupID"))
groupID = new UUID(request["GroupID"].ToString());
if (request.ContainsKey("Name"))
groupName = request["Name"].ToString();
ExtendedGroupRecord grec = m_GroupsService.GetGroupRecord(RequestingAgentID, groupID, groupName, token);
if (grec == null)
NullResult(result, "Group not found");
else
result["RESULT"] = GroupsDataUtils.GroupRecord(grec);
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleGetGroupMembers(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AccessToken"))
NullResult(result, "Bad network data");
else
{
UUID groupID = new UUID(request["GroupID"].ToString());
string requestingAgentID = request["RequestingAgentID"].ToString();
string token = request["AccessToken"].ToString();
List<ExtendedGroupMembersData> members = m_GroupsService.GetGroupMembers(requestingAgentID, groupID, token);
if (members == null || (members != null && members.Count == 0))
{
NullResult(result, "No members");
}
else
{
Dictionary<string, object> dict = new Dictionary<string, object>();
int i = 0;
foreach (ExtendedGroupMembersData m in members)
{
dict["m-" + i++] = GroupsDataUtils.GroupMembersData(m);
}
result["RESULT"] = dict;
}
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleGetGroupRoles(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AccessToken"))
NullResult(result, "Bad network data");
else
{
UUID groupID = new UUID(request["GroupID"].ToString());
string requestingAgentID = request["RequestingAgentID"].ToString();
string token = request["AccessToken"].ToString();
List<GroupRolesData> roles = m_GroupsService.GetGroupRoles(requestingAgentID, groupID, token);
if (roles == null || (roles != null && roles.Count == 0))
{
NullResult(result, "No members");
}
else
{
Dictionary<string, object> dict = new Dictionary<string, object>();
int i = 0;
foreach (GroupRolesData r in roles)
dict["r-" + i++] = GroupsDataUtils.GroupRolesData(r);
result["RESULT"] = dict;
}
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleGetRoleMembers(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AccessToken"))
NullResult(result, "Bad network data");
else
{
UUID groupID = new UUID(request["GroupID"].ToString());
string requestingAgentID = request["RequestingAgentID"].ToString();
string token = request["AccessToken"].ToString();
List<ExtendedGroupRoleMembersData> rmembers = m_GroupsService.GetGroupRoleMembers(requestingAgentID, groupID, token);
if (rmembers == null || (rmembers != null && rmembers.Count == 0))
{
NullResult(result, "No members");
}
else
{
Dictionary<string, object> dict = new Dictionary<string, object>();
int i = 0;
foreach (ExtendedGroupRoleMembersData rm in rmembers)
dict["rm-" + i++] = GroupsDataUtils.GroupRoleMembersData(rm);
result["RESULT"] = dict;
}
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleAddNotice(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("NoticeID") ||
!request.ContainsKey("FromName") || !request.ContainsKey("Subject") || !request.ContainsKey("Message") ||
!request.ContainsKey("HasAttachment"))
NullResult(result, "Bad network data");
else
{
bool hasAtt = bool.Parse(request["HasAttachment"].ToString());
byte attType = 0;
string attName = string.Empty;
string attOwner = string.Empty;
UUID attItem = UUID.Zero;
if (request.ContainsKey("AttachmentType"))
attType = byte.Parse(request["AttachmentType"].ToString());
if (request.ContainsKey("AttachmentName"))
attName = request["AttachmentType"].ToString();
if (request.ContainsKey("AttachmentItemID"))
attItem = new UUID(request["AttachmentItemID"].ToString());
if (request.ContainsKey("AttachmentOwnerID"))
attOwner = request["AttachmentOwnerID"].ToString();
bool success = m_GroupsService.AddNotice(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()),
new UUID(request["NoticeID"].ToString()), request["FromName"].ToString(), request["Subject"].ToString(),
request["Message"].ToString(), hasAtt, attType, attName, attItem, attOwner);
result["RESULT"] = success.ToString();
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleVerifyNotice(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("NoticeID") || !request.ContainsKey("GroupID"))
NullResult(result, "Bad network data");
else
{
UUID noticeID = new UUID(request["NoticeID"].ToString());
UUID groupID = new UUID(request["GroupID"].ToString());
bool success = m_GroupsService.VerifyNotice(noticeID, groupID);
//m_log.DebugFormat("[XXX]: VerifyNotice returned {0}", success);
result["RESULT"] = success.ToString();
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
//
//
//
//
//
#region Helpers
private void NullResult(Dictionary<string, object> result, string reason)
{
result["RESULT"] = "NULL";
result["REASON"] = reason;
}
private byte[] FailureResult()
{
Dictionary<string, object> result = new Dictionary<string, object>();
NullResult(result, "Unknown method");
string xmlString = ServerUtils.BuildXmlResponse(result);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
#endregion
}
}

View File

@ -1,112 +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 OpenMetaverse;
using OpenSim.Framework;
namespace OpenSim.Groups
{
public interface IGroupsServicesConnector
{
UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee,
bool openEnrollment, bool allowPublish, bool maturePublish, UUID founderID, out string reason);
bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee,
bool openEnrollment, bool allowPublish, bool maturePublish, out string reason);
ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName);
List<DirGroupsReplyData> FindGroups(string RequestingAgentIDstr, string search);
List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID);
bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason);
bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers);
void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID);
List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID);
List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID);
bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason);
void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID);
bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID);
GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID);
void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID);
void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID);
void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID);
List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID);
void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID);
ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID);
void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID);
void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile);
/// <summary>
/// Get information about a specific group to which the user belongs.
/// </summary>
/// <param name="RequestingAgentID">The agent requesting the information.</param>
/// <param name="AgentID">The agent requested.</param>
/// <param name="GroupID">The group requested.</param>
/// <returns>
/// If the user is a member of the group then the data structure is returned. If not, then null is returned.
/// </returns>
ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID);
/// <summary>
/// Get information about the groups to which a user belongs.
/// </summary>
/// <param name="RequestingAgentID">The agent requesting the information.</param>
/// <param name="AgentID">The agent requested.</param>
/// <returns>
/// Information about the groups to which the user belongs. If the user belongs to no groups then an empty
/// list is returned.
/// </returns>
List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID);
bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID);
GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID);
List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID);
}
public class GroupInviteInfo
{
public UUID GroupID = UUID.Zero;
public UUID RoleID = UUID.Zero;
public string AgentID = string.Empty;
public UUID InviteID = UUID.Zero;
}
public class GroupNoticeInfo
{
public ExtendedGroupNoticeData noticeData = new ExtendedGroupNoticeData();
public UUID GroupID = UUID.Zero;
public string Message = string.Empty;
}
}

View File

@ -1,326 +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.Linq;
using System.Reflection;
using System.Text;
using OpenSim.Framework;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Services.Interfaces;
using OpenMetaverse;
using Mono.Addins;
using log4net;
using Nini.Config;
namespace OpenSim.Groups
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsServiceLocalConnectorModule")]
public class GroupsServiceLocalConnectorModule : ISharedRegionModule, IGroupsServicesConnector
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private bool m_Enabled = false;
private GroupsService m_GroupsService;
private IUserManagement m_UserManagement;
private List<Scene> m_Scenes;
private ForeignImporter m_ForeignImporter;
#region constructors
public GroupsServiceLocalConnectorModule()
{
}
public GroupsServiceLocalConnectorModule(IConfigSource config, IUserManagement uman)
{
Init(config);
m_UserManagement = uman;
m_ForeignImporter = new ForeignImporter(uman);
}
#endregion
private void Init(IConfigSource config)
{
m_GroupsService = new GroupsService(config);
m_Scenes = new List<Scene>();
}
#region ISharedRegionModule
public void Initialise(IConfigSource config)
{
IConfig groupsConfig = config.Configs["Groups"];
if (groupsConfig == null)
return;
if ((groupsConfig.GetBoolean("Enabled", false) == false)
|| (groupsConfig.GetString("ServicesConnectorModule", string.Empty) != Name))
{
return;
}
Init(config);
m_Enabled = true;
m_log.DebugFormat("[Groups]: Initializing {0}", this.Name);
}
public string Name
{
get { return "Groups Local Service Connector"; }
}
public Type ReplaceableInterface
{
get { return null; }
}
public void AddRegion(Scene scene)
{
if (!m_Enabled)
return;
m_log.DebugFormat("[Groups]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName);
scene.RegisterModuleInterface<IGroupsServicesConnector>(this);
m_Scenes.Add(scene);
}
public void RemoveRegion(Scene scene)
{
if (!m_Enabled)
return;
scene.UnregisterModuleInterface<IGroupsServicesConnector>(this);
m_Scenes.Remove(scene);
}
public void RegionLoaded(Scene scene)
{
if (!m_Enabled)
return;
if (m_UserManagement == null)
{
m_UserManagement = scene.RequestModuleInterface<IUserManagement>();
m_ForeignImporter = new ForeignImporter(m_UserManagement);
}
}
public void PostInitialise()
{
}
public void Close()
{
}
#endregion
#region IGroupsServicesConnector
public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment,
bool allowPublish, bool maturePublish, UUID founderID, out string reason)
{
m_log.DebugFormat("[Groups]: Creating group {0}", name);
reason = string.Empty;
return m_GroupsService.CreateGroup(RequestingAgentID.ToString(), name, charter, showInList, insigniaID,
membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out reason);
}
public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee,
bool openEnrollment, bool allowPublish, bool maturePublish, out string reason)
{
reason = string.Empty;
m_GroupsService.UpdateGroup(RequestingAgentID, groupID, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish);
return true;
}
public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName)
{
if (GroupID != UUID.Zero)
return m_GroupsService.GetGroupRecord(RequestingAgentID, GroupID);
else if (GroupName != null)
return m_GroupsService.GetGroupRecord(RequestingAgentID, GroupName);
return null;
}
public List<DirGroupsReplyData> FindGroups(string RequestingAgentIDstr, string search)
{
return m_GroupsService.FindGroups(RequestingAgentIDstr, search);
}
public List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID)
{
List<ExtendedGroupMembersData> _members = m_GroupsService.GetGroupMembers(RequestingAgentID, GroupID);
if (_members != null && _members.Count > 0)
{
List<GroupMembersData> members = _members.ConvertAll<GroupMembersData>(new Converter<ExtendedGroupMembersData, GroupMembersData>(m_ForeignImporter.ConvertGroupMembersData));
return members;
}
return new List<GroupMembersData>();
}
public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason)
{
return m_GroupsService.AddGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers, out reason);
}
public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers)
{
return m_GroupsService.UpdateGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers);
}
public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID)
{
m_GroupsService.RemoveGroupRole(RequestingAgentID, groupID, roleID);
}
public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID)
{
return m_GroupsService.GetGroupRoles(RequestingAgentID, GroupID);
}
public List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID)
{
List<ExtendedGroupRoleMembersData> _rm = m_GroupsService.GetGroupRoleMembers(RequestingAgentID, GroupID);
if (_rm != null && _rm.Count > 0)
{
List<GroupRoleMembersData> rm = _rm.ConvertAll<GroupRoleMembersData>(new Converter<ExtendedGroupRoleMembersData, GroupRoleMembersData>(m_ForeignImporter.ConvertGroupRoleMembersData));
return rm;
}
return new List<GroupRoleMembersData>();
}
public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason)
{
return m_GroupsService.AddAgentToGroup(RequestingAgentID, AgentID, GroupID, RoleID, token, out reason);
}
public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
{
m_GroupsService.RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID);
}
public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID)
{
return m_GroupsService.AddAgentToGroupInvite(RequestingAgentID, inviteID, groupID, roleID, agentID);
}
public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
{
return m_GroupsService.GetAgentToGroupInvite(RequestingAgentID, inviteID); ;
}
public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
{
m_GroupsService.RemoveAgentToGroupInvite(RequestingAgentID, inviteID);
}
public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
{
m_GroupsService.AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
}
public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
{
m_GroupsService.RemoveAgentFromGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
}
public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID)
{
return m_GroupsService.GetAgentGroupRoles(RequestingAgentID, AgentID, GroupID);
}
public void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID)
{
m_GroupsService.SetAgentActiveGroup(RequestingAgentID, AgentID, GroupID);
}
public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID)
{
return m_GroupsService.GetAgentActiveMembership(RequestingAgentID, AgentID);
}
public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
{
m_GroupsService.SetAgentActiveGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
}
public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile)
{
m_GroupsService.UpdateMembership(RequestingAgentID, AgentID, GroupID, AcceptNotices, ListInProfile);
}
public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID)
{
return m_GroupsService.GetAgentGroupMembership(RequestingAgentID, AgentID, GroupID); ;
}
public List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID)
{
return m_GroupsService.GetAgentGroupMemberships(RequestingAgentID, AgentID);
}
public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
{
return m_GroupsService.AddGroupNotice(RequestingAgentID, groupID, noticeID, fromName, subject, message,
hasAttachment, attType, attName, attItemID, attOwnerID);
}
public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID)
{
GroupNoticeInfo notice = m_GroupsService.GetGroupNotice(RequestingAgentID, noticeID);
//if (notice != null && notice.noticeData.HasAttachment && notice.noticeData.AttachmentOwnerID != null)
//{
// UUID userID = UUID.Zero;
// string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty;
// Util.ParseUniversalUserIdentifier(notice.noticeData.AttachmentOwnerID, out userID, out url, out first, out last, out tmp);
// if (url != string.Empty)
// m_UserManagement.AddUser(userID, first, last, url);
//}
return notice;
}
public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID)
{
return m_GroupsService.GetGroupNotices(RequestingAgentID, GroupID);
}
#endregion
}
}

View File

@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Mono.Addins;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("OpenSim.Addons.Groups")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("http://opensimulator.org")]
[assembly: AssemblyProduct("OpenSim.Addons.Groups")]
[assembly: AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("313d4865-d179-4735-9b5a-fe74885878b2")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)]
[assembly: Addin("OpenSim.Groups", OpenSim.VersionInfo.VersionNumber)]
[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]

View File

@ -1,696 +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.Linq;
using System.Reflection;
using System.Text;
using OpenSim.Framework;
using OpenSim.Framework.ServiceAuth;
using OpenSim.Server.Base;
using OpenMetaverse;
using log4net;
using Nini.Config;
namespace OpenSim.Groups
{
public class GroupsServiceRemoteConnector
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private string m_ServerURI;
private IServiceAuth m_Auth;
private object m_Lock = new object();
public GroupsServiceRemoteConnector(IConfigSource config)
{
IConfig groupsConfig = config.Configs["Groups"];
string url = groupsConfig.GetString("GroupsServerURI", string.Empty);
if (!Uri.IsWellFormedUriString(url, UriKind.Absolute))
throw new Exception(string.Format("[Groups.RemoteConnector]: Malformed groups server URL {0}. Fix it or disable the Groups feature.", url));
m_ServerURI = url;
if (!m_ServerURI.EndsWith("/"))
m_ServerURI += "/";
/// This is from BaseServiceConnector
string authType = Util.GetConfigVarFromSections<string>(config, "AuthType", new string[] { "Network", "Groups" }, "None");
switch (authType)
{
case "BasicHttpAuthentication":
m_Auth = new BasicHttpAuthentication(config, "Groups");
break;
}
///
m_log.DebugFormat("[Groups.RemoteConnector]: Groups server at {0}, authentication {1}",
m_ServerURI, (m_Auth == null ? "None" : m_Auth.GetType().ToString()));
}
public ExtendedGroupRecord CreateGroup(string RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment,
bool allowPublish, bool maturePublish, UUID founderID, out string reason)
{
reason = string.Empty;
ExtendedGroupRecord rec = new ExtendedGroupRecord();
rec.AllowPublish = allowPublish;
rec.Charter = charter;
rec.FounderID = founderID;
rec.GroupName = name;
rec.GroupPicture = insigniaID;
rec.MaturePublish = maturePublish;
rec.MembershipFee = membershipFee;
rec.OpenEnrollment = openEnrollment;
rec.ShowInList = showInList;
Dictionary<string, object> sendData = GroupsDataUtils.GroupRecord(rec);
sendData["RequestingAgentID"] = RequestingAgentID;
sendData["OP"] = "ADD";
Dictionary<string, object> ret = MakeRequest("PUTGROUP", sendData);
if (ret == null)
return null;
if (ret["RESULT"].ToString() == "NULL")
{
reason = ret["REASON"].ToString();
return null;
}
return GroupsDataUtils.GroupRecord((Dictionary<string, object>)ret["RESULT"]);
}
public ExtendedGroupRecord UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment, bool allowPublish, bool maturePublish)
{
ExtendedGroupRecord rec = new ExtendedGroupRecord();
rec.AllowPublish = allowPublish;
rec.Charter = charter;
rec.GroupPicture = insigniaID;
rec.MaturePublish = maturePublish;
rec.GroupID = groupID;
rec.MembershipFee = membershipFee;
rec.OpenEnrollment = openEnrollment;
rec.ShowInList = showInList;
Dictionary<string, object> sendData = GroupsDataUtils.GroupRecord(rec);
sendData["RequestingAgentID"] = RequestingAgentID;
sendData["OP"] = "UPDATE";
Dictionary<string, object> ret = MakeRequest("PUTGROUP", sendData);
if (ret == null || (ret != null && (!ret.ContainsKey("RESULT") || ret["RESULT"].ToString() == "NULL")))
return null;
return GroupsDataUtils.GroupRecord((Dictionary<string, object>)ret["RESULT"]);
}
public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName)
{
if (GroupID == UUID.Zero && (GroupName == null || (GroupName != null && GroupName == string.Empty)))
return null;
Dictionary<string, object> sendData = new Dictionary<string, object>();
if (GroupID != UUID.Zero)
sendData["GroupID"] = GroupID.ToString();
if (!string.IsNullOrEmpty(GroupName))
sendData["Name"] = GroupsDataUtils.Sanitize(GroupName);
sendData["RequestingAgentID"] = RequestingAgentID;
Dictionary<string, object> ret = MakeRequest("GETGROUP", sendData);
if (ret == null || (ret != null && (!ret.ContainsKey("RESULT") || ret["RESULT"].ToString() == "NULL")))
return null;
return GroupsDataUtils.GroupRecord((Dictionary<string, object>)ret["RESULT"]);
}
public List<DirGroupsReplyData> FindGroups(string RequestingAgentIDstr, string query)
{
List<DirGroupsReplyData> hits = new List<DirGroupsReplyData>();
if (string.IsNullOrEmpty(query))
return hits;
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["Query"] = query;
sendData["RequestingAgentID"] = RequestingAgentIDstr;
Dictionary<string, object> ret = MakeRequest("FINDGROUPS", sendData);
if (ret == null)
return hits;
if (!ret.ContainsKey("RESULT"))
return hits;
if (ret["RESULT"].ToString() == "NULL")
return hits;
foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
{
DirGroupsReplyData m = GroupsDataUtils.DirGroupsReplyData((Dictionary<string, object>)v);
hits.Add(m);
}
return hits;
}
public GroupMembershipData AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason)
{
reason = string.Empty;
Dictionary<string, object> sendData = new Dictionary<string,object>();
sendData["AgentID"] = AgentID;
sendData["GroupID"] = GroupID.ToString();
sendData["RoleID"] = RoleID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
sendData["AccessToken"] = token;
Dictionary<string, object> ret = MakeRequest("ADDAGENTTOGROUP", sendData);
if (ret == null)
return null;
if (!ret.ContainsKey("RESULT"))
return null;
if (ret["RESULT"].ToString() == "NULL")
{
reason = ret["REASON"].ToString();
return null;
}
return GroupsDataUtils.GroupMembershipData((Dictionary<string, object>)ret["RESULT"]);
}
public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["AgentID"] = AgentID;
sendData["GroupID"] = GroupID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
MakeRequest("REMOVEAGENTFROMGROUP", sendData);
}
public ExtendedGroupMembershipData GetMembership(string RequestingAgentID, string AgentID, UUID GroupID)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["AgentID"] = AgentID;
if (GroupID != UUID.Zero)
sendData["GroupID"] = GroupID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
Dictionary<string, object> ret = MakeRequest("GETMEMBERSHIP", sendData);
if (ret == null)
return null;
if (!ret.ContainsKey("RESULT"))
return null;
if (ret["RESULT"].ToString() == "NULL")
return null;
return GroupsDataUtils.GroupMembershipData((Dictionary<string, object>)ret["RESULT"]);
}
public List<GroupMembershipData> GetMemberships(string RequestingAgentID, string AgentID)
{
List<GroupMembershipData> memberships = new List<GroupMembershipData>();
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["AgentID"] = AgentID;
sendData["ALL"] = "true";
sendData["RequestingAgentID"] = RequestingAgentID;
Dictionary<string, object> ret = MakeRequest("GETMEMBERSHIP", sendData);
if (ret == null)
return memberships;
if (!ret.ContainsKey("RESULT"))
return memberships;
if (ret["RESULT"].ToString() == "NULL")
return memberships;
foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
{
GroupMembershipData m = GroupsDataUtils.GroupMembershipData((Dictionary<string, object>)v);
memberships.Add(m);
}
return memberships;
}
public List<ExtendedGroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID)
{
List<ExtendedGroupMembersData> members = new List<ExtendedGroupMembersData>();
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["GroupID"] = GroupID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
Dictionary<string, object> ret = MakeRequest("GETGROUPMEMBERS", sendData);
if (ret == null)
return members;
if (!ret.ContainsKey("RESULT"))
return members;
if (ret["RESULT"].ToString() == "NULL")
return members;
foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
{
ExtendedGroupMembersData m = GroupsDataUtils.GroupMembersData((Dictionary<string, object>)v);
members.Add(m);
}
return members;
}
public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason)
{
reason = string.Empty;
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["GroupID"] = groupID.ToString();
sendData["RoleID"] = roleID.ToString();
sendData["Name"] = GroupsDataUtils.Sanitize(name);
sendData["Description"] = GroupsDataUtils.Sanitize(description);
sendData["Title"] = GroupsDataUtils.Sanitize(title);
sendData["Powers"] = powers.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
sendData["OP"] = "ADD";
Dictionary<string, object> ret = MakeRequest("PUTROLE", sendData);
if (ret == null)
return false;
if (!ret.ContainsKey("RESULT"))
return false;
if (ret["RESULT"].ToString().ToLower() != "true")
{
reason = ret["REASON"].ToString();
return false;
}
return true;
}
public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["GroupID"] = groupID.ToString();
sendData["RoleID"] = roleID.ToString();
sendData["Name"] = GroupsDataUtils.Sanitize(name);
sendData["Description"] = GroupsDataUtils.Sanitize(description);
sendData["Title"] = GroupsDataUtils.Sanitize(title);
sendData["Powers"] = powers.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
sendData["OP"] = "UPDATE";
Dictionary<string, object> ret = MakeRequest("PUTROLE", sendData);
if (ret == null)
return false;
if (!ret.ContainsKey("RESULT"))
return false;
if (ret["RESULT"].ToString().ToLower() != "true")
return false;
return true;
}
public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["GroupID"] = groupID.ToString();
sendData["RoleID"] = roleID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
MakeRequest("REMOVEROLE", sendData);
}
public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID)
{
List<GroupRolesData> roles = new List<GroupRolesData>();
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["GroupID"] = GroupID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
Dictionary<string, object> ret = MakeRequest("GETGROUPROLES", sendData);
if (ret == null)
return roles;
if (!ret.ContainsKey("RESULT"))
return roles;
if (ret["RESULT"].ToString() == "NULL")
return roles;
foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
{
GroupRolesData m = GroupsDataUtils.GroupRolesData((Dictionary<string, object>)v);
roles.Add(m);
}
return roles;
}
public List<ExtendedGroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID)
{
List<ExtendedGroupRoleMembersData> rmembers = new List<ExtendedGroupRoleMembersData>();
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["GroupID"] = GroupID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
Dictionary<string, object> ret = MakeRequest("GETROLEMEMBERS", sendData);
if (ret == null)
return rmembers;
if (!ret.ContainsKey("RESULT"))
return rmembers;
if (ret["RESULT"].ToString() == "NULL")
return rmembers;
foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
{
ExtendedGroupRoleMembersData m = GroupsDataUtils.GroupRoleMembersData((Dictionary<string, object>)v);
rmembers.Add(m);
}
return rmembers;
}
public bool AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["AgentID"] = AgentID.ToString();
sendData["GroupID"] = GroupID.ToString();
sendData["RoleID"] = RoleID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
sendData["OP"] = "ADD";
Dictionary<string, object> ret = MakeRequest("AGENTROLE", sendData);
if (ret == null)
return false;
if (!ret.ContainsKey("RESULT"))
return false;
if (ret["RESULT"].ToString().ToLower() != "true")
return false;
return true;
}
public bool RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["AgentID"] = AgentID.ToString();
sendData["GroupID"] = GroupID.ToString();
sendData["RoleID"] = RoleID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
sendData["OP"] = "DELETE";
Dictionary<string, object> ret = MakeRequest("AGENTROLE", sendData);
if (ret == null)
return false;
if (!ret.ContainsKey("RESULT"))
return false;
if (ret["RESULT"].ToString().ToLower() != "true")
return false;
return true;
}
public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID)
{
List<GroupRolesData> roles = new List<GroupRolesData>();
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["AgentID"] = AgentID.ToString();
sendData["GroupID"] = GroupID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
Dictionary<string, object> ret = MakeRequest("GETAGENTROLES", sendData);
if (ret == null)
return roles;
if (!ret.ContainsKey("RESULT"))
return roles;
if (ret["RESULT"].ToString() == "NULL")
return roles;
foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
{
GroupRolesData m = GroupsDataUtils.GroupRolesData((Dictionary<string, object>)v);
roles.Add(m);
}
return roles;
}
public GroupMembershipData SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["AgentID"] = AgentID.ToString();
sendData["GroupID"] = GroupID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
sendData["OP"] = "GROUP";
Dictionary<string, object> ret = MakeRequest("SETACTIVE", sendData);
if (ret == null)
return null;
if (!ret.ContainsKey("RESULT"))
return null;
if (ret["RESULT"].ToString() == "NULL")
return null;
return GroupsDataUtils.GroupMembershipData((Dictionary<string, object>)ret["RESULT"]);
}
public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["AgentID"] = AgentID.ToString();
sendData["GroupID"] = GroupID.ToString();
sendData["RoleID"] = RoleID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
sendData["OP"] = "ROLE";
MakeRequest("SETACTIVE", sendData);
}
public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["AgentID"] = AgentID.ToString();
sendData["GroupID"] = GroupID.ToString();
sendData["AcceptNotices"] = AcceptNotices.ToString();
sendData["ListInProfile"] = ListInProfile.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
MakeRequest("UPDATEMEMBERSHIP", sendData);
}
public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["InviteID"] = inviteID.ToString();
sendData["GroupID"] = groupID.ToString();
sendData["RoleID"] = roleID.ToString();
sendData["AgentID"] = agentID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
sendData["OP"] = "ADD";
Dictionary<string, object> ret = MakeRequest("INVITE", sendData);
if (ret == null)
return false;
if (!ret.ContainsKey("RESULT"))
return false;
if (ret["RESULT"].ToString().ToLower() != "true") // it may return "NULL"
return false;
return true;
}
public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["InviteID"] = inviteID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
sendData["OP"] = "GET";
Dictionary<string, object> ret = MakeRequest("INVITE", sendData);
if (ret == null)
return null;
if (!ret.ContainsKey("RESULT"))
return null;
if (ret["RESULT"].ToString() == "NULL")
return null;
return GroupsDataUtils.GroupInviteInfo((Dictionary<string, object>)ret["RESULT"]);
}
public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["InviteID"] = inviteID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
sendData["OP"] = "DELETE";
MakeRequest("INVITE", sendData);
}
public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["GroupID"] = groupID.ToString();
sendData["NoticeID"] = noticeID.ToString();
sendData["FromName"] = GroupsDataUtils.Sanitize(fromName);
sendData["Subject"] = GroupsDataUtils.Sanitize(subject);
sendData["Message"] = GroupsDataUtils.Sanitize(message);
sendData["HasAttachment"] = hasAttachment.ToString();
if (hasAttachment)
{
sendData["AttachmentType"] = attType.ToString();
sendData["AttachmentName"] = attName.ToString();
sendData["AttachmentItemID"] = attItemID.ToString();
sendData["AttachmentOwnerID"] = attOwnerID;
}
sendData["RequestingAgentID"] = RequestingAgentID;
Dictionary<string, object> ret = MakeRequest("ADDNOTICE", sendData);
if (ret == null)
return false;
if (!ret.ContainsKey("RESULT"))
return false;
if (ret["RESULT"].ToString().ToLower() != "true")
return false;
return true;
}
public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["NoticeID"] = noticeID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
Dictionary<string, object> ret = MakeRequest("GETNOTICES", sendData);
if (ret == null)
return null;
if (!ret.ContainsKey("RESULT"))
return null;
if (ret["RESULT"].ToString() == "NULL")
return null;
return GroupsDataUtils.GroupNoticeInfo((Dictionary<string, object>)ret["RESULT"]);
}
public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID)
{
List<ExtendedGroupNoticeData> notices = new List<ExtendedGroupNoticeData>();
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["GroupID"] = GroupID.ToString();
sendData["RequestingAgentID"] = RequestingAgentID;
Dictionary<string, object> ret = MakeRequest("GETNOTICES", sendData);
if (ret == null)
return notices;
if (!ret.ContainsKey("RESULT"))
return notices;
if (ret["RESULT"].ToString() == "NULL")
return notices;
foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
{
ExtendedGroupNoticeData m = GroupsDataUtils.GroupNoticeData((Dictionary<string, object>)v);
notices.Add(m);
}
return notices;
}
#region Make Request
private Dictionary<string, object> MakeRequest(string method, Dictionary<string, object> sendData)
{
sendData["METHOD"] = method;
string reply = string.Empty;
lock (m_Lock)
reply = SynchronousRestFormsRequester.MakeRequest("POST",
m_ServerURI + "groups",
ServerUtils.BuildQueryString(sendData),
m_Auth);
if (reply == string.Empty)
return null;
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(
reply);
return replyData;
}
#endregion
}
}

View File

@ -1,408 +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.Linq;
using System.Reflection;
using System.Threading;
using System.Text;
using OpenSim.Framework;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Server.Base;
using OpenSim.Services.Interfaces;
using OpenMetaverse;
using Mono.Addins;
using log4net;
using Nini.Config;
namespace OpenSim.Groups
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "GroupsServiceRemoteConnectorModule")]
public class GroupsServiceRemoteConnectorModule : ISharedRegionModule, IGroupsServicesConnector
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private bool m_Enabled = false;
private GroupsServiceRemoteConnector m_GroupsService;
private IUserManagement m_UserManagement;
private List<Scene> m_Scenes;
private RemoteConnectorCacheWrapper m_CacheWrapper;
#region constructors
public GroupsServiceRemoteConnectorModule()
{
}
public GroupsServiceRemoteConnectorModule(IConfigSource config, IUserManagement uman)
{
Init(config);
m_UserManagement = uman;
m_CacheWrapper = new RemoteConnectorCacheWrapper(m_UserManagement);
}
#endregion
private void Init(IConfigSource config)
{
m_GroupsService = new GroupsServiceRemoteConnector(config);
m_Scenes = new List<Scene>();
}
#region ISharedRegionModule
public void Initialise(IConfigSource config)
{
IConfig groupsConfig = config.Configs["Groups"];
if (groupsConfig == null)
return;
if ((groupsConfig.GetBoolean("Enabled", false) == false)
|| (groupsConfig.GetString("ServicesConnectorModule", string.Empty) != Name))
{
return;
}
Init(config);
m_Enabled = true;
m_log.DebugFormat("[Groups.RemoteConnector]: Initializing {0}", this.Name);
}
public string Name
{
get { return "Groups Remote Service Connector"; }
}
public Type ReplaceableInterface
{
get { return null; }
}
public void AddRegion(Scene scene)
{
if (!m_Enabled)
return;
m_log.DebugFormat("[Groups.RemoteConnector]: Registering {0} with {1}", this.Name, scene.RegionInfo.RegionName);
scene.RegisterModuleInterface<IGroupsServicesConnector>(this);
m_Scenes.Add(scene);
}
public void RemoveRegion(Scene scene)
{
if (!m_Enabled)
return;
scene.UnregisterModuleInterface<IGroupsServicesConnector>(this);
m_Scenes.Remove(scene);
}
public void RegionLoaded(Scene scene)
{
if (!m_Enabled)
return;
if (m_UserManagement == null)
{
m_UserManagement = scene.RequestModuleInterface<IUserManagement>();
m_CacheWrapper = new RemoteConnectorCacheWrapper(m_UserManagement);
}
}
public void PostInitialise()
{
}
public void Close()
{
}
#endregion
#region IGroupsServicesConnector
public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment,
bool allowPublish, bool maturePublish, UUID founderID, out string reason)
{
m_log.DebugFormat("[Groups.RemoteConnector]: Creating group {0}", name);
string r = string.Empty;
UUID groupID = m_CacheWrapper.CreateGroup(RequestingAgentID, delegate
{
return m_GroupsService.CreateGroup(RequestingAgentID.ToString(), name, charter, showInList, insigniaID,
membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out r);
});
reason = r;
return groupID;
}
public bool UpdateGroup(string RequestingAgentID, UUID groupID, string charter, bool showInList, UUID insigniaID, int membershipFee,
bool openEnrollment, bool allowPublish, bool maturePublish, out string reason)
{
string r = string.Empty;
bool success = m_CacheWrapper.UpdateGroup(groupID, delegate
{
return m_GroupsService.UpdateGroup(RequestingAgentID, groupID, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish);
});
reason = r;
return success;
}
public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName)
{
if (GroupID == UUID.Zero && (GroupName == null || GroupName != null && GroupName == string.Empty))
return null;
return m_CacheWrapper.GetGroupRecord(RequestingAgentID,GroupID,GroupName, delegate
{
return m_GroupsService.GetGroupRecord(RequestingAgentID, GroupID, GroupName);
});
}
public List<DirGroupsReplyData> FindGroups(string RequestingAgentIDstr, string search)
{
// TODO!
return m_GroupsService.FindGroups(RequestingAgentIDstr, search);
}
public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason)
{
string agentFullID = AgentID;
m_log.DebugFormat("[Groups.RemoteConnector]: Add agent {0} to group {1}", agentFullID, GroupID);
string r = string.Empty;
bool success = m_CacheWrapper.AddAgentToGroup(RequestingAgentID, AgentID, GroupID, delegate
{
return m_GroupsService.AddAgentToGroup(RequestingAgentID, agentFullID, GroupID, RoleID, token, out r);
});
reason = r;
return success;
}
public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
{
m_CacheWrapper.RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID, delegate
{
m_GroupsService.RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID);
});
}
public void SetAgentActiveGroup(string RequestingAgentID, string AgentID, UUID GroupID)
{
m_CacheWrapper.SetAgentActiveGroup(AgentID, delegate
{
return m_GroupsService.SetAgentActiveGroup(RequestingAgentID, AgentID, GroupID);
});
}
public ExtendedGroupMembershipData GetAgentActiveMembership(string RequestingAgentID, string AgentID)
{
return m_CacheWrapper.GetAgentActiveMembership(AgentID, delegate
{
return m_GroupsService.GetMembership(RequestingAgentID, AgentID, UUID.Zero);
});
}
public ExtendedGroupMembershipData GetAgentGroupMembership(string RequestingAgentID, string AgentID, UUID GroupID)
{
return m_CacheWrapper.GetAgentGroupMembership(AgentID, GroupID, delegate
{
return m_GroupsService.GetMembership(RequestingAgentID, AgentID, GroupID);
});
}
public List<GroupMembershipData> GetAgentGroupMemberships(string RequestingAgentID, string AgentID)
{
return m_CacheWrapper.GetAgentGroupMemberships(AgentID, delegate
{
return m_GroupsService.GetMemberships(RequestingAgentID, AgentID);
});
}
public List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID)
{
return m_CacheWrapper.GetGroupMembers(RequestingAgentID, GroupID, delegate
{
return m_GroupsService.GetGroupMembers(RequestingAgentID, GroupID);
});
}
public bool AddGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, out string reason)
{
string r = string.Empty;
bool success = m_CacheWrapper.AddGroupRole(groupID, roleID, description, name, powers, title, delegate
{
return m_GroupsService.AddGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers, out r);
});
reason = r;
return success;
}
public bool UpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers)
{
return m_CacheWrapper.UpdateGroupRole(groupID, roleID, name, description, title, powers, delegate
{
return m_GroupsService.UpdateGroupRole(RequestingAgentID, groupID, roleID, name, description, title, powers);
});
}
public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID)
{
m_CacheWrapper.RemoveGroupRole(RequestingAgentID, groupID, roleID, delegate
{
m_GroupsService.RemoveGroupRole(RequestingAgentID, groupID, roleID);
});
}
public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID)
{
return m_CacheWrapper.GetGroupRoles(RequestingAgentID, GroupID, delegate
{
return m_GroupsService.GetGroupRoles(RequestingAgentID, GroupID);
});
}
public List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID)
{
return m_CacheWrapper.GetGroupRoleMembers(RequestingAgentID, GroupID, delegate
{
return m_GroupsService.GetGroupRoleMembers(RequestingAgentID, GroupID);
});
}
public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
{
m_CacheWrapper.AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID, delegate
{
return m_GroupsService.AddAgentToGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
});
}
public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
{
m_CacheWrapper.RemoveAgentFromGroupRole(RequestingAgentID, AgentID, GroupID, RoleID, delegate
{
return m_GroupsService.RemoveAgentFromGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
});
}
public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID)
{
return m_CacheWrapper.GetAgentGroupRoles(RequestingAgentID, AgentID, GroupID, delegate
{
return m_GroupsService.GetAgentGroupRoles(RequestingAgentID, AgentID, GroupID); ;
});
}
public void SetAgentActiveGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
{
m_CacheWrapper.SetAgentActiveGroupRole(AgentID, GroupID, delegate
{
m_GroupsService.SetAgentActiveGroupRole(RequestingAgentID, AgentID, GroupID, RoleID);
});
}
public void UpdateMembership(string RequestingAgentID, string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile)
{
m_CacheWrapper.UpdateMembership(AgentID, GroupID, AcceptNotices, ListInProfile, delegate
{
m_GroupsService.UpdateMembership(RequestingAgentID, AgentID, GroupID, AcceptNotices, ListInProfile);
});
}
public bool AddAgentToGroupInvite(string RequestingAgentID, UUID inviteID, UUID groupID, UUID roleID, string agentID)
{
return m_GroupsService.AddAgentToGroupInvite(RequestingAgentID, inviteID, groupID, roleID, agentID);
}
public GroupInviteInfo GetAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
{
return m_GroupsService.GetAgentToGroupInvite(RequestingAgentID, inviteID);
}
public void RemoveAgentToGroupInvite(string RequestingAgentID, UUID inviteID)
{
m_GroupsService.RemoveAgentToGroupInvite(RequestingAgentID, inviteID);
}
public bool AddGroupNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
{
GroupNoticeInfo notice = new GroupNoticeInfo();
notice.GroupID = groupID;
notice.Message = message;
notice.noticeData = new ExtendedGroupNoticeData();
notice.noticeData.AttachmentItemID = attItemID;
notice.noticeData.AttachmentName = attName;
notice.noticeData.AttachmentOwnerID = attOwnerID.ToString();
notice.noticeData.AttachmentType = attType;
notice.noticeData.FromName = fromName;
notice.noticeData.HasAttachment = hasAttachment;
notice.noticeData.NoticeID = noticeID;
notice.noticeData.Subject = subject;
notice.noticeData.Timestamp = (uint)Util.UnixTimeSinceEpoch();
return m_CacheWrapper.AddGroupNotice(groupID, noticeID, notice, delegate
{
return m_GroupsService.AddGroupNotice(RequestingAgentID, groupID, noticeID, fromName, subject, message,
hasAttachment, attType, attName, attItemID, attOwnerID);
});
}
public GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID)
{
return m_CacheWrapper.GetGroupNotice(noticeID, delegate
{
return m_GroupsService.GetGroupNotice(RequestingAgentID, noticeID);
});
}
public List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID)
{
return m_CacheWrapper.GetGroupNotices(GroupID, delegate
{
return m_GroupsService.GetGroupNotices(RequestingAgentID, GroupID);
});
}
#endregion
}
}

View File

@ -1,817 +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.Reflection;
using System.Text;
using System.Xml;
using System.Collections.Generic;
using System.IO;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Server.Base;
using OpenSim.Services.Interfaces;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Framework.ServiceAuth;
using OpenSim.Server.Handlers.Base;
using log4net;
using OpenMetaverse;
namespace OpenSim.Groups
{
public class GroupsServiceRobustConnector : ServiceConnector
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private GroupsService m_GroupsService;
private string m_ConfigName = "Groups";
public GroupsServiceRobustConnector(IConfigSource config, IHttpServer server, string configName) :
base(config, server, configName)
{
string key = string.Empty;
if (configName != String.Empty)
m_ConfigName = configName;
m_log.DebugFormat("[Groups.RobustConnector]: Starting with config name {0}", m_ConfigName);
IConfig groupsConfig = config.Configs[m_ConfigName];
if (groupsConfig != null)
{
key = groupsConfig.GetString("SecretKey", string.Empty);
m_log.DebugFormat("[Groups.RobustConnector]: Starting with secret key {0}", key);
}
// else
// m_log.DebugFormat("[Groups.RobustConnector]: Unable to find {0} section in configuration", m_ConfigName);
m_GroupsService = new GroupsService(config);
IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName);
server.AddStreamHandler(new GroupsServicePostHandler(m_GroupsService, auth));
}
}
public class GroupsServicePostHandler : BaseStreamHandler
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private GroupsService m_GroupsService;
public GroupsServicePostHandler(GroupsService service, IServiceAuth auth) :
base("POST", "/groups", auth)
{
m_GroupsService = service;
}
protected override byte[] ProcessRequest(string path, Stream requestData,
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
string body;
using(StreamReader sr = new StreamReader(requestData))
body = sr.ReadToEnd();
body = body.Trim();
//m_log.DebugFormat("[XXX]: query String: {0}", body);
try
{
Dictionary<string, object> request =
ServerUtils.ParseQueryString(body);
if (!request.ContainsKey("METHOD"))
return FailureResult();
string method = request["METHOD"].ToString();
request.Remove("METHOD");
// m_log.DebugFormat("[Groups.Handler]: {0}", method);
switch (method)
{
case "PUTGROUP":
return HandleAddOrUpdateGroup(request);
case "GETGROUP":
return HandleGetGroup(request);
case "ADDAGENTTOGROUP":
return HandleAddAgentToGroup(request);
case "REMOVEAGENTFROMGROUP":
return HandleRemoveAgentFromGroup(request);
case "GETMEMBERSHIP":
return HandleGetMembership(request);
case "GETGROUPMEMBERS":
return HandleGetGroupMembers(request);
case "PUTROLE":
return HandlePutRole(request);
case "REMOVEROLE":
return HandleRemoveRole(request);
case "GETGROUPROLES":
return HandleGetGroupRoles(request);
case "GETROLEMEMBERS":
return HandleGetRoleMembers(request);
case "AGENTROLE":
return HandleAgentRole(request);
case "GETAGENTROLES":
return HandleGetAgentRoles(request);
case "SETACTIVE":
return HandleSetActive(request);
case "UPDATEMEMBERSHIP":
return HandleUpdateMembership(request);
case "INVITE":
return HandleInvite(request);
case "ADDNOTICE":
return HandleAddNotice(request);
case "GETNOTICES":
return HandleGetNotices(request);
case "FINDGROUPS":
return HandleFindGroups(request);
}
m_log.DebugFormat("[GROUPS HANDLER]: unknown method request: {0}", method);
}
catch (Exception e)
{
m_log.Error(string.Format("[GROUPS HANDLER]: Exception {0} ", e.Message), e);
}
return FailureResult();
}
byte[] HandleAddOrUpdateGroup(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
ExtendedGroupRecord grec = GroupsDataUtils.GroupRecord(request);
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("OP"))
NullResult(result, "Bad network data");
else
{
string RequestingAgentID = request["RequestingAgentID"].ToString();
string reason = string.Empty;
string op = request["OP"].ToString();
if (op == "ADD")
{
grec.GroupID = m_GroupsService.CreateGroup(RequestingAgentID, grec.GroupName, grec.Charter, grec.ShowInList, grec.GroupPicture, grec.MembershipFee,
grec.OpenEnrollment, grec.AllowPublish, grec.MaturePublish, grec.FounderID, out reason);
}
else if (op == "UPDATE")
{
m_GroupsService.UpdateGroup(RequestingAgentID, grec.GroupID, grec.Charter, grec.ShowInList, grec.GroupPicture, grec.MembershipFee,
grec.OpenEnrollment, grec.AllowPublish, grec.MaturePublish);
}
if (grec.GroupID != UUID.Zero)
{
grec = m_GroupsService.GetGroupRecord(RequestingAgentID, grec.GroupID);
if (grec == null)
NullResult(result, "Internal Error");
else
result["RESULT"] = GroupsDataUtils.GroupRecord(grec);
}
else
NullResult(result, reason);
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleGetGroup(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID"))
NullResult(result, "Bad network data");
else
{
string RequestingAgentID = request["RequestingAgentID"].ToString();
ExtendedGroupRecord grec = null;
if (request.ContainsKey("GroupID"))
{
UUID groupID = new UUID(request["GroupID"].ToString());
grec = m_GroupsService.GetGroupRecord(RequestingAgentID, groupID);
}
else if (request.ContainsKey("Name"))
{
string name = request["Name"].ToString();
grec = m_GroupsService.GetGroupRecord(RequestingAgentID, name);
}
if (grec == null)
NullResult(result, "Group not found");
else
result["RESULT"] = GroupsDataUtils.GroupRecord(grec);
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleAddAgentToGroup(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID") ||
!request.ContainsKey("GroupID") || !request.ContainsKey("RoleID"))
NullResult(result, "Bad network data");
else
{
UUID groupID = new UUID(request["GroupID"].ToString());
UUID roleID = new UUID(request["RoleID"].ToString());
string agentID = request["AgentID"].ToString();
string requestingAgentID = request["RequestingAgentID"].ToString();
string token = string.Empty;
string reason = string.Empty;
if (request.ContainsKey("AccessToken"))
token = request["AccessToken"].ToString();
if (!m_GroupsService.AddAgentToGroup(requestingAgentID, agentID, groupID, roleID, token, out reason))
NullResult(result, reason);
else
{
GroupMembershipData membership = m_GroupsService.GetAgentGroupMembership(requestingAgentID, agentID, groupID);
if (membership == null)
NullResult(result, "Internal error");
else
result["RESULT"] = GroupsDataUtils.GroupMembershipData((ExtendedGroupMembershipData)membership);
}
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleRemoveAgentFromGroup(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID") || !request.ContainsKey("GroupID"))
NullResult(result, "Bad network data");
else
{
UUID groupID = new UUID(request["GroupID"].ToString());
string agentID = request["AgentID"].ToString();
string requestingAgentID = request["RequestingAgentID"].ToString();
if (!m_GroupsService.RemoveAgentFromGroup(requestingAgentID, agentID, groupID))
NullResult(result, string.Format("Insufficient permissions. {0}", agentID));
else
result["RESULT"] = "true";
}
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
}
byte[] HandleGetMembership(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID"))
NullResult(result, "Bad network data");
else
{
string agentID = request["AgentID"].ToString();
UUID groupID = UUID.Zero;
if (request.ContainsKey("GroupID"))
groupID = new UUID(request["GroupID"].ToString());
string requestingAgentID = request["RequestingAgentID"].ToString();
bool all = request.ContainsKey("ALL");
if (!all)
{
ExtendedGroupMembershipData membership = null;
if (groupID == UUID.Zero)
{
membership = m_GroupsService.GetAgentActiveMembership(requestingAgentID, agentID);
}
else
{
membership = m_GroupsService.GetAgentGroupMembership(requestingAgentID, agentID, groupID);
}
if (membership == null)
NullResult(result, "No such membership");
else
result["RESULT"] = GroupsDataUtils.GroupMembershipData(membership);
}
else
{
List<GroupMembershipData> memberships = m_GroupsService.GetAgentGroupMemberships(requestingAgentID, agentID);
if (memberships == null || (memberships != null && memberships.Count == 0))
{
NullResult(result, "No memberships");
}
else
{
Dictionary<string, object> dict = new Dictionary<string, object>();
int i = 0;
foreach (GroupMembershipData m in memberships)
dict["m-" + i++] = GroupsDataUtils.GroupMembershipData((ExtendedGroupMembershipData)m);
result["RESULT"] = dict;
}
}
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleGetGroupMembers(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID"))
NullResult(result, "Bad network data");
else
{
UUID groupID = new UUID(request["GroupID"].ToString());
string requestingAgentID = request["RequestingAgentID"].ToString();
List<ExtendedGroupMembersData> members = m_GroupsService.GetGroupMembers(requestingAgentID, groupID);
if (members == null || (members != null && members.Count == 0))
{
NullResult(result, "No members");
}
else
{
Dictionary<string, object> dict = new Dictionary<string, object>();
int i = 0;
foreach (ExtendedGroupMembersData m in members)
{
dict["m-" + i++] = GroupsDataUtils.GroupMembersData(m);
}
result["RESULT"] = dict;
}
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandlePutRole(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID") ||
!request.ContainsKey("Name") || !request.ContainsKey("Description") || !request.ContainsKey("Title") ||
!request.ContainsKey("Powers") || !request.ContainsKey("OP"))
NullResult(result, "Bad network data");
else
{
string op = request["OP"].ToString();
string reason = string.Empty;
bool success = false;
if (op == "ADD")
success = m_GroupsService.AddGroupRole(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()),
new UUID(request["RoleID"].ToString()), request["Name"].ToString(), request["Description"].ToString(),
request["Title"].ToString(), UInt64.Parse(request["Powers"].ToString()), out reason);
else if (op == "UPDATE")
success = m_GroupsService.UpdateGroupRole(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()),
new UUID(request["RoleID"].ToString()), request["Name"].ToString(), request["Description"].ToString(),
request["Title"].ToString(), UInt64.Parse(request["Powers"].ToString()));
result["RESULT"] = success.ToString();
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleRemoveRole(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID"))
NullResult(result, "Bad network data");
else
{
m_GroupsService.RemoveGroupRole(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()),
new UUID(request["RoleID"].ToString()));
result["RESULT"] = "true";
}
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
}
byte[] HandleGetGroupRoles(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID"))
NullResult(result, "Bad network data");
else
{
UUID groupID = new UUID(request["GroupID"].ToString());
string requestingAgentID = request["RequestingAgentID"].ToString();
List<GroupRolesData> roles = m_GroupsService.GetGroupRoles(requestingAgentID, groupID);
if (roles == null || (roles != null && roles.Count == 0))
{
NullResult(result, "No members");
}
else
{
Dictionary<string, object> dict = new Dictionary<string, object>();
int i = 0;
foreach (GroupRolesData r in roles)
dict["r-" + i++] = GroupsDataUtils.GroupRolesData(r);
result["RESULT"] = dict;
}
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleGetRoleMembers(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID"))
NullResult(result, "Bad network data");
else
{
UUID groupID = new UUID(request["GroupID"].ToString());
string requestingAgentID = request["RequestingAgentID"].ToString();
List<ExtendedGroupRoleMembersData> rmembers = m_GroupsService.GetGroupRoleMembers(requestingAgentID, groupID);
if (rmembers == null || (rmembers != null && rmembers.Count == 0))
{
NullResult(result, "No members");
}
else
{
Dictionary<string, object> dict = new Dictionary<string, object>();
int i = 0;
foreach (ExtendedGroupRoleMembersData rm in rmembers)
dict["rm-" + i++] = GroupsDataUtils.GroupRoleMembersData(rm);
result["RESULT"] = dict;
}
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleAgentRole(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("RoleID") ||
!request.ContainsKey("AgentID") || !request.ContainsKey("OP"))
NullResult(result, "Bad network data");
else
{
string op = request["OP"].ToString();
bool success = false;
if (op == "ADD")
success = m_GroupsService.AddAgentToGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(),
new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString()));
else if (op == "DELETE")
success = m_GroupsService.RemoveAgentFromGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(),
new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString()));
result["RESULT"] = success.ToString();
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleGetAgentRoles(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("AgentID"))
NullResult(result, "Bad network data");
else
{
UUID groupID = new UUID(request["GroupID"].ToString());
string agentID = request["AgentID"].ToString();
string requestingAgentID = request["RequestingAgentID"].ToString();
List<GroupRolesData> roles = m_GroupsService.GetAgentGroupRoles(requestingAgentID, agentID, groupID);
if (roles == null || (roles != null && roles.Count == 0))
{
NullResult(result, "No members");
}
else
{
Dictionary<string, object> dict = new Dictionary<string, object>();
int i = 0;
foreach (GroupRolesData r in roles)
dict["r-" + i++] = GroupsDataUtils.GroupRolesData(r);
result["RESULT"] = dict;
}
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleSetActive(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") ||
!request.ContainsKey("AgentID") || !request.ContainsKey("OP"))
{
NullResult(result, "Bad network data");
string xmlString = ServerUtils.BuildXmlResponse(result);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
else
{
string op = request["OP"].ToString();
if (op == "GROUP")
{
ExtendedGroupMembershipData group = m_GroupsService.SetAgentActiveGroup(request["RequestingAgentID"].ToString(),
request["AgentID"].ToString(), new UUID(request["GroupID"].ToString()));
if (group == null)
NullResult(result, "Internal error");
else
result["RESULT"] = GroupsDataUtils.GroupMembershipData(group);
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
else if (op == "ROLE" && request.ContainsKey("RoleID"))
{
m_GroupsService.SetAgentActiveGroupRole(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(),
new UUID(request["GroupID"].ToString()), new UUID(request["RoleID"].ToString()));
result["RESULT"] = "true";
}
return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
}
}
byte[] HandleUpdateMembership(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("AgentID") || !request.ContainsKey("GroupID") ||
!request.ContainsKey("AcceptNotices") || !request.ContainsKey("ListInProfile"))
NullResult(result, "Bad network data");
else
{
m_GroupsService.UpdateMembership(request["RequestingAgentID"].ToString(), request["AgentID"].ToString(), new UUID(request["GroupID"].ToString()),
bool.Parse(request["AcceptNotices"].ToString()), bool.Parse(request["ListInProfile"].ToString()));
result["RESULT"] = "true";
}
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
}
byte[] HandleInvite(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("InviteID"))
{
NullResult(result, "Bad network data");
string xmlString = ServerUtils.BuildXmlResponse(result);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
else
{
string op = request["OP"].ToString();
if (op == "ADD" && request.ContainsKey("GroupID") && request.ContainsKey("RoleID") && request.ContainsKey("AgentID"))
{
bool success = m_GroupsService.AddAgentToGroupInvite(request["RequestingAgentID"].ToString(),
new UUID(request["InviteID"].ToString()), new UUID(request["GroupID"].ToString()),
new UUID(request["RoleID"].ToString()), request["AgentID"].ToString());
result["RESULT"] = success.ToString();
return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
}
else if (op == "DELETE")
{
m_GroupsService.RemoveAgentToGroupInvite(request["RequestingAgentID"].ToString(), new UUID(request["InviteID"].ToString()));
result["RESULT"] = "true";
return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
}
else if (op == "GET")
{
GroupInviteInfo invite = m_GroupsService.GetAgentToGroupInvite(request["RequestingAgentID"].ToString(),
new UUID(request["InviteID"].ToString()));
if (invite != null)
result["RESULT"] = GroupsDataUtils.GroupInviteInfo(invite);
else
result["RESULT"] = "NULL";
return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
}
NullResult(result, "Bad OP in request");
return Util.UTF8NoBomEncoding.GetBytes(ServerUtils.BuildXmlResponse(result));
}
}
byte[] HandleAddNotice(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("GroupID") || !request.ContainsKey("NoticeID") ||
!request.ContainsKey("FromName") || !request.ContainsKey("Subject") || !request.ContainsKey("Message") ||
!request.ContainsKey("HasAttachment"))
NullResult(result, "Bad network data");
else
{
bool hasAtt = bool.Parse(request["HasAttachment"].ToString());
byte attType = 0;
string attName = string.Empty;
string attOwner = string.Empty;
UUID attItem = UUID.Zero;
if (request.ContainsKey("AttachmentType"))
attType = byte.Parse(request["AttachmentType"].ToString());
if (request.ContainsKey("AttachmentName"))
attName = request["AttachmentName"].ToString();
if (request.ContainsKey("AttachmentItemID"))
attItem = new UUID(request["AttachmentItemID"].ToString());
if (request.ContainsKey("AttachmentOwnerID"))
attOwner = request["AttachmentOwnerID"].ToString();
bool success = m_GroupsService.AddGroupNotice(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()),
new UUID(request["NoticeID"].ToString()), request["FromName"].ToString(), request["Subject"].ToString(),
request["Message"].ToString(), hasAtt, attType, attName, attItem, attOwner);
result["RESULT"] = success.ToString();
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleGetNotices(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID"))
NullResult(result, "Bad network data");
else if (request.ContainsKey("NoticeID")) // just one
{
GroupNoticeInfo notice = m_GroupsService.GetGroupNotice(request["RequestingAgentID"].ToString(), new UUID(request["NoticeID"].ToString()));
if (notice == null)
NullResult(result, "NO such notice");
else
result["RESULT"] = GroupsDataUtils.GroupNoticeInfo(notice);
}
else if (request.ContainsKey("GroupID")) // all notices for group
{
List<ExtendedGroupNoticeData> notices = m_GroupsService.GetGroupNotices(request["RequestingAgentID"].ToString(), new UUID(request["GroupID"].ToString()));
if (notices == null || (notices != null && notices.Count == 0))
NullResult(result, "No notices");
else
{
Dictionary<string, object> dict = new Dictionary<string, object>();
int i = 0;
foreach (ExtendedGroupNoticeData n in notices)
dict["n-" + i++] = GroupsDataUtils.GroupNoticeData(n);
result["RESULT"] = dict;
}
}
else
NullResult(result, "Bad OP in request");
string xmlString = ServerUtils.BuildXmlResponse(result);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleFindGroups(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("RequestingAgentID") || !request.ContainsKey("Query"))
NullResult(result, "Bad network data");
List<DirGroupsReplyData> hits = m_GroupsService.FindGroups(request["RequestingAgentID"].ToString(), request["Query"].ToString());
if (hits == null || (hits != null && hits.Count == 0))
NullResult(result, "No hits");
else
{
Dictionary<string, object> dict = new Dictionary<string, object>();
int i = 0;
foreach (DirGroupsReplyData n in hits)
dict["n-" + i++] = GroupsDataUtils.DirGroupsReplyData(n);
result["RESULT"] = dict;
}
string xmlString = ServerUtils.BuildXmlResponse(result);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
#region Helpers
private void NullResult(Dictionary<string, object> result, string reason)
{
result["RESULT"] = "NULL";
result["REASON"] = reason;
}
private byte[] FailureResult()
{
Dictionary<string, object> result = new Dictionary<string, object>();
NullResult(result, "Unknown method");
string xmlString = ServerUtils.BuildXmlResponse(result);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
private byte[] FailureResult(string reason)
{
Dictionary<string, object> result = new Dictionary<string, object>();
NullResult(result, reason);
string xmlString = ServerUtils.BuildXmlResponse(result);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
#endregion
}
}

View File

@ -1,888 +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.Threading;
using OpenSim.Framework;
//using OpenSim.Region.Framework.Interfaces;
using OpenSim.Services.Interfaces;
using OpenMetaverse;
namespace OpenSim.Groups
{
public delegate ExtendedGroupRecord GroupRecordDelegate();
public delegate GroupMembershipData GroupMembershipDelegate();
public delegate List<GroupMembershipData> GroupMembershipListDelegate();
public delegate List<ExtendedGroupMembersData> GroupMembersListDelegate();
public delegate List<GroupRolesData> GroupRolesListDelegate();
public delegate List<ExtendedGroupRoleMembersData> RoleMembersListDelegate();
public delegate GroupNoticeInfo NoticeDelegate();
public delegate List<ExtendedGroupNoticeData> NoticeListDelegate();
public delegate void VoidDelegate();
public delegate bool BooleanDelegate();
public class RemoteConnectorCacheWrapper
{
private ForeignImporter m_ForeignImporter;
private Dictionary<string, bool> m_ActiveRequests = new Dictionary<string, bool>();
private const int GROUPS_CACHE_TIMEOUT = 1 * 60; // 1 minutes
// This all important cache cahces objects of different types:
// group-<GroupID> or group-<Name> => ExtendedGroupRecord
// active-<AgentID> => GroupMembershipData
// membership-<AgentID>-<GroupID> => GroupMembershipData
// memberships-<AgentID> => List<GroupMembershipData>
// members-<RequestingAgentID>-<GroupID> => List<ExtendedGroupMembersData>
// role-<RoleID> => GroupRolesData
// roles-<GroupID> => List<GroupRolesData> ; all roles in the group
// roles-<GroupID>-<AgentID> => List<GroupRolesData> ; roles that the agent has
// rolemembers-<RequestingAgentID>-<GroupID> => List<ExtendedGroupRoleMembersData>
// notice-<noticeID> => GroupNoticeInfo
// notices-<GroupID> => List<ExtendedGroupNoticeData>
private ExpiringCache<string, object> m_Cache = new ExpiringCache<string, object>();
public RemoteConnectorCacheWrapper(IUserManagement uman)
{
m_ForeignImporter = new ForeignImporter(uman);
}
public UUID CreateGroup(UUID RequestingAgentID, GroupRecordDelegate d)
{
//m_log.DebugFormat("[Groups.RemoteConnector]: Creating group {0}", name);
//reason = string.Empty;
//ExtendedGroupRecord group = m_GroupsService.CreateGroup(RequestingAgentID.ToString(), name, charter, showInList, insigniaID,
// membershipFee, openEnrollment, allowPublish, maturePublish, founderID, out reason);
ExtendedGroupRecord group = d();
if (group == null)
return UUID.Zero;
if (group.GroupID != UUID.Zero)
lock (m_Cache)
{
m_Cache.Add("group-" + group.GroupID.ToString(), group, GROUPS_CACHE_TIMEOUT);
if (m_Cache.Contains("memberships-" + RequestingAgentID.ToString()))
m_Cache.Remove("memberships-" + RequestingAgentID.ToString());
}
return group.GroupID;
}
public bool UpdateGroup(UUID groupID, GroupRecordDelegate d)
{
//reason = string.Empty;
//ExtendedGroupRecord group = m_GroupsService.UpdateGroup(RequestingAgentID, groupID, charter, showInList, insigniaID, membershipFee, openEnrollment, allowPublish, maturePublish);
ExtendedGroupRecord group = d();
if (group != null && group.GroupID != UUID.Zero)
lock (m_Cache)
m_Cache.AddOrUpdate("group-" + group.GroupID.ToString(), group, GROUPS_CACHE_TIMEOUT);
return true;
}
public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string GroupName, GroupRecordDelegate d)
{
//if (GroupID == UUID.Zero && (GroupName == null || GroupName != null && GroupName == string.Empty))
// return null;
object group = null;
bool firstCall = false;
string cacheKey = "group-";
if (GroupID != UUID.Zero)
cacheKey += GroupID.ToString();
else
cacheKey += GroupName;
//m_log.DebugFormat("[XXX]: GetGroupRecord {0}", cacheKey);
while (true)
{
lock (m_Cache)
{
if (m_Cache.TryGetValue(cacheKey, out group))
{
//m_log.DebugFormat("[XXX]: GetGroupRecord {0} cached!", cacheKey);
return (ExtendedGroupRecord)group;
}
// not cached
if (!m_ActiveRequests.ContainsKey(cacheKey))
{
m_ActiveRequests.Add(cacheKey, true);
firstCall = true;
}
}
if (firstCall)
{
try
{
//group = m_GroupsService.GetGroupRecord(RequestingAgentID, GroupID, GroupName);
group = d();
lock (m_Cache)
{
m_Cache.AddOrUpdate(cacheKey, group, GROUPS_CACHE_TIMEOUT);
return (ExtendedGroupRecord)group;
}
}
finally
{
m_ActiveRequests.Remove(cacheKey);
}
}
else
Thread.Sleep(50);
}
}
public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, GroupMembershipDelegate d)
{
GroupMembershipData membership = d();
if (membership == null)
return false;
lock (m_Cache)
{
// first, remove everything! add a user is a heavy-duty op
m_Cache.Clear();
m_Cache.AddOrUpdate("active-" + AgentID.ToString(), membership, GROUPS_CACHE_TIMEOUT);
m_Cache.AddOrUpdate("membership-" + AgentID.ToString() + "-" + GroupID.ToString(), membership, GROUPS_CACHE_TIMEOUT);
}
return true;
}
public void RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID, VoidDelegate d)
{
d();
lock (m_Cache)
{
string cacheKey = "active-" + AgentID.ToString();
if (m_Cache.Contains(cacheKey))
m_Cache.Remove(cacheKey);
cacheKey = "memberships-" + AgentID.ToString();
if (m_Cache.Contains(cacheKey))
m_Cache.Remove(cacheKey);
cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString();
if (m_Cache.Contains(cacheKey))
m_Cache.Remove(cacheKey);
cacheKey = "members-" + RequestingAgentID.ToString() + "-" + GroupID.ToString();
if (m_Cache.Contains(cacheKey))
m_Cache.Remove(cacheKey);
cacheKey = "roles-" + "-" + GroupID.ToString() + "-" + AgentID.ToString();
if (m_Cache.Contains(cacheKey))
m_Cache.Remove(cacheKey);
}
}
public void SetAgentActiveGroup(string AgentID, GroupMembershipDelegate d)
{
GroupMembershipData activeGroup = d();
string cacheKey = "active-" + AgentID.ToString();
lock (m_Cache)
if (m_Cache.Contains(cacheKey))
m_Cache.AddOrUpdate(cacheKey, activeGroup, GROUPS_CACHE_TIMEOUT);
}
public ExtendedGroupMembershipData GetAgentActiveMembership(string AgentID, GroupMembershipDelegate d)
{
object membership = null;
bool firstCall = false;
string cacheKey = "active-" + AgentID.ToString();
//m_log.DebugFormat("[XXX]: GetAgentActiveMembership {0}", cacheKey);
while (true)
{
lock (m_Cache)
{
if (m_Cache.TryGetValue(cacheKey, out membership))
{
//m_log.DebugFormat("[XXX]: GetAgentActiveMembership {0} cached!", cacheKey);
return (ExtendedGroupMembershipData)membership;
}
// not cached
if (!m_ActiveRequests.ContainsKey(cacheKey))
{
m_ActiveRequests.Add(cacheKey, true);
firstCall = true;
}
}
if (firstCall)
{
try
{
membership = d();
lock (m_Cache)
{
m_Cache.AddOrUpdate(cacheKey, membership, GROUPS_CACHE_TIMEOUT);
return (ExtendedGroupMembershipData)membership;
}
}
finally
{
m_ActiveRequests.Remove(cacheKey);
}
}
else
Thread.Sleep(50);
}
}
public ExtendedGroupMembershipData GetAgentGroupMembership(string AgentID, UUID GroupID, GroupMembershipDelegate d)
{
object membership = null;
bool firstCall = false;
string cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString();
//m_log.DebugFormat("[XXX]: GetAgentGroupMembership {0}", cacheKey);
while (true)
{
lock (m_Cache)
{
if (m_Cache.TryGetValue(cacheKey, out membership))
{
//m_log.DebugFormat("[XXX]: GetAgentGroupMembership {0}", cacheKey);
return (ExtendedGroupMembershipData)membership;
}
// not cached
if (!m_ActiveRequests.ContainsKey(cacheKey))
{
m_ActiveRequests.Add(cacheKey, true);
firstCall = true;
}
}
if (firstCall)
{
try
{
membership = d();
lock (m_Cache)
{
m_Cache.AddOrUpdate(cacheKey, membership, GROUPS_CACHE_TIMEOUT);
return (ExtendedGroupMembershipData)membership;
}
}
finally
{
m_ActiveRequests.Remove(cacheKey);
}
}
else
Thread.Sleep(50);
}
}
public List<GroupMembershipData> GetAgentGroupMemberships(string AgentID, GroupMembershipListDelegate d)
{
object memberships = null;
bool firstCall = false;
string cacheKey = "memberships-" + AgentID.ToString();
//m_log.DebugFormat("[XXX]: GetAgentGroupMemberships {0}", cacheKey);
while (true)
{
lock (m_Cache)
{
if (m_Cache.TryGetValue(cacheKey, out memberships))
{
//m_log.DebugFormat("[XXX]: GetAgentGroupMemberships {0} cached!", cacheKey);
return (List<GroupMembershipData>)memberships;
}
// not cached
if (!m_ActiveRequests.ContainsKey(cacheKey))
{
m_ActiveRequests.Add(cacheKey, true);
firstCall = true;
}
}
if (firstCall)
{
try
{
memberships = d();
lock (m_Cache)
{
m_Cache.AddOrUpdate(cacheKey, memberships, GROUPS_CACHE_TIMEOUT);
return (List<GroupMembershipData>)memberships;
}
}
finally
{
m_ActiveRequests.Remove(cacheKey);
}
}
else
Thread.Sleep(50);
}
}
public List<GroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID, GroupMembersListDelegate d)
{
object members = null;
bool firstCall = false;
// we need to key in also on the requester, because different ppl have different view privileges
string cacheKey = "members-" + RequestingAgentID.ToString() + "-" + GroupID.ToString();
//m_log.DebugFormat("[XXX]: GetGroupMembers {0}", cacheKey);
while (true)
{
lock (m_Cache)
{
if (m_Cache.TryGetValue(cacheKey, out members))
{
List<ExtendedGroupMembersData> xx = (List<ExtendedGroupMembersData>)members;
return xx.ConvertAll<GroupMembersData>(new Converter<ExtendedGroupMembersData, GroupMembersData>(m_ForeignImporter.ConvertGroupMembersData));
}
// not cached
if (!m_ActiveRequests.ContainsKey(cacheKey))
{
m_ActiveRequests.Add(cacheKey, true);
firstCall = true;
}
}
if (firstCall)
{
try
{
List<ExtendedGroupMembersData> _members = d();
if (_members != null && _members.Count > 0)
members = _members.ConvertAll<GroupMembersData>(new Converter<ExtendedGroupMembersData, GroupMembersData>(m_ForeignImporter.ConvertGroupMembersData));
else
members = new List<GroupMembersData>();
lock (m_Cache)
{
//m_Cache.AddOrUpdate(cacheKey, members, GROUPS_CACHE_TIMEOUT);
m_Cache.AddOrUpdate(cacheKey, _members, GROUPS_CACHE_TIMEOUT);
return (List<GroupMembersData>)members;
}
}
finally
{
m_ActiveRequests.Remove(cacheKey);
}
}
else
Thread.Sleep(50);
}
}
public bool AddGroupRole(UUID groupID, UUID roleID, string description, string name, ulong powers, string title, BooleanDelegate d)
{
if (d())
{
GroupRolesData role = new GroupRolesData();
role.Description = description;
role.Members = 0;
role.Name = name;
role.Powers = powers;
role.RoleID = roleID;
role.Title = title;
lock (m_Cache)
{
m_Cache.AddOrUpdate("role-" + roleID.ToString(), role, GROUPS_CACHE_TIMEOUT);
// also remove this list
if (m_Cache.Contains("roles-" + groupID.ToString()))
m_Cache.Remove("roles-" + groupID.ToString());
}
return true;
}
return false;
}
public bool UpdateGroupRole(UUID groupID, UUID roleID, string name, string description, string title, ulong powers, BooleanDelegate d)
{
if (d())
{
object role;
lock (m_Cache)
if (m_Cache.TryGetValue("role-" + roleID.ToString(), out role))
{
GroupRolesData r = (GroupRolesData)role;
r.Description = description;
r.Name = name;
r.Powers = powers;
r.Title = title;
m_Cache.Update("role-" + roleID.ToString(), r, GROUPS_CACHE_TIMEOUT);
}
return true;
}
else
{
lock (m_Cache)
{
if (m_Cache.Contains("role-" + roleID.ToString()))
m_Cache.Remove("role-" + roleID.ToString());
// also remove these lists, because they will have an outdated role
if (m_Cache.Contains("roles-" + groupID.ToString()))
m_Cache.Remove("roles-" + groupID.ToString());
}
return false;
}
}
public void RemoveGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, VoidDelegate d)
{
d();
lock (m_Cache)
{
if (m_Cache.Contains("role-" + roleID.ToString()))
m_Cache.Remove("role-" + roleID.ToString());
// also remove the list, because it will have an removed role
if (m_Cache.Contains("roles-" + groupID.ToString()))
m_Cache.Remove("roles-" + groupID.ToString());
if (m_Cache.Contains("roles-" + groupID.ToString() + "-" + RequestingAgentID.ToString()))
m_Cache.Remove("roles-" + groupID.ToString() + "-" + RequestingAgentID.ToString());
if (m_Cache.Contains("rolemembers-" + RequestingAgentID.ToString() + "-" + groupID.ToString()))
m_Cache.Remove("rolemembers-" + RequestingAgentID.ToString() + "-" + groupID.ToString());
}
}
public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID, GroupRolesListDelegate d)
{
object roles = null;
bool firstCall = false;
string cacheKey = "roles-" + GroupID.ToString();
while (true)
{
lock (m_Cache)
{
if (m_Cache.TryGetValue(cacheKey, out roles))
return (List<GroupRolesData>)roles;
// not cached
if (!m_ActiveRequests.ContainsKey(cacheKey))
{
m_ActiveRequests.Add(cacheKey, true);
firstCall = true;
}
}
if (firstCall)
{
try
{
roles = d();
if (roles != null)
{
lock (m_Cache)
{
m_Cache.AddOrUpdate(cacheKey, roles, GROUPS_CACHE_TIMEOUT);
return (List<GroupRolesData>)roles;
}
}
}
finally
{
m_ActiveRequests.Remove(cacheKey);
}
}
else
Thread.Sleep(50);
}
}
public List<GroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID, RoleMembersListDelegate d)
{
object rmembers = null;
bool firstCall = false;
// we need to key in also on the requester, because different ppl have different view privileges
string cacheKey = "rolemembers-" + RequestingAgentID.ToString() + "-" + GroupID.ToString();
//m_log.DebugFormat("[XXX]: GetGroupRoleMembers {0}", cacheKey);
while (true)
{
lock (m_Cache)
{
if (m_Cache.TryGetValue(cacheKey, out rmembers))
{
List<ExtendedGroupRoleMembersData> xx = (List<ExtendedGroupRoleMembersData>)rmembers;
return xx.ConvertAll<GroupRoleMembersData>(m_ForeignImporter.ConvertGroupRoleMembersData);
}
// not cached
if (!m_ActiveRequests.ContainsKey(cacheKey))
{
m_ActiveRequests.Add(cacheKey, true);
firstCall = true;
}
}
if (firstCall)
{
try
{
List<ExtendedGroupRoleMembersData> _rmembers = d();
if (_rmembers != null && _rmembers.Count > 0)
rmembers = _rmembers.ConvertAll<GroupRoleMembersData>(new Converter<ExtendedGroupRoleMembersData, GroupRoleMembersData>(m_ForeignImporter.ConvertGroupRoleMembersData));
else
rmembers = new List<GroupRoleMembersData>();
lock (m_Cache)
{
// For some strange reason, when I cache the list of GroupRoleMembersData,
// it gets emptied out. The TryGet gets an empty list...
//m_Cache.AddOrUpdate(cacheKey, rmembers, GROUPS_CACHE_TIMEOUT);
// Caching the list of ExtendedGroupRoleMembersData doesn't show that issue
// I don't get it.
m_Cache.AddOrUpdate(cacheKey, _rmembers, GROUPS_CACHE_TIMEOUT);
return (List<GroupRoleMembersData>)rmembers;
}
}
finally
{
m_ActiveRequests.Remove(cacheKey);
}
}
else
Thread.Sleep(50);
}
}
public void AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, BooleanDelegate d)
{
if (d())
{
lock (m_Cache)
{
// update the cached role
string cacheKey = "role-" + RoleID.ToString();
object obj;
if (m_Cache.TryGetValue(cacheKey, out obj))
{
GroupRolesData r = (GroupRolesData)obj;
r.Members++;
}
// add this agent to the list of role members
cacheKey = "rolemembers-" + RequestingAgentID.ToString() + "-" + GroupID.ToString();
if (m_Cache.TryGetValue(cacheKey, out obj))
{
try
{
// This may throw an exception, in which case the agentID is not a UUID but a full ID
// In that case, let's just remove the whoe things from the cache
UUID id = new UUID(AgentID);
List<ExtendedGroupRoleMembersData> xx = (List<ExtendedGroupRoleMembersData>)obj;
List<GroupRoleMembersData> rmlist = xx.ConvertAll<GroupRoleMembersData>(m_ForeignImporter.ConvertGroupRoleMembersData);
GroupRoleMembersData rm = new GroupRoleMembersData();
rm.MemberID = id;
rm.RoleID = RoleID;
rmlist.Add(rm);
}
catch
{
m_Cache.Remove(cacheKey);
}
}
// Remove the cached info about this agent's roles
// because we don't have enough local info about the new role
cacheKey = "roles-" + GroupID.ToString() + "-" + AgentID.ToString();
if (m_Cache.Contains(cacheKey))
m_Cache.Remove(cacheKey);
}
}
}
public void RemoveAgentFromGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, BooleanDelegate d)
{
if (d())
{
lock (m_Cache)
{
// update the cached role
string cacheKey = "role-" + RoleID.ToString();
object obj;
if (m_Cache.TryGetValue(cacheKey, out obj))
{
GroupRolesData r = (GroupRolesData)obj;
r.Members--;
}
cacheKey = "roles-" + GroupID.ToString() + "-" + AgentID.ToString();
if (m_Cache.Contains(cacheKey))
m_Cache.Remove(cacheKey);
cacheKey = "rolemembers-" + RequestingAgentID.ToString() + "-" + GroupID.ToString();
if (m_Cache.Contains(cacheKey))
m_Cache.Remove(cacheKey);
}
}
}
public List<GroupRolesData> GetAgentGroupRoles(string RequestingAgentID, string AgentID, UUID GroupID, GroupRolesListDelegate d)
{
object roles = null;
bool firstCall = false;
string cacheKey = "roles-" + GroupID.ToString() + "-" + AgentID.ToString();
//m_log.DebugFormat("[XXX]: GetAgentGroupRoles {0}", cacheKey);
while (true)
{
lock (m_Cache)
{
if (m_Cache.TryGetValue(cacheKey, out roles))
{
//m_log.DebugFormat("[XXX]: GetAgentGroupRoles {0} cached!", cacheKey);
return (List<GroupRolesData>)roles;
}
// not cached
if (!m_ActiveRequests.ContainsKey(cacheKey))
{
m_ActiveRequests.Add(cacheKey, true);
firstCall = true;
}
}
if (firstCall)
{
try
{
roles = d();
lock (m_Cache)
{
m_Cache.AddOrUpdate(cacheKey, roles, GROUPS_CACHE_TIMEOUT);
m_ActiveRequests.Remove(cacheKey);
return (List<GroupRolesData>)roles;
}
}
finally
{
m_ActiveRequests.Remove(cacheKey);
}
}
else
Thread.Sleep(50);
}
}
public void SetAgentActiveGroupRole(string AgentID, UUID GroupID, VoidDelegate d)
{
d();
lock (m_Cache)
{
// Invalidate cached info, because it has ActiveRoleID and Powers
string cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString();
if (m_Cache.Contains(cacheKey))
m_Cache.Remove(cacheKey);
cacheKey = "memberships-" + AgentID.ToString();
if (m_Cache.Contains(cacheKey))
m_Cache.Remove(cacheKey);
}
}
public void UpdateMembership(string AgentID, UUID GroupID, bool AcceptNotices, bool ListInProfile, VoidDelegate d)
{
d();
lock (m_Cache)
{
string cacheKey = "membership-" + AgentID.ToString() + "-" + GroupID.ToString();
if (m_Cache.Contains(cacheKey))
m_Cache.Remove(cacheKey);
cacheKey = "memberships-" + AgentID.ToString();
if (m_Cache.Contains(cacheKey))
m_Cache.Remove(cacheKey);
cacheKey = "active-" + AgentID.ToString();
object m = null;
if (m_Cache.TryGetValue(cacheKey, out m))
{
GroupMembershipData membership = (GroupMembershipData)m;
membership.ListInProfile = ListInProfile;
membership.AcceptNotices = AcceptNotices;
}
}
}
public bool AddGroupNotice(UUID groupID, UUID noticeID, GroupNoticeInfo notice, BooleanDelegate d)
{
if (d())
{
lock (m_Cache)
{
m_Cache.AddOrUpdate("notice-" + noticeID.ToString(), notice, GROUPS_CACHE_TIMEOUT);
string cacheKey = "notices-" + groupID.ToString();
if (m_Cache.Contains(cacheKey))
m_Cache.Remove(cacheKey);
}
return true;
}
return false;
}
public GroupNoticeInfo GetGroupNotice(UUID noticeID, NoticeDelegate d)
{
object notice = null;
bool firstCall = false;
string cacheKey = "notice-" + noticeID.ToString();
//m_log.DebugFormat("[XXX]: GetAgentGroupRoles {0}", cacheKey);
while (true)
{
lock (m_Cache)
{
if (m_Cache.TryGetValue(cacheKey, out notice))
{
return (GroupNoticeInfo)notice;
}
// not cached
if (!m_ActiveRequests.ContainsKey(cacheKey))
{
m_ActiveRequests.Add(cacheKey, true);
firstCall = true;
}
}
if (firstCall)
{
try
{
GroupNoticeInfo _notice = d();
lock (m_Cache)
{
m_Cache.AddOrUpdate(cacheKey, _notice, GROUPS_CACHE_TIMEOUT);
return _notice;
}
}
finally
{
m_ActiveRequests.Remove(cacheKey);
}
}
else
Thread.Sleep(50);
}
}
public List<ExtendedGroupNoticeData> GetGroupNotices(UUID GroupID, NoticeListDelegate d)
{
object notices = null;
bool firstCall = false;
string cacheKey = "notices-" + GroupID.ToString();
//m_log.DebugFormat("[XXX]: GetGroupNotices {0}", cacheKey);
while (true)
{
lock (m_Cache)
{
if (m_Cache.TryGetValue(cacheKey, out notices))
{
//m_log.DebugFormat("[XXX]: GetGroupNotices {0} cached!", cacheKey);
return (List<ExtendedGroupNoticeData>)notices;
}
// not cached
if (!m_ActiveRequests.ContainsKey(cacheKey))
{
m_ActiveRequests.Add(cacheKey, true);
firstCall = true;
}
}
if (firstCall)
{
try
{
notices = d();
lock (m_Cache)
{
m_Cache.AddOrUpdate(cacheKey, notices, GROUPS_CACHE_TIMEOUT);
return (List<ExtendedGroupNoticeData>)notices;
}
}
finally
{
m_ActiveRequests.Remove(cacheKey);
}
}
else
Thread.Sleep(50);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,101 +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.Reflection;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Data;
using OpenSim.Services.Interfaces;
using OpenSim.Services.Base;
namespace OpenSim.Groups
{
public class GroupsServiceBase : ServiceBase
{
protected IGroupsData m_Database = null;
protected IGridUserData m_GridUserService = null;
public GroupsServiceBase(IConfigSource config, string cName)
: base(config)
{
string dllName = String.Empty;
string connString = String.Empty;
string realm = "os_groups";
string usersRealm = "GridUser";
string configName = (cName == string.Empty) ? "Groups" : cName;
//
// Try reading the [DatabaseService] section, if it exists
//
IConfig dbConfig = config.Configs["DatabaseService"];
if (dbConfig != null)
{
if (dllName == String.Empty)
dllName = dbConfig.GetString("StorageProvider", String.Empty);
if (connString == String.Empty)
connString = dbConfig.GetString("ConnectionString", String.Empty);
}
//
// [Groups] section overrides [DatabaseService], if it exists
//
IConfig groupsConfig = config.Configs[configName];
if (groupsConfig != null)
{
dllName = groupsConfig.GetString("StorageProvider", dllName);
connString = groupsConfig.GetString("ConnectionString", connString);
realm = groupsConfig.GetString("Realm", realm);
}
//
// We tried, but this doesn't exist. We can't proceed.
//
if (dllName.Equals(String.Empty))
throw new Exception("No StorageProvider configured");
m_Database = LoadPlugin<IGroupsData>(dllName, new Object[] { connString, realm });
if (m_Database == null)
throw new Exception("Could not find a storage interface in the given module " + dllName);
//
// [GridUserService] section overrides [DatabaseService], if it exists
//
IConfig usersConfig = config.Configs["GridUserService"];
if (usersConfig != null)
{
dllName = usersConfig.GetString("StorageProvider", dllName);
connString = usersConfig.GetString("ConnectionString", connString);
usersRealm = usersConfig.GetString("Realm", usersRealm);
}
m_GridUserService = LoadPlugin<IGridUserData>(dllName, new Object[] { connString, usersRealm });
if (m_GridUserService == null)
throw new Exception("Could not find a storage inferface for the given users module " + dllName);
}
}
}

View File

@ -1,361 +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.Timers;
using log4net;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Data;
using OpenSim.Framework;
using OpenSim.Services.Interfaces;
namespace OpenSim.Groups
{
public class HGGroupsService : GroupsService
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IOfflineIMService m_OfflineIM;
private IUserAccountService m_UserAccounts;
private string m_HomeURI;
public HGGroupsService(IConfigSource config, IOfflineIMService im, IUserAccountService users, string homeURI)
: base(config, string.Empty)
{
m_OfflineIM = im;
m_UserAccounts = users;
m_HomeURI = homeURI;
if (!m_HomeURI.EndsWith("/"))
m_HomeURI += "/";
}
#region HG specific operations
public bool CreateGroupProxy(string RequestingAgentID, string agentID, string accessToken, UUID groupID, string serviceLocation, string name, out string reason)
{
reason = string.Empty;
Uri uri = null;
try
{
uri = new Uri(serviceLocation);
}
catch (UriFormatException)
{
reason = "Bad location for group proxy";
return false;
}
// Check if it already exists
GroupData grec = m_Database.RetrieveGroup(groupID);
if (grec == null ||
(grec != null && grec.Data["Location"] != string.Empty && grec.Data["Location"].ToLower() != serviceLocation.ToLower()))
{
// Create the group
grec = new GroupData();
grec.GroupID = groupID;
grec.Data = new Dictionary<string, string>();
grec.Data["Name"] = name + " @ " + uri.Authority;
grec.Data["Location"] = serviceLocation;
grec.Data["Charter"] = string.Empty;
grec.Data["InsigniaID"] = UUID.Zero.ToString();
grec.Data["FounderID"] = UUID.Zero.ToString();
grec.Data["MembershipFee"] = "0";
grec.Data["OpenEnrollment"] = "0";
grec.Data["ShowInList"] = "0";
grec.Data["AllowPublish"] = "0";
grec.Data["MaturePublish"] = "0";
grec.Data["OwnerRoleID"] = UUID.Zero.ToString();
if (!m_Database.StoreGroup(grec))
return false;
}
if (grec.Data["Location"] == string.Empty)
{
reason = "Cannot add proxy membership to non-proxy group";
return false;
}
UUID uid = UUID.Zero;
string url = string.Empty, first = string.Empty, last = string.Empty, tmp = string.Empty;
Util.ParseUniversalUserIdentifier(RequestingAgentID, out uid, out url, out first, out last, out tmp);
string fromName = first + "." + last + "@" + url;
// Invite to group again
InviteToGroup(fromName, groupID, new UUID(agentID), grec.Data["Name"]);
// Stick the proxy membership in the DB already
// we'll delete it if the agent declines the invitation
MembershipData membership = new MembershipData();
membership.PrincipalID = agentID;
membership.GroupID = groupID;
membership.Data = new Dictionary<string, string>();
membership.Data["SelectedRoleID"] = UUID.Zero.ToString();
membership.Data["Contribution"] = "0";
membership.Data["ListInProfile"] = "1";
membership.Data["AcceptNotices"] = "1";
membership.Data["AccessToken"] = accessToken;
m_Database.StoreMember(membership);
return true;
}
public bool RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID, string token)
{
// check the token
MembershipData membership = m_Database.RetrieveMember(GroupID, AgentID);
if (membership != null)
{
if (token != string.Empty && token.Equals(membership.Data["AccessToken"]))
{
return RemoveAgentFromGroup(RequestingAgentID, AgentID, GroupID);
}
else
{
m_log.DebugFormat("[Groups.HGGroupsService]: access token {0} did not match stored one {1}", token, membership.Data["AccessToken"]);
return false;
}
}
else
{
m_log.DebugFormat("[Groups.HGGroupsService]: membership not found for {0}", AgentID);
return false;
}
}
public ExtendedGroupRecord GetGroupRecord(string RequestingAgentID, UUID GroupID, string groupName, string token)
{
// check the token
if (!VerifyToken(GroupID, RequestingAgentID, token))
return null;
ExtendedGroupRecord grec;
if (GroupID == UUID.Zero)
grec = GetGroupRecord(RequestingAgentID, groupName);
else
grec = GetGroupRecord(RequestingAgentID, GroupID);
if (grec != null)
FillFounderUUI(grec);
return grec;
}
public List<ExtendedGroupMembersData> GetGroupMembers(string RequestingAgentID, UUID GroupID, string token)
{
if (!VerifyToken(GroupID, RequestingAgentID, token))
return new List<ExtendedGroupMembersData>();
List<ExtendedGroupMembersData> members = GetGroupMembers(RequestingAgentID, GroupID);
// convert UUIDs to UUIs
members.ForEach(delegate (ExtendedGroupMembersData m)
{
if (m.AgentID.ToString().Length == 36) // UUID
{
UserAccount account = m_UserAccounts.GetUserAccount(UUID.Zero, new UUID(m.AgentID));
if (account != null)
m.AgentID = Util.UniversalIdentifier(account.PrincipalID, account.FirstName, account.LastName, m_HomeURI);
}
});
return members;
}
public List<GroupRolesData> GetGroupRoles(string RequestingAgentID, UUID GroupID, string token)
{
if (!VerifyToken(GroupID, RequestingAgentID, token))
return new List<GroupRolesData>();
return GetGroupRoles(RequestingAgentID, GroupID);
}
public List<ExtendedGroupRoleMembersData> GetGroupRoleMembers(string RequestingAgentID, UUID GroupID, string token)
{
if (!VerifyToken(GroupID, RequestingAgentID, token))
return new List<ExtendedGroupRoleMembersData>();
List<ExtendedGroupRoleMembersData> rolemembers = GetGroupRoleMembers(RequestingAgentID, GroupID);
// convert UUIDs to UUIs
rolemembers.ForEach(delegate(ExtendedGroupRoleMembersData m)
{
if (m.MemberID.ToString().Length == 36) // UUID
{
UserAccount account = m_UserAccounts.GetUserAccount(UUID.Zero, new UUID(m.MemberID));
if (account != null)
m.MemberID = Util.UniversalIdentifier(account.PrincipalID, account.FirstName, account.LastName, m_HomeURI);
}
});
return rolemembers;
}
public bool AddNotice(string RequestingAgentID, UUID groupID, UUID noticeID, string fromName, string subject, string message,
bool hasAttachment, byte attType, string attName, UUID attItemID, string attOwnerID)
{
// check that the group proxy exists
ExtendedGroupRecord grec = GetGroupRecord(RequestingAgentID, groupID);
if (grec == null)
{
m_log.DebugFormat("[Groups.HGGroupsService]: attempt at adding notice to non-existent group proxy");
return false;
}
// check that the group is remote
if (grec.ServiceLocation == string.Empty)
{
m_log.DebugFormat("[Groups.HGGroupsService]: attempt at adding notice to local (non-proxy) group");
return false;
}
// check that there isn't already a notice with the same ID
if (GetGroupNotice(RequestingAgentID, noticeID) != null)
{
m_log.DebugFormat("[Groups.HGGroupsService]: a notice with the same ID already exists", grec.ServiceLocation);
return false;
}
// This has good intentions (security) but it will potentially DDS the origin...
// We'll need to send a proof along with the message. Maybe encrypt the message
// using key pairs
//
//// check that the notice actually exists in the origin
//GroupsServiceHGConnector c = new GroupsServiceHGConnector(grec.ServiceLocation);
//if (!c.VerifyNotice(noticeID, groupID))
//{
// m_log.DebugFormat("[Groups.HGGroupsService]: notice does not exist at origin {0}", grec.ServiceLocation);
// return false;
//}
// ok, we're good!
return _AddNotice(groupID, noticeID, fromName, subject, message, hasAttachment, attType, attName, attItemID, attOwnerID);
}
public bool VerifyNotice(UUID noticeID, UUID groupID)
{
GroupNoticeInfo notice = GetGroupNotice(string.Empty, noticeID);
if (notice == null)
return false;
if (notice.GroupID != groupID)
return false;
return true;
}
#endregion
private void InviteToGroup(string fromName, UUID groupID, UUID invitedAgentID, string groupName)
{
// Todo: Security check, probably also want to send some kind of notification
UUID InviteID = UUID.Random();
if (AddAgentToGroupInvite(InviteID, groupID, invitedAgentID.ToString()))
{
Guid inviteUUID = InviteID.Guid;
GridInstantMessage msg = new GridInstantMessage();
msg.imSessionID = inviteUUID;
// msg.fromAgentID = agentID.Guid;
msg.fromAgentID = groupID.Guid;
msg.toAgentID = invitedAgentID.Guid;
//msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
msg.timestamp = 0;
msg.fromAgentName = fromName;
msg.message = string.Format("Please confirm your acceptance to join group {0}.", groupName);
msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupInvitation;
msg.fromGroup = true;
msg.offline = (byte)0;
msg.ParentEstateID = 0;
msg.Position = Vector3.Zero;
msg.RegionID = UUID.Zero.Guid;
msg.binaryBucket = new byte[20];
string reason = string.Empty;
m_OfflineIM.StoreMessage(msg, out reason);
}
}
private bool AddAgentToGroupInvite(UUID inviteID, UUID groupID, string agentID)
{
// Check whether the invitee is already a member of the group
MembershipData m = m_Database.RetrieveMember(groupID, agentID);
if (m != null)
return false;
// Check whether there are pending invitations and delete them
InvitationData invite = m_Database.RetrieveInvitation(groupID, agentID);
if (invite != null)
m_Database.DeleteInvite(invite.InviteID);
invite = new InvitationData();
invite.InviteID = inviteID;
invite.PrincipalID = agentID;
invite.GroupID = groupID;
invite.RoleID = UUID.Zero;
invite.Data = new Dictionary<string, string>();
return m_Database.StoreInvitation(invite);
}
private void FillFounderUUI(ExtendedGroupRecord grec)
{
UserAccount account = m_UserAccounts.GetUserAccount(UUID.Zero, grec.FounderID);
if (account != null)
grec.FounderUUI = Util.UniversalIdentifier(account.PrincipalID, account.FirstName, account.LastName, m_HomeURI);
}
private bool VerifyToken(UUID groupID, string agentID, string token)
{
// check the token
MembershipData membership = m_Database.RetrieveMember(groupID, agentID);
if (membership != null)
{
if (token != string.Empty && token.Equals(membership.Data["AccessToken"]))
return true;
else
m_log.DebugFormat("[Groups.HGGroupsService]: access token {0} did not match stored one {1}", token, membership.Data["AccessToken"]);
}
else
m_log.DebugFormat("[Groups.HGGroupsService]: membership not found for {0}", agentID);
return false;
}
}
}

View File

@ -1,252 +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 log4net;
using Mono.Addins;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Client;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces;
namespace OpenSim.OfflineIM
{
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "OfflineIMConnectorModule")]
public class OfflineIMRegionModule : ISharedRegionModule, IOfflineIMService
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private bool m_Enabled = false;
private List<Scene> m_SceneList = new List<Scene>();
IMessageTransferModule m_TransferModule = null;
private bool m_ForwardOfflineGroupMessages = true;
private IOfflineIMService m_OfflineIMService;
public void Initialise(IConfigSource config)
{
IConfig cnf = config.Configs["Messaging"];
if (cnf == null)
return;
if (cnf != null && cnf.GetString("OfflineMessageModule", string.Empty) != Name)
return;
m_Enabled = true;
string serviceLocation = cnf.GetString("OfflineMessageURL", string.Empty);
if (serviceLocation == string.Empty)
m_OfflineIMService = new OfflineIMService(config);
else
m_OfflineIMService = new OfflineIMServiceRemoteConnector(config);
m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", m_ForwardOfflineGroupMessages);
m_log.DebugFormat("[OfflineIM.V2]: Offline messages enabled by {0}", Name);
}
public void AddRegion(Scene scene)
{
if (!m_Enabled)
return;
scene.RegisterModuleInterface<IOfflineIMService>(this);
m_SceneList.Add(scene);
scene.EventManager.OnNewClient += OnNewClient;
}
public void RegionLoaded(Scene scene)
{
if (!m_Enabled)
return;
if (m_TransferModule == null)
{
m_TransferModule = scene.RequestModuleInterface<IMessageTransferModule>();
if (m_TransferModule == null)
{
scene.EventManager.OnNewClient -= OnNewClient;
m_SceneList.Clear();
m_log.Error("[OfflineIM.V2]: No message transfer module is enabled. Disabling offline messages");
}
m_TransferModule.OnUndeliveredMessage += UndeliveredMessage;
}
}
public void RemoveRegion(Scene scene)
{
if (!m_Enabled)
return;
m_SceneList.Remove(scene);
scene.EventManager.OnNewClient -= OnNewClient;
m_TransferModule.OnUndeliveredMessage -= UndeliveredMessage;
scene.ForEachClient(delegate(IClientAPI client)
{
client.OnRetrieveInstantMessages -= RetrieveInstantMessages;
});
}
public void PostInitialise()
{
}
public string Name
{
get { return "Offline Message Module V2"; }
}
public Type ReplaceableInterface
{
get { return null; }
}
public void Close()
{
m_SceneList.Clear();
}
private Scene FindScene(UUID agentID)
{
foreach (Scene s in m_SceneList)
{
ScenePresence presence = s.GetScenePresence(agentID);
if (presence != null && !presence.IsChildAgent)
return s;
}
return null;
}
private IClientAPI FindClient(UUID agentID)
{
foreach (Scene s in m_SceneList)
{
ScenePresence presence = s.GetScenePresence(agentID);
if (presence != null && !presence.IsChildAgent)
return presence.ControllingClient;
}
return null;
}
private void OnNewClient(IClientAPI client)
{
client.OnRetrieveInstantMessages += RetrieveInstantMessages;
}
private void RetrieveInstantMessages(IClientAPI client)
{
m_log.DebugFormat("[OfflineIM.V2]: Retrieving stored messages for {0}", client.AgentId);
List<GridInstantMessage> msglist = m_OfflineIMService.GetMessages(client.AgentId);
if (msglist == null)
m_log.DebugFormat("[OfflineIM.V2]: WARNING null message list.");
foreach (GridInstantMessage im in msglist)
{
if (im.dialog == (byte)InstantMessageDialog.InventoryOffered)
// send it directly or else the item will be given twice
client.SendInstantMessage(im);
else
{
// Send through scene event manager so all modules get a chance
// to look at this message before it gets delivered.
//
// Needed for proper state management for stored group
// invitations
//
Scene s = FindScene(client.AgentId);
if (s != null)
s.EventManager.TriggerIncomingInstantMessage(im);
}
}
}
private void UndeliveredMessage(GridInstantMessage im)
{
if (im.dialog != (byte)InstantMessageDialog.MessageFromObject &&
im.dialog != (byte)InstantMessageDialog.MessageFromAgent &&
im.dialog != (byte)InstantMessageDialog.GroupNotice &&
im.dialog != (byte)InstantMessageDialog.GroupInvitation &&
im.dialog != (byte)InstantMessageDialog.InventoryOffered)
{
return;
}
if (!m_ForwardOfflineGroupMessages)
{
if (im.dialog == (byte)InstantMessageDialog.GroupNotice ||
im.dialog == (byte)InstantMessageDialog.GroupInvitation)
return;
}
string reason = string.Empty;
bool success = m_OfflineIMService.StoreMessage(im, out reason);
if (im.dialog == (byte)InstantMessageDialog.MessageFromAgent)
{
IClientAPI client = FindClient(new UUID(im.fromAgentID));
if (client == null)
return;
client.SendInstantMessage(new GridInstantMessage(
null, new UUID(im.toAgentID),
"System", new UUID(im.fromAgentID),
(byte)InstantMessageDialog.MessageFromAgent,
"User is not logged in. " +
(success ? "Message saved." : "Message not saved: " + reason),
false, new Vector3()));
}
}
#region IOfflineIM
public List<GridInstantMessage> GetMessages(UUID principalID)
{
return m_OfflineIMService.GetMessages(principalID);
}
public bool StoreMessage(GridInstantMessage im, out string reason)
{
return m_OfflineIMService.StoreMessage(im, out reason);
}
public void DeleteMessages(UUID userID)
{
m_OfflineIMService.DeleteMessages(userID);
}
#endregion
}
}

View File

@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Mono.Addins;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("OpenSim.Addons.OfflineIM")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("http://opensimulator.org")]
[assembly: AssemblyProduct("OpenSim.Addons.OfflineIM")]
[assembly: AssemblyCopyright("Copyright (c) OpenSimulator.org Developers")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a16a9905-4393-4872-9fca-4c81bedbd9f2")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)]
[assembly: Addin("OpenSim.OfflineIM", OpenSim.VersionInfo.VersionNumber)]
[assembly: AddinDependency("OpenSim.Region.Framework", OpenSim.VersionInfo.VersionNumber)]

View File

@ -1,171 +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.Linq;
using System.Reflection;
using System.Text;
using OpenSim.Framework;
using OpenSim.Framework.ServiceAuth;
using OpenSim.Server.Base;
using OpenSim.Services.Interfaces;
using OpenMetaverse;
using log4net;
using Nini.Config;
namespace OpenSim.OfflineIM
{
public class OfflineIMServiceRemoteConnector : IOfflineIMService
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private string m_ServerURI = string.Empty;
private IServiceAuth m_Auth;
private object m_Lock = new object();
public OfflineIMServiceRemoteConnector(string url)
{
m_ServerURI = url;
m_log.DebugFormat("[OfflineIM.V2.RemoteConnector]: Offline IM server at {0}", m_ServerURI);
}
public OfflineIMServiceRemoteConnector(IConfigSource config)
{
IConfig cnf = config.Configs["Messaging"];
if (cnf == null)
{
m_log.WarnFormat("[OfflineIM.V2.RemoteConnector]: Missing Messaging configuration");
return;
}
m_ServerURI = cnf.GetString("OfflineMessageURL", string.Empty);
/// This is from BaseServiceConnector
string authType = Util.GetConfigVarFromSections<string>(config, "AuthType", new string[] { "Network", "Messaging" }, "None");
switch (authType)
{
case "BasicHttpAuthentication":
m_Auth = new BasicHttpAuthentication(config, "Messaging");
break;
}
///
m_log.DebugFormat("[OfflineIM.V2.RemoteConnector]: Offline IM server at {0} with auth {1}",
m_ServerURI, (m_Auth == null ? "None" : m_Auth.GetType().ToString()));
}
#region IOfflineIMService
public List<GridInstantMessage> GetMessages(UUID principalID)
{
List<GridInstantMessage> ims = new List<GridInstantMessage>();
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["PrincipalID"] = principalID;
Dictionary<string, object> ret = MakeRequest("GET", sendData);
if (ret == null)
return ims;
if (!ret.ContainsKey("RESULT"))
return ims;
string result = ret["RESULT"].ToString();
if (result == "NULL" || result.ToLower() == "false")
{
string reason = ret.ContainsKey("REASON") ? ret["REASON"].ToString() : "Unknown error";
m_log.DebugFormat("[OfflineIM.V2.RemoteConnector]: GetMessages for {0} failed: {1}", principalID, reason);
return ims;
}
foreach (object v in ((Dictionary<string, object>)ret["RESULT"]).Values)
{
GridInstantMessage m = OfflineIMDataUtils.GridInstantMessage((Dictionary<string, object>)v);
ims.Add(m);
}
return ims;
}
public bool StoreMessage(GridInstantMessage im, out string reason)
{
reason = string.Empty;
Dictionary<string, object> sendData = OfflineIMDataUtils.GridInstantMessage(im);
Dictionary<string, object> ret = MakeRequest("STORE", sendData);
if (ret == null)
{
reason = "Bad response from server";
return false;
}
string result = ret["RESULT"].ToString();
if (result == "NULL" || result.ToLower() == "false")
{
reason = ret.ContainsKey("REASON") ? ret["REASON"].ToString() : "Unknown error";
return false;
}
return true;
}
public void DeleteMessages(UUID userID)
{
Dictionary<string, object> sendData = new Dictionary<string, object>();
sendData["UserID"] = userID;
MakeRequest("DELETE", sendData);
}
#endregion
#region Make Request
private Dictionary<string, object> MakeRequest(string method, Dictionary<string, object> sendData)
{
sendData["METHOD"] = method;
string reply = string.Empty;
lock (m_Lock)
reply = SynchronousRestFormsRequester.MakeRequest("POST",
m_ServerURI + "/offlineim",
ServerUtils.BuildQueryString(sendData),
m_Auth);
Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(
reply);
return replyData;
}
#endregion
}
}

View File

@ -1,223 +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.Reflection;
using System.Text;
using System.Xml;
using System.Collections.Generic;
using System.IO;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Server.Base;
using OpenSim.Services.Interfaces;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Framework.ServiceAuth;
using OpenSim.Server.Handlers.Base;
using log4net;
using OpenMetaverse;
namespace OpenSim.OfflineIM
{
public class OfflineIMServiceRobustConnector : ServiceConnector
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IOfflineIMService m_OfflineIMService;
private string m_ConfigName = "Messaging";
public OfflineIMServiceRobustConnector(IConfigSource config, IHttpServer server, string configName) :
base(config, server, configName)
{
if (configName != String.Empty)
m_ConfigName = configName;
m_log.DebugFormat("[OfflineIM.V2.RobustConnector]: Starting with config name {0}", m_ConfigName);
m_OfflineIMService = new OfflineIMService(config);
IServiceAuth auth = ServiceAuth.Create(config, m_ConfigName);
server.AddStreamHandler(new OfflineIMServicePostHandler(m_OfflineIMService, auth));
}
}
public class OfflineIMServicePostHandler : BaseStreamHandler
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IOfflineIMService m_OfflineIMService;
public OfflineIMServicePostHandler(IOfflineIMService service, IServiceAuth auth) :
base("POST", "/offlineim", auth)
{
m_OfflineIMService = service;
}
protected override byte[] ProcessRequest(string path, Stream requestData,
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
StreamReader sr = new StreamReader(requestData);
string body = sr.ReadToEnd();
sr.Close();
body = body.Trim();
//m_log.DebugFormat("[XXX]: query String: {0}", body);
try
{
Dictionary<string, object> request =
ServerUtils.ParseQueryString(body);
if (!request.ContainsKey("METHOD"))
return FailureResult();
string method = request["METHOD"].ToString();
request.Remove("METHOD");
switch (method)
{
case "GET":
return HandleGet(request);
case "STORE":
return HandleStore(request);
case "DELETE":
return HandleDelete(request);
}
m_log.DebugFormat("[OFFLINE IM HANDLER]: unknown method request: {0}", method);
}
catch (Exception e)
{
m_log.Error(string.Format("[OFFLINE IM HANDLER]: Exception {0} ", e.Message), e);
}
return FailureResult();
}
byte[] HandleStore(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
GridInstantMessage im = OfflineIMDataUtils.GridInstantMessage(request);
string reason = string.Empty;
bool success = m_OfflineIMService.StoreMessage(im, out reason);
result["RESULT"] = success.ToString();
if (!success)
result["REASON"] = reason;
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleGet(Dictionary<string, object> request)
{
Dictionary<string, object> result = new Dictionary<string, object>();
if (!request.ContainsKey("PrincipalID"))
NullResult(result, "Bad network data");
else
{
UUID principalID = new UUID(request["PrincipalID"].ToString());
List<GridInstantMessage> ims = m_OfflineIMService.GetMessages(principalID);
Dictionary<string, object> dict = new Dictionary<string, object>();
int i = 0;
foreach (GridInstantMessage m in ims)
dict["im-" + i++] = OfflineIMDataUtils.GridInstantMessage(m);
result["RESULT"] = dict;
}
string xmlString = ServerUtils.BuildXmlResponse(result);
//m_log.DebugFormat("[XXX]: resp string: {0}", xmlString);
return Util.UTF8NoBomEncoding.GetBytes(xmlString);
}
byte[] HandleDelete(Dictionary<string, object> request)
{
if (!request.ContainsKey("UserID"))
{
return FailureResult();
}
else
{
UUID userID = new UUID(request["UserID"].ToString());
m_OfflineIMService.DeleteMessages(userID);
return SuccessResult();
}
}
#region Helpers
private void NullResult(Dictionary<string, object> result, string reason)
{
result["RESULT"] = "NULL";
result["REASON"] = reason;
}
private byte[] FailureResult()
{
return BoolResult(false);
}
private byte[] SuccessResult()
{
return BoolResult(true);
}
private byte[] BoolResult(bool value)
{
XmlDocument doc = new XmlDocument();
XmlNode xmlnode = doc.CreateNode(XmlNodeType.XmlDeclaration,
"", "");
doc.AppendChild(xmlnode);
XmlElement rootElement = doc.CreateElement("", "ServerResponse",
"");
doc.AppendChild(rootElement);
XmlElement result = doc.CreateElement("", "RESULT", "");
result.AppendChild(doc.CreateTextNode(value.ToString()));
rootElement.AppendChild(result);
return Util.DocToBytes(doc);
}
#endregion
}
}

View File

@ -1,134 +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.Runtime.Serialization;
using System.Text;
using System.Timers;
using System.Xml;
using System.Xml.Serialization;
using log4net;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Data;
using OpenSim.Framework;
using OpenSim.Services.Interfaces;
namespace OpenSim.OfflineIM
{
public class OfflineIMService : OfflineIMServiceBase, IOfflineIMService
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private const int MAX_IM = 25;
private XmlSerializer m_serializer;
private static bool m_Initialized = false;
public OfflineIMService(IConfigSource config)
: base(config)
{
m_serializer = new XmlSerializer(typeof(GridInstantMessage));
if (!m_Initialized)
{
m_Database.DeleteOld();
m_Initialized = true;
}
}
public List<GridInstantMessage> GetMessages(UUID principalID)
{
List<GridInstantMessage> ims = new List<GridInstantMessage>();
OfflineIMData[] messages = m_Database.Get("PrincipalID", principalID.ToString());
if (messages == null || (messages != null && messages.Length == 0))
return ims;
foreach (OfflineIMData m in messages)
{
using (MemoryStream mstream = new MemoryStream(Encoding.UTF8.GetBytes(m.Data["Message"])))
{
GridInstantMessage im = (GridInstantMessage)m_serializer.Deserialize(mstream);
ims.Add(im);
}
}
// Then, delete them
m_Database.Delete("PrincipalID", principalID.ToString());
return ims;
}
public bool StoreMessage(GridInstantMessage im, out string reason)
{
reason = string.Empty;
// Check limits
UUID principalID = new UUID(im.toAgentID);
long count = m_Database.GetCount("PrincipalID", principalID.ToString());
if (count >= MAX_IM)
{
reason = "Number of offline IMs has maxed out";
return false;
}
string imXml;
using (MemoryStream mstream = new MemoryStream())
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Encoding = Util.UTF8NoBomEncoding;
using (XmlWriter writer = XmlWriter.Create(mstream, settings))
{
m_serializer.Serialize(writer, im);
writer.Flush();
imXml = Util.UTF8NoBomEncoding.GetString(mstream.ToArray());
}
}
OfflineIMData data = new OfflineIMData();
data.PrincipalID = principalID;
data.FromID = new UUID(im.fromAgentID);
data.Data = new Dictionary<string, string>();
data.Data["Message"] = imXml;
return m_Database.Store(data);
}
public void DeleteMessages(UUID userID)
{
m_Database.Delete("PrincipalID", userID.ToString());
m_Database.Delete("FromID", userID.ToString());
}
}
}

View File

@ -1,83 +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 Nini.Config;
using OpenSim.Framework;
using OpenSim.Data;
using OpenSim.Services.Interfaces;
using OpenSim.Services.Base;
namespace OpenSim.OfflineIM
{
public class OfflineIMServiceBase : ServiceBase
{
protected IOfflineIMData m_Database = null;
public OfflineIMServiceBase(IConfigSource config)
: base(config)
{
string dllName = String.Empty;
string connString = String.Empty;
string realm = "im_offline";
//
// Try reading the [DatabaseService] section, if it exists
//
IConfig dbConfig = config.Configs["DatabaseService"];
if (dbConfig != null)
{
if (dllName == String.Empty)
dllName = dbConfig.GetString("StorageProvider", String.Empty);
if (connString == String.Empty)
connString = dbConfig.GetString("ConnectionString", String.Empty);
}
//
// [Messaging] section overrides [DatabaseService], if it exists
//
IConfig imConfig = config.Configs["Messaging"];
if (imConfig != null)
{
dllName = imConfig.GetString("StorageProvider", dllName);
connString = imConfig.GetString("ConnectionString", connString);
realm = imConfig.GetString("Realm", realm);
}
//
// We tried, but this doesn't exist. We can't proceed.
//
if (dllName.Equals(String.Empty))
throw new Exception("No StorageProvider configured");
m_Database = LoadPlugin<IOfflineIMData>(dllName, new Object[] { connString, realm });
if (m_Database == null)
throw new Exception("Could not find a storage interface in the given module " + dllName);
}
}
}

View File

@ -9,7 +9,7 @@
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the * * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products * names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission. * derived from this software without specific prior written permission.
* *
@ -25,125 +25,72 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Reflection; using System.Reflection;
using System.Threading; using System.Threading;
using log4net; using log4net;
using OpenMetaverse; using Nini.Config;
using OpenSim.Framework; using OpenSim.Framework;
using OpenSim.Region.CoreModules.Agent.AssetTransaction; using OpenSim.Framework.RegionLoader.Filesystem;
using OpenSim.Region.CoreModules.Avatar.InstantMessage; using OpenSim.Framework.RegionLoader.Web;
using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
using OpenSim.Region.CoreModules.Scripting.LoadImageURL;
using OpenSim.Region.CoreModules.Scripting.XMLRPC;
using OpenSim.Services.Interfaces;
using Mono.Addins;
namespace OpenSim.ApplicationPlugins.LoadRegions namespace OpenSim.ApplicationPlugins.LoadRegions
{ {
[Extension(Path="/OpenSim/Startup", Id="LoadRegions", NodeName="Plugin")] public class LoadRegionsPlugin : IApplicationPlugin
public class LoadRegionsPlugin : IApplicationPlugin, IRegionCreator
{ {
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public event NewRegionCreated OnNewRegionCreated;
private NewRegionCreated m_newRegionCreatedHandler;
#region IApplicationPlugin Members #region IApplicationPlugin Members
// TODO: required by IPlugin, but likely not at all right // TODO: required by IPlugin, but likely not at all right
private string m_name = "LoadRegionsPlugin"; string m_name = "LoadRegionsPlugin";
private string m_version = "0.0"; string m_version = "0.0";
public string Version public string Version { get { return m_version; } }
{ public string Name { get { return m_name; } }
get { return m_version; }
}
public string Name
{
get { return m_name; }
}
protected OpenSimBase m_openSim;
public void Initialise() public void Initialise()
{ {
m_log.Error("[LOAD REGIONS PLUGIN]: " + Name + " cannot be default-initialized!"); m_log.Info("[LOADREGIONS]: " + Name + " cannot be default-initialized!");
throw new PluginNotInitialisedException(Name); throw new PluginNotInitialisedException(Name);
} }
public void Initialise(OpenSimBase openSim) public void Initialise(OpenSimBase openSim)
{ {
m_openSim = openSim; m_log.Info("[LOADREGIONS]: Load Regions addin being initialised");
m_openSim.ApplicationRegistry.RegisterInterface<IRegionCreator>(this);
}
public void PostInitialise()
{
//m_log.Info("[LOADREGIONS]: Load Regions addin being initialised");
IRegionLoader regionLoader; IRegionLoader regionLoader;
if (m_openSim.ConfigSource.Source.Configs["Startup"].GetString("region_info_source", "filesystem") == "filesystem") if (openSim.ConfigSource.Source.Configs["Startup"].GetString("region_info_source", "filesystem") == "filesystem")
{ {
m_log.Info("[LOAD REGIONS PLUGIN]: Loading region configurations from filesystem"); m_log.Info("[LOADREGIONS]: Loading Region Info from filesystem");
regionLoader = new RegionLoaderFileSystem(); regionLoader = new RegionLoaderFileSystem();
} }
else else
{ {
m_log.Info("[LOAD REGIONS PLUGIN]: Loading region configurations from web"); m_log.Info("[LOADREGIONSPLUGIN]: Loading Region Info from web");
regionLoader = new RegionLoaderWebServer(); regionLoader = new RegionLoaderWebServer();
} }
regionLoader.SetIniConfigSource(m_openSim.ConfigSource.Source); regionLoader.SetIniConfigSource(openSim.ConfigSource.Source);
RegionInfo[] regionsToLoad = regionLoader.LoadRegions(); RegionInfo[] regionsToLoad = regionLoader.LoadRegions();
m_log.Info("[LOAD REGIONS PLUGIN]: Loading specific shared modules..."); openSim.ModuleLoader.LoadDefaultSharedModules();
//m_log.Info("[LOAD REGIONS PLUGIN]: DynamicTextureModule...");
//m_openSim.ModuleLoader.LoadDefaultSharedModule(new DynamicTextureModule());
//m_log.Info("[LOAD REGIONS PLUGIN]: LoadImageURLModule...");
//m_openSim.ModuleLoader.LoadDefaultSharedModule(new LoadImageURLModule());
//m_log.Info("[LOAD REGIONS PLUGIN]: XMLRPCModule...");
//m_openSim.ModuleLoader.LoadDefaultSharedModule(new XMLRPCModule());
// m_log.Info("[LOADREGIONSPLUGIN]: AssetTransactionModule...");
// m_openSim.ModuleLoader.LoadDefaultSharedModule(new AssetTransactionModule());
m_log.Info("[LOAD REGIONS PLUGIN]: Done.");
if (!CheckRegionsForSanity(regionsToLoad)) if (!CheckRegionsForSanity(regionsToLoad))
{ {
m_log.Error("[LOAD REGIONS PLUGIN]: Halting startup due to conflicts in region configurations"); m_log.Error("[LOADREGIONS]: Halting startup due to conflicts in region configurations");
Environment.Exit(1); System.Environment.Exit(1);
} }
List<IScene> createdScenes = new List<IScene>();
for (int i = 0; i < regionsToLoad.Length; i++) for (int i = 0; i < regionsToLoad.Length; i++)
{ {
IScene scene; m_log.Debug("[LOADREGIONS]: Creating Region: " + regionsToLoad[i].RegionName + " (ThreadID: " + Thread.CurrentThread.ManagedThreadId.ToString() +
m_log.Debug("[LOAD REGIONS PLUGIN]: Creating Region: " + regionsToLoad[i].RegionName + " (ThreadID: " +
Thread.CurrentThread.ManagedThreadId.ToString() +
")"); ")");
openSim.CreateRegion(regionsToLoad[i], true);
bool changed = m_openSim.PopulateRegionEstateInfo(regionsToLoad[i]);
m_openSim.CreateRegion(regionsToLoad[i], true, out scene);
createdScenes.Add(scene);
if (changed)
m_openSim.EstateDataService.StoreEstateSettings(regionsToLoad[i].EstateSettings);
} }
foreach (IScene scene in createdScenes) openSim.ModuleLoader.PostInitialise();
{ openSim.ModuleLoader.ClearCache();
scene.Start();
m_newRegionCreatedHandler = OnNewRegionCreated;
if (m_newRegionCreatedHandler != null)
{
m_newRegionCreatedHandler(scene);
}
}
} }
public void Dispose() public void Dispose()
@ -159,44 +106,37 @@ namespace OpenSim.ApplicationPlugins.LoadRegions
/// <returns>True if we're sane, false if we're insane</returns> /// <returns>True if we're sane, false if we're insane</returns>
private bool CheckRegionsForSanity(RegionInfo[] regions) private bool CheckRegionsForSanity(RegionInfo[] regions)
{ {
if (regions.Length == 0) if (regions.Length <= 0)
return true; return true;
foreach (RegionInfo region in regions) List<RegionInfo> checkedRegions = new List<RegionInfo>();
{ checkedRegions.Add(regions[0]);
if (region.RegionID == UUID.Zero)
{
m_log.ErrorFormat(
"[LOAD REGIONS PLUGIN]: Region {0} has invalid UUID {1}",
region.RegionName, region.RegionID);
return false;
}
}
for (int i = 0; i < regions.Length - 1; i++) for (int i = 1; i < regions.Length; i++)
{ {
for (int j = i + 1; j < regions.Length; j++) RegionInfo region = regions[i];
foreach (RegionInfo checkedRegion in checkedRegions)
{ {
if (regions[i].RegionID == regions[j].RegionID) if (region.RegionID == checkedRegion.RegionID)
{ {
m_log.ErrorFormat( m_log.ErrorFormat(
"[LOAD REGIONS PLUGIN]: Regions {0} and {1} have the same UUID {2}", "[LOADREGIONS]: Regions {0} and {1} have the same UUID {2}",
regions[i].RegionName, regions[j].RegionName, regions[i].RegionID); region.RegionName, checkedRegion.RegionName, region.RegionID);
return false; return false;
} }
else if ( else if (region.RegionLocX == checkedRegion.RegionLocX && region.RegionLocY == checkedRegion.RegionLocY)
regions[i].RegionLocX == regions[j].RegionLocX && regions[i].RegionLocY == regions[j].RegionLocY)
{ {
m_log.ErrorFormat( m_log.ErrorFormat(
"[LOAD REGIONS PLUGIN]: Regions {0} and {1} have the same grid location ({2}, {3})", "[LOADREGIONS]: Regions {0} and {1} have the same location {2} {3}",
regions[i].RegionName, regions[j].RegionName, regions[i].RegionLocX, regions[i].RegionLocY); region.RegionName, checkedRegion.RegionName, region.RegionLocX, region.RegionLocY);
return false; return false;
} }
else if (regions[i].InternalEndPoint.Port == regions[j].InternalEndPoint.Port) else if (region.InternalEndPoint.Port == checkedRegion.InternalEndPoint.Port)
{ {
m_log.ErrorFormat( m_log.ErrorFormat(
"[LOAD REGIONS PLUGIN]: Regions {0} and {1} have the same internal IP port {2}", "[LOADREGIONS]: Regions {0} and {1} have the same internal IP port {2}",
regions[i].RegionName, regions[j].RegionName, regions[i].InternalEndPoint.Port); region.RegionName, checkedRegion.RegionName, region.InternalEndPoint.Port);
return false; return false;
} }
} }
@ -204,5 +144,34 @@ namespace OpenSim.ApplicationPlugins.LoadRegions
return true; return true;
} }
public void LoadRegionFromConfig(OpenSimBase openSim, ulong regionhandle)
{
m_log.Info("[LOADREGIONS]: Load Regions addin being initialised");
IRegionLoader regionLoader;
if (openSim.ConfigSource.Source.Configs["Startup"].GetString("region_info_source", "filesystem") == "filesystem")
{
m_log.Info("[LOADREGIONS]: Loading Region Info from filesystem");
regionLoader = new RegionLoaderFileSystem();
}
else
{
m_log.Info("[LOADREGIONS]: Loading Region Info from web");
regionLoader = new RegionLoaderWebServer();
}
regionLoader.SetIniConfigSource(openSim.ConfigSource.Source);
RegionInfo[] regionsToLoad = regionLoader.LoadRegions();
for (int i = 0; i < regionsToLoad.Length; i++)
{
if (regionhandle == regionsToLoad[i].RegionHandle)
{
m_log.Debug("[LOADREGIONS]: Creating Region: " + regionsToLoad[i].RegionName + " (ThreadID: " +
Thread.CurrentThread.ManagedThreadId.ToString() + ")");
openSim.CreateRegion(regionsToLoad[i], true);
}
}
}
} }
} }

View File

@ -9,7 +9,7 @@
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the * * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products * names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission. * derived from this software without specific prior written permission.
* *
@ -27,18 +27,17 @@
using System.Reflection; using System.Reflection;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using Mono.Addins;
// General information about an assembly is controlled through the following // General information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information // set of attributes. Change these attribute values to modify the information
// associated with an assembly. // associated with an assembly.
[assembly : AssemblyTitle("OpenSim.ApplicationPlugins.LoadRegions")] [assembly : AssemblyTitle("OpenSim.Addin")]
[assembly : AssemblyDescription("")] [assembly : AssemblyDescription("")]
[assembly : AssemblyConfiguration("")] [assembly : AssemblyConfiguration("")]
[assembly : AssemblyCompany("http://opensimulator.org")] [assembly : AssemblyCompany("")]
[assembly : AssemblyProduct("OpenSim")] [assembly : AssemblyProduct("OpenSim.Addin")]
[assembly : AssemblyCopyright("Copyright © OpenSimulator.org Developers 2007-2009")] [assembly : AssemblyCopyright("Copyright © OpenSimulator.org Developers 2007-2008")]
[assembly : AssemblyTrademark("")] [assembly : AssemblyTrademark("")]
[assembly : AssemblyCulture("")] [assembly : AssemblyCulture("")]
@ -61,8 +60,7 @@ using Mono.Addins;
// //
// You can specify all the values or you can default the Build and Revision Numbers // You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below: // by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly : AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)] [assembly : AssemblyVersion("1.0.0.0")]
[assembly : AssemblyFileVersion("1.0.0.0")]
[assembly: Addin("OpenSim.ApplicationPlugins.LoadRegions", OpenSim.VersionInfo.VersionNumber)]
[assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)]

View File

@ -1,117 +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 log4net;
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using Nini.Config;
using OpenSim.Framework;
namespace OpenSim.ApplicationPlugins.LoadRegions
{
public class RegionLoaderFileSystem : IRegionLoader
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IConfigSource m_configSource;
public void SetIniConfigSource(IConfigSource configSource)
{
m_configSource = configSource;
}
public RegionInfo[] LoadRegions()
{
string regionConfigPath = Path.Combine(Util.configDir(), "Regions");
bool allowRegionless = false;
try
{
IConfig startupConfig = (IConfig)m_configSource.Configs["Startup"];
regionConfigPath = startupConfig.GetString("regionload_regionsdir", regionConfigPath).Trim();
allowRegionless = startupConfig.GetBoolean("allow_regionless", false);
}
catch (Exception)
{
// No INI setting recorded.
}
if (!Directory.Exists(regionConfigPath))
{
Directory.CreateDirectory(regionConfigPath);
}
string[] configFiles = Directory.GetFiles(regionConfigPath, "*.xml");
string[] iniFiles = Directory.GetFiles(regionConfigPath, "*.ini");
// Create an empty Regions.ini if there are no existing config files.
if (!allowRegionless && configFiles.Length == 0 && iniFiles.Length == 0)
{
new RegionInfo("DEFAULT REGION CONFIG", Path.Combine(regionConfigPath, "Regions.ini"), false, m_configSource);
iniFiles = Directory.GetFiles(regionConfigPath, "*.ini");
}
m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config files from {0}", regionConfigPath);
List<RegionInfo> regionInfos = new List<RegionInfo>();
int i = 0;
foreach (string file in iniFiles)
{
m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config file {0}", file);
IConfigSource source = new IniConfigSource(file);
foreach (IConfig config in source.Configs)
{
RegionInfo regionInfo = new RegionInfo("REGION CONFIG #" + (i + 1), file, false, m_configSource, config.Name);
regionInfos.Add(regionInfo);
m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loaded config for region {0}", regionInfo.RegionName);
i++;
}
}
foreach (string file in configFiles)
{
m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loading config file {0}", file);
RegionInfo regionInfo = new RegionInfo("REGION CONFIG #" + (i + 1), file, false, m_configSource);
regionInfos.Add(regionInfo);
m_log.InfoFormat("[REGION LOADER FILE SYSTEM]: Loaded config for region {0}", regionInfo.RegionName);
i++;
}
return regionInfos.ToArray();
}
}
}

View File

@ -1,143 +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.Net;
using System.Reflection;
using System.Xml;
using log4net;
using Nini.Config;
using OpenSim.Framework;
namespace OpenSim.ApplicationPlugins.LoadRegions
{
public class RegionLoaderWebServer : IRegionLoader
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IConfigSource m_configSource;
public void SetIniConfigSource(IConfigSource configSource)
{
m_configSource = configSource;
}
public RegionInfo[] LoadRegions()
{
int tries = 3;
int wait = 2000;
if (m_configSource == null)
{
m_log.Error("[WEBLOADER]: Unable to load configuration source!");
return null;
}
else
{
IConfig startupConfig = (IConfig)m_configSource.Configs["Startup"];
string url = startupConfig.GetString("regionload_webserver_url", String.Empty).Trim();
bool allowRegionless = startupConfig.GetBoolean("allow_regionless", false);
if (url == String.Empty)
{
m_log.Error("[WEBLOADER]: Unable to load webserver URL - URL was empty.");
return null;
}
else
{
while (tries > 0)
{
RegionInfo[] regionInfos = new RegionInfo[] { };
int regionCount = 0;
HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url);
webRequest.Timeout = 30000; //30 Second Timeout
m_log.DebugFormat("[WEBLOADER]: Sending download request to {0}", url);
try
{
HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
m_log.Debug("[WEBLOADER]: Downloading region information...");
StreamReader reader = new StreamReader(webResponse.GetResponseStream());
string xmlSource = String.Empty;
string tempStr = reader.ReadLine();
while (tempStr != null)
{
xmlSource = xmlSource + tempStr;
tempStr = reader.ReadLine();
}
m_log.Debug("[WEBLOADER]: Done downloading region information from server. Total Bytes: " +
xmlSource.Length);
XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlSource);
if (xmlDoc.FirstChild.Name == "Nini")
{
regionCount = xmlDoc.FirstChild.ChildNodes.Count;
if (regionCount > 0)
{
regionInfos = new RegionInfo[regionCount];
int i;
for (i = 0; i < xmlDoc.FirstChild.ChildNodes.Count; i++)
{
m_log.Debug(xmlDoc.FirstChild.ChildNodes[i].OuterXml);
regionInfos[i] =
new RegionInfo("REGION CONFIG #" + (i + 1), xmlDoc.FirstChild.ChildNodes[i], false, m_configSource);
}
}
}
}
catch (WebException ex)
{
if (((HttpWebResponse)ex.Response).StatusCode == HttpStatusCode.NotFound)
{
if (!allowRegionless)
throw ex;
}
else
throw ex;
}
if (regionCount > 0 || allowRegionless)
return regionInfos;
m_log.Debug("[WEBLOADER]: Request yielded no regions.");
tries--;
if (tries > 0)
{
m_log.Debug("[WEBLOADER]: Retrying");
System.Threading.Thread.Sleep(wait);
}
}
m_log.Error("[WEBLOADER]: No region configs were available.");
return null;
}
}
}
}
}

View File

@ -0,0 +1,11 @@
<Addin id="OpenSim.ApplicationPlugins.LoadRegions" version="0.1">
<Runtime>
<Import assembly="OpenSim.ApplicationPlugins.LoadRegions.dll"/>
</Runtime>
<Dependencies>
<Addin id="OpenSim" version="0.5" />
</Dependencies>
<Extension path = "/OpenSim/Startup">
<Plugin id="LoadRegions" type="OpenSim.ApplicationPlugins.LoadRegions.LoadRegionsPlugin" />
</Extension>
</Addin>

View File

@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Mono.Addins;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("OpenSim.ApplicationPlugins.RegionModulesController")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("http://opensimulator.org")]
[assembly: AssemblyProduct("OpenSim")]
[assembly: AssemblyCopyright("OpenSimulator developers")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("c023816d-194e-40c1-9195-a0f281d4ac5d")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)]
[assembly: Addin("OpenSim.ApplicationPlugins.RegionModulesController", OpenSim.VersionInfo.VersionNumber)]
[assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)]

View File

@ -1,535 +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 log4net;
using Mono.Addins;
using Nini.Config;
using OpenSim;
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
namespace OpenSim.ApplicationPlugins.RegionModulesController
{
[Extension(Path = "/OpenSim/Startup", Id = "LoadRegions", NodeName = "Plugin")]
public class RegionModulesControllerPlugin : IRegionModulesController,
IApplicationPlugin
{
// Logger
private static readonly ILog m_log =
LogManager.GetLogger(
MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// Controls whether we load modules from Mono.Addins.
/// </summary>
/// <remarks>For debug purposes. Defaults to true.</remarks>
public bool LoadModulesFromAddins { get; set; }
// Config access
private OpenSimBase m_openSim;
// Our name
private string m_name;
// Internal lists to collect information about modules present
private List<TypeExtensionNode> m_nonSharedModules =
new List<TypeExtensionNode>();
private List<TypeExtensionNode> m_sharedModules =
new List<TypeExtensionNode>();
// List of shared module instances, for adding to Scenes
private List<ISharedRegionModule> m_sharedInstances =
new List<ISharedRegionModule>();
public RegionModulesControllerPlugin()
{
LoadModulesFromAddins = true;
}
#region IApplicationPlugin implementation
public void Initialise (OpenSimBase openSim)
{
m_openSim = openSim;
m_openSim.ApplicationRegistry.RegisterInterface<IRegionModulesController>(this);
m_log.DebugFormat("[REGIONMODULES]: Initializing...");
if (!LoadModulesFromAddins)
return;
// Who we are
string id = AddinManager.CurrentAddin.Id;
// Make friendly name
int pos = id.LastIndexOf(".");
if (pos == -1)
m_name = id;
else
m_name = id.Substring(pos + 1);
// The [Modules] section in the ini file
IConfig modulesConfig =
m_openSim.ConfigSource.Source.Configs["Modules"];
if (modulesConfig == null)
modulesConfig = m_openSim.ConfigSource.Source.AddConfig("Modules");
Dictionary<RuntimeAddin, IList<int>> loadedModules = new Dictionary<RuntimeAddin, IList<int>>();
// Scan modules and load all that aren't disabled
foreach (TypeExtensionNode node in AddinManager.GetExtensionNodes("/OpenSim/RegionModules"))
AddNode(node, modulesConfig, loadedModules);
foreach (KeyValuePair<RuntimeAddin, IList<int>> loadedModuleData in loadedModules)
{
m_log.InfoFormat(
"[REGIONMODULES]: From plugin {0}, (version {1}), loaded {2} modules, {3} shared, {4} non-shared {5} unknown",
loadedModuleData.Key.Id,
loadedModuleData.Key.Version,
loadedModuleData.Value[0] + loadedModuleData.Value[1] + loadedModuleData.Value[2],
loadedModuleData.Value[0], loadedModuleData.Value[1], loadedModuleData.Value[2]);
}
// Load and init the module. We try a constructor with a port
// if a port was given, fall back to one without if there is
// no port or the more specific constructor fails.
// This will be removed, so that any module capable of using a port
// must provide a constructor with a port in the future.
// For now, we do this so migration is easy.
//
foreach (TypeExtensionNode node in m_sharedModules)
{
Object[] ctorArgs = new Object[] { (uint)0 };
// Read the config again
string moduleString =
modulesConfig.GetString("Setup_" + node.Id, String.Empty);
// Test to see if we want this module
if (moduleString == "disabled")
continue;
// Get the port number, if there is one
if (moduleString != String.Empty)
{
// Get the port number from the string
string[] moduleParts = moduleString.Split(new char[] { '/' },
2);
if (moduleParts.Length > 1)
ctorArgs[0] = Convert.ToUInt32(moduleParts[0]);
}
// Try loading and initilaizing the module, using the
// port if appropriate
ISharedRegionModule module = null;
try
{
module = (ISharedRegionModule)Activator.CreateInstance(
node.Type, ctorArgs);
}
catch
{
module = (ISharedRegionModule)Activator.CreateInstance(
node.Type);
}
// OK, we're up and running
m_sharedInstances.Add(module);
module.Initialise(m_openSim.ConfigSource.Source);
}
}
public void PostInitialise ()
{
m_log.DebugFormat("[REGIONMODULES]: PostInitializing...");
// Immediately run PostInitialise on shared modules
foreach (ISharedRegionModule module in m_sharedInstances)
{
module.PostInitialise();
}
}
#endregion
#region IPlugin implementation
private void AddNode(
TypeExtensionNode node, IConfig modulesConfig, Dictionary<RuntimeAddin, IList<int>> loadedModules)
{
IList<int> loadedModuleData;
if (!loadedModules.ContainsKey(node.Addin))
loadedModules.Add(node.Addin, new List<int> { 0, 0, 0 });
loadedModuleData = loadedModules[node.Addin];
if (node.Type.GetInterface(typeof(ISharedRegionModule).ToString()) != null)
{
if (CheckModuleEnabled(node, modulesConfig))
{
m_log.DebugFormat("[REGIONMODULES]: Found shared region module {0}, class {1}", node.Id, node.Type);
m_sharedModules.Add(node);
loadedModuleData[0]++;
}
}
else if (node.Type.GetInterface(typeof(INonSharedRegionModule).ToString()) != null)
{
if (CheckModuleEnabled(node, modulesConfig))
{
m_log.DebugFormat("[REGIONMODULES]: Found non-shared region module {0}, class {1}", node.Id, node.Type);
m_nonSharedModules.Add(node);
loadedModuleData[1]++;
}
}
else
{
m_log.WarnFormat("[REGIONMODULES]: Found unknown type of module {0}, class {1}", node.Id, node.Type);
loadedModuleData[2]++;
}
}
// We don't do that here
//
public void Initialise ()
{
throw new System.NotImplementedException();
}
#endregion
#region IDisposable implementation
// Cleanup
//
public void Dispose ()
{
// We expect that all regions have been removed already
while (m_sharedInstances.Count > 0)
{
m_sharedInstances[0].Close();
m_sharedInstances.RemoveAt(0);
}
m_sharedModules.Clear();
m_nonSharedModules.Clear();
}
#endregion
public string Version
{
get
{
return AddinManager.CurrentAddin.Version;
}
}
public string Name
{
get
{
return m_name;
}
}
#region Region Module interfacesController implementation
/// <summary>
/// Check that the given module is no disabled in the [Modules] section of the config files.
/// </summary>
/// <param name="node"></param>
/// <param name="modulesConfig">The config section</param>
/// <returns>true if the module is enabled, false if it is disabled</returns>
protected bool CheckModuleEnabled(TypeExtensionNode node, IConfig modulesConfig)
{
// Get the config string
string moduleString =
modulesConfig.GetString("Setup_" + node.Id, String.Empty);
// We have a selector
if (moduleString != String.Empty)
{
// Allow disabling modules even if they don't have
// support for it
if (moduleString == "disabled")
return false;
// Split off port, if present
string[] moduleParts = moduleString.Split(new char[] { '/' }, 2);
// Format is [port/][class]
string className = moduleParts[0];
if (moduleParts.Length > 1)
className = moduleParts[1];
// Match the class name if given
if (className != String.Empty &&
node.Type.ToString() != className)
return false;
}
return true;
}
// The root of all evil.
// This is where we handle adding the modules to scenes when they
// load. This means that here we deal with replaceable interfaces,
// nonshared modules, etc.
//
public void AddRegionToModules (Scene scene)
{
Dictionary<Type, ISharedRegionModule> deferredSharedModules =
new Dictionary<Type, ISharedRegionModule>();
Dictionary<Type, INonSharedRegionModule> deferredNonSharedModules =
new Dictionary<Type, INonSharedRegionModule>();
// We need this to see if a module has already been loaded and
// has defined a replaceable interface. It's a generic call,
// so this can't be used directly. It will be used later
Type s = scene.GetType();
MethodInfo mi = s.GetMethod("RequestModuleInterface");
// This will hold the shared modules we actually load
List<ISharedRegionModule> sharedlist =
new List<ISharedRegionModule>();
// Iterate over the shared modules that have been loaded
// Add them to the new Scene
foreach (ISharedRegionModule module in m_sharedInstances)
{
// Here is where we check if a replaceable interface
// is defined. If it is, the module is checked against
// the interfaces already defined. If the interface is
// defined, we simply skip the module. Else, if the module
// defines a replaceable interface, we add it to the deferred
// list.
Type replaceableInterface = module.ReplaceableInterface;
if (replaceableInterface != null)
{
MethodInfo mii = mi.MakeGenericMethod(replaceableInterface);
if (mii.Invoke(scene, new object[0]) != null)
{
m_log.DebugFormat("[REGIONMODULE]: Not loading {0} because another module has registered {1}", module.Name, replaceableInterface.ToString());
continue;
}
deferredSharedModules[replaceableInterface] = module;
m_log.DebugFormat("[REGIONMODULE]: Deferred load of {0}", module.Name);
continue;
}
m_log.DebugFormat("[REGIONMODULE]: Adding scene {0} to shared module {1}",
scene.RegionInfo.RegionName, module.Name);
module.AddRegion(scene);
scene.AddRegionModule(module.Name, module);
sharedlist.Add(module);
}
IConfig modulesConfig =
m_openSim.ConfigSource.Source.Configs["Modules"];
// Scan for, and load, nonshared modules
List<INonSharedRegionModule> list = new List<INonSharedRegionModule>();
foreach (TypeExtensionNode node in m_nonSharedModules)
{
Object[] ctorArgs = new Object[] {0};
// Read the config
string moduleString =
modulesConfig.GetString("Setup_" + node.Id, String.Empty);
// We may not want to load this at all
if (moduleString == "disabled")
continue;
// Get the port number, if there is one
if (moduleString != String.Empty)
{
// Get the port number from the string
string[] moduleParts = moduleString.Split(new char[] {'/'},
2);
if (moduleParts.Length > 1)
ctorArgs[0] = Convert.ToUInt32(moduleParts[0]);
}
// Actually load it
INonSharedRegionModule module = null;
Type[] ctorParamTypes = new Type[ctorArgs.Length];
for (int i = 0; i < ctorParamTypes.Length; i++)
ctorParamTypes[i] = ctorArgs[i].GetType();
if (node.Type.GetConstructor(ctorParamTypes) != null)
module = (INonSharedRegionModule)Activator.CreateInstance(node.Type, ctorArgs);
else
module = (INonSharedRegionModule)Activator.CreateInstance(node.Type);
// Check for replaceable interfaces
Type replaceableInterface = module.ReplaceableInterface;
if (replaceableInterface != null)
{
MethodInfo mii = mi.MakeGenericMethod(replaceableInterface);
if (mii.Invoke(scene, new object[0]) != null)
{
m_log.DebugFormat("[REGIONMODULE]: Not loading {0} because another module has registered {1}", module.Name, replaceableInterface.ToString());
continue;
}
deferredNonSharedModules[replaceableInterface] = module;
m_log.DebugFormat("[REGIONMODULE]: Deferred load of {0}", module.Name);
continue;
}
m_log.DebugFormat("[REGIONMODULE]: Adding scene {0} to non-shared module {1}",
scene.RegionInfo.RegionName, module.Name);
// Initialise the module
module.Initialise(m_openSim.ConfigSource.Source);
list.Add(module);
}
// Now add the modules that we found to the scene. If a module
// wishes to override a replaceable interface, it needs to
// register it in Initialise, so that the deferred module
// won't load.
foreach (INonSharedRegionModule module in list)
{
module.AddRegion(scene);
scene.AddRegionModule(module.Name, module);
}
// Now all modules without a replaceable base interface are loaded
// Replaceable modules have either been skipped, or omitted.
// Now scan the deferred modules here
foreach (ISharedRegionModule module in deferredSharedModules.Values)
{
// Determine if the interface has been replaced
Type replaceableInterface = module.ReplaceableInterface;
MethodInfo mii = mi.MakeGenericMethod(replaceableInterface);
if (mii.Invoke(scene, new object[0]) != null)
{
m_log.DebugFormat("[REGIONMODULE]: Not loading {0} because another module has registered {1}", module.Name, replaceableInterface.ToString());
continue;
}
m_log.DebugFormat("[REGIONMODULE]: Adding scene {0} to shared module {1} (deferred)",
scene.RegionInfo.RegionName, module.Name);
// Not replaced, load the module
module.AddRegion(scene);
scene.AddRegionModule(module.Name, module);
sharedlist.Add(module);
}
// Same thing for nonshared modules, load them unless overridden
List<INonSharedRegionModule> deferredlist =
new List<INonSharedRegionModule>();
foreach (INonSharedRegionModule module in deferredNonSharedModules.Values)
{
// Check interface override
Type replaceableInterface = module.ReplaceableInterface;
if (replaceableInterface != null)
{
MethodInfo mii = mi.MakeGenericMethod(replaceableInterface);
if (mii.Invoke(scene, new object[0]) != null)
{
m_log.DebugFormat("[REGIONMODULE]: Not loading {0} because another module has registered {1}", module.Name, replaceableInterface.ToString());
continue;
}
}
m_log.DebugFormat("[REGIONMODULE]: Adding scene {0} to non-shared module {1} (deferred)",
scene.RegionInfo.RegionName, module.Name);
module.Initialise(m_openSim.ConfigSource.Source);
list.Add(module);
deferredlist.Add(module);
}
// Finally, load valid deferred modules
foreach (INonSharedRegionModule module in deferredlist)
{
module.AddRegion(scene);
scene.AddRegionModule(module.Name, module);
}
// This is needed for all module types. Modules will register
// Interfaces with scene in AddScene, and will also need a means
// to access interfaces registered by other modules. Without
// this extra method, a module attempting to use another modules's
// interface would be successful only depending on load order,
// which can't be depended upon, or modules would need to resort
// to ugly kludges to attempt to request interfaces when needed
// and unneccessary caching logic repeated in all modules.
// The extra function stub is just that much cleaner
//
foreach (ISharedRegionModule module in sharedlist)
{
module.RegionLoaded(scene);
}
foreach (INonSharedRegionModule module in list)
{
module.RegionLoaded(scene);
}
scene.AllModulesLoaded();
}
public void RemoveRegionFromModules (Scene scene)
{
foreach (IRegionModuleBase module in scene.RegionModules.Values)
{
m_log.DebugFormat("[REGIONMODULE]: Removing scene {0} from module {1}",
scene.RegionInfo.RegionName, module.Name);
module.RemoveRegion(scene);
if (module is INonSharedRegionModule)
{
// as we were the only user, this instance has to die
module.Close();
}
}
scene.RegionModules.Clear();
}
#endregion
}
}

View File

@ -1,36 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using Mono.Addins;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("OpenSim.ApplicationPlugins.RemoteController")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("http://opensimulator.org")]
[assembly: AssemblyProduct("OpenSim")]
[assembly: AssemblyCopyright("Copyright OpenSimulator developers © 2012")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("efec6e69-fc4a-4e21-86e6-4a261c12d4db")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)]
[assembly: Addin("OpenSim.ApplicationPlugins.RemoteController", OpenSim.VersionInfo.VersionNumber)]
[assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)]

View File

@ -0,0 +1,11 @@
<Addin id="OpenSim.ApplicationPlugins.RemoteController" version="0.1">
<Runtime>
<Import assembly="OpenSim.ApplicationPlugins.RemoteController.dll"/>
</Runtime>
<Dependencies>
<Addin id="OpenSim" version="0.5" />
</Dependencies>
<Extension path = "/OpenSim/Startup">
<Plugin id="RemoteController" type="OpenSim.ApplicationPlugins.RemoteController.RemoteAdminPlugin" />
</Extension>
</Addin>

View File

@ -0,0 +1,45 @@
/*
* 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 OpenSim 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;
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();
}
}

View File

@ -0,0 +1,60 @@
/*
* 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 OpenSim 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 OpenSim.Framework.Servers;
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

View File

@ -0,0 +1,11 @@
<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>

View File

@ -0,0 +1,528 @@
/*
* 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 OpenSim 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 OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Communications;
using OpenSim.Framework.Communications.Cache;
using Nini.Config;
namespace OpenSim.ApplicationPlugins.Rest.Inventory
{
public class Rest
{
internal static readonly log4net.ILog Log =
log4net.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 CommunicationsManager Comms = null;
internal static IInventoryServices InventoryServices = null;
internal static IUserService UserServices = null;
internal static IAvatarService AvatarServices = null;
internal static AssetCache AssetServices = 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 = false;
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>
/// 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 = Encoding.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 = Encoding.UTF8.GetBytes(str);
return Convert.ToBase64String(encData_byte);
}
catch
{
return String.Empty;
}
}
public static string Base64ToString(string str)
{
UTF8Encoding encoder = new UTF8Encoding();
Decoder utf8Decode = encoder.GetDecoder();
try
{
byte[] todecode_byte = Convert.FromBase64String(str);
int charCount = utf8Decode.GetCharCount(todecode_byte, 0, todecode_byte.Length);
char[] decoded_char = new char[charCount];
utf8Decode.GetChars(todecode_byte, 0, todecode_byte.Length, decoded_char, 0);
return new String(decoded_char);
}
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[Rest.DumpLineSize];
int cc = 0;
for (int i = 0; i < data.Length; i++)
{
if (i % Rest.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 % Rest.DumpLineSize] = (char) data[i];
else
buffer[i % Rest.DumpLineSize] = '.';
cc++;
if (i != 0 && (i + 1) % Rest.DumpLineSize == 0)
{
Console.Write(" |"+(new String(buffer))+"|");
cc = 0;
}
}
// Finish off any incomplete line
if (cc != 0)
{
for (int i = cc ; i < Rest.DumpLineSize; i++)
{
if (i % 4 == 0) Console.Write(" ");
Console.Write(" ");
buffer[i % Rest.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)
{
}
}
}

View File

@ -0,0 +1,874 @@
/*
* 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 OpenSim 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.IO;
using System.Threading;
using System.Xml;
using System.Drawing;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Communications;
using OpenSim.Framework.Communications.Cache;
using OpenMetaverse;
using OpenMetaverse.Imaging;
using Nini.Config;
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);
// This is better than a null reference.
if (Rest.AvatarServices == null)
throw new Exception(String.Format("{0} OpenSim inventory services are not available",
MsgId));
if (Rest.UserServices == null)
throw new Exception(String.Format("{0} OpenSim user profile services are not available",
MsgId));
// 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);
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)
{
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)
{
rdata.userAppearance = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID);
if (rdata.userAppearance == null)
{
rdata.Fail(Rest.HttpStatusCodeNoContent,
String.Format("appearance data not found for user {0} {1}",
rdata.userProfile.FirstName, rdata.userProfile.SurName));
}
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.
if (GetUserAppearance(rdata))
{
modified = rdata.userAppearance != null;
created = !modified;
Rest.AvatarServices.UpdateUserAppearance(rdata.userProfile.ID, rdata.userAppearance);
// Rest.UserServices.UpdateUserProfile(rdata.userProfile);
}
else
{
created = true;
Rest.AvatarServices.UpdateUserAppearance(rdata.userProfile.ID, rdata.userAppearance);
// 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)
{
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)
{
AvatarAppearance old = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID);
if (old != null)
{
rdata.userAppearance = new AvatarAppearance();
rdata.userAppearance.Owner = old.Owner;
Rest.AvatarServices.UpdateUserAppearance(rdata.userProfile.ID, rdata.userAppearance);
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);
Hashtable attachments = rdata.userAppearance.GetAttachments();
if (attachments != null)
{
Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting attachments", MsgId);
rdata.writer.WriteStartElement("Attachments");
for (int i = 0; i < attachments.Count; i++)
{
Hashtable attachment = attachments[i] as Hashtable;
rdata.writer.WriteStartElement("Attachment");
rdata.writer.WriteAttributeString("AtPoint", i.ToString());
rdata.writer.WriteAttributeString("Item", (string) attachment["item"]);
rdata.writer.WriteAttributeString("Asset", (string) attachment["asset"]);
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
}
}

View File

@ -0,0 +1,402 @@
/*
* 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 OpenSim 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 OpenMetaverse;
using Nini.Config;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Xml;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Communications;
using OpenSim.Framework.Communications.Cache;
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);
// This is better than a null reference.
if (Rest.AssetServices == null)
throw new Exception(String.Format("{0} OpenSim asset services are not available",
MsgId));
// 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)
{
bool istexture = false;
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.GetAsset(uuid, istexture);
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.ToString());
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.GetAsset(uuid, false);
modified = (asset != null);
created = !modified;
asset = new AssetBase();
asset.FullID = uuid;
asset.Name = xml.GetAttribute("name");
asset.Description = xml.GetAttribute("desc");
asset.Type = SByte.Parse(xml.GetAttribute("type"));
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.AddAsset(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.GetAsset(uuid, false);
modified = (asset != null);
created = !modified;
asset = new AssetBase();
asset.FullID = uuid;
asset.Name = xml.GetAttribute("name");
asset.Description = xml.GetAttribute("desc");
asset.Type = SByte.Parse(xml.GetAttribute("type"));
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.AddAsset(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)
{
}
}
}
}

View File

@ -0,0 +1,666 @@
/*
* 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 OpenSim 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;
using OpenSim.Framework.Servers;
using OpenSim.ApplicationPlugins.Rest;
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;
Rest.Plugin = this;
Rest.Comms = Rest.main.CommunicationsManager;
Rest.UserServices = Rest.Comms.UserService;
Rest.InventoryServices = Rest.Comms.InventoryService;
Rest.AssetServices = Rest.Comms.AssetCache;
Rest.AvatarServices = Rest.Comms.AvatarService;
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.Authenticate ? "" : "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
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);
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

View File

@ -0,0 +1,252 @@
/*
* 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 OpenSim 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 OpenMetaverse;
using Nini.Config;
using System;
using System.IO;
using System.Collections.Generic;
using System.Reflection;
using System.Threading;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Communications;
using OpenSim.Framework.Communications.Cache;
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;
}
}
}
}
}

View File

@ -0,0 +1,48 @@
/*
* 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 OpenSim 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;
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();
}
}

View File

@ -0,0 +1,217 @@
/*
* 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 OpenSim 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 OpenMetaverse;
using Nini.Config;
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Xml;
using OpenSim.Framework;
using OpenSim.Region.Environment.Scenes;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Communications;
using OpenSim.Framework.Communications.Cache;
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)
{
string[] names = rdata.Parameters[PARM_MOVE_AVATAR].Split(Rest.CA_SPACE);
ScenePresence avatar = 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.
foreach (Scene cs in Rest.main.SceneManager.Scenes)
{
foreach (ScenePresence presence in cs.GetAvatars())
{
if (presence.Firstname == names[0] &&
presence.Lastname == names[1])
{
scene = cs;
avatar = presence;
break;
}
}
}
if (avatar != 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);
avatar.DoAutoPilot(0,vector,avatar.ControllingClient);
}
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");
}
else
{
Rest.Log.WarnFormat("{0} Move: No movement information provided", MsgId);
rdata.Fail(Rest.HttpStatusCodeBadRequest, "no movement information provided");
}
}
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>"
;
}
}

View File

@ -0,0 +1,231 @@
/*
* 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 OpenSim 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.Threading;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Timers;
using System.Xml;
using System.Xml.Serialization;
using OpenMetaverse;
using Mono.Addins;
using Nwc.XmlRpc;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Communications;
using OpenSim.Region.Environment.Interfaces;
using OpenSim.Region.Environment.Scenes;
using OpenSim.ApplicationPlugins.Rest;
namespace OpenSim.ApplicationPlugins.Rest.Regions
{
public partial class RestRegionPlugin : RestPlugin
{
#region GET methods
public string GetHandler(string request, string path, string param,
OSHttpRequest httpRequest, OSHttpResponse 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(OSHttpResponse httpResponse)
{
XmlWriter.WriteStartElement(String.Empty, "regions", String.Empty);
foreach (Scene s in App.SceneManager.Scenes)
{
XmlWriter.WriteStartElement(String.Empty, "uuid", String.Empty);
XmlWriter.WriteString(s.RegionInfo.RegionID.ToString());
XmlWriter.WriteEndElement();
}
XmlWriter.WriteEndElement();
return XmlWriterResult;
}
protected string ShortRegionInfo(string key, string value)
{
if (String.IsNullOrEmpty(value) ||
String.IsNullOrEmpty(key)) return null;
XmlWriter.WriteStartElement(String.Empty, "region", String.Empty);
XmlWriter.WriteStartElement(String.Empty, key, String.Empty);
XmlWriter.WriteString(value);
XmlWriter.WriteEndDocument();
return XmlWriterResult;
}
public string GetHandlerRegion(OSHttpResponse 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
XmlSerializer xs = new XmlSerializer(typeof(RegionDetails));
xs.Serialize(XmlWriter, details, _xmlNs);
return XmlWriterResult;
}
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]), (float)Double.Parse(subregion[1]), (float)Double.Parse(subregion[2]));
max = new Vector3((float)Double.Parse(subregion[3]), (float)Double.Parse(subregion[4]), (float)Double.Parse(subregion[5]));
}
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(OSHttpResponse httpResponse, Scene scene)
{
return Failure(httpResponse, OSHttpStatusCode.ServerErrorNotImplemented,
"GET", "terrain not implemented");
}
protected string RegionStats(OSHttpResponse httpResponse, Scene scene)
{
int users = scene.GetAvatars().Count;
int objects = scene.Entities.Count - users;
XmlWriter.WriteStartElement(String.Empty, "region", String.Empty);
XmlWriter.WriteStartElement(String.Empty, "stats", String.Empty);
XmlWriter.WriteStartElement(String.Empty, "users", String.Empty);
XmlWriter.WriteString(users.ToString());
XmlWriter.WriteEndElement();
XmlWriter.WriteStartElement(String.Empty, "objects", String.Empty);
XmlWriter.WriteString(objects.ToString());
XmlWriter.WriteEndElement();
XmlWriter.WriteEndDocument();
return XmlWriterResult;
}
protected string RegionPrims(OSHttpResponse 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 "";
}
}
}

View File

@ -0,0 +1,133 @@
/*
* 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 OpenSim 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.Threading;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Timers;
using System.Xml;
using System.Xml.Serialization;
using OpenMetaverse;
using Mono.Addins;
using Nwc.XmlRpc;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Communications;
using OpenSim.Region.Environment.Interfaces;
using OpenSim.Region.Environment.Scenes;
using OpenSim.ApplicationPlugins.Rest;
namespace OpenSim.ApplicationPlugins.Rest.Regions
{
public partial class RestRegionPlugin : RestPlugin
{
#region POST methods
public string PostHandler(string request, string path, string param,
OSHttpRequest httpRequest, OSHttpResponse 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(OSHttpRequest request, OSHttpResponse response)
{
XmlWriter.WriteStartElement(String.Empty, "regions", String.Empty);
foreach (Scene s in App.SceneManager.Scenes)
{
XmlWriter.WriteStartElement(String.Empty, "uuid", String.Empty);
XmlWriter.WriteString(s.RegionInfo.RegionID.ToString());
XmlWriter.WriteEndElement();
}
XmlWriter.WriteEndElement();
return XmlWriterResult;
}
public string LoadPrims(string requestBody, OSHttpRequest request, OSHttpResponse response, Scene scene)
{
IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>();
if (serialiser != null)
serialiser.LoadPrimsFromXml2(scene, new StringReader(requestBody), true);
return "";
}
#endregion POST methods
}
}

View File

@ -0,0 +1,108 @@
/*
* 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 OpenSim 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 OpenMetaverse;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Xml.Serialization;
using OpenSim.Framework;
using OpenSim.Region.Environment.Scenes;
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;
if (regInfo.EstateSettings.EstateOwner != UUID.Zero)
region_owner_id = regInfo.EstateSettings.EstateOwner.ToString();
else
region_owner_id = regInfo.MasterAvatarAssignedUUID.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;
if (!String.IsNullOrEmpty(regInfo.MasterAvatarFirstName))
region_owner = String.Format("{0} {1}", regInfo.MasterAvatarFirstName,
regInfo.MasterAvatarLastName);
}
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;
}
}
}
}
}

View File

@ -0,0 +1,11 @@
<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>

View File

@ -0,0 +1,110 @@
/*
* 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 OpenSim 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.Threading;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Timers;
using System.Xml;
using System.Xml.Serialization;
using OpenMetaverse;
using Nwc.XmlRpc;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Communications;
using OpenSim.Region.Environment.Scenes;
using OpenSim.ApplicationPlugins.Rest;
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);
}
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
}
}

View File

@ -0,0 +1,410 @@
/*
* 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 OpenSim 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.Threading;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Reflection;
using System.Timers;
using System.Xml;
using OpenMetaverse;
using Nwc.XmlRpc;
using Nini.Config;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Communications;
using OpenSim.Region.Environment.Scenes;
namespace OpenSim.ApplicationPlugins.Rest
{
public abstract class RestPlugin : IApplicationPlugin
{
#region properties
protected static readonly log4net.ILog m_log =
log4net.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;
[ThreadStaticAttribute]
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
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 OpenSim implementation it is
// not possible for the openSim 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());
}
}
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);
}
/// <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(OSHttpRequest 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(OSHttpRequest 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(OSHttpResponse 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(OSHttpResponse 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
}
}

View File

@ -0,0 +1,56 @@
/*
* 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 OpenSim 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.IO;
using System.Text;
using System.Xml;
namespace OpenSim.ApplicationPlugins.Rest
{
public class RestXmlWriter: XmlTextWriter
{
public RestXmlWriter(TextWriter textWriter) : base(textWriter)
{
}
public RestXmlWriter(Stream stream) : this(stream, Encoding.UTF8)
{
}
public RestXmlWriter(Stream stream, Encoding enc) : base(stream, enc)
{
}
public override void WriteStartDocument()
{
}
public override void WriteStartDocument(bool standalone)
{
}
}
}

View File

@ -0,0 +1,276 @@
<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>

View File

@ -0,0 +1,145 @@
/*
* 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 OpenSim 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 log4net;
using OpenSim.ScriptEngine.Shared;
namespace OpenSim.ApplicationPlugins.ScriptEngine
{
public static class ComponentFactory
{
// Component providers are registered here wit a name (string)
// When a script engine is created the components are instanciated
public static Dictionary<string, Type> providers = new Dictionary<string, Type>();
public static Dictionary<string, Type> scriptEngines = new Dictionary<string, Type>();
internal static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private readonly static string nameIScriptEngineComponent = typeof(IScriptEngineComponent).Name; // keep interface name in managed code
private readonly static string nameIScriptEngine = typeof(IScriptEngine).Name; // keep interface name in managed code
public static string Name
{
get { return "SECS.ComponentFactory"; }
}
/// <summary>
/// Load components from directory
/// </summary>
/// <param name="directory"></param>
internal static void Load(string directory, string filter)
{
// We may want to change how this functions as currently it required unique class names for each component
foreach (string file in Directory.GetFiles(directory, filter))
{
//m_log.DebugFormat("[ScriptEngine]: Loading: [{0}].", file);
Assembly componentAssembly = null;
try
{
componentAssembly = Assembly.LoadFrom(file);
}
catch
{
m_log.ErrorFormat("[{0}] Error loading: \"{1}\".", Name, file);
}
if (componentAssembly != null)
{
try
{
// Go through all types in the assembly
foreach (Type componentType in componentAssembly.GetTypes())
{
if (componentType.IsPublic
&& !componentType.IsAbstract)
{
//if (componentType.IsSubclassOf(typeof(ComponentBase)))
if (componentType.GetInterface(nameIScriptEngineComponent) != null)
{
// We have found an type which is derived from ProdiverBase, add it to provider list
m_log.InfoFormat("[{0}] Adding component: {1}", Name, componentType.Name);
lock (providers)
{
providers.Add(componentType.Name, componentType);
}
}
//if (componentType.IsSubclassOf(typeof(ScriptEngineBase)))
if (componentType.GetInterface(nameIScriptEngine) != null)
{
// We have found an type which is derived from RegionScriptEngineBase, add it to engine list
m_log.InfoFormat("[{0}] Adding script engine: {1}", Name, componentType.Name);
lock (scriptEngines)
{
scriptEngines.Add(componentType.Name, componentType);
}
}
}
}
}
catch
(ReflectionTypeLoadException re)
{
m_log.ErrorFormat("[{0}] Could not load component \"{1}\": {2}", Name, componentAssembly.FullName, re.ToString());
int c = 0;
foreach (Exception e in re.LoaderExceptions)
{
c++;
m_log.ErrorFormat("[{0}] LoaderException {1}: {2}", Name, c, e.ToString());
}
}
} //if
} //foreach
}
public static IScriptEngineComponent GetComponentInstance(string name, params Object[] args)
{
lock (providers)
{
if (!providers.ContainsKey(name))
throw new Exception("ScriptEngine requested component named \"" + name +
"\" that does not exist.");
return Activator.CreateInstance(providers[name], args) as IScriptEngineComponent;
}
}
private readonly static string nameIScriptEngineRegionComponent = typeof(IScriptEngineRegionComponent).Name; // keep interface name in managed code
public static IScriptEngineComponent GetComponentInstance(RegionInfoStructure info, string name, params Object[] args)
{
IScriptEngineComponent c = GetComponentInstance(name, args);
// If module is IScriptEngineRegionComponent then it will have one instance per region and we will initialize it
if (c.GetType().GetInterface(nameIScriptEngineRegionComponent) != null)
((IScriptEngineRegionComponent)c).Initialize(info);
return c;
}
}
}

View File

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("OpenSim.ApplicationPlugins.ScriptEngine")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("Microsoft")]
[assembly: AssemblyProduct("OpenSim.ApplicationPlugins.ScriptEngine")]
[assembly: AssemblyCopyright("Copyright © Microsoft 2008")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("a234c402-3014-45de-9f6b-c024d9f71983")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -0,0 +1,121 @@
/*
* 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 OpenSim 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.Region.Environment.Interfaces;
using OpenSim.Region.Environment.Scenes;
using OpenSim.ScriptEngine.Shared;
namespace OpenSim.ApplicationPlugins.ScriptEngine
{
public class RegionEngineLoader : IRegionModule
{
// This is a region module.
// This means: Every time a new region is created, a new instance of this module is also created.
// This module is responsible for starting the script engine for this region.
public string Name { get { return "SECS.DotNetEngine.Scheduler.RegionLoader"; } }
public bool IsSharedModule { get { return true; } }
internal static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private string tempScriptEngineName = "DotNetEngine";
public IScriptEngine scriptEngine;
public IConfigSource ConfigSource;
public IConfig ScriptConfigSource;
public void Initialise(Scene scene, IConfigSource source)
{
// New region is being created
// Create a new script engine
// Make sure we have config
try
{
if (ConfigSource.Configs["SECS"] == null)
ConfigSource.AddConfig("SECS");
ScriptConfigSource = ConfigSource.Configs["SECS"];
// Is SECS enabled?
if (ScriptConfigSource.GetBoolean("Enabled", false))
{
LoadEngine();
if (scriptEngine != null)
scriptEngine.Initialise(scene, source);
}
}
catch (NullReferenceException)
{
}
}
public void PostInitialise()
{
if (scriptEngine != null)
scriptEngine.PostInitialise();
}
public void Close()
{
try
{
if (scriptEngine != null)
scriptEngine.Close();
}
catch (Exception ex)
{
m_log.ErrorFormat("[{0}] Unable to close engine \"{1}\": {2}", Name, tempScriptEngineName, ex.ToString());
}
}
private void LoadEngine()
{
m_log.DebugFormat("[{0}] Loading region script engine engine \"{1}\".", Name, tempScriptEngineName);
try
{
lock (ComponentFactory.scriptEngines)
{
if (!ComponentFactory.scriptEngines.ContainsKey(tempScriptEngineName))
{
m_log.ErrorFormat("[{0}] Unable to load region script engine: Script engine \"{1}\" does not exist.", Name, tempScriptEngineName);
}
else
{
scriptEngine =
Activator.CreateInstance(ComponentFactory.scriptEngines[tempScriptEngineName]) as
IScriptEngine;
}
}
}
catch (Exception ex)
{
m_log.ErrorFormat("[{0}] Internal error loading region script engine \"{1}\": {2}", Name, tempScriptEngineName, ex.ToString());
}
}
}
}

View File

@ -0,0 +1,11 @@
<Addin id="OpenSim.ApplicationPlugins.ScriptEngine" version="0.1">
<Runtime>
<Import assembly="OpenSim.ApplicationPlugins.ScriptEngine.dll" />
</Runtime>
<Dependencies>
<Addin id="OpenSim" version="0.5" />
</Dependencies>
<Extension path = "/OpenSim/Startup">
<Plugin id="ScriptEnginePlugin" type="OpenSim.ApplicationPlugins.ScriptEngine.ScriptEnginePlugin" />
</Extension>
</Addin>

View File

@ -0,0 +1,104 @@
/*
* 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 OpenSim 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;
namespace OpenSim.ApplicationPlugins.ScriptEngine
{
/// <summary>
/// Loads all Script Engine Components
/// </summary>
public class ScriptEnginePlugin : IApplicationPlugin
{
internal static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
internal OpenSimBase m_OpenSim;
public ScriptEnginePlugin()
{
// Application startup
#if DEBUG
m_log.InfoFormat("[{0}] ##################################", Name);
m_log.InfoFormat("[{0}] # Script Engine Component System #", Name);
m_log.InfoFormat("[{0}] ##################################", Name);
#else
m_log.InfoFormat("[{0}] Script Engine Component System", Name);
#endif
// Load all modules from current directory
// We only want files named OpenSim.ScriptEngine.*.dll
ComponentFactory.Load(".", "OpenSim.ScriptEngine.*.dll");
}
public void Initialise(OpenSimBase openSim)
{
// Our objective: Load component .dll's
m_OpenSim = openSim;
//m_OpenSim.Shutdown();
}
#region IApplicationPlugin stuff
/// <summary>
/// Returns the plugin version
/// </summary>
/// <returns>Plugin version in MAJOR.MINOR.REVISION.BUILD format</returns>
public string Version
{
get { return "1.0.0.0"; }
}
/// <summary>
/// Returns the plugin name
/// </summary>
/// <returns>Plugin name, eg MySQL User Provider</returns>
public string Name
{
get { return "SECS"; }
}
/// <summary>
/// Default-initialises the plugin
/// </summary>
public void Initialise() { }
///<summary>
///Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
///</summary>
///<filterpriority>2</filterpriority>
public void Dispose()
{
//throw new NotImplementedException();
}
#endregion
}
}

View File

@ -1,326 +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.Collections.Concurrent;
using System.IO;
using System.Reflection;
using System.Threading;
using log4net;
using Nini.Config;
using OpenMetaverse;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Services.Interfaces;
// using OpenSim.Region.Framework.Interfaces;
namespace OpenSim.Framework.Capabilities
{
/// <summary>
/// XXX Probably not a particularly nice way of allow us to get the scene presence from the scene (chiefly so that
/// we can popup a message on the user's client if the inventory service has permanently failed). But I didn't want
/// to just pass the whole Scene into CAPS.
/// </summary>
public delegate IClientAPI GetClientDelegate(UUID agentID);
public class Caps : IDisposable
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private string m_httpListenerHostName;
private uint m_httpListenPort;
/// <summary>
/// This is the uuid portion of every CAPS path. It is used to make capability urls private to the requester.
/// </summary>
private string m_capsObjectPath;
public string CapsObjectPath { get { return m_capsObjectPath; } }
private CapsHandlers m_capsHandlers;
private ConcurrentDictionary<string, PollServiceEventArgs> m_pollServiceHandlers
= new ConcurrentDictionary<string, PollServiceEventArgs>();
private Dictionary<string, string> m_externalCapsHandlers = new Dictionary<string, string>();
private IHttpServer m_httpListener;
private UUID m_agentID;
private string m_regionName;
private ManualResetEvent m_capsActive = new ManualResetEvent(false);
public UUID AgentID
{
get { return m_agentID; }
}
public string RegionName
{
get { return m_regionName; }
}
public string HostName
{
get { return m_httpListenerHostName; }
}
public uint Port
{
get { return m_httpListenPort; }
}
public IHttpServer HttpListener
{
get { return m_httpListener; }
}
public bool SSLCaps
{
get { return m_httpListener.UseSSL; }
}
public string SSLCommonName
{
get { return m_httpListener.SSLCommonName; }
}
public CapsHandlers CapsHandlers
{
get { return m_capsHandlers; }
}
public Dictionary<string, string> ExternalCapsHandlers
{
get { return m_externalCapsHandlers; }
}
[Flags]
public enum CapsFlags:uint
{
None = 0,
SentSeeds = 1,
ObjectAnim = 0x100,
WLEnv = 0x200,
AdvEnv = 0x400
}
public CapsFlags Flags { get; set;}
public Caps(IHttpServer httpServer, string httpListen, uint httpPort, string capsPath,
UUID agent, string regionName)
{
m_capsObjectPath = capsPath;
m_httpListener = httpServer;
m_httpListenerHostName = httpListen;
m_httpListenPort = httpPort;
if (httpServer != null && httpServer.UseSSL)
{
m_httpListenPort = httpServer.SSLPort;
httpListen = httpServer.SSLCommonName;
httpPort = httpServer.SSLPort;
}
m_agentID = agent;
m_capsHandlers = new CapsHandlers(httpServer, httpListen, httpPort);
m_regionName = regionName;
Flags = CapsFlags.None;
m_capsActive.Reset();
}
~Caps()
{
Flags = CapsFlags.None;
if (m_capsActive!= null)
{
m_capsActive.Dispose();
m_capsActive = null;
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Dispose(bool disposing)
{
Flags = CapsFlags.None;
if (m_capsActive != null)
{
DeregisterHandlers();
m_capsActive.Dispose();
m_capsActive = null;
}
}
/// <summary>
/// Register a handler. This allows modules to register handlers.
/// </summary>
/// <param name="capName"></param>
/// <param name="handler"></param>
public void RegisterHandler(string capName, IRequestHandler handler)
{
//m_log.DebugFormat("[CAPS]: Registering handler for \"{0}\": path {1}", capName, handler.Path);
m_capsHandlers[capName] = handler;
}
public void RegisterSimpleHandler(string capName, ISimpleStreamHandler handler, bool addToListener = true)
{
//m_log.DebugFormat("[CAPS]: Registering handler for \"{0}\": path {1}", capName, handler.Path);
m_capsHandlers.AddSimpleHandler(capName, handler, addToListener);
}
public void RegisterPollHandler(string capName, PollServiceEventArgs pollServiceHandler)
{
// m_log.DebugFormat(
// "[CAPS]: Registering handler with name {0}, url {1} for {2}",
// capName, pollServiceHandler.Url, m_agentID, m_regionName);
if(!m_pollServiceHandlers.TryAdd(capName, pollServiceHandler))
{
m_log.ErrorFormat(
"[CAPS]: Handler with name {0} already registered (ulr {1}, agent {2}, region {3}",
capName, pollServiceHandler.Url, m_agentID, m_regionName);
return;
}
m_httpListener.AddPollServiceHTTPHandler(pollServiceHandler);
// uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
// string protocol = "http";
// string hostName = m_httpListenerHostName;
//
// if (MainServer.Instance.UseSSL)
// {
// hostName = MainServer.Instance.SSLCommonName;
// port = MainServer.Instance.SSLPort;
// protocol = "https";
// }
// RegisterHandler(
// capName, String.Format("{0}://{1}:{2}{3}", protocol, hostName, port, pollServiceHandler.Url));
}
/// <summary>
/// Register an external handler. The service for this capability is somewhere else
/// given by the URL.
/// </summary>
/// <param name="capsName"></param>
/// <param name="url"></param>
public void RegisterHandler(string capsName, string url)
{
m_externalCapsHandlers.Add(capsName, url);
}
/// <summary>
/// Remove all CAPS service handlers.
/// </summary>
public void DeregisterHandlers()
{
foreach (string capsName in m_capsHandlers.Caps)
{
m_capsHandlers.Remove(capsName);
}
foreach (PollServiceEventArgs handler in m_pollServiceHandlers.Values)
{
m_httpListener.RemovePollServiceHTTPHandler(handler.Url);
}
m_pollServiceHandlers.Clear();
}
public bool TryGetPollHandler(string name, out PollServiceEventArgs pollHandler)
{
return m_pollServiceHandlers.TryGetValue(name, out pollHandler);
}
public Dictionary<string, PollServiceEventArgs> GetPollHandlers()
{
return new Dictionary<string, PollServiceEventArgs>(m_pollServiceHandlers);
}
/// <summary>
/// Return an LLSD-serializable Hashtable describing the
/// capabilities and their handler details.
/// </summary>
/// <param name="excludeSeed">If true, then exclude the seed cap.</param>
public Hashtable GetCapsDetails(bool excludeSeed, List<string> requestedCaps)
{
Hashtable caps = CapsHandlers.GetCapsDetails(excludeSeed, requestedCaps);
lock (m_pollServiceHandlers)
{
foreach (KeyValuePair <string, PollServiceEventArgs> kvp in m_pollServiceHandlers)
{
if (!requestedCaps.Contains(kvp.Key))
continue;
string hostName = m_httpListenerHostName;
uint port = (MainServer.Instance == null) ? 0 : MainServer.Instance.Port;
string protocol = "http";
if (MainServer.Instance.UseSSL)
{
hostName = MainServer.Instance.SSLCommonName;
port = MainServer.Instance.SSLPort;
protocol = "https";
}
caps[kvp.Key] = string.Format("{0}://{1}:{2}{3}", protocol, hostName, port, kvp.Value.Url);
}
}
// Add the external too
foreach (KeyValuePair<string, string> kvp in ExternalCapsHandlers)
{
if (!requestedCaps.Contains(kvp.Key))
continue;
caps[kvp.Key] = kvp.Value;
}
return caps;
}
public void Activate()
{
m_capsActive.Set();
}
public bool WaitForActivation()
{
// Wait for 30s. If that elapses, return false and run without caps
return m_capsActive.WaitOne(120000);
}
}
}

View File

@ -1,224 +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.Collections;
using System.Collections.Generic;
using System.Collections.Concurrent;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
namespace OpenSim.Framework.Capabilities
{
/// <summary>
/// CapsHandlers is a cap handler container but also takes
/// care of adding and removing cap handlers to and from the
/// supplied BaseHttpServer.
/// </summary>
public class CapsHandlers
{
private Dictionary<string, IRequestHandler> m_capsHandlers = new Dictionary<string, IRequestHandler>();
private ConcurrentDictionary<string, ISimpleStreamHandler> m_capsSimpleHandlers = new ConcurrentDictionary<string, ISimpleStreamHandler>();
private IHttpServer m_httpListener;
private string m_httpListenerHostName;
private uint m_httpListenerPort;
private bool m_useSSL = false;
/// <summary></summary>
/// CapsHandlers is a cap handler container but also takes
/// care of adding and removing cap handlers to and from the
/// supplied BaseHttpServer.
/// </summary>
/// <param name="httpListener">base HTTP server</param>
/// <param name="httpListenerHostname">host name of the HTTP server</param>
/// <param name="httpListenerPort">HTTP port</param>
public CapsHandlers(IHttpServer httpListener, string httpListenerHostname, uint httpListenerPort)
{
m_httpListener = httpListener;
m_httpListenerHostName = httpListenerHostname;
m_httpListenerPort = httpListenerPort;
if (httpListener != null && httpListener.UseSSL)
m_useSSL = true;
else
m_useSSL = false;
}
/// <summary>
/// Remove the cap handler for a capability.
/// </summary>
/// <param name="capsName">name of the capability of the cap
/// handler to be removed</param>
public void Remove(string capsName)
{
lock (m_capsHandlers)
{
if(m_capsHandlers.ContainsKey(capsName))
{
m_httpListener.RemoveStreamHandler("POST", m_capsHandlers[capsName].Path);
m_httpListener.RemoveStreamHandler("PUT", m_capsHandlers[capsName].Path);
m_httpListener.RemoveStreamHandler("GET", m_capsHandlers[capsName].Path);
m_httpListener.RemoveStreamHandler("DELETE", m_capsHandlers[capsName].Path);
m_capsHandlers.Remove(capsName);
}
}
if(m_capsSimpleHandlers.TryRemove(capsName, out ISimpleStreamHandler hdr))
{
m_httpListener.RemoveSimpleStreamHandler(hdr.Path);
}
}
public void AddSimpleHandler(string capName, ISimpleStreamHandler handler, bool addToListener = true)
{
if(ContainsCap(capName))
Remove(capName);
if(m_capsSimpleHandlers.TryAdd(capName, handler) && addToListener)
m_httpListener.AddSimpleStreamHandler(handler);
}
public bool ContainsCap(string cap)
{
lock (m_capsHandlers)
if (m_capsHandlers.ContainsKey(cap))
return true;
return m_capsSimpleHandlers.ContainsKey(cap);
}
/// <summary>
/// The indexer allows us to treat the CapsHandlers object
/// in an intuitive dictionary like way.
/// </summary>
/// <remarks>
/// The indexer will throw an exception when you try to
/// retrieve a cap handler for a cap that is not contained in
/// CapsHandlers.
/// </remarks>
public IRequestHandler this[string idx]
{
get
{
lock (m_capsHandlers)
return m_capsHandlers[idx];
}
set
{
lock (m_capsHandlers)
{
if (m_capsHandlers.ContainsKey(idx))
{
m_httpListener.RemoveStreamHandler("POST", m_capsHandlers[idx].Path);
m_httpListener.RemoveStreamHandler("PUT", m_capsHandlers[idx].Path);
m_httpListener.RemoveStreamHandler("GET", m_capsHandlers[idx].Path);
m_httpListener.RemoveStreamHandler("DELETE", m_capsHandlers[idx].Path);
m_capsHandlers.Remove(idx);
}
if (null == value) return;
m_capsHandlers[idx] = value;
m_httpListener.AddStreamHandler(value);
}
}
}
/// <summary>
/// Return the list of cap names for which this CapsHandlers
/// object contains cap handlers.
/// </summary>
public string[] Caps
{
get
{
lock (m_capsHandlers)
{
string[] __keys = new string[m_capsHandlers.Keys.Count + m_capsSimpleHandlers.Keys.Count];
m_capsHandlers.Keys.CopyTo(__keys, 0);
m_capsSimpleHandlers.Keys.CopyTo(__keys, m_capsHandlers.Keys.Count);
return __keys;
}
}
}
/// <summary>
/// Return an LLSD-serializable Hashtable describing the
/// capabilities and their handler details.
/// </summary>
/// <param name="excludeSeed">If true, then exclude the seed cap.</param>
public Hashtable GetCapsDetails(bool excludeSeed, List<string> requestedCaps)
{
Hashtable caps = new Hashtable();
string protocol = m_useSSL ? "https://" : "http://";
string baseUrl = protocol + m_httpListenerHostName + ":" + m_httpListenerPort.ToString();
if (requestedCaps == null)
{
lock (m_capsHandlers)
{
foreach (KeyValuePair<string, ISimpleStreamHandler> kvp in m_capsSimpleHandlers)
caps[kvp.Key] = baseUrl + kvp.Value.Path;
foreach (KeyValuePair<string, IRequestHandler> kvp in m_capsHandlers)
caps[kvp.Key] = baseUrl + kvp.Value.Path;
}
return caps;
}
lock (m_capsHandlers)
{
for(int i = 0; i < requestedCaps.Count; ++i)
{
string capsName = requestedCaps[i];
if (excludeSeed && "SEED" == capsName)
continue;
if (m_capsSimpleHandlers.TryGetValue(capsName, out ISimpleStreamHandler shdr))
{
caps[capsName] = baseUrl + shdr.Path;
continue;
}
if (m_capsHandlers.TryGetValue(capsName, out IRequestHandler chdr))
{
caps[capsName] = baseUrl + chdr.Path;
}
}
}
return caps;
}
/// <summary>
/// Returns a copy of the dictionary of all the HTTP cap handlers
/// </summary>
/// <returns>
/// The dictionary copy. The key is the capability name, the value is the HTTP handler.
/// </returns>
public Dictionary<string, IRequestHandler> GetCapsHandlers()
{
lock (m_capsHandlers)
return new Dictionary<string, IRequestHandler>(m_capsHandlers);
}
}
}

View File

@ -1,449 +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.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using log4net;
using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Framework.Capabilities;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Services.Interfaces;
using OSDMap = OpenMetaverse.StructuredData.OSDMap;
using OSDArray = OpenMetaverse.StructuredData.OSDArray;
namespace OpenSim.Capabilities.Handlers
{
public class FetchInvDescHandler
{
private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static byte[] EmptyResponse = Util.UTF8NBGetbytes("<llsd><map><key>folders</key><array /></map></llsd>");
private IInventoryService m_InventoryService;
private ILibraryService m_LibraryService;
private IScene m_Scene;
public FetchInvDescHandler(IInventoryService invService, ILibraryService libService, IScene s)
{
m_InventoryService = invService;
m_LibraryService = libService;
m_Scene = s;
}
public void FetchInventoryDescendentsRequest(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, ExpiringKey<UUID> BadRequests)
{
//m_log.DebugFormat("[XXX]: FetchInventoryDescendentsRequest in {0}, {1}", (m_Scene == null) ? "none" : m_Scene.Name, request);
List<LLSDFetchInventoryDescendents> folders = null;
List<UUID> bad_folders = new List<UUID>();
try
{
OSDArray foldersrequested = null;
OSD tmp = OSDParser.DeserializeLLSDXml(httpRequest.InputStream);
OSDMap map = (OSDMap)tmp;
if(map.TryGetValue("folders", out tmp) && tmp is OSDArray)
foldersrequested = tmp as OSDArray;
if (foldersrequested == null || foldersrequested.Count == 0)
{
httpResponse.RawBuffer = EmptyResponse;
return;
}
folders = new List<LLSDFetchInventoryDescendents>(foldersrequested.Count);
for (int i = 0; i < foldersrequested.Count; i++)
{
OSDMap mfolder = foldersrequested[i] as OSDMap;
UUID id = mfolder["folder_id"].AsUUID();
if(BadRequests.ContainsKey(id))
{
bad_folders.Add(id);
}
else
{
LLSDFetchInventoryDescendents llsdRequest = new LLSDFetchInventoryDescendents();
try
{
llsdRequest.folder_id = id;
llsdRequest.owner_id = mfolder["owner_id"].AsUUID();
llsdRequest.sort_order = mfolder["sort_order"].AsInteger();
llsdRequest.fetch_folders = mfolder["fetch_folders"].AsBoolean();
llsdRequest.fetch_items = mfolder["fetch_items"].AsBoolean();
}
catch (Exception e)
{
m_log.Debug("[WEB FETCH INV DESC HANDLER]: caught exception doing OSD deserialize" + e.Message);
continue;
}
folders.Add(llsdRequest);
}
}
foldersrequested = null;
tmp = null;
}
catch (Exception e)
{
m_log.ErrorFormat("[FETCH INV DESC]: fail parsing request: {0}", e.Message);
httpResponse.RawBuffer = EmptyResponse;
return;
}
if (folders == null || folders.Count == 0)
{
if(bad_folders.Count == 0)
{
httpResponse.RawBuffer = EmptyResponse;
return;
}
StringBuilder sb = osStringBuilderCache.Acquire();
sb.Append("<llsd><map><key>folders</key><array /></map><map><key>bad_folders</key><array>");
foreach (UUID bad in bad_folders)
{
sb.Append("<map><key>folder_id</key><uuid>");
sb.Append(bad.ToString());
sb.Append("</uuid><key>error</key><string>Unknown</string></map>");
}
sb.Append("</array></map></llsd>");
httpResponse.RawBuffer = Util.UTF8NBGetbytes(osStringBuilderCache.GetStringAndRelease(sb));
}
int total_folders = 0;
int total_items = 0;
List<InventoryCollection> invcollSet = Fetch(folders, bad_folders, ref total_folders, ref total_items);
//m_log.DebugFormat("[XXX]: Got {0} folders from a request of {1}", invcollSet.Count, folders.Count);
int invcollSetCount = 0;
if (invcollSet != null)
invcollSetCount = invcollSet.Count;
int mem = 8192 + ((256 * invcollSetCount +
384 * total_folders +
1024 * total_items +
128 * bad_folders.Count) & 0x7ffff000);
StringBuilder lastresponse = new StringBuilder(mem);
lastresponse.Append("<llsd>");
if (invcollSetCount > 0)
{
lastresponse.Append("<map><key>folders</key><array>");
int i = 0;
InventoryCollection thiscoll;
for (i = 0; i < invcollSetCount; i++)
{
thiscoll = invcollSet[i];
invcollSet[i] = null;
LLSDxmlEncode.AddMap(lastresponse);
LLSDxmlEncode.AddElem("agent_id", thiscoll.OwnerID, lastresponse);
LLSDxmlEncode.AddElem("descendents", thiscoll.Descendents, lastresponse);
LLSDxmlEncode.AddElem("folder_id", thiscoll.FolderID, lastresponse);
if (thiscoll.Folders == null || thiscoll.Folders.Count == 0)
LLSDxmlEncode.AddEmptyArray("categories", lastresponse);
else
{
LLSDxmlEncode.AddArray("categories", lastresponse);
foreach (InventoryFolderBase invFolder in thiscoll.Folders)
{
LLSDxmlEncode.AddMap(lastresponse);
LLSDxmlEncode.AddElem("folder_id", invFolder.ID, lastresponse);
LLSDxmlEncode.AddElem("parent_id", invFolder.ParentID, lastresponse);
LLSDxmlEncode.AddElem("name", invFolder.Name, lastresponse);
LLSDxmlEncode.AddElem("type", invFolder.Type, lastresponse);
LLSDxmlEncode.AddElem("preferred_type", (int)-1, lastresponse);
LLSDxmlEncode.AddElem("version", invFolder.Version, lastresponse);
LLSDxmlEncode.AddEndMap(lastresponse);
}
LLSDxmlEncode.AddEndArray(lastresponse);
}
if (thiscoll.Items == null || thiscoll.Items.Count == 0)
LLSDxmlEncode.AddEmptyArray("items", lastresponse);
else
{
LLSDxmlEncode.AddArray("items", lastresponse);
foreach (InventoryItemBase invItem in thiscoll.Items)
{
invItem.ToLLSDxml(lastresponse);
}
LLSDxmlEncode.AddEndArray(lastresponse);
}
LLSDxmlEncode.AddElem("owner_id", thiscoll.OwnerID, lastresponse);
LLSDxmlEncode.AddElem("version", thiscoll.Version, lastresponse);
LLSDxmlEncode.AddEndMap(lastresponse);
invcollSet[i] = null;
}
lastresponse.Append("</array></map>");
thiscoll = null;
}
else
{
lastresponse.Append("<map><key>folders</key><array /></map>");
}
//m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Bad folders {0}", string.Join(", ", bad_folders));
if (bad_folders.Count > 0)
{
lastresponse.Append("<map><key>bad_folders</key><array>");
foreach (UUID bad in bad_folders)
{
BadRequests.Add(bad);
lastresponse.Append("<map><key>folder_id</key><uuid>");
lastresponse.Append(bad.ToString());
lastresponse.Append("</uuid><key>error</key><string>Unknown</string></map>");
}
lastresponse.Append("</array></map>");
}
lastresponse.Append("</llsd>");
httpResponse.RawBuffer = Util.UTF8NBGetbytes(lastresponse.ToString());
}
private void AddLibraryFolders(List<LLSDFetchInventoryDescendents> libFolders, List<InventoryCollection> result, ref int total_folders, ref int total_items)
{
InventoryFolderImpl fold;
if (m_LibraryService == null || m_LibraryService.LibraryRootFolder == null)
return;
foreach (LLSDFetchInventoryDescendents f in libFolders)
{
if ((fold = m_LibraryService.LibraryRootFolder.FindFolder(f.folder_id)) != null)
{
InventoryCollection Collection = new InventoryCollection();
// ret.Collection.Folders = new List<InventoryFolderBase>();
Collection.Folders = fold.RequestListOfFolders();
Collection.Items = fold.RequestListOfItems();
Collection.OwnerID = m_LibraryService.LibraryRootFolder.Owner;
Collection.FolderID = f.folder_id;
Collection.Version = fold.Version;
Collection.Descendents = Collection.Items.Count + Collection.Folders.Count;
total_folders += Collection.Folders.Count;
total_items += Collection.Items.Count;
result.Add(Collection);
//m_log.DebugFormat("[XXX]: Added libfolder {0} ({1}) {2}", ret.Collection.FolderID, ret.Collection.OwnerID);
}
}
}
private List<InventoryCollection> Fetch(List<LLSDFetchInventoryDescendents> fetchFolders, List<UUID> bad_folders, ref int total_folders, ref int total_items)
{
//m_log.DebugFormat(
// "[WEB FETCH INV DESC HANDLER]: Fetching {0} folders for owner {1}", fetchFolders.Count, fetchFolders[0].owner_id);
// FIXME MAYBE: We're not handling sortOrder!
List<InventoryCollection> result = new List<InventoryCollection>(32);
List<LLSDFetchInventoryDescendents> libFolders = new List<LLSDFetchInventoryDescendents>(32);
List<LLSDFetchInventoryDescendents> otherFolders = new List<LLSDFetchInventoryDescendents>(32);
HashSet<UUID> libIDs = new HashSet<UUID>();
HashSet<UUID> otherIDs = new HashSet<UUID>();
bool dolib = (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null);
UUID libOwner = UUID.Zero;
if(dolib)
libOwner = m_LibraryService.LibraryRootFolder.Owner;
// Filter folder Zero right here. Some viewers (Firestorm) send request for folder Zero, which doesn't make sense
// and can kill the sim (all root folders have parent_id Zero)
// send something.
bool doneZeroID = false;
foreach(LLSDFetchInventoryDescendents f in fetchFolders)
{
if (f.folder_id == UUID.Zero)
{
if(doneZeroID)
continue;
doneZeroID = true;
InventoryCollection Collection = new InventoryCollection();
Collection.OwnerID = f.owner_id;
Collection.Version = 0;
Collection.FolderID = f.folder_id;
Collection.Descendents = 0;
result.Add(Collection);
continue;
}
if(dolib && f.owner_id == libOwner)
{
if(libIDs.Contains(f.folder_id))
continue;
libIDs.Add(f.folder_id);
libFolders.Add(f);
continue;
}
if(otherIDs.Contains(f.folder_id))
continue;
otherIDs.Add(f.folder_id);
otherFolders.Add(f);
}
fetchFolders.Clear();
if(otherFolders.Count > 0)
{
int i = 0;
//m_log.DebugFormat("[XXX]: {0}", string.Join(",", fids));
InventoryCollection[] fetchedContents = m_InventoryService.GetMultipleFoldersContent(otherFolders[0].owner_id, otherIDs.ToArray());
if (fetchedContents == null)
return null;
if (fetchedContents.Length == 0)
{
foreach (LLSDFetchInventoryDescendents freq in otherFolders)
BadFolder(freq, null, bad_folders);
}
else
{
i = 0;
// Do some post-processing. May need to fetch more from inv server for links
foreach (InventoryCollection contents in fetchedContents)
{
// Find the original request
LLSDFetchInventoryDescendents freq = otherFolders[i];
otherFolders[i]=null;
i++;
if (BadFolder(freq, contents, bad_folders))
continue;
if(!freq.fetch_folders)
contents.Folders.Clear();
if(!freq.fetch_items)
contents.Items.Clear();
contents.Descendents = contents.Items.Count + contents.Folders.Count;
// Next: link management
ProcessLinks(freq, contents);
total_folders += contents.Folders.Count;
total_items += contents.Items.Count;
result.Add(contents);
}
}
}
if(dolib && libFolders.Count > 0)
{
AddLibraryFolders(libFolders, result, ref total_folders, ref total_items);
}
return result;
}
private bool BadFolder(LLSDFetchInventoryDescendents freq, InventoryCollection contents, List<UUID> bad_folders)
{
if (contents == null)
{
bad_folders.Add(freq.folder_id);
return true;
}
// The inventory server isn't sending FolderID in the collection...
// Must fetch it individually
if (contents.FolderID == UUID.Zero)
{
InventoryFolderBase containingFolder = m_InventoryService.GetFolder(freq.owner_id, freq.folder_id);
if (containingFolder == null)
{
m_log.WarnFormat("[WEB FETCH INV DESC HANDLER]: Unable to fetch folder {0}", freq.folder_id);
bad_folders.Add(freq.folder_id);
return true;
}
contents.FolderID = containingFolder.ID;
contents.OwnerID = containingFolder.Owner;
contents.Version = containingFolder.Version;
}
return false;
}
private void ProcessLinks(LLSDFetchInventoryDescendents freq, InventoryCollection contents)
{
if (contents.Items == null || contents.Items.Count == 0)
return;
// viewers are lasy and want a copy of the linked item sent before the link to it
// look for item links
List<UUID> itemIDs = new List<UUID>();
foreach (InventoryItemBase item in contents.Items)
{
//m_log.DebugFormat("[XXX]: {0} {1}", item.Name, item.AssetType);
if (item.AssetType == (int)AssetType.Link)
itemIDs.Add(item.AssetID);
}
// get the linked if any
if (itemIDs.Count > 0)
{
InventoryItemBase[] linked = m_InventoryService.GetMultipleItems(freq.owner_id, itemIDs.ToArray());
if (linked != null)
{
List<InventoryItemBase> linkedItems = new List<InventoryItemBase>(linked.Length);
// check for broken
foreach (InventoryItemBase linkedItem in linked)
{
// Take care of genuinely broken links where the target doesn't exist
// HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
// but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
// rather than having to keep track of every folder requested in the recursion.
if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link)
{
linkedItems.Add(linkedItem);
//m_log.DebugFormat("[WEB FETCH INV DESC HANDLER]: Added {0} {1} {2}", linkedItem.Name, linkedItem.AssetType, linkedItem.Folder);
}
}
// insert them
if(linkedItems.Count > 0)
contents.Items.InsertRange(0, linkedItems);
}
}
}
}
}

View File

@ -1,85 +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 Nini.Config;
using OpenSim.Server.Base;
using OpenSim.Services.Interfaces;
using OpenSim.Framework;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Server.Handlers.Base;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
namespace OpenSim.Capabilities.Handlers
{
public class FetchInvDescServerConnector : ServiceConnector
{
private IInventoryService m_InventoryService;
private ILibraryService m_LibraryService;
private string m_ConfigName = "CapsService";
public FetchInvDescServerConnector(IConfigSource config, IHttpServer server, string configName) :
base(config, server, configName)
{
if (configName != String.Empty)
m_ConfigName = configName;
IConfig serverConfig = config.Configs[m_ConfigName];
if (serverConfig == null)
throw new Exception(String.Format("No section '{0}' in config file", m_ConfigName));
string invService = serverConfig.GetString("InventoryService", String.Empty);
if (invService == String.Empty)
throw new Exception("No InventoryService in config file");
Object[] args = new Object[] { config };
m_InventoryService =
ServerUtils.LoadPlugin<IInventoryService>(invService, args);
if (m_InventoryService == null)
throw new Exception(String.Format("Failed to load InventoryService from {0}; config is {1}", invService, m_ConfigName));
string libService = serverConfig.GetString("LibraryService", String.Empty);
m_LibraryService =
ServerUtils.LoadPlugin<ILibraryService>(libService, args);
ExpiringKey<UUID> m_badRequests = new ExpiringKey<UUID>(30000);
FetchInvDescHandler webFetchHandler = new FetchInvDescHandler(m_InventoryService, m_LibraryService, null);
ISimpleStreamHandler reqHandler
= new SimpleStreamHandler("/CAPS/WebFetchInvDesc/", delegate(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
webFetchHandler.FetchInventoryDescendentsRequest(httpRequest, httpResponse, m_badRequests);
});
server.AddSimpleStreamHandler(reqHandler);
}
}
}

View File

@ -1,166 +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.Net;
using System.Reflection;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Services.Interfaces;
using OSDArray = OpenMetaverse.StructuredData.OSDArray;
using OSDMap = OpenMetaverse.StructuredData.OSDMap;
using log4net;
namespace OpenSim.Capabilities.Handlers
{
public class FetchInventory2Handler
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IInventoryService m_inventoryService;
private UUID m_agentID;
public FetchInventory2Handler(IInventoryService invService, UUID agentId)
{
m_inventoryService = invService;
m_agentID = agentId;
}
public string FetchInventoryRequest(string request, string path, string param, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
//m_log.DebugFormat("[FETCH INVENTORY HANDLER]: Received FetchInventory capability request {0}", request);
OSDMap requestmap = (OSDMap)OSDParser.DeserializeLLSDXml(Utils.StringToBytes(request));
OSDArray itemsRequested = (OSDArray)requestmap["items"];
UUID[] itemIDs = new UUID[itemsRequested.Count];
int i = 0;
foreach (OSDMap osdItemId in itemsRequested)
{
itemIDs[i++] = osdItemId["item_id"].AsUUID();
}
InventoryItemBase[] items = null;
if (m_agentID != UUID.Zero)
{
items = m_inventoryService.GetMultipleItems(m_agentID, itemIDs);
}
else
{
items = new InventoryItemBase[itemsRequested.Count];
foreach (UUID id in itemIDs)
items[i++] = m_inventoryService.GetItem(UUID.Zero, id);
}
StringBuilder lsl = LLSDxmlEncode.Start(4096);
LLSDxmlEncode.AddMap(lsl);
if(m_agentID == UUID.Zero && items.Length > 0)
LLSDxmlEncode.AddElem("agent_id", items[0].Owner, lsl);
else
LLSDxmlEncode.AddElem("agent_id", m_agentID, lsl);
if(items == null || items.Length == 0)
{
LLSDxmlEncode.AddEmptyArray("items", lsl);
}
else
{
LLSDxmlEncode.AddArray("items", lsl);
foreach (InventoryItemBase item in items)
{
if (item != null)
item.ToLLSDxml(lsl, 0xff);
}
LLSDxmlEncode.AddEndArray(lsl);
}
LLSDxmlEncode.AddEndMap(lsl);
return LLSDxmlEncode.End(lsl);
}
public void FetchInventorySimpleRequest(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, OSDMap requestmap, ExpiringKey<UUID> BadRequests)
{
//m_log.DebugFormat("[FETCH INVENTORY HANDLER]: Received FetchInventory capability request {0}", request);
if(BadRequests == null)
{
httpResponse.StatusCode = (int)HttpStatusCode.NotFound;
return;
}
OSDArray itemsRequested = (OSDArray)requestmap["items"];
UUID[] itemIDs = new UUID[itemsRequested.Count];
int i = 0;
foreach (OSDMap osdItemId in itemsRequested)
{
UUID id = osdItemId["item_id"].AsUUID();
if(!BadRequests.ContainsKey(id))
itemIDs[i++] = id;
}
InventoryItemBase[] items = null;
try
{
// badrequests still not filled
items = m_inventoryService.GetMultipleItems(m_agentID, itemIDs);
}
catch{ }
StringBuilder lsl = LLSDxmlEncode.Start(4096);
LLSDxmlEncode.AddMap(lsl);
LLSDxmlEncode.AddElem("agent_id", m_agentID, lsl);
if (items == null || items.Length == 0)
{
LLSDxmlEncode.AddEmptyArray("items", lsl);
}
else
{
LLSDxmlEncode.AddArray("items", lsl);
foreach (InventoryItemBase item in items)
{
if (item != null)
item.ToLLSDxml(lsl, 0xff);
}
LLSDxmlEncode.AddEndArray(lsl);
}
LLSDxmlEncode.AddEndMap(lsl);
httpResponse.RawBuffer = Util.UTF8.GetBytes(LLSDxmlEncode.End(lsl));
httpResponse.StatusCode = (int)HttpStatusCode.OK;
}
}
}

View File

@ -1,71 +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 Nini.Config;
using OpenSim.Server.Base;
using OpenSim.Services.Interfaces;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Server.Handlers.Base;
using OpenMetaverse;
namespace OpenSim.Capabilities.Handlers
{
public class FetchInventory2ServerConnector : ServiceConnector
{
private IInventoryService m_InventoryService;
private string m_ConfigName = "CapsService";
public FetchInventory2ServerConnector(IConfigSource config, IHttpServer server, string configName)
: base(config, server, configName)
{
if (configName != String.Empty)
m_ConfigName = configName;
IConfig serverConfig = config.Configs[m_ConfigName];
if (serverConfig == null)
throw new Exception(String.Format("No section '{0}' in config file", m_ConfigName));
string invService = serverConfig.GetString("InventoryService", String.Empty);
if (invService == String.Empty)
throw new Exception("No InventoryService in config file");
Object[] args = new Object[] { config };
m_InventoryService = ServerUtils.LoadPlugin<IInventoryService>(invService, args);
if (m_InventoryService == null)
throw new Exception(String.Format("Failed to load InventoryService from {0}; config is {1}", invService, m_ConfigName));
FetchInventory2Handler fiHandler = new FetchInventory2Handler(m_InventoryService, UUID.Zero);
IRequestHandler reqHandler
= new RestStreamHandler(
"POST", "/CAPS/FetchInventory/", fiHandler.FetchInventoryRequest, "FetchInventory", null);
server.AddStreamHandler(reqHandler);
}
}
}

View File

@ -1,170 +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.Linq;
using System.Net;
using System.Text.RegularExpressions;
using log4net;
using log4net.Config;
using NUnit.Framework;
using OpenMetaverse;
using OpenSim.Capabilities.Handlers;
using OpenSim.Framework;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces;
using OpenSim.Tests.Common;
namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests
{
[TestFixture]
public class FetchInventory2HandlerTests : OpenSimTestCase
{
private UUID m_userID = UUID.Random();
private Scene m_scene;
private UUID m_rootFolderID;
private UUID m_notecardsFolder;
private UUID m_objectsFolder;
private void Init()
{
// Create an inventory that looks like this:
//
// /My Inventory
// <other system folders>
// /Objects
// Object 1
// Object 2
// Object 3
// /Notecards
// Notecard 1
// Notecard 2
// Notecard 3
// Notecard 4
// Notecard 5
m_scene = new SceneHelpers().SetupScene();
m_scene.InventoryService.CreateUserInventory(m_userID);
m_rootFolderID = m_scene.InventoryService.GetRootFolder(m_userID).ID;
InventoryFolderBase of = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Object);
m_objectsFolder = of.ID;
// Add 3 objects
InventoryItemBase item;
for (int i = 1; i <= 3; i++)
{
item = new InventoryItemBase(new UUID("b0000000-0000-0000-0000-0000000000b" + i), m_userID);
item.AssetID = UUID.Random();
item.AssetType = (int)AssetType.Object;
item.Folder = m_objectsFolder;
item.Name = "Object " + i;
m_scene.InventoryService.AddItem(item);
}
InventoryFolderBase ncf = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Notecard);
m_notecardsFolder = ncf.ID;
// Add 5 notecards
for (int i = 1; i <= 5; i++)
{
item = new InventoryItemBase(new UUID("10000000-0000-0000-0000-00000000000" + i), m_userID);
item.AssetID = UUID.Random();
item.AssetType = (int)AssetType.Notecard;
item.Folder = m_notecardsFolder;
item.Name = "Notecard " + i;
m_scene.InventoryService.AddItem(item);
}
}
[Test]
public void Test_001_RequestOne()
{
TestHelpers.InMethod();
Init();
FetchInventory2Handler handler = new FetchInventory2Handler(m_scene.InventoryService, m_userID);
TestOSHttpRequest req = new TestOSHttpRequest();
TestOSHttpResponse resp = new TestOSHttpResponse();
string request = "<llsd><map><key>items</key><array><map><key>item_id</key><uuid>";
request += "10000000-0000-0000-0000-000000000001"; // Notecard 1
request += "</uuid></map></array></map></llsd>";
string llsdresponse = handler.FetchInventoryRequest(request, "/FETCH", string.Empty, req, resp);
Assert.That(llsdresponse != null, Is.True, "Incorrect null response");
Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response");
Assert.That(llsdresponse.Contains(m_userID.ToString()), Is.True, "Response should contain userID");
Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000001"), Is.True, "Response does not contain item uuid");
Assert.That(llsdresponse.Contains("Notecard 1"), Is.True, "Response does not contain item Name");
Console.WriteLine(llsdresponse);
}
[Test]
public void Test_002_RequestMany()
{
TestHelpers.InMethod();
Init();
FetchInventory2Handler handler = new FetchInventory2Handler(m_scene.InventoryService, m_userID);
TestOSHttpRequest req = new TestOSHttpRequest();
TestOSHttpResponse resp = new TestOSHttpResponse();
string request = "<llsd><map><key>items</key><array>";
request += "<map><key>item_id</key><uuid>10000000-0000-0000-0000-000000000001</uuid></map>"; // Notecard 1
request += "<map><key>item_id</key><uuid>10000000-0000-0000-0000-000000000002</uuid></map>"; // Notecard 2
request += "<map><key>item_id</key><uuid>10000000-0000-0000-0000-000000000003</uuid></map>"; // Notecard 3
request += "<map><key>item_id</key><uuid>10000000-0000-0000-0000-000000000004</uuid></map>"; // Notecard 4
request += "<map><key>item_id</key><uuid>10000000-0000-0000-0000-000000000005</uuid></map>"; // Notecard 5
request += "</array></map></llsd>";
string llsdresponse = handler.FetchInventoryRequest(request, "/FETCH", string.Empty, req, resp);
Assert.That(llsdresponse != null, Is.True, "Incorrect null response");
Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response");
Assert.That(llsdresponse.Contains(m_userID.ToString()), Is.True, "Response should contain userID");
Console.WriteLine(llsdresponse);
Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000001"), Is.True, "Response does not contain notecard 1");
Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000002"), Is.True, "Response does not contain notecard 2");
Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000003"), Is.True, "Response does not contain notecard 3");
Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000004"), Is.True, "Response does not contain notecard 4");
Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000005"), Is.True, "Response does not contain notecard 5");
}
}
}

View File

@ -1,300 +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.Linq;
using System.IO;
using System.Text.RegularExpressions;
using log4net;
using log4net.Config;
using NUnit.Framework;
using OpenMetaverse;
using OpenSim.Capabilities.Handlers;
using OpenSim.Framework;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Services.Interfaces;
using OpenSim.Tests.Common;
namespace OpenSim.Capabilities.Handlers.FetchInventory.Tests
{
[TestFixture]
public class FetchInventoryDescendents2HandlerTests : OpenSimTestCase
{
private UUID m_userID = new UUID("00000000-0000-0000-0000-000000000001");
private Scene m_scene;
private UUID m_rootFolderID;
private int m_rootDescendents;
private UUID m_notecardsFolder;
private UUID m_objectsFolder;
private void Init()
{
// Create an inventory that looks like this:
//
// /My Inventory
// <other system folders>
// /Objects
// Some Object
// /Notecards
// Notecard 1
// Notecard 2
// /Test Folder
// Link to notecard -> /Notecards/Notecard 2
// Link to Objects folder -> /Objects
m_scene = new SceneHelpers().SetupScene();
m_scene.InventoryService.CreateUserInventory(m_userID);
m_rootFolderID = m_scene.InventoryService.GetRootFolder(m_userID).ID;
InventoryFolderBase of = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Object);
m_objectsFolder = of.ID;
// Add an object
InventoryItemBase item = new InventoryItemBase(new UUID("b0000000-0000-0000-0000-00000000000b"), m_userID);
item.AssetID = UUID.Random();
item.AssetType = (int)AssetType.Object;
item.Folder = m_objectsFolder;
item.Name = "Some Object";
m_scene.InventoryService.AddItem(item);
InventoryFolderBase ncf = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Notecard);
m_notecardsFolder = ncf.ID;
// Add a notecard
item = new InventoryItemBase(new UUID("10000000-0000-0000-0000-000000000001"), m_userID);
item.AssetID = UUID.Random();
item.AssetType = (int)AssetType.Notecard;
item.Folder = m_notecardsFolder;
item.Name = "Test Notecard 1";
m_scene.InventoryService.AddItem(item);
// Add another notecard
item.ID = new UUID("20000000-0000-0000-0000-000000000002");
item.AssetID = new UUID("a0000000-0000-0000-0000-00000000000a");
item.Name = "Test Notecard 2";
m_scene.InventoryService.AddItem(item);
// Add a folder
InventoryFolderBase folder = new InventoryFolderBase(new UUID("f0000000-0000-0000-0000-00000000000f"), "Test Folder", m_userID, m_rootFolderID);
folder.Type = (short)FolderType.None;
m_scene.InventoryService.AddFolder(folder);
// Add a link to notecard 2 in Test Folder
item.AssetID = item.ID; // use item ID of notecard 2
item.ID = new UUID("40000000-0000-0000-0000-000000000004");
item.AssetType = (int)AssetType.Link;
item.Folder = folder.ID;
item.Name = "Link to notecard";
m_scene.InventoryService.AddItem(item);
// Add a link to the Objects folder in Test Folder
item.AssetID = m_scene.InventoryService.GetFolderForType(m_userID, FolderType.Object).ID; // use item ID of Objects folder
item.ID = new UUID("50000000-0000-0000-0000-000000000005");
item.AssetType = (int)AssetType.LinkFolder;
item.Folder = folder.ID;
item.Name = "Link to Objects folder";
m_scene.InventoryService.AddItem(item);
InventoryCollection coll = m_scene.InventoryService.GetFolderContent(m_userID, m_rootFolderID);
m_rootDescendents = coll.Items.Count + coll.Folders.Count;
Console.WriteLine("Number of descendents: " + m_rootDescendents);
}
private string dorequest(FetchInvDescHandler handler, string request)
{
TestOSHttpRequest req = new TestOSHttpRequest();
TestOSHttpResponse resp = new TestOSHttpResponse();
using(ExpiringKey<UUID> bad = new ExpiringKey<UUID>(5000)) // bad but this is test
using (MemoryStream ms = new MemoryStream(Utils.StringToBytes(request), false))
{
req.InputStream = ms;
handler.FetchInventoryDescendentsRequest(req, resp, bad);
}
return Util.UTF8.GetString(resp.RawBuffer);
}
[Test]
public void Test_001_SimpleFolder()
{
TestHelpers.InMethod();
Init();
FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene);
string request = "<llsd><map><key>folders</key><array><map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>";
request += m_rootFolderID;
request += "</uuid><key>owner_id</key><uuid>";
request += m_userID.ToString();
request += "</uuid><key>sort_order</key><integer>1</integer></map></array></map></llsd>";
string llsdresponse = dorequest(handler, request);
Assert.That(llsdresponse != null, Is.True, "Incorrect null response");
Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response");
Assert.That(llsdresponse.Contains(m_userID.ToString()), Is.True, "Response should contain userID");
string descendents = "descendents</key><integer>" + m_rootDescendents + "</integer>";
Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents");
Console.WriteLine(llsdresponse);
}
[Test]
public void Test_002_MultipleFolders()
{
TestHelpers.InMethod();
FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene);
string request = "<llsd><map><key>folders</key><array>";
request += "<map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>";
request += m_rootFolderID;
request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000001</uuid><key>sort_order</key><integer>1</integer></map>";
request += "<map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>";
request += m_notecardsFolder;
request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000001</uuid><key>sort_order</key><integer>1</integer></map>";
request += "</array></map></llsd>";
string llsdresponse = dorequest(handler, request);
Console.WriteLine(llsdresponse);
string descendents = "descendents</key><integer>" + m_rootDescendents + "</integer>";
Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for root folder");
descendents = "descendents</key><integer>2</integer>";
Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for Notecard folder");
Assert.That(llsdresponse.Contains("10000000-0000-0000-0000-000000000001"), Is.True, "Notecard 1 is missing from response");
Assert.That(llsdresponse.Contains("20000000-0000-0000-0000-000000000002"), Is.True, "Notecard 2 is missing from response");
}
[Test]
public void Test_003_Links()
{
TestHelpers.InMethod();
FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene);
string request = "<llsd><map><key>folders</key><array><map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>";
request += "f0000000-0000-0000-0000-00000000000f";
request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000001</uuid><key>sort_order</key><integer>1</integer></map></array></map></llsd>";
string llsdresponse = dorequest(handler, request);
Console.WriteLine(llsdresponse);
string descendents = "descendents</key><integer>2</integer>";
Assert.That(llsdresponse.Contains(descendents), Is.True, "Incorrect number of descendents for Test Folder");
// Make sure that the note card link is included
Assert.That(llsdresponse.Contains("Link to notecard"), Is.True, "Link to notecard is missing");
//Make sure the notecard item itself is included
Assert.That(llsdresponse.Contains("Test Notecard 2"), Is.True, "Notecard 2 item (the source) is missing");
// Make sure that the source item is before the link item
int pos1 = llsdresponse.IndexOf("Test Notecard 2");
int pos2 = llsdresponse.IndexOf("Link to notecard");
Assert.Less(pos1, pos2, "Source of link is after link");
// Make sure the folder link is included
Assert.That(llsdresponse.Contains("Link to Objects folder"), Is.True, "Link to Objects folder is missing");
/* contents of link folder are not supposed to be listed
// Make sure the objects inside the Objects folder are included
// Note: I'm not entirely sure this is needed, but that's what I found in the implementation
Assert.That(llsdresponse.Contains("Some Object"), Is.True, "Some Object item (contents of the source) is missing");
*/
// Make sure that the source item is before the link item
pos1 = llsdresponse.IndexOf("Some Object");
pos2 = llsdresponse.IndexOf("Link to Objects folder");
Assert.Less(pos1, pos2, "Contents of source of folder link is after folder link");
}
[Test]
public void Test_004_DuplicateFolders()
{
TestHelpers.InMethod();
FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene);
string request = "<llsd><map><key>folders</key><array>";
request += "<map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>";
request += m_rootFolderID;
request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000000</uuid><key>sort_order</key><integer>1</integer></map>";
request += "<map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>";
request += m_notecardsFolder;
request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000000</uuid><key>sort_order</key><integer>1</integer></map>";
request += "<map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>";
request += m_rootFolderID;
request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000000</uuid><key>sort_order</key><integer>1</integer></map>";
request += "<map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>";
request += m_notecardsFolder;
request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000000</uuid><key>sort_order</key><integer>1</integer></map>";
request += "</array></map></llsd>";
string llsdresponse = dorequest(handler, request);
Console.WriteLine(llsdresponse);
string root_folder = "<key>folder_id</key><uuid>" + m_rootFolderID + "</uuid>";
string notecards_folder = "<key>folder_id</key><uuid>" + m_notecardsFolder + "</uuid>";
Assert.That(llsdresponse.Contains(root_folder), "Missing root folder");
Assert.That(llsdresponse.Contains(notecards_folder), "Missing notecards folder");
int count = Regex.Matches(llsdresponse, root_folder).Count;
Assert.AreEqual(1, count, "More than 1 root folder in response");
count = Regex.Matches(llsdresponse, notecards_folder).Count;
Assert.AreEqual(2, count, "More than 1 notecards folder in response"); // Notecards will also be under root, so 2
}
[Test]
public void Test_005_FolderZero()
{
TestHelpers.InMethod();
Init();
FetchInvDescHandler handler = new FetchInvDescHandler(m_scene.InventoryService, null, m_scene);
string request = "<llsd><map><key>folders</key><array><map><key>fetch_folders</key><integer>1</integer><key>fetch_items</key><boolean>1</boolean><key>folder_id</key><uuid>";
request += UUID.Zero;
request += "</uuid><key>owner_id</key><uuid>00000000-0000-0000-0000-000000000000</uuid><key>sort_order</key><integer>1</integer></map></array></map></llsd>";
string llsdresponse = dorequest(handler, request);
Assert.That(llsdresponse != null, Is.True, "Incorrect null response");
Assert.That(llsdresponse != string.Empty, Is.True, "Incorrect empty response");
// we do return a answer now
//Assert.That(llsdresponse.Contains("bad_folders</key><array><uuid>00000000-0000-0000-0000-000000000000"), Is.True, "Folder Zero should be a bad folder");
Console.WriteLine(llsdresponse);
}
}
}

View File

@ -1,190 +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.Net;
using System.Reflection;
using log4net;
using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Services.Interfaces;
using Caps = OpenSim.Framework.Capabilities.Caps;
namespace OpenSim.Capabilities.Handlers
{
public class GetAssetsHandler
{
private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private static readonly Dictionary<string, AssetType> queryTypes = new Dictionary<string, AssetType>()
{
{"texture_id", AssetType.Texture},
{"sound_id", AssetType.Sound},
{"callcard_id", AssetType.CallingCard},
{"landmark_id", AssetType.Landmark},
{"script_id", AssetType.LSLText},
{"clothing_id", AssetType.Clothing},
{"object_id", AssetType.Object},
{"notecard_id", AssetType.Notecard},
{"lsltext_id", AssetType.LSLText},
{"lslbyte_id", AssetType.LSLBytecode},
{"txtr_tga_id", AssetType.TextureTGA},
{"bodypart_id", AssetType.Bodypart},
{"snd_wav_id", AssetType.SoundWAV},
{"img_tga_id", AssetType.ImageTGA},
{"jpeg_id", AssetType.ImageJPEG},
{"animatn_id", AssetType.Animation},
{"gesture_id", AssetType.Gesture},
{"mesh_id", AssetType.Mesh},
{"settings_id", AssetType.Settings}
};
private IAssetService m_assetService;
public GetAssetsHandler(IAssetService assService)
{
m_assetService = assService;
}
public void Handle(OSHttpRequest req, OSHttpResponse response)
{
response.ContentType = "text/plain";
if (m_assetService == null)
{
response.StatusCode = (int)HttpStatusCode.ServiceUnavailable;
response.KeepAlive = false;
return;
}
response.StatusCode = (int)HttpStatusCode.BadRequest;
var queries = req.QueryAsDictionary;
if(queries.Count == 0)
return;
AssetType type = AssetType.Unknown;
string assetStr = string.Empty;
foreach (KeyValuePair<string,string> kvp in queries)
{
if (queryTypes.ContainsKey(kvp.Key))
{
type = queryTypes[kvp.Key];
assetStr = kvp.Value;
break;
}
}
if(type == AssetType.Unknown)
{
//m_log.Warn("[GETASSET]: Unknown type: " + query);
m_log.Warn("[GETASSET]: Unknown type");
response.StatusCode = (int)HttpStatusCode.NotFound;
return;
}
if (String.IsNullOrEmpty(assetStr))
return;
UUID assetID = UUID.Zero;
if(!UUID.TryParse(assetStr, out assetID))
return;
AssetBase asset = m_assetService.Get(assetID.ToString());
if(asset == null)
{
// m_log.Warn("[GETASSET]: not found: " + query + " " + assetStr);
response.StatusCode = (int)HttpStatusCode.NotFound;
return;
}
if (asset.Type != (sbyte)type)
return;
int len = asset.Data.Length;
string range = null;
if (req.Headers["Range"] != null)
range = req.Headers["Range"];
else if (req.Headers["range"] != null)
range = req.Headers["range"];
// range request
int start, end;
if (Util.TryParseHttpRange(range, out start, out end))
{
// Before clamping start make sure we can satisfy it in order to avoid
// sending back the last byte instead of an error status
if (start >= asset.Data.Length)
{
response.StatusCode = (int)HttpStatusCode.RequestedRangeNotSatisfiable;
return;
}
if (end == -1)
end = asset.Data.Length - 1;
else
end = Utils.Clamp(end, 0, asset.Data.Length - 1);
start = Utils.Clamp(start, 0, end);
len = end - start + 1;
//m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, asset.Data.Length));
response.StatusCode = (int)HttpStatusCode.PartialContent;
response.RawBufferStart = start;
}
else
response.StatusCode = (int)HttpStatusCode.OK;
response.ContentType = asset.Metadata.ContentType;
response.RawBuffer = asset.Data;
response.RawBufferLen = len;
if (type == AssetType.Mesh || type == AssetType.Texture)
{
if(len > 8196)
{
//if(type == AssetType.Texture && ((asset.Flags & AssetFlags.AvatarBake)!= 0))
// responsedata["prio"] = 1;
//else
response.Priority = 2;
}
else
response.Priority = 1;
}
else
response.Priority = -1;
}
}
}

View File

@ -1,155 +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.Specialized;
using System.Reflection;
using System.IO;
using System.Web;
using log4net;
using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Services.Interfaces;
using Caps = OpenSim.Framework.Capabilities.Caps;
namespace OpenSim.Capabilities.Handlers
{
public class GetMeshHandler
{
private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IAssetService m_assetService;
public const string DefaultFormat = "vnd.ll.mesh";
public GetMeshHandler(IAssetService assService)
{
m_assetService = assService;
}
public Hashtable Handle(Hashtable request)
{
return ProcessGetMesh(request, UUID.Zero, null); ;
}
public Hashtable ProcessGetMesh(Hashtable request, UUID AgentId, Caps cap)
{
Hashtable responsedata = new Hashtable();
if (m_assetService == null)
{
responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.ServiceUnavailable;
responsedata["str_response_string"] = "The asset service is unavailable";
responsedata["keepalive"] = false;
return responsedata;
}
responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.BadRequest;
responsedata["content_type"] = "text/plain";
responsedata["int_bytes"] = 0;
string meshStr = string.Empty;
if (request.ContainsKey("mesh_id"))
meshStr = request["mesh_id"].ToString();
if (String.IsNullOrEmpty(meshStr))
return responsedata;
UUID meshID = UUID.Zero;
if(!UUID.TryParse(meshStr, out meshID))
return responsedata;
AssetBase mesh = m_assetService.Get(meshID.ToString());
if(mesh == null)
{
responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
responsedata["str_response_string"] = "Mesh not found.";
return responsedata;
}
if (mesh.Type != (SByte)AssetType.Mesh)
{
responsedata["str_response_string"] = "Asset isn't a mesh.";
return responsedata;
}
string range = String.Empty;
if (((Hashtable)request["headers"])["range"] != null)
range = (string)((Hashtable)request["headers"])["range"];
else if (((Hashtable)request["headers"])["Range"] != null)
range = (string)((Hashtable)request["headers"])["Range"];
responsedata["content_type"] = "application/vnd.ll.mesh";
if (String.IsNullOrEmpty(range))
{
// full mesh
responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data);
responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.OK;
return responsedata;
}
// range request
int start, end;
if (Util.TryParseHttpRange(range, out start, out end))
{
// Before clamping start make sure we can satisfy it in order to avoid
// sending back the last byte instead of an error status
if (start >= mesh.Data.Length)
{
responsedata["str_response_string"] = "This range doesnt exist.";
return responsedata;
}
end = Utils.Clamp(end, 0, mesh.Data.Length - 1);
start = Utils.Clamp(start, 0, end);
int len = end - start + 1;
//m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
Hashtable headers = new Hashtable();
headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end, mesh.Data.Length);
responsedata["headers"] = headers;
responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.PartialContent;
byte[] d = new byte[len];
Array.Copy(mesh.Data, start, d, 0, len);
responsedata["bin_response_data"] = d;
responsedata["int_bytes"] = len;
return responsedata;
}
m_log.Warn("[GETMESH]: Failed to parse a range from GetMesh request, sending full asset: " + (string)request["uri"]);
responsedata["str_response_string"] = Convert.ToBase64String(mesh.Data);
responsedata["int_response_code"] = (int)System.Net.HttpStatusCode.OK;
return responsedata;
}
}
}

View File

@ -1,78 +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 Nini.Config;
using OpenMetaverse;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Server.Base;
using OpenSim.Server.Handlers.Base;
using OpenSim.Services.Interfaces;
using System;
namespace OpenSim.Capabilities.Handlers
{
public class GetMeshServerConnector : ServiceConnector
{
private IAssetService m_AssetService;
private string m_ConfigName = "CapsService";
public GetMeshServerConnector(IConfigSource config, IHttpServer server, string configName) :
base(config, server, configName)
{
if (configName != String.Empty)
m_ConfigName = configName;
IConfig serverConfig = config.Configs[m_ConfigName];
if (serverConfig == null)
throw new Exception(String.Format("No section '{0}' in config file", m_ConfigName));
string assetService = serverConfig.GetString("AssetService", String.Empty);
if (assetService == String.Empty)
throw new Exception("No AssetService in config file");
Object[] args = new Object[] { config };
m_AssetService =
ServerUtils.LoadPlugin<IAssetService>(assetService, args);
if (m_AssetService == null)
throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName));
string rurl = serverConfig.GetString("GetMeshRedirectURL");
GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService);
IRequestHandler reqHandler
= new RestHTTPHandler(
"GET",
"/" + UUID.Random(),
httpMethod => gmeshHandler.ProcessGetMesh(httpMethod, UUID.Zero, null),
"GetMesh",
null);
server.AddStreamHandler(reqHandler); ;
}
}
}

View File

@ -1,365 +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.Specialized;
using System.Drawing;
using System.Drawing.Imaging;
using System.Reflection;
using System.IO;
using System.Web;
using log4net;
using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenMetaverse.Imaging;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Services.Interfaces;
using Caps = OpenSim.Framework.Capabilities.Caps;
namespace OpenSim.Capabilities.Handlers
{
public class GetTextureHandler
{
private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IAssetService m_assetService;
public const string DefaultFormat = "x-j2c";
public GetTextureHandler(IAssetService assService)
{
m_assetService = assService;
}
public Hashtable Handle(Hashtable request)
{
Hashtable ret = new Hashtable();
ret["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
ret["content_type"] = "text/plain";
ret["int_bytes"] = 0;
string textureStr = (string)request["texture_id"];
string format = (string)request["format"];
//m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr);
if (m_assetService == null)
{
m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service");
}
UUID textureID;
if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID))
{
// m_log.DebugFormat("[GETTEXTURE]: Received request for texture id {0}", textureID);
string[] formats;
if (!string.IsNullOrEmpty(format))
{
formats = new string[1] { format.ToLower() };
}
else
{
formats = new string[1] { DefaultFormat }; // default
if (((Hashtable)request["headers"])["Accept"] != null)
formats = WebUtil.GetPreferredImageTypes((string)((Hashtable)request["headers"])["Accept"]);
if (formats.Length == 0)
formats = new string[1] { DefaultFormat }; // default
}
// OK, we have an array with preferred formats, possibly with only one entry
bool foundtexture = false;
foreach (string f in formats)
{
foundtexture = FetchTexture(request, ret, textureID, f);
if (foundtexture)
break;
}
if (!foundtexture)
{
ret["int_response_code"] = 404;
ret["error_status_text"] = "not found";
ret["str_response_string"] = "not found";
ret["content_type"] = "text/plain";
ret["int_bytes"] = 0;
}
}
else
{
m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + (string)request["uri"]);
}
// m_log.DebugFormat(
// "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}",
// textureID, httpResponse.StatusCode, httpResponse.ContentLength);
return ret;
}
/// <summary>
///
/// </summary>
/// <param name="httpRequest"></param>
/// <param name="httpResponse"></param>
/// <param name="textureID"></param>
/// <param name="format"></param>
/// <returns>False for "caller try another codec"; true otherwise</returns>
private bool FetchTexture(Hashtable request, Hashtable response, UUID textureID, string format)
{
// m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format);
AssetBase texture;
string fullID = textureID.ToString();
if (format != DefaultFormat)
fullID = fullID + "-" + format;
// try the cache
texture = m_assetService.GetCached(fullID);
if (texture == null)
{
//m_log.DebugFormat("[GETTEXTURE]: texture was not in the cache");
// Fetch locally or remotely. Misses return a 404
texture = m_assetService.Get(textureID.ToString());
if (texture != null)
{
if (texture.Type != (sbyte)AssetType.Texture)
return true;
if (format == DefaultFormat)
{
WriteTextureData(request, response, texture, format);
return true;
}
else
{
AssetBase newTexture = new AssetBase(texture.ID + "-" + format, texture.Name, (sbyte)AssetType.Texture, texture.Metadata.CreatorID);
newTexture.Data = ConvertTextureData(texture, format);
if (newTexture.Data.Length == 0)
return false; // !!! Caller try another codec, please!
newTexture.Flags = AssetFlags.Collectable;
newTexture.Temporary = true;
newTexture.Local = true;
m_assetService.Store(newTexture);
WriteTextureData(request, response, newTexture, format);
return true;
}
}
}
else // it was on the cache
{
//m_log.DebugFormat("[GETTEXTURE]: texture was in the cache");
WriteTextureData(request, response, texture, format);
return true;
}
//response = new Hashtable();
//WriteTextureData(request,response,null,format);
// not found
//m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found");
return false;
}
private void WriteTextureData(Hashtable request, Hashtable response, AssetBase texture, string format)
{
Hashtable headers = new Hashtable();
response["headers"] = headers;
string range = String.Empty;
if (((Hashtable)request["headers"])["range"] != null)
range = (string)((Hashtable)request["headers"])["range"];
else if (((Hashtable)request["headers"])["Range"] != null)
range = (string)((Hashtable)request["headers"])["Range"];
if (!String.IsNullOrEmpty(range)) // JP2's only
{
// Range request
int start, end;
if (Util.TryParseHttpRange(range, out start, out end))
{
// Before clamping start make sure we can satisfy it in order to avoid
// sending back the last byte instead of an error status
if (start >= texture.Data.Length)
{
// m_log.DebugFormat(
// "[GETTEXTURE]: Client requested range for texture {0} starting at {1} but texture has end of {2}",
// texture.ID, start, texture.Data.Length);
// Stricly speaking, as per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, we should be sending back
// Requested Range Not Satisfiable (416) here. However, it appears that at least recent implementations
// of the Linden Lab viewer (3.2.1 and 3.3.4 and probably earlier), a viewer that has previously
// received a very small texture may attempt to fetch bytes from the server past the
// range of data that it received originally. Whether this happens appears to depend on whether
// the viewer's estimation of how large a request it needs to make for certain discard levels
// (http://wiki.secondlife.com/wiki/Image_System#Discard_Level_and_Mip_Mapping), chiefly discard
// level 2. If this estimate is greater than the total texture size, returning a RequestedRangeNotSatisfiable
// here will cause the viewer to treat the texture as bad and never display the full resolution
// However, if we return PartialContent (or OK) instead, the viewer will display that resolution.
// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable;
// viewers don't seem to handle RequestedRangeNotSatisfiable and keep retrying with same parameters
response["int_response_code"] = (int)System.Net.HttpStatusCode.NotFound;
}
else
{
// Handle the case where no second range value was given. This is equivalent to requesting
// the rest of the entity.
if (end == -1)
end = int.MaxValue;
end = Utils.Clamp(end, 0, texture.Data.Length - 1);
start = Utils.Clamp(start, 0, end);
int len = end - start + 1;
// m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
response["content-type"] = texture.Metadata.ContentType;
response["int_response_code"] = (int)System.Net.HttpStatusCode.PartialContent;
headers["Content-Range"] = String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length);
byte[] d = new byte[len];
Array.Copy(texture.Data, start, d, 0, len);
response["bin_response_data"] = d;
response["int_bytes"] = len;
}
}
else
{
m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range);
response["int_response_code"] = (int)System.Net.HttpStatusCode.BadRequest;
}
}
else // JP2's or other formats
{
// Full content request
response["int_response_code"] = (int)System.Net.HttpStatusCode.OK;
if (format == DefaultFormat)
response["content_type"] = texture.Metadata.ContentType;
else
response["content_type"] = "image/" + format;
response["bin_response_data"] = texture.Data;
response["int_bytes"] = texture.Data.Length;
// response.Body.Write(texture.Data, 0, texture.Data.Length);
}
// if (response.StatusCode < 200 || response.StatusCode > 299)
// m_log.WarnFormat(
// "[GETTEXTURE]: For texture {0} requested range {1} responded {2} with content length {3} (actual {4})",
// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length);
// else
// m_log.DebugFormat(
// "[GETTEXTURE]: For texture {0} requested range {1} responded {2} with content length {3} (actual {4})",
// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length);
}
private byte[] ConvertTextureData(AssetBase texture, string format)
{
m_log.DebugFormat("[GETTEXTURE]: Converting texture {0} to {1}", texture.ID, format);
byte[] data = new byte[0];
MemoryStream imgstream = new MemoryStream();
Bitmap mTexture = null;
ManagedImage managedImage = null;
Image image = null;
try
{
// Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular data
// Decode image to System.Drawing.Image
if (OpenJPEG.DecodeToImage(texture.Data, out managedImage, out image) && image != null)
{
// Save to bitmap
mTexture = new Bitmap(image);
using(EncoderParameters myEncoderParameters = new EncoderParameters())
{
myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,95L);
// Save bitmap to stream
ImageCodecInfo codec = GetEncoderInfo("image/" + format);
if (codec != null)
{
mTexture.Save(imgstream, codec, myEncoderParameters);
// Write the stream to a byte array for output
data = imgstream.ToArray();
}
else
m_log.WarnFormat("[GETTEXTURE]: No such codec {0}", format);
}
}
}
catch (Exception e)
{
m_log.WarnFormat("[GETTEXTURE]: Unable to convert texture {0} to {1}: {2}", texture.ID, format, e.Message);
}
finally
{
// Reclaim memory, these are unmanaged resources
// If we encountered an exception, one or more of these will be null
if (mTexture != null)
mTexture.Dispose();
if (image != null)
image.Dispose();
if(managedImage != null)
managedImage.Clear();
if (imgstream != null)
imgstream.Dispose();
}
return data;
}
// From msdn
private static ImageCodecInfo GetEncoderInfo(String mimeType)
{
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for (int j = 0; j < encoders.Length; ++j)
{
if (encoders[j].MimeType == mimeType)
return encoders[j];
}
return null;
}
}
}

View File

@ -1,394 +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.Specialized;
using System.Drawing;
using System.Drawing.Imaging;
using System.Reflection;
using System.IO;
using System.Net;
using System.Web;
using log4net;
using Nini.Config;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
using OpenMetaverse.Imaging;
using OpenSim.Framework;
using OpenSim.Framework.Servers;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Services.Interfaces;
using Caps = OpenSim.Framework.Capabilities.Caps;
namespace OpenSim.Capabilities.Handlers
{
public class GetTextureRobustHandler : BaseStreamHandler
{
private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private IAssetService m_assetService;
public const string DefaultFormat = "x-j2c";
// TODO: Change this to a config option
private string m_RedirectURL = null;
public GetTextureRobustHandler(string path, IAssetService assService, string name, string description, string redirectURL)
: base("GET", path, name, description)
{
m_assetService = assService;
m_RedirectURL = redirectURL;
if (m_RedirectURL != null && !m_RedirectURL.EndsWith("/"))
m_RedirectURL += "/";
}
protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
{
// Try to parse the texture ID from the request URL
NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query);
string textureStr = query.GetOne("texture_id");
string format = query.GetOne("format");
//m_log.DebugFormat("[GETTEXTURE]: called {0}", textureStr);
if (m_assetService == null)
{
m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service");
httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
return null;
}
UUID textureID;
if (!String.IsNullOrEmpty(textureStr) && UUID.TryParse(textureStr, out textureID))
{
// m_log.DebugFormat("[GETTEXTURE]: Received request for texture id {0}", textureID);
string[] formats;
if (!string.IsNullOrEmpty(format))
{
formats = new string[1] { format.ToLower() };
}
else
{
formats = WebUtil.GetPreferredImageTypes(httpRequest.Headers.Get("Accept"));
if (formats.Length == 0)
formats = new string[1] { DefaultFormat }; // default
}
// OK, we have an array with preferred formats, possibly with only one entry
httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
foreach (string f in formats)
{
if (FetchTexture(httpRequest, httpResponse, textureID, f))
break;
}
}
else
{
m_log.Warn("[GETTEXTURE]: Failed to parse a texture_id from GetTexture request: " + httpRequest.Url);
}
// m_log.DebugFormat(
// "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}",
// textureID, httpResponse.StatusCode, httpResponse.ContentLength);
return null;
}
/// <summary>
///
/// </summary>
/// <param name="httpRequest"></param>
/// <param name="httpResponse"></param>
/// <param name="textureID"></param>
/// <param name="format"></param>
/// <returns>False for "caller try another codec"; true otherwise</returns>
private bool FetchTexture(IOSHttpRequest httpRequest, IOSHttpResponse httpResponse, UUID textureID, string format)
{
// m_log.DebugFormat("[GETTEXTURE]: {0} with requested format {1}", textureID, format);
if(!String.IsNullOrEmpty(m_RedirectURL))
{
string textureUrl = m_RedirectURL + "?texture_id=" + textureID.ToString();
m_log.Debug("[GETTEXTURE]: Redirecting texture request to " + textureUrl);
httpResponse.StatusCode = (int)HttpStatusCode.Moved;
httpResponse.AddHeader("Location:", textureUrl);
return true;
}
// Fetch, Misses or invalid return a 404
AssetBase texture = m_assetService.Get(textureID.ToString());
if (texture != null)
{
if (texture.Type != (sbyte)AssetType.Texture)
{
httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
return true;
}
if (format == DefaultFormat)
{
WriteTextureData(httpRequest, httpResponse, texture, format);
return true;
}
// need to convert format
AssetBase newTexture = new AssetBase(texture.ID + "-" + format, texture.Name, (sbyte)AssetType.Texture, texture.Metadata.CreatorID);
newTexture.Data = ConvertTextureData(texture, format);
if (newTexture.Data.Length == 0)
return false; // !!! Caller try another codec, please!
newTexture.Flags = AssetFlags.Collectable;
newTexture.Temporary = true;
newTexture.Local = true;
WriteTextureData(httpRequest, httpResponse, newTexture, format);
return true;
}
// not found
// m_log.Warn("[GETTEXTURE]: Texture " + textureID + " not found");
httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
return true;
}
private void WriteTextureData(IOSHttpRequest request, IOSHttpResponse response, AssetBase texture, string format)
{
string range = request.Headers.GetOne("Range");
if (!String.IsNullOrEmpty(range)) // JP2's only
{
// Range request
int start, end;
if (TryParseRange(range, out start, out end))
{
// Before clamping start make sure we can satisfy it in order to avoid
// sending back the last byte instead of an error status
if (start >= texture.Data.Length)
{
// m_log.DebugFormat(
// "[GETTEXTURE]: Client requested range for texture {0} starting at {1} but texture has end of {2}",
// texture.ID, start, texture.Data.Length);
// Stricly speaking, as per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html, we should be sending back
// Requested Range Not Satisfiable (416) here. However, it appears that at least recent implementations
// of the Linden Lab viewer (3.2.1 and 3.3.4 and probably earlier), a viewer that has previously
// received a very small texture may attempt to fetch bytes from the server past the
// range of data that it received originally. Whether this happens appears to depend on whether
// the viewer's estimation of how large a request it needs to make for certain discard levels
// (http://wiki.secondlife.com/wiki/Image_System#Discard_Level_and_Mip_Mapping), chiefly discard
// level 2. If this estimate is greater than the total texture size, returning a RequestedRangeNotSatisfiable
// here will cause the viewer to treat the texture as bad and never display the full resolution
// However, if we return PartialContent (or OK) instead, the viewer will display that resolution.
// response.StatusCode = (int)System.Net.HttpStatusCode.RequestedRangeNotSatisfiable;
// response.AddHeader("Content-Range", String.Format("bytes */{0}", texture.Data.Length));
// response.StatusCode = (int)System.Net.HttpStatusCode.OK;
response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
response.ContentType = texture.Metadata.ContentType;
}
else
{
// Handle the case where no second range value was given. This is equivalent to requesting
// the rest of the entity.
if (end == -1)
end = int.MaxValue;
end = Utils.Clamp(end, 0, texture.Data.Length - 1);
start = Utils.Clamp(start, 0, end);
int len = end - start + 1;
// m_log.Debug("Serving " + start + " to " + end + " of " + texture.Data.Length + " bytes for texture " + texture.ID);
// Always return PartialContent, even if the range covered the entire data length
// We were accidentally sending back 404 before in this situation
// https://issues.apache.org/bugzilla/show_bug.cgi?id=51878 supports sending 206 even if the
// entire range is requested, and viewer 3.2.2 (and very probably earlier) seems fine with this.
//
// We also do not want to send back OK even if the whole range was satisfiable since this causes
// HTTP textures on at least Imprudence 1.4.0-beta2 to never display the final texture quality.
// if (end > maxEnd)
// response.StatusCode = (int)System.Net.HttpStatusCode.OK;
// else
response.StatusCode = (int)System.Net.HttpStatusCode.PartialContent;
response.ContentLength = len;
response.ContentType = texture.Metadata.ContentType;
response.AddHeader("Content-Range", String.Format("bytes {0}-{1}/{2}", start, end, texture.Data.Length));
response.RawBuffer = texture.Data;
response.RawBufferStart = start;
response.RawBufferLen = len;
}
}
else
{
m_log.Warn("[GETTEXTURE]: Malformed Range header: " + range);
response.StatusCode = (int)System.Net.HttpStatusCode.BadRequest;
}
}
else // JP2's or other formats
{
// Full content request
response.StatusCode = (int)System.Net.HttpStatusCode.OK;
response.ContentLength = texture.Data.Length;
if (format == DefaultFormat)
response.ContentType = texture.Metadata.ContentType;
else
response.ContentType = "image/" + format;
response.RawBuffer = texture.Data;
response.RawBufferStart = 0;
response.RawBufferLen = texture.Data.Length;
}
// if (response.StatusCode < 200 || response.StatusCode > 299)
// m_log.WarnFormat(
// "[GETTEXTURE]: For texture {0} requested range {1} responded {2} with content length {3} (actual {4})",
// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length);
// else
// m_log.DebugFormat(
// "[GETTEXTURE]: For texture {0} requested range {1} responded {2} with content length {3} (actual {4})",
// texture.FullID, range, response.StatusCode, response.ContentLength, texture.Data.Length);
}
/// <summary>
/// Parse a range header.
/// </summary>
/// <remarks>
/// As per http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html,
/// this obeys range headers with two values (e.g. 533-4165) and no second value (e.g. 533-).
/// Where there is no value, -1 is returned.
/// FIXME: Need to cover the case where only a second value is specified (e.g. -4165), probably by returning -1
/// for start.</remarks>
/// <returns></returns>
/// <param name='header'></param>
/// <param name='start'>Start of the range. Undefined if this was not a number.</param>
/// <param name='end'>End of the range. Will be -1 if no end specified. Undefined if there was a raw string but this was not a number.</param>
private bool TryParseRange(string header, out int start, out int end)
{
start = end = 0;
if (header.StartsWith("bytes="))
{
string[] rangeValues = header.Substring(6).Split('-');
if (rangeValues.Length == 2)
{
if (!Int32.TryParse(rangeValues[0], out start))
return false;
string rawEnd = rangeValues[1];
if (rawEnd == "")
{
end = -1;
return true;
}
else if (Int32.TryParse(rawEnd, out end))
{
return true;
}
}
}
start = end = 0;
return false;
}
private byte[] ConvertTextureData(AssetBase texture, string format)
{
m_log.DebugFormat("[GETTEXTURE]: Converting texture {0} to {1}", texture.ID, format);
byte[] data = new byte[0];
MemoryStream imgstream = new MemoryStream();
Bitmap mTexture = null;
ManagedImage managedImage = null;
Image image = null;
try
{
// Taking our jpeg2000 data, decoding it, then saving it to a byte array with regular data
// Decode image to System.Drawing.Image
if (OpenJPEG.DecodeToImage(texture.Data, out managedImage, out image) && image != null)
{
// Save to bitmap
mTexture = new Bitmap(image);
using(EncoderParameters myEncoderParameters = new EncoderParameters())
{
myEncoderParameters.Param[0] = new EncoderParameter(Encoder.Quality,95L);
// Save bitmap to stream
ImageCodecInfo codec = GetEncoderInfo("image/" + format);
if (codec != null)
{
mTexture.Save(imgstream, codec, myEncoderParameters);
// Write the stream to a byte array for output
data = imgstream.ToArray();
}
else
m_log.WarnFormat("[GETTEXTURE]: No such codec {0}", format);
}
}
}
catch (Exception e)
{
m_log.WarnFormat("[GETTEXTURE]: Unable to convert texture {0} to {1}: {2}", texture.ID, format, e.Message);
}
finally
{
// Reclaim memory, these are unmanaged resources
// If we encountered an exception, one or more of these will be null
if (mTexture != null)
mTexture.Dispose();
if (image != null)
image.Dispose();
if(managedImage != null)
managedImage.Clear();
if (imgstream != null)
imgstream.Dispose();
}
return data;
}
// From msdn
private static ImageCodecInfo GetEncoderInfo(String mimeType)
{
ImageCodecInfo[] encoders;
encoders = ImageCodecInfo.GetImageEncoders();
for (int j = 0; j < encoders.Length; ++j)
{
if (encoders[j].MimeType == mimeType)
return encoders[j];
}
return null;
}
}
}

View File

@ -1,73 +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 Nini.Config;
using OpenSim.Server.Base;
using OpenSim.Services.Interfaces;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Server.Handlers.Base;
using OpenMetaverse;
namespace OpenSim.Capabilities.Handlers
{
public class GetTextureServerConnector : ServiceConnector
{
private IAssetService m_AssetService;
private string m_ConfigName = "CapsService";
public GetTextureServerConnector(IConfigSource config, IHttpServer server, string configName) :
base(config, server, configName)
{
if (configName != String.Empty)
m_ConfigName = configName;
IConfig serverConfig = config.Configs[m_ConfigName];
if (serverConfig == null)
throw new Exception(String.Format("No section '{0}' in config file", m_ConfigName));
string assetService = serverConfig.GetString("AssetService", String.Empty);
if (assetService == String.Empty)
throw new Exception("No AssetService in config file");
Object[] args = new Object[] { config };
m_AssetService =
ServerUtils.LoadPlugin<IAssetService>(assetService, args);
if (m_AssetService == null)
throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName));
string rurl = serverConfig.GetString("GetTextureRedirectURL");
;
server.AddStreamHandler(
new GetTextureRobustHandler("/CAPS/GetTexture", m_AssetService, "GetTexture", null, rurl));
}
}
}

View File

@ -1,64 +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.Net;
using log4net;
using log4net.Config;
using NUnit.Framework;
using OpenMetaverse;
using OpenSim.Capabilities.Handlers;
using OpenSim.Framework;
using OpenSim.Framework.Servers.HttpServer;
using OpenSim.Region.Framework.Scenes;
using OpenSim.Tests.Common;
/*
namespace OpenSim.Capabilities.Handlers.GetTexture.Tests
{
[TestFixture]
public class GetTextureHandlerTests : OpenSimTestCase
{
[Test]
public void TestTextureNotFound()
{
TestHelpers.InMethod();
// Overkill - we only really need the asset service, not a whole scene.
Scene scene = new SceneHelpers().SetupScene();
GetTextureHandler handler = new GetTextureHandler("/gettexture", scene.AssetService, "TestGetTexture", null, null);
TestOSHttpRequest req = new TestOSHttpRequest();
TestOSHttpResponse resp = new TestOSHttpResponse();
req.Url = new Uri("http://localhost/?texture_id=00000000-0000-1111-9999-000000000012");
handler.Handle(null, null, req, resp);
Assert.That(resp.StatusCode, Is.EqualTo((int)System.Net.HttpStatusCode.NotFound));
}
}
}
*/

View File

@ -1,33 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("OpenSim.Capabilities.Handlers")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("http://opensimulator.org")]
[assembly: AssemblyProduct("OpenSim")]
[assembly: AssemblyCopyright("OpenSimulator developers")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("32350823-e1df-45e3-b7fa-0a58b4372433")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)]

View File

@ -1,87 +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;
namespace OpenSim.Framework.Capabilities
{
[OSDMap]
public class LLSDAssetUploadError
{
public string message = String.Empty;
public UUID identifier = UUID.Zero;
}
[OSDMap]
public class LLSDAssetUploadResponsePricebrkDown
{
public int mesh_streaming;
public int mesh_physics;
public int mesh_instance;
public int texture;
public int model;
}
[OSDMap]
public class LLSDAssetUploadResponseData
{
public double resource_cost;
public double model_streaming_cost;
public double simulation_cost;
public double physics_cost;
public LLSDAssetUploadResponsePricebrkDown upload_price_breakdown = new LLSDAssetUploadResponsePricebrkDown();
}
[OSDMap]
public class LLSDAssetUploadResponse
{
public string uploader = String.Empty;
public string state = String.Empty;
public int upload_price = 0;
public LLSDAssetUploadResponseData data = null;
public LLSDAssetUploadError error = null;
public LLSDAssetUploadResponse()
{
}
}
[OSDMap]
public class LLSDNewFileAngentInventoryVariablePriceReplyResponse
{
public int resource_cost;
public string state;
public int upload_price;
public string rsvp;
public LLSDNewFileAngentInventoryVariablePriceReplyResponse()
{
state = "confirm_upload";
}
}
}

View File

@ -1,51 +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 OpenMetaverse;
namespace OpenSim.Framework.Capabilities
{
[OSDMap]
public class LLSDAvatarPicker
{
public string next_page_url;
// an array of LLSDPerson
public OSDArray agents = new OSDArray();
}
[OSDMap]
public class LLSDPerson
{
public string username;
public string display_name;
//'display_name_next_update':d"1970-01-01T00:00:00Z"
public string legacy_first_name;
public string legacy_last_name;
public UUID id;
public bool is_display_name_default;
}
}

View File

@ -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 System.Collections;
using System.IO;
using System.Reflection;
using System.Xml;
using OpenMetaverse;
namespace OpenSim.Framework.Capabilities
{
public class LLSDHelpers
{
// private static readonly log4net.ILog m_log
// = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
public static string SerialiseLLSDReply(object obj)
{
using(StringWriter sw = new StringWriter())
using(XmlTextWriter writer = new XmlTextWriter(sw))
{
writer.Formatting = Formatting.None;
writer.WriteStartElement(String.Empty, "llsd", String.Empty);
SerializeOSDType(writer, obj);
writer.WriteEndElement();
writer.Flush();
//m_log.DebugFormat("[LLSD Helpers]: Generated serialized LLSD reply {0}", sw.ToString());
return sw.ToString();
}
}
public static string SerialiseLLSDReplyNoHeader(object obj)
{
using(StringWriter sw = new StringWriter())
using(XmlTextWriter writer = new XmlTextWriter(sw))
{
writer.Formatting = Formatting.None;
SerializeOSDType(writer, obj);
writer.Flush();
//m_log.DebugFormat("[LLSD Helpers]: Generated serialized LLSD reply {0}", sw.ToString());
return sw.ToString();
}
}
private static void SerializeOSDType(XmlTextWriter writer, object obj)
{
Type myType = obj.GetType();
LLSDType[] llsdattributes = (LLSDType[]) myType.GetCustomAttributes(typeof (LLSDType), false);
if (llsdattributes.Length > 0)
{
switch (llsdattributes[0].ObjectType)
{
case "MAP":
writer.WriteStartElement(String.Empty, "map", String.Empty);
FieldInfo[] fields = myType.GetFields();
for (int i = 0; i < fields.Length; i++)
{
if (fields[i] != null && fields[i].GetValue(obj) != null)
{
object fieldValue = fields[i].GetValue(obj);
LLSDType[] fieldAttributes =
(LLSDType[]) fieldValue.GetType().GetCustomAttributes(typeof (LLSDType), false);
if (fieldAttributes.Length > 0)
{
writer.WriteStartElement(String.Empty, "key", String.Empty);
string fieldName = fields[i].Name;
fieldName = fieldName.Replace("___", "-");
writer.WriteString(fieldName);
writer.WriteEndElement();
SerializeOSDType(writer, fieldValue);
}
else
{
writer.WriteStartElement(String.Empty, "key", String.Empty);
string fieldName = fields[i].Name;
fieldName = fieldName.Replace("___", "-");
writer.WriteString(fieldName);
writer.WriteEndElement();
LLSD.LLSDWriteOne(writer, fieldValue);
// OpenMetaverse.StructuredData.LLSDParser.SerializeXmlElement(
// writer, OpenMetaverse.StructuredData.OSD.FromObject(fieldValue));
}
}
else
{
// TODO from ADAM: There is a nullref being caused by fields[i] being null
// on some computers. Unsure what is causing this, but would appreciate
// if sdague could take a look at this.
}
}
writer.WriteEndElement();
break;
case "ARRAY":
// OSDArray arrayObject = obj as OSDArray;
// ArrayList a = arrayObject.Array;
ArrayList a = (ArrayList) obj.GetType().GetField("Array").GetValue(obj);
if (a != null)
{
writer.WriteStartElement(String.Empty, "array", String.Empty);
foreach (object item in a)
{
SerializeOSDType(writer, item);
}
writer.WriteEndElement();
}
break;
}
}
else
{
LLSD.LLSDWriteOne(writer, obj);
//OpenMetaverse.StructuredData.LLSDParser.SerializeXmlElement(
// writer, OpenMetaverse.StructuredData.OSD.FromObject(obj));
}
}
public static object DeserialiseOSDMap(Hashtable llsd, object obj)
{
Type myType = obj.GetType();
LLSDType[] llsdattributes = (LLSDType[]) myType.GetCustomAttributes(typeof (LLSDType), false);
if (llsdattributes.Length > 0)
{
switch (llsdattributes[0].ObjectType)
{
case "MAP":
IDictionaryEnumerator enumerator = llsd.GetEnumerator();
while (enumerator.MoveNext())
{
string keyName = (string)enumerator.Key;
keyName = keyName.Replace("-","_");
FieldInfo field = myType.GetField(keyName);
if (field != null)
{
// if (enumerator.Value is OpenMetaverse.StructuredData.OSDMap)
if (enumerator.Value is Hashtable)
{
object fieldValue = field.GetValue(obj);
DeserialiseOSDMap((Hashtable) enumerator.Value, fieldValue);
// DeserialiseOSDMap((OpenMetaverse.StructuredData.OSDMap) enumerator.Value, fieldValue);
}
else if (enumerator.Value is ArrayList)
{
object fieldValue = field.GetValue(obj);
fieldValue.GetType().GetField("Array").SetValue(fieldValue, enumerator.Value);
//TODO
// the LLSD map/array types in the array need to be deserialised
// but first we need to know the right class to deserialise them into.
}
else if(enumerator.Value is Boolean && field.FieldType == typeof(int) )
{
int i = (bool)enumerator.Value ? 1 : 0;
field.SetValue(obj, i);
}
else if(field.FieldType == typeof(bool) && enumerator.Value is int)
{
bool b = (int)enumerator.Value != 0;
field.SetValue(obj, b);
}
else if(field.FieldType == typeof(UUID) && enumerator.Value is string)
{
UUID u;
UUID.TryParse((string)enumerator.Value, out u);
field.SetValue(obj, u);
}
else
{
field.SetValue(obj, enumerator.Value);
}
}
}
break;
}
}
return obj;
}
}
}

View File

@ -1,42 +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 OpenMetaverse;
namespace OpenSim.Framework.Capabilities
{
[OSDMap]
public class LLSDInventoryFolder
{
public UUID folder_id;
public UUID parent_id;
public string name;
public int type;
public int preferred_type;
public int version;
}
}

View File

@ -1,31 +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.Framework.Capabilities
{
public delegate TResponse LLSDMethod<TRequest, TResponse>(TRequest request);
}

View File

@ -1,31 +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.Framework.Capabilities
{
public delegate TResponse LLSDMethodString<TRequest, TResponse>(TRequest request, string path);
}

View File

@ -1,54 +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 OpenMetaverse;
using System;
using System.Collections;
namespace OpenSim.Framework.Capabilities
{
[OSDMap]
public class LLSDTaskScriptUploadComplete
{
/// <summary>
/// The task inventory item that was updated
/// </summary>
public UUID new_asset;
/// <summary>
/// Was it compiled?
/// </summary>
public bool compiled;
/// <summary>
/// State of the upload. So far have only even seen this set to "complete"
/// </summary>
public string state;
public OSDArray errors;
}
}

View File

@ -1,33 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("OpenSim.Capabilities")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("http://opensimulator.org")]
[assembly: AssemblyProduct("OpenSim")]
[assembly: AssemblyCopyright("OpenSimulator developers")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("7d1a55b1-8fab-42ff-9c83-066a9cc34d76")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion("0.7.6.*")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -1,225 +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 Nini.Config;
using log4net;
using System.Reflection;
using System;
using System.IO;
using System.Xml;
using System.Collections.Generic;
using OpenSim.Server.Base;
using OpenSim.Framework;
using OpenSim.Framework.Console;
using OpenMetaverse;
namespace OpenSim.ConsoleClient
{
public class OpenSimConsoleClient
{
protected static ServicesServerBase m_Server = null;
private static string m_Host;
private static int m_Port;
private static string m_User;
private static string m_Pass;
private static UUID m_SessionID;
static int Main(string[] args)
{
m_Server = new ServicesServerBase("Client", args);
IConfig serverConfig = m_Server.Config.Configs["Startup"];
if (serverConfig == null)
{
System.Console.WriteLine("Startup config section missing in .ini file");
throw new Exception("Configuration error");
}
ArgvConfigSource argvConfig = new ArgvConfigSource(args);
argvConfig.AddSwitch("Startup", "host", "h");
argvConfig.AddSwitch("Startup", "port", "p");
argvConfig.AddSwitch("Startup", "user", "u");
argvConfig.AddSwitch("Startup", "pass", "P");
m_Server.Config.Merge(argvConfig);
m_User = serverConfig.GetString("user", "Test");
m_Host = serverConfig.GetString("host", "localhost");
m_Port = serverConfig.GetInt("port", 8003);
m_Pass = serverConfig.GetString("pass", "secret");
Requester.MakeRequest("http://"+m_Host+":"+m_Port.ToString()+"/StartSession/", String.Format("USER={0}&PASS={1}", m_User, m_Pass), LoginReply);
string pidFile = serverConfig.GetString("PIDFile", String.Empty);
while (m_Server.Running)
{
System.Threading.Thread.Sleep(500);
MainConsole.Instance.Prompt();
}
if (pidFile != String.Empty)
File.Delete(pidFile);
Environment.Exit(0);
return 0;
}
private static void SendCommand(string module, string[] cmd)
{
string sendCmd = "";
string[] cmdlist = new string[cmd.Length - 1];
sendCmd = cmd[0];
if (cmd.Length > 1)
{
Array.Copy(cmd, 1, cmdlist, 0, cmd.Length - 1);
sendCmd += " \"" + String.Join("\" \"", cmdlist) + "\"";
}
Requester.MakeRequest("http://"+m_Host+":"+m_Port.ToString()+"/SessionCommand/", String.Format("ID={0}&COMMAND={1}", m_SessionID, sendCmd), CommandReply);
}
public static void LoginReply(string requestUrl, string requestData, string replyData)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(replyData);
XmlNodeList rootL = doc.GetElementsByTagName("ConsoleSession");
if (rootL.Count != 1)
{
MainConsole.Instance.Output("Connection data info was not valid");
Environment.Exit(1);
}
XmlElement rootNode = (XmlElement)rootL[0];
if (rootNode == null)
{
MainConsole.Instance.Output("Connection data info was not valid");
Environment.Exit(1);
}
XmlNodeList helpNodeL = rootNode.GetElementsByTagName("HelpTree");
if (helpNodeL.Count != 1)
{
MainConsole.Instance.Output("Connection data info was not valid");
Environment.Exit(1);
}
XmlElement helpNode = (XmlElement)helpNodeL[0];
if (helpNode == null)
{
MainConsole.Instance.Output("Connection data info was not valid");
Environment.Exit(1);
}
XmlNodeList sessionL = rootNode.GetElementsByTagName("SessionID");
if (sessionL.Count != 1)
{
MainConsole.Instance.Output("Connection data info was not valid");
Environment.Exit(1);
}
XmlElement sessionNode = (XmlElement)sessionL[0];
if (sessionNode == null)
{
MainConsole.Instance.Output("Connection data info was not valid");
Environment.Exit(1);
}
if (!UUID.TryParse(sessionNode.InnerText, out m_SessionID))
{
MainConsole.Instance.Output("Connection data info was not valid");
Environment.Exit(1);
}
MainConsole.Instance.Commands.FromXml(helpNode, SendCommand);
Requester.MakeRequest("http://"+m_Host+":"+m_Port.ToString()+"/ReadResponses/"+m_SessionID.ToString()+"/", String.Empty, ReadResponses);
}
public static void ReadResponses(string requestUrl, string requestData, string replyData)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(replyData);
XmlNodeList rootNodeL = doc.GetElementsByTagName("ConsoleSession");
if (rootNodeL.Count != 1 || rootNodeL[0] == null)
{
Requester.MakeRequest(requestUrl, requestData, ReadResponses);
return;
}
List<string> lines = new List<string>();
foreach (XmlNode part in rootNodeL[0].ChildNodes)
{
if (part.Name != "Line")
continue;
lines.Add(part.InnerText);
}
// Cut down scrollback to 100 lines (4 screens)
// for the command line client
//
while (lines.Count > 100)
lines.RemoveAt(0);
string prompt = String.Empty;
foreach (string l in lines)
{
string[] parts = l.Split(new char[] {':'}, 3);
if (parts.Length != 3)
continue;
if (parts[2].StartsWith("+++") || parts[2].StartsWith("-++"))
prompt = parts[2];
else
MainConsole.Instance.Output(parts[2].Trim(), parts[1]);
}
Requester.MakeRequest(requestUrl, requestData, ReadResponses);
if (prompt.StartsWith("+++"))
MainConsole.Instance.ReadLine(prompt.Substring(3), true, true);
else if (prompt.StartsWith("-++"))
SendCommand(String.Empty, new string[] { MainConsole.Instance.ReadLine(prompt.Substring(3), false, true) });
}
public static void CommandReply(string requestUrl, string requestData, string replyData)
{
}
}
}

View File

@ -1,33 +0,0 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("OpenSim.ConsoleClient")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("http://opensimulator.org")]
[assembly: AssemblyProduct("OpenSim")]
[assembly: AssemblyCopyright("OpenSimulator developers")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("8945df94-2e5e-475b-88fa-35a7cdde6fd7")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
[assembly: AssemblyVersion("0.7.6.*")]
[assembly: AssemblyFileVersion("1.0.0.0")]

View File

@ -1,85 +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.Net;
using System.Reflection;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using log4net;
namespace OpenSim.ConsoleClient
{
public delegate void ReplyDelegate(string requestUrl, string requestData, string replyData);
public class Requester
{
public static void MakeRequest(string requestUrl, string data,
ReplyDelegate action)
{
WebRequest request = WebRequest.Create(requestUrl);
request.Method = "POST";
request.ContentType = "application/x-www-form-urlencoded";
byte[] buffer = Encoding.ASCII.GetBytes(data);
int length = (int) buffer.Length;
request.ContentLength = length;
request.BeginGetRequestStream(delegate(IAsyncResult res)
{
Stream requestStream = request.EndGetRequestStream(res);
requestStream.Write(buffer, 0, length);
request.BeginGetResponse(delegate(IAsyncResult ar)
{
string reply = String.Empty;
using (WebResponse response = request.EndGetResponse(ar))
{
try
{
using (Stream s = response.GetResponseStream())
using (StreamReader r = new StreamReader(s))
reply = r.ReadToEnd();
}
catch (System.InvalidOperationException)
{
}
}
action(requestUrl, data, reply);
}, null);
}, null);
}
}
}

View File

@ -9,7 +9,7 @@
* * Redistributions in binary form must reproduce the above copyright * * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the * notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution. * documentation and/or other materials provided with the distribution.
* * Neither the name of the OpenSimulator Project nor the * * Neither the name of the OpenSim Project nor the
* names of its contributors may be used to endorse or promote products * names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission. * derived from this software without specific prior written permission.
* *
@ -25,28 +25,22 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/ */
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using OpenMetaverse; using OpenMetaverse;
using OpenSim.Framework; using OpenSim.Framework;
namespace OpenSim.Data namespace OpenSim.Data
{ {
public abstract class AssetDataBase : IAssetDataPlugin public abstract class AssetDataBase : IAssetProviderPlugin
{ {
public abstract AssetBase GetAsset(UUID uuid); public abstract AssetBase FetchAsset(UUID uuid);
public abstract bool StoreAsset(AssetBase asset); public abstract void CreateAsset(AssetBase asset);
public abstract bool[] AssetsExist(UUID[] uuids); public abstract void UpdateAsset(AssetBase asset);
public abstract bool ExistsAsset(UUID uuid);
public abstract List<AssetMetadata> FetchAssetMetadataSet(int start, int count);
public abstract string Version { get; } public abstract string Version { get; }
public abstract string Name { get; } public abstract string Name { get; }
public abstract void Initialise(string connect); public abstract void Initialise(string connect);
public abstract void Initialise(); public abstract void Initialise();
public abstract void Dispose(); public abstract void Dispose();
public abstract bool Delete(string id);
} }
} }

View File

@ -0,0 +1,205 @@
/*
* 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 OpenSim 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.Data;
using System.IO;
namespace OpenSim.Data.Base
{
/// <summary>
///
/// </summary>
public abstract class BaseDataReader
{
private readonly IDataReader m_source;
/// <summary>
///
/// </summary>
/// <param name="source"></param>
public BaseDataReader(IDataReader source)
{
m_source = source;
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public object Get(string name)
{
return m_source[name];
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public ushort GetUShort(string name)
{
return (ushort)m_source.GetInt32(m_source.GetOrdinal(name));
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public byte GetByte(string name)
{
int ordinal = m_source.GetOrdinal(name);
byte value = (byte)m_source.GetInt16(ordinal);
return value;
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public sbyte GetSByte(string name)
{
return (sbyte)m_source.GetInt16(m_source.GetOrdinal(name));
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public float GetFloat(string name)
{
return m_source.GetFloat(m_source.GetOrdinal(name));
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public byte[] GetBytes(string name)
{
int ordinal = m_source.GetOrdinal(name);
if (m_source.GetValue(ordinal) == DBNull.Value)
{
return null;
}
byte[] buffer = new byte[16384];
MemoryStream memStream = new MemoryStream();
long totalRead = 0;
int bytesRead;
do
{
bytesRead = (int)m_source.GetBytes(ordinal, totalRead, buffer, 0, buffer.Length);
totalRead += bytesRead;
memStream.Write(buffer, 0, bytesRead);
} while (bytesRead == buffer.Length);
return memStream.ToArray();
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public string GetString(string name)
{
int ordinal = m_source.GetOrdinal(name);
object value = m_source.GetValue(ordinal);
if (value is DBNull)
{
return null;
}
return (string)value;
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public bool Read()
{
return m_source.Read();
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public virtual Guid GetGuid(string name)
{
return m_source.GetGuid(m_source.GetOrdinal(name));
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public UInt32 GetUInt32(string name)
{
return (UInt32)GetInt32(name);
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
private Int32 GetInt32(string name)
{
int ordinal = m_source.GetOrdinal(name);
int int32 = m_source.GetInt32(ordinal);
return int32;
}
/// <summary>
///
/// </summary>
/// <param name="name"></param>
/// <returns></returns>
public Int64 GetInt64(string name)
{
int ordinal = m_source.GetOrdinal(name);
long int64 = m_source.GetInt64(ordinal);
return int64;
}
}
}

View File

@ -0,0 +1,185 @@
/*
* 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 OpenSim 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.Data;
using System.Data.Common;
namespace OpenSim.Data.Base
{
/// <summary>
///
/// </summary>
public abstract class BaseDatabaseConnector
{
protected string m_connectionString;
/// <summary>
///
/// </summary>
/// <param name="connectionString"></param>
public BaseDatabaseConnector(string connectionString)
{
m_connectionString = connectionString;
}
public abstract DbConnection GetNewConnection();
public abstract string CreateParamName(string fieldName);
/// <summary>
///
/// </summary>
/// <param name="mapper"></param>
/// <param name="connection"></param>
/// <param name="fieldName"></param>
/// <param name="key"></param>
/// <returns></returns>
public DbCommand CreateSelectCommand(BaseTableMapper mapper, DbConnection connection, string fieldName, object key)
{
string table = mapper.TableName;
DbCommand command = connection.CreateCommand();
string conditionString = CreateCondition(mapper, command, fieldName, key);
string query =
String.Format("select * from {0} where {1}", table, conditionString);
command.CommandText = query;
command.CommandType = CommandType.Text;
return command;
}
/// <summary>
///
/// </summary>
/// <param name="mapper"></param>
/// <param name="command"></param>
/// <param name="fieldName"></param>
/// <param name="key"></param>
/// <returns></returns>
public string CreateCondition(BaseTableMapper mapper, DbCommand command, string fieldName, object key)
{
string keyFieldParamName = mapper.CreateParamName(fieldName);
DbParameter param = command.CreateParameter();
param.ParameterName = keyFieldParamName;
param.Value = ConvertToDbType(key);
command.Parameters.Add(param);
return String.Format("{0}={1}", fieldName, keyFieldParamName);
}
/// <summary>
///
/// </summary>
/// <param name="mapper"></param>
/// <param name="connection"></param>
/// <param name="rowMapper"></param>
/// <param name="primaryKey"></param>
/// <returns></returns>
public DbCommand CreateUpdateCommand(BaseTableMapper mapper, DbConnection connection, object rowMapper, object primaryKey)
{
string table = mapper.TableName;
List<string> fieldNames = new List<string>();
DbCommand command = connection.CreateCommand();
foreach (BaseFieldMapper fieldMapper in mapper.Schema.Fields.Values)
{
if (fieldMapper != mapper.KeyFieldMapper)
{
fieldMapper.ExpandField(rowMapper, command, fieldNames);
}
}
List<string> assignments = new List<string>();
foreach (string field in fieldNames)
{
assignments.Add(String.Format("{0}={1}", field, mapper.CreateParamName(field)));
}
string conditionString = mapper.CreateCondition(command, mapper.KeyFieldMapper.FieldName, primaryKey);
command.CommandText =
String.Format("update {0} set {1} where {2}", table, String.Join(", ", assignments.ToArray()),
conditionString);
return command;
}
/// <summary>
///
/// </summary>
/// <param name="mapper"></param>
/// <param name="connection"></param>
/// <param name="obj"></param>
/// <returns></returns>
public DbCommand CreateInsertCommand(BaseTableMapper mapper, DbConnection connection, object obj)
{
string table = mapper.TableName;
List<string> fieldNames = new List<string>();
DbCommand command = connection.CreateCommand();
foreach (BaseFieldMapper fieldMapper in mapper.Schema.Fields.Values)
{
fieldMapper.ExpandField(obj, command, fieldNames);
}
List<string> paramNames = new List<string>();
foreach (string field in fieldNames)
{
paramNames.Add(mapper.CreateParamName(field));
}
command.CommandText =
String.Format("insert into {0} ({1}) values ({2})", table, String.Join(", ", fieldNames.ToArray()),
String.Join(", ", paramNames.ToArray()));
return command;
}
/// <summary>
///
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public virtual object ConvertToDbType(object value)
{
return value;
}
public abstract BaseDataReader CreateReader(IDataReader reader);
}
}

View File

@ -0,0 +1,214 @@
/*
* 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 OpenSim 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.Data.Common;
namespace OpenSim.Data.Base
{
public delegate TField ObjectGetAccessor<TObj, TField>(TObj obj);
public delegate void ObjectSetAccessor<TObj, TField>(TObj obj, TField value);
/// <summary>
///
/// </summary>
public abstract class BaseFieldMapper
{
private readonly BaseTableMapper m_tableMapper;
private readonly string m_fieldName;
/// <summary>
///
/// </summary>
public string FieldName
{
get { return m_fieldName; }
}
protected Type m_valueType;
/// <summary>
///
/// </summary>
public Type ValueType
{
get { return m_valueType; }
}
public abstract object GetParamValue(object obj);
/// <summary>
///
/// </summary>
/// <param name="tableMapper"></param>
/// <param name="fieldName"></param>
/// <param name="valueType"></param>
public BaseFieldMapper(BaseTableMapper tableMapper, string fieldName, Type valueType)
{
m_fieldName = fieldName;
m_valueType = valueType;
m_tableMapper = tableMapper;
}
public abstract void SetPropertyFromReader(object mapper, BaseDataReader reader);
/// <summary>
///
/// </summary>
/// <param name="command"></param>
/// <param name="fieldNames"></param>
/// <param name="fieldName"></param>
/// <param name="value"></param>
public void RawAddParam(DbCommand command, List<string> fieldNames, string fieldName, object value)
{
string paramName = m_tableMapper.CreateParamName(fieldName);
fieldNames.Add(fieldName);
DbParameter param = command.CreateParameter();
param.ParameterName = paramName;
param.Value = value;
command.Parameters.Add(param);
}
/// <summary>
///
/// </summary>
/// <typeparam name="TObj"></typeparam>
/// <param name="obj"></param>
/// <param name="command"></param>
/// <param name="fieldNames"></param>
public virtual void ExpandField<TObj>(TObj obj, DbCommand command, List<string> fieldNames)
{
string fieldName = FieldName;
object value = GetParamValue(obj);
RawAddParam(command, fieldNames, fieldName, m_tableMapper.ConvertToDbType(value));
}
/// <summary>
///
/// </summary>
/// <param name="reader"></param>
/// <returns></returns>
protected virtual object GetValue(BaseDataReader reader)
{
object value;
if (ValueType == typeof(Guid))
{
value = reader.GetGuid(m_fieldName);
}
else if (ValueType == typeof(bool))
{
uint boolVal = reader.GetUShort(m_fieldName);
value = (boolVal == 1);
}
else
if (ValueType == typeof(byte))
{
value = reader.GetByte(m_fieldName);
}
else if (ValueType == typeof(sbyte))
{
value = reader.GetSByte(m_fieldName);
}
else if (ValueType == typeof(ushort))
{
value = reader.GetUShort(m_fieldName);
}
else if (ValueType == typeof(uint))
{
value = reader.GetUInt32(m_fieldName);
}
else if (ValueType == typeof(byte[]))
{
value = reader.GetBytes(m_fieldName);
}
else
{
value = reader.Get(m_fieldName);
}
if (value is DBNull)
{
value = default(ValueType);
}
return value;
}
}
/// <summary>
///
/// </summary>
/// <typeparam name="TObject"></typeparam>
/// <typeparam name="TField"></typeparam>
public class ObjectField<TObject, TField> : BaseFieldMapper
{
private readonly ObjectGetAccessor<TObject, TField> m_fieldGetAccessor;
private readonly ObjectSetAccessor<TObject, TField> m_fieldSetAccessor;
public override object GetParamValue(object obj)
{
return m_fieldGetAccessor((TObject)obj);
}
public override void SetPropertyFromReader(object obj, BaseDataReader reader)
{
object value;
value = GetValue(reader);
if (value == null)
{
m_fieldSetAccessor((TObject)obj, default(TField));
}
else
{
m_fieldSetAccessor((TObject)obj, (TField)value);
}
}
/// <summary>
///
/// </summary>
/// <param name="tableMapper"></param>
/// <param name="fieldName"></param>
/// <param name="rowMapperGetAccessor"></param>
/// <param name="rowMapperSetAccessor"></param>
public ObjectField(BaseTableMapper tableMapper, string fieldName, ObjectGetAccessor<TObject, TField> rowMapperGetAccessor,
ObjectSetAccessor<TObject, TField> rowMapperSetAccessor)
: base(tableMapper, fieldName, typeof(TField))
{
m_fieldGetAccessor = rowMapperGetAccessor;
m_fieldSetAccessor = rowMapperSetAccessor;
}
}
}

View File

@ -0,0 +1,78 @@
/*
* 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 OpenSim 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.Data.Base
{
/// <summary>
///
/// </summary>
public abstract class BaseRowMapper
{
public abstract void FiPrimitive(BaseDataReader reader);
}
/// <summary>
///
/// </summary>
/// <typeparam name="TObj"></typeparam>
public class BaseRowMapper<TObj> : BaseRowMapper
{
private readonly BaseSchema m_schema;
private readonly TObj m_obj;
/// <summary>
///
/// </summary>
public TObj Object
{
get { return m_obj; }
}
/// <summary>
///
/// </summary>
/// <param name="schema"></param>
/// <param name="obj"></param>
public BaseRowMapper(BaseSchema schema, TObj obj)
{
m_schema = schema;
m_obj = obj;
}
/// <summary>
///
/// </summary>
/// <param name="reader"></param>
public override void FiPrimitive(BaseDataReader reader)
{
foreach (BaseFieldMapper fieldMapper in m_schema.Fields.Values)
{
fieldMapper.SetPropertyFromReader(this, reader);
}
}
}
}

View File

@ -0,0 +1,94 @@
/*
* 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 OpenSim 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.Collections.Generic;
namespace OpenSim.Data.Base
{
/// <summary>
///
/// </summary>
public class BaseSchema
{
protected BaseTableMapper m_tableMapper;
protected Dictionary<string, BaseFieldMapper> m_mappings;
/// <summary>
///
/// </summary>
public Dictionary<string, BaseFieldMapper> Fields
{
get { return m_mappings; }
}
/// <summary>
///
/// </summary>
/// <param name="tableMapper"></param>
public BaseSchema(BaseTableMapper tableMapper)
{
m_mappings = new Dictionary<string, BaseFieldMapper>();
m_tableMapper = tableMapper;
}
}
/// <summary>
///
/// </summary>
/// <typeparam name="TObj"></typeparam>
public class BaseSchema<TObj> : BaseSchema
{
/// <summary>
///
/// </summary>
/// <param name="tableMapper"></param>
public BaseSchema(BaseTableMapper tableMapper)
: base(tableMapper)
{
}
/// <summary>
///
/// </summary>
/// <typeparam name="TField"></typeparam>
/// <param name="fieldName"></param>
/// <param name="rowMapperGetAccessor"></param>
/// <param name="rowMapperSetAccessor"></param>
/// <returns></returns>
public ObjectField<TObj, TField> AddMapping<TField>(string fieldName,
ObjectGetAccessor<TObj, TField> rowMapperGetAccessor,
ObjectSetAccessor<TObj, TField> rowMapperSetAccessor)
{
ObjectField<TObj, TField> rowMapperField =
new ObjectField<TObj, TField>(m_tableMapper, fieldName, rowMapperGetAccessor, rowMapperSetAccessor);
m_mappings.Add(fieldName, rowMapperField);
return rowMapperField;
}
}
}

View File

@ -0,0 +1,399 @@
/*
* 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 OpenSim 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.Data;
using System.Data.Common;
namespace OpenSim.Data.Base
{
/// <summary>
///
/// </summary>
public abstract class BaseTableMapper
{
private readonly BaseDatabaseConnector m_database;
private readonly object m_syncRoot = new object();
/// <summary>
///
/// </summary>
/// <param name="action"></param>
protected void WithConnection(Action<DbConnection> action)
{
lock (m_syncRoot)
{
DbConnection m_connection = m_database.GetNewConnection();
if (m_connection.State != ConnectionState.Open)
{
m_connection.Open();
}
action(m_connection);
if (m_connection.State == ConnectionState.Open)
{
m_connection.Close();
}
}
}
private readonly string m_tableName;
public string TableName
{
get { return m_tableName; }
}
protected BaseSchema m_schema;
public BaseSchema Schema
{
get { return m_schema; }
}
protected BaseFieldMapper m_keyFieldMapper;
public BaseFieldMapper KeyFieldMapper
{
get { return m_keyFieldMapper; }
}
/// <summary>
///
/// </summary>
/// <param name="database"></param>
/// <param name="tableName"></param>
public BaseTableMapper(BaseDatabaseConnector database, string tableName)
{
m_database = database;
m_tableName = tableName.ToLower(); // Stupid MySQL hack.
}
/// <summary>
///
/// </summary>
/// <param name="fieldName"></param>
/// <returns></returns>
public string CreateParamName(string fieldName)
{
return m_database.CreateParamName(fieldName);
}
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
/// <param name="fieldName"></param>
/// <param name="primaryKey"></param>
/// <returns></returns>
protected DbCommand CreateSelectCommand(DbConnection connection, string fieldName, object primaryKey)
{
return m_database.CreateSelectCommand(this, connection, fieldName, primaryKey);
}
/// <summary>
///
/// </summary>
/// <param name="command"></param>
/// <param name="fieldName"></param>
/// <param name="key"></param>
/// <returns></returns>
public string CreateCondition(DbCommand command, string fieldName, object key)
{
return m_database.CreateCondition(this, command, fieldName, key);
}
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
/// <param name="obj"></param>
/// <returns></returns>
public DbCommand CreateInsertCommand(DbConnection connection, object obj)
{
return m_database.CreateInsertCommand(this, connection, obj);
}
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
/// <param name="rowMapper"></param>
/// <param name="primaryKey"></param>
/// <returns></returns>
public DbCommand CreateUpdateCommand(DbConnection connection, object rowMapper, object primaryKey)
{
return m_database.CreateUpdateCommand(this, connection, rowMapper, primaryKey);
}
/// <summary>
///
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public object ConvertToDbType(object value)
{
return m_database.ConvertToDbType(value);
}
/// <summary>
///
/// </summary>
/// <param name="reader"></param>
/// <returns></returns>
protected virtual BaseDataReader CreateReader(IDataReader reader)
{
return m_database.CreateReader(reader);
}
}
/// <summary>
///
/// </summary>
/// <typeparam name="TRowMapper"></typeparam>
/// <typeparam name="TPrimaryKey"></typeparam>
public abstract class BaseTableMapper<TRowMapper, TPrimaryKey> : BaseTableMapper
{
/// <summary>
///
/// </summary>
/// <param name="database"></param>
/// <param name="tableName"></param>
public BaseTableMapper(BaseDatabaseConnector database, string tableName)
: base(database, tableName)
{
}
/// <summary>
/// HACK: This is a temporary function used by TryGetValue().
/// Due to a bug in mono 1.2.6, delegate blocks cannot contain
/// a using block. This has been fixed in SVN, so the next
/// mono release should work.
/// </summary>
/// <param name="connection"></param>
/// <param name="primaryKey"></param>
/// <param name="result"></param>
/// <param name="success"></param>
private void TryGetConnectionValue(DbConnection connection, TPrimaryKey primaryKey, ref TRowMapper result, ref bool success)
{
using (
DbCommand command =
CreateSelectCommand(connection, KeyFieldMapper.FieldName, primaryKey))
{
using (IDataReader reader = command.ExecuteReader())
{
if (reader.Read())
{
result = FromReader(CreateReader(reader));
success = true;
}
else
{
success = false;
}
}
}
}
/// <summary>
///
/// </summary>
/// <param name="primaryKey"></param>
/// <param name="value"></param>
/// <returns></returns>
public bool TryGetValue(TPrimaryKey primaryKey, out TRowMapper value)
{
TRowMapper result = default(TRowMapper);
bool success = false;
WithConnection(delegate(DbConnection connection)
{
TryGetConnectionValue(connection, primaryKey, ref result, ref success);
});
value = result;
return success;
}
/// <summary>
/// HACK: This is a temporary function used by Remove().
/// Due to a bug in mono 1.2.6, delegate blocks cannot contain
/// a using block. This has been fixed in SVN, so the next
/// mono release should work.
/// </summary>
/// <param name="connection"></param>
/// <param name="id"></param>
/// <param name="deleted"></param>
protected virtual void TryDelete(DbConnection connection, TPrimaryKey id, ref int deleted)
{
using (
DbCommand command =
CreateDeleteCommand(connection, KeyFieldMapper.FieldName, id))
{
deleted = command.ExecuteNonQuery();
}
}
/// <summary>
///
/// </summary>
/// <param name="id"></param>
/// <returns></returns>
public virtual bool Remove(TPrimaryKey id)
{
int deleted = 0;
WithConnection(delegate(DbConnection connection)
{
TryDelete(connection, id, ref deleted);
});
if (deleted == 1)
{
return true;
}
else
{
return false;
}
}
/// <summary>
///
/// </summary>
/// <param name="connection"></param>
/// <param name="fieldName"></param>
/// <param name="primaryKey"></param>
/// <returns></returns>
public DbCommand CreateDeleteCommand(DbConnection connection, string fieldName, TPrimaryKey primaryKey)
{
string table = TableName;
DbCommand command = connection.CreateCommand();
string conditionString = CreateCondition(command, fieldName, primaryKey);
string query =
String.Format("delete from {0} where {1}", table, conditionString);
command.CommandText = query;
command.CommandType = CommandType.Text;
return command;
}
/// <summary>
/// HACK: This is a temporary function used by Update().
/// Due to a bug in mono 1.2.6, delegate blocks cannot contain
/// a using block. This has been fixed in SVN, so the next
/// mono release should work.
/// </summary>
/// <param name="connection"></param>
/// <param name="primaryKey"></param>
/// <param name="value"></param>
/// <param name="updated"></param>
protected void TryUpdate(DbConnection connection, TPrimaryKey primaryKey, TRowMapper value, ref int updated)
{
using (DbCommand command = CreateUpdateCommand(connection, value, primaryKey))
{
updated = command.ExecuteNonQuery();
}
}
/// <summary>
///
/// </summary>
/// <param name="primaryKey"></param>
/// <param name="value"></param>
/// <returns></returns>
public virtual bool Update(TPrimaryKey primaryKey, TRowMapper value)
{
int updated = 0;
WithConnection(delegate(DbConnection connection)
{
TryUpdate(connection, primaryKey, value, ref updated);
});
if (updated == 1)
{
return true;
}
else
{
return false;
}
}
/// <summary>
/// HACK: This is a temporary function used by Add().
/// Due to a bug in mono 1.2.6, delegate blocks cannot contain
/// a using block. This has been fixed in SVN, so the next
/// mono release should work.
/// </summary>
/// <param name="connection"></param>
/// <param name="value"></param>
/// <param name="added"></param>
protected void TryAdd(DbConnection connection, TRowMapper value, ref int added)
{
using (DbCommand command = CreateInsertCommand(connection, value))
{
added = command.ExecuteNonQuery();
}
}
/// <summary>
///
/// </summary>
/// <param name="value"></param>
/// <returns></returns>
public virtual bool Add(TRowMapper value)
{
int added = 0;
WithConnection(delegate(DbConnection connection)
{
TryAdd(connection, value, ref added);
});
if (added == 1)
{
return true;
}
else
{
return false;
}
}
public abstract TRowMapper FromReader(BaseDataReader reader);
}
}

Some files were not shown because too many files have changed in this diff Show More