Add project
Basic formatting applied. Unnecessary comments have been removed. Suspicious code is covered by TODO.
This commit is contained in:
@ -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 все;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user