diff options
Diffstat (limited to 'OpenSim/Services')
5 files changed, 361 insertions, 88 deletions
diff --git a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs index 7ac7917..99119d3 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServicesConnector.cs | |||
@@ -46,10 +46,13 @@ namespace OpenSim.Services.Connectors | |||
46 | LogManager.GetLogger( | 46 | LogManager.GetLogger( |
47 | MethodBase.GetCurrentMethod().DeclaringType); | 47 | MethodBase.GetCurrentMethod().DeclaringType); |
48 | 48 | ||
49 | const int MAXSENDRETRIESLEN = 30; | ||
50 | |||
49 | private string m_ServerURI = String.Empty; | 51 | private string m_ServerURI = String.Empty; |
50 | private IImprovedAssetCache m_Cache = null; | 52 | private IImprovedAssetCache m_Cache = null; |
51 | private int m_retryCounter; | 53 | private int m_retryCounter; |
52 | private Dictionary<int, List<AssetBase>> m_retryQueue = new Dictionary<int, List<AssetBase>>(); | 54 | private bool m_inRetries; |
55 | private List<AssetBase>[] m_sendRetries = new List<AssetBase>[MAXSENDRETRIESLEN]; | ||
53 | private System.Timers.Timer m_retryTimer; | 56 | private System.Timers.Timer m_retryTimer; |
54 | private int m_maxAssetRequestConcurrency = 30; | 57 | private int m_maxAssetRequestConcurrency = 30; |
55 | 58 | ||
@@ -110,9 +113,9 @@ namespace OpenSim.Services.Connectors | |||
110 | throw new Exception("Asset connector init error"); | 113 | throw new Exception("Asset connector init error"); |
111 | } | 114 | } |
112 | 115 | ||
113 | |||
114 | m_retryTimer = new System.Timers.Timer(); | 116 | m_retryTimer = new System.Timers.Timer(); |
115 | m_retryTimer.Elapsed += new ElapsedEventHandler(retryCheck); | 117 | m_retryTimer.Elapsed += new ElapsedEventHandler(retryCheck); |
118 | m_retryTimer.AutoReset = true; | ||
116 | m_retryTimer.Interval = 60000; | 119 | m_retryTimer.Interval = 60000; |
117 | 120 | ||
118 | Uri serverUri = new Uri(m_ServerURI); | 121 | Uri serverUri = new Uri(m_ServerURI); |
@@ -166,48 +169,67 @@ namespace OpenSim.Services.Connectors | |||
166 | 169 | ||
167 | protected void retryCheck(object source, ElapsedEventArgs e) | 170 | protected void retryCheck(object source, ElapsedEventArgs e) |
168 | { | 171 | { |
169 | m_retryCounter++; | 172 | lock(m_sendRetries) |
170 | if (m_retryCounter > 60) | ||
171 | m_retryCounter -= 60; | ||
172 | |||
173 | List<int> keys = new List<int>(); | ||
174 | foreach (int a in m_retryQueue.Keys) | ||
175 | { | 173 | { |
176 | keys.Add(a); | 174 | if(m_inRetries) |
175 | return; | ||
176 | m_inRetries = true; | ||
177 | } | 177 | } |
178 | foreach (int a in keys) | 178 | |
179 | m_retryCounter++; | ||
180 | if(m_retryCounter >= 61 ) // avoid overflow 60 is max in use below | ||
181 | m_retryCounter = 1; | ||
182 | |||
183 | int inUse = 0; | ||
184 | int nextlevel; | ||
185 | int timefactor; | ||
186 | List<AssetBase> retrylist; | ||
187 | // we need to go down | ||
188 | for(int i = MAXSENDRETRIESLEN - 1; i >= 0; i--) | ||
179 | { | 189 | { |
190 | lock(m_sendRetries) | ||
191 | retrylist = m_sendRetries[i]; | ||
192 | |||
193 | if(retrylist == null) | ||
194 | continue; | ||
195 | |||
196 | inUse++; | ||
197 | nextlevel = i + 1; | ||
198 | |||
180 | //We exponentially fall back on frequency until we reach one attempt per hour | 199 | //We exponentially fall back on frequency until we reach one attempt per hour |
181 | //The net result is that we end up in the queue for roughly 24 hours.. | 200 | //The net result is that we end up in the queue for roughly 24 hours.. |
182 | //24 hours worth of assets could be a lot, so the hope is that the region admin | 201 | //24 hours worth of assets could be a lot, so the hope is that the region admin |
183 | //will have gotten the asset connector back online quickly! | 202 | //will have gotten the asset connector back online quickly! |
184 | 203 | if(i == 0) | |
185 | int timefactor = a ^ 2; | 204 | timefactor = 1; |
186 | if (timefactor > 60) | 205 | else |
187 | { | 206 | { |
188 | timefactor = 60; | 207 | timefactor = 1 << nextlevel; |
208 | if (timefactor > 60) | ||
209 | timefactor = 60; | ||
189 | } | 210 | } |
190 | 211 | ||
191 | //First, find out if we care about this timefactor | 212 | if(m_retryCounter < timefactor) |
192 | if (timefactor % a == 0) | 213 | continue; // to update inUse; |
193 | { | ||
194 | //Yes, we do! | ||
195 | List<AssetBase> retrylist = m_retryQueue[a]; | ||
196 | m_retryQueue.Remove(a); | ||
197 | 214 | ||
198 | foreach(AssetBase ass in retrylist) | 215 | if (m_retryCounter % timefactor != 0) |
199 | { | 216 | continue; |
200 | Store(ass); //Store my ass. This function will put it back in the dictionary if it fails | 217 | |
201 | } | 218 | // a list to retry |
202 | } | 219 | lock(m_sendRetries) |
220 | m_sendRetries[i] = null; | ||
221 | |||
222 | // we are the only ones with a copy of this retrylist now | ||
223 | foreach(AssetBase ass in retrylist) | ||
224 | retryStore(ass, nextlevel); | ||
203 | } | 225 | } |
204 | 226 | ||
205 | if (m_retryQueue.Count == 0) | 227 | lock(m_sendRetries) |
206 | { | 228 | { |
207 | //It might only be one tick per minute, but I have | 229 | if(inUse == 0 ) |
208 | //repented and abandoned my wasteful ways | 230 | m_retryTimer.Stop(); |
209 | m_retryCounter = 0; | 231 | |
210 | m_retryTimer.Stop(); | 232 | m_inRetries = false; |
211 | } | 233 | } |
212 | } | 234 | } |
213 | 235 | ||
@@ -237,8 +259,9 @@ namespace OpenSim.Services.Connectors | |||
237 | 259 | ||
238 | asset = SynchronousRestObjectRequester.MakeRequest<int, AssetBase>("GET", uri, 0, m_Auth); | 260 | asset = SynchronousRestObjectRequester.MakeRequest<int, AssetBase>("GET", uri, 0, m_Auth); |
239 | 261 | ||
240 | if (m_Cache != null) | 262 | |
241 | m_Cache.Cache(asset); | 263 | if (asset != null && m_Cache != null) |
264 | m_Cache.Cache(asset); | ||
242 | } | 265 | } |
243 | return asset; | 266 | return asset; |
244 | } | 267 | } |
@@ -340,25 +363,18 @@ namespace OpenSim.Services.Connectors | |||
340 | m_AssetHandlers.Remove(id); | 363 | m_AssetHandlers.Remove(id); |
341 | } | 364 | } |
342 | 365 | ||
343 | Util.FireAndForget(x => | 366 | if(handlers != null) |
367 | { | ||
368 | Util.FireAndForget(x => | ||
344 | { | 369 | { |
345 | |||
346 | foreach (AssetRetrievedEx h in handlers) | 370 | foreach (AssetRetrievedEx h in handlers) |
347 | { | 371 | { |
348 | // Util.FireAndForget(x => | ||
349 | // { | ||
350 | try { h.Invoke(a); } | 372 | try { h.Invoke(a); } |
351 | catch { } | 373 | catch { } |
352 | // }); | ||
353 | } | 374 | } |
354 | 375 | handlers.Clear(); | |
355 | if (handlers != null) | ||
356 | handlers.Clear(); | ||
357 | |||
358 | }); | 376 | }); |
359 | 377 | } | |
360 | // if (handlers != null) | ||
361 | // handlers.Clear(); | ||
362 | success = true; | 378 | success = true; |
363 | } | 379 | } |
364 | } | 380 | } |
@@ -393,29 +409,24 @@ namespace OpenSim.Services.Connectors | |||
393 | { | 409 | { |
394 | AssetRetrievedEx handlerEx = new AssetRetrievedEx(delegate(AssetBase _asset) { handler(id, sender, _asset); }); | 410 | AssetRetrievedEx handlerEx = new AssetRetrievedEx(delegate(AssetBase _asset) { handler(id, sender, _asset); }); |
395 | 411 | ||
396 | // AssetRetrievedEx handlers; | ||
397 | List<AssetRetrievedEx> handlers; | 412 | List<AssetRetrievedEx> handlers; |
398 | if (m_AssetHandlers.TryGetValue(id, out handlers)) | 413 | if (m_AssetHandlers.TryGetValue(id, out handlers)) |
399 | { | 414 | { |
400 | // Someone else is already loading this asset. It will notify our handler when done. | 415 | // Someone else is already loading this asset. It will notify our handler when done. |
401 | // handlers += handlerEx; | ||
402 | handlers.Add(handlerEx); | 416 | handlers.Add(handlerEx); |
403 | return true; | 417 | return true; |
404 | } | 418 | } |
405 | 419 | ||
406 | // Load the asset ourselves | ||
407 | // handlers += handlerEx; | ||
408 | handlers = new List<AssetRetrievedEx>(); | 420 | handlers = new List<AssetRetrievedEx>(); |
409 | handlers.Add(handlerEx); | 421 | handlers.Add(handlerEx); |
410 | 422 | ||
411 | m_AssetHandlers.Add(id, handlers); | 423 | m_AssetHandlers.Add(id, handlers); |
412 | } | ||
413 | |||
414 | QueuedAssetRequest request = new QueuedAssetRequest(); | ||
415 | request.id = id; | ||
416 | request.uri = uri; | ||
417 | 424 | ||
418 | m_requestQueue.Enqueue(request); | 425 | QueuedAssetRequest request = new QueuedAssetRequest(); |
426 | request.id = id; | ||
427 | request.uri = uri; | ||
428 | m_requestQueue.Enqueue(request); | ||
429 | } | ||
419 | } | 430 | } |
420 | else | 431 | else |
421 | { | 432 | { |
@@ -495,43 +506,34 @@ namespace OpenSim.Services.Connectors | |||
495 | newID = SynchronousRestObjectRequester. | 506 | newID = SynchronousRestObjectRequester. |
496 | MakeRequest<AssetBase, string>("POST", uri, asset, 100000, m_Auth); | 507 | MakeRequest<AssetBase, string>("POST", uri, asset, 100000, m_Auth); |
497 | } | 508 | } |
498 | catch {} | 509 | catch |
510 | { | ||
511 | newID = null; | ||
512 | } | ||
499 | 513 | ||
500 | if (newID == null || newID == String.Empty || newID == stringUUIDZero) | 514 | if (newID == null || newID == String.Empty || newID == stringUUIDZero) |
501 | { | 515 | { |
502 | //The asset upload failed, put it in a queue for later | 516 | //The asset upload failed, try later |
503 | asset.UploadAttempts++; | 517 | lock(m_sendRetries) |
504 | if (asset.UploadAttempts > 30) | ||
505 | { | 518 | { |
506 | //By this stage we've been in the queue for a good few hours; | 519 | if (m_sendRetries[0] == null) |
507 | //We're going to drop the asset. | 520 | m_sendRetries[0] = new List<AssetBase>(); |
508 | m_log.ErrorFormat("[Assets] Dropping asset {0} - Upload has been in the queue for too long.", asset.ID.ToString()); | 521 | List<AssetBase> m_queue = m_sendRetries[0]; |
509 | } | ||
510 | else | ||
511 | { | ||
512 | if (!m_retryQueue.ContainsKey(asset.UploadAttempts)) | ||
513 | { | ||
514 | m_retryQueue.Add(asset.UploadAttempts, new List<AssetBase>()); | ||
515 | } | ||
516 | List<AssetBase> m_queue = m_retryQueue[asset.UploadAttempts]; | ||
517 | m_queue.Add(asset); | 522 | m_queue.Add(asset); |
518 | m_log.WarnFormat("[Assets] Upload failed: {0} - Requeuing asset for another run.", asset.ID.ToString()); | 523 | m_log.WarnFormat("[Assets] Upload failed: {0} type {1} will retry later", |
524 | asset.ID.ToString(), asset.Type.ToString()); | ||
519 | m_retryTimer.Start(); | 525 | m_retryTimer.Start(); |
520 | } | 526 | } |
521 | } | 527 | } |
522 | else | 528 | else |
523 | { | 529 | { |
524 | if (asset.UploadAttempts > 0) | ||
525 | { | ||
526 | m_log.InfoFormat("[Assets] Upload of {0} succeeded after {1} failed attempts", asset.ID.ToString(), asset.UploadAttempts.ToString()); | ||
527 | } | ||
528 | if (newID != asset.ID) | 530 | if (newID != asset.ID) |
529 | { | 531 | { |
530 | // Placing this here, so that this work with old asset servers that don't send any reply back | 532 | // Placing this here, so that this work with old asset servers that don't send any reply back |
531 | // SynchronousRestObjectRequester returns somethins that is not an empty string | 533 | // SynchronousRestObjectRequester returns somethins that is not an empty string |
532 | 534 | ||
533 | asset.ID = newID; | 535 | asset.ID = newID; |
534 | // what about FullID ???? | 536 | |
535 | if (m_Cache != null) | 537 | if (m_Cache != null) |
536 | m_Cache.Cache(asset); | 538 | m_Cache.Cache(asset); |
537 | } | 539 | } |
@@ -539,6 +541,62 @@ namespace OpenSim.Services.Connectors | |||
539 | return asset.ID; | 541 | return asset.ID; |
540 | } | 542 | } |
541 | 543 | ||
544 | public void retryStore(AssetBase asset, int nextRetryLevel) | ||
545 | { | ||
546 | /* this may be bad, so excluding | ||
547 | if (m_Cache != null && !m_Cache.Check(asset.ID)) | ||
548 | { | ||
549 | m_log.WarnFormat("[Assets] Upload giveup asset bc no longer in local cache: {0}", | ||
550 | asset.ID.ToString(); | ||
551 | return; // if no longer in cache, it was deleted or expired | ||
552 | } | ||
553 | */ | ||
554 | string uri = MapServer(asset.FullID.ToString()) + "/assets/"; | ||
555 | |||
556 | string newID = null; | ||
557 | try | ||
558 | { | ||
559 | newID = SynchronousRestObjectRequester. | ||
560 | MakeRequest<AssetBase, string>("POST", uri, asset, 100000, m_Auth); | ||
561 | } | ||
562 | catch | ||
563 | { | ||
564 | newID = null; | ||
565 | } | ||
566 | |||
567 | if (newID == null || newID == String.Empty || newID == stringUUIDZero) | ||
568 | { | ||
569 | if(nextRetryLevel >= MAXSENDRETRIESLEN) | ||
570 | m_log.WarnFormat("[Assets] Upload giveup after several retries id: {0} type {1}", | ||
571 | asset.ID.ToString(), asset.Type.ToString()); | ||
572 | else | ||
573 | { | ||
574 | lock(m_sendRetries) | ||
575 | { | ||
576 | if (m_sendRetries[nextRetryLevel] == null) | ||
577 | { | ||
578 | m_sendRetries[nextRetryLevel] = new List<AssetBase>(); | ||
579 | } | ||
580 | List<AssetBase> m_queue = m_sendRetries[nextRetryLevel]; | ||
581 | m_queue.Add(asset); | ||
582 | m_log.WarnFormat("[Assets] Upload failed: {0} type {1} will retry later", | ||
583 | asset.ID.ToString(), asset.Type.ToString()); | ||
584 | } | ||
585 | } | ||
586 | } | ||
587 | else | ||
588 | { | ||
589 | m_log.InfoFormat("[Assets] Upload of {0} succeeded after {1} failed attempts", asset.ID.ToString(), nextRetryLevel.ToString()); | ||
590 | if (newID != asset.ID) | ||
591 | { | ||
592 | asset.ID = newID; | ||
593 | |||
594 | if (m_Cache != null) | ||
595 | m_Cache.Cache(asset); | ||
596 | } | ||
597 | } | ||
598 | } | ||
599 | |||
542 | public bool UpdateContent(string id, byte[] data) | 600 | public bool UpdateContent(string id, byte[] data) |
543 | { | 601 | { |
544 | AssetBase asset = null; | 602 | AssetBase asset = null; |
@@ -569,6 +627,7 @@ namespace OpenSim.Services.Connectors | |||
569 | return false; | 627 | return false; |
570 | } | 628 | } |
571 | 629 | ||
630 | |||
572 | public bool Delete(string id) | 631 | public bool Delete(string id) |
573 | { | 632 | { |
574 | string uri = MapServer(id) + "/assets/" + id; | 633 | string uri = MapServer(id) + "/assets/" + id; |
diff --git a/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs index 2340998..aad3bd2 100644 --- a/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs +++ b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs | |||
@@ -159,8 +159,7 @@ namespace OpenSim.Services.Connectors.Hypergrid | |||
159 | string filename = string.Empty; | 159 | string filename = string.Empty; |
160 | 160 | ||
161 | try | 161 | try |
162 | { | 162 | { |
163 | WebClient c = new WebClient(); | ||
164 | //m_log.Debug("JPEG: " + imageURL); | 163 | //m_log.Debug("JPEG: " + imageURL); |
165 | string name = regionID.ToString(); | 164 | string name = regionID.ToString(); |
166 | filename = Path.Combine(storagePath, name + ".jpg"); | 165 | filename = Path.Combine(storagePath, name + ".jpg"); |
@@ -168,7 +167,8 @@ namespace OpenSim.Services.Connectors.Hypergrid | |||
168 | if (!File.Exists(filename)) | 167 | if (!File.Exists(filename)) |
169 | { | 168 | { |
170 | m_log.DebugFormat("[GATEKEEPER SERVICE CONNECTOR]: downloading..."); | 169 | m_log.DebugFormat("[GATEKEEPER SERVICE CONNECTOR]: downloading..."); |
171 | c.DownloadFile(imageURL, filename); | 170 | using(WebClient c = new WebClient()) |
171 | c.DownloadFile(imageURL, filename); | ||
172 | } | 172 | } |
173 | else | 173 | else |
174 | { | 174 | { |
diff --git a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs index 3a0d197..8e1bf37 100644 --- a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs +++ b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs | |||
@@ -106,17 +106,18 @@ namespace OpenSim.Services.Connectors.Simulation | |||
106 | 106 | ||
107 | public bool CreateAgent(GridRegion source, GridRegion destination, AgentCircuitData aCircuit, uint flags, EntityTransferContext ctx, out string myipaddress, out string reason) | 107 | public bool CreateAgent(GridRegion source, GridRegion destination, AgentCircuitData aCircuit, uint flags, EntityTransferContext ctx, out string myipaddress, out string reason) |
108 | { | 108 | { |
109 | m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: Creating agent at {0}", destination.ServerURI); | ||
110 | reason = String.Empty; | 109 | reason = String.Empty; |
111 | myipaddress = String.Empty; | 110 | myipaddress = String.Empty; |
112 | 111 | ||
113 | if (destination == null) | 112 | if (destination == null) |
114 | { | 113 | { |
115 | reason = "Destination not found"; | 114 | reason = "Destination not found"; |
116 | m_log.Debug("[REMOTE SIMULATION CONNECTOR]: Given destination is null"); | 115 | m_log.Debug("[REMOTE SIMULATION CONNECTOR]: Create agent destination is null"); |
117 | return false; | 116 | return false; |
118 | } | 117 | } |
119 | 118 | ||
119 | m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: Creating agent at {0}", destination.ServerURI); | ||
120 | |||
120 | string uri = destination.ServerURI + AgentPath() + aCircuit.AgentID + "/"; | 121 | string uri = destination.ServerURI + AgentPath() + aCircuit.AgentID + "/"; |
121 | 122 | ||
122 | try | 123 | try |
diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs index 6681f1a..92b3137 100644 --- a/OpenSim/Services/LLLoginService/LLLoginService.cs +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs | |||
@@ -512,8 +512,8 @@ namespace OpenSim.Services.LLLoginService | |||
512 | // | 512 | // |
513 | if (m_MessageUrl != String.Empty) | 513 | if (m_MessageUrl != String.Empty) |
514 | { | 514 | { |
515 | WebClient client = new WebClient(); | 515 | using(WebClient client = new WebClient()) |
516 | processedMessage = client.DownloadString(m_MessageUrl); | 516 | processedMessage = client.DownloadString(m_MessageUrl); |
517 | } | 517 | } |
518 | else | 518 | else |
519 | { | 519 | { |
diff --git a/OpenSim/Services/UserAccountService/UserAccountService.cs b/OpenSim/Services/UserAccountService/UserAccountService.cs index 668fe53..706d475 100644 --- a/OpenSim/Services/UserAccountService/UserAccountService.cs +++ b/OpenSim/Services/UserAccountService/UserAccountService.cs | |||
@@ -92,7 +92,7 @@ namespace OpenSim.Services.UserAccountService | |||
92 | m_RootInstance = this; | 92 | m_RootInstance = this; |
93 | MainConsole.Instance.Commands.AddCommand("Users", false, | 93 | MainConsole.Instance.Commands.AddCommand("Users", false, |
94 | "create user", | 94 | "create user", |
95 | "create user [<first> [<last> [<pass> [<email> [<user id>]]]]]", | 95 | "create user [<first> [<last> [<pass> [<email> [<user id> [<model>]]]]]]", |
96 | "Create a new user", HandleCreateUser); | 96 | "Create a new user", HandleCreateUser); |
97 | 97 | ||
98 | MainConsole.Instance.Commands.AddCommand("Users", false, | 98 | MainConsole.Instance.Commands.AddCommand("Users", false, |
@@ -353,7 +353,7 @@ namespace OpenSim.Services.UserAccountService | |||
353 | /// <summary> | 353 | /// <summary> |
354 | /// Handle the create user command from the console. | 354 | /// Handle the create user command from the console. |
355 | /// </summary> | 355 | /// </summary> |
356 | /// <param name="cmdparams">string array with parameters: firstname, lastname, password, locationX, locationY, email</param> | 356 | /// <param name="cmdparams">string array with parameters: firstname, lastname, password, locationX, locationY, email, userID, model name </param> |
357 | protected void HandleCreateUser(string module, string[] cmdparams) | 357 | protected void HandleCreateUser(string module, string[] cmdparams) |
358 | { | 358 | { |
359 | string firstName; | 359 | string firstName; |
@@ -361,6 +361,7 @@ namespace OpenSim.Services.UserAccountService | |||
361 | string password; | 361 | string password; |
362 | string email; | 362 | string email; |
363 | string rawPrincipalId; | 363 | string rawPrincipalId; |
364 | string model; | ||
364 | 365 | ||
365 | List<char> excluded = new List<char>(new char[]{' '}); | 366 | List<char> excluded = new List<char>(new char[]{' '}); |
366 | 367 | ||
@@ -385,11 +386,16 @@ namespace OpenSim.Services.UserAccountService | |||
385 | else | 386 | else |
386 | rawPrincipalId = cmdparams[6]; | 387 | rawPrincipalId = cmdparams[6]; |
387 | 388 | ||
389 | if (cmdparams.Length < 8) | ||
390 | model = MainConsole.Instance.CmdPrompt("Model name",""); | ||
391 | else | ||
392 | model = cmdparams[7]; | ||
393 | |||
388 | UUID principalId = UUID.Zero; | 394 | UUID principalId = UUID.Zero; |
389 | if (!UUID.TryParse(rawPrincipalId, out principalId)) | 395 | if (!UUID.TryParse(rawPrincipalId, out principalId)) |
390 | throw new Exception(string.Format("ID {0} is not a valid UUID", rawPrincipalId)); | 396 | throw new Exception(string.Format("ID {0} is not a valid UUID", rawPrincipalId)); |
391 | 397 | ||
392 | CreateUser(UUID.Zero, principalId, firstName, lastName, password, email); | 398 | CreateUser(UUID.Zero, principalId, firstName, lastName, password, email, model); |
393 | } | 399 | } |
394 | 400 | ||
395 | protected void HandleShowAccount(string module, string[] cmdparams) | 401 | protected void HandleShowAccount(string module, string[] cmdparams) |
@@ -544,7 +550,8 @@ namespace OpenSim.Services.UserAccountService | |||
544 | /// <param name="lastName"></param> | 550 | /// <param name="lastName"></param> |
545 | /// <param name="password"></param> | 551 | /// <param name="password"></param> |
546 | /// <param name="email"></param> | 552 | /// <param name="email"></param> |
547 | public UserAccount CreateUser(UUID scopeID, UUID principalID, string firstName, string lastName, string password, string email) | 553 | /// <param name="model"></param> |
554 | public UserAccount CreateUser(UUID scopeID, UUID principalID, string firstName, string lastName, string password, string email, string model = "") | ||
548 | { | 555 | { |
549 | UserAccount account = GetUserAccount(UUID.Zero, firstName, lastName); | 556 | UserAccount account = GetUserAccount(UUID.Zero, firstName, lastName); |
550 | if (null == account) | 557 | if (null == account) |
@@ -603,7 +610,12 @@ namespace OpenSim.Services.UserAccountService | |||
603 | } | 610 | } |
604 | 611 | ||
605 | if (m_CreateDefaultAvatarEntries) | 612 | if (m_CreateDefaultAvatarEntries) |
606 | CreateDefaultAppearanceEntries(account.PrincipalID); | 613 | { |
614 | if (String.IsNullOrEmpty(model)) | ||
615 | CreateDefaultAppearanceEntries(account.PrincipalID); | ||
616 | else | ||
617 | EstablishAppearance(account.PrincipalID, model); | ||
618 | } | ||
607 | } | 619 | } |
608 | 620 | ||
609 | m_log.InfoFormat( | 621 | m_log.InfoFormat( |
@@ -734,6 +746,7 @@ namespace OpenSim.Services.UserAccountService | |||
734 | wearables[AvatarWearable.PANTS] = new AvatarWearable(pants.ID, pants.AssetID); | 746 | wearables[AvatarWearable.PANTS] = new AvatarWearable(pants.ID, pants.AssetID); |
735 | 747 | ||
736 | AvatarAppearance ap = new AvatarAppearance(); | 748 | AvatarAppearance ap = new AvatarAppearance(); |
749 | // this loop works, but is questionable | ||
737 | for (int i = 0; i < 6; i++) | 750 | for (int i = 0; i < 6; i++) |
738 | { | 751 | { |
739 | ap.SetWearable(i, wearables[i]); | 752 | ap.SetWearable(i, wearables[i]); |
@@ -742,5 +755,205 @@ namespace OpenSim.Services.UserAccountService | |||
742 | m_AvatarService.SetAppearance(principalID, ap); | 755 | m_AvatarService.SetAppearance(principalID, ap); |
743 | } | 756 | } |
744 | } | 757 | } |
758 | |||
759 | protected void EstablishAppearance(UUID destinationAgent, string model) | ||
760 | { | ||
761 | m_log.DebugFormat("[USER ACCOUNT SERVICE]: Establishing new appearance for {0} - {1}", | ||
762 | destinationAgent.ToString(), model); | ||
763 | |||
764 | string[] modelSpecifiers = model.Split(); | ||
765 | if (modelSpecifiers.Length != 2) | ||
766 | { | ||
767 | m_log.WarnFormat("[USER ACCOUNT SERVICE]: Invalid model name \'{0}\'. Falling back to Ruth for {1}", | ||
768 | model, destinationAgent); | ||
769 | CreateDefaultAppearanceEntries(destinationAgent); | ||
770 | return; | ||
771 | } | ||
772 | |||
773 | // Does the source model exist? | ||
774 | UserAccount modelAccount = GetUserAccount(UUID.Zero, modelSpecifiers[0], modelSpecifiers[1]); | ||
775 | if (modelAccount == null) | ||
776 | { | ||
777 | m_log.WarnFormat("[USER ACCOUNT SERVICE]: Requested model \'{0}\' not found. Falling back to Ruth for {1}", | ||
778 | model, destinationAgent); | ||
779 | CreateDefaultAppearanceEntries(destinationAgent); | ||
780 | return; | ||
781 | } | ||
782 | |||
783 | // Does the source model have an established appearance herself? | ||
784 | AvatarAppearance modelAppearance = m_AvatarService.GetAppearance(modelAccount.PrincipalID); | ||
785 | if (modelAppearance == null) | ||
786 | { | ||
787 | m_log.WarnFormat("USER ACCOUNT SERVICE]: Requested model \'{0}\' does not have an established appearance. Falling back to Ruth for {1}", | ||
788 | model, destinationAgent); | ||
789 | CreateDefaultAppearanceEntries(destinationAgent); | ||
790 | return; | ||
791 | } | ||
792 | |||
793 | try | ||
794 | { | ||
795 | CopyWearablesAndAttachments(destinationAgent, modelAccount.PrincipalID, modelAppearance); | ||
796 | |||
797 | m_AvatarService.SetAppearance(destinationAgent, modelAppearance); | ||
798 | } | ||
799 | catch (Exception e) | ||
800 | { | ||
801 | m_log.WarnFormat("[USER ACCOUNT SERVICE]: Error transferring appearance for {0} : {1}", | ||
802 | destinationAgent, e.Message); | ||
803 | } | ||
804 | |||
805 | m_log.DebugFormat("[USER ACCOUNT SERVICE]: Finished establishing appearance for {0}", | ||
806 | destinationAgent.ToString()); | ||
807 | } | ||
808 | |||
809 | /// <summary> | ||
810 | /// This method is called by EstablishAppearance to do a copy all inventory items | ||
811 | /// worn or attached to the Clothing inventory folder of the receiving avatar. | ||
812 | /// In parallel the avatar wearables and attachments are updated. | ||
813 | /// </summary> | ||
814 | private void CopyWearablesAndAttachments(UUID destination, UUID source, AvatarAppearance avatarAppearance) | ||
815 | { | ||
816 | // Get Clothing folder of receiver | ||
817 | InventoryFolderBase destinationFolder = m_InventoryService.GetFolderForType(destination, FolderType.Clothing); | ||
818 | |||
819 | if (destinationFolder == null) | ||
820 | throw new Exception("Cannot locate folder(s)"); | ||
821 | |||
822 | // Missing destination folder? This should *never* be the case | ||
823 | if (destinationFolder.Type != (short)FolderType.Clothing) | ||
824 | { | ||
825 | destinationFolder = new InventoryFolderBase(); | ||
826 | |||
827 | destinationFolder.ID = UUID.Random(); | ||
828 | destinationFolder.Name = "Clothing"; | ||
829 | destinationFolder.Owner = destination; | ||
830 | destinationFolder.Type = (short)AssetType.Clothing; | ||
831 | destinationFolder.ParentID = m_InventoryService.GetRootFolder(destination).ID; | ||
832 | destinationFolder.Version = 1; | ||
833 | m_InventoryService.AddFolder(destinationFolder); // store base record | ||
834 | m_log.ErrorFormat("[USER ACCOUNT SERVICE]: Created folder for destination {0}", source); | ||
835 | } | ||
836 | |||
837 | // Wearables | ||
838 | AvatarWearable[] wearables = avatarAppearance.Wearables; | ||
839 | AvatarWearable wearable; | ||
840 | |||
841 | for (int i = 0; i < wearables.Length; i++) | ||
842 | { | ||
843 | wearable = wearables[i]; | ||
844 | if (wearable[0].ItemID != UUID.Zero) | ||
845 | { | ||
846 | // Get inventory item and copy it | ||
847 | InventoryItemBase item = m_InventoryService.GetItem(source, wearable[0].ItemID); | ||
848 | |||
849 | if (item != null) | ||
850 | { | ||
851 | InventoryItemBase destinationItem = new InventoryItemBase(UUID.Random(), destination); | ||
852 | destinationItem.Name = item.Name; | ||
853 | destinationItem.Owner = destination; | ||
854 | destinationItem.Description = item.Description; | ||
855 | destinationItem.InvType = item.InvType; | ||
856 | destinationItem.CreatorId = item.CreatorId; | ||
857 | destinationItem.CreatorData = item.CreatorData; | ||
858 | destinationItem.NextPermissions = item.NextPermissions; | ||
859 | destinationItem.CurrentPermissions = item.CurrentPermissions; | ||
860 | destinationItem.BasePermissions = item.BasePermissions; | ||
861 | destinationItem.EveryOnePermissions = item.EveryOnePermissions; | ||
862 | destinationItem.GroupPermissions = item.GroupPermissions; | ||
863 | destinationItem.AssetType = item.AssetType; | ||
864 | destinationItem.AssetID = item.AssetID; | ||
865 | destinationItem.GroupID = item.GroupID; | ||
866 | destinationItem.GroupOwned = item.GroupOwned; | ||
867 | destinationItem.SalePrice = item.SalePrice; | ||
868 | destinationItem.SaleType = item.SaleType; | ||
869 | destinationItem.Flags = item.Flags; | ||
870 | destinationItem.CreationDate = item.CreationDate; | ||
871 | destinationItem.Folder = destinationFolder.ID; | ||
872 | ApplyNextOwnerPermissions(destinationItem); | ||
873 | |||
874 | m_InventoryService.AddItem(destinationItem); | ||
875 | m_log.DebugFormat("[USER ACCOUNT SERVICE]: Added item {0} to folder {1}", destinationItem.ID, destinationFolder.ID); | ||
876 | |||
877 | // Wear item | ||
878 | AvatarWearable newWearable = new AvatarWearable(); | ||
879 | newWearable.Wear(destinationItem.ID, wearable[0].AssetID); | ||
880 | avatarAppearance.SetWearable(i, newWearable); | ||
881 | } | ||
882 | else | ||
883 | { | ||
884 | m_log.WarnFormat("[USER ACCOUNT SERVICE]: Error transferring {0} to folder {1}", wearable[0].ItemID, destinationFolder.ID); | ||
885 | } | ||
886 | } | ||
887 | } | ||
888 | |||
889 | // Attachments | ||
890 | List<AvatarAttachment> attachments = avatarAppearance.GetAttachments(); | ||
891 | |||
892 | foreach (AvatarAttachment attachment in attachments) | ||
893 | { | ||
894 | int attachpoint = attachment.AttachPoint; | ||
895 | UUID itemID = attachment.ItemID; | ||
896 | |||
897 | if (itemID != UUID.Zero) | ||
898 | { | ||
899 | // Get inventory item and copy it | ||
900 | InventoryItemBase item = m_InventoryService.GetItem(source, itemID); | ||
901 | |||
902 | if (item != null) | ||
903 | { | ||
904 | InventoryItemBase destinationItem = new InventoryItemBase(UUID.Random(), destination); | ||
905 | destinationItem.Name = item.Name; | ||
906 | destinationItem.Owner = destination; | ||
907 | destinationItem.Description = item.Description; | ||
908 | destinationItem.InvType = item.InvType; | ||
909 | destinationItem.CreatorId = item.CreatorId; | ||
910 | destinationItem.CreatorData = item.CreatorData; | ||
911 | destinationItem.NextPermissions = item.NextPermissions; | ||
912 | destinationItem.CurrentPermissions = item.CurrentPermissions; | ||
913 | destinationItem.BasePermissions = item.BasePermissions; | ||
914 | destinationItem.EveryOnePermissions = item.EveryOnePermissions; | ||
915 | destinationItem.GroupPermissions = item.GroupPermissions; | ||
916 | destinationItem.AssetType = item.AssetType; | ||
917 | destinationItem.AssetID = item.AssetID; | ||
918 | destinationItem.GroupID = item.GroupID; | ||
919 | destinationItem.GroupOwned = item.GroupOwned; | ||
920 | destinationItem.SalePrice = item.SalePrice; | ||
921 | destinationItem.SaleType = item.SaleType; | ||
922 | destinationItem.Flags = item.Flags; | ||
923 | destinationItem.CreationDate = item.CreationDate; | ||
924 | destinationItem.Folder = destinationFolder.ID; | ||
925 | ApplyNextOwnerPermissions(destinationItem); | ||
926 | |||
927 | m_InventoryService.AddItem(destinationItem); | ||
928 | m_log.DebugFormat("[USER ACCOUNT SERVICE]: Added item {0} to folder {1}", destinationItem.ID, destinationFolder.ID); | ||
929 | |||
930 | // Attach item | ||
931 | avatarAppearance.SetAttachment(attachpoint, destinationItem.ID, destinationItem.AssetID); | ||
932 | m_log.DebugFormat("[USER ACCOUNT SERVICE]: Attached {0}", destinationItem.ID); | ||
933 | } | ||
934 | else | ||
935 | { | ||
936 | m_log.WarnFormat("[USER ACCOUNT SERVICE]: Error transferring {0} to folder {1}", itemID, destinationFolder.ID); | ||
937 | } | ||
938 | } | ||
939 | } | ||
940 | } | ||
941 | |||
942 | /// <summary> | ||
943 | /// Apply next owner permissions. | ||
944 | /// </summary> | ||
945 | private void ApplyNextOwnerPermissions(InventoryItemBase item) | ||
946 | { | ||
947 | if (item.InvType == (int)InventoryType.Object) | ||
948 | { | ||
949 | uint perms = item.CurrentPermissions; | ||
950 | PermissionsUtil.ApplyFoldedPermissions(item.CurrentPermissions, ref perms); | ||
951 | item.CurrentPermissions = perms; | ||
952 | } | ||
953 | |||
954 | item.CurrentPermissions &= item.NextPermissions; | ||
955 | item.BasePermissions &= item.NextPermissions; | ||
956 | item.EveryOnePermissions &= item.NextPermissions; | ||
957 | } | ||
745 | } | 958 | } |
746 | } | 959 | } |