Ejemplo n.º 1
0
 public void Reconnect()
 {
     SparkleLogger.LogInfo("Listener", "Trying to reconnect to " + Server);
     Connect();
 }
Ejemplo n.º 2
0
 public void OnDisconnected(DisconnectReason reason, string message)
 {
     SparkleLogger.LogInfo("Listener", "Disconnected from " + Server + ": " + message);
     Disconnected(reason);
 }
Ejemplo n.º 3
0
 private void ListenerDisconnectedDelegate()
 {
     this.poll_interval = PollInterval.Short;
     SparkleLogger.LogInfo(Name, "Falling back to regular polling");
 }
Ejemplo n.º 4
0
        // 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();
        }
Ejemplo n.º 5
0
        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();
            }
        }
Ejemplo n.º 6
0
        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();
            }
        }
Ejemplo n.º 7
0
        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();
            }
        }
Ejemplo n.º 8
0
        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();
                }
            };
        }
Ejemplo n.º 9
0
        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);
        }
Ejemplo n.º 10
0
        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();
            }
        }
Ejemplo n.º 11
0
        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();
        }