Add project

Basic formatting applied. Unnecessary comments have been removed. Suspicious code is covered by TODO.
This commit is contained in:
2025-08-12 11:21:10 +09:00
parent bbcbe841a7
commit 33ab055b43
546 changed files with 176950 additions and 0 deletions

View File

@ -0,0 +1,132 @@
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 все;
}
}
}