AppType=StandardJava Build1=Default,b4j.JRDCMulti File1=config.DB2.properties File10=stop.bat File2=config.DB3.properties File3=config.DB4.properties File4=config.properties File5=login.html File6=reiniciaProcesoBow.bat File7=reiniciaProcesoPM2.bat File8=start.bat File9=start2.bat FileGroup1=Default Group FileGroup10=Default Group FileGroup2=Default Group FileGroup3=Default Group FileGroup4=Default Group FileGroup5=Default Group FileGroup6=Default Group FileGroup7=Default Group FileGroup8=Default Group FileGroup9=Default Group Group=Default Group Library1=byteconverter Library2=javaobject Library3=jcore Library4=jrandomaccessfile Library5=jserver Library6=jshell Library7=json Library8=jsql Library9=bcrypt Module1=Cambios Module10=Manager Module11=ping Module12=RDCConnector Module13=TestHandler Module2=ChangePassHandler Module3=DBHandlerB4X Module4=DBHandlerJSON Module5=DoLoginHandler Module6=faviconHandler Module7=GlobalParameters Module8=LoginHandler Module9=LogoutHandler NumberOfFiles=10 NumberOfLibraries=9 NumberOfModules=13 Version=10.3 @EndOfDesignText@ 'Non-UI application (console / server application) #Region Project Attributes #CommandLineArgs: #MergeLibraries: True ' VERSION 5.09.014 '########################################################################################################### '###################### PULL ############################################################# 'Ctrl + click ide://run?file=%WINDIR%\System32\cmd.exe&Args=/c&Args=git&Args=pull '########################################################################################################### '###################### PUSH ############################################################# 'Ctrl + click ide://run?file=%WINDIR%\System32\WindowsPowerShell\v1.0\powershell.exe&Args=github&Args=..\..\ '########################################################################################################### '###################### PUSH TORTOISE GIT ######################################################### 'Ctrl + click ide://run?file=%WINDIR%\System32\WindowsPowerShell\v1.0\powershell.exe&Args=TortoiseGitProc&Args=/command:commit&Args=/path:"../"&Args=/closeonend:2 '########################################################################################################### #End Region '- VERSION 5.09.08 '- Se agregó que se puedan configurar en el config.properties los siguientes parametros: ' ' - setInitialPoolSize = 3 ' - setMinPoolSize = 2 ' - setMaxPoolSize = 5 ' '- Se agregaron en duro a RDConnector los siguientes parametros: ' ' - setMaxIdleTime <-- Tiempo máximo de inactividad de la conexión. ' - setMaxConnectionAge <-- Tiempo de vida máximo de una conexión. ' - setCheckoutTimeout <-- Tiempo máximo de espera por una conexión. 'change based on the jdbc jar file '#AdditionalJar: mysql-connector-java-5.1.27-bin '#AdditionalJar: postgresql-42.7.0 #AdditionalJar: ojdbc11 ' Librería para manejar la base de datos SQLite #AdditionalJar: sqlite-jdbc-3.7.2 Sub Process_Globals ' --- Variables globales accesibles desde cualquier parte del proyecto --- Public srvr As Server ' El objeto principal del servidor HTTP de B4J. Public const VERSION As Float = 2.23 ' La versión actual de este servidor jRDC modificado. ' Tipos personalizados para la serialización y deserialización de datos ' entre el cliente B4X (DBRequestManager) y el servidor jRDC2. Type DBCommand (Name As String, Parameters() As Object) ' Define un comando SQL. Type DBResult (Tag As Object, Columns As Map, Rows As List) ' Define la estructura de un resultado de consulta. Public listaDeCP As List ' Contiene una lista de los identificadores de bases de datos configuradas (ej. "DB1", "DB2"). Private cpFiles As List ' Una lista temporal para almacenar los nombres de archivos encontrados en el directorio. ' Mapas globales para gestionar los conectores de base de datos y los comandos SQL. Public Connectors, commandsMap As Map ' Connectors: Almacena las instancias de RDCConnector por DB. ' commandsMap: Almacena los comandos SQL cargados para cada DB. Public SQL1 As SQL ' Objeto SQL para interactuar con la base de datos de usuarios (SQLite). Private bc As BCrypt ' Objeto para realizar operaciones de hashing de contraseñas de forma segura (para autenticación). Public MainConnectorsLock As JavaObject ' Objeto de bloqueo para proteger Main.Connectors End Sub Sub AppStart (Args() As String) ' --- Subrutina principal que se ejecuta al iniciar la aplicación --- ' 1. Inicializa la base de datos local de usuarios (SQLite). ' Esta base de datos se crea automáticamente si no existe y contiene los usuarios para el panel de administración. InitializeSQLiteDatabase ' 2. Inicializa los mapas globales definidos en GlobalParameters.bas. ' Estos mapas se usan para monitorear el servidor y gestionar configuraciones dinámicas. GlobalParameters.mpLogs.Initialize ' Mapa para almacenar logs de actividad. GlobalParameters.mpTotalRequests.Initialize ' Mapa para contar peticiones por endpoint/DB. GlobalParameters.mpTotalConnections.Initialize ' Mapa para almacenar el estado de los pools de conexión por DB. GlobalParameters.mpBlockConnection.Initialize ' Mapa para gestionar IPs bloqueadas (si la funcionalidad está activa). ' 3. Inicializa las estructuras principales del servidor HTTP. listaDeCP.Initialize ' Inicializa la lista que contendrá los IDs de las bases de datos. srvr.Initialize("") ' Inicializa el objeto servidor HTTP. Connectors = srvr.CreateThreadSafeMap ' Crea un mapa seguro para almacenar instancias de RDCConnector (un conector por DB). commandsMap.Initialize ' Inicializa el mapa que almacenará los comandos SQL cargados de los archivos de configuración. ' <<<< NUEVA INICIALIZACIÓN: Creamos una instancia de ReentrantLock para proteger Main.Connectors >>>> MainConnectorsLock.InitializeNewInstance("java.util.concurrent.locks.ReentrantLock", Null) ' <<<< HASTA AQUÍ LA NUEVA INICIALIZACIÓN >>>> ' === 4. INICIALIZACIÓN DEL CONECTOR PARA LA BASE DE DATOS PRINCIPAL (DB1) === ' DB1 siempre usa el archivo 'config.properties' por defecto. Dim con1 As RDCConnector ' Declara una variable específica y única para el conector de DB1. con1.Initialize("DB1") ' Inicializa la instancia del conector para "DB1". Connectors.Put("DB1", con1) ' Asocia el identificador "DB1" con su instancia de RDCConnector. srvr.Port = con1.serverPort ' El puerto del servidor HTTP se obtiene del config.properties de DB1. listaDeCP.Add("DB1") ' Añade "DB1" a la lista de bases de datos gestionadas.] Log($"Main.AppStart: Conector 'DB1' inicializado exitosamente en puerto: ${srvr.Port}"$) ' === 5. DETECCIÓN E INICIALIZACIÓN DE BASES DE DATOS ADICIONALES (DB2, DB3, DB4) === ' El servidor busca archivos de configuración adicionales (ej. config.DB2.properties) ' en el mismo directorio donde se ejecuta el JAR. cpFiles = File.ListFiles("./") If cpFiles.Size > 0 Then For i = 0 To cpFiles.Size - 1 ' Procesa 'config.DB2.properties' If cpFiles.Get(i) = "config.DB2.properties" Then Dim con2 As RDCConnector ' Declara una variable específica y única para el conector de DB2. con2.Initialize("DB2") ' Inicializa la instancia del conector para "DB2". Connectors.Put("DB2", con2) ' Asocia "DB2" con su instancia de RDCConnector. listaDeCP.Add("DB2") ' Añade "DB2" a la lista de bases de datos. Log("Main.AppStart: Conector 'DB2' inicializado exitosamente.") End If ' Procesa 'config.DB3.properties' If cpFiles.Get(i) = "config.DB3.properties" Then Dim con3 As RDCConnector ' Declara una variable específica y única para el conector de DB3. con3.Initialize("DB3") ' Inicializa la instancia del conector para "DB3". Connectors.Put("DB3", con3) ' Asocia "DB3" con su instancia de RDCConnector. listaDeCP.Add("DB3") ' Añade "DB3" a la lista de bases de datos. Log("Main.AppStart: Conector 'DB3' inicializado exitosamente.") End If ' Procesa 'config.DB4.properties' If cpFiles.Get(i) = "config.DB4.properties" Then Dim con4 As RDCConnector ' Declara una variable específica y única para el conector de DB4. con4.Initialize("DB4") ' Inicializa la instancia del conector para "DB4". Connectors.Put("DB4", con4) ' Asocia "DB4" con su instancia de RDCConnector. listaDeCP.Add("DB4") ' Añade "DB4" a la lista de bases de datos. Log("Main.AppStart: Conector 'DB4' inicializado exitosamente.") End If Next Else Log("Main.AppStart: No se encontraron archivos de configuración adicionales (config.DBx.properties).") End If ' Log final de las bases de datos que el servidor está gestionando. Dim sbListaDeCP_Log As StringBuilder sbListaDeCP_Log.Initialize For Each item As String In listaDeCP sbListaDeCP_Log.Append(item).Append(", ") Next If sbListaDeCP_Log.Length > 0 Then sbListaDeCP_Log.Remove(sbListaDeCP_Log.Length - 2, sbListaDeCP_Log.Length) ' Elimina la última ", " End If Log($"Main.AppStart: Bases de datos configuradas y listas: [${sbListaDeCP_Log.ToString}]"$) ' === 6. REGISTRO DE HANDLERS HTTP PARA EL SERVIDOR === ' Asocia rutas URL específicas con clases que manejarán las peticiones correspondientes. ' El último parámetro (True) indica que el handler se ejecutará en un nuevo hilo, ' lo que es recomendable para la mayoría de los casos para evitar bloqueos. srvr.AddHandler("/ping", "ping", True) ' Endpoint simple para verificar si el servidor está activo. srvr.AddHandler("/test", "TestHandler", True) ' Endpoint para pruebas de conexión y estado del servidor. srvr.AddHandler("/login", "LoginHandler", True) ' Muestra la página HTML de login. srvr.AddHandler("/dologin", "DoLoginHandler", True) ' Procesa el intento de inicio de sesión. srvr.AddHandler("/logout", "LogoutHandler", True) ' Cierra la sesión del usuario. srvr.AddHandler("/changepass", "ChangePassHandler", True) ' Permite a los usuarios cambiar su contraseña. srvr.AddHandler("/manager", "Manager", True) ' Panel de administración del servidor (requiere autenticación). srvr.AddHandler("/DBJ", "DBHandlerJSON", True) ' Handler para clientes web (ej. JavaScript, Node.js) que usan JSON. srvr.AddHandler("/dbrquery", "DBHandlerJSON", True) ' Un alias para el handler JSON, por si se usa en clientes específicos. srvr.AddHandler("/favicon.ico", "faviconHandler", True) ' Sirve el icono de la página (favicon). srvr.AddHandler("/*", "DBHandlerB4X", True) ' Handler por defecto para clientes B4X (DBRequestManager), ' procesa peticiones dinámicamente según la URL. ' 7. Inicia el servidor HTTP. srvr.Start Log("===========================================================") Log($"-=== jRDC está funcionando en el puerto: ${srvr.Port} (versión = $1.2{VERSION}) ===-"$) Log("===========================================================") ' 8. Inicia el bucle de mensajes de B4J. Es esencial para que la aplicación ' de servidor continúe ejecutándose y procesando eventos. StartMessageLoop End Sub ' --- Subrutina para inicializar la base de datos de usuarios local (SQLite) --- ' Esta base de datos se utiliza para almacenar credenciales de usuarios que pueden ' acceder al panel de administración del servidor jRDC. Sub InitializeSQLiteDatabase Dim dbFileName As String = "users.db" ' Nombre del archivo de la base de datos SQLite. ' Verifica si el archivo de la base de datos ya existe en el directorio de la aplicación. If File.Exists(File.DirApp, dbFileName) = False Then Log("Creando nueva base de datos de usuarios: " & dbFileName) ' Inicializa la conexión a la base de datos SQLite, creándola si no existe (último parámetro en True). SQL1.InitializeSQLite(File.DirApp, dbFileName, True) ' Define y ejecuta la sentencia SQL para crear la tabla 'users'. Dim createUserTable As String = "CREATE TABLE users (username TEXT PRIMARY KEY, password_hash TEXT NOT NULL)" SQL1.ExecNonQuery(createUserTable) ' Crea un usuario por defecto para facilitar el primer acceso al panel de administración. Dim defaultUser As String = "admin" Dim defaultPass As String = "12345" ' Genera un hash seguro de la contraseña usando BCrypt, lo cual es crucial para la seguridad. Dim hashedPass As String = bc.hashpw(defaultPass, bc.gensalt) ' Inserta el usuario por defecto en la tabla 'users'. SQL1.ExecNonQuery2("INSERT INTO users (username, password_hash) VALUES (?, ?)", Array As Object(defaultUser, hashedPass)) Log($"Usuario por defecto creado -> user: ${defaultUser}, pass: ${defaultPass}"$) Else ' Si el archivo de la base de datos ya existe, simplemente se abre. SQL1.InitializeSQLite(File.DirApp, dbFileName, True) Log("Base de datos de usuarios cargada.") End If End Sub