aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/OptionalModules/Avatar/Concierge
diff options
context:
space:
mode:
authorDr Scofield2009-02-10 13:10:57 +0000
committerDr Scofield2009-02-10 13:10:57 +0000
commit180be7de07014aa33bc6066f12a0819b731c1c9d (patch)
tree3aa13af3cda4b808fa9453655875327699b61311 /OpenSim/Region/OptionalModules/Avatar/Concierge
parentStopgap measure: To use gridlaunch, or GUI, start opensim with (diff)
downloadopensim-SC_OLD-180be7de07014aa33bc6066f12a0819b731c1c9d.zip
opensim-SC_OLD-180be7de07014aa33bc6066f12a0819b731c1c9d.tar.gz
opensim-SC_OLD-180be7de07014aa33bc6066f12a0819b731c1c9d.tar.bz2
opensim-SC_OLD-180be7de07014aa33bc6066f12a0819b731c1c9d.tar.xz
this is step 2 of 2 of the OpenSim.Region.Environment refactor.
NOTHING has been deleted or moved off to forge at this point. what has happened is that OpenSim.Region.Environment.Modules has been split in two: - OpenSim.Region.CoreModules: all those modules that are either directly or indirectly referenced from other OpenSim packages, or that provide functionality that the OpenSim developer community considers core functionality: CoreModules/Agent/AssetTransaction CoreModules/Agent/Capabilities CoreModules/Agent/TextureDownload CoreModules/Agent/TextureSender CoreModules/Agent/TextureSender/Tests CoreModules/Agent/Xfer CoreModules/Avatar/AvatarFactory CoreModules/Avatar/Chat/ChatModule CoreModules/Avatar/Combat CoreModules/Avatar/Currency/SampleMoney CoreModules/Avatar/Dialog CoreModules/Avatar/Friends CoreModules/Avatar/Gestures CoreModules/Avatar/Groups CoreModules/Avatar/InstantMessage CoreModules/Avatar/Inventory CoreModules/Avatar/Inventory/Archiver CoreModules/Avatar/Inventory/Transfer CoreModules/Avatar/Lure CoreModules/Avatar/ObjectCaps CoreModules/Avatar/Profiles CoreModules/Communications/Local CoreModules/Communications/REST CoreModules/Framework/EventQueue CoreModules/Framework/InterfaceCommander CoreModules/Hypergrid CoreModules/InterGrid CoreModules/Scripting/DynamicTexture CoreModules/Scripting/EMailModules CoreModules/Scripting/HttpRequest CoreModules/Scripting/LoadImageURL CoreModules/Scripting/VectorRender CoreModules/Scripting/WorldComm CoreModules/Scripting/XMLRPC CoreModules/World/Archiver CoreModules/World/Archiver/Tests CoreModules/World/Estate CoreModules/World/Land CoreModules/World/Permissions CoreModules/World/Serialiser CoreModules/World/Sound CoreModules/World/Sun CoreModules/World/Terrain CoreModules/World/Terrain/DefaultEffects CoreModules/World/Terrain/DefaultEffects/bin CoreModules/World/Terrain/DefaultEffects/bin/Debug CoreModules/World/Terrain/Effects CoreModules/World/Terrain/FileLoaders CoreModules/World/Terrain/FloodBrushes CoreModules/World/Terrain/PaintBrushes CoreModules/World/Terrain/Tests CoreModules/World/Vegetation CoreModules/World/Wind CoreModules/World/WorldMap - OpenSim.Region.OptionalModules: all those modules that are not core modules: OptionalModules/Avatar/Chat/IRC-stuff OptionalModules/Avatar/Concierge OptionalModules/Avatar/Voice/AsterixVoice OptionalModules/Avatar/Voice/SIPVoice OptionalModules/ContentManagementSystem OptionalModules/Grid/Interregion OptionalModules/Python OptionalModules/SvnSerialiser OptionalModules/World/NPC OptionalModules/World/TreePopulator
Diffstat (limited to 'OpenSim/Region/OptionalModules/Avatar/Concierge')
-rw-r--r--OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs604
-rwxr-xr-xOpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeServer.py130
2 files changed, 734 insertions, 0 deletions
diff --git a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs
new file mode 100644
index 0000000..bb46b11
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeModule.cs
@@ -0,0 +1,604 @@
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;
29using System.Collections;
30using System.Collections.Generic;
31using System.IO;
32using System.Net;
33using System.Net.Sockets;
34using System.Reflection;
35using System.Text;
36using System.Text.RegularExpressions;
37using System.Threading;
38using log4net;
39using Nini.Config;
40using Nwc.XmlRpc;
41using OpenMetaverse;
42using OpenSim.Framework;
43using OpenSim.Framework.Servers;
44using OpenSim.Region.Framework.Interfaces;
45using OpenSim.Region.Framework.Scenes;
46using OpenSim.Region.CoreModules.Avatar.Chat;
47
48namespace OpenSim.Region.OptionalModules.Avatar.Concierge
49{
50 public class ConciergeModule : ChatModule, IRegionModule
51 {
52 private static readonly ILog _log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType);
53
54 private const int DEBUG_CHANNEL = 2147483647;
55
56 private List<IScene> _scenes = new List<IScene>();
57 private List<IScene> _conciergedScenes = new List<IScene>();
58 private Dictionary<IScene, List<UUID>> _sceneAttendees =
59 new Dictionary<IScene, List<UUID>>();
60 private Dictionary<UUID, string> _attendeeNames =
61 new Dictionary<UUID, string>();
62
63 private bool _replacingChatModule = false;
64
65 private IConfig _config;
66
67 private string _whoami = "conferencier";
68 private Regex _regions = null;
69 private string _welcomes = null;
70 private int _conciergeChannel = 42;
71 private string _announceEntering = "{0} enters {1} (now {2} visitors in this region)";
72 private string _announceLeaving = "{0} leaves {1} (back to {2} visitors in this region)";
73 private string _xmlRpcPassword = String.Empty;
74 private string _brokerURI = String.Empty;
75
76 internal object _syncy = new object();
77
78 #region IRegionModule Members
79 public override void Initialise(Scene scene, IConfigSource config)
80 {
81 try
82 {
83 if ((_config = config.Configs["Concierge"]) == null)
84 {
85 //_log.InfoFormat("[Concierge]: no configuration section [Concierge] in OpenSim.ini: module not configured");
86 return;
87 }
88
89 if (!_config.GetBoolean("enabled", false))
90 {
91 //_log.InfoFormat("[Concierge]: module disabled by OpenSim.ini configuration");
92 return;
93 }
94 }
95 catch (Exception)
96 {
97 _log.Info("[Concierge]: module not configured");
98 return;
99 }
100
101 // check whether ChatModule has been disabled: if yes,
102 // then we'll "stand in"
103 try
104 {
105 if (config.Configs["Chat"] == null)
106 {
107 _replacingChatModule = false;
108 }
109 else
110 {
111 _replacingChatModule = !config.Configs["Chat"].GetBoolean("enabled", true);
112 }
113 }
114 catch (Exception)
115 {
116 _replacingChatModule = false;
117 }
118 _log.InfoFormat("[Concierge] {0} ChatModule", _replacingChatModule ? "replacing" : "not replacing");
119
120
121 // take note of concierge channel and of identity
122 _conciergeChannel = config.Configs["Concierge"].GetInt("concierge_channel", _conciergeChannel);
123 _whoami = _config.GetString("whoami", "conferencier");
124 _welcomes = _config.GetString("welcomes", _welcomes);
125 _announceEntering = _config.GetString("announce_entering", _announceEntering);
126 _announceLeaving = _config.GetString("announce_leaving", _announceLeaving);
127 _xmlRpcPassword = _config.GetString("password", _xmlRpcPassword);
128 _brokerURI = _config.GetString("broker", _brokerURI);
129
130 _log.InfoFormat("[Concierge] reporting as \"{0}\" to our users", _whoami);
131
132 // calculate regions Regex
133 if (_regions == null)
134 {
135 string regions = _config.GetString("regions", String.Empty);
136 if (!String.IsNullOrEmpty(regions))
137 {
138 _regions = new Regex(@regions, RegexOptions.Compiled | RegexOptions.IgnoreCase);
139 }
140 }
141
142 scene.CommsManager.HttpServer.AddXmlRPCHandler("concierge_update_welcome", XmlRpcUpdateWelcomeMethod, false);
143
144 lock (_syncy)
145 {
146 if (!_scenes.Contains(scene))
147 {
148 _scenes.Add(scene);
149
150 if (_regions == null || _regions.IsMatch(scene.RegionInfo.RegionName))
151 _conciergedScenes.Add(scene);
152
153 // subscribe to NewClient events
154 scene.EventManager.OnNewClient += OnNewClient;
155
156 // subscribe to *Chat events
157 scene.EventManager.OnChatFromWorld += OnChatFromWorld;
158 if (!_replacingChatModule)
159 scene.EventManager.OnChatFromClient += OnChatFromClient;
160 scene.EventManager.OnChatBroadcast += OnChatBroadcast;
161
162 // subscribe to agent change events
163 scene.EventManager.OnMakeRootAgent += OnMakeRootAgent;
164 scene.EventManager.OnMakeChildAgent += OnMakeChildAgent;
165 }
166 }
167 _log.InfoFormat("[Concierge]: initialized for {0}", scene.RegionInfo.RegionName);
168 }
169
170 public override void PostInitialise()
171 {
172 }
173
174 public override void Close()
175 {
176 }
177
178 public override string Name
179 {
180 get { return "ConciergeModule"; }
181 }
182
183 public override bool IsSharedModule
184 {
185 get { return true; }
186 }
187
188 #endregion
189
190 #region ISimChat Members
191 public override void OnChatBroadcast(Object sender, OSChatMessage c)
192 {
193 if (_replacingChatModule)
194 {
195 // distribute chat message to each and every avatar in
196 // the region
197 base.OnChatBroadcast(sender, c);
198 }
199
200 // TODO: capture logic
201 return;
202 }
203
204 public override void OnChatFromClient(Object sender, OSChatMessage c)
205 {
206 if (_replacingChatModule)
207 {
208 // replacing ChatModule: need to redistribute
209 // ChatFromClient to interested subscribers
210 c = FixPositionOfChatMessage(c);
211
212 Scene scene = (Scene)c.Scene;
213 scene.EventManager.TriggerOnChatFromClient(sender, c);
214
215 if (_conciergedScenes.Contains(c.Scene))
216 {
217 // when we are replacing ChatModule, we treat
218 // OnChatFromClient like OnChatBroadcast for
219 // concierged regions, effectively extending the
220 // range of chat to cover the whole
221 // region. however, we don't do this for whisper
222 // (got to have some privacy)
223 if (c.Type != ChatTypeEnum.Whisper)
224 {
225 base.OnChatBroadcast(sender, c);
226 return;
227 }
228 }
229
230 // redistribution will be done by base class
231 base.OnChatFromClient(sender, c);
232 }
233
234 // TODO: capture chat
235 return;
236 }
237
238 public override void OnChatFromWorld(Object sender, OSChatMessage c)
239 {
240 if (_replacingChatModule)
241 {
242 if (_conciergedScenes.Contains(c.Scene))
243 {
244 // when we are replacing ChatModule, we treat
245 // OnChatFromClient like OnChatBroadcast for
246 // concierged regions, effectively extending the
247 // range of chat to cover the whole
248 // region. however, we don't do this for whisper
249 // (got to have some privacy)
250 if (c.Type != ChatTypeEnum.Whisper)
251 {
252 base.OnChatBroadcast(sender, c);
253 return;
254 }
255 }
256
257 base.OnChatFromWorld(sender, c);
258 }
259 return;
260 }
261 #endregion
262
263
264 public override void OnNewClient(IClientAPI client)
265 {
266 client.OnLogout += OnClientLoggedOut;
267
268 if (_replacingChatModule)
269 client.OnChatFromClient += OnChatFromClient;
270 }
271
272
273
274 public void OnClientLoggedOut(IClientAPI client)
275 {
276 client.OnLogout -= OnClientLoggedOut;
277 client.OnConnectionClosed -= OnClientLoggedOut;
278
279 if (_conciergedScenes.Contains(client.Scene))
280 {
281 _log.DebugFormat("[Concierge]: {0} logs off from {1}", client.Name, client.Scene.RegionInfo.RegionName);
282 RemoveFromAttendeeList(client.AgentId, client.Name, client.Scene);
283 AnnounceToAgentsRegion(client.Scene, String.Format(_announceLeaving, client.Name, client.Scene.RegionInfo.RegionName,
284 _sceneAttendees[client.Scene].Count));
285 UpdateBroker(client.Scene);
286 }
287 }
288
289
290 public void OnMakeRootAgent(ScenePresence agent)
291 {
292 if (_conciergedScenes.Contains(agent.Scene))
293 {
294 _log.DebugFormat("[Concierge]: {0} enters {1}", agent.Name, agent.Scene.RegionInfo.RegionName);
295 AddToAttendeeList(agent.UUID, agent.Name, agent.Scene);
296 WelcomeAvatar(agent, agent.Scene);
297 AnnounceToAgentsRegion(agent.Scene, String.Format(_announceEntering, agent.Name, agent.Scene.RegionInfo.RegionName,
298 _sceneAttendees[agent.Scene].Count));
299 UpdateBroker(agent.Scene);
300 }
301 }
302
303
304 public void OnMakeChildAgent(ScenePresence agent)
305 {
306 if (_conciergedScenes.Contains(agent.Scene))
307 {
308 _log.DebugFormat("[Concierge]: {0} leaves {1}", agent.Name, agent.Scene.RegionInfo.RegionName);
309 RemoveFromAttendeeList(agent.UUID, agent.Name, agent.Scene);
310 AnnounceToAgentsRegion(agent.Scene, String.Format(_announceLeaving, agent.Name, agent.Scene.RegionInfo.RegionName,
311 _sceneAttendees[agent.Scene].Count));
312 UpdateBroker(agent.Scene);
313 }
314 }
315
316 protected void AddToAttendeeList(UUID agentID, string name, Scene scene)
317 {
318 lock (_sceneAttendees)
319 {
320 if (!_sceneAttendees.ContainsKey(scene))
321 _sceneAttendees[scene] = new List<UUID>();
322
323 List<UUID> attendees = _sceneAttendees[scene];
324 if (!attendees.Contains(agentID))
325 {
326 attendees.Add(agentID);
327 _attendeeNames[agentID] = name;
328 }
329 }
330 }
331
332 protected void RemoveFromAttendeeList(UUID agentID, String name, IScene scene)
333 {
334 lock (_sceneAttendees)
335 {
336 if (!_sceneAttendees.ContainsKey(scene))
337 {
338 _log.WarnFormat("[Concierge]: attendee list missing for region {0}", scene.RegionInfo.RegionName);
339 return;
340 }
341
342 List<UUID> attendees = _sceneAttendees[scene];
343 if (!attendees.Contains(agentID))
344 {
345 _log.WarnFormat("[Concierge]: avatar {0} must have sneaked in to region {1} earlier",
346 name, scene.RegionInfo.RegionName);
347 return;
348 }
349
350 attendees.Remove(agentID);
351 _attendeeNames.Remove(agentID);
352 }
353 }
354
355 protected void UpdateBroker(IScene scene)
356 {
357 if (String.IsNullOrEmpty(_brokerURI))
358 return;
359
360 string uri = String.Format(_brokerURI, scene.RegionInfo.RegionName, scene.RegionInfo.RegionID);
361
362 // get attendee list for the scene
363 List<UUID> attendees;
364 lock (_sceneAttendees)
365 {
366 if (!_sceneAttendees.ContainsKey(scene))
367 {
368 _log.DebugFormat("[Concierge]: attendee list missing for region {0}", scene.RegionInfo.RegionName);
369 return;
370 }
371
372 attendees = _sceneAttendees[scene];
373 }
374
375 // create XML sniplet
376 StringBuilder list = new StringBuilder();
377 if (0 == attendees.Count)
378 {
379 list.Append(String.Format("<avatars count=\"0\" region_name=\"{0}\" region_uuid=\"{1}\" timestamp=\"{2}\" />",
380 scene.RegionInfo.RegionName, scene.RegionInfo.RegionID,
381 DateTime.UtcNow.ToString("s")));
382 }
383 else
384 {
385 list.Append(String.Format("<avatars count=\"{0}\" region_name=\"{1}\" region_uuid=\"{2}\" timestamp=\"{3}\">\n",
386 attendees.Count, scene.RegionInfo.RegionName,
387 scene.RegionInfo.RegionID,
388 DateTime.UtcNow.ToString("s")));
389 foreach (UUID uuid in attendees)
390 {
391 string name = _attendeeNames[uuid];
392 list.Append(String.Format(" <avatar name=\"{0}\" uuid=\"{1}\" />\n", name, uuid));
393 }
394 list.Append("</avatars>");
395 }
396 string payload = list.ToString();
397
398 // post via REST to broker
399 HttpWebRequest updatePost = WebRequest.Create(uri) as HttpWebRequest;
400 updatePost.Method = "POST";
401 updatePost.ContentType = "text/xml";
402 updatePost.ContentLength = payload.Length;
403 updatePost.UserAgent = "OpenSim.Concierge";
404
405 try
406 {
407 StreamWriter payloadStream = new StreamWriter(updatePost.GetRequestStream());
408 payloadStream.Write(payload);
409 payloadStream.Close();
410
411 updatePost.BeginGetResponse(UpdateBrokerDone, updatePost);
412 _log.DebugFormat("[Concierge] async broker POST to {0} started", uri);
413 }
414 catch (WebException we)
415 {
416 _log.ErrorFormat("[Concierge] async broker POST to {0} failed: {1}", uri, we.Status);
417 }
418 }
419
420 private void UpdateBrokerDone(IAsyncResult result)
421 {
422 HttpWebRequest updatePost = null;
423 try
424 {
425 updatePost = result.AsyncState as HttpWebRequest;
426 using (HttpWebResponse response = updatePost.EndGetResponse(result) as HttpWebResponse)
427 {
428 _log.DebugFormat("[Concierge] broker update: status {0}", response.StatusCode);
429 }
430 }
431 catch (WebException we)
432 {
433 string uri = updatePost.RequestUri.OriginalString;
434 _log.ErrorFormat("[Concierge] broker update to {0} failed with status {1}", uri, we.Status);
435 if (null != we.Response)
436 {
437 using (HttpWebResponse resp = we.Response as HttpWebResponse)
438 {
439 _log.ErrorFormat("[Concierge] response from {0} status code: {1}", uri, resp.StatusCode);
440 _log.ErrorFormat("[Concierge] response from {0} status desc: {1}", uri, resp.StatusDescription);
441 _log.ErrorFormat("[Concierge] response from {0} server: {1}", uri, resp.Server);
442
443 if (resp.ContentLength > 0)
444 {
445 StreamReader content = new StreamReader(resp.GetResponseStream());
446 _log.ErrorFormat("[Concierge] response from {0} content: {1}", uri, content.ReadToEnd());
447 content.Close();
448 }
449 }
450 }
451 }
452 }
453
454 protected void WelcomeAvatar(ScenePresence agent, Scene scene)
455 {
456 // welcome mechanics: check whether we have a welcomes
457 // directory set and wether there is a region specific
458 // welcome file there: if yes, send it to the agent
459 if (!String.IsNullOrEmpty(_welcomes))
460 {
461 string[] welcomes = new string[] {
462 Path.Combine(_welcomes, agent.Scene.RegionInfo.RegionName),
463 Path.Combine(_welcomes, "DEFAULT")};
464 foreach (string welcome in welcomes)
465 {
466 if (File.Exists(welcome))
467 {
468 try
469 {
470 string[] welcomeLines = File.ReadAllLines(welcome);
471 foreach (string l in welcomeLines)
472 {
473 AnnounceToAgent(agent, String.Format(l, agent.Name, scene.RegionInfo.RegionName, _whoami));
474 }
475 }
476 catch (IOException ioe)
477 {
478 _log.ErrorFormat("[Concierge]: run into trouble reading welcome file {0} for region {1} for avatar {2}: {3}",
479 welcome, scene.RegionInfo.RegionName, agent.Name, ioe);
480 }
481 catch (FormatException fe)
482 {
483 _log.ErrorFormat("[Concierge]: welcome file {0} is malformed: {1}", welcome, fe);
484 }
485 }
486 return;
487 }
488 _log.DebugFormat("[Concierge]: no welcome message for region {0}", scene.RegionInfo.RegionName);
489 }
490 }
491
492 static private Vector3 PosOfGod = new Vector3(128, 128, 9999);
493
494 // protected void AnnounceToAgentsRegion(Scene scene, string msg)
495 // {
496 // ScenePresence agent = null;
497 // if ((client.Scene is Scene) && (client.Scene as Scene).TryGetAvatar(client.AgentId, out agent))
498 // AnnounceToAgentsRegion(agent, msg);
499 // else
500 // _log.DebugFormat("[Concierge]: could not find an agent for client {0}", client.Name);
501 // }
502
503 protected void AnnounceToAgentsRegion(IScene scene, string msg)
504 {
505 OSChatMessage c = new OSChatMessage();
506 c.Message = msg;
507 c.Type = ChatTypeEnum.Say;
508 c.Channel = 0;
509 c.Position = PosOfGod;
510 c.From = _whoami;
511 c.Sender = null;
512 c.SenderUUID = UUID.Zero;
513 c.Scene = scene;
514
515 if (scene is Scene)
516 (scene as Scene).EventManager.TriggerOnChatBroadcast(this, c);
517 }
518
519 protected void AnnounceToAgent(ScenePresence agent, string msg)
520 {
521 OSChatMessage c = new OSChatMessage();
522 c.Message = msg;
523 c.Type = ChatTypeEnum.Say;
524 c.Channel = 0;
525 c.Position = PosOfGod;
526 c.From = _whoami;
527 c.Sender = null;
528 c.SenderUUID = UUID.Zero;
529 c.Scene = agent.Scene;
530
531 agent.ControllingClient.SendChatMessage(msg, (byte) ChatTypeEnum.Say, PosOfGod, _whoami, UUID.Zero,
532 (byte)ChatSourceType.Object, (byte)ChatAudibleLevel.Fully);
533 }
534
535 private static void checkStringParameters(XmlRpcRequest request, string[] param)
536 {
537 Hashtable requestData = (Hashtable) request.Params[0];
538 foreach (string p in param)
539 {
540 if (!requestData.Contains(p))
541 throw new Exception(String.Format("missing string parameter {0}", p));
542 if (String.IsNullOrEmpty((string)requestData[p]))
543 throw new Exception(String.Format("parameter {0} is empty", p));
544 }
545 }
546
547 public XmlRpcResponse XmlRpcUpdateWelcomeMethod(XmlRpcRequest request)
548 {
549 _log.Info("[Concierge]: processing UpdateWelcome request");
550 XmlRpcResponse response = new XmlRpcResponse();
551 Hashtable responseData = new Hashtable();
552
553 try
554 {
555 Hashtable requestData = (Hashtable)request.Params[0];
556 checkStringParameters(request, new string[] { "password", "region", "welcome" });
557
558 // check password
559 if (!String.IsNullOrEmpty(_xmlRpcPassword) &&
560 (string)requestData["password"] != _xmlRpcPassword) throw new Exception("wrong password");
561
562 if (String.IsNullOrEmpty(_welcomes))
563 throw new Exception("welcome templates are not enabled, ask your OpenSim operator to set the \"welcomes\" option in the [Concierge] section of OpenSim.ini");
564
565 string msg = (string)requestData["welcome"];
566 if (String.IsNullOrEmpty(msg))
567 throw new Exception("empty parameter \"welcome\"");
568
569 string regionName = (string)requestData["region"];
570 IScene scene = _scenes.Find(delegate(IScene s) { return s.RegionInfo.RegionName == regionName; });
571 if (scene == null)
572 throw new Exception(String.Format("unknown region \"{0}\"", regionName));
573
574 if (!_conciergedScenes.Contains(scene))
575 throw new Exception(String.Format("region \"{0}\" is not a concierged region.", regionName));
576
577 string welcome = Path.Combine(_welcomes, regionName);
578 if (File.Exists(welcome))
579 {
580 _log.InfoFormat("[Concierge]: UpdateWelcome: updating existing template \"{0}\"", welcome);
581 string welcomeBackup = String.Format("{0}~", welcome);
582 if (File.Exists(welcomeBackup))
583 File.Delete(welcomeBackup);
584 File.Move(welcome, welcomeBackup);
585 }
586 File.WriteAllText(welcome, msg);
587
588 responseData["success"] = "true";
589 response.Value = responseData;
590 }
591 catch (Exception e)
592 {
593 _log.InfoFormat("[Concierge]: UpdateWelcome failed: {0}", e.Message);
594
595 responseData["success"] = "false";
596 responseData["error"] = e.Message;
597
598 response.Value = responseData;
599 }
600 _log.Debug("[Concierge]: done processing UpdateWelcome request");
601 return response;
602 }
603 }
604}
diff --git a/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeServer.py b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeServer.py
new file mode 100755
index 0000000..1c088fb
--- /dev/null
+++ b/OpenSim/Region/OptionalModules/Avatar/Concierge/ConciergeServer.py
@@ -0,0 +1,130 @@
1#!/usr/bin/env python
2# -*- encoding: utf-8 -*-
3#
4# Copyright (c) Contributors, http://opensimulator.org/
5# See CONTRIBUTORS.TXT for a full list of copyright holders.
6#
7# Redistribution and use in source and binary forms, with or without
8# modification, are permitted provided that the following conditions are met:
9# * Redistributions of source code must retain the above copyright
10# notice, this list of conditions and the following disclaimer.
11# * Redistributions in binary form must reproduce the above copyright
12# notice, this list of conditions and the following disclaimer in the
13# documentation and/or other materials provided with the distribution.
14# * Neither the name of the OpenSim Project nor the
15# names of its contributors may be used to endorse or promote products
16# derived from this software without specific prior written permission.
17#
18# THIS SOFTWARE IS PROVIDED BY THE DEVELOPERS ``AS IS'' AND ANY
19# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21# DISCLAIMED. IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY
22# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
27# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28#
29
30import logging
31import BaseHTTPServer
32import optparse
33import xml.etree.ElementTree as ET
34import xml.parsers.expat
35
36
37# enable debug level logging
38logging.basicConfig(level = logging.DEBUG,
39 format='%(asctime)s %(levelname)s %(message)s')
40
41options = None
42
43# subclassed HTTPRequestHandler
44class ConciergeHandler(BaseHTTPServer.BaseHTTPRequestHandler):
45 def logRequest(self):
46 logging.info('[ConciergeHandler] %(command)s request: %(host)s:%(port)d --- %(path)s',
47 dict(command = self.command,
48 host = self.client_address[0],
49 port = self.client_address[1],
50 path = self.path))
51
52 def logResponse(self, status):
53 logging.info('[ConciergeHandler] %(command)s returned %(status)d',
54 dict(command = self.command,
55 status = status))
56
57
58 def do_HEAD(self):
59 self.logRequest()
60
61 self.send_response(200)
62 self.send_header('Content-type', 'text/html')
63 self.end_headers()
64
65 self.logResponse(200)
66
67 def dumpXml(self, xml):
68 logging.debug('[ConciergeHandler] %s', xml.tag)
69 for attr in xml.attrib:
70 logging.debug('[ConciergeHandler] %s [%s] %s', xml.tag, attr, xml.attrib[attr])
71 for kid in xml.getchildren():
72 self.dumpXml(kid)
73
74 def do_POST(self):
75 self.logRequest()
76 hdrs = {}
77 for hdr in self.headers.headers:
78 logging.debug('[ConciergeHandler] POST: header: %s', hdr.rstrip())
79
80 length = int(self.headers.getheader('Content-Length'))
81 content = self.rfile.read(length)
82 self.rfile.close()
83
84 logging.debug('[ConciergeHandler] POST: content: %s', content)
85 try:
86 postXml = ET.fromstring(content)
87 self.dumpXml(postXml)
88 except xml.parsers.expat.ExpatError, xmlError:
89 logging.error('[ConciergeHandler] POST illformed:%s', xmlError)
90 self.send_response(500)
91 return
92
93 if not options.fail:
94 self.send_response(200)
95 self.send_header('Content-Type', 'text/html')
96 self.send_header('Content-Length', len('<success/>'))
97 self.end_headers()
98 self.logResponse(200)
99 self.wfile.write('<success/>')
100 self.wfile.close()
101 else:
102 self.send_response(500)
103 self.send_header('Content-Type', 'text/html')
104 self.send_header('Content-Length', len('<error>gotcha!</error>'))
105 self.end_headers()
106 self.wfile.write('<error>gotcha!</error>')
107 self.wfile.close()
108
109 self.logResponse(500)
110
111 def log_request(code, size):
112 pass
113
114if __name__ == '__main__':
115
116 logging.info('[ConciergeServer] Concierge Broker Test Server starting')
117
118 parser = optparse.OptionParser()
119 parser.add_option('-p', '--port', dest = 'port', help = 'port to listen on', metavar = 'PORT')
120 parser.add_option('-f', '--fail', dest = 'fail', action = 'store_true', help = 'always fail POST requests')
121
122 (options, args) = parser.parse_args()
123
124 httpServer = BaseHTTPServer.HTTPServer(('', 8080), ConciergeHandler)
125 try:
126 httpServer.serve_forever()
127 except KeyboardInterrupt:
128 logging.info('[ConciergeServer] terminating')
129
130 httpServer.server_close()