Compare commits
698 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5939529036 | ||
|
|
c8dcb8474d | ||
|
|
98f59ffed5 | ||
|
|
c61ff917ef | ||
|
|
f3b3e21dea | ||
|
|
fcb0349d56 | ||
|
|
e4f741f006 | ||
|
|
a2ee887c6d | ||
|
|
b4f1b9acf6 | ||
|
|
931eb892d9 | ||
|
|
4d93870fe5 | ||
|
|
5a1d6727e1 | ||
|
|
bc405a6a34 | ||
|
|
6825377380 | ||
|
|
3a26e366d2 | ||
|
|
ff4ad60207 | ||
|
|
ccee2959f7 | ||
|
|
a412b1d682 | ||
|
|
cd64a70c79 | ||
|
|
d06c85ea77 | ||
|
|
b4cb644a05 | ||
|
|
3d118fb580 | ||
|
|
fa02f28dbf | ||
|
|
3d700bb42c | ||
|
|
29f6ae199e | ||
|
|
65239b059f | ||
|
|
1909ee70f8 | ||
|
|
83d1680057 | ||
|
|
ba8f9c9d0a | ||
|
|
7c2e4786ce | ||
|
|
e15a15688b | ||
|
|
f57f49eede | ||
|
|
44e9849ed1 | ||
|
|
ee51a9f9c9 | ||
|
|
51d106cff8 | ||
|
|
c4f1ec1fd6 | ||
|
|
ea371a6f54 | ||
|
|
604967b31e | ||
|
|
3b48b6a792 | ||
|
|
0120e858b7 | ||
|
|
9173130fde | ||
|
|
fe5da43d15 | ||
|
|
bdaeb02863 | ||
|
|
864a86983e | ||
|
|
1b265b213b | ||
|
|
59d19f038a | ||
|
|
38e6da5522 | ||
|
|
bb6fb65392 | ||
|
|
cec8e6d0f7 | ||
|
|
095066b1ce | ||
|
|
d0dfb744b2 | ||
|
|
67e500383e | ||
|
|
2c761cef19 | ||
|
|
065f8f56a2 | ||
|
|
33eea62606 | ||
|
|
fad4241e4e | ||
|
|
76b2b20f7e | ||
|
|
5f58b9b552 | ||
|
|
83da14008f | ||
|
|
af9b17c545 | ||
|
|
2025dd25f6 | ||
|
|
047ef9c2a5 | ||
|
|
eccec4f8f6 | ||
|
|
8be59829d1 | ||
|
|
013710168b | ||
|
|
dc54581700 | ||
|
|
b2d4b8b1da | ||
|
|
c3db595944 | ||
|
|
e19defde36 | ||
|
|
a38c2abae4 | ||
|
|
c66a9a08e4 | ||
|
|
1e72e1b258 | ||
|
|
bbb9af363d | ||
|
|
bbc40fab62 | ||
|
|
6026759406 | ||
|
|
70d24a654b | ||
|
|
1286677352 | ||
|
|
803e5498b0 | ||
|
|
71e26555bd | ||
|
|
391633c072 | ||
|
|
1dd3a0bc57 | ||
|
|
9b75d75724 | ||
|
|
93fd5e4036 | ||
|
|
b29a09ab8e | ||
|
|
d838f15d97 | ||
|
|
a65cec3986 | ||
|
|
97698ae311 | ||
|
|
03268d85c4 | ||
|
|
5f97c6f8f0 | ||
|
|
c358d5d168 | ||
|
|
2f6ee8aee2 | ||
|
|
98de67d573 | ||
|
|
ccceb6d6d2 | ||
|
|
55ac8c83c7 | ||
|
|
a44ad01492 | ||
|
|
67407024a2 | ||
|
|
5dbdd5f8b4 | ||
|
|
dd15f95499 | ||
|
|
ca26583e6b | ||
|
|
c4506cf4f3 | ||
|
|
8265a88c4a | ||
|
|
f2f33b7577 | ||
|
|
d80936bbbb | ||
|
|
da3aa44138 | ||
|
|
33ddb6c246 | ||
|
|
c95a23863a | ||
|
|
38a04ff993 | ||
|
|
d997c49e47 | ||
|
|
ca380ec039 | ||
|
|
93ee515d9d | ||
|
|
fdafc2a16c | ||
|
|
bf214122cd | ||
|
|
15d0bc0900 | ||
|
|
ec9ffbb89a | ||
|
|
c61becc62b | ||
|
|
0cc0a2485c | ||
|
|
ae42c93f9a | ||
|
|
98a2fa8e35 | ||
|
|
068a3afad9 | ||
|
|
16f40c1a15 | ||
|
|
5eb78aad96 | ||
|
|
80f4a008eb | ||
|
|
27cdfb7b84 | ||
|
|
25889b2d7e | ||
|
|
119f84fe11 | ||
|
|
06dba1fa62 | ||
|
|
4d24bf75fd | ||
|
|
d01b8e163d | ||
|
|
316e8f9239 | ||
|
|
9725b829d5 | ||
|
|
2c05caec7f | ||
|
|
626940ceb8 | ||
|
|
e984bfb4c6 | ||
|
|
ccca005969 | ||
|
|
635704b7ef | ||
|
|
8eb86c9ec9 | ||
|
|
c24c99f4ba | ||
|
|
9d5ae75950 | ||
|
|
425d2a2a97 | ||
|
|
23516717e4 | ||
|
|
2f4a729d40 | ||
|
|
e377abcc35 | ||
|
|
c738368846 | ||
|
|
1e97972f78 | ||
|
|
d7775d1e11 | ||
|
|
1fc873d09f | ||
|
|
74e7fac13f | ||
|
|
20f2cf8769 | ||
|
|
c462e0a51c | ||
|
|
8fa5d12fcb | ||
|
|
0c97021565 | ||
|
|
ff47cf77ab | ||
|
|
00093a305d | ||
|
|
3a634c56e3 | ||
|
|
371085546d | ||
|
|
eed15703ed | ||
|
|
4406f07a84 | ||
|
|
4cb4c9fb25 | ||
|
|
cbb5122729 | ||
|
|
e26e8b8829 | ||
|
|
dc0455e217 | ||
|
|
f6ce87c96d | ||
|
|
529633d970 | ||
|
|
d47fc48b32 | ||
|
|
c1b8f83dd4 | ||
|
|
149487ea0f | ||
|
|
f7d09b898a | ||
|
|
f78d2ef166 | ||
|
|
ce9b1320d2 | ||
|
|
4b00203fa5 | ||
|
|
936700bda3 | ||
|
|
4bf1afe300 | ||
|
|
edb11a7eca | ||
|
|
6c7e33fe47 | ||
|
|
ca3ce6da73 | ||
|
|
4778d67005 | ||
|
|
74539659f6 | ||
|
|
a5de4f692b | ||
|
|
bbeff4b8ca | ||
|
|
a33b6eed6d | ||
|
|
085a87060a | ||
|
|
05790ba1cf | ||
|
|
5b1a9f84fd | ||
|
|
d97333255d | ||
|
|
3370e19205 | ||
|
|
086fd70a5f | ||
|
|
84af1cab9b | ||
|
|
8a86e29579 | ||
|
|
1a72f62d7b | ||
|
|
3fe5e9057f | ||
|
|
dda44e31e3 | ||
|
|
9501a583cb | ||
|
|
768e8e363b | ||
|
|
0767523834 | ||
|
|
a1e32b8437 | ||
|
|
b7c9dee033 | ||
|
|
c0a00cd7fd | ||
|
|
713a14a6b5 | ||
|
|
b9dac1f8df | ||
|
|
865d46ae1e | ||
|
|
2c9bb0f973 | ||
|
|
0d2fd0d914 | ||
|
|
694c4bcbb6 | ||
|
|
e6cb7b4764 | ||
|
|
42b0c68eab | ||
|
|
9c530d725f | ||
|
|
ecfc6a3f4a | ||
|
|
720806b661 | ||
|
|
da3724a904 | ||
|
|
f074739e33 | ||
|
|
fc89bde044 | ||
|
|
db9d9d83eb | ||
|
|
d412c1b0eb | ||
|
|
d7f3d7efd2 | ||
|
|
b2c8d5eec7 | ||
|
|
b271217084 | ||
|
|
7c00ccb548 | ||
|
|
6b8e94864a | ||
|
|
7759b05dcb | ||
|
|
3357300362 | ||
|
|
824a4b4808 | ||
|
|
ef5be42c86 | ||
|
|
47b6e78790 | ||
|
|
7a17c3720b | ||
|
|
9fec0faade | ||
|
|
3cb65f0d31 | ||
|
|
9f8a8f3719 | ||
|
|
90097de6c3 | ||
|
|
7556a0f699 | ||
|
|
135e10ba09 | ||
|
|
d8da83b4ff | ||
|
|
a0fed03e10 | ||
|
|
b33db917f5 | ||
|
|
26b66c730e | ||
|
|
d47a18fd09 | ||
|
|
ed950e6c74 | ||
|
|
ba84074468 | ||
|
|
9d9b9d4938 | ||
|
|
b242ead6df | ||
|
|
1c7fbb86c2 | ||
|
|
a949556c4e | ||
|
|
7af97f88b7 | ||
|
|
32d1e50565 | ||
|
|
a2f1cd87f8 | ||
|
|
82e3b9a6e0 | ||
|
|
795acaa6aa | ||
|
|
57141e34bf | ||
|
|
7de0912a97 | ||
|
|
e741e5ebce | ||
|
|
4e2e69bd25 | ||
|
|
d00770d56b | ||
|
|
75e4af9d39 | ||
|
|
34d40e46a5 | ||
|
|
1cb1245d84 | ||
|
|
1387224821 | ||
|
|
6aa54a8e16 | ||
|
|
07cc16ff9c | ||
|
|
3a722ef81b | ||
|
|
75631e0267 | ||
|
|
7c0bfca7a0 | ||
|
|
454499ff60 | ||
|
|
346eda27cc | ||
|
|
f2a4d9b99c | ||
|
|
a74e65200c | ||
|
|
045c26f626 | ||
|
|
664c6191ed | ||
|
|
ac9c37f31b | ||
|
|
06012f8675 | ||
|
|
25fa647a74 | ||
|
|
2ebf70d719 | ||
|
|
a3210d1cf8 | ||
|
|
81ad9255b5 | ||
|
|
e1d98c9e4c | ||
|
|
26cd59cd6f | ||
|
|
e53b62304f | ||
|
|
a7dbafb0e3 | ||
|
|
e449950030 | ||
|
|
cd64da8746 | ||
|
|
47ffa12078 | ||
|
|
f41fc4eb25 | ||
|
|
10572b78f8 | ||
|
|
b4f472c4fa | ||
|
|
b5d0ac4c42 | ||
|
|
0c971d148c | ||
|
|
43d804b998 | ||
|
|
07058b044b | ||
|
|
d7fa9f671e | ||
|
|
ba2f13db63 | ||
|
|
217c7d1140 | ||
|
|
921ad8704e | ||
|
|
00c1586ff8 | ||
|
|
bf03523323 | ||
|
|
5b3a443125 | ||
|
|
924a5df25f | ||
|
|
e85c70223a | ||
|
|
4d32ca19bf | ||
|
|
48a175eff7 | ||
|
|
439f11cc3c | ||
|
|
3aa2fb9928 | ||
|
|
46335b103e | ||
|
|
328883700a | ||
|
|
6b88a665d3 | ||
|
|
12a3b85561 | ||
|
|
8f9a726465 | ||
|
|
cc7aa88b26 | ||
|
|
f9ee9efb97 | ||
|
|
4898f18f89 | ||
|
|
233b9ec4d7 | ||
|
|
7e1c7f54c7 | ||
|
|
ae0d6ab28a | ||
|
|
7c3a46ccea | ||
|
|
0c35d28933 | ||
|
|
533bbf033d | ||
|
|
1821372634 | ||
|
|
5f1f5ea5ab | ||
|
|
4979940def | ||
|
|
81a6c39781 | ||
|
|
a087dbed7f | ||
|
|
bb0ea25090 | ||
|
|
681fbda4b6 | ||
|
|
440905ad14 | ||
|
|
21a3a81c7a | ||
|
|
0cdea5c2f3 | ||
|
|
eb2bd9d203 | ||
|
|
02fe05f346 | ||
|
|
e597a7d94e | ||
|
|
9b56f99326 | ||
|
|
d90d8e9999 | ||
|
|
c5549d2730 | ||
|
|
0d5566e879 | ||
|
|
28548ab347 | ||
|
|
0e002e3693 | ||
|
|
29b3b44fab | ||
|
|
5efce21abc | ||
|
|
f490522082 | ||
|
|
ffc9b3dda7 | ||
|
|
61cdf9390d | ||
|
|
7d38f4940c | ||
|
|
6596a1de80 | ||
|
|
10097f13aa | ||
|
|
2fd8819a04 | ||
|
|
9de3979f5b | ||
|
|
ece7b33a96 | ||
|
|
06ab168897 | ||
|
|
ba6a6b2d40 | ||
|
|
434c3cf83b | ||
|
|
5c8d38d6cf | ||
|
|
6edecd5d94 | ||
|
|
c47de9878d | ||
|
|
6ae426c96b | ||
|
|
10e4fb2ce2 | ||
|
|
26904cc5a1 | ||
|
|
e65d1e459e | ||
|
|
477bee6468 | ||
|
|
fa8f5bafb2 | ||
|
|
214bae1479 | ||
|
|
ec818a506b | ||
|
|
61f4ab6674 | ||
|
|
3bc8cf65a4 | ||
|
|
d214e2d0c4 | ||
|
|
bd31821792 | ||
|
|
46eb8465a0 | ||
|
|
71a5cc2041 | ||
|
|
12289c4fd1 | ||
|
|
a4290cdbb3 | ||
|
|
177a53fbcf | ||
|
|
23ebae1828 | ||
|
|
df2a0fec5f | ||
|
|
ce979552fd | ||
|
|
e9847a4dbd | ||
|
|
f8bb90d963 | ||
|
|
91091c3e54 | ||
|
|
03fddb301b | ||
|
|
b135f1d58a | ||
|
|
645da54f25 | ||
|
|
66c328f51b | ||
|
|
f32a21d967 | ||
|
|
c86e828dbf | ||
|
|
15360cbb6b | ||
|
|
45f37e11ad | ||
|
|
4194d935ec | ||
|
|
af1fa95875 | ||
|
|
25fea82049 | ||
|
|
a4431381fa | ||
|
|
ab4d530462 | ||
|
|
48f8b884c3 | ||
|
|
55c9bc15e5 | ||
|
|
81d8deb1a8 | ||
|
|
a42bb799cc | ||
|
|
a1031772eb | ||
|
|
ff0332730d | ||
|
|
292a6037ad | ||
|
|
0e6ad94829 | ||
|
|
9978f36d9f | ||
|
|
b4a6f2195d | ||
|
|
3290cd09d3 | ||
|
|
2cb2f1d7e3 | ||
|
|
2b0b9f3e6c | ||
|
|
641c636790 | ||
|
|
182ea00cb3 | ||
|
|
543d1fe70b | ||
|
|
33aaa40bee | ||
|
|
601aa91163 | ||
|
|
6f5222e863 | ||
|
|
e92c05ebbd | ||
|
|
ac6dcd35fb | ||
|
|
f247ae1a75 | ||
|
|
ddd97cb78e | ||
|
|
84118c5735 | ||
|
|
1c6b8293d7 | ||
|
|
5d5edde429 | ||
|
|
4c83b5e719 | ||
|
|
93e1986d69 | ||
|
|
045aaa838a | ||
|
|
bf31896983 | ||
|
|
f9fb1484aa | ||
|
|
90f03ccd42 | ||
|
|
a81ddf3d70 | ||
|
|
ad00466483 | ||
|
|
1ffa69f691 | ||
|
|
5d25bb3084 | ||
|
|
5d93c99e8c | ||
|
|
7ca42d5711 | ||
|
|
304c5d4a8b | ||
|
|
4042c82a72 | ||
|
|
d9c3947824 | ||
|
|
a9480aed85 | ||
|
|
4cb73192a7 | ||
|
|
ed46b42fea | ||
|
|
0378baed35 | ||
|
|
04f76af22c | ||
|
|
e3d9d5566a | ||
|
|
386d67ec61 | ||
|
|
854dcd1abd | ||
|
|
c6d50cd431 | ||
|
|
b26276c8c4 | ||
|
|
fca4e4ec7c | ||
|
|
81a90e30c6 | ||
|
|
8d3250cee4 | ||
|
|
206fb306a7 | ||
|
|
ac135c649c | ||
|
|
46ae84cfba | ||
|
|
7cdb07b386 | ||
|
|
d322625f90 | ||
|
|
15a3f80e2e | ||
|
|
3ce198165c | ||
|
|
537b243360 | ||
|
|
67789201c3 | ||
|
|
0beccf23c0 | ||
|
|
a7cbb9edc9 | ||
|
|
12054aaa9f | ||
|
|
92ee288d66 | ||
|
|
ad1787770e | ||
|
|
21ec434688 | ||
|
|
f2d408829b | ||
|
|
2da8e60b6d | ||
|
|
e5582939fd | ||
|
|
890cb6a293 | ||
|
|
3ff7391495 | ||
|
|
a517e597f5 | ||
|
|
a49c5291dc | ||
|
|
222f530411 | ||
|
|
90a6891a7d | ||
|
|
f675d465b2 | ||
|
|
12599c34e2 | ||
|
|
cbb3bb62da | ||
|
|
ef08ab68a7 | ||
|
|
2262b13048 | ||
|
|
0e162511cf | ||
|
|
03c9d8ae4f | ||
|
|
5d0a8ff391 | ||
|
|
3bc8017464 | ||
|
|
c10405330d | ||
|
|
0e22021c65 | ||
|
|
ec4f981f1d | ||
|
|
5cd77a460c | ||
|
|
6f3c905744 | ||
|
|
1593d795ea | ||
|
|
1868680848 | ||
|
|
70081a40a4 | ||
|
|
c22a2ab7d2 | ||
|
|
e324f6f3f0 | ||
|
|
522ab85045 | ||
|
|
ed22014646 | ||
|
|
115e0aaf83 | ||
|
|
e1ac683154 | ||
|
|
293a024c14 | ||
|
|
6ddc39a676 | ||
|
|
46e4ecadc8 | ||
|
|
69f07fdb34 | ||
|
|
855c88a9c0 | ||
|
|
f40abc493a | ||
|
|
233f761779 | ||
|
|
258804cc04 | ||
|
|
9ae24cac2f | ||
|
|
06829c4082 | ||
|
|
d5419f0a46 | ||
|
|
7c839f176f | ||
|
|
53122fad40 | ||
|
|
ce043c5141 | ||
|
|
d4fa2c69ed | ||
|
|
c5de9840b0 | ||
|
|
5f2cbfc0fd | ||
|
|
b53713cdda | ||
|
|
9cc41d5118 | ||
|
|
59135c9a31 | ||
|
|
17fd075f39 | ||
|
|
148e46563f | ||
|
|
29e28f4b84 | ||
|
|
e20b0d5695 | ||
|
|
06068444e2 | ||
|
|
659c741ff5 | ||
|
|
8690a08881 | ||
|
|
aab2b032aa | ||
|
|
8e04c752fc | ||
|
|
4d2203ff52 | ||
|
|
f68b963596 | ||
|
|
99f39836a1 | ||
|
|
a7a1b8b7e9 | ||
|
|
fe16dc09da | ||
|
|
c7cd077e55 | ||
|
|
7f070236f7 | ||
|
|
0f008d5f7d | ||
|
|
d2367968e4 | ||
|
|
f064075a85 | ||
|
|
f281a994e8 | ||
|
|
831e4c3850 | ||
|
|
94d44142e3 | ||
|
|
7bf1986e91 | ||
|
|
97f0c9da84 | ||
|
|
c0319daa40 | ||
|
|
3332af4060 | ||
|
|
a3c723ee30 | ||
|
|
68c8633ba1 | ||
|
|
17aef1c883 | ||
|
|
ebc1209fc9 | ||
|
|
2bfe60e2fb | ||
|
|
69bc37acd6 | ||
|
|
0dce496499 | ||
|
|
600087ab49 | ||
|
|
4153cfbf14 | ||
|
|
84eb25da23 | ||
|
|
933ac60746 | ||
|
|
7d50015a74 | ||
|
|
75b8cf428e | ||
|
|
747ece59d2 | ||
|
|
2c581cae2a | ||
|
|
9b83e53b28 | ||
|
|
9fee431cc8 | ||
|
|
f8785b5f47 | ||
|
|
76629289f0 | ||
|
|
cbc9ae898c | ||
|
|
023faa227e | ||
|
|
23ae4c0a4d | ||
|
|
e89bcf4f77 | ||
|
|
4dfffa1df3 | ||
|
|
d87ddf50fc | ||
|
|
285bd3abc8 | ||
|
|
c92654fb43 | ||
|
|
2b142f2f9e | ||
|
|
feffc8081d | ||
|
|
03e421bf3d | ||
|
|
4ad9b27530 | ||
|
|
3b377f16b2 | ||
|
|
e97567e227 | ||
|
|
c2093ccce1 | ||
|
|
6a9630d2bd | ||
|
|
3f9b274180 | ||
|
|
9ca54d00d8 | ||
|
|
afd0d6af07 | ||
|
|
d9c049fd9f | ||
|
|
b05ed4ffa6 | ||
|
|
506d5e41bf | ||
|
|
617637c788 | ||
|
|
b5b01e5bb5 | ||
|
|
876d0d310f | ||
|
|
f32027f3b5 | ||
|
|
cfb20f09a9 | ||
|
|
dd7d7683c9 | ||
|
|
da5dbaf1d0 | ||
|
|
3072f257f5 | ||
|
|
abde0d4efb | ||
|
|
13170ca627 | ||
|
|
3f0f313a76 | ||
|
|
e82fab34d7 | ||
|
|
5f4c4df227 | ||
|
|
285dc554ec | ||
|
|
c96a6f1de6 | ||
|
|
953090fd62 | ||
|
|
f783b9169f | ||
|
|
128c72a234 | ||
|
|
01636ca900 | ||
|
|
93206ef0fa | ||
|
|
c4d9a23f26 | ||
|
|
1f17ef6d3c | ||
|
|
7471bc7775 | ||
|
|
476a7d3eee | ||
|
|
e23a0dcc5d | ||
|
|
46c833810c | ||
|
|
4de530af45 | ||
|
|
b1cd1d917e | ||
|
|
16af5b87f8 | ||
|
|
36651bed71 | ||
|
|
8de933ab07 | ||
|
|
c0ff5635ba | ||
|
|
3cb1c23554 | ||
|
|
9151b9d233 | ||
|
|
90b9121e66 | ||
|
|
3648164219 | ||
|
|
c2e4f8aed5 | ||
|
|
1dd2d432f1 | ||
|
|
8360223fed | ||
|
|
8510f57ad4 | ||
|
|
397379cd3f | ||
|
|
55ab6f015a | ||
|
|
5e1f651e21 | ||
|
|
0635d9d174 | ||
|
|
e4a70b9f9a | ||
|
|
d07943c262 | ||
|
|
fcecfc81bb | ||
|
|
3611d33b00 | ||
|
|
a7a9a8a614 | ||
|
|
46a81b3527 | ||
|
|
464201b41d | ||
|
|
fc84ebb819 | ||
|
|
6e1b3f9951 | ||
|
|
03075359b5 | ||
|
|
7e5d553781 | ||
|
|
35843e8ec8 | ||
|
|
e9f3cd1a60 | ||
|
|
45dee383db | ||
|
|
bd0c1d9b6a | ||
|
|
d05af4bdad | ||
|
|
7fb458b055 | ||
|
|
3a7d9f740e | ||
|
|
8cc3adb585 | ||
|
|
924d6e892a | ||
|
|
032b645e80 | ||
|
|
78b25094dc | ||
|
|
c10c43d6f6 | ||
|
|
d3e76730bd | ||
|
|
cb74186888 | ||
|
|
e25ba116a3 | ||
|
|
081271e1d7 | ||
|
|
12900ea84e | ||
|
|
2fbc08d7dd | ||
|
|
0ea0f8aa83 | ||
|
|
56b333f301 | ||
|
|
55204ccde6 | ||
|
|
f8dab4f93f | ||
|
|
ca99f418d8 | ||
|
|
c1115e4c2e | ||
|
|
c09f4ff483 | ||
|
|
114fd042de | ||
|
|
d4b109b4c4 | ||
|
|
2a81eb8d45 | ||
|
|
b23009e480 | ||
|
|
a6f8638174 | ||
|
|
dd6f1fc637 | ||
|
|
e7603f98b7 | ||
|
|
e6eb914675 | ||
|
|
f8c24b2a61 | ||
|
|
3c9bea1e3f | ||
|
|
7b85279dba | ||
|
|
ff6a16b46e | ||
|
|
895aa7346f | ||
|
|
1774c631cb | ||
|
|
04e806036f | ||
|
|
ffbbe29229 | ||
|
|
c3e081a5ca | ||
|
|
f840728273 | ||
|
|
ad9bd3fe93 | ||
|
|
e9c394fb4e | ||
|
|
9fad90a914 | ||
|
|
42c533c589 | ||
|
|
43220afda2 | ||
|
|
48d41ef307 | ||
|
|
39a0928052 | ||
|
|
5c53660a7f | ||
|
|
b7216f4daf | ||
|
|
f8a4d95bdd | ||
|
|
0d25be3f81 | ||
|
|
fb1211ad5e | ||
|
|
c43d4b5572 | ||
|
|
0c6268fe56 | ||
|
|
be686f80a3 | ||
|
|
e898a5fec5 | ||
|
|
13f3bcae94 | ||
|
|
1120bcf123 | ||
|
|
5097437e11 | ||
|
|
33dab49d22 | ||
|
|
2f1aa87eb5 | ||
|
|
fdebee25db | ||
|
|
2b0056eaca | ||
|
|
6706e189d5 | ||
|
|
2fe938d11d | ||
|
|
5751ecde52 | ||
|
|
8960418e7d |
@@ -58,7 +58,7 @@ where we are today.
|
||||
|
||||
|
||||
= Additional OpenSim Contributors =
|
||||
These folks have contributed code patches to OpenSim to help make it
|
||||
These folks have contributed code patches or content to OpenSimulator to help make it
|
||||
what it is today.
|
||||
|
||||
* aduffy70
|
||||
@@ -75,11 +75,12 @@ what it is today.
|
||||
* controlbreak
|
||||
* coyled
|
||||
* Daedius
|
||||
* Dong Jun Lan (IBM)
|
||||
* DoranZemlja
|
||||
* daTwitch
|
||||
* devalnor-#708
|
||||
* dmiles (Daxtron Labs)
|
||||
* Dong Jun Lan (IBM)
|
||||
* DoranZemlja
|
||||
* dr0b3rts
|
||||
* dslake (Intel)
|
||||
* FredoChaplin
|
||||
* Garmin Kawaguichi
|
||||
@@ -101,6 +102,7 @@ what it is today.
|
||||
* jhurliman
|
||||
* John R Sohn (XenReborn)
|
||||
* jonc
|
||||
* Jon Cundill
|
||||
* Junta Kohime
|
||||
* Kayne
|
||||
* Kevin Cozens
|
||||
@@ -155,11 +157,13 @@ what it is today.
|
||||
* tglion
|
||||
* tlaukkan/Tommil (Tommi S. E. Laukkanen, Bubble Cloud)
|
||||
* tyre
|
||||
* Vegaslon <vegaslon@gmail.com>
|
||||
* VikingErik
|
||||
* Vytek
|
||||
* webmage (IBM)
|
||||
* Xantor
|
||||
* Y. Nitta
|
||||
* YoshikoFazuku
|
||||
* YZh
|
||||
* Zackary Geers aka Kunnis Basiat
|
||||
* Zha Ewry
|
||||
@@ -212,5 +216,3 @@ In addition, we would like to thank:
|
||||
* The Mono Project
|
||||
* The NANT Developers
|
||||
* Microsoft (.NET, MSSQL-Adapters)
|
||||
*x
|
||||
|
||||
|
||||
@@ -347,7 +347,7 @@ namespace OpenSim.Groups
|
||||
{
|
||||
if (m_debugEnabled) m_log.DebugFormat("[Groups]: {0} called", System.Reflection.MethodBase.GetCurrentMethod().Name);
|
||||
|
||||
m_log.DebugFormat("[Groups]: IM From {0} to {1} msg {2} type {3}", im.fromAgentID, im.toAgentID, im.message, (InstantMessageDialog)im.dialog);
|
||||
//m_log.DebugFormat("[Groups]: IM From {0} to {1} msg {2} type {3}", im.fromAgentID, im.toAgentID, im.message, (InstantMessageDialog)im.dialog);
|
||||
// Group invitations
|
||||
if ((im.dialog == (byte)InstantMessageDialog.GroupInvitationAccept) || (im.dialog == (byte)InstantMessageDialog.GroupInvitationDecline))
|
||||
{
|
||||
@@ -485,7 +485,7 @@ namespace OpenSim.Groups
|
||||
return;
|
||||
|
||||
//// 16 bytes are the UUID. Maybe.
|
||||
UUID folderID = new UUID(im.binaryBucket, 0);
|
||||
// UUID folderID = new UUID(im.binaryBucket, 0);
|
||||
UUID noticeID = new UUID(im.imSessionID);
|
||||
|
||||
GroupNoticeInfo notice = m_groupData.GetGroupNotice(remoteClient.AgentId.ToString(), noticeID);
|
||||
@@ -766,14 +766,17 @@ namespace OpenSim.Groups
|
||||
remoteClient.SendCreateGroupReply(UUID.Zero, false, "Insufficient funds to create a group.");
|
||||
return UUID.Zero;
|
||||
}
|
||||
money.ApplyCharge(remoteClient.AgentId, money.GroupCreationCharge, "Group Creation");
|
||||
}
|
||||
|
||||
string reason = string.Empty;
|
||||
UUID groupID = m_groupData.CreateGroup(remoteClient.AgentId, name, charter, showInList, insigniaID, membershipFee, openEnrollment,
|
||||
allowPublish, maturePublish, remoteClient.AgentId, out reason);
|
||||
|
||||
if (groupID != UUID.Zero)
|
||||
{
|
||||
if (money != null)
|
||||
money.ApplyCharge(remoteClient.AgentId, money.GroupCreationCharge, MoneyTransactionType.GroupCreate);
|
||||
|
||||
remoteClient.SendCreateGroupReply(groupID, true, "Group created successfullly");
|
||||
|
||||
// Update the founder with new group information.
|
||||
|
||||
@@ -186,7 +186,6 @@ namespace OpenSim.Groups
|
||||
public UUID CreateGroup(UUID RequestingAgentID, string name, string charter, bool showInList, UUID insigniaID, int membershipFee, bool openEnrollment,
|
||||
bool allowPublish, bool maturePublish, UUID founderID, out string reason)
|
||||
{
|
||||
m_log.DebugFormat("[Groups]: Creating group {0}", name);
|
||||
reason = string.Empty;
|
||||
if (m_UserManagement.IsLocalGridUser(RequestingAgentID))
|
||||
return m_LocalGroupsConnector.CreateGroup(RequestingAgentID, name, charter, showInList, insigniaID,
|
||||
@@ -544,7 +543,6 @@ namespace OpenSim.Groups
|
||||
List<string> urls = new List<string>();
|
||||
foreach (GroupMembersData m in members)
|
||||
{
|
||||
UUID userID = UUID.Zero;
|
||||
if (!m_UserManagement.IsLocalGridUser(m.AgentID))
|
||||
{
|
||||
string gURL = m_UserManagement.GetUserServerURL(m.AgentID, "GroupsServerURI");
|
||||
@@ -685,6 +683,9 @@ namespace OpenSim.Groups
|
||||
{
|
||||
serviceLocation = string.Empty;
|
||||
name = string.Empty;
|
||||
if (groupID.Equals(UUID.Zero))
|
||||
return true;
|
||||
|
||||
ExtendedGroupRecord group = m_LocalGroupsConnector.GetGroupRecord(UUID.Zero.ToString(), groupID, string.Empty);
|
||||
if (group == null)
|
||||
{
|
||||
|
||||
@@ -47,7 +47,6 @@ namespace OpenSim.Groups
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private HGGroupsService m_GroupsService;
|
||||
private string m_HomeURI = string.Empty;
|
||||
private string m_ConfigName = "Groups";
|
||||
|
||||
// Called by Robust shell
|
||||
@@ -113,7 +112,7 @@ namespace OpenSim.Groups
|
||||
m_GroupsService = service;
|
||||
}
|
||||
|
||||
public override byte[] Handle(string path, Stream requestData,
|
||||
protected override byte[] ProcessRequest(string path, Stream requestData,
|
||||
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
StreamReader sr = new StreamReader(requestData);
|
||||
@@ -209,7 +208,6 @@ namespace OpenSim.Groups
|
||||
UUID groupID = new UUID(request["GroupID"].ToString());
|
||||
string agentID = request["AgentID"].ToString();
|
||||
string token = request["AccessToken"].ToString();
|
||||
string reason = string.Empty;
|
||||
|
||||
m_GroupsService.RemoveAgentFromGroup(agentID, agentID, groupID, token);
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace OpenSim.Groups
|
||||
m_GroupsService = service;
|
||||
}
|
||||
|
||||
public override byte[] Handle(string path, Stream requestData,
|
||||
protected override byte[] ProcessRequest(string path, Stream requestData,
|
||||
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
StreamReader sr = new StreamReader(requestData);
|
||||
@@ -170,11 +170,16 @@ namespace OpenSim.Groups
|
||||
|
||||
}
|
||||
|
||||
grec = m_GroupsService.GetGroupRecord(RequestingAgentID, grec.GroupID);
|
||||
if (grec == null)
|
||||
NullResult(result, "Internal Error");
|
||||
if (grec.GroupID != UUID.Zero)
|
||||
{
|
||||
grec = m_GroupsService.GetGroupRecord(RequestingAgentID, grec.GroupID);
|
||||
if (grec == null)
|
||||
NullResult(result, "Internal Error");
|
||||
else
|
||||
result["RESULT"] = GroupsDataUtils.GroupRecord(grec);
|
||||
}
|
||||
else
|
||||
result["RESULT"] = GroupsDataUtils.GroupRecord(grec);
|
||||
NullResult(result, reason);
|
||||
}
|
||||
|
||||
string xmlString = ServerUtils.BuildXmlResponse(result);
|
||||
@@ -264,7 +269,6 @@ namespace OpenSim.Groups
|
||||
UUID groupID = new UUID(request["GroupID"].ToString());
|
||||
string agentID = request["AgentID"].ToString();
|
||||
string requestingAgentID = request["RequestingAgentID"].ToString();
|
||||
string reason = string.Empty;
|
||||
|
||||
m_GroupsService.RemoveAgentFromGroup(requestingAgentID, agentID, groupID);
|
||||
}
|
||||
@@ -495,7 +499,6 @@ namespace OpenSim.Groups
|
||||
else
|
||||
{
|
||||
string op = request["OP"].ToString();
|
||||
string reason = string.Empty;
|
||||
|
||||
bool success = false;
|
||||
if (op == "ADD")
|
||||
@@ -563,7 +566,6 @@ namespace OpenSim.Groups
|
||||
else
|
||||
{
|
||||
string op = request["OP"].ToString();
|
||||
string reason = string.Empty;
|
||||
|
||||
if (op == "GROUP")
|
||||
{
|
||||
@@ -626,7 +628,6 @@ namespace OpenSim.Groups
|
||||
else
|
||||
{
|
||||
string op = request["OP"].ToString();
|
||||
string reason = string.Empty;
|
||||
|
||||
if (op == "ADD" && request.ContainsKey("GroupID") && request.ContainsKey("RoleID") && request.ContainsKey("AgentID"))
|
||||
{
|
||||
|
||||
@@ -209,13 +209,10 @@ namespace OpenSim.Groups
|
||||
public void SetAgentActiveGroup(string AgentID, GroupMembershipDelegate d)
|
||||
{
|
||||
GroupMembershipData activeGroup = d();
|
||||
if (activeGroup != null)
|
||||
{
|
||||
string cacheKey = "active-" + AgentID.ToString();
|
||||
lock (m_Cache)
|
||||
if (m_Cache.Contains(cacheKey))
|
||||
m_Cache.AddOrUpdate(cacheKey, activeGroup, GROUPS_CACHE_TIMEOUT);
|
||||
}
|
||||
string cacheKey = "active-" + AgentID.ToString();
|
||||
lock (m_Cache)
|
||||
if (m_Cache.Contains(cacheKey))
|
||||
m_Cache.AddOrUpdate(cacheKey, activeGroup, GROUPS_CACHE_TIMEOUT);
|
||||
}
|
||||
|
||||
public ExtendedGroupMembershipData GetAgentActiveMembership(string AgentID, GroupMembershipDelegate d)
|
||||
|
||||
@@ -130,6 +130,13 @@ namespace OpenSim.Groups
|
||||
{
|
||||
reason = string.Empty;
|
||||
|
||||
// Check if the group already exists
|
||||
if (m_Database.RetrieveGroup(name) != null)
|
||||
{
|
||||
reason = "A group with that name already exists";
|
||||
return UUID.Zero;
|
||||
}
|
||||
|
||||
// Create the group
|
||||
GroupData data = new GroupData();
|
||||
data.GroupID = UUID.Random();
|
||||
@@ -723,12 +730,12 @@ namespace OpenSim.Groups
|
||||
|
||||
#region Actions without permission checks
|
||||
|
||||
private void _AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
|
||||
protected void _AddAgentToGroup(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
|
||||
{
|
||||
_AddAgentToGroup(RequestingAgentID, AgentID, GroupID, RoleID, string.Empty);
|
||||
}
|
||||
|
||||
public void _RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
|
||||
protected void _RemoveAgentFromGroup(string RequestingAgentID, string AgentID, UUID GroupID)
|
||||
{
|
||||
// 1. Delete membership
|
||||
m_Database.DeleteMember(GroupID, AgentID);
|
||||
@@ -780,7 +787,7 @@ namespace OpenSim.Groups
|
||||
|
||||
}
|
||||
|
||||
private bool _AddOrUpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, bool add)
|
||||
protected bool _AddOrUpdateGroupRole(string RequestingAgentID, UUID groupID, UUID roleID, string name, string description, string title, ulong powers, bool add)
|
||||
{
|
||||
RoleData data = m_Database.RetrieveRole(groupID, roleID);
|
||||
|
||||
@@ -810,12 +817,12 @@ namespace OpenSim.Groups
|
||||
return m_Database.StoreRole(data);
|
||||
}
|
||||
|
||||
private void _RemoveGroupRole(UUID groupID, UUID roleID)
|
||||
protected void _RemoveGroupRole(UUID groupID, UUID roleID)
|
||||
{
|
||||
m_Database.DeleteRole(groupID, roleID);
|
||||
}
|
||||
|
||||
private void _AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
|
||||
protected void _AddAgentToGroupRole(string RequestingAgentID, string AgentID, UUID GroupID, UUID RoleID)
|
||||
{
|
||||
RoleMembershipData data = m_Database.RetrieveRoleMember(GroupID, RoleID, AgentID);
|
||||
if (data != null)
|
||||
@@ -840,7 +847,7 @@ namespace OpenSim.Groups
|
||||
|
||||
}
|
||||
|
||||
private List<GroupRolesData> _GetGroupRoles(UUID groupID)
|
||||
protected List<GroupRolesData> _GetGroupRoles(UUID groupID)
|
||||
{
|
||||
List<GroupRolesData> roles = new List<GroupRolesData>();
|
||||
|
||||
@@ -865,7 +872,7 @@ namespace OpenSim.Groups
|
||||
return roles;
|
||||
}
|
||||
|
||||
private List<ExtendedGroupRoleMembersData> _GetGroupRoleMembers(UUID GroupID, bool isInGroup)
|
||||
protected List<ExtendedGroupRoleMembersData> _GetGroupRoleMembers(UUID GroupID, bool isInGroup)
|
||||
{
|
||||
List<ExtendedGroupRoleMembersData> rmembers = new List<ExtendedGroupRoleMembersData>();
|
||||
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace OpenSim.OfflineIM
|
||||
m_OfflineIMService = service;
|
||||
}
|
||||
|
||||
public override byte[] Handle(string path, Stream requestData,
|
||||
protected override byte[] ProcessRequest(string path, Stream requestData,
|
||||
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
StreamReader sr = new StreamReader(requestData);
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace OpenSim.OfflineIM
|
||||
{
|
||||
public class OfflineIMService : OfflineIMServiceBase, IOfflineIMService
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private const int MAX_IM = 25;
|
||||
|
||||
private XmlSerializer m_serializer;
|
||||
|
||||
@@ -115,6 +115,8 @@ namespace OpenSim.ApplicationPlugins.LoadRegions
|
||||
Environment.Exit(1);
|
||||
}
|
||||
|
||||
List<IScene> createdScenes = new List<IScene>();
|
||||
|
||||
for (int i = 0; i < regionsToLoad.Length; i++)
|
||||
{
|
||||
IScene scene;
|
||||
@@ -123,17 +125,22 @@ namespace OpenSim.ApplicationPlugins.LoadRegions
|
||||
")");
|
||||
|
||||
bool changed = m_openSim.PopulateRegionEstateInfo(regionsToLoad[i]);
|
||||
|
||||
m_openSim.CreateRegion(regionsToLoad[i], true, out scene);
|
||||
createdScenes.Add(scene);
|
||||
|
||||
if (changed)
|
||||
regionsToLoad[i].EstateSettings.Save();
|
||||
|
||||
if (scene != null)
|
||||
regionsToLoad[i].EstateSettings.Save();
|
||||
}
|
||||
|
||||
foreach (IScene scene in createdScenes)
|
||||
{
|
||||
scene.Start();
|
||||
|
||||
m_newRegionCreatedHandler = OnNewRegionCreated;
|
||||
if (m_newRegionCreatedHandler != null)
|
||||
{
|
||||
m_newRegionCreatedHandler = OnNewRegionCreated;
|
||||
if (m_newRegionCreatedHandler != null)
|
||||
{
|
||||
m_newRegionCreatedHandler(scene);
|
||||
}
|
||||
m_newRegionCreatedHandler(scene);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,6 +50,7 @@ using OpenSim.Region.Framework.Scenes;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo;
|
||||
using GridRegion = OpenSim.Services.Interfaces.GridRegion;
|
||||
using PermissionMask = OpenSim.Framework.PermissionMask;
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
{
|
||||
@@ -136,6 +137,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
availableMethods["admin_save_heightmap"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcSaveHeightmapMethod);
|
||||
|
||||
// Agent management
|
||||
availableMethods["admin_get_agents"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcGetAgentsMethod);
|
||||
availableMethods["admin_teleport_agent"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcTeleportAgentMethod);
|
||||
|
||||
// User management
|
||||
@@ -155,6 +157,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
availableMethods["admin_acl_add"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcAccessListAdd);
|
||||
availableMethods["admin_acl_remove"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcAccessListRemove);
|
||||
availableMethods["admin_acl_list"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcAccessListList);
|
||||
availableMethods["admin_estate_reload"] = (req, ep) => InvokeXmlRpcMethod(req, ep, XmlRpcEstateReload);
|
||||
|
||||
// Either enable full remote functionality or just selected features
|
||||
string enabledMethods = m_config.GetString("enabled_methods", "all");
|
||||
@@ -698,6 +701,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
|
||||
IScene newScene;
|
||||
m_application.CreateRegion(region, out newScene);
|
||||
newScene.Start();
|
||||
|
||||
// If an access specification was provided, use it.
|
||||
// Otherwise accept the default.
|
||||
@@ -1092,7 +1096,7 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
{
|
||||
GridUserInfo userInfo = m_application.SceneManager.CurrentOrFirstScene.GridUserService.GetGridUserInfo(account.PrincipalID.ToString());
|
||||
if (userInfo != null)
|
||||
responseData["lastlogin"] = userInfo.Login;
|
||||
responseData["lastlogin"] = Util.ToUnixTime(userInfo.Login);
|
||||
else
|
||||
responseData["lastlogin"] = 0;
|
||||
|
||||
@@ -1759,6 +1763,87 @@ namespace OpenSim.ApplicationPlugins.RemoteController
|
||||
m_log.Info("[RADMIN]: Access List List Request complete");
|
||||
}
|
||||
|
||||
private void XmlRpcEstateReload(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient)
|
||||
{
|
||||
m_log.Info("[RADMIN]: Received Estate Reload Request");
|
||||
|
||||
Hashtable responseData = (Hashtable)response.Value;
|
||||
// Hashtable requestData = (Hashtable)request.Params[0];
|
||||
|
||||
m_application.SceneManager.ForEachScene(s =>
|
||||
s.RegionInfo.EstateSettings = m_application.EstateDataService.LoadEstateSettings(s.RegionInfo.RegionID, false)
|
||||
);
|
||||
|
||||
responseData["success"] = true;
|
||||
|
||||
m_log.Info("[RADMIN]: Estate Reload Request complete");
|
||||
}
|
||||
|
||||
private void XmlRpcGetAgentsMethod(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient)
|
||||
{
|
||||
Hashtable responseData = (Hashtable)response.Value;
|
||||
Hashtable requestData = (Hashtable)request.Params[0];
|
||||
|
||||
bool includeChildren = false;
|
||||
|
||||
if (requestData.Contains("include_children"))
|
||||
bool.TryParse((string)requestData["include_children"], out includeChildren);
|
||||
|
||||
Scene scene;
|
||||
GetSceneFromRegionParams(requestData, responseData, out scene);
|
||||
|
||||
ArrayList xmlRpcRegions = new ArrayList();
|
||||
responseData["regions"] = xmlRpcRegions;
|
||||
|
||||
Hashtable xmlRpcRegion = new Hashtable();
|
||||
xmlRpcRegions.Add(xmlRpcRegion);
|
||||
|
||||
xmlRpcRegion["name"] = scene.Name;
|
||||
xmlRpcRegion["id"] = scene.RegionInfo.RegionID.ToString();
|
||||
|
||||
List<ScenePresence> agents = scene.GetScenePresences();
|
||||
ArrayList xmlrpcAgents = new ArrayList();
|
||||
|
||||
foreach (ScenePresence agent in agents)
|
||||
{
|
||||
if (agent.IsChildAgent && !includeChildren)
|
||||
continue;
|
||||
|
||||
Hashtable xmlRpcAgent = new Hashtable();
|
||||
xmlRpcAgent.Add("name", agent.Name);
|
||||
xmlRpcAgent.Add("id", agent.UUID.ToString());
|
||||
xmlRpcAgent.Add("type", agent.PresenceType.ToString());
|
||||
xmlRpcAgent.Add("current_parcel_id", agent.currentParcelUUID.ToString());
|
||||
|
||||
Vector3 pos = agent.AbsolutePosition;
|
||||
xmlRpcAgent.Add("pos_x", pos.X.ToString());
|
||||
xmlRpcAgent.Add("pos_y", pos.Y.ToString());
|
||||
xmlRpcAgent.Add("pos_z", pos.Z.ToString());
|
||||
|
||||
Vector3 lookAt = agent.Lookat;
|
||||
xmlRpcAgent.Add("lookat_x", lookAt.X.ToString());
|
||||
xmlRpcAgent.Add("lookat_y", lookAt.Y.ToString());
|
||||
xmlRpcAgent.Add("lookat_z", lookAt.Z.ToString());
|
||||
|
||||
Vector3 vel = agent.Velocity;
|
||||
xmlRpcAgent.Add("vel_x", vel.X.ToString());
|
||||
xmlRpcAgent.Add("vel_y", vel.Y.ToString());
|
||||
xmlRpcAgent.Add("vel_z", vel.Z.ToString());
|
||||
|
||||
xmlRpcAgent.Add("is_flying", agent.Flying.ToString());
|
||||
xmlRpcAgent.Add("is_sat_on_ground", agent.SitGround.ToString());
|
||||
xmlRpcAgent.Add("is_sat_on_object", agent.IsSatOnObject.ToString());
|
||||
|
||||
xmlrpcAgents.Add(xmlRpcAgent);
|
||||
}
|
||||
|
||||
m_log.DebugFormat(
|
||||
"[REMOTE ADMIN]: XmlRpcGetAgents found {0} agents in {1}", xmlrpcAgents.Count, scene.Name);
|
||||
|
||||
xmlRpcRegion["agents"] = xmlrpcAgents;
|
||||
responseData["success"] = true;
|
||||
}
|
||||
|
||||
private void XmlRpcTeleportAgentMethod(XmlRpcRequest request, XmlRpcResponse response, IPEndPoint remoteClient)
|
||||
{
|
||||
Hashtable responseData = (Hashtable)response.Value;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,11 +0,0 @@
|
||||
<Addin id="OpenSim.ApplicationPlugins.Rest.Inventory" version="0.1">
|
||||
<Runtime>
|
||||
<Import assembly="OpenSim.ApplicationPlugins.Rest.Inventory.dll"/>
|
||||
</Runtime>
|
||||
<Dependencies>
|
||||
<Addin id="OpenSim" version="0.5" />
|
||||
</Dependencies>
|
||||
<Extension path = "/OpenSim/Startup">
|
||||
<Plugin id="RestInventory" type="OpenSim.ApplicationPlugins.Rest.Inventory.RestHandler" />
|
||||
</Extension>
|
||||
</Addin>
|
||||
@@ -1,551 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using log4net;
|
||||
using Nini.Config;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Communications;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using IAvatarService = OpenSim.Services.Interfaces.IAvatarService;
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||
{
|
||||
public class Rest
|
||||
{
|
||||
internal static readonly ILog Log =
|
||||
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
internal static bool DEBUG = Log.IsDebugEnabled;
|
||||
|
||||
/// <summary>
|
||||
/// Supported authentication schemes
|
||||
/// </summary>
|
||||
|
||||
public const string AS_BASIC = "Basic"; // simple user/password verification
|
||||
public const string AS_DIGEST = "Digest"; // password safe authentication
|
||||
|
||||
/// Supported Digest algorithms
|
||||
|
||||
public const string Digest_MD5 = "MD5"; // assumed default if omitted
|
||||
public const string Digest_MD5Sess = "MD5-sess"; // session-span - not good for REST?
|
||||
|
||||
public const string Qop_Auth = "auth"; // authentication only
|
||||
public const string Qop_Int = "auth-int"; // TODO
|
||||
|
||||
/// <summary>
|
||||
/// These values have a single value for the whole
|
||||
/// domain and lifetime of the plugin handler. We
|
||||
/// make them static for ease of reference within
|
||||
/// the assembly. These are initialized by the
|
||||
/// RestHandler class during start-up.
|
||||
/// </summary>
|
||||
|
||||
internal static IRestHandler Plugin = null;
|
||||
internal static OpenSimBase main = null;
|
||||
internal static string Prefix = null;
|
||||
internal static IConfig Config = null;
|
||||
internal static string GodKey = null;
|
||||
internal static bool Authenticate = true;
|
||||
internal static bool Secure = true;
|
||||
internal static bool ExtendedEscape = true;
|
||||
internal static bool DumpAsset = false;
|
||||
internal static bool Fill = true;
|
||||
internal static bool FlushEnabled = true;
|
||||
internal static string Realm = "OpenSim REST";
|
||||
internal static string Scheme = AS_BASIC;
|
||||
internal static int DumpLineSize = 32; // Should be a multiple of 16 or (possibly) 4
|
||||
|
||||
/// <summary>
|
||||
/// These are all dependent upon the Comms manager
|
||||
/// being initialized. So they have to be properties
|
||||
/// because the comms manager is now a module and is
|
||||
/// not guaranteed to be there when the rest handler
|
||||
/// initializes.
|
||||
/// </summary>
|
||||
|
||||
internal static IInventoryService InventoryServices
|
||||
{
|
||||
get { return main.SceneManager.CurrentOrFirstScene.InventoryService; }
|
||||
}
|
||||
|
||||
internal static IUserAccountService UserServices
|
||||
{
|
||||
get { return main.SceneManager.CurrentOrFirstScene.UserAccountService; }
|
||||
}
|
||||
|
||||
internal static IAuthenticationService AuthServices
|
||||
{
|
||||
get { return main.SceneManager.CurrentOrFirstScene.AuthenticationService; }
|
||||
}
|
||||
|
||||
internal static IAvatarService AvatarServices
|
||||
{
|
||||
get { return main.SceneManager.CurrentOrFirstScene.AvatarService; }
|
||||
}
|
||||
|
||||
internal static IAssetService AssetServices
|
||||
{
|
||||
get { return main.SceneManager.CurrentOrFirstScene.AssetService; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// HTTP requires that status information be generated for PUT
|
||||
/// and POST opertaions. This is in support of that. The
|
||||
/// operation verb gets substituted into the first string,
|
||||
/// and the completion code is inserted into the tail. The
|
||||
/// strings are put here to encourage consistency.
|
||||
/// </summary>
|
||||
|
||||
internal static string statusHead = "<html><body><title>{0} status</title><break>";
|
||||
internal static string statusTail = "</body></html>";
|
||||
|
||||
internal static Dictionary<int,string> HttpStatusDesc;
|
||||
|
||||
static Rest()
|
||||
{
|
||||
HttpStatusDesc = new Dictionary<int,string>();
|
||||
if (HttpStatusCodeArray.Length != HttpStatusDescArray.Length)
|
||||
{
|
||||
Log.ErrorFormat("{0} HTTP Status Code and Description arrays do not match");
|
||||
throw new Exception("HTTP Status array discrepancy");
|
||||
}
|
||||
|
||||
// Repackage the data into something more tractable. The sparse
|
||||
// nature of HTTP return codes makes an array a bad choice.
|
||||
|
||||
for (int i=0; i<HttpStatusCodeArray.Length; i++)
|
||||
{
|
||||
HttpStatusDesc.Add(HttpStatusCodeArray[i], HttpStatusDescArray[i]);
|
||||
}
|
||||
}
|
||||
|
||||
internal static int CreationDate
|
||||
{
|
||||
get { return (int) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; }
|
||||
}
|
||||
|
||||
internal static string MsgId
|
||||
{
|
||||
get { return Plugin.MsgId; }
|
||||
}
|
||||
|
||||
internal static string RequestId
|
||||
{
|
||||
get { return Plugin.RequestId; }
|
||||
}
|
||||
|
||||
internal static Encoding Encoding = Util.UTF8;
|
||||
|
||||
/// <summary>
|
||||
/// Version control for REST implementation. This
|
||||
/// refers to the overall infrastructure represented
|
||||
/// by the following classes
|
||||
/// RequestData
|
||||
/// RequestInventoryPlugin
|
||||
/// Rest
|
||||
/// It does no describe implementation classes such as
|
||||
/// RestInventoryServices, which may morph much more
|
||||
/// often. Such classes ARE dependent upon this however
|
||||
/// and should check it in their Initialize method.
|
||||
/// </summary>
|
||||
|
||||
public static readonly float Version = 1.0F;
|
||||
public const string Name = "REST 1.0";
|
||||
|
||||
/// <summary>
|
||||
/// Currently defined HTTP methods.
|
||||
/// Only GET and HEAD are required to be
|
||||
/// supported by all servers. See Respond
|
||||
/// to see how these are handled.
|
||||
/// </summary>
|
||||
|
||||
// REST AGENT 1.0 interpretations
|
||||
public const string GET = "get"; // information retrieval - server state unchanged
|
||||
public const string HEAD = "head"; // same as get except only the headers are returned.
|
||||
public const string POST = "post"; // Replace the URI designated resource with the entity.
|
||||
public const string PUT = "put"; // Add the entity to the context represented by the URI
|
||||
public const string DELETE = "delete"; // Remove the URI designated resource from the server.
|
||||
|
||||
public const string OPTIONS = "options"; //
|
||||
public const string TRACE = "trace"; //
|
||||
public const string CONNECT = "connect"; //
|
||||
|
||||
// Define this in one place...
|
||||
|
||||
public const string UrlPathSeparator = "/";
|
||||
public const string UrlMethodSeparator = ":";
|
||||
|
||||
// Redirection qualifications
|
||||
|
||||
public const bool PERMANENT = false;
|
||||
public const bool TEMPORARY = true;
|
||||
|
||||
// Constant arrays used by String.Split
|
||||
|
||||
public static readonly char C_SPACE = ' ';
|
||||
public static readonly char C_SLASH = '/';
|
||||
public static readonly char C_PATHSEP = '/';
|
||||
public static readonly char C_COLON = ':';
|
||||
public static readonly char C_PLUS = '+';
|
||||
public static readonly char C_PERIOD = '.';
|
||||
public static readonly char C_COMMA = ',';
|
||||
public static readonly char C_DQUOTE = '"';
|
||||
|
||||
public static readonly string CS_SPACE = " ";
|
||||
public static readonly string CS_SLASH = "/";
|
||||
public static readonly string CS_PATHSEP = "/";
|
||||
public static readonly string CS_COLON = ":";
|
||||
public static readonly string CS_PLUS = "+";
|
||||
public static readonly string CS_PERIOD = ".";
|
||||
public static readonly string CS_COMMA = ",";
|
||||
public static readonly string CS_DQUOTE = "\"";
|
||||
|
||||
public static readonly char[] CA_SPACE = { C_SPACE };
|
||||
public static readonly char[] CA_SLASH = { C_SLASH };
|
||||
public static readonly char[] CA_PATHSEP = { C_PATHSEP };
|
||||
public static readonly char[] CA_COLON = { C_COLON };
|
||||
public static readonly char[] CA_PERIOD = { C_PERIOD };
|
||||
public static readonly char[] CA_PLUS = { C_PLUS };
|
||||
public static readonly char[] CA_COMMA = { C_COMMA };
|
||||
public static readonly char[] CA_DQUOTE = { C_DQUOTE };
|
||||
|
||||
// HTTP Code Values (in value order)
|
||||
|
||||
public const int HttpStatusCodeContinue = 100;
|
||||
public const int HttpStatusCodeSwitchingProtocols = 101;
|
||||
|
||||
public const int HttpStatusCodeOK = 200;
|
||||
public const int HttpStatusCodeCreated = 201;
|
||||
public const int HttpStatusCodeAccepted = 202;
|
||||
public const int HttpStatusCodeNonAuthoritative = 203;
|
||||
public const int HttpStatusCodeNoContent = 204;
|
||||
public const int HttpStatusCodeResetContent = 205;
|
||||
public const int HttpStatusCodePartialContent = 206;
|
||||
|
||||
public const int HttpStatusCodeMultipleChoices = 300;
|
||||
public const int HttpStatusCodePermanentRedirect = 301;
|
||||
public const int HttpStatusCodeFound = 302;
|
||||
public const int HttpStatusCodeSeeOther = 303;
|
||||
public const int HttpStatusCodeNotModified = 304;
|
||||
public const int HttpStatusCodeUseProxy = 305;
|
||||
public const int HttpStatusCodeReserved306 = 306;
|
||||
public const int HttpStatusCodeTemporaryRedirect = 307;
|
||||
|
||||
public const int HttpStatusCodeBadRequest = 400;
|
||||
public const int HttpStatusCodeNotAuthorized = 401;
|
||||
public const int HttpStatusCodePaymentRequired = 402;
|
||||
public const int HttpStatusCodeForbidden = 403;
|
||||
public const int HttpStatusCodeNotFound = 404;
|
||||
public const int HttpStatusCodeMethodNotAllowed = 405;
|
||||
public const int HttpStatusCodeNotAcceptable = 406;
|
||||
public const int HttpStatusCodeProxyAuthenticate = 407;
|
||||
public const int HttpStatusCodeTimeOut = 408;
|
||||
public const int HttpStatusCodeConflict = 409;
|
||||
public const int HttpStatusCodeGone = 410;
|
||||
public const int HttpStatusCodeLengthRequired = 411;
|
||||
public const int HttpStatusCodePreconditionFailed = 412;
|
||||
public const int HttpStatusCodeEntityTooLarge = 413;
|
||||
public const int HttpStatusCodeUriTooLarge = 414;
|
||||
public const int HttpStatusCodeUnsupportedMedia = 415;
|
||||
public const int HttpStatusCodeRangeNotSatsified = 416;
|
||||
public const int HttpStatusCodeExpectationFailed = 417;
|
||||
|
||||
public const int HttpStatusCodeServerError = 500;
|
||||
public const int HttpStatusCodeNotImplemented = 501;
|
||||
public const int HttpStatusCodeBadGateway = 502;
|
||||
public const int HttpStatusCodeServiceUnavailable = 503;
|
||||
public const int HttpStatusCodeGatewayTimeout = 504;
|
||||
public const int HttpStatusCodeHttpVersionError = 505;
|
||||
|
||||
public static readonly int[] HttpStatusCodeArray = {
|
||||
HttpStatusCodeContinue,
|
||||
HttpStatusCodeSwitchingProtocols,
|
||||
HttpStatusCodeOK,
|
||||
HttpStatusCodeCreated,
|
||||
HttpStatusCodeAccepted,
|
||||
HttpStatusCodeNonAuthoritative,
|
||||
HttpStatusCodeNoContent,
|
||||
HttpStatusCodeResetContent,
|
||||
HttpStatusCodePartialContent,
|
||||
HttpStatusCodeMultipleChoices,
|
||||
HttpStatusCodePermanentRedirect,
|
||||
HttpStatusCodeFound,
|
||||
HttpStatusCodeSeeOther,
|
||||
HttpStatusCodeNotModified,
|
||||
HttpStatusCodeUseProxy,
|
||||
HttpStatusCodeReserved306,
|
||||
HttpStatusCodeTemporaryRedirect,
|
||||
HttpStatusCodeBadRequest,
|
||||
HttpStatusCodeNotAuthorized,
|
||||
HttpStatusCodePaymentRequired,
|
||||
HttpStatusCodeForbidden,
|
||||
HttpStatusCodeNotFound,
|
||||
HttpStatusCodeMethodNotAllowed,
|
||||
HttpStatusCodeNotAcceptable,
|
||||
HttpStatusCodeProxyAuthenticate,
|
||||
HttpStatusCodeTimeOut,
|
||||
HttpStatusCodeConflict,
|
||||
HttpStatusCodeGone,
|
||||
HttpStatusCodeLengthRequired,
|
||||
HttpStatusCodePreconditionFailed,
|
||||
HttpStatusCodeEntityTooLarge,
|
||||
HttpStatusCodeUriTooLarge,
|
||||
HttpStatusCodeUnsupportedMedia,
|
||||
HttpStatusCodeRangeNotSatsified,
|
||||
HttpStatusCodeExpectationFailed,
|
||||
HttpStatusCodeServerError,
|
||||
HttpStatusCodeNotImplemented,
|
||||
HttpStatusCodeBadGateway,
|
||||
HttpStatusCodeServiceUnavailable,
|
||||
HttpStatusCodeGatewayTimeout,
|
||||
HttpStatusCodeHttpVersionError
|
||||
};
|
||||
|
||||
// HTTP Status Descriptions (in status code order)
|
||||
// This array must be kept strictly consistent with respect
|
||||
// to the status code array above.
|
||||
|
||||
public static readonly string[] HttpStatusDescArray = {
|
||||
"Continue Request",
|
||||
"Switching Protocols",
|
||||
"OK",
|
||||
"CREATED",
|
||||
"ACCEPTED",
|
||||
"NON-AUTHORITATIVE INFORMATION",
|
||||
"NO CONTENT",
|
||||
"RESET CONTENT",
|
||||
"PARTIAL CONTENT",
|
||||
"MULTIPLE CHOICES",
|
||||
"PERMANENT REDIRECT",
|
||||
"FOUND",
|
||||
"SEE OTHER",
|
||||
"NOT MODIFIED",
|
||||
"USE PROXY",
|
||||
"RESERVED CODE 306",
|
||||
"TEMPORARY REDIRECT",
|
||||
"BAD REQUEST",
|
||||
"NOT AUTHORIZED",
|
||||
"PAYMENT REQUIRED",
|
||||
"FORBIDDEN",
|
||||
"NOT FOUND",
|
||||
"METHOD NOT ALLOWED",
|
||||
"NOT ACCEPTABLE",
|
||||
"PROXY AUTHENTICATION REQUIRED",
|
||||
"TIMEOUT",
|
||||
"CONFLICT",
|
||||
"GONE",
|
||||
"LENGTH REQUIRED",
|
||||
"PRECONDITION FAILED",
|
||||
"ENTITY TOO LARGE",
|
||||
"URI TOO LARGE",
|
||||
"UNSUPPORTED MEDIA",
|
||||
"RANGE NOT SATISFIED",
|
||||
"EXPECTATION FAILED",
|
||||
"SERVER ERROR",
|
||||
"NOT IMPLEMENTED",
|
||||
"BAD GATEWAY",
|
||||
"SERVICE UNAVAILABLE",
|
||||
"GATEWAY TIMEOUT",
|
||||
"HTTP VERSION NOT SUPPORTED"
|
||||
};
|
||||
|
||||
// HTTP Headers
|
||||
|
||||
public const string HttpHeaderAccept = "Accept";
|
||||
public const string HttpHeaderAcceptCharset = "Accept-Charset";
|
||||
public const string HttpHeaderAcceptEncoding = "Accept-Encoding";
|
||||
public const string HttpHeaderAcceptLanguage = "Accept-Language";
|
||||
public const string HttpHeaderAcceptRanges = "Accept-Ranges";
|
||||
public const string HttpHeaderAge = "Age";
|
||||
public const string HttpHeaderAllow = "Allow";
|
||||
public const string HttpHeaderAuthorization = "Authorization";
|
||||
public const string HttpHeaderCacheControl = "Cache-Control";
|
||||
public const string HttpHeaderConnection = "Connection";
|
||||
public const string HttpHeaderContentEncoding = "Content-Encoding";
|
||||
public const string HttpHeaderContentLanguage = "Content-Language";
|
||||
public const string HttpHeaderContentLength = "Content-Length";
|
||||
public const string HttpHeaderContentLocation = "Content-Location";
|
||||
public const string HttpHeaderContentMD5 = "Content-MD5";
|
||||
public const string HttpHeaderContentRange = "Content-Range";
|
||||
public const string HttpHeaderContentType = "Content-Type";
|
||||
public const string HttpHeaderDate = "Date";
|
||||
public const string HttpHeaderETag = "ETag";
|
||||
public const string HttpHeaderExpect = "Expect";
|
||||
public const string HttpHeaderExpires = "Expires";
|
||||
public const string HttpHeaderFrom = "From";
|
||||
public const string HttpHeaderHost = "Host";
|
||||
public const string HttpHeaderIfMatch = "If-Match";
|
||||
public const string HttpHeaderIfModifiedSince = "If-Modified-Since";
|
||||
public const string HttpHeaderIfNoneMatch = "If-None-Match";
|
||||
public const string HttpHeaderIfRange = "If-Range";
|
||||
public const string HttpHeaderIfUnmodifiedSince = "If-Unmodified-Since";
|
||||
public const string HttpHeaderLastModified = "Last-Modified";
|
||||
public const string HttpHeaderLocation = "Location";
|
||||
public const string HttpHeaderMaxForwards = "Max-Forwards";
|
||||
public const string HttpHeaderPragma = "Pragma";
|
||||
public const string HttpHeaderProxyAuthenticate = "Proxy-Authenticate";
|
||||
public const string HttpHeaderProxyAuthorization = "Proxy-Authorization";
|
||||
public const string HttpHeaderRange = "Range";
|
||||
public const string HttpHeaderReferer = "Referer";
|
||||
public const string HttpHeaderRetryAfter = "Retry-After";
|
||||
public const string HttpHeaderServer = "Server";
|
||||
public const string HttpHeaderTE = "TE";
|
||||
public const string HttpHeaderTrailer = "Trailer";
|
||||
public const string HttpHeaderTransferEncoding = "Transfer-Encoding";
|
||||
public const string HttpHeaderUpgrade = "Upgrade";
|
||||
public const string HttpHeaderUserAgent = "User-Agent";
|
||||
public const string HttpHeaderVary = "Vary";
|
||||
public const string HttpHeaderVia = "Via";
|
||||
public const string HttpHeaderWarning = "Warning";
|
||||
public const string HttpHeaderWWWAuthenticate = "WWW-Authenticate";
|
||||
|
||||
/// Utility routines
|
||||
|
||||
public static string StringToBase64(string str)
|
||||
{
|
||||
try
|
||||
{
|
||||
byte[] encData_byte = new byte[str.Length];
|
||||
encData_byte = Util.UTF8.GetBytes(str);
|
||||
return Convert.ToBase64String(encData_byte);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public static string Base64ToString(string str)
|
||||
{
|
||||
try
|
||||
{
|
||||
return Util.Base64ToString(str);
|
||||
}
|
||||
catch
|
||||
{
|
||||
return String.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private const string hvals = "0123456789abcdef";
|
||||
|
||||
public static int Hex2Int(string hex)
|
||||
{
|
||||
int val = 0;
|
||||
int sum = 0;
|
||||
string tmp = null;
|
||||
|
||||
if (hex != null)
|
||||
{
|
||||
tmp = hex.ToLower();
|
||||
for (int i = 0; i < tmp.Length; i++)
|
||||
{
|
||||
val = hvals.IndexOf(tmp[i]);
|
||||
if (val == -1)
|
||||
break;
|
||||
sum *= 16;
|
||||
sum += val;
|
||||
}
|
||||
}
|
||||
|
||||
return sum;
|
||||
}
|
||||
|
||||
// Nonce management
|
||||
|
||||
public static string NonceGenerator()
|
||||
{
|
||||
return StringToBase64(CreationDate + Guid.NewGuid().ToString());
|
||||
}
|
||||
|
||||
// Dump the specified data stream
|
||||
|
||||
public static void Dump(byte[] data)
|
||||
{
|
||||
char[] buffer = new char[DumpLineSize];
|
||||
int cc = 0;
|
||||
|
||||
for (int i = 0; i < data.Length; i++)
|
||||
{
|
||||
if (i % DumpLineSize == 0) Console.Write("\n{0}: ",i.ToString("d8"));
|
||||
|
||||
if (i % 4 == 0) Console.Write(" ");
|
||||
|
||||
Console.Write("{0}",data[i].ToString("x2"));
|
||||
|
||||
if (data[i] < 127 && data[i] > 31)
|
||||
buffer[i % DumpLineSize] = (char) data[i];
|
||||
else
|
||||
buffer[i % DumpLineSize] = '.';
|
||||
|
||||
cc++;
|
||||
|
||||
if (i != 0 && (i + 1) % DumpLineSize == 0)
|
||||
{
|
||||
Console.Write(" |"+(new String(buffer))+"|");
|
||||
cc = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Finish off any incomplete line
|
||||
|
||||
if (cc != 0)
|
||||
{
|
||||
for (int i = cc ; i < DumpLineSize; i++)
|
||||
{
|
||||
if (i % 4 == 0) Console.Write(" ");
|
||||
Console.Write(" ");
|
||||
buffer[i % DumpLineSize] = ' ';
|
||||
}
|
||||
Console.WriteLine(" |"+(new String(buffer))+"|");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.Write("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Local exception type
|
||||
|
||||
public class RestException : Exception
|
||||
{
|
||||
internal int statusCode;
|
||||
internal string statusDesc;
|
||||
internal string httpmethod;
|
||||
internal string httppath;
|
||||
|
||||
public RestException(string msg) : base(msg)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,860 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Servers;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
using OpenSim.Services.Interfaces;
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||
{
|
||||
|
||||
public class RestAppearanceServices : IRest
|
||||
{
|
||||
// private static readonly int PARM_USERID = 0;
|
||||
|
||||
// private static readonly int PARM_PATH = 1;
|
||||
|
||||
// private bool enabled = false;
|
||||
private string qPrefix = "appearance";
|
||||
|
||||
/// <summary>
|
||||
/// The constructor makes sure that the service prefix is absolute
|
||||
/// and the registers the service handler and the allocator.
|
||||
/// </summary>
|
||||
|
||||
public RestAppearanceServices()
|
||||
{
|
||||
Rest.Log.InfoFormat("{0} User appearance services initializing", MsgId);
|
||||
Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
|
||||
|
||||
// If a relative path was specified for the handler's domain,
|
||||
// add the standard prefix to make it absolute, e.g. /admin
|
||||
|
||||
if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
|
||||
{
|
||||
Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId);
|
||||
qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
|
||||
qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
|
||||
Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix);
|
||||
}
|
||||
|
||||
// Register interface using the absolute URI.
|
||||
|
||||
Rest.Plugin.AddPathHandler(DoAppearance,qPrefix,Allocate);
|
||||
|
||||
// Activate if everything went OK
|
||||
|
||||
// enabled = true;
|
||||
|
||||
Rest.Log.InfoFormat("{0} User appearance services initialization complete", MsgId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Post-construction, pre-enabled initialization opportunity
|
||||
/// Not currently exploited.
|
||||
/// </summary>
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the plug-in to halt service processing. Local processing is
|
||||
/// disabled.
|
||||
/// </summary>
|
||||
|
||||
public void Close()
|
||||
{
|
||||
// enabled = false;
|
||||
Rest.Log.InfoFormat("{0} User appearance services closing down", MsgId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This property is declared locally because it is used a lot and
|
||||
/// brevity is nice.
|
||||
/// </summary>
|
||||
|
||||
internal string MsgId
|
||||
{
|
||||
get { return Rest.MsgId; }
|
||||
}
|
||||
|
||||
#region Interface
|
||||
|
||||
/// <summary>
|
||||
/// The plugin (RestHandler) calls this method to allocate the request
|
||||
/// state carrier for a new request. It is destroyed when the request
|
||||
/// completes. All request-instance specific state is kept here. This
|
||||
/// is registered when this service provider is registered.
|
||||
/// </summary>
|
||||
/// <param name=request>Inbound HTTP request information</param>
|
||||
/// <param name=response>Outbound HTTP request information</param>
|
||||
/// <param name=qPrefix>REST service domain prefix</param>
|
||||
/// <returns>A RequestData instance suitable for this service</returns>
|
||||
|
||||
private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
|
||||
{
|
||||
return (RequestData) new AppearanceRequestData(request, response, prefix);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is registered with the handler when this service provider
|
||||
/// is initialized. It is called whenever the plug-in identifies this service
|
||||
/// provider as the best match for a given request.
|
||||
/// It handles all aspects of inventory REST processing, i.e. /admin/inventory
|
||||
/// </summary>
|
||||
/// <param name=hdata>A consolidated HTTP request work area</param>
|
||||
|
||||
private void DoAppearance(RequestData hdata)
|
||||
{
|
||||
// !!! REFACTORIMG PROBLEM. This needs rewriting for 0.7
|
||||
|
||||
//AppearanceRequestData rdata = (AppearanceRequestData) hdata;
|
||||
|
||||
//Rest.Log.DebugFormat("{0} DoAppearance ENTRY", MsgId);
|
||||
|
||||
//// If we're disabled, do nothing.
|
||||
|
||||
//if (!enabled)
|
||||
//{
|
||||
// return;
|
||||
//}
|
||||
|
||||
//// Now that we know this is a serious attempt to
|
||||
//// access inventory data, we should find out who
|
||||
//// is asking, and make sure they are authorized
|
||||
//// to do so. We need to validate the caller's
|
||||
//// identity before revealing anything about the
|
||||
//// status quo. Authenticate throws an exception
|
||||
//// via Fail if no identity information is present.
|
||||
////
|
||||
//// With the present HTTP server we can't use the
|
||||
//// builtin authentication mechanisms because they
|
||||
//// would be enforced for all in-bound requests.
|
||||
//// Instead we look at the headers ourselves and
|
||||
//// handle authentication directly.
|
||||
|
||||
//try
|
||||
//{
|
||||
// if (!rdata.IsAuthenticated)
|
||||
// {
|
||||
// rdata.Fail(Rest.HttpStatusCodeNotAuthorized,String.Format("user \"{0}\" could not be authenticated", rdata.userName));
|
||||
// }
|
||||
//}
|
||||
//catch (RestException e)
|
||||
//{
|
||||
// if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
|
||||
// {
|
||||
// Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
|
||||
// Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
|
||||
// Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
|
||||
// }
|
||||
// throw (e);
|
||||
//}
|
||||
|
||||
//Rest.Log.DebugFormat("{0} Authenticated {1}", MsgId, rdata.userName);
|
||||
|
||||
//// We can only get here if we are authorized
|
||||
////
|
||||
//// The requestor may have specified an UUID or
|
||||
//// a conjoined FirstName LastName string. We'll
|
||||
//// try both. If we fail with the first, UUID,
|
||||
//// attempt, we try the other. As an example, the
|
||||
//// URI for a valid inventory request might be:
|
||||
////
|
||||
//// http://<host>:<port>/admin/inventory/Arthur Dent
|
||||
////
|
||||
//// Indicating that this is an inventory request for
|
||||
//// an avatar named Arthur Dent. This is ALL that is
|
||||
//// required to designate a GET for an entire
|
||||
//// inventory.
|
||||
////
|
||||
|
||||
//// Do we have at least a user agent name?
|
||||
|
||||
//if (rdata.Parameters.Length < 1)
|
||||
//{
|
||||
// Rest.Log.WarnFormat("{0} Appearance: No user agent identifier specified", MsgId);
|
||||
// rdata.Fail(Rest.HttpStatusCodeBadRequest, "no user identity specified");
|
||||
//}
|
||||
|
||||
//// The first parameter MUST be the agent identification, either an UUID
|
||||
//// or a space-separated First-name Last-Name specification. We check for
|
||||
//// an UUID first, if anyone names their character using a valid UUID
|
||||
//// that identifies another existing avatar will cause this a problem...
|
||||
|
||||
//try
|
||||
//{
|
||||
// rdata.uuid = new UUID(rdata.Parameters[PARM_USERID]);
|
||||
// Rest.Log.DebugFormat("{0} UUID supplied", MsgId);
|
||||
// rdata.userProfile = Rest.UserServices.GetUserProfile(rdata.uuid);
|
||||
//}
|
||||
//catch
|
||||
//{
|
||||
// string[] names = rdata.Parameters[PARM_USERID].Split(Rest.CA_SPACE);
|
||||
// if (names.Length == 2)
|
||||
// {
|
||||
// Rest.Log.DebugFormat("{0} Agent Name supplied [2]", MsgId);
|
||||
// rdata.userProfile = Rest.UserServices.GetUserProfile(names[0],names[1]);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// Rest.Log.WarnFormat("{0} A Valid UUID or both first and last names must be specified", MsgId);
|
||||
// rdata.Fail(Rest.HttpStatusCodeBadRequest, "invalid user identity");
|
||||
// }
|
||||
//}
|
||||
|
||||
//// If the user profile is null then either the server is broken, or the
|
||||
//// user is not known. We always assume the latter case.
|
||||
|
||||
//if (rdata.userProfile != null)
|
||||
//{
|
||||
// Rest.Log.DebugFormat("{0} User profile obtained for agent {1} {2}",
|
||||
// MsgId, rdata.userProfile.FirstName, rdata.userProfile.SurName);
|
||||
//}
|
||||
//else
|
||||
//{
|
||||
// Rest.Log.WarnFormat("{0} No user profile for {1}", MsgId, rdata.path);
|
||||
// rdata.Fail(Rest.HttpStatusCodeNotFound, "unrecognized user identity");
|
||||
//}
|
||||
|
||||
//// If we get to here, then we have effectively validated the user's
|
||||
|
||||
//switch (rdata.method)
|
||||
//{
|
||||
// case Rest.HEAD : // Do the processing, set the status code, suppress entity
|
||||
// DoGet(rdata);
|
||||
// rdata.buffer = null;
|
||||
// break;
|
||||
|
||||
// case Rest.GET : // Do the processing, set the status code, return entity
|
||||
// DoGet(rdata);
|
||||
// break;
|
||||
|
||||
// case Rest.PUT : // Update named element
|
||||
// DoUpdate(rdata);
|
||||
// break;
|
||||
|
||||
// case Rest.POST : // Add new information to identified context.
|
||||
// DoExtend(rdata);
|
||||
// break;
|
||||
|
||||
// case Rest.DELETE : // Delete information
|
||||
// DoDelete(rdata);
|
||||
// break;
|
||||
|
||||
// default :
|
||||
// Rest.Log.WarnFormat("{0} Method {1} not supported for {2}",
|
||||
// MsgId, rdata.method, rdata.path);
|
||||
// rdata.Fail(Rest.HttpStatusCodeMethodNotAllowed,
|
||||
// String.Format("{0} not supported", rdata.method));
|
||||
// break;
|
||||
//}
|
||||
}
|
||||
|
||||
#endregion Interface
|
||||
|
||||
#region method-specific processing
|
||||
|
||||
/// <summary>
|
||||
/// This method implements GET processing for user's appearance.
|
||||
/// </summary>
|
||||
/// <param name=rdata>HTTP service request work area</param>
|
||||
|
||||
// private void DoGet(AppearanceRequestData rdata)
|
||||
// {
|
||||
// AvatarData adata = Rest.AvatarServices.GetAvatar(rdata.userProfile.ID);
|
||||
//
|
||||
// if (adata == null)
|
||||
// {
|
||||
// rdata.Fail(Rest.HttpStatusCodeNoContent,
|
||||
// String.Format("appearance data not found for user {0} {1}",
|
||||
// rdata.userProfile.FirstName, rdata.userProfile.SurName));
|
||||
// }
|
||||
// rdata.userAppearance = adata.ToAvatarAppearance(rdata.userProfile.ID);
|
||||
//
|
||||
// rdata.initXmlWriter();
|
||||
//
|
||||
// FormatUserAppearance(rdata);
|
||||
//
|
||||
// // Indicate a successful request
|
||||
//
|
||||
// rdata.Complete();
|
||||
//
|
||||
// // Send the response to the user. The body will be implicitly
|
||||
// // constructed from the result of the XML writer.
|
||||
//
|
||||
// rdata.Respond(String.Format("Appearance {0} Normal completion", rdata.method));
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// POST adds NEW information to the user profile database.
|
||||
/// This effectively resets the appearance before applying those
|
||||
/// characteristics supplied in the request.
|
||||
/// </summary>
|
||||
|
||||
// private void DoExtend(AppearanceRequestData rdata)
|
||||
// {
|
||||
//
|
||||
// bool created = false;
|
||||
// bool modified = false;
|
||||
// string newnode = String.Empty;
|
||||
//
|
||||
// Rest.Log.DebugFormat("{0} POST ENTRY", MsgId);
|
||||
//
|
||||
// //AvatarAppearance old = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID);
|
||||
//
|
||||
// rdata.userAppearance = new AvatarAppearance();
|
||||
//
|
||||
// // Although the following behavior is admitted by HTTP I am becoming
|
||||
// // increasingly doubtful that it is appropriate for REST. If I attempt to
|
||||
// // add a new record, and it already exists, then it seems to me that the
|
||||
// // attempt should fail, rather than update the existing record.
|
||||
// AvatarData adata = null;
|
||||
// if (GetUserAppearance(rdata))
|
||||
// {
|
||||
// modified = rdata.userAppearance != null;
|
||||
// created = !modified;
|
||||
// adata = new AvatarData(rdata.userAppearance);
|
||||
// Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata);
|
||||
// // Rest.UserServices.UpdateUserProfile(rdata.userProfile);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// created = true;
|
||||
// adata = new AvatarData(rdata.userAppearance);
|
||||
// Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata);
|
||||
// // Rest.UserServices.UpdateUserProfile(rdata.userProfile);
|
||||
// }
|
||||
//
|
||||
// if (created)
|
||||
// {
|
||||
// newnode = String.Format("{0} {1}", rdata.userProfile.FirstName,
|
||||
// rdata.userProfile.SurName);
|
||||
// // Must include a location header with a URI that identifies the new resource.
|
||||
//
|
||||
// rdata.AddHeader(Rest.HttpHeaderLocation,String.Format("http://{0}{1}:{2}{3}{4}",
|
||||
// rdata.hostname,rdata.port,rdata.path,Rest.UrlPathSeparator, newnode));
|
||||
// rdata.Complete(Rest.HttpStatusCodeCreated);
|
||||
//
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (modified)
|
||||
// {
|
||||
// rdata.Complete(Rest.HttpStatusCodeOK);
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// rdata.Complete(Rest.HttpStatusCodeNoContent);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method));
|
||||
//
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// This updates the user's appearance. not all aspects need to be provided,
|
||||
/// only those supplied will be changed.
|
||||
/// </summary>
|
||||
|
||||
// private void DoUpdate(AppearanceRequestData rdata)
|
||||
// {
|
||||
//
|
||||
// // REFACTORING PROBLEM This was commented out. It doesn't work for 0.7
|
||||
//
|
||||
// //bool created = false;
|
||||
// //bool modified = false;
|
||||
//
|
||||
//
|
||||
// //rdata.userAppearance = Rest.AvatarServices.GetUserAppearance(rdata.userProfile.ID);
|
||||
//
|
||||
// //// If the user exists then this is considered a modification regardless
|
||||
// //// of what may, or may not be, specified in the payload.
|
||||
//
|
||||
// //if (rdata.userAppearance != null)
|
||||
// //{
|
||||
// // modified = true;
|
||||
// // Rest.AvatarServices.UpdateUserAppearance(rdata.userProfile.ID, rdata.userAppearance);
|
||||
// // Rest.UserServices.UpdateUserProfile(rdata.userProfile);
|
||||
// //}
|
||||
//
|
||||
// //if (created)
|
||||
// //{
|
||||
// // rdata.Complete(Rest.HttpStatusCodeCreated);
|
||||
// //}
|
||||
// //else
|
||||
// //{
|
||||
// // if (modified)
|
||||
// // {
|
||||
// // rdata.Complete(Rest.HttpStatusCodeOK);
|
||||
// // }
|
||||
// // else
|
||||
// // {
|
||||
// // rdata.Complete(Rest.HttpStatusCodeNoContent);
|
||||
// // }
|
||||
// //}
|
||||
//
|
||||
// rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method));
|
||||
//
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// Delete the specified user's appearance. This actually performs a reset
|
||||
/// to the default avatar appearance, if the info is already there.
|
||||
/// Existing ownership is preserved. All prior updates are lost and can not
|
||||
/// be recovered.
|
||||
/// </summary>
|
||||
// private void DoDelete(AppearanceRequestData rdata)
|
||||
// {
|
||||
// AvatarData adata = Rest.AvatarServices.GetAvatar(rdata.userProfile.ID);
|
||||
//
|
||||
// if (adata != null)
|
||||
// {
|
||||
// AvatarAppearance old = adata.ToAvatarAppearance(rdata.userProfile.ID);
|
||||
// rdata.userAppearance = new AvatarAppearance();
|
||||
// rdata.userAppearance.Owner = old.Owner;
|
||||
// adata = new AvatarData(rdata.userAppearance);
|
||||
//
|
||||
// Rest.AvatarServices.SetAvatar(rdata.userProfile.ID, adata);
|
||||
//
|
||||
// rdata.Complete();
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
//
|
||||
// rdata.Complete(Rest.HttpStatusCodeNoContent);
|
||||
// }
|
||||
//
|
||||
// rdata.Respond(String.Format("Appearance {0} : Normal completion", rdata.method));
|
||||
// }
|
||||
|
||||
#endregion method-specific processing
|
||||
|
||||
private bool GetUserAppearance(AppearanceRequestData rdata)
|
||||
{
|
||||
|
||||
XmlReader xml;
|
||||
bool indata = false;
|
||||
|
||||
rdata.initXmlReader();
|
||||
xml = rdata.reader;
|
||||
|
||||
while (xml.Read())
|
||||
{
|
||||
switch (xml.NodeType)
|
||||
{
|
||||
case XmlNodeType.Element :
|
||||
switch (xml.Name)
|
||||
{
|
||||
case "Appearance" :
|
||||
if (xml.MoveToAttribute("Height"))
|
||||
{
|
||||
rdata.userAppearance.AvatarHeight = (float) Convert.ToDouble(xml.Value);
|
||||
indata = true;
|
||||
}
|
||||
// if (xml.MoveToAttribute("Owner"))
|
||||
// {
|
||||
// rdata.userAppearance.Owner = (UUID)xml.Value;
|
||||
// indata = true;
|
||||
// }
|
||||
if (xml.MoveToAttribute("Serial"))
|
||||
{
|
||||
rdata.userAppearance.Serial = Convert.ToInt32(xml.Value);
|
||||
indata = true;
|
||||
}
|
||||
break;
|
||||
/*
|
||||
case "Body" :
|
||||
if (xml.MoveToAttribute("Item"))
|
||||
{
|
||||
rdata.userAppearance.BodyItem = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
if (xml.MoveToAttribute("Asset"))
|
||||
{
|
||||
rdata.userAppearance.BodyAsset = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
break;
|
||||
case "Skin" :
|
||||
if (xml.MoveToAttribute("Item"))
|
||||
{
|
||||
rdata.userAppearance.SkinItem = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
if (xml.MoveToAttribute("Asset"))
|
||||
{
|
||||
rdata.userAppearance.SkinAsset = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
break;
|
||||
case "Hair" :
|
||||
if (xml.MoveToAttribute("Item"))
|
||||
{
|
||||
rdata.userAppearance.HairItem = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
if (xml.MoveToAttribute("Asset"))
|
||||
{
|
||||
rdata.userAppearance.HairAsset = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
break;
|
||||
case "Eyes" :
|
||||
if (xml.MoveToAttribute("Item"))
|
||||
{
|
||||
rdata.userAppearance.EyesItem = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
if (xml.MoveToAttribute("Asset"))
|
||||
{
|
||||
rdata.userAppearance.EyesAsset = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
break;
|
||||
case "Shirt" :
|
||||
if (xml.MoveToAttribute("Item"))
|
||||
{
|
||||
rdata.userAppearance.ShirtItem = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
if (xml.MoveToAttribute("Asset"))
|
||||
{
|
||||
rdata.userAppearance.ShirtAsset = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
break;
|
||||
case "Pants" :
|
||||
if (xml.MoveToAttribute("Item"))
|
||||
{
|
||||
rdata.userAppearance.PantsItem = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
if (xml.MoveToAttribute("Asset"))
|
||||
{
|
||||
rdata.userAppearance.PantsAsset = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
break;
|
||||
case "Shoes" :
|
||||
if (xml.MoveToAttribute("Item"))
|
||||
{
|
||||
rdata.userAppearance.ShoesItem = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
if (xml.MoveToAttribute("Asset"))
|
||||
{
|
||||
rdata.userAppearance.ShoesAsset = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
break;
|
||||
case "Socks" :
|
||||
if (xml.MoveToAttribute("Item"))
|
||||
{
|
||||
rdata.userAppearance.SocksItem = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
if (xml.MoveToAttribute("Asset"))
|
||||
{
|
||||
rdata.userAppearance.SocksAsset = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
break;
|
||||
case "Jacket" :
|
||||
if (xml.MoveToAttribute("Item"))
|
||||
{
|
||||
rdata.userAppearance.JacketItem = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
if (xml.MoveToAttribute("Asset"))
|
||||
{
|
||||
rdata.userAppearance.JacketAsset = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
break;
|
||||
case "Gloves" :
|
||||
if (xml.MoveToAttribute("Item"))
|
||||
{
|
||||
rdata.userAppearance.GlovesItem = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
if (xml.MoveToAttribute("Asset"))
|
||||
{
|
||||
rdata.userAppearance.GlovesAsset = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
break;
|
||||
case "UnderShirt" :
|
||||
if (xml.MoveToAttribute("Item"))
|
||||
{
|
||||
rdata.userAppearance.UnderShirtItem = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
if (xml.MoveToAttribute("Asset"))
|
||||
{
|
||||
rdata.userAppearance.UnderShirtAsset = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
break;
|
||||
case "UnderPants" :
|
||||
if (xml.MoveToAttribute("Item"))
|
||||
{
|
||||
rdata.userAppearance.UnderPantsItem = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
if (xml.MoveToAttribute("Asset"))
|
||||
{
|
||||
rdata.userAppearance.UnderPantsAsset = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
break;
|
||||
case "Skirt" :
|
||||
if (xml.MoveToAttribute("Item"))
|
||||
{
|
||||
rdata.userAppearance.SkirtItem = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
if (xml.MoveToAttribute("Asset"))
|
||||
{
|
||||
rdata.userAppearance.SkirtAsset = (UUID)xml.Value;
|
||||
indata = true;
|
||||
}
|
||||
break;
|
||||
*/
|
||||
case "Attachment" :
|
||||
{
|
||||
|
||||
int ap;
|
||||
UUID asset;
|
||||
UUID item;
|
||||
|
||||
if (xml.MoveToAttribute("AtPoint"))
|
||||
{
|
||||
ap = Convert.ToInt32(xml.Value);
|
||||
if (xml.MoveToAttribute("Asset"))
|
||||
{
|
||||
asset = new UUID(xml.Value);
|
||||
if (xml.MoveToAttribute("Asset"))
|
||||
{
|
||||
item = new UUID(xml.Value);
|
||||
rdata.userAppearance.SetAttachment(ap, item, asset);
|
||||
indata = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "Texture" :
|
||||
if (xml.MoveToAttribute("Default"))
|
||||
{
|
||||
rdata.userAppearance.Texture = new Primitive.TextureEntry(new UUID(xml.Value));
|
||||
indata = true;
|
||||
}
|
||||
break;
|
||||
case "Face" :
|
||||
{
|
||||
uint index;
|
||||
if (xml.MoveToAttribute("Index"))
|
||||
{
|
||||
index = Convert.ToUInt32(xml.Value);
|
||||
if (xml.MoveToAttribute("Id"))
|
||||
{
|
||||
rdata.userAppearance.Texture.CreateFace(index).TextureID = new UUID(xml.Value);
|
||||
indata = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case "VisualParameters" :
|
||||
{
|
||||
xml.ReadContentAsBase64(rdata.userAppearance.VisualParams,
|
||||
0, rdata.userAppearance.VisualParams.Length);
|
||||
indata = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return indata;
|
||||
|
||||
}
|
||||
|
||||
private void FormatPart(AppearanceRequestData rdata, string part, UUID item, UUID asset)
|
||||
{
|
||||
if (item != UUID.Zero || asset != UUID.Zero)
|
||||
{
|
||||
rdata.writer.WriteStartElement(part);
|
||||
if (item != UUID.Zero)
|
||||
{
|
||||
rdata.writer.WriteAttributeString("Item",item.ToString());
|
||||
}
|
||||
|
||||
if (asset != UUID.Zero)
|
||||
{
|
||||
rdata.writer.WriteAttributeString("Asset",asset.ToString());
|
||||
}
|
||||
rdata.writer.WriteEndElement();
|
||||
}
|
||||
}
|
||||
|
||||
private void FormatUserAppearance(AppearanceRequestData rdata)
|
||||
{
|
||||
|
||||
Rest.Log.DebugFormat("{0} FormatUserAppearance", MsgId);
|
||||
|
||||
if (rdata.userAppearance != null)
|
||||
{
|
||||
|
||||
Rest.Log.DebugFormat("{0} FormatUserAppearance: appearance object exists", MsgId);
|
||||
rdata.writer.WriteStartElement("Appearance");
|
||||
|
||||
rdata.writer.WriteAttributeString("Height", rdata.userAppearance.AvatarHeight.ToString());
|
||||
// if (rdata.userAppearance.Owner != UUID.Zero)
|
||||
// rdata.writer.WriteAttributeString("Owner", rdata.userAppearance.Owner.ToString());
|
||||
rdata.writer.WriteAttributeString("Serial", rdata.userAppearance.Serial.ToString());
|
||||
|
||||
/*
|
||||
FormatPart(rdata, "Body", rdata.userAppearance.BodyItem, rdata.userAppearance.BodyAsset);
|
||||
FormatPart(rdata, "Skin", rdata.userAppearance.SkinItem, rdata.userAppearance.SkinAsset);
|
||||
FormatPart(rdata, "Hair", rdata.userAppearance.HairItem, rdata.userAppearance.HairAsset);
|
||||
FormatPart(rdata, "Eyes", rdata.userAppearance.EyesItem, rdata.userAppearance.EyesAsset);
|
||||
|
||||
FormatPart(rdata, "Shirt", rdata.userAppearance.ShirtItem, rdata.userAppearance.ShirtAsset);
|
||||
FormatPart(rdata, "Pants", rdata.userAppearance.PantsItem, rdata.userAppearance.PantsAsset);
|
||||
FormatPart(rdata, "Skirt", rdata.userAppearance.SkirtItem, rdata.userAppearance.SkirtAsset);
|
||||
FormatPart(rdata, "Shoes", rdata.userAppearance.ShoesItem, rdata.userAppearance.ShoesAsset);
|
||||
FormatPart(rdata, "Socks", rdata.userAppearance.SocksItem, rdata.userAppearance.SocksAsset);
|
||||
|
||||
FormatPart(rdata, "Jacket", rdata.userAppearance.JacketItem, rdata.userAppearance.JacketAsset);
|
||||
FormatPart(rdata, "Gloves", rdata.userAppearance.GlovesItem, rdata.userAppearance.GlovesAsset);
|
||||
|
||||
FormatPart(rdata, "UnderShirt", rdata.userAppearance.UnderShirtItem, rdata.userAppearance.UnderShirtAsset);
|
||||
FormatPart(rdata, "UnderPants", rdata.userAppearance.UnderPantsItem, rdata.userAppearance.UnderPantsAsset);
|
||||
*/
|
||||
Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting attachments", MsgId);
|
||||
|
||||
rdata.writer.WriteStartElement("Attachments");
|
||||
List<AvatarAttachment> attachments = rdata.userAppearance.GetAttachments();
|
||||
foreach (AvatarAttachment attach in attachments)
|
||||
{
|
||||
rdata.writer.WriteStartElement("Attachment");
|
||||
rdata.writer.WriteAttributeString("AtPoint", attach.AttachPoint.ToString());
|
||||
rdata.writer.WriteAttributeString("Item", attach.ItemID.ToString());
|
||||
rdata.writer.WriteAttributeString("Asset", attach.AssetID.ToString());
|
||||
rdata.writer.WriteEndElement();
|
||||
}
|
||||
rdata.writer.WriteEndElement();
|
||||
|
||||
Primitive.TextureEntry texture = rdata.userAppearance.Texture;
|
||||
|
||||
if (texture != null && (texture.DefaultTexture != null || texture.FaceTextures != null))
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting textures", MsgId);
|
||||
|
||||
rdata.writer.WriteStartElement("Texture");
|
||||
|
||||
if (texture.DefaultTexture != null)
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting default texture", MsgId);
|
||||
rdata.writer.WriteAttributeString("Default",
|
||||
texture.DefaultTexture.TextureID.ToString());
|
||||
}
|
||||
|
||||
if (texture.FaceTextures != null)
|
||||
{
|
||||
|
||||
Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting face textures", MsgId);
|
||||
|
||||
for (int i=0; i<texture.FaceTextures.Length;i++)
|
||||
{
|
||||
if (texture.FaceTextures[i] != null)
|
||||
{
|
||||
rdata.writer.WriteStartElement("Face");
|
||||
rdata.writer.WriteAttributeString("Index", i.ToString());
|
||||
rdata.writer.WriteAttributeString("Id",
|
||||
texture.FaceTextures[i].TextureID.ToString());
|
||||
rdata.writer.WriteEndElement();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
rdata.writer.WriteEndElement();
|
||||
}
|
||||
|
||||
Rest.Log.DebugFormat("{0} FormatUserAppearance: Formatting visual parameters", MsgId);
|
||||
|
||||
rdata.writer.WriteStartElement("VisualParameters");
|
||||
rdata.writer.WriteBase64(rdata.userAppearance.VisualParams,0,
|
||||
rdata.userAppearance.VisualParams.Length);
|
||||
rdata.writer.WriteEndElement();
|
||||
rdata.writer.WriteFullEndElement();
|
||||
}
|
||||
|
||||
Rest.Log.DebugFormat("{0} FormatUserAppearance: completed", MsgId);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
#region appearance RequestData extension
|
||||
|
||||
internal class AppearanceRequestData : RequestData
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// These are the inventory specific request/response state
|
||||
/// extensions.
|
||||
/// </summary>
|
||||
|
||||
internal UUID uuid = UUID.Zero;
|
||||
internal UserProfileData userProfile = null;
|
||||
internal AvatarAppearance userAppearance = null;
|
||||
|
||||
internal AppearanceRequestData(OSHttpRequest request, OSHttpResponse response, string prefix)
|
||||
: base(request, response, prefix)
|
||||
{
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endregion Appearance RequestData extension
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,383 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Xml;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Servers;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||
{
|
||||
public class RestAssetServices : IRest
|
||||
{
|
||||
private bool enabled = false;
|
||||
private string qPrefix = "assets";
|
||||
|
||||
// A simple constructor is used to handle any once-only
|
||||
// initialization of working classes.
|
||||
|
||||
public RestAssetServices()
|
||||
{
|
||||
Rest.Log.InfoFormat("{0} Asset services initializing", MsgId);
|
||||
Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
|
||||
|
||||
// If the handler specifies a relative path for its domain
|
||||
// then we must add the standard absolute prefix, e.g. /admin
|
||||
|
||||
if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
|
||||
{
|
||||
Rest.Log.InfoFormat("{0} Prefixing domain name ({1})", MsgId, qPrefix);
|
||||
qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
|
||||
Rest.Log.InfoFormat("{0} Fully qualified domain name is <{1}>", MsgId, qPrefix);
|
||||
}
|
||||
|
||||
// Register interface using the fully-qualified prefix
|
||||
|
||||
Rest.Plugin.AddPathHandler(DoAsset, qPrefix, Allocate);
|
||||
|
||||
// Activate if all went OK
|
||||
|
||||
enabled = true;
|
||||
|
||||
Rest.Log.InfoFormat("{0} Asset services initialization complete", MsgId);
|
||||
}
|
||||
|
||||
// Post-construction, pre-enabled initialization opportunity
|
||||
// Not currently exploited.
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
// Called by the plug-in to halt REST processing. Local processing is
|
||||
// disabled, and control blocks until all current processing has
|
||||
// completed. No new processing will be started
|
||||
|
||||
public void Close()
|
||||
{
|
||||
enabled = false;
|
||||
Rest.Log.InfoFormat("{0} Asset services ({1}) closing down", MsgId, qPrefix);
|
||||
}
|
||||
|
||||
// Properties
|
||||
|
||||
internal string MsgId
|
||||
{
|
||||
get { return Rest.MsgId; }
|
||||
}
|
||||
|
||||
#region Interface
|
||||
|
||||
private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
|
||||
{
|
||||
return (RequestData) new AssetRequestData(request, response, prefix);
|
||||
}
|
||||
|
||||
// Asset Handler
|
||||
|
||||
private void DoAsset(RequestData rparm)
|
||||
{
|
||||
if (!enabled) return;
|
||||
|
||||
AssetRequestData rdata = (AssetRequestData) rparm;
|
||||
|
||||
Rest.Log.DebugFormat("{0} REST Asset handler ({1}) ENTRY", MsgId, qPrefix);
|
||||
|
||||
// Now that we know this is a serious attempt to
|
||||
// access inventory data, we should find out who
|
||||
// is asking, and make sure they are authorized
|
||||
// to do so. We need to validate the caller's
|
||||
// identity before revealing anything about the
|
||||
// status quo. Authenticate throws an exception
|
||||
// via Fail if no identity information is present.
|
||||
//
|
||||
// With the present HTTP server we can't use the
|
||||
// builtin authentication mechanisms because they
|
||||
// would be enforced for all in-bound requests.
|
||||
// Instead we look at the headers ourselves and
|
||||
// handle authentication directly.
|
||||
|
||||
try
|
||||
{
|
||||
if (!rdata.IsAuthenticated)
|
||||
{
|
||||
rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated"));
|
||||
}
|
||||
}
|
||||
catch (RestException e)
|
||||
{
|
||||
if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
|
||||
{
|
||||
Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
|
||||
Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId,
|
||||
rdata.request.Headers.Get("Authorization"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
|
||||
Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId,
|
||||
rdata.request.Headers.Get("Authorization"));
|
||||
}
|
||||
throw (e);
|
||||
}
|
||||
|
||||
// Remove the prefix and what's left are the parameters. If we don't have
|
||||
// the parameters we need, fail the request. Parameters do NOT include
|
||||
// any supplied query values.
|
||||
|
||||
if (rdata.Parameters.Length > 0)
|
||||
{
|
||||
switch (rdata.method)
|
||||
{
|
||||
case "get" :
|
||||
DoGet(rdata);
|
||||
break;
|
||||
case "put" :
|
||||
DoPut(rdata);
|
||||
break;
|
||||
case "post" :
|
||||
DoPost(rdata);
|
||||
break;
|
||||
case "delete" :
|
||||
default :
|
||||
Rest.Log.WarnFormat("{0} Asset: Method not supported: {1}",
|
||||
MsgId, rdata.method);
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest,String.Format("method <{0}> not supported", rdata.method));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Rest.Log.WarnFormat("{0} Asset: No agent information provided", MsgId);
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest, "no agent information provided");
|
||||
}
|
||||
|
||||
Rest.Log.DebugFormat("{0} REST Asset handler EXIT", MsgId);
|
||||
}
|
||||
|
||||
#endregion Interface
|
||||
|
||||
/// <summary>
|
||||
/// The only parameter we recognize is a UUID.If an asset with this identification is
|
||||
/// found, it's content, base-64 encoded, is returned to the client.
|
||||
/// </summary>
|
||||
|
||||
private void DoGet(AssetRequestData rdata)
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method);
|
||||
|
||||
if (rdata.Parameters.Length == 1)
|
||||
{
|
||||
UUID uuid = new UUID(rdata.Parameters[0]);
|
||||
AssetBase asset = Rest.AssetServices.Get(uuid.ToString());
|
||||
|
||||
if (asset != null)
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Asset located <{1}>", MsgId, rdata.Parameters[0]);
|
||||
|
||||
rdata.initXmlWriter();
|
||||
|
||||
rdata.writer.WriteStartElement(String.Empty,"Asset",String.Empty);
|
||||
|
||||
rdata.writer.WriteAttributeString("id", asset.ID);
|
||||
rdata.writer.WriteAttributeString("name", asset.Name);
|
||||
rdata.writer.WriteAttributeString("desc", asset.Description);
|
||||
rdata.writer.WriteAttributeString("type", asset.Type.ToString());
|
||||
rdata.writer.WriteAttributeString("local", asset.Local.ToString());
|
||||
rdata.writer.WriteAttributeString("temporary", asset.Temporary.ToString());
|
||||
|
||||
rdata.writer.WriteBase64(asset.Data,0,asset.Data.Length);
|
||||
|
||||
rdata.writer.WriteFullEndElement();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
|
||||
rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
|
||||
}
|
||||
}
|
||||
|
||||
rdata.Complete();
|
||||
rdata.Respond(String.Format("Asset <{0}> : Normal completion", rdata.method));
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UPDATE existing item, if it exists. URI identifies the item in question.
|
||||
/// The only parameter we recognize is a UUID. The enclosed asset data (base-64 encoded)
|
||||
/// is decoded and stored in the database, identified by the supplied UUID.
|
||||
/// </summary>
|
||||
private void DoPut(AssetRequestData rdata)
|
||||
{
|
||||
bool modified = false;
|
||||
bool created = false;
|
||||
|
||||
AssetBase asset = null;
|
||||
|
||||
Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method);
|
||||
|
||||
if (rdata.Parameters.Length == 1)
|
||||
{
|
||||
|
||||
rdata.initXmlReader();
|
||||
XmlReader xml = rdata.reader;
|
||||
|
||||
if (!xml.ReadToFollowing("Asset"))
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path);
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data");
|
||||
}
|
||||
|
||||
UUID uuid = new UUID(rdata.Parameters[0]);
|
||||
asset = Rest.AssetServices.Get(uuid.ToString());
|
||||
|
||||
modified = (asset != null);
|
||||
created = !modified;
|
||||
|
||||
asset = new AssetBase(uuid, xml.GetAttribute("name"), SByte.Parse(xml.GetAttribute("type")), UUID.Zero.ToString());
|
||||
asset.Description = xml.GetAttribute("desc");
|
||||
asset.Local = Int32.Parse(xml.GetAttribute("local")) != 0;
|
||||
asset.Temporary = Int32.Parse(xml.GetAttribute("temporary")) != 0;
|
||||
asset.Data = Convert.FromBase64String(xml.ReadElementContentAsString("Asset", ""));
|
||||
|
||||
if (asset.ID != rdata.Parameters[0])
|
||||
{
|
||||
Rest.Log.WarnFormat("{0} URI and payload disagree on UUID U:{1} vs P:{2}",
|
||||
MsgId, rdata.Parameters[0], asset.ID);
|
||||
}
|
||||
|
||||
Rest.AssetServices.Store(asset);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
|
||||
rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
|
||||
}
|
||||
|
||||
if (created)
|
||||
{
|
||||
rdata.appendStatus(String.Format("<p> Created asset {0}, UUID {1} <p>", asset.Name, asset.FullID));
|
||||
rdata.Complete(Rest.HttpStatusCodeCreated);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (modified)
|
||||
{
|
||||
rdata.appendStatus(String.Format("<p> Modified asset {0}, UUID {1} <p>", asset.Name, asset.FullID));
|
||||
rdata.Complete(Rest.HttpStatusCodeOK);
|
||||
}
|
||||
else
|
||||
{
|
||||
rdata.Complete(Rest.HttpStatusCodeNoContent);
|
||||
}
|
||||
}
|
||||
|
||||
rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method));
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CREATE new item, replace if it exists. URI identifies the context for the item in question.
|
||||
/// No parameters are required for POST, just thepayload.
|
||||
/// </summary>
|
||||
|
||||
private void DoPost(AssetRequestData rdata)
|
||||
{
|
||||
|
||||
bool modified = false;
|
||||
bool created = false;
|
||||
|
||||
Rest.Log.DebugFormat("{0} REST Asset handler, Method = <{1}> ENTRY", MsgId, rdata.method);
|
||||
|
||||
if (rdata.Parameters.Length != 0)
|
||||
{
|
||||
Rest.Log.WarnFormat("{0} Parameters ignored <{1}>", MsgId, rdata.path);
|
||||
Rest.Log.InfoFormat("{0} POST of an asset has no parameters", MsgId, rdata.path);
|
||||
}
|
||||
|
||||
rdata.initXmlReader();
|
||||
XmlReader xml = rdata.reader;
|
||||
|
||||
if (!xml.ReadToFollowing("Asset"))
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path);
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data");
|
||||
}
|
||||
|
||||
UUID uuid = new UUID(xml.GetAttribute("id"));
|
||||
AssetBase asset = Rest.AssetServices.Get(uuid.ToString());
|
||||
|
||||
modified = (asset != null);
|
||||
created = !modified;
|
||||
|
||||
asset = new AssetBase(uuid, xml.GetAttribute("name"), SByte.Parse(xml.GetAttribute("type")), UUID.Zero.ToString());
|
||||
asset.Description = xml.GetAttribute("desc");
|
||||
asset.Local = Int32.Parse(xml.GetAttribute("local")) != 0;
|
||||
asset.Temporary = Int32.Parse(xml.GetAttribute("temporary")) != 0;
|
||||
asset.Data = Convert.FromBase64String(xml.ReadElementContentAsString("Asset", ""));
|
||||
|
||||
Rest.AssetServices.Store(asset);
|
||||
|
||||
if (created)
|
||||
{
|
||||
rdata.appendStatus(String.Format("<p> Created asset {0}, UUID {1} <p>", asset.Name, asset.FullID));
|
||||
rdata.Complete(Rest.HttpStatusCodeCreated);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (modified)
|
||||
{
|
||||
rdata.appendStatus(String.Format("<p> Modified asset {0}, UUID {1} <p>", asset.Name, asset.FullID));
|
||||
rdata.Complete(Rest.HttpStatusCodeOK);
|
||||
}
|
||||
else
|
||||
{
|
||||
rdata.Complete(Rest.HttpStatusCodeNoContent);
|
||||
}
|
||||
}
|
||||
|
||||
rdata.Respond(String.Format("Asset {0} : Normal completion", rdata.method));
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asset processing has no special data area requirements.
|
||||
/// </summary>
|
||||
|
||||
internal class AssetRequestData : RequestData
|
||||
{
|
||||
internal AssetRequestData(OSHttpRequest request, OSHttpResponse response, string prefix)
|
||||
: base(request, response, prefix)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,448 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Xml;
|
||||
using System.IO;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Servers;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||
{
|
||||
public class RestFileServices : IRest
|
||||
{
|
||||
private bool enabled = false;
|
||||
private string qPrefix = "files";
|
||||
|
||||
// A simple constructor is used to handle any once-only
|
||||
// initialization of working classes.
|
||||
|
||||
public RestFileServices()
|
||||
{
|
||||
Rest.Log.InfoFormat("{0} File services initializing", MsgId);
|
||||
Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
|
||||
|
||||
// If the handler specifies a relative path for its domain
|
||||
// then we must add the standard absolute prefix, e.g. /admin
|
||||
|
||||
if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
|
||||
{
|
||||
Rest.Log.InfoFormat("{0} Prefixing domain name ({1})", MsgId, qPrefix);
|
||||
qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
|
||||
Rest.Log.InfoFormat("{0} Fully qualified domain name is <{1}>", MsgId, qPrefix);
|
||||
}
|
||||
|
||||
// Register interface using the fully-qualified prefix
|
||||
|
||||
Rest.Plugin.AddPathHandler(DoFile, qPrefix, Allocate);
|
||||
|
||||
// Activate if all went OK
|
||||
|
||||
enabled = true;
|
||||
|
||||
Rest.Log.InfoFormat("{0} File services initialization complete", MsgId);
|
||||
}
|
||||
|
||||
// Post-construction, pre-enabled initialization opportunity
|
||||
// Not currently exploited.
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
// Called by the plug-in to halt REST processing. Local processing is
|
||||
// disabled, and control blocks until all current processing has
|
||||
// completed. No new processing will be started
|
||||
|
||||
public void Close()
|
||||
{
|
||||
enabled = false;
|
||||
Rest.Log.InfoFormat("{0} File services ({1}) closing down", MsgId, qPrefix);
|
||||
}
|
||||
|
||||
// Properties
|
||||
|
||||
internal string MsgId
|
||||
{
|
||||
get { return Rest.MsgId; }
|
||||
}
|
||||
|
||||
#region Interface
|
||||
|
||||
private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
|
||||
{
|
||||
return (RequestData) new FileRequestData(request, response, prefix);
|
||||
}
|
||||
|
||||
// Asset Handler
|
||||
|
||||
private void DoFile(RequestData rparm)
|
||||
{
|
||||
if (!enabled) return;
|
||||
|
||||
FileRequestData rdata = (FileRequestData) rparm;
|
||||
|
||||
Rest.Log.DebugFormat("{0} REST File handler ({1}) ENTRY", MsgId, qPrefix);
|
||||
|
||||
// Now that we know this is a serious attempt to
|
||||
// access file data, we should find out who
|
||||
// is asking, and make sure they are authorized
|
||||
// to do so. We need to validate the caller's
|
||||
// identity before revealing anything about the
|
||||
// status quo. Authenticate throws an exception
|
||||
// via Fail if no identity information is present.
|
||||
//
|
||||
// With the present HTTP server we can't use the
|
||||
// builtin authentication mechanisms because they
|
||||
// would be enforced for all in-bound requests.
|
||||
// Instead we look at the headers ourselves and
|
||||
// handle authentication directly.
|
||||
|
||||
try
|
||||
{
|
||||
if (!rdata.IsAuthenticated)
|
||||
{
|
||||
rdata.Fail(Rest.HttpStatusCodeNotAuthorized, String.Format("user \"{0}\" could not be authenticated"));
|
||||
}
|
||||
}
|
||||
catch (RestException e)
|
||||
{
|
||||
if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
|
||||
{
|
||||
Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
|
||||
Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId,
|
||||
rdata.request.Headers.Get("Authorization"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
|
||||
Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId,
|
||||
rdata.request.Headers.Get("Authorization"));
|
||||
}
|
||||
throw (e);
|
||||
}
|
||||
|
||||
// Remove the prefix and what's left are the parameters. If we don't have
|
||||
// the parameters we need, fail the request. Parameters do NOT include
|
||||
// any supplied query values.
|
||||
|
||||
if (rdata.Parameters.Length > 0)
|
||||
{
|
||||
switch (rdata.method)
|
||||
{
|
||||
case "get" :
|
||||
DoGet(rdata);
|
||||
break;
|
||||
case "put" :
|
||||
DoPut(rdata);
|
||||
break;
|
||||
case "post" :
|
||||
DoPost(rdata);
|
||||
break;
|
||||
case "delete" :
|
||||
DoDelete(rdata);
|
||||
break;
|
||||
default :
|
||||
Rest.Log.WarnFormat("{0} File: Method not supported: {1}",
|
||||
MsgId, rdata.method);
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest,String.Format("method <{0}> not supported", rdata.method));
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Rest.Log.WarnFormat("{0} File: No agent information provided", MsgId);
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest, "no agent information provided");
|
||||
}
|
||||
|
||||
Rest.Log.DebugFormat("{0} REST File handler EXIT", MsgId);
|
||||
|
||||
}
|
||||
|
||||
#endregion Interface
|
||||
|
||||
/// <summary>
|
||||
/// The only parameter we recognize is a UUID.If an asset with this identification is
|
||||
/// found, it's content, base-64 encoded, is returned to the client.
|
||||
/// </summary>
|
||||
|
||||
private void DoGet(FileRequestData rdata)
|
||||
{
|
||||
|
||||
string path = String.Empty;
|
||||
|
||||
Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method);
|
||||
|
||||
if (rdata.Parameters.Length > 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} File located <{1}>", MsgId, path);
|
||||
Byte[] data = File.ReadAllBytes(path);
|
||||
rdata.initXmlWriter();
|
||||
rdata.writer.WriteStartElement(String.Empty,"File",String.Empty);
|
||||
rdata.writer.WriteAttributeString("name", path);
|
||||
rdata.writer.WriteBase64(data,0,data.Length);
|
||||
rdata.writer.WriteFullEndElement();
|
||||
}
|
||||
else
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, path);
|
||||
rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0}", path));
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, e.Message);
|
||||
rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0} {1}",
|
||||
path, e.Message));
|
||||
}
|
||||
}
|
||||
|
||||
rdata.Complete();
|
||||
rdata.Respond(String.Format("File <{0}> : Normal completion", rdata.method));
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// UPDATE existing item, if it exists. URI identifies the item in question.
|
||||
/// The only parameter we recognize is a UUID. The enclosed asset data (base-64 encoded)
|
||||
/// is decoded and stored in the database, identified by the supplied UUID.
|
||||
/// </summary>
|
||||
private void DoPut(FileRequestData rdata)
|
||||
{
|
||||
bool modified = false;
|
||||
bool created = false;
|
||||
string path = String.Empty;
|
||||
|
||||
Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method);
|
||||
|
||||
if (rdata.Parameters.Length > 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2);
|
||||
bool maymod = File.Exists(path);
|
||||
|
||||
rdata.initXmlReader();
|
||||
XmlReader xml = rdata.reader;
|
||||
|
||||
if (!xml.ReadToFollowing("File"))
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path);
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data");
|
||||
}
|
||||
|
||||
Byte[] data = Convert.FromBase64String(xml.ReadElementContentAsString("File", ""));
|
||||
|
||||
File.WriteAllBytes(path,data);
|
||||
modified = maymod;
|
||||
created = ! maymod;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId,
|
||||
e.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
|
||||
rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
|
||||
}
|
||||
|
||||
if (created)
|
||||
{
|
||||
rdata.appendStatus(String.Format("<p> Created file {0} <p>", path));
|
||||
rdata.Complete(Rest.HttpStatusCodeCreated);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (modified)
|
||||
{
|
||||
rdata.appendStatus(String.Format("<p> Modified file {0} <p>", path));
|
||||
rdata.Complete(Rest.HttpStatusCodeOK);
|
||||
}
|
||||
else
|
||||
{
|
||||
rdata.Complete(Rest.HttpStatusCodeNoContent);
|
||||
}
|
||||
}
|
||||
|
||||
rdata.Respond(String.Format("File {0} : Normal completion", rdata.method));
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CREATE new item, replace if it exists. URI identifies the context for the item in question.
|
||||
/// No parameters are required for POST, just thepayload.
|
||||
/// </summary>
|
||||
|
||||
private void DoPost(FileRequestData rdata)
|
||||
{
|
||||
|
||||
bool modified = false;
|
||||
bool created = false;
|
||||
string path = String.Empty;
|
||||
|
||||
Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method);
|
||||
|
||||
if (rdata.Parameters.Length > 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2);
|
||||
bool maymod = File.Exists(path);
|
||||
|
||||
rdata.initXmlReader();
|
||||
XmlReader xml = rdata.reader;
|
||||
|
||||
if (!xml.ReadToFollowing("File"))
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Invalid request data: <{1}>", MsgId, rdata.path);
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest,"invalid request data");
|
||||
}
|
||||
|
||||
Byte[] data = Convert.FromBase64String(xml.ReadElementContentAsString("File", ""));
|
||||
|
||||
File.WriteAllBytes(path,data);
|
||||
modified = maymod;
|
||||
created = ! maymod;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId,
|
||||
e.Message);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
|
||||
rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
|
||||
}
|
||||
|
||||
if (created)
|
||||
{
|
||||
rdata.appendStatus(String.Format("<p> Created file {0} <p>", path));
|
||||
rdata.Complete(Rest.HttpStatusCodeCreated);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (modified)
|
||||
{
|
||||
rdata.appendStatus(String.Format("<p> Modified file {0} <p>", path));
|
||||
rdata.Complete(Rest.HttpStatusCodeOK);
|
||||
}
|
||||
else
|
||||
{
|
||||
rdata.Complete(Rest.HttpStatusCodeNoContent);
|
||||
}
|
||||
}
|
||||
|
||||
rdata.Respond(String.Format("File {0} : Normal completion", rdata.method));
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// CREATE new item, replace if it exists. URI identifies the context for the item in question.
|
||||
/// No parameters are required for POST, just thepayload.
|
||||
/// </summary>
|
||||
|
||||
private void DoDelete(FileRequestData rdata)
|
||||
{
|
||||
|
||||
bool modified = false;
|
||||
bool created = false;
|
||||
string path = String.Empty;
|
||||
|
||||
Rest.Log.DebugFormat("{0} REST File handler, Method = <{1}> ENTRY", MsgId, rdata.method);
|
||||
|
||||
if (rdata.Parameters.Length > 1)
|
||||
{
|
||||
try
|
||||
{
|
||||
path = rdata.path.Substring(rdata.Parameters[0].Length+qPrefix.Length+2);
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
File.Delete(path);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Exception during file processing : {1}", MsgId,
|
||||
e.Message);
|
||||
rdata.Fail(Rest.HttpStatusCodeNotFound, String.Format("invalid parameters : {0} {1}",
|
||||
path, e.Message));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Invalid parameters: <{1}>", MsgId, rdata.path);
|
||||
rdata.Fail(Rest.HttpStatusCodeNotFound, "invalid parameters");
|
||||
}
|
||||
|
||||
if (created)
|
||||
{
|
||||
rdata.appendStatus(String.Format("<p> Created file {0} <p>", path));
|
||||
rdata.Complete(Rest.HttpStatusCodeCreated);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (modified)
|
||||
{
|
||||
rdata.appendStatus(String.Format("<p> Modified file {0} <p>", path));
|
||||
rdata.Complete(Rest.HttpStatusCodeOK);
|
||||
}
|
||||
else
|
||||
{
|
||||
rdata.Complete(Rest.HttpStatusCodeNoContent);
|
||||
}
|
||||
}
|
||||
|
||||
rdata.Respond(String.Format("File {0} : Normal completion", rdata.method));
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// File processing has no special data area requirements.
|
||||
/// </summary>
|
||||
|
||||
internal class FileRequestData : RequestData
|
||||
{
|
||||
internal FileRequestData(OSHttpRequest request, OSHttpResponse response, string prefix)
|
||||
: base(request, response, prefix)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,662 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using OpenSim.Framework.Servers;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||
{
|
||||
/// <remarks>
|
||||
/// The class signature reveals the roles that RestHandler plays.
|
||||
///
|
||||
/// [1] It is a sub-class of RestPlugin. It inherits and extends
|
||||
/// the functionality of this class, constraining it to the
|
||||
/// specific needs of this REST implementation. This relates
|
||||
/// to the plug-in mechanism supported by OpenSim, the specifics
|
||||
/// of which are mostly hidden by RestPlugin.
|
||||
/// [2] IRestHandler describes the interface that this class
|
||||
/// exports to service implementations. This is the services
|
||||
/// management interface.
|
||||
/// [3] IHttpAgentHandler describes the interface that is exported
|
||||
/// to the BaseHttpServer in support of this particular HTTP
|
||||
/// processing model. This is the request interface of the
|
||||
/// handler.
|
||||
/// </remarks>
|
||||
|
||||
public class RestHandler : RestPlugin, IRestHandler, IHttpAgentHandler
|
||||
{
|
||||
// Handler tables: both stream and REST are supported. The path handlers and their
|
||||
// respective allocators are stored in separate tables.
|
||||
|
||||
internal Dictionary<string,RestMethodHandler> pathHandlers = new Dictionary<string,RestMethodHandler>();
|
||||
internal Dictionary<string,RestMethodAllocator> pathAllocators = new Dictionary<string,RestMethodAllocator>();
|
||||
internal Dictionary<string,RestStreamHandler> streamHandlers = new Dictionary<string,RestStreamHandler>();
|
||||
|
||||
#region local static state
|
||||
|
||||
private static bool handlersLoaded = false;
|
||||
private static List<Type> classes = new List<Type>();
|
||||
private static List<IRest> handlers = new List<IRest>();
|
||||
private static Type[] parms = new Type[0];
|
||||
private static Object[] args = new Object[0];
|
||||
|
||||
/// <summary>
|
||||
/// This static initializer scans the ASSEMBLY for classes that
|
||||
/// export the IRest interface and builds a list of them. These
|
||||
/// are later activated by the handler. To add a new handler it
|
||||
/// is only necessary to create a new services class that implements
|
||||
/// the IRest interface, and recompile the handler. This gives
|
||||
/// all of the build-time flexibility of a modular approach
|
||||
/// while not introducing yet-another module loader. Note that
|
||||
/// multiple assembles can still be built, each with its own set
|
||||
/// of handlers. Examples of services classes are RestInventoryServices
|
||||
/// and RestSkeleton.
|
||||
/// </summary>
|
||||
|
||||
static RestHandler()
|
||||
{
|
||||
Module[] mods = Assembly.GetExecutingAssembly().GetModules();
|
||||
|
||||
foreach (Module m in mods)
|
||||
{
|
||||
Type[] types = m.GetTypes();
|
||||
foreach (Type t in types)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (t.GetInterface("IRest") != null)
|
||||
{
|
||||
classes.Add(t);
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Rest.Log.WarnFormat("[STATIC-HANDLER]: #0 Error scanning {1}", t);
|
||||
Rest.Log.InfoFormat("[STATIC-HANDLER]: #0 {1} is not included", t);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion local static state
|
||||
|
||||
#region local instance state
|
||||
|
||||
/// <summary>
|
||||
/// This routine loads all of the handlers discovered during
|
||||
/// instance initialization.
|
||||
/// A table of all loaded and successfully constructed handlers
|
||||
/// is built, and this table is then used by the constructor to
|
||||
/// initialize each of the handlers in turn.
|
||||
/// NOTE: The loading process does not automatically imply that
|
||||
/// the handler has registered any kind of an interface, that
|
||||
/// may be (optionally) done by the handler either during
|
||||
/// construction, or during initialization.
|
||||
///
|
||||
/// I was not able to make this code work within a constructor
|
||||
/// so it is isolated within this method.
|
||||
/// </summary>
|
||||
|
||||
private void LoadHandlers()
|
||||
{
|
||||
lock (handlers)
|
||||
{
|
||||
if (!handlersLoaded)
|
||||
{
|
||||
ConstructorInfo ci;
|
||||
Object ht;
|
||||
|
||||
foreach (Type t in classes)
|
||||
{
|
||||
try
|
||||
{
|
||||
ci = t.GetConstructor(parms);
|
||||
ht = ci.Invoke(args);
|
||||
handlers.Add((IRest)ht);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Rest.Log.WarnFormat("{0} Unable to load {1} : {2}", MsgId, t, e.Message);
|
||||
}
|
||||
}
|
||||
handlersLoaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion local instance state
|
||||
|
||||
#region overriding properties
|
||||
|
||||
// These properties override definitions
|
||||
// in the base class.
|
||||
|
||||
// Name is used to differentiate the message header.
|
||||
|
||||
public override string Name
|
||||
{
|
||||
get { return "HANDLER"; }
|
||||
}
|
||||
|
||||
// Used to partition the .ini configuration space.
|
||||
|
||||
public override string ConfigName
|
||||
{
|
||||
get { return "RestHandler"; }
|
||||
}
|
||||
|
||||
// We have to rename these because we want
|
||||
// to be able to share the values with other
|
||||
// classes in our assembly and the base
|
||||
// names are protected.
|
||||
|
||||
public string MsgId
|
||||
{
|
||||
get { return base.MsgID; }
|
||||
}
|
||||
|
||||
public string RequestId
|
||||
{
|
||||
get { return base.RequestID; }
|
||||
}
|
||||
|
||||
#endregion overriding properties
|
||||
|
||||
#region overriding methods
|
||||
|
||||
/// <summary>
|
||||
/// This method is called by OpenSimMain immediately after loading the
|
||||
/// plugin and after basic server setup, but before running any server commands.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that entries MUST be added to the active configuration files before
|
||||
/// the plugin can be enabled.
|
||||
/// </remarks>
|
||||
|
||||
public override void Initialise(OpenSimBase openSim)
|
||||
{
|
||||
try
|
||||
{
|
||||
// This plugin will only be enabled if the broader
|
||||
// REST plugin mechanism is enabled.
|
||||
|
||||
//Rest.Log.InfoFormat("{0} Plugin is initializing", MsgId);
|
||||
|
||||
base.Initialise(openSim);
|
||||
|
||||
// IsEnabled is implemented by the base class and
|
||||
// reflects an overall RestPlugin status
|
||||
|
||||
if (!IsEnabled)
|
||||
{
|
||||
//Rest.Log.WarnFormat("{0} Plugins are disabled", MsgId);
|
||||
return;
|
||||
}
|
||||
|
||||
Rest.Log.InfoFormat("{0} Rest <{1}> plugin will be enabled", MsgId, Name);
|
||||
Rest.Log.InfoFormat("{0} Configuration parameters read from <{1}>", MsgId, ConfigName);
|
||||
|
||||
// These are stored in static variables to make
|
||||
// them easy to reach from anywhere in the assembly.
|
||||
|
||||
Rest.main = openSim;
|
||||
if (Rest.main == null)
|
||||
throw new Exception("OpenSim base pointer is null");
|
||||
|
||||
Rest.Plugin = this;
|
||||
Rest.Config = Config;
|
||||
Rest.Prefix = Prefix;
|
||||
Rest.GodKey = GodKey;
|
||||
Rest.Authenticate = Rest.Config.GetBoolean("authenticate", Rest.Authenticate);
|
||||
Rest.Scheme = Rest.Config.GetString("auth-scheme", Rest.Scheme);
|
||||
Rest.Secure = Rest.Config.GetBoolean("secured", Rest.Secure);
|
||||
Rest.ExtendedEscape = Rest.Config.GetBoolean("extended-escape", Rest.ExtendedEscape);
|
||||
Rest.Realm = Rest.Config.GetString("realm", Rest.Realm);
|
||||
Rest.DumpAsset = Rest.Config.GetBoolean("dump-asset", Rest.DumpAsset);
|
||||
Rest.Fill = Rest.Config.GetBoolean("path-fill", Rest.Fill);
|
||||
Rest.DumpLineSize = Rest.Config.GetInt("dump-line-size", Rest.DumpLineSize);
|
||||
Rest.FlushEnabled = Rest.Config.GetBoolean("flush-on-error", Rest.FlushEnabled);
|
||||
|
||||
// Note: Odd spacing is required in the following strings
|
||||
|
||||
Rest.Log.InfoFormat("{0} Authentication is {1}required", MsgId,
|
||||
(Rest.Authenticate ? "" : "not "));
|
||||
|
||||
Rest.Log.InfoFormat("{0} Security is {1}enabled", MsgId,
|
||||
(Rest.Secure ? "" : "not "));
|
||||
|
||||
Rest.Log.InfoFormat("{0} Extended URI escape processing is {1}enabled", MsgId,
|
||||
(Rest.ExtendedEscape ? "" : "not "));
|
||||
|
||||
Rest.Log.InfoFormat("{0} Dumping of asset data is {1}enabled", MsgId,
|
||||
(Rest.DumpAsset ? "" : "not "));
|
||||
|
||||
// The supplied prefix MUST be absolute
|
||||
|
||||
if (Rest.Prefix.Substring(0,1) != Rest.UrlPathSeparator)
|
||||
{
|
||||
Rest.Log.WarnFormat("{0} Prefix <{1}> is not absolute and must be", MsgId, Rest.Prefix);
|
||||
Rest.Log.InfoFormat("{0} Prefix changed to </{1}>", MsgId, Rest.Prefix);
|
||||
Rest.Prefix = String.Format("{0}{1}", Rest.UrlPathSeparator, Rest.Prefix);
|
||||
}
|
||||
|
||||
// If data dumping is requested, report on the chosen line
|
||||
// length.
|
||||
|
||||
if (Rest.DumpAsset)
|
||||
{
|
||||
Rest.Log.InfoFormat("{0} Dump {1} bytes per line", MsgId, Rest.DumpLineSize);
|
||||
}
|
||||
|
||||
// Load all of the handlers present in the
|
||||
// assembly
|
||||
|
||||
// In principle, as we're an application plug-in,
|
||||
// most of what needs to be done could be done using
|
||||
// static resources, however the Open Sim plug-in
|
||||
// model makes this an instance, so that's what we
|
||||
// need to be.
|
||||
// There is only one Communications manager per
|
||||
// server, and by inference, only one each of the
|
||||
// user, asset, and inventory servers. So we can cache
|
||||
// those using a static initializer.
|
||||
// We move all of this processing off to another
|
||||
// services class to minimize overlap between function
|
||||
// and infrastructure.
|
||||
|
||||
LoadHandlers();
|
||||
|
||||
// The intention of a post construction initializer
|
||||
// is to allow for setup that is dependent upon other
|
||||
// activities outside of the agency.
|
||||
|
||||
foreach (IRest handler in handlers)
|
||||
{
|
||||
try
|
||||
{
|
||||
handler.Initialize();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Rest.Log.ErrorFormat("{0} initialization error: {1}", MsgId, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
// Now that everything is setup we can proceed to
|
||||
// add THIS agent to the HTTP server's handler list
|
||||
|
||||
// FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
|
||||
// have to be handled through the AddHttpHandler interface.
|
||||
// if (!AddAgentHandler(Rest.Name,this))
|
||||
// {
|
||||
// Rest.Log.ErrorFormat("{0} Unable to activate handler interface", MsgId);
|
||||
// foreach (IRest handler in handlers)
|
||||
// {
|
||||
// handler.Close();
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Rest.Log.ErrorFormat("{0} Plugin initialization has failed: {1}", MsgId, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// In the interests of efficiency, and because we cannot determine whether
|
||||
/// or not this instance will actually be harvested, we clobber the only
|
||||
/// anchoring reference to the working state for this plug-in. What the
|
||||
/// call to close does is irrelevant to this class beyond knowing that it
|
||||
/// can nullify the reference when it returns.
|
||||
/// To make sure everything is copacetic we make sure the primary interface
|
||||
/// is disabled by deleting the handler from the HTTP server tables.
|
||||
/// </summary>
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
Rest.Log.InfoFormat("{0} Plugin is terminating", MsgId);
|
||||
|
||||
// FIXME: If this code is ever to be re-enabled (most of it is disabled already) then this will
|
||||
// have to be handled through the AddHttpHandler interface.
|
||||
// try
|
||||
// {
|
||||
// RemoveAgentHandler(Rest.Name, this);
|
||||
// }
|
||||
// catch (KeyNotFoundException){}
|
||||
|
||||
foreach (IRest handler in handlers)
|
||||
{
|
||||
handler.Close();
|
||||
}
|
||||
}
|
||||
|
||||
#endregion overriding methods
|
||||
|
||||
#region interface methods
|
||||
|
||||
/// <summary>
|
||||
/// This method is called by the HTTP server to match an incoming
|
||||
/// request. It scans all of the strings registered by the
|
||||
/// underlying handlers and looks for the best match. It returns
|
||||
/// true if a match is found.
|
||||
/// The matching process could be made arbitrarily complex.
|
||||
/// Note: The match is case-insensitive.
|
||||
/// </summary>
|
||||
|
||||
public bool Match(OSHttpRequest request, OSHttpResponse response)
|
||||
{
|
||||
|
||||
string path = request.RawUrl.ToLower();
|
||||
|
||||
// Rest.Log.DebugFormat("{0} Match ENTRY", MsgId);
|
||||
|
||||
try
|
||||
{
|
||||
foreach (string key in pathHandlers.Keys)
|
||||
{
|
||||
// Rest.Log.DebugFormat("{0} Match testing {1} against agent prefix <{2}>", MsgId, path, key);
|
||||
|
||||
// Note that Match will not necessarily find the handler that will
|
||||
// actually be used - it does no test for the "closest" fit. It
|
||||
// simply reflects that at least one possible handler exists.
|
||||
|
||||
if (path.StartsWith(key))
|
||||
{
|
||||
// Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key);
|
||||
|
||||
// This apparently odd evaluation is needed to prevent a match
|
||||
// on anything other than a URI token boundary. Otherwise we
|
||||
// may match on URL's that were not intended for this handler.
|
||||
|
||||
return (path.Length == key.Length ||
|
||||
path.Substring(key.Length, 1) == Rest.UrlPathSeparator);
|
||||
}
|
||||
}
|
||||
|
||||
path = String.Format("{0}{1}{2}", request.HttpMethod, Rest.UrlMethodSeparator, path);
|
||||
|
||||
foreach (string key in streamHandlers.Keys)
|
||||
{
|
||||
// Rest.Log.DebugFormat("{0} Match testing {1} against stream prefix <{2}>", MsgId, path, key);
|
||||
|
||||
// Note that Match will not necessarily find the handler that will
|
||||
// actually be used - it does no test for the "closest" fit. It
|
||||
// simply reflects that at least one possible handler exists.
|
||||
|
||||
if (path.StartsWith(key))
|
||||
{
|
||||
// Rest.Log.DebugFormat("{0} Matched prefix <{1}>", MsgId, key);
|
||||
|
||||
// This apparently odd evaluation is needed to prevent a match
|
||||
// on anything other than a URI token boundary. Otherwise we
|
||||
// may match on URL's that were not intended for this handler.
|
||||
|
||||
return (path.Length == key.Length ||
|
||||
path.Substring(key.Length, 1) == Rest.UrlPathSeparator);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Rest.Log.ErrorFormat("{0} matching exception for path <{1}> : {2}", MsgId, path, e.Message);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This is called by the HTTP server once the handler has indicated
|
||||
/// that it is able to handle the request.
|
||||
/// Preconditions:
|
||||
/// [1] request != null and is a valid request object
|
||||
/// [2] response != null and is a valid response object
|
||||
/// Behavior is undefined if preconditions are not satisfied.
|
||||
/// </summary>
|
||||
|
||||
public bool Handle(OSHttpRequest request, OSHttpResponse response)
|
||||
{
|
||||
bool handled;
|
||||
base.MsgID = base.RequestID;
|
||||
|
||||
// Debug only
|
||||
|
||||
if (Rest.DEBUG)
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} ENTRY", MsgId);
|
||||
Rest.Log.DebugFormat("{0} Agent: {1}", MsgId, request.UserAgent);
|
||||
Rest.Log.DebugFormat("{0} Method: {1}", MsgId, request.HttpMethod);
|
||||
|
||||
for (int i = 0; i < request.Headers.Count; i++)
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Header [{1}] : <{2}> = <{3}>",
|
||||
MsgId, i, request.Headers.GetKey(i), request.Headers.Get(i));
|
||||
}
|
||||
Rest.Log.DebugFormat("{0} URI: {1}", MsgId, request.RawUrl);
|
||||
}
|
||||
|
||||
// If a path handler worked we're done, otherwise try any
|
||||
// available stream handlers too.
|
||||
|
||||
try
|
||||
{
|
||||
handled = (FindPathHandler(request, response) ||
|
||||
FindStreamHandler(request, response));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// A raw exception indicates that something we weren't expecting has
|
||||
// happened. This should always reflect a shortcoming in the plugin,
|
||||
// or a failure to satisfy the preconditions. It should not reflect
|
||||
// an error in the request itself. Under such circumstances the state
|
||||
// of the request cannot be determined and we are obliged to mark it
|
||||
// as 'handled'.
|
||||
|
||||
Rest.Log.ErrorFormat("{0} Plugin error: {1}", MsgId, e.Message);
|
||||
handled = true;
|
||||
}
|
||||
|
||||
Rest.Log.DebugFormat("{0} EXIT", MsgId);
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
#endregion interface methods
|
||||
|
||||
/// <summary>
|
||||
/// If there is a stream handler registered that can handle the
|
||||
/// request, then fine. If the request is not matched, do
|
||||
/// nothing.
|
||||
/// Note: The selection is case-insensitive
|
||||
/// </summary>
|
||||
|
||||
private bool FindStreamHandler(OSHttpRequest request, OSHttpResponse response)
|
||||
{
|
||||
RequestData rdata = new RequestData(request, response, String.Empty);
|
||||
|
||||
string bestMatch = String.Empty;
|
||||
string path = String.Format("{0}:{1}", rdata.method, rdata.path).ToLower();
|
||||
|
||||
Rest.Log.DebugFormat("{0} Checking for stream handler for <{1}>", MsgId, path);
|
||||
|
||||
if (!IsEnabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (string pattern in streamHandlers.Keys)
|
||||
{
|
||||
if (path.StartsWith(pattern))
|
||||
{
|
||||
if (pattern.Length > bestMatch.Length)
|
||||
{
|
||||
bestMatch = pattern;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Handle using the best match available
|
||||
|
||||
if (bestMatch.Length > 0)
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Stream-based handler matched with <{1}>", MsgId, bestMatch);
|
||||
RestStreamHandler handler = streamHandlers[bestMatch];
|
||||
rdata.buffer = handler.Handle(rdata.path, rdata.request.InputStream, rdata.request, rdata.response);
|
||||
rdata.AddHeader(rdata.response.ContentType,handler.ContentType);
|
||||
rdata.Respond("FindStreamHandler Completion");
|
||||
}
|
||||
|
||||
return rdata.handled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a stream handler for the designated HTTP method and path prefix.
|
||||
/// If the handler is not enabled, the request is ignored. If the path
|
||||
/// does not start with the REST prefix, it is added. If method-qualified
|
||||
/// path has not already been registered, the method is added to the active
|
||||
/// handler table.
|
||||
/// </summary>
|
||||
public void AddStreamHandler(string httpMethod, string path, RestMethod method)
|
||||
{
|
||||
if (!IsEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!path.StartsWith(Rest.Prefix))
|
||||
{
|
||||
path = String.Format("{0}{1}", Rest.Prefix, path);
|
||||
}
|
||||
|
||||
path = String.Format("{0}{1}{2}", httpMethod, Rest.UrlMethodSeparator, path);
|
||||
|
||||
// Conditionally add to the list
|
||||
|
||||
if (!streamHandlers.ContainsKey(path))
|
||||
{
|
||||
streamHandlers.Add(path, new RestStreamHandler(httpMethod, path, method));
|
||||
Rest.Log.DebugFormat("{0} Added handler for {1}", MsgId, path);
|
||||
}
|
||||
else
|
||||
{
|
||||
Rest.Log.WarnFormat("{0} Ignoring duplicate handler for {1}", MsgId, path);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Given the supplied request/response, if the handler is enabled, the inbound
|
||||
/// information is used to match an entry in the active path handler tables, using
|
||||
/// the method-qualified path information. If a match is found, then the handler is
|
||||
/// invoked. The result is the boolean result of the handler, or false if no
|
||||
/// handler was located. The boolean indicates whether or not the request has been
|
||||
/// handled, not whether or not the request was successful - that information is in
|
||||
/// the response.
|
||||
/// Note: The selection process is case-insensitive
|
||||
/// </summary>
|
||||
|
||||
internal bool FindPathHandler(OSHttpRequest request, OSHttpResponse response)
|
||||
{
|
||||
RequestData rdata = null;
|
||||
string bestMatch = null;
|
||||
|
||||
if (!IsEnabled)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Conditionally add to the list
|
||||
|
||||
Rest.Log.DebugFormat("{0} Checking for path handler for <{1}>", MsgId, request.RawUrl);
|
||||
|
||||
foreach (string pattern in pathHandlers.Keys)
|
||||
{
|
||||
if (request.RawUrl.ToLower().StartsWith(pattern))
|
||||
{
|
||||
if (String.IsNullOrEmpty(bestMatch) || pattern.Length > bestMatch.Length)
|
||||
{
|
||||
bestMatch = pattern;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!String.IsNullOrEmpty(bestMatch))
|
||||
{
|
||||
rdata = pathAllocators[bestMatch](request, response, bestMatch);
|
||||
|
||||
Rest.Log.DebugFormat("{0} Path based REST handler matched with <{1}>", MsgId, bestMatch);
|
||||
|
||||
try
|
||||
{
|
||||
pathHandlers[bestMatch](rdata);
|
||||
}
|
||||
|
||||
// A plugin generated error indicates a request-related error
|
||||
// that has been handled by the plugin.
|
||||
|
||||
catch (RestException r)
|
||||
{
|
||||
Rest.Log.WarnFormat("{0} Request failed: {1}", MsgId, r.Message);
|
||||
}
|
||||
}
|
||||
|
||||
return (rdata == null) ? false : rdata.handled;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A method handler and a request allocator are stored using the designated
|
||||
/// path as a key. If an entry already exists, it is replaced by the new one.
|
||||
/// </summary>
|
||||
|
||||
public void AddPathHandler(RestMethodHandler mh, string path, RestMethodAllocator ra)
|
||||
{
|
||||
if (!IsEnabled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (pathHandlers.ContainsKey(path))
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Replacing handler for <${1}>", MsgId, path);
|
||||
pathHandlers.Remove(path);
|
||||
}
|
||||
|
||||
if (pathAllocators.ContainsKey(path))
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Replacing allocator for <${1}>", MsgId, path);
|
||||
pathAllocators.Remove(path);
|
||||
}
|
||||
|
||||
Rest.Log.DebugFormat("{0} Adding path handler for {1}", MsgId, path);
|
||||
|
||||
pathHandlers.Add(path, mh);
|
||||
pathAllocators.Add(path, ra);
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,246 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
using OpenSim.Framework.Servers;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||
{
|
||||
public class RestTestServices : IRest
|
||||
{
|
||||
private bool enabled = false;
|
||||
private string qPrefix = "test";
|
||||
|
||||
// A simple constructor is used to handle any once-only
|
||||
// initialization of working classes.
|
||||
|
||||
public RestTestServices()
|
||||
{
|
||||
Rest.Log.InfoFormat("{0} Test services initializing", MsgId);
|
||||
Rest.Log.InfoFormat("{0} Using REST Implementation Version {1}", MsgId, Rest.Version);
|
||||
|
||||
// If a relative path was specified, make it absolute by adding
|
||||
// the standard prefix, e.g. /admin
|
||||
|
||||
if (!qPrefix.StartsWith(Rest.UrlPathSeparator))
|
||||
{
|
||||
Rest.Log.InfoFormat("{0} Domain is relative, adding absolute prefix", MsgId);
|
||||
qPrefix = String.Format("{0}{1}{2}", Rest.Prefix, Rest.UrlPathSeparator, qPrefix);
|
||||
Rest.Log.InfoFormat("{0} Domain is now <{1}>", MsgId, qPrefix);
|
||||
}
|
||||
|
||||
// Load test cases
|
||||
|
||||
loadTests();
|
||||
foreach (ITest test in tests)
|
||||
{
|
||||
test.Initialize();
|
||||
}
|
||||
|
||||
// Register interface
|
||||
|
||||
Rest.Plugin.AddPathHandler(DoTests,qPrefix,Allocate);
|
||||
|
||||
// Activate
|
||||
|
||||
enabled = true;
|
||||
|
||||
Rest.Log.InfoFormat("{0} Test services initialization complete", MsgId);
|
||||
}
|
||||
|
||||
// Post-construction, pre-enabled initialization opportunity
|
||||
// Not currently exploited.
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
}
|
||||
|
||||
// Called by the plug-in to halt REST processing. Local processing is
|
||||
// disabled, and control blocks until all current processing has
|
||||
// completed. No new processing will be started
|
||||
|
||||
public void Close()
|
||||
{
|
||||
enabled = false;
|
||||
foreach (ITest test in tests)
|
||||
{
|
||||
test.Close();
|
||||
}
|
||||
Rest.Log.InfoFormat("{0} Test services closing down", MsgId);
|
||||
}
|
||||
|
||||
// Properties
|
||||
|
||||
internal string MsgId
|
||||
{
|
||||
get { return Rest.MsgId; }
|
||||
}
|
||||
|
||||
#region Interface
|
||||
|
||||
private RequestData Allocate(OSHttpRequest request, OSHttpResponse response, string prefix)
|
||||
{
|
||||
return new RequestData(request, response, prefix);
|
||||
}
|
||||
|
||||
// Inventory Handler
|
||||
|
||||
private void DoTests(RequestData rdata)
|
||||
{
|
||||
if (!enabled)
|
||||
return;
|
||||
|
||||
// Now that we know this is a serious attempt to
|
||||
// access inventory data, we should find out who
|
||||
// is asking, and make sure they are authorized
|
||||
// to do so. We need to validate the caller's
|
||||
// identity before revealing anything about the
|
||||
// status quo. Authenticate throws an exception
|
||||
// via Fail if no identity information is present.
|
||||
//
|
||||
// With the present HTTP server we can't use the
|
||||
// builtin authentication mechanisms because they
|
||||
// would be enforced for all in-bound requests.
|
||||
// Instead we look at the headers ourselves and
|
||||
// handle authentication directly.
|
||||
|
||||
try
|
||||
{
|
||||
if (!rdata.IsAuthenticated)
|
||||
{
|
||||
rdata.Fail(Rest.HttpStatusCodeNotAuthorized,
|
||||
String.Format("user \"{0}\" could not be authenticated", rdata.userName));
|
||||
}
|
||||
}
|
||||
catch (RestException e)
|
||||
{
|
||||
if (e.statusCode == Rest.HttpStatusCodeNotAuthorized)
|
||||
{
|
||||
Rest.Log.WarnFormat("{0} User not authenticated", MsgId);
|
||||
Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
|
||||
}
|
||||
else
|
||||
{
|
||||
Rest.Log.ErrorFormat("{0} User authentication failed", MsgId);
|
||||
Rest.Log.DebugFormat("{0} Authorization header: {1}", MsgId, rdata.request.Headers.Get("Authorization"));
|
||||
}
|
||||
throw (e);
|
||||
}
|
||||
|
||||
// Check that a test was specified
|
||||
|
||||
if (rdata.Parameters.Length < 1)
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Insufficient parameters", MsgId);
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest, "not enough parameters");
|
||||
}
|
||||
|
||||
// Select the test
|
||||
|
||||
foreach (ITest test in tests)
|
||||
{
|
||||
if (!rdata.handled)
|
||||
test.Execute(rdata);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Interface
|
||||
|
||||
private static bool testsLoaded = false;
|
||||
private static List<Type> classes = new List<Type>();
|
||||
private static List<ITest> tests = new List<ITest>();
|
||||
private static Type[] parms = new Type[0];
|
||||
private static Object[] args = new Object[0];
|
||||
|
||||
static RestTestServices()
|
||||
{
|
||||
Module[] mods = Assembly.GetExecutingAssembly().GetModules();
|
||||
foreach (Module m in mods)
|
||||
{
|
||||
Type[] types = m.GetTypes();
|
||||
foreach (Type t in types)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (t.GetInterface("ITest") != null)
|
||||
{
|
||||
classes.Add(t);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Rest.Log.WarnFormat("[STATIC-TEST] Unable to include test {0} : {1}", t, e.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This routine loads all of the handlers discovered during
|
||||
/// instance initialization. Each handler is responsible for
|
||||
/// registering itself with this handler.
|
||||
/// I was not able to make this code work in a constructor.
|
||||
/// </summary>
|
||||
|
||||
private void loadTests()
|
||||
{
|
||||
lock (tests)
|
||||
{
|
||||
if (!testsLoaded)
|
||||
{
|
||||
|
||||
ConstructorInfo ci;
|
||||
Object ht;
|
||||
|
||||
foreach (Type t in classes)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (t.GetInterface("ITest") != null)
|
||||
{
|
||||
ci = t.GetConstructor(parms);
|
||||
ht = ci.Invoke(args);
|
||||
tests.Add((ITest)ht);
|
||||
Rest.Log.InfoFormat("{0} Test {1} added", MsgId, t);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Rest.Log.WarnFormat("{0} Unable to load test {1} : {2}", MsgId, t, e.Message);
|
||||
}
|
||||
}
|
||||
testsLoaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// This interface represents the boundary between the general purpose
|
||||
/// REST plugin handling, and the functionally specific handlers. The
|
||||
/// handler knows only to initialzie and terminate all such handlers
|
||||
/// that it finds.
|
||||
/// </summary>
|
||||
|
||||
internal interface ITest
|
||||
{
|
||||
void Initialize();
|
||||
void Execute(RequestData rdata);
|
||||
void Close();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,204 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Inventory.Tests
|
||||
{
|
||||
public class Remote : ITest
|
||||
{
|
||||
private static readonly int PARM_TESTID = 0;
|
||||
private static readonly int PARM_COMMAND = 1;
|
||||
|
||||
private static readonly int PARM_MOVE_AVATAR = 2;
|
||||
private static readonly int PARM_MOVE_X = 3;
|
||||
private static readonly int PARM_MOVE_Y = 4;
|
||||
private static readonly int PARM_MOVE_Z = 5;
|
||||
|
||||
private bool enabled = false;
|
||||
|
||||
// No constructor code is required.
|
||||
|
||||
public Remote()
|
||||
{
|
||||
Rest.Log.InfoFormat("{0} Remote services constructor", MsgId);
|
||||
}
|
||||
|
||||
// Post-construction, pre-enabled initialization opportunity
|
||||
// Not currently exploited.
|
||||
|
||||
public void Initialize()
|
||||
{
|
||||
enabled = true;
|
||||
Rest.Log.InfoFormat("{0} Remote services initialized", MsgId);
|
||||
}
|
||||
|
||||
// Called by the plug-in to halt REST processing. Local processing is
|
||||
// disabled, and control blocks until all current processing has
|
||||
// completed. No new processing will be started
|
||||
|
||||
public void Close()
|
||||
{
|
||||
enabled = false;
|
||||
Rest.Log.InfoFormat("{0} Remote services closing down", MsgId);
|
||||
}
|
||||
|
||||
// Properties
|
||||
|
||||
internal string MsgId
|
||||
{
|
||||
get { return Rest.MsgId; }
|
||||
}
|
||||
|
||||
// Remote Handler
|
||||
// Key information of interest here is the Parameters array, each
|
||||
// entry represents an element of the URI, with element zero being
|
||||
// the
|
||||
|
||||
public void Execute(RequestData rdata)
|
||||
{
|
||||
if (!enabled) return;
|
||||
|
||||
// If we can't relate to what's there, leave it for others.
|
||||
|
||||
if (rdata.Parameters.Length == 0 || rdata.Parameters[PARM_TESTID] != "remote")
|
||||
return;
|
||||
|
||||
Rest.Log.DebugFormat("{0} REST Remote handler ENTRY", MsgId);
|
||||
|
||||
// Remove the prefix and what's left are the parameters. If we don't have
|
||||
// the parameters we need, fail the request. Parameters do NOT include
|
||||
// any supplied query values.
|
||||
|
||||
if (rdata.Parameters.Length > 1)
|
||||
{
|
||||
switch (rdata.Parameters[PARM_COMMAND].ToLower())
|
||||
{
|
||||
case "move" :
|
||||
DoMove(rdata);
|
||||
break;
|
||||
default :
|
||||
DoHelp(rdata);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
DoHelp(rdata);
|
||||
}
|
||||
}
|
||||
|
||||
private void DoHelp(RequestData rdata)
|
||||
{
|
||||
rdata.body = Help;
|
||||
rdata.Complete();
|
||||
rdata.Respond("Help");
|
||||
}
|
||||
|
||||
private void DoMove(RequestData rdata)
|
||||
{
|
||||
if (rdata.Parameters.Length < 6)
|
||||
{
|
||||
Rest.Log.WarnFormat("{0} Move: No movement information provided", MsgId);
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest, "no movement information provided");
|
||||
}
|
||||
else
|
||||
{
|
||||
string[] names = rdata.Parameters[PARM_MOVE_AVATAR].Split(Rest.CA_SPACE);
|
||||
ScenePresence presence = null;
|
||||
Scene scene = null;
|
||||
|
||||
if (names.Length != 2)
|
||||
{
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest,
|
||||
String.Format("invalid avatar name: <{0}>",rdata.Parameters[PARM_MOVE_AVATAR]));
|
||||
}
|
||||
|
||||
Rest.Log.WarnFormat("{0} '{1}' command received for {2} {3}",
|
||||
MsgId, rdata.Parameters[0], names[0], names[1]);
|
||||
|
||||
// The first parameter should be an avatar name, look for the
|
||||
// avatar in the known regions first.
|
||||
|
||||
Rest.main.SceneManager.ForEachScene(delegate(Scene s)
|
||||
{
|
||||
s.ForEachRootScenePresence(delegate(ScenePresence sp)
|
||||
{
|
||||
if (sp.Firstname == names[0] && sp.Lastname == names[1])
|
||||
{
|
||||
scene = s;
|
||||
presence = sp;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
if (presence != null)
|
||||
{
|
||||
Rest.Log.DebugFormat("{0} Move : Avatar {1} located in region {2}",
|
||||
MsgId, rdata.Parameters[PARM_MOVE_AVATAR], scene.RegionInfo.RegionName);
|
||||
|
||||
try
|
||||
{
|
||||
float x = Convert.ToSingle(rdata.Parameters[PARM_MOVE_X]);
|
||||
float y = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Y]);
|
||||
float z = Convert.ToSingle(rdata.Parameters[PARM_MOVE_Z]);
|
||||
Vector3 vector = new Vector3(x, y, z);
|
||||
presence.MoveToTarget(vector, false, false);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest,
|
||||
String.Format("invalid parameters: {0}", e.Message));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
rdata.Fail(Rest.HttpStatusCodeBadRequest,
|
||||
String.Format("avatar {0} not present", rdata.Parameters[PARM_MOVE_AVATAR]));
|
||||
}
|
||||
|
||||
rdata.Complete();
|
||||
rdata.Respond("OK");
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly string Help =
|
||||
"<html>"
|
||||
+ "<head><title>Remote Command Usage</title></head>"
|
||||
+ "<body>"
|
||||
+ "<p>Supported commands are:</p>"
|
||||
+ "<dl>"
|
||||
+ "<dt>move/avatar-name/x/y/z</dt>"
|
||||
+ "<dd>moves the specified avatar to another location</dd>"
|
||||
+ "</dl>"
|
||||
+ "</body>"
|
||||
+ "</html>"
|
||||
;
|
||||
}
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Xml.Serialization;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Servers;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Regions
|
||||
{
|
||||
public partial class RestRegionPlugin : RestPlugin
|
||||
{
|
||||
#region GET methods
|
||||
public string GetHandler(string request, string path, string param,
|
||||
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
// foreach (string h in httpRequest.Headers.AllKeys)
|
||||
// foreach (string v in httpRequest.Headers.GetValues(h))
|
||||
// m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v);
|
||||
|
||||
MsgID = RequestID;
|
||||
m_log.DebugFormat("{0} GET path {1} param {2}", MsgID, path, param);
|
||||
|
||||
try
|
||||
{
|
||||
// param empty: regions list
|
||||
if (String.IsNullOrEmpty(param)) return GetHandlerRegions(httpResponse);
|
||||
|
||||
// param not empty: specific region
|
||||
return GetHandlerRegion(httpResponse, param);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "GET", e);
|
||||
}
|
||||
}
|
||||
|
||||
public string GetHandlerRegions(IOSHttpResponse httpResponse)
|
||||
{
|
||||
RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
|
||||
|
||||
rxw.WriteStartElement(String.Empty, "regions", String.Empty);
|
||||
foreach (Scene s in App.SceneManager.Scenes)
|
||||
{
|
||||
rxw.WriteStartElement(String.Empty, "uuid", String.Empty);
|
||||
rxw.WriteString(s.RegionInfo.RegionID.ToString());
|
||||
rxw.WriteEndElement();
|
||||
}
|
||||
rxw.WriteEndElement();
|
||||
|
||||
return rxw.ToString();
|
||||
}
|
||||
|
||||
protected string ShortRegionInfo(string key, string value)
|
||||
{
|
||||
RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
|
||||
|
||||
if (String.IsNullOrEmpty(value) ||
|
||||
String.IsNullOrEmpty(key)) return null;
|
||||
|
||||
rxw.WriteStartElement(String.Empty, "region", String.Empty);
|
||||
rxw.WriteStartElement(String.Empty, key, String.Empty);
|
||||
rxw.WriteString(value);
|
||||
rxw.WriteEndDocument();
|
||||
|
||||
return rxw.ToString();
|
||||
}
|
||||
|
||||
public string GetHandlerRegion(IOSHttpResponse httpResponse, string param)
|
||||
{
|
||||
// be resilient and don't get confused by a terminating '/'
|
||||
param = param.TrimEnd(new char[]{'/'});
|
||||
string[] comps = param.Split('/');
|
||||
UUID regionID = (UUID)comps[0];
|
||||
|
||||
m_log.DebugFormat("{0} GET region UUID {1}", MsgID, regionID.ToString());
|
||||
|
||||
if (UUID.Zero == regionID) throw new Exception("missing region ID");
|
||||
|
||||
Scene scene = null;
|
||||
App.SceneManager.TryGetScene(regionID, out scene);
|
||||
if (null == scene) return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound,
|
||||
"GET", "cannot find region {0}", regionID.ToString());
|
||||
|
||||
RegionDetails details = new RegionDetails(scene.RegionInfo);
|
||||
|
||||
// m_log.DebugFormat("{0} GET comps {1}", MsgID, comps.Length);
|
||||
// for (int i = 0; i < comps.Length; i++) m_log.DebugFormat("{0} GET comps[{1}] >{2}<", MsgID, i, comps[i]);
|
||||
|
||||
if (1 == comps.Length)
|
||||
{
|
||||
// complete region details requested
|
||||
RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
|
||||
XmlSerializer xs = new XmlSerializer(typeof(RegionDetails));
|
||||
xs.Serialize(rxw, details, _xmlNs);
|
||||
return rxw.ToString();
|
||||
}
|
||||
|
||||
if (2 == comps.Length)
|
||||
{
|
||||
string resp = ShortRegionInfo(comps[1], details[comps[1]]);
|
||||
if (null != resp) return resp;
|
||||
|
||||
// m_log.DebugFormat("{0} GET comps advanced: >{1}<", MsgID, comps[1]);
|
||||
|
||||
// check for {terrain,stats,prims}
|
||||
switch (comps[1].ToLower())
|
||||
{
|
||||
case "terrain":
|
||||
return RegionTerrain(httpResponse, scene);
|
||||
|
||||
case "stats":
|
||||
return RegionStats(httpResponse, scene);
|
||||
|
||||
case "prims":
|
||||
return RegionPrims(httpResponse, scene, Vector3.Zero, Vector3.Zero);
|
||||
}
|
||||
}
|
||||
|
||||
if (3 == comps.Length)
|
||||
{
|
||||
switch (comps[1].ToLower())
|
||||
{
|
||||
case "prims":
|
||||
string[] subregion = comps[2].Split(',');
|
||||
if (subregion.Length == 6)
|
||||
{
|
||||
Vector3 min, max;
|
||||
try
|
||||
{
|
||||
min = new Vector3((float)Double.Parse(subregion[0], Culture.NumberFormatInfo), (float)Double.Parse(subregion[1], Culture.NumberFormatInfo), (float)Double.Parse(subregion[2], Culture.NumberFormatInfo));
|
||||
max = new Vector3((float)Double.Parse(subregion[3], Culture.NumberFormatInfo), (float)Double.Parse(subregion[4], Culture.NumberFormatInfo), (float)Double.Parse(subregion[5], Culture.NumberFormatInfo));
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest,
|
||||
"GET", "invalid subregion parameter");
|
||||
}
|
||||
return RegionPrims(httpResponse, scene, min, max);
|
||||
}
|
||||
else
|
||||
{
|
||||
return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest,
|
||||
"GET", "invalid subregion parameter");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Failure(httpResponse, OSHttpStatusCode.ClientErrorBadRequest,
|
||||
"GET", "too many parameters {0}", param);
|
||||
}
|
||||
#endregion GET methods
|
||||
|
||||
protected string RegionTerrain(IOSHttpResponse httpResponse, Scene scene)
|
||||
{
|
||||
httpResponse.SendChunked = true;
|
||||
httpResponse.ContentType = "text/xml";
|
||||
|
||||
return scene.Heightmap.SaveToXmlString();
|
||||
//return Failure(httpResponse, OSHttpStatusCode.ServerErrorNotImplemented,
|
||||
// "GET", "terrain not implemented");
|
||||
}
|
||||
|
||||
protected string RegionStats(IOSHttpResponse httpResponse, Scene scene)
|
||||
{
|
||||
int users = scene.GetRootAgentCount();
|
||||
int objects = scene.Entities.Count - users;
|
||||
|
||||
RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
|
||||
|
||||
rxw.WriteStartElement(String.Empty, "region", String.Empty);
|
||||
rxw.WriteStartElement(String.Empty, "stats", String.Empty);
|
||||
|
||||
rxw.WriteStartElement(String.Empty, "users", String.Empty);
|
||||
rxw.WriteString(users.ToString());
|
||||
rxw.WriteEndElement();
|
||||
|
||||
rxw.WriteStartElement(String.Empty, "objects", String.Empty);
|
||||
rxw.WriteString(objects.ToString());
|
||||
rxw.WriteEndElement();
|
||||
|
||||
rxw.WriteEndDocument();
|
||||
|
||||
return rxw.ToString();
|
||||
}
|
||||
|
||||
protected string RegionPrims(IOSHttpResponse httpResponse, Scene scene, Vector3 min, Vector3 max)
|
||||
{
|
||||
httpResponse.SendChunked = true;
|
||||
httpResponse.ContentType = "text/xml";
|
||||
|
||||
IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>();
|
||||
if (serialiser != null)
|
||||
serialiser.SavePrimsToXml2(scene, new StreamWriter(httpResponse.OutputStream), min, max);
|
||||
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Xml.Serialization;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework.Servers;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Regions
|
||||
{
|
||||
public partial class RestRegionPlugin : RestPlugin
|
||||
{
|
||||
#region GET methods
|
||||
public string GetRegionInfoHandler(string request, string path, string param,
|
||||
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
// foreach (string h in httpRequest.Headers.AllKeys)
|
||||
// foreach (string v in httpRequest.Headers.GetValues(h))
|
||||
// m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v);
|
||||
|
||||
MsgID = RequestID;
|
||||
m_log.DebugFormat("{0} GET path {1} param {2}", MsgID, path, param);
|
||||
|
||||
try
|
||||
{
|
||||
// param empty: regions list
|
||||
// if (String.IsNullOrEmpty(param))
|
||||
return GetRegionInfoHandlerRegions(httpResponse);
|
||||
|
||||
// // param not empty: specific region
|
||||
// return GetRegionInfoHandlerRegion(httpResponse, param);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "GET", e);
|
||||
}
|
||||
}
|
||||
|
||||
public string GetRegionInfoHandlerRegions(IOSHttpResponse httpResponse)
|
||||
{
|
||||
RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
|
||||
|
||||
// regions info
|
||||
rxw.WriteStartElement(String.Empty, "regions", String.Empty);
|
||||
{
|
||||
// regions info: number of regions
|
||||
rxw.WriteStartAttribute(String.Empty, "number", String.Empty);
|
||||
rxw.WriteValue(App.SceneManager.Scenes.Count);
|
||||
rxw.WriteEndAttribute();
|
||||
|
||||
// regions info: max number of regions
|
||||
rxw.WriteStartAttribute(String.Empty, "max", String.Empty);
|
||||
if (App.ConfigSource.Source.Configs["RemoteAdmin"] != null)
|
||||
{
|
||||
rxw.WriteValue(App.ConfigSource.Source.Configs["RemoteAdmin"].GetInt("region_limit", -1));
|
||||
}
|
||||
else
|
||||
{
|
||||
rxw.WriteValue(-1);
|
||||
}
|
||||
rxw.WriteEndAttribute();
|
||||
|
||||
// regions info: region
|
||||
foreach (Scene s in App.SceneManager.Scenes)
|
||||
{
|
||||
rxw.WriteStartElement(String.Empty, "region", String.Empty);
|
||||
|
||||
rxw.WriteStartAttribute(String.Empty, "uuid", String.Empty);
|
||||
rxw.WriteString(s.RegionInfo.RegionID.ToString());
|
||||
rxw.WriteEndAttribute();
|
||||
|
||||
rxw.WriteStartAttribute(String.Empty, "name", String.Empty);
|
||||
rxw.WriteString(s.RegionInfo.RegionName);
|
||||
rxw.WriteEndAttribute();
|
||||
|
||||
rxw.WriteStartAttribute(String.Empty, "x", String.Empty);
|
||||
rxw.WriteValue(s.RegionInfo.RegionLocX);
|
||||
rxw.WriteEndAttribute();
|
||||
|
||||
rxw.WriteStartAttribute(String.Empty, "y", String.Empty);
|
||||
rxw.WriteValue(s.RegionInfo.RegionLocY);
|
||||
rxw.WriteEndAttribute();
|
||||
|
||||
rxw.WriteStartAttribute(String.Empty, "external_hostname", String.Empty);
|
||||
rxw.WriteString(s.RegionInfo.ExternalHostName);
|
||||
rxw.WriteEndAttribute();
|
||||
|
||||
rxw.WriteStartAttribute(String.Empty, "ip", String.Empty);
|
||||
rxw.WriteString(s.RegionInfo.InternalEndPoint.ToString());
|
||||
rxw.WriteEndAttribute();
|
||||
|
||||
int users = s.GetRootAgentCount();
|
||||
rxw.WriteStartAttribute(String.Empty, "avatars", String.Empty);
|
||||
rxw.WriteValue(users);
|
||||
rxw.WriteEndAttribute();
|
||||
|
||||
rxw.WriteStartAttribute(String.Empty, "objects", String.Empty);
|
||||
rxw.WriteValue(s.Entities.Count - users);
|
||||
rxw.WriteEndAttribute();
|
||||
|
||||
rxw.WriteEndElement();
|
||||
}
|
||||
}
|
||||
return rxw.ToString();
|
||||
}
|
||||
#endregion GET methods
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework.Servers;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Region.Framework.Scenes;
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Regions
|
||||
{
|
||||
public partial class RestRegionPlugin : RestPlugin
|
||||
{
|
||||
#region POST methods
|
||||
|
||||
public string PostHandler(string request, string path, string param,
|
||||
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
// foreach (string h in httpRequest.Headers.AllKeys)
|
||||
// foreach (string v in httpRequest.Headers.GetValues(h))
|
||||
// m_log.DebugFormat("{0} IsGod: {1} -> {2}", MsgID, h, v);
|
||||
|
||||
MsgID = RequestID;
|
||||
m_log.DebugFormat("{0} POST path {1} param {2}", MsgID, path, param);
|
||||
|
||||
try
|
||||
{
|
||||
// param empty: new region post
|
||||
if (!IsGod(httpRequest))
|
||||
// XXX: this needs to be turned into a FailureUnauthorized(...)
|
||||
return Failure(httpResponse, OSHttpStatusCode.ClientErrorUnauthorized,
|
||||
"GET", "you are not god");
|
||||
|
||||
if (String.IsNullOrEmpty(param)) return CreateRegion(httpRequest, httpResponse);
|
||||
|
||||
// Parse region ID and other parameters
|
||||
param = param.TrimEnd(new char[] {'/'});
|
||||
string[] comps = param.Split('/');
|
||||
UUID regionID = (UUID) comps[0];
|
||||
|
||||
m_log.DebugFormat("{0} POST region UUID {1}", MsgID, regionID.ToString());
|
||||
if (UUID.Zero == regionID) throw new Exception("missing region ID");
|
||||
|
||||
Scene scene = null;
|
||||
App.SceneManager.TryGetScene(regionID, out scene);
|
||||
if (null == scene)
|
||||
return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound,
|
||||
"POST", "cannot find region {0}", regionID.ToString());
|
||||
|
||||
if (2 == comps.Length)
|
||||
{
|
||||
// check for {prims}
|
||||
switch (comps[1].ToLower())
|
||||
{
|
||||
case "prims":
|
||||
return LoadPrims(request, httpRequest, httpResponse, scene);
|
||||
}
|
||||
}
|
||||
|
||||
return Failure(httpResponse, OSHttpStatusCode.ClientErrorNotFound,
|
||||
"POST", "url {0} not supported", param);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return Failure(httpResponse, OSHttpStatusCode.ServerErrorInternalError, "POST", e);
|
||||
}
|
||||
}
|
||||
|
||||
public string CreateRegion(IOSHttpRequest request, IOSHttpResponse response)
|
||||
{
|
||||
RestXmlWriter rxw = new RestXmlWriter(new StringWriter());
|
||||
|
||||
rxw.WriteStartElement(String.Empty, "regions", String.Empty);
|
||||
foreach (Scene s in App.SceneManager.Scenes)
|
||||
{
|
||||
rxw.WriteStartElement(String.Empty, "uuid", String.Empty);
|
||||
rxw.WriteString(s.RegionInfo.RegionID.ToString());
|
||||
rxw.WriteEndElement();
|
||||
}
|
||||
rxw.WriteEndElement();
|
||||
|
||||
return rxw.ToString();
|
||||
}
|
||||
|
||||
public string LoadPrims(string requestBody, IOSHttpRequest request, IOSHttpResponse response, Scene scene)
|
||||
{
|
||||
IRegionSerialiserModule serialiser = scene.RequestModuleInterface<IRegionSerialiserModule>();
|
||||
if (serialiser != null)
|
||||
serialiser.LoadPrimsFromXml2(scene, new StringReader(requestBody), true);
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
#endregion POST methods
|
||||
}
|
||||
}
|
||||
@@ -1,98 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Xml.Serialization;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Regions
|
||||
{
|
||||
[XmlRoot(ElementName="region", IsNullable = false)]
|
||||
public class RegionDetails
|
||||
{
|
||||
public string region_name;
|
||||
public string region_id;
|
||||
public uint region_x;
|
||||
public uint region_y;
|
||||
public string region_owner;
|
||||
public string region_owner_id;
|
||||
public uint region_http_port;
|
||||
public uint region_port;
|
||||
public string region_server_uri;
|
||||
public string region_external_hostname;
|
||||
|
||||
public RegionDetails()
|
||||
{
|
||||
}
|
||||
|
||||
public RegionDetails(RegionInfo regInfo)
|
||||
{
|
||||
region_name = regInfo.RegionName;
|
||||
region_id = regInfo.RegionID.ToString();
|
||||
region_x = regInfo.RegionLocX;
|
||||
region_y = regInfo.RegionLocY;
|
||||
region_owner_id = regInfo.EstateSettings.EstateOwner.ToString();
|
||||
region_http_port = regInfo.HttpPort;
|
||||
region_server_uri = regInfo.ServerURI;
|
||||
region_external_hostname = regInfo.ExternalHostName;
|
||||
|
||||
Uri uri = new Uri(region_server_uri);
|
||||
region_port = (uint)uri.Port;
|
||||
}
|
||||
|
||||
public string this[string idx]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (idx.ToLower())
|
||||
{
|
||||
case "name":
|
||||
return region_name;
|
||||
case "id":
|
||||
return region_id;
|
||||
case "location":
|
||||
return String.Format("<x>{0}</x><y>{1}</y>", region_x, region_y);
|
||||
case "owner":
|
||||
return region_owner;
|
||||
case "owner_id":
|
||||
return region_owner_id;
|
||||
case "http_port":
|
||||
return region_http_port.ToString();
|
||||
case "server_uri":
|
||||
return region_server_uri;
|
||||
case "external_hostname":
|
||||
case "hostname":
|
||||
return region_external_hostname;
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
<Addin id="OpenSim.ApplicationPlugins.Rest.Regions" version="0.1">
|
||||
<Runtime>
|
||||
<Import assembly="OpenSim.ApplicationPlugins.Rest.Regions.dll"/>
|
||||
</Runtime>
|
||||
<Dependencies>
|
||||
<Addin id="OpenSim" version="0.5" />
|
||||
</Dependencies>
|
||||
<Extension path = "/OpenSim/Startup">
|
||||
<Plugin id="RestRegions" type="OpenSim.ApplicationPlugins.Rest.Regions.RestRegionPlugin" />
|
||||
</Extension>
|
||||
</Addin>
|
||||
@@ -1,417 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using log4net;
|
||||
using Nini.Config;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Servers;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.Rest
|
||||
{
|
||||
public abstract class RestPlugin : IApplicationPlugin
|
||||
{
|
||||
#region properties
|
||||
|
||||
protected static readonly ILog m_log =
|
||||
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private IConfig _config; // Configuration source: Rest Plugins
|
||||
private IConfig _pluginConfig; // Configuration source: Plugin specific
|
||||
private OpenSimBase _app; // The 'server'
|
||||
private BaseHttpServer _httpd; // The server's RPC interface
|
||||
private string _prefix; // URL prefix below
|
||||
// which all REST URLs
|
||||
// are living
|
||||
// private StringWriter _sw = null;
|
||||
// private RestXmlWriter _xw = null;
|
||||
|
||||
private string _godkey;
|
||||
private int _reqk;
|
||||
|
||||
[ThreadStatic]
|
||||
private static string _threadRequestID = String.Empty;
|
||||
|
||||
/// <summary>
|
||||
/// Return an ever increasing request ID for logging
|
||||
/// </summary>
|
||||
protected string RequestID
|
||||
{
|
||||
get { return _reqk++.ToString(); }
|
||||
set { _reqk = Convert.ToInt32(value); }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Thread-constant message IDs for logging.
|
||||
/// </summary>
|
||||
protected string MsgID
|
||||
{
|
||||
get { return String.Format("[REST-{0}] #{1}", Name, _threadRequestID); }
|
||||
set { _threadRequestID = value; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if Rest Plugins are enabled.
|
||||
/// </summary>
|
||||
public bool PluginsAreEnabled
|
||||
{
|
||||
get { return null != _config; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if specific Rest Plugin is enabled.
|
||||
/// </summary>
|
||||
public bool IsEnabled
|
||||
{
|
||||
get
|
||||
{
|
||||
return (null != _pluginConfig) && _pluginConfig.GetBoolean("enabled", false);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// OpenSimMain application
|
||||
/// </summary>
|
||||
public OpenSimBase App
|
||||
{
|
||||
get { return _app; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// RPC server
|
||||
/// </summary>
|
||||
public BaseHttpServer HttpServer
|
||||
{
|
||||
get { return _httpd; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// URL prefix to use for all REST handlers
|
||||
/// </summary>
|
||||
public string Prefix
|
||||
{
|
||||
get { return _prefix; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Access to GOD password string
|
||||
/// </summary>
|
||||
protected string GodKey
|
||||
{
|
||||
get { return _godkey; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Configuration of the plugin
|
||||
/// </summary>
|
||||
public IConfig Config
|
||||
{
|
||||
get { return _pluginConfig; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Name of the plugin
|
||||
/// </summary>
|
||||
public abstract string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Return the config section name
|
||||
/// </summary>
|
||||
public abstract string ConfigName { get; }
|
||||
|
||||
// public XmlTextWriter XmlWriter
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// if (null == _xw)
|
||||
// {
|
||||
// _sw = new StringWriter();
|
||||
// _xw = new RestXmlWriter(_sw);
|
||||
// _xw.Formatting = Formatting.Indented;
|
||||
// }
|
||||
// return _xw;
|
||||
// }
|
||||
// }
|
||||
|
||||
// public string XmlWriterResult
|
||||
// {
|
||||
// get
|
||||
// {
|
||||
// _xw.Flush();
|
||||
// _xw.Close();
|
||||
// _xw = null;
|
||||
|
||||
// return _sw.ToString();
|
||||
// }
|
||||
// }
|
||||
|
||||
#endregion properties
|
||||
|
||||
#region methods
|
||||
|
||||
// TODO: required by IPlugin, but likely not at all right
|
||||
private string m_version = "0.0";
|
||||
|
||||
public string Version
|
||||
{
|
||||
get { return m_version; }
|
||||
}
|
||||
|
||||
public void Initialise()
|
||||
{
|
||||
m_log.Info("[RESTPLUGIN]: " + Name + " cannot be default-initialized!");
|
||||
throw new PluginNotInitialisedException(Name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// This method is called by OpenSimMain immediately after loading the
|
||||
/// plugin and after basic server setup, but before running any server commands.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that entries MUST be added to the active configuration files before
|
||||
/// the plugin can be enabled.
|
||||
/// </remarks>
|
||||
public virtual void Initialise(OpenSimBase openSim)
|
||||
{
|
||||
RequestID = "0";
|
||||
MsgID = RequestID;
|
||||
|
||||
try
|
||||
{
|
||||
if ((_config = openSim.ConfigSource.Source.Configs["RestPlugins"]) == null)
|
||||
{
|
||||
m_log.WarnFormat("{0} Rest Plugins not configured", MsgID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_config.GetBoolean("enabled", false))
|
||||
{
|
||||
//m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID);
|
||||
return;
|
||||
}
|
||||
|
||||
_app = openSim;
|
||||
_httpd = openSim.HttpServer;
|
||||
|
||||
// Retrieve GOD key value, if any.
|
||||
_godkey = _config.GetString("god_key", String.Empty);
|
||||
|
||||
// Retrive prefix if any.
|
||||
_prefix = _config.GetString("prefix", "/admin");
|
||||
|
||||
// Get plugin specific config
|
||||
_pluginConfig = openSim.ConfigSource.Source.Configs[ConfigName];
|
||||
|
||||
m_log.InfoFormat("{0} Rest Plugins Enabled", MsgID);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
// we can safely ignore this, as it just means that
|
||||
// the key lookup in Configs failed, which signals to
|
||||
// us that noone is interested in our services...they
|
||||
// don't know what they are missing out on...
|
||||
// NOTE: Under the present OpenSimulator implementation it is
|
||||
// not possible for the openSimulator pointer to be null. However
|
||||
// were the implementation to be changed, this could
|
||||
// result in a silent initialization failure. Harmless
|
||||
// except for lack of function and lack of any
|
||||
// diagnostic indication as to why. The same is true if
|
||||
// the HTTP server reference is bad.
|
||||
// We should at least issue a message...
|
||||
m_log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message);
|
||||
m_log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void PostInitialise()
|
||||
{
|
||||
}
|
||||
|
||||
private List<RestStreamHandler> _handlers = new List<RestStreamHandler>();
|
||||
private Dictionary<string, IHttpAgentHandler> _agents = new Dictionary<string, IHttpAgentHandler>();
|
||||
|
||||
/// <summary>
|
||||
/// Add a REST stream handler to the underlying HTTP server.
|
||||
/// </summary>
|
||||
/// <param name="httpMethod">GET/PUT/POST/DELETE or
|
||||
/// similar</param>
|
||||
/// <param name="path">URL prefix</param>
|
||||
/// <param name="method">RestMethod handler doing the actual work</param>
|
||||
public virtual void AddRestStreamHandler(string httpMethod, string path, RestMethod method)
|
||||
{
|
||||
if (!IsEnabled) return;
|
||||
|
||||
if (!path.StartsWith(_prefix))
|
||||
{
|
||||
path = String.Format("{0}{1}", _prefix, path);
|
||||
}
|
||||
|
||||
RestStreamHandler h = new RestStreamHandler(httpMethod, path, method);
|
||||
_httpd.AddStreamHandler(h);
|
||||
_handlers.Add(h);
|
||||
|
||||
m_log.DebugFormat("{0} Added REST handler {1} {2}", MsgID, httpMethod, path);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a powerful Agent handler to the underlying HTTP
|
||||
/// server.
|
||||
/// </summary>
|
||||
/// <param name="agentName">name of agent handler</param>
|
||||
/// <param name="handler">agent handler method</param>
|
||||
/// <returns>false when the plugin is disabled or the agent
|
||||
/// handler could not be added. Any generated exceptions are
|
||||
/// allowed to drop through to the caller, i.e. ArgumentException.
|
||||
/// </returns>
|
||||
public bool AddAgentHandler(string agentName, IHttpAgentHandler handler)
|
||||
{
|
||||
if (!IsEnabled) return false;
|
||||
_agents.Add(agentName, handler);
|
||||
// return _httpd.AddAgentHandler(agentName, handler);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a powerful Agent handler from the underlying HTTP
|
||||
/// server.
|
||||
/// </summary>
|
||||
/// <param name="agentName">name of agent handler</param>
|
||||
/// <param name="handler">agent handler method</param>
|
||||
/// <returns>false when the plugin is disabled or the agent
|
||||
/// handler could not be removed. Any generated exceptions are
|
||||
/// allowed to drop through to the caller, i.e. KeyNotFound.
|
||||
/// </returns>
|
||||
public bool RemoveAgentHandler(string agentName, IHttpAgentHandler handler)
|
||||
{
|
||||
if (!IsEnabled) return false;
|
||||
if (_agents[agentName] == handler)
|
||||
{
|
||||
_agents.Remove(agentName);
|
||||
// return _httpd.RemoveAgentHandler(agentName, handler);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check whether the HTTP request came from god; that is, is
|
||||
/// the god_key as configured in the config section supplied
|
||||
/// via X-OpenSim-Godkey?
|
||||
/// </summary>
|
||||
/// <param name="request">HTTP request header</param>
|
||||
/// <returns>true when the HTTP request came from god.</returns>
|
||||
protected bool IsGod(IOSHttpRequest request)
|
||||
{
|
||||
string[] keys = request.Headers.GetValues("X-OpenSim-Godkey");
|
||||
if (null == keys) return false;
|
||||
|
||||
// we take the last key supplied
|
||||
return keys[keys.Length - 1] == _godkey;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks wether the X-OpenSim-Password value provided in the
|
||||
/// HTTP header is indeed the password on file for the avatar
|
||||
/// specified by the UUID
|
||||
/// </summary>
|
||||
protected bool IsVerifiedUser(IOSHttpRequest request, UUID uuid)
|
||||
{
|
||||
// XXX under construction
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clean up and remove all handlers that were added earlier.
|
||||
/// </summary>
|
||||
public virtual void Close()
|
||||
{
|
||||
foreach (RestStreamHandler h in _handlers)
|
||||
{
|
||||
_httpd.RemoveStreamHandler(h.HttpMethod, h.Path);
|
||||
}
|
||||
_handlers = null;
|
||||
// foreach (KeyValuePair<string, IHttpAgentHandler> h in _agents)
|
||||
// {
|
||||
// _httpd.RemoveAgentHandler(h.Key, h.Value);
|
||||
// }
|
||||
_agents = null;
|
||||
}
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a failure message.
|
||||
/// </summary>
|
||||
/// <param name="method">origin of the failure message</param>
|
||||
/// <param name="message">failure message</param>
|
||||
/// <remarks>This should probably set a return code as
|
||||
/// well. (?)</remarks>
|
||||
protected string Failure(IOSHttpResponse response, OSHttpStatusCode status,
|
||||
string method, string format, params string[] msg)
|
||||
{
|
||||
string m = String.Format(format, msg);
|
||||
|
||||
response.StatusCode = (int) status;
|
||||
response.StatusDescription = m;
|
||||
|
||||
m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, m);
|
||||
return String.Format("<error>{0}</error>", m);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a failure message.
|
||||
/// </summary>
|
||||
/// <param name="method">origin of the failure message</param>
|
||||
/// <param name="e">exception causing the failure message</param>
|
||||
/// <remarks>This should probably set a return code as
|
||||
/// well. (?)</remarks>
|
||||
public string Failure(IOSHttpResponse response, OSHttpStatusCode status,
|
||||
string method, Exception e)
|
||||
{
|
||||
string m = String.Format("exception occurred: {0}", e.Message);
|
||||
|
||||
response.StatusCode = (int) status;
|
||||
response.StatusDescription = m;
|
||||
|
||||
m_log.DebugFormat("{0} {1} failed: {2}", MsgID, method, e.ToString());
|
||||
m_log.ErrorFormat("{0} {1} failed: {2}", MsgID, method, e.Message);
|
||||
|
||||
return String.Format("<error>{0}</error>", e.Message);
|
||||
}
|
||||
|
||||
#endregion methods
|
||||
}
|
||||
}
|
||||
@@ -1,276 +0,0 @@
|
||||
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
|
||||
|
||||
<xsd:annotation>
|
||||
<xsd:documentation xml:lang="en">
|
||||
Open Simulator Export/Import XML schema
|
||||
August 2008
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
|
||||
<!-- WARNING!!!
|
||||
This is currently a draft, it does not reflect
|
||||
what is exported, nor what will be understood
|
||||
on import. It is included as a working document
|
||||
and this comment will be removed at such time as
|
||||
the schema corresponds to reality.
|
||||
-->
|
||||
|
||||
<!--
|
||||
REST-related information
|
||||
Inventory data is always framed by an
|
||||
inventory element. Consists of zero or
|
||||
more elements representing either folders
|
||||
or items within those folders. The inventory
|
||||
element represents the "real" root folder.
|
||||
-->
|
||||
|
||||
<xsd:element name="inventory" type="inventory_ct" />
|
||||
|
||||
<!--
|
||||
The inventory complex type is just an arbitrary
|
||||
sequence of folders and items. In reality it is
|
||||
typically just folders. Both item and folder
|
||||
have corresponding complex types. It is distinct
|
||||
from folders insofar as it has no other defining
|
||||
attributes.
|
||||
-->
|
||||
|
||||
<xsd:complexType name="inventory_ct">
|
||||
<xsd:element name="folder" type="folder_ct" maxOccurs="unbounded"/>
|
||||
<xsd:element name="item" type="item_ct" maxOccurs="unbounded" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="folder_ct">
|
||||
<xsd:attribute name="UUID" type="uuid_st" />
|
||||
<xsd:attribute name="name" type="name_st" />
|
||||
<xsd:attribute name="type" type="folder_type_st" />
|
||||
<xsd:attribute name="description" type="xsd:string" /> <!-- added -->
|
||||
<xsd:attribute name="version" type="unsignedShort" />
|
||||
<xsd:attribute name="owner" type="uuid_st" />
|
||||
|
||||
<xsd:attribute name="creator" type="uuid_st" /> <!-- added -->
|
||||
<xsd:attribute name="creationdate" type="date_st" /> <!-- added -->
|
||||
|
||||
<xsd:attribute name="parent" type="uuid_st" />
|
||||
|
||||
<xsd:element name="permissions" type="permissions_ct" maxOccurs="unbounded" /> <!-- added -->
|
||||
<xsd:element name="folder" type="folder_ct" maxOccurs="unbounded" />
|
||||
<xsd:element name="item" type="item_ct" maxOccurs="unbounded" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="item_ct">
|
||||
<xsd:attribute name="UUID" type="uuid_st" />
|
||||
<xsd:attribute name="name" type="name_st" />
|
||||
<xsd:attribute name="type" type="inventory_type_st" />
|
||||
<xsd:attribute name="description" type="xsd:string" />
|
||||
<xsd:attribute name="version" type="unsignedShort" /> <!-- added -->
|
||||
<xsd:attribute name="owner" type="uuid_st" />
|
||||
|
||||
<xsd:attribute name="creator" type="uuid_st" />
|
||||
<xsd:attribute name="creationdate" type="date_st" />
|
||||
|
||||
<xsd:attribute name="folder" type="uuid_st" />
|
||||
<xsd:attribute name="groupid" type="uuid_st" />
|
||||
<xsd:attribute name="groupowned" type="xsd:boolean" />
|
||||
<xsd:attribute name="saletype" type="sale_st" />
|
||||
<xsd:attribute name="saleprice" type="xsd:decimal" />
|
||||
|
||||
<xsd:element name="permissions" type="permissions_ct" maxOccurs="unbounded" />
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="asset_ct">
|
||||
<xsd:attribute name="UUID" type="uuid_st" />
|
||||
<xsd:attribute name="name" type="name_st" />
|
||||
<xsd:attribute name="type" type="asset_type_st" />
|
||||
<xsd:attribute name="description" type="xsd:string" />
|
||||
<xsd:attribute name="version" type="unsignedShort" /> <!-- added -->
|
||||
<xsd:attribute name="owner" type="uuid_st" />
|
||||
|
||||
<xsd:attribute name="creator" type="uuid_st" />
|
||||
<xsd:attribute name="creationdate" type="date_st" />
|
||||
|
||||
<xsd:attribute name="temporary" type="xsd:boolean" />
|
||||
<xsd:attribute name="local" type="xsd:boolean" />
|
||||
<xsd:attribute name="inline" type="xsd:boolean" />
|
||||
</xsd:complexType>
|
||||
|
||||
<!-- Constrained Simple Data types -->
|
||||
|
||||
<!--
|
||||
We need to specify name as a simple type because on
|
||||
some platforms it is constrained by a certain length
|
||||
limitation. For completeness we indicate that whitespace
|
||||
should be preserved exactly as specified.
|
||||
-->
|
||||
|
||||
<xsd:simpleType name="name_st">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<whiteSpace value="preserve" />
|
||||
<minLength value="0" />
|
||||
<maxLength value="64" />
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
<!--
|
||||
Type information in the folder is meant to indicate
|
||||
the preferred asset type for this folder. As such, that
|
||||
currently corresponds to the type values allowed for
|
||||
assets, however that is not mandated, so for
|
||||
now at least I'll represent this as a distinct
|
||||
enumeration.
|
||||
This seems inappropriate; it seems like the folder's
|
||||
content should reflect the InventoryType classifications
|
||||
rather than the asset types.
|
||||
-->
|
||||
|
||||
<xsd:simpleType name="folder_type_st">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="Texture" />
|
||||
<xsd:enumeration value="Sound" />
|
||||
<xsd:enumeration value="CallingCard" />
|
||||
<xsd:enumeration value="Landmark" />
|
||||
<xsd:enumeration value="Script" />
|
||||
<xsd:enumeration value="Clothing" />
|
||||
<xsd:enumeration value="Object" />
|
||||
<xsd:enumeration value="Notecard" />
|
||||
<xsd:enumeration value="LSLText" />
|
||||
<xsd:enumeration value="LSLByteCode" />
|
||||
<xsd:enumeration value="TextureTGA" />
|
||||
<xsd:enumeration value="BodyPart" />
|
||||
<xsd:enumeration value="SoundWAV" />
|
||||
<xsd:enumeration value="ImageTGA" />
|
||||
<xsd:enumeration value="ImageJPEG" />
|
||||
<xsd:enumeration value="Animation" />
|
||||
<xsd:enumeration value="Gesture" />
|
||||
<xsd:enumeration value="Simstate" />
|
||||
<xsd:enumeration value="Unknown" />
|
||||
<xsd:enumeration value="LostAndFoundFolder" />
|
||||
<xsd:enumeration value="SnapshotFolder" />
|
||||
<xsd:enumeration value="TrashFolder" />
|
||||
<xsd:enumeration value="Folder" />
|
||||
<xsd:enumeration value="RootFolder" />
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
<!--
|
||||
Inventory item type designates an asset class, rather
|
||||
than a specific asset type. For example, "SnapShot"
|
||||
might include a number of asset types such as JPEG,
|
||||
TGA, etc.. This is not a consistent interpretation,
|
||||
classifications such as LostAndFound are meta-types
|
||||
relative to asset classes.
|
||||
|
||||
These types should be abstract and not be tied to a
|
||||
specific platform. A world's import facility should be
|
||||
responsible for mapping these to meaningful internal
|
||||
representations.
|
||||
|
||||
These types were based on information in:
|
||||
libsecondlife/InventoryManager.cs
|
||||
-->
|
||||
|
||||
<xsd:simpleType name="inventory_type_st">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="Texture" />
|
||||
<xsd:enumeration value="Sound" />
|
||||
<xsd:enumeration value="CallingCard" />
|
||||
<xsd:enumeration value="Landmark" />
|
||||
<xsd:enumeration value="Script" />
|
||||
<xsd:enumeration value="Clothing" />
|
||||
<xsd:enumeration value="Object" />
|
||||
<xsd:enumeration value="Notecard" />
|
||||
<xsd:enumeration value="LSL" />
|
||||
<xsd:enumeration value="LSLBytecode" />
|
||||
<xsd:enumeration value="TextureTGA" />
|
||||
<xsd:enumeration value="BodyPart" />
|
||||
<xsd:enumeration value="Snapshot" />
|
||||
<xsd:enumeration value="Attachment" />
|
||||
<xsd:enumeration value="Wearable" />
|
||||
<xsd:enumeration value="Animation" />
|
||||
<xsd:enumeration value="Gesture" />
|
||||
<xsd:enumeration value="Folder" />
|
||||
<xsd:enumeration value="Unknown" />
|
||||
<xsd:enumeration value="LostAndFound" />
|
||||
<xsd:enumeration value="Trash" />
|
||||
<xsd:enumeration value="Root" />
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
<!--
|
||||
The asset types seem to be even more disarrayed than
|
||||
the inventory types. It seems to be little more than
|
||||
a reiteration of the inventory type information,
|
||||
which adds little or nothing to the overall data
|
||||
model.
|
||||
|
||||
Of course, given that these are drawn from the
|
||||
libsecondlife definitions, we aren't at liberty to
|
||||
simply redefine them in place. But the XML definitions
|
||||
here could be made more useful.
|
||||
|
||||
These types were based on information in:
|
||||
libsecondlife/AssetManager.cs
|
||||
-->
|
||||
|
||||
<xsd:simpleType name="asset_type_st">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="Texture" />
|
||||
<xsd:enumeration value="Sound" />
|
||||
<xsd:enumeration value="CallingCard" />
|
||||
<xsd:enumeration value="Landmark" />
|
||||
<xsd:enumeration value="Script" />
|
||||
<xsd:enumeration value="Clothing" />
|
||||
<xsd:enumeration value="Object" />
|
||||
<xsd:enumeration value="Notecard" />
|
||||
<xsd:enumeration value="LSLText" />
|
||||
<xsd:enumeration value="LSLByteCode" />
|
||||
<xsd:enumeration value="TextureTGA" />
|
||||
<xsd:enumeration value="BodyPart" />
|
||||
<xsd:enumeration value="SoundWAV" />
|
||||
<xsd:enumeration value="ImageTGA" />
|
||||
<xsd:enumeration value="ImageJPEG" />
|
||||
<xsd:enumeration value="Animation" />
|
||||
<xsd:enumeration value="Gesture" />
|
||||
<xsd:enumeration value="Simstate" />
|
||||
<xsd:enumeration value="Unknown" />
|
||||
<xsd:enumeration value="LostAndFoundFolder" />
|
||||
<xsd:enumeration value="SnapshotFolder" />
|
||||
<xsd:enumeration value="TrashFolder" />
|
||||
<xsd:enumeration value="Folder" />
|
||||
<xsd:enumeration value="RootFolder" />
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
<!-- This is describing the apparent form of a UUID. If
|
||||
we ever want a more metaphysical definition we'll
|
||||
need to add to it.
|
||||
-->
|
||||
|
||||
<xsd:simpleType name="uuid_st">
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:pattern value="[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
<!-- This constrains the date representation. Currently
|
||||
it is simply an integer representing the elapsed
|
||||
?? since ??.
|
||||
-->
|
||||
|
||||
<xsd:simpleType name="date_st">
|
||||
<xsd:restriction base="xsd:positiveInteger">
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
<!-- This constrains the representation of sale price.
|
||||
Currently it is a simple decimal with no unit
|
||||
specified.
|
||||
Issues: interoperability.
|
||||
-->
|
||||
|
||||
<xsd:simpleType name="sale_st">
|
||||
<xsd:restriction base="xsd:decimal">
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
|
||||
</xsd:schema>
|
||||
@@ -143,8 +143,8 @@ namespace OpenSim.Framework.Capabilities
|
||||
/// <param name="handler"></param>
|
||||
public void RegisterHandler(string capName, IRequestHandler handler)
|
||||
{
|
||||
m_capsHandlers[capName] = handler;
|
||||
//m_log.DebugFormat("[CAPS]: Registering handler for \"{0}\": path {1}", capName, handler.Path);
|
||||
m_capsHandlers[capName] = handler;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace OpenSim.Framework.Capabilities
|
||||
/// </summary>
|
||||
public class CapsHandlers
|
||||
{
|
||||
private Dictionary <string, IRequestHandler> m_capsHandlers = new Dictionary<string, IRequestHandler>();
|
||||
private Dictionary<string, IRequestHandler> m_capsHandlers = new Dictionary<string, IRequestHandler>();
|
||||
private IHttpServer m_httpListener;
|
||||
private string m_httpListenerHostName;
|
||||
private uint m_httpListenerPort;
|
||||
@@ -158,7 +158,7 @@ namespace OpenSim.Framework.Capabilities
|
||||
/// capabilities and their handler details.
|
||||
/// </summary>
|
||||
/// <param name="excludeSeed">If true, then exclude the seed cap.</param>
|
||||
public Hashtable GetCapsDetails(bool excludeSeed)
|
||||
public Hashtable GetCapsDetails(bool excludeSeed, List<string> requestedCaps)
|
||||
{
|
||||
Hashtable caps = new Hashtable();
|
||||
string protocol = "http://";
|
||||
@@ -175,11 +175,26 @@ namespace OpenSim.Framework.Capabilities
|
||||
if (excludeSeed && "SEED" == capsName)
|
||||
continue;
|
||||
|
||||
if (requestedCaps != null && !requestedCaps.Contains(capsName))
|
||||
continue;
|
||||
|
||||
caps[capsName] = baseUrl + m_capsHandlers[capsName].Path;
|
||||
}
|
||||
}
|
||||
|
||||
return caps;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns a copy of the dictionary of all the HTTP cap handlers
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// The dictionary copy. The key is the capability name, the value is the HTTP handler.
|
||||
/// </returns>
|
||||
public Dictionary<string, IRequestHandler> GetCapsHandlers()
|
||||
{
|
||||
lock (m_capsHandlers)
|
||||
return new Dictionary<string, IRequestHandler>(m_capsHandlers);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.Specialized;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Web;
|
||||
using log4net;
|
||||
using Nini.Config;
|
||||
using OpenMetaverse;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Capabilities;
|
||||
using OpenSim.Framework.Servers;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
//using OpenSim.Region.Framework.Interfaces;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using Caps = OpenSim.Framework.Capabilities.Caps;
|
||||
|
||||
namespace OpenSim.Capabilities.Handlers
|
||||
{
|
||||
public class AvatarPickerSearchHandler : BaseStreamHandler
|
||||
{
|
||||
private static readonly ILog m_log =
|
||||
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private IPeople m_PeopleService;
|
||||
|
||||
public AvatarPickerSearchHandler(string path, IPeople peopleService, string name, string description)
|
||||
: base("GET", path, name, description)
|
||||
{
|
||||
m_PeopleService = peopleService;
|
||||
}
|
||||
|
||||
protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
// Try to parse the texture ID from the request URL
|
||||
NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query);
|
||||
string names = query.GetOne("names");
|
||||
string psize = query.GetOne("page_size");
|
||||
string pnumber = query.GetOne("page");
|
||||
|
||||
if (m_PeopleService == null)
|
||||
return FailureResponse(names, (int)System.Net.HttpStatusCode.InternalServerError, httpResponse);
|
||||
|
||||
if (string.IsNullOrEmpty(names) || names.Length < 3)
|
||||
return FailureResponse(names, (int)System.Net.HttpStatusCode.BadRequest, httpResponse);
|
||||
|
||||
m_log.DebugFormat("[AVATAR PICKER SEARCH]: search for {0}", names);
|
||||
|
||||
int page_size = (string.IsNullOrEmpty(psize) ? 500 : Int32.Parse(psize));
|
||||
int page_number = (string.IsNullOrEmpty(pnumber) ? 1 : Int32.Parse(pnumber));
|
||||
|
||||
// Full content request
|
||||
httpResponse.StatusCode = (int)System.Net.HttpStatusCode.OK;
|
||||
//httpResponse.ContentLength = ??;
|
||||
httpResponse.ContentType = "application/llsd+xml";
|
||||
|
||||
List<UserData> users = m_PeopleService.GetUserData(names, page_size, page_number);
|
||||
|
||||
LLSDAvatarPicker osdReply = new LLSDAvatarPicker();
|
||||
osdReply.next_page_url = httpRequest.RawUrl;
|
||||
foreach (UserData u in users)
|
||||
osdReply.agents.Array.Add(ConvertUserData(u));
|
||||
|
||||
string reply = LLSDHelpers.SerialiseLLSDReply(osdReply);
|
||||
return System.Text.Encoding.UTF8.GetBytes(reply);
|
||||
}
|
||||
|
||||
private LLSDPerson ConvertUserData(UserData user)
|
||||
{
|
||||
LLSDPerson p = new LLSDPerson();
|
||||
p.legacy_first_name = user.FirstName;
|
||||
p.legacy_last_name = user.LastName;
|
||||
p.display_name = user.FirstName + " " + user.LastName;
|
||||
if (user.LastName.StartsWith("@"))
|
||||
p.username = user.FirstName.ToLower() + user.LastName.ToLower();
|
||||
else
|
||||
p.username = user.FirstName.ToLower() + "." + user.LastName.ToLower();
|
||||
p.id = user.Id;
|
||||
p.is_display_name_default = false;
|
||||
return p;
|
||||
}
|
||||
|
||||
private byte[] FailureResponse(string names, int statuscode, IOSHttpResponse httpResponse)
|
||||
{
|
||||
m_log.Error("[AVATAR PICKER SEARCH]: Error searching for " + names);
|
||||
httpResponse.StatusCode = (int)System.Net.HttpStatusCode.NotFound;
|
||||
return System.Text.Encoding.UTF8.GetBytes(string.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -46,7 +46,7 @@ namespace OpenSim.Capabilities.Handlers
|
||||
{
|
||||
public class FetchInventory2Handler
|
||||
{
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private IInventoryService m_inventoryService;
|
||||
|
||||
@@ -121,4 +121,4 @@ namespace OpenSim.Capabilities.Handlers
|
||||
return llsdItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ namespace OpenSim.Capabilities.Handlers
|
||||
m_assetService = assService;
|
||||
}
|
||||
|
||||
public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
// Try to parse the texture ID from the request URL
|
||||
NameValueCollection query = HttpUtility.ParseQueryString(httpRequest.Url.Query);
|
||||
@@ -189,6 +189,7 @@ namespace OpenSim.Capabilities.Handlers
|
||||
|
||||
newTexture.Flags = AssetFlags.Collectable;
|
||||
newTexture.Temporary = true;
|
||||
newTexture.Local = true;
|
||||
m_assetService.Store(newTexture);
|
||||
WriteTextureData(httpRequest, httpResponse, newTexture, format);
|
||||
return true;
|
||||
|
||||
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using Nini.Config;
|
||||
using OpenSim.Server.Base;
|
||||
using OpenSim.Services.Interfaces;
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
using OpenSim.Server.Handlers.Base;
|
||||
using OpenMetaverse;
|
||||
|
||||
namespace OpenSim.Capabilities.Handlers
|
||||
{
|
||||
public class UploadBakedTextureServerConnector : ServiceConnector
|
||||
{
|
||||
private IAssetService m_AssetService;
|
||||
private string m_ConfigName = "CapsService";
|
||||
|
||||
public UploadBakedTextureServerConnector(IConfigSource config, IHttpServer server, string configName) :
|
||||
base(config, server, configName)
|
||||
{
|
||||
if (configName != String.Empty)
|
||||
m_ConfigName = configName;
|
||||
|
||||
IConfig serverConfig = config.Configs[m_ConfigName];
|
||||
if (serverConfig == null)
|
||||
throw new Exception(String.Format("No section '{0}' in config file", m_ConfigName));
|
||||
|
||||
string assetService = serverConfig.GetString("AssetService", String.Empty);
|
||||
|
||||
if (assetService == String.Empty)
|
||||
throw new Exception("No AssetService in config file");
|
||||
|
||||
Object[] args = new Object[] { config };
|
||||
m_AssetService =
|
||||
ServerUtils.LoadPlugin<IAssetService>(assetService, args);
|
||||
|
||||
if (m_AssetService == null)
|
||||
throw new Exception(String.Format("Failed to load AssetService from {0}; config is {1}", assetService, m_ConfigName));
|
||||
|
||||
// NEED TO FIX THIS
|
||||
OpenSim.Framework.Capabilities.Caps caps = new OpenSim.Framework.Capabilities.Caps(server, "", server.Port, "", UUID.Zero, "");
|
||||
server.AddStreamHandler(new RestStreamHandler(
|
||||
"POST",
|
||||
"/CAPS/UploadBakedTexture/",
|
||||
new UploadBakedTextureHandler(caps, m_AssetService, true).UploadBakedTexture,
|
||||
"UploadBakedTexture",
|
||||
"Upload Baked Texture Capability"));
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -25,35 +25,27 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using OpenSim.Framework.Servers.HttpServer;
|
||||
using OpenMetaverse;
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||
namespace OpenSim.Framework.Capabilities
|
||||
{
|
||||
|
||||
/// <remarks>
|
||||
/// The handler delegates are not noteworthy. The allocator allows
|
||||
/// a given handler to optionally subclass the base RequestData
|
||||
/// structure to carry any locally required per-request state
|
||||
/// needed.
|
||||
/// </remarks>
|
||||
|
||||
public delegate void RestMethodHandler(RequestData rdata);
|
||||
public delegate RequestData RestMethodAllocator(OSHttpRequest request, OSHttpResponse response, string path);
|
||||
|
||||
/// <summary>
|
||||
/// This interface exports the generic plugin-handling services
|
||||
/// available to each loaded REST services module (IRest implementation)
|
||||
/// </summary>
|
||||
|
||||
internal interface IRestHandler
|
||||
[OSDMap]
|
||||
public class LLSDAvatarPicker
|
||||
{
|
||||
|
||||
string MsgId { get; }
|
||||
string RequestId { get; }
|
||||
|
||||
void AddPathHandler(RestMethodHandler mh, string path, RestMethodAllocator ma);
|
||||
void AddStreamHandler(string httpMethod, string path, RestMethod method);
|
||||
|
||||
public string next_page_url;
|
||||
// an array of LLSDPerson
|
||||
public OSDArray agents = new OSDArray();
|
||||
}
|
||||
|
||||
}
|
||||
[OSDMap]
|
||||
public class LLSDPerson
|
||||
{
|
||||
public string username;
|
||||
public string display_name;
|
||||
//'display_name_next_update':d"1970-01-01T00:00:00Z"
|
||||
public string legacy_first_name;
|
||||
public string legacy_last_name;
|
||||
public UUID id;
|
||||
public bool is_display_name_default;
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ namespace OpenSim.Framework.Capabilities
|
||||
m_method = method;
|
||||
}
|
||||
|
||||
public override byte[] Handle(string path, Stream request,
|
||||
protected override byte[] ProcessRequest(string path, Stream request,
|
||||
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
//Encoding encoding = Util.UTF8;
|
||||
|
||||
@@ -50,6 +50,7 @@ namespace OpenSim.Data
|
||||
public interface IGridUserData
|
||||
{
|
||||
GridUserData Get(string userID);
|
||||
GridUserData[] GetAll(string query);
|
||||
bool Store(GridUserData data);
|
||||
}
|
||||
}
|
||||
56
OpenSim/Data/IProfilesData.cs
Normal file
56
OpenSim/Data/IProfilesData.cs
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.StructuredData;
|
||||
using OpenSim.Framework;
|
||||
|
||||
namespace OpenSim.Data
|
||||
{
|
||||
|
||||
public interface IProfilesData
|
||||
{
|
||||
OSDArray GetClassifiedRecords(UUID creatorId);
|
||||
bool UpdateClassifiedRecord(UserClassifiedAdd ad, ref string result);
|
||||
bool DeleteClassifiedRecord(UUID recordId);
|
||||
OSDArray GetAvatarPicks(UUID avatarId);
|
||||
UserProfilePick GetPickInfo(UUID avatarId, UUID pickId);
|
||||
bool UpdatePicksRecord(UserProfilePick pick);
|
||||
bool DeletePicksRecord(UUID pickId);
|
||||
bool GetAvatarNotes(ref UserProfileNotes note);
|
||||
bool UpdateAvatarNotes(ref UserProfileNotes note, ref string result);
|
||||
bool GetAvatarProperties(ref UserProfileProperties props, ref string result);
|
||||
bool UpdateAvatarProperties(ref UserProfileProperties props, ref string result);
|
||||
bool UpdateAvatarInterests(UserProfileProperties up, ref string result);
|
||||
bool GetClassifiedInfo(ref UserClassifiedAdd ad, ref string result);
|
||||
bool GetUserAppData(ref UserAppData props, ref string result);
|
||||
bool SetUserAppData(UserAppData props, ref string result);
|
||||
OSDArray GetUserImageAssets(UUID avatarId);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ namespace OpenSim.Data.MSSQL
|
||||
{
|
||||
}
|
||||
|
||||
public GridUserData Get(string userID)
|
||||
public new GridUserData Get(string userID)
|
||||
{
|
||||
GridUserData[] ret = Get("UserID", userID);
|
||||
|
||||
@@ -60,5 +60,10 @@ namespace OpenSim.Data.MSSQL
|
||||
return ret[0];
|
||||
}
|
||||
|
||||
public GridUserData[] GetAll(string userID)
|
||||
{
|
||||
return base.Get(String.Format("UserID LIKE '{0}%'", userID));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2100,7 +2100,7 @@ VALUES
|
||||
parameters.Add(_Database.CreateParameter("LinkNumber", prim.LinkNum));
|
||||
parameters.Add(_Database.CreateParameter("MediaURL", prim.MediaUrl));
|
||||
|
||||
if (prim.DynAttrs.Count > 0)
|
||||
if (prim.DynAttrs.CountNamespaces > 0)
|
||||
parameters.Add(_Database.CreateParameter("DynAttrs", prim.DynAttrs.ToXml()));
|
||||
else
|
||||
parameters.Add(_Database.CreateParameter("DynAttrs", null));
|
||||
|
||||
@@ -1153,7 +1153,7 @@ COMMIT
|
||||
|
||||
BEGIN TRANSACTION
|
||||
|
||||
ALTER TABLE prims ADD COLUMN DynAttrs TEXT;
|
||||
ALTER TABLE prims ADD DynAttrs TEXT;
|
||||
|
||||
COMMIT
|
||||
|
||||
@@ -1161,10 +1161,10 @@ COMMIT
|
||||
|
||||
BEGIN TRANSACTION
|
||||
|
||||
ALTER TABLE prims ADD COLUMN `PhysicsShapeType` tinyint(4) NOT NULL default '0';
|
||||
ALTER TABLE prims ADD COLUMN `Density` double NOT NULL default '1000';
|
||||
ALTER TABLE prims ADD COLUMN `GravityModifier` double NOT NULL default '1';
|
||||
ALTER TABLE prims ADD COLUMN `Friction` double NOT NULL default '0.6';
|
||||
ALTER TABLE prims ADD COLUMN `Restitution` double NOT NULL default '0.5';
|
||||
ALTER TABLE prims ADD `PhysicsShapeType` tinyint(4) NOT NULL default '0';
|
||||
ALTER TABLE prims ADD `Density` double NOT NULL default '1000';
|
||||
ALTER TABLE prims ADD `GravityModifier` double NOT NULL default '1';
|
||||
ALTER TABLE prims ADD `Friction` double NOT NULL default '0.6';
|
||||
ALTER TABLE prims ADD `Restitution` double NOT NULL default '0.5';
|
||||
|
||||
COMMIT
|
||||
|
||||
@@ -142,7 +142,8 @@ namespace OpenSim.Data.MySQL
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Error("[ASSETS DB]: MySql failure fetching asset " + assetID + ": " + e.Message);
|
||||
m_log.Error(
|
||||
string.Format("[ASSETS DB]: MySql failure fetching asset {0}. Exception ", assetID), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -209,8 +210,11 @@ namespace OpenSim.Data.MySQL
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat("[ASSET DB]: MySQL failure creating asset {0} with name \"{1}\". Error: {2}",
|
||||
asset.FullID, asset.Name, e.Message);
|
||||
m_log.Error(
|
||||
string.Format(
|
||||
"[ASSET DB]: MySQL failure creating asset {0} with name {1}. Exception ",
|
||||
asset.FullID, asset.Name)
|
||||
, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -241,10 +245,11 @@ namespace OpenSim.Data.MySQL
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[ASSETS DB]: " +
|
||||
"MySql failure updating access_time for asset {0} with name {1}" + Environment.NewLine + e.ToString()
|
||||
+ Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name);
|
||||
m_log.Error(
|
||||
string.Format(
|
||||
"[ASSETS DB]: Failure updating access_time for asset {0} with name {1}. Exception ",
|
||||
asset.FullID, asset.Name),
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -284,8 +289,8 @@ namespace OpenSim.Data.MySQL
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[ASSETS DB]: MySql failure fetching asset {0}" + Environment.NewLine + e.ToString(), uuid);
|
||||
m_log.Error(
|
||||
string.Format("[ASSETS DB]: MySql failure fetching asset {0}. Exception ", uuid), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -344,7 +349,11 @@ namespace OpenSim.Data.MySQL
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Error("[ASSETS DB]: MySql failure fetching asset set" + Environment.NewLine + e.ToString());
|
||||
m_log.Error(
|
||||
string.Format(
|
||||
"[ASSETS DB]: MySql failure fetching asset set from {0}, count {1}. Exception ",
|
||||
start, count),
|
||||
e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ namespace OpenSim.Data.MySQL
|
||||
|
||||
public MySQLGridUserData(string connectionString, string realm) : base(connectionString, realm, "GridUserStore") {}
|
||||
|
||||
public GridUserData Get(string userID)
|
||||
public new GridUserData Get(string userID)
|
||||
{
|
||||
GridUserData[] ret = Get("UserID", userID);
|
||||
|
||||
@@ -56,6 +56,9 @@ namespace OpenSim.Data.MySQL
|
||||
return ret[0];
|
||||
}
|
||||
|
||||
|
||||
public GridUserData[] GetAll(string userID)
|
||||
{
|
||||
return base.Get(String.Format("UserID LIKE '{0}%'", userID));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -47,13 +47,10 @@ namespace OpenSim.Data.MySQL
|
||||
|
||||
public void DeleteOld()
|
||||
{
|
||||
uint now = (uint)Util.UnixTimeSinceEpoch();
|
||||
|
||||
using (MySqlCommand cmd = new MySqlCommand())
|
||||
{
|
||||
cmd.CommandText = String.Format("delete from {0} where TMStamp < ?tstamp", m_Realm);
|
||||
cmd.Parameters.AddWithValue("?tstamp", now - 14 * 24 * 60 * 60); // > 2 weeks old
|
||||
|
||||
cmd.CommandText = String.Format("delete from {0} where TMStamp < NOW() - INTERVAL 2 WEEK", m_Realm);
|
||||
|
||||
ExecuteNonQuery(cmd);
|
||||
}
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ namespace OpenSim.Data.MySQL
|
||||
private string m_connectionString;
|
||||
private object m_dbLock = new object();
|
||||
|
||||
protected Assembly Assembly
|
||||
protected virtual Assembly Assembly
|
||||
{
|
||||
get { return GetType().Assembly; }
|
||||
}
|
||||
@@ -173,9 +173,9 @@ namespace OpenSim.Data.MySQL
|
||||
"ParticleSystem, ClickAction, Material, " +
|
||||
"CollisionSound, CollisionSoundVolume, " +
|
||||
"PassTouches, " +
|
||||
"LinkNumber, MediaURL, DynAttrs, " +
|
||||
"LinkNumber, MediaURL, KeyframeMotion, " +
|
||||
"PhysicsShapeType, Density, GravityModifier, " +
|
||||
"Friction, Restitution " +
|
||||
"Friction, Restitution, DynAttrs " +
|
||||
") values (" + "?UUID, " +
|
||||
"?CreationDate, ?Name, ?Text, " +
|
||||
"?Description, ?SitName, ?TouchName, " +
|
||||
@@ -208,9 +208,9 @@ namespace OpenSim.Data.MySQL
|
||||
"?ColorB, ?ColorA, ?ParticleSystem, " +
|
||||
"?ClickAction, ?Material, ?CollisionSound, " +
|
||||
"?CollisionSoundVolume, ?PassTouches, " +
|
||||
"?LinkNumber, ?MediaURL, ?DynAttrs, " +
|
||||
"?LinkNumber, ?MediaURL, ?KeyframeMotion, " +
|
||||
"?PhysicsShapeType, ?Density, ?GravityModifier, " +
|
||||
"?Friction, ?Restitution)";
|
||||
"?Friction, ?Restitution, ?DynAttrs)";
|
||||
|
||||
FillPrimCommand(cmd, prim, obj.UUID, regionUUID);
|
||||
|
||||
@@ -455,7 +455,9 @@ namespace OpenSim.Data.MySQL
|
||||
foreach (SceneObjectPart prim in prims.Values)
|
||||
{
|
||||
if (prim.ParentUUID == UUID.Zero)
|
||||
{
|
||||
objects[prim.UUID] = new SceneObjectGroup(prim);
|
||||
}
|
||||
}
|
||||
|
||||
// Add all of the children objects to the SOGs
|
||||
@@ -1307,6 +1309,19 @@ namespace OpenSim.Data.MySQL
|
||||
else
|
||||
prim.DynAttrs = new DAMap();
|
||||
|
||||
if (!(row["KeyframeMotion"] is DBNull))
|
||||
{
|
||||
Byte[] data = (byte[])row["KeyframeMotion"];
|
||||
if (data.Length > 0)
|
||||
prim.KeyframeMotion = KeyframeMotion.FromData(null, data);
|
||||
else
|
||||
prim.KeyframeMotion = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
prim.KeyframeMotion = null;
|
||||
}
|
||||
|
||||
prim.PhysicsShapeType = (byte)Convert.ToInt32(row["PhysicsShapeType"].ToString());
|
||||
prim.Density = (float)(double)row["Density"];
|
||||
prim.GravityModifier = (float)(double)row["GravityModifier"];
|
||||
@@ -1659,8 +1674,12 @@ namespace OpenSim.Data.MySQL
|
||||
cmd.Parameters.AddWithValue("LinkNumber", prim.LinkNum);
|
||||
cmd.Parameters.AddWithValue("MediaURL", prim.MediaUrl);
|
||||
|
||||
if (prim.KeyframeMotion != null)
|
||||
cmd.Parameters.AddWithValue("KeyframeMotion", prim.KeyframeMotion.Serialize());
|
||||
else
|
||||
cmd.Parameters.AddWithValue("KeyframeMotion", new Byte[0]);
|
||||
|
||||
if (prim.DynAttrs.Count > 0)
|
||||
if (prim.DynAttrs.CountNamespaces > 0)
|
||||
cmd.Parameters.AddWithValue("DynAttrs", prim.DynAttrs.ToXml());
|
||||
else
|
||||
cmd.Parameters.AddWithValue("DynAttrs", null);
|
||||
|
||||
1096
OpenSim/Data/MySQL/MySQLUserProfilesData.cs
Normal file
1096
OpenSim/Data/MySQL/MySQLUserProfilesData.cs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -50,6 +50,11 @@ namespace OpenSim.Data.MySQL
|
||||
get { return GetType().Assembly; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Number of days that must pass before we update the access time on an asset when it has been fetched.
|
||||
/// </summary>
|
||||
private const int DaysBetweenAccessTimeUpdates = 30;
|
||||
|
||||
private bool m_enableCompression = false;
|
||||
private string m_connectionString;
|
||||
private object m_dbLock = new object();
|
||||
@@ -133,10 +138,10 @@ namespace OpenSim.Data.MySQL
|
||||
dbcon.Open();
|
||||
|
||||
using (MySqlCommand cmd = new MySqlCommand(
|
||||
"SELECT name, description, asset_type, local, temporary, asset_flags, creator_id, data FROM xassetsmeta JOIN xassetsdata ON xassetsmeta.hash = xassetsdata.hash WHERE id=?id",
|
||||
"SELECT Name, Description, AccessTime, AssetType, Local, Temporary, AssetFlags, CreatorID, Data FROM XAssetsMeta JOIN XAssetsData ON XAssetsMeta.Hash = XAssetsData.Hash WHERE ID=?ID",
|
||||
dbcon))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("?id", assetID.ToString());
|
||||
cmd.Parameters.AddWithValue("?ID", assetID.ToString());
|
||||
|
||||
try
|
||||
{
|
||||
@@ -144,18 +149,18 @@ namespace OpenSim.Data.MySQL
|
||||
{
|
||||
if (dbReader.Read())
|
||||
{
|
||||
asset = new AssetBase(assetID, (string)dbReader["name"], (sbyte)dbReader["asset_type"], dbReader["creator_id"].ToString());
|
||||
asset.Data = (byte[])dbReader["data"];
|
||||
asset.Description = (string)dbReader["description"];
|
||||
asset = new AssetBase(assetID, (string)dbReader["Name"], (sbyte)dbReader["AssetType"], dbReader["CreatorID"].ToString());
|
||||
asset.Data = (byte[])dbReader["Data"];
|
||||
asset.Description = (string)dbReader["Description"];
|
||||
|
||||
string local = dbReader["local"].ToString();
|
||||
string local = dbReader["Local"].ToString();
|
||||
if (local.Equals("1") || local.Equals("true", StringComparison.InvariantCultureIgnoreCase))
|
||||
asset.Local = true;
|
||||
else
|
||||
asset.Local = false;
|
||||
|
||||
asset.Temporary = Convert.ToBoolean(dbReader["temporary"]);
|
||||
asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]);
|
||||
asset.Temporary = Convert.ToBoolean(dbReader["Temporary"]);
|
||||
asset.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]);
|
||||
|
||||
if (m_enableCompression)
|
||||
{
|
||||
@@ -171,12 +176,14 @@ namespace OpenSim.Data.MySQL
|
||||
// asset.ID, asset.Name, asset.Data.Length, compressedLength);
|
||||
}
|
||||
}
|
||||
|
||||
UpdateAccessTime(asset.Metadata, (int)dbReader["AccessTime"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Error("[MYSQL XASSET DATA]: MySql failure fetching asset " + assetID + ": " + e.Message);
|
||||
m_log.Error(string.Format("[MYSQL XASSET DATA]: Failure fetching asset {0}", assetID), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -192,6 +199,8 @@ namespace OpenSim.Data.MySQL
|
||||
/// <remarks>On failure : Throw an exception and attempt to reconnect to database</remarks>
|
||||
public void StoreAsset(AssetBase asset)
|
||||
{
|
||||
// m_log.DebugFormat("[XASSETS DB]: Storing asset {0} {1}", asset.Name, asset.ID);
|
||||
|
||||
lock (m_dbLock)
|
||||
{
|
||||
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
||||
@@ -242,23 +251,23 @@ namespace OpenSim.Data.MySQL
|
||||
{
|
||||
using (MySqlCommand cmd =
|
||||
new MySqlCommand(
|
||||
"replace INTO xassetsmeta(id, hash, name, description, asset_type, local, temporary, create_time, access_time, asset_flags, creator_id)" +
|
||||
"VALUES(?id, ?hash, ?name, ?description, ?asset_type, ?local, ?temporary, ?create_time, ?access_time, ?asset_flags, ?creator_id)",
|
||||
"replace INTO XAssetsMeta(ID, Hash, Name, Description, AssetType, Local, Temporary, CreateTime, AccessTime, AssetFlags, CreatorID)" +
|
||||
"VALUES(?ID, ?Hash, ?Name, ?Description, ?AssetType, ?Local, ?Temporary, ?CreateTime, ?AccessTime, ?AssetFlags, ?CreatorID)",
|
||||
dbcon))
|
||||
{
|
||||
// create unix epoch time
|
||||
int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow);
|
||||
cmd.Parameters.AddWithValue("?id", asset.ID);
|
||||
cmd.Parameters.AddWithValue("?hash", hash);
|
||||
cmd.Parameters.AddWithValue("?name", assetName);
|
||||
cmd.Parameters.AddWithValue("?description", assetDescription);
|
||||
cmd.Parameters.AddWithValue("?asset_type", asset.Type);
|
||||
cmd.Parameters.AddWithValue("?local", asset.Local);
|
||||
cmd.Parameters.AddWithValue("?temporary", asset.Temporary);
|
||||
cmd.Parameters.AddWithValue("?create_time", now);
|
||||
cmd.Parameters.AddWithValue("?access_time", now);
|
||||
cmd.Parameters.AddWithValue("?creator_id", asset.Metadata.CreatorID);
|
||||
cmd.Parameters.AddWithValue("?asset_flags", (int)asset.Flags);
|
||||
cmd.Parameters.AddWithValue("?ID", asset.ID);
|
||||
cmd.Parameters.AddWithValue("?Hash", hash);
|
||||
cmd.Parameters.AddWithValue("?Name", assetName);
|
||||
cmd.Parameters.AddWithValue("?Description", assetDescription);
|
||||
cmd.Parameters.AddWithValue("?AssetType", asset.Type);
|
||||
cmd.Parameters.AddWithValue("?Local", asset.Local);
|
||||
cmd.Parameters.AddWithValue("?Temporary", asset.Temporary);
|
||||
cmd.Parameters.AddWithValue("?CreateTime", now);
|
||||
cmd.Parameters.AddWithValue("?AccessTime", now);
|
||||
cmd.Parameters.AddWithValue("?CreatorID", asset.Metadata.CreatorID);
|
||||
cmd.Parameters.AddWithValue("?AssetFlags", (int)asset.Flags);
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
@@ -278,11 +287,11 @@ namespace OpenSim.Data.MySQL
|
||||
{
|
||||
using (MySqlCommand cmd =
|
||||
new MySqlCommand(
|
||||
"INSERT INTO xassetsdata(hash, data) VALUES(?hash, ?data)",
|
||||
"INSERT INTO XAssetsData(Hash, Data) VALUES(?Hash, ?Data)",
|
||||
dbcon))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("?hash", hash);
|
||||
cmd.Parameters.AddWithValue("?data", asset.Data);
|
||||
cmd.Parameters.AddWithValue("?Hash", hash);
|
||||
cmd.Parameters.AddWithValue("?Data", asset.Data);
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
@@ -303,41 +312,49 @@ namespace OpenSim.Data.MySQL
|
||||
}
|
||||
}
|
||||
|
||||
// private void UpdateAccessTime(AssetBase asset)
|
||||
// {
|
||||
// lock (m_dbLock)
|
||||
// {
|
||||
// using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
||||
// {
|
||||
// dbcon.Open();
|
||||
// MySqlCommand cmd =
|
||||
// new MySqlCommand("update assets set access_time=?access_time where id=?id",
|
||||
// dbcon);
|
||||
//
|
||||
// // need to ensure we dispose
|
||||
// try
|
||||
// {
|
||||
// using (cmd)
|
||||
// {
|
||||
// // create unix epoch time
|
||||
// int now = (int)Utils.DateTimeToUnixTime(DateTime.UtcNow);
|
||||
// cmd.Parameters.AddWithValue("?id", asset.ID);
|
||||
// cmd.Parameters.AddWithValue("?access_time", now);
|
||||
// cmd.ExecuteNonQuery();
|
||||
// cmd.Dispose();
|
||||
// }
|
||||
// }
|
||||
// catch (Exception e)
|
||||
// {
|
||||
// m_log.ErrorFormat(
|
||||
// "[ASSETS DB]: " +
|
||||
// "MySql failure updating access_time for asset {0} with name {1}" + Environment.NewLine + e.ToString()
|
||||
// + Environment.NewLine + "Attempting reconnection", asset.FullID, asset.Name);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// }
|
||||
/// <summary>
|
||||
/// Updates the access time of the asset if it was accessed above a given threshhold amount of time.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This gives us some insight into assets which haven't ben accessed for a long period. This is only done
|
||||
/// over the threshold time to avoid excessive database writes as assets are fetched.
|
||||
/// </remarks>
|
||||
/// <param name='asset'></param>
|
||||
/// <param name='accessTime'></param>
|
||||
private void UpdateAccessTime(AssetMetadata assetMetadata, int accessTime)
|
||||
{
|
||||
DateTime now = DateTime.UtcNow;
|
||||
|
||||
if ((now - Utils.UnixTimeToDateTime(accessTime)).TotalDays < DaysBetweenAccessTimeUpdates)
|
||||
return;
|
||||
|
||||
lock (m_dbLock)
|
||||
{
|
||||
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
||||
{
|
||||
dbcon.Open();
|
||||
MySqlCommand cmd =
|
||||
new MySqlCommand("update XAssetsMeta set AccessTime=?AccessTime where ID=?ID", dbcon);
|
||||
|
||||
try
|
||||
{
|
||||
using (cmd)
|
||||
{
|
||||
// create unix epoch time
|
||||
cmd.Parameters.AddWithValue("?ID", assetMetadata.ID);
|
||||
cmd.Parameters.AddWithValue("?AccessTime", (int)Utils.DateTimeToUnixTime(now));
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[XASSET MYSQL DB]: Failure updating access_time for asset {0} with name {1}",
|
||||
assetMetadata.ID, assetMetadata.Name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// We assume we already have the m_dbLock.
|
||||
@@ -353,9 +370,9 @@ namespace OpenSim.Data.MySQL
|
||||
|
||||
bool exists = false;
|
||||
|
||||
using (MySqlCommand cmd = new MySqlCommand("SELECT hash FROM xassetsdata WHERE hash=?hash", dbcon))
|
||||
using (MySqlCommand cmd = new MySqlCommand("SELECT Hash FROM XAssetsData WHERE Hash=?Hash", dbcon))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("?hash", hash);
|
||||
cmd.Parameters.AddWithValue("?Hash", hash);
|
||||
|
||||
try
|
||||
{
|
||||
@@ -395,9 +412,9 @@ namespace OpenSim.Data.MySQL
|
||||
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
||||
{
|
||||
dbcon.Open();
|
||||
using (MySqlCommand cmd = new MySqlCommand("SELECT id FROM xassetsmeta WHERE id=?id", dbcon))
|
||||
using (MySqlCommand cmd = new MySqlCommand("SELECT ID FROM XAssetsMeta WHERE ID=?ID", dbcon))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("?id", uuid.ToString());
|
||||
cmd.Parameters.AddWithValue("?ID", uuid.ToString());
|
||||
|
||||
try
|
||||
{
|
||||
@@ -412,8 +429,7 @@ namespace OpenSim.Data.MySQL
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat(
|
||||
"[XASSETS DB]: MySql failure fetching asset {0}" + Environment.NewLine + e.ToString(), uuid);
|
||||
m_log.Error(string.Format("[XASSETS DB]: MySql failure fetching asset {0}", uuid), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -422,6 +438,7 @@ namespace OpenSim.Data.MySQL
|
||||
return assetExists;
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Returns a list of AssetMetadata objects. The list is a subset of
|
||||
/// the entire data set offset by <paramref name="start" /> containing
|
||||
@@ -439,7 +456,7 @@ namespace OpenSim.Data.MySQL
|
||||
using (MySqlConnection dbcon = new MySqlConnection(m_connectionString))
|
||||
{
|
||||
dbcon.Open();
|
||||
MySqlCommand cmd = new MySqlCommand("SELECT name,description,asset_type,temporary,id,asset_flags,creator_id FROM xassetsmeta LIMIT ?start, ?count", dbcon);
|
||||
MySqlCommand cmd = new MySqlCommand("SELECT Name, Description, AccessTime, AssetType, Temporary, ID, AssetFlags, CreatorID FROM XAssetsMeta LIMIT ?start, ?count", dbcon);
|
||||
cmd.Parameters.AddWithValue("?start", start);
|
||||
cmd.Parameters.AddWithValue("?count", count);
|
||||
|
||||
@@ -450,17 +467,19 @@ namespace OpenSim.Data.MySQL
|
||||
while (dbReader.Read())
|
||||
{
|
||||
AssetMetadata metadata = new AssetMetadata();
|
||||
metadata.Name = (string)dbReader["name"];
|
||||
metadata.Description = (string)dbReader["description"];
|
||||
metadata.Type = (sbyte)dbReader["asset_type"];
|
||||
metadata.Temporary = Convert.ToBoolean(dbReader["temporary"]); // Not sure if this is correct.
|
||||
metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["asset_flags"]);
|
||||
metadata.FullID = DBGuid.FromDB(dbReader["id"]);
|
||||
metadata.CreatorID = dbReader["creator_id"].ToString();
|
||||
metadata.Name = (string)dbReader["Name"];
|
||||
metadata.Description = (string)dbReader["Description"];
|
||||
metadata.Type = (sbyte)dbReader["AssetType"];
|
||||
metadata.Temporary = Convert.ToBoolean(dbReader["Temporary"]); // Not sure if this is correct.
|
||||
metadata.Flags = (AssetFlags)Convert.ToInt32(dbReader["AssetFlags"]);
|
||||
metadata.FullID = DBGuid.FromDB(dbReader["ID"]);
|
||||
metadata.CreatorID = dbReader["CreatorID"].ToString();
|
||||
|
||||
// We'll ignore this for now - it appears unused!
|
||||
// metadata.SHA1 = dbReader["hash"]);
|
||||
|
||||
UpdateAccessTime(metadata, (int)dbReader["AccessTime"]);
|
||||
|
||||
retList.Add(metadata);
|
||||
}
|
||||
}
|
||||
@@ -485,9 +504,9 @@ namespace OpenSim.Data.MySQL
|
||||
{
|
||||
dbcon.Open();
|
||||
|
||||
using (MySqlCommand cmd = new MySqlCommand("delete from xassetsmeta where id=?id", dbcon))
|
||||
using (MySqlCommand cmd = new MySqlCommand("delete from XAssetsMeta where ID=?ID", dbcon))
|
||||
{
|
||||
cmd.Parameters.AddWithValue("?id", id);
|
||||
cmd.Parameters.AddWithValue("?ID", id);
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
|
||||
|
||||
@@ -77,5 +77,11 @@ BEGIN;
|
||||
ALTER TABLE estate_settings AUTO_INCREMENT = 100;
|
||||
COMMIT;
|
||||
|
||||
:VERSION 33 #---------------------
|
||||
|
||||
BEGIN;
|
||||
ALTER TABLE estate_settings ADD COLUMN `AllowLandmark` tinyint(4) NOT NULL default '1';
|
||||
ALTER TABLE estate_settings ADD COLUMN `AllowParcelChanges` tinyint(4) NOT NULL default '1';
|
||||
ALTER TABLE estate_settings ADD COLUMN `AllowSetHome` tinyint(4) NOT NULL default '1';
|
||||
COMMIT;
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ CREATE TABLE `Friends` (
|
||||
`Offered` VARCHAR(32) NOT NULL DEFAULT 0,
|
||||
PRIMARY KEY(`PrincipalID`, `Friend`),
|
||||
KEY(`PrincipalID`)
|
||||
);
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
COMMIT;
|
||||
|
||||
|
||||
@@ -923,3 +923,10 @@ ALTER TABLE prims ADD COLUMN `Restitution` double NOT NULL default '0.5';
|
||||
|
||||
COMMIT;
|
||||
|
||||
:VERSION 48 #---------------- Keyframes
|
||||
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE prims ADD COLUMN `KeyframeMotion` blob;
|
||||
|
||||
COMMIT;
|
||||
|
||||
83
OpenSim/Data/MySQL/Resources/UserProfiles.migrations
Normal file
83
OpenSim/Data/MySQL/Resources/UserProfiles.migrations
Normal file
@@ -0,0 +1,83 @@
|
||||
:VERSION 1 # -------------------------------
|
||||
|
||||
begin;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `classifieds` (
|
||||
`classifieduuid` char(36) NOT NULL,
|
||||
`creatoruuid` char(36) NOT NULL,
|
||||
`creationdate` int(20) NOT NULL,
|
||||
`expirationdate` int(20) NOT NULL,
|
||||
`category` varchar(20) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`description` text NOT NULL,
|
||||
`parceluuid` char(36) NOT NULL,
|
||||
`parentestate` int(11) NOT NULL,
|
||||
`snapshotuuid` char(36) NOT NULL,
|
||||
`simname` varchar(255) NOT NULL,
|
||||
`posglobal` varchar(255) NOT NULL,
|
||||
`parcelname` varchar(255) NOT NULL,
|
||||
`classifiedflags` int(8) NOT NULL,
|
||||
`priceforlisting` int(5) NOT NULL,
|
||||
PRIMARY KEY (`classifieduuid`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `usernotes` (
|
||||
`useruuid` varchar(36) NOT NULL,
|
||||
`targetuuid` varchar(36) NOT NULL,
|
||||
`notes` text NOT NULL,
|
||||
UNIQUE KEY `useruuid` (`useruuid`,`targetuuid`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `userpicks` (
|
||||
`pickuuid` varchar(36) NOT NULL,
|
||||
`creatoruuid` varchar(36) NOT NULL,
|
||||
`toppick` enum('true','false') NOT NULL,
|
||||
`parceluuid` varchar(36) NOT NULL,
|
||||
`name` varchar(255) NOT NULL,
|
||||
`description` text NOT NULL,
|
||||
`snapshotuuid` varchar(36) NOT NULL,
|
||||
`user` varchar(255) NOT NULL,
|
||||
`originalname` varchar(255) NOT NULL,
|
||||
`simname` varchar(255) NOT NULL,
|
||||
`posglobal` varchar(255) NOT NULL,
|
||||
`sortorder` int(2) NOT NULL,
|
||||
`enabled` enum('true','false') NOT NULL,
|
||||
PRIMARY KEY (`pickuuid`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
|
||||
|
||||
|
||||
CREATE TABLE IF NOT EXISTS `userprofile` (
|
||||
`useruuid` varchar(36) NOT NULL,
|
||||
`profilePartner` varchar(36) NOT NULL,
|
||||
`profileAllowPublish` binary(1) NOT NULL,
|
||||
`profileMaturePublish` binary(1) NOT NULL,
|
||||
`profileURL` varchar(255) NOT NULL,
|
||||
`profileWantToMask` int(3) NOT NULL,
|
||||
`profileWantToText` text NOT NULL,
|
||||
`profileSkillsMask` int(3) NOT NULL,
|
||||
`profileSkillsText` text NOT NULL,
|
||||
`profileLanguages` text NOT NULL,
|
||||
`profileImage` varchar(36) NOT NULL,
|
||||
`profileAboutText` text NOT NULL,
|
||||
`profileFirstImage` varchar(36) NOT NULL,
|
||||
`profileFirstText` text NOT NULL,
|
||||
PRIMARY KEY (`useruuid`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
|
||||
|
||||
commit;
|
||||
|
||||
:VERSION 2 # -------------------------------
|
||||
|
||||
begin;
|
||||
CREATE TABLE IF NOT EXISTS `userdata` (
|
||||
`UserId` char(36) NOT NULL,
|
||||
`TagId` varchar(64) NOT NULL,
|
||||
`DataKey` varchar(255),
|
||||
`DataVal` varchar(255),
|
||||
PRIMARY KEY (`UserId`,`TagId`)
|
||||
) ENGINE=MyISAM DEFAULT CHARSET=latin1;
|
||||
|
||||
commit;
|
||||
|
||||
@@ -3,24 +3,24 @@
|
||||
|
||||
BEGIN;
|
||||
|
||||
CREATE TABLE `xassetsmeta` (
|
||||
`id` char(36) NOT NULL,
|
||||
`hash` binary(32) NOT NULL,
|
||||
`name` varchar(64) NOT NULL,
|
||||
`description` varchar(64) NOT NULL,
|
||||
`asset_type` tinyint(4) NOT NULL,
|
||||
`local` tinyint(1) NOT NULL,
|
||||
`temporary` tinyint(1) NOT NULL,
|
||||
`create_time` int(11) NOT NULL,
|
||||
`access_time` int(11) NOT NULL,
|
||||
`asset_flags` int(11) NOT NULL,
|
||||
`creator_id` varchar(128) NOT NULL,
|
||||
CREATE TABLE `XAssetsMeta` (
|
||||
`ID` char(36) NOT NULL,
|
||||
`Hash` binary(32) NOT NULL,
|
||||
`Name` varchar(64) NOT NULL,
|
||||
`Description` varchar(64) NOT NULL,
|
||||
`AssetType` tinyint(4) NOT NULL,
|
||||
`Local` tinyint(1) NOT NULL,
|
||||
`Temporary` tinyint(1) NOT NULL,
|
||||
`CreateTime` int(11) NOT NULL,
|
||||
`AccessTime` int(11) NOT NULL,
|
||||
`AssetFlags` int(11) NOT NULL,
|
||||
`CreatorID` varchar(128) NOT NULL,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1';
|
||||
|
||||
CREATE TABLE `xassetsdata` (
|
||||
`hash` binary(32) NOT NULL,
|
||||
`data` longblob NOT NULL,
|
||||
CREATE TABLE `XAssetsData` (
|
||||
`Hash` binary(32) NOT NULL,
|
||||
`Data` longblob NOT NULL,
|
||||
PRIMARY KEY (`hash`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Version 1';
|
||||
|
||||
|
||||
@@ -42,6 +42,22 @@ namespace OpenSim.Data.Null
|
||||
|
||||
// private string m_connectionString;
|
||||
|
||||
private Dictionary<uint, EstateSettings> m_knownEstates = new Dictionary<uint, EstateSettings>();
|
||||
private EstateSettings m_estate = null;
|
||||
|
||||
private EstateSettings GetEstate()
|
||||
{
|
||||
if (m_estate == null)
|
||||
{
|
||||
// This fools the initialization caller into thinking an estate was fetched (a check in OpenSimBase).
|
||||
// The estate info is pretty empty so don't try banning anyone.
|
||||
m_estate = new EstateSettings();
|
||||
m_estate.EstateID = 1;
|
||||
m_estate.OnSave += StoreEstateSettings;
|
||||
}
|
||||
return m_estate;
|
||||
}
|
||||
|
||||
protected virtual Assembly Assembly
|
||||
{
|
||||
get { return GetType().Assembly; }
|
||||
@@ -68,21 +84,18 @@ namespace OpenSim.Data.Null
|
||||
|
||||
public EstateSettings LoadEstateSettings(UUID regionID, bool create)
|
||||
{
|
||||
// This fools the initialization caller into thinking an estate was fetched (a check in OpenSimBase).
|
||||
// The estate info is pretty empty so don't try banning anyone.
|
||||
EstateSettings oneEstate = new EstateSettings();
|
||||
oneEstate.EstateID = 1;
|
||||
return oneEstate;
|
||||
return GetEstate();
|
||||
}
|
||||
|
||||
public void StoreEstateSettings(EstateSettings es)
|
||||
{
|
||||
m_estate = es;
|
||||
return;
|
||||
}
|
||||
|
||||
public EstateSettings LoadEstateSettings(int estateID)
|
||||
{
|
||||
return new EstateSettings();
|
||||
return GetEstate();
|
||||
}
|
||||
|
||||
public EstateSettings CreateNewEstate()
|
||||
@@ -93,13 +106,14 @@ namespace OpenSim.Data.Null
|
||||
public List<EstateSettings> LoadEstateSettingsAll()
|
||||
{
|
||||
List<EstateSettings> allEstateSettings = new List<EstateSettings>();
|
||||
allEstateSettings.Add(new EstateSettings());
|
||||
allEstateSettings.Add(GetEstate());
|
||||
return allEstateSettings;
|
||||
}
|
||||
|
||||
public List<int> GetEstatesAll()
|
||||
{
|
||||
List<int> result = new List<int>();
|
||||
result.Add((int)GetEstate().EstateID);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -86,3 +86,12 @@ begin;
|
||||
alter table estate_settings add column DenyMinors tinyint not null default 0;
|
||||
|
||||
commit;
|
||||
|
||||
:VERSION 9
|
||||
|
||||
begin;
|
||||
alter table estate_settings add column AllowLandmark tinyint not null default '1';
|
||||
alter table estate_settings add column AllowParcelChanges tinyint not null default '1';
|
||||
alter table estate_settings add column AllowSetHome tinyint not null default '1';
|
||||
commit;
|
||||
|
||||
|
||||
@@ -592,3 +592,11 @@ ALTER TABLE prims ADD COLUMN `Friction` double NOT NULL default '0.6';
|
||||
ALTER TABLE prims ADD COLUMN `Restitution` double NOT NULL default '0.5';
|
||||
|
||||
COMMIT;
|
||||
|
||||
:VERSION 29 #---------------- Keyframes
|
||||
|
||||
BEGIN;
|
||||
|
||||
ALTER TABLE prims ADD COLUMN `KeyframeMotion` blob;
|
||||
|
||||
COMMIT;
|
||||
|
||||
90
OpenSim/Data/SQLite/Resources/UserProfiles.migrations
Normal file
90
OpenSim/Data/SQLite/Resources/UserProfiles.migrations
Normal file
@@ -0,0 +1,90 @@
|
||||
:VERSION 1 # -------------------------------
|
||||
|
||||
begin;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS classifieds (
|
||||
classifieduuid char(36) NOT NULL PRIMARY KEY,
|
||||
creatoruuid char(36) NOT NULL,
|
||||
creationdate int(20) NOT NULL,
|
||||
expirationdate int(20) NOT NULL,
|
||||
category varchar(20) NOT NULL,
|
||||
name varchar(255) NOT NULL,
|
||||
description text NOT NULL,
|
||||
parceluuid char(36) NOT NULL,
|
||||
parentestate int(11) NOT NULL,
|
||||
snapshotuuid char(36) NOT NULL,
|
||||
simname varchar(255) NOT NULL,
|
||||
posglobal varchar(255) NOT NULL,
|
||||
parcelname varchar(255) NOT NULL,
|
||||
classifiedflags int(8) NOT NULL,
|
||||
priceforlisting int(5) NOT NULL
|
||||
);
|
||||
|
||||
commit;
|
||||
|
||||
begin;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS usernotes (
|
||||
useruuid varchar(36) NOT NULL,
|
||||
targetuuid varchar(36) NOT NULL,
|
||||
notes text NOT NULL,
|
||||
UNIQUE (useruuid,targetuuid) ON CONFLICT REPLACE
|
||||
);
|
||||
|
||||
commit;
|
||||
|
||||
begin;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS userpicks (
|
||||
pickuuid varchar(36) NOT NULL PRIMARY KEY,
|
||||
creatoruuid varchar(36) NOT NULL,
|
||||
toppick int NOT NULL,
|
||||
parceluuid varchar(36) NOT NULL,
|
||||
name varchar(255) NOT NULL,
|
||||
description text NOT NULL,
|
||||
snapshotuuid varchar(36) NOT NULL,
|
||||
user varchar(255) NOT NULL,
|
||||
originalname varchar(255) NOT NULL,
|
||||
simname varchar(255) NOT NULL,
|
||||
posglobal varchar(255) NOT NULL,
|
||||
sortorder int(2) NOT NULL,
|
||||
enabled int NOT NULL
|
||||
);
|
||||
|
||||
commit;
|
||||
|
||||
begin;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS userprofile (
|
||||
useruuid varchar(36) NOT NULL PRIMARY KEY,
|
||||
profilePartner varchar(36) NOT NULL,
|
||||
profileAllowPublish binary(1) NOT NULL,
|
||||
profileMaturePublish binary(1) NOT NULL,
|
||||
profileURL varchar(255) NOT NULL,
|
||||
profileWantToMask int(3) NOT NULL,
|
||||
profileWantToText text NOT NULL,
|
||||
profileSkillsMask int(3) NOT NULL,
|
||||
profileSkillsText text NOT NULL,
|
||||
profileLanguages text NOT NULL,
|
||||
profileImage varchar(36) NOT NULL,
|
||||
profileAboutText text NOT NULL,
|
||||
profileFirstImage varchar(36) NOT NULL,
|
||||
profileFirstText text NOT NULL
|
||||
);
|
||||
|
||||
commit;
|
||||
|
||||
:VERSION 2 # -------------------------------
|
||||
|
||||
begin;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS userdata (
|
||||
UserId char(36) NOT NULL,
|
||||
TagId varchar(64) NOT NULL,
|
||||
DataKey varchar(255),
|
||||
DataVal varchar(255),
|
||||
PRIMARY KEY (UserId,TagId)
|
||||
);
|
||||
|
||||
commit;
|
||||
|
||||
@@ -56,6 +56,10 @@ namespace OpenSim.Data.SQLite
|
||||
return ret[0];
|
||||
}
|
||||
|
||||
public GridUserData[] GetAll(string userID)
|
||||
{
|
||||
return base.Get(String.Format("UserID LIKE '{0}%'", userID));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -732,9 +732,12 @@ namespace OpenSim.Data.SQLite
|
||||
}
|
||||
|
||||
SceneObjectGroup group = new SceneObjectGroup(prim);
|
||||
|
||||
createdObjects.Add(group.UUID, group);
|
||||
retvals.Add(group);
|
||||
LoadItems(prim);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -1241,6 +1244,7 @@ namespace OpenSim.Data.SQLite
|
||||
createCol(prims, "Friction", typeof(Double));
|
||||
createCol(prims, "Restitution", typeof(Double));
|
||||
|
||||
createCol(prims, "KeyframeMotion", typeof(Byte[]));
|
||||
// Add in contraints
|
||||
prims.PrimaryKey = new DataColumn[] { prims.Columns["UUID"] };
|
||||
|
||||
@@ -1736,6 +1740,20 @@ namespace OpenSim.Data.SQLite
|
||||
prim.Friction = Convert.ToSingle(row["Friction"]);
|
||||
prim.Restitution = Convert.ToSingle(row["Restitution"]);
|
||||
|
||||
|
||||
if (!(row["KeyframeMotion"] is DBNull))
|
||||
{
|
||||
Byte[] data = (byte[])row["KeyframeMotion"];
|
||||
if (data.Length > 0)
|
||||
prim.KeyframeMotion = KeyframeMotion.FromData(null, data);
|
||||
else
|
||||
prim.KeyframeMotion = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
prim.KeyframeMotion = null;
|
||||
}
|
||||
|
||||
return prim;
|
||||
}
|
||||
|
||||
@@ -2158,7 +2176,7 @@ namespace OpenSim.Data.SQLite
|
||||
|
||||
row["MediaURL"] = prim.MediaUrl;
|
||||
|
||||
if (prim.DynAttrs.Count > 0)
|
||||
if (prim.DynAttrs.CountNamespaces > 0)
|
||||
row["DynAttrs"] = prim.DynAttrs.ToXml();
|
||||
else
|
||||
row["DynAttrs"] = null;
|
||||
@@ -2168,6 +2186,13 @@ namespace OpenSim.Data.SQLite
|
||||
row["GravityModifier"] = (double)prim.GravityModifier;
|
||||
row["Friction"] = (double)prim.Friction;
|
||||
row["Restitution"] = (double)prim.Restitution;
|
||||
|
||||
if (prim.KeyframeMotion != null)
|
||||
row["KeyframeMotion"] = prim.KeyframeMotion.Serialize();
|
||||
else
|
||||
row["KeyframeMotion"] = new Byte[0];
|
||||
|
||||
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
904
OpenSim/Data/SQLite/SQLiteUserProfilesData.cs
Normal file
904
OpenSim/Data/SQLite/SQLiteUserProfilesData.cs
Normal file
@@ -0,0 +1,904 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Reflection;
|
||||
using log4net;
|
||||
#if CSharpSqlite
|
||||
using Community.CsharpSqlite.Sqlite;
|
||||
#else
|
||||
using Mono.Data.Sqlite;
|
||||
#endif
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.StructuredData;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Region.Framework.Interfaces;
|
||||
|
||||
namespace OpenSim.Data.SQLite
|
||||
{
|
||||
public class SQLiteUserProfilesData: IProfilesData
|
||||
{
|
||||
private static readonly ILog m_log =
|
||||
LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private SqliteConnection m_connection;
|
||||
private string m_connectionString;
|
||||
|
||||
private FieldInfo[] m_Fields;
|
||||
private Dictionary<string, FieldInfo> m_FieldMap =
|
||||
new Dictionary<string, FieldInfo>();
|
||||
|
||||
protected virtual Assembly Assembly
|
||||
{
|
||||
get { return GetType().Assembly; }
|
||||
}
|
||||
|
||||
public SQLiteUserProfilesData()
|
||||
{
|
||||
}
|
||||
|
||||
public SQLiteUserProfilesData(string connectionString)
|
||||
{
|
||||
Initialise(connectionString);
|
||||
}
|
||||
|
||||
public void Initialise(string connectionString)
|
||||
{
|
||||
if (Util.IsWindows())
|
||||
Util.LoadArchSpecificWindowsDll("sqlite3.dll");
|
||||
|
||||
m_connectionString = connectionString;
|
||||
|
||||
m_log.Info("[PROFILES_DATA]: Sqlite - connecting: "+m_connectionString);
|
||||
|
||||
m_connection = new SqliteConnection(m_connectionString);
|
||||
m_connection.Open();
|
||||
|
||||
Migration m = new Migration(m_connection, Assembly, "UserProfiles");
|
||||
m.Update();
|
||||
}
|
||||
|
||||
private string[] FieldList
|
||||
{
|
||||
get { return new List<string>(m_FieldMap.Keys).ToArray(); }
|
||||
}
|
||||
|
||||
#region IProfilesData implementation
|
||||
public OSDArray GetClassifiedRecords(UUID creatorId)
|
||||
{
|
||||
OSDArray data = new OSDArray();
|
||||
string query = "SELECT classifieduuid, name FROM classifieds WHERE creatoruuid = :Id";
|
||||
IDataReader reader = null;
|
||||
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = query;
|
||||
cmd.Parameters.AddWithValue(":Id", creatorId);
|
||||
reader = cmd.ExecuteReader();
|
||||
}
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
OSDMap n = new OSDMap();
|
||||
UUID Id = UUID.Zero;
|
||||
string Name = null;
|
||||
try
|
||||
{
|
||||
UUID.TryParse(Convert.ToString( reader["classifieduuid"]), out Id);
|
||||
Name = Convert.ToString(reader["name"]);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": UserAccount exception {0}", e.Message);
|
||||
}
|
||||
n.Add("classifieduuid", OSD.FromUUID(Id));
|
||||
n.Add("name", OSD.FromString(Name));
|
||||
data.Add(n);
|
||||
}
|
||||
|
||||
reader.Close();
|
||||
|
||||
return data;
|
||||
}
|
||||
public bool UpdateClassifiedRecord(UserClassifiedAdd ad, ref string result)
|
||||
{
|
||||
string query = string.Empty;
|
||||
|
||||
query += "INSERT OR REPLACE INTO classifieds (";
|
||||
query += "`classifieduuid`,";
|
||||
query += "`creatoruuid`,";
|
||||
query += "`creationdate`,";
|
||||
query += "`expirationdate`,";
|
||||
query += "`category`,";
|
||||
query += "`name`,";
|
||||
query += "`description`,";
|
||||
query += "`parceluuid`,";
|
||||
query += "`parentestate`,";
|
||||
query += "`snapshotuuid`,";
|
||||
query += "`simname`,";
|
||||
query += "`posglobal`,";
|
||||
query += "`parcelname`,";
|
||||
query += "`classifiedflags`,";
|
||||
query += "`priceforlisting`) ";
|
||||
query += "VALUES (";
|
||||
query += ":ClassifiedId,";
|
||||
query += ":CreatorId,";
|
||||
query += ":CreatedDate,";
|
||||
query += ":ExpirationDate,";
|
||||
query += ":Category,";
|
||||
query += ":Name,";
|
||||
query += ":Description,";
|
||||
query += ":ParcelId,";
|
||||
query += ":ParentEstate,";
|
||||
query += ":SnapshotId,";
|
||||
query += ":SimName,";
|
||||
query += ":GlobalPos,";
|
||||
query += ":ParcelName,";
|
||||
query += ":Flags,";
|
||||
query += ":ListingPrice ) ";
|
||||
|
||||
if(string.IsNullOrEmpty(ad.ParcelName))
|
||||
ad.ParcelName = "Unknown";
|
||||
if(ad.ParcelId == null)
|
||||
ad.ParcelId = UUID.Zero;
|
||||
if(string.IsNullOrEmpty(ad.Description))
|
||||
ad.Description = "No Description";
|
||||
|
||||
DateTime epoch = new DateTime(1970, 1, 1);
|
||||
DateTime now = DateTime.Now;
|
||||
TimeSpan epochnow = now - epoch;
|
||||
TimeSpan duration;
|
||||
DateTime expiration;
|
||||
TimeSpan epochexp;
|
||||
|
||||
if(ad.Flags == 2)
|
||||
{
|
||||
duration = new TimeSpan(7,0,0,0);
|
||||
expiration = now.Add(duration);
|
||||
epochexp = expiration - epoch;
|
||||
}
|
||||
else
|
||||
{
|
||||
duration = new TimeSpan(365,0,0,0);
|
||||
expiration = now.Add(duration);
|
||||
epochexp = expiration - epoch;
|
||||
}
|
||||
ad.CreationDate = (int)epochnow.TotalSeconds;
|
||||
ad.ExpirationDate = (int)epochexp.TotalSeconds;
|
||||
|
||||
try {
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = query;
|
||||
cmd.Parameters.AddWithValue(":ClassifiedId", ad.ClassifiedId.ToString());
|
||||
cmd.Parameters.AddWithValue(":CreatorId", ad.CreatorId.ToString());
|
||||
cmd.Parameters.AddWithValue(":CreatedDate", ad.CreationDate.ToString());
|
||||
cmd.Parameters.AddWithValue(":ExpirationDate", ad.ExpirationDate.ToString());
|
||||
cmd.Parameters.AddWithValue(":Category", ad.Category.ToString());
|
||||
cmd.Parameters.AddWithValue(":Name", ad.Name.ToString());
|
||||
cmd.Parameters.AddWithValue(":Description", ad.Description.ToString());
|
||||
cmd.Parameters.AddWithValue(":ParcelId", ad.ParcelId.ToString());
|
||||
cmd.Parameters.AddWithValue(":ParentEstate", ad.ParentEstate.ToString());
|
||||
cmd.Parameters.AddWithValue(":SnapshotId", ad.SnapshotId.ToString ());
|
||||
cmd.Parameters.AddWithValue(":SimName", ad.SimName.ToString());
|
||||
cmd.Parameters.AddWithValue(":GlobalPos", ad.GlobalPos.ToString());
|
||||
cmd.Parameters.AddWithValue(":ParcelName", ad.ParcelName.ToString());
|
||||
cmd.Parameters.AddWithValue(":Flags", ad.Flags.ToString());
|
||||
cmd.Parameters.AddWithValue(":ListingPrice", ad.Price.ToString ());
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": ClassifiedesUpdate exception {0}", e.Message);
|
||||
result = e.Message;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public bool DeleteClassifiedRecord(UUID recordId)
|
||||
{
|
||||
string query = string.Empty;
|
||||
|
||||
query += "DELETE FROM classifieds WHERE ";
|
||||
query += "classifieduuid = :ClasifiedId";
|
||||
|
||||
try
|
||||
{
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = query;
|
||||
cmd.Parameters.AddWithValue(":ClassifiedId", recordId.ToString());
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": DeleteClassifiedRecord exception {0}", e.Message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool GetClassifiedInfo(ref UserClassifiedAdd ad, ref string result)
|
||||
{
|
||||
IDataReader reader = null;
|
||||
string query = string.Empty;
|
||||
|
||||
query += "SELECT * FROM classifieds WHERE ";
|
||||
query += "classifieduuid = :AdId";
|
||||
|
||||
try
|
||||
{
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = query;
|
||||
cmd.Parameters.AddWithValue(":AdId", ad.ClassifiedId.ToString());
|
||||
|
||||
using (reader = cmd.ExecuteReader())
|
||||
{
|
||||
if(reader.Read ())
|
||||
{
|
||||
ad.CreatorId = new UUID(reader["creatoruuid"].ToString());
|
||||
ad.ParcelId = new UUID(reader["parceluuid"].ToString ());
|
||||
ad.SnapshotId = new UUID(reader["snapshotuuid"].ToString ());
|
||||
ad.CreationDate = Convert.ToInt32(reader["creationdate"]);
|
||||
ad.ExpirationDate = Convert.ToInt32(reader["expirationdate"]);
|
||||
ad.ParentEstate = Convert.ToInt32(reader["parentestate"]);
|
||||
ad.Flags = (byte) Convert.ToUInt32(reader["classifiedflags"]);
|
||||
ad.Category = Convert.ToInt32(reader["category"]);
|
||||
ad.Price = Convert.ToInt16(reader["priceforlisting"]);
|
||||
ad.Name = reader["name"].ToString();
|
||||
ad.Description = reader["description"].ToString();
|
||||
ad.SimName = reader["simname"].ToString();
|
||||
ad.GlobalPos = reader["posglobal"].ToString();
|
||||
ad.ParcelName = reader["parcelname"].ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": GetPickInfo exception {0}", e.Message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public OSDArray GetAvatarPicks(UUID avatarId)
|
||||
{
|
||||
IDataReader reader = null;
|
||||
string query = string.Empty;
|
||||
|
||||
query += "SELECT `pickuuid`,`name` FROM userpicks WHERE ";
|
||||
query += "creatoruuid = :Id";
|
||||
OSDArray data = new OSDArray();
|
||||
|
||||
try
|
||||
{
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = query;
|
||||
cmd.Parameters.AddWithValue(":Id", avatarId.ToString());
|
||||
|
||||
using (reader = cmd.ExecuteReader())
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
OSDMap record = new OSDMap();
|
||||
|
||||
record.Add("pickuuid",OSD.FromString((string)reader["pickuuid"]));
|
||||
record.Add("name",OSD.FromString((string)reader["name"]));
|
||||
data.Add(record);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": GetAvatarPicks exception {0}", e.Message);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
public UserProfilePick GetPickInfo(UUID avatarId, UUID pickId)
|
||||
{
|
||||
IDataReader reader = null;
|
||||
string query = string.Empty;
|
||||
UserProfilePick pick = new UserProfilePick();
|
||||
|
||||
query += "SELECT * FROM userpicks WHERE ";
|
||||
query += "creatoruuid = :CreatorId AND ";
|
||||
query += "pickuuid = :PickId";
|
||||
|
||||
try
|
||||
{
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = query;
|
||||
cmd.Parameters.AddWithValue(":CreatorId", avatarId.ToString());
|
||||
cmd.Parameters.AddWithValue(":PickId", pickId.ToString());
|
||||
|
||||
using (reader = cmd.ExecuteReader())
|
||||
{
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
string description = (string)reader["description"];
|
||||
|
||||
if (string.IsNullOrEmpty(description))
|
||||
description = "No description given.";
|
||||
|
||||
UUID.TryParse((string)reader["pickuuid"], out pick.PickId);
|
||||
UUID.TryParse((string)reader["creatoruuid"], out pick.CreatorId);
|
||||
UUID.TryParse((string)reader["parceluuid"], out pick.ParcelId);
|
||||
UUID.TryParse((string)reader["snapshotuuid"], out pick.SnapshotId);
|
||||
pick.GlobalPos = (string)reader["posglobal"];
|
||||
bool.TryParse((string)reader["toppick"].ToString(), out pick.TopPick);
|
||||
bool.TryParse((string)reader["enabled"].ToString(), out pick.Enabled);
|
||||
pick.Name = (string)reader["name"];
|
||||
pick.Desc = description;
|
||||
pick.User = (string)reader["user"];
|
||||
pick.OriginalName = (string)reader["originalname"];
|
||||
pick.SimName = (string)reader["simname"];
|
||||
pick.SortOrder = (int)reader["sortorder"];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": GetPickInfo exception {0}", e.Message);
|
||||
}
|
||||
return pick;
|
||||
}
|
||||
|
||||
public bool UpdatePicksRecord(UserProfilePick pick)
|
||||
{
|
||||
string query = string.Empty;
|
||||
|
||||
query += "INSERT OR REPLACE INTO userpicks (";
|
||||
query += "pickuuid, ";
|
||||
query += "creatoruuid, ";
|
||||
query += "toppick, ";
|
||||
query += "parceluuid, ";
|
||||
query += "name, ";
|
||||
query += "description, ";
|
||||
query += "snapshotuuid, ";
|
||||
query += "user, ";
|
||||
query += "originalname, ";
|
||||
query += "simname, ";
|
||||
query += "posglobal, ";
|
||||
query += "sortorder, ";
|
||||
query += "enabled ) ";
|
||||
query += "VALUES (";
|
||||
query += ":PickId,";
|
||||
query += ":CreatorId,";
|
||||
query += ":TopPick,";
|
||||
query += ":ParcelId,";
|
||||
query += ":Name,";
|
||||
query += ":Desc,";
|
||||
query += ":SnapshotId,";
|
||||
query += ":User,";
|
||||
query += ":Original,";
|
||||
query += ":SimName,";
|
||||
query += ":GlobalPos,";
|
||||
query += ":SortOrder,";
|
||||
query += ":Enabled) ";
|
||||
|
||||
try
|
||||
{
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
int top_pick;
|
||||
int.TryParse(pick.TopPick.ToString(), out top_pick);
|
||||
int enabled;
|
||||
int.TryParse(pick.Enabled.ToString(), out enabled);
|
||||
|
||||
cmd.CommandText = query;
|
||||
cmd.Parameters.AddWithValue(":PickId", pick.PickId.ToString());
|
||||
cmd.Parameters.AddWithValue(":CreatorId", pick.CreatorId.ToString());
|
||||
cmd.Parameters.AddWithValue(":TopPick", top_pick);
|
||||
cmd.Parameters.AddWithValue(":ParcelId", pick.ParcelId.ToString());
|
||||
cmd.Parameters.AddWithValue(":Name", pick.Name.ToString());
|
||||
cmd.Parameters.AddWithValue(":Desc", pick.Desc.ToString());
|
||||
cmd.Parameters.AddWithValue(":SnapshotId", pick.SnapshotId.ToString());
|
||||
cmd.Parameters.AddWithValue(":User", pick.User.ToString());
|
||||
cmd.Parameters.AddWithValue(":Original", pick.OriginalName.ToString());
|
||||
cmd.Parameters.AddWithValue(":SimName",pick.SimName.ToString());
|
||||
cmd.Parameters.AddWithValue(":GlobalPos", pick.GlobalPos);
|
||||
cmd.Parameters.AddWithValue(":SortOrder", pick.SortOrder.ToString ());
|
||||
cmd.Parameters.AddWithValue(":Enabled", enabled);
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": UpdateAvatarNotes exception {0}", e.Message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool DeletePicksRecord(UUID pickId)
|
||||
{
|
||||
string query = string.Empty;
|
||||
|
||||
query += "DELETE FROM userpicks WHERE ";
|
||||
query += "pickuuid = :PickId";
|
||||
|
||||
try
|
||||
{
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = query;
|
||||
cmd.Parameters.AddWithValue(":PickId", pickId.ToString());
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": DeleteUserPickRecord exception {0}", e.Message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool GetAvatarNotes(ref UserProfileNotes notes)
|
||||
{
|
||||
IDataReader reader = null;
|
||||
string query = string.Empty;
|
||||
|
||||
query += "SELECT `notes` FROM usernotes WHERE ";
|
||||
query += "useruuid = :Id AND ";
|
||||
query += "targetuuid = :TargetId";
|
||||
OSDArray data = new OSDArray();
|
||||
|
||||
try
|
||||
{
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = query;
|
||||
cmd.Parameters.AddWithValue(":Id", notes.UserId.ToString());
|
||||
cmd.Parameters.AddWithValue(":TargetId", notes.TargetId.ToString());
|
||||
|
||||
using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
|
||||
{
|
||||
while (reader.Read())
|
||||
{
|
||||
notes.Notes = OSD.FromString((string)reader["notes"]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": GetAvatarNotes exception {0}", e.Message);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool UpdateAvatarNotes(ref UserProfileNotes note, ref string result)
|
||||
{
|
||||
string query = string.Empty;
|
||||
bool remove;
|
||||
|
||||
if(string.IsNullOrEmpty(note.Notes))
|
||||
{
|
||||
remove = true;
|
||||
query += "DELETE FROM usernotes WHERE ";
|
||||
query += "useruuid=:UserId AND ";
|
||||
query += "targetuuid=:TargetId";
|
||||
}
|
||||
else
|
||||
{
|
||||
remove = false;
|
||||
query += "INSERT OR REPLACE INTO usernotes VALUES ( ";
|
||||
query += ":UserId,";
|
||||
query += ":TargetId,";
|
||||
query += ":Notes )";
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = query;
|
||||
|
||||
if(!remove)
|
||||
cmd.Parameters.AddWithValue(":Notes", note.Notes);
|
||||
cmd.Parameters.AddWithValue(":TargetId", note.TargetId.ToString ());
|
||||
cmd.Parameters.AddWithValue(":UserId", note.UserId.ToString());
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": UpdateAvatarNotes exception {0}", e.Message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool GetAvatarProperties(ref UserProfileProperties props, ref string result)
|
||||
{
|
||||
IDataReader reader = null;
|
||||
string query = string.Empty;
|
||||
|
||||
query += "SELECT * FROM userprofile WHERE ";
|
||||
query += "useruuid = :Id";
|
||||
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = query;
|
||||
cmd.Parameters.AddWithValue(":Id", props.UserId.ToString());
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
reader = cmd.ExecuteReader();
|
||||
}
|
||||
catch(Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": GetAvatarProperties exception {0}", e.Message);
|
||||
result = e.Message;
|
||||
return false;
|
||||
}
|
||||
if(reader != null && reader.Read())
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": Getting data for {0}.", props.UserId);
|
||||
|
||||
props.WebUrl = (string)reader["profileURL"];
|
||||
UUID.TryParse((string)reader["profileImage"], out props.ImageId);
|
||||
props.AboutText = (string)reader["profileAboutText"];
|
||||
UUID.TryParse((string)reader["profileFirstImage"], out props.FirstLifeImageId);
|
||||
props.FirstLifeText = (string)reader["profileFirstText"];
|
||||
UUID.TryParse((string)reader["profilePartner"], out props.PartnerId);
|
||||
props.WantToMask = (int)reader["profileWantToMask"];
|
||||
props.WantToText = (string)reader["profileWantToText"];
|
||||
props.SkillsMask = (int)reader["profileSkillsMask"];
|
||||
props.SkillsText = (string)reader["profileSkillsText"];
|
||||
props.Language = (string)reader["profileLanguages"];
|
||||
}
|
||||
else
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": No data for {0}", props.UserId);
|
||||
|
||||
props.WebUrl = string.Empty;
|
||||
props.ImageId = UUID.Zero;
|
||||
props.AboutText = string.Empty;
|
||||
props.FirstLifeImageId = UUID.Zero;
|
||||
props.FirstLifeText = string.Empty;
|
||||
props.PartnerId = UUID.Zero;
|
||||
props.WantToMask = 0;
|
||||
props.WantToText = string.Empty;
|
||||
props.SkillsMask = 0;
|
||||
props.SkillsText = string.Empty;
|
||||
props.Language = string.Empty;
|
||||
props.PublishProfile = false;
|
||||
props.PublishMature = false;
|
||||
|
||||
query = "INSERT INTO userprofile (";
|
||||
query += "useruuid, ";
|
||||
query += "profilePartner, ";
|
||||
query += "profileAllowPublish, ";
|
||||
query += "profileMaturePublish, ";
|
||||
query += "profileURL, ";
|
||||
query += "profileWantToMask, ";
|
||||
query += "profileWantToText, ";
|
||||
query += "profileSkillsMask, ";
|
||||
query += "profileSkillsText, ";
|
||||
query += "profileLanguages, ";
|
||||
query += "profileImage, ";
|
||||
query += "profileAboutText, ";
|
||||
query += "profileFirstImage, ";
|
||||
query += "profileFirstText) VALUES (";
|
||||
query += ":userId, ";
|
||||
query += ":profilePartner, ";
|
||||
query += ":profileAllowPublish, ";
|
||||
query += ":profileMaturePublish, ";
|
||||
query += ":profileURL, ";
|
||||
query += ":profileWantToMask, ";
|
||||
query += ":profileWantToText, ";
|
||||
query += ":profileSkillsMask, ";
|
||||
query += ":profileSkillsText, ";
|
||||
query += ":profileLanguages, ";
|
||||
query += ":profileImage, ";
|
||||
query += ":profileAboutText, ";
|
||||
query += ":profileFirstImage, ";
|
||||
query += ":profileFirstText)";
|
||||
|
||||
using (SqliteCommand put = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
put.CommandText = query;
|
||||
put.Parameters.AddWithValue(":userId", props.UserId.ToString());
|
||||
put.Parameters.AddWithValue(":profilePartner", props.PartnerId.ToString());
|
||||
put.Parameters.AddWithValue(":profileAllowPublish", props.PublishProfile);
|
||||
put.Parameters.AddWithValue(":profileMaturePublish", props.PublishMature);
|
||||
put.Parameters.AddWithValue(":profileURL", props.WebUrl);
|
||||
put.Parameters.AddWithValue(":profileWantToMask", props.WantToMask);
|
||||
put.Parameters.AddWithValue(":profileWantToText", props.WantToText);
|
||||
put.Parameters.AddWithValue(":profileSkillsMask", props.SkillsMask);
|
||||
put.Parameters.AddWithValue(":profileSkillsText", props.SkillsText);
|
||||
put.Parameters.AddWithValue(":profileLanguages", props.Language);
|
||||
put.Parameters.AddWithValue(":profileImage", props.ImageId.ToString());
|
||||
put.Parameters.AddWithValue(":profileAboutText", props.AboutText);
|
||||
put.Parameters.AddWithValue(":profileFirstImage", props.FirstLifeImageId.ToString());
|
||||
put.Parameters.AddWithValue(":profileFirstText", props.FirstLifeText);
|
||||
|
||||
put.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool UpdateAvatarProperties(ref UserProfileProperties props, ref string result)
|
||||
{
|
||||
string query = string.Empty;
|
||||
|
||||
query += "UPDATE userprofile SET ";
|
||||
query += "profilePartner=:profilePartner, ";
|
||||
query += "profileURL=:profileURL, ";
|
||||
query += "profileImage=:image, ";
|
||||
query += "profileAboutText=:abouttext,";
|
||||
query += "profileFirstImage=:firstlifeimage,";
|
||||
query += "profileFirstText=:firstlifetext ";
|
||||
query += "WHERE useruuid=:uuid";
|
||||
|
||||
try
|
||||
{
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = query;
|
||||
cmd.Parameters.AddWithValue(":profileURL", props.WebUrl);
|
||||
cmd.Parameters.AddWithValue(":profilePartner", props.PartnerId.ToString());
|
||||
cmd.Parameters.AddWithValue(":image", props.ImageId.ToString());
|
||||
cmd.Parameters.AddWithValue(":abouttext", props.AboutText);
|
||||
cmd.Parameters.AddWithValue(":firstlifeimage", props.FirstLifeImageId.ToString());
|
||||
cmd.Parameters.AddWithValue(":firstlifetext", props.FirstLifeText);
|
||||
cmd.Parameters.AddWithValue(":uuid", props.UserId.ToString());
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": AgentPropertiesUpdate exception {0}", e.Message);
|
||||
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool UpdateAvatarInterests(UserProfileProperties up, ref string result)
|
||||
{
|
||||
string query = string.Empty;
|
||||
|
||||
query += "UPDATE userprofile SET ";
|
||||
query += "profileWantToMask=:WantMask, ";
|
||||
query += "profileWantToText=:WantText,";
|
||||
query += "profileSkillsMask=:SkillsMask,";
|
||||
query += "profileSkillsText=:SkillsText, ";
|
||||
query += "profileLanguages=:Languages ";
|
||||
query += "WHERE useruuid=:uuid";
|
||||
|
||||
try
|
||||
{
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = query;
|
||||
cmd.Parameters.AddWithValue(":WantMask", up.WantToMask);
|
||||
cmd.Parameters.AddWithValue(":WantText", up.WantToText);
|
||||
cmd.Parameters.AddWithValue(":SkillsMask", up.SkillsMask);
|
||||
cmd.Parameters.AddWithValue(":SkillsText", up.SkillsText);
|
||||
cmd.Parameters.AddWithValue(":Languages", up.Language);
|
||||
cmd.Parameters.AddWithValue(":uuid", up.UserId.ToString());
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": AgentInterestsUpdate exception {0}", e.Message);
|
||||
result = e.Message;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public bool GetUserAppData(ref UserAppData props, ref string result)
|
||||
{
|
||||
IDataReader reader = null;
|
||||
string query = string.Empty;
|
||||
|
||||
query += "SELECT * FROM `userdata` WHERE ";
|
||||
query += "UserId = :Id AND ";
|
||||
query += "TagId = :TagId";
|
||||
|
||||
try
|
||||
{
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = query;
|
||||
cmd.Parameters.AddWithValue(":Id", props.UserId.ToString());
|
||||
cmd.Parameters.AddWithValue (":TagId", props.TagId.ToString());
|
||||
|
||||
using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
|
||||
{
|
||||
if(reader.Read())
|
||||
{
|
||||
props.DataKey = (string)reader["DataKey"];
|
||||
props.DataVal = (string)reader["DataVal"];
|
||||
}
|
||||
else
|
||||
{
|
||||
query += "INSERT INTO userdata VALUES ( ";
|
||||
query += ":UserId,";
|
||||
query += ":TagId,";
|
||||
query += ":DataKey,";
|
||||
query += ":DataVal) ";
|
||||
|
||||
using (SqliteCommand put = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
put.Parameters.AddWithValue(":Id", props.UserId.ToString());
|
||||
put.Parameters.AddWithValue(":TagId", props.TagId.ToString());
|
||||
put.Parameters.AddWithValue(":DataKey", props.DataKey.ToString());
|
||||
put.Parameters.AddWithValue(":DataVal", props.DataVal.ToString());
|
||||
|
||||
put.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": Requst application data exception {0}", e.Message);
|
||||
result = e.Message;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public bool SetUserAppData(UserAppData props, ref string result)
|
||||
{
|
||||
string query = string.Empty;
|
||||
|
||||
query += "UPDATE userdata SET ";
|
||||
query += "TagId = :TagId, ";
|
||||
query += "DataKey = :DataKey, ";
|
||||
query += "DataVal = :DataVal WHERE ";
|
||||
query += "UserId = :UserId AND ";
|
||||
query += "TagId = :TagId";
|
||||
|
||||
try
|
||||
{
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = query;
|
||||
cmd.Parameters.AddWithValue(":UserId", props.UserId.ToString());
|
||||
cmd.Parameters.AddWithValue(":TagId", props.TagId.ToString ());
|
||||
cmd.Parameters.AddWithValue(":DataKey", props.DataKey.ToString ());
|
||||
cmd.Parameters.AddWithValue(":DataVal", props.DataKey.ToString ());
|
||||
|
||||
cmd.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": SetUserData exception {0}", e.Message);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
public OSDArray GetUserImageAssets(UUID avatarId)
|
||||
{
|
||||
IDataReader reader = null;
|
||||
OSDArray data = new OSDArray();
|
||||
string query = "SELECT `snapshotuuid` FROM {0} WHERE `creatoruuid` = :Id";
|
||||
|
||||
// Get classified image assets
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = query;
|
||||
cmd.Parameters.AddWithValue(":Id", avatarId.ToString());
|
||||
|
||||
using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
|
||||
{
|
||||
while(reader.Read())
|
||||
{
|
||||
data.Add(new OSDString((string)reader["snapshotuuid"].ToString()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = query;
|
||||
cmd.Parameters.AddWithValue(":Id", avatarId.ToString());
|
||||
|
||||
using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
|
||||
{
|
||||
if(reader.Read())
|
||||
{
|
||||
data.Add(new OSDString((string)reader["snapshotuuid"].ToString ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query = "SELECT `profileImage`, `profileFirstImage` FROM `userprofile` WHERE `useruuid` = :Id";
|
||||
|
||||
using (SqliteCommand cmd = (SqliteCommand)m_connection.CreateCommand())
|
||||
{
|
||||
cmd.CommandText = query;
|
||||
cmd.Parameters.AddWithValue(":Id", avatarId.ToString());
|
||||
|
||||
using (reader = cmd.ExecuteReader(CommandBehavior.SingleRow))
|
||||
{
|
||||
if(reader.Read())
|
||||
{
|
||||
data.Add(new OSDString((string)reader["profileImage"].ToString ()));
|
||||
data.Add(new OSDString((string)reader["profileFirstImage"].ToString ()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.DebugFormat("[PROFILES_DATA]" +
|
||||
": GetAvatarNotes exception {0}", e.Message);
|
||||
}
|
||||
return data;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,5 +120,24 @@ namespace OpenSim.Framework
|
||||
sequenceNum = args["seq_num"].AsInteger();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
Animation other = obj as Animation;
|
||||
if (other != null)
|
||||
{
|
||||
return (other.AnimID.Equals(this.AnimID)
|
||||
&& other.SequenceNum == this.SequenceNum
|
||||
&& other.ObjectID.Equals(this.ObjectID) );
|
||||
}
|
||||
return base.Equals(obj);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "AnimID=" + AnimID.ToString()
|
||||
+ "/seq=" + SequenceNum.ToString()
|
||||
+ "/objID=" + ObjectID.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,6 +53,7 @@ namespace OpenSim.Framework
|
||||
protected AvatarWearable[] m_wearables;
|
||||
protected Dictionary<int, List<AvatarAttachment>> m_attachments;
|
||||
protected float m_avatarHeight = 0;
|
||||
protected UUID[] m_texturehashes;
|
||||
|
||||
public virtual int Serial
|
||||
{
|
||||
@@ -98,6 +99,8 @@ namespace OpenSim.Framework
|
||||
SetDefaultParams();
|
||||
SetHeight();
|
||||
m_attachments = new Dictionary<int, List<AvatarAttachment>>();
|
||||
|
||||
ResetTextureHashes();
|
||||
}
|
||||
|
||||
public AvatarAppearance(OSDMap map)
|
||||
@@ -108,32 +111,6 @@ namespace OpenSim.Framework
|
||||
SetHeight();
|
||||
}
|
||||
|
||||
public AvatarAppearance(AvatarWearable[] wearables, Primitive.TextureEntry textureEntry, byte[] visualParams)
|
||||
{
|
||||
// m_log.WarnFormat("[AVATAR APPEARANCE] create initialized appearance");
|
||||
|
||||
m_serial = 0;
|
||||
|
||||
if (wearables != null)
|
||||
m_wearables = wearables;
|
||||
else
|
||||
SetDefaultWearables();
|
||||
|
||||
if (textureEntry != null)
|
||||
m_texture = textureEntry;
|
||||
else
|
||||
SetDefaultTexture();
|
||||
|
||||
if (visualParams != null)
|
||||
m_visualparams = visualParams;
|
||||
else
|
||||
SetDefaultParams();
|
||||
|
||||
SetHeight();
|
||||
|
||||
m_attachments = new Dictionary<int, List<AvatarAttachment>>();
|
||||
}
|
||||
|
||||
public AvatarAppearance(AvatarAppearance appearance) : this(appearance, true)
|
||||
{
|
||||
}
|
||||
@@ -151,6 +128,8 @@ namespace OpenSim.Framework
|
||||
SetHeight();
|
||||
m_attachments = new Dictionary<int, List<AvatarAttachment>>();
|
||||
|
||||
ResetTextureHashes();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -166,6 +145,10 @@ namespace OpenSim.Framework
|
||||
SetWearable(i,appearance.Wearables[i]);
|
||||
}
|
||||
|
||||
m_texturehashes = new UUID[AvatarAppearance.TEXTURE_COUNT];
|
||||
for (int i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++)
|
||||
m_texturehashes[i] = new UUID(appearance.m_texturehashes[i]);
|
||||
|
||||
m_texture = null;
|
||||
if (appearance.Texture != null)
|
||||
{
|
||||
@@ -200,6 +183,37 @@ namespace OpenSim.Framework
|
||||
}
|
||||
}
|
||||
|
||||
public void ResetTextureHashes()
|
||||
{
|
||||
m_texturehashes = new UUID[AvatarAppearance.TEXTURE_COUNT];
|
||||
for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++)
|
||||
m_texturehashes[i] = UUID.Zero;
|
||||
}
|
||||
|
||||
public UUID GetTextureHash(int textureIndex)
|
||||
{
|
||||
return m_texturehashes[NormalizeBakedTextureIndex(textureIndex)];
|
||||
}
|
||||
|
||||
public void SetTextureHash(int textureIndex, UUID textureHash)
|
||||
{
|
||||
m_texturehashes[NormalizeBakedTextureIndex(textureIndex)] = new UUID(textureHash);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Normalizes the texture index to the actual bake index, this is done to
|
||||
/// accommodate older viewers that send the BAKE_INDICES index rather than
|
||||
/// the actual texture index
|
||||
/// </summary>
|
||||
private int NormalizeBakedTextureIndex(int textureIndex)
|
||||
{
|
||||
// Earlier viewer send the index into the baked index array, just trying to be careful here
|
||||
if (textureIndex < BAKE_INDICES.Length)
|
||||
return BAKE_INDICES[textureIndex];
|
||||
|
||||
return textureIndex;
|
||||
}
|
||||
|
||||
public void ClearWearables()
|
||||
{
|
||||
m_wearables = new AvatarWearable[AvatarWearable.MAX_WEARABLES];
|
||||
@@ -223,12 +237,7 @@ namespace OpenSim.Framework
|
||||
m_serial = 0;
|
||||
|
||||
SetDefaultTexture();
|
||||
|
||||
//for (int i = 0; i < BAKE_INDICES.Length; i++)
|
||||
// {
|
||||
// int idx = BAKE_INDICES[i];
|
||||
// m_texture.FaceTextures[idx].TextureID = UUID.Zero;
|
||||
// }
|
||||
ResetTextureHashes();
|
||||
}
|
||||
|
||||
protected virtual void SetDefaultParams()
|
||||
@@ -459,45 +468,59 @@ namespace OpenSim.Framework
|
||||
if (attachpoint == 0)
|
||||
return false;
|
||||
|
||||
if (item == UUID.Zero)
|
||||
lock (m_attachments)
|
||||
{
|
||||
lock (m_attachments)
|
||||
if (item == UUID.Zero)
|
||||
{
|
||||
if (m_attachments.ContainsKey(attachpoint))
|
||||
{
|
||||
m_attachments.Remove(attachpoint);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// When a user logs in, the attachment item ids are pulled from persistence in the Avatars table. However,
|
||||
// the asset ids are not saved. When the avatar enters a simulator the attachments are set again. If
|
||||
// we simply perform an item check here then the asset ids (which are now present) are never set, and NPC attachments
|
||||
// later fail unless the attachment is detached and reattached.
|
||||
//
|
||||
// Therefore, we will carry on with the set if the existing attachment has no asset id.
|
||||
AvatarAttachment existingAttachment = GetAttachmentForItem(item);
|
||||
if (existingAttachment != null)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[AVATAR APPEARANCE]: Found existing attachment for {0}, asset {1} at point {2}",
|
||||
// existingAttachment.ItemID, existingAttachment.AssetID, existingAttachment.AttachPoint);
|
||||
|
||||
if (existingAttachment.AssetID != UUID.Zero && existingAttachment.AttachPoint == (attachpoint & 0x7F))
|
||||
{
|
||||
m_log.DebugFormat(
|
||||
"[AVATAR APPEARANCE]: Ignoring attempt to attach an already attached item {0} at point {1}",
|
||||
item, attachpoint);
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remove it here so that the later append does not add a second attachment but we still update
|
||||
// the assetID
|
||||
DetachAttachment(existingAttachment.ItemID);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// When a user logs in, the attachment item ids are pulled from persistence in the Avatars table. However,
|
||||
// the asset ids are not saved. When the avatar enters a simulator the attachments are set again. If
|
||||
// we simply perform an item check here then the asset ids (which are now present) are never set, and NPC attachments
|
||||
// later fail unless the attachment is detached and reattached.
|
||||
//
|
||||
// Therefore, we will carry on with the set if the existing attachment has no asset id.
|
||||
AvatarAttachment existingAttachment = GetAttachmentForItem(item);
|
||||
if (existingAttachment != null
|
||||
&& existingAttachment.AssetID != UUID.Zero
|
||||
&& existingAttachment.AttachPoint == (attachpoint & 0x7F))
|
||||
{
|
||||
// m_log.DebugFormat("[AVATAR APPEARANCE] attempt to attach an already attached item {0}",item);
|
||||
return false;
|
||||
}
|
||||
|
||||
// check if this is an append or a replace, 0x80 marks it as an append
|
||||
if ((attachpoint & 0x80) > 0)
|
||||
{
|
||||
// strip the append bit
|
||||
int point = attachpoint & 0x7F;
|
||||
AppendAttachment(new AvatarAttachment(point, item, asset));
|
||||
}
|
||||
else
|
||||
{
|
||||
ReplaceAttachment(new AvatarAttachment(attachpoint,item, asset));
|
||||
// check if this is an append or a replace, 0x80 marks it as an append
|
||||
if ((attachpoint & 0x80) > 0)
|
||||
{
|
||||
// strip the append bit
|
||||
int point = attachpoint & 0x7F;
|
||||
AppendAttachment(new AvatarAttachment(point, item, asset));
|
||||
}
|
||||
else
|
||||
{
|
||||
ReplaceAttachment(new AvatarAttachment(attachpoint,item, asset));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -547,6 +570,10 @@ namespace OpenSim.Framework
|
||||
int index = kvp.Value.FindIndex(delegate(AvatarAttachment a) { return a.ItemID == itemID; });
|
||||
if (index >= 0)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[AVATAR APPEARANCE]: Detaching attachment {0}, index {1}, point {2}",
|
||||
// m_attachments[kvp.Key][index].ItemID, index, m_attachments[kvp.Key][index].AttachPoint);
|
||||
|
||||
// Remove it from the list of attachments at that attach point
|
||||
m_attachments[kvp.Key].RemoveAt(index);
|
||||
|
||||
@@ -580,6 +607,12 @@ namespace OpenSim.Framework
|
||||
data["serial"] = OSD.FromInteger(m_serial);
|
||||
data["height"] = OSD.FromReal(m_avatarHeight);
|
||||
|
||||
// Hashes
|
||||
OSDArray hashes = new OSDArray(AvatarAppearance.TEXTURE_COUNT);
|
||||
for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++)
|
||||
hashes.Add(OSD.FromUUID(m_texturehashes[i]));
|
||||
data["hashes"] = hashes;
|
||||
|
||||
// Wearables
|
||||
OSDArray wears = new OSDArray(AvatarWearable.MAX_WEARABLES);
|
||||
for (int i = 0; i < AvatarWearable.MAX_WEARABLES; i++)
|
||||
@@ -624,6 +657,25 @@ namespace OpenSim.Framework
|
||||
|
||||
try
|
||||
{
|
||||
// Hashes
|
||||
m_texturehashes = new UUID[AvatarAppearance.TEXTURE_COUNT];
|
||||
if ((data != null) && (data["hashes"] != null) && (data["hashes"]).Type == OSDType.Array)
|
||||
{
|
||||
OSDArray hashes = (OSDArray)(data["hashes"]);
|
||||
for (int i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++)
|
||||
{
|
||||
UUID hashID = UUID.Zero;
|
||||
if (i < hashes.Count && hashes[i] != null)
|
||||
hashID = hashes[i].AsUUID();
|
||||
m_texturehashes[i] = hashID;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (uint i = 0; i < AvatarAppearance.TEXTURE_COUNT; i++)
|
||||
m_texturehashes[i] = UUID.Zero;
|
||||
}
|
||||
|
||||
// Wearables
|
||||
SetDefaultWearables();
|
||||
if ((data != null) && (data["wearables"] != null) && (data["wearables"]).Type == OSDType.Array)
|
||||
|
||||
@@ -25,19 +25,22 @@
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Inventory
|
||||
{
|
||||
/// <summary>
|
||||
/// This interface represents the boundary between the general purpose
|
||||
/// REST plugin handling, and the functionally specific handlers. The
|
||||
/// handler knows only to initialize and terminate all such handlers
|
||||
/// that it finds. Implementing this interface identifies the class as
|
||||
/// a REST handler implementation.
|
||||
/// </summary>
|
||||
using System;
|
||||
using System.Text;
|
||||
using OpenMetaverse;
|
||||
|
||||
internal interface IRest
|
||||
namespace OpenSim.Framework
|
||||
{
|
||||
public class CachedTextureRequestArg
|
||||
{
|
||||
void Initialize();
|
||||
void Close();
|
||||
public int BakedTextureIndex;
|
||||
public UUID WearableHashID;
|
||||
}
|
||||
|
||||
public class CachedTextureResponseArg
|
||||
{
|
||||
public int BakedTextureIndex;
|
||||
public UUID BakedTextureID;
|
||||
public String HostName;
|
||||
}
|
||||
}
|
||||
@@ -171,9 +171,10 @@ namespace OpenSim.Framework
|
||||
/// Soon to be decommissioned
|
||||
/// </summary>
|
||||
/// <param name="cAgent"></param>
|
||||
public void CopyFrom(ChildAgentDataUpdate cAgent)
|
||||
public void CopyFrom(ChildAgentDataUpdate cAgent, UUID sid)
|
||||
{
|
||||
AgentID = new UUID(cAgent.AgentID);
|
||||
SessionID = sid;
|
||||
|
||||
// next: ???
|
||||
Size = new Vector3();
|
||||
|
||||
@@ -33,12 +33,13 @@ namespace OpenSim.Framework
|
||||
{
|
||||
public class ClientInfo
|
||||
{
|
||||
public AgentCircuitData agentcircuit;
|
||||
public readonly DateTime StartedTime = DateTime.Now;
|
||||
public AgentCircuitData agentcircuit = null;
|
||||
|
||||
public Dictionary<uint, byte[]> needAck;
|
||||
|
||||
public List<byte[]> out_packets;
|
||||
public Dictionary<uint, uint> pendingAcks;
|
||||
public List<byte[]> out_packets = new List<byte[]>();
|
||||
public Dictionary<uint, uint> pendingAcks = new Dictionary<uint,uint>();
|
||||
public EndPoint proxyEP;
|
||||
|
||||
public uint sequence;
|
||||
@@ -53,5 +54,9 @@ namespace OpenSim.Framework
|
||||
public int assetThrottle;
|
||||
public int textureThrottle;
|
||||
public int totalThrottle;
|
||||
|
||||
public Dictionary<string, int> SyncRequests = new Dictionary<string,int>();
|
||||
public Dictionary<string, int> AsyncRequests = new Dictionary<string,int>();
|
||||
public Dictionary<string, int> GenericRequests = new Dictionary<string,int>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,6 +420,21 @@ namespace OpenSim.Framework.Console
|
||||
SetCursorLeft(0);
|
||||
m_cursorYPosition = SetCursorTop(m_cursorYPosition);
|
||||
|
||||
if (m_echo)
|
||||
System.Console.Write("{0}{1} ", prompt, m_commandLine);
|
||||
else
|
||||
System.Console.Write("{0}", prompt);
|
||||
|
||||
break;
|
||||
case ConsoleKey.Delete:
|
||||
if (m_cursorXPosition == m_commandLine.Length)
|
||||
break;
|
||||
|
||||
m_commandLine.Remove(m_cursorXPosition, 1);
|
||||
|
||||
SetCursorLeft(0);
|
||||
m_cursorYPosition = SetCursorTop(m_cursorYPosition);
|
||||
|
||||
if (m_echo)
|
||||
System.Console.Write("{0}{1} ", prompt, m_commandLine);
|
||||
else
|
||||
|
||||
@@ -234,7 +234,7 @@ namespace OpenSim.Framework.Console
|
||||
string uri = "/ReadResponses/" + sessionID.ToString() + "/";
|
||||
|
||||
m_Server.AddPollServiceHTTPHandler(
|
||||
uri, new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, sessionID));
|
||||
uri, new PollServiceEventArgs(null, HasEvents, GetEvents, NoEvents, sessionID,25000)); // 25 secs timeout
|
||||
|
||||
XmlDocument xmldoc = new XmlDocument();
|
||||
XmlNode xmlnode = xmldoc.CreateNode(XmlNodeType.XmlDeclaration,
|
||||
@@ -425,7 +425,7 @@ namespace OpenSim.Framework.Console
|
||||
return false;
|
||||
}
|
||||
|
||||
private Hashtable GetEvents(UUID RequestID, UUID sessionID, string request)
|
||||
private Hashtable GetEvents(UUID RequestID, UUID sessionID)
|
||||
{
|
||||
ConsoleConnection c = null;
|
||||
|
||||
|
||||
@@ -29,10 +29,12 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using System.Xml.Serialization;
|
||||
using log4net;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.StructuredData;
|
||||
|
||||
@@ -48,13 +50,20 @@ namespace OpenSim.Framework
|
||||
/// within their data store. However, avoid storing large amounts of data because that
|
||||
/// would slow down database access.
|
||||
/// </remarks>
|
||||
public class DAMap : IDictionary<string, OSDMap>, IXmlSerializable
|
||||
public class DAMap : IXmlSerializable
|
||||
{
|
||||
private static readonly int MIN_STORE_NAME_LENGTH = 4;
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
protected OSDMap m_map;
|
||||
|
||||
public DAMap() { m_map = new OSDMap(); }
|
||||
private static readonly int MIN_NAMESPACE_LENGTH = 4;
|
||||
|
||||
private OSDMap m_map = new OSDMap();
|
||||
|
||||
// WARNING: this is temporary for experimentation only, it will be removed!!!!
|
||||
public OSDMap TopLevelMap
|
||||
{
|
||||
get { return m_map; }
|
||||
set { m_map = value; }
|
||||
}
|
||||
|
||||
public XmlSchema GetSchema() { return null; }
|
||||
|
||||
@@ -64,39 +73,34 @@ namespace OpenSim.Framework
|
||||
map.ReadXml(rawXml);
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
public void ReadXml(XmlReader reader)
|
||||
{
|
||||
ReadXml(reader.ReadInnerXml());
|
||||
}
|
||||
|
||||
public void ReadXml(string rawXml)
|
||||
{
|
||||
// System.Console.WriteLine("Trying to deserialize [{0}]", rawXml);
|
||||
|
||||
lock (this)
|
||||
{
|
||||
m_map = (OSDMap)OSDParser.DeserializeLLSDXml(rawXml);
|
||||
}
|
||||
|
||||
// WARNING: this is temporary for experimentation only, it will be removed!!!!
|
||||
public OSDMap TopLevelMap
|
||||
{
|
||||
get { return m_map; }
|
||||
set { m_map = value; }
|
||||
}
|
||||
|
||||
|
||||
public void ReadXml(XmlReader reader)
|
||||
{
|
||||
ReadXml(reader.ReadInnerXml());
|
||||
}
|
||||
|
||||
public string ToXml()
|
||||
{
|
||||
lock (this)
|
||||
return OSDParser.SerializeLLSDXmlString(m_map);
|
||||
SanitiseMap(this);
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteXml(XmlWriter writer)
|
||||
{
|
||||
writer.WriteRaw(ToXml());
|
||||
}
|
||||
|
||||
|
||||
public string ToXml()
|
||||
{
|
||||
lock (this)
|
||||
return OSDParser.SerializeLLSDXmlString(m_map);
|
||||
}
|
||||
|
||||
public void CopyFrom(DAMap other)
|
||||
{
|
||||
// Deep copy
|
||||
@@ -104,7 +108,7 @@ namespace OpenSim.Framework
|
||||
string data = null;
|
||||
lock (other)
|
||||
{
|
||||
if (other.Count > 0)
|
||||
if (other.CountNamespaces > 0)
|
||||
{
|
||||
data = OSDParser.SerializeLLSDXmlString(other.m_map);
|
||||
}
|
||||
@@ -120,59 +124,132 @@ namespace OpenSim.Framework
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns the number of data stores.
|
||||
/// Sanitise the map to remove any namespaces or stores that are not OSDMap.
|
||||
/// </summary>
|
||||
public int Count { get { lock (this) { return m_map.Count; } } }
|
||||
|
||||
public bool IsReadOnly { get { return false; } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns the names of the data stores.
|
||||
/// </summary>
|
||||
public ICollection<string> Keys { get { lock (this) { return m_map.Keys; } } }
|
||||
|
||||
/// <summary>
|
||||
/// Returns all the data stores.
|
||||
/// </summary>
|
||||
public ICollection<OSDMap> Values
|
||||
/// <param name='map'>
|
||||
/// </param>
|
||||
public static void SanitiseMap(DAMap daMap)
|
||||
{
|
||||
get
|
||||
List<string> keysToRemove = null;
|
||||
|
||||
OSDMap namespacesMap = daMap.m_map;
|
||||
|
||||
foreach (string key in namespacesMap.Keys)
|
||||
{
|
||||
lock (this)
|
||||
// Console.WriteLine("Processing ns {0}", key);
|
||||
if (!(namespacesMap[key] is OSDMap))
|
||||
{
|
||||
List<OSDMap> stores = new List<OSDMap>(m_map.Count);
|
||||
foreach (OSD llsd in m_map.Values)
|
||||
stores.Add((OSDMap)llsd);
|
||||
return stores;
|
||||
if (keysToRemove == null)
|
||||
keysToRemove = new List<string>();
|
||||
|
||||
keysToRemove.Add(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (keysToRemove != null)
|
||||
{
|
||||
foreach (string key in keysToRemove)
|
||||
{
|
||||
// Console.WriteLine ("Removing bad ns {0}", key);
|
||||
namespacesMap.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (OSD nsOsd in namespacesMap.Values)
|
||||
{
|
||||
OSDMap nsOsdMap = (OSDMap)nsOsd;
|
||||
keysToRemove = null;
|
||||
|
||||
foreach (string key in nsOsdMap.Keys)
|
||||
{
|
||||
if (!(nsOsdMap[key] is OSDMap))
|
||||
{
|
||||
if (keysToRemove == null)
|
||||
keysToRemove = new List<string>();
|
||||
|
||||
keysToRemove.Add(key);
|
||||
}
|
||||
}
|
||||
|
||||
if (keysToRemove != null)
|
||||
foreach (string key in keysToRemove)
|
||||
nsOsdMap.Remove(key);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets one data store.
|
||||
/// Get the number of namespaces
|
||||
/// </summary>
|
||||
/// <param name="key">Store name</param>
|
||||
/// <returns></returns>
|
||||
public OSDMap this[string key]
|
||||
{
|
||||
get
|
||||
{
|
||||
OSD llsd;
|
||||
|
||||
public int CountNamespaces { get { lock (this) { return m_map.Count; } } }
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of stores.
|
||||
/// </summary>
|
||||
public int CountStores
|
||||
{
|
||||
get
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
lock (this)
|
||||
{
|
||||
if (m_map.TryGetValue(key, out llsd))
|
||||
return (OSDMap)llsd;
|
||||
else
|
||||
return null;
|
||||
foreach (OSD osdNamespace in m_map)
|
||||
{
|
||||
count += ((OSDMap)osdNamespace).Count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
set
|
||||
|
||||
return count;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve a Dynamic Attribute store
|
||||
/// </summary>
|
||||
/// <param name="ns">namespace for the store - use "OpenSim" for in-core modules</param>
|
||||
/// <param name="storeName">name of the store within the namespace</param>
|
||||
/// <returns>an OSDMap representing the stored data, or null if not found</returns>
|
||||
public OSDMap GetStore(string ns, string storeName)
|
||||
{
|
||||
OSD namespaceOsd;
|
||||
|
||||
lock (this)
|
||||
{
|
||||
ValidateKey(key);
|
||||
lock (this)
|
||||
m_map[key] = value;
|
||||
if (m_map.TryGetValue(ns, out namespaceOsd))
|
||||
{
|
||||
OSD store;
|
||||
|
||||
if (((OSDMap)namespaceOsd).TryGetValue(storeName, out store))
|
||||
return (OSDMap)store;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a Dynamic attribute store
|
||||
/// </summary>
|
||||
/// <param name="ns">namespace for the store - use "OpenSim" for in-core modules</param>
|
||||
/// <param name="storeName">name of the store within the namespace</param>
|
||||
/// <param name="store">an OSDMap representing the data to store</param>
|
||||
public void SetStore(string ns, string storeName, OSDMap store)
|
||||
{
|
||||
ValidateNamespace(ns);
|
||||
OSDMap nsMap;
|
||||
|
||||
lock (this)
|
||||
{
|
||||
if (!m_map.ContainsKey(ns))
|
||||
{
|
||||
nsMap = new OSDMap();
|
||||
m_map[ns] = nsMap;
|
||||
}
|
||||
|
||||
nsMap = (OSDMap)m_map[ns];
|
||||
|
||||
// m_log.DebugFormat("[DA MAP]: Setting store to {0}:{1}", ns, storeName);
|
||||
nsMap[storeName] = store;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,54 +257,46 @@ namespace OpenSim.Framework
|
||||
/// Validate the key used for storing separate data stores.
|
||||
/// </summary>
|
||||
/// <param name='key'></param>
|
||||
private static void ValidateKey(string key)
|
||||
public static void ValidateNamespace(string ns)
|
||||
{
|
||||
if (key.Length < MIN_STORE_NAME_LENGTH)
|
||||
throw new Exception("Minimum store name length is " + MIN_STORE_NAME_LENGTH);
|
||||
if (ns.Length < MIN_NAMESPACE_LENGTH)
|
||||
throw new Exception("Minimum namespace length is " + MIN_NAMESPACE_LENGTH);
|
||||
}
|
||||
|
||||
public bool ContainsKey(string key)
|
||||
public bool ContainsStore(string ns, string storeName)
|
||||
{
|
||||
lock (this)
|
||||
return m_map.ContainsKey(key);
|
||||
}
|
||||
OSD namespaceOsd;
|
||||
|
||||
public void Add(string key, OSDMap store)
|
||||
{
|
||||
ValidateKey(key);
|
||||
lock (this)
|
||||
m_map.Add(key, store);
|
||||
}
|
||||
|
||||
public void Add(KeyValuePair<string, OSDMap> kvp)
|
||||
{
|
||||
ValidateKey(kvp.Key);
|
||||
lock (this)
|
||||
m_map.Add(kvp.Key, kvp.Value);
|
||||
}
|
||||
|
||||
public bool Remove(string key)
|
||||
{
|
||||
lock (this)
|
||||
return m_map.Remove(key);
|
||||
}
|
||||
|
||||
public bool TryGetValue(string key, out OSDMap store)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
OSD llsd;
|
||||
if (m_map.TryGetValue(key, out llsd))
|
||||
if (m_map.TryGetValue(ns, out namespaceOsd))
|
||||
{
|
||||
store = (OSDMap)llsd;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
store = null;
|
||||
return false;
|
||||
return ((OSDMap)namespaceOsd).ContainsKey(storeName);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool TryGetStore(string ns, string storeName, out OSDMap store)
|
||||
{
|
||||
OSD namespaceOsd;
|
||||
|
||||
lock (this)
|
||||
{
|
||||
if (m_map.TryGetValue(ns, out namespaceOsd))
|
||||
{
|
||||
OSD storeOsd;
|
||||
|
||||
bool result = ((OSDMap)namespaceOsd).TryGetValue(storeName, out storeOsd);
|
||||
store = (OSDMap)storeOsd;
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
store = null;
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
@@ -235,39 +304,25 @@ namespace OpenSim.Framework
|
||||
lock (this)
|
||||
m_map.Clear();
|
||||
}
|
||||
|
||||
public bool Contains(KeyValuePair<string, OSDMap> kvp)
|
||||
|
||||
public bool RemoveStore(string ns, string storeName)
|
||||
{
|
||||
OSD namespaceOsd;
|
||||
|
||||
lock (this)
|
||||
return m_map.ContainsKey(kvp.Key);
|
||||
}
|
||||
{
|
||||
if (m_map.TryGetValue(ns, out namespaceOsd))
|
||||
{
|
||||
OSDMap namespaceOsdMap = (OSDMap)namespaceOsd;
|
||||
namespaceOsdMap.Remove(storeName);
|
||||
|
||||
public void CopyTo(KeyValuePair<string, OSDMap>[] array, int index)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
// Don't keep empty namespaces around
|
||||
if (namespaceOsdMap.Count <= 0)
|
||||
m_map.Remove(ns);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Remove(KeyValuePair<string, OSDMap> kvp)
|
||||
{
|
||||
lock (this)
|
||||
return m_map.Remove(kvp.Key);
|
||||
}
|
||||
|
||||
public System.Collections.IDictionaryEnumerator GetEnumerator()
|
||||
{
|
||||
lock (this)
|
||||
return m_map.GetEnumerator();
|
||||
}
|
||||
|
||||
IEnumerator<KeyValuePair<string, OSDMap>> IEnumerable<KeyValuePair<string, OSDMap>>.GetEnumerator()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
lock (this)
|
||||
return m_map.GetEnumerator();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -26,69 +26,73 @@
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using System.Xml.Serialization;
|
||||
using OpenMetaverse;
|
||||
using OpenMetaverse.StructuredData;
|
||||
|
||||
namespace OpenSim.ApplicationPlugins.Rest.Regions
|
||||
namespace OpenSim.Framework
|
||||
{
|
||||
public partial class RestRegionPlugin : RestPlugin
|
||||
/// <summary>
|
||||
/// This class stores and retrieves dynamic objects.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Experimental - DO NOT USE. Does not yet have namespace support.
|
||||
/// </remarks>
|
||||
public class DOMap
|
||||
{
|
||||
private static XmlSerializerNamespaces _xmlNs;
|
||||
|
||||
static RestRegionPlugin()
|
||||
private IDictionary<string, object> m_map;
|
||||
|
||||
public void Add(string ns, string objName, object dynObj)
|
||||
{
|
||||
_xmlNs = new XmlSerializerNamespaces();
|
||||
_xmlNs.Add(String.Empty, String.Empty);
|
||||
DAMap.ValidateNamespace(ns);
|
||||
|
||||
lock (this)
|
||||
{
|
||||
if (m_map == null)
|
||||
m_map = new Dictionary<string, object>();
|
||||
|
||||
m_map.Add(objName, dynObj);
|
||||
}
|
||||
}
|
||||
|
||||
#region overriding properties
|
||||
public override string Name
|
||||
public bool ContainsKey(string key)
|
||||
{
|
||||
get { return "REGION"; }
|
||||
return Get(key) != null;
|
||||
}
|
||||
|
||||
public override string ConfigName
|
||||
{
|
||||
get { return "RestRegionPlugin"; }
|
||||
}
|
||||
#endregion overriding properties
|
||||
|
||||
#region overriding methods
|
||||
/// <summary>
|
||||
/// This method is called by OpenSimMain immediately after loading the
|
||||
/// plugin and after basic server setup, but before running any server commands.
|
||||
/// Get a dynamic object
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Note that entries MUST be added to the active configuration files before
|
||||
/// the plugin can be enabled.
|
||||
/// Not providing an index method so that users can't casually overwrite each other's objects.
|
||||
/// </remarks>
|
||||
public override void Initialise(OpenSimBase openSim)
|
||||
/// <param name='key'></param>
|
||||
public object Get(string key)
|
||||
{
|
||||
try
|
||||
lock (this)
|
||||
{
|
||||
base.Initialise(openSim);
|
||||
if (!IsEnabled)
|
||||
{
|
||||
//m_log.WarnFormat("{0} Rest Plugins are disabled", MsgID);
|
||||
return;
|
||||
}
|
||||
|
||||
m_log.InfoFormat("{0} REST region plugin enabled", MsgID);
|
||||
|
||||
// add REST method handlers
|
||||
AddRestStreamHandler("GET", "/regions/", GetHandler);
|
||||
AddRestStreamHandler("POST", "/regions/", PostHandler);
|
||||
AddRestStreamHandler("GET", "/regioninfo/", GetRegionInfoHandler);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.WarnFormat("{0} Initialization failed: {1}", MsgID, e.Message);
|
||||
m_log.DebugFormat("{0} Initialization failed: {1}", MsgID, e.ToString());
|
||||
if (m_map == null)
|
||||
return null;
|
||||
else
|
||||
return m_map[key];
|
||||
}
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
public bool Remove(string key)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (m_map == null)
|
||||
return false;
|
||||
else
|
||||
return m_map.Remove(key);
|
||||
}
|
||||
}
|
||||
#endregion overriding methods
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,6 +58,30 @@ namespace OpenSim.Framework
|
||||
set { m_EstateName = value; }
|
||||
}
|
||||
|
||||
private bool m_AllowLandmark = true;
|
||||
|
||||
public bool AllowLandmark
|
||||
{
|
||||
get { return m_AllowLandmark; }
|
||||
set { m_AllowLandmark = value; }
|
||||
}
|
||||
|
||||
private bool m_AllowParcelChanges = true;
|
||||
|
||||
public bool AllowParcelChanges
|
||||
{
|
||||
get { return m_AllowParcelChanges; }
|
||||
set { m_AllowParcelChanges = value; }
|
||||
}
|
||||
|
||||
private bool m_AllowSetHome = true;
|
||||
|
||||
public bool AllowSetHome
|
||||
{
|
||||
get { return m_AllowSetHome; }
|
||||
set { m_AllowSetHome = value; }
|
||||
}
|
||||
|
||||
private uint m_ParentEstateID = 1;
|
||||
|
||||
public uint ParentEstateID
|
||||
@@ -374,10 +398,18 @@ namespace OpenSim.Framework
|
||||
return l_EstateAccess.Contains(user);
|
||||
}
|
||||
|
||||
public void SetFromFlags(ulong regionFlags)
|
||||
{
|
||||
ResetHomeOnTeleport = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.ResetHomeOnTeleport) == (ulong)OpenMetaverse.RegionFlags.ResetHomeOnTeleport);
|
||||
BlockDwell = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.BlockDwell) == (ulong)OpenMetaverse.RegionFlags.BlockDwell);
|
||||
AllowLandmark = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowLandmark) == (ulong)OpenMetaverse.RegionFlags.AllowLandmark);
|
||||
AllowParcelChanges = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowParcelChanges) == (ulong)OpenMetaverse.RegionFlags.AllowParcelChanges);
|
||||
AllowSetHome = ((regionFlags & (ulong)OpenMetaverse.RegionFlags.AllowSetHome) == (ulong)OpenMetaverse.RegionFlags.AllowSetHome);
|
||||
}
|
||||
|
||||
public bool GroupAccess(UUID groupID)
|
||||
{
|
||||
return l_EstateGroups.Contains(groupID);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,7 +64,9 @@ namespace OpenSim.Framework
|
||||
|
||||
public delegate void NetworkStats(int inPackets, int outPackets, int unAckedBytes);
|
||||
|
||||
public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams);
|
||||
public delegate void CachedTextureRequest(IClientAPI remoteClient, int serial, List<CachedTextureRequestArg> cachedTextureRequest);
|
||||
|
||||
public delegate void SetAppearance(IClientAPI remoteClient, Primitive.TextureEntry textureEntry, byte[] visualParams, List<CachedTextureRequestArg> cachedTextureData);
|
||||
|
||||
public delegate void StartAnim(IClientAPI remoteClient, UUID animID);
|
||||
|
||||
@@ -313,7 +315,7 @@ namespace OpenSim.Framework
|
||||
public delegate void ObjectPermissions(
|
||||
IClientAPI controller, UUID agentID, UUID sessionID, byte field, uint localId, uint mask, byte set);
|
||||
|
||||
public delegate void EconomyDataRequest(UUID agentID);
|
||||
public delegate void EconomyDataRequest(IClientAPI client);
|
||||
|
||||
public delegate void ObjectIncludeInSearch(IClientAPI remoteClient, bool IncludeInSearch, uint localID);
|
||||
|
||||
@@ -780,6 +782,7 @@ namespace OpenSim.Framework
|
||||
event EstateChangeInfo OnEstateChangeInfo;
|
||||
event EstateManageTelehub OnEstateManageTelehub;
|
||||
// [Obsolete("LLClientView Specific.")]
|
||||
event CachedTextureRequest OnCachedTextureRequest;
|
||||
event SetAppearance OnSetAppearance;
|
||||
// [Obsolete("LLClientView Specific - Replace and rename OnAvatarUpdate. Difference from SetAppearance?")]
|
||||
event AvatarNowWearing OnAvatarNowWearing;
|
||||
@@ -1087,14 +1090,15 @@ namespace OpenSim.Framework
|
||||
/// <param name="textureEntry"></param>
|
||||
void SendAppearance(UUID agentID, byte[] visualParams, byte[] textureEntry);
|
||||
|
||||
void SendCachedTextureResponse(ISceneEntity avatar, int serial, List<CachedTextureResponseArg> cachedTextures);
|
||||
|
||||
void SendStartPingCheck(byte seq);
|
||||
|
||||
/// <summary>
|
||||
/// Tell the client that an object has been deleted
|
||||
/// </summary>
|
||||
/// <param name="regionHandle"></param>
|
||||
/// <param name="localID"></param>
|
||||
void SendKillObject(ulong regionHandle, List<uint> localID);
|
||||
void SendKillObject(List<uint> localID);
|
||||
|
||||
void SendAnimations(UUID[] animID, int[] seqs, UUID sourceAgentId, UUID[] objectIDs);
|
||||
void SendRegionHandshake(RegionInfo regionInfo, RegionHandshakeArgs args);
|
||||
@@ -1116,8 +1120,8 @@ namespace OpenSim.Framework
|
||||
|
||||
void SendInstantMessage(GridInstantMessage im);
|
||||
|
||||
void SendGenericMessage(string method, List<string> message);
|
||||
void SendGenericMessage(string method, List<byte[]> message);
|
||||
void SendGenericMessage(string method, UUID invoice, List<string> message);
|
||||
void SendGenericMessage(string method, UUID invoice, List<byte[]> message);
|
||||
|
||||
void SendLayerData(float[] map);
|
||||
void SendLayerData(int px, int py, float[] map);
|
||||
@@ -1155,7 +1159,8 @@ namespace OpenSim.Framework
|
||||
void SendTeleportStart(uint flags);
|
||||
void SendTeleportProgress(uint flags, string message);
|
||||
|
||||
void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance);
|
||||
void SendMoneyBalance(UUID transaction, bool success, byte[] description, int balance, int transactionType, UUID sourceID, bool sourceIsGroup, UUID destID, bool destIsGroup, int amount, string item);
|
||||
|
||||
void SendPayPrice(UUID objectID, int[] payPrice);
|
||||
|
||||
void SendCoarseLocationUpdate(List<UUID> users, List<Vector3> CoarseLocations);
|
||||
@@ -1250,8 +1255,6 @@ namespace OpenSim.Framework
|
||||
void SendDialog(string objectname, UUID objectID, UUID ownerID, string ownerFirstName, string ownerLastName, string msg, UUID textureID, int ch,
|
||||
string[] buttonlabels);
|
||||
|
||||
bool AddMoney(int debit);
|
||||
|
||||
/// <summary>
|
||||
/// Update the client as to where the sun is currently located.
|
||||
/// </summary>
|
||||
|
||||
@@ -55,6 +55,13 @@ namespace OpenSim.Region.Framework.Interfaces
|
||||
/// <returns>Land object at the point supplied</returns>
|
||||
ILandObject GetLandObject(float x, float y);
|
||||
|
||||
/// <summary>
|
||||
/// Get the parcel at the specified point
|
||||
/// </summary>
|
||||
/// <param name="position">Vector where x and y components are between 0 and 256. z component is ignored.</param>
|
||||
/// <returns>Land object at the point supplied</returns>
|
||||
ILandObject GetLandObject(Vector3 position);
|
||||
|
||||
/// <summary>
|
||||
/// Get the parcels near the specified point
|
||||
/// </summary>
|
||||
|
||||
@@ -38,7 +38,8 @@ namespace OpenSim.Framework
|
||||
int GetBalance(UUID agentID);
|
||||
bool UploadCovered(UUID agentID, int amount);
|
||||
bool AmountCovered(UUID agentID, int amount);
|
||||
void ApplyCharge(UUID agentID, int amount, string text);
|
||||
void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type);
|
||||
void ApplyCharge(UUID agentID, int amount, MoneyTransactionType type, string extraData);
|
||||
void ApplyUploadCharge(UUID agentID, int amount, string text);
|
||||
|
||||
int UploadCharge { get; }
|
||||
|
||||
47
OpenSim/Framework/IPeople.cs
Normal file
47
OpenSim/Framework/IPeople.cs
Normal file
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenMetaverse;
|
||||
|
||||
namespace OpenSim.Framework
|
||||
{
|
||||
public class UserData
|
||||
{
|
||||
public UUID Id { get; set; }
|
||||
public string FirstName { get; set; }
|
||||
public string LastName { get; set; }
|
||||
public string HomeURL { get; set; }
|
||||
public Dictionary<string, object> ServerURLs { get; set; }
|
||||
}
|
||||
|
||||
public interface IPeople
|
||||
{
|
||||
List<UserData> GetUserData(string query, int page_size, int page_number);
|
||||
}
|
||||
}
|
||||
@@ -136,5 +136,10 @@ namespace OpenSim.Framework
|
||||
ISceneObject DeserializeObject(string representation);
|
||||
|
||||
bool CheckClient(UUID agentID, System.Net.IPEndPoint ep);
|
||||
|
||||
/// <summary>
|
||||
/// Start the scene and associated scripts within it.
|
||||
/// </summary>
|
||||
void Start();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
@@ -45,16 +45,16 @@ namespace OpenSim.Framework.Monitoring
|
||||
sb.Append(Environment.NewLine);
|
||||
|
||||
sb.AppendFormat(
|
||||
"Allocated to OpenSim objects: {0} MB\n",
|
||||
"Heap allocated to OpenSim : {0} MB\n",
|
||||
Math.Round(GC.GetTotalMemory(false) / 1024.0 / 1024.0));
|
||||
|
||||
sb.AppendFormat(
|
||||
"OpenSim last object memory churn : {0} MB/s\n",
|
||||
Math.Round((MemoryWatchdog.LastMemoryChurn * 1000) / 1024.0 / 1024, 3));
|
||||
"Last heap allocation rate : {0} MB/s\n",
|
||||
Math.Round((MemoryWatchdog.LastHeapAllocationRate * 1000) / 1024.0 / 1024, 3));
|
||||
|
||||
sb.AppendFormat(
|
||||
"OpenSim average object memory churn : {0} MB/s\n",
|
||||
Math.Round((MemoryWatchdog.AverageMemoryChurn * 1000) / 1024.0 / 1024, 3));
|
||||
"Average heap allocation rate: {0} MB/s\n",
|
||||
Math.Round((MemoryWatchdog.AverageHeapAllocationRate * 1000) / 1024.0 / 1024, 3));
|
||||
|
||||
sb.AppendFormat(
|
||||
"Process memory : {0} MB\n",
|
||||
|
||||
@@ -60,17 +60,17 @@ namespace OpenSim.Framework.Monitoring
|
||||
private static bool m_enabled;
|
||||
|
||||
/// <summary>
|
||||
/// Last memory churn in bytes per millisecond.
|
||||
/// Average heap allocation rate in bytes per millisecond.
|
||||
/// </summary>
|
||||
public static double AverageMemoryChurn
|
||||
public static double AverageHeapAllocationRate
|
||||
{
|
||||
get { if (m_samples.Count > 0) return m_samples.Average(); else return 0; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Average memory churn in bytes per millisecond.
|
||||
/// Last heap allocation in bytes
|
||||
/// </summary>
|
||||
public static double LastMemoryChurn
|
||||
public static double LastHeapAllocationRate
|
||||
{
|
||||
get { if (m_samples.Count > 0) return m_samples.Last(); else return 0; }
|
||||
}
|
||||
|
||||
349
OpenSim/Framework/Monitoring/ServerStatsCollector.cs
Normal file
349
OpenSim/Framework/Monitoring/ServerStatsCollector.cs
Normal file
@@ -0,0 +1,349 @@
|
||||
/*
|
||||
* 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.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using log4net;
|
||||
using Nini.Config;
|
||||
using OpenMetaverse.StructuredData;
|
||||
using OpenSim.Framework;
|
||||
|
||||
namespace OpenSim.Framework.Monitoring
|
||||
{
|
||||
public class ServerStatsCollector
|
||||
{
|
||||
private readonly ILog m_log = LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private readonly string LogHeader = "[SERVER STATS]";
|
||||
|
||||
public bool Enabled = false;
|
||||
private static Dictionary<string, Stat> RegisteredStats = new Dictionary<string, Stat>();
|
||||
|
||||
public readonly string CategoryServer = "server";
|
||||
|
||||
public readonly string ContainerThreadpool = "threadpool";
|
||||
public readonly string ContainerProcessor = "processor";
|
||||
public readonly string ContainerMemory = "memory";
|
||||
public readonly string ContainerNetwork = "network";
|
||||
public readonly string ContainerProcess = "process";
|
||||
|
||||
public string NetworkInterfaceTypes = "Ethernet";
|
||||
|
||||
readonly int performanceCounterSampleInterval = 500;
|
||||
// int lastperformanceCounterSampleTime = 0;
|
||||
|
||||
private class PerfCounterControl
|
||||
{
|
||||
public PerformanceCounter perfCounter;
|
||||
public int lastFetch;
|
||||
public string name;
|
||||
public PerfCounterControl(PerformanceCounter pPc)
|
||||
: this(pPc, String.Empty)
|
||||
{
|
||||
}
|
||||
public PerfCounterControl(PerformanceCounter pPc, string pName)
|
||||
{
|
||||
perfCounter = pPc;
|
||||
lastFetch = 0;
|
||||
name = pName;
|
||||
}
|
||||
}
|
||||
|
||||
PerfCounterControl processorPercentPerfCounter = null;
|
||||
|
||||
// IRegionModuleBase.Initialize
|
||||
public void Initialise(IConfigSource source)
|
||||
{
|
||||
IConfig cfg = source.Configs["Monitoring"];
|
||||
|
||||
if (cfg != null)
|
||||
Enabled = cfg.GetBoolean("ServerStatsEnabled", true);
|
||||
|
||||
if (Enabled)
|
||||
{
|
||||
NetworkInterfaceTypes = cfg.GetString("NetworkInterfaceTypes", "Ethernet");
|
||||
}
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
if (RegisteredStats.Count == 0)
|
||||
RegisterServerStats();
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
if (RegisteredStats.Count > 0)
|
||||
{
|
||||
foreach (Stat stat in RegisteredStats.Values)
|
||||
{
|
||||
StatsManager.DeregisterStat(stat);
|
||||
stat.Dispose();
|
||||
}
|
||||
RegisteredStats.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action<Stat> act)
|
||||
{
|
||||
MakeStat(pName, pDesc, pUnit, pContainer, act, MeasuresOfInterest.None);
|
||||
}
|
||||
|
||||
private void MakeStat(string pName, string pDesc, string pUnit, string pContainer, Action<Stat> act, MeasuresOfInterest moi)
|
||||
{
|
||||
string desc = pDesc;
|
||||
if (desc == null)
|
||||
desc = pName;
|
||||
Stat stat = new Stat(pName, pName, desc, pUnit, CategoryServer, pContainer, StatType.Pull, moi, act, StatVerbosity.Debug);
|
||||
StatsManager.RegisterStat(stat);
|
||||
RegisteredStats.Add(pName, stat);
|
||||
}
|
||||
|
||||
public void RegisterServerStats()
|
||||
{
|
||||
// lastperformanceCounterSampleTime = Util.EnvironmentTickCount();
|
||||
PerformanceCounter tempPC;
|
||||
Stat tempStat;
|
||||
string tempName;
|
||||
|
||||
try
|
||||
{
|
||||
tempName = "CPUPercent";
|
||||
tempPC = new PerformanceCounter("Processor", "% Processor Time", "_Total");
|
||||
processorPercentPerfCounter = new PerfCounterControl(tempPC);
|
||||
// A long time bug in mono is that CPU percent is reported as CPU percent idle. Windows reports CPU percent busy.
|
||||
tempStat = new Stat(tempName, tempName, "", "percent", CategoryServer, ContainerProcessor,
|
||||
StatType.Pull, (s) => { GetNextValue(s, processorPercentPerfCounter, Util.IsWindows() ? 1 : -1); },
|
||||
StatVerbosity.Info);
|
||||
StatsManager.RegisterStat(tempStat);
|
||||
RegisteredStats.Add(tempName, tempStat);
|
||||
|
||||
MakeStat("TotalProcessorTime", null, "sec", ContainerProcessor,
|
||||
(s) => { s.Value = Process.GetCurrentProcess().TotalProcessorTime.TotalSeconds; });
|
||||
|
||||
MakeStat("UserProcessorTime", null, "sec", ContainerProcessor,
|
||||
(s) => { s.Value = Process.GetCurrentProcess().UserProcessorTime.TotalSeconds; });
|
||||
|
||||
MakeStat("PrivilegedProcessorTime", null, "sec", ContainerProcessor,
|
||||
(s) => { s.Value = Process.GetCurrentProcess().PrivilegedProcessorTime.TotalSeconds; });
|
||||
|
||||
MakeStat("Threads", null, "threads", ContainerProcessor,
|
||||
(s) => { s.Value = Process.GetCurrentProcess().Threads.Count; });
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat("{0} Exception creating 'Process': {1}", LogHeader, e);
|
||||
}
|
||||
|
||||
MakeStat("BuiltinThreadpoolWorkerThreadsAvailable", null, "threads", ContainerThreadpool,
|
||||
s =>
|
||||
{
|
||||
int workerThreads, iocpThreads;
|
||||
ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads);
|
||||
s.Value = workerThreads;
|
||||
});
|
||||
|
||||
MakeStat("BuiltinThreadpoolIOCPThreadsAvailable", null, "threads", ContainerThreadpool,
|
||||
s =>
|
||||
{
|
||||
int workerThreads, iocpThreads;
|
||||
ThreadPool.GetAvailableThreads(out workerThreads, out iocpThreads);
|
||||
s.Value = iocpThreads;
|
||||
});
|
||||
|
||||
if (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool && Util.GetSmartThreadPoolInfo() != null)
|
||||
{
|
||||
MakeStat("STPMaxThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxThreads);
|
||||
MakeStat("STPMinThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MinThreads);
|
||||
MakeStat("STPConcurrency", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().MaxConcurrentWorkItems);
|
||||
MakeStat("STPActiveThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().ActiveThreads);
|
||||
MakeStat("STPInUseThreads", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().InUseThreads);
|
||||
MakeStat("STPWorkItemsWaiting", null, "threads", ContainerThreadpool, s => s.Value = Util.GetSmartThreadPoolInfo().WaitingCallbacks);
|
||||
}
|
||||
|
||||
MakeStat(
|
||||
"HTTPRequestsMade",
|
||||
"Number of outbound HTTP requests made",
|
||||
"requests",
|
||||
ContainerNetwork,
|
||||
s => s.Value = WebUtil.RequestNumber,
|
||||
MeasuresOfInterest.AverageChangeOverTime);
|
||||
|
||||
try
|
||||
{
|
||||
List<string> okInterfaceTypes = new List<string>(NetworkInterfaceTypes.Split(','));
|
||||
|
||||
IEnumerable<NetworkInterface> nics = NetworkInterface.GetAllNetworkInterfaces();
|
||||
foreach (NetworkInterface nic in nics)
|
||||
{
|
||||
if (nic.OperationalStatus != OperationalStatus.Up)
|
||||
continue;
|
||||
|
||||
string nicInterfaceType = nic.NetworkInterfaceType.ToString();
|
||||
if (!okInterfaceTypes.Contains(nicInterfaceType))
|
||||
{
|
||||
m_log.DebugFormat("{0} Not including stats for network interface '{1}' of type '{2}'.",
|
||||
LogHeader, nic.Name, nicInterfaceType);
|
||||
m_log.DebugFormat("{0} To include, add to comma separated list in [Monitoring]NetworkInterfaceTypes={1}",
|
||||
LogHeader, NetworkInterfaceTypes);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (nic.Supports(NetworkInterfaceComponent.IPv4))
|
||||
{
|
||||
IPv4InterfaceStatistics nicStats = nic.GetIPv4Statistics();
|
||||
if (nicStats != null)
|
||||
{
|
||||
MakeStat("BytesRcvd/" + nic.Name, nic.Name, "KB", ContainerNetwork,
|
||||
(s) => { LookupNic(s, (ns) => { return ns.BytesReceived; }, 1024.0); });
|
||||
MakeStat("BytesSent/" + nic.Name, nic.Name, "KB", ContainerNetwork,
|
||||
(s) => { LookupNic(s, (ns) => { return ns.BytesSent; }, 1024.0); });
|
||||
MakeStat("TotalBytes/" + nic.Name, nic.Name, "KB", ContainerNetwork,
|
||||
(s) => { LookupNic(s, (ns) => { return ns.BytesSent + ns.BytesReceived; }, 1024.0); });
|
||||
}
|
||||
}
|
||||
// TODO: add IPv6 (it may actually happen someday)
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat("{0} Exception creating 'Network Interface': {1}", LogHeader, e);
|
||||
}
|
||||
|
||||
MakeStat("ProcessMemory", null, "MB", ContainerMemory,
|
||||
(s) => { s.Value = Math.Round(Process.GetCurrentProcess().WorkingSet64 / 1024d / 1024d, 3); });
|
||||
MakeStat("HeapMemory", null, "MB", ContainerMemory,
|
||||
(s) => { s.Value = Math.Round(GC.GetTotalMemory(false) / 1024d / 1024d, 3); });
|
||||
MakeStat("LastHeapAllocationRate", null, "MB/sec", ContainerMemory,
|
||||
(s) => { s.Value = Math.Round(MemoryWatchdog.LastHeapAllocationRate * 1000d / 1024d / 1024d, 3); });
|
||||
MakeStat("AverageHeapAllocationRate", null, "MB/sec", ContainerMemory,
|
||||
(s) => { s.Value = Math.Round(MemoryWatchdog.AverageHeapAllocationRate * 1000d / 1024d / 1024d, 3); });
|
||||
}
|
||||
|
||||
// Notes on performance counters:
|
||||
// "How To Read Performance Counters": http://blogs.msdn.com/b/bclteam/archive/2006/06/02/618156.aspx
|
||||
// "How to get the CPU Usage in C#": http://stackoverflow.com/questions/278071/how-to-get-the-cpu-usage-in-c
|
||||
// "Mono Performance Counters": http://www.mono-project.com/Mono_Performance_Counters
|
||||
private delegate double PerfCounterNextValue();
|
||||
private void GetNextValue(Stat stat, PerfCounterControl perfControl)
|
||||
{
|
||||
GetNextValue(stat, perfControl, 1.0);
|
||||
}
|
||||
private void GetNextValue(Stat stat, PerfCounterControl perfControl, double factor)
|
||||
{
|
||||
if (Util.EnvironmentTickCountSubtract(perfControl.lastFetch) > performanceCounterSampleInterval)
|
||||
{
|
||||
if (perfControl != null && perfControl.perfCounter != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Kludge for factor to run double duty. If -1, subtract the value from one
|
||||
if (factor == -1)
|
||||
stat.Value = 1 - perfControl.perfCounter.NextValue();
|
||||
else
|
||||
stat.Value = perfControl.perfCounter.NextValue() / factor;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat("{0} Exception on NextValue fetching {1}: {2}", LogHeader, stat.Name, e);
|
||||
}
|
||||
perfControl.lastFetch = Util.EnvironmentTickCount();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Lookup the nic that goes with this stat and set the value by using a fetch action.
|
||||
// Not sure about closure with delegates inside delegates.
|
||||
private delegate double GetIPv4StatValue(IPv4InterfaceStatistics interfaceStat);
|
||||
private void LookupNic(Stat stat, GetIPv4StatValue getter, double factor)
|
||||
{
|
||||
// Get the one nic that has the name of this stat
|
||||
IEnumerable<NetworkInterface> nics = NetworkInterface.GetAllNetworkInterfaces().Where(
|
||||
(network) => network.Name == stat.Description);
|
||||
try
|
||||
{
|
||||
foreach (NetworkInterface nic in nics)
|
||||
{
|
||||
IPv4InterfaceStatistics intrStats = nic.GetIPv4Statistics();
|
||||
if (intrStats != null)
|
||||
{
|
||||
double newVal = Math.Round(getter(intrStats) / factor, 3);
|
||||
stat.Value = newVal;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// There are times interfaces go away so we just won't update the stat for this
|
||||
m_log.ErrorFormat("{0} Exception fetching stat on interface '{1}'", LogHeader, stat.Description);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ServerStatsAggregator : Stat
|
||||
{
|
||||
public ServerStatsAggregator(
|
||||
string shortName,
|
||||
string name,
|
||||
string description,
|
||||
string unitName,
|
||||
string category,
|
||||
string container
|
||||
)
|
||||
: base(
|
||||
shortName,
|
||||
name,
|
||||
description,
|
||||
unitName,
|
||||
category,
|
||||
container,
|
||||
StatType.Push,
|
||||
MeasuresOfInterest.None,
|
||||
null,
|
||||
StatVerbosity.Info)
|
||||
{
|
||||
}
|
||||
public override string ToConsoleString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public override OSDMap ToOSDMap()
|
||||
{
|
||||
OSDMap ret = new OSDMap();
|
||||
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -359,8 +359,9 @@ Asset service request failures: {3}" + Environment.NewLine,
|
||||
inPacketsPerSecond, outPacketsPerSecond, pendingDownloads, pendingUploads, unackedBytes, totalFrameTime,
|
||||
netFrameTime, physicsFrameTime, otherFrameTime, agentFrameTime, imageFrameTime));
|
||||
|
||||
/* 20130319 RA: For the moment, disable the dump of 'scene' catagory as they are mostly output by
|
||||
* the two formatted printouts above.
|
||||
SortedDictionary<string, SortedDictionary<string, Stat>> sceneStats;
|
||||
|
||||
if (StatsManager.TryGetStats("scene", out sceneStats))
|
||||
{
|
||||
foreach (KeyValuePair<string, SortedDictionary<string, Stat>> kvp in sceneStats)
|
||||
@@ -374,6 +375,7 @@ Asset service request failures: {3}" + Environment.NewLine,
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/*
|
||||
sb.Append(Environment.NewLine);
|
||||
|
||||
@@ -224,5 +224,26 @@ public class CounterStat : Stat
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// CounterStat is a basic stat plus histograms
|
||||
public override OSDMap ToOSDMap()
|
||||
{
|
||||
// Get the foundational instance
|
||||
OSDMap map = base.ToOSDMap();
|
||||
|
||||
map["StatType"] = "CounterStat";
|
||||
|
||||
// If there are any histograms, add a new field that is an array of histograms as OSDMaps
|
||||
if (m_histograms.Count > 0)
|
||||
{
|
||||
OSDArray histos = new OSDArray();
|
||||
foreach (EventHistogram histo in m_histograms.Values)
|
||||
{
|
||||
histos.Add(histo.GetHistogramAsOSDMap());
|
||||
}
|
||||
map.Add("Histograms", histos);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,10 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
|
||||
using log4net;
|
||||
using OpenMetaverse.StructuredData;
|
||||
|
||||
namespace OpenSim.Framework.Monitoring
|
||||
@@ -38,6 +40,10 @@ namespace OpenSim.Framework.Monitoring
|
||||
/// </summary>
|
||||
public class Stat : IDisposable
|
||||
{
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
public static readonly char[] DisallowedShortNameCharacters = { '.' };
|
||||
|
||||
/// <summary>
|
||||
/// Category of this stat (e.g. cache, scene, etc).
|
||||
/// </summary>
|
||||
@@ -95,7 +101,7 @@ namespace OpenSim.Framework.Monitoring
|
||||
/// <remarks>
|
||||
/// Will be null if no measures of interest require samples.
|
||||
/// </remarks>
|
||||
private static Queue<double> m_samples;
|
||||
private Queue<double> m_samples;
|
||||
|
||||
/// <summary>
|
||||
/// Maximum number of statistical samples.
|
||||
@@ -162,6 +168,12 @@ namespace OpenSim.Framework.Monitoring
|
||||
throw new Exception(
|
||||
string.Format("Stat cannot be in category '{0}' since this is reserved for a subcommand", category));
|
||||
|
||||
foreach (char c in DisallowedShortNameCharacters)
|
||||
{
|
||||
if (shortName.IndexOf(c) != -1)
|
||||
throw new Exception(string.Format("Stat name {0} cannot contain character {1}", shortName, c));
|
||||
}
|
||||
|
||||
ShortName = shortName;
|
||||
Name = name;
|
||||
Description = description;
|
||||
@@ -204,6 +216,8 @@ namespace OpenSim.Framework.Monitoring
|
||||
if (m_samples.Count >= m_maxSamples)
|
||||
m_samples.Dequeue();
|
||||
|
||||
// m_log.DebugFormat("[STAT]: Recording value {0} for {1}", newValue, Name);
|
||||
|
||||
m_samples.Enqueue(newValue);
|
||||
}
|
||||
}
|
||||
@@ -228,6 +242,7 @@ namespace OpenSim.Framework.Monitoring
|
||||
ret.Add("Description", OSD.FromString(Description));
|
||||
ret.Add("UnitName", OSD.FromString(UnitName));
|
||||
ret.Add("Value", OSD.FromReal(Value));
|
||||
ret.Add("StatType", "Stat"); // used by overloading classes to denote type of stat
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -242,6 +257,10 @@ namespace OpenSim.Framework.Monitoring
|
||||
|
||||
lock (m_samples)
|
||||
{
|
||||
// m_log.DebugFormat(
|
||||
// "[STAT]: Samples for {0} are {1}",
|
||||
// Name, string.Join(",", m_samples.Select(s => s.ToString()).ToArray()));
|
||||
|
||||
foreach (double s in m_samples)
|
||||
{
|
||||
if (lastSample != null)
|
||||
@@ -253,7 +272,7 @@ namespace OpenSim.Framework.Monitoring
|
||||
|
||||
int divisor = m_samples.Count <= 1 ? 1 : m_samples.Count - 1;
|
||||
|
||||
sb.AppendFormat(", {0:0.##}{1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName);
|
||||
sb.AppendFormat(", {0:0.##} {1}/s", totalChange / divisor / (Watchdog.WATCHDOG_INTERVAL_MS / 1000), UnitName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,8 +27,11 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using OpenMetaverse.StructuredData;
|
||||
|
||||
namespace OpenSim.Framework.Monitoring
|
||||
{
|
||||
/// <summary>
|
||||
@@ -54,13 +57,13 @@ namespace OpenSim.Framework.Monitoring
|
||||
public static SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Stat>>> RegisteredStats
|
||||
= new SortedDictionary<string, SortedDictionary<string, SortedDictionary<string, Stat>>>();
|
||||
|
||||
private static AssetStatsCollector assetStats;
|
||||
private static UserStatsCollector userStats;
|
||||
private static SimExtraStatsCollector simExtraStats = new SimExtraStatsCollector();
|
||||
// private static AssetStatsCollector assetStats;
|
||||
// private static UserStatsCollector userStats;
|
||||
// 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; } }
|
||||
// public static AssetStatsCollector AssetStats { get { return assetStats; } }
|
||||
// public static UserStatsCollector UserStats { get { return userStats; } }
|
||||
public static SimExtraStatsCollector SimExtraStats { get; set; }
|
||||
|
||||
public static void RegisterConsoleCommands(ICommandConsole console)
|
||||
{
|
||||
@@ -68,12 +71,14 @@ namespace OpenSim.Framework.Monitoring
|
||||
"General",
|
||||
false,
|
||||
"show stats",
|
||||
"show stats [list|all|<category>]",
|
||||
"show stats [list|all|(<category>[.<container>])+",
|
||||
"Show statistical information for this server",
|
||||
"If no final argument is specified then legacy statistics information is currently shown.\n"
|
||||
+ "If list is specified then statistic categories are shown.\n"
|
||||
+ "If all is specified then all registered statistics are shown.\n"
|
||||
+ "If a category name is specified then only statistics from that category are shown.\n"
|
||||
+ "'list' argument will show statistic categories.\n"
|
||||
+ "'all' will show all statistics.\n"
|
||||
+ "A <category> name will show statistics from that category.\n"
|
||||
+ "A <category>.<container> name will show statistics from that category in that container.\n"
|
||||
+ "More than one name can be given separated by spaces.\n"
|
||||
+ "THIS STATS FACILITY IS EXPERIMENTAL AND DOES NOT YET CONTAIN ALL STATS",
|
||||
HandleShowStatsCommand);
|
||||
}
|
||||
@@ -84,43 +89,47 @@ namespace OpenSim.Framework.Monitoring
|
||||
|
||||
if (cmd.Length > 2)
|
||||
{
|
||||
var categoryName = cmd[2];
|
||||
var containerName = cmd.Length > 3 ? cmd[3] : String.Empty;
|
||||
foreach (string name in cmd.Skip(2))
|
||||
{
|
||||
string[] components = name.Split('.');
|
||||
|
||||
if (categoryName == AllSubCommand)
|
||||
{
|
||||
foreach (var category in RegisteredStats.Values)
|
||||
string categoryName = components[0];
|
||||
string containerName = components.Length > 1 ? components[1] : null;
|
||||
|
||||
if (categoryName == AllSubCommand)
|
||||
{
|
||||
OutputCategoryStatsToConsole(con, category);
|
||||
OutputAllStatsToConsole(con);
|
||||
}
|
||||
}
|
||||
else if (categoryName == ListSubCommand)
|
||||
{
|
||||
con.Output("Statistic categories available are:");
|
||||
foreach (string category in RegisteredStats.Keys)
|
||||
con.OutputFormat(" {0}", category);
|
||||
}
|
||||
else
|
||||
{
|
||||
SortedDictionary<string, SortedDictionary<string, Stat>> category;
|
||||
if (!RegisteredStats.TryGetValue(categoryName, out category))
|
||||
else if (categoryName == ListSubCommand)
|
||||
{
|
||||
con.OutputFormat("No such category as {0}", categoryName);
|
||||
con.Output("Statistic categories available are:");
|
||||
foreach (string category in RegisteredStats.Keys)
|
||||
con.OutputFormat(" {0}", category);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (String.IsNullOrEmpty(containerName))
|
||||
OutputCategoryStatsToConsole(con, category);
|
||||
SortedDictionary<string, SortedDictionary<string, Stat>> category;
|
||||
if (!RegisteredStats.TryGetValue(categoryName, out category))
|
||||
{
|
||||
con.OutputFormat("No such category as {0}", categoryName);
|
||||
}
|
||||
else
|
||||
{
|
||||
SortedDictionary<string, Stat> container;
|
||||
if (category.TryGetValue(containerName, out container))
|
||||
if (String.IsNullOrEmpty(containerName))
|
||||
{
|
||||
OutputContainerStatsToConsole(con, container);
|
||||
OutputCategoryStatsToConsole(con, category);
|
||||
}
|
||||
else
|
||||
{
|
||||
con.OutputFormat("No such container {0} in category {1}", containerName, categoryName);
|
||||
SortedDictionary<string, Stat> container;
|
||||
if (category.TryGetValue(containerName, out container))
|
||||
{
|
||||
OutputContainerStatsToConsole(con, container);
|
||||
}
|
||||
else
|
||||
{
|
||||
con.OutputFormat("No such container {0} in category {1}", containerName, categoryName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -129,7 +138,18 @@ namespace OpenSim.Framework.Monitoring
|
||||
else
|
||||
{
|
||||
// Legacy
|
||||
con.Output(SimExtraStats.Report());
|
||||
if (SimExtraStats != null)
|
||||
con.Output(SimExtraStats.Report());
|
||||
else
|
||||
OutputAllStatsToConsole(con);
|
||||
}
|
||||
}
|
||||
|
||||
private static void OutputAllStatsToConsole(ICommandConsole con)
|
||||
{
|
||||
foreach (var category in RegisteredStats.Values)
|
||||
{
|
||||
OutputCategoryStatsToConsole(con, category);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -150,27 +170,91 @@ namespace OpenSim.Framework.Monitoring
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start collecting statistics related to assets.
|
||||
/// Should only be called once.
|
||||
/// </summary>
|
||||
public static AssetStatsCollector StartCollectingAssetStats()
|
||||
// Creates an OSDMap of the format:
|
||||
// { categoryName: {
|
||||
// containerName: {
|
||||
// statName: {
|
||||
// "Name": name,
|
||||
// "ShortName": shortName,
|
||||
// ...
|
||||
// },
|
||||
// statName: {
|
||||
// "Name": name,
|
||||
// "ShortName": shortName,
|
||||
// ...
|
||||
// },
|
||||
// ...
|
||||
// },
|
||||
// containerName: {
|
||||
// ...
|
||||
// },
|
||||
// ...
|
||||
// },
|
||||
// categoryName: {
|
||||
// ...
|
||||
// },
|
||||
// ...
|
||||
// }
|
||||
// The passed in parameters will filter the categories, containers and stats returned. If any of the
|
||||
// parameters are either EmptyOrNull or the AllSubCommand value, all of that type will be returned.
|
||||
// Case matters.
|
||||
public static OSDMap GetStatsAsOSDMap(string pCategoryName, string pContainerName, string pStatName)
|
||||
{
|
||||
assetStats = new AssetStatsCollector();
|
||||
OSDMap map = new OSDMap();
|
||||
|
||||
return assetStats;
|
||||
foreach (string catName in RegisteredStats.Keys)
|
||||
{
|
||||
// Do this category if null spec, "all" subcommand or category name matches passed parameter.
|
||||
// Skip category if none of the above.
|
||||
if (!(String.IsNullOrEmpty(pCategoryName) || pCategoryName == AllSubCommand || pCategoryName == catName))
|
||||
continue;
|
||||
|
||||
OSDMap contMap = new OSDMap();
|
||||
foreach (string contName in RegisteredStats[catName].Keys)
|
||||
{
|
||||
if (!(string.IsNullOrEmpty(pContainerName) || pContainerName == AllSubCommand || pContainerName == contName))
|
||||
continue;
|
||||
|
||||
OSDMap statMap = new OSDMap();
|
||||
|
||||
SortedDictionary<string, Stat> theStats = RegisteredStats[catName][contName];
|
||||
foreach (string statName in theStats.Keys)
|
||||
{
|
||||
if (!(String.IsNullOrEmpty(pStatName) || pStatName == AllSubCommand || pStatName == statName))
|
||||
continue;
|
||||
|
||||
statMap.Add(statName, theStats[statName].ToOSDMap());
|
||||
}
|
||||
|
||||
contMap.Add(contName, statMap);
|
||||
}
|
||||
map.Add(catName, contMap);
|
||||
}
|
||||
|
||||
return map;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Start collecting statistics related to users.
|
||||
/// Should only be called once.
|
||||
/// </summary>
|
||||
public static UserStatsCollector StartCollectingUserStats()
|
||||
{
|
||||
userStats = new UserStatsCollector();
|
||||
|
||||
return userStats;
|
||||
}
|
||||
// /// <summary>
|
||||
// /// Start collecting statistics related to assets.
|
||||
// /// Should only be called once.
|
||||
// /// </summary>
|
||||
// public static AssetStatsCollector StartCollectingAssetStats()
|
||||
// {
|
||||
// assetStats = new AssetStatsCollector();
|
||||
//
|
||||
// return assetStats;
|
||||
// }
|
||||
//
|
||||
// /// <summary>
|
||||
// /// Start collecting statistics related to users.
|
||||
// /// Should only be called once.
|
||||
// /// </summary>
|
||||
// public static UserStatsCollector StartCollectingUserStats()
|
||||
// {
|
||||
// userStats = new UserStatsCollector();
|
||||
//
|
||||
// return userStats;
|
||||
// }
|
||||
|
||||
/// <summary>
|
||||
/// Registers a statistic.
|
||||
|
||||
@@ -218,7 +218,7 @@ namespace OpenSim.Framework
|
||||
Console.WriteLine ("Looking for updates...");
|
||||
Repositories.UpdateAllRepositories (ps);
|
||||
Console.WriteLine ("Available add-in updates:");
|
||||
bool found = false;
|
||||
|
||||
AddinRepositoryEntry[] entries = Repositories.GetAvailableUpdates();
|
||||
|
||||
foreach (AddinRepositoryEntry entry in entries)
|
||||
@@ -541,7 +541,7 @@ namespace OpenSim.Framework
|
||||
{
|
||||
list.AddRange(PluginRegistry.GetAddins());
|
||||
}
|
||||
catch(Exception e)
|
||||
catch (Exception)
|
||||
{
|
||||
Addin[] x = xlist.ToArray(typeof(Addin)) as Addin[];
|
||||
return x;
|
||||
|
||||
@@ -86,25 +86,22 @@ namespace OpenSim.Framework.Servers
|
||||
/// </summary>
|
||||
protected virtual void StartupSpecific()
|
||||
{
|
||||
if (m_console == null)
|
||||
return;
|
||||
|
||||
StatsManager.SimExtraStats = new SimExtraStatsCollector();
|
||||
RegisterCommonCommands();
|
||||
|
||||
m_console.Commands.AddCommand("General", false, "quit",
|
||||
"quit",
|
||||
"Quit the application", HandleQuit);
|
||||
RegisterCommonComponents(Config);
|
||||
}
|
||||
|
||||
m_console.Commands.AddCommand("General", false, "shutdown",
|
||||
"shutdown",
|
||||
"Quit the application", HandleQuit);
|
||||
protected override void ShutdownSpecific()
|
||||
{
|
||||
m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting...");
|
||||
|
||||
RemovePIDFile();
|
||||
|
||||
base.ShutdownSpecific();
|
||||
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should be overriden and referenced by descendents if they need to perform extra shutdown processing
|
||||
/// </summary>
|
||||
public virtual void ShutdownSpecific() {}
|
||||
|
||||
/// <summary>
|
||||
/// Provides a list of help topics that are available. Overriding classes should append their topics to the
|
||||
/// information returned when the base method is called.
|
||||
@@ -133,17 +130,7 @@ namespace OpenSim.Framework.Servers
|
||||
/// Performs initialisation of the scene, such as loading configuration from disk.
|
||||
/// </summary>
|
||||
public virtual void Startup()
|
||||
{
|
||||
m_log.Info("[STARTUP]: Beginning startup processing");
|
||||
|
||||
m_log.Info("[STARTUP]: OpenSimulator version: " + m_version + Environment.NewLine);
|
||||
// clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and
|
||||
// the clr version number doesn't match the project version number under Mono.
|
||||
//m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine);
|
||||
m_log.InfoFormat(
|
||||
"[STARTUP]: Operating system version: {0}, .NET platform {1}, {2}-bit\n",
|
||||
Environment.OSVersion, Environment.OSVersion.Platform, Util.Is64BitProcess() ? "64" : "32");
|
||||
|
||||
{
|
||||
StartupSpecific();
|
||||
|
||||
TimeSpan timeTaken = DateTime.Now - m_startuptime;
|
||||
@@ -153,25 +140,8 @@ namespace OpenSim.Framework.Servers
|
||||
timeTaken.Minutes, timeTaken.Seconds);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should be overriden and referenced by descendents if they need to perform extra shutdown processing
|
||||
/// </summary>
|
||||
public virtual void Shutdown()
|
||||
public string osSecret
|
||||
{
|
||||
ShutdownSpecific();
|
||||
|
||||
m_log.Info("[SHUTDOWN]: Shutdown processing on main thread complete. Exiting...");
|
||||
RemovePIDFile();
|
||||
|
||||
Environment.Exit(0);
|
||||
}
|
||||
|
||||
private void HandleQuit(string module, string[] args)
|
||||
{
|
||||
Shutdown();
|
||||
}
|
||||
|
||||
public string osSecret {
|
||||
// Secret uuid for the simulator
|
||||
get { return m_osSecret; }
|
||||
}
|
||||
|
||||
@@ -54,7 +54,6 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private HttpServerLogWriter httpserverlog = new HttpServerLogWriter();
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// This is a pending websocket request before it got an sucessful upgrade response.
|
||||
/// The consumer must call handler.HandshakeAndUpgrade() to signal to the handler to
|
||||
@@ -81,6 +80,11 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
/// </remarks>
|
||||
public int RequestNumber { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Statistic for holding number of requests processed.
|
||||
/// </summary>
|
||||
private Stat m_requestsProcessedStat;
|
||||
|
||||
private volatile int NotSocketErrors = 0;
|
||||
public volatile bool HTTPDRunning = false;
|
||||
|
||||
@@ -436,9 +440,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
}
|
||||
}
|
||||
|
||||
public void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request)
|
||||
private void OnHandleRequestIOThread(IHttpClientContext context, IHttpRequest request)
|
||||
{
|
||||
|
||||
OSHttpRequest req = new OSHttpRequest(context, request);
|
||||
WebSocketRequestDelegate dWebSocketRequestDelegate = null;
|
||||
lock (m_WebSocketHandlers)
|
||||
@@ -453,9 +456,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
}
|
||||
|
||||
OSHttpResponse resp = new OSHttpResponse(new HttpResponse(context, request),context);
|
||||
|
||||
HandleRequest(req, resp);
|
||||
|
||||
resp.ReuseContext = true;
|
||||
HandleRequest(req, resp);
|
||||
|
||||
// !!!HACK ALERT!!!
|
||||
// There seems to be a bug in the underlying http code that makes subsequent requests
|
||||
@@ -486,7 +488,9 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
try
|
||||
{
|
||||
SendHTML500(response);
|
||||
byte[] buffer500 = SendHTML500(response);
|
||||
response.Body.Write(buffer500,0,buffer500.Length);
|
||||
response.Body.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
@@ -684,7 +688,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
if (buffer != null)
|
||||
{
|
||||
if (!response.SendChunked)
|
||||
if (!response.SendChunked && response.ContentLength64 <= 0)
|
||||
response.ContentLength64 = buffer.LongLength;
|
||||
|
||||
response.OutputStream.Write(buffer, 0, buffer.Length);
|
||||
@@ -719,7 +723,15 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.Error(String.Format("[BASE HTTP SERVER]: HandleRequest() threw {0} ", e.StackTrace), e);
|
||||
SendHTML500(response);
|
||||
try
|
||||
{
|
||||
byte[] buffer500 = SendHTML500(response);
|
||||
response.Body.Write(buffer500, 0, buffer500.Length);
|
||||
response.Body.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -1746,7 +1758,8 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
response.SendChunked = false;
|
||||
response.ContentLength64 = buffer.Length;
|
||||
response.ContentEncoding = Encoding.UTF8;
|
||||
|
||||
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
@@ -1813,6 +1826,21 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
// useful without inbound HTTP.
|
||||
throw e;
|
||||
}
|
||||
|
||||
m_requestsProcessedStat
|
||||
= new Stat(
|
||||
"HTTPRequestsServed",
|
||||
"Number of inbound HTTP requests processed",
|
||||
"",
|
||||
"requests",
|
||||
"httpserver",
|
||||
Port.ToString(),
|
||||
StatType.Pull,
|
||||
MeasuresOfInterest.AverageChangeOverTime,
|
||||
stat => stat.Value = RequestNumber,
|
||||
StatVerbosity.Debug);
|
||||
|
||||
StatsManager.RegisterStat(m_requestsProcessedStat);
|
||||
}
|
||||
|
||||
public void httpServerDisconnectMonitor(IHttpClientContext source, SocketError err)
|
||||
@@ -1843,6 +1871,9 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
public void Stop()
|
||||
{
|
||||
HTTPDRunning = false;
|
||||
|
||||
StatsManager.DeregisterStat(m_requestsProcessedStat);
|
||||
|
||||
try
|
||||
{
|
||||
m_PollServiceManager.Stop();
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the 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.IO;
|
||||
|
||||
namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Base handler for writing to an output stream
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Inheriting classes should override ProcessRequest() rather than Handle()
|
||||
/// </remarks>
|
||||
public abstract class BaseOutputStreamHandler : BaseRequestHandler, IRequestHandler
|
||||
{
|
||||
protected BaseOutputStreamHandler(string httpMethod, string path) : this(httpMethod, path, null, null) {}
|
||||
|
||||
protected BaseOutputStreamHandler(string httpMethod, string path, string name, string description)
|
||||
: base(httpMethod, path, name, description) {}
|
||||
|
||||
public virtual void Handle(
|
||||
string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
RequestsReceived++;
|
||||
|
||||
ProcessRequest(path, request, response, httpRequest, httpResponse);
|
||||
|
||||
RequestsHandled++;
|
||||
}
|
||||
|
||||
protected virtual void ProcessRequest(
|
||||
string path, Stream request, Stream response, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,6 +31,10 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
public abstract class BaseRequestHandler
|
||||
{
|
||||
public int RequestsReceived { get; protected set; }
|
||||
|
||||
public int RequestsHandled { get; protected set; }
|
||||
|
||||
public virtual string ContentType
|
||||
{
|
||||
get { return "application/xml"; }
|
||||
|
||||
@@ -29,14 +29,35 @@ using System.IO;
|
||||
|
||||
namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
/// <summary>
|
||||
/// Base streamed request handler.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Inheriting classes should override ProcessRequest() rather than Handle()
|
||||
/// </remarks>
|
||||
public abstract class BaseStreamHandler : BaseRequestHandler, IStreamedRequestHandler
|
||||
{
|
||||
public abstract byte[] Handle(string path, Stream request,
|
||||
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse);
|
||||
|
||||
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) {}
|
||||
|
||||
public virtual byte[] Handle(
|
||||
string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
RequestsReceived++;
|
||||
|
||||
byte[] result = ProcessRequest(path, request, httpRequest, httpResponse);
|
||||
|
||||
RequestsHandled++;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
protected virtual byte[] ProcessRequest(
|
||||
string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
m_method = binaryMethod;
|
||||
}
|
||||
|
||||
public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
byte[] data = ReadFully(request);
|
||||
string param = GetParam(path);
|
||||
|
||||
@@ -32,7 +32,6 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
public interface IRequestHandler
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Name for this handler.
|
||||
/// </summary>
|
||||
@@ -59,6 +58,19 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
// Return path
|
||||
string Path { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of requests received by this handler
|
||||
/// </summary>
|
||||
int RequestsReceived { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Number of requests handled.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// Should be equal to RequestsReceived unless requested are being handled slowly or there is deadlock.
|
||||
/// </remarks>
|
||||
int RequestsHandled { get; }
|
||||
}
|
||||
|
||||
public interface IStreamedRequestHandler : IRequestHandler
|
||||
@@ -69,7 +81,6 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
public interface IStreamHandler : IRequestHandler
|
||||
{
|
||||
// Handle request stream, return byte array
|
||||
void Handle(string path, Stream request, Stream response, IOSHttpRequest httpReqbuest, IOSHttpResponse httpResponse);
|
||||
}
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
public delegate void RequestMethod(UUID requestID, Hashtable request);
|
||||
public delegate bool HasEventsMethod(UUID requestID, UUID pId);
|
||||
|
||||
public delegate Hashtable GetEventsMethod(UUID requestID, UUID pId, string request);
|
||||
public delegate Hashtable GetEventsMethod(UUID requestID, UUID pId);
|
||||
|
||||
public delegate Hashtable NoEventsMethod(UUID requestID, UUID pId);
|
||||
|
||||
@@ -45,17 +45,28 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
public NoEventsMethod NoEvents;
|
||||
public RequestMethod Request;
|
||||
public UUID Id;
|
||||
public int TimeOutms;
|
||||
public EventType Type;
|
||||
|
||||
public enum EventType : int
|
||||
{
|
||||
Normal = 0,
|
||||
LslHttp = 1,
|
||||
Inventory = 2
|
||||
}
|
||||
|
||||
public PollServiceEventArgs(
|
||||
RequestMethod pRequest,
|
||||
HasEventsMethod pHasEvents, GetEventsMethod pGetEvents, NoEventsMethod pNoEvents,
|
||||
UUID pId)
|
||||
UUID pId, int pTimeOutms)
|
||||
{
|
||||
Request = pRequest;
|
||||
HasEvents = pHasEvents;
|
||||
GetEvents = pGetEvents;
|
||||
NoEvents = pNoEvents;
|
||||
Id = pId;
|
||||
TimeOutms = pTimeOutms;
|
||||
Type = EventType.Normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,54 +33,60 @@ using log4net;
|
||||
using HttpServer;
|
||||
using OpenSim.Framework;
|
||||
using OpenSim.Framework.Monitoring;
|
||||
using Amib.Threading;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
public class PollServiceRequestManager
|
||||
{
|
||||
// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
private readonly BaseHttpServer m_server;
|
||||
private static Queue m_requests = Queue.Synchronized(new Queue());
|
||||
|
||||
private BlockingQueue<PollServiceHttpRequest> m_requests = new BlockingQueue<PollServiceHttpRequest>();
|
||||
private static Queue<PollServiceHttpRequest> m_slowRequests = new Queue<PollServiceHttpRequest>();
|
||||
private static Queue<PollServiceHttpRequest> m_retryRequests = new Queue<PollServiceHttpRequest>();
|
||||
|
||||
private uint m_WorkerThreadCount = 0;
|
||||
private Thread[] m_workerThreads;
|
||||
private PollServiceWorkerThread[] m_PollServiceWorkerThreads;
|
||||
private volatile bool m_running = true;
|
||||
private int m_pollTimeout;
|
||||
private Thread m_retrysThread;
|
||||
|
||||
private bool m_running = true;
|
||||
private int slowCount = 0;
|
||||
|
||||
private SmartThreadPool m_threadPool = new SmartThreadPool(20000, 12, 2);
|
||||
|
||||
// private int m_timeout = 1000; // increase timeout 250; now use the event one
|
||||
|
||||
public PollServiceRequestManager(BaseHttpServer pSrv, uint pWorkerThreadCount, int pTimeout)
|
||||
{
|
||||
m_server = pSrv;
|
||||
m_WorkerThreadCount = pWorkerThreadCount;
|
||||
m_pollTimeout = pTimeout;
|
||||
m_workerThreads = new Thread[m_WorkerThreadCount];
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
m_running = true;
|
||||
m_workerThreads = new Thread[m_WorkerThreadCount];
|
||||
m_PollServiceWorkerThreads = new PollServiceWorkerThread[m_WorkerThreadCount];
|
||||
|
||||
//startup worker threads
|
||||
for (uint i = 0; i < m_WorkerThreadCount; i++)
|
||||
{
|
||||
m_PollServiceWorkerThreads[i] = new PollServiceWorkerThread(m_server, m_pollTimeout);
|
||||
m_PollServiceWorkerThreads[i].ReQueue += ReQueueEvent;
|
||||
|
||||
m_workerThreads[i]
|
||||
= Watchdog.StartThread(
|
||||
m_PollServiceWorkerThreads[i].ThreadStart,
|
||||
String.Format("PollServiceWorkerThread{0}", i),
|
||||
PoolWorkerJob,
|
||||
string.Format("PollServiceWorkerThread{0}:{1}", i, m_server.Port),
|
||||
ThreadPriority.Normal,
|
||||
false,
|
||||
true,
|
||||
false,
|
||||
null,
|
||||
int.MaxValue);
|
||||
}
|
||||
|
||||
Watchdog.StartThread(
|
||||
this.ThreadStart,
|
||||
"PollServiceWatcherThread",
|
||||
m_retrysThread = Watchdog.StartThread(
|
||||
this.CheckRetries,
|
||||
string.Format("PollServiceWatcherThread:{0}", m_server.Port),
|
||||
ThreadPriority.Normal,
|
||||
false,
|
||||
true,
|
||||
@@ -88,78 +94,210 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
1000 * 60 * 10);
|
||||
}
|
||||
|
||||
internal void ReQueueEvent(PollServiceHttpRequest req)
|
||||
private void ReQueueEvent(PollServiceHttpRequest req)
|
||||
{
|
||||
// Do accounting stuff here
|
||||
Enqueue(req);
|
||||
if (m_running)
|
||||
{
|
||||
lock (m_retryRequests)
|
||||
m_retryRequests.Enqueue(req);
|
||||
}
|
||||
}
|
||||
|
||||
public void Enqueue(PollServiceHttpRequest req)
|
||||
{
|
||||
lock (m_requests)
|
||||
m_requests.Enqueue(req);
|
||||
if (m_running)
|
||||
{
|
||||
if (req.PollServiceArgs.Type != PollServiceEventArgs.EventType.Normal)
|
||||
{
|
||||
m_requests.Enqueue(req);
|
||||
}
|
||||
else
|
||||
{
|
||||
lock (m_slowRequests)
|
||||
m_slowRequests.Enqueue(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ThreadStart()
|
||||
private void CheckRetries()
|
||||
{
|
||||
while (m_running)
|
||||
{
|
||||
Thread.Sleep(100); // let the world move .. back to faster rate
|
||||
Watchdog.UpdateThread();
|
||||
ProcessQueuedRequests();
|
||||
Thread.Sleep(1000);
|
||||
}
|
||||
}
|
||||
|
||||
private void ProcessQueuedRequests()
|
||||
{
|
||||
lock (m_requests)
|
||||
{
|
||||
if (m_requests.Count == 0)
|
||||
return;
|
||||
|
||||
// m_log.DebugFormat("[POLL SERVICE REQUEST MANAGER]: Processing {0} requests", m_requests.Count);
|
||||
|
||||
int reqperthread = (int) (m_requests.Count/m_WorkerThreadCount) + 1;
|
||||
|
||||
// For Each WorkerThread
|
||||
for (int tc = 0; tc < m_WorkerThreadCount && m_requests.Count > 0; tc++)
|
||||
lock (m_retryRequests)
|
||||
{
|
||||
//Loop over number of requests each thread handles.
|
||||
for (int i = 0; i < reqperthread && m_requests.Count > 0; i++)
|
||||
while (m_retryRequests.Count > 0 && m_running)
|
||||
m_requests.Enqueue(m_retryRequests.Dequeue());
|
||||
}
|
||||
slowCount++;
|
||||
if (slowCount >= 10)
|
||||
{
|
||||
slowCount = 0;
|
||||
|
||||
lock (m_slowRequests)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_PollServiceWorkerThreads[tc].Enqueue((PollServiceHttpRequest)m_requests.Dequeue());
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
// The queue is empty, we did our calculations wrong!
|
||||
return;
|
||||
}
|
||||
|
||||
while (m_slowRequests.Count > 0 && m_running)
|
||||
m_requests.Enqueue(m_slowRequests.Dequeue());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
m_running = false;
|
||||
// m_timeout = -10000; // cause all to expire
|
||||
Thread.Sleep(1000); // let the world move
|
||||
|
||||
foreach (object o in m_requests)
|
||||
foreach (Thread t in m_workerThreads)
|
||||
Watchdog.AbortThread(t.ManagedThreadId);
|
||||
|
||||
try
|
||||
{
|
||||
PollServiceHttpRequest req = (PollServiceHttpRequest) o;
|
||||
PollServiceWorkerThread.DoHTTPGruntWork(
|
||||
m_server, req, req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
|
||||
foreach (PollServiceHttpRequest req in m_retryRequests)
|
||||
{
|
||||
DoHTTPGruntWork(m_server,req,
|
||||
req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
|
||||
PollServiceHttpRequest wreq;
|
||||
m_retryRequests.Clear();
|
||||
|
||||
lock (m_slowRequests)
|
||||
{
|
||||
while (m_slowRequests.Count > 0 && m_running)
|
||||
m_requests.Enqueue(m_slowRequests.Dequeue());
|
||||
}
|
||||
|
||||
while (m_requests.Count() > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
wreq = m_requests.Dequeue(0);
|
||||
DoHTTPGruntWork(m_server,wreq,
|
||||
wreq.PollServiceArgs.NoEvents(wreq.RequestID, wreq.PollServiceArgs.Id));
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
m_requests.Clear();
|
||||
}
|
||||
|
||||
foreach (Thread t in m_workerThreads)
|
||||
// work threads
|
||||
|
||||
private void PoolWorkerJob()
|
||||
{
|
||||
while (m_running)
|
||||
{
|
||||
t.Abort();
|
||||
PollServiceHttpRequest req = m_requests.Dequeue(5000);
|
||||
|
||||
Watchdog.UpdateThread();
|
||||
if (req != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id))
|
||||
{
|
||||
Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id);
|
||||
|
||||
if (responsedata == null)
|
||||
continue;
|
||||
|
||||
if (req.PollServiceArgs.Type == PollServiceEventArgs.EventType.Normal) // This is the event queue
|
||||
{
|
||||
try
|
||||
{
|
||||
DoHTTPGruntWork(m_server, req, responsedata);
|
||||
}
|
||||
catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream
|
||||
{
|
||||
// Ignore it, no need to reply
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_threadPool.QueueWorkItem(x =>
|
||||
{
|
||||
try
|
||||
{
|
||||
DoHTTPGruntWork(m_server, req, responsedata);
|
||||
}
|
||||
catch (ObjectDisposedException) // Browser aborted before we could read body, server closed the stream
|
||||
{
|
||||
// Ignore it, no need to reply
|
||||
}
|
||||
|
||||
return null;
|
||||
}, null);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((Environment.TickCount - req.RequestTime) > req.PollServiceArgs.TimeOutms)
|
||||
{
|
||||
DoHTTPGruntWork(m_server, req,
|
||||
req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
|
||||
}
|
||||
else
|
||||
{
|
||||
ReQueueEvent(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat("Exception in poll service thread: " + e.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// DoHTTPGruntWork changed, not sending response
|
||||
// do the same work around as core
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) Contributors, http://opensimulator.org/
|
||||
* See CONTRIBUTORS.TXT for a full list of copyright holders.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of the OpenSimulator Project nor the
|
||||
* names of its contributors may be used to endorse or promote products
|
||||
* derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
|
||||
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
* DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
|
||||
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using HttpServer;
|
||||
using OpenMetaverse;
|
||||
using System.Reflection;
|
||||
using log4net;
|
||||
using OpenSim.Framework.Monitoring;
|
||||
|
||||
namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
public delegate void ReQueuePollServiceItem(PollServiceHttpRequest req);
|
||||
|
||||
public class PollServiceWorkerThread
|
||||
{
|
||||
private static readonly ILog m_log =
|
||||
LogManager.GetLogger(
|
||||
MethodBase.GetCurrentMethod().DeclaringType);
|
||||
|
||||
public event ReQueuePollServiceItem ReQueue;
|
||||
|
||||
private readonly BaseHttpServer m_server;
|
||||
private BlockingQueue<PollServiceHttpRequest> m_request;
|
||||
private bool m_running = true;
|
||||
private int m_timeout = 250;
|
||||
|
||||
public PollServiceWorkerThread(BaseHttpServer pSrv, int pTimeout)
|
||||
{
|
||||
m_request = new BlockingQueue<PollServiceHttpRequest>();
|
||||
m_server = pSrv;
|
||||
m_timeout = pTimeout;
|
||||
}
|
||||
|
||||
public void ThreadStart()
|
||||
{
|
||||
Run();
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
while (m_running)
|
||||
{
|
||||
PollServiceHttpRequest req = m_request.Dequeue();
|
||||
|
||||
Watchdog.UpdateThread();
|
||||
|
||||
try
|
||||
{
|
||||
if (req.PollServiceArgs.HasEvents(req.RequestID, req.PollServiceArgs.Id))
|
||||
{
|
||||
StreamReader str;
|
||||
try
|
||||
{
|
||||
str = new StreamReader(req.Request.Body);
|
||||
}
|
||||
catch (System.ArgumentException)
|
||||
{
|
||||
// Stream was not readable means a child agent
|
||||
// was closed due to logout, leaving the
|
||||
// Event Queue request orphaned.
|
||||
continue;
|
||||
}
|
||||
|
||||
Hashtable responsedata = req.PollServiceArgs.GetEvents(req.RequestID, req.PollServiceArgs.Id, str.ReadToEnd());
|
||||
DoHTTPGruntWork(m_server, req, responsedata);
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((Environment.TickCount - req.RequestTime) > m_timeout)
|
||||
{
|
||||
DoHTTPGruntWork(
|
||||
m_server,
|
||||
req,
|
||||
req.PollServiceArgs.NoEvents(req.RequestID, req.PollServiceArgs.Id));
|
||||
}
|
||||
else
|
||||
{
|
||||
ReQueuePollServiceItem reQueueItem = ReQueue;
|
||||
if (reQueueItem != null)
|
||||
reQueueItem(req);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
m_log.ErrorFormat("Exception in poll service thread: " + e.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal void Enqueue(PollServiceHttpRequest pPollServiceHttpRequest)
|
||||
{
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
public delegate TResponse RestDeserialiseMethod<TRequest, TResponse>(TRequest request);
|
||||
|
||||
public class RestDeserialiseHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler
|
||||
public class RestDeserialiseHandler<TRequest, TResponse> : BaseOutputStreamHandler, IStreamHandler
|
||||
where TRequest : new()
|
||||
{
|
||||
private RestDeserialiseMethod<TRequest, TResponse> m_method;
|
||||
@@ -48,7 +48,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
m_method = method;
|
||||
}
|
||||
|
||||
public void Handle(string path, Stream request, Stream responseStream,
|
||||
protected override void ProcessRequest(string path, Stream request, Stream responseStream,
|
||||
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
TRequest deserial;
|
||||
|
||||
@@ -183,7 +183,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
public delegate bool CheckIdentityMethod(string sid, string aid);
|
||||
|
||||
public class RestDeserialiseSecureHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler
|
||||
public class RestDeserialiseSecureHandler<TRequest, TResponse> : BaseOutputStreamHandler, IStreamHandler
|
||||
where TRequest : new()
|
||||
{
|
||||
private static readonly ILog m_log
|
||||
@@ -201,7 +201,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
m_method = method;
|
||||
}
|
||||
|
||||
public void Handle(string path, Stream request, Stream responseStream,
|
||||
protected override void ProcessRequest(string path, Stream request, Stream responseStream,
|
||||
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
RestSessionObject<TRequest> deserial = default(RestSessionObject<TRequest>);
|
||||
@@ -237,7 +237,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
|
||||
public delegate bool CheckTrustedSourceMethod(IPEndPoint peer);
|
||||
|
||||
public class RestDeserialiseTrustedHandler<TRequest, TResponse> : BaseRequestHandler, IStreamHandler
|
||||
public class RestDeserialiseTrustedHandler<TRequest, TResponse> : BaseOutputStreamHandler, IStreamHandler
|
||||
where TRequest : new()
|
||||
{
|
||||
private static readonly ILog m_log
|
||||
@@ -260,7 +260,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
m_method = method;
|
||||
}
|
||||
|
||||
public void Handle(string path, Stream request, Stream responseStream,
|
||||
protected override void ProcessRequest(string path, Stream request, Stream responseStream,
|
||||
IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
TRequest deserial = default(TRequest);
|
||||
@@ -292,6 +292,5 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
serializer.Serialize(xmlWriter, response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -48,7 +48,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
m_restMethod = restMethod;
|
||||
}
|
||||
|
||||
public override byte[] Handle(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
protected override byte[] ProcessRequest(string path, Stream request, IOSHttpRequest httpRequest, IOSHttpResponse httpResponse)
|
||||
{
|
||||
Encoding encoding = Encoding.UTF8;
|
||||
StreamReader streamReader = new StreamReader(request, encoding);
|
||||
|
||||
@@ -75,7 +75,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
/// <summary>
|
||||
/// This is a regular HTTP Request... This may be removed in the future.
|
||||
/// </summary>
|
||||
public event RegularHttpRequestDelegate OnRegularHttpRequest;
|
||||
// public event RegularHttpRequestDelegate OnRegularHttpRequest;
|
||||
|
||||
/// <summary>
|
||||
/// When the upgrade from a HTTP request to a Websocket is completed, this will be fired
|
||||
@@ -304,15 +304,14 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
if (d != null)
|
||||
d(this, new UpgradeCompletedEventArgs());
|
||||
}
|
||||
catch (IOException fail)
|
||||
catch (IOException)
|
||||
{
|
||||
Close(string.Empty);
|
||||
}
|
||||
catch (ObjectDisposedException fail)
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
Close(string.Empty);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -414,8 +413,6 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
_socketState.Header = pheader;
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (_socketState.FrameComplete)
|
||||
{
|
||||
ProcessFrame(_socketState);
|
||||
@@ -424,7 +421,6 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
_socketState.ExpectedBytes = 0;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -457,8 +453,7 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
_socketState.ReceivedBytes.Clear();
|
||||
_socketState.ExpectedBytes = 0;
|
||||
// do some processing
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (offset > 0)
|
||||
@@ -477,13 +472,12 @@ namespace OpenSim.Framework.Servers.HttpServer
|
||||
{
|
||||
// We can't read the stream anymore...
|
||||
}
|
||||
|
||||
}
|
||||
catch (IOException fail)
|
||||
catch (IOException)
|
||||
{
|
||||
Close(string.Empty);
|
||||
}
|
||||
catch (ObjectDisposedException fail)
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
Close(string.Empty);
|
||||
}
|
||||
|
||||
@@ -121,12 +121,14 @@ namespace OpenSim.Framework.Servers
|
||||
+ " level >= 2 then long warnings are logged when receiving bad input data.\n"
|
||||
+ " level >= 3 then short notices about all incoming non-poll HTTP requests are logged.\n"
|
||||
+ " level >= 4 then the time taken to fulfill the request is logged.\n"
|
||||
+ " level >= 5 then a sample from the beginning of the incoming data is logged.\n"
|
||||
+ " level >= 6 then the entire incoming data is logged.\n"
|
||||
+ " level >= 5 then a sample from the beginning of the data is logged.\n"
|
||||
+ " level >= 6 then the entire data is logged.\n"
|
||||
+ " no level is specified then the current level is returned.\n\n"
|
||||
+ "If out or all and\n"
|
||||
+ " level >= 3 then short notices about all outgoing requests going through WebUtil are logged.\n"
|
||||
+ " level >= 4 then the time taken to fulfill the request is logged.\n",
|
||||
+ " level >= 4 then the time taken to fulfill the request is logged.\n"
|
||||
+ " level >= 5 then a sample from the beginning of the data is logged.\n"
|
||||
+ " level >= 6 then the entire data is logged.\n",
|
||||
HandleDebugHttpCommand);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,6 +62,8 @@ namespace OpenSim.Framework.Servers
|
||||
|
||||
protected string m_pidFile = String.Empty;
|
||||
|
||||
protected ServerStatsCollector m_serverStatsCollector;
|
||||
|
||||
/// <summary>
|
||||
/// Server version information. Usually VersionInfo + information about git commit, operating system, etc.
|
||||
/// </summary>
|
||||
@@ -76,6 +78,11 @@ namespace OpenSim.Framework.Servers
|
||||
|
||||
protected void CreatePIDFile(string path)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
m_log.ErrorFormat(
|
||||
"[SERVER BASE]: Previous pid file {0} still exists on startup. Possibly previously unclean shutdown.",
|
||||
path);
|
||||
|
||||
try
|
||||
{
|
||||
string pidstring = System.Diagnostics.Process.GetCurrentProcess().Id.ToString();
|
||||
@@ -113,6 +120,26 @@ namespace OpenSim.Framework.Servers
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Log information about the circumstances in which we're running (OpenSimulator version number, CLR details,
|
||||
/// etc.).
|
||||
/// </summary>
|
||||
public void LogEnvironmentInformation()
|
||||
{
|
||||
// FIXME: This should be done down in ServerBase but we need to sort out and refactor the log4net
|
||||
// XmlConfigurator calls first accross servers.
|
||||
m_log.InfoFormat("[SERVER BASE]: Starting in {0}", m_startupDirectory);
|
||||
|
||||
m_log.InfoFormat("[SERVER BASE]: OpenSimulator version: {0}", m_version);
|
||||
|
||||
// clr version potentially is more confusing than helpful, since it doesn't tell us if we're running under Mono/MS .NET and
|
||||
// the clr version number doesn't match the project version number under Mono.
|
||||
//m_log.Info("[STARTUP]: Virtual machine runtime version: " + Environment.Version + Environment.NewLine);
|
||||
m_log.InfoFormat(
|
||||
"[SERVER BASE]: Operating system version: {0}, .NET platform {1}, {2}-bit",
|
||||
Environment.OSVersion, Environment.OSVersion.Platform, Util.Is64BitProcess() ? "64" : "32");
|
||||
}
|
||||
|
||||
public void RegisterCommonAppenders(IConfig startupConfig)
|
||||
{
|
||||
ILoggerRepository repository = LogManager.GetRepository();
|
||||
@@ -234,6 +261,25 @@ namespace OpenSim.Framework.Servers
|
||||
"force gc",
|
||||
"Manually invoke runtime garbage collection. For debugging purposes",
|
||||
HandleForceGc);
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"General", false, "quit",
|
||||
"quit",
|
||||
"Quit the application", (mod, args) => Shutdown());
|
||||
|
||||
m_console.Commands.AddCommand(
|
||||
"General", false, "shutdown",
|
||||
"shutdown",
|
||||
"Quit the application", (mod, args) => Shutdown());
|
||||
|
||||
StatsManager.RegisterConsoleCommands(m_console);
|
||||
}
|
||||
|
||||
public void RegisterCommonComponents(IConfigSource configSource)
|
||||
{
|
||||
m_serverStatsCollector = new ServerStatsCollector();
|
||||
m_serverStatsCollector.Initialise(configSource);
|
||||
m_serverStatsCollector.Start();
|
||||
}
|
||||
|
||||
private void HandleForceGc(string module, string[] args)
|
||||
@@ -621,7 +667,68 @@ namespace OpenSim.Framework.Servers
|
||||
sb.AppendFormat("Total threads active: {0}\n\n", totalThreads);
|
||||
|
||||
sb.Append("Main threadpool (excluding script engine pools)\n");
|
||||
sb.Append(Util.GetThreadPoolReport());
|
||||
sb.Append(GetThreadPoolReport());
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
/// <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 (Util.FireAndForgetMethod == FireAndForgetMethod.SmartThreadPool)
|
||||
{
|
||||
STPInfo stpi = Util.GetSmartThreadPoolInfo();
|
||||
|
||||
// ROBUST currently leaves this the FireAndForgetMethod but never actually initializes the threadpool.
|
||||
if (stpi != null)
|
||||
{
|
||||
threadPoolUsed = "SmartThreadPool";
|
||||
maxThreads = stpi.MaxThreads;
|
||||
minThreads = stpi.MinThreads;
|
||||
inUseThreads = stpi.InUseThreads;
|
||||
allocatedThreads = stpi.ActiveThreads;
|
||||
waitingCallbacks = stpi.WaitingCallbacks;
|
||||
}
|
||||
}
|
||||
else if (
|
||||
Util.FireAndForgetMethod == FireAndForgetMethod.QueueUserWorkItem
|
||||
|| Util.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();
|
||||
}
|
||||
@@ -673,5 +780,16 @@ namespace OpenSim.Framework.Servers
|
||||
if (m_console != null)
|
||||
m_console.OutputFormat(format, components);
|
||||
}
|
||||
|
||||
public virtual void Shutdown()
|
||||
{
|
||||
m_serverStatsCollector.Close();
|
||||
ShutdownSpecific();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Should be overriden and referenced by descendents if they need to perform extra shutdown processing
|
||||
/// </summary>
|
||||
protected virtual void ShutdownSpecific() {}
|
||||
}
|
||||
}
|
||||
@@ -100,7 +100,7 @@ namespace OpenSim.Framework.Tests
|
||||
cadu.AVHeight = Size1.Z;
|
||||
|
||||
AgentPosition position2 = new AgentPosition();
|
||||
position2.CopyFrom(cadu);
|
||||
position2.CopyFrom(cadu, position1.SessionID);
|
||||
|
||||
Assert.IsTrue(
|
||||
position2.AgentID == position1.AgentID
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user