Эх сурвалжийг харах

add support of DenyModelNames

Robert 1 жил өмнө
parent
commit
a1728f37a9

+ 69 - 0
EVCB_OCPP.WSServer/Helper/QueueHandler.cs

@@ -0,0 +1,69 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using static System.Runtime.InteropServices.JavaScript.JSType;
+
+namespace EVCB_OCPP.WSServer.Helper;
+
+public class QueueHandler<T>
+{
+    public QueueHandler(Func<T,Task> handler = null,int maxConcurrency = 1)
+    {
+        _queue = new ();
+        this._handler = handler;
+        this._semaphore = new (maxConcurrency);
+        this._handlerPair = new();
+    }
+
+    public void Enqueue(T data)
+    {
+        _queue.Enqueue(data);
+        _ = TrtStartHandler();
+    }
+    public void Enqueue(T data, Func<T, Task> handler)
+    {
+        _queue.Enqueue(data);
+        _handlerPair.Add(data, handler);
+        _ = TrtStartHandler();
+    }
+
+    private readonly ConcurrentQueue<T> _queue;
+    private readonly Func<T, Task> _handler;
+    private readonly SemaphoreSlim _semaphore;
+    private readonly Dictionary<T, Func<T, Task>> _handlerPair;
+
+    private async Task TrtStartHandler()
+    {
+        if(_semaphore.Wait(0))
+        {
+            return;
+        }
+        if(!_queue.TryDequeue(out var data))
+        {
+            return;
+        }
+        var handler = GetHandler(data);
+        await handler(data);
+        _semaphore.Release();
+        _ = TrtStartHandler();
+    }
+
+    private Func<T, Task> GetHandler(T data)
+    {
+        if (_handlerPair.TryGetValue(data, out Func<T, Task> value))
+        {
+            return value;
+        }
+
+        if (_handler is not null)
+        {
+            return _handler;
+        }
+
+        return (data) => Task.CompletedTask;
+    }
+}

+ 73 - 0
EVCB_OCPP.WSServer/Helper/QueueSemaphore.cs

@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Helper;
+
+public class QueueSemaphore
+{
+    public QueueSemaphore(int maxLimit)
+    {
+        this._queue = new();
+        this._semaphore = new(maxLimit);
+    }
+
+    private readonly ConcurrentQueue<SemaphoreSlim> _queue;
+    private readonly SemaphoreSlim _semaphore;
+
+    public async Task<QueueSemaphoreToken> GetToken()
+    {
+        //if (_semaphore.Wait(0))
+        //{
+        //    return CreateToken();
+        //}
+
+        SemaphoreSlim _selfSemaphore = new(0);
+        _queue.Enqueue(_selfSemaphore);
+        TryDequeue();
+        await _selfSemaphore.WaitAsync();
+        return CreateToken();
+    }
+
+    private QueueSemaphoreToken CreateToken()
+    {
+        QueueSemaphoreToken token = new ();
+        token.OnDisposed += Token_OnDisposed;
+        return token;
+    }
+
+    private void Token_OnDisposed(object sender, EventArgs e)
+    {
+        var token = sender as QueueSemaphoreToken;
+        token.OnDisposed -= Token_OnDisposed;
+        _semaphore.Release();
+        TryDequeue();
+    }
+
+    private bool TryDequeue()
+    {
+        if (!_semaphore.Wait(0))
+        {
+            return false;
+        }
+        if (_queue.TryDequeue(out var semaphore))
+        {
+            semaphore.Release();
+            return true;
+        }
+        return false;
+    }
+}
+
+public class QueueSemaphoreToken : IDisposable
+{
+    internal event EventHandler OnDisposed;
+    public void Dispose()
+    {
+        OnDisposed?.Invoke(this, EventArgs.Empty);
+    }
+}

+ 55 - 85
EVCB_OCPP.WSServer/HostedProtalServer.cs

@@ -1,6 +1,8 @@
 using EVCB_OCPP.WSServer.Jobs;
+using EVCB_OCPP.WSServer.Message;
+using EVCB_OCPP.WSServer.Service;
+using EVCB_OCPP.WSServer.SuperSocket;
 using Microsoft.Extensions.DependencyInjection;
-using OCPPServer.Protocol;
 using Quartz;
 using System;
 using System.Collections.Generic;
@@ -14,10 +16,19 @@ namespace EVCB_OCPP.WSServer
     {
         public static void AddProtalServer(this IServiceCollection services)
         {
+            services.AddBusinessServiceFactory();
+
             services.AddTransient<OCPPWSServer>();
             services.AddTransient<IOCPPWSServerFactory, OCPPWSServerFactory>();
+
+            services.AddSingleton<WebDbService>();
+            services.AddSingleton<IMainDbService, MainDbService>();
+            services.AddSingleton<IConnectionLogdbService, ConnectionLogdbService>();
+
+            services.AddTransient<ProfileHandler>();
             services.AddSingleton<ProtalServer>();
             services.AddHostedService<ProtalServer>(p => p.GetRequiredService<ProtalServer>());
+
             services.AddProtalServerJob();
         }
 
@@ -26,118 +37,77 @@ namespace EVCB_OCPP.WSServer
             services.AddQuartz(q => {
                 q.UseMicrosoftDependencyInjectionJobFactory();
 
-                var ServerUpdateJobKey = new JobKey("job1", "group1");
-                q.AddJob<ServerUpdateJob>(opts => { opts.WithIdentity(ServerUpdateJobKey); });
-
-                q.AddTrigger(opts =>
-                {
-                    opts
-                    .ForJob(ServerUpdateJobKey)
-                    .WithIdentity("trigger1", "group1")
+                q.ScheduleJob<ServerUpdateJob>(trigger =>
+                    trigger
+                    .WithIdentity("ServerUpdateJobTrigger")
                     .StartNow()
                     .WithSimpleSchedule(x => x
                         .WithIntervalInMinutes(3)
-                        .RepeatForever());
-                });
-
-                var ServerSetFeeJobKey = new JobKey("job2", "group1");
-                q.AddJob<ServerSetFeeJob>(opts => { opts.WithIdentity(ServerSetFeeJobKey); });
+                        .RepeatForever())
+                );
 
-                q.AddTrigger(opts =>
-                {
-                    opts
-                    .ForJob(ServerSetFeeJobKey)
-                    .WithIdentity("trigger2", "group1")
+                q.ScheduleJob<ServerSetFeeJob>(trigger =>
+                    trigger
+                    .WithIdentity("ServerSetFeeJobTrigger")
                     .StartNow()
                     .WithSimpleSchedule(x => x
                         .WithIntervalInMinutes(1)
-                        .RepeatForever());
-                });
+                        .RepeatForever())
+                );
 
-                var ServerMessageJobKey = new JobKey("job3", "group1");
-                q.AddJob<ServerMessageJob>(opts => { opts.WithIdentity(ServerMessageJobKey); });
-
-                q.AddTrigger(opts =>
-                {
-                    opts
-                    .ForJob(ServerMessageJobKey)
-                    .WithIdentity("trigger3", "group1")
+                q.ScheduleJob<ServerMessageJob>(trigger =>
+                    trigger
+                    .WithIdentity("ServerMessageJobTrigger")
                     .StartNow()
                     .WithSimpleSchedule(x => x
                         .WithInterval(TimeSpan.FromMilliseconds(500))
-                        .RepeatForever());
-                });
-
-                var HeartBeatCheckJobbKey = new JobKey("job4", "group1");
-                q.AddJob<HeartBeatCheckJob>(opts => { opts.WithIdentity(HeartBeatCheckJobbKey); });
+                        .RepeatForever())
+                );
 
-                q.AddTrigger(opts =>
-                {
-                    opts
-                    .ForJob(HeartBeatCheckJobbKey)
-                    .WithIdentity("trigger4", "group1")
+                q.ScheduleJob<HeartBeatCheckJob>(trigger => 
+                    trigger
+                    .WithIdentity("HeartBeatCheckJobTrigger")
                     .StartNow()
                     .WithSimpleSchedule(x => x
                         .WithIntervalInSeconds(30)
-                        .RepeatForever());
-                });
+                        .RepeatForever())
+                );
 
-                var ServerWeatherNotificationJobKey = new JobKey("job5", "group1");
-                q.AddJob<ServerWeatherNotificationJob>(opts => { opts.WithIdentity(ServerWeatherNotificationJobKey); });
-
-                q.AddTrigger(opts =>
-                {
-                    opts
-                    .ForJob(ServerWeatherNotificationJobKey)
-                    .WithIdentity("trigger5", "group1")
+                q.ScheduleJob<ServerWeatherNotificationJob>(trigger =>
+                    trigger
+                    .WithIdentity("ServerWeatherNotificationJobTrigger")
                     .StartNow()
                     .WithSimpleSchedule(x => x
                         .WithIntervalInMinutes(1)
-                        .RepeatForever());
-                });
-
-                var HealthCheckTriggerJobKey = new JobKey("job6", "group1");
-                q.AddJob<HealthCheckTriggerJob>(opts => { opts.WithIdentity(HealthCheckTriggerJobKey); });
+                        .RepeatForever())
+                );
 
-                q.AddTrigger(opts =>
-                {
-                    opts
-                    .ForJob(HealthCheckTriggerJobKey)
-                    .WithIdentity("trigger6", "group1")
+                q.ScheduleJob<HealthCheckTriggerJob>(trigger =>
+                    trigger
+                    .WithIdentity("HealthCheckTriggerJobTrigger")
                     .StartNow()
                     .WithSimpleSchedule(x => x
                         .WithIntervalInMinutes(1)
-                        .RepeatForever());
-                });
-
-
-                var SmartChargingJobKey = new JobKey("job7", "group1");
-                q.AddJob<SmartChargingJob>(opts => { opts.WithIdentity(SmartChargingJobKey); });
+                        .RepeatForever())
+                );
 
-                q.AddTrigger(opts =>
-                {
-                    opts
-                    .ForJob(SmartChargingJobKey)
-                    .WithIdentity("trigger7", "group1")
+                q.ScheduleJob<SmartChargingJob>(trigger =>
+                    trigger
+                    .WithIdentity("SmartChargingJobTrigger")
                     .StartNow()
                     .WithSimpleSchedule(x => x
                         .WithIntervalInMinutes(1)
-                        .RepeatForever());
-                });
+                        .RepeatForever())
+                );
 
-                //var DenyModelCheckJobKey = new JobKey("job8", "group1");
-                //q.AddJob<DenyModelCheckJob>(opts => { opts.WithIdentity(DenyModelCheckJobKey); });
-
-                //q.AddTrigger(opts =>
-                //{
-                //    opts
-                //    .ForJob(DenyModelCheckJobKey)
-                //    .WithIdentity("trigger8", "group1")
-                //    .StartNow()
-                //    .WithSimpleSchedule(x => x
-                //        .WithIntervalInMinutes(5)
-                //        .RepeatForever());
-                //});
+                q.ScheduleJob<DenyModelCheckJob>(trigger =>
+                    trigger
+                    .WithIdentity("DenyModelCheckJobTrigger")
+                    .StartNow()
+                    .WithSimpleSchedule(x => x
+                        .WithIntervalInMinutes(5)
+                        .RepeatForever())
+                );
             });
 
             services.AddQuartzHostedService(opt =>

+ 9 - 12
EVCB_OCPP.WSServer/Jobs/DenyModelCheckJob.cs

@@ -1,5 +1,6 @@
 using Dapper;
 using DnsClient.Internal;
+using EVCB_OCPP.WSServer.Service;
 using Microsoft.Data.SqlClient;
 using Microsoft.Extensions.Configuration;
 using Microsoft.Extensions.Logging;
@@ -19,16 +20,19 @@ public class DenyModelCheckJob : IJob
 {
     public DenyModelCheckJob(
         ProtalServer protalServer,
-        IConfiguration configuration,
+        WebDbService webDbService,
+        //IConfiguration configuration,
         ILogger<DenyModelCheckJob> logger)
     {
-        this.webConnectionString = configuration.GetConnectionString("WebDBContext");
+        //this.webConnectionString = configuration.GetConnectionString("WebDBContext");
         this.protalServer = protalServer;
+        this.webDbService = webDbService;
         this.logger = logger;
     }
 
-    private readonly string webConnectionString;
+    //private readonly string webConnectionString;
     private readonly ProtalServer protalServer;
+    private readonly WebDbService webDbService;
     private readonly ILogger<DenyModelCheckJob> logger;
 
     public async Task Execute(IJobExecutionContext context)
@@ -36,15 +40,8 @@ public class DenyModelCheckJob : IJob
         //logger.LogDebug("{0} Started", nameof(DenyModelCheckJob));
         try
         {
-            using (SqlConnection conn = new SqlConnection(webConnectionString))
-            {
-                string strSql = "SELECT [Value] FROM[StandardOCPP_Web].[dbo].[KernelConfig]" +
-                 "where SystemKey = 'DenyModelNames'; ";
-                var result = await conn.QueryFirstOrDefaultAsync<string>(strSql);
-
-                GlobalConfig.DenyModelNames = result.Split(',').ToList();
-                logger.LogDebug("Current DenyList:[{0}]", string.Join(",", GlobalConfig.DenyModelNames));
-            }
+            GlobalConfig.DenyModelNames = await webDbService.GetDenyModelNames();
+            logger.LogDebug("Current DenyList:[{0}]", string.Join(",", GlobalConfig.DenyModelNames));
 
             if (string.IsNullOrEmpty(GlobalConfig.DenyModelNames[0]))
             {

+ 9 - 27
EVCB_OCPP.WSServer/Program.cs

@@ -47,50 +47,32 @@ namespace EVCB_OCPP.WSServer
                 .UseNLog()
                 .ConfigureServices((hostContext, services) =>
                 {
+                    var commandTimeout = int.TryParse(hostContext.Configuration["CommandTimeout"], out var temp) ? temp : 180;
+                    var maxRetryCount = int.TryParse(hostContext.Configuration["MaxRetryCount"], out var temp2) ? temp2 : int.MaxValue;
+
                     services.AddPooledDbContextFactory<MainDBContext>((options) => {
                         var cString = hostContext.Configuration.GetConnectionString("MainDBContext");
-                        //var connection = new SqlConnection(cString);
-                        //connection.Open();
-                        //var com = new SqlCommand("SET ARITHABORT ON", connection);
-                        //com.ExecuteNonQuery();
-                        //com.Dispose();
-                        //connection.Close();
-                        //options.UseSqlServer(connection, dbOptions =>
-                        //{
-                        //    dbOptions.CommandTimeout(180);
-                        //});
-                        //options.LogTo(Console.WriteLine).EnableDetailedErrors();
                         options.UseSqlServer(cString, dbOptions =>
                         {
-                            dbOptions.EnableRetryOnFailure(int.MaxValue);
-                            dbOptions.CommandTimeout(int.MaxValue);
+                            dbOptions.EnableRetryOnFailure(maxRetryCount);
+                            dbOptions.CommandTimeout(commandTimeout);
                         });
                     });
                     services.AddPooledDbContextFactory<MeterValueDBContext>((options) => {
                         var cString = hostContext.Configuration.GetConnectionString("MeterValueDBContext");
                         options.UseSqlServer(cString, dbOptions => {
-                            dbOptions.EnableRetryOnFailure(int.MaxValue);
-                            dbOptions.CommandTimeout(int.MaxValue);
+                            dbOptions.EnableRetryOnFailure(maxRetryCount);
+                            dbOptions.CommandTimeout(commandTimeout);
                         });
                     });
                     services.AddPooledDbContextFactory<ConnectionLogDBContext>((options) => {
                         var cString = hostContext.Configuration.GetConnectionString("ConnectionLogDBContext");
                         options.UseSqlServer(cString, dbOptions => {
-                            dbOptions.EnableRetryOnFailure(int.MaxValue);
-                            dbOptions.CommandTimeout(int.MaxValue);
+                            dbOptions.EnableRetryOnFailure(maxRetryCount);
+                            dbOptions.CommandTimeout(commandTimeout);
                         });
                     });
 
-                    services.AddSingleton<ProfileHandler>();
-
-                    services.AddScoped<OuterBusinessService>();
-                    services.AddScoped<LocalBusinessService>();
-                    services.AddScoped<CPOOuterResponse>();
-                    services.AddSingleton<IBusinessServiceFactory, BusinessServiceFactory>();
-
-                    //services.AddHostedService<ProtalServer>();
-                    services.AddSingleton<IMainDbService, MainDbService>();
-
                     services.AddProtalServer();
                 })
                 .Build();

+ 21 - 40
EVCB_OCPP.WSServer/ProtalServer.cs

@@ -39,6 +39,7 @@ using NLog.Extensions.Logging;
 using Microsoft.Data.SqlClient;
 using System.Collections.ObjectModel;
 using System.Collections.Concurrent;
+using EVCB_OCPP.WSServer.SuperSocket;
 
 namespace EVCB_OCPP.WSServer
 {
@@ -63,21 +64,26 @@ namespace EVCB_OCPP.WSServer
 
         public ProtalServer(
             IConfiguration configuration
-            , IServiceProvider serviceProvider
             , IDbContextFactory<MainDBContext> maindbContextFactory
+            , IDbContextFactory<ConnectionLogDBContext> connectionLogdbContextFactory
             , IHostEnvironment environment
-            , IOCPPWSServerFactory ocppWSServerFactory)
+            , IOCPPWSServerFactory ocppWSServerFactory
+            , IConnectionLogdbService connectionLogdbService
+            , WebDbService webDbService
+            ,IServiceProvider serviceProvider)
         {
             _ct = _cts.Token;
 
             this.configuration = configuration;
-            this.serviceProvider = serviceProvider;
             this.maindbContextFactory = maindbContextFactory;
+            //this.connectionLogdbContextFactory = connectionLogdbContextFactory;
             this.ocppWSServerFactory = ocppWSServerFactory;
+            this.connectionLogdbService = connectionLogdbService;
+            this.webDbService = webDbService;
             isInDocker = !string.IsNullOrEmpty(configuration["DOTNET_RUNNING_IN_CONTAINER"]);
 
             webConnectionString = configuration.GetConnectionString("WebDBContext");
-            profileHandler = serviceProvider.GetService<ProfileHandler>();// new ProfileHandler(configuration, serviceProvider);
+            this.profileHandler = serviceProvider.GetService<ProfileHandler>();// new ProfileHandler(configuration, serviceProvider);
             _loadingBalanceService = new LoadingBalanceService(configuration);
 
             WarmUpLog();
@@ -89,9 +95,12 @@ namespace EVCB_OCPP.WSServer
         //private readonly Object _lockClientDic = new object();
         private readonly Object _lockConfirmPacketList = new object();
         private readonly IConfiguration configuration;
-        private readonly IServiceProvider serviceProvider;
+        //private readonly IServiceProvider serviceProvider;
         private readonly IDbContextFactory<MainDBContext> maindbContextFactory;
+        //private readonly IDbContextFactory<ConnectionLogDBContext> connectionLogdbContextFactory;
         private readonly IOCPPWSServerFactory ocppWSServerFactory;
+        private readonly IConnectionLogdbService connectionLogdbService;
+        private readonly WebDbService webDbService;
         private readonly ProfileHandler profileHandler;//= new ProfileHandler();
         private readonly string webConnectionString;// = ConfigurationManager.ConnectionStrings["WebDBContext"].ConnectionString;
         private readonly bool isInDocker;
@@ -168,10 +177,11 @@ namespace EVCB_OCPP.WSServer
         internal LoadingBalanceService LoadingBalanceService => _loadingBalanceService;
         internal ProfileHandler ProfileHandler => profileHandler;
 
-        public Task StartAsync(CancellationToken cancellationToken)
+        public async Task StartAsync(CancellationToken cancellationToken)
         {
+            GlobalConfig.DenyModelNames = await webDbService.GetDenyModelNames();
             Start();
-            return Task.CompletedTask;
+            return;
         }
 
         public Task StopAsync(CancellationToken cancellationToken)
@@ -1419,21 +1429,9 @@ namespace EVCB_OCPP.WSServer
             }
         }
 
-        private async void WarmUpLog()
+        private void WarmUpLog()
         {
-            try
-            {
-                using (var log = await serviceProvider.GetService<IDbContextFactory<ConnectionLogDBContext>>().CreateDbContextAsync())
-                {
-                    log.MachineConnectionLog.ToList();
-                }
-            }
-            catch (Exception ex)
-            {
-                Console.WriteLine(ex.ToString());
-            }
-
-
+            connectionLogdbService.WarmUpLog();
         }
 
         private async Task WriteMachineLog(ClientData clientData, string data, string messageType, string errorMsg = "", bool isSent = false)
@@ -1447,25 +1445,8 @@ namespace EVCB_OCPP.WSServer
                 {
                     logger.Fatal(clientData.Path + "]********************session ChargeBoxId null sessionId=" + clientData.SessionID);
                 }
-                using (var db = await serviceProvider.GetService<IDbContextFactory<ConnectionLogDBContext>>().CreateDbContextAsync())
-                {
-                    string sp = "[dbo].[uspInsertMachineConnectionLog] @CreatedOn," +
-                          "@ChargeBoxId,@MessageType,@Data,@Msg,@IsSent,@EVSEEndPoint,@Session";
-                    var dd = DateTime.UtcNow;
-                    SqlParameter[] parameter =
-                    {
-                           new SqlParameter("CreatedOn", SqlDbType.DateTime){ Value = dd },
-                           new SqlParameter("ChargeBoxId", SqlDbType.NVarChar, 50){ Value= clientData.ChargeBoxId==null?"unknown":clientData.ChargeBoxId.Replace("'","''") },
-                           new SqlParameter("MessageType", SqlDbType.NVarChar , 50){ Value =  messageType.Replace("'","''")},
-                           new SqlParameter("Data", SqlDbType.NVarChar, -1) { Value = data.Replace("'", "''") },
-                           new SqlParameter("Msg", SqlDbType.NVarChar, 200) { Value = errorMsg.Replace("'", "''") },
-                           new  SqlParameter("IsSent", SqlDbType.Bit) { Value = isSent },
-                           new  SqlParameter("EVSEEndPoint", SqlDbType.NVarChar, 25) { Value = clientData.RemoteEndPoint == null ? "123" : clientData.RemoteEndPoint.ToString() },
-                           new  SqlParameter("Session", SqlDbType.NVarChar, 36) { Value = clientData.SessionID == null ? "123" : clientData.SessionID }
-                    };
-
-                    await db.Database.ExecuteSqlRawAsync(sp, parameter);
-                }
+
+                connectionLogdbService.WriteMachineLog(clientData, data, messageType, errorMsg, isSent);
             }
             catch (Exception ex)
             {

+ 44 - 34
EVCB_OCPP.WSServer/Service/BusinessServiceFactory.cs

@@ -7,53 +7,63 @@ using System;
 using System.Linq;
 using System.Threading.Tasks;
 
-namespace EVCB_OCPP.WSServer.Service
+namespace EVCB_OCPP.WSServer.Service;
+
+
+public interface IBusinessService
 {
+    Task<IdTokenInfo> Authorize(string chargeBoxId, string idTag);
 
-    public interface IBusinessService
-    {
-        Task<IdTokenInfo> Authorize(string chargeBoxId, string idTag);
+    Task NotifyFaultStatus(ErrorDetails details);
 
-        Task NotifyFaultStatus(ErrorDetails details);
+    Task NotifyConnectorUnplugged(string chargeBoxId,string data);
 
-        Task NotifyConnectorUnplugged(string chargeBoxId,string data);
+}
 
+public static class BusinessServiceFactoryRegistration
+{
+    public static void AddBusinessServiceFactory(this IServiceCollection services)
+    {
+        services.AddScoped<OuterBusinessService>();
+        services.AddScoped<LocalBusinessService>();
+        services.AddSingleton<IBusinessServiceFactory, BusinessServiceFactory>();
     }
+}
 
-    public class BusinessServiceFactory : IBusinessServiceFactory
+public class BusinessServiceFactory : IBusinessServiceFactory
+{
+
+    public BusinessServiceFactory(
+        IServiceProvider serviceProvider,
+        IDbContextFactory<MainDBContext> mainDBContextFactory)
     {
-        public BusinessServiceFactory(
-            IServiceProvider serviceProvider,
-            IDbContextFactory<MainDBContext> mainDBContextFactory)
+        this.serviceProvider = serviceProvider;
+        this.mainDBContextFactory = mainDBContextFactory;
+    }
+
+    private readonly IServiceProvider serviceProvider;
+    private readonly IDbContextFactory<MainDBContext> mainDBContextFactory;
+
+    public async Task<IBusinessService> CreateBusinessService(string customerId)
+    {
+        bool isCallOut = false;
+        using (var db = this.mainDBContextFactory.CreateDbContext())
         {
-            this.serviceProvider = serviceProvider;
-            this.mainDBContextFactory = mainDBContextFactory;
+            isCallOut = await db.Customer.Where(x => x.Id == new Guid(customerId)).Select(x => x.CallPartnerApiOnSchedule).FirstOrDefaultAsync();
         }
 
-        private readonly IServiceProvider serviceProvider;
-        private readonly IDbContextFactory<MainDBContext> mainDBContextFactory;
-
-        public async Task<IBusinessService> CreateBusinessService(string customerId)
+        //return isCallOut ? new OuterBusinessService(customerId) : new LocalBusinessService(customerId);
+        if (isCallOut)
         {
-            bool isCallOut = false;
-            using (var db = this.mainDBContextFactory.CreateDbContext())
-            {
-                isCallOut = await db.Customer.Where(x => x.Id == new Guid(customerId)).Select(x => x.CallPartnerApiOnSchedule).FirstOrDefaultAsync();
-            }
-
-            //return isCallOut ? new OuterBusinessService(customerId) : new LocalBusinessService(customerId);
-            if (isCallOut)
-            {
-                OuterBusinessService outerBusinessService = serviceProvider.GetService<OuterBusinessService>();
-                outerBusinessService.CustomerId = customerId;
-                return outerBusinessService;
-            }
-            LocalBusinessService toReturn = serviceProvider.GetService<LocalBusinessService>();
-            toReturn.CustomerId = customerId;
-            return toReturn;
-
-            //return isCallOut ? new OuterBusinessService(customerId) : 
+            OuterBusinessService outerBusinessService = serviceProvider.GetService<OuterBusinessService>();
+            outerBusinessService.CustomerId = customerId;
+            return outerBusinessService;
         }
+        LocalBusinessService toReturn = serviceProvider.GetService<LocalBusinessService>();
+        toReturn.CustomerId = customerId;
+        return toReturn;
 
+        //return isCallOut ? new OuterBusinessService(customerId) : 
     }
+
 }

+ 112 - 0
EVCB_OCPP.WSServer/Service/ConnectionLogdbService.cs

@@ -0,0 +1,112 @@
+using EVCB_OCPP.Domain;
+using EVCB_OCPP.WSServer.Helper;
+using Microsoft.Data.SqlClient;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using OCPPServer.Protocol;
+using System;
+using System.Collections.Generic;
+using System.Data;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using static System.Runtime.InteropServices.JavaScript.JSType;
+
+namespace EVCB_OCPP.WSServer.Service;
+
+public interface IConnectionLogdbService
+{
+    void WarmUpLog();
+    void WriteMachineLog(ClientData clientData, string data, string messageType, string errorMsg = "", bool isSent = false);
+}
+
+public class ConnectionLogdbService : IConnectionLogdbService
+{
+    public const string LimitConfigKey = "ConnectionLogDbLimit";
+
+    public ConnectionLogdbService(
+        IDbContextFactory<ConnectionLogDBContext> connectionLogdbContextFactory,
+        ILogger<ConnectionLogdbService> logger,
+        IConfiguration configuration)
+    {
+        this.connectionLogdbContextFactory = connectionLogdbContextFactory;
+        this.logger = logger;
+        var opLimit = GetLimit(configuration);
+        this.queueHandler = new(WriteMachineLog, opLimit);
+    }
+
+    private readonly IDbContextFactory<ConnectionLogDBContext> connectionLogdbContextFactory;
+    private readonly ILogger<ConnectionLogdbService> logger;
+    private readonly QueueHandler<MachineLog> queueHandler;
+
+    public void WarmUpLog()
+    {
+        try
+        {
+            using (var log = connectionLogdbContextFactory.CreateDbContext())
+            {
+                log.MachineConnectionLog.ToList();
+            }
+        }
+        catch (Exception ex)
+        {
+            Console.WriteLine(ex.ToString());
+        }
+    }
+
+    public void WriteMachineLog(ClientData clientData, string data, string messageType, string errorMsg = "", bool isSent = false)
+    {
+        var log = new MachineLog(clientData, data, messageType, errorMsg, isSent);
+        queueHandler.Enqueue(log);
+    }
+
+    private async Task WriteMachineLog(MachineLog log)
+    {
+        try
+        {
+            if (log.clientData == null || string.IsNullOrEmpty(log.data)) return;
+
+            if (log.clientData.ChargeBoxId == null)
+            {
+                logger.LogCritical(log.clientData.Path + "]********************session ChargeBoxId null sessionId=" + log.clientData.SessionID);
+            }
+            using (var db = connectionLogdbContextFactory.CreateDbContext())
+            {
+                string sp = "[dbo].[uspInsertMachineConnectionLog] @CreatedOn," +
+                      "@ChargeBoxId,@MessageType,@Data,@Msg,@IsSent,@EVSEEndPoint,@Session";
+                var dd = DateTime.UtcNow;
+                SqlParameter[] parameter =
+                {
+                           new SqlParameter("CreatedOn", SqlDbType.DateTime){ Value = dd },
+                           new SqlParameter("ChargeBoxId", SqlDbType.NVarChar, 50){ Value= log.clientData.ChargeBoxId==null?"unknown":log.clientData.ChargeBoxId.Replace("'","''") },
+                           new SqlParameter("MessageType", SqlDbType.NVarChar , 50){ Value =  log.messageType.Replace("'","''")},
+                           new SqlParameter("Data", SqlDbType.NVarChar, -1) { Value = log.data.Replace("'", "''") },
+                           new SqlParameter("Msg", SqlDbType.NVarChar, 200) { Value = log.errorMsg.Replace("'", "''") },
+                           new  SqlParameter("IsSent", SqlDbType.Bit) { Value = log.isSent },
+                           new  SqlParameter("EVSEEndPoint", SqlDbType.NVarChar, 25) { Value = log.clientData.RemoteEndPoint == null ? "123" : log.clientData.RemoteEndPoint.ToString() },
+                           new  SqlParameter("Session", SqlDbType.NVarChar, 36) { Value = log.clientData.SessionID == null ? "123" : log.clientData.SessionID }
+                    };
+
+                await db.Database.ExecuteSqlRawAsync(sp, parameter);
+            }
+        }
+        catch (Exception ex)
+        {
+            Console.WriteLine(ex.ToString());
+        }
+    }
+
+    private int GetLimit(IConfiguration configuration)
+    {
+        var limitConfig = configuration[LimitConfigKey];
+        int limit = 10;
+        if (limitConfig != default)
+        {
+            int.TryParse(limitConfig, out limit);
+        }
+        return limit;
+    }
+}
+
+internal record MachineLog(ClientData clientData, string data, string messageType, string errorMsg, bool isSent);

+ 6 - 6
EVCB_OCPP.WSServer/Service/MainDbService.cs

@@ -34,19 +34,19 @@ public class MainDbService : IMainDbService
         this.contextFactory = contextFactory;
 
         var startupLimit = GetStartupLimit(configuration);
-        this.startupSemaphore = new SemaphoreSlim(startupLimit);
+        this.startupSemaphore = new (startupLimit);
 
         var opLimit = GetOpLimit(configuration);
         this.opSemaphore = new SemaphoreSlim(opLimit);
     }
 
     private readonly IDbContextFactory<MainDBContext> contextFactory;
-    private readonly SemaphoreSlim startupSemaphore;
+    private readonly QueueSemaphore startupSemaphore;
     private readonly SemaphoreSlim opSemaphore;
 
     public async Task<MachineAndCustomerInfo> GetMachineIdAndCustomerInfo(string ChargeBoxId)
     {
-        using var semaphoreWrapper = await SemaphoreWrapper.WaitAsync(startupSemaphore);
+        using var semaphoreWrapper = await startupSemaphore.GetToken();
         using var db = contextFactory.CreateDbContext();
         var machine = await db.Machine.Where(x => x.ChargeBoxId == ChargeBoxId && x.IsDelete == false).Select(x => new { x.CustomerId, x.Id }).AsNoTracking().FirstOrDefaultAsync();
         if (machine == null)
@@ -59,7 +59,7 @@ public class MainDbService : IMainDbService
 
     public async Task<string> GetMachineConfiguration(string ChargeBoxId, string configName)
     {
-        using var semaphoreWrapper = await SemaphoreWrapper.WaitAsync(startupSemaphore);
+        using var semaphoreWrapper = await startupSemaphore.GetToken();
         using var db = contextFactory.CreateDbContext();
         return await db.MachineConfigurations
             .Where(x => x.ChargeBoxId == ChargeBoxId && x.ConfigureName == configName)
@@ -83,7 +83,7 @@ public class MainDbService : IMainDbService
 
     public async Task UpdateMachineBasicInfo(string ChargeBoxId, Machine machine)
     {
-        using var semaphoreWrapper = await SemaphoreWrapper.WaitAsync(startupSemaphore);
+        using var semaphoreWrapper = await startupSemaphore.GetToken();
         using var db = contextFactory.CreateDbContext();
         var _machine = db.Machine.FirstOrDefault(x => x.ChargeBoxId == ChargeBoxId);
         _machine.ChargeBoxSerialNumber = machine.ChargeBoxSerialNumber;
@@ -118,7 +118,7 @@ public class MainDbService : IMainDbService
     {
         using var db = contextFactory.CreateDbContext();
 
-        ConnectorStatus status = new();
+        ConnectorStatus status = new() { Id = Id };
 
         db.ChangeTracker.AutoDetectChangesEnabled = false;
         db.ConnectorStatus.Attach(status);

+ 35 - 0
EVCB_OCPP.WSServer/Service/WebDbService.cs

@@ -0,0 +1,35 @@
+using Dapper;
+using Microsoft.Data.SqlClient;
+using Microsoft.Extensions.Configuration;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace EVCB_OCPP.WSServer.Service;
+
+public class WebDbService
+{
+    public WebDbService(IConfiguration configuration)
+    {
+        this.webConnectionString = configuration.GetConnectionString("WebDBContext");
+    }
+
+    private readonly string webConnectionString;
+
+    public async Task<List<string>> GetDenyModelNames()
+    {
+        using SqlConnection conn = new SqlConnection(webConnectionString) ;
+        string strSql = """
+                SELECT [Value] 
+                FROM [StandardOCPP_Web].[dbo].[KernelConfig]
+                where SystemKey = 'DenyModelNames';
+                """;
+
+        var result = await conn.QueryFirstOrDefaultAsync<string>(strSql);
+
+        return result.Split(',').ToList();
+
+    }
+}

+ 32 - 17
EVCB_OCPP.WSServer/SuperSocket.Protocol/OCPPWSServer.cs → EVCB_OCPP.WSServer/SuperSocket/OCPPWSServer.cs

@@ -1,25 +1,19 @@
-
-using EVCB_OCPP.Domain;
-using EVCB_OCPP.WSServer.Service;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Internal;
+using EVCB_OCPP.WSServer.Service;
 using Microsoft.Extensions.Configuration;
-using Microsoft.Extensions.DependencyInjection;
 using Microsoft.Extensions.Logging;
-using MongoDB.Driver.Core.Servers;
-using OCPPPackage.Profiles;
+using OCPPServer.Protocol;
+using SuperSocket.SocketBase;
 using SuperWebSocket;
 using SuperWebSocket.SubProtocol;
 using System;
 using System.Collections.Generic;
-using System.Configuration;
 using System.Linq;
 using System.Net;
 using System.Net.Security;
 using System.Security.Cryptography.X509Certificates;
 using System.Text;
 
-namespace OCPPServer.Protocol;
+namespace EVCB_OCPP.WSServer.SuperSocket;
 
 public class OCPPWSServer : WebSocketServer<ClientData>
 {
@@ -100,6 +94,27 @@ public class OCPPWSServer : WebSocketServer<ClientData>
         string[] words = session.Path.Split('/');
         session.ChargeBoxId = words.Last();
 
+        foreach (var denyModel in GlobalConfig.DenyModelNames)
+        {
+            if (string.IsNullOrEmpty(denyModel)) break;
+            if (session.ChargeBoxId.StartsWith(denyModel))
+            {
+
+                StringBuilder responseBuilder = new StringBuilder();
+
+                responseBuilder.AppendFormatWithCrCf(@"HTTP/{0} {1} {2}", "1.1",
+                (int)HttpStatusCode.Unauthorized, @"Unauthorized");
+
+                responseBuilder.AppendWithCrCf();
+                string sb = responseBuilder.ToString();
+                byte[] data = Encoding.UTF8.GetBytes(sb);
+
+                ((IWebSocketSession)session).SendRawData(data, 0, data.Length);
+                logger.LogTrace(sb);
+                return false;
+            }
+        }
+
         if (configuration["MaintainMode"] == "1")
         {
             session.ChargeBoxId = session.ChargeBoxId + "_2";
@@ -126,7 +141,7 @@ public class OCPPWSServer : WebSocketServer<ClientData>
 
             responseBuilder.AppendFormatWithCrCf(@"HTTP/{0} {1} {2}", "1.1",
             (int)HttpStatusCode.NotFound, @"Not Found");
-              
+
             responseBuilder.AppendWithCrCf();
             string sb = responseBuilder.ToString();
             byte[] data = Encoding.UTF8.GetBytes(sb);
@@ -146,7 +161,7 @@ public class OCPPWSServer : WebSocketServer<ClientData>
             // 1.6 server only support change server  function
             securityProfile = 0;
         }
-        
+
         if (securityProfile == 3 && session.UriScheme == "ws")
         {
             StringBuilder responseBuilder = new StringBuilder();
@@ -163,7 +178,7 @@ public class OCPPWSServer : WebSocketServer<ClientData>
             return false;
         }
 
-        if ((securityProfile == 1 || securityProfile == 2))
+        if (securityProfile == 1 || securityProfile == 2)
         {
             if (securityProfile == 2 && session.UriScheme == "ws")
             {
@@ -181,15 +196,15 @@ public class OCPPWSServer : WebSocketServer<ClientData>
                     // 1.6 server only support change server  function
                     securityProfile = 0;
                 }
-                
+
                 logger.LogInformation("***********Authorization   ");
 
                 if (!string.IsNullOrEmpty(authorizationKey))
                 {
                     string base64Encoded = session.Items.ContainsKey("Authorization") ? session.Items["Authorization"].ToString().Replace("Basic ", "") : session.Items["authorization"].ToString().Replace("Basic ", "");
                     byte[] data = Convert.FromBase64String(base64Encoded);
-                    string[] base64Decoded = System.Text.ASCIIEncoding.ASCII.GetString(data).Split(':');
-                    logger.LogInformation("***********Authorization   " + System.Text.ASCIIEncoding.ASCII.GetString(data));
+                    string[] base64Decoded = Encoding.ASCII.GetString(data).Split(':');
+                    logger.LogInformation("***********Authorization   " + Encoding.ASCII.GetString(data));
                     if (base64Decoded.Count() == 2 && base64Decoded[0] == session.ChargeBoxId && base64Decoded[1] == authorizationKey)
                     {
                         authorizated = true;
@@ -227,7 +242,7 @@ public class OCPPWSServer : WebSocketServer<ClientData>
         }
 
 
-     
+
 
 
 

+ 1 - 4
EVCB_OCPP.WSServer/SuperSocket.Protocol/OCPPWSServerFactory.cs → EVCB_OCPP.WSServer/SuperSocket/OCPPWSServerFactory.cs

@@ -6,11 +6,8 @@ using OCPPServer.Protocol;
 using SuperWebSocket.SubProtocol;
 using System;
 using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
 
-namespace OCPPServer.Protocol;
+namespace EVCB_OCPP.WSServer.SuperSocket;
 
 public interface IOCPPWSServerFactory
 {