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