diff --git a/.github/workflows/dotnet8-desktop.yml b/.github/workflows/dotnet8-desktop.yml
new file mode 100644
index 0000000..2c36ef4
--- /dev/null
+++ b/.github/workflows/dotnet8-desktop.yml
@@ -0,0 +1,35 @@
+# This workflow will build a .NET8 Desktop project
+# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-net
+
+name: .NET8 Desktop
+
+on:
+ push:
+ branches: [ "main" ]
+ pull_request:
+ branches: [ "main" ]
+
+jobs:
+ build:
+
+ runs-on: windows-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+ with:
+ fetch-depth: 0
+
+ - name: Setup .NET
+ uses: actions/setup-dotnet@v4
+ with:
+ dotnet-version: 8.0.x
+
+ - name: Restore dependencies
+ run: dotnet restore
+
+ - name: Build
+ run: dotnet build --no-restore
+
+ - name: Test
+ run: dotnet test --no-build --verbosity normal
diff --git a/FeedsAPI/ConfigManager.cs b/FeedsAPI/ConfigManager.cs
index 9e44bc3..15600bb 100644
--- a/FeedsAPI/ConfigManager.cs
+++ b/FeedsAPI/ConfigManager.cs
@@ -35,7 +35,10 @@ public static Config Read()
{
try
{
- string appsettings = Path.ChangeExtension(Environment.ProcessPath!, ".config.json");
+ // Works in Windows, fails in Linux (/usr/lib/dotnet...)
+ // string appsettings = Path.ChangeExtension(Environment.ProcessPath!, ".config.json");
+
+ string appsettings = Path.Combine(AppContext.BaseDirectory, "FeedsAPI.config.json"); //TODO what?
if (File.Exists(appsettings))
{
diff --git a/FeedsAPI/FeedsAPI.csproj b/FeedsAPI/FeedsAPI.csproj
index 0c9693e..85a6e22 100644
--- a/FeedsAPI/FeedsAPI.csproj
+++ b/FeedsAPI/FeedsAPI.csproj
@@ -6,7 +6,7 @@
FeedsApi
enable
enable
- 8.2024.712
+ 8.2024.726
diev
2022-2024 Dmitrii Evdokimov
Получение фидов из FinCERT (АСОИ ФинЦЕРТ) Банка России. Обновление референсного проекта до TLS с сертификатами.
diff --git a/FeedsAPI/FincertAPI.cs b/FeedsAPI/FincertAPI.cs
index 74d1caa..6436fd5 100644
--- a/FeedsAPI/FincertAPI.cs
+++ b/FeedsAPI/FincertAPI.cs
@@ -150,7 +150,7 @@ public async Task LogoutFromASOIAsync()
{
try
{
- var response = await _tlsClient.PostAsJsonAsync(_api + "account/logout", string.Empty);
+ using var response = await _tlsClient.PostAsJsonAsync(_api + "account/logout", string.Empty);
response.EnsureSuccessStatusCode();
if (response.StatusCode == HttpStatusCode.OK)
@@ -204,7 +204,7 @@ public async Task LogoutFromASOIAsync()
for (int i = 0; i < 3; i++) // Сколько делаем попыток получить данные
{
- var response = await _tlsClient.GetAsync(_api + $"antifraud/feeds/{feed}");
+ using var response = await _tlsClient.GetAsync(_api + $"antifraud/feeds/{feed}");
response.EnsureSuccessStatusCode();
if (response.StatusCode == HttpStatusCode.OK) // Ответ получен
@@ -260,7 +260,7 @@ public async Task LogoutFromASOIAsync()
for (int i = 0; i < 3; i++) // Сколько делаем попыток получить данные
{
- var response = await _tlsClient.GetAsync(_api + $"antifraud/feeds/{feed}/download");
+ using var response = await _tlsClient.GetAsync(_api + $"antifraud/feeds/{feed}/download");
response.EnsureSuccessStatusCode();
if (response.StatusCode == HttpStatusCode.OK) // Ответ получен
diff --git a/FeedsAPI/README.md b/FeedsAPI/README.md
index 3ed8de8..e64872c 100644
--- a/FeedsAPI/README.md
+++ b/FeedsAPI/README.md
@@ -1,6 +1,7 @@
# FeedsAPI
[![Build status](https://ci.appveyor.com/api/projects/status/hpsbfj3qds34i4yb?svg=true)](https://ci.appveyor.com/project/diev/fincert-client)
+[![.NET8 Desktop](https://github.com/diev/FinCERT-Client/actions/workflows/dotnet8-desktop.yml/badge.svg)](https://github.com/diev/FinCERT-Client/actions/workflows/dotnet8-desktop.yml)
[![GitHub Release](https://img.shields.io/github/release/diev/FinCERT-Client.svg)](https://github.com/diev/FinCERT-Client/releases/latest)
Получение по API фидов из FinCERT (АСОИ ФинЦЕРТ) Банка России.
@@ -21,8 +22,8 @@ read-only.
## Config / Конфигурация
-При первом запуске и отсутствии файла конфигурации `.config.json`, он
-создается рядом с программой с параметрами по умолчанию.
+При первом запуске и отсутствии файла конфигурации `FeedsAPI.config.json`,
+он создается рядом с программой с параметрами по умолчанию.
Никакие другие конфиги, переменные среды окружения и т.п. не используются.
Важно заполнить вашими данными значения параметров:
@@ -35,6 +36,9 @@ read-only.
Если указываете файловые пути, то по правилам JSON надо удваивать `\\`
в Windows и использовать `/` в Linux.
+По окончании корректировки надо переключить параметр NewConfig = `true`
+в `false` или удалить эту строчку полностью.
+
## Exit codes / Коды возврата
* 0 - успешно;
@@ -44,21 +48,30 @@ read-only.
## Requirements / Требования
* .NET 6-7-8 (Windows или Linux)
-* КриптоПро для подключения с сертификатом TLS
+* КриптоПро CSP для установки соединения TLS
* Сертификат TLS клиента и цепочка доверия
* Логин и пароль
-Вариант Linux пока не тестировался, Stunnel программе не требуется.
+## Linux
+
+Вариант Linux протестирован в WSL без установки КриптоПро.
Пример сборки проекта под Linux (укажите нужную версию .NET) из папки
с файлом FeedsAPI.csproj:
dotnet publish -r linux-x64 -f net6.0 --self-contained
-Запуск:
+Запуск из папки с файлами программы:
dotnet FeedsAPI.dll
+## Breaking Changes / Важные изменения
+
+Выяснилось, что механизм получения файла настроек, работавший в Windows
+(одноименный и рядом с exe), в Linux дает неправильное размещение файла.
+Пока пришлось жестко прописать имя файла в коде. Далее придется менять
+эту схему именования, крайне удобную ранее.
+
## Versioning / Порядок версий
Номер версии программы указывается по нарастающему принципу и строится
@@ -80,5 +93,7 @@ read-only.
## License / Лицензия
-Licensed under the [Apache License, Version 2.0](LICENSE).
+Licensed under the [Apache License, Version 2.0](LICENSE).
Вы можете использовать эти материалы под свою ответственность.
+
+[![Telegram](https://img.shields.io/badge/t.me-dievdo-blue?logo=telegram)](https://t.me/dievdo)
diff --git a/FinCERT-Client/API/Bulletins.cs b/FinCERT-Client/API/Bulletins.cs
index 738b5a7..1be277f 100644
--- a/FinCERT-Client/API/Bulletins.cs
+++ b/FinCERT-Client/API/Bulletins.cs
@@ -80,7 +80,8 @@ internal static class Bulletins
public static async Task GetBulletinIdsAsync(int limit = 100, long offset = 0)
{
string url = $"bulletins?limit={limit}&offset={offset}";
- var response = await TlsClient.GetAsync(url);
+ using var response = await TlsClient.GetAsync(url);
+ response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync()
?? throw new BulletinsException(
"Список бюллетеней не получен.");
@@ -95,7 +96,8 @@ public static async Task GetBulletinIdsAsync(int limit = 100, long
public static async Task GetBulletinIdsAsync(string path, int limit = 100, long offset = 0)
{
string url = $"bulletins?limit={limit}&offset={offset}";
- var response = await TlsClient.GetAsync(url);
+ using var response = await TlsClient.GetAsync(url);
+ response.EnsureSuccessStatusCode();
using var output = File.Create(path);
await response.Content.CopyToAsync(output);
}
@@ -109,7 +111,8 @@ public static async Task GetBulletinInfosAsync(string[] ids)
{
string url = "bulletins/list";
var content = new BulletinList(ids);
- var response = await TlsClient.PostAsJsonAsync(url, content);
+ using var response = await TlsClient.PostAsJsonAsync(url, content);
+ response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync()
?? throw new BulletinsException(
"Информация по бюллетеням не получена.");
@@ -124,7 +127,8 @@ public static async Task GetBulletinInfosAsync(string[] ids, string path)
{
string url = "bulletins/list";
var content = new BulletinList(ids);
- var response = await TlsClient.PostAsJsonAsync(url, content);
+ using var response = await TlsClient.PostAsJsonAsync(url, content);
+ response.EnsureSuccessStatusCode();
using var output = File.Create(path);
await response.Content.CopyToAsync(output);
}
@@ -137,7 +141,8 @@ public static async Task GetBulletinInfosAsync(string[] ids, string path)
public static async Task GetBulletinAttachInfoAsync(string id)
{
string url = $"bulletins/{id}";
- var response = await TlsClient.GetAsync(url);
+ using var response = await TlsClient.GetAsync(url);
+ response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync()
?? throw new BulletinsException(
$"Информация по бюллетеню '{id}' не получена.");
@@ -151,7 +156,8 @@ public static async Task GetBulletinAttachInfoAsync(string i
public static async Task GetBulletinAttachInfoAsync(string id, string path)
{
string url = $"bulletins/{id}";
- var response = await TlsClient.GetAsync(url);
+ using var response = await TlsClient.GetAsync(url);
+ response.EnsureSuccessStatusCode();
using var output = File.Create(path);
await response.Content.CopyToAsync(output);
}
@@ -164,7 +170,8 @@ public static async Task GetBulletinAttachInfoAsync(string id, string path)
public static async Task DownloadAttachmentAsync(string id, string path)
{
string url = $"attachments/{id}/download";
- var response = await TlsClient.GetAsync(url);
+ using var response = await TlsClient.GetAsync(url);
+ response.EnsureSuccessStatusCode();
using var output = File.Create(path);
await response.Content.CopyToAsync(output);
}
diff --git a/FinCERT-Client/API/Feeds.cs b/FinCERT-Client/API/Feeds.cs
index 175a18b..8bc9a55 100644
--- a/FinCERT-Client/API/Feeds.cs
+++ b/FinCERT-Client/API/Feeds.cs
@@ -39,7 +39,8 @@ internal static class Feeds
public static async Task GetFeedsStatusAsync(FeedType feed)
{
string url = $"antifraud/feeds/{feed}";
- var response = await TlsClient.GetAsync(url);
+ using var response = await TlsClient.GetAsync(url);
+ response.EnsureSuccessStatusCode();
return await response.Content.ReadFromJsonAsync()
?? throw new FeedsException("Статус фидов не получен.");
}
@@ -54,7 +55,8 @@ public static async Task DownloadFeedsAsync(FeedType feed, string path)
Directory.CreateDirectory(path);
string url = $"antifraud/feeds/{feed}/download";
- var response = await TlsClient.GetAsync(url);
+ using var response = await TlsClient.GetAsync(url);
+ response.EnsureSuccessStatusCode();
string name = feed switch
{
diff --git a/FinCERT-Client/FinCERT-Client.csproj b/FinCERT-Client/FinCERT-Client.csproj
index 7a2c0c0..ccb6a23 100644
--- a/FinCERT-Client/FinCERT-Client.csproj
+++ b/FinCERT-Client/FinCERT-Client.csproj
@@ -6,7 +6,7 @@
FincertClient
enable
enable
- 8.2024.712
+ 8.2024.726
diev
2022-2024 Dmitrii Evdokimov
Получение фидов и бюллетеней из FinCERT (АСОИ ФинЦЕРТ) Банка России.
diff --git a/FinCERT-Client/Managers/ConfigManager.cs b/FinCERT-Client/Managers/ConfigManager.cs
index eaa745b..ce85b85 100644
--- a/FinCERT-Client/Managers/ConfigManager.cs
+++ b/FinCERT-Client/Managers/ConfigManager.cs
@@ -33,16 +33,23 @@ private static JsonSerializerOptions GetJsonOptions()
public static Config Read()
{
- string appsettings = Path.ChangeExtension(Environment.ProcessPath!, ".config.json");
+ // Works in Windows, fails in Linux (/usr/lib/dotnet...)
+ // string appsettings = Path.ChangeExtension(Environment.ProcessPath!, ".config.json");
+
+ string appsettings = Path.Combine(AppContext.BaseDirectory, "FinCERT-Client.config.json"); //TODO what?
if (File.Exists(appsettings))
{
using var read = File.OpenRead(appsettings);
var config = JsonSerializer.Deserialize(read);
- if (config is null || config.NewConfig)
+ if (config is null)
+ throw new NewConfigException(
+ @$"Файл настроек ""{appsettings}"" испорчен - удалите его.");
+
+ if (config.NewConfig)
throw new NewConfigException(
- );
+ @$"Откорректируйте файл настроек ""{appsettings}"" и отключите NewConfig.");
return config;
}
@@ -52,22 +59,20 @@ public static Config Read()
JsonSerializer.Serialize(write, newConfig, GetJsonOptions());
throw new NewConfigException(
- @$"Создан новый файл настроек ""{appsettings}"".");
+ @$"Создан новый файл настроек ""{appsettings}"" - откорректируйте его.");
}
}
internal class NewConfigException : Exception
{
- const string message = @"Необходимо откорректировать новый конфиг ""{0}"".";
-
public NewConfigException()
: base() { }
- public NewConfigException(string config)
- : base(string.Format(message, config)) { }
+ public NewConfigException(string message)
+ : base(message) { }
- public NewConfigException(string config, Exception inner)
- : base(string.Format(message, config), inner) { }
+ public NewConfigException(string message, Exception inner)
+ : base(message, inner) { }
}
public class ConfigException : Exception
diff --git a/README.md b/README.md
index 6d002ed..b0be97e 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,7 @@
# FinCERT-Client
[![Build status](https://ci.appveyor.com/api/projects/status/hpsbfj3qds34i4yb?svg=true)](https://ci.appveyor.com/project/diev/fincert-client)
+[![.NET8 Desktop](https://github.com/diev/FinCERT-Client/actions/workflows/dotnet8-desktop.yml/badge.svg)](https://github.com/diev/FinCERT-Client/actions/workflows/dotnet8-desktop.yml)
[![GitHub Release](https://img.shields.io/github/release/diev/FinCERT-Client.svg)](https://github.com/diev/FinCERT-Client/releases/latest)
Получение по API фидов и бюллетеней из FinCERT (АСОИ ФинЦЕРТ) Банка России.
@@ -49,14 +50,10 @@ feeds_20240703-03.zip), то его содержимое будет распак
## Config / Конфигурация
-При первом запуске и отсутствии файла конфигурации `.config.json`, он
-создается рядом с программой с параметрами по умолчанию.
+При первом запуске и отсутствии файла конфигурации `FinCERT-Client.config.json`,
+он создается рядом с программой с параметрами по умолчанию.
Никакие другие конфиги, переменные среды окружения и т.п. не используются.
-В этом файле есть параметр `NewConfig` (true) - программа будет ждать
-корректировки созданного нового файла конфигурации при каждом запуске,
-пока этот параметр не будет удален или переключен в false.
-
Важно заполнить вашими данными значения параметров:
* `MyThumbprint` - отпечаток сертификата клиента, зарегистрированного на
@@ -72,6 +69,9 @@ feeds_20240703-03.zip), то его содержимое будет распак
Если указываете файловые пути, то по правилам JSON надо удваивать `\\`
в Windows и использовать `/` в Linux.
+По окончании корректировки надо переключить параметр NewConfig = `true`
+в `false` или удалить эту строчку полностью.
+
## Parameters / Опциональные параметры командной строки
* `-checklist` - сформировать в папке `BulletinsDownloads\CheckList`
@@ -117,21 +117,32 @@ feeds_20240703-03.zip), то его содержимое будет распак
## Requirements / Требования
* .NET 6-7-8 (Windows или Linux)
-* КриптоПро для подключения с сертификатом TLS
+* КриптоПро CSP для установки соединения TLS
* Сертификат TLS клиента и цепочка доверия
* Логин и пароль
-Вариант Linux пока не тестировался, Stunnel программе не требуется.
+*Stunnel* программе не требуется - она сама поднимает соединение TLS.
+
+## Linux
+
+Вариант Linux протестирован в WSL без установки КриптоПро.
Пример сборки проекта под Linux (укажите нужную версию .NET) из папки
с файлом FinCERT-Client.csproj:
- dotnet publish -r linux-x64 -f net6.0 --self-contained
+ dotnet publish -r linux-x64 -f net8.0 --self-contained
-Запуск:
+Запуск из папки с файлами программы:
dotnet FinCERT-Client.dll
+## Breaking Changes / Важные изменения
+
+Выяснилось, что механизм получения файла настроек, работавший в Windows
+(одноименный и рядом с exe), в Linux дает неправильное размещение файла.
+Пока пришлось жестко прописать имя файла в коде. Далее придется менять
+эту схему именования, крайне удобную ранее.
+
## Versioning / Порядок версий
Номер версии программы указывается по нарастающему принципу и строится
@@ -153,5 +164,7 @@ feeds_20240703-03.zip), то его содержимое будет распак
## License / Лицензия
-Licensed under the [Apache License, Version 2.0](LICENSE).
+Licensed under the [Apache License, Version 2.0](LICENSE).
Вы можете использовать эти материалы под свою ответственность.
+
+[![Telegram](https://img.shields.io/badge/t.me-dievdo-blue?logo=telegram)](https://t.me/dievdo)
diff --git a/build.cmd b/build.cmd
index bbc824f..e146273 100644
--- a/build.cmd
+++ b/build.cmd
@@ -28,6 +28,10 @@ call :bin %1 %option% %prj% net6.0 x64
call :bin %1 %option% %prj% net7.0 x64
call :bin %1 %option% %prj% net8.0 x64
+rem Linux
+rem set option=4
+rem call :bin %1 %option% %prj% net8.0 x64
+
call :version_txt %1 %prj% > bin\version.txt
set pack=%1-v%version%.zip
@@ -47,10 +51,10 @@ rem %3 - project.csproj
rem %4 - net
rem %5 - x86/x64
echo === Build %1 %4 %5 ===
-if /%2/==/1/ dotnet publish %3 -o bin\%4\%5 -f %4 -r win-%5
-if /%2/==/2/ dotnet publish %3 -o bin\%4\%5 -f %4 -r win-%5 -p:PublishSingleFile=true --no-self-contained
-if /%2/==/3/ dotnet publish %3 -o bin\%4\%5 -f %4 -r win-%5 -p:PublishSingleFile=true
-if /%2/==/4/ dotnet publish %3 -o bin\%4\%5 -f %4 -r linux-%5 --self-contained
+if /%2/==/1/ dotnet publish %3 -o bin\%4.%5 -f %4 -r win-%5
+if /%2/==/2/ dotnet publish %3 -o bin\%4.%5 -f %4 -r win-%5 -p:PublishSingleFile=true --no-self-contained
+if /%2/==/3/ dotnet publish %3 -o bin\%4.%5 -f %4 -r win-%5 -p:PublishSingleFile=true
+if /%2/==/4/ dotnet publish %3 -o bin\%4.linux-%5 -f %4 -r linux-%5 --self-contained
goto :eof
:init
@@ -94,7 +98,8 @@ echo Requires .NET [Desktop] Runtime to run
echo Download from https://dotnet.microsoft.com/download
echo.
echo Run once to create %1.config.json
-echo and correct it
+echo correct it and switch NewConfig to false
+echo (or delete this row with NewConfig)
echo.
echo https://github.com/diev/%repo%
echo https://gitverse.ru/diev/%repo%