diff options
Diffstat (limited to 'OpenSim/Region/Environment/Modules/Scripting')
6 files changed, 2423 insertions, 0 deletions
diff --git a/OpenSim/Region/Environment/Modules/Scripting/DynamicTexture/DynamicTextureModule.cs b/OpenSim/Region/Environment/Modules/Scripting/DynamicTexture/DynamicTextureModule.cs new file mode 100644 index 0000000..63eee97 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/Scripting/DynamicTexture/DynamicTextureModule.cs | |||
@@ -0,0 +1,277 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSim Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Drawing; | ||
31 | using System.Drawing.Imaging; | ||
32 | using libsecondlife; | ||
33 | using Nini.Config; | ||
34 | using OpenJPEGNet; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Region.Environment.Interfaces; | ||
37 | using OpenSim.Region.Environment.Scenes; | ||
38 | |||
39 | namespace OpenSim.Region.Environment.Modules.Scripting.DynamicTexture | ||
40 | { | ||
41 | public class DynamicTextureModule : IRegionModule, IDynamicTextureManager | ||
42 | { | ||
43 | private Dictionary<LLUUID, Scene> RegisteredScenes = new Dictionary<LLUUID, Scene>(); | ||
44 | |||
45 | private Dictionary<string, IDynamicTextureRender> RenderPlugins = | ||
46 | new Dictionary<string, IDynamicTextureRender>(); | ||
47 | |||
48 | private Dictionary<LLUUID, DynamicTextureUpdater> Updaters = new Dictionary<LLUUID, DynamicTextureUpdater>(); | ||
49 | |||
50 | public void Initialise(Scene scene, IConfigSource config) | ||
51 | { | ||
52 | if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID)) | ||
53 | { | ||
54 | RegisteredScenes.Add(scene.RegionInfo.RegionID, scene); | ||
55 | scene.RegisterModuleInterface<IDynamicTextureManager>(this); | ||
56 | } | ||
57 | } | ||
58 | |||
59 | public void PostInitialise() | ||
60 | { | ||
61 | } | ||
62 | |||
63 | public void Close() | ||
64 | { | ||
65 | } | ||
66 | |||
67 | public string Name | ||
68 | { | ||
69 | get { return "DynamicTextureModule"; } | ||
70 | } | ||
71 | |||
72 | public bool IsSharedModule | ||
73 | { | ||
74 | get { return true; } | ||
75 | } | ||
76 | |||
77 | public void RegisterRender(string handleType, IDynamicTextureRender render) | ||
78 | { | ||
79 | if (!RenderPlugins.ContainsKey(handleType)) | ||
80 | { | ||
81 | RenderPlugins.Add(handleType, render); | ||
82 | } | ||
83 | } | ||
84 | |||
85 | public void ReturnData(LLUUID id, byte[] data) | ||
86 | { | ||
87 | if (Updaters.ContainsKey(id)) | ||
88 | { | ||
89 | DynamicTextureUpdater updater = Updaters[id]; | ||
90 | if (RegisteredScenes.ContainsKey(updater.SimUUID)) | ||
91 | { | ||
92 | Scene scene = RegisteredScenes[updater.SimUUID]; | ||
93 | updater.DataReceived(data, scene); | ||
94 | } | ||
95 | } | ||
96 | } | ||
97 | |||
98 | |||
99 | public LLUUID AddDynamicTextureURL(LLUUID simID, LLUUID primID, string contentType, string url, | ||
100 | string extraParams, int updateTimer) | ||
101 | { | ||
102 | return AddDynamicTextureURL(simID, primID, contentType, url, extraParams, updateTimer, false, 255); | ||
103 | } | ||
104 | |||
105 | public LLUUID AddDynamicTextureURL(LLUUID simID, LLUUID primID, string contentType, string url, | ||
106 | string extraParams, int updateTimer, bool SetBlending, byte AlphaValue) | ||
107 | { | ||
108 | if (RenderPlugins.ContainsKey(contentType)) | ||
109 | { | ||
110 | //Console.WriteLine("dynamic texture being created: " + url + " of type " + contentType); | ||
111 | |||
112 | DynamicTextureUpdater updater = new DynamicTextureUpdater(); | ||
113 | updater.SimUUID = simID; | ||
114 | updater.PrimID = primID; | ||
115 | updater.ContentType = contentType; | ||
116 | updater.Url = url; | ||
117 | updater.UpdateTimer = updateTimer; | ||
118 | updater.UpdaterID = LLUUID.Random(); | ||
119 | updater.Params = extraParams; | ||
120 | updater.BlendWithOldTexture = SetBlending; | ||
121 | updater.FrontAlpha = AlphaValue; | ||
122 | |||
123 | if (!Updaters.ContainsKey(updater.UpdaterID)) | ||
124 | { | ||
125 | Updaters.Add(updater.UpdaterID, updater); | ||
126 | } | ||
127 | |||
128 | RenderPlugins[contentType].AsyncConvertUrl(updater.UpdaterID, url, extraParams); | ||
129 | return updater.UpdaterID; | ||
130 | } | ||
131 | return LLUUID.Zero; | ||
132 | } | ||
133 | |||
134 | public LLUUID AddDynamicTextureData(LLUUID simID, LLUUID primID, string contentType, string data, | ||
135 | string extraParams, int updateTimer) | ||
136 | { | ||
137 | return AddDynamicTextureData(simID, primID, contentType, data, extraParams, updateTimer, false, 255); | ||
138 | } | ||
139 | |||
140 | public LLUUID AddDynamicTextureData(LLUUID simID, LLUUID primID, string contentType, string data, | ||
141 | string extraParams, int updateTimer, bool SetBlending, byte AlphaValue) | ||
142 | { | ||
143 | if (RenderPlugins.ContainsKey(contentType)) | ||
144 | { | ||
145 | DynamicTextureUpdater updater = new DynamicTextureUpdater(); | ||
146 | updater.SimUUID = simID; | ||
147 | updater.PrimID = primID; | ||
148 | updater.ContentType = contentType; | ||
149 | updater.BodyData = data; | ||
150 | updater.UpdateTimer = updateTimer; | ||
151 | updater.UpdaterID = LLUUID.Random(); | ||
152 | updater.Params = extraParams; | ||
153 | updater.BlendWithOldTexture = SetBlending; | ||
154 | updater.FrontAlpha = AlphaValue; | ||
155 | |||
156 | if (!Updaters.ContainsKey(updater.UpdaterID)) | ||
157 | { | ||
158 | Updaters.Add(updater.UpdaterID, updater); | ||
159 | } | ||
160 | |||
161 | RenderPlugins[contentType].AsyncConvertData(updater.UpdaterID, data, extraParams); | ||
162 | return updater.UpdaterID; | ||
163 | } | ||
164 | return LLUUID.Zero; | ||
165 | } | ||
166 | |||
167 | public class DynamicTextureUpdater | ||
168 | { | ||
169 | public LLUUID SimUUID; | ||
170 | public LLUUID UpdaterID; | ||
171 | public string ContentType; | ||
172 | public string Url; | ||
173 | public string BodyData; | ||
174 | public LLUUID PrimID; | ||
175 | public int UpdateTimer; | ||
176 | public LLUUID LastAssetID; | ||
177 | public string Params; | ||
178 | public bool BlendWithOldTexture = false; | ||
179 | public bool SetNewFrontAlpha = false; | ||
180 | public byte FrontAlpha = 255; | ||
181 | |||
182 | public DynamicTextureUpdater() | ||
183 | { | ||
184 | LastAssetID = LLUUID.Zero; | ||
185 | UpdateTimer = 0; | ||
186 | BodyData = null; | ||
187 | } | ||
188 | |||
189 | public void DataReceived(byte[] data, Scene scene) | ||
190 | { | ||
191 | SceneObjectPart part = scene.GetSceneObjectPart(PrimID); | ||
192 | byte[] assetData; | ||
193 | AssetBase oldAsset = null; | ||
194 | if (BlendWithOldTexture) | ||
195 | { | ||
196 | LLUUID lastTextureID = part.Shape.Textures.DefaultTexture.TextureID; | ||
197 | oldAsset = scene.AssetCache.GetAsset(lastTextureID, true); | ||
198 | if (oldAsset != null) | ||
199 | { | ||
200 | assetData = BlendTextures(data, oldAsset.Data, SetNewFrontAlpha, FrontAlpha); | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | assetData = new byte[data.Length]; | ||
205 | Array.Copy(data, assetData, data.Length); | ||
206 | } | ||
207 | } | ||
208 | else | ||
209 | { | ||
210 | assetData = new byte[data.Length]; | ||
211 | Array.Copy(data, assetData, data.Length); | ||
212 | } | ||
213 | |||
214 | //TODO delete the last asset(data), if it was a dynamic texture | ||
215 | AssetBase asset = new AssetBase(); | ||
216 | asset.FullID = LLUUID.Random(); | ||
217 | asset.Data = assetData; | ||
218 | asset.Name = "DynamicImage" + Util.RandomClass.Next(1, 10000); | ||
219 | asset.Type = 0; | ||
220 | asset.Description = "dynamic image"; | ||
221 | asset.Local = false; | ||
222 | asset.Temporary = true; | ||
223 | scene.AssetCache.AddAsset(asset); | ||
224 | |||
225 | LastAssetID = asset.FullID; | ||
226 | |||
227 | |||
228 | part.Shape.Textures = new LLObject.TextureEntry(asset.FullID); | ||
229 | part.ScheduleFullUpdate(); | ||
230 | } | ||
231 | |||
232 | // TODO: unused | ||
233 | // private byte[] BlendTextures(byte[] frontImage, byte[] backImage) | ||
234 | // { | ||
235 | // return BlendTextures(frontImage, backImage, false, 0); | ||
236 | // } | ||
237 | |||
238 | private byte[] BlendTextures(byte[] frontImage, byte[] backImage, bool setNewAlpha, byte newAlpha) | ||
239 | { | ||
240 | Bitmap image1 = new Bitmap(OpenJPEG.DecodeToImage(frontImage)); | ||
241 | Bitmap image2 = new Bitmap(OpenJPEG.DecodeToImage(backImage)); | ||
242 | if (setNewAlpha) | ||
243 | { | ||
244 | SetAlpha(ref image1, newAlpha); | ||
245 | } | ||
246 | Bitmap joint = MergeBitMaps(image1, image2); | ||
247 | |||
248 | return OpenJPEG.EncodeFromImage(joint, true); | ||
249 | } | ||
250 | |||
251 | public Bitmap MergeBitMaps(Bitmap front, Bitmap back) | ||
252 | { | ||
253 | Bitmap joint; | ||
254 | Graphics jG; | ||
255 | |||
256 | joint = new Bitmap(back.Width, back.Height, PixelFormat.Format32bppArgb); | ||
257 | jG = Graphics.FromImage(joint); | ||
258 | |||
259 | jG.DrawImage(back, 0, 0, back.Width, back.Height); | ||
260 | jG.DrawImage(front, 0, 0, back.Width, back.Height); | ||
261 | |||
262 | return joint; | ||
263 | } | ||
264 | |||
265 | private void SetAlpha(ref Bitmap b, byte alpha) | ||
266 | { | ||
267 | for (int w = 0; w < b.Width; w++) | ||
268 | { | ||
269 | for (int h = 0; h < b.Height; h++) | ||
270 | { | ||
271 | b.SetPixel(w, h, Color.FromArgb(alpha, b.GetPixel(w, h))); | ||
272 | } | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | } | ||
277 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Environment/Modules/Scripting/HttpRequest/ScriptsHttpRequests.cs b/OpenSim/Region/Environment/Modules/Scripting/HttpRequest/ScriptsHttpRequests.cs new file mode 100644 index 0000000..4977a86 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/Scripting/HttpRequest/ScriptsHttpRequests.cs | |||
@@ -0,0 +1,356 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSim Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Net; | ||
32 | using System.Text; | ||
33 | using System.Threading; | ||
34 | using libsecondlife; | ||
35 | using Nini.Config; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Environment.Interfaces; | ||
38 | using OpenSim.Region.Environment.Scenes; | ||
39 | |||
40 | /***************************************************** | ||
41 | * | ||
42 | * ScriptsHttpRequests | ||
43 | * | ||
44 | * Implements the llHttpRequest and http_response | ||
45 | * callback. | ||
46 | * | ||
47 | * Some stuff was already in LSLLongCmdHandler, and then | ||
48 | * there was this file with a stub class in it. So, | ||
49 | * I am moving some of the objects and functions out of | ||
50 | * LSLLongCmdHandler, such as the HttpRequestClass, the | ||
51 | * start and stop methods, and setting up pending and | ||
52 | * completed queues. These are processed in the | ||
53 | * LSLLongCmdHandler polling loop. Similiar to the | ||
54 | * XMLRPCModule, since that seems to work. | ||
55 | * | ||
56 | * //TODO | ||
57 | * | ||
58 | * This probably needs some throttling mechanism but | ||
59 | * its wide open right now. This applies to both | ||
60 | * number of requests and data volume. | ||
61 | * | ||
62 | * Linden puts all kinds of header fields in the requests. | ||
63 | * Not doing any of that: | ||
64 | * User-Agent | ||
65 | * X-SecondLife-Shard | ||
66 | * X-SecondLife-Object-Name | ||
67 | * X-SecondLife-Object-Key | ||
68 | * X-SecondLife-Region | ||
69 | * X-SecondLife-Local-Position | ||
70 | * X-SecondLife-Local-Velocity | ||
71 | * X-SecondLife-Local-Rotation | ||
72 | * X-SecondLife-Owner-Name | ||
73 | * X-SecondLife-Owner-Key | ||
74 | * | ||
75 | * HTTPS support | ||
76 | * | ||
77 | * Configurable timeout? | ||
78 | * Configurable max repsonse size? | ||
79 | * Configurable | ||
80 | * | ||
81 | * **************************************************/ | ||
82 | |||
83 | namespace OpenSim.Region.Environment.Modules.Scripting.HttpRequest | ||
84 | { | ||
85 | public class HttpRequestModule : IRegionModule, IHttpRequests | ||
86 | { | ||
87 | private Scene m_scene; | ||
88 | private Queue<HttpRequestClass> rpcQueue = new Queue<HttpRequestClass>(); | ||
89 | private object HttpListLock = new object(); | ||
90 | private string m_name = "HttpScriptRequests"; | ||
91 | private int httpTimeout = 30000; | ||
92 | |||
93 | // <request id, HttpRequestClass> | ||
94 | private Dictionary<LLUUID, HttpRequestClass> m_pendingRequests; | ||
95 | |||
96 | public HttpRequestModule() | ||
97 | { | ||
98 | } | ||
99 | |||
100 | public void Initialise(Scene scene, IConfigSource config) | ||
101 | { | ||
102 | m_scene = scene; | ||
103 | |||
104 | m_scene.RegisterModuleInterface<IHttpRequests>(this); | ||
105 | |||
106 | m_pendingRequests = new Dictionary<LLUUID, HttpRequestClass>(); | ||
107 | } | ||
108 | |||
109 | public void PostInitialise() | ||
110 | { | ||
111 | } | ||
112 | |||
113 | public void Close() | ||
114 | { | ||
115 | } | ||
116 | |||
117 | public string Name | ||
118 | { | ||
119 | get { return m_name; } | ||
120 | } | ||
121 | |||
122 | public bool IsSharedModule | ||
123 | { | ||
124 | get { return true; } | ||
125 | } | ||
126 | |||
127 | public LLUUID MakeHttpRequest(string url, string parameters, string body) | ||
128 | { | ||
129 | return LLUUID.Zero; | ||
130 | } | ||
131 | |||
132 | public LLUUID StartHttpRequest(uint localID, LLUUID itemID, string url, List<string> parameters, string body) | ||
133 | { | ||
134 | LLUUID reqID = LLUUID.Random(); | ||
135 | HttpRequestClass htc = new HttpRequestClass(); | ||
136 | |||
137 | // Partial implementation: support for parameter flags needed | ||
138 | // see http://wiki.secondlife.com/wiki/LlHTTPRequest | ||
139 | // | ||
140 | // Parameters are expected in {key, value, ... , key, value} | ||
141 | if (parameters != null) | ||
142 | { | ||
143 | string[] parms = parameters.ToArray(); | ||
144 | for (int i = 0; i < parms.Length/2; i += 2) | ||
145 | { | ||
146 | switch (Int32.Parse(parms[i])) | ||
147 | { | ||
148 | case HttpRequestClass.HTTP_METHOD: | ||
149 | |||
150 | htc.httpMethod = parms[i + 1]; | ||
151 | break; | ||
152 | |||
153 | case HttpRequestClass.HTTP_MIMETYPE: | ||
154 | |||
155 | htc.httpMIMEType = parms[i + 1]; | ||
156 | break; | ||
157 | |||
158 | case HttpRequestClass.HTTP_BODY_MAXLENGTH: | ||
159 | |||
160 | // TODO implement me | ||
161 | break; | ||
162 | |||
163 | case HttpRequestClass.HTTP_VERIFY_CERT: | ||
164 | |||
165 | // TODO implement me | ||
166 | break; | ||
167 | } | ||
168 | } | ||
169 | } | ||
170 | |||
171 | htc.localID = localID; | ||
172 | htc.itemID = itemID; | ||
173 | htc.url = url; | ||
174 | htc.reqID = reqID; | ||
175 | htc.httpTimeout = httpTimeout; | ||
176 | htc.outbound_body = body; | ||
177 | |||
178 | lock (HttpListLock) | ||
179 | { | ||
180 | m_pendingRequests.Add(reqID, htc); | ||
181 | } | ||
182 | |||
183 | htc.process(); | ||
184 | |||
185 | return reqID; | ||
186 | } | ||
187 | |||
188 | public void StopHttpRequest(uint m_localID, LLUUID m_itemID) | ||
189 | { | ||
190 | if(m_pendingRequests != null) { | ||
191 | lock (HttpListLock) | ||
192 | { | ||
193 | HttpRequestClass tmpReq; | ||
194 | if (m_pendingRequests.TryGetValue(m_itemID, out tmpReq)) | ||
195 | { | ||
196 | tmpReq.Stop(); | ||
197 | m_pendingRequests.Remove(m_itemID); | ||
198 | } | ||
199 | } | ||
200 | } | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * TODO | ||
205 | * Not sure how important ordering is is here - the next first | ||
206 | * one completed in the list is returned, based soley on its list | ||
207 | * position, not the order in which the request was started or | ||
208 | * finsihed. I thought about setting up a queue for this, but | ||
209 | * it will need some refactoring and this works 'enough' right now | ||
210 | */ | ||
211 | |||
212 | public HttpRequestClass GetNextCompletedRequest() | ||
213 | { | ||
214 | lock (HttpListLock) | ||
215 | { | ||
216 | foreach (LLUUID luid in m_pendingRequests.Keys) | ||
217 | { | ||
218 | HttpRequestClass tmpReq; | ||
219 | |||
220 | if (m_pendingRequests.TryGetValue(luid, out tmpReq)) | ||
221 | { | ||
222 | if (tmpReq.finished) | ||
223 | { | ||
224 | return tmpReq; | ||
225 | } | ||
226 | } | ||
227 | } | ||
228 | } | ||
229 | return null; | ||
230 | } | ||
231 | |||
232 | public void RemoveCompletedRequest(LLUUID id) | ||
233 | { | ||
234 | lock (HttpListLock) | ||
235 | { | ||
236 | HttpRequestClass tmpReq; | ||
237 | if (m_pendingRequests.TryGetValue(id, out tmpReq)) | ||
238 | { | ||
239 | tmpReq.Stop(); | ||
240 | tmpReq = null; | ||
241 | m_pendingRequests.Remove(id); | ||
242 | } | ||
243 | } | ||
244 | } | ||
245 | |||
246 | } | ||
247 | |||
248 | public class HttpRequestClass | ||
249 | { | ||
250 | // Constants for parameters | ||
251 | public const int HTTP_METHOD = 0; | ||
252 | public const int HTTP_MIMETYPE = 1; | ||
253 | public const int HTTP_BODY_MAXLENGTH = 2; | ||
254 | public const int HTTP_VERIFY_CERT = 3; | ||
255 | |||
256 | // Parameter members and default values | ||
257 | public string httpMethod = "GET"; | ||
258 | public string httpMIMEType = "text/plain;charset=utf-8"; | ||
259 | public int httpBodyMaxLen = 2048; // not implemented | ||
260 | public bool httpVerifyCert = true; // not implemented | ||
261 | |||
262 | // Request info | ||
263 | public uint localID; | ||
264 | public LLUUID itemID; | ||
265 | public LLUUID reqID; | ||
266 | public int httpTimeout; | ||
267 | public string url; | ||
268 | public string outbound_body; | ||
269 | public DateTime next; | ||
270 | public int status; | ||
271 | public bool finished; | ||
272 | public List<string> response_metadata; | ||
273 | public string response_body; | ||
274 | public HttpWebRequest request; | ||
275 | private Thread httpThread; | ||
276 | |||
277 | public void process() | ||
278 | { | ||
279 | httpThread = new Thread(SendRequest); | ||
280 | httpThread.Name = "HttpRequestThread"; | ||
281 | httpThread.Priority = ThreadPriority.BelowNormal; | ||
282 | httpThread.IsBackground = true; | ||
283 | finished = false; | ||
284 | httpThread.Start(); | ||
285 | ThreadTracker.Add(httpThread); | ||
286 | } | ||
287 | |||
288 | /* | ||
289 | * TODO: More work on the response codes. Right now | ||
290 | * returning 200 for success or 499 for exception | ||
291 | */ | ||
292 | |||
293 | public void SendRequest() | ||
294 | { | ||
295 | HttpWebResponse response = null; | ||
296 | StringBuilder sb = new StringBuilder(); | ||
297 | byte[] buf = new byte[8192]; | ||
298 | string tempString = null; | ||
299 | int count = 0; | ||
300 | |||
301 | try | ||
302 | { | ||
303 | request = (HttpWebRequest) | ||
304 | WebRequest.Create(url); | ||
305 | request.Method = httpMethod; | ||
306 | request.ContentType = httpMIMEType; | ||
307 | |||
308 | request.Timeout = httpTimeout; | ||
309 | // execute the request | ||
310 | response = (HttpWebResponse) | ||
311 | request.GetResponse(); | ||
312 | |||
313 | Stream resStream = response.GetResponseStream(); | ||
314 | |||
315 | do | ||
316 | { | ||
317 | // fill the buffer with data | ||
318 | count = resStream.Read(buf, 0, buf.Length); | ||
319 | |||
320 | // make sure we read some data | ||
321 | if (count != 0) | ||
322 | { | ||
323 | // translate from bytes to ASCII text | ||
324 | tempString = Encoding.UTF8.GetString(buf, 0, count); | ||
325 | |||
326 | // continue building the string | ||
327 | sb.Append(tempString); | ||
328 | } | ||
329 | } while (count > 0); // any more data to read? | ||
330 | |||
331 | response_body = sb.ToString(); | ||
332 | } | ||
333 | catch (Exception e) | ||
334 | { | ||
335 | status = 499; | ||
336 | response_body = e.Message; | ||
337 | finished = true; | ||
338 | return; | ||
339 | } | ||
340 | |||
341 | status = 200; | ||
342 | finished = true; | ||
343 | } | ||
344 | |||
345 | public void Stop() | ||
346 | { | ||
347 | try | ||
348 | { | ||
349 | httpThread.Abort(); | ||
350 | } | ||
351 | catch (Exception) | ||
352 | { | ||
353 | } | ||
354 | } | ||
355 | } | ||
356 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Environment/Modules/Scripting/LoadImageURL/LoadImageURLModule.cs b/OpenSim/Region/Environment/Modules/Scripting/LoadImageURL/LoadImageURLModule.cs new file mode 100644 index 0000000..eaf9d36 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/Scripting/LoadImageURL/LoadImageURLModule.cs | |||
@@ -0,0 +1,179 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSim Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Drawing; | ||
30 | using System.IO; | ||
31 | using System.Net; | ||
32 | using libsecondlife; | ||
33 | using Nini.Config; | ||
34 | using OpenJPEGNet; | ||
35 | using OpenSim.Region.Environment.Interfaces; | ||
36 | using OpenSim.Region.Environment.Scenes; | ||
37 | |||
38 | namespace OpenSim.Region.Environment.Modules.Scripting.LoadImageURL | ||
39 | { | ||
40 | public class LoadImageURLModule : IRegionModule, IDynamicTextureRender | ||
41 | { | ||
42 | private string m_name = "LoadImageURL"; | ||
43 | private IDynamicTextureManager m_textureManager; | ||
44 | private Scene m_scene; | ||
45 | |||
46 | public void Initialise(Scene scene, IConfigSource config) | ||
47 | { | ||
48 | if (m_scene == null) | ||
49 | { | ||
50 | m_scene = scene; | ||
51 | } | ||
52 | } | ||
53 | |||
54 | public void PostInitialise() | ||
55 | { | ||
56 | m_textureManager = m_scene.RequestModuleInterface<IDynamicTextureManager>(); | ||
57 | if (m_textureManager != null) | ||
58 | { | ||
59 | m_textureManager.RegisterRender(GetContentType(), this); | ||
60 | } | ||
61 | } | ||
62 | |||
63 | public void Close() | ||
64 | { | ||
65 | } | ||
66 | |||
67 | public string Name | ||
68 | { | ||
69 | get { return m_name; } | ||
70 | } | ||
71 | |||
72 | public bool IsSharedModule | ||
73 | { | ||
74 | get { return true; } | ||
75 | } | ||
76 | |||
77 | public string GetName() | ||
78 | { | ||
79 | return m_name; | ||
80 | } | ||
81 | |||
82 | public string GetContentType() | ||
83 | { | ||
84 | return ("image"); | ||
85 | } | ||
86 | |||
87 | public bool SupportsAsynchronous() | ||
88 | { | ||
89 | return true; | ||
90 | } | ||
91 | |||
92 | public byte[] ConvertUrl(string url, string extraParams) | ||
93 | { | ||
94 | return null; | ||
95 | } | ||
96 | |||
97 | public byte[] ConvertStream(Stream data, string extraParams) | ||
98 | { | ||
99 | return null; | ||
100 | } | ||
101 | |||
102 | public bool AsyncConvertUrl(LLUUID id, string url, string extraParams) | ||
103 | { | ||
104 | MakeHttpRequest(url, id); | ||
105 | return true; | ||
106 | } | ||
107 | |||
108 | public bool AsyncConvertData(LLUUID id, string bodyData, string extraParams) | ||
109 | { | ||
110 | return false; | ||
111 | } | ||
112 | |||
113 | private void MakeHttpRequest(string url, LLUUID requestID) | ||
114 | { | ||
115 | WebRequest request = HttpWebRequest.Create(url); | ||
116 | RequestState state = new RequestState((HttpWebRequest) request, requestID); | ||
117 | IAsyncResult result = request.BeginGetResponse(new AsyncCallback(HttpRequestReturn), state); | ||
118 | |||
119 | TimeSpan t = (DateTime.UtcNow - new DateTime(1970, 1, 1)); | ||
120 | state.TimeOfRequest = (int) t.TotalSeconds; | ||
121 | } | ||
122 | |||
123 | private void HttpRequestReturn(IAsyncResult result) | ||
124 | { | ||
125 | RequestState state = (RequestState) result.AsyncState; | ||
126 | WebRequest request = (WebRequest) state.Request; | ||
127 | HttpWebResponse response = (HttpWebResponse) request.EndGetResponse(result); | ||
128 | if (response.StatusCode == HttpStatusCode.OK) | ||
129 | { | ||
130 | Bitmap image = new Bitmap(response.GetResponseStream()); | ||
131 | Size newsize; | ||
132 | |||
133 | // TODO: make this a bit less hard coded | ||
134 | if ((image.Height < 64) && (image.Width < 64)) | ||
135 | { | ||
136 | newsize = new Size(32, 32); | ||
137 | } | ||
138 | else if ((image.Height < 128) && (image.Width < 128)) | ||
139 | { | ||
140 | newsize = new Size(64, 64); | ||
141 | } | ||
142 | else if ((image.Height <256) && (image.Width < 256)) | ||
143 | { | ||
144 | newsize = new Size(128, 128); | ||
145 | } | ||
146 | else if ((image.Height < 512 && image.Width < 512)) | ||
147 | { | ||
148 | newsize = new Size(256, 256); | ||
149 | } | ||
150 | else if ((image.Height < 1024 && image.Width < 1024)) | ||
151 | { | ||
152 | newsize = new Size(512, 512); | ||
153 | } | ||
154 | else | ||
155 | { | ||
156 | newsize = new Size(1024,1024); | ||
157 | } | ||
158 | |||
159 | Bitmap resize = new Bitmap(image, newsize); | ||
160 | byte[] imageJ2000 = OpenJPEG.EncodeFromImage(resize, true); | ||
161 | |||
162 | m_textureManager.ReturnData(state.RequestID, imageJ2000); | ||
163 | } | ||
164 | } | ||
165 | |||
166 | public class RequestState | ||
167 | { | ||
168 | public HttpWebRequest Request = null; | ||
169 | public LLUUID RequestID = LLUUID.Zero; | ||
170 | public int TimeOfRequest = 0; | ||
171 | |||
172 | public RequestState(HttpWebRequest request, LLUUID requestID) | ||
173 | { | ||
174 | Request = request; | ||
175 | RequestID = requestID; | ||
176 | } | ||
177 | } | ||
178 | } | ||
179 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Environment/Modules/Scripting/VectorRender/VectorRenderModule.cs b/OpenSim/Region/Environment/Modules/Scripting/VectorRender/VectorRenderModule.cs new file mode 100644 index 0000000..4fba5b9 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/Scripting/VectorRender/VectorRenderModule.cs | |||
@@ -0,0 +1,361 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSim Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Drawing; | ||
30 | using System.Drawing.Imaging; | ||
31 | using System.Globalization; | ||
32 | using System.IO; | ||
33 | using System.Net; | ||
34 | using libsecondlife; | ||
35 | using Nini.Config; | ||
36 | using OpenJPEGNet; | ||
37 | using OpenSim.Region.Environment.Interfaces; | ||
38 | using OpenSim.Region.Environment.Scenes; | ||
39 | using Image=System.Drawing.Image; | ||
40 | |||
41 | //using Cairo; | ||
42 | |||
43 | namespace OpenSim.Region.Environment.Modules.Scripting.VectorRender | ||
44 | { | ||
45 | public class VectorRenderModule : IRegionModule, IDynamicTextureRender | ||
46 | { | ||
47 | private Scene m_scene; | ||
48 | private string m_name = "VectorRenderModule"; | ||
49 | private IDynamicTextureManager m_textureManager; | ||
50 | |||
51 | public VectorRenderModule() | ||
52 | { | ||
53 | } | ||
54 | |||
55 | public void Initialise(Scene scene, IConfigSource config) | ||
56 | { | ||
57 | if (m_scene == null) | ||
58 | { | ||
59 | m_scene = scene; | ||
60 | } | ||
61 | } | ||
62 | |||
63 | public void PostInitialise() | ||
64 | { | ||
65 | m_textureManager = m_scene.RequestModuleInterface<IDynamicTextureManager>(); | ||
66 | if (m_textureManager != null) | ||
67 | { | ||
68 | m_textureManager.RegisterRender(GetContentType(), this); | ||
69 | } | ||
70 | } | ||
71 | |||
72 | public void Close() | ||
73 | { | ||
74 | } | ||
75 | |||
76 | public string Name | ||
77 | { | ||
78 | get { return m_name; } | ||
79 | } | ||
80 | |||
81 | public bool IsSharedModule | ||
82 | { | ||
83 | get { return true; } | ||
84 | } | ||
85 | |||
86 | private void Draw(string data, LLUUID id, string extraParams) | ||
87 | { | ||
88 | // TODO: this is a brutal hack. extraParams should actually be parsed reasonably. | ||
89 | int size = 256; | ||
90 | try { | ||
91 | size = Convert.ToInt32(extraParams); | ||
92 | } catch (Exception e) { | ||
93 | |||
94 | //Ckrinke: Add a WriteLine to remove the warning about 'e' defined but not used | ||
95 | Console.WriteLine("Problem with Draw. Please verify parameters." + e.ToString()); | ||
96 | } | ||
97 | |||
98 | if ((size < 128) || (size > 1024)) | ||
99 | size = 256; | ||
100 | |||
101 | Bitmap bitmap = new Bitmap(size, size, PixelFormat.Format32bppArgb); | ||
102 | |||
103 | Graphics graph = Graphics.FromImage(bitmap); | ||
104 | |||
105 | extraParams = extraParams.ToLower(); | ||
106 | int alpha = 255; | ||
107 | if (extraParams == "setalpha") | ||
108 | { | ||
109 | alpha = 0; | ||
110 | } | ||
111 | else | ||
112 | { | ||
113 | graph.FillRectangle(new SolidBrush(Color.White), 0, 0, size, size); | ||
114 | } | ||
115 | |||
116 | for (int w = 0; w < bitmap.Width; w++) | ||
117 | { | ||
118 | for (int h = 0; h < bitmap.Height; h++) | ||
119 | { | ||
120 | bitmap.SetPixel(w, h, Color.FromArgb(alpha, bitmap.GetPixel(w, h))); | ||
121 | } | ||
122 | } | ||
123 | |||
124 | |||
125 | |||
126 | GDIDraw(data, graph); | ||
127 | |||
128 | byte[] imageJ2000 = OpenJPEG.EncodeFromImage(bitmap, true); | ||
129 | m_textureManager.ReturnData(id, imageJ2000); | ||
130 | |||
131 | } | ||
132 | |||
133 | /* | ||
134 | private void CairoDraw(string data, System.Drawing.Graphics graph) | ||
135 | { | ||
136 | using (Win32Surface draw = new Win32Surface(graph.GetHdc())) | ||
137 | { | ||
138 | Context contex = new Context(draw); | ||
139 | |||
140 | contex.Antialias = Antialias.None; //fastest method but low quality | ||
141 | contex.LineWidth = 7; | ||
142 | char[] lineDelimiter = { ';' }; | ||
143 | char[] partsDelimiter = { ',' }; | ||
144 | string[] lines = data.Split(lineDelimiter); | ||
145 | |||
146 | foreach (string line in lines) | ||
147 | { | ||
148 | string nextLine = line.Trim(); | ||
149 | |||
150 | if (nextLine.StartsWith("MoveTO")) | ||
151 | { | ||
152 | float x = 0; | ||
153 | float y = 0; | ||
154 | GetParams(partsDelimiter, ref nextLine, ref x, ref y); | ||
155 | contex.MoveTo(x, y); | ||
156 | } | ||
157 | else if (nextLine.StartsWith("LineTo")) | ||
158 | { | ||
159 | float x = 0; | ||
160 | float y = 0; | ||
161 | GetParams(partsDelimiter, ref nextLine, ref x, ref y); | ||
162 | contex.LineTo(x, y); | ||
163 | contex.Stroke(); | ||
164 | } | ||
165 | } | ||
166 | } | ||
167 | graph.ReleaseHdc(); | ||
168 | } | ||
169 | */ | ||
170 | |||
171 | private void GDIDraw(string data, Graphics graph) | ||
172 | { | ||
173 | Point startPoint = new Point(0, 0); | ||
174 | Point endPoint = new Point(0, 0); | ||
175 | Pen drawPen = new Pen(Color.Black, 7); | ||
176 | Font myFont = new Font("Times New Roman", 14); | ||
177 | SolidBrush myBrush = new SolidBrush(Color.Black); | ||
178 | char[] lineDelimiter = { ';' }; | ||
179 | char[] partsDelimiter = { ',' }; | ||
180 | string[] lines = data.Split(lineDelimiter); | ||
181 | |||
182 | foreach (string line in lines) | ||
183 | { | ||
184 | string nextLine = line.Trim(); | ||
185 | //replace with switch, or even better, do some proper parsing | ||
186 | if (nextLine.StartsWith("MoveTo")) | ||
187 | { | ||
188 | float x = 0; | ||
189 | float y = 0; | ||
190 | GetParams(partsDelimiter, ref nextLine, 6, ref x, ref y); | ||
191 | startPoint.X = (int)x; | ||
192 | startPoint.Y = (int)y; | ||
193 | } | ||
194 | else if (nextLine.StartsWith("LineTo")) | ||
195 | { | ||
196 | float x = 0; | ||
197 | float y = 0; | ||
198 | GetParams(partsDelimiter, ref nextLine, 6, ref x, ref y); | ||
199 | endPoint.X = (int)x; | ||
200 | endPoint.Y = (int)y; | ||
201 | graph.DrawLine(drawPen, startPoint, endPoint); | ||
202 | startPoint.X = endPoint.X; | ||
203 | startPoint.Y = endPoint.Y; | ||
204 | } | ||
205 | else if (nextLine.StartsWith("Text")) | ||
206 | { | ||
207 | nextLine = nextLine.Remove(0, 4); | ||
208 | nextLine = nextLine.Trim(); | ||
209 | graph.DrawString(nextLine, myFont, myBrush, startPoint); | ||
210 | } | ||
211 | else if (nextLine.StartsWith("Image")) | ||
212 | { | ||
213 | float x = 0; | ||
214 | float y = 0; | ||
215 | GetParams(partsDelimiter, ref nextLine, 5, ref x, ref y); | ||
216 | endPoint.X = (int)x; | ||
217 | endPoint.Y = (int)y; | ||
218 | Image image = ImageHttpRequest(nextLine); | ||
219 | graph.DrawImage(image, (float)startPoint.X, (float)startPoint.Y, x, y); | ||
220 | startPoint.X += endPoint.X; | ||
221 | startPoint.Y += endPoint.Y; | ||
222 | } | ||
223 | else if (nextLine.StartsWith("Rectangle")) | ||
224 | { | ||
225 | float x = 0; | ||
226 | float y = 0; | ||
227 | GetParams(partsDelimiter, ref nextLine, 9, ref x, ref y); | ||
228 | endPoint.X = (int)x; | ||
229 | endPoint.Y = (int)y; | ||
230 | graph.DrawRectangle(drawPen, startPoint.X, startPoint.Y, endPoint.X, endPoint.Y); | ||
231 | startPoint.X += endPoint.X; | ||
232 | startPoint.Y += endPoint.Y; | ||
233 | } | ||
234 | else if (nextLine.StartsWith("FillRectangle")) | ||
235 | { | ||
236 | float x = 0; | ||
237 | float y = 0; | ||
238 | GetParams(partsDelimiter, ref nextLine, 13, ref x, ref y); | ||
239 | endPoint.X = (int)x; | ||
240 | endPoint.Y = (int)y; | ||
241 | graph.FillRectangle(myBrush, startPoint.X, startPoint.Y, endPoint.X, endPoint.Y); | ||
242 | startPoint.X += endPoint.X; | ||
243 | startPoint.Y += endPoint.Y; | ||
244 | } | ||
245 | else if (nextLine.StartsWith("Ellipse")) | ||
246 | { | ||
247 | float x = 0; | ||
248 | float y = 0; | ||
249 | GetParams(partsDelimiter, ref nextLine, 7, ref x, ref y); | ||
250 | endPoint.X = (int)x; | ||
251 | endPoint.Y = (int)y; | ||
252 | graph.DrawEllipse(drawPen, startPoint.X, startPoint.Y, endPoint.X, endPoint.Y); | ||
253 | startPoint.X += endPoint.X; | ||
254 | startPoint.Y += endPoint.Y; | ||
255 | } | ||
256 | else if (nextLine.StartsWith("FontSize")) | ||
257 | { | ||
258 | nextLine = nextLine.Remove(0, 8); | ||
259 | nextLine = nextLine.Trim(); | ||
260 | float size = Convert.ToSingle(nextLine, CultureInfo.InvariantCulture); | ||
261 | myFont = new Font("Times New Roman", size); | ||
262 | } | ||
263 | else if (nextLine.StartsWith("PenSize")) | ||
264 | { | ||
265 | nextLine = nextLine.Remove(0, 8); | ||
266 | nextLine = nextLine.Trim(); | ||
267 | float size = Convert.ToSingle(nextLine, CultureInfo.InvariantCulture); | ||
268 | drawPen.Width = size; | ||
269 | } | ||
270 | else if (nextLine.StartsWith("PenColour")) | ||
271 | { | ||
272 | nextLine = nextLine.Remove(0, 9); | ||
273 | nextLine = nextLine.Trim(); | ||
274 | |||
275 | Color newColour = Color.FromName(nextLine); | ||
276 | |||
277 | myBrush.Color = newColour; | ||
278 | drawPen.Color = newColour; | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | |||
283 | private static void GetParams(char[] partsDelimiter, ref string line, int startLength, ref float x, ref float y) | ||
284 | { | ||
285 | line = line.Remove(0, startLength); | ||
286 | string[] parts = line.Split(partsDelimiter); | ||
287 | if (parts.Length == 2) | ||
288 | { | ||
289 | string xVal = parts[0].Trim(); | ||
290 | string yVal = parts[1].Trim(); | ||
291 | x = Convert.ToSingle(xVal, CultureInfo.InvariantCulture); | ||
292 | y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture); | ||
293 | } | ||
294 | else if (parts.Length > 2) | ||
295 | { | ||
296 | string xVal = parts[0].Trim(); | ||
297 | string yVal = parts[1].Trim(); | ||
298 | x = Convert.ToSingle(xVal, CultureInfo.InvariantCulture); | ||
299 | y = Convert.ToSingle(yVal, CultureInfo.InvariantCulture); | ||
300 | |||
301 | line = ""; | ||
302 | for (int i = 2; i < parts.Length; i++) | ||
303 | { | ||
304 | line = line + parts[i].Trim(); | ||
305 | line = line + " "; | ||
306 | } | ||
307 | } | ||
308 | } | ||
309 | |||
310 | private Bitmap ImageHttpRequest(string url) | ||
311 | { | ||
312 | WebRequest request = HttpWebRequest.Create(url); | ||
313 | //Ckrinke: Comment out for now as 'str' is unused. Bring it back into play later when it is used. | ||
314 | //Ckrinke Stream str = null; | ||
315 | HttpWebResponse response = (HttpWebResponse)(request).GetResponse(); | ||
316 | if (response.StatusCode == HttpStatusCode.OK) | ||
317 | { | ||
318 | Bitmap image = new Bitmap(response.GetResponseStream()); | ||
319 | return image; | ||
320 | } | ||
321 | |||
322 | return null; | ||
323 | } | ||
324 | |||
325 | public string GetContentType() | ||
326 | { | ||
327 | return ("vector"); | ||
328 | } | ||
329 | |||
330 | public string GetName() | ||
331 | { | ||
332 | return m_name; | ||
333 | } | ||
334 | |||
335 | public bool SupportsAsynchronous() | ||
336 | { | ||
337 | return true; | ||
338 | } | ||
339 | |||
340 | public byte[] ConvertUrl(string url, string extraParams) | ||
341 | { | ||
342 | return null; | ||
343 | } | ||
344 | |||
345 | public byte[] ConvertStream(Stream data, string extraParams) | ||
346 | { | ||
347 | return null; | ||
348 | } | ||
349 | |||
350 | public bool AsyncConvertUrl(LLUUID id, string url, string extraParams) | ||
351 | { | ||
352 | return false; | ||
353 | } | ||
354 | |||
355 | public bool AsyncConvertData(LLUUID id, string bodyData, string extraParams) | ||
356 | { | ||
357 | Draw(bodyData, id, extraParams); | ||
358 | return true; | ||
359 | } | ||
360 | } | ||
361 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Environment/Modules/Scripting/WorldComm/WorldCommModule.cs b/OpenSim/Region/Environment/Modules/Scripting/WorldComm/WorldCommModule.cs new file mode 100644 index 0000000..a949fb6 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/Scripting/WorldComm/WorldCommModule.cs | |||
@@ -0,0 +1,578 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSim Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using libsecondlife; | ||
31 | using Nini.Config; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Environment.Interfaces; | ||
34 | using OpenSim.Region.Environment.Scenes; | ||
35 | |||
36 | /***************************************************** | ||
37 | * | ||
38 | * WorldCommModule | ||
39 | * | ||
40 | * | ||
41 | * Holding place for world comms - basically llListen | ||
42 | * function implementation. | ||
43 | * | ||
44 | * lLListen(integer channel, string name, key id, string msg) | ||
45 | * The name, id, and msg arguments specify the filtering | ||
46 | * criteria. You can pass the empty string | ||
47 | * (or NULL_KEY for id) for these to set a completely | ||
48 | * open filter; this causes the listen() event handler to be | ||
49 | * invoked for all chat on the channel. To listen only | ||
50 | * for chat spoken by a specific object or avatar, | ||
51 | * specify the name and/or id arguments. To listen | ||
52 | * only for a specific command, specify the | ||
53 | * (case-sensitive) msg argument. If msg is not empty, | ||
54 | * listener will only hear strings which are exactly equal | ||
55 | * to msg. You can also use all the arguments to establish | ||
56 | * the most restrictive filtering criteria. | ||
57 | * | ||
58 | * It might be useful for each listener to maintain a message | ||
59 | * digest, with a list of recent messages by UUID. This can | ||
60 | * be used to prevent in-world repeater loops. However, the | ||
61 | * linden functions do not have this capability, so for now | ||
62 | * thats the way it works. | ||
63 | * | ||
64 | * **************************************************/ | ||
65 | |||
66 | namespace OpenSim.Region.Environment.Modules.Scripting.WorldComm | ||
67 | { | ||
68 | public class WorldCommModule : IRegionModule, IWorldComm | ||
69 | { | ||
70 | private Scene m_scene; | ||
71 | private object CommListLock = new object(); | ||
72 | private object ListLock = new object(); | ||
73 | private string m_name = "WorldCommModule"; | ||
74 | private ListenerManager m_listenerManager; | ||
75 | private Queue m_pendingQ; | ||
76 | private Queue m_pending; | ||
77 | |||
78 | public WorldCommModule() | ||
79 | { | ||
80 | } | ||
81 | |||
82 | public void Initialise(Scene scene, IConfigSource config) | ||
83 | { | ||
84 | m_scene = scene; | ||
85 | m_scene.RegisterModuleInterface<IWorldComm>(this); | ||
86 | m_listenerManager = new ListenerManager(); | ||
87 | m_scene.EventManager.OnNewClient += NewClient; | ||
88 | m_pendingQ = new Queue(); | ||
89 | m_pending = Queue.Synchronized(m_pendingQ); | ||
90 | } | ||
91 | |||
92 | public void PostInitialise() | ||
93 | { | ||
94 | } | ||
95 | |||
96 | public void Close() | ||
97 | { | ||
98 | } | ||
99 | |||
100 | public string Name | ||
101 | { | ||
102 | get { return m_name; } | ||
103 | } | ||
104 | |||
105 | public bool IsSharedModule | ||
106 | { | ||
107 | get { return false; } | ||
108 | } | ||
109 | |||
110 | public void NewClient(IClientAPI client) | ||
111 | { | ||
112 | client.OnChatFromViewer += DeliverClientMessage; | ||
113 | } | ||
114 | |||
115 | /******************************************************************** | ||
116 | * | ||
117 | * Listener Stuff | ||
118 | * | ||
119 | * *****************************************************************/ | ||
120 | private void DeliverClientMessage(Object sender, ChatFromViewerArgs e) | ||
121 | { | ||
122 | DeliverMessage(e.Sender.AgentId.ToString(), | ||
123 | e.Type, e.Channel, | ||
124 | e.Sender.FirstName + " " + e.Sender.LastName, | ||
125 | e.Message); | ||
126 | } | ||
127 | |||
128 | public int Listen(uint localID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, string msg) | ||
129 | { | ||
130 | return m_listenerManager.AddListener(localID, itemID, hostID, channel, name, id, msg); | ||
131 | } | ||
132 | |||
133 | public void ListenControl(int handle, int active) | ||
134 | { | ||
135 | if (m_listenerManager != null) | ||
136 | { | ||
137 | if (active == 1) | ||
138 | m_listenerManager.Activate(handle); | ||
139 | else if (active == 0) | ||
140 | m_listenerManager.Dectivate(handle); | ||
141 | } | ||
142 | } | ||
143 | |||
144 | public void ListenRemove(int handle) | ||
145 | { | ||
146 | if (m_listenerManager != null) | ||
147 | { | ||
148 | m_listenerManager.Remove(handle); | ||
149 | } | ||
150 | } | ||
151 | |||
152 | public void DeleteListener(LLUUID itemID) | ||
153 | { | ||
154 | if (m_listenerManager != null) | ||
155 | { | ||
156 | m_listenerManager.DeleteListener(itemID); | ||
157 | } | ||
158 | } | ||
159 | |||
160 | // This method scans nearby objects and determines if they are listeners, | ||
161 | // and if so if this message fits the filter. If it does, then | ||
162 | // enqueue the message for delivery to the objects listen event handler. | ||
163 | // Objects that do an llSay have their messages delivered here, and for | ||
164 | // nearby avatars, the SimChat function is used. | ||
165 | public void DeliverMessage(string sourceItemID, ChatTypeEnum type, int channel, string name, string msg) | ||
166 | { | ||
167 | SceneObjectPart source = null; | ||
168 | ScenePresence avatar = null; | ||
169 | |||
170 | source = m_scene.GetSceneObjectPart(new LLUUID(sourceItemID)); | ||
171 | if (source == null) | ||
172 | { | ||
173 | avatar = m_scene.GetScenePresence(new LLUUID(sourceItemID)); | ||
174 | } | ||
175 | if ((avatar != null) || (source != null)) | ||
176 | { | ||
177 | // Loop through the objects in the scene | ||
178 | // If they are in proximity, then if they are | ||
179 | // listeners, if so add them to the pending queue | ||
180 | |||
181 | foreach (ListenerInfo li in m_listenerManager.GetListeners()) | ||
182 | { | ||
183 | EntityBase sPart; | ||
184 | |||
185 | m_scene.Entities.TryGetValue(li.GetHostID(), out sPart); | ||
186 | |||
187 | if (sPart != null) | ||
188 | { | ||
189 | double dis = 0; | ||
190 | |||
191 | if (source != null) | ||
192 | dis = Util.GetDistanceTo(sPart.AbsolutePosition, source.AbsolutePosition); | ||
193 | else | ||
194 | dis = Util.GetDistanceTo(sPart.AbsolutePosition, avatar.AbsolutePosition); | ||
195 | |||
196 | switch (type) | ||
197 | { | ||
198 | case ChatTypeEnum.Whisper: | ||
199 | |||
200 | if ((dis < 10) && (dis > -10)) | ||
201 | { | ||
202 | if (li.GetChannel() == channel) | ||
203 | { | ||
204 | ListenerInfo isListener = m_listenerManager.IsListenerMatch( | ||
205 | sourceItemID, sPart.UUID, channel, name, msg | ||
206 | ); | ||
207 | if (isListener != null) | ||
208 | { | ||
209 | lock (m_pending.SyncRoot) | ||
210 | { | ||
211 | m_pending.Enqueue(isListener); | ||
212 | } | ||
213 | } | ||
214 | } | ||
215 | } | ||
216 | break; | ||
217 | |||
218 | case ChatTypeEnum.Say: | ||
219 | |||
220 | if ((dis < 30) && (dis > -30)) | ||
221 | { | ||
222 | if (li.GetChannel() == channel) | ||
223 | { | ||
224 | ListenerInfo isListener = m_listenerManager.IsListenerMatch( | ||
225 | sourceItemID, sPart.UUID, channel, name, msg | ||
226 | ); | ||
227 | if (isListener != null) | ||
228 | { | ||
229 | lock (m_pending.SyncRoot) | ||
230 | { | ||
231 | m_pending.Enqueue(isListener); | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | break; | ||
237 | |||
238 | case ChatTypeEnum.Shout: | ||
239 | if ((dis < 100) && (dis > -100)) | ||
240 | { | ||
241 | if (li.GetChannel() == channel) | ||
242 | { | ||
243 | ListenerInfo isListener = m_listenerManager.IsListenerMatch( | ||
244 | sourceItemID, sPart.UUID, channel, name, msg | ||
245 | ); | ||
246 | if (isListener != null) | ||
247 | { | ||
248 | lock (m_pending.SyncRoot) | ||
249 | { | ||
250 | m_pending.Enqueue(isListener); | ||
251 | } | ||
252 | } | ||
253 | } | ||
254 | } | ||
255 | break; | ||
256 | |||
257 | case ChatTypeEnum.Broadcast: | ||
258 | // Dont process if this message is from itself! | ||
259 | if (li.GetHostID().ToString().Equals(sourceItemID) || | ||
260 | sPart.UUID.ToString().Equals(sourceItemID)) | ||
261 | continue; | ||
262 | |||
263 | if (li.GetChannel() == channel) | ||
264 | { | ||
265 | ListenerInfo isListener = m_listenerManager.IsListenerMatch( | ||
266 | sourceItemID, sPart.UUID, channel, name, msg | ||
267 | ); | ||
268 | if (isListener != null) | ||
269 | { | ||
270 | lock (m_pending.SyncRoot) | ||
271 | { | ||
272 | m_pending.Enqueue(isListener); | ||
273 | } | ||
274 | } | ||
275 | } | ||
276 | |||
277 | break; | ||
278 | } | ||
279 | } | ||
280 | } | ||
281 | } | ||
282 | } | ||
283 | |||
284 | public bool HasMessages() | ||
285 | { | ||
286 | if (m_pending != null) | ||
287 | return (m_pending.Count > 0); | ||
288 | else | ||
289 | return false; | ||
290 | } | ||
291 | |||
292 | public ListenerInfo GetNextMessage() | ||
293 | { | ||
294 | ListenerInfo li = null; | ||
295 | |||
296 | lock (m_pending.SyncRoot) | ||
297 | { | ||
298 | li = (ListenerInfo)m_pending.Dequeue(); | ||
299 | } | ||
300 | |||
301 | return li; | ||
302 | } | ||
303 | |||
304 | public uint PeekNextMessageLocalID() | ||
305 | { | ||
306 | return ((ListenerInfo)m_pending.Peek()).GetLocalID(); | ||
307 | } | ||
308 | |||
309 | public LLUUID PeekNextMessageItemID() | ||
310 | { | ||
311 | return ((ListenerInfo)m_pending.Peek()).GetItemID(); | ||
312 | } | ||
313 | } | ||
314 | |||
315 | public class ListenerManager | ||
316 | { | ||
317 | //private Dictionary<int, ListenerInfo> m_listeners; | ||
318 | private Hashtable m_listeners = Hashtable.Synchronized(new Hashtable()); | ||
319 | private object ListenersLock = new object(); | ||
320 | private int m_MaxListeners = 100; | ||
321 | |||
322 | public int AddListener(uint localID, LLUUID itemID, LLUUID hostID, int channel, string name, string id, string msg) | ||
323 | { | ||
324 | if (m_listeners.Count < m_MaxListeners) | ||
325 | { | ||
326 | ListenerInfo isListener = IsListenerMatch(LLUUID.Zero.ToString(), itemID, channel, name, msg); | ||
327 | |||
328 | if (isListener == null) | ||
329 | { | ||
330 | int newHandle = GetNewHandle(); | ||
331 | |||
332 | if (newHandle > -1) | ||
333 | { | ||
334 | ListenerInfo li = new ListenerInfo(localID, newHandle, itemID, hostID, channel, name, id, msg); | ||
335 | |||
336 | lock (m_listeners.SyncRoot) | ||
337 | { | ||
338 | m_listeners.Add(newHandle, li); | ||
339 | } | ||
340 | |||
341 | return newHandle; | ||
342 | } | ||
343 | } | ||
344 | } | ||
345 | |||
346 | return -1; | ||
347 | } | ||
348 | |||
349 | public void Remove(int handle) | ||
350 | { | ||
351 | lock (m_listeners.SyncRoot) | ||
352 | { | ||
353 | m_listeners.Remove(handle); | ||
354 | } | ||
355 | } | ||
356 | |||
357 | public void DeleteListener(LLUUID itemID) | ||
358 | { | ||
359 | ArrayList removedListeners = new ArrayList(); | ||
360 | |||
361 | lock (m_listeners.SyncRoot) | ||
362 | { | ||
363 | IDictionaryEnumerator en = m_listeners.GetEnumerator(); | ||
364 | while (en.MoveNext()) | ||
365 | { | ||
366 | ListenerInfo li = (ListenerInfo)en.Value; | ||
367 | if (li.GetItemID().Equals(itemID)) | ||
368 | { | ||
369 | removedListeners.Add(li.GetHandle()); | ||
370 | } | ||
371 | } | ||
372 | foreach (int handle in removedListeners) | ||
373 | { | ||
374 | m_listeners.Remove(handle); | ||
375 | } | ||
376 | } | ||
377 | } | ||
378 | |||
379 | private int GetNewHandle() | ||
380 | { | ||
381 | for (int i = 0; i < int.MaxValue - 1; i++) | ||
382 | { | ||
383 | if (!m_listeners.ContainsKey(i)) | ||
384 | return i; | ||
385 | } | ||
386 | |||
387 | return -1; | ||
388 | } | ||
389 | |||
390 | public bool IsListener(LLUUID hostID) | ||
391 | { | ||
392 | foreach (ListenerInfo li in m_listeners.Values) | ||
393 | { | ||
394 | if (li.GetHostID().Equals(hostID)) | ||
395 | return true; | ||
396 | } | ||
397 | |||
398 | return false; | ||
399 | } | ||
400 | |||
401 | public void Activate(int handle) | ||
402 | { | ||
403 | |||
404 | if (m_listeners.ContainsKey(handle)) | ||
405 | { | ||
406 | lock (m_listeners.SyncRoot) | ||
407 | { | ||
408 | ListenerInfo li = (ListenerInfo)m_listeners[handle]; | ||
409 | li.Activate(); | ||
410 | } | ||
411 | } | ||
412 | } | ||
413 | |||
414 | public void Dectivate(int handle) | ||
415 | { | ||
416 | |||
417 | if (m_listeners.ContainsKey(handle)) | ||
418 | { | ||
419 | ListenerInfo li = (ListenerInfo)m_listeners[handle]; | ||
420 | li.Deactivate(); | ||
421 | } | ||
422 | } | ||
423 | |||
424 | // Theres probably a more clever and efficient way to | ||
425 | // do this, maybe with regex. | ||
426 | public ListenerInfo IsListenerMatch(string sourceItemID, LLUUID listenerKey, int channel, string name, | ||
427 | string msg) | ||
428 | { | ||
429 | bool isMatch = true; | ||
430 | lock (m_listeners.SyncRoot) | ||
431 | { | ||
432 | IDictionaryEnumerator en = m_listeners.GetEnumerator(); | ||
433 | while (en.MoveNext()) | ||
434 | { | ||
435 | ListenerInfo li = (ListenerInfo)en.Value; | ||
436 | |||
437 | if (li.IsActive()) | ||
438 | { | ||
439 | if (li.GetHostID().Equals(listenerKey)) | ||
440 | { | ||
441 | if (channel == li.GetChannel()) | ||
442 | { | ||
443 | if ((li.GetID().ToString().Length > 0) && | ||
444 | (!li.GetID().Equals(LLUUID.Zero))) | ||
445 | { | ||
446 | if (!li.GetID().ToString().Equals(sourceItemID)) | ||
447 | { | ||
448 | isMatch = false; | ||
449 | } | ||
450 | } | ||
451 | if (isMatch && (li.GetName().Length > 0)) | ||
452 | { | ||
453 | if (li.GetName().Equals(name)) | ||
454 | { | ||
455 | isMatch = false; | ||
456 | } | ||
457 | } | ||
458 | if (isMatch) | ||
459 | { | ||
460 | return new ListenerInfo( | ||
461 | li.GetLocalID(), li.GetHandle(), li.GetItemID(), li.GetHostID(), | ||
462 | li.GetChannel(), name, li.GetID(), msg, new LLUUID(sourceItemID) | ||
463 | ); | ||
464 | } | ||
465 | } | ||
466 | } | ||
467 | } | ||
468 | } | ||
469 | } | ||
470 | return null; | ||
471 | } | ||
472 | |||
473 | public ICollection GetListeners() | ||
474 | { | ||
475 | return m_listeners.Values; | ||
476 | } | ||
477 | } | ||
478 | |||
479 | public class ListenerInfo | ||
480 | { | ||
481 | private LLUUID m_itemID; // ID of the host script engine | ||
482 | private LLUUID m_hostID; // ID of the host/scene part | ||
483 | private LLUUID m_sourceItemID; // ID of the scenePart or avatar source of the message | ||
484 | private int m_channel; // Channel | ||
485 | private int m_handle; // Assigned handle of this listener | ||
486 | private uint m_localID; // Local ID from script engine | ||
487 | private string m_name; // Object name to filter messages from | ||
488 | private LLUUID m_id; // ID to filter messages from | ||
489 | private string m_message; // The message | ||
490 | private bool m_active; // Listener is active or not | ||
491 | |||
492 | public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, string message) | ||
493 | { | ||
494 | Initialise(localID, handle, ItemID, hostID, channel, name, id, message); | ||
495 | } | ||
496 | |||
497 | public ListenerInfo(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, LLUUID id, | ||
498 | string message, LLUUID sourceItemID) | ||
499 | { | ||
500 | Initialise(localID, handle, ItemID, hostID, channel, name, id, message); | ||
501 | m_sourceItemID = sourceItemID; | ||
502 | } | ||
503 | |||
504 | private void Initialise(uint localID, int handle, LLUUID ItemID, LLUUID hostID, int channel, string name, | ||
505 | LLUUID id, string message) | ||
506 | { | ||
507 | m_handle = handle; | ||
508 | m_channel = channel; | ||
509 | m_itemID = ItemID; | ||
510 | m_hostID = hostID; | ||
511 | m_name = name; | ||
512 | m_id = id; | ||
513 | m_message = message; | ||
514 | m_active = true; | ||
515 | m_localID = localID; | ||
516 | } | ||
517 | |||
518 | public LLUUID GetItemID() | ||
519 | { | ||
520 | return m_itemID; | ||
521 | } | ||
522 | |||
523 | public LLUUID GetHostID() | ||
524 | { | ||
525 | return m_hostID; | ||
526 | } | ||
527 | |||
528 | public LLUUID GetSourceItemID() | ||
529 | { | ||
530 | return m_sourceItemID; | ||
531 | } | ||
532 | |||
533 | public int GetChannel() | ||
534 | { | ||
535 | return m_channel; | ||
536 | } | ||
537 | |||
538 | public uint GetLocalID() | ||
539 | { | ||
540 | return m_localID; | ||
541 | } | ||
542 | |||
543 | public int GetHandle() | ||
544 | { | ||
545 | return m_handle; | ||
546 | } | ||
547 | |||
548 | public string GetMessage() | ||
549 | { | ||
550 | return m_message; | ||
551 | } | ||
552 | |||
553 | public string GetName() | ||
554 | { | ||
555 | return m_name; | ||
556 | } | ||
557 | |||
558 | public bool IsActive() | ||
559 | { | ||
560 | return m_active; | ||
561 | } | ||
562 | |||
563 | public void Deactivate() | ||
564 | { | ||
565 | m_active = false; | ||
566 | } | ||
567 | |||
568 | public void Activate() | ||
569 | { | ||
570 | m_active = true; | ||
571 | } | ||
572 | |||
573 | public LLUUID GetID() | ||
574 | { | ||
575 | return m_id; | ||
576 | } | ||
577 | } | ||
578 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Environment/Modules/Scripting/XMLRPC/XMLRPCModule.cs b/OpenSim/Region/Environment/Modules/Scripting/XMLRPC/XMLRPCModule.cs new file mode 100644 index 0000000..1139b4b --- /dev/null +++ b/OpenSim/Region/Environment/Modules/Scripting/XMLRPC/XMLRPCModule.cs | |||
@@ -0,0 +1,672 @@ | |||
1 | /* | ||
2 | * Copyright (c) Contributors, http://opensimulator.org/ | ||
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | ||
4 | * | ||
5 | * Redistribution and use in source and binary forms, with or without | ||
6 | * modification, are permitted provided that the following conditions are met: | ||
7 | * * Redistributions of source code must retain the above copyright | ||
8 | * notice, this list of conditions and the following disclaimer. | ||
9 | * * Redistributions in binary form must reproduce the above copyright | ||
10 | * notice, this list of conditions and the following disclaimer in the | ||
11 | * documentation and/or other materials provided with the distribution. | ||
12 | * * Neither the name of the OpenSim Project nor the | ||
13 | * names of its contributors may be used to endorse or promote products | ||
14 | * derived from this software without specific prior written permission. | ||
15 | * | ||
16 | * THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY | ||
17 | * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED | ||
18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
19 | * DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY | ||
20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES | ||
21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||
22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND | ||
23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | ||
24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
26 | */ | ||
27 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | using System.Threading; | ||
34 | using libsecondlife; | ||
35 | using log4net; | ||
36 | using Nini.Config; | ||
37 | using Nwc.XmlRpc; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Framework.Servers; | ||
40 | using OpenSim.Region.Environment.Interfaces; | ||
41 | using OpenSim.Region.Environment.Scenes; | ||
42 | |||
43 | /***************************************************** | ||
44 | * | ||
45 | * XMLRPCModule | ||
46 | * | ||
47 | * Module for accepting incoming communications from | ||
48 | * external XMLRPC client and calling a remote data | ||
49 | * procedure for a registered data channel/prim. | ||
50 | * | ||
51 | * | ||
52 | * 1. On module load, open a listener port | ||
53 | * 2. Attach an XMLRPC handler | ||
54 | * 3. When a request is received: | ||
55 | * 3.1 Parse into components: channel key, int, string | ||
56 | * 3.2 Look up registered channel listeners | ||
57 | * 3.3 Call the channel (prim) remote data method | ||
58 | * 3.4 Capture the response (llRemoteDataReply) | ||
59 | * 3.5 Return response to client caller | ||
60 | * 3.6 If no response from llRemoteDataReply within | ||
61 | * RemoteReplyScriptTimeout, generate script timeout fault | ||
62 | * | ||
63 | * Prims in script must: | ||
64 | * 1. Open a remote data channel | ||
65 | * 1.1 Generate a channel ID | ||
66 | * 1.2 Register primid,channelid pair with module | ||
67 | * 2. Implement the remote data procedure handler | ||
68 | * | ||
69 | * llOpenRemoteDataChannel | ||
70 | * llRemoteDataReply | ||
71 | * remote_data(integer type, key channel, key messageid, string sender, integer ival, string sval) | ||
72 | * llCloseRemoteDataChannel | ||
73 | * | ||
74 | * **************************************************/ | ||
75 | |||
76 | namespace OpenSim.Region.Environment.Modules.Scripting.XMLRPC | ||
77 | { | ||
78 | public class XMLRPCModule : IRegionModule, IXMLRPC | ||
79 | { | ||
80 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
81 | |||
82 | private object XMLRPCListLock = new object(); | ||
83 | private string m_name = "XMLRPCModule"; | ||
84 | private int RemoteReplyScriptWait = 300; | ||
85 | private int RemoteReplyScriptTimeout = 9000; | ||
86 | private int m_remoteDataPort = 0; | ||
87 | private List<Scene> m_scenes = new List<Scene>(); | ||
88 | |||
89 | // <channel id, RPCChannelInfo> | ||
90 | private Dictionary<LLUUID, RPCChannelInfo> m_openChannels; | ||
91 | |||
92 | private Dictionary<LLUUID, RPCRequestInfo> m_rpcPending; | ||
93 | private Dictionary<LLUUID, RPCRequestInfo> m_rpcPendingResponses; | ||
94 | |||
95 | private Dictionary<LLUUID, SendRemoteDataRequest> m_pendingSRDResponses; | ||
96 | |||
97 | public void Initialise(Scene scene, IConfigSource config) | ||
98 | { | ||
99 | try | ||
100 | { | ||
101 | m_remoteDataPort = config.Configs["Network"].GetInt("remoteDataPort", m_remoteDataPort); | ||
102 | } | ||
103 | catch (Exception) | ||
104 | { | ||
105 | } | ||
106 | |||
107 | if (!m_scenes.Contains(scene)) | ||
108 | { | ||
109 | m_scenes.Add(scene); | ||
110 | |||
111 | scene.RegisterModuleInterface<IXMLRPC>(this); | ||
112 | } | ||
113 | } | ||
114 | |||
115 | public void PostInitialise() | ||
116 | { | ||
117 | if (IsEnabled()) | ||
118 | { | ||
119 | m_openChannels = new Dictionary<LLUUID, RPCChannelInfo>(); | ||
120 | m_rpcPending = new Dictionary<LLUUID, RPCRequestInfo>(); | ||
121 | m_rpcPendingResponses = new Dictionary<LLUUID, RPCRequestInfo>(); | ||
122 | m_pendingSRDResponses = new Dictionary<LLUUID, SendRemoteDataRequest>(); | ||
123 | |||
124 | // Start http server | ||
125 | // Attach xmlrpc handlers | ||
126 | m_log.Info("[REMOTE_DATA]: " + | ||
127 | "Starting XMLRPC Server on port " + m_remoteDataPort + " for llRemoteData commands."); | ||
128 | BaseHttpServer httpServer = new BaseHttpServer((uint)m_remoteDataPort); | ||
129 | httpServer.AddXmlRPCHandler("llRemoteData", XmlRpcRemoteData); | ||
130 | httpServer.Start(); | ||
131 | } | ||
132 | } | ||
133 | |||
134 | public void Close() | ||
135 | { | ||
136 | } | ||
137 | |||
138 | public string Name | ||
139 | { | ||
140 | get { return m_name; } | ||
141 | } | ||
142 | |||
143 | public bool IsSharedModule | ||
144 | { | ||
145 | get { return true; } | ||
146 | } | ||
147 | |||
148 | public bool IsEnabled() | ||
149 | { | ||
150 | return (m_remoteDataPort > 0); | ||
151 | } | ||
152 | |||
153 | /********************************************** | ||
154 | * OpenXMLRPCChannel | ||
155 | * | ||
156 | * Generate a LLUUID channel key and add it and | ||
157 | * the prim id to dictionary <channelUUID, primUUID> | ||
158 | * | ||
159 | * First check if there is a channel assigned for | ||
160 | * this itemID. If there is, then someone called | ||
161 | * llOpenRemoteDataChannel twice. Just return the | ||
162 | * original channel. Other option is to delete the | ||
163 | * current channel and assign a new one. | ||
164 | * | ||
165 | * ********************************************/ | ||
166 | |||
167 | public LLUUID OpenXMLRPCChannel(uint localID, LLUUID itemID) | ||
168 | { | ||
169 | LLUUID channel = new LLUUID(); | ||
170 | |||
171 | //Is a dupe? | ||
172 | foreach (RPCChannelInfo ci in m_openChannels.Values) | ||
173 | { | ||
174 | if (ci.GetItemID().Equals(itemID)) | ||
175 | { | ||
176 | // return the original channel ID for this item | ||
177 | channel = ci.GetChannelID(); | ||
178 | break; | ||
179 | } | ||
180 | } | ||
181 | |||
182 | if (channel == LLUUID.Zero) | ||
183 | { | ||
184 | channel = LLUUID.Random(); | ||
185 | RPCChannelInfo rpcChanInfo = new RPCChannelInfo(localID, itemID, channel); | ||
186 | lock (XMLRPCListLock) | ||
187 | { | ||
188 | m_openChannels.Add(channel, rpcChanInfo); | ||
189 | } | ||
190 | } | ||
191 | |||
192 | return channel; | ||
193 | } | ||
194 | |||
195 | // Delete channels based on itemID | ||
196 | // for when a script is deleted | ||
197 | public void DeleteChannels(LLUUID itemID) | ||
198 | { | ||
199 | |||
200 | if (m_openChannels != null) | ||
201 | { | ||
202 | ArrayList tmp = new ArrayList(); | ||
203 | |||
204 | lock (XMLRPCListLock) | ||
205 | { | ||
206 | foreach (RPCChannelInfo li in m_openChannels.Values) | ||
207 | { | ||
208 | if (li.GetItemID().Equals(itemID)) | ||
209 | { | ||
210 | tmp.Add(itemID); | ||
211 | } | ||
212 | } | ||
213 | |||
214 | IEnumerator tmpEnumerator = tmp.GetEnumerator(); | ||
215 | while ( tmpEnumerator.MoveNext() ) | ||
216 | m_openChannels.Remove((LLUUID)tmpEnumerator.Current); | ||
217 | } | ||
218 | |||
219 | } | ||
220 | |||
221 | } | ||
222 | |||
223 | /********************************************** | ||
224 | * Remote Data Reply | ||
225 | * | ||
226 | * Response to RPC message | ||
227 | * | ||
228 | *********************************************/ | ||
229 | |||
230 | public void RemoteDataReply(string channel, string message_id, string sdata, int idata) | ||
231 | { | ||
232 | RPCRequestInfo rpcInfo; | ||
233 | LLUUID message_key = new LLUUID(message_id); | ||
234 | |||
235 | if (m_rpcPendingResponses.TryGetValue(message_key, out rpcInfo)) | ||
236 | { | ||
237 | rpcInfo.SetStrRetval(sdata); | ||
238 | rpcInfo.SetIntRetval(idata); | ||
239 | rpcInfo.SetProcessed(true); | ||
240 | m_rpcPendingResponses.Remove(message_key); | ||
241 | } | ||
242 | } | ||
243 | |||
244 | /********************************************** | ||
245 | * CloseXMLRPCChannel | ||
246 | * | ||
247 | * Remove channel from dictionary | ||
248 | * | ||
249 | *********************************************/ | ||
250 | |||
251 | public void CloseXMLRPCChannel(LLUUID channelKey) | ||
252 | { | ||
253 | if (m_openChannels.ContainsKey(channelKey)) | ||
254 | m_openChannels.Remove(channelKey); | ||
255 | } | ||
256 | |||
257 | |||
258 | public XmlRpcResponse XmlRpcRemoteData(XmlRpcRequest request) | ||
259 | { | ||
260 | XmlRpcResponse response = new XmlRpcResponse(); | ||
261 | |||
262 | Hashtable requestData = (Hashtable)request.Params[0]; | ||
263 | bool GoodXML = (requestData.Contains("Channel") && requestData.Contains("IntValue") && | ||
264 | requestData.Contains("StringValue")); | ||
265 | |||
266 | if (GoodXML) | ||
267 | { | ||
268 | LLUUID channel = new LLUUID((string)requestData["Channel"]); | ||
269 | RPCChannelInfo rpcChanInfo; | ||
270 | if (m_openChannels.TryGetValue(channel, out rpcChanInfo)) | ||
271 | { | ||
272 | string intVal = (string)requestData["IntValue"]; | ||
273 | string strVal = (string)requestData["StringValue"]; | ||
274 | |||
275 | RPCRequestInfo rpcInfo; | ||
276 | |||
277 | lock (XMLRPCListLock) | ||
278 | { | ||
279 | rpcInfo = | ||
280 | new RPCRequestInfo(rpcChanInfo.GetLocalID(), rpcChanInfo.GetItemID(), channel, strVal, | ||
281 | intVal); | ||
282 | m_rpcPending.Add(rpcInfo.GetMessageID(), rpcInfo); | ||
283 | } | ||
284 | |||
285 | int timeoutCtr = 0; | ||
286 | |||
287 | while (!rpcInfo.IsProcessed() && (timeoutCtr < RemoteReplyScriptTimeout)) | ||
288 | { | ||
289 | Thread.Sleep(RemoteReplyScriptWait); | ||
290 | timeoutCtr += RemoteReplyScriptWait; | ||
291 | } | ||
292 | if (rpcInfo.IsProcessed()) | ||
293 | { | ||
294 | Hashtable param = new Hashtable(); | ||
295 | param["StringValue"] = rpcInfo.GetStrRetval(); | ||
296 | param["IntValue"] = Convert.ToString(rpcInfo.GetIntRetval()); | ||
297 | |||
298 | ArrayList parameters = new ArrayList(); | ||
299 | parameters.Add(param); | ||
300 | |||
301 | response.Value = parameters; | ||
302 | rpcInfo = null; | ||
303 | } | ||
304 | else | ||
305 | { | ||
306 | response.SetFault(-1, "Script timeout"); | ||
307 | rpcInfo = null; | ||
308 | } | ||
309 | } | ||
310 | else | ||
311 | { | ||
312 | response.SetFault(-1, "Invalid channel"); | ||
313 | } | ||
314 | } | ||
315 | |||
316 | return response; | ||
317 | } | ||
318 | |||
319 | public bool hasRequests() | ||
320 | { | ||
321 | lock (XMLRPCListLock) | ||
322 | { | ||
323 | if (m_rpcPending != null) | ||
324 | return (m_rpcPending.Count > 0); | ||
325 | else | ||
326 | return false; | ||
327 | } | ||
328 | } | ||
329 | |||
330 | public RPCRequestInfo GetNextCompletedRequest() | ||
331 | { | ||
332 | if (m_rpcPending != null) | ||
333 | { | ||
334 | lock (XMLRPCListLock) | ||
335 | { | ||
336 | foreach (LLUUID luid in m_rpcPending.Keys) | ||
337 | { | ||
338 | RPCRequestInfo tmpReq; | ||
339 | |||
340 | if (m_rpcPending.TryGetValue(luid, out tmpReq)) | ||
341 | { | ||
342 | |||
343 | if (!tmpReq.IsProcessed()) return tmpReq; | ||
344 | } | ||
345 | } | ||
346 | } | ||
347 | } | ||
348 | return null; | ||
349 | } | ||
350 | |||
351 | public void RemoveCompletedRequest(LLUUID id) | ||
352 | { | ||
353 | lock (XMLRPCListLock) | ||
354 | { | ||
355 | RPCRequestInfo tmp; | ||
356 | if (m_rpcPending.TryGetValue(id, out tmp)) | ||
357 | { | ||
358 | m_rpcPending.Remove(id); | ||
359 | m_rpcPendingResponses.Add(id, tmp); | ||
360 | } | ||
361 | else | ||
362 | { | ||
363 | Console.WriteLine("UNABLE TO REMOVE COMPLETED REQUEST"); | ||
364 | } | ||
365 | } | ||
366 | } | ||
367 | |||
368 | public LLUUID SendRemoteData(uint localID, LLUUID itemID, string channel, string dest, int idata, string sdata) | ||
369 | { | ||
370 | |||
371 | SendRemoteDataRequest req = new SendRemoteDataRequest( | ||
372 | localID, itemID, channel, dest, idata, sdata | ||
373 | ); | ||
374 | m_pendingSRDResponses.Add(req.GetReqID(), req); | ||
375 | return req.process(); | ||
376 | |||
377 | } | ||
378 | |||
379 | public SendRemoteDataRequest GetNextCompletedSRDRequest() | ||
380 | { | ||
381 | if (m_pendingSRDResponses != null) | ||
382 | { | ||
383 | lock (XMLRPCListLock) | ||
384 | { | ||
385 | foreach (LLUUID luid in m_pendingSRDResponses.Keys) | ||
386 | { | ||
387 | SendRemoteDataRequest tmpReq; | ||
388 | |||
389 | if (m_pendingSRDResponses.TryGetValue(luid, out tmpReq)) | ||
390 | { | ||
391 | if (tmpReq.finished) | ||
392 | return tmpReq; | ||
393 | } | ||
394 | } | ||
395 | } | ||
396 | } | ||
397 | return null; | ||
398 | } | ||
399 | |||
400 | public void RemoveCompletedSRDRequest(LLUUID id) | ||
401 | { | ||
402 | lock (XMLRPCListLock) | ||
403 | { | ||
404 | SendRemoteDataRequest tmpReq; | ||
405 | if (m_pendingSRDResponses.TryGetValue(id, out tmpReq)) | ||
406 | { | ||
407 | m_pendingSRDResponses.Remove(id); | ||
408 | } | ||
409 | } | ||
410 | } | ||
411 | |||
412 | public void CancelSRDRequests(LLUUID itemID) | ||
413 | { | ||
414 | if (m_pendingSRDResponses != null) | ||
415 | { | ||
416 | lock (XMLRPCListLock) | ||
417 | { | ||
418 | foreach (SendRemoteDataRequest li in m_pendingSRDResponses.Values) | ||
419 | { | ||
420 | if (li.m_itemID.Equals(itemID)) | ||
421 | m_pendingSRDResponses.Remove(li.GetReqID()); | ||
422 | } | ||
423 | } | ||
424 | } | ||
425 | } | ||
426 | } | ||
427 | |||
428 | public class RPCRequestInfo | ||
429 | { | ||
430 | private string m_StrVal; | ||
431 | private string m_IntVal; | ||
432 | private bool m_processed; | ||
433 | private string m_respStr; | ||
434 | private int m_respInt; | ||
435 | private uint m_localID; | ||
436 | private LLUUID m_ItemID; | ||
437 | private LLUUID m_MessageID; | ||
438 | private LLUUID m_ChannelKey; | ||
439 | |||
440 | public RPCRequestInfo(uint localID, LLUUID itemID, LLUUID channelKey, string strVal, string intVal) | ||
441 | { | ||
442 | m_localID = localID; | ||
443 | m_StrVal = strVal; | ||
444 | m_IntVal = intVal; | ||
445 | m_ItemID = itemID; | ||
446 | m_ChannelKey = channelKey; | ||
447 | m_MessageID = LLUUID.Random(); | ||
448 | m_processed = false; | ||
449 | m_respStr = String.Empty; | ||
450 | m_respInt = 0; | ||
451 | } | ||
452 | |||
453 | public bool IsProcessed() | ||
454 | { | ||
455 | return m_processed; | ||
456 | } | ||
457 | |||
458 | public LLUUID GetChannelKey() | ||
459 | { | ||
460 | return m_ChannelKey; | ||
461 | } | ||
462 | |||
463 | public void SetProcessed(bool processed) | ||
464 | { | ||
465 | m_processed = processed; | ||
466 | } | ||
467 | |||
468 | public void SetStrRetval(string resp) | ||
469 | { | ||
470 | m_respStr = resp; | ||
471 | } | ||
472 | |||
473 | public string GetStrRetval() | ||
474 | { | ||
475 | return m_respStr; | ||
476 | } | ||
477 | public void SetIntRetval(int resp) | ||
478 | { | ||
479 | m_respInt = resp; | ||
480 | } | ||
481 | |||
482 | public int GetIntRetval() | ||
483 | { | ||
484 | return m_respInt; | ||
485 | } | ||
486 | public uint GetLocalID() | ||
487 | { | ||
488 | return m_localID; | ||
489 | } | ||
490 | |||
491 | public LLUUID GetItemID() | ||
492 | { | ||
493 | return m_ItemID; | ||
494 | } | ||
495 | |||
496 | public string GetStrVal() | ||
497 | { | ||
498 | return m_StrVal; | ||
499 | } | ||
500 | |||
501 | public int GetIntValue() | ||
502 | { | ||
503 | return int.Parse(m_IntVal); | ||
504 | } | ||
505 | |||
506 | public LLUUID GetMessageID() | ||
507 | { | ||
508 | return m_MessageID; | ||
509 | } | ||
510 | } | ||
511 | |||
512 | public class RPCChannelInfo | ||
513 | { | ||
514 | private LLUUID m_itemID; | ||
515 | private uint m_localID; | ||
516 | private LLUUID m_ChannelKey; | ||
517 | |||
518 | public RPCChannelInfo(uint localID, LLUUID itemID, LLUUID channelID) | ||
519 | { | ||
520 | m_ChannelKey = channelID; | ||
521 | m_localID = localID; | ||
522 | m_itemID = itemID; | ||
523 | } | ||
524 | |||
525 | public LLUUID GetItemID() | ||
526 | { | ||
527 | return m_itemID; | ||
528 | } | ||
529 | |||
530 | public LLUUID GetChannelID() | ||
531 | { | ||
532 | return m_ChannelKey; | ||
533 | } | ||
534 | |||
535 | public uint GetLocalID() | ||
536 | { | ||
537 | return m_localID; | ||
538 | } | ||
539 | |||
540 | } | ||
541 | |||
542 | public class SendRemoteDataRequest | ||
543 | { | ||
544 | |||
545 | public LLUUID reqID; | ||
546 | public string destURL; | ||
547 | public string channel; | ||
548 | public string sdata; | ||
549 | public int idata; | ||
550 | public bool finished; | ||
551 | public string response_sdata; | ||
552 | public int response_idata; | ||
553 | public XmlRpcRequest request; | ||
554 | private Thread httpThread; | ||
555 | public LLUUID m_itemID; | ||
556 | public uint m_localID; | ||
557 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
558 | |||
559 | public SendRemoteDataRequest(uint localID, LLUUID itemID, string channel, string dest, int idata, string sdata) | ||
560 | { | ||
561 | |||
562 | this.channel = channel; | ||
563 | this.destURL = dest; | ||
564 | this.idata = idata; | ||
565 | this.sdata = sdata; | ||
566 | m_itemID = itemID; | ||
567 | m_localID = localID; | ||
568 | |||
569 | reqID = LLUUID.Random(); | ||
570 | |||
571 | } | ||
572 | |||
573 | public LLUUID process() | ||
574 | { | ||
575 | httpThread = new Thread(SendRequest); | ||
576 | httpThread.Name = "HttpRequestThread"; | ||
577 | httpThread.Priority = ThreadPriority.BelowNormal; | ||
578 | httpThread.IsBackground = true; | ||
579 | finished = false; | ||
580 | httpThread.Start(); | ||
581 | ThreadTracker.Add(httpThread); | ||
582 | |||
583 | return reqID; | ||
584 | |||
585 | } | ||
586 | |||
587 | /* | ||
588 | * TODO: More work on the response codes. Right now | ||
589 | * returning 200 for success or 499 for exception | ||
590 | */ | ||
591 | |||
592 | public void SendRequest() | ||
593 | { | ||
594 | Hashtable param = new Hashtable(); | ||
595 | |||
596 | // Check if channel is an LLUUID | ||
597 | // if not, use as method name | ||
598 | LLUUID parseUID; | ||
599 | string mName = "llRemoteData"; | ||
600 | if( (channel != null) && (channel != "") ) | ||
601 | if( !LLUUID.TryParse(channel, out parseUID) ) | ||
602 | mName = channel; | ||
603 | else | ||
604 | param["Channel"] = channel; | ||
605 | |||
606 | param["StringValue"] = sdata; | ||
607 | param["IntValue"] = Convert.ToString(idata); | ||
608 | |||
609 | ArrayList parameters = new ArrayList(); | ||
610 | parameters.Add(param); | ||
611 | XmlRpcRequest req = new XmlRpcRequest(mName, parameters); | ||
612 | try | ||
613 | { | ||
614 | XmlRpcResponse resp = req.Send(destURL, 30000); | ||
615 | if (resp != null) | ||
616 | { | ||
617 | Hashtable respParms; | ||
618 | if(resp.Value.GetType().Equals(Type.GetType("System.Collections.Hashtable"))) { | ||
619 | respParms = (Hashtable)resp.Value; | ||
620 | } | ||
621 | else { | ||
622 | ArrayList respData = (ArrayList)resp.Value; | ||
623 | respParms = (Hashtable)respData[0]; | ||
624 | } | ||
625 | if (respParms != null) | ||
626 | { | ||
627 | if (respParms.Contains("StringValue")) | ||
628 | { | ||
629 | sdata = (string)respParms["StringValue"]; | ||
630 | } | ||
631 | if (respParms.Contains("IntValue")) | ||
632 | { | ||
633 | idata = Convert.ToInt32((string)respParms["IntValue"]); | ||
634 | } | ||
635 | if (respParms.Contains("faultString")) | ||
636 | { | ||
637 | sdata = (string)respParms["faultString"]; | ||
638 | } | ||
639 | if (respParms.Contains("faultCode")) | ||
640 | { | ||
641 | idata = Convert.ToInt32(respParms["faultCode"]); | ||
642 | } | ||
643 | } | ||
644 | } | ||
645 | } | ||
646 | catch (WebException we) | ||
647 | { | ||
648 | sdata = we.Message; | ||
649 | m_log.Warn("[SendRemoteDataRequest]: Request failed"); | ||
650 | m_log.Warn(we.StackTrace); | ||
651 | } | ||
652 | |||
653 | finished = true; | ||
654 | } | ||
655 | |||
656 | public void Stop() | ||
657 | { | ||
658 | try | ||
659 | { | ||
660 | httpThread.Abort(); | ||
661 | } | ||
662 | catch (Exception) | ||
663 | { | ||
664 | } | ||
665 | } | ||
666 | |||
667 | public LLUUID GetReqID() | ||
668 | { | ||
669 | return reqID; | ||
670 | } | ||
671 | } | ||
672 | } \ No newline at end of file | ||