public CloudFolderEvents(CloudFolderFileSystem fileSystem)
        {
            if (fileSystem == null)
            {
                throw new ArgumentNullException(nameof(fileSystem));
            }

            _fileSystem = fileSystem;

            // build SignalR connection
            _connection = new HubConnectionBuilder()
                          .WithUrl(WebApi.RootUrl + "events")
                          .WithAutomaticReconnect()
                          .Build();

            _connection.Closed += async(error) =>
            {
                _fileSystem.Logger?.Log(TraceLevel.Warning, "Server events closed. Error: " + error?.Message + " Restart: " + _started);
                // restart?
                if (_started)
                {
                    await Task.Delay(new Random().Next(0, 5) * 1000).ConfigureAwait(false);

                    await _connection.StartAsync().ConfigureAwait(false);
                }
            };

            // must match server's IFileSystemEvents method signature
            // Change(Guid id, Guid itemId, Guid parentId, WatcherChangeTypes types, DateTime creationTimeUtc, string oldName);
            _connection.On <Guid, Guid, Guid, WatcherChangeTypes, DateTime, string>("Change", (id, itemId, parentId, type, dt, oldName) =>
            {
                _fileSystem.Logger?.Log(TraceLevel.Verbose, "id: " + id + " itemid: " + itemId + " parentId: " + parentId + " type: " + type + " oldName:" + oldName);

                StateSyncEntry entry;
                switch (type)
                {
                case WatcherChangeTypes.Deleted:
                    entry = ToEntry(itemId, parentId);
                    _fileSystem.OnEvent(new SyncFileSystemEventArgs(SyncFileSystemEventType.Deleted, dt, entry));
                    break;

                case WatcherChangeTypes.Created:
                    entry = ToEntry(itemId, parentId);
                    _fileSystem.OnEvent(new SyncFileSystemEventArgs(SyncFileSystemEventType.Created, dt, entry));
                    break;

                case WatcherChangeTypes.Changed:
                    entry = ToEntry(itemId, parentId);
                    _fileSystem.OnEvent(new SyncFileSystemEventArgs(SyncFileSystemEventType.Changed, dt, entry));
                    break;

                case WatcherChangeTypes.Renamed:
                    entry = ToEntry(itemId, parentId);

                    var oldEntry      = ToEntry(itemId, parentId);
                    oldEntry.FileName = oldName;
                    _fileSystem.OnEvent(new SyncFileSystemEventArgs(SyncFileSystemEventType.Moved, dt, entry, oldEntry));
                    break;
                }

                SetLastEventTime(dt);
            });
        }