Compare commits
19 Commits
59b8f4bbb9
...
243d1551d1
| Author | SHA1 | Date | |
|---|---|---|---|
| 243d1551d1 | |||
| d512a8afc4 | |||
| 04bf10f65c | |||
| b340b9ef46 | |||
| 441a70edaf | |||
| ddcc46c3d0 | |||
| a170168f21 | |||
| e6ce1ba938 | |||
| e76e3c9a9f | |||
| e49aa18ced | |||
| 9b13701441 | |||
| 920904fe11 | |||
| 7758c13742 | |||
| 671e065ebc | |||
| 26bd4d1da9 | |||
| ec61534f17 | |||
| 5f137b8fae | |||
| bab1031833 | |||
| 63ee35b527 |
@ -2,7 +2,7 @@
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net6.0-windows</TargetFramework>
|
||||
<TargetFramework>net9.0-windows7.0</TargetFramework>
|
||||
<ImplicitUsings>enable</ImplicitUsings>
|
||||
<Nullable>enable</Nullable>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
@ -34,10 +34,8 @@
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Databasic" Version="1.2.7" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||
<PackageReference Include="Npgsql" Version="6.0.4" />
|
||||
<PackageReference Include="System.Data.OleDb" Version="6.0.0" />
|
||||
<PackageReference Include="Npgsql" Version="9.0.3" />
|
||||
<PackageReference Include="System.Data.OleDb" Version="9.0.9" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
745
Program.cs
745
Program.cs
@ -1,234 +1,225 @@
|
||||
// See https://aka.ms/new-console-template for more information
|
||||
using Npgsql;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Data;
|
||||
using System.Data.OleDb;
|
||||
using System.Globalization;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Xml.Linq;
|
||||
using Npgsql;
|
||||
|
||||
internal class Plat_integ
|
||||
{
|
||||
static string PG_CONN_STRING_DEV = "Server = smart-energia-dev-pgsql.cykff7tj7mik.us-east-1.rds.amazonaws.com; Port = 5432; Database = smartimptest; User Id = postgres; Password = VfHml#Z78!%kvvNM;";
|
||||
static string PG_CONN_STRING_PROD = "Server = smart-energia-dev-pgsql.cykff7tj7mik.us-east-1.rds.amazonaws.com; Port = 5432; Database = smartenergiaprod; User Id = postgres; Password = VfHml#Z78!%kvvNM; Timeout = 300;CommandTimeout = 300";
|
||||
static string ENVIRONMENT = "dev"; // "dev" | "prod"
|
||||
public static IEnumerable<XElement>? pag_ant;
|
||||
static void Main(string[] args)
|
||||
static string PG_CONN_STRING_PROD = "Server = smart-energia-dev-pgsql.cykff7tj7mik.us-east-1.rds.amazonaws.com; Port = 5432; Database = smartenergiaprod; Username = postgres; Password = VfHml#Z78!%kvvNM; Timeout = 60; CommandTimeout = 60; ApplicationName = new_med_5_min; Connection Lifetime = 120; Minimum Pool Size = 2; Maximum Pool Size = 2;";
|
||||
static readonly HttpClient client = new HttpClient(new HttpClientHandler
|
||||
{
|
||||
bool loadFromArgs = false;
|
||||
if (args.Length > 0)
|
||||
{
|
||||
loadFromArgs = true;
|
||||
}
|
||||
ClientCertificateOptions = ClientCertificateOption.Automatic,
|
||||
//Proxy = new WebProxy("127.0.0.1", 8888),
|
||||
//UseProxy = true,
|
||||
//ServerCertificateCustomValidationCallback = (HttpRequestMessage req, X509Certificate2? cert, X509Chain? chain, SslPolicyErrors errors) => true
|
||||
});
|
||||
|
||||
down_sync(loadFromArgs, args); //metodo sincrono
|
||||
|
||||
Console.WriteLine("" +
|
||||
"Pressione qualquer tecla para finalizar");
|
||||
_ = Console.ReadLine();
|
||||
Environment.Exit(0);
|
||||
return;
|
||||
}
|
||||
public static void down_sync(bool loadFromArgs, string[] args)
|
||||
static async Task Main()
|
||||
{
|
||||
string caminho_BD, caminho_log, caminho_log_sec;
|
||||
DateTime tempo_ini;
|
||||
List<Tuple<string, string>> lt_perf_pto;
|
||||
|
||||
Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture("en-GB");
|
||||
DateTime inicio = DateTime.Now;
|
||||
|
||||
//auxiliar para calculo do tempo de execucao do codigo
|
||||
tempo_ini = DateTime.Now;
|
||||
string caminhoBD = @"\\srv-dados\documentos\Middle\Informativo Setorial\Modelo Word\BD1_dados cadastrais e faturas.accdb";
|
||||
string caminhoLog = $@"\\srv-dados\documentos\Back\Carteira x.x\Codigo\Erros\log_erros_{DateTime.Now:MM_dd_HH_mm}.csv";
|
||||
|
||||
//busca os dados para compor a lista perfis x
|
||||
caminho_BD = @"\\srv-dados\documentos\Middle\Informativo Setorial\Modelo Word\BD1_dados cadastrais e faturas.accdb";
|
||||
caminho_log = @"\\srv-dados\documentos\Back\Carteira x.x\Codigo\Erros\log_erros_" + DateTime.Now.Month + "_" + DateTime.Now.Day + "_" + DateTime.Now.Hour + "_" + DateTime.Now.Second + ".csv";
|
||||
lt_perf_pto = Busca_dad_BD(caminho_BD); //ACCESS OK - PG OK
|
||||
|
||||
//exlclui os dados do mes atual salvos no BD
|
||||
caminho_BD = @"\\srv-dados\documentos\Back\Carteira x.x\Gestão Geral v1\Access\BDs teste\DB_med_5min.accdb";
|
||||
DateTime now = DateTime.Now;
|
||||
//PROD
|
||||
DateTime data_ini;
|
||||
DateTime data_fim;
|
||||
if (loadFromArgs)
|
||||
{
|
||||
int ano_ini = Int32.Parse(args[0]);
|
||||
int mes_ini = Int32.Parse(args[1]);
|
||||
int ano_fim = Int32.Parse(args[2]);
|
||||
int mes_fim = Int32.Parse(args[3]);
|
||||
//DateTime dataIni = new DateTime(now.Year, now.Month, 1);
|
||||
//DateTime dataFim = new DateTime(now.Year, now.Month, now.Day);
|
||||
DateTime dataIni = new DateTime(now.Year, 7, 1);
|
||||
DateTime dataFim = new DateTime(now.Year, 8, 1);
|
||||
|
||||
data_ini = new DateTime(ano_ini, mes_ini, 1);
|
||||
data_fim = new DateTime(ano_fim, mes_fim, 1).AddMonths(1);
|
||||
}
|
||||
else
|
||||
var perfis = Busca_dad_BD(caminhoBD, dataIni);
|
||||
|
||||
await ProcessarMedicoesAsync(dataIni, dataFim, perfis, caminhoLog);
|
||||
|
||||
Console.WriteLine($"Concluído. Tempo total: {DateTime.Now - inicio}");
|
||||
|
||||
Console.ReadKey();
|
||||
}
|
||||
public static List<perfil> Busca_dad_BD(string caminho_BD, DateTime dataIni)
|
||||
{
|
||||
var lista = new List<perfil>();
|
||||
|
||||
string query = $"SELECT Cod_5min, Codigo_SCDE, Data_de_Migracao FROM Dados_cadastrais WHERE LEN(Codigo_SCDE) > 5 AND Unidade_gerenciada ORDER BY cod_smart_unidade";
|
||||
//string query = "SELECT Cod_5min, Codigo_SCDE FROM Dados_cadastrais WHERE LEN(Codigo_SCDE) > 5 and (Cliente = 'RMC ALIMENTOS' OR Cliente = 'FERREIRA SUPERMERCADO' OR Cliente = 'VANGUARDA ALIMENTOS') AND Unidade_gerenciada ORDER BY PerfilCCEE";
|
||||
//string query = "SELECT Cod_5min, Codigo_SCDE FROM Dados_cadastrais WHERE LEN(Codigo_SCDE) > 5 and Cliente = 'ALMAVIVA' and Unidade = 'GUARULHOS' AND unidadade_gerenciada ORDER BY PerfilCCEE";
|
||||
//string query = "SELECT Cod_5min, Codigo_SCDE FROM Dados_cadastrais WHERE LEN(Codigo_SCDE) > 5 and Cliente = 'bramagran' AND Unidade_gerenciada ORDER BY PerfilCCEE";
|
||||
using (var connection = new OleDbConnection($"Provider=Microsoft.ACE.OLEDB.12.0;Data Source={caminho_BD};Jet OLEDB:Database Password=gds21"))
|
||||
{
|
||||
if (ENVIRONMENT is "dev")
|
||||
using var cmd = new OleDbCommand(query, connection);
|
||||
connection.Open();
|
||||
using var reader = cmd.ExecuteReader();
|
||||
|
||||
while (reader.Read())
|
||||
{
|
||||
data_ini = new DateTime(2021, 3, 1);
|
||||
data_fim = new DateTime(2021, 3, 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
//configuração mês atual
|
||||
data_ini = new DateTime(now.Year, now.Month, 1);
|
||||
data_fim = new DateTime(now.Year, now.Month, now.Day);
|
||||
lista.Add(
|
||||
new perfil(
|
||||
reader["Cod_5min"].ToString(),
|
||||
reader["Codigo_SCDE"].ToString(),
|
||||
DateTime.Parse(reader["Data_de_Migracao"].ToString())
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
Exclui_med(data_ini.ToOADate(), data_fim.ToOADate(), caminho_BD);
|
||||
//abre a conexao com o BD onde serao salvos os dados
|
||||
caminho_BD = @"\\srv-dados\documentos\Back\Carteira x.x\Gestão Geral v1\Access\BDs teste\DB_med_5min.accdb";
|
||||
OleDbConnection access_conn = new("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + caminho_BD + ";Jet OLEDB:Database Password=gds21");
|
||||
|
||||
NpgsqlConnection pg_conn;
|
||||
if (ENVIRONMENT is "dev")
|
||||
{
|
||||
pg_conn = new(PG_CONN_STRING_DEV);
|
||||
}
|
||||
else
|
||||
{
|
||||
pg_conn = new(PG_CONN_STRING_PROD);
|
||||
}
|
||||
|
||||
//loop para cada dia e cada cod ponto salvando os dados no BD
|
||||
req_sincrona(data_ini, data_fim, lt_perf_pto, access_conn, pg_conn, caminho_log);
|
||||
|
||||
Console.WriteLine("Concluido. Tempo TOTAL de execucao: {0}", DateTime.Now - tempo_ini);
|
||||
return lista;
|
||||
}
|
||||
|
||||
//busca lista de PerfisCCEE e codigos ponto de medicao no BD cadastral
|
||||
public static List<Tuple<string, string>> Busca_dad_BD(string caminho_BD)
|
||||
private static async Task ProcessarMedicoesAsync(DateTime dataIni, DateTime dataFim, List<perfil> perfis, string caminhoLog)
|
||||
{
|
||||
var lt_perf_pto = new List<Tuple<string, string>>();
|
||||
var limiter = new RateLimiter(400, TimeSpan.FromMinutes(1));
|
||||
|
||||
string strCOM;
|
||||
int i;
|
||||
var errosPersistentes = new ConcurrentBag<string>();
|
||||
var atualizados = new ConcurrentBag<string>();
|
||||
var inseridos = new ConcurrentBag<string>();
|
||||
|
||||
//strCOM = "SELECT Cod_5min, Codigo_SCDE FROM Dados_cadastrais WHERE LEN(Codigo_SCDE) > 5 AND Unidade_gerenciada = TRUE ORDER BY PerfilCCEE";
|
||||
strCOM = "SELECT Cod_5min, Codigo_SCDE FROM Dados_cadastrais WHERE LEN(Codigo_SCDE) > 5 and Cliente = 'PENHASCO GRANITOS' ORDER BY PerfilCCEE";
|
||||
//strCOM = "SELECT Cod_5min, Codigo_SCDE FROM Dados_cadastrais WHERE LEN(Codigo_SCDE) > 5 and Cliente = 'ALMAVIVA' and Unidade = 'GUARULHOS' ORDER BY PerfilCCEE";
|
||||
OleDbConnection conn = new("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + caminho_BD + ";Jet OLEDB:Database Password=gds21");
|
||||
conn.Open();
|
||||
OleDbCommand tcDC = new(strCOM, conn);
|
||||
OleDbDataReader reader = tcDC.ExecuteReader();
|
||||
await using var dataSource = NpgsqlDataSource.Create(PG_CONN_STRING_PROD);
|
||||
|
||||
i = 0;
|
||||
while (reader.Read())
|
||||
{
|
||||
lt_perf_pto.Add(new Tuple<string, string>(reader["Cod_5min"].ToString(), reader["Codigo_SCDE"].ToString()));
|
||||
i++;
|
||||
}
|
||||
|
||||
conn.Close();
|
||||
return lt_perf_pto;
|
||||
}
|
||||
|
||||
//Exlclui dados do mes atual no BD medicoes
|
||||
public static void Exclui_med(double data_ini, double data_fim, string caminho_BD)
|
||||
{
|
||||
//ACCESS DB
|
||||
string strCOM;
|
||||
//strCOM = "DELETE FROM Med_5min WHERE Data >= " + data_ini + " AND Data <= "+data_fim;
|
||||
//OleDbConnection conn = new("Provider=Microsoft.ACE.OLEDB.12.0;Data Source=" + caminho_BD + ";Jet OLEDB:Database Password=gds21");
|
||||
//conn.Open();
|
||||
//OleDbCommand tcSCDE = new(strCOM, conn);
|
||||
//tcSCDE.ExecuteReader();
|
||||
//conn.Close();
|
||||
|
||||
//POSTGRE
|
||||
NpgsqlConnection pg_conn;
|
||||
if (ENVIRONMENT is "dev")
|
||||
{
|
||||
pg_conn = new(PG_CONN_STRING_DEV);
|
||||
}
|
||||
else
|
||||
{
|
||||
pg_conn = new(PG_CONN_STRING_PROD);
|
||||
}
|
||||
pg_conn.Open();
|
||||
//string pg_strCOM = "DELETE FROM med_5min WHERE dia_num >= " + data_ini + " AND dia_num < " + data_fim;
|
||||
string pg_strCOM = "DELETE FROM med_5min WHERE dia_num >= " + data_ini + " AND dia_num < " + data_fim + " AND ponto = 'ESPMSOENTR101P'";
|
||||
NpgsqlCommand pg_tcSCDE = new(pg_strCOM, pg_conn);
|
||||
NpgsqlDataReader pg_reader = pg_tcSCDE.ExecuteReader();
|
||||
pg_reader.Close();
|
||||
pg_conn.Close();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
public static void req_sincrona(DateTime data_inicial, DateTime data_final, List<Tuple<string, string>> lt_perf_pto, OleDbConnection access_conn, NpgsqlConnection pg_conn, string caminho_log)
|
||||
{
|
||||
string log_erros;
|
||||
int i;
|
||||
long erros = 0;
|
||||
var handler = new HttpClientHandler();
|
||||
int tam_arr;
|
||||
tam_arr = ((data_final - data_inicial).Days) * lt_perf_pto.Count;
|
||||
|
||||
handler.ClientCertificateOptions = ClientCertificateOption.Automatic;
|
||||
|
||||
DateTime aux_tempo = DateTime.Now;
|
||||
var client = new HttpClient(handler);
|
||||
client.DefaultRequestHeaders.Add("SOAPAction", "listarMedidaCincoMinutos");
|
||||
var endpoint = new Uri("https://servicos.ccee.org.br:443/ws/v2/MedidaCincoMinutosBSv2");
|
||||
var endpoint = new Uri("https://servicos.ccee.org.br/ws/v2/MedidaCincoMinutosBSv2");
|
||||
|
||||
i = 0;
|
||||
log_erros = "Perfil;Ponto;Status;Message\n";
|
||||
var datas = Enumerable.Range(0, (dataFim - dataIni).Days).Select(i => dataIni.AddDays(i));
|
||||
|
||||
while (data_inicial < data_final)
|
||||
await Parallel.ForEachAsync(perfis, async (perfil, ct) =>
|
||||
{
|
||||
foreach (Tuple<string, string> item in lt_perf_pto)
|
||||
try
|
||||
{
|
||||
int pagina = 1;
|
||||
int paginasTotal = 1;
|
||||
try
|
||||
Console.WriteLine($"{DateTime.Now}: Iniciado ponto {perfil._Codigo_SCDE}");
|
||||
if (perfil._Cod_5min == "0" || perfil._Cod_5min == string.Empty)
|
||||
{
|
||||
while (pagina <= paginasTotal)
|
||||
{
|
||||
var payload = new StringContent(Xml_requisicao(data_inicial, item.Item1, item.Item2, pagina), Encoding.UTF8, "application/json");
|
||||
var retorno = client.PostAsync(endpoint, payload).Result.Content.ReadAsStringAsync().Result.ToString();
|
||||
Console.WriteLine("Processando requisicao {0,5}, Perf: {1,6}, Ponto: {2,10}, Página: {3}", i, item.Item1, item.Item2, pagina);
|
||||
if (access_conn != null && access_conn.State == ConnectionState.Closed)
|
||||
{
|
||||
access_conn.Open();
|
||||
}
|
||||
if (pg_conn != null && pg_conn.State == ConnectionState.Closed)
|
||||
{
|
||||
pg_conn.Open();
|
||||
}
|
||||
paginasTotal = processar_XML_sincrono(retorno, access_conn, pg_conn);
|
||||
Console.WriteLine($"Pular {perfil._Codigo_SCDE} - (cod 5 min pendente)");
|
||||
errosPersistentes.Add($"{perfil._Cod_5min};{perfil._Codigo_SCDE}; cod_5min pendente");
|
||||
return;
|
||||
}
|
||||
string sqlSelect = @"
|
||||
SELECT ponto, dia_num, minuto, origem,
|
||||
ativa_consumo, ativa_geracao, reativa_consumo, reativa_geracao
|
||||
FROM med_5min
|
||||
WHERE ponto = @ponto AND dia_num >= @data_ini AND dia_num < @data_fim;
|
||||
";
|
||||
|
||||
pagina++;
|
||||
var existentes = new Dictionary<(string, double, int), dynamic>();
|
||||
|
||||
await using (var command = dataSource.CreateCommand(sqlSelect))
|
||||
{
|
||||
|
||||
command.Parameters.AddWithValue("ponto", perfil._Codigo_SCDE + "P");
|
||||
command.Parameters.AddWithValue("data_ini", dataIni.ToOADate());
|
||||
command.Parameters.AddWithValue("data_fim", dataFim.ToOADate());
|
||||
|
||||
await using (var reader = await command.ExecuteReaderAsync(ct))
|
||||
{
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
existentes[(reader.GetString(0), reader.GetDouble(1), reader.GetInt32(2))] = new
|
||||
{
|
||||
Origem = reader.GetString(3),
|
||||
AtivaC = reader.GetDouble(4),
|
||||
AtivaG = reader.GetDouble(5),
|
||||
ReatC = reader.GetDouble(6),
|
||||
ReatG = reader.GetDouble(7)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception he)
|
||||
|
||||
foreach (DateTime dia in datas)
|
||||
{
|
||||
Console.WriteLine(he.Message);
|
||||
Console.WriteLine("caught exception");
|
||||
erros++;
|
||||
log_erros += item.Item1 + ";" + item.Item2 + ";Erro;" + he.Message.Replace("\n", "-n-") + "\n";
|
||||
continue;
|
||||
int tentativas = 0;
|
||||
bool sucesso = false;
|
||||
|
||||
while (tentativas < 5 && !sucesso)
|
||||
{
|
||||
if (perfil._Data_de_Migracao > dia)
|
||||
{
|
||||
Console.WriteLine($"Pular {perfil._Codigo_SCDE} - {dia.ToShortDateString()} (antes da migração)");
|
||||
errosPersistentes.Add($"{perfil._Cod_5min};{perfil._Codigo_SCDE};Fora da data de migração {perfil._Data_de_Migracao} x {dia}");
|
||||
break; // não tentar antes da data de migração
|
||||
}
|
||||
try
|
||||
{
|
||||
string payload = Xml_requisicao(dia, perfil._Cod_5min, perfil._Codigo_SCDE, 1);
|
||||
var conteudo = new StringContent(payload, Encoding.UTF8, "application/xml");
|
||||
|
||||
await limiter.WaitAsync(ct);
|
||||
using var response = await client.PostAsync(endpoint, conteudo, ct);
|
||||
string resposta = await response.Content.ReadAsStringAsync();
|
||||
|
||||
if ((int)response.StatusCode >= 400)
|
||||
{
|
||||
try
|
||||
{
|
||||
VerificarRespostaSOAP(resposta);
|
||||
}
|
||||
catch (SoapFaultException ex)
|
||||
{
|
||||
if (ex.ErrorCode == "2003") // limite de requisições
|
||||
{
|
||||
var now = DateTime.UtcNow;
|
||||
var delay = 60000 - (now.Second * 1000 + now.Millisecond);
|
||||
Console.WriteLine($"!! Limite de requisições atingido. Aguardando até {DateTime.Now.AddMilliseconds(delay)}");
|
||||
await Task.Delay(delay, ct); // tentar de novo sem contar como falha
|
||||
continue;
|
||||
}
|
||||
if (ex.ErrorCode == "4001") // Dados não encontrados
|
||||
{
|
||||
errosPersistentes.Add($"{perfil._Cod_5min};{perfil._Codigo_SCDE};SOAP Fault: {ex.ErrorCode};{ex.ErrorMessage.Replace("\n", "-n-")}");
|
||||
break;
|
||||
}
|
||||
if (ex.ErrorCode == "2001") // Sem acesso
|
||||
{
|
||||
errosPersistentes.Add($"{perfil._Cod_5min};{perfil._Codigo_SCDE};SOAP Fault: {ex.ErrorCode};{ex.ErrorMessage.Replace("\n", "-n-")}");
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
await ProcessarXMLAsync(resposta, dataSource, dia, perfil._Cod_5min, perfil._Codigo_SCDE, existentes, limiter, ct, 1);
|
||||
|
||||
sucesso = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
tentativas++;
|
||||
if (tentativas >= 5)
|
||||
{
|
||||
errosPersistentes.Add($"{perfil._Cod_5min};{perfil._Codigo_SCDE};Erro;{ex.Message.Replace("\n", "-n-")}");
|
||||
}
|
||||
else
|
||||
{
|
||||
int backoff = (int)Math.Pow(2.4, tentativas) * 1000; // exponencial
|
||||
Console.WriteLine($"Erro na requisição ({ex.Message}), tentativa {tentativas}. Aguardando {backoff / 1000}s...");
|
||||
await Task.Delay(backoff);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
pag_ant = null;
|
||||
Console.WriteLine($"{DateTime.Now}: Finalizado ponto {perfil._Codigo_SCDE}");
|
||||
}
|
||||
data_inicial = data_inicial.AddDays(1);
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex.ToString());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
if (errosPersistentes.Count > 0)
|
||||
{
|
||||
File.WriteAllLines(caminhoLog, new[] { "Perfil;Ponto;Status;Message" }.Concat(errosPersistentes));
|
||||
}
|
||||
|
||||
Console.WriteLine("Houve {0} requisicoes, com {1} erros", i, erros);
|
||||
File.WriteAllText(caminho_log, log_erros);
|
||||
client.Dispose();
|
||||
}
|
||||
|
||||
//prepara o xml de entrada a ser enviado à CCEE
|
||||
public static string Xml_requisicao(DateTime data_req, string perfil, string cod_ponto, int pagina)
|
||||
{
|
||||
string cam_ent, tex_req, sdat_req;
|
||||
//cam_ent = @"X:\Back\Plataforma de Integração CCEE\Medições\RequestPaginate.txt";
|
||||
cam_ent = @"X:\Back\Plataforma de Integração CCEE\RequestPaginate.txt";
|
||||
cod_ponto += "P";
|
||||
sdat_req = data_req.ToString("yyyy-MM-ddT00:00:00"); //2022-12-31T00:00:00
|
||||
sdat_req = data_req.ToString("yyyy-MM-ddT00:00:00");
|
||||
tex_req = File.ReadAllText(cam_ent);
|
||||
tex_req = tex_req.Replace("DATAALTERADA", sdat_req);
|
||||
tex_req = tex_req.Replace("PONTOMEDICAO", cod_ponto);
|
||||
@ -236,179 +227,253 @@ internal class Plat_integ
|
||||
tex_req = tex_req.Replace("PAGNUM", pagina.ToString());
|
||||
return tex_req;
|
||||
}
|
||||
public static int processar_XML_sincrono(string entrada, OleDbConnection access_conn, NpgsqlConnection pg_conn)
|
||||
|
||||
private static async Task ProcessarXMLAsync(string xml, NpgsqlDataSource dataSource, DateTime dia, string perfil, string ponto, Dictionary<(string, double, int), dynamic> existentes, RateLimiter limiter, CancellationToken ct, int paginaAtual = 1, List<XElement> acumulador = null, int totalPaginas = 1)
|
||||
{
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.LoadXml(entrada);
|
||||
DateTime aux_data = new DateTime(2005, 01, 01);
|
||||
DateTime tempo_xml;
|
||||
string access_strCOM, pg_strCOM, log_erros;
|
||||
XElement pag_atual;
|
||||
var doc = XDocument.Parse(xml);
|
||||
XNamespace ns = "http://xmlns.energia.org.br/BO/v2";
|
||||
|
||||
pag_atual = XElement.Parse(entrada);
|
||||
tempo_xml = DateTime.Now;
|
||||
int.TryParse(doc.Descendants().FirstOrDefault(e => e.Name.LocalName == "totalPaginas")?.Value, out totalPaginas);
|
||||
int.TryParse(doc.Descendants().FirstOrDefault(e => e.Name.LocalName == "numero")?.Value, out paginaAtual);
|
||||
|
||||
double data, ativa_g, ativa_c, reat_g, reat_c;
|
||||
long min;
|
||||
string ponto, origem;
|
||||
|
||||
XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);
|
||||
nsmgr.AddNamespace("hdr", "http://xmlns.energia.org.br/MH/v2");
|
||||
nsmgr.AddNamespace("soapenv", "http://schemas.xmlsoap.org/soap/envelope");
|
||||
nsmgr.AddNamespace("xsi", "http://www.w3.org/2001/XMLSchema-instance");
|
||||
nsmgr.AddNamespace("bmv2", "http://xmlns.energia.org.br/BM/v2");
|
||||
nsmgr.AddNamespace("bov2", "http://xmlns.energia.org.br/BO/v2");
|
||||
var medidas = doc.Descendants(ns + "medida")
|
||||
.Where(x => (string)x.Element(ns + "tipoEnergia") == "L");
|
||||
|
||||
if (access_conn.State != ConnectionState.Open)
|
||||
acumulador ??= new List<XElement>();
|
||||
acumulador.AddRange(medidas);
|
||||
|
||||
if (paginaAtual < totalPaginas)
|
||||
{
|
||||
access_conn.Open();
|
||||
}
|
||||
if (pg_conn.State != ConnectionState.Open)
|
||||
{
|
||||
pg_conn.Open();
|
||||
// Requisita próxima página
|
||||
string payload = Xml_requisicao(dia, perfil, ponto, paginaAtual + 1);
|
||||
|
||||
var conteudo = new StringContent(payload, Encoding.UTF8, "application/xml");
|
||||
await limiter.WaitAsync(ct);
|
||||
using var resp = await client.PostAsync("https://servicos.ccee.org.br/ws/v2/MedidaCincoMinutosBSv2", conteudo);
|
||||
|
||||
string proxXml = await resp.Content.ReadAsStringAsync();
|
||||
|
||||
await ProcessarXMLAsync(proxXml, dataSource, dia, perfil, ponto, existentes, limiter, ct, paginaAtual + 1, acumulador, totalPaginas);
|
||||
return;
|
||||
}
|
||||
|
||||
log_erros = "Origem;Ponto;Status;Message\n";
|
||||
|
||||
ponto = "";
|
||||
origem = "";
|
||||
|
||||
|
||||
if (pag_ant == null)
|
||||
var medidasProcessadas = acumulador
|
||||
.Select(m =>
|
||||
{
|
||||
XNamespace ns = "http://xmlns.energia.org.br/BO/v2";
|
||||
string origem = m.Element(ns + "coletaMedicao")?.Element(ns + "tipo")?.Element(ns + "nome")?.Value ?? "";
|
||||
string ponto = m.Element(ns + "medidor")?.Element(ns + "codigo")?.Value ?? "";
|
||||
DateTime data = DateTime.Parse(m.Element(ns + "data")?.Value ?? "");
|
||||
double diaNum = (data.ToOADate() - data.ToOADate() % 1);
|
||||
int minuto = data.Hour * 60 + data.Minute;
|
||||
if (minuto == 0) { minuto = 1440; diaNum--; }
|
||||
|
||||
pag_ant = pag_atual.Descendants(ns + "medida").Where(x => x.Element(ns + "tipoEnergia").Value == "L");
|
||||
}
|
||||
else
|
||||
{
|
||||
XNamespace ns = "http://xmlns.energia.org.br/BO/v2";
|
||||
pag_ant = pag_ant.Concat(pag_atual.Descendants(ns + "medida").Where(x => x.Element(ns + "tipoEnergia").Value == "L"));
|
||||
}
|
||||
double.TryParse(m.Element(ns + "energiaAtiva")?.Element(ns + "consumo")?.Element(ns + "valor")?.Value, out double ativa_c);
|
||||
double.TryParse(m.Element(ns + "energiaAtiva")?.Element(ns + "geracao")?.Element(ns + "valor")?.Value, out double ativa_g);
|
||||
double.TryParse(m.Element(ns + "energiaReativa")?.Element(ns + "consumo")?.Element(ns + "valor")?.Value, out double reat_c);
|
||||
double.TryParse(m.Element(ns + "energiaReativa")?.Element(ns + "geracao")?.Element(ns + "valor")?.Value, out double reat_g);
|
||||
|
||||
try
|
||||
{
|
||||
int num_pag = 1;
|
||||
foreach (XmlNode n1 in doc.GetElementsByTagName("hdr:totalPaginas"))
|
||||
return new
|
||||
{
|
||||
int.TryParse(n1.InnerText, out num_pag);
|
||||
Origem = origem,
|
||||
Ponto = ponto,
|
||||
DiaNum = diaNum,
|
||||
Minuto = minuto,
|
||||
AtivaC = ativa_c,
|
||||
AtivaG = ativa_g,
|
||||
ReatC = reat_c,
|
||||
ReatG = reat_g
|
||||
};
|
||||
})
|
||||
.GroupBy(x => new { x.Ponto, x.DiaNum, x.Minuto })
|
||||
.Select(g =>
|
||||
{
|
||||
// Se houver alguma Inspeção Lógica → prioriza
|
||||
var logica = g.FirstOrDefault(x => x.Origem == "Inspeção Lógica");
|
||||
return logica ?? g.First(); // se não tiver lógica, pega qualquer (coleta diária)
|
||||
});
|
||||
|
||||
var novos = new List<dynamic>();
|
||||
var alterados = new List<dynamic>();
|
||||
|
||||
foreach (var m in medidasProcessadas)
|
||||
{
|
||||
var chave = (m.Ponto, m.DiaNum, m.Minuto);
|
||||
|
||||
if (!existentes.TryGetValue(chave, out var existente))
|
||||
{
|
||||
// não existe → inserir
|
||||
novos.Add(m);
|
||||
}
|
||||
int num_pag_atual = 1;
|
||||
foreach (XmlNode n1 in doc.GetElementsByTagName("hdr:numero"))
|
||||
else
|
||||
{
|
||||
int.TryParse(n1.InnerText, out num_pag_atual);
|
||||
}
|
||||
if (num_pag_atual == num_pag)
|
||||
{
|
||||
XmlNode node_ant = doc.SelectNodes("//bov2:medida", nsmgr).Item(5);
|
||||
using (var pg_writer = pg_conn.BeginBinaryImport("COPY med_5min (origem, dia_num, minuto, ativa_consumo, ativa_geracao, reativa_consumo, reativa_geracao, ponto) FROM STDIN (FORMAT BINARY)"))
|
||||
// existe mas mudou → atualizar
|
||||
if (existente.Origem != m.Origem ||
|
||||
existente.AtivaC != m.AtivaC ||
|
||||
existente.AtivaG != m.AtivaG ||
|
||||
existente.ReatC != m.ReatC ||
|
||||
existente.ReatG != m.ReatG)
|
||||
{
|
||||
for (int i = 0; i < pag_ant.Count(); i++)
|
||||
{
|
||||
XmlDocument nodeDoc = new XmlDocument();
|
||||
nodeDoc.LoadXml(pag_ant.ElementAt(i).ToString());
|
||||
XmlNode node = nodeDoc.SelectSingleNode("//bov2:medida", nsmgr);
|
||||
|
||||
if (node.SelectSingleNode("bov2:coletaMedicao//bov2:tipo//bov2:nome", nsmgr).InnerText == "Inspeção Lógica")
|
||||
{
|
||||
aux_data = DateTime.ParseExact(node.SelectSingleNode("bov2:data", nsmgr).InnerText, "yyyy-MM-dd'T'HH:mm:ss'-03:00'", null);
|
||||
data = (aux_data.ToOADate() - aux_data.ToOADate() % 1);
|
||||
min = aux_data.Hour * 60 + aux_data.Minute;
|
||||
|
||||
if (min == 0)
|
||||
{
|
||||
min = 1440;
|
||||
data = data - 1;
|
||||
}
|
||||
|
||||
ponto = node.SelectSingleNode("bov2:medidor//bov2:codigo", nsmgr).InnerText;
|
||||
origem = node.SelectSingleNode("bov2:coletaMedicao//bov2:tipo//bov2:nome", nsmgr).InnerText;
|
||||
|
||||
Double.TryParse(node.SelectSingleNode("bov2:energiaAtiva//bov2:consumo//bov2:valor", nsmgr).InnerText, out ativa_c);
|
||||
Double.TryParse(node.SelectSingleNode("bov2:energiaAtiva//bov2:geracao//bov2:valor", nsmgr).InnerText, out ativa_g);
|
||||
Double.TryParse(node.SelectSingleNode("bov2:energiaReativa//bov2:consumo//bov2:valor", nsmgr).InnerText, out reat_c);
|
||||
Double.TryParse(node.SelectSingleNode("bov2:energiaReativa//bov2:geracao//bov2:valor", nsmgr).InnerText, out reat_g);
|
||||
|
||||
access_strCOM = "INSERT INTO Med_5min (Origem, Data, Minuto, Ativa_consumo, Ativa_geracao, Reativa_consumo, Reativa_geracao, Ponto)";
|
||||
access_strCOM += " VALUES (\"" + origem + "\"," + data + "," + min + "," + ativa_c + "," + ativa_g + "," + reat_c + "," + reat_g + ",\"" + ponto + "\")";
|
||||
|
||||
pg_writer.StartRow();
|
||||
pg_writer.Write(origem);
|
||||
pg_writer.Write(data, NpgsqlTypes.NpgsqlDbType.Numeric);
|
||||
pg_writer.Write(min, NpgsqlTypes.NpgsqlDbType.Integer);
|
||||
pg_writer.Write(ativa_c, NpgsqlTypes.NpgsqlDbType.Numeric);
|
||||
pg_writer.Write(ativa_g, NpgsqlTypes.NpgsqlDbType.Numeric);
|
||||
pg_writer.Write(reat_c, NpgsqlTypes.NpgsqlDbType.Numeric);
|
||||
pg_writer.Write(reat_g, NpgsqlTypes.NpgsqlDbType.Numeric);
|
||||
pg_writer.Write(ponto);
|
||||
//PGSQL END
|
||||
node_ant = node;
|
||||
}
|
||||
else if (node.SelectSingleNode("bov2:coletaMedicao//bov2:tipo//bov2:nome", nsmgr).InnerText == "Coleta Diária")
|
||||
{
|
||||
var data_fut = "a";
|
||||
if (i + 1 < pag_ant.Count())
|
||||
{
|
||||
data_fut = pag_ant.ElementAt(i + 1).Element("{http://xmlns.energia.org.br/BO/v2}data").Value;
|
||||
}
|
||||
|
||||
var data_atual = node.SelectSingleNode("bov2:data", nsmgr).InnerText;
|
||||
var data_ant = "a";
|
||||
if (i != 0)
|
||||
{
|
||||
data_ant = node_ant.SelectSingleNode("bov2:data", nsmgr).InnerText;
|
||||
}
|
||||
|
||||
if (data_ant != data_atual && data_fut != data_atual)
|
||||
{
|
||||
aux_data = DateTime.ParseExact(node.SelectSingleNode("bov2:data", nsmgr).InnerText, "yyyy-MM-dd'T'HH:mm:ss'-03:00'", null);
|
||||
data = (aux_data.ToOADate() - aux_data.ToOADate() % 1);
|
||||
min = aux_data.Hour * 60 + aux_data.Minute;
|
||||
|
||||
if (min == 0)
|
||||
{
|
||||
min = 1440;
|
||||
data = data - 1;
|
||||
}
|
||||
|
||||
ponto = node.SelectSingleNode("bov2:medidor//bov2:codigo", nsmgr).InnerText;
|
||||
origem = node.SelectSingleNode("bov2:coletaMedicao//bov2:tipo//bov2:nome", nsmgr).InnerText;
|
||||
|
||||
Double.TryParse(node.SelectSingleNode("bov2:energiaAtiva//bov2:consumo//bov2:valor", nsmgr).InnerText, out ativa_c);
|
||||
Double.TryParse(node.SelectSingleNode("bov2:energiaAtiva//bov2:geracao//bov2:valor", nsmgr).InnerText, out ativa_g);
|
||||
Double.TryParse(node.SelectSingleNode("bov2:energiaReativa//bov2:consumo//bov2:valor", nsmgr).InnerText, out reat_c);
|
||||
Double.TryParse(node.SelectSingleNode("bov2:energiaReativa//bov2:geracao//bov2:valor", nsmgr).InnerText, out reat_g);
|
||||
|
||||
|
||||
access_strCOM = "INSERT INTO Med_5min (Origem, Data, Minuto, Ativa_consumo, Ativa_geracao, Reativa_consumo, Reativa_geracao, Ponto)";
|
||||
access_strCOM += " VALUES (\"" + origem + "\"," + data + "," + min + "," + ativa_c + "," + ativa_g + "," + reat_c + "," + reat_g + ",\"" + ponto + "\")";
|
||||
|
||||
pg_writer.StartRow();
|
||||
pg_writer.Write(origem);
|
||||
pg_writer.Write(data, NpgsqlTypes.NpgsqlDbType.Numeric);
|
||||
pg_writer.Write(min, NpgsqlTypes.NpgsqlDbType.Integer);
|
||||
pg_writer.Write(ativa_c, NpgsqlTypes.NpgsqlDbType.Numeric);
|
||||
pg_writer.Write(ativa_g, NpgsqlTypes.NpgsqlDbType.Numeric);
|
||||
pg_writer.Write(reat_c, NpgsqlTypes.NpgsqlDbType.Numeric);
|
||||
pg_writer.Write(reat_g, NpgsqlTypes.NpgsqlDbType.Numeric);
|
||||
pg_writer.Write(ponto);
|
||||
//PGSQL END
|
||||
}
|
||||
node_ant = node;
|
||||
}
|
||||
}
|
||||
pg_writer.Complete();
|
||||
alterados.Add(m);
|
||||
}
|
||||
}
|
||||
return num_pag;
|
||||
}
|
||||
catch (Exception ex)
|
||||
|
||||
if (novos.Any())
|
||||
{
|
||||
Console.WriteLine(ex.Message);
|
||||
log_erros += origem + ";" + ponto + ";Erro;" + ex.Message.Replace("\n", "-n-") + "\n";
|
||||
string caminho_log_sec = @"\\srv-dados\documentos\Back\Carteira x.x\Codigo\Erros\log_sec_erros_" + DateTime.Now.Month + "_" + DateTime.Now.Day + "_" + DateTime.Now.Hour + "_" + DateTime.Now.Second + "_" + DateTime.Now.Millisecond + "_sec.csv";
|
||||
File.WriteAllText(caminho_log_sec, log_erros);
|
||||
return 1;
|
||||
await using (var connection = await dataSource.OpenConnectionAsync(ct))
|
||||
{
|
||||
using var writer = connection.BeginBinaryImport("COPY med_5min (origem, dia_num, minuto, ativa_consumo, ativa_geracao, reativa_consumo, reativa_geracao, ponto) FROM STDIN (FORMAT BINARY)");
|
||||
|
||||
foreach (var m in novos)
|
||||
{
|
||||
writer.StartRow();
|
||||
writer.Write(m.Origem);
|
||||
writer.Write(m.DiaNum, NpgsqlTypes.NpgsqlDbType.Numeric);
|
||||
writer.Write(m.Minuto, NpgsqlTypes.NpgsqlDbType.Integer);
|
||||
writer.Write(m.AtivaC, NpgsqlTypes.NpgsqlDbType.Numeric);
|
||||
writer.Write(m.AtivaG, NpgsqlTypes.NpgsqlDbType.Numeric);
|
||||
writer.Write(m.ReatC, NpgsqlTypes.NpgsqlDbType.Numeric);
|
||||
writer.Write(m.ReatG, NpgsqlTypes.NpgsqlDbType.Numeric);
|
||||
writer.Write(m.Ponto);
|
||||
}
|
||||
|
||||
await writer.CompleteAsync();
|
||||
}
|
||||
Console.WriteLine($"Inserido {novos.Count} registros. Ponto {ponto}. Dia {dia}");
|
||||
}
|
||||
|
||||
if (alterados.Any())
|
||||
{
|
||||
await using (var connection = await dataSource.OpenConnectionAsync(ct))
|
||||
{
|
||||
using (var batch = new NpgsqlBatch(connection))
|
||||
{
|
||||
foreach (var m in alterados)
|
||||
{
|
||||
var cmd = new NpgsqlBatchCommand(@"
|
||||
UPDATE med_5min
|
||||
SET origem = @origem,
|
||||
ativa_consumo = @ativa_consumo,
|
||||
ativa_geracao = @ativa_geracao,
|
||||
reativa_consumo = @reativa_consumo,
|
||||
reativa_geracao = @reativa_geracao
|
||||
WHERE ponto = @ponto
|
||||
AND dia_num = @dia_num
|
||||
AND minuto = @minuto;");
|
||||
|
||||
// Adiciona os parâmetros de forma segura
|
||||
cmd.Parameters.AddWithValue("origem", m.Origem);
|
||||
cmd.Parameters.AddWithValue("ativa_consumo", m.AtivaC);
|
||||
cmd.Parameters.AddWithValue("ativa_geracao", m.AtivaG);
|
||||
cmd.Parameters.AddWithValue("reativa_consumo", m.ReatC);
|
||||
cmd.Parameters.AddWithValue("reativa_geracao", m.ReatG);
|
||||
cmd.Parameters.AddWithValue("ponto", m.Ponto);
|
||||
cmd.Parameters.AddWithValue("dia_num", m.DiaNum);
|
||||
cmd.Parameters.AddWithValue("minuto", m.Minuto);
|
||||
|
||||
batch.BatchCommands.Add(cmd);
|
||||
}
|
||||
|
||||
// Executa o lote de comandos de uma vez
|
||||
await batch.ExecuteNonQueryAsync();
|
||||
Console.WriteLine($"Atualizado {alterados.Count} registros. Ponto {ponto}. Dia {dia}");
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
public class SoapFaultException : Exception
|
||||
{
|
||||
public string FaultCode { get; }
|
||||
public string FaultString { get; }
|
||||
public string ErrorCode { get; }
|
||||
public string ErrorMessage { get; }
|
||||
|
||||
public SoapFaultException(string faultCode, string faultString, string errorCode, string errorMessage)
|
||||
: base($"{faultString} (Code: {errorCode})")
|
||||
{
|
||||
FaultCode = faultCode;
|
||||
FaultString = faultString;
|
||||
ErrorCode = errorCode;
|
||||
ErrorMessage = errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
public static void VerificarRespostaSOAP(string responseXml)
|
||||
{
|
||||
var doc = XDocument.Parse(responseXml);
|
||||
XNamespace env = "http://schemas.xmlsoap.org/soap/envelope/";
|
||||
XNamespace tns = "http://xmlns.energia.org.br/FM/v2";
|
||||
|
||||
var fault = doc.Descendants(env + "Fault").FirstOrDefault();
|
||||
if (fault != null)
|
||||
{
|
||||
string faultCode = fault.Element("faultcode")?.Value ?? "";
|
||||
string faultString = fault.Element("faultstring")?.Value ?? "";
|
||||
|
||||
var detail = fault.Element("detail")?.Descendants().First();
|
||||
string errorCode = detail?.Element(tns + "errorCode")?.Value ?? "";
|
||||
string message = detail?.Element(tns + "message")?.Value ?? "";
|
||||
|
||||
throw new SoapFaultException(faultCode, faultString, errorCode, message);
|
||||
}
|
||||
}
|
||||
|
||||
public class RateLimiter
|
||||
{
|
||||
private readonly int _maxRequests;
|
||||
private readonly TimeSpan _interval;
|
||||
private int _requestCount;
|
||||
private DateTime _windowStart;
|
||||
private readonly object _lock = new();
|
||||
|
||||
public RateLimiter(int maxRequests, TimeSpan interval)
|
||||
{
|
||||
_maxRequests = maxRequests;
|
||||
_interval = interval;
|
||||
var now = DateTime.Now;
|
||||
_windowStart = new DateTime(now.Year, now.Month, now.Day, now.Hour, now.Minute - (now.Minute % interval.Minutes), 0);
|
||||
_requestCount = 0;
|
||||
}
|
||||
|
||||
public async Task WaitAsync(CancellationToken ct)
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if ((DateTime.Now - _windowStart) > _interval)
|
||||
{
|
||||
// reset janela
|
||||
_windowStart = DateTime.Now;
|
||||
_requestCount = 0;
|
||||
}
|
||||
|
||||
if (_requestCount < _maxRequests)
|
||||
{
|
||||
_requestCount++;
|
||||
return; // pode prosseguir
|
||||
}
|
||||
}
|
||||
|
||||
// já bateu o limite → espera até reset
|
||||
await Task.Delay(200, ct); // aguarda 200ms e tenta de novo
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class perfil
|
||||
{
|
||||
public string _Cod_5min { get; set; }
|
||||
public string _Codigo_SCDE { get; set; }
|
||||
public DateTime _Data_de_Migracao { get; set; }
|
||||
|
||||
public perfil(string cod_5min, string codigo_scde, DateTime data_de_migracao)
|
||||
{
|
||||
_Cod_5min = cod_5min;
|
||||
_Codigo_SCDE = codigo_scde;
|
||||
_Data_de_Migracao = data_de_migracao;
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user