Compare commits
511 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5269d77cf9 | ||
|
|
8c8e6220fb | ||
|
|
150860c964 | ||
|
|
0cb1b0bb4a | ||
|
|
56d894ae24 | ||
|
|
b34fd50155 | ||
|
|
74486e767d | ||
|
|
1b8814878d | ||
|
|
095375d63d | ||
|
|
cb4e074a8c | ||
|
|
222f844d65 | ||
|
|
bb2a9060f1 | ||
|
|
e21dd88ed5 | ||
|
|
35457448ca | ||
|
|
596caf41db | ||
|
|
c62b46a167 | ||
|
|
2b3098f011 | ||
|
|
74b4efd7f9 | ||
|
|
298c4c0eb5 | ||
|
|
068917bc29 | ||
|
|
d8f1d2892c | ||
|
|
ccf8e89193 | ||
|
|
f17f58ac2a | ||
|
|
6bcb5baab6 | ||
|
|
0aaf935333 | ||
|
|
b30806822e | ||
|
|
a2c3dfc422 | ||
|
|
4050a6f8bb | ||
|
|
0d0d04c484 | ||
|
|
952b3448a6 | ||
|
|
d53ef3b302 | ||
|
|
48e88397a0 | ||
|
|
976190fe96 | ||
|
|
1e025d6074 | ||
|
|
fffd2fe10d | ||
|
|
cf8adbe007 | ||
|
|
890f617e58 | ||
|
|
6ff0e58db7 | ||
|
|
795443cff1 | ||
|
|
8c7f511e55 | ||
|
|
0acac2f890 | ||
|
|
72554fc5b8 | ||
|
|
aa1442b07e | ||
|
|
e8a0ec1287 | ||
|
|
3436be2046 | ||
|
|
9a0bcb7750 | ||
|
|
218fe36f84 | ||
|
|
07298c8b4f | ||
|
|
d9f40d1ebc | ||
|
|
eddff428ed | ||
|
|
61aaa10460 | ||
|
|
e1d6929e61 | ||
|
|
6b87873aa7 | ||
|
|
f690acbfb6 | ||
|
|
f49c850269 | ||
|
|
70f85af75b | ||
|
|
663b0cc681 | ||
|
|
733a8c9f89 | ||
|
|
25109c8e4d | ||
|
|
51724128bf | ||
|
|
461831a65e | ||
|
|
c6fa09c3af | ||
|
|
9ccf56eaae | ||
|
|
ea9b0794e0 | ||
|
|
96191241be | ||
|
|
779f0ede49 | ||
|
|
e511106d8d | ||
|
|
37f22e2946 | ||
|
|
b802906827 | ||
|
|
c6fb5f0fe4 | ||
|
|
8909e70fc3 | ||
|
|
78fcee1f4b | ||
|
|
3106a0f25e | ||
|
|
19c2f08a8b | ||
|
|
005ca12a99 | ||
|
|
02fe1a676e | ||
|
|
03fc8cf155 | ||
|
|
8dedd91961 | ||
|
|
0ac040d9ca | ||
|
|
c5e5308120 | ||
|
|
1cfaacb88b | ||
|
|
689cafec63 | ||
|
|
d4cd9e050b | ||
|
|
472785a5e8 | ||
|
|
da28fcd357 | ||
|
|
1999338773 | ||
|
|
95670d2086 | ||
|
|
af2c48449c | ||
|
|
ffc6110edf | ||
|
|
1edd1f93c1 | ||
|
|
b6e42da21a | ||
|
|
2e0402433d | ||
|
|
d19600e257 | ||
|
|
a6d97e6353 | ||
|
|
8eb39eb3ac | ||
|
|
553ac6335d | ||
|
|
32a2515817 | ||
|
|
a0482bccc7 | ||
|
|
3291e256ba | ||
|
|
fb7573f713 | ||
|
|
4684207d6e | ||
|
|
499b778391 | ||
|
|
9779ceded5 | ||
|
|
512d0ac411 | ||
|
|
981c7d63a0 | ||
|
|
7bd1601a3f | ||
|
|
3aef006e78 | ||
|
|
9a6aa528db | ||
|
|
02a163848c | ||
|
|
b9f122be07 | ||
|
|
e64ca361df | ||
|
|
8a11c4e7d4 | ||
|
|
584a076bec | ||
|
|
88596d6097 | ||
|
|
84d97b3bc0 | ||
|
|
2b4e97eeaf | ||
|
|
a544280ef2 | ||
|
|
3a0f9836f3 | ||
|
|
4bfac5688d | ||
|
|
0fb93042c6 | ||
|
|
a3586a7c4b | ||
|
|
d4ff56710b | ||
|
|
6219c137e1 | ||
|
|
da3877a77d | ||
|
|
10ed7e3bbc | ||
|
|
f248f8bf31 | ||
|
|
6f2031001b | ||
|
|
1c5ad8e9ab | ||
|
|
d8d8b8fc9b | ||
|
|
719efdaf1f | ||
|
|
6a8e3907ca | ||
|
|
5a1b8fc6f7 | ||
|
|
00ac962db7 | ||
|
|
cb518ad68c | ||
|
|
4859bc8c49 | ||
|
|
196e014782 | ||
|
|
c6ffaaa959 | ||
|
|
c3104f4bd2 | ||
|
|
d8c40ca462 | ||
|
|
48f47bb4c7 | ||
|
|
8db6edbe87 | ||
|
|
a57b78b44b | ||
|
|
280d005d55 | ||
|
|
61e7d4a0e2 | ||
|
|
3e75083d2d | ||
|
|
3d400dd677 | ||
|
|
1fbb0f97bf | ||
|
|
4968191c1e | ||
|
|
8889309324 | ||
|
|
27a7ba3e6a | ||
|
|
2d16d14ef1 | ||
|
|
f2f8dcd65c | ||
|
|
332f8b6623 | ||
|
|
4eda679e12 | ||
|
|
498154af80 | ||
|
|
ba0ebe6d75 | ||
|
|
28f93512bc | ||
|
|
78c2ef2346 | ||
|
|
d30d68657e | ||
|
|
3a27f656b3 | ||
|
|
cc27a6cb84 | ||
|
|
ed21576ce0 | ||
|
|
9d9e042b4c | ||
|
|
4fb8d5cfba | ||
|
|
896c4b6248 | ||
|
|
f6730da13a | ||
|
|
41d98916df | ||
|
|
771539a4e0 | ||
|
|
27c62bba99 | ||
|
|
93e053a122 | ||
|
|
eb022f4cc1 | ||
|
|
83542034dd | ||
|
|
627382f702 | ||
|
|
2eb563b3bb | ||
|
|
54a23f14d5 | ||
|
|
e8059b74f8 | ||
|
|
075909520a | ||
|
|
808bf12cd5 | ||
|
|
0f39f41317 | ||
|
|
f23b7ae3e9 | ||
|
|
5e4b09fc22 | ||
|
|
25ab7841b7 | ||
|
|
0c0e575379 | ||
|
|
68946bffae | ||
|
|
2fc461d9ab | ||
|
|
59a48d9ebb | ||
|
|
533d1ea20c | ||
|
|
dca1ca1d07 | ||
|
|
20a3907e86 | ||
|
|
7358e5748d | ||
|
|
a1b64db942 | ||
|
|
4d44f2d248 | ||
|
|
67abbcf269 | ||
|
|
6b819a9032 | ||
|
|
2021a8aedb | ||
|
|
58dc175ae3 | ||
|
|
4ad6763956 | ||
|
|
702826b850 | ||
|
|
8d30a1f74b | ||
|
|
1a988ba835 | ||
|
|
c422f852a6 | ||
|
|
bcacdb3352 | ||
|
|
cd61567de8 | ||
|
|
5c48c3c57a | ||
|
|
7692ccc0cc | ||
|
|
17cc7e85e2 | ||
|
|
96b3e1d0fa | ||
|
|
dc3cfcbe69 | ||
|
|
1ca1f80eac | ||
|
|
afe2b437bc | ||
|
|
dff71c1aa9 | ||
|
|
7f9a025e30 | ||
|
|
a0ac284a11 | ||
|
|
5341036261 | ||
|
|
46a6cab307 | ||
|
|
edb17d1aac | ||
|
|
dd05e96066 | ||
|
|
ed0878ca23 | ||
|
|
54c222be26 | ||
|
|
80d139297a | ||
|
|
8e6459f616 | ||
|
|
ba909cb692 | ||
|
|
96b964f7fa | ||
|
|
7bbab2f1d5 | ||
|
|
e5f3af4abe | ||
|
|
452538c6b0 | ||
|
|
5c828724f3 | ||
|
|
6538dd24bb | ||
|
|
996abe1ea5 | ||
|
|
f421e0c3d1 | ||
|
|
e4eaca5f9b | ||
|
|
ef5925fa18 | ||
|
|
bae48a9394 | ||
|
|
c813ed44d8 | ||
|
|
885bec68bd | ||
|
|
b553a05db3 | ||
|
|
5473c4f8cc | ||
|
|
0d73f81fb5 | ||
|
|
66c204b983 | ||
|
|
afb0600621 | ||
|
|
a13f2c6985 | ||
|
|
17c7ef06ba | ||
|
|
4933ce49b6 | ||
|
|
5cec1fa50a | ||
|
|
debd83b06a | ||
|
|
f01618ad1a | ||
|
|
cfc1dba99b | ||
|
|
529a3f2400 | ||
|
|
7c1abc5225 | ||
|
|
ca22b5e2f0 | ||
|
|
9ec74f2098 | ||
|
|
cb4ae39cb9 | ||
|
|
802488814f | ||
|
|
53aa48b42c | ||
|
|
b33801f854 | ||
|
|
fc88ce0615 | ||
|
|
28daec7f4e | ||
|
|
f25efa291d | ||
|
|
5ed0559cf2 | ||
|
|
8c1e549c12 | ||
|
|
796334c5ff | ||
|
|
2e1c2e1261 | ||
|
|
a896aac4bd | ||
|
|
80030d3f15 | ||
|
|
4eba4a37ed | ||
|
|
dd0858e204 | ||
|
|
25fa6ee699 | ||
|
|
84dfffe0aa | ||
|
|
aba803c447 | ||
|
|
79aae63aff | ||
|
|
59e93b8ee3 | ||
|
|
e0e63f312f | ||
|
|
d453372f4e | ||
|
|
0f5a77c5bd | ||
|
|
0c96d7ea5c | ||
|
|
4b947cd6d3 | ||
|
|
ca586ca809 | ||
|
|
880358f46b | ||
|
|
3393babb7d | ||
|
|
c3ae90c067 | ||
|
|
25983f20a0 | ||
|
|
1441758bc6 | ||
|
|
c7bbeb4490 | ||
|
|
6145f90423 | ||
|
|
2e397d1514 | ||
|
|
a5d0a29dd9 | ||
|
|
de843fd0a8 | ||
|
|
ced4eeddcf | ||
|
|
093910e90e | ||
|
|
37685ec1b4 | ||
|
|
ccd7d35b3f | ||
|
|
de7e0d7e52 | ||
|
|
89ee03a24d | ||
|
|
79d1d3ca55 | ||
|
|
675c208c7e | ||
|
|
b3307850ab | ||
|
|
eaa840dbd9 | ||
|
|
f64089fa6c | ||
|
|
5157d2023d | ||
|
|
2cd927bb14 | ||
|
|
2889961622 | ||
|
|
232f59749e | ||
|
|
d368a10cc7 | ||
|
|
139b848774 | ||
|
|
74a5226af5 | ||
|
|
c7ddc7a633 | ||
|
|
265707d21c | ||
|
|
eb39d1c4d4 | ||
|
|
1197d48fc7 | ||
|
|
23e1a55ed5 | ||
|
|
ba2a539603 | ||
|
|
8a8093d8dd | ||
|
|
3fb0103452 | ||
|
|
aeefdaedc7 | ||
|
|
756d1f917f | ||
|
|
6fa3dffad2 | ||
|
|
123e781cb3 | ||
|
|
ed9bf5b0c6 | ||
|
|
dd4e39ca1d | ||
|
|
5a551b074b | ||
|
|
c1a9355865 | ||
|
|
3ea6c25fb6 | ||
|
|
2d3135448c | ||
|
|
36a99af37c | ||
|
|
2aefd15913 | ||
|
|
6bc55b1086 | ||
|
|
7058ce2c70 | ||
|
|
8e111e9018 | ||
|
|
d8bd7ca436 | ||
|
|
392f73a000 | ||
|
|
67efbaf33b | ||
|
|
0d06740148 | ||
|
|
eda6947a22 | ||
|
|
f331173145 | ||
|
|
a666cd9e1f | ||
|
|
2657aa6987 | ||
|
|
6610cd2332 | ||
|
|
0c8b44d514 | ||
|
|
ec46ff4445 | ||
|
|
db891880e6 | ||
|
|
9c433e8c50 | ||
|
|
5141863ae3 | ||
|
|
d23550dea5 | ||
|
|
c3b12510ae | ||
|
|
b2685e3671 | ||
|
|
601d2ddbf3 | ||
|
|
a5e8fe70af | ||
|
|
9b3a96aa81 | ||
|
|
d674e815bd | ||
|
|
c2e696d686 | ||
|
|
411dbb8df4 | ||
|
|
b22dfbbf15 | ||
|
|
4c39a3fdbf | ||
|
|
f3eb366f24 | ||
|
|
a20d1b8f6b | ||
|
|
0a51289332 | ||
|
|
97ebfb00b4 | ||
|
|
c7d664f9d0 | ||
|
|
c2fbaaa95d | ||
|
|
84d4b390f1 | ||
|
|
54e59099b7 | ||
|
|
d9585ba37e | ||
|
|
45c617b5c3 | ||
|
|
4b0c78c64f | ||
|
|
dd36e23a62 | ||
|
|
e2dade05d9 | ||
|
|
fbd61106cb | ||
|
|
67e66a2d34 | ||
|
|
59911963ca | ||
|
|
dc2a4a6ccd | ||
|
|
81fb0b4f07 | ||
|
|
a06c8fb7b2 | ||
|
|
05e70f76a9 | ||
|
|
b9f4836d3e | ||
|
|
ef77dc932b | ||
|
|
bd5b1d4d48 | ||
|
|
5c2ffa260c | ||
|
|
23d04fa25c | ||
|
|
67dbce4512 | ||
|
|
46170fd0d8 | ||
|
|
f85a453dc8 | ||
|
|
bcfe48e05b | ||
|
|
722ca250ea | ||
|
|
f4df128e52 | ||
|
|
8cc5322b39 | ||
|
|
1480845597 | ||
|
|
c877e73463 | ||
|
|
3ce5e8eb6c | ||
|
|
e6b12e1f9d | ||
|
|
bfbbd4ccba | ||
|
|
fec7016665 | ||
|
|
47fe6170b2 | ||
|
|
24b5fb8523 | ||
|
|
e8cd9688ce | ||
|
|
fa952f6d35 | ||
|
|
df55fd69af | ||
|
|
019fc4c1f2 | ||
|
|
22ea441feb | ||
|
|
9f5b33e52e | ||
|
|
92837c4f89 | ||
|
|
68ce06f40f | ||
|
|
279b31c75b | ||
|
|
3117b3cd88 | ||
|
|
9b547f76e7 | ||
|
|
3d6675784a | ||
|
|
26f50eadd1 | ||
|
|
6e8496ffc5 | ||
|
|
88d6c4ec0e | ||
|
|
135eeb45d6 | ||
|
|
54ee59c0bb | ||
|
|
4a5c61a33d | ||
|
|
179c0f5f56 | ||
|
|
4dbf937707 | ||
|
|
9edb57e5e9 | ||
|
|
4d15ad63bf | ||
|
|
4021709371 | ||
|
|
3c13f5c3aa | ||
|
|
381517b451 | ||
|
|
6ecf36d49c | ||
|
|
64eb4b8408 | ||
|
|
318da3fdcd | ||
|
|
50c99fcda6 | ||
|
|
321de1f263 | ||
|
|
fa30ace67d | ||
|
|
92baa79253 | ||
|
|
e861b45313 | ||
|
|
cf91ac68b6 | ||
|
|
d4aba13526 | ||
|
|
d36c7c3782 | ||
|
|
4385fcdeae | ||
|
|
04eb170624 | ||
|
|
4803686078 | ||
|
|
20b0fda3bb | ||
|
|
4e5f823595 | ||
|
|
a74408d1d2 | ||
|
|
8206537efd | ||
|
|
a9a77bb3ab | ||
|
|
6390de689d | ||
|
|
41ce19836b | ||
|
|
883a4f6fff | ||
|
|
5f1da80fc1 | ||
|
|
64217d67f6 | ||
|
|
b01c79354c | ||
|
|
9ecbcb787c | ||
|
|
e17e376b04 | ||
|
|
1b4ea4f178 | ||
|
|
1de29fb362 | ||
|
|
7e4bd492fd | ||
|
|
588d56503d | ||
|
|
e9602656f8 | ||
|
|
0116d418f0 | ||
|
|
9992974c66 | ||
|
|
ba27d8a389 | ||
|
|
f96e985763 | ||
|
|
5b9eaae50d | ||
|
|
74a13f7e3b | ||
|
|
3e88fc8aad | ||
|
|
881740d702 | ||
|
|
9a643a1bb9 | ||
|
|
a5488650ff | ||
|
|
a275127a65 | ||
|
|
02db31db6a | ||
|
|
8bd813e6fc | ||
|
|
09ff121654 | ||
|
|
0434758a0d | ||
|
|
8bb0a71083 | ||
|
|
d7651a389e | ||
|
|
824318a0c1 | ||
|
|
5e9ed22e84 | ||
|
|
a6c611e7c9 | ||
|
|
72b325f8b5 | ||
|
|
54d0514b13 | ||
|
|
58b1c3cec0 | ||
|
|
71641523a3 | ||
|
|
94c5e25c3b | ||
|
|
20bad0aa6c | ||
|
|
e7f23a6218 | ||
|
|
25c29db8b6 | ||
|
|
1750fba9ce | ||
|
|
b18e410586 | ||
|
|
38d5e1fab3 | ||
|
|
4180c32eb1 | ||
|
|
5115229fdf | ||
|
|
e8f2d814e7 | ||
|
|
1fda8c5a86 | ||
|
|
6b77b55d40 | ||
|
|
82cdb08c1f | ||
|
|
dafcb3bcd7 | ||
|
|
3259b1d1e0 | ||
|
|
512910a51f | ||
|
|
fdda57cf10 | ||
|
|
ec8e34950d | ||
|
|
93964ef3a4 | ||
|
|
5c8af6a136 | ||
|
|
4d0c8aca05 | ||
|
|
8fc16ece96 | ||
|
|
fcbb375e8f | ||
|
|
49c65279fa | ||
|
|
86e8a56fe1 | ||
|
|
b199330682 | ||
|
|
7a7ebaebd1 | ||
|
|
164ae0b24b | ||
|
|
7156545fca | ||
|
|
73a5abf4d9 | ||
|
|
630c8dc828 | ||
|
|
6de89246c2 | ||
|
|
96973a5778 | ||
|
|
96843f2b17 | ||
|
|
8a36f54cf4 | ||
|
|
1a14e660d2 | ||
|
|
2502aae5db |
@@ -8,6 +8,24 @@
|
||||
<copy file="bin/OpenSim.ini.example" tofile="bin/OpenSim.ini"/>
|
||||
<copy file="bin/config-include/StandaloneCommon.ini.example" tofile="bin/config-include/StandaloneCommon.ini"/>
|
||||
<copy file="bin/config-include/FlotsamCache.ini.example" tofile="bin/config-include/FlotsamCache.ini"/>
|
||||
<!-- delete files generated by runprebuild.sh which had to be run in order to generate the build file for this target-->
|
||||
<delete>
|
||||
<fileset basedir="OpenSim">
|
||||
<include name="**/*.build"/>
|
||||
<include name="**/*.csproj*"/>
|
||||
<include name="**/*.dll.build"/>
|
||||
<include name="**/*.pidb"/>
|
||||
<exclude name="Tools/OpenSim.32BitLaunch/**"/>
|
||||
<exclude name="Tools/Robust.32BitLaunch/**"/>
|
||||
<exclude name="Tools/LaunchSLClient/**"/>
|
||||
</fileset>
|
||||
</delete>
|
||||
<delete>
|
||||
<fileset>
|
||||
<include name="OpenSim.build"/>
|
||||
<include name="OpenSim.sln"/>
|
||||
</fileset>
|
||||
</delete>
|
||||
</target>
|
||||
|
||||
<property name="distbindir" value="distbin" />
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
The following people have contributed to OpenSim (Thank you
|
||||
<<<>>>>The following people have contributed to OpenSim (Thank you
|
||||
for your effort!)
|
||||
|
||||
= Current OpenSim Developers (in very rough order of appearance) =
|
||||
@@ -139,6 +139,9 @@ what it is today.
|
||||
* SignpostMarv
|
||||
* SpotOn3D
|
||||
* Strawberry Fride
|
||||
* Talun
|
||||
* TechplexEngineer (Blake Bourque)
|
||||
* TBG Renfold
|
||||
* tglion
|
||||
* tlaukkan/Tommil (Tommi S. E. Laukkanen, Bubble Cloud)
|
||||
* tyre
|
||||
|
||||
@@ -539,7 +539,6 @@ namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||
/// path has not already been registered, the method is added to the active
|
||||
/// handler table.
|
||||
/// </summary>
|
||||
|
||||
public void AddStreamHandler(string httpMethod, string path, RestMethod method)
|
||||
{
|
||||
if (!IsEnabled)
|
||||
|
||||
@@ -101,18 +101,8 @@ namespace OpenSim.Capabilities.Handlers
|
||||
llsdItem.item_id = invItem.ID;
|
||||
llsdItem.name = invItem.Name;
|
||||
llsdItem.parent_id = invItem.Folder;
|
||||
|
||||
try
|
||||
{
|
||||
llsdItem.type = Utils.AssetTypeToString((AssetType)invItem.AssetType);
|
||||
llsdItem.inv_type = Utils.InventoryTypeToString((InventoryType)invItem.InvType);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[WEB FETCH INV DESC HANDLER]: Problem setting asset {0} inventory {1} types while converting inventory item {2}: {3}",
|
||||
invItem.AssetType, invItem.InvType, invItem.Name, e.Message);
|
||||
}
|
||||
llsdItem.type = invItem.AssetType;
|
||||
llsdItem.inv_type = invItem.InvType;
|
||||
|
||||
llsdItem.permissions = new LLSDPermissions();
|
||||
llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid;
|
||||
@@ -126,21 +116,7 @@ namespace OpenSim.Capabilities.Handlers
|
||||
llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions;
|
||||
llsdItem.sale_info = new LLSDSaleInfo();
|
||||
llsdItem.sale_info.sale_price = invItem.SalePrice;
|
||||
switch (invItem.SaleType)
|
||||
{
|
||||
default:
|
||||
llsdItem.sale_info.sale_type = "not";
|
||||
break;
|
||||
case 1:
|
||||
llsdItem.sale_info.sale_type = "original";
|
||||
break;
|
||||
case 2:
|
||||
llsdItem.sale_info.sale_type = "copy";
|
||||
break;
|
||||
case 3:
|
||||
llsdItem.sale_info.sale_type = "contents";
|
||||
break;
|
||||
}
|
||||
llsdItem.sale_info.sale_type = invItem.SaleType;
|
||||
|
||||
return llsdItem;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,8 @@ namespace OpenSim.Capabilities.Handlers
|
||||
|
||||
FetchInventory2Handler fiHandler = new FetchInventory2Handler(m_InventoryService);
|
||||
IRequestHandler reqHandler
|
||||
= new RestStreamHandler("POST", "/CAPS/FetchInventory/", fiHandler.FetchInventoryRequest);
|
||||
= new RestStreamHandler(
|
||||
"POST", "/CAPS/FetchInventory/", fiHandler.FetchInventoryRequest, "FetchInventory", null);
|
||||
server.AddStreamHandler(reqHandler);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,13 +66,14 @@ namespace OpenSim.Capabilities.Handlers
|
||||
throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName));
|
||||
|
||||
GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService);
|
||||
IRequestHandler reqHandler = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(),
|
||||
delegate(Hashtable m_dhttpMethod)
|
||||
{
|
||||
return gmeshHandler.ProcessGetMesh(m_dhttpMethod, UUID.Zero, null);
|
||||
});
|
||||
IRequestHandler reqHandler
|
||||
= new RestHTTPHandler(
|
||||
"GET",
|
||||
"/CAPS/" + UUID.Random(),
|
||||
httpMethod => gmeshHandler.ProcessGetMesh(httpMethod, UUID.Zero, null),
|
||||
"GetMesh",
|
||||
null);
|
||||
server.AddStreamHandler(reqHandler);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,8 +58,8 @@ namespace OpenSim.Capabilities.Handlers
|
||||
// TODO: Change this to a config option
|
||||
const string REDIRECT_URL = null;
|
||||
|
||||
public GetTextureHandler(string path, IAssetService assService) :
|
||||
base("GET", path)
|
||||
public GetTextureHandler(string path, IAssetService assService, string name, string description)
|
||||
: base("GET", path, name, description)
|
||||
{
|
||||
m_assetService = assService;
|
||||
}
|
||||
@@ -77,7 +77,6 @@ namespace OpenSim.Capabilities.Handlers
|
||||
{
|
||||
m_log.Error("[GETTEXTURE]: Cannot fetch texture " + textureStr + " without an asset service");
|
||||
httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
|
||||
return null;
|
||||
}
|
||||
|
||||
UUID textureID;
|
||||
@@ -115,7 +114,6 @@ namespace OpenSim.Capabilities.Handlers
|
||||
// "[GETTEXTURE]: For texture {0} sending back response {1}, data length {2}",
|
||||
// textureID, httpResponse.StatusCode, httpResponse.ContentLength);
|
||||
|
||||
httpResponse.Send();
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -62,8 +62,8 @@ namespace OpenSim.Capabilities.Handlers
|
||||
if (m_AssetService == null)
|
||||
throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName));
|
||||
|
||||
server.AddStreamHandler(new GetTextureHandler("/CAPS/GetTexture/" /*+ UUID.Random() */, m_AssetService));
|
||||
server.AddStreamHandler(
|
||||
new GetTextureHandler("/CAPS/GetTexture/" /*+ UUID.Random() */, m_AssetService, "GetTexture", null));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -50,9 +50,9 @@ namespace OpenSim.Capabilities.Handlers.GetTexture.Tests
|
||||
TestHelpers.InMethod();
|
||||
|
||||
// Overkill - we only really need the asset service, not a whole scene.
|
||||
Scene scene = SceneHelpers.SetupScene();
|
||||
Scene scene = new SceneHelpers().SetupScene();
|
||||
|
||||
GetTextureHandler handler = new GetTextureHandler(null, scene.AssetService);
|
||||
GetTextureHandler handler = new GetTextureHandler(null, scene.AssetService, "TestGetTexture", null);
|
||||
TestOSHttpRequest req = new TestOSHttpRequest();
|
||||
TestOSHttpResponse resp = new TestOSHttpResponse();
|
||||
req.Url = new Uri("http://localhost/?texture_id=00000000-0000-1111-9999-000000000012");
|
||||
|
||||
@@ -85,8 +85,8 @@ namespace OpenSim.Capabilities.Handlers
|
||||
uploader.OnUpLoad += BakedTextureUploaded;
|
||||
|
||||
m_HostCapsObj.HttpListener.AddStreamHandler(
|
||||
new BinaryStreamHandler("POST", capsBase + uploaderPath,
|
||||
uploader.uploaderCaps));
|
||||
new BinaryStreamHandler(
|
||||
"POST", capsBase + uploaderPath, uploader.uploaderCaps, "UploadBakedTexture", null));
|
||||
|
||||
string protocol = "http://";
|
||||
|
||||
|
||||
@@ -156,11 +156,12 @@ namespace OpenSim.Capabilities.Handlers
|
||||
inv.Folders = new List<InventoryFolderBase>();
|
||||
inv.Items = new List<InventoryItemBase>();
|
||||
int version = 0;
|
||||
int descendents = 0;
|
||||
|
||||
inv
|
||||
= Fetch(
|
||||
invFetch.owner_id, invFetch.folder_id, invFetch.owner_id,
|
||||
invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version);
|
||||
invFetch.fetch_folders, invFetch.fetch_items, invFetch.sort_order, out version, out descendents);
|
||||
|
||||
if (inv.Folders != null)
|
||||
{
|
||||
@@ -168,6 +169,8 @@ namespace OpenSim.Capabilities.Handlers
|
||||
{
|
||||
contents.categories.Array.Add(ConvertInventoryFolder(invFolder));
|
||||
}
|
||||
|
||||
descendents += inv.Folders.Count;
|
||||
}
|
||||
|
||||
if (inv.Items != null)
|
||||
@@ -178,7 +181,7 @@ namespace OpenSim.Capabilities.Handlers
|
||||
}
|
||||
}
|
||||
|
||||
contents.descendents = contents.items.Array.Count + contents.categories.Array.Count;
|
||||
contents.descendents = descendents;
|
||||
contents.version = version;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
@@ -206,7 +209,7 @@ namespace OpenSim.Capabilities.Handlers
|
||||
/// <returns>An empty InventoryCollection if the inventory look up failed</returns>
|
||||
private InventoryCollection Fetch(
|
||||
UUID agentID, UUID folderID, UUID ownerID,
|
||||
bool fetchFolders, bool fetchItems, int sortOrder, out int version)
|
||||
bool fetchFolders, bool fetchItems, int sortOrder, out int version, out int descendents)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Fetching folders ({0}), items ({1}) from {2} for agent {3}",
|
||||
@@ -215,6 +218,8 @@ namespace OpenSim.Capabilities.Handlers
|
||||
// FIXME MAYBE: We're not handling sortOrder!
|
||||
|
||||
version = 0;
|
||||
descendents = 0;
|
||||
|
||||
InventoryFolderImpl fold;
|
||||
if (m_LibraryService != null && m_LibraryService.LibraryRootFolder != null && agentID == m_LibraryService.LibraryRootFolder.Owner)
|
||||
{
|
||||
@@ -223,6 +228,7 @@ namespace OpenSim.Capabilities.Handlers
|
||||
InventoryCollection ret = new InventoryCollection();
|
||||
ret.Folders = new List<InventoryFolderBase>();
|
||||
ret.Items = fold.RequestListOfItems();
|
||||
descendents = ret.Folders.Count + ret.Items.Count;
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -246,24 +252,72 @@ namespace OpenSim.Capabilities.Handlers
|
||||
|
||||
version = containingFolder.Version;
|
||||
|
||||
// if (fetchItems)
|
||||
if (fetchItems)
|
||||
{
|
||||
List<InventoryItemBase> itemsToReturn = contents.Items;
|
||||
List<InventoryItemBase> originalItems = new List<InventoryItemBase>(itemsToReturn);
|
||||
|
||||
// descendents must only include the links, not the linked items we add
|
||||
descendents = originalItems.Count;
|
||||
|
||||
// Add target items for links in this folder before the links themselves.
|
||||
foreach (InventoryItemBase item in originalItems)
|
||||
{
|
||||
if (item.AssetType == (int)AssetType.Link)
|
||||
{
|
||||
InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID));
|
||||
|
||||
// Take care of genuinely broken links where the target doesn't exist
|
||||
// HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
|
||||
// but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
|
||||
// rather than having to keep track of every folder requested in the recursion.
|
||||
if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link)
|
||||
itemsToReturn.Insert(0, linkedItem);
|
||||
}
|
||||
}
|
||||
|
||||
// Now scan for folder links and insert the items they target and those links at the head of the return data
|
||||
foreach (InventoryItemBase item in originalItems)
|
||||
{
|
||||
if (item.AssetType == (int)AssetType.LinkFolder)
|
||||
{
|
||||
InventoryCollection linkedFolderContents = m_InventoryService.GetFolderContent(ownerID, item.AssetID);
|
||||
List<InventoryItemBase> links = linkedFolderContents.Items;
|
||||
|
||||
itemsToReturn.InsertRange(0, links);
|
||||
|
||||
foreach (InventoryItemBase link in linkedFolderContents.Items)
|
||||
{
|
||||
// Take care of genuinely broken links where the target doesn't exist
|
||||
// HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
|
||||
// but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
|
||||
// rather than having to keep track of every folder requested in the recursion.
|
||||
if (link != null)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Adding item {0} {1} from folder {2} linked from {3}",
|
||||
// link.Name, (AssetType)link.AssetType, item.AssetID, containingFolder.Name);
|
||||
|
||||
InventoryItemBase linkedItem
|
||||
= m_InventoryService.GetItem(new InventoryItemBase(link.AssetID));
|
||||
|
||||
if (linkedItem != null)
|
||||
itemsToReturn.Insert(0, linkedItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// foreach (InventoryItemBase item in contents.Items)
|
||||
// {
|
||||
// List<InventoryItemBase> linkedItemsToAdd = new List<InventoryItemBase>();
|
||||
//
|
||||
// foreach (InventoryItemBase item in contents.Items)
|
||||
// {
|
||||
// if (item.AssetType == (int)AssetType.Link)
|
||||
// {
|
||||
// InventoryItemBase linkedItem = m_InventoryService.GetItem(new InventoryItemBase(item.AssetID));
|
||||
//
|
||||
// // Take care of genuinely broken links where the target doesn't exist
|
||||
// // HACK: Also, don't follow up links that just point to other links. In theory this is legitimate,
|
||||
// // but no viewer has been observed to set these up and this is the lazy way of avoiding cycles
|
||||
// // rather than having to keep track of every folder requested in the recursion.
|
||||
// if (linkedItem != null && linkedItem.AssetType != (int)AssetType.Link)
|
||||
// linkedItemsToAdd.Insert(0, linkedItem);
|
||||
// }
|
||||
// }
|
||||
// m_log.DebugFormat(
|
||||
// "[WEB FETCH INV DESC HANDLER]: Returning item {0}, type {1}, parent {2} in {3} {4}",
|
||||
// item.Name, (AssetType)item.AssetType, item.Folder, containingFolder.Name, containingFolder.ID);
|
||||
// }
|
||||
|
||||
// =====
|
||||
|
||||
//
|
||||
// foreach (InventoryItemBase linkedItem in linkedItemsToAdd)
|
||||
// {
|
||||
@@ -340,12 +394,8 @@ namespace OpenSim.Capabilities.Handlers
|
||||
llsdFolder.folder_id = invFolder.ID;
|
||||
llsdFolder.parent_id = invFolder.ParentID;
|
||||
llsdFolder.name = invFolder.Name;
|
||||
|
||||
if (invFolder.Type == (short)AssetType.Unknown || !Enum.IsDefined(typeof(AssetType), (sbyte)invFolder.Type))
|
||||
llsdFolder.type = "-1";
|
||||
else
|
||||
llsdFolder.type = Utils.AssetTypeToString((AssetType)invFolder.Type);
|
||||
llsdFolder.preferred_type = "-1";
|
||||
llsdFolder.type = invFolder.Type;
|
||||
llsdFolder.preferred_type = -1;
|
||||
|
||||
return llsdFolder;
|
||||
}
|
||||
@@ -365,18 +415,8 @@ namespace OpenSim.Capabilities.Handlers
|
||||
llsdItem.item_id = invItem.ID;
|
||||
llsdItem.name = invItem.Name;
|
||||
llsdItem.parent_id = invItem.Folder;
|
||||
|
||||
try
|
||||
{
|
||||
llsdItem.type = Utils.AssetTypeToString((AssetType)invItem.AssetType);
|
||||
llsdItem.inv_type = Utils.InventoryTypeToString((InventoryType)invItem.InvType);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[WEB FETCH INV DESC HANDLER]: Problem setting asset {0} inventory {1} types while converting inventory item {2}: {3}",
|
||||
invItem.AssetType, invItem.InvType, invItem.Name, e.Message);
|
||||
}
|
||||
llsdItem.type = invItem.AssetType;
|
||||
llsdItem.inv_type = invItem.InvType;
|
||||
|
||||
llsdItem.permissions = new LLSDPermissions();
|
||||
llsdItem.permissions.creator_id = invItem.CreatorIdAsUuid;
|
||||
@@ -390,21 +430,7 @@ namespace OpenSim.Capabilities.Handlers
|
||||
llsdItem.permissions.owner_mask = (int)invItem.CurrentPermissions;
|
||||
llsdItem.sale_info = new LLSDSaleInfo();
|
||||
llsdItem.sale_info.sale_price = invItem.SalePrice;
|
||||
switch (invItem.SaleType)
|
||||
{
|
||||
default:
|
||||
llsdItem.sale_info.sale_type = "not";
|
||||
break;
|
||||
case 1:
|
||||
llsdItem.sale_info.sale_type = "original";
|
||||
break;
|
||||
case 2:
|
||||
llsdItem.sale_info.sale_type = "copy";
|
||||
break;
|
||||
case 3:
|
||||
llsdItem.sale_info.sale_type = "contents";
|
||||
break;
|
||||
}
|
||||
llsdItem.sale_info.sale_type = invItem.SaleType;
|
||||
|
||||
return llsdItem;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,13 @@ namespace OpenSim.Capabilities.Handlers
|
||||
ServerUtils.LoadPlugin<ILibraryService>(libService, args);
|
||||
|
||||
WebFetchInvDescHandler webFetchHandler = new WebFetchInvDescHandler(m_InventoryService, m_LibraryService);
|
||||
IRequestHandler reqHandler = new RestStreamHandler("POST", "/CAPS/WebFetchInvDesc/" /*+ UUID.Random()*/, webFetchHandler.FetchInventoryDescendentsRequest);
|
||||
IRequestHandler reqHandler
|
||||
= new RestStreamHandler(
|
||||
"POST",
|
||||
"/CAPS/WebFetchInvDesc/" /*+ UUID.Random()*/,
|
||||
webFetchHandler.FetchInventoryDescendentsRequest,
|
||||
"WebFetchInvDesc",
|
||||
null);
|
||||
server.AddStreamHandler(reqHandler);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace OpenSim.Framework.Capabilities
|
||||
public UUID folder_id;
|
||||
public UUID parent_id;
|
||||
public string name;
|
||||
public string type;
|
||||
public string preferred_type;
|
||||
public int type;
|
||||
public int preferred_type;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,8 +37,8 @@ namespace OpenSim.Framework.Capabilities
|
||||
public UUID asset_id;
|
||||
public UUID item_id;
|
||||
public LLSDPermissions permissions;
|
||||
public string type;
|
||||
public string inv_type;
|
||||
public int type;
|
||||
public int inv_type;
|
||||
public int flags;
|
||||
|
||||
public LLSDSaleInfo sale_info;
|
||||
@@ -65,7 +65,7 @@ namespace OpenSim.Framework.Capabilities
|
||||
public class LLSDSaleInfo
|
||||
{
|
||||
public int sale_price;
|
||||
public string sale_type;
|
||||
public int sale_type;
|
||||
}
|
||||
|
||||
[OSDMap]
|
||||
|
||||
@@ -39,7 +39,11 @@ namespace OpenSim.Framework.Capabilities
|
||||
private LLSDMethod<TRequest, TResponse> m_method;
|
||||
|
||||
public LLSDStreamhandler(string httpMethod, string path, LLSDMethod<TRequest, TResponse> method)
|
||||
: base(httpMethod, path)
|
||||
: this(httpMethod, path, method, null, null) {}
|
||||
|
||||
public LLSDStreamhandler(
|
||||
string httpMethod, string path, LLSDMethod<TRequest, TResponse> method, string name, string description)
|
||||
: base(httpMethod, path, name, description)
|
||||
{
|
||||
m_method = method;
|
||||
}
|
||||
|
||||
@@ -89,5 +89,11 @@ namespace OpenSim.Data.MSSQL
|
||||
return DoQuery(cmd);
|
||||
}
|
||||
}
|
||||
|
||||
public FriendsData[] GetFriends(Guid principalID)
|
||||
{
|
||||
return GetFriends(principalID.ToString());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -813,7 +813,7 @@ namespace OpenSim.Data.MSSQL
|
||||
{
|
||||
try
|
||||
{
|
||||
using (SqlCommand command = new SqlCommand("DELETE FROM inventoryfolders WHERE folderID=@folderID", connection))
|
||||
using (SqlCommand command = new SqlCommand("DELETE FROM inventoryfolders WHERE folderID=@folderID and type=-1", connection))
|
||||
{
|
||||
command.Parameters.Add(database.CreateParameter("folderID", folderID));
|
||||
|
||||
|
||||
@@ -675,7 +675,7 @@ VALUES
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
sql = "INSERT INTO [landaccesslist] ([LandUUID],[AccessUUID],[Flags]) VALUES (@LandUUID,@AccessUUID,@Flags)";
|
||||
sql = "INSERT INTO [landaccesslist] ([LandUUID],[AccessUUID],[Flags],[Expires]) VALUES (@LandUUID,@AccessUUID,@Flags,@Expires)";
|
||||
|
||||
using (SqlConnection conn = new SqlConnection(m_connectionString))
|
||||
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||
@@ -1215,6 +1215,8 @@ VALUES
|
||||
//Store new values
|
||||
StoreNewRegionSettings(regionSettings);
|
||||
|
||||
LoadSpawnPoints(regionSettings);
|
||||
|
||||
return regionSettings;
|
||||
}
|
||||
|
||||
@@ -1252,7 +1254,7 @@ VALUES
|
||||
,[elevation_1_ne] = @elevation_1_ne ,[elevation_2_ne] = @elevation_2_ne ,[elevation_1_se] = @elevation_1_se ,[elevation_2_se] = @elevation_2_se
|
||||
,[elevation_1_sw] = @elevation_1_sw ,[elevation_2_sw] = @elevation_2_sw ,[water_height] = @water_height ,[terrain_raise_limit] = @terrain_raise_limit
|
||||
,[terrain_lower_limit] = @terrain_lower_limit ,[use_estate_sun] = @use_estate_sun ,[fixed_sun] = @fixed_sun ,[sun_position] = @sun_position
|
||||
,[covenant] = @covenant ,[covenant_datetime] = @covenant_datetime, [sunvectorx] = @sunvectorx, [sunvectory] = @sunvectory, [sunvectorz] = @sunvectorz, [Sandbox] = @Sandbox, [loaded_creation_datetime] = @loaded_creation_datetime, [loaded_creation_id] = @loaded_creation_id
|
||||
,[covenant] = @covenant ,[covenant_datetime] = @covenant_datetime, [sunvectorx] = @sunvectorx, [sunvectory] = @sunvectory, [sunvectorz] = @sunvectorz, [Sandbox] = @Sandbox, [loaded_creation_datetime] = @loaded_creation_datetime, [loaded_creation_id] = @loaded_creation_id, [map_tile_id] = @TerrainImageID, [telehubobject] = @telehubobject, [parcel_tile_id] = @ParcelImageID
|
||||
WHERE [regionUUID] = @regionUUID";
|
||||
|
||||
using (SqlConnection conn = new SqlConnection(m_connectionString))
|
||||
@@ -1263,6 +1265,7 @@ VALUES
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
SaveSpawnPoints(regionSettings);
|
||||
}
|
||||
|
||||
public void Shutdown()
|
||||
@@ -1383,6 +1386,11 @@ VALUES
|
||||
newSettings.LoadedCreationID = "";
|
||||
else
|
||||
newSettings.LoadedCreationID = (String)row["loaded_creation_id"];
|
||||
|
||||
newSettings.TerrainImageID = new UUID((string)row["map_tile_ID"]);
|
||||
newSettings.ParcelImageID = new UUID((Guid)row["parcel_tile_ID"]);
|
||||
newSettings.TelehubObject = new UUID((Guid)row["TelehubObject"]);
|
||||
|
||||
return newSettings;
|
||||
}
|
||||
|
||||
@@ -1454,6 +1462,13 @@ VALUES
|
||||
}
|
||||
|
||||
newData.ParcelAccessList = new List<LandAccessEntry>();
|
||||
newData.MediaDescription = (string)row["MediaDescription"];
|
||||
newData.MediaType = (string)row["MediaType"];
|
||||
newData.MediaWidth = Convert.ToInt32((((string)row["MediaSize"]).Split(','))[0]);
|
||||
newData.MediaHeight = Convert.ToInt32((((string)row["MediaSize"]).Split(','))[1]);
|
||||
newData.MediaLoop = Convert.ToBoolean(row["MediaLoop"]);
|
||||
newData.ObscureMusic = Convert.ToBoolean(row["ObscureMusic"]);
|
||||
newData.ObscureMedia = Convert.ToBoolean(row["ObscureMedia"]);
|
||||
|
||||
return newData;
|
||||
}
|
||||
@@ -1468,7 +1483,7 @@ VALUES
|
||||
LandAccessEntry entry = new LandAccessEntry();
|
||||
entry.AgentID = new UUID((Guid)row["AccessUUID"]);
|
||||
entry.Flags = (AccessList)Convert.ToInt32(row["Flags"]);
|
||||
entry.Expires = 0;
|
||||
entry.Expires = Convert.ToInt32(row["Expires"]);
|
||||
return entry;
|
||||
}
|
||||
|
||||
@@ -1497,7 +1512,8 @@ VALUES
|
||||
prim.TouchName = (string)primRow["TouchName"];
|
||||
// permissions
|
||||
prim.Flags = (PrimFlags)Convert.ToUInt32(primRow["ObjectFlags"]);
|
||||
prim.CreatorID = new UUID((Guid)primRow["CreatorID"]);
|
||||
//prim.CreatorID = new UUID((Guid)primRow["CreatorID"]);
|
||||
prim.CreatorIdentification = (string)primRow["CreatorID"];
|
||||
prim.OwnerID = new UUID((Guid)primRow["OwnerID"]);
|
||||
prim.GroupID = new UUID((Guid)primRow["GroupID"]);
|
||||
prim.LastOwnerID = new UUID((Guid)primRow["LastOwnerID"]);
|
||||
@@ -1691,7 +1707,8 @@ VALUES
|
||||
taskItem.Name = (string)inventoryRow["name"];
|
||||
taskItem.Description = (string)inventoryRow["description"];
|
||||
taskItem.CreationDate = Convert.ToUInt32(inventoryRow["creationDate"]);
|
||||
taskItem.CreatorID = new UUID((Guid)inventoryRow["creatorID"]);
|
||||
//taskItem.CreatorID = new UUID((Guid)inventoryRow["creatorID"]);
|
||||
taskItem.CreatorIdentification = (string)inventoryRow["creatorID"];
|
||||
taskItem.OwnerID = new UUID((Guid)inventoryRow["ownerID"]);
|
||||
taskItem.LastOwnerID = new UUID((Guid)inventoryRow["lastOwnerID"]);
|
||||
taskItem.GroupID = new UUID((Guid)inventoryRow["groupID"]);
|
||||
@@ -1792,6 +1809,9 @@ VALUES
|
||||
parameters.Add(_Database.CreateParameter("covenant_datetime", settings.CovenantChangedDateTime));
|
||||
parameters.Add(_Database.CreateParameter("Loaded_Creation_DateTime", settings.LoadedCreationDateTime));
|
||||
parameters.Add(_Database.CreateParameter("Loaded_Creation_ID", settings.LoadedCreationID));
|
||||
parameters.Add(_Database.CreateParameter("TerrainImageID", settings.TerrainImageID));
|
||||
parameters.Add(_Database.CreateParameter("ParcelImageID", settings.ParcelImageID));
|
||||
parameters.Add(_Database.CreateParameter("TelehubObject", settings.TelehubObject));
|
||||
|
||||
return parameters.ToArray();
|
||||
}
|
||||
@@ -1859,6 +1879,7 @@ VALUES
|
||||
parameters.Add(_Database.CreateParameter("LandUUID", parcelID));
|
||||
parameters.Add(_Database.CreateParameter("AccessUUID", parcelAccessEntry.AgentID));
|
||||
parameters.Add(_Database.CreateParameter("Flags", parcelAccessEntry.Flags));
|
||||
parameters.Add(_Database.CreateParameter("Expires", parcelAccessEntry.Expires));
|
||||
|
||||
return parameters.ToArray();
|
||||
}
|
||||
@@ -2063,5 +2084,57 @@ VALUES
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
private void LoadSpawnPoints(RegionSettings rs)
|
||||
{
|
||||
rs.ClearSpawnPoints();
|
||||
|
||||
string sql = "SELECT Yaw, Pitch, Distance FROM spawn_points WHERE RegionUUID = @RegionUUID";
|
||||
using (SqlConnection conn = new SqlConnection(m_connectionString))
|
||||
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||
{
|
||||
cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", rs.RegionUUID.ToString()));
|
||||
conn.Open();
|
||||
using (SqlDataReader reader = cmd.ExecuteReader())
|
||||
{
|
||||
if (reader.Read())
|
||||
{
|
||||
SpawnPoint sp = new SpawnPoint();
|
||||
|
||||
sp.Yaw = (float)reader["Yaw"];
|
||||
sp.Pitch = (float)reader["Pitch"];
|
||||
sp.Distance = (float)reader["Distance"];
|
||||
|
||||
rs.AddSpawnPoint(sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveSpawnPoints(RegionSettings rs)
|
||||
{
|
||||
string sql = "DELETE FROM spawn_points WHERE RegionUUID = @RegionUUID";
|
||||
using (SqlConnection conn = new SqlConnection(m_connectionString))
|
||||
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||
{
|
||||
cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", rs.RegionUUID));
|
||||
conn.Open();
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
foreach (SpawnPoint p in rs.SpawnPoints())
|
||||
{
|
||||
sql = "INSERT INTO spawn_points (RegionUUID, Yaw, Pitch, Distance) VALUES (@RegionUUID, @Yaw, @Pitch, @Distance)";
|
||||
using (SqlConnection conn = new SqlConnection(m_connectionString))
|
||||
using (SqlCommand cmd = new SqlCommand(sql, conn))
|
||||
{
|
||||
cmd.Parameters.Add(_Database.CreateParameter("@RegionUUID", rs.RegionUUID));
|
||||
cmd.Parameters.Add(_Database.CreateParameter("@Yaw", p.Yaw));
|
||||
cmd.Parameters.Add(_Database.CreateParameter("@Pitch", p.Pitch));
|
||||
cmd.Parameters.Add(_Database.CreateParameter("@Distance", p.Distance));
|
||||
conn.Open();
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1044,10 +1044,93 @@ ALTER TABLE primitems ALTER COLUMN CreatorID uniqueidentifier NOT NULL
|
||||
|
||||
COMMIT
|
||||
|
||||
:VERSION 29 #---------------------
|
||||
:VERSION 29 #----------------- Region Covenant changed time
|
||||
|
||||
BEGIN TRANSACTION
|
||||
|
||||
ALTER TABLE regionsettings ADD covenant_datetime int NOT NULL default 0
|
||||
|
||||
COMMIT
|
||||
|
||||
:VERSION 30 #------------------Migrate creatorID storage to varchars instead of UUIDs for HG support
|
||||
|
||||
BEGIN TRANSACTION
|
||||
|
||||
EXECUTE sp_rename N'dbo.prims.creatorid', N'creatoridold', 'COLUMN'
|
||||
EXECUTE sp_rename N'dbo.primitems.creatorid', N'creatoridold', 'COLUMN'
|
||||
|
||||
COMMIT
|
||||
|
||||
:VERSION 31 #---------------------
|
||||
|
||||
BEGIN TRANSACTION
|
||||
|
||||
ALTER TABLE prims ADD CreatorID varchar(255)
|
||||
ALTER TABLE primitems ADD CreatorID varchar(255)
|
||||
|
||||
COMMIT
|
||||
|
||||
:VERSION 32 #---------------------
|
||||
|
||||
BEGIN TRANSACTION
|
||||
|
||||
UPDATE prims SET prims.CreatorID = CONVERT(varchar(255), creatoridold)
|
||||
UPDATE primitems SET primitems.CreatorID = CONVERT(varchar(255), creatoridold)
|
||||
|
||||
COMMIT
|
||||
|
||||
:VERSION 33 #---------------------
|
||||
|
||||
BEGIN TRANSACTION
|
||||
|
||||
ALTER TABLE prims
|
||||
ADD CONSTRAINT DF_prims_CreatorIDNew
|
||||
DEFAULT '00000000-0000-0000-0000-000000000000'
|
||||
FOR CreatorID
|
||||
|
||||
ALTER TABLE prims ALTER COLUMN CreatorID varchar(255) NOT NULL
|
||||
|
||||
ALTER TABLE primitems
|
||||
ADD CONSTRAINT DF_primitems_CreatorIDNew
|
||||
DEFAULT '00000000-0000-0000-0000-000000000000'
|
||||
FOR CreatorID
|
||||
|
||||
ALTER TABLE primitems ALTER COLUMN CreatorID varchar(255) NOT NULL
|
||||
|
||||
COMMIT
|
||||
|
||||
:VERSION 34 #--------------- Telehub support
|
||||
|
||||
BEGIN TRANSACTION
|
||||
|
||||
CREATE TABLE [dbo].[Spawn_Points](
|
||||
[RegionUUID] [uniqueidentifier] NOT NULL,
|
||||
[Yaw] [float] NOT NULL,
|
||||
[Pitch] [float] NOT NULL,
|
||||
[Distance] [float] NOT NULL,
|
||||
PRIMARY KEY CLUSTERED
|
||||
(
|
||||
[RegionUUID] ASC
|
||||
)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
|
||||
) ON [PRIMARY]
|
||||
|
||||
ALTER TABLE regionsettings ADD TelehubObject uniqueidentifier NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000';
|
||||
|
||||
COMMIT
|
||||
|
||||
:VERSION 35 #---------------- Parcels for sale
|
||||
|
||||
BEGIN TRANSACTION
|
||||
|
||||
ALTER TABLE regionsettings ADD parcel_tile_ID uniqueidentifier NOT NULL DEFAULT '00000000-0000-0000-0000-000000000000';
|
||||
|
||||
COMMIT
|
||||
|
||||
:VERSION 36 #---------------- Timed bans/access
|
||||
|
||||
BEGIN TRANSACTION
|
||||
|
||||
ALTER TABLE landaccesslist ADD Expires integer NOT NULL DEFAULT 0;
|
||||
|
||||
COMMIT
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Data;
|
||||
@@ -36,12 +39,26 @@ namespace OpenSim.Data.Null
|
||||
{
|
||||
public class NullFriendsData : IFriendsData
|
||||
{
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private static List<FriendsData> m_Data = new List<FriendsData>();
|
||||
|
||||
public NullFriendsData(string connectionString, string realm)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear all friends data
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is required by unit tests to clear the static data between test runs.
|
||||
/// </remarks>
|
||||
public static void Clear()
|
||||
{
|
||||
lock (m_Data)
|
||||
m_Data.Clear();
|
||||
}
|
||||
|
||||
public FriendsData[] GetFriends(UUID principalID)
|
||||
{
|
||||
return GetFriends(principalID.ToString());
|
||||
@@ -56,20 +73,30 @@ namespace OpenSim.Data.Null
|
||||
/// <returns></returns>
|
||||
public FriendsData[] GetFriends(string userID)
|
||||
{
|
||||
List<FriendsData> lst = m_Data.FindAll(fdata =>
|
||||
lock (m_Data)
|
||||
{
|
||||
return fdata.PrincipalID == userID.ToString();
|
||||
});
|
||||
|
||||
if (lst != null)
|
||||
{
|
||||
lst.ForEach(f =>
|
||||
List<FriendsData> lst = m_Data.FindAll(fdata =>
|
||||
{
|
||||
FriendsData f2 = m_Data.Find(candidateF2 => f.Friend == candidateF2.PrincipalID);
|
||||
if (f2 != null) { f.Data["TheirFlags"] = f2.Data["Flags"]; }
|
||||
return fdata.PrincipalID == userID.ToString();
|
||||
});
|
||||
|
||||
return lst.ToArray();
|
||||
|
||||
if (lst != null)
|
||||
{
|
||||
lst.ForEach(f =>
|
||||
{
|
||||
FriendsData f2 = m_Data.Find(candidateF2 => f.Friend == candidateF2.PrincipalID);
|
||||
if (f2 != null)
|
||||
f.Data["TheirFlags"] = f2.Data["Flags"];
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[NULL FRIENDS DATA]: Got {0} {1} {2} for {3}",
|
||||
// f.Friend, f.Data["Flags"], f2 != null ? f.Data["TheirFlags"] : "not found!", f.PrincipalID);
|
||||
});
|
||||
|
||||
// m_log.DebugFormat("[NULL FRIENDS DATA]: Got {0} friends for {1}", lst.Count, userID);
|
||||
|
||||
return lst.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
return new FriendsData[0];
|
||||
@@ -80,7 +107,11 @@ namespace OpenSim.Data.Null
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
m_Data.Add(data);
|
||||
// m_log.DebugFormat(
|
||||
// "[NULL FRIENDS DATA]: Storing {0} {1} {2}", data.PrincipalID, data.Friend, data.Data["Flags"]);
|
||||
|
||||
lock (m_Data)
|
||||
m_Data.Add(data);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -92,14 +123,21 @@ namespace OpenSim.Data.Null
|
||||
|
||||
public bool Delete(string userID, string friendID)
|
||||
{
|
||||
List<FriendsData> lst = m_Data.FindAll(delegate(FriendsData fdata) { return fdata.PrincipalID == userID.ToString(); });
|
||||
if (lst != null)
|
||||
lock (m_Data)
|
||||
{
|
||||
FriendsData friend = lst.Find(delegate(FriendsData fdata) { return fdata.Friend == friendID; });
|
||||
if (friendID != null)
|
||||
List<FriendsData> lst = m_Data.FindAll(delegate(FriendsData fdata) { return fdata.PrincipalID == userID.ToString(); });
|
||||
if (lst != null)
|
||||
{
|
||||
m_Data.Remove(friend);
|
||||
return true;
|
||||
FriendsData friend = lst.Find(delegate(FriendsData fdata) { return fdata.Friend == friendID; });
|
||||
if (friendID != null)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[NULL FRIENDS DATA]: Deleting friend {0} {1} for {2}",
|
||||
// friend.Friend, friend.Data["Flags"], friend.PrincipalID);
|
||||
|
||||
m_Data.Remove(friend);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -110,7 +110,6 @@ namespace OpenSim.Data.Null
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public PresenceData[] Get(string field, string data)
|
||||
{
|
||||
if (Instance != this)
|
||||
|
||||
@@ -1070,8 +1070,6 @@ namespace OpenSim.Data.Tests
|
||||
regionInfo.RegionLocX = 0;
|
||||
regionInfo.RegionLocY = 0;
|
||||
|
||||
Scene scene = new Scene(regionInfo);
|
||||
|
||||
SceneObjectPart sop = new SceneObjectPart();
|
||||
sop.Name = name;
|
||||
sop.Description = name;
|
||||
@@ -1082,7 +1080,7 @@ namespace OpenSim.Data.Tests
|
||||
sop.Shape = PrimitiveBaseShape.Default;
|
||||
|
||||
SceneObjectGroup sog = new SceneObjectGroup(sop);
|
||||
sog.SetScene(scene);
|
||||
// sog.SetScene(scene);
|
||||
|
||||
return sog;
|
||||
}
|
||||
|
||||
40
OpenSim/Framework/Client/IClientInventory.cs
Normal file
40
OpenSim/Framework/Client/IClientInventory.cs
Normal file
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
|
||||
namespace OpenSim.Framework.Client
|
||||
{
|
||||
public interface IClientInventory
|
||||
{
|
||||
void SendRemoveInventoryFolders(UUID[] folders);
|
||||
void SendRemoveInventoryItems(UUID[] folders);
|
||||
void SendBulkUpdateInventory(InventoryFolderBase[] folders, InventoryItemBase[] items);
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ using System;
|
||||
using System.Xml;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
@@ -40,6 +41,8 @@ namespace OpenSim.Framework.Console
|
||||
{
|
||||
public class Commands : ICommands
|
||||
{
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
/// <summary>
|
||||
/// Encapsulates a command that can be invoked from the console
|
||||
/// </summary>
|
||||
@@ -76,12 +79,23 @@ namespace OpenSim.Framework.Console
|
||||
public List<CommandDelegate> fn;
|
||||
}
|
||||
|
||||
public const string GeneralHelpText
|
||||
= "To enter an argument that contains spaces, surround the argument with double quotes.\nFor example, show object name \"My long object name\"\n";
|
||||
|
||||
public const string ItemHelpText
|
||||
= "For more information, type 'help <item>' where <item> is one of the following:";
|
||||
|
||||
/// <value>
|
||||
/// Commands organized by keyword in a tree
|
||||
/// </value>
|
||||
private Dictionary<string, object> tree =
|
||||
new Dictionary<string, object>();
|
||||
|
||||
/// <summary>
|
||||
/// Commands organized by module
|
||||
/// </summary>
|
||||
private Dictionary<string, List<CommandInfo>> m_modulesCommands = new Dictionary<string, List<CommandInfo>>();
|
||||
|
||||
/// <summary>
|
||||
/// Get help for the given help string
|
||||
/// </summary>
|
||||
@@ -98,8 +112,10 @@ namespace OpenSim.Framework.Console
|
||||
// General help
|
||||
if (helpParts.Count == 0)
|
||||
{
|
||||
help.AddRange(CollectHelp(tree));
|
||||
help.Sort();
|
||||
help.Add(""); // Will become a newline.
|
||||
help.Add(GeneralHelpText);
|
||||
help.Add(ItemHelpText);
|
||||
help.AddRange(CollectModulesHelp(tree));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -118,6 +134,13 @@ namespace OpenSim.Framework.Console
|
||||
{
|
||||
string originalHelpRequest = string.Join(" ", helpParts.ToArray());
|
||||
List<string> help = new List<string>();
|
||||
|
||||
// Check modules first to see if we just need to display a list of those commands
|
||||
if (TryCollectModuleHelp(originalHelpRequest, help))
|
||||
{
|
||||
help.Insert(0, ItemHelpText);
|
||||
return help;
|
||||
}
|
||||
|
||||
Dictionary<string, object> dict = tree;
|
||||
while (helpParts.Count > 0)
|
||||
@@ -161,25 +184,63 @@ namespace OpenSim.Framework.Console
|
||||
return help;
|
||||
}
|
||||
|
||||
private List<string> CollectHelp(Dictionary<string, object> dict)
|
||||
/// <summary>
|
||||
/// Try to collect help for the given module if that module exists.
|
||||
/// </summary>
|
||||
/// <param name="moduleName"></param>
|
||||
/// <param name="helpText">/param>
|
||||
/// <returns>true if there was the module existed, false otherwise.</returns>
|
||||
private bool TryCollectModuleHelp(string moduleName, List<string> helpText)
|
||||
{
|
||||
List<string> result = new List<string>();
|
||||
|
||||
foreach (KeyValuePair<string, object> kvp in dict)
|
||||
lock (m_modulesCommands)
|
||||
{
|
||||
if (kvp.Value is Dictionary<string, Object>)
|
||||
foreach (string key in m_modulesCommands.Keys)
|
||||
{
|
||||
result.AddRange(CollectHelp((Dictionary<string, Object>)kvp.Value));
|
||||
}
|
||||
else
|
||||
{
|
||||
if (((CommandInfo)kvp.Value).long_help != String.Empty)
|
||||
result.Add(((CommandInfo)kvp.Value).help_text+" - "+
|
||||
((CommandInfo)kvp.Value).long_help);
|
||||
// Allow topic help requests to succeed whether they are upper or lowercase.
|
||||
if (moduleName.ToLower() == key.ToLower())
|
||||
{
|
||||
List<CommandInfo> commands = m_modulesCommands[key];
|
||||
var ourHelpText = commands.ConvertAll(c => string.Format("{0} - {1}", c.help_text, c.long_help));
|
||||
ourHelpText.Sort();
|
||||
helpText.AddRange(ourHelpText);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<string> CollectModulesHelp(Dictionary<string, object> dict)
|
||||
{
|
||||
lock (m_modulesCommands)
|
||||
{
|
||||
List<string> helpText = new List<string>(m_modulesCommands.Keys);
|
||||
helpText.Sort();
|
||||
return helpText;
|
||||
}
|
||||
}
|
||||
|
||||
// private List<string> CollectHelp(Dictionary<string, object> dict)
|
||||
// {
|
||||
// List<string> result = new List<string>();
|
||||
//
|
||||
// foreach (KeyValuePair<string, object> kvp in dict)
|
||||
// {
|
||||
// if (kvp.Value is Dictionary<string, Object>)
|
||||
// {
|
||||
// result.AddRange(CollectHelp((Dictionary<string, Object>)kvp.Value));
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (((CommandInfo)kvp.Value).long_help != String.Empty)
|
||||
// result.Add(((CommandInfo)kvp.Value).help_text+" - "+
|
||||
// ((CommandInfo)kvp.Value).long_help);
|
||||
// }
|
||||
// }
|
||||
// return result;
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// Add a command to those which can be invoked from the console.
|
||||
@@ -212,21 +273,19 @@ namespace OpenSim.Framework.Console
|
||||
|
||||
Dictionary<string, Object> current = tree;
|
||||
|
||||
foreach (string s in parts)
|
||||
foreach (string part in parts)
|
||||
{
|
||||
if (current.ContainsKey(s))
|
||||
if (current.ContainsKey(part))
|
||||
{
|
||||
if (current[s] is Dictionary<string, Object>)
|
||||
{
|
||||
current = (Dictionary<string, Object>)current[s];
|
||||
}
|
||||
if (current[part] is Dictionary<string, Object>)
|
||||
current = (Dictionary<string, Object>)current[part];
|
||||
else
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
current[s] = new Dictionary<string, Object>();
|
||||
current = (Dictionary<string, Object>)current[s];
|
||||
current[part] = new Dictionary<string, Object>();
|
||||
current = (Dictionary<string, Object>)current[part];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -250,6 +309,24 @@ namespace OpenSim.Framework.Console
|
||||
info.fn = new List<CommandDelegate>();
|
||||
info.fn.Add(fn);
|
||||
current[String.Empty] = info;
|
||||
|
||||
// Now add command to modules dictionary
|
||||
lock (m_modulesCommands)
|
||||
{
|
||||
List<CommandInfo> commands;
|
||||
if (m_modulesCommands.ContainsKey(module))
|
||||
{
|
||||
commands = m_modulesCommands[module];
|
||||
}
|
||||
else
|
||||
{
|
||||
commands = new List<CommandInfo>();
|
||||
m_modulesCommands[module] = commands;
|
||||
}
|
||||
|
||||
// m_log.DebugFormat("[COMMAND CONSOLE]: Adding to category {0} command {1}", module, command);
|
||||
commands.Add(info);
|
||||
}
|
||||
}
|
||||
|
||||
public string[] FindNextOption(string[] cmd, bool term)
|
||||
@@ -607,8 +684,9 @@ namespace OpenSim.Framework.Console
|
||||
{
|
||||
Commands = new Commands();
|
||||
|
||||
Commands.AddCommand("console", false, "help", "help [<command>]",
|
||||
"Get general command list or more detailed help on a specific command", Help);
|
||||
Commands.AddCommand(
|
||||
"Help", false, "help", "help [<item>]",
|
||||
"Display help on a particular command or on a list of commands in a category", Help);
|
||||
}
|
||||
|
||||
private void Help(string module, string[] cmd)
|
||||
|
||||
112
OpenSim/Framework/Console/ConsoleDisplayList.cs
Normal file
112
OpenSim/Framework/Console/ConsoleDisplayList.cs
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace OpenSim.Framework.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to generated a formatted table for the console.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Currently subject to change. If you use this, be prepared to change your code when this class changes.
|
||||
/// </remarks>
|
||||
public class ConsoleDisplayList
|
||||
{
|
||||
/// <summary>
|
||||
/// The default divider between key and value for a list item.
|
||||
/// </summary>
|
||||
public const string DefaultKeyValueDivider = " : ";
|
||||
|
||||
/// <summary>
|
||||
/// The divider used between key and value for a list item.
|
||||
/// </summary>
|
||||
public string KeyValueDivider { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Table rows
|
||||
/// </summary>
|
||||
public List<KeyValuePair<string, string>> Rows { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of spaces to indent the list.
|
||||
/// </summary>
|
||||
public int Indent { get; set; }
|
||||
|
||||
public ConsoleDisplayList()
|
||||
{
|
||||
Rows = new List<KeyValuePair<string, string>>();
|
||||
KeyValueDivider = DefaultKeyValueDivider;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
AddToStringBuilder(sb);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public void AddToStringBuilder(StringBuilder sb)
|
||||
{
|
||||
string formatString = GetFormatString();
|
||||
// System.Console.WriteLine("FORMAT STRING [{0}]", formatString);
|
||||
|
||||
// rows
|
||||
foreach (KeyValuePair<string, string> row in Rows)
|
||||
sb.AppendFormat(formatString, row.Key, row.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the format string for the table.
|
||||
/// </summary>
|
||||
private string GetFormatString()
|
||||
{
|
||||
StringBuilder formatSb = new StringBuilder();
|
||||
|
||||
int longestKey = -1;
|
||||
|
||||
foreach (KeyValuePair<string, string> row in Rows)
|
||||
if (row.Key.Length > longestKey)
|
||||
longestKey = row.Key.Length;
|
||||
|
||||
formatSb.Append(' ', Indent);
|
||||
|
||||
// Can only do left formatting for now
|
||||
formatSb.AppendFormat("{{0,-{0}}}{1}{{1}}\n", longestKey, KeyValueDivider);
|
||||
|
||||
return formatSb.ToString();
|
||||
}
|
||||
|
||||
public void AddRow(object key, object value)
|
||||
{
|
||||
Rows.Add(new KeyValuePair<string, string>(key.ToString(), value.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
154
OpenSim/Framework/Console/ConsoleDisplayTable.cs
Normal file
154
OpenSim/Framework/Console/ConsoleDisplayTable.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
namespace OpenSim.Framework.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// Used to generated a formatted table for the console.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Currently subject to change. If you use this, be prepared to change your code when this class changes.
|
||||
/// </remarks>
|
||||
public class ConsoleDisplayTable
|
||||
{
|
||||
/// <summary>
|
||||
/// Default number of spaces between table columns.
|
||||
/// </summary>
|
||||
public const int DefaultTableSpacing = 2;
|
||||
|
||||
/// <summary>
|
||||
/// Table columns.
|
||||
/// </summary>
|
||||
public List<ConsoleDisplayTableColumn> Columns { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Table rows
|
||||
/// </summary>
|
||||
public List<ConsoleDisplayTableRow> Rows { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of spaces to indent the table.
|
||||
/// </summary>
|
||||
public int Indent { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Spacing between table columns
|
||||
/// </summary>
|
||||
public int TableSpacing { get; set; }
|
||||
|
||||
public ConsoleDisplayTable()
|
||||
{
|
||||
TableSpacing = DefaultTableSpacing;
|
||||
Columns = new List<ConsoleDisplayTableColumn>();
|
||||
Rows = new List<ConsoleDisplayTableRow>();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
AddToStringBuilder(sb);
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public void AddColumn(string name, int width)
|
||||
{
|
||||
Columns.Add(new ConsoleDisplayTableColumn(name, width));
|
||||
}
|
||||
|
||||
public void AddRow(params string[] cells)
|
||||
{
|
||||
Rows.Add(new ConsoleDisplayTableRow(cells));
|
||||
}
|
||||
|
||||
public void AddToStringBuilder(StringBuilder sb)
|
||||
{
|
||||
string formatString = GetFormatString();
|
||||
// System.Console.WriteLine("FORMAT STRING [{0}]", formatString);
|
||||
|
||||
// columns
|
||||
sb.AppendFormat(formatString, Columns.ConvertAll(c => c.Header).ToArray());
|
||||
|
||||
// rows
|
||||
foreach (ConsoleDisplayTableRow row in Rows)
|
||||
sb.AppendFormat(formatString, row.Cells.ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the format string for the table.
|
||||
/// </summary>
|
||||
private string GetFormatString()
|
||||
{
|
||||
StringBuilder formatSb = new StringBuilder();
|
||||
|
||||
formatSb.Append(' ', Indent);
|
||||
|
||||
for (int i = 0; i < Columns.Count; i++)
|
||||
{
|
||||
formatSb.Append(' ', TableSpacing);
|
||||
|
||||
// Can only do left formatting for now
|
||||
formatSb.AppendFormat("{{{0},-{1}}}", i, Columns[i].Width);
|
||||
}
|
||||
|
||||
formatSb.Append('\n');
|
||||
|
||||
return formatSb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public struct ConsoleDisplayTableColumn
|
||||
{
|
||||
public string Header { get; set; }
|
||||
public int Width { get; set; }
|
||||
|
||||
public ConsoleDisplayTableColumn(string header, int width) : this()
|
||||
{
|
||||
Header = header;
|
||||
Width = width;
|
||||
}
|
||||
}
|
||||
|
||||
public struct ConsoleDisplayTableRow
|
||||
{
|
||||
public List<string> Cells { get; private set; }
|
||||
|
||||
public ConsoleDisplayTableRow(List<string> cells) : this()
|
||||
{
|
||||
Cells = cells;
|
||||
}
|
||||
|
||||
public ConsoleDisplayTableRow(params string[] cells) : this()
|
||||
{
|
||||
Cells = new List<string>(cells);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,7 @@ using System;
|
||||
using System.Threading;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
|
||||
namespace OpenSim.Framework.Console
|
||||
{
|
||||
@@ -37,28 +38,42 @@ namespace OpenSim.Framework.Console
|
||||
/// Don't use this except for Unit Testing or you're in for a world of hurt when the
|
||||
/// sim gets to ReadLine
|
||||
/// </summary>
|
||||
public class MockConsole : CommandConsole
|
||||
public class MockConsole : ICommandConsole
|
||||
{
|
||||
public MockConsole(string defaultPrompt) : base(defaultPrompt)
|
||||
{
|
||||
}
|
||||
public override void Output(string text)
|
||||
{
|
||||
}
|
||||
public override void Output(string text, string level)
|
||||
{
|
||||
}
|
||||
private MockCommands m_commands = new MockCommands();
|
||||
|
||||
public override string ReadLine(string p, bool isCommand, bool e)
|
||||
{
|
||||
//Thread.CurrentThread.Join(1000);
|
||||
return string.Empty;
|
||||
}
|
||||
public override void UnlockOutput()
|
||||
{
|
||||
}
|
||||
public override void LockOutput()
|
||||
{
|
||||
}
|
||||
public ICommands Commands { get { return m_commands; } }
|
||||
|
||||
public void Prompt() {}
|
||||
|
||||
public void RunCommand(string cmd) {}
|
||||
|
||||
public string ReadLine(string p, bool isCommand, bool e) { return ""; }
|
||||
|
||||
public object ConsoleScene { get { return null; } }
|
||||
|
||||
public void Output(string text, string level) {}
|
||||
public void Output(string text) {}
|
||||
public void OutputFormat(string format, params object[] components) {}
|
||||
|
||||
public string CmdPrompt(string p) { return ""; }
|
||||
public string CmdPrompt(string p, string def) { return ""; }
|
||||
public string CmdPrompt(string p, List<char> excludedCharacters) { return ""; }
|
||||
public string CmdPrompt(string p, string def, List<char> excludedCharacters) { return ""; }
|
||||
|
||||
public string CmdPrompt(string prompt, string defaultresponse, List<string> options) { return ""; }
|
||||
|
||||
public string PasswdPrompt(string p) { return ""; }
|
||||
}
|
||||
}
|
||||
|
||||
public class MockCommands : ICommands
|
||||
{
|
||||
public void FromXml(XmlElement root, CommandDelegate fn) {}
|
||||
public List<string> GetHelp(string[] cmd) { return null; }
|
||||
public void AddCommand(string module, bool shared, string command, string help, string longhelp, CommandDelegate fn) {}
|
||||
public void AddCommand(string module, bool shared, string command, string help, string longhelp, string descriptivehelp, CommandDelegate fn) {}
|
||||
public string[] FindNextOption(string[] cmd, bool term) { return null; }
|
||||
public string[] Resolve(string[] cmd) { return null; }
|
||||
public XmlElement GetXml(XmlDocument doc) { return null; }
|
||||
}
|
||||
}
|
||||
62
OpenSim/Framework/GcNotify.cs
Normal file
62
OpenSim/Framework/GcNotify.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* 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 log4net;
|
||||
|
||||
public class GcNotify
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
public static bool Enabled
|
||||
{
|
||||
get { return s_initialized; }
|
||||
set
|
||||
{
|
||||
if (!s_initialized && value)
|
||||
new GcNotify();
|
||||
|
||||
s_initialized = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static bool s_initialized = false;
|
||||
|
||||
private GcNotify() {}
|
||||
|
||||
~GcNotify()
|
||||
{
|
||||
if (!Environment.HasShutdownStarted && !AppDomain.CurrentDomain.IsFinalizingForUnload())
|
||||
{
|
||||
m_log.DebugFormat("[GC NOTIFY]: Garbage collection triggered.");
|
||||
|
||||
if (Enabled)
|
||||
new GcNotify();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -296,9 +296,9 @@ namespace OpenSim.Framework
|
||||
public delegate void ConfirmXfer(IClientAPI remoteClient, ulong xferID, uint packetID);
|
||||
|
||||
public delegate void FriendActionDelegate(
|
||||
IClientAPI remoteClient, UUID agentID, UUID transactionID, List<UUID> callingCardFolders);
|
||||
IClientAPI remoteClient, UUID transactionID, List<UUID> callingCardFolders);
|
||||
|
||||
public delegate void FriendshipTermination(IClientAPI remoteClient, UUID agentID, UUID ExID);
|
||||
public delegate void FriendshipTermination(IClientAPI remoteClient, UUID ExID);
|
||||
|
||||
public delegate void MoneyTransferRequest(
|
||||
UUID sourceID, UUID destID, int amount, int transactionType, string description);
|
||||
@@ -458,7 +458,7 @@ namespace OpenSim.Framework
|
||||
public delegate void AvatarNotesUpdate(IClientAPI client, UUID targetID, string notes);
|
||||
public delegate void MuteListRequest(IClientAPI client, uint muteCRC);
|
||||
public delegate void AvatarInterestUpdate(IClientAPI client, uint wantmask, string wanttext, uint skillsmask, string skillstext, string languages);
|
||||
public delegate void GrantUserFriendRights(IClientAPI client, UUID requester, UUID target, int rights);
|
||||
public delegate void GrantUserFriendRights(IClientAPI client, UUID target, int rights);
|
||||
public delegate void PlacesQuery(UUID QueryID, UUID TransactionID, string QueryText, uint QueryFlags, byte Category, string SimName, IClientAPI client);
|
||||
|
||||
public delegate void AgentFOV(IClientAPI client, float verticalAngle);
|
||||
@@ -710,7 +710,7 @@ namespace OpenSim.Framework
|
||||
/// The scene agent for this client. This will only be set if the client has an agent in a scene (i.e. if it
|
||||
/// is connected).
|
||||
/// </summary>
|
||||
ISceneAgent SceneAgent { get; }
|
||||
ISceneAgent SceneAgent { get; set; }
|
||||
|
||||
UUID SessionId { get; }
|
||||
|
||||
@@ -740,14 +740,21 @@ namespace OpenSim.Framework
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
/// <value>
|
||||
/// Determines whether the client thread is doing anything or not.
|
||||
/// </value>
|
||||
/// <summary>
|
||||
/// True if the client is active (sending and receiving new UDP messages). False if the client is being closed.
|
||||
/// </summary>
|
||||
bool IsActive { get; set; }
|
||||
|
||||
/// <value>
|
||||
/// Determines whether the client is or has been removed from a given scene
|
||||
/// </value>
|
||||
/// <summary>
|
||||
/// Set if the client is closing due to a logout request
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Do not use this flag if you want to know if the client is closing, since it will not be set in other
|
||||
/// circumstances (e.g. if a child agent is closed or the agent is kicked off the simulator). Use IsActive
|
||||
/// instead with a IClientAPI.SceneAgent.IsChildAgent check if necessary.
|
||||
///
|
||||
/// Only set for root agents.
|
||||
/// </remarks>
|
||||
bool IsLoggingOut { get; set; }
|
||||
|
||||
bool SendLogoutPacketWhenClosing { set; }
|
||||
@@ -1408,8 +1415,6 @@ namespace OpenSim.Framework
|
||||
|
||||
void SendGroupVoteHistory(UUID groupID, UUID transactionID, GroupVoteHistory[] Votes);
|
||||
|
||||
void KillEndDone();
|
||||
|
||||
bool AddGenericPacketHandler(string MethodName, GenericMessage handler);
|
||||
|
||||
void SendRebakeAvatarTextures(UUID textureID);
|
||||
|
||||
@@ -40,7 +40,7 @@ namespace OpenSim.Framework
|
||||
/// <summary>
|
||||
/// Get help for the given help string
|
||||
/// </summary>
|
||||
/// <param name="helpParts">Parsed parts of the help string. If empty then general help is returned.</param>
|
||||
/// <param name="cmd">Parsed parts of the help string. If empty then general help is returned.</param>
|
||||
/// <returns></returns>
|
||||
List<string> GetHelp(string[] cmd);
|
||||
|
||||
|
||||
@@ -71,6 +71,7 @@ namespace OpenSim.Framework
|
||||
bool IsEitherBannedOrRestricted(UUID avatar);
|
||||
bool IsBannedFromLand(UUID avatar);
|
||||
bool IsRestrictedFromLand(UUID avatar);
|
||||
bool IsInLandAccessList(UUID avatar);
|
||||
void SendLandUpdateToClient(IClientAPI remote_client);
|
||||
void SendLandUpdateToClient(bool snap_selection, IClientAPI remote_client);
|
||||
List<LandAccessEntry> CreateAccessListArrayByFlag(AccessList flag);
|
||||
|
||||
@@ -56,6 +56,11 @@ namespace OpenSim.Framework
|
||||
|
||||
public interface IScene
|
||||
{
|
||||
/// <summary>
|
||||
/// The name of this scene.
|
||||
/// </summary>
|
||||
string Name { get; }
|
||||
|
||||
RegionInfo RegionInfo { get; }
|
||||
RegionStatus RegionStatus { get; set; }
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using OpenMetaverse;
|
||||
|
||||
namespace OpenSim.Framework
|
||||
{
|
||||
@@ -71,5 +72,11 @@ namespace OpenSim.Framework
|
||||
/// This includes scene object data and the appearance data of other avatars.
|
||||
/// </remarks>
|
||||
void SendInitialDataToMe();
|
||||
|
||||
/// <summary>
|
||||
/// Direction in which the scene presence is looking.
|
||||
/// </summary>
|
||||
/// <remarks>Will be Vector3.Zero for a child agent.</remarks>
|
||||
Vector3 Lookat { get; }
|
||||
}
|
||||
}
|
||||
@@ -69,7 +69,7 @@ namespace OpenSim.Framework
|
||||
(uint) ParcelFlags.AllowAPrimitiveEntry |
|
||||
(uint) ParcelFlags.AllowDeedToGroup | (uint) ParcelFlags.AllowTerraform |
|
||||
(uint) ParcelFlags.CreateObjects | (uint) ParcelFlags.AllowOtherScripts |
|
||||
(uint) ParcelFlags.SoundLocal;
|
||||
(uint) ParcelFlags.SoundLocal | (uint) ParcelFlags.AllowVoiceChat;
|
||||
|
||||
private byte _landingType = 0;
|
||||
private string _name = "Your Parcel";
|
||||
|
||||
@@ -161,43 +161,43 @@ namespace OpenSim.Framework.Servers
|
||||
Notice(String.Format("Console log level is {0}", m_consoleAppender.Threshold));
|
||||
}
|
||||
|
||||
m_console.Commands.AddCommand("base", false, "quit",
|
||||
m_console.Commands.AddCommand("General", false, "quit",
|
||||
"quit",
|
||||
"Quit the application", HandleQuit);
|
||||
|
||||
m_console.Commands.AddCommand("base", false, "shutdown",
|
||||
m_console.Commands.AddCommand("General", false, "shutdown",
|
||||
"shutdown",
|
||||
"Quit the application", HandleQuit);
|
||||
|
||||
m_console.Commands.AddCommand("base", false, "set log level",
|
||||
m_console.Commands.AddCommand("General", false, "set log level",
|
||||
"set log level <level>",
|
||||
"Set the console logging level", HandleLogLevel);
|
||||
|
||||
m_console.Commands.AddCommand("base", false, "show info",
|
||||
m_console.Commands.AddCommand("General", false, "show info",
|
||||
"show info",
|
||||
"Show general information about the server", HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand("base", false, "show stats",
|
||||
m_console.Commands.AddCommand("General", false, "show stats",
|
||||
"show stats",
|
||||
"Show statistics", HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand("base", false, "show threads",
|
||||
m_console.Commands.AddCommand("General", false, "show threads",
|
||||
"show threads",
|
||||
"Show thread status", HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand("base", false, "show uptime",
|
||||
m_console.Commands.AddCommand("General", false, "show uptime",
|
||||
"show uptime",
|
||||
"Show server uptime", HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand("base", false, "show version",
|
||||
m_console.Commands.AddCommand("General", false, "show version",
|
||||
"show version",
|
||||
"Show server version", HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand("base", false, "threads abort",
|
||||
m_console.Commands.AddCommand("General", false, "threads abort",
|
||||
"threads abort <thread-id>",
|
||||
"Abort a managed thread. Use \"show threads\" to find possible threads.", HandleThreadsAbort);
|
||||
|
||||
m_console.Commands.AddCommand("base", false, "threads show",
|
||||
m_console.Commands.AddCommand("General", false, "threads show",
|
||||
"threads show",
|
||||
"Show thread status. Synonym for \"show threads\"",
|
||||
(string module, string[] args) => Notice(GetThreadsReport()));
|
||||
@@ -269,15 +269,19 @@ namespace OpenSim.Framework.Servers
|
||||
t.Priority,
|
||||
t.ThreadState);
|
||||
|
||||
sb.Append(Environment.NewLine);
|
||||
sb.Append("\n");
|
||||
}
|
||||
|
||||
int workers = 0, ports = 0, maxWorkers = 0, maxPorts = 0;
|
||||
ThreadPool.GetAvailableThreads(out workers, out ports);
|
||||
ThreadPool.GetMaxThreads(out maxWorkers, out maxPorts);
|
||||
sb.Append("\n");
|
||||
|
||||
sb.Append(Environment.NewLine + "*** ThreadPool threads ***" + Environment.NewLine);
|
||||
sb.Append("workers: " + (maxWorkers - workers) + " (" + maxWorkers + "); ports: " + (maxPorts - ports) + " (" + maxPorts + ")" + Environment.NewLine);
|
||||
// For some reason mono 2.6.7 returns an empty threads set! Not going to confuse people by reporting
|
||||
// zero active threads.
|
||||
int totalThreads = Process.GetCurrentProcess().Threads.Count;
|
||||
if (totalThreads > 0)
|
||||
sb.AppendFormat("Total threads active: {0}\n\n", totalThreads);
|
||||
|
||||
sb.Append("Main threadpool (excluding script engine pools)\n");
|
||||
sb.Append(Util.GetThreadPoolReport());
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
@@ -316,7 +320,9 @@ namespace OpenSim.Framework.Servers
|
||||
|
||||
TimeSpan timeTaken = DateTime.Now - m_startuptime;
|
||||
|
||||
m_log.InfoFormat("[STARTUP]: Startup took {0}m {1}s", timeTaken.Minutes, timeTaken.Seconds);
|
||||
m_log.InfoFormat(
|
||||
"[STARTUP]: Non-script portion of startup took {0}m {1}s. PLEASE WAIT FOR LOGINS TO BE ENABLED ON REGIONS ONCE SCRIPTS HAVE STARTED.",
|
||||
timeTaken.Minutes, timeTaken.Seconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -33,9 +33,9 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
public abstract Hashtable Handle(string path, Hashtable Request);
|
||||
|
||||
protected BaseHTTPHandler(string httpMethod, string path)
|
||||
: base(httpMethod, path)
|
||||
{
|
||||
}
|
||||
protected BaseHTTPHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {}
|
||||
|
||||
protected BaseHTTPHandler(string httpMethod, string path, string name, string description)
|
||||
: base(httpMethod, path, name, description) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -53,6 +53,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private HttpServerLogWriter httpserverlog = new HttpServerLogWriter();
|
||||
|
||||
public int DebugLevel { get; set; }
|
||||
|
||||
private volatile int NotSocketErrors = 0;
|
||||
public volatile bool HTTPDRunning = false;
|
||||
|
||||
@@ -79,11 +81,6 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
private PollServiceRequestManager m_PollServiceManager;
|
||||
|
||||
/// <summary>
|
||||
/// Control the printing of certain debug messages.
|
||||
/// </summary>
|
||||
public int DebugLevel { get; set; }
|
||||
|
||||
public uint SSLPort
|
||||
{
|
||||
get { return m_sslport; }
|
||||
@@ -156,7 +153,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
}
|
||||
}
|
||||
|
||||
public List<string> GetStreamHandlerKeys()
|
||||
public List<string> GetStreamHandlerKeys()
|
||||
{
|
||||
lock (m_streamHandlers)
|
||||
return new List<string>(m_streamHandlers.Keys);
|
||||
@@ -356,7 +353,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat("[BASE HTTP SERVER]: OnRequest() failed with {0}{1}", e.Message, e.StackTrace);
|
||||
m_log.Error(String.Format("[BASE HTTP SERVER]: OnRequest() failed: {0} ", e.Message), e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -408,7 +405,12 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
string uriString = request.RawUrl;
|
||||
|
||||
// string reqnum = "unknown";
|
||||
int tickstart = Environment.TickCount;
|
||||
int requestStartTick = Environment.TickCount;
|
||||
|
||||
// Will be adjusted later on.
|
||||
int requestEndTick = requestStartTick;
|
||||
|
||||
IRequestHandler requestHandler = null;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -431,6 +433,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
if (HandleAgentRequest(agentHandler, request, response))
|
||||
{
|
||||
requestEndTick = Environment.TickCount;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -438,20 +441,16 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
//response.KeepAlive = true;
|
||||
response.SendChunked = false;
|
||||
|
||||
IRequestHandler requestHandler;
|
||||
|
||||
string path = request.RawUrl;
|
||||
string handlerKey = GetHandlerKey(request.HttpMethod, path);
|
||||
byte[] buffer = null;
|
||||
|
||||
if (TryGetStreamHandler(handlerKey, out requestHandler))
|
||||
{
|
||||
if (DebugLevel >= 1)
|
||||
if (DebugLevel >= 3)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Found stream handler for {0} {1}",
|
||||
request.HttpMethod, request.Url.PathAndQuery);
|
||||
|
||||
// Okay, so this is bad, but should be considered temporary until everything is IStreamHandler.
|
||||
byte[] buffer = null;
|
||||
"[BASE HTTP SERVER]: Found stream handler for {0} {1} {2} {3}",
|
||||
request.HttpMethod, request.Url.PathAndQuery, requestHandler.Name, requestHandler.Description);
|
||||
|
||||
response.ContentType = requestHandler.ContentType; // Lets do this defaulting before in case handler has varying content type.
|
||||
|
||||
@@ -507,8 +506,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
//m_log.Warn("[HTTP]: " + requestBody);
|
||||
|
||||
}
|
||||
DoHTTPGruntWork(HTTPRequestHandler.Handle(path, keysvals), response);
|
||||
return;
|
||||
|
||||
buffer = DoHTTPGruntWork(HTTPRequestHandler.Handle(path, keysvals), response);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -521,133 +520,99 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
buffer = memoryStream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch (request.ContentType)
|
||||
{
|
||||
case null:
|
||||
case "text/html":
|
||||
|
||||
if (DebugLevel >= 3)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
|
||||
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
|
||||
|
||||
buffer = HandleHTTPRequest(request, response);
|
||||
break;
|
||||
|
||||
case "application/llsd+xml":
|
||||
case "application/xml+llsd":
|
||||
case "application/llsd+json":
|
||||
|
||||
if (DebugLevel >= 3)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
|
||||
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
|
||||
|
||||
buffer = HandleLLSDRequests(request, response);
|
||||
break;
|
||||
|
||||
case "text/xml":
|
||||
case "application/xml":
|
||||
case "application/json":
|
||||
default:
|
||||
//m_log.Info("[Debug BASE HTTP SERVER]: in default handler");
|
||||
// Point of note.. the DoWeHaveA methods check for an EXACT path
|
||||
// if (request.RawUrl.Contains("/CAPS/EQG"))
|
||||
// {
|
||||
// int i = 1;
|
||||
// }
|
||||
//m_log.Info("[Debug BASE HTTP SERVER]: Checking for LLSD Handler");
|
||||
if (DoWeHaveALLSDHandler(request.RawUrl))
|
||||
{
|
||||
if (DebugLevel >= 3)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
|
||||
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
|
||||
|
||||
buffer = HandleLLSDRequests(request, response);
|
||||
}
|
||||
// m_log.DebugFormat("[BASE HTTP SERVER]: Checking for HTTP Handler for request {0}", request.RawUrl);
|
||||
else if (DoWeHaveAHTTPHandler(request.RawUrl))
|
||||
{
|
||||
if (DebugLevel >= 3)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
|
||||
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
|
||||
|
||||
buffer = HandleHTTPRequest(request, response);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DebugLevel >= 3)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Assuming a generic XMLRPC request for {0} {1}",
|
||||
request.HttpMethod, request.Url.PathAndQuery);
|
||||
|
||||
// generic login request.
|
||||
buffer = HandleXmlRpcRequests(request, response);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
request.InputStream.Close();
|
||||
|
||||
// HTTP IN support. The script engine takes it from here
|
||||
// Nothing to worry about for us.
|
||||
//
|
||||
if (buffer == null)
|
||||
return;
|
||||
request.InputStream.Close();
|
||||
|
||||
if (buffer != null)
|
||||
{
|
||||
if (!response.SendChunked)
|
||||
response.ContentLength64 = buffer.LongLength;
|
||||
|
||||
try
|
||||
{
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
//response.OutputStream.Close();
|
||||
}
|
||||
catch (HttpListenerException)
|
||||
{
|
||||
m_log.WarnFormat("[BASE HTTP SERVER]: HTTP request abnormally terminated.");
|
||||
}
|
||||
//response.OutputStream.Close();
|
||||
try
|
||||
{
|
||||
response.Send();
|
||||
//response.FreeContext();
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
// This has to be here to prevent a Linux/Mono crash
|
||||
m_log.WarnFormat("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
m_log.Warn("[BASE HTTP SERVER]: XmlRpcRequest issue: " + e.Message);
|
||||
}
|
||||
|
||||
return;
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
if (request.AcceptTypes != null && request.AcceptTypes.Length > 0)
|
||||
{
|
||||
foreach (string strAccept in request.AcceptTypes)
|
||||
{
|
||||
if (strAccept.Contains("application/llsd+xml") ||
|
||||
strAccept.Contains("application/llsd+json"))
|
||||
{
|
||||
if (DebugLevel >= 1)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Found application/llsd+xml accept header handler for {0} {1}",
|
||||
request.HttpMethod, request.Url.PathAndQuery);
|
||||
// Do not include the time taken to actually send the response to the caller in the measurement
|
||||
// time. This is to avoid logging when it's the client that is slow to process rather than the
|
||||
// server
|
||||
requestEndTick = Environment.TickCount;
|
||||
|
||||
HandleLLSDRequests(request, response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
response.Send();
|
||||
|
||||
switch (request.ContentType)
|
||||
{
|
||||
case null:
|
||||
case "text/html":
|
||||
//response.OutputStream.Close();
|
||||
|
||||
if (DebugLevel >= 1)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
|
||||
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
|
||||
|
||||
HandleHTTPRequest(request, response);
|
||||
return;
|
||||
|
||||
case "application/llsd+xml":
|
||||
case "application/xml+llsd":
|
||||
case "application/llsd+json":
|
||||
|
||||
if (DebugLevel >= 1)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
|
||||
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
|
||||
|
||||
HandleLLSDRequests(request, response);
|
||||
return;
|
||||
|
||||
case "text/xml":
|
||||
case "application/xml":
|
||||
case "application/json":
|
||||
default:
|
||||
//m_log.Info("[Debug BASE HTTP SERVER]: in default handler");
|
||||
// Point of note.. the DoWeHaveA methods check for an EXACT path
|
||||
// if (request.RawUrl.Contains("/CAPS/EQG"))
|
||||
// {
|
||||
// int i = 1;
|
||||
// }
|
||||
//m_log.Info("[Debug BASE HTTP SERVER]: Checking for LLSD Handler");
|
||||
if (DoWeHaveALLSDHandler(request.RawUrl))
|
||||
{
|
||||
if (DebugLevel >= 1)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
|
||||
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
|
||||
|
||||
HandleLLSDRequests(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
// m_log.DebugFormat("[BASE HTTP SERVER]: Checking for HTTP Handler for request {0}", request.RawUrl);
|
||||
if (DoWeHaveAHTTPHandler(request.RawUrl))
|
||||
{
|
||||
if (DebugLevel >= 1)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Found a {0} content type handler for {1} {2}",
|
||||
request.ContentType, request.HttpMethod, request.Url.PathAndQuery);
|
||||
|
||||
HandleHTTPRequest(request, response);
|
||||
return;
|
||||
}
|
||||
|
||||
if (DebugLevel >= 1)
|
||||
m_log.DebugFormat(
|
||||
"[BASE HTTP SERVER]: Assuming a generic XMLRPC request for {0} {1}",
|
||||
request.HttpMethod, request.Url.PathAndQuery);
|
||||
|
||||
// generic login request.
|
||||
HandleXmlRpcRequests(request, response);
|
||||
|
||||
return;
|
||||
}
|
||||
//response.FreeContext();
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
@@ -658,25 +623,33 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
//
|
||||
// An alternative may be to turn off all response write exceptions on the HttpListener, but let's go
|
||||
// with the minimum first
|
||||
m_log.WarnFormat("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux", e);
|
||||
m_log.Warn(String.Format("[BASE HTTP SERVER]: HandleRequest threw {0}.\nNOTE: this may be spurious on Linux ", e.Message), e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw ", e);
|
||||
m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.Message), e);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat("[BASE HTTP SERVER]: HandleRequest() threw " + e.ToString());
|
||||
m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.Message), e);
|
||||
SendHTML500(response);
|
||||
}
|
||||
finally
|
||||
{
|
||||
// Every month or so this will wrap and give bad numbers, not really a problem
|
||||
// since its just for reporting, tickdiff limit can be adjusted
|
||||
int tickdiff = Environment.TickCount - tickstart;
|
||||
// since its just for reporting
|
||||
int tickdiff = requestEndTick - requestStartTick;
|
||||
if (tickdiff > 3000)
|
||||
{
|
||||
m_log.InfoFormat(
|
||||
"[BASE HTTP SERVER]: slow {0} request for {1} from {2} took {3} ms", requestMethod, uriString, request.RemoteIPEndPoint.ToString(), tickdiff);
|
||||
"[BASE HTTP SERVER]: Slow handling of {0} {1} {2} {3} from {4} took {5}ms",
|
||||
requestMethod,
|
||||
uriString,
|
||||
requestHandler != null ? requestHandler.Name : "",
|
||||
requestHandler != null ? requestHandler.Description : "",
|
||||
request.RemoteIPEndPoint.ToString(),
|
||||
tickdiff);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -797,7 +770,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
/// </summary>
|
||||
/// <param name="request"></param>
|
||||
/// <param name="response"></param>
|
||||
private void HandleXmlRpcRequests(OSHttpRequest request, OSHttpResponse response)
|
||||
private byte[] HandleXmlRpcRequests(OSHttpRequest request, OSHttpResponse response)
|
||||
{
|
||||
Stream requestStream = request.InputStream;
|
||||
|
||||
@@ -816,8 +789,23 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
xmlRprcRequest = (XmlRpcRequest) (new XmlRpcRequestDeserializer()).Deserialize(requestBody);
|
||||
}
|
||||
catch (XmlException)
|
||||
catch (XmlException e)
|
||||
{
|
||||
if (DebugLevel >= 1)
|
||||
{
|
||||
if (DebugLevel >= 2)
|
||||
m_log.Warn(
|
||||
string.Format(
|
||||
"[BASE HTTP SERVER]: Got XMLRPC request with invalid XML from {0}. XML was '{1}'. Sending blank response. Exception ",
|
||||
request.RemoteIPEndPoint, requestBody),
|
||||
e);
|
||||
else
|
||||
{
|
||||
m_log.WarnFormat(
|
||||
"[BASE HTTP SERVER]: Got XMLRPC request with invalid XML from {0}, length {1}. Sending blank response.",
|
||||
request.RemoteIPEndPoint, requestBody.Length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (xmlRprcRequest != null)
|
||||
@@ -887,6 +875,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
String.Format("Requested method [{0}] not found", methodName));
|
||||
}
|
||||
|
||||
response.ContentType = "text/xml";
|
||||
responseString = XmlRpcResponseSerializer.Singleton.Serialize(xmlRpcResponse);
|
||||
}
|
||||
else
|
||||
@@ -896,82 +885,25 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
response.StatusCode = 404;
|
||||
response.StatusDescription = "Not Found";
|
||||
response.ProtocolVersion = "HTTP/1.0";
|
||||
byte[] buf = Encoding.UTF8.GetBytes("Not found");
|
||||
responseString = "Not found";
|
||||
response.KeepAlive = false;
|
||||
|
||||
m_log.ErrorFormat(
|
||||
"[BASE HTTP SERVER]: Handler not found for http request {0} {1}",
|
||||
request.HttpMethod, request.Url.PathAndQuery);
|
||||
|
||||
response.SendChunked = false;
|
||||
response.ContentLength64 = buf.Length;
|
||||
response.ContentEncoding = Encoding.UTF8;
|
||||
|
||||
try
|
||||
{
|
||||
response.OutputStream.Write(buf, 0, buf.Length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
response.Send();
|
||||
//response.FreeContext();
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
// This has to be here to prevent a Linux/Mono crash
|
||||
m_log.WarnFormat("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
m_log.Warn("[BASE HTTP SERVER]: XmlRpcRequest issue: " + e.Message);
|
||||
}
|
||||
}
|
||||
return;
|
||||
//responseString = "Error";
|
||||
}
|
||||
}
|
||||
|
||||
response.ContentType = "text/xml";
|
||||
|
||||
byte[] buffer = Encoding.UTF8.GetBytes(responseString);
|
||||
|
||||
response.SendChunked = false;
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.ContentEncoding = Encoding.UTF8;
|
||||
try
|
||||
{
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
try
|
||||
{
|
||||
response.Send();
|
||||
//response.FreeContext();
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
// This has to be here to prevent a Linux/Mono crash
|
||||
m_log.WarnFormat("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
m_log.Warn("[BASE HTTP SERVER]: XmlRpcRequest issue: " + e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private void HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response)
|
||||
private byte[] HandleLLSDRequests(OSHttpRequest request, OSHttpResponse response)
|
||||
{
|
||||
//m_log.Warn("[BASE HTTP SERVER]: We've figured out it's a LLSD Request");
|
||||
Stream requestStream = request.InputStream;
|
||||
@@ -1057,34 +989,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
response.ContentEncoding = Encoding.UTF8;
|
||||
response.KeepAlive = true;
|
||||
|
||||
try
|
||||
{
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
//response.OutputStream.Close();
|
||||
try
|
||||
{
|
||||
response.Send();
|
||||
response.OutputStream.Flush();
|
||||
//response.FreeContext();
|
||||
//response.OutputStream.Close();
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
m_log.WarnFormat("[BASE HTTP SERVER]: LLSD IOException {0}.", e);
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
// This has to be here to prevent a Linux/Mono crash
|
||||
m_log.WarnFormat("[BASE HTTP SERVER]: LLSD issue {0}.\nNOTE: this may be spurious on Linux.", e);
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private byte[] BuildLLSDResponse(OSHttpRequest request, OSHttpResponse response, OSD llsdResponse)
|
||||
@@ -1334,8 +1239,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
catch (SocketException f)
|
||||
{
|
||||
// This has to be here to prevent a Linux/Mono crash
|
||||
m_log.WarnFormat(
|
||||
"[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", f);
|
||||
m_log.Warn(
|
||||
String.Format("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux. ", f.Message), f);
|
||||
}
|
||||
}
|
||||
catch(Exception)
|
||||
@@ -1349,7 +1254,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
}
|
||||
|
||||
public void HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response)
|
||||
public byte[] HandleHTTPRequest(OSHttpRequest request, OSHttpResponse response)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[BASE HTTP SERVER]: HandleHTTPRequest for request to {0}, method {1}",
|
||||
@@ -1359,15 +1264,14 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
case "OPTIONS":
|
||||
response.StatusCode = (int)OSHttpStatusCode.SuccessOk;
|
||||
return;
|
||||
return null;
|
||||
|
||||
default:
|
||||
HandleContentVerbs(request, response);
|
||||
return;
|
||||
return HandleContentVerbs(request, response);
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleContentVerbs(OSHttpRequest request, OSHttpResponse response)
|
||||
private byte[] HandleContentVerbs(OSHttpRequest request, OSHttpResponse response)
|
||||
{
|
||||
// m_log.DebugFormat("[BASE HTTP SERVER]: HandleContentVerbs for request to {0}", request.RawUrl);
|
||||
|
||||
@@ -1383,6 +1287,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
// to display the form, or process it.
|
||||
// a better way would be nifty.
|
||||
|
||||
byte[] buffer;
|
||||
|
||||
Stream requestStream = request.InputStream;
|
||||
|
||||
Encoding encoding = Encoding.UTF8;
|
||||
@@ -1443,14 +1349,14 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
if (foundHandler)
|
||||
{
|
||||
Hashtable responsedata1 = requestprocessor(keysvals);
|
||||
DoHTTPGruntWork(responsedata1,response);
|
||||
buffer = DoHTTPGruntWork(responsedata1,response);
|
||||
|
||||
//SendHTML500(response);
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_log.Warn("[BASE HTTP SERVER]: Handler Not Found");
|
||||
SendHTML404(response, host);
|
||||
buffer = SendHTML404(response, host);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1460,16 +1366,18 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
if (foundHandler)
|
||||
{
|
||||
Hashtable responsedata2 = requestprocessor(keysvals);
|
||||
DoHTTPGruntWork(responsedata2, response);
|
||||
buffer = DoHTTPGruntWork(responsedata2, response);
|
||||
|
||||
//SendHTML500(response);
|
||||
}
|
||||
else
|
||||
{
|
||||
// m_log.Warn("[BASE HTTP SERVER]: Handler Not Found2");
|
||||
SendHTML404(response, host);
|
||||
buffer = SendHTML404(response, host);
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
private bool TryGetHTTPHandlerPathBased(string path, out GenericHTTPMethod httpHandler)
|
||||
@@ -1537,14 +1445,13 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
}
|
||||
}
|
||||
|
||||
internal void DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response)
|
||||
internal byte[] DoHTTPGruntWork(Hashtable responsedata, OSHttpResponse response)
|
||||
{
|
||||
//m_log.Info("[BASE HTTP SERVER]: Doing HTTP Grunt work with response");
|
||||
int responsecode = (int)responsedata["int_response_code"];
|
||||
string responseString = (string)responsedata["str_response_string"];
|
||||
string contentType = (string)responsedata["content_type"];
|
||||
|
||||
|
||||
if (responsedata.ContainsKey("error_status_text"))
|
||||
{
|
||||
response.StatusDescription = (string)responsedata["error_status_text"];
|
||||
@@ -1608,38 +1515,10 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.ContentEncoding = Encoding.UTF8;
|
||||
|
||||
try
|
||||
{
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_log.Warn("[HTTPD]: Error - " + ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
//response.OutputStream.Close();
|
||||
try
|
||||
{
|
||||
response.OutputStream.Flush();
|
||||
response.Send();
|
||||
|
||||
//if (!response.KeepAlive && response.ReuseContext)
|
||||
// response.FreeContext();
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
// This has to be here to prevent a Linux/Mono crash
|
||||
m_log.WarnFormat("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e);
|
||||
}
|
||||
catch (IOException e)
|
||||
{
|
||||
m_log.Warn("[BASE HTTP SERVER]: XmlRpcRequest issue: " + e.Message);
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public void SendHTML404(OSHttpResponse response, string host)
|
||||
public byte[] SendHTML404(OSHttpResponse response, string host)
|
||||
{
|
||||
// I know this statuscode is dumb, but the client doesn't respond to 404s and 500s
|
||||
response.StatusCode = 404;
|
||||
@@ -1652,31 +1531,10 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.ContentEncoding = Encoding.UTF8;
|
||||
|
||||
try
|
||||
{
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
//response.OutputStream.Close();
|
||||
try
|
||||
{
|
||||
response.Send();
|
||||
//response.FreeContext();
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
// This has to be here to prevent a Linux/Mono crash
|
||||
m_log.WarnFormat("[BASE HTTP SERVER]: XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e);
|
||||
}
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public void SendHTML500(OSHttpResponse response)
|
||||
public byte[] SendHTML500(OSHttpResponse response)
|
||||
{
|
||||
// I know this statuscode is dumb, but the client doesn't respond to 404s and 500s
|
||||
response.StatusCode = (int)OSHttpStatusCode.SuccessOk;
|
||||
@@ -1688,28 +1546,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
response.SendChunked = false;
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.ContentEncoding = Encoding.UTF8;
|
||||
try
|
||||
{
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_log.Warn("[BASE HTTP SERVER]: Error - " + ex.Message);
|
||||
}
|
||||
finally
|
||||
{
|
||||
//response.OutputStream.Close();
|
||||
try
|
||||
{
|
||||
response.Send();
|
||||
//response.FreeContext();
|
||||
}
|
||||
catch (SocketException e)
|
||||
{
|
||||
// This has to be here to prevent a Linux/Mono crash
|
||||
m_log.WarnFormat("[BASE HTTP SERVER] XmlRpcRequest issue {0}.\nNOTE: this may be spurious on Linux.", e);
|
||||
}
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
@@ -1719,6 +1557,9 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
private void StartHTTP()
|
||||
{
|
||||
m_log.InfoFormat(
|
||||
"[BASE HTTP SERVER]: Starting {0} server on port {1}", UseSSL ? "HTTPS" : "HTTP", Port);
|
||||
|
||||
try
|
||||
{
|
||||
//m_httpListener = new HttpListener();
|
||||
@@ -1786,7 +1627,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
public void httpServerException(object source, Exception exception)
|
||||
{
|
||||
m_log.ErrorFormat("[BASE HTTP SERVER]: {0} had an exception {1}", source.ToString(), exception.ToString());
|
||||
m_log.Error(String.Format("[BASE HTTP SERVER]: {0} had an exception: {1} ", source.ToString(), exception.Message), exception);
|
||||
/*
|
||||
if (HTTPDRunning)// && NotSocketErrors > 5)
|
||||
{
|
||||
|
||||
@@ -45,8 +45,16 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
private readonly string m_path;
|
||||
|
||||
protected BaseRequestHandler(string httpMethod, string path)
|
||||
public string Name { get; private set; }
|
||||
|
||||
public string Description { get; private set; }
|
||||
|
||||
protected BaseRequestHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {}
|
||||
|
||||
protected BaseRequestHandler(string httpMethod, string path, string name, string description)
|
||||
{
|
||||
Name = name;
|
||||
Description = description;
|
||||
m_httpMethod = httpMethod;
|
||||
m_path = path;
|
||||
}
|
||||
|
||||
@@ -34,8 +34,9 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
public abstract byte[] Handle(string path, Stream request,
|
||||
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse);
|
||||
|
||||
protected BaseStreamHandler(string httpMethod, string path) : base(httpMethod, path)
|
||||
{
|
||||
}
|
||||
protected BaseStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {}
|
||||
|
||||
protected BaseStreamHandler(string httpMethod, string path, string name, string description)
|
||||
: base(httpMethod, path, name, description) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,15 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
private BinaryMethod m_method;
|
||||
|
||||
public BinaryStreamHandler(string httpMethod, string path, BinaryMethod binaryMethod)
|
||||
: this(httpMethod, path, binaryMethod, null, null) {}
|
||||
|
||||
public BinaryStreamHandler(string httpMethod, string path, BinaryMethod binaryMethod, string name, string description)
|
||||
: base(httpMethod, path, name, description)
|
||||
{
|
||||
m_method = binaryMethod;
|
||||
}
|
||||
|
||||
public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
byte[] data = ReadFully(request);
|
||||
@@ -45,12 +54,6 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
return Encoding.UTF8.GetBytes(responseString);
|
||||
}
|
||||
|
||||
public BinaryStreamHandler(string httpMethod, string path, BinaryMethod binaryMethod)
|
||||
: base(httpMethod, path)
|
||||
{
|
||||
m_method = binaryMethod;
|
||||
}
|
||||
|
||||
private static byte[] ReadFully(Stream stream)
|
||||
{
|
||||
byte[] buffer = new byte[1024];
|
||||
@@ -70,4 +73,4 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -128,11 +128,5 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
/// <param name="value">string containing the header field
|
||||
/// value</param>
|
||||
void AddHeader(string key, string value);
|
||||
|
||||
/// <summary>
|
||||
/// Send the response back to the remote client
|
||||
/// </summary>
|
||||
void Send();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -32,6 +32,25 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
public interface IRequestHandler
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Name for this handler.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used for diagnostics. The path doesn't always describe what the handler does. Can be null if none
|
||||
/// specified.
|
||||
/// </remarks>
|
||||
string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Description for this handler.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Used for diagnostics. The path doesn't always describe what the handler does. Can be null if none
|
||||
/// specified.
|
||||
/// </remarks>
|
||||
string Description { get; }
|
||||
|
||||
// Return response content type
|
||||
string ContentType { get; }
|
||||
|
||||
@@ -58,4 +77,4 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
Hashtable Handle(string path, Hashtable request);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,13 +321,12 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
_httpResponse.Body.Flush();
|
||||
_httpResponse.Send();
|
||||
|
||||
}
|
||||
|
||||
public void FreeContext()
|
||||
{
|
||||
if (_httpClientContext != null)
|
||||
_httpClientContext.Close();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -28,6 +28,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using OpenMetaverse;
|
||||
|
||||
namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
public delegate void RequestMethod(UUID requestID, Hashtable request);
|
||||
@@ -44,7 +45,11 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
public NoEventsMethod NoEvents;
|
||||
public RequestMethod Request;
|
||||
public UUID Id;
|
||||
public PollServiceEventArgs(RequestMethod pRequest, HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents,UUID pId)
|
||||
|
||||
public PollServiceEventArgs(
|
||||
RequestMethod pRequest,
|
||||
HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents,
|
||||
UUID pId)
|
||||
{
|
||||
Request = pRequest;
|
||||
HasEvents = pHasEvents;
|
||||
@@ -53,4 +58,4 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
Id = pId;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,7 +31,6 @@ using OpenMetaverse;
|
||||
|
||||
namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
|
||||
public class PollServiceHttpRequest
|
||||
{
|
||||
public readonly PollServiceEventArgs PollServiceArgs;
|
||||
@@ -39,7 +38,9 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
public readonly IHttpRequest Request;
|
||||
public readonly int RequestTime;
|
||||
public readonly UUID RequestID;
|
||||
public PollServiceHttpRequest(PollServiceEventArgs pPollServiceArgs, IHttpClientContext pHttpContext, IHttpRequest pRequest)
|
||||
|
||||
public PollServiceHttpRequest(
|
||||
PollServiceEventArgs pPollServiceArgs, IHttpClientContext pHttpContext, IHttpRequest pRequest)
|
||||
{
|
||||
PollServiceArgs = pPollServiceArgs;
|
||||
HttpContext = pHttpContext;
|
||||
@@ -48,4 +49,4 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
RequestID = UUID.Random();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -66,6 +66,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
ThreadPriority.Normal,
|
||||
false,
|
||||
true,
|
||||
null,
|
||||
int.MaxValue);
|
||||
}
|
||||
|
||||
@@ -75,6 +76,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
ThreadPriority.Normal,
|
||||
false,
|
||||
true,
|
||||
null,
|
||||
1000 * 60 * 10);
|
||||
}
|
||||
|
||||
@@ -138,9 +140,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
foreach (object o in m_requests)
|
||||
{
|
||||
PollServiceHttpRequest req = (PollServiceHttpRequest) o;
|
||||
m_server.DoHTTPGruntWork(
|
||||
req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id),
|
||||
new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request), req.HttpContext));
|
||||
PollServiceWorkerThread.DoHTTPGruntWork(
|
||||
m_server, req, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
|
||||
}
|
||||
|
||||
m_requests.Clear();
|
||||
@@ -149,6 +150,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
t.Abort();
|
||||
}
|
||||
|
||||
m_running = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -90,15 +90,16 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
}
|
||||
|
||||
Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id, str.ReadToEnd());
|
||||
m_server.DoHTTPGruntWork(responsedata,
|
||||
new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request),req.HttpContext));
|
||||
DoHTTPGruntWork(m_server, req, responsedata);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((Environment.TickCount - req.RequestTime) > m_timeout)
|
||||
{
|
||||
m_server.DoHTTPGruntWork(req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id),
|
||||
new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request),req.HttpContext));
|
||||
DoHTTPGruntWork(
|
||||
m_server,
|
||||
req,
|
||||
req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -119,5 +120,45 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
m_request.Enqueue(pPollServiceHttpRequest);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// FIXME: This should be part of BaseHttpServer
|
||||
/// </summary>
|
||||
internal static void DoHTTPGruntWork(BaseHttpServer server, PollServiceHttpRequest req, Hashtable responsedata)
|
||||
{
|
||||
OSHttpResponse response
|
||||
= new OSHttpResponse(new HttpResponse(req.HttpContext, req.Request), req.HttpContext);
|
||||
|
||||
byte[] buffer = server.DoHTTPGruntWork(responsedata, response);
|
||||
|
||||
response.SendChunked = false;
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.ContentEncoding = Encoding.UTF8;
|
||||
|
||||
try
|
||||
{
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_log.Warn(string.Format("[POLL SERVICE WORKER THREAD]: Error ", ex));
|
||||
}
|
||||
finally
|
||||
{
|
||||
//response.OutputStream.Close();
|
||||
try
|
||||
{
|
||||
response.OutputStream.Flush();
|
||||
response.Send();
|
||||
|
||||
//if (!response.KeepAlive && response.ReuseContext)
|
||||
// response.FreeContext();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Warn(String.Format("[POLL SERVICE WORKER THREAD]: Error ", e));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,11 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
private RestDeserialiseMethod<TRequest, TResponse> m_method;
|
||||
|
||||
public RestDeserialiseHandler(string httpMethod, string path, RestDeserialiseMethod<TRequest, TResponse> method)
|
||||
: base(httpMethod, path)
|
||||
: this(httpMethod, path, method, null, null) {}
|
||||
|
||||
public RestDeserialiseHandler(
|
||||
string httpMethod, string path, RestDeserialiseMethod<TRequest, TResponse> method, string name, string description)
|
||||
: base(httpMethod, path, name, description)
|
||||
{
|
||||
m_method = method;
|
||||
}
|
||||
|
||||
@@ -38,19 +38,25 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
get { return m_dhttpMethod; }
|
||||
}
|
||||
|
||||
public override Hashtable Handle(string path, Hashtable request)
|
||||
{
|
||||
|
||||
string param = GetParam(path);
|
||||
request.Add("param", param);
|
||||
request.Add("path", path);
|
||||
return m_dhttpMethod(request);
|
||||
}
|
||||
|
||||
public RestHTTPHandler(string httpMethod, string path, GenericHTTPMethod dhttpMethod)
|
||||
: base(httpMethod, path)
|
||||
{
|
||||
m_dhttpMethod = dhttpMethod;
|
||||
}
|
||||
|
||||
public RestHTTPHandler(
|
||||
string httpMethod, string path, GenericHTTPMethod dhttpMethod, string name, string description)
|
||||
: base(httpMethod, path, name, description)
|
||||
{
|
||||
m_dhttpMethod = dhttpMethod;
|
||||
}
|
||||
|
||||
public override Hashtable Handle(string path, Hashtable request)
|
||||
{
|
||||
string param = GetParam(path);
|
||||
request.Add("param", param);
|
||||
request.Add("path", path);
|
||||
return m_dhttpMethod(request);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,6 +39,15 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
get { return m_restMethod; }
|
||||
}
|
||||
|
||||
public RestStreamHandler(string httpMethod, string path, RestMethod restMethod)
|
||||
: this(httpMethod, path, restMethod, null, null) {}
|
||||
|
||||
public RestStreamHandler(string httpMethod, string path, RestMethod restMethod, string name, string description)
|
||||
: base(httpMethod, path, name, description)
|
||||
{
|
||||
m_restMethod = restMethod;
|
||||
}
|
||||
|
||||
public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
Encoding encoding = Encoding.UTF8;
|
||||
@@ -52,10 +61,5 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
return Encoding.UTF8.GetBytes(responseString);
|
||||
}
|
||||
|
||||
public RestStreamHandler(string httpMethod, string path, RestMethod restMethod) : base(httpMethod, path)
|
||||
{
|
||||
m_restMethod = restMethod;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,57 +25,209 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Net;
|
||||
using log4net;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Console;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
|
||||
namespace OpenSim.Framework.Servers
|
||||
{
|
||||
public class MainServer
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private static BaseHttpServer instance = null;
|
||||
private static Dictionary<uint, BaseHttpServer> m_Servers =
|
||||
new Dictionary<uint, BaseHttpServer>();
|
||||
private static Dictionary<uint, BaseHttpServer> m_Servers = new Dictionary<uint, BaseHttpServer>();
|
||||
|
||||
/// <summary>
|
||||
/// Control the printing of certain debug messages.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If DebugLevel >= 1, then short warnings are logged when receiving bad input data.
|
||||
/// If DebugLevel >= 2, then long warnings are logged when receiving bad input data.
|
||||
/// If DebugLevel >= 3, then short notices about all incoming non-poll HTTP requests are logged.
|
||||
/// </remarks>
|
||||
public static int DebugLevel
|
||||
{
|
||||
get { return s_debugLevel; }
|
||||
set
|
||||
{
|
||||
s_debugLevel = value;
|
||||
|
||||
lock (m_Servers)
|
||||
foreach (BaseHttpServer server in m_Servers.Values)
|
||||
server.DebugLevel = s_debugLevel;
|
||||
}
|
||||
}
|
||||
|
||||
private static int s_debugLevel;
|
||||
|
||||
/// <summary>
|
||||
/// Set the main HTTP server instance.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This will be used to register all handlers that listen to the default port.
|
||||
/// </remarks>
|
||||
/// <exception cref='Exception'>
|
||||
/// Thrown if the HTTP server has not already been registered via AddHttpServer()
|
||||
/// </exception>
|
||||
public static BaseHttpServer Instance
|
||||
{
|
||||
get { return instance; }
|
||||
set { instance = value; }
|
||||
|
||||
set
|
||||
{
|
||||
lock (m_Servers)
|
||||
if (!m_Servers.ContainsValue(value))
|
||||
throw new Exception("HTTP server must already have been registered to be set as the main instance");
|
||||
|
||||
instance = value;
|
||||
}
|
||||
}
|
||||
|
||||
public static IHttpServer GetHttpServer(uint port)
|
||||
/// <summary>
|
||||
/// Get all the registered servers.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Returns a copy of the dictionary so this can be iterated through without locking.
|
||||
/// </remarks>
|
||||
/// <value></value>
|
||||
public static Dictionary<uint, BaseHttpServer> Servers
|
||||
{
|
||||
return GetHttpServer(port,null);
|
||||
get { return new Dictionary<uint, BaseHttpServer>(m_Servers); }
|
||||
}
|
||||
|
||||
|
||||
public static void RegisterHttpConsoleCommands(ICommandConsole console)
|
||||
{
|
||||
console.Commands.AddCommand(
|
||||
"Debug", false, "debug http", "debug http [<level>]",
|
||||
"Turn on inbound non-poll http request debugging.",
|
||||
"If level <= 0, then no extra logging is done.\n"
|
||||
+ "If level >= 1, then short warnings are logged when receiving bad input data.\n"
|
||||
+ "If level >= 2, then long warnings are logged when receiving bad input data.\n"
|
||||
+ "If level >= 3, then short notices about all incoming non-poll HTTP requests are logged.\n"
|
||||
+ "If no level is specified then the current level is returned.",
|
||||
HandleDebugHttpCommand);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Turn on some debugging values for OpenSim.
|
||||
/// </summary>
|
||||
/// <param name="args"></param>
|
||||
private static void HandleDebugHttpCommand(string module, string[] args)
|
||||
{
|
||||
if (args.Length == 3)
|
||||
{
|
||||
int newDebug;
|
||||
if (int.TryParse(args[2], out newDebug))
|
||||
{
|
||||
MainServer.DebugLevel = newDebug;
|
||||
MainConsole.Instance.OutputFormat("Debug http level set to {0}", newDebug);
|
||||
}
|
||||
}
|
||||
else if (args.Length == 2)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat("Current debug http level is {0}", MainServer.DebugLevel);
|
||||
}
|
||||
else
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug http 0..3");
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Register an already started HTTP server to the collection of known servers.
|
||||
/// </summary>
|
||||
/// <param name='server'></param>
|
||||
public static void AddHttpServer(BaseHttpServer server)
|
||||
{
|
||||
m_Servers.Add(server.Port, server);
|
||||
lock (m_Servers)
|
||||
{
|
||||
if (m_Servers.ContainsKey(server.Port))
|
||||
throw new Exception(string.Format("HTTP server for port {0} already exists.", server.Port));
|
||||
|
||||
m_Servers.Add(server.Port, server);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the http server listening on the given port.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// It is the responsibility of the caller to do clean up.
|
||||
/// </remarks>
|
||||
/// <param name='port'></param>
|
||||
/// <returns></returns>
|
||||
public static bool RemoveHttpServer(uint port)
|
||||
{
|
||||
lock (m_Servers)
|
||||
return m_Servers.Remove(port);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Does this collection of servers contain one with the given port?
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Unlike GetHttpServer, this will not instantiate a server if one does not exist on that port.
|
||||
/// </remarks>
|
||||
/// <param name='port'></param>
|
||||
/// <returns>true if a server with the given port is registered, false otherwise.</returns>
|
||||
public static bool ContainsHttpServer(uint port)
|
||||
{
|
||||
lock (m_Servers)
|
||||
return m_Servers.ContainsKey(port);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the default http server or an http server for a specific port.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the requested HTTP server doesn't already exist then a new one is instantiated and started.
|
||||
/// </remarks>
|
||||
/// <returns></returns>
|
||||
/// <param name='port'>If 0 then the default HTTP server is returned.</param>
|
||||
public static IHttpServer GetHttpServer(uint port)
|
||||
{
|
||||
return GetHttpServer(port, null);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the default http server, an http server for a specific port
|
||||
/// and/or an http server bound to a specific address
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If the requested HTTP server doesn't already exist then a new one is instantiated and started.
|
||||
/// </remarks>
|
||||
/// <returns></returns>
|
||||
/// <param name='port'>If 0 then the default HTTP server is returned.</param>
|
||||
/// <param name='ipaddr'>A specific IP address to bind to. If null then the default IP address is used.</param>
|
||||
public static IHttpServer GetHttpServer(uint port, IPAddress ipaddr)
|
||||
{
|
||||
if (port == 0)
|
||||
return Instance;
|
||||
|
||||
if (instance != null && port == Instance.Port)
|
||||
return Instance;
|
||||
|
||||
if (m_Servers.ContainsKey(port))
|
||||
lock (m_Servers)
|
||||
{
|
||||
if (m_Servers.ContainsKey(port))
|
||||
return m_Servers[port];
|
||||
|
||||
m_Servers[port] = new BaseHttpServer(port);
|
||||
|
||||
if (ipaddr != null)
|
||||
m_Servers[port].ListenIPAddress = ipaddr;
|
||||
|
||||
m_Servers[port].Start();
|
||||
|
||||
return m_Servers[port];
|
||||
|
||||
m_Servers[port] = new BaseHttpServer(port);
|
||||
|
||||
if (ipaddr != null)
|
||||
m_Servers[port].ListenIPAddress = ipaddr;
|
||||
|
||||
m_log.InfoFormat("[MAIN HTTP SERVER]: Starting main http server on port {0}", port);
|
||||
m_Servers[port].Start();
|
||||
|
||||
return m_Servers[port];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -30,7 +30,7 @@ namespace OpenSim
|
||||
public class VersionInfo
|
||||
{
|
||||
private const string VERSION_NUMBER = "0.7.3";
|
||||
private const Flavour VERSION_FLAVOUR = Flavour.Dev;
|
||||
private const Flavour VERSION_FLAVOUR = Flavour.Extended;
|
||||
|
||||
public enum Flavour
|
||||
{
|
||||
@@ -39,7 +39,8 @@ namespace OpenSim
|
||||
RC1,
|
||||
RC2,
|
||||
Release,
|
||||
Post_Fixes
|
||||
Post_Fixes,
|
||||
Extended
|
||||
}
|
||||
|
||||
public static string Version
|
||||
|
||||
@@ -26,8 +26,8 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.StructuredData;
|
||||
|
||||
@@ -46,8 +46,12 @@ namespace OpenSim.Framework.Statistics
|
||||
sb.Append(Environment.NewLine);
|
||||
sb.Append(
|
||||
string.Format(
|
||||
"Allocated to OpenSim : {0} MB" + Environment.NewLine,
|
||||
"Allocated to OpenSim objects: {0} MB\n",
|
||||
Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0)));
|
||||
sb.Append(
|
||||
string.Format(
|
||||
"Process memory : {0} MB\n",
|
||||
Math.Round(Process.GetCurrentProcess().WorkingSet64 / 1024.0 / 1024.0)));
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
@@ -34,14 +34,12 @@ namespace OpenSim.Framework.Statistics
|
||||
{
|
||||
private static AssetStatsCollector assetStats;
|
||||
private static UserStatsCollector userStats;
|
||||
private static SimExtraStatsCollector simExtraStats;
|
||||
private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector();
|
||||
|
||||
public static AssetStatsCollector AssetStats { get { return assetStats; } }
|
||||
public static UserStatsCollector UserStats { get { return userStats; } }
|
||||
public static SimExtraStatsCollector SimExtraStats { get { return simExtraStats; } }
|
||||
|
||||
private StatsManager() {}
|
||||
|
||||
/// <summary>
|
||||
/// Start collecting statistics related to assets.
|
||||
/// Should only be called once.
|
||||
@@ -63,16 +61,5 @@ namespace OpenSim.Framework.Statistics
|
||||
|
||||
return userStats;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start collecting extra sim statistics apart from those collected for the client.
|
||||
/// Should only be called once.
|
||||
/// </summary>
|
||||
public static SimExtraStatsCollector StartCollectingSimExtraStats()
|
||||
{
|
||||
simExtraStats = new SimExtraStatsCollector();
|
||||
|
||||
return simExtraStats;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,12 +81,15 @@ namespace OpenSim.Framework
|
||||
|
||||
private static uint nextXferID = 5000;
|
||||
private static Random randomClass = new Random();
|
||||
|
||||
// Get a list of invalid file characters (OS dependent)
|
||||
private static string regexInvalidFileChars = "[" + new String(Path.GetInvalidFileNameChars()) + "]";
|
||||
private static string regexInvalidPathChars = "[" + new String(Path.GetInvalidPathChars()) + "]";
|
||||
private static object XferLock = new object();
|
||||
/// <summary>Thread pool used for Util.FireAndForget if
|
||||
/// FireAndForgetMethod.SmartThreadPool is used</summary>
|
||||
|
||||
/// <summary>
|
||||
/// Thread pool used for Util.FireAndForget if FireAndForgetMethod.SmartThreadPool is used
|
||||
/// </summary>
|
||||
private static SmartThreadPool m_ThreadPool;
|
||||
|
||||
// Unix-epoch starts at January 1st 1970, 00:00:00 UTC. And all our times in the server are (or at least should be) in UTC.
|
||||
@@ -144,7 +147,6 @@ namespace OpenSim.Framework
|
||||
return lerp(y, lerp(x, a, b), lerp(x, c, d));
|
||||
}
|
||||
|
||||
|
||||
public static Encoding UTF8 = Encoding.UTF8;
|
||||
|
||||
/// <value>
|
||||
@@ -1671,6 +1673,61 @@ namespace OpenSim.Framework
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a thread pool report.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static string GetThreadPoolReport()
|
||||
{
|
||||
string threadPoolUsed = null;
|
||||
int maxThreads = 0;
|
||||
int minThreads = 0;
|
||||
int allocatedThreads = 0;
|
||||
int inUseThreads = 0;
|
||||
int waitingCallbacks = 0;
|
||||
int completionPortThreads = 0;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
if (FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
|
||||
{
|
||||
threadPoolUsed = "SmartThreadPool";
|
||||
maxThreads = m_ThreadPool.MaxThreads;
|
||||
minThreads = m_ThreadPool.MinThreads;
|
||||
inUseThreads = m_ThreadPool.InUseThreads;
|
||||
allocatedThreads = m_ThreadPool.ActiveThreads;
|
||||
waitingCallbacks = m_ThreadPool.WaitingCallbacks;
|
||||
}
|
||||
else if (
|
||||
FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem
|
||||
|| FireAndForgetMethod == FireAndForgetMethod.UnsafeQueueUserWorkItem)
|
||||
{
|
||||
threadPoolUsed = "BuiltInThreadPool";
|
||||
ThreadPool.GetMaxThreads(out maxThreads, out completionPortThreads);
|
||||
ThreadPool.GetMinThreads(out minThreads, out completionPortThreads);
|
||||
int availableThreads;
|
||||
ThreadPool.GetAvailableThreads(out availableThreads, out completionPortThreads);
|
||||
inUseThreads = maxThreads - availableThreads;
|
||||
allocatedThreads = -1;
|
||||
waitingCallbacks = -1;
|
||||
}
|
||||
|
||||
if (threadPoolUsed != null)
|
||||
{
|
||||
sb.AppendFormat("Thread pool used : {0}\n", threadPoolUsed);
|
||||
sb.AppendFormat("Max threads : {0}\n", maxThreads);
|
||||
sb.AppendFormat("Min threads : {0}\n", minThreads);
|
||||
sb.AppendFormat("Allocated threads : {0}\n", allocatedThreads < 0 ? "not applicable" : allocatedThreads.ToString());
|
||||
sb.AppendFormat("In use threads : {0}\n", inUseThreads);
|
||||
sb.AppendFormat("Work items waiting : {0}\n", waitingCallbacks < 0 ? "not available" : waitingCallbacks.ToString());
|
||||
}
|
||||
else
|
||||
{
|
||||
sb.AppendFormat("Thread pool not used\n");
|
||||
}
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
private static object SmartThreadPoolCallback(object o)
|
||||
{
|
||||
object[] array = (object[])o;
|
||||
@@ -1696,6 +1753,20 @@ namespace OpenSim.Framework
|
||||
}
|
||||
const Int32 EnvironmentTickCountMask = 0x3fffffff;
|
||||
|
||||
/// <summary>
|
||||
/// Environment.TickCount is an int but it counts all 32 bits so it goes positive
|
||||
/// and negative every 24.9 days. Subtracts the passed value (previously fetched by
|
||||
/// 'EnvironmentTickCount()') and accounts for any wrapping.
|
||||
/// </summary>
|
||||
/// <param name="newValue"></param>
|
||||
/// <param name="prevValue"></param>
|
||||
/// <returns>subtraction of passed prevValue from current Environment.TickCount</returns>
|
||||
public static Int32 EnvironmentTickCountSubtract(Int32 newValue, Int32 prevValue)
|
||||
{
|
||||
Int32 diff = newValue - prevValue;
|
||||
return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Environment.TickCount is an int but it counts all 32 bits so it goes positive
|
||||
/// and negative every 24.9 days. Subtracts the passed value (previously fetched by
|
||||
@@ -1704,8 +1775,7 @@ namespace OpenSim.Framework
|
||||
/// <returns>subtraction of passed prevValue from current Environment.TickCount</returns>
|
||||
public static Int32 EnvironmentTickCountSubtract(Int32 prevValue)
|
||||
{
|
||||
Int32 diff = EnvironmentTickCount() - prevValue;
|
||||
return (diff >= 0) ? diff : (diff + EnvironmentTickCountMask + 1);
|
||||
return EnvironmentTickCountSubtract(EnvironmentTickCount(), prevValue);
|
||||
}
|
||||
|
||||
// Returns value of Tick Count A - TickCount B accounting for wrapping of TickCount
|
||||
|
||||
@@ -41,8 +41,8 @@ namespace OpenSim.Framework
|
||||
/// <summary>Timer interval in milliseconds for the watchdog timer</summary>
|
||||
const double WATCHDOG_INTERVAL_MS = 2500.0d;
|
||||
|
||||
/// <summary>Maximum timeout in milliseconds before a thread is considered dead</summary>
|
||||
const int WATCHDOG_TIMEOUT_MS = 5000;
|
||||
/// <summary>Default timeout in milliseconds before a thread is considered dead</summary>
|
||||
public const int DEFAULT_WATCHDOG_TIMEOUT_MS = 5000;
|
||||
|
||||
[System.Diagnostics.DebuggerDisplay("{Thread.Name}")]
|
||||
public class ThreadWatchdogInfo
|
||||
@@ -58,7 +58,7 @@ namespace OpenSim.Framework
|
||||
public int FirstTick { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// First time this heartbeat update was invoked
|
||||
/// Last time this heartbeat update was invoked
|
||||
/// </summary>
|
||||
public int LastTick { get; set; }
|
||||
|
||||
@@ -77,6 +77,11 @@ namespace OpenSim.Framework
|
||||
/// </summary>
|
||||
public bool AlarmIfTimeout { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Method execute if alarm goes off. If null then no alarm method is fired.
|
||||
/// </summary>
|
||||
public Func<string> AlarmMethod { get; set; }
|
||||
|
||||
public ThreadWatchdogInfo(Thread thread, int timeout)
|
||||
{
|
||||
Thread = thread;
|
||||
@@ -87,27 +92,33 @@ namespace OpenSim.Framework
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This event is called whenever a tracked thread is stopped or
|
||||
/// has not called UpdateThread() in time
|
||||
/// </summary>
|
||||
/// <param name="thread">The thread that has been identified as dead</param>
|
||||
/// <param name="lastTick">The last time this thread called UpdateThread()</param>
|
||||
public delegate void WatchdogTimeout(Thread thread, int lastTick);
|
||||
|
||||
/// <summary>This event is called whenever a tracked thread is
|
||||
/// stopped or has not called UpdateThread() in time</summary>
|
||||
public static event WatchdogTimeout OnWatchdogTimeout;
|
||||
/// This event is called whenever a tracked thread is
|
||||
/// stopped or has not called UpdateThread() in time<
|
||||
/// /summary>
|
||||
public static event Action<ThreadWatchdogInfo> OnWatchdogTimeout;
|
||||
|
||||
private static readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static Dictionary<int, ThreadWatchdogInfo> m_threads;
|
||||
private static System.Timers.Timer m_watchdogTimer;
|
||||
|
||||
/// <summary>
|
||||
/// Last time the watchdog thread ran.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Should run every WATCHDOG_INTERVAL_MS
|
||||
/// </remarks>
|
||||
public static int LastWatchdogThreadTick { get; private set; }
|
||||
|
||||
static Watchdog()
|
||||
{
|
||||
m_threads = new Dictionary<int, ThreadWatchdogInfo>();
|
||||
m_watchdogTimer = new System.Timers.Timer(WATCHDOG_INTERVAL_MS);
|
||||
m_watchdogTimer.AutoReset = false;
|
||||
m_watchdogTimer.Elapsed += WatchdogTimerElapsed;
|
||||
|
||||
// Set now so we don't get alerted on the first run
|
||||
LastWatchdogThreadTick = Environment.TickCount & Int32.MaxValue;
|
||||
|
||||
m_watchdogTimer.Start();
|
||||
}
|
||||
|
||||
@@ -123,7 +134,7 @@ namespace OpenSim.Framework
|
||||
public static Thread StartThread(
|
||||
ThreadStart start, string name, ThreadPriority priority, bool isBackground, bool alarmIfTimeout)
|
||||
{
|
||||
return StartThread(start, name, priority, isBackground, alarmIfTimeout, WATCHDOG_TIMEOUT_MS);
|
||||
return StartThread(start, name, priority, isBackground, alarmIfTimeout, null, DEFAULT_WATCHDOG_TIMEOUT_MS);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -135,17 +146,24 @@ namespace OpenSim.Framework
|
||||
/// <param name="isBackground">True to run this thread as a background
|
||||
/// thread, otherwise false</param>
|
||||
/// <param name="alarmIfTimeout">Trigger an alarm function is we have timed out</param>
|
||||
/// <param name="alarmMethod">
|
||||
/// Alarm method to call if alarmIfTimeout is true and there is a timeout.
|
||||
/// Normally, this will just return some useful debugging information.
|
||||
/// </param>
|
||||
/// <param name="timeout">Number of milliseconds to wait until we issue a warning about timeout.</param>
|
||||
/// <returns>The newly created Thread object</returns>
|
||||
public static Thread StartThread(
|
||||
ThreadStart start, string name, ThreadPriority priority, bool isBackground, bool alarmIfTimeout, int timeout)
|
||||
ThreadStart start, string name, ThreadPriority priority, bool isBackground,
|
||||
bool alarmIfTimeout, Func<string> alarmMethod, int timeout)
|
||||
{
|
||||
Thread thread = new Thread(start);
|
||||
thread.Name = name;
|
||||
thread.Priority = priority;
|
||||
thread.IsBackground = isBackground;
|
||||
|
||||
ThreadWatchdogInfo twi = new ThreadWatchdogInfo(thread, timeout) { AlarmIfTimeout = alarmIfTimeout };
|
||||
ThreadWatchdogInfo twi
|
||||
= new ThreadWatchdogInfo(thread, timeout)
|
||||
{ AlarmIfTimeout = alarmIfTimeout, AlarmMethod = alarmMethod };
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[WATCHDOG]: Started tracking thread {0}, ID {1}", twi.Thread.Name, twi.Thread.ManagedThreadId);
|
||||
@@ -258,7 +276,17 @@ namespace OpenSim.Framework
|
||||
/// <param name="e"></param>
|
||||
private static void WatchdogTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
|
||||
{
|
||||
WatchdogTimeout callback = OnWatchdogTimeout;
|
||||
int now = Environment.TickCount & Int32.MaxValue;
|
||||
int msElapsed = now - LastWatchdogThreadTick;
|
||||
|
||||
if (msElapsed > WATCHDOG_INTERVAL_MS * 2)
|
||||
m_log.WarnFormat(
|
||||
"[WATCHDOG]: {0} ms since Watchdog last ran. Interval should be approximately {1} ms",
|
||||
msElapsed, WATCHDOG_INTERVAL_MS);
|
||||
|
||||
LastWatchdogThreadTick = Environment.TickCount & Int32.MaxValue;
|
||||
|
||||
Action<ThreadWatchdogInfo> callback = OnWatchdogTimeout;
|
||||
|
||||
if (callback != null)
|
||||
{
|
||||
@@ -266,8 +294,6 @@ namespace OpenSim.Framework
|
||||
|
||||
lock (m_threads)
|
||||
{
|
||||
int now = Environment.TickCount & Int32.MaxValue;
|
||||
|
||||
foreach (ThreadWatchdogInfo threadInfo in m_threads.Values)
|
||||
{
|
||||
if (threadInfo.Thread.ThreadState == ThreadState.Stopped)
|
||||
@@ -296,7 +322,7 @@ namespace OpenSim.Framework
|
||||
|
||||
if (callbackInfos != null)
|
||||
foreach (ThreadWatchdogInfo callbackInfo in callbackInfos)
|
||||
callback(callbackInfo.Thread, callbackInfo.LastTick);
|
||||
callback(callbackInfo);
|
||||
}
|
||||
|
||||
m_watchdogTimer.Start();
|
||||
|
||||
@@ -53,45 +53,36 @@ namespace OpenSim.Framework
|
||||
LogManager.GetLogger(
|
||||
MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private static int m_requestNumber = 0;
|
||||
/// <summary>
|
||||
/// Request number for diagnostic purposes.
|
||||
/// </summary>
|
||||
public static int RequestNumber = 0;
|
||||
|
||||
// this is the header field used to communicate the local request id
|
||||
// used for performance and debugging
|
||||
/// <summary>
|
||||
/// this is the header field used to communicate the local request id
|
||||
/// used for performance and debugging
|
||||
/// </summary>
|
||||
public const string OSHeaderRequestID = "opensim-request-id";
|
||||
|
||||
// number of milliseconds a call can take before it is considered
|
||||
// a "long" call for warning & debugging purposes
|
||||
public const int LongCallTime = 500;
|
||||
/// <summary>
|
||||
/// Number of milliseconds a call can take before it is considered
|
||||
/// a "long" call for warning & debugging purposes
|
||||
/// </summary>
|
||||
public const int LongCallTime = 3000;
|
||||
|
||||
// /// <summary>
|
||||
// /// Send LLSD to an HTTP client in application/llsd+json form
|
||||
// /// </summary>
|
||||
// /// <param name="response">HTTP response to send the data in</param>
|
||||
// /// <param name="body">LLSD to send to the client</param>
|
||||
// public static void SendJSONResponse(OSHttpResponse response, OSDMap body)
|
||||
// {
|
||||
// byte[] responseData = Encoding.UTF8.GetBytes(OSDParser.SerializeJsonString(body));
|
||||
//
|
||||
// response.ContentEncoding = Encoding.UTF8;
|
||||
// response.ContentLength = responseData.Length;
|
||||
// response.ContentType = "application/llsd+json";
|
||||
// response.Body.Write(responseData, 0, responseData.Length);
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Send LLSD to an HTTP client in application/llsd+xml form
|
||||
// /// </summary>
|
||||
// /// <param name="response">HTTP response to send the data in</param>
|
||||
// /// <param name="body">LLSD to send to the client</param>
|
||||
// public static void SendXMLResponse(OSHttpResponse response, OSDMap body)
|
||||
// {
|
||||
// byte[] responseData = OSDParser.SerializeLLSDXmlBytes(body);
|
||||
//
|
||||
// response.ContentEncoding = Encoding.UTF8;
|
||||
// response.ContentLength = responseData.Length;
|
||||
// response.ContentType = "application/llsd+xml";
|
||||
// response.Body.Write(responseData, 0, responseData.Length);
|
||||
// }
|
||||
/// <summary>
|
||||
/// The maximum length of any data logged because of a long request time.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is to truncate any really large post data, such as an asset. In theory, the first section should
|
||||
/// give us useful information about the call (which agent it relates to if applicable, etc.).
|
||||
/// </remarks>
|
||||
public const int MaxRequestDiagLength = 100;
|
||||
|
||||
/// <summary>
|
||||
/// Dictionary of end points
|
||||
/// </summary>
|
||||
private static Dictionary<string,object> m_endpointSerializer = new Dictionary<string,object>();
|
||||
|
||||
/// <summary>
|
||||
/// Make a GET or GET-like request to a web service that returns LLSD
|
||||
@@ -166,12 +157,14 @@ namespace OpenSim.Framework
|
||||
|
||||
public static OSDMap ServiceOSDRequest(string url, OSDMap data, string method, int timeout, bool compressed)
|
||||
{
|
||||
int reqnum = m_requestNumber++;
|
||||
int reqnum = RequestNumber++;
|
||||
|
||||
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
|
||||
|
||||
string errorMessage = "unknown error";
|
||||
int tickstart = Util.EnvironmentTickCount();
|
||||
int tickdata = 0;
|
||||
string strBuffer = null;
|
||||
|
||||
try
|
||||
{
|
||||
@@ -186,7 +179,7 @@ namespace OpenSim.Framework
|
||||
// If there is some input, write it into the request
|
||||
if (data != null)
|
||||
{
|
||||
string strBuffer = OSDParser.SerializeJsonString(data);
|
||||
strBuffer = OSDParser.SerializeJsonString(data);
|
||||
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(strBuffer);
|
||||
|
||||
if (compressed)
|
||||
@@ -246,14 +239,23 @@ namespace OpenSim.Framework
|
||||
}
|
||||
finally
|
||||
{
|
||||
// This just dumps a warning for any operation that takes more than 100 ms
|
||||
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
|
||||
if (tickdiff > LongCallTime)
|
||||
m_log.DebugFormat("[WEB UTIL]: osd request <{0}> (URI:{1}, METHOD:{2}) took {3}ms overall, {4}ms writing",
|
||||
reqnum,url,method,tickdiff,tickdata);
|
||||
m_log.InfoFormat(
|
||||
"[OSD REQUEST]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
|
||||
reqnum,
|
||||
method,
|
||||
url,
|
||||
tickdiff,
|
||||
tickdata,
|
||||
strBuffer != null
|
||||
? (strBuffer.Length > MaxRequestDiagLength ? strBuffer.Remove(MaxRequestDiagLength) : strBuffer)
|
||||
: "");
|
||||
}
|
||||
|
||||
m_log.DebugFormat("[WEB UTIL]: <{0}> osd request for {1}, method {2} FAILED: {3}", reqnum, url, method, errorMessage);
|
||||
m_log.DebugFormat(
|
||||
"[WEB UTIL]: <{0}> osd request for {1}, method {2} FAILED: {3}", reqnum, url, method, errorMessage);
|
||||
|
||||
return ErrorResponseMap(errorMessage);
|
||||
}
|
||||
|
||||
@@ -314,17 +316,17 @@ namespace OpenSim.Framework
|
||||
|
||||
public static OSDMap ServiceFormRequest(string url, NameValueCollection data, int timeout)
|
||||
{
|
||||
int reqnum = m_requestNumber++;
|
||||
int reqnum = RequestNumber++;
|
||||
string method = (data != null && data["RequestMethod"] != null) ? data["RequestMethod"] : "unknown";
|
||||
// m_log.DebugFormat("[WEB UTIL]: <{0}> start form request for {1}, method {2}",reqnum,url,method);
|
||||
|
||||
string errorMessage = "unknown error";
|
||||
int tickstart = Util.EnvironmentTickCount();
|
||||
int tickdata = 0;
|
||||
string queryString = null;
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
|
||||
request.Method = "POST";
|
||||
request.Timeout = timeout;
|
||||
@@ -335,7 +337,7 @@ namespace OpenSim.Framework
|
||||
|
||||
if (data != null)
|
||||
{
|
||||
string queryString = BuildQueryString(data);
|
||||
queryString = BuildQueryString(data);
|
||||
byte[] buffer = System.Text.Encoding.UTF8.GetBytes(queryString);
|
||||
|
||||
request.ContentLength = buffer.Length;
|
||||
@@ -378,11 +380,20 @@ namespace OpenSim.Framework
|
||||
{
|
||||
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
|
||||
if (tickdiff > LongCallTime)
|
||||
m_log.InfoFormat("[WEB UTIL]: form request <{0}> (URI:{1}, METHOD:{2}) took {3}ms overall, {4}ms writing",
|
||||
reqnum,url,method,tickdiff,tickdata);
|
||||
m_log.InfoFormat(
|
||||
"[SERVICE FORM]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
|
||||
reqnum,
|
||||
method,
|
||||
url,
|
||||
tickdiff,
|
||||
tickdata,
|
||||
queryString != null
|
||||
? (queryString.Length > MaxRequestDiagLength) ? queryString.Remove(MaxRequestDiagLength) : queryString
|
||||
: "");
|
||||
}
|
||||
|
||||
m_log.WarnFormat("[WEB UTIL]: <{0}> form request failed: {1}",reqnum,errorMessage);
|
||||
m_log.WarnFormat("[SERVICE FORM]: <{0}> form request to {1} failed: {2}", reqnum, url, errorMessage);
|
||||
|
||||
return ErrorResponseMap(errorMessage);
|
||||
}
|
||||
|
||||
@@ -655,8 +666,6 @@ namespace OpenSim.Framework
|
||||
|
||||
return new string[0];
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static class AsynchronousRestObjectRequester
|
||||
@@ -679,6 +688,12 @@ namespace OpenSim.Framework
|
||||
public static void MakeRequest<TRequest, TResponse>(string verb,
|
||||
string requestUrl, TRequest obj, Action<TResponse> action)
|
||||
{
|
||||
int reqnum = WebUtil.RequestNumber++;
|
||||
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
|
||||
|
||||
int tickstart = Util.EnvironmentTickCount();
|
||||
int tickdata = 0;
|
||||
|
||||
// m_log.DebugFormat("[ASYNC REQUEST]: Starting {0} {1}", verb, requestUrl);
|
||||
|
||||
Type type = typeof(TRequest);
|
||||
@@ -689,12 +704,13 @@ namespace OpenSim.Framework
|
||||
XmlSerializer deserializer = new XmlSerializer(typeof(TResponse));
|
||||
|
||||
request.Method = verb;
|
||||
MemoryStream buffer = null;
|
||||
|
||||
if (verb == "POST")
|
||||
{
|
||||
request.ContentType = "text/xml";
|
||||
|
||||
MemoryStream buffer = new MemoryStream();
|
||||
buffer = new MemoryStream();
|
||||
|
||||
XmlWriterSettings settings = new XmlWriterSettings();
|
||||
settings.Encoding = Encoding.UTF8;
|
||||
@@ -716,6 +732,9 @@ namespace OpenSim.Framework
|
||||
requestStream.Write(buffer.ToArray(), 0, length);
|
||||
requestStream.Close();
|
||||
|
||||
// capture how much time was spent writing
|
||||
tickdata = Util.EnvironmentTickCountSubtract(tickstart);
|
||||
|
||||
request.BeginGetResponse(delegate(IAsyncResult ar)
|
||||
{
|
||||
response = request.EndGetResponse(ar);
|
||||
@@ -741,83 +760,108 @@ namespace OpenSim.Framework
|
||||
|
||||
}, null);
|
||||
}, null);
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
request.BeginGetResponse(delegate(IAsyncResult res2)
|
||||
else
|
||||
{
|
||||
try
|
||||
request.BeginGetResponse(delegate(IAsyncResult res2)
|
||||
{
|
||||
// If the server returns a 404, this appears to trigger a System.Net.WebException even though that isn't
|
||||
// documented in MSDN
|
||||
response = request.EndGetResponse(res2);
|
||||
|
||||
Stream respStream = null;
|
||||
try
|
||||
{
|
||||
respStream = response.GetResponseStream();
|
||||
deserial = (TResponse)deserializer.Deserialize(respStream);
|
||||
}
|
||||
catch (System.InvalidOperationException)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
respStream.Close();
|
||||
response.Close();
|
||||
}
|
||||
}
|
||||
catch (WebException e)
|
||||
{
|
||||
if (e.Status == WebExceptionStatus.ProtocolError)
|
||||
{
|
||||
if (e.Response is HttpWebResponse)
|
||||
// If the server returns a 404, this appears to trigger a System.Net.WebException even though that isn't
|
||||
// documented in MSDN
|
||||
response = request.EndGetResponse(res2);
|
||||
|
||||
Stream respStream = null;
|
||||
try
|
||||
{
|
||||
HttpWebResponse httpResponse = (HttpWebResponse)e.Response;
|
||||
|
||||
if (httpResponse.StatusCode != HttpStatusCode.NotFound)
|
||||
{
|
||||
// We don't appear to be handling any other status codes, so log these feailures to that
|
||||
// people don't spend unnecessary hours hunting phantom bugs.
|
||||
m_log.DebugFormat(
|
||||
"[ASYNC REQUEST]: Request {0} {1} failed with unexpected status code {2}",
|
||||
verb, requestUrl, httpResponse.StatusCode);
|
||||
}
|
||||
respStream = response.GetResponseStream();
|
||||
deserial = (TResponse)deserializer.Deserialize(respStream);
|
||||
}
|
||||
catch (System.InvalidOperationException)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
respStream.Close();
|
||||
response.Close();
|
||||
}
|
||||
}
|
||||
else
|
||||
catch (WebException e)
|
||||
{
|
||||
m_log.ErrorFormat("[ASYNC REQUEST]: Request {0} {1} failed with status {2} and message {3}", verb, requestUrl, e.Status, e.Message);
|
||||
if (e.Status == WebExceptionStatus.ProtocolError)
|
||||
{
|
||||
if (e.Response is HttpWebResponse)
|
||||
{
|
||||
HttpWebResponse httpResponse = (HttpWebResponse)e.Response;
|
||||
|
||||
if (httpResponse.StatusCode != HttpStatusCode.NotFound)
|
||||
{
|
||||
// We don't appear to be handling any other status codes, so log these feailures to that
|
||||
// people don't spend unnecessary hours hunting phantom bugs.
|
||||
m_log.DebugFormat(
|
||||
"[ASYNC REQUEST]: Request {0} {1} failed with unexpected status code {2}",
|
||||
verb, requestUrl, httpResponse.StatusCode);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[ASYNC REQUEST]: Request {0} {1} failed with status {2} and message {3}",
|
||||
verb, requestUrl, e.Status, e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[ASYNC REQUEST]: Request {0} {1} failed with exception {2}{3}",
|
||||
verb, requestUrl, e.Message, e.StackTrace);
|
||||
}
|
||||
|
||||
// m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString());
|
||||
|
||||
try
|
||||
{
|
||||
action(deserial);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[ASYNC REQUEST]: Request {0} {1} callback failed with exception {2}{3}",
|
||||
verb, requestUrl, e.Message, e.StackTrace);
|
||||
}
|
||||
|
||||
}, null);
|
||||
}
|
||||
|
||||
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
|
||||
if (tickdiff > WebUtil.LongCallTime)
|
||||
{
|
||||
string originalRequest = null;
|
||||
|
||||
if (buffer != null)
|
||||
{
|
||||
m_log.ErrorFormat("[ASYNC REQUEST]: Request {0} {1} failed with exception {2}", verb, requestUrl, e);
|
||||
originalRequest = Encoding.UTF8.GetString(buffer.ToArray());
|
||||
|
||||
if (originalRequest.Length > WebUtil.MaxRequestDiagLength)
|
||||
originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength);
|
||||
}
|
||||
|
||||
// m_log.DebugFormat("[ASYNC REQUEST]: Received {0}", deserial.ToString());
|
||||
|
||||
try
|
||||
{
|
||||
action(deserial);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[ASYNC REQUEST]: Request {0} {1} callback failed with exception {2}", verb, requestUrl, e);
|
||||
}
|
||||
|
||||
}, null);
|
||||
m_log.InfoFormat(
|
||||
"[ASYNC REQUEST]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
|
||||
reqnum,
|
||||
verb,
|
||||
requestUrl,
|
||||
tickdiff,
|
||||
tickdata,
|
||||
originalRequest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class SynchronousRestFormsRequester
|
||||
{
|
||||
private static readonly ILog m_log =
|
||||
LogManager.GetLogger(
|
||||
MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
/// <summary>
|
||||
/// Perform a synchronous REST request.
|
||||
@@ -831,6 +875,12 @@ namespace OpenSim.Framework
|
||||
/// the request. You'll want to make sure you deal with this as they're not uncommon</exception>
|
||||
public static string MakeRequest(string verb, string requestUrl, string obj)
|
||||
{
|
||||
int reqnum = WebUtil.RequestNumber++;
|
||||
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
|
||||
|
||||
int tickstart = Util.EnvironmentTickCount();
|
||||
int tickdata = 0;
|
||||
|
||||
WebRequest request = WebRequest.Create(requestUrl);
|
||||
request.Method = verb;
|
||||
string respstring = String.Empty;
|
||||
@@ -859,12 +909,16 @@ namespace OpenSim.Framework
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[FORMS]: exception occured on sending request to {0}: " + e.ToString(), requestUrl);
|
||||
m_log.DebugFormat(
|
||||
"[FORMS]: exception occured {0} {1}: {2}{3}", verb, requestUrl, e.Message, e.StackTrace);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (requestStream != null)
|
||||
requestStream.Close();
|
||||
|
||||
// capture how much time was spent writing
|
||||
tickdata = Util.EnvironmentTickCountSubtract(tickstart);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -885,7 +939,9 @@ namespace OpenSim.Framework
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[FORMS]: exception occured on receiving reply " + e.ToString());
|
||||
m_log.DebugFormat(
|
||||
"[FORMS]: Exception occured on receiving {0} {1}: {2}{3}",
|
||||
verb, requestUrl, e.Message, e.StackTrace);
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -898,9 +954,21 @@ namespace OpenSim.Framework
|
||||
catch (System.InvalidOperationException)
|
||||
{
|
||||
// This is what happens when there is invalid XML
|
||||
m_log.DebugFormat("[FORMS]: InvalidOperationException on receiving request");
|
||||
m_log.DebugFormat("[FORMS]: InvalidOperationException on receiving {0} {1}", verb, requestUrl);
|
||||
}
|
||||
}
|
||||
|
||||
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
|
||||
if (tickdiff > WebUtil.LongCallTime)
|
||||
m_log.InfoFormat(
|
||||
"[FORMS]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
|
||||
reqnum,
|
||||
verb,
|
||||
requestUrl,
|
||||
tickdiff,
|
||||
tickdata,
|
||||
obj.Length > WebUtil.MaxRequestDiagLength ? obj.Remove(WebUtil.MaxRequestDiagLength) : obj);
|
||||
|
||||
return respstring;
|
||||
}
|
||||
}
|
||||
@@ -923,17 +991,24 @@ namespace OpenSim.Framework
|
||||
/// the request. You'll want to make sure you deal with this as they're not uncommon</exception>
|
||||
public static TResponse MakeRequest<TRequest, TResponse>(string verb, string requestUrl, TRequest obj)
|
||||
{
|
||||
int reqnum = WebUtil.RequestNumber++;
|
||||
// m_log.DebugFormat("[WEB UTIL]: <{0}> start osd request for {1}, method {2}",reqnum,url,method);
|
||||
|
||||
int tickstart = Util.EnvironmentTickCount();
|
||||
int tickdata = 0;
|
||||
|
||||
Type type = typeof(TRequest);
|
||||
TResponse deserial = default(TResponse);
|
||||
|
||||
WebRequest request = WebRequest.Create(requestUrl);
|
||||
request.Method = verb;
|
||||
MemoryStream buffer = null;
|
||||
|
||||
if ((verb == "POST") || (verb == "PUT"))
|
||||
{
|
||||
request.ContentType = "text/xml";
|
||||
|
||||
MemoryStream buffer = new MemoryStream();
|
||||
buffer = new MemoryStream();
|
||||
|
||||
XmlWriterSettings settings = new XmlWriterSettings();
|
||||
settings.Encoding = Encoding.UTF8;
|
||||
@@ -956,13 +1031,19 @@ namespace OpenSim.Framework
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[SynchronousRestObjectRequester]: exception in sending data to {0}: {1}", requestUrl, e);
|
||||
m_log.DebugFormat(
|
||||
"[SynchronousRestObjectRequester]: Exception in making request {0} {1}: {2}{3}",
|
||||
verb, requestUrl, e.Message, e.StackTrace);
|
||||
|
||||
return deserial;
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (requestStream != null)
|
||||
requestStream.Close();
|
||||
|
||||
// capture how much time was spent writing
|
||||
tickdata = Util.EnvironmentTickCountSubtract(tickstart);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -978,7 +1059,11 @@ namespace OpenSim.Framework
|
||||
respStream.Close();
|
||||
}
|
||||
else
|
||||
m_log.DebugFormat("[SynchronousRestObjectRequester]: Oops! no content found in response stream from {0} {1}", requestUrl, verb);
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[SynchronousRestObjectRequester]: Oops! no content found in response stream from {0} {1}",
|
||||
verb, requestUrl);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (WebException e)
|
||||
@@ -989,17 +1074,44 @@ namespace OpenSim.Framework
|
||||
return deserial;
|
||||
else
|
||||
m_log.ErrorFormat(
|
||||
"[SynchronousRestObjectRequester]: WebException {0} {1} {2} {3}",
|
||||
requestUrl, typeof(TResponse).ToString(), e.Message, e.StackTrace);
|
||||
"[SynchronousRestObjectRequester]: WebException for {0} {1} {2}: {3} {4}",
|
||||
verb, requestUrl, typeof(TResponse).ToString(), e.Message, e.StackTrace);
|
||||
}
|
||||
catch (System.InvalidOperationException)
|
||||
{
|
||||
// This is what happens when there is invalid XML
|
||||
m_log.DebugFormat("[SynchronousRestObjectRequester]: Invalid XML {0} {1}", requestUrl, typeof(TResponse).ToString());
|
||||
m_log.DebugFormat(
|
||||
"[SynchronousRestObjectRequester]: Invalid XML from {0} {1} {2}",
|
||||
verb, requestUrl, typeof(TResponse).ToString());
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[SynchronousRestObjectRequester]: Exception on response from {0} {1}", requestUrl, e);
|
||||
m_log.DebugFormat(
|
||||
"[SynchronousRestObjectRequester]: Exception on response from {0} {1}: {2}{3}",
|
||||
verb, requestUrl, e.Message, e.StackTrace);
|
||||
}
|
||||
|
||||
int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
|
||||
if (tickdiff > WebUtil.LongCallTime)
|
||||
{
|
||||
string originalRequest = null;
|
||||
|
||||
if (buffer != null)
|
||||
{
|
||||
originalRequest = Encoding.UTF8.GetString(buffer.ToArray());
|
||||
|
||||
if (originalRequest.Length > WebUtil.MaxRequestDiagLength)
|
||||
originalRequest = originalRequest.Remove(WebUtil.MaxRequestDiagLength);
|
||||
}
|
||||
|
||||
m_log.InfoFormat(
|
||||
"[SynchronousRestObjectRequester]: Slow request to <{0}> {1} {2} took {3}ms, {4}ms writing, {5}",
|
||||
reqnum,
|
||||
verb,
|
||||
requestUrl,
|
||||
tickdiff,
|
||||
tickdata,
|
||||
originalRequest);
|
||||
}
|
||||
|
||||
return deserial;
|
||||
|
||||
@@ -92,9 +92,14 @@ namespace OpenSim
|
||||
m_log.Info("[OPENSIM MAIN]: configured log4net using default OpenSim.exe.config");
|
||||
}
|
||||
|
||||
m_log.DebugFormat(
|
||||
m_log.InfoFormat(
|
||||
"[OPENSIM MAIN]: System Locale is {0}", System.Threading.Thread.CurrentThread.CurrentCulture);
|
||||
|
||||
string monoThreadsPerCpu = System.Environment.GetEnvironmentVariable("MONO_THREADS_PER_CPU");
|
||||
|
||||
m_log.InfoFormat(
|
||||
"[OPENSIM MAIN]: Environment variable MONO_THREADS_PER_CPU is {0}", monoThreadsPerCpu ?? "unset");
|
||||
|
||||
// Increase the number of IOCP threads available. Mono defaults to a tragically low number
|
||||
int workerThreads, iocpThreads;
|
||||
System.Threading.ThreadPool.GetMaxThreads(out workerThreads, out iocpThreads);
|
||||
@@ -109,7 +114,6 @@ namespace OpenSim
|
||||
|
||||
// Check if the system is compatible with OpenSimulator.
|
||||
// Ensures that the minimum system requirements are met
|
||||
m_log.Info("Performing compatibility checks... \n");
|
||||
string supported = String.Empty;
|
||||
if (Util.IsEnvironmentSupported(ref supported))
|
||||
{
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
@@ -138,7 +139,7 @@ namespace OpenSim
|
||||
m_log.Info("====================================================================");
|
||||
m_log.Info("========================= STARTING OPENSIM =========================");
|
||||
m_log.Info("====================================================================");
|
||||
|
||||
|
||||
//m_log.InfoFormat("[OPENSIM MAIN]: GC Is Server GC: {0}", GCSettings.IsServerGC.ToString());
|
||||
// http://msdn.microsoft.com/en-us/library/bb384202.aspx
|
||||
//GCSettings.LatencyMode = GCLatencyMode.Batch;
|
||||
@@ -225,12 +226,14 @@ namespace OpenSim
|
||||
/// </summary>
|
||||
private void RegisterConsoleCommands()
|
||||
{
|
||||
m_console.Commands.AddCommand("region", false, "force update",
|
||||
MainServer.RegisterHttpConsoleCommands(m_console);
|
||||
|
||||
m_console.Commands.AddCommand("Objects", false, "force update",
|
||||
"force update",
|
||||
"Force the update of all objects on clients",
|
||||
HandleForceUpdate);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "debug packet",
|
||||
m_console.Commands.AddCommand("Debug", false, "debug packet",
|
||||
"debug packet <level> [<avatar-first-name> <avatar-last-name>]",
|
||||
"Turn on packet debugging",
|
||||
"If level > 255 then all incoming and outgoing packets are logged.\n"
|
||||
@@ -242,45 +245,37 @@ namespace OpenSim
|
||||
+ "If an avatar name is given then only packets from that avatar are logged",
|
||||
Debug);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "debug http",
|
||||
"debug http <level>",
|
||||
"Turn on inbound http request debugging for everything except the event queue (see debug eq).",
|
||||
"If level >= 2 then the handler used to service the request is logged.\n"
|
||||
+ "If level >= 1 then incoming HTTP requests are logged.\n"
|
||||
+ "If level <= 0 then no extra http logging is done.\n",
|
||||
Debug);
|
||||
m_console.Commands.AddCommand("Debug", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "debug teleport", "debug teleport", "Toggle teleport route debugging", Debug);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "debug scene",
|
||||
m_console.Commands.AddCommand("Debug", false, "debug scene",
|
||||
"debug scene <scripting> <collisions> <physics>",
|
||||
"Turn on scene debugging", Debug);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "change region",
|
||||
m_console.Commands.AddCommand("General", false, "change region",
|
||||
"change region <region name>",
|
||||
"Change current console region", ChangeSelectedRegion);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "save xml",
|
||||
m_console.Commands.AddCommand("Archiving", false, "save xml",
|
||||
"save xml",
|
||||
"Save a region's data in XML format", SaveXml);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "save xml2",
|
||||
m_console.Commands.AddCommand("Archiving", false, "save xml2",
|
||||
"save xml2",
|
||||
"Save a region's data in XML2 format", SaveXml2);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "load xml",
|
||||
m_console.Commands.AddCommand("Archiving", false, "load xml",
|
||||
"load xml [-newIDs [<x> <y> <z>]]",
|
||||
"Load a region's data from XML format", LoadXml);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "load xml2",
|
||||
m_console.Commands.AddCommand("Archiving", false, "load xml2",
|
||||
"load xml2",
|
||||
"Load a region's data from XML2 format", LoadXml2);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "save prims xml2",
|
||||
m_console.Commands.AddCommand("Archiving", false, "save prims xml2",
|
||||
"save prims xml2 [<prim name> <file name>]",
|
||||
"Save named prim to XML2", SavePrimsXml2);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "load oar",
|
||||
m_console.Commands.AddCommand("Archiving", false, "load oar",
|
||||
"load oar [--merge] [--skip-assets] [<OAR path>]",
|
||||
"Load a region's data from an OAR archive.",
|
||||
"--merge will merge the OAR with the existing scene." + Environment.NewLine
|
||||
@@ -289,7 +284,7 @@ namespace OpenSim
|
||||
+ " If this is not given then the command looks for an OAR named region.oar in the current directory.",
|
||||
LoadOar);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "save oar",
|
||||
m_console.Commands.AddCommand("Archiving", false, "save oar",
|
||||
//"save oar [-v|--version=<N>] [-p|--profile=<url>] [<OAR path>]",
|
||||
"save oar [-h|--home=<url>] [--noassets] [--publish] [--perm=<permissions>] [<OAR path>]",
|
||||
"Save a region's data to an OAR archive.",
|
||||
@@ -306,54 +301,54 @@ namespace OpenSim
|
||||
+ " If this is not given then the oar is saved to region.oar in the current directory.",
|
||||
SaveOar);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "edit scale",
|
||||
m_console.Commands.AddCommand("Objects", false, "edit scale",
|
||||
"edit scale <name> <x> <y> <z>",
|
||||
"Change the scale of a named prim", HandleEditScale);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "kick user",
|
||||
m_console.Commands.AddCommand("Users", false, "kick user",
|
||||
"kick user <first> <last> [message]",
|
||||
"Kick a user off the simulator", KickUserCommand);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "show users",
|
||||
m_console.Commands.AddCommand("Users", false, "show users",
|
||||
"show users [full]",
|
||||
"Show user data for users currently on the region",
|
||||
"Without the 'full' option, only users actually on the region are shown."
|
||||
+ " With the 'full' option child agents of users in neighbouring regions are also shown.",
|
||||
HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "show connections",
|
||||
m_console.Commands.AddCommand("Comms", false, "show connections",
|
||||
"show connections",
|
||||
"Show connection data", HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "show circuits",
|
||||
m_console.Commands.AddCommand("Comms", false, "show circuits",
|
||||
"show circuits",
|
||||
"Show agent circuit data", HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "show http-handlers",
|
||||
m_console.Commands.AddCommand("Comms", false, "show http-handlers",
|
||||
"show http-handlers",
|
||||
"Show all registered http handlers", HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "show pending-objects",
|
||||
m_console.Commands.AddCommand("Comms", false, "show pending-objects",
|
||||
"show pending-objects",
|
||||
"Show # of objects on the pending queues of all scene viewers", HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "show modules",
|
||||
m_console.Commands.AddCommand("General", false, "show modules",
|
||||
"show modules",
|
||||
"Show module data", HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "show regions",
|
||||
m_console.Commands.AddCommand("Regions", false, "show regions",
|
||||
"show regions",
|
||||
"Show region data", HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "show ratings",
|
||||
m_console.Commands.AddCommand("Regions", false, "show ratings",
|
||||
"show ratings",
|
||||
"Show rating data", HandleShow);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "backup",
|
||||
m_console.Commands.AddCommand("Objects", false, "backup",
|
||||
"backup",
|
||||
"Persist currently unsaved object changes immediately instead of waiting for the normal persistence call.", RunCommand);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "create region",
|
||||
m_console.Commands.AddCommand("Regions", false, "create region",
|
||||
"create region [\"region name\"] <region_file.ini>",
|
||||
"Create a new region.",
|
||||
"The settings for \"region name\" are read from <region_file.ini>. Paths specified with <region_file.ini> are relative to your Regions directory, unless an absolute path is given."
|
||||
@@ -362,62 +357,57 @@ namespace OpenSim
|
||||
+ "If <region_file.ini> does not exist, it will be created.",
|
||||
HandleCreateRegion);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "restart",
|
||||
m_console.Commands.AddCommand("Regions", false, "restart",
|
||||
"restart",
|
||||
"Restart all sims in this instance", RunCommand);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "config set",
|
||||
m_console.Commands.AddCommand("General", false, "config set",
|
||||
"config set <section> <key> <value>",
|
||||
"Set a config option. In most cases this is not useful since changed parameters are not dynamically reloaded. Neither do changed parameters persist - you will have to change a config file manually and restart.", HandleConfig);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "config get",
|
||||
m_console.Commands.AddCommand("General", false, "config get",
|
||||
"config get [<section>] [<key>]",
|
||||
"Synonym for config show",
|
||||
HandleConfig);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "config show",
|
||||
m_console.Commands.AddCommand("General", false, "config show",
|
||||
"config show [<section>] [<key>]",
|
||||
"Show config information",
|
||||
"If neither section nor field are specified, then the whole current configuration is printed." + Environment.NewLine
|
||||
+ "If a section is given but not a field, then all fields in that section are printed.",
|
||||
HandleConfig);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "config save",
|
||||
m_console.Commands.AddCommand("General", false, "config save",
|
||||
"config save <path>",
|
||||
"Save current configuration to a file at the given path", HandleConfig);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "command-script",
|
||||
m_console.Commands.AddCommand("General", false, "command-script",
|
||||
"command-script <script>",
|
||||
"Run a command script from file", RunCommand);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "remove-region",
|
||||
m_console.Commands.AddCommand("Regions", false, "remove-region",
|
||||
"remove-region <name>",
|
||||
"Remove a region from this simulator", RunCommand);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "delete-region",
|
||||
m_console.Commands.AddCommand("Regions", false, "delete-region",
|
||||
"delete-region <name>",
|
||||
"Delete a region from disk", RunCommand);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "modules list",
|
||||
m_console.Commands.AddCommand("General", false, "modules list",
|
||||
"modules list",
|
||||
"List modules", HandleModules);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "modules load",
|
||||
m_console.Commands.AddCommand("General", false, "modules load",
|
||||
"modules load <name>",
|
||||
"Load a module", HandleModules);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "modules unload",
|
||||
m_console.Commands.AddCommand("General", false, "modules unload",
|
||||
"modules unload <name>",
|
||||
"Unload a module", HandleModules);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "Add-InventoryHost",
|
||||
"Add-InventoryHost <host>",
|
||||
String.Empty, RunCommand);
|
||||
|
||||
m_console.Commands.AddCommand("region", false, "kill uuid",
|
||||
m_console.Commands.AddCommand("Objects", false, "kill uuid",
|
||||
"kill uuid <UUID>",
|
||||
"Kill an object by UUID", KillUUID);
|
||||
|
||||
}
|
||||
|
||||
public override void ShutdownSpecific()
|
||||
@@ -442,12 +432,16 @@ namespace OpenSim
|
||||
}
|
||||
}
|
||||
|
||||
private void WatchdogTimeoutHandler(System.Threading.Thread thread, int lastTick)
|
||||
private void WatchdogTimeoutHandler(Watchdog.ThreadWatchdogInfo twi)
|
||||
{
|
||||
int now = Environment.TickCount & Int32.MaxValue;
|
||||
|
||||
m_log.ErrorFormat("[WATCHDOG]: Timeout detected for thread \"{0}\". ThreadState={1}. Last tick was {2}ms ago",
|
||||
thread.Name, thread.ThreadState, now - lastTick);
|
||||
m_log.ErrorFormat(
|
||||
"[WATCHDOG]: Timeout detected for thread \"{0}\". ThreadState={1}. Last tick was {2}ms ago. {3}",
|
||||
twi.Thread.Name,
|
||||
twi.Thread.ThreadState,
|
||||
now - twi.LastTick,
|
||||
twi.AlarmMethod != null ? string.Format("Data: {0}", twi.AlarmMethod()) : "");
|
||||
}
|
||||
|
||||
#region Console Commands
|
||||
@@ -486,10 +480,10 @@ namespace OpenSim
|
||||
else
|
||||
presence.ControllingClient.Kick("\nThe OpenSim manager kicked you out.\n");
|
||||
|
||||
// ...and close on our side
|
||||
presence.Scene.IncomingCloseAgent(presence.UUID);
|
||||
}
|
||||
}
|
||||
|
||||
MainConsole.Instance.Output("");
|
||||
}
|
||||
|
||||
@@ -829,14 +823,6 @@ namespace OpenSim
|
||||
case "restart":
|
||||
m_sceneManager.RestartCurrentScene();
|
||||
break;
|
||||
|
||||
case "Add-InventoryHost":
|
||||
if (cmdparams.Length > 0)
|
||||
{
|
||||
MainConsole.Instance.Output("Not implemented.");
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -912,23 +898,8 @@ namespace OpenSim
|
||||
|
||||
break;
|
||||
|
||||
case "http":
|
||||
if (args.Length == 3)
|
||||
{
|
||||
int newDebug;
|
||||
if (int.TryParse(args[2], out newDebug))
|
||||
{
|
||||
MainServer.Instance.DebugLevel = newDebug;
|
||||
MainConsole.Instance.OutputFormat("Debug http level set to {0}", newDebug);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MainConsole.Instance.Output("Usage: debug http 0..2");
|
||||
break;
|
||||
|
||||
case "scene":
|
||||
if (args.Length == 5)
|
||||
if (args.Length == 4)
|
||||
{
|
||||
if (m_sceneManager.CurrentScene == null)
|
||||
{
|
||||
@@ -936,39 +907,21 @@ namespace OpenSim
|
||||
}
|
||||
else
|
||||
{
|
||||
bool scriptingOn = !Convert.ToBoolean(args[2]);
|
||||
bool collisionsOn = !Convert.ToBoolean(args[3]);
|
||||
bool physicsOn = !Convert.ToBoolean(args[4]);
|
||||
m_sceneManager.CurrentScene.SetSceneCoreDebug(scriptingOn, collisionsOn, physicsOn);
|
||||
string key = args[2];
|
||||
string value = args[3];
|
||||
m_sceneManager.CurrentScene.SetSceneCoreDebug(
|
||||
new Dictionary<string, string>() { { key, value } });
|
||||
|
||||
MainConsole.Instance.Output(
|
||||
String.Format(
|
||||
"Set debug scene scripting = {0}, collisions = {1}, physics = {2}",
|
||||
!scriptingOn, !collisionsOn, !physicsOn));
|
||||
MainConsole.Instance.OutputFormat("Set debug scene {0} = {1}", key, value);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
MainConsole.Instance.Output("Usage: debug scene <scripting> <collisions> <physics> (where inside <> is true/false)");
|
||||
MainConsole.Instance.Output("Usage: debug scene scripting|collisions|physics|teleport true|false");
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case "teleport":
|
||||
foreach(Scene s in m_sceneManager.Scenes)
|
||||
{
|
||||
if (s.DEBUG)
|
||||
{
|
||||
s.DEBUG = false;
|
||||
MainConsole.Instance.Output("Teleport debugging is disabled!");
|
||||
}
|
||||
else{
|
||||
s.DEBUG = true;
|
||||
MainConsole.Instance.Output("Teleport debugging is enabled!");
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
MainConsole.Instance.Output("Unknown debug command");
|
||||
break;
|
||||
|
||||
@@ -219,7 +219,7 @@ namespace OpenSim
|
||||
|
||||
base.StartupSpecific();
|
||||
|
||||
m_stats = StatsManager.StartCollectingSimExtraStats();
|
||||
m_stats = StatsManager.SimExtraStats;
|
||||
|
||||
// Create a ModuleLoader instance
|
||||
m_moduleLoader = new ModuleLoader(m_config.Source);
|
||||
@@ -242,15 +242,18 @@ namespace OpenSim
|
||||
|
||||
foreach (string topic in topics)
|
||||
{
|
||||
m_console.Commands.AddCommand("plugin", false, "help " + topic,
|
||||
"help " + topic,
|
||||
string capitalizedTopic = char.ToUpper(topic[0]) + topic.Substring(1);
|
||||
|
||||
// This is a hack to allow the user to enter the help command in upper or lowercase. This will go
|
||||
// away at some point.
|
||||
m_console.Commands.AddCommand(capitalizedTopic, false, "help " + topic,
|
||||
"help " + capitalizedTopic,
|
||||
"Get help on plugin command '" + topic + "'",
|
||||
HandleCommanderHelp);
|
||||
m_console.Commands.AddCommand(capitalizedTopic, false, "help " + capitalizedTopic,
|
||||
"help " + capitalizedTopic,
|
||||
"Get help on plugin command '" + topic + "'",
|
||||
HandleCommanderHelp);
|
||||
|
||||
m_console.Commands.AddCommand("plugin", false, topic,
|
||||
topic,
|
||||
"Execute subcommand for plugin '" + topic + "'",
|
||||
null);
|
||||
|
||||
ICommander commander = null;
|
||||
|
||||
@@ -267,7 +270,7 @@ namespace OpenSim
|
||||
|
||||
foreach (string command in commander.Commands.Keys)
|
||||
{
|
||||
m_console.Commands.AddCommand(topic, false,
|
||||
m_console.Commands.AddCommand(capitalizedTopic, false,
|
||||
topic + " " + command,
|
||||
topic + " " + commander.Commands[command].ShortHelp(),
|
||||
String.Empty, HandleCommanderCommand);
|
||||
@@ -286,7 +289,7 @@ namespace OpenSim
|
||||
// Only safe for the interactive console, since it won't
|
||||
// let us come here unless both scene and commander exist
|
||||
//
|
||||
ICommander moduleCommander = SceneManager.CurrentOrFirstScene.GetCommander(cmd[1]);
|
||||
ICommander moduleCommander = SceneManager.CurrentOrFirstScene.GetCommander(cmd[1].ToLower());
|
||||
if (moduleCommander != null)
|
||||
m_console.Output(moduleCommander.Help);
|
||||
}
|
||||
@@ -381,7 +384,7 @@ namespace OpenSim
|
||||
scene.LoadPrimsFromStorage(regionInfo.originRegionID);
|
||||
|
||||
// TODO : Try setting resource for region xstats here on scene
|
||||
MainServer.Instance.AddStreamHandler(new Region.Framework.Scenes.RegionStatsHandler(regionInfo));
|
||||
MainServer.Instance.AddStreamHandler(new RegionStatsHandler(regionInfo));
|
||||
|
||||
scene.loadAllLandObjectsFromStorage(regionInfo.originRegionID);
|
||||
scene.EventManager.TriggerParcelPrimCountUpdate();
|
||||
@@ -424,7 +427,7 @@ namespace OpenSim
|
||||
|
||||
mscene = scene;
|
||||
|
||||
scene.StartTimer();
|
||||
scene.Start();
|
||||
|
||||
scene.StartScripts();
|
||||
|
||||
@@ -724,6 +727,9 @@ namespace OpenSim
|
||||
return Util.UTF8.GetBytes("OK");
|
||||
}
|
||||
|
||||
public string Name { get { return "SimStatus"; } }
|
||||
public string Description { get { return "Simulator Status"; } }
|
||||
|
||||
public string ContentType
|
||||
{
|
||||
get { return "text/plain"; }
|
||||
@@ -748,6 +754,9 @@ namespace OpenSim
|
||||
{
|
||||
OpenSimBase m_opensim;
|
||||
string osXStatsURI = String.Empty;
|
||||
|
||||
public string Name { get { return "XSimStatus"; } }
|
||||
public string Description { get { return "Simulator XStatus"; } }
|
||||
|
||||
public XSimStatusHandler(OpenSimBase sim)
|
||||
{
|
||||
@@ -788,6 +797,9 @@ namespace OpenSim
|
||||
{
|
||||
OpenSimBase m_opensim;
|
||||
string osUXStatsURI = String.Empty;
|
||||
|
||||
public string Name { get { return "UXSimStatus"; } }
|
||||
public string Description { get { return "Simulator UXStatus"; } }
|
||||
|
||||
public UXSimStatusHandler(OpenSimBase sim)
|
||||
{
|
||||
|
||||
@@ -151,7 +151,9 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
try
|
||||
{
|
||||
// the root of all evil
|
||||
m_HostCapsObj.RegisterHandler("SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest));
|
||||
m_HostCapsObj.RegisterHandler(
|
||||
"SEED", new RestStreamHandler("POST", capsBase + m_requestPath, SeedCapRequest, "SEED", null));
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[CAPS]: Registered seed capability {0} for {1}", capsBase + m_requestPath, m_HostCapsObj.AgentID);
|
||||
|
||||
@@ -159,7 +161,10 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
// new LLSDStreamhandler<OSDMapRequest, OSDMapLayerResponse>("POST",
|
||||
// capsBase + m_mapLayerPath,
|
||||
// GetMapLayer);
|
||||
IRequestHandler req = new RestStreamHandler("POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory);
|
||||
IRequestHandler req
|
||||
= new RestStreamHandler(
|
||||
"POST", capsBase + m_notecardTaskUpdatePath, ScriptTaskInventory, "UpdateScript", null);
|
||||
|
||||
m_HostCapsObj.RegisterHandler("UpdateScriptTaskInventory", req);
|
||||
m_HostCapsObj.RegisterHandler("UpdateScriptTask", req);
|
||||
}
|
||||
@@ -174,14 +179,27 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
try
|
||||
{
|
||||
// I don't think this one works...
|
||||
m_HostCapsObj.RegisterHandler("NewFileAgentInventory", new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>("POST",
|
||||
capsBase + m_newInventory,
|
||||
NewAgentInventoryRequest));
|
||||
IRequestHandler req = new RestStreamHandler("POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory);
|
||||
m_HostCapsObj.RegisterHandler(
|
||||
"NewFileAgentInventory",
|
||||
new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDAssetUploadResponse>(
|
||||
"POST",
|
||||
capsBase + m_newInventory,
|
||||
NewAgentInventoryRequest,
|
||||
"NewFileAgentInventory",
|
||||
null));
|
||||
|
||||
IRequestHandler req
|
||||
= new RestStreamHandler(
|
||||
"POST", capsBase + m_notecardUpdatePath, NoteCardAgentInventory, "Update*", null);
|
||||
|
||||
m_HostCapsObj.RegisterHandler("UpdateNotecardAgentInventory", req);
|
||||
m_HostCapsObj.RegisterHandler("UpdateScriptAgentInventory", req);
|
||||
m_HostCapsObj.RegisterHandler("UpdateScriptAgent", req);
|
||||
m_HostCapsObj.RegisterHandler("CopyInventoryFromNotecard", new RestStreamHandler("POST", capsBase + m_copyFromNotecardPath, CopyInventoryFromNotecard));
|
||||
|
||||
m_HostCapsObj.RegisterHandler(
|
||||
"CopyInventoryFromNotecard",
|
||||
new RestStreamHandler(
|
||||
"POST", capsBase + m_copyFromNotecardPath, CopyInventoryFromNotecard, "CopyInventoryFromNotecard", null));
|
||||
|
||||
// As of RC 1.22.9 of the Linden client this is
|
||||
// supported
|
||||
@@ -231,7 +249,10 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
if (!m_Scene.CheckClient(m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint))
|
||||
{
|
||||
m_log.DebugFormat("[CAPS]: Unauthorized CAPS client");
|
||||
m_log.DebugFormat(
|
||||
"[CAPS]: Unauthorized CAPS client {0} from {1}",
|
||||
m_HostCapsObj.AgentID, httpRequest.RemoteIPEndPoint);
|
||||
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
@@ -282,7 +303,9 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
m_dumpAssetsToFile);
|
||||
uploader.OnUpLoad += TaskScriptUpdated;
|
||||
|
||||
m_HostCapsObj.HttpListener.AddStreamHandler(new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
|
||||
m_HostCapsObj.HttpListener.AddStreamHandler(
|
||||
new BinaryStreamHandler(
|
||||
"POST", capsBase + uploaderPath, uploader.uploaderCaps, "TaskInventoryScriptUpdater", null));
|
||||
|
||||
string protocol = "http://";
|
||||
|
||||
@@ -393,8 +416,14 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
AssetUploader uploader =
|
||||
new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
|
||||
llsdRequest.asset_type, capsBase + uploaderPath, m_HostCapsObj.HttpListener, m_dumpAssetsToFile);
|
||||
|
||||
m_HostCapsObj.HttpListener.AddStreamHandler(
|
||||
new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
|
||||
new BinaryStreamHandler(
|
||||
"POST",
|
||||
capsBase + uploaderPath,
|
||||
uploader.uploaderCaps,
|
||||
"NewAgentInventoryRequest",
|
||||
m_HostCapsObj.AgentID.ToString()));
|
||||
|
||||
string protocol = "http://";
|
||||
|
||||
@@ -710,7 +739,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
uploader.OnUpLoad += ItemUpdated;
|
||||
|
||||
m_HostCapsObj.HttpListener.AddStreamHandler(
|
||||
new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
|
||||
new BinaryStreamHandler(
|
||||
"POST", capsBase + uploaderPath, uploader.uploaderCaps, "NoteCardAgentInventory", null));
|
||||
|
||||
string protocol = "http://";
|
||||
|
||||
|
||||
@@ -106,13 +106,14 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
scene.EventManager.OnRegisterCaps += OnRegisterCaps;
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(
|
||||
"event queue",
|
||||
"Debug",
|
||||
false,
|
||||
"debug eq",
|
||||
"debug eq [0|1]",
|
||||
"Turn on event queue debugging",
|
||||
"debug eq 1 will turn on event queue debugging. This will log all outgoing event queue messages to clients.\n"
|
||||
+ "debug eq 0 will turn off event queue debugging.",
|
||||
"debug eq [0|1|2]",
|
||||
"Turn on event queue debugging"
|
||||
+ "<= 0 - turns off all event queue logging"
|
||||
+ ">= 1 - turns on outgoing event logging"
|
||||
+ ">= 2 - turns on poll notification",
|
||||
HandleDebugEq);
|
||||
}
|
||||
else
|
||||
@@ -235,19 +236,19 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
// ClientClosed(client.AgentId);
|
||||
// }
|
||||
|
||||
private void ClientClosed(UUID AgentID, Scene scene)
|
||||
private void ClientClosed(UUID agentID, Scene scene)
|
||||
{
|
||||
// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", AgentID, m_scene.RegionInfo.RegionName);
|
||||
// m_log.DebugFormat("[EVENTQUEUE]: Closed client {0} in region {1}", agentID, m_scene.RegionInfo.RegionName);
|
||||
|
||||
int count = 0;
|
||||
while (queues.ContainsKey(AgentID) && queues[AgentID].Count > 0 && count++ < 5)
|
||||
while (queues.ContainsKey(agentID) && queues[agentID].Count > 0 && count++ < 5)
|
||||
{
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
|
||||
lock (queues)
|
||||
{
|
||||
queues.Remove(AgentID);
|
||||
queues.Remove(agentID);
|
||||
}
|
||||
|
||||
List<UUID> removeitems = new List<UUID>();
|
||||
@@ -256,7 +257,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
foreach (UUID ky in m_AvatarQueueUUIDMapping.Keys)
|
||||
{
|
||||
// m_log.DebugFormat("[EVENTQUEUE]: Found key {0} in m_AvatarQueueUUIDMapping while looking for {1}", ky, AgentID);
|
||||
if (ky == AgentID)
|
||||
if (ky == agentID)
|
||||
{
|
||||
removeitems.Add(ky);
|
||||
}
|
||||
@@ -267,7 +268,12 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
UUID eventQueueGetUuid = m_AvatarQueueUUIDMapping[ky];
|
||||
m_AvatarQueueUUIDMapping.Remove(ky);
|
||||
|
||||
MainServer.Instance.RemovePollServiceHTTPHandler("","/CAPS/EQG/" + eventQueueGetUuid.ToString() + "/");
|
||||
string eqgPath = GenerateEqgCapPath(eventQueueGetUuid);
|
||||
MainServer.Instance.RemovePollServiceHTTPHandler("", eqgPath);
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[EVENT QUEUE GET MODULE]: Removed EQG handler {0} for {1} in {2}",
|
||||
// eqgPath, agentID, m_scene.RegionInfo.RegionName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,7 +287,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
{
|
||||
searchval = m_QueueUUIDAvatarMapping[ky];
|
||||
|
||||
if (searchval == AgentID)
|
||||
if (searchval == agentID)
|
||||
{
|
||||
removeitems.Add(ky);
|
||||
}
|
||||
@@ -305,6 +311,15 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
//}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Generate an Event Queue Get handler path for the given eqg uuid.
|
||||
/// </summary>
|
||||
/// <param name='eqgUuid'></param>
|
||||
private string GenerateEqgCapPath(UUID eqgUuid)
|
||||
{
|
||||
return string.Format("/CAPS/EQG/{0}/", eqgUuid);
|
||||
}
|
||||
|
||||
public void OnRegisterCaps(UUID agentID, Caps caps)
|
||||
{
|
||||
// Register an event queue for the client
|
||||
@@ -316,8 +331,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
// Let's instantiate a Queue for this agent right now
|
||||
TryGetQueue(agentID);
|
||||
|
||||
string capsBase = "/CAPS/EQG/";
|
||||
UUID EventQueueGetUUID = UUID.Zero;
|
||||
UUID eventQueueGetUUID;
|
||||
|
||||
lock (m_AvatarQueueUUIDMapping)
|
||||
{
|
||||
@@ -325,44 +339,50 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
if (m_AvatarQueueUUIDMapping.ContainsKey(agentID))
|
||||
{
|
||||
//m_log.DebugFormat("[EVENTQUEUE]: Found Existing UUID!");
|
||||
EventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
|
||||
eventQueueGetUUID = m_AvatarQueueUUIDMapping[agentID];
|
||||
}
|
||||
else
|
||||
{
|
||||
EventQueueGetUUID = UUID.Random();
|
||||
eventQueueGetUUID = UUID.Random();
|
||||
//m_log.DebugFormat("[EVENTQUEUE]: Using random UUID!");
|
||||
}
|
||||
}
|
||||
|
||||
lock (m_QueueUUIDAvatarMapping)
|
||||
{
|
||||
if (!m_QueueUUIDAvatarMapping.ContainsKey(EventQueueGetUUID))
|
||||
m_QueueUUIDAvatarMapping.Add(EventQueueGetUUID, agentID);
|
||||
if (!m_QueueUUIDAvatarMapping.ContainsKey(eventQueueGetUUID))
|
||||
m_QueueUUIDAvatarMapping.Add(eventQueueGetUUID, agentID);
|
||||
}
|
||||
|
||||
lock (m_AvatarQueueUUIDMapping)
|
||||
{
|
||||
if (!m_AvatarQueueUUIDMapping.ContainsKey(agentID))
|
||||
m_AvatarQueueUUIDMapping.Add(agentID, EventQueueGetUUID);
|
||||
m_AvatarQueueUUIDMapping.Add(agentID, eventQueueGetUUID);
|
||||
}
|
||||
|
||||
string eventQueueGetPath = GenerateEqgCapPath(eventQueueGetUUID);
|
||||
|
||||
// Register this as a caps handler
|
||||
// FIXME: Confusingly, we need to register separate as a capability so that the client is told about
|
||||
// EventQueueGet when it receive capability information, but then we replace the rest handler immediately
|
||||
// afterwards with the poll service. So for now, we'll pass a null instead to simplify code reading, but
|
||||
// really it should be possible to directly register the poll handler as a capability.
|
||||
caps.RegisterHandler("EventQueueGet",
|
||||
new RestHTTPHandler("POST", capsBase + EventQueueGetUUID.ToString() + "/", null));
|
||||
caps.RegisterHandler("EventQueueGet", new RestHTTPHandler("POST", eventQueueGetPath, null));
|
||||
// delegate(Hashtable m_dhttpMethod)
|
||||
// {
|
||||
// return ProcessQueue(m_dhttpMethod, agentID, caps);
|
||||
// }));
|
||||
|
||||
// This will persist this beyond the expiry of the caps handlers
|
||||
// TODO: Add EventQueueGet name/description for diagnostics
|
||||
MainServer.Instance.AddPollServiceHTTPHandler(
|
||||
capsBase + EventQueueGetUUID.ToString() + "/",
|
||||
eventQueueGetPath,
|
||||
new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, agentID));
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[EVENT QUEUE GET MODULE]: Registered EQG handler {0} for {1} in {2}",
|
||||
// eventQueueGetPath, agentID, m_scene.RegionInfo.RegionName);
|
||||
|
||||
Random rnd = new Random(Environment.TickCount);
|
||||
lock (m_ids)
|
||||
{
|
||||
@@ -384,9 +404,25 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Logs a debug line for an outbound event queue message if appropriate.
|
||||
/// </summary>
|
||||
/// <param name='element'>Element containing message</param>
|
||||
private void LogOutboundDebugMessage(OSD element, UUID agentId)
|
||||
{
|
||||
if (element is OSDMap)
|
||||
{
|
||||
OSDMap ev = (OSDMap)element;
|
||||
m_log.DebugFormat(
|
||||
"Eq OUT {0,-30} to {1,-20} {2,-20}",
|
||||
ev["message"], m_scene.GetScenePresence(agentId).Name, m_scene.RegionInfo.RegionName);
|
||||
}
|
||||
}
|
||||
|
||||
public Hashtable GetEvents(UUID requestID, UUID pAgentId, string request)
|
||||
{
|
||||
// m_log.DebugFormat("[EVENT QUEUE GET MODULE]: Invoked GetEvents() for {0}", pAgentId);
|
||||
if (DebugLevel >= 2)
|
||||
m_log.DebugFormat("POLLED FOR EQ MESSAGES BY {0} in {1}", pAgentId, m_scene.RegionInfo.RegionName);
|
||||
|
||||
Queue<OSD> queue = TryGetQueue(pAgentId);
|
||||
OSD element;
|
||||
@@ -410,13 +446,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
}
|
||||
else
|
||||
{
|
||||
if (DebugLevel > 0 && element is OSDMap)
|
||||
{
|
||||
OSDMap ev = (OSDMap)element;
|
||||
m_log.DebugFormat(
|
||||
"[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}",
|
||||
ev["message"], m_scene.GetScenePresence(pAgentId).Name);
|
||||
}
|
||||
if (DebugLevel > 0)
|
||||
LogOutboundDebugMessage(element, pAgentId);
|
||||
|
||||
array.Add(element);
|
||||
|
||||
@@ -426,13 +457,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
{
|
||||
element = queue.Dequeue();
|
||||
|
||||
if (DebugLevel > 0 && element is OSDMap)
|
||||
{
|
||||
OSDMap ev = (OSDMap)element;
|
||||
m_log.DebugFormat(
|
||||
"[EVENT QUEUE GET MODULE]: Eq OUT {0} to {1}",
|
||||
ev["message"], m_scene.GetScenePresence(pAgentId).Name);
|
||||
}
|
||||
if (DebugLevel > 0)
|
||||
LogOutboundDebugMessage(element, pAgentId);
|
||||
|
||||
array.Add(element);
|
||||
thisID++;
|
||||
|
||||
@@ -51,7 +51,16 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
MainServer.Instance = new BaseHttpServer(9999, false, 9998, "");
|
||||
uint port = 9999;
|
||||
uint sslPort = 9998;
|
||||
|
||||
// This is an unfortunate bit of clean up we have to do because MainServer manages things through static
|
||||
// variables and the VM is not restarted between tests.
|
||||
MainServer.RemoveHttpServer(port);
|
||||
|
||||
BaseHttpServer server = new BaseHttpServer(port, false, sslPort, "");
|
||||
MainServer.AddHttpServer(server);
|
||||
MainServer.Instance = server;
|
||||
|
||||
IConfigSource config = new IniConfigSource();
|
||||
config.AddConfig("Startup");
|
||||
@@ -60,7 +69,7 @@ namespace OpenSim.Region.ClientStack.Linden.Tests
|
||||
CapabilitiesModule capsModule = new CapabilitiesModule();
|
||||
EventQueueGetModule eqgModule = new EventQueueGetModule();
|
||||
|
||||
m_scene = SceneHelpers.SetupScene();
|
||||
m_scene = new SceneHelpers().SetupScene();
|
||||
SceneHelpers.SetupSceneModules(m_scene, config, capsModule, eqgModule);
|
||||
}
|
||||
|
||||
|
||||
@@ -132,7 +132,8 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
capUrl = "/CAPS/" + UUID.Random();
|
||||
|
||||
IRequestHandler reqHandler
|
||||
= new RestStreamHandler("POST", capUrl, m_fetchHandler.FetchInventoryRequest);
|
||||
= new RestStreamHandler(
|
||||
"POST", capUrl, m_fetchHandler.FetchInventoryRequest, capName, agentID.ToString());
|
||||
|
||||
caps.RegisterHandler(capName, reqHandler);
|
||||
}
|
||||
|
||||
@@ -120,11 +120,13 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
{
|
||||
// m_log.DebugFormat("[GETMESH]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
|
||||
GetMeshHandler gmeshHandler = new GetMeshHandler(m_AssetService);
|
||||
IRequestHandler reqHandler = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(),
|
||||
delegate(Hashtable m_dhttpMethod)
|
||||
{
|
||||
return gmeshHandler.ProcessGetMesh(m_dhttpMethod, UUID.Zero, null);
|
||||
});
|
||||
IRequestHandler reqHandler
|
||||
= new RestHTTPHandler(
|
||||
"GET",
|
||||
"/CAPS/" + UUID.Random(),
|
||||
httpMethod => gmeshHandler.ProcessGetMesh(httpMethod, UUID.Zero, null),
|
||||
"GetMesh",
|
||||
agentID.ToString());
|
||||
|
||||
caps.RegisterHandler("GetMesh", reqHandler);
|
||||
}
|
||||
|
||||
@@ -130,7 +130,9 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
if (m_URL == "localhost")
|
||||
{
|
||||
// m_log.DebugFormat("[GETTEXTURE]: /CAPS/{0} in region {1}", capID, m_scene.RegionInfo.RegionName);
|
||||
caps.RegisterHandler("GetTexture", new GetTextureHandler("/CAPS/" + capID + "/", m_assetService));
|
||||
caps.RegisterHandler(
|
||||
"GetTexture",
|
||||
new GetTextureHandler("/CAPS/" + capID + "/", m_assetService, "GetTexture", agentID.ToString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -117,7 +117,9 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
public void RegisterCaps(UUID agentID, Caps caps)
|
||||
{
|
||||
IRequestHandler reqHandler = new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), MeshUploadFlag);
|
||||
IRequestHandler reqHandler
|
||||
= new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), MeshUploadFlag, "MeshUploadFlag", agentID.ToString());
|
||||
|
||||
caps.RegisterHandler("MeshUploadFlag", reqHandler);
|
||||
m_agentID = agentID;
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
// private IAssetService m_assetService;
|
||||
private bool m_dumpAssetsToFile = false;
|
||||
private bool m_enabled = true;
|
||||
private int m_levelUpload = 0;
|
||||
|
||||
#region IRegionModuleBase Members
|
||||
|
||||
@@ -72,6 +73,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
return;
|
||||
|
||||
m_enabled = meshConfig.GetBoolean("AllowMeshUpload", true);
|
||||
m_levelUpload = meshConfig.GetInt("LevelUpload", 0);
|
||||
}
|
||||
|
||||
public void AddRegion(Scene pScene)
|
||||
@@ -113,51 +115,66 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
UUID capID = UUID.Random();
|
||||
|
||||
// m_log.Debug("[NEW FILE AGENT INVENTORY VARIABLE PRICE]: /CAPS/" + capID);
|
||||
caps.RegisterHandler("NewFileAgentInventoryVariablePrice",
|
||||
|
||||
new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>("POST",
|
||||
"/CAPS/" + capID.ToString(),
|
||||
delegate(LLSDAssetUploadRequest req)
|
||||
{
|
||||
return NewAgentInventoryRequest(req,agentID);
|
||||
}));
|
||||
|
||||
caps.RegisterHandler(
|
||||
"NewFileAgentInventoryVariablePrice",
|
||||
new LLSDStreamhandler<LLSDAssetUploadRequest, LLSDNewFileAngentInventoryVariablePriceReplyResponse>(
|
||||
"POST",
|
||||
"/CAPS/" + capID.ToString(),
|
||||
req => NewAgentInventoryRequest(req, agentID),
|
||||
"NewFileAgentInventoryVariablePrice",
|
||||
agentID.ToString()));
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public LLSDNewFileAngentInventoryVariablePriceReplyResponse NewAgentInventoryRequest(LLSDAssetUploadRequest llsdRequest, UUID agentID)
|
||||
{
|
||||
|
||||
//TODO: The Mesh uploader uploads many types of content. If you're going to implement a Money based limit
|
||||
// You need to be aware of this and
|
||||
|
||||
// you need to be aware of this
|
||||
|
||||
//if (llsdRequest.asset_type == "texture" ||
|
||||
// llsdRequest.asset_type == "animation" ||
|
||||
// llsdRequest.asset_type == "sound")
|
||||
// {
|
||||
IClientAPI client = null;
|
||||
// check user level
|
||||
|
||||
|
||||
IMoneyModule mm = m_scene.RequestModuleInterface<IMoneyModule>();
|
||||
|
||||
if (mm != null)
|
||||
ScenePresence avatar = null;
|
||||
IClientAPI client = null;
|
||||
m_scene.TryGetScenePresence(agentID, out avatar);
|
||||
|
||||
if (avatar != null)
|
||||
{
|
||||
client = avatar.ControllingClient;
|
||||
|
||||
if (avatar.UserLevel < m_levelUpload)
|
||||
{
|
||||
if (m_scene.TryGetClient(agentID, out client))
|
||||
{
|
||||
if (!mm.UploadCovered(client.AgentId, mm.UploadCharge))
|
||||
{
|
||||
if (client != null)
|
||||
client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
|
||||
if (client != null)
|
||||
client.SendAgentAlertMessage("Unable to upload asset. Insufficient permissions.", false);
|
||||
|
||||
LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
|
||||
errorResponse.rsvp = "";
|
||||
errorResponse.state = "error";
|
||||
return errorResponse;
|
||||
}
|
||||
}
|
||||
LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
|
||||
errorResponse.rsvp = "";
|
||||
errorResponse.state = "error";
|
||||
return errorResponse;
|
||||
}
|
||||
}
|
||||
|
||||
// check funds
|
||||
IMoneyModule mm = m_scene.RequestModuleInterface<IMoneyModule>();
|
||||
|
||||
if (mm != null)
|
||||
{
|
||||
if (!mm.UploadCovered(agentID, mm.UploadCharge))
|
||||
{
|
||||
if (client != null)
|
||||
client.SendAgentAlertMessage("Unable to upload asset. Insufficient funds.", false);
|
||||
|
||||
LLSDNewFileAngentInventoryVariablePriceReplyResponse errorResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
|
||||
errorResponse.rsvp = "";
|
||||
errorResponse.state = "error";
|
||||
return errorResponse;
|
||||
}
|
||||
}
|
||||
|
||||
// }
|
||||
|
||||
string assetName = llsdRequest.name;
|
||||
@@ -171,8 +188,14 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
AssetUploader uploader =
|
||||
new AssetUploader(assetName, assetDes, newAsset, newInvItem, parentFolder, llsdRequest.inventory_type,
|
||||
llsdRequest.asset_type, capsBase + uploaderPath, MainServer.Instance, m_dumpAssetsToFile);
|
||||
|
||||
MainServer.Instance.AddStreamHandler(
|
||||
new BinaryStreamHandler("POST", capsBase + uploaderPath, uploader.uploaderCaps));
|
||||
new BinaryStreamHandler(
|
||||
"POST",
|
||||
capsBase + uploaderPath,
|
||||
uploader.uploaderCaps,
|
||||
"NewFileAgentInventoryVariablePrice",
|
||||
agentID.ToString()));
|
||||
|
||||
string protocol = "http://";
|
||||
|
||||
@@ -181,10 +204,9 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
string uploaderURL = protocol + m_scene.RegionInfo.ExternalHostName + ":" + MainServer.Instance.Port.ToString() + capsBase +
|
||||
uploaderPath;
|
||||
|
||||
|
||||
|
||||
LLSDNewFileAngentInventoryVariablePriceReplyResponse uploadResponse = new LLSDNewFileAngentInventoryVariablePriceReplyResponse();
|
||||
|
||||
|
||||
uploadResponse.rsvp = uploaderURL;
|
||||
uploadResponse.state = "upload";
|
||||
@@ -202,6 +224,7 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
pinventoryItem, pparentFolder, pdata, pinventoryType,
|
||||
passetType,agentID);
|
||||
};
|
||||
|
||||
return uploadResponse;
|
||||
}
|
||||
|
||||
|
||||
@@ -66,12 +66,14 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
|
||||
// m_log.InfoFormat("[OBJECTADD]: {0}", "/CAPS/OA/" + capuuid + "/");
|
||||
|
||||
caps.RegisterHandler("ObjectAdd",
|
||||
new RestHTTPHandler("POST", "/CAPS/OA/" + capuuid + "/",
|
||||
delegate(Hashtable m_dhttpMethod)
|
||||
{
|
||||
return ProcessAdd(m_dhttpMethod, agentID, caps);
|
||||
}));
|
||||
caps.RegisterHandler(
|
||||
"ObjectAdd",
|
||||
new RestHTTPHandler(
|
||||
"POST",
|
||||
"/CAPS/OA/" + capuuid + "/",
|
||||
httpMethod => ProcessAdd(httpMethod, agentID, caps),
|
||||
"ObjectAdd",
|
||||
agentID.ToString()));;
|
||||
}
|
||||
|
||||
public Hashtable ProcessAdd(Hashtable request, UUID AgentId, Caps cap)
|
||||
|
||||
@@ -106,12 +106,15 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
UUID capID = UUID.Random();
|
||||
|
||||
// m_log.Debug("[UPLOAD OBJECT ASSET MODULE]: /CAPS/" + capID);
|
||||
caps.RegisterHandler("UploadObjectAsset",
|
||||
new RestHTTPHandler("POST", "/CAPS/OA/" + capID + "/",
|
||||
delegate(Hashtable m_dhttpMethod)
|
||||
{
|
||||
return ProcessAdd(m_dhttpMethod, agentID, caps);
|
||||
}));
|
||||
caps.RegisterHandler(
|
||||
"UploadObjectAsset",
|
||||
new RestHTTPHandler(
|
||||
"POST",
|
||||
"/CAPS/OA/" + capID + "/",
|
||||
httpMethod => ProcessAdd(httpMethod, agentID, caps),
|
||||
"UploadObjectAsset",
|
||||
agentID.ToString()));
|
||||
|
||||
/*
|
||||
caps.RegisterHandler("NewFileAgentInventoryVariablePrice",
|
||||
|
||||
@@ -330,7 +333,6 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
grp.AbsolutePosition = obj.Position;
|
||||
prim.RotationOffset = obj.Rotation;
|
||||
|
||||
grp.IsAttachment = false;
|
||||
// Required for linking
|
||||
grp.RootPart.ClearUpdateSchedule();
|
||||
|
||||
|
||||
@@ -154,7 +154,9 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
public void RegisterCaps(UUID agentID, Caps caps)
|
||||
{
|
||||
IRequestHandler reqHandler
|
||||
= new RestHTTPHandler("GET", "/CAPS/" + UUID.Random(), HandleSimulatorFeaturesRequest);
|
||||
= new RestHTTPHandler(
|
||||
"GET", "/CAPS/" + UUID.Random(),
|
||||
HandleSimulatorFeaturesRequest, "SimulatorFeatures", agentID.ToString());
|
||||
|
||||
caps.RegisterHandler("SimulatorFeatures", reqHandler);
|
||||
}
|
||||
|
||||
@@ -106,7 +106,9 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
"POST",
|
||||
"/CAPS/" + caps.CapsObjectPath + m_uploadBakedTexturePath,
|
||||
new UploadBakedTextureHandler(
|
||||
caps, m_scene.AssetService, m_persistBakedTextures).UploadBakedTexture));
|
||||
caps, m_scene.AssetService, m_persistBakedTextures).UploadBakedTexture,
|
||||
"UploadBakedTexture",
|
||||
agentID.ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -144,7 +144,12 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
capUrl = "/CAPS/" + UUID.Random();
|
||||
|
||||
IRequestHandler reqHandler
|
||||
= new RestStreamHandler("POST", capUrl, m_webFetchHandler.FetchInventoryDescendentsRequest);
|
||||
= new RestStreamHandler(
|
||||
"POST",
|
||||
capUrl,
|
||||
m_webFetchHandler.FetchInventoryDescendentsRequest,
|
||||
"FetchInventoryDescendents2",
|
||||
agentID.ToString());
|
||||
|
||||
caps.RegisterHandler(capName, reqHandler);
|
||||
}
|
||||
@@ -160,4 +165,4 @@ namespace OpenSim.Region.ClientStack.Linden
|
||||
// capName, capUrl, m_scene.RegionInfo.RegionName, agentID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
public sealed class IncomingPacket
|
||||
{
|
||||
/// <summary>Client this packet came from</summary>
|
||||
public LLUDPClient Client;
|
||||
public LLClientView Client;
|
||||
|
||||
/// <summary>Packet data that has been received</summary>
|
||||
public Packet Packet;
|
||||
|
||||
@@ -48,7 +49,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// </summary>
|
||||
/// <param name="client">Reference to the client this packet came from</param>
|
||||
/// <param name="packet">Packet data</param>
|
||||
public IncomingPacket(LLUDPClient client, Packet packet)
|
||||
public IncomingPacket(LLClientView client, Packet packet)
|
||||
{
|
||||
Client = client;
|
||||
Packet = packet;
|
||||
|
||||
@@ -59,7 +59,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// Handles new client connections
|
||||
/// Constructor takes a single Packet and authenticates everything
|
||||
/// </summary>
|
||||
public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientIPEndpoint, IStatsCollector
|
||||
public class LLClientView : IClientAPI, IClientCore, IClientIM, IClientChat, IClientInventory, IClientIPEndpoint, IStatsCollector
|
||||
{
|
||||
/// <value>
|
||||
/// Debug packet level. See OpenSim.RegisterConsoleCommands() for more details.
|
||||
@@ -385,7 +385,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
set { m_startpos = value; }
|
||||
}
|
||||
public UUID AgentId { get { return m_agentId; } }
|
||||
public ISceneAgent SceneAgent { get; private set; }
|
||||
public ISceneAgent SceneAgent { get; set; }
|
||||
public UUID ActiveGroupId { get { return m_activeGroupID; } }
|
||||
public string ActiveGroupName { get { return m_activeGroupName; } }
|
||||
public ulong ActiveGroupPowers { get { return m_activeGroupPowers; } }
|
||||
@@ -449,6 +449,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// DebugPacketLevel = 1;
|
||||
|
||||
RegisterInterface<IClientIM>(this);
|
||||
RegisterInterface<IClientInventory>(this);
|
||||
RegisterInterface<IClientChat>(this);
|
||||
RegisterInterface<IClientIPEndpoint>(this);
|
||||
|
||||
@@ -493,16 +494,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// </summary>
|
||||
public void Close()
|
||||
{
|
||||
IsActive = false;
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[CLIENT]: Close has been called for {0} attached to scene {1}",
|
||||
Name, m_scene.RegionInfo.RegionName);
|
||||
|
||||
// Send the STOP packet
|
||||
DisableSimulatorPacket disable = (DisableSimulatorPacket)PacketPool.Instance.GetPacket(PacketType.DisableSimulator);
|
||||
OutPacket(disable, ThrottleOutPacketType.Unknown);
|
||||
|
||||
IsActive = false;
|
||||
|
||||
// Shutdown the image manager
|
||||
ImageManager.Close();
|
||||
|
||||
@@ -698,7 +695,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
public virtual void Start()
|
||||
{
|
||||
SceneAgent = m_scene.AddNewClient(this, PresenceType.User);
|
||||
m_scene.AddNewClient(this, PresenceType.User);
|
||||
|
||||
RefreshGroupMembership();
|
||||
}
|
||||
@@ -2725,6 +2722,19 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
}
|
||||
|
||||
public void SendAssetNotFound(AssetRequestToClient req)
|
||||
{
|
||||
TransferInfoPacket Transfer = new TransferInfoPacket();
|
||||
Transfer.TransferInfo.ChannelType = 2;
|
||||
Transfer.TransferInfo.Status = -2;
|
||||
Transfer.TransferInfo.TargetType = 0;
|
||||
Transfer.TransferInfo.Params = req.Params;
|
||||
Transfer.TransferInfo.Size = 0;
|
||||
Transfer.TransferInfo.TransferID = req.TransferRequestID;
|
||||
Transfer.Header.Zerocoded = true;
|
||||
OutPacket(Transfer, ThrottleOutPacketType.Asset);
|
||||
}
|
||||
|
||||
public void SendTexture(AssetBase TextureAsset)
|
||||
{
|
||||
|
||||
@@ -3728,8 +3738,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
}
|
||||
|
||||
++updatesThisCall;
|
||||
|
||||
#region UpdateFlags to packet type conversion
|
||||
|
||||
PrimUpdateFlags updateFlags = (PrimUpdateFlags)update.Flags;
|
||||
@@ -3786,20 +3794,53 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
if (!canUseImproved && !canUseCompressed)
|
||||
{
|
||||
ObjectUpdatePacket.ObjectDataBlock updateBlock;
|
||||
|
||||
if (update.Entity is ScenePresence)
|
||||
{
|
||||
objectUpdateBlocks.Value.Add(CreateAvatarUpdateBlock((ScenePresence)update.Entity));
|
||||
objectUpdates.Value.Add(update);
|
||||
updateBlock = CreateAvatarUpdateBlock((ScenePresence)update.Entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
objectUpdateBlocks.Value.Add(CreatePrimUpdateBlock((SceneObjectPart)update.Entity, this.m_agentId));
|
||||
objectUpdates.Value.Add(update);
|
||||
SceneObjectPart part = (SceneObjectPart)update.Entity;
|
||||
updateBlock = CreatePrimUpdateBlock(part, AgentId);
|
||||
|
||||
// If the part has become a private hud since the update was scheduled then we do not
|
||||
// want to send it to other avatars.
|
||||
if (part.ParentGroup.IsAttachment
|
||||
&& part.ParentGroup.HasPrivateAttachmentPoint
|
||||
&& part.ParentGroup.AttachedAvatar != AgentId)
|
||||
continue;
|
||||
|
||||
// If the part has since been deleted, then drop the update. In the case of attachments,
|
||||
// this is to avoid spurious updates to other viewers since post-processing of attachments
|
||||
// has to change the IsAttachment flag for various reasons (which will end up in a pass
|
||||
// of the test above).
|
||||
//
|
||||
// Actual deletions (kills) happen in another method.
|
||||
if (part.ParentGroup.IsDeleted)
|
||||
continue;
|
||||
}
|
||||
|
||||
objectUpdateBlocks.Value.Add(updateBlock);
|
||||
objectUpdates.Value.Add(update);
|
||||
}
|
||||
else if (!canUseImproved)
|
||||
{
|
||||
compressedUpdateBlocks.Value.Add(CreateCompressedUpdateBlock((SceneObjectPart)update.Entity, updateFlags));
|
||||
SceneObjectPart part = (SceneObjectPart)update.Entity;
|
||||
ObjectUpdateCompressedPacket.ObjectDataBlock compressedBlock
|
||||
= CreateCompressedUpdateBlock(part, updateFlags);
|
||||
|
||||
// If the part has since been deleted, then drop the update. In the case of attachments,
|
||||
// this is to avoid spurious updates to other viewers since post-processing of attachments
|
||||
// has to change the IsAttachment flag for various reasons (which will end up in a pass
|
||||
// of the test above).
|
||||
//
|
||||
// Actual deletions (kills) happen in another method.
|
||||
if (part.ParentGroup.IsDeleted)
|
||||
continue;
|
||||
|
||||
compressedUpdateBlocks.Value.Add(compressedBlock);
|
||||
compressedUpdates.Value.Add(update);
|
||||
}
|
||||
else
|
||||
@@ -3812,15 +3853,40 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
else
|
||||
{
|
||||
ImprovedTerseObjectUpdatePacket.ObjectDataBlock terseUpdateBlock
|
||||
= CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures));
|
||||
|
||||
// Everything else goes here
|
||||
terseUpdateBlocks.Value.Add(CreateImprovedTerseBlock(update.Entity, updateFlags.HasFlag(PrimUpdateFlags.Textures)));
|
||||
if (update.Entity is SceneObjectPart)
|
||||
{
|
||||
SceneObjectPart part = (SceneObjectPart)update.Entity;
|
||||
|
||||
// If the part has become a private hud since the update was scheduled then we do not
|
||||
// want to send it to other avatars.
|
||||
if (part.ParentGroup.IsAttachment
|
||||
&& part.ParentGroup.HasPrivateAttachmentPoint
|
||||
&& part.ParentGroup.AttachedAvatar != AgentId)
|
||||
continue;
|
||||
|
||||
// If the part has since been deleted, then drop the update. In the case of attachments,
|
||||
// this is to avoid spurious updates to other viewers since post-processing of attachments
|
||||
// has to change the IsAttachment flag for various reasons (which will end up in a pass
|
||||
// of the test above).
|
||||
//
|
||||
// Actual deletions (kills) happen in another method.
|
||||
if (part.ParentGroup.IsDeleted)
|
||||
continue;
|
||||
}
|
||||
|
||||
terseUpdateBlocks.Value.Add(terseUpdateBlock);
|
||||
terseUpdates.Value.Add(update);
|
||||
}
|
||||
}
|
||||
|
||||
++updatesThisCall;
|
||||
|
||||
#endregion Block Construction
|
||||
}
|
||||
|
||||
|
||||
#region Packet Sending
|
||||
ushort timeDilation = Utils.FloatToUInt16(avgTimeDilation, 0.0f, 1.0f);
|
||||
@@ -4273,7 +4339,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
block.OwnerID = sop.OwnerID;
|
||||
|
||||
block.ItemID = sop.FromUserInventoryItemID;
|
||||
block.FolderID = UUID.Zero; // sop.FromFolderID ??
|
||||
block.FolderID = UUID.Zero; // sog.FromFolderID ??
|
||||
block.FromTaskID = UUID.Zero; // ???
|
||||
block.InventorySerial = (short)sop.InventorySerial;
|
||||
|
||||
@@ -4959,7 +5025,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
update.MediaURL = Utils.EmptyBytes; // FIXME: Support this in OpenSim
|
||||
if (data.ParentGroup.IsAttachment)
|
||||
{
|
||||
update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.FromItemID);
|
||||
update.NameValue = Util.StringToBytes256("AttachItemID STRING RW SV " + data.ParentGroup.FromItemID);
|
||||
update.State = (byte)((data.ParentGroup.AttachmentPoint % 16) * 16 + (data.ParentGroup.AttachmentPoint / 16));
|
||||
}
|
||||
else
|
||||
@@ -5787,7 +5853,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// My guess is this is the folder to stick the calling card into
|
||||
List<UUID> callingCardFolders = new List<UUID>();
|
||||
|
||||
UUID agentID = afriendpack.AgentData.AgentID;
|
||||
UUID transactionID = afriendpack.TransactionBlock.TransactionID;
|
||||
|
||||
for (int fi = 0; fi < afriendpack.FolderData.Length; fi++)
|
||||
@@ -5798,10 +5863,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
FriendActionDelegate handlerApproveFriendRequest = OnApproveFriendRequest;
|
||||
if (handlerApproveFriendRequest != null)
|
||||
{
|
||||
handlerApproveFriendRequest(this, agentID, transactionID, callingCardFolders);
|
||||
handlerApproveFriendRequest(this, transactionID, callingCardFolders);
|
||||
}
|
||||
return true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandlerDeclineFriendship(IClientAPI sender, Packet Pack)
|
||||
@@ -5820,7 +5885,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
if (OnDenyFriendRequest != null)
|
||||
{
|
||||
OnDenyFriendRequest(this,
|
||||
dfriendpack.AgentData.AgentID,
|
||||
dfriendpack.TransactionBlock.TransactionID,
|
||||
null);
|
||||
}
|
||||
@@ -5840,14 +5904,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
#endregion
|
||||
|
||||
UUID listOwnerAgentID = tfriendpack.AgentData.AgentID;
|
||||
UUID exFriendID = tfriendpack.ExBlock.OtherID;
|
||||
FriendshipTermination TerminateFriendshipHandler = OnTerminateFriendship;
|
||||
if (TerminateFriendshipHandler != null)
|
||||
{
|
||||
TerminateFriendshipHandler(this, listOwnerAgentID, exFriendID);
|
||||
TerminateFriendshipHandler(this, exFriendID);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -11165,12 +11229,13 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
return true;
|
||||
}
|
||||
#endregion
|
||||
|
||||
GrantUserFriendRights GrantUserRightsHandler = OnGrantUserRights;
|
||||
if (GrantUserRightsHandler != null)
|
||||
GrantUserRightsHandler(this,
|
||||
GrantUserRights.AgentData.AgentID,
|
||||
GrantUserRights.Rights[0].AgentRelated,
|
||||
GrantUserRights.Rights[0].RelatedRights);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -11683,7 +11748,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
if (DebugPacketLevel <= 100 && (packet.Type == PacketType.AvatarAnimation || packet.Type == PacketType.ViewerEffect))
|
||||
logPacket = false;
|
||||
|
||||
if (DebugPacketLevel <= 50 && packet.Type == PacketType.ImprovedTerseObjectUpdate)
|
||||
if (DebugPacketLevel <= 50
|
||||
& (packet.Type == PacketType.ImprovedTerseObjectUpdate || packet.Type == PacketType.ObjectUpdate))
|
||||
logPacket = false;
|
||||
|
||||
if (DebugPacketLevel <= 25 && packet.Type == PacketType.ObjectPropertiesFamily)
|
||||
@@ -11893,10 +11959,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public void KillEndDone()
|
||||
{
|
||||
}
|
||||
|
||||
#region IClientCore
|
||||
|
||||
private readonly Dictionary<Type, object> m_clientInterfaces = new Dictionary<Type, object>();
|
||||
@@ -11984,21 +12046,24 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
protected void MakeAssetRequest(TransferRequestPacket transferRequest, UUID taskID)
|
||||
{
|
||||
UUID requestID = UUID.Zero;
|
||||
if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset)
|
||||
int sourceType = transferRequest.TransferInfo.SourceType;
|
||||
|
||||
if (sourceType == (int)SourceType.Asset)
|
||||
{
|
||||
requestID = new UUID(transferRequest.TransferInfo.Params, 0);
|
||||
}
|
||||
else if (transferRequest.TransferInfo.SourceType == (int)SourceType.SimInventoryItem)
|
||||
else if (sourceType == (int)SourceType.SimInventoryItem)
|
||||
{
|
||||
requestID = new UUID(transferRequest.TransferInfo.Params, 80);
|
||||
}
|
||||
else if (transferRequest.TransferInfo.SourceType == (int)SourceType.SimEstate)
|
||||
else if (sourceType == (int)SourceType.SimEstate)
|
||||
{
|
||||
requestID = taskID;
|
||||
}
|
||||
|
||||
|
||||
// m_log.DebugFormat("[CLIENT]: {0} requesting asset {1}", Name, requestID);
|
||||
// m_log.DebugFormat(
|
||||
// "[LLCLIENTVIEW]: Received transfer request for {0} in {1} type {2} by {3}",
|
||||
// requestID, taskID, (SourceType)sourceType, Name);
|
||||
|
||||
m_assetService.Get(requestID.ToString(), transferRequest, AssetReceived);
|
||||
}
|
||||
@@ -12011,14 +12076,27 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
/// <param name="asset"></param>
|
||||
protected void AssetReceived(string id, Object sender, AssetBase asset)
|
||||
{
|
||||
if (asset == null)
|
||||
return;
|
||||
|
||||
TransferRequestPacket transferRequest = (TransferRequestPacket)sender;
|
||||
|
||||
UUID requestID = UUID.Zero;
|
||||
byte source = (byte)SourceType.Asset;
|
||||
|
||||
AssetRequestToClient req = new AssetRequestToClient();
|
||||
|
||||
if (asset == null)
|
||||
{
|
||||
req.AssetInf = null;
|
||||
req.AssetRequestSource = source;
|
||||
req.IsTextureRequest = false;
|
||||
req.NumPackets = 0;
|
||||
req.Params = transferRequest.TransferInfo.Params;
|
||||
req.RequestAssetID = requestID;
|
||||
req.TransferRequestID = transferRequest.TransferInfo.TransferID;
|
||||
|
||||
SendAssetNotFound(req);
|
||||
return;
|
||||
}
|
||||
|
||||
if (transferRequest.TransferInfo.SourceType == (int)SourceType.Asset)
|
||||
{
|
||||
requestID = new UUID(transferRequest.TransferInfo.Params, 0);
|
||||
@@ -12035,7 +12113,6 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
return;
|
||||
|
||||
// The asset is known to exist and is in our cache, so add it to the AssetRequests list
|
||||
AssetRequestToClient req = new AssetRequestToClient();
|
||||
req.AssetInf = asset;
|
||||
req.AssetRequestSource = source;
|
||||
req.IsTextureRequest = false;
|
||||
@@ -12292,5 +12369,175 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
if (reply != null)
|
||||
OutPacket(reply, ThrottleOutPacketType.Task);
|
||||
}
|
||||
|
||||
public void SendRemoveInventoryItems(UUID[] items)
|
||||
{
|
||||
IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
|
||||
|
||||
if (eq == null)
|
||||
{
|
||||
m_log.DebugFormat("[LLCLIENT]: Null event queue");
|
||||
return;
|
||||
}
|
||||
|
||||
OSDMap llsd = new OSDMap(3);
|
||||
|
||||
OSDMap AgentDataMap = new OSDMap(1);
|
||||
AgentDataMap.Add("AgentID", OSD.FromUUID(AgentId));
|
||||
AgentDataMap.Add("SessionID", OSD.FromUUID(SessionId));
|
||||
|
||||
OSDArray AgentData = new OSDArray(1);
|
||||
AgentData.Add(AgentDataMap);
|
||||
|
||||
llsd.Add("AgentData", AgentData);
|
||||
|
||||
OSDArray ItemData = new OSDArray();
|
||||
|
||||
foreach (UUID item in items)
|
||||
{
|
||||
OSDMap ItemDataMap = new OSDMap(2);
|
||||
ItemDataMap.Add("ItemID", OSD.FromUUID(item));
|
||||
ItemDataMap.Add("AgentID", OSD.FromUUID(AgentId));
|
||||
|
||||
ItemData.Add(ItemDataMap);
|
||||
}
|
||||
|
||||
llsd.Add("InventoryData", ItemData);
|
||||
|
||||
eq.Enqueue(BuildEvent("RemoveInventoryItem",
|
||||
llsd), AgentId);
|
||||
}
|
||||
|
||||
public void SendRemoveInventoryFolders(UUID[] folders)
|
||||
{
|
||||
IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
|
||||
|
||||
if (eq == null)
|
||||
{
|
||||
m_log.DebugFormat("[LLCLIENT]: Null event queue");
|
||||
return;
|
||||
}
|
||||
|
||||
OSDMap llsd = new OSDMap(3);
|
||||
|
||||
OSDMap AgentDataMap = new OSDMap(1);
|
||||
AgentDataMap.Add("AgentID", OSD.FromUUID(AgentId));
|
||||
AgentDataMap.Add("SessionID", OSD.FromUUID(SessionId));
|
||||
|
||||
OSDArray AgentData = new OSDArray(1);
|
||||
AgentData.Add(AgentDataMap);
|
||||
|
||||
llsd.Add("AgentData", AgentData);
|
||||
|
||||
OSDArray FolderData = new OSDArray();
|
||||
|
||||
foreach (UUID folder in folders)
|
||||
{
|
||||
OSDMap FolderDataMap = new OSDMap(2);
|
||||
FolderDataMap.Add("FolderID", OSD.FromUUID(folder));
|
||||
FolderDataMap.Add("AgentID", OSD.FromUUID(AgentId));
|
||||
|
||||
FolderData.Add(FolderDataMap);
|
||||
}
|
||||
|
||||
llsd.Add("FolderData", FolderData);
|
||||
|
||||
eq.Enqueue(BuildEvent("RemoveInventoryFolder",
|
||||
llsd), AgentId);
|
||||
}
|
||||
|
||||
private byte[] EncodeU32(uint val)
|
||||
{
|
||||
byte[] ret = BitConverter.GetBytes(val);
|
||||
if (BitConverter.IsLittleEndian)
|
||||
Array.Reverse(ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void SendBulkUpdateInventory(InventoryFolderBase[] folders, InventoryItemBase[] items)
|
||||
{
|
||||
IEventQueue eq = Scene.RequestModuleInterface<IEventQueue>();
|
||||
|
||||
if (eq == null)
|
||||
{
|
||||
m_log.DebugFormat("[LLCLIENT]: Null event queue");
|
||||
return;
|
||||
}
|
||||
|
||||
OSDMap llsd = new OSDMap(3);
|
||||
|
||||
OSDMap AgentDataMap = new OSDMap(1);
|
||||
AgentDataMap.Add("AgentID", OSD.FromUUID(AgentId));
|
||||
AgentDataMap.Add("SessionID", OSD.FromUUID(SessionId));
|
||||
AgentDataMap.Add("TransactionID", OSD.FromUUID(UUID.Random()));
|
||||
|
||||
OSDArray AgentData = new OSDArray(1);
|
||||
AgentData.Add(AgentDataMap);
|
||||
|
||||
llsd.Add("AgentData", AgentData);
|
||||
|
||||
OSDArray FolderData = new OSDArray();
|
||||
|
||||
foreach (InventoryFolderBase folder in folders)
|
||||
{
|
||||
OSDMap FolderDataMap = new OSDMap(5);
|
||||
FolderDataMap.Add("FolderID", OSD.FromUUID(folder.ID));
|
||||
FolderDataMap.Add("AgentID", OSD.FromUUID(AgentId));
|
||||
FolderDataMap.Add("ParentID", OSD.FromUUID(folder.ParentID));
|
||||
FolderDataMap.Add("Type", OSD.FromInteger(folder.Type));
|
||||
FolderDataMap.Add("Name", OSD.FromString(folder.Name));
|
||||
|
||||
FolderData.Add(FolderDataMap);
|
||||
}
|
||||
|
||||
llsd.Add("FolderData", FolderData);
|
||||
|
||||
OSDArray ItemData = new OSDArray();
|
||||
|
||||
foreach (InventoryItemBase item in items)
|
||||
{
|
||||
OSDMap ItemDataMap = new OSDMap();
|
||||
|
||||
ItemDataMap.Add("ItemID", OSD.FromUUID(item.ID));
|
||||
ItemDataMap.Add("FolderID", OSD.FromUUID(item.Folder));
|
||||
|
||||
ItemDataMap.Add("CreatorID", OSD.FromUUID(item.CreatorIdAsUuid));
|
||||
ItemDataMap.Add("OwnerID", OSD.FromUUID(item.Owner));
|
||||
ItemDataMap.Add("GroupID", OSD.FromUUID(item.GroupID));
|
||||
ItemDataMap.Add("BaseMask", OSD.FromBinary(EncodeU32((uint)item.BasePermissions)));
|
||||
ItemDataMap.Add("OwnerMask", OSD.FromBinary(EncodeU32((uint)item.CurrentPermissions)));
|
||||
ItemDataMap.Add("GroupMask", OSD.FromBinary(EncodeU32((uint)item.GroupPermissions)));
|
||||
ItemDataMap.Add("EveryoneMask", OSD.FromBinary(EncodeU32((uint)item.EveryOnePermissions)));
|
||||
ItemDataMap.Add("NextOwnerMask", OSD.FromBinary(EncodeU32((uint)item.NextPermissions)));
|
||||
ItemDataMap.Add("GroupOwned", OSD.FromBoolean(item.GroupOwned));
|
||||
ItemDataMap.Add("AssetID", OSD.FromUUID(item.AssetID));
|
||||
ItemDataMap.Add("Type", OSD.FromInteger(item.AssetType));
|
||||
ItemDataMap.Add("InvType", OSD.FromInteger(item.InvType));
|
||||
ItemDataMap.Add("Flags", OSD.FromBinary(EncodeU32((uint)item.Flags)));
|
||||
ItemDataMap.Add("SaleType", OSD.FromInteger((byte)item.SaleType));
|
||||
ItemDataMap.Add("SalePrice", OSD.FromInteger(item.SalePrice));
|
||||
ItemDataMap.Add("Name", OSD.FromString(item.Name));
|
||||
ItemDataMap.Add("Description", OSD.FromString(item.Description));
|
||||
ItemDataMap.Add("CreationDate", OSD.FromInteger(item.CreationDate));
|
||||
|
||||
ItemDataMap.Add("CRC", OSD.FromBinary(EncodeU32(
|
||||
Helpers.InventoryCRC(1000, 0, (sbyte)item.InvType,
|
||||
(sbyte)item.AssetType, item.AssetID,
|
||||
item.GroupID, 100,
|
||||
item.Owner, item.CreatorIdAsUuid,
|
||||
item.ID, item.Folder,
|
||||
(uint)PermissionMask.All, 1, (uint)PermissionMask.All, (uint)PermissionMask.All,
|
||||
(uint)PermissionMask.All)
|
||||
)));
|
||||
ItemDataMap.Add("CallbackID", 0);
|
||||
|
||||
ItemData.Add(ItemDataMap);
|
||||
}
|
||||
|
||||
llsd.Add("ItemData", ItemData);
|
||||
|
||||
eq.Enqueue(BuildEvent("BulkUpdateInventory",
|
||||
llsd), AgentId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,21 +147,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
private int m_elapsed500MSOutgoingPacketHandler;
|
||||
|
||||
/// <summary>Flag to signal when clients should check for resends</summary>
|
||||
private bool m_resendUnacked;
|
||||
protected bool m_resendUnacked;
|
||||
|
||||
/// <summary>Flag to signal when clients should send ACKs</summary>
|
||||
private bool m_sendAcks;
|
||||
protected bool m_sendAcks;
|
||||
|
||||
/// <summary>Flag to signal when clients should send pings</summary>
|
||||
private bool m_sendPing;
|
||||
protected bool m_sendPing;
|
||||
|
||||
private int m_defaultRTO = 0;
|
||||
private int m_maxRTO = 0;
|
||||
|
||||
private int m_ackTimeout = 0;
|
||||
private int m_pausedAckTimeout = 0;
|
||||
private bool m_disableFacelights = false;
|
||||
|
||||
public Socket Server { get { return null; } }
|
||||
|
||||
private int m_malformedCount = 0; // Guard against a spamming attack
|
||||
|
||||
/// <summary>
|
||||
/// Record current outgoing client for monitoring purposes.
|
||||
/// </summary>
|
||||
private IClientAPI m_currentOutgoingClient;
|
||||
|
||||
/// <summary>
|
||||
/// Recording current incoming client for monitoring purposes.
|
||||
/// </summary>
|
||||
private IClientAPI m_currentIncomingClient;
|
||||
|
||||
public LLUDPServer(IPAddress listenIP, ref uint port, int proxyPortOffsetParm, bool allow_alternate_port, IConfigSource configSource, AgentCircuitManager circuitManager)
|
||||
: base(listenIP, (int)port)
|
||||
{
|
||||
@@ -198,11 +211,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
m_defaultRTO = config.GetInt("DefaultRTO", 0);
|
||||
m_maxRTO = config.GetInt("MaxRTO", 0);
|
||||
m_disableFacelights = config.GetBoolean("DisableFacelights", false);
|
||||
m_ackTimeout = 1000 * config.GetInt("AckTimeout", 60);
|
||||
m_pausedAckTimeout = 1000 * config.GetInt("PausedAckTimeout", 300);
|
||||
}
|
||||
else
|
||||
{
|
||||
PrimUpdatesPerCallback = 100;
|
||||
TextureSendLimit = 20;
|
||||
m_ackTimeout = 1000 * 60; // 1 minute
|
||||
m_pausedAckTimeout = 1000 * 300; // 5 minutes
|
||||
}
|
||||
|
||||
#region BinaryStats
|
||||
@@ -239,19 +256,56 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
if (m_scene == null)
|
||||
throw new InvalidOperationException("[LLUDPSERVER]: Cannot LLUDPServer.Start() without an IScene reference");
|
||||
|
||||
m_log.Info("[LLUDPSERVER]: Starting the LLUDP server in " + (m_asyncPacketHandling ? "asynchronous" : "synchronous") + " mode");
|
||||
m_log.InfoFormat(
|
||||
"[LLUDPSERVER]: Starting the LLUDP server in {0} mode",
|
||||
m_asyncPacketHandling ? "asynchronous" : "synchronous");
|
||||
|
||||
base.Start(m_recvBufferSize, m_asyncPacketHandling);
|
||||
|
||||
// Start the packet processing threads
|
||||
Watchdog.StartThread(
|
||||
IncomingPacketHandler, "Incoming Packets (" + m_scene.RegionInfo.RegionName + ")", ThreadPriority.Normal, false, true);
|
||||
IncomingPacketHandler,
|
||||
string.Format("Incoming Packets ({0})", m_scene.RegionInfo.RegionName),
|
||||
ThreadPriority.Normal,
|
||||
false,
|
||||
true,
|
||||
GetWatchdogIncomingAlarmData,
|
||||
Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
|
||||
|
||||
Watchdog.StartThread(
|
||||
OutgoingPacketHandler, "Outgoing Packets (" + m_scene.RegionInfo.RegionName + ")", ThreadPriority.Normal, false, true);
|
||||
OutgoingPacketHandler,
|
||||
string.Format("Outgoing Packets ({0})", m_scene.RegionInfo.RegionName),
|
||||
ThreadPriority.Normal,
|
||||
false,
|
||||
true,
|
||||
GetWatchdogOutgoingAlarmData,
|
||||
Watchdog.DEFAULT_WATCHDOG_TIMEOUT_MS);
|
||||
|
||||
m_elapsedMSSinceLastStatReport = Environment.TickCount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private string GetWatchdogIncomingAlarmData()
|
||||
{
|
||||
return string.Format(
|
||||
"Client is {0}",
|
||||
m_currentIncomingClient != null ? m_currentIncomingClient.Name : "none");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If the outgoing UDP thread times out, then return client that was being processed to help with debugging.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private string GetWatchdogOutgoingAlarmData()
|
||||
{
|
||||
return string.Format(
|
||||
"Client is {0}",
|
||||
m_currentOutgoingClient != null ? m_currentOutgoingClient.Name : "none");
|
||||
}
|
||||
|
||||
public new void Stop()
|
||||
{
|
||||
m_log.Info("[LLUDPSERVER]: Shutting down the LLUDP server for " + m_scene.RegionInfo.RegionName);
|
||||
@@ -485,19 +539,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
SendPacket(udpClient, completePing, ThrottleOutPacketType.Unknown, false, null);
|
||||
}
|
||||
|
||||
public void HandleUnacked(LLUDPClient udpClient)
|
||||
public void HandleUnacked(LLClientView client)
|
||||
{
|
||||
LLUDPClient udpClient = client.UDPClient;
|
||||
|
||||
if (!udpClient.IsConnected)
|
||||
return;
|
||||
|
||||
// Disconnect an agent if no packets are received for some time
|
||||
//FIXME: Make 60 an .ini setting
|
||||
if ((Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > 1000 * 60)
|
||||
{
|
||||
m_log.Warn("[LLUDPSERVER]: Ack timeout, disconnecting " + udpClient.AgentID);
|
||||
StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
|
||||
int timeoutTicks = m_ackTimeout;
|
||||
|
||||
// Allow more slack if the client is "paused" eg file upload dialogue is open
|
||||
// Some sort of limit is needed in case the client crashes, loses its network connection
|
||||
// or some other disaster prevents it from sendung the AgentResume
|
||||
if (udpClient.IsPaused)
|
||||
timeoutTicks = m_pausedAckTimeout;
|
||||
|
||||
if (client.IsActive &&
|
||||
(Environment.TickCount & Int32.MaxValue) - udpClient.TickLastPacketReceived > timeoutTicks)
|
||||
{
|
||||
// We must set IsActive synchronously so that we can stop the packet loop reinvoking this method, even
|
||||
// though it's set later on by LLClientView.Close()
|
||||
client.IsActive = false;
|
||||
|
||||
// Fire this out on a different thread so that we don't hold up outgoing packet processing for
|
||||
// everybody else if this is being called due to an ack timeout.
|
||||
// This is the same as processing as the async process of a logout request.
|
||||
Util.FireAndForget(o => DeactivateClientDueToTimeout(client));
|
||||
|
||||
RemoveClient(udpClient);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -820,7 +889,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
#endregion Ping Check Handling
|
||||
|
||||
// Inbox insertion
|
||||
packetInbox.Enqueue(new IncomingPacket(udpClient, packet));
|
||||
packetInbox.Enqueue(new IncomingPacket((LLClientView)client, packet));
|
||||
}
|
||||
|
||||
#region BinaryStats
|
||||
@@ -916,7 +985,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
UDPPacketBuffer buffer = (UDPPacketBuffer)array[0];
|
||||
UseCircuitCodePacket uccp = (UseCircuitCodePacket)array[1];
|
||||
|
||||
m_log.DebugFormat("[LLUDPSERVER]: Handling UseCircuitCode request from {0}", buffer.RemoteEndPoint);
|
||||
m_log.DebugFormat(
|
||||
"[LLUDPSERVER]: Handling UseCircuitCode request for circuit {0} to {1} from IP {2}",
|
||||
uccp.CircuitCode.Code, m_scene.RegionInfo.RegionName, buffer.RemoteEndPoint);
|
||||
|
||||
remoteEndPoint = (IPEndPoint)buffer.RemoteEndPoint;
|
||||
|
||||
@@ -945,8 +1016,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
// Don't create clients for unauthorized requesters.
|
||||
m_log.WarnFormat(
|
||||
"[LLUDPSERVER]: Connection request for client {0} connecting with unnotified circuit code {1} from {2}",
|
||||
uccp.CircuitCode.ID, uccp.CircuitCode.Code, remoteEndPoint);
|
||||
"[LLUDPSERVER]: Ignoring connection request for {0} to {1} with unknown circuit code {2} from IP {3}",
|
||||
uccp.CircuitCode.ID, m_scene.RegionInfo.RegionName, uccp.CircuitCode.Code, remoteEndPoint);
|
||||
}
|
||||
|
||||
// m_log.DebugFormat(
|
||||
@@ -1044,15 +1115,30 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
return client;
|
||||
}
|
||||
|
||||
private void RemoveClient(LLUDPClient udpClient)
|
||||
/// <summary>
|
||||
/// Deactivates the client if we don't receive any packets within a certain amount of time (default 60 seconds).
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// If a connection is active then we will always receive packets even if nothing else is happening, due to
|
||||
/// regular client pings.
|
||||
/// </remarks>
|
||||
/// <param name='client'></param>
|
||||
private void DeactivateClientDueToTimeout(IClientAPI client)
|
||||
{
|
||||
// Remove this client from the scene
|
||||
IClientAPI client;
|
||||
if (m_scene.TryGetClient(udpClient.AgentID, out client))
|
||||
{
|
||||
client.IsLoggingOut = true;
|
||||
client.Close();
|
||||
}
|
||||
// We must set IsActive synchronously so that we can stop the packet loop reinvoking this method, even
|
||||
// though it's set later on by LLClientView.Close()
|
||||
client.IsActive = false;
|
||||
|
||||
m_log.WarnFormat(
|
||||
"[LLUDPSERVER]: Ack timeout, disconnecting {0} agent for {1} in {2}",
|
||||
client.SceneAgent.IsChildAgent ? "child" : "root", client.Name, m_scene.RegionInfo.RegionName);
|
||||
|
||||
StatsManager.SimExtraStats.AddAbnormalClientThreadTermination();
|
||||
|
||||
if (!client.SceneAgent.IsChildAgent)
|
||||
client.Kick("Simulator logged you out due to connection timeout");
|
||||
|
||||
client.Close();
|
||||
}
|
||||
|
||||
private void IncomingPacketHandler()
|
||||
@@ -1159,6 +1245,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
// client. m_packetSent will be set to true if a packet is sent
|
||||
m_scene.ForEachClient(clientPacketHandler);
|
||||
|
||||
m_currentOutgoingClient = null;
|
||||
|
||||
// If nothing was sent, sleep for the minimum amount of time before a
|
||||
// token bucket could get more tokens
|
||||
if (!m_packetSent)
|
||||
@@ -1175,18 +1263,21 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
Watchdog.RemoveThread();
|
||||
}
|
||||
|
||||
private void ClientOutgoingPacketHandler(IClientAPI client)
|
||||
protected void ClientOutgoingPacketHandler(IClientAPI client)
|
||||
{
|
||||
m_currentOutgoingClient = client;
|
||||
|
||||
try
|
||||
{
|
||||
if (client is LLClientView)
|
||||
{
|
||||
LLUDPClient udpClient = ((LLClientView)client).UDPClient;
|
||||
LLClientView llClient = (LLClientView)client;
|
||||
LLUDPClient udpClient = llClient.UDPClient;
|
||||
|
||||
if (udpClient.IsConnected)
|
||||
{
|
||||
if (m_resendUnacked)
|
||||
HandleUnacked(udpClient);
|
||||
HandleUnacked(llClient);
|
||||
|
||||
if (m_sendAcks)
|
||||
SendAcks(udpClient);
|
||||
@@ -1202,8 +1293,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
m_log.Error("[LLUDPSERVER]: OutgoingPacketHandler iteration for " + client.Name +
|
||||
" threw an exception: " + ex.Message, ex);
|
||||
m_log.Error(
|
||||
string.Format("[LLUDPSERVER]: OutgoingPacketHandler iteration for {0} threw ", client.Name), ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1229,11 +1320,14 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
{
|
||||
nticks++;
|
||||
watch1.Start();
|
||||
m_currentOutgoingClient = client;
|
||||
|
||||
try
|
||||
{
|
||||
if (client is LLClientView)
|
||||
{
|
||||
LLUDPClient udpClient = ((LLClientView)client).UDPClient;
|
||||
LLClientView llClient = (LLClientView)client;
|
||||
LLUDPClient udpClient = llClient.UDPClient;
|
||||
|
||||
if (udpClient.IsConnected)
|
||||
{
|
||||
@@ -1242,7 +1336,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
nticksUnack++;
|
||||
watch2.Start();
|
||||
|
||||
HandleUnacked(udpClient);
|
||||
HandleUnacked(llClient);
|
||||
|
||||
watch2.Stop();
|
||||
avgResendUnackedTicks = (nticksUnack - 1)/(float)nticksUnack * avgResendUnackedTicks + (watch2.ElapsedTicks / (float)nticksUnack);
|
||||
@@ -1313,23 +1407,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
|
||||
#endregion
|
||||
|
||||
private void ProcessInPacket(object state)
|
||||
private void ProcessInPacket(IncomingPacket incomingPacket)
|
||||
{
|
||||
IncomingPacket incomingPacket = (IncomingPacket)state;
|
||||
Packet packet = incomingPacket.Packet;
|
||||
LLUDPClient udpClient = incomingPacket.Client;
|
||||
IClientAPI client;
|
||||
LLClientView client = incomingPacket.Client;
|
||||
|
||||
// Sanity check
|
||||
if (packet == null || udpClient == null)
|
||||
if (client.IsActive)
|
||||
{
|
||||
m_log.WarnFormat("[LLUDPSERVER]: Processing a packet with incomplete state. Packet=\"{0}\", UDPClient=\"{1}\"",
|
||||
packet, udpClient);
|
||||
}
|
||||
m_currentIncomingClient = client;
|
||||
|
||||
// Make sure this client is still alive
|
||||
if (m_scene.TryGetClient(udpClient.AgentID, out client))
|
||||
{
|
||||
try
|
||||
{
|
||||
// Process this packet
|
||||
@@ -1344,21 +1430,34 @@ namespace OpenSim.Region.ClientStack.LindenUDP
|
||||
catch (Exception e)
|
||||
{
|
||||
// Don't let a failure in an individual client thread crash the whole sim.
|
||||
m_log.ErrorFormat("[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw an exception", udpClient.AgentID, packet.Type);
|
||||
m_log.Error(e.Message, e);
|
||||
m_log.Error(
|
||||
string.Format(
|
||||
"[LLUDPSERVER]: Client packet handler for {0} for packet {1} threw ",
|
||||
client.Name, packet.Type),
|
||||
e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
m_currentIncomingClient = null;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.DebugFormat("[LLUDPSERVER]: Dropping incoming {0} packet for dead client {1}", packet.Type, udpClient.AgentID);
|
||||
m_log.DebugFormat(
|
||||
"[LLUDPSERVER]: Dropped incoming {0} for dead client {1} in {2}",
|
||||
packet.Type, client.Name, m_scene.RegionInfo.RegionName);
|
||||
}
|
||||
}
|
||||
|
||||
protected void LogoutHandler(IClientAPI client)
|
||||
{
|
||||
client.SendLogoutPacket();
|
||||
if (client.IsActive)
|
||||
RemoveClient(((LLClientView)client).UDPClient);
|
||||
|
||||
if (!client.IsLoggingOut)
|
||||
{
|
||||
client.IsLoggingOut = true;
|
||||
client.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,9 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||
[TestFixture]
|
||||
public class BasicCircuitTests
|
||||
{
|
||||
private Scene m_scene;
|
||||
private TestLLUDPServer m_udpServer;
|
||||
|
||||
[TestFixtureSetUp]
|
||||
public void FixtureInit()
|
||||
{
|
||||
@@ -61,83 +64,18 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||
Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
|
||||
}
|
||||
|
||||
// /// <summary>
|
||||
// /// Add a client for testing
|
||||
// /// </summary>
|
||||
// /// <param name="scene"></param>
|
||||
// /// <param name="testLLUDPServer"></param>
|
||||
// /// <param name="testPacketServer"></param>
|
||||
// /// <param name="acm">Agent circuit manager used in setting up the stack</param>
|
||||
// protected void SetupStack(
|
||||
// IScene scene, out TestLLUDPServer testLLUDPServer, out TestLLPacketServer testPacketServer,
|
||||
// out AgentCircuitManager acm)
|
||||
// {
|
||||
// IConfigSource configSource = new IniConfigSource();
|
||||
// ClientStackUserSettings userSettings = new ClientStackUserSettings();
|
||||
// testLLUDPServer = new TestLLUDPServer();
|
||||
// acm = new AgentCircuitManager();
|
||||
//
|
||||
// uint port = 666;
|
||||
// testLLUDPServer.Initialise(null, ref port, 0, false, configSource, acm);
|
||||
// testPacketServer = new TestLLPacketServer(testLLUDPServer, userSettings);
|
||||
// testLLUDPServer.LocalScene = scene;
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// Set up a client for tests which aren't concerned with this process itself and where only one client is being
|
||||
// /// tested
|
||||
// /// </summary>
|
||||
// /// <param name="circuitCode"></param>
|
||||
// /// <param name="epSender"></param>
|
||||
// /// <param name="testLLUDPServer"></param>
|
||||
// /// <param name="acm"></param>
|
||||
// protected void AddClient(
|
||||
// uint circuitCode, EndPoint epSender, TestLLUDPServer testLLUDPServer, AgentCircuitManager acm)
|
||||
// {
|
||||
// UUID myAgentUuid = UUID.Parse("00000000-0000-0000-0000-000000000001");
|
||||
// UUID mySessionUuid = UUID.Parse("00000000-0000-0000-0000-000000000002");
|
||||
//
|
||||
// AddClient(circuitCode, epSender, myAgentUuid, mySessionUuid, testLLUDPServer, acm);
|
||||
// }
|
||||
|
||||
// /// <summary>
|
||||
// /// Set up a client for tests which aren't concerned with this process itself
|
||||
// /// </summary>
|
||||
// /// <param name="circuitCode"></param>
|
||||
// /// <param name="epSender"></param>
|
||||
// /// <param name="agentId"></param>
|
||||
// /// <param name="sessionId"></param>
|
||||
// /// <param name="testLLUDPServer"></param>
|
||||
// /// <param name="acm"></param>
|
||||
// protected void AddClient(
|
||||
// uint circuitCode, EndPoint epSender, UUID agentId, UUID sessionId,
|
||||
// TestLLUDPServer testLLUDPServer, AgentCircuitManager acm)
|
||||
// {
|
||||
// AgentCircuitData acd = new AgentCircuitData();
|
||||
// acd.AgentID = agentId;
|
||||
// acd.SessionID = sessionId;
|
||||
//
|
||||
// UseCircuitCodePacket uccp = new UseCircuitCodePacket();
|
||||
//
|
||||
// UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock
|
||||
// = new UseCircuitCodePacket.CircuitCodeBlock();
|
||||
// uccpCcBlock.Code = circuitCode;
|
||||
// uccpCcBlock.ID = agentId;
|
||||
// uccpCcBlock.SessionID = sessionId;
|
||||
// uccp.CircuitCode = uccpCcBlock;
|
||||
//
|
||||
// acm.AddNewCircuit(circuitCode, acd);
|
||||
//
|
||||
// testLLUDPServer.LoadReceive(uccp, epSender);
|
||||
// testLLUDPServer.ReceiveData(null);
|
||||
// }
|
||||
[SetUp]
|
||||
public void SetUp()
|
||||
{
|
||||
m_scene = new SceneHelpers().SetupScene();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Build an object name packet for test purposes
|
||||
/// </summary>
|
||||
/// <param name="objectLocalId"></param>
|
||||
/// <param name="objectName"></param>
|
||||
protected ObjectNamePacket BuildTestObjectNamePacket(uint objectLocalId, string objectName)
|
||||
private ObjectNamePacket BuildTestObjectNamePacket(uint objectLocalId, string objectName)
|
||||
{
|
||||
ObjectNamePacket onp = new ObjectNamePacket();
|
||||
ObjectNamePacket.ObjectDataBlock odb = new ObjectNamePacket.ObjectDataBlock();
|
||||
@@ -148,29 +86,31 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||
|
||||
return onp;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test adding a client to the stack
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestAddClient()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// XmlConfigurator.Configure();
|
||||
|
||||
TestScene scene = SceneHelpers.SetupScene();
|
||||
uint myCircuitCode = 123456;
|
||||
private void AddUdpServer()
|
||||
{
|
||||
AddUdpServer(new IniConfigSource());
|
||||
}
|
||||
|
||||
private void AddUdpServer(IniConfigSource configSource)
|
||||
{
|
||||
uint port = 0;
|
||||
AgentCircuitManager acm = m_scene.AuthenticateHandler;
|
||||
|
||||
m_udpServer = new TestLLUDPServer(IPAddress.Any, ref port, 0, false, configSource, acm);
|
||||
m_udpServer.AddScene(m_scene);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Used by tests that aren't testing this stage.
|
||||
/// </summary>
|
||||
private ScenePresence AddClient()
|
||||
{
|
||||
UUID myAgentUuid = TestHelpers.ParseTail(0x1);
|
||||
UUID mySessionUuid = TestHelpers.ParseTail(0x2);
|
||||
uint myCircuitCode = 123456;
|
||||
IPEndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999);
|
||||
|
||||
uint port = 0;
|
||||
AgentCircuitManager acm = scene.AuthenticateHandler;
|
||||
|
||||
TestLLUDPServer llUdpServer
|
||||
= new TestLLUDPServer(IPAddress.Any, ref port, 0, false, new IniConfigSource(), acm);
|
||||
llUdpServer.AddScene(scene);
|
||||
|
||||
UseCircuitCodePacket uccp = new UseCircuitCodePacket();
|
||||
|
||||
UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock
|
||||
@@ -185,26 +125,67 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||
upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor.
|
||||
Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length);
|
||||
|
||||
llUdpServer.PacketReceived(upb);
|
||||
AgentCircuitData acd = new AgentCircuitData();
|
||||
acd.AgentID = myAgentUuid;
|
||||
acd.SessionID = mySessionUuid;
|
||||
|
||||
m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd);
|
||||
|
||||
m_udpServer.PacketReceived(upb);
|
||||
|
||||
return m_scene.GetScenePresence(myAgentUuid);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test adding a client to the stack
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestAddClient()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// XmlConfigurator.Configure();
|
||||
|
||||
AddUdpServer();
|
||||
|
||||
UUID myAgentUuid = TestHelpers.ParseTail(0x1);
|
||||
UUID mySessionUuid = TestHelpers.ParseTail(0x2);
|
||||
uint myCircuitCode = 123456;
|
||||
IPEndPoint testEp = new IPEndPoint(IPAddress.Loopback, 999);
|
||||
|
||||
UseCircuitCodePacket uccp = new UseCircuitCodePacket();
|
||||
|
||||
UseCircuitCodePacket.CircuitCodeBlock uccpCcBlock
|
||||
= new UseCircuitCodePacket.CircuitCodeBlock();
|
||||
uccpCcBlock.Code = myCircuitCode;
|
||||
uccpCcBlock.ID = myAgentUuid;
|
||||
uccpCcBlock.SessionID = mySessionUuid;
|
||||
uccp.CircuitCode = uccpCcBlock;
|
||||
|
||||
byte[] uccpBytes = uccp.ToBytes();
|
||||
UDPPacketBuffer upb = new UDPPacketBuffer(testEp, uccpBytes.Length);
|
||||
upb.DataLength = uccpBytes.Length; // God knows why this isn't set by the constructor.
|
||||
Buffer.BlockCopy(uccpBytes, 0, upb.Data, 0, uccpBytes.Length);
|
||||
|
||||
m_udpServer.PacketReceived(upb);
|
||||
|
||||
// Presence shouldn't exist since the circuit manager doesn't know about this circuit for authentication yet
|
||||
Assert.That(scene.GetScenePresence(myAgentUuid), Is.Null);
|
||||
Assert.That(m_scene.GetScenePresence(myAgentUuid), Is.Null);
|
||||
|
||||
AgentCircuitData acd = new AgentCircuitData();
|
||||
acd.AgentID = myAgentUuid;
|
||||
acd.SessionID = mySessionUuid;
|
||||
|
||||
acm.AddNewCircuit(myCircuitCode, acd);
|
||||
m_scene.AuthenticateHandler.AddNewCircuit(myCircuitCode, acd);
|
||||
|
||||
llUdpServer.PacketReceived(upb);
|
||||
m_udpServer.PacketReceived(upb);
|
||||
|
||||
// Should succeed now
|
||||
ScenePresence sp = scene.GetScenePresence(myAgentUuid);
|
||||
ScenePresence sp = m_scene.GetScenePresence(myAgentUuid);
|
||||
Assert.That(sp.UUID, Is.EqualTo(myAgentUuid));
|
||||
|
||||
Assert.That(llUdpServer.PacketsSent.Count, Is.EqualTo(1));
|
||||
Assert.That(m_udpServer.PacketsSent.Count, Is.EqualTo(1));
|
||||
|
||||
Packet packet = llUdpServer.PacketsSent[0];
|
||||
Packet packet = m_udpServer.PacketsSent[0];
|
||||
Assert.That(packet, Is.InstanceOf(typeof(PacketAckPacket)));
|
||||
|
||||
PacketAckPacket ackPacket = packet as PacketAckPacket;
|
||||
@@ -212,6 +193,26 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||
Assert.That(ackPacket.Packets[0].ID, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLogoutClientDueToAck()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
IniConfigSource ics = new IniConfigSource();
|
||||
IConfig config = ics.AddConfig("ClientStack.LindenUDP");
|
||||
config.Set("AckTimeout", -1);
|
||||
AddUdpServer(ics);
|
||||
|
||||
ScenePresence sp = AddClient();
|
||||
m_udpServer.ClientOutgoingPacketHandler(sp.ControllingClient, true, false, false);
|
||||
|
||||
ScenePresence spAfterAckTimeout = m_scene.GetScenePresence(sp.UUID);
|
||||
Assert.That(spAfterAckTimeout, Is.Null);
|
||||
|
||||
// TestHelpers.DisableLogging();
|
||||
}
|
||||
|
||||
// /// <summary>
|
||||
// /// Test removing a client from the stack
|
||||
// /// </summary>
|
||||
|
||||
@@ -79,7 +79,8 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||
|
||||
J2KDecoderModule j2kdm = new J2KDecoderModule();
|
||||
|
||||
scene = SceneHelpers.SetupScene();
|
||||
SceneHelpers sceneHelpers = new SceneHelpers();
|
||||
scene = sceneHelpers.SetupScene();
|
||||
SceneHelpers.SetupSceneModules(scene, j2kdm);
|
||||
|
||||
tc = new TestClient(SceneHelpers.GenerateAgentData(userId), scene);
|
||||
|
||||
@@ -44,13 +44,12 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||
}
|
||||
protected int m_objectNameCallsReceived;
|
||||
|
||||
public MockScene()
|
||||
public MockScene() : base(new RegionInfo(1000, 1000, null, null))
|
||||
{
|
||||
m_regInfo = new RegionInfo(1000, 1000, null, null);
|
||||
m_regStatus = RegionStatus.Up;
|
||||
}
|
||||
|
||||
public override void Update() {}
|
||||
public override void Update(int frames) {}
|
||||
public override void LoadWorldMap() {}
|
||||
|
||||
public override ISceneAgent AddNewClient(IClientAPI client, PresenceType type)
|
||||
|
||||
@@ -59,6 +59,15 @@ namespace OpenSim.Region.ClientStack.LindenUDP.Tests
|
||||
PacketsSent.Add(packet);
|
||||
}
|
||||
|
||||
public void ClientOutgoingPacketHandler(IClientAPI client, bool resendUnacked, bool sendAcks, bool sendPing)
|
||||
{
|
||||
m_resendUnacked = resendUnacked;
|
||||
m_sendAcks = sendAcks;
|
||||
m_sendPing = sendPing;
|
||||
|
||||
ClientOutgoingPacketHandler(client);
|
||||
}
|
||||
|
||||
//// /// <summary>
|
||||
//// /// The chunks of data to pass to the LLUDPServer when it calls EndReceive
|
||||
//// /// </summary>
|
||||
|
||||
@@ -94,24 +94,21 @@ namespace OpenSim.Region.ClientStack
|
||||
m_log.InfoFormat("[REGION SERVER]: Starting HTTP server on port {0}", m_httpServerPort);
|
||||
m_httpServer.Start();
|
||||
|
||||
MainServer.AddHttpServer(m_httpServer);
|
||||
MainServer.Instance = m_httpServer;
|
||||
|
||||
// "OOB" Server
|
||||
if (m_networkServersInfo.ssl_listener)
|
||||
{
|
||||
BaseHttpServer server = null;
|
||||
server = new BaseHttpServer(
|
||||
BaseHttpServer server = new BaseHttpServer(
|
||||
m_networkServersInfo.https_port, m_networkServersInfo.ssl_listener, m_networkServersInfo.cert_path,
|
||||
m_networkServersInfo.cert_pass);
|
||||
// Add the server to m_Servers
|
||||
if(server != null)
|
||||
{
|
||||
m_log.InfoFormat("[REGION SERVER]: Starting HTTPS server on port {0}", server.Port);
|
||||
MainServer.AddHttpServer(server);
|
||||
server.Start();
|
||||
}
|
||||
}
|
||||
|
||||
m_log.InfoFormat("[REGION SERVER]: Starting HTTPS server on port {0}", server.Port);
|
||||
MainServer.AddHttpServer(server);
|
||||
server.Start();
|
||||
}
|
||||
|
||||
base.StartupSpecific();
|
||||
}
|
||||
|
||||
|
||||
@@ -42,8 +42,7 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
|
||||
public class AssetTransactionModule : INonSharedRegionModule,
|
||||
IAgentAssetTransactions
|
||||
{
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(
|
||||
// MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
protected Scene m_Scene;
|
||||
private bool m_dumpAssetsToFile = false;
|
||||
@@ -203,15 +202,15 @@ namespace OpenSim.Region.CoreModules.Agent.AssetTransaction
|
||||
/// and comes through this method.
|
||||
/// </summary>
|
||||
/// <param name="remoteClient"></param>
|
||||
/// <param name="part"></param>
|
||||
/// <param name="transactionID"></param>
|
||||
/// <param name="item"></param>
|
||||
public void HandleTaskItemUpdateFromTransaction(IClientAPI remoteClient,
|
||||
SceneObjectPart part, UUID transactionID,
|
||||
TaskInventoryItem item)
|
||||
public void HandleTaskItemUpdateFromTransaction(
|
||||
IClientAPI remoteClient, SceneObjectPart part, UUID transactionID, TaskInventoryItem item)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[TRANSACTIONS MANAGER] Called HandleTaskItemUpdateFromTransaction with item {0}",
|
||||
// item.Name);
|
||||
m_log.DebugFormat(
|
||||
"[TRANSACTIONS MANAGER] Called HandleTaskItemUpdateFromTransaction with item {0} in {1} for {2} in {3}",
|
||||
item.Name, part.Name, remoteClient.Name, m_Scene.RegionInfo.RegionName);
|
||||
|
||||
AgentAssetTransactions transactions =
|
||||
GetUserTransactions(remoteClient.AgentId);
|
||||
|
||||
@@ -143,7 +143,7 @@ namespace Flotsam.RegionModules.AssetCache
|
||||
IConfig assetConfig = source.Configs["AssetCache"];
|
||||
if (assetConfig == null)
|
||||
{
|
||||
m_log.Warn(
|
||||
m_log.Debug(
|
||||
"[FLOTSAM ASSET CACHE]: AssetCache section missing from config (not copied config-include/FlotsamCache.ini.example? Using defaults.");
|
||||
}
|
||||
else
|
||||
@@ -203,10 +203,10 @@ namespace Flotsam.RegionModules.AssetCache
|
||||
m_CacheDirectoryTierLen = 4;
|
||||
}
|
||||
|
||||
MainConsole.Instance.Commands.AddCommand(Name, true, "fcache status", "fcache status", "Display cache status", HandleConsoleCommand);
|
||||
MainConsole.Instance.Commands.AddCommand(Name, true, "fcache clear", "fcache clear [file] [memory]", "Remove all assets in the cache. If file or memory is specified then only this cache is cleared.", HandleConsoleCommand);
|
||||
MainConsole.Instance.Commands.AddCommand(Name, true, "fcache assets", "fcache assets", "Attempt a deep scan and cache of all assets in all scenes", HandleConsoleCommand);
|
||||
MainConsole.Instance.Commands.AddCommand(Name, true, "fcache expire", "fcache expire <datetime>", "Purge cached assets older then the specified date/time", HandleConsoleCommand);
|
||||
MainConsole.Instance.Commands.AddCommand("Assets", true, "fcache status", "fcache status", "Display cache status", HandleConsoleCommand);
|
||||
MainConsole.Instance.Commands.AddCommand("Assets", true, "fcache clear", "fcache clear [file] [memory]", "Remove all assets in the cache. If file or memory is specified then only this cache is cleared.", HandleConsoleCommand);
|
||||
MainConsole.Instance.Commands.AddCommand("Assets", true, "fcache assets", "fcache assets", "Attempt a deep scan and cache of all assets in all scenes", HandleConsoleCommand);
|
||||
MainConsole.Instance.Commands.AddCommand("Assets", true, "fcache expire", "fcache expire <datetime>", "Purge cached assets older then the specified date/time", HandleConsoleCommand);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@ namespace OpenSim.Region.CoreModules.Asset.Tests
|
||||
config.Configs["AssetCache"].Set("MemoryCacheEnabled", "true");
|
||||
|
||||
m_cache = new FlotsamAssetCache();
|
||||
m_scene = SceneHelpers.SetupScene();
|
||||
m_scene = new SceneHelpers().SetupScene();
|
||||
SceneHelpers.SetupSceneModules(m_scene, config, m_cache);
|
||||
}
|
||||
|
||||
|
||||
@@ -49,6 +49,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
|
||||
private Scene m_scene;
|
||||
private IDialogModule m_dialogModule;
|
||||
private IInventoryAccessModule m_invAccessModule;
|
||||
|
||||
/// <summary>
|
||||
/// Are attachments enabled?
|
||||
@@ -70,7 +71,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
public void AddRegion(Scene scene)
|
||||
{
|
||||
m_scene = scene;
|
||||
m_dialogModule = m_scene.RequestModuleInterface<IDialogModule>();
|
||||
m_scene.RegisterModuleInterface<IAttachmentsModule>(this);
|
||||
|
||||
if (Enabled)
|
||||
@@ -87,7 +87,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
m_scene.EventManager.OnNewClient -= SubscribeToClientEvents;
|
||||
}
|
||||
|
||||
public void RegionLoaded(Scene scene) {}
|
||||
public void RegionLoaded(Scene scene)
|
||||
{
|
||||
m_dialogModule = m_scene.RequestModuleInterface<IDialogModule>();
|
||||
m_invAccessModule = m_scene.RequestModuleInterface<IInventoryAccessModule>();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
@@ -98,6 +102,56 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
|
||||
#region IAttachmentsModule
|
||||
|
||||
public void CopyAttachments(IScenePresence sp, AgentData ad)
|
||||
{
|
||||
lock (sp.AttachmentsSyncLock)
|
||||
{
|
||||
// Attachment objects
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments();
|
||||
if (attachments.Count > 0)
|
||||
{
|
||||
ad.AttachmentObjects = new List<ISceneObject>();
|
||||
ad.AttachmentObjectStates = new List<string>();
|
||||
// IScriptModule se = m_scene.RequestModuleInterface<IScriptModule>();
|
||||
sp.InTransitScriptStates.Clear();
|
||||
|
||||
foreach (SceneObjectGroup sog in attachments)
|
||||
{
|
||||
// We need to make a copy and pass that copy
|
||||
// because of transfers withn the same sim
|
||||
ISceneObject clone = sog.CloneForNewScene();
|
||||
// Attachment module assumes that GroupPosition holds the offsets...!
|
||||
((SceneObjectGroup)clone).RootPart.GroupPosition = sog.RootPart.AttachedPos;
|
||||
((SceneObjectGroup)clone).IsAttachment = false;
|
||||
ad.AttachmentObjects.Add(clone);
|
||||
string state = sog.GetStateSnapshot();
|
||||
ad.AttachmentObjectStates.Add(state);
|
||||
sp.InTransitScriptStates.Add(state);
|
||||
// Let's remove the scripts of the original object here
|
||||
sog.RemoveScriptInstances(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CopyAttachments(AgentData ad, IScenePresence sp)
|
||||
{
|
||||
if (ad.AttachmentObjects != null && ad.AttachmentObjects.Count > 0)
|
||||
{
|
||||
lock (sp.AttachmentsSyncLock)
|
||||
sp.ClearAttachments();
|
||||
|
||||
int i = 0;
|
||||
foreach (ISceneObject so in ad.AttachmentObjects)
|
||||
{
|
||||
((SceneObjectGroup)so).LocalId = 0;
|
||||
((SceneObjectGroup)so).RootPart.ClearUpdateSchedule();
|
||||
so.SetState(ad.AttachmentObjectStates[i++], m_scene);
|
||||
m_scene.IncomingCreateObject(Vector3.Zero, so);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RezAttachments. This should only be called upon login on the first region.
|
||||
/// Attachment rezzings on crossings and TPs are done in a different way.
|
||||
@@ -148,31 +202,44 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
}
|
||||
}
|
||||
|
||||
public void SaveChangedAttachments(IScenePresence sp, bool saveAllScripted)
|
||||
public void DeRezAttachments(IScenePresence sp, bool saveChanged, bool saveAllScripted)
|
||||
{
|
||||
// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name);
|
||||
|
||||
if (!Enabled)
|
||||
return;
|
||||
|
||||
foreach (SceneObjectGroup grp in sp.GetAttachments())
|
||||
// m_log.DebugFormat("[ATTACHMENTS MODULE]: Saving changed attachments for {0}", sp.Name);
|
||||
|
||||
lock (sp.AttachmentsSyncLock)
|
||||
{
|
||||
grp.IsAttachment = false;
|
||||
grp.AbsolutePosition = grp.RootPart.AttachedPos;
|
||||
UpdateKnownItem(sp, grp, saveAllScripted);
|
||||
grp.IsAttachment = true;
|
||||
foreach (SceneObjectGroup so in sp.GetAttachments())
|
||||
{
|
||||
// We can only remove the script instances from the script engine after we've retrieved their xml state
|
||||
// when we update the attachment item.
|
||||
m_scene.DeleteSceneObject(so, false, false);
|
||||
|
||||
if (saveChanged || saveAllScripted)
|
||||
{
|
||||
so.IsAttachment = false;
|
||||
so.AbsolutePosition = so.RootPart.AttachedPos;
|
||||
UpdateKnownItem(sp, so, saveAllScripted);
|
||||
}
|
||||
|
||||
so.RemoveScriptInstances(true);
|
||||
}
|
||||
|
||||
sp.ClearAttachments();
|
||||
}
|
||||
}
|
||||
|
||||
public void DeleteAttachmentsFromScene(IScenePresence sp, bool silent)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}",
|
||||
// m_scene.RegionInfo.RegionName, sp.Name, silent);
|
||||
|
||||
if (!Enabled)
|
||||
return;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[ATTACHMENTS MODULE]: Deleting attachments from scene {0} for {1}, silent = {2}",
|
||||
// m_scene.RegionInfo.RegionName, sp.Name, silent);
|
||||
|
||||
foreach (SceneObjectGroup sop in sp.GetAttachments())
|
||||
{
|
||||
sop.Scene.DeleteSceneObject(sop, silent);
|
||||
@@ -188,6 +255,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
// m_log.DebugFormat(
|
||||
// "[ATTACHMENTS MODULE]: Attaching object {0} {1} to {2} point {3} from ground (silent = {4})",
|
||||
// group.Name, group.LocalId, sp.Name, attachmentPt, silent);
|
||||
|
||||
if (group.GetSittingAvatarsCount() != 0)
|
||||
{
|
||||
// m_log.WarnFormat(
|
||||
// "[ATTACHMENTS MODULE]: Ignoring request to attach {0} {1} to {2} on {3} since {4} avatars are still sitting on it",
|
||||
// group.Name, group.LocalId, sp.Name, attachmentPt, group.GetSittingAvatarsCount());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sp.GetAttachments(attachmentPt).Contains(group))
|
||||
{
|
||||
@@ -229,33 +305,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
|
||||
group.AttachmentPoint = attachmentPt;
|
||||
group.AbsolutePosition = attachPos;
|
||||
|
||||
// We also don't want to do any of the inventory operations for an NPC.
|
||||
|
||||
if (sp.PresenceType != PresenceType.Npc)
|
||||
{
|
||||
// Remove any previous attachments
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
|
||||
|
||||
// At the moment we can only deal with a single attachment
|
||||
if (attachments.Count != 0)
|
||||
{
|
||||
UUID oldAttachmentItemID = attachments[0].GetFromItemID();
|
||||
|
||||
if (oldAttachmentItemID != UUID.Zero)
|
||||
DetachSingleAttachmentToInvInternal(sp, oldAttachmentItemID);
|
||||
else
|
||||
m_log.WarnFormat(
|
||||
"[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!",
|
||||
attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name);
|
||||
}
|
||||
|
||||
// Add the new attachment to inventory if we don't already have it.
|
||||
UUID newAttachmentItemID = group.GetFromItemID();
|
||||
if (newAttachmentItemID == UUID.Zero)
|
||||
newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID;
|
||||
|
||||
ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group);
|
||||
}
|
||||
UpdateUserInventoryWithAttachment(sp, group, attachmentPt);
|
||||
|
||||
AttachToAgent(sp, group, attachmentPt, attachPos, silent);
|
||||
}
|
||||
@@ -263,7 +315,31 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
return true;
|
||||
}
|
||||
|
||||
public ISceneEntity RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt)
|
||||
private void UpdateUserInventoryWithAttachment(IScenePresence sp, SceneObjectGroup group, uint attachmentPt)
|
||||
{
|
||||
// Remove any previous attachments
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments(attachmentPt);
|
||||
|
||||
// At the moment we can only deal with a single attachment
|
||||
if (attachments.Count != 0)
|
||||
{
|
||||
if (attachments[0].FromItemID != UUID.Zero)
|
||||
DetachSingleAttachmentToInvInternal(sp, attachments[0]);
|
||||
else
|
||||
m_log.WarnFormat(
|
||||
"[ATTACHMENTS MODULE]: When detaching existing attachment {0} {1} at point {2} to make way for {3} {4} for {5}, couldn't find the associated item ID to adjust inventory attachment record!",
|
||||
attachments[0].Name, attachments[0].LocalId, attachmentPt, group.Name, group.LocalId, sp.Name);
|
||||
}
|
||||
|
||||
// Add the new attachment to inventory if we don't already have it.
|
||||
UUID newAttachmentItemID = group.FromItemID;
|
||||
if (newAttachmentItemID == UUID.Zero)
|
||||
newAttachmentItemID = AddSceneObjectAsNewAttachmentInInv(sp, group).ID;
|
||||
|
||||
ShowAttachInUserInventory(sp, attachmentPt, newAttachmentItemID, group);
|
||||
}
|
||||
|
||||
public SceneObjectGroup RezSingleAttachmentFromInventory(IScenePresence sp, UUID itemID, uint AttachmentPt)
|
||||
{
|
||||
if (!Enabled)
|
||||
return null;
|
||||
@@ -285,7 +361,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
List<SceneObjectGroup> existingAttachments = sp.GetAttachments();
|
||||
foreach (SceneObjectGroup so in existingAttachments)
|
||||
{
|
||||
if (so.GetFromItemID() == itemID)
|
||||
if (so.FromItemID == itemID)
|
||||
{
|
||||
alreadyOn = true;
|
||||
break;
|
||||
@@ -302,12 +378,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
return null;
|
||||
}
|
||||
|
||||
SceneObjectGroup att = RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt);
|
||||
|
||||
if (att == null)
|
||||
DetachSingleAttachmentToInv(sp, itemID);
|
||||
|
||||
return att;
|
||||
return RezSingleAttachmentFromInventoryInternal(sp, itemID, UUID.Zero, AttachmentPt);
|
||||
}
|
||||
|
||||
public void RezMultipleAttachmentsFromInventory(IScenePresence sp, List<KeyValuePair<UUID, uint>> rezlist)
|
||||
@@ -342,7 +413,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
if (so.AttachedAvatar != sp.UUID)
|
||||
return;
|
||||
|
||||
UUID inventoryID = so.GetFromItemID();
|
||||
UUID inventoryID = so.FromItemID;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[ATTACHMENTS MODULE]: In DetachSingleAttachmentToGround(), object is {0} {1}, associated item is {2}",
|
||||
@@ -359,9 +430,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
|
||||
|
||||
sp.RemoveAttachment(so);
|
||||
so.FromItemID = UUID.Zero;
|
||||
|
||||
SceneObjectPart rootPart = so.RootPart;
|
||||
rootPart.FromItemID = UUID.Zero;
|
||||
so.AbsolutePosition = sp.AbsolutePosition;
|
||||
so.AttachedAvatar = UUID.Zero;
|
||||
rootPart.SetParentLocalId(0);
|
||||
@@ -384,18 +455,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
m_scene.EventManager.TriggerOnAttach(so.LocalId, so.UUID, UUID.Zero);
|
||||
}
|
||||
|
||||
public void DetachSingleAttachmentToInv(IScenePresence sp, UUID itemID)
|
||||
public void DetachSingleAttachmentToInv(IScenePresence sp, SceneObjectGroup so)
|
||||
{
|
||||
lock (sp.AttachmentsSyncLock)
|
||||
{
|
||||
// Save avatar attachment information
|
||||
m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID);
|
||||
// m_log.Debug("[ATTACHMENTS MODULE]: Detaching from UserID: " + sp.UUID + ", ItemID: " + itemID);
|
||||
|
||||
bool changed = sp.Appearance.DetachAttachment(itemID);
|
||||
if (so.AttachedAvatar != sp.UUID)
|
||||
{
|
||||
m_log.WarnFormat(
|
||||
"[ATTACHMENTS MODULE]: Tried to detach object {0} from {1} {2} but attached avatar id was {3} in {4}",
|
||||
so.Name, sp.Name, sp.UUID, so.AttachedAvatar, m_scene.RegionInfo.RegionName);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
bool changed = sp.Appearance.DetachAttachment(so.FromItemID);
|
||||
if (changed && m_scene.AvatarFactory != null)
|
||||
m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
|
||||
|
||||
DetachSingleAttachmentToInvInternal(sp, itemID);
|
||||
DetachSingleAttachmentToInvInternal(sp, so);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -404,17 +484,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
if (!Enabled)
|
||||
return;
|
||||
|
||||
// First we save the
|
||||
// attachment point information, then we update the relative
|
||||
// positioning. Then we have to mark the object as NOT an
|
||||
// attachment. This is necessary in order to correctly save
|
||||
// and retrieve GroupPosition information for the attachment.
|
||||
// Finally, we restore the object's attachment status.
|
||||
uint attachmentPoint = sog.AttachmentPoint;
|
||||
sog.UpdateGroupPosition(pos);
|
||||
sog.IsAttachment = false;
|
||||
sog.AbsolutePosition = sog.RootPart.AttachedPos;
|
||||
sog.AttachmentPoint = attachmentPoint;
|
||||
sog.HasGroupChanged = true;
|
||||
}
|
||||
|
||||
@@ -457,6 +527,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
/// </remarks>
|
||||
/// <param name="sp"></param>
|
||||
/// <param name="grp"></param>
|
||||
/// <param name="saveAllScripted"></param>
|
||||
private void UpdateKnownItem(IScenePresence sp, SceneObjectGroup grp, bool saveAllScripted)
|
||||
{
|
||||
// Saving attachments for NPCs messes them up for the real owner!
|
||||
@@ -469,13 +540,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
|
||||
if (grp.HasGroupChanged || (saveAllScripted && grp.ContainsScripts()))
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}",
|
||||
grp.UUID, grp.AttachmentPoint);
|
||||
// m_log.DebugFormat(
|
||||
// "[ATTACHMENTS MODULE]: Updating asset for attachment {0}, attachpoint {1}",
|
||||
// grp.UUID, grp.AttachmentPoint);
|
||||
|
||||
string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp);
|
||||
|
||||
InventoryItemBase item = new InventoryItemBase(grp.GetFromItemID(), sp.UUID);
|
||||
InventoryItemBase item = new InventoryItemBase(grp.FromItemID, sp.UUID);
|
||||
item = m_scene.InventoryService.GetItem(item);
|
||||
|
||||
if (item != null)
|
||||
@@ -502,12 +573,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
}
|
||||
grp.HasGroupChanged = false; // Prevent it being saved over and over
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}",
|
||||
grp.UUID, grp.AttachmentPoint);
|
||||
}
|
||||
// else
|
||||
// {
|
||||
// m_log.DebugFormat(
|
||||
// "[ATTACHMENTS MODULE]: Don't need to update asset for unchanged attachment {0}, attachpoint {1}",
|
||||
// grp.UUID, grp.AttachmentPoint);
|
||||
// }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -558,6 +629,20 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
{
|
||||
m_scene.SendKillObject(new List<uint> { so.RootPart.LocalId });
|
||||
}
|
||||
else if (so.HasPrivateAttachmentPoint)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[ATTACHMENTS MODULE]: Killing private HUD {0} for avatars other than {1} at attachment point {2}",
|
||||
// so.Name, sp.Name, so.AttachmentPoint);
|
||||
|
||||
// As this scene object can now only be seen by the attaching avatar, tell everybody else in the
|
||||
// scene that it's no longer in their awareness.
|
||||
m_scene.ForEachClient(
|
||||
client =>
|
||||
{ if (client.AgentId != so.AttachedAvatar)
|
||||
client.SendKillObject(m_scene.RegionInfo.RegionHandle, new List<uint>() { so.LocalId });
|
||||
});
|
||||
}
|
||||
|
||||
so.IsSelected = false; // fudge....
|
||||
so.ScheduleGroupForFullUpdate();
|
||||
@@ -576,201 +661,118 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
/// <returns>The user inventory item created that holds the attachment.</returns>
|
||||
private InventoryItemBase AddSceneObjectAsNewAttachmentInInv(IScenePresence sp, SceneObjectGroup grp)
|
||||
{
|
||||
if (m_invAccessModule == null)
|
||||
return null;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[ATTACHMENTS MODULE]: Called AddSceneObjectAsAttachment for object {0} {1} for {2}",
|
||||
// grp.Name, grp.LocalId, remoteClient.Name);
|
||||
|
||||
Vector3 inventoryStoredPosition = new Vector3
|
||||
(((grp.AbsolutePosition.X > (int)Constants.RegionSize)
|
||||
? Constants.RegionSize - 6
|
||||
: grp.AbsolutePosition.X)
|
||||
,
|
||||
(grp.AbsolutePosition.Y > (int)Constants.RegionSize)
|
||||
? Constants.RegionSize - 6
|
||||
: grp.AbsolutePosition.Y,
|
||||
grp.AbsolutePosition.Z);
|
||||
|
||||
Vector3 originalPosition = grp.AbsolutePosition;
|
||||
|
||||
grp.AbsolutePosition = inventoryStoredPosition;
|
||||
|
||||
// If we're being called from a script, then trying to serialize that same script's state will not complete
|
||||
// in any reasonable time period. Therefore, we'll avoid it. The worst that can happen is that if
|
||||
// the client/server crashes rather than logging out normally, the attachment's scripts will resume
|
||||
// without state on relog. Arguably, this is what we want anyway.
|
||||
string sceneObjectXml = SceneObjectSerializer.ToOriginalXmlFormat(grp, false);
|
||||
|
||||
grp.AbsolutePosition = originalPosition;
|
||||
|
||||
AssetBase asset = m_scene.CreateAsset(
|
||||
grp.GetPartName(grp.LocalId),
|
||||
grp.GetPartDescription(grp.LocalId),
|
||||
(sbyte)AssetType.Object,
|
||||
Utils.StringToBytes(sceneObjectXml),
|
||||
sp.UUID);
|
||||
|
||||
m_scene.AssetService.Store(asset);
|
||||
|
||||
InventoryItemBase item = new InventoryItemBase();
|
||||
item.CreatorId = grp.RootPart.CreatorID.ToString();
|
||||
item.CreatorData = grp.RootPart.CreatorData;
|
||||
item.Owner = sp.UUID;
|
||||
item.ID = UUID.Random();
|
||||
item.AssetID = asset.FullID;
|
||||
item.Description = asset.Description;
|
||||
item.Name = asset.Name;
|
||||
item.AssetType = asset.Type;
|
||||
item.InvType = (int)InventoryType.Object;
|
||||
|
||||
InventoryFolderBase folder = m_scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object);
|
||||
if (folder != null)
|
||||
item.Folder = folder.ID;
|
||||
else // oopsies
|
||||
item.Folder = UUID.Zero;
|
||||
|
||||
if ((sp.UUID != grp.RootPart.OwnerID) && m_scene.Permissions.PropagatePermissions())
|
||||
{
|
||||
item.BasePermissions = grp.RootPart.NextOwnerMask;
|
||||
item.CurrentPermissions = grp.RootPart.NextOwnerMask;
|
||||
item.NextPermissions = grp.RootPart.NextOwnerMask;
|
||||
item.EveryOnePermissions = grp.RootPart.EveryoneMask & grp.RootPart.NextOwnerMask;
|
||||
item.GroupPermissions = grp.RootPart.GroupMask & grp.RootPart.NextOwnerMask;
|
||||
}
|
||||
else
|
||||
{
|
||||
item.BasePermissions = grp.RootPart.BaseMask;
|
||||
item.CurrentPermissions = grp.RootPart.OwnerMask;
|
||||
item.NextPermissions = grp.RootPart.NextOwnerMask;
|
||||
item.EveryOnePermissions = grp.RootPart.EveryoneMask;
|
||||
item.GroupPermissions = grp.RootPart.GroupMask;
|
||||
}
|
||||
item.CreationDate = Util.UnixTimeSinceEpoch();
|
||||
InventoryItemBase newItem
|
||||
= m_invAccessModule.CopyToInventory(
|
||||
DeRezAction.TakeCopy,
|
||||
m_scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object).ID,
|
||||
new List<SceneObjectGroup> { grp },
|
||||
sp.ControllingClient, true)[0];
|
||||
|
||||
// sets itemID so client can show item as 'attached' in inventory
|
||||
grp.SetFromItemID(item.ID);
|
||||
grp.FromItemID = newItem.ID;
|
||||
|
||||
if (m_scene.AddInventoryItem(item))
|
||||
{
|
||||
sp.ControllingClient.SendInventoryItemCreateUpdate(item, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_dialogModule != null)
|
||||
m_dialogModule.SendAlertToUser(sp.ControllingClient, "Operation failed");
|
||||
}
|
||||
|
||||
return item;
|
||||
return newItem;
|
||||
}
|
||||
|
||||
// What makes this method odd and unique is it tries to detach using an UUID.... Yay for standards.
|
||||
// To LocalId or UUID, *THAT* is the question. How now Brown UUID??
|
||||
private void DetachSingleAttachmentToInvInternal(IScenePresence sp, UUID itemID)
|
||||
private void DetachSingleAttachmentToInvInternal(IScenePresence sp, SceneObjectGroup so)
|
||||
{
|
||||
// m_log.DebugFormat("[ATTACHMENTS MODULE]: Detaching item {0} to inventory for {1}", itemID, sp.Name);
|
||||
|
||||
if (itemID == UUID.Zero) // If this happened, someone made a mistake....
|
||||
return;
|
||||
m_scene.EventManager.TriggerOnAttach(so.LocalId, so.FromItemID, UUID.Zero);
|
||||
sp.RemoveAttachment(so);
|
||||
|
||||
// We can NOT use the dictionries here, as we are looking
|
||||
// for an entity by the fromAssetID, which is NOT the prim UUID
|
||||
EntityBase[] detachEntities = m_scene.GetEntities();
|
||||
SceneObjectGroup group;
|
||||
// We can only remove the script instances from the script engine after we've retrieved their xml state
|
||||
// when we update the attachment item.
|
||||
m_scene.DeleteSceneObject(so, false, false);
|
||||
|
||||
lock (sp.AttachmentsSyncLock)
|
||||
{
|
||||
foreach (EntityBase entity in detachEntities)
|
||||
{
|
||||
if (entity is SceneObjectGroup)
|
||||
{
|
||||
group = (SceneObjectGroup)entity;
|
||||
if (group.GetFromItemID() == itemID)
|
||||
{
|
||||
m_scene.EventManager.TriggerOnAttach(group.LocalId, itemID, UUID.Zero);
|
||||
sp.RemoveAttachment(group);
|
||||
// Prepare sog for storage
|
||||
so.AttachedAvatar = UUID.Zero;
|
||||
so.RootPart.SetParentLocalId(0);
|
||||
so.IsAttachment = false;
|
||||
so.AbsolutePosition = so.RootPart.AttachedPos;
|
||||
|
||||
// Prepare sog for storage
|
||||
group.AttachedAvatar = UUID.Zero;
|
||||
group.RootPart.SetParentLocalId(0);
|
||||
group.IsAttachment = false;
|
||||
group.AbsolutePosition = group.RootPart.AttachedPos;
|
||||
|
||||
UpdateKnownItem(sp, group, true);
|
||||
m_scene.DeleteSceneObject(group, false);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
UpdateKnownItem(sp, so, true);
|
||||
so.RemoveScriptInstances(true);
|
||||
}
|
||||
|
||||
private SceneObjectGroup RezSingleAttachmentFromInventoryInternal(
|
||||
IScenePresence sp, UUID itemID, UUID assetID, uint attachmentPt)
|
||||
{
|
||||
IInventoryAccessModule invAccess = m_scene.RequestModuleInterface<IInventoryAccessModule>();
|
||||
if (invAccess != null)
|
||||
if (m_invAccessModule == null)
|
||||
return null;
|
||||
|
||||
lock (sp.AttachmentsSyncLock)
|
||||
{
|
||||
lock (sp.AttachmentsSyncLock)
|
||||
SceneObjectGroup objatt;
|
||||
|
||||
if (itemID != UUID.Zero)
|
||||
objatt = m_invAccessModule.RezObject(sp.ControllingClient,
|
||||
itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
|
||||
false, false, sp.UUID, true);
|
||||
else
|
||||
objatt = m_invAccessModule.RezObject(sp.ControllingClient,
|
||||
null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
|
||||
false, false, sp.UUID, true);
|
||||
|
||||
if (objatt != null)
|
||||
{
|
||||
SceneObjectGroup objatt;
|
||||
// m_log.DebugFormat(
|
||||
// "[ATTACHMENTS MODULE]: Rezzed single object {0} for attachment to {1} on point {2} in {3}",
|
||||
// objatt.Name, sp.Name, attachmentPt, m_scene.Name);
|
||||
|
||||
if (itemID != UUID.Zero)
|
||||
objatt = invAccess.RezObject(sp.ControllingClient,
|
||||
itemID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
|
||||
false, false, sp.UUID, true);
|
||||
else
|
||||
objatt = invAccess.RezObject(sp.ControllingClient,
|
||||
null, assetID, Vector3.Zero, Vector3.Zero, UUID.Zero, (byte)1, true,
|
||||
false, false, sp.UUID, true);
|
||||
// HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
|
||||
objatt.HasGroupChanged = false;
|
||||
bool tainted = false;
|
||||
if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
|
||||
tainted = true;
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[ATTACHMENTS MODULE]: Retrieved single object {0} for attachment to {1} on point {2}",
|
||||
// objatt.Name, remoteClient.Name, AttachmentPt);
|
||||
|
||||
if (objatt != null)
|
||||
// FIXME: Detect whether it's really likely for AttachObject to throw an exception in the normal
|
||||
// course of events. If not, then it's probably not worth trying to recover the situation
|
||||
// since this is more likely to trigger further exceptions and confuse later debugging. If
|
||||
// exceptions can be thrown in expected error conditions (not NREs) then make this consistent
|
||||
// since other normal error conditions will simply return false instead.
|
||||
// This will throw if the attachment fails
|
||||
try
|
||||
{
|
||||
// HasGroupChanged is being set from within RezObject. Ideally it would be set by the caller.
|
||||
objatt.HasGroupChanged = false;
|
||||
bool tainted = false;
|
||||
if (attachmentPt != 0 && attachmentPt != objatt.AttachmentPoint)
|
||||
tainted = true;
|
||||
|
||||
// This will throw if the attachment fails
|
||||
try
|
||||
{
|
||||
AttachObject(sp, objatt, attachmentPt, false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
|
||||
objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
|
||||
|
||||
// Make sure the object doesn't stick around and bail
|
||||
sp.RemoveAttachment(objatt);
|
||||
m_scene.DeleteSceneObject(objatt, false);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (tainted)
|
||||
objatt.HasGroupChanged = true;
|
||||
|
||||
// Fire after attach, so we don't get messy perms dialogs
|
||||
// 4 == AttachedRez
|
||||
objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
|
||||
objatt.ResumeScripts();
|
||||
|
||||
// Do this last so that event listeners have access to all the effects of the attachment
|
||||
m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID);
|
||||
|
||||
return objatt;
|
||||
AttachObject(sp, objatt, attachmentPt, false);
|
||||
}
|
||||
else
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.WarnFormat(
|
||||
"[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
|
||||
itemID, sp.Name, attachmentPt);
|
||||
m_log.ErrorFormat(
|
||||
"[ATTACHMENTS MODULE]: Failed to attach {0} {1} for {2}, exception {3}{4}",
|
||||
objatt.Name, objatt.UUID, sp.Name, e.Message, e.StackTrace);
|
||||
|
||||
// Make sure the object doesn't stick around and bail
|
||||
sp.RemoveAttachment(objatt);
|
||||
m_scene.DeleteSceneObject(objatt, false);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (tainted)
|
||||
objatt.HasGroupChanged = true;
|
||||
|
||||
// Fire after attach, so we don't get messy perms dialogs
|
||||
// 4 == AttachedRez
|
||||
objatt.CreateScriptInstances(0, true, m_scene.DefaultScriptEngine, 4);
|
||||
objatt.ResumeScripts();
|
||||
|
||||
// Do this last so that event listeners have access to all the effects of the attachment
|
||||
m_scene.EventManager.TriggerOnAttach(objatt.LocalId, itemID, sp.UUID);
|
||||
|
||||
return objatt;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.WarnFormat(
|
||||
"[ATTACHMENTS MODULE]: Could not retrieve item {0} for attaching to avatar {1} at point {2}",
|
||||
itemID, sp.Name, attachmentPt);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -806,7 +808,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
item = m_scene.InventoryService.GetItem(item);
|
||||
bool changed = sp.Appearance.SetAttachment((int)AttachmentPt, itemID, item.AssetID);
|
||||
if (changed && m_scene.AvatarFactory != null)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[ATTACHMENTS MODULE]: Queueing appearance save for {0}, attachment {1} point {2} in ShowAttachInUserInventory()",
|
||||
// sp.Name, att.Name, AttachmentPt);
|
||||
|
||||
m_scene.AvatarFactory.QueueAppearanceSave(sp.UUID);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -889,13 +897,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
// Calls attach with a Zero position
|
||||
if (AttachObject(sp, part.ParentGroup, AttachmentPt, false))
|
||||
{
|
||||
m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.GetFromItemID(), remoteClient.AgentId);
|
||||
// m_log.Debug(
|
||||
// "[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId
|
||||
// + ", AttachmentPoint: " + AttachmentPt);
|
||||
|
||||
// Save avatar attachment information
|
||||
m_log.Debug(
|
||||
"[ATTACHMENTS MODULE]: Saving avatar attachment. AgentID: " + remoteClient.AgentId
|
||||
+ ", AttachmentPoint: " + AttachmentPt);
|
||||
|
||||
m_scene.EventManager.TriggerOnAttach(objectLocalID, part.ParentGroup.FromItemID, remoteClient.AgentId);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -911,8 +918,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
|
||||
ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
|
||||
SceneObjectGroup group = m_scene.GetGroupByPrim(objectLocalID);
|
||||
|
||||
if (sp != null && group != null)
|
||||
DetachSingleAttachmentToInv(sp, group.GetFromItemID());
|
||||
DetachSingleAttachmentToInv(sp, group);
|
||||
}
|
||||
|
||||
private void Client_OnDetachAttachmentIntoInv(UUID itemID, IClientAPI remoteClient)
|
||||
@@ -922,7 +930,21 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments
|
||||
|
||||
ScenePresence sp = m_scene.GetScenePresence(remoteClient.AgentId);
|
||||
if (sp != null)
|
||||
DetachSingleAttachmentToInv(sp, itemID);
|
||||
{
|
||||
lock (sp.AttachmentsSyncLock)
|
||||
{
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments();
|
||||
|
||||
foreach (SceneObjectGroup group in attachments)
|
||||
{
|
||||
if (group.FromItemID == itemID)
|
||||
{
|
||||
DetachSingleAttachmentToInv(sp, group);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Client_OnObjectDrop(uint soLocalId, IClientAPI remoteClient)
|
||||
|
||||
@@ -31,6 +31,7 @@ using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Timers;
|
||||
using System.Xml;
|
||||
using Timer=System.Timers.Timer;
|
||||
using Nini.Config;
|
||||
using NUnit.Framework;
|
||||
@@ -38,11 +39,16 @@ using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Communications;
|
||||
using OpenSim.Region.CoreModules.Avatar.Attachments;
|
||||
using OpenSim.Region.CoreModules.Framework;
|
||||
using OpenSim.Region.CoreModules.Framework.EntityTransfer;
|
||||
using OpenSim.Region.CoreModules.Framework.InventoryAccess;
|
||||
using OpenSim.Region.CoreModules.World.Serialiser;
|
||||
using OpenSim.Region.CoreModules.Scripting.WorldComm;
|
||||
using OpenSim.Region.CoreModules.ServiceConnectorsOut.Simulation;
|
||||
using OpenSim.Region.CoreModules.World.Serialiser;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.ScriptEngine.XEngine;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using OpenSim.Tests.Common;
|
||||
using OpenSim.Tests.Common.Mock;
|
||||
|
||||
@@ -52,11 +58,10 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
/// Attachment tests
|
||||
/// </summary>
|
||||
[TestFixture]
|
||||
public class AttachmentsModuleTests
|
||||
public class AttachmentsModuleTests : OpenSimTestCase
|
||||
{
|
||||
private Scene scene;
|
||||
private AttachmentsModule m_attMod;
|
||||
private ScenePresence m_presence;
|
||||
private AutoResetEvent m_chatEvent = new AutoResetEvent(false);
|
||||
private OSChatMessage m_osChatMessageReceived;
|
||||
|
||||
[TestFixtureSetUp]
|
||||
public void FixtureInit()
|
||||
@@ -65,18 +70,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
Util.FireAndForgetMethod = FireAndForgetMethod.None;
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void Init()
|
||||
{
|
||||
IConfigSource config = new IniConfigSource();
|
||||
config.AddConfig("Modules");
|
||||
config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule");
|
||||
|
||||
scene = SceneHelpers.SetupScene();
|
||||
m_attMod = new AttachmentsModule();
|
||||
SceneHelpers.SetupSceneModules(scene, config, m_attMod, new BasicInventoryAccessModule());
|
||||
}
|
||||
|
||||
[TestFixtureTearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
@@ -85,32 +78,121 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add the standard presence for a test.
|
||||
/// </summary>
|
||||
private void AddPresence()
|
||||
private void OnChatFromWorld(object sender, OSChatMessage oscm)
|
||||
{
|
||||
UUID userId = TestHelpers.ParseTail(0x1);
|
||||
UserAccountHelpers.CreateUserWithInventory(scene, userId);
|
||||
m_presence = SceneHelpers.AddScenePresence(scene, userId);
|
||||
// Console.WriteLine("Got chat [{0}]", oscm.Message);
|
||||
|
||||
m_osChatMessageReceived = oscm;
|
||||
m_chatEvent.Set();
|
||||
}
|
||||
|
||||
private Scene CreateTestScene()
|
||||
{
|
||||
IConfigSource config = new IniConfigSource();
|
||||
List<object> modules = new List<object>();
|
||||
|
||||
AddCommonConfig(config, modules);
|
||||
|
||||
Scene scene
|
||||
= new SceneHelpers().SetupScene(
|
||||
"attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config);
|
||||
SceneHelpers.SetupSceneModules(scene, config, modules.ToArray());
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
private Scene CreateScriptingEnabledTestScene()
|
||||
{
|
||||
IConfigSource config = new IniConfigSource();
|
||||
List<object> modules = new List<object>();
|
||||
|
||||
AddCommonConfig(config, modules);
|
||||
AddScriptingConfig(config, modules);
|
||||
|
||||
Scene scene
|
||||
= new SceneHelpers().SetupScene(
|
||||
"attachments-test-scene", TestHelpers.ParseTail(999), 1000, 1000, config);
|
||||
SceneHelpers.SetupSceneModules(scene, config, modules.ToArray());
|
||||
|
||||
scene.StartScripts();
|
||||
|
||||
return scene;
|
||||
}
|
||||
|
||||
private void AddCommonConfig(IConfigSource config, List<object> modules)
|
||||
{
|
||||
config.AddConfig("Modules");
|
||||
config.Configs["Modules"].Set("InventoryAccessModule", "BasicInventoryAccessModule");
|
||||
|
||||
modules.Add(new AttachmentsModule());
|
||||
modules.Add(new BasicInventoryAccessModule());
|
||||
}
|
||||
|
||||
private void AddScriptingConfig(IConfigSource config, List<object> modules)
|
||||
{
|
||||
IConfig startupConfig = config.AddConfig("Startup");
|
||||
startupConfig.Set("DefaultScriptEngine", "XEngine");
|
||||
|
||||
IConfig xEngineConfig = config.AddConfig("XEngine");
|
||||
xEngineConfig.Set("Enabled", "true");
|
||||
xEngineConfig.Set("StartDelay", "0");
|
||||
|
||||
// These tests will not run with AppDomainLoading = true, at least on mono. For unknown reasons, the call
|
||||
// to AssemblyResolver.OnAssemblyResolve fails.
|
||||
xEngineConfig.Set("AppDomainLoading", "false");
|
||||
|
||||
modules.Add(new XEngine());
|
||||
|
||||
// Necessary to stop serialization complaining
|
||||
// FIXME: Stop this being necessary if at all possible
|
||||
// modules.Add(new WorldCommModule());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates an attachment item in the given user's inventory. Does not attach.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// A user with the given ID and an inventory must already exist.
|
||||
/// </remarks>
|
||||
/// <returns>
|
||||
/// The attachment item.
|
||||
/// </returns>
|
||||
/// <param name='scene'></param>
|
||||
/// <param name='userId'></param>
|
||||
/// <param name='attName'></param>
|
||||
/// <param name='rawItemId'></param>
|
||||
/// <param name='rawAssetId'></param>
|
||||
private InventoryItemBase CreateAttachmentItem(
|
||||
Scene scene, UUID userId, string attName, int rawItemId, int rawAssetId)
|
||||
{
|
||||
return UserInventoryHelpers.CreateInventoryItem(
|
||||
scene,
|
||||
attName,
|
||||
TestHelpers.ParseTail(rawItemId),
|
||||
TestHelpers.ParseTail(rawAssetId),
|
||||
userId,
|
||||
InventoryType.Object);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddAttachmentFromGround()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
Scene scene = CreateTestScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
||||
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
|
||||
|
||||
AddPresence();
|
||||
string attName = "att";
|
||||
|
||||
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName).ParentGroup;
|
||||
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID);
|
||||
|
||||
m_attMod.AttachObject(m_presence, so, (uint)AttachmentPoint.Chest, false);
|
||||
scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false);
|
||||
|
||||
// Check status on scene presence
|
||||
Assert.That(m_presence.HasAttachments(), Is.True);
|
||||
List<SceneObjectGroup> attachments = m_presence.GetAttachments();
|
||||
Assert.That(sp.HasAttachments(), Is.True);
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments();
|
||||
Assert.That(attachments.Count, Is.EqualTo(1));
|
||||
SceneObjectGroup attSo = attachments[0];
|
||||
Assert.That(attSo.Name, Is.EqualTo(attName));
|
||||
@@ -120,42 +202,108 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
Assert.That(attSo.IsTemporary, Is.False);
|
||||
|
||||
// Check item status
|
||||
Assert.That(m_presence.Appearance.GetAttachpoint(
|
||||
attSo.GetFromItemID()), Is.EqualTo((int)AttachmentPoint.Chest));
|
||||
Assert.That(
|
||||
sp.Appearance.GetAttachpoint(attSo.FromItemID),
|
||||
Is.EqualTo((int)AttachmentPoint.Chest));
|
||||
|
||||
InventoryItemBase attachmentItem = scene.InventoryService.GetItem(new InventoryItemBase(attSo.FromItemID));
|
||||
Assert.That(attachmentItem, Is.Not.Null);
|
||||
Assert.That(attachmentItem.Name, Is.EqualTo(attName));
|
||||
|
||||
InventoryFolderBase targetFolder = scene.InventoryService.GetFolderForType(sp.UUID, AssetType.Object);
|
||||
Assert.That(attachmentItem.Folder, Is.EqualTo(targetFolder.ID));
|
||||
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
|
||||
// TestHelpers.DisableLogging();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test that we do not attempt to attach an in-world object that someone else is sitting on.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestAddSatOnAttachmentFromGround()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
Scene scene = CreateTestScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
||||
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
|
||||
|
||||
string attName = "att";
|
||||
|
||||
SceneObjectGroup so = SceneHelpers.AddSceneObject(scene, attName, sp.UUID);
|
||||
|
||||
UserAccount ua2 = UserAccountHelpers.CreateUserWithInventory(scene, 0x2);
|
||||
ScenePresence sp2 = SceneHelpers.AddScenePresence(scene, ua2);
|
||||
|
||||
// Put avatar within 10m of the prim so that sit doesn't fail.
|
||||
sp2.AbsolutePosition = new Vector3(0, 0, 0);
|
||||
sp2.HandleAgentRequestSit(sp2.ControllingClient, sp2.UUID, so.UUID, Vector3.Zero);
|
||||
|
||||
scene.AttachmentsModule.AttachObject(sp, so, (uint)AttachmentPoint.Chest, false);
|
||||
|
||||
Assert.That(sp.HasAttachments(), Is.False);
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddAttachmentFromInventory()
|
||||
public void TestRezAttachmentFromInventory()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
|
||||
AddPresence();
|
||||
Scene scene = CreateTestScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
||||
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID);
|
||||
|
||||
UUID attItemId = TestHelpers.ParseTail(0x2);
|
||||
UUID attAssetId = TestHelpers.ParseTail(0x3);
|
||||
string attName = "att";
|
||||
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
|
||||
|
||||
UserInventoryHelpers.CreateInventoryItem(
|
||||
scene, attName, attItemId, attAssetId, m_presence.UUID, InventoryType.Object);
|
||||
|
||||
m_attMod.RezSingleAttachmentFromInventory(
|
||||
m_presence, attItemId, (uint)AttachmentPoint.Chest);
|
||||
scene.AttachmentsModule.RezSingleAttachmentFromInventory(
|
||||
sp, attItem.ID, (uint)AttachmentPoint.Chest);
|
||||
|
||||
// Check scene presence status
|
||||
Assert.That(m_presence.HasAttachments(), Is.True);
|
||||
List<SceneObjectGroup> attachments = m_presence.GetAttachments();
|
||||
Assert.That(sp.HasAttachments(), Is.True);
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments();
|
||||
Assert.That(attachments.Count, Is.EqualTo(1));
|
||||
SceneObjectGroup attSo = attachments[0];
|
||||
Assert.That(attSo.Name, Is.EqualTo(attName));
|
||||
Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
|
||||
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
|
||||
Assert.That(attSo.IsAttachment);
|
||||
Assert.That(attSo.UsesPhysics, Is.False);
|
||||
Assert.That(attSo.IsTemporary, Is.False);
|
||||
|
||||
// Check appearance status
|
||||
Assert.That(m_presence.Appearance.GetAttachments().Count, Is.EqualTo(1));
|
||||
Assert.That(m_presence.Appearance.GetAttachpoint(attItemId), Is.EqualTo((int)AttachmentPoint.Chest));
|
||||
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(1));
|
||||
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
|
||||
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test specific conditions associated with rezzing a scripted attachment from inventory.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestRezScriptedAttachmentFromInventory()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
|
||||
Scene scene = CreateTestScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
||||
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID);
|
||||
|
||||
SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10);
|
||||
TaskInventoryHelpers.AddScript(scene, so.RootPart);
|
||||
InventoryItemBase userItem = UserInventoryHelpers.AddInventoryItem(scene, so, 0x100, 0x1000);
|
||||
|
||||
scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest);
|
||||
|
||||
// TODO: Need to have a test that checks the script is actually started but this involves a lot more
|
||||
// plumbing of the script engine and either pausing for events or more infrastructure to turn off various
|
||||
// script engine delays/asychronicity that isn't helpful in an automated regression testing context.
|
||||
SceneObjectGroup attSo = scene.GetSceneObjectGroup(so.Name);
|
||||
Assert.That(attSo.ContainsScripts(), Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@@ -164,29 +312,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
|
||||
AddPresence();
|
||||
Scene scene = CreateTestScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
||||
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID);
|
||||
|
||||
UUID attItemId = TestHelpers.ParseTail(0x2);
|
||||
UUID attAssetId = TestHelpers.ParseTail(0x3);
|
||||
string attName = "att";
|
||||
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
|
||||
|
||||
UserInventoryHelpers.CreateInventoryItem(
|
||||
scene, attName, attItemId, attAssetId, m_presence.UUID, InventoryType.Object);
|
||||
|
||||
ISceneEntity so = m_attMod.RezSingleAttachmentFromInventory(
|
||||
m_presence, attItemId, (uint)AttachmentPoint.Chest);
|
||||
m_attMod.DetachSingleAttachmentToGround(m_presence, so.LocalId);
|
||||
ISceneEntity so
|
||||
= scene.AttachmentsModule.RezSingleAttachmentFromInventory(
|
||||
sp, attItem.ID, (uint)AttachmentPoint.Chest);
|
||||
scene.AttachmentsModule.DetachSingleAttachmentToGround(sp, so.LocalId);
|
||||
|
||||
// Check scene presence status
|
||||
Assert.That(m_presence.HasAttachments(), Is.False);
|
||||
List<SceneObjectGroup> attachments = m_presence.GetAttachments();
|
||||
Assert.That(sp.HasAttachments(), Is.False);
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments();
|
||||
Assert.That(attachments.Count, Is.EqualTo(0));
|
||||
|
||||
// Check appearance status
|
||||
Assert.That(m_presence.Appearance.GetAttachments().Count, Is.EqualTo(0));
|
||||
Assert.That(sp.Appearance.GetAttachments().Count, Is.EqualTo(0));
|
||||
|
||||
// Check item status
|
||||
Assert.That(scene.InventoryService.GetItem(new InventoryItemBase(attItemId)), Is.Null);
|
||||
Assert.That(scene.InventoryService.GetItem(new InventoryItemBase(attItem.ID)), Is.Null);
|
||||
|
||||
// Check object in scene
|
||||
Assert.That(scene.GetSceneObjectGroup("att"), Is.Not.Null);
|
||||
@@ -196,28 +342,66 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
public void TestDetachAttachmentToInventory()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
|
||||
AddPresence();
|
||||
Scene scene = CreateTestScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
||||
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1.PrincipalID);
|
||||
|
||||
UUID attItemId = TestHelpers.ParseTail(0x2);
|
||||
UUID attAssetId = TestHelpers.ParseTail(0x3);
|
||||
string attName = "att";
|
||||
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
|
||||
|
||||
UserInventoryHelpers.CreateInventoryItem(
|
||||
scene, attName, attItemId, attAssetId, m_presence.UUID, InventoryType.Object);
|
||||
|
||||
m_attMod.RezSingleAttachmentFromInventory(
|
||||
m_presence, attItemId, (uint)AttachmentPoint.Chest);
|
||||
m_attMod.DetachSingleAttachmentToInv(m_presence, attItemId);
|
||||
SceneObjectGroup so
|
||||
= (SceneObjectGroup)scene.AttachmentsModule.RezSingleAttachmentFromInventory(
|
||||
sp, attItem.ID, (uint)AttachmentPoint.Chest);
|
||||
scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, so);
|
||||
|
||||
// Check status on scene presence
|
||||
Assert.That(m_presence.HasAttachments(), Is.False);
|
||||
List<SceneObjectGroup> attachments = m_presence.GetAttachments();
|
||||
Assert.That(sp.HasAttachments(), Is.False);
|
||||
List<SceneObjectGroup> attachments = sp.GetAttachments();
|
||||
Assert.That(attachments.Count, Is.EqualTo(0));
|
||||
|
||||
// Check item status
|
||||
Assert.That(m_presence.Appearance.GetAttachpoint(attItemId), Is.EqualTo(0));
|
||||
Assert.That(sp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo(0));
|
||||
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Test specific conditions associated with detaching a scripted attachment from inventory.
|
||||
/// </summary>
|
||||
[Test]
|
||||
public void TestDetachScriptedAttachmentToInventory()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
Scene scene = CreateScriptingEnabledTestScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
||||
ScenePresence sp = SceneHelpers.AddScenePresence(scene, ua1);
|
||||
|
||||
SceneObjectGroup so = SceneHelpers.CreateSceneObject(1, sp.UUID, "att-name", 0x10);
|
||||
TaskInventoryHelpers.AddScript(scene, so.RootPart);
|
||||
InventoryItemBase userItem = UserInventoryHelpers.AddInventoryItem(scene, so, 0x100, 0x1000);
|
||||
|
||||
// FIXME: Right now, we have to do a tricksy chat listen to make sure we know when the script is running.
|
||||
// In the future, we need to be able to do this programatically more predicably.
|
||||
scene.EventManager.OnChatFromWorld += OnChatFromWorld;
|
||||
|
||||
SceneObjectGroup soRezzed
|
||||
= scene.AttachmentsModule.RezSingleAttachmentFromInventory(sp, userItem.ID, (uint)AttachmentPoint.Chest);
|
||||
|
||||
// Wait for chat to signal rezzed script has been started.
|
||||
m_chatEvent.WaitOne(60000);
|
||||
|
||||
scene.AttachmentsModule.DetachSingleAttachmentToInv(sp, soRezzed);
|
||||
|
||||
InventoryItemBase userItemUpdated = scene.InventoryService.GetItem(userItem);
|
||||
AssetBase asset = scene.AssetService.Get(userItemUpdated.AssetID.ToString());
|
||||
|
||||
XmlDocument soXml = new XmlDocument();
|
||||
soXml.LoadXml(Encoding.UTF8.GetString(asset.Data));
|
||||
|
||||
XmlNodeList scriptStateNodes = soXml.GetElementsByTagName("ScriptState");
|
||||
Assert.That(scriptStateNodes.Count, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -229,17 +413,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
|
||||
UUID userId = TestHelpers.ParseTail(0x1);
|
||||
UUID attItemId = TestHelpers.ParseTail(0x2);
|
||||
UUID attAssetId = TestHelpers.ParseTail(0x3);
|
||||
string attName = "att";
|
||||
Scene scene = CreateTestScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
||||
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
|
||||
|
||||
UserAccountHelpers.CreateUserWithInventory(scene, userId);
|
||||
InventoryItemBase attItem
|
||||
= UserInventoryHelpers.CreateInventoryItem(
|
||||
scene, attName, attItemId, attAssetId, userId, InventoryType.Object);
|
||||
|
||||
AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
|
||||
AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
|
||||
acd.Appearance = new AvatarAppearance();
|
||||
acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID);
|
||||
ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd);
|
||||
@@ -258,17 +436,11 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
|
||||
UUID userId = TestHelpers.ParseTail(0x1);
|
||||
UUID attItemId = TestHelpers.ParseTail(0x2);
|
||||
UUID attAssetId = TestHelpers.ParseTail(0x3);
|
||||
string attName = "att";
|
||||
Scene scene = CreateTestScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
||||
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
|
||||
|
||||
UserAccountHelpers.CreateUserWithInventory(scene, userId);
|
||||
InventoryItemBase attItem
|
||||
= UserInventoryHelpers.CreateInventoryItem(
|
||||
scene, attName, attItemId, attAssetId, userId, InventoryType.Object);
|
||||
|
||||
AgentCircuitData acd = SceneHelpers.GenerateAgentData(userId);
|
||||
AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
|
||||
acd.Appearance = new AvatarAppearance();
|
||||
acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID);
|
||||
ScenePresence presence = SceneHelpers.AddScenePresence(scene, acd);
|
||||
@@ -278,7 +450,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
|
||||
Assert.That(attachments.Count, Is.EqualTo(1));
|
||||
SceneObjectGroup attSo = attachments[0];
|
||||
Assert.That(attSo.Name, Is.EqualTo(attName));
|
||||
Assert.That(attSo.Name, Is.EqualTo(attItem.Name));
|
||||
Assert.That(attSo.AttachmentPoint, Is.EqualTo((byte)AttachmentPoint.Chest));
|
||||
Assert.That(attSo.IsAttachment);
|
||||
Assert.That(attSo.UsesPhysics, Is.False);
|
||||
@@ -288,9 +460,125 @@ namespace OpenSim.Region.CoreModules.Avatar.Attachments.Tests
|
||||
List<AvatarAttachment> retreivedAttachments = presence.Appearance.GetAttachments();
|
||||
Assert.That(retreivedAttachments.Count, Is.EqualTo(1));
|
||||
Assert.That(retreivedAttachments[0].AttachPoint, Is.EqualTo((int)AttachmentPoint.Chest));
|
||||
Assert.That(retreivedAttachments[0].ItemID, Is.EqualTo(attItemId));
|
||||
Assert.That(retreivedAttachments[0].AssetID, Is.EqualTo(attAssetId));
|
||||
Assert.That(presence.Appearance.GetAttachpoint(attItemId), Is.EqualTo((int)AttachmentPoint.Chest));
|
||||
Assert.That(retreivedAttachments[0].ItemID, Is.EqualTo(attItem.ID));
|
||||
Assert.That(retreivedAttachments[0].AssetID, Is.EqualTo(attItem.AssetID));
|
||||
Assert.That(presence.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
|
||||
|
||||
Assert.That(scene.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestUpdateAttachmentPosition()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
|
||||
Scene scene = CreateTestScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene, 0x1);
|
||||
InventoryItemBase attItem = CreateAttachmentItem(scene, ua1.PrincipalID, "att", 0x10, 0x20);
|
||||
|
||||
AgentCircuitData acd = SceneHelpers.GenerateAgentData(ua1.PrincipalID);
|
||||
acd.Appearance = new AvatarAppearance();
|
||||
acd.Appearance.SetAttachment((int)AttachmentPoint.Chest, attItem.ID, attItem.AssetID);
|
||||
ScenePresence sp = SceneHelpers.AddScenePresence(scene, acd);
|
||||
|
||||
SceneObjectGroup attSo = sp.GetAttachments()[0];
|
||||
|
||||
Vector3 newPosition = new Vector3(1, 2, 4);
|
||||
|
||||
scene.SceneGraph.UpdatePrimGroupPosition(attSo.LocalId, newPosition, sp.ControllingClient);
|
||||
|
||||
Assert.That(attSo.AbsolutePosition, Is.EqualTo(sp.AbsolutePosition));
|
||||
Assert.That(attSo.RootPart.AttachedPos, Is.EqualTo(newPosition));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSameSimulatorNeighbouringRegionsTeleport()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// TestHelpers.EnableLogging();
|
||||
|
||||
AttachmentsModule attModA = new AttachmentsModule();
|
||||
AttachmentsModule attModB = new AttachmentsModule();
|
||||
EntityTransferModule etmA = new EntityTransferModule();
|
||||
EntityTransferModule etmB = new EntityTransferModule();
|
||||
LocalSimulationConnectorModule lscm = new LocalSimulationConnectorModule();
|
||||
|
||||
IConfigSource config = new IniConfigSource();
|
||||
IConfig modulesConfig = config.AddConfig("Modules");
|
||||
modulesConfig.Set("EntityTransferModule", etmA.Name);
|
||||
modulesConfig.Set("SimulationServices", lscm.Name);
|
||||
IConfig entityTransferConfig = config.AddConfig("EntityTransfer");
|
||||
|
||||
// In order to run a single threaded regression test we do not want the entity transfer module waiting
|
||||
// for a callback from the destination scene before removing its avatar data.
|
||||
entityTransferConfig.Set("wait_for_callback", false);
|
||||
|
||||
modulesConfig.Set("InventoryAccessModule", "BasicInventoryAccessModule");
|
||||
|
||||
SceneHelpers sh = new SceneHelpers();
|
||||
TestScene sceneA = sh.SetupScene("sceneA", TestHelpers.ParseTail(0x100), 1000, 1000);
|
||||
TestScene sceneB = sh.SetupScene("sceneB", TestHelpers.ParseTail(0x200), 1001, 1000);
|
||||
|
||||
SceneHelpers.SetupSceneModules(new Scene[] { sceneA, sceneB }, config, lscm);
|
||||
SceneHelpers.SetupSceneModules(
|
||||
sceneA, config, new CapabilitiesModule(), etmA, attModA, new BasicInventoryAccessModule());
|
||||
SceneHelpers.SetupSceneModules(
|
||||
sceneB, config, new CapabilitiesModule(), etmB, attModB, new BasicInventoryAccessModule());
|
||||
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(sceneA, 0x1);
|
||||
ScenePresence beforeTeleportSp = SceneHelpers.AddScenePresence(sceneA, ua1.PrincipalID, sh.SceneManager);
|
||||
beforeTeleportSp.AbsolutePosition = new Vector3(30, 31, 32);
|
||||
|
||||
InventoryItemBase attItem = CreateAttachmentItem(sceneA, ua1.PrincipalID, "att", 0x10, 0x20);
|
||||
|
||||
sceneA.AttachmentsModule.RezSingleAttachmentFromInventory(
|
||||
beforeTeleportSp, attItem.ID, (uint)AttachmentPoint.Chest);
|
||||
|
||||
Vector3 teleportPosition = new Vector3(10, 11, 12);
|
||||
Vector3 teleportLookAt = new Vector3(20, 21, 22);
|
||||
|
||||
sceneA.RequestTeleportLocation(
|
||||
beforeTeleportSp.ControllingClient,
|
||||
sceneB.RegionInfo.RegionHandle,
|
||||
teleportPosition,
|
||||
teleportLookAt,
|
||||
(uint)TeleportFlags.ViaLocation);
|
||||
|
||||
((TestClient)beforeTeleportSp.ControllingClient).CompleteTeleportClientSide();
|
||||
|
||||
// Check attachments have made it into sceneB
|
||||
ScenePresence afterTeleportSceneBSp = sceneB.GetScenePresence(ua1.PrincipalID);
|
||||
|
||||
// This is appearance data, as opposed to actually rezzed attachments
|
||||
List<AvatarAttachment> sceneBAttachments = afterTeleportSceneBSp.Appearance.GetAttachments();
|
||||
Assert.That(sceneBAttachments.Count, Is.EqualTo(1));
|
||||
Assert.That(sceneBAttachments[0].AttachPoint, Is.EqualTo((int)AttachmentPoint.Chest));
|
||||
Assert.That(sceneBAttachments[0].ItemID, Is.EqualTo(attItem.ID));
|
||||
Assert.That(sceneBAttachments[0].AssetID, Is.EqualTo(attItem.AssetID));
|
||||
Assert.That(afterTeleportSceneBSp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
|
||||
|
||||
// This is the actual attachment
|
||||
List<SceneObjectGroup> actualSceneBAttachments = afterTeleportSceneBSp.GetAttachments();
|
||||
Assert.That(actualSceneBAttachments.Count, Is.EqualTo(1));
|
||||
SceneObjectGroup actualSceneBAtt = actualSceneBAttachments[0];
|
||||
Assert.That(actualSceneBAtt.Name, Is.EqualTo(attItem.Name));
|
||||
Assert.That(actualSceneBAtt.AttachmentPoint, Is.EqualTo((uint)AttachmentPoint.Chest));
|
||||
|
||||
Assert.That(sceneB.GetSceneObjectGroups().Count, Is.EqualTo(1));
|
||||
|
||||
// Check attachments have been removed from sceneA
|
||||
ScenePresence afterTeleportSceneASp = sceneA.GetScenePresence(ua1.PrincipalID);
|
||||
|
||||
// Since this is appearance data, it is still present on the child avatar!
|
||||
List<AvatarAttachment> sceneAAttachments = afterTeleportSceneASp.Appearance.GetAttachments();
|
||||
Assert.That(sceneAAttachments.Count, Is.EqualTo(1));
|
||||
Assert.That(afterTeleportSceneASp.Appearance.GetAttachpoint(attItem.ID), Is.EqualTo((int)AttachmentPoint.Chest));
|
||||
|
||||
// This is the actual attachment, which should no longer exist
|
||||
List<SceneObjectGroup> actualSceneAAttachments = afterTeleportSceneASp.GetAttachments();
|
||||
Assert.That(actualSceneAAttachments.Count, Is.EqualTo(0));
|
||||
|
||||
Assert.That(sceneA.GetSceneObjectGroups().Count, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
// I'm commenting this test because scene setup NEEDS InventoryService to
|
||||
|
||||
@@ -128,7 +128,9 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
|
||||
/// <param name="visualParam"></param>
|
||||
public void SetAppearance(IScenePresence sp, Primitive.TextureEntry textureEntry, byte[] visualParams)
|
||||
{
|
||||
// m_log.InfoFormat("[AVFACTORY]: start SetAppearance for {0}", client.AgentId);
|
||||
// m_log.DebugFormat(
|
||||
// "[AVFACTORY]: start SetAppearance for {0}, te {1}, visualParams {2}",
|
||||
// sp.Name, textureEntry, visualParams);
|
||||
|
||||
// TODO: This is probably not necessary any longer, just assume the
|
||||
// textureEntry set implies that the appearance transaction is complete
|
||||
@@ -158,7 +160,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
|
||||
// Process the baked texture array
|
||||
if (textureEntry != null)
|
||||
{
|
||||
m_log.InfoFormat("[AVFACTORY]: Received texture update for {0} {1}", sp.Name, sp.UUID);
|
||||
// m_log.DebugFormat("[AVFACTORY]: Received texture update for {0} {1}", sp.Name, sp.UUID);
|
||||
|
||||
// WriteBakedTexturesReport(sp, m_log.DebugFormat);
|
||||
|
||||
@@ -208,7 +210,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
|
||||
ScenePresence sp = m_scene.GetScenePresence(agentId);
|
||||
if (sp == null)
|
||||
{
|
||||
m_log.WarnFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentId);
|
||||
// This is expected if the user has gone away.
|
||||
// m_log.DebugFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentId);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -337,7 +340,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
|
||||
return false;
|
||||
}
|
||||
|
||||
m_log.DebugFormat("[AVFACTORY]: Completed texture check for {0} {1}", sp.Name, sp.UUID);
|
||||
// m_log.DebugFormat("[AVFACTORY]: Completed texture check for {0} {1}", sp.Name, sp.UUID);
|
||||
|
||||
// If we only found default textures, then the appearance is not cached
|
||||
return (defonly ? false : true);
|
||||
@@ -370,11 +373,21 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
|
||||
if (missingTexturesOnly)
|
||||
{
|
||||
if (m_scene.AssetService.Get(face.TextureID.ToString()) != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
// On inter-simulator teleports, this occurs if baked textures are not being stored by the
|
||||
// grid asset service (which means that they are not available to the new region and so have
|
||||
// to be re-requested from the client).
|
||||
//
|
||||
// The only available core OpenSimulator behaviour right now
|
||||
// is not to store these textures, temporarily or otherwise.
|
||||
m_log.DebugFormat(
|
||||
"[AVFACTORY]: Missing baked texture {0} ({1}) for {2}, requesting rebake.",
|
||||
face.TextureID, idx, sp.Name);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -482,7 +495,8 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
|
||||
ScenePresence sp = m_scene.GetScenePresence(agentid);
|
||||
if (sp == null)
|
||||
{
|
||||
m_log.WarnFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentid);
|
||||
// This is expected if the user has gone away.
|
||||
// m_log.DebugFormat("[AVFACTORY]: Agent {0} no longer in the scene", agentid);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
|
||||
UUID userId = TestHelpers.ParseTail(0x1);
|
||||
|
||||
AvatarFactoryModule afm = new AvatarFactoryModule();
|
||||
TestScene scene = SceneHelpers.SetupScene();
|
||||
TestScene scene = new SceneHelpers().SetupScene();
|
||||
SceneHelpers.SetupSceneModules(scene, afm);
|
||||
ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId);
|
||||
|
||||
@@ -81,7 +81,7 @@ namespace OpenSim.Region.CoreModules.Avatar.AvatarFactory
|
||||
CoreAssetCache assetCache = new CoreAssetCache();
|
||||
|
||||
AvatarFactoryModule afm = new AvatarFactoryModule();
|
||||
TestScene scene = SceneHelpers.SetupScene(assetCache);
|
||||
TestScene scene = new SceneHelpers(assetCache).SetupScene();
|
||||
SceneHelpers.SetupSceneModules(scene, afm);
|
||||
ScenePresence sp = SceneHelpers.AddScenePresence(scene, userId);
|
||||
|
||||
|
||||
189
OpenSim/Region/CoreModules/Avatar/Commands/UserCommandsModule.cs
Normal file
189
OpenSim/Region/CoreModules/Avatar/Commands/UserCommandsModule.cs
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using log4net;
|
||||
using Mono.Addins;
|
||||
using NDesk.Options;
|
||||
using Nini.Config;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Console;
|
||||
using OpenSim.Framework.Statistics;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.Avatars.Commands
|
||||
{
|
||||
/// <summary>
|
||||
/// A module that holds commands for manipulating objects in the scene.
|
||||
/// </summary>
|
||||
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "UserCommandsModule")]
|
||||
public class UserCommandsModule : ISharedRegionModule
|
||||
{
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
public const string TeleportUserCommandSyntax = "teleport user <first-name> <last-name> <destination>";
|
||||
|
||||
public static Regex InterRegionDestinationRegex
|
||||
= new Regex(@"^(?<regionName>.+)/(?<x>\d+)/(?<y>\d+)/(?<z>\d+)$", RegexOptions.Compiled);
|
||||
|
||||
public static Regex WithinRegionDestinationRegex
|
||||
= new Regex(@"^(?<x>\d+)/(?<y>\d+)/(?<z>\d+)$", RegexOptions.Compiled);
|
||||
|
||||
private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>();
|
||||
|
||||
public string Name { get { return "User Commands Module"; } }
|
||||
|
||||
public Type ReplaceableInterface { get { return null; } }
|
||||
|
||||
public void Initialise(IConfigSource source)
|
||||
{
|
||||
// m_log.DebugFormat("[USER COMMANDS MODULE]: INITIALIZED MODULE");
|
||||
}
|
||||
|
||||
public void PostInitialise()
|
||||
{
|
||||
// m_log.DebugFormat("[USER COMMANDS MODULE]: POST INITIALIZED MODULE");
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
// m_log.DebugFormat("[USER COMMANDS MODULE]: CLOSED MODULE");
|
||||
}
|
||||
|
||||
public void AddRegion(Scene scene)
|
||||
{
|
||||
// m_log.DebugFormat("[USER COMMANDS MODULE]: REGION {0} ADDED", scene.RegionInfo.RegionName);
|
||||
|
||||
lock (m_scenes)
|
||||
m_scenes[scene.RegionInfo.RegionID] = scene;
|
||||
|
||||
scene.AddCommand(
|
||||
"Users",
|
||||
this,
|
||||
"teleport user",
|
||||
TeleportUserCommandSyntax,
|
||||
"Teleport a user in this simulator to the given destination",
|
||||
"<destination> is in format [<region-name>]/<x>/<y>/<z>, e.g. regionone/20/30/40 or just 20/30/40 to teleport within same region."
|
||||
+ "\nIf the region contains a space then the whole destination must be in quotes, e.g. \"region one/20/30/40\"",
|
||||
HandleTeleportUser);
|
||||
}
|
||||
|
||||
public void RemoveRegion(Scene scene)
|
||||
{
|
||||
// m_log.DebugFormat("[USER COMMANDS MODULE]: REGION {0} REMOVED", scene.RegionInfo.RegionName);
|
||||
|
||||
lock (m_scenes)
|
||||
m_scenes.Remove(scene.RegionInfo.RegionID);
|
||||
}
|
||||
|
||||
public void RegionLoaded(Scene scene)
|
||||
{
|
||||
// m_log.DebugFormat("[USER COMMANDS MODULE]: REGION {0} LOADED", scene.RegionInfo.RegionName);
|
||||
}
|
||||
|
||||
private ScenePresence GetUser(string firstName, string lastName)
|
||||
{
|
||||
ScenePresence userFound = null;
|
||||
|
||||
lock (m_scenes)
|
||||
{
|
||||
foreach (Scene scene in m_scenes.Values)
|
||||
{
|
||||
ScenePresence user = scene.GetScenePresence(firstName, lastName);
|
||||
if (user != null && !user.IsChildAgent)
|
||||
{
|
||||
userFound = user;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return userFound;
|
||||
}
|
||||
|
||||
private void HandleTeleportUser(string module, string[] cmd)
|
||||
{
|
||||
if (cmd.Length < 5)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat("Usage: " + TeleportUserCommandSyntax);
|
||||
return;
|
||||
}
|
||||
|
||||
string firstName = cmd[2];
|
||||
string lastName = cmd[3];
|
||||
string rawDestination = cmd[4];
|
||||
|
||||
ScenePresence user = GetUser(firstName, lastName);
|
||||
|
||||
if (user == null)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat("No user found with name {0} {1}", firstName, lastName);
|
||||
return;
|
||||
}
|
||||
|
||||
// MainConsole.Instance.OutputFormat("rawDestination [{0}]", rawDestination);
|
||||
|
||||
Match m = WithinRegionDestinationRegex.Match(rawDestination);
|
||||
|
||||
if (!m.Success)
|
||||
{
|
||||
m = InterRegionDestinationRegex.Match(rawDestination);
|
||||
|
||||
if (!m.Success)
|
||||
{
|
||||
MainConsole.Instance.OutputFormat("Invalid destination {0}", rawDestination);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
string regionName
|
||||
= m.Groups["regionName"].Success ? m.Groups["regionName"].Value : user.Scene.RegionInfo.RegionName;
|
||||
|
||||
MainConsole.Instance.OutputFormat(
|
||||
"Teleporting {0} to {1},{2},{3} in {4}",
|
||||
user.Name,
|
||||
m.Groups["x"], m.Groups["y"], m.Groups["z"],
|
||||
regionName);
|
||||
|
||||
user.Scene.RequestTeleportLocation(
|
||||
user.ControllingClient,
|
||||
regionName,
|
||||
new Vector3(
|
||||
float.Parse(m.Groups["x"].Value),
|
||||
float.Parse(m.Groups["y"].Value),
|
||||
float.Parse(m.Groups["z"].Value)),
|
||||
user.Lookat,
|
||||
(uint)TeleportFlags.ViaLocation);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,12 +51,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Dialog
|
||||
m_scene.RegisterModuleInterface<IDialogModule>(this);
|
||||
|
||||
m_scene.AddCommand(
|
||||
this, "alert", "alert <message>",
|
||||
"Users", this, "alert", "alert <message>",
|
||||
"Send an alert to everyone",
|
||||
HandleAlertConsoleCommand);
|
||||
|
||||
m_scene.AddCommand(
|
||||
this, "alert-user", "alert-user <first> <last> <message>",
|
||||
"Users", this, "alert-user", "alert-user <first> <last> <message>",
|
||||
"Send an alert to a user",
|
||||
HandleAlertConsoleCommand);
|
||||
}
|
||||
|
||||
313
OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
Normal file
313
OpenSim/Region/CoreModules/Avatar/Friends/CallingCardModule.cs
Normal file
@@ -0,0 +1,313 @@
|
||||
/*
|
||||
* 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 Nini.Config;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using Mono.Addins;
|
||||
|
||||
namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
{
|
||||
[Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "XCallingCard")]
|
||||
public class CallingCardModule : ISharedRegionModule, ICallingCardModule
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
protected List<Scene> m_Scenes = new List<Scene>();
|
||||
protected bool m_Enabled = true;
|
||||
|
||||
public void Initialise(IConfigSource source)
|
||||
{
|
||||
IConfig ccConfig = source.Configs["XCallingCard"];
|
||||
if (ccConfig != null)
|
||||
m_Enabled = ccConfig.GetBoolean("Enabled", true);
|
||||
}
|
||||
|
||||
public void AddRegion(Scene scene)
|
||||
{
|
||||
if (!m_Enabled)
|
||||
return;
|
||||
|
||||
m_Scenes.Add(scene);
|
||||
|
||||
scene.RegisterModuleInterface<ICallingCardModule>(this);
|
||||
}
|
||||
|
||||
public void RemoveRegion(Scene scene)
|
||||
{
|
||||
if (!m_Enabled)
|
||||
return;
|
||||
|
||||
m_Scenes.Remove(scene);
|
||||
|
||||
scene.EventManager.OnNewClient -= OnNewClient;
|
||||
scene.EventManager.OnIncomingInstantMessage +=
|
||||
OnIncomingInstantMessage;
|
||||
|
||||
scene.UnregisterModuleInterface<ICallingCardModule>(this);
|
||||
}
|
||||
|
||||
public void RegionLoaded(Scene scene)
|
||||
{
|
||||
if (!m_Enabled)
|
||||
return;
|
||||
scene.EventManager.OnNewClient += OnNewClient;
|
||||
}
|
||||
|
||||
public void PostInitialise()
|
||||
{
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
}
|
||||
|
||||
public Type ReplaceableInterface
|
||||
{
|
||||
get { return null; }
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get { return "XCallingCardModule"; }
|
||||
}
|
||||
|
||||
private void OnNewClient(IClientAPI client)
|
||||
{
|
||||
client.OnOfferCallingCard += OnOfferCallingCard;
|
||||
client.OnAcceptCallingCard += OnAcceptCallingCard;
|
||||
client.OnDeclineCallingCard += OnDeclineCallingCard;
|
||||
}
|
||||
|
||||
private void OnOfferCallingCard(IClientAPI client, UUID destID, UUID transactionID)
|
||||
{
|
||||
ScenePresence sp = GetClientPresence(client.AgentId);
|
||||
if (sp != null)
|
||||
{
|
||||
// If we're in god mode, we reverse the meaning. Offer
|
||||
// calling card becomes "Take a calling card" for that
|
||||
// person, no matter if they agree or not.
|
||||
if (sp.GodLevel >= 200)
|
||||
{
|
||||
CreateCallingCard(client.AgentId, destID, UUID.Zero, true);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
IClientAPI dest = FindClientObject(destID);
|
||||
if (dest != null)
|
||||
{
|
||||
DoCallingCardOffer(dest, client.AgentId);
|
||||
return;
|
||||
}
|
||||
|
||||
IMessageTransferModule transferModule =
|
||||
m_Scenes[0].RequestModuleInterface<IMessageTransferModule>();
|
||||
|
||||
if (transferModule != null)
|
||||
{
|
||||
transferModule.SendInstantMessage(new GridInstantMessage(
|
||||
client.Scene, client.AgentId,
|
||||
client.FirstName+" "+client.LastName,
|
||||
destID, (byte)211, false,
|
||||
String.Empty,
|
||||
transactionID, false, new Vector3(), new byte[0]),
|
||||
delegate(bool success) {} );
|
||||
}
|
||||
}
|
||||
|
||||
private void DoCallingCardOffer(IClientAPI dest, UUID from)
|
||||
{
|
||||
UUID itemID = CreateCallingCard(dest.AgentId, from, UUID.Zero, false);
|
||||
|
||||
dest.SendOfferCallingCard(from, itemID);
|
||||
}
|
||||
|
||||
// Create a calling card in the user's inventory. This is called
|
||||
// from direct calling card creation, when the offer is forwarded,
|
||||
// and from the friends module when the friend is confirmed.
|
||||
// Because of the latter, it will send a bulk inventory update
|
||||
// if the receiving user is in the same simulator.
|
||||
public UUID CreateCallingCard(UUID userID, UUID creatorID, UUID folderID)
|
||||
{
|
||||
return CreateCallingCard(userID, creatorID, folderID, false);
|
||||
}
|
||||
|
||||
private UUID CreateCallingCard(UUID userID, UUID creatorID, UUID folderID, bool isGod)
|
||||
{
|
||||
IUserAccountService userv = m_Scenes[0].UserAccountService;
|
||||
if (userv == null)
|
||||
return UUID.Zero;
|
||||
|
||||
UserAccount info = userv.GetUserAccount(UUID.Zero, creatorID);
|
||||
if (info == null)
|
||||
return UUID.Zero;
|
||||
|
||||
IInventoryService inv = m_Scenes[0].InventoryService;
|
||||
if (inv == null)
|
||||
return UUID.Zero;
|
||||
|
||||
if (folderID == UUID.Zero)
|
||||
{
|
||||
InventoryFolderBase folder = inv.GetFolderForType(userID,
|
||||
AssetType.CallingCard);
|
||||
|
||||
if (folder == null) // Nowhere to put it
|
||||
return UUID.Zero;
|
||||
|
||||
folderID = folder.ID;
|
||||
}
|
||||
|
||||
m_log.DebugFormat("[XCALLINGCARD]: Creating calling card for {0} in inventory of {1}", info.Name, userID);
|
||||
|
||||
InventoryItemBase item = new InventoryItemBase();
|
||||
item.AssetID = UUID.Zero;
|
||||
item.AssetType = (int)AssetType.CallingCard;
|
||||
item.BasePermissions = (uint)(PermissionMask.Copy | PermissionMask.Modify);
|
||||
if (isGod)
|
||||
item.BasePermissions = (uint)(PermissionMask.Copy | PermissionMask.Modify | PermissionMask.Transfer | PermissionMask.Move);
|
||||
|
||||
item.EveryOnePermissions = (uint)PermissionMask.None;
|
||||
item.CurrentPermissions = item.BasePermissions;
|
||||
item.NextPermissions = (uint)(PermissionMask.Copy | PermissionMask.Modify);
|
||||
|
||||
item.ID = UUID.Random();
|
||||
item.CreatorId = creatorID.ToString();
|
||||
item.Owner = userID;
|
||||
item.GroupID = UUID.Zero;
|
||||
item.GroupOwned = false;
|
||||
item.Folder = folderID;
|
||||
|
||||
item.CreationDate = Util.UnixTimeSinceEpoch();
|
||||
item.InvType = (int)InventoryType.CallingCard;
|
||||
item.Flags = 0;
|
||||
|
||||
item.Name = info.Name;
|
||||
item.Description = "";
|
||||
|
||||
item.SalePrice = 10;
|
||||
item.SaleType = (byte)SaleType.Not;
|
||||
|
||||
inv.AddItem(item);
|
||||
|
||||
IClientAPI client = FindClientObject(userID);
|
||||
if (client != null)
|
||||
client.SendBulkUpdateInventory(item);
|
||||
|
||||
return item.ID;
|
||||
}
|
||||
|
||||
private void OnAcceptCallingCard(IClientAPI client, UUID transactionID, UUID folderID)
|
||||
{
|
||||
}
|
||||
|
||||
private void OnDeclineCallingCard(IClientAPI client, UUID transactionID)
|
||||
{
|
||||
IInventoryService invService = m_Scenes[0].InventoryService;
|
||||
|
||||
InventoryFolderBase trashFolder =
|
||||
invService.GetFolderForType(client.AgentId, AssetType.TrashFolder);
|
||||
|
||||
InventoryItemBase item = new InventoryItemBase(transactionID, client.AgentId);
|
||||
item = invService.GetItem(item);
|
||||
|
||||
if (item != null && trashFolder != null)
|
||||
{
|
||||
item.Folder = trashFolder.ID;
|
||||
List<UUID> uuids = new List<UUID>();
|
||||
uuids.Add(item.ID);
|
||||
invService.DeleteItems(item.Owner, uuids);
|
||||
m_Scenes[0].AddInventoryItem(client, item);
|
||||
}
|
||||
}
|
||||
|
||||
public IClientAPI FindClientObject(UUID agentID)
|
||||
{
|
||||
Scene scene = GetClientScene(agentID);
|
||||
if (scene == null)
|
||||
return null;
|
||||
|
||||
ScenePresence presence = scene.GetScenePresence(agentID);
|
||||
if (presence == null)
|
||||
return null;
|
||||
|
||||
return presence.ControllingClient;
|
||||
}
|
||||
|
||||
private Scene GetClientScene(UUID agentId)
|
||||
{
|
||||
lock (m_Scenes)
|
||||
{
|
||||
foreach (Scene scene in m_Scenes)
|
||||
{
|
||||
ScenePresence presence = scene.GetScenePresence(agentId);
|
||||
if (presence != null)
|
||||
{
|
||||
if (!presence.IsChildAgent)
|
||||
return scene;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private ScenePresence GetClientPresence(UUID agentId)
|
||||
{
|
||||
lock (m_Scenes)
|
||||
{
|
||||
foreach (Scene scene in m_Scenes)
|
||||
{
|
||||
ScenePresence presence = scene.GetScenePresence(agentId);
|
||||
if (presence != null)
|
||||
{
|
||||
if (!presence.IsChildAgent)
|
||||
return presence;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void OnIncomingInstantMessage(GridInstantMessage msg)
|
||||
{
|
||||
if (msg.dialog == (uint)211)
|
||||
{
|
||||
IClientAPI client = FindClientObject(new UUID(msg.toAgentID));
|
||||
if (client == null)
|
||||
return;
|
||||
|
||||
DoCallingCardOffer(client, new UUID(msg.fromAgentID));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
{
|
||||
public class FriendsModule : ISharedRegionModule, IFriendsModule
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
protected bool m_Enabled = false;
|
||||
|
||||
protected class UserFriendData
|
||||
@@ -72,7 +74,6 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
}
|
||||
|
||||
protected static readonly FriendInfo[] EMPTY_FRIENDS = new FriendInfo[0];
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
protected List<Scene> m_Scenes = new List<Scene>();
|
||||
|
||||
@@ -109,7 +110,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
}
|
||||
}
|
||||
|
||||
protected IFriendsService FriendsService
|
||||
public IFriendsService FriendsService
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -156,7 +157,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
InitModule(config);
|
||||
|
||||
m_Enabled = true;
|
||||
m_log.InfoFormat("[FRIENDS MODULE]: {0} enabled.", Name);
|
||||
m_log.DebugFormat("[FRIENDS MODULE]: {0} enabled.", Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -201,7 +202,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
if (!m_Enabled)
|
||||
return;
|
||||
|
||||
m_log.DebugFormat("[FRIENDS MODULE]: AddRegion on {0}", Name);
|
||||
// m_log.DebugFormat("[FRIENDS MODULE]: AddRegion on {0}", Name);
|
||||
|
||||
m_Scenes.Add(scene);
|
||||
scene.RegisterModuleInterface<IFriendsModule>(this);
|
||||
@@ -212,9 +213,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
scene.EventManager.OnClientLogin += OnClientLogin;
|
||||
}
|
||||
|
||||
public void RegionLoaded(Scene scene)
|
||||
{
|
||||
}
|
||||
public virtual void RegionLoaded(Scene scene) {}
|
||||
|
||||
public void RemoveRegion(Scene scene)
|
||||
{
|
||||
@@ -236,13 +235,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
|
||||
#endregion
|
||||
|
||||
public virtual uint GetFriendPerms(UUID principalID, UUID friendID)
|
||||
public virtual int GetRightsGrantedByFriend(UUID principalID, UUID friendID)
|
||||
{
|
||||
FriendInfo[] friends = GetFriends(principalID);
|
||||
FriendInfo[] friends = GetFriendsFromCache(principalID);
|
||||
FriendInfo finfo = GetFriend(friends, friendID);
|
||||
if (finfo != null)
|
||||
{
|
||||
return (uint)finfo.TheirFlags;
|
||||
return finfo.TheirFlags;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -253,9 +252,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
client.OnInstantMessage += OnInstantMessage;
|
||||
client.OnApproveFriendRequest += OnApproveFriendRequest;
|
||||
client.OnDenyFriendRequest += OnDenyFriendRequest;
|
||||
client.OnTerminateFriendship += (thisClient, agentID, exfriendID) => RemoveFriendship(thisClient, exfriendID);
|
||||
client.OnGrantUserRights += OnGrantUserRights;
|
||||
client.OnTerminateFriendship += RemoveFriendship;
|
||||
client.OnGrantUserRights += GrantRights;
|
||||
|
||||
// We need to cache information for child agents as well as root agents so that friend edit/move/delete
|
||||
// permissions will work across borders where both regions are on different simulators.
|
||||
//
|
||||
// Do not do this asynchronously. If we do, then subsequent code can outrace CacheFriends() and
|
||||
// return misleading results from the still empty friends cache.
|
||||
// If we absolutely need to do this asynchronously, then a signalling mechanism is needed so that calls
|
||||
@@ -328,7 +330,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
//m_log.DebugFormat("[XXX]: OnClientLogin!");
|
||||
// Inform the friends that this user is online
|
||||
StatusChange(agentID, true);
|
||||
|
||||
|
||||
// Register that we need to send the list of online friends to this user
|
||||
lock (m_NeedsListOfOnlineFriends)
|
||||
m_NeedsListOfOnlineFriends.Add(agentID);
|
||||
@@ -347,18 +349,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
|
||||
// Send the friends online
|
||||
List<UUID> online = GetOnlineFriends(agentID);
|
||||
if (online.Count > 0)
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[FRIENDS MODULE]: User {0} in region {1} has {2} friends online",
|
||||
client.Name, client.Scene.RegionInfo.RegionName, online.Count);
|
||||
|
||||
if (online.Count > 0)
|
||||
client.SendAgentOnline(online.ToArray());
|
||||
}
|
||||
|
||||
// Send outstanding friendship offers
|
||||
List<string> outstanding = new List<string>();
|
||||
FriendInfo[] friends = GetFriends(agentID);
|
||||
FriendInfo[] friends = GetFriendsFromCache(agentID);
|
||||
foreach (FriendInfo fi in friends)
|
||||
{
|
||||
if (fi.TheirFlags == -1)
|
||||
@@ -414,23 +411,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
List<UUID> GetOnlineFriends(UUID userID)
|
||||
{
|
||||
List<string> friendList = new List<string>();
|
||||
List<UUID> online = new List<UUID>();
|
||||
|
||||
FriendInfo[] friends = GetFriends(userID);
|
||||
FriendInfo[] friends = GetFriendsFromCache(userID);
|
||||
foreach (FriendInfo fi in friends)
|
||||
{
|
||||
if (((fi.TheirFlags & 1) != 0) && (fi.TheirFlags != -1))
|
||||
if (((fi.TheirFlags & (int)FriendRights.CanSeeOnline) != 0) && (fi.TheirFlags != -1))
|
||||
friendList.Add(fi.Friend);
|
||||
}
|
||||
|
||||
List<UUID> online = new List<UUID>();
|
||||
|
||||
if (friendList.Count > 0)
|
||||
GetOnlineFriends(userID, friendList, online);
|
||||
|
||||
// m_log.DebugFormat(
|
||||
// "[FRIENDS MODULE]: User {0} has {1} friends online", userID, online.Count);
|
||||
|
||||
return online;
|
||||
}
|
||||
|
||||
protected virtual void GetOnlineFriends(UUID userID, List<string> friendList, /*collector*/ List<UUID> online)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[FRIENDS MODULE]: Looking for online presence of {0} users for {1}", friendList.Count, userID);
|
||||
|
||||
PresenceInfo[] presence = PresenceService.GetAgents(friendList.ToArray());
|
||||
foreach (PresenceInfo pi in presence)
|
||||
{
|
||||
@@ -444,30 +448,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
/// Find the client for a ID
|
||||
/// </summary>
|
||||
public IClientAPI LocateClientObject(UUID agentID)
|
||||
{
|
||||
Scene scene = GetClientScene(agentID);
|
||||
if (scene != null)
|
||||
{
|
||||
ScenePresence presence = scene.GetScenePresence(agentID);
|
||||
if (presence != null)
|
||||
return presence.ControllingClient;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find the scene for an agent
|
||||
/// </summary>
|
||||
private Scene GetClientScene(UUID agentId)
|
||||
{
|
||||
lock (m_Scenes)
|
||||
{
|
||||
foreach (Scene scene in m_Scenes)
|
||||
{
|
||||
ScenePresence presence = scene.GetScenePresence(agentId);
|
||||
ScenePresence presence = scene.GetScenePresence(agentID);
|
||||
if (presence != null && !presence.IsChildAgent)
|
||||
return scene;
|
||||
return presence.ControllingClient;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,20 +469,23 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
/// <param name="online"></param>
|
||||
private void StatusChange(UUID agentID, bool online)
|
||||
{
|
||||
FriendInfo[] friends = GetFriends(agentID);
|
||||
FriendInfo[] friends = GetFriendsFromCache(agentID);
|
||||
if (friends.Length > 0)
|
||||
{
|
||||
List<FriendInfo> friendList = new List<FriendInfo>();
|
||||
foreach (FriendInfo fi in friends)
|
||||
{
|
||||
if (((fi.MyFlags & 1) != 0) && (fi.TheirFlags != -1))
|
||||
if (((fi.MyFlags & (int)FriendRights.CanSeeOnline) != 0) && (fi.TheirFlags != -1))
|
||||
friendList.Add(fi);
|
||||
}
|
||||
|
||||
Util.FireAndForget(
|
||||
delegate
|
||||
{
|
||||
m_log.DebugFormat("[FRIENDS MODULE]: Notifying {0} friends", friendList.Count);
|
||||
m_log.DebugFormat(
|
||||
"[FRIENDS MODULE]: Notifying {0} friends of {1} of online status {2}",
|
||||
friendList.Count, agentID, online);
|
||||
|
||||
// Notify about this user status
|
||||
StatusNotify(friendList, agentID, online);
|
||||
}
|
||||
@@ -511,7 +502,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
{
|
||||
// Try local
|
||||
if (LocalStatusNotification(userID, friendID, online))
|
||||
return;
|
||||
continue;
|
||||
|
||||
// The friend is not here [as root]. Let's forward.
|
||||
PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() });
|
||||
@@ -519,11 +510,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
{
|
||||
PresenceInfo friendSession = null;
|
||||
foreach (PresenceInfo pinfo in friendSessions)
|
||||
{
|
||||
if (pinfo.RegionID != UUID.Zero) // let's guard against sessions-gone-bad
|
||||
{
|
||||
friendSession = pinfo;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (friendSession != null)
|
||||
{
|
||||
@@ -550,7 +543,19 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
UUID principalID = new UUID(im.fromAgentID);
|
||||
UUID friendID = new UUID(im.toAgentID);
|
||||
|
||||
m_log.DebugFormat("[FRIENDS]: {0} ({1}) offered friendship to {2}", principalID, im.fromAgentName, friendID);
|
||||
m_log.DebugFormat("[FRIENDS]: {0} ({1}) offered friendship to {2} ({3})", principalID, client.FirstName + client.LastName, friendID, im.fromAgentName);
|
||||
|
||||
// Check that the friendship doesn't exist yet
|
||||
FriendInfo[] finfos = GetFriendsFromCache(principalID);
|
||||
if (finfos != null)
|
||||
{
|
||||
FriendInfo f = GetFriend(finfos, friendID);
|
||||
if (f != null)
|
||||
{
|
||||
client.SendAgentAlertMessage("This person is already your friend. Please delete it first if you want to reestablish the friendship.", false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// This user wants to be friends with the other user.
|
||||
// Let's add the relation backwards, in case the other is not online
|
||||
@@ -592,7 +597,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
return (account == null) ? "Unknown" : account.FirstName + " " + account.LastName;
|
||||
}
|
||||
|
||||
private void OnApproveFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders)
|
||||
protected virtual void OnApproveFriendRequest(IClientAPI client, UUID friendID, List<UUID> callingCardFolders)
|
||||
{
|
||||
m_log.DebugFormat("[FRIENDS]: {0} accepted friendship from {1}", client.AgentId, friendID);
|
||||
|
||||
@@ -603,8 +608,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
{
|
||||
StoreFriendships(client.AgentId, friendID);
|
||||
|
||||
// Update the local cache
|
||||
RecacheFriends(client);
|
||||
ICallingCardModule ccm = client.Scene.RequestModuleInterface<ICallingCardModule>();
|
||||
if (ccm != null)
|
||||
{
|
||||
ccm.CreateCallingCard(client.AgentId, friendID, UUID.Zero);
|
||||
}
|
||||
|
||||
// Update the local cache.
|
||||
CacheFriends(client);
|
||||
|
||||
//
|
||||
// Notify the friend
|
||||
@@ -631,18 +642,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDenyFriendRequest(IClientAPI client, UUID agentID, UUID friendID, List<UUID> callingCardFolders)
|
||||
private void OnDenyFriendRequest(IClientAPI client, UUID friendID, List<UUID> callingCardFolders)
|
||||
{
|
||||
m_log.DebugFormat("[FRIENDS]: {0} denied friendship to {1}", agentID, friendID);
|
||||
m_log.DebugFormat("[FRIENDS]: {0} denied friendship to {1}", client.AgentId, friendID);
|
||||
|
||||
DeleteFriendship(agentID, friendID);
|
||||
DeleteFriendship(client.AgentId, friendID);
|
||||
|
||||
//
|
||||
// Notify the friend
|
||||
//
|
||||
|
||||
// Try local
|
||||
if (LocalFriendshipDenied(agentID, client.Name, friendID))
|
||||
if (LocalFriendshipDenied(client.AgentId, client.Name, friendID))
|
||||
return;
|
||||
|
||||
PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() });
|
||||
@@ -653,7 +664,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
{
|
||||
GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
|
||||
if (region != null)
|
||||
m_FriendsSimConnector.FriendshipDenied(region, agentID, client.Name, friendID);
|
||||
m_FriendsSimConnector.FriendshipDenied(region, client.AgentId, client.Name, friendID);
|
||||
else
|
||||
m_log.WarnFormat("[FRIENDS]: Could not find region {0} in locating {1}", friendSession.RegionID, friendID);
|
||||
}
|
||||
@@ -690,23 +701,27 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGrantUserRights(IClientAPI remoteClient, UUID requester, UUID target, int rights)
|
||||
public void GrantRights(IClientAPI remoteClient, UUID friendID, int rights)
|
||||
{
|
||||
m_log.DebugFormat("[FRIENDS MODULE]: User {0} changing rights to {1} for friend {2}", requester, rights, target);
|
||||
UUID requester = remoteClient.AgentId;
|
||||
|
||||
FriendInfo[] friends = GetFriends(remoteClient.AgentId);
|
||||
m_log.DebugFormat(
|
||||
"[FRIENDS MODULE]: User {0} changing rights to {1} for friend {2}",
|
||||
requester, rights, friendID);
|
||||
|
||||
FriendInfo[] friends = GetFriendsFromCache(requester);
|
||||
if (friends.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Let's find the friend in this user's friend list
|
||||
FriendInfo friend = GetFriend(friends, target);
|
||||
FriendInfo friend = GetFriend(friends, friendID);
|
||||
|
||||
if (friend != null) // Found it
|
||||
{
|
||||
// Store it on the DB
|
||||
if (!StoreRights(requester, target, rights))
|
||||
if (!StoreRights(requester, friendID, rights))
|
||||
{
|
||||
remoteClient.SendAlertMessage("Unable to grant rights.");
|
||||
return;
|
||||
@@ -717,17 +732,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
friend.MyFlags = rights;
|
||||
|
||||
// Always send this back to the original client
|
||||
remoteClient.SendChangeUserRights(requester, target, rights);
|
||||
remoteClient.SendChangeUserRights(requester, friendID, rights);
|
||||
|
||||
//
|
||||
// Notify the friend
|
||||
//
|
||||
|
||||
// Try local
|
||||
if (LocalGrantRights(requester, target, myFlags, rights))
|
||||
if (LocalGrantRights(requester, friendID, myFlags, rights))
|
||||
return;
|
||||
|
||||
PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { target.ToString() });
|
||||
PresenceInfo[] friendSessions = PresenceService.GetAgents(new string[] { friendID.ToString() });
|
||||
if (friendSessions != null && friendSessions.Length > 0)
|
||||
{
|
||||
PresenceInfo friendSession = friendSessions[0];
|
||||
@@ -736,12 +751,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
GridRegion region = GridService.GetRegionByUUID(m_Scenes[0].RegionInfo.ScopeID, friendSession.RegionID);
|
||||
// TODO: You might want to send the delta to save the lookup
|
||||
// on the other end!!
|
||||
m_FriendsSimConnector.GrantRights(region, requester, target, myFlags, rights);
|
||||
m_FriendsSimConnector.GrantRights(region, requester, friendID, myFlags, rights);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
m_log.DebugFormat("[FRIENDS MODULE]: friend {0} not found for {1}", target, requester);
|
||||
{
|
||||
m_log.DebugFormat("[FRIENDS MODULE]: friend {0} not found for {1}", friendID, requester);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual FriendInfo GetFriend(FriendInfo[] friends, UUID friendID)
|
||||
@@ -779,6 +796,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
(byte)OpenMetaverse.InstantMessageDialog.FriendshipAccepted, userID.ToString(), false, Vector3.Zero);
|
||||
friendClient.SendInstantMessage(im);
|
||||
|
||||
ICallingCardModule ccm = friendClient.Scene.RequestModuleInterface<ICallingCardModule>();
|
||||
if (ccm != null)
|
||||
{
|
||||
ccm.CreateCallingCard(friendID, userID, UUID.Zero);
|
||||
}
|
||||
|
||||
// Update the local cache
|
||||
RecacheFriends(friendClient);
|
||||
|
||||
@@ -801,7 +824,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
// we're done
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -853,7 +876,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
|
||||
public bool LocalStatusNotification(UUID userID, UUID friendID, bool online)
|
||||
{
|
||||
// m_log.DebugFormat("[FRIENDS]: Local Status Notify {0} that user {1} is {2}", friendID, userID, online);
|
||||
//m_log.DebugFormat("[FRIENDS]: Local Status Notify {0} that user {1} is {2}", friendID, userID, online);
|
||||
IClientAPI friendClient = LocateClientObject(friendID);
|
||||
if (friendClient != null)
|
||||
{
|
||||
@@ -872,18 +895,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
#endregion
|
||||
|
||||
#region Get / Set friends in several flavours
|
||||
/// <summary>
|
||||
/// Get friends from local cache only
|
||||
/// </summary>
|
||||
/// <param name="agentID"></param>
|
||||
/// <returns></returns>
|
||||
protected FriendInfo[] GetFriends(UUID agentID)
|
||||
|
||||
public FriendInfo[] GetFriendsFromCache(UUID userID)
|
||||
{
|
||||
UserFriendData friendsData;
|
||||
|
||||
lock (m_Friends)
|
||||
{
|
||||
if (m_Friends.TryGetValue(agentID, out friendsData))
|
||||
if (m_Friends.TryGetValue(userID, out friendsData))
|
||||
return friendsData.Friends;
|
||||
}
|
||||
|
||||
@@ -901,13 +920,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
// Update local cache
|
||||
lock (m_Friends)
|
||||
{
|
||||
FriendInfo[] friends = GetFriends(friendID);
|
||||
FriendInfo[] friends = GetFriendsFromCache(friendID);
|
||||
FriendInfo finfo = GetFriend(friends, userID);
|
||||
finfo.TheirFlags = rights;
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual FriendInfo[] GetFriendsFromService(IClientAPI client)
|
||||
public virtual FriendInfo[] GetFriendsFromService(IClientAPI client)
|
||||
{
|
||||
return FriendsService.GetFriends(client.AgentId);
|
||||
}
|
||||
@@ -925,6 +944,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
}
|
||||
}
|
||||
|
||||
public bool AreFriendsCached(UUID userID)
|
||||
{
|
||||
lock (m_Friends)
|
||||
return m_Friends.ContainsKey(userID);
|
||||
}
|
||||
|
||||
protected virtual bool StoreRights(UUID agentID, UUID friendID, int rights)
|
||||
{
|
||||
FriendsService.StoreFriend(agentID.ToString(), friendID.ToString(), rights);
|
||||
@@ -938,8 +963,8 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
|
||||
protected virtual void StoreFriendships(UUID agentID, UUID friendID)
|
||||
{
|
||||
FriendsService.StoreFriend(agentID.ToString(), friendID.ToString(), 1);
|
||||
FriendsService.StoreFriend(friendID.ToString(), agentID.ToString(), 1);
|
||||
FriendsService.StoreFriend(agentID.ToString(), friendID.ToString(), (int)FriendRights.CanSeeOnline);
|
||||
FriendsService.StoreFriend(friendID.ToString(), agentID.ToString(), (int)FriendRights.CanSeeOnline);
|
||||
}
|
||||
|
||||
protected virtual bool DeleteFriendship(UUID agentID, UUID exfriendID)
|
||||
|
||||
@@ -94,6 +94,14 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
|
||||
#endregion
|
||||
|
||||
protected override void OnApproveFriendRequest(IClientAPI client, UUID friendID, List<UUID> callingCardFolders)
|
||||
{
|
||||
// Update the local cache. Yes, we need to do it right here
|
||||
// because the HGFriendsService placed something on the DB
|
||||
// from under the sim
|
||||
base.OnApproveFriendRequest(client, friendID, callingCardFolders);
|
||||
}
|
||||
|
||||
protected override bool CacheFriends(IClientAPI client)
|
||||
{
|
||||
// m_log.DebugFormat("[HGFRIENDS MODULE]: Entered CacheFriends for {0}", client.Name);
|
||||
@@ -144,7 +152,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
UserAccount account = m_Scenes[0].UserAccountService.GetUserAccount(client.Scene.RegionInfo.ScopeID, client.AgentId);
|
||||
if (account == null) // foreign
|
||||
{
|
||||
FriendInfo[] friends = GetFriends(client.AgentId);
|
||||
FriendInfo[] friends = GetFriendsFromCache(client.AgentId);
|
||||
foreach (FriendInfo f in friends)
|
||||
{
|
||||
client.SendChangeUserRights(new UUID(f.Friend), client.AgentId, f.TheirFlags);
|
||||
@@ -376,8 +384,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
protected override FriendInfo[] GetFriendsFromService(IClientAPI client)
|
||||
public override FriendInfo[] GetFriendsFromService(IClientAPI client)
|
||||
{
|
||||
// m_log.DebugFormat("[HGFRIENDS MODULE]: Entering GetFriendsFromService for {0}", client.Name);
|
||||
Boolean agentIsLocal = true;
|
||||
@@ -422,7 +429,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
|
||||
if (agentIsLocal) // agent is local, friend is foreigner
|
||||
{
|
||||
FriendInfo[] finfos = GetFriends(agentID);
|
||||
FriendInfo[] finfos = GetFriendsFromCache(agentID);
|
||||
FriendInfo finfo = GetFriend(finfos, friendID);
|
||||
if (finfo != null)
|
||||
{
|
||||
@@ -519,10 +526,12 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
{
|
||||
// This may happen when the agent returned home, in which case the friend is not there
|
||||
// We need to look for its information in the friends list itself
|
||||
FriendInfo[] finfos = null;
|
||||
bool confirming = false;
|
||||
if (friendUUI == string.Empty)
|
||||
{
|
||||
FriendInfo[] finfos = GetFriends(agentID);
|
||||
finfos = GetFriendsFromCache(agentID);
|
||||
|
||||
foreach (FriendInfo finfo in finfos)
|
||||
{
|
||||
if (finfo.TheirFlags == -1)
|
||||
@@ -606,7 +615,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
if (agentIsLocal) // agent is local, 'friend' is foreigner
|
||||
{
|
||||
// We need to look for its information in the friends list itself
|
||||
FriendInfo[] finfos = GetFriends(agentID);
|
||||
FriendInfo[] finfos = GetFriendsFromCache(agentID);
|
||||
FriendInfo finfo = GetFriend(finfos, exfriendID);
|
||||
if (finfo != null)
|
||||
{
|
||||
@@ -650,7 +659,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends
|
||||
private string GetUUI(UUID localUser, UUID foreignUser)
|
||||
{
|
||||
// Let's see if the user is here by any chance
|
||||
FriendInfo[] finfos = GetFriends(localUser);
|
||||
FriendInfo[] finfos = GetFriendsFromCache(localUser);
|
||||
if (finfos != EMPTY_FRIENDS) // friend is here, cool
|
||||
{
|
||||
FriendInfo finfo = GetFriend(finfos, foreignUser);
|
||||
|
||||
@@ -30,6 +30,7 @@ using System.Collections.Generic;
|
||||
using Nini.Config;
|
||||
using NUnit.Framework;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Data.Null;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.CoreModules.Avatar.Friends;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
@@ -44,9 +45,30 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests
|
||||
private FriendsModule m_fm;
|
||||
private TestScene m_scene;
|
||||
|
||||
[TestFixtureSetUp]
|
||||
public void FixtureInit()
|
||||
{
|
||||
// Don't allow tests to be bamboozled by asynchronous events. Execute everything on the same thread.
|
||||
Util.FireAndForgetMethod = FireAndForgetMethod.RegressionTest;
|
||||
}
|
||||
|
||||
[TestFixtureTearDown]
|
||||
public void TearDown()
|
||||
{
|
||||
// We must set this back afterwards, otherwise later tests will fail since they're expecting multiple
|
||||
// threads. Possibly, later tests should be rewritten so none of them require async stuff (which regression
|
||||
// tests really shouldn't).
|
||||
Util.FireAndForgetMethod = Util.DefaultFireAndForgetMethod;
|
||||
}
|
||||
|
||||
[SetUp]
|
||||
public void Init()
|
||||
{
|
||||
// We must clear friends data between tests since Data.Null holds it in static properties. This is necessary
|
||||
// so that different services and simulator can share the data in standalone mode. This is pretty horrible
|
||||
// effectively the statics are global variables.
|
||||
NullFriendsData.Clear();
|
||||
|
||||
IConfigSource config = new IniConfigSource();
|
||||
config.AddConfig("Modules");
|
||||
// Not strictly necessary since FriendsModule assumes it is the default (!)
|
||||
@@ -56,13 +78,13 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests
|
||||
config.AddConfig("FriendsService");
|
||||
config.Configs["FriendsService"].Set("StorageProvider", "OpenSim.Data.Null.dll");
|
||||
|
||||
m_scene = SceneHelpers.SetupScene();
|
||||
m_scene = new SceneHelpers().SetupScene();
|
||||
m_fm = new FriendsModule();
|
||||
SceneHelpers.SetupSceneModules(m_scene, config, m_fm);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestNoFriends()
|
||||
public void TestLoginWithNoFriends()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
@@ -75,6 +97,76 @@ namespace OpenSim.Region.CoreModules.Avatar.Friends.Tests
|
||||
Assert.That(((TestClient)sp.ControllingClient).ReceivedOnlineNotifications.Count, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLoginWithOfflineFriends()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
|
||||
UUID user1Id = TestHelpers.ParseTail(0x1);
|
||||
UUID user2Id = TestHelpers.ParseTail(0x2);
|
||||
|
||||
// UserAccountHelpers.CreateUserWithInventory(m_scene, user1Id);
|
||||
// UserAccountHelpers.CreateUserWithInventory(m_scene, user2Id);
|
||||
//
|
||||
// m_fm.AddFriendship(user1Id, user2Id);
|
||||
|
||||
ScenePresence sp1 = SceneHelpers.AddScenePresence(m_scene, user1Id);
|
||||
ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, user2Id);
|
||||
|
||||
m_fm.AddFriendship(sp1.ControllingClient, user2Id);
|
||||
|
||||
// Not necessary for this test. CanSeeOnline is automatically granted.
|
||||
// m_fm.GrantRights(sp1.ControllingClient, user2Id, (int)FriendRights.CanSeeOnline);
|
||||
|
||||
// We must logout from the client end so that the presence service is correctly updated by the presence
|
||||
// detector. This is listening to the OnConnectionClosed event on the client.
|
||||
((TestClient)sp1.ControllingClient).Logout();
|
||||
((TestClient)sp2.ControllingClient).Logout();
|
||||
// m_scene.RemoveClient(sp1.UUID, true);
|
||||
// m_scene.RemoveClient(sp2.UUID, true);
|
||||
|
||||
ScenePresence sp1Redux = SceneHelpers.AddScenePresence(m_scene, user1Id);
|
||||
|
||||
// We don't expect to receive notifications of offline friends on login, just online.
|
||||
Assert.That(((TestClient)sp1Redux.ControllingClient).ReceivedOfflineNotifications.Count, Is.EqualTo(0));
|
||||
Assert.That(((TestClient)sp1Redux.ControllingClient).ReceivedOnlineNotifications.Count, Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestLoginWithOnlineFriends()
|
||||
{
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
|
||||
UUID user1Id = TestHelpers.ParseTail(0x1);
|
||||
UUID user2Id = TestHelpers.ParseTail(0x2);
|
||||
|
||||
// UserAccountHelpers.CreateUserWithInventory(m_scene, user1Id);
|
||||
// UserAccountHelpers.CreateUserWithInventory(m_scene, user2Id);
|
||||
//
|
||||
// m_fm.AddFriendship(user1Id, user2Id);
|
||||
|
||||
ScenePresence sp1 = SceneHelpers.AddScenePresence(m_scene, user1Id);
|
||||
ScenePresence sp2 = SceneHelpers.AddScenePresence(m_scene, user2Id);
|
||||
|
||||
m_fm.AddFriendship(sp1.ControllingClient, user2Id);
|
||||
|
||||
// Not necessary for this test. CanSeeOnline is automatically granted.
|
||||
// m_fm.GrantRights(sp1.ControllingClient, user2Id, (int)FriendRights.CanSeeOnline);
|
||||
|
||||
// We must logout from the client end so that the presence service is correctly updated by the presence
|
||||
// detector. This is listening to the OnConnectionClosed event on the client.
|
||||
// ((TestClient)sp1.ControllingClient).Logout();
|
||||
((TestClient)sp2.ControllingClient).Logout();
|
||||
// m_scene.RemoveClient(user2Id, true);
|
||||
|
||||
ScenePresence sp2Redux = SceneHelpers.AddScenePresence(m_scene, user2Id);
|
||||
|
||||
Assert.That(((TestClient)sp2Redux.ControllingClient).ReceivedOfflineNotifications.Count, Is.EqualTo(0));
|
||||
Assert.That(((TestClient)sp2Redux.ControllingClient).ReceivedOnlineNotifications.Count, Is.EqualTo(1));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestAddFriendshipWhileOnline()
|
||||
{
|
||||
|
||||
@@ -108,7 +108,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
OnInventoryArchiveSaved += SaveInvConsoleCommandCompleted;
|
||||
|
||||
scene.AddCommand(
|
||||
this, "load iar",
|
||||
"Archiving", this, "load iar",
|
||||
"load iar [-m|--merge] <first> <last> <inventory path> <password> [<IAR path>]",
|
||||
"Load user inventory archive (IAR).",
|
||||
"-m|--merge is an option which merges the loaded IAR with existing inventory folders where possible, rather than always creating new ones"
|
||||
@@ -121,18 +121,18 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver
|
||||
HandleLoadInvConsoleCommand);
|
||||
|
||||
scene.AddCommand(
|
||||
this, "save iar",
|
||||
"Archiving", this, "save iar",
|
||||
"save iar [-h|--home=<url>] [--noassets] <first> <last> <inventory path> <password> [<IAR path>] [-c|--creators] [-v|--verbose]",
|
||||
"Save user inventory archive (IAR).",
|
||||
"<first> is the user's first name." + Environment.NewLine
|
||||
+ "<last> is the user's last name." + Environment.NewLine
|
||||
+ "<inventory path> is the path inside the user's inventory for the folder/item to be saved." + Environment.NewLine
|
||||
+ "-h|--home=<url> adds the url of the profile service to the saved user information." + Environment.NewLine
|
||||
+ "-c|--creators preserves information about foreign creators." + Environment.NewLine
|
||||
+ "-v|--verbose extra debug messages." + Environment.NewLine
|
||||
+ "--noassets stops assets being saved to the IAR."
|
||||
"<first> is the user's first name.\n"
|
||||
+ "<last> is the user's last name.\n"
|
||||
+ "<inventory path> is the path inside the user's inventory for the folder/item to be saved.\n"
|
||||
+ "<IAR path> is the filesystem path at which to save the IAR."
|
||||
+ string.Format(" If this is not given then the filename {0} in the current directory is used", DEFAULT_INV_BACKUP_FILENAME),
|
||||
+ string.Format(" If this is not given then the filename {0} in the current directory is used.\n", DEFAULT_INV_BACKUP_FILENAME)
|
||||
+ "-h|--home=<url> adds the url of the profile service to the saved user information.\n"
|
||||
+ "-c|--creators preserves information about foreign creators.\n"
|
||||
+ "-v|--verbose extra debug messages.\n"
|
||||
+ "--noassets stops assets being saved to the IAR.",
|
||||
HandleSaveInvConsoleCommand);
|
||||
|
||||
m_aScene = scene;
|
||||
|
||||
@@ -48,7 +48,7 @@ using OpenSim.Tests.Common.Mock;
|
||||
namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||
{
|
||||
[TestFixture]
|
||||
public class InventoryArchiveTestCase
|
||||
public class InventoryArchiveTestCase : OpenSimTestCase
|
||||
{
|
||||
protected ManualResetEvent mre = new ManualResetEvent(false);
|
||||
|
||||
@@ -84,8 +84,9 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||
protected string m_coaItemName = "Coalesced Item";
|
||||
|
||||
[SetUp]
|
||||
public virtual void SetUp()
|
||||
public override void SetUp()
|
||||
{
|
||||
base.SetUp();
|
||||
m_iarStream = new MemoryStream(m_iarStreamBytes);
|
||||
}
|
||||
|
||||
@@ -100,7 +101,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
|
||||
InventoryArchiverModule archiverModule = new InventoryArchiverModule();
|
||||
Scene scene = SceneHelpers.SetupScene();
|
||||
Scene scene = new SceneHelpers().SetupScene();
|
||||
SceneHelpers.SetupSceneModules(scene, archiverModule);
|
||||
|
||||
UserAccountHelpers.CreateUserWithInventory(scene, m_uaLL1, "hampshire");
|
||||
|
||||
@@ -61,7 +61,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||
SerialiserModule serialiserModule = new SerialiserModule();
|
||||
m_archiverModule = new InventoryArchiverModule();
|
||||
|
||||
m_scene = SceneHelpers.SetupScene();
|
||||
m_scene = new SceneHelpers().SetupScene();
|
||||
SceneHelpers.SetupSceneModules(m_scene, serialiserModule, m_archiverModule);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +62,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||
|
||||
InventoryArchiverModule archiverModule = new InventoryArchiverModule();
|
||||
|
||||
Scene scene = SceneHelpers.SetupScene();
|
||||
Scene scene = new SceneHelpers().SetupScene();
|
||||
SceneHelpers.SetupSceneModules(scene, archiverModule);
|
||||
|
||||
// Create user
|
||||
@@ -179,7 +179,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||
InventoryArchiverModule archiverModule = new InventoryArchiverModule();
|
||||
|
||||
// Annoyingly, we have to set up a scene even though inventory loading has nothing to do with a scene
|
||||
Scene scene = SceneHelpers.SetupScene();
|
||||
Scene scene = new SceneHelpers().SetupScene();
|
||||
|
||||
SceneHelpers.SetupSceneModules(scene, serialiserModule, archiverModule);
|
||||
|
||||
@@ -222,7 +222,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||
|
||||
SerialiserModule serialiserModule = new SerialiserModule();
|
||||
InventoryArchiverModule archiverModule = new InventoryArchiverModule();
|
||||
Scene scene = SceneHelpers.SetupScene();
|
||||
Scene scene = new SceneHelpers().SetupScene();
|
||||
SceneHelpers.SetupSceneModules(scene, serialiserModule, archiverModule);
|
||||
|
||||
UserAccountHelpers.CreateUserWithInventory(scene, m_uaMT, "password");
|
||||
@@ -247,7 +247,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||
|
||||
InventoryArchiverModule archiverModule = new InventoryArchiverModule();
|
||||
|
||||
Scene scene = SceneHelpers.SetupScene();
|
||||
Scene scene = new SceneHelpers().SetupScene();
|
||||
SceneHelpers.SetupSceneModules(scene, archiverModule);
|
||||
|
||||
// Create user
|
||||
@@ -326,7 +326,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
|
||||
Scene scene = SceneHelpers.SetupScene();
|
||||
Scene scene = new SceneHelpers().SetupScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene);
|
||||
|
||||
Dictionary <string, InventoryFolderBase> foldersCreated = new Dictionary<string, InventoryFolderBase>();
|
||||
@@ -393,7 +393,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||
TestHelpers.InMethod();
|
||||
//log4net.Config.XmlConfigurator.Configure();
|
||||
|
||||
Scene scene = SceneHelpers.SetupScene();
|
||||
Scene scene = new SceneHelpers().SetupScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene);
|
||||
|
||||
string folder1ExistingName = "a";
|
||||
@@ -444,7 +444,7 @@ namespace OpenSim.Region.CoreModules.Avatar.Inventory.Archiver.Tests
|
||||
TestHelpers.InMethod();
|
||||
// log4net.Config.XmlConfigurator.Configure();
|
||||
|
||||
Scene scene = SceneHelpers.SetupScene();
|
||||
Scene scene = new SceneHelpers().SetupScene();
|
||||
UserAccount ua1 = UserAccountHelpers.CreateUserWithInventory(scene);
|
||||
|
||||
string folder1ExistingName = "a";
|
||||
|
||||
@@ -240,13 +240,15 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
|
||||
{
|
||||
ScenePresence sp = scene.GetScenePresence(client.AgentId);
|
||||
IEntityTransferModule transferMod = scene.RequestModuleInterface<IEntityTransferModule>();
|
||||
IEventQueue eq = sp.Scene.RequestModuleInterface<IEventQueue>();
|
||||
if (transferMod != null && sp != null && eq != null)
|
||||
transferMod.DoTeleport(sp, gatekeeper, finalDestination, im.Position + new Vector3(0.5f, 0.5f, 0f), Vector3.UnitX, teleportflags, eq);
|
||||
|
||||
if (transferMod != null && sp != null)
|
||||
transferMod.DoTeleport(
|
||||
sp, gatekeeper, finalDestination, im.Position + new Vector3(0.5f, 0.5f, 0f),
|
||||
Vector3.UnitX, teleportflags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -151,11 +151,17 @@ namespace OpenSim.Region.CoreModules.Avatar.Lure
|
||||
Scene scene = (Scene)(client.Scene);
|
||||
ScenePresence presence = scene.GetScenePresence(client.AgentId);
|
||||
|
||||
// Round up Z co-ordinate rather than round-down by casting. This stops tall avatars from being given
|
||||
// a teleport Z co-ordinate by short avatars that drops them through or embeds them in thin floors on
|
||||
// arrival.
|
||||
//
|
||||
// Ideally we would give the exact float position adjusting for the relative height of the two avatars
|
||||
// but it looks like a float component isn't possible with a parcel ID.
|
||||
UUID dest = Util.BuildFakeParcelID(
|
||||
scene.RegionInfo.RegionHandle,
|
||||
(uint)presence.AbsolutePosition.X,
|
||||
(uint)presence.AbsolutePosition.Y,
|
||||
(uint)presence.AbsolutePosition.Z);
|
||||
(uint)Math.Ceiling(presence.AbsolutePosition.Z));
|
||||
|
||||
m_log.DebugFormat("TP invite with message {0}", message);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user