예제 #1
0
        private void AuthenticateClient(DownloadStationSettings settings)
        {
            var arguments = new Dictionary <string, object>
            {
                { "api", "SYNO.API.Auth" },
                { "version", "1" },
                { "method", "login" },
                { "account", settings.Username },
                { "passwd", settings.Password },
                { "format", "cookie" },
                { "session", "DownloadStation" },
            };

            var authLoginRequest = BuildRequest(settings, DiskStationApi.Auth, arguments, HttpMethod.GET);

            authLoginRequest.StoreResponseCookie = true;

            var response = _httpClient.Execute(authLoginRequest);

            var downloadStationResponse = Json.Deserialize <DiskStationResponse <DiskStationAuthResponse> >(response.Content);

            var authResponse = Json.Deserialize <DiskStationResponse <DiskStationAuthResponse> >(response.Content);

            _authenticated = authResponse.Success;

            if (!_authenticated)
            {
                throw new DownloadClientAuthenticationException(downloadStationResponse.Error.GetMessage(DiskStationApi.Auth));
            }
        }
예제 #2
0
        private DiskStationApiInfo GetApiInfo(DiskStationApi api, DownloadStationSettings settings)
        {
            if (api == DiskStationApi.Info)
            {
                return(_apiInfo);
            }

            var key  = GenerateInfoCacheKey(settings, api);
            var info = _infoCache.Find(key);

            if (info == null)
            {
                UpdateApiInfo(settings);
                info = _infoCache.Find(key);

                if (info == null)
                {
                    if (api == DiskStationApi.DownloadStation2Task)
                    {
                        _logger.Warn("Info of {0} not found on {1}:{2}", api, settings.Host, settings.Port);
                    }
                    else
                    {
                        throw new DownloadClientException("Info of {0} not found on {1}:{2}", api, settings.Host, settings.Port);
                    }
                }
            }

            return(info);
        }
예제 #3
0
        private void UpdateApiInfo(DownloadStationSettings settings)
        {
            var apis = new Dictionary <string, DiskStationApi>()
            {
                { "SYNO.API.Auth", DiskStationApi.Auth },
                { _apiName, _apiType }
            };

            var requestBuilder = BuildRequest(settings, _apiInfo, "query", _apiInfo.MinVersion);

            requestBuilder.AddQueryParam("query", string.Join(",", apis.Keys));

            var infoResponse = ProcessRequest <DiskStationApiInfoResponse>(requestBuilder, "get api info", _apiInfo.Type, settings);

            foreach (var data in infoResponse.Data)
            {
                if (apis.ContainsKey(data.Key))
                {
                    data.Value.Name = data.Key;
                    data.Value.Type = apis[data.Key];
                    data.Value.NeedsAuthentication = apis[data.Key] != DiskStationApi.Auth;

                    _infoCache.Set(GenerateInfoCacheKey(settings, apis[data.Key]), data.Value, TimeSpan.FromHours(1));
                }
            }
        }
예제 #4
0
 protected DiskStationResponse <T> ProcessRequest <T>(HttpRequestBuilder requestBuilder,
                                                      string operation,
                                                      DownloadStationSettings settings)
     where T : new()
 {
     return(ProcessRequest <T>(requestBuilder, operation, _apiType, settings));
 }
        public void AddTaskFromUrl(string url, string downloadDirectory, DownloadStationSettings settings)
        {
            var requestBuilder = BuildRequest(settings, "create", 2);

            requestBuilder.AddQueryParam("type", "url");
            requestBuilder.AddQueryParam("url", url);
            requestBuilder.AddQueryParam("create_list", "false");

            if (downloadDirectory.IsNotNullOrWhiteSpace())
            {
                requestBuilder.AddQueryParam("destination", downloadDirectory);
            }
            else
            {
                _logger.Trace("No directory configured in settings; falling back to client default destination folder.");
                string defaultDestination = _defaultDestinationProxy.GetDefaultDestination(settings);

                if (defaultDestination.IsNotNullOrWhiteSpace())
                {
                    _logger.Trace($"Default destination folder found: {defaultDestination}.");
                    requestBuilder.AddQueryParam("destination", $"\"{defaultDestination}\"");
                }
                else
                {
                    _logger.Error("Unable to get default destination folder from DownloadStation.");
                }
            }

            ProcessRequest <object>(requestBuilder, $"add task from url {url}", settings);
        }
예제 #6
0
        private DiskStationResponse <T> ProcessRequest <T>(HttpRequestBuilder requestBuilder,
                                                           string operation,
                                                           DiskStationApi api,
                                                           DownloadStationSettings settings)
            where T : new()
        {
            var          request = requestBuilder.Build();
            HttpResponse response;

            try
            {
                response = _httpClient.Execute(request);
            }
            catch (HttpException ex)
            {
                throw new DownloadClientException("Unable to connect to Diskstation, please check your settings", ex);
            }
            catch (WebException ex)
            {
                if (ex.Status == WebExceptionStatus.TrustFailure)
                {
                    throw new DownloadClientUnavailableException("Unable to connect to Diskstation, certificate validation failed.", ex);
                }

                throw new DownloadClientUnavailableException("Unable to connect to Diskstation, please check your settings", ex);
            }

            _logger.Debug("Trying to {0}", operation);

            if (response.StatusCode == HttpStatusCode.OK)
            {
                var responseContent = Json.Deserialize <DiskStationResponse <T> >(response.Content);

                if (responseContent.Success)
                {
                    return(responseContent);
                }
                else
                {
                    var msg = $"Failed to {operation}. Reason: {responseContent.Error.GetMessage(api)}";
                    _logger.Error(msg);

                    if (responseContent.Error.SessionError)
                    {
                        _sessionCache.Remove(GenerateSessionCacheKey(settings));

                        if (responseContent.Error.Code == 105)
                        {
                            throw new DownloadClientAuthenticationException(msg);
                        }
                    }

                    throw new DownloadClientException(msg);
                }
            }
            else
            {
                throw new HttpException(request, response);
            }
        }
예제 #7
0
        protected HttpRequestBuilder BuildRequest(DownloadStationSettings settings, string methodName, int apiVersion, HttpMethod httpVerb = null)
        {
            httpVerb ??= HttpMethod.Get;

            var info = GetApiInfo(_apiType, settings);

            return(BuildRequest(settings, info, methodName, apiVersion, httpVerb));
        }
예제 #8
0
        public SharedFolderMapping GetSharedFolderMapping(string sharedFolder, DownloadStationSettings settings)
        {
            var info = GetInfoFileOrDirectory(sharedFolder, settings);

            var physicalPath = info.Additional["real_path"].ToString();

            return(new SharedFolderMapping(sharedFolder, physicalPath));
        }
        public Dictionary <string, object> GetConfig(DownloadStationSettings settings)
        {
            var requestBuilder = BuildRequest(settings, "getConfig", 1);

            var response = ProcessRequest <Dictionary <string, object> >(requestBuilder, "get config", settings);

            return(response.Data);
        }
예제 #10
0
 protected DiskStationResponse <object> ProcessRequest(DiskStationApi api,
                                                       Dictionary <string, object> arguments,
                                                       DownloadStationSettings settings,
                                                       string operation,
                                                       HttpMethod method = HttpMethod.GET)
 {
     return(ProcessRequest <object>(api, arguments, settings, operation, method));
 }
예제 #11
0
        public void RemoveTask(string downloadId, DownloadStationSettings settings)
        {
            var requestBuilder = BuildRequest(settings, "delete", 2);

            requestBuilder.AddQueryParam("id", downloadId);
            requestBuilder.AddQueryParam("force_complete", "false");

            ProcessRequest <object>(requestBuilder, $"remove item {downloadId}", settings);
        }
예제 #12
0
        public string GetDefaultDestination(DownloadStationSettings settings)
        {
            var info = GetApiInfo(settings);

            var requestBuilder = BuildRequest(settings, "get", info.MinVersion);

            var response = ProcessRequest <DownloadStation2SettingsLocationResponse>(requestBuilder, "get default destination folder", settings);

            return(response.Data.Default_Destination);
        }
예제 #13
0
        public string GetSerialNumber(DownloadStationSettings settings)
        {
            var info = GetApiInfo(settings);

            var requestBuilder = BuildRequest(settings, "getinfo", info.MinVersion);

            var response = ProcessRequest <DSMInfoResponse>(requestBuilder, "get serial number", settings);

            return(response.Data.SerialNumber);
        }
예제 #14
0
        protected DiskStationResponse <T> ProcessRequest <T>(DiskStationApi api,
                                                             Dictionary <string, object> arguments,
                                                             DownloadStationSettings settings,
                                                             string operation,
                                                             HttpMethod method = HttpMethod.GET,
                                                             int retries       = 0) where T : new()
        {
            if (retries == 5)
            {
                throw new DownloadClientException("Try to process request to {0} with {1} more than 5 times", api, arguments.ToJson().ToString());
            }

            if (!_authenticated && api != DiskStationApi.Info && api != DiskStationApi.DSMInfo)
            {
                AuthenticateClient(settings);
            }

            var request  = BuildRequest(settings, api, arguments, method);
            var response = _httpClient.Execute(request);

            _logger.Debug("Trying to {0}", operation);

            if (response.StatusCode == HttpStatusCode.OK)
            {
                var responseContent = Json.Deserialize <DiskStationResponse <T> >(response.Content);

                if (responseContent.Success)
                {
                    return(responseContent);
                }
                else
                {
                    var msg = $"Failed to {operation}. Reason: {responseContent.Error.GetMessage(api)}";
                    _logger.Error(msg);

                    if (responseContent.Error.SessionError)
                    {
                        _authenticated = false;

                        if (responseContent.Error.Code == 105)
                        {
                            throw new DownloadClientAuthenticationException(msg);
                        }

                        return(ProcessRequest <T>(api, arguments, settings, operation, method, ++retries));
                    }

                    throw new DownloadClientException(msg);
                }
            }
            else
            {
                throw new HttpException(request, response);
            }
        }
예제 #15
0
        public FileStationListFileInfoResponse GetInfoFileOrDirectory(string path, DownloadStationSettings settings)
        {
            var requestBuilder = BuildRequest(settings, "getinfo", 2);

            requestBuilder.AddQueryParam("path", new[] { path }.ToJson());
            requestBuilder.AddQueryParam("additional", "[\"real_path\"]");

            var response = ProcessRequest <FileStationListResponse>(requestBuilder, $"get info of {path}", settings);

            return(response.Data.Files.First());
        }
        public void AddTaskFromUrl(string url, string downloadDirectory, DownloadStationSettings settings)
        {
            var requestBuilder = BuildRequest(settings, "create", 3);

            requestBuilder.AddQueryParam("uri", url);

            if (downloadDirectory.IsNotNullOrWhiteSpace())
            {
                requestBuilder.AddQueryParam("destination", downloadDirectory);
            }

            var response = ProcessRequest <object>(requestBuilder, $"add task from url {url}", settings);
        }
예제 #17
0
        public void RemoveTask(string downloadId, DownloadStationSettings settings)
        {
            var arguments = new Dictionary <string, object>
            {
                { "api", "SYNO.DownloadStation.Task" },
                { "version", "1" },
                { "method", "delete" },
                { "id", downloadId },
                { "force_complete", false }
            };

            var response = ProcessRequest(DiskStationApi.DownloadStationTask, arguments, settings, $"remove item {downloadId}");
        }
예제 #18
0
        public string GetSerialNumber(DownloadStationSettings settings)
        {
            var arguments = new Dictionary <string, object>()
            {
                { "api", "SYNO.DSM.Info" },
                { "version", "2" },
                { "method", "getinfo" }
            };

            var response = ProcessRequest <DSMInfoResponse>(DiskStationApi.DSMInfo, arguments, settings, "get serial number");

            return(response.Data.SerialNumber);
        }
예제 #19
0
        public Dictionary <string, object> GetConfig(DownloadStationSettings settings)
        {
            var arguments = new Dictionary <string, object>
            {
                { "api", "SYNO.DownloadStation.Info" },
                { "version", "1" },
                { "method", "getconfig" }
            };

            var response = ProcessRequest <Dictionary <string, object> >(DiskStationApi.DownloadStationInfo, arguments, settings, "get config");

            return(response.Data);
        }
예제 #20
0
        public IEnumerable <DownloadStationTask> GetTasks(DownloadStationSettings settings)
        {
            try
            {
                var result = new List <DownloadStationTask>();

                var requestBuilder = BuildRequest(settings, "list", 1);
                requestBuilder.AddQueryParam("additional", "detail");

                var response = ProcessRequest <DownloadStation2TaskInfoResponse>(requestBuilder, "get tasks with additional detail", settings);

                if (response.Success && response.Data.Total > 0)
                {
                    requestBuilder.AddQueryParam("additional", "transfer");
                    var responseTransfer = ProcessRequest <DownloadStation2TaskInfoResponse>(requestBuilder, "get tasks with additional transfer", settings);

                    if (responseTransfer.Success)
                    {
                        foreach (var task in response.Data.Task)
                        {
                            var taskTransfer = responseTransfer.Data.Task.Where(t => t.Id == task.Id).First();

                            var combinedTask = new DownloadStationTask
                            {
                                Username   = task.Username,
                                Id         = task.Id,
                                Title      = task.Title,
                                Size       = task.Size,
                                Status     = (DownloadStationTaskStatus)task.Status,
                                Type       = task.Type,
                                Additional = new DownloadStationTaskAdditional
                                {
                                    Detail   = task.Additional.Detail,
                                    Transfer = taskTransfer.Additional.Transfer
                                }
                            };

                            result.Add(combinedTask);
                        }
                    }
                }

                return(result);
            }
            catch (DownloadClientException e)
            {
                _logger.Error(e);
                return(new List <DownloadStationTask>());
            }
        }
예제 #21
0
        protected void Setup()
        {
            _sharedFolder = new OsPath("/myFolder");
            _physicalPath = new OsPath("/mnt/sda1/folder");
            _settings     = new DownloadStationSettings();

            Mocker.GetMock <IFileStationProxy>()
            .Setup(f => f.GetSharedFolderMapping(It.IsAny <string>(), It.IsAny <DownloadStationSettings>()))
            .Throws(new DownloadClientException("There is no shared folder"));

            Mocker.GetMock <IFileStationProxy>()
            .Setup(f => f.GetSharedFolderMapping(_sharedFolder.FullPath, It.IsAny <DownloadStationSettings>()))
            .Returns(new SharedFolderMapping(_sharedFolder.FullPath, _physicalPath.FullPath));
        }
예제 #22
0
        private HttpRequestBuilder BuildRequest(DownloadStationSettings settings, DiskStationApiInfo apiInfo, string methodName, int apiVersion, HttpMethod httpVerb = null)
        {
            httpVerb ??= HttpMethod.Get;

            var requestBuilder = new HttpRequestBuilder(settings.UseSsl, settings.Host, settings.Port).Resource($"webapi/{apiInfo.Path}");

            requestBuilder.Method              = httpVerb;
            requestBuilder.LogResponseContent  = true;
            requestBuilder.SuppressHttpError   = true;
            requestBuilder.AllowAutoRedirect   = false;
            requestBuilder.Headers.ContentType = "application/json";

            if (apiVersion < apiInfo.MinVersion || apiVersion > apiInfo.MaxVersion)
            {
                throw new ArgumentOutOfRangeException(nameof(apiVersion));
            }

            if (httpVerb == HttpMethod.Post)
            {
                if (apiInfo.NeedsAuthentication)
                {
                    if (_apiType == DiskStationApi.DownloadStation2Task)
                    {
                        requestBuilder.AddQueryParam("_sid", _sessionCache.Get(GenerateSessionCacheKey(settings), () => AuthenticateClient(settings), TimeSpan.FromHours(6)));
                    }
                    else
                    {
                        requestBuilder.AddFormParameter("_sid", _sessionCache.Get(GenerateSessionCacheKey(settings), () => AuthenticateClient(settings), TimeSpan.FromHours(6)));
                    }
                }

                requestBuilder.AddFormParameter("api", apiInfo.Name);
                requestBuilder.AddFormParameter("version", apiVersion);
                requestBuilder.AddFormParameter("method", methodName);
            }
            else
            {
                if (apiInfo.NeedsAuthentication)
                {
                    requestBuilder.AddQueryParam("_sid", _sessionCache.Get(GenerateSessionCacheKey(settings), () => AuthenticateClient(settings), TimeSpan.FromHours(6)));
                }

                requestBuilder.AddQueryParam("api", apiInfo.Name);
                requestBuilder.AddQueryParam("version", apiVersion);
                requestBuilder.AddQueryParam("method", methodName);
            }

            return(requestBuilder);
        }
예제 #23
0
        public FileStationListFileInfoResponse GetInfoFileOrDirectory(string path, DownloadStationSettings settings)
        {
            var arguments = new Dictionary <string, object>
            {
                { "api", "SYNO.FileStation.List" },
                { "version", "2" },
                { "method", "getinfo" },
                { "path", new [] { path }.ToJson() },
                { "additional", $"[\"real_path\"]" }
            };

            var response = ProcessRequest <FileStationListResponse>(DiskStationApi.FileStationList, arguments, settings, $"get info of {path}");

            return(response.Data.Files.First());
        }
예제 #24
0
        private string AuthenticateClient(DownloadStationSettings settings)
        {
            var authInfo = GetApiInfo(DiskStationApi.Auth, settings);

            var requestBuilder = BuildRequest(settings, authInfo, "login", 2);

            requestBuilder.AddQueryParam("account", settings.Username);
            requestBuilder.AddQueryParam("passwd", settings.Password);
            requestBuilder.AddQueryParam("format", "sid");
            requestBuilder.AddQueryParam("session", "DownloadStation");

            var authResponse = ProcessRequest <DiskStationAuthResponse>(requestBuilder, "login", DiskStationApi.Auth, settings);

            return(authResponse.Data.SId);
        }
예제 #25
0
        private HttpRequest BuildRequest(DownloadStationSettings settings, DiskStationApi api, Dictionary <string, object> arguments, HttpMethod method)
        {
            if (!Resources.ContainsKey(api))
            {
                GetApiVersion(settings, api);
            }

            var requestBuilder = new HttpRequestBuilder(settings.UseSsl, settings.Host, settings.Port).Resource($"webapi/{Resources[api]}");

            requestBuilder.Method             = method;
            requestBuilder.LogResponseContent = true;
            requestBuilder.SuppressHttpError  = true;
            requestBuilder.AllowAutoRedirect  = false;

            if (requestBuilder.Method == HttpMethod.POST)
            {
                if (api == DiskStationApi.DownloadStationTask && arguments.ContainsKey("file"))
                {
                    requestBuilder.Headers.ContentType = "multipart/form-data";

                    foreach (var arg in arguments)
                    {
                        if (arg.Key == "file")
                        {
                            Dictionary <string, object> file = (Dictionary <string, object>)arg.Value;
                            requestBuilder.AddFormUpload(arg.Key, file["name"].ToString(), (byte[])file["data"]);
                        }
                        else
                        {
                            requestBuilder.AddFormParameter(arg.Key, arg.Value);
                        }
                    }
                }
                else
                {
                    requestBuilder.Headers.ContentType = "application/json";
                }
            }
            else
            {
                foreach (var arg in arguments)
                {
                    requestBuilder.AddQueryParam(arg.Key, arg.Value);
                }
            }

            return(requestBuilder.Build());
        }
예제 #26
0
        private IDownloadStationTaskProxy FetchProxy(DownloadStationSettings settings)
        {
            if (_proxyV2.IsApiSupported(settings))
            {
                _logger.Trace("Using DownloadStation Task API v2");
                return(_proxyV2);
            }

            if (_proxyV1.IsApiSupported(settings))
            {
                _logger.Trace("Using DownloadStation Task API v1");
                return(_proxyV1);
            }

            throw new DownloadClientException("Unable to determine DownloadStations Task API version");
        }
예제 #27
0
        protected IEnumerable <int> GetApiVersion(DownloadStationSettings settings, DiskStationApi api)
        {
            var arguments = new Dictionary <string, object>
            {
                { "api", "SYNO.API.Info" },
                { "version", "1" },
                { "method", "query" },
                { "query", "SYNO.API.Auth, SYNO.DownloadStation.Info, SYNO.DownloadStation.Task, SYNO.FileStation.List, SYNO.DSM.Info" },
            };

            var infoResponse = ProcessRequest <DiskStationApiInfoResponse>(DiskStationApi.Info, arguments, settings, "Get api version");

            //TODO: Refactor this into more elegant code
            var infoResponeDSAuth   = infoResponse.Data["SYNO.API.Auth"];
            var infoResponeDSInfo   = infoResponse.Data["SYNO.DownloadStation.Info"];
            var infoResponeDSTask   = infoResponse.Data["SYNO.DownloadStation.Task"];
            var infoResponseFSList  = infoResponse.Data["SYNO.FileStation.List"];
            var infoResponseDSMInfo = infoResponse.Data["SYNO.DSM.Info"];

            Resources[DiskStationApi.Auth] = infoResponeDSAuth.Path;
            Resources[DiskStationApi.DownloadStationInfo] = infoResponeDSInfo.Path;
            Resources[DiskStationApi.DownloadStationTask] = infoResponeDSTask.Path;
            Resources[DiskStationApi.FileStationList]     = infoResponseFSList.Path;
            Resources[DiskStationApi.DSMInfo]             = infoResponseDSMInfo.Path;

            switch (api)
            {
            case DiskStationApi.Auth:
                return(Enumerable.Range(infoResponeDSAuth.MinVersion, infoResponeDSAuth.MaxVersion - infoResponeDSAuth.MinVersion + 1));

            case DiskStationApi.DownloadStationInfo:
                return(Enumerable.Range(infoResponeDSInfo.MinVersion, infoResponeDSInfo.MaxVersion - infoResponeDSInfo.MinVersion + 1));

            case DiskStationApi.DownloadStationTask:
                return(Enumerable.Range(infoResponeDSTask.MinVersion, infoResponeDSTask.MaxVersion - infoResponeDSTask.MinVersion + 1));

            case DiskStationApi.FileStationList:
                return(Enumerable.Range(infoResponseFSList.MinVersion, infoResponseFSList.MaxVersion - infoResponseFSList.MinVersion + 1));

            case DiskStationApi.DSMInfo:
                return(Enumerable.Range(infoResponseDSMInfo.MinVersion, infoResponseDSMInfo.MaxVersion - infoResponseDSMInfo.MinVersion + 1));

            default:
                throw new DownloadClientException("Api not implemented");
            }
        }
        public IEnumerable <DownloadStationTask> GetTasks(DownloadStationSettings settings)
        {
            try
            {
                var requestBuilder = BuildRequest(settings, "list", 1);
                requestBuilder.AddQueryParam("additional", "detail,transfer");

                var response = ProcessRequest <DownloadStationTaskInfoResponse>(requestBuilder, "get tasks", settings);

                return(response.Data.Tasks);
            }
            catch (DownloadClientException e)
            {
                _logger.Error(e);
                return(new List <DownloadStationTask>());
            }
        }
예제 #29
0
        public void AddTaskFromUrl(string url, string downloadDirectory, DownloadStationSettings settings)
        {
            var arguments = new Dictionary <string, object>
            {
                { "api", "SYNO.DownloadStation.Task" },
                { "version", "3" },
                { "method", "create" },
                { "uri", url }
            };

            if (downloadDirectory.IsNotNullOrWhiteSpace())
            {
                arguments.Add("destination", downloadDirectory);
            }

            var response = ProcessRequest(DiskStationApi.DownloadStationTask, arguments, settings, $"add task from url {url}");
        }
예제 #30
0
        private DiskStationResponse <T> ProcessRequest <T>(HttpRequestBuilder requestBuilder,
                                                           string operation,
                                                           DiskStationApi api,
                                                           DownloadStationSettings settings) where T : new()
        {
            var request  = requestBuilder.Build();
            var response = _httpClient.Execute(request);

            _logger.Debug("Trying to {0}", operation);

            if (response.StatusCode == HttpStatusCode.OK)
            {
                var responseContent = Json.Deserialize <DiskStationResponse <T> >(response.Content);

                if (responseContent.Success)
                {
                    return(responseContent);
                }
                else
                {
                    var msg = $"Failed to {operation}. Reason: {responseContent.Error.GetMessage(api)}";
                    _logger.Error(msg);

                    if (responseContent.Error.SessionError)
                    {
                        _sessionCache.Remove(GenerateSessionCacheKey(settings));

                        if (responseContent.Error.Code == 105)
                        {
                            throw new DownloadClientAuthenticationException(msg);
                        }
                    }

                    throw new DownloadClientException(msg);
                }
            }
            else
            {
                throw new HttpException(request, response);
            }
        }