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.cs262
1 files changed, 262 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..93fdae3
--- /dev/null
+++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridMaptileModule.cs
@@ -0,0 +1,262 @@
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 int refreshseconds = Convert.ToInt32(config.GetString("RefreshTime"));
91 if (refreshseconds <= 0)
92 return;
93
94 m_refreshtime = refreshseconds * 1000; // convert from seconds to ms
95 m_log.InfoFormat("[SIMIAN MAPTILE] enabled with refresh timeout {0} and URL {1}",
96 m_refreshtime,m_serverUrl);
97
98 m_enabled = true;
99 }
100
101 ///<summary>
102 ///
103 ///</summary>
104 public void PostInitialise()
105 {
106 if (m_enabled)
107 {
108 m_refreshTimer.Enabled = true;
109 m_refreshTimer.AutoReset = true;
110 m_refreshTimer.Interval = 5 * 60 * 1000; // every 5 minutes
111 m_refreshTimer.Elapsed += new ElapsedEventHandler(HandleMaptileRefresh);
112 }
113 }
114
115
116 ///<summary>
117 ///
118 ///</summary>
119 public void AddRegion(Scene scene)
120 {
121 if (! m_enabled)
122 return;
123
124 // Every shared region module has to maintain an indepedent list of
125 // currently running regions
126 lock (m_scenes)
127 m_scenes[scene.RegionInfo.RegionID] = scene;
128 }
129
130 ///<summary>
131 ///
132 ///</summary>
133 public void RemoveRegion(Scene scene)
134 {
135 if (! m_enabled)
136 return;
137
138 lock (m_scenes)
139 m_scenes.Remove(scene.RegionInfo.RegionID);
140 }
141
142 #endregion ISharedRegionModule
143
144 ///<summary>
145 ///
146 ///</summary>
147 private void HandleMaptileRefresh(object sender, EventArgs ea)
148 {
149 // this approach is a bit convoluted becase we want to wait for the
150 // first upload to happen on startup but after all the objects are
151 // loaded and initialized
152 if (m_lastrefresh > 0 && Util.EnvironmentTickCountSubtract(m_lastrefresh) < m_refreshtime)
153 return;
154
155 m_log.DebugFormat("[SIMIAN MAPTILE] map refresh fired");
156 lock (m_scenes)
157 {
158 foreach (IScene scene in m_scenes.Values)
159 {
160 try
161 {
162 UploadMapTile(scene);
163 }
164 catch (Exception ex)
165 {
166 m_log.WarnFormat("[SIMIAN MAPTILE] something bad happened {0}",ex.Message);
167 }
168 }
169 }
170
171 m_lastrefresh = Util.EnvironmentTickCount();
172 }
173
174 ///<summary>
175 ///
176 ///</summary>
177 private void UploadMapTile(IScene scene)
178 {
179 m_log.DebugFormat("[SIMIAN MAPTILE]: upload maptile for {0}",scene.RegionInfo.RegionName);
180
181 // Create a PNG map tile and upload it to the AddMapTile API
182 byte[] pngData = Utils.EmptyBytes;
183 IMapImageGenerator tileGenerator = scene.RequestModuleInterface<IMapImageGenerator>();
184 if (tileGenerator == null)
185 {
186 m_log.Warn("[SIMIAN MAPTILE]: Cannot upload PNG map tile without an ImageGenerator");
187 return;
188 }
189
190 using (Image mapTile = tileGenerator.CreateMapTile())
191 {
192 using (MemoryStream stream = new MemoryStream())
193 {
194 mapTile.Save(stream, ImageFormat.Png);
195 pngData = stream.ToArray();
196 }
197 }
198
199 List<MultipartForm.Element> postParameters = new List<MultipartForm.Element>()
200 {
201 new MultipartForm.Parameter("X", scene.RegionInfo.RegionLocX.ToString()),
202 new MultipartForm.Parameter("Y", scene.RegionInfo.RegionLocY.ToString()),
203 new MultipartForm.File("Tile", "tile.png", "image/png", pngData)
204 };
205
206 string errorMessage = null;
207 int tickstart = Util.EnvironmentTickCount();
208
209 // Make the remote storage request
210 try
211 {
212 HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl);
213 request.Timeout = 20000;
214 request.ReadWriteTimeout = 5000;
215
216 using (HttpWebResponse response = MultipartForm.Post(request, postParameters))
217 {
218 using (Stream responseStream = response.GetResponseStream())
219 {
220 string responseStr = responseStream.GetStreamString();
221 OSD responseOSD = OSDParser.Deserialize(responseStr);
222 if (responseOSD.Type == OSDType.Map)
223 {
224 OSDMap responseMap = (OSDMap)responseOSD;
225 if (responseMap["Success"].AsBoolean())
226 return;
227
228 errorMessage = "Upload failed: " + responseMap["Message"].AsString();
229 }
230 else
231 {
232 errorMessage = "Response format was invalid:\n" + responseStr;
233 }
234 }
235 }
236 }
237 catch (WebException we)
238 {
239 errorMessage = we.Message;
240 if (we.Status == WebExceptionStatus.ProtocolError)
241 {
242 HttpWebResponse webResponse = (HttpWebResponse)we.Response;
243 errorMessage = String.Format("[{0}] {1}",
244 webResponse.StatusCode,webResponse.StatusDescription);
245 }
246 }
247 catch (Exception ex)
248 {
249 errorMessage = ex.Message;
250 }
251 finally
252 {
253 // This just dumps a warning for any operation that takes more than 100 ms
254 int tickdiff = Util.EnvironmentTickCountSubtract(tickstart);
255 m_log.DebugFormat("[SIMIAN MAPTILE]: map tile uploaded in {0}ms",tickdiff);
256 }
257
258 m_log.WarnFormat("[SIMIAN MAPTILE]: Failed to store {0} byte tile for {1}: {2}",
259 pngData.Length, scene.RegionInfo.RegionName, errorMessage);
260 }
261 }
262} \ No newline at end of file