Files
hcs/Hcs.Client/ClientApi/HouseManagementApi/HcsContractRegistryDownloader.cs
HOME-LAPTOP\kshkulev 33ab055b43 Add project
Basic formatting applied. Unnecessary comments have been removed. Suspicious code is covered by TODO.
2025-08-12 11:21:10 +09:00

133 lines
8.1 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Hcs.ClientApi.DataTypes;
using System;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
namespace Hcs.ClientApi.HouseManagementApi
{
/// <summary>
/// Метод получения из ГИС ЖКХ полного реестра договоров ресурсоснабжения
/// и всех связанных с ними лицевых счетов и приборов учета
/// </summary>
internal class HcsContractRegistryDownloader
{
private HcsHouseManagementApi api;
internal HcsContractRegistryDownloader(HcsHouseManagementApi api)
{
this.api = api;
}
private void ThrowOperationCancelled()
{
throw new HcsException("Операция прервана пользователем");
}
/// <summary>
/// Получить все договоры РСО удовлетворяющие фильтру @фильтрДоговоров
/// с подчиненными объектами (ЛС и ПУ)
/// </summary>
internal async Task<ГисДоговорыИПриборы> ПолучитьВсеДоговорыИПриборы(
Func<ГисДоговор, bool> фильтрДоговоров, CancellationToken token)
{
// TODO: Проверить комментарий
// В процессе будет много запросов, возвращающих мало данных,
// но требующих стандартного ожидания в несколько секунд, что
// суммарно складывается в целые часы. Экспериментально установлено
// что ГИС ЖКХ способна пережить некоторую параллельность запросов
// к ней. Так, с параллельностью в 5 потоков получение данных
// по 3000 договорам РСО (70000 ПУ) длится 2,5 часа.
int числоПотоковПараллельности = 5;
var все = new ГисДоговорыИПриборы();
все.ДатаНачалаСборки = DateTime.Now;
Action<ГисДоговор> обработчикДоговора = (ГисДоговор договор) =>
{
if (фильтрДоговоров(договор)) все.ДоговорыРСО.Add(договор);
};
await api.ПолучитьДоговорыРСО(обработчикДоговора, token);
int сделаноДоговоров = 0;
Action<ГисАдресныйОбъект> обработчикАдреса = все.АдресаОбъектов.Add;
Func<ГисДоговор, Task> обработчикДоговораАдреса = async (договор) =>
{
if (token.IsCancellationRequested) ThrowOperationCancelled();
api.Config.Log($"Получаем адреса договора #{++сделаноДоговоров}/{все.ДоговорыРСО.Count()}...");
await api.ПолучитьАдресаДоговораРСО(договор, обработчикАдреса, token);
};
await HcsParallel.ForEachAsync(все.ДоговорыРСО, обработчикДоговораАдреса, числоПотоковПараллельности);
var гуидыЗданий = все.АдресаОбъектов.Select(x => x.ГуидЗданияФиас).Distinct();
int сделаноЗданий = 0;
Func<Guid, Task> обработчикЗдания = async (гуидЗдания) =>
{
if (token.IsCancellationRequested) ThrowOperationCancelled();
api.Config.Log($"Получаем помещения здания #{++сделаноЗданий}/{гуидыЗданий.Count()}...");
try
{
var здание = await api.ПолучитьЗданиеПоГуидФиас(гуидЗдания, token);
все.Здания.Add(здание);
}
catch (Exception e)
{
if (HcsRemoteException.ContainsErrorCode(e, HcsRemoteException.KnownCodes.ОтсутствуетВРеестре))
{
api.Config.Log($"Не удалось получить здание по ФИАС ГУИД {гуидЗдания}: здание отсутствует в реестре");
var здание = new ГисЗдание() { ГуидЗданияФиас = гуидЗдания };
все.Здания.Add(здание);
}
else if (HcsRemoteException.ContainsErrorCode(e, HcsRemoteException.KnownCodes.ДоступЗапрещен))
{
api.Config.Log($"Не удалось получить здание по ФИАС ГУИД {гуидЗдания}: доступ запрещен");
var здание = new ГисЗдание() { ГуидЗданияФиас = гуидЗдания };
все.Здания.Add(здание);
}
else
{
throw new HcsException($"Вложенная ошибка получения здания {гуидЗдания}", e);
}
}
};
await HcsParallel.ForEachAsync(гуидыЗданий, обработчикЗдания, числоПотоковПараллельности);
сделаноЗданий = 0;
Action<ГисЛицевойСчет> обработчикЛС = (ГисЛицевойСчет лс) =>
{
if (лс.ДействуетСейчас && все.ЭтотЛицевойСчетСвязанСДоговорами(лс))
{
все.ЛицевыеСчета.Add(лс);
}
};
Func<Guid, Task> обработчикЗданияЛС = async (гуидЗдания) =>
{
if (token.IsCancellationRequested) ThrowOperationCancelled();
api.Config.Log($"Получаем ЛС по зданию #{++сделаноЗданий}/{гуидыЗданий.Count()}...");
await api.ПолучитьЛицевыеСчетаПоЗданию(гуидЗдания, обработчикЛС, token);
};
await HcsParallel.ForEachAsync(гуидыЗданий, обработчикЗданияЛС, числоПотоковПараллельности);
сделаноЗданий = 0;
Action<ГисПриборУчета> обработчикПУ = (ГисПриборУчета прибор) =>
{
if (прибор.ЭтоАктивный && (прибор.ЭтоОДПУ || все.ЭтотПриборСвязанСЛицевымиСчетами(прибор)))
{
все.ПриборыУчета.Add(прибор);
}
};
Func<Guid, Task> обработчикЗданияПУ = async (гуидЗдания) =>
{
if (token.IsCancellationRequested) ThrowOperationCancelled();
api.Config.Log($"Получаем ПУ по зданию #{++сделаноЗданий}/{гуидыЗданий.Count()}...");
await api.ПолучитьПриборыУчетаПоЗданию(гуидЗдания, обработчикПУ, token);
};
await HcsParallel.ForEachAsync(гуидыЗданий, обработчикЗданияПУ, числоПотоковПараллельности);
все.ДатаКонцаСборки = DateTime.Now;
return все;
}
}
}