aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/AssetDownloadModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Environment/Modules/AssetDownloadModule.cs')
-rw-r--r--OpenSim/Region/Environment/Modules/AssetDownloadModule.cs270
1 files changed, 268 insertions, 2 deletions
diff --git a/OpenSim/Region/Environment/Modules/AssetDownloadModule.cs b/OpenSim/Region/Environment/Modules/AssetDownloadModule.cs
index 012f920..ca01cae 100644
--- a/OpenSim/Region/Environment/Modules/AssetDownloadModule.cs
+++ b/OpenSim/Region/Environment/Modules/AssetDownloadModule.cs
@@ -26,25 +26,57 @@
26* 26*
27*/ 27*/
28 28
29using System;
30using System.Collections.Generic;
31using System.Threading;
29using Nini.Config; 32using Nini.Config;
30using OpenSim.Framework; 33using OpenSim.Framework;
31using OpenSim.Region.Environment.Interfaces; 34using OpenSim.Region.Environment.Interfaces;
32using OpenSim.Region.Environment.Scenes; 35using OpenSim.Region.Environment.Scenes;
36using libsecondlife;
37using libsecondlife.Packets;
33 38
34namespace OpenSim.Region.Environment.Modules 39namespace OpenSim.Region.Environment.Modules
35{ 40{
36 public class AssetDownloadModule : IRegionModule 41 public class AssetDownloadModule : IRegionModule
37 { 42 {
38 private Scene m_scene; 43 private Scene m_scene;
44 private Dictionary<LLUUID, Scene> RegisteredScenes = new Dictionary<LLUUID, Scene>();
45 ///
46 /// Assets requests (for each user) which are waiting for asset server data. This includes texture requests
47 /// </summary>
48 private Dictionary<LLUUID, Dictionary<LLUUID,AssetRequest>> RequestedAssets;
49
50 /// <summary>
51 /// Asset requests with data which are ready to be sent back to requesters. This includes textures.
52 /// </summary>
53 private List<AssetRequest> AssetRequests;
54
55 private Thread m_thread;
39 56
40 public AssetDownloadModule() 57 public AssetDownloadModule()
41 { 58 {
59 RequestedAssets = new Dictionary<LLUUID, Dictionary<LLUUID, AssetRequest>>();
60 AssetRequests = new List<AssetRequest>();
42 } 61 }
43 62
44 public void Initialise(Scene scene, IConfigSource config) 63 public void Initialise(Scene scene, IConfigSource config)
45 { 64 {
46 m_scene = scene; 65 if (!RegisteredScenes.ContainsKey(scene.RegionInfo.RegionID))
47 m_scene.EventManager.OnNewClient += NewClient; 66 {
67 RegisteredScenes.Add(scene.RegionInfo.RegionID, scene);
68 scene.EventManager.OnNewClient += NewClient;
69 }
70
71 if (m_scene == null)
72 {
73 m_scene = scene;
74 m_thread = new Thread(new ThreadStart(RunAssetQueue));
75 m_thread.Name = "AssetDownloadQueueThread";
76 m_thread.IsBackground = true;
77 m_thread.Start();
78 OpenSim.Framework.ThreadTracker.Add(m_thread);
79 }
48 } 80 }
49 81
50 public void PostInitialise() 82 public void PostInitialise()
@@ -67,6 +99,240 @@ namespace OpenSim.Region.Environment.Modules
67 99
68 public void NewClient(IClientAPI client) 100 public void NewClient(IClientAPI client)
69 { 101 {
102 client.OnRequestAsset += AddAssetRequest;
103 }
104
105 /// <summary>
106 /// Make an asset request the result of which will be packeted up and sent directly back to the client.
107 /// </summary>
108 /// <param name="userInfo"></param>
109 /// <param name="transferRequest"></param>
110 public void AddAssetRequest(IClientAPI userInfo, TransferRequestPacket transferRequest)
111 {
112 LLUUID requestID = null;
113 byte source = 2;
114 if (transferRequest.TransferInfo.SourceType == 2)
115 {
116 //direct asset request
117 requestID = new LLUUID(transferRequest.TransferInfo.Params, 0);
118 }
119 else if (transferRequest.TransferInfo.SourceType == 3)
120 {
121 //inventory asset request
122 requestID = new LLUUID(transferRequest.TransferInfo.Params, 80);
123 source = 3;
124 //Console.WriteLine("asset request " + requestID);
125 }
126
127 //not found asset
128 // so request from asset server
129 Dictionary<LLUUID, AssetRequest> userRequests = null;
130 if (RequestedAssets.TryGetValue(userInfo.AgentId, out userRequests))
131 {
132 if (!userRequests.ContainsKey(requestID))
133 {
134
135 AssetRequest request = new AssetRequest();
136 request.RequestUser = userInfo;
137 request.RequestAssetID = requestID;
138 request.TransferRequestID = transferRequest.TransferInfo.TransferID;
139 request.AssetRequestSource = source;
140 request.Params = transferRequest.TransferInfo.Params;
141 userRequests[requestID] = request;
142 m_scene.AssetCache.GetAsset(requestID, AssetCallback, false);
143 }
144 }
145 else
146 {
147 userRequests = new Dictionary<LLUUID, AssetRequest>();
148 AssetRequest request = new AssetRequest();
149 request.RequestUser = userInfo;
150 request.RequestAssetID = requestID;
151 request.TransferRequestID = transferRequest.TransferInfo.TransferID;
152 request.AssetRequestSource = source;
153 request.Params = transferRequest.TransferInfo.Params;
154 userRequests.Add(requestID, request);
155 RequestedAssets[userInfo.AgentId] = userRequests;
156 m_scene.AssetCache.GetAsset(requestID, AssetCallback, false);
157
158 }
159 return;
160 }
161
162 public void AssetCallback(LLUUID assetID, AssetBase asset)
163 {
164 if (asset != null)
165 {
166 foreach (Dictionary<LLUUID, AssetRequest> userRequests in RequestedAssets.Values)
167 {
168 if (userRequests.ContainsKey(assetID))
169 {
170 AssetRequest req = userRequests[assetID];
171 if (req != null)
172 {
173 req.AssetInf = asset;
174 req.NumPackets = CalculateNumPackets(asset.Data);
175
176 userRequests.Remove(assetID);
177 AssetRequests.Add(req);
178 }
179 }
180 }
181 }
182 }
183
184 private void RunAssetQueue()
185 {
186 while (true)
187 {
188 try
189 {
190 ProcessAssetQueue();
191 Thread.Sleep(500);
192 }
193 catch (Exception e)
194 {
195 // m_log.Error("[ASSET CACHE]: " + e.ToString());
196 }
197 }
198 }
199
200 /// <summary>
201 /// Process the asset queue which sends packets directly back to the client.
202 /// </summary>
203 private void ProcessAssetQueue()
204 {
205 //should move the asset downloading to a module, like has been done with texture downloading
206 if (AssetRequests.Count == 0)
207 {
208 //no requests waiting
209 return;
210 }
211 // if less than 5, do all of them
212 int num = Math.Min(5, AssetRequests.Count);
213
214 AssetRequest req;
215 for (int i = 0; i < num; i++)
216 {
217 req = (AssetRequest)AssetRequests[i];
218 //Console.WriteLine("sending asset " + req.RequestAssetID);
219 TransferInfoPacket Transfer = new TransferInfoPacket();
220 Transfer.TransferInfo.ChannelType = 2;
221 Transfer.TransferInfo.Status = 0;
222 Transfer.TransferInfo.TargetType = 0;
223 if (req.AssetRequestSource == 2)
224 {
225 Transfer.TransferInfo.Params = new byte[20];
226 Array.Copy(req.RequestAssetID.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16);
227 int assType = (int)req.AssetInf.Type;
228 Array.Copy(Helpers.IntToBytes(assType), 0, Transfer.TransferInfo.Params, 16, 4);
229 }
230 else if (req.AssetRequestSource == 3)
231 {
232 Transfer.TransferInfo.Params = req.Params;
233 // Transfer.TransferInfo.Params = new byte[100];
234 //Array.Copy(req.RequestUser.AgentId.GetBytes(), 0, Transfer.TransferInfo.Params, 0, 16);
235 //Array.Copy(req.RequestUser.SessionId.GetBytes(), 0, Transfer.TransferInfo.Params, 16, 16);
236 }
237 Transfer.TransferInfo.Size = (int)req.AssetInf.Data.Length;
238 Transfer.TransferInfo.TransferID = req.TransferRequestID;
239 req.RequestUser.OutPacket(Transfer, ThrottleOutPacketType.Asset);
240
241 if (req.NumPackets == 1)
242 {
243 TransferPacketPacket TransferPacket = new TransferPacketPacket();
244 TransferPacket.TransferData.Packet = 0;
245 TransferPacket.TransferData.ChannelType = 2;
246 TransferPacket.TransferData.TransferID = req.TransferRequestID;
247 TransferPacket.TransferData.Data = req.AssetInf.Data;
248 TransferPacket.TransferData.Status = 1;
249 req.RequestUser.OutPacket(TransferPacket, ThrottleOutPacketType.Asset);
250 }
251 else
252 {
253 int processedLength = 0;
254 // libsecondlife hardcodes 1500 as the maximum data chunk size
255 int maxChunkSize = 1250;
256 int packetNumber = 0;
257
258 while (processedLength < req.AssetInf.Data.Length)
259 {
260 TransferPacketPacket TransferPacket = new TransferPacketPacket();
261 TransferPacket.TransferData.Packet = packetNumber;
262 TransferPacket.TransferData.ChannelType = 2;
263 TransferPacket.TransferData.TransferID = req.TransferRequestID;
264
265 int chunkSize = Math.Min(req.AssetInf.Data.Length - processedLength, maxChunkSize);
266 byte[] chunk = new byte[chunkSize];
267 Array.Copy(req.AssetInf.Data, processedLength, chunk, 0, chunk.Length);
268
269 TransferPacket.TransferData.Data = chunk;
270
271 // 0 indicates more packets to come, 1 indicates last packet
272 if (req.AssetInf.Data.Length - processedLength > maxChunkSize)
273 {
274 TransferPacket.TransferData.Status = 0;
275 }
276 else
277 {
278 TransferPacket.TransferData.Status = 1;
279 }
280
281 req.RequestUser.OutPacket(TransferPacket, ThrottleOutPacketType.Asset);
282
283 processedLength += chunkSize;
284 packetNumber++;
285 }
286 }
287 }
288
289 //remove requests that have been completed
290 for (int i = 0; i < num; i++)
291 {
292 AssetRequests.RemoveAt(0);
293 }
294 }
295 /// <summary>
296 /// Calculate the number of packets required to send the asset to the client.
297 /// </summary>
298 /// <param name="data"></param>
299 /// <returns></returns>
300 private int CalculateNumPackets(byte[] data)
301 {
302 const uint m_maxPacketSize = 600;
303 int numPackets = 1;
304
305 if (data.LongLength > m_maxPacketSize)
306 {
307 // over max number of bytes so split up file
308 long restData = data.LongLength - m_maxPacketSize;
309 int restPackets = (int)((restData + m_maxPacketSize - 1) / m_maxPacketSize);
310 numPackets += restPackets;
311 }
312
313 return numPackets;
314 }
315
316 public class AssetRequest
317 {
318 public IClientAPI RequestUser;
319 public LLUUID RequestAssetID;
320 public AssetBase AssetInf;
321 public AssetBase ImageInfo;
322 public LLUUID TransferRequestID;
323 public long DataPointer = 0;
324 public int NumPackets = 0;
325 public int PacketCounter = 0;
326 public bool IsTextureRequest;
327 public byte AssetRequestSource = 2;
328 public byte[] Params = null;
329 //public bool AssetInCache;
330 //public int TimeRequested;
331 public int DiscardLevel = -1;
332
333 public AssetRequest()
334 {
335 }
70 } 336 }
71 } 337 }
72} \ No newline at end of file 338} \ No newline at end of file