Basic formatting applied. Unnecessary comments have been removed. Suspicious code is covered by TODO.
133 lines
8.1 KiB
C#
133 lines
8.1 KiB
C#
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 все;
|
||
}
|
||
}
|
||
}
|