aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs')
-rw-r--r--OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs261
1 files changed, 261 insertions, 0 deletions
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs
new file mode 100644
index 0000000..dd8fe2b
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs
@@ -0,0 +1,261 @@
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 OpenSimulator 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;
29using System.Collections.Generic;
30using System.Reflection;
31using System.Net;
32using System.IO;
33using System.Timers;
34using System.Drawing;
35using System.Drawing.Imaging;
36
37using log4net;
38using Mono.Addins;
39using Nini.Config;
40using OpenSim.Framework;
41using OpenSim.Region.Framework.Interfaces;
42using OpenSim.Region.Framework.Scenes;
43using OpenMetaverse;
44using OpenMetaverse.StructuredData;
45
46namespace OpenSim.Region.OptionalModules.Simian
47{
48 /// <summary>
49 /// </summary>
50 /// <remarks>
51 /// </remarks>
52
53 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SimianGridMaptile")]
54 public class SimianGridMaptile : ISharedRegionModule
55 {
56 private static readonly ILog m_log =
57 LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
58
59 private bool m_enabled = false;
60 private string m_serverUrl = String.Empty;
61 private Dictionary<UUID, Scene> m_scenes = new Dictionary<UUID, Scene>();
62
63 private int m_refreshtime = 0;
64 private int m_lastrefresh = 0;
65 private System.Timers.Timer m_refreshTimer = new System.Timers.Timer();
66
67 #region ISharedRegionModule
68
69 public Type ReplaceableInterface { get { return null; } }
70 public string Name { get { return "SimianGridMaptile"; } }
71 public void RegionLoaded(Scene scene) { }
72 public void Close() { }
73
74 ///<summary>
75 ///
76 ///</summary>
77 public void Initialise(IConfigSource source)
78 {
79 IConfig config = source.Configs["SimianGridMaptiles"];
80 if (config == null)
81 return;
82
83 if (! config.GetBoolean("Enabled", false))
84 return;
85
86 m_serverUrl = config.GetString("MaptileURL");
87 if (String.IsNullOrEmpty(m_serverUrl))
88 return;
89
90 m_refreshtime = Convert.ToInt32(config.GetString("RefreshTime"));
91 if (m_refreshtime <= 0)
92 return;
93
94 m_log.InfoFormat("[SIMIAN MAPTILE] enabled with refresh timeout {0} and URL {1}",
95 m_refreshtime,m_serverUrl);
96
97 m_enabled = true;
98 }
99
100 ///<summary>
101 ///
102 ///</summary>
103 public void PostInitialise()
104 {
105 if (m_enabled)
106 {
107 m_refreshTimer.Enabled = true;
108 m_refreshTimer.AutoReset = true;
109 m_refreshTimer.Interval = 5 * 60 * 1000; // every 5 minutes
110 m_refreshTimer.Elapsed += new ElapsedEventHandler(HandleMaptileRefresh);
111 }
112 }
113
114
115 ///<summary>
116 ///
117 ///</summary>
118 public void AddRegion(Scene scene)
119 {
120 if (! m_enabled)
121 return;
122
123 // Every shared region module has to maintain an indepedent list of
124 // currently running regions
125 lock (m_scenes)
126 m_scenes[scene.RegionInfo.RegionID] = scene;
127 }
128
129 ///<summary>
130 ///
131 ///</summary>
132 public void RemoveRegion(Scene scene)
133 {
134 if (! m_enabled)
135 return;
136
137 lock (m_scenes)
138 m_scenes.Remove(scene.RegionInfo.RegionID);
139 }
140
141 #endregion ISharedRegionModule
142
143 ///<summary>
144 ///
145 ///</summary>
146 private void HandleMaptileRefresh(object sender, EventArgs ea)
147 {
148 // this approach is a bit convoluted becase we want to wait for the
149 // first upload to happen on startup but after all the objects are
150 // loaded and initialized
151 if (m_lastrefresh > 0 && Util.EnvironmentTickCountSubtract(m_lastrefresh) < m_refreshtime)
152 return;
153
154 m_log.DebugFormat("[SIMIAN MAPTILE] map refresh fired");
155 lock (m_scenes)
156 {
157 foreach (IScene scene in m_scenes.Values)
158 {
159 try
160 {
161 UploadMapTile(scene);
162 }
163 catch (Exception ex)
164 {
165 m_log.WarnFormat("[SIMIAN MAPTILE] something bad happened {0}",ex.Message);
166 }
167 }
168 }
169
170 m_lastrefresh = Util.EnvironmentTickCount();
171 }
172
173 ///<summary>
174 ///
175 ///</summary>
176 private void UploadMapTile(IScene scene)
177 {
178 m_log.DebugFormat("[SIMIAN MAPTILE]: upload maptile for {0}",scene.RegionInfo.RegionName);
179
180 // Create a PNG map tile and upload it to the AddMapTile API
181 byte[] pngData = Utils.EmptyBytes;
182 IMapImageGenerator tileGenerator = scene.RequestModuleInterface<IMapImageGenerator>();
183 if (tileGenerator == null)
184 {
185 m_log.Warn("[SIMIAN MAPTILE]: Cannot upload PNG map tile without an ImageGenerator");
186 return;
187 }
188
189 using (Image mapTile = tileGenerator.CreateMapTile())
190 {
191 using (MemoryStream stream = new MemoryStream())
192 {
193 mapTile.Save(stream, ImageFormat.Png);
194 pngData = stream.ToArray();
195 }
196 }
197
198 List<MultipartForm.Element> postParameters = new List<MultipartForm.Element>()
199 {
200 new MultipartForm.Parameter("X", scene.RegionInfo.RegionLocX.ToString()),
201 new MultipartForm.Parameter("Y", scene.RegionInfo.RegionLocY.ToString()),
202 new MultipartForm.File("Tile", "tile.png", "image/png", pngData)
203 };
204
205 string errorMessage = null;
206 int tickstart = Util.EnvironmentTickCount();
207
208 // Make the remote storage request
209 try
210 {
211 HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl);
212 request.Timeout = 20000;
213 request.ReadWriteTimeout = 5000;
214
215 using (HttpWebResponse response = MultipartForm.Post(request, postParameters))
216 {
217 using (Stream responseStream = response.GetResponseStream())
218 {
219 string responseStr = responseStream.GetStreamString();
220 OSD responseOSD = OSDParser.Deserialize(responseStr);
221 if (responseOSD.Type == OSDType.Map)
222 {
223 OSDMap responseMap = (OSDMap)responseOSD;
224 if (responseMap["Success"].AsBoolean())
225 return;
226
227 errorMessage = "Upload failed: " + responseMap["Message"].AsString();
228 }
229 else
230 {
231 errorMessage = "Response format was invalid:\n" + responseStr;
232 }
233 }
234 }
235 }
236 catch (WebException we)
237 {
238 errorMessage = we.Message;
239 if (we.Status == WebExceptionStatus.ProtocolError)
240 {
241 HttpWebResponse webResponse = (HttpWebResponse)we.Response;
242 errorMessage = String.Format("[{0}] {1}",
243 webResponse.StatusCode,webResponse.StatusDescription);
244 }
245 }
246 catch (Exception ex)
247 {
248 errorMessage = ex.Message;
249 }
250 finally
251 {
252 // This just dumps a warning for any operation that takes more than 100 ms
253 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
254 m_log.DebugFormat("[SIMIAN MAPTILE]: map tile uploaded in {0}ms",tickdiff);
255 }
256
257 m_log.WarnFormat("[SIMIAN MAPTILE]: Failed to store {0} byte tile for {1}: {2}",
258 pngData.Length, scene.RegionInfo.RegionName, errorMessage);
259 }
260 }
261} \ No newline at end of file