Compare commits
13 Commits
master
...
GenericGri
Author | SHA1 | Date |
---|---|---|
MW | 66dc459a06 | |
MW | 78f4f49965 | |
MW | 70f283e089 | |
MW | c7151a5a2b | |
MW | da2cbb75b6 | |
MW | aa5b4b6437 | |
MW | 9b9456c985 | |
MW | ce0e98ad30 | |
MW | bb1823a7ad | |
MW | 21e9ad6150 | |
MW | 4fc37a4abd | |
MW | 1e015a4cb8 | |
MW | 29c4eef1fe |
|
@ -1,116 +1,41 @@
|
||||||
.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/*/*.dll
|
||||||
bin/ScriptEngines/*/*.state
|
bin/ScriptEngines/*/*.state
|
||||||
bin/*.maddin
|
bin/*.maddin
|
||||||
bin/*.exe
|
bin/*.exe
|
||||||
bin/*.ini
|
|
||||||
bin/j2kDecodeCache
|
bin/j2kDecodeCache
|
||||||
bin/Physics*
|
bin/Physics*
|
||||||
bin/Terrain*
|
bin/Terrain*
|
||||||
bin/Regions/*
|
|
||||||
bin/UserAssets
|
bin/UserAssets
|
||||||
bin/assetcache
|
|
||||||
bin/maptiles
|
|
||||||
bin/bakes
|
|
||||||
bin/estate_settings.xml
|
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
|
||||||
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
|
||||||
cov/*
|
cov/*
|
||||||
OpenSim/OpenSim.userprefs
|
OpenSim/OpenSim.userprefs
|
||||||
OpenSim/OpenSim.usertasks
|
OpenSim/OpenSim.usertasks
|
||||||
TAGS
|
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
|
|
||||||
|
|
|
@ -0,0 +1,75 @@
|
||||||
|
<?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.3" />
|
||||||
|
<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 64 bit ode library 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.Tests.dll"/>
|
||||||
|
<include name="../bin/OpenSim.Region.CoreModules.Tests.dll"/>
|
||||||
|
<include name="../bin/OpenSim.Region.Framework.Tests.dll"/>
|
||||||
|
<include name="../bin/OpenSim.Data.SQLite.Tests.dll"/>
|
||||||
|
<include name="../bin/OpenSim.Data.MySQL.Tests.dll"/>
|
||||||
|
<include name="../bin/OpenSim.Region.Physics.OdePlugin.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>
|
|
@ -1,289 +1,194 @@
|
||||||
<!-- -*- 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>
|
</fileset>
|
||||||
</delete>
|
</copy>
|
||||||
|
<touch file="${projectdir}/bin/startup_commands.txt" />
|
||||||
</target>
|
</target>
|
||||||
|
|
||||||
<property name="distbindir" value="distbin" />
|
<target name="test" depends="build">
|
||||||
<!-- This target produces a binary directory called distbin/ in OpenSim/bin which contains everything needed for binary distribution -->
|
<nunit2 failonerror="true" verbose="true">
|
||||||
<!-- For safety/laziness sake, we're going to take the approach of deleting known extraneous files here rather than
|
<formatter type="Plain" />
|
||||||
trying to copy across only the essential ones -->
|
<test>
|
||||||
<target name="distbin">
|
<assemblies>
|
||||||
<delete dir="${distbindir}"/>
|
<include name="./bin/OpenSim.Framework.Tests.dll" />
|
||||||
<copy todir="${distbindir}">
|
<include name="./bin/OpenSim.Framework.Communications.Tests.dll"/>
|
||||||
<fileset>
|
<include name="./bin/OpenSim.Framework.Servers.Tests.dll" />
|
||||||
<include name="**"/>
|
<include name="./bin/OpenSim.Region.ClientStack.LindenUDP.Tests.dll" />
|
||||||
</fileset>
|
<include name="./bin/OpenSim.Region.ScriptEngine.Tests.dll" />
|
||||||
</copy>
|
<include name="./bin/OpenSim.Region.CoreModules.Tests.dll" />
|
||||||
<delete dir="${distbindir}/OpenSim"/>
|
<include name="./bin/OpenSim.Region.Framework.Tests.dll" />
|
||||||
<delete dir="${distbindir}/Prebuild"/>
|
<include name="./bin/OpenSim.Data.SQLite.Tests.dll" />
|
||||||
<delete dir="${distbindir}/%temp%"/>
|
<include name="./bin/OpenSim.Data.MySQL.Tests.dll" />
|
||||||
<delete dir="${distbindir}/.nant"/>
|
</assemblies>
|
||||||
<delete dir="${distbindir}/ThirdParty"/>
|
</test>
|
||||||
<delete>
|
</nunit2>
|
||||||
<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-cov" depends="build">
|
||||||
<setenv name="MONO_THREADS_PER_CPU" value="100" />
|
<!-- Code Coverage Test. Prototype, only works with mono 1.2. Instructions in http://opensimulator.org/wiki/Automated_Testing -->
|
||||||
|
<mkdir dir="cov" failonerror="false" />
|
||||||
|
<exec program="mono">
|
||||||
|
<arg value="--debug" />
|
||||||
|
<arg value="--profile=monocov:outfile=./cov/OpenSim.Framework.Servers.cov,+[OpenSim.Framework.Servers]" />
|
||||||
|
<arg value="/usr/lib/nunit/nunit-console.exe" />
|
||||||
|
<arg value="./bin/OpenSim.Framework.Servers.Tests.dll" />
|
||||||
|
</exec>
|
||||||
|
<delete dir="./cov/OpenSim.Framework.Servers" />
|
||||||
|
<exec program="monocov">
|
||||||
|
<arg value="--export-html=./cov/OpenSim.Framework.Servers ./cov/OpenSim.Framework.Servers.cov" />
|
||||||
|
</exec>
|
||||||
|
|
||||||
<!-- Unit Test Assembly -->
|
<exec program="mono">
|
||||||
<!-- if you want to add more unit tests it's important that you add
|
<arg value="--debug" />
|
||||||
the assembly here as an exec, and you add the fail clause later.
|
<arg value="--profile=monocov:outfile=./cov/OpenSim.Framework.Communications.cov,+[OpenSim.Framework.Communications]" />
|
||||||
This lets all the unit tests run and tells you if they fail at the
|
<arg value="/usr/lib/nunit/nunit-console.exe" />
|
||||||
end, instead of stopping short -->
|
<arg value="./bin/OpenSim.Framework.Communications.Tests.dll" />
|
||||||
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests">
|
</exec>
|
||||||
<arg value="./bin/OpenSim.Tests.dll" />
|
<delete dir="./cov/OpenSim.Framework.Communications" />
|
||||||
</exec>
|
<exec program="monocov">
|
||||||
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.tests)==0}" />
|
<arg value="--export-html=./cov/OpenSim.Framework.Servers ./cov/OpenSim.Framework.Communications.cov" />
|
||||||
|
</exec>
|
||||||
|
|
||||||
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.framework.tests">
|
<exec program="mono">
|
||||||
<arg value="./bin/OpenSim.Framework.Tests.dll" />
|
<arg value="--debug" />
|
||||||
</exec>
|
<arg value="--profile=monocov:outfile=./cov/OpenSim.Region.ClientStack.LindenUDP.cov,+[OpenSim.Region.ClientStack.LindenUDP]" />
|
||||||
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.framework.tests)==0}" />
|
<arg value="/usr/lib/nunit/nunit-console.exe" />
|
||||||
|
<arg value="./bin/OpenSim.Region.ClientStack.LindenUDP.Tests.dll" />
|
||||||
|
</exec>
|
||||||
|
<delete dir="./cov/OpenSim.Region.ClientStack.LindenUDP" />
|
||||||
|
<exec program="monocov">
|
||||||
|
<arg value="--export-html=./cov/OpenSim.Region.ClientStack.LindenUDP ./cov/OpenSim.Region.ClientStack.LindenUDP.cov" />
|
||||||
|
</exec>
|
||||||
|
|
||||||
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.framework.servers.tests">
|
<exec program="mono">
|
||||||
<arg value="./bin/OpenSim.Framework.Servers.Tests.dll" />
|
<arg value="--debug" />
|
||||||
</exec>
|
<arg value="--profile=monocov:outfile=./cov/OpenSim.Region.ScriptEngine.Shared.cov,+[OpenSim.Region.ScriptEngine.Shared]" />
|
||||||
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.framework.servers.tests)==0}" />
|
<arg value="/usr/lib/nunit/nunit-console.exe" />
|
||||||
|
<arg value="./bin/OpenSim.Region.ScriptEngine.Shared.Tests.dll" />
|
||||||
|
</exec>
|
||||||
|
<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>
|
||||||
|
|
||||||
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.framework.serialization.tests">
|
<exec program="mono">
|
||||||
<arg value="./bin/OpenSim.Framework.Serialization.Tests.dll" />
|
<arg value="--debug" />
|
||||||
</exec>
|
<arg value="--profile=monocov:outfile=./cov/OpenSim.Region.ScriptEngine.Shared.CodeTools.cov,+[OpenSim.Region.ScriptEngine.Shared.CodeTools]" />
|
||||||
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.framework.serialization.tests)==0}" />
|
<arg value="/usr/lib/nunit/nunit-console.exe" />
|
||||||
|
<arg value="./bin/OpenSim.Region.ScriptEngine.Shared.CodeTools.Tests.dll" />
|
||||||
|
</exec>
|
||||||
|
<delete dir="./cov/OpenSim.Region.ScriptEngine.Shared.CodeTools" />
|
||||||
|
<exec program="monocov">
|
||||||
|
<arg value="--export-html=./cov/OpenSim.Region.ScriptEngine.Shared.CodeTools ./cov/OpenSim.Region.ScriptEngine.Shared.CodeTools.cov" />
|
||||||
|
</exec>
|
||||||
|
|
||||||
<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" />
|
||||||
</exec>
|
<arg value="--profile=monocov:outfile=./cov/OpenSim.Region.CoreModules.cov,+[OpenSim.Region.CoreModules]" />
|
||||||
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.clientstack.lindencaps.tests)==0}" />
|
<arg value="/usr/lib/nunit/nunit-console.exe" />
|
||||||
|
<arg value="./bin/OpenSim.Region.CoreModules.Tests.dll" />
|
||||||
|
</exec>
|
||||||
|
<delete dir="./cov/OpenSim.Region.CoreModules" />
|
||||||
|
<exec program="monocov">
|
||||||
|
<arg value="--export-html=./cov/OpenSim.Region.CoreModules ./cov/OpenSim.Region.CoreModules.cov" />
|
||||||
|
</exec>
|
||||||
|
|
||||||
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.region.clientstack.lindenudp.tests">
|
<exec program="mono">
|
||||||
<arg value="./bin/OpenSim.Region.ClientStack.LindenUDP.Tests.dll" />
|
<arg value="--debug" />
|
||||||
</exec>
|
<arg value="--profile=monocov:outfile=./cov/OpenSim.Region.Framework.cov,+[OpenSim.Region.Framework]" />
|
||||||
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.clientstack.lindenudp.tests)==0}" />
|
<arg value="/usr/lib/nunit/nunit-console.exe" />
|
||||||
|
<arg value="./bin/OpenSim.Region.Framework.Tests.dll" />
|
||||||
|
</exec>
|
||||||
|
<delete dir="./cov/OpenSim.Region.Framework" />
|
||||||
|
<exec program="monocov">
|
||||||
|
<arg value="--export-html=./cov/OpenSim.Region.Framework ./cov/OpenSim.Region.Framework.cov" />
|
||||||
|
</exec>
|
||||||
|
|
||||||
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.region.scriptengine.tests">
|
<exec program="mono">
|
||||||
<arg value="./bin/OpenSim.Region.ScriptEngine.Tests.dll" />
|
<arg value="--debug" />
|
||||||
</exec>
|
<arg value="--profile=monocov:outfile=./cov/OpenSim.Data.SQLite.cov,+[OpenSim.Data.SQLite]" />
|
||||||
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.scriptengine.tests)==0}" />
|
<arg value="/usr/lib/nunit/nunit-console.exe" />
|
||||||
|
<arg value="./bin/OpenSim.Data.SQLite.Tests.dll" />
|
||||||
|
</exec>
|
||||||
|
<delete dir="./cov/OpenSim.Data.SQLite" />
|
||||||
|
<exec program="monocov">
|
||||||
|
<arg value="--export-html=./cov/OpenSim.Data.SQLite ./cov/OpenSim.Data.SQLite.cov" />
|
||||||
|
</exec>
|
||||||
|
|
||||||
<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" />
|
||||||
</exec>
|
<arg value="--profile=monocov:outfile=./cov/OpenSim.Data.MySQL.cov,+[OpenSim.Data.MySQL.Tests]" />
|
||||||
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.coremodules.tests)==0}" />
|
<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" />
|
||||||
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.region.optionalmodules.tests">
|
<delete file="TestResult.xml" failonerror="false" />
|
||||||
<arg value="./bin/OpenSim.Region.OptionalModules.Tests.dll" />
|
|
||||||
</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">
|
|
||||||
<arg value="./bin/OpenSim.Region.Framework.Tests.dll" />
|
|
||||||
</exec>
|
|
||||||
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.region.framework.tests)==0}" />
|
|
||||||
|
|
||||||
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.data.tests">
|
|
||||||
<arg value="./bin/OpenSim.Data.Tests.dll" />
|
|
||||||
</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">
|
|
||||||
<arg value="./bin/OpenSim.Capabilities.Handlers.Tests.dll" />
|
|
||||||
</exec>
|
|
||||||
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.capabilities.handlers.tests)==0}" />
|
|
||||||
|
|
||||||
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.server.handlers.tests">
|
|
||||||
<arg value="./bin/OpenSim.Server.Handlers.Tests.dll" />
|
|
||||||
</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">
|
|
||||||
<arg value="./bin/OpenSim.Services.InventoryService.Tests.dll" />
|
|
||||||
</exec>
|
|
||||||
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.services.inventoryservice.tests)==0}" />
|
|
||||||
|
|
||||||
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests.permissions">
|
|
||||||
<arg value="./bin/OpenSim.Tests.Permissions.dll" />
|
|
||||||
</exec>
|
|
||||||
<fail message="Failures reported in unit tests." unless="${int::parse(testresult.opensim.tests.permissions)==0}" />
|
|
||||||
|
|
||||||
<delete dir="%temp%"/>
|
|
||||||
</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.Tests.dll" />
|
||||||
|
<include name="./bin/OpenSim.Region.CoreModules.Tests.dll" />
|
||||||
<exec program="${nunitcmd}" failonerror="true" resultproperty="testresult.opensim.tests.performance">
|
<include name="./bin/OpenSim.Region.Framework.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>
|
||||||
|
|
37
BUILDING.md
37
BUILDING.md
|
@ -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
|
|
210
CONTRIBUTORS.txt
210
CONTRIBUTORS.txt
|
@ -1,252 +1,132 @@
|
||||||
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
|
* 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
|
||||||
|
* DoranZemlja
|
||||||
* 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
|
|
||||||
* Kitto Flora
|
* Kitto Flora
|
||||||
* KittyLiu
|
* krtaylor (IBM)
|
||||||
* 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
|
* mpallari
|
||||||
* MrMonkE
|
* nlin
|
||||||
* 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)
|
* 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
|
||||||
|
|
||||||
|
|
||||||
|
AssetInventory Server and some plugins are based on Cable Beach
|
||||||
|
Cable Beach is Copyright (c) 2008 Intel Corporation
|
||||||
|
see http://forge.opensimulator.org/gf/project/assetserver/
|
||||||
|
|
||||||
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/)
|
* Prototype JavaScript Framework ajax (http://www.prototypejs.org/)
|
||||||
* C5 GENERIC COLLECTION LIBRARY FOR C#/CLI
|
* C5 GENERIC COLLECTION LIBRARY FOR C#/CLI
|
||||||
* Nini (http://nini.sourceforge.net/)
|
* Nini (http://nini.sourceforge.net/)
|
||||||
* log4net (http://logging.apache.org/log4net/)
|
* log4net (http://logging.apache.org/log4net/)
|
||||||
* GlynnTucker.Cache (http://gtcache.sourceforge.net/)
|
* 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
|
||||||
|
|
|
@ -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.
|
||||||
|
|
||||||
|
|
18
Makefile
18
Makefile
|
@ -1,14 +1,4 @@
|
||||||
# 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)
|
||||||
|
@ -24,7 +14,7 @@ prebuild:
|
||||||
|
|
||||||
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 +25,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)
|
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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
|
@ -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
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)]
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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)]
|
|
|
@ -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
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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());
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,256 @@
|
||||||
|
/*
|
||||||
|
* 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.Threading;
|
||||||
|
using log4net;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.RegionLoader.Filesystem;
|
||||||
|
using OpenSim.Framework.RegionLoader.Web;
|
||||||
|
using OpenSim.Region.CoreModules.Agent.AssetTransaction;
|
||||||
|
using OpenSim.Region.CoreModules.Avatar.InstantMessage;
|
||||||
|
using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
|
||||||
|
using OpenSim.Region.CoreModules.Scripting.LoadImageURL;
|
||||||
|
using OpenSim.Region.CoreModules.Scripting.XMLRPC;
|
||||||
|
using OpenSim.Framework.Communications;
|
||||||
|
using OpenSim.Framework.Communications.Cache;
|
||||||
|
using OpenSim.Region.Communications.Hypergrid;
|
||||||
|
using OpenSim.Region.Communications.Local;
|
||||||
|
using OpenSim.Region.Communications.OGS1;
|
||||||
|
using OpenSim.Framework.Servers;
|
||||||
|
using OpenSim.ApplicationPlugins.LoadRegions;
|
||||||
|
|
||||||
|
namespace OpenSim.ApplicationPlugins.CreateCommsManager
|
||||||
|
{
|
||||||
|
public class CreateCommsManagerPlugin : IApplicationPlugin
|
||||||
|
{
|
||||||
|
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
#region IApplicationPlugin Members
|
||||||
|
|
||||||
|
// TODO: required by IPlugin, but likely not at all right
|
||||||
|
string m_name = "CreateCommsManagerPlugin";
|
||||||
|
string m_version = "0.0";
|
||||||
|
|
||||||
|
public string Version { get { return m_version; } }
|
||||||
|
public string Name { get { return m_name; } }
|
||||||
|
|
||||||
|
protected OpenSimBase m_openSim;
|
||||||
|
|
||||||
|
protected BaseHttpServer m_httpServer;
|
||||||
|
|
||||||
|
protected CommunicationsManager m_commsManager;
|
||||||
|
protected GridInfoService m_gridInfoService;
|
||||||
|
protected IHyperlink HGServices = null;
|
||||||
|
|
||||||
|
protected LoadRegionsPlugin m_loadRegionsPlugin;
|
||||||
|
|
||||||
|
public void Initialise()
|
||||||
|
{
|
||||||
|
m_log.Info("[LOADREGIONS]: " + Name + " cannot be default-initialized!");
|
||||||
|
throw new PluginNotInitialisedException(Name);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Initialise(OpenSimBase openSim)
|
||||||
|
{
|
||||||
|
m_openSim = openSim;
|
||||||
|
m_httpServer = openSim.HttpServer;
|
||||||
|
|
||||||
|
InitialiseCommsManager(openSim);
|
||||||
|
if (m_commsManager != null)
|
||||||
|
{
|
||||||
|
m_openSim.ApplicationRegistry.RegisterInterface<IUserService>(m_commsManager.UserService);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PostInitialise()
|
||||||
|
{
|
||||||
|
if (m_openSim.ApplicationRegistry.TryGet<LoadRegionsPlugin>(out m_loadRegionsPlugin))
|
||||||
|
{
|
||||||
|
m_loadRegionsPlugin.OnNewRegionCreated += RegionCreated;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private void RegionCreated(IScene scene)
|
||||||
|
{
|
||||||
|
if (m_commsManager != null)
|
||||||
|
{
|
||||||
|
scene.RegisterModuleInterface<IUserService>(m_commsManager.UserService);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void InitialiseCommsManager(OpenSimBase openSim)
|
||||||
|
{
|
||||||
|
LibraryRootFolder libraryRootFolder = new LibraryRootFolder(m_openSim.ConfigurationSettings.LibrariesXMLFile);
|
||||||
|
|
||||||
|
bool hgrid = m_openSim.ConfigSource.Source.Configs["Startup"].GetBoolean("hypergrid", false);
|
||||||
|
|
||||||
|
if (hgrid)
|
||||||
|
{
|
||||||
|
HGOpenSimNode hgNode = (HGOpenSimNode)openSim;
|
||||||
|
|
||||||
|
// Standalone mode is determined by !startupConfig.GetBoolean("gridmode", false)
|
||||||
|
if (m_openSim.ConfigurationSettings.Standalone)
|
||||||
|
{
|
||||||
|
InitialiseHGStandaloneServices(libraryRootFolder);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We are in grid mode
|
||||||
|
InitialiseHGGridServices(libraryRootFolder);
|
||||||
|
}
|
||||||
|
hgNode.HGServices = HGServices;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Standalone mode is determined by !startupConfig.GetBoolean("gridmode", false)
|
||||||
|
if (m_openSim.ConfigurationSettings.Standalone)
|
||||||
|
{
|
||||||
|
InitialiseStandaloneServices(libraryRootFolder);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// We are in grid mode
|
||||||
|
InitialiseGridServices(libraryRootFolder);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
openSim.CommunicationsManager = m_commsManager;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initialises the backend services for standalone mode, and registers some http handlers
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="libraryRootFolder"></param>
|
||||||
|
protected virtual void InitialiseStandaloneServices(LibraryRootFolder libraryRootFolder)
|
||||||
|
{
|
||||||
|
LocalInventoryService inventoryService = new LocalInventoryService();
|
||||||
|
inventoryService.AddPlugin(m_openSim.ConfigurationSettings.StandaloneInventoryPlugin, m_openSim.ConfigurationSettings.StandaloneInventorySource);
|
||||||
|
|
||||||
|
LocalUserServices userService =
|
||||||
|
new LocalUserServices(
|
||||||
|
m_openSim.NetServersInfo.DefaultHomeLocX, m_openSim.NetServersInfo.DefaultHomeLocY, inventoryService);
|
||||||
|
userService.AddPlugin(m_openSim.ConfigurationSettings.StandaloneUserPlugin, m_openSim.ConfigurationSettings.StandaloneUserSource);
|
||||||
|
|
||||||
|
LocalBackEndServices backendService = new LocalBackEndServices();
|
||||||
|
|
||||||
|
LocalLoginService loginService =
|
||||||
|
new LocalLoginService(
|
||||||
|
userService, m_openSim.ConfigurationSettings.StandaloneWelcomeMessage, inventoryService, backendService, m_openSim.NetServersInfo,
|
||||||
|
m_openSim.ConfigurationSettings.StandaloneAuthenticate, libraryRootFolder);
|
||||||
|
|
||||||
|
m_commsManager
|
||||||
|
= new CommunicationsLocal(
|
||||||
|
m_openSim.NetServersInfo, m_httpServer, m_openSim.AssetCache, userService, userService,
|
||||||
|
inventoryService, backendService, userService,
|
||||||
|
libraryRootFolder, m_openSim.ConfigurationSettings.DumpAssetsToFile);
|
||||||
|
|
||||||
|
// set up XMLRPC handler for client's initial login request message
|
||||||
|
m_httpServer.AddXmlRPCHandler("login_to_simulator", loginService.XmlRpcLoginMethod);
|
||||||
|
|
||||||
|
// provides the web form login
|
||||||
|
m_httpServer.AddHTTPHandler("login", loginService.ProcessHTMLLogin);
|
||||||
|
|
||||||
|
// Provides the LLSD login
|
||||||
|
m_httpServer.SetDefaultLLSDHandler(loginService.LLSDLoginMethod);
|
||||||
|
|
||||||
|
// provide grid info
|
||||||
|
// m_gridInfoService = new GridInfoService(m_config.Source.Configs["Startup"].GetString("inifile", Path.Combine(Util.configDir(), "OpenSim.ini")));
|
||||||
|
m_gridInfoService = new GridInfoService(m_openSim.ConfigSource.Source);
|
||||||
|
m_httpServer.AddXmlRPCHandler("get_grid_info", m_gridInfoService.XmlRpcGridInfoMethod);
|
||||||
|
m_httpServer.AddStreamHandler(new RestStreamHandler("GET", "/get_grid_info", m_gridInfoService.RestGetGridInfoMethod));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void InitialiseGridServices(LibraryRootFolder libraryRootFolder)
|
||||||
|
{
|
||||||
|
m_commsManager
|
||||||
|
= new CommunicationsOGS1(m_openSim.NetServersInfo, m_httpServer, m_openSim.AssetCache, libraryRootFolder);
|
||||||
|
|
||||||
|
m_httpServer.AddStreamHandler(new OpenSim.SimStatusHandler());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void InitialiseHGStandaloneServices(LibraryRootFolder libraryRootFolder)
|
||||||
|
{
|
||||||
|
// Standalone mode
|
||||||
|
|
||||||
|
HGInventoryService inventoryService = new HGInventoryService(m_openSim.NetServersInfo.InventoryURL, null, false);
|
||||||
|
inventoryService.AddPlugin(m_openSim.ConfigurationSettings.StandaloneInventoryPlugin, m_openSim.ConfigurationSettings.StandaloneInventorySource);
|
||||||
|
|
||||||
|
LocalUserServices userService =
|
||||||
|
new LocalUserServices(
|
||||||
|
m_openSim.NetServersInfo.DefaultHomeLocX, m_openSim.NetServersInfo.DefaultHomeLocY, inventoryService);
|
||||||
|
userService.AddPlugin(m_openSim.ConfigurationSettings.StandaloneUserPlugin, m_openSim.ConfigurationSettings.StandaloneUserSource);
|
||||||
|
|
||||||
|
//LocalBackEndServices backendService = new LocalBackEndServices();
|
||||||
|
HGGridServicesStandalone gridService = new HGGridServicesStandalone(m_openSim.NetServersInfo, m_httpServer, m_openSim.AssetCache, m_openSim.SceneManager);
|
||||||
|
|
||||||
|
LocalLoginService loginService =
|
||||||
|
new LocalLoginService(
|
||||||
|
userService, m_openSim.ConfigurationSettings.StandaloneWelcomeMessage, inventoryService, gridService.LocalBackend, m_openSim.NetServersInfo,
|
||||||
|
m_openSim.ConfigurationSettings.StandaloneAuthenticate, libraryRootFolder);
|
||||||
|
|
||||||
|
|
||||||
|
m_commsManager = new HGCommunicationsStandalone(m_openSim.NetServersInfo, m_httpServer, m_openSim.AssetCache,
|
||||||
|
userService, userService, inventoryService, gridService, userService, libraryRootFolder, m_openSim.ConfigurationSettings.DumpAssetsToFile);
|
||||||
|
|
||||||
|
inventoryService.UserProfileCache = m_commsManager.UserProfileCacheService;
|
||||||
|
HGServices = gridService;
|
||||||
|
|
||||||
|
// set up XMLRPC handler for client's initial login request message
|
||||||
|
m_httpServer.AddXmlRPCHandler("login_to_simulator", loginService.XmlRpcLoginMethod);
|
||||||
|
|
||||||
|
// provides the web form login
|
||||||
|
m_httpServer.AddHTTPHandler("login", loginService.ProcessHTMLLogin);
|
||||||
|
|
||||||
|
// Provides the LLSD login
|
||||||
|
m_httpServer.SetDefaultLLSDHandler(loginService.LLSDLoginMethod);
|
||||||
|
|
||||||
|
// provide grid info
|
||||||
|
// m_gridInfoService = new GridInfoService(m_config.Source.Configs["Startup"].GetString("inifile", Path.Combine(Util.configDir(), "OpenSim.ini")));
|
||||||
|
m_gridInfoService = new GridInfoService(m_openSim.ConfigSource.Source);
|
||||||
|
m_httpServer.AddXmlRPCHandler("get_grid_info", m_gridInfoService.XmlRpcGridInfoMethod);
|
||||||
|
m_httpServer.AddStreamHandler(new RestStreamHandler("GET", "/get_grid_info", m_gridInfoService.RestGetGridInfoMethod));
|
||||||
|
}
|
||||||
|
|
||||||
|
protected virtual void InitialiseHGGridServices(LibraryRootFolder libraryRootFolder)
|
||||||
|
{
|
||||||
|
m_commsManager = new HGCommunicationsGridMode(m_openSim.NetServersInfo, m_httpServer, m_openSim.AssetCache, m_openSim.SceneManager, libraryRootFolder);
|
||||||
|
|
||||||
|
HGServices = ((HGCommunicationsGridMode)m_commsManager).HGServices;
|
||||||
|
|
||||||
|
m_httpServer.AddStreamHandler(new OpenSim.SimStatusHandler());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
<Addin id="OpenSim.ApplicationPlugins.CreateCommsManager" version="0.1">
|
||||||
|
<Runtime>
|
||||||
|
<Import assembly="OpenSim.ApplicationPlugins.CreateCommsManager.dll"/>
|
||||||
|
</Runtime>
|
||||||
|
<Dependencies>
|
||||||
|
<Addin id="OpenSim" version="0.5" />
|
||||||
|
</Dependencies>
|
||||||
|
<Extension path = "/OpenSim/Startup">
|
||||||
|
<Plugin id="CreateCommsManager" type="OpenSim.ApplicationPlugins.CreateCommsManager.CreateCommsManagerPlugin" />
|
||||||
|
</Extension>
|
||||||
|
</Addin>
|
|
@ -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.
|
||||||
*
|
*
|
||||||
|
@ -30,19 +30,18 @@ using System.Collections.Generic;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using log4net;
|
using log4net;
|
||||||
using OpenMetaverse;
|
|
||||||
using OpenSim.Framework;
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.RegionLoader.Filesystem;
|
||||||
|
using OpenSim.Framework.RegionLoader.Web;
|
||||||
using OpenSim.Region.CoreModules.Agent.AssetTransaction;
|
using OpenSim.Region.CoreModules.Agent.AssetTransaction;
|
||||||
using OpenSim.Region.CoreModules.Avatar.InstantMessage;
|
using OpenSim.Region.CoreModules.Avatar.InstantMessage;
|
||||||
using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
|
using OpenSim.Region.CoreModules.Scripting.DynamicTexture;
|
||||||
using OpenSim.Region.CoreModules.Scripting.LoadImageURL;
|
using OpenSim.Region.CoreModules.Scripting.LoadImageURL;
|
||||||
using OpenSim.Region.CoreModules.Scripting.XMLRPC;
|
using OpenSim.Region.CoreModules.Scripting.XMLRPC;
|
||||||
using OpenSim.Services.Interfaces;
|
using OpenSim.Framework.Servers;
|
||||||
using Mono.Addins;
|
|
||||||
|
|
||||||
namespace OpenSim.ApplicationPlugins.LoadRegions
|
namespace OpenSim.ApplicationPlugins.LoadRegions
|
||||||
{
|
{
|
||||||
[Extension(Path="/OpenSim/Startup", Id="LoadRegions", NodeName="Plugin")]
|
|
||||||
public class LoadRegionsPlugin : IApplicationPlugin, IRegionCreator
|
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);
|
||||||
|
@ -53,97 +52,75 @@ namespace OpenSim.ApplicationPlugins.LoadRegions
|
||||||
#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;
|
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_openSim = openSim;
|
||||||
m_openSim.ApplicationRegistry.RegisterInterface<IRegionCreator>(this);
|
m_openSim.ApplicationRegistry.RegisterInterface<LoadRegionsPlugin>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void PostInitialise()
|
public void PostInitialise()
|
||||||
{
|
{
|
||||||
//m_log.Info("[LOADREGIONS]: Load Regions addin being initialised");
|
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 (m_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(m_openSim.ConfigSource.Source);
|
||||||
RegionInfo[] regionsToLoad = regionLoader.LoadRegions();
|
RegionInfo[] regionsToLoad = regionLoader.LoadRegions();
|
||||||
|
|
||||||
m_log.Info("[LOAD REGIONS PLUGIN]: Loading specific shared modules...");
|
m_openSim.ModuleLoader.LoadDefaultSharedModule(new DynamicTextureModule());
|
||||||
//m_log.Info("[LOAD REGIONS PLUGIN]: DynamicTextureModule...");
|
m_openSim.ModuleLoader.LoadDefaultSharedModule(new InstantMessageModule());
|
||||||
//m_openSim.ModuleLoader.LoadDefaultSharedModule(new DynamicTextureModule());
|
m_openSim.ModuleLoader.LoadDefaultSharedModule(new LoadImageURLModule());
|
||||||
//m_log.Info("[LOAD REGIONS PLUGIN]: LoadImageURLModule...");
|
m_openSim.ModuleLoader.LoadDefaultSharedModule(new XMLRPCModule());
|
||||||
//m_openSim.ModuleLoader.LoadDefaultSharedModule(new LoadImageURLModule());
|
m_openSim.ModuleLoader.LoadDefaultSharedModule(new AssetTransactionModule());
|
||||||
//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);
|
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;
|
IScene scene;
|
||||||
m_log.Debug("[LOAD REGIONS PLUGIN]: Creating Region: " + regionsToLoad[i].RegionName + " (ThreadID: " +
|
m_log.Debug("[LOADREGIONS]: Creating Region: " + regionsToLoad[i].RegionName + " (ThreadID: " + Thread.CurrentThread.ManagedThreadId.ToString() +
|
||||||
Thread.CurrentThread.ManagedThreadId.ToString() +
|
|
||||||
")");
|
")");
|
||||||
|
|
||||||
bool changed = m_openSim.PopulateRegionEstateInfo(regionsToLoad[i]);
|
|
||||||
|
|
||||||
m_openSim.CreateRegion(regionsToLoad[i], true, out scene);
|
m_openSim.CreateRegion(regionsToLoad[i], true, out scene);
|
||||||
createdScenes.Add(scene);
|
if (scene != null)
|
||||||
|
|
||||||
if (changed)
|
|
||||||
m_openSim.EstateDataService.StoreEstateSettings(regionsToLoad[i].EstateSettings);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (IScene scene in createdScenes)
|
|
||||||
{
|
|
||||||
scene.Start();
|
|
||||||
|
|
||||||
m_newRegionCreatedHandler = OnNewRegionCreated;
|
|
||||||
if (m_newRegionCreatedHandler != null)
|
|
||||||
{
|
{
|
||||||
m_newRegionCreatedHandler(scene);
|
m_newRegionCreatedHandler = OnNewRegionCreated;
|
||||||
|
if (m_newRegionCreatedHandler != null)
|
||||||
|
{
|
||||||
|
m_newRegionCreatedHandler(scene);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_openSim.ModuleLoader.PostInitialise();
|
||||||
|
m_openSim.ModuleLoader.ClearCache();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
|
@ -159,44 +136,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 +174,35 @@ 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)
|
||||||
|
{
|
||||||
|
IScene scene;
|
||||||
|
m_log.Debug("[LOADREGIONS]: Creating Region: " + regionsToLoad[i].RegionName + " (ThreadID: " +
|
||||||
|
Thread.CurrentThread.ManagedThreadId.ToString() + ")");
|
||||||
|
openSim.CreateRegion(regionsToLoad[i], true, out scene);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,17 +27,16 @@
|
||||||
|
|
||||||
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("http://opensimulator.org")]
|
||||||
[assembly : AssemblyProduct("OpenSim")]
|
[assembly : AssemblyProduct("OpenSim.Addin")]
|
||||||
[assembly : AssemblyCopyright("Copyright © OpenSimulator.org Developers 2007-2009")]
|
[assembly : AssemblyCopyright("Copyright © OpenSimulator.org Developers 2007-2009")]
|
||||||
[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("0.6.3.*")]
|
||||||
|
|
||||||
[assembly : AssemblyVersion(OpenSim.VersionInfo.AssemblyVersionNumber)]
|
[assembly : AssemblyVersion("0.6.3.*")]
|
||||||
|
[assembly : AssemblyFileVersion("1.0.0.0")]
|
||||||
[assembly: Addin("OpenSim.ApplicationPlugins.LoadRegions", OpenSim.VersionInfo.VersionNumber)]
|
|
||||||
[assembly: AddinDependency("OpenSim", OpenSim.VersionInfo.VersionNumber)]
|
|
|
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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>
|
|
@ -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)]
|
|
|
@ -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
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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)]
|
|
File diff suppressed because it is too large
Load Diff
|
@ -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>
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* 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.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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,59 @@
|
||||||
|
/*
|
||||||
|
* 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 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
|
@ -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>
|
|
@ -0,0 +1,527 @@
|
||||||
|
/*
|
||||||
|
* 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.Framework;
|
||||||
|
using OpenSim.Framework.Communications;
|
||||||
|
|
||||||
|
namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||||
|
{
|
||||||
|
public class Rest
|
||||||
|
{
|
||||||
|
internal static readonly ILog Log =
|
||||||
|
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
internal static bool DEBUG = Log.IsDebugEnabled;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Supported authentication schemes
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
public const string AS_BASIC = "Basic"; // simple user/password verification
|
||||||
|
public const string AS_DIGEST = "Digest"; // password safe authentication
|
||||||
|
|
||||||
|
/// Supported Digest algorithms
|
||||||
|
|
||||||
|
public const string Digest_MD5 = "MD5"; // assumed default if omitted
|
||||||
|
public const string Digest_MD5Sess = "MD5-sess"; // session-span - not good for REST?
|
||||||
|
|
||||||
|
public const string Qop_Auth = "auth"; // authentication only
|
||||||
|
public const string Qop_Int = "auth-int"; // TODO
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// These values have a single value for the whole
|
||||||
|
/// domain and lifetime of the plugin handler. We
|
||||||
|
/// make them static for ease of reference within
|
||||||
|
/// the assembly. These are initialized by the
|
||||||
|
/// RestHandler class during start-up.
|
||||||
|
/// </summary>
|
||||||
|
|
||||||
|
internal static IRestHandler Plugin = null;
|
||||||
|
internal static OpenSimBase main = null;
|
||||||
|
internal static CommunicationsManager Comms = null;
|
||||||
|
internal static IInventoryServices InventoryServices = null;
|
||||||
|
internal static IUserService UserServices = null;
|
||||||
|
internal static IAvatarService AvatarServices = null;
|
||||||
|
internal static IAssetCache 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[DumpLineSize];
|
||||||
|
int cc = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < data.Length; i++)
|
||||||
|
{
|
||||||
|
if (i % DumpLineSize == 0) Console.Write("\n{0}: ",i.ToString("d8"));
|
||||||
|
|
||||||
|
if (i % 4 == 0) Console.Write(" ");
|
||||||
|
|
||||||
|
Console.Write("{0}",data[i].ToString("x2"));
|
||||||
|
|
||||||
|
if (data[i] < 127 && data[i] > 31)
|
||||||
|
buffer[i % DumpLineSize] = (char) data[i];
|
||||||
|
else
|
||||||
|
buffer[i % DumpLineSize] = '.';
|
||||||
|
|
||||||
|
cc++;
|
||||||
|
|
||||||
|
if (i != 0 && (i + 1) % DumpLineSize == 0)
|
||||||
|
{
|
||||||
|
Console.Write(" |"+(new String(buffer))+"|");
|
||||||
|
cc = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finish off any incomplete line
|
||||||
|
|
||||||
|
if (cc != 0)
|
||||||
|
{
|
||||||
|
for (int i = cc ; i < DumpLineSize; i++)
|
||||||
|
{
|
||||||
|
if (i % 4 == 0) Console.Write(" ");
|
||||||
|
Console.Write(" ");
|
||||||
|
buffer[i % DumpLineSize] = ' ';
|
||||||
|
}
|
||||||
|
Console.WriteLine(" |"+(new String(buffer))+"|");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Console.Write("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Local exception type
|
||||||
|
|
||||||
|
public class RestException : Exception
|
||||||
|
{
|
||||||
|
internal int statusCode;
|
||||||
|
internal string statusDesc;
|
||||||
|
internal string httpmethod;
|
||||||
|
internal string httppath;
|
||||||
|
|
||||||
|
public RestException(string msg) : base(msg)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,866 @@
|
||||||
|
/*
|
||||||
|
* 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.Xml;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.Servers;
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,396 @@
|
||||||
|
/*
|
||||||
|
* 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.Xml;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.Servers;
|
||||||
|
|
||||||
|
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);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,664 @@
|
||||||
|
/*
|
||||||
|
* 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.Servers;
|
||||||
|
|
||||||
|
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
|
@ -0,0 +1,245 @@
|
||||||
|
/*
|
||||||
|
* 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.Servers;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
/*
|
||||||
|
* 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.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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,208 @@
|
||||||
|
/*
|
||||||
|
* 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 OpenMetaverse;
|
||||||
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
|
||||||
|
namespace OpenSim.ApplicationPlugins.Rest.Inventory.Tests
|
||||||
|
{
|
||||||
|
public class Remote : ITest
|
||||||
|
{
|
||||||
|
private static readonly int PARM_TESTID = 0;
|
||||||
|
private static readonly int PARM_COMMAND = 1;
|
||||||
|
|
||||||
|
private static readonly int PARM_MOVE_AVATAR = 2;
|
||||||
|
private static readonly int PARM_MOVE_X = 3;
|
||||||
|
private static readonly int PARM_MOVE_Y = 4;
|
||||||
|
private static readonly int PARM_MOVE_Z = 5;
|
||||||
|
|
||||||
|
private bool enabled = false;
|
||||||
|
|
||||||
|
// No constructor code is required.
|
||||||
|
|
||||||
|
public Remote()
|
||||||
|
{
|
||||||
|
Rest.Log.InfoFormat("{0} Remote services constructor", MsgId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Post-construction, pre-enabled initialization opportunity
|
||||||
|
// Not currently exploited.
|
||||||
|
|
||||||
|
public void Initialize()
|
||||||
|
{
|
||||||
|
enabled = true;
|
||||||
|
Rest.Log.InfoFormat("{0} Remote services initialized", MsgId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Called by the plug-in to halt REST processing. Local processing is
|
||||||
|
// disabled, and control blocks until all current processing has
|
||||||
|
// completed. No new processing will be started
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
enabled = false;
|
||||||
|
Rest.Log.InfoFormat("{0} Remote services closing down", MsgId);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Properties
|
||||||
|
|
||||||
|
internal string MsgId
|
||||||
|
{
|
||||||
|
get { return Rest.MsgId; }
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remote Handler
|
||||||
|
// Key information of interest here is the Parameters array, each
|
||||||
|
// entry represents an element of the URI, with element zero being
|
||||||
|
// the
|
||||||
|
|
||||||
|
public void Execute(RequestData rdata)
|
||||||
|
{
|
||||||
|
if (!enabled) return;
|
||||||
|
|
||||||
|
// If we can't relate to what's there, leave it for others.
|
||||||
|
|
||||||
|
if (rdata.Parameters.Length == 0 || rdata.Parameters[PARM_TESTID] != "remote")
|
||||||
|
return;
|
||||||
|
|
||||||
|
Rest.Log.DebugFormat("{0} REST Remote handler ENTRY", MsgId);
|
||||||
|
|
||||||
|
// Remove the prefix and what's left are the parameters. If we don't have
|
||||||
|
// the parameters we need, fail the request. Parameters do NOT include
|
||||||
|
// any supplied query values.
|
||||||
|
|
||||||
|
if (rdata.Parameters.Length > 1)
|
||||||
|
{
|
||||||
|
switch (rdata.Parameters[PARM_COMMAND].ToLower())
|
||||||
|
{
|
||||||
|
case "move" :
|
||||||
|
DoMove(rdata);
|
||||||
|
break;
|
||||||
|
default :
|
||||||
|
DoHelp(rdata);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DoHelp(rdata);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoHelp(RequestData rdata)
|
||||||
|
{
|
||||||
|
rdata.body = Help;
|
||||||
|
rdata.Complete();
|
||||||
|
rdata.Respond("Help");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DoMove(RequestData rdata)
|
||||||
|
{
|
||||||
|
if (rdata.Parameters.Length >= 6)
|
||||||
|
{
|
||||||
|
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>"
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,215 @@
|
||||||
|
/*
|
||||||
|
* 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.IO;
|
||||||
|
using System.Xml.Serialization;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Framework.Servers;
|
||||||
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
|
||||||
|
namespace OpenSim.ApplicationPlugins.Rest.Regions
|
||||||
|
{
|
||||||
|
public partial class RestRegionPlugin : RestPlugin
|
||||||
|
{
|
||||||
|
#region GET methods
|
||||||
|
public string GetHandler(string request, string path, string param,
|
||||||
|
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 "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,117 @@
|
||||||
|
/*
|
||||||
|
* 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.IO;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Framework.Servers;
|
||||||
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
|
||||||
|
namespace OpenSim.ApplicationPlugins.Rest.Regions
|
||||||
|
{
|
||||||
|
|
||||||
|
public partial class RestRegionPlugin : RestPlugin
|
||||||
|
{
|
||||||
|
#region POST methods
|
||||||
|
public string PostHandler(string request, string path, string param,
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,105 @@
|
||||||
|
/*
|
||||||
|
* 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.Xml.Serialization;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
|
||||||
|
namespace OpenSim.ApplicationPlugins.Rest.Regions
|
||||||
|
{
|
||||||
|
[XmlRoot(ElementName="region", IsNullable = false)]
|
||||||
|
public class RegionDetails
|
||||||
|
{
|
||||||
|
public string region_name;
|
||||||
|
public string region_id;
|
||||||
|
public uint region_x;
|
||||||
|
public uint region_y;
|
||||||
|
public string region_owner;
|
||||||
|
public string region_owner_id;
|
||||||
|
public uint region_http_port;
|
||||||
|
public uint region_port;
|
||||||
|
public string region_server_uri;
|
||||||
|
public string region_external_hostname;
|
||||||
|
|
||||||
|
public RegionDetails()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public RegionDetails(RegionInfo regInfo)
|
||||||
|
{
|
||||||
|
region_name = regInfo.RegionName;
|
||||||
|
region_id = regInfo.RegionID.ToString();
|
||||||
|
region_x = regInfo.RegionLocX;
|
||||||
|
region_y = regInfo.RegionLocY;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -0,0 +1,92 @@
|
||||||
|
/*
|
||||||
|
* 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.Xml.Serialization;
|
||||||
|
|
||||||
|
namespace OpenSim.ApplicationPlugins.Rest.Regions
|
||||||
|
{
|
||||||
|
public partial class RestRegionPlugin : RestPlugin
|
||||||
|
{
|
||||||
|
private static XmlSerializerNamespaces _xmlNs;
|
||||||
|
|
||||||
|
static RestRegionPlugin()
|
||||||
|
{
|
||||||
|
_xmlNs = new XmlSerializerNamespaces();
|
||||||
|
_xmlNs.Add(String.Empty, String.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region overriding properties
|
||||||
|
public override string Name
|
||||||
|
{
|
||||||
|
get { return "REGION"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public override string ConfigName
|
||||||
|
{
|
||||||
|
get { return "RestRegionPlugin"; }
|
||||||
|
}
|
||||||
|
#endregion overriding properties
|
||||||
|
|
||||||
|
#region overriding methods
|
||||||
|
/// <summary>
|
||||||
|
/// This method is called by OpenSimMain immediately after loading the
|
||||||
|
/// plugin and after basic server setup, but before running any server commands.
|
||||||
|
/// </summary>
|
||||||
|
/// <remarks>
|
||||||
|
/// Note that entries MUST be added to the active configuration files before
|
||||||
|
/// the plugin can be enabled.
|
||||||
|
/// </remarks>
|
||||||
|
public override void Initialise(OpenSimBase openSim)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
base.Initialise(openSim);
|
||||||
|
if (!IsEnabled)
|
||||||
|
{
|
||||||
|
m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_log.InfoFormat("{0} REST region plugin enabled", MsgID);
|
||||||
|
|
||||||
|
// add REST method handlers
|
||||||
|
AddRestStreamHandler("GET", "/regions/", GetHandler);
|
||||||
|
AddRestStreamHandler("POST", "/regions/", PostHandler);
|
||||||
|
}
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,407 @@
|
||||||
|
/*
|
||||||
|
* 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 System.Xml;
|
||||||
|
using log4net;
|
||||||
|
using Nini.Config;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Framework.Servers;
|
||||||
|
|
||||||
|
namespace OpenSim.ApplicationPlugins.Rest
|
||||||
|
{
|
||||||
|
public abstract class RestPlugin : IApplicationPlugin
|
||||||
|
{
|
||||||
|
#region properties
|
||||||
|
|
||||||
|
protected static readonly ILog m_log =
|
||||||
|
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
private IConfig _config; // Configuration source: Rest Plugins
|
||||||
|
private IConfig _pluginConfig; // Configuration source: Plugin specific
|
||||||
|
private OpenSimBase _app; // The 'server'
|
||||||
|
private BaseHttpServer _httpd; // The server's RPC interface
|
||||||
|
private string _prefix; // URL prefix below
|
||||||
|
// which all REST URLs
|
||||||
|
// are living
|
||||||
|
private StringWriter _sw = null;
|
||||||
|
private RestXmlWriter _xw = null;
|
||||||
|
|
||||||
|
private string _godkey;
|
||||||
|
private int _reqk;
|
||||||
|
|
||||||
|
[ThreadStatic]
|
||||||
|
private static string _threadRequestID = String.Empty;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return an ever increasing request ID for logging
|
||||||
|
/// </summary>
|
||||||
|
protected string RequestID
|
||||||
|
{
|
||||||
|
get { return _reqk++.ToString(); }
|
||||||
|
set { _reqk = Convert.ToInt32(value); }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Thread-constant message IDs for logging.
|
||||||
|
/// </summary>
|
||||||
|
protected string MsgID
|
||||||
|
{
|
||||||
|
get { return String.Format("[REST-{0}] #{1}", Name, _threadRequestID); }
|
||||||
|
set { _threadRequestID = value; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if Rest Plugins are enabled.
|
||||||
|
/// </summary>
|
||||||
|
public bool PluginsAreEnabled
|
||||||
|
{
|
||||||
|
get { return null != _config; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Returns true if specific Rest Plugin is enabled.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsEnabled
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return (null != _pluginConfig) && _pluginConfig.GetBoolean("enabled", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// OpenSimMain application
|
||||||
|
/// </summary>
|
||||||
|
public OpenSimBase App
|
||||||
|
{
|
||||||
|
get { return _app; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// RPC server
|
||||||
|
/// </summary>
|
||||||
|
public BaseHttpServer HttpServer
|
||||||
|
{
|
||||||
|
get { return _httpd; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// URL prefix to use for all REST handlers
|
||||||
|
/// </summary>
|
||||||
|
public string Prefix
|
||||||
|
{
|
||||||
|
get { return _prefix; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Access to GOD password string
|
||||||
|
/// </summary>
|
||||||
|
protected string GodKey
|
||||||
|
{
|
||||||
|
get { return _godkey; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configuration of the plugin
|
||||||
|
/// </summary>
|
||||||
|
public IConfig Config
|
||||||
|
{
|
||||||
|
get { return _pluginConfig; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Name of the plugin
|
||||||
|
/// </summary>
|
||||||
|
public abstract string Name { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Return the config section name
|
||||||
|
/// </summary>
|
||||||
|
public abstract string ConfigName { get; }
|
||||||
|
|
||||||
|
public XmlTextWriter XmlWriter
|
||||||
|
{
|
||||||
|
get {
|
||||||
|
if (null == _xw)
|
||||||
|
{
|
||||||
|
_sw = new StringWriter();
|
||||||
|
_xw = new RestXmlWriter(_sw);
|
||||||
|
_xw.Formatting = Formatting.Indented;
|
||||||
|
}
|
||||||
|
return _xw; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string XmlWriterResult
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
_xw.Flush();
|
||||||
|
_xw.Close();
|
||||||
|
_xw = null;
|
||||||
|
|
||||||
|
return _sw.ToString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion properties
|
||||||
|
|
||||||
|
|
||||||
|
#region methods
|
||||||
|
// TODO: required by IPlugin, but likely not at all right
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public virtual void PostInitialise()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<RestStreamHandler> _handlers = new List<RestStreamHandler>();
|
||||||
|
private Dictionary<string, IHttpAgentHandler> _agents = new Dictionary<string, IHttpAgentHandler>();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a REST stream handler to the underlying HTTP server.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="httpMethod">GET/PUT/POST/DELETE or
|
||||||
|
/// similar</param>
|
||||||
|
/// <param name="path">URL prefix</param>
|
||||||
|
/// <param name="method">RestMethod handler doing the actual work</param>
|
||||||
|
public virtual void AddRestStreamHandler(string httpMethod, string path, RestMethod method)
|
||||||
|
{
|
||||||
|
if (!IsEnabled) return;
|
||||||
|
|
||||||
|
if (!path.StartsWith(_prefix))
|
||||||
|
{
|
||||||
|
path = String.Format("{0}{1}", _prefix, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
RestStreamHandler h = new RestStreamHandler(httpMethod, path, method);
|
||||||
|
_httpd.AddStreamHandler(h);
|
||||||
|
_handlers.Add(h);
|
||||||
|
|
||||||
|
m_log.DebugFormat("{0} Added REST handler {1} {2}", MsgID, httpMethod, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Add a powerful Agent handler to the underlying HTTP
|
||||||
|
/// server.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="agentName">name of agent handler</param>
|
||||||
|
/// <param name="handler">agent handler method</param>
|
||||||
|
/// <returns>false when the plugin is disabled or the agent
|
||||||
|
/// handler could not be added. Any generated exceptions are
|
||||||
|
/// allowed to drop through to the caller, i.e. ArgumentException.
|
||||||
|
/// </returns>
|
||||||
|
public bool AddAgentHandler(string agentName, IHttpAgentHandler handler)
|
||||||
|
{
|
||||||
|
if (!IsEnabled) return false;
|
||||||
|
_agents.Add(agentName, handler);
|
||||||
|
return _httpd.AddAgentHandler(agentName, handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <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
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
using System.Reflection;
|
||||||
|
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("http://opensimulator.org")]
|
||||||
|
[assembly: AssemblyProduct("OpenSim.ApplicationPlugins.ScriptEngine")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright (c) OpenSimulator.org Developers 2007-2009")]
|
||||||
|
[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("0.6.3.*")]
|
||||||
|
[assembly: AssemblyVersion("0.6.3.*")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,119 @@
|
||||||
|
/*
|
||||||
|
* 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.Reflection;
|
||||||
|
using log4net;
|
||||||
|
using Nini.Config;
|
||||||
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
|
using OpenSim.Region.Framework.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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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>
|
|
@ -0,0 +1,106 @@
|
||||||
|
/*
|
||||||
|
* 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.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();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PostInitialise()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#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
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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); ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*/
|
|
|
@ -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)]
|
|
||||||
|
|
|
@ -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";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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);
|
|
||||||
}
|
|
|
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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")]
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,114 @@
|
||||||
|
/*
|
||||||
|
* 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.Text;
|
||||||
|
using System.Timers;
|
||||||
|
using MXP;
|
||||||
|
using Nini.Config;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Client.MXP.PacketHandler;
|
||||||
|
using OpenSim.Region.Framework.Interfaces;
|
||||||
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
|
||||||
|
namespace OpenSim.Client.MXP
|
||||||
|
{
|
||||||
|
public class MXPModule : IRegionModule
|
||||||
|
{
|
||||||
|
private int mxp_Port = 1253;
|
||||||
|
//private double mxp_BubbleRadius = 181.01933598375616624661615669884; // Radius of a sphere big enough to encapsulate a 256x256 square
|
||||||
|
|
||||||
|
private readonly Timer ticker = new Timer(100);
|
||||||
|
|
||||||
|
private int ticks;
|
||||||
|
private bool shutdown = false;
|
||||||
|
|
||||||
|
private IConfigSource config;
|
||||||
|
|
||||||
|
private readonly Dictionary<UUID,Scene> m_scenes = new Dictionary<UUID, Scene>();
|
||||||
|
|
||||||
|
private MXPPacketServer server;
|
||||||
|
|
||||||
|
|
||||||
|
public void Initialise(Scene scene, IConfigSource source)
|
||||||
|
{
|
||||||
|
if (!m_scenes.ContainsKey(scene.RegionInfo.RegionID))
|
||||||
|
m_scenes.Add(scene.RegionInfo.RegionID, scene);
|
||||||
|
config = source;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PostInitialise()
|
||||||
|
{
|
||||||
|
if (config.Configs["MXP"] != null)
|
||||||
|
{
|
||||||
|
IConfig con = config.Configs["MXP"];
|
||||||
|
|
||||||
|
if (!con.GetBoolean("Enabled", false))
|
||||||
|
return;
|
||||||
|
|
||||||
|
mxp_Port = con.GetInt("Port", mxp_Port);
|
||||||
|
|
||||||
|
server = new MXPPacketServer("http://null", mxp_Port, m_scenes);
|
||||||
|
|
||||||
|
ticker.AutoReset = false;
|
||||||
|
ticker.Elapsed += ticker_Elapsed;
|
||||||
|
|
||||||
|
ticker.Start();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ticker_Elapsed(object sender, ElapsedEventArgs e)
|
||||||
|
{
|
||||||
|
server.Process();
|
||||||
|
|
||||||
|
if (!shutdown)
|
||||||
|
ticker.Start();
|
||||||
|
|
||||||
|
if (++ticks % 100 == 0)
|
||||||
|
{
|
||||||
|
server.PrintDebugInformation();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Close()
|
||||||
|
{
|
||||||
|
shutdown = true;
|
||||||
|
ticker.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
public string Name
|
||||||
|
{
|
||||||
|
get { return "MXP ClientStack Module"; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool IsSharedModule
|
||||||
|
{
|
||||||
|
get { return true; }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,42 @@
|
||||||
|
/*
|
||||||
|
* 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.Text;
|
||||||
|
using OpenMetaverse;
|
||||||
|
|
||||||
|
namespace OpenSim.Client.MXP
|
||||||
|
{
|
||||||
|
static class MXPUtil
|
||||||
|
{
|
||||||
|
public static string GenerateMXPURL(string server, int port, UUID bubbleID, Vector3 location)
|
||||||
|
{
|
||||||
|
return string.Format("mxp://{0}:{1}/{2}/{3}", server, port, bubbleID.Guid, location);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,481 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* This file borrows heavily from MXPServer.cs - the reference MXPServer
|
||||||
|
* See http://www.bubblecloud.org for a copy of the original file and
|
||||||
|
* implementation details. */
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Threading;
|
||||||
|
using log4net;
|
||||||
|
using MXP;
|
||||||
|
using MXP.Messages;
|
||||||
|
using OpenMetaverse;
|
||||||
|
using OpenSim.Client.MXP.ClientStack;
|
||||||
|
using OpenSim.Framework;
|
||||||
|
using OpenSim.Region.Framework.Scenes;
|
||||||
|
|
||||||
|
namespace OpenSim.Client.MXP.PacketHandler
|
||||||
|
{
|
||||||
|
class MXPPacketServer
|
||||||
|
{
|
||||||
|
internal static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||||
|
|
||||||
|
private readonly List<MXPClientView> Clients = new List<MXPClientView>();
|
||||||
|
private readonly Dictionary<UUID, Scene> Scenes;
|
||||||
|
|
||||||
|
#region Fields
|
||||||
|
|
||||||
|
private readonly Transmitter transmitter;
|
||||||
|
|
||||||
|
private readonly Thread m_clientThread;
|
||||||
|
|
||||||
|
private readonly IList<Session> sessions = new List<Session>();
|
||||||
|
private readonly IList<Session> sessionsToClient = new List<Session>();
|
||||||
|
private readonly IList<MXPClientView> sessionsToRemove = new List<MXPClientView>();
|
||||||
|
|
||||||
|
private readonly String cloudUrl;
|
||||||
|
private readonly String programName;
|
||||||
|
private readonly byte programMajorVersion;
|
||||||
|
private readonly byte programMinorVersion;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public MXPPacketServer(string cloudUrl, int port, Dictionary<UUID, Scene> scenes)
|
||||||
|
{
|
||||||
|
this.cloudUrl = cloudUrl;
|
||||||
|
|
||||||
|
Scenes = scenes;
|
||||||
|
|
||||||
|
programMinorVersion = 63;
|
||||||
|
programMajorVersion = 0;
|
||||||
|
programName = "OpenSimulator";
|
||||||
|
|
||||||
|
transmitter = new Transmitter(port);
|
||||||
|
|
||||||
|
m_clientThread = new Thread(StartListener);
|
||||||
|
m_clientThread.Name = "MXPThread";
|
||||||
|
m_clientThread.IsBackground = true;
|
||||||
|
m_clientThread.Start();
|
||||||
|
ThreadTracker.Add(m_clientThread);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void StartListener()
|
||||||
|
{
|
||||||
|
transmitter.Startup();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Number of sessions pending. (Process() accepts pending sessions).
|
||||||
|
/// </summary>
|
||||||
|
public int PendingSessionCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return transmitter.PendingSessionCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Number of connected sessions.
|
||||||
|
/// </summary>
|
||||||
|
public int SessionCount
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return sessions.Count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Property reflecting whether client transmitter threads are alive.
|
||||||
|
/// </summary>
|
||||||
|
public bool IsTransmitterAlive
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return transmitter != null && transmitter.IsAlive;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Number of packets sent.
|
||||||
|
/// </summary>
|
||||||
|
public ulong PacketsSent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return transmitter != null ? transmitter.PacketsSent : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Number of packets received.
|
||||||
|
/// </summary>
|
||||||
|
public ulong PacketsReceived
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return transmitter != null ? transmitter.PacketsReceived : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Bytes client has received so far.
|
||||||
|
/// </summary>
|
||||||
|
public ulong BytesReceived
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return transmitter != null ? transmitter.BytesReceived : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Bytes client has sent so far.
|
||||||
|
/// </summary>
|
||||||
|
public ulong BytesSent
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return transmitter != null ? transmitter.BytesSent : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Number of bytes received (bytes per second) during past second.
|
||||||
|
/// </summary>
|
||||||
|
public double ReceiveRate
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return transmitter != null ? transmitter.ReceiveRate : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// <summary>
|
||||||
|
/// Number of bytes sent (bytes per second) during past second.
|
||||||
|
/// </summary>
|
||||||
|
public double SendRate
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
return transmitter != null ? transmitter.SendRate : 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Session Management
|
||||||
|
|
||||||
|
public void Disconnect(Session session)
|
||||||
|
{
|
||||||
|
if (session.IsConnected)
|
||||||
|
{
|
||||||
|
Message message = MessageFactory.Current.ReserveMessage(typeof(LeaveRequestMessage));
|
||||||
|
session.Send(message);
|
||||||
|
MessageFactory.Current.ReleaseMessage(message);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw new Exception("Not connected.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
|
||||||
|
#region Processing
|
||||||
|
|
||||||
|
public void PrintDebugInformation()
|
||||||
|
{
|
||||||
|
m_log.Info("[MXP ClientStack] Statistics report");
|
||||||
|
m_log.Info("Pending Sessions: " + PendingSessionCount);
|
||||||
|
m_log.Info("Sessions: " + SessionCount + " (Clients: " + Clients.Count + " )");
|
||||||
|
m_log.Info("Transmitter Alive?: " + IsTransmitterAlive);
|
||||||
|
m_log.Info("Packets Sent/Received: " + PacketsSent + " / " + PacketsReceived);
|
||||||
|
m_log.Info("Bytes Sent/Received: " + BytesSent + " / " + BytesReceived);
|
||||||
|
m_log.Info("Send/Recieve Rate (bps): " + SendRate + " / " + ReceiveRate);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Process()
|
||||||
|
{
|
||||||
|
ProcessMessages();
|
||||||
|
Clean();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Clean()
|
||||||
|
{
|
||||||
|
foreach (MXPClientView clientView in Clients)
|
||||||
|
{
|
||||||
|
if (clientView.Session.SessionState == SessionState.Disconnected)
|
||||||
|
{
|
||||||
|
sessionsToRemove.Add(clientView);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (MXPClientView clientView in sessionsToRemove)
|
||||||
|
{
|
||||||
|
clientView.Scene.RemoveClient(clientView.AgentId);
|
||||||
|
Clients.Remove(clientView);
|
||||||
|
sessions.Remove(clientView.Session);
|
||||||
|
}
|
||||||
|
|
||||||
|
sessionsToRemove.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool AuthoriseUser(string participantName, string password, UUID sceneId, out UUID userId, out string firstName, out string lastName)
|
||||||
|
{
|
||||||
|
userId = UUID.Zero;
|
||||||
|
firstName = "";
|
||||||
|
lastName = "";
|
||||||
|
|
||||||
|
if (!Scenes.ContainsKey(sceneId))
|
||||||
|
{
|
||||||
|
m_log.Info("Login failed as region was not found: " + sceneId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
string[] nameParts=participantName.Split(' ');
|
||||||
|
if(nameParts.Length!=2)
|
||||||
|
{
|
||||||
|
m_log.Info("Login failed as user name is not formed of first and last name separated by space: " + participantName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
firstName = nameParts[0];
|
||||||
|
lastName = nameParts[1];
|
||||||
|
|
||||||
|
UserProfileData userProfile = Scenes[sceneId].CommsManager.UserService.GetUserProfile(firstName, lastName);
|
||||||
|
if (userProfile == null)
|
||||||
|
{
|
||||||
|
m_log.Info("Login failed as user was not found: " + participantName);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
userId = userProfile.ID;
|
||||||
|
|
||||||
|
if (!password.StartsWith("$1$"))
|
||||||
|
{
|
||||||
|
password = "$1$" + Util.Md5Hash(password);
|
||||||
|
}
|
||||||
|
password = password.Remove(0, 3); //remove $1$
|
||||||
|
string s = Util.Md5Hash(password + ":" + userProfile.PasswordSalt);
|
||||||
|
return (userProfile.PasswordHash.Equals(s.ToString(), StringComparison.InvariantCultureIgnoreCase)
|
||||||
|
|| userProfile.PasswordHash.Equals(password, StringComparison.InvariantCultureIgnoreCase));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void ProcessMessages()
|
||||||
|
{
|
||||||
|
if (transmitter.PendingSessionCount > 0)
|
||||||
|
{
|
||||||
|
Session tmp = transmitter.AcceptPendingSession();
|
||||||
|
sessions.Add(tmp);
|
||||||
|
sessionsToClient.Add(tmp);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
List<Session> tmpRemove = new List<Session>();
|
||||||
|
|
||||||
|
foreach (Session session in sessionsToClient)
|
||||||
|
{
|
||||||
|
while (session.AvailableMessages > 0)
|
||||||
|
{
|
||||||
|
Message message = session.Receive();
|
||||||
|
|
||||||
|
if (message.GetType() == typeof (JoinRequestMessage))
|
||||||
|
{
|
||||||
|
|
||||||
|
JoinRequestMessage joinRequestMessage = (JoinRequestMessage) message;
|
||||||
|
|
||||||
|
UUID userId;
|
||||||
|
string firstName;
|
||||||
|
string lastName;
|
||||||
|
|
||||||
|
bool authorized = AuthoriseUser(joinRequestMessage.ParticipantName,
|
||||||
|
joinRequestMessage.ParticipantPassphrase,
|
||||||
|
new UUID(joinRequestMessage.BubbleId), out userId, out firstName, out lastName);
|
||||||
|
|
||||||
|
if (authorized)
|
||||||
|
{
|
||||||
|
Scene target = Scenes[new UUID(joinRequestMessage.BubbleId)];
|
||||||
|
|
||||||
|
UUID mxpSessionID = UUID.Random();
|
||||||
|
|
||||||
|
m_log.Info("[MXP ClientStack] Session join request success: " + session.SessionId + " (" +
|
||||||
|
(session.IsIncoming ? "from" : "to") + " " + session.RemoteEndPoint.Address + ":" +
|
||||||
|
session.RemoteEndPoint.Port + ")");
|
||||||
|
|
||||||
|
AcceptConnection(session, joinRequestMessage, mxpSessionID,userId);
|
||||||
|
|
||||||
|
MXPClientView client = new MXPClientView(session, mxpSessionID,userId, target,
|
||||||
|
firstName, lastName);
|
||||||
|
m_log.Info("[MXP ClientStack] Created Client");
|
||||||
|
Clients.Add(client);
|
||||||
|
|
||||||
|
m_log.Info("[MXP ClientStack] Adding to Scene");
|
||||||
|
target.ClientManager.Add(client.CircuitCode, client);
|
||||||
|
|
||||||
|
m_log.Info("[MXP ClientStack] Initialising...");
|
||||||
|
try
|
||||||
|
{
|
||||||
|
client.Start();
|
||||||
|
} catch( Exception e)
|
||||||
|
{
|
||||||
|
m_log.Info(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_log.Info("[MXP ClientStack] Connected");
|
||||||
|
//target.EventManager.TriggerOnNewClient(client);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_log.Info("[MXP ClientStack] Session join request failure: " + session.SessionId + " (" +
|
||||||
|
(session.IsIncoming ? "from" : "to") + " " + session.RemoteEndPoint.Address + ":" +
|
||||||
|
session.RemoteEndPoint.Port + ")");
|
||||||
|
|
||||||
|
DeclineConnection(session, joinRequestMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpRemove.Add(session);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (Session session in tmpRemove)
|
||||||
|
{
|
||||||
|
sessionsToClient.Remove(session);
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (MXPClientView clientView in Clients)
|
||||||
|
{
|
||||||
|
|
||||||
|
int messagesProcessedCount = 0;
|
||||||
|
Session session = clientView.Session;
|
||||||
|
|
||||||
|
while (session.AvailableMessages > 0)
|
||||||
|
{
|
||||||
|
Message message = session.Receive();
|
||||||
|
|
||||||
|
if (message.GetType() == typeof(LeaveRequestMessage))
|
||||||
|
{
|
||||||
|
|
||||||
|
LeaveResponseMessage leaveResponseMessage = (LeaveResponseMessage)MessageFactory.Current.ReserveMessage(
|
||||||
|
typeof(LeaveResponseMessage));
|
||||||
|
|
||||||
|
m_log.Info("[MXP ClientStack] Session leave request: " + session.SessionId + " (" + (session.IsIncoming ? "from" : "to") + " " + session.RemoteEndPoint.Address + ":" + session.RemoteEndPoint.Port + ")");
|
||||||
|
|
||||||
|
leaveResponseMessage.RequestMessageId = message.MessageId;
|
||||||
|
leaveResponseMessage.FailureCode = 0;
|
||||||
|
session.Send(leaveResponseMessage);
|
||||||
|
|
||||||
|
if (session.SessionState != SessionState.Disconnected)
|
||||||
|
{
|
||||||
|
session.SetStateDisconnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_log.Info("[MXP ClientStack] Removing Client from Scene");
|
||||||
|
clientView.Scene.RemoveClient(clientView.AgentId);
|
||||||
|
}
|
||||||
|
if (message.GetType() == typeof(LeaveResponseMessage))
|
||||||
|
{
|
||||||
|
|
||||||
|
LeaveResponseMessage leaveResponseMessage = (LeaveResponseMessage)message;
|
||||||
|
|
||||||
|
m_log.Info("[MXP ClientStack] Session leave response: " + session.SessionId + " (" + (session.IsIncoming ? "from" : "to") + " " + session.RemoteEndPoint.Address + ":" + session.RemoteEndPoint.Port + ")");
|
||||||
|
|
||||||
|
if (leaveResponseMessage.FailureCode == 0)
|
||||||
|
{
|
||||||
|
session.SetStateDisconnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
m_log.Info("[MXP ClientStack] Removing Client from Scene");
|
||||||
|
clientView.Scene.RemoveClient(clientView.AgentId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
clientView.ProcessMXPPacket(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
MessageFactory.Current.ReleaseMessage(message);
|
||||||
|
messagesProcessedCount++;
|
||||||
|
if (messagesProcessedCount > 1000)
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void AcceptConnection(Session session, JoinRequestMessage joinRequestMessage, UUID mxpSessionID, UUID userId)
|
||||||
|
{
|
||||||
|
JoinResponseMessage joinResponseMessage = (JoinResponseMessage)MessageFactory.Current.ReserveMessage(
|
||||||
|
typeof(JoinResponseMessage));
|
||||||
|
|
||||||
|
joinResponseMessage.RequestMessageId = joinRequestMessage.MessageId;
|
||||||
|
joinResponseMessage.FailureCode = 0;
|
||||||
|
|
||||||
|
joinResponseMessage.ParticipantId = userId.Guid;
|
||||||
|
joinResponseMessage.CloudUrl = cloudUrl;
|
||||||
|
|
||||||
|
joinResponseMessage.BubbleName = Scenes[new UUID(joinRequestMessage.BubbleId)].RegionInfo.RegionName;
|
||||||
|
|
||||||
|
joinResponseMessage.BubbleRealTime = 0;
|
||||||
|
joinResponseMessage.ProgramName = programName;
|
||||||
|
joinResponseMessage.ProgramMajorVersion = programMajorVersion;
|
||||||
|
joinResponseMessage.ProgramMinorVersion = programMinorVersion;
|
||||||
|
joinResponseMessage.ProtocolMajorVersion = MxpConstants.ProtocolMajorVersion;
|
||||||
|
joinResponseMessage.ProtocolMinorVersion = MxpConstants.ProtocolMinorVersion;
|
||||||
|
|
||||||
|
session.Send(joinResponseMessage);
|
||||||
|
|
||||||
|
session.SetStateConnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeclineConnection(Session session, Message joinRequestMessage)
|
||||||
|
{
|
||||||
|
JoinResponseMessage joinResponseMessage = (JoinResponseMessage)MessageFactory.Current.ReserveMessage(typeof(JoinResponseMessage));
|
||||||
|
|
||||||
|
joinResponseMessage.RequestMessageId = joinRequestMessage.MessageId;
|
||||||
|
joinResponseMessage.FailureCode = 1;
|
||||||
|
|
||||||
|
joinResponseMessage.CloudUrl = cloudUrl;
|
||||||
|
|
||||||
|
joinResponseMessage.BubbleName = "Declined OpenSim Region"; // Dont reveal anything about the sim in the disconnect notice
|
||||||
|
|
||||||
|
joinResponseMessage.BubbleRealTime = 0;
|
||||||
|
joinResponseMessage.ProgramName = programName;
|
||||||
|
joinResponseMessage.ProgramMajorVersion = programMajorVersion;
|
||||||
|
joinResponseMessage.ProgramMinorVersion = programMinorVersion;
|
||||||
|
joinResponseMessage.ProtocolMajorVersion = MxpConstants.ProtocolMajorVersion;
|
||||||
|
joinResponseMessage.ProtocolMinorVersion = MxpConstants.ProtocolMinorVersion;
|
||||||
|
|
||||||
|
session.Send(joinResponseMessage);
|
||||||
|
|
||||||
|
session.SetStateDisconnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
|
@ -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)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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")]
|
|
|
@ -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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -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,10 +25,6 @@
|
||||||
* 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;
|
||||||
|
|
||||||
|
@ -36,17 +32,15 @@ namespace OpenSim.Data
|
||||||
{
|
{
|
||||||
public abstract class AssetDataBase : IAssetDataPlugin
|
public abstract class AssetDataBase : IAssetDataPlugin
|
||||||
{
|
{
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue