Compare commits

...

416 Commits

Author SHA1 Message Date
Robert Adams
511122834b BulletSim: change collision flags for groundplane to not interact with static objects.
Reorder collision flag setting code for terrain to fit pattern used elsewhere.
2013-10-23 16:07:03 -07:00
Justin Clark-Casey (justincc)
4830431eb0 Add current .NET windows framework requirement to README. 2013-10-22 01:02:40 +01:00
Robert Adams
a7e7bed660 BulletSim: update SOs and DLLs with version that enables compressed
AABB maps for Bvh meshes. This greatly reduces the memory usage for
large meshes and for mesh terrain in particular.
2013-10-19 11:44:27 -07:00
Kevin Cozens
84a149ecbf Call ScriptSleep() instead of llSleep() in routine for llEmail.
Signed-off-by: teravus <teravus@gmail.com>
2013-10-18 14:30:05 -05:00
Robert Adams
571a75f934 BulletSim: update lib32/libBulletSim.dylib to current BulletSim C++ API. 2013-10-18 09:15:08 -07:00
Oren Hurvitz
0094971186 After finishing to edit an attachment, let other avatars see the changes. (The changes weren't visible before because updates to attachments aren't sent while the attachment is selected.) 2013-10-17 23:10:16 +01:00
Justin Clark-Casey (justincc)
1bd89ac287 Readding Mono.Security.dll. This comes from http://pgfoundry.org/frs/download.php/3354/Npgsql2.0.12.0-bin-ms.net3.5sp1.zip
This is identical to what was previously there but need to record origin information
2013-10-17 22:31:15 +01:00
Justin Clark-Casey (justincc)
6221356712 Removing Mono.Security.dll temporarily so that it can be re-added with origin information 2013-10-17 22:28:58 +01:00
Fernando Oliveira
67ffb64764 Corrected estateID to EstateID on getEstates function at PGSQLEstateData.cs 2013-10-16 21:58:22 -05:00
Fernando Oliveira
f83343d302 * One More thing, add an appdomain data element to ensure that we don't duplicate the assembly resolving. 2013-10-16 21:20:11 -05:00
Fernando Oliveira
8fdf70b87e * Fixes mantis mantis 0006803 [PGSQL] - Simulator crashes - Mono.Security.dll missing. The root of the issue is that the Postgres driver relies on Mono.Security.dll from the mono project. Unfortunately, when using Mono, including the dll in the distribution causes conflicts. This solution puts Mono.Security.dll in bin/lib/NET/ and, if windows .NET is the runtime, informs the assembly loader to load bin/lib/NET/Mono.Security.dll when .NET is scanning for the Mono.Security namespace. On Mono, the included Mono.Security assembly is ignored. 2013-10-16 20:16:29 -05:00
Robert Adams
766a31431e BulletSim: implement the SL bug where VEHICLE_HOVER_UP_ONLY disables
the vehicle buoyancy if the vehicle is above its hover height.

This is a known misfeature of this vehicle flag which has been accepted
since it would break too many implementations. The problem is noticed
when creating a jetski-like vehicle that jumps over sand bars. A boat
normally is configured with neutral buoyancy and hovering at water
height. When it jumps the sandbar, it needs to have gravity applied
to get back to water level.
2013-10-15 17:02:22 -07:00
Oren Hurvitz
d0c1780839 Fixed rezzing coalesced objects from a prim's inventory
Previously only the first object in the Coalesced Object was rezzed. Now all the objects are rezzed.
2013-10-15 23:59:16 +01:00
Justin Clark-Casey (justincc)
acfe603a5f As discussed on many previous occasions, switch the default physics engine in OpenSimulator from OpenDynamicsEngine to BulletSim.
The BulletSim plugin is higher performance and has a better implementation of vehicles amongst other things.
Many thanks to Robert Adams for making this possible with the enormous amount of work that he has done on this plugin.
If you want to continue using ODE, set physics = OpenDynamicsEngine in the [Startup] section of OpenSim.ini
2013-10-15 23:24:49 +01:00
Justin Clark-Casey (justincc)
d82d6bb1ec Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-10-15 23:18:50 +01:00
Kevin Cozens
5ca7395e17 Added support for attachments to group notices when using Flotsam groups. 2013-10-15 23:07:49 +01:00
fernando
3e1ca2bd21 * Fixes mantis #6802 Simulator crashes whist loading (lighshare enabled)
* Please test
2013-10-15 11:55:08 -05:00
Oren Hurvitz
f106ba87ca Made terrain uploads thread-safe 2013-10-15 00:12:56 +01:00
Justin Clark-Casey (justincc)
a27c2432bb This is Npgsql2.0.12.0-bin-ms-net3.5sp1
From http://pgfoundry.org/frs/download.php/3354/Npgsql2.0.12.0-bin-ms.net3.5sp1.zip
This is identical to the version added in ff8a7682, removed and readded to check and record version
2013-10-14 23:59:49 +01:00
Justin Clark-Casey (justincc)
dbdcf2d995 Remove to re-add with version information for future reference 2013-10-14 23:58:12 +01:00
Michael Cerquoni
daf44cc65e fix missing " for variable SRV_IMServerURI in example file 2013-10-12 20:47:10 -04:00
Fernando Oliveira
ff8a768258 Fernando Oliveira's Postgress SQL Server Data Connector as a single commit.
* Added PostGreSQL support
* Added MySQL/MySQLXGroupData.cs
* PostgreSQL data access implementation
* PostgreSQL dll binarie and RegionStore.migrations
* Migrations Scripts from MSSQL to POSTGRES
* Postgres SQL Type fixes
* Postgres SQL Connection string
* Data type issues
* more fixes
* tests and +tests
* UUID x string - FIGHT!
* Fixed PG types to internal csharp types
* More data type fix (PostgreSQL fields are case sensitive) :(
* more field case sensitive fixes
* changed the migration files to be case sensitive for fields.
* fixed fields case
* finished converting, now search for hidden bugs.
* some more fixes
* bool type fixed
* more case fixes;
* creatorID case fixed
* case fields fixed
* fixed default now() for TMStamp fields with don't allow nulls.
* fix case sensitve for Region name and Estate name
* fixed case for names for search
* fix class name Error
* Bug fixed on select and migrations
* Un-Reverting my change due to Postgres issue with the ILIKE function
* Fixed some issued for Diva Distro
* Fixes for integration with Diva Distro
* Added System.Core to prebuild.xml for PG project
* Configured to make DIff for Push to OpenSim Project
* Diffs only to PostgreSQL mods.
2013-10-12 16:33:45 -05:00
teravus
2eade55471 * pushing test 2013-10-12 15:06:05 -05:00
Robert Adams
8b5e2f2cd2 BulletSim: Fix snap back from edge of region problem. Mantis 6794. 2013-10-11 13:29:43 -07:00
teravus
75f63ecfcd * Add a session concurrency option per key. Allows developer/config to specify number of concurrent requests on a service. 2013-10-09 22:21:25 -05:00
teravus
e7ea053c4a * Remove a test *cleanup* 2013-10-07 23:52:44 -05:00
teravus
1df58d04b1 * Move the BasicDOSProtector.cs to OpenSim.Framework (all useful classes belong there.....)
* Add an IsBlocked(string Key) method so it can be used more generically.   (think..   if we want to rate limit login failures, we could have a call in the Login Service to IsBlocked(uuid.ToString()) and ignore the connection if it returns true, if IsBlocked returns false, we could run the login information and if the login fails we could run the Process method to count the login failures.
2013-10-07 23:48:24 -05:00
teravus
75fdd6054d * Refactor
* Break out common BasicDOSProtector code into separate class.
2013-10-07 23:19:50 -05:00
teravus
f76cc6036e * Added a Basic DOS protection container/base object for the most common HTTP Server handlers. XMLRPC Handler, GenericHttpHandler and <Various>StreamHandler
* Applied the XmlRpcBasicDOSProtector.cs to the login service as both an example, and good practice.
* Applied the BaseStreamHandlerBasicDOSProtector.cs to the friends service as an example of the DOS Protector on StreamHandlers
* Added CircularBuffer, used for CPU and Memory friendly rate monitoring.
* DosProtector has 2 states, 1. Just Check for blocked users and check general velocity, 2. Track velocity per user,     It only jumps to 2 if it's getting a lot of requests, and state 1 is about as resource friendly as if it wasn't even there.
2013-10-07 21:35:55 -05:00
teravus
31246ecd04 * Added a unique and interesting WebSocket grid login processor by hijacking the LLSD login code. This sends the data through the normal login channels and spits out a JSON object back that mimics the login response. Feel free to comment on the best way to set this up as a config option. 2013-10-04 20:53:01 -05:00
teravus
85593d8d25 * Add an initial complete frame timeout to the WebSocket processor to make it easier to write WebSocket service code that is resistant to Denial of Service attacks. 2013-10-04 20:37:59 -05:00
Diva Canto
083eb7679b Added SimulatorFeatures/OpenSimExtras: say-range, whisper-range, shout-range, at the request of Singularity dev Liru-Dargon 2013-10-04 17:32:17 -07:00
Justin Clark-Casey (justincc)
44580e2233 Update an AssmblyVersion property that I missed to 0.8.0 2013-10-04 23:36:28 +01:00
Justin Clark-Casey (justincc)
42bdf44658 Bump OPenSimulator version and assembly versions up to 0.8.0 Dev 2013-10-04 23:33:47 +01:00
Justin Clark-Casey (justincc)
970249a3c7 Add OnChatToNPC and OnInstantMessageToNPC messages to NPCAvatar to allow region modules to directly subscribe to chat and messages received by NPCs
Currently still requires INPC from NPCModule.GetNPC() to be cast to an NPCAvatar.
2013-10-04 19:40:43 +01:00
Justin Clark-Casey (justincc)
8996ac1a9c minor: Disable logging left active on regression test TestSameSimulatorIsolatedRegionsV2() 2013-09-27 22:33:42 +01:00
Justin Clark-Casey (justincc)
2cd95fac73 refactor: Rename Scene.AddNewClient() to AddNewAgent() to make it obvious in the code that this is symmetric with CloseAgent() 2013-09-27 22:27:39 +01:00
Justin Clark-Casey (justincc)
b16bc7b01c refactor: rename Scene.IncomingCloseAgent() to CloseAgent() in order to make it clear that all non-clientstack callers should be using this rather than RemoveClient() in order to step through the ScenePresence state machine properly.
Adds IScene.CloseAgent() to replace RemoveClient()
2013-09-27 19:14:21 +01:00
dahlia
b704de9bf8 minor code formatting for the sake of consistency and readability 2013-09-26 16:27:11 -07:00
Justin Clark-Casey (justincc)
585d0800dd minor: Make OpenSimDefaults.ini consistent (spacing and tabs to spaces) 2013-09-27 00:14:40 +01:00
Justin Clark-Casey (justincc)
70b51f12cd minor: Clean up tabbing and spacing issues in OpenSim.ini.example 2013-09-27 00:01:18 +01:00
Justin Clark-Casey (justincc)
d6d82dbd3c minor: correct attachment spelling mistake in log message in HGEntityTransferModule.OnIncomingSceneObject() 2013-09-26 20:13:29 +01:00
Justin Clark-Casey (justincc)
e24edada24 minor: Comment out windlight log message about sending scene data for now. 2013-09-26 00:39:32 +01:00
Justin Clark-Casey (justincc)
253f8de8cd minor: Add scene name to baked textures in cache log message 2013-09-26 00:33:50 +01:00
Justin Clark-Casey (justincc)
babfbe8d6d minor: log MaxOutgoingTransferVersion at EntityTransferModule startup 2013-09-26 00:31:33 +01:00
Justin Clark-Casey (justincc)
4664090b34 minor: correct spelling of Initialized in LSC connector version message 2013-09-25 22:59:57 +01:00
Justin Clark-Casey (justincc)
b22c92368f Move adding UUID.Zero -> Unknown User binding to UMM.Init() so that it's also called by HGUserManagementModule 2013-09-25 21:53:38 +01:00
Justin Clark-Casey (justincc)
32ddfc2740 Reinsert client.SceneAgent checks into LLUDPServer.HandleCompleteMovementIntoRegion() to fix race condition regression in commit 7dbc93c (Wed Sep 18 21:41:51 2013 +0100)
This check is necessary to close a race condition where the CompleteAgentMovement processing could proceed when the UseCircuitCode thread had added the client to the client manager but before the ScenePresence had registered to process the CompleteAgentMovement message.
This is most probably why the message appeared to get lost on a proportion of entity transfers.
A better long term solution may be to set the IClientAPI.SceneAgent property before the client is added to the manager.
2013-09-25 18:45:56 +01:00
Justin Clark-Casey (justincc)
732554be04 Reinsert 200ms sleep accidentally removed in commit 7dbc93c (Wed Sep 18 21:41:51 2013 +0100) 2013-09-25 18:29:14 +01:00
Justin Clark-Casey (justincc)
f384a6291e Instead of swallowing any socket begin/end receive exceptions, log them for debugging purposes.
This may reveal why on some teleports with current code, the UseCircuitCode message gets through but CompleteMovement disappears into the ether.
2013-09-25 00:02:17 +01:00
teravus
8de5c29e2c * The last two are the the patch that Aleric wanted pulled from his repo. * Added GregC to CONTRIBUTORS.txt, Aleric was already in there. * There's some controversy, Some people have suggested that this could be stored in dynamic attributes instead of the database.. Melanie was wanting to pull from the avination repo but was asked to wait on committing anything new until the release. The cherry-pick doesn't answer those questions. 2013-09-22 21:34:55 -05:00
Aleric Inglewood
7889e7757a Don't use 'Indented' formatting for RpcXml responses.
(cherry picked from commit 93abcde69043b175071e0bb752538d9730433f1d)
2013-09-22 21:10:01 -05:00
Aleric Inglewood
2dc92e7de1 Preserve attachment point & position when attachment is rezzed in world
Patch taken from
http://opensimulator.org/mantis/view.php?id=4905
originally by Greg C.

Fixed to apply to r/23314 commit
ba9daf849e
(cherry picked from commit 4ff9fbca441110cc2b93edc7286e0e9339e61cbe)
2013-09-22 21:10:01 -05:00
Justin Clark-Casey (justincc)
a37c59b43e minor: Recomment out log message uncommented in previous cbdfe969 2013-09-21 00:40:23 +01:00
Oren Hurvitz
cbdfe96905 When giving items between avatars in different simulators, only add the item to the receiving avatar's inventory once.
When a user gives an item, the user's client sends an InventoryOffered IM message to its simulator. This adds the item to the receiver's inventory. If the receiver isn't in the same simulator then XMLRPC is used to forward the IM to the correct simulator. The bug was that the receiving simulator handled the message by calling OnInstantMessage() again, which added a second copy of the item to the inventory. Instead, the receiving simulator should only notify the avatar that the item was offered.
2013-09-21 00:32:56 +01:00
Justin Clark-Casey (justincc)
4c0ec86176 minor: Add prefix to log message in LureModule 2013-09-21 00:14:57 +01:00
Justin Clark-Casey (justincc)
e2b3b7a2ae minor: Correct minor spelling mistake Reseting -> Resetting in HG Map module log message 2013-09-20 23:42:55 +01:00
Justin Clark-Casey (justincc)
8502517d80 Make UUID.Zero resolve to "Unknown User" in user cache.
This is to avoid massive numbers of 'no user found' logs when user IDs are missing for some reason.
UUID.Zero should not be used for any user ID.
2013-09-20 23:07:24 +01:00
Justin Clark-Casey (justincc)
c01db5fbdd Lock around read/write of ScenePresence.m_originRegionID to make sure that all threads are seeing the latest value and not a cached one.
There is a possibilty that some V2 teleport failures are due to the viewer triggered CompleteMovement thread not seeing the change of m_originRegionID by the UpdateAgent thread.
2013-09-20 22:41:53 +01:00
Justin Clark-Casey (justincc)
c6dea6ee78 Change some message log levels in Scene.IncomingUpdateChildAgent() for debugging purposes 2013-09-20 20:19:44 +01:00
Robert Adams
35a6361b24 BulletSim: reduce avatar walking stopped threshold.
Add parameter for setting the walking stopped threshold.

This fixes the slight jump when an avatar stops walking.
2013-09-20 09:58:45 -07:00
Robert Adams
07d7a5fd76 BulletSim: zero velocity when avatar not moving.
This fixes a movement jitter that happens when an avatar is standing on a
tilted surface.
2013-09-20 09:58:25 -07:00
Justin Clark-Casey (justincc)
c06a9ffe5c Make new regions PG by default instead of Mature.
This makes scripted object sounds and a few other things play by default instead of having to switch the viewer to adult
This reduces the support burden
2013-09-20 00:04:33 +01:00
Oren Hurvitz
f1267730ef UUID Gatherer: find assets used in Light Projection, Particle Systems, and Collision Sounds. 2013-09-19 23:01:06 +01:00
Justin Clark-Casey (justincc)
979b17165b For debug purposes, allow simulators to force use of earlier SIMULATION/0.1 teleport protocol even if SIMULATION/0.2 is available.
This is specified in the MaxOutgoingTransferVersion attribute of [EntityTransfer] in OpenSim.ini, see OpenSimDefaults.ini for more details.
Default remains "SIMULATION/0.2"
Primarily for http://opensimulator.org/mantis/view.php?id=6755
2013-09-19 22:45:50 +01:00
Justin Clark-Casey (justincc)
b6f10780c2 minor: Make SP.MakeRootAgent() private - no external code has any business calling this method 2013-09-19 21:44:30 +01:00
Justin Clark-Casey (justincc)
03b2b5b77b minor: Make log message at top of ScenePresence.CompleteMovement info level and comment out later log message in ScenePresence.MakeRootAgent()
Need an info message since this is currently important in detecting teleport issue when not at debug log level.
CompleteMovement message occurs before MakeRootAgent() one did
2013-09-19 20:59:27 +01:00
Justin Clark-Casey (justincc)
6bdef1f70b minor: Stop debug logging whenever an npc is moved, other npc log related formatting cleanups 2013-09-19 20:49:55 +01:00
Justin Clark-Casey (justincc)
3a9a8d2113 Revert "Also check user authorization if looking to upgrade from a child to a root agent."
This reverts commit c7ded0618c.
This proves not to be necessary - the necessary checks are already being done via QueryAccess() before cross or teleport
2013-09-19 20:26:26 +01:00
Justin Clark-Casey (justincc)
83c113896e Create regression TestCrossOnSameSimulatorNoRootDestPerm() to check that avatars are not allowed to cross into a neighbour where they are not authorized, even if a child agent was allowed. 2013-09-19 20:26:08 +01:00
Justin Clark-Casey (justincc)
997700c4aa minor: Make config-include .ini files more consistent
Chiefly tabs to spaces.
No actual setting changes
2013-09-18 23:49:27 +01:00
Justin Clark-Casey (justincc)
ac0a527976 Add [SimulationService] section to GridHypergrid.ini and StandaloneHypergrid.ini
This was already in Grid.ini and Standalone.ini
Default settings are same as previously, just introduce a debug ConnectorProtocolVersion parameter
2013-09-18 23:27:37 +01:00
Justin Clark-Casey (justincc)
8999f06025 minor: correct method name in comment 2013-09-18 23:13:31 +01:00
Justin Clark-Casey (justincc)
ddcbd4bb7d refactor: rename *ChildAgentDataUpdate() methods to *UpdateChildAgent()
verb-noun is consistent with other similar methods
2013-09-18 23:09:38 +01:00
Justin Clark-Casey (justincc)
3ce46adb2a minor: Make log message when Scene.IncomingChildAgentDateUpdate() more explicit that there is a problem if it still finds the agent to be a child if the sender wanted to wait till it became root
Add some comments about the mssage sequence, though much more data is at
http://opensimulator.org/wiki/Teleports
2013-09-18 22:56:00 +01:00
Justin Clark-Casey (justincc)
f4d82a56f4 Double the time spent waiting for a UseCircuitCode packet in LLUDPServer.HandleCompleteMovementIntoRegion()
This is to deal with one aspect of http://opensimulator.org/mantis/view.php?id=6755
With the V2 teleport arrangements, viewers appear to send the single UseCircuitCode and CompleteAgentMovement packets immediately after each other
Possibly, on occasion a poor network might drop the initial UseCircuitCode packet and by the time it retries, the CompleteAgementMovement has timed out and the teleport fails.
There's no apparant harm in doubling the wait time (most times only one wait will be performed) so trying this.
2013-09-18 22:09:46 +01:00
Justin Clark-Casey (justincc)
7dbc93c62a Change logging to provide more information on LLUDPServer.HandleCompleteMovementIntoRegion()
Add more information on which endpoint sent the packet when we have to wait and if we end up dropping the packet
Only check if the client is active - other checks are redundant since they can only failed if IsActve = false
2013-09-18 21:41:51 +01:00
Justin Clark-Casey (justincc)
1d2466889a Reinstate insertion of "Unknown UserUMMAU4" now, as naive removing may be generating too many repeating user requests from other sources.
Leaves in the dropping of the client GUN8 (now 9) uuid binding message, since this was the much more common case from the viewer-side and this can only affect viewers.
2013-09-17 01:20:55 +01:00
Justin Clark-Casey (justincc)
845d2b193a Comment out warning about no grid user found in UMM.TryGetUserNamesFromServices() for now 2013-09-17 00:54:53 +01:00
Justin Clark-Casey (justincc)
69ec85f491 Fix issue in recent 3f0fa9f7 where the code start adding unknown user cache entries with no name 2013-09-17 00:02:36 +01:00
Justin Clark-Casey (justincc)
2603a2891b Reinsert comments about possible race conditions when sending bulk inventory updates on non-flag clothing editing 2013-09-16 23:26:13 +01:00
Justin Clark-Casey (justincc)
f99dae03cb Fix bug where using PRIM_LINK_TARGET with only two remaining list items (e.g. link number then PRIM_ROTATION) would not return the parameter
Extended regression test for this case
2013-09-16 23:00:40 +01:00
Justin Clark-Casey (justincc)
60cf42cb8d Make llGetLinkPrimitiveParams() abort and return existing list of params when it encounters an invalid link number, rather than throwing an exception
Addresses http://opensimulator.org/mantis/view.php?id=6768
Thanks to talun for the patch on that commit - in the end I took a different approach that also deals with invalid PRIM_LINK_TARGET
However, not yet generating the same warning on invalid PRIM_LINK_TARGET as seen on LL grid
This commit also adds regression tests for some cases of llGetLinkPrimitiveParams()
2013-09-16 22:56:08 +01:00
Justin Clark-Casey (justincc)
3f0fa9f707 To avoid viewers (particularly on the Hypergrid) from permanently caching a UUID -> "Unknown User" binding, drop the binding request rather than replying with "Unknown User"
By not binding UUID -> "Unknown User", we leave open the possibility that the binding may be correctly resolved at a later time, which can still happen in some Hypergrid situations.
Observed behaviour of LL viewer 3.3.4 is that a dropped bind request is not retried until the next session.
2013-09-16 19:45:42 +01:00
Justin Clark-Casey (justincc)
53de6d94ea minor: replace spaces with tabs for see_into_region setting 2013-09-12 23:38:50 +01:00
Talun
07d6a0385f 6762: llList2Key fails to convert a string in a list to a key
llGetPrimitiveParams changed to return the sculpty key as an LSL_String so
that type checking in llList2Key will work
2013-09-12 23:23:52 +01:00
Robert Adams
2d7adcb22f BulletSim: update DLLs and SOs to disable Bullet's internal profiling.
This was accidentily left on. This version should make performance better
and fix the memory leak.
2013-09-12 13:07:18 -07:00
BlueWall
3c85afbb43 Allow setting the EntityTransfer-max_distance to 0 to override distance checks. This is to facilitate current viewer work fixing the distance limitations for teleporting. 2013-09-12 11:46:12 -04:00
Robert Adams
dacc20ee48 BulletSim: remove collision cache clearing logic for physical objects.
This fixes constraints from getting messed up when properties change.
2013-09-11 16:50:27 -07:00
Mic Bowman
b29e9d37e7 Change handling of the FetchInventoryDescendents2 capability configuration to allow
for external handlers.
2013-09-11 12:15:16 -07:00
Robert Adams
8bcf753127 BulletSim: update DLLs and SOs with ClearCollisionCache inteface calls
and constraint debugging messages.
2013-09-11 09:12:26 -07:00
Robert Adams
6e39cc316f BulletSim: add ClearCollisionProxyCache function to API.
Add proxy cache clearing when some properties are changed. This fixes
a problem where objects would stop colliding of they were moved
with setPosition mulitple times.
2013-09-11 09:12:24 -07:00
Robert Adams
e34385634b BulletSim: update DLLs and SOs for spring parameters and constraint
debugging dump code.
2013-09-11 09:12:22 -07:00
Robert Adams
c5eabb28b4 BulletSim: add LSL function and plumbing for setting a spring
equilibrium point in the physics engine constraint.
2013-09-11 09:12:19 -07:00
Robert Adams
5827b6e1aa BulletSim: add extended physics LSL constants for axis specification.
Add specific error warnings for mis-matched parameter types in extended
   physics functions.
2013-09-11 09:12:18 -07:00
Robert Adams
cf2cdc191d BulletSim: ability to specify groups of axis to modify in constraint parameters that control multiple axis. Add useLinearReferenceFrameA constraint parameter. 2013-09-11 09:12:16 -07:00
Robert Adams
7c54630a2d BulletSim: add axis parameter for specifying enable, damping, and stiffness for spring constraints. Renumber parameter ops since I can as no one is using them yet. 2013-09-11 09:12:14 -07:00
Robert Adams
30b3657a66 BulletSim: implementation of setting spring specific physical parameters. Add setting of linkset type to physChangeLinkParams. Lots of detail logging for setting of linkset constraint parameters. 2013-09-11 09:12:12 -07:00
Robert Adams
67195618d5 BulletSim: add requestor's ID to post taint detail log message. 2013-09-11 09:12:10 -07:00
Robert Adams
3dbf4a1002 BulletSim: remove chatty debug message from previous commit. 2013-09-11 09:12:09 -07:00
Robert Adams
e0b457d3c3 BulletSim: add position and rotation update for child prim physics update events. Normally, physics engines do not return updates for child prims so, under normal operation, this code should never execute. Will only be used when using flexible linkset linkages. 2013-09-11 09:12:07 -07:00
Robert Adams
d09c35f506 BulletSim: pass both root and child BSPhysObjects to Extension function. Update routines to use the new parameters list from above change. 2013-09-11 09:12:05 -07:00
Robert Adams
995314f91f BulletSim: add ID parameter to TaintedObject calls so logging will include LocalID of object which created the taint. 2013-09-11 09:12:03 -07:00
Robert Adams
4781297b4e BulletSim: Extension parameters passed through the classes made to pass just and array of objects rather than a mixture of parameters and array. Makes understanding and parsing what is being passed much easier. 2013-09-11 09:12:02 -07:00
Robert Adams
6d83f3f021 BulletSim: adjust avatar capsule height calculation to be closer to defined SL heights. Correct BSParam avatar height defaults to be what's in OpenSimDefaults.ini. 2013-09-11 09:12:00 -07:00
Robert Adams
e1120cb74d BulletSim: add extended physics function physGetLinkType(linkNum). Add implementation of physChangeLinkParams() in BSLinksetConstraint. 2013-09-11 09:11:58 -07:00
Robert Adams
8755aeb348 BulletSim: update DLLs and SOs with Bullet svn version 2644 (no major fixes) and with BulletSim implementing more of the constraint types and parameter settings. 2013-09-11 09:11:56 -07:00
Robert Adams
f6fdfd16f5 BulletSim: change ExtendedPhysics constants to 'const' so they can be used as case variables in switch statements. 2013-09-11 09:11:54 -07:00
Robert Adams
455d36c4c7 BulletSim: add physChangeLinkParams to set individual parameters on link constraints. Not fully functional. Remove double definition of ExtendedPhysics parameters by having BulletSim reference the optional module (addition to prebuild.xml and usings). 2013-09-11 09:11:52 -07:00
Robert Adams
b2a1348adc BulletSim: update C++ HACD parameters to values that handle enclosed hollow spaces better. This shouldn't affect many since this HACD routine is off by default. 2013-09-11 09:11:50 -07:00
Robert Adams
6aee08ac3c BulletSim: add physChangeLinkSpring to change linkset link to be a spring constraint. Add implementation to create spring constraint. Send up property updates for linkset children at the end of flexible linkset links. The simulator probably doesn't do the right thing yet. 2013-09-11 09:11:48 -07:00
Robert Adams
dff0fb5690 BulletSim: Linkset.Refresh() calls internal ScheduleRebuild() to recreate the linkset physics at next PostTaint time. Replace the existing calls to ScheduleRebuild to be calls to Refresh(). This allows external routines to make changes to parameters and then cause the linkset to rebuild. 2013-09-11 09:11:46 -07:00
Robert Adams
f3cc20050e BulletSim: initial implementation of physChangeLinkFixed that resets a linkset's link back to a fixed, non-moving connection. 2013-09-11 09:11:45 -07:00
Robert Adams
c6a6631efc BulletSim: move linkset extension operations into BSPrimLinkable where they should be. 2013-09-11 09:11:43 -07:00
Robert Adams
993bcec088 BulletSim: add unmanaged and XNA functions for hinge, slider and spring constraints. 2013-09-11 09:11:41 -07:00
Robert Adams
0971c7ae77 BulletSim: complete linkage of spring constraint into linkset constraint. 2013-09-11 09:11:39 -07:00
Robert Adams
9a7d0e489c BulletSim: add spring constraint to linkset constraint types. 2013-09-11 09:11:37 -07:00
Robert Adams
48ee73bfa7 BulletSim: add API and calls for spring constraint parameters. 2013-09-11 09:11:36 -07:00
Robert Adams
725751fd6c BulletSim: fixes for change linkset implementation of physical linksets. 2013-09-11 09:11:34 -07:00
Michael Cerquoni
663059ac5c chaning the default max_distance to 16383 as we actually start counting at zero, thank you dahlia for pointing this out. 2013-09-10 19:56:39 -04:00
Michael Cerquoni
ec5f17b2ce This extends the default max_distance for teleports to 16384, a big thank you to all of the viewer devs who made this possibe! 2013-09-10 18:35:02 -04:00
Robert Adams
b05cb3b2bf Change collision logic in SceneObjectPart so land_collision will happen.
The previous logic would generate land_collision_start and land_collision_end
but would not generate the land_collision itself.
2013-09-09 14:50:33 -07:00
BlueWall
a97f6f8668 Fix configuration/ini expansion issue. Thanks to smxy for testing. 2013-09-07 13:11:31 -04:00
Diva Canto
08874d6b9e Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-09-05 07:44:49 -07:00
Diva Canto
04619a9b13 Restore group membership check for HG users in QueryAccess. 2013-09-05 07:44:27 -07:00
Justin Clark-Casey (justincc)
b858be345a minor: add doc about DefaultHGRegion and some of the other GridService region settings (though not all as of yet) 2013-09-05 00:41:03 +01:00
Justin Clark-Casey (justincc)
dc74a50225 Stop "show client stats" from throwing an exception if somehow Scene.m_clientManager still retains a reference to a dead client.
Instead, "show client stats" now prints "Off!" so that exception is not thrown and we know which entries in ClientManager are in this state.
There's a race condition which could trigger this, but the window is extremely short and exceptions would not be thrown consistently (which is the behaviour observed).
It should otherwise be impossible for this condition to occur, so there may be a weakness in client manager IClientAPI removal.
2013-09-04 23:48:24 +01:00
Justin Clark-Casey (justincc)
c7ded0618c Also check user authorization if looking to upgrade from a child to a root agent.
Relevant if a child agent has been allowed into the region which should not be upgraded to a root agent.
2013-09-04 00:44:17 +01:00
Justin Clark-Casey (justincc)
5f0d54c209 For a Hypergrid user, delay estate access checks until NewUserConnection() so that they work.
This is necessary because the hypergrid groups checks (as referenced by estates) require an agent circuit to be present to construct the hypergrid ID.
However, this is not around until Scene.NewUserConnection(), as called by CreateAgent() in EntityTransferModule.
Therefore, if we're dealing with a hypergrid user, delay the check until NewUserConnection()/CreateAgent()
The entity transfer impact should be minimal since CreateAgent() is the next significant call after NewUserConnection()
However, to preserve the accuracy of query access we will only relax the check for HG users.
2013-09-04 00:42:23 +01:00
Justin Clark-Casey (justincc)
b781a23c44 In pCampbot PhysicsBehaviour.Close(), only cancel jumping if bot is connected 2013-09-03 19:58:27 +01:00
Justin Clark-Casey (justincc)
9c3c9b7f5f Make pCampbot "add behaviour" and "remove behaviour" console commands work for all bots if no bot number is given 2013-09-03 19:57:34 +01:00
Justin Clark-Casey (justincc)
76bd2e2d72 Consistently give responsibility for thread sleeping to behaviours rather than controlling from the main action loop
This is to avoid excessive and inconsistent delays between behaviours that currently need to embed sleeps in other actions (e.g. physics) and other behaviours.
Might need a more sophisticated approach in the long term.
2013-09-03 19:41:12 +01:00
Justin Clark-Casey (justincc)
3dbe7313d1 Add Close() method to IBehaviour to allow behaviours to cleanup when removed or bot it disconnected.
In this case, it is used to turn off jump when physics testing behaviour is removed.
2013-09-03 19:33:17 +01:00
Justin Clark-Casey (justincc)
1a2627031d Add pCampbot "remove behaviour" console command for removing bot behaviours during operation.
Doesn't currently work very well as stopping physics, for instance, can leave bot travelling in old direction
2013-09-03 19:05:54 +01:00
Justin Clark-Casey (justincc)
9bd6271570 Add ability to adjust pCampbot bot behaviours whilst running with "add behaviour <behaviour-name> <bot-number>" console commad 2013-09-03 18:51:55 +01:00
Justin Clark-Casey (justincc)
01cb8033a4 And fix break in "show bot" from commit 9c65207 2013-09-03 17:55:20 +01:00
Justin Clark-Casey (justincc)
a89c56dcf1 Fix build break from last commit 9c65207. Mono 2.4 lacks string.join(string, List<string>), or some auto casting is missing 2013-09-03 17:53:29 +01:00
Justin Clark-Casey (justincc)
9c65207936 Show behaviours of pCampbot bots in "show bots" and "show bot" console commands 2013-09-03 17:07:57 +01:00
Justin Clark-Casey (justincc)
431156f6c4 minor simplification of some unix date functions in Util. No functional change. 2013-09-03 00:17:50 +01:00
Justin Clark-Casey (justincc)
5f15ee95dc Fix logic errors in "show grid users online" console command which didn't actually filter out users shown continuously online for more than 5 days
Remove confusion in command output.
2013-09-03 00:16:43 +01:00
Justin Clark-Casey (justincc)
fc9f50d940 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-09-03 00:06:50 +01:00
Justin Clark-Casey (justincc)
4035badd20 Add experimental "show grid users online" console command to show grid users online from a standalone/robust instance.
This is not guaranteed to be accurate since users may be left "online" in certain situations.
For example, if a simulator crashes and they never login/logout again.
To counter this somewhat, only users continuously online for less than 5 days are shown.
2013-09-03 00:04:12 +01:00
BlueWall
9643915093 Remove test that gives issue on Windows, just let the try/catch do the work. 2013-09-02 16:28:40 -04:00
Justin Clark-Casey (justincc)
857f24a5e2 Fix bug where users teleporting to non-neighbour regions could continue to hear chat from their source region for some time after teleport completion.
This occurs on v2 teleport since the source region now waits 15 secs before closing the old child agent, which could still receive chat.
This commit introduces a ScenePresenceState.PreClose which is set before the wait, so that ChatModule can check for ScenePresenceState.Running.
This was theoretically also an issue on v1 teleport but since the pause before close was only 2 secs there, it was not noticed.
2013-09-02 19:15:10 +01:00
Justin Clark-Casey (justincc)
5ce5ce6edb Comment out warning about agent updating without valid session ID for now.
This causes extreme console spam if a simulator running latest master and one running 0.7.5 have adjacent regions occupied by avatars.
2013-09-02 17:45:38 +01:00
Justin Clark-Casey (justincc)
4cbadc3c49 Allow one to specify a DefaultHGRegion flag in [GridService] in order to allow different default regions for HG and direct grid logins.
This requires a new GridService.GetDefaultHypergridRegions() so ROBUST services require updating but not simulators.
This method still returns regions flagged with just DefaultRegion after any DefaultHGRegions, so if no DefaultHGRegions are specified
then existing configured defaults will still work.
Immediate use is for conference where we need to be able to specify different defaults
However, this is also generally useful to send experienced HG users to one default location and local users whose specified region fails (e.g. no "home" or "last") to another.
2013-09-02 17:27:45 +01:00
BlueWall
56f565b601 Profiles: Clean up some log entries caused when visiting HG avatar is using legacy profiles 2013-08-29 16:54:13 -04:00
BlueWall
a8c0e16e47 Initialization: move key expansion out to operate on all sources and not just environment variables 2013-08-29 14:35:56 -04:00
Robert Adams
aa521fb385 Do not add a port zero to end of the hypergrid gateway host name.
If the port is specified it is added but a ":0" is not added if the port is zero.
This enables the hypergrid address short form "hypergridGateway:regionName"
which is handled by the parser but failed because of this zero port addition.
2013-08-28 16:38:07 -07:00
Robert Adams
0882cf0fc3 BulletSim: add some protections for processing when shutting down.
Attempt to fix Mantis 6740 (http://opensimulator.org/mantis/view.php?id=6740).
2013-08-27 09:55:50 -07:00
Justin Clark-Casey (justincc)
0dd9a68eb7 Revert "Make HG logins fall back to fallback regions if the desired region fails."
This is very similar to my earlier revert in bcb8605f84 and fails for the same reasons.
Reverting this change because it causes a problem if access is denied to the user.
This reverts commit c7a8afbb8d.
2013-08-26 21:07:49 +01:00
Justin Clark-Casey (justincc)
1b2830b929 Revert "Added some more debug messages."
Fallback doesn't work at this level as the change of destination isn't communicated to the source region/viewer
Reverting because this introduces a bug when access does fail.
More detail in revert of main commit.

This reverts commit ec32c1d4b6.
2013-08-26 21:05:55 +01:00
Justin Clark-Casey (justincc)
60e4ce20b8 Fix exception thrown after a region has been restarted through scheduling.
This exception was very likely harmless since it occurred after the restart had taken place, but still misleading.
Thanks to SCGreyWolf for the code change suggestion in http://opensimulator.org/mantis/view.php?id=6747, though I did this in a slightly different way.
2013-08-25 20:17:04 +01:00
Justin Clark-Casey (justincc)
85824d2cd9 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-08-25 20:12:59 +01:00
Diva Canto
ec32c1d4b6 Added some more debug messages. 2013-08-24 09:59:05 -07:00
Diva Canto
f0c0376660 Potential fix for access control bug on login introduced with SeeIntoRegion commit. 2013-08-24 08:42:41 -07:00
Diva Canto
5cd7bc2848 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-08-24 03:42:39 -07:00
Diva Canto
c7a8afbb8d Make HG logins fall back to fallback regions if the desired region fails. 2013-08-24 03:41:56 -07:00
Diva Canto
6a24515269 Whitespace fubar. 2013-08-24 03:40:44 -07:00
Robert Adams
c34e6f25b1 Fix a printing of exception error in InventoryArchiveModule that only
printed the error message and not the call stack.
2013-08-23 13:53:47 -07:00
Justin Clark-Casey (justincc)
1a623bb266 Rename pCampbot.ini -> pCampBot.ini (and example file) to be consistent with other capitalizations of pCampBot 2013-08-23 20:58:46 +01:00
Justin Clark-Casey (justincc)
0fbfef9649 minor: shortern warning messages in EntityTransferModule when UpdateAgent() fails 2013-08-23 01:21:03 +01:00
Justin Clark-Casey (justincc)
050617ae0e Make pCampbot "show bot" command take the bot number instead of the full bot name
Shorter and can do this because bot names are uniform
2013-08-23 01:13:19 +01:00
Justin Clark-Casey (justincc)
04f4dd3dc7 remove redundant return at end of HandleDeregisterRegion() 2013-08-23 01:04:03 +01:00
Justin Clark-Casey (justincc)
2be786709b Make it possible for the "deregister region id" command to accept more than one id 2013-08-23 01:03:27 +01:00
Justin Clark-Casey (justincc)
61c20bd06a Remove old and unused ScenePresence.RestoreInCurrentScene() 2013-08-23 00:53:42 +01:00
Justin Clark-Casey (justincc)
065c5839b5 Refactor: merge SceneGraph.AddScenePresence() into CreateAndAddChildScenePresence() since the former was only ever called from the latter
This allows us to remove dead code relating to adding root agents directly to the scenegraph, which never happens.
2013-08-23 00:49:13 +01:00
Justin Clark-Casey (justincc)
a9f9b0da9d minor: Correct typo on "debug stats record start" message 2013-08-23 00:13:31 +01:00
Justin Clark-Casey (justincc)
a0c99a7dcc minor: remove mono compiler warning from LLClientView 2013-08-23 00:03:47 +01:00
Justin Clark-Casey (justincc)
13556cf129 Fix a further bug in pCampbot connect where ignoring already connected bots was wrongly counted as a connect
Also, only sleep when we actually perform a connection
2013-08-22 23:49:19 +01:00
Justin Clark-Casey (justincc)
70f89ae65b Make it possible to adjust the pCampbot login delay via the [BotManager] LoginDelay parameter of pCampbot.ini 2013-08-22 23:43:33 +01:00
Justin Clark-Casey (justincc)
51c7fb1969 Add "set bots" command to make it possible to set SEND_AGENT_UPDATES on all bots whilst pCampbot is running 2013-08-22 23:11:05 +01:00
Justin Clark-Casey (justincc)
beb9d966f9 Stop "handle sit user name" command from trying to sit avatars on objects which have sit positions but are attachments 2013-08-22 22:49:23 +01:00
Justin Clark-Casey (justincc)
416bbe9583 Stop error messages being misleadingly generated when on client connection activity timeout, a root connection triggers a CloseAgent to a neighbour region which has already closed the agent due to inactivity.
Also separates out log messages to distinguish between close not finding an agent and wrong auth token, and downgrades former to debug and latter to warn
2013-08-22 22:46:40 +01:00
Justin Clark-Casey (justincc)
66a7dc3a0d In pCampbot, don't try and reconnect bots that are already connected on console "connect" command 2013-08-22 20:12:14 +01:00
Justin Clark-Casey (justincc)
832c35d4d5 Stop "sit user name" and "stand user name" console commands from trying to sit/stand avatars already sitting/standing 2013-08-22 20:05:57 +01:00
Justin Clark-Casey (justincc)
689cf2d367 minor: Make logging in GatekeeperService.LoginAgent() a bit more detailed so that we can distinguish between simultaneous logins 2013-08-22 01:24:55 +01:00
Justin Clark-Casey (justincc)
bcb8605f84 Revert "Implement ability for hg logins to try fallback regions just like local logins."
This approach does not work - it is taking place too far down the login process where really the region checking
could only be done when the hg map tiles are linked on the main map (messy and probably impossible) or possibly
when the final destination is fetched at the very first stage of teleport (which couldn't be done without a protocol
change to pass the agentID as well as the requested regionID)

This reverts commit 3d9b73c47a.
2013-08-22 01:20:01 +01:00
Justin Clark-Casey (justincc)
3d9b73c47a Implement ability for hg logins to try fallback regions just like local logins.
These would be specified in the [GridService] section of Robust.HG.ini, which already lists these in the example text.
Untested patch so that Neb can easily pull in for testing, though shouldn't disrupt existing hg logins since fallback processing is a bit of code stuck on the end of the login sequence.
2013-08-21 23:19:31 +01:00
Justin Clark-Casey (justincc)
1f39a763a5 Don't allow users to attempt to sit on objects in a child region without going to that region first.
If this is attempted, they get a "Try moving closer.  Can't sit on object because it is not in the same region as you." message instead, which is the same as current ll grid.
Sitting on ground is okay, since viewer navigates avatar to required region first before sitting.
2013-08-21 21:35:03 +01:00
teravus
a6af561660 * Fix some threading issues in BulletXNA (the managed bullet library), this should better allow you to run it in multiple region scenarios (but why would you really want to do that?) Source in OpenSimLibs.
* Fixed a null ref during shutdown.
2013-08-20 21:09:17 -05:00
Justin Clark-Casey (justincc)
4a81465b91 Fix build break from last commit a3e1b27 on mono 2.4.3
Looks like this level of mono doesn't have a string.Join() which will take a list rather than an array (or some implicit conversion isn't happening)
2013-08-20 18:47:52 +01:00
Justin Clark-Casey (justincc)
a3e1b278a1 Add pCampbot "show bot" console command to show more detailed information on a particular bot (e.g. what sims they are connected to) 2013-08-20 18:41:09 +01:00
Justin Clark-Casey (justincc)
43940f6562 Add --regex options to "sit user name" and "stand user name" console commands to sit/stand many avatars at once.
Currently, first name and last name are input separate but are concatenated with a space in the middle to form a regex.
So to sit all bots with the first name "ima", for instance, the command is "sit user name --regex ima .*"
2013-08-20 18:13:40 +01:00
Justin Clark-Casey (justincc)
e384ff604e Add experimental "sit user name" and "stand user name" console commands in SitStandCommandsModule.
"sit user name" will currently only sit the given avatar on prims which have a sit target set and are not already sat upon.
Chiefly for debug purposes.
2013-08-20 17:43:02 +01:00
Justin Clark-Casey (justincc)
56d1d67a34 Add pCampbot console commands to sit all bots on ground and stand all bots 2013-08-20 17:01:12 +01:00
Justin Clark-Casey (justincc)
a3dd7db4a3 Add -connect (-c) switch to pCampbot command line options.
Now, bots will only connect at startup if this switch is specified.
If it is not specified, then a separate "connect" command is required on the pCampbot command line
2013-08-20 00:08:47 +01:00
Justin Clark-Casey (justincc)
589b1a2eaf Make it possible to reconnect pCampbots with the console command "connect [<n>]".
If no n is given then all available bots are connected
2013-08-19 23:50:18 +01:00
Justin Clark-Casey (justincc)
ea3f024b8a refactor: start bot connection thread within BotManager rather than externally 2013-08-19 21:25:17 +01:00
Justin Clark-Casey (justincc)
079cd4e94f refactor: restructure pCampbot multi-bot connection code. 2013-08-19 21:17:59 +01:00
Justin Clark-Casey (justincc)
2fa42f24fd Make it possible to disconnected a specified number of bots via the pCampbot console command "disconnect [<n>]"
Bots disconnected are ascending from last in numeric order.
Temporarily no way to reconnect bots.
2013-08-19 21:00:31 +01:00
Justin Clark-Casey (justincc)
49b7cbda72 Create a separate pCampbot "disconnect" console command which disconnects connected bots.
"quit" console command now requires bots to be separate disconnected first before quitting.
This is to prepare the way for disconnecting/reconnecting different numbers of bots in a pCampbot session.
And hopefully resolves bug where console appears not to be reset if Environment.Exit(0) is called on a different thread
2013-08-19 20:29:17 +01:00
Justin Clark-Casey (justincc)
ef63abe9b1 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-08-19 20:00:42 +01:00
Justin Clark-Casey (justincc)
a90a5f52dd Show number of connections each bot has established in "show bots" command. 2013-08-19 19:38:20 +01:00
Melanie
3585b0a139 Allow updating the wearable type of wearables that have a type of 0.
This will allow viewers to fix broken wearables as they detect them.
2013-08-18 02:59:10 +01:00
Justin Clark-Casey (justincc)
85a9cb260a Remove mono compiler warnings from UserProfilesModule 2013-08-17 01:10:58 +01:00
Justin Clark-Casey (justincc)
d75f00cc2d minor: remove mono compiler warning from AttachmentsModule 2013-08-17 01:09:31 +01:00
Justin Clark-Casey (justincc)
b3052c425e Remove some mono compiler warnings from OpenSim/Server/Handlers 2013-08-17 01:08:19 +01:00
Justin Clark-Casey (justincc)
f5dbfe99b1 minor: remove mono compiler warnings from OpenSim/Services/Connectors/SimianGrid 2013-08-17 01:06:48 +01:00
Justin Clark-Casey (justincc)
d38d5ecbac minor: remove mono compiler warnings from ScenePresence 2013-08-17 01:00:20 +01:00
Justin Clark-Casey (justincc)
77d418a36d remove mono compiler warnings from PollServiceRequestManager 2013-08-17 00:56:19 +01:00
Justin Clark-Casey (justincc)
217c8deae5 minor: remove mono compiler warning in StatsManager 2013-08-17 00:51:21 +01:00
Justin Clark-Casey (justincc)
1f1736a79f minor: Make log messages consistent in NeighbourServicesConnector 2013-08-17 00:46:18 +01:00
Justin Clark-Casey (justincc)
14ae89dbe7 Fix issues with RemoteAdmin admin_save_heightmap and admin_load_heightmap not working.
This is because they were wrongly looking for both regionid and region_id parameters in the same request.
Now only region_id is required (and recognized), regionid having been already deprecated for some time.
This is essentially Michelle Argus' patch from http://opensimulator.org/mantis/view.php?id=6737 but with tabs replaced with spaces.
Thanks!
2013-08-17 00:39:41 +01:00
Justin Clark-Casey (justincc)
f5d3145bea Add ScenePresenceTeleportTests.TestSameSimulatorIsolatedRegionsV2() regression test for v2 transfers.
Also adjusts names of teleport setup helpers in EntityTransferHelpers
2013-08-17 00:24:56 +01:00
Justin Clark-Casey (justincc)
fbab898f74 Add TestSameSimulatorNeighbouringRegionsV2() regression test for v2 entity transfer protocl 2013-08-16 23:52:55 +01:00
Justin Clark-Casey (justincc)
1624522761 refactor: Make AttachmentModulesTests.TestSameSimulatorNeighbouringRegionsTeleportV2 use already available TestClient handle rather than retrieving it via the ScenePresence 2013-08-16 23:45:04 +01:00
Justin Clark-Casey (justincc)
7d268912f1 Packet headers are not zero-encoded so don't try to zero-decode these in PacketPool.GetType()
Instead adjusts code with that from Packet.BuildHeader(byte[], ref int, ref int):Header in libomv
This stops packet decoding failures with agent UUIDs that contain 00 in their earlier parts (e.g. b0b0b0b0-0000-0000-0000-000000000211)
Thanks to lkalif for pointing this out.
2013-08-16 00:58:25 +01:00
Justin Clark-Casey (justincc)
7c916ab91c Try to make "slow down" message that one could receive on rapid teleporting more informative to the user.
This message is seen on V2 if one attempts to quickly re-teleport from a source region where one had previously teleported to a non-neighbour and back within 15 secs.
The solution here is for the user to wait a short while.
This message can also be seen on any teleport protocol if one recieves multiple teleport attempts simultaneously.  Probably still useful here to help identify misbehaving scripts.
2013-08-15 14:51:54 +01:00
Justin Clark-Casey (justincc)
3ddb7438d7 Move DoNotCloseAfterTeleport flag reset before UpdateAgent in V2 to avoid a low probability where the destination re-establishing the child connection before the flag was reset 2013-08-15 14:41:00 +01:00
Justin Clark-Casey (justincc)
3f8d79024b Rely on the Scene.IncomingCloseAgent() check as to whether the connection should be kept open after teleport-end rather than doing this in the ET Module
This is safer since the close check in IncomingCloseAgent() is done under lock conditions, which prevents a race between ETM and Scene.AddClient()
2013-08-15 14:07:57 +01:00
Justin Clark-Casey (justincc)
2231fcf5b4 Do not use the SP.DoNotCloseAfterTeleport flag for child agent connections.
This approach has problems if a client quits without sending a proper logout but then reconnects before the connection is closed due to inactivity.
In this case, the DoNotCloseAfterTeleport was wrongly set.
The simplest approach is to close child agents on teleport as quickly as possible so that races are very unlikely to occur
Hence, this code now closes child agents as the first action after a sucessful teleport.
2013-08-15 13:46:46 +01:00
Justin Clark-Casey (justincc)
5011c657b5 Actually implement the bot request object textures switch started in 225cf0d.
Forgot to propogate it down to bot level.
2013-08-14 23:37:07 +01:00
Justin Clark-Casey (justincc)
104626d732 minor: Comment out AvatarPicketSearch caps log message for now, which is occuring on every login and entity transfer 2013-08-14 23:22:52 +01:00
Justin Clark-Casey (justincc)
73e3ca670d Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-08-14 23:21:51 +01:00
Justin Clark-Casey (justincc)
60cc9e9a3c minor: remove unused entity transfer config in teleport v2 attachments test 2013-08-14 23:21:18 +01:00
Robert Adams
e8b1e91a1d BulletSim: include check for volume detect in check for zeroing avatar motion.
Normally, avatar motion is zeroed if colliding with a stationary object so
they don't slide down hills and such. Without volume detect check this also
allowed avatars to stand on volume detect objects and to have some jiggling
when they were in the volume detect object. This commit fixes both.
2013-08-14 14:49:24 -07:00
Robert Adams
7c3b71d294 BulletSim: add physical object initialized flag so updates and collisions
don't happen until the object is completely initialized.

This fixes the problem of doing a teleport while the simulator is running.
The destruction of the physical object while the engine is running means
that the physics parameter update would overwrite the new position of the
newly created avatar.
2013-08-14 14:49:22 -07:00
Justin Clark-Casey (justincc)
93dffe1777 Add stat clientstack.<scene>.IncomingPacketsOrphanedCount to record well-formed packets that were not initial connection packets and could not be associated with a connected viewer. 2013-08-14 22:33:12 +01:00
Justin Clark-Casey (justincc)
0d5680e971 Count any incoming packet that could not be recognized as an LLUDP packet as a malformed packet. Record this as stat clientstack.<scene>.IncomingPacketsMalformedCount
Used to detect if a simulator is receiving significant junk UDP
Decimates the number of packets between which a warning is logged and prints the IP source of the last malformed packet when logging
2013-08-14 22:08:28 +01:00
Justin Clark-Casey (justincc)
2c67aa0f41 If pCampbot has been asked to shutdown, don't carry on logging in queued bots 2013-08-14 21:08:00 +01:00
Justin Clark-Casey (justincc)
225cf0d010 Add pCampbot RequestObjectTextures ini setting to control whether textures are requested for received objects. 2013-08-14 19:53:10 +01:00
Justin Clark-Casey (justincc)
fd519748e9 Add method doc to Scene.RemoveClient() to ask any callers to use Scene.IncomingCloseAgent() instead.
IncomingCloseAgent() now sets the scene presence state machine properly, which is necessary to avoid races between multiple sources of close.
Hence, it's also necessary for everyone to consistently call IncomingCloseAgent()
Calling RemoveClient() directly is currently generating an attention-grabbing exception though this right now this is harmless.
2013-08-14 19:36:52 +01:00
Justin Clark-Casey (justincc)
97c514daa5 Shutdown a bot's actions by making it check for disconnecting state rather than aborting the thread.
Aborting the thread appears to be causing shutdown issues.
2013-08-14 19:21:07 +01:00
Justin Clark-Casey (justincc)
3a62f39044 Add a -form switch to pCampbot to allow one to login a sequence of bots starting from numbers other than 0 2013-08-14 18:26:11 +01:00
Justin Clark-Casey (justincc)
2146b20169 Add the ability to explicitly specify a login start location to pCampbot via the -start parameter 2013-08-14 16:51:51 +01:00
Robert Adams
0feb5da31e BulletSim: move the creation of the avatar movement actor creating to
taint time. Attempt to fix a problem of teleporting within the same
region where the remove and addition of the physical avatar occasionally
ends up with a non-moving avatar.
2013-08-13 21:06:24 -07:00
Justin Clark-Casey (justincc)
5933f9448d Add a SendAgentUpdates setting to a new pCampbot.ini.example file which can control whether bots send agent updates
pCampbot.ini.example is used by copying to pCampbot.ini, like other ini files
2013-08-13 23:54:50 +01:00
Justin Clark-Casey (justincc)
e311f902ff minor: Eliminate one of the duplicate 'have's in the HG message telling the user if no GroupsServerURI has been given in user data by the home grid 2013-08-13 20:13:12 +01:00
Robert Adams
a90351cd2c Remove exception when printing error for failure removing script state. 2013-08-13 11:49:09 -07:00
Justin Clark-Casey (justincc)
4f8c691f8c Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-08-12 22:57:32 +01:00
Justin Clark-Casey (justincc)
c49ea491a3 Make show bots pCampbot console command print connected, connecting, etc. bot totals at end. 2013-08-12 22:49:17 +01:00
Robert Adams
2c31fe4614 BulletSim: add check in avatar stair step code to verify the collision
is not with a volume detect object.

This fixes a problem of avatars trying to step over a volume detect object
that they collide with. This appeared as the avatar popping up as it started
to step up but then continuing on since the object wasn't physically interacting.
2013-08-12 13:44:53 -07:00
Justin Clark-Casey (justincc)
377fe63c60 Don't try and send group updates to NPCs via event queue, since NPCs have no event queue.
I think there is an argument for sending this information to NPCs anyway since in some cases it appears a lot easier to write server-side bots by hooking into such internal events.
However, would need to stop event messages building up on NPC queues if they are never retrieved.
2013-08-12 21:02:50 +01:00
Justin Clark-Casey (justincc)
f3edc0d8b7 minor: Extend warning message when adding trying to add an event for a client without a queue to include the event message name. 2013-08-12 19:38:23 +01:00
Justin Clark-Casey (justincc)
de6ad380f6 Get rid of issue where removing NPCs would through an exception by routing close through Scene.IncomingCloseAgent() and NPCAvatar.Close() rather than directly to Scene.RemoveClient().
This exception was actually harmless since it occurred at the very last stage of the remove client process.
2013-08-12 19:31:45 +01:00
Justin Clark-Casey (justincc)
e5b1688913 Add none behaviour to pCampbot when one wants bots to just stand around 2013-08-12 18:48:18 +01:00
Justin Clark-Casey (justincc)
b64d3ecaed Create TestSameSimulatorNeighbouringRegionsTeleportV2() regression test for V2 transfer protocol. 2013-08-12 18:15:12 +01:00
Robert Adams
216f5afe54 Stats treaking. Update ToOSDMap for Stat and PercentageStat to return
all the various numbers that have been added to the console output.
Break out EventHistogram from CounterStat.
2013-08-10 09:09:52 -07:00
Justin Clark-Casey (justincc)
23ca1f859e minor: Consistently log IOCP for IO completion thread startup log information instead of mixing this with "IO Completion Threads" 2013-08-09 18:27:26 +01:00
Justin Clark-Casey (justincc)
bfdcdbb2f3 Increase wait for source region to sent UpdateAgent to 10 seconds instead of 4.
This is giving much better results on teleports between simulators over my lan where for some reason there is a pause before the receiving simulator processes UpdateAgent()
At this point, v2 teleports between neighbour and non-neighbour regions on a single simulator and between v2 simulators and between a v1 and v2 simulator
are working okay for me in different scenarios (e.g. simple teleport, teleport back to original quickly and re-teleport, teleport back to neighbour and re-teleport. etc.)
2013-08-09 17:59:58 +01:00
Justin Clark-Casey (justincc)
aec7019728 Add missing file from b1c26a56 2013-08-09 17:57:24 +01:00
Justin Clark-Casey (justincc)
97bcb59bee Merge branch 'TeleportWork' 2013-08-09 17:52:29 +01:00
Justin Clark-Casey (justincc)
6fcbf219da Comment back out seed dump code enabled in b1c26a56. Also adds a few teleport comments. 2013-08-09 17:48:35 +01:00
Diva Canto
2cdcf62b48 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-08-09 08:31:30 -07:00
Diva Canto
7e01213bf2 Go easy on enforcing session ids in position updates 2013-08-09 08:31:15 -07:00
Justin Clark-Casey (justincc)
99bce9d877 Fix an issue with an A->C->B->A teleport where these regions are in a row (A,B,C) where the A root agent is still closed, terminating the connection.
This was occuring because teleport to B did not set DoNotCloseAfterTeleport on A as it was a neighbour (where it isn't set to avoid the issue where the source region doesn't send Close() to regions that are still neighbours (hence not resetting DoNotCloseAfterTeleport).
Fix here is to still set DoNotCloseAfterTeleport if scene presence is still registered as in transit from A
2013-08-09 00:24:22 +01:00
Justin Clark-Casey (justincc)
b1c26a56b3 Fix an issue where under teleport v2 protocol, teleporting from regions in an line from A->B->C would not close region A when reaching C
The root cause was that v2 was only closing neighbour agents if the root connection also needed a close.
However, fixing this requires the neighbour regions also detect when they should not close due to re-teleports re-establishing the child connection.
This involves restructuring the code to introduce a scene presence state machine that can serialize the different add and remove client calls that are now possible with the late close of the
This commit appears to fix these issues and improve teleport, but still has holes on at least quick reteleporting (and possibly occasionally on ordinary teleports).
Also, has not been completely tested yet in scenarios where regions are running on different simulators
2013-08-08 23:29:30 +01:00
Robert Adams
6410a25cef BulletSim: adjust avatar position when the avatar's size is changed.
This fixes the problem of avatars bouncing when logged in.
Added a little height to the avatar height fudges to eliminate a problem
of feet being in the ground a bit.
2013-08-08 13:55:17 -07:00
Dan Lake
9fc97cbbf7 Make m_originRegionID in ScenePresence public to allow DSG module to work for now. Once the code churn on teleport ends, I can find a better solution 2013-08-08 12:44:03 -07:00
Robert Adams
d9bd6e6b5b Add parameter and explanation of ManagedStats return to OpenSimDefaults.ini.
Add 'callback' query parameter to managed stats return to return function
form of JSON data.
2013-08-08 09:45:30 -07:00
Robert Adams
c67c55e0fc Better error reporting when registering LSL function extensions (comms module).
For unknown reasons, a dynamic function signature cannot have more than 5
parameters. Error message now tells you this fact so you can curse MS and
then go change your function definitions.
2013-08-08 09:45:16 -07:00
Robert Adams
50c163ae6c Add a JSON web fetch of the statististics managed by StatsManager.
Disabled by default. Enable by setting
[Startup]ManagedStatsRemoteFetchURI="Something"
and thereafter "http://ServerHTTPPort/Something/" will return all the managed
stats (equivilent to "show stats all" console command).
Accepts queries "cat=", "cont=" and "stat=" to specify statistic category,
container and statistic names. The special name "all" is the default and returns
all values in that group.
2013-08-08 09:45:01 -07:00
teravus
4e86674a3a * Added set water height <height> [<x>] [<y>] console command following the set terrain heights console command as an example. 2013-08-07 23:33:23 -05:00
teravus
99a4a91488 * This makes in-world terrain editing smoother, even in MegaRegions. This change only affects the editing user's experience. Non-editing users will see nothing different from the current 'slow' result. See comments for the thought process and how the issues surrounding terrain editing, cache, bandwidth, threading, terrain patch reliability and throttling were balanced. 2013-08-07 21:22:04 -05:00
Justin Clark-Casey (justincc)
ce1361f2fe minor: Remove console lines at bottom of FakeParcelIDTests() regression test that were accidentally left in 2013-08-08 01:07:30 +01:00
Kevin Cozens
64216b34a4 Fixed error in BuildFakeParcelID() which was detected by regression tests. 2013-08-08 01:02:04 +01:00
Kevin Cozens
43da879ea2 Added regression tests for the routines related to fake parcel IDs. 2013-08-08 00:59:55 +01:00
Kevin Cozens
e4da8d74d8 Additional regression tests for the location routines in Location.cs 2013-08-08 00:56:13 +01:00
Justin Clark-Casey (justincc)
638c3d25b0 Remove never implemented stub modules commands (list, load, unload) from back in 2009.
"show modules" is the functional console command that will show currently loaded modules.
Addresses http://opensimulator.org/mantis/view.php?id=6730
2013-08-08 00:48:22 +01:00
Justin Clark-Casey (justincc)
b10710d4a5 minor: add some method doc to ScenePresence fields used for entity transfer, add minor details to some log messages, rename a misleading local variable name.
No functional changes.
2013-08-07 23:17:31 +01:00
Justin Clark-Casey (justincc)
a33a1ac958 Add post-CreateAgent teleport cancellation/abortion functionality from v1 transfer protocol into v2.
This stops OpenSimulator still trying to teleport the user if they hit cancel on the teleport screen or closed the viewer whilst the protocol was trying to create an agent on the remote region.
Ideally, the code may also attempt to tell the destination simulator that the agent should be removed (accounting for issues where the destination was not responding in the first place, etc.)
2013-08-07 18:52:30 +01:00
Diva Canto
dbd773e89e Amend to last commit -- remove the obsolete var from OpenSim.ini.example 2013-08-07 10:04:53 -07:00
Diva Canto
6b9a65972c Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-08-07 08:02:36 -07:00
Diva Canto
3194ffdab8 Fixed incomplete commit r/23317 -- see_into_region. Put the guard around estate bans also, and delete the obsolete config var. 2013-08-07 08:01:59 -07:00
Justin Clark-Casey (justincc)
d6d5d4ebd0 Add file missing from last commit 4c2f6de 2013-08-06 18:32:16 +01:00
Justin Clark-Casey (justincc)
4c2f6de8e4 Add the experimental ability to dump stats (result of command "show stats all") to file OpenSimStats.log every 5 seconds.
This can currently only be activated with the console command "debug stats record start".
Off by default.
Records to file OpenSimStats.log for simulator and RobustStats.log for ROBUST
2013-08-06 18:29:33 +01:00
Justin Clark-Casey (justincc)
ac198068ab Add "debug threadpool status" console command to show min/max/current worker/iocp threadpool numbers 2013-08-06 00:00:12 +01:00
Justin Clark-Casey (justincc)
4581bdd929 Add "debug comms status" command to show current debug comms settings 2013-08-05 23:49:33 +01:00
Justin Clark-Casey (justincc)
9bcf072795 Make it possible to switch whether we serialize osd requests per endpoint or not, either via config (SerializeOSDRequests in [Network]) or via the "debug comms set" console command.
For debug purposes to assess what impact this has on network response in a heavy test environment.
2013-08-05 23:44:48 +01:00
Justin Clark-Casey (justincc)
f9dc5815c4 For LLImageManagerTests, make tests execute under synchronous fire and forget conditions.
I generally prefer this approach for regression tests because of the complexity of accounting for different threading conditions.
2013-08-05 23:15:30 +01:00
Justin Clark-Casey (justincc)
139dcf1246 minor: move "threads abort" and "force gc" console commands into debug category - these are not things one needs to do in normal operation 2013-08-05 23:06:17 +01:00
Justin Clark-Casey (justincc)
76e778fe2c Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-08-05 23:05:12 +01:00
Justin Clark-Casey (justincc)
160659f683 Make it possible to set worker/iocp min/max threadpool limits on the fly with the console command "debug threadpool set" 2013-08-05 23:04:36 +01:00
Diva Canto
2d3ac2b1ec Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-08-05 14:21:39 -07:00
Diva Canto
946b370966 Child agent updates: remove the dependency on the root agent's camera position. That was a complete overkill that is unnecessary at this point. 2013-08-05 14:21:17 -07:00
Justin Clark-Casey (justincc)
24dcf3cf6a Comment out debug log lines about script modules comms for now.
If this is an issue, could change log4net config instead to allow re-enablement
2013-08-05 20:51:40 +01:00
Justin Clark-Casey (justincc)
b8612e005a At OpenSimulator startup, print out default min built-in threadpool threads as well as max.
Make it clear that we only try to adjust max, and log at warn level if this fails.
Other minor logging cleanup.
2013-08-05 20:47:47 +01:00
Justin Clark-Casey (justincc)
151a8ca0cc Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-08-05 20:37:27 +01:00
Justin Clark-Casey (justincc)
7f0d9ad644 Make test AssetsClient print out more information about any failure to set thread numbers and immediate post config thread numbers 2013-08-05 20:36:46 +01:00
Mic Bowman
03698121ed Remove some debugging from simian connectors. 2013-08-05 12:34:53 -07:00
Justin Clark-Casey (justincc)
976514d39a Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-08-05 19:25:51 +01:00
Justin Clark-Casey (justincc)
76bd3de2fd Add checks monitoring framework to provide alerts if certain conditions do not hold.
Not yet in use.
2013-08-05 19:22:47 +01:00
Diva Canto
05012bb0df Group notices bug fix: use a new IM for each member of the group, otherwise the fields get messed up because the transfer is async 2013-08-05 08:09:30 -07:00
Diva Canto
5b4b349776 Fix the failing TestSendImage. J2K decoding is async. 2013-08-03 21:27:32 -07:00
Diva Canto
09cb2a37dd More on HG inventory and OutboundPermission: disallowing giving inventory to foreigners if OutboundPermission is false 2013-08-03 20:36:30 -07:00
Diva Canto
dcfeb95e98 HG: If OutboundPermission is set to false, let's enforce stricter permissions by not allowing objects to be taken to inventory. 2013-08-03 20:13:44 -07:00
Diva Canto
b857353fc9 Making the J2KDecoderModule decoder function async. Could this be the cause of sim freeze? -- HandleRequestImage in LLClientView is now sync, which means that it cannot take too long to complete. However, its execution path may end up in J2KDecoderModule.Decode, which is heavy and could stop the packet processing thread while it's at it. 2013-08-03 15:42:25 -07:00
Diva Canto
847c01f406 Amend Justin's last commit regarding the new config var ServiceVersion. The section may not exist at all. 2013-08-02 17:38:08 -07:00
Diva Canto
fdfc951744 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-08-02 17:00:34 -07:00
Diva Canto
5198df3aa0 Issue: 10 simultaneous TPs, many not making it. Now bypassing the per-url lock -- we should be "ok" (or, more "ok") now that we have increased the connection limit on the http library. But this is a sensitive part of the code, so it may need reverting. 2013-08-02 17:00:18 -07:00
Justin Clark-Casey (justincc)
4ff3757f86 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-08-02 23:17:20 +01:00
Justin Clark-Casey (justincc)
54b1071556 Allow older teleport ConnectorProtocolVersion of "SIMULATION/0.1" to be manually forced in a new [SimulationService] config setting.
This is for testing and debugging purposes to help determine whether a particular issue may be teleport related or not
"SIMULATION/0.2" (the newer teleport protocol) remains the default.  If the source simulator only implements "SIMULATION/0.1" this will correctly allow fallback to the older protocol.
Specifying "SIMULATION/0.1" will force the older, less efficient protocol to always be used.
2013-08-02 23:12:54 +01:00
Robert Adams
5bdfd55ace BulletSim: When converting linkset types, don't try to change the list
of linkset children while iterating through the list.
2013-08-02 10:32:43 -07:00
Robert Adams
24df15dab7 BulletSim: add implementation of 'physSetLinksetType' and 'physGetLinksetType'
and processing routines in BulletSim.
Add linkset rebuild/conversion routine in BSLinkset.
2013-08-02 09:47:12 -07:00
Robert Adams
5bcccfc305 BulletSim: add BSLinkInfo structure to remember link specific information
for each link in a linkset.
Extend BSLinksetConstraint to create and use BSLinkInfo with the default
static constraint.
2013-08-02 09:47:11 -07:00
Robert Adams
87ee0c395e Fix problem with modInvoke defined integer constants being build into
scripts as boxed integers rather than proper reference to a new LSLInteger.
This fixes an exception when using a registered integer constant in
a script.
2013-08-02 09:44:01 -07:00
Diva Canto
07e4958b19 Turn off edit beams when object is derezed while being edited. (mantis #6722) 2013-08-01 20:40:13 -07:00
Justin Clark-Casey (justincc)
d4c506e453 minor: replace veclist.Add(new Vector3(0,0,0)) with Vector3.Zero in InventoryAccessModules.RezObject() - structs are passed by value 2013-08-02 00:08:14 +01:00
Justin Clark-Casey (justincc)
c9695a0a59 Move experimental attachments throttling further down the chain so that multiple attachments changes (e.g. change outfit) are also throttled 2013-08-02 00:00:00 +01:00
Justin Clark-Casey (justincc)
7a5d11f8a7 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-08-01 23:17:21 +01:00
Justin Clark-Casey (justincc)
68b98a8003 minor: Add name to debug lludp packet level feedback on console 2013-08-01 23:16:41 +01:00
teravus
7b9a50721d * Thanks Plugh for pointing out that the constructor that takes a ulong regionhandle and saves it to to X,Y vars in the OpenSim.Framework.Location object was inverting the X and Y resulting in X and Y confusion. The test also used 256x256 in the uint,uint constructor so it was unable to determine if the X and Y components swapped. I don't expect much upheaval from this commit, not a lot of features were using the ulong Location object constructor. The database never stores the ulong regionhandle... the prims are loaded by region Guid. LLUDPServer used it to determine regions that it handled in a service definition where there was simply a X == X test which has the same logical result un-switched as it did switched. Again, thanks LibOMV for the regionhandle code. 2013-08-01 16:32:36 -05:00
Justin Clark-Casey (justincc)
216e785ca9 Add experimental "debug attachments throttle <ms>" setting (command line) and ThrottlePer100PrimsRezzed in [Attachments] in config
This is an experimental setting to control cpu spikes when an attachment heavy avatar logs in or avatars with medium attachments lgoin simultaneously.
It inserts a ms sleep specified in terms of attachments prims after each rez when an avatar logs in.
Default is 0 (no throttling).
"debug attachments <level>" changes to "debug attachments log <level>" which controls logging.  A logging level of 1 will show the throttling performed if applicable.
Also adds "debug attachments status" command to show current throttle and debug logging levels.
2013-08-01 21:16:53 +01:00
Justin Clark-Casey (justincc)
0c4c084bed Try a different approach to slow terrain update by always cycling the loop immediately if any data was sent, rather than waiting.
What I believe is happening is that on initial terrain send, this is done one packet at a time.
With WaitOne, the outbound loop has enough time to loop and wait again after the first packet before the second, leading to a slower send.
This approach instead does not wait if a packet was just sent but instead loops again, which appears to lead to a quicker send without losing the cpu benefit of not continually looping when there is no outbound data.
2013-08-01 18:12:28 +01:00
Justin Clark-Casey (justincc)
932c382737 Revert "Issue: painfully slow terrain loading. The cause is commit d9d995914c (r/23185) -- the WaitOne on the UDPServer. Putting it back to how it was done solves the issue. But this may impact CPU usage, so I'm pushing it to test if it does."
This reverts commit 59b461ac0e.
2013-08-01 18:11:50 +01:00
Diva Canto
59b461ac0e Issue: painfully slow terrain loading. The cause is commit d9d995914c (r/23185) -- the WaitOne on the UDPServer. Putting it back to how it was done solves the issue. But this may impact CPU usage, so I'm pushing it to test if it does. 2013-08-01 09:27:44 -07:00
Justin Clark-Casey (justincc)
9f05a7ac7b Include missing reference that probably stops windows build from commit 1299592405 2013-08-01 00:25:59 +01:00
Mic Bowman
1299592405 Experimental comment to eneralize the handling of Linden caps when the
cap is something other than "localhost". A new interface for handling
external caps is supported with an example implemented for Simian. The
only linden cap supporting this interface right now is the GetTexture
cap.
2013-07-31 15:37:15 -07:00
Mic Bowman
d82126b651 Add the Simian service config to the GridCommon example 2013-07-31 11:42:22 -07:00
Mic Bowman
48ee440983 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-07-31 11:31:03 -07:00
Mic Bowman
64f2dc778a A pretty major restructuring of the simian method invocations in order to
service access capabilities. In conjunction with the corresponding Simian
updates, this enables explicit per-simulator capability-based access to
grid services. That enables grid owners to add or revoke access to the grid
on a simulator by simulator basis.
2013-07-31 11:27:35 -07:00
Diva Canto
ac2ad9690d HGWorldMapModule: unregister event on RemoveRegion 2013-07-31 11:20:27 -07:00
Diva Canto
87fcff9fc3 HGWorldMapModule: check whether it's enabled or not. 2013-07-31 11:13:55 -07:00
Diva Canto
3c540f0d33 Avoid another null ref opportunity. 2013-07-30 22:07:33 -07:00
Diva Canto
e4ecbc2b10 Fix null ref. 2013-07-30 21:38:41 -07:00
Diva Canto
fd050fca7c Doing the HG Map / SimulatorFeatures "the right way": moved it to HGMapModule, hooking on to SimulatorFeatures.OnSimulatorFeaturesRequest event (similar to what the DynamicMenuModule does).
Only HG Visitors get this var, to avoid spamming local users.
The config var  is now called MapTileURL, to be consistent with the login one, and its being picked up from either [LoginService], [HGWorldMap] or [SimulatorFeatures], just because I have a bad memory.
2013-07-30 21:10:00 -07:00
Diva Canto
590a8b0315 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-07-30 17:27:32 -07:00
Diva Canto
2b54199271 After talking to lkalif on the IRC: SimulatorFeatures response: renamed the OSDMap GridServices to OpenSimExtras, normalized the url keys under it, and moved ExportEnabled to under it too. Melanie: change your viewer code accordingly.
Documentation at http://opensimulator.org/wiki/SimulatorFeatures_Extras
2013-07-30 17:26:56 -07:00
Robert Adams
0d189165a8 BulletSim: distribute vehicle physical settings to all members of
a linkset. Enables constraint based linksets.
Rename some internal variables to clarify whether values world or
vehicle relative.
2013-07-30 15:23:33 -07:00
Robert Adams
6ad577d32b BulletSim: test method for debugging of extended physics script operations. 2013-07-30 15:22:32 -07:00
Robert Adams
5a7784a0e6 BulletSim: make density display and return value consistant with how
the simulator expects it (scaled to 100kg/m^3).
2013-07-30 07:22:43 -07:00
Justin Clark-Casey (justincc)
1416c90932 minor: Add timeout secs to connection timeout message. Change message to reflect it is a timeout due to no data received rather than an ack issue. 2013-07-29 23:53:59 +01:00
Justin Clark-Casey (justincc)
8004e6f31c Fix issue just introduced in 8efe4bfc2e where I accidentally left in a test line to force very quick client unack 2013-07-29 23:38:54 +01:00
Justin Clark-Casey (justincc)
8efe4bfc2e Make "abnormal thread terminations" into "ClientLogoutsDueToNoReceives" and add this to the StatsManager
This reflects the actual use of this stat - it hasn't recorded general exceptions for some time.
Make the sim extra stats collector draw the data from the stats manager rather than maintaing this data itself.
2013-07-29 23:18:29 +01:00
Diva Canto
7eee9eb312 Groups: Better warning messages to the user. 2013-07-28 20:47:15 -07:00
Diva Canto
1b94de8e58 Group chat: prevent a situation where dupe IMs could occur. 2013-07-28 19:31:17 -07:00
Diva Canto
1d4bf06fe7 Group chat: guard against duplicate sends 2013-07-28 18:49:10 -07:00
Diva Canto
33b54807a1 Changing the visibility test in groups service to be UUID.Zero.ToString() instead of "all" because some paths in the code assume there's a UUI in the RequestingAgent string. 2013-07-28 18:08:50 -07:00
Diva Canto
468ddd2373 Same issue. 2013-07-28 17:12:14 -07:00
Diva Canto
c442ef346e Same issue as previous commit. 2013-07-28 16:44:31 -07:00
Diva Canto
698b2135ee Fix an issue where HG members of groups weren't seeing the entire membership for group chat. 2013-07-28 15:59:24 -07:00
Diva Canto
63f6c8f27c Removed commented lines and useless debug message 2013-07-28 13:53:47 -07:00
Diva Canto
7b0b5c9d97 Added BasicSearchModule.cs which handles OnDirFindQuery events. Removed that handler from both Groups modules in core, and replaced them with an operation on IGroupsModule. 2013-07-28 13:49:58 -07:00
Diva Canto
6be614ba84 This makes people search work. 2013-07-28 09:54:34 -07:00
Diva Canto
170a6f0563 This makes group search work (Groups V2). 2013-07-28 09:00:28 -07:00
Diva Canto
8dff05a897 More on group chat: only root agents should subscribe to OnInstantMessage, or else they'll see an echo of their own messages after teleporting. 2013-07-27 20:30:00 -07:00
Diva Canto
9cbbb7eddf Clarification on docs of .ini.examples for Groups (again) 2013-07-27 19:16:48 -07:00
Diva Canto
18eca40af3 More bug fixes on group chat 2013-07-27 19:12:47 -07:00
Diva Canto
69975763d2 Several major improvements to group (V2) chat. Specifically: handle join/drop appropriately, invitechatboxes.
The major departure from flotsam is to send only one message per destination region, as opposed to one message per group member. This reduces messaging considerably in large groups that have clusters of members in certain regions.
2013-07-27 15:38:56 -07:00
Diva Canto
1572e91b5f Clarifications on documentation of Group configs 2013-07-27 08:04:48 -07:00
Diva Canto
3dac92f345 Increased the rate of the PollServiceRequestManager to 0.5 secs (it was 1sec). Group chat is going over the EQ... Hopefully this won't increase CPU when there's nothing going on, but we need to watch for that. 2013-07-26 21:40:04 -07:00
Diva Canto
85428c49bb Trying to decrease the lag on group chat. (Groups V2 only) 2013-07-26 21:27:00 -07:00
Diva Canto
428916a64d Commented out ChatSessionRequest capability in Vivox and Freeswitch. We aren't processing it in any meaningful way, and it seems to get invoked everytime someone types a message in group chat. 2013-07-26 21:14:21 -07:00
Justin Clark-Casey (justincc)
ba9daf849e Fix regression from 056a6ee7 because the RemoteSimulationConnector uses a copy of the LocalSimulationConnector but never initializes it (hence ServiceVersion was never set) 2013-07-26 22:52:08 +01:00
Justin Clark-Casey (justincc)
840be97e40 Fix failure in TestCreateDuplicateRootScenePresence().
This is a test setup failure since code paths when adding a duplicate root scene presence now require the EntityTransferModule to be present.
Test fixed by adding this module to test setup
2013-07-26 20:52:30 +01:00
Justin Clark-Casey (justincc)
c245365484 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-07-26 19:23:12 +01:00
Justin Clark-Casey (justincc)
056a6ee765 Fix regression tests relating to agent transfer by making simulator use last week's SIMULATOR/0.1 protocol for now. 2013-07-26 19:22:30 +01:00
nebadon
9038a503eb Add Aleric to Contributors list, thanks Aleric!! 2013-07-26 14:17:36 -04:00
nebadon
d27cc62458 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-07-26 14:13:02 -04:00
nebadon
ad2ebd2f3d Force map tiler to save Water.jpg as an actual jpeg format it seems even though we specified jpg extention it was actually a png and thus confusing the viewer silently. 2013-07-26 14:11:42 -04:00
Justin Clark-Casey (justincc)
a08f01fa83 Fix NPC regression test failures.
These were genuine failures caused by ScenePresence.CompleteMovement() waiting for an UpdateAgent from NPC introduction that would never come.
Instead, we do not wait if the agent is an NPC.
2013-07-26 18:43:15 +01:00
Diva Canto
dd2c211e62 Comment debug message 2013-07-26 07:40:55 -07:00
Diva Canto
d5367a219d Slight improvement: no need to delay the removal of the queues in EQ, because DisableSimulator is now being sent via UDP 2013-07-26 07:39:57 -07:00
Diva Canto
878ce1e6b2 This should fix all issues with teleports. One should be able to TP as fast as needed. (Although sometimes Justin's state machine kicks in and doesn't let you) The EventQueues are a hairy mess, and it's very easy to mess things up. But it looks like this commit makes them work right. Here's what's going on:
- Child and root agents are only closed after 15 sec, maybe
- If the user comes back, they aren't closed, and everything is reused
- On the receiving side, clients and scene presences are reused if they already exist
- Caps are always recreated (this is where I spent most of my time!). It turns out that, because the agents carry the seeds around, the seed gets the same URL, except for the root agent coming back to a far away region, which gets a new seed (because we don't know what was its seed in the departing region, and we can't send it back to the client when the agent returns there).
2013-07-25 23:44:58 -07:00
Justin Clark-Casey (justincc)
4cd03d8c31 Return Simulator/0.1 (V1) entity transfer behaviour to waiting only 2 seconds before closing root agent after 15.
This is because a returning viewer by teleport before 15 seconds are up will be disrupted by the close.
The 2 second delay is within the scope where a normal viewer would not allow a teleport back anyway.
Simulator/0.2 (V2) protocol will continue with the longer delay since this is actually the behaviour viewers get from the ll grid
and an early close causes other issues (avatar being sent to infinite locations temporarily, etc.)
2013-07-26 01:40:56 +01:00
Justin Clark-Casey (justincc)
72ed49af5f Reset DoNotClose scene presence teleport flag before pausing. Rename DoNotClose to DoNotCloseAfterTeleport 2013-07-26 01:38:04 +01:00
Justin Clark-Casey (justincc)
1fabdcc43c If a returning teleport starts to reuse a downgraded child connection that was a previous root agent, do not close that child agent at the end of the 15 sec teleport timer.
This prevents an issue if the user teleports back to the neighbour simulator of a source before 15 seconds have elapsed.
This more closely emulates observed linden behaviour, though the timeout there is 50 secs and applies to all the pre-teleport agents.
Currently sticks a DoNotClose flag on ScenePresence though this may be temporary as possibly it could be incorporated into the ETM state machine
2013-07-26 01:04:16 +01:00
Diva Canto
20b989e048 Increased the wait time to 15 secs. In a 0.7.5 standalone where the effect was always present, this seems to have fixed it. 2013-07-24 17:10:26 -07:00
Diva Canto
cac37e298c Deleted all [ZZZ] debug messages. 2013-07-24 14:31:30 -07:00
Diva Canto
f0320f5652 The previous commit did fix the infinity problem! I'm putting the same time on TP_V1 and adding a big red warning on top of those lines. 2013-07-24 14:31:18 -07:00
Diva Canto
46d017b197 Today's wild shot at the infinity problem. Wait on the child agent left behind. 2013-07-24 14:31:03 -07:00
Diva Canto
4e5c7bdeb3 Moved TriggerOnMakeRootAgent back to the end of MakeRootAgent, to see if that eliminates the temporary placement at infinity upon TPs 2013-07-24 14:30:13 -07:00
Diva Canto
e6a0f6e428 One more thing to test in order to let CompleteMovement go up the stack. 2013-07-24 14:29:51 -07:00
Diva Canto
14530b2607 Minor adjustment on timings of waits. 2013-07-24 14:29:37 -07:00
Diva Canto
c0433d5e4c Changed the RegionHandshake packet to the Unknown queue, so that it is sent with high priority and hopefully gets to the client before AgentMovementComplete 2013-07-24 14:29:15 -07:00
Diva Canto
879cbb4575 This commit message intentionally left blank (last commit was idiotic) 2013-07-24 14:28:55 -07:00
Diva Canto
261512606d Improve the opening test in CompleteMovement, to account for multiple flags besides ViaLogin. 2013-07-24 14:28:41 -07:00
Diva Canto
d7984ef775 More on putting TP V1 as it was 2013-07-24 14:28:27 -07:00
Diva Canto
aaee63af82 Minor improvements on TP V1 trying to make it exactly as it was before. 2013-07-24 14:28:14 -07:00
Diva Canto
3891a8946b New Teleport protocol (V2), still compatible with V1 and older. (version of the destination is being checked)
In this new protocol, and as committed before, the viewer is not sent EnableSimulator/EstablishChildCommunication for the destination. Instead, it is sent TeleportFinish directly. TeleportFinish, in turn, makes the viewer send a UserCircuitCode packet followed by CompleteMovementIntoRegion packet. These 2 packets tend to occur one after the other almost immediately to the point that when CMIR arrives the client is not even connected yet and that packet is ignored (there might have been some race conditions here before); then the viewer sends CMIR again within 5-8 secs. But the delay between them may be higher in busier regions, which may lead to race conditions.
This commit improves the process so there are are no race conditions at the destination. CompleteMovement (triggered by the viewer) waits until Update has been sent from the origin. Update, in turn, waits until there is a *root* scene presence -- so making sure CompleteMovement has run MakeRoot. In other words, there are two threadlets at the destination, one from the viewer and one from the origin region, waiting for each other to do the right thing. That makes it safe to close the agent at the origin upon return of the Update call without having to wait for callback, because we are absolutely sure that the viewer knows it is in th new region.
Note also that in the V1 protocol, the destination was getting UseCircuitCode from the viewer twice -- once on EstablishAgentCommunication and then again on TeleportFinish. The second UCC was being ignored, but it shows how we were not following the expected steps...
2013-07-24 14:27:58 -07:00
Diva Canto
aae29c0ee2 Further tweaks on TPs: not sending the callback URL and instead waiting 15sec before closing the agent. This seems to be working fairly well. The viewer seems to have an 8 sec delay between UseCircuitCode and CompleteMovement.
Also added back the position on UpdateAgent, because it's needed for TPing between neighboring regions.
2013-07-24 14:27:37 -07:00
Diva Canto
9ab78d412c EXPERIMENTAL: yet another variation of ES/EAC/TPFinish 2013-07-24 14:27:22 -07:00
Diva Canto
00d4a26eef Amend previous commit. 2013-07-24 12:49:30 -07:00
Diva Canto
665fb66686 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-07-24 11:26:30 -07:00
Diva Canto
e103e34f1d Added config var that we all thought was already there: see_into_region. (Note: different from the defunct see_into_neighboring_sim, which used to control the process from the other end). This enables child agents in neighbors for which the root agent doesn't have permission to be in. 2013-07-24 11:25:41 -07:00
Diva Canto
d8a6eb5641 Decreased the time of group cache to 1 min, because it was getting on my nerves that it takes so long to let go of old info. 2013-07-24 11:25:24 -07:00
Justin Clark-Casey (justincc)
feef9d64a4 For unknown user issue, bump GUN7 to GUN8 and UMMAU3 to UMMAU4 to assess what looks like a very significant reducing in GUN occurrances 2013-07-23 23:42:34 +01:00
Justin Clark-Casey (justincc)
fa2653c8e1 Merge branch 'master' of ssh://opensimulator.org/var/git/opensim 2013-07-23 23:32:24 +01:00
Justin Clark-Casey (justincc)
9a4a513b5e Correct issue where the last instance of a sampled stat was shown 3x larger than it should have been (though internal use was correct) 2013-07-23 23:31:35 +01:00
Diva Canto
516062ae1f Don't touch the Current Outfit folder also on coming back home 2013-07-23 15:05:32 -07:00
Diva Canto
901bdfed40 Restoring landing on prims, which had been affected by the edit beams commit. 2013-07-23 14:31:16 -07:00
Diva Canto
744276dd50 In renaming the folders for hypergriding, don't rename the Current Outfit folder. The viewer doesn't like that. 2013-07-23 14:31:03 -07:00
Diva Canto
42e52f544d Improvement of fetching name in groups 2013-07-23 14:30:50 -07:00
Diva Canto
7c1eb86c7d Don't post Link asset types back to the home grid 2013-07-23 14:28:53 -07:00
Justin Clark-Casey (justincc)
76e46d0158 Improve spacing between data and units on console stats display 2013-07-23 17:23:16 +01:00
Robert Adams
aec8d1e6be BulletSim: Turn on center-of-mass calculation by default.
Reduce object density by factor of 100 to bring physical mass computations
into a range better suited for Bullet.
2013-07-23 09:09:25 -07:00
Robert Adams
f499b328c4 Revert "Revert "BulletSim: Add logic to linksets to change physical properties for""
Found that the vehicle movement problem was not caused by these physics changes.

This reverts commit 84d0699761.
2013-07-23 08:14:20 -07:00
Robert Adams
75686e0e49 Revert "Revert "BulletSim: change BSDynamics to expect to be passed a BSPrimLinkable""
Found that the vehicle movement problem was not caused by these physics changes.

This reverts commit 7b187deb19.
2013-07-23 08:13:56 -07:00
Robert Adams
b14156aa63 Revert "Revert "BulletSim: only create vehicle prim actor when vehicles are enabled.""
Found that the vehicle movement problem was not caused by these physics changes.

This reverts commit 5f7b2ea81b.
2013-07-23 08:13:29 -07:00
Robert Adams
aec8852af7 Revert "Revert "BulletSim: move collision processing for linksets from BSPrimLinkable""
Found that the vehicle movement problem was not caused by these physics changes.

This reverts commit c45659863d.
2013-07-23 08:13:01 -07:00
Robert Adams
401c2e2f2e Revert "Revert "Add experimental stubs for an extension function interface on both""
Found that the vehicle movement problem was not caused by these physics changes.

This reverts commit 89857378ce.
2013-07-23 08:12:34 -07:00
Robert Adams
af9deed135 Revert "Revert "BulletSim: freshen up the code for constraint based linksets.""
Found that the vehicle movement problem was not caused by these physics changes.

This reverts commit 44543ebe63.
2013-07-23 08:11:21 -07:00
Justin Clark-Casey (justincc)
90528c23d9 For stats which can show average change over time, show the last sample as well as the average.
This is somewhat cryptic at the moment, need to improve documentation.
2013-07-23 01:13:13 +01:00
Justin Clark-Casey (justincc)
a57a472ab8 Add proper method doc and comments to m_dataPresentEvent (from d9d9959) 2013-07-23 00:51:59 +01:00
Justin Clark-Casey (justincc)
9fb9da1b6c Add clientstack.InboxPacketsCount stat. This records the number of packets waiting to be processed at the second stage (after initial UDP processing)
If this consistently increases then this is a problem since it means the simulator is receiving more requests than it can distribute to other parts of the code.
2013-07-23 00:35:41 +01:00
Justin Clark-Casey (justincc)
60732c96ef Add clientstack.OutgoingUDPSendsCount stat to show number of outbound UDP packets sent by a region per second 2013-07-23 00:35:34 +01:00
Justin Clark-Casey (justincc)
8396f1bd42 Record raw number of UDP receives as clientstack.IncomingUDPReceivesCount 2013-07-23 00:35:23 +01:00
Justin Clark-Casey (justincc)
bf517899a7 Add AverageUDPProcessTime stat to try and get a handle on how long we're taking on the initial processing of a UDP packet.
If we're not receiving packets with multiple threads (m_asyncPacketHandling) then this is critical since it will limit the number of incoming UDP requests that the region can handle and affects packet loss.
If m_asyncPacketHandling then this is less critical though a long process will increase the scope for threads to race.
This is an experimental stat which may be changed.
2013-07-23 00:35:09 +01:00
Robert Adams
e6b6af62dd Added check for user movement specification before discarding an incoming
AgentUpdate packet. This fixes the problem with vehicles not moving forward
after the first up-arrow.
Code to fix a potential exception when using different IClientAPIs.
2013-07-22 15:41:14 -07:00
Robert Adams
44543ebe63 Revert "BulletSim: freshen up the code for constraint based linksets."
The changes don't seem to be ready for prime time.

This reverts commit 803632f8f3.
2013-07-22 12:10:23 -07:00
Robert Adams
89857378ce Revert "Add experimental stubs for an extension function interface on both"
The changes don't seem to be ready for prime time.

This reverts commit 13a4a80b38.
2013-07-22 12:09:55 -07:00
Robert Adams
c45659863d Revert "BulletSim: move collision processing for linksets from BSPrimLinkable"
The changes don't seem to be ready for prime time.

This reverts commit b4c3a791aa.
2013-07-22 12:09:17 -07:00
Robert Adams
5f7b2ea81b Revert "BulletSim: only create vehicle prim actor when vehicles are enabled."
The changes don't seem to be ready for prime time.

This reverts commit acb7b4a09a.
2013-07-22 12:08:49 -07:00
Robert Adams
7b187deb19 Revert "BulletSim: change BSDynamics to expect to be passed a BSPrimLinkable"
The changes don't seem to be ready for prime time.

This reverts commit d0d654e218.
2013-07-22 12:08:25 -07:00
Robert Adams
84d0699761 Revert "BulletSim: Add logic to linksets to change physical properties for"
The changes don't seem to be ready for prime time.

This reverts commit b44f0e1a00.
2013-07-22 12:07:42 -07:00
Robert Adams
b44f0e1a00 BulletSim: Add logic to linksets to change physical properties for
whole linkset.
Override physical property setting for BSLinksetCompound as there are
not children to the compound spape.
2013-07-22 10:27:24 -07:00
Robert Adams
d0d654e218 BulletSim: change BSDynamics to expect to be passed a BSPrimLinkable
and start changing the logic to handle the base prim as a complex
object (ie, a linkset).
2013-07-22 10:27:21 -07:00
Robert Adams
acb7b4a09a BulletSim: only create vehicle prim actor when vehicles are enabled. 2013-07-22 10:27:18 -07:00
Robert Adams
b4c3a791aa BulletSim: move collision processing for linksets from BSPrimLinkable
into the linkset implementation classes.
Add HasSomeCollision attribute that remembers of any component of
   a linkset has a collision.
Update vehicle code (BSDynamic) to use the HasSomeCollision in place of
   IsColliding to make constraint based linksets properly notice the ground.
Add linkset functions to change physical attributes of all the members
   of a linkset.
2013-07-22 10:27:15 -07:00
Robert Adams
13a4a80b38 Add experimental stubs for an extension function interface on both
PhysicsScene and PhysicsActor.
2013-07-22 10:27:09 -07:00
Robert Adams
803632f8f3 BulletSim: freshen up the code for constraint based linksets. 2013-07-22 10:27:06 -07:00
Diva Canto
df63bfafef Better version of previous commit 2013-07-21 15:42:22 -07:00
Diva Canto
f81e289a1b Add the Current Outfit folder as an available folder in the SuitcaseInventory. 2013-07-21 15:42:05 -07:00
Diva Canto
99a727600b Minor cosmetic changes. 2013-07-21 10:07:35 -07:00
Diva Canto
8d18ad2f6f Minor aesthetic change to make things more clear. 2013-07-21 09:02:56 -07:00
351 changed files with 28261 additions and 3075 deletions

View File

@@ -65,6 +65,7 @@ what it is today.
* A_Biondi
* alex_carnell
* Alan Webb (IBM)
* Aleric
* Allen Kerensky
* BigFootAg
* BlueWall Slade
@@ -86,6 +87,7 @@ what it is today.
* Garmin Kawaguichi
* Gerhard
* Godfrey
* Greg C.
* Grumly57
* GuduleLapointe
* Ewe Loon

View File

@@ -504,6 +504,30 @@ namespace OpenSim.Groups
return notice;
}
public static Dictionary<string, object> DirGroupsReplyData(DirGroupsReplyData g)
{
Dictionary<string, object> dict = new Dictionary<string, object>();
dict["GroupID"] = g.groupID;
dict["Name"] = g.groupName;
dict["NMembers"] = g.members;
dict["SearchOrder"] = g.searchOrder;
return dict;
}
public static DirGroupsReplyData DirGroupsReplyData(Dictionary<string, object> dict)
{
DirGroupsReplyData g;
g.groupID = new UUID(dict["GroupID"].ToString());
g.groupName = dict["Name"].ToString();
Int32.TryParse(dict["NMembers"].ToString(), out g.members);
float.TryParse(dict["SearchOrder"].ToString(), out g.searchOrder);
return g;
}
}
}

View File

@@ -39,6 +39,7 @@ 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
{
@@ -51,7 +52,7 @@ namespace OpenSim.Groups
private IPresenceService m_presenceService;
private IMessageTransferModule m_msgTransferModule = null;
private IUserManagement m_UserManagement = null;
private IGroupsServicesConnector m_groupData = null;
// Config Options
@@ -79,6 +80,10 @@ namespace OpenSim.Groups
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)
@@ -124,10 +129,12 @@ namespace OpenSim.Groups
m_sceneList.Add(scene);
scene.EventManager.OnNewClient += OnNewClient;
scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
scene.EventManager.OnMakeChildAgent += OnMakeChildAgent;
scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
scene.EventManager.OnClientLogin += OnClientLogin;
}
public void RegionLoaded(Scene scene)
{
if (!m_groupMessagingEnabled)
@@ -155,6 +162,17 @@ namespace OpenSim.Groups
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;
@@ -227,87 +245,107 @@ namespace OpenSim.Groups
public void SendMessageToGroup(GridInstantMessage im, UUID groupID)
{
List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(new UUID(im.fromAgentID).ToString(), groupID);
UUID fromAgentID = new UUID(im.fromAgentID);
List<GroupMembersData> groupMembers = m_groupData.GetGroupMembers(UUID.Zero.ToString(), groupID);
int groupMembersCount = groupMembers.Count;
PresenceInfo[] onlineAgents = null;
if (m_messageOnlineAgentsOnly)
// 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 overwhlem 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))
{
string[] t1 = groupMembers.ConvertAll<string>(gmd => gmd.AgentID.ToString()).ToArray();
onlineAgents = m_presenceService.GetAgents(t1);
m_usersOnlineCache.Add(groupID, onlineAgents, m_usersOnlineCacheExpirySeconds);
}
// We cache in order not to overwhlem 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).
PresenceInfo[] onlineAgents;
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));
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();
groupMembers = groupMembers.Where(gmd => onlineAgentsUuidSet.Contains(gmd.AgentID.ToString())).ToList();
// if (m_debugEnabled)
// if (m_debugEnabled)
// m_log.DebugFormat(
// "[Groups.Messaging]: SendMessageToGroup called for group {0} with {1} visible members, {2} online",
// groupID, groupMembersCount, groupMembers.Count());
}
else
{
if (m_debugEnabled)
m_log.DebugFormat(
"[Groups.Messaging]: SendMessageToGroup called for group {0} with {1} visible members",
groupID, groupMembers.Count);
}
int requestStartTick = Environment.TickCount;
im.imSessionID = groupID.Guid;
im.fromGroup = true;
IClientAPI thisClient = GetActiveClient(fromAgentID);
if (thisClient != null)
{
im.RegionID = thisClient.Scene.RegionInfo.RegionID.Guid;
}
// 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 (m_groupData.hasAgentDroppedGroupChatSession(member.AgentID.ToString(), groupID))
if (member.AgentID.Guid == im.fromAgentID)
continue;
if (clientsAlreadySent.Contains(member.AgentID))
continue;
clientsAlreadySent.Add(member.AgentID);
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;
}
// Copy Message
GridInstantMessage msg = new GridInstantMessage();
msg.imSessionID = groupID.Guid;
msg.fromAgentName = im.fromAgentName;
msg.message = im.message;
msg.dialog = im.dialog;
msg.offline = im.offline;
msg.ParentEstateID = im.ParentEstateID;
msg.Position = im.Position;
msg.RegionID = im.RegionID;
msg.binaryBucket = im.binaryBucket;
msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
msg.fromAgentID = im.fromAgentID;
msg.fromGroup = true;
msg.toAgentID = member.AgentID.Guid;
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);
m_msgTransferModule.SendInstantMessage(msg, delegate(bool success) { });
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(msg);
ProcessMessageFromGroupSession(im);
}
}
// Temporary for assessing how long it still takes to send messages to large online groups.
if (m_messageOnlineAgentsOnly)
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);
@@ -324,9 +362,20 @@ namespace OpenSim.Groups
{
if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: OnInstantMessage registered for {0}", client.Name);
client.OnInstantMessage += OnInstantMessage;
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:
@@ -335,21 +384,91 @@ namespace OpenSim.Groups
// 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", System.Reflection.MethodBase.GetCurrentMethod().Name);
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)
|| (msg.dialog == (byte)InstantMessageDialog.SessionAdd)
|| (msg.dialog == (byte)InstantMessageDialog.SessionDrop)))
if ((msg.fromGroup == true) && (msg.dialog == (byte)InstantMessageDialog.SessionSend))
{
ProcessMessageFromGroupSession(msg);
// 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);
}
}
});
}
}
}
@@ -359,82 +478,40 @@ namespace OpenSim.Groups
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:
m_groupData.AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
break;
case (byte)InstantMessageDialog.SessionDrop:
m_groupData.AgentDroppedFromGroupChatSession(AgentID.ToString(), GroupID);
AgentDroppedFromGroupChatSession(AgentID.ToString(), GroupID);
break;
case (byte)InstantMessageDialog.SessionSend:
if (!m_groupData.hasAgentDroppedGroupChatSession(AgentID.ToString(), GroupID)
&& !m_groupData.hasAgentBeenInvitedToGroupChatSession(AgentID.ToString(), GroupID)
)
// 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)
{
// Agent not in session and hasn't dropped from session
// Add them to the session for now, and Invite them
m_groupData.AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
// Deliver locally, directly
if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Delivering to {0} locally", client.Name);
UUID toAgentID = new UUID(msg.toAgentID);
IClientAPI activeClient = GetActiveClient(toAgentID);
if (activeClient != null)
if (!hasAgentDroppedGroupChatSession(toAgentID.ToString(), GroupID))
{
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");
// 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>();
eq.ChatterboxInvitation(
GroupID
, groupInfo.GroupName
, new UUID(msg.fromAgentID)
, msg.message
, new UUID(msg.toAgentID)
, 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)
);
eq.ChatterBoxSessionAgentListUpdates(
new UUID(GroupID)
, new UUID(msg.fromAgentID)
, new UUID(msg.toAgentID)
, false //canVoiceChat
, false //isModerator
, false //text mute
);
}
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 if (!m_groupData.hasAgentDroppedGroupChatSession(AgentID.ToString(), GroupID))
else
{
// 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);
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);
}
m_log.WarnFormat("[Groups.Messaging]: Received a message over the grid for a client that isn't here: {0}", msg.toAgentID);
}
break;
@@ -444,6 +521,53 @@ namespace OpenSim.Groups
}
}
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");
// 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>();
eq.ChatterboxInvitation(
GroupID
, groupInfo.GroupName
, new UUID(msg.fromAgentID)
, 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)
);
eq.ChatterBoxSessionAgentListUpdates(
new UUID(GroupID)
, AgentID
, new UUID(msg.toAgentID)
, false //canVoiceChat
, false //isModerator
, false //text mute
);
}
}
}
#endregion
@@ -469,7 +593,7 @@ namespace OpenSim.Groups
if (groupInfo != null)
{
m_groupData.AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
ChatterBoxSessionStartReplyViaCaps(remoteClient, groupInfo.GroupName, GroupID);
@@ -495,7 +619,7 @@ namespace OpenSim.Groups
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
m_groupData.AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
AgentInvitedToGroupChatSession(AgentID.ToString(), GroupID);
SendMessageToGroup(im, GroupID);
}
@@ -566,12 +690,12 @@ namespace OpenSim.Groups
{
if (!sp.IsChildAgent)
{
if (m_debugEnabled) m_log.WarnFormat("[Groups.Messaging]: Found root agent for client : {0}", sp.ControllingClient.Name);
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.WarnFormat("[Groups.Messaging]: Found child agent for client : {0}", sp.ControllingClient.Name);
if (m_debugEnabled) m_log.DebugFormat("[Groups.Messaging]: Found child agent for client : {0}", sp.ControllingClient.Name);
child = sp.ControllingClient;
}
}
@@ -590,5 +714,71 @@ namespace OpenSim.Groups
}
#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
}
}

View File

@@ -141,6 +141,8 @@ namespace OpenSim.Groups
if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
scene.EventManager.OnNewClient += OnNewClient;
scene.EventManager.OnMakeRootAgent += OnMakeRoot;
scene.EventManager.OnMakeChildAgent += OnMakeChild;
scene.EventManager.OnIncomingInstantMessage += OnGridInstantMessage;
// The InstantMessageModule itself doesn't do this,
// so lets see if things explode if we don't do it
@@ -194,6 +196,8 @@ namespace OpenSim.Groups
if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
scene.EventManager.OnNewClient -= OnNewClient;
scene.EventManager.OnMakeRootAgent -= OnMakeRoot;
scene.EventManager.OnMakeChildAgent -= OnMakeChild;
scene.EventManager.OnIncomingInstantMessage -= OnGridInstantMessage;
lock (m_sceneList)
@@ -232,16 +236,29 @@ namespace OpenSim.Groups
{
if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
client.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest;
client.OnAgentDataUpdateRequest += OnAgentDataUpdateRequest;
client.OnDirFindQuery += OnDirFindQuery;
client.OnRequestAvatarProperties += OnRequestAvatarProperties;
}
private void OnMakeRoot(ScenePresence sp)
{
if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
sp.ControllingClient.OnUUIDGroupNameRequest += HandleUUIDGroupNameRequest;
// Used for Notices and Group Invites/Accept/Reject
client.OnInstantMessage += OnInstantMessage;
sp.ControllingClient.OnInstantMessage += OnInstantMessage;
// Send client their groups information.
SendAgentGroupDataUpdate(client, client.AgentId);
SendAgentGroupDataUpdate(sp.ControllingClient, sp.UUID);
}
private void OnMakeChild(ScenePresence sp)
{
if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
sp.ControllingClient.OnUUIDGroupNameRequest -= HandleUUIDGroupNameRequest;
// Used for Notices and Group Invites/Accept/Reject
sp.ControllingClient.OnInstantMessage -= OnInstantMessage;
}
private void OnRequestAvatarProperties(IClientAPI remoteClient, UUID avatarID)
@@ -287,21 +304,6 @@ namespace OpenSim.Groups
}
*/
void OnDirFindQuery(IClientAPI remoteClient, UUID queryID, string queryText, uint queryFlags, int queryStart)
{
if (((DirFindFlags)queryFlags & DirFindFlags.Groups) == DirFindFlags.Groups)
{
if (m_debugEnabled)
m_log.DebugFormat(
"[Groups]: {0} called with queryText({1}) queryFlags({2}) queryStart({3})",
System.Reflection.MethodBase.GetCurrentMethod().Name, queryText, (DirFindFlags)queryFlags, queryStart);
// TODO: This currently ignores pretty much all the query flags including Mature and sort order
remoteClient.SendDirGroupsReply(queryID, m_groupData.FindGroups(GetRequestingAgentIDStr(remoteClient), queryText).ToArray());
}
}
private void OnAgentDataUpdateRequest(IClientAPI remoteClient, UUID dataForAgentID, UUID sessionID)
{
if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
@@ -465,12 +467,12 @@ namespace OpenSim.Groups
}
// Send notice out to everyone that wants notices
// Build notice IIM
GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice);
foreach (GroupMembersData member in m_groupData.GetGroupMembers(GetRequestingAgentIDStr(remoteClient), GroupID))
{
if (member.AcceptNotices)
{
// Build notice IIM, one of reach, because the sending may be async
GridInstantMessage msg = CreateGroupNoticeIM(UUID.Zero, NoticeID, (byte)OpenMetaverse.InstantMessageDialog.GroupNotice);
msg.toAgentID = member.AgentID.Guid;
OutgoingInstantMessage(msg, member.AgentID);
}
@@ -907,23 +909,7 @@ namespace OpenSim.Groups
{
if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called for notice {1}", System.Reflection.MethodBase.GetCurrentMethod().Name, groupNoticeID);
//GroupRecord groupInfo = m_groupData.GetGroupRecord(GetRequestingAgentID(remoteClient), data.GroupID, null);
GridInstantMessage msg = CreateGroupNoticeIM(remoteClient.AgentId, groupNoticeID, (byte)InstantMessageDialog.GroupNoticeRequested);
//GridInstantMessage msg = new GridInstantMessage();
//msg.imSessionID = UUID.Zero.Guid;
//msg.fromAgentID = data.GroupID.Guid;
//msg.toAgentID = GetRequestingAgentID(remoteClient).Guid;
//msg.timestamp = (uint)Util.UnixTimeSinceEpoch();
//msg.fromAgentName = "Group Notice : " + groupInfo == null ? "Unknown" : groupInfo.GroupName;
//msg.message = data.noticeData.Subject + "|" + data.Message;
//msg.dialog = (byte)OpenMetaverse.InstantMessageDialog.GroupNoticeRequested;
//msg.fromGroup = true;
//msg.offline = (byte)0;
//msg.ParentEstateID = 0;
//msg.Position = Vector3.Zero;
//msg.RegionID = UUID.Zero.Guid;
//msg.binaryBucket = data.BinaryBucket;
OutgoingInstantMessage(msg, GetRequestingAgentID(remoteClient));
}
@@ -1005,6 +991,10 @@ namespace OpenSim.Groups
// Should this send updates to everyone in the group?
SendAgentGroupDataUpdate(remoteClient, GetRequestingAgentID(remoteClient));
if (reason != string.Empty)
// A warning
remoteClient.SendAlertMessage("Warning: " + reason);
}
else
remoteClient.SendJoinGroupReply(groupID, false);
@@ -1189,6 +1179,11 @@ namespace OpenSim.Groups
}
}
public List<DirGroupsReplyData> FindGroups(IClientAPI remoteClient, string query)
{
return m_groupData.FindGroups(GetRequestingAgentIDStr(remoteClient), query);
}
#endregion
#region Client/Update Tools
@@ -1228,12 +1223,16 @@ namespace OpenSim.Groups
{
if (m_debugEnabled) m_log.InfoFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
// NPCs currently don't have a CAPs structure or event queues. There is a strong argument for conveying this information
// to them anyway since it makes writing server-side bots a lot easier, but for now we don't do anything.
if (remoteClient.SceneAgent.PresenceType == PresenceType.Npc)
return;
OSDArray AgentData = new OSDArray(1);
OSDMap AgentDataMap = new OSDMap(1);
AgentDataMap.Add("AgentID", OSD.FromUUID(dataForAgentID));
AgentData.Add(AgentDataMap);
OSDArray GroupData = new OSDArray(data.Length);
OSDArray NewGroupData = new OSDArray(data.Length);
@@ -1279,8 +1278,7 @@ namespace OpenSim.Groups
if (queue != null)
{
queue.Enqueue(queue.BuildEvent("AgentGroupDataUpdate", llDataStruct), GetRequestingAgentID(remoteClient));
}
}
}
private void SendScenePresenceUpdate(UUID AgentID, string Title)
@@ -1342,6 +1340,7 @@ namespace OpenSim.Groups
GroupMembershipData[] membershipArray = GetProfileListedGroupMemberships(remoteClient, dataForAgentID);
SendGroupMembershipInfoViaCaps(remoteClient, dataForAgentID, membershipArray);
//remoteClient.SendAvatarGroupsReply(dataForAgentID, membershipArray);
if (remoteClient.AgentId == dataForAgentID)
remoteClient.RefreshGroupMembership();
@@ -1402,19 +1401,18 @@ namespace OpenSim.Groups
if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
// TODO: All the client update functions need to be reexamined because most do too much and send too much stuff
UserAccount account = m_sceneList[0].UserAccountService.GetUserAccount(remoteClient.Scene.RegionInfo.ScopeID, dataForAgentID);
string firstname, lastname;
if (account != null)
string firstname = "Unknown", lastname = "Unknown";
string name = m_UserManagement.GetUserName(dataForAgentID);
if (!string.IsNullOrEmpty(name))
{
firstname = account.FirstName;
lastname = account.LastName;
string[] parts = name.Split(new char[] { ' ' });
if (parts.Length >= 2)
{
firstname = parts[0];
lastname = parts[1];
}
}
else
{
firstname = "Unknown";
lastname = "Unknown";
}
remoteClient.SendAgentDataUpdate(dataForAgentID, activeGroupID, firstname,
lastname, activeGroupPowers, activeGroupName,
activeGroupTitle);

View File

@@ -254,7 +254,10 @@ namespace OpenSim.Groups
{
string url = string.Empty, gname = string.Empty;
if (IsLocal(GroupID, out url, out gname))
return m_LocalGroupsConnector.GetGroupMembers(AgentUUI(RequestingAgentID), GroupID);
{
string agentID = AgentUUI(RequestingAgentID);
return m_LocalGroupsConnector.GetGroupMembers(agentID, GroupID);
}
else if (!string.IsNullOrEmpty(url))
{
ExtendedGroupMembershipData membership = m_LocalGroupsConnector.GetAgentGroupMembership(RequestingAgentID, RequestingAgentID, GroupID);
@@ -396,17 +399,21 @@ namespace OpenSim.Groups
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 = "User doesn't have a groups server";
return false;
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)
return c.CreateProxy(AgentUUI(RequestingAgentID), AgentID, token, GroupID, m_LocalGroupsServiceLocation, name, out reason);
c.CreateProxy(AgentUUI(RequestingAgentID), AgentID, token, GroupID, m_LocalGroupsServiceLocation, name, out reason);
return true;
}
return false;
}
}
else if (m_UserManagement.IsLocalGridUser(uid)) // local user
@@ -590,28 +597,6 @@ namespace OpenSim.Groups
return m_LocalGroupsConnector.GetGroupNotices(AgentUUI(RequestingAgentID), GroupID);
}
public void ResetAgentGroupChatSessions(string agentID)
{
}
public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID)
{
return false;
}
public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID)
{
return false;
}
public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID)
{
}
public void AgentInvitedToGroupChatSession(string agentID, UUID groupID)
{
}
#endregion
#region hypergrid groups
@@ -638,10 +623,13 @@ namespace OpenSim.Groups
if (agent != null)
break;
}
if (agent == null) // oops
return AgentID.ToString();
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);
return Util.ProduceUserUniversalIdentifier(agent);
}
private string AgentUUIForOutside(string AgentIDStr)

View File

@@ -92,12 +92,6 @@ namespace OpenSim.Groups
GroupNoticeInfo GetGroupNotice(string RequestingAgentID, UUID noticeID);
List<ExtendedGroupNoticeData> GetGroupNotices(string RequestingAgentID, UUID GroupID);
void ResetAgentGroupChatSessions(string agentID);
bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID);
bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID);
void AgentDroppedFromGroupChatSession(string agentID, UUID groupID);
void AgentInvitedToGroupChatSession(string agentID, UUID groupID);
}
public class GroupInviteInfo

View File

@@ -320,28 +320,6 @@ namespace OpenSim.Groups
return m_GroupsService.GetGroupNotices(RequestingAgentID, GroupID);
}
public void ResetAgentGroupChatSessions(string agentID)
{
}
public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID)
{
return false;
}
public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID)
{
return false;
}
public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID)
{
}
public void AgentInvitedToGroupChatSession(string agentID, UUID groupID)
{
}
#endregion
}
}

View File

@@ -30,7 +30,7 @@ using Mono.Addins;
// Build Number
// Revision
//
[assembly: AssemblyVersion("0.7.6.*")]
[assembly: AssemblyVersion("0.8.0.*")]
[assembly: Addin("OpenSim.Groups", "0.1")]
[assembly: AddinDependency("OpenSim", "0.5")]

View File

@@ -133,6 +133,36 @@ namespace OpenSim.Groups
return GroupsDataUtils.GroupRecord((Dictionary<string, object>)ret["RESULT"]);
}
public List<DirGroupsReplyData> FindGroups(string RequestingAgentID, 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"] = RequestingAgentID;
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;
@@ -226,6 +256,7 @@ namespace OpenSim.Groups
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)

View File

@@ -199,7 +199,7 @@ namespace OpenSim.Groups
public List<DirGroupsReplyData> FindGroups(string RequestingAgentID, string search)
{
// TODO!
return new List<DirGroupsReplyData>();
return m_GroupsService.FindGroups(RequestingAgentID, search);
}
public bool AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID, string token, out string reason)
@@ -406,28 +406,6 @@ namespace OpenSim.Groups
});
}
public void ResetAgentGroupChatSessions(string agentID)
{
}
public bool hasAgentBeenInvitedToGroupChatSession(string agentID, UUID groupID)
{
return false;
}
public bool hasAgentDroppedGroupChatSession(string agentID, UUID groupID)
{
return false;
}
public void AgentDroppedFromGroupChatSession(string agentID, UUID groupID)
{
}
public void AgentInvitedToGroupChatSession(string agentID, UUID groupID)
{
}
#endregion
}

View File

@@ -133,6 +133,8 @@ namespace OpenSim.Groups
return HandleAddNotice(request);
case "GETNOTICES":
return HandleGetNotices(request);
case "FINDGROUPS":
return HandleFindGroups(request);
}
m_log.DebugFormat("[GROUPS HANDLER]: unknown method request: {0}", method);
}
@@ -740,6 +742,32 @@ namespace OpenSim.Groups
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

View File

@@ -53,7 +53,7 @@ namespace OpenSim.Groups
private ForeignImporter m_ForeignImporter;
private Dictionary<string, bool> m_ActiveRequests = new Dictionary<string, bool>();
private const int GROUPS_CACHE_TIMEOUT = 5 * 60; // 5 minutes
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

View File

@@ -255,13 +255,20 @@ namespace OpenSim.Groups
return members;
List<RoleData> rolesList = new List<RoleData>(roles);
// Is the requester a member of the group?
bool isInGroup = false;
if (m_Database.RetrieveMember(GroupID, RequestingAgentID) != null)
isInGroup = true;
// Check visibility?
// When we don't want to check visibility, we pass it "all" as the requestingAgentID
bool checkVisibility = !RequestingAgentID.Equals(UUID.Zero.ToString());
if (!isInGroup) // reduce the roles to the visible ones
rolesList = rolesList.FindAll(r => (UInt64.Parse(r.Data["Powers"]) & (ulong)GroupPowers.MemberVisible) != 0);
if (checkVisibility)
{
// Is the requester a member of the group?
bool isInGroup = false;
if (m_Database.RetrieveMember(GroupID, RequestingAgentID) != null)
isInGroup = true;
if (!isInGroup) // reduce the roles to the visible ones
rolesList = rolesList.FindAll(r => (UInt64.Parse(r.Data["Powers"]) & (ulong)GroupPowers.MemberVisible) != 0);
}
MembershipData[] datas = m_Database.RetrieveMembers(GroupID);
if (datas == null || (datas != null && datas.Length == 0))

View File

@@ -30,7 +30,7 @@ using Mono.Addins;
// Build Number
// Revision
//
[assembly: AssemblyVersion("0.7.6.*")]
[assembly: AssemblyVersion("0.8.0.*")]
[assembly: Addin("OpenSim.OfflineIM", "0.1")]
[assembly: AddinDependency("OpenSim", "0.5")]

View File

@@ -62,4 +62,4 @@ using System.Runtime.InteropServices;
// by using the '*' as shown below:
// [assembly: AssemblyVersion("0.7.6.*")]
[assembly : AssemblyVersion("0.7.6.*")]
[assembly : AssemblyVersion("0.8.0.*")]

View File

@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
[assembly: AssemblyVersion("0.7.6.*")]
[assembly: AssemblyVersion("0.8.0.*")]

View File

@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
[assembly: AssemblyVersion("0.7.6.*")]
[assembly: AssemblyVersion("0.8.0.*")]

View File

@@ -327,18 +327,26 @@ namespace OpenSim.ApplicationPlugins.RemoteController
// k, (string)requestData[k], ((string)requestData[k]).Length);
// }
CheckStringParameters(requestData, responseData, new string[] {"filename", "regionid"});
CheckStringParameters(requestData, responseData, new string[] { "filename" });
CheckRegionParams(requestData, responseData);
Scene scene = null;
GetSceneFromRegionParams(requestData, responseData, out scene);
string file = (string)requestData["filename"];
responseData["accepted"] = true;
if (scene != null)
{
string file = (string)requestData["filename"];
LoadHeightmap(file, scene.RegionInfo.RegionID);
responseData["accepted"] = true;
responseData["success"] = true;
LoadHeightmap(file, scene.RegionInfo.RegionID);
responseData["success"] = true;
}
else
{
responseData["success"] = false;
}
m_log.Info("[RADMIN]: Load height maps request complete");
}
@@ -352,23 +360,30 @@ namespace OpenSim.ApplicationPlugins.RemoteController
// m_log.DebugFormat("[RADMIN]: Save Terrain: XmlRpc {0}", request.ToString());
CheckStringParameters(requestData, responseData, new string[] { "filename", "regionid" });
CheckStringParameters(requestData, responseData, new string[] { "filename" });
CheckRegionParams(requestData, responseData);
Scene region = null;
GetSceneFromRegionParams(requestData, responseData, out region);
Scene scene = null;
GetSceneFromRegionParams(requestData, responseData, out scene);
string file = (string)requestData["filename"];
m_log.InfoFormat("[RADMIN]: Terrain Saving: {0}", file);
if (scene != null)
{
string file = (string)requestData["filename"];
m_log.InfoFormat("[RADMIN]: Terrain Saving: {0}", file);
responseData["accepted"] = true;
responseData["accepted"] = true;
ITerrainModule terrainModule = region.RequestModuleInterface<ITerrainModule>();
if (null == terrainModule) throw new Exception("terrain module not available");
ITerrainModule terrainModule = scene.RequestModuleInterface<ITerrainModule>();
if (null == terrainModule) throw new Exception("terrain module not available");
terrainModule.SaveToFile(file);
terrainModule.SaveToFile(file);
responseData["success"] = true;
responseData["success"] = true;
}
else
{
responseData["success"] = false;
}
m_log.Info("[RADMIN]: Save height maps request complete");
}

View File

@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
[assembly: AssemblyVersion("0.7.6.*")]
[assembly: AssemblyVersion("0.8.0.*")]

View File

@@ -81,6 +81,7 @@ namespace OpenSim.Data
bool Delete(UUID regionID);
List<RegionData> GetDefaultRegions(UUID scopeID);
List<RegionData> GetDefaultHypergridRegions(UUID scopeID);
List<RegionData> GetFallbackRegions(UUID scopeID, int x, int y);
List<RegionData> GetHyperlinks(UUID scopeID);
}

View File

@@ -315,6 +315,11 @@ namespace OpenSim.Data.MSSQL
return Get((int)RegionFlags.DefaultRegion, scopeID);
}
public List<RegionData> GetDefaultHypergridRegions(UUID scopeID)
{
return Get((int)RegionFlags.DefaultHGRegion, scopeID);
}
public List<RegionData> GetFallbackRegions(UUID scopeID, int x, int y)
{
List<RegionData> regions = Get((int)RegionFlags.FallbackRegion, scopeID);

View File

@@ -351,7 +351,7 @@ IF EXISTS (SELECT UUID FROM prims WHERE UUID = @UUID)
ScriptAccessPin = @ScriptAccessPin, AllowedDrop = @AllowedDrop, DieAtEdge = @DieAtEdge, SalePrice = @SalePrice,
SaleType = @SaleType, ColorR = @ColorR, ColorG = @ColorG, ColorB = @ColorB, ColorA = @ColorA, ParticleSystem = @ParticleSystem,
ClickAction = @ClickAction, Material = @Material, CollisionSound = @CollisionSound, CollisionSoundVolume = @CollisionSoundVolume, PassTouches = @PassTouches,
LinkNumber = @LinkNumber, MediaURL = @MediaURL, DynAttrs = @DynAttrs,
LinkNumber = @LinkNumber, MediaURL = @MediaURL, AttachedPosX = @AttachedPosX, AttachedPosY = @AttachedPosY, AttachedPosZ = @AttachedPosZ, DynAttrs = @DynAttrs,
PhysicsShapeType = @PhysicsShapeType, Density = @Density, GravityModifier = @GravityModifier, Friction = @Friction, Restitution = @Restitution
WHERE UUID = @UUID
END
@@ -367,7 +367,7 @@ ELSE
PayPrice, PayButton1, PayButton2, PayButton3, PayButton4, LoopedSound, LoopedSoundGain, TextureAnimation, OmegaX,
OmegaY, OmegaZ, CameraEyeOffsetX, CameraEyeOffsetY, CameraEyeOffsetZ, CameraAtOffsetX, CameraAtOffsetY, CameraAtOffsetZ,
ForceMouselook, ScriptAccessPin, AllowedDrop, DieAtEdge, SalePrice, SaleType, ColorR, ColorG, ColorB, ColorA,
ParticleSystem, ClickAction, Material, CollisionSound, CollisionSoundVolume, PassTouches, LinkNumber, MediaURL, DynAttrs,
ParticleSystem, ClickAction, Material, CollisionSound, CollisionSoundVolume, PassTouches, LinkNumber, MediaURL, AttachedPosX, AttachedPosY, AttachedPosZ, DynAttrs,
PhysicsShapeType, Density, GravityModifier, Friction, Restitution
) VALUES (
@UUID, @CreationDate, @Name, @Text, @Description, @SitName, @TouchName, @ObjectFlags, @OwnerMask, @NextOwnerMask, @GroupMask,
@@ -378,7 +378,7 @@ ELSE
@PayPrice, @PayButton1, @PayButton2, @PayButton3, @PayButton4, @LoopedSound, @LoopedSoundGain, @TextureAnimation, @OmegaX,
@OmegaY, @OmegaZ, @CameraEyeOffsetX, @CameraEyeOffsetY, @CameraEyeOffsetZ, @CameraAtOffsetX, @CameraAtOffsetY, @CameraAtOffsetZ,
@ForceMouselook, @ScriptAccessPin, @AllowedDrop, @DieAtEdge, @SalePrice, @SaleType, @ColorR, @ColorG, @ColorB, @ColorA,
@ParticleSystem, @ClickAction, @Material, @CollisionSound, @CollisionSoundVolume, @PassTouches, @LinkNumber, @MediaURL, @DynAttrs,
@ParticleSystem, @ClickAction, @Material, @CollisionSound, @CollisionSoundVolume, @PassTouches, @LinkNumber, @MediaURL, @AttachedPosX, @AttachedPosY, @AttachedPosZ, @DynAttrs,
@PhysicsShapeType, @Density, @GravityModifier, @Friction, @Restitution
)
END";
@@ -1695,6 +1695,12 @@ VALUES
if (!(primRow["MediaURL"] is System.DBNull))
prim.MediaUrl = (string)primRow["MediaURL"];
if (!(primRow["AttachedPosX"] is System.DBNull))
prim.AttachedPos = new Vector3(
Convert.ToSingle(primRow["AttachedPosX"]),
Convert.ToSingle(primRow["AttachedPosY"]),
Convert.ToSingle(primRow["AttachedPosZ"]));
if (!(primRow["DynAttrs"] is System.DBNull))
prim.DynAttrs = DAMap.FromXml((string)primRow["DynAttrs"]);
else
@@ -2099,7 +2105,10 @@ VALUES
parameters.Add(_Database.CreateParameter("PassTouches", 0));
parameters.Add(_Database.CreateParameter("LinkNumber", prim.LinkNum));
parameters.Add(_Database.CreateParameter("MediaURL", prim.MediaUrl));
parameters.Add(_Database.CreateParameter("AttachedPosX", prim.AttachedPos.X));
parameters.Add(_Database.CreateParameter("AttachedPosY", prim.AttachedPos.Y));
parameters.Add(_Database.CreateParameter("AttachedPosZ", prim.AttachedPos.Z));
if (prim.DynAttrs.CountNamespaces > 0)
parameters.Add(_Database.CreateParameter("DynAttrs", prim.DynAttrs.ToXml()));
else

View File

@@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly : AssemblyVersion("0.7.6.*")]
[assembly : AssemblyVersion("0.8.0.*")]

View File

@@ -1168,3 +1168,15 @@ ALTER TABLE prims ADD `Friction` double NOT NULL default '0.6';
ALTER TABLE prims ADD `Restitution` double NOT NULL default '0.5';
COMMIT
:VERSION 40 #---------------- Save Attachment info
BEGIN TRANSACTION
ALTER TABLE prims ADD AttachedPosX float(53) default 0.0;
ALTER TABLE prims ADD AttachedPosY float(53) default 0.0;
ALTER TABLE prims ADD AttachedPosZ float(53) default 0.0;
ALTER TABLE primshapes ADD LastAttachPoint int not null default 0;
COMMIT

View File

@@ -88,7 +88,7 @@ namespace OpenSim.Data.MySQL
if (string.IsNullOrEmpty(pattern))
pattern = "1 ORDER BY Name LIMIT 100";
else
pattern = string.Format("Name LIKE %{0}% ORDER BY Name LIMIT 100", pattern);
pattern = string.Format("Name LIKE '%{0}%' ORDER BY Name LIMIT 100", pattern);
return m_Groups.Get(pattern);
}

View File

@@ -310,6 +310,11 @@ namespace OpenSim.Data.MySQL
return Get((int)RegionFlags.DefaultRegion, scopeID);
}
public List<RegionData> GetDefaultHypergridRegions(UUID scopeID)
{
return Get((int)RegionFlags.DefaultHGRegion, scopeID);
}
public List<RegionData> GetFallbackRegions(UUID scopeID, int x, int y)
{
List<RegionData> regions = Get((int)RegionFlags.FallbackRegion, scopeID);

View File

@@ -173,7 +173,8 @@ namespace OpenSim.Data.MySQL
"ParticleSystem, ClickAction, Material, " +
"CollisionSound, CollisionSoundVolume, " +
"PassTouches, " +
"LinkNumber, MediaURL, KeyframeMotion, " +
"LinkNumber, MediaURL, AttachedPosX, " +
"AttachedPosY, AttachedPosZ, KeyframeMotion, " +
"PhysicsShapeType, Density, GravityModifier, " +
"Friction, Restitution, DynAttrs " +
") values (" + "?UUID, " +
@@ -208,7 +209,8 @@ namespace OpenSim.Data.MySQL
"?ColorB, ?ColorA, ?ParticleSystem, " +
"?ClickAction, ?Material, ?CollisionSound, " +
"?CollisionSoundVolume, ?PassTouches, " +
"?LinkNumber, ?MediaURL, ?KeyframeMotion, " +
"?LinkNumber, ?MediaURL, ?AttachedPosX, " +
"?AttachedPosY, ?AttachedPosZ, ?KeyframeMotion, " +
"?PhysicsShapeType, ?Density, ?GravityModifier, " +
"?Friction, ?Restitution, ?DynAttrs)";
@@ -227,7 +229,7 @@ namespace OpenSim.Data.MySQL
"PathTaperX, PathTaperY, PathTwist, " +
"PathTwistBegin, ProfileBegin, ProfileEnd, " +
"ProfileCurve, ProfileHollow, Texture, " +
"ExtraParams, State, Media) " +
"ExtraParams, State, LastAttachPoint, Media) " +
"values (?UUID, " +
"?Shape, ?ScaleX, ?ScaleY, ?ScaleZ, " +
"?PCode, ?PathBegin, ?PathEnd, " +
@@ -239,7 +241,7 @@ namespace OpenSim.Data.MySQL
"?PathTwistBegin, ?ProfileBegin, " +
"?ProfileEnd, ?ProfileCurve, " +
"?ProfileHollow, ?Texture, ?ExtraParams, " +
"?State, ?Media)";
"?State, ?LastAttachPoint, ?Media)";
FillShapeCommand(cmd, prim);
@@ -1303,7 +1305,16 @@ namespace OpenSim.Data.MySQL
if (!(row["MediaURL"] is System.DBNull))
prim.MediaUrl = (string)row["MediaURL"];
if (!(row["AttachedPosX"] is System.DBNull))
{
prim.AttachedPos = new Vector3(
(float)(double)row["AttachedPosX"],
(float)(double)row["AttachedPosY"],
(float)(double)row["AttachedPosZ"]
);
}
if (!(row["DynAttrs"] is System.DBNull))
prim.DynAttrs = DAMap.FromXml((string)row["DynAttrs"]);
else
@@ -1673,6 +1684,12 @@ namespace OpenSim.Data.MySQL
cmd.Parameters.AddWithValue("LinkNumber", prim.LinkNum);
cmd.Parameters.AddWithValue("MediaURL", prim.MediaUrl);
if (prim.AttachedPos != null)
{
cmd.Parameters.AddWithValue("AttachedPosX", (double)prim.AttachedPos.X);
cmd.Parameters.AddWithValue("AttachedPosY", (double)prim.AttachedPos.Y);
cmd.Parameters.AddWithValue("AttachedPosZ", (double)prim.AttachedPos.Z);
}
if (prim.KeyframeMotion != null)
cmd.Parameters.AddWithValue("KeyframeMotion", prim.KeyframeMotion.Serialize());
@@ -1879,6 +1896,7 @@ namespace OpenSim.Data.MySQL
s.ExtraParams = (byte[])row["ExtraParams"];
s.State = (byte)(int)row["State"];
s.LastAttachPoint = (byte)(int)row["LastAttachPoint"];
if (!(row["Media"] is System.DBNull))
s.Media = PrimitiveBaseShape.MediaList.FromXml((string)row["Media"]);
@@ -1925,6 +1943,7 @@ namespace OpenSim.Data.MySQL
cmd.Parameters.AddWithValue("Texture", s.TextureEntry);
cmd.Parameters.AddWithValue("ExtraParams", s.ExtraParams);
cmd.Parameters.AddWithValue("State", s.State);
cmd.Parameters.AddWithValue("LastAttachPoint", s.LastAttachPoint);
cmd.Parameters.AddWithValue("Media", null == s.Media ? null : s.Media.ToXml());
}

View File

@@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly : AssemblyVersion("0.7.6.*")]
[assembly : AssemblyVersion("0.8.0.*")]

View File

@@ -930,3 +930,13 @@ BEGIN;
ALTER TABLE prims ADD COLUMN `KeyframeMotion` blob;
COMMIT;
:VERSION 49 #--------------------- Save attachment info
BEGIN;
ALTER TABLE prims ADD COLUMN AttachedPosX double default 0;
ALTER TABLE prims ADD COLUMN AttachedPosY double default 0;
ALTER TABLE prims ADD COLUMN AttachedPosZ double default 0;
ALTER TABLE primshapes ADD COLUMN LastAttachPoint int(4) not null default '0';
COMMIT;

View File

@@ -239,6 +239,11 @@ namespace OpenSim.Data.Null
return Get((int)RegionFlags.DefaultRegion, scopeID);
}
public List<RegionData> GetDefaultHypergridRegions(UUID scopeID)
{
return Get((int)RegionFlags.DefaultHGRegion, scopeID);
}
public List<RegionData> GetFallbackRegions(UUID scopeID, int x, int y)
{
List<RegionData> regions = Get((int)RegionFlags.FallbackRegion, scopeID);

View File

@@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly : AssemblyVersion("0.7.6.*")]
[assembly : AssemblyVersion("0.8.0.*")]

View File

@@ -0,0 +1,295 @@
/*
* 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.Data;
using System.Reflection;
using System.Collections.Generic;
using OpenMetaverse;
using log4net;
using OpenSim.Framework;
using Npgsql;
using NpgsqlTypes;
namespace OpenSim.Data.PGSQL
{
/// <summary>
/// A PGSQL Interface for the Asset server
/// </summary>
public class PGSQLAssetData : AssetDataBase
{
private const string _migrationStore = "AssetStore";
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private long m_ticksToEpoch;
/// <summary>
/// Database manager
/// </summary>
private PGSQLManager m_database;
private string m_connectionString;
protected virtual Assembly Assembly
{
get { return GetType().Assembly; }
}
#region IPlugin Members
override public void Dispose() { }
/// <summary>
/// <para>Initialises asset interface</para>
/// </summary>
// [Obsolete("Cannot be default-initialized!")]
override public void Initialise()
{
m_log.Info("[PGSQLAssetData]: " + Name + " cannot be default-initialized!");
throw new PluginNotInitialisedException(Name);
}
/// <summary>
/// Initialises asset interface
/// </summary>
/// <para>
/// a string instead of file, if someone writes the support
/// </para>
/// <param name="connectionString">connect string</param>
override public void Initialise(string connectionString)
{
m_ticksToEpoch = new System.DateTime(1970, 1, 1).Ticks;
m_database = new PGSQLManager(connectionString);
m_connectionString = connectionString;
//New migration to check for DB changes
m_database.CheckMigration(_migrationStore);
}
/// <summary>
/// Database provider version.
/// </summary>
override public string Version
{
get { return m_database.getVersion(); }
}
/// <summary>
/// The name of this DB provider.
/// </summary>
override public string Name
{
get { return "PGSQL Asset storage engine"; }
}
#endregion
#region IAssetDataPlugin Members
/// <summary>
/// Fetch Asset from m_database
/// </summary>
/// <param name="assetID">the asset UUID</param>
/// <returns></returns>
override public AssetBase GetAsset(UUID assetID)
{
string sql = "SELECT * FROM assets WHERE id = :id";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(m_database.CreateParameter("id", assetID));
conn.Open();
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
AssetBase asset = new AssetBase(
DBGuid.FromDB(reader["id"]),
(string)reader["name"],
Convert.ToSByte(reader["assetType"]),
reader["creatorid"].ToString()
);
// Region Main
asset.Description = (string)reader["description"];
asset.Local = Convert.ToBoolean(reader["local"]);
asset.Temporary = Convert.ToBoolean(reader["temporary"]);
asset.Flags = (AssetFlags)(Convert.ToInt32(reader["asset_flags"]));
asset.Data = (byte[])reader["data"];
return asset;
}
return null; // throw new Exception("No rows to return");
}
}
}
/// <summary>
/// Create asset in m_database
/// </summary>
/// <param name="asset">the asset</param>
override public void StoreAsset(AssetBase asset)
{
string sql =
@"UPDATE assets set name = :name, description = :description, " + "\"assetType\" " + @" = :assetType,
local = :local, temporary = :temporary, creatorid = :creatorid, data = :data
WHERE id=:id;
INSERT INTO assets
(id, name, description, " + "\"assetType\" " + @", local,
temporary, create_time, access_time, creatorid, asset_flags, data)
Select :id, :name, :description, :assetType, :local,
:temporary, :create_time, :access_time, :creatorid, :asset_flags, :data
Where not EXISTS(SELECT * FROM assets WHERE id=:id)
";
string assetName = asset.Name;
if (asset.Name.Length > 64)
{
assetName = asset.Name.Substring(0, 64);
m_log.WarnFormat(
"[ASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add",
asset.Name, asset.ID, asset.Name.Length, assetName.Length);
}
string assetDescription = asset.Description;
if (asset.Description.Length > 64)
{
assetDescription = asset.Description.Substring(0, 64);
m_log.WarnFormat(
"[ASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add",
asset.Description, asset.ID, asset.Description.Length, assetDescription.Length);
}
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand command = new NpgsqlCommand(sql, conn))
{
int now = (int)((System.DateTime.Now.Ticks - m_ticksToEpoch) / 10000000);
command.Parameters.Add(m_database.CreateParameter("id", asset.FullID));
command.Parameters.Add(m_database.CreateParameter("name", assetName));
command.Parameters.Add(m_database.CreateParameter("description", assetDescription));
command.Parameters.Add(m_database.CreateParameter("assetType", asset.Type));
command.Parameters.Add(m_database.CreateParameter("local", asset.Local));
command.Parameters.Add(m_database.CreateParameter("temporary", asset.Temporary));
command.Parameters.Add(m_database.CreateParameter("access_time", now));
command.Parameters.Add(m_database.CreateParameter("create_time", now));
command.Parameters.Add(m_database.CreateParameter("asset_flags", (int)asset.Flags));
command.Parameters.Add(m_database.CreateParameter("creatorid", asset.Metadata.CreatorID));
command.Parameters.Add(m_database.CreateParameter("data", asset.Data));
conn.Open();
try
{
command.ExecuteNonQuery();
}
catch(Exception e)
{
m_log.Error("[ASSET DB]: Error storing item :" + e.Message + " sql "+sql);
}
}
}
// Commented out since currently unused - this probably should be called in GetAsset()
// private void UpdateAccessTime(AssetBase asset)
// {
// using (AutoClosingSqlCommand cmd = m_database.Query("UPDATE assets SET access_time = :access_time WHERE id=:id"))
// {
// int now = (int)((System.DateTime.Now.Ticks - m_ticksToEpoch) / 10000000);
// cmd.Parameters.AddWithValue(":id", asset.FullID.ToString());
// cmd.Parameters.AddWithValue(":access_time", now);
// try
// {
// cmd.ExecuteNonQuery();
// }
// catch (Exception e)
// {
// m_log.Error(e.ToString());
// }
// }
// }
/// <summary>
/// Check if asset exist in m_database
/// </summary>
/// <param name="uuid"></param>
/// <returns>true if exist.</returns>
override public bool ExistsAsset(UUID uuid)
{
if (GetAsset(uuid) != null)
{
return true;
}
return false;
}
/// <summary>
/// Returns a list of AssetMetadata objects. The list is a subset of
/// the entire data set offset by <paramref name="start" /> containing
/// <paramref name="count" /> elements.
/// </summary>
/// <param name="start">The number of results to discard from the total data set.</param>
/// <param name="count">The number of rows the returned list should contain.</param>
/// <returns>A list of AssetMetadata objects.</returns>
public override List<AssetMetadata> FetchAssetMetadataSet(int start, int count)
{
List<AssetMetadata> retList = new List<AssetMetadata>(count);
string sql = @" SELECT id, name, description, " + "\"assetType\"" + @", temporary, creatorid
FROM assets
order by id
limit :stop
offset :start;";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(m_database.CreateParameter("start", start));
cmd.Parameters.Add(m_database.CreateParameter("stop", start + count - 1));
conn.Open();
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
AssetMetadata metadata = new AssetMetadata();
metadata.FullID = DBGuid.FromDB(reader["id"]);
metadata.Name = (string)reader["name"];
metadata.Description = (string)reader["description"];
metadata.Type = Convert.ToSByte(reader["assetType"]);
metadata.Temporary = Convert.ToBoolean(reader["temporary"]);
metadata.CreatorID = (string)reader["creatorid"];
retList.Add(metadata);
}
}
}
return retList;
}
public override bool Delete(string id)
{
return false;
}
#endregion
}
}

View File

@@ -0,0 +1,254 @@
/*
* 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 OpenMetaverse;
using OpenSim.Framework;
using System.Reflection;
using System.Text;
using System.Data;
using Npgsql;
using NpgsqlTypes;
namespace OpenSim.Data.PGSQL
{
public class PGSQLAuthenticationData : IAuthenticationData
{
private string m_Realm;
private List<string> m_ColumnNames = null;
private int m_LastExpire = 0;
private string m_ConnectionString;
private PGSQLManager m_database;
protected virtual Assembly Assembly
{
get { return GetType().Assembly; }
}
public PGSQLAuthenticationData(string connectionString, string realm)
{
m_Realm = realm;
m_ConnectionString = connectionString;
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
{
conn.Open();
Migration m = new Migration(conn, GetType().Assembly, "AuthStore");
m_database = new PGSQLManager(m_ConnectionString);
m.Update();
}
}
public AuthenticationData Get(UUID principalID)
{
AuthenticationData ret = new AuthenticationData();
ret.Data = new Dictionary<string, object>();
string sql = string.Format("select * from {0} where uuid = :principalID", m_Realm);
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(m_database.CreateParameter("principalID", principalID));
conn.Open();
using (NpgsqlDataReader result = cmd.ExecuteReader())
{
if (result.Read())
{
ret.PrincipalID = principalID;
if (m_ColumnNames == null)
{
m_ColumnNames = new List<string>();
DataTable schemaTable = result.GetSchemaTable();
foreach (DataRow row in schemaTable.Rows)
m_ColumnNames.Add(row["ColumnName"].ToString());
}
foreach (string s in m_ColumnNames)
{
if (s == "UUID"||s == "uuid")
continue;
ret.Data[s] = result[s].ToString();
}
return ret;
}
}
}
return null;
}
public bool Store(AuthenticationData data)
{
if (data.Data.ContainsKey("UUID"))
data.Data.Remove("UUID");
if (data.Data.ContainsKey("uuid"))
data.Data.Remove("uuid");
/*
Dictionary<string, object> oAuth = new Dictionary<string, object>();
foreach (KeyValuePair<string, object> oDado in data.Data)
{
if (oDado.Key != oDado.Key.ToLower())
{
oAuth.Add(oDado.Key.ToLower(), oDado.Value);
}
}
foreach (KeyValuePair<string, object> oDado in data.Data)
{
if (!oAuth.ContainsKey(oDado.Key.ToLower())) {
oAuth.Add(oDado.Key.ToLower(), oDado.Value);
}
}
*/
string[] fields = new List<string>(data.Data.Keys).ToArray();
StringBuilder updateBuilder = new StringBuilder();
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
updateBuilder.AppendFormat("update {0} set ", m_Realm);
bool first = true;
foreach (string field in fields)
{
if (!first)
updateBuilder.Append(", ");
updateBuilder.AppendFormat("\"{0}\" = :{0}",field);
first = false;
cmd.Parameters.Add(m_database.CreateParameter("" + field, data.Data[field]));
}
updateBuilder.Append(" where uuid = :principalID");
cmd.CommandText = updateBuilder.ToString();
cmd.Connection = conn;
cmd.Parameters.Add(m_database.CreateParameter("principalID", data.PrincipalID));
conn.Open();
if (cmd.ExecuteNonQuery() < 1)
{
StringBuilder insertBuilder = new StringBuilder();
insertBuilder.AppendFormat("insert into {0} (uuid, \"", m_Realm);
insertBuilder.Append(String.Join("\", \"", fields));
insertBuilder.Append("\") values (:principalID, :");
insertBuilder.Append(String.Join(", :", fields));
insertBuilder.Append(")");
cmd.CommandText = insertBuilder.ToString();
if (cmd.ExecuteNonQuery() < 1)
{
return false;
}
}
}
return true;
}
public bool SetDataItem(UUID principalID, string item, string value)
{
string sql = string.Format("update {0} set {1} = :{1} where uuid = :UUID", m_Realm, item);
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(m_database.CreateParameter("" + item, value));
conn.Open();
if (cmd.ExecuteNonQuery() > 0)
return true;
}
return false;
}
public bool SetToken(UUID principalID, string token, int lifetime)
{
if (System.Environment.TickCount - m_LastExpire > 30000)
DoExpire();
string sql = "insert into tokens (uuid, token, validity) values (:principalID, :token, :lifetime)";
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(m_database.CreateParameter("principalID", principalID));
cmd.Parameters.Add(m_database.CreateParameter("token", token));
cmd.Parameters.Add(m_database.CreateParameter("lifetime", DateTime.Now.AddMinutes(lifetime)));
conn.Open();
if (cmd.ExecuteNonQuery() > 0)
{
return true;
}
}
return false;
}
public bool CheckToken(UUID principalID, string token, int lifetime)
{
if (System.Environment.TickCount - m_LastExpire > 30000)
DoExpire();
DateTime validDate = DateTime.Now.AddMinutes(lifetime);
string sql = "update tokens set validity = :validDate where uuid = :principalID and token = :token and validity > (CURRENT_DATE + CURRENT_TIME)";
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(m_database.CreateParameter("principalID", principalID));
cmd.Parameters.Add(m_database.CreateParameter("token", token));
cmd.Parameters.Add(m_database.CreateParameter("validDate", validDate));
conn.Open();
if (cmd.ExecuteNonQuery() > 0)
{
return true;
}
}
return false;
}
private void DoExpire()
{
DateTime currentDateTime = DateTime.Now;
string sql = "delete from tokens where validity < :currentDateTime";
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
conn.Open();
cmd.Parameters.Add(m_database.CreateParameter("currentDateTime", currentDateTime));
cmd.ExecuteNonQuery();
}
m_LastExpire = System.Environment.TickCount;
}
}
}

View File

@@ -0,0 +1,72 @@
/*
* 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 log4net;
using OpenMetaverse;
using OpenSim.Framework;
using Npgsql;
using NpgsqlTypes;
namespace OpenSim.Data.PGSQL
{
/// <summary>
/// A PGSQL Interface for Avatar Storage
/// </summary>
public class PGSQLAvatarData : PGSQLGenericTableHandler<AvatarBaseData>,
IAvatarData
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public PGSQLAvatarData(string connectionString, string realm) :
base(connectionString, realm, "Avatar")
{
}
public bool Delete(UUID principalID, string name)
{
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
cmd.CommandText = String.Format("DELETE FROM {0} where \"PrincipalID\" = :PrincipalID and \"Name\" = :Name", m_Realm);
cmd.Parameters.Add(m_database.CreateParameter("PrincipalID", principalID));
cmd.Parameters.Add(m_database.CreateParameter("Name", name));
cmd.Connection = conn;
conn.Open();
if (cmd.ExecuteNonQuery() > 0)
return true;
return false;
}
}
}
}

View File

@@ -0,0 +1,602 @@
/*
* 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 OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using System.Data;
using Npgsql;
using NpgsqlTypes;
namespace OpenSim.Data.PGSQL
{
public class PGSQLEstateStore : IEstateDataStore
{
private const string _migrationStore = "EstateStore";
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private PGSQLManager _Database;
private string m_connectionString;
private FieldInfo[] _Fields;
private Dictionary<string, FieldInfo> _FieldMap = new Dictionary<string, FieldInfo>();
#region Public methods
public PGSQLEstateStore()
{
}
public PGSQLEstateStore(string connectionString)
{
Initialise(connectionString);
}
protected virtual Assembly Assembly
{
get { return GetType().Assembly; }
}
/// <summary>
/// Initialises the estatedata class.
/// </summary>
/// <param name="connectionString">connectionString.</param>
public void Initialise(string connectionString)
{
if (!string.IsNullOrEmpty(connectionString))
{
m_connectionString = connectionString;
_Database = new PGSQLManager(connectionString);
}
//Migration settings
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
{
conn.Open();
Migration m = new Migration(conn, GetType().Assembly, "EstateStore");
m.Update();
}
//Interesting way to get parameters! Maybe implement that also with other types
Type t = typeof(EstateSettings);
_Fields = t.GetFields(BindingFlags.NonPublic |
BindingFlags.Instance |
BindingFlags.DeclaredOnly);
foreach (FieldInfo f in _Fields)
{
if (f.Name.Substring(0, 2) == "m_")
_FieldMap[f.Name.Substring(2)] = f;
}
}
/// <summary>
/// Loads the estate settings.
/// </summary>
/// <param name="regionID">region ID.</param>
/// <returns></returns>
public EstateSettings LoadEstateSettings(UUID regionID, bool create)
{
EstateSettings es = new EstateSettings();
string sql = "select estate_settings.\"" + String.Join("\",estate_settings.\"", FieldList) +
"\" from estate_map left join estate_settings on estate_map.\"EstateID\" = estate_settings.\"EstateID\" " +
" where estate_settings.\"EstateID\" is not null and \"RegionID\" = :RegionID";
bool insertEstate = false;
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(_Database.CreateParameter("RegionID", regionID));
conn.Open();
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
foreach (string name in FieldList)
{
FieldInfo f = _FieldMap[name];
object v = reader[name];
if (f.FieldType == typeof(bool))
{
f.SetValue(es, v);
}
else if (f.FieldType == typeof(UUID))
{
UUID estUUID = UUID.Zero;
UUID.TryParse(v.ToString(), out estUUID);
f.SetValue(es, estUUID);
}
else if (f.FieldType == typeof(string))
{
f.SetValue(es, v.ToString());
}
else if (f.FieldType == typeof(UInt32))
{
f.SetValue(es, Convert.ToUInt32(v));
}
else if (f.FieldType == typeof(Single))
{
f.SetValue(es, Convert.ToSingle(v));
}
else
f.SetValue(es, v);
}
}
else
{
insertEstate = true;
}
}
}
if (insertEstate && create)
{
DoCreate(es);
LinkRegion(regionID, (int)es.EstateID);
}
LoadBanList(es);
es.EstateManagers = LoadUUIDList(es.EstateID, "estate_managers");
es.EstateAccess = LoadUUIDList(es.EstateID, "estate_users");
es.EstateGroups = LoadUUIDList(es.EstateID, "estate_groups");
//Set event
es.OnSave += StoreEstateSettings;
return es;
}
public EstateSettings CreateNewEstate()
{
EstateSettings es = new EstateSettings();
es.OnSave += StoreEstateSettings;
DoCreate(es);
LoadBanList(es);
es.EstateManagers = LoadUUIDList(es.EstateID, "estate_managers");
es.EstateAccess = LoadUUIDList(es.EstateID, "estate_users");
es.EstateGroups = LoadUUIDList(es.EstateID, "estate_groups");
return es;
}
private void DoCreate(EstateSettings es)
{
List<string> names = new List<string>(FieldList);
names.Remove("EstateID");
string sql = string.Format("insert into estate_settings (\"{0}\") values ( :{1} )", String.Join("\",\"", names.ToArray()), String.Join(", :", names.ToArray()));
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand insertCommand = new NpgsqlCommand(sql, conn))
{
insertCommand.CommandText = sql;
foreach (string name in names)
{
insertCommand.Parameters.Add(_Database.CreateParameter("" + name, _FieldMap[name].GetValue(es)));
}
//NpgsqlParameter idParameter = new NpgsqlParameter("ID", SqlDbType.Int);
//idParameter.Direction = ParameterDirection.Output;
//insertCommand.Parameters.Add(idParameter);
conn.Open();
es.EstateID = 100;
if (insertCommand.ExecuteNonQuery() > 0)
{
insertCommand.CommandText = "Select cast(lastval() as int) as ID ;";
using (NpgsqlDataReader result = insertCommand.ExecuteReader())
{
if (result.Read())
{
es.EstateID = (uint)result.GetInt32(0);
}
}
}
}
//TODO check if this is needed??
es.Save();
}
/// <summary>
/// Stores the estate settings.
/// </summary>
/// <param name="es">estate settings</param>
public void StoreEstateSettings(EstateSettings es)
{
List<string> names = new List<string>(FieldList);
names.Remove("EstateID");
string sql = string.Format("UPDATE estate_settings SET ");
foreach (string name in names)
{
sql += "\"" + name + "\" = :" + name + ", ";
}
sql = sql.Remove(sql.LastIndexOf(","));
sql += " WHERE \"EstateID\" = :EstateID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
foreach (string name in names)
{
cmd.Parameters.Add(_Database.CreateParameter("" + name, _FieldMap[name].GetValue(es)));
}
cmd.Parameters.Add(_Database.CreateParameter("EstateID", es.EstateID));
conn.Open();
cmd.ExecuteNonQuery();
}
SaveBanList(es);
SaveUUIDList(es.EstateID, "estate_managers", es.EstateManagers);
SaveUUIDList(es.EstateID, "estate_users", es.EstateAccess);
SaveUUIDList(es.EstateID, "estate_groups", es.EstateGroups);
}
#endregion
#region Private methods
private string[] FieldList
{
get { return new List<string>(_FieldMap.Keys).ToArray(); }
}
private void LoadBanList(EstateSettings es)
{
es.ClearBans();
string sql = "select \"bannedUUID\" from estateban where \"EstateID\" = :EstateID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
NpgsqlParameter idParameter = new NpgsqlParameter("EstateID", DbType.Int32);
idParameter.Value = es.EstateID;
cmd.Parameters.Add(idParameter);
conn.Open();
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
EstateBan eb = new EstateBan();
eb.BannedUserID = new UUID((Guid)reader["bannedUUID"]); //uuid;
eb.BannedHostAddress = "0.0.0.0";
eb.BannedHostIPMask = "0.0.0.0";
es.AddBan(eb);
}
}
}
}
private UUID[] LoadUUIDList(uint estateID, string table)
{
List<UUID> uuids = new List<UUID>();
string sql = string.Format("select uuid from {0} where \"EstateID\" = :EstateID", table);
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(_Database.CreateParameter("EstateID", estateID));
conn.Open();
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
uuids.Add(new UUID((Guid)reader["uuid"])); //uuid);
}
}
}
return uuids.ToArray();
}
private void SaveBanList(EstateSettings es)
{
//Delete first
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
{
conn.Open();
using (NpgsqlCommand cmd = conn.CreateCommand())
{
cmd.CommandText = "delete from estateban where \"EstateID\" = :EstateID";
cmd.Parameters.AddWithValue("EstateID", (int)es.EstateID);
cmd.ExecuteNonQuery();
//Insert after
cmd.CommandText = "insert into estateban (\"EstateID\", \"bannedUUID\",\"bannedIp\", \"bannedIpHostMask\", \"bannedNameMask\") values ( :EstateID, :bannedUUID, '','','' )";
cmd.Parameters.AddWithValue("bannedUUID", Guid.Empty);
foreach (EstateBan b in es.EstateBans)
{
cmd.Parameters["bannedUUID"].Value = b.BannedUserID.Guid;
cmd.ExecuteNonQuery();
}
}
}
}
private void SaveUUIDList(uint estateID, string table, UUID[] data)
{
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
{
conn.Open();
using (NpgsqlCommand cmd = conn.CreateCommand())
{
cmd.Parameters.AddWithValue("EstateID", (int)estateID);
cmd.CommandText = string.Format("delete from {0} where \"EstateID\" = :EstateID", table);
cmd.ExecuteNonQuery();
cmd.CommandText = string.Format("insert into {0} (\"EstateID\", uuid) values ( :EstateID, :uuid )", table);
cmd.Parameters.AddWithValue("uuid", Guid.Empty);
foreach (UUID uuid in data)
{
cmd.Parameters["uuid"].Value = uuid.Guid; //.ToString(); //TODO check if this works
cmd.ExecuteNonQuery();
}
}
}
}
public EstateSettings LoadEstateSettings(int estateID)
{
EstateSettings es = new EstateSettings();
string sql = "select estate_settings.\"" + String.Join("\",estate_settings.\"", FieldList) + "\" from estate_settings where \"EstateID\" = :EstateID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
{
conn.Open();
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("EstateID", (int)estateID);
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
foreach (string name in FieldList)
{
FieldInfo f = _FieldMap[name];
object v = reader[name];
if (f.FieldType == typeof(bool))
{
f.SetValue(es, Convert.ToInt32(v) != 0);
}
else if (f.FieldType == typeof(UUID))
{
f.SetValue(es, new UUID((Guid)v)); // uuid);
}
else if (f.FieldType == typeof(string))
{
f.SetValue(es, v.ToString());
}
else if (f.FieldType == typeof(UInt32))
{
f.SetValue(es, Convert.ToUInt32(v));
}
else if (f.FieldType == typeof(Single))
{
f.SetValue(es, Convert.ToSingle(v));
}
else
f.SetValue(es, v);
}
}
}
}
}
LoadBanList(es);
es.EstateManagers = LoadUUIDList(es.EstateID, "estate_managers");
es.EstateAccess = LoadUUIDList(es.EstateID, "estate_users");
es.EstateGroups = LoadUUIDList(es.EstateID, "estate_groups");
//Set event
es.OnSave += StoreEstateSettings;
return es;
}
public List<EstateSettings> LoadEstateSettingsAll()
{
List<EstateSettings> allEstateSettings = new List<EstateSettings>();
List<int> allEstateIds = GetEstatesAll();
foreach (int estateId in allEstateIds)
allEstateSettings.Add(LoadEstateSettings(estateId));
return allEstateSettings;
}
public List<int> GetEstates(string search)
{
List<int> result = new List<int>();
string sql = "select \"EstateID\" from estate_settings where lower(\"EstateName\") = lower(:EstateName)";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
{
conn.Open();
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("EstateName", search);
using (IDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
result.Add(Convert.ToInt32(reader["EstateID"]));
}
reader.Close();
}
}
}
return result;
}
public List<int> GetEstatesAll()
{
List<int> result = new List<int>();
string sql = "select \"EstateID\" from estate_settings";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
{
conn.Open();
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
using (IDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
result.Add(Convert.ToInt32(reader["EstateID"]));
}
reader.Close();
}
}
}
return result;
}
public List<int> GetEstatesByOwner(UUID ownerID)
{
List<int> result = new List<int>();
string sql = "select \"estateID\" from estate_settings where \"EstateOwner\" = :EstateOwner";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
{
conn.Open();
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("EstateOwner", ownerID);
using (IDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
result.Add(Convert.ToInt32(reader["EstateID"]));
}
reader.Close();
}
}
}
return result;
}
public bool LinkRegion(UUID regionID, int estateID)
{
string deleteSQL = "delete from estate_map where \"RegionID\" = :RegionID";
string insertSQL = "insert into estate_map values (:RegionID, :EstateID)";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
{
conn.Open();
NpgsqlTransaction transaction = conn.BeginTransaction();
try
{
using (NpgsqlCommand cmd = new NpgsqlCommand(deleteSQL, conn))
{
cmd.Transaction = transaction;
cmd.Parameters.AddWithValue("RegionID", regionID.Guid);
cmd.ExecuteNonQuery();
}
using (NpgsqlCommand cmd = new NpgsqlCommand(insertSQL, conn))
{
cmd.Transaction = transaction;
cmd.Parameters.AddWithValue("RegionID", regionID.Guid);
cmd.Parameters.AddWithValue("EstateID", estateID);
int ret = cmd.ExecuteNonQuery();
if (ret != 0)
transaction.Commit();
else
transaction.Rollback();
return (ret != 0);
}
}
catch (Exception ex)
{
m_log.Error("[REGION DB]: LinkRegion failed: " + ex.Message);
transaction.Rollback();
}
}
return false;
}
public List<UUID> GetRegions(int estateID)
{
List<UUID> result = new List<UUID>();
string sql = "select \"RegionID\" from estate_map where \"EstateID\" = :EstateID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
{
conn.Open();
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.AddWithValue("EstateID", estateID);
using (IDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
result.Add(DBGuid.FromDB(reader["RegionID"]));
}
reader.Close();
}
}
}
return result;
}
public bool DeleteEstate(int estateID)
{
// TODO: Implementation!
return false;
}
#endregion
}
}

View File

@@ -0,0 +1,111 @@
/*
* 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.Data;
using System.Reflection;
using OpenMetaverse;
using OpenSim.Framework;
using Npgsql;
namespace OpenSim.Data.PGSQL
{
/// <summary>
/// A database interface class to a user profile storage system
/// </summary>
public class PGSqlFramework
{
private static readonly log4net.ILog m_log =
log4net.LogManager.GetLogger(
System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
protected string m_connectionString;
protected object m_dbLock = new object();
protected PGSqlFramework(string connectionString)
{
m_connectionString = connectionString;
InitializeMonoSecurity();
}
public void InitializeMonoSecurity()
{
if (!Util.IsPlatformMono)
{
if (AppDomain.CurrentDomain.GetData("MonoSecurityPostgresAdded") == null)
{
AppDomain.CurrentDomain.SetData("MonoSecurityPostgresAdded", "true");
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(ResolveEventHandlerMonoSec);
}
}
}
private System.Reflection.Assembly ResolveEventHandlerMonoSec(object sender, ResolveEventArgs args)
{
Assembly MyAssembly = null;
if (args.Name.Substring(0, args.Name.IndexOf(",")) == "Mono.Security")
{
MyAssembly = Assembly.LoadFrom("lib/NET/Mono.Security.dll");
}
//Return the loaded assembly.
return MyAssembly;
}
//////////////////////////////////////////////////////////////
//
// All non queries are funneled through one connection
// to increase performance a little
//
protected int ExecuteNonQuery(NpgsqlCommand cmd)
{
lock (m_dbLock)
{
using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString))
{
dbcon.Open();
cmd.Connection = dbcon;
try
{
return cmd.ExecuteNonQuery();
}
catch (Exception e)
{
m_log.Error(e.Message, e);
return 0;
}
}
}
}
}
}

View File

@@ -0,0 +1,116 @@
/*
* 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.Data;
using OpenMetaverse;
using OpenSim.Framework;
using System.Reflection;
using System.Text;
using Npgsql;
namespace OpenSim.Data.PGSQL
{
public class PGSQLFriendsData : PGSQLGenericTableHandler<FriendsData>, IFriendsData
{
public PGSQLFriendsData(string connectionString, string realm)
: base(connectionString, realm, "FriendsStore")
{
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
{
conn.Open();
Migration m = new Migration(conn, GetType().Assembly, "FriendsStore");
m.Update();
}
}
public bool Delete(string principalID, string friend)
{
UUID princUUID = UUID.Zero;
bool ret = UUID.TryParse(principalID, out princUUID);
if (ret)
return Delete(princUUID, friend);
else
return false;
}
public bool Delete(UUID principalID, string friend)
{
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
cmd.CommandText = String.Format("delete from {0} where \"PrincipalID\" = :PrincipalID and \"Friend\" = :Friend", m_Realm);
cmd.Parameters.Add(m_database.CreateParameter("PrincipalID", principalID.ToString()));
cmd.Parameters.Add(m_database.CreateParameter("Friend", friend));
cmd.Connection = conn;
conn.Open();
cmd.ExecuteNonQuery();
return true;
}
}
public FriendsData[] GetFriends(string principalID)
{
UUID princUUID = UUID.Zero;
bool ret = UUID.TryParse(principalID, out princUUID);
if (ret)
return GetFriends(princUUID);
else
return new FriendsData[0];
}
public FriendsData[] GetFriends(UUID principalID)
{
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
cmd.CommandText = String.Format("select a.*,case when b.\"Flags\" is null then '-1' else b.\"Flags\" end as \"TheirFlags\" from {0} as a " +
" left join {0} as b on a.\"PrincipalID\" = b.\"Friend\" and a.\"Friend\" = b.\"PrincipalID\" " +
" where a.\"PrincipalID\" = :PrincipalID", m_Realm);
cmd.Parameters.Add(m_database.CreateParameter("PrincipalID", principalID.ToString()));
cmd.Connection = conn;
conn.Open();
return DoQuery(cmd);
}
}
public FriendsData[] GetFriends(Guid principalID)
{
return GetFriends(principalID);
}
}
}

View File

@@ -0,0 +1,519 @@
/*
* 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.Data;
using System.Reflection;
using log4net;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using System.Text;
using Npgsql;
namespace OpenSim.Data.PGSQL
{
public class PGSQLGenericTableHandler<T> : PGSqlFramework where T : class, new()
{
private static readonly ILog m_log =
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
protected string m_ConnectionString;
protected PGSQLManager m_database; //used for parameter type translation
protected Dictionary<string, FieldInfo> m_Fields =
new Dictionary<string, FieldInfo>();
protected Dictionary<string, string> m_FieldTypes = new Dictionary<string, string>();
protected List<string> m_ColumnNames = null;
protected string m_Realm;
protected FieldInfo m_DataField = null;
protected virtual Assembly Assembly
{
get { return GetType().Assembly; }
}
public PGSQLGenericTableHandler(string connectionString,
string realm, string storeName)
: base(connectionString)
{
m_Realm = realm;
m_ConnectionString = connectionString;
if (storeName != String.Empty)
{
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
{
conn.Open();
Migration m = new Migration(conn, GetType().Assembly, storeName);
m.Update();
}
}
m_database = new PGSQLManager(m_ConnectionString);
Type t = typeof(T);
FieldInfo[] fields = t.GetFields(BindingFlags.Public |
BindingFlags.Instance |
BindingFlags.DeclaredOnly);
LoadFieldTypes();
if (fields.Length == 0)
return;
foreach (FieldInfo f in fields)
{
if (f.Name != "Data")
m_Fields[f.Name] = f;
else
m_DataField = f;
}
}
private void LoadFieldTypes()
{
m_FieldTypes = new Dictionary<string, string>();
string query = string.Format(@"select column_name,data_type
from INFORMATION_SCHEMA.COLUMNS
where table_name = lower('{0}');
", m_Realm);
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(query, conn))
{
conn.Open();
using (NpgsqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
// query produces 0 to many rows of single column, so always add the first item in each row
m_FieldTypes.Add((string)rdr[0], (string)rdr[1]);
}
}
}
}
private void CheckColumnNames(NpgsqlDataReader reader)
{
if (m_ColumnNames != null)
return;
m_ColumnNames = new List<string>();
DataTable schemaTable = reader.GetSchemaTable();
foreach (DataRow row in schemaTable.Rows)
{
if (row["ColumnName"] != null &&
(!m_Fields.ContainsKey(row["ColumnName"].ToString())))
m_ColumnNames.Add(row["ColumnName"].ToString());
}
}
// TODO GET CONSTRAINTS FROM POSTGRESQL
private List<string> GetConstraints()
{
List<string> constraints = new List<string>();
string query = string.Format(@"SELECT kcu.column_name
FROM information_schema.table_constraints tc
LEFT JOIN information_schema.key_column_usage kcu
ON tc.constraint_catalog = kcu.constraint_catalog
AND tc.constraint_schema = kcu.constraint_schema
AND tc.constraint_name = kcu.constraint_name
LEFT JOIN information_schema.referential_constraints rc
ON tc.constraint_catalog = rc.constraint_catalog
AND tc.constraint_schema = rc.constraint_schema
AND tc.constraint_name = rc.constraint_name
LEFT JOIN information_schema.constraint_column_usage ccu
ON rc.unique_constraint_catalog = ccu.constraint_catalog
AND rc.unique_constraint_schema = ccu.constraint_schema
AND rc.unique_constraint_name = ccu.constraint_name
where tc.table_name = lower('{0}')
and lower(tc.constraint_type) in ('primary key')
and kcu.column_name is not null
;", m_Realm);
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(query, conn))
{
conn.Open();
using (NpgsqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
// query produces 0 to many rows of single column, so always add the first item in each row
constraints.Add((string)rdr[0]);
}
}
return constraints;
}
}
public virtual T[] Get(string field, string key)
{
return Get(new string[] { field }, new string[] { key });
}
public virtual T[] Get(string[] fields, string[] keys)
{
if (fields.Length != keys.Length)
return new T[0];
List<string> terms = new List<string>();
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
for (int i = 0; i < fields.Length; i++)
{
if ( m_FieldTypes.ContainsKey(fields[i]) )
cmd.Parameters.Add(m_database.CreateParameter(fields[i], keys[i], m_FieldTypes[fields[i]]));
else
cmd.Parameters.Add(m_database.CreateParameter(fields[i], keys[i]));
terms.Add(" \"" + fields[i] + "\" = :" + fields[i]);
}
string where = String.Join(" AND ", terms.ToArray());
string query = String.Format("SELECT * FROM {0} WHERE {1}",
m_Realm, where);
cmd.Connection = conn;
cmd.CommandText = query;
conn.Open();
return DoQuery(cmd);
}
}
protected T[] DoQuery(NpgsqlCommand cmd)
{
List<T> result = new List<T>();
if (cmd.Connection == null)
{
cmd.Connection = new NpgsqlConnection(m_connectionString);
}
if (cmd.Connection.State == ConnectionState.Closed)
{
cmd.Connection.Open();
}
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
if (reader == null)
return new T[0];
CheckColumnNames(reader);
while (reader.Read())
{
T row = new T();
foreach (string name in m_Fields.Keys)
{
if (m_Fields[name].GetValue(row) is bool)
{
int v = Convert.ToInt32(reader[name]);
m_Fields[name].SetValue(row, v != 0 ? true : false);
}
else if (m_Fields[name].GetValue(row) is UUID)
{
UUID uuid = UUID.Zero;
UUID.TryParse(reader[name].ToString(), out uuid);
m_Fields[name].SetValue(row, uuid);
}
else if (m_Fields[name].GetValue(row) is int)
{
int v = Convert.ToInt32(reader[name]);
m_Fields[name].SetValue(row, v);
}
else
{
m_Fields[name].SetValue(row, reader[name]);
}
}
if (m_DataField != null)
{
Dictionary<string, string> data =
new Dictionary<string, string>();
foreach (string col in m_ColumnNames)
{
data[col] = reader[col].ToString();
if (data[col] == null)
data[col] = String.Empty;
}
m_DataField.SetValue(row, data);
}
result.Add(row);
}
return result.ToArray();
}
}
public virtual T[] Get(string where)
{
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
string query = String.Format("SELECT * FROM {0} WHERE {1}",
m_Realm, where);
cmd.Connection = conn;
cmd.CommandText = query;
//m_log.WarnFormat("[PGSQLGenericTable]: SELECT {0} WHERE {1}", m_Realm, where);
conn.Open();
return DoQuery(cmd);
}
}
public virtual bool Store(T row)
{
List<string> constraintFields = GetConstraints();
List<KeyValuePair<string, string>> constraints = new List<KeyValuePair<string, string>>();
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
StringBuilder query = new StringBuilder();
List<String> names = new List<String>();
List<String> values = new List<String>();
foreach (FieldInfo fi in m_Fields.Values)
{
names.Add(fi.Name);
values.Add(":" + fi.Name);
// Temporarily return more information about what field is unexpectedly null for
// http://opensimulator.org/mantis/view.php?id=5403. This might be due to a bug in the
// InventoryTransferModule or we may be required to substitute a DBNull here.
if (fi.GetValue(row) == null)
throw new NullReferenceException(
string.Format(
"[PGSQL GENERIC TABLE HANDLER]: Trying to store field {0} for {1} which is unexpectedly null",
fi.Name, row));
if (constraintFields.Count > 0 && constraintFields.Contains(fi.Name))
{
constraints.Add(new KeyValuePair<string, string>(fi.Name, fi.GetValue(row).ToString() ));
}
if (m_FieldTypes.ContainsKey(fi.Name))
cmd.Parameters.Add(m_database.CreateParameter(fi.Name, fi.GetValue(row), m_FieldTypes[fi.Name]));
else
cmd.Parameters.Add(m_database.CreateParameter(fi.Name, fi.GetValue(row)));
}
if (m_DataField != null)
{
Dictionary<string, string> data =
(Dictionary<string, string>)m_DataField.GetValue(row);
foreach (KeyValuePair<string, string> kvp in data)
{
if (constraintFields.Count > 0 && constraintFields.Contains(kvp.Key))
{
constraints.Add(new KeyValuePair<string, string>(kvp.Key, kvp.Key));
}
names.Add(kvp.Key);
values.Add(":" + kvp.Key);
if (m_FieldTypes.ContainsKey(kvp.Key))
cmd.Parameters.Add(m_database.CreateParameter("" + kvp.Key, kvp.Value, m_FieldTypes[kvp.Key]));
else
cmd.Parameters.Add(m_database.CreateParameter("" + kvp.Key, kvp.Value));
}
}
query.AppendFormat("UPDATE {0} SET ", m_Realm);
int i = 0;
for (i = 0; i < names.Count - 1; i++)
{
query.AppendFormat("\"{0}\" = {1}, ", names[i], values[i]);
}
query.AppendFormat("\"{0}\" = {1} ", names[i], values[i]);
if (constraints.Count > 0)
{
List<string> terms = new List<string>();
for (int j = 0; j < constraints.Count; j++)
{
terms.Add(String.Format(" \"{0}\" = :{0}", constraints[j].Key));
}
string where = String.Join(" AND ", terms.ToArray());
query.AppendFormat(" WHERE {0} ", where);
}
cmd.Connection = conn;
cmd.CommandText = query.ToString();
conn.Open();
if (cmd.ExecuteNonQuery() > 0)
{
//m_log.WarnFormat("[PGSQLGenericTable]: Updating {0}", m_Realm);
return true;
}
else
{
// assume record has not yet been inserted
query = new StringBuilder();
query.AppendFormat("INSERT INTO {0} (\"", m_Realm);
query.Append(String.Join("\",\"", names.ToArray()));
query.Append("\") values (" + String.Join(",", values.ToArray()) + ")");
cmd.Connection = conn;
cmd.CommandText = query.ToString();
// m_log.WarnFormat("[PGSQLGenericTable]: Inserting into {0} sql {1}", m_Realm, cmd.CommandText);
if (conn.State != ConnectionState.Open)
conn.Open();
if (cmd.ExecuteNonQuery() > 0)
return true;
}
return false;
}
}
public virtual bool Delete(string field, string key)
{
return Delete(new string[] { field }, new string[] { key });
}
public virtual bool Delete(string[] fields, string[] keys)
{
if (fields.Length != keys.Length)
return false;
List<string> terms = new List<string>();
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
for (int i = 0; i < fields.Length; i++)
{
if (m_FieldTypes.ContainsKey(fields[i]))
cmd.Parameters.Add(m_database.CreateParameter(fields[i], keys[i], m_FieldTypes[fields[i]]));
else
cmd.Parameters.Add(m_database.CreateParameter(fields[i], keys[i]));
terms.Add(" \"" + fields[i] + "\" = :" + fields[i]);
}
string where = String.Join(" AND ", terms.ToArray());
string query = String.Format("DELETE FROM {0} WHERE {1}", m_Realm, where);
cmd.Connection = conn;
cmd.CommandText = query;
conn.Open();
if (cmd.ExecuteNonQuery() > 0)
{
//m_log.Warn("[PGSQLGenericTable]: " + deleteCommand);
return true;
}
return false;
}
}
public long GetCount(string field, string key)
{
return GetCount(new string[] { field }, new string[] { key });
}
public long GetCount(string[] fields, string[] keys)
{
if (fields.Length != keys.Length)
return 0;
List<string> terms = new List<string>();
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
for (int i = 0; i < fields.Length; i++)
{
cmd.Parameters.AddWithValue(fields[i], keys[i]);
terms.Add("\"" + fields[i] + "\" = :" + fields[i]);
}
string where = String.Join(" and ", terms.ToArray());
string query = String.Format("select count(*) from {0} where {1}",
m_Realm, where);
cmd.CommandText = query;
Object result = DoQueryScalar(cmd);
return Convert.ToInt64(result);
}
}
public long GetCount(string where)
{
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
string query = String.Format("select count(*) from {0} where {1}",
m_Realm, where);
cmd.CommandText = query;
object result = DoQueryScalar(cmd);
return Convert.ToInt64(result);
}
}
public object DoQueryScalar(NpgsqlCommand cmd)
{
using (NpgsqlConnection dbcon = new NpgsqlConnection(m_ConnectionString))
{
dbcon.Open();
cmd.Connection = dbcon;
return cmd.ExecuteScalar();
}
}
}
}

View File

@@ -0,0 +1,68 @@
/*
* 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.Data;
using System.Reflection;
using System.Threading;
using log4net;
using OpenMetaverse;
using OpenSim.Framework;
namespace OpenSim.Data.PGSQL
{
/// <summary>
/// A PGSQL Interface for Avatar Storage
/// </summary>
public class PGSQLGridUserData : PGSQLGenericTableHandler<GridUserData>,
IGridUserData
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public PGSQLGridUserData(string connectionString, string realm) :
base(connectionString, realm, "GridUserStore")
{
}
public new GridUserData Get(string userID)
{
GridUserData[] ret = Get("UserID", userID);
if (ret.Length == 0)
return null;
return ret[0];
}
public GridUserData[] GetAll(string userID)
{
return base.Get(String.Format("\"UserID\" LIKE '{0}%'", userID));
}
}
}

View File

@@ -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.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using OpenSim.Framework;
using OpenMetaverse;
using Npgsql;
namespace OpenSim.Data.PGSQL
{
public class PGSQLGroupsData : IGroupsData
{
private PGSqlGroupsGroupsHandler m_Groups;
private PGSqlGroupsMembershipHandler m_Membership;
private PGSqlGroupsRolesHandler m_Roles;
private PGSqlGroupsRoleMembershipHandler m_RoleMembership;
private PGSqlGroupsInvitesHandler m_Invites;
private PGSqlGroupsNoticesHandler m_Notices;
private PGSqlGroupsPrincipalsHandler m_Principals;
public PGSQLGroupsData(string connectionString, string realm)
{
m_Groups = new PGSqlGroupsGroupsHandler(connectionString, realm + "_groups", realm + "_Store");
m_Membership = new PGSqlGroupsMembershipHandler(connectionString, realm + "_membership");
m_Roles = new PGSqlGroupsRolesHandler(connectionString, realm + "_roles");
m_RoleMembership = new PGSqlGroupsRoleMembershipHandler(connectionString, realm + "_rolemembership");
m_Invites = new PGSqlGroupsInvitesHandler(connectionString, realm + "_invites");
m_Notices = new PGSqlGroupsNoticesHandler(connectionString, realm + "_notices");
m_Principals = new PGSqlGroupsPrincipalsHandler(connectionString, realm + "_principals");
}
#region groups table
public bool StoreGroup(GroupData data)
{
return m_Groups.Store(data);
}
public GroupData RetrieveGroup(UUID groupID)
{
GroupData[] groups = m_Groups.Get("GroupID", groupID.ToString());
if (groups.Length > 0)
return groups[0];
return null;
}
public GroupData RetrieveGroup(string name)
{
GroupData[] groups = m_Groups.Get("Name", name);
if (groups.Length > 0)
return groups[0];
return null;
}
public GroupData[] RetrieveGroups(string pattern)
{
if (string.IsNullOrEmpty(pattern)) // True for where clause
pattern = " true ORDER BY lower(\"Name\") LIMIT 100";
else
pattern = string.Format(" lower(\"Name\") LIKE lower('%{0}%') ORDER BY lower(\"Name\") LIMIT 100", pattern);
return m_Groups.Get(pattern);
}
public bool DeleteGroup(UUID groupID)
{
return m_Groups.Delete("GroupID", groupID.ToString());
}
public int GroupsCount()
{
return (int)m_Groups.GetCount(" \"Location\" = \"\"");
}
#endregion
#region membership table
public MembershipData[] RetrieveMembers(UUID groupID)
{
return m_Membership.Get("GroupID", groupID.ToString());
}
public MembershipData RetrieveMember(UUID groupID, string pricipalID)
{
MembershipData[] m = m_Membership.Get(new string[] { "GroupID", "PrincipalID" },
new string[] { groupID.ToString(), pricipalID });
if (m != null && m.Length > 0)
return m[0];
return null;
}
public MembershipData[] RetrieveMemberships(string pricipalID)
{
return m_Membership.Get("PrincipalID", pricipalID.ToString());
}
public bool StoreMember(MembershipData data)
{
return m_Membership.Store(data);
}
public bool DeleteMember(UUID groupID, string pricipalID)
{
return m_Membership.Delete(new string[] { "GroupID", "PrincipalID" },
new string[] { groupID.ToString(), pricipalID });
}
public int MemberCount(UUID groupID)
{
return (int)m_Membership.GetCount("GroupID", groupID.ToString());
}
#endregion
#region roles table
public bool StoreRole(RoleData data)
{
return m_Roles.Store(data);
}
public RoleData RetrieveRole(UUID groupID, UUID roleID)
{
RoleData[] data = m_Roles.Get(new string[] { "GroupID", "RoleID" },
new string[] { groupID.ToString(), roleID.ToString() });
if (data != null && data.Length > 0)
return data[0];
return null;
}
public RoleData[] RetrieveRoles(UUID groupID)
{
//return m_Roles.RetrieveRoles(groupID);
return m_Roles.Get("GroupID", groupID.ToString());
}
public bool DeleteRole(UUID groupID, UUID roleID)
{
return m_Roles.Delete(new string[] { "GroupID", "RoleID" },
new string[] { groupID.ToString(), roleID.ToString() });
}
public int RoleCount(UUID groupID)
{
return (int)m_Roles.GetCount("GroupID", groupID.ToString());
}
#endregion
#region rolememberhip table
public RoleMembershipData[] RetrieveRolesMembers(UUID groupID)
{
RoleMembershipData[] data = m_RoleMembership.Get("GroupID", groupID.ToString());
return data;
}
public RoleMembershipData[] RetrieveRoleMembers(UUID groupID, UUID roleID)
{
RoleMembershipData[] data = m_RoleMembership.Get(new string[] { "GroupID", "RoleID" },
new string[] { groupID.ToString(), roleID.ToString() });
return data;
}
public RoleMembershipData[] RetrieveMemberRoles(UUID groupID, string principalID)
{
RoleMembershipData[] data = m_RoleMembership.Get(new string[] { "GroupID", "PrincipalID" },
new string[] { groupID.ToString(), principalID.ToString() });
return data;
}
public RoleMembershipData RetrieveRoleMember(UUID groupID, UUID roleID, string principalID)
{
RoleMembershipData[] data = m_RoleMembership.Get(new string[] { "GroupID", "RoleID", "PrincipalID" },
new string[] { groupID.ToString(), roleID.ToString(), principalID.ToString() });
if (data != null && data.Length > 0)
return data[0];
return null;
}
public int RoleMemberCount(UUID groupID, UUID roleID)
{
return (int)m_RoleMembership.GetCount(new string[] { "GroupID", "RoleID" },
new string[] { groupID.ToString(), roleID.ToString() });
}
public bool StoreRoleMember(RoleMembershipData data)
{
return m_RoleMembership.Store(data);
}
public bool DeleteRoleMember(RoleMembershipData data)
{
return m_RoleMembership.Delete(new string[] { "GroupID", "RoleID", "PrincipalID"},
new string[] { data.GroupID.ToString(), data.RoleID.ToString(), data.PrincipalID });
}
public bool DeleteMemberAllRoles(UUID groupID, string principalID)
{
return m_RoleMembership.Delete(new string[] { "GroupID", "PrincipalID" },
new string[] { groupID.ToString(), principalID });
}
#endregion
#region principals table
public bool StorePrincipal(PrincipalData data)
{
return m_Principals.Store(data);
}
public PrincipalData RetrievePrincipal(string principalID)
{
PrincipalData[] p = m_Principals.Get("PrincipalID", principalID);
if (p != null && p.Length > 0)
return p[0];
return null;
}
public bool DeletePrincipal(string principalID)
{
return m_Principals.Delete("PrincipalID", principalID);
}
#endregion
#region invites table
public bool StoreInvitation(InvitationData data)
{
return m_Invites.Store(data);
}
public InvitationData RetrieveInvitation(UUID inviteID)
{
InvitationData[] invites = m_Invites.Get("InviteID", inviteID.ToString());
if (invites != null && invites.Length > 0)
return invites[0];
return null;
}
public InvitationData RetrieveInvitation(UUID groupID, string principalID)
{
InvitationData[] invites = m_Invites.Get(new string[] { "GroupID", "PrincipalID" },
new string[] { groupID.ToString(), principalID });
if (invites != null && invites.Length > 0)
return invites[0];
return null;
}
public bool DeleteInvite(UUID inviteID)
{
return m_Invites.Delete("InviteID", inviteID.ToString());
}
public void DeleteOldInvites()
{
m_Invites.DeleteOld();
}
#endregion
#region notices table
public bool StoreNotice(NoticeData data)
{
return m_Notices.Store(data);
}
public NoticeData RetrieveNotice(UUID noticeID)
{
NoticeData[] notices = m_Notices.Get("NoticeID", noticeID.ToString());
if (notices != null && notices.Length > 0)
return notices[0];
return null;
}
public NoticeData[] RetrieveNotices(UUID groupID)
{
NoticeData[] notices = m_Notices.Get("GroupID", groupID.ToString());
return notices;
}
public bool DeleteNotice(UUID noticeID)
{
return m_Notices.Delete("NoticeID", noticeID.ToString());
}
public void DeleteOldNotices()
{
m_Notices.DeleteOld();
}
#endregion
#region combinations
public MembershipData RetrievePrincipalGroupMembership(string principalID, UUID groupID)
{
// TODO
return null;
}
public MembershipData[] RetrievePrincipalGroupMemberships(string principalID)
{
// TODO
return null;
}
#endregion
}
public class PGSqlGroupsGroupsHandler : PGSQLGenericTableHandler<GroupData>
{
protected override Assembly Assembly
{
// WARNING! Moving migrations to this assembly!!!
get { return GetType().Assembly; }
}
public PGSqlGroupsGroupsHandler(string connectionString, string realm, string store)
: base(connectionString, realm, store)
{
}
}
public class PGSqlGroupsMembershipHandler : PGSQLGenericTableHandler<MembershipData>
{
protected override Assembly Assembly
{
// WARNING! Moving migrations to this assembly!!!
get { return GetType().Assembly; }
}
public PGSqlGroupsMembershipHandler(string connectionString, string realm)
: base(connectionString, realm, string.Empty)
{
}
}
public class PGSqlGroupsRolesHandler : PGSQLGenericTableHandler<RoleData>
{
protected override Assembly Assembly
{
// WARNING! Moving migrations to this assembly!!!
get { return GetType().Assembly; }
}
public PGSqlGroupsRolesHandler(string connectionString, string realm)
: base(connectionString, realm, string.Empty)
{
}
}
public class PGSqlGroupsRoleMembershipHandler : PGSQLGenericTableHandler<RoleMembershipData>
{
protected override Assembly Assembly
{
// WARNING! Moving migrations to this assembly!!!
get { return GetType().Assembly; }
}
public PGSqlGroupsRoleMembershipHandler(string connectionString, string realm)
: base(connectionString, realm, string.Empty)
{
}
}
public class PGSqlGroupsInvitesHandler : PGSQLGenericTableHandler<InvitationData>
{
protected override Assembly Assembly
{
// WARNING! Moving migrations to this assembly!!!
get { return GetType().Assembly; }
}
public PGSqlGroupsInvitesHandler(string connectionString, string realm)
: base(connectionString, realm, string.Empty)
{
}
public void DeleteOld()
{
uint now = (uint)Util.UnixTimeSinceEpoch();
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
cmd.CommandText = String.Format("delete from {0} where \"TMStamp\" < :tstamp", m_Realm);
cmd.Parameters.AddWithValue("tstamp", now - 14 * 24 * 60 * 60); // > 2 weeks old
ExecuteNonQuery(cmd);
}
}
}
public class PGSqlGroupsNoticesHandler : PGSQLGenericTableHandler<NoticeData>
{
protected override Assembly Assembly
{
// WARNING! Moving migrations to this assembly!!!
get { return GetType().Assembly; }
}
public PGSqlGroupsNoticesHandler(string connectionString, string realm)
: base(connectionString, realm, string.Empty)
{
}
public void DeleteOld()
{
uint now = (uint)Util.UnixTimeSinceEpoch();
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
cmd.CommandText = String.Format("delete from {0} where \"TMStamp\" < :tstamp", m_Realm);
cmd.Parameters.AddWithValue("tstamp", now - 14 * 24 * 60 * 60); // > 2 weeks old
ExecuteNonQuery(cmd);
}
}
}
public class PGSqlGroupsPrincipalsHandler : PGSQLGenericTableHandler<PrincipalData>
{
protected override Assembly Assembly
{
// WARNING! Moving migrations to this assembly!!!
get { return GetType().Assembly; }
}
public PGSqlGroupsPrincipalsHandler(string connectionString, string realm)
: base(connectionString, realm, string.Empty)
{
}
}
}

View File

@@ -0,0 +1,80 @@
/*
* 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.Data;
using System.Reflection;
using System.Threading;
using log4net;
using OpenMetaverse;
using OpenSim.Framework;
using Npgsql;
namespace OpenSim.Data.PGSQL
{
/// <summary>
/// A PGSQL Interface for user grid data
/// </summary>
public class PGSQLHGTravelData : PGSQLGenericTableHandler<HGTravelingData>, IHGTravelingData
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public PGSQLHGTravelData(string connectionString, string realm) : base(connectionString, realm, "HGTravelStore") { }
public HGTravelingData Get(UUID sessionID)
{
HGTravelingData[] ret = Get("SessionID", sessionID.ToString());
if (ret.Length == 0)
return null;
return ret[0];
}
public HGTravelingData[] GetSessions(UUID userID)
{
return base.Get("UserID", userID.ToString());
}
public bool Delete(UUID sessionID)
{
return Delete("SessionID", sessionID.ToString());
}
public void DeleteOld()
{
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
cmd.CommandText = String.Format(@"delete from {0} where ""TMStamp"" < CURRENT_DATE - INTERVAL '2 day'", m_Realm);
ExecuteNonQuery(cmd);
}
}
}
}

View File

@@ -0,0 +1,831 @@
/*
* 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.Data;
using System.Reflection;
using log4net;
using OpenMetaverse;
using OpenSim.Framework;
using Npgsql;
namespace OpenSim.Data.PGSQL
{
/// <summary>
/// A PGSQL interface for the inventory server
/// </summary>
public class PGSQLInventoryData : IInventoryDataPlugin
{
private const string _migrationStore = "InventoryStore";
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// The database manager
/// </summary>
private PGSQLManager database;
private string m_connectionString;
#region IPlugin members
[Obsolete("Cannot be default-initialized!")]
public void Initialise()
{
m_log.Info("[PGSQLInventoryData]: " + Name + " cannot be default-initialized!");
throw new PluginNotInitialisedException(Name);
}
/// <summary>
/// Loads and initialises the PGSQL inventory storage interface
/// </summary>
/// <param name="connectionString">connect string</param>
/// <remarks>use PGSQL_connection.ini</remarks>
public void Initialise(string connectionString)
{
m_connectionString = connectionString;
database = new PGSQLManager(connectionString);
//New migrations check of store
database.CheckMigration(_migrationStore);
}
/// <summary>
/// The name of this DB provider
/// </summary>
/// <returns>A string containing the name of the DB provider</returns>
public string Name
{
get { return "PGSQL Inventory Data Interface"; }
}
/// <summary>
/// Closes this DB provider
/// </summary>
public void Dispose()
{
database = null;
}
/// <summary>
/// Returns the version of this DB provider
/// </summary>
/// <returns>A string containing the DB provider</returns>
public string Version
{
get { return database.getVersion(); }
}
#endregion
#region Folder methods
/// <summary>
/// Returns a list of the root folders within a users inventory
/// </summary>
/// <param name="user">The user whos inventory is to be searched</param>
/// <returns>A list of folder objects</returns>
public List<InventoryFolderBase> getUserRootFolders(UUID user)
{
if (user == UUID.Zero)
return new List<InventoryFolderBase>();
return getInventoryFolders(UUID.Zero, user);
}
/// <summary>
/// see InventoryItemBase.getUserRootFolder
/// </summary>
/// <param name="user">the User UUID</param>
/// <returns></returns>
public InventoryFolderBase getUserRootFolder(UUID user)
{
List<InventoryFolderBase> items = getUserRootFolders(user);
InventoryFolderBase rootFolder = null;
// There should only ever be one root folder for a user. However, if there's more
// than one we'll simply use the first one rather than failing. It would be even
// nicer to print some message to this effect, but this feels like it's too low a
// to put such a message out, and it's too minor right now to spare the time to
// suitably refactor.
if (items.Count > 0)
{
rootFolder = items[0];
}
return rootFolder;
}
/// <summary>
/// Returns a list of folders in a users inventory contained within the specified folder
/// </summary>
/// <param name="parentID">The folder to search</param>
/// <returns>A list of inventory folders</returns>
public List<InventoryFolderBase> getInventoryFolders(UUID parentID)
{
return getInventoryFolders(parentID, UUID.Zero);
}
/// <summary>
/// Returns a specified inventory folder
/// </summary>
/// <param name="folderID">The folder to return</param>
/// <returns>A folder class</returns>
public InventoryFolderBase getInventoryFolder(UUID folderID)
{
string sql = "SELECT * FROM inventoryfolders WHERE \"folderID\" = :folderID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(database.CreateParameter("folderID", folderID));
conn.Open();
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
return readInventoryFolder(reader);
}
}
}
m_log.InfoFormat("[INVENTORY DB] : Found no inventory folder with ID : {0}", folderID);
return null;
}
/// <summary>
/// Returns all child folders in the hierarchy from the parent folder and down.
/// Does not return the parent folder itself.
/// </summary>
/// <param name="parentID">The folder to get subfolders for</param>
/// <returns>A list of inventory folders</returns>
public List<InventoryFolderBase> getFolderHierarchy(UUID parentID)
{
//Note maybe change this to use a Dataset that loading in all folders of a user and then go throw it that way.
//Note this is changed so it opens only one connection to the database and not everytime it wants to get data.
/* NOTE: the implementation below is very inefficient (makes a separate request to get subfolders for
* every found folder, recursively). Inventory code for other DBs has been already rewritten to get ALL
* inventory for a specific user at once.
*
* Meanwhile, one little thing is corrected: getFolderHierarchy(UUID.Zero) doesn't make sense and should never
* be used, so check for that and return an empty list.
*/
List<InventoryFolderBase> folders = new List<InventoryFolderBase>();
if (parentID == UUID.Zero)
return folders;
string sql = "SELECT * FROM inventoryfolders WHERE \"parentFolderID\" = :parentID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(database.CreateParameter("parentID", parentID));
conn.Open();
folders.AddRange(getInventoryFolders(cmd));
List<InventoryFolderBase> tempFolders = new List<InventoryFolderBase>();
foreach (InventoryFolderBase folderBase in folders)
{
tempFolders.AddRange(getFolderHierarchy(folderBase.ID, cmd));
}
if (tempFolders.Count > 0)
{
folders.AddRange(tempFolders);
}
}
return folders;
}
/// <summary>
/// Creates a new inventory folder
/// </summary>
/// <param name="folder">Folder to create</param>
public void addInventoryFolder(InventoryFolderBase folder)
{
string sql = "INSERT INTO inventoryfolders (\"folderID\", \"agentID\", \"parentFolderID\", \"folderName\", type, version) " +
" VALUES (:folderID, :agentID, :parentFolderID, :folderName, :type, :version);";
string folderName = folder.Name;
if (folderName.Length > 64)
{
folderName = folderName.Substring(0, 64);
m_log.Warn("[INVENTORY DB]: Name field truncated from " + folder.Name.Length.ToString() + " to " + folderName.Length + " characters on add");
}
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(database.CreateParameter("folderID", folder.ID));
cmd.Parameters.Add(database.CreateParameter("agentID", folder.Owner));
cmd.Parameters.Add(database.CreateParameter("parentFolderID", folder.ParentID));
cmd.Parameters.Add(database.CreateParameter("folderName", folderName));
cmd.Parameters.Add(database.CreateParameter("type", folder.Type));
cmd.Parameters.Add(database.CreateParameter("version", folder.Version));
conn.Open();
try
{
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
m_log.ErrorFormat("[INVENTORY DB]: Error : {0}", e.Message);
}
}
}
/// <summary>
/// Updates an inventory folder
/// </summary>
/// <param name="folder">Folder to update</param>
public void updateInventoryFolder(InventoryFolderBase folder)
{
string sql = @"UPDATE inventoryfolders SET ""agentID"" = :agentID,
""parentFolderID"" = :parentFolderID,
""folderName"" = :folderName,
type = :type,
version = :version
WHERE folderID = :folderID";
string folderName = folder.Name;
if (folderName.Length > 64)
{
folderName = folderName.Substring(0, 64);
m_log.Warn("[INVENTORY DB]: Name field truncated from " + folder.Name.Length.ToString() + " to " + folderName.Length + " characters on update");
}
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(database.CreateParameter("folderID", folder.ID));
cmd.Parameters.Add(database.CreateParameter("agentID", folder.Owner));
cmd.Parameters.Add(database.CreateParameter("parentFolderID", folder.ParentID));
cmd.Parameters.Add(database.CreateParameter("folderName", folderName));
cmd.Parameters.Add(database.CreateParameter("type", folder.Type));
cmd.Parameters.Add(database.CreateParameter("version", folder.Version));
conn.Open();
try
{
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
m_log.ErrorFormat("[INVENTORY DB]: Error : {0}", e.Message);
}
}
}
/// <summary>
/// Updates an inventory folder
/// </summary>
/// <param name="folder">Folder to update</param>
public void moveInventoryFolder(InventoryFolderBase folder)
{
string sql = @"UPDATE inventoryfolders SET ""parentFolderID"" = :parentFolderID WHERE ""folderID"" = :folderID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(database.CreateParameter("parentFolderID", folder.ParentID));
cmd.Parameters.Add(database.CreateParameter("folderID", folder.ID));
conn.Open();
try
{
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
m_log.ErrorFormat("[INVENTORY DB]: Error : {0}", e.Message);
}
}
}
/// <summary>
/// Delete an inventory folder
/// </summary>
/// <param name="folderID">Id of folder to delete</param>
public void deleteInventoryFolder(UUID folderID)
{
string sql = @"SELECT * FROM inventoryfolders WHERE ""parentFolderID"" = :parentID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
List<InventoryFolderBase> subFolders;
cmd.Parameters.Add(database.CreateParameter("parentID", UUID.Zero));
conn.Open();
subFolders = getFolderHierarchy(folderID, cmd);
//Delete all sub-folders
foreach (InventoryFolderBase f in subFolders)
{
DeleteOneFolder(f.ID, conn);
DeleteItemsInFolder(f.ID, conn);
}
//Delete the actual row
DeleteOneFolder(folderID, conn);
DeleteItemsInFolder(folderID, conn);
}
}
#endregion
#region Item Methods
/// <summary>
/// Returns a list of items in a specified folder
/// </summary>
/// <param name="folderID">The folder to search</param>
/// <returns>A list containing inventory items</returns>
public List<InventoryItemBase> getInventoryInFolder(UUID folderID)
{
string sql = @"SELECT * FROM inventoryitems WHERE ""parentFolderID"" = :parentFolderID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(database.CreateParameter("parentFolderID", folderID));
conn.Open();
List<InventoryItemBase> items = new List<InventoryItemBase>();
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
while (reader.Read())
{
items.Add(readInventoryItem(reader));
}
}
return items;
}
}
/// <summary>
/// Returns a specified inventory item
/// </summary>
/// <param name="itemID">The item ID</param>
/// <returns>An inventory item</returns>
public InventoryItemBase getInventoryItem(UUID itemID)
{
string sql = @"SELECT * FROM inventoryitems WHERE ""inventoryID"" = :inventoryID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(database.CreateParameter("inventoryID", itemID));
conn.Open();
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
return readInventoryItem(reader);
}
}
}
m_log.InfoFormat("[INVENTORY DB]: Found no inventory item with ID : {0}", itemID);
return null;
}
/// <summary>
/// Adds a specified item to the database
/// </summary>
/// <param name="item">The inventory item</param>
public void addInventoryItem(InventoryItemBase item)
{
if (getInventoryItem(item.ID) != null)
{
updateInventoryItem(item);
return;
}
string sql = @"INSERT INTO inventoryitems
(""inventoryID"", ""assetID"", ""assetType"", ""parentFolderID"", ""avatarID"", ""inventoryName"",
""inventoryDescription"", ""inventoryNextPermissions"", ""inventoryCurrentPermissions"",
""invType"", ""creatorID"", ""inventoryBasePermissions"", ""inventoryEveryOnePermissions"", ""inventoryGroupPermissions"",
""salePrice"", ""SaleType"", ""creationDate"", ""groupID"", ""groupOwned"", flags)
VALUES
(:inventoryID, :assetID, :assetType, :parentFolderID, :avatarID, :inventoryName, :inventoryDescription,
:inventoryNextPermissions, :inventoryCurrentPermissions, :invType, :creatorID,
:inventoryBasePermissions, :inventoryEveryOnePermissions, :inventoryGroupPermissions, :SalePrice, :SaleType,
:creationDate, :groupID, :groupOwned, :flags)";
string itemName = item.Name;
if (item.Name.Length > 64)
{
itemName = item.Name.Substring(0, 64);
m_log.Warn("[INVENTORY DB]: Name field truncated from " + item.Name.Length.ToString() + " to " + itemName.Length.ToString() + " characters");
}
string itemDesc = item.Description;
if (item.Description.Length > 128)
{
itemDesc = item.Description.Substring(0, 128);
m_log.Warn("[INVENTORY DB]: Description field truncated from " + item.Description.Length.ToString() + " to " + itemDesc.Length.ToString() + " characters");
}
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand command = new NpgsqlCommand(sql, conn))
{
command.Parameters.Add(database.CreateParameter("inventoryID", item.ID));
command.Parameters.Add(database.CreateParameter("assetID", item.AssetID));
command.Parameters.Add(database.CreateParameter("assetType", item.AssetType));
command.Parameters.Add(database.CreateParameter("parentFolderID", item.Folder));
command.Parameters.Add(database.CreateParameter("avatarID", item.Owner));
command.Parameters.Add(database.CreateParameter("inventoryName", itemName));
command.Parameters.Add(database.CreateParameter("inventoryDescription", itemDesc));
command.Parameters.Add(database.CreateParameter("inventoryNextPermissions", item.NextPermissions));
command.Parameters.Add(database.CreateParameter("inventoryCurrentPermissions", item.CurrentPermissions));
command.Parameters.Add(database.CreateParameter("invType", item.InvType));
command.Parameters.Add(database.CreateParameter("creatorID", item.CreatorId));
command.Parameters.Add(database.CreateParameter("inventoryBasePermissions", item.BasePermissions));
command.Parameters.Add(database.CreateParameter("inventoryEveryOnePermissions", item.EveryOnePermissions));
command.Parameters.Add(database.CreateParameter("inventoryGroupPermissions", item.GroupPermissions));
command.Parameters.Add(database.CreateParameter("SalePrice", item.SalePrice));
command.Parameters.Add(database.CreateParameter("SaleType", item.SaleType));
command.Parameters.Add(database.CreateParameter("creationDate", item.CreationDate));
command.Parameters.Add(database.CreateParameter("groupID", item.GroupID));
command.Parameters.Add(database.CreateParameter("groupOwned", item.GroupOwned));
command.Parameters.Add(database.CreateParameter("flags", item.Flags));
conn.Open();
try
{
command.ExecuteNonQuery();
}
catch (Exception e)
{
m_log.Error("[INVENTORY DB]: Error inserting item :" + e.Message);
}
}
sql = @"UPDATE inventoryfolders SET version = version + 1 WHERE ""folderID"" = @folderID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand command = new NpgsqlCommand(sql, conn))
{
command.Parameters.Add(database.CreateParameter("folderID", item.Folder.ToString()));
conn.Open();
try
{
command.ExecuteNonQuery();
}
catch (Exception e)
{
m_log.Error("[INVENTORY DB] Error updating inventory folder for new item :" + e.Message);
}
}
}
/// <summary>
/// Updates the specified inventory item
/// </summary>
/// <param name="item">Inventory item to update</param>
public void updateInventoryItem(InventoryItemBase item)
{
string sql = @"UPDATE inventoryitems SET ""assetID"" = :assetID,
""assetType"" = :assetType,
""parentFolderID"" = :parentFolderID,
""avatarID"" = :avatarID,
""inventoryName"" = :inventoryName,
""inventoryDescription"" = :inventoryDescription,
""inventoryNextPermissions"" = :inventoryNextPermissions,
""inventoryCurrentPermissions"" = :inventoryCurrentPermissions,
""invType"" = :invType,
""creatorID"" = :creatorID,
""inventoryBasePermissions"" = :inventoryBasePermissions,
""inventoryEveryOnePermissions"" = :inventoryEveryOnePermissions,
""inventoryGroupPermissions"" = :inventoryGroupPermissions,
""salePrice"" = :SalePrice,
""saleType"" = :SaleType,
""creationDate"" = :creationDate,
""groupID"" = :groupID,
""groupOwned"" = :groupOwned,
flags = :flags
WHERE ""inventoryID"" = :inventoryID";
string itemName = item.Name;
if (item.Name.Length > 64)
{
itemName = item.Name.Substring(0, 64);
m_log.Warn("[INVENTORY DB]: Name field truncated from " + item.Name.Length.ToString() + " to " + itemName.Length.ToString() + " characters on update");
}
string itemDesc = item.Description;
if (item.Description.Length > 128)
{
itemDesc = item.Description.Substring(0, 128);
m_log.Warn("[INVENTORY DB]: Description field truncated from " + item.Description.Length.ToString() + " to " + itemDesc.Length.ToString() + " characters on update");
}
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand command = new NpgsqlCommand(sql, conn))
{
command.Parameters.Add(database.CreateParameter("inventoryID", item.ID));
command.Parameters.Add(database.CreateParameter("assetID", item.AssetID));
command.Parameters.Add(database.CreateParameter("assetType", item.AssetType));
command.Parameters.Add(database.CreateParameter("parentFolderID", item.Folder));
command.Parameters.Add(database.CreateParameter("avatarID", item.Owner));
command.Parameters.Add(database.CreateParameter("inventoryName", itemName));
command.Parameters.Add(database.CreateParameter("inventoryDescription", itemDesc));
command.Parameters.Add(database.CreateParameter("inventoryNextPermissions", item.NextPermissions));
command.Parameters.Add(database.CreateParameter("inventoryCurrentPermissions", item.CurrentPermissions));
command.Parameters.Add(database.CreateParameter("invType", item.InvType));
command.Parameters.Add(database.CreateParameter("creatorID", item.CreatorId));
command.Parameters.Add(database.CreateParameter("inventoryBasePermissions", item.BasePermissions));
command.Parameters.Add(database.CreateParameter("inventoryEveryOnePermissions", item.EveryOnePermissions));
command.Parameters.Add(database.CreateParameter("inventoryGroupPermissions", item.GroupPermissions));
command.Parameters.Add(database.CreateParameter("SalePrice", item.SalePrice));
command.Parameters.Add(database.CreateParameter("SaleType", item.SaleType));
command.Parameters.Add(database.CreateParameter("creationDate", item.CreationDate));
command.Parameters.Add(database.CreateParameter("groupID", item.GroupID));
command.Parameters.Add(database.CreateParameter("groupOwned", item.GroupOwned));
command.Parameters.Add(database.CreateParameter("flags", item.Flags));
conn.Open();
try
{
command.ExecuteNonQuery();
}
catch (Exception e)
{
m_log.Error("[INVENTORY DB]: Error updating item :" + e.Message);
}
}
}
// See IInventoryDataPlugin
/// <summary>
/// Delete an item in inventory database
/// </summary>
/// <param name="itemID">the item UUID</param>
public void deleteInventoryItem(UUID itemID)
{
string sql = @"DELETE FROM inventoryitems WHERE ""inventoryID""=:inventoryID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(database.CreateParameter("inventoryID", itemID));
try
{
conn.Open();
cmd.ExecuteNonQuery();
}
catch (Exception e)
{
m_log.Error("[INVENTORY DB]: Error deleting item :" + e.Message);
}
}
}
public InventoryItemBase queryInventoryItem(UUID itemID)
{
return getInventoryItem(itemID);
}
public InventoryFolderBase queryInventoryFolder(UUID folderID)
{
return getInventoryFolder(folderID);
}
/// <summary>
/// Returns all activated gesture-items in the inventory of the specified avatar.
/// </summary>
/// <param name="avatarID">The <see cref="UUID"/> of the avatar</param>
/// <returns>
/// The list of gestures (<see cref="InventoryItemBase"/>s)
/// </returns>
public List<InventoryItemBase> fetchActiveGestures(UUID avatarID)
{
string sql = @"SELECT * FROM inventoryitems WHERE ""avatarID"" = :uuid AND ""assetType"" = :assetType and flags = 1";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(database.CreateParameter("uuid", avatarID));
cmd.Parameters.Add(database.CreateParameter("assetType", (int)AssetType.Gesture));
conn.Open();
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
List<InventoryItemBase> gestureList = new List<InventoryItemBase>();
while (reader.Read())
{
gestureList.Add(readInventoryItem(reader));
}
return gestureList;
}
}
}
#endregion
#region Private methods
/// <summary>
/// Delete an item in inventory database
/// </summary>
/// <param name="folderID">the item ID</param>
/// <param name="connection">connection to the database</param>
private void DeleteItemsInFolder(UUID folderID, NpgsqlConnection connection)
{
using (NpgsqlCommand command = new NpgsqlCommand(@"DELETE FROM inventoryitems WHERE ""folderID""=:folderID", connection))
{
command.Parameters.Add(database.CreateParameter("folderID", folderID));
try
{
command.ExecuteNonQuery();
}
catch (Exception e)
{
m_log.Error("[INVENTORY DB] Error deleting item :" + e.Message);
}
}
}
/// <summary>
/// Gets the folder hierarchy in a loop.
/// </summary>
/// <param name="parentID">parent ID.</param>
/// <param name="command">SQL command/connection to database</param>
/// <returns></returns>
private static List<InventoryFolderBase> getFolderHierarchy(UUID parentID, NpgsqlCommand command)
{
command.Parameters["parentID"].Value = parentID.Guid; //.ToString();
List<InventoryFolderBase> folders = getInventoryFolders(command);
if (folders.Count > 0)
{
List<InventoryFolderBase> tempFolders = new List<InventoryFolderBase>();
foreach (InventoryFolderBase folderBase in folders)
{
tempFolders.AddRange(getFolderHierarchy(folderBase.ID, command));
}
if (tempFolders.Count > 0)
{
folders.AddRange(tempFolders);
}
}
return folders;
}
/// <summary>
/// Gets the inventory folders.
/// </summary>
/// <param name="parentID">parentID, use UUID.Zero to get root</param>
/// <param name="user">user id, use UUID.Zero, if you want all folders from a parentID.</param>
/// <returns></returns>
private List<InventoryFolderBase> getInventoryFolders(UUID parentID, UUID user)
{
string sql = @"SELECT * FROM inventoryfolders WHERE ""parentFolderID"" = :parentID AND ""agentID"" = :uuid";
using (NpgsqlConnection conn = new NpgsqlConnection(m_connectionString))
using (NpgsqlCommand command = new NpgsqlCommand(sql, conn))
{
if (user == UUID.Zero)
{
command.Parameters.Add(database.CreateParameter("uuid", "%"));
}
else
{
command.Parameters.Add(database.CreateParameter("uuid", user));
}
command.Parameters.Add(database.CreateParameter("parentID", parentID));
conn.Open();
return getInventoryFolders(command);
}
}
/// <summary>
/// Gets the inventory folders.
/// </summary>
/// <param name="command">SQLcommand.</param>
/// <returns></returns>
private static List<InventoryFolderBase> getInventoryFolders(NpgsqlCommand command)
{
using (NpgsqlDataReader reader = command.ExecuteReader())
{
List<InventoryFolderBase> items = new List<InventoryFolderBase>();
while (reader.Read())
{
items.Add(readInventoryFolder(reader));
}
return items;
}
}
/// <summary>
/// Reads a list of inventory folders returned by a query.
/// </summary>
/// <param name="reader">A PGSQL Data Reader</param>
/// <returns>A List containing inventory folders</returns>
protected static InventoryFolderBase readInventoryFolder(NpgsqlDataReader reader)
{
try
{
InventoryFolderBase folder = new InventoryFolderBase();
folder.Owner = DBGuid.FromDB(reader["agentID"]);
folder.ParentID = DBGuid.FromDB(reader["parentFolderID"]);
folder.ID = DBGuid.FromDB(reader["folderID"]);
folder.Name = (string)reader["folderName"];
folder.Type = (short)reader["type"];
folder.Version = Convert.ToUInt16(reader["version"]);
return folder;
}
catch (Exception e)
{
m_log.Error("[INVENTORY DB] Error reading inventory folder :" + e.Message);
}
return null;
}
/// <summary>
/// Reads a one item from an SQL result
/// </summary>
/// <param name="reader">The SQL Result</param>
/// <returns>the item read</returns>
private static InventoryItemBase readInventoryItem(IDataRecord reader)
{
try
{
InventoryItemBase item = new InventoryItemBase();
item.ID = DBGuid.FromDB(reader["inventoryID"]);
item.AssetID = DBGuid.FromDB(reader["assetID"]);
item.AssetType = Convert.ToInt32(reader["assetType"].ToString());
item.Folder = DBGuid.FromDB(reader["parentFolderID"]);
item.Owner = DBGuid.FromDB(reader["avatarID"]);
item.Name = reader["inventoryName"].ToString();
item.Description = reader["inventoryDescription"].ToString();
item.NextPermissions = Convert.ToUInt32(reader["inventoryNextPermissions"]);
item.CurrentPermissions = Convert.ToUInt32(reader["inventoryCurrentPermissions"]);
item.InvType = Convert.ToInt32(reader["invType"].ToString());
item.CreatorId = reader["creatorID"].ToString();
item.BasePermissions = Convert.ToUInt32(reader["inventoryBasePermissions"]);
item.EveryOnePermissions = Convert.ToUInt32(reader["inventoryEveryOnePermissions"]);
item.GroupPermissions = Convert.ToUInt32(reader["inventoryGroupPermissions"]);
item.SalePrice = Convert.ToInt32(reader["salePrice"]);
item.SaleType = Convert.ToByte(reader["saleType"]);
item.CreationDate = Convert.ToInt32(reader["creationDate"]);
item.GroupID = DBGuid.FromDB(reader["groupID"]);
item.GroupOwned = Convert.ToBoolean(reader["groupOwned"]);
item.Flags = Convert.ToUInt32(reader["flags"]);
return item;
}
catch (NpgsqlException e)
{
m_log.Error("[INVENTORY DB]: Error reading inventory item :" + e.Message);
}
return null;
}
/// <summary>
/// Delete a folder in inventory databasae
/// </summary>
/// <param name="folderID">the folder UUID</param>
/// <param name="connection">connection to database</param>
private void DeleteOneFolder(UUID folderID, NpgsqlConnection connection)
{
try
{
using (NpgsqlCommand command = new NpgsqlCommand(@"DELETE FROM inventoryfolders WHERE ""folderID""=:folderID and type=-1", connection))
{
command.Parameters.Add(database.CreateParameter("folderID", folderID));
command.ExecuteNonQuery();
}
}
catch (NpgsqlException e)
{
m_log.Error("[INVENTORY DB]: Error deleting folder :" + e.Message);
}
}
#endregion
}
}

View File

@@ -0,0 +1,350 @@
/*
* 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.Data;
using System.IO;
using System.Reflection;
using OpenSim.Framework;
using log4net;
using OpenMetaverse;
using Npgsql;
using NpgsqlTypes;
namespace OpenSim.Data.PGSQL
{
/// <summary>
/// A management class for the MS SQL Storage Engine
/// </summary>
public class PGSQLManager
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
/// <summary>
/// Connection string for ADO.net
/// </summary>
private readonly string connectionString;
/// <summary>
/// Initialize the manager and set the connectionstring
/// </summary>
/// <param name="connection"></param>
public PGSQLManager(string connection)
{
connectionString = connection;
InitializeMonoSecurity();
}
public void InitializeMonoSecurity()
{
if (!Util.IsPlatformMono)
{
if (AppDomain.CurrentDomain.GetData("MonoSecurityPostgresAdded") == null)
{
AppDomain.CurrentDomain.SetData("MonoSecurityPostgresAdded", "true");
AppDomain currentDomain = AppDomain.CurrentDomain;
currentDomain.AssemblyResolve += new ResolveEventHandler(ResolveEventHandlerMonoSec);
}
}
}
private System.Reflection.Assembly ResolveEventHandlerMonoSec(object sender, ResolveEventArgs args)
{
Assembly MyAssembly = null;
if (args.Name.Substring(0, args.Name.IndexOf(",")) == "Mono.Security")
{
MyAssembly = Assembly.LoadFrom("lib/NET/Mono.Security.dll");
}
//Return the loaded assembly.
return MyAssembly;
}
/// <summary>
/// Type conversion to a SQLDbType functions
/// </summary>
/// <param name="type"></param>
/// <returns></returns>
internal NpgsqlDbType DbtypeFromType(Type type)
{
if (type == typeof(string))
{
return NpgsqlDbType.Varchar;
}
if (type == typeof(double))
{
return NpgsqlDbType.Double;
}
if (type == typeof(Single))
{
return NpgsqlDbType.Double;
}
if (type == typeof(int))
{
return NpgsqlDbType.Integer;
}
if (type == typeof(bool))
{
return NpgsqlDbType.Boolean;
}
if (type == typeof(UUID))
{
return NpgsqlDbType.Uuid;
}
if (type == typeof(byte))
{
return NpgsqlDbType.Smallint;
}
if (type == typeof(sbyte))
{
return NpgsqlDbType.Integer;
}
if (type == typeof(Byte[]))
{
return NpgsqlDbType.Bytea;
}
if (type == typeof(uint) || type == typeof(ushort))
{
return NpgsqlDbType.Integer;
}
if (type == typeof(ulong))
{
return NpgsqlDbType.Bigint;
}
if (type == typeof(DateTime))
{
return NpgsqlDbType.Timestamp;
}
return NpgsqlDbType.Varchar;
}
internal NpgsqlDbType DbtypeFromString(Type type, string PGFieldType)
{
if (PGFieldType == "")
{
return DbtypeFromType(type);
}
if (PGFieldType == "character varying")
{
return NpgsqlDbType.Varchar;
}
if (PGFieldType == "double precision")
{
return NpgsqlDbType.Double;
}
if (PGFieldType == "integer")
{
return NpgsqlDbType.Integer;
}
if (PGFieldType == "smallint")
{
return NpgsqlDbType.Smallint;
}
if (PGFieldType == "boolean")
{
return NpgsqlDbType.Boolean;
}
if (PGFieldType == "uuid")
{
return NpgsqlDbType.Uuid;
}
if (PGFieldType == "bytea")
{
return NpgsqlDbType.Bytea;
}
return DbtypeFromType(type);
}
/// <summary>
/// Creates value for parameter.
/// </summary>
/// <param name="value">The value.</param>
/// <returns></returns>
private static object CreateParameterValue(object value)
{
Type valueType = value.GetType();
if (valueType == typeof(UUID)) //TODO check if this works
{
return ((UUID) value).Guid;
}
if (valueType == typeof(UUID))
{
return ((UUID)value).Guid;
}
if (valueType == typeof(bool))
{
return (bool)value;
}
if (valueType == typeof(Byte[]))
{
return value;
}
if (valueType == typeof(int))
{
return value;
}
return value;
}
/// <summary>
/// Create value for parameter based on PGSQL Schema
/// </summary>
/// <param name="value"></param>
/// <param name="PGFieldType"></param>
/// <returns></returns>
internal static object CreateParameterValue(object value, string PGFieldType)
{
if (PGFieldType == "uuid")
{
UUID uidout;
UUID.TryParse(value.ToString(), out uidout);
return uidout;
}
if (PGFieldType == "integer")
{
int intout;
int.TryParse(value.ToString(), out intout);
return intout;
}
if (PGFieldType == "boolean")
{
return (value.ToString() == "true");
}
if (PGFieldType == "timestamp with time zone")
{
return (DateTime)value;
}
if (PGFieldType == "timestamp without time zone")
{
return (DateTime)value;
}
return CreateParameterValue(value);
}
/// <summary>
/// Create a parameter for a command
/// </summary>
/// <param name="parameterName">Name of the parameter.</param>
/// <param name="parameterObject">parameter object.</param>
/// <returns></returns>
internal NpgsqlParameter CreateParameter(string parameterName, object parameterObject)
{
return CreateParameter(parameterName, parameterObject, false);
}
/// <summary>
/// Creates the parameter for a command.
/// </summary>
/// <param name="parameterName">Name of the parameter.</param>
/// <param name="parameterObject">parameter object.</param>
/// <param name="parameterOut">if set to <c>true</c> parameter is a output parameter</param>
/// <returns></returns>
internal NpgsqlParameter CreateParameter(string parameterName, object parameterObject, bool parameterOut)
{
//Tweak so we dont always have to add : sign
if (parameterName.StartsWith(":")) parameterName = parameterName.Replace(":","");
//HACK if object is null, it is turned into a string, there are no nullable type till now
if (parameterObject == null) parameterObject = "";
NpgsqlParameter parameter = new NpgsqlParameter(parameterName, DbtypeFromType(parameterObject.GetType()));
if (parameterOut)
{
parameter.Direction = ParameterDirection.Output;
}
else
{
parameter.Direction = ParameterDirection.Input;
parameter.Value = CreateParameterValue(parameterObject);
}
return parameter;
}
/// <summary>
/// Create a parameter with PGSQL schema type
/// </summary>
/// <param name="parameterName"></param>
/// <param name="parameterObject"></param>
/// <param name="PGFieldType"></param>
/// <returns></returns>
internal NpgsqlParameter CreateParameter(string parameterName, object parameterObject, string PGFieldType)
{
//Tweak so we dont always have to add : sign
if (parameterName.StartsWith(":")) parameterName = parameterName.Replace(":", "");
//HACK if object is null, it is turned into a string, there are no nullable type till now
if (parameterObject == null) parameterObject = "";
NpgsqlParameter parameter = new NpgsqlParameter(parameterName, DbtypeFromString(parameterObject.GetType(), PGFieldType));
parameter.Direction = ParameterDirection.Input;
parameter.Value = CreateParameterValue(parameterObject, PGFieldType);
return parameter;
}
/// <summary>
/// Checks if we need to do some migrations to the database
/// </summary>
/// <param name="migrationStore">migrationStore.</param>
public void CheckMigration(string migrationStore)
{
using (NpgsqlConnection connection = new NpgsqlConnection(connectionString))
{
connection.Open();
Assembly assem = GetType().Assembly;
PGSQLMigration migration = new PGSQLMigration(connection, assem, migrationStore);
migration.Update();
}
}
/// <summary>
/// Returns the version of this DB provider
/// </summary>
/// <returns>A string containing the DB provider</returns>
public string getVersion()
{
Module module = GetType().Module;
// string dllName = module.Assembly.ManifestModule.Name;
Version dllVersion = module.Assembly.GetName().Version;
return
string.Format("{0}.{1}.{2}.{3}", dllVersion.Major, dllVersion.Minor, dllVersion.Build,
dllVersion.Revision);
}
}
}

View File

@@ -0,0 +1,102 @@
/*
* 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 Npgsql;
using System;
using System.Data;
using System.Data.Common;
using System.Reflection;
namespace OpenSim.Data.PGSQL
{
public class PGSQLMigration : Migration
{
public PGSQLMigration(NpgsqlConnection conn, Assembly assem, string type)
: base(conn, assem, type)
{
}
public PGSQLMigration(NpgsqlConnection conn, Assembly assem, string subtype, string type)
: base(conn, assem, subtype, type)
{
}
protected override int FindVersion(DbConnection conn, string type)
{
int version = 0;
NpgsqlConnection lcConn = (NpgsqlConnection)conn;
using (NpgsqlCommand cmd = lcConn.CreateCommand())
{
try
{
cmd.CommandText = "select version from migrations where name = '" + type + "' " +
" order by version desc limit 1"; //Must be
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
if (reader.Read())
{
version = Convert.ToInt32(reader["version"]);
}
reader.Close();
}
}
catch
{
// Return -1 to indicate table does not exist
return -1;
}
}
return version;
}
protected override void ExecuteScript(DbConnection conn, string[] script)
{
if (!(conn is NpgsqlConnection))
{
base.ExecuteScript(conn, script);
return;
}
foreach (string sql in script)
{
try
{
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, (NpgsqlConnection)conn))
{
cmd.ExecuteNonQuery();
}
}
catch (Exception)
{
throw new Exception(sql);
}
}
}
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the 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.Reflection;
using OpenSim.Framework;
using OpenMetaverse;
using Npgsql;
namespace OpenSim.Data.PGSQL
{
public class PGSQLOfflineIMData : PGSQLGenericTableHandler<OfflineIMData>, IOfflineIMData
{
public PGSQLOfflineIMData(string connectionString, string realm)
: base(connectionString, realm, "IM_Store")
{
}
public void DeleteOld()
{
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
cmd.CommandText = String.Format("delete from {0} where \"TMStamp\" < CURRENT_DATE - INTERVAL '2 week'", m_Realm);
ExecuteNonQuery(cmd);
}
}
}
}

View File

@@ -0,0 +1,115 @@
/*
* 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.Data;
using System.Reflection;
using System.Threading;
using log4net;
using OpenMetaverse;
using OpenSim.Framework;
using Npgsql;
namespace OpenSim.Data.PGSQL
{
/// <summary>
/// A PGSQL Interface for the Presence Server
/// </summary>
public class PGSQLPresenceData : PGSQLGenericTableHandler<PresenceData>,
IPresenceData
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public PGSQLPresenceData(string connectionString, string realm) :
base(connectionString, realm, "Presence")
{
}
public PresenceData Get(UUID sessionID)
{
PresenceData[] ret = Get("SessionID", sessionID.ToString());
if (ret.Length == 0)
return null;
return ret[0];
}
public void LogoutRegionAgents(UUID regionID)
{
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
cmd.CommandText = String.Format(@"DELETE FROM {0} WHERE ""RegionID""=:RegionID", m_Realm);
cmd.Parameters.Add(m_database.CreateParameter("RegionID", regionID));
cmd.Connection = conn;
conn.Open();
cmd.ExecuteNonQuery();
}
}
public bool ReportAgent(UUID sessionID, UUID regionID)
{
PresenceData[] pd = Get("SessionID", sessionID.ToString());
if (pd.Length == 0)
return false;
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
cmd.CommandText = String.Format(@"UPDATE {0} SET
""RegionID"" = :RegionID
WHERE ""SessionID"" = :SessionID", m_Realm);
cmd.Parameters.Add(m_database.CreateParameter("SessionID", sessionID));
cmd.Parameters.Add(m_database.CreateParameter("RegionID", regionID));
cmd.Connection = conn;
conn.Open();
if (cmd.ExecuteNonQuery() == 0)
return false;
}
return true;
}
public bool VerifyAgent(UUID agentId, UUID secureSessionID)
{
PresenceData[] ret = Get("SecureSessionID", secureSessionID.ToString());
if (ret.Length == 0)
return false;
if(ret[0].UserID != agentId.ToString())
return false;
return true;
}
}
}

View File

@@ -0,0 +1,392 @@
/*
* 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.Data;
using System.Drawing;
using System.IO;
using System.Reflection;
using log4net;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Region.Framework.Interfaces;
using OpenSim.Region.Framework.Scenes;
using RegionFlags = OpenSim.Framework.RegionFlags;
using Npgsql;
namespace OpenSim.Data.PGSQL
{
/// <summary>
/// A PGSQL Interface for the Region Server.
/// </summary>
public class PGSQLRegionData : IRegionData
{
private string m_Realm;
private List<string> m_ColumnNames = null;
private string m_ConnectionString;
private PGSQLManager m_database;
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
protected Dictionary<string, string> m_FieldTypes = new Dictionary<string, string>();
protected virtual Assembly Assembly
{
get { return GetType().Assembly; }
}
public PGSQLRegionData(string connectionString, string realm)
{
m_Realm = realm;
m_ConnectionString = connectionString;
m_database = new PGSQLManager(connectionString);
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
{
conn.Open();
Migration m = new Migration(conn, GetType().Assembly, "GridStore");
m.Update();
}
LoadFieldTypes();
}
private void LoadFieldTypes()
{
m_FieldTypes = new Dictionary<string, string>();
string query = string.Format(@"select column_name,data_type
from INFORMATION_SCHEMA.COLUMNS
where table_name = lower('{0}');
", m_Realm);
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(query, conn))
{
conn.Open();
using (NpgsqlDataReader rdr = cmd.ExecuteReader())
{
while (rdr.Read())
{
// query produces 0 to many rows of single column, so always add the first item in each row
m_FieldTypes.Add((string)rdr[0], (string)rdr[1]);
}
}
}
}
public List<RegionData> Get(string regionName, UUID scopeID)
{
string sql = "select * from "+m_Realm+" where lower(\"regionName\") like lower(:regionName) ";
if (scopeID != UUID.Zero)
sql += " and \"ScopeID\" = :scopeID";
sql += " order by lower(\"regionName\")";
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(m_database.CreateParameter("regionName", regionName));
if (scopeID != UUID.Zero)
cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID));
conn.Open();
return RunCommand(cmd);
}
}
public RegionData Get(int posX, int posY, UUID scopeID)
{
string sql = "select * from "+m_Realm+" where \"locX\" = :posX and \"locY\" = :posY";
if (scopeID != UUID.Zero)
sql += " and \"ScopeID\" = :scopeID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(m_database.CreateParameter("posX", posX));
cmd.Parameters.Add(m_database.CreateParameter("posY", posY));
if (scopeID != UUID.Zero)
cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID));
conn.Open();
List<RegionData> ret = RunCommand(cmd);
if (ret.Count == 0)
return null;
return ret[0];
}
}
public RegionData Get(UUID regionID, UUID scopeID)
{
string sql = "select * from "+m_Realm+" where uuid = :regionID";
if (scopeID != UUID.Zero)
sql += " and \"ScopeID\" = :scopeID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(m_database.CreateParameter("regionID", regionID));
if (scopeID != UUID.Zero)
cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID));
conn.Open();
List<RegionData> ret = RunCommand(cmd);
if (ret.Count == 0)
return null;
return ret[0];
}
}
public List<RegionData> Get(int startX, int startY, int endX, int endY, UUID scopeID)
{
string sql = "select * from "+m_Realm+" where \"locX\" between :startX and :endX and \"locY\" between :startY and :endY";
if (scopeID != UUID.Zero)
sql += " and \"ScopeID\" = :scopeID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(m_database.CreateParameter("startX", startX));
cmd.Parameters.Add(m_database.CreateParameter("startY", startY));
cmd.Parameters.Add(m_database.CreateParameter("endX", endX));
cmd.Parameters.Add(m_database.CreateParameter("endY", endY));
cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID));
conn.Open();
return RunCommand(cmd);
}
}
public List<RegionData> RunCommand(NpgsqlCommand cmd)
{
List<RegionData> retList = new List<RegionData>();
NpgsqlDataReader result = cmd.ExecuteReader();
while (result.Read())
{
RegionData ret = new RegionData();
ret.Data = new Dictionary<string, object>();
UUID regionID;
UUID.TryParse(result["uuid"].ToString(), out regionID);
ret.RegionID = regionID;
UUID scope;
UUID.TryParse(result["ScopeID"].ToString(), out scope);
ret.ScopeID = scope;
ret.RegionName = result["regionName"].ToString();
ret.posX = Convert.ToInt32(result["locX"]);
ret.posY = Convert.ToInt32(result["locY"]);
ret.sizeX = Convert.ToInt32(result["sizeX"]);
ret.sizeY = Convert.ToInt32(result["sizeY"]);
if (m_ColumnNames == null)
{
m_ColumnNames = new List<string>();
DataTable schemaTable = result.GetSchemaTable();
foreach (DataRow row in schemaTable.Rows)
m_ColumnNames.Add(row["ColumnName"].ToString());
}
foreach (string s in m_ColumnNames)
{
if (s == "uuid")
continue;
if (s == "ScopeID")
continue;
if (s == "regionName")
continue;
if (s == "locX")
continue;
if (s == "locY")
continue;
ret.Data[s] = result[s].ToString();
}
retList.Add(ret);
}
return retList;
}
public bool Store(RegionData data)
{
if (data.Data.ContainsKey("uuid"))
data.Data.Remove("uuid");
if (data.Data.ContainsKey("ScopeID"))
data.Data.Remove("ScopeID");
if (data.Data.ContainsKey("regionName"))
data.Data.Remove("regionName");
if (data.Data.ContainsKey("posX"))
data.Data.Remove("posX");
if (data.Data.ContainsKey("posY"))
data.Data.Remove("posY");
if (data.Data.ContainsKey("sizeX"))
data.Data.Remove("sizeX");
if (data.Data.ContainsKey("sizeY"))
data.Data.Remove("sizeY");
if (data.Data.ContainsKey("locX"))
data.Data.Remove("locX");
if (data.Data.ContainsKey("locY"))
data.Data.Remove("locY");
string[] fields = new List<string>(data.Data.Keys).ToArray();
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
string update = "update " + m_Realm + " set \"locX\"=:posX, \"locY\"=:posY, \"sizeX\"=:sizeX, \"sizeY\"=:sizeY ";
foreach (string field in fields)
{
update += ", ";
update += " \"" + field + "\" = :" + field;
if (m_FieldTypes.ContainsKey(field))
cmd.Parameters.Add(m_database.CreateParameter(field, data.Data[field], m_FieldTypes[field]));
else
cmd.Parameters.Add(m_database.CreateParameter(field, data.Data[field]));
}
update += " where uuid = :regionID";
if (data.ScopeID != UUID.Zero)
update += " and \"ScopeID\" = :scopeID";
cmd.CommandText = update;
cmd.Connection = conn;
cmd.Parameters.Add(m_database.CreateParameter("regionID", data.RegionID));
cmd.Parameters.Add(m_database.CreateParameter("regionName", data.RegionName));
cmd.Parameters.Add(m_database.CreateParameter("scopeID", data.ScopeID));
cmd.Parameters.Add(m_database.CreateParameter("posX", data.posX));
cmd.Parameters.Add(m_database.CreateParameter("posY", data.posY));
cmd.Parameters.Add(m_database.CreateParameter("sizeX", data.sizeX));
cmd.Parameters.Add(m_database.CreateParameter("sizeY", data.sizeY));
conn.Open();
try
{
if (cmd.ExecuteNonQuery() < 1)
{
string insert = "insert into " + m_Realm + " (uuid, \"ScopeID\", \"locX\", \"locY\", \"sizeX\", \"sizeY\", \"regionName\", \"" +
String.Join("\", \"", fields) +
"\") values (:regionID, :scopeID, :posX, :posY, :sizeX, :sizeY, :regionName, :" + String.Join(", :", fields) + ")";
cmd.CommandText = insert;
try
{
if (cmd.ExecuteNonQuery() < 1)
{
return false;
}
}
catch (Exception ex)
{
m_log.Warn("[PGSQL Grid]: Error inserting into Regions table: " + ex.Message + ", INSERT sql: " + insert);
}
}
}
catch (Exception ex)
{
m_log.Warn("[PGSQL Grid]: Error updating Regions table: " + ex.Message + ", UPDATE sql: " + update);
}
}
return true;
}
public bool SetDataItem(UUID regionID, string item, string value)
{
string sql = "update " + m_Realm +
" set \"" + item + "\" = :" + item + " where uuid = :UUID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(m_database.CreateParameter("" + item, value));
cmd.Parameters.Add(m_database.CreateParameter("UUID", regionID));
conn.Open();
if (cmd.ExecuteNonQuery() > 0)
return true;
}
return false;
}
public bool Delete(UUID regionID)
{
string sql = "delete from " + m_Realm +
" where uuid = :UUID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(m_database.CreateParameter("UUID", regionID));
conn.Open();
if (cmd.ExecuteNonQuery() > 0)
return true;
}
return false;
}
public List<RegionData> GetDefaultRegions(UUID scopeID)
{
return Get((int)RegionFlags.DefaultRegion, scopeID);
}
public List<RegionData> GetDefaultHypergridRegions(UUID scopeID)
{
return Get((int)RegionFlags.DefaultHGRegion, scopeID);
}
public List<RegionData> GetFallbackRegions(UUID scopeID, int x, int y)
{
List<RegionData> regions = Get((int)RegionFlags.FallbackRegion, scopeID);
RegionDataDistanceCompare distanceComparer = new RegionDataDistanceCompare(x, y);
regions.Sort(distanceComparer);
return regions;
}
public List<RegionData> GetHyperlinks(UUID scopeID)
{
return Get((int)RegionFlags.Hyperlink, scopeID);
}
private List<RegionData> Get(int regionFlags, UUID scopeID)
{
string sql = "SELECT * FROM " + m_Realm + " WHERE (flags & " + regionFlags.ToString() + ") <> 0";
if (scopeID != UUID.Zero)
sql += " AND \"ScopeID\" = :scopeID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID));
conn.Open();
return RunCommand(cmd);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,325 @@
/*
* 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.Data;
using OpenMetaverse;
using OpenSim.Framework;
using System.Text;
using Npgsql;
using log4net;
using System.Reflection;
namespace OpenSim.Data.PGSQL
{
public class PGSQLUserAccountData : PGSQLGenericTableHandler<UserAccountData>,IUserAccountData
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public PGSQLUserAccountData(string connectionString, string realm) :
base(connectionString, realm, "UserAccount")
{
}
/*
private string m_Realm;
private List<string> m_ColumnNames = null;
private PGSQLManager m_database;
public PGSQLUserAccountData(string connectionString, string realm) :
base(connectionString, realm, "UserAccount")
{
m_Realm = realm;
m_ConnectionString = connectionString;
m_database = new PGSQLManager(connectionString);
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
{
conn.Open();
Migration m = new Migration(conn, GetType().Assembly, "UserAccount");
m.Update();
}
}
*/
/*
public List<UserAccountData> Query(UUID principalID, UUID scopeID, string query)
{
return null;
}
*/
/*
public override UserAccountData[] Get(string[] fields, string[] keys)
{
UserAccountData[] retUA = base.Get(fields,keys);
if (retUA.Length > 0)
{
Dictionary<string, string> data = retUA[0].Data;
Dictionary<string, string> data2 = new Dictionary<string, string>();
foreach (KeyValuePair<string,string> chave in data)
{
string s2 = chave.Key;
data2[s2] = chave.Value;
if (!m_FieldTypes.ContainsKey(chave.Key))
{
string tipo = "";
m_FieldTypes.TryGetValue(chave.Key, out tipo);
m_FieldTypes.Add(s2, tipo);
}
}
foreach (KeyValuePair<string, string> chave in data2)
{
if (!retUA[0].Data.ContainsKey(chave.Key))
retUA[0].Data.Add(chave.Key, chave.Value);
}
}
return retUA;
}
*/
/*
public UserAccountData Get(UUID principalID, UUID scopeID)
{
UserAccountData ret = new UserAccountData();
ret.Data = new Dictionary<string, string>();
string sql = string.Format(@"select * from {0} where ""PrincipalID"" = :principalID", m_Realm);
if (scopeID != UUID.Zero)
sql += @" and ""ScopeID"" = :scopeID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
cmd.Parameters.Add(m_database.CreateParameter("principalID", principalID));
cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID));
conn.Open();
using (NpgsqlDataReader result = cmd.ExecuteReader())
{
if (result.Read())
{
ret.PrincipalID = principalID;
UUID scope;
UUID.TryParse(result["scopeid"].ToString(), out scope);
ret.ScopeID = scope;
if (m_ColumnNames == null)
{
m_ColumnNames = new List<string>();
DataTable schemaTable = result.GetSchemaTable();
foreach (DataRow row in schemaTable.Rows)
m_ColumnNames.Add(row["ColumnName"].ToString());
}
foreach (string s in m_ColumnNames)
{
string s2 = s;
if (s2 == "uuid")
continue;
if (s2 == "scopeid")
continue;
ret.Data[s] = result[s].ToString();
}
return ret;
}
}
}
return null;
}
public override bool Store(UserAccountData data)
{
if (data.Data.ContainsKey("PrincipalID"))
data.Data.Remove("PrincipalID");
if (data.Data.ContainsKey("ScopeID"))
data.Data.Remove("ScopeID");
string[] fields = new List<string>(data.Data.Keys).ToArray();
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
m_log.DebugFormat("[USER]: Try to update user {0} {1}", data.FirstName, data.LastName);
StringBuilder updateBuilder = new StringBuilder();
updateBuilder.AppendFormat("update {0} set ", m_Realm);
bool first = true;
foreach (string field in fields)
{
if (!first)
updateBuilder.Append(", ");
updateBuilder.AppendFormat("\"{0}\" = :{0}", field);
first = false;
if (m_FieldTypes.ContainsKey(field))
cmd.Parameters.Add(m_database.CreateParameter("" + field, data.Data[field], m_FieldTypes[field]));
else
cmd.Parameters.Add(m_database.CreateParameter("" + field, data.Data[field]));
}
updateBuilder.Append(" where \"PrincipalID\" = :principalID");
if (data.ScopeID != UUID.Zero)
updateBuilder.Append(" and \"ScopeID\" = :scopeID");
cmd.CommandText = updateBuilder.ToString();
cmd.Connection = conn;
cmd.Parameters.Add(m_database.CreateParameter("principalID", data.PrincipalID));
cmd.Parameters.Add(m_database.CreateParameter("scopeID", data.ScopeID));
m_log.DebugFormat("[USER]: SQL update user {0} ", cmd.CommandText);
conn.Open();
m_log.DebugFormat("[USER]: CON opened update user {0} ", cmd.CommandText);
int conta = 0;
try
{
conta = cmd.ExecuteNonQuery();
}
catch (Exception e){
m_log.ErrorFormat("[USER]: ERROR opened update user {0} ", e.Message);
}
if (conta < 1)
{
m_log.DebugFormat("[USER]: Try to insert user {0} {1}", data.FirstName, data.LastName);
StringBuilder insertBuilder = new StringBuilder();
insertBuilder.AppendFormat(@"insert into {0} (""PrincipalID"", ""ScopeID"", ""FirstName"", ""LastName"", """, m_Realm);
insertBuilder.Append(String.Join(@""", """, fields));
insertBuilder.Append(@""") values (:principalID, :scopeID, :FirstName, :LastName, :");
insertBuilder.Append(String.Join(", :", fields));
insertBuilder.Append(");");
cmd.Parameters.Add(m_database.CreateParameter("FirstName", data.FirstName));
cmd.Parameters.Add(m_database.CreateParameter("LastName", data.LastName));
cmd.CommandText = insertBuilder.ToString();
if (cmd.ExecuteNonQuery() < 1)
{
return false;
}
}
else
m_log.DebugFormat("[USER]: User {0} {1} exists", data.FirstName, data.LastName);
}
return true;
}
public bool Store(UserAccountData data, UUID principalID, string token)
{
return false;
}
public bool SetDataItem(UUID principalID, string item, string value)
{
string sql = string.Format(@"update {0} set {1} = :{1} where ""UUID"" = :UUID", m_Realm, item);
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
if (m_FieldTypes.ContainsKey(item))
cmd.Parameters.Add(m_database.CreateParameter("" + item, value, m_FieldTypes[item]));
else
cmd.Parameters.Add(m_database.CreateParameter("" + item, value));
cmd.Parameters.Add(m_database.CreateParameter("UUID", principalID));
conn.Open();
if (cmd.ExecuteNonQuery() > 0)
return true;
}
return false;
}
*/
/*
public UserAccountData[] Get(string[] keys, string[] vals)
{
return null;
}
*/
public UserAccountData[] GetUsers(UUID scopeID, string query)
{
string[] words = query.Split(new char[] { ' ' });
for (int i = 0; i < words.Length; i++)
{
if (words[i].Length < 3)
{
if (i != words.Length - 1)
Array.Copy(words, i + 1, words, i, words.Length - i - 1);
Array.Resize(ref words, words.Length - 1);
}
}
if (words.Length == 0)
return new UserAccountData[0];
if (words.Length > 2)
return new UserAccountData[0];
string sql = "";
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
if (words.Length == 1)
{
sql = String.Format(@"select * from {0} where (""ScopeID""=:ScopeID or ""ScopeID""='00000000-0000-0000-0000-000000000000') and (""FirstName"" ilike :search or ""LastName"" ilike :search)", m_Realm);
cmd.Parameters.Add(m_database.CreateParameter("scopeID", scopeID));
cmd.Parameters.Add(m_database.CreateParameter("search", "%" + words[0] + "%"));
}
else
{
sql = String.Format(@"select * from {0} where (""ScopeID""=:ScopeID or ""ScopeID""='00000000-0000-0000-0000-000000000000') and (""FirstName"" ilike :searchFirst or ""LastName"" ilike :searchLast)", m_Realm);
cmd.Parameters.Add(m_database.CreateParameter("searchFirst", "%" + words[0] + "%"));
cmd.Parameters.Add(m_database.CreateParameter("searchLast", "%" + words[1] + "%"));
cmd.Parameters.Add(m_database.CreateParameter("ScopeID", scopeID.ToString()));
}
cmd.Connection = conn;
cmd.CommandText = sql;
conn.Open();
return DoQuery(cmd);
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,535 @@
/*
* 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.Data;
using System.IO;
using System.IO.Compression;
using System.Reflection;
using System.Security.Cryptography;
using System.Text;
using log4net;
using OpenMetaverse;
using OpenSim.Framework;
using OpenSim.Data;
using Npgsql;
namespace OpenSim.Data.PGSQL
{
public class PGSQLXAssetData : IXAssetDataPlugin
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
protected virtual Assembly Assembly
{
get { return GetType().Assembly; }
}
/// <summary>
/// Number of days that must pass before we update the access time on an asset when it has been fetched.
/// </summary>
private const int DaysBetweenAccessTimeUpdates = 30;
private bool m_enableCompression = false;
private string m_connectionString;
private object m_dbLock = new object();
/// <summary>
/// We can reuse this for all hashing since all methods are single-threaded through m_dbBLock
/// </summary>
private HashAlgorithm hasher = new SHA256CryptoServiceProvider();
#region IPlugin Members
public string Version { get { return "1.0.0.0"; } }
/// <summary>
/// <para>Initialises Asset interface</para>
/// <para>
/// <list type="bullet">
/// <item>Loads and initialises the PGSQL storage plugin.</item>
/// <item>Warns and uses the obsolete pgsql_connection.ini if connect string is empty.</item>
/// <item>Check for migration</item>
/// </list>
/// </para>
/// </summary>
/// <param name="connect">connect string</param>
public void Initialise(string connect)
{
m_log.ErrorFormat("[PGSQL XASSETDATA]: ***********************************************************");
m_log.ErrorFormat("[PGSQL XASSETDATA]: ***********************************************************");
m_log.ErrorFormat("[PGSQL XASSETDATA]: ***********************************************************");
m_log.ErrorFormat("[PGSQL XASSETDATA]: THIS PLUGIN IS STRICTLY EXPERIMENTAL.");
m_log.ErrorFormat("[PGSQL XASSETDATA]: DO NOT USE FOR ANY DATA THAT YOU DO NOT MIND LOSING.");
m_log.ErrorFormat("[PGSQL XASSETDATA]: DATABASE TABLES CAN CHANGE AT ANY TIME, CAUSING EXISTING DATA TO BE LOST.");
m_log.ErrorFormat("[PGSQL XASSETDATA]: ***********************************************************");
m_log.ErrorFormat("[PGSQL XASSETDATA]: ***********************************************************");
m_log.ErrorFormat("[PGSQL XASSETDATA]: ***********************************************************");
m_connectionString = connect;
using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString))
{
dbcon.Open();
Migration m = new Migration(dbcon, Assembly, "XAssetStore");
m.Update();
}
}
public void Initialise()
{
throw new NotImplementedException();
}
public void Dispose() { }
/// <summary>
/// The name of this DB provider
/// </summary>
public string Name
{
get { return "PGSQL XAsset storage engine"; }
}
#endregion
#region IAssetDataPlugin Members
/// <summary>
/// Fetch Asset <paramref name="assetID"/> from database
/// </summary>
/// <param name="assetID">Asset UUID to fetch</param>
/// <returns>Return the asset</returns>
/// <remarks>On failure : throw an exception and attempt to reconnect to database</remarks>
public AssetBase GetAsset(UUID assetID)
{
// m_log.DebugFormat("[PGSQL XASSET DATA]: Looking for asset {0}", assetID);
AssetBase asset = null;
lock (m_dbLock)
{
using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString))
{
dbcon.Open();
using (NpgsqlCommand cmd = new NpgsqlCommand(
@"SELECT ""Name"", ""Description"", ""AccessTime"", ""AssetType"", ""Local"", ""Temporary"", ""AssetFlags"", ""CreatorID"", ""Data""
FROM XAssetsMeta
JOIN XAssetsData ON XAssetsMeta.Hash = XAssetsData.Hash WHERE ""ID""=:ID",
dbcon))
{
cmd.Parameters.AddWithValue("ID", assetID.ToString());
try
{
using (NpgsqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow))
{
if (dbReader.Read())
{
asset = new AssetBase(assetID, (string)dbReader["Name"], (sbyte)dbReader["AssetType"], dbReader["CreatorID"].ToString());
asset.Data = (byte[])dbReader["Data"];
asset.Description = (string)dbReader["Description"];
string local = dbReader["Local"].ToString();
if (local.Equals("1") || local.Equals("true", StringComparison.InvariantCultureIgnoreCase))
asset.Local = true;
else
asset.Local = false;
asset.Temporary = Convert.ToBoolean(dbReader["Temporary"]);
asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]);
if (m_enableCompression)
{
using (GZipStream decompressionStream = new GZipStream(new MemoryStream(asset.Data), CompressionMode.Decompress))
{
MemoryStream outputStream = new MemoryStream();
WebUtil.CopyStream(decompressionStream, outputStream, int.MaxValue);
// int compressedLength = asset.Data.Length;
asset.Data = outputStream.ToArray();
// m_log.DebugFormat(
// "[XASSET DB]: Decompressed {0} {1} to {2} bytes from {3}",
// asset.ID, asset.Name, asset.Data.Length, compressedLength);
}
}
UpdateAccessTime(asset.Metadata, (int)dbReader["AccessTime"]);
}
}
}
catch (Exception e)
{
m_log.Error(string.Format("[PGSQL XASSET DATA]: Failure fetching asset {0}", assetID), e);
}
}
}
}
return asset;
}
/// <summary>
/// Create an asset in database, or update it if existing.
/// </summary>
/// <param name="asset">Asset UUID to create</param>
/// <remarks>On failure : Throw an exception and attempt to reconnect to database</remarks>
public void StoreAsset(AssetBase asset)
{
// m_log.DebugFormat("[XASSETS DB]: Storing asset {0} {1}", asset.Name, asset.ID);
lock (m_dbLock)
{
using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString))
{
dbcon.Open();
using (NpgsqlTransaction transaction = dbcon.BeginTransaction())
{
string assetName = asset.Name;
if (asset.Name.Length > 64)
{
assetName = asset.Name.Substring(0, 64);
m_log.WarnFormat(
"[XASSET DB]: Name '{0}' for asset {1} truncated from {2} to {3} characters on add",
asset.Name, asset.ID, asset.Name.Length, assetName.Length);
}
string assetDescription = asset.Description;
if (asset.Description.Length > 64)
{
assetDescription = asset.Description.Substring(0, 64);
m_log.WarnFormat(
"[XASSET DB]: Description '{0}' for asset {1} truncated from {2} to {3} characters on add",
asset.Description, asset.ID, asset.Description.Length, assetDescription.Length);
}
if (m_enableCompression)
{
MemoryStream outputStream = new MemoryStream();
using (GZipStream compressionStream = new GZipStream(outputStream, CompressionMode.Compress, false))
{
// Console.WriteLine(WebUtil.CopyTo(new MemoryStream(asset.Data), compressionStream, int.MaxValue));
// We have to close the compression stream in order to make sure it writes everything out to the underlying memory output stream.
compressionStream.Close();
byte[] compressedData = outputStream.ToArray();
asset.Data = compressedData;
}
}
byte[] hash = hasher.ComputeHash(asset.Data);
// m_log.DebugFormat(
// "[XASSET DB]: Compressed data size for {0} {1}, hash {2} is {3}",
// asset.ID, asset.Name, hash, compressedData.Length);
try
{
using (NpgsqlCommand cmd =
new NpgsqlCommand(
@"insert INTO XAssetsMeta(""ID"", ""Hash"", ""Name"", ""Description"", ""AssetType"", ""Local"", ""Temporary"", ""CreateTime"", ""AccessTime"", ""AssetFlags"", ""CreatorID"")
Select :ID, :Hash, :Name, :Description, :AssetType, :Local, :Temporary, :CreateTime, :AccessTime, :AssetFlags, :CreatorID
where not exists( Select ""ID"" from XAssetsMeta where ""ID"" = :ID ;
update XAssetsMeta
set ""ID"" = :ID, ""Hash"" = :Hash, ""Name"" = :Name, ""Description"" = :Description,
""AssetType"" = :AssetType, ""Local"" = :Local, ""Temporary"" = :Temporary, ""CreateTime"" = :CreateTime,
""AccessTime"" = :AccessTime, ""AssetFlags"" = :AssetFlags, ""CreatorID"" = :CreatorID
where ""ID"" = :ID;
",
dbcon))
{
// create unix epoch time
int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow);
cmd.Parameters.AddWithValue("ID", asset.ID);
cmd.Parameters.AddWithValue("Hash", hash);
cmd.Parameters.AddWithValue("Name", assetName);
cmd.Parameters.AddWithValue("Description", assetDescription);
cmd.Parameters.AddWithValue("AssetType", asset.Type);
cmd.Parameters.AddWithValue("Local", asset.Local);
cmd.Parameters.AddWithValue("Temporary", asset.Temporary);
cmd.Parameters.AddWithValue("CreateTime", now);
cmd.Parameters.AddWithValue("AccessTime", now);
cmd.Parameters.AddWithValue("CreatorID", asset.Metadata.CreatorID);
cmd.Parameters.AddWithValue("AssetFlags", (int)asset.Flags);
cmd.ExecuteNonQuery();
}
}
catch (Exception e)
{
m_log.ErrorFormat("[ASSET DB]: PGSQL failure creating asset metadata {0} with name \"{1}\". Error: {2}",
asset.FullID, asset.Name, e.Message);
transaction.Rollback();
return;
}
if (!ExistsData(dbcon, transaction, hash))
{
try
{
using (NpgsqlCommand cmd =
new NpgsqlCommand(
@"INSERT INTO XAssetsData(""Hash"", ""Data"") VALUES(:Hash, :Data)",
dbcon))
{
cmd.Parameters.AddWithValue("Hash", hash);
cmd.Parameters.AddWithValue("Data", asset.Data);
cmd.ExecuteNonQuery();
}
}
catch (Exception e)
{
m_log.ErrorFormat("[XASSET DB]: PGSQL failure creating asset data {0} with name \"{1}\". Error: {2}",
asset.FullID, asset.Name, e.Message);
transaction.Rollback();
return;
}
}
transaction.Commit();
}
}
}
}
/// <summary>
/// Updates the access time of the asset if it was accessed above a given threshhold amount of time.
/// </summary>
/// <remarks>
/// This gives us some insight into assets which haven't ben accessed for a long period. This is only done
/// over the threshold time to avoid excessive database writes as assets are fetched.
/// </remarks>
/// <param name='asset'></param>
/// <param name='accessTime'></param>
private void UpdateAccessTime(AssetMetadata assetMetadata, int accessTime)
{
DateTime now = DateTime.UtcNow;
if ((now - Utils.UnixTimeToDateTime(accessTime)).TotalDays < DaysBetweenAccessTimeUpdates)
return;
lock (m_dbLock)
{
using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString))
{
dbcon.Open();
NpgsqlCommand cmd =
new NpgsqlCommand(@"update XAssetsMeta set ""AccessTime""=:AccessTime where ID=:ID", dbcon);
try
{
using (cmd)
{
// create unix epoch time
cmd.Parameters.AddWithValue("ID", assetMetadata.ID);
cmd.Parameters.AddWithValue("AccessTime", (int)Utils.DateTimeToUnixTime(now));
cmd.ExecuteNonQuery();
}
}
catch (Exception e)
{
m_log.ErrorFormat(
"[XASSET PGSQL DB]: Failure updating access_time for asset {0} with name {1} : {2}",
assetMetadata.ID, assetMetadata.Name, e.Message);
}
}
}
}
/// <summary>
/// We assume we already have the m_dbLock.
/// </summary>
/// TODO: need to actually use the transaction.
/// <param name="dbcon"></param>
/// <param name="transaction"></param>
/// <param name="hash"></param>
/// <returns></returns>
private bool ExistsData(NpgsqlConnection dbcon, NpgsqlTransaction transaction, byte[] hash)
{
// m_log.DebugFormat("[ASSETS DB]: Checking for asset {0}", uuid);
bool exists = false;
using (NpgsqlCommand cmd = new NpgsqlCommand(@"SELECT ""Hash"" FROM XAssetsData WHERE ""Hash""=:Hash", dbcon))
{
cmd.Parameters.AddWithValue("Hash", hash);
try
{
using (NpgsqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow))
{
if (dbReader.Read())
{
// m_log.DebugFormat("[ASSETS DB]: Found asset {0}", uuid);
exists = true;
}
}
}
catch (Exception e)
{
m_log.ErrorFormat(
"[XASSETS DB]: PGSql failure in ExistsData fetching hash {0}. Exception {1}{2}",
hash, e.Message, e.StackTrace);
}
}
return exists;
}
/// <summary>
/// Check if the asset exists in the database
/// </summary>
/// <param name="uuid">The asset UUID</param>
/// <returns>true if it exists, false otherwise.</returns>
public bool ExistsAsset(UUID uuid)
{
// m_log.DebugFormat("[ASSETS DB]: Checking for asset {0}", uuid);
bool assetExists = false;
lock (m_dbLock)
{
using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString))
{
dbcon.Open();
using (NpgsqlCommand cmd = new NpgsqlCommand(@"SELECT ""ID"" FROM XAssetsMeta WHERE ""ID""=:ID", dbcon))
{
cmd.Parameters.AddWithValue("ID", uuid.ToString());
try
{
using (NpgsqlDataReader dbReader = cmd.ExecuteReader(CommandBehavior.SingleRow))
{
if (dbReader.Read())
{
// m_log.DebugFormat("[ASSETS DB]: Found asset {0}", uuid);
assetExists = true;
}
}
}
catch (Exception e)
{
m_log.Error(string.Format("[XASSETS DB]: PGSql failure fetching asset {0}", uuid), e);
}
}
}
}
return assetExists;
}
/// <summary>
/// Returns a list of AssetMetadata objects. The list is a subset of
/// the entire data set offset by <paramref name="start" /> containing
/// <paramref name="count" /> elements.
/// </summary>
/// <param name="start">The number of results to discard from the total data set.</param>
/// <param name="count">The number of rows the returned list should contain.</param>
/// <returns>A list of AssetMetadata objects.</returns>
public List<AssetMetadata> FetchAssetMetadataSet(int start, int count)
{
List<AssetMetadata> retList = new List<AssetMetadata>(count);
lock (m_dbLock)
{
using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString))
{
dbcon.Open();
NpgsqlCommand cmd = new NpgsqlCommand( @"SELECT ""Name"", ""Description"", ""AccessTime"", ""AssetType"", ""Temporary"", ""ID"", ""AssetFlags"", ""CreatorID""
FROM XAssetsMeta
LIMIT :start, :count", dbcon);
cmd.Parameters.AddWithValue("start", start);
cmd.Parameters.AddWithValue("count", count);
try
{
using (NpgsqlDataReader dbReader = cmd.ExecuteReader())
{
while (dbReader.Read())
{
AssetMetadata metadata = new AssetMetadata();
metadata.Name = (string)dbReader["Name"];
metadata.Description = (string)dbReader["Description"];
metadata.Type = (sbyte)dbReader["AssetType"];
metadata.Temporary = Convert.ToBoolean(dbReader["Temporary"]); // Not sure if this is correct.
metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]);
metadata.FullID = DBGuid.FromDB(dbReader["ID"]);
metadata.CreatorID = dbReader["CreatorID"].ToString();
// We'll ignore this for now - it appears unused!
// metadata.SHA1 = dbReader["hash"]);
UpdateAccessTime(metadata, (int)dbReader["AccessTime"]);
retList.Add(metadata);
}
}
}
catch (Exception e)
{
m_log.Error("[XASSETS DB]: PGSql failure fetching asset set" + Environment.NewLine + e.ToString());
}
}
}
return retList;
}
public bool Delete(string id)
{
// m_log.DebugFormat("[XASSETS DB]: Deleting asset {0}", id);
lock (m_dbLock)
{
using (NpgsqlConnection dbcon = new NpgsqlConnection(m_connectionString))
{
dbcon.Open();
using (NpgsqlCommand cmd = new NpgsqlCommand(@"delete from XAssetsMeta where ""ID""=:ID", dbcon))
{
cmd.Parameters.AddWithValue("ID", id);
cmd.ExecuteNonQuery();
}
// TODO: How do we deal with data from deleted assets? Probably not easily reapable unless we
// keep a reference count (?)
}
}
return true;
}
#endregion
}
}

View File

@@ -0,0 +1,330 @@
/*
* 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.Data;
using OpenMetaverse;
using OpenSim.Framework;
using System.Reflection;
using System.Text;
using log4net;
using Npgsql;
using NpgsqlTypes;
namespace OpenSim.Data.PGSQL
{
public class PGSQLXInventoryData : IXInventoryData
{
// private static readonly ILog m_log = LogManager.GetLogger(
// MethodBase.GetCurrentMethod().DeclaringType);
private PGSQLFolderHandler m_Folders;
private PGSQLItemHandler m_Items;
public PGSQLXInventoryData(string conn, string realm)
{
m_Folders = new PGSQLFolderHandler(
conn, "inventoryfolders", "InventoryStore");
m_Items = new PGSQLItemHandler(
conn, "inventoryitems", String.Empty);
}
public static UUID str2UUID(string strUUID)
{
UUID newUUID = UUID.Zero;
UUID.TryParse(strUUID, out newUUID);
return newUUID;
}
public XInventoryFolder[] GetFolders(string[] fields, string[] vals)
{
return m_Folders.Get(fields, vals);
}
public XInventoryItem[] GetItems(string[] fields, string[] vals)
{
return m_Items.Get(fields, vals);
}
public bool StoreFolder(XInventoryFolder folder)
{
if (folder.folderName.Length > 64)
folder.folderName = folder.folderName.Substring(0, 64);
return m_Folders.Store(folder);
}
public bool StoreItem(XInventoryItem item)
{
if (item.inventoryName.Length > 64)
item.inventoryName = item.inventoryName.Substring(0, 64);
if (item.inventoryDescription.Length > 128)
item.inventoryDescription = item.inventoryDescription.Substring(0, 128);
return m_Items.Store(item);
}
public bool DeleteFolders(string field, string val)
{
return m_Folders.Delete(field, val);
}
public bool DeleteFolders(string[] fields, string[] vals)
{
return m_Folders.Delete(fields, vals);
}
public bool DeleteItems(string field, string val)
{
return m_Items.Delete(field, val);
}
public bool DeleteItems(string[] fields, string[] vals)
{
return m_Items.Delete(fields, vals);
}
public bool MoveItem(string id, string newParent)
{
return m_Items.MoveItem(id, newParent);
}
public bool MoveFolder(string id, string newParent)
{
return m_Folders.MoveFolder(id, newParent);
}
public XInventoryItem[] GetActiveGestures(UUID principalID)
{
return m_Items.GetActiveGestures(principalID.ToString());
}
public int GetAssetPermissions(UUID principalID, UUID assetID)
{
return m_Items.GetAssetPermissions(principalID, assetID);
}
}
public class PGSQLItemHandler : PGSQLInventoryHandler<XInventoryItem>
{
public PGSQLItemHandler(string c, string t, string m) :
base(c, t, m)
{
}
public bool MoveItem(string id, string newParent)
{
XInventoryItem[] retrievedItems = Get(new string[] { "inventoryID" }, new string[] { id });
if (retrievedItems.Length == 0)
return false;
UUID oldParent = retrievedItems[0].parentFolderID;
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
{
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
cmd.CommandText = String.Format(@"update {0} set ""parentFolderID"" = :ParentFolderID where ""inventoryID"" = :InventoryID", m_Realm);
cmd.Parameters.Add(m_database.CreateParameter("ParentFolderID", newParent));
cmd.Parameters.Add(m_database.CreateParameter("InventoryID", id ));
cmd.Connection = conn;
conn.Open();
if (cmd.ExecuteNonQuery() == 0)
return false;
}
}
IncrementFolderVersion(oldParent);
IncrementFolderVersion(newParent);
return true;
}
public XInventoryItem[] GetActiveGestures(string principalID)
{
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
{
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
cmd.CommandText = String.Format(@"select * from inventoryitems where ""avatarID"" = :uuid and ""assetType"" = :type and ""flags"" = 1", m_Realm);
UUID princID = UUID.Zero;
UUID.TryParse(principalID, out princID);
cmd.Parameters.Add(m_database.CreateParameter("uuid", principalID));
cmd.Parameters.Add(m_database.CreateParameter("type", (int)AssetType.Gesture));
cmd.Connection = conn;
conn.Open();
return DoQuery(cmd);
}
}
}
public int GetAssetPermissions(UUID principalID, UUID assetID)
{
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
{
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
cmd.CommandText = String.Format(@"select bit_or(""inventoryCurrentPermissions"") as ""inventoryCurrentPermissions""
from inventoryitems
where ""avatarID"" = :PrincipalID
and ""assetID"" = :AssetID
group by ""assetID"" ", m_Realm);
cmd.Parameters.Add(m_database.CreateParameter("PrincipalID", principalID));
cmd.Parameters.Add(m_database.CreateParameter("AssetID", assetID));
cmd.Connection = conn;
conn.Open();
using (NpgsqlDataReader reader = cmd.ExecuteReader())
{
int perms = 0;
if (reader.Read())
{
perms = Convert.ToInt32(reader["inventoryCurrentPermissions"]);
}
return perms;
}
}
}
}
public override bool Store(XInventoryItem item)
{
if (!base.Store(item))
return false;
IncrementFolderVersion(item.parentFolderID);
return true;
}
}
public class PGSQLFolderHandler : PGSQLInventoryHandler<XInventoryFolder>
{
public PGSQLFolderHandler(string c, string t, string m) :
base(c, t, m)
{
}
public bool MoveFolder(string id, string newParentFolderID)
{
XInventoryFolder[] folders = Get(new string[] { "folderID" }, new string[] { id });
if (folders.Length == 0)
return false;
UUID oldParentFolderUUID = folders[0].parentFolderID;
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
{
using (NpgsqlCommand cmd = new NpgsqlCommand())
{
UUID foldID = UUID.Zero;
UUID.TryParse(id, out foldID);
UUID newPar = UUID.Zero;
UUID.TryParse(newParentFolderID, out newPar);
cmd.CommandText = String.Format(@"update {0} set ""parentFolderID"" = :ParentFolderID where ""folderID"" = :folderID", m_Realm);
cmd.Parameters.Add(m_database.CreateParameter("ParentFolderID", newPar));
cmd.Parameters.Add(m_database.CreateParameter("folderID", foldID));
cmd.Connection = conn;
conn.Open();
if (cmd.ExecuteNonQuery() == 0)
return false;
}
}
IncrementFolderVersion(oldParentFolderUUID);
IncrementFolderVersion(newParentFolderID);
return true;
}
public override bool Store(XInventoryFolder folder)
{
if (!base.Store(folder))
return false;
IncrementFolderVersion(folder.parentFolderID);
return true;
}
}
public class PGSQLInventoryHandler<T> : PGSQLGenericTableHandler<T> where T: class, new()
{
public PGSQLInventoryHandler(string c, string t, string m) : base(c, t, m) {}
protected bool IncrementFolderVersion(UUID folderID)
{
return IncrementFolderVersion(folderID.ToString());
}
protected bool IncrementFolderVersion(string folderID)
{
// m_log.DebugFormat("[PGSQL ITEM HANDLER]: Incrementing version on folder {0}", folderID);
// Util.PrintCallStack();
string sql = @"update inventoryfolders set version=version+1 where ""folderID"" = :folderID";
using (NpgsqlConnection conn = new NpgsqlConnection(m_ConnectionString))
{
using (NpgsqlCommand cmd = new NpgsqlCommand(sql, conn))
{
UUID foldID = UUID.Zero;
UUID.TryParse(folderID, out foldID);
conn.Open();
cmd.Parameters.Add( m_database.CreateParameter("folderID", foldID) );
try
{
cmd.ExecuteNonQuery();
}
catch (Exception)
{
return false;
}
}
}
return true;
}
}
}

View File

@@ -0,0 +1,65 @@
/*
* 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.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.Data.PGSQL")]
[assembly : AssemblyDescription("")]
[assembly : AssemblyConfiguration("")]
[assembly : AssemblyCompany("http://opensimulator.org")]
[assembly : AssemblyProduct("OpenSim.Data.PGSQL")]
[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("0e1c1ca4-2cf2-4315-b0e7-432c02feea8a")]
// 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 Revision and Build Numbers
// by using the '*' as shown below:
[assembly : AssemblyVersion("0.7.6.*")]

View File

@@ -0,0 +1,94 @@
:VERSION 1
CREATE TABLE assets (
"id" varchar(36) NOT NULL PRIMARY KEY,
"name" varchar(64) NOT NULL,
"description" varchar(64) NOT NULL,
"assetType" smallint NOT NULL,
"local" smallint NOT NULL,
"temporary" smallint NOT NULL,
"data" bytea NOT NULL
) ;
:VERSION 2
BEGIN TRANSACTION;
CREATE TABLE Tmp_assets
(
"id" varchar(36) NOT NULL,
"name" varchar(64) NOT NULL,
"description" varchar(64) NOT NULL,
"assetType" smallint NOT NULL,
"local" boolean NOT NULL,
"temporary" boolean NOT NULL,
"data" bytea NOT NULL
) ;
INSERT INTO Tmp_assets ("id", "name", "description", "assetType", "local", "temporary", "data")
SELECT "id", "name", "description", "assetType", case when "local" = 1 then true else false end, case when "temporary" = 1 then true else false end, "data"
FROM assets ;
DROP TABLE assets;
Alter table Tmp_assets
rename to assets;
ALTER TABLE assets ADD PRIMARY KEY ("id");
COMMIT;
:VERSION 3
BEGIN TRANSACTION;
ALTER TABLE assets add "create_time" integer default 0;
ALTER TABLE assets add "access_time" integer default 0;
COMMIT;
:VERSION 4
BEGIN TRANSACTION;
CREATE TABLE Tmp_assets
(
"id" uuid NOT NULL,
"name" varchar(64) NOT NULL,
"description" varchar(64) NOT NULL,
"assetType" smallint NOT NULL,
"local" boolean NOT NULL,
"temporary" boolean NOT NULL,
"data" bytea NOT NULL,
"create_time" int NULL,
"access_time" int NULL
) ;
INSERT INTO Tmp_assets ("id", "name", "description", "assetType", "local", "temporary", "data", "create_time", "access_time")
SELECT cast("id" as uuid), "name", "description", "assetType", "local", "temporary", "data", "create_time", "access_time"
FROM assets ;
DROP TABLE assets;
Alter table Tmp_assets
rename to assets;
ALTER TABLE assets ADD PRIMARY KEY ("id");
COMMIT;
:VERSION 5
DELETE FROM assets WHERE "id" = 'dc4b9f0b-d008-45c6-96a4-01dd947ac621';
:VERSION 6
ALTER TABLE assets ADD "asset_flags" INTEGER NOT NULL DEFAULT 0;
:VERSION 7
alter table assets add "creatorid" varchar(36) not null default '';

View File

@@ -0,0 +1,32 @@
:VERSION 1
BEGIN TRANSACTION;
CREATE TABLE auth (
uuid uuid NOT NULL default '00000000-0000-0000-0000-000000000000',
"passwordHash" varchar(32) NOT NULL,
"passwordSalt" varchar(32) NOT NULL,
"webLoginKey" varchar(255) NOT NULL,
"accountType" VARCHAR(32) NOT NULL DEFAULT 'UserAccount'
) ;
CREATE TABLE tokens (
uuid uuid NOT NULL default '00000000-0000-0000-0000-000000000000',
token varchar(255) NOT NULL,
validity TIMESTAMP NOT NULL )
;
COMMIT;
:VERSION 2
BEGIN TRANSACTION;
INSERT INTO auth (uuid, "passwordHash", "passwordSalt", "webLoginKey", "accountType")
SELECT uuid AS UUID, passwordHash AS passwordHash, passwordSalt AS passwordSalt, webLoginKey AS webLoginKey, 'UserAccount' as accountType
FROM users
where exists ( Select * from information_schema.tables where table_name = 'users' )
;
COMMIT;

View File

@@ -0,0 +1,59 @@
:VERSION 1
BEGIN TRANSACTION;
CREATE TABLE Avatars (
"PrincipalID" uuid NOT NULL PRIMARY KEY,
"Name" varchar(32) NOT NULL,
"Value" varchar(255) NOT NULL DEFAULT ''
);
COMMIT;
:VERSION 2
BEGIN TRANSACTION;
CREATE TABLE Tmp_Avatars
(
"PrincipalID" uuid NOT NULL,
"Name" varchar(32) NOT NULL,
"Value" text NOT NULL DEFAULT ''
) ;
INSERT INTO Tmp_Avatars ("PrincipalID", "Name", "Value")
SELECT "PrincipalID", cast("Name" as text), "Value"
FROM Avatars ;
DROP TABLE Avatars;
Alter table Tmp_Avatars
rename to Avatars;
COMMIT;
:VERSION 3
BEGIN TRANSACTION;
CREATE TABLE Tmp_Avatars
(
"PrincipalID" uuid NOT NULL,
"Name" varchar(32) NOT NULL,
"Value" text NOT NULL DEFAULT ''
);
ALTER TABLE Tmp_Avatars ADD PRIMARY KEY ("PrincipalID", "Name");
INSERT INTO Tmp_Avatars ("PrincipalID", "Name", "Value")
SELECT "PrincipalID", "Name", cast("Value" as text) FROM Avatars ;
DROP TABLE Avatars;
Alter table Tmp_Avatars
rename to Avatars;
COMMIT;

View File

@@ -0,0 +1,307 @@
:VERSION 1
BEGIN TRANSACTION;
CREATE TABLE estate_managers(
"EstateID" int NOT NULL Primary Key,
uuid varchar(36) NOT NULL
);
CREATE TABLE estate_groups(
"EstateID" int NOT NULL,
uuid varchar(36) NOT NULL
);
CREATE TABLE estate_users(
"EstateID" int NOT NULL,
uuid varchar(36) NOT NULL
);
CREATE TABLE estateban(
"EstateID" int NOT NULL,
"bannedUUID" varchar(36) NOT NULL,
"bannedIp" varchar(16) NOT NULL,
"bannedIpHostMask" varchar(16) NOT NULL,
"bannedNameMask" varchar(64) NULL DEFAULT NULL
);
Create Sequence estate_settings_id increment by 100 start with 100;
CREATE TABLE estate_settings(
"EstateID" integer DEFAULT nextval('estate_settings_id') NOT NULL,
"EstateName" varchar(64) NULL DEFAULT (NULL),
"AbuseEmailToEstateOwner" boolean NOT NULL,
"DenyAnonymous" boolean NOT NULL,
"ResetHomeOnTeleport" boolean NOT NULL,
"FixedSun" boolean NOT NULL,
"DenyTransacted" boolean NOT NULL,
"BlockDwell" boolean NOT NULL,
"DenyIdentified" boolean NOT NULL,
"AllowVoice" boolean NOT NULL,
"UseGlobalTime" boolean NOT NULL,
"PricePerMeter" int NOT NULL,
"TaxFree" boolean NOT NULL,
"AllowDirectTeleport" boolean NOT NULL,
"RedirectGridX" int NOT NULL,
"RedirectGridY" int NOT NULL,
"ParentEstateID" int NOT NULL,
"SunPosition" double precision NOT NULL,
"EstateSkipScripts" boolean NOT NULL,
"BillableFactor" double precision NOT NULL,
"PublicAccess" boolean NOT NULL,
"AbuseEmail" varchar(255) NOT NULL,
"EstateOwner" varchar(36) NOT NULL,
"DenyMinors" boolean NOT NULL
);
CREATE TABLE estate_map(
"RegionID" varchar(36) NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'),
"EstateID" int NOT NULL
);
COMMIT;
:VERSION 2
BEGIN TRANSACTION;
CREATE INDEX IX_estate_managers ON estate_managers
(
"EstateID"
);
CREATE INDEX IX_estate_groups ON estate_groups
(
"EstateID"
);
CREATE INDEX IX_estate_users ON estate_users
(
"EstateID"
);
COMMIT;
:VERSION 3
BEGIN TRANSACTION;
CREATE TABLE Tmp_estateban
(
"EstateID" int NOT NULL,
"bannedUUID" varchar(36) NOT NULL,
"bannedIp" varchar(16) NULL,
"bannedIpHostMask" varchar(16) NULL,
"bannedNameMask" varchar(64) NULL
);
INSERT INTO Tmp_estateban ("EstateID", "bannedUUID", "bannedIp", "bannedIpHostMask", "bannedNameMask")
SELECT "EstateID", "bannedUUID", "bannedIp", "bannedIpHostMask", "bannedNameMask" FROM estateban;
DROP TABLE estateban;
Alter table Tmp_estateban
rename to estateban;
CREATE INDEX IX_estateban ON estateban
(
"EstateID"
);
COMMIT;
:VERSION 4
BEGIN TRANSACTION;
CREATE TABLE Tmp_estate_managers
(
"EstateID" int NOT NULL,
uuid uuid NOT NULL
);
INSERT INTO Tmp_estate_managers ("EstateID", uuid)
SELECT "EstateID", cast(uuid as uuid) FROM estate_managers;
DROP TABLE estate_managers;
Alter table Tmp_estate_managers
rename to estate_managers;
CREATE INDEX IX_estate_managers ON estate_managers
(
"EstateID"
);
COMMIT;
:VERSION 5
BEGIN TRANSACTION;
CREATE TABLE Tmp_estate_groups
(
"EstateID" int NOT NULL,
uuid uuid NOT NULL
) ;
INSERT INTO Tmp_estate_groups ("EstateID", uuid)
SELECT "EstateID", cast(uuid as uuid) FROM estate_groups;
DROP TABLE estate_groups;
Alter table Tmp_estate_groups
rename to estate_groups;
CREATE INDEX IX_estate_groups ON estate_groups
(
"EstateID"
);
COMMIT;
:VERSION 6
BEGIN TRANSACTION;
CREATE TABLE Tmp_estate_users
(
"EstateID" int NOT NULL,
uuid uuid NOT NULL
);
INSERT INTO Tmp_estate_users ("EstateID", uuid)
SELECT "EstateID", cast(uuid as uuid) FROM estate_users ;
DROP TABLE estate_users;
Alter table Tmp_estate_users
rename to estate_users;
CREATE INDEX IX_estate_users ON estate_users
(
"EstateID"
);
COMMIT;
:VERSION 7
BEGIN TRANSACTION;
CREATE TABLE Tmp_estateban
(
"EstateID" int NOT NULL,
"bannedUUID" uuid NOT NULL,
"bannedIp" varchar(16) NULL,
"bannedIpHostMask" varchar(16) NULL,
"bannedNameMask" varchar(64) NULL
);
INSERT INTO Tmp_estateban ("EstateID", "bannedUUID", "bannedIp", "bannedIpHostMask", "bannedNameMask")
SELECT "EstateID", cast("bannedUUID" as uuid), "bannedIp", "bannedIpHostMask", "bannedNameMask" FROM estateban ;
DROP TABLE estateban;
Alter table Tmp_estateban
rename to estateban;
CREATE INDEX IX_estateban ON estateban
(
"EstateID"
);
COMMIT;
:VERSION 8
BEGIN TRANSACTION;
CREATE TABLE Tmp_estate_settings
(
"EstateID" integer default nextval('estate_settings_id') NOT NULL,
"EstateName" varchar(64) NULL DEFAULT (NULL),
"AbuseEmailToEstateOwner" boolean NOT NULL,
"DenyAnonymous" boolean NOT NULL,
"ResetHomeOnTeleport" boolean NOT NULL,
"FixedSun" boolean NOT NULL,
"DenyTransacted" boolean NOT NULL,
"BlockDwell" boolean NOT NULL,
"DenyIdentified" boolean NOT NULL,
"AllowVoice" boolean NOT NULL,
"UseGlobalTime" boolean NOT NULL,
"PricePerMeter" int NOT NULL,
"TaxFree" boolean NOT NULL,
"AllowDirectTeleport" boolean NOT NULL,
"RedirectGridX" int NOT NULL,
"RedirectGridY" int NOT NULL,
"ParentEstateID" int NOT NULL,
"SunPosition" double precision NOT NULL,
"EstateSkipScripts" boolean NOT NULL,
"BillableFactor" double precision NOT NULL,
"PublicAccess" boolean NOT NULL,
"AbuseEmail" varchar(255) NOT NULL,
"EstateOwner" uuid NOT NULL,
"DenyMinors" boolean NOT NULL
);
INSERT INTO Tmp_estate_settings ("EstateID", "EstateName", "AbuseEmailToEstateOwner", "DenyAnonymous", "ResetHomeOnTeleport", "FixedSun", "DenyTransacted", "BlockDwell", "DenyIdentified", "AllowVoice", "UseGlobalTime", "PricePerMeter", "TaxFree", "AllowDirectTeleport", "RedirectGridX", "RedirectGridY", "ParentEstateID", "SunPosition", "EstateSkipScripts", "BillableFactor", "PublicAccess", "AbuseEmail", "EstateOwner", "DenyMinors")
SELECT "EstateID", "EstateName", "AbuseEmailToEstateOwner", "DenyAnonymous", "ResetHomeOnTeleport", "FixedSun", "DenyTransacted", "BlockDwell", "DenyIdentified", "AllowVoice", "UseGlobalTime", "PricePerMeter", "TaxFree", "AllowDirectTeleport", "RedirectGridX", "RedirectGridY", "ParentEstateID", "SunPosition", "EstateSkipScripts", "BillableFactor", "PublicAccess", "AbuseEmail", cast("EstateOwner" as uuid), "DenyMinors" FROM estate_settings ;
DROP TABLE estate_settings;
Alter table Tmp_estate_settings
rename to estate_settings;
Create index on estate_settings (lower("EstateName"));
COMMIT;
:VERSION 9
BEGIN TRANSACTION;
CREATE TABLE Tmp_estate_map
(
"RegionID" uuid NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'),
"EstateID" int NOT NULL
);
INSERT INTO Tmp_estate_map ("RegionID", "EstateID")
SELECT cast("RegionID" as uuid), "EstateID" FROM estate_map ;
DROP TABLE estate_map;
Alter table Tmp_estate_map
rename to estate_map;
COMMIT;
:VERSION 10
BEGIN TRANSACTION;
ALTER TABLE estate_settings ADD COLUMN "AllowLandmark" boolean NOT NULL default true;
ALTER TABLE estate_settings ADD COLUMN "AllowParcelChanges" boolean NOT NULL default true;
ALTER TABLE estate_settings ADD COLUMN "AllowSetHome" boolean NOT NULL default true;
COMMIT;
:VERSION 11
Begin transaction;
Commit;

View File

@@ -0,0 +1,44 @@
:VERSION 1
BEGIN TRANSACTION;
CREATE TABLE Friends (
"PrincipalID" uuid NOT NULL,
"Friend" varchar(255) NOT NULL,
"Flags" char(16) NOT NULL DEFAULT '0',
"Offered" varchar(32) NOT NULL DEFAULT 0);
COMMIT;
:VERSION 2
BEGIN TRANSACTION;
INSERT INTO Friends ("PrincipalID", "Friend", "Flags", "Offered")
SELECT "ownerID", "friendID", "friendPerms", 0 FROM userfriends;
COMMIT;
:VERSION 3
BEGIN TRANSACTION;
CREATE TABLE Tmp_Friends
("PrincipalID" varchar(255) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000',
"Friend" varchar(255) NOT NULL,
"Flags" char(16) NOT NULL DEFAULT '0',
"Offered" varchar(32) NOT NULL DEFAULT 0) ;
INSERT INTO Tmp_Friends ("PrincipalID", "Friend", "Flags", "Offered")
SELECT cast("PrincipalID" as varchar(255)), "Friend", "Flags", "Offered" FROM Friends ;
DROP TABLE Friends;
Alter table Tmp_Friends
rename to Friends;
ALTER TABLE Friends ADD PRIMARY KEY("PrincipalID", "Friend");
COMMIT;

View File

@@ -0,0 +1,242 @@
:VERSION 1
BEGIN TRANSACTION;
CREATE TABLE regions(
"regionHandle" varchar(255) NULL,
"regionName" varchar(255) NULL,
uuid varchar(255) NOT NULL PRIMARY KEY,
"regionRecvKey" varchar(255) NULL,
"regionSecret" varchar(255) NULL,
"regionSendKey" varchar(255) NULL,
"regionDataURI" varchar(255) NULL,
"serverIP" varchar(255) NULL,
"serverPort" varchar(255) NULL,
"serverURI" varchar(255) NULL,
"locX" varchar(255) NULL,
"locY" varchar(255) NULL,
"locZ" varchar(255) NULL,
"eastOverrideHandle" varchar(255) NULL,
"westOverrideHandle" varchar(255) NULL,
"southOverrideHandle" varchar(255) NULL,
"northOverrideHandle" varchar(255) NULL,
"regionAssetURI" varchar(255) NULL,
"regionAssetRecvKey" varchar(255) NULL,
"regionAssetSendKey" varchar(255) NULL,
"regionUserURI" varchar(255) NULL,
"regionUserRecvKey" varchar(255) NULL,
"regionUserSendKey" varchar(255) NULL,
"regionMapTexture" varchar(255) NULL,
"serverHttpPort" varchar(255) NULL,
"serverRemotingPort" varchar(255) NULL,
"owner_uuid" varchar(36) NULL
);
COMMIT;
:VERSION 2
BEGIN TRANSACTION;
CREATE TABLE Tmp_regions
(
uuid varchar(36) NOT NULL,
"regionHandle" bigint NULL,
"regionName" varchar(20) NULL,
"regionRecvKey" varchar(128) NULL,
"regionSendKey" varchar(128) NULL,
"regionSecret" varchar(128) NULL,
"regionDataURI" varchar(128) NULL,
"serverIP" varchar(64) NULL,
"serverPort" int NULL,
"serverURI" varchar(255) NULL,
"locX" int NULL,
"locY" int NULL,
"locZ" int NULL,
"eastOverrideHandle" bigint NULL,
"westOverrideHandle" bigint NULL,
"southOverrideHandle" bigint NULL,
"northOverrideHandle" bigint NULL,
"regionAssetURI" varchar(255) NULL,
"regionAssetRecvKey" varchar(128) NULL,
"regionAssetSendKey" varchar(128) NULL,
"regionUserURI" varchar(255) NULL,
"regionUserRecvKey" varchar(128) NULL,
"regionUserSendKey" varchar(128) NULL,
"regionMapTexture" varchar(36) NULL,
"serverHttpPort" int NULL,
"serverRemotingPort" int NULL,
"owner_uuid" varchar(36) NULL,
"originUUID" varchar(36) NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000')
);
INSERT INTO Tmp_regions (uuid, "regionHandle", "regionName", "regionRecvKey", "regionSendKey", "regionSecret", "regionDataURI", "serverIP", "serverPort", "serverURI", "locX", "locY", "locZ", "eastOverrideHandle", "westOverrideHandle", "southOverrideHandle", "northOverrideHandle", "regionAssetURI", "regionAssetRecvKey", "regionAssetSendKey", "regionUserURI", "regionUserRecvKey", "regionUserSendKey", "regionMapTexture", "serverHttpPort", "serverRemotingPort", "owner_uuid")
SELECT cast(uuid as varchar(36)), cast("regionHandle" as bigint), cast("regionName" as varchar(20)), cast("regionRecvKey" as varchar(128)), cast("regionSendKey" as varchar(128)), cast("regionSecret" as varchar(128)), cast("regionDataURI" as varchar(128)), cast("serverIP" as varchar(64)), cast("serverPort" as int), "serverURI", cast("locX" as int), cast("locY" as int), cast("locZ" as int), cast("eastOverrideHandle" as bigint), cast("westOverrideHandle" as bigint),
cast("southOverrideHandle" as bigint), cast("northOverrideHandle" as bigint), "regionAssetURI", cast("regionAssetRecvKey" as varchar(128)), cast("regionAssetSendKey" as varchar(128)), "regionUserURI", cast("regionUserRecvKey" as varchar(128)), cast("regionUserSendKey" as varchar(128)), cast("regionMapTexture" as varchar(36)),
cast("serverHttpPort" as int), cast("serverRemotingPort" as int), "owner_uuid"
FROM regions;
DROP TABLE regions;
alter table Tmp_regions
rename to regions;
COMMIT;
:VERSION 3
BEGIN TRANSACTION;
CREATE INDEX IX_regions_name ON regions
(
"regionName"
);
CREATE INDEX IX_regions_handle ON regions
(
"regionHandle"
);
CREATE INDEX IX_regions_override ON regions
(
"eastOverrideHandle",
"westOverrideHandle",
"southOverrideHandle",
"northOverrideHandle"
);
COMMIT;
:VERSION 4
/* To prevent any potential data loss issues, you should review this script in detail before running it outside the cotext of the database designer.*/
BEGIN TRANSACTION;
CREATE TABLE Tmp_regions
(
uuid uuid NOT NULL,
"regionHandle" bigint NULL,
"regionName" varchar(20) NULL,
"regionRecvKey" varchar(128) NULL,
"regionSendKey" varchar(128) NULL,
"regionSecret" varchar(128) NULL,
"regionDataURI" varchar(128) NULL,
"serverIP" varchar(64) NULL,
"serverPort" int NULL,
"serverURI" varchar(255) NULL,
"locX" int NULL,
"locY" int NULL,
"locZ" int NULL,
"eastOverrideHandle" bigint NULL,
"westOverrideHandle" bigint NULL,
"southOverrideHandle" bigint NULL,
"northOverrideHandle" bigint NULL,
"regionAssetURI" varchar(255) NULL,
"regionAssetRecvKey" varchar(128) NULL,
"regionAssetSendKey" varchar(128) NULL,
"regionUserURI" varchar(255) NULL,
"regionUserRecvKey" varchar(128) NULL,
"regionUserSendKey" varchar(128) NULL,
"regionMapTexture" uuid NULL,
"serverHttpPort" int NULL,
"serverRemotingPort" int NULL,
"owner_uuid" uuid NOT NULL,
"originUUID" uuid NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000')
);
INSERT INTO Tmp_regions (uuid, "regionHandle", "regionName", "regionRecvKey", "regionSendKey", "regionSecret", "regionDataURI", "serverIP", "serverPort", "serverURI", "locX", "locY", "locZ", "eastOverrideHandle", "westOverrideHandle", "southOverrideHandle", "northOverrideHandle", "regionAssetURI", "regionAssetRecvKey", "regionAssetSendKey", "regionUserURI", "regionUserRecvKey", "regionUserSendKey", "regionMapTexture", "serverHttpPort", "serverRemotingPort", "owner_uuid", "originUUID")
SELECT cast(uuid as uuid), "regionHandle", "regionName", "regionRecvKey", "regionSendKey", "regionSecret", "regionDataURI", "serverIP", "serverPort", "serverURI", "locX", "locY", "locZ", "eastOverrideHandle", "westOverrideHandle", "southOverrideHandle", "northOverrideHandle", "regionAssetURI", "regionAssetRecvKey", "regionAssetSendKey", "regionUserURI", "regionUserRecvKey", "regionUserSendKey", cast("regionMapTexture" as uuid), "serverHttpPort", "serverRemotingPort", cast( "owner_uuid" as uuid), cast("originUUID" as uuid) FROM regions ;
DROP TABLE regions;
alter table Tmp_regions rename to regions;
ALTER TABLE regions ADD CONSTRAINT
PK__regions__uuid PRIMARY KEY
(
uuid
);
CREATE INDEX IX_regions_name ON regions
(
"regionName"
);
CREATE INDEX IX_regions_handle ON regions
(
"regionHandle"
);
CREATE INDEX IX_regions_override ON regions
(
"eastOverrideHandle",
"westOverrideHandle",
"southOverrideHandle",
"northOverrideHandle"
);
COMMIT;
:VERSION 5
BEGIN TRANSACTION;
ALTER TABLE regions ADD access int default 0;
COMMIT;
:VERSION 6
BEGIN TRANSACTION;
ALTER TABLE regions ADD "ScopeID" uuid default '00000000-0000-0000-0000-000000000000';
ALTER TABLE regions alter column "owner_uuid" set DEFAULT ('00000000-0000-0000-0000-000000000000');
ALTER TABLE regions ADD "sizeX" integer not null default 0;
ALTER TABLE regions ADD "sizeY" integer not null default 0;
COMMIT;
:VERSION 7
BEGIN TRANSACTION;
ALTER TABLE regions ADD "flags" integer NOT NULL DEFAULT 0;
CREATE INDEX flags ON regions("flags");
ALTER TABLE regions ADD "last_seen" integer NOT NULL DEFAULT 0;
ALTER TABLE regions ADD "PrincipalID" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000';
ALTER TABLE regions ADD "Token" varchar(255) NOT NULL DEFAULT 0;
COMMIT;
:VERSION 8
BEGIN TRANSACTION;
ALTER TABLE regions ALTER COLUMN "regionName" type VarChar(128) ;
DROP INDEX IX_regions_name;
ALTER TABLE regions ALTER COLUMN "regionName" type VarChar(128),
ALTER COLUMN "regionName" SET NOT NULL;
CREATE INDEX IX_regions_name ON regions
(
"regionName"
);
COMMIT;
:VERSION 9
BEGIN TRANSACTION;
ALTER TABLE regions ADD "parcelMapTexture" uuid NULL;
COMMIT;

View File

@@ -0,0 +1,60 @@
:VERSION 1 # --------------------------
BEGIN TRANSACTION;
CREATE TABLE GridUser (
"UserID" VARCHAR(255) NOT NULL Primary Key,
"HomeRegionID" CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000',
"HomePosition" CHAR(64) NOT NULL DEFAULT '<0,0,0>',
"HomeLookAt" CHAR(64) NOT NULL DEFAULT '<0,0,0>',
"LastRegionID" CHAR(36) NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000',
"LastPosition" CHAR(64) NOT NULL DEFAULT '<0,0,0>',
"LastLookAt" CHAR(64) NOT NULL DEFAULT '<0,0,0>',
"Online" CHAR(5) NOT NULL DEFAULT 'false',
"Login" CHAR(16) NOT NULL DEFAULT '0',
"Logout" CHAR(16) NOT NULL DEFAULT '0'
) ;
COMMIT;
:VERSION 2 # --------------------------
BEGIN TRANSACTION;
CREATE TABLE GridUser_tmp (
"UserID" VARCHAR(255) NOT NULL PRIMARY KEY,
"HomeRegionID" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000',
"HomePosition" CHAR(64) NOT NULL DEFAULT '<0,0,0>',
"HomeLookAt" CHAR(64) NOT NULL DEFAULT '<0,0,0>',
"LastRegionID" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000',
"LastPosition" CHAR(64) NOT NULL DEFAULT '<0,0,0>',
"LastLookAt" CHAR(64) NOT NULL DEFAULT '<0,0,0>',
"Online" CHAR(5) NOT NULL DEFAULT 'false',
"Login" CHAR(16) NOT NULL DEFAULT '0',
"Logout" CHAR(16) NOT NULL DEFAULT '0'
);
COMMIT;
INSERT INTO GridUser_tmp ("UserID"
,"HomeRegionID"
,"HomePosition"
,"HomeLookAt"
,"LastRegionID"
,"LastPosition"
,"LastLookAt"
,"Online"
,"Login"
,"Logout")
SELECT "UserID", cast("HomeRegionID" as uuid), "HomePosition" ,"HomeLookAt" , cast("LastRegionID" as uuid),
"LastPosition"
,"LastLookAt"
,"Online"
,"Login"
,"Logout" FROM GridUser;
DROP TABLE GridUser;
alter table GridUser_tmp rename to GridUser;

View File

@@ -0,0 +1,17 @@
:VERSION 1 # --------------------------
BEGIN;
CREATE TABLE hg_traveling_data (
"SessionID" VARCHAR(36) NOT NULL Primary Key,
"UserID" VARCHAR(36) NOT NULL,
"GridExternalName" VARCHAR(255) NOT NULL DEFAULT '',
"ServiceToken" VARCHAR(255) NOT NULL DEFAULT '',
"ClientIPAddress" VARCHAR(16) NOT NULL DEFAULT '',
"MyIPAddress" VARCHAR(16) NOT NULL DEFAULT '',
"TMStamp" timestamp NOT NULL default now()
);
COMMIT;

View File

@@ -0,0 +1,26 @@
:VERSION 1 # --------------------------
BEGIN Transaction;
Create Sequence im_offiline_id increment by 1 start with 1;
CREATE TABLE im_offline (
"ID" integer PRIMARY KEY NOT NULL DEFAULT nextval('im_offiline_id') ,
"PrincipalID" char(36) NOT NULL default '',
"Message" text NOT NULL,
"TMStamp" timestamp NOT NULL default now()
);
COMMIT;
:VERSION 2 # --------------------------
BEGIN;
/*
INSERT INTO `im_offline` SELECT * from `diva_im_offline`;
DROP TABLE `diva_im_offline`;
DELETE FROM `migrations` WHERE name='diva_im_Store';
*/
COMMIT;

View File

@@ -0,0 +1,220 @@
:VERSION 1
BEGIN TRANSACTION;
CREATE TABLE inventoryfolders (
"folderID" varchar(36) NOT NULL default '' PRIMARY KEY,
"agentID" varchar(36) default NULL,
"parentFolderID" varchar(36) default NULL,
"folderName" varchar(64) default NULL,
"type" smallint NOT NULL default 0,
"version" int NOT NULL default 0
);
CREATE INDEX owner ON inventoryfolders
(
"agentID" ASC
);
CREATE INDEX parent ON inventoryfolders
(
"parentFolderID" ASC
);
CREATE TABLE inventoryitems (
"inventoryID" varchar(36) NOT NULL default '' Primary Key,
"assetID" varchar(36) default NULL,
"assetType" int default NULL,
"parentFolderID" varchar(36) default NULL,
"avatarID" varchar(36) default NULL,
"inventoryName" varchar(64) default NULL,
"inventoryDescription" varchar(128) default NULL,
"inventoryNextPermissions" int default NULL,
"inventoryCurrentPermissions" int default NULL,
"invType" int default NULL,
"creatorID" varchar(36) default NULL,
"inventoryBasePermissions" int NOT NULL default 0,
"inventoryEveryOnePermissions" int NOT NULL default 0,
"salePrice" int default NULL,
"saleType" smallint default NULL,
"creationDate" int default NULL,
"groupID" varchar(36) default NULL,
"groupOwned" boolean default NULL,
"flags" int default NULL
);
CREATE INDEX ii_owner ON inventoryitems
(
"avatarID" ASC
);
CREATE INDEX ii_folder ON inventoryitems
(
"parentFolderID" ASC
);
COMMIT;
:VERSION 2
BEGIN TRANSACTION;
ALTER TABLE inventoryitems ADD "inventoryGroupPermissions" INTEGER NOT NULL default 0;
COMMIT;
:VERSION 3
/* To prevent any potential data loss issues, you should review this script in detail before running it outside the cotext of the database designer.*/
BEGIN TRANSACTION;
CREATE TABLE Tmp_inventoryfolders
(
"folderID" uuid NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'),
"agentID" uuid NULL DEFAULT (NULL),
"parentFolderID" uuid NULL DEFAULT (NULL),
"folderName" varchar(64) NULL DEFAULT (NULL),
"type" smallint NOT NULL DEFAULT ((0)),
"version" int NOT NULL DEFAULT ((0))
);
INSERT INTO Tmp_inventoryfolders ("folderID", "agentID", "parentFolderID", "folderName", type, version)
SELECT cast("folderID" as uuid), cast("agentID" as uuid), cast("parentFolderID" as uuid), "folderName", "type", "version"
FROM inventoryfolders;
DROP TABLE inventoryfolders;
alter table Tmp_inventoryfolders rename to inventoryfolders;
ALTER TABLE inventoryfolders ADD CONSTRAINT
PK__inventor__C2FABFB3173876EA PRIMARY KEY
(
"folderID"
);
CREATE INDEX owner ON inventoryfolders
(
"agentID"
);
CREATE INDEX parent ON inventoryfolders
(
"parentFolderID"
);
COMMIT;
:VERSION 4
BEGIN TRANSACTION;
CREATE TABLE Tmp_inventoryitems
(
"inventoryID" uuid NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'),
"assetID" uuid NULL DEFAULT (NULL),
"assetType" int NULL DEFAULT (NULL),
"parentFolderID" uuid NULL DEFAULT (NULL),
"avatarID" uuid NULL DEFAULT (NULL),
"inventoryName" varchar(64) NULL DEFAULT (NULL),
"inventoryDescription" varchar(128) NULL DEFAULT (NULL),
"inventoryNextPermissions" int NULL DEFAULT (NULL),
"inventoryCurrentPermissions" int NULL DEFAULT (NULL),
"invType" int NULL DEFAULT (NULL),
"creatorID" uuid NULL DEFAULT (NULL),
"inventoryBasePermissions" int NOT NULL DEFAULT ((0)),
"inventoryEveryOnePermissions" int NOT NULL DEFAULT ((0)),
"salePrice" int NULL DEFAULT (NULL),
"SaleType" smallint NULL DEFAULT (NULL),
"creationDate" int NULL DEFAULT (NULL),
"groupID" uuid NULL DEFAULT (NULL),
"groupOwned" boolean NULL DEFAULT (NULL),
"flags" int NULL DEFAULT (NULL),
"inventoryGroupPermissions" int NOT NULL DEFAULT ((0))
);
INSERT INTO Tmp_inventoryitems ("inventoryID", "assetID", "assetType", "parentFolderID", "avatarID", "inventoryName", "inventoryDescription", "inventoryNextPermissions", "inventoryCurrentPermissions", "invType", "creatorID", "inventoryBasePermissions", "inventoryEveryOnePermissions", "salePrice", "SaleType", "creationDate", "groupID", "groupOwned", "flags", "inventoryGroupPermissions")
SELECT cast("inventoryID" as uuid), cast("assetID" as uuid), "assetType", cast("parentFolderID" as uuid), cast("avatarID" as uuid), "inventoryName", "inventoryDescription", "inventoryNextPermissions", "inventoryCurrentPermissions", "invType", cast("creatorID" as uuid), "inventoryBasePermissions", "inventoryEveryOnePermissions", "salePrice", "SaleType", "creationDate", cast("groupID" as uuid), "groupOwned", "flags", "inventoryGroupPermissions"
FROM inventoryitems ;
DROP TABLE inventoryitems;
alter table Tmp_inventoryitems rename to inventoryitems;
ALTER TABLE inventoryitems ADD CONSTRAINT
PK__inventor__C4B7BC2220C1E124 PRIMARY KEY
(
"inventoryID"
);
CREATE INDEX ii2_owner ON inventoryitems
(
"avatarID"
);
CREATE INDEX ii2_folder ON inventoryitems
(
"parentFolderID"
);
COMMIT;
:VERSION 5
BEGIN TRANSACTION;
-- # Restoring defaults:
-- # NOTE: "inventoryID" does NOT need one: it's NOT NULL PK and a unique Guid must be provided every time anyway!
alter table inventoryitems
alter column "inventoryBasePermissions" set default 0;
alter table inventoryitems
alter column "inventoryEveryOnePermissions" set default 0;
alter table inventoryitems
alter column "inventoryGroupPermissions" set default 0 ;
COMMIT ;
:VERSION 7
BEGIN TRANSACTION;
-- # "creatorID" goes back to VARCHAR(36) (???)
alter table inventoryitems
alter column "creatorID" type varchar(36);
COMMIT ;
:VERSION 8
ALTER TABLE inventoryitems
alter column "creatorID" set DEFAULT '00000000-0000-0000-0000-000000000000';
:VERSION 9
BEGIN TRANSACTION;
--# "creatorID" goes up to VARCHAR(255)
alter table inventoryitems
alter column "creatorID" type varchar(255);
Commit;
:VERSION 10
BEGIN TRANSACTION;
Alter table inventoryitems Rename Column "SaleType" to "saleType";
Commit;

View File

@@ -0,0 +1,16 @@
:VERSION 1
BEGIN TRANSACTION;
CREATE TABLE logs (
"logID" int NOT NULL Primary Key,
"target" varchar(36) default NULL,
"server" varchar(64) default NULL,
"method" varchar(64) default NULL,
"arguments" varchar(255) default NULL,
"priority" int default NULL,
"message" text
);
COMMIT;

View File

@@ -0,0 +1,30 @@
:VERSION 1
BEGIN TRANSACTION;
CREATE TABLE Presence (
"UserID" varchar(255) NOT NULL,
"RegionID" uuid NOT NULL,
"SessionID" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000',
"SecureSessionID" uuid NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000'
);
COMMIT;
:VERSION 2
BEGIN TRANSACTION;
CREATE UNIQUE INDEX SessionID ON Presence("SessionID");
CREATE INDEX UserID ON Presence("UserID");
COMMIT;
:VERSION 2
BEGIN TRANSACTION;
ALTER TABLE Presence ADD "LastSeen" Timestamp;
COMMIT;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,51 @@
:VERSION 1
CREATE TABLE UserAccounts (
"PrincipalID" uuid NOT NULL Primary key,
"ScopeID" uuid NOT NULL,
"FirstName" varchar(64) NOT NULL,
"LastName" varchar(64) NOT NULL,
"Email" varchar(64) NULL,
"ServiceURLs" text NULL,
"Created" int default NULL
);
:VERSION 2
BEGIN TRANSACTION;
INSERT INTO UserAccounts ("PrincipalID", "ScopeID", "FirstName", "LastName", "Email", "ServiceURLs", "Created")
SELECT UUID AS "PrincipalID", '00000000-0000-0000-0000-000000000000' AS "ScopeID",
username AS "FirstName",
lastname AS "LastName",
email as "Email", (
'AssetServerURI=' +
userAssetURI + ' InventoryServerURI=' + userInventoryURI + ' GatewayURI= HomeURI=') AS "ServiceURLs",
created as "Created" FROM users;
COMMIT;
:VERSION 3
BEGIN TRANSACTION;
CREATE UNIQUE INDEX "PrincipalID" ON UserAccounts("PrincipalID");
CREATE INDEX "Email" ON UserAccounts("Email");
CREATE INDEX "FirstName" ON UserAccounts("FirstName");
CREATE INDEX "LastName" ON UserAccounts("LastName");
CREATE INDEX Name ON UserAccounts("FirstName","LastName");
COMMIT;
:VERSION 4
BEGIN TRANSACTION;
ALTER TABLE UserAccounts ADD "UserLevel" integer NOT NULL DEFAULT 0;
ALTER TABLE UserAccounts ADD "UserFlags" integer NOT NULL DEFAULT 0;
ALTER TABLE UserAccounts ADD "UserTitle" varchar(64) NOT NULL DEFAULT '';
COMMIT;

View File

@@ -0,0 +1,83 @@
:VERSION 1 # -------------------------------
begin;
CREATE TABLE classifieds (
"classifieduuid" char(36) NOT NULL,
"creatoruuid" char(36) NOT NULL,
"creationdate" integer NOT NULL,
"expirationdate" integer NOT NULL,
"category" varchar(20) NOT NULL,
"name" varchar(255) NOT NULL,
"description" text NOT NULL,
"parceluuid" char(36) NOT NULL,
"parentestate" integer NOT NULL,
"snapshotuuid" char(36) NOT NULL,
"simname" varchar(255) NOT NULL,
"posglobal" varchar(255) NOT NULL,
"parcelname" varchar(255) NOT NULL,
"classifiedflags" integer NOT NULL,
"priceforlisting" integer NOT NULL,
constraint classifiedspk PRIMARY KEY ("classifieduuid")
);
CREATE TABLE usernotes (
"useruuid" varchar(36) NOT NULL,
"targetuuid" varchar(36) NOT NULL,
"notes" text NOT NULL,
constraint usernoteuk UNIQUE ("useruuid","targetuuid")
);
CREATE TABLE userpicks (
"pickuuid" varchar(36) NOT NULL,
"creatoruuid" varchar(36) NOT NULL,
"toppick" boolean NOT NULL,
"parceluuid" varchar(36) NOT NULL,
"name" varchar(255) NOT NULL,
"description" text NOT NULL,
"snapshotuuid" varchar(36) NOT NULL,
"user" varchar(255) NOT NULL,
"originalname" varchar(255) NOT NULL,
"simname" varchar(255) NOT NULL,
"posglobal" varchar(255) NOT NULL,
"sortorder" integer NOT NULL,
"enabled" boolean NOT NULL,
PRIMARY KEY ("pickuuid")
);
CREATE TABLE userprofile (
"useruuid" varchar(36) NOT NULL,
"profilePartner" varchar(36) NOT NULL,
"profileAllowPublish" bytea NOT NULL,
"profileMaturePublish" bytea NOT NULL,
"profileURL" varchar(255) NOT NULL,
"profileWantToMask" integer NOT NULL,
"profileWantToText" text NOT NULL,
"profileSkillsMask" integer NOT NULL,
"profileSkillsText" text NOT NULL,
"profileLanguages" text NOT NULL,
"profileImage" varchar(36) NOT NULL,
"profileAboutText" text NOT NULL,
"profileFirstImage" varchar(36) NOT NULL,
"profileFirstText" text NOT NULL,
PRIMARY KEY ("useruuid")
);
commit;
:VERSION 2 # -------------------------------
begin;
CREATE TABLE userdata (
"UserId" char(36) NOT NULL,
"TagId" varchar(64) NOT NULL,
"DataKey" varchar(255),
"DataVal" varchar(255),
PRIMARY KEY ("UserId","TagId")
);
commit;

View File

@@ -0,0 +1,404 @@
:VERSION 1
CREATE TABLE users (
"UUID" varchar(36) NOT NULL default '' Primary Key,
"username" varchar(32) NOT NULL,
"lastname" varchar(32) NOT NULL,
"passwordHash" varchar(32) NOT NULL,
"passwordSalt" varchar(32) NOT NULL,
"homeRegion" bigint default NULL,
"homeLocationX" double precision default NULL,
"homeLocationY" double precision default NULL,
"homeLocationZ" double precision default NULL,
"homeLookAtX" double precision default NULL,
"homeLookAtY" double precision default NULL,
"homeLookAtZ" double precision default NULL,
"created" int NOT NULL,
"lastLogin" int NOT NULL,
"userInventoryURI" varchar(255) default NULL,
"userAssetURI" varchar(255) default NULL,
"profileCanDoMask" int default NULL,
"profileWantDoMask" int default NULL,
"profileAboutText" text,
"profileFirstText" text,
"profileImage" varchar(36) default NULL,
"profileFirstImage" varchar(36) default NULL,
"webLoginKey" varchar(36) default NULL
);
CREATE INDEX "usernames" ON users
(
"username" ASC,
"lastname" ASC
);
CREATE TABLE agents (
"UUID" varchar(36) NOT NULL Primary Key,
"sessionID" varchar(36) NOT NULL,
"secureSessionID" varchar(36) NOT NULL,
"agentIP" varchar(16) NOT NULL,
"agentPort" int NOT NULL,
"agentOnline" smallint NOT NULL,
"loginTime" int NOT NULL,
"logoutTime" int NOT NULL,
"currentRegion" varchar(36) NOT NULL,
"currentHandle" bigint NOT NULL,
"currentPos" varchar(64) NOT NULL
);
CREATE INDEX session ON agents
(
"sessionID" ASC
);
CREATE INDEX ssession ON agents
(
"secureSessionID" ASC
);
CREATE TABLE userfriends(
"ownerID" varchar(50) NOT NULL,
"friendID" varchar(50) NOT NULL,
"friendPerms" varchar(50) NOT NULL,
"datetimestamp" varchar(50) NOT NULL
);
CREATE TABLE avatarappearance (
"Owner" varchar(36) NOT NULL primary key,
"Serial" int NOT NULL,
"Visual_Params" bytea NOT NULL,
"Texture" bytea NOT NULL,
"Avatar_Height" double precision NOT NULL,
"Body_Item" varchar(36) NOT NULL,
"Body_Asset" varchar(36) NOT NULL,
"Skin_Item" varchar(36) NOT NULL,
"Skin_Asset" varchar(36) NOT NULL,
"Hair_Item" varchar(36) NOT NULL,
"Hair_Asset" varchar(36) NOT NULL,
"Eyes_Item" varchar(36) NOT NULL,
"Eyes_Asset" varchar(36) NOT NULL,
"Shirt_Item" varchar(36) NOT NULL,
"Shirt_Asset" varchar(36) NOT NULL,
"Pants_Item" varchar(36) NOT NULL,
"Pants_Asset" varchar(36) NOT NULL,
"Shoes_Item" varchar(36) NOT NULL,
"Shoes_Asset" varchar(36) NOT NULL,
"Socks_Item" varchar(36) NOT NULL,
"Socks_Asset" varchar(36) NOT NULL,
"Jacket_Item" varchar(36) NOT NULL,
"Jacket_Asset" varchar(36) NOT NULL,
"Gloves_Item" varchar(36) NOT NULL,
"Gloves_Asset" varchar(36) NOT NULL,
"Undershirt_Item" varchar(36) NOT NULL,
"Undershirt_Asset" varchar(36) NOT NULL,
"Underpants_Item" varchar(36) NOT NULL,
"Underpants_Asset" varchar(36) NOT NULL,
"Skirt_Item" varchar(36) NOT NULL,
"Skirt_Asset" varchar(36) NOT NULL
);
:VERSION 2
BEGIN TRANSACTION;
ALTER TABLE users ADD "homeRegionID" varchar(36) NOT NULL default '00000000-0000-0000-0000-000000000000';
ALTER TABLE users ADD "userFlags" int NOT NULL default 0;
ALTER TABLE users ADD "godLevel" int NOT NULL default 0;
ALTER TABLE users ADD "customType" varchar(32) not null default '';
ALTER TABLE users ADD "partner" varchar(36) not null default '00000000-0000-0000-0000-000000000000';
COMMIT;
:VERSION 3
BEGIN TRANSACTION;
CREATE TABLE avatarattachments (
"UUID" varchar(36) NOT NULL
, "attachpoint" int NOT NULL
, item varchar(36) NOT NULL
, asset varchar(36) NOT NULL);
CREATE INDEX IX_avatarattachments ON avatarattachments
(
"UUID"
);
COMMIT;
:VERSION 4
BEGIN TRANSACTION;
CREATE TABLE Tmp_userfriends
(
"ownerID" varchar(36) NOT NULL,
"friendID" varchar(36) NOT NULL,
"friendPerms" int NOT NULL,
"datetimestamp" int NOT NULL
);
INSERT INTO Tmp_userfriends ("ownerID", "friendID", "friendPerms", "datetimestamp")
SELECT cast("ownerID" as varchar(36)), cast("friendID" as varchar(36)), cast("friendPerms" as int), cast("datetimestamp" as int)
FROM userfriends;
DROP TABLE userfriends;
alter table Tmp_userfriends rename to userfriends;
CREATE INDEX IX_userfriends_ownerID ON userfriends
(
"ownerID"
);
CREATE INDEX IX_userfriends_friendID ON userfriends
(
"friendID"
);
COMMIT;
:VERSION 5
BEGIN TRANSACTION;
ALTER TABLE users add "email" varchar(250);
COMMIT;
:VERSION 6
BEGIN TRANSACTION;
CREATE TABLE Tmp_users
(
"UUID" uuid NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'),
"username" varchar(32) NOT NULL,
"lastname" varchar(32) NOT NULL,
"passwordHash" varchar(32) NOT NULL,
"passwordSalt" varchar(32) NOT NULL,
"homeRegion" bigint NULL DEFAULT (NULL),
"homeLocationX" double precision NULL DEFAULT (NULL),
"homeLocationY" double precision NULL DEFAULT (NULL),
"homeLocationZ" double precision NULL DEFAULT (NULL),
"homeLookAtX" double precision NULL DEFAULT (NULL),
"homeLookAtY" double precision NULL DEFAULT (NULL),
"homeLookAtZ" double precision NULL DEFAULT (NULL),
"created" int NOT NULL,
"lastLogin" int NOT NULL,
"userInventoryURI" varchar(255) NULL DEFAULT (NULL),
"userAssetURI" varchar(255) NULL DEFAULT (NULL),
"profileCanDoMask" int NULL DEFAULT (NULL),
"profileWantDoMask" int NULL DEFAULT (NULL),
"profileAboutText" text NULL,
"profileFirstText" text NULL,
"profileImage" uuid NULL DEFAULT (NULL),
"profileFirstImage" uuid NULL DEFAULT (NULL),
"webLoginKey" uuid NULL DEFAULT (NULL),
"homeRegionID" uuid NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'),
"userFlags" int NOT NULL DEFAULT ((0)),
"godLevel" int NOT NULL DEFAULT ((0)),
"customType" varchar(32) NOT NULL DEFAULT (''),
"partner" uuid NOT NULL DEFAULT ('00000000-0000-0000-0000-000000000000'),
email varchar(250) NULL
);
INSERT INTO Tmp_users ("UUID", "username", "lastname", "passwordHash", "passwordSalt", "homeRegion", "homeLocationX", "homeLocationY", "homeLocationZ", "homeLookAtX", "homeLookAtY", "homeLookAtZ", "created", "lastLogin", "userInventoryURI", "userAssetURI", "profileCanDoMask", "profileWantDoMask", "profileAboutText", "profileFirstText", "profileImage", "profileFirstImage", "webLoginKey", "homeRegionID", "userFlags", "godLevel", "customType", "partner", email)
SELECT cast("UUID" as uuid), "username", "lastname", "passwordHash", "passwordSalt", "homeRegion", "homeLocationX", "homeLocationY", "homeLocationZ", "homeLookAtX", "homeLookAtY", "homeLookAtZ", "created", "lastLogin", "userInventoryURI", "userAssetURI", "profileCanDoMask", "profileWantDoMask", "profileAboutText", "profileFirstText", cast("profileImage" as uuid), cast("profileFirstImage" as uuid), cast("webLoginKey" as uuid), cast("homeRegionID" as uuid), "userFlags", "godLevel", "customType", cast("partner" as uuid), email
FROM users ;
DROP TABLE users;
alter table Tmp_users rename to users;
ALTER TABLE users ADD CONSTRAINT
PK__users__65A475E737A5467C PRIMARY KEY
(
"UUID"
);
CREATE INDEX "usernames" ON users
(
"username",
"lastname"
);
COMMIT;
:VERSION 7
BEGIN TRANSACTION;
CREATE TABLE Tmp_agents
(
"UUID" uuid NOT NULL,
"sessionID" uuid NOT NULL,
"secureSessionID" uuid NOT NULL,
"agentIP" varchar(16) NOT NULL,
"agentPort" int NOT NULL,
"agentOnline" smallint NOT NULL,
"loginTime" int NOT NULL,
"logoutTime" int NOT NULL,
"currentRegion" uuid NOT NULL,
"currentHandle" bigint NOT NULL,
"currentPos" varchar(64) NOT NULL
);
INSERT INTO Tmp_agents ("UUID", "sessionID", "secureSessionID", "agentIP", "agentPort", "agentOnline", "loginTime", "logoutTime", "currentRegion", "currentHandle", "currentPos")
SELECT cast("UUID" as uuid), cast("sessionID" as uuid), cast("secureSessionID" as uuid), "agentIP", "agentPort", "agentOnline", "loginTime", "logoutTime", cast("currentRegion" as uuid), "currentHandle", "currentPos"
FROM agents ;
DROP TABLE agents;
alter table Tmp_agents rename to agents;
ALTER TABLE agents ADD CONSTRAINT
PK__agents__65A475E749C3F6B7 PRIMARY KEY
(
"UUID"
) ;
CREATE INDEX session ON agents
(
"sessionID"
);
CREATE INDEX ssession ON agents
(
"secureSessionID"
);
COMMIT;
:VERSION 8
BEGIN TRANSACTION;
CREATE TABLE Tmp_userfriends
(
"ownerID" uuid NOT NULL,
"friendID" uuid NOT NULL,
"friendPerms" int NOT NULL,
"datetimestamp" int NOT NULL
);
INSERT INTO Tmp_userfriends ("ownerID", "friendID", "friendPerms", "datetimestamp")
SELECT cast("ownerID" as uuid), cast( "friendID" as uuid), "friendPerms", "datetimestamp"
FROM userfriends;
DROP TABLE userfriends;
alter table Tmp_userfriends rename to userfriends;
CREATE INDEX IX_userfriends_ownerID ON userfriends
(
"ownerID"
);
CREATE INDEX IX_userfriends_friendID ON userfriends
(
"friendID"
);
COMMIT;
:VERSION 9
BEGIN TRANSACTION;
CREATE TABLE Tmp_avatarappearance
(
"Owner" uuid NOT NULL,
"Serial" int NOT NULL,
"Visual_Params" bytea NOT NULL,
"Texture" bytea NOT NULL,
"Avatar_Height" double precision NOT NULL,
"Body_Item" uuid NOT NULL,
"Body_Asset" uuid NOT NULL,
"Skin_Item" uuid NOT NULL,
"Skin_Asset" uuid NOT NULL,
"Hair_Item" uuid NOT NULL,
"Hair_Asset" uuid NOT NULL,
"Eyes_Item" uuid NOT NULL,
"Eyes_Asset" uuid NOT NULL,
"Shirt_Item" uuid NOT NULL,
"Shirt_Asset" uuid NOT NULL,
"Pants_Item" uuid NOT NULL,
"Pants_Asset" uuid NOT NULL,
"Shoes_Item" uuid NOT NULL,
"Shoes_Asset" uuid NOT NULL,
"Socks_Item" uuid NOT NULL,
"Socks_Asset" uuid NOT NULL,
"Jacket_Item" uuid NOT NULL,
"Jacket_Asset" uuid NOT NULL,
"Gloves_Item" uuid NOT NULL,
"Gloves_Asset" uuid NOT NULL,
"Undershirt_Item" uuid NOT NULL,
"Undershirt_Asset" uuid NOT NULL,
"Underpants_Item" uuid NOT NULL,
"Underpants_Asset" uuid NOT NULL,
"Skirt_Item" uuid NOT NULL,
"Skirt_Asset" uuid NOT NULL
);
INSERT INTO Tmp_avatarappearance ("Owner", "Serial", "Visual_Params", "Texture", "Avatar_Height", "Body_Item", "Body_Asset", "Skin_Item", "Skin_Asset", "Hair_Item", "Hair_Asset", "Eyes_Item", "Eyes_Asset", "Shirt_Item", "Shirt_Asset", "Pants_Item", "Pants_Asset", "Shoes_Item", "Shoes_Asset", "Socks_Item", "Socks_Asset", "Jacket_Item", "Jacket_Asset", "Gloves_Item", "Gloves_Asset", "Undershirt_Item", "Undershirt_Asset", "Underpants_Item", "Underpants_Asset", "Skirt_Item", "Skirt_Asset")
SELECT cast("Owner" as uuid), "Serial", "Visual_Params", "Texture", "Avatar_Height", cast("Body_Item" as uuid), cast("Body_Asset" as uuid), cast("Skin_Item" as uuid), cast("Skin_Asset" as uuid), cast("Hair_Item" as uuid), cast("Hair_Asset" as uuid), cast("Eyes_Item" as uuid), cast("Eyes_Asset" as uuid), cast("Shirt_Item" as uuid), cast("Shirt_Asset" as uuid), cast("Pants_Item" as uuid), cast("Pants_Asset" as uuid), cast("Shoes_Item" as uuid), cast("Shoes_Asset" as uuid), cast("Socks_Item" as uuid), cast("Socks_Asset" as uuid), cast("Jacket_Item" as uuid), cast("Jacket_Asset" as uuid), cast("Gloves_Item" as uuid), cast("Gloves_Asset" as uuid), cast("Undershirt_Item" as uuid), cast("Undershirt_Asset" as uuid), cast("Underpants_Item" as uuid), cast("Underpants_Asset" as uuid), cast("Skirt_Item" as uuid), cast("Skirt_Asset" as uuid)
FROM avatarappearance ;
DROP TABLE avatarappearance;
alter table Tmp_avatarappearance rename to avatarappearance;
ALTER TABLE avatarappearance ADD CONSTRAINT
PK__avatarap__7DD115CC4E88ABD4 PRIMARY KEY
(
"Owner"
);
COMMIT;
:VERSION 10
BEGIN TRANSACTION;
CREATE TABLE Tmp_avatarattachments
(
"UUID" uuid NOT NULL,
"attachpoint" int NOT NULL,
item uuid NOT NULL,
asset uuid NOT NULL
);
INSERT INTO Tmp_avatarattachments ("UUID", "attachpoint", item, asset)
SELECT cast("UUID" as uuid), "attachpoint", cast(item as uuid), cast(asset as uuid)
FROM avatarattachments ;
DROP TABLE avatarattachments;
alter table Tmp_avatarattachments rename to avatarattachments;
CREATE INDEX IX_avatarattachments ON avatarattachments
(
"UUID"
);
COMMIT;
:VERSION 11
BEGIN TRANSACTION;
ALTER TABLE users ADD "scopeID" uuid not null default '00000000-0000-0000-0000-000000000000';
COMMIT;

View File

@@ -0,0 +1,27 @@
# -----------------
:VERSION 1
BEGIN;
CREATE TABLE XAssetsMeta (
"ID" char(36) NOT NULL,
"Hash" char(32) NOT NULL,
"Name" varchar(64) NOT NULL,
"Description" varchar(64) NOT NULL,
"AssetType" smallint NOT NULL,
"Local" smallint NOT NULL,
"Temporary" smallint NOT NULL,
"CreateTime" integer NOT NULL,
"AccessTime" integer NOT NULL,
"AssetFlags" integer NOT NULL,
"CreatorID" varchar(128) NOT NULL,
PRIMARY KEY ("ID")
);
CREATE TABLE XAssetsData (
"Hash" char(32) NOT NULL,
"Data" bytea NOT NULL,
PRIMARY KEY ("Hash")
);
COMMIT;

View File

@@ -0,0 +1,94 @@
:VERSION 1 # --------------------------
BEGIN;
CREATE TABLE os_groups_groups (
"GroupID" char(36) Primary Key NOT NULL default '',
"Location" varchar(255) NOT NULL default '',
"Name" varchar(255) NOT NULL default '',
"Charter" text NOT NULL,
"InsigniaID" char(36) NOT NULL default '',
"FounderID" char(36) NOT NULL default '',
"MembershipFee" integer NOT NULL default '0',
"OpenEnrollment" varchar(255) NOT NULL default '',
"ShowInList" integer NOT NULL default '0',
"AllowPublish" integer NOT NULL default '0',
"MaturePublish" integer NOT NULL default '0',
"OwnerRoleID" char(36) NOT NULL default ''
);
CREATE TABLE os_groups_membership (
"GroupID"char(36) NOT NULL default '',
"PrincipalID" VARCHAR(255) NOT NULL default '',
"SelectedRoleID" char(36) NOT NULL default '',
"Contribution" integer NOT NULL default '0',
"ListInProfile" integer NOT NULL default '1',
"AcceptNotices" integer NOT NULL default '1',
"AccessToken" char(36) NOT NULL default '',
constraint os_groupmemberpk primary key ("GroupID", "PrincipalID")
);
CREATE TABLE os_groups_roles (
"GroupID" char(36) NOT NULL default '',
"RoleID" char(36) NOT NULL default '',
"Name" varchar(255) NOT NULL default '',
"Description" varchar(255) NOT NULL default '',
"Title" varchar(255) NOT NULL default '',
"Powers" bigint NOT NULL default 0,
constraint os_grouprolepk PRIMARY KEY ("GroupID","RoleID")
);
CREATE TABLE os_groups_rolemembership (
"GroupID" char(36) NOT NULL default '',
"RoleID" char(36) NOT NULL default '',
"PrincipalID" VARCHAR(255) NOT NULL default '',
constraint os_grouprolememberpk PRIMARY KEY ("GroupID","RoleID","PrincipalID")
);
CREATE TABLE os_groups_invites (
"InviteID" char(36) NOT NULL default '',
"GroupID" char(36) NOT NULL default '',
"RoleID" char(36) NOT NULL default '',
"PrincipalID" VARCHAR(255) NOT NULL default '',
"TMStamp" timestamp NOT NULL default now(),
constraint os_groupinvitespk PRIMARY KEY ("InviteID")
);
-- UNIQUE KEY "PrincipalGroup" ("GroupID","PrincipalID")
CREATE TABLE os_groups_notices (
"GroupID" char(36) NOT NULL default '',
"NoticeID" char(36) NOT NULL default '',
"TMStamp" integer NOT NULL default '0',
"FromName" varchar(255) NOT NULL default '',
"Subject" varchar(255) NOT NULL default '',
"Message" text NOT NULL,
"HasAttachment" integer NOT NULL default '0',
"AttachmentType" integer NOT NULL default '0',
"AttachmentName" varchar(128) NOT NULL default '',
"AttachmentItemID" char(36) NOT NULL default '',
"AttachmentOwnerID" varchar(255) NOT NULL default '',
constraint os_groupsnoticespk PRIMARY KEY ("NoticeID")
);
-- KEY "GroupID" ("GroupID"),
-- KEY "TMStamp" ("TMStamp")
CREATE TABLE os_groups_principals (
"PrincipalID" VARCHAR(255) NOT NULL default '',
"ActiveGroupID" char(36) NOT NULL default '',
constraint os_groupprincpk PRIMARY KEY ("PrincipalID")
);
COMMIT;
:VERSION 2 # --------------------------
BEGIN;
COMMIT;

View File

@@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly : AssemblyVersion("0.7.6.*")]
[assembly : AssemblyVersion("0.8.0.*")]

View File

@@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly : AssemblyVersion("0.7.6.*")]
[assembly : AssemblyVersion("0.8.0.*")]

View File

@@ -600,3 +600,15 @@ BEGIN;
ALTER TABLE prims ADD COLUMN `KeyframeMotion` blob;
COMMIT;
:VERSION 30 #---------------- Save Attachment info
BEGIN;
ALTER TABLE prims ADD COLUMN AttachedPosX double default '0';
ALTER TABLE prims ADD COLUMN AttachedPosY double default '0';
ALTER TABLE prims ADD COLUMN AttachedPosZ double default '0';
ALTER TABLE primshapes ADD COLUMN LastAttachPoint int not null default '0';
COMMIT;

View File

@@ -1236,6 +1236,10 @@ namespace OpenSim.Data.SQLite
createCol(prims, "MediaURL", typeof(String));
createCol(prims, "AttachedPosX", typeof(Double));
createCol(prims, "AttachedPosY", typeof(Double));
createCol(prims, "AttachedPosZ", typeof(Double));
createCol(prims, "DynAttrs", typeof(String));
createCol(prims, "PhysicsShapeType", typeof(Byte));
@@ -1724,6 +1728,12 @@ namespace OpenSim.Data.SQLite
prim.MediaUrl = (string)row["MediaURL"];
}
prim.AttachedPos = new Vector3(
Convert.ToSingle(row["AttachedPosX"]),
Convert.ToSingle(row["AttachedPosY"]),
Convert.ToSingle(row["AttachedPosZ"])
);
if (!(row["DynAttrs"] is System.DBNull))
{
//m_log.DebugFormat("[SQLITE]: DynAttrs type [{0}]", row["DynAttrs"].GetType());
@@ -2176,6 +2186,10 @@ namespace OpenSim.Data.SQLite
row["MediaURL"] = prim.MediaUrl;
row["AttachedPosX"] = prim.AttachedPos.X;
row["AttachedPosY"] = prim.AttachedPos.Y;
row["AttachedPosZ"] = prim.AttachedPos.Z;
if (prim.DynAttrs.CountNamespaces > 0)
row["DynAttrs"] = prim.DynAttrs.ToXml();
else
@@ -2444,6 +2458,7 @@ namespace OpenSim.Data.SQLite
s.ProfileCurve = Convert.ToByte(row["ProfileCurve"]);
s.ProfileHollow = Convert.ToUInt16(row["ProfileHollow"]);
s.State = Convert.ToByte(row["State"]);
s.LastAttachPoint = Convert.ToByte(row["LastAttachPoint"]);
byte[] textureEntry = (byte[])row["Texture"];
s.TextureEntry = textureEntry;
@@ -2493,6 +2508,7 @@ namespace OpenSim.Data.SQLite
row["ProfileCurve"] = s.ProfileCurve;
row["ProfileHollow"] = s.ProfileHollow;
row["State"] = s.State;
row["LastAttachPoint"] = s.LastAttachPoint;
row["Texture"] = s.TextureEntry;
row["ExtraParams"] = s.ExtraParams;

View File

@@ -59,4 +59,4 @@ using System.Runtime.InteropServices;
// Revision
//
[assembly : AssemblyVersion("0.7.6.*")]
[assembly : AssemblyVersion("0.8.0.*")]

View File

@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
[assembly: AssemblyVersion("0.7.6.*")]
[assembly: AssemblyVersion("0.8.0.*")]

View File

@@ -0,0 +1,275 @@
/*
* 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;
namespace OpenSim.Framework
{
public class BasicDOSProtector
{
public enum ThrottleAction
{
DoThrottledMethod,
DoThrow
}
private readonly CircularBuffer<int> _generalRequestTimes; // General request checker
private readonly BasicDosProtectorOptions _options;
private readonly Dictionary<string, CircularBuffer<int>> _deeperInspection; // per client request checker
private readonly Dictionary<string, int> _tempBlocked; // blocked list
private readonly Dictionary<string, int> _sessions;
private readonly System.Timers.Timer _forgetTimer; // Cleanup timer
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
private readonly System.Threading.ReaderWriterLockSlim _blockLockSlim = new System.Threading.ReaderWriterLockSlim();
private readonly System.Threading.ReaderWriterLockSlim _sessionLockSlim = new System.Threading.ReaderWriterLockSlim();
public BasicDOSProtector(BasicDosProtectorOptions options)
{
_generalRequestTimes = new CircularBuffer<int>(options.MaxRequestsInTimeframe + 1, true);
_generalRequestTimes.Put(0);
_options = options;
_deeperInspection = new Dictionary<string, CircularBuffer<int>>();
_tempBlocked = new Dictionary<string, int>();
_sessions = new Dictionary<string, int>();
_forgetTimer = new System.Timers.Timer();
_forgetTimer.Elapsed += delegate
{
_forgetTimer.Enabled = false;
List<string> removes = new List<string>();
_blockLockSlim.EnterReadLock();
foreach (string str in _tempBlocked.Keys)
{
if (
Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(),
_tempBlocked[str]) > 0)
removes.Add(str);
}
_blockLockSlim.ExitReadLock();
lock (_deeperInspection)
{
_blockLockSlim.EnterWriteLock();
for (int i = 0; i < removes.Count; i++)
{
_tempBlocked.Remove(removes[i]);
_deeperInspection.Remove(removes[i]);
_sessions.Remove(removes[i]);
}
_blockLockSlim.ExitWriteLock();
}
foreach (string str in removes)
{
m_log.InfoFormat("[{0}] client: {1} is no longer blocked.",
_options.ReportingName, str);
}
_blockLockSlim.EnterReadLock();
if (_tempBlocked.Count > 0)
_forgetTimer.Enabled = true;
_blockLockSlim.ExitReadLock();
};
_forgetTimer.Interval = _options.ForgetTimeSpan.TotalMilliseconds;
}
/// <summary>
/// Given a string Key, Returns if that context is blocked
/// </summary>
/// <param name="key">A Key identifying the context</param>
/// <returns>bool Yes or No, True or False for blocked</returns>
public bool IsBlocked(string key)
{
bool ret = false;
_blockLockSlim.EnterReadLock();
ret = _tempBlocked.ContainsKey(key);
_blockLockSlim.ExitReadLock();
return ret;
}
/// <summary>
/// Process the velocity of this context
/// </summary>
/// <param name="key"></param>
/// <param name="endpoint"></param>
/// <returns></returns>
public bool Process(string key, string endpoint)
{
if (_options.MaxRequestsInTimeframe < 1 || _options.RequestTimeSpan.TotalMilliseconds < 1)
return true;
string clientstring = key;
_blockLockSlim.EnterReadLock();
if (_tempBlocked.ContainsKey(clientstring))
{
_blockLockSlim.ExitReadLock();
if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod)
return false;
else
throw new System.Security.SecurityException("Throttled");
}
_blockLockSlim.ExitReadLock();
lock (_generalRequestTimes)
_generalRequestTimes.Put(Util.EnvironmentTickCount());
if (_options.MaxConcurrentSessions > 0)
{
int sessionscount = 0;
_sessionLockSlim.EnterReadLock();
if (_sessions.ContainsKey(key))
sessionscount = _sessions[key];
_sessionLockSlim.ExitReadLock();
if (sessionscount > _options.MaxConcurrentSessions)
{
// Add to blocking and cleanup methods
lock (_deeperInspection)
{
_blockLockSlim.EnterWriteLock();
if (!_tempBlocked.ContainsKey(clientstring))
{
_tempBlocked.Add(clientstring,
Util.EnvironmentTickCount() +
(int) _options.ForgetTimeSpan.TotalMilliseconds);
_forgetTimer.Enabled = true;
m_log.WarnFormat("[{0}]: client: {1} is blocked for {2} milliseconds based on concurrency, X-ForwardedForAllowed status is {3}, endpoint:{4}", _options.ReportingName, clientstring, _options.ForgetTimeSpan.TotalMilliseconds, _options.AllowXForwardedFor, endpoint);
}
else
_tempBlocked[clientstring] = Util.EnvironmentTickCount() +
(int) _options.ForgetTimeSpan.TotalMilliseconds;
_blockLockSlim.ExitWriteLock();
}
}
else
ProcessConcurrency(key, endpoint);
}
if (_generalRequestTimes.Size == _generalRequestTimes.Capacity &&
(Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _generalRequestTimes.Get()) <
_options.RequestTimeSpan.TotalMilliseconds))
{
//Trigger deeper inspection
if (DeeperInspection(key, endpoint))
return true;
if (_options.ThrottledAction == ThrottleAction.DoThrottledMethod)
return false;
else
throw new System.Security.SecurityException("Throttled");
}
return true;
}
private void ProcessConcurrency(string key, string endpoint)
{
_sessionLockSlim.EnterWriteLock();
if (_sessions.ContainsKey(key))
_sessions[key] = _sessions[key] + 1;
else
_sessions.Add(key,1);
_sessionLockSlim.ExitWriteLock();
}
public void ProcessEnd(string key, string endpoint)
{
_sessionLockSlim.EnterWriteLock();
if (_sessions.ContainsKey(key))
{
_sessions[key]--;
if (_sessions[key] <= 0)
_sessions.Remove(key);
}
else
_sessions.Add(key, 1);
_sessionLockSlim.ExitWriteLock();
}
/// <summary>
/// At this point, the rate limiting code needs to track 'per user' velocity.
/// </summary>
/// <param name="key">Context Key, string representing a rate limiting context</param>
/// <param name="endpoint"></param>
/// <returns></returns>
private bool DeeperInspection(string key, string endpoint)
{
lock (_deeperInspection)
{
string clientstring = key;
if (_deeperInspection.ContainsKey(clientstring))
{
_deeperInspection[clientstring].Put(Util.EnvironmentTickCount());
if (_deeperInspection[clientstring].Size == _deeperInspection[clientstring].Capacity &&
(Util.EnvironmentTickCountSubtract(Util.EnvironmentTickCount(), _deeperInspection[clientstring].Get()) <
_options.RequestTimeSpan.TotalMilliseconds))
{
//Looks like we're over the limit
_blockLockSlim.EnterWriteLock();
if (!_tempBlocked.ContainsKey(clientstring))
_tempBlocked.Add(clientstring, Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds);
else
_tempBlocked[clientstring] = Util.EnvironmentTickCount() + (int)_options.ForgetTimeSpan.TotalMilliseconds;
_blockLockSlim.ExitWriteLock();
m_log.WarnFormat("[{0}]: client: {1} is blocked for {2} milliseconds, X-ForwardedForAllowed status is {3}, endpoint:{4}", _options.ReportingName, clientstring, _options.ForgetTimeSpan.TotalMilliseconds, _options.AllowXForwardedFor, endpoint);
return false;
}
//else
// return true;
}
else
{
_deeperInspection.Add(clientstring, new CircularBuffer<int>(_options.MaxRequestsInTimeframe + 1, true));
_deeperInspection[clientstring].Put(Util.EnvironmentTickCount());
_forgetTimer.Enabled = true;
}
}
return true;
}
}
public class BasicDosProtectorOptions
{
public int MaxRequestsInTimeframe;
public TimeSpan RequestTimeSpan;
public TimeSpan ForgetTimeSpan;
public bool AllowXForwardedFor;
public string ReportingName = "BASICDOSPROTECTOR";
public BasicDOSProtector.ThrottleAction ThrottledAction = BasicDOSProtector.ThrottleAction.DoThrottledMethod;
public int MaxConcurrentSessions;
}
}

View File

@@ -287,7 +287,13 @@ namespace OpenSim.Framework
public Vector3 AtAxis;
public Vector3 LeftAxis;
public Vector3 UpAxis;
public bool ChangedGrid;
/// <summary>
/// Signal on a V2 teleport that Scene.IncomingChildAgentDataUpdate(AgentData ad) should wait for the
/// scene presence to become root (triggered when the viewer sends a CompleteAgentMovement UDP packet after
/// establishing the connection triggered by it's receipt of a TeleportFinish EQ message).
/// </summary>
public bool SenderWantsToWaitForRoot;
public float Far;
public float Aspect;
@@ -356,8 +362,9 @@ namespace OpenSim.Framework
args["left_axis"] = OSD.FromString(LeftAxis.ToString());
args["up_axis"] = OSD.FromString(UpAxis.ToString());
args["changed_grid"] = OSD.FromBoolean(ChangedGrid);
//backwards compatibility
args["changed_grid"] = OSD.FromBoolean(SenderWantsToWaitForRoot);
args["wait_for_root"] = OSD.FromBoolean(SenderWantsToWaitForRoot);
args["far"] = OSD.FromReal(Far);
args["aspect"] = OSD.FromReal(Aspect);
@@ -526,8 +533,8 @@ namespace OpenSim.Framework
if (args["up_axis"] != null)
Vector3.TryParse(args["up_axis"].AsString(), out AtAxis);
if (args["changed_grid"] != null)
ChangedGrid = args["changed_grid"].AsBoolean();
if (args.ContainsKey("wait_for_root") && args["wait_for_root"] != null)
SenderWantsToWaitForRoot = args["wait_for_root"].AsBoolean();
if (args["far"] != null)
Far = (float)(args["far"].AsReal());

View File

@@ -0,0 +1,312 @@
/*
Copyright (c) 2012, Alex Regueiro
All rights reserved.
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.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 COPYRIGHT HOLDER OR 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.Threading;
namespace OpenSim.Framework
{
public class CircularBuffer<T> : ICollection<T>, IEnumerable<T>, ICollection, IEnumerable
{
private int capacity;
private int size;
private int head;
private int tail;
private T[] buffer;
[NonSerialized()]
private object syncRoot;
public CircularBuffer(int capacity)
: this(capacity, false)
{
}
public CircularBuffer(int capacity, bool allowOverflow)
{
if (capacity < 0)
throw new ArgumentException("Needs to have at least 1","capacity");
this.capacity = capacity;
size = 0;
head = 0;
tail = 0;
buffer = new T[capacity];
AllowOverflow = allowOverflow;
}
public bool AllowOverflow
{
get;
set;
}
public int Capacity
{
get { return capacity; }
set
{
if (value == capacity)
return;
if (value < size)
throw new ArgumentOutOfRangeException("value","Capacity is too small.");
var dst = new T[value];
if (size > 0)
CopyTo(dst);
buffer = dst;
capacity = value;
}
}
public int Size
{
get { return size; }
}
public bool Contains(T item)
{
int bufferIndex = head;
var comparer = EqualityComparer<T>.Default;
for (int i = 0; i < size; i++, bufferIndex++)
{
if (bufferIndex == capacity)
bufferIndex = 0;
if (item == null && buffer[bufferIndex] == null)
return true;
else if ((buffer[bufferIndex] != null) &&
comparer.Equals(buffer[bufferIndex], item))
return true;
}
return false;
}
public void Clear()
{
size = 0;
head = 0;
tail = 0;
}
public int Put(T[] src)
{
return Put(src, 0, src.Length);
}
public int Put(T[] src, int offset, int count)
{
if (!AllowOverflow && count > capacity - size)
throw new InvalidOperationException("Buffer Overflow");
int srcIndex = offset;
for (int i = 0; i < count; i++, tail++, srcIndex++)
{
if (tail == capacity)
tail = 0;
buffer[tail] = src[srcIndex];
}
size = Math.Min(size + count, capacity);
return count;
}
public void Put(T item)
{
if (!AllowOverflow && size == capacity)
throw new InvalidOperationException("Buffer Overflow");
buffer[tail] = item;
if (++tail == capacity)
tail = 0;
size++;
}
public void Skip(int count)
{
head += count;
if (head >= capacity)
head -= capacity;
}
public T[] Get(int count)
{
var dst = new T[count];
Get(dst);
return dst;
}
public int Get(T[] dst)
{
return Get(dst, 0, dst.Length);
}
public int Get(T[] dst, int offset, int count)
{
int realCount = Math.Min(count, size);
int dstIndex = offset;
for (int i = 0; i < realCount; i++, head++, dstIndex++)
{
if (head == capacity)
head = 0;
dst[dstIndex] = buffer[head];
}
size -= realCount;
return realCount;
}
public T Get()
{
if (size == 0)
throw new InvalidOperationException("Buffer Empty");
var item = buffer[head];
if (++head == capacity)
head = 0;
size--;
return item;
}
public void CopyTo(T[] array)
{
CopyTo(array, 0);
}
public void CopyTo(T[] array, int arrayIndex)
{
CopyTo(0, array, arrayIndex, size);
}
public void CopyTo(int index, T[] array, int arrayIndex, int count)
{
if (count > size)
throw new ArgumentOutOfRangeException("count", "Count Too Large");
int bufferIndex = head;
for (int i = 0; i < count; i++, bufferIndex++, arrayIndex++)
{
if (bufferIndex == capacity)
bufferIndex = 0;
array[arrayIndex] = buffer[bufferIndex];
}
}
public IEnumerator<T> GetEnumerator()
{
int bufferIndex = head;
for (int i = 0; i < size; i++, bufferIndex++)
{
if (bufferIndex == capacity)
bufferIndex = 0;
yield return buffer[bufferIndex];
}
}
public T[] GetBuffer()
{
return buffer;
}
public T[] ToArray()
{
var dst = new T[size];
CopyTo(dst);
return dst;
}
#region ICollection<T> Members
int ICollection<T>.Count
{
get { return Size; }
}
bool ICollection<T>.IsReadOnly
{
get { return false; }
}
void ICollection<T>.Add(T item)
{
Put(item);
}
bool ICollection<T>.Remove(T item)
{
if (size == 0)
return false;
Get();
return true;
}
#endregion
#region IEnumerable<T> Members
IEnumerator<T> IEnumerable<T>.GetEnumerator()
{
return GetEnumerator();
}
#endregion
#region ICollection Members
int ICollection.Count
{
get { return Size; }
}
bool ICollection.IsSynchronized
{
get { return false; }
}
object ICollection.SyncRoot
{
get
{
if (syncRoot == null)
Interlocked.CompareExchange(ref syncRoot, new object(), null);
return syncRoot;
}
}
void ICollection.CopyTo(Array array, int arrayIndex)
{
CopyTo((T[])array, arrayIndex);
}
#endregion
#region IEnumerable Members
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)GetEnumerator();
}
#endregion
}
}

View File

@@ -61,5 +61,5 @@ using System.Runtime.InteropServices;
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly : AssemblyVersion("0.7.6.*")]
[assembly : AssemblyVersion("0.8.0.*")]

View File

@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
[assembly: AssemblyVersion("0.7.6.*")]
[assembly: AssemblyVersion("0.8.0.*")]

View File

@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
[assembly: AssemblyVersion("0.7.6.*")]
[assembly: AssemblyVersion("0.8.0.*")]

View File

@@ -55,4 +55,4 @@ using System.Runtime.InteropServices;
// You can specify all values by your own or you can build default build and revision
// numbers with the '*' character (the default):
[assembly : AssemblyVersion("0.7.6.*")]
[assembly : AssemblyVersion("0.8.0.*")]

View File

@@ -156,12 +156,32 @@ namespace OpenSim.Framework.Console
}
/// <summary>
/// Convert a minimum vector input from the console to an OpenMetaverse.Vector3
/// Convert a console integer to an int, automatically complaining if a console is given.
/// </summary>
/// <param name='console'>Can be null if no console is available.</param>
/// <param name='rawConsoleVector'>/param>
/// <param name='vector'></param>
/// <returns></returns>
public static bool TryParseConsoleBool(ICommandConsole console, string rawConsoleString, out bool b)
{
if (!bool.TryParse(rawConsoleString, out b))
{
if (console != null)
console.OutputFormat("ERROR: {0} is not a true or false value", rawConsoleString);
return false;
}
return true;
}
/// <summary>
/// Convert a console integer to an int, automatically complaining if a console is given.
/// </summary>
/// <param name='console'>Can be null if no console is available.</param>
/// <param name='rawConsoleInt'>/param>
/// <param name='i'></param>
/// <returns></returns>
public static bool TryParseConsoleInt(ICommandConsole console, string rawConsoleInt, out int i)
{
if (!int.TryParse(rawConsoleInt, out i))
@@ -174,6 +194,31 @@ namespace OpenSim.Framework.Console
return true;
}
/// <summary>
/// Convert a console integer to a natural int, automatically complaining if a console is given.
/// </summary>
/// <param name='console'>Can be null if no console is available.</param>
/// <param name='rawConsoleInt'>/param>
/// <param name='i'></param>
/// <returns></returns>
public static bool TryParseConsoleNaturalInt(ICommandConsole console, string rawConsoleInt, out int i)
{
if (TryParseConsoleInt(console, rawConsoleInt, out i))
{
if (i < 0)
{
if (console != null)
console.OutputFormat("ERROR: {0} is not a positive integer", rawConsoleInt);
return false;
}
return true;
}
return false;
}
/// <summary>
/// Convert a minimum vector input from the console to an OpenMetaverse.Vector3

View File

@@ -53,6 +53,24 @@ namespace OpenSim.Framework
binaryBucket = new byte[0];
}
public GridInstantMessage(GridInstantMessage im, bool addTimestamp)
{
fromAgentID = im.fromAgentID;
fromAgentName = im.fromAgentName;
toAgentID = im.toAgentID;
dialog = im.dialog;
fromGroup = im.fromGroup;
message = im.message;
imSessionID = im.imSessionID;
offline = im.offline;
Position = im.Position;
binaryBucket = im.binaryBucket;
RegionID = im.RegionID;
if (addTimestamp)
timestamp = (uint)Util.UnixTimeSinceEpoch();
}
public GridInstantMessage(IScene scene, UUID _fromAgentID,
string _fromAgentName, UUID _toAgentID,
byte _dialog, bool _fromGroup, string _message,

View File

@@ -86,24 +86,26 @@ namespace OpenSim.Framework
event restart OnRestart;
/// <summary>
/// Add a new client and create a presence for it. All clients except initial login clients will starts off as a child agent
/// Add a new agent with an attached client. All agents except initial login clients will starts off as a child agent
/// - the later agent crossing will promote it to a root agent.
/// </summary>
/// <param name="client"></param>
/// <param name="type">The type of agent to add.</param>
/// <returns>
/// The scene agent if the new client was added or if an agent that already existed.</returns>
ISceneAgent AddNewClient(IClientAPI client, PresenceType type);
ISceneAgent AddNewAgent(IClientAPI client, PresenceType type);
/// <summary>
/// Remove the given client from the scene.
/// Tell a single agent to disconnect from the region.
/// </summary>
/// <param name="agentID"></param>
/// <param name="closeChildAgents">Close the neighbour child agents associated with this client.</param>
void RemoveClient(UUID agentID, bool closeChildAgents);
/// <param name="force">
/// Force the agent to close even if it might be in the middle of some other operation. You do not want to
/// force unless you are absolutely sure that the agent is dead and a normal close is not working.
/// </param>
bool CloseAgent(UUID agentID, bool force);
void Restart();
//RegionInfo OtherRegionUp(RegionInfo thisRegion);
string GetSimulatorVersion();

View File

@@ -33,10 +33,10 @@ namespace OpenSim.Framework
[Serializable]
public class Location : ICloneable
{
private readonly int m_x;
private readonly int m_y;
private readonly uint m_x;
private readonly uint m_y;
public Location(int x, int y)
public Location(uint x, uint y)
{
m_x = x;
m_y = y;
@@ -44,21 +44,21 @@ namespace OpenSim.Framework
public Location(ulong regionHandle)
{
m_x = (int) regionHandle;
m_y = (int) (regionHandle >> 32);
m_x = (uint)(regionHandle >> 32);
m_y = (uint)(regionHandle & (ulong)uint.MaxValue);
}
public ulong RegionHandle
{
get { return Utils.UIntsToLong((uint)m_x, (uint)m_y); }
get { return Utils.UIntsToLong(m_x, m_y); }
}
public int X
public uint X
{
get { return m_x; }
}
public int Y
public uint Y
{
get { return m_y; }
}

View File

@@ -0,0 +1,118 @@
/*
* 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.Text;
namespace OpenSim.Framework.Monitoring
{
public class Check
{
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
public static readonly char[] DisallowedShortNameCharacters = { '.' };
/// <summary>
/// Category of this stat (e.g. cache, scene, etc).
/// </summary>
public string Category { get; private set; }
/// <summary>
/// Containing name for this stat.
/// FIXME: In the case of a scene, this is currently the scene name (though this leaves
/// us with a to-be-resolved problem of non-unique region names).
/// </summary>
/// <value>
/// The container.
/// </value>
public string Container { get; private set; }
/// <summary>
/// Action used to check whether alert should go off.
/// </summary>
/// <remarks>
/// Should return true if check passes. False otherwise.
/// </remarks>
public Func<Check, bool> CheckFunc { get; private set; }
/// <summary>
/// Message from the last failure, if any. If there is no message or no failure then will be null.
/// </summary>
/// <remarks>
/// Should be set by the CheckFunc when applicable.
/// </remarks>
public string LastFailureMessage { get; set; }
public StatVerbosity Verbosity { get; private set; }
public string ShortName { get; private set; }
public string Name { get; private set; }
public string Description { get; private set; }
public Check(
string shortName,
string name,
string description,
string category,
string container,
Func<Check, bool> checkFunc,
StatVerbosity verbosity)
{
if (ChecksManager.SubCommands.Contains(category))
throw new Exception(
string.Format("Alert cannot be in category '{0}' since this is reserved for a subcommand", category));
foreach (char c in DisallowedShortNameCharacters)
{
if (shortName.IndexOf(c) != -1)
throw new Exception(string.Format("Alert name {0} cannot contain character {1}", shortName, c));
}
ShortName = shortName;
Name = name;
Description = description;
Category = category;
Container = container;
CheckFunc = checkFunc;
Verbosity = verbosity;
}
public bool CheckIt()
{
return CheckFunc(this);
}
public virtual string ToConsoleString()
{
return string.Format(
"{0}.{1}.{2} - {3}",
Category,
Container,
ShortName,
Description);
}
}
}

View File

@@ -0,0 +1,262 @@
/*
* 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 log4net;
namespace OpenSim.Framework.Monitoring
{
/// <summary>
/// Static class used to register/deregister checks on runtime conditions.
/// </summary>
public static class ChecksManager
{
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
// Subcommand used to list other stats.
public const string ListSubCommand = "list";
// All subcommands
public static HashSet<string> SubCommands = new HashSet<string> { ListSubCommand };
/// <summary>
/// Checks categorized by category/container/shortname
/// </summary>
/// <remarks>
/// Do not add or remove directly from this dictionary.
/// </remarks>
public static SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Check>>> RegisteredChecks
= new SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Check>>>();
public static void RegisterConsoleCommands(ICommandConsole console)
{
console.Commands.AddCommand(
"General",
false,
"show checks",
"show checks",
"Show checks configured for this server",
"If no argument is specified then info on all checks will be shown.\n"
+ "'list' argument will show check categories.\n"
+ "THIS FACILITY IS EXPERIMENTAL",
HandleShowchecksCommand);
}
public static void HandleShowchecksCommand(string module, string[] cmd)
{
ICommandConsole con = MainConsole.Instance;
if (cmd.Length > 2)
{
foreach (string name in cmd.Skip(2))
{
string[] components = name.Split('.');
string categoryName = components[0];
// string containerName = components.Length > 1 ? components[1] : null;
if (categoryName == ListSubCommand)
{
con.Output("check categories available are:");
foreach (string category in RegisteredChecks.Keys)
con.OutputFormat(" {0}", category);
}
// else
// {
// SortedDictionary<string, SortedDictionary<string, Check>> category;
// if (!Registeredchecks.TryGetValue(categoryName, out category))
// {
// con.OutputFormat("No such category as {0}", categoryName);
// }
// else
// {
// if (String.IsNullOrEmpty(containerName))
// {
// OutputConfiguredToConsole(con, category);
// }
// else
// {
// SortedDictionary<string, Check> container;
// if (category.TryGetValue(containerName, out container))
// {
// OutputContainerChecksToConsole(con, container);
// }
// else
// {
// con.OutputFormat("No such container {0} in category {1}", containerName, categoryName);
// }
// }
// }
// }
}
}
else
{
OutputAllChecksToConsole(con);
}
}
/// <summary>
/// Registers a statistic.
/// </summary>
/// <param name='stat'></param>
/// <returns></returns>
public static bool RegisterCheck(Check check)
{
SortedDictionary<string, SortedDictionary<string, Check>> category = null, newCategory;
SortedDictionary<string, Check> container = null, newContainer;
lock (RegisteredChecks)
{
// Check name is not unique across category/container/shortname key.
// XXX: For now just return false. This is to avoid problems in regression tests where all tests
// in a class are run in the same instance of the VM.
if (TryGetCheckParents(check, out category, out container))
return false;
// We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
// This means that we don't need to lock or copy them on iteration, which will be a much more
// common operation after startup.
if (container != null)
newContainer = new SortedDictionary<string, Check>(container);
else
newContainer = new SortedDictionary<string, Check>();
if (category != null)
newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>(category);
else
newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>();
newContainer[check.ShortName] = check;
newCategory[check.Container] = newContainer;
RegisteredChecks[check.Category] = newCategory;
}
return true;
}
/// <summary>
/// Deregister an check
/// </summary>>
/// <param name='stat'></param>
/// <returns></returns>
public static bool DeregisterCheck(Check check)
{
SortedDictionary<string, SortedDictionary<string, Check>> category = null, newCategory;
SortedDictionary<string, Check> container = null, newContainer;
lock (RegisteredChecks)
{
if (!TryGetCheckParents(check, out category, out container))
return false;
newContainer = new SortedDictionary<string, Check>(container);
newContainer.Remove(check.ShortName);
newCategory = new SortedDictionary<string, SortedDictionary<string, Check>>(category);
newCategory.Remove(check.Container);
newCategory[check.Container] = newContainer;
RegisteredChecks[check.Category] = newCategory;
return true;
}
}
public static bool TryGetCheckParents(
Check check,
out SortedDictionary<string, SortedDictionary<string, Check>> category,
out SortedDictionary<string, Check> container)
{
category = null;
container = null;
lock (RegisteredChecks)
{
if (RegisteredChecks.TryGetValue(check.Category, out category))
{
if (category.TryGetValue(check.Container, out container))
{
if (container.ContainsKey(check.ShortName))
return true;
}
}
}
return false;
}
public static void CheckChecks()
{
lock (RegisteredChecks)
{
foreach (SortedDictionary<string, SortedDictionary<string, Check>> category in RegisteredChecks.Values)
{
foreach (SortedDictionary<string, Check> container in category.Values)
{
foreach (Check check in container.Values)
{
if (!check.CheckIt())
m_log.WarnFormat(
"[CHECKS MANAGER]: Check {0}.{1}.{2} failed with message {3}", check.Category, check.Container, check.ShortName, check.LastFailureMessage);
}
}
}
}
}
private static void OutputAllChecksToConsole(ICommandConsole con)
{
foreach (var category in RegisteredChecks.Values)
{
OutputCategoryChecksToConsole(con, category);
}
}
private static void OutputCategoryChecksToConsole(
ICommandConsole con, SortedDictionary<string, SortedDictionary<string, Check>> category)
{
foreach (var container in category.Values)
{
OutputContainerChecksToConsole(con, container);
}
}
private static void OutputContainerChecksToConsole(ICommandConsole con, SortedDictionary<string, Check> container)
{
foreach (Check check in container.Values)
{
con.Output(check.ToConsoleString());
}
}
}
}

View File

@@ -29,5 +29,5 @@ using System.Runtime.InteropServices;
// Build Number
// Revision
//
[assembly: AssemblyVersion("0.7.6.*")]
[assembly: AssemblyVersion("0.8.0.*")]

View File

@@ -27,6 +27,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenMetaverse;
using OpenMetaverse.StructuredData;
@@ -39,8 +40,6 @@ namespace OpenSim.Framework.Monitoring
/// </summary>
public class SimExtraStatsCollector : BaseStatsCollector
{
private long abnormalClientThreadTerminations;
// private long assetsInCache;
// private long texturesInCache;
// private long assetCacheMemoryUsage;
@@ -73,11 +72,6 @@ namespace OpenSim.Framework.Monitoring
private volatile float activeScripts;
private volatile float scriptLinesPerSecond;
/// <summary>
/// Number of times that a client thread terminated because of an exception
/// </summary>
public long AbnormalClientThreadTerminations { get { return abnormalClientThreadTerminations; } }
// /// <summary>
// /// These statistics are being collected by push rather than pull. Pull would be simpler, but I had the
// /// notion of providing some flow statistics (which pull wouldn't give us). Though admittedly these
@@ -166,11 +160,6 @@ namespace OpenSim.Framework.Monitoring
private IDictionary<UUID, PacketQueueStatsCollector> packetQueueStatsCollectors
= new Dictionary<UUID, PacketQueueStatsCollector>();
public void AddAbnormalClientThreadTermination()
{
abnormalClientThreadTerminations++;
}
// public void AddAsset(AssetBase asset)
// {
// assetsInCache++;
@@ -324,10 +313,12 @@ Asset service request failures: {3}" + Environment.NewLine,
sb.Append(Environment.NewLine);
sb.Append("CONNECTION STATISTICS");
sb.Append(Environment.NewLine);
sb.Append(
string.Format(
"Abnormal client thread terminations: {0}" + Environment.NewLine,
abnormalClientThreadTerminations));
List<Stat> stats = StatsManager.GetStatsFromEachContainer("clientstack", "ClientLogoutsDueToNoReceives");
sb.AppendFormat(
"Client logouts due to no data receive timeout: {0}\n\n",
stats != null ? stats.Sum(s => s.Value).ToString() : "unknown");
// sb.Append(Environment.NewLine);
// sb.Append("INVENTORY STATISTICS");
@@ -338,7 +329,7 @@ Asset service request failures: {3}" + Environment.NewLine,
// InventoryServiceRetrievalFailures));
sb.Append(Environment.NewLine);
sb.Append("FRAME STATISTICS");
sb.Append("SAMPLE FRAME STATISTICS");
sb.Append(Environment.NewLine);
sb.Append("Dilatn SimFPS PhyFPS AgntUp RootAg ChldAg Prims AtvPrm AtvScr ScrLPS");
sb.Append(Environment.NewLine);

View File

@@ -34,142 +34,6 @@ using OpenMetaverse.StructuredData;
namespace OpenSim.Framework.Monitoring
{
// Create a time histogram of events. The histogram is built in a wrap-around
// array of equally distributed buckets.
// For instance, a minute long histogram of second sized buckets would be:
// new EventHistogram(60, 1000)
public class EventHistogram
{
private int m_timeBase;
private int m_numBuckets;
private int m_bucketMilliseconds;
private int m_lastBucket;
private int m_totalHistogramMilliseconds;
private long[] m_histogram;
private object histoLock = new object();
public EventHistogram(int numberOfBuckets, int millisecondsPerBucket)
{
m_numBuckets = numberOfBuckets;
m_bucketMilliseconds = millisecondsPerBucket;
m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds;
m_histogram = new long[m_numBuckets];
Zero();
m_lastBucket = 0;
m_timeBase = Util.EnvironmentTickCount();
}
public void Event()
{
this.Event(1);
}
// Record an event at time 'now' in the histogram.
public void Event(int cnt)
{
lock (histoLock)
{
// The time as displaced from the base of the histogram
int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase);
// If more than the total time of the histogram, we just start over
if (bucketTime > m_totalHistogramMilliseconds)
{
Zero();
m_lastBucket = 0;
m_timeBase = Util.EnvironmentTickCount();
}
else
{
// To which bucket should we add this event?
int bucket = bucketTime / m_bucketMilliseconds;
// Advance m_lastBucket to the new bucket. Zero any buckets skipped over.
while (bucket != m_lastBucket)
{
// Zero from just after the last bucket to the new bucket or the end
for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++)
{
m_histogram[jj] = 0;
}
m_lastBucket = bucket;
// If the new bucket is off the end, wrap around to the beginning
if (bucket > m_numBuckets)
{
bucket -= m_numBuckets;
m_lastBucket = 0;
m_histogram[m_lastBucket] = 0;
m_timeBase += m_totalHistogramMilliseconds;
}
}
}
m_histogram[m_lastBucket] += cnt;
}
}
// Get a copy of the current histogram
public long[] GetHistogram()
{
long[] ret = new long[m_numBuckets];
lock (histoLock)
{
int indx = m_lastBucket + 1;
for (int ii = 0; ii < m_numBuckets; ii++, indx++)
{
if (indx >= m_numBuckets)
indx = 0;
ret[ii] = m_histogram[indx];
}
}
return ret;
}
public OSDMap GetHistogramAsOSDMap()
{
OSDMap ret = new OSDMap();
ret.Add("Buckets", OSD.FromInteger(m_numBuckets));
ret.Add("BucketMilliseconds", OSD.FromInteger(m_bucketMilliseconds));
ret.Add("TotalMilliseconds", OSD.FromInteger(m_totalHistogramMilliseconds));
// Compute a number for the first bucket in the histogram.
// This will allow readers to know how this histogram relates to any previously read histogram.
int baseBucketNum = (m_timeBase / m_bucketMilliseconds) + m_lastBucket + 1;
ret.Add("BaseNumber", OSD.FromInteger(baseBucketNum));
ret.Add("Values", GetHistogramAsOSDArray());
return ret;
}
// Get a copy of the current histogram
public OSDArray GetHistogramAsOSDArray()
{
OSDArray ret = new OSDArray(m_numBuckets);
lock (histoLock)
{
int indx = m_lastBucket + 1;
for (int ii = 0; ii < m_numBuckets; ii++, indx++)
{
if (indx >= m_numBuckets)
indx = 0;
ret[ii] = OSD.FromLong(m_histogram[indx]);
}
}
return ret;
}
// Zero out the histogram
public void Zero()
{
lock (histoLock)
{
for (int ii = 0; ii < m_numBuckets; ii++)
m_histogram[ii] = 0;
}
}
}
// A statistic that wraps a counter.
// Built this way mostly so histograms and history can be created.
public class CounterStat : Stat
@@ -236,12 +100,18 @@ public class CounterStat : Stat
// If there are any histograms, add a new field that is an array of histograms as OSDMaps
if (m_histograms.Count > 0)
{
OSDArray histos = new OSDArray();
foreach (EventHistogram histo in m_histograms.Values)
lock (counterLock)
{
histos.Add(histo.GetHistogramAsOSDMap());
if (m_histograms.Count > 0)
{
OSDArray histos = new OSDArray();
foreach (EventHistogram histo in m_histograms.Values)
{
histos.Add(histo.GetHistogramAsOSDMap());
}
map.Add("Histograms", histos);
}
}
map.Add("Histograms", histos);
}
return map;
}

View File

@@ -0,0 +1,173 @@
/*
* 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.Text;
using OpenMetaverse.StructuredData;
namespace OpenSim.Framework.Monitoring
{
// Create a time histogram of events. The histogram is built in a wrap-around
// array of equally distributed buckets.
// For instance, a minute long histogram of second sized buckets would be:
// new EventHistogram(60, 1000)
public class EventHistogram
{
private int m_timeBase;
private int m_numBuckets;
private int m_bucketMilliseconds;
private int m_lastBucket;
private int m_totalHistogramMilliseconds;
private long[] m_histogram;
private object histoLock = new object();
public EventHistogram(int numberOfBuckets, int millisecondsPerBucket)
{
m_numBuckets = numberOfBuckets;
m_bucketMilliseconds = millisecondsPerBucket;
m_totalHistogramMilliseconds = m_numBuckets * m_bucketMilliseconds;
m_histogram = new long[m_numBuckets];
Zero();
m_lastBucket = 0;
m_timeBase = Util.EnvironmentTickCount();
}
public void Event()
{
this.Event(1);
}
// Record an event at time 'now' in the histogram.
public void Event(int cnt)
{
lock (histoLock)
{
// The time as displaced from the base of the histogram
int bucketTime = Util.EnvironmentTickCountSubtract(m_timeBase);
// If more than the total time of the histogram, we just start over
if (bucketTime > m_totalHistogramMilliseconds)
{
Zero();
m_lastBucket = 0;
m_timeBase = Util.EnvironmentTickCount();
}
else
{
// To which bucket should we add this event?
int bucket = bucketTime / m_bucketMilliseconds;
// Advance m_lastBucket to the new bucket. Zero any buckets skipped over.
while (bucket != m_lastBucket)
{
// Zero from just after the last bucket to the new bucket or the end
for (int jj = m_lastBucket + 1; jj <= Math.Min(bucket, m_numBuckets - 1); jj++)
{
m_histogram[jj] = 0;
}
m_lastBucket = bucket;
// If the new bucket is off the end, wrap around to the beginning
if (bucket > m_numBuckets)
{
bucket -= m_numBuckets;
m_lastBucket = 0;
m_histogram[m_lastBucket] = 0;
m_timeBase += m_totalHistogramMilliseconds;
}
}
}
m_histogram[m_lastBucket] += cnt;
}
}
// Get a copy of the current histogram
public long[] GetHistogram()
{
long[] ret = new long[m_numBuckets];
lock (histoLock)
{
int indx = m_lastBucket + 1;
for (int ii = 0; ii < m_numBuckets; ii++, indx++)
{
if (indx >= m_numBuckets)
indx = 0;
ret[ii] = m_histogram[indx];
}
}
return ret;
}
public OSDMap GetHistogramAsOSDMap()
{
OSDMap ret = new OSDMap();
ret.Add("Buckets", OSD.FromInteger(m_numBuckets));
ret.Add("BucketMilliseconds", OSD.FromInteger(m_bucketMilliseconds));
ret.Add("TotalMilliseconds", OSD.FromInteger(m_totalHistogramMilliseconds));
// Compute a number for the first bucket in the histogram.
// This will allow readers to know how this histogram relates to any previously read histogram.
int baseBucketNum = (m_timeBase / m_bucketMilliseconds) + m_lastBucket + 1;
ret.Add("BaseNumber", OSD.FromInteger(baseBucketNum));
ret.Add("Values", GetHistogramAsOSDArray());
return ret;
}
// Get a copy of the current histogram
public OSDArray GetHistogramAsOSDArray()
{
OSDArray ret = new OSDArray(m_numBuckets);
lock (histoLock)
{
int indx = m_lastBucket + 1;
for (int ii = 0; ii < m_numBuckets; ii++, indx++)
{
if (indx >= m_numBuckets)
indx = 0;
ret[ii] = OSD.FromLong(m_histogram[indx]);
}
}
return ret;
}
// Zero out the histogram
public void Zero()
{
lock (histoLock)
{
for (int ii = 0; ii < m_numBuckets; ii++)
m_histogram[ii] = 0;
}
}
}
}

View File

@@ -29,6 +29,8 @@ using System;
using System.Collections.Generic;
using System.Text;
using OpenMetaverse.StructuredData;
namespace OpenSim.Framework.Monitoring
{
public class PercentageStat : Stat
@@ -84,5 +86,19 @@ namespace OpenSim.Framework.Monitoring
return sb.ToString();
}
// PercentageStat is a basic stat plus percent calc
public override OSDMap ToOSDMap()
{
// Get the foundational instance
OSDMap map = base.ToOSDMap();
map["StatType"] = "PercentageStat";
map.Add("Antecedent", OSD.FromLong(Antecedent));
map.Add("Consequent", OSD.FromLong(Consequent));
return map;
}
}
}

View File

@@ -225,7 +225,13 @@ namespace OpenSim.Framework.Monitoring
public virtual string ToConsoleString()
{
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0}.{1}.{2} : {3} {4}", Category, Container, ShortName, Value, UnitName);
sb.AppendFormat(
"{0}.{1}.{2} : {3}{4}",
Category,
Container,
ShortName,
Value,
UnitName == null || UnitName == "" ? "" : string.Format(" {0}", UnitName));
AppendMeasuresOfInterest(sb);
@@ -235,6 +241,8 @@ namespace OpenSim.Framework.Monitoring
public virtual OSDMap ToOSDMap()
{
OSDMap ret = new OSDMap();
ret.Add("StatType", "Stat"); // used by overloading classes to denote type of stat
ret.Add("Category", OSD.FromString(Category));
ret.Add("Container", OSD.FromString(Container));
ret.Add("ShortName", OSD.FromString(ShortName));
@@ -242,37 +250,75 @@ namespace OpenSim.Framework.Monitoring
ret.Add("Description", OSD.FromString(Description));
ret.Add("UnitName", OSD.FromString(UnitName));
ret.Add("Value", OSD.FromReal(Value));
ret.Add("StatType", "Stat"); // used by overloading classes to denote type of stat
double lastChangeOverTime, averageChangeOverTime;
if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime))
{
ret.Add("LastChangeOverTime", OSD.FromReal(lastChangeOverTime));
ret.Add("AverageChangeOverTime", OSD.FromReal(averageChangeOverTime));
}
return ret;
}
protected void AppendMeasuresOfInterest(StringBuilder sb)
// Compute the averages over time and return same.
// Return 'true' if averages were actually computed. 'false' if no average info.
public bool ComputeMeasuresOfInterest(out double lastChangeOverTime, out double averageChangeOverTime)
{
if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime)
== MeasuresOfInterest.AverageChangeOverTime)
bool ret = false;
lastChangeOverTime = 0;
averageChangeOverTime = 0;
if ((MeasuresOfInterest & MeasuresOfInterest.AverageChangeOverTime) == MeasuresOfInterest.AverageChangeOverTime)
{
double totalChange = 0;
double? penultimateSample = null;
double? lastSample = null;
lock (m_samples)
{
// m_log.DebugFormat(
// "[STAT]: Samples for {0} are {1}",
// Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray()));
// m_log.DebugFormat(
// "[STAT]: Samples for {0} are {1}",
// Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray()));
foreach (double s in m_samples)
{
if (lastSample != null)
totalChange += s - (double)lastSample;
penultimateSample = lastSample;
lastSample = s;
}
}
if (lastSample != null && penultimateSample != null)
{
lastChangeOverTime
= ((double)lastSample - (double)penultimateSample) / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
}
int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1;
sb.AppendFormat(", {0:0.##} {1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName);
averageChangeOverTime = totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000);
ret = true;
}
return ret;
}
protected void AppendMeasuresOfInterest(StringBuilder sb)
{
double lastChangeOverTime = 0;
double averageChangeOverTime = 0;
if (ComputeMeasuresOfInterest(out lastChangeOverTime, out averageChangeOverTime))
{
sb.AppendFormat(
", {0:0.##}{1}/s, {2:0.##}{3}/s",
lastChangeOverTime,
UnitName == null || UnitName == "" ? "" : string.Format(" {0}", UnitName),
averageChangeOverTime,
UnitName == null || UnitName == "" ? "" : string.Format(" {0}", UnitName));
}
}
}

View File

@@ -0,0 +1,108 @@
/*
* Copyright (c) Contributors, http://opensimulator.org/
* See CONTRIBUTORS.TXT for a full list of copyright holders.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the 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.Timers;
using log4net;
namespace OpenSim.Framework.Monitoring
{
/// <summary>
/// Provides a means to continuously log stats for debugging purposes.
/// </summary>
public static class StatsLogger
{
private static readonly ILog m_statsLog = LogManager.GetLogger("special.StatsLogger");
private static Timer m_loggingTimer;
private static int m_statsLogIntervalMs = 5000;
public static void RegisterConsoleCommands(ICommandConsole console)
{
console.Commands.AddCommand(
"Debug",
false,
"debug stats record",
"debug stats record start|stop",
"Control whether stats are being regularly recorded to a separate file.",
"For debug purposes. Experimental.",
HandleStatsRecordCommand);
}
public static void HandleStatsRecordCommand(string module, string[] cmd)
{
ICommandConsole con = MainConsole.Instance;
if (cmd.Length != 4)
{
con.Output("Usage: debug stats record start|stop");
return;
}
if (cmd[3] == "start")
{
Start();
con.OutputFormat("Now recording all stats to file every {0}ms", m_statsLogIntervalMs);
}
else if (cmd[3] == "stop")
{
Stop();
con.Output("Stopped recording stats to file.");
}
}
public static void Start()
{
if (m_loggingTimer != null)
Stop();
m_loggingTimer = new Timer(m_statsLogIntervalMs);
m_loggingTimer.AutoReset = false;
m_loggingTimer.Elapsed += Log;
m_loggingTimer.Start();
}
public static void Stop()
{
if (m_loggingTimer != null)
{
m_loggingTimer.Stop();
}
}
private static void Log(object sender, ElapsedEventArgs e)
{
m_statsLog.InfoFormat("*** STATS REPORT AT {0} ***", DateTime.Now);
foreach (string report in StatsManager.GetAllStatsReports())
m_statsLog.Info(report);
m_loggingTimer.Start();
}
}
}

View File

@@ -26,18 +26,20 @@
*/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenSim.Framework;
using OpenMetaverse.StructuredData;
namespace OpenSim.Framework.Monitoring
{
/// <summary>
/// Singleton used to provide access to statistics reporters
/// Static class used to register/deregister/fetch statistics
/// </summary>
public class StatsManager
public static class StatsManager
{
// Subcommand used to list other stats.
public const string AllSubCommand = "all";
@@ -81,6 +83,8 @@ namespace OpenSim.Framework.Monitoring
+ "More than one name can be given separated by spaces.\n"
+ "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS",
HandleShowStatsCommand);
StatsLogger.RegisterConsoleCommands(console);
}
public static void HandleShowStatsCommand(string module, string[] cmd)
@@ -145,29 +149,55 @@ namespace OpenSim.Framework.Monitoring
}
}
public static List<string> GetAllStatsReports()
{
List<string> reports = new List<string>();
foreach (var category in RegisteredStats.Values)
reports.AddRange(GetCategoryStatsReports(category));
return reports;
}
private static void OutputAllStatsToConsole(ICommandConsole con)
{
foreach (var category in RegisteredStats.Values)
{
OutputCategoryStatsToConsole(con, category);
}
foreach (string report in GetAllStatsReports())
con.Output(report);
}
private static List<string> GetCategoryStatsReports(
SortedDictionary<string, SortedDictionary<string, Stat>> category)
{
List<string> reports = new List<string>();
foreach (var container in category.Values)
reports.AddRange(GetContainerStatsReports(container));
return reports;
}
private static void OutputCategoryStatsToConsole(
ICommandConsole con, SortedDictionary<string, SortedDictionary<string, Stat>> category)
{
foreach (var container in category.Values)
{
OutputContainerStatsToConsole(con, container);
}
foreach (string report in GetCategoryStatsReports(category))
con.Output(report);
}
private static void OutputContainerStatsToConsole( ICommandConsole con, SortedDictionary<string, Stat> container)
private static List<string> GetContainerStatsReports(SortedDictionary<string, Stat> container)
{
List<string> reports = new List<string>();
foreach (Stat stat in container.Values)
{
con.Output(stat.ToConsoleString());
}
reports.Add(stat.ToConsoleString());
return reports;
}
private static void OutputContainerStatsToConsole(
ICommandConsole con, SortedDictionary<string, Stat> container)
{
foreach (string report in GetContainerStatsReports(container))
con.Output(report);
}
// Creates an OSDMap of the format:
@@ -234,6 +264,41 @@ namespace OpenSim.Framework.Monitoring
return map;
}
public static Hashtable HandleStatsRequest(Hashtable request)
{
Hashtable responsedata = new Hashtable();
// string regpath = request["uri"].ToString();
int response_code = 200;
string contenttype = "text/json";
string pCategoryName = StatsManager.AllSubCommand;
string pContainerName = StatsManager.AllSubCommand;
string pStatName = StatsManager.AllSubCommand;
if (request.ContainsKey("cat")) pCategoryName = request["cat"].ToString();
if (request.ContainsKey("cont")) pContainerName = request["cat"].ToString();
if (request.ContainsKey("stat")) pStatName = request["cat"].ToString();
string strOut = StatsManager.GetStatsAsOSDMap(pCategoryName, pContainerName, pStatName).ToString();
// If requestor wants it as a callback function, build response as a function rather than just the JSON string.
if (request.ContainsKey("callback"))
{
strOut = request["callback"].ToString() + "(" + strOut + ");";
}
// m_log.DebugFormat("{0} StatFetch: uri={1}, cat={2}, cont={3}, stat={4}, resp={5}",
// LogHeader, regpath, pCategoryName, pContainerName, pStatName, strOut);
responsedata["int_response_code"] = response_code;
responsedata["content_type"] = contenttype;
responsedata["keepalive"] = false;
responsedata["str_response_string"] = strOut;
responsedata["access_control_allow_origin"] = "*";
return responsedata;
}
// /// <summary>
// /// Start collecting statistics related to assets.
// /// Should only be called once.
@@ -257,7 +322,7 @@ namespace OpenSim.Framework.Monitoring
// }
/// <summary>
/// Registers a statistic.
/// Register a statistic.
/// </summary>
/// <param name='stat'></param>
/// <returns></returns>
@@ -271,7 +336,7 @@ namespace OpenSim.Framework.Monitoring
// Stat name is not unique across category/container/shortname key.
// XXX: For now just return false. This is to avoid problems in regression tests where all tests
// in a class are run in the same instance of the VM.
if (TryGetStat(stat, out category, out container))
if (TryGetStatParents(stat, out category, out container))
return false;
// We take a copy-on-write approach here of replacing dictionaries when keys are added or removed.
@@ -307,7 +372,7 @@ namespace OpenSim.Framework.Monitoring
lock (RegisteredStats)
{
if (!TryGetStat(stat, out category, out container))
if (!TryGetStatParents(stat, out category, out container))
return false;
newContainer = new SortedDictionary<string, Stat>(container);
@@ -323,12 +388,67 @@ namespace OpenSim.Framework.Monitoring
}
}
public static bool TryGetStats(string category, out SortedDictionary<string, SortedDictionary<string, Stat>> stats)
public static bool TryGetStat(string category, string container, string statShortName, out Stat stat)
{
return RegisteredStats.TryGetValue(category, out stats);
stat = null;
SortedDictionary<string, SortedDictionary<string, Stat>> categoryStats;
lock (RegisteredStats)
{
if (!TryGetStatsForCategory(category, out categoryStats))
return false;
SortedDictionary<string, Stat> containerStats;
if (!categoryStats.TryGetValue(container, out containerStats))
return false;
return containerStats.TryGetValue(statShortName, out stat);
}
}
public static bool TryGetStat(
public static bool TryGetStatsForCategory(
string category, out SortedDictionary<string, SortedDictionary<string, Stat>> stats)
{
lock (RegisteredStats)
return RegisteredStats.TryGetValue(category, out stats);
}
/// <summary>
/// Get the same stat for each container in a given category.
/// </summary>
/// <returns>
/// The stats if there were any to fetch. Otherwise null.
/// </returns>
/// <param name='category'></param>
/// <param name='statShortName'></param>
public static List<Stat> GetStatsFromEachContainer(string category, string statShortName)
{
SortedDictionary<string, SortedDictionary<string, Stat>> categoryStats;
lock (RegisteredStats)
{
if (!RegisteredStats.TryGetValue(category, out categoryStats))
return null;
List<Stat> stats = null;
foreach (SortedDictionary<string, Stat> containerStats in categoryStats.Values)
{
if (containerStats.ContainsKey(statShortName))
{
if (stats == null)
stats = new List<Stat>();
stats.Add(containerStats[statShortName]);
}
}
return stats;
}
}
public static bool TryGetStatParents(
Stat stat,
out SortedDictionary<string, SortedDictionary<string, Stat>> category,
out SortedDictionary<string, Stat> container)

View File

@@ -380,6 +380,7 @@ namespace OpenSim.Framework.Monitoring
if (MemoryWatchdog.Enabled)
MemoryWatchdog.Update();
ChecksManager.CheckChecks();
StatsManager.RecordStats();
m_watchdogTimer.Start();

View File

@@ -105,6 +105,7 @@ namespace OpenSim.Framework
private ushort _profileHollow;
private Vector3 _scale;
private byte _state;
private byte _lastattach;
private ProfileShape _profileShape;
private HollowShape _hollowShape;
@@ -207,6 +208,7 @@ namespace OpenSim.Framework
PCode = (byte)prim.PrimData.PCode;
State = prim.PrimData.State;
LastAttachPoint = prim.PrimData.State;
PathBegin = Primitive.PackBeginCut(prim.PrimData.PathBegin);
PathEnd = Primitive.PackEndCut(prim.PrimData.PathEnd);
PathScaleX = Primitive.PackPathScale(prim.PrimData.PathScaleX);
@@ -583,6 +585,15 @@ namespace OpenSim.Framework
}
}
public byte LastAttachPoint {
get {
return _lastattach;
}
set {
_lastattach = value;
}
}
public ProfileShape ProfileShape {
get {
return _profileShape;

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