Refactor the invite system, warn if cloning's taking place already

This commit is contained in:
Hylke Bons 2012-02-12 22:25:20 +01:00
parent 1e8e6b8363
commit 77add3df11
5 changed files with 110 additions and 182 deletions

View file

@ -42,6 +42,7 @@ namespace SparkleLib {
public string RemoteUrl; public string RemoteUrl;
public string [] ExcludeRules; public string [] ExcludeRules;
public string [] Warnings; public string [] Warnings;
public bool IsActive { get; private set; }
private Thread thread; private Thread thread;
@ -50,6 +51,7 @@ namespace SparkleLib {
{ {
TargetFolder = target_folder; TargetFolder = target_folder;
RemoteUrl = server + "/" + remote_folder; RemoteUrl = server + "/" + remote_folder;
IsActive = false;
ExcludeRules = new string [] { ExcludeRules = new string [] {
// gedit and emacs // gedit and emacs
@ -125,6 +127,7 @@ namespace SparkleLib {
// Clones the remote repository // Clones the remote repository
public void Start () public void Start ()
{ {
IsActive = true;
SparkleHelpers.DebugInfo ("Fetcher", "[" + TargetFolder + "] Fetching folder: " + RemoteUrl); SparkleHelpers.DebugInfo ("Fetcher", "[" + TargetFolder + "] Fetching folder: " + RemoteUrl);
if (Started != null) if (Started != null)
@ -149,6 +152,7 @@ namespace SparkleLib {
SparkleHelpers.DebugInfo ("Fetcher", "Finished"); SparkleHelpers.DebugInfo ("Fetcher", "Finished");
EnableHostKeyCheckingForHost (host); EnableHostKeyCheckingForHost (host);
IsActive = false;
if (Finished != null) if (Finished != null)
Finished (Warnings); Finished (Warnings);
@ -157,6 +161,7 @@ namespace SparkleLib {
SparkleHelpers.DebugInfo ("Fetcher", "Failed"); SparkleHelpers.DebugInfo ("Fetcher", "Failed");
EnableHostKeyCheckingForHost (host); EnableHostKeyCheckingForHost (host);
IsActive = false;
if (Failed != null) if (Failed != null)
Failed (); Failed ();

View file

@ -28,10 +28,8 @@ namespace SparkleShare {
public SparkleBubblesController () public SparkleBubblesController ()
{ {
Program.Controller.ConflictNotificationRaised += delegate { Program.Controller.AlertNotificationRaised += delegate (string title, string message) {
ShowBubble ("Conflict detected.", ShowBubble (title, message, null);
"Don't worry, SparkleShare made a copy of each conflicting file.",
null);
}; };
Program.Controller.NotificationRaised += delegate (SparkleChangeSet change_set) { Program.Controller.NotificationRaised += delegate (SparkleChangeSet change_set) {

View file

@ -67,12 +67,12 @@ namespace SparkleShare {
public event OnInviteHandler OnInvite; public event OnInviteHandler OnInvite;
public delegate void OnInviteHandler (SparkleInvite invite); public delegate void OnInviteHandler (SparkleInvite invite);
public event ConflictNotificationRaisedHandler ConflictNotificationRaised;
public delegate void ConflictNotificationRaisedHandler ();
public event NotificationRaisedEventHandler NotificationRaised; public event NotificationRaisedEventHandler NotificationRaised;
public delegate void NotificationRaisedEventHandler (SparkleChangeSet change_set); public delegate void NotificationRaisedEventHandler (SparkleChangeSet change_set);
public event AlertNotificationRaisedEventHandler AlertNotificationRaised;
public delegate void AlertNotificationRaisedEventHandler (string title, string message);
public event NoteNotificationRaisedEventHandler NoteNotificationRaised; public event NoteNotificationRaisedEventHandler NoteNotificationRaised;
public delegate void NoteNotificationRaisedEventHandler (SparkleUser user, string folder_name); public delegate void NoteNotificationRaisedEventHandler (SparkleUser user, string folder_name);
@ -126,16 +126,23 @@ namespace SparkleShare {
FolderListChanged (); FolderListChanged ();
}; };
watcher.Created += delegate (object o, FileSystemEventArgs args) {
if (!args.FullPath.EndsWith (".xml"))
return;
SparkleInviteListener invite_listener = new SparkleInviteListener (1987); if (this.fetcher == null ||
this.fetcher.IsActive) {
invite_listener.InviteReceived += delegate (SparkleInvite invite) { if (AlertNotificationRaised != null)
if (OnInvite != null && !FirstRun) AlertNotificationRaised ("SparkleShare Setup is busy",
OnInvite (invite); "Please try again later");
} else {
if (OnInvite != null)
OnInvite (new SparkleInvite (args.FullPath));
}
}; };
invite_listener.Start ();
new Thread (new ThreadStart (PopulateRepositories)).Start (); new Thread (new ThreadStart (PopulateRepositories)).Start ();
} }
@ -147,7 +154,7 @@ namespace SparkleShare {
} }
// Uploads the user's public key to the server // Uploads the user's public key to the server TODO
public bool AcceptInvitation (string server, string folder, string token) public bool AcceptInvitation (string server, string folder, string token)
{ {
// The location of the user's public key for SparkleShare // The location of the user's public key for SparkleShare
@ -184,6 +191,7 @@ namespace SparkleShare {
get { get {
List<string> folders = SparkleConfig.DefaultConfig.Folders; List<string> folders = SparkleConfig.DefaultConfig.Folders;
folders.Sort (); folders.Sort ();
return folders; return folders;
} }
} }
@ -584,7 +592,6 @@ namespace SparkleShare {
repo.NewChangeSet += delegate (SparkleChangeSet change_set) { repo.NewChangeSet += delegate (SparkleChangeSet change_set) {
if (NotificationRaised != null) if (NotificationRaised != null)
NotificationRaised (change_set); NotificationRaised (change_set);
}; };
@ -596,8 +603,9 @@ namespace SparkleShare {
}; };
repo.ConflictResolved += delegate { repo.ConflictResolved += delegate {
if (ConflictNotificationRaised != null) if (AlertNotificationRaised != null)
ConflictNotificationRaised (); AlertNotificationRaised ("Conflict detected.",
"Don't worry, SparkleShare made a copy of each conflicting file.");
}; };
repo.SyncStatusChanged += delegate (SyncStatus status) { repo.SyncStatusChanged += delegate (SyncStatus status) {
@ -851,7 +859,6 @@ namespace SparkleShare {
} }
foreach (string raw_email in emails) { foreach (string raw_email in emails) {
// Gravatar wants lowercase emails // Gravatar wants lowercase emails
string email = raw_email.ToLower (); string email = raw_email.ToLower ();
string avatar_file_path = Path.Combine (avatar_path, "avatar-" + email); string avatar_file_path = Path.Combine (avatar_path, "avatar-" + email);
@ -866,9 +873,6 @@ namespace SparkleShare {
old_avatars.Add (email); old_avatars.Add (email);
} catch (FileNotFoundException) { } catch (FileNotFoundException) {
// FIXME: For some reason the previous File.Exists () check
// doesn't cover all cases sometimes, so we catch any errors
if (old_avatars.Contains (email)) if (old_avatars.Contains (email))
old_avatars.Remove (email); old_avatars.Remove (email);
} }
@ -876,11 +880,11 @@ namespace SparkleShare {
} else if (this.failed_avatars.Contains (email)) { } else if (this.failed_avatars.Contains (email)) {
break; break;
} else { } else {
WebClient client = new WebClient (); WebClient client = new WebClient ();
string url = "http://gravatar.com/avatar/" + GetMD5 (email) + string url = "http://gravatar.com/avatar/" + GetMD5 (email) +
".jpg?s=" + size + "&d=404"; ".jpg?s=" + size + "&d=404";
try { try {
// Fetch the avatar // Fetch the avatar
byte [] buffer = client.DownloadData (url); byte [] buffer = client.DownloadData (url);
@ -900,11 +904,10 @@ namespace SparkleShare {
SparkleHelpers.DebugInfo ("Avatar", "Failed fetching gravatar for " + email); SparkleHelpers.DebugInfo ("Avatar", "Failed fetching gravatar for " + email);
// Stop downloading further avatars if we have no internet access // Stop downloading further avatars if we have no internet access
if (e.Status == WebExceptionStatus.Timeout){ if (e.Status == WebExceptionStatus.Timeout)
break; break;
} else { else
this.failed_avatars.Add (email); this.failed_avatars.Add (email);
}
} }
} }
} }

View file

@ -29,32 +29,22 @@ namespace SparkleShare {
public class SparkleInvite { public class SparkleInvite {
public readonly Uri FullAddress; public readonly string Address;
public readonly string Token; public readonly string RemotePath;
public readonly Uri AcceptUrl;
public string Host {
get {
return FullAddress.Host;
}
}
public string Path {
get {
return FullAddress.AbsolutePath;
}
}
public SparkleInvite (string host, string path, string token) public SparkleInvite (string address, string remote_path, string accept_url)
{ {
if (path.StartsWith ("/")) if (remote_path.StartsWith ("/"))
path = path.Substring (1); remote_path = remote_path.Substring (1);
if (!host.EndsWith ("/")) if (!address.EndsWith ("/"))
host = host + "/"; address = address + "/";
FullAddress = new Uri ("ssh://" + host + path); Address = address;
Token = token; RemotePath = remote_path;
AcceptUrl = new Uri (accept_url);
} }
@ -63,19 +53,19 @@ namespace SparkleShare {
XmlDocument xml_document = new XmlDocument (); XmlDocument xml_document = new XmlDocument ();
XmlNode node; XmlNode node;
string host = "", path = "", token = ""; string address = "", remote_path = "", accept_url = "";
try { try {
xml_document.Load (xml_file_path); xml_document.Load (xml_file_path);
node = xml_document.SelectSingleNode ("/sparkleshare/invite/host/text()"); node = xml_document.SelectSingleNode ("/sparkleshare/invite/address/text()");
if (node != null) { host = node.Value; } if (node != null) { address = node.Value; }
node = xml_document.SelectSingleNode ("/sparkleshare/invite/path/text()"); node = xml_document.SelectSingleNode ("/sparkleshare/invite/remote_path/text()");
if (node != null) { path = node.Value; } if (node != null) { remote_path = node.Value; }
node = xml_document.SelectSingleNode ("/sparkleshare/invite/token/text()"); node = xml_document.SelectSingleNode ("/sparkleshare/invite/accept_url/text()");
if (node != null) { token = node.Value; } if (node != null) { accept_url = node.Value; }
} catch (XmlException e) { } catch (XmlException e) {
SparkleHelpers.DebugInfo ("Invite", "Invalid XML: " + e.Message); SparkleHelpers.DebugInfo ("Invite", "Invalid XML: " + e.Message);
@ -83,146 +73,34 @@ namespace SparkleShare {
} }
if (path.StartsWith ("/")) if (remote_path.StartsWith ("/"))
path = path.Substring (1); remote_path = remote_path.Substring (1);
if (!host.EndsWith ("/")) if (!address.EndsWith ("/"))
host = host + "/"; address = address + "/";
FullAddress = new Uri ("ssh://" + host + path); Address = address;
Token = token; RemotePath = remote_path;
} AcceptUrl = new Uri (accept_url);
}
public class SparkleInviteListener {
public event InviteReceivedHandler InviteReceived;
public delegate void InviteReceivedHandler (SparkleInvite invite);
private Thread thread;
private TcpListener tcp_listener;
public SparkleInviteListener (int port)
{
this.tcp_listener = new TcpListener (IPAddress.Loopback, port);
this.thread = new Thread(new ThreadStart (Listen));
} }
public void Start () public bool Accept ()
{ {
this.thread.Start (); WebClient web_client = new WebClient ();
}
try {
web_client.DownloadData (AcceptUrl);
SparkleHelpers.DebugInfo ("Invite", "Uploaded public key");
private void Listen () return true;
{
this.tcp_listener.Start ();
while (true) } catch (WebException e) {
{ SparkleHelpers.DebugInfo ("Invite",
// Blocks until a client connects "Failed uploading public key: " + e.Message);
TcpClient client = this.tcp_listener.AcceptTcpClient ();
// Create a thread to handle communications return false;
Thread client_thread = new Thread (HandleClient);
client_thread.Start (client);
} }
} }
private void HandleClient (object client)
{
TcpClient tcp_client = (TcpClient) client;
NetworkStream client_stream = tcp_client.GetStream ();
byte [] message = new byte [4096];
int bytes_read;
while (true)
{
bytes_read = 0;
try {
// Blocks until the client sends a message
bytes_read = client_stream.Read (message, 0, 4096);
} catch {
Console.WriteLine ("Socket error...");
}
// The client has disconnected
if (bytes_read == 0)
break;
ASCIIEncoding encoding = new ASCIIEncoding ();
string received_message = encoding.GetString (message, 0, bytes_read);
string invite_xml = "";
if (received_message.StartsWith (Uri.UriSchemeHttp) ||
received_message.StartsWith (Uri.UriSchemeHttps)) {
WebClient web_client = new WebClient ();
try {
// Fetch the invite file
byte [] buffer = web_client.DownloadData (received_message);
SparkleHelpers.DebugInfo ("Invite", "Received: " + received_message);
invite_xml = ASCIIEncoding.ASCII.GetString (buffer);
} catch (WebException e) {
SparkleHelpers.DebugInfo ("Invite", "Failed downloading: " +
received_message + " " + e.Message);
continue;
}
} else if (received_message.StartsWith (Uri.UriSchemeFile)) {
try {
received_message = received_message.Replace (Uri.UriSchemeFile + "://", "");
invite_xml = File.ReadAllText (received_message);
} catch {
SparkleHelpers.DebugInfo ("Invite", "Failed opening: " + received_message);
continue;
}
} else {
SparkleHelpers.DebugInfo ("Invite",
"Path to invite must use either the file:// or http(s):// scheme");
continue;
}
XmlDocument xml_document = new XmlDocument ();
XmlNode node;
string host = "", path = "", token = "";
try {
xml_document.LoadXml (invite_xml);
node = xml_document.SelectSingleNode ("/sparkleshare/invite/host/text()");
if (node != null) { host = node.Value; }
node = xml_document.SelectSingleNode ("/sparkleshare/invite/path/text()");
if (node != null) { path = node.Value; }
node = xml_document.SelectSingleNode ("/sparkleshare/invite/token/text()");
if (node != null) { token = node.Value; }
} catch (XmlException e) {
SparkleHelpers.DebugInfo ("Invite", "Invalid XML: " + received_message + " " + e.Message);
return;
}
if (InviteReceived != null)
InviteReceived (new SparkleInvite (host, path, token));
}
tcp_client.Close ();
}
} }
} }

View file

@ -27,6 +27,7 @@ namespace SparkleShare {
public enum PageType { public enum PageType {
Setup, Setup,
Add, Add,
Invite,
Syncing, Syncing,
Error, Error,
Finished, Finished,
@ -274,6 +275,49 @@ namespace SparkleShare {
} }
public void InvitePageCompleted (SparkleInvite invite)
{/*
if (ChangePageEvent != null)
ChangePageEvent (PageType.Syncing, null);
if (!invite.Accept ()) {
if (ChangePageEvent != null)
ChangePageEvent (PageType.Error, null);
return;
}
*/
// TODO: Remove events afterwards
Program.Controller.FolderFetched += delegate (string [] warnings) {
if (ChangePageEvent != null)
ChangePageEvent (PageType.Finished, warnings);
this.previous_address = "";
this.syncing_folder = "";
this.previous_url = "";
SelectedPlugin = Plugins [0];
};
Program.Controller.FolderFetchError += delegate (string remote_url) {
this.previous_url = remote_url;
if (ChangePageEvent != null)
ChangePageEvent (PageType.Error, null);
this.syncing_folder = "";
};
Program.Controller.FolderFetching += delegate (double percentage) {
if (UpdateProgressBarEvent != null)
UpdateProgressBarEvent (percentage);
};
//Program.Controller.FetchFolder (address, path);
}
public void ErrorPageCompleted () public void ErrorPageCompleted ()
{ {
if (ChangePageEvent != null) if (ChangePageEvent != null)