config.kt (3292B)
1 /* 2 * This file is part of LibEuFin. 3 * Copyright (C) 2024 Taler Systems S.A. 4 * 5 * LibEuFin is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU Affero General Public License as 7 * published by the Free Software Foundation; either version 3, or 8 * (at your option) any later version. 9 * 10 * LibEuFin is distributed in the hope that it will be useful, but 11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General 13 * Public License for more details. 14 * 15 * You should have received a copy of the GNU Affero General Public 16 * License along with LibEuFin; see the file COPYING. If not, see 17 * <http://www.gnu.org/licenses/> 18 */ 19 20 package tech.libeufin.common.db 21 22 import io.ktor.http.* 23 import org.postgresql.ds.PGSimpleDataSource 24 import org.postgresql.jdbc.PgConnection 25 import java.net.URI 26 import java.nio.file.Path 27 28 fun currentUser(): String = System.getProperty("user.name") 29 30 /** 31 * This function converts postgresql:// URIs to JDBC URIs. 32 * 33 * URIs that are already jdbc: URIs are passed through. 34 * 35 * This avoids the user having to create complex JDBC URIs for postgres connections. 36 * They are especially complex when using unix domain sockets, as they're not really 37 * supported natively by JDBC. 38 */ 39 fun jdbcFromPg(pgConn: String): String { 40 // Pass through jdbc URIs. 41 if (pgConn.startsWith("jdbc:")) { 42 return pgConn 43 } 44 require(pgConn.startsWith("postgresql://") || pgConn.startsWith("postgres://")) { 45 "Not a Postgres connection string: $pgConn" 46 } 47 val uri = URI(pgConn) 48 val params = parseQueryString(uri.query ?: "", decode = false) 49 50 val host = uri.host ?: params["host"] ?: System.getenv("PGHOST") 51 if (host == null || host.startsWith('/')) { 52 val port = (if (uri.port == -1) null else uri.port.toString()) ?: params["port"] ?: System.getenv("PGPORT") ?: "5432" 53 val user = params["user"] ?: currentUser() 54 val unixPath = (host ?:"/var/run/postgresql") + "/.s.PGSQL.$port" 55 return "jdbc:postgresql://localhost${uri.path}?user=$user&socketFactory=org.newsclub.net.unix." + 56 "AFUNIXSocketFactory\$FactoryArg&socketFactoryArg=$unixPath" 57 } 58 if (pgConn.startsWith("postgres://")) { 59 // The JDBC driver doesn't like postgres://, only postgresql://. 60 // For consistency with other components, we normalize the postgres:// URI 61 // into one that the JDBC driver likes. 62 return "jdbc:postgresql://" + pgConn.removePrefix("postgres://") 63 } 64 logger.info("connecting to database via JDBC string '$pgConn'") 65 return "jdbc:$pgConn" 66 } 67 68 data class DatabaseConfig( 69 val dbConnStr: String, 70 val sqlDir: Path 71 ) 72 73 fun pgDataSource(dbConfig: String): PGSimpleDataSource { 74 val jdbcConnStr = jdbcFromPg(dbConfig) 75 logger.debug("connecting to database via JDBC string '$jdbcConnStr'") 76 val pgSource = PGSimpleDataSource() 77 pgSource.setUrl(jdbcConnStr) 78 pgSource.prepareThreshold = 1 79 return pgSource 80 } 81 82 fun PGSimpleDataSource.pgConnection(schema: String? = null): PgConnection { 83 val conn = connection.unwrap(PgConnection::class.java) 84 if (schema != null) conn.execSQLUpdate("SET search_path TO $schema") 85 return conn 86 }