public void Reconnect() { SparkleLogger.LogInfo("Listener", "Trying to reconnect to " + Server); Connect(); }
public void OnDisconnected(DisconnectReason reason, string message) { SparkleLogger.LogInfo("Listener", "Disconnected from " + Server + ": " + message); Disconnected(reason); }
private void ListenerDisconnectedDelegate() { this.poll_interval = PollInterval.Short; SparkleLogger.LogInfo(Name, "Falling back to regular polling"); }
// Starts a new thread and listens to the channel public override void Connect() { this.is_connecting = true; this.thread = new Thread(() => { int port = Server.Port; if (port < 0) { port = 443; } try { this.socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp) { ReceiveTimeout = 5 * 1000, SendTimeout = 5 * 1000 }; // Try to connect to the server this.socket.Connect(Server.Host, port); this.is_connecting = false; this.is_connected = true; OnConnected(); } catch (Exception e) { this.is_connected = false; this.is_connecting = false; if (this.socket != null) { this.socket.Close(); } OnDisconnected(SparkleLib.DisconnectReason.TimeOut, e.Message); return; } byte [] bytes = new byte [4096]; int bytes_read = 0; this.last_ping = DateTime.Now; // Wait for messages while (this.is_connected) { try { int i = 0; int timeout = 300; DisconnectReason reason = DisconnectReason.TimeOut; // This blocks the thread while (this.socket.Available < 1) { try { // We've timed out, let's ping the server to // see if the connection is still up if (i == timeout) { SparkleLogger.LogInfo("ListenerTcp", "Pinging " + Server); byte [] ping_bytes = Encoding.UTF8.GetBytes("ping\n"); byte [] pong_bytes = new byte [4096]; this.socket.Send(ping_bytes); if (this.socket.Receive(pong_bytes) < 1) { // 10057 means "Socket is not connected" throw new SocketException(10057); } SparkleLogger.LogInfo("ListenerTcp", "Received pong from " + Server); i = 0; this.last_ping = DateTime.Now; } else { // Check when the last ping occured. If it's // significantly longer than our regular interval the // system likely woke up from sleep and we want to // simulate a disconnect int sleepiness = DateTime.Compare( this.last_ping.AddMilliseconds(timeout * 1000 * 1.2), DateTime.Now ); if (sleepiness <= 0) { SparkleLogger.LogInfo("ListenerTcp", "System woke up from sleep"); reason = DisconnectReason.SystemSleep; // 10057 means "Socket is not connected" throw new SocketException(10057); } } // The ping failed: disconnect completely } catch (SocketException e) { Disconnect(reason, "Ping timeout: " + e.Message); return; } Thread.Sleep(1000); i++; } } catch (Exception) { return; } try { if (this.socket.Available > 0) { bytes_read = this.socket.Receive(bytes); } // Parse the received message if (bytes_read > 0) { string received = Encoding.UTF8.GetString(bytes); string line = received.Substring(0, received.IndexOf("\n")); if (!line.Contains("!")) { continue; } string folder_identifier = line.Substring(0, line.IndexOf("!")); string message = CleanMessage(line.Substring(line.IndexOf("!") + 1)); // We have a message! if (!folder_identifier.Equals("debug") && !string.IsNullOrEmpty(message)) { OnAnnouncement(new SparkleAnnouncement(folder_identifier, message)); } } } catch (SocketException e) { Disconnect(DisconnectReason.TimeOut, "Timeout during receiving: " + e.Message); return; } } }); this.thread.Start(); }
private void SyncUpBase() { if (!UseCustomWatcher) { this.watcher.Disable(); } SparkleLogger.LogInfo("SyncUp", Name + " | Initiated"); HasUnsyncedChanges = true; Status = SyncStatus.SyncUp; SyncStatusChanged(Status); if (SyncUp()) { SparkleLogger.LogInfo("SyncUp", Name + " | Done"); ChangeSets = GetChangeSets(); HasUnsyncedChanges = false; this.poll_interval = PollInterval.Long; this.listener.Announce(new SparkleAnnouncement(Identifier, CurrentRevision)); Status = SyncStatus.Idle; SyncStatusChanged(Status); } else { SparkleLogger.LogInfo("SyncUp", Name + " | Error"); SyncDownBase(); if (!UseCustomWatcher) { this.watcher.Disable(); } if (Error == ErrorStatus.None && SyncUp()) { HasUnsyncedChanges = false; this.listener.Announce(new SparkleAnnouncement(Identifier, CurrentRevision)); Status = SyncStatus.Idle; SyncStatusChanged(Status); } else { this.poll_interval = PollInterval.Short; Status = SyncStatus.Error; SyncStatusChanged(Status); } } ProgressPercentage = 0.0; ProgressSpeed = 0.0; if (!UseCustomWatcher) { this.watcher.Enable(); } }
private void SyncDownBase() { if (!UseCustomWatcher) { this.watcher.Disable(); } SparkleLogger.LogInfo("SyncDown", Name + " | Initiated"); Status = SyncStatus.SyncDown; SyncStatusChanged(Status); string pre_sync_revision = CurrentRevision; if (SyncDown()) { SparkleLogger.LogInfo("SyncDown", Name + " | Done"); Error = ErrorStatus.None; string identifier_file_path = Path.Combine(LocalPath, ".sparkleshare"); File.SetAttributes(identifier_file_path, FileAttributes.Hidden); ChangeSets = GetChangeSets(); if (!pre_sync_revision.Equals(CurrentRevision) && ChangeSets != null && ChangeSets.Count > 0 && !ChangeSets [0].User.Name.Equals(this.local_config.User.Name)) { bool emit_change_event = true; foreach (SparkleChange change in ChangeSets[0].Changes) { if (change.Path.EndsWith(".sparkleshare")) { emit_change_event = false; break; } } if (emit_change_event) { NewChangeSet(ChangeSets [0]); } } // There could be changes from a resolved // conflict. Tries only once, then lets // the timer try again periodically if (HasUnsyncedChanges) { Status = SyncStatus.SyncUp; SyncStatusChanged(Status); if (SyncUp()) { HasUnsyncedChanges = false; } } Status = SyncStatus.Idle; SyncStatusChanged(Status); } else { SparkleLogger.LogInfo("SyncDown", Name + " | Error"); ChangeSets = GetChangeSets(); Status = SyncStatus.Error; SyncStatusChanged(Status); } ProgressPercentage = 0.0; ProgressSpeed = 0.0; Status = SyncStatus.Idle; SyncStatusChanged(Status); if (!UseCustomWatcher) { this.watcher.Enable(); } }
public void OnFileActivity(FileSystemEventArgs args) { if (IsBuffering || this.is_syncing) { return; } if (args != null) { foreach (string exclude_path in ExcludePaths) { if (args.FullPath.Contains(Path.DirectorySeparatorChar + exclude_path)) { return; } } } lock (this.buffer_lock) { if (IsBuffering || this.is_syncing || !HasLocalChanges) { return; } IsBuffering = true; } ChangesDetected(); if (!UseCustomWatcher) { this.watcher.Disable(); } SparkleLogger.LogInfo("Local", Name + " | Activity detected, waiting for it to settle..."); List <double> size_buffer = new List <double> (); DirectoryInfo info = new DirectoryInfo(LocalPath); do { if (size_buffer.Count >= 4) { size_buffer.RemoveAt(0); } size_buffer.Add(CalculateSize(info)); if (size_buffer.Count >= 4 && size_buffer [0].Equals(size_buffer [1]) && size_buffer [1].Equals(size_buffer [2]) && size_buffer [2].Equals(size_buffer [3])) { SparkleLogger.LogInfo("Local", Name + " | Activity has settled"); IsBuffering = false; bool first_sync = true; if (HasLocalChanges && Status == SyncStatus.Idle) { do { if (!first_sync) { SparkleLogger.LogInfo("Local", Name + " | More changes found"); } SyncUpBase(); if (Error == ErrorStatus.UnreadableFiles) { return; } first_sync = false; } while (HasLocalChanges); } else { Status = SyncStatus.Idle; SyncStatusChanged(Status); } } else { Thread.Sleep(500); } } while (IsBuffering); if (!UseCustomWatcher) { this.watcher.Enable(); } }
public SparkleRepoBase(string path, SparkleConfig config) { SparkleLogger.LogInfo(path, "Initializing..."); Status = SyncStatus.Idle; Error = ErrorStatus.None; this.local_config = config; LocalPath = path; Name = Path.GetFileName(LocalPath); RemoteUrl = new Uri(this.local_config.GetUrlForFolder(Name)); IsBuffering = false; this.identifier = Identifier; ChangeSets = GetChangeSets(); string identifier_file_path = Path.Combine(LocalPath, ".sparkleshare"); File.SetAttributes(identifier_file_path, FileAttributes.Hidden); if (!UseCustomWatcher) { this.watcher = new SparkleWatcher(LocalPath); } new Thread(() => CreateListener()).Start(); this.remote_timer.Elapsed += delegate { if (this.is_syncing || IsBuffering) { return; } int time_comparison = DateTime.Compare(this.last_poll, DateTime.Now.Subtract(this.poll_interval)); if (time_comparison < 0) { if (HasUnsyncedChanges && !this.is_syncing) { SyncUpBase(); } this.last_poll = DateTime.Now; if (HasRemoteChanges && !this.is_syncing) { SyncDownBase(); } if (this.listener.IsConnected) { this.poll_interval = PollInterval.Long; } } // In the unlikely case that we haven't synced up our // changes or the server was down, sync up again if (HasUnsyncedChanges && !this.is_syncing && Error == ErrorStatus.None) { SyncUpBase(); } }; }
private void SyncDownBase() { if (!UseCustomWatcher) { this.watcher.Disable(); } SparkleLogger.LogInfo("SyncDown", Name + " | Initiated"); SyncStatusChanged(SyncStatus.SyncDown); string pre_sync_revision = CurrentRevision; if (SyncDown()) { SparkleLogger.LogInfo("SyncDown", Name + " | Done"); ServerOnline = true; ChangeSets = GetChangeSets(); if (!pre_sync_revision.Equals(CurrentRevision) && ChangeSets != null && ChangeSets.Count > 0) { bool emit_change_event = true; foreach (SparkleChange change in ChangeSets[0].Changes) { if (change.Path.EndsWith(".sparkleshare")) { emit_change_event = false; break; } } if (emit_change_event) { NewChangeSet(ChangeSets [0]); } } // There could be changes from a resolved // conflict. Tries only once, then lets // the timer try again periodically if (HasUnsyncedChanges) { SyncStatusChanged(SyncStatus.SyncUp); SyncUp(); HasUnsyncedChanges = false; } SyncStatusChanged(SyncStatus.Idle); } else { SparkleLogger.LogInfo("SyncDown", Name + " | Error"); ServerOnline = false; ChangeSets = GetChangeSets(); SyncStatusChanged(SyncStatus.Error); } ProgressPercentage = 0.0; ProgressSpeed = ""; if (!UseCustomWatcher) { this.watcher.Enable(); } SyncStatusChanged(SyncStatus.Idle); }
public void OnFileActivity(FileSystemEventArgs args) { if (IsBuffering) { return; } ChangesDetected(); string relative_path = args.FullPath.Replace(LocalPath, ""); foreach (string exclude_path in ExcludePaths) { if (relative_path.Contains(exclude_path)) { return; } } if (IsBuffering || !HasLocalChanges) { return; } IsBuffering = true; if (!UseCustomWatcher) { this.watcher.Disable(); } SparkleLogger.LogInfo("Local", Name + " | Activity detected, waiting for it to settle..."); List <double> size_buffer = new List <double> (); do { if (size_buffer.Count >= 4) { size_buffer.RemoveAt(0); } DirectoryInfo info = new DirectoryInfo(LocalPath); size_buffer.Add(CalculateSize(info)); if (size_buffer.Count >= 4 && size_buffer [0].Equals(size_buffer [1]) && size_buffer [1].Equals(size_buffer [2]) && size_buffer [2].Equals(size_buffer [3])) { SparkleLogger.LogInfo("Local", Name + " | Activity has settled"); IsBuffering = false; if (HasLocalChanges) { do { SyncUpBase(); } while (HasLocalChanges); } else { SyncStatusChanged(SyncStatus.Idle); } } else { Thread.Sleep(500); } } while (IsBuffering); if (!UseCustomWatcher) { this.watcher.Enable(); } }
public void Start() { IsActive = true; Started(); SparkleLogger.LogInfo("Fetcher", TargetFolder + " | Fetching folder: " + RemoteUrl); if (Directory.Exists(TargetFolder)) { Directory.Delete(TargetFolder, true); } string host = RemoteUrl.Host; string host_key = GetHostKey(); if (string.IsNullOrEmpty(host) || host_key == null) { Failed(); return; } bool warn = true; if (RequiredFingerprint != null) { string host_fingerprint = GetFingerprint(host_key); if (host_fingerprint == null || !RequiredFingerprint.Equals(host_fingerprint)) { SparkleLogger.LogInfo("Auth", "Fingerprint doesn't match"); this.errors.Add("error: Host fingerprint doesn't match"); Failed(); return; } warn = false; SparkleLogger.LogInfo("Auth", "Fingerprint matches"); } else { SparkleLogger.LogInfo("Auth", "Skipping fingerprint check"); } AcceptHostKey(host_key, warn); this.thread = new Thread(() => { if (Fetch()) { Thread.Sleep(500); SparkleLogger.LogInfo("Fetcher", "Finished"); IsActive = false; // TODO: Find better way to determine if folder should have crypto setup bool repo_is_encrypted = RemoteUrl.ToString().Contains("crypto"); Finished(repo_is_encrypted, IsFetchedRepoEmpty, Warnings); } else { Thread.Sleep(500); SparkleLogger.LogInfo("Fetcher", "Failed"); IsActive = false; Failed(); } }); this.thread.Start(); }