2011-06-01 23:08:05 +00:00
// SparkleShare, a collaboration and sharing tool.
2011-05-14 17:10:24 +00:00
// Copyright (C) 2010 Hylke Bons <hylkebons@gmail.com>
//
// 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 3 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, see <http://www.gnu.org/licenses/>.
using System ;
2011-11-03 23:15:59 +00:00
using System.Collections ;
2011-05-14 17:10:24 +00:00
using System.Collections.Generic ;
2011-05-28 23:52:46 +00:00
using System.Timers ;
2011-11-03 23:15:59 +00:00
using System.Linq ;
2011-05-14 17:10:24 +00:00
namespace SparkleLib {
2011-05-22 00:02:16 +00:00
public class SparkleAnnouncement {
public readonly string FolderIdentifier ;
public readonly string Message ;
public SparkleAnnouncement ( string folder_identifier , string message )
{
FolderIdentifier = folder_identifier ;
Message = message ;
}
}
public static class SparkleListenerFactory {
2011-06-28 19:54:47 +00:00
private static List < SparkleListenerBase > listeners = new List < SparkleListenerBase > ( ) ;
2011-05-22 00:02:16 +00:00
2011-06-28 19:54:47 +00:00
public static SparkleListenerBase CreateListener ( string folder_name , string folder_identifier )
2011-05-22 00:02:16 +00:00
{
2011-07-24 01:00:40 +00:00
string uri = SparkleConfig . DefaultConfig . GetFolderOptionalAttribute (
folder_name , "announcements_url" ) ;
2011-06-28 19:54:47 +00:00
2011-07-23 15:57:46 +00:00
if ( uri = = null ) {
2011-06-28 19:54:47 +00:00
// This is SparkleShare's centralized notification service.
// Don't worry, we only use this server as a backup if you
// don't have your own. All data needed to connect is hashed and
// we don't store any personal information ever
2011-07-23 15:57:46 +00:00
2011-09-25 17:28:24 +00:00
uri = "tcp://204.62.14.135:1986" ; // TODO: announcements.sparkleshare.org
2011-06-28 19:54:47 +00:00
}
2011-05-22 00:02:16 +00:00
2011-07-23 15:57:46 +00:00
Uri announce_uri = new Uri ( uri ) ;
2011-07-23 14:27:07 +00:00
// We use only one listener per server to keep
// the number of connections as low as possible
2011-05-22 00:02:16 +00:00
foreach ( SparkleListenerBase listener in listeners ) {
2011-06-28 19:54:47 +00:00
if ( listener . Server . Equals ( announce_uri ) ) {
2011-07-23 14:27:07 +00:00
SparkleHelpers . DebugInfo ( "ListenerFactory" ,
"Refered to existing listener for " + announce_uri ) ;
2011-05-22 00:02:16 +00:00
listener . AlsoListenTo ( folder_identifier ) ;
2011-06-28 18:36:47 +00:00
return ( SparkleListenerBase ) listener ;
2011-05-22 00:02:16 +00:00
}
}
2011-07-23 14:27:07 +00:00
// Create a new listener with the appropriate
// type if one doesn't exist yet for that server
switch ( announce_uri . Scheme ) {
case "tcp" :
listeners . Add ( new SparkleListenerTcp ( announce_uri , folder_identifier ) ) ;
break ;
case "irc" :
listeners . Add ( new SparkleListenerIrc ( announce_uri , folder_identifier ) ) ;
break ;
default :
2011-09-25 17:22:35 +00:00
listeners . Add ( new SparkleListenerTcp ( announce_uri , folder_identifier ) ) ;
2011-07-23 14:27:07 +00:00
break ;
2011-06-28 18:36:47 +00:00
}
2011-06-28 19:54:47 +00:00
SparkleHelpers . DebugInfo ( "ListenerFactory" , "Issued new listener for " + announce_uri ) ;
2011-06-28 21:13:28 +00:00
return ( SparkleListenerBase ) listeners [ listeners . Count - 1 ] ;
2011-05-22 00:02:16 +00:00
}
}
2011-05-14 17:10:24 +00:00
// A persistent connection to the server that
// listens for change notifications
public abstract class SparkleListenerBase {
// We've connected to the server
public event ConnectedEventHandler Connected ;
public delegate void ConnectedEventHandler ( ) ;
// We've disconnected from the server
public event DisconnectedEventHandler Disconnected ;
public delegate void DisconnectedEventHandler ( ) ;
// We've been notified about a remote
// change by the channel
2011-05-28 23:52:46 +00:00
public event AnnouncementEventHandler Announcement ;
public delegate void AnnouncementEventHandler ( SparkleAnnouncement announcement ) ;
2011-05-19 15:41:46 +00:00
2011-05-14 17:10:24 +00:00
2011-05-22 00:02:16 +00:00
public abstract void Connect ( ) ;
public abstract void Announce ( SparkleAnnouncement announcent ) ;
public abstract void AlsoListenTo ( string folder_identifier ) ;
2011-05-14 17:10:24 +00:00
public abstract bool IsConnected { get ; }
2011-05-19 15:14:50 +00:00
2011-05-22 00:02:16 +00:00
2011-05-22 17:52:50 +00:00
protected List < string > channels = new List < string > ( ) ;
2011-11-03 23:15:59 +00:00
protected Hashtable last_announce = new Hashtable ( ) ;
2011-05-22 17:37:36 +00:00
protected List < SparkleAnnouncement > queue_up = new List < SparkleAnnouncement > ( ) ;
protected List < SparkleAnnouncement > queue_down = new List < SparkleAnnouncement > ( ) ;
2011-05-22 00:02:16 +00:00
protected bool is_connecting ;
2011-06-28 18:36:47 +00:00
protected Uri server ;
2011-05-29 19:01:56 +00:00
protected Timer reconnect_timer = new Timer { Interval = 60 * 1000 , Enabled = true } ;
2011-05-22 00:02:16 +00:00
2011-07-23 14:27:07 +00:00
public SparkleListenerBase ( Uri server , string folder_identifier )
{
this . server = server ;
2011-06-28 18:36:47 +00:00
this . reconnect_timer . Elapsed + = delegate {
2011-05-29 19:01:56 +00:00
if ( ! IsConnected & & ! this . is_connecting )
2011-05-28 23:52:46 +00:00
Reconnect ( ) ;
2011-06-28 18:36:47 +00:00
} ;
2011-05-22 00:02:16 +00:00
2011-06-28 18:36:47 +00:00
this . reconnect_timer . Start ( ) ;
2011-05-28 23:52:46 +00:00
}
2011-05-22 00:02:16 +00:00
2011-07-23 14:27:07 +00:00
public void AnnounceBase ( SparkleAnnouncement announcement )
{
2011-05-22 00:02:16 +00:00
if ( IsConnected ) {
2011-07-23 14:27:07 +00:00
SparkleHelpers . DebugInfo ( "Listener" ,
"Announcing to " + announcement . FolderIdentifier + " on " + this . server ) ;
2011-05-22 00:02:16 +00:00
Announce ( announcement ) ;
2011-05-22 17:52:50 +00:00
2011-05-22 00:02:16 +00:00
} else {
SparkleHelpers . DebugInfo ( "Listener" , "Not connected to " + this . server + ". Queuing message" ) ;
2011-05-22 17:37:36 +00:00
this . queue_up . Add ( announcement ) ;
2011-05-22 00:02:16 +00:00
}
}
2011-05-14 17:10:24 +00:00
2011-11-04 00:05:25 +00:00
public string NextQueueDownMessage ( string folder_identifier )
2011-05-14 17:10:24 +00:00
{
2011-11-04 00:05:25 +00:00
foreach ( SparkleAnnouncement announcement in this . queue_down . GetRange ( 0 , this . queue_down . Count ) ) {
2011-05-22 17:37:36 +00:00
if ( announcement . FolderIdentifier . Equals ( folder_identifier ) ) {
2011-11-04 00:05:25 +00:00
string message = announcement . Message ;
2011-05-22 17:37:36 +00:00
this . queue_down . Remove ( announcement ) ;
2011-11-04 00:05:25 +00:00
return message ;
2011-05-22 17:37:36 +00:00
}
}
2011-11-04 00:05:25 +00:00
return null ;
2011-05-14 17:10:24 +00:00
}
2011-05-22 00:02:16 +00:00
2011-05-28 23:52:46 +00:00
public void Reconnect ( )
{
SparkleHelpers . DebugInfo ( "Listener" , "Trying to reconnect to " + this . server ) ;
Connect ( ) ;
}
2011-05-14 17:10:24 +00:00
public void OnConnected ( )
{
2011-05-22 00:02:16 +00:00
SparkleHelpers . DebugInfo ( "Listener" , "Connected to " + Server ) ;
2011-05-19 15:41:46 +00:00
2011-05-14 17:10:24 +00:00
if ( Connected ! = null )
Connected ( ) ;
2011-05-19 15:41:46 +00:00
2011-05-22 17:37:36 +00:00
if ( this . queue_up . Count > 0 ) {
2011-10-25 18:24:30 +00:00
SparkleHelpers . DebugInfo ( "Listener" , "Delivering " + this . queue_up . Count + " queued messages..." ) ;
2011-07-23 14:27:07 +00:00
2011-10-25 18:24:30 +00:00
foreach ( SparkleAnnouncement announcement in this . queue_up . GetRange ( 0 , this . queue_up . Count ) ) {
2011-05-22 00:02:16 +00:00
AnnounceBase ( announcement ) ;
2011-05-28 23:52:46 +00:00
this . queue_up . Remove ( announcement ) ;
}
2011-05-19 15:41:46 +00:00
}
2011-05-14 17:10:24 +00:00
}
2011-05-22 00:02:16 +00:00
2011-05-14 17:10:24 +00:00
public void OnDisconnected ( )
{
2011-07-24 18:22:17 +00:00
SparkleHelpers . DebugInfo ( "Listener" , "Disonnected from " + Server ) ;
2011-05-19 15:41:46 +00:00
2011-05-14 17:10:24 +00:00
if ( Disconnected ! = null )
Disconnected ( ) ;
}
2011-05-22 00:02:16 +00:00
2011-05-28 23:52:46 +00:00
public void OnAnnouncement ( SparkleAnnouncement announcement )
2011-05-14 17:10:24 +00:00
{
2011-11-03 23:15:59 +00:00
SparkleHelpers . DebugInfo ( "Listener" , "Got message " + announcement . Message + " from " + announcement . FolderIdentifier + " on " + this . server ) ;
2011-11-03 16:22:12 +00:00
2011-11-03 23:15:59 +00:00
if ( this . last_announce . ContainsKey ( announcement . FolderIdentifier ) ) {
SparkleHelpers . DebugInfo ( "Listener" , "Received previous message from " + announcement . FolderIdentifier + " on " + this . server ) ;
if ( this . last_announce [ announcement . FolderIdentifier ] . Equals ( announcement . Message ) ) {
SparkleHelpers . DebugInfo ( "Listener" , "Ignoring already processed announcment " + announcement . Message + " from " + announcement . FolderIdentifier + " on " + this . server ) ;
return ;
}
}
SparkleHelpers . DebugInfo ( "Listener" , "Processing message " + announcement . Message + " from " + announcement . FolderIdentifier + " on " + this . server ) ;
if ( this . last_announce . ContainsKey ( announcement . FolderIdentifier ) )
this . last_announce . Remove ( announcement . FolderIdentifier ) ;
this . last_announce . Add ( announcement . FolderIdentifier , announcement . Message ) ;
2011-11-03 16:54:01 +00:00
this . queue_down . Add ( announcement ) ;
2011-05-19 15:41:46 +00:00
2011-05-28 23:52:46 +00:00
if ( Announcement ! = null )
Announcement ( announcement ) ;
2011-05-14 17:10:24 +00:00
}
2011-05-22 17:52:50 +00:00
2011-05-29 19:01:56 +00:00
public virtual void Dispose ( )
{
this . reconnect_timer . Dispose ( ) ;
}
2011-06-28 18:36:47 +00:00
public Uri Server {
2011-05-22 17:52:50 +00:00
get {
return this . server ;
}
}
public bool IsConnecting {
get {
return this . is_connecting ;
}
}
2011-05-14 17:10:24 +00:00
}
}