Logo Search packages:      
Sourcecode: galaxium version File versions  Download package

MsnSoapService.cs

/*
 * Galaxium Messenger
 * 
 * Copyright (C) 2008 Paul Burton <paulburton89@gmail.com>
 * 
 * License: GNU General Public License (GPL)
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation; either version 2 of the License, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

using System;
using System.Collections.Generic;
using System.IO;
using System.Net;
using System.Reflection;
using System.Threading;
using System.Web.Services;
using System.Web.Services.Protocols;

using Anculus.Core;

using Galaxium.Core;

namespace Galaxium.Protocol.Msn.Soap
{
      public class MsnSoapService : SoapHttpClientProtocol
      {
            IConfigurationSection _config = Configuration.Protocol.Section["MSN"];
            IConfigurationSection _serviceConfig;
            bool _forceContentType = false;
            int _timeout;
            int _attempts;
            MsnSession _session;
            List<string> _urls = new List<string> ();
            
            delegate object[] InvokeDelegate (string method_name, object[] parameters, bool saveState);
            Dictionary<IAsyncResult, InvokeDelegate> _asyncDelegates = new Dictionary<IAsyncResult, InvokeDelegate> ();
            
            protected bool ForceContentType
            {
                  set { _forceContentType = value; }
            }
            
            public MsnSession Session
            {
                  get { return _session; }
            }
            
            public IEnumerable<string> Urls
            {
                  get { return _urls; }
            }
            
            public MsnSoapService (MsnSession session)
            {
                  UserAgent = SoapConstants.UserAgent;
                  AllowAutoRedirect = true;
                  
                  _session = session;
                  
                  _timeout = _config.GetInt ("SOAPTimeout", 10000);
                  _attempts = _config.GetInt ("SOAPAttempts", 10);
                  
                  _serviceConfig = ConfigurationUtility.Accounts[Session.Account.Protocol.Name][Session.Account.UniqueIdentifier]["SOAP"][GetType ().Name];
                  
                  Timeout = _timeout;
            }
            
            protected override WebRequest GetWebRequest (Uri uri)
            {
                  WebRequest request = base.GetWebRequest (uri);
                  
                  if (Configuration.Proxy.Section.GetBool (Configuration.Proxy.UseProxy.Name, Configuration.Proxy.UseProxy.Default))
                  {
                        string host = string.Empty;
                        int port = 0;
                        string username = string.Empty;
                        string password = string.Empty;
                        
                        if (request.RequestUri.OriginalString.Contains ("https://"))
                        {
                              if (Configuration.Proxy.Section.GetBool (Configuration.Proxy.UseSame.Name, Configuration.Proxy.UseSame.Default))
                              {
                                    host = Configuration.Proxy.Section.GetString (Configuration.Proxy.HttpHost.Name, Configuration.Proxy.HttpHost.Default);
                                    port = Configuration.Proxy.Section.GetInt (Configuration.Proxy.HttpPort.Name, Configuration.Proxy.HttpPort.Default);
                                    username = Configuration.Proxy.Section.GetString (Configuration.Proxy.HttpUsername.Name, Configuration.Proxy.HttpUsername.Default);
                                    password = Configuration.Proxy.Section.GetString (Configuration.Proxy.HttpPassword.Name, Configuration.Proxy.HttpPassword.Default);
                              }
                              else
                              {
                                    host = Configuration.Proxy.Section.GetString (Configuration.Proxy.HttpsHost.Name, Configuration.Proxy.HttpsHost.Default);
                                    port = Configuration.Proxy.Section.GetInt (Configuration.Proxy.HttpsPort.Name, Configuration.Proxy.HttpsPort.Default);
                                    username = Configuration.Proxy.Section.GetString (Configuration.Proxy.HttpsUsername.Name, Configuration.Proxy.HttpsUsername.Default);
                                    password = Configuration.Proxy.Section.GetString (Configuration.Proxy.HttpsPassword.Name, Configuration.Proxy.HttpsPassword.Default);
                              }
                        }
                        else if (request.RequestUri.OriginalString.Contains ("http://"))
                        {
                              host = Configuration.Proxy.Section.GetString (Configuration.Proxy.HttpHost.Name, Configuration.Proxy.HttpHost.Default);
                              port = Configuration.Proxy.Section.GetInt (Configuration.Proxy.HttpPort.Name, Configuration.Proxy.HttpPort.Default);
                              username = Configuration.Proxy.Section.GetString (Configuration.Proxy.HttpUsername.Name, Configuration.Proxy.HttpUsername.Default);
                              password = Configuration.Proxy.Section.GetString (Configuration.Proxy.HttpPassword.Name, Configuration.Proxy.HttpPassword.Default);
                        }
                        
                        (request as HttpWebRequest).Proxy = new WebProxy (host, port);
                        (request as HttpWebRequest).Proxy.Credentials = new NetworkCredential (username, password);
                  }
                  
                  return request;
            }
            
            protected override WebResponse GetWebResponse (WebRequest request)
            {
                  request.Timeout = _timeout;
                  (request as HttpWebRequest).AllowAutoRedirect = true;
                  (request as HttpWebRequest).KeepAlive = false;
                  
                  return new MsnSoapWebResponse (base.GetWebResponse (request), _forceContentType ? "text/xml" : null);
            }

            protected override WebResponse GetWebResponse (WebRequest request, IAsyncResult result)
            {
                  request.Timeout = _timeout;
                  (request as HttpWebRequest).AllowAutoRedirect = true;
                  (request as HttpWebRequest).KeepAlive = false;
                  
                  return new MsnSoapWebResponse (base.GetWebResponse (request, result), _forceContentType ? "text/xml" : null);
            }
            
            protected virtual object[] SaveState ()
            {
                  List<object> state = new List<object> ();
                  
                  foreach (FieldInfo field in this.GetType ().GetFields ())
                  {
                        if (field.FieldType.IsSubclassOf (typeof (SoapHeader)) && (field.FieldType.GetInterface ("ICloneable") != null))
                        {
                              object header = field.GetValue (this);
                              
                              Log.Debug ("Saving cloned header {0}", field.FieldType.Name);
                              
                              if (header != null)
                              {
                                    // Clone the header and save it
                                    state.Add ((header as ICloneable).Clone ());
                              }
                              else
                                    state.Add (null);
                        }
                  }
                  
                  return state.ToArray ();
            }
            
            protected virtual void LoadState (object[] state)
            {
                  int i = 0;
                  
                  foreach (FieldInfo field in this.GetType ().GetFields ())
                  {
                        if (field.FieldType.IsSubclassOf (typeof (SoapHeader)) && (field.FieldType.GetInterface ("ICloneable") != null))
                        {
                              Log.Debug ("Restoring header {0}", field.FieldType.Name);
                              
                              field.SetValue (this, state[i++]);
                        }
                  }
            }
            
            protected virtual bool HandleFault (SoapException ex)
            {
                  return false;
            }
            
            protected virtual object[] Invoke (string method_name, object[] parameters, bool saveState)
            {
                  foreach (RequireSecurityTokensAttribute att in this.GetType ().GetMethod (method_name).GetCustomAttributes (typeof (RequireSecurityTokensAttribute), true))
                        _session.RequireSecurityTokens (att.Domains);
                  
                  object[] state = saveState ? SaveState () : new object[0];
                  
                  for (int attempt = 0; attempt < _attempts; attempt++)
                  {
                        DateTime startTime = DateTime.Now;
                        
                        if (saveState && (attempt > 0))
                              LoadState (state);
                        
                        if (string.IsNullOrEmpty (Url))
                              SwitchUrl ();
                        
                        try
                        {
                              Log.Debug ("Invoking {0} (attempt {1} of {2}) on {3}", method_name, attempt + 1, _attempts, Url);
                              object[] ret = base.Invoke (method_name, parameters);
                              Log.Debug ("Invoke {0} on {1} successful on attempt {2}", method_name, Url, attempt + 1);
                              
                              _serviceConfig.SetString ("LastSuccessfulURL", Url);
                                                      
                              return ret;
                        }
                        catch (TargetException ex)
                        {
                              // Skip any further attempts
                              attempt = _attempts - 1;
                              
                              throw ex;
                        }
                        catch (Exception ex)
                        {
                              if ((ex is SoapException) && !HandleFault (ex as SoapException))
                              {
                                    // Skip any further attempts
                                    attempt = _attempts - 1;
                              }
                              
                              // Ensure we wait at least the timeout before retrying
                              
                              //Log.Warn (ex, "Error invoking {0} on {1}", method_name, Url);
                              
                              if (attempt == _attempts - 1)
                                    throw ex;
                              
                              if ((ex is WebException) && !(ex is SoapException))
                                    SwitchUrl ();
                              
                              if ((DateTime.Now - startTime).TotalMilliseconds < _timeout - 100)
                              {
                                    int delay = _timeout - (int)(DateTime.Now - startTime).TotalMilliseconds;
                                    Log.Debug ("Waiting {0}ms before retrying", delay);
                                    Thread.Sleep (delay);
                              }
                        }
                  }
                  
                  throw new ApplicationException ("Unknown SOAP invoke error");
            }
            
            public new virtual object[] Invoke (string method_name, object[] parameters)
            {
                  return Invoke (method_name, parameters, false);
            }
            
            public new IAsyncResult BeginInvoke (string method_name, object[] parameters, AsyncCallback callback, object asyncState)
            {
                  // We have to use our own delegate so that our own Invoke is called rather than base.Invoke which doesn't
                  // retry requests
                  
                  InvokeDelegate del = new InvokeDelegate (Invoke);
                  IAsyncResult asyncResult = del.BeginInvoke (method_name, parameters, true, delegate (IAsyncResult result)
                  {
                        if (callback != null)
                        {
                              ThreadUtility.SyncDispatch (new VoidDelegate (delegate
                              {
                                    callback (result);
                              }));
                        }
                  }, asyncState);
                  
                  _asyncDelegates.Add (asyncResult, del);
                  
                  return asyncResult;
            }
            
            public new object[] EndInvoke (IAsyncResult asyncResult)
            {
                  if (!_asyncDelegates.ContainsKey (asyncResult))
                  {
                        Log.Error ("EndInvoke called with an invalid asyncResult");
                        return null;
                  }
                  
                  Exception ex = null;
                  object[] ret = null;
                  
                  try
                  {
                        ret = _asyncDelegates[asyncResult].EndInvoke (asyncResult);
                  }
                  catch (Exception e)
                  {
                        ex = e;
                  }
                  
                  _asyncDelegates.Remove (asyncResult);
                  
                  if (ex != null)
                        throw ex;
                  
                  return ret;
            }
            
            protected void AddUrl (string url)
            {
                  _urls.Add (url);
            }
            
            protected void SwitchUrl ()
            {
                  int i;
                  
                  if (string.IsNullOrEmpty (Url) && _urls.Contains (_serviceConfig.GetString ("LastSuccessfulURL", string.Empty)))
                        i = _urls.IndexOf (_serviceConfig.GetString ("LastSuccessfulURL"));
                  else
                        i = _urls.IndexOf (Url) + 1;
                  
                  if (i >= _urls.Count)
                        i = 0;
                  
                  SwitchUrl (_urls[i]);
            }
            
            protected void SwitchUrl (string url)
            {
                  if (!_urls.Contains (url))
                        AddUrl (url);
                  
                  if (Url == url)
                        return;
                  
                  Log.Debug ("Switching to Url {0}", url);
                  
                  Url = url;
            }
      }           
}

Generated by  Doxygen 1.6.0   Back to index