diff options
Diffstat (limited to 'OpenSim/Services')
93 files changed, 18490 insertions, 2080 deletions
diff --git a/OpenSim/Services/AssetService/AssetService.cs b/OpenSim/Services/AssetService/AssetService.cs index ed87f3f..ec424c0 100644 --- a/OpenSim/Services/AssetService/AssetService.cs +++ b/OpenSim/Services/AssetService/AssetService.cs | |||
@@ -26,6 +26,8 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
29 | using System.Reflection; | 31 | using System.Reflection; |
30 | using Nini.Config; | 32 | using Nini.Config; |
31 | using log4net; | 33 | using log4net; |
@@ -43,74 +45,114 @@ namespace OpenSim.Services.AssetService | |||
43 | LogManager.GetLogger( | 45 | LogManager.GetLogger( |
44 | MethodBase.GetCurrentMethod().DeclaringType); | 46 | MethodBase.GetCurrentMethod().DeclaringType); |
45 | 47 | ||
48 | protected static AssetService m_RootInstance; | ||
49 | |||
46 | public AssetService(IConfigSource config) : base(config) | 50 | public AssetService(IConfigSource config) : base(config) |
47 | { | 51 | { |
48 | MainConsole.Instance.Commands.AddCommand("kfs", false, | 52 | if (m_RootInstance == null) |
49 | "show digest", | 53 | { |
50 | "show digest <ID>", | 54 | m_RootInstance = this; |
51 | "Show asset digest", HandleShowDigest); | ||
52 | 55 | ||
53 | MainConsole.Instance.Commands.AddCommand("kfs", false, | 56 | MainConsole.Instance.Commands.AddCommand("kfs", false, |
54 | "delete asset", | 57 | "show digest", |
55 | "delete asset <ID>", | 58 | "show digest <ID>", |
56 | "Delete asset from database", HandleDeleteAsset); | 59 | "Show asset digest", HandleShowDigest); |
57 | 60 | ||
58 | if (m_AssetLoader != null) | 61 | MainConsole.Instance.Commands.AddCommand("kfs", false, |
59 | { | 62 | "delete asset", |
60 | IConfig assetConfig = config.Configs["AssetService"]; | 63 | "delete asset <ID>", |
61 | if (assetConfig == null) | 64 | "Delete asset from database", HandleDeleteAsset); |
62 | throw new Exception("No AssetService configuration"); | 65 | |
66 | MainConsole.Instance.Commands.AddCommand("kfs", false, | ||
67 | "dump asset", | ||
68 | "dump asset <ID>", | ||
69 | "Dump asset to a file", | ||
70 | "The filename is the same as the ID given.", | ||
71 | HandleDumpAsset); | ||
72 | |||
73 | if (m_AssetLoader != null) | ||
74 | { | ||
75 | IConfig assetConfig = config.Configs["AssetService"]; | ||
76 | if (assetConfig == null) | ||
77 | throw new Exception("No AssetService configuration"); | ||
63 | 78 | ||
64 | string loaderArgs = assetConfig.GetString("AssetLoaderArgs", | 79 | string loaderArgs = assetConfig.GetString("AssetLoaderArgs", |
65 | String.Empty); | 80 | String.Empty); |
66 | 81 | ||
67 | bool assetLoaderEnabled = assetConfig.GetBoolean("AssetLoaderEnabled", true); | 82 | bool assetLoaderEnabled = assetConfig.GetBoolean("AssetLoaderEnabled", true); |
68 | 83 | ||
69 | if (assetLoaderEnabled) | 84 | if (assetLoaderEnabled) |
70 | { | 85 | { |
71 | m_log.InfoFormat("[ASSET]: Loading default asset set from {0}", loaderArgs); | 86 | m_log.DebugFormat("[ASSET]: Loading default asset set from {0}", loaderArgs); |
72 | m_AssetLoader.ForEachDefaultXmlAsset(loaderArgs, | 87 | |
88 | m_AssetLoader.ForEachDefaultXmlAsset( | ||
89 | loaderArgs, | ||
73 | delegate(AssetBase a) | 90 | delegate(AssetBase a) |
74 | { | 91 | { |
75 | Store(a); | 92 | AssetBase existingAsset = Get(a.ID); |
93 | // AssetMetadata existingMetadata = GetMetadata(a.ID); | ||
94 | |||
95 | if (existingAsset == null || Util.SHA1Hash(existingAsset.Data) != Util.SHA1Hash(a.Data)) | ||
96 | { | ||
97 | // m_log.DebugFormat("[ASSET]: Storing {0} {1}", a.Name, a.ID); | ||
98 | Store(a); | ||
99 | } | ||
76 | }); | 100 | }); |
101 | } | ||
102 | |||
103 | m_log.Debug("[ASSET SERVICE]: Local asset service enabled"); | ||
77 | } | 104 | } |
78 | |||
79 | m_log.Info("[ASSET SERVICE]: Local asset service enabled"); | ||
80 | } | 105 | } |
81 | } | 106 | } |
82 | 107 | ||
83 | public AssetBase Get(string id) | 108 | public virtual AssetBase Get(string id) |
84 | { | 109 | { |
110 | // m_log.DebugFormat("[ASSET SERVICE]: Get asset for {0}", id); | ||
111 | |||
85 | UUID assetID; | 112 | UUID assetID; |
86 | 113 | ||
87 | if (!UUID.TryParse(id, out assetID)) | 114 | if (!UUID.TryParse(id, out assetID)) |
88 | { | 115 | { |
89 | m_log.WarnFormat("[ASSET SERVICE]: Could not parse requested sset id {0}", id); | 116 | m_log.WarnFormat("[ASSET SERVICE]: Could not parse requested asset id {0}", id); |
90 | return null; | 117 | return null; |
91 | } | 118 | } |
92 | 119 | ||
93 | return m_Database.GetAsset(assetID); | 120 | try |
121 | { | ||
122 | return m_Database.GetAsset(assetID); | ||
123 | } | ||
124 | catch (Exception e) | ||
125 | { | ||
126 | m_log.ErrorFormat("[ASSET SERVICE]: Exception getting asset {0} {1}", assetID, e); | ||
127 | return null; | ||
128 | } | ||
94 | } | 129 | } |
95 | 130 | ||
96 | public AssetBase GetCached(string id) | 131 | public virtual AssetBase GetCached(string id) |
97 | { | 132 | { |
98 | return Get(id); | 133 | return Get(id); |
99 | } | 134 | } |
100 | 135 | ||
101 | public AssetMetadata GetMetadata(string id) | 136 | public virtual AssetMetadata GetMetadata(string id) |
102 | { | 137 | { |
138 | // m_log.DebugFormat("[ASSET SERVICE]: Get asset metadata for {0}", id); | ||
139 | |||
103 | UUID assetID; | 140 | UUID assetID; |
104 | 141 | ||
105 | if (!UUID.TryParse(id, out assetID)) | 142 | if (!UUID.TryParse(id, out assetID)) |
106 | return null; | 143 | return null; |
107 | 144 | ||
108 | AssetBase asset = m_Database.GetAsset(assetID); | 145 | AssetBase asset = m_Database.GetAsset(assetID); |
109 | return asset.Metadata; | 146 | if (asset != null) |
147 | return asset.Metadata; | ||
148 | |||
149 | return null; | ||
110 | } | 150 | } |
111 | 151 | ||
112 | public byte[] GetData(string id) | 152 | public virtual byte[] GetData(string id) |
113 | { | 153 | { |
154 | // m_log.DebugFormat("[ASSET SERVICE]: Get asset data for {0}", id); | ||
155 | |||
114 | UUID assetID; | 156 | UUID assetID; |
115 | 157 | ||
116 | if (!UUID.TryParse(id, out assetID)) | 158 | if (!UUID.TryParse(id, out assetID)) |
@@ -120,7 +162,7 @@ namespace OpenSim.Services.AssetService | |||
120 | return asset.Data; | 162 | return asset.Data; |
121 | } | 163 | } |
122 | 164 | ||
123 | public bool Get(string id, Object sender, AssetRetrieved handler) | 165 | public virtual bool Get(string id, Object sender, AssetRetrieved handler) |
124 | { | 166 | { |
125 | //m_log.DebugFormat("[AssetService]: Get asset async {0}", id); | 167 | //m_log.DebugFormat("[AssetService]: Get asset async {0}", id); |
126 | 168 | ||
@@ -138,10 +180,22 @@ namespace OpenSim.Services.AssetService | |||
138 | return true; | 180 | return true; |
139 | } | 181 | } |
140 | 182 | ||
141 | public string Store(AssetBase asset) | 183 | public virtual string Store(AssetBase asset) |
142 | { | 184 | { |
143 | //m_log.DebugFormat("[ASSET SERVICE]: Store asset {0} {1}", asset.Name, asset.ID); | 185 | if (!m_Database.ExistsAsset(asset.FullID)) |
144 | m_Database.StoreAsset(asset); | 186 | { |
187 | // m_log.DebugFormat( | ||
188 | // "[ASSET SERVICE]: Storing asset {0} {1}, bytes {2}", asset.Name, asset.FullID, asset.Data.Length); | ||
189 | if (!m_Database.StoreAsset(asset)) | ||
190 | { | ||
191 | return UUID.Zero.ToString(); | ||
192 | } | ||
193 | } | ||
194 | // else | ||
195 | // { | ||
196 | // m_log.DebugFormat( | ||
197 | // "[ASSET SERVICE]: Not storing asset {0} {1}, bytes {2} as it already exists", asset.Name, asset.FullID, asset.Data.Length); | ||
198 | // } | ||
145 | 199 | ||
146 | return asset.ID; | 200 | return asset.ID; |
147 | } | 201 | } |
@@ -151,10 +205,63 @@ namespace OpenSim.Services.AssetService | |||
151 | return false; | 205 | return false; |
152 | } | 206 | } |
153 | 207 | ||
154 | public bool Delete(string id) | 208 | public virtual bool Delete(string id) |
155 | { | 209 | { |
210 | m_log.DebugFormat("[ASSET SERVICE]: Deleting asset {0}", id); | ||
211 | UUID assetID; | ||
212 | if (!UUID.TryParse(id, out assetID)) | ||
213 | return false; | ||
214 | |||
215 | AssetBase asset = m_Database.GetAsset(assetID); | ||
216 | if (asset == null) | ||
217 | return false; | ||
218 | |||
219 | if ((int)(asset.Flags & AssetFlags.Maptile) != 0) | ||
220 | { | ||
221 | return m_Database.Delete(id); | ||
222 | } | ||
223 | else | ||
224 | m_log.DebugFormat("[ASSET SERVICE]: Request to delete asset {0}, but flags are not Maptile", id); | ||
225 | |||
156 | return false; | 226 | return false; |
157 | } | 227 | } |
228 | |||
229 | void HandleDumpAsset(string module, string[] args) | ||
230 | { | ||
231 | if (args.Length < 3) | ||
232 | { | ||
233 | MainConsole.Instance.Output("Usage is dump asset <ID>"); | ||
234 | return; | ||
235 | } | ||
236 | |||
237 | string rawAssetId = args[2]; | ||
238 | UUID assetId; | ||
239 | |||
240 | if (!UUID.TryParse(rawAssetId, out assetId)) | ||
241 | { | ||
242 | MainConsole.Instance.OutputFormat("ERROR: {0} is not a valid ID format", rawAssetId); | ||
243 | return; | ||
244 | } | ||
245 | |||
246 | AssetBase asset = m_Database.GetAsset(assetId); | ||
247 | if (asset == null) | ||
248 | { | ||
249 | MainConsole.Instance.OutputFormat("ERROR: No asset found with ID {0}", assetId); | ||
250 | return; | ||
251 | } | ||
252 | |||
253 | string fileName = rawAssetId; | ||
254 | |||
255 | using (FileStream fs = new FileStream(fileName, FileMode.CreateNew)) | ||
256 | { | ||
257 | using (BinaryWriter bw = new BinaryWriter(fs)) | ||
258 | { | ||
259 | bw.Write(asset.Data); | ||
260 | } | ||
261 | } | ||
262 | |||
263 | MainConsole.Instance.OutputFormat("Asset dumped to file {0}", fileName); | ||
264 | } | ||
158 | 265 | ||
159 | void HandleShowDigest(string module, string[] args) | 266 | void HandleShowDigest(string module, string[] args) |
160 | { | 267 | { |
@@ -174,10 +281,11 @@ namespace OpenSim.Services.AssetService | |||
174 | 281 | ||
175 | int i; | 282 | int i; |
176 | 283 | ||
177 | MainConsole.Instance.Output(String.Format("Name: {0}", asset.Name)); | 284 | MainConsole.Instance.OutputFormat("Name: {0}", asset.Name); |
178 | MainConsole.Instance.Output(String.Format("Description: {0}", asset.Description)); | 285 | MainConsole.Instance.OutputFormat("Description: {0}", asset.Description); |
179 | MainConsole.Instance.Output(String.Format("Type: {0}", asset.Type)); | 286 | MainConsole.Instance.OutputFormat("Type: {0} (type number = {1})", (AssetType)asset.Type, asset.Type); |
180 | MainConsole.Instance.Output(String.Format("Content-type: {0}", asset.Metadata.ContentType)); | 287 | MainConsole.Instance.OutputFormat("Content-type: {0}", asset.Metadata.ContentType); |
288 | MainConsole.Instance.OutputFormat("Flags: {0}", asset.Metadata.Flags); | ||
181 | 289 | ||
182 | for (i = 0 ; i < 5 ; i++) | 290 | for (i = 0 ; i < 5 ; i++) |
183 | { | 291 | { |
diff --git a/OpenSim/Services/AuthenticationService/AuthenticationServiceBase.cs b/OpenSim/Services/AuthenticationService/AuthenticationServiceBase.cs index dcf090e..e42f9a0 100644 --- a/OpenSim/Services/AuthenticationService/AuthenticationServiceBase.cs +++ b/OpenSim/Services/AuthenticationService/AuthenticationServiceBase.cs | |||
@@ -30,8 +30,11 @@ using OpenMetaverse; | |||
30 | using log4net; | 30 | using log4net; |
31 | using Nini.Config; | 31 | using Nini.Config; |
32 | using System.Reflection; | 32 | using System.Reflection; |
33 | using OpenSim.Services.Base; | 33 | using OpenSim.Server.Base; |
34 | using OpenSim.Services.Interfaces; | ||
34 | using OpenSim.Data; | 35 | using OpenSim.Data; |
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Services.Base; | ||
35 | 38 | ||
36 | namespace OpenSim.Services.AuthenticationService | 39 | namespace OpenSim.Services.AuthenticationService |
37 | { | 40 | { |
@@ -43,11 +46,17 @@ namespace OpenSim.Services.AuthenticationService | |||
43 | // | 46 | // |
44 | public class AuthenticationServiceBase : ServiceBase | 47 | public class AuthenticationServiceBase : ServiceBase |
45 | { | 48 | { |
46 | // private static readonly ILog m_log = | 49 | private static readonly ILog m_log = |
47 | // LogManager.GetLogger( | 50 | LogManager.GetLogger( |
48 | // MethodBase.GetCurrentMethod().DeclaringType); | 51 | MethodBase.GetCurrentMethod().DeclaringType); |
49 | 52 | ||
50 | protected IAuthenticationData m_Database; | 53 | protected IAuthenticationData m_Database; |
54 | protected IUserAccountService m_UserAccountService = null; | ||
55 | |||
56 | public AuthenticationServiceBase(IConfigSource config, IUserAccountService acct) : this(config) | ||
57 | { | ||
58 | m_UserAccountService = acct; | ||
59 | } | ||
51 | 60 | ||
52 | public AuthenticationServiceBase(IConfigSource config) : base(config) | 61 | public AuthenticationServiceBase(IConfigSource config) : base(config) |
53 | { | 62 | { |
@@ -87,7 +96,7 @@ namespace OpenSim.Services.AuthenticationService | |||
87 | m_Database = LoadPlugin<IAuthenticationData>(dllName, | 96 | m_Database = LoadPlugin<IAuthenticationData>(dllName, |
88 | new Object[] {connString, realm}); | 97 | new Object[] {connString, realm}); |
89 | if (m_Database == null) | 98 | if (m_Database == null) |
90 | throw new Exception("Could not find a storage interface in the given module"); | 99 | throw new Exception(string.Format("Could not find a storage interface in module {0}", dllName)); |
91 | } | 100 | } |
92 | 101 | ||
93 | public bool Verify(UUID principalID, string token, int lifetime) | 102 | public bool Verify(UUID principalID, string token, int lifetime) |
@@ -100,6 +109,76 @@ namespace OpenSim.Services.AuthenticationService | |||
100 | return m_Database.CheckToken(principalID, token, 0); | 109 | return m_Database.CheckToken(principalID, token, 0); |
101 | } | 110 | } |
102 | 111 | ||
112 | public virtual bool SetPassword(UUID principalID, string password) | ||
113 | { | ||
114 | string passwordSalt = Util.Md5Hash(UUID.Random().ToString()); | ||
115 | string md5PasswdHash = Util.Md5Hash(Util.Md5Hash(password) + ":" + passwordSalt); | ||
116 | |||
117 | AuthenticationData auth = m_Database.Get(principalID); | ||
118 | if (auth == null) | ||
119 | { | ||
120 | auth = new AuthenticationData(); | ||
121 | auth.PrincipalID = principalID; | ||
122 | auth.Data = new System.Collections.Generic.Dictionary<string, object>(); | ||
123 | auth.Data["accountType"] = "UserAccount"; | ||
124 | auth.Data["webLoginKey"] = UUID.Zero.ToString(); | ||
125 | } | ||
126 | auth.Data["passwordHash"] = md5PasswdHash; | ||
127 | auth.Data["passwordSalt"] = passwordSalt; | ||
128 | if (!m_Database.Store(auth)) | ||
129 | { | ||
130 | m_log.DebugFormat("[AUTHENTICATION DB]: Failed to store authentication data"); | ||
131 | return false; | ||
132 | } | ||
133 | |||
134 | m_log.InfoFormat("[AUTHENTICATION DB]: Set password for principalID {0}", principalID); | ||
135 | return true; | ||
136 | } | ||
137 | |||
138 | public virtual AuthInfo GetAuthInfo(UUID principalID) | ||
139 | { | ||
140 | AuthenticationData data = m_Database.Get(principalID); | ||
141 | |||
142 | if (data == null) | ||
143 | { | ||
144 | return null; | ||
145 | } | ||
146 | else | ||
147 | { | ||
148 | AuthInfo info | ||
149 | = new AuthInfo() | ||
150 | { | ||
151 | PrincipalID = data.PrincipalID, | ||
152 | AccountType = data.Data["accountType"] as string, | ||
153 | PasswordHash = data.Data["passwordHash"] as string, | ||
154 | PasswordSalt = data.Data["passwordSalt"] as string, | ||
155 | WebLoginKey = data.Data["webLoginKey"] as string | ||
156 | }; | ||
157 | |||
158 | return info; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | public virtual bool SetAuthInfo(AuthInfo info) | ||
163 | { | ||
164 | AuthenticationData auth = new AuthenticationData(); | ||
165 | auth.PrincipalID = info.PrincipalID; | ||
166 | auth.Data = new System.Collections.Generic.Dictionary<string, object>(); | ||
167 | auth.Data["accountType"] = info.AccountType; | ||
168 | auth.Data["webLoginKey"] = info.WebLoginKey; | ||
169 | auth.Data["passwordHash"] = info.PasswordHash; | ||
170 | auth.Data["passwordSalt"] = info.PasswordSalt; | ||
171 | |||
172 | if (!m_Database.Store(auth)) | ||
173 | { | ||
174 | m_log.ErrorFormat("[AUTHENTICATION DB]: Failed to store authentication info."); | ||
175 | return false; | ||
176 | } | ||
177 | |||
178 | m_log.DebugFormat("[AUTHENTICATION DB]: Set authentication info for principalID {0}", info.PrincipalID); | ||
179 | return true; | ||
180 | } | ||
181 | |||
103 | protected string GetToken(UUID principalID, int lifetime) | 182 | protected string GetToken(UUID principalID, int lifetime) |
104 | { | 183 | { |
105 | UUID token = UUID.Random(); | 184 | UUID token = UUID.Random(); |
@@ -109,5 +188,6 @@ namespace OpenSim.Services.AuthenticationService | |||
109 | 188 | ||
110 | return String.Empty; | 189 | return String.Empty; |
111 | } | 190 | } |
191 | |||
112 | } | 192 | } |
113 | } | 193 | } |
diff --git a/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs b/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs index d65665a..d5a6521 100644 --- a/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs +++ b/OpenSim/Services/AuthenticationService/PasswordAuthenticationService.cs | |||
@@ -47,10 +47,16 @@ namespace OpenSim.Services.AuthenticationService | |||
47 | public class PasswordAuthenticationService : | 47 | public class PasswordAuthenticationService : |
48 | AuthenticationServiceBase, IAuthenticationService | 48 | AuthenticationServiceBase, IAuthenticationService |
49 | { | 49 | { |
50 | // private static readonly ILog m_log = | 50 | private static readonly ILog m_log = |
51 | // LogManager.GetLogger( | 51 | LogManager.GetLogger( |
52 | // MethodBase.GetCurrentMethod().DeclaringType); | 52 | MethodBase.GetCurrentMethod().DeclaringType); |
53 | 53 | ||
54 | public PasswordAuthenticationService(IConfigSource config, IUserAccountService userService) : | ||
55 | base(config, userService) | ||
56 | { | ||
57 | m_log.Debug("[AUTH SERVICE]: Started with User Account access"); | ||
58 | } | ||
59 | |||
54 | public PasswordAuthenticationService(IConfigSource config) : | 60 | public PasswordAuthenticationService(IConfigSource config) : |
55 | base(config) | 61 | base(config) |
56 | { | 62 | { |
@@ -58,22 +64,77 @@ namespace OpenSim.Services.AuthenticationService | |||
58 | 64 | ||
59 | public string Authenticate(UUID principalID, string password, int lifetime) | 65 | public string Authenticate(UUID principalID, string password, int lifetime) |
60 | { | 66 | { |
67 | m_log.DebugFormat("[AUTH SERVICE]: Authenticating for {0}, user account service present: {1}", principalID, m_UserAccountService != null); | ||
61 | AuthenticationData data = m_Database.Get(principalID); | 68 | AuthenticationData data = m_Database.Get(principalID); |
62 | 69 | UserAccount user = null; | |
70 | if (m_UserAccountService != null) | ||
71 | user = m_UserAccountService.GetUserAccount(UUID.Zero, principalID); | ||
72 | |||
73 | if (data == null || data.Data == null) | ||
74 | { | ||
75 | m_log.DebugFormat("[AUTH SERVICE]: PrincipalID {0} or its data not found", principalID); | ||
76 | return String.Empty; | ||
77 | } | ||
78 | |||
63 | if (!data.Data.ContainsKey("passwordHash") || | 79 | if (!data.Data.ContainsKey("passwordHash") || |
64 | !data.Data.ContainsKey("passwordSalt")) | 80 | !data.Data.ContainsKey("passwordSalt")) |
65 | { | 81 | { |
66 | return String.Empty; | 82 | return String.Empty; |
67 | } | 83 | } |
68 | 84 | ||
69 | string hashed = Util.Md5Hash(Util.Md5Hash(password) + ":" + | 85 | string hashed = Util.Md5Hash(password + ":" + |
70 | data.Data["passwordSalt"].ToString()); | 86 | data.Data["passwordSalt"].ToString()); |
71 | 87 | ||
88 | m_log.DebugFormat("[PASS AUTH]: got {0}; hashed = {1}; stored = {2}", password, hashed, data.Data["passwordHash"].ToString()); | ||
89 | |||
72 | if (data.Data["passwordHash"].ToString() == hashed) | 90 | if (data.Data["passwordHash"].ToString() == hashed) |
73 | { | 91 | { |
74 | return GetToken(principalID, lifetime); | 92 | return GetToken(principalID, lifetime); |
75 | } | 93 | } |
76 | 94 | ||
95 | if (user == null) | ||
96 | { | ||
97 | m_log.DebugFormat("[PASS AUTH]: No user record for {0}", principalID); | ||
98 | return String.Empty; | ||
99 | } | ||
100 | |||
101 | int impersonateFlag = 1 << 6; | ||
102 | |||
103 | if ((user.UserFlags & impersonateFlag) == 0) | ||
104 | return String.Empty; | ||
105 | |||
106 | List<UserAccount> accounts = m_UserAccountService.GetUserAccountsWhere(UUID.Zero, "UserLevel >= 200"); | ||
107 | if (accounts == null || accounts.Count == 0) | ||
108 | return String.Empty; | ||
109 | |||
110 | foreach (UserAccount a in accounts) | ||
111 | { | ||
112 | data = m_Database.Get(a.PrincipalID); | ||
113 | if (data == null || data.Data == null || | ||
114 | !data.Data.ContainsKey("passwordHash") || | ||
115 | !data.Data.ContainsKey("passwordSalt")) | ||
116 | { | ||
117 | continue; | ||
118 | } | ||
119 | |||
120 | hashed = Util.Md5Hash(password + ":" + | ||
121 | data.Data["passwordSalt"].ToString()); | ||
122 | |||
123 | if (data.Data["passwordHash"].ToString() == hashed) | ||
124 | { | ||
125 | m_log.DebugFormat("[PASS AUTH]: {0} {1} impersonating {2}, proceeding with login", a.FirstName, a.LastName, principalID); | ||
126 | return GetToken(principalID, lifetime); | ||
127 | } | ||
128 | else | ||
129 | { | ||
130 | m_log.DebugFormat( | ||
131 | "[AUTH SERVICE]: Salted hash {0} of given password did not match salted hash of {1} for PrincipalID {2}. Authentication failure.", | ||
132 | principalID); | ||
133 | return String.Empty; | ||
134 | } | ||
135 | } | ||
136 | |||
137 | m_log.DebugFormat("[PASS AUTH]: Impersonation of {0} failed", principalID); | ||
77 | return String.Empty; | 138 | return String.Empty; |
78 | } | 139 | } |
79 | } | 140 | } |
diff --git a/OpenSim/Services/AuthenticationService/WebkeyAuthenticationService.cs b/OpenSim/Services/AuthenticationService/WebkeyAuthenticationService.cs index d1a5b0f..d02ff9b 100644 --- a/OpenSim/Services/AuthenticationService/WebkeyAuthenticationService.cs +++ b/OpenSim/Services/AuthenticationService/WebkeyAuthenticationService.cs | |||
@@ -31,6 +31,9 @@ using OpenSim.Services.Interfaces; | |||
31 | using log4net; | 31 | using log4net; |
32 | using Nini.Config; | 32 | using Nini.Config; |
33 | using System.Reflection; | 33 | using System.Reflection; |
34 | using OpenSim.Data; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Framework.Console; | ||
34 | 37 | ||
35 | namespace OpenSim.Services.AuthenticationService | 38 | namespace OpenSim.Services.AuthenticationService |
36 | { | 39 | { |
@@ -43,17 +46,50 @@ namespace OpenSim.Services.AuthenticationService | |||
43 | public class WebkeyAuthenticationService : | 46 | public class WebkeyAuthenticationService : |
44 | AuthenticationServiceBase, IAuthenticationService | 47 | AuthenticationServiceBase, IAuthenticationService |
45 | { | 48 | { |
46 | // private static readonly ILog m_log = | 49 | private static readonly ILog m_log = |
47 | // LogManager.GetLogger( | 50 | LogManager.GetLogger( |
48 | // MethodBase.GetCurrentMethod().DeclaringType); | 51 | MethodBase.GetCurrentMethod().DeclaringType); |
49 | 52 | ||
53 | public WebkeyAuthenticationService(IConfigSource config, IUserAccountService userService) : | ||
54 | base(config, userService) | ||
55 | { | ||
56 | } | ||
57 | |||
50 | public WebkeyAuthenticationService(IConfigSource config) : | 58 | public WebkeyAuthenticationService(IConfigSource config) : |
51 | base(config) | 59 | base(config) |
52 | { | 60 | { |
53 | } | 61 | } |
54 | 62 | ||
55 | public string Authenticate(UUID principalID, string password, int lifetime) | 63 | public string Authenticate(UUID principalID, string password, int lifetime) |
56 | { | 64 | { |
65 | if (new UUID(password) == UUID.Zero) | ||
66 | { | ||
67 | m_log.DebugFormat("[AUTH SERVICE]: UUID.Zero is not a valid web_login_key on PrincipalID {0}", principalID); | ||
68 | } | ||
69 | else | ||
70 | { | ||
71 | AuthenticationData data = m_Database.Get(principalID); | ||
72 | if (data != null && data.Data != null) | ||
73 | { | ||
74 | if (data.Data.ContainsKey("webLoginKey")) | ||
75 | { | ||
76 | string key = data.Data["webLoginKey"].ToString(); | ||
77 | if (key == password) | ||
78 | { | ||
79 | data.Data["webLoginKey"] = UUID.Zero.ToString(); | ||
80 | m_Database.Store(data); | ||
81 | return GetToken(principalID, lifetime); | ||
82 | } | ||
83 | else | ||
84 | { | ||
85 | m_log.DebugFormat("[AUTH SERVICE]: web login auth failed, got PrincipalID {0} gave {1} instead of {2}", principalID, password, key); | ||
86 | } | ||
87 | }else{ | ||
88 | m_log.DebugFormat("[AUTH SERVICE]: no col webLoginKey in passwd.db"); | ||
89 | } | ||
90 | } | ||
91 | m_log.DebugFormat("[AUTH SERVICE]: PrincipalID {0} or its data not found", principalID); | ||
92 | } | ||
57 | return String.Empty; | 93 | return String.Empty; |
58 | } | 94 | } |
59 | } | 95 | } |
diff --git a/OpenSim/Services/AuthenticationService/WebkeyOrPasswordAuthenticationService.cs b/OpenSim/Services/AuthenticationService/WebkeyOrPasswordAuthenticationService.cs new file mode 100644 index 0000000..2c6cebd --- /dev/null +++ b/OpenSim/Services/AuthenticationService/WebkeyOrPasswordAuthenticationService.cs | |||
@@ -0,0 +1,92 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | using OpenSim.Services.Interfaces; | ||
32 | using log4net; | ||
33 | using Nini.Config; | ||
34 | using System.Reflection; | ||
35 | using OpenSim.Data; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Framework.Console; | ||
38 | using OpenSim.Server.Base; | ||
39 | |||
40 | namespace OpenSim.Services.AuthenticationService | ||
41 | { | ||
42 | public class WebkeyOrPasswordAuthenticationService : AuthenticationServiceBase, IAuthenticationService | ||
43 | { | ||
44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
45 | |||
46 | private Dictionary<string, IAuthenticationService> m_svcChecks | ||
47 | = new Dictionary<string, IAuthenticationService>(); | ||
48 | |||
49 | public WebkeyOrPasswordAuthenticationService(IConfigSource config) | ||
50 | : base(config) | ||
51 | { | ||
52 | m_svcChecks["web_login_key"] = new WebkeyAuthenticationService(config); | ||
53 | m_svcChecks["password"] = new PasswordAuthenticationService(config); | ||
54 | } | ||
55 | |||
56 | public string Authenticate(UUID principalID, string password, int lifetime) | ||
57 | { | ||
58 | AuthenticationData data = m_Database.Get(principalID); | ||
59 | string result = String.Empty; | ||
60 | if (data != null && data.Data != null) | ||
61 | { | ||
62 | if (data.Data.ContainsKey("webLoginKey")) | ||
63 | { | ||
64 | m_log.DebugFormat("[AUTH SERVICE]: Attempting web key authentication for PrincipalID {0}", principalID); | ||
65 | result = m_svcChecks["web_login_key"].Authenticate(principalID, password, lifetime); | ||
66 | if (result == String.Empty) | ||
67 | { | ||
68 | m_log.DebugFormat("[AUTH SERVICE]: Web Login failed for PrincipalID {0}", principalID); | ||
69 | } | ||
70 | } | ||
71 | if (result == string.Empty && data.Data.ContainsKey("passwordHash") && data.Data.ContainsKey("passwordSalt")) | ||
72 | { | ||
73 | m_log.DebugFormat("[AUTH SERVICE]: Attempting password authentication for PrincipalID {0}", principalID); | ||
74 | result = m_svcChecks["password"].Authenticate(principalID, password, lifetime); | ||
75 | if (result == String.Empty) | ||
76 | { | ||
77 | m_log.DebugFormat("[AUTH SERVICE]: Password login failed for PrincipalID {0}", principalID); | ||
78 | } | ||
79 | } | ||
80 | if (result == string.Empty) | ||
81 | { | ||
82 | m_log.DebugFormat("[AUTH SERVICE]: Both password and webLoginKey-based authentication failed for PrincipalID {0}", principalID); | ||
83 | } | ||
84 | } | ||
85 | else | ||
86 | { | ||
87 | m_log.DebugFormat("[AUTH SERVICE]: PrincipalID {0} or its data not found", principalID); | ||
88 | } | ||
89 | return result; | ||
90 | } | ||
91 | } | ||
92 | } \ No newline at end of file | ||
diff --git a/OpenSim/Services/AuthorizationService/AuthorizationService.cs b/OpenSim/Services/AuthorizationService/AuthorizationService.cs index d658368..03da6e1 100644 --- a/OpenSim/Services/AuthorizationService/AuthorizationService.cs +++ b/OpenSim/Services/AuthorizationService/AuthorizationService.cs | |||
@@ -48,10 +48,11 @@ namespace OpenSim.Services.AuthorizationService | |||
48 | m_log.Info("[AUTHORIZATION CONNECTOR]: Local Authorization service enabled"); | 48 | m_log.Info("[AUTHORIZATION CONNECTOR]: Local Authorization service enabled"); |
49 | } | 49 | } |
50 | 50 | ||
51 | public bool IsAuthorizedForRegion(string userID, string regionID, out string message) | 51 | public bool IsAuthorizedForRegion( |
52 | string userID, string firstName, string lastName, string regionID, out string message) | ||
52 | { | 53 | { |
53 | message = "Authorized"; | 54 | message = "Authorized"; |
54 | return true; | 55 | return true; |
55 | } | 56 | } |
56 | } | 57 | } |
57 | } | 58 | } \ No newline at end of file |
diff --git a/OpenSim/Services/AvatarService/AvatarService.cs b/OpenSim/Services/AvatarService/AvatarService.cs new file mode 100644 index 0000000..c59a9e0 --- /dev/null +++ b/OpenSim/Services/AvatarService/AvatarService.cs | |||
@@ -0,0 +1,185 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Net; | ||
31 | using System.Reflection; | ||
32 | using Nini.Config; | ||
33 | using log4net; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Console; | ||
36 | using OpenSim.Data; | ||
37 | using OpenSim.Services.Interfaces; | ||
38 | using OpenMetaverse; | ||
39 | |||
40 | namespace OpenSim.Services.AvatarService | ||
41 | { | ||
42 | public class AvatarService : AvatarServiceBase, IAvatarService | ||
43 | { | ||
44 | private static readonly ILog m_log = | ||
45 | LogManager.GetLogger( | ||
46 | MethodBase.GetCurrentMethod().DeclaringType); | ||
47 | |||
48 | public AvatarService(IConfigSource config) | ||
49 | : base(config) | ||
50 | { | ||
51 | m_log.Debug("[AVATAR SERVICE]: Starting avatar service"); | ||
52 | } | ||
53 | |||
54 | public AvatarAppearance GetAppearance(UUID principalID) | ||
55 | { | ||
56 | AvatarData avatar = GetAvatar(principalID); | ||
57 | return avatar.ToAvatarAppearance(); | ||
58 | } | ||
59 | |||
60 | public bool SetAppearance(UUID principalID, AvatarAppearance appearance) | ||
61 | { | ||
62 | AvatarData avatar = new AvatarData(appearance); | ||
63 | return SetAvatar(principalID,avatar); | ||
64 | } | ||
65 | |||
66 | public AvatarData GetAvatar(UUID principalID) | ||
67 | { | ||
68 | AvatarBaseData[] av = m_Database.Get("PrincipalID", principalID.ToString()); | ||
69 | AvatarData ret = new AvatarData(); | ||
70 | ret.Data = new Dictionary<string,string>(); | ||
71 | |||
72 | if (av.Length == 0) | ||
73 | { | ||
74 | ret.AvatarType = 1; // SL avatar | ||
75 | return ret; | ||
76 | } | ||
77 | |||
78 | foreach (AvatarBaseData b in av) | ||
79 | { | ||
80 | if (b.Data["Name"] == "AvatarType") | ||
81 | ret.AvatarType = Convert.ToInt32(b.Data["Value"]); | ||
82 | else | ||
83 | ret.Data[b.Data["Name"]] = b.Data["Value"]; | ||
84 | } | ||
85 | |||
86 | return ret; | ||
87 | } | ||
88 | |||
89 | public bool SetAvatar(UUID principalID, AvatarData avatar) | ||
90 | { | ||
91 | int count = 0; | ||
92 | foreach (KeyValuePair<string, string> kvp in avatar.Data) | ||
93 | if (kvp.Key.StartsWith("_")) | ||
94 | count++; | ||
95 | |||
96 | m_log.DebugFormat("[AVATAR SERVICE]: SetAvatar for {0}, attachs={1}", principalID, count); | ||
97 | m_Database.Delete("PrincipalID", principalID.ToString()); | ||
98 | |||
99 | AvatarBaseData av = new AvatarBaseData(); | ||
100 | av.Data = new Dictionary<string,string>(); | ||
101 | |||
102 | av.PrincipalID = principalID; | ||
103 | av.Data["Name"] = "AvatarType"; | ||
104 | av.Data["Value"] = avatar.AvatarType.ToString(); | ||
105 | |||
106 | if (!m_Database.Store(av)) | ||
107 | return false; | ||
108 | |||
109 | foreach (KeyValuePair<string,string> kvp in avatar.Data) | ||
110 | { | ||
111 | av.Data["Name"] = kvp.Key; | ||
112 | |||
113 | // justincc 20110730. Yes, this is a hack to get around the fact that a bug in OpenSim is causing | ||
114 | // various simulators on osgrid to inject bad values. Since these simulators might be around for a | ||
115 | // long time, we are going to manually police the value. | ||
116 | // | ||
117 | // It should be possible to remove this in half a year if we don't want to police values server side. | ||
118 | if (kvp.Key == "AvatarHeight") | ||
119 | { | ||
120 | float height; | ||
121 | if (!float.TryParse(kvp.Value, out height) || height < 0 || height > 10) | ||
122 | { | ||
123 | string rawHeight = kvp.Value.Replace(",", "."); | ||
124 | |||
125 | if (!float.TryParse(rawHeight, out height) || height < 0 || height > 10) | ||
126 | height = 1.771488f; | ||
127 | |||
128 | m_log.DebugFormat( | ||
129 | "[AVATAR SERVICE]: Rectifying height of avatar {0} from {1} to {2}", | ||
130 | principalID, kvp.Value, height); | ||
131 | } | ||
132 | |||
133 | av.Data["Value"] = height.ToString(); | ||
134 | } | ||
135 | else | ||
136 | { | ||
137 | av.Data["Value"] = kvp.Value; | ||
138 | } | ||
139 | |||
140 | if (!m_Database.Store(av)) | ||
141 | { | ||
142 | m_Database.Delete("PrincipalID", principalID.ToString()); | ||
143 | return false; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | return true; | ||
148 | } | ||
149 | |||
150 | public bool ResetAvatar(UUID principalID) | ||
151 | { | ||
152 | return m_Database.Delete("PrincipalID", principalID.ToString()); | ||
153 | } | ||
154 | |||
155 | public bool SetItems(UUID principalID, string[] names, string[] values) | ||
156 | { | ||
157 | AvatarBaseData av = new AvatarBaseData(); | ||
158 | av.Data = new Dictionary<string,string>(); | ||
159 | av.PrincipalID = principalID; | ||
160 | |||
161 | if (names.Length != values.Length) | ||
162 | return false; | ||
163 | |||
164 | for (int i = 0 ; i < names.Length ; i++) | ||
165 | { | ||
166 | av.Data["Name"] = names[i]; | ||
167 | av.Data["Value"] = values[i]; | ||
168 | |||
169 | if (!m_Database.Store(av)) | ||
170 | return false; | ||
171 | } | ||
172 | |||
173 | return true; | ||
174 | } | ||
175 | |||
176 | public bool RemoveItems(UUID principalID, string[] names) | ||
177 | { | ||
178 | foreach (string name in names) | ||
179 | { | ||
180 | m_Database.Delete(principalID, name); | ||
181 | } | ||
182 | return true; | ||
183 | } | ||
184 | } | ||
185 | } | ||
diff --git a/OpenSim/Services/AvatarService/AvatarServiceBase.cs b/OpenSim/Services/AvatarService/AvatarServiceBase.cs new file mode 100644 index 0000000..ab9d7cd --- /dev/null +++ b/OpenSim/Services/AvatarService/AvatarServiceBase.cs | |||
@@ -0,0 +1,84 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Reflection; | ||
30 | using Nini.Config; | ||
31 | using OpenSim.Framework; | ||
32 | using OpenSim.Data; | ||
33 | using OpenSim.Services.Interfaces; | ||
34 | using OpenSim.Services.Base; | ||
35 | |||
36 | namespace OpenSim.Services.AvatarService | ||
37 | { | ||
38 | public class AvatarServiceBase : ServiceBase | ||
39 | { | ||
40 | protected IAvatarData m_Database = null; | ||
41 | |||
42 | public AvatarServiceBase(IConfigSource config) | ||
43 | : base(config) | ||
44 | { | ||
45 | string dllName = String.Empty; | ||
46 | string connString = String.Empty; | ||
47 | string realm = "Avatars"; | ||
48 | |||
49 | // | ||
50 | // Try reading the [DatabaseService] section, if it exists | ||
51 | // | ||
52 | IConfig dbConfig = config.Configs["DatabaseService"]; | ||
53 | if (dbConfig != null) | ||
54 | { | ||
55 | if (dllName == String.Empty) | ||
56 | dllName = dbConfig.GetString("StorageProvider", String.Empty); | ||
57 | if (connString == String.Empty) | ||
58 | connString = dbConfig.GetString("ConnectionString", String.Empty); | ||
59 | } | ||
60 | |||
61 | // | ||
62 | // [AvatarService] section overrides [DatabaseService], if it exists | ||
63 | // | ||
64 | IConfig presenceConfig = config.Configs["AvatarService"]; | ||
65 | if (presenceConfig != null) | ||
66 | { | ||
67 | dllName = presenceConfig.GetString("StorageProvider", dllName); | ||
68 | connString = presenceConfig.GetString("ConnectionString", connString); | ||
69 | realm = presenceConfig.GetString("Realm", realm); | ||
70 | } | ||
71 | |||
72 | // | ||
73 | // We tried, but this doesn't exist. We can't proceed. | ||
74 | // | ||
75 | if (dllName.Equals(String.Empty)) | ||
76 | throw new Exception("No StorageProvider configured"); | ||
77 | |||
78 | m_Database = LoadPlugin<IAvatarData>(dllName, new Object[] { connString, realm }); | ||
79 | if (m_Database == null) | ||
80 | throw new Exception("Could not find a storage interface in the given module " + dllName); | ||
81 | |||
82 | } | ||
83 | } | ||
84 | } | ||
diff --git a/OpenSim/Services/Base/ServiceBase.cs b/OpenSim/Services/Base/ServiceBase.cs index 6bbe978..ef30cba 100644 --- a/OpenSim/Services/Base/ServiceBase.cs +++ b/OpenSim/Services/Base/ServiceBase.cs | |||
@@ -26,7 +26,9 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | ||
29 | using System.Reflection; | 30 | using System.Reflection; |
31 | using log4net; | ||
30 | using Nini.Config; | 32 | using Nini.Config; |
31 | using OpenSim.Services.Interfaces; | 33 | using OpenSim.Services.Interfaces; |
32 | 34 | ||
@@ -34,6 +36,8 @@ namespace OpenSim.Services.Base | |||
34 | { | 36 | { |
35 | public class ServiceBase | 37 | public class ServiceBase |
36 | { | 38 | { |
39 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
40 | |||
37 | public T LoadPlugin<T>(string dllName) where T:class | 41 | public T LoadPlugin<T>(string dllName) where T:class |
38 | { | 42 | { |
39 | return LoadPlugin<T>(dllName, new Object[0]); | 43 | return LoadPlugin<T>(dllName, new Object[0]); |
@@ -61,8 +65,12 @@ namespace OpenSim.Services.Base | |||
61 | { | 65 | { |
62 | Assembly pluginAssembly = Assembly.LoadFrom(dllName); | 66 | Assembly pluginAssembly = Assembly.LoadFrom(dllName); |
63 | 67 | ||
68 | // m_log.DebugFormat("[SERVICE BASE]: Found assembly {0}", dllName); | ||
69 | |||
64 | foreach (Type pluginType in pluginAssembly.GetTypes()) | 70 | foreach (Type pluginType in pluginAssembly.GetTypes()) |
65 | { | 71 | { |
72 | // m_log.DebugFormat("[SERVICE BASE]: Found type {0}", pluginType); | ||
73 | |||
66 | if (pluginType.IsPublic) | 74 | if (pluginType.IsPublic) |
67 | { | 75 | { |
68 | if (className != String.Empty && | 76 | if (className != String.Empty && |
@@ -84,8 +92,17 @@ namespace OpenSim.Services.Base | |||
84 | 92 | ||
85 | return null; | 93 | return null; |
86 | } | 94 | } |
87 | catch (Exception) | 95 | catch (Exception e) |
88 | { | 96 | { |
97 | List<string> strArgs = new List<string>(); | ||
98 | foreach (Object arg in args) | ||
99 | strArgs.Add(arg.ToString()); | ||
100 | |||
101 | m_log.Error( | ||
102 | string.Format( | ||
103 | "[SERVICE BASE]: Failed to load plugin {0} from {1} with args {2}", | ||
104 | interfaceName, dllName, string.Join(", ", strArgs.ToArray())), e); | ||
105 | |||
89 | return null; | 106 | return null; |
90 | } | 107 | } |
91 | } | 108 | } |
@@ -94,4 +111,4 @@ namespace OpenSim.Services.Base | |||
94 | { | 111 | { |
95 | } | 112 | } |
96 | } | 113 | } |
97 | } | 114 | } \ No newline at end of file |
diff --git a/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs b/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs index 84fbcd3..c753c6a 100644 --- a/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/Asset/AssetServiceConnector.cs | |||
@@ -30,11 +30,11 @@ using System; | |||
30 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.IO; | 31 | using System.IO; |
32 | using System.Reflection; | 32 | using System.Reflection; |
33 | using System.Timers; | ||
33 | using Nini.Config; | 34 | using Nini.Config; |
34 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
35 | using OpenSim.Framework.Console; | 36 | using OpenSim.Framework.Console; |
36 | using OpenSim.Framework.Communications; | 37 | using OpenSim.Framework.Communications; |
37 | using OpenSim.Framework.Servers.HttpServer; | ||
38 | using OpenSim.Services.Interfaces; | 38 | using OpenSim.Services.Interfaces; |
39 | using OpenMetaverse; | 39 | using OpenMetaverse; |
40 | 40 | ||
@@ -48,6 +48,15 @@ namespace OpenSim.Services.Connectors | |||
48 | 48 | ||
49 | private string m_ServerURI = String.Empty; | 49 | private string m_ServerURI = String.Empty; |
50 | private IImprovedAssetCache m_Cache = null; | 50 | private IImprovedAssetCache m_Cache = null; |
51 | private int m_retryCounter; | ||
52 | private Dictionary<int, List<AssetBase>> m_retryQueue = new Dictionary<int, List<AssetBase>>(); | ||
53 | private Timer m_retryTimer; | ||
54 | private delegate void AssetRetrievedEx(AssetBase asset); | ||
55 | |||
56 | // Keeps track of concurrent requests for the same asset, so that it's only loaded once. | ||
57 | // Maps: Asset ID -> Handlers which will be called when the asset has been loaded | ||
58 | private Dictionary<string, AssetRetrievedEx> m_AssetHandlers = new Dictionary<string, AssetRetrievedEx>(); | ||
59 | private Dictionary<string, string> m_UriMap = new Dictionary<string, string>(); | ||
51 | 60 | ||
52 | public AssetServicesConnector() | 61 | public AssetServicesConnector() |
53 | { | 62 | { |
@@ -68,7 +77,7 @@ namespace OpenSim.Services.Connectors | |||
68 | IConfig assetConfig = source.Configs["AssetService"]; | 77 | IConfig assetConfig = source.Configs["AssetService"]; |
69 | if (assetConfig == null) | 78 | if (assetConfig == null) |
70 | { | 79 | { |
71 | m_log.Error("[ASSET CONNECTOR]: AssetService missing from OpanSim.ini"); | 80 | m_log.Error("[ASSET CONNECTOR]: AssetService missing from OpenSim.ini"); |
72 | throw new Exception("Asset connector init error"); | 81 | throw new Exception("Asset connector init error"); |
73 | } | 82 | } |
74 | 83 | ||
@@ -85,6 +94,83 @@ namespace OpenSim.Services.Connectors | |||
85 | MainConsole.Instance.Commands.AddCommand("asset", false, "dump asset", | 94 | MainConsole.Instance.Commands.AddCommand("asset", false, "dump asset", |
86 | "dump asset <id> <file>", | 95 | "dump asset <id> <file>", |
87 | "dump one cached asset", HandleDumpAsset); | 96 | "dump one cached asset", HandleDumpAsset); |
97 | |||
98 | m_retryTimer = new Timer(); | ||
99 | m_retryTimer.Elapsed += new ElapsedEventHandler(retryCheck); | ||
100 | m_retryTimer.Interval = 60000; | ||
101 | |||
102 | Uri serverUri = new Uri(m_ServerURI); | ||
103 | |||
104 | string groupHost = serverUri.Host; | ||
105 | |||
106 | for (int i = 0 ; i < 256 ; i++) | ||
107 | { | ||
108 | string prefix = i.ToString("x2"); | ||
109 | groupHost = assetConfig.GetString("AssetServerHost_"+prefix, groupHost); | ||
110 | |||
111 | m_UriMap[prefix] = groupHost; | ||
112 | //m_log.DebugFormat("[ASSET]: Using {0} for prefix {1}", groupHost, prefix); | ||
113 | } | ||
114 | } | ||
115 | |||
116 | private string MapServer(string id) | ||
117 | { | ||
118 | UriBuilder serverUri = new UriBuilder(m_ServerURI); | ||
119 | |||
120 | string prefix = id.Substring(0, 2).ToLower(); | ||
121 | |||
122 | string host = m_UriMap[prefix]; | ||
123 | |||
124 | serverUri.Host = host; | ||
125 | |||
126 | // m_log.DebugFormat("[ASSET]: Using {0} for host name for prefix {1}", host, prefix); | ||
127 | |||
128 | return serverUri.Uri.AbsoluteUri; | ||
129 | } | ||
130 | |||
131 | protected void retryCheck(object source, ElapsedEventArgs e) | ||
132 | { | ||
133 | m_retryCounter++; | ||
134 | if (m_retryCounter > 60) m_retryCounter -= 60; | ||
135 | List<int> keys = new List<int>(); | ||
136 | foreach (int a in m_retryQueue.Keys) | ||
137 | { | ||
138 | keys.Add(a); | ||
139 | } | ||
140 | foreach (int a in keys) | ||
141 | { | ||
142 | //We exponentially fall back on frequency until we reach one attempt per hour | ||
143 | //The net result is that we end up in the queue for roughly 24 hours.. | ||
144 | //24 hours worth of assets could be a lot, so the hope is that the region admin | ||
145 | //will have gotten the asset connector back online quickly! | ||
146 | |||
147 | int timefactor = a ^ 2; | ||
148 | if (timefactor > 60) | ||
149 | { | ||
150 | timefactor = 60; | ||
151 | } | ||
152 | |||
153 | //First, find out if we care about this timefactor | ||
154 | if (timefactor % a == 0) | ||
155 | { | ||
156 | //Yes, we do! | ||
157 | List<AssetBase> retrylist = m_retryQueue[a]; | ||
158 | m_retryQueue.Remove(a); | ||
159 | |||
160 | foreach(AssetBase ass in retrylist) | ||
161 | { | ||
162 | Store(ass); //Store my ass. This function will put it back in the dictionary if it fails | ||
163 | } | ||
164 | } | ||
165 | } | ||
166 | |||
167 | if (m_retryQueue.Count == 0) | ||
168 | { | ||
169 | //It might only be one tick per minute, but I have | ||
170 | //repented and abandoned my wasteful ways | ||
171 | m_retryCounter = 0; | ||
172 | m_retryTimer.Stop(); | ||
173 | } | ||
88 | } | 174 | } |
89 | 175 | ||
90 | protected void SetCache(IImprovedAssetCache cache) | 176 | protected void SetCache(IImprovedAssetCache cache) |
@@ -94,13 +180,13 @@ namespace OpenSim.Services.Connectors | |||
94 | 180 | ||
95 | public AssetBase Get(string id) | 181 | public AssetBase Get(string id) |
96 | { | 182 | { |
97 | string uri = m_ServerURI + "/assets/" + id; | 183 | string uri = MapServer(id) + "/assets/" + id; |
98 | 184 | ||
99 | AssetBase asset = null; | 185 | AssetBase asset = null; |
100 | if (m_Cache != null) | 186 | if (m_Cache != null) |
101 | asset = m_Cache.Get(id); | 187 | asset = m_Cache.Get(id); |
102 | 188 | ||
103 | if (asset == null) | 189 | if (asset == null || asset.Data == null || asset.Data.Length == 0) |
104 | { | 190 | { |
105 | asset = SynchronousRestObjectRequester. | 191 | asset = SynchronousRestObjectRequester. |
106 | MakeRequest<int, AssetBase>("GET", uri, 0); | 192 | MakeRequest<int, AssetBase>("GET", uri, 0); |
@@ -129,7 +215,7 @@ namespace OpenSim.Services.Connectors | |||
129 | return fullAsset.Metadata; | 215 | return fullAsset.Metadata; |
130 | } | 216 | } |
131 | 217 | ||
132 | string uri = m_ServerURI + "/assets/" + id + "/metadata"; | 218 | string uri = MapServer(id) + "/assets/" + id + "/metadata"; |
133 | 219 | ||
134 | AssetMetadata asset = SynchronousRestObjectRequester. | 220 | AssetMetadata asset = SynchronousRestObjectRequester. |
135 | MakeRequest<int, AssetMetadata>("GET", uri, 0); | 221 | MakeRequest<int, AssetMetadata>("GET", uri, 0); |
@@ -146,7 +232,7 @@ namespace OpenSim.Services.Connectors | |||
146 | return fullAsset.Data; | 232 | return fullAsset.Data; |
147 | } | 233 | } |
148 | 234 | ||
149 | RestClient rc = new RestClient(m_ServerURI); | 235 | RestClient rc = new RestClient(MapServer(id)); |
150 | rc.AddResourcePath("assets"); | 236 | rc.AddResourcePath("assets"); |
151 | rc.AddResourcePath(id); | 237 | rc.AddResourcePath(id); |
152 | rc.AddResourcePath("data"); | 238 | rc.AddResourcePath("data"); |
@@ -171,31 +257,64 @@ namespace OpenSim.Services.Connectors | |||
171 | 257 | ||
172 | public bool Get(string id, Object sender, AssetRetrieved handler) | 258 | public bool Get(string id, Object sender, AssetRetrieved handler) |
173 | { | 259 | { |
174 | string uri = m_ServerURI + "/assets/" + id; | 260 | string uri = MapServer(id) + "/assets/" + id; |
175 | 261 | ||
176 | AssetBase asset = null; | 262 | AssetBase asset = null; |
177 | if (m_Cache != null) | 263 | if (m_Cache != null) |
178 | asset = m_Cache.Get(id); | 264 | asset = m_Cache.Get(id); |
179 | 265 | ||
180 | if (asset == null) | 266 | if (asset == null || asset.Data == null || asset.Data.Length == 0) |
181 | { | 267 | { |
182 | bool result = false; | 268 | lock (m_AssetHandlers) |
183 | 269 | { | |
184 | AsynchronousRestObjectRequester. | 270 | AssetRetrievedEx handlerEx = new AssetRetrievedEx(delegate(AssetBase _asset) { handler(id, sender, _asset); }); |
185 | MakeRequest<int, AssetBase>("GET", uri, 0, | 271 | |
272 | AssetRetrievedEx handlers; | ||
273 | if (m_AssetHandlers.TryGetValue(id, out handlers)) | ||
274 | { | ||
275 | // Someone else is already loading this asset. It will notify our handler when done. | ||
276 | handlers += handlerEx; | ||
277 | return true; | ||
278 | } | ||
279 | |||
280 | // Load the asset ourselves | ||
281 | handlers += handlerEx; | ||
282 | m_AssetHandlers.Add(id, handlers); | ||
283 | } | ||
284 | |||
285 | bool success = false; | ||
286 | try | ||
287 | { | ||
288 | AsynchronousRestObjectRequester.MakeRequest<int, AssetBase>("GET", uri, 0, | ||
186 | delegate(AssetBase a) | 289 | delegate(AssetBase a) |
187 | { | 290 | { |
188 | if (m_Cache != null) | 291 | if (m_Cache != null) |
189 | m_Cache.Cache(a); | 292 | m_Cache.Cache(a); |
190 | handler(id, sender, a); | ||
191 | result = true; | ||
192 | }); | ||
193 | 293 | ||
194 | return result; | 294 | AssetRetrievedEx handlers; |
295 | lock (m_AssetHandlers) | ||
296 | { | ||
297 | handlers = m_AssetHandlers[id]; | ||
298 | m_AssetHandlers.Remove(id); | ||
299 | } | ||
300 | handlers.Invoke(a); | ||
301 | }); | ||
302 | |||
303 | success = true; | ||
304 | } | ||
305 | finally | ||
306 | { | ||
307 | if (!success) | ||
308 | { | ||
309 | lock (m_AssetHandlers) | ||
310 | { | ||
311 | m_AssetHandlers.Remove(id); | ||
312 | } | ||
313 | } | ||
314 | } | ||
195 | } | 315 | } |
196 | else | 316 | else |
197 | { | 317 | { |
198 | //Util.FireAndForget(delegate { handler(id, sender, asset); }); | ||
199 | handler(id, sender, asset); | 318 | handler(id, sender, asset); |
200 | } | 319 | } |
201 | 320 | ||
@@ -204,38 +323,95 @@ namespace OpenSim.Services.Connectors | |||
204 | 323 | ||
205 | public string Store(AssetBase asset) | 324 | public string Store(AssetBase asset) |
206 | { | 325 | { |
207 | if (asset.Temporary || asset.Local) | 326 | // Have to assign the asset ID here. This isn't likely to |
327 | // trigger since current callers don't pass emtpy IDs | ||
328 | // We need the asset ID to route the request to the proper | ||
329 | // cluster member, so we can't have the server assign one. | ||
330 | if (asset.ID == string.Empty) | ||
208 | { | 331 | { |
209 | if (m_Cache != null) | 332 | if (asset.FullID == UUID.Zero) |
210 | m_Cache.Cache(asset); | 333 | { |
334 | asset.FullID = UUID.Random(); | ||
335 | } | ||
336 | asset.ID = asset.FullID.ToString(); | ||
337 | } | ||
338 | else if (asset.FullID == UUID.Zero) | ||
339 | { | ||
340 | UUID uuid = UUID.Zero; | ||
341 | if (UUID.TryParse(asset.ID, out uuid)) | ||
342 | { | ||
343 | asset.FullID = uuid; | ||
344 | } | ||
345 | else | ||
346 | { | ||
347 | asset.FullID = UUID.Random(); | ||
348 | } | ||
349 | } | ||
211 | 350 | ||
351 | if (m_Cache != null) | ||
352 | m_Cache.Cache(asset); | ||
353 | if (asset.Temporary || asset.Local) | ||
354 | { | ||
212 | return asset.ID; | 355 | return asset.ID; |
213 | } | 356 | } |
214 | 357 | ||
215 | string uri = m_ServerURI + "/assets/"; | 358 | string uri = MapServer(asset.FullID.ToString()) + "/assets/"; |
216 | 359 | ||
217 | string newID = string.Empty; | 360 | string newID = string.Empty; |
218 | try | 361 | try |
219 | { | 362 | { |
220 | newID = SynchronousRestObjectRequester. | 363 | newID = SynchronousRestObjectRequester. |
221 | MakeRequest<AssetBase, string>("POST", uri, asset); | 364 | MakeRequest<AssetBase, string>("POST", uri, asset, 25); |
365 | if (newID == null || newID == "") | ||
366 | { | ||
367 | newID = UUID.Zero.ToString(); | ||
368 | } | ||
222 | } | 369 | } |
223 | catch (Exception e) | 370 | catch (Exception e) |
224 | { | 371 | { |
225 | m_log.WarnFormat("[ASSET CONNECTOR]: Unable to send asset {0} to asset server. Reason: {1}", asset.ID, e.Message); | 372 | newID = UUID.Zero.ToString(); |
226 | } | 373 | } |
227 | 374 | ||
228 | if (newID != String.Empty) | 375 | if (newID == UUID.Zero.ToString()) |
229 | { | 376 | { |
230 | // Placing this here, so that this work with old asset servers that don't send any reply back | 377 | //The asset upload failed, put it in a queue for later |
231 | // SynchronousRestObjectRequester returns somethins that is not an empty string | 378 | asset.UploadAttempts++; |
232 | if (newID != null) | 379 | if (asset.UploadAttempts > 30) |
233 | asset.ID = newID; | 380 | { |
234 | 381 | //By this stage we've been in the queue for a good few hours; | |
235 | if (m_Cache != null) | 382 | //We're going to drop the asset. |
236 | m_Cache.Cache(asset); | 383 | m_log.ErrorFormat("[Assets] Dropping asset {0} - Upload has been in the queue for too long.", asset.ID.ToString()); |
384 | } | ||
385 | else | ||
386 | { | ||
387 | if (!m_retryQueue.ContainsKey(asset.UploadAttempts)) | ||
388 | { | ||
389 | m_retryQueue.Add(asset.UploadAttempts, new List<AssetBase>()); | ||
390 | } | ||
391 | List<AssetBase> m_queue = m_retryQueue[asset.UploadAttempts]; | ||
392 | m_queue.Add(asset); | ||
393 | m_log.WarnFormat("[Assets] Upload failed: {0} - Requeuing asset for another run.", asset.ID.ToString()); | ||
394 | m_retryTimer.Start(); | ||
395 | } | ||
396 | } | ||
397 | else | ||
398 | { | ||
399 | if (asset.UploadAttempts > 0) | ||
400 | { | ||
401 | m_log.InfoFormat("[Assets] Upload of {0} succeeded after {1} failed attempts", asset.ID.ToString(), asset.UploadAttempts.ToString()); | ||
402 | } | ||
403 | if (newID != String.Empty) | ||
404 | { | ||
405 | // Placing this here, so that this work with old asset servers that don't send any reply back | ||
406 | // SynchronousRestObjectRequester returns somethins that is not an empty string | ||
407 | if (newID != null) | ||
408 | asset.ID = newID; | ||
409 | |||
410 | if (m_Cache != null) | ||
411 | m_Cache.Cache(asset); | ||
412 | } | ||
237 | } | 413 | } |
238 | return newID; | 414 | return asset.ID; |
239 | } | 415 | } |
240 | 416 | ||
241 | public bool UpdateContent(string id, byte[] data) | 417 | public bool UpdateContent(string id, byte[] data) |
@@ -251,12 +427,12 @@ namespace OpenSim.Services.Connectors | |||
251 | if (metadata == null) | 427 | if (metadata == null) |
252 | return false; | 428 | return false; |
253 | 429 | ||
254 | asset = new AssetBase(metadata.FullID, metadata.Name, metadata.Type); | 430 | asset = new AssetBase(metadata.FullID, metadata.Name, metadata.Type, UUID.Zero.ToString()); |
255 | asset.Metadata = metadata; | 431 | asset.Metadata = metadata; |
256 | } | 432 | } |
257 | asset.Data = data; | 433 | asset.Data = data; |
258 | 434 | ||
259 | string uri = m_ServerURI + "/assets/" + id; | 435 | string uri = MapServer(id) + "/assets/" + id; |
260 | 436 | ||
261 | if (SynchronousRestObjectRequester. | 437 | if (SynchronousRestObjectRequester. |
262 | MakeRequest<AssetBase, bool>("POST", uri, asset)) | 438 | MakeRequest<AssetBase, bool>("POST", uri, asset)) |
@@ -271,7 +447,7 @@ namespace OpenSim.Services.Connectors | |||
271 | 447 | ||
272 | public bool Delete(string id) | 448 | public bool Delete(string id) |
273 | { | 449 | { |
274 | string uri = m_ServerURI + "/assets/" + id; | 450 | string uri = MapServer(id) + "/assets/" + id; |
275 | 451 | ||
276 | if (SynchronousRestObjectRequester. | 452 | if (SynchronousRestObjectRequester. |
277 | MakeRequest<int, bool>("DELETE", uri, 0)) | 453 | MakeRequest<int, bool>("DELETE", uri, 0)) |
diff --git a/OpenSim/Services/Connectors/Asset/HGAssetServiceConnector.cs b/OpenSim/Services/Connectors/Asset/HGAssetServiceConnector.cs index 34df54a..5c31639 100644 --- a/OpenSim/Services/Connectors/Asset/HGAssetServiceConnector.cs +++ b/OpenSim/Services/Connectors/Asset/HGAssetServiceConnector.cs | |||
@@ -32,6 +32,8 @@ using System.Collections.Generic; | |||
32 | using System.Reflection; | 32 | using System.Reflection; |
33 | using OpenSim.Framework; | 33 | using OpenSim.Framework; |
34 | using OpenSim.Services.Interfaces; | 34 | using OpenSim.Services.Interfaces; |
35 | using OpenSim.Services.Connectors.Hypergrid; | ||
36 | using OpenSim.Services.Connectors.SimianGrid; | ||
35 | 37 | ||
36 | namespace OpenSim.Services.Connectors | 38 | namespace OpenSim.Services.Connectors |
37 | { | 39 | { |
@@ -41,7 +43,7 @@ namespace OpenSim.Services.Connectors | |||
41 | LogManager.GetLogger( | 43 | LogManager.GetLogger( |
42 | MethodBase.GetCurrentMethod().DeclaringType); | 44 | MethodBase.GetCurrentMethod().DeclaringType); |
43 | 45 | ||
44 | private Dictionary<string, AssetServicesConnector> m_connectors = new Dictionary<string, AssetServicesConnector>(); | 46 | private Dictionary<string, IAssetService> m_connectors = new Dictionary<string, IAssetService>(); |
45 | 47 | ||
46 | public HGAssetServiceConnector(IConfigSource source) | 48 | public HGAssetServiceConnector(IConfigSource source) |
47 | { | 49 | { |
@@ -81,7 +83,7 @@ namespace OpenSim.Services.Connectors | |||
81 | 83 | ||
82 | private IAssetService GetConnector(string url) | 84 | private IAssetService GetConnector(string url) |
83 | { | 85 | { |
84 | AssetServicesConnector connector = null; | 86 | IAssetService connector = null; |
85 | lock (m_connectors) | 87 | lock (m_connectors) |
86 | { | 88 | { |
87 | if (m_connectors.ContainsKey(url)) | 89 | if (m_connectors.ContainsKey(url)) |
@@ -90,12 +92,17 @@ namespace OpenSim.Services.Connectors | |||
90 | } | 92 | } |
91 | else | 93 | else |
92 | { | 94 | { |
93 | // We're instantiating this class explicitly, but this won't | 95 | // Still not as flexible as I would like this to be, |
94 | // work in general, because the remote grid may be running | 96 | // but good enough for now |
95 | // an asset server that has a different protocol. | 97 | string connectorType = new HeloServicesConnector(url).Helo(); |
96 | // Eventually we will want a piece of protocol asking | 98 | m_log.DebugFormat("[HG ASSET SERVICE]: HELO returned {0}", connectorType); |
97 | // the remote server about its kind. Definitely cool thing to do! | 99 | if (connectorType == "opensim-simian") |
98 | connector = new AssetServicesConnector(url); | 100 | { |
101 | connector = new SimianAssetServiceConnector(url); | ||
102 | } | ||
103 | else | ||
104 | connector = new AssetServicesConnector(url); | ||
105 | |||
99 | m_connectors.Add(url, connector); | 106 | m_connectors.Add(url, connector); |
100 | } | 107 | } |
101 | } | 108 | } |
diff --git a/OpenSim/Services/Connectors/Authentication/AuthenticationServiceConnector.cs b/OpenSim/Services/Connectors/Authentication/AuthenticationServiceConnector.cs index 19bb3e2..2b77154 100644 --- a/OpenSim/Services/Connectors/Authentication/AuthenticationServiceConnector.cs +++ b/OpenSim/Services/Connectors/Authentication/AuthenticationServiceConnector.cs | |||
@@ -33,7 +33,6 @@ using System.Reflection; | |||
33 | using Nini.Config; | 33 | using Nini.Config; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Framework.Communications; | 35 | using OpenSim.Framework.Communications; |
36 | using OpenSim.Framework.Servers.HttpServer; | ||
37 | using OpenSim.Services.Interfaces; | 36 | using OpenSim.Services.Interfaces; |
38 | using OpenSim.Server.Base; | 37 | using OpenSim.Server.Base; |
39 | using OpenMetaverse; | 38 | using OpenMetaverse; |
@@ -67,7 +66,7 @@ namespace OpenSim.Services.Connectors | |||
67 | IConfig assetConfig = source.Configs["AuthenticationService"]; | 66 | IConfig assetConfig = source.Configs["AuthenticationService"]; |
68 | if (assetConfig == null) | 67 | if (assetConfig == null) |
69 | { | 68 | { |
70 | m_log.Error("[USER CONNECTOR]: AuthenticationService missing from OpanSim.ini"); | 69 | m_log.Error("[AUTH CONNECTOR]: AuthenticationService missing from OpenSim.ini"); |
71 | throw new Exception("Authentication connector init error"); | 70 | throw new Exception("Authentication connector init error"); |
72 | } | 71 | } |
73 | 72 | ||
@@ -76,7 +75,7 @@ namespace OpenSim.Services.Connectors | |||
76 | 75 | ||
77 | if (serviceURI == String.Empty) | 76 | if (serviceURI == String.Empty) |
78 | { | 77 | { |
79 | m_log.Error("[USER CONNECTOR]: No Server URI named in section AuthenticationService"); | 78 | m_log.Error("[AUTH CONNECTOR]: No Server URI named in section AuthenticationService"); |
80 | throw new Exception("Authentication connector init error"); | 79 | throw new Exception("Authentication connector init error"); |
81 | } | 80 | } |
82 | m_ServerURI = serviceURI; | 81 | m_ServerURI = serviceURI; |
@@ -146,5 +145,23 @@ namespace OpenSim.Services.Connectors | |||
146 | 145 | ||
147 | return true; | 146 | return true; |
148 | } | 147 | } |
148 | |||
149 | public bool SetPassword(UUID principalID, string passwd) | ||
150 | { | ||
151 | // nope, we don't do this | ||
152 | return false; | ||
153 | } | ||
154 | |||
155 | public AuthInfo GetAuthInfo(UUID principalID) | ||
156 | { | ||
157 | // not done from remote simulators | ||
158 | return null; | ||
159 | } | ||
160 | |||
161 | public bool SetAuthInfo(AuthInfo info) | ||
162 | { | ||
163 | // not done from remote simulators | ||
164 | return false; | ||
165 | } | ||
149 | } | 166 | } |
150 | } | 167 | } |
diff --git a/OpenSim/Services/Connectors/Authorization/AuthorizationServiceConnector.cs b/OpenSim/Services/Connectors/Authorization/AuthorizationServiceConnector.cs index 4eb4bd2..35b7109 100644 --- a/OpenSim/Services/Connectors/Authorization/AuthorizationServiceConnector.cs +++ b/OpenSim/Services/Connectors/Authorization/AuthorizationServiceConnector.cs | |||
@@ -33,7 +33,6 @@ using System.Reflection; | |||
33 | using Nini.Config; | 33 | using Nini.Config; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Framework.Communications; | 35 | using OpenSim.Framework.Communications; |
36 | using OpenSim.Framework.Servers.HttpServer; | ||
37 | using OpenSim.Services.Interfaces; | 36 | using OpenSim.Services.Interfaces; |
38 | using OpenMetaverse; | 37 | using OpenMetaverse; |
39 | 38 | ||
diff --git a/OpenSim/Services/Connectors/Avatar/AvatarServiceConnector.cs b/OpenSim/Services/Connectors/Avatar/AvatarServiceConnector.cs new file mode 100644 index 0000000..8fdb4d0 --- /dev/null +++ b/OpenSim/Services/Connectors/Avatar/AvatarServiceConnector.cs | |||
@@ -0,0 +1,328 @@ | |||
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 | |||
28 | using log4net; | ||
29 | using System; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Reflection; | ||
33 | using Nini.Config; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Communications; | ||
36 | using OpenSim.Services.Interfaces; | ||
37 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
38 | using IAvatarService = OpenSim.Services.Interfaces.IAvatarService; | ||
39 | using OpenSim.Server.Base; | ||
40 | using OpenMetaverse; | ||
41 | |||
42 | namespace OpenSim.Services.Connectors | ||
43 | { | ||
44 | public class AvatarServicesConnector : IAvatarService | ||
45 | { | ||
46 | private static readonly ILog m_log = | ||
47 | LogManager.GetLogger( | ||
48 | MethodBase.GetCurrentMethod().DeclaringType); | ||
49 | |||
50 | private string m_ServerURI = String.Empty; | ||
51 | |||
52 | public AvatarServicesConnector() | ||
53 | { | ||
54 | } | ||
55 | |||
56 | public AvatarServicesConnector(string serverURI) | ||
57 | { | ||
58 | m_ServerURI = serverURI.TrimEnd('/'); | ||
59 | } | ||
60 | |||
61 | public AvatarServicesConnector(IConfigSource source) | ||
62 | { | ||
63 | Initialise(source); | ||
64 | } | ||
65 | |||
66 | public virtual void Initialise(IConfigSource source) | ||
67 | { | ||
68 | IConfig gridConfig = source.Configs["AvatarService"]; | ||
69 | if (gridConfig == null) | ||
70 | { | ||
71 | m_log.Error("[AVATAR CONNECTOR]: AvatarService missing from OpenSim.ini"); | ||
72 | throw new Exception("Avatar connector init error"); | ||
73 | } | ||
74 | |||
75 | string serviceURI = gridConfig.GetString("AvatarServerURI", | ||
76 | String.Empty); | ||
77 | |||
78 | if (serviceURI == String.Empty) | ||
79 | { | ||
80 | m_log.Error("[AVATAR CONNECTOR]: No Server URI named in section AvatarService"); | ||
81 | throw new Exception("Avatar connector init error"); | ||
82 | } | ||
83 | m_ServerURI = serviceURI; | ||
84 | } | ||
85 | |||
86 | |||
87 | #region IAvatarService | ||
88 | |||
89 | public AvatarAppearance GetAppearance(UUID userID) | ||
90 | { | ||
91 | AvatarData avatar = GetAvatar(userID); | ||
92 | return avatar.ToAvatarAppearance(); | ||
93 | } | ||
94 | |||
95 | public bool SetAppearance(UUID userID, AvatarAppearance appearance) | ||
96 | { | ||
97 | AvatarData avatar = new AvatarData(appearance); | ||
98 | return SetAvatar(userID,avatar); | ||
99 | } | ||
100 | |||
101 | public AvatarData GetAvatar(UUID userID) | ||
102 | { | ||
103 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
104 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
105 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
106 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
107 | sendData["METHOD"] = "getavatar"; | ||
108 | |||
109 | sendData["UserID"] = userID; | ||
110 | |||
111 | string reply = string.Empty; | ||
112 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
113 | // m_log.DebugFormat("[AVATAR CONNECTOR]: queryString = {0}", reqString); | ||
114 | try | ||
115 | { | ||
116 | reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
117 | m_ServerURI + "/avatar", | ||
118 | reqString); | ||
119 | if (reply == null || (reply != null && reply == string.Empty)) | ||
120 | { | ||
121 | m_log.DebugFormat("[AVATAR CONNECTOR]: GetAgent received null or empty reply"); | ||
122 | return null; | ||
123 | } | ||
124 | } | ||
125 | catch (Exception e) | ||
126 | { | ||
127 | m_log.DebugFormat("[AVATAR CONNECTOR]: Exception when contacting presence server: {0}", e.Message); | ||
128 | } | ||
129 | |||
130 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
131 | AvatarData avatar = null; | ||
132 | |||
133 | if ((replyData != null) && replyData.ContainsKey("result") && (replyData["result"] != null)) | ||
134 | { | ||
135 | if (replyData["result"] is Dictionary<string, object>) | ||
136 | { | ||
137 | avatar = new AvatarData((Dictionary<string, object>)replyData["result"]); | ||
138 | } | ||
139 | } | ||
140 | |||
141 | return avatar; | ||
142 | |||
143 | } | ||
144 | |||
145 | public bool SetAvatar(UUID userID, AvatarData avatar) | ||
146 | { | ||
147 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
148 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
149 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
150 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
151 | sendData["METHOD"] = "setavatar"; | ||
152 | |||
153 | sendData["UserID"] = userID.ToString(); | ||
154 | |||
155 | Dictionary<string, object> structData = avatar.ToKeyValuePairs(); | ||
156 | |||
157 | foreach (KeyValuePair<string, object> kvp in structData) | ||
158 | sendData[kvp.Key] = kvp.Value.ToString(); | ||
159 | |||
160 | |||
161 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
162 | //m_log.DebugFormat("[AVATAR CONNECTOR]: queryString = {0}", reqString); | ||
163 | try | ||
164 | { | ||
165 | string reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
166 | m_ServerURI + "/avatar", | ||
167 | reqString); | ||
168 | if (reply != string.Empty) | ||
169 | { | ||
170 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
171 | |||
172 | if (replyData.ContainsKey("result")) | ||
173 | { | ||
174 | if (replyData["result"].ToString().ToLower() == "success") | ||
175 | return true; | ||
176 | else | ||
177 | return false; | ||
178 | } | ||
179 | else | ||
180 | m_log.DebugFormat("[AVATAR CONNECTOR]: SetAvatar reply data does not contain result field"); | ||
181 | |||
182 | } | ||
183 | else | ||
184 | m_log.DebugFormat("[AVATAR CONNECTOR]: SetAvatar received empty reply"); | ||
185 | } | ||
186 | catch (Exception e) | ||
187 | { | ||
188 | m_log.DebugFormat("[AVATAR CONNECTOR]: Exception when contacting avatar server: {0}", e.Message); | ||
189 | } | ||
190 | |||
191 | return false; | ||
192 | } | ||
193 | |||
194 | public bool ResetAvatar(UUID userID) | ||
195 | { | ||
196 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
197 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
198 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
199 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
200 | sendData["METHOD"] = "resetavatar"; | ||
201 | |||
202 | sendData["UserID"] = userID.ToString(); | ||
203 | |||
204 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
205 | // m_log.DebugFormat("[AVATAR CONNECTOR]: queryString = {0}", reqString); | ||
206 | try | ||
207 | { | ||
208 | string reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
209 | m_ServerURI + "/avatar", | ||
210 | reqString); | ||
211 | if (reply != string.Empty) | ||
212 | { | ||
213 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
214 | |||
215 | if (replyData.ContainsKey("result")) | ||
216 | { | ||
217 | if (replyData["result"].ToString().ToLower() == "success") | ||
218 | return true; | ||
219 | else | ||
220 | return false; | ||
221 | } | ||
222 | else | ||
223 | m_log.DebugFormat("[AVATAR CONNECTOR]: SetItems reply data does not contain result field"); | ||
224 | |||
225 | } | ||
226 | else | ||
227 | m_log.DebugFormat("[AVATAR CONNECTOR]: SetItems received empty reply"); | ||
228 | } | ||
229 | catch (Exception e) | ||
230 | { | ||
231 | m_log.DebugFormat("[AVATAR CONNECTOR]: Exception when contacting avatar server: {0}", e.Message); | ||
232 | } | ||
233 | |||
234 | return false; | ||
235 | } | ||
236 | |||
237 | public bool SetItems(UUID userID, string[] names, string[] values) | ||
238 | { | ||
239 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
240 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
241 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
242 | sendData["METHOD"] = "setitems"; | ||
243 | |||
244 | sendData["UserID"] = userID.ToString(); | ||
245 | sendData["Names"] = new List<string>(names); | ||
246 | sendData["Values"] = new List<string>(values); | ||
247 | |||
248 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
249 | // m_log.DebugFormat("[AVATAR CONNECTOR]: queryString = {0}", reqString); | ||
250 | try | ||
251 | { | ||
252 | string reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
253 | m_ServerURI + "/avatar", | ||
254 | reqString); | ||
255 | if (reply != string.Empty) | ||
256 | { | ||
257 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
258 | |||
259 | if (replyData.ContainsKey("result")) | ||
260 | { | ||
261 | if (replyData["result"].ToString().ToLower() == "success") | ||
262 | return true; | ||
263 | else | ||
264 | return false; | ||
265 | } | ||
266 | else | ||
267 | m_log.DebugFormat("[AVATAR CONNECTOR]: SetItems reply data does not contain result field"); | ||
268 | |||
269 | } | ||
270 | else | ||
271 | m_log.DebugFormat("[AVATAR CONNECTOR]: SetItems received empty reply"); | ||
272 | } | ||
273 | catch (Exception e) | ||
274 | { | ||
275 | m_log.DebugFormat("[AVATAR CONNECTOR]: Exception when contacting avatar server: {0}", e.Message); | ||
276 | } | ||
277 | |||
278 | return false; | ||
279 | } | ||
280 | |||
281 | public bool RemoveItems(UUID userID, string[] names) | ||
282 | { | ||
283 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
284 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
285 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
286 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
287 | sendData["METHOD"] = "removeitems"; | ||
288 | |||
289 | sendData["UserID"] = userID.ToString(); | ||
290 | sendData["Names"] = new List<string>(names); | ||
291 | |||
292 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
293 | // m_log.DebugFormat("[AVATAR CONNECTOR]: queryString = {0}", reqString); | ||
294 | try | ||
295 | { | ||
296 | string reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
297 | m_ServerURI + "/avatar", | ||
298 | reqString); | ||
299 | if (reply != string.Empty) | ||
300 | { | ||
301 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
302 | |||
303 | if (replyData.ContainsKey("result")) | ||
304 | { | ||
305 | if (replyData["result"].ToString().ToLower() == "success") | ||
306 | return true; | ||
307 | else | ||
308 | return false; | ||
309 | } | ||
310 | else | ||
311 | m_log.DebugFormat("[AVATAR CONNECTOR]: RemoveItems reply data does not contain result field"); | ||
312 | |||
313 | } | ||
314 | else | ||
315 | m_log.DebugFormat("[AVATAR CONNECTOR]: RemoveItems received empty reply"); | ||
316 | } | ||
317 | catch (Exception e) | ||
318 | { | ||
319 | m_log.DebugFormat("[AVATAR CONNECTOR]: Exception when contacting avatar server: {0}", e.Message); | ||
320 | } | ||
321 | |||
322 | return false; | ||
323 | } | ||
324 | |||
325 | #endregion | ||
326 | |||
327 | } | ||
328 | } | ||
diff --git a/OpenSim/Services/Connectors/User/UserServiceConnector.cs b/OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs index 683990f..d688299 100644 --- a/OpenSim/Services/Connectors/User/UserServiceConnector.cs +++ b/OpenSim/Services/Connectors/Freeswitch/RemoteFreeswitchConnector.cs | |||
@@ -27,88 +27,77 @@ | |||
27 | 27 | ||
28 | using log4net; | 28 | using log4net; |
29 | using System; | 29 | using System; |
30 | using System.Collections.Generic; | ||
31 | using System.IO; | 30 | using System.IO; |
31 | using System.Collections; | ||
32 | using System.Reflection; | 32 | using System.Reflection; |
33 | using Nini.Config; | 33 | using Nini.Config; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Framework.Communications; | 35 | using OpenSim.Framework.Communications; |
36 | using OpenSim.Framework.Servers.HttpServer; | ||
37 | using OpenSim.Services.Interfaces; | 36 | using OpenSim.Services.Interfaces; |
37 | using OpenSim.Server.Base; | ||
38 | using OpenMetaverse; | 38 | using OpenMetaverse; |
39 | 39 | ||
40 | namespace OpenSim.Services.Connectors | 40 | namespace OpenSim.Services.Connectors |
41 | { | 41 | { |
42 | public class UserServicesConnector : IUserAccountService | 42 | public class RemoteFreeswitchConnector : IFreeswitchService |
43 | { | 43 | { |
44 | private static readonly ILog m_log = | 44 | private static readonly ILog m_log = |
45 | LogManager.GetLogger( | 45 | LogManager.GetLogger( |
46 | MethodBase.GetCurrentMethod().DeclaringType); | 46 | MethodBase.GetCurrentMethod().DeclaringType); |
47 | 47 | ||
48 | // private string m_ServerURI = String.Empty; | 48 | private string m_ServerURI = String.Empty; |
49 | 49 | ||
50 | public UserServicesConnector() | 50 | public RemoteFreeswitchConnector() |
51 | { | 51 | { |
52 | } | 52 | } |
53 | 53 | ||
54 | public UserServicesConnector(string serverURI) | 54 | public RemoteFreeswitchConnector(string serverURI) |
55 | { | 55 | { |
56 | // m_ServerURI = serverURI.TrimEnd('/'); | 56 | m_ServerURI = serverURI.TrimEnd('/') + "/region-config"; |
57 | } | 57 | } |
58 | 58 | ||
59 | public UserServicesConnector(IConfigSource source) | 59 | public RemoteFreeswitchConnector(IConfigSource source) |
60 | { | 60 | { |
61 | Initialise(source); | 61 | Initialise(source); |
62 | } | 62 | } |
63 | 63 | ||
64 | public virtual void Initialise(IConfigSource source) | 64 | public virtual void Initialise(IConfigSource source) |
65 | { | 65 | { |
66 | IConfig assetConfig = source.Configs["UserService"]; | 66 | IConfig freeswitchConfig = source.Configs["FreeSwitchVoice"]; |
67 | if (assetConfig == null) | 67 | if (freeswitchConfig == null) |
68 | { | 68 | { |
69 | m_log.Error("[USER CONNECTOR]: UserService missing from OpanSim.ini"); | 69 | m_log.Error("[FREESWITCH CONNECTOR]: FreeSwitchVoice missing from OpenSim.ini"); |
70 | throw new Exception("User connector init error"); | 70 | throw new Exception("Freeswitch connector init error"); |
71 | } | 71 | } |
72 | 72 | ||
73 | string serviceURI = assetConfig.GetString("UserServerURI", | 73 | string serviceURI = freeswitchConfig.GetString("FreeswitchServiceURL", |
74 | String.Empty); | 74 | String.Empty); |
75 | 75 | ||
76 | if (serviceURI == String.Empty) | 76 | if (serviceURI == String.Empty) |
77 | { | 77 | { |
78 | m_log.Error("[USER CONNECTOR]: No Server URI named in section UserService"); | 78 | m_log.Error("[FREESWITCH CONNECTOR]: No FreeswitchServiceURL named in section FreeSwitchVoice"); |
79 | throw new Exception("User connector init error"); | 79 | throw new Exception("Freeswitch connector init error"); |
80 | } | 80 | } |
81 | //m_ServerURI = serviceURI; | 81 | m_ServerURI = serviceURI.TrimEnd('/') + "/region-config"; |
82 | } | 82 | } |
83 | 83 | ||
84 | public UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName) | 84 | public Hashtable HandleDirectoryRequest(Hashtable requestBody) |
85 | { | 85 | { |
86 | return null; | 86 | // not used here |
87 | return new Hashtable(); | ||
87 | } | 88 | } |
88 | 89 | ||
89 | public UserAccount GetUserAccount(UUID scopeID, UUID userID) | 90 | public Hashtable HandleDialplanRequest(Hashtable requestBody) |
90 | { | 91 | { |
91 | return null; | 92 | // not used here |
93 | return new Hashtable(); | ||
92 | } | 94 | } |
93 | 95 | ||
94 | public bool SetHomePosition(UserAccount data, UUID regionID, UUID regionSecret) | 96 | public string GetJsonConfig() |
95 | { | 97 | { |
96 | return false; | 98 | m_log.DebugFormat("[FREESWITCH CONNECTOR]: Requesting config from {0}", m_ServerURI); |
97 | } | 99 | return SynchronousRestFormsRequester.MakeRequest("GET", |
98 | 100 | m_ServerURI, String.Empty); | |
99 | public bool SetUserAccount(UserAccount data, UUID principalID, string token) | ||
100 | { | ||
101 | return false; | ||
102 | } | ||
103 | |||
104 | public bool CreateUserAccount(UserAccount data, UUID principalID, string token) | ||
105 | { | ||
106 | return false; | ||
107 | } | ||
108 | |||
109 | public List<UserAccount> GetUserAccount(UUID scopeID, string query) | ||
110 | { | ||
111 | return null; | ||
112 | } | 101 | } |
113 | } | 102 | } |
114 | } | 103 | } |
diff --git a/OpenSim/Services/Connectors/Friends/FriendsServiceConnector.cs b/OpenSim/Services/Connectors/Friends/FriendsServiceConnector.cs new file mode 100644 index 0000000..41361ab --- /dev/null +++ b/OpenSim/Services/Connectors/Friends/FriendsServiceConnector.cs | |||
@@ -0,0 +1,271 @@ | |||
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 | |||
28 | using log4net; | ||
29 | using System; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Reflection; | ||
33 | using Nini.Config; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Communications; | ||
36 | using OpenSim.Services.Interfaces; | ||
37 | using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; | ||
38 | using OpenSim.Server.Base; | ||
39 | using OpenMetaverse; | ||
40 | |||
41 | namespace OpenSim.Services.Connectors.Friends | ||
42 | { | ||
43 | public class FriendsServicesConnector : IFriendsService | ||
44 | { | ||
45 | private static readonly ILog m_log = | ||
46 | LogManager.GetLogger( | ||
47 | MethodBase.GetCurrentMethod().DeclaringType); | ||
48 | |||
49 | private string m_ServerURI = String.Empty; | ||
50 | |||
51 | public FriendsServicesConnector() | ||
52 | { | ||
53 | } | ||
54 | |||
55 | public FriendsServicesConnector(string serverURI) | ||
56 | { | ||
57 | m_ServerURI = serverURI.TrimEnd('/'); | ||
58 | } | ||
59 | |||
60 | public FriendsServicesConnector(IConfigSource source) | ||
61 | { | ||
62 | Initialise(source); | ||
63 | } | ||
64 | |||
65 | public virtual void Initialise(IConfigSource source) | ||
66 | { | ||
67 | IConfig gridConfig = source.Configs["FriendsService"]; | ||
68 | if (gridConfig == null) | ||
69 | { | ||
70 | m_log.Error("[FRIENDS SERVICE CONNECTOR]: FriendsService missing from OpenSim.ini"); | ||
71 | throw new Exception("Friends connector init error"); | ||
72 | } | ||
73 | |||
74 | string serviceURI = gridConfig.GetString("FriendsServerURI", | ||
75 | String.Empty); | ||
76 | |||
77 | if (serviceURI == String.Empty) | ||
78 | { | ||
79 | m_log.Error("[FRIENDS SERVICE CONNECTOR]: No Server URI named in section FriendsService"); | ||
80 | throw new Exception("Friends connector init error"); | ||
81 | } | ||
82 | m_ServerURI = serviceURI; | ||
83 | } | ||
84 | |||
85 | |||
86 | #region IFriendsService | ||
87 | |||
88 | public FriendInfo[] GetFriends(UUID PrincipalID) | ||
89 | { | ||
90 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
91 | |||
92 | sendData["PRINCIPALID"] = PrincipalID.ToString(); | ||
93 | sendData["METHOD"] = "getfriends"; | ||
94 | |||
95 | return GetFriends(sendData, PrincipalID.ToString()); | ||
96 | } | ||
97 | |||
98 | public FriendInfo[] GetFriends(string PrincipalID) | ||
99 | { | ||
100 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
101 | |||
102 | sendData["PRINCIPALID"] = PrincipalID; | ||
103 | sendData["METHOD"] = "getfriends_string"; | ||
104 | |||
105 | return GetFriends(sendData, PrincipalID); | ||
106 | } | ||
107 | |||
108 | protected FriendInfo[] GetFriends(Dictionary<string, object> sendData, string PrincipalID) | ||
109 | { | ||
110 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
111 | |||
112 | try | ||
113 | { | ||
114 | string reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
115 | m_ServerURI + "/friends", | ||
116 | reqString); | ||
117 | if (reply != string.Empty) | ||
118 | { | ||
119 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
120 | |||
121 | if (replyData != null) | ||
122 | { | ||
123 | if (replyData.ContainsKey("result") && (replyData["result"].ToString().ToLower() == "null")) | ||
124 | { | ||
125 | return new FriendInfo[0]; | ||
126 | } | ||
127 | |||
128 | List<FriendInfo> finfos = new List<FriendInfo>(); | ||
129 | Dictionary<string, object>.ValueCollection finfosList = replyData.Values; | ||
130 | //m_log.DebugFormat("[FRIENDS SERVICE CONNECTOR]: get neighbours returned {0} elements", rinfosList.Count); | ||
131 | foreach (object f in finfosList) | ||
132 | { | ||
133 | if (f is Dictionary<string, object>) | ||
134 | { | ||
135 | FriendInfo finfo = new FriendInfo((Dictionary<string, object>)f); | ||
136 | finfos.Add(finfo); | ||
137 | } | ||
138 | else | ||
139 | m_log.DebugFormat("[FRIENDS SERVICE CONNECTOR]: GetFriends {0} received invalid response type {1}", | ||
140 | PrincipalID, f.GetType()); | ||
141 | } | ||
142 | |||
143 | // Success | ||
144 | return finfos.ToArray(); | ||
145 | } | ||
146 | |||
147 | else | ||
148 | m_log.DebugFormat("[FRIENDS SERVICE CONNECTOR]: GetFriends {0} received null response", | ||
149 | PrincipalID); | ||
150 | |||
151 | } | ||
152 | } | ||
153 | catch (Exception e) | ||
154 | { | ||
155 | m_log.DebugFormat("[FRIENDS SERVICE CONNECTOR]: Exception when contacting friends server: {0}", e.Message); | ||
156 | } | ||
157 | |||
158 | return new FriendInfo[0]; | ||
159 | |||
160 | } | ||
161 | |||
162 | public bool StoreFriend(string PrincipalID, string Friend, int flags) | ||
163 | { | ||
164 | |||
165 | Dictionary<string, object> sendData = ToKeyValuePairs(PrincipalID, Friend, flags); | ||
166 | |||
167 | sendData["METHOD"] = "storefriend"; | ||
168 | |||
169 | string reply = string.Empty; | ||
170 | try | ||
171 | { | ||
172 | reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
173 | m_ServerURI + "/friends", | ||
174 | ServerUtils.BuildQueryString(sendData)); | ||
175 | } | ||
176 | catch (Exception e) | ||
177 | { | ||
178 | m_log.DebugFormat("[FRIENDS SERVICE CONNECTOR]: Exception when contacting friends server: {0}", e.Message); | ||
179 | return false; | ||
180 | } | ||
181 | |||
182 | if (reply != string.Empty) | ||
183 | { | ||
184 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
185 | |||
186 | if ((replyData != null) && replyData.ContainsKey("Result") && (replyData["Result"] != null)) | ||
187 | { | ||
188 | bool success = false; | ||
189 | Boolean.TryParse(replyData["Result"].ToString(), out success); | ||
190 | return success; | ||
191 | } | ||
192 | else | ||
193 | m_log.DebugFormat("[FRIENDS SERVICE CONNECTOR]: StoreFriend {0} {1} received null response", | ||
194 | PrincipalID, Friend); | ||
195 | } | ||
196 | else | ||
197 | m_log.DebugFormat("[FRIENDS SERVICE CONNECTOR]: StoreFriend received null reply"); | ||
198 | |||
199 | return false; | ||
200 | |||
201 | } | ||
202 | |||
203 | public bool Delete(string PrincipalID, string Friend) | ||
204 | { | ||
205 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
206 | sendData["PRINCIPALID"] = PrincipalID.ToString(); | ||
207 | sendData["FRIEND"] = Friend; | ||
208 | sendData["METHOD"] = "deletefriend_string"; | ||
209 | |||
210 | return Delete(sendData, PrincipalID, Friend); | ||
211 | } | ||
212 | |||
213 | public bool Delete(UUID PrincipalID, string Friend) | ||
214 | { | ||
215 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
216 | sendData["PRINCIPALID"] = PrincipalID.ToString(); | ||
217 | sendData["FRIEND"] = Friend; | ||
218 | sendData["METHOD"] = "deletefriend"; | ||
219 | |||
220 | return Delete(sendData, PrincipalID.ToString(), Friend); | ||
221 | } | ||
222 | |||
223 | public bool Delete(Dictionary<string, object> sendData, string PrincipalID, string Friend) | ||
224 | { | ||
225 | string reply = string.Empty; | ||
226 | try | ||
227 | { | ||
228 | reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
229 | m_ServerURI + "/friends", | ||
230 | ServerUtils.BuildQueryString(sendData)); | ||
231 | } | ||
232 | catch (Exception e) | ||
233 | { | ||
234 | m_log.DebugFormat("[FRIENDS SERVICE CONNECTOR]: Exception when contacting friends server: {0}", e.Message); | ||
235 | return false; | ||
236 | } | ||
237 | |||
238 | if (reply != string.Empty) | ||
239 | { | ||
240 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
241 | |||
242 | if ((replyData != null) && replyData.ContainsKey("Result") && (replyData["Result"] != null)) | ||
243 | { | ||
244 | bool success = false; | ||
245 | Boolean.TryParse(replyData["Result"].ToString(), out success); | ||
246 | return success; | ||
247 | } | ||
248 | else | ||
249 | m_log.DebugFormat("[FRIENDS SERVICE CONNECTOR]: DeleteFriend {0} {1} received null response", | ||
250 | PrincipalID, Friend); | ||
251 | } | ||
252 | else | ||
253 | m_log.DebugFormat("[FRIENDS SERVICE CONNECTOR]: DeleteFriend received null reply"); | ||
254 | |||
255 | return false; | ||
256 | } | ||
257 | |||
258 | #endregion | ||
259 | |||
260 | public Dictionary<string, object> ToKeyValuePairs(string principalID, string friend, int flags) | ||
261 | { | ||
262 | Dictionary<string, object> result = new Dictionary<string, object>(); | ||
263 | result["PrincipalID"] = principalID; | ||
264 | result["Friend"] = friend; | ||
265 | result["MyFlags"] = flags; | ||
266 | |||
267 | return result; | ||
268 | } | ||
269 | |||
270 | } | ||
271 | } \ No newline at end of file | ||
diff --git a/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs b/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs new file mode 100644 index 0000000..d0a20fc --- /dev/null +++ b/OpenSim/Services/Connectors/Friends/FriendsSimConnector.cs | |||
@@ -0,0 +1,174 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | |||
32 | using OpenSim.Services.Interfaces; | ||
33 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
34 | using OpenSim.Server.Base; | ||
35 | using OpenSim.Framework; | ||
36 | |||
37 | using OpenMetaverse; | ||
38 | using log4net; | ||
39 | |||
40 | namespace OpenSim.Services.Connectors.Friends | ||
41 | { | ||
42 | public class FriendsSimConnector | ||
43 | { | ||
44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
45 | |||
46 | public bool FriendshipOffered(GridRegion region, UUID userID, UUID friendID, string message) | ||
47 | { | ||
48 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
49 | //sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
50 | //sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
51 | sendData["METHOD"] = "friendship_offered"; | ||
52 | |||
53 | sendData["FromID"] = userID.ToString(); | ||
54 | sendData["ToID"] = friendID.ToString(); | ||
55 | sendData["Message"] = message; | ||
56 | |||
57 | return Call(region, sendData); | ||
58 | |||
59 | } | ||
60 | |||
61 | public bool FriendshipApproved(GridRegion region, UUID userID, string userName, UUID friendID) | ||
62 | { | ||
63 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
64 | //sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
65 | //sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
66 | sendData["METHOD"] = "friendship_approved"; | ||
67 | |||
68 | sendData["FromID"] = userID.ToString(); | ||
69 | sendData["FromName"] = userName; | ||
70 | sendData["ToID"] = friendID.ToString(); | ||
71 | |||
72 | return Call(region, sendData); | ||
73 | } | ||
74 | |||
75 | public bool FriendshipDenied(GridRegion region, UUID userID, string userName, UUID friendID) | ||
76 | { | ||
77 | if (region == null) | ||
78 | return false; | ||
79 | |||
80 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
81 | //sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
82 | //sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
83 | sendData["METHOD"] = "friendship_denied"; | ||
84 | |||
85 | sendData["FromID"] = userID.ToString(); | ||
86 | sendData["FromName"] = userName; | ||
87 | sendData["ToID"] = friendID.ToString(); | ||
88 | |||
89 | return Call(region, sendData); | ||
90 | } | ||
91 | |||
92 | public bool FriendshipTerminated(GridRegion region, UUID userID, UUID friendID) | ||
93 | { | ||
94 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
95 | //sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
96 | //sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
97 | sendData["METHOD"] = "friendship_terminated"; | ||
98 | |||
99 | sendData["FromID"] = userID.ToString(); | ||
100 | sendData["ToID"] = friendID.ToString(); | ||
101 | |||
102 | return Call(region, sendData); | ||
103 | } | ||
104 | |||
105 | public bool GrantRights(GridRegion region, UUID userID, UUID friendID, int userFlags, int rights) | ||
106 | { | ||
107 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
108 | //sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
109 | //sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
110 | sendData["METHOD"] = "grant_rights"; | ||
111 | |||
112 | sendData["FromID"] = userID.ToString(); | ||
113 | sendData["ToID"] = friendID.ToString(); | ||
114 | sendData["UserFlags"] = userFlags.ToString(); | ||
115 | sendData["Rights"] = rights.ToString(); | ||
116 | |||
117 | return Call(region, sendData); | ||
118 | } | ||
119 | |||
120 | public bool StatusNotify(GridRegion region, UUID userID, UUID friendID, bool online) | ||
121 | { | ||
122 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
123 | //sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
124 | //sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
125 | sendData["METHOD"] = "status"; | ||
126 | |||
127 | sendData["FromID"] = userID.ToString(); | ||
128 | sendData["ToID"] = friendID.ToString(); | ||
129 | sendData["Online"] = online.ToString(); | ||
130 | |||
131 | return Call(region, sendData); | ||
132 | } | ||
133 | |||
134 | private bool Call(GridRegion region, Dictionary<string, object> sendData) | ||
135 | { | ||
136 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
137 | //m_log.DebugFormat("[FRIENDS SIM CONNECTOR]: queryString = {0}", reqString); | ||
138 | if (region == null) | ||
139 | return false; | ||
140 | |||
141 | m_log.DebugFormat("[FRIENDS SIM CONNECTOR]: region: {0}", region.ExternalHostName + ":" + region.HttpPort); | ||
142 | try | ||
143 | { | ||
144 | string url = "http://" + region.ExternalHostName + ":" + region.HttpPort; | ||
145 | string reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
146 | url + "/friends", | ||
147 | reqString); | ||
148 | if (reply != string.Empty) | ||
149 | { | ||
150 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
151 | |||
152 | if (replyData.ContainsKey("RESULT")) | ||
153 | { | ||
154 | if (replyData["RESULT"].ToString().ToLower() == "true") | ||
155 | return true; | ||
156 | else | ||
157 | return false; | ||
158 | } | ||
159 | else | ||
160 | m_log.DebugFormat("[FRIENDS SIM CONNECTOR]: reply data does not contain result field"); | ||
161 | |||
162 | } | ||
163 | else | ||
164 | m_log.DebugFormat("[FRIENDS SIM CONNECTOR]: received empty reply"); | ||
165 | } | ||
166 | catch (Exception e) | ||
167 | { | ||
168 | m_log.DebugFormat("[FRIENDS SIM CONNECTOR]: Exception when contacting remote sim: {0}", e.ToString()); | ||
169 | } | ||
170 | |||
171 | return false; | ||
172 | } | ||
173 | } | ||
174 | } | ||
diff --git a/OpenSim/Services/Connectors/Grid/GridServiceConnector.cs b/OpenSim/Services/Connectors/Grid/GridServiceConnector.cs index 04c7c53..e57f28b 100644 --- a/OpenSim/Services/Connectors/Grid/GridServiceConnector.cs +++ b/OpenSim/Services/Connectors/Grid/GridServiceConnector.cs | |||
@@ -33,7 +33,6 @@ using System.Reflection; | |||
33 | using Nini.Config; | 33 | using Nini.Config; |
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Framework.Communications; | 35 | using OpenSim.Framework.Communications; |
36 | using OpenSim.Framework.Servers.HttpServer; | ||
37 | using OpenSim.Services.Interfaces; | 36 | using OpenSim.Services.Interfaces; |
38 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | 37 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; |
39 | using OpenSim.Server.Base; | 38 | using OpenSim.Server.Base; |
@@ -86,7 +85,7 @@ namespace OpenSim.Services.Connectors | |||
86 | 85 | ||
87 | #region IGridService | 86 | #region IGridService |
88 | 87 | ||
89 | public virtual string RegisterRegion(UUID scopeID, GridRegion regionInfo) | 88 | public string RegisterRegion(UUID scopeID, GridRegion regionInfo) |
90 | { | 89 | { |
91 | Dictionary<string, object> rinfo = regionInfo.ToKeyValuePairs(); | 90 | Dictionary<string, object> rinfo = regionInfo.ToKeyValuePairs(); |
92 | Dictionary<string, object> sendData = new Dictionary<string,object>(); | 91 | Dictionary<string, object> sendData = new Dictionary<string,object>(); |
@@ -140,7 +139,7 @@ namespace OpenSim.Services.Connectors | |||
140 | return "Error communicating with grid service"; | 139 | return "Error communicating with grid service"; |
141 | } | 140 | } |
142 | 141 | ||
143 | public virtual bool DeregisterRegion(UUID regionID) | 142 | public bool DeregisterRegion(UUID regionID) |
144 | { | 143 | { |
145 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | 144 | Dictionary<string, object> sendData = new Dictionary<string, object>(); |
146 | 145 | ||
@@ -172,7 +171,7 @@ namespace OpenSim.Services.Connectors | |||
172 | return false; | 171 | return false; |
173 | } | 172 | } |
174 | 173 | ||
175 | public virtual List<GridRegion> GetNeighbours(UUID scopeID, UUID regionID) | 174 | public List<GridRegion> GetNeighbours(UUID scopeID, UUID regionID) |
176 | { | 175 | { |
177 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | 176 | Dictionary<string, object> sendData = new Dictionary<string, object>(); |
178 | 177 | ||
@@ -210,9 +209,6 @@ namespace OpenSim.Services.Connectors | |||
210 | GridRegion rinfo = new GridRegion((Dictionary<string, object>)r); | 209 | GridRegion rinfo = new GridRegion((Dictionary<string, object>)r); |
211 | rinfos.Add(rinfo); | 210 | rinfos.Add(rinfo); |
212 | } | 211 | } |
213 | else | ||
214 | m_log.DebugFormat("[GRID CONNECTOR]: GetNeighbours {0}, {1} received invalid response type {2}", | ||
215 | scopeID, regionID, r.GetType()); | ||
216 | } | 212 | } |
217 | } | 213 | } |
218 | else | 214 | else |
@@ -222,7 +218,7 @@ namespace OpenSim.Services.Connectors | |||
222 | return rinfos; | 218 | return rinfos; |
223 | } | 219 | } |
224 | 220 | ||
225 | public virtual GridRegion GetRegionByUUID(UUID scopeID, UUID regionID) | 221 | public GridRegion GetRegionByUUID(UUID scopeID, UUID regionID) |
226 | { | 222 | { |
227 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | 223 | Dictionary<string, object> sendData = new Dictionary<string, object>(); |
228 | 224 | ||
@@ -268,7 +264,7 @@ namespace OpenSim.Services.Connectors | |||
268 | return rinfo; | 264 | return rinfo; |
269 | } | 265 | } |
270 | 266 | ||
271 | public virtual GridRegion GetRegionByPosition(UUID scopeID, int x, int y) | 267 | public GridRegion GetRegionByPosition(UUID scopeID, int x, int y) |
272 | { | 268 | { |
273 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | 269 | Dictionary<string, object> sendData = new Dictionary<string, object>(); |
274 | 270 | ||
@@ -299,9 +295,9 @@ namespace OpenSim.Services.Connectors | |||
299 | { | 295 | { |
300 | if (replyData["result"] is Dictionary<string, object>) | 296 | if (replyData["result"] is Dictionary<string, object>) |
301 | rinfo = new GridRegion((Dictionary<string, object>)replyData["result"]); | 297 | rinfo = new GridRegion((Dictionary<string, object>)replyData["result"]); |
302 | else | 298 | //else |
303 | m_log.DebugFormat("[GRID CONNECTOR]: GetRegionByPosition {0}, {1}-{2} received invalid response", | 299 | // m_log.DebugFormat("[GRID CONNECTOR]: GetRegionByPosition {0}, {1}-{2} received no region", |
304 | scopeID, x, y); | 300 | // scopeID, x, y); |
305 | } | 301 | } |
306 | else | 302 | else |
307 | m_log.DebugFormat("[GRID CONNECTOR]: GetRegionByPosition {0}, {1}-{2} received null response", | 303 | m_log.DebugFormat("[GRID CONNECTOR]: GetRegionByPosition {0}, {1}-{2} received null response", |
@@ -313,7 +309,7 @@ namespace OpenSim.Services.Connectors | |||
313 | return rinfo; | 309 | return rinfo; |
314 | } | 310 | } |
315 | 311 | ||
316 | public virtual GridRegion GetRegionByName(UUID scopeID, string regionName) | 312 | public GridRegion GetRegionByName(UUID scopeID, string regionName) |
317 | { | 313 | { |
318 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | 314 | Dictionary<string, object> sendData = new Dictionary<string, object>(); |
319 | 315 | ||
@@ -354,7 +350,7 @@ namespace OpenSim.Services.Connectors | |||
354 | return rinfo; | 350 | return rinfo; |
355 | } | 351 | } |
356 | 352 | ||
357 | public virtual List<GridRegion> GetRegionsByName(UUID scopeID, string name, int maxNumber) | 353 | public List<GridRegion> GetRegionsByName(UUID scopeID, string name, int maxNumber) |
358 | { | 354 | { |
359 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | 355 | Dictionary<string, object> sendData = new Dictionary<string, object>(); |
360 | 356 | ||
@@ -391,9 +387,6 @@ namespace OpenSim.Services.Connectors | |||
391 | GridRegion rinfo = new GridRegion((Dictionary<string, object>)r); | 387 | GridRegion rinfo = new GridRegion((Dictionary<string, object>)r); |
392 | rinfos.Add(rinfo); | 388 | rinfos.Add(rinfo); |
393 | } | 389 | } |
394 | else | ||
395 | m_log.DebugFormat("[GRID CONNECTOR]: GetRegionsByName {0}, {1}, {2} received invalid response", | ||
396 | scopeID, name, maxNumber); | ||
397 | } | 390 | } |
398 | } | 391 | } |
399 | else | 392 | else |
@@ -406,7 +399,7 @@ namespace OpenSim.Services.Connectors | |||
406 | return rinfos; | 399 | return rinfos; |
407 | } | 400 | } |
408 | 401 | ||
409 | public virtual List<GridRegion> GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax) | 402 | public List<GridRegion> GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax) |
410 | { | 403 | { |
411 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | 404 | Dictionary<string, object> sendData = new Dictionary<string, object>(); |
412 | 405 | ||
@@ -460,6 +453,203 @@ namespace OpenSim.Services.Connectors | |||
460 | return rinfos; | 453 | return rinfos; |
461 | } | 454 | } |
462 | 455 | ||
456 | public List<GridRegion> GetDefaultRegions(UUID scopeID) | ||
457 | { | ||
458 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
459 | |||
460 | sendData["SCOPEID"] = scopeID.ToString(); | ||
461 | |||
462 | sendData["METHOD"] = "get_default_regions"; | ||
463 | |||
464 | List<GridRegion> rinfos = new List<GridRegion>(); | ||
465 | string reply = string.Empty; | ||
466 | try | ||
467 | { | ||
468 | reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
469 | m_ServerURI + "/grid", | ||
470 | ServerUtils.BuildQueryString(sendData)); | ||
471 | |||
472 | //m_log.DebugFormat("[GRID CONNECTOR]: reply was {0}", reply); | ||
473 | } | ||
474 | catch (Exception e) | ||
475 | { | ||
476 | m_log.DebugFormat("[GRID CONNECTOR]: Exception when contacting grid server: {0}", e.Message); | ||
477 | return rinfos; | ||
478 | } | ||
479 | |||
480 | if (reply != string.Empty) | ||
481 | { | ||
482 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
483 | |||
484 | if (replyData != null) | ||
485 | { | ||
486 | Dictionary<string, object>.ValueCollection rinfosList = replyData.Values; | ||
487 | foreach (object r in rinfosList) | ||
488 | { | ||
489 | if (r is Dictionary<string, object>) | ||
490 | { | ||
491 | GridRegion rinfo = new GridRegion((Dictionary<string, object>)r); | ||
492 | rinfos.Add(rinfo); | ||
493 | } | ||
494 | } | ||
495 | } | ||
496 | else | ||
497 | m_log.DebugFormat("[GRID CONNECTOR]: GetDefaultRegions {0} received null response", | ||
498 | scopeID); | ||
499 | } | ||
500 | else | ||
501 | m_log.DebugFormat("[GRID CONNECTOR]: GetDefaultRegions received null reply"); | ||
502 | |||
503 | return rinfos; | ||
504 | } | ||
505 | |||
506 | public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y) | ||
507 | { | ||
508 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
509 | |||
510 | sendData["SCOPEID"] = scopeID.ToString(); | ||
511 | sendData["X"] = x.ToString(); | ||
512 | sendData["Y"] = y.ToString(); | ||
513 | |||
514 | sendData["METHOD"] = "get_fallback_regions"; | ||
515 | |||
516 | List<GridRegion> rinfos = new List<GridRegion>(); | ||
517 | string reply = string.Empty; | ||
518 | try | ||
519 | { | ||
520 | reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
521 | m_ServerURI + "/grid", | ||
522 | ServerUtils.BuildQueryString(sendData)); | ||
523 | |||
524 | //m_log.DebugFormat("[GRID CONNECTOR]: reply was {0}", reply); | ||
525 | } | ||
526 | catch (Exception e) | ||
527 | { | ||
528 | m_log.DebugFormat("[GRID CONNECTOR]: Exception when contacting grid server: {0}", e.Message); | ||
529 | return rinfos; | ||
530 | } | ||
531 | |||
532 | if (reply != string.Empty) | ||
533 | { | ||
534 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
535 | |||
536 | if (replyData != null) | ||
537 | { | ||
538 | Dictionary<string, object>.ValueCollection rinfosList = replyData.Values; | ||
539 | foreach (object r in rinfosList) | ||
540 | { | ||
541 | if (r is Dictionary<string, object>) | ||
542 | { | ||
543 | GridRegion rinfo = new GridRegion((Dictionary<string, object>)r); | ||
544 | rinfos.Add(rinfo); | ||
545 | } | ||
546 | } | ||
547 | } | ||
548 | else | ||
549 | m_log.DebugFormat("[GRID CONNECTOR]: GetFallbackRegions {0}, {1}-{2} received null response", | ||
550 | scopeID, x, y); | ||
551 | } | ||
552 | else | ||
553 | m_log.DebugFormat("[GRID CONNECTOR]: GetFallbackRegions received null reply"); | ||
554 | |||
555 | return rinfos; | ||
556 | } | ||
557 | |||
558 | public List<GridRegion> GetHyperlinks(UUID scopeID) | ||
559 | { | ||
560 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
561 | |||
562 | sendData["SCOPEID"] = scopeID.ToString(); | ||
563 | |||
564 | sendData["METHOD"] = "get_hyperlinks"; | ||
565 | |||
566 | List<GridRegion> rinfos = new List<GridRegion>(); | ||
567 | string reply = string.Empty; | ||
568 | try | ||
569 | { | ||
570 | reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
571 | m_ServerURI + "/grid", | ||
572 | ServerUtils.BuildQueryString(sendData)); | ||
573 | |||
574 | //m_log.DebugFormat("[GRID CONNECTOR]: reply was {0}", reply); | ||
575 | } | ||
576 | catch (Exception e) | ||
577 | { | ||
578 | m_log.DebugFormat("[GRID CONNECTOR]: Exception when contacting grid server: {0}", e.Message); | ||
579 | return rinfos; | ||
580 | } | ||
581 | |||
582 | if (reply != string.Empty) | ||
583 | { | ||
584 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
585 | |||
586 | if (replyData != null) | ||
587 | { | ||
588 | Dictionary<string, object>.ValueCollection rinfosList = replyData.Values; | ||
589 | foreach (object r in rinfosList) | ||
590 | { | ||
591 | if (r is Dictionary<string, object>) | ||
592 | { | ||
593 | GridRegion rinfo = new GridRegion((Dictionary<string, object>)r); | ||
594 | rinfos.Add(rinfo); | ||
595 | } | ||
596 | } | ||
597 | } | ||
598 | else | ||
599 | m_log.DebugFormat("[GRID CONNECTOR]: GetHyperlinks {0} received null response", | ||
600 | scopeID); | ||
601 | } | ||
602 | else | ||
603 | m_log.DebugFormat("[GRID CONNECTOR]: GetHyperlinks received null reply"); | ||
604 | |||
605 | return rinfos; | ||
606 | } | ||
607 | |||
608 | public int GetRegionFlags(UUID scopeID, UUID regionID) | ||
609 | { | ||
610 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
611 | |||
612 | sendData["SCOPEID"] = scopeID.ToString(); | ||
613 | sendData["REGIONID"] = regionID.ToString(); | ||
614 | |||
615 | sendData["METHOD"] = "get_region_flags"; | ||
616 | |||
617 | string reply = string.Empty; | ||
618 | try | ||
619 | { | ||
620 | reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
621 | m_ServerURI + "/grid", | ||
622 | ServerUtils.BuildQueryString(sendData)); | ||
623 | } | ||
624 | catch (Exception e) | ||
625 | { | ||
626 | m_log.DebugFormat("[GRID CONNECTOR]: Exception when contacting grid server: {0}", e.Message); | ||
627 | return -1; | ||
628 | } | ||
629 | |||
630 | int flags = -1; | ||
631 | |||
632 | if (reply != string.Empty) | ||
633 | { | ||
634 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
635 | |||
636 | if ((replyData != null) && replyData.ContainsKey("result") && (replyData["result"] != null)) | ||
637 | { | ||
638 | Int32.TryParse((string)replyData["result"], out flags); | ||
639 | //else | ||
640 | // m_log.DebugFormat("[GRID CONNECTOR]: GetRegionFlags {0}, {1} received wrong type {2}", | ||
641 | // scopeID, regionID, replyData["result"].GetType()); | ||
642 | } | ||
643 | else | ||
644 | m_log.DebugFormat("[GRID CONNECTOR]: GetRegionFlags {0}, {1} received null response", | ||
645 | scopeID, regionID); | ||
646 | } | ||
647 | else | ||
648 | m_log.DebugFormat("[GRID CONNECTOR]: GetRegionFlags received null reply"); | ||
649 | |||
650 | return flags; | ||
651 | } | ||
652 | |||
463 | #endregion | 653 | #endregion |
464 | 654 | ||
465 | } | 655 | } |
diff --git a/OpenSim/Services/Connectors/Grid/HypergridServiceConnector.cs b/OpenSim/Services/Connectors/Grid/HypergridServiceConnector.cs deleted file mode 100644 index 7098b07..0000000 --- a/OpenSim/Services/Connectors/Grid/HypergridServiceConnector.cs +++ /dev/null | |||
@@ -1,254 +0,0 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Text; | ||
32 | using System.Drawing; | ||
33 | using System.Net; | ||
34 | using System.Reflection; | ||
35 | using OpenSim.Services.Interfaces; | ||
36 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
37 | |||
38 | using OpenSim.Framework; | ||
39 | |||
40 | using OpenMetaverse; | ||
41 | using OpenMetaverse.Imaging; | ||
42 | using log4net; | ||
43 | using Nwc.XmlRpc; | ||
44 | |||
45 | namespace OpenSim.Services.Connectors.Grid | ||
46 | { | ||
47 | public class HypergridServiceConnector | ||
48 | { | ||
49 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
50 | |||
51 | private IAssetService m_AssetService; | ||
52 | |||
53 | public HypergridServiceConnector(IAssetService assService) | ||
54 | { | ||
55 | m_AssetService = assService; | ||
56 | } | ||
57 | |||
58 | public UUID LinkRegion(GridRegion info, out ulong realHandle) | ||
59 | { | ||
60 | UUID uuid = UUID.Zero; | ||
61 | realHandle = 0; | ||
62 | |||
63 | Hashtable hash = new Hashtable(); | ||
64 | hash["region_name"] = info.RegionName; | ||
65 | |||
66 | IList paramList = new ArrayList(); | ||
67 | paramList.Add(hash); | ||
68 | |||
69 | XmlRpcRequest request = new XmlRpcRequest("link_region", paramList); | ||
70 | string uri = "http://" + info.ExternalEndPoint.Address + ":" + info.HttpPort + "/"; | ||
71 | m_log.Debug("[HGrid]: Linking to " + uri); | ||
72 | XmlRpcResponse response = null; | ||
73 | try | ||
74 | { | ||
75 | response = request.Send(uri, 10000); | ||
76 | } | ||
77 | catch (Exception e) | ||
78 | { | ||
79 | m_log.Debug("[HGrid]: Exception " + e.Message); | ||
80 | return uuid; | ||
81 | } | ||
82 | |||
83 | if (response.IsFault) | ||
84 | { | ||
85 | m_log.ErrorFormat("[HGrid]: remote call returned an error: {0}", response.FaultString); | ||
86 | } | ||
87 | else | ||
88 | { | ||
89 | hash = (Hashtable)response.Value; | ||
90 | //foreach (Object o in hash) | ||
91 | // m_log.Debug(">> " + ((DictionaryEntry)o).Key + ":" + ((DictionaryEntry)o).Value); | ||
92 | try | ||
93 | { | ||
94 | UUID.TryParse((string)hash["uuid"], out uuid); | ||
95 | //m_log.Debug(">> HERE, uuid: " + uuid); | ||
96 | info.RegionID = uuid; | ||
97 | if ((string)hash["handle"] != null) | ||
98 | { | ||
99 | realHandle = Convert.ToUInt64((string)hash["handle"]); | ||
100 | //m_log.Debug(">> HERE, realHandle: " + realHandle); | ||
101 | } | ||
102 | //if (hash["region_image"] != null) | ||
103 | //{ | ||
104 | // UUID img = UUID.Zero; | ||
105 | // UUID.TryParse((string)hash["region_image"], out img); | ||
106 | // info.RegionSettings.TerrainImageID = img; | ||
107 | //} | ||
108 | if (hash["region_name"] != null) | ||
109 | { | ||
110 | info.RegionName = (string)hash["region_name"]; | ||
111 | //m_log.Debug(">> " + info.RegionName); | ||
112 | } | ||
113 | if (hash["internal_port"] != null) | ||
114 | { | ||
115 | int port = Convert.ToInt32((string)hash["internal_port"]); | ||
116 | info.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), port); | ||
117 | //m_log.Debug(">> " + info.InternalEndPoint.ToString()); | ||
118 | } | ||
119 | |||
120 | } | ||
121 | catch (Exception e) | ||
122 | { | ||
123 | m_log.Error("[HGrid]: Got exception while parsing hyperlink response " + e.StackTrace); | ||
124 | } | ||
125 | } | ||
126 | return uuid; | ||
127 | } | ||
128 | |||
129 | public void GetMapImage(GridRegion info) | ||
130 | { | ||
131 | try | ||
132 | { | ||
133 | string regionimage = "regionImage" + info.RegionID.ToString(); | ||
134 | regionimage = regionimage.Replace("-", ""); | ||
135 | |||
136 | WebClient c = new WebClient(); | ||
137 | string uri = "http://" + info.ExternalHostName + ":" + info.HttpPort + "/index.php?method=" + regionimage; | ||
138 | //m_log.Debug("JPEG: " + uri); | ||
139 | c.DownloadFile(uri, info.RegionID.ToString() + ".jpg"); | ||
140 | Bitmap m = new Bitmap(info.RegionID.ToString() + ".jpg"); | ||
141 | //m_log.Debug("Size: " + m.PhysicalDimension.Height + "-" + m.PhysicalDimension.Width); | ||
142 | byte[] imageData = OpenJPEG.EncodeFromImage(m, true); | ||
143 | AssetBase ass = new AssetBase(UUID.Random(), "region " + info.RegionID.ToString(), (sbyte)AssetType.Texture); | ||
144 | |||
145 | // !!! for now | ||
146 | //info.RegionSettings.TerrainImageID = ass.FullID; | ||
147 | |||
148 | ass.Temporary = true; | ||
149 | ass.Local = true; | ||
150 | ass.Data = imageData; | ||
151 | |||
152 | m_AssetService.Store(ass); | ||
153 | |||
154 | // finally | ||
155 | info.TerrainImage = ass.FullID; | ||
156 | |||
157 | } | ||
158 | catch // LEGIT: Catching problems caused by OpenJPEG p/invoke | ||
159 | { | ||
160 | m_log.Warn("[HGrid]: Failed getting/storing map image, because it is probably already in the cache"); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | public bool InformRegionOfUser(GridRegion regInfo, AgentCircuitData agentData, GridRegion home, string userServer, string assetServer, string inventoryServer) | ||
165 | { | ||
166 | string capsPath = agentData.CapsPath; | ||
167 | Hashtable loginParams = new Hashtable(); | ||
168 | loginParams["session_id"] = agentData.SessionID.ToString(); | ||
169 | |||
170 | loginParams["firstname"] = agentData.firstname; | ||
171 | loginParams["lastname"] = agentData.lastname; | ||
172 | |||
173 | loginParams["agent_id"] = agentData.AgentID.ToString(); | ||
174 | loginParams["circuit_code"] = agentData.circuitcode.ToString(); | ||
175 | loginParams["startpos_x"] = agentData.startpos.X.ToString(); | ||
176 | loginParams["startpos_y"] = agentData.startpos.Y.ToString(); | ||
177 | loginParams["startpos_z"] = agentData.startpos.Z.ToString(); | ||
178 | loginParams["caps_path"] = capsPath; | ||
179 | |||
180 | if (home != null) | ||
181 | { | ||
182 | loginParams["region_uuid"] = home.RegionID.ToString(); | ||
183 | loginParams["regionhandle"] = home.RegionHandle.ToString(); | ||
184 | loginParams["home_address"] = home.ExternalHostName; | ||
185 | loginParams["home_port"] = home.HttpPort.ToString(); | ||
186 | loginParams["internal_port"] = home.InternalEndPoint.Port.ToString(); | ||
187 | |||
188 | m_log.Debug(" --------- Home -------"); | ||
189 | m_log.Debug(" >> " + loginParams["home_address"] + " <<"); | ||
190 | m_log.Debug(" >> " + loginParams["region_uuid"] + " <<"); | ||
191 | m_log.Debug(" >> " + loginParams["regionhandle"] + " <<"); | ||
192 | m_log.Debug(" >> " + loginParams["home_port"] + " <<"); | ||
193 | m_log.Debug(" --------- ------------ -------"); | ||
194 | } | ||
195 | else | ||
196 | m_log.WarnFormat("[HGrid]: Home region not found for {0} {1}", agentData.firstname, agentData.lastname); | ||
197 | |||
198 | loginParams["userserver_id"] = userServer; | ||
199 | loginParams["assetserver_id"] = assetServer; | ||
200 | loginParams["inventoryserver_id"] = inventoryServer; | ||
201 | |||
202 | |||
203 | ArrayList SendParams = new ArrayList(); | ||
204 | SendParams.Add(loginParams); | ||
205 | |||
206 | // Send | ||
207 | string uri = "http://" + regInfo.ExternalHostName + ":" + regInfo.HttpPort + "/"; | ||
208 | //m_log.Debug("XXX uri: " + uri); | ||
209 | XmlRpcRequest request = new XmlRpcRequest("expect_hg_user", SendParams); | ||
210 | XmlRpcResponse reply; | ||
211 | try | ||
212 | { | ||
213 | reply = request.Send(uri, 6000); | ||
214 | } | ||
215 | catch (Exception e) | ||
216 | { | ||
217 | m_log.Warn("[HGrid]: Failed to notify region about user. Reason: " + e.Message); | ||
218 | return false; | ||
219 | } | ||
220 | |||
221 | if (!reply.IsFault) | ||
222 | { | ||
223 | bool responseSuccess = true; | ||
224 | if (reply.Value != null) | ||
225 | { | ||
226 | Hashtable resp = (Hashtable)reply.Value; | ||
227 | if (resp.ContainsKey("success")) | ||
228 | { | ||
229 | if ((string)resp["success"] == "FALSE") | ||
230 | { | ||
231 | responseSuccess = false; | ||
232 | } | ||
233 | } | ||
234 | } | ||
235 | if (responseSuccess) | ||
236 | { | ||
237 | m_log.Info("[HGrid]: Successfully informed remote region about user " + agentData.AgentID); | ||
238 | return true; | ||
239 | } | ||
240 | else | ||
241 | { | ||
242 | m_log.ErrorFormat("[HGrid]: Region responded that it is not available to receive clients"); | ||
243 | return false; | ||
244 | } | ||
245 | } | ||
246 | else | ||
247 | { | ||
248 | m_log.ErrorFormat("[HGrid]: XmlRpc request to region failed with message {0}, code {1} ", reply.FaultString, reply.FaultCode); | ||
249 | return false; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | } | ||
254 | } | ||
diff --git a/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs b/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs new file mode 100644 index 0000000..738cc06 --- /dev/null +++ b/OpenSim/Services/Connectors/GridUser/GridUserServiceConnector.cs | |||
@@ -0,0 +1,227 @@ | |||
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 | |||
28 | using log4net; | ||
29 | using System; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Reflection; | ||
33 | using Nini.Config; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Communications; | ||
36 | using OpenSim.Services.Interfaces; | ||
37 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
38 | using OpenSim.Server.Base; | ||
39 | using OpenMetaverse; | ||
40 | |||
41 | namespace OpenSim.Services.Connectors | ||
42 | { | ||
43 | public class GridUserServicesConnector : IGridUserService | ||
44 | { | ||
45 | private static readonly ILog m_log = | ||
46 | LogManager.GetLogger( | ||
47 | MethodBase.GetCurrentMethod().DeclaringType); | ||
48 | |||
49 | private string m_ServerURI = String.Empty; | ||
50 | |||
51 | public GridUserServicesConnector() | ||
52 | { | ||
53 | } | ||
54 | |||
55 | public GridUserServicesConnector(string serverURI) | ||
56 | { | ||
57 | m_ServerURI = serverURI.TrimEnd('/'); | ||
58 | } | ||
59 | |||
60 | public GridUserServicesConnector(IConfigSource source) | ||
61 | { | ||
62 | Initialise(source); | ||
63 | } | ||
64 | |||
65 | public virtual void Initialise(IConfigSource source) | ||
66 | { | ||
67 | IConfig gridConfig = source.Configs["GridUserService"]; | ||
68 | if (gridConfig == null) | ||
69 | { | ||
70 | m_log.Error("[GRID USER CONNECTOR]: GridUserService missing from OpenSim.ini"); | ||
71 | throw new Exception("GridUser connector init error"); | ||
72 | } | ||
73 | |||
74 | string serviceURI = gridConfig.GetString("GridUserServerURI", | ||
75 | String.Empty); | ||
76 | |||
77 | if (serviceURI == String.Empty) | ||
78 | { | ||
79 | m_log.Error("[GRID USER CONNECTOR]: No Server URI named in section GridUserService"); | ||
80 | throw new Exception("GridUser connector init error"); | ||
81 | } | ||
82 | m_ServerURI = serviceURI; | ||
83 | } | ||
84 | |||
85 | |||
86 | #region IGridUserService | ||
87 | |||
88 | |||
89 | public GridUserInfo LoggedIn(string userID) | ||
90 | { | ||
91 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
92 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
93 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
94 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
95 | sendData["METHOD"] = "loggedin"; | ||
96 | |||
97 | sendData["UserID"] = userID; | ||
98 | |||
99 | return Get(sendData); | ||
100 | |||
101 | } | ||
102 | |||
103 | public bool LoggedOut(string userID, UUID sessionID, UUID region, Vector3 position, Vector3 lookat) | ||
104 | { | ||
105 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
106 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
107 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
108 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
109 | sendData["METHOD"] = "loggedout"; | ||
110 | |||
111 | return Set(sendData, userID, region, position, lookat); | ||
112 | } | ||
113 | |||
114 | public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt) | ||
115 | { | ||
116 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
117 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
118 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
119 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
120 | sendData["METHOD"] = "sethome"; | ||
121 | |||
122 | return Set(sendData, userID, regionID, position, lookAt); | ||
123 | } | ||
124 | |||
125 | public bool SetLastPosition(string userID, UUID sessionID, UUID regionID, Vector3 position, Vector3 lookAt) | ||
126 | { | ||
127 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
128 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
129 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
130 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
131 | sendData["METHOD"] = "setposition"; | ||
132 | |||
133 | return Set(sendData, userID, regionID, position, lookAt); | ||
134 | } | ||
135 | |||
136 | public GridUserInfo GetGridUserInfo(string userID) | ||
137 | { | ||
138 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
139 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
140 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
141 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
142 | sendData["METHOD"] = "getgriduserinfo"; | ||
143 | |||
144 | sendData["UserID"] = userID; | ||
145 | |||
146 | return Get(sendData); | ||
147 | } | ||
148 | |||
149 | #endregion | ||
150 | |||
151 | protected bool Set(Dictionary<string, object> sendData, string userID, UUID regionID, Vector3 position, Vector3 lookAt) | ||
152 | { | ||
153 | sendData["UserID"] = userID; | ||
154 | sendData["RegionID"] = regionID.ToString(); | ||
155 | sendData["Position"] = position.ToString(); | ||
156 | sendData["LookAt"] = lookAt.ToString(); | ||
157 | |||
158 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
159 | // m_log.DebugFormat("[GRID USER CONNECTOR]: queryString = {0}", reqString); | ||
160 | try | ||
161 | { | ||
162 | string reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
163 | m_ServerURI + "/griduser", | ||
164 | reqString); | ||
165 | if (reply != string.Empty) | ||
166 | { | ||
167 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
168 | |||
169 | if (replyData.ContainsKey("result")) | ||
170 | { | ||
171 | if (replyData["result"].ToString().ToLower() == "success") | ||
172 | return true; | ||
173 | else | ||
174 | return false; | ||
175 | } | ||
176 | else | ||
177 | m_log.DebugFormat("[GRID USER CONNECTOR]: SetPosition reply data does not contain result field"); | ||
178 | |||
179 | } | ||
180 | else | ||
181 | m_log.DebugFormat("[GRID USER CONNECTOR]: SetPosition received empty reply"); | ||
182 | } | ||
183 | catch (Exception e) | ||
184 | { | ||
185 | m_log.DebugFormat("[GRID USER CONNECTOR]: Exception when contacting grid user server: {0}", e.Message); | ||
186 | } | ||
187 | |||
188 | return false; | ||
189 | } | ||
190 | |||
191 | protected GridUserInfo Get(Dictionary<string, object> sendData) | ||
192 | { | ||
193 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
194 | // m_log.DebugFormat("[GRID USER CONNECTOR]: queryString = {0}", reqString); | ||
195 | try | ||
196 | { | ||
197 | string reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
198 | m_ServerURI + "/griduser", | ||
199 | reqString); | ||
200 | if (reply != string.Empty) | ||
201 | { | ||
202 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
203 | GridUserInfo guinfo = null; | ||
204 | |||
205 | if ((replyData != null) && replyData.ContainsKey("result") && (replyData["result"] != null)) | ||
206 | { | ||
207 | if (replyData["result"] is Dictionary<string, object>) | ||
208 | guinfo = new GridUserInfo((Dictionary<string, object>)replyData["result"]); | ||
209 | } | ||
210 | |||
211 | return guinfo; | ||
212 | |||
213 | } | ||
214 | else | ||
215 | m_log.DebugFormat("[GRID USER CONNECTOR]: Loggedin received empty reply"); | ||
216 | } | ||
217 | catch (Exception e) | ||
218 | { | ||
219 | m_log.DebugFormat("[GRID USER CONNECTOR]: Exception when contacting grid user server: {0}", e.Message); | ||
220 | } | ||
221 | |||
222 | return null; | ||
223 | |||
224 | } | ||
225 | |||
226 | } | ||
227 | } | ||
diff --git a/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs new file mode 100644 index 0000000..bc0bc54 --- /dev/null +++ b/OpenSim/Services/Connectors/Hypergrid/GatekeeperServiceConnector.cs | |||
@@ -0,0 +1,334 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Drawing; | ||
32 | using System.IO; | ||
33 | using System.Net; | ||
34 | using System.Reflection; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Services.Interfaces; | ||
37 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
38 | using OpenMetaverse; | ||
39 | using OpenMetaverse.Imaging; | ||
40 | using OpenMetaverse.StructuredData; | ||
41 | using Nwc.XmlRpc; | ||
42 | using log4net; | ||
43 | |||
44 | using OpenSim.Services.Connectors.Simulation; | ||
45 | |||
46 | namespace OpenSim.Services.Connectors.Hypergrid | ||
47 | { | ||
48 | public class GatekeeperServiceConnector : SimulationServiceConnector | ||
49 | { | ||
50 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
51 | |||
52 | private static UUID m_HGMapImage = new UUID("00000000-0000-1111-9999-000000000013"); | ||
53 | |||
54 | private IAssetService m_AssetService; | ||
55 | |||
56 | public GatekeeperServiceConnector() : base() | ||
57 | { | ||
58 | } | ||
59 | |||
60 | public GatekeeperServiceConnector(IAssetService assService) | ||
61 | { | ||
62 | m_AssetService = assService; | ||
63 | } | ||
64 | |||
65 | protected override string AgentPath() | ||
66 | { | ||
67 | return "foreignagent/"; | ||
68 | } | ||
69 | |||
70 | protected override string ObjectPath() | ||
71 | { | ||
72 | return "foreignobject/"; | ||
73 | } | ||
74 | |||
75 | public bool LinkRegion(GridRegion info, out UUID regionID, out ulong realHandle, out string externalName, out string imageURL, out string reason) | ||
76 | { | ||
77 | regionID = UUID.Zero; | ||
78 | imageURL = string.Empty; | ||
79 | realHandle = 0; | ||
80 | externalName = string.Empty; | ||
81 | reason = string.Empty; | ||
82 | |||
83 | Hashtable hash = new Hashtable(); | ||
84 | hash["region_name"] = info.RegionName; | ||
85 | |||
86 | IList paramList = new ArrayList(); | ||
87 | paramList.Add(hash); | ||
88 | |||
89 | XmlRpcRequest request = new XmlRpcRequest("link_region", paramList); | ||
90 | m_log.Debug("[GATEKEEPER SERVICE CONNECTOR]: Linking to " + info.ServerURI); | ||
91 | XmlRpcResponse response = null; | ||
92 | try | ||
93 | { | ||
94 | response = request.Send(info.ServerURI, 10000); | ||
95 | } | ||
96 | catch (Exception e) | ||
97 | { | ||
98 | m_log.Debug("[GATEKEEPER SERVICE CONNECTOR]: Exception " + e.Message); | ||
99 | reason = "Error contacting remote server"; | ||
100 | return false; | ||
101 | } | ||
102 | |||
103 | if (response.IsFault) | ||
104 | { | ||
105 | reason = response.FaultString; | ||
106 | m_log.ErrorFormat("[GATEKEEPER SERVICE CONNECTOR]: remote call returned an error: {0}", response.FaultString); | ||
107 | return false; | ||
108 | } | ||
109 | |||
110 | hash = (Hashtable)response.Value; | ||
111 | //foreach (Object o in hash) | ||
112 | // m_log.Debug(">> " + ((DictionaryEntry)o).Key + ":" + ((DictionaryEntry)o).Value); | ||
113 | try | ||
114 | { | ||
115 | bool success = false; | ||
116 | Boolean.TryParse((string)hash["result"], out success); | ||
117 | if (success) | ||
118 | { | ||
119 | UUID.TryParse((string)hash["uuid"], out regionID); | ||
120 | //m_log.Debug(">> HERE, uuid: " + regionID); | ||
121 | if ((string)hash["handle"] != null) | ||
122 | { | ||
123 | realHandle = Convert.ToUInt64((string)hash["handle"]); | ||
124 | //m_log.Debug(">> HERE, realHandle: " + realHandle); | ||
125 | } | ||
126 | if (hash["region_image"] != null) { | ||
127 | imageURL = (string)hash["region_image"]; | ||
128 | //m_log.Debug(">> HERE, imageURL: " + imageURL); | ||
129 | } | ||
130 | if (hash["external_name"] != null) { | ||
131 | externalName = (string)hash["external_name"]; | ||
132 | //m_log.Debug(">> HERE, externalName: " + externalName); | ||
133 | } | ||
134 | } | ||
135 | |||
136 | } | ||
137 | catch (Exception e) | ||
138 | { | ||
139 | reason = "Error parsing return arguments"; | ||
140 | m_log.Error("[GATEKEEPER SERVICE CONNECTOR]: Got exception while parsing hyperlink response " + e.StackTrace); | ||
141 | return false; | ||
142 | } | ||
143 | |||
144 | return true; | ||
145 | } | ||
146 | |||
147 | public UUID GetMapImage(UUID regionID, string imageURL, string storagePath) | ||
148 | { | ||
149 | if (m_AssetService == null) | ||
150 | { | ||
151 | m_log.DebugFormat("[GATEKEEPER SERVICE CONNECTOR]: No AssetService defined. Map tile not retrieved."); | ||
152 | return m_HGMapImage; | ||
153 | } | ||
154 | |||
155 | UUID mapTile = m_HGMapImage; | ||
156 | string filename = string.Empty; | ||
157 | Bitmap bitmap = null; | ||
158 | try | ||
159 | { | ||
160 | WebClient c = new WebClient(); | ||
161 | //m_log.Debug("JPEG: " + imageURL); | ||
162 | string name = regionID.ToString(); | ||
163 | filename = Path.Combine(storagePath, name + ".jpg"); | ||
164 | c.DownloadFile(imageURL, filename); | ||
165 | bitmap = new Bitmap(filename); | ||
166 | //m_log.Debug("Size: " + m.PhysicalDimension.Height + "-" + m.PhysicalDimension.Width); | ||
167 | byte[] imageData = OpenJPEG.EncodeFromImage(bitmap, true); | ||
168 | AssetBase ass = new AssetBase(UUID.Random(), "region " + name, (sbyte)AssetType.Texture, regionID.ToString()); | ||
169 | |||
170 | // !!! for now | ||
171 | //info.RegionSettings.TerrainImageID = ass.FullID; | ||
172 | |||
173 | ass.Data = imageData; | ||
174 | |||
175 | m_AssetService.Store(ass); | ||
176 | |||
177 | // finally | ||
178 | mapTile = ass.FullID; | ||
179 | } | ||
180 | catch // LEGIT: Catching problems caused by OpenJPEG p/invoke | ||
181 | { | ||
182 | m_log.Info("[GATEKEEPER SERVICE CONNECTOR]: Failed getting/storing map image, because it is probably already in the cache"); | ||
183 | } | ||
184 | return mapTile; | ||
185 | } | ||
186 | |||
187 | public GridRegion GetHyperlinkRegion(GridRegion gatekeeper, UUID regionID) | ||
188 | { | ||
189 | Hashtable hash = new Hashtable(); | ||
190 | hash["region_uuid"] = regionID.ToString(); | ||
191 | |||
192 | IList paramList = new ArrayList(); | ||
193 | paramList.Add(hash); | ||
194 | |||
195 | XmlRpcRequest request = new XmlRpcRequest("get_region", paramList); | ||
196 | m_log.Debug("[GATEKEEPER SERVICE CONNECTOR]: contacting " + gatekeeper.ServerURI); | ||
197 | XmlRpcResponse response = null; | ||
198 | try | ||
199 | { | ||
200 | response = request.Send(gatekeeper.ServerURI, 10000); | ||
201 | } | ||
202 | catch (Exception e) | ||
203 | { | ||
204 | m_log.Debug("[GATEKEEPER SERVICE CONNECTOR]: Exception " + e.Message); | ||
205 | return null; | ||
206 | } | ||
207 | |||
208 | if (response.IsFault) | ||
209 | { | ||
210 | m_log.ErrorFormat("[GATEKEEPER SERVICE CONNECTOR]: remote call returned an error: {0}", response.FaultString); | ||
211 | return null; | ||
212 | } | ||
213 | |||
214 | hash = (Hashtable)response.Value; | ||
215 | //foreach (Object o in hash) | ||
216 | // m_log.Debug(">> " + ((DictionaryEntry)o).Key + ":" + ((DictionaryEntry)o).Value); | ||
217 | try | ||
218 | { | ||
219 | bool success = false; | ||
220 | Boolean.TryParse((string)hash["result"], out success); | ||
221 | if (success) | ||
222 | { | ||
223 | GridRegion region = new GridRegion(); | ||
224 | |||
225 | UUID.TryParse((string)hash["uuid"], out region.RegionID); | ||
226 | //m_log.Debug(">> HERE, uuid: " + region.RegionID); | ||
227 | int n = 0; | ||
228 | if (hash["x"] != null) | ||
229 | { | ||
230 | Int32.TryParse((string)hash["x"], out n); | ||
231 | region.RegionLocX = n; | ||
232 | //m_log.Debug(">> HERE, x: " + region.RegionLocX); | ||
233 | } | ||
234 | if (hash["y"] != null) | ||
235 | { | ||
236 | Int32.TryParse((string)hash["y"], out n); | ||
237 | region.RegionLocY = n; | ||
238 | //m_log.Debug(">> HERE, y: " + region.RegionLocY); | ||
239 | } | ||
240 | if (hash["region_name"] != null) | ||
241 | { | ||
242 | region.RegionName = (string)hash["region_name"]; | ||
243 | //m_log.Debug(">> HERE, region_name: " + region.RegionName); | ||
244 | } | ||
245 | if (hash["hostname"] != null) { | ||
246 | region.ExternalHostName = (string)hash["hostname"]; | ||
247 | //m_log.Debug(">> HERE, hostname: " + region.ExternalHostName); | ||
248 | } | ||
249 | if (hash["http_port"] != null) | ||
250 | { | ||
251 | uint p = 0; | ||
252 | UInt32.TryParse((string)hash["http_port"], out p); | ||
253 | region.HttpPort = p; | ||
254 | //m_log.Debug(">> HERE, http_port: " + region.HttpPort); | ||
255 | } | ||
256 | if (hash["internal_port"] != null) | ||
257 | { | ||
258 | int p = 0; | ||
259 | Int32.TryParse((string)hash["internal_port"], out p); | ||
260 | region.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), p); | ||
261 | //m_log.Debug(">> HERE, internal_port: " + region.InternalEndPoint); | ||
262 | } | ||
263 | |||
264 | if (hash["server_uri"] != null) | ||
265 | { | ||
266 | region.ServerURI = (string) hash["server_uri"]; | ||
267 | //m_log.Debug(">> HERE, server_uri: " + region.ServerURI); | ||
268 | } | ||
269 | |||
270 | // Successful return | ||
271 | return region; | ||
272 | } | ||
273 | |||
274 | } | ||
275 | catch (Exception e) | ||
276 | { | ||
277 | m_log.Error("[GATEKEEPER SERVICE CONNECTOR]: Got exception while parsing hyperlink response " + e.StackTrace); | ||
278 | return null; | ||
279 | } | ||
280 | |||
281 | return null; | ||
282 | } | ||
283 | |||
284 | public bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint flags, out string myipaddress, out string reason) | ||
285 | { | ||
286 | // m_log.DebugFormat("[GATEKEEPER SERVICE CONNECTOR]: CreateAgent start"); | ||
287 | |||
288 | myipaddress = String.Empty; | ||
289 | reason = String.Empty; | ||
290 | |||
291 | if (destination == null) | ||
292 | { | ||
293 | m_log.Debug("[GATEKEEPER SERVICE CONNECTOR]: Given destination is null"); | ||
294 | return false; | ||
295 | } | ||
296 | |||
297 | string uri = destination.ServerURI + AgentPath() + aCircuit.AgentID + "/"; | ||
298 | |||
299 | try | ||
300 | { | ||
301 | OSDMap args = aCircuit.PackAgentCircuitData(); | ||
302 | |||
303 | args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); | ||
304 | args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); | ||
305 | args["destination_name"] = OSD.FromString(destination.RegionName); | ||
306 | args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); | ||
307 | args["teleport_flags"] = OSD.FromString(flags.ToString()); | ||
308 | |||
309 | OSDMap result = WebUtil.PostToService(uri, args, 20000); | ||
310 | if (result["Success"].AsBoolean()) | ||
311 | { | ||
312 | OSDMap unpacked = (OSDMap)result["_Result"]; | ||
313 | |||
314 | if (unpacked != null) | ||
315 | { | ||
316 | reason = unpacked["reason"].AsString(); | ||
317 | myipaddress = unpacked["your_ip"].AsString(); | ||
318 | return unpacked["success"].AsBoolean(); | ||
319 | } | ||
320 | } | ||
321 | |||
322 | reason = result["Message"] != null ? result["Message"].AsString() : "error"; | ||
323 | return false; | ||
324 | } | ||
325 | catch (Exception e) | ||
326 | { | ||
327 | m_log.Warn("[REMOTE SIMULATION CONNECTOR]: CreateAgent failed with exception: " + e.ToString()); | ||
328 | reason = e.Message; | ||
329 | } | ||
330 | |||
331 | return false; | ||
332 | } | ||
333 | } | ||
334 | } | ||
diff --git a/OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs new file mode 100644 index 0000000..d699f59 --- /dev/null +++ b/OpenSim/Services/Connectors/Hypergrid/HGFriendsServiceConnector.cs | |||
@@ -0,0 +1,206 @@ | |||
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 | |||
28 | using log4net; | ||
29 | using System; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Reflection; | ||
33 | using Nini.Config; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Services.Interfaces; | ||
36 | using OpenSim.Services.Connectors.Friends; | ||
37 | using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; | ||
38 | using OpenSim.Server.Base; | ||
39 | using OpenMetaverse; | ||
40 | |||
41 | namespace OpenSim.Services.Connectors.Hypergrid | ||
42 | { | ||
43 | public class HGFriendsServicesConnector | ||
44 | { | ||
45 | private static readonly ILog m_log = | ||
46 | LogManager.GetLogger( | ||
47 | MethodBase.GetCurrentMethod().DeclaringType); | ||
48 | |||
49 | private string m_ServerURI = String.Empty; | ||
50 | private string m_ServiceKey = String.Empty; | ||
51 | private UUID m_SessionID; | ||
52 | |||
53 | public HGFriendsServicesConnector() | ||
54 | { | ||
55 | } | ||
56 | |||
57 | public HGFriendsServicesConnector(string serverURI) | ||
58 | { | ||
59 | m_ServerURI = serverURI.TrimEnd('/'); | ||
60 | } | ||
61 | |||
62 | public HGFriendsServicesConnector(string serverURI, UUID sessionID, string serviceKey) | ||
63 | { | ||
64 | m_ServerURI = serverURI.TrimEnd('/'); | ||
65 | m_ServiceKey = serviceKey; | ||
66 | m_SessionID = sessionID; | ||
67 | } | ||
68 | |||
69 | #region IFriendsService | ||
70 | |||
71 | public uint GetFriendPerms(UUID PrincipalID, UUID friendID) | ||
72 | { | ||
73 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
74 | |||
75 | sendData["PRINCIPALID"] = PrincipalID.ToString(); | ||
76 | sendData["FRIENDID"] = friendID.ToString(); | ||
77 | sendData["METHOD"] = "getfriendperms"; | ||
78 | sendData["KEY"] = m_ServiceKey; | ||
79 | sendData["SESSIONID"] = m_SessionID.ToString(); | ||
80 | |||
81 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
82 | |||
83 | try | ||
84 | { | ||
85 | string reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
86 | m_ServerURI + "/hgfriends", | ||
87 | reqString); | ||
88 | if (reply != string.Empty) | ||
89 | { | ||
90 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
91 | |||
92 | if ((replyData != null) && replyData.ContainsKey("Value") && (replyData["Value"] != null)) | ||
93 | { | ||
94 | uint perms = 0; | ||
95 | uint.TryParse(replyData["Value"].ToString(), out perms); | ||
96 | return perms; | ||
97 | } | ||
98 | else | ||
99 | m_log.DebugFormat("[HGFRIENDS CONNECTOR]: GetFriendPerms {0} received null response", | ||
100 | PrincipalID); | ||
101 | |||
102 | } | ||
103 | } | ||
104 | catch (Exception e) | ||
105 | { | ||
106 | m_log.DebugFormat("[HGFRIENDS CONNECTOR]: Exception when contacting friends server: {0}", e.Message); | ||
107 | } | ||
108 | |||
109 | return 0; | ||
110 | |||
111 | } | ||
112 | |||
113 | public bool NewFriendship(UUID PrincipalID, string Friend) | ||
114 | { | ||
115 | FriendInfo finfo = new FriendInfo(); | ||
116 | finfo.PrincipalID = PrincipalID; | ||
117 | finfo.Friend = Friend; | ||
118 | |||
119 | Dictionary<string, object> sendData = finfo.ToKeyValuePairs(); | ||
120 | |||
121 | sendData["METHOD"] = "newfriendship"; | ||
122 | sendData["KEY"] = m_ServiceKey; | ||
123 | sendData["SESSIONID"] = m_SessionID.ToString(); | ||
124 | |||
125 | string reply = string.Empty; | ||
126 | try | ||
127 | { | ||
128 | reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
129 | m_ServerURI + "/hgfriends", | ||
130 | ServerUtils.BuildQueryString(sendData)); | ||
131 | } | ||
132 | catch (Exception e) | ||
133 | { | ||
134 | m_log.DebugFormat("[HGFRIENDS CONNECTOR]: Exception when contacting friends server: {0}", e.Message); | ||
135 | return false; | ||
136 | } | ||
137 | |||
138 | if (reply != string.Empty) | ||
139 | { | ||
140 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
141 | |||
142 | if ((replyData != null) && replyData.ContainsKey("Result") && (replyData["Result"] != null)) | ||
143 | { | ||
144 | bool success = false; | ||
145 | Boolean.TryParse(replyData["Result"].ToString(), out success); | ||
146 | return success; | ||
147 | } | ||
148 | else | ||
149 | m_log.DebugFormat("[HGFRIENDS CONNECTOR]: StoreFriend {0} {1} received null response", | ||
150 | PrincipalID, Friend); | ||
151 | } | ||
152 | else | ||
153 | m_log.DebugFormat("[HGFRIENDS CONNECTOR]: StoreFriend received null reply"); | ||
154 | |||
155 | return false; | ||
156 | |||
157 | } | ||
158 | |||
159 | public bool DeleteFriendship(UUID PrincipalID, UUID Friend, string secret) | ||
160 | { | ||
161 | FriendInfo finfo = new FriendInfo(); | ||
162 | finfo.PrincipalID = PrincipalID; | ||
163 | finfo.Friend = Friend.ToString(); | ||
164 | |||
165 | Dictionary<string, object> sendData = finfo.ToKeyValuePairs(); | ||
166 | |||
167 | sendData["METHOD"] = "deletefriendship"; | ||
168 | sendData["SECRET"] = secret; | ||
169 | |||
170 | string reply = string.Empty; | ||
171 | try | ||
172 | { | ||
173 | reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
174 | m_ServerURI + "/hgfriends", | ||
175 | ServerUtils.BuildQueryString(sendData)); | ||
176 | } | ||
177 | catch (Exception e) | ||
178 | { | ||
179 | m_log.DebugFormat("[HGFRIENDS CONNECTOR]: Exception when contacting friends server: {0}", e.Message); | ||
180 | return false; | ||
181 | } | ||
182 | |||
183 | if (reply != string.Empty) | ||
184 | { | ||
185 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
186 | |||
187 | if ((replyData != null) && replyData.ContainsKey("Result") && (replyData["Result"] != null)) | ||
188 | { | ||
189 | bool success = false; | ||
190 | Boolean.TryParse(replyData["Result"].ToString(), out success); | ||
191 | return success; | ||
192 | } | ||
193 | else | ||
194 | m_log.DebugFormat("[HGFRIENDS CONNECTOR]: Delete {0} {1} received null response", | ||
195 | PrincipalID, Friend); | ||
196 | } | ||
197 | else | ||
198 | m_log.DebugFormat("[HGFRIENDS CONNECTOR]: DeleteFriend received null reply"); | ||
199 | |||
200 | return false; | ||
201 | |||
202 | } | ||
203 | |||
204 | #endregion | ||
205 | } | ||
206 | } \ No newline at end of file | ||
diff --git a/OpenSim/Services/Connectors/Hypergrid/HeloServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/HeloServiceConnector.cs new file mode 100644 index 0000000..7cfd6e8 --- /dev/null +++ b/OpenSim/Services/Connectors/Hypergrid/HeloServiceConnector.cs | |||
@@ -0,0 +1,77 @@ | |||
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 | |||
28 | using log4net; | ||
29 | using System; | ||
30 | using System.Net; | ||
31 | using System.Reflection; | ||
32 | using Nini.Config; | ||
33 | |||
34 | namespace OpenSim.Services.Connectors | ||
35 | { | ||
36 | public class HeloServicesConnector | ||
37 | { | ||
38 | private static readonly ILog m_log = | ||
39 | LogManager.GetLogger( | ||
40 | MethodBase.GetCurrentMethod().DeclaringType); | ||
41 | |||
42 | private string m_ServerURI = String.Empty; | ||
43 | |||
44 | public HeloServicesConnector() | ||
45 | { | ||
46 | } | ||
47 | |||
48 | public HeloServicesConnector(string serverURI) | ||
49 | { | ||
50 | m_ServerURI = serverURI.TrimEnd('/'); | ||
51 | } | ||
52 | |||
53 | |||
54 | public virtual string Helo() | ||
55 | { | ||
56 | HttpWebRequest req = (HttpWebRequest)HttpWebRequest.Create(m_ServerURI + "/helo"); | ||
57 | // Eventually we need to switch to HEAD | ||
58 | /* req.Method = "HEAD"; */ | ||
59 | |||
60 | try | ||
61 | { | ||
62 | WebResponse response = req.GetResponse(); | ||
63 | if (response.Headers.Get("X-Handlers-Provided") == null) // just in case this ever returns a null | ||
64 | return string.Empty; | ||
65 | return response.Headers.Get("X-Handlers-Provided"); | ||
66 | } | ||
67 | catch (Exception e) | ||
68 | { | ||
69 | m_log.DebugFormat("[HELO SERVICE]: Unable to perform HELO request to {0}: {1}", m_ServerURI, e.Message); | ||
70 | } | ||
71 | |||
72 | // fail | ||
73 | return string.Empty; | ||
74 | } | ||
75 | |||
76 | } | ||
77 | } | ||
diff --git a/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs new file mode 100644 index 0000000..a59b9ee --- /dev/null +++ b/OpenSim/Services/Connectors/Hypergrid/UserAgentServiceConnector.cs | |||
@@ -0,0 +1,796 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Net; | ||
33 | using System.Reflection; | ||
34 | using System.Text; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Services.Interfaces; | ||
37 | using OpenSim.Services.Connectors.Simulation; | ||
38 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
39 | using OpenMetaverse; | ||
40 | using OpenMetaverse.StructuredData; | ||
41 | using log4net; | ||
42 | using Nwc.XmlRpc; | ||
43 | using Nini.Config; | ||
44 | |||
45 | namespace OpenSim.Services.Connectors.Hypergrid | ||
46 | { | ||
47 | public class UserAgentServiceConnector : IUserAgentService | ||
48 | { | ||
49 | private static readonly ILog m_log = | ||
50 | LogManager.GetLogger( | ||
51 | MethodBase.GetCurrentMethod().DeclaringType); | ||
52 | |||
53 | string m_ServerURL; | ||
54 | |||
55 | public UserAgentServiceConnector(string url) : this(url, true) | ||
56 | { | ||
57 | } | ||
58 | |||
59 | public UserAgentServiceConnector(string url, bool dnsLookup) | ||
60 | { | ||
61 | m_ServerURL = url; | ||
62 | |||
63 | if (dnsLookup) | ||
64 | { | ||
65 | // Doing this here, because XML-RPC or mono have some strong ideas about | ||
66 | // caching DNS translations. | ||
67 | try | ||
68 | { | ||
69 | Uri m_Uri = new Uri(m_ServerURL); | ||
70 | IPAddress ip = Util.GetHostFromDNS(m_Uri.Host); | ||
71 | m_ServerURL = m_ServerURL.Replace(m_Uri.Host, ip.ToString()); | ||
72 | if (!m_ServerURL.EndsWith("/")) | ||
73 | m_ServerURL += "/"; | ||
74 | } | ||
75 | catch (Exception e) | ||
76 | { | ||
77 | m_log.DebugFormat("[USER AGENT CONNECTOR]: Malformed Uri {0}: {1}", m_ServerURL, e.Message); | ||
78 | } | ||
79 | } | ||
80 | m_log.DebugFormat("[USER AGENT CONNECTOR]: new connector to {0} ({1})", url, m_ServerURL); | ||
81 | } | ||
82 | |||
83 | public UserAgentServiceConnector(IConfigSource config) | ||
84 | { | ||
85 | IConfig serviceConfig = config.Configs["UserAgentService"]; | ||
86 | if (serviceConfig == null) | ||
87 | { | ||
88 | m_log.Error("[USER AGENT CONNECTOR]: UserAgentService missing from ini"); | ||
89 | throw new Exception("UserAgent connector init error"); | ||
90 | } | ||
91 | |||
92 | string serviceURI = serviceConfig.GetString("UserAgentServerURI", | ||
93 | String.Empty); | ||
94 | |||
95 | if (serviceURI == String.Empty) | ||
96 | { | ||
97 | m_log.Error("[USER AGENT CONNECTOR]: No Server URI named in section UserAgentService"); | ||
98 | throw new Exception("UserAgent connector init error"); | ||
99 | } | ||
100 | m_ServerURL = serviceURI; | ||
101 | |||
102 | m_log.DebugFormat("[USER AGENT CONNECTOR]: UserAgentServiceConnector started for {0}", m_ServerURL); | ||
103 | } | ||
104 | |||
105 | |||
106 | // The Login service calls this interface with a non-null [client] ipaddress | ||
107 | public bool LoginAgentToGrid(AgentCircuitData aCircuit, GridRegion gatekeeper, GridRegion destination, IPEndPoint ipaddress, out string reason) | ||
108 | { | ||
109 | reason = String.Empty; | ||
110 | |||
111 | if (destination == null) | ||
112 | { | ||
113 | reason = "Destination is null"; | ||
114 | m_log.Debug("[USER AGENT CONNECTOR]: Given destination is null"); | ||
115 | return false; | ||
116 | } | ||
117 | |||
118 | string uri = m_ServerURL + "homeagent/" + aCircuit.AgentID + "/"; | ||
119 | |||
120 | Console.WriteLine(" >>> LoginAgentToGrid <<< " + uri); | ||
121 | |||
122 | HttpWebRequest AgentCreateRequest = (HttpWebRequest)WebRequest.Create(uri); | ||
123 | AgentCreateRequest.Method = "POST"; | ||
124 | AgentCreateRequest.ContentType = "application/json"; | ||
125 | AgentCreateRequest.Timeout = 10000; | ||
126 | //AgentCreateRequest.KeepAlive = false; | ||
127 | //AgentCreateRequest.Headers.Add("Authorization", authKey); | ||
128 | |||
129 | // Fill it in | ||
130 | OSDMap args = PackCreateAgentArguments(aCircuit, gatekeeper, destination, ipaddress); | ||
131 | |||
132 | string strBuffer = ""; | ||
133 | byte[] buffer = new byte[1]; | ||
134 | try | ||
135 | { | ||
136 | strBuffer = OSDParser.SerializeJsonString(args); | ||
137 | Encoding str = Util.UTF8; | ||
138 | buffer = str.GetBytes(strBuffer); | ||
139 | |||
140 | } | ||
141 | catch (Exception e) | ||
142 | { | ||
143 | m_log.WarnFormat("[USER AGENT CONNECTOR]: Exception thrown on serialization of ChildCreate: {0}", e.Message); | ||
144 | // ignore. buffer will be empty, caller should check. | ||
145 | } | ||
146 | |||
147 | Stream os = null; | ||
148 | try | ||
149 | { // send the Post | ||
150 | AgentCreateRequest.ContentLength = buffer.Length; //Count bytes to send | ||
151 | os = AgentCreateRequest.GetRequestStream(); | ||
152 | os.Write(buffer, 0, strBuffer.Length); //Send it | ||
153 | m_log.InfoFormat("[USER AGENT CONNECTOR]: Posted CreateAgent request to remote sim {0}, region {1}, x={2} y={3}", | ||
154 | uri, destination.RegionName, destination.RegionLocX, destination.RegionLocY); | ||
155 | } | ||
156 | //catch (WebException ex) | ||
157 | catch | ||
158 | { | ||
159 | //m_log.InfoFormat("[USER AGENT CONNECTOR]: Bad send on ChildAgentUpdate {0}", ex.Message); | ||
160 | reason = "cannot contact remote region"; | ||
161 | return false; | ||
162 | } | ||
163 | finally | ||
164 | { | ||
165 | if (os != null) | ||
166 | os.Close(); | ||
167 | } | ||
168 | |||
169 | // Let's wait for the response | ||
170 | //m_log.Info("[USER AGENT CONNECTOR]: Waiting for a reply after DoCreateChildAgentCall"); | ||
171 | |||
172 | WebResponse webResponse = null; | ||
173 | StreamReader sr = null; | ||
174 | try | ||
175 | { | ||
176 | webResponse = AgentCreateRequest.GetResponse(); | ||
177 | if (webResponse == null) | ||
178 | { | ||
179 | m_log.Info("[USER AGENT CONNECTOR]: Null reply on DoCreateChildAgentCall post"); | ||
180 | } | ||
181 | else | ||
182 | { | ||
183 | |||
184 | sr = new StreamReader(webResponse.GetResponseStream()); | ||
185 | string response = sr.ReadToEnd().Trim(); | ||
186 | m_log.InfoFormat("[USER AGENT CONNECTOR]: DoCreateChildAgentCall reply was {0} ", response); | ||
187 | |||
188 | if (!String.IsNullOrEmpty(response)) | ||
189 | { | ||
190 | try | ||
191 | { | ||
192 | // we assume we got an OSDMap back | ||
193 | OSDMap r = Util.GetOSDMap(response); | ||
194 | bool success = r["success"].AsBoolean(); | ||
195 | reason = r["reason"].AsString(); | ||
196 | return success; | ||
197 | } | ||
198 | catch (NullReferenceException e) | ||
199 | { | ||
200 | m_log.InfoFormat("[USER AGENT CONNECTOR]: exception on reply of DoCreateChildAgentCall {0}", e.Message); | ||
201 | |||
202 | // check for old style response | ||
203 | if (response.ToLower().StartsWith("true")) | ||
204 | return true; | ||
205 | |||
206 | return false; | ||
207 | } | ||
208 | } | ||
209 | } | ||
210 | } | ||
211 | catch (WebException ex) | ||
212 | { | ||
213 | m_log.InfoFormat("[USER AGENT CONNECTOR]: exception on reply of DoCreateChildAgentCall {0}", ex.Message); | ||
214 | reason = "Destination did not reply"; | ||
215 | return false; | ||
216 | } | ||
217 | finally | ||
218 | { | ||
219 | if (sr != null) | ||
220 | sr.Close(); | ||
221 | } | ||
222 | |||
223 | return true; | ||
224 | |||
225 | } | ||
226 | |||
227 | |||
228 | // The simulators call this interface | ||
229 | public bool LoginAgentToGrid(AgentCircuitData aCircuit, GridRegion gatekeeper, GridRegion destination, out string reason) | ||
230 | { | ||
231 | return LoginAgentToGrid(aCircuit, gatekeeper, destination, null, out reason); | ||
232 | } | ||
233 | |||
234 | protected OSDMap PackCreateAgentArguments(AgentCircuitData aCircuit, GridRegion gatekeeper, GridRegion destination, IPEndPoint ipaddress) | ||
235 | { | ||
236 | OSDMap args = null; | ||
237 | try | ||
238 | { | ||
239 | args = aCircuit.PackAgentCircuitData(); | ||
240 | } | ||
241 | catch (Exception e) | ||
242 | { | ||
243 | m_log.Debug("[USER AGENT CONNECTOR]: PackAgentCircuitData failed with exception: " + e.Message); | ||
244 | } | ||
245 | |||
246 | // Add the input arguments | ||
247 | args["gatekeeper_serveruri"] = OSD.FromString(gatekeeper.ServerURI); | ||
248 | args["gatekeeper_host"] = OSD.FromString(gatekeeper.ExternalHostName); | ||
249 | args["gatekeeper_port"] = OSD.FromString(gatekeeper.HttpPort.ToString()); | ||
250 | args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); | ||
251 | args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); | ||
252 | args["destination_name"] = OSD.FromString(destination.RegionName); | ||
253 | args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); | ||
254 | args["destination_serveruri"] = OSD.FromString(destination.ServerURI); | ||
255 | |||
256 | // 10/3/2010 | ||
257 | // I added the client_ip up to the regular AgentCircuitData, so this doesn't need to be here. | ||
258 | // This need cleaning elsewhere... | ||
259 | //if (ipaddress != null) | ||
260 | // args["client_ip"] = OSD.FromString(ipaddress.Address.ToString()); | ||
261 | |||
262 | return args; | ||
263 | } | ||
264 | |||
265 | public void SetClientToken(UUID sessionID, string token) | ||
266 | { | ||
267 | // no-op | ||
268 | } | ||
269 | |||
270 | public GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt) | ||
271 | { | ||
272 | position = Vector3.UnitY; lookAt = Vector3.UnitY; | ||
273 | |||
274 | Hashtable hash = new Hashtable(); | ||
275 | hash["userID"] = userID.ToString(); | ||
276 | |||
277 | IList paramList = new ArrayList(); | ||
278 | paramList.Add(hash); | ||
279 | |||
280 | XmlRpcRequest request = new XmlRpcRequest("get_home_region", paramList); | ||
281 | XmlRpcResponse response = null; | ||
282 | try | ||
283 | { | ||
284 | response = request.Send(m_ServerURL, 10000); | ||
285 | } | ||
286 | catch (Exception) | ||
287 | { | ||
288 | return null; | ||
289 | } | ||
290 | |||
291 | if (response.IsFault) | ||
292 | { | ||
293 | return null; | ||
294 | } | ||
295 | |||
296 | hash = (Hashtable)response.Value; | ||
297 | //foreach (Object o in hash) | ||
298 | // m_log.Debug(">> " + ((DictionaryEntry)o).Key + ":" + ((DictionaryEntry)o).Value); | ||
299 | try | ||
300 | { | ||
301 | bool success = false; | ||
302 | Boolean.TryParse((string)hash["result"], out success); | ||
303 | if (success) | ||
304 | { | ||
305 | GridRegion region = new GridRegion(); | ||
306 | |||
307 | UUID.TryParse((string)hash["uuid"], out region.RegionID); | ||
308 | //m_log.Debug(">> HERE, uuid: " + region.RegionID); | ||
309 | int n = 0; | ||
310 | if (hash["x"] != null) | ||
311 | { | ||
312 | Int32.TryParse((string)hash["x"], out n); | ||
313 | region.RegionLocX = n; | ||
314 | //m_log.Debug(">> HERE, x: " + region.RegionLocX); | ||
315 | } | ||
316 | if (hash["y"] != null) | ||
317 | { | ||
318 | Int32.TryParse((string)hash["y"], out n); | ||
319 | region.RegionLocY = n; | ||
320 | //m_log.Debug(">> HERE, y: " + region.RegionLocY); | ||
321 | } | ||
322 | if (hash["region_name"] != null) | ||
323 | { | ||
324 | region.RegionName = (string)hash["region_name"]; | ||
325 | //m_log.Debug(">> HERE, name: " + region.RegionName); | ||
326 | } | ||
327 | if (hash["hostname"] != null) | ||
328 | region.ExternalHostName = (string)hash["hostname"]; | ||
329 | if (hash["http_port"] != null) | ||
330 | { | ||
331 | uint p = 0; | ||
332 | UInt32.TryParse((string)hash["http_port"], out p); | ||
333 | region.HttpPort = p; | ||
334 | } | ||
335 | if (hash["internal_port"] != null) | ||
336 | { | ||
337 | int p = 0; | ||
338 | Int32.TryParse((string)hash["internal_port"], out p); | ||
339 | region.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), p); | ||
340 | } | ||
341 | if (hash["position"] != null) | ||
342 | Vector3.TryParse((string)hash["position"], out position); | ||
343 | if (hash["lookAt"] != null) | ||
344 | Vector3.TryParse((string)hash["lookAt"], out lookAt); | ||
345 | |||
346 | // Successful return | ||
347 | return region; | ||
348 | } | ||
349 | |||
350 | } | ||
351 | catch (Exception) | ||
352 | { | ||
353 | return null; | ||
354 | } | ||
355 | |||
356 | return null; | ||
357 | } | ||
358 | |||
359 | public bool IsAgentComingHome(UUID sessionID, string thisGridExternalName) | ||
360 | { | ||
361 | Hashtable hash = new Hashtable(); | ||
362 | hash["sessionID"] = sessionID.ToString(); | ||
363 | hash["externalName"] = thisGridExternalName; | ||
364 | |||
365 | IList paramList = new ArrayList(); | ||
366 | paramList.Add(hash); | ||
367 | |||
368 | XmlRpcRequest request = new XmlRpcRequest("agent_is_coming_home", paramList); | ||
369 | string reason = string.Empty; | ||
370 | return GetBoolResponse(request, out reason); | ||
371 | } | ||
372 | |||
373 | public bool VerifyAgent(UUID sessionID, string token) | ||
374 | { | ||
375 | Hashtable hash = new Hashtable(); | ||
376 | hash["sessionID"] = sessionID.ToString(); | ||
377 | hash["token"] = token; | ||
378 | |||
379 | IList paramList = new ArrayList(); | ||
380 | paramList.Add(hash); | ||
381 | |||
382 | XmlRpcRequest request = new XmlRpcRequest("verify_agent", paramList); | ||
383 | string reason = string.Empty; | ||
384 | return GetBoolResponse(request, out reason); | ||
385 | } | ||
386 | |||
387 | public bool VerifyClient(UUID sessionID, string token) | ||
388 | { | ||
389 | Hashtable hash = new Hashtable(); | ||
390 | hash["sessionID"] = sessionID.ToString(); | ||
391 | hash["token"] = token; | ||
392 | |||
393 | IList paramList = new ArrayList(); | ||
394 | paramList.Add(hash); | ||
395 | |||
396 | XmlRpcRequest request = new XmlRpcRequest("verify_client", paramList); | ||
397 | string reason = string.Empty; | ||
398 | return GetBoolResponse(request, out reason); | ||
399 | } | ||
400 | |||
401 | public void LogoutAgent(UUID userID, UUID sessionID) | ||
402 | { | ||
403 | Hashtable hash = new Hashtable(); | ||
404 | hash["sessionID"] = sessionID.ToString(); | ||
405 | hash["userID"] = userID.ToString(); | ||
406 | |||
407 | IList paramList = new ArrayList(); | ||
408 | paramList.Add(hash); | ||
409 | |||
410 | XmlRpcRequest request = new XmlRpcRequest("logout_agent", paramList); | ||
411 | string reason = string.Empty; | ||
412 | GetBoolResponse(request, out reason); | ||
413 | } | ||
414 | |||
415 | public List<UUID> StatusNotification(List<string> friends, UUID userID, bool online) | ||
416 | { | ||
417 | Hashtable hash = new Hashtable(); | ||
418 | hash["userID"] = userID.ToString(); | ||
419 | hash["online"] = online.ToString(); | ||
420 | int i = 0; | ||
421 | foreach (string s in friends) | ||
422 | { | ||
423 | hash["friend_" + i.ToString()] = s; | ||
424 | i++; | ||
425 | } | ||
426 | |||
427 | IList paramList = new ArrayList(); | ||
428 | paramList.Add(hash); | ||
429 | |||
430 | XmlRpcRequest request = new XmlRpcRequest("status_notification", paramList); | ||
431 | // string reason = string.Empty; | ||
432 | |||
433 | // Send and get reply | ||
434 | List<UUID> friendsOnline = new List<UUID>(); | ||
435 | XmlRpcResponse response = null; | ||
436 | try | ||
437 | { | ||
438 | response = request.Send(m_ServerURL, 6000); | ||
439 | } | ||
440 | catch | ||
441 | { | ||
442 | m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for StatusNotification", m_ServerURL); | ||
443 | // reason = "Exception: " + e.Message; | ||
444 | return friendsOnline; | ||
445 | } | ||
446 | |||
447 | if (response.IsFault) | ||
448 | { | ||
449 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for StatusNotification returned an error: {1}", m_ServerURL, response.FaultString); | ||
450 | // reason = "XMLRPC Fault"; | ||
451 | return friendsOnline; | ||
452 | } | ||
453 | |||
454 | hash = (Hashtable)response.Value; | ||
455 | //foreach (Object o in hash) | ||
456 | // m_log.Debug(">> " + ((DictionaryEntry)o).Key + ":" + ((DictionaryEntry)o).Value); | ||
457 | try | ||
458 | { | ||
459 | if (hash == null) | ||
460 | { | ||
461 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: GetOnlineFriends Got null response from {0}! THIS IS BAAAAD", m_ServerURL); | ||
462 | // reason = "Internal error 1"; | ||
463 | return friendsOnline; | ||
464 | } | ||
465 | |||
466 | // Here is the actual response | ||
467 | foreach (object key in hash.Keys) | ||
468 | { | ||
469 | if (key is string && ((string)key).StartsWith("friend_") && hash[key] != null) | ||
470 | { | ||
471 | UUID uuid; | ||
472 | if (UUID.TryParse(hash[key].ToString(), out uuid)) | ||
473 | friendsOnline.Add(uuid); | ||
474 | } | ||
475 | } | ||
476 | |||
477 | } | ||
478 | catch | ||
479 | { | ||
480 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: Got exception on GetOnlineFriends response."); | ||
481 | // reason = "Exception: " + e.Message; | ||
482 | } | ||
483 | |||
484 | return friendsOnline; | ||
485 | } | ||
486 | |||
487 | public List<UUID> GetOnlineFriends(UUID userID, List<string> friends) | ||
488 | { | ||
489 | Hashtable hash = new Hashtable(); | ||
490 | hash["userID"] = userID.ToString(); | ||
491 | int i = 0; | ||
492 | foreach (string s in friends) | ||
493 | { | ||
494 | hash["friend_" + i.ToString()] = s; | ||
495 | i++; | ||
496 | } | ||
497 | |||
498 | IList paramList = new ArrayList(); | ||
499 | paramList.Add(hash); | ||
500 | |||
501 | XmlRpcRequest request = new XmlRpcRequest("get_online_friends", paramList); | ||
502 | // string reason = string.Empty; | ||
503 | |||
504 | // Send and get reply | ||
505 | List<UUID> online = new List<UUID>(); | ||
506 | XmlRpcResponse response = null; | ||
507 | try | ||
508 | { | ||
509 | response = request.Send(m_ServerURL, 10000); | ||
510 | } | ||
511 | catch | ||
512 | { | ||
513 | m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for GetOnlineFriends", m_ServerURL); | ||
514 | // reason = "Exception: " + e.Message; | ||
515 | return online; | ||
516 | } | ||
517 | |||
518 | if (response.IsFault) | ||
519 | { | ||
520 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for GetOnlineFriends returned an error: {1}", m_ServerURL, response.FaultString); | ||
521 | // reason = "XMLRPC Fault"; | ||
522 | return online; | ||
523 | } | ||
524 | |||
525 | hash = (Hashtable)response.Value; | ||
526 | //foreach (Object o in hash) | ||
527 | // m_log.Debug(">> " + ((DictionaryEntry)o).Key + ":" + ((DictionaryEntry)o).Value); | ||
528 | try | ||
529 | { | ||
530 | if (hash == null) | ||
531 | { | ||
532 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: GetOnlineFriends Got null response from {0}! THIS IS BAAAAD", m_ServerURL); | ||
533 | // reason = "Internal error 1"; | ||
534 | return online; | ||
535 | } | ||
536 | |||
537 | // Here is the actual response | ||
538 | foreach (object key in hash.Keys) | ||
539 | { | ||
540 | if (key is string && ((string)key).StartsWith("friend_") && hash[key] != null) | ||
541 | { | ||
542 | UUID uuid; | ||
543 | if (UUID.TryParse(hash[key].ToString(), out uuid)) | ||
544 | online.Add(uuid); | ||
545 | } | ||
546 | } | ||
547 | |||
548 | } | ||
549 | catch | ||
550 | { | ||
551 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: Got exception on GetOnlineFriends response."); | ||
552 | // reason = "Exception: " + e.Message; | ||
553 | } | ||
554 | |||
555 | return online; | ||
556 | } | ||
557 | |||
558 | public Dictionary<string, object> GetServerURLs(UUID userID) | ||
559 | { | ||
560 | Hashtable hash = new Hashtable(); | ||
561 | hash["userID"] = userID.ToString(); | ||
562 | |||
563 | IList paramList = new ArrayList(); | ||
564 | paramList.Add(hash); | ||
565 | |||
566 | XmlRpcRequest request = new XmlRpcRequest("get_server_urls", paramList); | ||
567 | // string reason = string.Empty; | ||
568 | |||
569 | // Send and get reply | ||
570 | Dictionary<string, object> serverURLs = new Dictionary<string,object>(); | ||
571 | XmlRpcResponse response = null; | ||
572 | try | ||
573 | { | ||
574 | response = request.Send(m_ServerURL, 10000); | ||
575 | } | ||
576 | catch | ||
577 | { | ||
578 | m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for GetServerURLs", m_ServerURL); | ||
579 | // reason = "Exception: " + e.Message; | ||
580 | return serverURLs; | ||
581 | } | ||
582 | |||
583 | if (response.IsFault) | ||
584 | { | ||
585 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for GetServerURLs returned an error: {1}", m_ServerURL, response.FaultString); | ||
586 | // reason = "XMLRPC Fault"; | ||
587 | return serverURLs; | ||
588 | } | ||
589 | |||
590 | hash = (Hashtable)response.Value; | ||
591 | //foreach (Object o in hash) | ||
592 | // m_log.Debug(">> " + ((DictionaryEntry)o).Key + ":" + ((DictionaryEntry)o).Value); | ||
593 | try | ||
594 | { | ||
595 | if (hash == null) | ||
596 | { | ||
597 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: GetServerURLs Got null response from {0}! THIS IS BAAAAD", m_ServerURL); | ||
598 | // reason = "Internal error 1"; | ||
599 | return serverURLs; | ||
600 | } | ||
601 | |||
602 | // Here is the actual response | ||
603 | foreach (object key in hash.Keys) | ||
604 | { | ||
605 | if (key is string && ((string)key).StartsWith("SRV_") && hash[key] != null) | ||
606 | { | ||
607 | string serverType = key.ToString().Substring(4); // remove "SRV_" | ||
608 | serverURLs.Add(serverType, hash[key].ToString()); | ||
609 | } | ||
610 | } | ||
611 | |||
612 | } | ||
613 | catch | ||
614 | { | ||
615 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: Got exception on GetOnlineFriends response."); | ||
616 | // reason = "Exception: " + e.Message; | ||
617 | } | ||
618 | |||
619 | return serverURLs; | ||
620 | } | ||
621 | |||
622 | public string LocateUser(UUID userID) | ||
623 | { | ||
624 | Hashtable hash = new Hashtable(); | ||
625 | hash["userID"] = userID.ToString(); | ||
626 | |||
627 | IList paramList = new ArrayList(); | ||
628 | paramList.Add(hash); | ||
629 | |||
630 | XmlRpcRequest request = new XmlRpcRequest("locate_user", paramList); | ||
631 | // string reason = string.Empty; | ||
632 | |||
633 | // Send and get reply | ||
634 | string url = string.Empty; | ||
635 | XmlRpcResponse response = null; | ||
636 | try | ||
637 | { | ||
638 | response = request.Send(m_ServerURL, 10000); | ||
639 | } | ||
640 | catch | ||
641 | { | ||
642 | m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for LocateUser", m_ServerURL); | ||
643 | // reason = "Exception: " + e.Message; | ||
644 | return url; | ||
645 | } | ||
646 | |||
647 | if (response.IsFault) | ||
648 | { | ||
649 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for LocateUser returned an error: {1}", m_ServerURL, response.FaultString); | ||
650 | // reason = "XMLRPC Fault"; | ||
651 | return url; | ||
652 | } | ||
653 | |||
654 | hash = (Hashtable)response.Value; | ||
655 | //foreach (Object o in hash) | ||
656 | // m_log.Debug(">> " + ((DictionaryEntry)o).Key + ":" + ((DictionaryEntry)o).Value); | ||
657 | try | ||
658 | { | ||
659 | if (hash == null) | ||
660 | { | ||
661 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: LocateUser Got null response from {0}! THIS IS BAAAAD", m_ServerURL); | ||
662 | // reason = "Internal error 1"; | ||
663 | return url; | ||
664 | } | ||
665 | |||
666 | // Here's the actual response | ||
667 | if (hash.ContainsKey("URL")) | ||
668 | url = hash["URL"].ToString(); | ||
669 | |||
670 | } | ||
671 | catch | ||
672 | { | ||
673 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: Got exception on LocateUser response."); | ||
674 | // reason = "Exception: " + e.Message; | ||
675 | } | ||
676 | |||
677 | return url; | ||
678 | } | ||
679 | |||
680 | public string GetUUI(UUID userID, UUID targetUserID) | ||
681 | { | ||
682 | Hashtable hash = new Hashtable(); | ||
683 | hash["userID"] = userID.ToString(); | ||
684 | hash["targetUserID"] = targetUserID.ToString(); | ||
685 | |||
686 | IList paramList = new ArrayList(); | ||
687 | paramList.Add(hash); | ||
688 | |||
689 | XmlRpcRequest request = new XmlRpcRequest("get_uui", paramList); | ||
690 | // string reason = string.Empty; | ||
691 | |||
692 | // Send and get reply | ||
693 | string uui = string.Empty; | ||
694 | XmlRpcResponse response = null; | ||
695 | try | ||
696 | { | ||
697 | response = request.Send(m_ServerURL, 10000); | ||
698 | } | ||
699 | catch | ||
700 | { | ||
701 | m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for GetUUI", m_ServerURL); | ||
702 | // reason = "Exception: " + e.Message; | ||
703 | return uui; | ||
704 | } | ||
705 | |||
706 | if (response.IsFault) | ||
707 | { | ||
708 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for GetUUI returned an error: {1}", m_ServerURL, response.FaultString); | ||
709 | // reason = "XMLRPC Fault"; | ||
710 | return uui; | ||
711 | } | ||
712 | |||
713 | hash = (Hashtable)response.Value; | ||
714 | //foreach (Object o in hash) | ||
715 | // m_log.Debug(">> " + ((DictionaryEntry)o).Key + ":" + ((DictionaryEntry)o).Value); | ||
716 | try | ||
717 | { | ||
718 | if (hash == null) | ||
719 | { | ||
720 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: GetUUI Got null response from {0}! THIS IS BAAAAD", m_ServerURL); | ||
721 | // reason = "Internal error 1"; | ||
722 | return uui; | ||
723 | } | ||
724 | |||
725 | // Here's the actual response | ||
726 | if (hash.ContainsKey("UUI")) | ||
727 | uui = hash["UUI"].ToString(); | ||
728 | |||
729 | } | ||
730 | catch | ||
731 | { | ||
732 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: Got exception on LocateUser response."); | ||
733 | // reason = "Exception: " + e.Message; | ||
734 | } | ||
735 | |||
736 | return uui; | ||
737 | } | ||
738 | |||
739 | private bool GetBoolResponse(XmlRpcRequest request, out string reason) | ||
740 | { | ||
741 | //m_log.Debug("[USER AGENT CONNECTOR]: GetBoolResponse from/to " + m_ServerURL); | ||
742 | XmlRpcResponse response = null; | ||
743 | try | ||
744 | { | ||
745 | response = request.Send(m_ServerURL, 10000); | ||
746 | } | ||
747 | catch (Exception e) | ||
748 | { | ||
749 | m_log.DebugFormat("[USER AGENT CONNECTOR]: Unable to contact remote server {0} for GetBoolResponse", m_ServerURL); | ||
750 | reason = "Exception: " + e.Message; | ||
751 | return false; | ||
752 | } | ||
753 | |||
754 | if (response.IsFault) | ||
755 | { | ||
756 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: remote call to {0} for GetBoolResponse returned an error: {1}", m_ServerURL, response.FaultString); | ||
757 | reason = "XMLRPC Fault"; | ||
758 | return false; | ||
759 | } | ||
760 | |||
761 | Hashtable hash = (Hashtable)response.Value; | ||
762 | //foreach (Object o in hash) | ||
763 | // m_log.Debug(">> " + ((DictionaryEntry)o).Key + ":" + ((DictionaryEntry)o).Value); | ||
764 | try | ||
765 | { | ||
766 | if (hash == null) | ||
767 | { | ||
768 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: Got null response from {0}! THIS IS BAAAAD", m_ServerURL); | ||
769 | reason = "Internal error 1"; | ||
770 | return false; | ||
771 | } | ||
772 | bool success = false; | ||
773 | reason = string.Empty; | ||
774 | if (hash.ContainsKey("result")) | ||
775 | Boolean.TryParse((string)hash["result"], out success); | ||
776 | else | ||
777 | { | ||
778 | reason = "Internal error 2"; | ||
779 | m_log.WarnFormat("[USER AGENT CONNECTOR]: response from {0} does not have expected key 'result'", m_ServerURL); | ||
780 | } | ||
781 | |||
782 | return success; | ||
783 | } | ||
784 | catch (Exception e) | ||
785 | { | ||
786 | m_log.ErrorFormat("[USER AGENT CONNECTOR]: Got exception on GetBoolResponse response."); | ||
787 | if (hash.ContainsKey("result") && hash["result"] != null) | ||
788 | m_log.ErrorFormat("Reply was ", (string)hash["result"]); | ||
789 | reason = "Exception: " + e.Message; | ||
790 | return false; | ||
791 | } | ||
792 | |||
793 | } | ||
794 | |||
795 | } | ||
796 | } | ||
diff --git a/OpenSim/Services/Connectors/InstantMessage/InstantMessageServiceConnector.cs b/OpenSim/Services/Connectors/InstantMessage/InstantMessageServiceConnector.cs new file mode 100644 index 0000000..dbce9f6 --- /dev/null +++ b/OpenSim/Services/Connectors/InstantMessage/InstantMessageServiceConnector.cs | |||
@@ -0,0 +1,131 @@ | |||
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 | using System; | ||
28 | using System.Collections; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Net; | ||
31 | using System.Reflection; | ||
32 | |||
33 | using OpenMetaverse; | ||
34 | using Nwc.XmlRpc; | ||
35 | using log4net; | ||
36 | |||
37 | using OpenSim.Framework; | ||
38 | |||
39 | namespace OpenSim.Services.Connectors.InstantMessage | ||
40 | { | ||
41 | public class InstantMessageServiceConnector | ||
42 | { | ||
43 | private static readonly ILog m_log = | ||
44 | LogManager.GetLogger( | ||
45 | MethodBase.GetCurrentMethod().DeclaringType); | ||
46 | |||
47 | /// <summary> | ||
48 | /// This actually does the XMLRPC Request | ||
49 | /// </summary> | ||
50 | /// <param name="url">URL we pull the data out of to send the request to</param> | ||
51 | /// <param name="im">The Instant Message </param> | ||
52 | /// <returns>Bool if the message was successfully delivered at the other side.</returns> | ||
53 | public static bool SendInstantMessage(string url, GridInstantMessage im) | ||
54 | { | ||
55 | Hashtable xmlrpcdata = ConvertGridInstantMessageToXMLRPC(im); | ||
56 | xmlrpcdata["region_handle"] = 0; | ||
57 | |||
58 | ArrayList SendParams = new ArrayList(); | ||
59 | SendParams.Add(xmlrpcdata); | ||
60 | XmlRpcRequest GridReq = new XmlRpcRequest("grid_instant_message", SendParams); | ||
61 | try | ||
62 | { | ||
63 | |||
64 | XmlRpcResponse GridResp = GridReq.Send(url, 10000); | ||
65 | |||
66 | Hashtable responseData = (Hashtable)GridResp.Value; | ||
67 | |||
68 | if (responseData.ContainsKey("success")) | ||
69 | { | ||
70 | if ((string)responseData["success"] == "TRUE") | ||
71 | { | ||
72 | //m_log.DebugFormat("[XXX] Success"); | ||
73 | return true; | ||
74 | } | ||
75 | else | ||
76 | { | ||
77 | //m_log.DebugFormat("[XXX] Fail"); | ||
78 | return false; | ||
79 | } | ||
80 | } | ||
81 | else | ||
82 | { | ||
83 | m_log.DebugFormat("[GRID INSTANT MESSAGE]: No response from {0}", url); | ||
84 | return false; | ||
85 | } | ||
86 | } | ||
87 | catch (WebException e) | ||
88 | { | ||
89 | m_log.ErrorFormat("[GRID INSTANT MESSAGE]: Error sending message to {0} the host didn't respond " + e.ToString(), url); | ||
90 | } | ||
91 | |||
92 | return false; | ||
93 | } | ||
94 | |||
95 | /// <summary> | ||
96 | /// Takes a GridInstantMessage and converts it into a Hashtable for XMLRPC | ||
97 | /// </summary> | ||
98 | /// <param name="msg">The GridInstantMessage object</param> | ||
99 | /// <returns>Hashtable containing the XMLRPC request</returns> | ||
100 | protected static Hashtable ConvertGridInstantMessageToXMLRPC(GridInstantMessage msg) | ||
101 | { | ||
102 | Hashtable gim = new Hashtable(); | ||
103 | gim["from_agent_id"] = msg.fromAgentID.ToString(); | ||
104 | // Kept for compatibility | ||
105 | gim["from_agent_session"] = UUID.Zero.ToString(); | ||
106 | gim["to_agent_id"] = msg.toAgentID.ToString(); | ||
107 | gim["im_session_id"] = msg.imSessionID.ToString(); | ||
108 | gim["timestamp"] = msg.timestamp.ToString(); | ||
109 | gim["from_agent_name"] = msg.fromAgentName; | ||
110 | gim["message"] = msg.message; | ||
111 | byte[] dialogdata = new byte[1]; dialogdata[0] = msg.dialog; | ||
112 | gim["dialog"] = Convert.ToBase64String(dialogdata, Base64FormattingOptions.None); | ||
113 | |||
114 | if (msg.fromGroup) | ||
115 | gim["from_group"] = "TRUE"; | ||
116 | else | ||
117 | gim["from_group"] = "FALSE"; | ||
118 | byte[] offlinedata = new byte[1]; offlinedata[0] = msg.offline; | ||
119 | gim["offline"] = Convert.ToBase64String(offlinedata, Base64FormattingOptions.None); | ||
120 | gim["parent_estate_id"] = msg.ParentEstateID.ToString(); | ||
121 | gim["position_x"] = msg.Position.X.ToString(); | ||
122 | gim["position_y"] = msg.Position.Y.ToString(); | ||
123 | gim["position_z"] = msg.Position.Z.ToString(); | ||
124 | gim["region_id"] = msg.RegionID.ToString(); | ||
125 | gim["binary_bucket"] = Convert.ToBase64String(msg.binaryBucket, Base64FormattingOptions.None); | ||
126 | |||
127 | return gim; | ||
128 | } | ||
129 | |||
130 | } | ||
131 | } | ||
diff --git a/OpenSim/Services/Connectors/Inventory/HGInventoryServiceConnector.cs b/OpenSim/Services/Connectors/Inventory/HGInventoryServiceConnector.cs deleted file mode 100644 index 9878855..0000000 --- a/OpenSim/Services/Connectors/Inventory/HGInventoryServiceConnector.cs +++ /dev/null | |||
@@ -1,335 +0,0 @@ | |||
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 | |||
28 | using log4net; | ||
29 | using Nini.Config; | ||
30 | using System; | ||
31 | using System.Collections.Generic; | ||
32 | using System.Reflection; | ||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Services.Interfaces; | ||
35 | using OpenMetaverse; | ||
36 | |||
37 | namespace OpenSim.Services.Connectors.Inventory | ||
38 | { | ||
39 | public class HGInventoryServiceConnector : ISessionAuthInventoryService | ||
40 | { | ||
41 | private static readonly ILog m_log = | ||
42 | LogManager.GetLogger( | ||
43 | MethodBase.GetCurrentMethod().DeclaringType); | ||
44 | |||
45 | private Dictionary<string, InventoryServicesConnector> m_connectors = new Dictionary<string, InventoryServicesConnector>(); | ||
46 | |||
47 | public HGInventoryServiceConnector(IConfigSource source) | ||
48 | { | ||
49 | IConfig moduleConfig = source.Configs["Modules"]; | ||
50 | if (moduleConfig != null) | ||
51 | { | ||
52 | |||
53 | IConfig inventoryConfig = source.Configs["InventoryService"]; | ||
54 | if (inventoryConfig == null) | ||
55 | { | ||
56 | m_log.Error("[HG INVENTORY SERVICE]: InventoryService missing from OpenSim.ini"); | ||
57 | return; | ||
58 | } | ||
59 | |||
60 | m_log.Info("[HG INVENTORY SERVICE]: HG inventory service enabled"); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | private bool StringToUrlAndUserID(string id, out string url, out string userID) | ||
65 | { | ||
66 | url = String.Empty; | ||
67 | userID = String.Empty; | ||
68 | |||
69 | Uri assetUri; | ||
70 | |||
71 | if (Uri.TryCreate(id, UriKind.Absolute, out assetUri) && | ||
72 | assetUri.Scheme == Uri.UriSchemeHttp) | ||
73 | { | ||
74 | url = "http://" + assetUri.Authority; | ||
75 | userID = assetUri.LocalPath.Trim(new char[] { '/' }); | ||
76 | return true; | ||
77 | } | ||
78 | |||
79 | return false; | ||
80 | } | ||
81 | private ISessionAuthInventoryService GetConnector(string url) | ||
82 | { | ||
83 | InventoryServicesConnector connector = null; | ||
84 | lock (m_connectors) | ||
85 | { | ||
86 | if (m_connectors.ContainsKey(url)) | ||
87 | { | ||
88 | connector = m_connectors[url]; | ||
89 | } | ||
90 | else | ||
91 | { | ||
92 | // We're instantiating this class explicitly, but this won't | ||
93 | // work in general, because the remote grid may be running | ||
94 | // an inventory server that has a different protocol. | ||
95 | // Eventually we will want a piece of protocol asking | ||
96 | // the remote server about its kind. Definitely cool thing to do! | ||
97 | connector = new InventoryServicesConnector(url); | ||
98 | m_connectors.Add(url, connector); | ||
99 | } | ||
100 | } | ||
101 | return connector; | ||
102 | } | ||
103 | |||
104 | public string Host | ||
105 | { | ||
106 | get { return string.Empty; } | ||
107 | } | ||
108 | |||
109 | public void GetUserInventory(string id, UUID sessionID, InventoryReceiptCallback callback) | ||
110 | { | ||
111 | m_log.Debug("[HGInventory]: GetUserInventory " + id); | ||
112 | string url = string.Empty; | ||
113 | string userID = string.Empty; | ||
114 | |||
115 | if (StringToUrlAndUserID(id, out url, out userID)) | ||
116 | { | ||
117 | ISessionAuthInventoryService connector = GetConnector(url); | ||
118 | connector.GetUserInventory(userID, sessionID, callback); | ||
119 | } | ||
120 | |||
121 | } | ||
122 | |||
123 | /// <summary> | ||
124 | /// Gets the user folder for the given folder-type | ||
125 | /// </summary> | ||
126 | /// <param name="userID"></param> | ||
127 | /// <param name="type"></param> | ||
128 | /// <returns></returns> | ||
129 | public Dictionary<AssetType, InventoryFolderBase> GetSystemFolders(string id, UUID sessionID) | ||
130 | { | ||
131 | m_log.Debug("[HGInventory]: GetSystemFolders " + id); | ||
132 | string url = string.Empty; | ||
133 | string userID = string.Empty; | ||
134 | |||
135 | if (StringToUrlAndUserID(id, out url, out userID)) | ||
136 | { | ||
137 | ISessionAuthInventoryService connector = GetConnector(url); | ||
138 | return connector.GetSystemFolders(userID, sessionID); | ||
139 | } | ||
140 | |||
141 | return new Dictionary<AssetType, InventoryFolderBase>(); | ||
142 | } | ||
143 | |||
144 | /// <summary> | ||
145 | /// Gets everything (folders and items) inside a folder | ||
146 | /// </summary> | ||
147 | /// <param name="userId"></param> | ||
148 | /// <param name="folderID"></param> | ||
149 | /// <returns></returns> | ||
150 | public InventoryCollection GetFolderContent(string id, UUID folderID, UUID sessionID) | ||
151 | { | ||
152 | m_log.Debug("[HGInventory]: GetFolderContent " + id); | ||
153 | string url = string.Empty; | ||
154 | string userID = string.Empty; | ||
155 | |||
156 | if (StringToUrlAndUserID(id, out url, out userID)) | ||
157 | { | ||
158 | ISessionAuthInventoryService connector = GetConnector(url); | ||
159 | return connector.GetFolderContent(userID, folderID, sessionID); | ||
160 | } | ||
161 | |||
162 | return null; | ||
163 | } | ||
164 | |||
165 | public bool AddFolder(string id, InventoryFolderBase folder, UUID sessionID) | ||
166 | { | ||
167 | string url = string.Empty; | ||
168 | string userID = string.Empty; | ||
169 | |||
170 | if (StringToUrlAndUserID(id, out url, out userID)) | ||
171 | { | ||
172 | ISessionAuthInventoryService connector = GetConnector(url); | ||
173 | return connector.AddFolder(userID, folder, sessionID); | ||
174 | } | ||
175 | return false; | ||
176 | } | ||
177 | |||
178 | public bool UpdateFolder(string id, InventoryFolderBase folder, UUID sessionID) | ||
179 | { | ||
180 | string url = string.Empty; | ||
181 | string userID = string.Empty; | ||
182 | |||
183 | if (StringToUrlAndUserID(id, out url, out userID)) | ||
184 | { | ||
185 | ISessionAuthInventoryService connector = GetConnector(url); | ||
186 | return connector.UpdateFolder(userID, folder, sessionID); | ||
187 | } | ||
188 | return false; | ||
189 | } | ||
190 | |||
191 | public bool MoveFolder(string id, InventoryFolderBase folder, UUID sessionID) | ||
192 | { | ||
193 | string url = string.Empty; | ||
194 | string userID = string.Empty; | ||
195 | |||
196 | if (StringToUrlAndUserID(id, out url, out userID)) | ||
197 | { | ||
198 | ISessionAuthInventoryService connector = GetConnector(url); | ||
199 | return connector.MoveFolder(userID, folder, sessionID); | ||
200 | } | ||
201 | return false; | ||
202 | } | ||
203 | |||
204 | public bool DeleteFolders(string id, List<UUID> folders, UUID sessionID) | ||
205 | { | ||
206 | string url = string.Empty; | ||
207 | string userID = string.Empty; | ||
208 | |||
209 | if (StringToUrlAndUserID(id, out url, out userID)) | ||
210 | { | ||
211 | ISessionAuthInventoryService connector = GetConnector(url); | ||
212 | return connector.DeleteFolders(userID, folders, sessionID); | ||
213 | } | ||
214 | return false; | ||
215 | } | ||
216 | |||
217 | public bool PurgeFolder(string id, InventoryFolderBase folder, UUID sessionID) | ||
218 | { | ||
219 | string url = string.Empty; | ||
220 | string userID = string.Empty; | ||
221 | |||
222 | if (StringToUrlAndUserID(id, out url, out userID)) | ||
223 | { | ||
224 | ISessionAuthInventoryService connector = GetConnector(url); | ||
225 | return connector.PurgeFolder(userID, folder, sessionID); | ||
226 | } | ||
227 | return false; | ||
228 | } | ||
229 | |||
230 | public List<InventoryItemBase> GetFolderItems(string id, UUID folderID, UUID sessionID) | ||
231 | { | ||
232 | string url = string.Empty; | ||
233 | string userID = string.Empty; | ||
234 | |||
235 | if (StringToUrlAndUserID(id, out url, out userID)) | ||
236 | { | ||
237 | ISessionAuthInventoryService connector = GetConnector(url); | ||
238 | return connector.GetFolderItems(userID, folderID, sessionID); | ||
239 | } | ||
240 | return new List<InventoryItemBase>(); | ||
241 | } | ||
242 | |||
243 | public bool AddItem(string id, InventoryItemBase item, UUID sessionID) | ||
244 | { | ||
245 | string url = string.Empty; | ||
246 | string userID = string.Empty; | ||
247 | |||
248 | if (StringToUrlAndUserID(id, out url, out userID)) | ||
249 | { | ||
250 | ISessionAuthInventoryService connector = GetConnector(url); | ||
251 | return connector.AddItem(userID, item, sessionID); | ||
252 | } | ||
253 | return false; | ||
254 | } | ||
255 | |||
256 | public bool UpdateItem(string id, InventoryItemBase item, UUID sessionID) | ||
257 | { | ||
258 | string url = string.Empty; | ||
259 | string userID = string.Empty; | ||
260 | |||
261 | if (StringToUrlAndUserID(id, out url, out userID)) | ||
262 | { | ||
263 | ISessionAuthInventoryService connector = GetConnector(url); | ||
264 | return connector.UpdateItem(userID, item, sessionID); | ||
265 | } | ||
266 | return false; | ||
267 | } | ||
268 | |||
269 | public bool MoveItems(string id, List<InventoryItemBase> items, UUID sessionID) | ||
270 | { | ||
271 | string url = string.Empty; | ||
272 | string userID = string.Empty; | ||
273 | |||
274 | if (StringToUrlAndUserID(id, out url, out userID)) | ||
275 | { | ||
276 | ISessionAuthInventoryService connector = GetConnector(url); | ||
277 | return connector.MoveItems(userID, items, sessionID); | ||
278 | } | ||
279 | return false; | ||
280 | } | ||
281 | |||
282 | public bool DeleteItems(string id, List<UUID> itemIDs, UUID sessionID) | ||
283 | { | ||
284 | string url = string.Empty; | ||
285 | string userID = string.Empty; | ||
286 | |||
287 | if (StringToUrlAndUserID(id, out url, out userID)) | ||
288 | { | ||
289 | ISessionAuthInventoryService connector = GetConnector(url); | ||
290 | return connector.DeleteItems(userID, itemIDs, sessionID); | ||
291 | } | ||
292 | return false; | ||
293 | } | ||
294 | |||
295 | public InventoryItemBase QueryItem(string id, InventoryItemBase item, UUID sessionID) | ||
296 | { | ||
297 | string url = string.Empty; | ||
298 | string userID = string.Empty; | ||
299 | |||
300 | if (StringToUrlAndUserID(id, out url, out userID)) | ||
301 | { | ||
302 | //m_log.DebugFormat("[HGInventory CONNECTOR]: calling {0}", url); | ||
303 | ISessionAuthInventoryService connector = GetConnector(url); | ||
304 | return connector.QueryItem(userID, item, sessionID); | ||
305 | } | ||
306 | return null; | ||
307 | } | ||
308 | |||
309 | public InventoryFolderBase QueryFolder(string id, InventoryFolderBase folder, UUID sessionID) | ||
310 | { | ||
311 | string url = string.Empty; | ||
312 | string userID = string.Empty; | ||
313 | |||
314 | if (StringToUrlAndUserID(id, out url, out userID)) | ||
315 | { | ||
316 | ISessionAuthInventoryService connector = GetConnector(url); | ||
317 | return connector.QueryFolder(userID, folder, sessionID); | ||
318 | } | ||
319 | return null; | ||
320 | } | ||
321 | |||
322 | public int GetAssetPermissions(string id, UUID assetID, UUID sessionID) | ||
323 | { | ||
324 | string url = string.Empty; | ||
325 | string userID = string.Empty; | ||
326 | |||
327 | if (StringToUrlAndUserID(id, out url, out userID)) | ||
328 | { | ||
329 | ISessionAuthInventoryService connector = GetConnector(url); | ||
330 | return connector.GetAssetPermissions(userID, assetID, sessionID); | ||
331 | } | ||
332 | return 0; | ||
333 | } | ||
334 | } | ||
335 | } | ||
diff --git a/OpenSim/Services/Connectors/Inventory/ISessionAuthInventoryService.cs b/OpenSim/Services/Connectors/Inventory/ISessionAuthInventoryService.cs deleted file mode 100644 index da8c7e2..0000000 --- a/OpenSim/Services/Connectors/Inventory/ISessionAuthInventoryService.cs +++ /dev/null | |||
@@ -1,140 +0,0 @@ | |||
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 | |||
28 | using System.Collections.Generic; | ||
29 | using OpenSim.Framework; | ||
30 | using OpenSim.Services.Interfaces; | ||
31 | using OpenMetaverse; | ||
32 | |||
33 | namespace OpenSim.Services.Connectors | ||
34 | { | ||
35 | /// <summary> | ||
36 | /// Defines all operations to access a remote inventory service | ||
37 | /// using session authentication as a form of security. | ||
38 | /// </summary> | ||
39 | public interface ISessionAuthInventoryService | ||
40 | { | ||
41 | string Host | ||
42 | { | ||
43 | get; | ||
44 | } | ||
45 | |||
46 | /// <summary> | ||
47 | /// Request the inventory for a user. This is an asynchronous operation that will call the callback when the | ||
48 | /// inventory has been received | ||
49 | /// </summary> | ||
50 | /// <param name="userID"></param> | ||
51 | /// <param name="callback"></param> | ||
52 | void GetUserInventory(string userID, UUID session_id, InventoryReceiptCallback callback); | ||
53 | |||
54 | /// <summary> | ||
55 | /// Gets the user folder for the given folder-type | ||
56 | /// </summary> | ||
57 | /// <param name="userID"></param> | ||
58 | /// <param name="type"></param> | ||
59 | /// <returns></returns> | ||
60 | Dictionary<AssetType, InventoryFolderBase> GetSystemFolders(string userID, UUID session_id); | ||
61 | |||
62 | /// <summary> | ||
63 | /// Gets everything (folders and items) inside a folder | ||
64 | /// </summary> | ||
65 | /// <param name="userId"></param> | ||
66 | /// <param name="folderID"></param> | ||
67 | /// <returns></returns> | ||
68 | InventoryCollection GetFolderContent(string userID, UUID folderID, UUID session_id); | ||
69 | |||
70 | /// <summary> | ||
71 | /// Add a new folder to the user's inventory | ||
72 | /// </summary> | ||
73 | /// <param name="folder"></param> | ||
74 | /// <returns>true if the folder was successfully added</returns> | ||
75 | bool AddFolder(string userID, InventoryFolderBase folder, UUID session_id); | ||
76 | |||
77 | /// <summary> | ||
78 | /// Update a folder in the user's inventory | ||
79 | /// </summary> | ||
80 | /// <param name="folder"></param> | ||
81 | /// <returns>true if the folder was successfully updated</returns> | ||
82 | bool UpdateFolder(string userID, InventoryFolderBase folder, UUID session_id); | ||
83 | |||
84 | /// <summary> | ||
85 | /// Move an inventory folder to a new location | ||
86 | /// </summary> | ||
87 | /// <param name="folder">A folder containing the details of the new location</param> | ||
88 | /// <returns>true if the folder was successfully moved</returns> | ||
89 | bool MoveFolder(string userID, InventoryFolderBase folder, UUID session_id); | ||
90 | |||
91 | /// <summary> | ||
92 | /// Delete a list of inventory folders (from trash) | ||
93 | /// </summary> | ||
94 | bool DeleteFolders(string userID, List<UUID> folders, UUID session_id); | ||
95 | |||
96 | /// <summary> | ||
97 | /// Purge an inventory folder of all its items and subfolders. | ||
98 | /// </summary> | ||
99 | /// <param name="folder"></param> | ||
100 | /// <returns>true if the folder was successfully purged</returns> | ||
101 | bool PurgeFolder(string userID, InventoryFolderBase folder, UUID session_id); | ||
102 | |||
103 | /// <summary> | ||
104 | /// Get items from a folder. | ||
105 | /// </summary> | ||
106 | /// <param name="folder"></param> | ||
107 | /// <returns>true if the folder was successfully purged</returns> | ||
108 | List<InventoryItemBase> GetFolderItems(string userID, UUID folderID, UUID session_id); | ||
109 | |||
110 | /// <summary> | ||
111 | /// Add a new item to the user's inventory | ||
112 | /// </summary> | ||
113 | /// <param name="item"></param> | ||
114 | /// <returns>true if the item was successfully added</returns> | ||
115 | bool AddItem(string userID, InventoryItemBase item, UUID session_id); | ||
116 | |||
117 | /// <summary> | ||
118 | /// Update an item in the user's inventory | ||
119 | /// </summary> | ||
120 | /// <param name="item"></param> | ||
121 | /// <returns>true if the item was successfully updated</returns> | ||
122 | bool UpdateItem(string userID, InventoryItemBase item, UUID session_id); | ||
123 | |||
124 | bool MoveItems(string userID, List<InventoryItemBase> items, UUID session_id); | ||
125 | |||
126 | /// <summary> | ||
127 | /// Delete an item from the user's inventory | ||
128 | /// </summary> | ||
129 | /// <param name="item"></param> | ||
130 | /// <returns>true if the item was successfully deleted</returns> | ||
131 | bool DeleteItems(string userID, List<UUID> itemIDs, UUID session_id); | ||
132 | |||
133 | InventoryItemBase QueryItem(string userID, InventoryItemBase item, UUID session_id); | ||
134 | |||
135 | InventoryFolderBase QueryFolder(string userID, InventoryFolderBase item, UUID session_id); | ||
136 | |||
137 | int GetAssetPermissions(string userID, UUID assetID, UUID session_id); | ||
138 | |||
139 | } | ||
140 | } | ||
diff --git a/OpenSim/Services/Connectors/Inventory/InventoryServiceConnector.cs b/OpenSim/Services/Connectors/Inventory/InventoryServiceConnector.cs deleted file mode 100644 index f86b453..0000000 --- a/OpenSim/Services/Connectors/Inventory/InventoryServiceConnector.cs +++ /dev/null | |||
@@ -1,582 +0,0 @@ | |||
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 | |||
28 | using log4net; | ||
29 | using System; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Reflection; | ||
33 | using Nini.Config; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Servers.HttpServer; | ||
36 | using OpenSim.Services.Interfaces; | ||
37 | using OpenMetaverse; | ||
38 | |||
39 | namespace OpenSim.Services.Connectors | ||
40 | { | ||
41 | public class InventoryServicesConnector : ISessionAuthInventoryService | ||
42 | { | ||
43 | private static readonly ILog m_log = | ||
44 | LogManager.GetLogger( | ||
45 | MethodBase.GetCurrentMethod().DeclaringType); | ||
46 | |||
47 | private string m_ServerURI = String.Empty; | ||
48 | |||
49 | private Dictionary<UUID, InventoryReceiptCallback> m_RequestingInventory = new Dictionary<UUID, InventoryReceiptCallback>(); | ||
50 | private Dictionary<UUID, DateTime> m_RequestTime = new Dictionary<UUID, DateTime>(); | ||
51 | |||
52 | public InventoryServicesConnector() | ||
53 | { | ||
54 | } | ||
55 | |||
56 | public InventoryServicesConnector(string serverURI) | ||
57 | { | ||
58 | m_ServerURI = serverURI.TrimEnd('/'); | ||
59 | } | ||
60 | |||
61 | public InventoryServicesConnector(IConfigSource source) | ||
62 | { | ||
63 | Initialise(source); | ||
64 | } | ||
65 | |||
66 | public virtual void Initialise(IConfigSource source) | ||
67 | { | ||
68 | IConfig inventoryConfig = source.Configs["InventoryService"]; | ||
69 | if (inventoryConfig == null) | ||
70 | { | ||
71 | m_log.Error("[INVENTORY CONNECTOR]: InventoryService missing from OpenSim.ini"); | ||
72 | throw new Exception("InventoryService missing from OpenSim.ini"); | ||
73 | } | ||
74 | |||
75 | string serviceURI = inventoryConfig.GetString("InventoryServerURI", | ||
76 | String.Empty); | ||
77 | |||
78 | if (serviceURI == String.Empty) | ||
79 | { | ||
80 | m_log.Error("[INVENTORY CONNECTOR]: No Server URI named in section InventoryService"); | ||
81 | throw new Exception("Unable to proceed. Please make sure your ini files in config-include are updated according to .example's"); | ||
82 | } | ||
83 | m_ServerURI = serviceURI.TrimEnd('/'); | ||
84 | } | ||
85 | |||
86 | #region ISessionAuthInventoryService | ||
87 | |||
88 | public string Host | ||
89 | { | ||
90 | get { return m_ServerURI; } | ||
91 | } | ||
92 | |||
93 | /// <summary> | ||
94 | /// Caller must catch eventual Exceptions. | ||
95 | /// </summary> | ||
96 | /// <param name="userID"></param> | ||
97 | /// <param name="sessionID"></param> | ||
98 | /// <param name="callback"></param> | ||
99 | public void GetUserInventory(string userIDStr, UUID sessionID, InventoryReceiptCallback callback) | ||
100 | { | ||
101 | UUID userID = UUID.Zero; | ||
102 | if (UUID.TryParse(userIDStr, out userID)) | ||
103 | { | ||
104 | lock (m_RequestingInventory) | ||
105 | { | ||
106 | // *HACK ALERT* | ||
107 | |||
108 | // If an inventory request times out, it blocks any further requests from the | ||
109 | // same user, even after a relog. This is bad, and makes me sad. | ||
110 | |||
111 | // Really, we should detect a timeout and report a failure to the callback, | ||
112 | // BUT in my testing i found that it's hard to detect a timeout.. sometimes, | ||
113 | // a partial response is recieved, and sometimes a null response. | ||
114 | |||
115 | // So, for now, add a timer of ten seconds (which is the request timeout). | ||
116 | |||
117 | // This should basically have the same effect. | ||
118 | |||
119 | lock (m_RequestTime) | ||
120 | { | ||
121 | if (m_RequestTime.ContainsKey(userID)) | ||
122 | { | ||
123 | TimeSpan interval = DateTime.Now - m_RequestTime[userID]; | ||
124 | if (interval.TotalSeconds > 10) | ||
125 | { | ||
126 | m_RequestTime.Remove(userID); | ||
127 | if (m_RequestingInventory.ContainsKey(userID)) | ||
128 | { | ||
129 | m_RequestingInventory.Remove(userID); | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | if (!m_RequestingInventory.ContainsKey(userID)) | ||
134 | { | ||
135 | m_RequestTime.Add(userID, DateTime.Now); | ||
136 | m_RequestingInventory.Add(userID, callback); | ||
137 | } | ||
138 | else | ||
139 | { | ||
140 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: GetUserInventory - ignoring repeated request for user {0}", userID); | ||
141 | return; | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | |||
146 | m_log.InfoFormat( | ||
147 | "[INVENTORY CONNECTOR]: Requesting inventory from {0}/GetInventory/ for user {1}", | ||
148 | m_ServerURI, userID); | ||
149 | |||
150 | RestSessionObjectPosterResponse<Guid, InventoryCollection> requester | ||
151 | = new RestSessionObjectPosterResponse<Guid, InventoryCollection>(); | ||
152 | requester.ResponseCallback = InventoryResponse; | ||
153 | |||
154 | requester.BeginPostObject(m_ServerURI + "/GetInventory/", userID.Guid, sessionID.ToString(), userID.ToString()); | ||
155 | } | ||
156 | } | ||
157 | |||
158 | /// <summary> | ||
159 | /// Gets the user folder for the given folder-type | ||
160 | /// </summary> | ||
161 | /// <param name="userID"></param> | ||
162 | /// <param name="type"></param> | ||
163 | /// <returns></returns> | ||
164 | public Dictionary<AssetType, InventoryFolderBase> GetSystemFolders(string userID, UUID sessionID) | ||
165 | { | ||
166 | List<InventoryFolderBase> folders = null; | ||
167 | Dictionary<AssetType, InventoryFolderBase> dFolders = new Dictionary<AssetType, InventoryFolderBase>(); | ||
168 | try | ||
169 | { | ||
170 | folders = SynchronousRestSessionObjectPoster<Guid, List<InventoryFolderBase>>.BeginPostObject( | ||
171 | "POST", m_ServerURI + "/SystemFolders/", new Guid(userID), sessionID.ToString(), userID.ToString()); | ||
172 | |||
173 | foreach (InventoryFolderBase f in folders) | ||
174 | dFolders[(AssetType)f.Type] = f; | ||
175 | |||
176 | return dFolders; | ||
177 | } | ||
178 | catch (Exception e) | ||
179 | { | ||
180 | // Maybe we're talking to an old inventory server. Try this other thing. | ||
181 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: GetSystemFolders operation failed, {0} {1} (old sever?). Trying GetInventory.", | ||
182 | e.Source, e.Message); | ||
183 | |||
184 | try | ||
185 | { | ||
186 | InventoryCollection inventory = SynchronousRestSessionObjectPoster<Guid, InventoryCollection>.BeginPostObject( | ||
187 | "POST", m_ServerURI + "/GetInventory/", new Guid(userID), sessionID.ToString(), userID.ToString()); | ||
188 | folders = inventory.Folders; | ||
189 | } | ||
190 | catch (Exception ex) | ||
191 | { | ||
192 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: GetInventory operation also failed, {0} {1}. Giving up.", | ||
193 | e.Source, ex.Message); | ||
194 | } | ||
195 | |||
196 | if ((folders != null) && (folders.Count > 0)) | ||
197 | { | ||
198 | m_log.DebugFormat("[INVENTORY CONNECTOR]: Received entire inventory ({0} folders) for user {1}", | ||
199 | folders.Count, userID); | ||
200 | foreach (InventoryFolderBase f in folders) | ||
201 | { | ||
202 | if ((f.Type != (short)AssetType.Folder) && (f.Type != (short)AssetType.Unknown)) | ||
203 | dFolders[(AssetType)f.Type] = f; | ||
204 | } | ||
205 | |||
206 | UUID rootFolderID = dFolders[AssetType.Animation].ParentID; | ||
207 | InventoryFolderBase rootFolder = new InventoryFolderBase(rootFolderID, new UUID(userID)); | ||
208 | rootFolder = QueryFolder(userID, rootFolder, sessionID); | ||
209 | dFolders[AssetType.Folder] = rootFolder; | ||
210 | m_log.DebugFormat("[INVENTORY CONNECTOR]: {0} system folders for user {1}", dFolders.Count, userID); | ||
211 | return dFolders; | ||
212 | } | ||
213 | } | ||
214 | |||
215 | return new Dictionary<AssetType, InventoryFolderBase>(); | ||
216 | } | ||
217 | |||
218 | /// <summary> | ||
219 | /// Gets everything (folders and items) inside a folder | ||
220 | /// </summary> | ||
221 | /// <param name="userId"></param> | ||
222 | /// <param name="folderID"></param> | ||
223 | /// <returns></returns> | ||
224 | public InventoryCollection GetFolderContent(string userID, UUID folderID, UUID sessionID) | ||
225 | { | ||
226 | try | ||
227 | { | ||
228 | // normal case | ||
229 | return SynchronousRestSessionObjectPoster<Guid, InventoryCollection>.BeginPostObject( | ||
230 | "POST", m_ServerURI + "/GetFolderContent/", folderID.Guid, sessionID.ToString(), userID.ToString()); | ||
231 | } | ||
232 | catch (TimeoutException e) | ||
233 | { | ||
234 | m_log.ErrorFormat( | ||
235 | "[INVENTORY CONNECTOR]: GetFolderContent operation to {0} for {1} timed out {2} {3}.", | ||
236 | m_ServerURI, folderID, e.Source, e.Message); | ||
237 | } | ||
238 | catch (Exception e) | ||
239 | { | ||
240 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: GetFolderContent operation failed for {0}, {1} {2} (old server?).", | ||
241 | folderID, e.Source, e.Message); | ||
242 | } | ||
243 | |||
244 | InventoryCollection nullCollection = new InventoryCollection(); | ||
245 | nullCollection.Folders = new List<InventoryFolderBase>(); | ||
246 | nullCollection.Items = new List<InventoryItemBase>(); | ||
247 | nullCollection.UserID = new UUID(userID); | ||
248 | return nullCollection; | ||
249 | } | ||
250 | |||
251 | public bool AddFolder(string userID, InventoryFolderBase folder, UUID sessionID) | ||
252 | { | ||
253 | try | ||
254 | { | ||
255 | return SynchronousRestSessionObjectPoster<InventoryFolderBase, bool>.BeginPostObject( | ||
256 | "POST", m_ServerURI + "/NewFolder/", folder, sessionID.ToString(), folder.Owner.ToString()); | ||
257 | } | ||
258 | catch (Exception e) | ||
259 | { | ||
260 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: Add new inventory folder operation failed for {0} {1}, {2} {3}", | ||
261 | folder.Name, folder.ID, e.Source, e.Message); | ||
262 | } | ||
263 | |||
264 | return false; | ||
265 | } | ||
266 | |||
267 | public bool UpdateFolder(string userID, InventoryFolderBase folder, UUID sessionID) | ||
268 | { | ||
269 | try | ||
270 | { | ||
271 | return SynchronousRestSessionObjectPoster<InventoryFolderBase, bool>.BeginPostObject( | ||
272 | "POST", m_ServerURI + "/UpdateFolder/", folder, sessionID.ToString(), folder.Owner.ToString()); | ||
273 | } | ||
274 | catch (Exception e) | ||
275 | { | ||
276 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: Update inventory folder operation failed for {0} {1}, {2} {3}", | ||
277 | folder.Name, folder.ID, e.Source, e.Message); | ||
278 | } | ||
279 | |||
280 | return false; | ||
281 | } | ||
282 | |||
283 | public bool DeleteFolders(string userID, List<UUID> folderIDs, UUID sessionID) | ||
284 | { | ||
285 | try | ||
286 | { | ||
287 | List<Guid> guids = new List<Guid>(); | ||
288 | foreach (UUID u in folderIDs) | ||
289 | guids.Add(u.Guid); | ||
290 | return SynchronousRestSessionObjectPoster<List<Guid>, bool>.BeginPostObject( | ||
291 | "POST", m_ServerURI + "/DeleteFolders/", guids, sessionID.ToString(), userID); | ||
292 | } | ||
293 | catch (Exception e) | ||
294 | { | ||
295 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: Delete inventory folders operation failed, {0} {1}", | ||
296 | e.Source, e.Message); | ||
297 | } | ||
298 | |||
299 | return false; | ||
300 | } | ||
301 | |||
302 | public bool MoveFolder(string userID, InventoryFolderBase folder, UUID sessionID) | ||
303 | { | ||
304 | try | ||
305 | { | ||
306 | return SynchronousRestSessionObjectPoster<InventoryFolderBase, bool>.BeginPostObject( | ||
307 | "POST", m_ServerURI + "/MoveFolder/", folder, sessionID.ToString(), folder.Owner.ToString()); | ||
308 | } | ||
309 | catch (Exception e) | ||
310 | { | ||
311 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: Move inventory folder operation failed for {0} {1}, {2} {3}", | ||
312 | folder.Name, folder.ID, e.Source, e.Message); | ||
313 | } | ||
314 | |||
315 | return false; | ||
316 | } | ||
317 | |||
318 | public bool PurgeFolder(string userID, InventoryFolderBase folder, UUID sessionID) | ||
319 | { | ||
320 | try | ||
321 | { | ||
322 | return SynchronousRestSessionObjectPoster<InventoryFolderBase, bool>.BeginPostObject( | ||
323 | "POST", m_ServerURI + "/PurgeFolder/", folder, sessionID.ToString(), folder.Owner.ToString()); | ||
324 | } | ||
325 | catch (Exception e) | ||
326 | { | ||
327 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: Purge inventory folder operation failed for {0} {1}, {2} {3}", | ||
328 | folder.Name, folder.ID, e.Source, e.Message); | ||
329 | } | ||
330 | |||
331 | return false; | ||
332 | } | ||
333 | |||
334 | public List<InventoryItemBase> GetFolderItems(string userID, UUID folderID, UUID sessionID) | ||
335 | { | ||
336 | try | ||
337 | { | ||
338 | InventoryFolderBase folder = new InventoryFolderBase(folderID, new UUID(userID)); | ||
339 | return SynchronousRestSessionObjectPoster<InventoryFolderBase, List<InventoryItemBase>>.BeginPostObject( | ||
340 | "POST", m_ServerURI + "/GetItems/", folder, sessionID.ToString(), userID); | ||
341 | } | ||
342 | catch (Exception e) | ||
343 | { | ||
344 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: Get folder items operation failed for folder {0}, {1} {2}", | ||
345 | folderID, e.Source, e.Message); | ||
346 | } | ||
347 | |||
348 | return null; | ||
349 | } | ||
350 | |||
351 | public bool AddItem(string userID, InventoryItemBase item, UUID sessionID) | ||
352 | { | ||
353 | try | ||
354 | { | ||
355 | return SynchronousRestSessionObjectPoster<InventoryItemBase, bool>.BeginPostObject( | ||
356 | "POST", m_ServerURI + "/NewItem/", item, sessionID.ToString(), item.Owner.ToString()); | ||
357 | } | ||
358 | catch (Exception e) | ||
359 | { | ||
360 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: Add new inventory item operation failed for {0} {1}, {2} {3}", | ||
361 | item.Name, item.ID, e.Source, e.Message); | ||
362 | } | ||
363 | |||
364 | return false; | ||
365 | } | ||
366 | |||
367 | public bool UpdateItem(string userID, InventoryItemBase item, UUID sessionID) | ||
368 | { | ||
369 | try | ||
370 | { | ||
371 | return SynchronousRestSessionObjectPoster<InventoryItemBase, bool>.BeginPostObject( | ||
372 | "POST", m_ServerURI + "/NewItem/", item, sessionID.ToString(), item.Owner.ToString()); | ||
373 | } | ||
374 | catch (Exception e) | ||
375 | { | ||
376 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: Update new inventory item operation failed for {0} {1}, {2} {3}", | ||
377 | item.Name, item.ID, e.Source, e.Message); | ||
378 | } | ||
379 | |||
380 | return false; | ||
381 | } | ||
382 | |||
383 | /** | ||
384 | * MoveItems Async group | ||
385 | */ | ||
386 | |||
387 | delegate void MoveItemsDelegate(string userID, List<InventoryItemBase> items, UUID sessionID); | ||
388 | |||
389 | private void MoveItemsAsync(string userID, List<InventoryItemBase> items, UUID sessionID) | ||
390 | { | ||
391 | if (items == null) | ||
392 | { | ||
393 | m_log.WarnFormat("[INVENTORY CONNECTOR]: request to move items got a null list."); | ||
394 | return; | ||
395 | } | ||
396 | |||
397 | try | ||
398 | { | ||
399 | //SynchronousRestSessionObjectPoster<List<InventoryItemBase>, bool>.BeginPostObject( | ||
400 | // "POST", m_ServerURI + "/MoveItems/", items, sessionID.ToString(), userID.ToString()); | ||
401 | |||
402 | //// Success | ||
403 | //return; | ||
404 | string uri = m_ServerURI + "/inventory/" + userID; | ||
405 | if (SynchronousRestObjectRequester. | ||
406 | MakeRequest<List<InventoryItemBase>, bool>("PUT", uri, items)) | ||
407 | m_log.DebugFormat("[INVENTORY CONNECTOR]: move {0} items poster succeeded {1}", items.Count, uri); | ||
408 | else | ||
409 | m_log.DebugFormat("[INVENTORY CONNECTOR]: move {0} items poster failed {1}", items.Count, uri); ; | ||
410 | |||
411 | return; | ||
412 | |||
413 | } | ||
414 | catch (Exception e) | ||
415 | { | ||
416 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: Move inventory items operation failed, {0} {1} (old server?). Trying slow way.", | ||
417 | e.Source, e.Message); | ||
418 | } | ||
419 | |||
420 | } | ||
421 | |||
422 | private void MoveItemsCompleted(IAsyncResult iar) | ||
423 | { | ||
424 | MoveItemsDelegate d = (MoveItemsDelegate)iar.AsyncState; | ||
425 | d.EndInvoke(iar); | ||
426 | } | ||
427 | |||
428 | public bool MoveItems(string userID, List<InventoryItemBase> items, UUID sessionID) | ||
429 | { | ||
430 | MoveItemsDelegate d = MoveItemsAsync; | ||
431 | d.BeginInvoke(userID, items, sessionID, MoveItemsCompleted, d); | ||
432 | return true; | ||
433 | } | ||
434 | |||
435 | public bool DeleteItems(string userID, List<UUID> items, UUID sessionID) | ||
436 | { | ||
437 | try | ||
438 | { | ||
439 | List<Guid> guids = new List<Guid>(); | ||
440 | foreach (UUID u in items) | ||
441 | guids.Add(u.Guid); | ||
442 | return SynchronousRestSessionObjectPoster<List<Guid>, bool>.BeginPostObject( | ||
443 | "POST", m_ServerURI + "/DeleteItem/", guids, sessionID.ToString(), userID); | ||
444 | } | ||
445 | catch (Exception e) | ||
446 | { | ||
447 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: Delete inventory items operation failed, {0} {1}", | ||
448 | e.Source, e.Message); | ||
449 | } | ||
450 | |||
451 | return false; | ||
452 | } | ||
453 | |||
454 | public InventoryItemBase QueryItem(string userID, InventoryItemBase item, UUID sessionID) | ||
455 | { | ||
456 | try | ||
457 | { | ||
458 | return SynchronousRestSessionObjectPoster<InventoryItemBase, InventoryItemBase>.BeginPostObject( | ||
459 | "POST", m_ServerURI + "/QueryItem/", item, sessionID.ToString(), item.Owner.ToString()); | ||
460 | } | ||
461 | catch (Exception e) | ||
462 | { | ||
463 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: Query inventory item operation failed, {0} {1}", | ||
464 | e.Source, e.Message); | ||
465 | } | ||
466 | |||
467 | return null; | ||
468 | } | ||
469 | |||
470 | public InventoryFolderBase QueryFolder(string userID, InventoryFolderBase folder, UUID sessionID) | ||
471 | { | ||
472 | try | ||
473 | { | ||
474 | return SynchronousRestSessionObjectPoster<InventoryFolderBase, InventoryFolderBase>.BeginPostObject( | ||
475 | "POST", m_ServerURI + "/QueryFolder/", folder, sessionID.ToString(), userID); | ||
476 | } | ||
477 | catch (Exception e) | ||
478 | { | ||
479 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: Query inventory folder operation failed, {0} {1}", | ||
480 | e.Source, e.Message); | ||
481 | } | ||
482 | |||
483 | return null; | ||
484 | } | ||
485 | |||
486 | public int GetAssetPermissions(string userID, UUID assetID, UUID sessionID) | ||
487 | { | ||
488 | try | ||
489 | { | ||
490 | InventoryItemBase item = new InventoryItemBase(); | ||
491 | item.Owner = new UUID(userID); | ||
492 | item.AssetID = assetID; | ||
493 | return SynchronousRestSessionObjectPoster<InventoryItemBase, int>.BeginPostObject( | ||
494 | "POST", m_ServerURI + "/AssetPermissions/", item, sessionID.ToString(), userID); | ||
495 | } | ||
496 | catch (Exception e) | ||
497 | { | ||
498 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: AssetPermissions operation failed, {0} {1}", | ||
499 | e.Source, e.Message); | ||
500 | } | ||
501 | |||
502 | return 0; | ||
503 | } | ||
504 | |||
505 | #endregion | ||
506 | |||
507 | /// <summary> | ||
508 | /// Callback used by the inventory server GetInventory request | ||
509 | /// </summary> | ||
510 | /// <param name="userID"></param> | ||
511 | private void InventoryResponse(InventoryCollection response) | ||
512 | { | ||
513 | UUID userID = response.UserID; | ||
514 | InventoryReceiptCallback callback = null; | ||
515 | lock (m_RequestingInventory) | ||
516 | { | ||
517 | if (m_RequestingInventory.ContainsKey(userID)) | ||
518 | { | ||
519 | callback = m_RequestingInventory[userID]; | ||
520 | m_RequestingInventory.Remove(userID); | ||
521 | lock (m_RequestTime) | ||
522 | { | ||
523 | if (m_RequestTime.ContainsKey(userID)) | ||
524 | { | ||
525 | m_RequestTime.Remove(userID); | ||
526 | } | ||
527 | } | ||
528 | } | ||
529 | else | ||
530 | { | ||
531 | m_log.WarnFormat( | ||
532 | "[INVENTORY CONNECTOR]: " + | ||
533 | "Received inventory response for {0} for which we do not have a record of requesting!", | ||
534 | userID); | ||
535 | return; | ||
536 | } | ||
537 | } | ||
538 | |||
539 | m_log.InfoFormat("[INVENTORY CONNECTOR]: " + | ||
540 | "Received inventory response for user {0} containing {1} folders and {2} items", | ||
541 | userID, response.Folders.Count, response.Items.Count); | ||
542 | |||
543 | InventoryFolderImpl rootFolder = null; | ||
544 | |||
545 | ICollection<InventoryFolderImpl> folders = new List<InventoryFolderImpl>(); | ||
546 | ICollection<InventoryItemBase> items = new List<InventoryItemBase>(); | ||
547 | |||
548 | foreach (InventoryFolderBase folder in response.Folders) | ||
549 | { | ||
550 | if (folder.ParentID == UUID.Zero) | ||
551 | { | ||
552 | rootFolder = new InventoryFolderImpl(folder); | ||
553 | folders.Add(rootFolder); | ||
554 | |||
555 | break; | ||
556 | } | ||
557 | } | ||
558 | |||
559 | if (rootFolder != null) | ||
560 | { | ||
561 | foreach (InventoryFolderBase folder in response.Folders) | ||
562 | { | ||
563 | if (folder.ID != rootFolder.ID) | ||
564 | { | ||
565 | folders.Add(new InventoryFolderImpl(folder)); | ||
566 | } | ||
567 | } | ||
568 | |||
569 | foreach (InventoryItemBase item in response.Items) | ||
570 | { | ||
571 | items.Add(item); | ||
572 | } | ||
573 | } | ||
574 | else | ||
575 | { | ||
576 | m_log.ErrorFormat("[INVENTORY CONNECTOR]: Did not get back an inventory containing a root folder for user {0}", userID); | ||
577 | } | ||
578 | |||
579 | callback(folders, items); | ||
580 | } | ||
581 | } | ||
582 | } | ||
diff --git a/OpenSim/Services/Connectors/Inventory/QuickAndDirtyInventoryServiceConnector.cs b/OpenSim/Services/Connectors/Inventory/QuickAndDirtyInventoryServiceConnector.cs deleted file mode 100644 index a7aa138..0000000 --- a/OpenSim/Services/Connectors/Inventory/QuickAndDirtyInventoryServiceConnector.cs +++ /dev/null | |||
@@ -1,196 +0,0 @@ | |||
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 | |||
28 | using log4net; | ||
29 | using System; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Reflection; | ||
33 | using Nini.Config; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Servers.HttpServer; | ||
36 | using OpenSim.Services.Interfaces; | ||
37 | using OpenMetaverse; | ||
38 | |||
39 | namespace OpenSim.Services.Connectors | ||
40 | { | ||
41 | /// <summary> | ||
42 | /// This connector is temporary. It's used by the user server, before that server is refactored. | ||
43 | /// </summary> | ||
44 | public class QuickAndDirtyInventoryServiceConnector : IInventoryService | ||
45 | { | ||
46 | // private static readonly ILog m_log = | ||
47 | // LogManager.GetLogger( | ||
48 | // MethodBase.GetCurrentMethod().DeclaringType); | ||
49 | |||
50 | private string m_ServerURI = String.Empty; | ||
51 | |||
52 | //private Dictionary<UUID, InventoryReceiptCallback> m_RequestingInventory = new Dictionary<UUID, InventoryReceiptCallback>(); | ||
53 | |||
54 | public QuickAndDirtyInventoryServiceConnector() | ||
55 | { | ||
56 | } | ||
57 | |||
58 | public QuickAndDirtyInventoryServiceConnector(string serverURI) | ||
59 | { | ||
60 | m_ServerURI = serverURI.TrimEnd('/'); | ||
61 | } | ||
62 | |||
63 | /// <summary> | ||
64 | /// <see cref="OpenSim.Framework.Communications.IInterServiceInventoryServices"/> | ||
65 | /// </summary> | ||
66 | /// <param name="userId"></param> | ||
67 | /// <returns></returns> | ||
68 | public bool CreateUserInventory(UUID userId) | ||
69 | { | ||
70 | return SynchronousRestObjectPoster.BeginPostObject<Guid, bool>( | ||
71 | "POST", m_ServerURI + "CreateInventory/", userId.Guid); | ||
72 | } | ||
73 | |||
74 | /// <summary> | ||
75 | /// <see cref="OpenSim.Framework.Communications.IInterServiceInventoryServices"/> | ||
76 | /// </summary> | ||
77 | /// <param name="userId"></param> | ||
78 | /// <returns></returns> | ||
79 | public List<InventoryFolderBase> GetInventorySkeleton(UUID userId) | ||
80 | { | ||
81 | return SynchronousRestObjectPoster.BeginPostObject<Guid, List<InventoryFolderBase>>( | ||
82 | "POST", m_ServerURI + "RootFolders/", userId.Guid); | ||
83 | } | ||
84 | |||
85 | /// <summary> | ||
86 | /// Returns a list of all the active gestures in a user's inventory. | ||
87 | /// </summary> | ||
88 | /// <param name="userId"> | ||
89 | /// The <see cref="UUID"/> of the user | ||
90 | /// </param> | ||
91 | /// <returns> | ||
92 | /// A flat list of the gesture items. | ||
93 | /// </returns> | ||
94 | public List<InventoryItemBase> GetActiveGestures(UUID userId) | ||
95 | { | ||
96 | return SynchronousRestObjectPoster.BeginPostObject<Guid, List<InventoryItemBase>>( | ||
97 | "POST", m_ServerURI + "ActiveGestures/", userId.Guid); | ||
98 | } | ||
99 | |||
100 | public InventoryCollection GetUserInventory(UUID userID) | ||
101 | { | ||
102 | return null; | ||
103 | } | ||
104 | |||
105 | public void GetUserInventory(UUID userID, InventoryReceiptCallback callback) | ||
106 | { | ||
107 | } | ||
108 | |||
109 | public InventoryFolderBase GetFolderForType(UUID userID, AssetType type) | ||
110 | { | ||
111 | return null; | ||
112 | } | ||
113 | |||
114 | public InventoryCollection GetFolderContent(UUID userID, UUID folderID) | ||
115 | { | ||
116 | return null; | ||
117 | } | ||
118 | |||
119 | public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID) | ||
120 | { | ||
121 | return null; | ||
122 | } | ||
123 | |||
124 | public bool AddFolder(InventoryFolderBase folder) | ||
125 | { | ||
126 | return false; | ||
127 | } | ||
128 | |||
129 | public bool UpdateFolder(InventoryFolderBase folder) | ||
130 | { | ||
131 | return false; | ||
132 | } | ||
133 | |||
134 | public bool MoveFolder(InventoryFolderBase folder) | ||
135 | { | ||
136 | return false; | ||
137 | } | ||
138 | |||
139 | public bool DeleteFolders(UUID ownerID, List<UUID> folderIDs) | ||
140 | { | ||
141 | return false; | ||
142 | } | ||
143 | |||
144 | |||
145 | public bool PurgeFolder(InventoryFolderBase folder) | ||
146 | { | ||
147 | return false; | ||
148 | } | ||
149 | |||
150 | public bool AddItem(InventoryItemBase item) | ||
151 | { | ||
152 | return false; | ||
153 | } | ||
154 | |||
155 | public bool UpdateItem(InventoryItemBase item) | ||
156 | { | ||
157 | return false; | ||
158 | } | ||
159 | |||
160 | public bool MoveItems(UUID ownerID, List<InventoryItemBase> items) | ||
161 | { | ||
162 | return false; | ||
163 | } | ||
164 | |||
165 | public bool DeleteItems(UUID owner, List<UUID> itemIDs) | ||
166 | { | ||
167 | return false; | ||
168 | } | ||
169 | |||
170 | public InventoryItemBase GetItem(InventoryItemBase item) | ||
171 | { | ||
172 | return null; | ||
173 | } | ||
174 | |||
175 | public InventoryFolderBase GetFolder(InventoryFolderBase folder) | ||
176 | { | ||
177 | return null; | ||
178 | } | ||
179 | |||
180 | public bool HasInventoryForUser(UUID userID) | ||
181 | { | ||
182 | return false; | ||
183 | } | ||
184 | |||
185 | public InventoryFolderBase GetRootFolder(UUID userID) | ||
186 | { | ||
187 | return null; | ||
188 | } | ||
189 | |||
190 | public int GetAssetPermissions(UUID userID, UUID assetID) | ||
191 | { | ||
192 | return 0; | ||
193 | } | ||
194 | |||
195 | } | ||
196 | } | ||
diff --git a/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs b/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs index b9ccd7e..a662abb 100644 --- a/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs +++ b/OpenSim/Services/Connectors/Inventory/XInventoryConnector.cs | |||
@@ -34,7 +34,6 @@ using Nini.Config; | |||
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Framework.Console; | 35 | using OpenSim.Framework.Console; |
36 | using OpenSim.Framework.Communications; | 36 | using OpenSim.Framework.Communications; |
37 | using OpenSim.Framework.Servers.HttpServer; | ||
38 | using OpenSim.Services.Interfaces; | 37 | using OpenSim.Services.Interfaces; |
39 | using OpenSim.Server.Base; | 38 | using OpenSim.Server.Base; |
40 | using OpenMetaverse; | 39 | using OpenMetaverse; |
@@ -68,7 +67,7 @@ namespace OpenSim.Services.Connectors | |||
68 | IConfig assetConfig = source.Configs["InventoryService"]; | 67 | IConfig assetConfig = source.Configs["InventoryService"]; |
69 | if (assetConfig == null) | 68 | if (assetConfig == null) |
70 | { | 69 | { |
71 | m_log.Error("[INVENTORY CONNECTOR]: InventoryService missing from OpanSim.ini"); | 70 | m_log.Error("[INVENTORY CONNECTOR]: InventoryService missing from OpenSim.ini"); |
72 | throw new Exception("Inventory connector init error"); | 71 | throw new Exception("Inventory connector init error"); |
73 | } | 72 | } |
74 | 73 | ||
@@ -92,6 +91,8 @@ namespace OpenSim.Services.Connectors | |||
92 | 91 | ||
93 | if (ret == null) | 92 | if (ret == null) |
94 | return false; | 93 | return false; |
94 | if (ret.Count == 0) | ||
95 | return false; | ||
95 | 96 | ||
96 | return bool.Parse(ret["RESULT"].ToString()); | 97 | return bool.Parse(ret["RESULT"].ToString()); |
97 | } | 98 | } |
@@ -105,11 +106,20 @@ namespace OpenSim.Services.Connectors | |||
105 | 106 | ||
106 | if (ret == null) | 107 | if (ret == null) |
107 | return null; | 108 | return null; |
109 | if (ret.Count == 0) | ||
110 | return null; | ||
108 | 111 | ||
109 | List<InventoryFolderBase> folders = new List<InventoryFolderBase>(); | 112 | List<InventoryFolderBase> folders = new List<InventoryFolderBase>(); |
110 | 113 | ||
111 | foreach (Object o in ret.Values) | 114 | try |
112 | folders.Add(BuildFolder((Dictionary<string,object>)o)); | 115 | { |
116 | foreach (Object o in ret.Values) | ||
117 | folders.Add(BuildFolder((Dictionary<string, object>)o)); | ||
118 | } | ||
119 | catch (Exception e) | ||
120 | { | ||
121 | m_log.DebugFormat("[XINVENTORY CONNECTOR STUB]: Exception unwrapping folder list: {0}", e.Message); | ||
122 | } | ||
113 | 123 | ||
114 | return folders; | 124 | return folders; |
115 | } | 125 | } |
@@ -123,11 +133,10 @@ namespace OpenSim.Services.Connectors | |||
123 | 133 | ||
124 | if (ret == null) | 134 | if (ret == null) |
125 | return null; | 135 | return null; |
126 | |||
127 | if (ret.Count == 0) | 136 | if (ret.Count == 0) |
128 | return null; | 137 | return null; |
129 | 138 | ||
130 | return BuildFolder(ret); | 139 | return BuildFolder((Dictionary<string, object>)ret["folder"]); |
131 | } | 140 | } |
132 | 141 | ||
133 | public InventoryFolderBase GetFolderForType(UUID principalID, AssetType type) | 142 | public InventoryFolderBase GetFolderForType(UUID principalID, AssetType type) |
@@ -140,49 +149,53 @@ namespace OpenSim.Services.Connectors | |||
140 | 149 | ||
141 | if (ret == null) | 150 | if (ret == null) |
142 | return null; | 151 | return null; |
143 | |||
144 | if (ret.Count == 0) | 152 | if (ret.Count == 0) |
145 | return null; | 153 | return null; |
146 | 154 | ||
147 | return BuildFolder(ret); | 155 | return BuildFolder((Dictionary<string, object>)ret["folder"]); |
148 | } | 156 | } |
149 | 157 | ||
150 | public InventoryCollection GetFolderContent(UUID principalID, UUID folderID) | 158 | public InventoryCollection GetFolderContent(UUID principalID, UUID folderID) |
151 | { | 159 | { |
152 | Dictionary<string,object> ret = MakeRequest("GETFOLDERCONTENT", | ||
153 | new Dictionary<string,object> { | ||
154 | { "PRINCIPAL", principalID.ToString() }, | ||
155 | { "FOLDER", folderID.ToString() } | ||
156 | }); | ||
157 | |||
158 | if (ret == null) | ||
159 | return null; | ||
160 | |||
161 | if (ret.Count == 0) | ||
162 | return null; | ||
163 | |||
164 | |||
165 | InventoryCollection inventory = new InventoryCollection(); | 160 | InventoryCollection inventory = new InventoryCollection(); |
166 | inventory.Folders = new List<InventoryFolderBase>(); | 161 | inventory.Folders = new List<InventoryFolderBase>(); |
167 | inventory.Items = new List<InventoryItemBase>(); | 162 | inventory.Items = new List<InventoryItemBase>(); |
168 | inventory.UserID = principalID; | 163 | inventory.UserID = principalID; |
169 | |||
170 | Dictionary<string,object> folders = | ||
171 | (Dictionary<string,object>)ret["FOLDERS"]; | ||
172 | Dictionary<string,object> items = | ||
173 | (Dictionary<string,object>)ret["ITEMS"]; | ||
174 | 164 | ||
175 | foreach (Object o in folders.Values) | 165 | try |
176 | inventory.Folders.Add(BuildFolder((Dictionary<string,object>)o)); | 166 | { |
177 | foreach (Object o in items.Values) | 167 | Dictionary<string,object> ret = MakeRequest("GETFOLDERCONTENT", |
178 | inventory.Items.Add(BuildItem((Dictionary<string,object>)o)); | 168 | new Dictionary<string,object> { |
169 | { "PRINCIPAL", principalID.ToString() }, | ||
170 | { "FOLDER", folderID.ToString() } | ||
171 | }); | ||
172 | |||
173 | if (ret == null) | ||
174 | return null; | ||
175 | if (ret.Count == 0) | ||
176 | return null; | ||
177 | |||
178 | Dictionary<string,object> folders = | ||
179 | (Dictionary<string,object>)ret["FOLDERS"]; | ||
180 | Dictionary<string,object> items = | ||
181 | (Dictionary<string,object>)ret["ITEMS"]; | ||
182 | |||
183 | foreach (Object o in folders.Values) // getting the values directly, we don't care about the keys folder_i | ||
184 | inventory.Folders.Add(BuildFolder((Dictionary<string, object>)o)); | ||
185 | foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i | ||
186 | inventory.Items.Add(BuildItem((Dictionary<string, object>)o)); | ||
187 | } | ||
188 | catch (Exception e) | ||
189 | { | ||
190 | m_log.DebugFormat("[XINVENTORY CONNECTOR STUB]: Exception in GetFolderContent: {0}", e.Message); | ||
191 | } | ||
179 | 192 | ||
180 | return inventory; | 193 | return inventory; |
181 | } | 194 | } |
182 | 195 | ||
183 | public List<InventoryItemBase> GetFolderItems(UUID principalID, UUID folderID) | 196 | public List<InventoryItemBase> GetFolderItems(UUID principalID, UUID folderID) |
184 | { | 197 | { |
185 | Dictionary<string,object> ret = MakeRequest("GETFOLDERCONTENT", | 198 | Dictionary<string,object> ret = MakeRequest("GETFOLDERITEMS", |
186 | new Dictionary<string,object> { | 199 | new Dictionary<string,object> { |
187 | { "PRINCIPAL", principalID.ToString() }, | 200 | { "PRINCIPAL", principalID.ToString() }, |
188 | { "FOLDER", folderID.ToString() } | 201 | { "FOLDER", folderID.ToString() } |
@@ -190,17 +203,15 @@ namespace OpenSim.Services.Connectors | |||
190 | 203 | ||
191 | if (ret == null) | 204 | if (ret == null) |
192 | return null; | 205 | return null; |
193 | |||
194 | if (ret.Count == 0) | 206 | if (ret.Count == 0) |
195 | return null; | 207 | return null; |
196 | 208 | ||
197 | 209 | Dictionary<string, object> items = (Dictionary<string, object>)ret["ITEMS"]; | |
198 | List<InventoryItemBase> items = new List<InventoryItemBase>(); | 210 | List<InventoryItemBase> fitems = new List<InventoryItemBase>(); |
199 | 211 | foreach (Object o in items.Values) // getting the values directly, we don't care about the keys item_i | |
200 | foreach (Object o in ret.Values) | 212 | fitems.Add(BuildItem((Dictionary<string, object>)o)); |
201 | items.Add(BuildItem((Dictionary<string,object>)o)); | ||
202 | 213 | ||
203 | return items; | 214 | return fitems; |
204 | } | 215 | } |
205 | 216 | ||
206 | public bool AddFolder(InventoryFolderBase folder) | 217 | public bool AddFolder(InventoryFolderBase folder) |
@@ -244,7 +255,8 @@ namespace OpenSim.Services.Connectors | |||
244 | Dictionary<string,object> ret = MakeRequest("MOVEFOLDER", | 255 | Dictionary<string,object> ret = MakeRequest("MOVEFOLDER", |
245 | new Dictionary<string,object> { | 256 | new Dictionary<string,object> { |
246 | { "ParentID", folder.ParentID.ToString() }, | 257 | { "ParentID", folder.ParentID.ToString() }, |
247 | { "ID", folder.ID.ToString() } | 258 | { "ID", folder.ID.ToString() }, |
259 | { "PRINCIPAL", folder.Owner.ToString() } | ||
248 | }); | 260 | }); |
249 | 261 | ||
250 | if (ret == null) | 262 | if (ret == null) |
@@ -287,6 +299,8 @@ namespace OpenSim.Services.Connectors | |||
287 | 299 | ||
288 | public bool AddItem(InventoryItemBase item) | 300 | public bool AddItem(InventoryItemBase item) |
289 | { | 301 | { |
302 | if (item.CreatorData == null) | ||
303 | item.CreatorData = String.Empty; | ||
290 | Dictionary<string,object> ret = MakeRequest("ADDITEM", | 304 | Dictionary<string,object> ret = MakeRequest("ADDITEM", |
291 | new Dictionary<string,object> { | 305 | new Dictionary<string,object> { |
292 | { "AssetID", item.AssetID.ToString() }, | 306 | { "AssetID", item.AssetID.ToString() }, |
@@ -297,6 +311,7 @@ namespace OpenSim.Services.Connectors | |||
297 | { "InvType", item.InvType.ToString() }, | 311 | { "InvType", item.InvType.ToString() }, |
298 | { "Folder", item.Folder.ToString() }, | 312 | { "Folder", item.Folder.ToString() }, |
299 | { "CreatorId", item.CreatorId.ToString() }, | 313 | { "CreatorId", item.CreatorId.ToString() }, |
314 | { "CreatorData", item.CreatorData.ToString() }, | ||
300 | { "Description", item.Description.ToString() }, | 315 | { "Description", item.Description.ToString() }, |
301 | { "NextPermissions", item.NextPermissions.ToString() }, | 316 | { "NextPermissions", item.NextPermissions.ToString() }, |
302 | { "CurrentPermissions", item.CurrentPermissions.ToString() }, | 317 | { "CurrentPermissions", item.CurrentPermissions.ToString() }, |
@@ -319,6 +334,8 @@ namespace OpenSim.Services.Connectors | |||
319 | 334 | ||
320 | public bool UpdateItem(InventoryItemBase item) | 335 | public bool UpdateItem(InventoryItemBase item) |
321 | { | 336 | { |
337 | if (item.CreatorData == null) | ||
338 | item.CreatorData = String.Empty; | ||
322 | Dictionary<string,object> ret = MakeRequest("UPDATEITEM", | 339 | Dictionary<string,object> ret = MakeRequest("UPDATEITEM", |
323 | new Dictionary<string,object> { | 340 | new Dictionary<string,object> { |
324 | { "AssetID", item.AssetID.ToString() }, | 341 | { "AssetID", item.AssetID.ToString() }, |
@@ -329,6 +346,7 @@ namespace OpenSim.Services.Connectors | |||
329 | { "InvType", item.InvType.ToString() }, | 346 | { "InvType", item.InvType.ToString() }, |
330 | { "Folder", item.Folder.ToString() }, | 347 | { "Folder", item.Folder.ToString() }, |
331 | { "CreatorId", item.CreatorId.ToString() }, | 348 | { "CreatorId", item.CreatorId.ToString() }, |
349 | { "CreatorData", item.CreatorData.ToString() }, | ||
332 | { "Description", item.Description.ToString() }, | 350 | { "Description", item.Description.ToString() }, |
333 | { "NextPermissions", item.NextPermissions.ToString() }, | 351 | { "NextPermissions", item.NextPermissions.ToString() }, |
334 | { "CurrentPermissions", item.CurrentPermissions.ToString() }, | 352 | { "CurrentPermissions", item.CurrentPermissions.ToString() }, |
@@ -362,7 +380,7 @@ namespace OpenSim.Services.Connectors | |||
362 | 380 | ||
363 | Dictionary<string,object> ret = MakeRequest("MOVEITEMS", | 381 | Dictionary<string,object> ret = MakeRequest("MOVEITEMS", |
364 | new Dictionary<string,object> { | 382 | new Dictionary<string,object> { |
365 | { "PrincipalID", principalID.ToString() }, | 383 | { "PRINCIPAL", principalID.ToString() }, |
366 | { "IDLIST", idlist }, | 384 | { "IDLIST", idlist }, |
367 | { "DESTLIST", destlist } | 385 | { "DESTLIST", destlist } |
368 | }); | 386 | }); |
@@ -394,34 +412,50 @@ namespace OpenSim.Services.Connectors | |||
394 | 412 | ||
395 | public InventoryItemBase GetItem(InventoryItemBase item) | 413 | public InventoryItemBase GetItem(InventoryItemBase item) |
396 | { | 414 | { |
397 | Dictionary<string,object> ret = MakeRequest("GETITEM", | 415 | try |
398 | new Dictionary<string,object> { | 416 | { |
417 | Dictionary<string, object> ret = MakeRequest("GETITEM", | ||
418 | new Dictionary<string, object> { | ||
399 | { "ID", item.ID.ToString() } | 419 | { "ID", item.ID.ToString() } |
400 | }); | 420 | }); |
401 | 421 | ||
402 | if (ret == null) | 422 | if (ret == null) |
403 | return null; | 423 | return null; |
424 | if (ret.Count == 0) | ||
425 | return null; | ||
404 | 426 | ||
405 | if (ret.Count == 0) | 427 | return BuildItem((Dictionary<string, object>)ret["item"]); |
406 | return null; | 428 | } |
429 | catch (Exception e) | ||
430 | { | ||
431 | m_log.DebugFormat("[XINVENTORY CONNECTOR STUB]: Exception in GetItem: {0}", e.Message); | ||
432 | } | ||
407 | 433 | ||
408 | return BuildItem(ret); | 434 | return null; |
409 | } | 435 | } |
410 | 436 | ||
411 | public InventoryFolderBase GetFolder(InventoryFolderBase folder) | 437 | public InventoryFolderBase GetFolder(InventoryFolderBase folder) |
412 | { | 438 | { |
413 | Dictionary<string,object> ret = MakeRequest("GETFOLDER", | 439 | try |
414 | new Dictionary<string,object> { | 440 | { |
441 | Dictionary<string, object> ret = MakeRequest("GETFOLDER", | ||
442 | new Dictionary<string, object> { | ||
415 | { "ID", folder.ID.ToString() } | 443 | { "ID", folder.ID.ToString() } |
416 | }); | 444 | }); |
417 | 445 | ||
418 | if (ret == null) | 446 | if (ret == null) |
419 | return null; | 447 | return null; |
448 | if (ret.Count == 0) | ||
449 | return null; | ||
420 | 450 | ||
421 | if (ret.Count == 0) | 451 | return BuildFolder((Dictionary<string, object>)ret["folder"]); |
422 | return null; | 452 | } |
453 | catch (Exception e) | ||
454 | { | ||
455 | m_log.DebugFormat("[XINVENTORY CONNECTOR STUB]: Exception in GetFolder: {0}", e.Message); | ||
456 | } | ||
423 | 457 | ||
424 | return BuildFolder(ret); | 458 | return null; |
425 | } | 459 | } |
426 | 460 | ||
427 | public List<InventoryItemBase> GetActiveGestures(UUID principalID) | 461 | public List<InventoryItemBase> GetActiveGestures(UUID principalID) |
@@ -436,8 +470,8 @@ namespace OpenSim.Services.Connectors | |||
436 | 470 | ||
437 | List<InventoryItemBase> items = new List<InventoryItemBase>(); | 471 | List<InventoryItemBase> items = new List<InventoryItemBase>(); |
438 | 472 | ||
439 | foreach (Object o in ret.Values) | 473 | foreach (Object o in ret.Values) // getting the values directly, we don't care about the keys item_i |
440 | items.Add(BuildItem((Dictionary<string,object>)o)); | 474 | items.Add(BuildItem((Dictionary<string, object>)o)); |
441 | 475 | ||
442 | return items; | 476 | return items; |
443 | } | 477 | } |
@@ -494,13 +528,20 @@ namespace OpenSim.Services.Connectors | |||
494 | { | 528 | { |
495 | InventoryFolderBase folder = new InventoryFolderBase(); | 529 | InventoryFolderBase folder = new InventoryFolderBase(); |
496 | 530 | ||
497 | folder.ParentID = new UUID(data["ParentID"].ToString()); | 531 | try |
498 | folder.Type = short.Parse(data["Type"].ToString()); | 532 | { |
499 | folder.Version = ushort.Parse(data["Version"].ToString()); | 533 | folder.ParentID = new UUID(data["ParentID"].ToString()); |
500 | folder.Name = data["Name"].ToString(); | 534 | folder.Type = short.Parse(data["Type"].ToString()); |
501 | folder.Owner = new UUID(data["Owner"].ToString()); | 535 | folder.Version = ushort.Parse(data["Version"].ToString()); |
502 | folder.ID = new UUID(data["ID"].ToString()); | 536 | folder.Name = data["Name"].ToString(); |
503 | 537 | folder.Owner = new UUID(data["Owner"].ToString()); | |
538 | folder.ID = new UUID(data["ID"].ToString()); | ||
539 | } | ||
540 | catch (Exception e) | ||
541 | { | ||
542 | m_log.DebugFormat("[XINVENTORY CONNECTOR STUB]: Exception building folder: {0}", e.Message); | ||
543 | } | ||
544 | |||
504 | return folder; | 545 | return folder; |
505 | } | 546 | } |
506 | 547 | ||
@@ -508,28 +549,40 @@ namespace OpenSim.Services.Connectors | |||
508 | { | 549 | { |
509 | InventoryItemBase item = new InventoryItemBase(); | 550 | InventoryItemBase item = new InventoryItemBase(); |
510 | 551 | ||
511 | item.AssetID = new UUID(data["AssetID"].ToString()); | 552 | try |
512 | item.AssetType = int.Parse(data["AssetType"].ToString()); | 553 | { |
513 | item.Name = data["Name"].ToString(); | 554 | item.AssetID = new UUID(data["AssetID"].ToString()); |
514 | item.Owner = new UUID(data["Owner"].ToString()); | 555 | item.AssetType = int.Parse(data["AssetType"].ToString()); |
515 | item.ID = new UUID(data["ID"].ToString()); | 556 | item.Name = data["Name"].ToString(); |
516 | item.InvType = int.Parse(data["InvType"].ToString()); | 557 | item.Owner = new UUID(data["Owner"].ToString()); |
517 | item.Folder = new UUID(data["Folder"].ToString()); | 558 | item.ID = new UUID(data["ID"].ToString()); |
518 | item.CreatorId = data["CreatorId"].ToString(); | 559 | item.InvType = int.Parse(data["InvType"].ToString()); |
519 | item.Description = data["Description"].ToString(); | 560 | item.Folder = new UUID(data["Folder"].ToString()); |
520 | item.NextPermissions = uint.Parse(data["NextPermissions"].ToString()); | 561 | item.CreatorId = data["CreatorId"].ToString(); |
521 | item.CurrentPermissions = uint.Parse(data["CurrentPermissions"].ToString()); | 562 | if (data.ContainsKey("CreatorData")) |
522 | item.BasePermissions = uint.Parse(data["BasePermissions"].ToString()); | 563 | item.CreatorData = data["CreatorData"].ToString(); |
523 | item.EveryOnePermissions = uint.Parse(data["EveryOnePermissions"].ToString()); | 564 | else |
524 | item.GroupPermissions = uint.Parse(data["GroupPermissions"].ToString()); | 565 | item.CreatorData = String.Empty; |
525 | item.GroupID = new UUID(data["GroupID"].ToString()); | 566 | item.Description = data["Description"].ToString(); |
526 | item.GroupOwned = bool.Parse(data["GroupOwned"].ToString()); | 567 | item.NextPermissions = uint.Parse(data["NextPermissions"].ToString()); |
527 | item.SalePrice = int.Parse(data["SalePrice"].ToString()); | 568 | item.CurrentPermissions = uint.Parse(data["CurrentPermissions"].ToString()); |
528 | item.SaleType = byte.Parse(data["SaleType"].ToString()); | 569 | item.BasePermissions = uint.Parse(data["BasePermissions"].ToString()); |
529 | item.Flags = uint.Parse(data["Flags"].ToString()); | 570 | item.EveryOnePermissions = uint.Parse(data["EveryOnePermissions"].ToString()); |
530 | item.CreationDate = int.Parse(data["CreationDate"].ToString()); | 571 | item.GroupPermissions = uint.Parse(data["GroupPermissions"].ToString()); |
572 | item.GroupID = new UUID(data["GroupID"].ToString()); | ||
573 | item.GroupOwned = bool.Parse(data["GroupOwned"].ToString()); | ||
574 | item.SalePrice = int.Parse(data["SalePrice"].ToString()); | ||
575 | item.SaleType = byte.Parse(data["SaleType"].ToString()); | ||
576 | item.Flags = uint.Parse(data["Flags"].ToString()); | ||
577 | item.CreationDate = int.Parse(data["CreationDate"].ToString()); | ||
578 | } | ||
579 | catch (Exception e) | ||
580 | { | ||
581 | m_log.DebugFormat("[XINVENTORY CONNECTOR STUB]: Exception building item: {0}", e.Message); | ||
582 | } | ||
531 | 583 | ||
532 | return item; | 584 | return item; |
533 | } | 585 | } |
586 | |||
534 | } | 587 | } |
535 | } | 588 | } |
diff --git a/OpenSim/Services/Connectors/Land/LandServiceConnector.cs b/OpenSim/Services/Connectors/Land/LandServiceConnector.cs index 06bc11c..833e22a 100644 --- a/OpenSim/Services/Connectors/Land/LandServiceConnector.cs +++ b/OpenSim/Services/Connectors/Land/LandServiceConnector.cs | |||
@@ -34,7 +34,6 @@ using System.Reflection; | |||
34 | using Nini.Config; | 34 | using Nini.Config; |
35 | using OpenSim.Framework; | 35 | using OpenSim.Framework; |
36 | using OpenSim.Framework.Communications; | 36 | using OpenSim.Framework.Communications; |
37 | using OpenSim.Framework.Servers.HttpServer; | ||
38 | using OpenSim.Services.Interfaces; | 37 | using OpenSim.Services.Interfaces; |
39 | using OpenMetaverse; | 38 | using OpenMetaverse; |
40 | using Nwc.XmlRpc; | 39 | using Nwc.XmlRpc; |
@@ -64,7 +63,7 @@ namespace OpenSim.Services.Connectors | |||
64 | m_GridService = gridServices; | 63 | m_GridService = gridServices; |
65 | } | 64 | } |
66 | 65 | ||
67 | public virtual LandData GetLandData(ulong regionHandle, uint x, uint y) | 66 | public virtual LandData GetLandData(UUID scopeID, ulong regionHandle, uint x, uint y, out byte regionAccess) |
68 | { | 67 | { |
69 | LandData landData = null; | 68 | LandData landData = null; |
70 | Hashtable hash = new Hashtable(); | 69 | Hashtable hash = new Hashtable(); |
@@ -74,20 +73,20 @@ namespace OpenSim.Services.Connectors | |||
74 | 73 | ||
75 | IList paramList = new ArrayList(); | 74 | IList paramList = new ArrayList(); |
76 | paramList.Add(hash); | 75 | paramList.Add(hash); |
76 | regionAccess = 42; // Default to adult. Better safe... | ||
77 | 77 | ||
78 | try | 78 | try |
79 | { | 79 | { |
80 | uint xpos = 0, ypos = 0; | 80 | uint xpos = 0, ypos = 0; |
81 | Utils.LongToUInts(regionHandle, out xpos, out ypos); | 81 | Utils.LongToUInts(regionHandle, out xpos, out ypos); |
82 | GridRegion info = m_GridService.GetRegionByPosition(UUID.Zero, (int)xpos, (int)ypos); | 82 | GridRegion info = m_GridService.GetRegionByPosition(scopeID, (int)xpos, (int)ypos); |
83 | if (info != null) // just to be sure | 83 | if (info != null) // just to be sure |
84 | { | 84 | { |
85 | XmlRpcRequest request = new XmlRpcRequest("land_data", paramList); | 85 | XmlRpcRequest request = new XmlRpcRequest("land_data", paramList); |
86 | string uri = "http://" + info.ExternalEndPoint.Address + ":" + info.HttpPort + "/"; | 86 | XmlRpcResponse response = request.Send(info.ServerURI, 10000); |
87 | XmlRpcResponse response = request.Send(uri, 10000); | ||
88 | if (response.IsFault) | 87 | if (response.IsFault) |
89 | { | 88 | { |
90 | m_log.ErrorFormat("[LAND CONNECTOR] remote call returned an error: {0}", response.FaultString); | 89 | m_log.ErrorFormat("[LAND CONNECTOR]: remote call returned an error: {0}", response.FaultString); |
91 | } | 90 | } |
92 | else | 91 | else |
93 | { | 92 | { |
@@ -107,19 +106,25 @@ namespace OpenSim.Services.Connectors | |||
107 | landData.SalePrice = Convert.ToInt32(hash["SalePrice"]); | 106 | landData.SalePrice = Convert.ToInt32(hash["SalePrice"]); |
108 | landData.SnapshotID = new UUID((string)hash["SnapshotID"]); | 107 | landData.SnapshotID = new UUID((string)hash["SnapshotID"]); |
109 | landData.UserLocation = Vector3.Parse((string)hash["UserLocation"]); | 108 | landData.UserLocation = Vector3.Parse((string)hash["UserLocation"]); |
110 | m_log.DebugFormat("[OGS1 GRID SERVICES] Got land data for parcel {0}", landData.Name); | 109 | if (hash["RegionAccess"] != null) |
110 | regionAccess = (byte)Convert.ToInt32((string)hash["RegionAccess"]); | ||
111 | m_log.DebugFormat("[LAND CONNECTOR]: Got land data for parcel {0}", landData.Name); | ||
111 | } | 112 | } |
112 | catch (Exception e) | 113 | catch (Exception e) |
113 | { | 114 | { |
114 | m_log.Error("[LAND CONNECTOR] Got exception while parsing land-data:", e); | 115 | m_log.ErrorFormat( |
116 | "[LAND CONNECTOR]: Got exception while parsing land-data: {0} {1}", | ||
117 | e.Message, e.StackTrace); | ||
115 | } | 118 | } |
116 | } | 119 | } |
117 | } | 120 | } |
118 | else m_log.WarnFormat("[LAND CONNECTOR] Couldn't find region with handle {0}", regionHandle); | 121 | else |
122 | m_log.WarnFormat("[LAND CONNECTOR]: Couldn't find region with handle {0}", regionHandle); | ||
119 | } | 123 | } |
120 | catch (Exception e) | 124 | catch (Exception e) |
121 | { | 125 | { |
122 | m_log.ErrorFormat("[LAND CONNECTOR] Couldn't contact region {0}: {1}", regionHandle, e); | 126 | m_log.ErrorFormat( |
127 | "[LAND CONNECTOR]: Couldn't contact region {0}: {1} {2}", regionHandle, e.Message, e.StackTrace); | ||
123 | } | 128 | } |
124 | 129 | ||
125 | return landData; | 130 | return landData; |
diff --git a/OpenSim/Services/Connectors/MapImage/MapImageServiceConnector.cs b/OpenSim/Services/Connectors/MapImage/MapImageServiceConnector.cs new file mode 100644 index 0000000..e46714e --- /dev/null +++ b/OpenSim/Services/Connectors/MapImage/MapImageServiceConnector.cs | |||
@@ -0,0 +1,158 @@ | |||
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 | |||
28 | using log4net; | ||
29 | using System; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Net; | ||
33 | using System.Reflection; | ||
34 | |||
35 | using Nini.Config; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Framework.Console; | ||
38 | using OpenSim.Framework.Communications; | ||
39 | using OpenSim.Server.Base; | ||
40 | using OpenSim.Services.Interfaces; | ||
41 | using OpenMetaverse; | ||
42 | using OpenMetaverse.StructuredData; | ||
43 | |||
44 | namespace OpenSim.Services.Connectors | ||
45 | { | ||
46 | public class MapImageServicesConnector : IMapImageService | ||
47 | { | ||
48 | private static readonly ILog m_log = | ||
49 | LogManager.GetLogger( | ||
50 | MethodBase.GetCurrentMethod().DeclaringType); | ||
51 | |||
52 | private string m_ServerURI = String.Empty; | ||
53 | |||
54 | public MapImageServicesConnector() | ||
55 | { | ||
56 | } | ||
57 | |||
58 | public MapImageServicesConnector(string serverURI) | ||
59 | { | ||
60 | m_ServerURI = serverURI.TrimEnd('/'); | ||
61 | } | ||
62 | |||
63 | public MapImageServicesConnector(IConfigSource source) | ||
64 | { | ||
65 | Initialise(source); | ||
66 | } | ||
67 | |||
68 | public virtual void Initialise(IConfigSource source) | ||
69 | { | ||
70 | IConfig config = source.Configs["MapImageService"]; | ||
71 | if (config == null) | ||
72 | { | ||
73 | m_log.Error("[MAP IMAGE CONNECTOR]: MapImageService missing"); | ||
74 | throw new Exception("MapImage connector init error"); | ||
75 | } | ||
76 | |||
77 | string serviceURI = config.GetString("MapImageServerURI", | ||
78 | String.Empty); | ||
79 | |||
80 | if (serviceURI == String.Empty) | ||
81 | { | ||
82 | m_log.Error("[MAP IMAGE CONNECTOR]: No Server URI named in section MapImageService"); | ||
83 | throw new Exception("MapImage connector init error"); | ||
84 | } | ||
85 | m_ServerURI = serviceURI; | ||
86 | m_ServerURI = serviceURI.TrimEnd('/'); | ||
87 | } | ||
88 | |||
89 | public bool AddMapTile(int x, int y, byte[] jpgData, out string reason) | ||
90 | { | ||
91 | reason = string.Empty; | ||
92 | int tickstart = Util.EnvironmentTickCount(); | ||
93 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
94 | sendData["X"] = x.ToString(); | ||
95 | sendData["Y"] = y.ToString(); | ||
96 | sendData["TYPE"] = "image/jpeg"; | ||
97 | sendData["DATA"] = Convert.ToBase64String(jpgData); | ||
98 | |||
99 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
100 | |||
101 | try | ||
102 | { | ||
103 | string reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
104 | m_ServerURI + "/map", | ||
105 | reqString); | ||
106 | if (reply != string.Empty) | ||
107 | { | ||
108 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
109 | |||
110 | if (replyData.ContainsKey("Result") && (replyData["Result"].ToString().ToLower() == "success")) | ||
111 | { | ||
112 | return true; | ||
113 | } | ||
114 | else if (replyData.ContainsKey("Result") && (replyData["Result"].ToString().ToLower() == "failure")) | ||
115 | { | ||
116 | m_log.DebugFormat("[MAP IMAGE CONNECTOR]: Registration failed: {0}", replyData["Message"].ToString()); | ||
117 | reason = replyData["Message"].ToString(); | ||
118 | return false; | ||
119 | } | ||
120 | else if (!replyData.ContainsKey("Result")) | ||
121 | { | ||
122 | m_log.DebugFormat("[MAP IMAGE CONNECTOR]: reply data does not contain result field"); | ||
123 | } | ||
124 | else | ||
125 | { | ||
126 | m_log.DebugFormat("[MAP IMAGE CONNECTOR]: unexpected result {0}", replyData["Result"].ToString()); | ||
127 | reason = "Unexpected result " + replyData["Result"].ToString(); | ||
128 | } | ||
129 | |||
130 | } | ||
131 | else | ||
132 | { | ||
133 | m_log.DebugFormat("[MAP IMAGE CONNECTOR]: Map post received null reply"); | ||
134 | } | ||
135 | } | ||
136 | catch (Exception e) | ||
137 | { | ||
138 | m_log.DebugFormat("[MAP IMAGE CONNECTOR]: Exception when contacting grid server: {0}", e.Message); | ||
139 | } | ||
140 | finally | ||
141 | { | ||
142 | // This just dumps a warning for any operation that takes more than 100 ms | ||
143 | int tickdiff = Util.EnvironmentTickCountSubtract(tickstart); | ||
144 | m_log.DebugFormat("[MAP IMAGE CONNECTOR]: map tile uploaded in {0}ms", tickdiff); | ||
145 | } | ||
146 | |||
147 | return false; | ||
148 | |||
149 | } | ||
150 | |||
151 | public byte[] GetMapTile(string fileName, out string format) | ||
152 | { | ||
153 | format = string.Empty; | ||
154 | new Exception("GetMapTile method not Implemented"); | ||
155 | return null; | ||
156 | } | ||
157 | } | ||
158 | } | ||
diff --git a/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs b/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs index 0a982f8..888b072 100644 --- a/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs +++ b/OpenSim/Services/Connectors/Neighbour/NeighbourServiceConnector.cs | |||
@@ -36,7 +36,6 @@ using System.Text; | |||
36 | using Nini.Config; | 36 | using Nini.Config; |
37 | using OpenSim.Framework; | 37 | using OpenSim.Framework; |
38 | using OpenSim.Framework.Communications; | 38 | using OpenSim.Framework.Communications; |
39 | using OpenSim.Framework.Servers.HttpServer; | ||
40 | using OpenSim.Services.Interfaces; | 39 | using OpenSim.Services.Interfaces; |
41 | using OpenMetaverse; | 40 | using OpenMetaverse; |
42 | using OpenMetaverse.StructuredData; | 41 | using OpenMetaverse.StructuredData; |
@@ -71,7 +70,7 @@ namespace OpenSim.Services.Connectors | |||
71 | { | 70 | { |
72 | uint x = 0, y = 0; | 71 | uint x = 0, y = 0; |
73 | Utils.LongToUInts(regionHandle, out x, out y); | 72 | Utils.LongToUInts(regionHandle, out x, out y); |
74 | GridRegion regInfo = m_GridService.GetRegionByPosition(UUID.Zero, (int)x, (int)y); | 73 | GridRegion regInfo = m_GridService.GetRegionByPosition(thisRegion.ScopeID, (int)x, (int)y); |
75 | if ((regInfo != null) && | 74 | if ((regInfo != null) && |
76 | // Don't remote-call this instance; that's a startup hickup | 75 | // Don't remote-call this instance; that's a startup hickup |
77 | !((regInfo.ExternalHostName == thisRegion.ExternalHostName) && (regInfo.HttpPort == thisRegion.HttpPort))) | 76 | !((regInfo.ExternalHostName == thisRegion.ExternalHostName) && (regInfo.HttpPort == thisRegion.HttpPort))) |
@@ -87,13 +86,27 @@ namespace OpenSim.Services.Connectors | |||
87 | 86 | ||
88 | public bool DoHelloNeighbourCall(GridRegion region, RegionInfo thisRegion) | 87 | public bool DoHelloNeighbourCall(GridRegion region, RegionInfo thisRegion) |
89 | { | 88 | { |
90 | string uri = "http://" + region.ExternalEndPoint.Address + ":" + region.HttpPort + "/region/" + thisRegion.RegionID + "/"; | 89 | string uri = region.ServerURI + "region/" + thisRegion.RegionID + "/"; |
91 | //m_log.Debug(" >>> DoHelloNeighbourCall <<< " + uri); | 90 | // m_log.Debug(" >>> DoHelloNeighbourCall <<< " + uri); |
92 | 91 | ||
93 | WebRequest HelloNeighbourRequest = WebRequest.Create(uri); | 92 | WebRequest helloNeighbourRequest; |
94 | HelloNeighbourRequest.Method = "POST"; | 93 | |
95 | HelloNeighbourRequest.ContentType = "application/json"; | 94 | try |
96 | HelloNeighbourRequest.Timeout = 10000; | 95 | { |
96 | helloNeighbourRequest = WebRequest.Create(uri); | ||
97 | } | ||
98 | catch (Exception e) | ||
99 | { | ||
100 | m_log.WarnFormat( | ||
101 | "[NEIGHBOUR SERVICE CONNCTOR]: Unable to parse uri {0} to send HelloNeighbour from {1} to {2}. Exception {3}{4}", | ||
102 | uri, thisRegion.RegionName, region.RegionName, e.Message, e.StackTrace); | ||
103 | |||
104 | return false; | ||
105 | } | ||
106 | |||
107 | helloNeighbourRequest.Method = "POST"; | ||
108 | helloNeighbourRequest.ContentType = "application/json"; | ||
109 | helloNeighbourRequest.Timeout = 10000; | ||
97 | 110 | ||
98 | // Fill it in | 111 | // Fill it in |
99 | OSDMap args = null; | 112 | OSDMap args = null; |
@@ -103,38 +116,48 @@ namespace OpenSim.Services.Connectors | |||
103 | } | 116 | } |
104 | catch (Exception e) | 117 | catch (Exception e) |
105 | { | 118 | { |
106 | m_log.Debug("[REST COMMS]: PackRegionInfoData failed with exception: " + e.Message); | 119 | m_log.WarnFormat( |
120 | "[NEIGHBOUR SERVICE CONNCTOR]: PackRegionInfoData failed for HelloNeighbour from {0} to {1}. Exception {2}{3}", | ||
121 | thisRegion.RegionName, region.RegionName, e.Message, e.StackTrace); | ||
122 | |||
107 | return false; | 123 | return false; |
108 | } | 124 | } |
125 | |||
109 | // Add the regionhandle of the destination region | 126 | // Add the regionhandle of the destination region |
110 | args["destination_handle"] = OSD.FromString(region.RegionHandle.ToString()); | 127 | args["destination_handle"] = OSD.FromString(region.RegionHandle.ToString()); |
111 | 128 | ||
112 | string strBuffer = ""; | 129 | string strBuffer = ""; |
113 | byte[] buffer = new byte[1]; | 130 | byte[] buffer = new byte[1]; |
131 | |||
114 | try | 132 | try |
115 | { | 133 | { |
116 | strBuffer = OSDParser.SerializeJsonString(args); | 134 | strBuffer = OSDParser.SerializeJsonString(args); |
117 | UTF8Encoding str = new UTF8Encoding(); | 135 | UTF8Encoding str = new UTF8Encoding(); |
118 | buffer = str.GetBytes(strBuffer); | 136 | buffer = str.GetBytes(strBuffer); |
119 | |||
120 | } | 137 | } |
121 | catch (Exception e) | 138 | catch (Exception e) |
122 | { | 139 | { |
123 | m_log.WarnFormat("[REST COMMS]: Exception thrown on serialization of HelloNeighbour: {0}", e.Message); | 140 | m_log.WarnFormat( |
141 | "[NEIGHBOUR SERVICE CONNCTOR]: Exception thrown on serialization of HelloNeighbour from {0} to {1}. Exception {2}{3}", | ||
142 | thisRegion.RegionName, region.RegionName, e.Message, e.StackTrace); | ||
143 | |||
124 | return false; | 144 | return false; |
125 | } | 145 | } |
126 | 146 | ||
127 | Stream os = null; | 147 | Stream os = null; |
128 | try | 148 | try |
129 | { // send the Post | 149 | { // send the Post |
130 | HelloNeighbourRequest.ContentLength = buffer.Length; //Count bytes to send | 150 | helloNeighbourRequest.ContentLength = buffer.Length; //Count bytes to send |
131 | os = HelloNeighbourRequest.GetRequestStream(); | 151 | os = helloNeighbourRequest.GetRequestStream(); |
132 | os.Write(buffer, 0, strBuffer.Length); //Send it | 152 | os.Write(buffer, 0, strBuffer.Length); //Send it |
133 | //m_log.InfoFormat("[REST COMMS]: Posted HelloNeighbour request to remote sim {0}", uri); | 153 | //m_log.InfoFormat("[REST COMMS]: Posted HelloNeighbour request to remote sim {0}", uri); |
134 | } | 154 | } |
135 | catch (Exception ex) | 155 | catch (Exception e) |
136 | { | 156 | { |
137 | m_log.InfoFormat("[REST COMMS]: Unable to send HelloNeighbour to {0}: {1}", region.RegionName, ex.Message); | 157 | m_log.WarnFormat( |
158 | "[NEIGHBOUR SERVICE CONNCTOR]: Unable to send HelloNeighbour from {0} to {1}. Exception {2}{3}", | ||
159 | thisRegion.RegionName, region.RegionName, e.Message, e.StackTrace); | ||
160 | |||
138 | return false; | 161 | return false; |
139 | } | 162 | } |
140 | finally | 163 | finally |
@@ -149,10 +172,12 @@ namespace OpenSim.Services.Connectors | |||
149 | StreamReader sr = null; | 172 | StreamReader sr = null; |
150 | try | 173 | try |
151 | { | 174 | { |
152 | WebResponse webResponse = HelloNeighbourRequest.GetResponse(); | 175 | WebResponse webResponse = helloNeighbourRequest.GetResponse(); |
153 | if (webResponse == null) | 176 | if (webResponse == null) |
154 | { | 177 | { |
155 | m_log.Info("[REST COMMS]: Null reply on DoHelloNeighbourCall post"); | 178 | m_log.DebugFormat( |
179 | "[REST COMMS]: Null reply on DoHelloNeighbourCall post from {0} to {1}", | ||
180 | thisRegion.RegionName, region.RegionName); | ||
156 | } | 181 | } |
157 | 182 | ||
158 | sr = new StreamReader(webResponse.GetResponseStream()); | 183 | sr = new StreamReader(webResponse.GetResponseStream()); |
@@ -161,9 +186,12 @@ namespace OpenSim.Services.Connectors | |||
161 | //m_log.InfoFormat("[REST COMMS]: DoHelloNeighbourCall reply was {0} ", reply); | 186 | //m_log.InfoFormat("[REST COMMS]: DoHelloNeighbourCall reply was {0} ", reply); |
162 | 187 | ||
163 | } | 188 | } |
164 | catch (Exception ex) | 189 | catch (Exception e) |
165 | { | 190 | { |
166 | m_log.InfoFormat("[REST COMMS]: exception on reply of DoHelloNeighbourCall {0}", ex.Message); | 191 | m_log.WarnFormat( |
192 | "[NEIGHBOUR SERVICE CONNCTOR]: Exception on reply of DoHelloNeighbourCall from {0} back to {1}. Exception {2}{3}", | ||
193 | region.RegionName, thisRegion.RegionName, e.Message, e.StackTrace); | ||
194 | |||
167 | return false; | 195 | return false; |
168 | } | 196 | } |
169 | finally | 197 | finally |
@@ -173,8 +201,6 @@ namespace OpenSim.Services.Connectors | |||
173 | } | 201 | } |
174 | 202 | ||
175 | return true; | 203 | return true; |
176 | |||
177 | } | 204 | } |
178 | |||
179 | } | 205 | } |
180 | } | 206 | } \ No newline at end of file |
diff --git a/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs b/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs new file mode 100644 index 0000000..e16dc36 --- /dev/null +++ b/OpenSim/Services/Connectors/Presence/PresenceServiceConnector.cs | |||
@@ -0,0 +1,383 @@ | |||
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 | |||
28 | using log4net; | ||
29 | using System; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Reflection; | ||
33 | using Nini.Config; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Communications; | ||
36 | using OpenSim.Services.Interfaces; | ||
37 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
38 | using OpenSim.Server.Base; | ||
39 | using OpenMetaverse; | ||
40 | |||
41 | namespace OpenSim.Services.Connectors | ||
42 | { | ||
43 | public class PresenceServicesConnector : IPresenceService | ||
44 | { | ||
45 | private static readonly ILog m_log = | ||
46 | LogManager.GetLogger( | ||
47 | MethodBase.GetCurrentMethod().DeclaringType); | ||
48 | |||
49 | private string m_ServerURI = String.Empty; | ||
50 | |||
51 | public PresenceServicesConnector() | ||
52 | { | ||
53 | } | ||
54 | |||
55 | public PresenceServicesConnector(string serverURI) | ||
56 | { | ||
57 | m_ServerURI = serverURI.TrimEnd('/'); | ||
58 | } | ||
59 | |||
60 | public PresenceServicesConnector(IConfigSource source) | ||
61 | { | ||
62 | Initialise(source); | ||
63 | } | ||
64 | |||
65 | public virtual void Initialise(IConfigSource source) | ||
66 | { | ||
67 | IConfig gridConfig = source.Configs["PresenceService"]; | ||
68 | if (gridConfig == null) | ||
69 | { | ||
70 | m_log.Error("[PRESENCE CONNECTOR]: PresenceService missing from OpenSim.ini"); | ||
71 | throw new Exception("Presence connector init error"); | ||
72 | } | ||
73 | |||
74 | string serviceURI = gridConfig.GetString("PresenceServerURI", | ||
75 | String.Empty); | ||
76 | |||
77 | if (serviceURI == String.Empty) | ||
78 | { | ||
79 | m_log.Error("[PRESENCE CONNECTOR]: No Server URI named in section PresenceService"); | ||
80 | throw new Exception("Presence connector init error"); | ||
81 | } | ||
82 | m_ServerURI = serviceURI; | ||
83 | } | ||
84 | |||
85 | |||
86 | #region IPresenceService | ||
87 | |||
88 | public bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID) | ||
89 | { | ||
90 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
91 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
92 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
93 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
94 | sendData["METHOD"] = "login"; | ||
95 | |||
96 | sendData["UserID"] = userID; | ||
97 | sendData["SessionID"] = sessionID.ToString(); | ||
98 | sendData["SecureSessionID"] = secureSessionID.ToString(); | ||
99 | |||
100 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
101 | // m_log.DebugFormat("[PRESENCE CONNECTOR]: queryString = {0}", reqString); | ||
102 | try | ||
103 | { | ||
104 | string reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
105 | m_ServerURI + "/presence", | ||
106 | reqString); | ||
107 | if (reply != string.Empty) | ||
108 | { | ||
109 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
110 | |||
111 | if (replyData.ContainsKey("result")) | ||
112 | { | ||
113 | if (replyData["result"].ToString().ToLower() == "success") | ||
114 | return true; | ||
115 | else | ||
116 | return false; | ||
117 | } | ||
118 | else | ||
119 | m_log.DebugFormat("[PRESENCE CONNECTOR]: LoginAgent reply data does not contain result field"); | ||
120 | |||
121 | } | ||
122 | else | ||
123 | m_log.DebugFormat("[PRESENCE CONNECTOR]: LoginAgent received empty reply"); | ||
124 | } | ||
125 | catch (Exception e) | ||
126 | { | ||
127 | m_log.DebugFormat("[PRESENCE CONNECTOR]: Exception when contacting presence server: {0}", e.Message); | ||
128 | } | ||
129 | |||
130 | return false; | ||
131 | |||
132 | } | ||
133 | |||
134 | public bool LogoutAgent(UUID sessionID) | ||
135 | { | ||
136 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
137 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
138 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
139 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
140 | sendData["METHOD"] = "logout"; | ||
141 | |||
142 | sendData["SessionID"] = sessionID.ToString(); | ||
143 | |||
144 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
145 | // m_log.DebugFormat("[PRESENCE CONNECTOR]: queryString = {0}", reqString); | ||
146 | try | ||
147 | { | ||
148 | string reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
149 | m_ServerURI + "/presence", | ||
150 | reqString); | ||
151 | if (reply != string.Empty) | ||
152 | { | ||
153 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
154 | |||
155 | if (replyData.ContainsKey("result")) | ||
156 | { | ||
157 | if (replyData["result"].ToString().ToLower() == "success") | ||
158 | return true; | ||
159 | else | ||
160 | return false; | ||
161 | } | ||
162 | else | ||
163 | m_log.DebugFormat("[PRESENCE CONNECTOR]: LogoutAgent reply data does not contain result field"); | ||
164 | |||
165 | } | ||
166 | else | ||
167 | m_log.DebugFormat("[PRESENCE CONNECTOR]: LogoutAgent received empty reply"); | ||
168 | } | ||
169 | catch (Exception e) | ||
170 | { | ||
171 | m_log.DebugFormat("[PRESENCE CONNECTOR]: Exception when contacting presence server: {0}", e.Message); | ||
172 | } | ||
173 | |||
174 | return false; | ||
175 | } | ||
176 | |||
177 | public bool LogoutRegionAgents(UUID regionID) | ||
178 | { | ||
179 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
180 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
181 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
182 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
183 | sendData["METHOD"] = "logoutregion"; | ||
184 | |||
185 | sendData["RegionID"] = regionID.ToString(); | ||
186 | |||
187 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
188 | // m_log.DebugFormat("[PRESENCE CONNECTOR]: queryString = {0}", reqString); | ||
189 | try | ||
190 | { | ||
191 | string reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
192 | m_ServerURI + "/presence", | ||
193 | reqString); | ||
194 | if (reply != string.Empty) | ||
195 | { | ||
196 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
197 | |||
198 | if (replyData.ContainsKey("result")) | ||
199 | { | ||
200 | if (replyData["result"].ToString().ToLower() == "success") | ||
201 | return true; | ||
202 | else | ||
203 | return false; | ||
204 | } | ||
205 | else | ||
206 | m_log.DebugFormat("[PRESENCE CONNECTOR]: LogoutRegionAgents reply data does not contain result field"); | ||
207 | |||
208 | } | ||
209 | else | ||
210 | m_log.DebugFormat("[PRESENCE CONNECTOR]: LogoutRegionAgents received empty reply"); | ||
211 | } | ||
212 | catch (Exception e) | ||
213 | { | ||
214 | m_log.DebugFormat("[PRESENCE CONNECTOR]: Exception when contacting presence server: {0}", e.Message); | ||
215 | } | ||
216 | |||
217 | return false; | ||
218 | } | ||
219 | |||
220 | public bool ReportAgent(UUID sessionID, UUID regionID) | ||
221 | { | ||
222 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
223 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
224 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
225 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
226 | sendData["METHOD"] = "report"; | ||
227 | |||
228 | sendData["SessionID"] = sessionID.ToString(); | ||
229 | sendData["RegionID"] = regionID.ToString(); | ||
230 | |||
231 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
232 | // m_log.DebugFormat("[PRESENCE CONNECTOR]: queryString = {0}", reqString); | ||
233 | try | ||
234 | { | ||
235 | string reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
236 | m_ServerURI + "/presence", | ||
237 | reqString); | ||
238 | if (reply != string.Empty) | ||
239 | { | ||
240 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
241 | |||
242 | if (replyData.ContainsKey("result")) | ||
243 | { | ||
244 | if (replyData["result"].ToString().ToLower() == "success") | ||
245 | return true; | ||
246 | else | ||
247 | return false; | ||
248 | } | ||
249 | else | ||
250 | m_log.DebugFormat("[PRESENCE CONNECTOR]: ReportAgent reply data does not contain result field"); | ||
251 | |||
252 | } | ||
253 | else | ||
254 | m_log.DebugFormat("[PRESENCE CONNECTOR]: ReportAgent received empty reply"); | ||
255 | } | ||
256 | catch (Exception e) | ||
257 | { | ||
258 | m_log.DebugFormat("[PRESENCE CONNECTOR]: Exception when contacting presence server: {0}", e.Message); | ||
259 | } | ||
260 | |||
261 | return false; | ||
262 | } | ||
263 | |||
264 | public PresenceInfo GetAgent(UUID sessionID) | ||
265 | { | ||
266 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
267 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
268 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
269 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
270 | sendData["METHOD"] = "getagent"; | ||
271 | |||
272 | sendData["SessionID"] = sessionID.ToString(); | ||
273 | |||
274 | string reply = string.Empty; | ||
275 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
276 | // m_log.DebugFormat("[PRESENCE CONNECTOR]: queryString = {0}", reqString); | ||
277 | try | ||
278 | { | ||
279 | reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
280 | m_ServerURI + "/presence", | ||
281 | reqString); | ||
282 | if (reply == null || (reply != null && reply == string.Empty)) | ||
283 | { | ||
284 | m_log.DebugFormat("[PRESENCE CONNECTOR]: GetAgent received null or empty reply"); | ||
285 | return null; | ||
286 | } | ||
287 | } | ||
288 | catch (Exception e) | ||
289 | { | ||
290 | m_log.DebugFormat("[PRESENCE CONNECTOR]: Exception when contacting presence server: {0}", e.Message); | ||
291 | } | ||
292 | |||
293 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
294 | PresenceInfo pinfo = null; | ||
295 | |||
296 | if ((replyData != null) && replyData.ContainsKey("result") && (replyData["result"] != null)) | ||
297 | { | ||
298 | if (replyData["result"] is Dictionary<string, object>) | ||
299 | { | ||
300 | pinfo = new PresenceInfo((Dictionary<string, object>)replyData["result"]); | ||
301 | } | ||
302 | else | ||
303 | { | ||
304 | if (replyData["result"].ToString() == "null") | ||
305 | return null; | ||
306 | |||
307 | m_log.DebugFormat("[PRESENCE CONNECTOR]: Invalid reply (result not dictionary) received from presence server when querying for sessionID {0}", sessionID.ToString()); | ||
308 | } | ||
309 | } | ||
310 | else | ||
311 | { | ||
312 | m_log.DebugFormat("[PRESENCE CONNECTOR]: Invalid reply received from presence server when querying for sessionID {0}", sessionID.ToString()); | ||
313 | } | ||
314 | |||
315 | return pinfo; | ||
316 | } | ||
317 | |||
318 | public PresenceInfo[] GetAgents(string[] userIDs) | ||
319 | { | ||
320 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
321 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
322 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
323 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
324 | sendData["METHOD"] = "getagents"; | ||
325 | |||
326 | sendData["uuids"] = new List<string>(userIDs); | ||
327 | |||
328 | string reply = string.Empty; | ||
329 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
330 | //m_log.DebugFormat("[PRESENCE CONNECTOR]: queryString = {0}", reqString); | ||
331 | try | ||
332 | { | ||
333 | reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
334 | m_ServerURI + "/presence", | ||
335 | reqString); | ||
336 | if (reply == null || (reply != null && reply == string.Empty)) | ||
337 | { | ||
338 | m_log.DebugFormat("[PRESENCE CONNECTOR]: GetAgents received null or empty reply"); | ||
339 | return null; | ||
340 | } | ||
341 | } | ||
342 | catch (Exception e) | ||
343 | { | ||
344 | m_log.DebugFormat("[PRESENCE CONNECTOR]: Exception when contacting presence server: {0}", e.Message); | ||
345 | } | ||
346 | |||
347 | List<PresenceInfo> rinfos = new List<PresenceInfo>(); | ||
348 | |||
349 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
350 | |||
351 | if (replyData != null) | ||
352 | { | ||
353 | if (replyData.ContainsKey("result") && | ||
354 | (replyData["result"].ToString() == "null" || replyData["result"].ToString() == "Failure")) | ||
355 | { | ||
356 | return new PresenceInfo[0]; | ||
357 | } | ||
358 | |||
359 | Dictionary<string, object>.ValueCollection pinfosList = replyData.Values; | ||
360 | //m_log.DebugFormat("[PRESENCE CONNECTOR]: GetAgents returned {0} elements", pinfosList.Count); | ||
361 | foreach (object presence in pinfosList) | ||
362 | { | ||
363 | if (presence is Dictionary<string, object>) | ||
364 | { | ||
365 | PresenceInfo pinfo = new PresenceInfo((Dictionary<string, object>)presence); | ||
366 | rinfos.Add(pinfo); | ||
367 | } | ||
368 | else | ||
369 | m_log.DebugFormat("[PRESENCE CONNECTOR]: GetAgents received invalid response type {0}", | ||
370 | presence.GetType()); | ||
371 | } | ||
372 | } | ||
373 | else | ||
374 | m_log.DebugFormat("[PRESENCE CONNECTOR]: GetAgents received null response"); | ||
375 | |||
376 | return rinfos.ToArray(); | ||
377 | } | ||
378 | |||
379 | |||
380 | #endregion | ||
381 | |||
382 | } | ||
383 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianActivityDetector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianActivityDetector.cs new file mode 100644 index 0000000..2267325 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianActivityDetector.cs | |||
@@ -0,0 +1,114 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Reflection; | ||
30 | using OpenSim.Framework; | ||
31 | using OpenSim.Region.Framework.Scenes; | ||
32 | using OpenSim.Services.Interfaces; | ||
33 | using OpenMetaverse; | ||
34 | using log4net; | ||
35 | |||
36 | namespace OpenSim.Services.Connectors.SimianGrid | ||
37 | { | ||
38 | public class SimianActivityDetector | ||
39 | { | ||
40 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
41 | |||
42 | private IGridUserService m_GridUserService; | ||
43 | |||
44 | public SimianActivityDetector(IGridUserService guService) | ||
45 | { | ||
46 | m_GridUserService = guService; | ||
47 | m_log.DebugFormat("[SIMIAN ACTIVITY DETECTOR]: Started"); | ||
48 | } | ||
49 | |||
50 | public void AddRegion(Scene scene) | ||
51 | { | ||
52 | // For now the only events we listen to are these | ||
53 | // But we could trigger the position update more often | ||
54 | scene.EventManager.OnMakeRootAgent += OnMakeRootAgent; | ||
55 | scene.EventManager.OnNewClient += OnNewClient; | ||
56 | scene.EventManager.OnAvatarEnteringNewParcel += OnEnteringNewParcel; | ||
57 | } | ||
58 | |||
59 | public void RemoveRegion(Scene scene) | ||
60 | { | ||
61 | scene.EventManager.OnMakeRootAgent -= OnMakeRootAgent; | ||
62 | scene.EventManager.OnNewClient -= OnNewClient; | ||
63 | scene.EventManager.OnAvatarEnteringNewParcel -= OnEnteringNewParcel; | ||
64 | } | ||
65 | |||
66 | public void OnMakeRootAgent(ScenePresence sp) | ||
67 | { | ||
68 | m_log.DebugFormat("[SIMIAN ACTIVITY DETECTOR]: Detected root presence {0} in {1}", sp.UUID, sp.Scene.RegionInfo.RegionName); | ||
69 | Util.FireAndForget(delegate(object o) | ||
70 | { | ||
71 | m_GridUserService.SetLastPosition(sp.UUID.ToString(), sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); | ||
72 | }); | ||
73 | } | ||
74 | |||
75 | public void OnNewClient(IClientAPI client) | ||
76 | { | ||
77 | client.OnConnectionClosed += OnConnectionClose; | ||
78 | } | ||
79 | |||
80 | public void OnConnectionClose(IClientAPI client) | ||
81 | { | ||
82 | if (client.IsLoggingOut) | ||
83 | { | ||
84 | object sp = null; | ||
85 | Vector3 position = new Vector3(128, 128, 0); | ||
86 | Vector3 lookat = new Vector3(0, 1, 0); | ||
87 | |||
88 | if (client.Scene.TryGetScenePresence(client.AgentId, out sp)) | ||
89 | { | ||
90 | if (sp is ScenePresence) | ||
91 | { | ||
92 | if (((ScenePresence)sp).IsChildAgent) | ||
93 | return; | ||
94 | |||
95 | position = ((ScenePresence)sp).AbsolutePosition; | ||
96 | lookat = ((ScenePresence)sp).Lookat; | ||
97 | } | ||
98 | } | ||
99 | |||
100 | // m_log.DebugFormat("[SIMIAN ACTIVITY DETECTOR]: Detected client logout {0} in {1}", client.AgentId, client.Scene.RegionInfo.RegionName); | ||
101 | m_GridUserService.LoggedOut(client.AgentId.ToString(), client.SessionId, client.Scene.RegionInfo.RegionID, position, lookat); | ||
102 | } | ||
103 | } | ||
104 | |||
105 | void OnEnteringNewParcel(ScenePresence sp, int localLandID, UUID regionID) | ||
106 | { | ||
107 | // Asynchronously update the position stored in the session table for this agent | ||
108 | Util.FireAndForget(delegate(object o) | ||
109 | { | ||
110 | m_GridUserService.SetLastPosition(sp.UUID.ToString(), sp.ControllingClient.SessionId, sp.Scene.RegionInfo.RegionID, sp.AbsolutePosition, sp.Lookat); | ||
111 | }); | ||
112 | } | ||
113 | } | ||
114 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs new file mode 100644 index 0000000..9573e21 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAssetServiceConnector.cs | |||
@@ -0,0 +1,497 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | using log4net; | ||
34 | using Mono.Addins; | ||
35 | using Nini.Config; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | using OpenSim.Region.Framework.Scenes; | ||
39 | using OpenSim.Services.Interfaces; | ||
40 | using OpenMetaverse; | ||
41 | using OpenMetaverse.StructuredData; | ||
42 | |||
43 | namespace OpenSim.Services.Connectors.SimianGrid | ||
44 | { | ||
45 | /// <summary> | ||
46 | /// Connects to the SimianGrid asset service | ||
47 | /// </summary> | ||
48 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
49 | public class SimianAssetServiceConnector : IAssetService, ISharedRegionModule | ||
50 | { | ||
51 | private static readonly ILog m_log = | ||
52 | LogManager.GetLogger( | ||
53 | MethodBase.GetCurrentMethod().DeclaringType); | ||
54 | private static string ZeroID = UUID.Zero.ToString(); | ||
55 | |||
56 | private string m_serverUrl = String.Empty; | ||
57 | private IImprovedAssetCache m_cache; | ||
58 | private bool m_Enabled = false; | ||
59 | |||
60 | #region ISharedRegionModule | ||
61 | |||
62 | public Type ReplaceableInterface { get { return null; } } | ||
63 | public void RegionLoaded(Scene scene) | ||
64 | { | ||
65 | if (m_cache == null) | ||
66 | { | ||
67 | IImprovedAssetCache cache = scene.RequestModuleInterface<IImprovedAssetCache>(); | ||
68 | if (cache is ISharedRegionModule) | ||
69 | m_cache = cache; | ||
70 | } | ||
71 | } | ||
72 | public void PostInitialise() { } | ||
73 | public void Close() { } | ||
74 | |||
75 | public SimianAssetServiceConnector() { } | ||
76 | public string Name { get { return "SimianAssetServiceConnector"; } } | ||
77 | public void AddRegion(Scene scene) { if (m_Enabled) { scene.RegisterModuleInterface<IAssetService>(this); } } | ||
78 | public void RemoveRegion(Scene scene) { if (m_Enabled) { scene.UnregisterModuleInterface<IAssetService>(this); } } | ||
79 | |||
80 | #endregion ISharedRegionModule | ||
81 | |||
82 | public SimianAssetServiceConnector(IConfigSource source) | ||
83 | { | ||
84 | CommonInit(source); | ||
85 | } | ||
86 | |||
87 | public SimianAssetServiceConnector(string url) | ||
88 | { | ||
89 | m_serverUrl = url; | ||
90 | } | ||
91 | |||
92 | public void Initialise(IConfigSource source) | ||
93 | { | ||
94 | IConfig moduleConfig = source.Configs["Modules"]; | ||
95 | if (moduleConfig != null) | ||
96 | { | ||
97 | string name = moduleConfig.GetString("AssetServices", ""); | ||
98 | if (name == Name) | ||
99 | CommonInit(source); | ||
100 | } | ||
101 | } | ||
102 | |||
103 | private void CommonInit(IConfigSource source) | ||
104 | { | ||
105 | IConfig gridConfig = source.Configs["AssetService"]; | ||
106 | if (gridConfig != null) | ||
107 | { | ||
108 | string serviceUrl = gridConfig.GetString("AssetServerURI"); | ||
109 | if (!String.IsNullOrEmpty(serviceUrl)) | ||
110 | { | ||
111 | if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("=")) | ||
112 | serviceUrl = serviceUrl + '/'; | ||
113 | m_serverUrl = serviceUrl; | ||
114 | } | ||
115 | } | ||
116 | |||
117 | if (String.IsNullOrEmpty(m_serverUrl)) | ||
118 | m_log.Info("[SIMIAN ASSET CONNECTOR]: No AssetServerURI specified, disabling connector"); | ||
119 | else | ||
120 | m_Enabled = true; | ||
121 | } | ||
122 | |||
123 | #region IAssetService | ||
124 | |||
125 | public AssetBase Get(string id) | ||
126 | { | ||
127 | if (String.IsNullOrEmpty(m_serverUrl)) | ||
128 | { | ||
129 | m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured"); | ||
130 | throw new InvalidOperationException(); | ||
131 | } | ||
132 | |||
133 | // Cache fetch | ||
134 | if (m_cache != null) | ||
135 | { | ||
136 | AssetBase asset = m_cache.Get(id); | ||
137 | if (asset != null) | ||
138 | return asset; | ||
139 | } | ||
140 | |||
141 | return GetRemote(id); | ||
142 | } | ||
143 | |||
144 | public AssetBase GetCached(string id) | ||
145 | { | ||
146 | if (m_cache != null) | ||
147 | return m_cache.Get(id); | ||
148 | |||
149 | return null; | ||
150 | } | ||
151 | |||
152 | /// <summary> | ||
153 | /// Get an asset's metadata | ||
154 | /// </summary> | ||
155 | /// <param name="id"></param> | ||
156 | /// <returns></returns> | ||
157 | public AssetMetadata GetMetadata(string id) | ||
158 | { | ||
159 | if (String.IsNullOrEmpty(m_serverUrl)) | ||
160 | { | ||
161 | m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured"); | ||
162 | throw new InvalidOperationException(); | ||
163 | } | ||
164 | |||
165 | AssetMetadata metadata = null; | ||
166 | |||
167 | // Cache fetch | ||
168 | if (m_cache != null) | ||
169 | { | ||
170 | AssetBase asset = m_cache.Get(id); | ||
171 | if (asset != null) | ||
172 | return asset.Metadata; | ||
173 | } | ||
174 | |||
175 | Uri url; | ||
176 | |||
177 | // Determine if id is an absolute URL or a grid-relative UUID | ||
178 | if (!Uri.TryCreate(id, UriKind.Absolute, out url)) | ||
179 | url = new Uri(m_serverUrl + id); | ||
180 | |||
181 | try | ||
182 | { | ||
183 | HttpWebRequest request = UntrustedHttpWebRequest.Create(url); | ||
184 | request.Method = "HEAD"; | ||
185 | |||
186 | using (WebResponse response = request.GetResponse()) | ||
187 | { | ||
188 | using (Stream responseStream = response.GetResponseStream()) | ||
189 | { | ||
190 | // Create the metadata object | ||
191 | metadata = new AssetMetadata(); | ||
192 | metadata.ContentType = response.ContentType; | ||
193 | metadata.ID = id; | ||
194 | |||
195 | UUID uuid; | ||
196 | if (UUID.TryParse(id, out uuid)) | ||
197 | metadata.FullID = uuid; | ||
198 | |||
199 | string lastModifiedStr = response.Headers.Get("Last-Modified"); | ||
200 | if (!String.IsNullOrEmpty(lastModifiedStr)) | ||
201 | { | ||
202 | DateTime lastModified; | ||
203 | if (DateTime.TryParse(lastModifiedStr, out lastModified)) | ||
204 | metadata.CreationDate = lastModified; | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | } | ||
209 | catch (Exception ex) | ||
210 | { | ||
211 | m_log.Warn("[SIMIAN ASSET CONNECTOR]: Asset HEAD from " + url + " failed: " + ex.Message); | ||
212 | } | ||
213 | |||
214 | return metadata; | ||
215 | } | ||
216 | |||
217 | public byte[] GetData(string id) | ||
218 | { | ||
219 | AssetBase asset = Get(id); | ||
220 | |||
221 | if (asset != null) | ||
222 | return asset.Data; | ||
223 | |||
224 | return null; | ||
225 | } | ||
226 | |||
227 | /// <summary> | ||
228 | /// Get an asset asynchronously | ||
229 | /// </summary> | ||
230 | /// <param name="id">The asset id</param> | ||
231 | /// <param name="sender">Represents the requester. Passed back via the handler</param> | ||
232 | /// <param name="handler">The handler to call back once the asset has been retrieved</param> | ||
233 | /// <returns>True if the id was parseable, false otherwise</returns> | ||
234 | public bool Get(string id, Object sender, AssetRetrieved handler) | ||
235 | { | ||
236 | if (String.IsNullOrEmpty(m_serverUrl)) | ||
237 | { | ||
238 | m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured"); | ||
239 | throw new InvalidOperationException(); | ||
240 | } | ||
241 | |||
242 | // Cache fetch | ||
243 | if (m_cache != null) | ||
244 | { | ||
245 | AssetBase asset = m_cache.Get(id); | ||
246 | if (asset != null) | ||
247 | { | ||
248 | handler(id, sender, asset); | ||
249 | return true; | ||
250 | } | ||
251 | } | ||
252 | |||
253 | Util.FireAndForget( | ||
254 | delegate(object o) | ||
255 | { | ||
256 | AssetBase asset = GetRemote(id); | ||
257 | handler(id, sender, asset); | ||
258 | } | ||
259 | ); | ||
260 | |||
261 | return true; | ||
262 | } | ||
263 | |||
264 | /// <summary> | ||
265 | /// Creates a new asset | ||
266 | /// </summary> | ||
267 | /// Returns a random ID if none is passed into it | ||
268 | /// <param name="asset"></param> | ||
269 | /// <returns></returns> | ||
270 | public string Store(AssetBase asset) | ||
271 | { | ||
272 | if (String.IsNullOrEmpty(m_serverUrl)) | ||
273 | { | ||
274 | m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured"); | ||
275 | throw new InvalidOperationException(); | ||
276 | } | ||
277 | |||
278 | bool storedInCache = false; | ||
279 | string errorMessage = null; | ||
280 | |||
281 | // AssetID handling | ||
282 | if (String.IsNullOrEmpty(asset.ID) || asset.ID == ZeroID) | ||
283 | { | ||
284 | asset.FullID = UUID.Random(); | ||
285 | asset.ID = asset.FullID.ToString(); | ||
286 | } | ||
287 | |||
288 | // Cache handling | ||
289 | if (m_cache != null) | ||
290 | { | ||
291 | m_cache.Cache(asset); | ||
292 | storedInCache = true; | ||
293 | } | ||
294 | |||
295 | // Local asset handling | ||
296 | if (asset.Local) | ||
297 | { | ||
298 | if (!storedInCache) | ||
299 | { | ||
300 | m_log.Error("Cannot store local " + asset.Metadata.ContentType + " asset without an asset cache"); | ||
301 | asset.ID = null; | ||
302 | asset.FullID = UUID.Zero; | ||
303 | } | ||
304 | |||
305 | return asset.ID; | ||
306 | } | ||
307 | |||
308 | // Distinguish public and private assets | ||
309 | bool isPublic = true; | ||
310 | switch ((AssetType)asset.Type) | ||
311 | { | ||
312 | case AssetType.CallingCard: | ||
313 | case AssetType.Gesture: | ||
314 | case AssetType.LSLBytecode: | ||
315 | case AssetType.LSLText: | ||
316 | isPublic = false; | ||
317 | break; | ||
318 | } | ||
319 | |||
320 | // Make sure ContentType is set | ||
321 | if (String.IsNullOrEmpty(asset.Metadata.ContentType)) | ||
322 | asset.Metadata.ContentType = SLUtil.SLAssetTypeToContentType(asset.Type); | ||
323 | |||
324 | // Build the remote storage request | ||
325 | List<MultipartForm.Element> postParameters = new List<MultipartForm.Element>() | ||
326 | { | ||
327 | new MultipartForm.Parameter("AssetID", asset.FullID.ToString()), | ||
328 | new MultipartForm.Parameter("CreatorID", asset.Metadata.CreatorID), | ||
329 | new MultipartForm.Parameter("Temporary", asset.Temporary ? "1" : "0"), | ||
330 | new MultipartForm.Parameter("Public", isPublic ? "1" : "0"), | ||
331 | new MultipartForm.File("Asset", asset.Name, asset.Metadata.ContentType, asset.Data) | ||
332 | }; | ||
333 | |||
334 | // Make the remote storage request | ||
335 | try | ||
336 | { | ||
337 | // Simian does not require the asset ID to be in the URL because it's in the post data. | ||
338 | // By appending it to the URL also, we allow caching proxies (squid) to invalidate asset URLs | ||
339 | HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_serverUrl + asset.FullID.ToString()); | ||
340 | |||
341 | HttpWebResponse response = MultipartForm.Post(request, postParameters); | ||
342 | using (Stream responseStream = response.GetResponseStream()) | ||
343 | { | ||
344 | string responseStr = null; | ||
345 | |||
346 | try | ||
347 | { | ||
348 | responseStr = responseStream.GetStreamString(); | ||
349 | OSD responseOSD = OSDParser.Deserialize(responseStr); | ||
350 | if (responseOSD.Type == OSDType.Map) | ||
351 | { | ||
352 | OSDMap responseMap = (OSDMap)responseOSD; | ||
353 | if (responseMap["Success"].AsBoolean()) | ||
354 | return asset.ID; | ||
355 | else | ||
356 | errorMessage = "Upload failed: " + responseMap["Message"].AsString(); | ||
357 | } | ||
358 | else | ||
359 | { | ||
360 | errorMessage = "Response format was invalid:\n" + responseStr; | ||
361 | } | ||
362 | } | ||
363 | catch (Exception ex) | ||
364 | { | ||
365 | if (!String.IsNullOrEmpty(responseStr)) | ||
366 | errorMessage = "Failed to parse the response:\n" + responseStr; | ||
367 | else | ||
368 | errorMessage = "Failed to retrieve the response: " + ex.Message; | ||
369 | } | ||
370 | } | ||
371 | } | ||
372 | catch (WebException ex) | ||
373 | { | ||
374 | errorMessage = ex.Message; | ||
375 | } | ||
376 | |||
377 | m_log.WarnFormat("[SIMIAN ASSET CONNECTOR]: Failed to store asset \"{0}\" ({1}, {2}): {3}", | ||
378 | asset.Name, asset.ID, asset.Metadata.ContentType, errorMessage); | ||
379 | return null; | ||
380 | } | ||
381 | |||
382 | /// <summary> | ||
383 | /// Update an asset's content | ||
384 | /// </summary> | ||
385 | /// Attachments and bare scripts need this!! | ||
386 | /// <param name="id"> </param> | ||
387 | /// <param name="data"></param> | ||
388 | /// <returns></returns> | ||
389 | public bool UpdateContent(string id, byte[] data) | ||
390 | { | ||
391 | AssetBase asset = Get(id); | ||
392 | |||
393 | if (asset == null) | ||
394 | { | ||
395 | m_log.Warn("[SIMIAN ASSET CONNECTOR]: Failed to fetch asset " + id + " for updating"); | ||
396 | return false; | ||
397 | } | ||
398 | |||
399 | asset.Data = data; | ||
400 | |||
401 | string result = Store(asset); | ||
402 | return !String.IsNullOrEmpty(result); | ||
403 | } | ||
404 | |||
405 | /// <summary> | ||
406 | /// Delete an asset | ||
407 | /// </summary> | ||
408 | /// <param name="id"></param> | ||
409 | /// <returns></returns> | ||
410 | public bool Delete(string id) | ||
411 | { | ||
412 | if (String.IsNullOrEmpty(m_serverUrl)) | ||
413 | { | ||
414 | m_log.Error("[SIMIAN ASSET CONNECTOR]: No AssetServerURI configured"); | ||
415 | throw new InvalidOperationException(); | ||
416 | } | ||
417 | |||
418 | //string errorMessage = String.Empty; | ||
419 | string url = m_serverUrl + id; | ||
420 | |||
421 | if (m_cache != null) | ||
422 | m_cache.Expire(id); | ||
423 | |||
424 | try | ||
425 | { | ||
426 | HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url); | ||
427 | request.Method = "DELETE"; | ||
428 | |||
429 | using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) | ||
430 | { | ||
431 | if (response.StatusCode != HttpStatusCode.NoContent) | ||
432 | { | ||
433 | m_log.Warn("[SIMIAN ASSET CONNECTOR]: Unexpected response when deleting asset " + url + ": " + | ||
434 | response.StatusCode + " (" + response.StatusDescription + ")"); | ||
435 | } | ||
436 | } | ||
437 | |||
438 | return true; | ||
439 | } | ||
440 | catch (Exception ex) | ||
441 | { | ||
442 | m_log.Warn("[SIMIAN ASSET CONNECTOR]: Failed to delete asset " + id + " from the asset service: " + ex.Message); | ||
443 | return false; | ||
444 | } | ||
445 | } | ||
446 | |||
447 | #endregion IAssetService | ||
448 | |||
449 | private AssetBase GetRemote(string id) | ||
450 | { | ||
451 | AssetBase asset = null; | ||
452 | Uri url; | ||
453 | |||
454 | // Determine if id is an absolute URL or a grid-relative UUID | ||
455 | if (!Uri.TryCreate(id, UriKind.Absolute, out url)) | ||
456 | url = new Uri(m_serverUrl + id); | ||
457 | |||
458 | try | ||
459 | { | ||
460 | HttpWebRequest request = UntrustedHttpWebRequest.Create(url); | ||
461 | |||
462 | using (WebResponse response = request.GetResponse()) | ||
463 | { | ||
464 | using (Stream responseStream = response.GetResponseStream()) | ||
465 | { | ||
466 | string creatorID = response.Headers.GetOne("X-Asset-Creator-Id") ?? String.Empty; | ||
467 | |||
468 | // Create the asset object | ||
469 | asset = new AssetBase(id, String.Empty, SLUtil.ContentTypeToSLAssetType(response.ContentType), creatorID); | ||
470 | |||
471 | UUID assetID; | ||
472 | if (UUID.TryParse(id, out assetID)) | ||
473 | asset.FullID = assetID; | ||
474 | |||
475 | // Grab the asset data from the response stream | ||
476 | using (MemoryStream stream = new MemoryStream()) | ||
477 | { | ||
478 | responseStream.CopyTo(stream, 4096); | ||
479 | asset.Data = stream.ToArray(); | ||
480 | } | ||
481 | } | ||
482 | } | ||
483 | |||
484 | // Cache store | ||
485 | if (m_cache != null && asset != null) | ||
486 | m_cache.Cache(asset); | ||
487 | |||
488 | return asset; | ||
489 | } | ||
490 | catch (Exception ex) | ||
491 | { | ||
492 | m_log.Warn("[SIMIAN ASSET CONNECTOR]: Asset GET from " + url + " failed: " + ex.Message); | ||
493 | return null; | ||
494 | } | ||
495 | } | ||
496 | } | ||
497 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs new file mode 100644 index 0000000..69f6ed2 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAuthenticationServiceConnector.cs | |||
@@ -0,0 +1,307 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Specialized; | ||
30 | using System.Reflection; | ||
31 | using log4net; | ||
32 | using Mono.Addins; | ||
33 | using Nini.Config; | ||
34 | using OpenMetaverse; | ||
35 | using OpenMetaverse.StructuredData; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Region.Framework.Interfaces; | ||
38 | using OpenSim.Region.Framework.Scenes; | ||
39 | using OpenSim.Services.Interfaces; | ||
40 | |||
41 | namespace OpenSim.Services.Connectors.SimianGrid | ||
42 | { | ||
43 | /// <summary> | ||
44 | /// Connects authentication/authorization to the SimianGrid backend | ||
45 | /// </summary> | ||
46 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
47 | public class SimianAuthenticationServiceConnector : IAuthenticationService, ISharedRegionModule | ||
48 | { | ||
49 | private static readonly ILog m_log = | ||
50 | LogManager.GetLogger( | ||
51 | MethodBase.GetCurrentMethod().DeclaringType); | ||
52 | |||
53 | private string m_serverUrl = String.Empty; | ||
54 | private bool m_Enabled = false; | ||
55 | |||
56 | #region ISharedRegionModule | ||
57 | |||
58 | public Type ReplaceableInterface { get { return null; } } | ||
59 | public void RegionLoaded(Scene scene) { } | ||
60 | public void PostInitialise() { } | ||
61 | public void Close() { } | ||
62 | |||
63 | public SimianAuthenticationServiceConnector() { } | ||
64 | public string Name { get { return "SimianAuthenticationServiceConnector"; } } | ||
65 | public void AddRegion(Scene scene) { if (m_Enabled) { scene.RegisterModuleInterface<IAuthenticationService>(this); } } | ||
66 | public void RemoveRegion(Scene scene) { if (m_Enabled) { scene.UnregisterModuleInterface<IAuthenticationService>(this); } } | ||
67 | |||
68 | #endregion ISharedRegionModule | ||
69 | |||
70 | public SimianAuthenticationServiceConnector(IConfigSource source) | ||
71 | { | ||
72 | CommonInit(source); | ||
73 | } | ||
74 | |||
75 | public void Initialise(IConfigSource source) | ||
76 | { | ||
77 | IConfig moduleConfig = source.Configs["Modules"]; | ||
78 | if (moduleConfig != null) | ||
79 | { | ||
80 | string name = moduleConfig.GetString("AuthenticationServices", ""); | ||
81 | if (name == Name) | ||
82 | CommonInit(source); | ||
83 | } | ||
84 | } | ||
85 | |||
86 | private void CommonInit(IConfigSource source) | ||
87 | { | ||
88 | IConfig gridConfig = source.Configs["AuthenticationService"]; | ||
89 | if (gridConfig != null) | ||
90 | { | ||
91 | string serviceUrl = gridConfig.GetString("AuthenticationServerURI"); | ||
92 | if (!String.IsNullOrEmpty(serviceUrl)) | ||
93 | { | ||
94 | if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("=")) | ||
95 | serviceUrl = serviceUrl + '/'; | ||
96 | m_serverUrl = serviceUrl; | ||
97 | m_Enabled = true; | ||
98 | } | ||
99 | } | ||
100 | |||
101 | if (String.IsNullOrEmpty(m_serverUrl)) | ||
102 | m_log.Info("[SIMIAN AUTH CONNECTOR]: No AuthenticationServerURI specified, disabling connector"); | ||
103 | } | ||
104 | |||
105 | public string Authenticate(UUID principalID, string password, int lifetime) | ||
106 | { | ||
107 | NameValueCollection requestArgs = new NameValueCollection | ||
108 | { | ||
109 | { "RequestMethod", "GetIdentities" }, | ||
110 | { "UserID", principalID.ToString() } | ||
111 | }; | ||
112 | |||
113 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
114 | if (response["Success"].AsBoolean() && response["Identities"] is OSDArray) | ||
115 | { | ||
116 | bool md5hashFound = false; | ||
117 | |||
118 | OSDArray identities = (OSDArray)response["Identities"]; | ||
119 | for (int i = 0; i < identities.Count; i++) | ||
120 | { | ||
121 | OSDMap identity = identities[i] as OSDMap; | ||
122 | if (identity != null) | ||
123 | { | ||
124 | if (identity["Type"].AsString() == "md5hash") | ||
125 | { | ||
126 | string authorizeResult; | ||
127 | if (CheckPassword(principalID, password, identity["Credential"].AsString(), out authorizeResult)) | ||
128 | return authorizeResult; | ||
129 | |||
130 | md5hashFound = true; | ||
131 | break; | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | |||
136 | if (!md5hashFound) | ||
137 | m_log.Warn("[SIMIAN AUTH CONNECTOR]: Authentication failed for " + principalID + ", no md5hash identity found"); | ||
138 | } | ||
139 | else | ||
140 | { | ||
141 | m_log.Warn("[SIMIAN AUTH CONNECTOR]: Failed to retrieve identities for " + principalID + ": " + | ||
142 | response["Message"].AsString()); | ||
143 | } | ||
144 | |||
145 | return String.Empty; | ||
146 | } | ||
147 | |||
148 | public bool Verify(UUID principalID, string token, int lifetime) | ||
149 | { | ||
150 | NameValueCollection requestArgs = new NameValueCollection | ||
151 | { | ||
152 | { "RequestMethod", "GetSession" }, | ||
153 | { "SessionID", token } | ||
154 | }; | ||
155 | |||
156 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
157 | if (response["Success"].AsBoolean()) | ||
158 | { | ||
159 | return true; | ||
160 | } | ||
161 | else | ||
162 | { | ||
163 | m_log.Warn("[SIMIAN AUTH CONNECTOR]: Could not verify session for " + principalID + ": " + | ||
164 | response["Message"].AsString()); | ||
165 | } | ||
166 | |||
167 | return false; | ||
168 | } | ||
169 | |||
170 | public bool Release(UUID principalID, string token) | ||
171 | { | ||
172 | NameValueCollection requestArgs = new NameValueCollection | ||
173 | { | ||
174 | { "RequestMethod", "RemoveSession" }, | ||
175 | { "UserID", principalID.ToString() } | ||
176 | }; | ||
177 | |||
178 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
179 | if (response["Success"].AsBoolean()) | ||
180 | { | ||
181 | return true; | ||
182 | } | ||
183 | else | ||
184 | { | ||
185 | m_log.Warn("[SIMIAN AUTH CONNECTOR]: Failed to remove session for " + principalID + ": " + | ||
186 | response["Message"].AsString()); | ||
187 | } | ||
188 | |||
189 | return false; | ||
190 | } | ||
191 | |||
192 | public bool SetPassword(UUID principalID, string passwd) | ||
193 | { | ||
194 | // Fetch the user name first | ||
195 | NameValueCollection requestArgs = new NameValueCollection | ||
196 | { | ||
197 | { "RequestMethod", "GetUser" }, | ||
198 | { "UserID", principalID.ToString() } | ||
199 | }; | ||
200 | |||
201 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
202 | if (response["Success"].AsBoolean() && response["User"] is OSDMap) | ||
203 | { | ||
204 | OSDMap userMap = (OSDMap)response["User"]; | ||
205 | string identifier = userMap["Name"].AsString(); | ||
206 | |||
207 | if (!String.IsNullOrEmpty(identifier)) | ||
208 | { | ||
209 | // Add/update the md5hash identity | ||
210 | // TODO: Support salts when AddIdentity does | ||
211 | // TODO: Create an a1hash too for WebDAV logins | ||
212 | requestArgs = new NameValueCollection | ||
213 | { | ||
214 | { "RequestMethod", "AddIdentity" }, | ||
215 | { "Identifier", identifier }, | ||
216 | { "Credential", "$1$" + Utils.MD5String(passwd) }, | ||
217 | { "Type", "md5hash" }, | ||
218 | { "UserID", principalID.ToString() } | ||
219 | }; | ||
220 | |||
221 | response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
222 | bool success = response["Success"].AsBoolean(); | ||
223 | |||
224 | if (!success) | ||
225 | m_log.WarnFormat("[SIMIAN AUTH CONNECTOR]: Failed to set password for {0} ({1})", identifier, principalID); | ||
226 | |||
227 | return success; | ||
228 | } | ||
229 | } | ||
230 | else | ||
231 | { | ||
232 | m_log.Warn("[SIMIAN AUTH CONNECTOR]: Failed to retrieve identities for " + principalID + ": " + | ||
233 | response["Message"].AsString()); | ||
234 | } | ||
235 | |||
236 | return false; | ||
237 | } | ||
238 | |||
239 | public AuthInfo GetAuthInfo(UUID principalID) | ||
240 | { | ||
241 | throw new NotImplementedException(); | ||
242 | } | ||
243 | |||
244 | public bool SetAuthInfo(AuthInfo info) | ||
245 | { | ||
246 | throw new NotImplementedException(); | ||
247 | } | ||
248 | |||
249 | private bool CheckPassword(UUID userID, string password, string simianGridCredential, out string authorizeResult) | ||
250 | { | ||
251 | if (simianGridCredential.Contains(":")) | ||
252 | { | ||
253 | // Salted version | ||
254 | int idx = simianGridCredential.IndexOf(':'); | ||
255 | string finalhash = simianGridCredential.Substring(0, idx); | ||
256 | string salt = simianGridCredential.Substring(idx + 1); | ||
257 | |||
258 | if (finalhash == Utils.MD5String(password + ":" + salt)) | ||
259 | { | ||
260 | authorizeResult = Authorize(userID); | ||
261 | return true; | ||
262 | } | ||
263 | else | ||
264 | { | ||
265 | m_log.Warn("[SIMIAN AUTH CONNECTOR]: Authentication failed for " + userID + | ||
266 | " using md5hash " + Utils.MD5String(password) + ":" + salt); | ||
267 | } | ||
268 | } | ||
269 | else | ||
270 | { | ||
271 | // Unsalted version | ||
272 | if (password == simianGridCredential || | ||
273 | "$1$" + password == simianGridCredential || | ||
274 | "$1$" + Utils.MD5String(password) == simianGridCredential || | ||
275 | Utils.MD5String(password) == simianGridCredential || | ||
276 | "$1$" + Utils.MD5String(password + ":") == simianGridCredential) | ||
277 | { | ||
278 | authorizeResult = Authorize(userID); | ||
279 | return true; | ||
280 | } | ||
281 | else | ||
282 | { | ||
283 | m_log.Warn("[SIMIAN AUTH CONNECTOR]: Authentication failed for " + userID + | ||
284 | " using md5hash $1$" + Utils.MD5String(password)); | ||
285 | } | ||
286 | } | ||
287 | |||
288 | authorizeResult = null; | ||
289 | return false; | ||
290 | } | ||
291 | |||
292 | private string Authorize(UUID userID) | ||
293 | { | ||
294 | NameValueCollection requestArgs = new NameValueCollection | ||
295 | { | ||
296 | { "RequestMethod", "AddSession" }, | ||
297 | { "UserID", userID.ToString() } | ||
298 | }; | ||
299 | |||
300 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
301 | if (response["Success"].AsBoolean()) | ||
302 | return response["SessionID"].AsUUID().ToString(); | ||
303 | else | ||
304 | return String.Empty; | ||
305 | } | ||
306 | } | ||
307 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs new file mode 100644 index 0000000..360f0dd --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianAvatarServiceConnector.cs | |||
@@ -0,0 +1,344 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Collections.Specialized; | ||
31 | // DEBUG ON | ||
32 | using System.Diagnostics; | ||
33 | // DEBUG OFF | ||
34 | using System.Reflection; | ||
35 | using log4net; | ||
36 | using Mono.Addins; | ||
37 | using Nini.Config; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | using OpenSim.Services.Interfaces; | ||
42 | using OpenMetaverse; | ||
43 | using OpenMetaverse.StructuredData; | ||
44 | |||
45 | namespace OpenSim.Services.Connectors.SimianGrid | ||
46 | { | ||
47 | /// <summary> | ||
48 | /// Connects avatar appearance data to the SimianGrid backend | ||
49 | /// </summary> | ||
50 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
51 | public class SimianAvatarServiceConnector : IAvatarService, ISharedRegionModule | ||
52 | { | ||
53 | private static readonly ILog m_log = | ||
54 | LogManager.GetLogger( | ||
55 | MethodBase.GetCurrentMethod().DeclaringType); | ||
56 | // private static string ZeroID = UUID.Zero.ToString(); | ||
57 | |||
58 | private string m_serverUrl = String.Empty; | ||
59 | private bool m_Enabled = false; | ||
60 | |||
61 | #region ISharedRegionModule | ||
62 | |||
63 | public Type ReplaceableInterface { get { return null; } } | ||
64 | public void RegionLoaded(Scene scene) { } | ||
65 | public void PostInitialise() { } | ||
66 | public void Close() { } | ||
67 | |||
68 | public SimianAvatarServiceConnector() { } | ||
69 | public string Name { get { return "SimianAvatarServiceConnector"; } } | ||
70 | public void AddRegion(Scene scene) { if (m_Enabled) { scene.RegisterModuleInterface<IAvatarService>(this); } } | ||
71 | public void RemoveRegion(Scene scene) { if (m_Enabled) { scene.UnregisterModuleInterface<IAvatarService>(this); } } | ||
72 | |||
73 | #endregion ISharedRegionModule | ||
74 | |||
75 | public SimianAvatarServiceConnector(IConfigSource source) | ||
76 | { | ||
77 | CommonInit(source); | ||
78 | } | ||
79 | |||
80 | public void Initialise(IConfigSource source) | ||
81 | { | ||
82 | IConfig moduleConfig = source.Configs["Modules"]; | ||
83 | if (moduleConfig != null) | ||
84 | { | ||
85 | string name = moduleConfig.GetString("AvatarServices", ""); | ||
86 | if (name == Name) | ||
87 | CommonInit(source); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | private void CommonInit(IConfigSource source) | ||
92 | { | ||
93 | IConfig gridConfig = source.Configs["AvatarService"]; | ||
94 | if (gridConfig != null) | ||
95 | { | ||
96 | string serviceUrl = gridConfig.GetString("AvatarServerURI"); | ||
97 | if (!String.IsNullOrEmpty(serviceUrl)) | ||
98 | { | ||
99 | if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("=")) | ||
100 | serviceUrl = serviceUrl + '/'; | ||
101 | m_serverUrl = serviceUrl; | ||
102 | m_Enabled = true; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | if (String.IsNullOrEmpty(m_serverUrl)) | ||
107 | m_log.Info("[SIMIAN AVATAR CONNECTOR]: No AvatarServerURI specified, disabling connector"); | ||
108 | } | ||
109 | |||
110 | #region IAvatarService | ||
111 | |||
112 | // <summary> | ||
113 | // Retrieves the LLPackedAppearance field from user data and unpacks | ||
114 | // it into an AvatarAppearance structure | ||
115 | // </summary> | ||
116 | // <param name="userID"></param> | ||
117 | public AvatarAppearance GetAppearance(UUID userID) | ||
118 | { | ||
119 | NameValueCollection requestArgs = new NameValueCollection | ||
120 | { | ||
121 | { "RequestMethod", "GetUser" }, | ||
122 | { "UserID", userID.ToString() } | ||
123 | }; | ||
124 | |||
125 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
126 | if (response["Success"].AsBoolean()) | ||
127 | { | ||
128 | OSDMap map = null; | ||
129 | try { map = OSDParser.DeserializeJson(response["LLPackedAppearance"].AsString()) as OSDMap; } | ||
130 | catch { } | ||
131 | |||
132 | if (map != null) | ||
133 | { | ||
134 | AvatarAppearance appearance = new AvatarAppearance(map); | ||
135 | // DEBUG ON | ||
136 | m_log.WarnFormat("[SIMIAN AVATAR CONNECTOR] retrieved appearance for {0}:\n{1}",userID,appearance.ToString()); | ||
137 | // DEBUG OFF | ||
138 | return appearance; | ||
139 | } | ||
140 | |||
141 | m_log.WarnFormat("[SIMIAN AVATAR CONNECTOR]: Failed to decode appearance for {0}",userID); | ||
142 | return null; | ||
143 | } | ||
144 | |||
145 | m_log.WarnFormat("[SIMIAN AVATAR CONNECTOR]: Failed to get appearance for {0}: {1}", | ||
146 | userID,response["Message"].AsString()); | ||
147 | return null; | ||
148 | } | ||
149 | |||
150 | // <summary> | ||
151 | // </summary> | ||
152 | // <param name=""></param> | ||
153 | public bool SetAppearance(UUID userID, AvatarAppearance appearance) | ||
154 | { | ||
155 | OSDMap map = appearance.Pack(); | ||
156 | if (map == null) | ||
157 | { | ||
158 | m_log.WarnFormat("[SIMIAN AVATAR CONNECTOR]: Failed to encode appearance for {0}",userID); | ||
159 | return false; | ||
160 | } | ||
161 | |||
162 | // m_log.DebugFormat("[SIMIAN AVATAR CONNECTOR] save appearance for {0}",userID); | ||
163 | |||
164 | NameValueCollection requestArgs = new NameValueCollection | ||
165 | { | ||
166 | { "RequestMethod", "AddUserData" }, | ||
167 | { "UserID", userID.ToString() }, | ||
168 | { "LLPackedAppearance", OSDParser.SerializeJsonString(map) } | ||
169 | }; | ||
170 | |||
171 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
172 | bool success = response["Success"].AsBoolean(); | ||
173 | |||
174 | if (! success) | ||
175 | m_log.WarnFormat("[SIMIAN AVATAR CONNECTOR]: Failed to save appearance for {0}: {1}", | ||
176 | userID,response["Message"].AsString()); | ||
177 | |||
178 | return success; | ||
179 | } | ||
180 | |||
181 | // <summary> | ||
182 | // </summary> | ||
183 | // <param name=""></param> | ||
184 | public AvatarData GetAvatar(UUID userID) | ||
185 | { | ||
186 | NameValueCollection requestArgs = new NameValueCollection | ||
187 | { | ||
188 | { "RequestMethod", "GetUser" }, | ||
189 | { "UserID", userID.ToString() } | ||
190 | }; | ||
191 | |||
192 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
193 | if (response["Success"].AsBoolean()) | ||
194 | { | ||
195 | OSDMap map = null; | ||
196 | try { map = OSDParser.DeserializeJson(response["LLAppearance"].AsString()) as OSDMap; } | ||
197 | catch { } | ||
198 | |||
199 | if (map != null) | ||
200 | { | ||
201 | AvatarWearable[] wearables = new AvatarWearable[13]; | ||
202 | wearables[0] = new AvatarWearable(map["ShapeItem"].AsUUID(), map["ShapeAsset"].AsUUID()); | ||
203 | wearables[1] = new AvatarWearable(map["SkinItem"].AsUUID(), map["SkinAsset"].AsUUID()); | ||
204 | wearables[2] = new AvatarWearable(map["HairItem"].AsUUID(), map["HairAsset"].AsUUID()); | ||
205 | wearables[3] = new AvatarWearable(map["EyesItem"].AsUUID(), map["EyesAsset"].AsUUID()); | ||
206 | wearables[4] = new AvatarWearable(map["ShirtItem"].AsUUID(), map["ShirtAsset"].AsUUID()); | ||
207 | wearables[5] = new AvatarWearable(map["PantsItem"].AsUUID(), map["PantsAsset"].AsUUID()); | ||
208 | wearables[6] = new AvatarWearable(map["ShoesItem"].AsUUID(), map["ShoesAsset"].AsUUID()); | ||
209 | wearables[7] = new AvatarWearable(map["SocksItem"].AsUUID(), map["SocksAsset"].AsUUID()); | ||
210 | wearables[8] = new AvatarWearable(map["JacketItem"].AsUUID(), map["JacketAsset"].AsUUID()); | ||
211 | wearables[9] = new AvatarWearable(map["GlovesItem"].AsUUID(), map["GlovesAsset"].AsUUID()); | ||
212 | wearables[10] = new AvatarWearable(map["UndershirtItem"].AsUUID(), map["UndershirtAsset"].AsUUID()); | ||
213 | wearables[11] = new AvatarWearable(map["UnderpantsItem"].AsUUID(), map["UnderpantsAsset"].AsUUID()); | ||
214 | wearables[12] = new AvatarWearable(map["SkirtItem"].AsUUID(), map["SkirtAsset"].AsUUID()); | ||
215 | |||
216 | AvatarAppearance appearance = new AvatarAppearance(); | ||
217 | appearance.Wearables = wearables; | ||
218 | appearance.AvatarHeight = (float)map["Height"].AsReal(); | ||
219 | |||
220 | AvatarData avatar = new AvatarData(appearance); | ||
221 | |||
222 | // Get attachments | ||
223 | map = null; | ||
224 | try { map = OSDParser.DeserializeJson(response["LLAttachments"].AsString()) as OSDMap; } | ||
225 | catch { } | ||
226 | |||
227 | if (map != null) | ||
228 | { | ||
229 | foreach (KeyValuePair<string, OSD> kvp in map) | ||
230 | avatar.Data[kvp.Key] = kvp.Value.AsString(); | ||
231 | } | ||
232 | |||
233 | return avatar; | ||
234 | } | ||
235 | else | ||
236 | { | ||
237 | m_log.Warn("[SIMIAN AVATAR CONNECTOR]: Failed to get user appearance for " + userID + | ||
238 | ", LLAppearance is missing or invalid"); | ||
239 | return null; | ||
240 | } | ||
241 | } | ||
242 | else | ||
243 | { | ||
244 | m_log.Warn("[SIMIAN AVATAR CONNECTOR]: Failed to get user appearance for " + userID + ": " + | ||
245 | response["Message"].AsString()); | ||
246 | } | ||
247 | |||
248 | return null; | ||
249 | } | ||
250 | |||
251 | // <summary> | ||
252 | // </summary> | ||
253 | // <param name=""></param> | ||
254 | public bool SetAvatar(UUID userID, AvatarData avatar) | ||
255 | { | ||
256 | m_log.Debug("[SIMIAN AVATAR CONNECTOR]: SetAvatar called for " + userID); | ||
257 | |||
258 | if (avatar.AvatarType == 1) // LLAvatar | ||
259 | { | ||
260 | AvatarAppearance appearance = avatar.ToAvatarAppearance(); | ||
261 | |||
262 | OSDMap map = new OSDMap(); | ||
263 | |||
264 | map["Height"] = OSD.FromReal(appearance.AvatarHeight); | ||
265 | |||
266 | map["BodyItem"] = appearance.Wearables[AvatarWearable.BODY][0].ItemID.ToString(); | ||
267 | map["EyesItem"] = appearance.Wearables[AvatarWearable.EYES][0].ItemID.ToString(); | ||
268 | map["GlovesItem"] = appearance.Wearables[AvatarWearable.GLOVES][0].ItemID.ToString(); | ||
269 | map["HairItem"] = appearance.Wearables[AvatarWearable.HAIR][0].ItemID.ToString(); | ||
270 | map["JacketItem"] = appearance.Wearables[AvatarWearable.JACKET][0].ItemID.ToString(); | ||
271 | map["PantsItem"] = appearance.Wearables[AvatarWearable.PANTS][0].ItemID.ToString(); | ||
272 | map["ShirtItem"] = appearance.Wearables[AvatarWearable.SHIRT][0].ItemID.ToString(); | ||
273 | map["ShoesItem"] = appearance.Wearables[AvatarWearable.SHOES][0].ItemID.ToString(); | ||
274 | map["SkinItem"] = appearance.Wearables[AvatarWearable.SKIN][0].ItemID.ToString(); | ||
275 | map["SkirtItem"] = appearance.Wearables[AvatarWearable.SKIRT][0].ItemID.ToString(); | ||
276 | map["SocksItem"] = appearance.Wearables[AvatarWearable.SOCKS][0].ItemID.ToString(); | ||
277 | map["UnderPantsItem"] = appearance.Wearables[AvatarWearable.UNDERPANTS][0].ItemID.ToString(); | ||
278 | map["UnderShirtItem"] = appearance.Wearables[AvatarWearable.UNDERSHIRT][0].ItemID.ToString(); | ||
279 | map["BodyAsset"] = appearance.Wearables[AvatarWearable.BODY][0].AssetID.ToString(); | ||
280 | map["EyesAsset"] = appearance.Wearables[AvatarWearable.EYES][0].AssetID.ToString(); | ||
281 | map["GlovesAsset"] = appearance.Wearables[AvatarWearable.GLOVES][0].AssetID.ToString(); | ||
282 | map["HairAsset"] = appearance.Wearables[AvatarWearable.HAIR][0].AssetID.ToString(); | ||
283 | map["JacketAsset"] = appearance.Wearables[AvatarWearable.JACKET][0].AssetID.ToString(); | ||
284 | map["PantsAsset"] = appearance.Wearables[AvatarWearable.PANTS][0].AssetID.ToString(); | ||
285 | map["ShirtAsset"] = appearance.Wearables[AvatarWearable.SHIRT][0].AssetID.ToString(); | ||
286 | map["ShoesAsset"] = appearance.Wearables[AvatarWearable.SHOES][0].AssetID.ToString(); | ||
287 | map["SkinAsset"] = appearance.Wearables[AvatarWearable.SKIN][0].AssetID.ToString(); | ||
288 | map["SkirtAsset"] = appearance.Wearables[AvatarWearable.SKIRT][0].AssetID.ToString(); | ||
289 | map["SocksAsset"] = appearance.Wearables[AvatarWearable.SOCKS][0].AssetID.ToString(); | ||
290 | map["UnderPantsAsset"] = appearance.Wearables[AvatarWearable.UNDERPANTS][0].AssetID.ToString(); | ||
291 | map["UnderShirtAsset"] = appearance.Wearables[AvatarWearable.UNDERSHIRT][0].AssetID.ToString(); | ||
292 | |||
293 | |||
294 | OSDMap items = new OSDMap(); | ||
295 | foreach (KeyValuePair<string, string> kvp in avatar.Data) | ||
296 | { | ||
297 | if (kvp.Key.StartsWith("_ap_")) | ||
298 | items.Add(kvp.Key, OSD.FromString(kvp.Value)); | ||
299 | } | ||
300 | |||
301 | NameValueCollection requestArgs = new NameValueCollection | ||
302 | { | ||
303 | { "RequestMethod", "AddUserData" }, | ||
304 | { "UserID", userID.ToString() }, | ||
305 | { "LLAppearance", OSDParser.SerializeJsonString(map) }, | ||
306 | { "LLAttachments", OSDParser.SerializeJsonString(items) } | ||
307 | }; | ||
308 | |||
309 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
310 | bool success = response["Success"].AsBoolean(); | ||
311 | |||
312 | if (!success) | ||
313 | m_log.Warn("[SIMIAN AVATAR CONNECTOR]: Failed saving appearance for " + userID + ": " + response["Message"].AsString()); | ||
314 | |||
315 | return success; | ||
316 | } | ||
317 | else | ||
318 | { | ||
319 | m_log.Error("[SIMIAN AVATAR CONNECTOR]: Can't save appearance for " + userID + ". Unhandled avatar type " + avatar.AvatarType); | ||
320 | return false; | ||
321 | } | ||
322 | } | ||
323 | |||
324 | public bool ResetAvatar(UUID userID) | ||
325 | { | ||
326 | m_log.Error("[SIMIAN AVATAR CONNECTOR]: ResetAvatar called for " + userID + ", implement this"); | ||
327 | return false; | ||
328 | } | ||
329 | |||
330 | public bool SetItems(UUID userID, string[] names, string[] values) | ||
331 | { | ||
332 | m_log.Error("[SIMIAN AVATAR CONNECTOR]: SetItems called for " + userID + " with " + names.Length + " names and " + values.Length + " values, implement this"); | ||
333 | return false; | ||
334 | } | ||
335 | |||
336 | public bool RemoveItems(UUID userID, string[] names) | ||
337 | { | ||
338 | m_log.Error("[SIMIAN AVATAR CONNECTOR]: RemoveItems called for " + userID + " with " + names.Length + " names, implement this"); | ||
339 | return false; | ||
340 | } | ||
341 | |||
342 | #endregion IAvatarService | ||
343 | } | ||
344 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs new file mode 100644 index 0000000..7422d94 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianFriendsServiceConnector.cs | |||
@@ -0,0 +1,236 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Reflection; | ||
32 | using log4net; | ||
33 | using Nini.Config; | ||
34 | using OpenMetaverse; | ||
35 | using OpenMetaverse.StructuredData; | ||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Services.Interfaces; | ||
38 | |||
39 | using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; | ||
40 | |||
41 | namespace OpenSim.Services.Connectors.SimianGrid | ||
42 | { | ||
43 | /// <summary> | ||
44 | /// Stores and retrieves friend lists from the SimianGrid backend | ||
45 | /// </summary> | ||
46 | public class SimianFriendsServiceConnector : IFriendsService | ||
47 | { | ||
48 | private static readonly ILog m_log = | ||
49 | LogManager.GetLogger( | ||
50 | MethodBase.GetCurrentMethod().DeclaringType); | ||
51 | |||
52 | private string m_serverUrl = String.Empty; | ||
53 | |||
54 | public SimianFriendsServiceConnector(IConfigSource source) | ||
55 | { | ||
56 | Initialise(source); | ||
57 | } | ||
58 | |||
59 | public void Initialise(IConfigSource source) | ||
60 | { | ||
61 | IConfig gridConfig = source.Configs["FriendsService"]; | ||
62 | if (gridConfig != null) | ||
63 | { | ||
64 | string serviceUrl = gridConfig.GetString("FriendsServerURI"); | ||
65 | if (!String.IsNullOrEmpty(serviceUrl)) | ||
66 | { | ||
67 | if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("=")) | ||
68 | serviceUrl = serviceUrl + '/'; | ||
69 | m_serverUrl = serviceUrl; | ||
70 | } | ||
71 | } | ||
72 | |||
73 | if (String.IsNullOrEmpty(m_serverUrl)) | ||
74 | m_log.Info("[SIMIAN FRIENDS CONNECTOR]: No FriendsServerURI specified, disabling connector"); | ||
75 | } | ||
76 | |||
77 | #region IFriendsService | ||
78 | |||
79 | public FriendInfo[] GetFriends(UUID principalID) | ||
80 | { | ||
81 | return GetFriends(principalID.ToString()); | ||
82 | } | ||
83 | |||
84 | public FriendInfo[] GetFriends(string principalID) | ||
85 | { | ||
86 | if (String.IsNullOrEmpty(m_serverUrl)) | ||
87 | return new FriendInfo[0]; | ||
88 | |||
89 | Dictionary<UUID, FriendInfo> friends = new Dictionary<UUID, FriendInfo>(); | ||
90 | |||
91 | OSDArray friendsArray = GetFriended(principalID); | ||
92 | OSDArray friendedMeArray = GetFriendedBy(principalID); | ||
93 | |||
94 | // Load the list of friends and their granted permissions | ||
95 | for (int i = 0; i < friendsArray.Count; i++) | ||
96 | { | ||
97 | OSDMap friendEntry = friendsArray[i] as OSDMap; | ||
98 | if (friendEntry != null) | ||
99 | { | ||
100 | UUID friendID = friendEntry["Key"].AsUUID(); | ||
101 | |||
102 | FriendInfo friend = new FriendInfo(); | ||
103 | if (!UUID.TryParse(principalID, out friend.PrincipalID)) | ||
104 | { | ||
105 | string tmp = string.Empty; | ||
106 | if (!Util.ParseUniversalUserIdentifier(principalID, out friend.PrincipalID, out tmp, out tmp, out tmp, out tmp)) | ||
107 | // bad record. ignore this entry | ||
108 | continue; | ||
109 | } | ||
110 | |||
111 | friend.Friend = friendID.ToString(); | ||
112 | friend.MyFlags = friendEntry["Value"].AsInteger(); | ||
113 | friend.TheirFlags = -1; | ||
114 | |||
115 | friends[friendID] = friend; | ||
116 | } | ||
117 | } | ||
118 | |||
119 | // Load the permissions those friends have granted to this user | ||
120 | for (int i = 0; i < friendedMeArray.Count; i++) | ||
121 | { | ||
122 | OSDMap friendedMeEntry = friendedMeArray[i] as OSDMap; | ||
123 | if (friendedMeEntry != null) | ||
124 | { | ||
125 | UUID friendID = friendedMeEntry["OwnerID"].AsUUID(); | ||
126 | |||
127 | FriendInfo friend; | ||
128 | if (friends.TryGetValue(friendID, out friend)) | ||
129 | friend.TheirFlags = friendedMeEntry["Value"].AsInteger(); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | // Convert the dictionary of friends to an array and return it | ||
134 | FriendInfo[] array = new FriendInfo[friends.Count]; | ||
135 | int j = 0; | ||
136 | foreach (FriendInfo friend in friends.Values) | ||
137 | array[j++] = friend; | ||
138 | |||
139 | return array; | ||
140 | } | ||
141 | |||
142 | public bool StoreFriend(string principalID, string friend, int flags) | ||
143 | { | ||
144 | if (String.IsNullOrEmpty(m_serverUrl)) | ||
145 | return true; | ||
146 | |||
147 | NameValueCollection requestArgs = new NameValueCollection | ||
148 | { | ||
149 | { "RequestMethod", "AddGeneric" }, | ||
150 | { "OwnerID", principalID.ToString() }, | ||
151 | { "Type", "Friend" }, | ||
152 | { "Key", friend }, | ||
153 | { "Value", flags.ToString() } | ||
154 | }; | ||
155 | |||
156 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
157 | bool success = response["Success"].AsBoolean(); | ||
158 | |||
159 | if (!success) | ||
160 | m_log.Error("[SIMIAN FRIENDS CONNECTOR]: Failed to store friend " + friend + " for user " + principalID + ": " + response["Message"].AsString()); | ||
161 | |||
162 | return success; | ||
163 | } | ||
164 | |||
165 | public bool Delete(UUID principalID, string friend) | ||
166 | { | ||
167 | return Delete(principalID.ToString(), friend); | ||
168 | } | ||
169 | |||
170 | public bool Delete(string principalID, string friend) | ||
171 | { | ||
172 | if (String.IsNullOrEmpty(m_serverUrl)) | ||
173 | return true; | ||
174 | |||
175 | NameValueCollection requestArgs = new NameValueCollection | ||
176 | { | ||
177 | { "RequestMethod", "RemoveGeneric" }, | ||
178 | { "OwnerID", principalID.ToString() }, | ||
179 | { "Type", "Friend" }, | ||
180 | { "Key", friend } | ||
181 | }; | ||
182 | |||
183 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
184 | bool success = response["Success"].AsBoolean(); | ||
185 | |||
186 | if (!success) | ||
187 | m_log.Error("[SIMIAN FRIENDS CONNECTOR]: Failed to remove friend " + friend + " for user " + principalID + ": " + response["Message"].AsString()); | ||
188 | |||
189 | return success; | ||
190 | } | ||
191 | |||
192 | #endregion IFriendsService | ||
193 | |||
194 | private OSDArray GetFriended(string ownerID) | ||
195 | { | ||
196 | NameValueCollection requestArgs = new NameValueCollection | ||
197 | { | ||
198 | { "RequestMethod", "GetGenerics" }, | ||
199 | { "OwnerID", ownerID.ToString() }, | ||
200 | { "Type", "Friend" } | ||
201 | }; | ||
202 | |||
203 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
204 | if (response["Success"].AsBoolean() && response["Entries"] is OSDArray) | ||
205 | { | ||
206 | return (OSDArray)response["Entries"]; | ||
207 | } | ||
208 | else | ||
209 | { | ||
210 | m_log.Warn("[SIMIAN FRIENDS CONNECTOR]: Failed to retrieve friends for user " + ownerID + ": " + response["Message"].AsString()); | ||
211 | return new OSDArray(0); | ||
212 | } | ||
213 | } | ||
214 | |||
215 | private OSDArray GetFriendedBy(string ownerID) | ||
216 | { | ||
217 | NameValueCollection requestArgs = new NameValueCollection | ||
218 | { | ||
219 | { "RequestMethod", "GetGenerics" }, | ||
220 | { "Key", ownerID.ToString() }, | ||
221 | { "Type", "Friend" } | ||
222 | }; | ||
223 | |||
224 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
225 | if (response["Success"].AsBoolean() && response["Entries"] is OSDArray) | ||
226 | { | ||
227 | return (OSDArray)response["Entries"]; | ||
228 | } | ||
229 | else | ||
230 | { | ||
231 | m_log.Warn("[SIMIAN FRIENDS CONNECTOR]: Failed to retrieve reverse friends for user " + ownerID + ": " + response["Message"].AsString()); | ||
232 | return new OSDArray(0); | ||
233 | } | ||
234 | } | ||
235 | } | ||
236 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs new file mode 100644 index 0000000..847319c --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGrid.cs | |||
@@ -0,0 +1,33 @@ | |||
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 | |||
28 | using System; | ||
29 | using Mono.Addins; | ||
30 | using Nini.Config; | ||
31 | |||
32 | [assembly: Addin("SimianGrid", "1.0")] | ||
33 | [assembly: AddinDependency("OpenSim", "0.5")] | ||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using System.Net; | ||
32 | using System.IO; | ||
33 | using System.Timers; | ||
34 | using System.Drawing; | ||
35 | using System.Drawing.Imaging; | ||
36 | |||
37 | using log4net; | ||
38 | using Mono.Addins; | ||
39 | using Nini.Config; | ||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Region.Framework.Interfaces; | ||
42 | using OpenSim.Region.Framework.Scenes; | ||
43 | using OpenMetaverse; | ||
44 | using OpenMetaverse.StructuredData; | ||
45 | |||
46 | namespace 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 | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs new file mode 100644 index 0000000..feea196 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianGridServiceConnector.cs | |||
@@ -0,0 +1,524 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Drawing; | ||
32 | using System.Drawing.Imaging; | ||
33 | using System.IO; | ||
34 | using System.Net; | ||
35 | using System.Reflection; | ||
36 | using log4net; | ||
37 | using Mono.Addins; | ||
38 | using Nini.Config; | ||
39 | using OpenSim.Framework; | ||
40 | using OpenSim.Region.Framework.Interfaces; | ||
41 | using OpenSim.Region.Framework.Scenes; | ||
42 | using OpenSim.Services.Interfaces; | ||
43 | using OpenMetaverse; | ||
44 | using OpenMetaverse.StructuredData; | ||
45 | |||
46 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
47 | |||
48 | namespace OpenSim.Services.Connectors.SimianGrid | ||
49 | { | ||
50 | /// <summary> | ||
51 | /// Connects region registration and neighbor lookups to the SimianGrid | ||
52 | /// backend | ||
53 | /// </summary> | ||
54 | public class SimianGridServiceConnector : IGridService | ||
55 | { | ||
56 | private static readonly ILog m_log = | ||
57 | LogManager.GetLogger( | ||
58 | MethodBase.GetCurrentMethod().DeclaringType); | ||
59 | |||
60 | private string m_ServerURI = String.Empty; | ||
61 | // private bool m_Enabled = false; | ||
62 | |||
63 | public SimianGridServiceConnector() { } | ||
64 | public SimianGridServiceConnector(string serverURI) | ||
65 | { | ||
66 | m_ServerURI = serverURI.TrimEnd('/'); | ||
67 | } | ||
68 | |||
69 | public SimianGridServiceConnector(IConfigSource source) | ||
70 | { | ||
71 | CommonInit(source); | ||
72 | } | ||
73 | |||
74 | public void Initialise(IConfigSource source) | ||
75 | { | ||
76 | CommonInit(source); | ||
77 | } | ||
78 | |||
79 | private void CommonInit(IConfigSource source) | ||
80 | { | ||
81 | IConfig gridConfig = source.Configs["GridService"]; | ||
82 | if (gridConfig == null) | ||
83 | { | ||
84 | m_log.Error("[SIMIAN GRID CONNECTOR]: GridService missing from OpenSim.ini"); | ||
85 | throw new Exception("Grid connector init error"); | ||
86 | } | ||
87 | |||
88 | string serviceUrl = gridConfig.GetString("GridServerURI"); | ||
89 | if (String.IsNullOrEmpty(serviceUrl)) | ||
90 | { | ||
91 | m_log.Error("[SIMIAN GRID CONNECTOR]: No Server URI named in section GridService"); | ||
92 | throw new Exception("Grid connector init error"); | ||
93 | } | ||
94 | |||
95 | if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("=")) | ||
96 | serviceUrl = serviceUrl + '/'; | ||
97 | m_ServerURI = serviceUrl; | ||
98 | // m_Enabled = true; | ||
99 | } | ||
100 | |||
101 | #region IGridService | ||
102 | |||
103 | public string RegisterRegion(UUID scopeID, GridRegion regionInfo) | ||
104 | { | ||
105 | IPEndPoint ext = regionInfo.ExternalEndPoint; | ||
106 | if (ext == null) return "Region registration for " + regionInfo.RegionName + " failed: Could not resolve EndPoint"; | ||
107 | // Generate and upload our map tile in PNG format to the SimianGrid AddMapTile service | ||
108 | // Scene scene; | ||
109 | // if (m_scenes.TryGetValue(regionInfo.RegionID, out scene)) | ||
110 | // UploadMapTile(scene); | ||
111 | // else | ||
112 | // m_log.Warn("Registering region " + regionInfo.RegionName + " (" + regionInfo.RegionID + ") that we are not tracking"); | ||
113 | |||
114 | Vector3d minPosition = new Vector3d(regionInfo.RegionLocX, regionInfo.RegionLocY, 0.0); | ||
115 | Vector3d maxPosition = minPosition + new Vector3d(Constants.RegionSize, Constants.RegionSize, 4096.0); | ||
116 | |||
117 | OSDMap extraData = new OSDMap | ||
118 | { | ||
119 | { "ServerURI", OSD.FromString(regionInfo.ServerURI) }, | ||
120 | { "InternalAddress", OSD.FromString(regionInfo.InternalEndPoint.Address.ToString()) }, | ||
121 | { "InternalPort", OSD.FromInteger(regionInfo.InternalEndPoint.Port) }, | ||
122 | { "ExternalAddress", OSD.FromString(ext.Address.ToString()) }, | ||
123 | { "ExternalPort", OSD.FromInteger(regionInfo.ExternalEndPoint.Port) }, | ||
124 | { "MapTexture", OSD.FromUUID(regionInfo.TerrainImage) }, | ||
125 | { "Access", OSD.FromInteger(regionInfo.Access) }, | ||
126 | { "RegionSecret", OSD.FromString(regionInfo.RegionSecret) }, | ||
127 | { "EstateOwner", OSD.FromUUID(regionInfo.EstateOwner) }, | ||
128 | { "Token", OSD.FromString(regionInfo.Token) } | ||
129 | }; | ||
130 | |||
131 | NameValueCollection requestArgs = new NameValueCollection | ||
132 | { | ||
133 | { "RequestMethod", "AddScene" }, | ||
134 | { "SceneID", regionInfo.RegionID.ToString() }, | ||
135 | { "Name", regionInfo.RegionName }, | ||
136 | { "MinPosition", minPosition.ToString() }, | ||
137 | { "MaxPosition", maxPosition.ToString() }, | ||
138 | { "Address", regionInfo.ServerURI }, | ||
139 | { "Enabled", "1" }, | ||
140 | { "ExtraData", OSDParser.SerializeJsonString(extraData) } | ||
141 | }; | ||
142 | |||
143 | OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); | ||
144 | if (response["Success"].AsBoolean()) | ||
145 | return String.Empty; | ||
146 | else | ||
147 | return "Region registration for " + regionInfo.RegionName + " failed: " + response["Message"].AsString(); | ||
148 | } | ||
149 | |||
150 | public bool DeregisterRegion(UUID regionID) | ||
151 | { | ||
152 | NameValueCollection requestArgs = new NameValueCollection | ||
153 | { | ||
154 | { "RequestMethod", "AddScene" }, | ||
155 | { "SceneID", regionID.ToString() }, | ||
156 | { "Enabled", "0" } | ||
157 | }; | ||
158 | |||
159 | OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); | ||
160 | bool success = response["Success"].AsBoolean(); | ||
161 | |||
162 | if (!success) | ||
163 | m_log.Warn("[SIMIAN GRID CONNECTOR]: Region deregistration for " + regionID + " failed: " + response["Message"].AsString()); | ||
164 | |||
165 | return success; | ||
166 | } | ||
167 | |||
168 | public List<GridRegion> GetNeighbours(UUID scopeID, UUID regionID) | ||
169 | { | ||
170 | const int NEIGHBOR_RADIUS = 128; | ||
171 | |||
172 | GridRegion region = GetRegionByUUID(scopeID, regionID); | ||
173 | |||
174 | if (region != null) | ||
175 | { | ||
176 | List<GridRegion> regions = GetRegionRange(scopeID, | ||
177 | region.RegionLocX - NEIGHBOR_RADIUS, region.RegionLocX + (int)Constants.RegionSize + NEIGHBOR_RADIUS, | ||
178 | region.RegionLocY - NEIGHBOR_RADIUS, region.RegionLocY + (int)Constants.RegionSize + NEIGHBOR_RADIUS); | ||
179 | |||
180 | for (int i = 0; i < regions.Count; i++) | ||
181 | { | ||
182 | if (regions[i].RegionID == regionID) | ||
183 | { | ||
184 | regions.RemoveAt(i); | ||
185 | break; | ||
186 | } | ||
187 | } | ||
188 | |||
189 | // m_log.Debug("[SIMIAN GRID CONNECTOR]: Found " + regions.Count + " neighbors for region " + regionID); | ||
190 | return regions; | ||
191 | } | ||
192 | |||
193 | return new List<GridRegion>(0); | ||
194 | } | ||
195 | |||
196 | public GridRegion GetRegionByUUID(UUID scopeID, UUID regionID) | ||
197 | { | ||
198 | NameValueCollection requestArgs = new NameValueCollection | ||
199 | { | ||
200 | { "RequestMethod", "GetScene" }, | ||
201 | { "SceneID", regionID.ToString() } | ||
202 | }; | ||
203 | |||
204 | // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request region with uuid {0}",regionID.ToString()); | ||
205 | |||
206 | OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); | ||
207 | if (response["Success"].AsBoolean()) | ||
208 | { | ||
209 | // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] uuid request successful {0}",response["Name"].AsString()); | ||
210 | return ResponseToGridRegion(response); | ||
211 | } | ||
212 | else | ||
213 | { | ||
214 | m_log.Warn("[SIMIAN GRID CONNECTOR]: Grid service did not find a match for region " + regionID); | ||
215 | return null; | ||
216 | } | ||
217 | } | ||
218 | |||
219 | public GridRegion GetRegionByPosition(UUID scopeID, int x, int y) | ||
220 | { | ||
221 | // Go one meter in from the requested x/y coords to avoid requesting a position | ||
222 | // that falls on the border of two sims | ||
223 | Vector3d position = new Vector3d(x + 1, y + 1, 0.0); | ||
224 | |||
225 | NameValueCollection requestArgs = new NameValueCollection | ||
226 | { | ||
227 | { "RequestMethod", "GetScene" }, | ||
228 | { "Position", position.ToString() }, | ||
229 | { "Enabled", "1" } | ||
230 | }; | ||
231 | |||
232 | // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request grid at {0}",position.ToString()); | ||
233 | |||
234 | OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); | ||
235 | if (response["Success"].AsBoolean()) | ||
236 | { | ||
237 | // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] position request successful {0}",response["Name"].AsString()); | ||
238 | return ResponseToGridRegion(response); | ||
239 | } | ||
240 | else | ||
241 | { | ||
242 | // m_log.InfoFormat("[SIMIAN GRID CONNECTOR]: Grid service did not find a match for region at {0},{1}", | ||
243 | // x / Constants.RegionSize, y / Constants.RegionSize); | ||
244 | return null; | ||
245 | } | ||
246 | } | ||
247 | |||
248 | public GridRegion GetRegionByName(UUID scopeID, string regionName) | ||
249 | { | ||
250 | List<GridRegion> regions = GetRegionsByName(scopeID, regionName, 1); | ||
251 | |||
252 | m_log.Debug("[SIMIAN GRID CONNECTOR]: Got " + regions.Count + " matches for region name " + regionName); | ||
253 | |||
254 | if (regions.Count > 0) | ||
255 | return regions[0]; | ||
256 | |||
257 | return null; | ||
258 | } | ||
259 | |||
260 | public List<GridRegion> GetRegionsByName(UUID scopeID, string name, int maxNumber) | ||
261 | { | ||
262 | List<GridRegion> foundRegions = new List<GridRegion>(); | ||
263 | |||
264 | NameValueCollection requestArgs = new NameValueCollection | ||
265 | { | ||
266 | { "RequestMethod", "GetScenes" }, | ||
267 | { "NameQuery", name }, | ||
268 | { "Enabled", "1" } | ||
269 | }; | ||
270 | if (maxNumber > 0) | ||
271 | requestArgs["MaxNumber"] = maxNumber.ToString(); | ||
272 | |||
273 | // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request regions with name {0}",name); | ||
274 | |||
275 | OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); | ||
276 | if (response["Success"].AsBoolean()) | ||
277 | { | ||
278 | // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] found regions with name {0}",name); | ||
279 | |||
280 | OSDArray array = response["Scenes"] as OSDArray; | ||
281 | if (array != null) | ||
282 | { | ||
283 | for (int i = 0; i < array.Count; i++) | ||
284 | { | ||
285 | GridRegion region = ResponseToGridRegion(array[i] as OSDMap); | ||
286 | if (region != null) | ||
287 | foundRegions.Add(region); | ||
288 | } | ||
289 | } | ||
290 | } | ||
291 | |||
292 | return foundRegions; | ||
293 | } | ||
294 | |||
295 | public List<GridRegion> GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax) | ||
296 | { | ||
297 | List<GridRegion> foundRegions = new List<GridRegion>(); | ||
298 | |||
299 | Vector3d minPosition = new Vector3d(xmin, ymin, 0.0); | ||
300 | Vector3d maxPosition = new Vector3d(xmax, ymax, 4096.0); | ||
301 | |||
302 | NameValueCollection requestArgs = new NameValueCollection | ||
303 | { | ||
304 | { "RequestMethod", "GetScenes" }, | ||
305 | { "MinPosition", minPosition.ToString() }, | ||
306 | { "MaxPosition", maxPosition.ToString() }, | ||
307 | { "Enabled", "1" } | ||
308 | }; | ||
309 | |||
310 | //m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request regions by range {0} to {1}",minPosition.ToString(),maxPosition.ToString()); | ||
311 | |||
312 | |||
313 | OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); | ||
314 | if (response["Success"].AsBoolean()) | ||
315 | { | ||
316 | OSDArray array = response["Scenes"] as OSDArray; | ||
317 | if (array != null) | ||
318 | { | ||
319 | for (int i = 0; i < array.Count; i++) | ||
320 | { | ||
321 | GridRegion region = ResponseToGridRegion(array[i] as OSDMap); | ||
322 | if (region != null) | ||
323 | foundRegions.Add(region); | ||
324 | } | ||
325 | } | ||
326 | } | ||
327 | |||
328 | return foundRegions; | ||
329 | } | ||
330 | |||
331 | public List<GridRegion> GetDefaultRegions(UUID scopeID) | ||
332 | { | ||
333 | // TODO: Allow specifying the default grid location | ||
334 | const int DEFAULT_X = 1000 * 256; | ||
335 | const int DEFAULT_Y = 1000 * 256; | ||
336 | |||
337 | GridRegion defRegion = GetNearestRegion(new Vector3d(DEFAULT_X, DEFAULT_Y, 0.0), true); | ||
338 | if (defRegion != null) | ||
339 | return new List<GridRegion>(1) { defRegion }; | ||
340 | else | ||
341 | return new List<GridRegion>(0); | ||
342 | } | ||
343 | |||
344 | public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y) | ||
345 | { | ||
346 | GridRegion defRegion = GetNearestRegion(new Vector3d(x, y, 0.0), true); | ||
347 | if (defRegion != null) | ||
348 | return new List<GridRegion>(1) { defRegion }; | ||
349 | else | ||
350 | return new List<GridRegion>(0); | ||
351 | } | ||
352 | |||
353 | public List<GridRegion> GetHyperlinks(UUID scopeID) | ||
354 | { | ||
355 | // Hypergrid/linked regions are not supported | ||
356 | return new List<GridRegion>(); | ||
357 | } | ||
358 | |||
359 | public int GetRegionFlags(UUID scopeID, UUID regionID) | ||
360 | { | ||
361 | const int REGION_ONLINE = 4; | ||
362 | |||
363 | NameValueCollection requestArgs = new NameValueCollection | ||
364 | { | ||
365 | { "RequestMethod", "GetScene" }, | ||
366 | { "SceneID", regionID.ToString() } | ||
367 | }; | ||
368 | |||
369 | // m_log.DebugFormat("[SIMIAN GRID CONNECTOR] request region flags for {0}",regionID.ToString()); | ||
370 | |||
371 | OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); | ||
372 | if (response["Success"].AsBoolean()) | ||
373 | { | ||
374 | return response["Enabled"].AsBoolean() ? REGION_ONLINE : 0; | ||
375 | } | ||
376 | else | ||
377 | { | ||
378 | m_log.Warn("[SIMIAN GRID CONNECTOR]: Grid service did not find a match for region " + regionID + " during region flags check"); | ||
379 | return -1; | ||
380 | } | ||
381 | } | ||
382 | |||
383 | #endregion IGridService | ||
384 | |||
385 | private void UploadMapTile(IScene scene) | ||
386 | { | ||
387 | string errorMessage = null; | ||
388 | |||
389 | // Create a PNG map tile and upload it to the AddMapTile API | ||
390 | byte[] pngData = Utils.EmptyBytes; | ||
391 | IMapImageGenerator tileGenerator = scene.RequestModuleInterface<IMapImageGenerator>(); | ||
392 | if (tileGenerator == null) | ||
393 | { | ||
394 | m_log.Warn("[SIMIAN GRID CONNECTOR]: Cannot upload PNG map tile without an IMapImageGenerator"); | ||
395 | return; | ||
396 | } | ||
397 | |||
398 | using (Image mapTile = tileGenerator.CreateMapTile()) | ||
399 | { | ||
400 | using (MemoryStream stream = new MemoryStream()) | ||
401 | { | ||
402 | mapTile.Save(stream, ImageFormat.Png); | ||
403 | pngData = stream.ToArray(); | ||
404 | } | ||
405 | } | ||
406 | |||
407 | List<MultipartForm.Element> postParameters = new List<MultipartForm.Element>() | ||
408 | { | ||
409 | new MultipartForm.Parameter("X", scene.RegionInfo.RegionLocX.ToString()), | ||
410 | new MultipartForm.Parameter("Y", scene.RegionInfo.RegionLocY.ToString()), | ||
411 | new MultipartForm.File("Tile", "tile.png", "image/png", pngData) | ||
412 | }; | ||
413 | |||
414 | // Make the remote storage request | ||
415 | try | ||
416 | { | ||
417 | HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(m_ServerURI); | ||
418 | |||
419 | HttpWebResponse response = MultipartForm.Post(request, postParameters); | ||
420 | using (Stream responseStream = response.GetResponseStream()) | ||
421 | { | ||
422 | string responseStr = null; | ||
423 | |||
424 | try | ||
425 | { | ||
426 | responseStr = responseStream.GetStreamString(); | ||
427 | OSD responseOSD = OSDParser.Deserialize(responseStr); | ||
428 | if (responseOSD.Type == OSDType.Map) | ||
429 | { | ||
430 | OSDMap responseMap = (OSDMap)responseOSD; | ||
431 | if (responseMap["Success"].AsBoolean()) | ||
432 | m_log.Info("[SIMIAN GRID CONNECTOR]: Uploaded " + pngData.Length + " byte PNG map tile to AddMapTile"); | ||
433 | else | ||
434 | errorMessage = "Upload failed: " + responseMap["Message"].AsString(); | ||
435 | } | ||
436 | else | ||
437 | { | ||
438 | errorMessage = "Response format was invalid:\n" + responseStr; | ||
439 | } | ||
440 | } | ||
441 | catch (Exception ex) | ||
442 | { | ||
443 | if (!String.IsNullOrEmpty(responseStr)) | ||
444 | errorMessage = "Failed to parse the response:\n" + responseStr; | ||
445 | else | ||
446 | errorMessage = "Failed to retrieve the response: " + ex.Message; | ||
447 | } | ||
448 | } | ||
449 | } | ||
450 | catch (WebException ex) | ||
451 | { | ||
452 | errorMessage = ex.Message; | ||
453 | } | ||
454 | |||
455 | if (!String.IsNullOrEmpty(errorMessage)) | ||
456 | { | ||
457 | m_log.WarnFormat("[SIMIAN GRID CONNECTOR]: Failed to store {0} byte PNG map tile for {1}: {2}", | ||
458 | pngData.Length, scene.RegionInfo.RegionName, errorMessage.Replace('\n', ' ')); | ||
459 | } | ||
460 | } | ||
461 | |||
462 | private GridRegion GetNearestRegion(Vector3d position, bool onlyEnabled) | ||
463 | { | ||
464 | NameValueCollection requestArgs = new NameValueCollection | ||
465 | { | ||
466 | { "RequestMethod", "GetScene" }, | ||
467 | { "Position", position.ToString() }, | ||
468 | { "FindClosest", "1" } | ||
469 | }; | ||
470 | if (onlyEnabled) | ||
471 | requestArgs["Enabled"] = "1"; | ||
472 | |||
473 | OSDMap response = WebUtil.PostToService(m_ServerURI, requestArgs); | ||
474 | if (response["Success"].AsBoolean()) | ||
475 | { | ||
476 | return ResponseToGridRegion(response); | ||
477 | } | ||
478 | else | ||
479 | { | ||
480 | m_log.Warn("[SIMIAN GRID CONNECTOR]: Grid service did not find a match for region at " + position); | ||
481 | return null; | ||
482 | } | ||
483 | } | ||
484 | |||
485 | private GridRegion ResponseToGridRegion(OSDMap response) | ||
486 | { | ||
487 | if (response == null) | ||
488 | return null; | ||
489 | |||
490 | OSDMap extraData = response["ExtraData"] as OSDMap; | ||
491 | if (extraData == null) | ||
492 | return null; | ||
493 | |||
494 | GridRegion region = new GridRegion(); | ||
495 | |||
496 | region.RegionID = response["SceneID"].AsUUID(); | ||
497 | region.RegionName = response["Name"].AsString(); | ||
498 | |||
499 | Vector3d minPosition = response["MinPosition"].AsVector3d(); | ||
500 | region.RegionLocX = (int)minPosition.X; | ||
501 | region.RegionLocY = (int)minPosition.Y; | ||
502 | |||
503 | Uri httpAddress = response["Address"].AsUri(); | ||
504 | region.ExternalHostName = httpAddress.Host; | ||
505 | region.HttpPort = (uint)httpAddress.Port; | ||
506 | |||
507 | region.ServerURI = extraData["ServerURI"].AsString(); | ||
508 | |||
509 | IPAddress internalAddress; | ||
510 | IPAddress.TryParse(extraData["InternalAddress"].AsString(), out internalAddress); | ||
511 | if (internalAddress == null) | ||
512 | internalAddress = IPAddress.Any; | ||
513 | |||
514 | region.InternalEndPoint = new IPEndPoint(internalAddress, extraData["InternalPort"].AsInteger()); | ||
515 | region.TerrainImage = extraData["MapTexture"].AsUUID(); | ||
516 | region.Access = (byte)extraData["Access"].AsInteger(); | ||
517 | region.RegionSecret = extraData["RegionSecret"].AsString(); | ||
518 | region.EstateOwner = extraData["EstateOwner"].AsUUID(); | ||
519 | region.Token = extraData["Token"].AsString(); | ||
520 | |||
521 | return region; | ||
522 | } | ||
523 | } | ||
524 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs new file mode 100644 index 0000000..39df1f5 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianInventoryServiceConnector.cs | |||
@@ -0,0 +1,922 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Reflection; | ||
32 | using log4net; | ||
33 | using Mono.Addins; | ||
34 | using Nini.Config; | ||
35 | using OpenMetaverse; | ||
36 | using OpenMetaverse.StructuredData; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Region.Framework.Interfaces; | ||
39 | using OpenSim.Region.Framework.Scenes; | ||
40 | using OpenSim.Services.Interfaces; | ||
41 | |||
42 | namespace OpenSim.Services.Connectors.SimianGrid | ||
43 | { | ||
44 | /// <summary> | ||
45 | /// Permissions bitflags | ||
46 | /// </summary> | ||
47 | [Flags] | ||
48 | public enum PermissionMask : uint | ||
49 | { | ||
50 | None = 0, | ||
51 | Transfer = 1 << 13, | ||
52 | Modify = 1 << 14, | ||
53 | Copy = 1 << 15, | ||
54 | Move = 1 << 19, | ||
55 | Damage = 1 << 20, | ||
56 | All = 0x7FFFFFFF | ||
57 | } | ||
58 | |||
59 | /// <summary> | ||
60 | /// Connects avatar inventories to the SimianGrid backend | ||
61 | /// </summary> | ||
62 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
63 | public class SimianInventoryServiceConnector : IInventoryService, ISharedRegionModule | ||
64 | { | ||
65 | private static readonly ILog m_log = | ||
66 | LogManager.GetLogger( | ||
67 | MethodBase.GetCurrentMethod().DeclaringType); | ||
68 | |||
69 | private string m_serverUrl = String.Empty; | ||
70 | private string m_userServerUrl = String.Empty; | ||
71 | // private object m_gestureSyncRoot = new object(); | ||
72 | private bool m_Enabled = false; | ||
73 | |||
74 | #region ISharedRegionModule | ||
75 | |||
76 | public Type ReplaceableInterface { get { return null; } } | ||
77 | public void RegionLoaded(Scene scene) { } | ||
78 | public void PostInitialise() { } | ||
79 | public void Close() { } | ||
80 | |||
81 | public SimianInventoryServiceConnector() { } | ||
82 | public string Name { get { return "SimianInventoryServiceConnector"; } } | ||
83 | public void AddRegion(Scene scene) { if (m_Enabled) { scene.RegisterModuleInterface<IInventoryService>(this); } } | ||
84 | public void RemoveRegion(Scene scene) { if (m_Enabled) { scene.UnregisterModuleInterface<IInventoryService>(this); } } | ||
85 | |||
86 | #endregion ISharedRegionModule | ||
87 | |||
88 | public SimianInventoryServiceConnector(IConfigSource source) | ||
89 | { | ||
90 | CommonInit(source); | ||
91 | } | ||
92 | |||
93 | public SimianInventoryServiceConnector(string url) | ||
94 | { | ||
95 | m_serverUrl = url; | ||
96 | } | ||
97 | |||
98 | public void Initialise(IConfigSource source) | ||
99 | { | ||
100 | IConfig moduleConfig = source.Configs["Modules"]; | ||
101 | if (moduleConfig != null) | ||
102 | { | ||
103 | string name = moduleConfig.GetString("InventoryServices", ""); | ||
104 | if (name == Name) | ||
105 | CommonInit(source); | ||
106 | } | ||
107 | } | ||
108 | |||
109 | private void CommonInit(IConfigSource source) | ||
110 | { | ||
111 | IConfig gridConfig = source.Configs["InventoryService"]; | ||
112 | if (gridConfig != null) | ||
113 | { | ||
114 | string serviceUrl = gridConfig.GetString("InventoryServerURI"); | ||
115 | if (!String.IsNullOrEmpty(serviceUrl)) | ||
116 | { | ||
117 | if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("=")) | ||
118 | serviceUrl = serviceUrl + '/'; | ||
119 | m_serverUrl = serviceUrl; | ||
120 | |||
121 | gridConfig = source.Configs["UserAccountService"]; | ||
122 | if (gridConfig != null) | ||
123 | { | ||
124 | serviceUrl = gridConfig.GetString("UserAccountServerURI"); | ||
125 | if (!String.IsNullOrEmpty(serviceUrl)) | ||
126 | { | ||
127 | m_userServerUrl = serviceUrl; | ||
128 | m_Enabled = true; | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
134 | if (String.IsNullOrEmpty(m_serverUrl)) | ||
135 | m_log.Info("[SIMIAN INVENTORY CONNECTOR]: No InventoryServerURI specified, disabling connector"); | ||
136 | else if (String.IsNullOrEmpty(m_userServerUrl)) | ||
137 | m_log.Info("[SIMIAN INVENTORY CONNECTOR]: No UserAccountServerURI specified, disabling connector"); | ||
138 | } | ||
139 | |||
140 | /// <summary> | ||
141 | /// Create the entire inventory for a given user | ||
142 | /// </summary> | ||
143 | /// <param name="user"></param> | ||
144 | /// <returns></returns> | ||
145 | public bool CreateUserInventory(UUID userID) | ||
146 | { | ||
147 | NameValueCollection requestArgs = new NameValueCollection | ||
148 | { | ||
149 | { "RequestMethod", "AddInventory" }, | ||
150 | { "OwnerID", userID.ToString() } | ||
151 | }; | ||
152 | |||
153 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
154 | bool success = response["Success"].AsBoolean(); | ||
155 | |||
156 | if (!success) | ||
157 | m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Inventory creation for " + userID + " failed: " + response["Message"].AsString()); | ||
158 | |||
159 | return success; | ||
160 | } | ||
161 | |||
162 | /// <summary> | ||
163 | /// Gets the skeleton of the inventory -- folders only | ||
164 | /// </summary> | ||
165 | /// <param name="userID"></param> | ||
166 | /// <returns></returns> | ||
167 | public List<InventoryFolderBase> GetInventorySkeleton(UUID userID) | ||
168 | { | ||
169 | NameValueCollection requestArgs = new NameValueCollection | ||
170 | { | ||
171 | { "RequestMethod", "GetInventoryNode" }, | ||
172 | { "ItemID", userID.ToString() }, | ||
173 | { "OwnerID", userID.ToString() }, | ||
174 | { "IncludeFolders", "1" }, | ||
175 | { "IncludeItems", "0" }, | ||
176 | { "ChildrenOnly", "0" } | ||
177 | }; | ||
178 | |||
179 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
180 | if (response["Success"].AsBoolean() && response["Items"] is OSDArray) | ||
181 | { | ||
182 | OSDArray items = (OSDArray)response["Items"]; | ||
183 | return GetFoldersFromResponse(items, userID, true); | ||
184 | } | ||
185 | else | ||
186 | { | ||
187 | m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Failed to retrieve inventory skeleton for " + userID + ": " + | ||
188 | response["Message"].AsString()); | ||
189 | return new List<InventoryFolderBase>(0); | ||
190 | } | ||
191 | } | ||
192 | |||
193 | /// <summary> | ||
194 | /// Synchronous inventory fetch. | ||
195 | /// </summary> | ||
196 | /// <param name="userID"></param> | ||
197 | /// <returns></returns> | ||
198 | [Obsolete] | ||
199 | public InventoryCollection GetUserInventory(UUID userID) | ||
200 | { | ||
201 | m_log.Error("[SIMIAN INVENTORY CONNECTOR]: Obsolete GetUserInventory called for " + userID); | ||
202 | |||
203 | InventoryCollection inventory = new InventoryCollection(); | ||
204 | inventory.UserID = userID; | ||
205 | inventory.Folders = new List<InventoryFolderBase>(); | ||
206 | inventory.Items = new List<InventoryItemBase>(); | ||
207 | |||
208 | return inventory; | ||
209 | } | ||
210 | |||
211 | /// <summary> | ||
212 | /// Request the inventory for a user. This is an asynchronous operation that will call the callback when the | ||
213 | /// inventory has been received | ||
214 | /// </summary> | ||
215 | /// <param name="userID"></param> | ||
216 | /// <param name="callback"></param> | ||
217 | [Obsolete] | ||
218 | public void GetUserInventory(UUID userID, InventoryReceiptCallback callback) | ||
219 | { | ||
220 | m_log.Error("[SIMIAN INVENTORY CONNECTOR]: Obsolete GetUserInventory called for " + userID); | ||
221 | callback(new List<InventoryFolderImpl>(0), new List<InventoryItemBase>(0)); | ||
222 | } | ||
223 | |||
224 | /// <summary> | ||
225 | /// Retrieve the root inventory folder for the given user. | ||
226 | /// </summary> | ||
227 | /// <param name="userID"></param> | ||
228 | /// <returns>null if no root folder was found</returns> | ||
229 | public InventoryFolderBase GetRootFolder(UUID userID) | ||
230 | { | ||
231 | NameValueCollection requestArgs = new NameValueCollection | ||
232 | { | ||
233 | { "RequestMethod", "GetInventoryNode" }, | ||
234 | { "ItemID", userID.ToString() }, | ||
235 | { "OwnerID", userID.ToString() }, | ||
236 | { "IncludeFolders", "1" }, | ||
237 | { "IncludeItems", "0" }, | ||
238 | { "ChildrenOnly", "1" } | ||
239 | }; | ||
240 | |||
241 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
242 | if (response["Success"].AsBoolean() && response["Items"] is OSDArray) | ||
243 | { | ||
244 | OSDArray items = (OSDArray)response["Items"]; | ||
245 | List<InventoryFolderBase> folders = GetFoldersFromResponse(items, userID, true); | ||
246 | |||
247 | if (folders.Count > 0) | ||
248 | return folders[0]; | ||
249 | } | ||
250 | |||
251 | return null; | ||
252 | } | ||
253 | |||
254 | /// <summary> | ||
255 | /// Gets the user folder for the given folder-type | ||
256 | /// </summary> | ||
257 | /// <param name="userID"></param> | ||
258 | /// <param name="type"></param> | ||
259 | /// <returns></returns> | ||
260 | public InventoryFolderBase GetFolderForType(UUID userID, AssetType type) | ||
261 | { | ||
262 | string contentType = SLUtil.SLAssetTypeToContentType((int)type); | ||
263 | |||
264 | NameValueCollection requestArgs = new NameValueCollection | ||
265 | { | ||
266 | { "RequestMethod", "GetFolderForType" }, | ||
267 | { "ContentType", contentType }, | ||
268 | { "OwnerID", userID.ToString() } | ||
269 | }; | ||
270 | |||
271 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
272 | if (response["Success"].AsBoolean() && response["Folder"] is OSDMap) | ||
273 | { | ||
274 | OSDMap folder = (OSDMap)response["Folder"]; | ||
275 | |||
276 | return new InventoryFolderBase( | ||
277 | folder["ID"].AsUUID(), | ||
278 | folder["Name"].AsString(), | ||
279 | folder["OwnerID"].AsUUID(), | ||
280 | (short)SLUtil.ContentTypeToSLAssetType(folder["ContentType"].AsString()), | ||
281 | folder["ParentID"].AsUUID(), | ||
282 | (ushort)folder["Version"].AsInteger() | ||
283 | ); | ||
284 | } | ||
285 | else | ||
286 | { | ||
287 | m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Default folder not found for content type " + contentType + ": " + response["Message"].AsString()); | ||
288 | return GetRootFolder(userID); | ||
289 | } | ||
290 | } | ||
291 | |||
292 | /// <summary> | ||
293 | /// Get an item, given by its UUID | ||
294 | /// </summary> | ||
295 | /// <param name="item"></param> | ||
296 | /// <returns></returns> | ||
297 | public InventoryItemBase GetItem(InventoryItemBase item) | ||
298 | { | ||
299 | NameValueCollection requestArgs = new NameValueCollection | ||
300 | { | ||
301 | { "RequestMethod", "GetInventoryNode" }, | ||
302 | { "ItemID", item.ID.ToString() }, | ||
303 | { "OwnerID", item.Owner.ToString() }, | ||
304 | { "IncludeFolders", "1" }, | ||
305 | { "IncludeItems", "1" }, | ||
306 | { "ChildrenOnly", "1" } | ||
307 | }; | ||
308 | |||
309 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
310 | if (response["Success"].AsBoolean() && response["Items"] is OSDArray) | ||
311 | { | ||
312 | List<InventoryItemBase> items = GetItemsFromResponse((OSDArray)response["Items"]); | ||
313 | if (items.Count > 0) | ||
314 | { | ||
315 | // The requested item should be the first in this list, but loop through | ||
316 | // and sanity check just in case | ||
317 | for (int i = 0; i < items.Count; i++) | ||
318 | { | ||
319 | if (items[i].ID == item.ID) | ||
320 | return items[i]; | ||
321 | } | ||
322 | } | ||
323 | } | ||
324 | |||
325 | m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Item " + item.ID + " owned by " + item.Owner + " not found"); | ||
326 | return null; | ||
327 | } | ||
328 | |||
329 | /// <summary> | ||
330 | /// Get a folder, given by its UUID | ||
331 | /// </summary> | ||
332 | /// <param name="folder"></param> | ||
333 | /// <returns></returns> | ||
334 | public InventoryFolderBase GetFolder(InventoryFolderBase folder) | ||
335 | { | ||
336 | NameValueCollection requestArgs = new NameValueCollection | ||
337 | { | ||
338 | { "RequestMethod", "GetInventoryNode" }, | ||
339 | { "ItemID", folder.ID.ToString() }, | ||
340 | { "OwnerID", folder.Owner.ToString() }, | ||
341 | { "IncludeFolders", "1" }, | ||
342 | { "IncludeItems", "0" }, | ||
343 | { "ChildrenOnly", "1" } | ||
344 | }; | ||
345 | |||
346 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
347 | if (response["Success"].AsBoolean() && response["Items"] is OSDArray) | ||
348 | { | ||
349 | OSDArray items = (OSDArray)response["Items"]; | ||
350 | List<InventoryFolderBase> folders = GetFoldersFromResponse(items, folder.ID, true); | ||
351 | |||
352 | if (folders.Count > 0) | ||
353 | return folders[0]; | ||
354 | } | ||
355 | |||
356 | return null; | ||
357 | } | ||
358 | |||
359 | /// <summary> | ||
360 | /// Gets everything (folders and items) inside a folder | ||
361 | /// </summary> | ||
362 | /// <param name="userID"></param> | ||
363 | /// <param name="folderID"></param> | ||
364 | /// <returns></returns> | ||
365 | public InventoryCollection GetFolderContent(UUID userID, UUID folderID) | ||
366 | { | ||
367 | InventoryCollection inventory = new InventoryCollection(); | ||
368 | inventory.UserID = userID; | ||
369 | |||
370 | NameValueCollection requestArgs = new NameValueCollection | ||
371 | { | ||
372 | { "RequestMethod", "GetInventoryNode" }, | ||
373 | { "ItemID", folderID.ToString() }, | ||
374 | { "OwnerID", userID.ToString() }, | ||
375 | { "IncludeFolders", "1" }, | ||
376 | { "IncludeItems", "1" }, | ||
377 | { "ChildrenOnly", "1" } | ||
378 | }; | ||
379 | |||
380 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
381 | if (response["Success"].AsBoolean() && response["Items"] is OSDArray) | ||
382 | { | ||
383 | OSDArray items = (OSDArray)response["Items"]; | ||
384 | |||
385 | inventory.Folders = GetFoldersFromResponse(items, folderID, false); | ||
386 | inventory.Items = GetItemsFromResponse(items); | ||
387 | } | ||
388 | else | ||
389 | { | ||
390 | m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Error fetching folder " + folderID + " content for " + userID + ": " + | ||
391 | response["Message"].AsString()); | ||
392 | inventory.Folders = new List<InventoryFolderBase>(0); | ||
393 | inventory.Items = new List<InventoryItemBase>(0); | ||
394 | } | ||
395 | |||
396 | return inventory; | ||
397 | } | ||
398 | |||
399 | /// <summary> | ||
400 | /// Gets the items inside a folder | ||
401 | /// </summary> | ||
402 | /// <param name="userID"></param> | ||
403 | /// <param name="folderID"></param> | ||
404 | /// <returns></returns> | ||
405 | public List<InventoryItemBase> GetFolderItems(UUID userID, UUID folderID) | ||
406 | { | ||
407 | InventoryCollection inventory = new InventoryCollection(); | ||
408 | inventory.UserID = userID; | ||
409 | |||
410 | NameValueCollection requestArgs = new NameValueCollection | ||
411 | { | ||
412 | { "RequestMethod", "GetInventoryNode" }, | ||
413 | { "ItemID", folderID.ToString() }, | ||
414 | { "OwnerID", userID.ToString() }, | ||
415 | { "IncludeFolders", "0" }, | ||
416 | { "IncludeItems", "1" }, | ||
417 | { "ChildrenOnly", "1" } | ||
418 | }; | ||
419 | |||
420 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
421 | if (response["Success"].AsBoolean() && response["Items"] is OSDArray) | ||
422 | { | ||
423 | OSDArray items = (OSDArray)response["Items"]; | ||
424 | return GetItemsFromResponse(items); | ||
425 | } | ||
426 | else | ||
427 | { | ||
428 | m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Error fetching folder " + folderID + " for " + userID + ": " + | ||
429 | response["Message"].AsString()); | ||
430 | return new List<InventoryItemBase>(0); | ||
431 | } | ||
432 | } | ||
433 | |||
434 | /// <summary> | ||
435 | /// Add a new folder to the user's inventory | ||
436 | /// </summary> | ||
437 | /// <param name="folder"></param> | ||
438 | /// <returns>true if the folder was successfully added</returns> | ||
439 | public bool AddFolder(InventoryFolderBase folder) | ||
440 | { | ||
441 | NameValueCollection requestArgs = new NameValueCollection | ||
442 | { | ||
443 | { "RequestMethod", "AddInventoryFolder" }, | ||
444 | { "FolderID", folder.ID.ToString() }, | ||
445 | { "ParentID", folder.ParentID.ToString() }, | ||
446 | { "OwnerID", folder.Owner.ToString() }, | ||
447 | { "Name", folder.Name }, | ||
448 | { "ContentType", SLUtil.SLAssetTypeToContentType(folder.Type) } | ||
449 | }; | ||
450 | |||
451 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
452 | bool success = response["Success"].AsBoolean(); | ||
453 | |||
454 | if (!success) | ||
455 | { | ||
456 | m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Error creating folder " + folder.Name + " for " + folder.Owner + ": " + | ||
457 | response["Message"].AsString()); | ||
458 | } | ||
459 | |||
460 | return success; | ||
461 | } | ||
462 | |||
463 | /// <summary> | ||
464 | /// Update a folder in the user's inventory | ||
465 | /// </summary> | ||
466 | /// <param name="folder"></param> | ||
467 | /// <returns>true if the folder was successfully updated</returns> | ||
468 | public bool UpdateFolder(InventoryFolderBase folder) | ||
469 | { | ||
470 | return AddFolder(folder); | ||
471 | } | ||
472 | |||
473 | /// <summary> | ||
474 | /// Move an inventory folder to a new location | ||
475 | /// </summary> | ||
476 | /// <param name="folder">A folder containing the details of the new location</param> | ||
477 | /// <returns>true if the folder was successfully moved</returns> | ||
478 | public bool MoveFolder(InventoryFolderBase folder) | ||
479 | { | ||
480 | return AddFolder(folder); | ||
481 | } | ||
482 | |||
483 | /// <summary> | ||
484 | /// Delete an item from the user's inventory | ||
485 | /// </summary> | ||
486 | /// <param name="item"></param> | ||
487 | /// <returns>true if the item was successfully deleted</returns> | ||
488 | //bool DeleteItem(InventoryItemBase item); | ||
489 | public bool DeleteFolders(UUID userID, List<UUID> folderIDs) | ||
490 | { | ||
491 | return DeleteItems(userID, folderIDs); | ||
492 | } | ||
493 | |||
494 | /// <summary> | ||
495 | /// Delete an item from the user's inventory | ||
496 | /// </summary> | ||
497 | /// <param name="item"></param> | ||
498 | /// <returns>true if the item was successfully deleted</returns> | ||
499 | public bool DeleteItems(UUID userID, List<UUID> itemIDs) | ||
500 | { | ||
501 | // TODO: RemoveInventoryNode should be replaced with RemoveInventoryNodes | ||
502 | bool allSuccess = true; | ||
503 | |||
504 | for (int i = 0; i < itemIDs.Count; i++) | ||
505 | { | ||
506 | UUID itemID = itemIDs[i]; | ||
507 | |||
508 | NameValueCollection requestArgs = new NameValueCollection | ||
509 | { | ||
510 | { "RequestMethod", "RemoveInventoryNode" }, | ||
511 | { "OwnerID", userID.ToString() }, | ||
512 | { "ItemID", itemID.ToString() } | ||
513 | }; | ||
514 | |||
515 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
516 | bool success = response["Success"].AsBoolean(); | ||
517 | |||
518 | if (!success) | ||
519 | { | ||
520 | m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Error removing item " + itemID + " for " + userID + ": " + | ||
521 | response["Message"].AsString()); | ||
522 | allSuccess = false; | ||
523 | } | ||
524 | } | ||
525 | |||
526 | return allSuccess; | ||
527 | } | ||
528 | |||
529 | /// <summary> | ||
530 | /// Purge an inventory folder of all its items and subfolders. | ||
531 | /// </summary> | ||
532 | /// <param name="folder"></param> | ||
533 | /// <returns>true if the folder was successfully purged</returns> | ||
534 | public bool PurgeFolder(InventoryFolderBase folder) | ||
535 | { | ||
536 | NameValueCollection requestArgs = new NameValueCollection | ||
537 | { | ||
538 | { "RequestMethod", "PurgeInventoryFolder" }, | ||
539 | { "OwnerID", folder.Owner.ToString() }, | ||
540 | { "FolderID", folder.ID.ToString() } | ||
541 | }; | ||
542 | |||
543 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
544 | bool success = response["Success"].AsBoolean(); | ||
545 | |||
546 | if (!success) | ||
547 | { | ||
548 | m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Error purging folder " + folder.ID + " for " + folder.Owner + ": " + | ||
549 | response["Message"].AsString()); | ||
550 | } | ||
551 | |||
552 | return success; | ||
553 | } | ||
554 | |||
555 | /// <summary> | ||
556 | /// Add a new item to the user's inventory | ||
557 | /// </summary> | ||
558 | /// <param name="item"></param> | ||
559 | /// <returns>true if the item was successfully added</returns> | ||
560 | public bool AddItem(InventoryItemBase item) | ||
561 | { | ||
562 | // A folder of UUID.Zero means we need to find the most appropriate home for this item | ||
563 | if (item.Folder == UUID.Zero) | ||
564 | { | ||
565 | InventoryFolderBase folder = GetFolderForType(item.Owner, (AssetType)item.AssetType); | ||
566 | if (folder != null && folder.ID != UUID.Zero) | ||
567 | item.Folder = folder.ID; | ||
568 | else | ||
569 | item.Folder = item.Owner; // Root folder | ||
570 | } | ||
571 | |||
572 | if ((AssetType)item.AssetType == AssetType.Gesture) | ||
573 | UpdateGesture(item.Owner, item.ID, item.Flags == 1); | ||
574 | |||
575 | if (item.BasePermissions == 0) | ||
576 | m_log.WarnFormat("[SIMIAN INVENTORY CONNECTOR]: Adding inventory item {0} ({1}) with no base permissions", item.Name, item.ID); | ||
577 | |||
578 | OSDMap permissions = new OSDMap | ||
579 | { | ||
580 | { "BaseMask", OSD.FromInteger(item.BasePermissions) }, | ||
581 | { "EveryoneMask", OSD.FromInteger(item.EveryOnePermissions) }, | ||
582 | { "GroupMask", OSD.FromInteger(item.GroupPermissions) }, | ||
583 | { "NextOwnerMask", OSD.FromInteger(item.NextPermissions) }, | ||
584 | { "OwnerMask", OSD.FromInteger(item.CurrentPermissions) } | ||
585 | }; | ||
586 | |||
587 | OSDMap extraData = new OSDMap() | ||
588 | { | ||
589 | { "Flags", OSD.FromInteger(item.Flags) }, | ||
590 | { "GroupID", OSD.FromUUID(item.GroupID) }, | ||
591 | { "GroupOwned", OSD.FromBoolean(item.GroupOwned) }, | ||
592 | { "SalePrice", OSD.FromInteger(item.SalePrice) }, | ||
593 | { "SaleType", OSD.FromInteger(item.SaleType) }, | ||
594 | { "Permissions", permissions } | ||
595 | }; | ||
596 | |||
597 | // Add different asset type only if it differs from inventory type | ||
598 | // (needed for links) | ||
599 | string invContentType = SLUtil.SLInvTypeToContentType(item.InvType); | ||
600 | string assetContentType = SLUtil.SLAssetTypeToContentType(item.AssetType); | ||
601 | |||
602 | if (invContentType != assetContentType) | ||
603 | extraData["LinkedItemType"] = OSD.FromString(assetContentType); | ||
604 | |||
605 | NameValueCollection requestArgs = new NameValueCollection | ||
606 | { | ||
607 | { "RequestMethod", "AddInventoryItem" }, | ||
608 | { "ItemID", item.ID.ToString() }, | ||
609 | { "AssetID", item.AssetID.ToString() }, | ||
610 | { "ParentID", item.Folder.ToString() }, | ||
611 | { "OwnerID", item.Owner.ToString() }, | ||
612 | { "Name", item.Name }, | ||
613 | { "Description", item.Description }, | ||
614 | { "CreatorID", item.CreatorId }, | ||
615 | { "CreatorData", item.CreatorData }, | ||
616 | { "ContentType", invContentType }, | ||
617 | { "ExtraData", OSDParser.SerializeJsonString(extraData) } | ||
618 | }; | ||
619 | |||
620 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
621 | bool success = response["Success"].AsBoolean(); | ||
622 | |||
623 | if (!success) | ||
624 | { | ||
625 | m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Error creating item " + item.Name + " for " + item.Owner + ": " + | ||
626 | response["Message"].AsString()); | ||
627 | } | ||
628 | |||
629 | return success; | ||
630 | } | ||
631 | |||
632 | /// <summary> | ||
633 | /// Update an item in the user's inventory | ||
634 | /// </summary> | ||
635 | /// <param name="item"></param> | ||
636 | /// <returns>true if the item was successfully updated</returns> | ||
637 | public bool UpdateItem(InventoryItemBase item) | ||
638 | { | ||
639 | if (item.AssetID != UUID.Zero) | ||
640 | { | ||
641 | return AddItem(item); | ||
642 | } | ||
643 | else | ||
644 | { | ||
645 | // This is actually a folder update | ||
646 | InventoryFolderBase folder = new InventoryFolderBase(item.ID, item.Name, item.Owner, (short)item.AssetType, item.Folder, 0); | ||
647 | return UpdateFolder(folder); | ||
648 | } | ||
649 | } | ||
650 | |||
651 | public bool MoveItems(UUID ownerID, List<InventoryItemBase> items) | ||
652 | { | ||
653 | bool success = true; | ||
654 | |||
655 | while (items.Count > 0) | ||
656 | { | ||
657 | List<InventoryItemBase> currentItems = new List<InventoryItemBase>(); | ||
658 | UUID destFolderID = items[0].Folder; | ||
659 | |||
660 | // Find all of the items being moved to the current destination folder | ||
661 | for (int i = 0; i < items.Count; i++) | ||
662 | { | ||
663 | InventoryItemBase item = items[i]; | ||
664 | if (item.Folder == destFolderID) | ||
665 | currentItems.Add(item); | ||
666 | } | ||
667 | |||
668 | // Do the inventory move for the current items | ||
669 | success &= MoveItems(ownerID, items, destFolderID); | ||
670 | |||
671 | // Remove the processed items from the list | ||
672 | for (int i = 0; i < currentItems.Count; i++) | ||
673 | items.Remove(currentItems[i]); | ||
674 | } | ||
675 | |||
676 | return success; | ||
677 | } | ||
678 | |||
679 | /// <summary> | ||
680 | /// Does the given user have an inventory structure? | ||
681 | /// </summary> | ||
682 | /// <param name="userID"></param> | ||
683 | /// <returns></returns> | ||
684 | public bool HasInventoryForUser(UUID userID) | ||
685 | { | ||
686 | return GetRootFolder(userID) != null; | ||
687 | } | ||
688 | |||
689 | /// <summary> | ||
690 | /// Get the active gestures of the agent. | ||
691 | /// </summary> | ||
692 | /// <param name="userID"></param> | ||
693 | /// <returns></returns> | ||
694 | public List<InventoryItemBase> GetActiveGestures(UUID userID) | ||
695 | { | ||
696 | OSDArray items = FetchGestures(userID); | ||
697 | |||
698 | string[] itemIDs = new string[items.Count]; | ||
699 | for (int i = 0; i < items.Count; i++) | ||
700 | itemIDs[i] = items[i].AsUUID().ToString(); | ||
701 | |||
702 | // NameValueCollection requestArgs = new NameValueCollection | ||
703 | // { | ||
704 | // { "RequestMethod", "GetInventoryNodes" }, | ||
705 | // { "OwnerID", userID.ToString() }, | ||
706 | // { "Items", String.Join(",", itemIDs) } | ||
707 | // }; | ||
708 | |||
709 | // FIXME: Implement this in SimianGrid | ||
710 | return new List<InventoryItemBase>(0); | ||
711 | } | ||
712 | |||
713 | /// <summary> | ||
714 | /// Get the union of permissions of all inventory items | ||
715 | /// that hold the given assetID. | ||
716 | /// </summary> | ||
717 | /// <param name="userID"></param> | ||
718 | /// <param name="assetID"></param> | ||
719 | /// <returns>The permissions or 0 if no such asset is found in | ||
720 | /// the user's inventory</returns> | ||
721 | public int GetAssetPermissions(UUID userID, UUID assetID) | ||
722 | { | ||
723 | // NameValueCollection requestArgs = new NameValueCollection | ||
724 | // { | ||
725 | // { "RequestMethod", "GetInventoryNodes" }, | ||
726 | // { "OwnerID", userID.ToString() }, | ||
727 | // { "AssetID", assetID.ToString() } | ||
728 | // }; | ||
729 | |||
730 | // FIXME: Implement this in SimianGrid | ||
731 | return (int)PermissionMask.All; | ||
732 | } | ||
733 | |||
734 | private List<InventoryFolderBase> GetFoldersFromResponse(OSDArray items, UUID baseFolder, bool includeBaseFolder) | ||
735 | { | ||
736 | List<InventoryFolderBase> invFolders = new List<InventoryFolderBase>(items.Count); | ||
737 | |||
738 | for (int i = 0; i < items.Count; i++) | ||
739 | { | ||
740 | OSDMap item = items[i] as OSDMap; | ||
741 | |||
742 | if (item != null && item["Type"].AsString() == "Folder") | ||
743 | { | ||
744 | UUID folderID = item["ID"].AsUUID(); | ||
745 | |||
746 | if (folderID == baseFolder && !includeBaseFolder) | ||
747 | continue; | ||
748 | |||
749 | invFolders.Add(new InventoryFolderBase( | ||
750 | folderID, | ||
751 | item["Name"].AsString(), | ||
752 | item["OwnerID"].AsUUID(), | ||
753 | (short)SLUtil.ContentTypeToSLAssetType(item["ContentType"].AsString()), | ||
754 | item["ParentID"].AsUUID(), | ||
755 | (ushort)item["Version"].AsInteger() | ||
756 | )); | ||
757 | } | ||
758 | } | ||
759 | |||
760 | // m_log.Debug("[SIMIAN INVENTORY CONNECTOR]: Parsed " + invFolders.Count + " folders from SimianGrid response"); | ||
761 | return invFolders; | ||
762 | } | ||
763 | |||
764 | private List<InventoryItemBase> GetItemsFromResponse(OSDArray items) | ||
765 | { | ||
766 | List<InventoryItemBase> invItems = new List<InventoryItemBase>(items.Count); | ||
767 | |||
768 | for (int i = 0; i < items.Count; i++) | ||
769 | { | ||
770 | OSDMap item = items[i] as OSDMap; | ||
771 | |||
772 | if (item != null && item["Type"].AsString() == "Item") | ||
773 | { | ||
774 | InventoryItemBase invItem = new InventoryItemBase(); | ||
775 | |||
776 | invItem.AssetID = item["AssetID"].AsUUID(); | ||
777 | invItem.AssetType = SLUtil.ContentTypeToSLAssetType(item["ContentType"].AsString()); | ||
778 | invItem.CreationDate = item["CreationDate"].AsInteger(); | ||
779 | invItem.CreatorId = item["CreatorID"].AsString(); | ||
780 | invItem.CreatorData = item["CreatorData"].AsString(); | ||
781 | invItem.CreatorIdAsUuid = item["CreatorID"].AsUUID(); | ||
782 | invItem.Description = item["Description"].AsString(); | ||
783 | invItem.Folder = item["ParentID"].AsUUID(); | ||
784 | invItem.ID = item["ID"].AsUUID(); | ||
785 | invItem.InvType = SLUtil.ContentTypeToSLInvType(item["ContentType"].AsString()); | ||
786 | invItem.Name = item["Name"].AsString(); | ||
787 | invItem.Owner = item["OwnerID"].AsUUID(); | ||
788 | |||
789 | OSDMap extraData = item["ExtraData"] as OSDMap; | ||
790 | if (extraData != null && extraData.Count > 0) | ||
791 | { | ||
792 | invItem.Flags = extraData["Flags"].AsUInteger(); | ||
793 | invItem.GroupID = extraData["GroupID"].AsUUID(); | ||
794 | invItem.GroupOwned = extraData["GroupOwned"].AsBoolean(); | ||
795 | invItem.SalePrice = extraData["SalePrice"].AsInteger(); | ||
796 | invItem.SaleType = (byte)extraData["SaleType"].AsInteger(); | ||
797 | |||
798 | OSDMap perms = extraData["Permissions"] as OSDMap; | ||
799 | if (perms != null) | ||
800 | { | ||
801 | invItem.BasePermissions = perms["BaseMask"].AsUInteger(); | ||
802 | invItem.CurrentPermissions = perms["OwnerMask"].AsUInteger(); | ||
803 | invItem.EveryOnePermissions = perms["EveryoneMask"].AsUInteger(); | ||
804 | invItem.GroupPermissions = perms["GroupMask"].AsUInteger(); | ||
805 | invItem.NextPermissions = perms["NextOwnerMask"].AsUInteger(); | ||
806 | } | ||
807 | |||
808 | if (extraData.ContainsKey("LinkedItemType")) | ||
809 | invItem.AssetType = SLUtil.ContentTypeToSLAssetType(extraData["LinkedItemType"].AsString()); | ||
810 | } | ||
811 | |||
812 | if (invItem.BasePermissions == 0) | ||
813 | { | ||
814 | m_log.InfoFormat("[SIMIAN INVENTORY CONNECTOR]: Forcing item permissions to full for item {0} ({1})", | ||
815 | invItem.Name, invItem.ID); | ||
816 | invItem.BasePermissions = (uint)PermissionMask.All; | ||
817 | invItem.CurrentPermissions = (uint)PermissionMask.All; | ||
818 | invItem.EveryOnePermissions = (uint)PermissionMask.All; | ||
819 | invItem.GroupPermissions = (uint)PermissionMask.All; | ||
820 | invItem.NextPermissions = (uint)PermissionMask.All; | ||
821 | } | ||
822 | |||
823 | invItems.Add(invItem); | ||
824 | } | ||
825 | } | ||
826 | |||
827 | // m_log.Debug("[SIMIAN INVENTORY CONNECTOR]: Parsed " + invItems.Count + " items from SimianGrid response"); | ||
828 | return invItems; | ||
829 | } | ||
830 | |||
831 | private bool MoveItems(UUID ownerID, List<InventoryItemBase> items, UUID destFolderID) | ||
832 | { | ||
833 | string[] itemIDs = new string[items.Count]; | ||
834 | for (int i = 0; i < items.Count; i++) | ||
835 | itemIDs[i] = items[i].ID.ToString(); | ||
836 | |||
837 | NameValueCollection requestArgs = new NameValueCollection | ||
838 | { | ||
839 | { "RequestMethod", "MoveInventoryNodes" }, | ||
840 | { "OwnerID", ownerID.ToString() }, | ||
841 | { "FolderID", destFolderID.ToString() }, | ||
842 | { "Items", String.Join(",", itemIDs) } | ||
843 | }; | ||
844 | |||
845 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
846 | bool success = response["Success"].AsBoolean(); | ||
847 | |||
848 | if (!success) | ||
849 | { | ||
850 | m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Failed to move " + items.Count + " items to " + | ||
851 | destFolderID + ": " + response["Message"].AsString()); | ||
852 | } | ||
853 | |||
854 | return success; | ||
855 | } | ||
856 | |||
857 | private void UpdateGesture(UUID userID, UUID itemID, bool enabled) | ||
858 | { | ||
859 | OSDArray gestures = FetchGestures(userID); | ||
860 | OSDArray newGestures = new OSDArray(); | ||
861 | |||
862 | for (int i = 0; i < gestures.Count; i++) | ||
863 | { | ||
864 | UUID gesture = gestures[i].AsUUID(); | ||
865 | if (gesture != itemID) | ||
866 | newGestures.Add(OSD.FromUUID(gesture)); | ||
867 | } | ||
868 | |||
869 | if (enabled) | ||
870 | newGestures.Add(OSD.FromUUID(itemID)); | ||
871 | |||
872 | SaveGestures(userID, newGestures); | ||
873 | } | ||
874 | |||
875 | private OSDArray FetchGestures(UUID userID) | ||
876 | { | ||
877 | NameValueCollection requestArgs = new NameValueCollection | ||
878 | { | ||
879 | { "RequestMethod", "GetUser" }, | ||
880 | { "UserID", userID.ToString() } | ||
881 | }; | ||
882 | |||
883 | OSDMap response = WebUtil.PostToService(m_userServerUrl, requestArgs); | ||
884 | if (response["Success"].AsBoolean()) | ||
885 | { | ||
886 | OSDMap user = response["User"] as OSDMap; | ||
887 | if (user != null && response.ContainsKey("Gestures")) | ||
888 | { | ||
889 | OSD gestures = OSDParser.DeserializeJson(response["Gestures"].AsString()); | ||
890 | if (gestures != null && gestures is OSDArray) | ||
891 | return (OSDArray)gestures; | ||
892 | else | ||
893 | m_log.Error("[SIMIAN INVENTORY CONNECTOR]: Unrecognized active gestures data for " + userID); | ||
894 | } | ||
895 | } | ||
896 | else | ||
897 | { | ||
898 | m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Failed to fetch active gestures for " + userID + ": " + | ||
899 | response["Message"].AsString()); | ||
900 | } | ||
901 | |||
902 | return new OSDArray(); | ||
903 | } | ||
904 | |||
905 | private void SaveGestures(UUID userID, OSDArray gestures) | ||
906 | { | ||
907 | NameValueCollection requestArgs = new NameValueCollection | ||
908 | { | ||
909 | { "RequestMethod", "AddUserData" }, | ||
910 | { "UserID", userID.ToString() }, | ||
911 | { "Gestures", OSDParser.SerializeJsonString(gestures) } | ||
912 | }; | ||
913 | |||
914 | OSDMap response = WebUtil.PostToService(m_userServerUrl, requestArgs); | ||
915 | if (!response["Success"].AsBoolean()) | ||
916 | { | ||
917 | m_log.Warn("[SIMIAN INVENTORY CONNECTOR]: Failed to save active gestures for " + userID + ": " + | ||
918 | response["Message"].AsString()); | ||
919 | } | ||
920 | } | ||
921 | } | ||
922 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs new file mode 100644 index 0000000..678f738 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianPresenceServiceConnector.cs | |||
@@ -0,0 +1,477 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Reflection; | ||
32 | using log4net; | ||
33 | using Mono.Addins; | ||
34 | using Nini.Config; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Region.Framework.Interfaces; | ||
37 | using OpenSim.Region.Framework.Scenes; | ||
38 | using OpenSim.Services.Interfaces; | ||
39 | using OpenMetaverse; | ||
40 | using OpenMetaverse.StructuredData; | ||
41 | |||
42 | using PresenceInfo = OpenSim.Services.Interfaces.PresenceInfo; | ||
43 | |||
44 | namespace OpenSim.Services.Connectors.SimianGrid | ||
45 | { | ||
46 | /// <summary> | ||
47 | /// Connects avatar presence information (for tracking current location and | ||
48 | /// message routing) to the SimianGrid backend | ||
49 | /// </summary> | ||
50 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
51 | public class SimianPresenceServiceConnector : IPresenceService, IGridUserService, ISharedRegionModule | ||
52 | { | ||
53 | private static readonly ILog m_log = | ||
54 | LogManager.GetLogger( | ||
55 | MethodBase.GetCurrentMethod().DeclaringType); | ||
56 | |||
57 | private string m_serverUrl = String.Empty; | ||
58 | private SimianActivityDetector m_activityDetector; | ||
59 | private bool m_Enabled = false; | ||
60 | |||
61 | #region ISharedRegionModule | ||
62 | |||
63 | public Type ReplaceableInterface { get { return null; } } | ||
64 | public void RegionLoaded(Scene scene) { } | ||
65 | public void PostInitialise() { } | ||
66 | public void Close() { } | ||
67 | |||
68 | public SimianPresenceServiceConnector() { m_activityDetector = new SimianActivityDetector(this); } | ||
69 | public string Name { get { return "SimianPresenceServiceConnector"; } } | ||
70 | public void AddRegion(Scene scene) | ||
71 | { | ||
72 | if (m_Enabled) | ||
73 | { | ||
74 | scene.RegisterModuleInterface<IPresenceService>(this); | ||
75 | scene.RegisterModuleInterface<IGridUserService>(this); | ||
76 | |||
77 | m_activityDetector.AddRegion(scene); | ||
78 | |||
79 | LogoutRegionAgents(scene.RegionInfo.RegionID); | ||
80 | } | ||
81 | } | ||
82 | public void RemoveRegion(Scene scene) | ||
83 | { | ||
84 | if (m_Enabled) | ||
85 | { | ||
86 | scene.UnregisterModuleInterface<IPresenceService>(this); | ||
87 | scene.UnregisterModuleInterface<IGridUserService>(this); | ||
88 | |||
89 | m_activityDetector.RemoveRegion(scene); | ||
90 | |||
91 | LogoutRegionAgents(scene.RegionInfo.RegionID); | ||
92 | } | ||
93 | } | ||
94 | |||
95 | #endregion ISharedRegionModule | ||
96 | |||
97 | public SimianPresenceServiceConnector(IConfigSource source) | ||
98 | { | ||
99 | CommonInit(source); | ||
100 | } | ||
101 | |||
102 | public void Initialise(IConfigSource source) | ||
103 | { | ||
104 | IConfig moduleConfig = source.Configs["Modules"]; | ||
105 | if (moduleConfig != null) | ||
106 | { | ||
107 | string name = moduleConfig.GetString("PresenceServices", ""); | ||
108 | if (name == Name) | ||
109 | CommonInit(source); | ||
110 | } | ||
111 | } | ||
112 | |||
113 | private void CommonInit(IConfigSource source) | ||
114 | { | ||
115 | IConfig gridConfig = source.Configs["PresenceService"]; | ||
116 | if (gridConfig != null) | ||
117 | { | ||
118 | string serviceUrl = gridConfig.GetString("PresenceServerURI"); | ||
119 | if (!String.IsNullOrEmpty(serviceUrl)) | ||
120 | { | ||
121 | if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("=")) | ||
122 | serviceUrl = serviceUrl + '/'; | ||
123 | m_serverUrl = serviceUrl; | ||
124 | m_Enabled = true; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | if (String.IsNullOrEmpty(m_serverUrl)) | ||
129 | m_log.Info("[SIMIAN PRESENCE CONNECTOR]: No PresenceServerURI specified, disabling connector"); | ||
130 | } | ||
131 | |||
132 | #region IPresenceService | ||
133 | |||
134 | public bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID) | ||
135 | { | ||
136 | m_log.ErrorFormat("[SIMIAN PRESENCE CONNECTOR]: Login requested, UserID={0}, SessionID={1}, SecureSessionID={2}", | ||
137 | userID, sessionID, secureSessionID); | ||
138 | |||
139 | NameValueCollection requestArgs = new NameValueCollection | ||
140 | { | ||
141 | { "RequestMethod", "AddSession" }, | ||
142 | { "UserID", userID.ToString() } | ||
143 | }; | ||
144 | if (sessionID != UUID.Zero) | ||
145 | { | ||
146 | requestArgs["SessionID"] = sessionID.ToString(); | ||
147 | requestArgs["SecureSessionID"] = secureSessionID.ToString(); | ||
148 | } | ||
149 | |||
150 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
151 | bool success = response["Success"].AsBoolean(); | ||
152 | |||
153 | if (!success) | ||
154 | m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to login agent " + userID + ": " + response["Message"].AsString()); | ||
155 | |||
156 | return success; | ||
157 | } | ||
158 | |||
159 | public bool LogoutAgent(UUID sessionID) | ||
160 | { | ||
161 | // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for agent with sessionID " + sessionID); | ||
162 | |||
163 | NameValueCollection requestArgs = new NameValueCollection | ||
164 | { | ||
165 | { "RequestMethod", "RemoveSession" }, | ||
166 | { "SessionID", sessionID.ToString() } | ||
167 | }; | ||
168 | |||
169 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
170 | bool success = response["Success"].AsBoolean(); | ||
171 | |||
172 | if (!success) | ||
173 | m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to logout agent with sessionID " + sessionID + ": " + response["Message"].AsString()); | ||
174 | |||
175 | return success; | ||
176 | } | ||
177 | |||
178 | public bool LogoutRegionAgents(UUID regionID) | ||
179 | { | ||
180 | // m_log.InfoFormat("[SIMIAN PRESENCE CONNECTOR]: Logout requested for all agents in region " + regionID); | ||
181 | |||
182 | NameValueCollection requestArgs = new NameValueCollection | ||
183 | { | ||
184 | { "RequestMethod", "RemoveSessions" }, | ||
185 | { "SceneID", regionID.ToString() } | ||
186 | }; | ||
187 | |||
188 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
189 | bool success = response["Success"].AsBoolean(); | ||
190 | |||
191 | if (!success) | ||
192 | m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to logout agents from region " + regionID + ": " + response["Message"].AsString()); | ||
193 | |||
194 | return success; | ||
195 | } | ||
196 | |||
197 | public bool ReportAgent(UUID sessionID, UUID regionID) | ||
198 | { | ||
199 | // Not needed for SimianGrid | ||
200 | return true; | ||
201 | } | ||
202 | |||
203 | public PresenceInfo GetAgent(UUID sessionID) | ||
204 | { | ||
205 | // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent with sessionID " + sessionID); | ||
206 | |||
207 | NameValueCollection requestArgs = new NameValueCollection | ||
208 | { | ||
209 | { "RequestMethod", "GetSession" }, | ||
210 | { "SessionID", sessionID.ToString() } | ||
211 | }; | ||
212 | |||
213 | OSDMap sessionResponse = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
214 | if (sessionResponse["Success"].AsBoolean()) | ||
215 | { | ||
216 | UUID userID = sessionResponse["UserID"].AsUUID(); | ||
217 | m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); | ||
218 | |||
219 | requestArgs = new NameValueCollection | ||
220 | { | ||
221 | { "RequestMethod", "GetUser" }, | ||
222 | { "UserID", userID.ToString() } | ||
223 | }; | ||
224 | |||
225 | OSDMap userResponse = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
226 | if (userResponse["Success"].AsBoolean()) | ||
227 | return ResponseToPresenceInfo(sessionResponse, userResponse); | ||
228 | else | ||
229 | m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + userResponse["Message"].AsString()); | ||
230 | } | ||
231 | else | ||
232 | { | ||
233 | m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve session " + sessionID + ": " + sessionResponse["Message"].AsString()); | ||
234 | } | ||
235 | |||
236 | return null; | ||
237 | } | ||
238 | |||
239 | public PresenceInfo[] GetAgents(string[] userIDs) | ||
240 | { | ||
241 | List<PresenceInfo> presences = new List<PresenceInfo>(userIDs.Length); | ||
242 | |||
243 | for (int i = 0; i < userIDs.Length; i++) | ||
244 | { | ||
245 | UUID userID; | ||
246 | if (UUID.TryParse(userIDs[i], out userID) && userID != UUID.Zero) | ||
247 | presences.AddRange(GetSessions(userID)); | ||
248 | } | ||
249 | |||
250 | return presences.ToArray(); | ||
251 | } | ||
252 | |||
253 | #endregion IPresenceService | ||
254 | |||
255 | #region IGridUserService | ||
256 | |||
257 | public GridUserInfo LoggedIn(string userID) | ||
258 | { | ||
259 | // Never implemented at the sim | ||
260 | return null; | ||
261 | } | ||
262 | |||
263 | public bool LoggedOut(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) | ||
264 | { | ||
265 | // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Logging out user " + userID); | ||
266 | |||
267 | // Remove the session to mark this user offline | ||
268 | if (!LogoutAgent(sessionID)) | ||
269 | return false; | ||
270 | |||
271 | // Save our last position as user data | ||
272 | NameValueCollection requestArgs = new NameValueCollection | ||
273 | { | ||
274 | { "RequestMethod", "AddUserData" }, | ||
275 | { "UserID", userID.ToString() }, | ||
276 | { "LastLocation", SerializeLocation(regionID, lastPosition, lastLookAt) } | ||
277 | }; | ||
278 | |||
279 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
280 | bool success = response["Success"].AsBoolean(); | ||
281 | |||
282 | if (!success) | ||
283 | m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to set last location for " + userID + ": " + response["Message"].AsString()); | ||
284 | |||
285 | return success; | ||
286 | } | ||
287 | |||
288 | public bool SetHome(string userID, UUID regionID, Vector3 position, Vector3 lookAt) | ||
289 | { | ||
290 | // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Setting home location for user " + userID); | ||
291 | |||
292 | NameValueCollection requestArgs = new NameValueCollection | ||
293 | { | ||
294 | { "RequestMethod", "AddUserData" }, | ||
295 | { "UserID", userID.ToString() }, | ||
296 | { "HomeLocation", SerializeLocation(regionID, position, lookAt) } | ||
297 | }; | ||
298 | |||
299 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
300 | bool success = response["Success"].AsBoolean(); | ||
301 | |||
302 | if (!success) | ||
303 | m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to set home location for " + userID + ": " + response["Message"].AsString()); | ||
304 | |||
305 | return success; | ||
306 | } | ||
307 | |||
308 | public bool SetLastPosition(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) | ||
309 | { | ||
310 | return UpdateSession(sessionID, regionID, lastPosition, lastLookAt); | ||
311 | } | ||
312 | |||
313 | public GridUserInfo GetGridUserInfo(string user) | ||
314 | { | ||
315 | // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting session data for agent " + user); | ||
316 | |||
317 | UUID userID = new UUID(user); | ||
318 | // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); | ||
319 | |||
320 | NameValueCollection requestArgs = new NameValueCollection | ||
321 | { | ||
322 | { "RequestMethod", "GetUser" }, | ||
323 | { "UserID", userID.ToString() } | ||
324 | }; | ||
325 | |||
326 | OSDMap userResponse = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
327 | if (userResponse["Success"].AsBoolean()) | ||
328 | return ResponseToGridUserInfo(userResponse); | ||
329 | else | ||
330 | m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + userResponse["Message"].AsString()); | ||
331 | |||
332 | return null; | ||
333 | } | ||
334 | |||
335 | #endregion | ||
336 | |||
337 | #region Helpers | ||
338 | |||
339 | private OSDMap GetUserData(UUID userID) | ||
340 | { | ||
341 | // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting user data for " + userID); | ||
342 | |||
343 | NameValueCollection requestArgs = new NameValueCollection | ||
344 | { | ||
345 | { "RequestMethod", "GetUser" }, | ||
346 | { "UserID", userID.ToString() } | ||
347 | }; | ||
348 | |||
349 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
350 | if (response["Success"].AsBoolean() && response["User"] is OSDMap) | ||
351 | return response; | ||
352 | else | ||
353 | m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to retrieve user data for " + userID + ": " + response["Message"].AsString()); | ||
354 | |||
355 | return null; | ||
356 | } | ||
357 | |||
358 | private List<PresenceInfo> GetSessions(UUID userID) | ||
359 | { | ||
360 | List<PresenceInfo> presences = new List<PresenceInfo>(1); | ||
361 | |||
362 | OSDMap userResponse = GetUserData(userID); | ||
363 | if (userResponse != null) | ||
364 | { | ||
365 | // m_log.DebugFormat("[SIMIAN PRESENCE CONNECTOR]: Requesting sessions for " + userID); | ||
366 | |||
367 | NameValueCollection requestArgs = new NameValueCollection | ||
368 | { | ||
369 | { "RequestMethod", "GetSession" }, | ||
370 | { "UserID", userID.ToString() } | ||
371 | }; | ||
372 | |||
373 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
374 | if (response["Success"].AsBoolean()) | ||
375 | { | ||
376 | PresenceInfo presence = ResponseToPresenceInfo(response, userResponse); | ||
377 | if (presence != null) | ||
378 | presences.Add(presence); | ||
379 | } | ||
380 | // else | ||
381 | // { | ||
382 | // m_log.Debug("[SIMIAN PRESENCE CONNECTOR]: No session returned for " + userID + ": " + response["Message"].AsString()); | ||
383 | // } | ||
384 | } | ||
385 | |||
386 | return presences; | ||
387 | } | ||
388 | |||
389 | private bool UpdateSession(UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) | ||
390 | { | ||
391 | // Save our current location as session data | ||
392 | NameValueCollection requestArgs = new NameValueCollection | ||
393 | { | ||
394 | { "RequestMethod", "UpdateSession" }, | ||
395 | { "SessionID", sessionID.ToString() }, | ||
396 | { "SceneID", regionID.ToString() }, | ||
397 | { "ScenePosition", lastPosition.ToString() }, | ||
398 | { "SceneLookAt", lastLookAt.ToString() } | ||
399 | }; | ||
400 | |||
401 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
402 | bool success = response["Success"].AsBoolean(); | ||
403 | |||
404 | if (!success) | ||
405 | m_log.Warn("[SIMIAN PRESENCE CONNECTOR]: Failed to update agent session " + sessionID + ": " + response["Message"].AsString()); | ||
406 | |||
407 | return success; | ||
408 | } | ||
409 | |||
410 | private PresenceInfo ResponseToPresenceInfo(OSDMap sessionResponse, OSDMap userResponse) | ||
411 | { | ||
412 | if (sessionResponse == null) | ||
413 | return null; | ||
414 | |||
415 | PresenceInfo info = new PresenceInfo(); | ||
416 | |||
417 | info.UserID = sessionResponse["UserID"].AsUUID().ToString(); | ||
418 | info.RegionID = sessionResponse["SceneID"].AsUUID(); | ||
419 | |||
420 | return info; | ||
421 | } | ||
422 | |||
423 | private GridUserInfo ResponseToGridUserInfo(OSDMap userResponse) | ||
424 | { | ||
425 | if (userResponse != null && userResponse["User"] is OSDMap) | ||
426 | { | ||
427 | GridUserInfo info = new GridUserInfo(); | ||
428 | |||
429 | info.Online = true; | ||
430 | info.UserID = userResponse["UserID"].AsUUID().ToString(); | ||
431 | info.LastRegionID = userResponse["SceneID"].AsUUID(); | ||
432 | info.LastPosition = userResponse["ScenePosition"].AsVector3(); | ||
433 | info.LastLookAt = userResponse["SceneLookAt"].AsVector3(); | ||
434 | |||
435 | OSDMap user = (OSDMap)userResponse["User"]; | ||
436 | |||
437 | info.Login = user["LastLoginDate"].AsDate(); | ||
438 | info.Logout = user["LastLogoutDate"].AsDate(); | ||
439 | DeserializeLocation(user["HomeLocation"].AsString(), out info.HomeRegionID, out info.HomePosition, out info.HomeLookAt); | ||
440 | |||
441 | return info; | ||
442 | } | ||
443 | |||
444 | return null; | ||
445 | } | ||
446 | |||
447 | private string SerializeLocation(UUID regionID, Vector3 position, Vector3 lookAt) | ||
448 | { | ||
449 | return "{" + String.Format("\"SceneID\":\"{0}\",\"Position\":\"{1}\",\"LookAt\":\"{2}\"", regionID, position, lookAt) + "}"; | ||
450 | } | ||
451 | |||
452 | private bool DeserializeLocation(string location, out UUID regionID, out Vector3 position, out Vector3 lookAt) | ||
453 | { | ||
454 | OSDMap map = null; | ||
455 | |||
456 | try { map = OSDParser.DeserializeJson(location) as OSDMap; } | ||
457 | catch { } | ||
458 | |||
459 | if (map != null) | ||
460 | { | ||
461 | regionID = map["SceneID"].AsUUID(); | ||
462 | if (Vector3.TryParse(map["Position"].AsString(), out position) && | ||
463 | Vector3.TryParse(map["LookAt"].AsString(), out lookAt)) | ||
464 | { | ||
465 | return true; | ||
466 | } | ||
467 | } | ||
468 | |||
469 | regionID = UUID.Zero; | ||
470 | position = Vector3.Zero; | ||
471 | lookAt = Vector3.Zero; | ||
472 | return false; | ||
473 | } | ||
474 | |||
475 | #endregion Helpers | ||
476 | } | ||
477 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs new file mode 100644 index 0000000..6aefc38 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianProfiles.cs | |||
@@ -0,0 +1,478 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Reflection; | ||
32 | using log4net; | ||
33 | using Mono.Addins; | ||
34 | using Nini.Config; | ||
35 | using OpenMetaverse; | ||
36 | using OpenMetaverse.StructuredData; | ||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Framework.Client; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | using OpenSim.Services.Interfaces; | ||
42 | |||
43 | namespace OpenSim.Services.Connectors.SimianGrid | ||
44 | { | ||
45 | /// <summary> | ||
46 | /// Avatar profile flags | ||
47 | /// </summary> | ||
48 | [Flags] | ||
49 | public enum ProfileFlags : uint | ||
50 | { | ||
51 | AllowPublish = 1, | ||
52 | MaturePublish = 2, | ||
53 | Identified = 4, | ||
54 | Transacted = 8, | ||
55 | Online = 16 | ||
56 | } | ||
57 | |||
58 | /// <summary> | ||
59 | /// Connects avatar profile and classified queries to the SimianGrid | ||
60 | /// backend | ||
61 | /// </summary> | ||
62 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
63 | public class SimianProfiles : INonSharedRegionModule | ||
64 | { | ||
65 | private static readonly ILog m_log = | ||
66 | LogManager.GetLogger( | ||
67 | MethodBase.GetCurrentMethod().DeclaringType); | ||
68 | |||
69 | private string m_serverUrl = String.Empty; | ||
70 | private bool m_Enabled = false; | ||
71 | |||
72 | #region INonSharedRegionModule | ||
73 | |||
74 | public Type ReplaceableInterface { get { return null; } } | ||
75 | public void RegionLoaded(Scene scene) { } | ||
76 | public void Close() { } | ||
77 | |||
78 | public SimianProfiles() { } | ||
79 | public string Name { get { return "SimianProfiles"; } } | ||
80 | |||
81 | public void AddRegion(Scene scene) | ||
82 | { | ||
83 | if (m_Enabled) | ||
84 | { | ||
85 | CheckEstateManager(scene); | ||
86 | scene.EventManager.OnClientConnect += ClientConnectHandler; | ||
87 | } | ||
88 | } | ||
89 | |||
90 | public void RemoveRegion(Scene scene) | ||
91 | { | ||
92 | if (m_Enabled) | ||
93 | { | ||
94 | scene.EventManager.OnClientConnect -= ClientConnectHandler; | ||
95 | } | ||
96 | } | ||
97 | |||
98 | #endregion INonSharedRegionModule | ||
99 | |||
100 | public SimianProfiles(IConfigSource source) | ||
101 | { | ||
102 | Initialise(source); | ||
103 | } | ||
104 | |||
105 | public void Initialise(IConfigSource source) | ||
106 | { | ||
107 | IConfig profileConfig = source.Configs["Profiles"]; | ||
108 | if (profileConfig == null) | ||
109 | return; | ||
110 | |||
111 | if (profileConfig.GetString("Module", String.Empty) != Name) | ||
112 | return; | ||
113 | |||
114 | m_log.DebugFormat("[SIMIAN PROFILES] module enabled"); | ||
115 | m_Enabled = true; | ||
116 | |||
117 | IConfig gridConfig = source.Configs["UserAccountService"]; | ||
118 | if (gridConfig != null) | ||
119 | { | ||
120 | string serviceUrl = gridConfig.GetString("UserAccountServerURI"); | ||
121 | if (!String.IsNullOrEmpty(serviceUrl)) | ||
122 | { | ||
123 | if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("=")) | ||
124 | serviceUrl = serviceUrl + '/'; | ||
125 | m_serverUrl = serviceUrl; | ||
126 | } | ||
127 | } | ||
128 | |||
129 | if (String.IsNullOrEmpty(m_serverUrl)) | ||
130 | m_log.Info("[SIMIAN PROFILES]: No UserAccountServerURI specified, disabling connector"); | ||
131 | } | ||
132 | |||
133 | private void ClientConnectHandler(IClientCore clientCore) | ||
134 | { | ||
135 | if (clientCore is IClientAPI) | ||
136 | { | ||
137 | IClientAPI client = (IClientAPI)clientCore; | ||
138 | |||
139 | // Classifieds | ||
140 | client.AddGenericPacketHandler("avatarclassifiedsrequest", AvatarClassifiedsRequestHandler); | ||
141 | client.OnClassifiedInfoRequest += ClassifiedInfoRequestHandler; | ||
142 | client.OnClassifiedInfoUpdate += ClassifiedInfoUpdateHandler; | ||
143 | client.OnClassifiedDelete += ClassifiedDeleteHandler; | ||
144 | |||
145 | // Picks | ||
146 | client.AddGenericPacketHandler("avatarpicksrequest", HandleAvatarPicksRequest); | ||
147 | client.AddGenericPacketHandler("pickinforequest", HandlePickInfoRequest); | ||
148 | client.OnPickInfoUpdate += PickInfoUpdateHandler; | ||
149 | client.OnPickDelete += PickDeleteHandler; | ||
150 | |||
151 | // Notes | ||
152 | client.AddGenericPacketHandler("avatarnotesrequest", HandleAvatarNotesRequest); | ||
153 | client.OnAvatarNotesUpdate += AvatarNotesUpdateHandler; | ||
154 | |||
155 | // Profiles | ||
156 | client.OnRequestAvatarProperties += RequestAvatarPropertiesHandler; | ||
157 | |||
158 | client.OnUpdateAvatarProperties += UpdateAvatarPropertiesHandler; | ||
159 | client.OnAvatarInterestUpdate += AvatarInterestUpdateHandler; | ||
160 | client.OnUserInfoRequest += UserInfoRequestHandler; | ||
161 | client.OnUpdateUserInfo += UpdateUserInfoHandler; | ||
162 | } | ||
163 | } | ||
164 | |||
165 | #region Classifieds | ||
166 | |||
167 | private void AvatarClassifiedsRequestHandler(Object sender, string method, List<String> args) | ||
168 | { | ||
169 | if (!(sender is IClientAPI)) | ||
170 | return; | ||
171 | IClientAPI client = (IClientAPI)sender; | ||
172 | |||
173 | UUID targetAvatarID; | ||
174 | if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID)) | ||
175 | { | ||
176 | m_log.Error("[SIMIAN PROFILES]: Unrecognized arguments for " + method); | ||
177 | return; | ||
178 | } | ||
179 | |||
180 | // FIXME: Query the generic key/value store for classifieds | ||
181 | client.SendAvatarClassifiedReply(targetAvatarID, new Dictionary<UUID, string>(0)); | ||
182 | } | ||
183 | |||
184 | private void ClassifiedInfoRequestHandler(UUID classifiedID, IClientAPI client) | ||
185 | { | ||
186 | // FIXME: Fetch this info | ||
187 | client.SendClassifiedInfoReply(classifiedID, UUID.Zero, 0, Utils.DateTimeToUnixTime(DateTime.UtcNow + TimeSpan.FromDays(1)), | ||
188 | 0, String.Empty, String.Empty, UUID.Zero, 0, UUID.Zero, String.Empty, Vector3.Zero, String.Empty, 0, 0); | ||
189 | } | ||
190 | |||
191 | private void ClassifiedInfoUpdateHandler(UUID classifiedID, uint category, string name, string description, | ||
192 | UUID parcelID, uint parentEstate, UUID snapshotID, Vector3 globalPos, byte classifiedFlags, int price, | ||
193 | IClientAPI client) | ||
194 | { | ||
195 | // FIXME: Save this info | ||
196 | } | ||
197 | |||
198 | private void ClassifiedDeleteHandler(UUID classifiedID, IClientAPI client) | ||
199 | { | ||
200 | // FIXME: Delete the specified classified ad | ||
201 | } | ||
202 | |||
203 | #endregion Classifieds | ||
204 | |||
205 | #region Picks | ||
206 | |||
207 | private void HandleAvatarPicksRequest(Object sender, string method, List<String> args) | ||
208 | { | ||
209 | if (!(sender is IClientAPI)) | ||
210 | return; | ||
211 | IClientAPI client = (IClientAPI)sender; | ||
212 | |||
213 | UUID targetAvatarID; | ||
214 | if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID)) | ||
215 | { | ||
216 | m_log.Error("[SIMIAN PROFILES]: Unrecognized arguments for " + method); | ||
217 | return; | ||
218 | } | ||
219 | |||
220 | // FIXME: Fetch these | ||
221 | client.SendAvatarPicksReply(targetAvatarID, new Dictionary<UUID, string>(0)); | ||
222 | } | ||
223 | |||
224 | private void HandlePickInfoRequest(Object sender, string method, List<String> args) | ||
225 | { | ||
226 | if (!(sender is IClientAPI)) | ||
227 | return; | ||
228 | IClientAPI client = (IClientAPI)sender; | ||
229 | |||
230 | UUID avatarID; | ||
231 | UUID pickID; | ||
232 | if (args.Count < 2 || !UUID.TryParse(args[0], out avatarID) || !UUID.TryParse(args[1], out pickID)) | ||
233 | { | ||
234 | m_log.Error("[SIMIAN PROFILES]: Unrecognized arguments for " + method); | ||
235 | return; | ||
236 | } | ||
237 | |||
238 | // FIXME: Fetch this | ||
239 | client.SendPickInfoReply(pickID, avatarID, false, UUID.Zero, String.Empty, String.Empty, UUID.Zero, String.Empty, | ||
240 | String.Empty, String.Empty, Vector3.Zero, 0, false); | ||
241 | } | ||
242 | |||
243 | private void PickInfoUpdateHandler(IClientAPI client, UUID pickID, UUID creatorID, bool topPick, string name, | ||
244 | string desc, UUID snapshotID, int sortOrder, bool enabled) | ||
245 | { | ||
246 | // FIXME: Save this | ||
247 | } | ||
248 | |||
249 | private void PickDeleteHandler(IClientAPI client, UUID pickID) | ||
250 | { | ||
251 | // FIXME: Delete | ||
252 | } | ||
253 | |||
254 | #endregion Picks | ||
255 | |||
256 | #region Notes | ||
257 | |||
258 | private void HandleAvatarNotesRequest(Object sender, string method, List<String> args) | ||
259 | { | ||
260 | if (!(sender is IClientAPI)) | ||
261 | return; | ||
262 | IClientAPI client = (IClientAPI)sender; | ||
263 | |||
264 | UUID targetAvatarID; | ||
265 | if (args.Count < 1 || !UUID.TryParse(args[0], out targetAvatarID)) | ||
266 | { | ||
267 | m_log.Error("[SIMIAN PROFILES]: Unrecognized arguments for " + method); | ||
268 | return; | ||
269 | } | ||
270 | |||
271 | // FIXME: Fetch this | ||
272 | client.SendAvatarNotesReply(targetAvatarID, String.Empty); | ||
273 | } | ||
274 | |||
275 | private void AvatarNotesUpdateHandler(IClientAPI client, UUID targetID, string notes) | ||
276 | { | ||
277 | // FIXME: Save this | ||
278 | } | ||
279 | |||
280 | #endregion Notes | ||
281 | |||
282 | #region Profiles | ||
283 | |||
284 | private void RequestAvatarPropertiesHandler(IClientAPI client, UUID avatarID) | ||
285 | { | ||
286 | m_log.DebugFormat("[SIMIAN PROFILES]: Request avatar properties for {0}",avatarID); | ||
287 | |||
288 | OSDMap user = FetchUserData(avatarID); | ||
289 | |||
290 | ProfileFlags flags = ProfileFlags.AllowPublish | ProfileFlags.MaturePublish; | ||
291 | |||
292 | if (user != null) | ||
293 | { | ||
294 | OSDMap about = null; | ||
295 | if (user.ContainsKey("LLAbout")) | ||
296 | { | ||
297 | try | ||
298 | { | ||
299 | about = OSDParser.DeserializeJson(user["LLAbout"].AsString()) as OSDMap; | ||
300 | } | ||
301 | catch | ||
302 | { | ||
303 | m_log.WarnFormat("[SIMIAN PROFILES]: Unable to decode LLAbout"); | ||
304 | } | ||
305 | } | ||
306 | |||
307 | if (about == null) | ||
308 | about = new OSDMap(0); | ||
309 | |||
310 | // Check if this user is a grid operator | ||
311 | byte[] charterMember; | ||
312 | if (user["AccessLevel"].AsInteger() >= 200) | ||
313 | charterMember = Utils.StringToBytes("Operator"); | ||
314 | else | ||
315 | charterMember = Utils.EmptyBytes; | ||
316 | |||
317 | // Check if the user is online | ||
318 | if (client.Scene is Scene) | ||
319 | { | ||
320 | OpenSim.Services.Interfaces.PresenceInfo[] presences = ((Scene)client.Scene).PresenceService.GetAgents(new string[] { avatarID.ToString() }); | ||
321 | if (presences != null && presences.Length > 0) | ||
322 | flags |= ProfileFlags.Online; | ||
323 | } | ||
324 | |||
325 | // Check if the user is identified | ||
326 | if (user["Identified"].AsBoolean()) | ||
327 | flags |= ProfileFlags.Identified; | ||
328 | |||
329 | client.SendAvatarProperties(avatarID, about["About"].AsString(), user["CreationDate"].AsDate().ToString("M/d/yyyy", | ||
330 | System.Globalization.CultureInfo.InvariantCulture), charterMember, about["FLAbout"].AsString(), (uint)flags, | ||
331 | about["FLImage"].AsUUID(), about["Image"].AsUUID(), about["URL"].AsString(), user["Partner"].AsUUID()); | ||
332 | |||
333 | OSDMap interests = null; | ||
334 | if (user.ContainsKey("LLInterests")) | ||
335 | { | ||
336 | try | ||
337 | { | ||
338 | interests = OSDParser.DeserializeJson(user["LLInterests"].AsString()) as OSDMap; | ||
339 | client.SendAvatarInterestsReply(avatarID, interests["WantMask"].AsUInteger(), interests["WantText"].AsString(), interests["SkillsMask"].AsUInteger(), interests["SkillsText"].AsString(), interests["Languages"].AsString()); | ||
340 | } | ||
341 | catch { } | ||
342 | } | ||
343 | |||
344 | if (about == null) | ||
345 | about = new OSDMap(0); | ||
346 | } | ||
347 | else | ||
348 | { | ||
349 | m_log.Warn("[SIMIAN PROFILES]: Failed to fetch profile information for " + client.Name + ", returning default values"); | ||
350 | client.SendAvatarProperties(avatarID, String.Empty, "1/1/1970", Utils.EmptyBytes, | ||
351 | String.Empty, (uint)flags, UUID.Zero, UUID.Zero, String.Empty, UUID.Zero); | ||
352 | } | ||
353 | } | ||
354 | |||
355 | private void UpdateAvatarPropertiesHandler(IClientAPI client, UserProfileData profileData) | ||
356 | { | ||
357 | OSDMap map = new OSDMap | ||
358 | { | ||
359 | { "About", OSD.FromString(profileData.AboutText) }, | ||
360 | { "Image", OSD.FromUUID(profileData.Image) }, | ||
361 | { "FLAbout", OSD.FromString(profileData.FirstLifeAboutText) }, | ||
362 | { "FLImage", OSD.FromUUID(profileData.FirstLifeImage) }, | ||
363 | { "URL", OSD.FromString(profileData.ProfileUrl) } | ||
364 | }; | ||
365 | |||
366 | AddUserData(client.AgentId, "LLAbout", map); | ||
367 | } | ||
368 | |||
369 | private void AvatarInterestUpdateHandler(IClientAPI client, uint wantmask, string wanttext, uint skillsmask, | ||
370 | string skillstext, string languages) | ||
371 | { | ||
372 | OSDMap map = new OSDMap | ||
373 | { | ||
374 | { "WantMask", OSD.FromInteger(wantmask) }, | ||
375 | { "WantText", OSD.FromString(wanttext) }, | ||
376 | { "SkillsMask", OSD.FromInteger(skillsmask) }, | ||
377 | { "SkillsText", OSD.FromString(skillstext) }, | ||
378 | { "Languages", OSD.FromString(languages) } | ||
379 | }; | ||
380 | |||
381 | AddUserData(client.AgentId, "LLInterests", map); | ||
382 | } | ||
383 | |||
384 | private void UserInfoRequestHandler(IClientAPI client) | ||
385 | { | ||
386 | m_log.Error("[SIMIAN PROFILES]: UserInfoRequestHandler"); | ||
387 | |||
388 | // Fetch this user's e-mail address | ||
389 | NameValueCollection requestArgs = new NameValueCollection | ||
390 | { | ||
391 | { "RequestMethod", "GetUser" }, | ||
392 | { "UserID", client.AgentId.ToString() } | ||
393 | }; | ||
394 | |||
395 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
396 | string email = response["Email"].AsString(); | ||
397 | |||
398 | if (!response["Success"].AsBoolean()) | ||
399 | m_log.Warn("[SIMIAN PROFILES]: GetUser failed during a user info request for " + client.Name); | ||
400 | |||
401 | client.SendUserInfoReply(false, true, email); | ||
402 | } | ||
403 | |||
404 | private void UpdateUserInfoHandler(bool imViaEmail, bool visible, IClientAPI client) | ||
405 | { | ||
406 | m_log.Info("[SIMIAN PROFILES]: Ignoring user info update from " + client.Name); | ||
407 | } | ||
408 | |||
409 | #endregion Profiles | ||
410 | |||
411 | /// <summary> | ||
412 | /// Sanity checks regions for a valid estate owner at startup | ||
413 | /// </summary> | ||
414 | private void CheckEstateManager(Scene scene) | ||
415 | { | ||
416 | EstateSettings estate = scene.RegionInfo.EstateSettings; | ||
417 | |||
418 | if (estate.EstateOwner == UUID.Zero) | ||
419 | { | ||
420 | // Attempt to lookup the grid admin | ||
421 | UserAccount admin = scene.UserAccountService.GetUserAccount(scene.RegionInfo.ScopeID, UUID.Zero); | ||
422 | if (admin != null) | ||
423 | { | ||
424 | m_log.InfoFormat("[SIMIAN PROFILES]: Setting estate {0} (ID: {1}) owner to {2}", estate.EstateName, | ||
425 | estate.EstateID, admin.Name); | ||
426 | |||
427 | estate.EstateOwner = admin.PrincipalID; | ||
428 | estate.Save(); | ||
429 | } | ||
430 | else | ||
431 | { | ||
432 | m_log.WarnFormat("[SIMIAN PROFILES]: Estate {0} (ID: {1}) does not have an owner", estate.EstateName, estate.EstateID); | ||
433 | } | ||
434 | } | ||
435 | } | ||
436 | |||
437 | private bool AddUserData(UUID userID, string key, OSDMap value) | ||
438 | { | ||
439 | NameValueCollection requestArgs = new NameValueCollection | ||
440 | { | ||
441 | { "RequestMethod", "AddUserData" }, | ||
442 | { "UserID", userID.ToString() }, | ||
443 | { key, OSDParser.SerializeJsonString(value) } | ||
444 | }; | ||
445 | |||
446 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
447 | bool success = response["Success"].AsBoolean(); | ||
448 | |||
449 | if (!success) | ||
450 | m_log.WarnFormat("[SIMIAN PROFILES]: Failed to add user data with key {0} for {1}: {2}", key, userID, response["Message"].AsString()); | ||
451 | |||
452 | return success; | ||
453 | } | ||
454 | |||
455 | private OSDMap FetchUserData(UUID userID) | ||
456 | { | ||
457 | m_log.DebugFormat("[SIMIAN PROFILES]: Fetch information about {0}",userID); | ||
458 | |||
459 | NameValueCollection requestArgs = new NameValueCollection | ||
460 | { | ||
461 | { "RequestMethod", "GetUser" }, | ||
462 | { "UserID", userID.ToString() } | ||
463 | }; | ||
464 | |||
465 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
466 | if (response["Success"].AsBoolean() && response["User"] is OSDMap) | ||
467 | { | ||
468 | return (OSDMap)response["User"]; | ||
469 | } | ||
470 | else | ||
471 | { | ||
472 | m_log.Error("[SIMIAN PROFILES]: Failed to fetch user data for " + userID + ": " + response["Message"].AsString()); | ||
473 | } | ||
474 | |||
475 | return null; | ||
476 | } | ||
477 | } | ||
478 | } | ||
diff --git a/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.cs new file mode 100644 index 0000000..801b424 --- /dev/null +++ b/OpenSim/Services/Connectors/SimianGrid/SimianUserAccountServiceConnector.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 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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Collections.Specialized; | ||
31 | using System.Reflection; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Region.Framework.Interfaces; | ||
34 | using OpenSim.Region.Framework.Scenes; | ||
35 | using OpenSim.Services.Interfaces; | ||
36 | using log4net; | ||
37 | using Mono.Addins; | ||
38 | using Nini.Config; | ||
39 | using OpenMetaverse; | ||
40 | using OpenMetaverse.StructuredData; | ||
41 | |||
42 | namespace OpenSim.Services.Connectors.SimianGrid | ||
43 | { | ||
44 | /// <summary> | ||
45 | /// Connects user account data (creating new users, looking up existing | ||
46 | /// users) to the SimianGrid backend | ||
47 | /// </summary> | ||
48 | [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule")] | ||
49 | public class SimianUserAccountServiceConnector : IUserAccountService, ISharedRegionModule | ||
50 | { | ||
51 | private const double CACHE_EXPIRATION_SECONDS = 120.0; | ||
52 | |||
53 | private static readonly ILog m_log = | ||
54 | LogManager.GetLogger( | ||
55 | MethodBase.GetCurrentMethod().DeclaringType); | ||
56 | |||
57 | private string m_serverUrl = String.Empty; | ||
58 | private ExpiringCache<UUID, UserAccount> m_accountCache = new ExpiringCache<UUID,UserAccount>(); | ||
59 | private bool m_Enabled; | ||
60 | |||
61 | #region ISharedRegionModule | ||
62 | |||
63 | public Type ReplaceableInterface { get { return null; } } | ||
64 | public void RegionLoaded(Scene scene) { } | ||
65 | public void PostInitialise() { } | ||
66 | public void Close() { } | ||
67 | |||
68 | public SimianUserAccountServiceConnector() { } | ||
69 | public string Name { get { return "SimianUserAccountServiceConnector"; } } | ||
70 | public void AddRegion(Scene scene) { if (m_Enabled) { scene.RegisterModuleInterface<IUserAccountService>(this); } } | ||
71 | public void RemoveRegion(Scene scene) { if (m_Enabled) { scene.UnregisterModuleInterface<IUserAccountService>(this); } } | ||
72 | |||
73 | #endregion ISharedRegionModule | ||
74 | |||
75 | public SimianUserAccountServiceConnector(IConfigSource source) | ||
76 | { | ||
77 | CommonInit(source); | ||
78 | } | ||
79 | |||
80 | public void Initialise(IConfigSource source) | ||
81 | { | ||
82 | IConfig moduleConfig = source.Configs["Modules"]; | ||
83 | if (moduleConfig != null) | ||
84 | { | ||
85 | string name = moduleConfig.GetString("UserAccountServices", ""); | ||
86 | if (name == Name) | ||
87 | CommonInit(source); | ||
88 | } | ||
89 | } | ||
90 | |||
91 | private void CommonInit(IConfigSource source) | ||
92 | { | ||
93 | IConfig gridConfig = source.Configs["UserAccountService"]; | ||
94 | if (gridConfig != null) | ||
95 | { | ||
96 | string serviceUrl = gridConfig.GetString("UserAccountServerURI"); | ||
97 | if (!String.IsNullOrEmpty(serviceUrl)) | ||
98 | { | ||
99 | if (!serviceUrl.EndsWith("/") && !serviceUrl.EndsWith("=")) | ||
100 | serviceUrl = serviceUrl + '/'; | ||
101 | m_serverUrl = serviceUrl; | ||
102 | m_Enabled = true; | ||
103 | } | ||
104 | } | ||
105 | |||
106 | if (String.IsNullOrEmpty(m_serverUrl)) | ||
107 | m_log.Info("[SIMIAN ACCOUNT CONNECTOR]: No UserAccountServerURI specified, disabling connector"); | ||
108 | } | ||
109 | |||
110 | public UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName) | ||
111 | { | ||
112 | NameValueCollection requestArgs = new NameValueCollection | ||
113 | { | ||
114 | { "RequestMethod", "GetUser" }, | ||
115 | { "Name", firstName + ' ' + lastName } | ||
116 | }; | ||
117 | |||
118 | return GetUser(requestArgs); | ||
119 | } | ||
120 | |||
121 | public UserAccount GetUserAccount(UUID scopeID, string email) | ||
122 | { | ||
123 | NameValueCollection requestArgs = new NameValueCollection | ||
124 | { | ||
125 | { "RequestMethod", "GetUser" }, | ||
126 | { "Email", email } | ||
127 | }; | ||
128 | |||
129 | return GetUser(requestArgs); | ||
130 | } | ||
131 | |||
132 | public UserAccount GetUserAccount(UUID scopeID, UUID userID) | ||
133 | { | ||
134 | // Cache check | ||
135 | UserAccount account; | ||
136 | if (m_accountCache.TryGetValue(userID, out account)) | ||
137 | return account; | ||
138 | |||
139 | NameValueCollection requestArgs = new NameValueCollection | ||
140 | { | ||
141 | { "RequestMethod", "GetUser" }, | ||
142 | { "UserID", userID.ToString() } | ||
143 | }; | ||
144 | |||
145 | account = GetUser(requestArgs); | ||
146 | |||
147 | if (account == null) | ||
148 | { | ||
149 | // Store null responses too, to avoid repeated lookups for missing accounts | ||
150 | m_accountCache.AddOrUpdate(userID, null, CACHE_EXPIRATION_SECONDS); | ||
151 | } | ||
152 | |||
153 | return account; | ||
154 | } | ||
155 | |||
156 | public List<UserAccount> GetUserAccounts(UUID scopeID, string query) | ||
157 | { | ||
158 | List<UserAccount> accounts = new List<UserAccount>(); | ||
159 | |||
160 | // m_log.DebugFormat("[SIMIAN ACCOUNT CONNECTOR]: Searching for user accounts with name query " + query); | ||
161 | |||
162 | NameValueCollection requestArgs = new NameValueCollection | ||
163 | { | ||
164 | { "RequestMethod", "GetUsers" }, | ||
165 | { "NameQuery", query } | ||
166 | }; | ||
167 | |||
168 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
169 | if (response["Success"].AsBoolean()) | ||
170 | { | ||
171 | OSDArray array = response["Users"] as OSDArray; | ||
172 | if (array != null && array.Count > 0) | ||
173 | { | ||
174 | for (int i = 0; i < array.Count; i++) | ||
175 | { | ||
176 | UserAccount account = ResponseToUserAccount(array[i] as OSDMap); | ||
177 | if (account != null) | ||
178 | accounts.Add(account); | ||
179 | } | ||
180 | } | ||
181 | else | ||
182 | { | ||
183 | m_log.Warn("[SIMIAN ACCOUNT CONNECTOR]: Account search failed, response data was in an invalid format"); | ||
184 | } | ||
185 | } | ||
186 | else | ||
187 | { | ||
188 | m_log.Warn("[SIMIAN ACCOUNT CONNECTOR]: Failed to search for account data by name " + query); | ||
189 | } | ||
190 | |||
191 | return accounts; | ||
192 | } | ||
193 | |||
194 | public List<UserAccount> GetUserAccountsWhere(UUID scopeID, string query) | ||
195 | { | ||
196 | return null; | ||
197 | } | ||
198 | |||
199 | public bool StoreUserAccount(UserAccount data) | ||
200 | { | ||
201 | // m_log.InfoFormat("[SIMIAN ACCOUNT CONNECTOR]: Storing user account for " + data.Name); | ||
202 | |||
203 | NameValueCollection requestArgs = new NameValueCollection | ||
204 | { | ||
205 | { "RequestMethod", "AddUser" }, | ||
206 | { "UserID", data.PrincipalID.ToString() }, | ||
207 | { "Name", data.Name }, | ||
208 | { "Email", data.Email }, | ||
209 | { "AccessLevel", data.UserLevel.ToString() } | ||
210 | }; | ||
211 | |||
212 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
213 | |||
214 | if (response["Success"].AsBoolean()) | ||
215 | { | ||
216 | m_log.InfoFormat("[SIMIAN ACCOUNT CONNECTOR]: Storing user account data for " + data.Name); | ||
217 | |||
218 | requestArgs = new NameValueCollection | ||
219 | { | ||
220 | { "RequestMethod", "AddUserData" }, | ||
221 | { "UserID", data.PrincipalID.ToString() }, | ||
222 | { "CreationDate", data.Created.ToString() }, | ||
223 | { "UserFlags", data.UserFlags.ToString() }, | ||
224 | { "UserTitle", data.UserTitle } | ||
225 | }; | ||
226 | |||
227 | response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
228 | bool success = response["Success"].AsBoolean(); | ||
229 | |||
230 | if (success) | ||
231 | { | ||
232 | // Cache the user account info | ||
233 | m_accountCache.AddOrUpdate(data.PrincipalID, data, CACHE_EXPIRATION_SECONDS); | ||
234 | } | ||
235 | else | ||
236 | { | ||
237 | m_log.Warn("[SIMIAN ACCOUNT CONNECTOR]: Failed to store user account data for " + data.Name + ": " + response["Message"].AsString()); | ||
238 | } | ||
239 | |||
240 | return success; | ||
241 | } | ||
242 | else | ||
243 | { | ||
244 | m_log.Warn("[SIMIAN ACCOUNT CONNECTOR]: Failed to store user account for " + data.Name + ": " + response["Message"].AsString()); | ||
245 | } | ||
246 | |||
247 | return false; | ||
248 | } | ||
249 | |||
250 | /// <summary> | ||
251 | /// Helper method for the various ways of retrieving a user account | ||
252 | /// </summary> | ||
253 | /// <param name="requestArgs">Service query parameters</param> | ||
254 | /// <returns>A UserAccount object on success, null on failure</returns> | ||
255 | private UserAccount GetUser(NameValueCollection requestArgs) | ||
256 | { | ||
257 | string lookupValue = (requestArgs.Count > 1) ? requestArgs[1] : "(Unknown)"; | ||
258 | // m_log.DebugFormat("[SIMIAN ACCOUNT CONNECTOR]: Looking up user account with query: " + lookupValue); | ||
259 | |||
260 | OSDMap response = WebUtil.PostToService(m_serverUrl, requestArgs); | ||
261 | if (response["Success"].AsBoolean()) | ||
262 | { | ||
263 | OSDMap user = response["User"] as OSDMap; | ||
264 | if (user != null) | ||
265 | return ResponseToUserAccount(user); | ||
266 | else | ||
267 | m_log.Warn("[SIMIAN ACCOUNT CONNECTOR]: Account search failed, response data was in an invalid format"); | ||
268 | } | ||
269 | else | ||
270 | { | ||
271 | m_log.Warn("[SIMIAN ACCOUNT CONNECTOR]: Failed to lookup user account with query: " + lookupValue); | ||
272 | } | ||
273 | |||
274 | return null; | ||
275 | } | ||
276 | |||
277 | /// <summary> | ||
278 | /// Convert a User object in LLSD format to a UserAccount | ||
279 | /// </summary> | ||
280 | /// <param name="response">LLSD containing user account data</param> | ||
281 | /// <returns>A UserAccount object on success, null on failure</returns> | ||
282 | private UserAccount ResponseToUserAccount(OSDMap response) | ||
283 | { | ||
284 | if (response == null) | ||
285 | return null; | ||
286 | |||
287 | UserAccount account = new UserAccount(); | ||
288 | account.PrincipalID = response["UserID"].AsUUID(); | ||
289 | account.Created = response["CreationDate"].AsInteger(); | ||
290 | account.Email = response["Email"].AsString(); | ||
291 | account.ServiceURLs = new Dictionary<string, object>(0); | ||
292 | account.UserFlags = response["UserFlags"].AsInteger(); | ||
293 | account.UserLevel = response["AccessLevel"].AsInteger(); | ||
294 | account.UserTitle = response["UserTitle"].AsString(); | ||
295 | GetFirstLastName(response["Name"].AsString(), out account.FirstName, out account.LastName); | ||
296 | |||
297 | // Cache the user account info | ||
298 | m_accountCache.AddOrUpdate(account.PrincipalID, account, CACHE_EXPIRATION_SECONDS); | ||
299 | |||
300 | return account; | ||
301 | } | ||
302 | |||
303 | /// <summary> | ||
304 | /// Convert a name with a single space in it to a first and last name | ||
305 | /// </summary> | ||
306 | /// <param name="name">A full name such as "John Doe"</param> | ||
307 | /// <param name="firstName">First name</param> | ||
308 | /// <param name="lastName">Last name (surname)</param> | ||
309 | private static void GetFirstLastName(string name, out string firstName, out string lastName) | ||
310 | { | ||
311 | if (String.IsNullOrEmpty(name)) | ||
312 | { | ||
313 | firstName = String.Empty; | ||
314 | lastName = String.Empty; | ||
315 | } | ||
316 | else | ||
317 | { | ||
318 | string[] names = name.Split(' '); | ||
319 | |||
320 | if (names.Length == 2) | ||
321 | { | ||
322 | firstName = names[0]; | ||
323 | lastName = names[1]; | ||
324 | } | ||
325 | else | ||
326 | { | ||
327 | firstName = String.Empty; | ||
328 | lastName = name; | ||
329 | } | ||
330 | } | ||
331 | } | ||
332 | } | ||
333 | } \ No newline at end of file | ||
diff --git a/OpenSim/Services/Connectors/Simulation/EstateDataService.cs b/OpenSim/Services/Connectors/Simulation/EstateDataService.cs new file mode 100644 index 0000000..cdcdecf --- /dev/null +++ b/OpenSim/Services/Connectors/Simulation/EstateDataService.cs | |||
@@ -0,0 +1,139 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | using log4net; | ||
32 | using Mono.Addins; | ||
33 | using Nini.Config; | ||
34 | using System.Reflection; | ||
35 | using OpenSim.Services.Base; | ||
36 | using OpenSim.Services.Interfaces; | ||
37 | using OpenSim.Data; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | |||
42 | namespace OpenSim.Services.Connectors | ||
43 | { | ||
44 | public class EstateDataService : ServiceBase, IEstateDataService | ||
45 | { | ||
46 | // private static readonly ILog m_log = | ||
47 | // LogManager.GetLogger( | ||
48 | // MethodBase.GetCurrentMethod().DeclaringType); | ||
49 | |||
50 | protected IEstateDataStore m_database; | ||
51 | |||
52 | public EstateDataService(IConfigSource config) | ||
53 | : base(config) | ||
54 | { | ||
55 | string dllName = String.Empty; | ||
56 | string connString = String.Empty; | ||
57 | |||
58 | // Try reading the [DatabaseService] section, if it exists | ||
59 | IConfig dbConfig = config.Configs["DatabaseService"]; | ||
60 | if (dbConfig != null) | ||
61 | { | ||
62 | dllName = dbConfig.GetString("StorageProvider", String.Empty); | ||
63 | connString = dbConfig.GetString("ConnectionString", String.Empty); | ||
64 | connString = dbConfig.GetString("EstateConnectionString", connString); | ||
65 | } | ||
66 | |||
67 | // Try reading the [EstateDataStore] section, if it exists | ||
68 | IConfig estConfig = config.Configs["EstateDataStore"]; | ||
69 | if (estConfig != null) | ||
70 | { | ||
71 | dllName = estConfig.GetString("StorageProvider", dllName); | ||
72 | connString = estConfig.GetString("ConnectionString", connString); | ||
73 | } | ||
74 | |||
75 | // We tried, but this doesn't exist. We can't proceed | ||
76 | if (dllName == String.Empty) | ||
77 | throw new Exception("No StorageProvider configured"); | ||
78 | |||
79 | m_database = LoadPlugin<IEstateDataStore>(dllName, new Object[] { connString }); | ||
80 | if (m_database == null) | ||
81 | throw new Exception("Could not find a storage interface in the given module"); | ||
82 | } | ||
83 | |||
84 | public EstateSettings LoadEstateSettings(UUID regionID, bool create) | ||
85 | { | ||
86 | return m_database.LoadEstateSettings(regionID, create); | ||
87 | } | ||
88 | |||
89 | public EstateSettings LoadEstateSettings(int estateID) | ||
90 | { | ||
91 | return m_database.LoadEstateSettings(estateID); | ||
92 | } | ||
93 | |||
94 | public EstateSettings CreateNewEstate() | ||
95 | { | ||
96 | return m_database.CreateNewEstate(); | ||
97 | } | ||
98 | |||
99 | public List<EstateSettings> LoadEstateSettingsAll() | ||
100 | { | ||
101 | return m_database.LoadEstateSettingsAll(); | ||
102 | } | ||
103 | |||
104 | public void StoreEstateSettings(EstateSettings es) | ||
105 | { | ||
106 | m_database.StoreEstateSettings(es); | ||
107 | } | ||
108 | |||
109 | public List<int> GetEstates(string search) | ||
110 | { | ||
111 | return m_database.GetEstates(search); | ||
112 | } | ||
113 | |||
114 | public List<int> GetEstatesAll() | ||
115 | { | ||
116 | return m_database.GetEstatesAll(); | ||
117 | } | ||
118 | |||
119 | public List<int> GetEstatesByOwner(UUID ownerID) | ||
120 | { | ||
121 | return m_database.GetEstatesByOwner(ownerID); | ||
122 | } | ||
123 | |||
124 | public bool LinkRegion(UUID regionID, int estateID) | ||
125 | { | ||
126 | return m_database.LinkRegion(regionID, estateID); | ||
127 | } | ||
128 | |||
129 | public List<UUID> GetRegions(int estateID) | ||
130 | { | ||
131 | return m_database.GetRegions(estateID); | ||
132 | } | ||
133 | |||
134 | public bool DeleteEstate(int estateID) | ||
135 | { | ||
136 | return m_database.DeleteEstate(estateID); | ||
137 | } | ||
138 | } | ||
139 | } | ||
diff --git a/OpenSim/Services/Connectors/Simulation/SimulationDataService.cs b/OpenSim/Services/Connectors/Simulation/SimulationDataService.cs new file mode 100644 index 0000000..ccef50b --- /dev/null +++ b/OpenSim/Services/Connectors/Simulation/SimulationDataService.cs | |||
@@ -0,0 +1,152 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | using log4net; | ||
32 | using Mono.Addins; | ||
33 | using Nini.Config; | ||
34 | using System.Reflection; | ||
35 | using OpenSim.Services.Base; | ||
36 | using OpenSim.Services.Interfaces; | ||
37 | using OpenSim.Data; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Region.Framework.Interfaces; | ||
40 | using OpenSim.Region.Framework.Scenes; | ||
41 | |||
42 | namespace OpenSim.Services.Connectors | ||
43 | { | ||
44 | public class SimulationDataService : ServiceBase, ISimulationDataService | ||
45 | { | ||
46 | // private static readonly ILog m_log = | ||
47 | // LogManager.GetLogger( | ||
48 | // MethodBase.GetCurrentMethod().DeclaringType); | ||
49 | |||
50 | protected ISimulationDataStore m_database; | ||
51 | |||
52 | public SimulationDataService(IConfigSource config) | ||
53 | : base(config) | ||
54 | { | ||
55 | string dllName = String.Empty; | ||
56 | string connString = String.Empty; | ||
57 | |||
58 | // Try reading the [DatabaseService] section, if it exists | ||
59 | IConfig dbConfig = config.Configs["DatabaseService"]; | ||
60 | if (dbConfig != null) | ||
61 | { | ||
62 | dllName = dbConfig.GetString("StorageProvider", String.Empty); | ||
63 | connString = dbConfig.GetString("ConnectionString", String.Empty); | ||
64 | } | ||
65 | |||
66 | // Try reading the [SimulationDataStore] section | ||
67 | IConfig simConfig = config.Configs["SimulationDataStore"]; | ||
68 | if (simConfig != null) | ||
69 | { | ||
70 | dllName = simConfig.GetString("StorageProvider", dllName); | ||
71 | connString = simConfig.GetString("ConnectionString", connString); | ||
72 | } | ||
73 | |||
74 | // We tried, but this doesn't exist. We can't proceed | ||
75 | if (dllName == String.Empty) | ||
76 | throw new Exception("No StorageProvider configured"); | ||
77 | |||
78 | m_database = LoadPlugin<ISimulationDataStore>(dllName, new Object[] { connString }); | ||
79 | if (m_database == null) | ||
80 | throw new Exception("Could not find a storage interface in the given module"); | ||
81 | } | ||
82 | |||
83 | public void StoreObject(SceneObjectGroup obj, UUID regionUUID) | ||
84 | { | ||
85 | m_database.StoreObject(obj, regionUUID); | ||
86 | } | ||
87 | |||
88 | public void RemoveObject(UUID uuid, UUID regionUUID) | ||
89 | { | ||
90 | m_database.RemoveObject(uuid, regionUUID); | ||
91 | } | ||
92 | |||
93 | public void StorePrimInventory(UUID primID, ICollection<TaskInventoryItem> items) | ||
94 | { | ||
95 | m_database.StorePrimInventory(primID, items); | ||
96 | } | ||
97 | |||
98 | public List<SceneObjectGroup> LoadObjects(UUID regionUUID) | ||
99 | { | ||
100 | return m_database.LoadObjects(regionUUID); | ||
101 | } | ||
102 | |||
103 | public void StoreTerrain(double[,] terrain, UUID regionID) | ||
104 | { | ||
105 | m_database.StoreTerrain(terrain, regionID); | ||
106 | } | ||
107 | |||
108 | public double[,] LoadTerrain(UUID regionID) | ||
109 | { | ||
110 | return m_database.LoadTerrain(regionID); | ||
111 | } | ||
112 | |||
113 | public void StoreLandObject(ILandObject Parcel) | ||
114 | { | ||
115 | m_database.StoreLandObject(Parcel); | ||
116 | } | ||
117 | |||
118 | public void RemoveLandObject(UUID globalID) | ||
119 | { | ||
120 | m_database.RemoveLandObject(globalID); | ||
121 | } | ||
122 | |||
123 | public List<LandData> LoadLandObjects(UUID regionUUID) | ||
124 | { | ||
125 | return m_database.LoadLandObjects(regionUUID); | ||
126 | } | ||
127 | |||
128 | public void StoreRegionSettings(RegionSettings rs) | ||
129 | { | ||
130 | m_database.StoreRegionSettings(rs); | ||
131 | } | ||
132 | |||
133 | public RegionSettings LoadRegionSettings(UUID regionUUID) | ||
134 | { | ||
135 | return m_database.LoadRegionSettings(regionUUID); | ||
136 | } | ||
137 | |||
138 | public RegionLightShareData LoadRegionWindlightSettings(UUID regionUUID) | ||
139 | { | ||
140 | return m_database.LoadRegionWindlightSettings(regionUUID); | ||
141 | } | ||
142 | |||
143 | public void StoreRegionWindlightSettings(RegionLightShareData wl) | ||
144 | { | ||
145 | m_database.StoreRegionWindlightSettings(wl); | ||
146 | } | ||
147 | public void RemoveRegionWindlightSettings(UUID regionID) | ||
148 | { | ||
149 | m_database.RemoveRegionWindlightSettings(regionID); | ||
150 | } | ||
151 | } | ||
152 | } | ||
diff --git a/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs new file mode 100644 index 0000000..24a23dd --- /dev/null +++ b/OpenSim/Services/Connectors/Simulation/SimulationServiceConnector.cs | |||
@@ -0,0 +1,457 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | using System.Text; | ||
34 | using System.Collections; | ||
35 | |||
36 | using OpenSim.Framework; | ||
37 | using OpenSim.Services.Interfaces; | ||
38 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
39 | |||
40 | using OpenMetaverse; | ||
41 | using OpenMetaverse.StructuredData; | ||
42 | using log4net; | ||
43 | using Nini.Config; | ||
44 | |||
45 | namespace OpenSim.Services.Connectors.Simulation | ||
46 | { | ||
47 | public class SimulationServiceConnector : ISimulationService | ||
48 | { | ||
49 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
50 | |||
51 | // we use this dictionary to track the pending updateagent requests, maps URI --> position update | ||
52 | private Dictionary<string,AgentPosition> m_updateAgentQueue = new Dictionary<string,AgentPosition>(); | ||
53 | |||
54 | //private GridRegion m_Region; | ||
55 | |||
56 | public SimulationServiceConnector() | ||
57 | { | ||
58 | } | ||
59 | |||
60 | public SimulationServiceConnector(IConfigSource config) | ||
61 | { | ||
62 | //m_Region = region; | ||
63 | } | ||
64 | |||
65 | public IScene GetScene(ulong regionHandle) | ||
66 | { | ||
67 | return null; | ||
68 | } | ||
69 | |||
70 | public ISimulationService GetInnerService() | ||
71 | { | ||
72 | return null; | ||
73 | } | ||
74 | |||
75 | #region Agents | ||
76 | |||
77 | protected virtual string AgentPath() | ||
78 | { | ||
79 | return "agent/"; | ||
80 | } | ||
81 | |||
82 | public bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint flags, out string reason) | ||
83 | { | ||
84 | // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: CreateAgent start"); | ||
85 | |||
86 | reason = String.Empty; | ||
87 | if (destination == null) | ||
88 | { | ||
89 | m_log.Debug("[REMOTE SIMULATION CONNECTOR]: Given destination is null"); | ||
90 | return false; | ||
91 | } | ||
92 | |||
93 | string uri = destination.ServerURI + AgentPath() + aCircuit.AgentID + "/"; | ||
94 | |||
95 | try | ||
96 | { | ||
97 | OSDMap args = aCircuit.PackAgentCircuitData(); | ||
98 | |||
99 | args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); | ||
100 | args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); | ||
101 | args["destination_name"] = OSD.FromString(destination.RegionName); | ||
102 | args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); | ||
103 | args["teleport_flags"] = OSD.FromString(flags.ToString()); | ||
104 | |||
105 | OSDMap result = WebUtil.PostToServiceCompressed(uri, args, 30000); | ||
106 | bool success = result["success"].AsBoolean(); | ||
107 | if (success && result.ContainsKey("_Result")) | ||
108 | { | ||
109 | OSDMap data = (OSDMap)result["_Result"]; | ||
110 | |||
111 | reason = data["reason"].AsString(); | ||
112 | success = data["success"].AsBoolean(); | ||
113 | return success; | ||
114 | } | ||
115 | |||
116 | // Try the old version, uncompressed | ||
117 | result = WebUtil.PostToService(uri, args, 30000); | ||
118 | |||
119 | if (result["Success"].AsBoolean()) | ||
120 | { | ||
121 | if (result.ContainsKey("_Result")) | ||
122 | { | ||
123 | OSDMap data = (OSDMap)result["_Result"]; | ||
124 | |||
125 | reason = data["reason"].AsString(); | ||
126 | success = data["success"].AsBoolean(); | ||
127 | m_log.WarnFormat( | ||
128 | "[REMOTE SIMULATION CONNECTOR]: Remote simulator {0} did not accept compressed transfer, suggest updating it.", destination.RegionName); | ||
129 | return success; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | m_log.WarnFormat( | ||
134 | "[REMOTE SIMULATION CONNECTOR]: Failed to create agent {0} {1} at remote simulator {2}", | ||
135 | aCircuit.firstname, aCircuit.lastname, destination.RegionName); | ||
136 | reason = result["Message"] != null ? result["Message"].AsString() : "error"; | ||
137 | return false; | ||
138 | } | ||
139 | catch (Exception e) | ||
140 | { | ||
141 | m_log.Warn("[REMOTE SIMULATION CONNECTOR]: CreateAgent failed with exception: " + e.ToString()); | ||
142 | reason = e.Message; | ||
143 | } | ||
144 | |||
145 | return false; | ||
146 | } | ||
147 | |||
148 | /// <summary> | ||
149 | /// Send complete data about an agent in this region to a neighbor | ||
150 | /// </summary> | ||
151 | public bool UpdateAgent(GridRegion destination, AgentData data) | ||
152 | { | ||
153 | return UpdateAgent(destination, (IAgentData)data, 200000); // yes, 200 seconds | ||
154 | } | ||
155 | |||
156 | /// <summary> | ||
157 | /// Send updated position information about an agent in this region to a neighbor | ||
158 | /// This operation may be called very frequently if an avatar is moving about in | ||
159 | /// the region. | ||
160 | /// </summary> | ||
161 | public bool UpdateAgent(GridRegion destination, AgentPosition data) | ||
162 | { | ||
163 | // The basic idea of this code is that the first thread that needs to | ||
164 | // send an update for a specific avatar becomes the worker for any subsequent | ||
165 | // requests until there are no more outstanding requests. Further, only send the most | ||
166 | // recent update; this *should* never be needed but some requests get | ||
167 | // slowed down and once that happens the problem with service end point | ||
168 | // limits kicks in and nothing proceeds | ||
169 | string uri = destination.ServerURI + AgentPath() + data.AgentID + "/"; | ||
170 | lock (m_updateAgentQueue) | ||
171 | { | ||
172 | if (m_updateAgentQueue.ContainsKey(uri)) | ||
173 | { | ||
174 | // Another thread is already handling | ||
175 | // updates for this simulator, just update | ||
176 | // the position and return, overwrites are | ||
177 | // not a problem since we only care about the | ||
178 | // last update anyway | ||
179 | m_updateAgentQueue[uri] = data; | ||
180 | return true; | ||
181 | } | ||
182 | |||
183 | // Otherwise update the reference and start processing | ||
184 | m_updateAgentQueue[uri] = data; | ||
185 | } | ||
186 | |||
187 | AgentPosition pos = null; | ||
188 | while (true) | ||
189 | { | ||
190 | lock (m_updateAgentQueue) | ||
191 | { | ||
192 | // save the position | ||
193 | AgentPosition lastpos = pos; | ||
194 | |||
195 | pos = m_updateAgentQueue[uri]; | ||
196 | |||
197 | // this is true if no one put a new | ||
198 | // update in the map since the last | ||
199 | // one we processed, if thats the | ||
200 | // case then we are done | ||
201 | if (pos == lastpos) | ||
202 | { | ||
203 | m_updateAgentQueue.Remove(uri); | ||
204 | return true; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | UpdateAgent(destination, (IAgentData)pos, 10000); | ||
209 | } | ||
210 | |||
211 | // unreachable | ||
212 | // return true; | ||
213 | } | ||
214 | |||
215 | /// <summary> | ||
216 | /// This is the worker function to send AgentData to a neighbor region | ||
217 | /// </summary> | ||
218 | private bool UpdateAgent(GridRegion destination, IAgentData cAgentData, int timeout) | ||
219 | { | ||
220 | // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: UpdateAgent start"); | ||
221 | |||
222 | // Eventually, we want to use a caps url instead of the agentID | ||
223 | string uri = destination.ServerURI + AgentPath() + cAgentData.AgentID + "/"; | ||
224 | |||
225 | try | ||
226 | { | ||
227 | OSDMap args = cAgentData.Pack(); | ||
228 | |||
229 | args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); | ||
230 | args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); | ||
231 | args["destination_name"] = OSD.FromString(destination.RegionName); | ||
232 | args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); | ||
233 | |||
234 | OSDMap result = WebUtil.PutToServiceCompressed(uri, args, timeout); | ||
235 | if (result["Success"].AsBoolean()) | ||
236 | return true; | ||
237 | |||
238 | result = WebUtil.PutToService(uri, args, timeout); | ||
239 | |||
240 | return result["Success"].AsBoolean(); | ||
241 | } | ||
242 | catch (Exception e) | ||
243 | { | ||
244 | m_log.Warn("[REMOTE SIMULATION CONNECTOR]: UpdateAgent failed with exception: " + e.ToString()); | ||
245 | } | ||
246 | |||
247 | return false; | ||
248 | } | ||
249 | |||
250 | /// <summary> | ||
251 | /// Not sure what sequence causes this function to be invoked. The only calling | ||
252 | /// path is through the GET method | ||
253 | /// </summary> | ||
254 | public bool RetrieveAgent(GridRegion destination, UUID id, out IAgentData agent) | ||
255 | { | ||
256 | // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: RetrieveAgent start"); | ||
257 | |||
258 | agent = null; | ||
259 | |||
260 | // Eventually, we want to use a caps url instead of the agentID | ||
261 | string uri = destination.ServerURI + AgentPath() + id + "/" + destination.RegionID.ToString() + "/"; | ||
262 | |||
263 | try | ||
264 | { | ||
265 | OSDMap result = WebUtil.GetFromService(uri, 10000); | ||
266 | if (result["Success"].AsBoolean()) | ||
267 | { | ||
268 | // OSDMap args = Util.GetOSDMap(result["_RawResult"].AsString()); | ||
269 | OSDMap args = (OSDMap)result["_Result"]; | ||
270 | if (args != null) | ||
271 | { | ||
272 | agent = new CompleteAgentData(); | ||
273 | agent.Unpack(args, null); | ||
274 | return true; | ||
275 | } | ||
276 | } | ||
277 | } | ||
278 | catch (Exception e) | ||
279 | { | ||
280 | m_log.Warn("[REMOTE SIMULATION CONNECTOR]: UpdateAgent failed with exception: " + e.ToString()); | ||
281 | } | ||
282 | |||
283 | return false; | ||
284 | } | ||
285 | |||
286 | /// <summary> | ||
287 | /// </summary> | ||
288 | public bool QueryAccess(GridRegion destination, UUID id, Vector3 position, out string version, out string reason) | ||
289 | { | ||
290 | reason = "Failed to contact destination"; | ||
291 | version = "Unknown"; | ||
292 | |||
293 | // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: QueryAccess start, position={0}", position); | ||
294 | |||
295 | IPEndPoint ext = destination.ExternalEndPoint; | ||
296 | if (ext == null) return false; | ||
297 | |||
298 | // Eventually, we want to use a caps url instead of the agentID | ||
299 | string uri = destination.ServerURI + AgentPath() + id + "/" + destination.RegionID.ToString() + "/"; | ||
300 | |||
301 | OSDMap request = new OSDMap(); | ||
302 | request.Add("position", OSD.FromString(position.ToString())); | ||
303 | |||
304 | try | ||
305 | { | ||
306 | OSDMap result = WebUtil.ServiceOSDRequest(uri, request, "QUERYACCESS", 10000, false); | ||
307 | bool success = result["success"].AsBoolean(); | ||
308 | if (result.ContainsKey("_Result")) | ||
309 | { | ||
310 | OSDMap data = (OSDMap)result["_Result"]; | ||
311 | |||
312 | reason = data["reason"].AsString(); | ||
313 | if (data["version"] != null && data["version"].AsString() != string.Empty) | ||
314 | version = data["version"].AsString(); | ||
315 | |||
316 | m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: QueryAccess to {0} returned {1} version {2} ({3})", uri, success, version, data["version"].AsString()); | ||
317 | } | ||
318 | |||
319 | if (!success) | ||
320 | { | ||
321 | if (result.ContainsKey("Message")) | ||
322 | { | ||
323 | string message = result["Message"].AsString(); | ||
324 | if (message == "Service request failed: [MethodNotAllowed] MethodNotAllowed") // Old style region | ||
325 | { | ||
326 | m_log.Info("[REMOTE SIMULATION CONNECTOR]: The above web util error was caused by a TP to a sim that doesn't support QUERYACCESS and can be ignored"); | ||
327 | return true; | ||
328 | } | ||
329 | |||
330 | reason = result["Message"]; | ||
331 | } | ||
332 | else | ||
333 | { | ||
334 | reason = "Communications failure"; | ||
335 | } | ||
336 | |||
337 | return false; | ||
338 | } | ||
339 | |||
340 | OSDMap resp = (OSDMap)result["_Result"]; | ||
341 | success = resp["success"].AsBoolean(); | ||
342 | reason = resp["reason"].AsString(); | ||
343 | |||
344 | return success; | ||
345 | } | ||
346 | catch (Exception e) | ||
347 | { | ||
348 | m_log.WarnFormat("[REMOTE SIMULATION CONNECTOR] QueryAcess failed with exception; {0}",e.ToString()); | ||
349 | } | ||
350 | |||
351 | return false; | ||
352 | } | ||
353 | |||
354 | /// <summary> | ||
355 | /// </summary> | ||
356 | public bool ReleaseAgent(UUID origin, UUID id, string uri) | ||
357 | { | ||
358 | // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: ReleaseAgent start"); | ||
359 | |||
360 | try | ||
361 | { | ||
362 | WebUtil.ServiceOSDRequest(uri, null, "DELETE", 10000, false); | ||
363 | } | ||
364 | catch (Exception e) | ||
365 | { | ||
366 | m_log.WarnFormat("[REMOTE SIMULATION CONNECTOR] ReleaseAgent failed with exception; {0}",e.ToString()); | ||
367 | } | ||
368 | |||
369 | return true; | ||
370 | } | ||
371 | |||
372 | private bool CloseAgent(GridRegion destination, UUID id, bool ChildOnly) | ||
373 | { | ||
374 | // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: CloseAgent start"); | ||
375 | |||
376 | string uri = destination.ServerURI + AgentPath() + id + "/" + destination.RegionID.ToString() + "/"; | ||
377 | |||
378 | try | ||
379 | { | ||
380 | WebUtil.ServiceOSDRequest(uri, null, "DELETE", 10000, false); | ||
381 | } | ||
382 | catch (Exception e) | ||
383 | { | ||
384 | m_log.WarnFormat("[REMOTE SIMULATION CONNECTOR] CloseAgent failed with exception; {0}",e.ToString()); | ||
385 | } | ||
386 | |||
387 | return true; | ||
388 | } | ||
389 | |||
390 | public bool CloseChildAgent(GridRegion destination, UUID id) | ||
391 | { | ||
392 | return CloseAgent(destination, id, true); | ||
393 | } | ||
394 | |||
395 | public bool CloseAgent(GridRegion destination, UUID id) | ||
396 | { | ||
397 | return CloseAgent(destination, id, false); | ||
398 | } | ||
399 | |||
400 | #endregion Agents | ||
401 | |||
402 | #region Objects | ||
403 | |||
404 | protected virtual string ObjectPath() | ||
405 | { | ||
406 | return "object/"; | ||
407 | } | ||
408 | |||
409 | /// <summary> | ||
410 | /// | ||
411 | /// </summary> | ||
412 | public bool CreateObject(GridRegion destination, ISceneObject sog, bool isLocalCall) | ||
413 | { | ||
414 | // m_log.DebugFormat("[REMOTE SIMULATION CONNECTOR]: CreateObject start"); | ||
415 | |||
416 | string uri = destination.ServerURI + ObjectPath() + sog.UUID + "/"; | ||
417 | |||
418 | try | ||
419 | { | ||
420 | OSDMap args = new OSDMap(2); | ||
421 | |||
422 | args["sog"] = OSD.FromString(sog.ToXml2()); | ||
423 | args["extra"] = OSD.FromString(sog.ExtraToXmlString()); | ||
424 | args["modified"] = OSD.FromBoolean(sog.HasGroupChanged); | ||
425 | |||
426 | string state = sog.GetStateSnapshot(); | ||
427 | if (state.Length > 0) | ||
428 | args["state"] = OSD.FromString(state); | ||
429 | |||
430 | // Add the input general arguments | ||
431 | args["destination_x"] = OSD.FromString(destination.RegionLocX.ToString()); | ||
432 | args["destination_y"] = OSD.FromString(destination.RegionLocY.ToString()); | ||
433 | args["destination_name"] = OSD.FromString(destination.RegionName); | ||
434 | args["destination_uuid"] = OSD.FromString(destination.RegionID.ToString()); | ||
435 | |||
436 | WebUtil.PostToService(uri, args, 40000); | ||
437 | } | ||
438 | catch (Exception e) | ||
439 | { | ||
440 | m_log.WarnFormat("[REMOTE SIMULATION CONNECTOR] CreateObject failed with exception; {0}",e.ToString()); | ||
441 | } | ||
442 | |||
443 | return true; | ||
444 | } | ||
445 | |||
446 | /// <summary> | ||
447 | /// | ||
448 | /// </summary> | ||
449 | public bool CreateObject(GridRegion destination, UUID userID, UUID itemID) | ||
450 | { | ||
451 | // TODO, not that urgent | ||
452 | return false; | ||
453 | } | ||
454 | |||
455 | #endregion Objects | ||
456 | } | ||
457 | } | ||
diff --git a/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs b/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs new file mode 100644 index 0000000..60f3abe --- /dev/null +++ b/OpenSim/Services/Connectors/UserAccounts/UserAccountServiceConnector.cs | |||
@@ -0,0 +1,282 @@ | |||
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 | |||
28 | using log4net; | ||
29 | using System; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Reflection; | ||
33 | using Nini.Config; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Communications; | ||
36 | using OpenSim.Server.Base; | ||
37 | using OpenSim.Services.Interfaces; | ||
38 | using OpenMetaverse; | ||
39 | |||
40 | namespace OpenSim.Services.Connectors | ||
41 | { | ||
42 | public class UserAccountServicesConnector : IUserAccountService | ||
43 | { | ||
44 | private static readonly ILog m_log = | ||
45 | LogManager.GetLogger( | ||
46 | MethodBase.GetCurrentMethod().DeclaringType); | ||
47 | |||
48 | private string m_ServerURI = String.Empty; | ||
49 | |||
50 | public UserAccountServicesConnector() | ||
51 | { | ||
52 | } | ||
53 | |||
54 | public UserAccountServicesConnector(string serverURI) | ||
55 | { | ||
56 | m_ServerURI = serverURI.TrimEnd('/'); | ||
57 | } | ||
58 | |||
59 | public UserAccountServicesConnector(IConfigSource source) | ||
60 | { | ||
61 | Initialise(source); | ||
62 | } | ||
63 | |||
64 | public virtual void Initialise(IConfigSource source) | ||
65 | { | ||
66 | IConfig assetConfig = source.Configs["UserAccountService"]; | ||
67 | if (assetConfig == null) | ||
68 | { | ||
69 | m_log.Error("[ACCOUNT CONNECTOR]: UserAccountService missing from OpenSim.ini"); | ||
70 | throw new Exception("User account connector init error"); | ||
71 | } | ||
72 | |||
73 | string serviceURI = assetConfig.GetString("UserAccountServerURI", | ||
74 | String.Empty); | ||
75 | |||
76 | if (serviceURI == String.Empty) | ||
77 | { | ||
78 | m_log.Error("[ACCOUNT CONNECTOR]: No Server URI named in section UserAccountService"); | ||
79 | throw new Exception("User account connector init error"); | ||
80 | } | ||
81 | m_ServerURI = serviceURI; | ||
82 | } | ||
83 | |||
84 | public virtual UserAccount GetUserAccount(UUID scopeID, string firstName, string lastName) | ||
85 | { | ||
86 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
87 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
88 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
89 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
90 | sendData["METHOD"] = "getaccount"; | ||
91 | |||
92 | sendData["ScopeID"] = scopeID; | ||
93 | sendData["FirstName"] = firstName.ToString(); | ||
94 | sendData["LastName"] = lastName.ToString(); | ||
95 | |||
96 | return SendAndGetReply(sendData); | ||
97 | } | ||
98 | |||
99 | public virtual UserAccount GetUserAccount(UUID scopeID, string email) | ||
100 | { | ||
101 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
102 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
103 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
104 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
105 | sendData["METHOD"] = "getaccount"; | ||
106 | |||
107 | sendData["ScopeID"] = scopeID; | ||
108 | sendData["Email"] = email; | ||
109 | |||
110 | return SendAndGetReply(sendData); | ||
111 | } | ||
112 | |||
113 | public virtual UserAccount GetUserAccount(UUID scopeID, UUID userID) | ||
114 | { | ||
115 | //m_log.DebugFormat("[ACCOUNTS CONNECTOR]: GetUserAccount {0}", userID); | ||
116 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
117 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
118 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
119 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
120 | sendData["METHOD"] = "getaccount"; | ||
121 | |||
122 | sendData["ScopeID"] = scopeID; | ||
123 | sendData["UserID"] = userID.ToString(); | ||
124 | |||
125 | return SendAndGetReply(sendData); | ||
126 | } | ||
127 | |||
128 | public List<UserAccount> GetUserAccounts(UUID scopeID, string query) | ||
129 | { | ||
130 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
131 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
132 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
133 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
134 | sendData["METHOD"] = "getaccounts"; | ||
135 | |||
136 | sendData["ScopeID"] = scopeID.ToString(); | ||
137 | sendData["query"] = query; | ||
138 | |||
139 | string reply = string.Empty; | ||
140 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
141 | // m_log.DebugFormat("[ACCOUNTS CONNECTOR]: queryString = {0}", reqString); | ||
142 | try | ||
143 | { | ||
144 | reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
145 | m_ServerURI + "/accounts", | ||
146 | reqString); | ||
147 | if (reply == null || (reply != null && reply == string.Empty)) | ||
148 | { | ||
149 | m_log.DebugFormat("[ACCOUNT CONNECTOR]: GetUserAccounts received null or empty reply"); | ||
150 | return null; | ||
151 | } | ||
152 | } | ||
153 | catch (Exception e) | ||
154 | { | ||
155 | m_log.DebugFormat("[ACCOUNT CONNECTOR]: Exception when contacting accounts server: {0}", e.Message); | ||
156 | } | ||
157 | |||
158 | List<UserAccount> accounts = new List<UserAccount>(); | ||
159 | |||
160 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
161 | |||
162 | if (replyData != null) | ||
163 | { | ||
164 | if (replyData.ContainsKey("result") && replyData.ContainsKey("result").ToString() == "null") | ||
165 | { | ||
166 | return accounts; | ||
167 | } | ||
168 | |||
169 | Dictionary<string, object>.ValueCollection accountList = replyData.Values; | ||
170 | //m_log.DebugFormat("[ACCOUNTS CONNECTOR]: GetAgents returned {0} elements", pinfosList.Count); | ||
171 | foreach (object acc in accountList) | ||
172 | { | ||
173 | if (acc is Dictionary<string, object>) | ||
174 | { | ||
175 | UserAccount pinfo = new UserAccount((Dictionary<string, object>)acc); | ||
176 | accounts.Add(pinfo); | ||
177 | } | ||
178 | else | ||
179 | m_log.DebugFormat("[ACCOUNT CONNECTOR]: GetUserAccounts received invalid response type {0}", | ||
180 | acc.GetType()); | ||
181 | } | ||
182 | } | ||
183 | else | ||
184 | m_log.DebugFormat("[ACCOUNTS CONNECTOR]: GetUserAccounts received null response"); | ||
185 | |||
186 | return accounts; | ||
187 | } | ||
188 | |||
189 | public List<UserAccount> GetUserAccountsWhere(UUID scopeID, string where) | ||
190 | { | ||
191 | return null; // Not implemented for regions | ||
192 | } | ||
193 | |||
194 | public virtual bool StoreUserAccount(UserAccount data) | ||
195 | { | ||
196 | Dictionary<string, object> sendData = new Dictionary<string, object>(); | ||
197 | //sendData["SCOPEID"] = scopeID.ToString(); | ||
198 | sendData["VERSIONMIN"] = ProtocolVersions.ClientProtocolVersionMin.ToString(); | ||
199 | sendData["VERSIONMAX"] = ProtocolVersions.ClientProtocolVersionMax.ToString(); | ||
200 | sendData["METHOD"] = "setaccount"; | ||
201 | |||
202 | Dictionary<string, object> structData = data.ToKeyValuePairs(); | ||
203 | |||
204 | foreach (KeyValuePair<string,object> kvp in structData) | ||
205 | sendData[kvp.Key] = kvp.Value.ToString(); | ||
206 | |||
207 | return SendAndGetBoolReply(sendData); | ||
208 | } | ||
209 | |||
210 | private UserAccount SendAndGetReply(Dictionary<string, object> sendData) | ||
211 | { | ||
212 | string reply = string.Empty; | ||
213 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
214 | // m_log.DebugFormat("[ACCOUNTS CONNECTOR]: queryString = {0}", reqString); | ||
215 | try | ||
216 | { | ||
217 | reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
218 | m_ServerURI + "/accounts", | ||
219 | reqString); | ||
220 | if (reply == null || (reply != null && reply == string.Empty)) | ||
221 | { | ||
222 | m_log.DebugFormat("[ACCOUNT CONNECTOR]: GetUserAccount received null or empty reply"); | ||
223 | return null; | ||
224 | } | ||
225 | } | ||
226 | catch (Exception e) | ||
227 | { | ||
228 | m_log.DebugFormat("[ACCOUNT CONNECTOR]: Exception when contacting user account server: {0}", e.Message); | ||
229 | } | ||
230 | |||
231 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
232 | UserAccount account = null; | ||
233 | |||
234 | if ((replyData != null) && replyData.ContainsKey("result") && (replyData["result"] != null)) | ||
235 | { | ||
236 | if (replyData["result"] is Dictionary<string, object>) | ||
237 | { | ||
238 | account = new UserAccount((Dictionary<string, object>)replyData["result"]); | ||
239 | } | ||
240 | } | ||
241 | |||
242 | return account; | ||
243 | |||
244 | } | ||
245 | |||
246 | private bool SendAndGetBoolReply(Dictionary<string, object> sendData) | ||
247 | { | ||
248 | string reqString = ServerUtils.BuildQueryString(sendData); | ||
249 | // m_log.DebugFormat("[ACCOUNTS CONNECTOR]: queryString = {0}", reqString); | ||
250 | try | ||
251 | { | ||
252 | string reply = SynchronousRestFormsRequester.MakeRequest("POST", | ||
253 | m_ServerURI + "/accounts", | ||
254 | reqString); | ||
255 | if (reply != string.Empty) | ||
256 | { | ||
257 | Dictionary<string, object> replyData = ServerUtils.ParseXmlResponse(reply); | ||
258 | |||
259 | if (replyData.ContainsKey("result")) | ||
260 | { | ||
261 | if (replyData["result"].ToString().ToLower() == "success") | ||
262 | return true; | ||
263 | else | ||
264 | return false; | ||
265 | } | ||
266 | else | ||
267 | m_log.DebugFormat("[ACCOUNTS CONNECTOR]: Set or Create UserAccount reply data does not contain result field"); | ||
268 | |||
269 | } | ||
270 | else | ||
271 | m_log.DebugFormat("[ACCOUNTS CONNECTOR]: Set or Create UserAccount received empty reply"); | ||
272 | } | ||
273 | catch (Exception e) | ||
274 | { | ||
275 | m_log.DebugFormat("[ACCOUNTS CONNECTOR]: Exception when contacting user account server: {0}", e.Message); | ||
276 | } | ||
277 | |||
278 | return false; | ||
279 | } | ||
280 | |||
281 | } | ||
282 | } | ||
diff --git a/OpenSim/Services/FreeswitchService/FreeswitchService.cs b/OpenSim/Services/FreeswitchService/FreeswitchService.cs index 0a38300..201e72f 100644 --- a/OpenSim/Services/FreeswitchService/FreeswitchService.cs +++ b/OpenSim/Services/FreeswitchService/FreeswitchService.cs | |||
@@ -26,6 +26,7 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Text; | ||
29 | using System.Reflection; | 30 | using System.Reflection; |
30 | using Nini.Config; | 31 | using Nini.Config; |
31 | using log4net; | 32 | using log4net; |
@@ -33,19 +34,374 @@ using OpenSim.Framework; | |||
33 | using OpenSim.Data; | 34 | using OpenSim.Data; |
34 | using OpenSim.Services.Interfaces; | 35 | using OpenSim.Services.Interfaces; |
35 | using OpenMetaverse; | 36 | using OpenMetaverse; |
37 | using OpenMetaverse.StructuredData; | ||
38 | using System.Collections; | ||
36 | 39 | ||
37 | namespace OpenSim.Services.FreeswitchService | 40 | namespace OpenSim.Services.FreeswitchService |
38 | { | 41 | { |
39 | public class FreeswitchService : FreeswitchServiceBase, IFreeswitchService | 42 | public class FreeswitchService : FreeswitchServiceBase, IFreeswitchService |
40 | { | 43 | { |
41 | //private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
42 | 45 | ||
43 | public FreeswitchService(IConfigSource config) : base(config) | 46 | public FreeswitchService(IConfigSource config) : base(config) |
44 | { | 47 | { |
45 | // Perform initilialization here | 48 | // Perform initilialization here |
46 | } | 49 | } |
47 | 50 | ||
51 | public Hashtable HandleDialplanRequest(Hashtable request) | ||
52 | { | ||
53 | m_log.DebugFormat("[FreeSwitchVoice]: HandleDialplanRequest called with {0}",request.ToString()); | ||
54 | |||
55 | Hashtable response = new Hashtable(); | ||
56 | |||
57 | // foreach (DictionaryEntry item in request) | ||
58 | // { | ||
59 | //// m_log.InfoFormat("[FreeSwitchDirectory]: requestBody item {0} {1}",item.Key, item.Value); | ||
60 | // } | ||
61 | |||
62 | string requestcontext = (string) request["Hunt-Context"]; | ||
63 | response["content_type"] = "text/xml"; | ||
64 | response["keepalive"] = false; | ||
65 | response["int_response_code"] = 200; | ||
66 | |||
67 | if (m_freeSwitchContext != String.Empty && m_freeSwitchContext != requestcontext) | ||
68 | { | ||
69 | m_log.Debug("[FreeSwitchDirectory]: returning empty as it's for another context"); | ||
70 | response["str_response_string"] = ""; | ||
71 | } | ||
72 | else | ||
73 | { | ||
74 | response["str_response_string"] = String.Format(@"<?xml version=""1.0"" encoding=""utf-8""?> | ||
75 | <document type=""freeswitch/xml""> | ||
76 | <section name=""dialplan""> | ||
77 | <context name=""{0}"">" + | ||
78 | |||
79 | /* <!-- dial via SIP uri --> | ||
80 | <extension name=""sip_uri""> | ||
81 | <condition field=""destination_number"" expression=""^sip:(.*)$""> | ||
82 | <action application=""bridge"" data=""sofia/${use_profile}/$1""/> | ||
83 | <!--<action application=""bridge"" data=""$1""/>--> | ||
84 | </condition> | ||
85 | </extension>*/ | ||
86 | |||
87 | @"<extension name=""opensim_conferences""> | ||
88 | <condition field=""destination_number"" expression=""^confctl-(.*)$""> | ||
89 | <action application=""answer""/> | ||
90 | <action application=""conference"" data=""$1-{1}@{0}""/> | ||
91 | </condition> | ||
92 | </extension> | ||
93 | |||
94 | <extension name=""opensim_conf""> | ||
95 | <condition field=""destination_number"" expression=""^conf-(.*)$""> | ||
96 | <action application=""answer""/> | ||
97 | <action application=""conference"" data=""$1-{1}@{0}""/> | ||
98 | </condition> | ||
99 | </extension> | ||
100 | |||
101 | <extension name=""avatar""> | ||
102 | <condition field=""destination_number"" expression=""^(x.*)$""> | ||
103 | <action application=""bridge"" data=""user/$1""/> | ||
104 | </condition> | ||
105 | </extension> | ||
106 | |||
107 | </context> | ||
108 | </section> | ||
109 | </document>", m_freeSwitchContext, m_freeSwitchRealm); | ||
110 | } | ||
111 | |||
112 | return response; | ||
113 | } | ||
114 | |||
115 | public Hashtable HandleDirectoryRequest(Hashtable request) | ||
116 | { | ||
117 | Hashtable response = new Hashtable(); | ||
118 | string domain = (string) request["domain"]; | ||
119 | if (domain != m_freeSwitchRealm) | ||
120 | { | ||
121 | response["content_type"] = "text/xml"; | ||
122 | response["keepalive"] = false; | ||
123 | response["int_response_code"] = 200; | ||
124 | response["str_response_string"] = ""; | ||
125 | } | ||
126 | else | ||
127 | { | ||
128 | // m_log.DebugFormat("[FreeSwitchDirectory]: HandleDirectoryRequest called with {0}",request.ToString()); | ||
129 | |||
130 | // information in the request we might be interested in | ||
131 | |||
132 | // Request 1 sip_auth for users account | ||
133 | |||
134 | //Event-Calling-Function=sofia_reg_parse_auth | ||
135 | //Event-Calling-Line-Number=1494 | ||
136 | //action=sip_auth | ||
137 | //sip_user_agent=Vivox-SDK-2.1.3010.6151-Mac%20(Feb-11-2009/16%3A42%3A41) | ||
138 | //sip_auth_username=xhZuXKmRpECyr2AARJYyGgg%3D%3D (==) | ||
139 | //sip_auth_realm=9.20.151.43 | ||
140 | //sip_contact_user=xhZuXKmRpECyr2AARJYyGgg%3D%3D (==) | ||
141 | //sip_contact_host=192.168.0.3 // this shouldnt really be a local IP, investigate STUN servers | ||
142 | //sip_to_user=xhZuXKmRpECyr2AARJYyGgg%3D%3D | ||
143 | //sip_to_host=9.20.151.43 | ||
144 | //sip_auth_method=REGISTER | ||
145 | //user=xhZuXKmRpECyr2AARJYyGgg%3D%3D | ||
146 | //domain=9.20.151.43 | ||
147 | //ip=9.167.220.137 // this is the correct IP rather than sip_contact_host above when through a vpn or NAT setup | ||
148 | |||
149 | // foreach (DictionaryEntry item in request) | ||
150 | // m_log.DebugFormat("[FreeSwitchDirectory]: requestBody item {0} {1}", item.Key, item.Value); | ||
151 | |||
152 | string eventCallingFunction = (string) request["Event-Calling-Function"]; | ||
153 | if (eventCallingFunction == null) | ||
154 | { | ||
155 | eventCallingFunction = "sofia_reg_parse_auth"; | ||
156 | } | ||
157 | |||
158 | if (eventCallingFunction.Length == 0) | ||
159 | { | ||
160 | eventCallingFunction = "sofia_reg_parse_auth"; | ||
161 | } | ||
162 | |||
163 | if (eventCallingFunction == "sofia_reg_parse_auth") | ||
164 | { | ||
165 | string sipAuthMethod = (string)request["sip_auth_method"]; | ||
166 | |||
167 | if (sipAuthMethod == "REGISTER") | ||
168 | { | ||
169 | response = HandleRegister(m_freeSwitchContext, m_freeSwitchRealm, request); | ||
170 | } | ||
171 | else if (sipAuthMethod == "INVITE") | ||
172 | { | ||
173 | response = HandleInvite(m_freeSwitchContext, m_freeSwitchRealm, request); | ||
174 | } | ||
175 | else | ||
176 | { | ||
177 | m_log.ErrorFormat("[FreeSwitchVoice]: HandleDirectoryRequest unknown sip_auth_method {0}",sipAuthMethod); | ||
178 | response["int_response_code"] = 404; | ||
179 | response["content_type"] = "text/xml"; | ||
180 | response["str_response_string"] = ""; | ||
181 | } | ||
182 | } | ||
183 | else if (eventCallingFunction == "switch_xml_locate_user") | ||
184 | { | ||
185 | response = HandleLocateUser(m_freeSwitchRealm, request); | ||
186 | } | ||
187 | else if (eventCallingFunction == "user_data_function") // gets called when an avatar to avatar call is made | ||
188 | { | ||
189 | response = HandleLocateUser(m_freeSwitchRealm, request); | ||
190 | } | ||
191 | else if (eventCallingFunction == "user_outgoing_channel") | ||
192 | { | ||
193 | response = HandleRegister(m_freeSwitchContext, m_freeSwitchRealm, request); | ||
194 | } | ||
195 | else if (eventCallingFunction == "config_sofia") // happens once on freeswitch startup | ||
196 | { | ||
197 | response = HandleConfigSofia(m_freeSwitchContext, m_freeSwitchRealm, request); | ||
198 | } | ||
199 | else if (eventCallingFunction == "switch_load_network_lists") | ||
200 | { | ||
201 | //response = HandleLoadNetworkLists(request); | ||
202 | response["int_response_code"] = 404; | ||
203 | response["keepalive"] = false; | ||
204 | response["content_type"] = "text/xml"; | ||
205 | response["str_response_string"] = ""; | ||
206 | } | ||
207 | else | ||
208 | { | ||
209 | m_log.ErrorFormat("[FreeSwitchVoice]: HandleDirectoryRequest unknown Event-Calling-Function {0}",eventCallingFunction); | ||
210 | response["int_response_code"] = 404; | ||
211 | response["keepalive"] = false; | ||
212 | response["content_type"] = "text/xml"; | ||
213 | response["str_response_string"] = ""; | ||
214 | } | ||
215 | } | ||
216 | return response; | ||
217 | } | ||
218 | |||
219 | private Hashtable HandleRegister(string Context, string Realm, Hashtable request) | ||
220 | { | ||
221 | m_log.Info("[FreeSwitchDirectory]: HandleRegister called"); | ||
222 | |||
223 | // TODO the password we return needs to match that sent in the request, this is hard coded for now | ||
224 | string password = "1234"; | ||
225 | string domain = (string) request["domain"]; | ||
226 | string user = (string) request["user"]; | ||
227 | |||
228 | Hashtable response = new Hashtable(); | ||
229 | response["content_type"] = "text/xml"; | ||
230 | response["keepalive"] = false; | ||
231 | response["int_response_code"] = 200; | ||
232 | |||
233 | response["str_response_string"] = String.Format( | ||
234 | "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" + | ||
235 | "<document type=\"freeswitch/xml\">\r\n" + | ||
236 | "<section name=\"directory\" description=\"User Directory\">\r\n" + | ||
237 | "<domain name=\"{0}\">\r\n" + | ||
238 | "<user id=\"{1}\">\r\n" + | ||
239 | "<params>\r\n" + | ||
240 | "<param name=\"password\" value=\"{2}\" />\r\n" + | ||
241 | "<param name=\"dial-string\" value=\"{{sip_contact_user={1}}}{{presence_id=${{dialed_user}}@${{dialed_domain}}}}${{sofia_contact(${{dialed_user}}@${{dialed_domain}})}}\"/>\r\n" + | ||
242 | "</params>\r\n" + | ||
243 | "<variables>\r\n" + | ||
244 | "<variable name=\"user_context\" value=\"{3}\" />\r\n" + | ||
245 | "<variable name=\"presence_id\" value=\"{1}@{0}\"/>"+ | ||
246 | "</variables>\r\n" + | ||
247 | "</user>\r\n" + | ||
248 | "</domain>\r\n" + | ||
249 | "</section>\r\n" + | ||
250 | "</document>\r\n", | ||
251 | domain , user, password, Context); | ||
252 | |||
253 | return response; | ||
254 | } | ||
255 | |||
256 | private Hashtable HandleInvite(string Context, string Realm, Hashtable request) | ||
257 | { | ||
258 | m_log.Info("[FreeSwitchDirectory]: HandleInvite called"); | ||
259 | |||
260 | // TODO the password we return needs to match that sent in the request, this is hard coded for now | ||
261 | string password = "1234"; | ||
262 | string domain = (string) request["domain"]; | ||
263 | string user = (string) request["user"]; | ||
264 | string sipRequestUser = (string) request["sip_request_user"]; | ||
265 | |||
266 | Hashtable response = new Hashtable(); | ||
267 | response["content_type"] = "text/xml"; | ||
268 | response["keepalive"] = false; | ||
269 | response["int_response_code"] = 200; | ||
270 | response["str_response_string"] = String.Format( | ||
271 | "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" + | ||
272 | "<document type=\"freeswitch/xml\">\r\n" + | ||
273 | "<section name=\"directory\" description=\"User Directory\">\r\n" + | ||
274 | "<domain name=\"{0}\">\r\n" + | ||
275 | "<user id=\"{1}\">\r\n" + | ||
276 | "<params>\r\n" + | ||
277 | "<param name=\"password\" value=\"{2}\" />\r\n" + | ||
278 | "<param name=\"dial-string\" value=\"{{sip_contact_user={1}}}{{presence_id=${1}@${{dialed_domain}}}}${{sofia_contact(${1}@${{dialed_domain}})}}\"/>\r\n" + | ||
279 | "</params>\r\n" + | ||
280 | "<variables>\r\n" + | ||
281 | "<variable name=\"user_context\" value=\"{4}\" />\r\n" + | ||
282 | "<variable name=\"presence_id\" value=\"{1}@$${{domain}}\"/>"+ | ||
283 | "</variables>\r\n" + | ||
284 | "</user>\r\n" + | ||
285 | "<user id=\"{3}\">\r\n" + | ||
286 | "<params>\r\n" + | ||
287 | "<param name=\"password\" value=\"{2}\" />\r\n" + | ||
288 | "<param name=\"dial-string\" value=\"{{sip_contact_user={1}}}{{presence_id=${3}@${{dialed_domain}}}}${{sofia_contact(${3}@${{dialed_domain}})}}\"/>\r\n" + | ||
289 | "</params>\r\n" + | ||
290 | "<variables>\r\n" + | ||
291 | "<variable name=\"user_context\" value=\"{4}\" />\r\n" + | ||
292 | "<variable name=\"presence_id\" value=\"{3}@$${{domain}}\"/>"+ | ||
293 | "</variables>\r\n" + | ||
294 | "</user>\r\n" + | ||
295 | "</domain>\r\n" + | ||
296 | "</section>\r\n" + | ||
297 | "</document>\r\n", | ||
298 | domain , user, password,sipRequestUser, Context); | ||
299 | |||
300 | return response; | ||
301 | } | ||
48 | 302 | ||
49 | // Implement IFreeswitchService here | 303 | private Hashtable HandleLocateUser(String Realm, Hashtable request) |
304 | { | ||
305 | m_log.Info("[FreeSwitchDirectory]: HandleLocateUser called"); | ||
306 | |||
307 | // TODO the password we return needs to match that sent in the request, this is hard coded for now | ||
308 | string domain = (string) request["domain"]; | ||
309 | string user = (string) request["user"]; | ||
310 | |||
311 | Hashtable response = new Hashtable(); | ||
312 | response["content_type"] = "text/xml"; | ||
313 | response["keepalive"] = false; | ||
314 | response["int_response_code"] = 200; | ||
315 | response["str_response_string"] = String.Format( | ||
316 | "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" + | ||
317 | "<document type=\"freeswitch/xml\">\r\n" + | ||
318 | "<section name=\"directory\" description=\"User Directory\">\r\n" + | ||
319 | "<domain name=\"{0}\">\r\n" + | ||
320 | "<params>\r\n" + | ||
321 | "<param name=\"dial-string\" value=\"{{sip_contact_user=${{dialed_user}}}}{{presence_id=${{dialed_user}}@${{dialed_domain}}}}${{sofia_contact(${{dialed_user}}@${{dialed_domain}})}}\"/>\r\n" + | ||
322 | "</params>\r\n" + | ||
323 | "<user id=\"{1}\">\r\n" + | ||
324 | "<variables>\r\n"+ | ||
325 | "<variable name=\"default_gateway\" value=\"$${{default_provider}}\"/>\r\n"+ | ||
326 | "<variable name=\"presence_id\" value=\"{1}@$${{domain}}\"/>"+ | ||
327 | "</variables>\r\n"+ | ||
328 | "</user>\r\n" + | ||
329 | "</domain>\r\n" + | ||
330 | "</section>\r\n" + | ||
331 | "</document>\r\n", | ||
332 | domain , user); | ||
333 | |||
334 | return response; | ||
335 | } | ||
336 | |||
337 | private Hashtable HandleConfigSofia(string Context, string Realm, Hashtable request) | ||
338 | { | ||
339 | m_log.Info("[FreeSwitchDirectory]: HandleConfigSofia called."); | ||
340 | |||
341 | // TODO the password we return needs to match that sent in the request, this is hard coded for now | ||
342 | string domain = (string) request["domain"]; | ||
343 | |||
344 | Hashtable response = new Hashtable(); | ||
345 | response["content_type"] = "text/xml"; | ||
346 | response["keepalive"] = false; | ||
347 | response["int_response_code"] = 200; | ||
348 | response["str_response_string"] = String.Format( | ||
349 | "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n" + | ||
350 | "<document type=\"freeswitch/xml\">\r\n" + | ||
351 | "<section name=\"directory\" description=\"User Directory\">\r\n" + | ||
352 | "<domain name=\"{0}\">\r\n" + | ||
353 | "<params>\r\n" + | ||
354 | "<param name=\"dial-string\" value=\"{{sip_contact_user=${{dialed_user}}}}{{presence_id=${{dialed_user}}@${{dialed_domain}}}}${{sofia_contact(${{dialed_user}}@${{dialed_domain}})}}\"/>\r\n" + | ||
355 | "</params>\r\n" + | ||
356 | "<groups name=\"default\">\r\n"+ | ||
357 | "<users>\r\n"+ | ||
358 | "<user id=\"$${{default_provider}}\">\r\n"+ | ||
359 | "<gateways>\r\n"+ | ||
360 | "<gateway name=\"$${{default_provider}}\">\r\n"+ | ||
361 | "<param name=\"username\" value=\"$${{default_provider_username}}\"/>\r\n"+ | ||
362 | "<param name=\"password\" value=\"$${{default_provider_password}}\"/>\r\n"+ | ||
363 | "<param name=\"from-user\" value=\"$${{default_provider_username}}\"/>\r\n"+ | ||
364 | "<param name=\"from-domain\" value=\"$${{default_provider_from_domain}}\"/>\r\n"+ | ||
365 | "<param name=\"expire-seconds\" value=\"600\"/>\r\n"+ | ||
366 | "<param name=\"register\" value=\"$${{default_provider_register}}\"/>\r\n"+ | ||
367 | "<param name=\"retry-seconds\" value=\"30\"/>\r\n"+ | ||
368 | "<param name=\"extension\" value=\"$${{default_provider_contact}}\"/>\r\n"+ | ||
369 | "<param name=\"contact-params\" value=\"domain_name=$${{domain}}\"/>\r\n"+ | ||
370 | "<param name=\"context\" value=\"{1}\"/>\r\n"+ | ||
371 | "</gateway>\r\n"+ | ||
372 | "</gateways>\r\n"+ | ||
373 | "<params>\r\n"+ | ||
374 | "<param name=\"password\" value=\"$${{default_provider_password}}\"/>\r\n"+ | ||
375 | "</params>\r\n"+ | ||
376 | "</user>\r\n"+ | ||
377 | "</users>"+ | ||
378 | "</groups>\r\n" + | ||
379 | "<variables>\r\n"+ | ||
380 | "<variable name=\"default_gateway\" value=\"$${{default_provider}}\"/>\r\n"+ | ||
381 | "</variables>\r\n"+ | ||
382 | "</domain>\r\n" + | ||
383 | "</section>\r\n" + | ||
384 | "</document>\r\n", | ||
385 | domain, Context); | ||
386 | |||
387 | return response; | ||
388 | } | ||
389 | |||
390 | public string GetJsonConfig() | ||
391 | { | ||
392 | OSDMap map = new OSDMap(9); | ||
393 | |||
394 | map.Add("Realm", m_freeSwitchRealm); | ||
395 | map.Add("SIPProxy", m_freeSwitchSIPProxy); | ||
396 | map.Add("AttemptUseSTUN", m_freeSwitchAttemptUseSTUN); | ||
397 | map.Add("EchoServer", m_freeSwitchEchoServer); | ||
398 | map.Add("EchoPort", m_freeSwitchEchoPort); | ||
399 | map.Add("DefaultWellKnownIP", m_freeSwitchDefaultWellKnownIP); | ||
400 | map.Add("DefaultTimeout", m_freeSwitchDefaultTimeout); | ||
401 | map.Add("Context", m_freeSwitchContext); | ||
402 | map.Add("APIPrefix", m_freeSwitchAPIPrefix); | ||
403 | |||
404 | return OSDParser.SerializeJsonString(map); | ||
405 | } | ||
50 | } | 406 | } |
51 | } | 407 | } |
diff --git a/OpenSim/Services/FreeswitchService/FreeswitchServiceBase.cs b/OpenSim/Services/FreeswitchService/FreeswitchServiceBase.cs index 83fecef..25c18b6 100644 --- a/OpenSim/Services/FreeswitchService/FreeswitchServiceBase.cs +++ b/OpenSim/Services/FreeswitchService/FreeswitchServiceBase.cs | |||
@@ -31,11 +31,28 @@ using Nini.Config; | |||
31 | using OpenSim.Framework; | 31 | using OpenSim.Framework; |
32 | using OpenSim.Services.Interfaces; | 32 | using OpenSim.Services.Interfaces; |
33 | using OpenSim.Services.Base; | 33 | using OpenSim.Services.Base; |
34 | using log4net; | ||
34 | 35 | ||
35 | namespace OpenSim.Services.FreeswitchService | 36 | namespace OpenSim.Services.FreeswitchService |
36 | { | 37 | { |
37 | public class FreeswitchServiceBase : ServiceBase | 38 | public class FreeswitchServiceBase : ServiceBase |
38 | { | 39 | { |
40 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
41 | |||
42 | protected string m_freeSwitchRealm; | ||
43 | protected string m_freeSwitchSIPProxy; | ||
44 | protected bool m_freeSwitchAttemptUseSTUN = false; | ||
45 | protected string m_freeSwitchEchoServer; | ||
46 | protected int m_freeSwitchEchoPort = 50505; | ||
47 | protected string m_freeSwitchDefaultWellKnownIP; | ||
48 | protected int m_freeSwitchDefaultTimeout = 5000; | ||
49 | protected string m_freeSwitchContext = "default"; | ||
50 | protected string m_freeSwitchServerUser = "freeswitch"; | ||
51 | protected string m_freeSwitchServerPass = "password"; | ||
52 | protected readonly string m_freeSwitchAPIPrefix = "/fsapi"; | ||
53 | |||
54 | protected bool m_Enabled = false; | ||
55 | |||
39 | public FreeswitchServiceBase(IConfigSource config) : base(config) | 56 | public FreeswitchServiceBase(IConfigSource config) : base(config) |
40 | { | 57 | { |
41 | // | 58 | // |
@@ -44,7 +61,24 @@ namespace OpenSim.Services.FreeswitchService | |||
44 | IConfig freeswitchConfig = config.Configs["FreeswitchService"]; | 61 | IConfig freeswitchConfig = config.Configs["FreeswitchService"]; |
45 | if (freeswitchConfig != null) | 62 | if (freeswitchConfig != null) |
46 | { | 63 | { |
47 | // Read config here !! | 64 | m_freeSwitchDefaultWellKnownIP = freeswitchConfig.GetString("ServerAddress", String.Empty); |
65 | if (m_freeSwitchDefaultWellKnownIP == String.Empty) | ||
66 | { | ||
67 | m_log.Error("[FREESWITCH]: No ServerAddress given, cannot start service."); | ||
68 | return; | ||
69 | } | ||
70 | |||
71 | m_freeSwitchRealm = freeswitchConfig.GetString("Realm", m_freeSwitchDefaultWellKnownIP); | ||
72 | m_freeSwitchSIPProxy = freeswitchConfig.GetString("SIPProxy", m_freeSwitchDefaultWellKnownIP + ":5060"); | ||
73 | m_freeSwitchEchoServer = freeswitchConfig.GetString("EchoServer", m_freeSwitchDefaultWellKnownIP); | ||
74 | m_freeSwitchEchoPort = freeswitchConfig.GetInt("EchoPort", m_freeSwitchEchoPort); | ||
75 | m_freeSwitchAttemptUseSTUN = freeswitchConfig.GetBoolean("AttemptSTUN", false); // This may not work | ||
76 | m_freeSwitchDefaultTimeout = freeswitchConfig.GetInt("DefaultTimeout", m_freeSwitchDefaultTimeout); | ||
77 | m_freeSwitchContext = freeswitchConfig.GetString("Context", m_freeSwitchContext); | ||
78 | m_freeSwitchServerUser = freeswitchConfig.GetString("UserName", m_freeSwitchServerUser); | ||
79 | m_freeSwitchServerPass = freeswitchConfig.GetString("Password", m_freeSwitchServerPass); | ||
80 | |||
81 | m_Enabled = true; | ||
48 | } | 82 | } |
49 | } | 83 | } |
50 | } | 84 | } |
diff --git a/OpenSim/Services/Friends/FriendsService.cs b/OpenSim/Services/Friends/FriendsService.cs new file mode 100644 index 0000000..e2033ac --- /dev/null +++ b/OpenSim/Services/Friends/FriendsService.cs | |||
@@ -0,0 +1,115 @@ | |||
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 | |||
28 | using OpenMetaverse; | ||
29 | using OpenSim.Framework; | ||
30 | using System; | ||
31 | using System.Collections.Generic; | ||
32 | using OpenSim.Services.Interfaces; | ||
33 | using OpenSim.Data; | ||
34 | using Nini.Config; | ||
35 | using log4net; | ||
36 | using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; | ||
37 | |||
38 | namespace OpenSim.Services.Friends | ||
39 | { | ||
40 | public class FriendsService : FriendsServiceBase, IFriendsService | ||
41 | { | ||
42 | public FriendsService(IConfigSource config) : base(config) | ||
43 | { | ||
44 | } | ||
45 | |||
46 | public virtual FriendInfo[] GetFriends(UUID PrincipalID) | ||
47 | { | ||
48 | FriendsData[] data = m_Database.GetFriends(PrincipalID); | ||
49 | List<FriendInfo> info = new List<FriendInfo>(); | ||
50 | |||
51 | foreach (FriendsData d in data) | ||
52 | { | ||
53 | FriendInfo i = new FriendInfo(); | ||
54 | |||
55 | i.PrincipalID = new UUID(d.PrincipalID); | ||
56 | i.Friend = d.Friend; | ||
57 | i.MyFlags = Convert.ToInt32(d.Data["Flags"]); | ||
58 | i.TheirFlags = Convert.ToInt32(d.Data["TheirFlags"]); | ||
59 | |||
60 | info.Add(i); | ||
61 | } | ||
62 | |||
63 | return info.ToArray(); | ||
64 | } | ||
65 | |||
66 | public virtual FriendInfo[] GetFriends(string PrincipalID) | ||
67 | { | ||
68 | FriendsData[] data = m_Database.GetFriends(PrincipalID); | ||
69 | List<FriendInfo> info = new List<FriendInfo>(); | ||
70 | |||
71 | foreach (FriendsData d in data) | ||
72 | { | ||
73 | FriendInfo i = new FriendInfo(); | ||
74 | |||
75 | if (!UUID.TryParse(d.PrincipalID, out i.PrincipalID)) | ||
76 | { | ||
77 | string tmp = string.Empty; | ||
78 | if (!Util.ParseUniversalUserIdentifier(d.PrincipalID, out i.PrincipalID, out tmp, out tmp, out tmp, out tmp)) | ||
79 | // bad record. ignore this entry | ||
80 | continue; | ||
81 | } | ||
82 | i.Friend = d.Friend; | ||
83 | i.MyFlags = Convert.ToInt32(d.Data["Flags"]); | ||
84 | i.TheirFlags = Convert.ToInt32(d.Data["TheirFlags"]); | ||
85 | |||
86 | info.Add(i); | ||
87 | } | ||
88 | |||
89 | return info.ToArray(); | ||
90 | } | ||
91 | |||
92 | public virtual bool StoreFriend(string PrincipalID, string Friend, int flags) | ||
93 | { | ||
94 | FriendsData d = new FriendsData(); | ||
95 | |||
96 | d.PrincipalID = PrincipalID; | ||
97 | d.Friend = Friend; | ||
98 | d.Data = new Dictionary<string, string>(); | ||
99 | d.Data["Flags"] = flags.ToString(); | ||
100 | |||
101 | return m_Database.Store(d); | ||
102 | } | ||
103 | |||
104 | public bool Delete(string principalID, string friend) | ||
105 | { | ||
106 | return m_Database.Delete(principalID, friend); | ||
107 | } | ||
108 | |||
109 | public virtual bool Delete(UUID PrincipalID, string Friend) | ||
110 | { | ||
111 | return m_Database.Delete(PrincipalID, Friend); | ||
112 | } | ||
113 | |||
114 | } | ||
115 | } | ||
diff --git a/OpenSim/Services/Friends/FriendsServiceBase.cs b/OpenSim/Services/Friends/FriendsServiceBase.cs new file mode 100644 index 0000000..6ab0bff --- /dev/null +++ b/OpenSim/Services/Friends/FriendsServiceBase.cs | |||
@@ -0,0 +1,89 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Reflection; | ||
30 | using log4net; | ||
31 | using Nini.Config; | ||
32 | using OpenSim.Framework; | ||
33 | using OpenSim.Data; | ||
34 | using OpenSim.Services.Interfaces; | ||
35 | using OpenSim.Services.Base; | ||
36 | |||
37 | namespace OpenSim.Services.Friends | ||
38 | { | ||
39 | public class FriendsServiceBase : ServiceBase | ||
40 | { | ||
41 | protected IFriendsData m_Database = null; | ||
42 | |||
43 | public FriendsServiceBase(IConfigSource config) : base(config) | ||
44 | { | ||
45 | string dllName = String.Empty; | ||
46 | string connString = String.Empty; | ||
47 | |||
48 | // | ||
49 | // Try reading the [FriendsService] section first, if it exists | ||
50 | // | ||
51 | IConfig friendsConfig = config.Configs["FriendsService"]; | ||
52 | if (friendsConfig != null) | ||
53 | { | ||
54 | dllName = friendsConfig.GetString("StorageProvider", dllName); | ||
55 | connString = friendsConfig.GetString("ConnectionString", connString); | ||
56 | } | ||
57 | |||
58 | // | ||
59 | // Try reading the [DatabaseService] section, if it exists | ||
60 | // | ||
61 | IConfig dbConfig = config.Configs["DatabaseService"]; | ||
62 | if (dbConfig != null) | ||
63 | { | ||
64 | if (dllName == String.Empty) | ||
65 | dllName = dbConfig.GetString("StorageProvider", String.Empty); | ||
66 | if (connString == String.Empty) | ||
67 | connString = dbConfig.GetString("ConnectionString", String.Empty); | ||
68 | } | ||
69 | |||
70 | // | ||
71 | // We tried, but this doesn't exist. We can't proceed. | ||
72 | // | ||
73 | if (String.Empty.Equals(dllName)) | ||
74 | throw new Exception("No StorageProvider configured"); | ||
75 | |||
76 | string realm = "Friends"; | ||
77 | if (friendsConfig != null) | ||
78 | realm = friendsConfig.GetString("Realm", realm); | ||
79 | |||
80 | m_Database = LoadPlugin<IFriendsData>(dllName, new Object[] { connString, realm }); | ||
81 | if (m_Database == null) | ||
82 | { | ||
83 | throw new Exception( | ||
84 | string.Format( | ||
85 | "Could not find a storage interface {0} in the given StorageProvider {1}", "IFriendsData", dllName)); | ||
86 | } | ||
87 | } | ||
88 | } | ||
89 | } | ||
diff --git a/OpenSim/Services/GridService/GridService.cs b/OpenSim/Services/GridService/GridService.cs index 7749c37..89f0716 100644 --- a/OpenSim/Services/GridService/GridService.cs +++ b/OpenSim/Services/GridService/GridService.cs | |||
@@ -34,6 +34,7 @@ using log4net; | |||
34 | using OpenSim.Framework; | 34 | using OpenSim.Framework; |
35 | using OpenSim.Framework.Console; | 35 | using OpenSim.Framework.Console; |
36 | using OpenSim.Data; | 36 | using OpenSim.Data; |
37 | using OpenSim.Server.Base; | ||
37 | using OpenSim.Services.Interfaces; | 38 | using OpenSim.Services.Interfaces; |
38 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | 39 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; |
39 | using OpenMetaverse; | 40 | using OpenMetaverse; |
@@ -46,17 +47,58 @@ namespace OpenSim.Services.GridService | |||
46 | LogManager.GetLogger( | 47 | LogManager.GetLogger( |
47 | MethodBase.GetCurrentMethod().DeclaringType); | 48 | MethodBase.GetCurrentMethod().DeclaringType); |
48 | 49 | ||
50 | private bool m_DeleteOnUnregister = true; | ||
51 | private static GridService m_RootInstance = null; | ||
52 | protected IConfigSource m_config; | ||
53 | protected static HypergridLinker m_HypergridLinker; | ||
54 | |||
55 | protected IAuthenticationService m_AuthenticationService = null; | ||
49 | protected bool m_AllowDuplicateNames = false; | 56 | protected bool m_AllowDuplicateNames = false; |
57 | protected bool m_AllowHypergridMapSearch = false; | ||
50 | 58 | ||
51 | public GridService(IConfigSource config) | 59 | public GridService(IConfigSource config) |
52 | : base(config) | 60 | : base(config) |
53 | { | 61 | { |
54 | m_log.DebugFormat("[GRID SERVICE]: Starting..."); | 62 | m_log.DebugFormat("[GRID SERVICE]: Starting..."); |
55 | 63 | ||
64 | m_config = config; | ||
56 | IConfig gridConfig = config.Configs["GridService"]; | 65 | IConfig gridConfig = config.Configs["GridService"]; |
57 | if (gridConfig != null) | 66 | if (gridConfig != null) |
58 | { | 67 | { |
68 | m_DeleteOnUnregister = gridConfig.GetBoolean("DeleteOnUnregister", true); | ||
69 | |||
70 | string authService = gridConfig.GetString("AuthenticationService", String.Empty); | ||
71 | |||
72 | if (authService != String.Empty) | ||
73 | { | ||
74 | Object[] args = new Object[] { config }; | ||
75 | m_AuthenticationService = ServerUtils.LoadPlugin<IAuthenticationService>(authService, args); | ||
76 | } | ||
59 | m_AllowDuplicateNames = gridConfig.GetBoolean("AllowDuplicateNames", m_AllowDuplicateNames); | 77 | m_AllowDuplicateNames = gridConfig.GetBoolean("AllowDuplicateNames", m_AllowDuplicateNames); |
78 | m_AllowHypergridMapSearch = gridConfig.GetBoolean("AllowHypergridMapSearch", m_AllowHypergridMapSearch); | ||
79 | } | ||
80 | |||
81 | if (m_RootInstance == null) | ||
82 | { | ||
83 | m_RootInstance = this; | ||
84 | |||
85 | if (MainConsole.Instance != null) | ||
86 | { | ||
87 | MainConsole.Instance.Commands.AddCommand("grid", true, | ||
88 | "show region", | ||
89 | "show region <Region name>", | ||
90 | "Show details on a region", | ||
91 | String.Empty, | ||
92 | HandleShowRegion); | ||
93 | |||
94 | MainConsole.Instance.Commands.AddCommand("grid", true, | ||
95 | "set region flags", | ||
96 | "set region flags <Region name> <flags>", | ||
97 | "Set database flags for region", | ||
98 | String.Empty, | ||
99 | HandleSetFlags); | ||
100 | } | ||
101 | m_HypergridLinker = new HypergridLinker(m_config, this, m_Database); | ||
60 | } | 102 | } |
61 | } | 103 | } |
62 | 104 | ||
@@ -64,18 +106,63 @@ namespace OpenSim.Services.GridService | |||
64 | 106 | ||
65 | public string RegisterRegion(UUID scopeID, GridRegion regionInfos) | 107 | public string RegisterRegion(UUID scopeID, GridRegion regionInfos) |
66 | { | 108 | { |
109 | IConfig gridConfig = m_config.Configs["GridService"]; | ||
110 | |||
111 | if (regionInfos.RegionID == UUID.Zero) | ||
112 | return "Invalid RegionID - cannot be zero UUID"; | ||
113 | |||
67 | // This needs better sanity testing. What if regionInfo is registering in | 114 | // This needs better sanity testing. What if regionInfo is registering in |
68 | // overlapping coords? | 115 | // overlapping coords? |
69 | RegionData region = m_Database.Get(regionInfos.RegionLocX, regionInfos.RegionLocY, scopeID); | 116 | RegionData region = m_Database.Get(regionInfos.RegionLocX, regionInfos.RegionLocY, scopeID); |
117 | if (region != null) | ||
118 | { | ||
119 | // There is a preexisting record | ||
120 | // | ||
121 | // Get it's flags | ||
122 | // | ||
123 | OpenSim.Data.RegionFlags rflags = (OpenSim.Data.RegionFlags)Convert.ToInt32(region.Data["flags"]); | ||
124 | |||
125 | // Is this a reservation? | ||
126 | // | ||
127 | if ((rflags & OpenSim.Data.RegionFlags.Reservation) != 0) | ||
128 | { | ||
129 | // Regions reserved for the null key cannot be taken. | ||
130 | if ((string)region.Data["PrincipalID"] == UUID.Zero.ToString()) | ||
131 | return "Region location is reserved"; | ||
132 | |||
133 | // Treat it as an auth request | ||
134 | // | ||
135 | // NOTE: Fudging the flags value here, so these flags | ||
136 | // should not be used elsewhere. Don't optimize | ||
137 | // this with the later retrieval of the same flags! | ||
138 | rflags |= OpenSim.Data.RegionFlags.Authenticate; | ||
139 | } | ||
140 | |||
141 | if ((rflags & OpenSim.Data.RegionFlags.Authenticate) != 0) | ||
142 | { | ||
143 | // Can we authenticate at all? | ||
144 | // | ||
145 | if (m_AuthenticationService == null) | ||
146 | return "No authentication possible"; | ||
147 | |||
148 | if (!m_AuthenticationService.Verify(new UUID(region.Data["PrincipalID"].ToString()), regionInfos.Token, 30)) | ||
149 | return "Bad authentication"; | ||
150 | } | ||
151 | } | ||
152 | |||
70 | if ((region != null) && (region.RegionID != regionInfos.RegionID)) | 153 | if ((region != null) && (region.RegionID != regionInfos.RegionID)) |
71 | { | 154 | { |
72 | m_log.WarnFormat("[GRID SERVICE]: Region {0} tried to register in coordinates {1}, {2} which are already in use in scope {3}.", | 155 | m_log.WarnFormat("[GRID SERVICE]: Region {0} tried to register in coordinates {1}, {2} which are already in use in scope {3}.", |
73 | regionInfos.RegionID, regionInfos.RegionLocX, regionInfos.RegionLocY, scopeID); | 156 | regionInfos.RegionID, regionInfos.RegionLocX, regionInfos.RegionLocY, scopeID); |
74 | return "Region overlaps another region"; | 157 | return "Region overlaps another region"; |
75 | } | 158 | } |
159 | |||
76 | if ((region != null) && (region.RegionID == regionInfos.RegionID) && | 160 | if ((region != null) && (region.RegionID == regionInfos.RegionID) && |
77 | ((region.posX != regionInfos.RegionLocX) || (region.posY != regionInfos.RegionLocY))) | 161 | ((region.posX != regionInfos.RegionLocX) || (region.posY != regionInfos.RegionLocY))) |
78 | { | 162 | { |
163 | if ((Convert.ToInt32(region.Data["flags"]) & (int)OpenSim.Data.RegionFlags.NoMove) != 0) | ||
164 | return "Can't move this region"; | ||
165 | |||
79 | // Region reregistering in other coordinates. Delete the old entry | 166 | // Region reregistering in other coordinates. Delete the old entry |
80 | m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) was previously registered at {2}-{3}. Deleting old entry.", | 167 | m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) was previously registered at {2}-{3}. Deleting old entry.", |
81 | regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionLocX, regionInfos.RegionLocY); | 168 | regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionLocX, regionInfos.RegionLocY); |
@@ -110,8 +197,38 @@ namespace OpenSim.Services.GridService | |||
110 | // Everything is ok, let's register | 197 | // Everything is ok, let's register |
111 | RegionData rdata = RegionInfo2RegionData(regionInfos); | 198 | RegionData rdata = RegionInfo2RegionData(regionInfos); |
112 | rdata.ScopeID = scopeID; | 199 | rdata.ScopeID = scopeID; |
200 | |||
201 | if (region != null) | ||
202 | { | ||
203 | int oldFlags = Convert.ToInt32(region.Data["flags"]); | ||
204 | if ((oldFlags & (int)OpenSim.Data.RegionFlags.LockedOut) != 0) | ||
205 | return "Region locked out"; | ||
206 | |||
207 | oldFlags &= ~(int)OpenSim.Data.RegionFlags.Reservation; | ||
208 | |||
209 | rdata.Data["flags"] = oldFlags.ToString(); // Preserve flags | ||
210 | } | ||
211 | else | ||
212 | { | ||
213 | rdata.Data["flags"] = "0"; | ||
214 | if ((gridConfig != null) && rdata.RegionName != string.Empty) | ||
215 | { | ||
216 | int newFlags = 0; | ||
217 | string regionName = rdata.RegionName.Trim().Replace(' ', '_'); | ||
218 | newFlags = ParseFlags(newFlags, gridConfig.GetString("DefaultRegionFlags", String.Empty)); | ||
219 | newFlags = ParseFlags(newFlags, gridConfig.GetString("Region_" + regionName, String.Empty)); | ||
220 | newFlags = ParseFlags(newFlags, gridConfig.GetString("Region_" + rdata.RegionID.ToString(), String.Empty)); | ||
221 | rdata.Data["flags"] = newFlags.ToString(); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | int flags = Convert.ToInt32(rdata.Data["flags"]); | ||
226 | flags |= (int)OpenSim.Data.RegionFlags.RegionOnline; | ||
227 | rdata.Data["flags"] = flags.ToString(); | ||
228 | |||
113 | try | 229 | try |
114 | { | 230 | { |
231 | rdata.Data["last_seen"] = Util.UnixTimeSinceEpoch(); | ||
115 | m_Database.Store(rdata); | 232 | m_Database.Store(rdata); |
116 | } | 233 | } |
117 | catch (Exception e) | 234 | catch (Exception e) |
@@ -120,14 +237,41 @@ namespace OpenSim.Services.GridService | |||
120 | } | 237 | } |
121 | 238 | ||
122 | m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) registered successfully at {2}-{3}", | 239 | m_log.DebugFormat("[GRID SERVICE]: Region {0} ({1}) registered successfully at {2}-{3}", |
123 | regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionLocX, regionInfos.RegionLocY); | 240 | regionInfos.RegionName, regionInfos.RegionID, regionInfos.RegionCoordX, regionInfos.RegionCoordY); |
124 | 241 | ||
125 | return String.Empty; | 242 | return String.Empty; |
126 | } | 243 | } |
127 | 244 | ||
128 | public bool DeregisterRegion(UUID regionID) | 245 | public bool DeregisterRegion(UUID regionID) |
129 | { | 246 | { |
130 | m_log.DebugFormat("[GRID SERVICE]: Region {0} deregistered", regionID); | 247 | RegionData region = m_Database.Get(regionID, UUID.Zero); |
248 | if (region == null) | ||
249 | return false; | ||
250 | |||
251 | m_log.DebugFormat( | ||
252 | "[GRID SERVICE]: Deregistering region {0} ({1}) at {2}-{3}", | ||
253 | region.RegionName, region.RegionID, region.coordX, region.coordY); | ||
254 | |||
255 | int flags = Convert.ToInt32(region.Data["flags"]); | ||
256 | |||
257 | if (!m_DeleteOnUnregister || (flags & (int)OpenSim.Data.RegionFlags.Persistent) != 0) | ||
258 | { | ||
259 | flags &= ~(int)OpenSim.Data.RegionFlags.RegionOnline; | ||
260 | region.Data["flags"] = flags.ToString(); | ||
261 | region.Data["last_seen"] = Util.UnixTimeSinceEpoch(); | ||
262 | try | ||
263 | { | ||
264 | m_Database.Store(region); | ||
265 | } | ||
266 | catch (Exception e) | ||
267 | { | ||
268 | m_log.DebugFormat("[GRID SERVICE]: Database exception: {0}", e); | ||
269 | } | ||
270 | |||
271 | return true; | ||
272 | |||
273 | } | ||
274 | |||
131 | return m_Database.Delete(regionID); | 275 | return m_Database.Delete(regionID); |
132 | } | 276 | } |
133 | 277 | ||
@@ -135,17 +279,32 @@ namespace OpenSim.Services.GridService | |||
135 | { | 279 | { |
136 | List<GridRegion> rinfos = new List<GridRegion>(); | 280 | List<GridRegion> rinfos = new List<GridRegion>(); |
137 | RegionData region = m_Database.Get(regionID, scopeID); | 281 | RegionData region = m_Database.Get(regionID, scopeID); |
282 | |||
138 | if (region != null) | 283 | if (region != null) |
139 | { | 284 | { |
140 | // Not really? Maybe? | 285 | // Not really? Maybe? |
141 | List<RegionData> rdatas = m_Database.Get(region.posX - (int)Constants.RegionSize, region.posY - (int)Constants.RegionSize, | 286 | List<RegionData> rdatas = m_Database.Get(region.posX - (int)Constants.RegionSize - 1, region.posY - (int)Constants.RegionSize - 1, |
142 | region.posX + (int)Constants.RegionSize, region.posY + (int)Constants.RegionSize, scopeID); | 287 | region.posX + (int)Constants.RegionSize + 1, region.posY + (int)Constants.RegionSize + 1, scopeID); |
143 | 288 | ||
144 | foreach (RegionData rdata in rdatas) | 289 | foreach (RegionData rdata in rdatas) |
290 | { | ||
145 | if (rdata.RegionID != regionID) | 291 | if (rdata.RegionID != regionID) |
146 | rinfos.Add(RegionData2RegionInfo(rdata)); | 292 | { |
293 | int flags = Convert.ToInt32(rdata.Data["flags"]); | ||
294 | if ((flags & (int)Data.RegionFlags.Hyperlink) == 0) // no hyperlinks as neighbours | ||
295 | rinfos.Add(RegionData2RegionInfo(rdata)); | ||
296 | } | ||
297 | } | ||
147 | 298 | ||
299 | // m_log.DebugFormat("[GRID SERVICE]: region {0} has {1} neighbours", region.RegionName, rinfos.Count); | ||
148 | } | 300 | } |
301 | else | ||
302 | { | ||
303 | m_log.WarnFormat( | ||
304 | "[GRID SERVICE]: GetNeighbours() called for scope {0}, region {1} but no such region found", | ||
305 | scopeID, regionID); | ||
306 | } | ||
307 | |||
149 | return rinfos; | 308 | return rinfos; |
150 | } | 309 | } |
151 | 310 | ||
@@ -169,24 +328,34 @@ namespace OpenSim.Services.GridService | |||
169 | return null; | 328 | return null; |
170 | } | 329 | } |
171 | 330 | ||
172 | public GridRegion GetRegionByName(UUID scopeID, string regionName) | 331 | public GridRegion GetRegionByName(UUID scopeID, string name) |
173 | { | 332 | { |
174 | List<RegionData> rdatas = m_Database.Get(regionName + "%", scopeID); | 333 | List<RegionData> rdatas = m_Database.Get(name, scopeID); |
175 | if ((rdatas != null) && (rdatas.Count > 0)) | 334 | if ((rdatas != null) && (rdatas.Count > 0)) |
176 | return RegionData2RegionInfo(rdatas[0]); // get the first | 335 | return RegionData2RegionInfo(rdatas[0]); // get the first |
177 | 336 | ||
337 | if (m_AllowHypergridMapSearch) | ||
338 | { | ||
339 | GridRegion r = GetHypergridRegionByName(scopeID, name); | ||
340 | if (r != null) | ||
341 | return r; | ||
342 | } | ||
343 | |||
178 | return null; | 344 | return null; |
179 | } | 345 | } |
180 | 346 | ||
181 | public List<GridRegion> GetRegionsByName(UUID scopeID, string name, int maxNumber) | 347 | public List<GridRegion> GetRegionsByName(UUID scopeID, string name, int maxNumber) |
182 | { | 348 | { |
183 | List<RegionData> rdatas = m_Database.Get("%" + name + "%", scopeID); | 349 | // m_log.DebugFormat("[GRID SERVICE]: GetRegionsByName {0}", name); |
350 | |||
351 | List<RegionData> rdatas = m_Database.Get(name + "%", scopeID); | ||
184 | 352 | ||
185 | int count = 0; | 353 | int count = 0; |
186 | List<GridRegion> rinfos = new List<GridRegion>(); | 354 | List<GridRegion> rinfos = new List<GridRegion>(); |
187 | 355 | ||
188 | if (rdatas != null) | 356 | if (rdatas != null) |
189 | { | 357 | { |
358 | // m_log.DebugFormat("[GRID SERVICE]: Found {0} regions", rdatas.Count); | ||
190 | foreach (RegionData rdata in rdatas) | 359 | foreach (RegionData rdata in rdatas) |
191 | { | 360 | { |
192 | if (count++ < maxNumber) | 361 | if (count++ < maxNumber) |
@@ -194,9 +363,30 @@ namespace OpenSim.Services.GridService | |||
194 | } | 363 | } |
195 | } | 364 | } |
196 | 365 | ||
366 | if (m_AllowHypergridMapSearch && (rdatas == null || (rdatas != null && rdatas.Count == 0))) | ||
367 | { | ||
368 | GridRegion r = GetHypergridRegionByName(scopeID, name); | ||
369 | if (r != null) | ||
370 | rinfos.Add(r); | ||
371 | } | ||
372 | |||
197 | return rinfos; | 373 | return rinfos; |
198 | } | 374 | } |
199 | 375 | ||
376 | /// <summary> | ||
377 | /// Get a hypergrid region. | ||
378 | /// </summary> | ||
379 | /// <param name="scopeID"></param> | ||
380 | /// <param name="name"></param> | ||
381 | /// <returns>null if no hypergrid region could be found.</returns> | ||
382 | protected GridRegion GetHypergridRegionByName(UUID scopeID, string name) | ||
383 | { | ||
384 | if (name.Contains(".")) | ||
385 | return m_HypergridLinker.LinkRegion(scopeID, name); | ||
386 | else | ||
387 | return null; | ||
388 | } | ||
389 | |||
200 | public List<GridRegion> GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax) | 390 | public List<GridRegion> GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax) |
201 | { | 391 | { |
202 | int xminSnap = (int)(xmin / Constants.RegionSize) * (int)Constants.RegionSize; | 392 | int xminSnap = (int)(xmin / Constants.RegionSize) * (int)Constants.RegionSize; |
@@ -216,7 +406,7 @@ namespace OpenSim.Services.GridService | |||
216 | 406 | ||
217 | #region Data structure conversions | 407 | #region Data structure conversions |
218 | 408 | ||
219 | protected RegionData RegionInfo2RegionData(GridRegion rinfo) | 409 | public RegionData RegionInfo2RegionData(GridRegion rinfo) |
220 | { | 410 | { |
221 | RegionData rdata = new RegionData(); | 411 | RegionData rdata = new RegionData(); |
222 | rdata.posX = (int)rinfo.RegionLocX; | 412 | rdata.posX = (int)rinfo.RegionLocX; |
@@ -229,7 +419,7 @@ namespace OpenSim.Services.GridService | |||
229 | return rdata; | 419 | return rdata; |
230 | } | 420 | } |
231 | 421 | ||
232 | protected GridRegion RegionData2RegionInfo(RegionData rdata) | 422 | public GridRegion RegionData2RegionInfo(RegionData rdata) |
233 | { | 423 | { |
234 | GridRegion rinfo = new GridRegion(rdata.Data); | 424 | GridRegion rinfo = new GridRegion(rdata.Data); |
235 | rinfo.RegionLocX = rdata.posX; | 425 | rinfo.RegionLocX = rdata.posX; |
@@ -243,5 +433,160 @@ namespace OpenSim.Services.GridService | |||
243 | 433 | ||
244 | #endregion | 434 | #endregion |
245 | 435 | ||
436 | public List<GridRegion> GetDefaultRegions(UUID scopeID) | ||
437 | { | ||
438 | List<GridRegion> ret = new List<GridRegion>(); | ||
439 | |||
440 | List<RegionData> regions = m_Database.GetDefaultRegions(scopeID); | ||
441 | |||
442 | foreach (RegionData r in regions) | ||
443 | { | ||
444 | if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Data.RegionFlags.RegionOnline) != 0) | ||
445 | ret.Add(RegionData2RegionInfo(r)); | ||
446 | } | ||
447 | |||
448 | m_log.DebugFormat("[GRID SERVICE]: GetDefaultRegions returning {0} regions", ret.Count); | ||
449 | return ret; | ||
450 | } | ||
451 | |||
452 | public List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y) | ||
453 | { | ||
454 | List<GridRegion> ret = new List<GridRegion>(); | ||
455 | |||
456 | List<RegionData> regions = m_Database.GetFallbackRegions(scopeID, x, y); | ||
457 | |||
458 | foreach (RegionData r in regions) | ||
459 | { | ||
460 | if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Data.RegionFlags.RegionOnline) != 0) | ||
461 | ret.Add(RegionData2RegionInfo(r)); | ||
462 | } | ||
463 | |||
464 | m_log.DebugFormat("[GRID SERVICE]: Fallback returned {0} regions", ret.Count); | ||
465 | return ret; | ||
466 | } | ||
467 | |||
468 | public List<GridRegion> GetHyperlinks(UUID scopeID) | ||
469 | { | ||
470 | List<GridRegion> ret = new List<GridRegion>(); | ||
471 | |||
472 | List<RegionData> regions = m_Database.GetHyperlinks(scopeID); | ||
473 | |||
474 | foreach (RegionData r in regions) | ||
475 | { | ||
476 | if ((Convert.ToInt32(r.Data["flags"]) & (int)OpenSim.Data.RegionFlags.RegionOnline) != 0) | ||
477 | ret.Add(RegionData2RegionInfo(r)); | ||
478 | } | ||
479 | |||
480 | m_log.DebugFormat("[GRID SERVICE]: Hyperlinks returned {0} regions", ret.Count); | ||
481 | return ret; | ||
482 | } | ||
483 | |||
484 | public int GetRegionFlags(UUID scopeID, UUID regionID) | ||
485 | { | ||
486 | RegionData region = m_Database.Get(regionID, scopeID); | ||
487 | |||
488 | if (region != null) | ||
489 | { | ||
490 | int flags = Convert.ToInt32(region.Data["flags"]); | ||
491 | //m_log.DebugFormat("[GRID SERVICE]: Request for flags of {0}: {1}", regionID, flags); | ||
492 | return flags; | ||
493 | } | ||
494 | else | ||
495 | return -1; | ||
496 | } | ||
497 | |||
498 | private void HandleShowRegion(string module, string[] cmd) | ||
499 | { | ||
500 | if (cmd.Length != 3) | ||
501 | { | ||
502 | MainConsole.Instance.Output("Syntax: show region <region name>"); | ||
503 | return; | ||
504 | } | ||
505 | List<RegionData> regions = m_Database.Get(cmd[2], UUID.Zero); | ||
506 | if (regions == null || regions.Count < 1) | ||
507 | { | ||
508 | MainConsole.Instance.Output("Region not found"); | ||
509 | return; | ||
510 | } | ||
511 | |||
512 | MainConsole.Instance.Output("Region Name Region UUID"); | ||
513 | MainConsole.Instance.Output("Location URI"); | ||
514 | MainConsole.Instance.Output("Owner ID Flags"); | ||
515 | MainConsole.Instance.Output("-------------------------------------------------------------------------------"); | ||
516 | foreach (RegionData r in regions) | ||
517 | { | ||
518 | OpenSim.Data.RegionFlags flags = (OpenSim.Data.RegionFlags)Convert.ToInt32(r.Data["flags"]); | ||
519 | MainConsole.Instance.Output(String.Format("{0,-20} {1}\n{2,-20} {3}\n{4,-39} {5}\n\n", | ||
520 | r.RegionName, r.RegionID, | ||
521 | String.Format("{0},{1}", r.posX / Constants.RegionSize, r.posY / Constants.RegionSize), | ||
522 | r.Data["serverURI"], | ||
523 | r.Data["owner_uuid"], flags)); | ||
524 | } | ||
525 | return; | ||
526 | } | ||
527 | |||
528 | private int ParseFlags(int prev, string flags) | ||
529 | { | ||
530 | OpenSim.Data.RegionFlags f = (OpenSim.Data.RegionFlags)prev; | ||
531 | |||
532 | string[] parts = flags.Split(new char[] {',', ' '}, StringSplitOptions.RemoveEmptyEntries); | ||
533 | |||
534 | foreach (string p in parts) | ||
535 | { | ||
536 | int val; | ||
537 | |||
538 | try | ||
539 | { | ||
540 | if (p.StartsWith("+")) | ||
541 | { | ||
542 | val = (int)Enum.Parse(typeof(OpenSim.Data.RegionFlags), p.Substring(1)); | ||
543 | f |= (OpenSim.Data.RegionFlags)val; | ||
544 | } | ||
545 | else if (p.StartsWith("-")) | ||
546 | { | ||
547 | val = (int)Enum.Parse(typeof(OpenSim.Data.RegionFlags), p.Substring(1)); | ||
548 | f &= ~(OpenSim.Data.RegionFlags)val; | ||
549 | } | ||
550 | else | ||
551 | { | ||
552 | val = (int)Enum.Parse(typeof(OpenSim.Data.RegionFlags), p); | ||
553 | f |= (OpenSim.Data.RegionFlags)val; | ||
554 | } | ||
555 | } | ||
556 | catch (Exception) | ||
557 | { | ||
558 | MainConsole.Instance.Output("Error in flag specification: " + p); | ||
559 | } | ||
560 | } | ||
561 | |||
562 | return (int)f; | ||
563 | } | ||
564 | |||
565 | private void HandleSetFlags(string module, string[] cmd) | ||
566 | { | ||
567 | if (cmd.Length < 5) | ||
568 | { | ||
569 | MainConsole.Instance.Output("Syntax: set region flags <region name> <flags>"); | ||
570 | return; | ||
571 | } | ||
572 | |||
573 | List<RegionData> regions = m_Database.Get(cmd[3], UUID.Zero); | ||
574 | if (regions == null || regions.Count < 1) | ||
575 | { | ||
576 | MainConsole.Instance.Output("Region not found"); | ||
577 | return; | ||
578 | } | ||
579 | |||
580 | foreach (RegionData r in regions) | ||
581 | { | ||
582 | int flags = Convert.ToInt32(r.Data["flags"]); | ||
583 | flags = ParseFlags(flags, cmd[4]); | ||
584 | r.Data["flags"] = flags.ToString(); | ||
585 | OpenSim.Data.RegionFlags f = (OpenSim.Data.RegionFlags)flags; | ||
586 | |||
587 | MainConsole.Instance.Output(String.Format("Set region {0} to {1}", r.RegionName, f)); | ||
588 | m_Database.Store(r); | ||
589 | } | ||
590 | } | ||
246 | } | 591 | } |
247 | } | 592 | } |
diff --git a/OpenSim/Services/GridService/HypergridLinker.cs b/OpenSim/Services/GridService/HypergridLinker.cs new file mode 100644 index 0000000..b70b425 --- /dev/null +++ b/OpenSim/Services/GridService/HypergridLinker.cs | |||
@@ -0,0 +1,724 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.IO; | ||
32 | using System.Linq; | ||
33 | using System.Net; | ||
34 | using System.Reflection; | ||
35 | using System.Xml; | ||
36 | |||
37 | using Nini.Config; | ||
38 | using log4net; | ||
39 | using OpenSim.Framework; | ||
40 | using OpenSim.Framework.Console; | ||
41 | using OpenSim.Data; | ||
42 | using OpenSim.Server.Base; | ||
43 | using OpenSim.Services.Interfaces; | ||
44 | using OpenSim.Services.Connectors.Hypergrid; | ||
45 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
46 | using OpenMetaverse; | ||
47 | |||
48 | namespace OpenSim.Services.GridService | ||
49 | { | ||
50 | public class HypergridLinker | ||
51 | { | ||
52 | private static readonly ILog m_log = | ||
53 | LogManager.GetLogger( | ||
54 | MethodBase.GetCurrentMethod().DeclaringType); | ||
55 | |||
56 | private static uint m_autoMappingX = 0; | ||
57 | private static uint m_autoMappingY = 0; | ||
58 | private static bool m_enableAutoMapping = false; | ||
59 | |||
60 | protected IRegionData m_Database; | ||
61 | protected GridService m_GridService; | ||
62 | protected IAssetService m_AssetService; | ||
63 | protected GatekeeperServiceConnector m_GatekeeperConnector; | ||
64 | |||
65 | protected UUID m_ScopeID = UUID.Zero; | ||
66 | // protected bool m_Check4096 = true; | ||
67 | protected string m_MapTileDirectory = string.Empty; | ||
68 | protected string m_ThisGatekeeper = string.Empty; | ||
69 | protected Uri m_ThisGatekeeperURI = null; | ||
70 | |||
71 | // Hyperlink regions are hyperlinks on the map | ||
72 | public readonly Dictionary<UUID, GridRegion> m_HyperlinkRegions = new Dictionary<UUID, GridRegion>(); | ||
73 | protected Dictionary<UUID, ulong> m_HyperlinkHandles = new Dictionary<UUID, ulong>(); | ||
74 | |||
75 | protected GridRegion m_DefaultRegion; | ||
76 | protected GridRegion DefaultRegion | ||
77 | { | ||
78 | get | ||
79 | { | ||
80 | if (m_DefaultRegion == null) | ||
81 | { | ||
82 | List<GridRegion> defs = m_GridService.GetDefaultRegions(m_ScopeID); | ||
83 | if (defs != null && defs.Count > 0) | ||
84 | m_DefaultRegion = defs[0]; | ||
85 | else | ||
86 | { | ||
87 | // Get any region | ||
88 | defs = m_GridService.GetRegionsByName(m_ScopeID, "", 1); | ||
89 | if (defs != null && defs.Count > 0) | ||
90 | m_DefaultRegion = defs[0]; | ||
91 | else | ||
92 | { | ||
93 | // This shouldn't happen | ||
94 | m_DefaultRegion = new GridRegion(1000, 1000); | ||
95 | m_log.Error("[HYPERGRID LINKER]: Something is wrong with this grid. It has no regions?"); | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | return m_DefaultRegion; | ||
100 | } | ||
101 | } | ||
102 | |||
103 | public HypergridLinker(IConfigSource config, GridService gridService, IRegionData db) | ||
104 | { | ||
105 | IConfig modulesConfig = config.Configs["Modules"]; | ||
106 | if (modulesConfig == null) | ||
107 | return; | ||
108 | |||
109 | if (modulesConfig.GetString("HypergridLinker", "") != "HypergridLinker") | ||
110 | return; | ||
111 | |||
112 | m_log.DebugFormat("[HYPERGRID LINKER]: Starting with db {0}", db.GetType()); | ||
113 | |||
114 | m_Database = db; | ||
115 | m_GridService = gridService; | ||
116 | |||
117 | IConfig gridConfig = config.Configs["GridService"]; | ||
118 | if (gridConfig != null) | ||
119 | { | ||
120 | string assetService = gridConfig.GetString("AssetService", string.Empty); | ||
121 | |||
122 | Object[] args = new Object[] { config }; | ||
123 | |||
124 | if (assetService != string.Empty) | ||
125 | m_AssetService = ServerUtils.LoadPlugin<IAssetService>(assetService, args); | ||
126 | |||
127 | string scope = gridConfig.GetString("ScopeID", string.Empty); | ||
128 | if (scope != string.Empty) | ||
129 | UUID.TryParse(scope, out m_ScopeID); | ||
130 | |||
131 | // m_Check4096 = gridConfig.GetBoolean("Check4096", true); | ||
132 | |||
133 | m_MapTileDirectory = gridConfig.GetString("MapTileDirectory", "maptiles"); | ||
134 | |||
135 | m_ThisGatekeeper = gridConfig.GetString("Gatekeeper", string.Empty); | ||
136 | try | ||
137 | { | ||
138 | m_ThisGatekeeperURI = new Uri(m_ThisGatekeeper); | ||
139 | } | ||
140 | catch | ||
141 | { | ||
142 | m_log.WarnFormat("[HYPERGRID LINKER]: Malformed URL in [GridService], variable Gatekeeper = {0}", m_ThisGatekeeper); | ||
143 | } | ||
144 | |||
145 | m_GatekeeperConnector = new GatekeeperServiceConnector(m_AssetService); | ||
146 | |||
147 | m_log.Debug("[HYPERGRID LINKER]: Loaded all services..."); | ||
148 | } | ||
149 | |||
150 | if (!string.IsNullOrEmpty(m_MapTileDirectory)) | ||
151 | { | ||
152 | try | ||
153 | { | ||
154 | Directory.CreateDirectory(m_MapTileDirectory); | ||
155 | } | ||
156 | catch (Exception e) | ||
157 | { | ||
158 | m_log.WarnFormat("[HYPERGRID LINKER]: Could not create map tile storage directory {0}: {1}", m_MapTileDirectory, e); | ||
159 | m_MapTileDirectory = string.Empty; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | if (MainConsole.Instance != null) | ||
164 | { | ||
165 | MainConsole.Instance.Commands.AddCommand("hypergrid", false, "link-region", | ||
166 | "link-region <Xloc> <Yloc> <ServerURI> [<RemoteRegionName>]", | ||
167 | "Link a HyperGrid Region. Examples for <ServerURI>: http://grid.net:8002/ or http://example.org/path/foo.php", RunCommand); | ||
168 | MainConsole.Instance.Commands.AddCommand("hypergrid", false, "link-region", | ||
169 | "link-region <Xloc> <Yloc> <RegionIP> <RegionPort> [<RemoteRegionName>]", | ||
170 | "Link a hypergrid region (deprecated)", RunCommand); | ||
171 | MainConsole.Instance.Commands.AddCommand("hypergrid", false, "unlink-region", | ||
172 | "unlink-region <local name>", | ||
173 | "Unlink a hypergrid region", RunCommand); | ||
174 | MainConsole.Instance.Commands.AddCommand("hypergrid", false, "link-mapping", "link-mapping [<x> <y>]", | ||
175 | "Set local coordinate to map HG regions to", RunCommand); | ||
176 | MainConsole.Instance.Commands.AddCommand("hypergrid", false, "show hyperlinks", "show hyperlinks", | ||
177 | "List the HG regions", HandleShow); | ||
178 | } | ||
179 | } | ||
180 | |||
181 | |||
182 | #region Link Region | ||
183 | |||
184 | public GridRegion LinkRegion(UUID scopeID, string regionDescriptor) | ||
185 | { | ||
186 | string reason = string.Empty; | ||
187 | int xloc = random.Next(0, Int16.MaxValue) * (int)Constants.RegionSize; | ||
188 | return TryLinkRegionToCoords(scopeID, regionDescriptor, xloc, 0, out reason); | ||
189 | } | ||
190 | |||
191 | private static Random random = new Random(); | ||
192 | |||
193 | // From the command line link-region | ||
194 | public GridRegion TryLinkRegionToCoords(UUID scopeID, string mapName, int xloc, int yloc, out string reason) | ||
195 | { | ||
196 | return TryLinkRegionToCoords(scopeID, mapName, xloc, yloc, UUID.Zero, out reason); | ||
197 | } | ||
198 | |||
199 | public GridRegion TryLinkRegionToCoords(UUID scopeID, string mapName, int xloc, int yloc, UUID ownerID, out string reason) | ||
200 | { | ||
201 | reason = string.Empty; | ||
202 | uint port = 0; | ||
203 | string[] parts = mapName.Split(new char[] {':'}); | ||
204 | string regionName = String.Empty; | ||
205 | if (parts.Length > 1) | ||
206 | { | ||
207 | regionName = mapName.Substring(parts[0].Length + 1); | ||
208 | regionName = regionName.Trim(new char[] {'"'}); | ||
209 | } | ||
210 | GridRegion regInfo; | ||
211 | if (TryCreateLink(scopeID, xloc, yloc, regionName, 0, null, parts[0], ownerID, out regInfo, out reason)) | ||
212 | { | ||
213 | regInfo.RegionName = mapName; | ||
214 | return regInfo; | ||
215 | } | ||
216 | |||
217 | return null; | ||
218 | } | ||
219 | |||
220 | public bool TryCreateLink(UUID scopeID, int xloc, int yloc, string remoteRegionName, uint externalPort, string externalHostName, UUID ownerID, out GridRegion regInfo, out string reason) | ||
221 | { | ||
222 | return TryCreateLink(scopeID, xloc, yloc, remoteRegionName, externalPort, externalHostName, null, ownerID, out regInfo, out reason); | ||
223 | } | ||
224 | |||
225 | public bool TryCreateLink(UUID scopeID, int xloc, int yloc, string remoteRegionName, uint externalPort, string externalHostName, string serverURI, UUID ownerID, out GridRegion regInfo, out string reason) | ||
226 | { | ||
227 | m_log.DebugFormat("[HYPERGRID LINKER]: Link to {0}:{1}, in {2}-{3}", | ||
228 | ((serverURI == null) ? (externalHostName + ":" + externalPort) : serverURI), | ||
229 | remoteRegionName, xloc / Constants.RegionSize, yloc / Constants.RegionSize); | ||
230 | |||
231 | reason = string.Empty; | ||
232 | Uri uri = null; | ||
233 | |||
234 | regInfo = new GridRegion(); | ||
235 | if ( externalPort > 0) | ||
236 | regInfo.HttpPort = externalPort; | ||
237 | else | ||
238 | regInfo.HttpPort = 0; | ||
239 | if ( externalHostName != null) | ||
240 | regInfo.ExternalHostName = externalHostName; | ||
241 | else | ||
242 | regInfo.ExternalHostName = "0.0.0.0"; | ||
243 | if ( serverURI != null) | ||
244 | { | ||
245 | regInfo.ServerURI = serverURI; | ||
246 | try | ||
247 | { | ||
248 | uri = new Uri(serverURI); | ||
249 | regInfo.ExternalHostName = uri.Host; | ||
250 | regInfo.HttpPort = (uint)uri.Port; | ||
251 | } | ||
252 | catch {} | ||
253 | } | ||
254 | |||
255 | if ( remoteRegionName != string.Empty ) | ||
256 | regInfo.RegionName = remoteRegionName; | ||
257 | |||
258 | regInfo.RegionLocX = xloc; | ||
259 | regInfo.RegionLocY = yloc; | ||
260 | regInfo.ScopeID = scopeID; | ||
261 | regInfo.EstateOwner = ownerID; | ||
262 | |||
263 | // Make sure we're not hyperlinking to regions on this grid! | ||
264 | if (m_ThisGatekeeperURI != null) | ||
265 | { | ||
266 | if (regInfo.ExternalHostName == m_ThisGatekeeperURI.Host && regInfo.HttpPort == m_ThisGatekeeperURI.Port) | ||
267 | { | ||
268 | reason = "Cannot hyperlink to regions on the same grid"; | ||
269 | return false; | ||
270 | } | ||
271 | } | ||
272 | else | ||
273 | m_log.WarnFormat("[HYPERGRID LINKER]: Please set this grid's Gatekeeper's address in [GridService]!"); | ||
274 | |||
275 | // Check for free coordinates | ||
276 | GridRegion region = m_GridService.GetRegionByPosition(regInfo.ScopeID, regInfo.RegionLocX, regInfo.RegionLocY); | ||
277 | if (region != null) | ||
278 | { | ||
279 | m_log.WarnFormat("[HYPERGRID LINKER]: Coordinates {0}-{1} are already occupied by region {2} with uuid {3}", | ||
280 | regInfo.RegionLocX / Constants.RegionSize, regInfo.RegionLocY / Constants.RegionSize, | ||
281 | region.RegionName, region.RegionID); | ||
282 | reason = "Coordinates are already in use"; | ||
283 | return false; | ||
284 | } | ||
285 | |||
286 | try | ||
287 | { | ||
288 | regInfo.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), (int)0); | ||
289 | } | ||
290 | catch (Exception e) | ||
291 | { | ||
292 | m_log.Warn("[HYPERGRID LINKER]: Wrong format for link-region: " + e.Message); | ||
293 | reason = "Internal error"; | ||
294 | return false; | ||
295 | } | ||
296 | |||
297 | // Finally, link it | ||
298 | ulong handle = 0; | ||
299 | UUID regionID = UUID.Zero; | ||
300 | string externalName = string.Empty; | ||
301 | string imageURL = string.Empty; | ||
302 | if (!m_GatekeeperConnector.LinkRegion(regInfo, out regionID, out handle, out externalName, out imageURL, out reason)) | ||
303 | return false; | ||
304 | |||
305 | if (regionID == UUID.Zero) | ||
306 | { | ||
307 | m_log.Warn("[HYPERGRID LINKER]: Unable to link region"); | ||
308 | reason = "Remote region could not be found"; | ||
309 | return false; | ||
310 | } | ||
311 | |||
312 | region = m_GridService.GetRegionByUUID(scopeID, regionID); | ||
313 | if (region != null) | ||
314 | { | ||
315 | m_log.DebugFormat("[HYPERGRID LINKER]: Region already exists in coordinates {0} {1}", | ||
316 | region.RegionLocX / Constants.RegionSize, region.RegionLocY / Constants.RegionSize); | ||
317 | regInfo = region; | ||
318 | return true; | ||
319 | } | ||
320 | |||
321 | // We are now performing this check for each individual teleport in the EntityTransferModule instead. This | ||
322 | // allows us to give better feedback when teleports fail because of the distance reason (which can't be | ||
323 | // done here) and it also hypergrid teleports that are within range (possibly because the source grid | ||
324 | // itself has regions that are very far apart). | ||
325 | // uint x, y; | ||
326 | // if (m_Check4096 && !Check4096(handle, out x, out y)) | ||
327 | // { | ||
328 | // //RemoveHyperlinkRegion(regInfo.RegionID); | ||
329 | // reason = "Region is too far (" + x + ", " + y + ")"; | ||
330 | // m_log.Info("[HYPERGRID LINKER]: Unable to link, region is too far (" + x + ", " + y + ")"); | ||
331 | // //return false; | ||
332 | // } | ||
333 | |||
334 | regInfo.RegionID = regionID; | ||
335 | |||
336 | if (externalName == string.Empty) | ||
337 | regInfo.RegionName = regInfo.ServerURI; | ||
338 | else | ||
339 | regInfo.RegionName = externalName; | ||
340 | |||
341 | m_log.DebugFormat("[HYPERGRID LINKER]: naming linked region {0}, handle {1}", regInfo.RegionName, handle.ToString()); | ||
342 | |||
343 | // Get the map image | ||
344 | regInfo.TerrainImage = GetMapImage(regionID, imageURL); | ||
345 | |||
346 | // Store the origin's coordinates somewhere | ||
347 | regInfo.RegionSecret = handle.ToString(); | ||
348 | |||
349 | AddHyperlinkRegion(regInfo, handle); | ||
350 | m_log.Info("[HYPERGRID LINKER]: Successfully linked to region_uuid " + regInfo.RegionID); | ||
351 | return true; | ||
352 | } | ||
353 | |||
354 | public bool TryUnlinkRegion(string mapName) | ||
355 | { | ||
356 | m_log.DebugFormat("[HYPERGRID LINKER]: Request to unlink {0}", mapName); | ||
357 | GridRegion regInfo = null; | ||
358 | |||
359 | List<RegionData> regions = m_Database.Get(mapName, m_ScopeID); | ||
360 | if (regions != null && regions.Count > 0) | ||
361 | { | ||
362 | OpenSim.Data.RegionFlags rflags = (OpenSim.Data.RegionFlags)Convert.ToInt32(regions[0].Data["flags"]); | ||
363 | if ((rflags & OpenSim.Data.RegionFlags.Hyperlink) != 0) | ||
364 | { | ||
365 | regInfo = new GridRegion(); | ||
366 | regInfo.RegionID = regions[0].RegionID; | ||
367 | regInfo.ScopeID = m_ScopeID; | ||
368 | } | ||
369 | } | ||
370 | |||
371 | if (regInfo != null) | ||
372 | { | ||
373 | RemoveHyperlinkRegion(regInfo.RegionID); | ||
374 | return true; | ||
375 | } | ||
376 | else | ||
377 | { | ||
378 | m_log.InfoFormat("[HYPERGRID LINKER]: Region {0} not found", mapName); | ||
379 | return false; | ||
380 | } | ||
381 | } | ||
382 | |||
383 | // Not currently used | ||
384 | // /// <summary> | ||
385 | // /// Cope with this viewer limitation. | ||
386 | // /// </summary> | ||
387 | // /// <param name="regInfo"></param> | ||
388 | // /// <returns></returns> | ||
389 | // public bool Check4096(ulong realHandle, out uint x, out uint y) | ||
390 | // { | ||
391 | // uint ux = 0, uy = 0; | ||
392 | // Utils.LongToUInts(realHandle, out ux, out uy); | ||
393 | // x = ux / Constants.RegionSize; | ||
394 | // y = uy / Constants.RegionSize; | ||
395 | // | ||
396 | // const uint limit = (4096 - 1) * Constants.RegionSize; | ||
397 | // uint xmin = ux - limit; | ||
398 | // uint xmax = ux + limit; | ||
399 | // uint ymin = uy - limit; | ||
400 | // uint ymax = uy + limit; | ||
401 | // // World map boundary checks | ||
402 | // if (xmin < 0 || xmin > ux) | ||
403 | // xmin = 0; | ||
404 | // if (xmax > int.MaxValue || xmax < ux) | ||
405 | // xmax = int.MaxValue; | ||
406 | // if (ymin < 0 || ymin > uy) | ||
407 | // ymin = 0; | ||
408 | // if (ymax > int.MaxValue || ymax < uy) | ||
409 | // ymax = int.MaxValue; | ||
410 | // | ||
411 | // // Check for any regions that are within the possible teleport range to the linked region | ||
412 | // List<GridRegion> regions = m_GridService.GetRegionRange(m_ScopeID, (int)xmin, (int)xmax, (int)ymin, (int)ymax); | ||
413 | // if (regions.Count == 0) | ||
414 | // { | ||
415 | // return false; | ||
416 | // } | ||
417 | // else | ||
418 | // { | ||
419 | // // Check for regions which are not linked regions | ||
420 | // List<GridRegion> hyperlinks = m_GridService.GetHyperlinks(m_ScopeID); | ||
421 | // IEnumerable<GridRegion> availableRegions = regions.Except(hyperlinks); | ||
422 | // if (availableRegions.Count() == 0) | ||
423 | // return false; | ||
424 | // } | ||
425 | // | ||
426 | // return true; | ||
427 | // } | ||
428 | |||
429 | private void AddHyperlinkRegion(GridRegion regionInfo, ulong regionHandle) | ||
430 | { | ||
431 | RegionData rdata = m_GridService.RegionInfo2RegionData(regionInfo); | ||
432 | int flags = (int)OpenSim.Data.RegionFlags.Hyperlink + (int)OpenSim.Data.RegionFlags.NoDirectLogin + (int)OpenSim.Data.RegionFlags.RegionOnline; | ||
433 | rdata.Data["flags"] = flags.ToString(); | ||
434 | |||
435 | m_Database.Store(rdata); | ||
436 | } | ||
437 | |||
438 | private void RemoveHyperlinkRegion(UUID regionID) | ||
439 | { | ||
440 | m_Database.Delete(regionID); | ||
441 | } | ||
442 | |||
443 | public UUID GetMapImage(UUID regionID, string imageURL) | ||
444 | { | ||
445 | return m_GatekeeperConnector.GetMapImage(regionID, imageURL, m_MapTileDirectory); | ||
446 | } | ||
447 | #endregion | ||
448 | |||
449 | |||
450 | #region Console Commands | ||
451 | |||
452 | public void HandleShow(string module, string[] cmd) | ||
453 | { | ||
454 | if (cmd.Length != 2) | ||
455 | { | ||
456 | MainConsole.Instance.Output("Syntax: show hyperlinks"); | ||
457 | return; | ||
458 | } | ||
459 | List<RegionData> regions = m_Database.GetHyperlinks(UUID.Zero); | ||
460 | if (regions == null || regions.Count < 1) | ||
461 | { | ||
462 | MainConsole.Instance.Output("No hyperlinks"); | ||
463 | return; | ||
464 | } | ||
465 | |||
466 | MainConsole.Instance.Output("Region Name"); | ||
467 | MainConsole.Instance.Output("Location Region UUID"); | ||
468 | MainConsole.Instance.Output(new string('-', 72)); | ||
469 | foreach (RegionData r in regions) | ||
470 | { | ||
471 | MainConsole.Instance.Output(String.Format("{0}\n{2,-32} {1}\n", | ||
472 | r.RegionName, r.RegionID, String.Format("{0},{1} ({2},{3})", r.posX, r.posY, | ||
473 | r.posX / Constants.RegionSize, r.posY / Constants.RegionSize))); | ||
474 | } | ||
475 | return; | ||
476 | } | ||
477 | |||
478 | public void RunCommand(string module, string[] cmdparams) | ||
479 | { | ||
480 | List<string> args = new List<string>(cmdparams); | ||
481 | if (args.Count < 1) | ||
482 | return; | ||
483 | |||
484 | string command = args[0]; | ||
485 | args.RemoveAt(0); | ||
486 | |||
487 | cmdparams = args.ToArray(); | ||
488 | |||
489 | RunHGCommand(command, cmdparams); | ||
490 | |||
491 | } | ||
492 | |||
493 | private void RunLinkRegionCommand(string[] cmdparams) | ||
494 | { | ||
495 | int xloc, yloc; | ||
496 | string serverURI; | ||
497 | string remoteName = null; | ||
498 | xloc = Convert.ToInt32(cmdparams[0]) * (int)Constants.RegionSize; | ||
499 | yloc = Convert.ToInt32(cmdparams[1]) * (int)Constants.RegionSize; | ||
500 | serverURI = cmdparams[2]; | ||
501 | if (cmdparams.Length > 3) | ||
502 | remoteName = string.Join(" ", cmdparams, 3, cmdparams.Length - 3); | ||
503 | string reason = string.Empty; | ||
504 | GridRegion regInfo; | ||
505 | if (TryCreateLink(UUID.Zero, xloc, yloc, remoteName, 0, null, serverURI, UUID.Zero, out regInfo, out reason)) | ||
506 | MainConsole.Instance.Output("Hyperlink established"); | ||
507 | else | ||
508 | MainConsole.Instance.Output("Failed to link region: " + reason); | ||
509 | } | ||
510 | |||
511 | private void RunHGCommand(string command, string[] cmdparams) | ||
512 | { | ||
513 | if (command.Equals("link-mapping")) | ||
514 | { | ||
515 | if (cmdparams.Length == 2) | ||
516 | { | ||
517 | try | ||
518 | { | ||
519 | m_autoMappingX = Convert.ToUInt32(cmdparams[0]); | ||
520 | m_autoMappingY = Convert.ToUInt32(cmdparams[1]); | ||
521 | m_enableAutoMapping = true; | ||
522 | } | ||
523 | catch (Exception) | ||
524 | { | ||
525 | m_autoMappingX = 0; | ||
526 | m_autoMappingY = 0; | ||
527 | m_enableAutoMapping = false; | ||
528 | } | ||
529 | } | ||
530 | } | ||
531 | else if (command.Equals("link-region")) | ||
532 | { | ||
533 | if (cmdparams.Length < 3) | ||
534 | { | ||
535 | if ((cmdparams.Length == 1) || (cmdparams.Length == 2)) | ||
536 | { | ||
537 | LoadXmlLinkFile(cmdparams); | ||
538 | } | ||
539 | else | ||
540 | { | ||
541 | LinkRegionCmdUsage(); | ||
542 | } | ||
543 | return; | ||
544 | } | ||
545 | |||
546 | //this should be the prefererred way of setting up hg links now | ||
547 | if (cmdparams[2].StartsWith("http")) | ||
548 | { | ||
549 | RunLinkRegionCommand(cmdparams); | ||
550 | } | ||
551 | else if (cmdparams[2].Contains(":")) | ||
552 | { | ||
553 | // New format | ||
554 | string[] parts = cmdparams[2].Split(':'); | ||
555 | if (parts.Length > 2) | ||
556 | { | ||
557 | // Insert remote region name | ||
558 | ArrayList parameters = new ArrayList(cmdparams); | ||
559 | parameters.Insert(3, parts[2]); | ||
560 | cmdparams = (string[])parameters.ToArray(typeof(string)); | ||
561 | } | ||
562 | cmdparams[2] = "http://" + parts[0] + ':' + parts[1]; | ||
563 | |||
564 | RunLinkRegionCommand(cmdparams); | ||
565 | } | ||
566 | else | ||
567 | { | ||
568 | // old format | ||
569 | GridRegion regInfo; | ||
570 | int xloc, yloc; | ||
571 | uint externalPort; | ||
572 | string externalHostName; | ||
573 | try | ||
574 | { | ||
575 | xloc = Convert.ToInt32(cmdparams[0]); | ||
576 | yloc = Convert.ToInt32(cmdparams[1]); | ||
577 | externalPort = Convert.ToUInt32(cmdparams[3]); | ||
578 | externalHostName = cmdparams[2]; | ||
579 | //internalPort = Convert.ToUInt32(cmdparams[4]); | ||
580 | //remotingPort = Convert.ToUInt32(cmdparams[5]); | ||
581 | } | ||
582 | catch (Exception e) | ||
583 | { | ||
584 | MainConsole.Instance.Output("[HGrid] Wrong format for link-region command: " + e.Message); | ||
585 | LinkRegionCmdUsage(); | ||
586 | return; | ||
587 | } | ||
588 | |||
589 | // Convert cell coordinates given by the user to meters | ||
590 | xloc = xloc * (int)Constants.RegionSize; | ||
591 | yloc = yloc * (int)Constants.RegionSize; | ||
592 | string reason = string.Empty; | ||
593 | if (TryCreateLink(UUID.Zero, xloc, yloc, string.Empty, externalPort, externalHostName, UUID.Zero, out regInfo, out reason)) | ||
594 | { | ||
595 | // What is this? The GridRegion instance will be discarded anyway, | ||
596 | // which effectively ignores any local name given with the command. | ||
597 | //if (cmdparams.Length >= 5) | ||
598 | //{ | ||
599 | // regInfo.RegionName = ""; | ||
600 | // for (int i = 4; i < cmdparams.Length; i++) | ||
601 | // regInfo.RegionName += cmdparams[i] + " "; | ||
602 | //} | ||
603 | } | ||
604 | } | ||
605 | return; | ||
606 | } | ||
607 | else if (command.Equals("unlink-region")) | ||
608 | { | ||
609 | if (cmdparams.Length < 1) | ||
610 | { | ||
611 | UnlinkRegionCmdUsage(); | ||
612 | return; | ||
613 | } | ||
614 | string region = string.Join(" ", cmdparams); | ||
615 | if (TryUnlinkRegion(region)) | ||
616 | MainConsole.Instance.Output("Successfully unlinked " + region); | ||
617 | else | ||
618 | MainConsole.Instance.Output("Unable to unlink " + region + ", region not found."); | ||
619 | } | ||
620 | } | ||
621 | |||
622 | private void LoadXmlLinkFile(string[] cmdparams) | ||
623 | { | ||
624 | //use http://www.hgurl.com/hypergrid.xml for test | ||
625 | try | ||
626 | { | ||
627 | XmlReader r = XmlReader.Create(cmdparams[0]); | ||
628 | XmlConfigSource cs = new XmlConfigSource(r); | ||
629 | string[] excludeSections = null; | ||
630 | |||
631 | if (cmdparams.Length == 2) | ||
632 | { | ||
633 | if (cmdparams[1].ToLower().StartsWith("excludelist:")) | ||
634 | { | ||
635 | string excludeString = cmdparams[1].ToLower(); | ||
636 | excludeString = excludeString.Remove(0, 12); | ||
637 | char[] splitter = { ';' }; | ||
638 | |||
639 | excludeSections = excludeString.Split(splitter); | ||
640 | } | ||
641 | } | ||
642 | |||
643 | for (int i = 0; i < cs.Configs.Count; i++) | ||
644 | { | ||
645 | bool skip = false; | ||
646 | if ((excludeSections != null) && (excludeSections.Length > 0)) | ||
647 | { | ||
648 | for (int n = 0; n < excludeSections.Length; n++) | ||
649 | { | ||
650 | if (excludeSections[n] == cs.Configs[i].Name.ToLower()) | ||
651 | { | ||
652 | skip = true; | ||
653 | break; | ||
654 | } | ||
655 | } | ||
656 | } | ||
657 | if (!skip) | ||
658 | { | ||
659 | ReadLinkFromConfig(cs.Configs[i]); | ||
660 | } | ||
661 | } | ||
662 | } | ||
663 | catch (Exception e) | ||
664 | { | ||
665 | m_log.Error(e.ToString()); | ||
666 | } | ||
667 | } | ||
668 | |||
669 | |||
670 | private void ReadLinkFromConfig(IConfig config) | ||
671 | { | ||
672 | GridRegion regInfo; | ||
673 | int xloc, yloc; | ||
674 | uint externalPort; | ||
675 | string externalHostName; | ||
676 | uint realXLoc, realYLoc; | ||
677 | |||
678 | xloc = Convert.ToInt32(config.GetString("xloc", "0")); | ||
679 | yloc = Convert.ToInt32(config.GetString("yloc", "0")); | ||
680 | externalPort = Convert.ToUInt32(config.GetString("externalPort", "0")); | ||
681 | externalHostName = config.GetString("externalHostName", ""); | ||
682 | realXLoc = Convert.ToUInt32(config.GetString("real-xloc", "0")); | ||
683 | realYLoc = Convert.ToUInt32(config.GetString("real-yloc", "0")); | ||
684 | |||
685 | if (m_enableAutoMapping) | ||
686 | { | ||
687 | xloc = (int)((xloc % 100) + m_autoMappingX); | ||
688 | yloc = (int)((yloc % 100) + m_autoMappingY); | ||
689 | } | ||
690 | |||
691 | if (((realXLoc == 0) && (realYLoc == 0)) || | ||
692 | (((realXLoc - xloc < 3896) || (xloc - realXLoc < 3896)) && | ||
693 | ((realYLoc - yloc < 3896) || (yloc - realYLoc < 3896)))) | ||
694 | { | ||
695 | xloc = xloc * (int)Constants.RegionSize; | ||
696 | yloc = yloc * (int)Constants.RegionSize; | ||
697 | string reason = string.Empty; | ||
698 | if (TryCreateLink(UUID.Zero, xloc, yloc, string.Empty, externalPort, externalHostName, UUID.Zero, out regInfo, out reason)) | ||
699 | { | ||
700 | regInfo.RegionName = config.GetString("localName", ""); | ||
701 | } | ||
702 | else | ||
703 | MainConsole.Instance.Output("Unable to link " + externalHostName + ": " + reason); | ||
704 | } | ||
705 | } | ||
706 | |||
707 | |||
708 | private void LinkRegionCmdUsage() | ||
709 | { | ||
710 | MainConsole.Instance.Output("Usage: link-region <Xloc> <Yloc> <ServerURI> [<RemoteRegionName>]"); | ||
711 | MainConsole.Instance.Output("Usage (deprecated): link-region <Xloc> <Yloc> <HostName>:<HttpPort>[:<RemoteRegionName>]"); | ||
712 | MainConsole.Instance.Output("Usage (deprecated): link-region <Xloc> <Yloc> <HostName> <HttpPort> [<LocalName>]"); | ||
713 | MainConsole.Instance.Output("Usage: link-region <URI_of_xml> [<exclude>]"); | ||
714 | } | ||
715 | |||
716 | private void UnlinkRegionCmdUsage() | ||
717 | { | ||
718 | MainConsole.Instance.Output("Usage: unlink-region <LocalName>"); | ||
719 | } | ||
720 | |||
721 | #endregion | ||
722 | |||
723 | } | ||
724 | } | ||
diff --git a/OpenSim/Services/HypergridService/GatekeeperService.cs b/OpenSim/Services/HypergridService/GatekeeperService.cs new file mode 100644 index 0000000..5d99c79 --- /dev/null +++ b/OpenSim/Services/HypergridService/GatekeeperService.cs | |||
@@ -0,0 +1,383 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Net; | ||
31 | using System.Reflection; | ||
32 | using System.Text.RegularExpressions; | ||
33 | |||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Services.Interfaces; | ||
36 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
37 | using OpenSim.Server.Base; | ||
38 | using OpenSim.Services.Connectors.Hypergrid; | ||
39 | |||
40 | using OpenMetaverse; | ||
41 | |||
42 | using Nini.Config; | ||
43 | using log4net; | ||
44 | |||
45 | namespace OpenSim.Services.HypergridService | ||
46 | { | ||
47 | public class GatekeeperService : IGatekeeperService | ||
48 | { | ||
49 | private static readonly ILog m_log = | ||
50 | LogManager.GetLogger( | ||
51 | MethodBase.GetCurrentMethod().DeclaringType); | ||
52 | |||
53 | private static bool m_Initialized = false; | ||
54 | |||
55 | private static IGridService m_GridService; | ||
56 | private static IPresenceService m_PresenceService; | ||
57 | private static IUserAccountService m_UserAccountService; | ||
58 | private static IUserAgentService m_UserAgentService; | ||
59 | private static ISimulationService m_SimulationService; | ||
60 | |||
61 | protected string m_AllowedClients = string.Empty; | ||
62 | protected string m_DeniedClients = string.Empty; | ||
63 | |||
64 | private static UUID m_ScopeID; | ||
65 | private static bool m_AllowTeleportsToAnyRegion; | ||
66 | private static string m_ExternalName; | ||
67 | private static GridRegion m_DefaultGatewayRegion; | ||
68 | |||
69 | public GatekeeperService(IConfigSource config, ISimulationService simService) | ||
70 | { | ||
71 | if (!m_Initialized) | ||
72 | { | ||
73 | m_Initialized = true; | ||
74 | |||
75 | IConfig serverConfig = config.Configs["GatekeeperService"]; | ||
76 | if (serverConfig == null) | ||
77 | throw new Exception(String.Format("No section GatekeeperService in config file")); | ||
78 | |||
79 | string accountService = serverConfig.GetString("UserAccountService", String.Empty); | ||
80 | string homeUsersService = serverConfig.GetString("UserAgentService", string.Empty); | ||
81 | string gridService = serverConfig.GetString("GridService", String.Empty); | ||
82 | string presenceService = serverConfig.GetString("PresenceService", String.Empty); | ||
83 | string simulationService = serverConfig.GetString("SimulationService", String.Empty); | ||
84 | |||
85 | // These 3 are mandatory, the others aren't | ||
86 | if (gridService == string.Empty || presenceService == string.Empty) | ||
87 | throw new Exception("Incomplete specifications, Gatekeeper Service cannot function."); | ||
88 | |||
89 | string scope = serverConfig.GetString("ScopeID", UUID.Zero.ToString()); | ||
90 | UUID.TryParse(scope, out m_ScopeID); | ||
91 | //m_WelcomeMessage = serverConfig.GetString("WelcomeMessage", "Welcome to OpenSim!"); | ||
92 | m_AllowTeleportsToAnyRegion = serverConfig.GetBoolean("AllowTeleportsToAnyRegion", true); | ||
93 | m_ExternalName = serverConfig.GetString("ExternalName", string.Empty); | ||
94 | if (m_ExternalName != string.Empty && !m_ExternalName.EndsWith("/")) | ||
95 | m_ExternalName = m_ExternalName + "/"; | ||
96 | |||
97 | Object[] args = new Object[] { config }; | ||
98 | m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args); | ||
99 | m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args); | ||
100 | |||
101 | if (accountService != string.Empty) | ||
102 | m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args); | ||
103 | if (homeUsersService != string.Empty) | ||
104 | m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(homeUsersService, args); | ||
105 | |||
106 | if (simService != null) | ||
107 | m_SimulationService = simService; | ||
108 | else if (simulationService != string.Empty) | ||
109 | m_SimulationService = ServerUtils.LoadPlugin<ISimulationService>(simulationService, args); | ||
110 | |||
111 | m_AllowedClients = serverConfig.GetString("AllowedClients", string.Empty); | ||
112 | m_DeniedClients = serverConfig.GetString("DeniedClients", string.Empty); | ||
113 | |||
114 | if (m_GridService == null || m_PresenceService == null || m_SimulationService == null) | ||
115 | throw new Exception("Unable to load a required plugin, Gatekeeper Service cannot function."); | ||
116 | |||
117 | m_log.Debug("[GATEKEEPER SERVICE]: Starting..."); | ||
118 | } | ||
119 | } | ||
120 | |||
121 | public GatekeeperService(IConfigSource config) | ||
122 | : this(config, null) | ||
123 | { | ||
124 | } | ||
125 | |||
126 | public bool LinkRegion(string regionName, out UUID regionID, out ulong regionHandle, out string externalName, out string imageURL, out string reason) | ||
127 | { | ||
128 | regionID = UUID.Zero; | ||
129 | regionHandle = 0; | ||
130 | externalName = m_ExternalName + ((regionName != string.Empty) ? " " + regionName : ""); | ||
131 | imageURL = string.Empty; | ||
132 | reason = string.Empty; | ||
133 | GridRegion region = null; | ||
134 | |||
135 | m_log.DebugFormat("[GATEKEEPER SERVICE]: Request to link to {0}", (regionName == string.Empty)? "default region" : regionName); | ||
136 | if (!m_AllowTeleportsToAnyRegion || regionName == string.Empty) | ||
137 | { | ||
138 | List<GridRegion> defs = m_GridService.GetDefaultRegions(m_ScopeID); | ||
139 | if (defs != null && defs.Count > 0) | ||
140 | { | ||
141 | region = defs[0]; | ||
142 | m_DefaultGatewayRegion = region; | ||
143 | } | ||
144 | else | ||
145 | { | ||
146 | reason = "Grid setup problem. Try specifying a particular region here."; | ||
147 | m_log.DebugFormat("[GATEKEEPER SERVICE]: Unable to send information. Please specify a default region for this grid!"); | ||
148 | return false; | ||
149 | } | ||
150 | } | ||
151 | else | ||
152 | { | ||
153 | region = m_GridService.GetRegionByName(m_ScopeID, regionName); | ||
154 | if (region == null) | ||
155 | { | ||
156 | reason = "Region not found"; | ||
157 | return false; | ||
158 | } | ||
159 | } | ||
160 | |||
161 | regionID = region.RegionID; | ||
162 | regionHandle = region.RegionHandle; | ||
163 | |||
164 | string regionimage = "regionImage" + regionID.ToString(); | ||
165 | regionimage = regionimage.Replace("-", ""); | ||
166 | imageURL = region.ServerURI + "index.php?method=" + regionimage; | ||
167 | |||
168 | return true; | ||
169 | } | ||
170 | |||
171 | public GridRegion GetHyperlinkRegion(UUID regionID) | ||
172 | { | ||
173 | m_log.DebugFormat("[GATEKEEPER SERVICE]: Request to get hyperlink region {0}", regionID); | ||
174 | |||
175 | if (!m_AllowTeleportsToAnyRegion) | ||
176 | // Don't even check the given regionID | ||
177 | return m_DefaultGatewayRegion; | ||
178 | |||
179 | GridRegion region = m_GridService.GetRegionByUUID(m_ScopeID, regionID); | ||
180 | return region; | ||
181 | } | ||
182 | |||
183 | #region Login Agent | ||
184 | public bool LoginAgent(AgentCircuitData aCircuit, GridRegion destination, out string reason) | ||
185 | { | ||
186 | reason = string.Empty; | ||
187 | |||
188 | string authURL = string.Empty; | ||
189 | if (aCircuit.ServiceURLs.ContainsKey("HomeURI")) | ||
190 | authURL = aCircuit.ServiceURLs["HomeURI"].ToString(); | ||
191 | m_log.InfoFormat("[GATEKEEPER SERVICE]: Login request for {0} {1} @ {2} ({3}) at {4} using viewer {5}, channel {6}, IP {7}, Mac {8}, Id0 {9}", | ||
192 | aCircuit.firstname, aCircuit.lastname, authURL, aCircuit.AgentID, destination.RegionName, | ||
193 | aCircuit.Viewer, aCircuit.Channel, aCircuit.IPAddress, aCircuit.Mac, aCircuit.Id0); | ||
194 | |||
195 | // | ||
196 | // Check client | ||
197 | // | ||
198 | if (m_AllowedClients != string.Empty) | ||
199 | { | ||
200 | Regex arx = new Regex(m_AllowedClients); | ||
201 | Match am = arx.Match(aCircuit.Viewer); | ||
202 | |||
203 | if (!am.Success) | ||
204 | { | ||
205 | m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is not allowed", aCircuit.Viewer); | ||
206 | return false; | ||
207 | } | ||
208 | } | ||
209 | |||
210 | if (m_DeniedClients != string.Empty) | ||
211 | { | ||
212 | Regex drx = new Regex(m_DeniedClients); | ||
213 | Match dm = drx.Match(aCircuit.Viewer); | ||
214 | |||
215 | if (dm.Success) | ||
216 | { | ||
217 | m_log.InfoFormat("[GATEKEEPER SERVICE]: Login failed, reason: client {0} is denied", aCircuit.Viewer); | ||
218 | return false; | ||
219 | } | ||
220 | } | ||
221 | |||
222 | // | ||
223 | // Authenticate the user | ||
224 | // | ||
225 | if (!Authenticate(aCircuit)) | ||
226 | { | ||
227 | reason = "Unable to verify identity"; | ||
228 | m_log.InfoFormat("[GATEKEEPER SERVICE]: Unable to verify identity of agent {0} {1}. Refusing service.", aCircuit.firstname, aCircuit.lastname); | ||
229 | return false; | ||
230 | } | ||
231 | m_log.DebugFormat("[GATEKEEPER SERVICE]: Identity verified for {0} {1} @ {2}", aCircuit.firstname, aCircuit.lastname, authURL); | ||
232 | |||
233 | // | ||
234 | // Check for impersonations | ||
235 | // | ||
236 | UserAccount account = null; | ||
237 | if (m_UserAccountService != null) | ||
238 | { | ||
239 | // Check to see if we have a local user with that UUID | ||
240 | account = m_UserAccountService.GetUserAccount(m_ScopeID, aCircuit.AgentID); | ||
241 | if (account != null) | ||
242 | { | ||
243 | // Make sure this is the user coming home, and not a foreign user with same UUID as a local user | ||
244 | if (m_UserAgentService != null) | ||
245 | { | ||
246 | if (!m_UserAgentService.IsAgentComingHome(aCircuit.SessionID, m_ExternalName)) | ||
247 | { | ||
248 | // Can't do, sorry | ||
249 | reason = "Unauthorized"; | ||
250 | m_log.InfoFormat("[GATEKEEPER SERVICE]: Foreign agent {0} {1} has same ID as local user. Refusing service.", | ||
251 | aCircuit.firstname, aCircuit.lastname); | ||
252 | return false; | ||
253 | |||
254 | } | ||
255 | } | ||
256 | } | ||
257 | } | ||
258 | m_log.DebugFormat("[GATEKEEPER SERVICE]: User is ok"); | ||
259 | |||
260 | // May want to authorize | ||
261 | |||
262 | bool isFirstLogin = false; | ||
263 | // | ||
264 | // Login the presence, if it's not there yet (by the login service) | ||
265 | // | ||
266 | PresenceInfo presence = m_PresenceService.GetAgent(aCircuit.SessionID); | ||
267 | if (presence != null) // it has been placed there by the login service | ||
268 | isFirstLogin = true; | ||
269 | |||
270 | else | ||
271 | if (!m_PresenceService.LoginAgent(aCircuit.AgentID.ToString(), aCircuit.SessionID, aCircuit.SecureSessionID)) | ||
272 | { | ||
273 | reason = "Unable to login presence"; | ||
274 | m_log.InfoFormat("[GATEKEEPER SERVICE]: Presence login failed for foreign agent {0} {1}. Refusing service.", | ||
275 | aCircuit.firstname, aCircuit.lastname); | ||
276 | return false; | ||
277 | } | ||
278 | m_log.DebugFormat("[GATEKEEPER SERVICE]: Login presence ok"); | ||
279 | |||
280 | // | ||
281 | // Get the region | ||
282 | // | ||
283 | destination = m_GridService.GetRegionByUUID(m_ScopeID, destination.RegionID); | ||
284 | if (destination == null) | ||
285 | { | ||
286 | reason = "Destination region not found"; | ||
287 | return false; | ||
288 | } | ||
289 | m_log.DebugFormat("[GATEKEEPER SERVICE]: destination ok: {0}", destination.RegionName); | ||
290 | |||
291 | // | ||
292 | // Adjust the visible name | ||
293 | // | ||
294 | if (account != null) | ||
295 | { | ||
296 | aCircuit.firstname = account.FirstName; | ||
297 | aCircuit.lastname = account.LastName; | ||
298 | } | ||
299 | if (account == null && !aCircuit.lastname.StartsWith("@")) | ||
300 | { | ||
301 | aCircuit.firstname = aCircuit.firstname + "." + aCircuit.lastname; | ||
302 | try | ||
303 | { | ||
304 | Uri uri = new Uri(aCircuit.ServiceURLs["HomeURI"].ToString()); | ||
305 | aCircuit.lastname = "@" + uri.Host; // + ":" + uri.Port; | ||
306 | } | ||
307 | catch | ||
308 | { | ||
309 | m_log.WarnFormat("[GATEKEEPER SERVICE]: Malformed HomeURI (this should never happen): {0}", aCircuit.ServiceURLs["HomeURI"]); | ||
310 | aCircuit.lastname = "@" + aCircuit.ServiceURLs["HomeURI"].ToString(); | ||
311 | } | ||
312 | } | ||
313 | |||
314 | // | ||
315 | // Finally launch the agent at the destination | ||
316 | // | ||
317 | Constants.TeleportFlags loginFlag = isFirstLogin ? Constants.TeleportFlags.ViaLogin : Constants.TeleportFlags.ViaHGLogin; | ||
318 | m_log.DebugFormat("[GATEKEEPER SERVICE]: launching agent {0}", loginFlag); | ||
319 | return m_SimulationService.CreateAgent(destination, aCircuit, (uint)loginFlag, out reason); | ||
320 | } | ||
321 | |||
322 | protected bool Authenticate(AgentCircuitData aCircuit) | ||
323 | { | ||
324 | if (!CheckAddress(aCircuit.ServiceSessionID)) | ||
325 | return false; | ||
326 | |||
327 | string userURL = string.Empty; | ||
328 | if (aCircuit.ServiceURLs.ContainsKey("HomeURI")) | ||
329 | userURL = aCircuit.ServiceURLs["HomeURI"].ToString(); | ||
330 | |||
331 | if (userURL == string.Empty) | ||
332 | { | ||
333 | m_log.DebugFormat("[GATEKEEPER SERVICE]: Agent did not provide an authentication server URL"); | ||
334 | return false; | ||
335 | } | ||
336 | |||
337 | if (userURL == m_ExternalName) | ||
338 | { | ||
339 | return m_UserAgentService.VerifyAgent(aCircuit.SessionID, aCircuit.ServiceSessionID); | ||
340 | } | ||
341 | else | ||
342 | { | ||
343 | IUserAgentService userAgentService = new UserAgentServiceConnector(userURL); | ||
344 | |||
345 | try | ||
346 | { | ||
347 | return userAgentService.VerifyAgent(aCircuit.SessionID, aCircuit.ServiceSessionID); | ||
348 | } | ||
349 | catch | ||
350 | { | ||
351 | m_log.DebugFormat("[GATEKEEPER SERVICE]: Unable to contact authentication service at {0}", userURL); | ||
352 | return false; | ||
353 | } | ||
354 | } | ||
355 | |||
356 | return false; | ||
357 | } | ||
358 | |||
359 | // Check that the service token was generated for *this* grid. | ||
360 | // If it wasn't then that's a fake agent. | ||
361 | protected bool CheckAddress(string serviceToken) | ||
362 | { | ||
363 | string[] parts = serviceToken.Split(new char[] { ';' }); | ||
364 | if (parts.Length < 2) | ||
365 | return false; | ||
366 | |||
367 | char[] trailing_slash = new char[] { '/' }; | ||
368 | string addressee = parts[0].TrimEnd(trailing_slash); | ||
369 | string externalname = m_ExternalName.TrimEnd(trailing_slash); | ||
370 | m_log.DebugFormat("[GATEKEEPER SERVICE]: Verifying {0} against {1}", addressee, externalname); | ||
371 | |||
372 | return string.Equals(addressee, externalname, StringComparison.OrdinalIgnoreCase); | ||
373 | } | ||
374 | |||
375 | #endregion | ||
376 | |||
377 | |||
378 | #region Misc | ||
379 | |||
380 | |||
381 | #endregion | ||
382 | } | ||
383 | } | ||
diff --git a/OpenSim/Services/HypergridService/HGAssetService.cs b/OpenSim/Services/HypergridService/HGAssetService.cs new file mode 100644 index 0000000..e518329 --- /dev/null +++ b/OpenSim/Services/HypergridService/HGAssetService.cs | |||
@@ -0,0 +1,148 @@ | |||
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 | using System; | ||
28 | using System.Collections.Generic; | ||
29 | using System.IO; | ||
30 | using System.Reflection; | ||
31 | using System.Xml; | ||
32 | |||
33 | using Nini.Config; | ||
34 | using log4net; | ||
35 | using OpenMetaverse; | ||
36 | |||
37 | using OpenSim.Framework; | ||
38 | using OpenSim.Framework.Serialization.External; | ||
39 | using OpenSim.Server.Base; | ||
40 | using OpenSim.Services.Interfaces; | ||
41 | using OpenSim.Services.AssetService; | ||
42 | |||
43 | namespace OpenSim.Services.HypergridService | ||
44 | { | ||
45 | /// <summary> | ||
46 | /// Hypergrid asset service. It serves the IAssetService interface, | ||
47 | /// but implements it in ways that are appropriate for inter-grid | ||
48 | /// asset exchanges. | ||
49 | /// </summary> | ||
50 | public class HGAssetService : OpenSim.Services.AssetService.AssetService, IAssetService | ||
51 | { | ||
52 | private static readonly ILog m_log = | ||
53 | LogManager.GetLogger( | ||
54 | MethodBase.GetCurrentMethod().DeclaringType); | ||
55 | |||
56 | private string m_ProfileServiceURL; | ||
57 | private IUserAccountService m_UserAccountService; | ||
58 | |||
59 | private UserAccountCache m_Cache; | ||
60 | |||
61 | public HGAssetService(IConfigSource config) : base(config) | ||
62 | { | ||
63 | m_log.Debug("[HGAsset Service]: Starting"); | ||
64 | IConfig assetConfig = config.Configs["HGAssetService"]; | ||
65 | if (assetConfig == null) | ||
66 | throw new Exception("No HGAssetService configuration"); | ||
67 | |||
68 | string userAccountsDll = assetConfig.GetString("UserAccountsService", string.Empty); | ||
69 | if (userAccountsDll == string.Empty) | ||
70 | throw new Exception("Please specify UserAccountsService in HGAssetService configuration"); | ||
71 | |||
72 | Object[] args = new Object[] { config }; | ||
73 | m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(userAccountsDll, args); | ||
74 | if (m_UserAccountService == null) | ||
75 | throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll)); | ||
76 | |||
77 | m_ProfileServiceURL = assetConfig.GetString("ProfileServerURI", string.Empty); | ||
78 | |||
79 | m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService); | ||
80 | } | ||
81 | |||
82 | #region IAssetService overrides | ||
83 | public override AssetBase Get(string id) | ||
84 | { | ||
85 | AssetBase asset = base.Get(id); | ||
86 | |||
87 | if (asset == null) | ||
88 | return null; | ||
89 | |||
90 | if (asset.Metadata.Type == (sbyte)AssetType.Object) | ||
91 | asset.Data = AdjustIdentifiers(asset.Data); ; | ||
92 | |||
93 | AdjustIdentifiers(asset.Metadata); | ||
94 | |||
95 | return asset; | ||
96 | } | ||
97 | |||
98 | public override AssetMetadata GetMetadata(string id) | ||
99 | { | ||
100 | AssetMetadata meta = base.GetMetadata(id); | ||
101 | |||
102 | if (meta == null) | ||
103 | return null; | ||
104 | |||
105 | AdjustIdentifiers(meta); | ||
106 | |||
107 | return meta; | ||
108 | } | ||
109 | |||
110 | public override byte[] GetData(string id) | ||
111 | { | ||
112 | byte[] data = base.GetData(id); | ||
113 | |||
114 | if (data == null) | ||
115 | return null; | ||
116 | |||
117 | return AdjustIdentifiers(data); | ||
118 | } | ||
119 | |||
120 | //public virtual bool Get(string id, Object sender, AssetRetrieved handler) | ||
121 | |||
122 | public override bool Delete(string id) | ||
123 | { | ||
124 | // NOGO | ||
125 | return false; | ||
126 | } | ||
127 | |||
128 | #endregion | ||
129 | |||
130 | protected void AdjustIdentifiers(AssetMetadata meta) | ||
131 | { | ||
132 | if (meta == null || m_Cache == null) | ||
133 | return; | ||
134 | |||
135 | UserAccount creator = m_Cache.GetUser(meta.CreatorID); | ||
136 | if (creator != null) | ||
137 | meta.CreatorID = m_ProfileServiceURL + "/" + meta.CreatorID + ";" + creator.FirstName + " " + creator.LastName; | ||
138 | } | ||
139 | |||
140 | protected byte[] AdjustIdentifiers(byte[] data) | ||
141 | { | ||
142 | string xml = Utils.BytesToString(data); | ||
143 | return Utils.StringToBytes(ExternalRepresentationUtils.RewriteSOP(xml, m_ProfileServiceURL, m_Cache, UUID.Zero)); | ||
144 | } | ||
145 | |||
146 | } | ||
147 | |||
148 | } | ||
diff --git a/OpenSim/Services/HypergridService/HGInstantMessageService.cs b/OpenSim/Services/HypergridService/HGInstantMessageService.cs new file mode 100644 index 0000000..0c9cfd3 --- /dev/null +++ b/OpenSim/Services/HypergridService/HGInstantMessageService.cs | |||
@@ -0,0 +1,346 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Net; | ||
31 | using System.Reflection; | ||
32 | |||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Services.Connectors.Friends; | ||
35 | using OpenSim.Services.Connectors.Hypergrid; | ||
36 | using OpenSim.Services.Interfaces; | ||
37 | using OpenSim.Services.Connectors.InstantMessage; | ||
38 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
39 | using OpenSim.Server.Base; | ||
40 | using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; | ||
41 | |||
42 | using OpenMetaverse; | ||
43 | using log4net; | ||
44 | using Nini.Config; | ||
45 | |||
46 | namespace OpenSim.Services.HypergridService | ||
47 | { | ||
48 | /// <summary> | ||
49 | /// Inter-grid IM | ||
50 | /// </summary> | ||
51 | public class HGInstantMessageService : IInstantMessage | ||
52 | { | ||
53 | private static readonly ILog m_log = | ||
54 | LogManager.GetLogger( | ||
55 | MethodBase.GetCurrentMethod().DeclaringType); | ||
56 | |||
57 | private const double CACHE_EXPIRATION_SECONDS = 120000.0; // 33 hours | ||
58 | |||
59 | static bool m_Initialized = false; | ||
60 | |||
61 | protected static IGridService m_GridService; | ||
62 | protected static IPresenceService m_PresenceService; | ||
63 | protected static IUserAgentService m_UserAgentService; | ||
64 | |||
65 | protected static IInstantMessageSimConnector m_IMSimConnector; | ||
66 | |||
67 | protected static Dictionary<UUID, object> m_UserLocationMap = new Dictionary<UUID, object>(); | ||
68 | private static ExpiringCache<UUID, GridRegion> m_RegionCache; | ||
69 | |||
70 | private static string m_RestURL; | ||
71 | private static bool m_ForwardOfflineGroupMessages; | ||
72 | private static bool m_InGatekeeper; | ||
73 | |||
74 | public HGInstantMessageService(IConfigSource config) | ||
75 | : this(config, null) | ||
76 | { | ||
77 | } | ||
78 | |||
79 | public HGInstantMessageService(IConfigSource config, IInstantMessageSimConnector imConnector) | ||
80 | { | ||
81 | if (imConnector != null) | ||
82 | m_IMSimConnector = imConnector; | ||
83 | |||
84 | if (!m_Initialized) | ||
85 | { | ||
86 | m_Initialized = true; | ||
87 | |||
88 | IConfig serverConfig = config.Configs["HGInstantMessageService"]; | ||
89 | if (serverConfig == null) | ||
90 | throw new Exception(String.Format("No section HGInstantMessageService in config file")); | ||
91 | |||
92 | string gridService = serverConfig.GetString("GridService", String.Empty); | ||
93 | string presenceService = serverConfig.GetString("PresenceService", String.Empty); | ||
94 | string userAgentService = serverConfig.GetString("UserAgentService", String.Empty); | ||
95 | m_InGatekeeper = serverConfig.GetBoolean("InGatekeeper", false); | ||
96 | m_log.DebugFormat("[HG IM SERVICE]: Starting... InRobust? {0}", m_InGatekeeper); | ||
97 | |||
98 | if (gridService == string.Empty || presenceService == string.Empty) | ||
99 | throw new Exception(String.Format("Incomplete specifications, InstantMessage Service cannot function.")); | ||
100 | |||
101 | Object[] args = new Object[] { config }; | ||
102 | m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args); | ||
103 | m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args); | ||
104 | m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(userAgentService, args); | ||
105 | |||
106 | m_RegionCache = new ExpiringCache<UUID, GridRegion>(); | ||
107 | |||
108 | IConfig cnf = config.Configs["Messaging"]; | ||
109 | if (cnf == null) | ||
110 | { | ||
111 | return; | ||
112 | } | ||
113 | |||
114 | m_RestURL = cnf.GetString("OfflineMessageURL", string.Empty); | ||
115 | m_ForwardOfflineGroupMessages = cnf.GetBoolean("ForwardOfflineGroupMessages", false); | ||
116 | |||
117 | } | ||
118 | } | ||
119 | |||
120 | public bool IncomingInstantMessage(GridInstantMessage im) | ||
121 | { | ||
122 | // m_log.DebugFormat("[HG IM SERVICE]: Received message from {0} to {1}", im.fromAgentID, im.toAgentID); | ||
123 | // UUID toAgentID = new UUID(im.toAgentID); | ||
124 | |||
125 | bool success = false; | ||
126 | if (m_IMSimConnector != null) | ||
127 | { | ||
128 | //m_log.DebugFormat("[XXX] SendIMToRegion local im connector"); | ||
129 | success = m_IMSimConnector.SendInstantMessage(im); | ||
130 | } | ||
131 | else | ||
132 | { | ||
133 | success = TrySendInstantMessage(im, "", true, false); | ||
134 | } | ||
135 | |||
136 | if (!success && m_InGatekeeper) // we do this only in the Gatekeeper IM service | ||
137 | UndeliveredMessage(im); | ||
138 | |||
139 | return success; | ||
140 | } | ||
141 | |||
142 | public bool OutgoingInstantMessage(GridInstantMessage im, string url, bool foreigner) | ||
143 | { | ||
144 | // m_log.DebugFormat("[HG IM SERVICE]: Sending message from {0} to {1}@{2}", im.fromAgentID, im.toAgentID, url); | ||
145 | if (url != string.Empty) | ||
146 | return TrySendInstantMessage(im, url, true, foreigner); | ||
147 | else | ||
148 | { | ||
149 | PresenceInfo upd = new PresenceInfo(); | ||
150 | upd.RegionID = UUID.Zero; | ||
151 | return TrySendInstantMessage(im, upd, true, foreigner); | ||
152 | } | ||
153 | |||
154 | } | ||
155 | |||
156 | protected bool TrySendInstantMessage(GridInstantMessage im, object previousLocation, bool firstTime, bool foreigner) | ||
157 | { | ||
158 | UUID toAgentID = new UUID(im.toAgentID); | ||
159 | |||
160 | PresenceInfo upd = null; | ||
161 | string url = string.Empty; | ||
162 | |||
163 | bool lookupAgent = false; | ||
164 | |||
165 | lock (m_UserLocationMap) | ||
166 | { | ||
167 | if (m_UserLocationMap.ContainsKey(toAgentID)) | ||
168 | { | ||
169 | object o = m_UserLocationMap[toAgentID]; | ||
170 | if (o is PresenceInfo) | ||
171 | upd = (PresenceInfo)o; | ||
172 | else if (o is string) | ||
173 | url = (string)o; | ||
174 | |||
175 | // We need to compare the current location with the previous | ||
176 | // or the recursive loop will never end because it will never try to lookup the agent again | ||
177 | if (!firstTime) | ||
178 | { | ||
179 | lookupAgent = true; | ||
180 | upd = null; | ||
181 | } | ||
182 | } | ||
183 | else | ||
184 | { | ||
185 | lookupAgent = true; | ||
186 | } | ||
187 | } | ||
188 | |||
189 | //m_log.DebugFormat("[XXX] Neeed lookup ? {0}", (lookupAgent ? "yes" : "no")); | ||
190 | |||
191 | // Are we needing to look-up an agent? | ||
192 | if (lookupAgent) | ||
193 | { | ||
194 | // Non-cached user agent lookup. | ||
195 | PresenceInfo[] presences = m_PresenceService.GetAgents(new string[] { toAgentID.ToString() }); | ||
196 | if (presences != null && presences.Length > 0) | ||
197 | { | ||
198 | foreach (PresenceInfo p in presences) | ||
199 | { | ||
200 | if (p.RegionID != UUID.Zero) | ||
201 | { | ||
202 | //m_log.DebugFormat("[XXX]: Found presence in {0}", p.RegionID); | ||
203 | upd = p; | ||
204 | break; | ||
205 | } | ||
206 | } | ||
207 | } | ||
208 | |||
209 | if (upd == null && !foreigner) | ||
210 | { | ||
211 | // Let's check with the UAS if the user is elsewhere | ||
212 | m_log.DebugFormat("[HG IM SERVICE]: User is not present. Checking location with User Agent service"); | ||
213 | url = m_UserAgentService.LocateUser(toAgentID); | ||
214 | } | ||
215 | |||
216 | // check if we've tried this before.. | ||
217 | // This is one way to end the recursive loop | ||
218 | // | ||
219 | if (!firstTime && ((previousLocation is PresenceInfo && upd != null && upd.RegionID == ((PresenceInfo)previousLocation).RegionID) || | ||
220 | (previousLocation is string && upd == null && previousLocation.Equals(url)))) | ||
221 | { | ||
222 | // m_log.Error("[GRID INSTANT MESSAGE]: Unable to deliver an instant message"); | ||
223 | m_log.DebugFormat("[HG IM SERVICE]: Fail 2 {0} {1}", previousLocation, url); | ||
224 | |||
225 | return false; | ||
226 | } | ||
227 | } | ||
228 | |||
229 | if (upd != null) | ||
230 | { | ||
231 | // ok, the user is around somewhere. Let's send back the reply with "success" | ||
232 | // even though the IM may still fail. Just don't keep the caller waiting for | ||
233 | // the entire time we're trying to deliver the IM | ||
234 | return SendIMToRegion(upd, im, toAgentID, foreigner); | ||
235 | } | ||
236 | else if (url != string.Empty) | ||
237 | { | ||
238 | // ok, the user is around somewhere. Let's send back the reply with "success" | ||
239 | // even though the IM may still fail. Just don't keep the caller waiting for | ||
240 | // the entire time we're trying to deliver the IM | ||
241 | return ForwardIMToGrid(url, im, toAgentID, foreigner); | ||
242 | } | ||
243 | else if (firstTime && previousLocation is string && (string)previousLocation != string.Empty) | ||
244 | { | ||
245 | return ForwardIMToGrid((string)previousLocation, im, toAgentID, foreigner); | ||
246 | } | ||
247 | else | ||
248 | m_log.DebugFormat("[HG IM SERVICE]: Unable to locate user {0}", toAgentID); | ||
249 | return false; | ||
250 | } | ||
251 | |||
252 | bool SendIMToRegion(PresenceInfo upd, GridInstantMessage im, UUID toAgentID, bool foreigner) | ||
253 | { | ||
254 | bool imresult = false; | ||
255 | GridRegion reginfo = null; | ||
256 | if (!m_RegionCache.TryGetValue(upd.RegionID, out reginfo)) | ||
257 | { | ||
258 | reginfo = m_GridService.GetRegionByUUID(UUID.Zero /*!!!*/, upd.RegionID); | ||
259 | if (reginfo != null) | ||
260 | m_RegionCache.AddOrUpdate(upd.RegionID, reginfo, CACHE_EXPIRATION_SECONDS); | ||
261 | } | ||
262 | |||
263 | if (reginfo != null) | ||
264 | { | ||
265 | imresult = InstantMessageServiceConnector.SendInstantMessage(reginfo.ServerURI, im); | ||
266 | } | ||
267 | else | ||
268 | { | ||
269 | m_log.DebugFormat("[HG IM SERVICE]: Failed to deliver message to {0}", reginfo.ServerURI); | ||
270 | return false; | ||
271 | } | ||
272 | |||
273 | if (imresult) | ||
274 | { | ||
275 | // IM delivery successful, so store the Agent's location in our local cache. | ||
276 | lock (m_UserLocationMap) | ||
277 | { | ||
278 | if (m_UserLocationMap.ContainsKey(toAgentID)) | ||
279 | { | ||
280 | m_UserLocationMap[toAgentID] = upd; | ||
281 | } | ||
282 | else | ||
283 | { | ||
284 | m_UserLocationMap.Add(toAgentID, upd); | ||
285 | } | ||
286 | } | ||
287 | return true; | ||
288 | } | ||
289 | else | ||
290 | { | ||
291 | // try again, but lookup user this time. | ||
292 | // Warning, this must call the Async version | ||
293 | // of this method or we'll be making thousands of threads | ||
294 | // The version within the spawned thread is SendGridInstantMessageViaXMLRPCAsync | ||
295 | // The version that spawns the thread is SendGridInstantMessageViaXMLRPC | ||
296 | |||
297 | // This is recursive!!!!! | ||
298 | return TrySendInstantMessage(im, upd, false, foreigner); | ||
299 | } | ||
300 | } | ||
301 | |||
302 | bool ForwardIMToGrid(string url, GridInstantMessage im, UUID toAgentID, bool foreigner) | ||
303 | { | ||
304 | if (InstantMessageServiceConnector.SendInstantMessage(url, im)) | ||
305 | { | ||
306 | // IM delivery successful, so store the Agent's location in our local cache. | ||
307 | lock (m_UserLocationMap) | ||
308 | { | ||
309 | if (m_UserLocationMap.ContainsKey(toAgentID)) | ||
310 | { | ||
311 | m_UserLocationMap[toAgentID] = url; | ||
312 | } | ||
313 | else | ||
314 | { | ||
315 | m_UserLocationMap.Add(toAgentID, url); | ||
316 | } | ||
317 | } | ||
318 | |||
319 | return true; | ||
320 | } | ||
321 | else | ||
322 | { | ||
323 | // try again, but lookup user this time. | ||
324 | |||
325 | // This is recursive!!!!! | ||
326 | return TrySendInstantMessage(im, url, false, foreigner); | ||
327 | } | ||
328 | } | ||
329 | |||
330 | private bool UndeliveredMessage(GridInstantMessage im) | ||
331 | { | ||
332 | if (m_RestURL != string.Empty && (im.offline != 0) | ||
333 | && (!im.fromGroup || (im.fromGroup && m_ForwardOfflineGroupMessages))) | ||
334 | { | ||
335 | // m_log.DebugFormat("[HG IM SERVICE]: Message saved"); | ||
336 | |||
337 | return SynchronousRestObjectRequester.MakeRequest<GridInstantMessage, bool>( | ||
338 | "POST", m_RestURL + "/SaveMessage/", im); | ||
339 | } | ||
340 | else | ||
341 | { | ||
342 | return false; | ||
343 | } | ||
344 | } | ||
345 | } | ||
346 | } \ No newline at end of file | ||
diff --git a/OpenSim/Services/HypergridService/HGInventoryService.cs b/OpenSim/Services/HypergridService/HGInventoryService.cs new file mode 100644 index 0000000..4eb61ba --- /dev/null +++ b/OpenSim/Services/HypergridService/HGInventoryService.cs | |||
@@ -0,0 +1,342 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | using log4net; | ||
32 | using Nini.Config; | ||
33 | using System.Reflection; | ||
34 | using OpenSim.Services.Base; | ||
35 | using OpenSim.Services.Interfaces; | ||
36 | using OpenSim.Services.InventoryService; | ||
37 | using OpenSim.Data; | ||
38 | using OpenSim.Framework; | ||
39 | using OpenSim.Server.Base; | ||
40 | |||
41 | namespace OpenSim.Services.HypergridService | ||
42 | { | ||
43 | /// <summary> | ||
44 | /// Hypergrid inventory service. It serves the IInventoryService interface, | ||
45 | /// but implements it in ways that are appropriate for inter-grid | ||
46 | /// inventory exchanges. Specifically, it does not performs deletions | ||
47 | /// and it responds to GetRootFolder requests with the ID of the | ||
48 | /// Suitcase folder, not the actual "My Inventory" folder. | ||
49 | /// </summary> | ||
50 | public class HGInventoryService : XInventoryService, IInventoryService | ||
51 | { | ||
52 | private static readonly ILog m_log = | ||
53 | LogManager.GetLogger( | ||
54 | MethodBase.GetCurrentMethod().DeclaringType); | ||
55 | |||
56 | protected new IXInventoryData m_Database; | ||
57 | |||
58 | private string m_ProfileServiceURL; | ||
59 | private IUserAccountService m_UserAccountService; | ||
60 | |||
61 | private UserAccountCache m_Cache; | ||
62 | |||
63 | public HGInventoryService(IConfigSource config) | ||
64 | : base(config) | ||
65 | { | ||
66 | m_log.Debug("[HGInventory Service]: Starting"); | ||
67 | |||
68 | string dllName = String.Empty; | ||
69 | string connString = String.Empty; | ||
70 | //string realm = "Inventory"; // OSG version doesn't use this | ||
71 | |||
72 | // | ||
73 | // Try reading the [DatabaseService] section, if it exists | ||
74 | // | ||
75 | IConfig dbConfig = config.Configs["DatabaseService"]; | ||
76 | if (dbConfig != null) | ||
77 | { | ||
78 | if (dllName == String.Empty) | ||
79 | dllName = dbConfig.GetString("StorageProvider", String.Empty); | ||
80 | if (connString == String.Empty) | ||
81 | connString = dbConfig.GetString("ConnectionString", String.Empty); | ||
82 | } | ||
83 | |||
84 | // | ||
85 | // Try reading the [InventoryService] section, if it exists | ||
86 | // | ||
87 | IConfig invConfig = config.Configs["HGInventoryService"]; | ||
88 | if (invConfig != null) | ||
89 | { | ||
90 | dllName = invConfig.GetString("StorageProvider", dllName); | ||
91 | connString = invConfig.GetString("ConnectionString", connString); | ||
92 | |||
93 | // realm = authConfig.GetString("Realm", realm); | ||
94 | string userAccountsDll = invConfig.GetString("UserAccountsService", string.Empty); | ||
95 | if (userAccountsDll == string.Empty) | ||
96 | throw new Exception("Please specify UserAccountsService in HGInventoryService configuration"); | ||
97 | |||
98 | Object[] args = new Object[] { config }; | ||
99 | m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(userAccountsDll, args); | ||
100 | if (m_UserAccountService == null) | ||
101 | throw new Exception(String.Format("Unable to create UserAccountService from {0}", userAccountsDll)); | ||
102 | |||
103 | m_ProfileServiceURL = invConfig.GetString("ProfileServerURI", string.Empty); | ||
104 | |||
105 | m_Cache = UserAccountCache.CreateUserAccountCache(m_UserAccountService); | ||
106 | } | ||
107 | |||
108 | // | ||
109 | // We tried, but this doesn't exist. We can't proceed. | ||
110 | // | ||
111 | if (dllName == String.Empty) | ||
112 | throw new Exception("No StorageProvider configured"); | ||
113 | |||
114 | m_Database = LoadPlugin<IXInventoryData>(dllName, | ||
115 | new Object[] {connString, String.Empty}); | ||
116 | if (m_Database == null) | ||
117 | throw new Exception("Could not find a storage interface in the given module"); | ||
118 | |||
119 | m_log.Debug("[HG INVENTORY SERVICE]: Starting..."); | ||
120 | } | ||
121 | |||
122 | public override bool CreateUserInventory(UUID principalID) | ||
123 | { | ||
124 | // NOGO | ||
125 | return false; | ||
126 | } | ||
127 | |||
128 | |||
129 | public override List<InventoryFolderBase> GetInventorySkeleton(UUID principalID) | ||
130 | { | ||
131 | // NOGO for this inventory service | ||
132 | return new List<InventoryFolderBase>(); | ||
133 | } | ||
134 | |||
135 | public override InventoryFolderBase GetRootFolder(UUID principalID) | ||
136 | { | ||
137 | //m_log.DebugFormat("[HG INVENTORY SERVICE]: GetRootFolder for {0}", principalID); | ||
138 | // Warp! Root folder for travelers | ||
139 | XInventoryFolder[] folders = m_Database.GetFolders( | ||
140 | new string[] { "agentID", "folderName"}, | ||
141 | new string[] { principalID.ToString(), "My Suitcase" }); | ||
142 | |||
143 | if (folders.Length > 0) | ||
144 | return ConvertToOpenSim(folders[0]); | ||
145 | |||
146 | // make one | ||
147 | XInventoryFolder suitcase = CreateFolder(principalID, UUID.Zero, (int)AssetType.Folder, "My Suitcase"); | ||
148 | return ConvertToOpenSim(suitcase); | ||
149 | } | ||
150 | |||
151 | //private bool CreateSystemFolders(UUID principalID, XInventoryFolder suitcase) | ||
152 | //{ | ||
153 | |||
154 | // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Animation, "Animations"); | ||
155 | // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Bodypart, "Body Parts"); | ||
156 | // CreateFolder(principalID, suitcase.folderID, (int)AssetType.CallingCard, "Calling Cards"); | ||
157 | // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Clothing, "Clothing"); | ||
158 | // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Gesture, "Gestures"); | ||
159 | // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Landmark, "Landmarks"); | ||
160 | // CreateFolder(principalID, suitcase.folderID, (int)AssetType.LostAndFoundFolder, "Lost And Found"); | ||
161 | // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Notecard, "Notecards"); | ||
162 | // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Object, "Objects"); | ||
163 | // CreateFolder(principalID, suitcase.folderID, (int)AssetType.SnapshotFolder, "Photo Album"); | ||
164 | // CreateFolder(principalID, suitcase.folderID, (int)AssetType.LSLText, "Scripts"); | ||
165 | // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Sound, "Sounds"); | ||
166 | // CreateFolder(principalID, suitcase.folderID, (int)AssetType.Texture, "Textures"); | ||
167 | // CreateFolder(principalID, suitcase.folderID, (int)AssetType.TrashFolder, "Trash"); | ||
168 | |||
169 | // return true; | ||
170 | //} | ||
171 | |||
172 | |||
173 | public override InventoryFolderBase GetFolderForType(UUID principalID, AssetType type) | ||
174 | { | ||
175 | //m_log.DebugFormat("[HG INVENTORY SERVICE]: GetFolderForType for {0} {0}", principalID, type); | ||
176 | return GetRootFolder(principalID); | ||
177 | } | ||
178 | |||
179 | // | ||
180 | // Use the inherited methods | ||
181 | // | ||
182 | //public InventoryCollection GetFolderContent(UUID principalID, UUID folderID) | ||
183 | //{ | ||
184 | //} | ||
185 | |||
186 | //public List<InventoryItemBase> GetFolderItems(UUID principalID, UUID folderID) | ||
187 | //{ | ||
188 | //} | ||
189 | |||
190 | //public override bool AddFolder(InventoryFolderBase folder) | ||
191 | //{ | ||
192 | // // Check if it's under the Suitcase folder | ||
193 | // List<InventoryFolderBase> skel = base.GetInventorySkeleton(folder.Owner); | ||
194 | // InventoryFolderBase suitcase = GetRootFolder(folder.Owner); | ||
195 | // List<InventoryFolderBase> suitDescendents = GetDescendents(skel, suitcase.ID); | ||
196 | |||
197 | // foreach (InventoryFolderBase f in suitDescendents) | ||
198 | // if (folder.ParentID == f.ID) | ||
199 | // { | ||
200 | // XInventoryFolder xFolder = ConvertFromOpenSim(folder); | ||
201 | // return m_Database.StoreFolder(xFolder); | ||
202 | // } | ||
203 | // return false; | ||
204 | //} | ||
205 | |||
206 | private List<InventoryFolderBase> GetDescendents(List<InventoryFolderBase> lst, UUID root) | ||
207 | { | ||
208 | List<InventoryFolderBase> direct = lst.FindAll(delegate(InventoryFolderBase f) { return f.ParentID == root; }); | ||
209 | if (direct == null) | ||
210 | return new List<InventoryFolderBase>(); | ||
211 | |||
212 | List<InventoryFolderBase> indirect = new List<InventoryFolderBase>(); | ||
213 | foreach (InventoryFolderBase f in direct) | ||
214 | indirect.AddRange(GetDescendents(lst, f.ID)); | ||
215 | |||
216 | direct.AddRange(indirect); | ||
217 | return direct; | ||
218 | } | ||
219 | |||
220 | // Use inherited method | ||
221 | //public bool UpdateFolder(InventoryFolderBase folder) | ||
222 | //{ | ||
223 | //} | ||
224 | |||
225 | //public override bool MoveFolder(InventoryFolderBase folder) | ||
226 | //{ | ||
227 | // XInventoryFolder[] x = m_Database.GetFolders( | ||
228 | // new string[] { "folderID" }, | ||
229 | // new string[] { folder.ID.ToString() }); | ||
230 | |||
231 | // if (x.Length == 0) | ||
232 | // return false; | ||
233 | |||
234 | // // Check if it's under the Suitcase folder | ||
235 | // List<InventoryFolderBase> skel = base.GetInventorySkeleton(folder.Owner); | ||
236 | // InventoryFolderBase suitcase = GetRootFolder(folder.Owner); | ||
237 | // List<InventoryFolderBase> suitDescendents = GetDescendents(skel, suitcase.ID); | ||
238 | |||
239 | // foreach (InventoryFolderBase f in suitDescendents) | ||
240 | // if (folder.ParentID == f.ID) | ||
241 | // { | ||
242 | // x[0].parentFolderID = folder.ParentID; | ||
243 | // return m_Database.StoreFolder(x[0]); | ||
244 | // } | ||
245 | |||
246 | // return false; | ||
247 | //} | ||
248 | |||
249 | public override bool DeleteFolders(UUID principalID, List<UUID> folderIDs) | ||
250 | { | ||
251 | // NOGO | ||
252 | return false; | ||
253 | } | ||
254 | |||
255 | public override bool PurgeFolder(InventoryFolderBase folder) | ||
256 | { | ||
257 | // NOGO | ||
258 | return false; | ||
259 | } | ||
260 | |||
261 | // Unfortunately we need to use the inherited method because of how DeRez works. | ||
262 | // The viewer sends the folderID hard-wired in the derez message | ||
263 | //public override bool AddItem(InventoryItemBase item) | ||
264 | //{ | ||
265 | // // Check if it's under the Suitcase folder | ||
266 | // List<InventoryFolderBase> skel = base.GetInventorySkeleton(item.Owner); | ||
267 | // InventoryFolderBase suitcase = GetRootFolder(item.Owner); | ||
268 | // List<InventoryFolderBase> suitDescendents = GetDescendents(skel, suitcase.ID); | ||
269 | |||
270 | // foreach (InventoryFolderBase f in suitDescendents) | ||
271 | // if (item.Folder == f.ID) | ||
272 | // return m_Database.StoreItem(ConvertFromOpenSim(item)); | ||
273 | |||
274 | // return false; | ||
275 | //} | ||
276 | |||
277 | //public override bool UpdateItem(InventoryItemBase item) | ||
278 | //{ | ||
279 | // // Check if it's under the Suitcase folder | ||
280 | // List<InventoryFolderBase> skel = base.GetInventorySkeleton(item.Owner); | ||
281 | // InventoryFolderBase suitcase = GetRootFolder(item.Owner); | ||
282 | // List<InventoryFolderBase> suitDescendents = GetDescendents(skel, suitcase.ID); | ||
283 | |||
284 | // foreach (InventoryFolderBase f in suitDescendents) | ||
285 | // if (item.Folder == f.ID) | ||
286 | // return m_Database.StoreItem(ConvertFromOpenSim(item)); | ||
287 | |||
288 | // return false; | ||
289 | //} | ||
290 | |||
291 | //public override bool MoveItems(UUID principalID, List<InventoryItemBase> items) | ||
292 | //{ | ||
293 | // // Principal is b0rked. *sigh* | ||
294 | // // | ||
295 | // // Let's assume they all have the same principal | ||
296 | // // Check if it's under the Suitcase folder | ||
297 | // List<InventoryFolderBase> skel = base.GetInventorySkeleton(items[0].Owner); | ||
298 | // InventoryFolderBase suitcase = GetRootFolder(items[0].Owner); | ||
299 | // List<InventoryFolderBase> suitDescendents = GetDescendents(skel, suitcase.ID); | ||
300 | |||
301 | // foreach (InventoryItemBase i in items) | ||
302 | // { | ||
303 | // foreach (InventoryFolderBase f in suitDescendents) | ||
304 | // if (i.Folder == f.ID) | ||
305 | // m_Database.MoveItem(i.ID.ToString(), i.Folder.ToString()); | ||
306 | // } | ||
307 | |||
308 | // return true; | ||
309 | //} | ||
310 | |||
311 | // Let these pass. Use inherited methods. | ||
312 | //public bool DeleteItems(UUID principalID, List<UUID> itemIDs) | ||
313 | //{ | ||
314 | //} | ||
315 | |||
316 | public override InventoryItemBase GetItem(InventoryItemBase item) | ||
317 | { | ||
318 | InventoryItemBase it = base.GetItem(item); | ||
319 | |||
320 | UserAccount user = m_Cache.GetUser(it.CreatorId); | ||
321 | |||
322 | // Adjust the creator data | ||
323 | if (user != null && it != null && (it.CreatorData == null || it.CreatorData == string.Empty)) | ||
324 | it.CreatorData = m_ProfileServiceURL + "/" + it.CreatorId + ";" + user.FirstName + " " + user.LastName; | ||
325 | |||
326 | return it; | ||
327 | } | ||
328 | |||
329 | //public InventoryFolderBase GetFolder(InventoryFolderBase folder) | ||
330 | //{ | ||
331 | //} | ||
332 | |||
333 | //public List<InventoryItemBase> GetActiveGestures(UUID principalID) | ||
334 | //{ | ||
335 | //} | ||
336 | |||
337 | //public int GetAssetPermissions(UUID principalID, UUID assetID) | ||
338 | //{ | ||
339 | //} | ||
340 | |||
341 | } | ||
342 | } | ||
diff --git a/OpenSim/Services/HypergridService/UserAccountCache.cs b/OpenSim/Services/HypergridService/UserAccountCache.cs new file mode 100644 index 0000000..e0a3e61 --- /dev/null +++ b/OpenSim/Services/HypergridService/UserAccountCache.cs | |||
@@ -0,0 +1,111 @@ | |||
1 | using System; | ||
2 | using System.Collections.Generic; | ||
3 | using System.Reflection; | ||
4 | |||
5 | using log4net; | ||
6 | using OpenMetaverse; | ||
7 | |||
8 | using OpenSim.Services.Interfaces; | ||
9 | |||
10 | namespace OpenSim.Services.HypergridService | ||
11 | { | ||
12 | public class UserAccountCache : IUserAccountService | ||
13 | { | ||
14 | private const double CACHE_EXPIRATION_SECONDS = 120000.0; // 33 hours! | ||
15 | |||
16 | // private static readonly ILog m_log = | ||
17 | // LogManager.GetLogger( | ||
18 | // MethodBase.GetCurrentMethod().DeclaringType); | ||
19 | |||
20 | private ExpiringCache<UUID, UserAccount> m_UUIDCache; | ||
21 | |||
22 | private IUserAccountService m_UserAccountService; | ||
23 | |||
24 | private static UserAccountCache m_Singleton; | ||
25 | |||
26 | public static UserAccountCache CreateUserAccountCache(IUserAccountService u) | ||
27 | { | ||
28 | if (m_Singleton == null) | ||
29 | m_Singleton = new UserAccountCache(u); | ||
30 | |||
31 | return m_Singleton; | ||
32 | } | ||
33 | |||
34 | private UserAccountCache(IUserAccountService u) | ||
35 | { | ||
36 | m_UUIDCache = new ExpiringCache<UUID, UserAccount>(); | ||
37 | m_UserAccountService = u; | ||
38 | } | ||
39 | |||
40 | public void Cache(UUID userID, UserAccount account) | ||
41 | { | ||
42 | // Cache even null accounts | ||
43 | m_UUIDCache.AddOrUpdate(userID, account, CACHE_EXPIRATION_SECONDS); | ||
44 | |||
45 | //m_log.DebugFormat("[USER CACHE]: cached user {0}", userID); | ||
46 | } | ||
47 | |||
48 | public UserAccount Get(UUID userID, out bool inCache) | ||
49 | { | ||
50 | UserAccount account = null; | ||
51 | inCache = false; | ||
52 | if (m_UUIDCache.TryGetValue(userID, out account)) | ||
53 | { | ||
54 | //m_log.DebugFormat("[USER CACHE]: Account {0} {1} found in cache", account.FirstName, account.LastName); | ||
55 | inCache = true; | ||
56 | return account; | ||
57 | } | ||
58 | |||
59 | return null; | ||
60 | } | ||
61 | |||
62 | public UserAccount GetUser(string id) | ||
63 | { | ||
64 | UUID uuid = UUID.Zero; | ||
65 | UUID.TryParse(id, out uuid); | ||
66 | bool inCache = false; | ||
67 | UserAccount account = Get(uuid, out inCache); | ||
68 | if (!inCache) | ||
69 | { | ||
70 | account = m_UserAccountService.GetUserAccount(UUID.Zero, uuid); | ||
71 | Cache(uuid, account); | ||
72 | } | ||
73 | |||
74 | return account; | ||
75 | } | ||
76 | |||
77 | #region IUserAccountService | ||
78 | public UserAccount GetUserAccount(UUID scopeID, UUID userID) | ||
79 | { | ||
80 | return GetUser(userID.ToString()); | ||
81 | } | ||
82 | |||
83 | public UserAccount GetUserAccount(UUID scopeID, string FirstName, string LastName) | ||
84 | { | ||
85 | return null; | ||
86 | } | ||
87 | |||
88 | public UserAccount GetUserAccount(UUID scopeID, string Email) | ||
89 | { | ||
90 | return null; | ||
91 | } | ||
92 | |||
93 | public List<UserAccount> GetUserAccountsWhere(UUID scopeID, string query) | ||
94 | { | ||
95 | return null; | ||
96 | } | ||
97 | |||
98 | public List<UserAccount> GetUserAccounts(UUID scopeID, string query) | ||
99 | { | ||
100 | return null; | ||
101 | } | ||
102 | |||
103 | public bool StoreUserAccount(UserAccount data) | ||
104 | { | ||
105 | return false; | ||
106 | } | ||
107 | #endregion | ||
108 | |||
109 | } | ||
110 | |||
111 | } | ||
diff --git a/OpenSim/Services/HypergridService/UserAgentService.cs b/OpenSim/Services/HypergridService/UserAgentService.cs new file mode 100644 index 0000000..398a7b7 --- /dev/null +++ b/OpenSim/Services/HypergridService/UserAgentService.cs | |||
@@ -0,0 +1,545 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Net; | ||
31 | using System.Reflection; | ||
32 | |||
33 | using OpenSim.Framework; | ||
34 | using OpenSim.Services.Connectors.Friends; | ||
35 | using OpenSim.Services.Connectors.Hypergrid; | ||
36 | using OpenSim.Services.Interfaces; | ||
37 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
38 | using OpenSim.Server.Base; | ||
39 | using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; | ||
40 | |||
41 | using OpenMetaverse; | ||
42 | using log4net; | ||
43 | using Nini.Config; | ||
44 | |||
45 | namespace OpenSim.Services.HypergridService | ||
46 | { | ||
47 | /// <summary> | ||
48 | /// This service is for HG1.5 only, to make up for the fact that clients don't | ||
49 | /// keep any private information in themselves, and that their 'home service' | ||
50 | /// needs to do it for them. | ||
51 | /// Once we have better clients, this shouldn't be needed. | ||
52 | /// </summary> | ||
53 | public class UserAgentService : IUserAgentService | ||
54 | { | ||
55 | private static readonly ILog m_log = | ||
56 | LogManager.GetLogger( | ||
57 | MethodBase.GetCurrentMethod().DeclaringType); | ||
58 | |||
59 | // This will need to go into a DB table | ||
60 | static Dictionary<UUID, TravelingAgentInfo> m_TravelingAgents = new Dictionary<UUID, TravelingAgentInfo>(); | ||
61 | |||
62 | static bool m_Initialized = false; | ||
63 | |||
64 | protected static IGridUserService m_GridUserService; | ||
65 | protected static IGridService m_GridService; | ||
66 | protected static GatekeeperServiceConnector m_GatekeeperConnector; | ||
67 | protected static IGatekeeperService m_GatekeeperService; | ||
68 | protected static IFriendsService m_FriendsService; | ||
69 | protected static IPresenceService m_PresenceService; | ||
70 | protected static IUserAccountService m_UserAccountService; | ||
71 | protected static IFriendsSimConnector m_FriendsLocalSimConnector; // standalone, points to HGFriendsModule | ||
72 | protected static FriendsSimConnector m_FriendsSimConnector; // grid | ||
73 | |||
74 | protected static string m_GridName; | ||
75 | |||
76 | protected static bool m_BypassClientVerification; | ||
77 | |||
78 | public UserAgentService(IConfigSource config) : this(config, null) | ||
79 | { | ||
80 | } | ||
81 | |||
82 | public UserAgentService(IConfigSource config, IFriendsSimConnector friendsConnector) | ||
83 | { | ||
84 | // Let's set this always, because we don't know the sequence | ||
85 | // of instantiations | ||
86 | if (friendsConnector != null) | ||
87 | m_FriendsLocalSimConnector = friendsConnector; | ||
88 | |||
89 | if (!m_Initialized) | ||
90 | { | ||
91 | m_Initialized = true; | ||
92 | |||
93 | m_log.DebugFormat("[HOME USERS SECURITY]: Starting..."); | ||
94 | |||
95 | m_FriendsSimConnector = new FriendsSimConnector(); | ||
96 | |||
97 | IConfig serverConfig = config.Configs["UserAgentService"]; | ||
98 | if (serverConfig == null) | ||
99 | throw new Exception(String.Format("No section UserAgentService in config file")); | ||
100 | |||
101 | string gridService = serverConfig.GetString("GridService", String.Empty); | ||
102 | string gridUserService = serverConfig.GetString("GridUserService", String.Empty); | ||
103 | string gatekeeperService = serverConfig.GetString("GatekeeperService", String.Empty); | ||
104 | string friendsService = serverConfig.GetString("FriendsService", String.Empty); | ||
105 | string presenceService = serverConfig.GetString("PresenceService", String.Empty); | ||
106 | string userAccountService = serverConfig.GetString("UserAccountService", String.Empty); | ||
107 | |||
108 | m_BypassClientVerification = serverConfig.GetBoolean("BypassClientVerification", false); | ||
109 | |||
110 | if (gridService == string.Empty || gridUserService == string.Empty || gatekeeperService == string.Empty) | ||
111 | throw new Exception(String.Format("Incomplete specifications, UserAgent Service cannot function.")); | ||
112 | |||
113 | Object[] args = new Object[] { config }; | ||
114 | m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args); | ||
115 | m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args); | ||
116 | m_GatekeeperConnector = new GatekeeperServiceConnector(); | ||
117 | m_GatekeeperService = ServerUtils.LoadPlugin<IGatekeeperService>(gatekeeperService, args); | ||
118 | m_FriendsService = ServerUtils.LoadPlugin<IFriendsService>(friendsService, args); | ||
119 | m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args); | ||
120 | m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(userAccountService, args); | ||
121 | |||
122 | m_GridName = serverConfig.GetString("ExternalName", string.Empty); | ||
123 | if (m_GridName == string.Empty) | ||
124 | { | ||
125 | serverConfig = config.Configs["GatekeeperService"]; | ||
126 | m_GridName = serverConfig.GetString("ExternalName", string.Empty); | ||
127 | } | ||
128 | if (!m_GridName.EndsWith("/")) | ||
129 | m_GridName = m_GridName + "/"; | ||
130 | } | ||
131 | } | ||
132 | |||
133 | public GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt) | ||
134 | { | ||
135 | position = new Vector3(128, 128, 0); lookAt = Vector3.UnitY; | ||
136 | |||
137 | m_log.DebugFormat("[USER AGENT SERVICE]: Request to get home region of user {0}", userID); | ||
138 | |||
139 | GridRegion home = null; | ||
140 | GridUserInfo uinfo = m_GridUserService.GetGridUserInfo(userID.ToString()); | ||
141 | if (uinfo != null) | ||
142 | { | ||
143 | if (uinfo.HomeRegionID != UUID.Zero) | ||
144 | { | ||
145 | home = m_GridService.GetRegionByUUID(UUID.Zero, uinfo.HomeRegionID); | ||
146 | position = uinfo.HomePosition; | ||
147 | lookAt = uinfo.HomeLookAt; | ||
148 | } | ||
149 | if (home == null) | ||
150 | { | ||
151 | List<GridRegion> defs = m_GridService.GetDefaultRegions(UUID.Zero); | ||
152 | if (defs != null && defs.Count > 0) | ||
153 | home = defs[0]; | ||
154 | } | ||
155 | } | ||
156 | |||
157 | return home; | ||
158 | } | ||
159 | |||
160 | public bool LoginAgentToGrid(AgentCircuitData agentCircuit, GridRegion gatekeeper, GridRegion finalDestination, IPEndPoint clientIP, out string reason) | ||
161 | { | ||
162 | m_log.DebugFormat("[USER AGENT SERVICE]: Request to login user {0} {1} (@{2}) to grid {3}", | ||
163 | agentCircuit.firstname, agentCircuit.lastname, ((clientIP == null) ? "stored IP" : clientIP.Address.ToString()), gatekeeper.ServerURI); | ||
164 | // Take the IP address + port of the gatekeeper (reg) plus the info of finalDestination | ||
165 | GridRegion region = new GridRegion(gatekeeper); | ||
166 | region.ServerURI = gatekeeper.ServerURI; | ||
167 | region.ExternalHostName = finalDestination.ExternalHostName; | ||
168 | region.InternalEndPoint = finalDestination.InternalEndPoint; | ||
169 | region.RegionName = finalDestination.RegionName; | ||
170 | region.RegionID = finalDestination.RegionID; | ||
171 | region.RegionLocX = finalDestination.RegionLocX; | ||
172 | region.RegionLocY = finalDestination.RegionLocY; | ||
173 | |||
174 | // Generate a new service session | ||
175 | agentCircuit.ServiceSessionID = region.ServerURI + ";" + UUID.Random(); | ||
176 | TravelingAgentInfo old = UpdateTravelInfo(agentCircuit, region); | ||
177 | |||
178 | bool success = false; | ||
179 | string myExternalIP = string.Empty; | ||
180 | string gridName = gatekeeper.ServerURI; | ||
181 | |||
182 | m_log.DebugFormat("[USER AGENT SERVICE]: this grid: {0}, desired grid: {1}", m_GridName, gridName); | ||
183 | |||
184 | if (m_GridName == gridName) | ||
185 | success = m_GatekeeperService.LoginAgent(agentCircuit, finalDestination, out reason); | ||
186 | else | ||
187 | { | ||
188 | success = m_GatekeeperConnector.CreateAgent(region, agentCircuit, (uint)Constants.TeleportFlags.ViaLogin, out myExternalIP, out reason); | ||
189 | if (success) | ||
190 | // Report them as nowhere | ||
191 | m_PresenceService.ReportAgent(agentCircuit.SessionID, UUID.Zero); | ||
192 | } | ||
193 | |||
194 | if (!success) | ||
195 | { | ||
196 | m_log.DebugFormat("[USER AGENT SERVICE]: Unable to login user {0} {1} to grid {2}, reason: {3}", | ||
197 | agentCircuit.firstname, agentCircuit.lastname, region.ServerURI, reason); | ||
198 | |||
199 | // restore the old travel info | ||
200 | lock (m_TravelingAgents) | ||
201 | { | ||
202 | if (old == null) | ||
203 | m_TravelingAgents.Remove(agentCircuit.SessionID); | ||
204 | else | ||
205 | m_TravelingAgents[agentCircuit.SessionID] = old; | ||
206 | } | ||
207 | |||
208 | return false; | ||
209 | } | ||
210 | |||
211 | m_log.DebugFormat("[USER AGENT SERVICE]: Gatekeeper sees me as {0}", myExternalIP); | ||
212 | // else set the IP addresses associated with this client | ||
213 | if (clientIP != null) | ||
214 | m_TravelingAgents[agentCircuit.SessionID].ClientIPAddress = clientIP.Address.ToString(); | ||
215 | m_TravelingAgents[agentCircuit.SessionID].MyIpAddress = myExternalIP; | ||
216 | |||
217 | return true; | ||
218 | } | ||
219 | |||
220 | public bool LoginAgentToGrid(AgentCircuitData agentCircuit, GridRegion gatekeeper, GridRegion finalDestination, out string reason) | ||
221 | { | ||
222 | reason = string.Empty; | ||
223 | return LoginAgentToGrid(agentCircuit, gatekeeper, finalDestination, null, out reason); | ||
224 | } | ||
225 | |||
226 | private void SetClientIP(UUID sessionID, string ip) | ||
227 | { | ||
228 | if (m_TravelingAgents.ContainsKey(sessionID)) | ||
229 | { | ||
230 | m_log.DebugFormat("[USER AGENT SERVICE]: Setting IP {0} for session {1}", ip, sessionID); | ||
231 | m_TravelingAgents[sessionID].ClientIPAddress = ip; | ||
232 | } | ||
233 | } | ||
234 | |||
235 | TravelingAgentInfo UpdateTravelInfo(AgentCircuitData agentCircuit, GridRegion region) | ||
236 | { | ||
237 | TravelingAgentInfo travel = new TravelingAgentInfo(); | ||
238 | TravelingAgentInfo old = null; | ||
239 | lock (m_TravelingAgents) | ||
240 | { | ||
241 | if (m_TravelingAgents.ContainsKey(agentCircuit.SessionID)) | ||
242 | { | ||
243 | // Very important! Override whatever this agent comes with. | ||
244 | // UserAgentService always sets the IP for every new agent | ||
245 | // with the original IP address. | ||
246 | agentCircuit.IPAddress = m_TravelingAgents[agentCircuit.SessionID].ClientIPAddress; | ||
247 | |||
248 | old = m_TravelingAgents[agentCircuit.SessionID]; | ||
249 | } | ||
250 | |||
251 | m_TravelingAgents[agentCircuit.SessionID] = travel; | ||
252 | } | ||
253 | travel.UserID = agentCircuit.AgentID; | ||
254 | travel.GridExternalName = region.ServerURI; | ||
255 | travel.ServiceToken = agentCircuit.ServiceSessionID; | ||
256 | if (old != null) | ||
257 | travel.ClientIPAddress = old.ClientIPAddress; | ||
258 | |||
259 | return old; | ||
260 | } | ||
261 | |||
262 | public void LogoutAgent(UUID userID, UUID sessionID) | ||
263 | { | ||
264 | m_log.DebugFormat("[USER AGENT SERVICE]: User {0} logged out", userID); | ||
265 | |||
266 | lock (m_TravelingAgents) | ||
267 | { | ||
268 | List<UUID> travels = new List<UUID>(); | ||
269 | foreach (KeyValuePair<UUID, TravelingAgentInfo> kvp in m_TravelingAgents) | ||
270 | if (kvp.Value == null) // do some clean up | ||
271 | travels.Add(kvp.Key); | ||
272 | else if (kvp.Value.UserID == userID) | ||
273 | travels.Add(kvp.Key); | ||
274 | foreach (UUID session in travels) | ||
275 | m_TravelingAgents.Remove(session); | ||
276 | } | ||
277 | |||
278 | GridUserInfo guinfo = m_GridUserService.GetGridUserInfo(userID.ToString()); | ||
279 | if (guinfo != null) | ||
280 | m_GridUserService.LoggedOut(userID.ToString(), sessionID, guinfo.LastRegionID, guinfo.LastPosition, guinfo.LastLookAt); | ||
281 | } | ||
282 | |||
283 | // We need to prevent foreign users with the same UUID as a local user | ||
284 | public bool IsAgentComingHome(UUID sessionID, string thisGridExternalName) | ||
285 | { | ||
286 | if (!m_TravelingAgents.ContainsKey(sessionID)) | ||
287 | return false; | ||
288 | |||
289 | TravelingAgentInfo travel = m_TravelingAgents[sessionID]; | ||
290 | |||
291 | return travel.GridExternalName.ToLower() == thisGridExternalName.ToLower(); | ||
292 | } | ||
293 | |||
294 | public bool VerifyClient(UUID sessionID, string reportedIP) | ||
295 | { | ||
296 | if (m_BypassClientVerification) | ||
297 | return true; | ||
298 | |||
299 | m_log.DebugFormat("[USER AGENT SERVICE]: Verifying Client session {0} with reported IP {1}.", | ||
300 | sessionID, reportedIP); | ||
301 | |||
302 | if (m_TravelingAgents.ContainsKey(sessionID)) | ||
303 | { | ||
304 | m_log.DebugFormat("[USER AGENT SERVICE]: Comparing with login IP {0} and MyIP {1}", | ||
305 | m_TravelingAgents[sessionID].ClientIPAddress, m_TravelingAgents[sessionID].MyIpAddress); | ||
306 | |||
307 | return m_TravelingAgents[sessionID].ClientIPAddress == reportedIP || | ||
308 | m_TravelingAgents[sessionID].MyIpAddress == reportedIP; // NATed | ||
309 | } | ||
310 | |||
311 | return false; | ||
312 | } | ||
313 | |||
314 | public bool VerifyAgent(UUID sessionID, string token) | ||
315 | { | ||
316 | if (m_TravelingAgents.ContainsKey(sessionID)) | ||
317 | { | ||
318 | m_log.DebugFormat("[USER AGENT SERVICE]: Verifying agent token {0} against {1}", token, m_TravelingAgents[sessionID].ServiceToken); | ||
319 | return m_TravelingAgents[sessionID].ServiceToken == token; | ||
320 | } | ||
321 | |||
322 | m_log.DebugFormat("[USER AGENT SERVICE]: Token verification for session {0}: no such session", sessionID); | ||
323 | |||
324 | return false; | ||
325 | } | ||
326 | |||
327 | public List<UUID> StatusNotification(List<string> friends, UUID foreignUserID, bool online) | ||
328 | { | ||
329 | if (m_FriendsService == null || m_PresenceService == null) | ||
330 | { | ||
331 | m_log.WarnFormat("[USER AGENT SERVICE]: Unable to perform status notifications because friends or presence services are missing"); | ||
332 | return new List<UUID>(); | ||
333 | } | ||
334 | |||
335 | List<UUID> localFriendsOnline = new List<UUID>(); | ||
336 | |||
337 | m_log.DebugFormat("[USER AGENT SERVICE]: Status notification: foreign user {0} wants to notify {1} local friends", foreignUserID, friends.Count); | ||
338 | |||
339 | // First, let's double check that the reported friends are, indeed, friends of that user | ||
340 | // And let's check that the secret matches | ||
341 | List<string> usersToBeNotified = new List<string>(); | ||
342 | foreach (string uui in friends) | ||
343 | { | ||
344 | UUID localUserID; | ||
345 | string secret = string.Empty, tmp = string.Empty; | ||
346 | if (Util.ParseUniversalUserIdentifier(uui, out localUserID, out tmp, out tmp, out tmp, out secret)) | ||
347 | { | ||
348 | FriendInfo[] friendInfos = m_FriendsService.GetFriends(localUserID); | ||
349 | foreach (FriendInfo finfo in friendInfos) | ||
350 | { | ||
351 | if (finfo.Friend.StartsWith(foreignUserID.ToString()) && finfo.Friend.EndsWith(secret)) | ||
352 | { | ||
353 | // great! | ||
354 | usersToBeNotified.Add(localUserID.ToString()); | ||
355 | } | ||
356 | } | ||
357 | } | ||
358 | } | ||
359 | |||
360 | // Now, let's send the notifications | ||
361 | m_log.DebugFormat("[USER AGENT SERVICE]: Status notification: user has {0} local friends", usersToBeNotified.Count); | ||
362 | |||
363 | // First, let's send notifications to local users who are online in the home grid | ||
364 | PresenceInfo[] friendSessions = m_PresenceService.GetAgents(usersToBeNotified.ToArray()); | ||
365 | if (friendSessions != null && friendSessions.Length > 0) | ||
366 | { | ||
367 | PresenceInfo friendSession = null; | ||
368 | foreach (PresenceInfo pinfo in friendSessions) | ||
369 | if (pinfo.RegionID != UUID.Zero) // let's guard against traveling agents | ||
370 | { | ||
371 | friendSession = pinfo; | ||
372 | break; | ||
373 | } | ||
374 | |||
375 | if (friendSession != null) | ||
376 | { | ||
377 | ForwardStatusNotificationToSim(friendSession.RegionID, foreignUserID, friendSession.UserID, online); | ||
378 | usersToBeNotified.Remove(friendSession.UserID.ToString()); | ||
379 | UUID id; | ||
380 | if (UUID.TryParse(friendSession.UserID, out id)) | ||
381 | localFriendsOnline.Add(id); | ||
382 | |||
383 | } | ||
384 | } | ||
385 | |||
386 | // Lastly, let's notify the rest who may be online somewhere else | ||
387 | foreach (string user in usersToBeNotified) | ||
388 | { | ||
389 | UUID id = new UUID(user); | ||
390 | if (m_TravelingAgents.ContainsKey(id) && m_TravelingAgents[id].GridExternalName != m_GridName) | ||
391 | { | ||
392 | string url = m_TravelingAgents[id].GridExternalName; | ||
393 | // forward | ||
394 | m_log.WarnFormat("[USER AGENT SERVICE]: User {0} is visiting {1}. HG Status notifications still not implemented.", user, url); | ||
395 | } | ||
396 | } | ||
397 | |||
398 | // and finally, let's send the online friends | ||
399 | if (online) | ||
400 | { | ||
401 | return localFriendsOnline; | ||
402 | } | ||
403 | else | ||
404 | return new List<UUID>(); | ||
405 | } | ||
406 | |||
407 | protected void ForwardStatusNotificationToSim(UUID regionID, UUID foreignUserID, string user, bool online) | ||
408 | { | ||
409 | UUID userID; | ||
410 | if (UUID.TryParse(user, out userID)) | ||
411 | { | ||
412 | if (m_FriendsLocalSimConnector != null) | ||
413 | { | ||
414 | m_log.DebugFormat("[USER AGENT SERVICE]: Local Notify, user {0} is {1}", foreignUserID, (online ? "online" : "offline")); | ||
415 | m_FriendsLocalSimConnector.StatusNotify(foreignUserID, userID, online); | ||
416 | } | ||
417 | else | ||
418 | { | ||
419 | GridRegion region = m_GridService.GetRegionByUUID(UUID.Zero /* !!! */, regionID); | ||
420 | if (region != null) | ||
421 | { | ||
422 | m_log.DebugFormat("[USER AGENT SERVICE]: Remote Notify to region {0}, user {1} is {2}", region.RegionName, foreignUserID, (online ? "online" : "offline")); | ||
423 | m_FriendsSimConnector.StatusNotify(region, foreignUserID, userID, online); | ||
424 | } | ||
425 | } | ||
426 | } | ||
427 | } | ||
428 | |||
429 | public List<UUID> GetOnlineFriends(UUID foreignUserID, List<string> friends) | ||
430 | { | ||
431 | List<UUID> online = new List<UUID>(); | ||
432 | |||
433 | if (m_FriendsService == null || m_PresenceService == null) | ||
434 | { | ||
435 | m_log.WarnFormat("[USER AGENT SERVICE]: Unable to get online friends because friends or presence services are missing"); | ||
436 | return online; | ||
437 | } | ||
438 | |||
439 | m_log.DebugFormat("[USER AGENT SERVICE]: Foreign user {0} wants to know status of {1} local friends", foreignUserID, friends.Count); | ||
440 | |||
441 | // First, let's double check that the reported friends are, indeed, friends of that user | ||
442 | // And let's check that the secret matches and the rights | ||
443 | List<string> usersToBeNotified = new List<string>(); | ||
444 | foreach (string uui in friends) | ||
445 | { | ||
446 | UUID localUserID; | ||
447 | string secret = string.Empty, tmp = string.Empty; | ||
448 | if (Util.ParseUniversalUserIdentifier(uui, out localUserID, out tmp, out tmp, out tmp, out secret)) | ||
449 | { | ||
450 | FriendInfo[] friendInfos = m_FriendsService.GetFriends(localUserID); | ||
451 | foreach (FriendInfo finfo in friendInfos) | ||
452 | { | ||
453 | if (finfo.Friend.StartsWith(foreignUserID.ToString()) && finfo.Friend.EndsWith(secret) && | ||
454 | (finfo.TheirFlags & (int)FriendRights.CanSeeOnline) != 0 && (finfo.TheirFlags != -1)) | ||
455 | { | ||
456 | // great! | ||
457 | usersToBeNotified.Add(localUserID.ToString()); | ||
458 | } | ||
459 | } | ||
460 | } | ||
461 | } | ||
462 | |||
463 | // Now, let's find out their status | ||
464 | m_log.DebugFormat("[USER AGENT SERVICE]: GetOnlineFriends: user has {0} local friends with status rights", usersToBeNotified.Count); | ||
465 | |||
466 | // First, let's send notifications to local users who are online in the home grid | ||
467 | PresenceInfo[] friendSessions = m_PresenceService.GetAgents(usersToBeNotified.ToArray()); | ||
468 | if (friendSessions != null && friendSessions.Length > 0) | ||
469 | { | ||
470 | foreach (PresenceInfo pi in friendSessions) | ||
471 | { | ||
472 | UUID presenceID; | ||
473 | if (UUID.TryParse(pi.UserID, out presenceID)) | ||
474 | online.Add(presenceID); | ||
475 | } | ||
476 | } | ||
477 | |||
478 | return online; | ||
479 | } | ||
480 | |||
481 | public Dictionary<string, object> GetServerURLs(UUID userID) | ||
482 | { | ||
483 | if (m_UserAccountService == null) | ||
484 | { | ||
485 | m_log.WarnFormat("[USER AGENT SERVICE]: Unable to get server URLs because user account service is missing"); | ||
486 | return new Dictionary<string, object>(); | ||
487 | } | ||
488 | UserAccount account = m_UserAccountService.GetUserAccount(UUID.Zero /*!!!*/, userID); | ||
489 | if (account != null) | ||
490 | return account.ServiceURLs; | ||
491 | |||
492 | return new Dictionary<string, object>(); | ||
493 | } | ||
494 | |||
495 | public string LocateUser(UUID userID) | ||
496 | { | ||
497 | foreach (TravelingAgentInfo t in m_TravelingAgents.Values) | ||
498 | { | ||
499 | if (t == null) | ||
500 | { | ||
501 | m_log.ErrorFormat("[USER AGENT SERVICE]: Oops! Null TravelingAgentInfo. Please report this on mantis"); | ||
502 | continue; | ||
503 | } | ||
504 | if (t.UserID == userID && !m_GridName.Equals(t.GridExternalName)) | ||
505 | return t.GridExternalName; | ||
506 | } | ||
507 | |||
508 | return string.Empty; | ||
509 | } | ||
510 | |||
511 | public string GetUUI(UUID userID, UUID targetUserID) | ||
512 | { | ||
513 | // Let's see if it's a local user | ||
514 | UserAccount account = m_UserAccountService.GetUserAccount(UUID.Zero, targetUserID); | ||
515 | if (account != null) | ||
516 | return targetUserID.ToString() + ";" + m_GridName + ";" + account.FirstName + " " + account.LastName ; | ||
517 | |||
518 | // Let's try the list of friends | ||
519 | FriendInfo[] friends = m_FriendsService.GetFriends(userID); | ||
520 | if (friends != null && friends.Length > 0) | ||
521 | { | ||
522 | foreach (FriendInfo f in friends) | ||
523 | if (f.Friend.StartsWith(targetUserID.ToString())) | ||
524 | { | ||
525 | // Let's remove the secret | ||
526 | UUID id; string tmp = string.Empty, secret = string.Empty; | ||
527 | if (Util.ParseUniversalUserIdentifier(f.Friend, out id, out tmp, out tmp, out tmp, out secret)) | ||
528 | return f.Friend.Replace(secret, "0"); | ||
529 | } | ||
530 | } | ||
531 | |||
532 | return string.Empty; | ||
533 | } | ||
534 | } | ||
535 | |||
536 | class TravelingAgentInfo | ||
537 | { | ||
538 | public UUID UserID; | ||
539 | public string GridExternalName = string.Empty; | ||
540 | public string ServiceToken = string.Empty; | ||
541 | public string ClientIPAddress = string.Empty; // as seen from this user agent service | ||
542 | public string MyIpAddress = string.Empty; // the user agent service's external IP, as seen from the next gatekeeper | ||
543 | } | ||
544 | |||
545 | } | ||
diff --git a/OpenSim/Services/Interfaces/IAssetService.cs b/OpenSim/Services/Interfaces/IAssetService.cs index 3be6815..80494f1 100644 --- a/OpenSim/Services/Interfaces/IAssetService.cs +++ b/OpenSim/Services/Interfaces/IAssetService.cs | |||
@@ -48,10 +48,15 @@ namespace OpenSim.Services.Interfaces | |||
48 | /// <returns></returns> | 48 | /// <returns></returns> |
49 | AssetMetadata GetMetadata(string id); | 49 | AssetMetadata GetMetadata(string id); |
50 | 50 | ||
51 | /// <summary> | ||
52 | /// Get an asset's data, ignoring the metadata. | ||
53 | /// </summary> | ||
54 | /// <param name="id"></param> | ||
55 | /// <returns>null if there is no such asset</returns> | ||
51 | byte[] GetData(string id); | 56 | byte[] GetData(string id); |
52 | 57 | ||
53 | /// <summary> | 58 | /// <summary> |
54 | /// Synchronously fetches an asset from the local cache only | 59 | /// Synchronously fetches an asset from the local cache only. |
55 | /// </summary> | 60 | /// </summary> |
56 | /// <param name="id">Asset ID</param> | 61 | /// <param name="id">Asset ID</param> |
57 | /// <returns>The fetched asset, or null if it did not exist in the local cache</returns> | 62 | /// <returns>The fetched asset, or null if it did not exist in the local cache</returns> |
@@ -70,7 +75,9 @@ namespace OpenSim.Services.Interfaces | |||
70 | /// <summary> | 75 | /// <summary> |
71 | /// Creates a new asset | 76 | /// Creates a new asset |
72 | /// </summary> | 77 | /// </summary> |
73 | /// Returns a random ID if none is passed into it | 78 | /// <remarks> |
79 | /// Returns a random ID if none is passed via the asset argument. | ||
80 | /// </remarks> | ||
74 | /// <param name="asset"></param> | 81 | /// <param name="asset"></param> |
75 | /// <returns></returns> | 82 | /// <returns></returns> |
76 | string Store(AssetBase asset); | 83 | string Store(AssetBase asset); |
@@ -78,7 +85,9 @@ namespace OpenSim.Services.Interfaces | |||
78 | /// <summary> | 85 | /// <summary> |
79 | /// Update an asset's content | 86 | /// Update an asset's content |
80 | /// </summary> | 87 | /// </summary> |
88 | /// <remarks> | ||
81 | /// Attachments and bare scripts need this!! | 89 | /// Attachments and bare scripts need this!! |
90 | /// </remarks> | ||
82 | /// <param name="id"> </param> | 91 | /// <param name="id"> </param> |
83 | /// <param name="data"></param> | 92 | /// <param name="data"></param> |
84 | /// <returns></returns> | 93 | /// <returns></returns> |
diff --git a/OpenSim/Services/Interfaces/IAttachmentsService.cs b/OpenSim/Services/Interfaces/IAttachmentsService.cs new file mode 100644 index 0000000..bdde369 --- /dev/null +++ b/OpenSim/Services/Interfaces/IAttachmentsService.cs | |||
@@ -0,0 +1,17 @@ | |||
1 | //////////////////////////////////////////////////////////////// | ||
2 | // | ||
3 | // (c) 2009, 2010 Careminster Limited and Melanie Thielker | ||
4 | // | ||
5 | // All rights reserved | ||
6 | // | ||
7 | using System; | ||
8 | using Nini.Config; | ||
9 | |||
10 | namespace OpenSim.Services.Interfaces | ||
11 | { | ||
12 | public interface IAttachmentsService | ||
13 | { | ||
14 | string Get(string id); | ||
15 | void Store(string id, string data); | ||
16 | } | ||
17 | } | ||
diff --git a/OpenSim/Services/Interfaces/IAuthenticationService.cs b/OpenSim/Services/Interfaces/IAuthenticationService.cs index 9225773..cee8bc0 100644 --- a/OpenSim/Services/Interfaces/IAuthenticationService.cs +++ b/OpenSim/Services/Interfaces/IAuthenticationService.cs | |||
@@ -26,10 +26,32 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Collections.Generic; | ||
29 | using OpenMetaverse; | 30 | using OpenMetaverse; |
30 | 31 | ||
31 | namespace OpenSim.Services.Interfaces | 32 | namespace OpenSim.Services.Interfaces |
32 | { | 33 | { |
34 | public class AuthInfo | ||
35 | { | ||
36 | public UUID PrincipalID { get; set; } | ||
37 | public string AccountType { get; set; } | ||
38 | public string PasswordHash { get; set; } | ||
39 | public string PasswordSalt { get; set; } | ||
40 | public string WebLoginKey { get; set; } | ||
41 | |||
42 | public Dictionary<string, object> ToKeyValuePairs() | ||
43 | { | ||
44 | Dictionary<string, object> result = new Dictionary<string, object>(); | ||
45 | result["PrincipalID"] = PrincipalID; | ||
46 | result["AccountType"] = AccountType; | ||
47 | result["PasswordHash"] = PasswordHash; | ||
48 | result["PasswordSalt"] = PasswordSalt; | ||
49 | result["WebLoginKey"] = WebLoginKey; | ||
50 | |||
51 | return result; | ||
52 | } | ||
53 | } | ||
54 | |||
33 | // Generic Authentication service used for identifying | 55 | // Generic Authentication service used for identifying |
34 | // and authenticating principals. | 56 | // and authenticating principals. |
35 | // Principals may be clients acting on users' behalf, | 57 | // Principals may be clients acting on users' behalf, |
@@ -66,6 +88,21 @@ namespace OpenSim.Services.Interfaces | |||
66 | bool Release(UUID principalID, string token); | 88 | bool Release(UUID principalID, string token); |
67 | 89 | ||
68 | ////////////////////////////////////////////////////// | 90 | ////////////////////////////////////////////////////// |
91 | // SetPassword for a principal | ||
92 | // | ||
93 | // This method exists for the service, but may or may not | ||
94 | // be served remotely. That is, the authentication | ||
95 | // handlers may not include one handler for this, | ||
96 | // because it's a bit risky. Such handlers require | ||
97 | // authentication/authorization. | ||
98 | // | ||
99 | bool SetPassword(UUID principalID, string passwd); | ||
100 | |||
101 | AuthInfo GetAuthInfo(UUID principalID); | ||
102 | |||
103 | bool SetAuthInfo(AuthInfo info); | ||
104 | |||
105 | ////////////////////////////////////////////////////// | ||
69 | // Grid | 106 | // Grid |
70 | // | 107 | // |
71 | // We no longer need a shared secret between grid | 108 | // We no longer need a shared secret between grid |
diff --git a/OpenSim/Services/Interfaces/IAuthorizationService.cs b/OpenSim/Services/Interfaces/IAuthorizationService.cs index c5d577a..e5c68f6 100644 --- a/OpenSim/Services/Interfaces/IAuthorizationService.cs +++ b/OpenSim/Services/Interfaces/IAuthorizationService.cs | |||
@@ -34,14 +34,21 @@ namespace OpenSim.Services.Interfaces | |||
34 | 34 | ||
35 | public interface IAuthorizationService | 35 | public interface IAuthorizationService |
36 | { | 36 | { |
37 | ////////////////////////////////////////////////////// | 37 | /// <summary> |
38 | // Authorized | 38 | /// Check whether the user should be given access to the region. |
39 | // | 39 | /// </summary> |
40 | // This method returns a simple true false indicating | 40 | /// <remarks> |
41 | // whether or not a user has access to the region | 41 | /// We also supply user first name and last name for situations where the user does not have an account |
42 | // | 42 | /// on the region (e.g. they're a visitor via Hypergrid). |
43 | bool IsAuthorizedForRegion(string userID, string regionID, out string message); | 43 | /// </remarks> |
44 | 44 | /// <param name="userID"></param> | |
45 | /// <param name="firstName">/param> | ||
46 | /// <param name="lastName"></param> | ||
47 | /// <param name="regionID"></param> | ||
48 | /// <param name="message"></param> | ||
49 | /// <returns></returns> | ||
50 | bool IsAuthorizedForRegion( | ||
51 | string userID, string firstName, string lastName, string regionID, out string message); | ||
45 | } | 52 | } |
46 | 53 | ||
47 | public class AuthorizationRequest | 54 | public class AuthorizationRequest |
@@ -63,7 +70,8 @@ namespace OpenSim.Services.Interfaces | |||
63 | m_regionID = RegionID; | 70 | m_regionID = RegionID; |
64 | } | 71 | } |
65 | 72 | ||
66 | public AuthorizationRequest(string ID,string FirstName, string SurName, string Email, string RegionName, string RegionID) | 73 | public AuthorizationRequest( |
74 | string ID, string FirstName, string SurName, string Email, string RegionName, string RegionID) | ||
67 | { | 75 | { |
68 | m_userID = ID; | 76 | m_userID = ID; |
69 | m_firstname = FirstName; | 77 | m_firstname = FirstName; |
@@ -108,9 +116,6 @@ namespace OpenSim.Services.Interfaces | |||
108 | get { return m_regionID; } | 116 | get { return m_regionID; } |
109 | set { m_regionID = value; } | 117 | set { m_regionID = value; } |
110 | } | 118 | } |
111 | |||
112 | |||
113 | |||
114 | } | 119 | } |
115 | 120 | ||
116 | public class AuthorizationResponse | 121 | public class AuthorizationResponse |
@@ -126,7 +131,6 @@ namespace OpenSim.Services.Interfaces | |||
126 | { | 131 | { |
127 | m_isAuthorized = isAuthorized; | 132 | m_isAuthorized = isAuthorized; |
128 | m_message = message; | 133 | m_message = message; |
129 | |||
130 | } | 134 | } |
131 | 135 | ||
132 | public bool IsAuthorized | 136 | public bool IsAuthorized |
@@ -141,4 +145,4 @@ namespace OpenSim.Services.Interfaces | |||
141 | set { m_message = value; } | 145 | set { m_message = value; } |
142 | } | 146 | } |
143 | } | 147 | } |
144 | } | 148 | } \ No newline at end of file |
diff --git a/OpenSim/Services/Interfaces/IAvatarService.cs b/OpenSim/Services/Interfaces/IAvatarService.cs new file mode 100644 index 0000000..cda7113 --- /dev/null +++ b/OpenSim/Services/Interfaces/IAvatarService.cs | |||
@@ -0,0 +1,342 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | |||
32 | using OpenSim.Framework; | ||
33 | |||
34 | using OpenMetaverse; | ||
35 | |||
36 | namespace OpenSim.Services.Interfaces | ||
37 | { | ||
38 | public interface IAvatarService | ||
39 | { | ||
40 | /// <summary> | ||
41 | /// Called by the login service | ||
42 | /// </summary> | ||
43 | /// <param name="userID"></param> | ||
44 | /// <returns></returns> | ||
45 | AvatarAppearance GetAppearance(UUID userID); | ||
46 | |||
47 | /// <summary> | ||
48 | /// Called by everyone who can change the avatar data (so, regions) | ||
49 | /// </summary> | ||
50 | /// <param name="userID"></param> | ||
51 | /// <param name="appearance"></param> | ||
52 | /// <returns></returns> | ||
53 | bool SetAppearance(UUID userID, AvatarAppearance appearance); | ||
54 | |||
55 | /// <summary> | ||
56 | /// Called by the login service | ||
57 | /// </summary> | ||
58 | /// <param name="userID"></param> | ||
59 | /// <returns></returns> | ||
60 | AvatarData GetAvatar(UUID userID); | ||
61 | |||
62 | /// <summary> | ||
63 | /// Called by everyone who can change the avatar data (so, regions) | ||
64 | /// </summary> | ||
65 | /// <param name="userID"></param> | ||
66 | /// <param name="avatar"></param> | ||
67 | /// <returns></returns> | ||
68 | bool SetAvatar(UUID userID, AvatarData avatar); | ||
69 | |||
70 | /// <summary> | ||
71 | /// Not sure if it's needed | ||
72 | /// </summary> | ||
73 | /// <param name="userID"></param> | ||
74 | /// <returns></returns> | ||
75 | bool ResetAvatar(UUID userID); | ||
76 | |||
77 | /// <summary> | ||
78 | /// These methods raison d'etre: | ||
79 | /// No need to send the entire avatar data (SetAvatar) for changing attachments | ||
80 | /// </summary> | ||
81 | /// <param name="userID"></param> | ||
82 | /// <param name="attach"></param> | ||
83 | /// <returns></returns> | ||
84 | bool SetItems(UUID userID, string[] names, string[] values); | ||
85 | bool RemoveItems(UUID userID, string[] names); | ||
86 | } | ||
87 | |||
88 | /// <summary> | ||
89 | /// Each region/client that uses avatars will have a data structure | ||
90 | /// of this type representing the avatars. | ||
91 | /// </summary> | ||
92 | public class AvatarData | ||
93 | { | ||
94 | // This pretty much determines which name/value pairs will be | ||
95 | // present below. The name/value pair describe a part of | ||
96 | // the avatar. For SL avatars, these would be "shape", "texture1", | ||
97 | // etc. For other avatars, they might be "mesh", "skin", etc. | ||
98 | // The value portion is a URL that is expected to resolve to an | ||
99 | // asset of the type required by the handler for that field. | ||
100 | // It is required that regions can access these URLs. Allowing | ||
101 | // direct access by a viewer is not required, and, if provided, | ||
102 | // may be read-only. A "naked" UUID can be used to refer to an | ||
103 | // asset int he current region's asset service, which is not | ||
104 | // portable, but allows legacy appearance to continue to | ||
105 | // function. Closed, LL-based grids will never need URLs here. | ||
106 | |||
107 | public int AvatarType; | ||
108 | public Dictionary<string,string> Data; | ||
109 | |||
110 | public AvatarData() | ||
111 | { | ||
112 | } | ||
113 | |||
114 | public AvatarData(Dictionary<string, object> kvp) | ||
115 | { | ||
116 | Data = new Dictionary<string, string>(); | ||
117 | |||
118 | if (kvp.ContainsKey("AvatarType")) | ||
119 | Int32.TryParse(kvp["AvatarType"].ToString(), out AvatarType); | ||
120 | |||
121 | foreach (KeyValuePair<string, object> _kvp in kvp) | ||
122 | { | ||
123 | if (_kvp.Value != null) | ||
124 | Data[_kvp.Key] = _kvp.Value.ToString(); | ||
125 | } | ||
126 | } | ||
127 | |||
128 | /// <summary> | ||
129 | /// </summary> | ||
130 | /// <returns></returns> | ||
131 | public Dictionary<string, object> ToKeyValuePairs() | ||
132 | { | ||
133 | Dictionary<string, object> result = new Dictionary<string, object>(); | ||
134 | |||
135 | result["AvatarType"] = AvatarType.ToString(); | ||
136 | foreach (KeyValuePair<string, string> _kvp in Data) | ||
137 | { | ||
138 | if (_kvp.Value != null) | ||
139 | result[_kvp.Key] = _kvp.Value; | ||
140 | } | ||
141 | return result; | ||
142 | } | ||
143 | |||
144 | public AvatarData(AvatarAppearance appearance) | ||
145 | { | ||
146 | AvatarType = 1; // SL avatars | ||
147 | Data = new Dictionary<string, string>(); | ||
148 | |||
149 | Data["Serial"] = appearance.Serial.ToString(); | ||
150 | // Wearables | ||
151 | Data["AvatarHeight"] = appearance.AvatarHeight.ToString(); | ||
152 | |||
153 | for (int i = 0 ; i < AvatarWearable.MAX_WEARABLES ; i++) | ||
154 | { | ||
155 | for (int j = 0 ; j < appearance.Wearables[i].Count ; j++) | ||
156 | { | ||
157 | string fieldName = String.Format("Wearable {0}:{1}", i, j); | ||
158 | Data[fieldName] = String.Format("{0}:{1}", | ||
159 | appearance.Wearables[i][j].ItemID.ToString(), | ||
160 | appearance.Wearables[i][j].AssetID.ToString()); | ||
161 | } | ||
162 | } | ||
163 | |||
164 | // Visual Params | ||
165 | string[] vps = new string[AvatarAppearance.VISUALPARAM_COUNT]; | ||
166 | byte[] binary = appearance.VisualParams; | ||
167 | |||
168 | for (int i = 0 ; i < AvatarAppearance.VISUALPARAM_COUNT ; i++) | ||
169 | { | ||
170 | vps[i] = binary[i].ToString(); | ||
171 | } | ||
172 | |||
173 | Data["VisualParams"] = String.Join(",", vps); | ||
174 | |||
175 | // Attachments | ||
176 | List<AvatarAttachment> attachments = appearance.GetAttachments(); | ||
177 | foreach (AvatarAttachment attach in attachments) | ||
178 | { | ||
179 | Data["_ap_" + attach.AttachPoint] = attach.ItemID.ToString(); | ||
180 | } | ||
181 | } | ||
182 | |||
183 | public AvatarAppearance ToAvatarAppearance() | ||
184 | { | ||
185 | AvatarAppearance appearance = new AvatarAppearance(); | ||
186 | |||
187 | if (Data.Count == 0) | ||
188 | return appearance; | ||
189 | |||
190 | appearance.ClearWearables(); | ||
191 | try | ||
192 | { | ||
193 | if (Data.ContainsKey("Serial")) | ||
194 | appearance.Serial = Int32.Parse(Data["Serial"]); | ||
195 | |||
196 | if (Data.ContainsKey("AvatarHeight")) | ||
197 | appearance.AvatarHeight = float.Parse(Data["AvatarHeight"]); | ||
198 | |||
199 | // Legacy Wearables | ||
200 | if (Data.ContainsKey("BodyItem")) | ||
201 | appearance.Wearables[AvatarWearable.BODY].Wear( | ||
202 | UUID.Parse(Data["BodyItem"]), | ||
203 | UUID.Parse(Data["BodyAsset"])); | ||
204 | |||
205 | if (Data.ContainsKey("SkinItem")) | ||
206 | appearance.Wearables[AvatarWearable.SKIN].Wear( | ||
207 | UUID.Parse(Data["SkinItem"]), | ||
208 | UUID.Parse(Data["SkinAsset"])); | ||
209 | |||
210 | if (Data.ContainsKey("HairItem")) | ||
211 | appearance.Wearables[AvatarWearable.HAIR].Wear( | ||
212 | UUID.Parse(Data["HairItem"]), | ||
213 | UUID.Parse(Data["HairAsset"])); | ||
214 | |||
215 | if (Data.ContainsKey("EyesItem")) | ||
216 | appearance.Wearables[AvatarWearable.EYES].Wear( | ||
217 | UUID.Parse(Data["EyesItem"]), | ||
218 | UUID.Parse(Data["EyesAsset"])); | ||
219 | |||
220 | if (Data.ContainsKey("ShirtItem")) | ||
221 | appearance.Wearables[AvatarWearable.SHIRT].Wear( | ||
222 | UUID.Parse(Data["ShirtItem"]), | ||
223 | UUID.Parse(Data["ShirtAsset"])); | ||
224 | |||
225 | if (Data.ContainsKey("PantsItem")) | ||
226 | appearance.Wearables[AvatarWearable.PANTS].Wear( | ||
227 | UUID.Parse(Data["PantsItem"]), | ||
228 | UUID.Parse(Data["PantsAsset"])); | ||
229 | |||
230 | if (Data.ContainsKey("ShoesItem")) | ||
231 | appearance.Wearables[AvatarWearable.SHOES].Wear( | ||
232 | UUID.Parse(Data["ShoesItem"]), | ||
233 | UUID.Parse(Data["ShoesAsset"])); | ||
234 | |||
235 | if (Data.ContainsKey("SocksItem")) | ||
236 | appearance.Wearables[AvatarWearable.SOCKS].Wear( | ||
237 | UUID.Parse(Data["SocksItem"]), | ||
238 | UUID.Parse(Data["SocksAsset"])); | ||
239 | |||
240 | if (Data.ContainsKey("JacketItem")) | ||
241 | appearance.Wearables[AvatarWearable.JACKET].Wear( | ||
242 | UUID.Parse(Data["JacketItem"]), | ||
243 | UUID.Parse(Data["JacketAsset"])); | ||
244 | |||
245 | if (Data.ContainsKey("GlovesItem")) | ||
246 | appearance.Wearables[AvatarWearable.GLOVES].Wear( | ||
247 | UUID.Parse(Data["GlovesItem"]), | ||
248 | UUID.Parse(Data["GlovesAsset"])); | ||
249 | |||
250 | if (Data.ContainsKey("UnderShirtItem")) | ||
251 | appearance.Wearables[AvatarWearable.UNDERSHIRT].Wear( | ||
252 | UUID.Parse(Data["UnderShirtItem"]), | ||
253 | UUID.Parse(Data["UnderShirtAsset"])); | ||
254 | |||
255 | if (Data.ContainsKey("UnderPantsItem")) | ||
256 | appearance.Wearables[AvatarWearable.UNDERPANTS].Wear( | ||
257 | UUID.Parse(Data["UnderPantsItem"]), | ||
258 | UUID.Parse(Data["UnderPantsAsset"])); | ||
259 | |||
260 | if (Data.ContainsKey("SkirtItem")) | ||
261 | appearance.Wearables[AvatarWearable.SKIRT].Wear( | ||
262 | UUID.Parse(Data["SkirtItem"]), | ||
263 | UUID.Parse(Data["SkirtAsset"])); | ||
264 | |||
265 | if (Data.ContainsKey("VisualParams")) | ||
266 | { | ||
267 | string[] vps = Data["VisualParams"].Split(new char[] {','}); | ||
268 | byte[] binary = new byte[AvatarAppearance.VISUALPARAM_COUNT]; | ||
269 | |||
270 | for (int i = 0 ; i < vps.Length && i < binary.Length ; i++) | ||
271 | binary[i] = (byte)Convert.ToInt32(vps[i]); | ||
272 | |||
273 | appearance.VisualParams = binary; | ||
274 | } | ||
275 | |||
276 | // New style wearables | ||
277 | foreach (KeyValuePair<string, string> _kvp in Data) | ||
278 | { | ||
279 | if (_kvp.Key.StartsWith("Wearable ")) | ||
280 | { | ||
281 | string wearIndex = _kvp.Key.Substring(9); | ||
282 | string[] wearIndices = wearIndex.Split(new char[] {':'}); | ||
283 | int index = Convert.ToInt32(wearIndices[0]); | ||
284 | |||
285 | string[] ids = _kvp.Value.Split(new char[] {':'}); | ||
286 | UUID itemID = new UUID(ids[0]); | ||
287 | UUID assetID = new UUID(ids[1]); | ||
288 | |||
289 | appearance.Wearables[index].Add(itemID, assetID); | ||
290 | } | ||
291 | } | ||
292 | |||
293 | // Attachments | ||
294 | Dictionary<string, string> attchs = new Dictionary<string, string>(); | ||
295 | foreach (KeyValuePair<string, string> _kvp in Data) | ||
296 | if (_kvp.Key.StartsWith("_ap_")) | ||
297 | attchs[_kvp.Key] = _kvp.Value; | ||
298 | |||
299 | foreach (KeyValuePair<string, string> _kvp in attchs) | ||
300 | { | ||
301 | string pointStr = _kvp.Key.Substring(4); | ||
302 | int point = 0; | ||
303 | if (!Int32.TryParse(pointStr, out point)) | ||
304 | continue; | ||
305 | |||
306 | UUID uuid = UUID.Zero; | ||
307 | UUID.TryParse(_kvp.Value, out uuid); | ||
308 | |||
309 | appearance.SetAttachment(point, uuid, UUID.Zero); | ||
310 | } | ||
311 | |||
312 | if (appearance.Wearables[AvatarWearable.BODY].Count == 0) | ||
313 | appearance.Wearables[AvatarWearable.BODY].Wear( | ||
314 | AvatarWearable.DefaultWearables[ | ||
315 | AvatarWearable.BODY][0]); | ||
316 | |||
317 | if (appearance.Wearables[AvatarWearable.SKIN].Count == 0) | ||
318 | appearance.Wearables[AvatarWearable.SKIN].Wear( | ||
319 | AvatarWearable.DefaultWearables[ | ||
320 | AvatarWearable.SKIN][0]); | ||
321 | |||
322 | if (appearance.Wearables[AvatarWearable.HAIR].Count == 0) | ||
323 | appearance.Wearables[AvatarWearable.HAIR].Wear( | ||
324 | AvatarWearable.DefaultWearables[ | ||
325 | AvatarWearable.HAIR][0]); | ||
326 | |||
327 | if (appearance.Wearables[AvatarWearable.EYES].Count == 0) | ||
328 | appearance.Wearables[AvatarWearable.EYES].Wear( | ||
329 | AvatarWearable.DefaultWearables[ | ||
330 | AvatarWearable.EYES][0]); | ||
331 | } | ||
332 | catch | ||
333 | { | ||
334 | // We really should report something here, returning null | ||
335 | // will at least break the wrapper | ||
336 | return null; | ||
337 | } | ||
338 | |||
339 | return appearance; | ||
340 | } | ||
341 | } | ||
342 | } | ||
diff --git a/OpenSim/Services/Interfaces/IFreeswitchService.cs b/OpenSim/Services/Interfaces/IFreeswitchService.cs index d1f635b..e7941d5 100644 --- a/OpenSim/Services/Interfaces/IFreeswitchService.cs +++ b/OpenSim/Services/Interfaces/IFreeswitchService.cs | |||
@@ -27,11 +27,14 @@ | |||
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using OpenSim.Framework; | 29 | using OpenSim.Framework; |
30 | using System.Collections; | ||
30 | 31 | ||
31 | namespace OpenSim.Services.Interfaces | 32 | namespace OpenSim.Services.Interfaces |
32 | { | 33 | { |
33 | public interface IFreeswitchService | 34 | public interface IFreeswitchService |
34 | { | 35 | { |
35 | // Place anything the connector eeds to access here! | 36 | Hashtable HandleDirectoryRequest(Hashtable requestBody); |
37 | Hashtable HandleDialplanRequest(Hashtable requestBody); | ||
38 | string GetJsonConfig(); | ||
36 | } | 39 | } |
37 | } | 40 | } |
diff --git a/OpenSim/Services/Interfaces/IFriendsService.cs b/OpenSim/Services/Interfaces/IFriendsService.cs new file mode 100644 index 0000000..1664f3b --- /dev/null +++ b/OpenSim/Services/Interfaces/IFriendsService.cs | |||
@@ -0,0 +1,82 @@ | |||
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 | |||
28 | using System; | ||
29 | using OpenMetaverse; | ||
30 | using OpenSim.Framework; | ||
31 | using System.Collections.Generic; | ||
32 | |||
33 | namespace OpenSim.Services.Interfaces | ||
34 | { | ||
35 | public class FriendInfo | ||
36 | { | ||
37 | public UUID PrincipalID; | ||
38 | public string Friend; | ||
39 | public int MyFlags; | ||
40 | public int TheirFlags; | ||
41 | |||
42 | public FriendInfo() | ||
43 | { | ||
44 | } | ||
45 | |||
46 | public FriendInfo(Dictionary<string, object> kvp) | ||
47 | { | ||
48 | PrincipalID = UUID.Zero; | ||
49 | if (kvp.ContainsKey("PrincipalID") && kvp["PrincipalID"] != null) | ||
50 | UUID.TryParse(kvp["PrincipalID"].ToString(), out PrincipalID); | ||
51 | Friend = string.Empty; | ||
52 | if (kvp.ContainsKey("Friend") && kvp["Friend"] != null) | ||
53 | Friend = kvp["Friend"].ToString(); | ||
54 | MyFlags = 0; | ||
55 | if (kvp.ContainsKey("MyFlags") && kvp["MyFlags"] != null) | ||
56 | Int32.TryParse(kvp["MyFlags"].ToString(), out MyFlags); | ||
57 | TheirFlags = 0; | ||
58 | if (kvp.ContainsKey("TheirFlags") && kvp["TheirFlags"] != null) | ||
59 | Int32.TryParse(kvp["TheirFlags"].ToString(), out TheirFlags); | ||
60 | } | ||
61 | |||
62 | public Dictionary<string, object> ToKeyValuePairs() | ||
63 | { | ||
64 | Dictionary<string, object> result = new Dictionary<string, object>(); | ||
65 | result["PrincipalID"] = PrincipalID.ToString(); | ||
66 | result["Friend"] = Friend; | ||
67 | result["MyFlags"] = MyFlags.ToString(); | ||
68 | result["TheirFlags"] = TheirFlags.ToString(); | ||
69 | |||
70 | return result; | ||
71 | } | ||
72 | } | ||
73 | |||
74 | public interface IFriendsService | ||
75 | { | ||
76 | FriendInfo[] GetFriends(UUID PrincipalID); | ||
77 | FriendInfo[] GetFriends(string PrincipalID); | ||
78 | bool StoreFriend(string PrincipalID, string Friend, int flags); | ||
79 | bool Delete(UUID PrincipalID, string Friend); | ||
80 | bool Delete(string PrincipalID, string Friend); | ||
81 | } | ||
82 | } | ||
diff --git a/OpenSim/Services/Interfaces/IGridService.cs b/OpenSim/Services/Interfaces/IGridService.cs index 5135f6d..2b0b947 100644 --- a/OpenSim/Services/Interfaces/IGridService.cs +++ b/OpenSim/Services/Interfaces/IGridService.cs | |||
@@ -71,6 +71,12 @@ namespace OpenSim.Services.Interfaces | |||
71 | /// <returns></returns> | 71 | /// <returns></returns> |
72 | GridRegion GetRegionByPosition(UUID scopeID, int x, int y); | 72 | GridRegion GetRegionByPosition(UUID scopeID, int x, int y); |
73 | 73 | ||
74 | /// <summary> | ||
75 | /// Get information about a region which exactly matches the name given. | ||
76 | /// </summary> | ||
77 | /// <param name="scopeID"></param> | ||
78 | /// <param name="regionName"></param> | ||
79 | /// <returns>Returns the region information if the name matched. Null otherwise.</returns> | ||
74 | GridRegion GetRegionByName(UUID scopeID, string regionName); | 80 | GridRegion GetRegionByName(UUID scopeID, string regionName); |
75 | 81 | ||
76 | /// <summary> | 82 | /// <summary> |
@@ -90,11 +96,15 @@ namespace OpenSim.Services.Interfaces | |||
90 | 96 | ||
91 | List<GridRegion> GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax); | 97 | List<GridRegion> GetRegionRange(UUID scopeID, int xmin, int xmax, int ymin, int ymax); |
92 | 98 | ||
99 | List<GridRegion> GetDefaultRegions(UUID scopeID); | ||
100 | List<GridRegion> GetFallbackRegions(UUID scopeID, int x, int y); | ||
101 | List<GridRegion> GetHyperlinks(UUID scopeID); | ||
102 | |||
103 | int GetRegionFlags(UUID scopeID, UUID regionID); | ||
93 | } | 104 | } |
94 | 105 | ||
95 | public class GridRegion | 106 | public class GridRegion |
96 | { | 107 | { |
97 | |||
98 | /// <summary> | 108 | /// <summary> |
99 | /// The port by which http communication occurs with the region | 109 | /// The port by which http communication occurs with the region |
100 | /// </summary> | 110 | /// </summary> |
@@ -110,8 +120,20 @@ namespace OpenSim.Services.Interfaces | |||
110 | /// </summary> | 120 | /// </summary> |
111 | public string ServerURI | 121 | public string ServerURI |
112 | { | 122 | { |
113 | get { return m_serverURI; } | 123 | get { |
114 | set { m_serverURI = value; } | 124 | if ( m_serverURI != string.Empty ) { |
125 | return m_serverURI; | ||
126 | } else { | ||
127 | return "http://" + m_externalHostName + ":" + m_httpPort + "/"; | ||
128 | } | ||
129 | } | ||
130 | set { | ||
131 | if ( value.EndsWith("/") ) { | ||
132 | m_serverURI = value; | ||
133 | } else { | ||
134 | m_serverURI = value + '/'; | ||
135 | } | ||
136 | } | ||
115 | } | 137 | } |
116 | protected string m_serverURI; | 138 | protected string m_serverURI; |
117 | 139 | ||
@@ -126,6 +148,19 @@ namespace OpenSim.Services.Interfaces | |||
126 | 148 | ||
127 | protected IPEndPoint m_internalEndPoint; | 149 | protected IPEndPoint m_internalEndPoint; |
128 | 150 | ||
151 | /// <summary> | ||
152 | /// The co-ordinate of this region. | ||
153 | /// </summary> | ||
154 | public int RegionCoordX { get { return RegionLocX / (int)Constants.RegionSize; } } | ||
155 | |||
156 | /// <summary> | ||
157 | /// The co-ordinate of this region | ||
158 | /// </summary> | ||
159 | public int RegionCoordY { get { return RegionLocY / (int)Constants.RegionSize; } } | ||
160 | |||
161 | /// <summary> | ||
162 | /// The location of this region in meters. | ||
163 | /// </summary> | ||
129 | public int RegionLocX | 164 | public int RegionLocX |
130 | { | 165 | { |
131 | get { return m_regionLocX; } | 166 | get { return m_regionLocX; } |
@@ -133,6 +168,9 @@ namespace OpenSim.Services.Interfaces | |||
133 | } | 168 | } |
134 | protected int m_regionLocX; | 169 | protected int m_regionLocX; |
135 | 170 | ||
171 | /// <summary> | ||
172 | /// The location of this region in meters. | ||
173 | /// </summary> | ||
136 | public int RegionLocY | 174 | public int RegionLocY |
137 | { | 175 | { |
138 | get { return m_regionLocY; } | 176 | get { return m_regionLocY; } |
@@ -154,10 +192,12 @@ namespace OpenSim.Services.Interfaces | |||
154 | public UUID TerrainImage = UUID.Zero; | 192 | public UUID TerrainImage = UUID.Zero; |
155 | public byte Access; | 193 | public byte Access; |
156 | public int Maturity; | 194 | public int Maturity; |
157 | public string RegionSecret; | 195 | public string RegionSecret = string.Empty; |
196 | public string Token = string.Empty; | ||
158 | 197 | ||
159 | public GridRegion() | 198 | public GridRegion() |
160 | { | 199 | { |
200 | m_serverURI = string.Empty; | ||
161 | } | 201 | } |
162 | 202 | ||
163 | public GridRegion(int regionLocX, int regionLocY, IPEndPoint internalEndPoint, string externalUri) | 203 | public GridRegion(int regionLocX, int regionLocY, IPEndPoint internalEndPoint, string externalUri) |
@@ -200,12 +240,6 @@ namespace OpenSim.Services.Interfaces | |||
200 | Maturity = ConvertFrom.RegionSettings.Maturity; | 240 | Maturity = ConvertFrom.RegionSettings.Maturity; |
201 | RegionSecret = ConvertFrom.regionSecret; | 241 | RegionSecret = ConvertFrom.regionSecret; |
202 | EstateOwner = ConvertFrom.EstateSettings.EstateOwner; | 242 | EstateOwner = ConvertFrom.EstateSettings.EstateOwner; |
203 | if (EstateOwner == UUID.Zero) | ||
204 | { | ||
205 | EstateOwner = ConvertFrom.MasterAvatarAssignedUUID; | ||
206 | ConvertFrom.EstateSettings.EstateOwner = EstateOwner; | ||
207 | ConvertFrom.EstateSettings.Save(); | ||
208 | } | ||
209 | } | 243 | } |
210 | 244 | ||
211 | public GridRegion(GridRegion ConvertFrom) | 245 | public GridRegion(GridRegion ConvertFrom) |
@@ -225,6 +259,33 @@ namespace OpenSim.Services.Interfaces | |||
225 | EstateOwner = ConvertFrom.EstateOwner; | 259 | EstateOwner = ConvertFrom.EstateOwner; |
226 | } | 260 | } |
227 | 261 | ||
262 | # region Definition of equality | ||
263 | |||
264 | /// <summary> | ||
265 | /// Define equality as two regions having the same, non-zero UUID. | ||
266 | /// </summary> | ||
267 | public bool Equals(GridRegion region) | ||
268 | { | ||
269 | if ((object)region == null) | ||
270 | return false; | ||
271 | // Return true if the non-zero UUIDs are equal: | ||
272 | return (RegionID != UUID.Zero) && RegionID.Equals(region.RegionID); | ||
273 | } | ||
274 | |||
275 | public override bool Equals(Object obj) | ||
276 | { | ||
277 | if (obj == null) | ||
278 | return false; | ||
279 | return Equals(obj as GridRegion); | ||
280 | } | ||
281 | |||
282 | public override int GetHashCode() | ||
283 | { | ||
284 | return RegionID.GetHashCode() ^ TerrainImage.GetHashCode(); | ||
285 | } | ||
286 | |||
287 | #endregion | ||
288 | |||
228 | /// <value> | 289 | /// <value> |
229 | /// This accessor can throw all the exceptions that Dns.GetHostAddresses can throw. | 290 | /// This accessor can throw all the exceptions that Dns.GetHostAddresses can throw. |
230 | /// | 291 | /// |
@@ -260,15 +321,17 @@ namespace OpenSim.Services.Interfaces | |||
260 | } | 321 | } |
261 | catch (SocketException e) | 322 | catch (SocketException e) |
262 | { | 323 | { |
263 | throw new Exception( | 324 | /*throw new Exception( |
264 | "Unable to resolve local hostname " + m_externalHostName + " innerException of type '" + | 325 | "Unable to resolve local hostname " + m_externalHostName + " innerException of type '" + |
265 | e + "' attached to this exception", e); | 326 | e + "' attached to this exception", e);*/ |
327 | // Don't throw a fatal exception here, instead, return Null and handle it in the caller. | ||
328 | // Reason is, on systems such as OSgrid it has occured that known hostnames stop | ||
329 | // resolving and thus make surrounding regions crash out with this exception. | ||
330 | return null; | ||
266 | } | 331 | } |
267 | 332 | ||
268 | return new IPEndPoint(ia, m_internalEndPoint.Port); | 333 | return new IPEndPoint(ia, m_internalEndPoint.Port); |
269 | } | 334 | } |
270 | |||
271 | set { m_externalHostName = value.ToString(); } | ||
272 | } | 335 | } |
273 | 336 | ||
274 | public string ExternalHostName | 337 | public string ExternalHostName |
@@ -288,11 +351,6 @@ namespace OpenSim.Services.Interfaces | |||
288 | get { return Util.UIntsToLong((uint)RegionLocX, (uint)RegionLocY); } | 351 | get { return Util.UIntsToLong((uint)RegionLocX, (uint)RegionLocY); } |
289 | } | 352 | } |
290 | 353 | ||
291 | public int getInternalEndPointPort() | ||
292 | { | ||
293 | return m_internalEndPoint.Port; | ||
294 | } | ||
295 | |||
296 | public Dictionary<string, object> ToKeyValuePairs() | 354 | public Dictionary<string, object> ToKeyValuePairs() |
297 | { | 355 | { |
298 | Dictionary<string, object> kvp = new Dictionary<string, object>(); | 356 | Dictionary<string, object> kvp = new Dictionary<string, object>(); |
@@ -308,6 +366,7 @@ namespace OpenSim.Services.Interfaces | |||
308 | kvp["access"] = Access.ToString(); | 366 | kvp["access"] = Access.ToString(); |
309 | kvp["regionSecret"] = RegionSecret; | 367 | kvp["regionSecret"] = RegionSecret; |
310 | kvp["owner_uuid"] = EstateOwner.ToString(); | 368 | kvp["owner_uuid"] = EstateOwner.ToString(); |
369 | kvp["Token"] = Token.ToString(); | ||
311 | // Maturity doesn't seem to exist in the DB | 370 | // Maturity doesn't seem to exist in the DB |
312 | return kvp; | 371 | return kvp; |
313 | } | 372 | } |
@@ -326,6 +385,12 @@ namespace OpenSim.Services.Interfaces | |||
326 | if (kvp.ContainsKey("regionName")) | 385 | if (kvp.ContainsKey("regionName")) |
327 | RegionName = (string)kvp["regionName"]; | 386 | RegionName = (string)kvp["regionName"]; |
328 | 387 | ||
388 | if (kvp.ContainsKey("access")) | ||
389 | { | ||
390 | byte access = Convert.ToByte((string)kvp["access"]); | ||
391 | Maturity = (int)Util.ConvertAccessLevelToMaturity(access); | ||
392 | } | ||
393 | |||
329 | if (kvp.ContainsKey("serverIP")) | 394 | if (kvp.ContainsKey("serverIP")) |
330 | { | 395 | { |
331 | //int port = 0; | 396 | //int port = 0; |
@@ -365,7 +430,8 @@ namespace OpenSim.Services.Interfaces | |||
365 | if (kvp.ContainsKey("owner_uuid")) | 430 | if (kvp.ContainsKey("owner_uuid")) |
366 | EstateOwner = new UUID(kvp["owner_uuid"].ToString()); | 431 | EstateOwner = new UUID(kvp["owner_uuid"].ToString()); |
367 | 432 | ||
433 | if (kvp.ContainsKey("Token")) | ||
434 | Token = kvp["Token"].ToString(); | ||
368 | } | 435 | } |
369 | } | 436 | } |
370 | |||
371 | } | 437 | } |
diff --git a/OpenSim/Services/Interfaces/IGridUserService.cs b/OpenSim/Services/Interfaces/IGridUserService.cs new file mode 100644 index 0000000..6613ae7 --- /dev/null +++ b/OpenSim/Services/Interfaces/IGridUserService.cs | |||
@@ -0,0 +1,135 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | |||
32 | namespace OpenSim.Services.Interfaces | ||
33 | { | ||
34 | /// <summary> | ||
35 | /// Records user information specific to a grid but which is not part of a user's account. | ||
36 | /// </summary> | ||
37 | public class GridUserInfo | ||
38 | { | ||
39 | public string UserID; | ||
40 | |||
41 | public UUID HomeRegionID; | ||
42 | public Vector3 HomePosition; | ||
43 | public Vector3 HomeLookAt; | ||
44 | |||
45 | public UUID LastRegionID; | ||
46 | public Vector3 LastPosition; | ||
47 | public Vector3 LastLookAt; | ||
48 | |||
49 | public bool Online; | ||
50 | public DateTime Login; | ||
51 | public DateTime Logout; | ||
52 | |||
53 | public GridUserInfo() {} | ||
54 | |||
55 | public GridUserInfo(Dictionary<string, object> kvp) | ||
56 | { | ||
57 | if (kvp.ContainsKey("UserID")) | ||
58 | UserID = kvp["UserID"].ToString(); | ||
59 | |||
60 | if (kvp.ContainsKey("HomeRegionID")) | ||
61 | UUID.TryParse(kvp["HomeRegionID"].ToString(), out HomeRegionID); | ||
62 | if (kvp.ContainsKey("HomePosition")) | ||
63 | Vector3.TryParse(kvp["HomePosition"].ToString(), out HomePosition); | ||
64 | if (kvp.ContainsKey("HomeLookAt")) | ||
65 | Vector3.TryParse(kvp["HomeLookAt"].ToString(), out HomeLookAt); | ||
66 | |||
67 | if (kvp.ContainsKey("LastRegionID")) | ||
68 | UUID.TryParse(kvp["LastRegionID"].ToString(), out LastRegionID); | ||
69 | if (kvp.ContainsKey("LastPosition")) | ||
70 | Vector3.TryParse(kvp["LastPosition"].ToString(), out LastPosition); | ||
71 | if (kvp.ContainsKey("LastLookAt")) | ||
72 | Vector3.TryParse(kvp["LastLookAt"].ToString(), out LastLookAt); | ||
73 | |||
74 | if (kvp.ContainsKey("Login")) | ||
75 | DateTime.TryParse(kvp["Login"].ToString(), out Login); | ||
76 | if (kvp.ContainsKey("Logout")) | ||
77 | DateTime.TryParse(kvp["Logout"].ToString(), out Logout); | ||
78 | if (kvp.ContainsKey("Online")) | ||
79 | Boolean.TryParse(kvp["Online"].ToString(), out Online); | ||
80 | |||
81 | } | ||
82 | |||
83 | public Dictionary<string, object> ToKeyValuePairs() | ||
84 | { | ||
85 | Dictionary<string, object> result = new Dictionary<string, object>(); | ||
86 | result["UserID"] = UserID; | ||
87 | |||
88 | result["HomeRegionID"] = HomeRegionID.ToString(); | ||
89 | result["HomePosition"] = HomePosition.ToString(); | ||
90 | result["HomeLookAt"] = HomeLookAt.ToString(); | ||
91 | |||
92 | result["LastRegionID"] = LastRegionID.ToString(); | ||
93 | result["LastPosition"] = LastPosition.ToString(); | ||
94 | result["LastLookAt"] = LastLookAt.ToString(); | ||
95 | |||
96 | result["Online"] = Online.ToString(); | ||
97 | result["Login"] = Login.ToString(); | ||
98 | result["Logout"] = Logout.ToString(); | ||
99 | |||
100 | |||
101 | return result; | ||
102 | } | ||
103 | } | ||
104 | |||
105 | public interface IGridUserService | ||
106 | { | ||
107 | GridUserInfo LoggedIn(string userID); | ||
108 | |||
109 | /// <summary> | ||
110 | /// Informs the grid that a user is logged out and to remove any session data for them | ||
111 | /// </summary> | ||
112 | /// <param name="userID">Ignore if your connector does not use userID for logouts</param> | ||
113 | /// <param name="sessionID">Ignore if your connector does not use sessionID for logouts</param> | ||
114 | /// <param name="regionID">RegionID where the user was last located</param> | ||
115 | /// <param name="lastPosition">Last region-relative position of the user</param> | ||
116 | /// <param name="lastLookAt">Last normalized look direction for the user</param> | ||
117 | /// <returns>True if the logout request was successfully processed, otherwise false</returns> | ||
118 | bool LoggedOut(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt); | ||
119 | |||
120 | bool SetHome(string userID, UUID homeID, Vector3 homePosition, Vector3 homeLookAt); | ||
121 | |||
122 | /// <summary> | ||
123 | /// Stores the last known user position at the grid level | ||
124 | /// </summary> | ||
125 | /// <param name="userID">Ignore if your connector does not use userID for position updates</param> | ||
126 | /// <param name="sessionID">Ignore if your connector does not use sessionID for position updates</param> | ||
127 | /// <param name="regionID">RegionID where the user is currently located</param> | ||
128 | /// <param name="lastPosition">Region-relative position</param> | ||
129 | /// <param name="lastLookAt">Normalized look direction</param> | ||
130 | /// <returns>True if the user's last position was successfully updated, otherwise false</returns> | ||
131 | bool SetLastPosition(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt); | ||
132 | |||
133 | GridUserInfo GetGridUserInfo(string userID); | ||
134 | } | ||
135 | } \ No newline at end of file | ||
diff --git a/OpenSim/Services/Interfaces/IHypergridServices.cs b/OpenSim/Services/Interfaces/IHypergridServices.cs new file mode 100644 index 0000000..e86ec51 --- /dev/null +++ b/OpenSim/Services/Interfaces/IHypergridServices.cs | |||
@@ -0,0 +1,87 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Net; | ||
30 | using System.Collections.Generic; | ||
31 | |||
32 | using OpenSim.Framework; | ||
33 | using OpenMetaverse; | ||
34 | |||
35 | namespace OpenSim.Services.Interfaces | ||
36 | { | ||
37 | public interface IGatekeeperService | ||
38 | { | ||
39 | bool LinkRegion(string regionDescriptor, out UUID regionID, out ulong regionHandle, out string externalName, out string imageURL, out string reason); | ||
40 | GridRegion GetHyperlinkRegion(UUID regionID); | ||
41 | |||
42 | bool LoginAgent(AgentCircuitData aCircuit, GridRegion destination, out string reason); | ||
43 | |||
44 | } | ||
45 | |||
46 | /// <summary> | ||
47 | /// HG1.5 only | ||
48 | /// </summary> | ||
49 | public interface IUserAgentService | ||
50 | { | ||
51 | // called by login service only | ||
52 | bool LoginAgentToGrid(AgentCircuitData agent, GridRegion gatekeeper, GridRegion finalDestination, IPEndPoint clientIP, out string reason); | ||
53 | // called by simulators | ||
54 | bool LoginAgentToGrid(AgentCircuitData agent, GridRegion gatekeeper, GridRegion finalDestination, out string reason); | ||
55 | void LogoutAgent(UUID userID, UUID sessionID); | ||
56 | GridRegion GetHomeRegion(UUID userID, out Vector3 position, out Vector3 lookAt); | ||
57 | Dictionary<string, object> GetServerURLs(UUID userID); | ||
58 | |||
59 | string LocateUser(UUID userID); | ||
60 | // Tries to get the universal user identifier for the targetUserId | ||
61 | // on behalf of the userID | ||
62 | string GetUUI(UUID userID, UUID targetUserID); | ||
63 | |||
64 | // Returns the local friends online | ||
65 | List<UUID> StatusNotification(List<string> friends, UUID userID, bool online); | ||
66 | //List<UUID> GetOnlineFriends(UUID userID, List<string> friends); | ||
67 | |||
68 | bool IsAgentComingHome(UUID sessionID, string thisGridExternalName); | ||
69 | bool VerifyAgent(UUID sessionID, string token); | ||
70 | bool VerifyClient(UUID sessionID, string reportedIP); | ||
71 | } | ||
72 | |||
73 | public interface IInstantMessage | ||
74 | { | ||
75 | bool IncomingInstantMessage(GridInstantMessage im); | ||
76 | bool OutgoingInstantMessage(GridInstantMessage im, string url, bool foreigner); | ||
77 | } | ||
78 | public interface IFriendsSimConnector | ||
79 | { | ||
80 | bool StatusNotify(UUID userID, UUID friendID, bool online); | ||
81 | } | ||
82 | |||
83 | public interface IInstantMessageSimConnector | ||
84 | { | ||
85 | bool SendInstantMessage(GridInstantMessage im); | ||
86 | } | ||
87 | } | ||
diff --git a/OpenSim/Services/Interfaces/IInventoryService.cs b/OpenSim/Services/Interfaces/IInventoryService.cs index 1b78fb3..a8bfe47 100644 --- a/OpenSim/Services/Interfaces/IInventoryService.cs +++ b/OpenSim/Services/Interfaces/IInventoryService.cs | |||
@@ -141,8 +141,11 @@ namespace OpenSim.Services.Interfaces | |||
141 | /// <summary> | 141 | /// <summary> |
142 | /// Add a new item to the user's inventory | 142 | /// Add a new item to the user's inventory |
143 | /// </summary> | 143 | /// </summary> |
144 | /// <param name="item"></param> | 144 | /// <param name="item"> |
145 | /// <returns>true if the item was successfully added</returns> | 145 | /// The item to be added. If item.FolderID == UUID.Zero then the item is added to the most suitable system |
146 | /// folder. If there is no suitable folder then the item is added to the user's root inventory folder. | ||
147 | /// </param> | ||
148 | /// <returns>true if the item was successfully added, false if it was not</returns> | ||
146 | bool AddItem(InventoryItemBase item); | 149 | bool AddItem(InventoryItemBase item); |
147 | 150 | ||
148 | /// <summary> | 151 | /// <summary> |
@@ -166,7 +169,7 @@ namespace OpenSim.Services.Interfaces | |||
166 | /// Get an item, given by its UUID | 169 | /// Get an item, given by its UUID |
167 | /// </summary> | 170 | /// </summary> |
168 | /// <param name="item"></param> | 171 | /// <param name="item"></param> |
169 | /// <returns></returns> | 172 | /// <returns>null if no item was found, otherwise the found item</returns> |
170 | InventoryItemBase GetItem(InventoryItemBase item); | 173 | InventoryItemBase GetItem(InventoryItemBase item); |
171 | 174 | ||
172 | /// <summary> | 175 | /// <summary> |
diff --git a/OpenSim/Services/Interfaces/ILandService.cs b/OpenSim/Services/Interfaces/ILandService.cs index e2f1d1d..63d9a27 100644 --- a/OpenSim/Services/Interfaces/ILandService.cs +++ b/OpenSim/Services/Interfaces/ILandService.cs | |||
@@ -33,6 +33,6 @@ namespace OpenSim.Services.Interfaces | |||
33 | { | 33 | { |
34 | public interface ILandService | 34 | public interface ILandService |
35 | { | 35 | { |
36 | LandData GetLandData(ulong regionHandle, uint x, uint y); | 36 | LandData GetLandData(UUID scopeID, ulong regionHandle, uint x, uint y, out byte regionAccess); |
37 | } | 37 | } |
38 | } | 38 | } |
diff --git a/OpenSim/Services/Interfaces/IMapService.cs b/OpenSim/Services/Interfaces/ILibraryService.cs index c70f484..861cf0e 100644 --- a/OpenSim/Services/Interfaces/IMapService.cs +++ b/OpenSim/Services/Interfaces/ILibraryService.cs | |||
@@ -25,14 +25,19 @@ | |||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using OpenSim.Framework; | 28 | using System; |
29 | using System.Collections.Generic; | 29 | using System.Collections.Generic; |
30 | |||
31 | using OpenSim.Framework; | ||
30 | using OpenMetaverse; | 32 | using OpenMetaverse; |
31 | 33 | ||
32 | namespace OpenSim.Services.Interfaces | 34 | namespace OpenSim.Services.Interfaces |
33 | { | 35 | { |
34 | public interface IMapService | 36 | public interface ILibraryService |
35 | { | 37 | { |
36 | List<MapBlockData> GetMapBlocks(UUID scopeID, int minX, int minY, int maxX, int maxY); | 38 | InventoryFolderImpl LibraryRootFolder { get; } |
39 | |||
40 | Dictionary<UUID, InventoryFolderImpl> GetAllFolders(); | ||
37 | } | 41 | } |
42 | |||
38 | } | 43 | } |
diff --git a/OpenSim/Services/UserService/UserService.cs b/OpenSim/Services/Interfaces/ILoginService.cs index e8b9fc3..ee9b0b1 100644 --- a/OpenSim/Services/UserService/UserService.cs +++ b/OpenSim/Services/Interfaces/ILoginService.cs | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
@@ -26,51 +26,31 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | 28 | using System; |
29 | using System.Reflection; | 29 | using System.Collections; |
30 | using Nini.Config; | ||
31 | using OpenSim.Data; | ||
32 | using OpenSim.Services.Interfaces; | ||
33 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
31 | using System.Net; | ||
32 | |||
33 | using OpenMetaverse.StructuredData; | ||
34 | using OpenMetaverse; | 34 | using OpenMetaverse; |
35 | 35 | ||
36 | namespace OpenSim.Services.UserAccountService | 36 | namespace OpenSim.Services.Interfaces |
37 | { | 37 | { |
38 | public class UserAccountService : UserAccountServiceBase, IUserAccountService | 38 | public abstract class LoginResponse |
39 | { | 39 | { |
40 | public UserAccountService(IConfigSource config) : base(config) | 40 | public abstract Hashtable ToHashtable(); |
41 | { | 41 | public abstract OSD ToOSDMap(); |
42 | } | 42 | } |
43 | |||
44 | public UserAccount GetUserAccount(UUID scopeID, string firstName, | ||
45 | string lastName) | ||
46 | { | ||
47 | return null; | ||
48 | } | ||
49 | |||
50 | public UserAccount GetUserAccount(UUID scopeID, UUID userID) | ||
51 | { | ||
52 | return null; | ||
53 | } | ||
54 | 43 | ||
55 | public bool SetHomePosition(UserAccount data, UUID regionID, UUID regionSecret) | 44 | public abstract class FailedLoginResponse : LoginResponse |
56 | { | 45 | { |
57 | return false; | 46 | } |
58 | } | ||
59 | 47 | ||
60 | public bool SetUserAccount(UserAccount data, UUID principalID, string token) | 48 | public interface ILoginService |
61 | { | 49 | { |
62 | return false; | 50 | LoginResponse Login(string firstName, string lastName, string passwd, string startLocation, UUID scopeID, |
63 | } | 51 | string clientVersion, string channel, string mac, string id0, IPEndPoint clientIP); |
52 | Hashtable SetLevel(string firstName, string lastName, string passwd, int level, IPEndPoint clientIP); | ||
53 | } | ||
64 | 54 | ||
65 | public bool CreateUserAccount(UserAccount data, UUID principalID, string token) | ||
66 | { | ||
67 | return false; | ||
68 | } | ||
69 | 55 | ||
70 | public List<UserAccount> GetUserAccount(UUID scopeID, | ||
71 | string query) | ||
72 | { | ||
73 | return null; | ||
74 | } | ||
75 | } | ||
76 | } | 56 | } |
diff --git a/OpenSim/Services/Interfaces/IHyperlink.cs b/OpenSim/Services/Interfaces/IMapImageService.cs index ed3ff23..a7b2cf1 100644 --- a/OpenSim/Services/Interfaces/IHyperlink.cs +++ b/OpenSim/Services/Interfaces/IMapImageService.cs | |||
@@ -1,4 +1,4 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (c) Contributors, http://opensimulator.org/ | 2 | * Copyright (c) Contributors, http://opensimulator.org/ |
3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. | 3 | * See CONTRIBUTORS.TXT for a full list of copyright holders. |
4 | * | 4 | * |
@@ -26,24 +26,15 @@ | |||
26 | */ | 26 | */ |
27 | 27 | ||
28 | using OpenSim.Framework; | 28 | using OpenSim.Framework; |
29 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | 29 | using System.Collections.Generic; |
30 | |||
31 | using OpenMetaverse; | 30 | using OpenMetaverse; |
32 | 31 | ||
33 | namespace OpenSim.Services.Interfaces | 32 | namespace OpenSim.Services.Interfaces |
34 | { | 33 | { |
35 | public interface IHyperlinkService | 34 | public interface IMapImageService |
36 | { | 35 | { |
37 | GridRegion TryLinkRegion(IClientAPI client, string regionDescriptor); | 36 | //List<MapBlockData> GetMapBlocks(UUID scopeID, int minX, int minY, int maxX, int maxY); |
38 | GridRegion GetHyperlinkRegion(ulong handle); | 37 | bool AddMapTile(int x, int y, byte[] imageData, out string reason); |
39 | ulong FindRegionHandle(ulong handle); | 38 | byte[] GetMapTile(string fileName, out string format); |
40 | |||
41 | bool SendUserInformation(GridRegion region, AgentCircuitData aCircuit); | ||
42 | void AdjustUserInformation(AgentCircuitData aCircuit); | ||
43 | |||
44 | bool CheckUserAtEntry(UUID userID, UUID sessionID, out bool comingHome); | ||
45 | void AcceptUser(ForeignUserProfileData user, GridRegion home); | ||
46 | |||
47 | bool IsLocalUser(UUID userID); | ||
48 | } | 39 | } |
49 | } | 40 | } |
diff --git a/OpenSim/Services/Interfaces/IPresenceService.cs b/OpenSim/Services/Interfaces/IPresenceService.cs index aa1c5bf..8d583ff 100644 --- a/OpenSim/Services/Interfaces/IPresenceService.cs +++ b/OpenSim/Services/Interfaces/IPresenceService.cs | |||
@@ -25,6 +25,7 @@ | |||
25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 25 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
26 | */ | 26 | */ |
27 | 27 | ||
28 | using System; | ||
28 | using OpenSim.Framework; | 29 | using OpenSim.Framework; |
29 | using System.Collections.Generic; | 30 | using System.Collections.Generic; |
30 | using OpenMetaverse; | 31 | using OpenMetaverse; |
@@ -33,13 +34,40 @@ namespace OpenSim.Services.Interfaces | |||
33 | { | 34 | { |
34 | public class PresenceInfo | 35 | public class PresenceInfo |
35 | { | 36 | { |
36 | public UUID PrincipalID; | 37 | public string UserID; |
37 | public UUID RegionID; | 38 | public UUID RegionID; |
38 | public Dictionary<string, string> Data; | 39 | |
40 | public PresenceInfo() | ||
41 | { | ||
42 | } | ||
43 | |||
44 | public PresenceInfo(Dictionary<string, object> kvp) | ||
45 | { | ||
46 | if (kvp.ContainsKey("UserID")) | ||
47 | UserID = kvp["UserID"].ToString(); | ||
48 | if (kvp.ContainsKey("RegionID")) | ||
49 | UUID.TryParse(kvp["RegionID"].ToString(), out RegionID); | ||
50 | } | ||
51 | |||
52 | public Dictionary<string, object> ToKeyValuePairs() | ||
53 | { | ||
54 | Dictionary<string, object> result = new Dictionary<string, object>(); | ||
55 | result["UserID"] = UserID; | ||
56 | result["RegionID"] = RegionID.ToString(); | ||
57 | |||
58 | return result; | ||
59 | } | ||
39 | } | 60 | } |
40 | 61 | ||
41 | public interface IPresenceService | 62 | public interface IPresenceService |
42 | { | 63 | { |
43 | bool Report(PresenceInfo presence); | 64 | bool LoginAgent(string userID, UUID sessionID, UUID secureSessionID); |
65 | bool LogoutAgent(UUID sessionID); | ||
66 | bool LogoutRegionAgents(UUID regionID); | ||
67 | |||
68 | bool ReportAgent(UUID sessionID, UUID regionID); | ||
69 | |||
70 | PresenceInfo GetAgent(UUID sessionID); | ||
71 | PresenceInfo[] GetAgents(string[] userIDs); | ||
44 | } | 72 | } |
45 | } | 73 | } |
diff --git a/OpenSim/Services/Interfaces/ISimulationService.cs b/OpenSim/Services/Interfaces/ISimulationService.cs index a169ab7..ae6bd72 100644 --- a/OpenSim/Services/Interfaces/ISimulationService.cs +++ b/OpenSim/Services/Interfaces/ISimulationService.cs | |||
@@ -29,13 +29,25 @@ using System; | |||
29 | using OpenSim.Framework; | 29 | using OpenSim.Framework; |
30 | using OpenMetaverse; | 30 | using OpenMetaverse; |
31 | 31 | ||
32 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
33 | |||
32 | namespace OpenSim.Services.Interfaces | 34 | namespace OpenSim.Services.Interfaces |
33 | { | 35 | { |
34 | public interface ISimulationService | 36 | public interface ISimulationService |
35 | { | 37 | { |
38 | IScene GetScene(ulong regionHandle); | ||
39 | ISimulationService GetInnerService(); | ||
40 | |||
36 | #region Agents | 41 | #region Agents |
37 | 42 | ||
38 | bool CreateAgent(ulong regionHandle, AgentCircuitData aCircuit, out string reason); | 43 | /// <summary> |
44 | /// Ask the simulator hosting the destination to create an agent on that region. | ||
45 | /// </summary> | ||
46 | /// <param name="destination"></param> | ||
47 | /// <param name="aCircuit"></param> | ||
48 | /// <param name="flags"></param> | ||
49 | /// <param name="reason">Reason message in the event of a failure.</param> | ||
50 | bool CreateAgent(GridRegion destination, AgentCircuitData aCircuit, uint flags, out string reason); | ||
39 | 51 | ||
40 | /// <summary> | 52 | /// <summary> |
41 | /// Full child agent update. | 53 | /// Full child agent update. |
@@ -43,7 +55,7 @@ namespace OpenSim.Services.Interfaces | |||
43 | /// <param name="regionHandle"></param> | 55 | /// <param name="regionHandle"></param> |
44 | /// <param name="data"></param> | 56 | /// <param name="data"></param> |
45 | /// <returns></returns> | 57 | /// <returns></returns> |
46 | bool UpdateAgent(ulong regionHandle, AgentData data); | 58 | bool UpdateAgent(GridRegion destination, AgentData data); |
47 | 59 | ||
48 | /// <summary> | 60 | /// <summary> |
49 | /// Short child agent update, mostly for position. | 61 | /// Short child agent update, mostly for position. |
@@ -51,9 +63,11 @@ namespace OpenSim.Services.Interfaces | |||
51 | /// <param name="regionHandle"></param> | 63 | /// <param name="regionHandle"></param> |
52 | /// <param name="data"></param> | 64 | /// <param name="data"></param> |
53 | /// <returns></returns> | 65 | /// <returns></returns> |
54 | bool UpdateAgent(ulong regionHandle, AgentPosition data); | 66 | bool UpdateAgent(GridRegion destination, AgentPosition data); |
55 | 67 | ||
56 | bool RetrieveAgent(ulong regionHandle, UUID id, out IAgentData agent); | 68 | bool RetrieveAgent(GridRegion destination, UUID id, out IAgentData agent); |
69 | |||
70 | bool QueryAccess(GridRegion destination, UUID id, Vector3 position, out string version, out string reason); | ||
57 | 71 | ||
58 | /// <summary> | 72 | /// <summary> |
59 | /// Message from receiving region to departing region, telling it got contacted by the client. | 73 | /// Message from receiving region to departing region, telling it got contacted by the client. |
@@ -63,7 +77,15 @@ namespace OpenSim.Services.Interfaces | |||
63 | /// <param name="id"></param> | 77 | /// <param name="id"></param> |
64 | /// <param name="uri"></param> | 78 | /// <param name="uri"></param> |
65 | /// <returns></returns> | 79 | /// <returns></returns> |
66 | bool ReleaseAgent(ulong regionHandle, UUID id, string uri); | 80 | bool ReleaseAgent(UUID originRegion, UUID id, string uri); |
81 | |||
82 | /// <summary> | ||
83 | /// Close child agent. | ||
84 | /// </summary> | ||
85 | /// <param name="regionHandle"></param> | ||
86 | /// <param name="id"></param> | ||
87 | /// <returns></returns> | ||
88 | bool CloseChildAgent(GridRegion destination, UUID id); | ||
67 | 89 | ||
68 | /// <summary> | 90 | /// <summary> |
69 | /// Close agent. | 91 | /// Close agent. |
@@ -71,7 +93,7 @@ namespace OpenSim.Services.Interfaces | |||
71 | /// <param name="regionHandle"></param> | 93 | /// <param name="regionHandle"></param> |
72 | /// <param name="id"></param> | 94 | /// <param name="id"></param> |
73 | /// <returns></returns> | 95 | /// <returns></returns> |
74 | bool CloseAgent(ulong regionHandle, UUID id); | 96 | bool CloseAgent(GridRegion destination, UUID id); |
75 | 97 | ||
76 | #endregion Agents | 98 | #endregion Agents |
77 | 99 | ||
@@ -84,7 +106,7 @@ namespace OpenSim.Services.Interfaces | |||
84 | /// <param name="sog"></param> | 106 | /// <param name="sog"></param> |
85 | /// <param name="isLocalCall"></param> | 107 | /// <param name="isLocalCall"></param> |
86 | /// <returns></returns> | 108 | /// <returns></returns> |
87 | bool CreateObject(ulong regionHandle, ISceneObject sog, bool isLocalCall); | 109 | bool CreateObject(GridRegion destination, ISceneObject sog, bool isLocalCall); |
88 | 110 | ||
89 | /// <summary> | 111 | /// <summary> |
90 | /// Create an object from the user's inventory in the destination region. | 112 | /// Create an object from the user's inventory in the destination region. |
@@ -94,15 +116,9 @@ namespace OpenSim.Services.Interfaces | |||
94 | /// <param name="userID"></param> | 116 | /// <param name="userID"></param> |
95 | /// <param name="itemID"></param> | 117 | /// <param name="itemID"></param> |
96 | /// <returns></returns> | 118 | /// <returns></returns> |
97 | bool CreateObject(ulong regionHandle, UUID userID, UUID itemID); | 119 | bool CreateObject(GridRegion destination, UUID userID, UUID itemID); |
98 | 120 | ||
99 | #endregion Objects | 121 | #endregion Objects |
100 | 122 | ||
101 | #region Regions | ||
102 | |||
103 | bool HelloNeighbour(ulong regionHandle, RegionInfo thisRegion); | ||
104 | |||
105 | #endregion Regions | ||
106 | |||
107 | } | 123 | } |
108 | } | 124 | } |
diff --git a/OpenSim/Services/Interfaces/IUserAccountService.cs b/OpenSim/Services/Interfaces/IUserAccountService.cs new file mode 100644 index 0000000..d0fddee --- /dev/null +++ b/OpenSim/Services/Interfaces/IUserAccountService.cs | |||
@@ -0,0 +1,194 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using OpenMetaverse; | ||
31 | |||
32 | using OpenSim.Framework; | ||
33 | |||
34 | namespace OpenSim.Services.Interfaces | ||
35 | { | ||
36 | public class UserAccount | ||
37 | { | ||
38 | public UserAccount() | ||
39 | { | ||
40 | } | ||
41 | |||
42 | public UserAccount(UUID principalID) | ||
43 | { | ||
44 | PrincipalID = principalID; | ||
45 | } | ||
46 | |||
47 | /// <summary> | ||
48 | /// Initializes a new instance of the <see cref="OpenSim.Services.Interfaces.UserAccount"/> class. | ||
49 | /// This method is used by externasl/3rd party management applications that need us to create a | ||
50 | /// random UUID for the new user. | ||
51 | /// </summary> | ||
52 | /// <param name='scopeID'> | ||
53 | /// Scope I. | ||
54 | /// </param> | ||
55 | /// <param name='firstName'> | ||
56 | /// First name. | ||
57 | /// </param> | ||
58 | /// <param name='lastName'> | ||
59 | /// Last name. | ||
60 | /// </param> | ||
61 | /// <param name='email'> | ||
62 | /// Email. | ||
63 | /// </param> | ||
64 | public UserAccount(UUID scopeID, string firstName, string lastName, string email) | ||
65 | { | ||
66 | PrincipalID = UUID.Random(); | ||
67 | ScopeID = scopeID; | ||
68 | FirstName = firstName; | ||
69 | LastName = lastName; | ||
70 | Email = email; | ||
71 | ServiceURLs = new Dictionary<string, object>(); | ||
72 | Created = Util.UnixTimeSinceEpoch(); | ||
73 | } | ||
74 | |||
75 | public UserAccount(UUID scopeID, UUID principalID, string firstName, string lastName, string email) | ||
76 | { | ||
77 | PrincipalID = principalID; | ||
78 | ScopeID = scopeID; | ||
79 | FirstName = firstName; | ||
80 | LastName = lastName; | ||
81 | Email = email; | ||
82 | ServiceURLs = new Dictionary<string, object>(); | ||
83 | Created = Util.UnixTimeSinceEpoch(); | ||
84 | } | ||
85 | |||
86 | public string FirstName; | ||
87 | public string LastName; | ||
88 | public string Email; | ||
89 | public UUID PrincipalID; | ||
90 | public UUID ScopeID; | ||
91 | public int UserLevel; | ||
92 | public int UserFlags; | ||
93 | public string UserTitle; | ||
94 | public string UserCountry; | ||
95 | |||
96 | public Dictionary<string, object> ServiceURLs; | ||
97 | |||
98 | public int Created; | ||
99 | |||
100 | public string Name | ||
101 | { | ||
102 | get { return FirstName + " " + LastName; } | ||
103 | } | ||
104 | |||
105 | public UserAccount(Dictionary<string, object> kvp) | ||
106 | { | ||
107 | if (kvp.ContainsKey("FirstName")) | ||
108 | FirstName = kvp["FirstName"].ToString(); | ||
109 | if (kvp.ContainsKey("LastName")) | ||
110 | LastName = kvp["LastName"].ToString(); | ||
111 | if (kvp.ContainsKey("Email")) | ||
112 | Email = kvp["Email"].ToString(); | ||
113 | if (kvp.ContainsKey("PrincipalID")) | ||
114 | UUID.TryParse(kvp["PrincipalID"].ToString(), out PrincipalID); | ||
115 | if (kvp.ContainsKey("ScopeID")) | ||
116 | UUID.TryParse(kvp["ScopeID"].ToString(), out ScopeID); | ||
117 | if (kvp.ContainsKey("UserLevel")) | ||
118 | UserLevel = Convert.ToInt32(kvp["UserLevel"].ToString()); | ||
119 | if (kvp.ContainsKey("UserFlags")) | ||
120 | UserFlags = Convert.ToInt32(kvp["UserFlags"].ToString()); | ||
121 | if (kvp.ContainsKey("UserTitle")) | ||
122 | UserTitle = kvp["UserTitle"].ToString(); | ||
123 | if (kvp.ContainsKey("UserCountry")) | ||
124 | UserCountry = kvp["UserCountry"].ToString(); | ||
125 | |||
126 | if (kvp.ContainsKey("Created")) | ||
127 | Created = Convert.ToInt32(kvp["Created"].ToString()); | ||
128 | if (kvp.ContainsKey("ServiceURLs") && kvp["ServiceURLs"] != null) | ||
129 | { | ||
130 | ServiceURLs = new Dictionary<string, object>(); | ||
131 | string str = kvp["ServiceURLs"].ToString(); | ||
132 | if (str != string.Empty) | ||
133 | { | ||
134 | string[] parts = str.Split(new char[] { ';' }); | ||
135 | // Dictionary<string, object> dic = new Dictionary<string, object>(); | ||
136 | foreach (string s in parts) | ||
137 | { | ||
138 | string[] parts2 = s.Split(new char[] { '*' }); | ||
139 | if (parts2.Length == 2) | ||
140 | ServiceURLs[parts2[0]] = parts2[1]; | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | |||
146 | public Dictionary<string, object> ToKeyValuePairs() | ||
147 | { | ||
148 | Dictionary<string, object> result = new Dictionary<string, object>(); | ||
149 | result["FirstName"] = FirstName; | ||
150 | result["LastName"] = LastName; | ||
151 | result["Email"] = Email; | ||
152 | result["PrincipalID"] = PrincipalID.ToString(); | ||
153 | result["ScopeID"] = ScopeID.ToString(); | ||
154 | result["Created"] = Created.ToString(); | ||
155 | result["UserLevel"] = UserLevel.ToString(); | ||
156 | result["UserFlags"] = UserFlags.ToString(); | ||
157 | result["UserTitle"] = UserTitle; | ||
158 | result["UserCountry"] = UserCountry; | ||
159 | |||
160 | string str = string.Empty; | ||
161 | foreach (KeyValuePair<string, object> kvp in ServiceURLs) | ||
162 | { | ||
163 | str += kvp.Key + "*" + (kvp.Value == null ? "" : kvp.Value) + ";"; | ||
164 | } | ||
165 | result["ServiceURLs"] = str; | ||
166 | |||
167 | return result; | ||
168 | } | ||
169 | |||
170 | }; | ||
171 | |||
172 | public interface IUserAccountService | ||
173 | { | ||
174 | UserAccount GetUserAccount(UUID scopeID, UUID userID); | ||
175 | UserAccount GetUserAccount(UUID scopeID, string FirstName, string LastName); | ||
176 | UserAccount GetUserAccount(UUID scopeID, string Email); | ||
177 | |||
178 | /// <summary> | ||
179 | /// Returns the list of avatars that matches both the search criterion and the scope ID passed | ||
180 | /// </summary> | ||
181 | /// <param name="scopeID"></param> | ||
182 | /// <param name="query"></param> | ||
183 | /// <returns></returns> | ||
184 | List<UserAccount> GetUserAccounts(UUID scopeID, string query); | ||
185 | List<UserAccount> GetUserAccountsWhere(UUID scopeID, string where); | ||
186 | |||
187 | /// <summary> | ||
188 | /// Store the data given, wich replaces the stored data, therefore must be complete. | ||
189 | /// </summary> | ||
190 | /// <param name="data"></param> | ||
191 | /// <returns></returns> | ||
192 | bool StoreUserAccount(UserAccount data); | ||
193 | } | ||
194 | } | ||
diff --git a/OpenSim/Services/Interfaces/IUserService.cs b/OpenSim/Services/Interfaces/IUserService.cs deleted file mode 100644 index 92bd8ef..0000000 --- a/OpenSim/Services/Interfaces/IUserService.cs +++ /dev/null | |||
@@ -1,103 +0,0 @@ | |||
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 | |||
28 | using System.Collections.Generic; | ||
29 | using OpenMetaverse; | ||
30 | |||
31 | namespace OpenSim.Services.Interfaces | ||
32 | { | ||
33 | public class UserAccount | ||
34 | { | ||
35 | public UserAccount() | ||
36 | { | ||
37 | } | ||
38 | |||
39 | public UserAccount(UUID userID, UUID homeRegionID, float homePositionX, | ||
40 | float homePositionY, float homePositionZ, float homeLookAtX, | ||
41 | float homeLookAtY, float homeLookAtZ) | ||
42 | { | ||
43 | UserID = userID; | ||
44 | HomeRegionID = homeRegionID; | ||
45 | HomePositionX = homePositionX; | ||
46 | HomePositionY = homePositionY; | ||
47 | HomePositionZ = homePositionZ; | ||
48 | HomeLookAtX = homeLookAtX; | ||
49 | HomeLookAtY = homeLookAtY; | ||
50 | HomeLookAtZ = homeLookAtZ; | ||
51 | } | ||
52 | |||
53 | public string FirstName; | ||
54 | public string LastName; | ||
55 | public UUID UserID; | ||
56 | public UUID ScopeID; | ||
57 | |||
58 | // For informational purposes only! | ||
59 | // | ||
60 | public string HomeRegionName; | ||
61 | |||
62 | public UUID HomeRegionID; | ||
63 | public float HomePositionX; | ||
64 | public float HomePositionY; | ||
65 | public float HomePositionZ; | ||
66 | public float HomeLookAtX; | ||
67 | public float HomeLookAtY; | ||
68 | public float HomeLookAtZ; | ||
69 | |||
70 | // These are here because they | ||
71 | // concern the account rather than | ||
72 | // the profile. They just happen to | ||
73 | // be used in the Linden profile as well | ||
74 | // | ||
75 | public int GodLevel; | ||
76 | public int UserFlags; | ||
77 | public string AccountType; | ||
78 | |||
79 | }; | ||
80 | |||
81 | public interface IUserAccountService | ||
82 | { | ||
83 | UserAccount GetUserAccount(UUID scopeID, UUID userID); | ||
84 | UserAccount GetUserAccount(UUID scopeID, string FirstName, string LastName); | ||
85 | // Returns the list of avatars that matches both the search | ||
86 | // criterion and the scope ID passed | ||
87 | // | ||
88 | List<UserAccount> GetUserAccount(UUID scopeID, string query); | ||
89 | |||
90 | |||
91 | // This will set only the home region portion of the data! | ||
92 | // Can't be used to set god level, flags, type or change the name! | ||
93 | // | ||
94 | bool SetHomePosition(UserAccount data, UUID RegionID, UUID RegionSecret); | ||
95 | |||
96 | // Update all updatable fields | ||
97 | // | ||
98 | bool SetUserAccount(UserAccount data, UUID PrincipalID, string token); | ||
99 | |||
100 | // Creates a user data record | ||
101 | bool CreateUserAccount(UserAccount data, UUID PrincipalID, string token); | ||
102 | } | ||
103 | } | ||
diff --git a/OpenSim/Services/InventoryService/InventoryService.cs b/OpenSim/Services/InventoryService/InventoryService.cs index 95007f1..73dd06a 100644 --- a/OpenSim/Services/InventoryService/InventoryService.cs +++ b/OpenSim/Services/InventoryService/InventoryService.cs | |||
@@ -66,6 +66,7 @@ namespace OpenSim.Services.InventoryService | |||
66 | // Agent has no inventory structure yet. | 66 | // Agent has no inventory structure yet. |
67 | if (null == rootFolder) | 67 | if (null == rootFolder) |
68 | { | 68 | { |
69 | m_log.DebugFormat("[INVENTORY SERVICE]: No root folder"); | ||
69 | return null; | 70 | return null; |
70 | } | 71 | } |
71 | 72 | ||
@@ -108,7 +109,7 @@ namespace OpenSim.Services.InventoryService | |||
108 | { | 109 | { |
109 | existingRootFolder = GetRootFolder(user); | 110 | existingRootFolder = GetRootFolder(user); |
110 | } | 111 | } |
111 | catch (Exception e) | 112 | catch /*(Exception e)*/ |
112 | { | 113 | { |
113 | // Munch the exception, it has already been reported | 114 | // Munch the exception, it has already been reported |
114 | // | 115 | // |
@@ -267,6 +268,8 @@ namespace OpenSim.Services.InventoryService | |||
267 | 268 | ||
268 | public InventoryFolderBase GetFolderForType(UUID userID, AssetType type) | 269 | public InventoryFolderBase GetFolderForType(UUID userID, AssetType type) |
269 | { | 270 | { |
271 | // m_log.DebugFormat("[INVENTORY SERVICE]: Looking for folder type {0} for user {1}", type, userID); | ||
272 | |||
270 | InventoryFolderBase root = m_Database.getUserRootFolder(userID); | 273 | InventoryFolderBase root = m_Database.getUserRootFolder(userID); |
271 | if (root != null) | 274 | if (root != null) |
272 | { | 275 | { |
@@ -275,7 +278,12 @@ namespace OpenSim.Services.InventoryService | |||
275 | foreach (InventoryFolderBase folder in folders) | 278 | foreach (InventoryFolderBase folder in folders) |
276 | { | 279 | { |
277 | if (folder.Type == (short)type) | 280 | if (folder.Type == (short)type) |
281 | { | ||
282 | // m_log.DebugFormat( | ||
283 | // "[INVENTORY SERVICE]: Found folder {0} type {1}", folder.Name, (AssetType)folder.Type); | ||
284 | |||
278 | return folder; | 285 | return folder; |
286 | } | ||
279 | } | 287 | } |
280 | } | 288 | } |
281 | 289 | ||
@@ -298,6 +306,7 @@ namespace OpenSim.Services.InventoryService | |||
298 | if ((folder.Type != (short)AssetType.Folder) && (folder.Type != (short)AssetType.Unknown)) | 306 | if ((folder.Type != (short)AssetType.Folder) && (folder.Type != (short)AssetType.Unknown)) |
299 | folders[(AssetType)folder.Type] = folder; | 307 | folders[(AssetType)folder.Type] = folder; |
300 | } | 308 | } |
309 | m_log.DebugFormat("[INVENTORY SERVICE]: Got {0} system folders for {1}", folders.Count, userID); | ||
301 | return folders; | 310 | return folders; |
302 | } | 311 | } |
303 | } | 312 | } |
@@ -331,6 +340,9 @@ namespace OpenSim.Services.InventoryService | |||
331 | List<InventoryItemBase> itemsList = new List<InventoryItemBase>(); | 340 | List<InventoryItemBase> itemsList = new List<InventoryItemBase>(); |
332 | 341 | ||
333 | itemsList.AddRange(m_Database.getInventoryInFolder(folderID)); | 342 | itemsList.AddRange(m_Database.getInventoryInFolder(folderID)); |
343 | |||
344 | // m_log.DebugFormat( | ||
345 | // "[INVENTORY SERVICE]: Found {0} items in folder {1} for {2}", itemsList.Count, folderID, userID); | ||
334 | 346 | ||
335 | return itemsList; | 347 | return itemsList; |
336 | } | 348 | } |
@@ -376,8 +388,9 @@ namespace OpenSim.Services.InventoryService | |||
376 | // See IInventoryServices | 388 | // See IInventoryServices |
377 | public virtual bool AddItem(InventoryItemBase item) | 389 | public virtual bool AddItem(InventoryItemBase item) |
378 | { | 390 | { |
379 | m_log.DebugFormat( | 391 | // m_log.DebugFormat( |
380 | "[INVENTORY SERVICE]: Adding item {0} {1} to folder {2}", item.Name, item.ID, item.Folder); | 392 | // "[INVENTORY SERVICE]: Adding item {0} {1} to folder {2} for {3}", |
393 | // item.Name, item.ID, item.Folder, item.Owner); | ||
381 | 394 | ||
382 | m_Database.addInventoryItem(item); | 395 | m_Database.addInventoryItem(item); |
383 | 396 | ||
diff --git a/OpenSim/Services/InventoryService/LibraryService.cs b/OpenSim/Services/InventoryService/LibraryService.cs new file mode 100644 index 0000000..f90895b --- /dev/null +++ b/OpenSim/Services/InventoryService/LibraryService.cs | |||
@@ -0,0 +1,284 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.IO; | ||
31 | using System.Reflection; | ||
32 | using System.Xml; | ||
33 | |||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Services.Base; | ||
36 | using OpenSim.Services.Interfaces; | ||
37 | |||
38 | using log4net; | ||
39 | using Nini.Config; | ||
40 | using OpenMetaverse; | ||
41 | |||
42 | namespace OpenSim.Services.InventoryService | ||
43 | { | ||
44 | /// <summary> | ||
45 | /// Basically a hack to give us a Inventory library while we don't have a inventory server | ||
46 | /// once the server is fully implemented then should read the data from that | ||
47 | /// </summary> | ||
48 | public class LibraryService : ServiceBase, ILibraryService | ||
49 | { | ||
50 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
51 | |||
52 | private InventoryFolderImpl m_LibraryRootFolder; | ||
53 | |||
54 | public InventoryFolderImpl LibraryRootFolder | ||
55 | { | ||
56 | get { return m_LibraryRootFolder; } | ||
57 | } | ||
58 | |||
59 | private UUID libOwner = new UUID("11111111-1111-0000-0000-000100bba000"); | ||
60 | |||
61 | /// <summary> | ||
62 | /// Holds the root library folder and all its descendents. This is really only used during inventory | ||
63 | /// setup so that we don't have to repeatedly search the tree of library folders. | ||
64 | /// </summary> | ||
65 | protected Dictionary<UUID, InventoryFolderImpl> libraryFolders | ||
66 | = new Dictionary<UUID, InventoryFolderImpl>(); | ||
67 | |||
68 | public LibraryService(IConfigSource config) | ||
69 | : base(config) | ||
70 | { | ||
71 | string pLibrariesLocation = Path.Combine("inventory", "Libraries.xml"); | ||
72 | string pLibName = "OpenSim Library"; | ||
73 | |||
74 | IConfig libConfig = config.Configs["LibraryService"]; | ||
75 | if (libConfig != null) | ||
76 | { | ||
77 | pLibrariesLocation = libConfig.GetString("DefaultLibrary", pLibrariesLocation); | ||
78 | pLibName = libConfig.GetString("LibraryName", pLibName); | ||
79 | } | ||
80 | |||
81 | m_log.Debug("[LIBRARY]: Starting library service..."); | ||
82 | |||
83 | m_LibraryRootFolder = new InventoryFolderImpl(); | ||
84 | m_LibraryRootFolder.Owner = libOwner; | ||
85 | m_LibraryRootFolder.ID = new UUID("00000112-000f-0000-0000-000100bba000"); | ||
86 | m_LibraryRootFolder.Name = pLibName; | ||
87 | m_LibraryRootFolder.ParentID = UUID.Zero; | ||
88 | m_LibraryRootFolder.Type = (short)8; | ||
89 | m_LibraryRootFolder.Version = (ushort)1; | ||
90 | |||
91 | libraryFolders.Add(m_LibraryRootFolder.ID, m_LibraryRootFolder); | ||
92 | |||
93 | LoadLibraries(pLibrariesLocation); | ||
94 | } | ||
95 | |||
96 | public InventoryItemBase CreateItem(UUID inventoryID, UUID assetID, string name, string description, | ||
97 | int assetType, int invType, UUID parentFolderID) | ||
98 | { | ||
99 | InventoryItemBase item = new InventoryItemBase(); | ||
100 | item.Owner = libOwner; | ||
101 | item.CreatorId = libOwner.ToString(); | ||
102 | item.ID = inventoryID; | ||
103 | item.AssetID = assetID; | ||
104 | item.Description = description; | ||
105 | item.Name = name; | ||
106 | item.AssetType = assetType; | ||
107 | item.InvType = invType; | ||
108 | item.Folder = parentFolderID; | ||
109 | item.BasePermissions = 0x7FFFFFFF; | ||
110 | item.EveryOnePermissions = 0x7FFFFFFF; | ||
111 | item.CurrentPermissions = 0x7FFFFFFF; | ||
112 | item.NextPermissions = 0x7FFFFFFF; | ||
113 | return item; | ||
114 | } | ||
115 | |||
116 | /// <summary> | ||
117 | /// Use the asset set information at path to load assets | ||
118 | /// </summary> | ||
119 | /// <param name="path"></param> | ||
120 | /// <param name="assets"></param> | ||
121 | protected void LoadLibraries(string librariesControlPath) | ||
122 | { | ||
123 | m_log.InfoFormat("[LIBRARY INVENTORY]: Loading library control file {0}", librariesControlPath); | ||
124 | LoadFromFile(librariesControlPath, "Libraries control", ReadLibraryFromConfig); | ||
125 | } | ||
126 | |||
127 | /// <summary> | ||
128 | /// Read a library set from config | ||
129 | /// </summary> | ||
130 | /// <param name="config"></param> | ||
131 | protected void ReadLibraryFromConfig(IConfig config, string path) | ||
132 | { | ||
133 | string basePath = Path.GetDirectoryName(path); | ||
134 | string foldersPath | ||
135 | = Path.Combine( | ||
136 | basePath, config.GetString("foldersFile", String.Empty)); | ||
137 | |||
138 | LoadFromFile(foldersPath, "Library folders", ReadFolderFromConfig); | ||
139 | |||
140 | string itemsPath | ||
141 | = Path.Combine( | ||
142 | basePath, config.GetString("itemsFile", String.Empty)); | ||
143 | |||
144 | LoadFromFile(itemsPath, "Library items", ReadItemFromConfig); | ||
145 | } | ||
146 | |||
147 | /// <summary> | ||
148 | /// Read a library inventory folder from a loaded configuration | ||
149 | /// </summary> | ||
150 | /// <param name="source"></param> | ||
151 | private void ReadFolderFromConfig(IConfig config, string path) | ||
152 | { | ||
153 | InventoryFolderImpl folderInfo = new InventoryFolderImpl(); | ||
154 | |||
155 | folderInfo.ID = new UUID(config.GetString("folderID", m_LibraryRootFolder.ID.ToString())); | ||
156 | folderInfo.Name = config.GetString("name", "unknown"); | ||
157 | folderInfo.ParentID = new UUID(config.GetString("parentFolderID", m_LibraryRootFolder.ID.ToString())); | ||
158 | folderInfo.Type = (short)config.GetInt("type", 8); | ||
159 | |||
160 | folderInfo.Owner = libOwner; | ||
161 | folderInfo.Version = 1; | ||
162 | |||
163 | if (libraryFolders.ContainsKey(folderInfo.ParentID)) | ||
164 | { | ||
165 | InventoryFolderImpl parentFolder = libraryFolders[folderInfo.ParentID]; | ||
166 | |||
167 | libraryFolders.Add(folderInfo.ID, folderInfo); | ||
168 | parentFolder.AddChildFolder(folderInfo); | ||
169 | |||
170 | // m_log.InfoFormat("[LIBRARY INVENTORY]: Adding folder {0} ({1})", folderInfo.name, folderInfo.folderID); | ||
171 | } | ||
172 | else | ||
173 | { | ||
174 | m_log.WarnFormat( | ||
175 | "[LIBRARY INVENTORY]: Couldn't add folder {0} ({1}) since parent folder with ID {2} does not exist!", | ||
176 | folderInfo.Name, folderInfo.ID, folderInfo.ParentID); | ||
177 | } | ||
178 | } | ||
179 | |||
180 | /// <summary> | ||
181 | /// Read a library inventory item metadata from a loaded configuration | ||
182 | /// </summary> | ||
183 | /// <param name="source"></param> | ||
184 | private void ReadItemFromConfig(IConfig config, string path) | ||
185 | { | ||
186 | InventoryItemBase item = new InventoryItemBase(); | ||
187 | item.Owner = libOwner; | ||
188 | item.CreatorId = libOwner.ToString(); | ||
189 | item.ID = new UUID(config.GetString("inventoryID", m_LibraryRootFolder.ID.ToString())); | ||
190 | item.AssetID = new UUID(config.GetString("assetID", item.ID.ToString())); | ||
191 | item.Folder = new UUID(config.GetString("folderID", m_LibraryRootFolder.ID.ToString())); | ||
192 | item.Name = config.GetString("name", String.Empty); | ||
193 | item.Description = config.GetString("description", item.Name); | ||
194 | item.InvType = config.GetInt("inventoryType", 0); | ||
195 | item.AssetType = config.GetInt("assetType", item.InvType); | ||
196 | item.CurrentPermissions = (uint)config.GetLong("currentPermissions", (uint)PermissionMask.All); | ||
197 | item.NextPermissions = (uint)config.GetLong("nextPermissions", (uint)PermissionMask.All); | ||
198 | item.EveryOnePermissions | ||
199 | = (uint)config.GetLong("everyonePermissions", (uint)PermissionMask.All - (uint)PermissionMask.Modify); | ||
200 | item.BasePermissions = (uint)config.GetLong("basePermissions", (uint)PermissionMask.All); | ||
201 | item.Flags = (uint)config.GetInt("flags", 0); | ||
202 | |||
203 | if (libraryFolders.ContainsKey(item.Folder)) | ||
204 | { | ||
205 | InventoryFolderImpl parentFolder = libraryFolders[item.Folder]; | ||
206 | try | ||
207 | { | ||
208 | parentFolder.Items.Add(item.ID, item); | ||
209 | } | ||
210 | catch (Exception) | ||
211 | { | ||
212 | m_log.WarnFormat("[LIBRARY INVENTORY] Item {1} [{0}] not added, duplicate item", item.ID, item.Name); | ||
213 | } | ||
214 | } | ||
215 | else | ||
216 | { | ||
217 | m_log.WarnFormat( | ||
218 | "[LIBRARY INVENTORY]: Couldn't add item {0} ({1}) since parent folder with ID {2} does not exist!", | ||
219 | item.Name, item.ID, item.Folder); | ||
220 | } | ||
221 | } | ||
222 | |||
223 | private delegate void ConfigAction(IConfig config, string path); | ||
224 | |||
225 | /// <summary> | ||
226 | /// Load the given configuration at a path and perform an action on each Config contained within it | ||
227 | /// </summary> | ||
228 | /// <param name="path"></param> | ||
229 | /// <param name="fileDescription"></param> | ||
230 | /// <param name="action"></param> | ||
231 | private static void LoadFromFile(string path, string fileDescription, ConfigAction action) | ||
232 | { | ||
233 | if (File.Exists(path)) | ||
234 | { | ||
235 | try | ||
236 | { | ||
237 | XmlConfigSource source = new XmlConfigSource(path); | ||
238 | |||
239 | for (int i = 0; i < source.Configs.Count; i++) | ||
240 | { | ||
241 | action(source.Configs[i], path); | ||
242 | } | ||
243 | } | ||
244 | catch (XmlException e) | ||
245 | { | ||
246 | m_log.ErrorFormat("[LIBRARY INVENTORY]: Error loading {0} : {1}", path, e); | ||
247 | } | ||
248 | } | ||
249 | else | ||
250 | { | ||
251 | m_log.ErrorFormat("[LIBRARY INVENTORY]: {0} file {1} does not exist!", fileDescription, path); | ||
252 | } | ||
253 | } | ||
254 | |||
255 | /// <summary> | ||
256 | /// Looks like a simple getter, but is written like this for some consistency with the other Request | ||
257 | /// methods in the superclass | ||
258 | /// </summary> | ||
259 | /// <returns></returns> | ||
260 | public Dictionary<UUID, InventoryFolderImpl> GetAllFolders() | ||
261 | { | ||
262 | Dictionary<UUID, InventoryFolderImpl> fs = new Dictionary<UUID, InventoryFolderImpl>(); | ||
263 | fs.Add(m_LibraryRootFolder.ID, m_LibraryRootFolder); | ||
264 | List<InventoryFolderImpl> fis = TraverseFolder(m_LibraryRootFolder); | ||
265 | foreach (InventoryFolderImpl f in fis) | ||
266 | { | ||
267 | fs.Add(f.ID, f); | ||
268 | } | ||
269 | //return libraryFolders; | ||
270 | return fs; | ||
271 | } | ||
272 | |||
273 | private List<InventoryFolderImpl> TraverseFolder(InventoryFolderImpl node) | ||
274 | { | ||
275 | List<InventoryFolderImpl> folders = node.RequestListOfFolderImpls(); | ||
276 | List<InventoryFolderImpl> subs = new List<InventoryFolderImpl>(); | ||
277 | foreach (InventoryFolderImpl f in folders) | ||
278 | subs.AddRange(TraverseFolder(f)); | ||
279 | |||
280 | folders.AddRange(subs); | ||
281 | return folders; | ||
282 | } | ||
283 | } | ||
284 | } | ||
diff --git a/OpenSim/Services/InventoryService/XInventoryService.cs b/OpenSim/Services/InventoryService/XInventoryService.cs index 2c79c77..1648b51 100644 --- a/OpenSim/Services/InventoryService/XInventoryService.cs +++ b/OpenSim/Services/InventoryService/XInventoryService.cs | |||
@@ -40,11 +40,12 @@ namespace OpenSim.Services.InventoryService | |||
40 | { | 40 | { |
41 | public class XInventoryService : ServiceBase, IInventoryService | 41 | public class XInventoryService : ServiceBase, IInventoryService |
42 | { | 42 | { |
43 | private static readonly ILog m_log = | 43 | // private static readonly ILog m_log = |
44 | LogManager.GetLogger( | 44 | // LogManager.GetLogger( |
45 | MethodBase.GetCurrentMethod().DeclaringType); | 45 | // MethodBase.GetCurrentMethod().DeclaringType); |
46 | 46 | ||
47 | protected IXInventoryData m_Database; | 47 | protected IXInventoryData m_Database; |
48 | protected bool m_AllowDelete = true; | ||
48 | 49 | ||
49 | public XInventoryService(IConfigSource config) : base(config) | 50 | public XInventoryService(IConfigSource config) : base(config) |
50 | { | 51 | { |
@@ -60,6 +61,7 @@ namespace OpenSim.Services.InventoryService | |||
60 | { | 61 | { |
61 | dllName = authConfig.GetString("StorageProvider", dllName); | 62 | dllName = authConfig.GetString("StorageProvider", dllName); |
62 | connString = authConfig.GetString("ConnectionString", connString); | 63 | connString = authConfig.GetString("ConnectionString", connString); |
64 | m_AllowDelete = authConfig.GetBoolean("AllowDelete", true); | ||
63 | // realm = authConfig.GetString("Realm", realm); | 65 | // realm = authConfig.GetString("Realm", realm); |
64 | } | 66 | } |
65 | 67 | ||
@@ -87,7 +89,7 @@ namespace OpenSim.Services.InventoryService | |||
87 | throw new Exception("Could not find a storage interface in the given module"); | 89 | throw new Exception("Could not find a storage interface in the given module"); |
88 | } | 90 | } |
89 | 91 | ||
90 | public bool CreateUserInventory(UUID principalID) | 92 | public virtual bool CreateUserInventory(UUID principalID) |
91 | { | 93 | { |
92 | // This is braindeaad. We can't ever communicate that we fixed | 94 | // This is braindeaad. We can't ever communicate that we fixed |
93 | // an existing inventory. Well, just return root folder status, | 95 | // an existing inventory. Well, just return root folder status, |
@@ -99,7 +101,7 @@ namespace OpenSim.Services.InventoryService | |||
99 | 101 | ||
100 | if (rootFolder == null) | 102 | if (rootFolder == null) |
101 | { | 103 | { |
102 | rootFolder = ConvertToOpenSim(CreateFolder(principalID, UUID.Zero, (int)AssetType.Folder, "My Inventory")); | 104 | rootFolder = ConvertToOpenSim(CreateFolder(principalID, UUID.Zero, (int)AssetType.RootFolder, "My Inventory")); |
103 | result = true; | 105 | result = true; |
104 | } | 106 | } |
105 | 107 | ||
@@ -137,7 +139,7 @@ namespace OpenSim.Services.InventoryService | |||
137 | return result; | 139 | return result; |
138 | } | 140 | } |
139 | 141 | ||
140 | private XInventoryFolder CreateFolder(UUID principalID, UUID parentID, int type, string name) | 142 | protected XInventoryFolder CreateFolder(UUID principalID, UUID parentID, int type, string name) |
141 | { | 143 | { |
142 | XInventoryFolder newFolder = new XInventoryFolder(); | 144 | XInventoryFolder newFolder = new XInventoryFolder(); |
143 | 145 | ||
@@ -153,8 +155,10 @@ namespace OpenSim.Services.InventoryService | |||
153 | return newFolder; | 155 | return newFolder; |
154 | } | 156 | } |
155 | 157 | ||
156 | private XInventoryFolder[] GetSystemFolders(UUID principalID) | 158 | protected virtual XInventoryFolder[] GetSystemFolders(UUID principalID) |
157 | { | 159 | { |
160 | // m_log.DebugFormat("[XINVENTORY SERVICE]: Getting system folders for {0}", principalID); | ||
161 | |||
158 | XInventoryFolder[] allFolders = m_Database.GetFolders( | 162 | XInventoryFolder[] allFolders = m_Database.GetFolders( |
159 | new string[] { "agentID" }, | 163 | new string[] { "agentID" }, |
160 | new string[] { principalID.ToString() }); | 164 | new string[] { principalID.ToString() }); |
@@ -168,10 +172,13 @@ namespace OpenSim.Services.InventoryService | |||
168 | return false; | 172 | return false; |
169 | }); | 173 | }); |
170 | 174 | ||
175 | // m_log.DebugFormat( | ||
176 | // "[XINVENTORY SERVICE]: Found {0} system folders for {1}", sysFolders.Length, principalID); | ||
177 | |||
171 | return sysFolders; | 178 | return sysFolders; |
172 | } | 179 | } |
173 | 180 | ||
174 | public List<InventoryFolderBase> GetInventorySkeleton(UUID principalID) | 181 | public virtual List<InventoryFolderBase> GetInventorySkeleton(UUID principalID) |
175 | { | 182 | { |
176 | XInventoryFolder[] allFolders = m_Database.GetFolders( | 183 | XInventoryFolder[] allFolders = m_Database.GetFolders( |
177 | new string[] { "agentID" }, | 184 | new string[] { "agentID" }, |
@@ -184,14 +191,14 @@ namespace OpenSim.Services.InventoryService | |||
184 | 191 | ||
185 | foreach (XInventoryFolder x in allFolders) | 192 | foreach (XInventoryFolder x in allFolders) |
186 | { | 193 | { |
187 | m_log.DebugFormat("[INVENTORY]: Adding folder {0} to skeleton", x.folderName); | 194 | //m_log.DebugFormat("[XINVENTORY SERVICE]: Adding folder {0} to skeleton", x.folderName); |
188 | folders.Add(ConvertToOpenSim(x)); | 195 | folders.Add(ConvertToOpenSim(x)); |
189 | } | 196 | } |
190 | 197 | ||
191 | return folders; | 198 | return folders; |
192 | } | 199 | } |
193 | 200 | ||
194 | public InventoryFolderBase GetRootFolder(UUID principalID) | 201 | public virtual InventoryFolderBase GetRootFolder(UUID principalID) |
195 | { | 202 | { |
196 | XInventoryFolder[] folders = m_Database.GetFolders( | 203 | XInventoryFolder[] folders = m_Database.GetFolders( |
197 | new string[] { "agentID", "parentFolderID"}, | 204 | new string[] { "agentID", "parentFolderID"}, |
@@ -200,28 +207,44 @@ namespace OpenSim.Services.InventoryService | |||
200 | if (folders.Length == 0) | 207 | if (folders.Length == 0) |
201 | return null; | 208 | return null; |
202 | 209 | ||
203 | return ConvertToOpenSim(folders[0]); | 210 | XInventoryFolder root = null; |
211 | foreach (XInventoryFolder folder in folders) | ||
212 | if (folder.folderName == "My Inventory") | ||
213 | root = folder; | ||
214 | if (folders == null) // oops | ||
215 | root = folders[0]; | ||
216 | |||
217 | return ConvertToOpenSim(root); | ||
204 | } | 218 | } |
205 | 219 | ||
206 | public InventoryFolderBase GetFolderForType(UUID principalID, AssetType type) | 220 | public virtual InventoryFolderBase GetFolderForType(UUID principalID, AssetType type) |
207 | { | 221 | { |
222 | // m_log.DebugFormat("[XINVENTORY SERVICE]: Getting folder type {0} for user {1}", type, principalID); | ||
223 | |||
208 | XInventoryFolder[] folders = m_Database.GetFolders( | 224 | XInventoryFolder[] folders = m_Database.GetFolders( |
209 | new string[] { "agentID", "type"}, | 225 | new string[] { "agentID", "type"}, |
210 | new string[] { principalID.ToString(), ((int)type).ToString() }); | 226 | new string[] { principalID.ToString(), ((int)type).ToString() }); |
211 | 227 | ||
212 | if (folders.Length == 0) | 228 | if (folders.Length == 0) |
229 | { | ||
230 | // m_log.WarnFormat("[XINVENTORY SERVICE]: Found no folder for type {0} for user {1}", type, principalID); | ||
213 | return null; | 231 | return null; |
232 | } | ||
233 | |||
234 | // m_log.DebugFormat( | ||
235 | // "[XINVENTORY SERVICE]: Found folder {0} {1} for type {2} for user {3}", | ||
236 | // folders[0].folderName, folders[0].folderID, type, principalID); | ||
214 | 237 | ||
215 | return ConvertToOpenSim(folders[0]); | 238 | return ConvertToOpenSim(folders[0]); |
216 | } | 239 | } |
217 | 240 | ||
218 | public InventoryCollection GetFolderContent(UUID principalID, UUID folderID) | 241 | public virtual InventoryCollection GetFolderContent(UUID principalID, UUID folderID) |
219 | { | 242 | { |
220 | // This method doesn't receive a valud principal id from the | 243 | // This method doesn't receive a valud principal id from the |
221 | // connector. So we disregard the principal and look | 244 | // connector. So we disregard the principal and look |
222 | // by ID. | 245 | // by ID. |
223 | // | 246 | // |
224 | m_log.DebugFormat("[INVENTORY]: Fetch contents for folder {0}", folderID.ToString()); | 247 | //m_log.DebugFormat("[XINVENTORY SERVICE]: Fetch contents for folder {0}", folderID.ToString()); |
225 | InventoryCollection inventory = new InventoryCollection(); | 248 | InventoryCollection inventory = new InventoryCollection(); |
226 | inventory.UserID = principalID; | 249 | inventory.UserID = principalID; |
227 | inventory.Folders = new List<InventoryFolderBase>(); | 250 | inventory.Folders = new List<InventoryFolderBase>(); |
@@ -233,7 +256,7 @@ namespace OpenSim.Services.InventoryService | |||
233 | 256 | ||
234 | foreach (XInventoryFolder x in folders) | 257 | foreach (XInventoryFolder x in folders) |
235 | { | 258 | { |
236 | m_log.DebugFormat("[INVENTORY]: Adding folder {0} to response", x.folderName); | 259 | //m_log.DebugFormat("[XINVENTORY]: Adding folder {0} to response", x.folderName); |
237 | inventory.Folders.Add(ConvertToOpenSim(x)); | 260 | inventory.Folders.Add(ConvertToOpenSim(x)); |
238 | } | 261 | } |
239 | 262 | ||
@@ -243,22 +266,24 @@ namespace OpenSim.Services.InventoryService | |||
243 | 266 | ||
244 | foreach (XInventoryItem i in items) | 267 | foreach (XInventoryItem i in items) |
245 | { | 268 | { |
246 | m_log.DebugFormat("[INVENTORY]: Adding item {0} to response", i.inventoryName); | 269 | //m_log.DebugFormat("[XINVENTORY]: Adding item {0} to response", i.inventoryName); |
247 | inventory.Items.Add(ConvertToOpenSim(i)); | 270 | inventory.Items.Add(ConvertToOpenSim(i)); |
248 | } | 271 | } |
249 | 272 | ||
250 | return inventory; | 273 | return inventory; |
251 | } | 274 | } |
252 | 275 | ||
253 | public List<InventoryItemBase> GetFolderItems(UUID principalID, UUID folderID) | 276 | public virtual List<InventoryItemBase> GetFolderItems(UUID principalID, UUID folderID) |
254 | { | 277 | { |
278 | // m_log.DebugFormat("[XINVENTORY]: Fetch items for folder {0}", folderID); | ||
279 | |||
255 | // Since we probably don't get a valid principal here, either ... | 280 | // Since we probably don't get a valid principal here, either ... |
256 | // | 281 | // |
257 | List<InventoryItemBase> invItems = new List<InventoryItemBase>(); | 282 | List<InventoryItemBase> invItems = new List<InventoryItemBase>(); |
258 | 283 | ||
259 | XInventoryItem[] items = m_Database.GetItems( | 284 | XInventoryItem[] items = m_Database.GetItems( |
260 | new string[] { "parentFolderID"}, | 285 | new string[] { "parentFolderID" }, |
261 | new string[] { UUID.Zero.ToString() }); | 286 | new string[] { folderID.ToString() }); |
262 | 287 | ||
263 | foreach (XInventoryItem i in items) | 288 | foreach (XInventoryItem i in items) |
264 | invItems.Add(ConvertToOpenSim(i)); | 289 | invItems.Add(ConvertToOpenSim(i)); |
@@ -266,18 +291,40 @@ namespace OpenSim.Services.InventoryService | |||
266 | return invItems; | 291 | return invItems; |
267 | } | 292 | } |
268 | 293 | ||
269 | public bool AddFolder(InventoryFolderBase folder) | 294 | public virtual bool AddFolder(InventoryFolderBase folder) |
270 | { | 295 | { |
296 | InventoryFolderBase check = GetFolder(folder); | ||
297 | if (check != null) | ||
298 | return false; | ||
299 | |||
271 | XInventoryFolder xFolder = ConvertFromOpenSim(folder); | 300 | XInventoryFolder xFolder = ConvertFromOpenSim(folder); |
272 | return m_Database.StoreFolder(xFolder); | 301 | return m_Database.StoreFolder(xFolder); |
273 | } | 302 | } |
274 | 303 | ||
275 | public bool UpdateFolder(InventoryFolderBase folder) | 304 | public virtual bool UpdateFolder(InventoryFolderBase folder) |
276 | { | 305 | { |
277 | return AddFolder(folder); | 306 | XInventoryFolder xFolder = ConvertFromOpenSim(folder); |
307 | InventoryFolderBase check = GetFolder(folder); | ||
308 | if (check == null) | ||
309 | return AddFolder(folder); | ||
310 | |||
311 | if (check.Type != -1 || xFolder.type != -1) | ||
312 | { | ||
313 | if (xFolder.version > check.Version) | ||
314 | return false; | ||
315 | check.Version = (ushort)xFolder.version; | ||
316 | xFolder = ConvertFromOpenSim(check); | ||
317 | return m_Database.StoreFolder(xFolder); | ||
318 | } | ||
319 | |||
320 | if (xFolder.version < check.Version) | ||
321 | xFolder.version = check.Version; | ||
322 | xFolder.folderID = check.ID; | ||
323 | |||
324 | return m_Database.StoreFolder(xFolder); | ||
278 | } | 325 | } |
279 | 326 | ||
280 | public bool MoveFolder(InventoryFolderBase folder) | 327 | public virtual bool MoveFolder(InventoryFolderBase folder) |
281 | { | 328 | { |
282 | XInventoryFolder[] x = m_Database.GetFolders( | 329 | XInventoryFolder[] x = m_Database.GetFolders( |
283 | new string[] { "folderID" }, | 330 | new string[] { "folderID" }, |
@@ -293,12 +340,17 @@ namespace OpenSim.Services.InventoryService | |||
293 | 340 | ||
294 | // We don't check the principal's ID here | 341 | // We don't check the principal's ID here |
295 | // | 342 | // |
296 | public bool DeleteFolders(UUID principalID, List<UUID> folderIDs) | 343 | public virtual bool DeleteFolders(UUID principalID, List<UUID> folderIDs) |
297 | { | 344 | { |
345 | if (!m_AllowDelete) | ||
346 | return false; | ||
347 | |||
298 | // Ignore principal ID, it's bogus at connector level | 348 | // Ignore principal ID, it's bogus at connector level |
299 | // | 349 | // |
300 | foreach (UUID id in folderIDs) | 350 | foreach (UUID id in folderIDs) |
301 | { | 351 | { |
352 | if (!ParentIsTrash(id)) | ||
353 | continue; | ||
302 | InventoryFolderBase f = new InventoryFolderBase(); | 354 | InventoryFolderBase f = new InventoryFolderBase(); |
303 | f.ID = id; | 355 | f.ID = id; |
304 | PurgeFolder(f); | 356 | PurgeFolder(f); |
@@ -308,8 +360,14 @@ namespace OpenSim.Services.InventoryService | |||
308 | return true; | 360 | return true; |
309 | } | 361 | } |
310 | 362 | ||
311 | public bool PurgeFolder(InventoryFolderBase folder) | 363 | public virtual bool PurgeFolder(InventoryFolderBase folder) |
312 | { | 364 | { |
365 | if (!m_AllowDelete) | ||
366 | return false; | ||
367 | |||
368 | if (!ParentIsTrash(folder.ID)) | ||
369 | return false; | ||
370 | |||
313 | XInventoryFolder[] subFolders = m_Database.GetFolders( | 371 | XInventoryFolder[] subFolders = m_Database.GetFolders( |
314 | new string[] { "parentFolderID" }, | 372 | new string[] { "parentFolderID" }, |
315 | new string[] { folder.ID.ToString() }); | 373 | new string[] { folder.ID.ToString() }); |
@@ -325,17 +383,28 @@ namespace OpenSim.Services.InventoryService | |||
325 | return true; | 383 | return true; |
326 | } | 384 | } |
327 | 385 | ||
328 | public bool AddItem(InventoryItemBase item) | 386 | public virtual bool AddItem(InventoryItemBase item) |
329 | { | 387 | { |
388 | // m_log.DebugFormat( | ||
389 | // "[XINVENTORY SERVICE]: Adding item {0} to folder {1} for {2}", item.ID, item.Folder, item.Owner); | ||
390 | |||
330 | return m_Database.StoreItem(ConvertFromOpenSim(item)); | 391 | return m_Database.StoreItem(ConvertFromOpenSim(item)); |
331 | } | 392 | } |
332 | 393 | ||
333 | public bool UpdateItem(InventoryItemBase item) | 394 | public virtual bool UpdateItem(InventoryItemBase item) |
334 | { | 395 | { |
396 | // throw new Exception("urrgh"); | ||
397 | if (!m_AllowDelete) | ||
398 | if (item.AssetType == (sbyte)AssetType.Link || item.AssetType == (sbyte)AssetType.LinkFolder) | ||
399 | return false; | ||
400 | |||
401 | // m_log.InfoFormat( | ||
402 | // "[XINVENTORY SERVICE]: Updating item {0} {1} in folder {2}", item.Name, item.ID, item.Folder); | ||
403 | |||
335 | return m_Database.StoreItem(ConvertFromOpenSim(item)); | 404 | return m_Database.StoreItem(ConvertFromOpenSim(item)); |
336 | } | 405 | } |
337 | 406 | ||
338 | public bool MoveItems(UUID principalID, List<InventoryItemBase> items) | 407 | public virtual bool MoveItems(UUID principalID, List<InventoryItemBase> items) |
339 | { | 408 | { |
340 | // Principal is b0rked. *sigh* | 409 | // Principal is b0rked. *sigh* |
341 | // | 410 | // |
@@ -347,17 +416,38 @@ namespace OpenSim.Services.InventoryService | |||
347 | return true; | 416 | return true; |
348 | } | 417 | } |
349 | 418 | ||
350 | public bool DeleteItems(UUID principalID, List<UUID> itemIDs) | 419 | public virtual bool DeleteItems(UUID principalID, List<UUID> itemIDs) |
351 | { | 420 | { |
352 | // Just use the ID... *facepalms* | 421 | if (!m_AllowDelete) |
353 | // | 422 | { |
354 | foreach (UUID id in itemIDs) | 423 | // We must still allow links and links to folders to be deleted, otherwise they will build up |
355 | m_Database.DeleteItems("inventoryID", id.ToString()); | 424 | // in the player's inventory until they can no longer log in. Deletions of links due to code bugs or |
425 | // similar is inconvenient but on a par with accidental movement of items. The original item is never | ||
426 | // touched. | ||
427 | foreach (UUID id in itemIDs) | ||
428 | { | ||
429 | if (!m_Database.DeleteItems( | ||
430 | new string[] { "inventoryID", "assetType" }, | ||
431 | new string[] { id.ToString(), ((sbyte)AssetType.Link).ToString() })) | ||
432 | { | ||
433 | m_Database.DeleteItems( | ||
434 | new string[] { "inventoryID", "assetType" }, | ||
435 | new string[] { id.ToString(), ((sbyte)AssetType.LinkFolder).ToString() }); | ||
436 | } | ||
437 | } | ||
438 | } | ||
439 | else | ||
440 | { | ||
441 | // Just use the ID... *facepalms* | ||
442 | // | ||
443 | foreach (UUID id in itemIDs) | ||
444 | m_Database.DeleteItems("inventoryID", id.ToString()); | ||
445 | } | ||
356 | 446 | ||
357 | return true; | 447 | return true; |
358 | } | 448 | } |
359 | 449 | ||
360 | public InventoryItemBase GetItem(InventoryItemBase item) | 450 | public virtual InventoryItemBase GetItem(InventoryItemBase item) |
361 | { | 451 | { |
362 | XInventoryItem[] items = m_Database.GetItems( | 452 | XInventoryItem[] items = m_Database.GetItems( |
363 | new string[] { "inventoryID" }, | 453 | new string[] { "inventoryID" }, |
@@ -369,7 +459,7 @@ namespace OpenSim.Services.InventoryService | |||
369 | return ConvertToOpenSim(items[0]); | 459 | return ConvertToOpenSim(items[0]); |
370 | } | 460 | } |
371 | 461 | ||
372 | public InventoryFolderBase GetFolder(InventoryFolderBase folder) | 462 | public virtual InventoryFolderBase GetFolder(InventoryFolderBase folder) |
373 | { | 463 | { |
374 | XInventoryFolder[] folders = m_Database.GetFolders( | 464 | XInventoryFolder[] folders = m_Database.GetFolders( |
375 | new string[] { "folderID"}, | 465 | new string[] { "folderID"}, |
@@ -381,12 +471,12 @@ namespace OpenSim.Services.InventoryService | |||
381 | return ConvertToOpenSim(folders[0]); | 471 | return ConvertToOpenSim(folders[0]); |
382 | } | 472 | } |
383 | 473 | ||
384 | public List<InventoryItemBase> GetActiveGestures(UUID principalID) | 474 | public virtual List<InventoryItemBase> GetActiveGestures(UUID principalID) |
385 | { | 475 | { |
386 | XInventoryItem[] items = m_Database.GetActiveGestures(principalID); | 476 | XInventoryItem[] items = m_Database.GetActiveGestures(principalID); |
387 | 477 | ||
388 | if (items.Length == 0) | 478 | if (items.Length == 0) |
389 | return null; | 479 | return new List<InventoryItemBase>(); |
390 | 480 | ||
391 | List<InventoryItemBase> ret = new List<InventoryItemBase>(); | 481 | List<InventoryItemBase> ret = new List<InventoryItemBase>(); |
392 | 482 | ||
@@ -396,7 +486,7 @@ namespace OpenSim.Services.InventoryService | |||
396 | return ret; | 486 | return ret; |
397 | } | 487 | } |
398 | 488 | ||
399 | public int GetAssetPermissions(UUID principalID, UUID assetID) | 489 | public virtual int GetAssetPermissions(UUID principalID, UUID assetID) |
400 | { | 490 | { |
401 | return m_Database.GetAssetPermissions(principalID, assetID); | 491 | return m_Database.GetAssetPermissions(principalID, assetID); |
402 | } | 492 | } |
@@ -421,7 +511,7 @@ namespace OpenSim.Services.InventoryService | |||
421 | 511 | ||
422 | // CM Helpers | 512 | // CM Helpers |
423 | // | 513 | // |
424 | private InventoryFolderBase ConvertToOpenSim(XInventoryFolder folder) | 514 | protected InventoryFolderBase ConvertToOpenSim(XInventoryFolder folder) |
425 | { | 515 | { |
426 | InventoryFolderBase newFolder = new InventoryFolderBase(); | 516 | InventoryFolderBase newFolder = new InventoryFolderBase(); |
427 | 517 | ||
@@ -435,7 +525,7 @@ namespace OpenSim.Services.InventoryService | |||
435 | return newFolder; | 525 | return newFolder; |
436 | } | 526 | } |
437 | 527 | ||
438 | private XInventoryFolder ConvertFromOpenSim(InventoryFolderBase folder) | 528 | protected XInventoryFolder ConvertFromOpenSim(InventoryFolderBase folder) |
439 | { | 529 | { |
440 | XInventoryFolder newFolder = new XInventoryFolder(); | 530 | XInventoryFolder newFolder = new XInventoryFolder(); |
441 | 531 | ||
@@ -449,7 +539,7 @@ namespace OpenSim.Services.InventoryService | |||
449 | return newFolder; | 539 | return newFolder; |
450 | } | 540 | } |
451 | 541 | ||
452 | private InventoryItemBase ConvertToOpenSim(XInventoryItem item) | 542 | protected InventoryItemBase ConvertToOpenSim(XInventoryItem item) |
453 | { | 543 | { |
454 | InventoryItemBase newItem = new InventoryItemBase(); | 544 | InventoryItemBase newItem = new InventoryItemBase(); |
455 | 545 | ||
@@ -460,7 +550,7 @@ namespace OpenSim.Services.InventoryService | |||
460 | newItem.ID = item.inventoryID; | 550 | newItem.ID = item.inventoryID; |
461 | newItem.InvType = item.invType; | 551 | newItem.InvType = item.invType; |
462 | newItem.Folder = item.parentFolderID; | 552 | newItem.Folder = item.parentFolderID; |
463 | newItem.CreatorId = item.creatorID.ToString(); | 553 | newItem.CreatorIdentification = item.creatorID; |
464 | newItem.Description = item.inventoryDescription; | 554 | newItem.Description = item.inventoryDescription; |
465 | newItem.NextPermissions = (uint)item.inventoryNextPermissions; | 555 | newItem.NextPermissions = (uint)item.inventoryNextPermissions; |
466 | newItem.CurrentPermissions = (uint)item.inventoryCurrentPermissions; | 556 | newItem.CurrentPermissions = (uint)item.inventoryCurrentPermissions; |
@@ -468,7 +558,10 @@ namespace OpenSim.Services.InventoryService | |||
468 | newItem.EveryOnePermissions = (uint)item.inventoryEveryOnePermissions; | 558 | newItem.EveryOnePermissions = (uint)item.inventoryEveryOnePermissions; |
469 | newItem.GroupPermissions = (uint)item.inventoryGroupPermissions; | 559 | newItem.GroupPermissions = (uint)item.inventoryGroupPermissions; |
470 | newItem.GroupID = item.groupID; | 560 | newItem.GroupID = item.groupID; |
471 | newItem.GroupOwned = item.groupOwned; | 561 | if (item.groupOwned == 0) |
562 | newItem.GroupOwned = false; | ||
563 | else | ||
564 | newItem.GroupOwned = true; | ||
472 | newItem.SalePrice = item.salePrice; | 565 | newItem.SalePrice = item.salePrice; |
473 | newItem.SaleType = (byte)item.saleType; | 566 | newItem.SaleType = (byte)item.saleType; |
474 | newItem.Flags = (uint)item.flags; | 567 | newItem.Flags = (uint)item.flags; |
@@ -477,7 +570,7 @@ namespace OpenSim.Services.InventoryService | |||
477 | return newItem; | 570 | return newItem; |
478 | } | 571 | } |
479 | 572 | ||
480 | private XInventoryItem ConvertFromOpenSim(InventoryItemBase item) | 573 | protected XInventoryItem ConvertFromOpenSim(InventoryItemBase item) |
481 | { | 574 | { |
482 | XInventoryItem newItem = new XInventoryItem(); | 575 | XInventoryItem newItem = new XInventoryItem(); |
483 | 576 | ||
@@ -488,7 +581,7 @@ namespace OpenSim.Services.InventoryService | |||
488 | newItem.inventoryID = item.ID; | 581 | newItem.inventoryID = item.ID; |
489 | newItem.invType = item.InvType; | 582 | newItem.invType = item.InvType; |
490 | newItem.parentFolderID = item.Folder; | 583 | newItem.parentFolderID = item.Folder; |
491 | newItem.creatorID = item.CreatorIdAsUuid; | 584 | newItem.creatorID = item.CreatorIdentification; |
492 | newItem.inventoryDescription = item.Description; | 585 | newItem.inventoryDescription = item.Description; |
493 | newItem.inventoryNextPermissions = (int)item.NextPermissions; | 586 | newItem.inventoryNextPermissions = (int)item.NextPermissions; |
494 | newItem.inventoryCurrentPermissions = (int)item.CurrentPermissions; | 587 | newItem.inventoryCurrentPermissions = (int)item.CurrentPermissions; |
@@ -496,7 +589,10 @@ namespace OpenSim.Services.InventoryService | |||
496 | newItem.inventoryEveryOnePermissions = (int)item.EveryOnePermissions; | 589 | newItem.inventoryEveryOnePermissions = (int)item.EveryOnePermissions; |
497 | newItem.inventoryGroupPermissions = (int)item.GroupPermissions; | 590 | newItem.inventoryGroupPermissions = (int)item.GroupPermissions; |
498 | newItem.groupID = item.GroupID; | 591 | newItem.groupID = item.GroupID; |
499 | newItem.groupOwned = item.GroupOwned; | 592 | if (item.GroupOwned) |
593 | newItem.groupOwned = 1; | ||
594 | else | ||
595 | newItem.groupOwned = 0; | ||
500 | newItem.salePrice = item.SalePrice; | 596 | newItem.salePrice = item.SalePrice; |
501 | newItem.saleType = (int)item.SaleType; | 597 | newItem.saleType = (int)item.SaleType; |
502 | newItem.flags = (int)item.Flags; | 598 | newItem.flags = (int)item.Flags; |
@@ -504,5 +600,32 @@ namespace OpenSim.Services.InventoryService | |||
504 | 600 | ||
505 | return newItem; | 601 | return newItem; |
506 | } | 602 | } |
603 | |||
604 | private bool ParentIsTrash(UUID folderID) | ||
605 | { | ||
606 | XInventoryFolder[] folder = m_Database.GetFolders(new string[] {"folderID"}, new string[] {folderID.ToString()}); | ||
607 | if (folder.Length < 1) | ||
608 | return false; | ||
609 | |||
610 | if (folder[0].type == (int)AssetType.TrashFolder) | ||
611 | return true; | ||
612 | |||
613 | UUID parentFolder = folder[0].parentFolderID; | ||
614 | |||
615 | while (parentFolder != UUID.Zero) | ||
616 | { | ||
617 | XInventoryFolder[] parent = m_Database.GetFolders(new string[] {"folderID"}, new string[] {parentFolder.ToString()}); | ||
618 | if (parent.Length < 1) | ||
619 | return false; | ||
620 | |||
621 | if (parent[0].type == (int)AssetType.TrashFolder) | ||
622 | return true; | ||
623 | if (parent[0].type == (int)AssetType.RootFolder) | ||
624 | return false; | ||
625 | |||
626 | parentFolder = parent[0].parentFolderID; | ||
627 | } | ||
628 | return false; | ||
629 | } | ||
507 | } | 630 | } |
508 | } | 631 | } |
diff --git a/OpenSim/Services/LLLoginService/LLLoginResponse.cs b/OpenSim/Services/LLLoginService/LLLoginResponse.cs new file mode 100644 index 0000000..de05f28 --- /dev/null +++ b/OpenSim/Services/LLLoginService/LLLoginResponse.cs | |||
@@ -0,0 +1,1026 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Net; | ||
32 | using System.Reflection; | ||
33 | |||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Services.Interfaces; | ||
36 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
37 | using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; | ||
38 | |||
39 | using log4net; | ||
40 | using OpenMetaverse; | ||
41 | using OpenMetaverse.StructuredData; | ||
42 | using OSDArray = OpenMetaverse.StructuredData.OSDArray; | ||
43 | using OSDMap = OpenMetaverse.StructuredData.OSDMap; | ||
44 | |||
45 | namespace OpenSim.Services.LLLoginService | ||
46 | { | ||
47 | public class LLFailedLoginResponse : OpenSim.Services.Interfaces.FailedLoginResponse | ||
48 | { | ||
49 | protected string m_key; | ||
50 | protected string m_value; | ||
51 | protected string m_login; | ||
52 | |||
53 | public static LLFailedLoginResponse UserProblem; | ||
54 | public static LLFailedLoginResponse GridProblem; | ||
55 | public static LLFailedLoginResponse InventoryProblem; | ||
56 | public static LLFailedLoginResponse DeadRegionProblem; | ||
57 | public static LLFailedLoginResponse LoginBlockedProblem; | ||
58 | public static LLFailedLoginResponse UnverifiedAccountProblem; | ||
59 | public static LLFailedLoginResponse AlreadyLoggedInProblem; | ||
60 | public static LLFailedLoginResponse InternalError; | ||
61 | |||
62 | static LLFailedLoginResponse() | ||
63 | { | ||
64 | UserProblem = new LLFailedLoginResponse("key", | ||
65 | "Could not authenticate your avatar. Please check your username and password, and check the grid if problems persist.", | ||
66 | "false"); | ||
67 | GridProblem = new LLFailedLoginResponse("key", | ||
68 | "Error connecting to the desired location. Try connecting to another region.", | ||
69 | "false"); | ||
70 | InventoryProblem = new LLFailedLoginResponse("key", | ||
71 | "The inventory service is not responding. Please notify your login region operator.", | ||
72 | "false"); | ||
73 | DeadRegionProblem = new LLFailedLoginResponse("key", | ||
74 | "The region you are attempting to log into is not responding. Please select another region and try again.", | ||
75 | "false"); | ||
76 | LoginBlockedProblem = new LLFailedLoginResponse("presence", | ||
77 | "Logins are currently restricted. Please try again later.", | ||
78 | "false"); | ||
79 | UnverifiedAccountProblem = new LLFailedLoginResponse("presence", | ||
80 | "Your account has not yet been verified. Please check " + | ||
81 | "your email and click the provided link.", | ||
82 | "false"); | ||
83 | AlreadyLoggedInProblem = new LLFailedLoginResponse("presence", | ||
84 | "You appear to be already logged in. " + | ||
85 | "If this is not the case please wait for your session to timeout. " + | ||
86 | "If this takes longer than a few minutes please contact the grid owner. " + | ||
87 | "Please wait 5 minutes if you are going to connect to a region nearby to the region you were at previously.", | ||
88 | "false"); | ||
89 | InternalError = new LLFailedLoginResponse("Internal Error", "Error generating Login Response", "false"); | ||
90 | } | ||
91 | |||
92 | public LLFailedLoginResponse(string key, string value, string login) | ||
93 | { | ||
94 | m_key = key; | ||
95 | m_value = value; | ||
96 | m_login = login; | ||
97 | } | ||
98 | |||
99 | public override Hashtable ToHashtable() | ||
100 | { | ||
101 | Hashtable loginError = new Hashtable(); | ||
102 | loginError["reason"] = m_key; | ||
103 | loginError["message"] = m_value; | ||
104 | loginError["login"] = m_login; | ||
105 | return loginError; | ||
106 | } | ||
107 | |||
108 | public override OSD ToOSDMap() | ||
109 | { | ||
110 | OSDMap map = new OSDMap(); | ||
111 | |||
112 | map["reason"] = OSD.FromString(m_key); | ||
113 | map["message"] = OSD.FromString(m_value); | ||
114 | map["login"] = OSD.FromString(m_login); | ||
115 | |||
116 | return map; | ||
117 | } | ||
118 | } | ||
119 | |||
120 | /// <summary> | ||
121 | /// A class to handle LL login response. | ||
122 | /// </summary> | ||
123 | public class LLLoginResponse : OpenSim.Services.Interfaces.LoginResponse | ||
124 | { | ||
125 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
126 | private static Hashtable globalTexturesHash; | ||
127 | // Global Textures | ||
128 | private static string sunTexture = "cce0f112-878f-4586-a2e2-a8f104bba271"; | ||
129 | private static string cloudTexture = "dc4b9f0b-d008-45c6-96a4-01dd947ac621"; | ||
130 | private static string moonTexture = "ec4b9f0b-d008-45c6-96a4-01dd947ac621"; | ||
131 | |||
132 | private Hashtable loginFlagsHash; | ||
133 | private Hashtable uiConfigHash; | ||
134 | |||
135 | private ArrayList loginFlags; | ||
136 | private ArrayList globalTextures; | ||
137 | private ArrayList eventCategories; | ||
138 | private ArrayList uiConfig; | ||
139 | private ArrayList classifiedCategories; | ||
140 | private ArrayList inventoryRoot; | ||
141 | private ArrayList initialOutfit; | ||
142 | private ArrayList agentInventory; | ||
143 | private ArrayList inventoryLibraryOwner; | ||
144 | private ArrayList inventoryLibRoot; | ||
145 | private ArrayList inventoryLibrary; | ||
146 | private ArrayList activeGestures; | ||
147 | |||
148 | private UserInfo userProfile; | ||
149 | |||
150 | private UUID agentID; | ||
151 | private UUID sessionID; | ||
152 | private UUID secureSessionID; | ||
153 | |||
154 | // Login Flags | ||
155 | private string dst; | ||
156 | private string stipendSinceLogin; | ||
157 | private string gendered; | ||
158 | private string everLoggedIn; | ||
159 | private string login; | ||
160 | private uint simPort; | ||
161 | private uint simHttpPort; | ||
162 | private string simAddress; | ||
163 | private string agentAccess; | ||
164 | private string agentAccessMax; | ||
165 | private Int32 circuitCode; | ||
166 | private uint regionX; | ||
167 | private uint regionY; | ||
168 | |||
169 | // Login | ||
170 | private string firstname; | ||
171 | private string lastname; | ||
172 | |||
173 | // Web map | ||
174 | private string mapTileURL; | ||
175 | |||
176 | private string searchURL; | ||
177 | |||
178 | // Error Flags | ||
179 | private string errorReason; | ||
180 | private string errorMessage; | ||
181 | |||
182 | private string welcomeMessage; | ||
183 | private string startLocation; | ||
184 | private string allowFirstLife; | ||
185 | private string home; | ||
186 | private string seedCapability; | ||
187 | private string lookAt; | ||
188 | |||
189 | private BuddyList m_buddyList = null; | ||
190 | |||
191 | private string currency; | ||
192 | |||
193 | static LLLoginResponse() | ||
194 | { | ||
195 | // This is being set, but it's not used | ||
196 | // not sure why. | ||
197 | globalTexturesHash = new Hashtable(); | ||
198 | globalTexturesHash["sun_texture_id"] = sunTexture; | ||
199 | globalTexturesHash["cloud_texture_id"] = cloudTexture; | ||
200 | globalTexturesHash["moon_texture_id"] = moonTexture; | ||
201 | } | ||
202 | |||
203 | public LLLoginResponse() | ||
204 | { | ||
205 | loginFlags = new ArrayList(); | ||
206 | globalTextures = new ArrayList(); | ||
207 | eventCategories = new ArrayList(); | ||
208 | uiConfig = new ArrayList(); | ||
209 | classifiedCategories = new ArrayList(); | ||
210 | |||
211 | uiConfigHash = new Hashtable(); | ||
212 | |||
213 | // defaultXmlRpcResponse = new XmlRpcResponse(); | ||
214 | userProfile = new UserInfo(); | ||
215 | inventoryRoot = new ArrayList(); | ||
216 | initialOutfit = new ArrayList(); | ||
217 | agentInventory = new ArrayList(); | ||
218 | inventoryLibrary = new ArrayList(); | ||
219 | inventoryLibraryOwner = new ArrayList(); | ||
220 | activeGestures = new ArrayList(); | ||
221 | |||
222 | SetDefaultValues(); | ||
223 | } | ||
224 | |||
225 | public LLLoginResponse(UserAccount account, AgentCircuitData aCircuit, GridUserInfo pinfo, | ||
226 | GridRegion destination, List<InventoryFolderBase> invSkel, FriendInfo[] friendsList, ILibraryService libService, | ||
227 | string where, string startlocation, Vector3 position, Vector3 lookAt, List<InventoryItemBase> gestures, string message, | ||
228 | GridRegion home, IPEndPoint clientIP, string mapTileURL, string searchURL, string currency) | ||
229 | : this() | ||
230 | { | ||
231 | FillOutInventoryData(invSkel, libService); | ||
232 | |||
233 | FillOutActiveGestures(gestures); | ||
234 | |||
235 | CircuitCode = (int)aCircuit.circuitcode; | ||
236 | Lastname = account.LastName; | ||
237 | Firstname = account.FirstName; | ||
238 | AgentID = account.PrincipalID; | ||
239 | SessionID = aCircuit.SessionID; | ||
240 | SecureSessionID = aCircuit.SecureSessionID; | ||
241 | Message = message; | ||
242 | BuddList = ConvertFriendListItem(friendsList); | ||
243 | StartLocation = where; | ||
244 | MapTileURL = mapTileURL; | ||
245 | SearchURL = searchURL; | ||
246 | Currency = currency; | ||
247 | |||
248 | FillOutHomeData(pinfo, home); | ||
249 | LookAt = String.Format("[r{0},r{1},r{2}]", lookAt.X, lookAt.Y, lookAt.Z); | ||
250 | |||
251 | FillOutRegionData(destination); | ||
252 | |||
253 | FillOutSeedCap(aCircuit, destination, clientIP); | ||
254 | |||
255 | } | ||
256 | |||
257 | private void FillOutInventoryData(List<InventoryFolderBase> invSkel, ILibraryService libService) | ||
258 | { | ||
259 | InventoryData inventData = null; | ||
260 | |||
261 | try | ||
262 | { | ||
263 | inventData = GetInventorySkeleton(invSkel); | ||
264 | } | ||
265 | catch (Exception e) | ||
266 | { | ||
267 | m_log.WarnFormat( | ||
268 | "[LLLOGIN SERVICE]: Error processing inventory skeleton of agent {0} - {1}", | ||
269 | agentID, e); | ||
270 | |||
271 | // ignore and continue | ||
272 | } | ||
273 | |||
274 | if (inventData != null) | ||
275 | { | ||
276 | ArrayList AgentInventoryArray = inventData.InventoryArray; | ||
277 | |||
278 | Hashtable InventoryRootHash = new Hashtable(); | ||
279 | InventoryRootHash["folder_id"] = inventData.RootFolderID.ToString(); | ||
280 | InventoryRoot = new ArrayList(); | ||
281 | InventoryRoot.Add(InventoryRootHash); | ||
282 | InventorySkeleton = AgentInventoryArray; | ||
283 | } | ||
284 | |||
285 | // Inventory Library Section | ||
286 | if (libService != null && libService.LibraryRootFolder != null) | ||
287 | { | ||
288 | Hashtable InventoryLibRootHash = new Hashtable(); | ||
289 | InventoryLibRootHash["folder_id"] = "00000112-000f-0000-0000-000100bba000"; | ||
290 | InventoryLibRoot = new ArrayList(); | ||
291 | InventoryLibRoot.Add(InventoryLibRootHash); | ||
292 | |||
293 | InventoryLibraryOwner = GetLibraryOwner(libService.LibraryRootFolder); | ||
294 | InventoryLibrary = GetInventoryLibrary(libService); | ||
295 | } | ||
296 | } | ||
297 | |||
298 | private void FillOutActiveGestures(List<InventoryItemBase> gestures) | ||
299 | { | ||
300 | ArrayList list = new ArrayList(); | ||
301 | if (gestures != null) | ||
302 | { | ||
303 | foreach (InventoryItemBase gesture in gestures) | ||
304 | { | ||
305 | Hashtable item = new Hashtable(); | ||
306 | item["item_id"] = gesture.ID.ToString(); | ||
307 | item["asset_id"] = gesture.AssetID.ToString(); | ||
308 | list.Add(item); | ||
309 | } | ||
310 | } | ||
311 | ActiveGestures = list; | ||
312 | } | ||
313 | |||
314 | private void FillOutHomeData(GridUserInfo pinfo, GridRegion home) | ||
315 | { | ||
316 | int x = 1000 * (int)Constants.RegionSize, y = 1000 * (int)Constants.RegionSize; | ||
317 | if (home != null) | ||
318 | { | ||
319 | x = home.RegionLocX; | ||
320 | y = home.RegionLocY; | ||
321 | } | ||
322 | |||
323 | Home = string.Format( | ||
324 | "{{'region_handle':[r{0},r{1}], 'position':[r{2},r{3},r{4}], 'look_at':[r{5},r{6},r{7}]}}", | ||
325 | x, | ||
326 | y, | ||
327 | pinfo.HomePosition.X, pinfo.HomePosition.Y, pinfo.HomePosition.Z, | ||
328 | pinfo.HomeLookAt.X, pinfo.HomeLookAt.Y, pinfo.HomeLookAt.Z); | ||
329 | |||
330 | } | ||
331 | |||
332 | private void FillOutRegionData(GridRegion destination) | ||
333 | { | ||
334 | IPEndPoint endPoint = destination.ExternalEndPoint; | ||
335 | if (endPoint == null) return; | ||
336 | SimAddress = endPoint.Address.ToString(); | ||
337 | SimPort = (uint)endPoint.Port; | ||
338 | RegionX = (uint)destination.RegionLocX; | ||
339 | RegionY = (uint)destination.RegionLocY; | ||
340 | } | ||
341 | |||
342 | private void FillOutSeedCap(AgentCircuitData aCircuit, GridRegion destination, IPEndPoint ipepClient) | ||
343 | { | ||
344 | SeedCapability = destination.ServerURI + CapsUtil.GetCapsSeedPath(aCircuit.CapsPath); | ||
345 | } | ||
346 | |||
347 | private void SetDefaultValues() | ||
348 | { | ||
349 | DST = TimeZone.CurrentTimeZone.IsDaylightSavingTime(DateTime.Now) ? "Y" : "N"; | ||
350 | StipendSinceLogin = "N"; | ||
351 | Gendered = "Y"; | ||
352 | EverLoggedIn = "Y"; | ||
353 | login = "false"; | ||
354 | firstname = "Test"; | ||
355 | lastname = "User"; | ||
356 | agentAccess = "M"; | ||
357 | agentAccessMax = "A"; | ||
358 | startLocation = "last"; | ||
359 | allowFirstLife = "Y"; | ||
360 | |||
361 | ErrorMessage = "You have entered an invalid name/password combination. Check Caps/lock."; | ||
362 | ErrorReason = "key"; | ||
363 | welcomeMessage = "Welcome to OpenSim!"; | ||
364 | seedCapability = String.Empty; | ||
365 | home = "{'region_handle':[r" + (1000*Constants.RegionSize).ToString() + ",r" + (1000*Constants.RegionSize).ToString() + "], 'position':[r" + | ||
366 | userProfile.homepos.X.ToString() + ",r" + userProfile.homepos.Y.ToString() + ",r" + | ||
367 | userProfile.homepos.Z.ToString() + "], 'look_at':[r" + userProfile.homelookat.X.ToString() + ",r" + | ||
368 | userProfile.homelookat.Y.ToString() + ",r" + userProfile.homelookat.Z.ToString() + "]}"; | ||
369 | lookAt = "[r0.99949799999999999756,r0.03166859999999999814,r0]"; | ||
370 | RegionX = (uint) 255232; | ||
371 | RegionY = (uint) 254976; | ||
372 | |||
373 | // Classifieds; | ||
374 | AddClassifiedCategory((Int32) 1, "Shopping"); | ||
375 | AddClassifiedCategory((Int32) 2, "Land Rental"); | ||
376 | AddClassifiedCategory((Int32) 3, "Property Rental"); | ||
377 | AddClassifiedCategory((Int32) 4, "Special Attraction"); | ||
378 | AddClassifiedCategory((Int32) 5, "New Products"); | ||
379 | AddClassifiedCategory((Int32) 6, "Employment"); | ||
380 | AddClassifiedCategory((Int32) 7, "Wanted"); | ||
381 | AddClassifiedCategory((Int32) 8, "Service"); | ||
382 | AddClassifiedCategory((Int32) 9, "Personal"); | ||
383 | |||
384 | SessionID = UUID.Random(); | ||
385 | SecureSessionID = UUID.Random(); | ||
386 | AgentID = UUID.Random(); | ||
387 | |||
388 | Hashtable InitialOutfitHash = new Hashtable(); | ||
389 | InitialOutfitHash["folder_name"] = "Nightclub Female"; | ||
390 | InitialOutfitHash["gender"] = "female"; | ||
391 | initialOutfit.Add(InitialOutfitHash); | ||
392 | mapTileURL = String.Empty; | ||
393 | searchURL = String.Empty; | ||
394 | |||
395 | currency = String.Empty; | ||
396 | } | ||
397 | |||
398 | |||
399 | public override Hashtable ToHashtable() | ||
400 | { | ||
401 | try | ||
402 | { | ||
403 | Hashtable responseData = new Hashtable(); | ||
404 | |||
405 | loginFlagsHash = new Hashtable(); | ||
406 | loginFlagsHash["daylight_savings"] = DST; | ||
407 | loginFlagsHash["stipend_since_login"] = StipendSinceLogin; | ||
408 | loginFlagsHash["gendered"] = Gendered; | ||
409 | loginFlagsHash["ever_logged_in"] = EverLoggedIn; | ||
410 | loginFlags.Add(loginFlagsHash); | ||
411 | |||
412 | responseData["first_name"] = Firstname; | ||
413 | responseData["last_name"] = Lastname; | ||
414 | responseData["agent_access"] = agentAccess; | ||
415 | responseData["agent_access_max"] = agentAccessMax; | ||
416 | |||
417 | globalTextures.Add(globalTexturesHash); | ||
418 | // this.eventCategories.Add(this.eventCategoriesHash); | ||
419 | |||
420 | AddToUIConfig("allow_first_life", allowFirstLife); | ||
421 | uiConfig.Add(uiConfigHash); | ||
422 | |||
423 | responseData["sim_port"] = (Int32) SimPort; | ||
424 | responseData["sim_ip"] = SimAddress; | ||
425 | responseData["http_port"] = (Int32)SimHttpPort; | ||
426 | |||
427 | responseData["agent_id"] = AgentID.ToString(); | ||
428 | responseData["session_id"] = SessionID.ToString(); | ||
429 | responseData["secure_session_id"] = SecureSessionID.ToString(); | ||
430 | responseData["circuit_code"] = CircuitCode; | ||
431 | responseData["seconds_since_epoch"] = (Int32) (DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds; | ||
432 | responseData["login-flags"] = loginFlags; | ||
433 | responseData["global-textures"] = globalTextures; | ||
434 | responseData["seed_capability"] = seedCapability; | ||
435 | |||
436 | responseData["event_categories"] = eventCategories; | ||
437 | responseData["event_notifications"] = new ArrayList(); // todo | ||
438 | responseData["classified_categories"] = classifiedCategories; | ||
439 | responseData["ui-config"] = uiConfig; | ||
440 | |||
441 | if (agentInventory != null) | ||
442 | { | ||
443 | responseData["inventory-skeleton"] = agentInventory; | ||
444 | responseData["inventory-root"] = inventoryRoot; | ||
445 | } | ||
446 | responseData["inventory-skel-lib"] = inventoryLibrary; | ||
447 | responseData["inventory-lib-root"] = inventoryLibRoot; | ||
448 | responseData["gestures"] = activeGestures; | ||
449 | responseData["inventory-lib-owner"] = inventoryLibraryOwner; | ||
450 | responseData["initial-outfit"] = initialOutfit; | ||
451 | responseData["start_location"] = startLocation; | ||
452 | responseData["seed_capability"] = seedCapability; | ||
453 | responseData["home"] = home; | ||
454 | responseData["look_at"] = lookAt; | ||
455 | responseData["message"] = welcomeMessage; | ||
456 | responseData["region_x"] = (Int32)(RegionX); | ||
457 | responseData["region_y"] = (Int32)(RegionY); | ||
458 | |||
459 | if (searchURL != String.Empty) | ||
460 | responseData["search"] = searchURL; | ||
461 | |||
462 | if (mapTileURL != String.Empty) | ||
463 | responseData["map-server-url"] = mapTileURL; | ||
464 | |||
465 | if (m_buddyList != null) | ||
466 | { | ||
467 | responseData["buddy-list"] = m_buddyList.ToArray(); | ||
468 | } | ||
469 | |||
470 | if (currency != String.Empty) | ||
471 | { | ||
472 | // responseData["real_currency"] = currency; | ||
473 | responseData["currency"] = currency; | ||
474 | } | ||
475 | |||
476 | responseData["login"] = "true"; | ||
477 | |||
478 | return responseData; | ||
479 | } | ||
480 | catch (Exception e) | ||
481 | { | ||
482 | m_log.Warn("[CLIENT]: LoginResponse: Error creating Hashtable Response: " + e.Message); | ||
483 | |||
484 | return LLFailedLoginResponse.InternalError.ToHashtable(); | ||
485 | } | ||
486 | } | ||
487 | |||
488 | public override OSD ToOSDMap() | ||
489 | { | ||
490 | try | ||
491 | { | ||
492 | OSDMap map = new OSDMap(); | ||
493 | |||
494 | map["first_name"] = OSD.FromString(Firstname); | ||
495 | map["last_name"] = OSD.FromString(Lastname); | ||
496 | map["agent_access"] = OSD.FromString(agentAccess); | ||
497 | map["agent_access_max"] = OSD.FromString(agentAccessMax); | ||
498 | |||
499 | map["sim_port"] = OSD.FromInteger(SimPort); | ||
500 | map["sim_ip"] = OSD.FromString(SimAddress); | ||
501 | |||
502 | map["agent_id"] = OSD.FromUUID(AgentID); | ||
503 | map["session_id"] = OSD.FromUUID(SessionID); | ||
504 | map["secure_session_id"] = OSD.FromUUID(SecureSessionID); | ||
505 | map["circuit_code"] = OSD.FromInteger(CircuitCode); | ||
506 | map["seconds_since_epoch"] = OSD.FromInteger((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds); | ||
507 | |||
508 | #region Login Flags | ||
509 | |||
510 | OSDMap loginFlagsLLSD = new OSDMap(); | ||
511 | loginFlagsLLSD["daylight_savings"] = OSD.FromString(DST); | ||
512 | loginFlagsLLSD["stipend_since_login"] = OSD.FromString(StipendSinceLogin); | ||
513 | loginFlagsLLSD["gendered"] = OSD.FromString(Gendered); | ||
514 | loginFlagsLLSD["ever_logged_in"] = OSD.FromString(EverLoggedIn); | ||
515 | map["login-flags"] = WrapOSDMap(loginFlagsLLSD); | ||
516 | |||
517 | #endregion Login Flags | ||
518 | |||
519 | #region Global Textures | ||
520 | |||
521 | OSDMap globalTexturesLLSD = new OSDMap(); | ||
522 | globalTexturesLLSD["sun_texture_id"] = OSD.FromString(SunTexture); | ||
523 | globalTexturesLLSD["cloud_texture_id"] = OSD.FromString(CloudTexture); | ||
524 | globalTexturesLLSD["moon_texture_id"] = OSD.FromString(MoonTexture); | ||
525 | |||
526 | map["global-textures"] = WrapOSDMap(globalTexturesLLSD); | ||
527 | |||
528 | #endregion Global Textures | ||
529 | |||
530 | map["seed_capability"] = OSD.FromString(seedCapability); | ||
531 | |||
532 | map["event_categories"] = ArrayListToOSDArray(eventCategories); | ||
533 | //map["event_notifications"] = new OSDArray(); // todo | ||
534 | map["classified_categories"] = ArrayListToOSDArray(classifiedCategories); | ||
535 | |||
536 | #region UI Config | ||
537 | |||
538 | OSDMap uiConfigLLSD = new OSDMap(); | ||
539 | uiConfigLLSD["allow_first_life"] = OSD.FromString(allowFirstLife); | ||
540 | map["ui-config"] = WrapOSDMap(uiConfigLLSD); | ||
541 | |||
542 | #endregion UI Config | ||
543 | |||
544 | #region Inventory | ||
545 | |||
546 | map["inventory-skeleton"] = ArrayListToOSDArray(agentInventory); | ||
547 | |||
548 | map["inventory-skel-lib"] = ArrayListToOSDArray(inventoryLibrary); | ||
549 | map["inventory-root"] = ArrayListToOSDArray(inventoryRoot); ; | ||
550 | map["inventory-lib-root"] = ArrayListToOSDArray(inventoryLibRoot); | ||
551 | map["inventory-lib-owner"] = ArrayListToOSDArray(inventoryLibraryOwner); | ||
552 | |||
553 | #endregion Inventory | ||
554 | |||
555 | map["gestures"] = ArrayListToOSDArray(activeGestures); | ||
556 | |||
557 | map["initial-outfit"] = ArrayListToOSDArray(initialOutfit); | ||
558 | map["start_location"] = OSD.FromString(startLocation); | ||
559 | |||
560 | map["seed_capability"] = OSD.FromString(seedCapability); | ||
561 | map["home"] = OSD.FromString(home); | ||
562 | map["look_at"] = OSD.FromString(lookAt); | ||
563 | map["message"] = OSD.FromString(welcomeMessage); | ||
564 | map["region_x"] = OSD.FromInteger(RegionX); | ||
565 | map["region_y"] = OSD.FromInteger(RegionY); | ||
566 | |||
567 | if (mapTileURL != String.Empty) | ||
568 | map["map-server-url"] = OSD.FromString(mapTileURL); | ||
569 | |||
570 | if (searchURL != String.Empty) | ||
571 | map["search"] = OSD.FromString(searchURL); | ||
572 | |||
573 | if (m_buddyList != null) | ||
574 | { | ||
575 | map["buddy-list"] = ArrayListToOSDArray(m_buddyList.ToArray()); | ||
576 | } | ||
577 | |||
578 | map["login"] = OSD.FromString("true"); | ||
579 | |||
580 | return map; | ||
581 | } | ||
582 | catch (Exception e) | ||
583 | { | ||
584 | m_log.Warn("[CLIENT]: LoginResponse: Error creating LLSD Response: " + e.Message); | ||
585 | |||
586 | return LLFailedLoginResponse.InternalError.ToOSDMap(); | ||
587 | } | ||
588 | } | ||
589 | |||
590 | public OSDArray ArrayListToOSDArray(ArrayList arrlst) | ||
591 | { | ||
592 | OSDArray llsdBack = new OSDArray(); | ||
593 | foreach (Hashtable ht in arrlst) | ||
594 | { | ||
595 | OSDMap mp = new OSDMap(); | ||
596 | foreach (DictionaryEntry deHt in ht) | ||
597 | { | ||
598 | mp.Add((string)deHt.Key, OSDString.FromObject(deHt.Value)); | ||
599 | } | ||
600 | llsdBack.Add(mp); | ||
601 | } | ||
602 | return llsdBack; | ||
603 | } | ||
604 | |||
605 | private static OSDArray WrapOSDMap(OSDMap wrapMe) | ||
606 | { | ||
607 | OSDArray array = new OSDArray(); | ||
608 | array.Add(wrapMe); | ||
609 | return array; | ||
610 | } | ||
611 | |||
612 | public void SetEventCategories(string category, string value) | ||
613 | { | ||
614 | // this.eventCategoriesHash[category] = value; | ||
615 | //TODO | ||
616 | } | ||
617 | |||
618 | public void AddToUIConfig(string itemName, string item) | ||
619 | { | ||
620 | uiConfigHash[itemName] = item; | ||
621 | } | ||
622 | |||
623 | public void AddClassifiedCategory(Int32 ID, string categoryName) | ||
624 | { | ||
625 | Hashtable hash = new Hashtable(); | ||
626 | hash["category_name"] = categoryName; | ||
627 | hash["category_id"] = ID; | ||
628 | classifiedCategories.Add(hash); | ||
629 | // this.classifiedCategoriesHash.Clear(); | ||
630 | } | ||
631 | |||
632 | |||
633 | private static LLLoginResponse.BuddyList ConvertFriendListItem(FriendInfo[] friendsList) | ||
634 | { | ||
635 | LLLoginResponse.BuddyList buddylistreturn = new LLLoginResponse.BuddyList(); | ||
636 | foreach (FriendInfo finfo in friendsList) | ||
637 | { | ||
638 | if (finfo.TheirFlags == -1) | ||
639 | continue; | ||
640 | LLLoginResponse.BuddyList.BuddyInfo buddyitem = new LLLoginResponse.BuddyList.BuddyInfo(finfo.Friend); | ||
641 | // finfo.Friend may not be a simple uuid | ||
642 | UUID friendID = UUID.Zero; | ||
643 | if (UUID.TryParse(finfo.Friend, out friendID)) | ||
644 | buddyitem.BuddyID = finfo.Friend; | ||
645 | else | ||
646 | { | ||
647 | string tmp; | ||
648 | if (Util.ParseUniversalUserIdentifier(finfo.Friend, out friendID, out tmp, out tmp, out tmp, out tmp)) | ||
649 | buddyitem.BuddyID = friendID.ToString(); | ||
650 | else | ||
651 | // junk entry | ||
652 | continue; | ||
653 | } | ||
654 | buddyitem.BuddyRightsHave = (int)finfo.TheirFlags; | ||
655 | buddyitem.BuddyRightsGiven = (int)finfo.MyFlags; | ||
656 | buddylistreturn.AddNewBuddy(buddyitem); | ||
657 | } | ||
658 | return buddylistreturn; | ||
659 | } | ||
660 | |||
661 | private InventoryData GetInventorySkeleton(List<InventoryFolderBase> folders) | ||
662 | { | ||
663 | UUID rootID = UUID.Zero; | ||
664 | ArrayList AgentInventoryArray = new ArrayList(); | ||
665 | Hashtable TempHash; | ||
666 | foreach (InventoryFolderBase InvFolder in folders) | ||
667 | { | ||
668 | if (InvFolder.ParentID == UUID.Zero && InvFolder.Name == "My Inventory") | ||
669 | { | ||
670 | rootID = InvFolder.ID; | ||
671 | } | ||
672 | TempHash = new Hashtable(); | ||
673 | TempHash["name"] = InvFolder.Name; | ||
674 | TempHash["parent_id"] = InvFolder.ParentID.ToString(); | ||
675 | TempHash["version"] = (Int32)InvFolder.Version; | ||
676 | TempHash["type_default"] = (Int32)InvFolder.Type; | ||
677 | TempHash["folder_id"] = InvFolder.ID.ToString(); | ||
678 | AgentInventoryArray.Add(TempHash); | ||
679 | } | ||
680 | |||
681 | return new InventoryData(AgentInventoryArray, rootID); | ||
682 | |||
683 | } | ||
684 | |||
685 | /// <summary> | ||
686 | /// Converts the inventory library skeleton into the form required by the rpc request. | ||
687 | /// </summary> | ||
688 | /// <returns></returns> | ||
689 | protected virtual ArrayList GetInventoryLibrary(ILibraryService library) | ||
690 | { | ||
691 | Dictionary<UUID, InventoryFolderImpl> rootFolders = library.GetAllFolders(); | ||
692 | // m_log.DebugFormat("[LLOGIN]: Library has {0} folders", rootFolders.Count); | ||
693 | //Dictionary<UUID, InventoryFolderImpl> rootFolders = new Dictionary<UUID,InventoryFolderImpl>(); | ||
694 | ArrayList folderHashes = new ArrayList(); | ||
695 | |||
696 | foreach (InventoryFolderBase folder in rootFolders.Values) | ||
697 | { | ||
698 | Hashtable TempHash = new Hashtable(); | ||
699 | TempHash["name"] = folder.Name; | ||
700 | TempHash["parent_id"] = folder.ParentID.ToString(); | ||
701 | TempHash["version"] = (Int32)folder.Version; | ||
702 | TempHash["type_default"] = (Int32)folder.Type; | ||
703 | TempHash["folder_id"] = folder.ID.ToString(); | ||
704 | folderHashes.Add(TempHash); | ||
705 | } | ||
706 | |||
707 | return folderHashes; | ||
708 | } | ||
709 | |||
710 | /// <summary> | ||
711 | /// | ||
712 | /// </summary> | ||
713 | /// <returns></returns> | ||
714 | protected virtual ArrayList GetLibraryOwner(InventoryFolderImpl libFolder) | ||
715 | { | ||
716 | //for now create random inventory library owner | ||
717 | Hashtable TempHash = new Hashtable(); | ||
718 | TempHash["agent_id"] = "11111111-1111-0000-0000-000100bba000"; // libFolder.Owner | ||
719 | ArrayList inventoryLibOwner = new ArrayList(); | ||
720 | inventoryLibOwner.Add(TempHash); | ||
721 | return inventoryLibOwner; | ||
722 | } | ||
723 | |||
724 | public class InventoryData | ||
725 | { | ||
726 | public ArrayList InventoryArray = null; | ||
727 | public UUID RootFolderID = UUID.Zero; | ||
728 | |||
729 | public InventoryData(ArrayList invList, UUID rootID) | ||
730 | { | ||
731 | InventoryArray = invList; | ||
732 | RootFolderID = rootID; | ||
733 | } | ||
734 | } | ||
735 | |||
736 | #region Properties | ||
737 | |||
738 | public string Login | ||
739 | { | ||
740 | get { return login; } | ||
741 | set { login = value; } | ||
742 | } | ||
743 | |||
744 | public string DST | ||
745 | { | ||
746 | get { return dst; } | ||
747 | set { dst = value; } | ||
748 | } | ||
749 | |||
750 | public string StipendSinceLogin | ||
751 | { | ||
752 | get { return stipendSinceLogin; } | ||
753 | set { stipendSinceLogin = value; } | ||
754 | } | ||
755 | |||
756 | public string Gendered | ||
757 | { | ||
758 | get { return gendered; } | ||
759 | set { gendered = value; } | ||
760 | } | ||
761 | |||
762 | public string EverLoggedIn | ||
763 | { | ||
764 | get { return everLoggedIn; } | ||
765 | set { everLoggedIn = value; } | ||
766 | } | ||
767 | |||
768 | public uint SimPort | ||
769 | { | ||
770 | get { return simPort; } | ||
771 | set { simPort = value; } | ||
772 | } | ||
773 | |||
774 | public uint SimHttpPort | ||
775 | { | ||
776 | get { return simHttpPort; } | ||
777 | set { simHttpPort = value; } | ||
778 | } | ||
779 | |||
780 | public string SimAddress | ||
781 | { | ||
782 | get { return simAddress; } | ||
783 | set { simAddress = value; } | ||
784 | } | ||
785 | |||
786 | public UUID AgentID | ||
787 | { | ||
788 | get { return agentID; } | ||
789 | set { agentID = value; } | ||
790 | } | ||
791 | |||
792 | public UUID SessionID | ||
793 | { | ||
794 | get { return sessionID; } | ||
795 | set { sessionID = value; } | ||
796 | } | ||
797 | |||
798 | public UUID SecureSessionID | ||
799 | { | ||
800 | get { return secureSessionID; } | ||
801 | set { secureSessionID = value; } | ||
802 | } | ||
803 | |||
804 | public Int32 CircuitCode | ||
805 | { | ||
806 | get { return circuitCode; } | ||
807 | set { circuitCode = value; } | ||
808 | } | ||
809 | |||
810 | public uint RegionX | ||
811 | { | ||
812 | get { return regionX; } | ||
813 | set { regionX = value; } | ||
814 | } | ||
815 | |||
816 | public uint RegionY | ||
817 | { | ||
818 | get { return regionY; } | ||
819 | set { regionY = value; } | ||
820 | } | ||
821 | |||
822 | public string SunTexture | ||
823 | { | ||
824 | get { return sunTexture; } | ||
825 | set { sunTexture = value; } | ||
826 | } | ||
827 | |||
828 | public string CloudTexture | ||
829 | { | ||
830 | get { return cloudTexture; } | ||
831 | set { cloudTexture = value; } | ||
832 | } | ||
833 | |||
834 | public string MoonTexture | ||
835 | { | ||
836 | get { return moonTexture; } | ||
837 | set { moonTexture = value; } | ||
838 | } | ||
839 | |||
840 | public string Firstname | ||
841 | { | ||
842 | get { return firstname; } | ||
843 | set { firstname = value; } | ||
844 | } | ||
845 | |||
846 | public string Lastname | ||
847 | { | ||
848 | get { return lastname; } | ||
849 | set { lastname = value; } | ||
850 | } | ||
851 | |||
852 | public string AgentAccess | ||
853 | { | ||
854 | get { return agentAccess; } | ||
855 | set { agentAccess = value; } | ||
856 | } | ||
857 | |||
858 | public string AgentAccessMax | ||
859 | { | ||
860 | get { return agentAccessMax; } | ||
861 | set { agentAccessMax = value; } | ||
862 | } | ||
863 | |||
864 | public string StartLocation | ||
865 | { | ||
866 | get { return startLocation; } | ||
867 | set { startLocation = value; } | ||
868 | } | ||
869 | |||
870 | public string LookAt | ||
871 | { | ||
872 | get { return lookAt; } | ||
873 | set { lookAt = value; } | ||
874 | } | ||
875 | |||
876 | public string SeedCapability | ||
877 | { | ||
878 | get { return seedCapability; } | ||
879 | set { seedCapability = value; } | ||
880 | } | ||
881 | |||
882 | public string ErrorReason | ||
883 | { | ||
884 | get { return errorReason; } | ||
885 | set { errorReason = value; } | ||
886 | } | ||
887 | |||
888 | public string ErrorMessage | ||
889 | { | ||
890 | get { return errorMessage; } | ||
891 | set { errorMessage = value; } | ||
892 | } | ||
893 | |||
894 | public ArrayList InventoryRoot | ||
895 | { | ||
896 | get { return inventoryRoot; } | ||
897 | set { inventoryRoot = value; } | ||
898 | } | ||
899 | |||
900 | public ArrayList InventorySkeleton | ||
901 | { | ||
902 | get { return agentInventory; } | ||
903 | set { agentInventory = value; } | ||
904 | } | ||
905 | |||
906 | public ArrayList InventoryLibrary | ||
907 | { | ||
908 | get { return inventoryLibrary; } | ||
909 | set { inventoryLibrary = value; } | ||
910 | } | ||
911 | |||
912 | public ArrayList InventoryLibraryOwner | ||
913 | { | ||
914 | get { return inventoryLibraryOwner; } | ||
915 | set { inventoryLibraryOwner = value; } | ||
916 | } | ||
917 | |||
918 | public ArrayList InventoryLibRoot | ||
919 | { | ||
920 | get { return inventoryLibRoot; } | ||
921 | set { inventoryLibRoot = value; } | ||
922 | } | ||
923 | |||
924 | public ArrayList ActiveGestures | ||
925 | { | ||
926 | get { return activeGestures; } | ||
927 | set { activeGestures = value; } | ||
928 | } | ||
929 | |||
930 | public string Home | ||
931 | { | ||
932 | get { return home; } | ||
933 | set { home = value; } | ||
934 | } | ||
935 | |||
936 | public string MapTileURL | ||
937 | { | ||
938 | get { return mapTileURL; } | ||
939 | set { mapTileURL = value; } | ||
940 | } | ||
941 | |||
942 | public string SearchURL | ||
943 | { | ||
944 | get { return searchURL; } | ||
945 | set { searchURL = value; } | ||
946 | } | ||
947 | |||
948 | public string Message | ||
949 | { | ||
950 | get { return welcomeMessage; } | ||
951 | set { welcomeMessage = value; } | ||
952 | } | ||
953 | |||
954 | public BuddyList BuddList | ||
955 | { | ||
956 | get { return m_buddyList; } | ||
957 | set { m_buddyList = value; } | ||
958 | } | ||
959 | |||
960 | public string Currency | ||
961 | { | ||
962 | get { return currency; } | ||
963 | set { currency = value; } | ||
964 | } | ||
965 | |||
966 | #endregion | ||
967 | |||
968 | public class UserInfo | ||
969 | { | ||
970 | public string firstname; | ||
971 | public string lastname; | ||
972 | public ulong homeregionhandle; | ||
973 | public Vector3 homepos; | ||
974 | public Vector3 homelookat; | ||
975 | } | ||
976 | |||
977 | public class BuddyList | ||
978 | { | ||
979 | public List<BuddyInfo> Buddies = new List<BuddyInfo>(); | ||
980 | |||
981 | public void AddNewBuddy(BuddyInfo buddy) | ||
982 | { | ||
983 | if (!Buddies.Contains(buddy)) | ||
984 | { | ||
985 | Buddies.Add(buddy); | ||
986 | } | ||
987 | } | ||
988 | |||
989 | public ArrayList ToArray() | ||
990 | { | ||
991 | ArrayList buddyArray = new ArrayList(); | ||
992 | foreach (BuddyInfo buddy in Buddies) | ||
993 | { | ||
994 | buddyArray.Add(buddy.ToHashTable()); | ||
995 | } | ||
996 | return buddyArray; | ||
997 | } | ||
998 | |||
999 | public class BuddyInfo | ||
1000 | { | ||
1001 | public int BuddyRightsHave = 1; | ||
1002 | public int BuddyRightsGiven = 1; | ||
1003 | public string BuddyID; | ||
1004 | |||
1005 | public BuddyInfo(string buddyID) | ||
1006 | { | ||
1007 | BuddyID = buddyID; | ||
1008 | } | ||
1009 | |||
1010 | public BuddyInfo(UUID buddyID) | ||
1011 | { | ||
1012 | BuddyID = buddyID.ToString(); | ||
1013 | } | ||
1014 | |||
1015 | public Hashtable ToHashTable() | ||
1016 | { | ||
1017 | Hashtable hTable = new Hashtable(); | ||
1018 | hTable["buddy_rights_has"] = BuddyRightsHave; | ||
1019 | hTable["buddy_rights_given"] = BuddyRightsGiven; | ||
1020 | hTable["buddy_id"] = BuddyID; | ||
1021 | return hTable; | ||
1022 | } | ||
1023 | } | ||
1024 | } | ||
1025 | } | ||
1026 | } | ||
diff --git a/OpenSim/Services/LLLoginService/LLLoginService.cs b/OpenSim/Services/LLLoginService/LLLoginService.cs new file mode 100644 index 0000000..035980d --- /dev/null +++ b/OpenSim/Services/LLLoginService/LLLoginService.cs | |||
@@ -0,0 +1,938 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections; | ||
30 | using System.Collections.Generic; | ||
31 | using System.Linq; | ||
32 | using System.Net; | ||
33 | using System.Reflection; | ||
34 | using System.Text.RegularExpressions; | ||
35 | |||
36 | using log4net; | ||
37 | using Nini.Config; | ||
38 | using OpenMetaverse; | ||
39 | |||
40 | using OpenSim.Framework; | ||
41 | using OpenSim.Framework.Console; | ||
42 | using OpenSim.Server.Base; | ||
43 | using OpenSim.Services.Interfaces; | ||
44 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
45 | using FriendInfo = OpenSim.Services.Interfaces.FriendInfo; | ||
46 | using OpenSim.Services.Connectors.Hypergrid; | ||
47 | |||
48 | namespace OpenSim.Services.LLLoginService | ||
49 | { | ||
50 | public class LLLoginService : ILoginService | ||
51 | { | ||
52 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
53 | private static bool Initialized = false; | ||
54 | |||
55 | protected IUserAccountService m_UserAccountService; | ||
56 | protected IGridUserService m_GridUserService; | ||
57 | protected IAuthenticationService m_AuthenticationService; | ||
58 | protected IInventoryService m_InventoryService; | ||
59 | protected IGridService m_GridService; | ||
60 | protected IPresenceService m_PresenceService; | ||
61 | protected ISimulationService m_LocalSimulationService; | ||
62 | protected ISimulationService m_RemoteSimulationService; | ||
63 | protected ILibraryService m_LibraryService; | ||
64 | protected IFriendsService m_FriendsService; | ||
65 | protected IAvatarService m_AvatarService; | ||
66 | protected IUserAgentService m_UserAgentService; | ||
67 | |||
68 | protected GatekeeperServiceConnector m_GatekeeperConnector; | ||
69 | |||
70 | protected string m_DefaultRegionName; | ||
71 | protected string m_WelcomeMessage; | ||
72 | protected bool m_RequireInventory; | ||
73 | protected int m_MinLoginLevel; | ||
74 | protected string m_GatekeeperURL; | ||
75 | protected bool m_AllowRemoteSetLoginLevel; | ||
76 | protected string m_MapTileURL; | ||
77 | protected string m_SearchURL; | ||
78 | protected string m_Currency; | ||
79 | |||
80 | protected string m_AllowedClients; | ||
81 | protected string m_DeniedClients; | ||
82 | |||
83 | IConfig m_LoginServerConfig; | ||
84 | // IConfig m_ClientsConfig; | ||
85 | |||
86 | public LLLoginService(IConfigSource config, ISimulationService simService, ILibraryService libraryService) | ||
87 | { | ||
88 | m_LoginServerConfig = config.Configs["LoginService"]; | ||
89 | if (m_LoginServerConfig == null) | ||
90 | throw new Exception(String.Format("No section LoginService in config file")); | ||
91 | |||
92 | string accountService = m_LoginServerConfig.GetString("UserAccountService", String.Empty); | ||
93 | string gridUserService = m_LoginServerConfig.GetString("GridUserService", String.Empty); | ||
94 | string agentService = m_LoginServerConfig.GetString("UserAgentService", String.Empty); | ||
95 | string authService = m_LoginServerConfig.GetString("AuthenticationService", String.Empty); | ||
96 | string invService = m_LoginServerConfig.GetString("InventoryService", String.Empty); | ||
97 | string gridService = m_LoginServerConfig.GetString("GridService", String.Empty); | ||
98 | string presenceService = m_LoginServerConfig.GetString("PresenceService", String.Empty); | ||
99 | string libService = m_LoginServerConfig.GetString("LibraryService", String.Empty); | ||
100 | string friendsService = m_LoginServerConfig.GetString("FriendsService", String.Empty); | ||
101 | string avatarService = m_LoginServerConfig.GetString("AvatarService", String.Empty); | ||
102 | string simulationService = m_LoginServerConfig.GetString("SimulationService", String.Empty); | ||
103 | |||
104 | m_DefaultRegionName = m_LoginServerConfig.GetString("DefaultRegion", String.Empty); | ||
105 | m_WelcomeMessage = m_LoginServerConfig.GetString("WelcomeMessage", "Welcome to OpenSim!"); | ||
106 | m_RequireInventory = m_LoginServerConfig.GetBoolean("RequireInventory", true); | ||
107 | m_AllowRemoteSetLoginLevel = m_LoginServerConfig.GetBoolean("AllowRemoteSetLoginLevel", false); | ||
108 | m_MinLoginLevel = m_LoginServerConfig.GetInt("MinLoginLevel", 0); | ||
109 | m_GatekeeperURL = m_LoginServerConfig.GetString("GatekeeperURI", string.Empty); | ||
110 | m_MapTileURL = m_LoginServerConfig.GetString("MapTileURL", string.Empty); | ||
111 | m_SearchURL = m_LoginServerConfig.GetString("SearchURL", string.Empty); | ||
112 | m_Currency = m_LoginServerConfig.GetString("Currency", string.Empty); | ||
113 | |||
114 | m_AllowedClients = m_LoginServerConfig.GetString("AllowedClients", string.Empty); | ||
115 | m_DeniedClients = m_LoginServerConfig.GetString("DeniedClients", string.Empty); | ||
116 | |||
117 | // Clean up some of these vars | ||
118 | if (m_MapTileURL != String.Empty) | ||
119 | { | ||
120 | m_MapTileURL = m_MapTileURL.Trim(); | ||
121 | if (!m_MapTileURL.EndsWith("/")) | ||
122 | m_MapTileURL = m_MapTileURL + "/"; | ||
123 | } | ||
124 | |||
125 | // These are required; the others aren't | ||
126 | if (accountService == string.Empty || authService == string.Empty) | ||
127 | throw new Exception("LoginService is missing service specifications"); | ||
128 | |||
129 | // replace newlines in welcome message | ||
130 | m_WelcomeMessage = m_WelcomeMessage.Replace("\\n", "\n"); | ||
131 | |||
132 | Object[] args = new Object[] { config }; | ||
133 | m_UserAccountService = ServerUtils.LoadPlugin<IUserAccountService>(accountService, args); | ||
134 | m_GridUserService = ServerUtils.LoadPlugin<IGridUserService>(gridUserService, args); | ||
135 | Object[] authArgs = new Object[] { config, m_UserAccountService }; | ||
136 | m_AuthenticationService = ServerUtils.LoadPlugin<IAuthenticationService>(authService, authArgs); | ||
137 | m_InventoryService = ServerUtils.LoadPlugin<IInventoryService>(invService, args); | ||
138 | |||
139 | if (gridService != string.Empty) | ||
140 | m_GridService = ServerUtils.LoadPlugin<IGridService>(gridService, args); | ||
141 | if (presenceService != string.Empty) | ||
142 | m_PresenceService = ServerUtils.LoadPlugin<IPresenceService>(presenceService, args); | ||
143 | if (avatarService != string.Empty) | ||
144 | m_AvatarService = ServerUtils.LoadPlugin<IAvatarService>(avatarService, args); | ||
145 | if (friendsService != string.Empty) | ||
146 | m_FriendsService = ServerUtils.LoadPlugin<IFriendsService>(friendsService, args); | ||
147 | if (simulationService != string.Empty) | ||
148 | m_RemoteSimulationService = ServerUtils.LoadPlugin<ISimulationService>(simulationService, args); | ||
149 | if (agentService != string.Empty) | ||
150 | m_UserAgentService = ServerUtils.LoadPlugin<IUserAgentService>(agentService, args); | ||
151 | |||
152 | // | ||
153 | // deal with the services given as argument | ||
154 | // | ||
155 | m_LocalSimulationService = simService; | ||
156 | if (libraryService != null) | ||
157 | { | ||
158 | m_log.DebugFormat("[LLOGIN SERVICE]: Using LibraryService given as argument"); | ||
159 | m_LibraryService = libraryService; | ||
160 | } | ||
161 | else if (libService != string.Empty) | ||
162 | { | ||
163 | m_log.DebugFormat("[LLOGIN SERVICE]: Using instantiated LibraryService"); | ||
164 | m_LibraryService = ServerUtils.LoadPlugin<ILibraryService>(libService, args); | ||
165 | } | ||
166 | |||
167 | m_GatekeeperConnector = new GatekeeperServiceConnector(); | ||
168 | |||
169 | if (!Initialized) | ||
170 | { | ||
171 | Initialized = true; | ||
172 | RegisterCommands(); | ||
173 | } | ||
174 | |||
175 | m_log.DebugFormat("[LLOGIN SERVICE]: Starting..."); | ||
176 | |||
177 | } | ||
178 | |||
179 | public LLLoginService(IConfigSource config) : this(config, null, null) | ||
180 | { | ||
181 | } | ||
182 | |||
183 | public Hashtable SetLevel(string firstName, string lastName, string passwd, int level, IPEndPoint clientIP) | ||
184 | { | ||
185 | Hashtable response = new Hashtable(); | ||
186 | response["success"] = "false"; | ||
187 | |||
188 | if (!m_AllowRemoteSetLoginLevel) | ||
189 | return response; | ||
190 | |||
191 | try | ||
192 | { | ||
193 | UserAccount account = m_UserAccountService.GetUserAccount(UUID.Zero, firstName, lastName); | ||
194 | if (account == null) | ||
195 | { | ||
196 | m_log.InfoFormat("[LLOGIN SERVICE]: Set Level failed, user {0} {1} not found", firstName, lastName); | ||
197 | return response; | ||
198 | } | ||
199 | |||
200 | if (account.UserLevel < 200) | ||
201 | { | ||
202 | m_log.InfoFormat("[LLOGIN SERVICE]: Set Level failed, reason: user level too low"); | ||
203 | return response; | ||
204 | } | ||
205 | |||
206 | // | ||
207 | // Authenticate this user | ||
208 | // | ||
209 | // We don't support clear passwords here | ||
210 | // | ||
211 | string token = m_AuthenticationService.Authenticate(account.PrincipalID, passwd, 30); | ||
212 | UUID secureSession = UUID.Zero; | ||
213 | if ((token == string.Empty) || (token != string.Empty && !UUID.TryParse(token, out secureSession))) | ||
214 | { | ||
215 | m_log.InfoFormat("[LLOGIN SERVICE]: SetLevel failed, reason: authentication failed"); | ||
216 | return response; | ||
217 | } | ||
218 | } | ||
219 | catch (Exception e) | ||
220 | { | ||
221 | m_log.Error("[LLOGIN SERVICE]: SetLevel failed, exception " + e.ToString()); | ||
222 | return response; | ||
223 | } | ||
224 | |||
225 | m_MinLoginLevel = level; | ||
226 | m_log.InfoFormat("[LLOGIN SERVICE]: Login level set to {0} by {1} {2}", level, firstName, lastName); | ||
227 | |||
228 | response["success"] = true; | ||
229 | return response; | ||
230 | } | ||
231 | |||
232 | public LoginResponse Login(string firstName, string lastName, string passwd, string startLocation, UUID scopeID, | ||
233 | string clientVersion, string channel, string mac, string id0, IPEndPoint clientIP) | ||
234 | { | ||
235 | bool success = false; | ||
236 | UUID session = UUID.Random(); | ||
237 | |||
238 | m_log.InfoFormat("[LLOGIN SERVICE]: Login request for {0} {1} at {2} using viewer {3}, channel {4}, IP {5}, Mac {6}, Id0 {7}", | ||
239 | firstName, lastName, startLocation, clientVersion, channel, clientIP.Address.ToString(), mac, id0); | ||
240 | try | ||
241 | { | ||
242 | // | ||
243 | // Check client | ||
244 | // | ||
245 | if (m_AllowedClients != string.Empty) | ||
246 | { | ||
247 | Regex arx = new Regex(m_AllowedClients); | ||
248 | Match am = arx.Match(clientVersion); | ||
249 | |||
250 | if (!am.Success) | ||
251 | { | ||
252 | m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: client {0} is not allowed", clientVersion); | ||
253 | return LLFailedLoginResponse.LoginBlockedProblem; | ||
254 | } | ||
255 | } | ||
256 | |||
257 | if (m_DeniedClients != string.Empty) | ||
258 | { | ||
259 | Regex drx = new Regex(m_DeniedClients); | ||
260 | Match dm = drx.Match(clientVersion); | ||
261 | |||
262 | if (dm.Success) | ||
263 | { | ||
264 | m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: client {0} is denied", clientVersion); | ||
265 | return LLFailedLoginResponse.LoginBlockedProblem; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | // | ||
270 | // Get the account and check that it exists | ||
271 | // | ||
272 | UserAccount account = m_UserAccountService.GetUserAccount(scopeID, firstName, lastName); | ||
273 | if (account == null) | ||
274 | { | ||
275 | m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: user not found"); | ||
276 | return LLFailedLoginResponse.UserProblem; | ||
277 | } | ||
278 | |||
279 | if (account.UserLevel < 0) | ||
280 | { | ||
281 | m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: Unverified account"); | ||
282 | return LLFailedLoginResponse.UnverifiedAccountProblem; | ||
283 | } | ||
284 | |||
285 | if (account.UserLevel < m_MinLoginLevel) | ||
286 | { | ||
287 | m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: login is blocked for user level {0}", account.UserLevel); | ||
288 | return LLFailedLoginResponse.LoginBlockedProblem; | ||
289 | } | ||
290 | |||
291 | // If a scope id is requested, check that the account is in | ||
292 | // that scope, or unscoped. | ||
293 | // | ||
294 | if (scopeID != UUID.Zero) | ||
295 | { | ||
296 | if (account.ScopeID != scopeID && account.ScopeID != UUID.Zero) | ||
297 | { | ||
298 | m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: user not found"); | ||
299 | return LLFailedLoginResponse.UserProblem; | ||
300 | } | ||
301 | } | ||
302 | else | ||
303 | { | ||
304 | scopeID = account.ScopeID; | ||
305 | } | ||
306 | |||
307 | // | ||
308 | // Authenticate this user | ||
309 | // | ||
310 | if (!passwd.StartsWith("$1$")) | ||
311 | passwd = "$1$" + Util.Md5Hash(passwd); | ||
312 | passwd = passwd.Remove(0, 3); //remove $1$ | ||
313 | string token = m_AuthenticationService.Authenticate(account.PrincipalID, passwd, 30); | ||
314 | UUID secureSession = UUID.Zero; | ||
315 | if ((token == string.Empty) || (token != string.Empty && !UUID.TryParse(token, out secureSession))) | ||
316 | { | ||
317 | m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: authentication failed"); | ||
318 | return LLFailedLoginResponse.UserProblem; | ||
319 | } | ||
320 | |||
321 | // | ||
322 | // Get the user's inventory | ||
323 | // | ||
324 | if (m_RequireInventory && m_InventoryService == null) | ||
325 | { | ||
326 | m_log.WarnFormat("[LLOGIN SERVICE]: Login failed, reason: inventory service not set up"); | ||
327 | return LLFailedLoginResponse.InventoryProblem; | ||
328 | } | ||
329 | List<InventoryFolderBase> inventorySkel = m_InventoryService.GetInventorySkeleton(account.PrincipalID); | ||
330 | if (m_RequireInventory && ((inventorySkel == null) || (inventorySkel != null && inventorySkel.Count == 0))) | ||
331 | { | ||
332 | m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: unable to retrieve user inventory"); | ||
333 | return LLFailedLoginResponse.InventoryProblem; | ||
334 | } | ||
335 | |||
336 | // Get active gestures | ||
337 | List<InventoryItemBase> gestures = m_InventoryService.GetActiveGestures(account.PrincipalID); | ||
338 | // m_log.DebugFormat("[LLOGIN SERVICE]: {0} active gestures", gestures.Count); | ||
339 | |||
340 | // | ||
341 | // Login the presence | ||
342 | // | ||
343 | if (m_PresenceService != null) | ||
344 | { | ||
345 | success = m_PresenceService.LoginAgent(account.PrincipalID.ToString(), session, secureSession); | ||
346 | if (!success) | ||
347 | { | ||
348 | m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: could not login presence"); | ||
349 | return LLFailedLoginResponse.GridProblem; | ||
350 | } | ||
351 | } | ||
352 | |||
353 | // | ||
354 | // Change Online status and get the home region | ||
355 | // | ||
356 | GridRegion home = null; | ||
357 | GridUserInfo guinfo = m_GridUserService.LoggedIn(account.PrincipalID.ToString()); | ||
358 | if (guinfo != null && (guinfo.HomeRegionID != UUID.Zero) && m_GridService != null) | ||
359 | { | ||
360 | home = m_GridService.GetRegionByUUID(scopeID, guinfo.HomeRegionID); | ||
361 | } | ||
362 | if (guinfo == null) | ||
363 | { | ||
364 | // something went wrong, make something up, so that we don't have to test this anywhere else | ||
365 | guinfo = new GridUserInfo(); | ||
366 | guinfo.LastPosition = guinfo.HomePosition = new Vector3(128, 128, 30); | ||
367 | } | ||
368 | |||
369 | // | ||
370 | // Find the destination region/grid | ||
371 | // | ||
372 | string where = string.Empty; | ||
373 | Vector3 position = Vector3.Zero; | ||
374 | Vector3 lookAt = Vector3.Zero; | ||
375 | GridRegion gatekeeper = null; | ||
376 | TeleportFlags flags; | ||
377 | GridRegion destination = FindDestination(account, scopeID, guinfo, session, startLocation, home, out gatekeeper, out where, out position, out lookAt, out flags); | ||
378 | if (destination == null) | ||
379 | { | ||
380 | m_PresenceService.LogoutAgent(session); | ||
381 | m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: destination not found"); | ||
382 | return LLFailedLoginResponse.GridProblem; | ||
383 | } | ||
384 | |||
385 | if (account.UserLevel >= 200) | ||
386 | flags |= TeleportFlags.Godlike; | ||
387 | // | ||
388 | // Get the avatar | ||
389 | // | ||
390 | AvatarAppearance avatar = null; | ||
391 | if (m_AvatarService != null) | ||
392 | { | ||
393 | avatar = m_AvatarService.GetAppearance(account.PrincipalID); | ||
394 | } | ||
395 | |||
396 | // | ||
397 | // Instantiate/get the simulation interface and launch an agent at the destination | ||
398 | // | ||
399 | string reason = string.Empty; | ||
400 | GridRegion dest; | ||
401 | AgentCircuitData aCircuit = LaunchAgentAtGrid(gatekeeper, destination, account, avatar, session, secureSession, position, where, | ||
402 | clientVersion, channel, mac, id0, clientIP, flags, out where, out reason, out dest); | ||
403 | destination = dest; | ||
404 | if (aCircuit == null) | ||
405 | { | ||
406 | m_PresenceService.LogoutAgent(session); | ||
407 | m_log.InfoFormat("[LLOGIN SERVICE]: Login failed, reason: {0}", reason); | ||
408 | return new LLFailedLoginResponse("key", reason, "false"); | ||
409 | |||
410 | } | ||
411 | // Get Friends list | ||
412 | FriendInfo[] friendsList = new FriendInfo[0]; | ||
413 | if (m_FriendsService != null) | ||
414 | { | ||
415 | friendsList = m_FriendsService.GetFriends(account.PrincipalID); | ||
416 | // m_log.DebugFormat("[LLOGIN SERVICE]: Retrieved {0} friends", friendsList.Length); | ||
417 | } | ||
418 | |||
419 | // | ||
420 | // Finally, fill out the response and return it | ||
421 | // | ||
422 | LLLoginResponse response = new LLLoginResponse(account, aCircuit, guinfo, destination, inventorySkel, friendsList, m_LibraryService, | ||
423 | where, startLocation, position, lookAt, gestures, m_WelcomeMessage, home, clientIP, m_MapTileURL, m_SearchURL, m_Currency); | ||
424 | |||
425 | m_log.DebugFormat("[LLOGIN SERVICE]: All clear. Sending login response to client."); | ||
426 | return response; | ||
427 | } | ||
428 | catch (Exception e) | ||
429 | { | ||
430 | m_log.WarnFormat("[LLOGIN SERVICE]: Exception processing login for {0} {1}: {2} {3}", firstName, lastName, e.ToString(), e.StackTrace); | ||
431 | if (m_PresenceService != null) | ||
432 | m_PresenceService.LogoutAgent(session); | ||
433 | return LLFailedLoginResponse.InternalError; | ||
434 | } | ||
435 | } | ||
436 | |||
437 | protected GridRegion FindDestination(UserAccount account, UUID scopeID, GridUserInfo pinfo, UUID sessionID, string startLocation, GridRegion home, out GridRegion gatekeeper, out string where, out Vector3 position, out Vector3 lookAt, out TeleportFlags flags) | ||
438 | { | ||
439 | flags = TeleportFlags.ViaLogin; | ||
440 | |||
441 | m_log.DebugFormat("[LLOGIN SERVICE]: FindDestination for start location {0}", startLocation); | ||
442 | |||
443 | gatekeeper = null; | ||
444 | where = "home"; | ||
445 | position = new Vector3(128, 128, 0); | ||
446 | lookAt = new Vector3(0, 1, 0); | ||
447 | |||
448 | if (m_GridService == null) | ||
449 | return null; | ||
450 | |||
451 | if (startLocation.Equals("home")) | ||
452 | { | ||
453 | // logging into home region | ||
454 | if (pinfo == null) | ||
455 | return null; | ||
456 | |||
457 | GridRegion region = null; | ||
458 | |||
459 | bool tryDefaults = false; | ||
460 | |||
461 | if (home == null) | ||
462 | { | ||
463 | m_log.WarnFormat( | ||
464 | "[LLOGIN SERVICE]: User {0} {1} tried to login to a 'home' start location but they have none set", | ||
465 | account.FirstName, account.LastName); | ||
466 | |||
467 | tryDefaults = true; | ||
468 | } | ||
469 | else | ||
470 | { | ||
471 | region = home; | ||
472 | |||
473 | position = pinfo.HomePosition; | ||
474 | lookAt = pinfo.HomeLookAt; | ||
475 | } | ||
476 | |||
477 | if (tryDefaults) | ||
478 | { | ||
479 | List<GridRegion> defaults = m_GridService.GetDefaultRegions(scopeID); | ||
480 | if (defaults != null && defaults.Count > 0) | ||
481 | { | ||
482 | region = defaults[0]; | ||
483 | where = "safe"; | ||
484 | } | ||
485 | else | ||
486 | { | ||
487 | m_log.WarnFormat("[LLOGIN SERVICE]: User {0} {1} does not have a valid home and this grid does not have default locations. Attempting to find random region", | ||
488 | account.FirstName, account.LastName); | ||
489 | region = FindAlternativeRegion(scopeID); | ||
490 | if (region != null) | ||
491 | where = "safe"; | ||
492 | } | ||
493 | } | ||
494 | |||
495 | return region; | ||
496 | } | ||
497 | else if (startLocation.Equals("last")) | ||
498 | { | ||
499 | // logging into last visited region | ||
500 | where = "last"; | ||
501 | |||
502 | if (pinfo == null) | ||
503 | return null; | ||
504 | |||
505 | GridRegion region = null; | ||
506 | |||
507 | if (pinfo.LastRegionID.Equals(UUID.Zero) || (region = m_GridService.GetRegionByUUID(scopeID, pinfo.LastRegionID)) == null) | ||
508 | { | ||
509 | List<GridRegion> defaults = m_GridService.GetDefaultRegions(scopeID); | ||
510 | if (defaults != null && defaults.Count > 0) | ||
511 | { | ||
512 | region = defaults[0]; | ||
513 | where = "safe"; | ||
514 | } | ||
515 | else | ||
516 | { | ||
517 | m_log.Info("[LLOGIN SERVICE]: Last Region Not Found Attempting to find random region"); | ||
518 | region = FindAlternativeRegion(scopeID); | ||
519 | if (region != null) | ||
520 | where = "safe"; | ||
521 | } | ||
522 | |||
523 | } | ||
524 | else | ||
525 | { | ||
526 | position = pinfo.LastPosition; | ||
527 | lookAt = pinfo.LastLookAt; | ||
528 | } | ||
529 | |||
530 | return region; | ||
531 | } | ||
532 | else | ||
533 | { | ||
534 | flags |= TeleportFlags.ViaRegionID; | ||
535 | |||
536 | // free uri form | ||
537 | // e.g. New Moon&135&46 New Moon@osgrid.org:8002&153&34 | ||
538 | where = "url"; | ||
539 | GridRegion region = null; | ||
540 | Regex reURI = new Regex(@"^uri:(?<region>[^&]+)&(?<x>\d+)&(?<y>\d+)&(?<z>\d+)$"); | ||
541 | Match uriMatch = reURI.Match(startLocation); | ||
542 | if (uriMatch == null) | ||
543 | { | ||
544 | m_log.InfoFormat("[LLLOGIN SERVICE]: Got Custom Login URI {0}, but can't process it", startLocation); | ||
545 | return null; | ||
546 | } | ||
547 | else | ||
548 | { | ||
549 | position = new Vector3(float.Parse(uriMatch.Groups["x"].Value, Culture.NumberFormatInfo), | ||
550 | float.Parse(uriMatch.Groups["y"].Value, Culture.NumberFormatInfo), | ||
551 | float.Parse(uriMatch.Groups["z"].Value, Culture.NumberFormatInfo)); | ||
552 | |||
553 | string regionName = uriMatch.Groups["region"].ToString(); | ||
554 | if (regionName != null) | ||
555 | { | ||
556 | if (!regionName.Contains("@")) | ||
557 | { | ||
558 | List<GridRegion> regions = m_GridService.GetRegionsByName(scopeID, regionName, 1); | ||
559 | if ((regions == null) || (regions != null && regions.Count == 0)) | ||
560 | { | ||
561 | m_log.InfoFormat("[LLLOGIN SERVICE]: Got Custom Login URI {0}, can't locate region {1}. Trying defaults.", startLocation, regionName); | ||
562 | regions = m_GridService.GetDefaultRegions(scopeID); | ||
563 | if (regions != null && regions.Count > 0) | ||
564 | { | ||
565 | where = "safe"; | ||
566 | return regions[0]; | ||
567 | } | ||
568 | else | ||
569 | { | ||
570 | m_log.Info("[LLOGIN SERVICE]: Last Region Not Found Attempting to find random region"); | ||
571 | region = FindAlternativeRegion(scopeID); | ||
572 | if (region != null) | ||
573 | { | ||
574 | where = "safe"; | ||
575 | return region; | ||
576 | } | ||
577 | else | ||
578 | { | ||
579 | m_log.InfoFormat("[LLLOGIN SERVICE]: Got Custom Login URI {0}, Grid does not provide default regions and no alternative found.", startLocation); | ||
580 | return null; | ||
581 | } | ||
582 | } | ||
583 | } | ||
584 | return regions[0]; | ||
585 | } | ||
586 | else | ||
587 | { | ||
588 | if (m_UserAgentService == null) | ||
589 | { | ||
590 | m_log.WarnFormat("[LLLOGIN SERVICE]: This llogin service is not running a user agent service, as such it can't lauch agents at foreign grids"); | ||
591 | return null; | ||
592 | } | ||
593 | string[] parts = regionName.Split(new char[] { '@' }); | ||
594 | if (parts.Length < 2) | ||
595 | { | ||
596 | m_log.InfoFormat("[LLLOGIN SERVICE]: Got Custom Login URI {0}, can't locate region {1}", startLocation, regionName); | ||
597 | return null; | ||
598 | } | ||
599 | // Valid specification of a remote grid | ||
600 | |||
601 | regionName = parts[0]; | ||
602 | string domainLocator = parts[1]; | ||
603 | parts = domainLocator.Split(new char[] {':'}); | ||
604 | string domainName = parts[0]; | ||
605 | uint port = 0; | ||
606 | if (parts.Length > 1) | ||
607 | UInt32.TryParse(parts[1], out port); | ||
608 | |||
609 | // GridRegion region = FindForeignRegion(domainName, port, regionName, out gatekeeper); | ||
610 | region = FindForeignRegion(domainName, port, regionName, out gatekeeper); | ||
611 | return region; | ||
612 | } | ||
613 | } | ||
614 | else | ||
615 | { | ||
616 | List<GridRegion> defaults = m_GridService.GetDefaultRegions(scopeID); | ||
617 | if (defaults != null && defaults.Count > 0) | ||
618 | { | ||
619 | where = "safe"; | ||
620 | return defaults[0]; | ||
621 | } | ||
622 | else | ||
623 | return null; | ||
624 | } | ||
625 | } | ||
626 | //response.LookAt = "[r0,r1,r0]"; | ||
627 | //// can be: last, home, safe, url | ||
628 | //response.StartLocation = "url"; | ||
629 | |||
630 | } | ||
631 | |||
632 | } | ||
633 | |||
634 | private GridRegion FindAlternativeRegion(UUID scopeID) | ||
635 | { | ||
636 | List<GridRegion> hyperlinks = null; | ||
637 | List<GridRegion> regions = m_GridService.GetFallbackRegions(scopeID, 1000 * (int)Constants.RegionSize, 1000 * (int)Constants.RegionSize); | ||
638 | if (regions != null && regions.Count > 0) | ||
639 | { | ||
640 | hyperlinks = m_GridService.GetHyperlinks(scopeID); | ||
641 | IEnumerable<GridRegion> availableRegions = regions.Except(hyperlinks); | ||
642 | if (availableRegions.Count() > 0) | ||
643 | return availableRegions.ElementAt(0); | ||
644 | } | ||
645 | // No fallbacks, try to find an arbitrary region that is not a hyperlink | ||
646 | // maxNumber is fixed for now; maybe use some search pattern with increasing maxSize here? | ||
647 | regions = m_GridService.GetRegionsByName(scopeID, "", 10); | ||
648 | if (regions != null && regions.Count > 0) | ||
649 | { | ||
650 | if (hyperlinks == null) | ||
651 | hyperlinks = m_GridService.GetHyperlinks(scopeID); | ||
652 | IEnumerable<GridRegion> availableRegions = regions.Except(hyperlinks); | ||
653 | if (availableRegions.Count() > 0) | ||
654 | return availableRegions.ElementAt(0); | ||
655 | } | ||
656 | return null; | ||
657 | } | ||
658 | |||
659 | private GridRegion FindForeignRegion(string domainName, uint port, string regionName, out GridRegion gatekeeper) | ||
660 | { | ||
661 | m_log.Debug("[LLLOGIN SERVICE]: attempting to findforeignregion " + domainName + ":" + port.ToString() + ":" + regionName); | ||
662 | gatekeeper = new GridRegion(); | ||
663 | gatekeeper.ExternalHostName = domainName; | ||
664 | gatekeeper.HttpPort = port; | ||
665 | gatekeeper.RegionName = regionName; | ||
666 | gatekeeper.InternalEndPoint = new IPEndPoint(IPAddress.Parse("0.0.0.0"), 0); | ||
667 | |||
668 | UUID regionID; | ||
669 | ulong handle; | ||
670 | string imageURL = string.Empty, reason = string.Empty; | ||
671 | if (m_GatekeeperConnector.LinkRegion(gatekeeper, out regionID, out handle, out domainName, out imageURL, out reason)) | ||
672 | { | ||
673 | GridRegion destination = m_GatekeeperConnector.GetHyperlinkRegion(gatekeeper, regionID); | ||
674 | return destination; | ||
675 | } | ||
676 | |||
677 | return null; | ||
678 | } | ||
679 | |||
680 | private string hostName = string.Empty; | ||
681 | private int port = 0; | ||
682 | |||
683 | private void SetHostAndPort(string url) | ||
684 | { | ||
685 | try | ||
686 | { | ||
687 | Uri uri = new Uri(url); | ||
688 | hostName = uri.Host; | ||
689 | port = uri.Port; | ||
690 | } | ||
691 | catch | ||
692 | { | ||
693 | m_log.WarnFormat("[LLLogin SERVICE]: Unable to parse GatekeeperURL {0}", url); | ||
694 | } | ||
695 | } | ||
696 | |||
697 | protected AgentCircuitData LaunchAgentAtGrid(GridRegion gatekeeper, GridRegion destination, UserAccount account, AvatarAppearance avatar, | ||
698 | UUID session, UUID secureSession, Vector3 position, string currentWhere, string viewer, string channel, string mac, string id0, | ||
699 | IPEndPoint clientIP, TeleportFlags flags, out string where, out string reason, out GridRegion dest) | ||
700 | { | ||
701 | where = currentWhere; | ||
702 | ISimulationService simConnector = null; | ||
703 | reason = string.Empty; | ||
704 | uint circuitCode = 0; | ||
705 | AgentCircuitData aCircuit = null; | ||
706 | |||
707 | if (m_UserAgentService == null) | ||
708 | { | ||
709 | // HG standalones have both a localSimulatonDll and a remoteSimulationDll | ||
710 | // non-HG standalones have just a localSimulationDll | ||
711 | // independent login servers have just a remoteSimulationDll | ||
712 | if (m_LocalSimulationService != null) | ||
713 | simConnector = m_LocalSimulationService; | ||
714 | else if (m_RemoteSimulationService != null) | ||
715 | simConnector = m_RemoteSimulationService; | ||
716 | } | ||
717 | else // User Agent Service is on | ||
718 | { | ||
719 | if (gatekeeper == null) // login to local grid | ||
720 | { | ||
721 | if (hostName == string.Empty) | ||
722 | SetHostAndPort(m_GatekeeperURL); | ||
723 | |||
724 | gatekeeper = new GridRegion(destination); | ||
725 | gatekeeper.ExternalHostName = hostName; | ||
726 | gatekeeper.HttpPort = (uint)port; | ||
727 | gatekeeper.ServerURI = m_GatekeeperURL; | ||
728 | } | ||
729 | m_log.Debug("[LLLOGIN SERVICE]: no gatekeeper detected..... using " + m_GatekeeperURL); | ||
730 | } | ||
731 | |||
732 | bool success = false; | ||
733 | |||
734 | if (m_UserAgentService == null && simConnector != null) | ||
735 | { | ||
736 | circuitCode = (uint)Util.RandomClass.Next(); ; | ||
737 | aCircuit = MakeAgent(destination, account, avatar, session, secureSession, circuitCode, position, clientIP.Address.ToString(), viewer, channel, mac, id0); | ||
738 | success = LaunchAgentDirectly(simConnector, destination, aCircuit, flags, out reason); | ||
739 | if (!success && m_GridService != null) | ||
740 | { | ||
741 | // Try the fallback regions | ||
742 | List<GridRegion> fallbacks = m_GridService.GetFallbackRegions(account.ScopeID, destination.RegionLocX, destination.RegionLocY); | ||
743 | if (fallbacks != null) | ||
744 | { | ||
745 | foreach (GridRegion r in fallbacks) | ||
746 | { | ||
747 | success = LaunchAgentDirectly(simConnector, r, aCircuit, flags | TeleportFlags.ViaRegionID, out reason); | ||
748 | if (success) | ||
749 | { | ||
750 | where = "safe"; | ||
751 | destination = r; | ||
752 | break; | ||
753 | } | ||
754 | } | ||
755 | } | ||
756 | } | ||
757 | } | ||
758 | |||
759 | if (m_UserAgentService != null) | ||
760 | { | ||
761 | circuitCode = (uint)Util.RandomClass.Next(); ; | ||
762 | aCircuit = MakeAgent(destination, account, avatar, session, secureSession, circuitCode, position, clientIP.Address.ToString(), viewer, channel, mac, id0); | ||
763 | success = LaunchAgentIndirectly(gatekeeper, destination, aCircuit, clientIP, out reason); | ||
764 | if (!success && m_GridService != null) | ||
765 | { | ||
766 | // Try the fallback regions | ||
767 | List<GridRegion> fallbacks = m_GridService.GetFallbackRegions(account.ScopeID, destination.RegionLocX, destination.RegionLocY); | ||
768 | if (fallbacks != null) | ||
769 | { | ||
770 | foreach (GridRegion r in fallbacks) | ||
771 | { | ||
772 | success = LaunchAgentIndirectly(gatekeeper, r, aCircuit, clientIP, out reason); | ||
773 | if (success) | ||
774 | { | ||
775 | where = "safe"; | ||
776 | destination = r; | ||
777 | break; | ||
778 | } | ||
779 | } | ||
780 | } | ||
781 | } | ||
782 | } | ||
783 | dest = destination; | ||
784 | if (success) | ||
785 | return aCircuit; | ||
786 | else | ||
787 | return null; | ||
788 | } | ||
789 | |||
790 | private AgentCircuitData MakeAgent(GridRegion region, UserAccount account, | ||
791 | AvatarAppearance avatar, UUID session, UUID secureSession, uint circuit, Vector3 position, | ||
792 | string ipaddress, string viewer, string channel, string mac, string id0) | ||
793 | { | ||
794 | AgentCircuitData aCircuit = new AgentCircuitData(); | ||
795 | |||
796 | aCircuit.AgentID = account.PrincipalID; | ||
797 | if (avatar != null) | ||
798 | aCircuit.Appearance = new AvatarAppearance(avatar); | ||
799 | else | ||
800 | aCircuit.Appearance = new AvatarAppearance(); | ||
801 | |||
802 | //aCircuit.BaseFolder = irrelevant | ||
803 | aCircuit.CapsPath = CapsUtil.GetRandomCapsObjectPath(); | ||
804 | aCircuit.child = false; // the first login agent is root | ||
805 | aCircuit.ChildrenCapSeeds = new Dictionary<ulong, string>(); | ||
806 | aCircuit.circuitcode = circuit; | ||
807 | aCircuit.firstname = account.FirstName; | ||
808 | //aCircuit.InventoryFolder = irrelevant | ||
809 | aCircuit.lastname = account.LastName; | ||
810 | aCircuit.SecureSessionID = secureSession; | ||
811 | aCircuit.SessionID = session; | ||
812 | aCircuit.startpos = position; | ||
813 | aCircuit.IPAddress = ipaddress; | ||
814 | aCircuit.Viewer = viewer; | ||
815 | aCircuit.Channel = channel; | ||
816 | aCircuit.Mac = mac; | ||
817 | aCircuit.Id0 = id0; | ||
818 | SetServiceURLs(aCircuit, account); | ||
819 | |||
820 | return aCircuit; | ||
821 | |||
822 | //m_UserAgentService.LoginAgentToGrid(aCircuit, GatekeeperServiceConnector, region, out reason); | ||
823 | //if (simConnector.CreateAgent(region, aCircuit, 0, out reason)) | ||
824 | // return aCircuit; | ||
825 | |||
826 | //return null; | ||
827 | |||
828 | } | ||
829 | |||
830 | private void SetServiceURLs(AgentCircuitData aCircuit, UserAccount account) | ||
831 | { | ||
832 | aCircuit.ServiceURLs = new Dictionary<string, object>(); | ||
833 | if (account.ServiceURLs == null) | ||
834 | return; | ||
835 | |||
836 | // Old style: get the service keys from the DB | ||
837 | foreach (KeyValuePair<string, object> kvp in account.ServiceURLs) | ||
838 | { | ||
839 | if (kvp.Value != null) | ||
840 | { | ||
841 | aCircuit.ServiceURLs[kvp.Key] = kvp.Value; | ||
842 | |||
843 | if (!aCircuit.ServiceURLs[kvp.Key].ToString().EndsWith("/")) | ||
844 | aCircuit.ServiceURLs[kvp.Key] = aCircuit.ServiceURLs[kvp.Key] + "/"; | ||
845 | } | ||
846 | } | ||
847 | |||
848 | // New style: service keys start with SRV_; override the previous | ||
849 | string[] keys = m_LoginServerConfig.GetKeys(); | ||
850 | |||
851 | if (keys.Length > 0) | ||
852 | { | ||
853 | bool newUrls = false; | ||
854 | IEnumerable<string> serviceKeys = keys.Where(value => value.StartsWith("SRV_")); | ||
855 | foreach (string serviceKey in serviceKeys) | ||
856 | { | ||
857 | string keyName = serviceKey.Replace("SRV_", ""); | ||
858 | string keyValue = m_LoginServerConfig.GetString(serviceKey, string.Empty); | ||
859 | if (!keyValue.EndsWith("/")) | ||
860 | keyValue = keyValue + "/"; | ||
861 | |||
862 | if (!account.ServiceURLs.ContainsKey(keyName) || (account.ServiceURLs.ContainsKey(keyName) && account.ServiceURLs[keyName] != keyValue)) | ||
863 | { | ||
864 | account.ServiceURLs[keyName] = keyValue; | ||
865 | newUrls = true; | ||
866 | } | ||
867 | aCircuit.ServiceURLs[keyName] = keyValue; | ||
868 | |||
869 | m_log.DebugFormat("[LLLOGIN SERVICE]: found new key {0} {1}", keyName, aCircuit.ServiceURLs[keyName]); | ||
870 | } | ||
871 | |||
872 | // The grid operator decided to override the defaults in the | ||
873 | // [LoginService] configuration. Let's store the correct ones. | ||
874 | if (newUrls) | ||
875 | m_UserAccountService.StoreUserAccount(account); | ||
876 | } | ||
877 | |||
878 | } | ||
879 | |||
880 | private bool LaunchAgentDirectly(ISimulationService simConnector, GridRegion region, AgentCircuitData aCircuit, TeleportFlags flags, out string reason) | ||
881 | { | ||
882 | return simConnector.CreateAgent(region, aCircuit, (uint)flags, out reason); | ||
883 | } | ||
884 | |||
885 | private bool LaunchAgentIndirectly(GridRegion gatekeeper, GridRegion destination, AgentCircuitData aCircuit, IPEndPoint clientIP, out string reason) | ||
886 | { | ||
887 | m_log.Debug("[LLOGIN SERVICE] Launching agent at " + destination.RegionName); | ||
888 | if (m_UserAgentService.LoginAgentToGrid(aCircuit, gatekeeper, destination, clientIP, out reason)) | ||
889 | return true; | ||
890 | return false; | ||
891 | } | ||
892 | |||
893 | #region Console Commands | ||
894 | private void RegisterCommands() | ||
895 | { | ||
896 | //MainConsole.Instance.Commands.AddCommand | ||
897 | MainConsole.Instance.Commands.AddCommand("loginservice", false, "login level", | ||
898 | "login level <level>", | ||
899 | "Set the minimum user level to log in", HandleLoginCommand); | ||
900 | |||
901 | MainConsole.Instance.Commands.AddCommand("loginservice", false, "login reset", | ||
902 | "login reset", | ||
903 | "Reset the login level to allow all users", | ||
904 | HandleLoginCommand); | ||
905 | |||
906 | MainConsole.Instance.Commands.AddCommand("loginservice", false, "login text", | ||
907 | "login text <text>", | ||
908 | "Set the text users will see on login", HandleLoginCommand); | ||
909 | |||
910 | } | ||
911 | |||
912 | private void HandleLoginCommand(string module, string[] cmd) | ||
913 | { | ||
914 | string subcommand = cmd[1]; | ||
915 | |||
916 | switch (subcommand) | ||
917 | { | ||
918 | case "level": | ||
919 | // Set the minimum level to allow login | ||
920 | // Useful to allow grid update without worrying about users. | ||
921 | // or fixing critical issues | ||
922 | // | ||
923 | if (cmd.Length > 2) | ||
924 | Int32.TryParse(cmd[2], out m_MinLoginLevel); | ||
925 | break; | ||
926 | case "reset": | ||
927 | m_MinLoginLevel = 0; | ||
928 | break; | ||
929 | case "text": | ||
930 | if (cmd.Length > 2) | ||
931 | m_WelcomeMessage = cmd[2]; | ||
932 | break; | ||
933 | } | ||
934 | } | ||
935 | } | ||
936 | |||
937 | #endregion | ||
938 | } | ||
diff --git a/OpenSim/Services/MapImageService/MapImageService.cs b/OpenSim/Services/MapImageService/MapImageService.cs new file mode 100644 index 0000000..a85ee70 --- /dev/null +++ b/OpenSim/Services/MapImageService/MapImageService.cs | |||
@@ -0,0 +1,300 @@ | |||
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 | * The design of this map service is based on SimianGrid's PHP-based | ||
28 | * map service. See this URL for the original PHP version: | ||
29 | * https://github.com/openmetaversefoundation/simiangrid/ | ||
30 | */ | ||
31 | |||
32 | using System; | ||
33 | using System.Collections.Generic; | ||
34 | using System.Drawing; | ||
35 | using System.Drawing.Imaging; | ||
36 | using System.IO; | ||
37 | using System.Net; | ||
38 | using System.Reflection; | ||
39 | |||
40 | using Nini.Config; | ||
41 | using log4net; | ||
42 | using OpenMetaverse; | ||
43 | |||
44 | using OpenSim.Framework; | ||
45 | using OpenSim.Framework.Console; | ||
46 | using OpenSim.Services.Interfaces; | ||
47 | |||
48 | |||
49 | namespace OpenSim.Services.MapImageService | ||
50 | { | ||
51 | public class MapImageService : IMapImageService | ||
52 | { | ||
53 | private static readonly ILog m_log = | ||
54 | LogManager.GetLogger( | ||
55 | MethodBase.GetCurrentMethod().DeclaringType); | ||
56 | |||
57 | private const int ZOOM_LEVELS = 8; | ||
58 | private const int IMAGE_WIDTH = 256; | ||
59 | private const int HALF_WIDTH = 128; | ||
60 | private const int JPEG_QUALITY = 80; | ||
61 | |||
62 | private static string m_TilesStoragePath = "maptiles"; | ||
63 | |||
64 | private static object m_Sync = new object(); | ||
65 | private static bool m_Initialized = false; | ||
66 | private static string m_WaterTileFile = string.Empty; | ||
67 | private static Color m_Watercolor = Color.FromArgb(29, 71, 95); | ||
68 | |||
69 | public MapImageService(IConfigSource config) | ||
70 | { | ||
71 | if (!m_Initialized) | ||
72 | { | ||
73 | m_Initialized = true; | ||
74 | m_log.Debug("[MAP IMAGE SERVICE]: Starting MapImage service"); | ||
75 | |||
76 | IConfig serviceConfig = config.Configs["MapImageService"]; | ||
77 | if (serviceConfig != null) | ||
78 | { | ||
79 | m_TilesStoragePath = serviceConfig.GetString("TilesStoragePath", m_TilesStoragePath); | ||
80 | if (!Directory.Exists(m_TilesStoragePath)) | ||
81 | Directory.CreateDirectory(m_TilesStoragePath); | ||
82 | |||
83 | |||
84 | m_WaterTileFile = Path.Combine(m_TilesStoragePath, "water.jpg"); | ||
85 | if (!File.Exists(m_WaterTileFile)) | ||
86 | { | ||
87 | Bitmap waterTile = new Bitmap(IMAGE_WIDTH, IMAGE_WIDTH); | ||
88 | FillImage(waterTile, m_Watercolor); | ||
89 | waterTile.Save(m_WaterTileFile); | ||
90 | } | ||
91 | } | ||
92 | } | ||
93 | } | ||
94 | |||
95 | #region IMapImageService | ||
96 | |||
97 | public bool AddMapTile(int x, int y, byte[] imageData, out string reason) | ||
98 | { | ||
99 | reason = string.Empty; | ||
100 | string fileName = GetFileName(1, x, y); | ||
101 | |||
102 | lock (m_Sync) | ||
103 | { | ||
104 | try | ||
105 | { | ||
106 | using (FileStream f = File.Open(fileName, FileMode.OpenOrCreate, FileAccess.Write)) | ||
107 | f.Write(imageData, 0, imageData.Length); | ||
108 | } | ||
109 | catch (Exception e) | ||
110 | { | ||
111 | m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to save image file {0}: {1}", fileName, e); | ||
112 | reason = e.Message; | ||
113 | return false; | ||
114 | } | ||
115 | |||
116 | // Also save in png format? | ||
117 | |||
118 | // Stitch seven more aggregate tiles together | ||
119 | for (uint zoomLevel = 2; zoomLevel <= ZOOM_LEVELS; zoomLevel++) | ||
120 | { | ||
121 | // Calculate the width (in full resolution tiles) and bottom-left | ||
122 | // corner of the current zoom level | ||
123 | int width = (int)Math.Pow(2, (double)(zoomLevel - 1)); | ||
124 | int x1 = x - (x % width); | ||
125 | int y1 = y - (y % width); | ||
126 | |||
127 | if (!CreateTile(zoomLevel, x1, y1)) | ||
128 | { | ||
129 | m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to create tile for {0} at zoom level {1}", fileName, zoomLevel); | ||
130 | reason = string.Format("Map tile at zoom level {0} failed", zoomLevel); | ||
131 | return false; | ||
132 | } | ||
133 | } | ||
134 | } | ||
135 | |||
136 | return true; | ||
137 | } | ||
138 | |||
139 | public byte[] GetMapTile(string fileName, out string format) | ||
140 | { | ||
141 | // m_log.DebugFormat("[MAP IMAGE SERVICE]: Getting map tile {0}", fileName); | ||
142 | |||
143 | format = ".jpg"; | ||
144 | string fullName = Path.Combine(m_TilesStoragePath, fileName); | ||
145 | if (File.Exists(fullName)) | ||
146 | { | ||
147 | format = Path.GetExtension(fileName).ToLower(); | ||
148 | //m_log.DebugFormat("[MAP IMAGE SERVICE]: Found file {0}, extension {1}", fileName, format); | ||
149 | return File.ReadAllBytes(fullName); | ||
150 | } | ||
151 | else if (File.Exists(m_WaterTileFile)) | ||
152 | { | ||
153 | return File.ReadAllBytes(m_WaterTileFile); | ||
154 | } | ||
155 | else | ||
156 | { | ||
157 | m_log.DebugFormat("[MAP IMAGE SERVICE]: unable to get file {0}", fileName); | ||
158 | return new byte[0]; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | #endregion | ||
163 | |||
164 | |||
165 | private string GetFileName(uint zoomLevel, int x, int y) | ||
166 | { | ||
167 | string extension = "jpg"; | ||
168 | return Path.Combine(m_TilesStoragePath, string.Format("map-{0}-{1}-{2}-objects.{3}", zoomLevel, x, y, extension)); | ||
169 | } | ||
170 | |||
171 | private Bitmap GetInputTileImage(string fileName) | ||
172 | { | ||
173 | try | ||
174 | { | ||
175 | if (File.Exists(fileName)) | ||
176 | return new Bitmap(fileName); | ||
177 | } | ||
178 | catch (Exception e) | ||
179 | { | ||
180 | m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to read image data from {0}: {1}", fileName, e); | ||
181 | } | ||
182 | |||
183 | return null; | ||
184 | } | ||
185 | |||
186 | private Bitmap GetOutputTileImage(string fileName) | ||
187 | { | ||
188 | try | ||
189 | { | ||
190 | if (File.Exists(fileName)) | ||
191 | return new Bitmap(fileName); | ||
192 | |||
193 | else | ||
194 | { | ||
195 | // Create a new output tile with a transparent background | ||
196 | Bitmap bm = new Bitmap(IMAGE_WIDTH, IMAGE_WIDTH, PixelFormat.Format24bppRgb); | ||
197 | bm.MakeTransparent(); | ||
198 | return bm; | ||
199 | } | ||
200 | } | ||
201 | catch (Exception e) | ||
202 | { | ||
203 | m_log.WarnFormat("[MAP IMAGE SERVICE]: Unable to read image data from {0}: {1}", fileName, e); | ||
204 | } | ||
205 | |||
206 | return null; | ||
207 | } | ||
208 | |||
209 | private bool CreateTile(uint zoomLevel, int x, int y) | ||
210 | { | ||
211 | // m_log.DebugFormat("[MAP IMAGE SERVICE]: Create tile for {0} {1}, zoom {2}", x, y, zoomLevel); | ||
212 | int prevWidth = (int)Math.Pow(2, (double)zoomLevel - 2); | ||
213 | int thisWidth = (int)Math.Pow(2, (double)zoomLevel - 1); | ||
214 | |||
215 | // Convert x and y to the bottom left tile for this zoom level | ||
216 | int xIn = x - (x % prevWidth); | ||
217 | int yIn = y - (y % prevWidth); | ||
218 | |||
219 | // Convert x and y to the bottom left tile for the next zoom level | ||
220 | int xOut = x - (x % thisWidth); | ||
221 | int yOut = y - (y % thisWidth); | ||
222 | |||
223 | // Try to open the four input tiles from the previous zoom level | ||
224 | Bitmap inputBL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn)); | ||
225 | Bitmap inputBR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn)); | ||
226 | Bitmap inputTL = GetInputTileImage(GetFileName(zoomLevel - 1, xIn, yIn + prevWidth)); | ||
227 | Bitmap inputTR = GetInputTileImage(GetFileName(zoomLevel - 1, xIn + prevWidth, yIn + prevWidth)); | ||
228 | |||
229 | // Open the output tile (current zoom level) | ||
230 | string outputFile = GetFileName(zoomLevel, xOut, yOut); | ||
231 | Bitmap output = GetOutputTileImage(outputFile); | ||
232 | if (output == null) | ||
233 | return false; | ||
234 | FillImage(output, m_Watercolor); | ||
235 | |||
236 | if (inputBL != null) | ||
237 | { | ||
238 | ImageCopyResampled(output, inputBL, 0, HALF_WIDTH, 0, 0); | ||
239 | inputBL.Dispose(); | ||
240 | } | ||
241 | if (inputBR != null) | ||
242 | { | ||
243 | ImageCopyResampled(output, inputBR, HALF_WIDTH, HALF_WIDTH, 0, 0); | ||
244 | inputBR.Dispose(); | ||
245 | } | ||
246 | if (inputTL != null) | ||
247 | { | ||
248 | ImageCopyResampled(output, inputTL, 0, 0, 0, 0); | ||
249 | inputTL.Dispose(); | ||
250 | } | ||
251 | if (inputTR != null) | ||
252 | { | ||
253 | ImageCopyResampled(output, inputTR, HALF_WIDTH, 0, 0, 0); | ||
254 | inputTR.Dispose(); | ||
255 | } | ||
256 | |||
257 | // Write the modified output | ||
258 | try | ||
259 | { | ||
260 | using (Bitmap final = new Bitmap(output)) | ||
261 | { | ||
262 | output.Dispose(); | ||
263 | final.Save(outputFile, ImageFormat.Jpeg); | ||
264 | } | ||
265 | } | ||
266 | catch (Exception e) | ||
267 | { | ||
268 | m_log.WarnFormat("[MAP IMAGE SERVICE]: Oops on saving {0} {1}", outputFile, e); | ||
269 | } | ||
270 | |||
271 | // Save also as png? | ||
272 | |||
273 | return true; | ||
274 | } | ||
275 | |||
276 | #region Image utilities | ||
277 | |||
278 | private void FillImage(Bitmap bm, Color c) | ||
279 | { | ||
280 | for (int x = 0; x < bm.Width; x++) | ||
281 | for (int y = 0; y < bm.Height; y++) | ||
282 | bm.SetPixel(x, y, c); | ||
283 | } | ||
284 | |||
285 | private void ImageCopyResampled(Bitmap output, Bitmap input, int destX, int destY, int srcX, int srcY) | ||
286 | { | ||
287 | int resamplingRateX = 2; // (input.Width - srcX) / (output.Width - destX); | ||
288 | int resamplingRateY = 2; // (input.Height - srcY) / (output.Height - destY); | ||
289 | |||
290 | for (int x = destX; x < destX + HALF_WIDTH; x++) | ||
291 | for (int y = destY; y < destY + HALF_WIDTH; y++) | ||
292 | { | ||
293 | Color p = input.GetPixel(srcX + (x - destX) * resamplingRateX, srcY + (y - destY) * resamplingRateY); | ||
294 | output.SetPixel(x, y, p); | ||
295 | } | ||
296 | } | ||
297 | |||
298 | #endregion | ||
299 | } | ||
300 | } | ||
diff --git a/OpenSim/Services/PresenceService/PresenceService.cs b/OpenSim/Services/PresenceService/PresenceService.cs index 2157462..c8ac38e 100644 --- a/OpenSim/Services/PresenceService/PresenceService.cs +++ b/OpenSim/Services/PresenceService/PresenceService.cs | |||
@@ -41,27 +41,121 @@ namespace OpenSim.Services.PresenceService | |||
41 | { | 41 | { |
42 | public class PresenceService : PresenceServiceBase, IPresenceService | 42 | public class PresenceService : PresenceServiceBase, IPresenceService |
43 | { | 43 | { |
44 | // private static readonly ILog m_log = | 44 | private static readonly ILog m_log = |
45 | // LogManager.GetLogger( | 45 | LogManager.GetLogger( |
46 | // MethodBase.GetCurrentMethod().DeclaringType); | 46 | MethodBase.GetCurrentMethod().DeclaringType); |
47 | |||
48 | protected bool m_allowDuplicatePresences = false; | ||
47 | 49 | ||
48 | public PresenceService(IConfigSource config) | 50 | public PresenceService(IConfigSource config) |
49 | : base(config) | 51 | : base(config) |
50 | { | 52 | { |
53 | m_log.Debug("[PRESENCE SERVICE]: Starting presence service"); | ||
54 | |||
55 | IConfig presenceConfig = config.Configs["PresenceService"]; | ||
56 | if (presenceConfig != null) | ||
57 | { | ||
58 | m_allowDuplicatePresences = | ||
59 | presenceConfig.GetBoolean("AllowDuplicatePresences", | ||
60 | m_allowDuplicatePresences); | ||
61 | } | ||
51 | } | 62 | } |
52 | 63 | ||
53 | public bool Report(PresenceInfo presence) | 64 | public bool LoginAgent(string userID, UUID sessionID, |
65 | UUID secureSessionID) | ||
54 | { | 66 | { |
55 | PresenceData p = new PresenceData(); | 67 | //PresenceData[] d = m_Database.Get("UserID", userID); |
56 | p.Data = new Dictionary<string, string>(); | 68 | //m_Database.Get("UserID", userID); |
69 | |||
70 | if (!m_allowDuplicatePresences) | ||
71 | m_Database.Delete("UserID", userID.ToString()); | ||
72 | |||
73 | PresenceData data = new PresenceData(); | ||
57 | 74 | ||
58 | p.UUID = presence.PrincipalID; | 75 | data.UserID = userID; |
59 | p.currentRegion = presence.RegionID; | 76 | data.RegionID = UUID.Zero; |
77 | data.SessionID = sessionID; | ||
78 | data.Data = new Dictionary<string, string>(); | ||
79 | data.Data["SecureSessionID"] = secureSessionID.ToString(); | ||
80 | |||
81 | m_Database.Store(data); | ||
60 | 82 | ||
61 | foreach (KeyValuePair<string, string> kvp in presence.Data) | 83 | m_log.DebugFormat("[PRESENCE SERVICE]: LoginAgent {0} with session {1} and ssession {2}", |
62 | p.Data[kvp.Key] = kvp.Value; | 84 | userID, sessionID, secureSessionID); |
85 | return true; | ||
86 | } | ||
87 | |||
88 | public bool LogoutAgent(UUID sessionID) | ||
89 | { | ||
90 | m_log.DebugFormat("[PRESENCE SERVICE]: Session {0} logout", sessionID); | ||
91 | return m_Database.Delete("SessionID", sessionID.ToString()); | ||
92 | } | ||
93 | |||
94 | public bool LogoutRegionAgents(UUID regionID) | ||
95 | { | ||
96 | m_Database.LogoutRegionAgents(regionID); | ||
97 | |||
98 | return true; | ||
99 | } | ||
100 | |||
101 | |||
102 | public bool ReportAgent(UUID sessionID, UUID regionID) | ||
103 | { | ||
104 | // m_log.DebugFormat("[PRESENCE SERVICE]: ReportAgent with session {0} in region {1}", sessionID, regionID); | ||
105 | try | ||
106 | { | ||
107 | PresenceData pdata = m_Database.Get(sessionID); | ||
108 | if (pdata == null) | ||
109 | return false; | ||
110 | if (pdata.Data == null) | ||
111 | return false; | ||
63 | 112 | ||
64 | return false; | 113 | return m_Database.ReportAgent(sessionID, regionID); |
114 | } | ||
115 | catch (Exception e) | ||
116 | { | ||
117 | m_log.DebugFormat("[PRESENCE SERVICE]: ReportAgent threw exception {0}", e.StackTrace); | ||
118 | return false; | ||
119 | } | ||
65 | } | 120 | } |
121 | |||
122 | public PresenceInfo GetAgent(UUID sessionID) | ||
123 | { | ||
124 | PresenceInfo ret = new PresenceInfo(); | ||
125 | |||
126 | PresenceData data = m_Database.Get(sessionID); | ||
127 | if (data == null) | ||
128 | return null; | ||
129 | |||
130 | ret.UserID = data.UserID; | ||
131 | ret.RegionID = data.RegionID; | ||
132 | |||
133 | return ret; | ||
134 | } | ||
135 | |||
136 | public PresenceInfo[] GetAgents(string[] userIDs) | ||
137 | { | ||
138 | List<PresenceInfo> info = new List<PresenceInfo>(); | ||
139 | |||
140 | foreach (string userIDStr in userIDs) | ||
141 | { | ||
142 | PresenceData[] data = m_Database.Get("UserID", | ||
143 | userIDStr); | ||
144 | |||
145 | foreach (PresenceData d in data) | ||
146 | { | ||
147 | PresenceInfo ret = new PresenceInfo(); | ||
148 | |||
149 | ret.UserID = d.UserID; | ||
150 | ret.RegionID = d.RegionID; | ||
151 | |||
152 | info.Add(ret); | ||
153 | } | ||
154 | } | ||
155 | |||
156 | // m_log.DebugFormat("[PRESENCE SERVICE]: GetAgents for {0} userIDs found {1} presences", userIDs.Length, info.Count); | ||
157 | return info.ToArray(); | ||
158 | } | ||
159 | |||
66 | } | 160 | } |
67 | } | 161 | } |
diff --git a/OpenSim/Services/PresenceService/PresenceServiceBase.cs b/OpenSim/Services/PresenceService/PresenceServiceBase.cs index 60a246b..a4adb2f 100644 --- a/OpenSim/Services/PresenceService/PresenceServiceBase.cs +++ b/OpenSim/Services/PresenceService/PresenceServiceBase.cs | |||
@@ -44,7 +44,7 @@ namespace OpenSim.Services.PresenceService | |||
44 | { | 44 | { |
45 | string dllName = String.Empty; | 45 | string dllName = String.Empty; |
46 | string connString = String.Empty; | 46 | string connString = String.Empty; |
47 | string realm = "agents"; | 47 | string realm = "Presence"; |
48 | 48 | ||
49 | // | 49 | // |
50 | // Try reading the [DatabaseService] section, if it exists | 50 | // Try reading the [DatabaseService] section, if it exists |
@@ -77,7 +77,7 @@ namespace OpenSim.Services.PresenceService | |||
77 | 77 | ||
78 | m_Database = LoadPlugin<IPresenceData>(dllName, new Object[] { connString, realm }); | 78 | m_Database = LoadPlugin<IPresenceData>(dllName, new Object[] { connString, realm }); |
79 | if (m_Database == null) | 79 | if (m_Database == null) |
80 | throw new Exception("Could not find a storage interface in the given module"); | 80 | throw new Exception("Could not find a storage interface in the given module " + dllName); |
81 | 81 | ||
82 | } | 82 | } |
83 | } | 83 | } |
diff --git a/OpenSim/Services/UserAccountService/GridUserService.cs b/OpenSim/Services/UserAccountService/GridUserService.cs new file mode 100644 index 0000000..9b18915 --- /dev/null +++ b/OpenSim/Services/UserAccountService/GridUserService.cs | |||
@@ -0,0 +1,159 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using Nini.Config; | ||
32 | using OpenSim.Data; | ||
33 | using OpenSim.Services.Interfaces; | ||
34 | using OpenSim.Framework; | ||
35 | using OpenSim.Framework.Console; | ||
36 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
37 | |||
38 | using OpenMetaverse; | ||
39 | using log4net; | ||
40 | |||
41 | namespace OpenSim.Services.UserAccountService | ||
42 | { | ||
43 | public class GridUserService : GridUserServiceBase, IGridUserService | ||
44 | { | ||
45 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
46 | |||
47 | public GridUserService(IConfigSource config) : base(config) | ||
48 | { | ||
49 | m_log.Debug("[USER GRID SERVICE]: Starting user grid service"); | ||
50 | } | ||
51 | |||
52 | public GridUserInfo GetGridUserInfo(string userID) | ||
53 | { | ||
54 | GridUserData d = m_Database.Get(userID); | ||
55 | |||
56 | if (d == null) | ||
57 | return null; | ||
58 | |||
59 | GridUserInfo info = new GridUserInfo(); | ||
60 | info.UserID = d.UserID; | ||
61 | info.HomeRegionID = new UUID(d.Data["HomeRegionID"]); | ||
62 | info.HomePosition = Vector3.Parse(d.Data["HomePosition"]); | ||
63 | info.HomeLookAt = Vector3.Parse(d.Data["HomeLookAt"]); | ||
64 | |||
65 | info.LastRegionID = new UUID(d.Data["LastRegionID"]); | ||
66 | info.LastPosition = Vector3.Parse(d.Data["LastPosition"]); | ||
67 | info.LastLookAt = Vector3.Parse(d.Data["LastLookAt"]); | ||
68 | |||
69 | info.Online = bool.Parse(d.Data["Online"]); | ||
70 | info.Login = Util.ToDateTime(Convert.ToInt32(d.Data["Login"])); | ||
71 | info.Logout = Util.ToDateTime(Convert.ToInt32(d.Data["Logout"])); | ||
72 | |||
73 | return info; | ||
74 | } | ||
75 | |||
76 | public GridUserInfo LoggedIn(string userID) | ||
77 | { | ||
78 | m_log.DebugFormat("[GRID USER SERVICE]: User {0} is online", userID); | ||
79 | GridUserData d = m_Database.Get(userID); | ||
80 | |||
81 | if (d == null) | ||
82 | { | ||
83 | d = new GridUserData(); | ||
84 | d.UserID = userID; | ||
85 | } | ||
86 | |||
87 | d.Data["Online"] = true.ToString(); | ||
88 | d.Data["Login"] = Util.UnixTimeSinceEpoch().ToString(); | ||
89 | |||
90 | m_Database.Store(d); | ||
91 | |||
92 | return GetGridUserInfo(userID); | ||
93 | } | ||
94 | |||
95 | public bool LoggedOut(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) | ||
96 | { | ||
97 | m_log.DebugFormat("[GRID USER SERVICE]: User {0} is offline", userID); | ||
98 | GridUserData d = m_Database.Get(userID); | ||
99 | |||
100 | if (d == null) | ||
101 | { | ||
102 | d = new GridUserData(); | ||
103 | d.UserID = userID; | ||
104 | } | ||
105 | |||
106 | d.Data["Online"] = false.ToString(); | ||
107 | d.Data["Logout"] = Util.UnixTimeSinceEpoch().ToString(); | ||
108 | d.Data["LastRegionID"] = regionID.ToString(); | ||
109 | d.Data["LastPosition"] = lastPosition.ToString(); | ||
110 | d.Data["LastLookAt"] = lastLookAt.ToString(); | ||
111 | |||
112 | return m_Database.Store(d); | ||
113 | } | ||
114 | |||
115 | protected bool StoreGridUserInfo(GridUserInfo info) | ||
116 | { | ||
117 | GridUserData d = new GridUserData(); | ||
118 | |||
119 | d.Data["HomeRegionID"] = info.HomeRegionID.ToString(); | ||
120 | d.Data["HomePosition"] = info.HomePosition.ToString(); | ||
121 | d.Data["HomeLookAt"] = info.HomeLookAt.ToString(); | ||
122 | |||
123 | return m_Database.Store(d); | ||
124 | } | ||
125 | |||
126 | public bool SetHome(string userID, UUID homeID, Vector3 homePosition, Vector3 homeLookAt) | ||
127 | { | ||
128 | GridUserData d = m_Database.Get(userID); | ||
129 | if (d == null) | ||
130 | { | ||
131 | d = new GridUserData(); | ||
132 | d.UserID = userID; | ||
133 | } | ||
134 | |||
135 | d.Data["HomeRegionID"] = homeID.ToString(); | ||
136 | d.Data["HomePosition"] = homePosition.ToString(); | ||
137 | d.Data["HomeLookAt"] = homeLookAt.ToString(); | ||
138 | |||
139 | return m_Database.Store(d); | ||
140 | } | ||
141 | |||
142 | public bool SetLastPosition(string userID, UUID sessionID, UUID regionID, Vector3 lastPosition, Vector3 lastLookAt) | ||
143 | { | ||
144 | //m_log.DebugFormat("[Grid User Service]: SetLastPosition for {0}", userID); | ||
145 | GridUserData d = m_Database.Get(userID); | ||
146 | if (d == null) | ||
147 | { | ||
148 | d = new GridUserData(); | ||
149 | d.UserID = userID; | ||
150 | } | ||
151 | |||
152 | d.Data["LastRegionID"] = regionID.ToString(); | ||
153 | d.Data["LastPosition"] = lastPosition.ToString(); | ||
154 | d.Data["LastLookAt"] = lastLookAt.ToString(); | ||
155 | |||
156 | return m_Database.Store(d); | ||
157 | } | ||
158 | } | ||
159 | } \ No newline at end of file | ||
diff --git a/OpenSim/Services/UserAccountService/GridUserServiceBase.cs b/OpenSim/Services/UserAccountService/GridUserServiceBase.cs new file mode 100644 index 0000000..990cb63 --- /dev/null +++ b/OpenSim/Services/UserAccountService/GridUserServiceBase.cs | |||
@@ -0,0 +1,82 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Reflection; | ||
30 | using Nini.Config; | ||
31 | using OpenSim.Framework; | ||
32 | using OpenSim.Data; | ||
33 | using OpenSim.Services.Interfaces; | ||
34 | using OpenSim.Services.Base; | ||
35 | |||
36 | namespace OpenSim.Services.UserAccountService | ||
37 | { | ||
38 | public class GridUserServiceBase : ServiceBase | ||
39 | { | ||
40 | protected IGridUserData m_Database = null; | ||
41 | |||
42 | public GridUserServiceBase(IConfigSource config) : base(config) | ||
43 | { | ||
44 | string dllName = String.Empty; | ||
45 | string connString = String.Empty; | ||
46 | string realm = "GridUser"; | ||
47 | |||
48 | // | ||
49 | // Try reading the [DatabaseService] section, if it exists | ||
50 | // | ||
51 | IConfig dbConfig = config.Configs["DatabaseService"]; | ||
52 | if (dbConfig != null) | ||
53 | { | ||
54 | if (dllName == String.Empty) | ||
55 | dllName = dbConfig.GetString("StorageProvider", String.Empty); | ||
56 | if (connString == String.Empty) | ||
57 | connString = dbConfig.GetString("ConnectionString", String.Empty); | ||
58 | } | ||
59 | |||
60 | // | ||
61 | // [GridUsetService] section overrides [DatabaseService], if it exists | ||
62 | // | ||
63 | IConfig presenceConfig = config.Configs["GridUserService"]; | ||
64 | if (presenceConfig != null) | ||
65 | { | ||
66 | dllName = presenceConfig.GetString("StorageProvider", dllName); | ||
67 | connString = presenceConfig.GetString("ConnectionString", connString); | ||
68 | realm = presenceConfig.GetString("Realm", realm); | ||
69 | } | ||
70 | |||
71 | // | ||
72 | // We tried, but this doesn't exist. We can't proceed. | ||
73 | // | ||
74 | if (dllName.Equals(String.Empty)) | ||
75 | throw new Exception("No StorageProvider configured"); | ||
76 | |||
77 | m_Database = LoadPlugin<IGridUserData>(dllName, new Object[] { connString, realm }); | ||
78 | if (m_Database == null) | ||
79 | throw new Exception("Could not find a storage interface in the given module " + dllName); | ||
80 | } | ||
81 | } | ||
82 | } \ No newline at end of file | ||
diff --git a/OpenSim/Services/UserAccountService/UserAccountService.cs b/OpenSim/Services/UserAccountService/UserAccountService.cs new file mode 100644 index 0000000..ad06300 --- /dev/null +++ b/OpenSim/Services/UserAccountService/UserAccountService.cs | |||
@@ -0,0 +1,687 @@ | |||
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 | |||
28 | using System; | ||
29 | using System.Collections.Generic; | ||
30 | using System.Reflection; | ||
31 | using log4net; | ||
32 | using Nini.Config; | ||
33 | using OpenMetaverse; | ||
34 | using OpenSim.Data; | ||
35 | using OpenSim.Framework; | ||
36 | using OpenSim.Services.Interfaces; | ||
37 | using OpenSim.Framework.Console; | ||
38 | using GridRegion = OpenSim.Services.Interfaces.GridRegion; | ||
39 | |||
40 | namespace OpenSim.Services.UserAccountService | ||
41 | { | ||
42 | public class UserAccountService : UserAccountServiceBase, IUserAccountService | ||
43 | { | ||
44 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | ||
45 | private static UserAccountService m_RootInstance; | ||
46 | |||
47 | /// <summary> | ||
48 | /// Should we create default entries (minimum body parts/clothing, avatar wearable entries) for a new avatar? | ||
49 | /// </summary> | ||
50 | private bool m_CreateDefaultAvatarEntries; | ||
51 | |||
52 | protected IGridService m_GridService; | ||
53 | protected IAuthenticationService m_AuthenticationService; | ||
54 | protected IGridUserService m_GridUserService; | ||
55 | protected IInventoryService m_InventoryService; | ||
56 | protected IAvatarService m_AvatarService; | ||
57 | |||
58 | public UserAccountService(IConfigSource config) | ||
59 | : base(config) | ||
60 | { | ||
61 | IConfig userConfig = config.Configs["UserAccountService"]; | ||
62 | if (userConfig == null) | ||
63 | throw new Exception("No UserAccountService configuration"); | ||
64 | |||
65 | string gridServiceDll = userConfig.GetString("GridService", string.Empty); | ||
66 | if (gridServiceDll != string.Empty) | ||
67 | m_GridService = LoadPlugin<IGridService>(gridServiceDll, new Object[] { config }); | ||
68 | |||
69 | string authServiceDll = userConfig.GetString("AuthenticationService", string.Empty); | ||
70 | if (authServiceDll != string.Empty) | ||
71 | m_AuthenticationService = LoadPlugin<IAuthenticationService>(authServiceDll, new Object[] { config }); | ||
72 | |||
73 | string presenceServiceDll = userConfig.GetString("GridUserService", string.Empty); | ||
74 | if (presenceServiceDll != string.Empty) | ||
75 | m_GridUserService = LoadPlugin<IGridUserService>(presenceServiceDll, new Object[] { config }); | ||
76 | |||
77 | string invServiceDll = userConfig.GetString("InventoryService", string.Empty); | ||
78 | if (invServiceDll != string.Empty) | ||
79 | m_InventoryService = LoadPlugin<IInventoryService>(invServiceDll, new Object[] { config }); | ||
80 | |||
81 | string avatarServiceDll = userConfig.GetString("AvatarService", string.Empty); | ||
82 | if (avatarServiceDll != string.Empty) | ||
83 | m_AvatarService = LoadPlugin<IAvatarService>(avatarServiceDll, new Object[] { config }); | ||
84 | |||
85 | m_CreateDefaultAvatarEntries = userConfig.GetBoolean("CreateDefaultAvatarEntries", false); | ||
86 | |||
87 | // In case there are several instances of this class in the same process, | ||
88 | // the console commands are only registered for the root instance | ||
89 | if (m_RootInstance == null && MainConsole.Instance != null) | ||
90 | { | ||
91 | m_RootInstance = this; | ||
92 | MainConsole.Instance.Commands.AddCommand("UserService", false, | ||
93 | "create user", | ||
94 | "create user [<first> [<last> [<pass> [<email> [<user id>]]]]]", | ||
95 | "Create a new user", HandleCreateUser); | ||
96 | |||
97 | MainConsole.Instance.Commands.AddCommand("UserService", false, | ||
98 | "reset user password", | ||
99 | "reset user password [<first> [<last> [<password>]]]", | ||
100 | "Reset a user password", HandleResetUserPassword); | ||
101 | |||
102 | MainConsole.Instance.Commands.AddCommand("UserService", false, | ||
103 | "set user level", | ||
104 | "set user level [<first> [<last> [<level>]]]", | ||
105 | "Set user level. If >= 200 and 'allow_grid_gods = true' in OpenSim.ini, " | ||
106 | + "this account will be treated as god-moded. " | ||
107 | + "It will also affect the 'login level' command. ", | ||
108 | HandleSetUserLevel); | ||
109 | |||
110 | MainConsole.Instance.Commands.AddCommand("UserService", false, | ||
111 | "show account", | ||
112 | "show account <first> <last>", | ||
113 | "Show account details for the given user", HandleShowAccount); | ||
114 | } | ||
115 | } | ||
116 | |||
117 | #region IUserAccountService | ||
118 | |||
119 | public UserAccount GetUserAccount(UUID scopeID, string firstName, | ||
120 | string lastName) | ||
121 | { | ||
122 | // m_log.DebugFormat( | ||
123 | // "[USER ACCOUNT SERVICE]: Retrieving account by username for {0} {1}, scope {2}", | ||
124 | // firstName, lastName, scopeID); | ||
125 | |||
126 | UserAccountData[] d; | ||
127 | |||
128 | if (scopeID != UUID.Zero) | ||
129 | { | ||
130 | d = m_Database.Get( | ||
131 | new string[] { "ScopeID", "FirstName", "LastName" }, | ||
132 | new string[] { scopeID.ToString(), firstName, lastName }); | ||
133 | if (d.Length < 1) | ||
134 | { | ||
135 | d = m_Database.Get( | ||
136 | new string[] { "ScopeID", "FirstName", "LastName" }, | ||
137 | new string[] { UUID.Zero.ToString(), firstName, lastName }); | ||
138 | } | ||
139 | } | ||
140 | else | ||
141 | { | ||
142 | d = m_Database.Get( | ||
143 | new string[] { "FirstName", "LastName" }, | ||
144 | new string[] { firstName, lastName }); | ||
145 | } | ||
146 | |||
147 | if (d.Length < 1) | ||
148 | return null; | ||
149 | |||
150 | return MakeUserAccount(d[0]); | ||
151 | } | ||
152 | |||
153 | private UserAccount MakeUserAccount(UserAccountData d) | ||
154 | { | ||
155 | UserAccount u = new UserAccount(); | ||
156 | u.FirstName = d.FirstName; | ||
157 | u.LastName = d.LastName; | ||
158 | u.PrincipalID = d.PrincipalID; | ||
159 | u.ScopeID = d.ScopeID; | ||
160 | if (d.Data.ContainsKey("Email") && d.Data["Email"] != null) | ||
161 | u.Email = d.Data["Email"].ToString(); | ||
162 | else | ||
163 | u.Email = string.Empty; | ||
164 | u.Created = Convert.ToInt32(d.Data["Created"].ToString()); | ||
165 | if (d.Data.ContainsKey("UserTitle") && d.Data["UserTitle"] != null) | ||
166 | u.UserTitle = d.Data["UserTitle"].ToString(); | ||
167 | else | ||
168 | u.UserTitle = string.Empty; | ||
169 | if (d.Data.ContainsKey("UserLevel") && d.Data["UserLevel"] != null) | ||
170 | Int32.TryParse(d.Data["UserLevel"], out u.UserLevel); | ||
171 | if (d.Data.ContainsKey("UserFlags") && d.Data["UserFlags"] != null) | ||
172 | Int32.TryParse(d.Data["UserFlags"], out u.UserFlags); | ||
173 | if (d.Data.ContainsKey("UserCountry") && d.Data["UserCountry"] != null) | ||
174 | u.UserCountry = d.Data["UserCountry"].ToString(); | ||
175 | else | ||
176 | u.UserTitle = string.Empty; | ||
177 | |||
178 | if (d.Data.ContainsKey("ServiceURLs") && d.Data["ServiceURLs"] != null) | ||
179 | { | ||
180 | string[] URLs = d.Data["ServiceURLs"].ToString().Split(new char[] { ' ' }); | ||
181 | u.ServiceURLs = new Dictionary<string, object>(); | ||
182 | |||
183 | foreach (string url in URLs) | ||
184 | { | ||
185 | string[] parts = url.Split(new char[] { '=' }); | ||
186 | |||
187 | if (parts.Length != 2) | ||
188 | continue; | ||
189 | |||
190 | string name = System.Web.HttpUtility.UrlDecode(parts[0]); | ||
191 | string val = System.Web.HttpUtility.UrlDecode(parts[1]); | ||
192 | |||
193 | u.ServiceURLs[name] = val; | ||
194 | } | ||
195 | } | ||
196 | else | ||
197 | u.ServiceURLs = new Dictionary<string, object>(); | ||
198 | |||
199 | return u; | ||
200 | } | ||
201 | |||
202 | public UserAccount GetUserAccount(UUID scopeID, string email) | ||
203 | { | ||
204 | UserAccountData[] d; | ||
205 | |||
206 | if (scopeID != UUID.Zero) | ||
207 | { | ||
208 | d = m_Database.Get( | ||
209 | new string[] { "ScopeID", "Email" }, | ||
210 | new string[] { scopeID.ToString(), email }); | ||
211 | if (d.Length < 1) | ||
212 | { | ||
213 | d = m_Database.Get( | ||
214 | new string[] { "ScopeID", "Email" }, | ||
215 | new string[] { UUID.Zero.ToString(), email }); | ||
216 | } | ||
217 | } | ||
218 | else | ||
219 | { | ||
220 | d = m_Database.Get( | ||
221 | new string[] { "Email" }, | ||
222 | new string[] { email }); | ||
223 | } | ||
224 | |||
225 | if (d.Length < 1) | ||
226 | return null; | ||
227 | |||
228 | return MakeUserAccount(d[0]); | ||
229 | } | ||
230 | |||
231 | public UserAccount GetUserAccount(UUID scopeID, UUID principalID) | ||
232 | { | ||
233 | UserAccountData[] d; | ||
234 | |||
235 | if (scopeID != UUID.Zero) | ||
236 | { | ||
237 | d = m_Database.Get( | ||
238 | new string[] { "ScopeID", "PrincipalID" }, | ||
239 | new string[] { scopeID.ToString(), principalID.ToString() }); | ||
240 | if (d.Length < 1) | ||
241 | { | ||
242 | d = m_Database.Get( | ||
243 | new string[] { "ScopeID", "PrincipalID" }, | ||
244 | new string[] { UUID.Zero.ToString(), principalID.ToString() }); | ||
245 | } | ||
246 | } | ||
247 | else | ||
248 | { | ||
249 | d = m_Database.Get( | ||
250 | new string[] { "PrincipalID" }, | ||
251 | new string[] { principalID.ToString() }); | ||
252 | } | ||
253 | |||
254 | if (d.Length < 1) | ||
255 | { | ||
256 | return null; | ||
257 | } | ||
258 | |||
259 | return MakeUserAccount(d[0]); | ||
260 | } | ||
261 | |||
262 | public bool StoreUserAccount(UserAccount data) | ||
263 | { | ||
264 | // m_log.DebugFormat( | ||
265 | // "[USER ACCOUNT SERVICE]: Storing user account for {0} {1} {2}, scope {3}", | ||
266 | // data.FirstName, data.LastName, data.PrincipalID, data.ScopeID); | ||
267 | |||
268 | UserAccountData d = new UserAccountData(); | ||
269 | |||
270 | d.FirstName = data.FirstName; | ||
271 | d.LastName = data.LastName; | ||
272 | d.PrincipalID = data.PrincipalID; | ||
273 | d.ScopeID = data.ScopeID; | ||
274 | d.Data = new Dictionary<string, string>(); | ||
275 | d.Data["Email"] = data.Email; | ||
276 | d.Data["Created"] = data.Created.ToString(); | ||
277 | d.Data["UserLevel"] = data.UserLevel.ToString(); | ||
278 | d.Data["UserFlags"] = data.UserFlags.ToString(); | ||
279 | if (data.UserTitle != null) | ||
280 | d.Data["UserTitle"] = data.UserTitle.ToString(); | ||
281 | |||
282 | List<string> parts = new List<string>(); | ||
283 | |||
284 | foreach (KeyValuePair<string, object> kvp in data.ServiceURLs) | ||
285 | { | ||
286 | string key = System.Web.HttpUtility.UrlEncode(kvp.Key); | ||
287 | string val = System.Web.HttpUtility.UrlEncode(kvp.Value.ToString()); | ||
288 | parts.Add(key + "=" + val); | ||
289 | } | ||
290 | |||
291 | d.Data["ServiceURLs"] = string.Join(" ", parts.ToArray()); | ||
292 | |||
293 | return m_Database.Store(d); | ||
294 | } | ||
295 | |||
296 | public List<UserAccount> GetUserAccounts(UUID scopeID, string query) | ||
297 | { | ||
298 | UserAccountData[] d = m_Database.GetUsers(scopeID, query.Trim()); | ||
299 | |||
300 | if (d == null) | ||
301 | return new List<UserAccount>(); | ||
302 | |||
303 | List<UserAccount> ret = new List<UserAccount>(); | ||
304 | |||
305 | foreach (UserAccountData data in d) | ||
306 | ret.Add(MakeUserAccount(data)); | ||
307 | |||
308 | return ret; | ||
309 | } | ||
310 | |||
311 | public List<UserAccount> GetUserAccountsWhere(UUID scopeID, string where) | ||
312 | { | ||
313 | UserAccountData[] d = m_Database.GetUsersWhere(scopeID, where); | ||
314 | |||
315 | if (d == null) | ||
316 | return new List<UserAccount>(); | ||
317 | |||
318 | List<UserAccount> ret = new List<UserAccount>(); | ||
319 | |||
320 | foreach (UserAccountData data in d) | ||
321 | ret.Add(MakeUserAccount(data)); | ||
322 | |||
323 | return ret; | ||
324 | } | ||
325 | |||
326 | #endregion | ||
327 | |||
328 | #region Console commands | ||
329 | |||
330 | /// <summary> | ||
331 | /// Handle the create user command from the console. | ||
332 | /// </summary> | ||
333 | /// <param name="cmdparams">string array with parameters: firstname, lastname, password, locationX, locationY, email</param> | ||
334 | protected void HandleCreateUser(string module, string[] cmdparams) | ||
335 | { | ||
336 | string firstName; | ||
337 | string lastName; | ||
338 | string password; | ||
339 | string email; | ||
340 | string rawPrincipalId; | ||
341 | |||
342 | List<char> excluded = new List<char>(new char[]{' '}); | ||
343 | |||
344 | if (cmdparams.Length < 3) | ||
345 | firstName = MainConsole.Instance.CmdPrompt("First name", "Default", excluded); | ||
346 | else firstName = cmdparams[2]; | ||
347 | |||
348 | if (cmdparams.Length < 4) | ||
349 | lastName = MainConsole.Instance.CmdPrompt("Last name", "User", excluded); | ||
350 | else lastName = cmdparams[3]; | ||
351 | |||
352 | if (cmdparams.Length < 5) | ||
353 | password = MainConsole.Instance.PasswdPrompt("Password"); | ||
354 | else password = cmdparams[4]; | ||
355 | |||
356 | if (cmdparams.Length < 6) | ||
357 | email = MainConsole.Instance.CmdPrompt("Email", ""); | ||
358 | else email = cmdparams[5]; | ||
359 | |||
360 | if (cmdparams.Length < 7) | ||
361 | rawPrincipalId = MainConsole.Instance.CmdPrompt("User ID", UUID.Random().ToString()); | ||
362 | else | ||
363 | rawPrincipalId = cmdparams[6]; | ||
364 | |||
365 | UUID principalId = UUID.Zero; | ||
366 | if (!UUID.TryParse(rawPrincipalId, out principalId)) | ||
367 | throw new Exception(string.Format("ID {0} is not a valid UUID", rawPrincipalId)); | ||
368 | |||
369 | CreateUser(UUID.Zero, principalId, firstName, lastName, password, email); | ||
370 | } | ||
371 | |||
372 | protected void HandleShowAccount(string module, string[] cmdparams) | ||
373 | { | ||
374 | if (cmdparams.Length != 4) | ||
375 | { | ||
376 | MainConsole.Instance.Output("Usage: show account <first-name> <last-name>"); | ||
377 | return; | ||
378 | } | ||
379 | |||
380 | string firstName = cmdparams[2]; | ||
381 | string lastName = cmdparams[3]; | ||
382 | |||
383 | UserAccount ua = GetUserAccount(UUID.Zero, firstName, lastName); | ||
384 | |||
385 | if (ua == null) | ||
386 | { | ||
387 | MainConsole.Instance.OutputFormat("No user named {0} {1}", firstName, lastName); | ||
388 | return; | ||
389 | } | ||
390 | |||
391 | MainConsole.Instance.OutputFormat("Name: {0}", ua.Name); | ||
392 | MainConsole.Instance.OutputFormat("ID: {0}", ua.PrincipalID); | ||
393 | MainConsole.Instance.OutputFormat("Title: {0}", ua.UserTitle); | ||
394 | MainConsole.Instance.OutputFormat("E-mail: {0}", ua.Email); | ||
395 | MainConsole.Instance.OutputFormat("Created: {0}", Utils.UnixTimeToDateTime(ua.Created)); | ||
396 | MainConsole.Instance.OutputFormat("Level: {0}", ua.UserLevel); | ||
397 | MainConsole.Instance.OutputFormat("Flags: {0}", ua.UserFlags); | ||
398 | foreach (KeyValuePair<string, Object> kvp in ua.ServiceURLs) | ||
399 | MainConsole.Instance.OutputFormat("{0}: {1}", kvp.Key, kvp.Value); | ||
400 | } | ||
401 | |||
402 | protected void HandleResetUserPassword(string module, string[] cmdparams) | ||
403 | { | ||
404 | string firstName; | ||
405 | string lastName; | ||
406 | string newPassword; | ||
407 | |||
408 | if (cmdparams.Length < 4) | ||
409 | firstName = MainConsole.Instance.CmdPrompt("First name"); | ||
410 | else firstName = cmdparams[3]; | ||
411 | |||
412 | if (cmdparams.Length < 5) | ||
413 | lastName = MainConsole.Instance.CmdPrompt("Last name"); | ||
414 | else lastName = cmdparams[4]; | ||
415 | |||
416 | if (cmdparams.Length < 6) | ||
417 | newPassword = MainConsole.Instance.PasswdPrompt("New password"); | ||
418 | else newPassword = cmdparams[5]; | ||
419 | |||
420 | UserAccount account = GetUserAccount(UUID.Zero, firstName, lastName); | ||
421 | if (account == null) | ||
422 | { | ||
423 | MainConsole.Instance.OutputFormat("No such user as {0} {1}", firstName, lastName); | ||
424 | return; | ||
425 | } | ||
426 | |||
427 | bool success = false; | ||
428 | if (m_AuthenticationService != null) | ||
429 | success = m_AuthenticationService.SetPassword(account.PrincipalID, newPassword); | ||
430 | |||
431 | if (!success) | ||
432 | MainConsole.Instance.OutputFormat("Unable to reset password for account {0} {1}.", firstName, lastName); | ||
433 | else | ||
434 | MainConsole.Instance.OutputFormat("Password reset for user {0} {1}", firstName, lastName); | ||
435 | } | ||
436 | |||
437 | protected void HandleSetUserLevel(string module, string[] cmdparams) | ||
438 | { | ||
439 | string firstName; | ||
440 | string lastName; | ||
441 | string rawLevel; | ||
442 | int level; | ||
443 | |||
444 | if (cmdparams.Length < 4) | ||
445 | firstName = MainConsole.Instance.CmdPrompt("First name"); | ||
446 | else firstName = cmdparams[3]; | ||
447 | |||
448 | if (cmdparams.Length < 5) | ||
449 | lastName = MainConsole.Instance.CmdPrompt("Last name"); | ||
450 | else lastName = cmdparams[4]; | ||
451 | |||
452 | UserAccount account = GetUserAccount(UUID.Zero, firstName, lastName); | ||
453 | if (account == null) { | ||
454 | MainConsole.Instance.OutputFormat("No such user"); | ||
455 | return; | ||
456 | } | ||
457 | |||
458 | if (cmdparams.Length < 6) | ||
459 | rawLevel = MainConsole.Instance.CmdPrompt("User level"); | ||
460 | else rawLevel = cmdparams[5]; | ||
461 | |||
462 | if(int.TryParse(rawLevel, out level) == false) { | ||
463 | MainConsole.Instance.OutputFormat("Invalid user level"); | ||
464 | return; | ||
465 | } | ||
466 | |||
467 | account.UserLevel = level; | ||
468 | |||
469 | bool success = StoreUserAccount(account); | ||
470 | if (!success) | ||
471 | MainConsole.Instance.OutputFormat("Unable to set user level for account {0} {1}.", firstName, lastName); | ||
472 | else | ||
473 | MainConsole.Instance.OutputFormat("User level set for user {0} {1} to {2}", firstName, lastName, level); | ||
474 | } | ||
475 | |||
476 | #endregion | ||
477 | |||
478 | /// <summary> | ||
479 | /// Create a user | ||
480 | /// </summary> | ||
481 | /// <param name="scopeID">Allows hosting of multiple grids in a single database. Normally left as UUID.Zero</param> | ||
482 | /// <param name="principalID">ID of the user</param> | ||
483 | /// <param name="firstName"></param> | ||
484 | /// <param name="lastName"></param> | ||
485 | /// <param name="password"></param> | ||
486 | /// <param name="email"></param> | ||
487 | public UserAccount CreateUser(UUID scopeID, UUID principalID, string firstName, string lastName, string password, string email) | ||
488 | { | ||
489 | UserAccount account = GetUserAccount(UUID.Zero, firstName, lastName); | ||
490 | if (null == account) | ||
491 | { | ||
492 | account = new UserAccount(UUID.Zero, principalID, firstName, lastName, email); | ||
493 | if (account.ServiceURLs == null || (account.ServiceURLs != null && account.ServiceURLs.Count == 0)) | ||
494 | { | ||
495 | account.ServiceURLs = new Dictionary<string, object>(); | ||
496 | account.ServiceURLs["HomeURI"] = string.Empty; | ||
497 | account.ServiceURLs["GatekeeperURI"] = string.Empty; | ||
498 | account.ServiceURLs["InventoryServerURI"] = string.Empty; | ||
499 | account.ServiceURLs["AssetServerURI"] = string.Empty; | ||
500 | } | ||
501 | |||
502 | if (StoreUserAccount(account)) | ||
503 | { | ||
504 | bool success; | ||
505 | if (m_AuthenticationService != null) | ||
506 | { | ||
507 | success = m_AuthenticationService.SetPassword(account.PrincipalID, password); | ||
508 | if (!success) | ||
509 | m_log.WarnFormat("[USER ACCOUNT SERVICE]: Unable to set password for account {0} {1}.", | ||
510 | firstName, lastName); | ||
511 | } | ||
512 | |||
513 | GridRegion home = null; | ||
514 | if (m_GridService != null) | ||
515 | { | ||
516 | List<GridRegion> defaultRegions = m_GridService.GetDefaultRegions(UUID.Zero); | ||
517 | if (defaultRegions != null && defaultRegions.Count >= 1) | ||
518 | home = defaultRegions[0]; | ||
519 | |||
520 | if (m_GridUserService != null && home != null) | ||
521 | m_GridUserService.SetHome(account.PrincipalID.ToString(), home.RegionID, new Vector3(128, 128, 0), new Vector3(0, 1, 0)); | ||
522 | else | ||
523 | m_log.WarnFormat("[USER ACCOUNT SERVICE]: Unable to set home for account {0} {1}.", | ||
524 | firstName, lastName); | ||
525 | } | ||
526 | else | ||
527 | { | ||
528 | m_log.WarnFormat("[USER ACCOUNT SERVICE]: Unable to retrieve home region for account {0} {1}.", | ||
529 | firstName, lastName); | ||
530 | } | ||
531 | |||
532 | if (m_InventoryService != null) | ||
533 | { | ||
534 | success = m_InventoryService.CreateUserInventory(account.PrincipalID); | ||
535 | if (!success) | ||
536 | { | ||
537 | m_log.WarnFormat("[USER ACCOUNT SERVICE]: Unable to create inventory for account {0} {1}.", | ||
538 | firstName, lastName); | ||
539 | } | ||
540 | else | ||
541 | { | ||
542 | m_log.DebugFormat( | ||
543 | "[USER ACCOUNT SERVICE]; Created user inventory for {0} {1}", firstName, lastName); | ||
544 | } | ||
545 | |||
546 | if (m_CreateDefaultAvatarEntries) | ||
547 | CreateDefaultAppearanceEntries(account.PrincipalID); | ||
548 | } | ||
549 | |||
550 | m_log.InfoFormat( | ||
551 | "[USER ACCOUNT SERVICE]: Account {0} {1} {2} created successfully", | ||
552 | firstName, lastName, account.PrincipalID); | ||
553 | } | ||
554 | else | ||
555 | { | ||
556 | m_log.ErrorFormat("[USER ACCOUNT SERVICE]: Account creation failed for account {0} {1}", firstName, lastName); | ||
557 | } | ||
558 | } | ||
559 | else | ||
560 | { | ||
561 | m_log.ErrorFormat("[USER ACCOUNT SERVICE]: A user with the name {0} {1} already exists!", firstName, lastName); | ||
562 | } | ||
563 | |||
564 | return account; | ||
565 | } | ||
566 | |||
567 | private void CreateDefaultAppearanceEntries(UUID principalID) | ||
568 | { | ||
569 | m_log.DebugFormat("[USER ACCOUNT SERVICE]: Creating default appearance items for {0}", principalID); | ||
570 | |||
571 | InventoryFolderBase bodyPartsFolder = m_InventoryService.GetFolderForType(principalID, AssetType.Bodypart); | ||
572 | |||
573 | InventoryItemBase eyes = new InventoryItemBase(UUID.Random(), principalID); | ||
574 | eyes.AssetID = new UUID("4bb6fa4d-1cd2-498a-a84c-95c1a0e745a7"); | ||
575 | eyes.Name = "Default Eyes"; | ||
576 | eyes.CreatorId = principalID.ToString(); | ||
577 | eyes.AssetType = (int)AssetType.Bodypart; | ||
578 | eyes.InvType = (int)InventoryType.Wearable; | ||
579 | eyes.Folder = bodyPartsFolder.ID; | ||
580 | eyes.BasePermissions = (uint)PermissionMask.All; | ||
581 | eyes.CurrentPermissions = (uint)PermissionMask.All; | ||
582 | eyes.EveryOnePermissions = (uint)PermissionMask.All; | ||
583 | eyes.GroupPermissions = (uint)PermissionMask.All; | ||
584 | eyes.NextPermissions = (uint)PermissionMask.All; | ||
585 | eyes.Flags = (uint)WearableType.Eyes; | ||
586 | m_InventoryService.AddItem(eyes); | ||
587 | |||
588 | InventoryItemBase shape = new InventoryItemBase(UUID.Random(), principalID); | ||
589 | shape.AssetID = AvatarWearable.DEFAULT_BODY_ASSET; | ||
590 | shape.Name = "Default Shape"; | ||
591 | shape.CreatorId = principalID.ToString(); | ||
592 | shape.AssetType = (int)AssetType.Bodypart; | ||
593 | shape.InvType = (int)InventoryType.Wearable; | ||
594 | shape.Folder = bodyPartsFolder.ID; | ||
595 | shape.BasePermissions = (uint)PermissionMask.All; | ||
596 | shape.CurrentPermissions = (uint)PermissionMask.All; | ||
597 | shape.EveryOnePermissions = (uint)PermissionMask.All; | ||
598 | shape.GroupPermissions = (uint)PermissionMask.All; | ||
599 | shape.NextPermissions = (uint)PermissionMask.All; | ||
600 | shape.Flags = (uint)WearableType.Shape; | ||
601 | m_InventoryService.AddItem(shape); | ||
602 | |||
603 | InventoryItemBase skin = new InventoryItemBase(UUID.Random(), principalID); | ||
604 | skin.AssetID = AvatarWearable.DEFAULT_SKIN_ASSET; | ||
605 | skin.Name = "Default Skin"; | ||
606 | skin.CreatorId = principalID.ToString(); | ||
607 | skin.AssetType = (int)AssetType.Bodypart; | ||
608 | skin.InvType = (int)InventoryType.Wearable; | ||
609 | skin.Folder = bodyPartsFolder.ID; | ||
610 | skin.BasePermissions = (uint)PermissionMask.All; | ||
611 | skin.CurrentPermissions = (uint)PermissionMask.All; | ||
612 | skin.EveryOnePermissions = (uint)PermissionMask.All; | ||
613 | skin.GroupPermissions = (uint)PermissionMask.All; | ||
614 | skin.NextPermissions = (uint)PermissionMask.All; | ||
615 | skin.Flags = (uint)WearableType.Skin; | ||
616 | m_InventoryService.AddItem(skin); | ||
617 | |||
618 | InventoryItemBase hair = new InventoryItemBase(UUID.Random(), principalID); | ||
619 | hair.AssetID = AvatarWearable.DEFAULT_HAIR_ASSET; | ||
620 | hair.Name = "Default Hair"; | ||
621 | hair.CreatorId = principalID.ToString(); | ||
622 | hair.AssetType = (int)AssetType.Bodypart; | ||
623 | hair.InvType = (int)InventoryType.Wearable; | ||
624 | hair.Folder = bodyPartsFolder.ID; | ||
625 | hair.BasePermissions = (uint)PermissionMask.All; | ||
626 | hair.CurrentPermissions = (uint)PermissionMask.All; | ||
627 | hair.EveryOnePermissions = (uint)PermissionMask.All; | ||
628 | hair.GroupPermissions = (uint)PermissionMask.All; | ||
629 | hair.NextPermissions = (uint)PermissionMask.All; | ||
630 | hair.Flags = (uint)WearableType.Hair; | ||
631 | m_InventoryService.AddItem(hair); | ||
632 | |||
633 | InventoryFolderBase clothingFolder = m_InventoryService.GetFolderForType(principalID, AssetType.Clothing); | ||
634 | |||
635 | InventoryItemBase shirt = new InventoryItemBase(UUID.Random(), principalID); | ||
636 | shirt.AssetID = AvatarWearable.DEFAULT_SHIRT_ASSET; | ||
637 | shirt.Name = "Default Shirt"; | ||
638 | shirt.CreatorId = principalID.ToString(); | ||
639 | shirt.AssetType = (int)AssetType.Clothing; | ||
640 | shirt.InvType = (int)InventoryType.Wearable; | ||
641 | shirt.Folder = clothingFolder.ID; | ||
642 | shirt.BasePermissions = (uint)PermissionMask.All; | ||
643 | shirt.CurrentPermissions = (uint)PermissionMask.All; | ||
644 | shirt.EveryOnePermissions = (uint)PermissionMask.All; | ||
645 | shirt.GroupPermissions = (uint)PermissionMask.All; | ||
646 | shirt.NextPermissions = (uint)PermissionMask.All; | ||
647 | shirt.Flags = (uint)WearableType.Shirt; | ||
648 | m_InventoryService.AddItem(shirt); | ||
649 | |||
650 | InventoryItemBase pants = new InventoryItemBase(UUID.Random(), principalID); | ||
651 | pants.AssetID = AvatarWearable.DEFAULT_PANTS_ASSET; | ||
652 | pants.Name = "Default Pants"; | ||
653 | pants.CreatorId = principalID.ToString(); | ||
654 | pants.AssetType = (int)AssetType.Clothing; | ||
655 | pants.InvType = (int)InventoryType.Wearable; | ||
656 | pants.Folder = clothingFolder.ID; | ||
657 | pants.BasePermissions = (uint)PermissionMask.All; | ||
658 | pants.CurrentPermissions = (uint)PermissionMask.All; | ||
659 | pants.EveryOnePermissions = (uint)PermissionMask.All; | ||
660 | pants.GroupPermissions = (uint)PermissionMask.All; | ||
661 | pants.NextPermissions = (uint)PermissionMask.All; | ||
662 | pants.Flags = (uint)WearableType.Pants; | ||
663 | m_InventoryService.AddItem(pants); | ||
664 | |||
665 | if (m_AvatarService != null) | ||
666 | { | ||
667 | m_log.DebugFormat("[USER ACCOUNT SERVICE]: Creating default avatar entries for {0}", principalID); | ||
668 | |||
669 | AvatarWearable[] wearables = new AvatarWearable[6]; | ||
670 | wearables[AvatarWearable.EYES] = new AvatarWearable(eyes.ID, eyes.AssetID); | ||
671 | wearables[AvatarWearable.BODY] = new AvatarWearable(shape.ID, shape.AssetID); | ||
672 | wearables[AvatarWearable.SKIN] = new AvatarWearable(skin.ID, skin.AssetID); | ||
673 | wearables[AvatarWearable.HAIR] = new AvatarWearable(hair.ID, hair.AssetID); | ||
674 | wearables[AvatarWearable.SHIRT] = new AvatarWearable(shirt.ID, shirt.AssetID); | ||
675 | wearables[AvatarWearable.PANTS] = new AvatarWearable(pants.ID, pants.AssetID); | ||
676 | |||
677 | AvatarAppearance ap = new AvatarAppearance(); | ||
678 | for (int i = 0; i < 6; i++) | ||
679 | { | ||
680 | ap.SetWearable(i, wearables[i]); | ||
681 | } | ||
682 | |||
683 | m_AvatarService.SetAppearance(principalID, ap); | ||
684 | } | ||
685 | } | ||
686 | } | ||
687 | } \ No newline at end of file | ||
diff --git a/OpenSim/Services/UserService/UserServiceBase.cs b/OpenSim/Services/UserAccountService/UserAccountServiceBase.cs index fea8b01..c1a7b76 100644 --- a/OpenSim/Services/UserService/UserServiceBase.cs +++ b/OpenSim/Services/UserAccountService/UserAccountServiceBase.cs | |||
@@ -40,20 +40,29 @@ namespace OpenSim.Services.UserAccountService | |||
40 | 40 | ||
41 | public UserAccountServiceBase(IConfigSource config) : base(config) | 41 | public UserAccountServiceBase(IConfigSource config) : base(config) |
42 | { | 42 | { |
43 | string dllName = String.Empty; | ||
44 | string connString = String.Empty; | ||
45 | string realm = "UserAccounts"; | ||
46 | |||
47 | IConfig dbConfig = config.Configs["DatabaseService"]; | ||
48 | if (dbConfig != null) | ||
49 | { | ||
50 | dllName = dbConfig.GetString("StorageProvider", String.Empty); | ||
51 | connString = dbConfig.GetString("ConnectionString", String.Empty); | ||
52 | } | ||
53 | |||
43 | IConfig userConfig = config.Configs["UserAccountService"]; | 54 | IConfig userConfig = config.Configs["UserAccountService"]; |
44 | if (userConfig == null) | 55 | if (userConfig == null) |
45 | throw new Exception("No UserAccountService configuration"); | 56 | throw new Exception("No UserAccountService configuration"); |
46 | 57 | ||
47 | string dllName = userConfig.GetString("StorageProvider", | 58 | dllName = userConfig.GetString("StorageProvider", dllName); |
48 | String.Empty); | ||
49 | 59 | ||
50 | if (dllName == String.Empty) | 60 | if (dllName == String.Empty) |
51 | throw new Exception("No StorageProvider configured"); | 61 | throw new Exception("No StorageProvider configured"); |
52 | 62 | ||
53 | string connString = userConfig.GetString("ConnectionString", | 63 | connString = userConfig.GetString("ConnectionString", connString); |
54 | String.Empty); | ||
55 | 64 | ||
56 | string realm = userConfig.GetString("Realm", "users"); | 65 | realm = userConfig.GetString("Realm", realm); |
57 | 66 | ||
58 | m_Database = LoadPlugin<IUserAccountData>(dllName, new Object[] {connString, realm}); | 67 | m_Database = LoadPlugin<IUserAccountData>(dllName, new Object[] {connString, realm}); |
59 | 68 | ||