diff options
author | lbsa71 | 2008-01-03 13:40:38 +0000 |
---|---|---|
committer | lbsa71 | 2008-01-03 13:40:38 +0000 |
commit | 1d098aa84c8c82a4e62ebbaa20809a0efd3e8774 (patch) | |
tree | 515865fcaf2f2d80fdfe9ac9046865ebb2979dd7 /OpenSim | |
parent | * Added lock to Contains to avoid enumeration exceptions (diff) | |
download | opensim-SC-1d098aa84c8c82a4e62ebbaa20809a0efd3e8774.zip opensim-SC-1d098aa84c8c82a4e62ebbaa20809a0efd3e8774.tar.gz opensim-SC-1d098aa84c8c82a4e62ebbaa20809a0efd3e8774.tar.bz2 opensim-SC-1d098aa84c8c82a4e62ebbaa20809a0efd3e8774.tar.xz |
* Some work on TextureDownloadModule
* fixed Cancel bug
Diffstat (limited to 'OpenSim')
3 files changed, 236 insertions, 214 deletions
diff --git a/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs b/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs index 6d5d5e8..4e96572 100644 --- a/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs +++ b/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs | |||
@@ -132,6 +132,8 @@ namespace OpenSim.Region.Environment.Modules | |||
132 | if (sender.Cancel) | 132 | if (sender.Cancel) |
133 | { | 133 | { |
134 | TextureSent(sender); | 134 | TextureSent(sender); |
135 | |||
136 | sender.Cancel = false; | ||
135 | } | 137 | } |
136 | else | 138 | else |
137 | { | 139 | { |
@@ -152,219 +154,5 @@ namespace OpenSim.Region.Environment.Modules | |||
152 | { | 154 | { |
153 | sender.Sending = false; | 155 | sender.Sending = false; |
154 | } | 156 | } |
155 | |||
156 | public class UserTextureDownloadService | ||
157 | { | ||
158 | private readonly Dictionary<LLUUID, TextureSender> m_textureSenders = new Dictionary<LLUUID, TextureSender>(); | ||
159 | private readonly BlockingQueue<TextureSender> m_sharedSendersQueue; | ||
160 | private readonly Scene m_scene; | ||
161 | |||
162 | public UserTextureDownloadService(Scene scene, BlockingQueue<TextureSender> sharedQueue) | ||
163 | { | ||
164 | m_scene = scene; | ||
165 | m_sharedSendersQueue = sharedQueue; | ||
166 | } | ||
167 | |||
168 | public void HandleTextureRequest(IClientAPI client, TextureRequestArgs e) | ||
169 | { | ||
170 | TextureSender textureSender; | ||
171 | |||
172 | //TODO: should be working out the data size/ number of packets to be sent for each discard level | ||
173 | if ((e.DiscardLevel >= 0) || (e.Priority != 0)) | ||
174 | { | ||
175 | lock (m_textureSenders) | ||
176 | { | ||
177 | if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender)) | ||
178 | { | ||
179 | textureSender.UpdateRequest(e.DiscardLevel, e.PacketNumber); | ||
180 | textureSender.counter = 0; | ||
181 | |||
182 | if ((textureSender.ImageLoaded) && | ||
183 | (textureSender.Sending == false)) | ||
184 | { | ||
185 | textureSender.Sending = true; | ||
186 | |||
187 | if (!m_sharedSendersQueue.Contains(textureSender)) | ||
188 | { | ||
189 | m_sharedSendersQueue.Enqueue(textureSender); | ||
190 | } | ||
191 | } | ||
192 | } | ||
193 | else | ||
194 | { | ||
195 | TextureSender requestHandler = | ||
196 | new TextureSender(client, e.RequestedAssetID, e.DiscardLevel, e.PacketNumber); | ||
197 | m_textureSenders.Add(e.RequestedAssetID, requestHandler); | ||
198 | m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback); | ||
199 | } | ||
200 | } | ||
201 | } | ||
202 | else | ||
203 | { | ||
204 | lock (m_textureSenders) | ||
205 | { | ||
206 | if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender)) | ||
207 | { | ||
208 | textureSender.Cancel = true; | ||
209 | } | ||
210 | } | ||
211 | } | ||
212 | } | ||
213 | |||
214 | public void TextureCallback(LLUUID textureID, AssetBase asset) | ||
215 | { | ||
216 | lock (m_textureSenders) | ||
217 | { | ||
218 | TextureSender textureSender; | ||
219 | |||
220 | if (m_textureSenders.TryGetValue(textureID, out textureSender)) | ||
221 | { | ||
222 | if (!textureSender.ImageLoaded) | ||
223 | { | ||
224 | textureSender.TextureReceived(asset); | ||
225 | textureSender.Sending = true; | ||
226 | textureSender.counter = 0; | ||
227 | |||
228 | if (!m_sharedSendersQueue.Contains(textureSender)) | ||
229 | { | ||
230 | m_sharedSendersQueue.Enqueue(textureSender); | ||
231 | } | ||
232 | } | ||
233 | } | ||
234 | else | ||
235 | { | ||
236 | throw new Exception("Got a texture with no sender object to handle it, this shouldn't happen"); | ||
237 | } | ||
238 | } | ||
239 | } | ||
240 | } | ||
241 | |||
242 | public class TextureSender | ||
243 | { | ||
244 | public int counter = 0; | ||
245 | private AssetBase m_asset; | ||
246 | public long DataPointer = 0; | ||
247 | public int NumPackets = 0; | ||
248 | public int PacketCounter = 0; | ||
249 | public bool Cancel = false; | ||
250 | public bool ImageLoaded = false; | ||
251 | |||
252 | public bool Sending = false; | ||
253 | |||
254 | public IClientAPI RequestUser; | ||
255 | public LLUUID RequestedAssetID; | ||
256 | public int RequestedDiscardLevel = -1; | ||
257 | public uint StartPacketNumber = 0; | ||
258 | |||
259 | // private int m_sentDiscardLevel = -1; | ||
260 | |||
261 | public TextureSender(IClientAPI client, LLUUID textureID, int discardLevel, uint packetNumber) | ||
262 | { | ||
263 | RequestUser = client; | ||
264 | RequestedAssetID = textureID; | ||
265 | RequestedDiscardLevel = discardLevel; | ||
266 | StartPacketNumber = packetNumber; | ||
267 | } | ||
268 | |||
269 | public void TextureReceived(AssetBase asset) | ||
270 | { | ||
271 | m_asset = asset; | ||
272 | NumPackets = CalculateNumPackets(asset.Data.Length); | ||
273 | PacketCounter = (int) StartPacketNumber; | ||
274 | ImageLoaded = true; | ||
275 | } | ||
276 | |||
277 | public void UpdateRequest(int discardLevel, uint packetNumber) | ||
278 | { | ||
279 | RequestedDiscardLevel = discardLevel; | ||
280 | StartPacketNumber = packetNumber; | ||
281 | PacketCounter = (int) StartPacketNumber; | ||
282 | } | ||
283 | |||
284 | public bool SendTexturePacket() | ||
285 | { | ||
286 | SendPacket(); | ||
287 | counter++; | ||
288 | if ((NumPackets == 0) || (RequestedDiscardLevel == -1) || (PacketCounter > NumPackets) || | ||
289 | ((RequestedDiscardLevel > 0) && (counter > 50 + (NumPackets/(RequestedDiscardLevel + 1))))) | ||
290 | { | ||
291 | return true; | ||
292 | } | ||
293 | return false; | ||
294 | } | ||
295 | |||
296 | private void SendPacket() | ||
297 | { | ||
298 | if (PacketCounter <= NumPackets) | ||
299 | { | ||
300 | if (PacketCounter == 0) | ||
301 | { | ||
302 | if (NumPackets == 0) | ||
303 | { | ||
304 | ImageDataPacket im = new ImageDataPacket(); | ||
305 | im.Header.Reliable = false; | ||
306 | im.ImageID.Packets = 1; | ||
307 | im.ImageID.ID = m_asset.FullID; | ||
308 | im.ImageID.Size = (uint) m_asset.Data.Length; | ||
309 | im.ImageData.Data = m_asset.Data; | ||
310 | im.ImageID.Codec = 2; | ||
311 | RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); | ||
312 | PacketCounter++; | ||
313 | } | ||
314 | else | ||
315 | { | ||
316 | ImageDataPacket im = new ImageDataPacket(); | ||
317 | im.Header.Reliable = false; | ||
318 | im.ImageID.Packets = (ushort) (NumPackets); | ||
319 | im.ImageID.ID = m_asset.FullID; | ||
320 | im.ImageID.Size = (uint) m_asset.Data.Length; | ||
321 | im.ImageData.Data = new byte[600]; | ||
322 | Array.Copy(m_asset.Data, 0, im.ImageData.Data, 0, 600); | ||
323 | im.ImageID.Codec = 2; | ||
324 | RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); | ||
325 | PacketCounter++; | ||
326 | } | ||
327 | } | ||
328 | else | ||
329 | { | ||
330 | ImagePacketPacket im = new ImagePacketPacket(); | ||
331 | im.Header.Reliable = false; | ||
332 | im.ImageID.Packet = (ushort) (PacketCounter); | ||
333 | im.ImageID.ID = m_asset.FullID; | ||
334 | int size = m_asset.Data.Length - 600 - (1000*(PacketCounter - 1)); | ||
335 | if (size > 1000) size = 1000; | ||
336 | im.ImageData.Data = new byte[size]; | ||
337 | try | ||
338 | { | ||
339 | Array.Copy(m_asset.Data, 600 + (1000*(PacketCounter - 1)), im.ImageData.Data, 0, size); | ||
340 | } | ||
341 | catch (ArgumentOutOfRangeException) | ||
342 | { | ||
343 | MainLog.Instance.Error("TEXTURE", | ||
344 | "Unable to separate texture into multiple packets: Array bounds failure on asset:" + | ||
345 | m_asset.FullID.ToString() ); | ||
346 | return; | ||
347 | } | ||
348 | RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); | ||
349 | PacketCounter++; | ||
350 | } | ||
351 | } | ||
352 | } | ||
353 | |||
354 | private int CalculateNumPackets(int length) | ||
355 | { | ||
356 | int numPackets = 0; | ||
357 | |||
358 | if (length > 600) | ||
359 | { | ||
360 | //over 600 bytes so split up file | ||
361 | int restData = (length - 600); | ||
362 | int restPackets = ((restData + 999)/1000); | ||
363 | numPackets = restPackets; | ||
364 | } | ||
365 | |||
366 | return numPackets; | ||
367 | } | ||
368 | } | ||
369 | } | 157 | } |
370 | } \ No newline at end of file | 158 | } \ No newline at end of file |
diff --git a/OpenSim/Region/Environment/Modules/TextureSender.cs b/OpenSim/Region/Environment/Modules/TextureSender.cs new file mode 100644 index 0000000..aba0126 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/TextureSender.cs | |||
@@ -0,0 +1,136 @@ | |||
1 | using System; | ||
2 | using libsecondlife; | ||
3 | using libsecondlife.Packets; | ||
4 | using OpenSim.Framework; | ||
5 | using OpenSim.Framework.Console; | ||
6 | |||
7 | namespace OpenSim.Region.Environment.Modules | ||
8 | { | ||
9 | public class TextureSender | ||
10 | { | ||
11 | public int counter = 0; | ||
12 | private AssetBase m_asset; | ||
13 | public long DataPointer = 0; | ||
14 | public int NumPackets = 0; | ||
15 | public int PacketCounter = 0; | ||
16 | public bool Cancel = false; | ||
17 | public bool ImageLoaded = false; | ||
18 | |||
19 | public bool Sending = false; | ||
20 | |||
21 | public IClientAPI RequestUser; | ||
22 | public LLUUID RequestedAssetID; | ||
23 | public int RequestedDiscardLevel = -1; | ||
24 | public uint StartPacketNumber = 0; | ||
25 | |||
26 | // private int m_sentDiscardLevel = -1; | ||
27 | |||
28 | public TextureSender(IClientAPI client, LLUUID textureID, int discardLevel, uint packetNumber) | ||
29 | { | ||
30 | RequestUser = client; | ||
31 | RequestedAssetID = textureID; | ||
32 | RequestedDiscardLevel = discardLevel; | ||
33 | StartPacketNumber = packetNumber; | ||
34 | } | ||
35 | |||
36 | public void TextureReceived(AssetBase asset) | ||
37 | { | ||
38 | m_asset = asset; | ||
39 | NumPackets = CalculateNumPackets(asset.Data.Length); | ||
40 | PacketCounter = (int) StartPacketNumber; | ||
41 | ImageLoaded = true; | ||
42 | } | ||
43 | |||
44 | public void UpdateRequest(int discardLevel, uint packetNumber) | ||
45 | { | ||
46 | RequestedDiscardLevel = discardLevel; | ||
47 | StartPacketNumber = packetNumber; | ||
48 | PacketCounter = (int) StartPacketNumber; | ||
49 | } | ||
50 | |||
51 | public bool SendTexturePacket() | ||
52 | { | ||
53 | SendPacket(); | ||
54 | counter++; | ||
55 | if ((NumPackets == 0) || (RequestedDiscardLevel == -1) || (PacketCounter > NumPackets) || | ||
56 | ((RequestedDiscardLevel > 0) && (counter > 50 + (NumPackets/(RequestedDiscardLevel + 1))))) | ||
57 | { | ||
58 | return true; | ||
59 | } | ||
60 | return false; | ||
61 | } | ||
62 | |||
63 | private void SendPacket() | ||
64 | { | ||
65 | if (PacketCounter <= NumPackets) | ||
66 | { | ||
67 | if (PacketCounter == 0) | ||
68 | { | ||
69 | if (NumPackets == 0) | ||
70 | { | ||
71 | ImageDataPacket im = new ImageDataPacket(); | ||
72 | im.Header.Reliable = false; | ||
73 | im.ImageID.Packets = 1; | ||
74 | im.ImageID.ID = m_asset.FullID; | ||
75 | im.ImageID.Size = (uint) m_asset.Data.Length; | ||
76 | im.ImageData.Data = m_asset.Data; | ||
77 | im.ImageID.Codec = 2; | ||
78 | RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); | ||
79 | PacketCounter++; | ||
80 | } | ||
81 | else | ||
82 | { | ||
83 | ImageDataPacket im = new ImageDataPacket(); | ||
84 | im.Header.Reliable = false; | ||
85 | im.ImageID.Packets = (ushort) (NumPackets); | ||
86 | im.ImageID.ID = m_asset.FullID; | ||
87 | im.ImageID.Size = (uint) m_asset.Data.Length; | ||
88 | im.ImageData.Data = new byte[600]; | ||
89 | Array.Copy(m_asset.Data, 0, im.ImageData.Data, 0, 600); | ||
90 | im.ImageID.Codec = 2; | ||
91 | RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); | ||
92 | PacketCounter++; | ||
93 | } | ||
94 | } | ||
95 | else | ||
96 | { | ||
97 | ImagePacketPacket im = new ImagePacketPacket(); | ||
98 | im.Header.Reliable = false; | ||
99 | im.ImageID.Packet = (ushort) (PacketCounter); | ||
100 | im.ImageID.ID = m_asset.FullID; | ||
101 | int size = m_asset.Data.Length - 600 - (1000*(PacketCounter - 1)); | ||
102 | if (size > 1000) size = 1000; | ||
103 | im.ImageData.Data = new byte[size]; | ||
104 | try | ||
105 | { | ||
106 | Array.Copy(m_asset.Data, 600 + (1000*(PacketCounter - 1)), im.ImageData.Data, 0, size); | ||
107 | } | ||
108 | catch (ArgumentOutOfRangeException) | ||
109 | { | ||
110 | MainLog.Instance.Error("TEXTURE", | ||
111 | "Unable to separate texture into multiple packets: Array bounds failure on asset:" + | ||
112 | m_asset.FullID.ToString() ); | ||
113 | return; | ||
114 | } | ||
115 | RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); | ||
116 | PacketCounter++; | ||
117 | } | ||
118 | } | ||
119 | } | ||
120 | |||
121 | private int CalculateNumPackets(int length) | ||
122 | { | ||
123 | int numPackets = 0; | ||
124 | |||
125 | if (length > 600) | ||
126 | { | ||
127 | //over 600 bytes so split up file | ||
128 | int restData = (length - 600); | ||
129 | int restPackets = ((restData + 999)/1000); | ||
130 | numPackets = restPackets; | ||
131 | } | ||
132 | |||
133 | return numPackets; | ||
134 | } | ||
135 | } | ||
136 | } \ No newline at end of file | ||
diff --git a/OpenSim/Region/Environment/Modules/UserTextureDownloadService.cs b/OpenSim/Region/Environment/Modules/UserTextureDownloadService.cs new file mode 100644 index 0000000..6ee43e2 --- /dev/null +++ b/OpenSim/Region/Environment/Modules/UserTextureDownloadService.cs | |||
@@ -0,0 +1,98 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using libsecondlife; | ||
4 | using OpenSim.Framework; | ||
5 | using OpenSim.Framework.Console; | ||
6 | using OpenSim.Region.Environment.Scenes; | ||
7 | |||
8 | namespace OpenSim.Region.Environment.Modules | ||
9 | { | ||
10 | public class UserTextureDownloadService | ||
11 | { | ||
12 | private readonly Dictionary<LLUUID, TextureSender> m_textureSenders = new Dictionary<LLUUID, TextureSender>(); | ||
13 | private readonly BlockingQueue<TextureSender> m_sharedSendersQueue; | ||
14 | private readonly Scene m_scene; | ||
15 | |||
16 | public UserTextureDownloadService(Scene scene, BlockingQueue<TextureSender> sharedQueue) | ||
17 | { | ||
18 | m_scene = scene; | ||
19 | m_sharedSendersQueue = sharedQueue; | ||
20 | } | ||
21 | |||
22 | public void HandleTextureRequest(IClientAPI client, TextureRequestArgs e) | ||
23 | { | ||
24 | TextureSender textureSender; | ||
25 | |||
26 | //TODO: should be working out the data size/ number of packets to be sent for each discard level | ||
27 | if ((e.DiscardLevel >= 0) || (e.Priority != 0)) | ||
28 | { | ||
29 | lock (m_textureSenders) | ||
30 | { | ||
31 | if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender)) | ||
32 | { | ||
33 | textureSender.UpdateRequest(e.DiscardLevel, e.PacketNumber); | ||
34 | |||
35 | if ((textureSender.ImageLoaded) && | ||
36 | (textureSender.Sending == false)) | ||
37 | { | ||
38 | EnqueueTextureSender(textureSender); | ||
39 | } | ||
40 | } | ||
41 | else | ||
42 | { | ||
43 | TextureSender requestHandler = | ||
44 | new TextureSender(client, e.RequestedAssetID, e.DiscardLevel, e.PacketNumber); | ||
45 | m_textureSenders.Add(e.RequestedAssetID, requestHandler); | ||
46 | m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback); | ||
47 | } | ||
48 | } | ||
49 | } | ||
50 | else | ||
51 | { | ||
52 | lock (m_textureSenders) | ||
53 | { | ||
54 | if (m_textureSenders.TryGetValue(e.RequestedAssetID, out textureSender)) | ||
55 | { | ||
56 | textureSender.Cancel = true; | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | } | ||
61 | |||
62 | public void TextureCallback(LLUUID textureID, AssetBase asset) | ||
63 | { | ||
64 | lock (m_textureSenders) | ||
65 | { | ||
66 | TextureSender textureSender; | ||
67 | |||
68 | if (m_textureSenders.TryGetValue(textureID, out textureSender)) | ||
69 | { | ||
70 | if (!textureSender.ImageLoaded) | ||
71 | { | ||
72 | textureSender.TextureReceived(asset); | ||
73 | |||
74 | EnqueueTextureSender(textureSender); | ||
75 | } | ||
76 | } | ||
77 | else | ||
78 | { | ||
79 | throw new Exception("Got a texture with no sender object to handle it, this shouldn't happen"); | ||
80 | } | ||
81 | } | ||
82 | } | ||
83 | |||
84 | private void EnqueueTextureSender(TextureSender textureSender) | ||
85 | { | ||
86 | MainLog.Instance.Debug( "TEXTUREDOWNLOAD", "Start: ["+textureSender.RequestedAssetID+"] to ["+textureSender.RequestUser.Name+"]"); | ||
87 | |||
88 | textureSender.Cancel = false; | ||
89 | textureSender.Sending = true; | ||
90 | textureSender.counter = 0; | ||
91 | |||
92 | if (!m_sharedSendersQueue.Contains(textureSender)) | ||
93 | { | ||
94 | m_sharedSendersQueue.Enqueue(textureSender); | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | } \ No newline at end of file | ||