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

AbstractMsnP2PApplication.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 Anculus.Core;

namespace Galaxium.Protocol.Msn
{
      public abstract class AbstractMsnP2PApplication : IMsnP2PApplication
      {
            public event EventHandler Complete;
            public event EventHandler Error;
            
            IMsnP2PBridge _bridge;
            MsnAccount _local;
            MsnContact _remote;
            MsnSession _session;
            Queue<P2PMessage> _outQueue = new Queue<P2PMessage> ();
            
            static uint _dbgAppCount = 0;
            protected uint _dbgAppID = _dbgAppCount++;
            
            public virtual uint AppID
            {
                  // Return the AppID MsnP2PUtility got from the MsnP2PApplicationAttribute
                  get { return MsnP2PUtility.GetAppID (this); }
            }
            
            public IMsnP2PBridge Bridge
            {
                  get { return _bridge; }
            }
            
            public MsnAccount Local
            {
                  get { return _local; }
            }
            
            public MsnContact Remote
            {
                  get { return _remote; }
            }
            
            public MsnSession Session
            {
                  get { return _session; }
            }
            
            protected Queue<P2PMessage> OutQueue
            {
                  get { return _outQueue; }
            }
            
            public AbstractMsnP2PApplication (MsnAccount local, MsnContact remote)
            {
                  _local = local;
                  _remote = remote;
                  _session = _local.Session;
                  
                  Log.Debug ("P2PApp {0} created ({1})", _dbgAppID, GetType().Name);
                  
                  MigrateToOptimalBridge ();
            }
            
            public virtual void Dispose ()
            {
                  Log.Debug ("P2PApp {0} disposed", _dbgAppID);
                  
                  if (_bridge != null)
                  {
                        _bridge.BridgeReady -= OnBridgeReady;
                        _bridge.BridgeClosed -= OnBridgeClosed;
                  }
            }
            
            protected virtual void MigrateToOptimalBridge ()
            {
                  if (_remote.DirectBridge != null)
                  {
                        Migrate (_remote.DirectBridge);
                        return;
                  }
                  
                  //Log.Debug ("Calling GETSWITCHBOARD from the AbstractMsnP2PApplication");
                  
                  SBConnection sb = _session.GetSwitchboard (false, _remote);
                  Migrate (sb);
            }
            
            protected virtual void Migrate (IMsnP2PBridge bridge)
            {
                  if (bridge == _bridge)
                        return;
                  
                  Log.Debug ("P2PApp {0} migrating to {1}", _dbgAppID, bridge);
                  
                  if (_bridge != null)
                  {
                        _bridge.BridgeReady -= OnBridgeReady;
                        _bridge.BridgeClosed -= OnBridgeClosed;
                  }
                  
                  _bridge = bridge;
                  _bridge.BridgeReady += OnBridgeReady;
                  _bridge.BridgeClosed += OnBridgeClosed;
                  
                  ProcessOutQueue (false);
            }
            
            protected virtual void OnBridgeReady (object sender, EventArgs args)
            {
                  //Log.Debug ("P2PApp {0} bridge ready, {1} messages queued", _dbgAppID, _outQueue.Count);
                  ProcessOutQueue (true);
            }
            
            protected virtual void OnBridgeClosed (object sender, EventArgs args)
            {
                  Log.Debug ("P2PApp {0} bridge closed", _dbgAppID);
                  
                  _bridge.BridgeReady -= OnBridgeReady;
                  _bridge.BridgeClosed -= OnBridgeClosed;
                  
                  _bridge = null;
                  
                  if (_outQueue.Count > 0)
                        MigrateToOptimalBridge ();
            }
            
            public abstract bool ProcessMessage (IMsnP2PBridge bridge, P2PMessage msg);
            
            public virtual void Send (P2PMessage msg, AckHandler ackHandler)
            {
                  // If not an ack, set the footer to the application ID
                  if ((msg.Header.Flags & P2PHeaderFlag.Ack) != P2PHeaderFlag.Ack)
                        msg.Footer = MsnP2PUtility.GetAppID (this);
                  
                  P2PMessage[] msgs = MsnP2PUtility.SplitMessage (msg, _bridge != null ? _bridge.MaxDataSize : 1150);
                  
                  lock (_outQueue)
                  {
                        foreach (P2PMessage m in msgs)
                              _outQueue.Enqueue (m);
                  }
                  
                  if (ackHandler != null)
                        MsnP2PUtility.RegisterAckHandler (msg.Header.AckID, ackHandler);
                  
                  ProcessOutQueue (false);
            }
            
            public void Send (P2PMessage msg)
            {
                  Send (msg, null);
            }
            
            protected virtual void ProcessOutQueue (bool forceReady)
            {
                  if (_outQueue.Count == 0)
                  {
                        //Log.Debug ("Out queue is empty");
                        return;
                  }
                  
                  if (_bridge == null)
                  {
                        //Log.Debug ("ProcessOutQueue with no bridge");
                        MigrateToOptimalBridge ();
                        return;
                  }
                  
                  if (!(_bridge.Ready || forceReady))
                  {
                        //Log.Debug ("Bridge not ready");
                        return;
                  }
                  
                  //Log.Debug ("P2PApp {0} sending", _dbgAppID);
                  
                  lock (_outQueue)
                        _bridge.Send (_outQueue.Dequeue ());
            }
            
            protected void OnComplete ()
            {
                  Log.Debug ("P2PApp {0} complete", _dbgAppID);
                  
                  if (this.Complete != null)
                        this.Complete (this, EventArgs.Empty);
            }
            
            protected void OnError ()
            {
                  if (this.Error != null)
                        this.Error (this, EventArgs.Empty);
            }
      }
      
      public abstract class AbstractMsnP2PSessionApplication : AbstractMsnP2PApplication, IMsnP2PSessionApplication
      {
            public event EventHandler Began;
            public event EventHandler LocallyCancelled;
            public event EventHandler RemotelyCancelled;
            
            MsnP2PSession _p2pSession;
            
            public virtual bool AutoAccept
            {
                  get { return false; }
            }
            
            public MsnP2PSession P2PSession
            {
                  get { return _p2pSession; }
                  set
                  {
                        _p2pSession = value;
                        
                        _p2pSession.Closing += P2PSessionClosing;
                  }
            }
            
            public AbstractMsnP2PSessionApplication (MsnP2PSession p2pSession)
                  : base (p2pSession.Local, p2pSession.Remote)
            {
                  P2PSession = p2pSession;
                  
                  Log.Debug ("P2PApp {0} associated with session {1}", _dbgAppID, _p2pSession.SessionID);
            }
            
            public AbstractMsnP2PSessionApplication (MsnAccount local, MsnContact remote)
                  : base (local, remote)
            {
            }
            
            public override void Dispose ()
            {
                  _p2pSession.Closing -= P2PSessionClosing;
                  
                  base.Dispose ();
            }
            
            public virtual bool CheckInvite (SLPRequestMessage invite)
            {
                  // If the invite isn't for us, it isn't valid
                  return invite.To == invite.Session.Account;
            }
            
            public abstract string CreateInviteContext ();
            
            public virtual void Begin ()
            {
                  OnBegan ();
            }
            
            public virtual void Accept ()
            {
                  _p2pSession.Accept ();
            }
            
            public virtual void Decline ()
            {
                  _p2pSession.Decline ();
            }
            
            public virtual void Cancel ()
            {
                  OnLocallyCancelled ();
                  _p2pSession.Close ();
            }
            
            public override void Send (P2PMessage msg, AckHandler ackHandler)
            {
                  msg.Header.SessionID = _p2pSession.SessionID;
                  
                  // Set the MessageID, but only if it's not already set
                  if (msg.Header.MessageID == 0)
                        msg.Header.MessageID = _p2pSession.NextID ();
                  
                  base.Send (msg, ackHandler);
            }
            
            internal void OnBegan ()
            {
                  Log.Debug ("P2PApp {0} began", _dbgAppID);
                  
                  if (this.Began != null)
                        this.Began (this, EventArgs.Empty);
            }
            
            internal void OnLocallyCancelled ()
            {
                  Log.Debug ("P2PApp {0} cancelled locally", _dbgAppID);
                  
                  if (this.LocallyCancelled != null)
                        this.LocallyCancelled (this, EventArgs.Empty);
            }
            
            internal void OnRemotelyCancelled ()
            {
                  Log.Debug ("P2PApp {0} cancelled remotely", _dbgAppID);
                  
                  if (this.RemotelyCancelled != null)
                        this.RemotelyCancelled (this, EventArgs.Empty);
            }
            
            void P2PSessionClosing (object sender, EventArgs args)
            {
                  OnRemotelyCancelled ();
            }
      }
}

Generated by  Doxygen 1.6.0   Back to index