diff --git a/Dockerfile b/Dockerfile index a3c73116..84414f0f 100755 --- a/Dockerfile +++ b/Dockerfile @@ -13,13 +13,15 @@ RUN eval "$(cs java --jvm $GRAAL_VERSION --env)"; $JAVA_HOME/bin/gu install nati #RUN /mongocamp-cli/mongocamp-cli/target/graalvm-native-image/mongocamp-cli prepare cache; FROM debian:12.1-slim +ENV PLUGINS_DIRECTORY="/opt/mongocamp/plugins" COPY --from=builder /mongocamp-cli/mongocamp-cli/target/graalvm-native-image/mongocamp-cli /opt/bin/mongocamp-cli ## todo: reactivate build if fixed. https://github.com/oracle/graal/issues/7264 ## COPY --from=builder /mongocamp-cli/server-raw /opt/bin/server-raw ENV MODE="default" WORKDIR /opt/bin/ +RUN echo 'debconf debconf/frontend select Noninteractive' | debconf-set-selections; apt-get update; apt-get install -y snappy-dev zlib-dev bash; apt-get -y upgrade; ## todo: reactivate build if fixed. https://github.com/oracle/graal/issues/7264 # RUN mkdir -p /opt/mongocamp/plugins; chmod -R 777 /opt/mongocamp/plugins; chmod +x /opt/bin/mongocamp-cli; chmod +x /opt/bin/server-raw; apt-get update; -RUN mkdir -p /opt/mongocamp/plugins; chmod -R 777 /opt/mongocamp/plugins; chmod +x /opt/bin/mongocamp-cli; +RUN mkdir -p $PLUGINS_DIRECTORY; chmod -R 777 $PLUGINS_DIRECTORY; chmod +x /opt/bin/mongocamp-cli; RUN ./mongocamp-cli prepare cache; ENTRYPOINT ./mongocamp-cli run $MODE diff --git a/mongocamp-cli/src/main/resources/META-INF/native-image/dev.mongocamp/mongocamp-cli/native-image.properties b/mongocamp-cli/src/main/resources/META-INF/native-image/dev.mongocamp/mongocamp-cli/native-image.properties index cc12df8b..63f1370a 100755 --- a/mongocamp-cli/src/main/resources/META-INF/native-image/dev.mongocamp/mongocamp-cli/native-image.properties +++ b/mongocamp-cli/src/main/resources/META-INF/native-image/dev.mongocamp/mongocamp-cli/native-image.properties @@ -1,4 +1,4 @@ Args = -H:ReflectionConfigurationResources=${.}/reflection-config.json \ -H:ResourceConfigurationResources=${.}/resource-config.json \ - --initialize-at-build-time=org.slf4j.LoggerFactory,ch.qos.logback \ + --initialize-at-build-time=org.slf4j.LoggerFactory,ch.qos.logback,dev.mongocamp.driver.mongodb.Converter,dev.mongocamp.driver.mongodb.bson.BsonConverter,dev.mongocamp.driver.mongodb.Converter$,dev.mongocamp.driver.mongodb.bson.BsonConverter$ \ --enable-url-protocols=https,http \ No newline at end of file diff --git a/mongocamp-cli/src/main/resources/META-INF/native-image/dev.mongocamp/mongocamp-cli/reflection-config.json b/mongocamp-cli/src/main/resources/META-INF/native-image/dev.mongocamp/mongocamp-cli/reflection-config.json index 970368d3..fb95b38c 100755 --- a/mongocamp-cli/src/main/resources/META-INF/native-image/dev.mongocamp/mongocamp-cli/reflection-config.json +++ b/mongocamp-cli/src/main/resources/META-INF/native-image/dev.mongocamp/mongocamp-cli/reflection-config.json @@ -121,111 +121,159 @@ "allPublicClasses": true }, { - "name":"com.github.benmanes.caffeine.cache.AccessOrderDeque$AccessOrder" + "name": "com.github.benmanes.caffeine.cache.AccessOrderDeque$AccessOrder" }, { - "name":"com.github.benmanes.caffeine.cache.AsyncCache" + "name": "com.github.benmanes.caffeine.cache.AsyncCache" }, { - "name":"com.github.benmanes.caffeine.cache.AsyncCacheLoader" + "name": "com.github.benmanes.caffeine.cache.AsyncCacheLoader" }, { - "name":"com.github.benmanes.caffeine.cache.BBHeader$PadReadCounter" + "name": "com.github.benmanes.caffeine.cache.BBHeader$PadReadCounter" }, { - "name":"com.github.benmanes.caffeine.cache.BLCHeader$DrainStatusRef", - "fields":[{"name":"drainStatus"}] + "name": "com.github.benmanes.caffeine.cache.BLCHeader$DrainStatusRef", + "fields": [ + { + "name": "drainStatus" + } + ] }, { - "name":"com.github.benmanes.caffeine.cache.BLCHeader$PadDrainStatus" + "name": "com.github.benmanes.caffeine.cache.BLCHeader$PadDrainStatus" }, { - "name":"com.github.benmanes.caffeine.cache.BaseMpscLinkedArrayQueueColdProducerFields", - "fields":[{"name":"producerLimit"}] + "name": "com.github.benmanes.caffeine.cache.BaseMpscLinkedArrayQueueColdProducerFields", + "fields": [ + { + "name": "producerLimit" + } + ] }, { - "name":"com.github.benmanes.caffeine.cache.BaseMpscLinkedArrayQueueConsumerFields", - "fields":[{"name":"consumerIndex"}] + "name": "com.github.benmanes.caffeine.cache.BaseMpscLinkedArrayQueueConsumerFields", + "fields": [ + { + "name": "consumerIndex" + } + ] }, { - "name":"com.github.benmanes.caffeine.cache.BaseMpscLinkedArrayQueueProducerFields", - "fields":[{"name":"producerIndex"}] + "name": "com.github.benmanes.caffeine.cache.BaseMpscLinkedArrayQueueProducerFields", + "fields": [ + { + "name": "producerIndex" + } + ] }, { - "name":"com.github.benmanes.caffeine.cache.BoundedLocalCache", - "fields":[{"name":"refreshes"}] + "name": "com.github.benmanes.caffeine.cache.BoundedLocalCache", + "fields": [ + { + "name": "refreshes" + } + ] }, { - "name":"com.github.benmanes.caffeine.cache.Buffer" + "name": "com.github.benmanes.caffeine.cache.Buffer" }, { - "name":"com.github.benmanes.caffeine.cache.Cache" + "name": "com.github.benmanes.caffeine.cache.Cache" }, { - "name":"com.github.benmanes.caffeine.cache.Expiry" + "name": "com.github.benmanes.caffeine.cache.Expiry" }, { - "name":"com.github.benmanes.caffeine.cache.Interner" + "name": "com.github.benmanes.caffeine.cache.Interner" }, { - "name":"com.github.benmanes.caffeine.cache.NodeFactory" + "name": "com.github.benmanes.caffeine.cache.NodeFactory" }, { - "name":"com.github.benmanes.caffeine.cache.PS", - "fields":[ - {"name":"key"}, - {"name":"value"} + "name": "com.github.benmanes.caffeine.cache.PS", + "fields": [ + { + "name": "key" + }, + { + "name": "value" + } ] }, { - "name":"com.github.benmanes.caffeine.cache.PSW", - "fields":[{"name":"writeTime"}], - "methods":[{"name":"","parameterTypes":[] }] + "name": "com.github.benmanes.caffeine.cache.PSW", + "fields": [ + { + "name": "writeTime" + } + ], + "methods": [ + { + "name": "", + "parameterTypes": [] + } + ] }, { - "name":"com.github.benmanes.caffeine.cache.Policy" + "name": "com.github.benmanes.caffeine.cache.Policy" }, { - "name":"com.github.benmanes.caffeine.cache.Policy$Eviction" + "name": "com.github.benmanes.caffeine.cache.Policy$Eviction" }, { - "name":"com.github.benmanes.caffeine.cache.Policy$FixedExpiration" + "name": "com.github.benmanes.caffeine.cache.Policy$FixedExpiration" }, { - "name":"com.github.benmanes.caffeine.cache.Policy$FixedRefresh" + "name": "com.github.benmanes.caffeine.cache.Policy$FixedRefresh" }, { - "name":"com.github.benmanes.caffeine.cache.Policy$VarExpiration" + "name": "com.github.benmanes.caffeine.cache.Policy$VarExpiration" }, { - "name":"com.github.benmanes.caffeine.cache.References$InternalReference" + "name": "com.github.benmanes.caffeine.cache.References$InternalReference" + }, + { + "name": "com.github.benmanes.caffeine.cache.RemovalListener" + }, + { + "name": "com.github.benmanes.caffeine.cache.SSSW", + "methods": [ + { + "name": "", + "parameterTypes": [ + "com.github.benmanes.caffeine.cache.Caffeine", + "com.github.benmanes.caffeine.cache.AsyncCacheLoader", + "boolean" + ] + } + ] }, { - "name":"com.github.benmanes.caffeine.cache.RemovalListener" + "name": "com.github.benmanes.caffeine.cache.Scheduler" }, { - "name":"com.github.benmanes.caffeine.cache.SSSW", - "methods":[{"name":"","parameterTypes":["com.github.benmanes.caffeine.cache.Caffeine","com.github.benmanes.caffeine.cache.AsyncCacheLoader","boolean"] }] + "name": "com.github.benmanes.caffeine.cache.Ticker" }, { - "name":"com.github.benmanes.caffeine.cache.Scheduler" + "name": "com.github.benmanes.caffeine.cache.Weigher" }, { - "name":"com.github.benmanes.caffeine.cache.Ticker" + "name": "com.github.benmanes.caffeine.cache.WriteOrderDeque$WriteOrder" }, { - "name":"com.github.benmanes.caffeine.cache.Weigher" + "name": "com.github.benmanes.caffeine.cache.stats.StatsCounter" }, { - "name":"com.github.benmanes.caffeine.cache.WriteOrderDeque$WriteOrder" + "name": "com.github.blemale.scaffeine.AsyncCache" }, { - "name":"com.github.benmanes.caffeine.cache.stats.StatsCounter" + "name": "com.github.blemale.scaffeine.Cache" }, { - "name":"com.github.blemale.scaffeine.AsyncCache" + "name": "dev.mongocamp.driver.mongodb.Converter" }, { - "name":"com.github.blemale.scaffeine.Cache" + "name": "dev.mongocamp.driver.mongodb.bson.BsonConverter" } ] \ No newline at end of file diff --git a/mongocamp-cli/src/main/scala/dev/mongocamp/server/cli/Main.scala b/mongocamp-cli/src/main/scala/dev/mongocamp/server/cli/Main.scala index 6929fc0c..04c7207d 100755 --- a/mongocamp-cli/src/main/scala/dev/mongocamp/server/cli/Main.scala +++ b/mongocamp-cli/src/main/scala/dev/mongocamp/server/cli/Main.scala @@ -1,6 +1,7 @@ package dev.mongocamp.server.cli import dev.mongocamp.server.library.BuildInfo +import dev.mongocamp.server.service.ConfigurationRead import lukfor.progress.TaskService import picocli.CommandLine import picocli.CommandLine.Help.Ansi.Style diff --git a/mongocamp-cli/src/main/scala/dev/mongocamp/server/cli/StartApplicationCommand.scala b/mongocamp-cli/src/main/scala/dev/mongocamp/server/cli/StartApplicationCommand.scala index c28bd320..6a39bc79 100755 --- a/mongocamp-cli/src/main/scala/dev/mongocamp/server/cli/StartApplicationCommand.scala +++ b/mongocamp-cli/src/main/scala/dev/mongocamp/server/cli/StartApplicationCommand.scala @@ -36,7 +36,8 @@ class StartApplicationCommand extends Callable[Integer] with LazyLogging { case s: String if s.equalsIgnoreCase("default") => val pluginUrls = PluginService.listOfReadableUrls().map(url => File(url)) - if (pluginUrls.nonEmpty) { + // todo: reactivate build if fixed. https://github.com/oracle/graal/issues/7264 + if (pluginUrls.nonEmpty || true) { JvmStartService.startServer() } else { diff --git a/mongocamp-library/build.sbt b/mongocamp-library/build.sbt index b8ac7787..3c3ee66a 100755 --- a/mongocamp-library/build.sbt +++ b/mongocamp-library/build.sbt @@ -2,7 +2,7 @@ name := "mongocamp-library" libraryDependencies += "io.get-coursier" %% "coursier" % "2.1.7" -libraryDependencies += "dev.mongocamp" %% "mongodb-driver" % "2.6.4" +libraryDependencies += "dev.mongocamp" %% "mongodb-driver" % "2.6.5-SNAPSHOT" libraryDependencies += "io.github.classgraph" % "classgraph" % "4.8.163" diff --git a/mongocamp-library/src/main/resources/reference.conf b/mongocamp-library/src/main/resources/reference.conf new file mode 100755 index 00000000..a46e826a --- /dev/null +++ b/mongocamp-library/src/main/resources/reference.conf @@ -0,0 +1,57 @@ +server { + interface = "0.0.0.0" + port = 8080 +} + +cors { + origins.allowed = ["http://localhost:8080"] + headers { + allowed = ["Authorization", "Content-Type", "X-Requested-With", "X-AUTH-APIKEY"] + exposed = ["Content-Type", "x-pagination-rows-per-page", "x-pagination-current-page", "x-pagination-count-rows", "x-pagination-count-pages", "x-request-id"] + } +} + +connection { + host = "localhost" + port = 27017 + database = "mongocamp" + username = "" + password = "" + authdb = "admin" +} + +docs { + openapi = true + swagger = false +} + +auth { + handler = "mongo" + apikeylength = 32 + + bearer = true + token = true + basic = true + cache.db = true + + users = ["{}"] + roles = ["{}"] + secret = "secret_key" + expiring.duration = 6h + prefix = "mc_" +} + +file { + handler = "gridfs" + cache.age = "7776000" +} + +plugins { + directory="/opt/mongocamp/plugins" + ignored=[] + modules=[] + maven.repositories=[] + urls=[] +} + +http.client.headers = "{}" diff --git a/mongocamp-library/src/main/scala/dev/mongocamp/server/database/MongoDatabase.scala b/mongocamp-library/src/main/scala/dev/mongocamp/server/database/MongoDatabase.scala index 265ae8fc..814332e9 100755 --- a/mongocamp-library/src/main/scala/dev/mongocamp/server/database/MongoDatabase.scala +++ b/mongocamp-library/src/main/scala/dev/mongocamp/server/database/MongoDatabase.scala @@ -1,14 +1,16 @@ package dev.mongocamp.server.database -import com.mongodb.event.{ CommandListener, ConnectionPoolListener } +import com.mongodb.event.{CommandListener, ConnectionPoolListener} import dev.mongocamp.driver.mongodb.bson.codecs.CustomCodecProvider -import dev.mongocamp.driver.mongodb.database.{ DatabaseProvider, MongoConfig } +import dev.mongocamp.driver.mongodb.database.{DatabaseProvider, MongoConfig} import dev.mongocamp.server.config.DefaultConfigurations import dev.mongocamp.server.library.BuildInfo +import dev.mongocamp.server.model.MongoCampConfiguration import dev.mongocamp.server.service.ConfigurationRead import org.bson.codecs.configuration.CodecProvider import org.bson.codecs.configuration.CodecRegistries._ import org.mongodb.scala.MongoClient.DEFAULT_CODEC_REGISTRY +import org.mongodb.scala.bson.codecs.Macros._ import scala.collection.mutable.ArrayBuffer import scala.jdk.CollectionConverters._ diff --git a/mongocamp-library/src/main/scala/dev/mongocamp/server/model/MongoCampConfiguration.scala b/mongocamp-library/src/main/scala/dev/mongocamp/server/model/MongoCampConfiguration.scala index f83e9c11..975b37d6 100755 --- a/mongocamp-library/src/main/scala/dev/mongocamp/server/model/MongoCampConfiguration.scala +++ b/mongocamp-library/src/main/scala/dev/mongocamp/server/model/MongoCampConfiguration.scala @@ -1,6 +1,6 @@ package dev.mongocamp.server.model -case class MongoCampConfiguration(key: String, value: Any, configType: String, comment: String, needsRestartForActivation: Boolean) {} +case class MongoCampConfiguration(key: String, value: Any, configType: String, comment: String, needsRestartForActivation: Boolean) object MongoCampConfiguration { val confTypeBoolean = "Boolean" diff --git a/mongocamp-library/src/main/scala/dev/mongocamp/server/service/ConfigurationRead.scala b/mongocamp-library/src/main/scala/dev/mongocamp/server/service/ConfigurationRead.scala index 98b772e5..75dde0a8 100755 --- a/mongocamp-library/src/main/scala/dev/mongocamp/server/service/ConfigurationRead.scala +++ b/mongocamp-library/src/main/scala/dev/mongocamp/server/service/ConfigurationRead.scala @@ -3,6 +3,7 @@ package dev.mongocamp.server.service import com.github.blemale.scaffeine.Scaffeine import com.typesafe.config import com.typesafe.config.ConfigFactory +import com.typesafe.scalalogging.LazyLogging import dev.mongocamp.driver.mongodb._ import dev.mongocamp.server.config.DefaultConfigurations._ import dev.mongocamp.server.database.ConfigDao @@ -11,13 +12,14 @@ import dev.mongocamp.server.model.MongoCampConfiguration import dev.mongocamp.server.model.MongoCampConfigurationExtensions._ import dev.mongocamp.server.service.ConfigurationRead.{ configCache, isDefaultConfigsRegistered, nonPersistentConfigs } import io.circe.parser.decode +import org.bson.BsonDocument import org.mongodb.scala.bson.Document import sttp.model.StatusCode import scala.collection.mutable import scala.concurrent.duration._ import scala.util.Random -trait ConfigurationRead { +trait ConfigurationRead extends LazyLogging { private lazy val conf: config.Config = ConfigFactory.load() @@ -27,6 +29,7 @@ trait ConfigurationRead { def getConfig(key: String): Option[MongoCampConfiguration] = { if (!isDefaultConfigsRegistered) { + println("configuration should registered") registerMongoCampServerDefaultConfigs() } if (nonPersistentConfigs.contains(key)) { @@ -54,11 +57,10 @@ trait ConfigurationRead { } def registerMongoCampServerDefaultConfigs(): Unit = { - isDefaultConfigsRegistered = true registerNonPersistentConfig(ConfigKeyConnectionHost, MongoCampConfiguration.confTypeString) registerNonPersistentConfig(ConfigKeyConnectionPort, MongoCampConfiguration.confTypeLong) - registerNonPersistentConfig(ConfigKeyConnectionDatabase, MongoCampConfiguration.confTypeString) + registerNonPersistentConfig(ConfigKeyConnectionDatabase, MongoCampConfiguration.confTypeString, Some("mongocamp")) registerNonPersistentConfig(ConfigKeyConnectionUsername, MongoCampConfiguration.confTypeStringOption) registerNonPersistentConfig(ConfigKeyConnectionPassword, MongoCampConfiguration.confTypeStringOption) registerNonPersistentConfig(ConfigKeyConnectionAuthDb, MongoCampConfiguration.confTypeString, Some("admin")) @@ -66,6 +68,9 @@ trait ConfigurationRead { registerNonPersistentConfig(ConfigKeyAuthUsers, MongoCampConfiguration.confTypeStringList) registerNonPersistentConfig(ConfigKeyAuthRoles, MongoCampConfiguration.confTypeStringList) + isDefaultConfigsRegistered = true + ConfigDao().createUniqueIndexForField("key").result() + registerConfig(ConfigKeyServerInterface, MongoCampConfiguration.confTypeString, needsRestartForActivation = true) registerConfig(ConfigKeyServerPort, MongoCampConfiguration.confTypeLong, needsRestartForActivation = true) @@ -97,8 +102,6 @@ trait ConfigurationRead { registerConfig(ConfigKeyDocsSwagger, MongoCampConfiguration.confTypeBoolean, needsRestartForActivation = true) registerConfig(ConfigKeyOpenApi, MongoCampConfiguration.confTypeBoolean, needsRestartForActivation = true) - ConfigDao().createUniqueIndexForField("key").result() - } def registerNonPersistentConfig(configKey: String, configType: String, value: Option[Any] = None, comment: String = ""): Boolean = { @@ -158,8 +161,9 @@ trait ConfigurationRead { dbConfiguration } } - val insertResponse = ConfigDao().insertOne(Converter.toDocument(configToInsert)).result() - publishConfigRegisterEvent(true, configKey, configType, value, comment, needsRestartForActivation = needsRestartForActivation) + val document = configurationToDocument(configToInsert) + val insertResponse = ConfigDao().insertOne(document).result() + publishConfigRegisterEvent(persistent = true, configKey, configType, value, comment, needsRestartForActivation = needsRestartForActivation) checkAndUpdateWithEnv(configKey) insertResponse.wasAcknowledged() } @@ -168,6 +172,13 @@ trait ConfigurationRead { } } + private def configurationToDocument(configToInsert: MongoCampConfiguration): Document = { + val document = documentFromScalaMap( + Map("key" -> configToInsert.key, "value" -> configToInsert.value, "configType" -> configToInsert.configType, "comment" -> configToInsert.comment, "needsRestartForActivation" -> configToInsert.needsRestartForActivation) + ) + document + } + private[service] def checkAndUpdateWithEnv(key: String): Unit = { getConfigFromDatabase(key).foreach(dbConfig => { loadEnvValue(key) @@ -175,7 +186,7 @@ trait ConfigurationRead { .map(envConfigValue => { if (dbConfig.value == null || !dbConfig.value.equals(envConfigValue)) { val mongoCampConfiguration = dbConfig.copy(value = envConfigValue, comment = "updated by env") - val replaceResult = ConfigDao().replaceOne(Map("key" -> key), Converter.toDocument(mongoCampConfiguration)).result() + val replaceResult = ConfigDao().replaceOne(Map("key" -> key), configurationToDocument(mongoCampConfiguration)).result() configCache.invalidate(key) publishConfigUpdateEvent(key, envConfigValue, dbConfig.value, "checkAndUpdateWithEnv") replaceResult.wasAcknowledged() diff --git a/mongocamp-library/src/main/scala/dev/mongocamp/server/service/CoursierModuleService.scala b/mongocamp-library/src/main/scala/dev/mongocamp/server/service/CoursierModuleService.scala index 9ed3eeac..4721d2c0 100755 --- a/mongocamp-library/src/main/scala/dev/mongocamp/server/service/CoursierModuleService.scala +++ b/mongocamp-library/src/main/scala/dev/mongocamp/server/service/CoursierModuleService.scala @@ -53,7 +53,7 @@ object CoursierModuleService extends LazyLogging { val scalaVersion = new Semver(BuildInfo.scalaVersion) val scalaShort = s"${scalaVersion.getMajor}.${scalaVersion.getMinor}" val dependency = Dependency(Module(Organization(BuildInfo.organization), ModuleName(s"mongocamp-server_$scalaShort")), BuildInfo.version) - CoursierModuleService.fetchMavenDependencies(List(dependency), None, false) + CoursierModuleService.fetchMavenDependencies(List(dependency), None, useCustomMavenRepos = false) } private def fetchMavenDependencies(dependencies: List[Dependency], resolutionParams: Option[ResolutionParams], useCustomMavenRepos: Boolean): List[File] = { diff --git a/mongocamp-server/src/main/resources/application.conf b/mongocamp-server/src/main/resources/application.conf index 7f87d9a2..cd98b60c 100755 --- a/mongocamp-server/src/main/resources/application.conf +++ b/mongocamp-server/src/main/resources/application.conf @@ -25,59 +25,4 @@ pekko { } } } -} - -server { - interface = "0.0.0.0" - port = 8080 -} - -cors { - origins.allowed = ["http://localhost:8080"] - headers { - allowed = ["Authorization", "Content-Type", "X-Requested-With", "X-AUTH-APIKEY"] - exposed = ["Content-Type", "x-pagination-rows-per-page", "x-pagination-current-page", "x-pagination-count-rows", "x-pagination-count-pages", "x-request-id"] - } -} - -connection { - host = "localhost" - port = 27017 - database = "mongocamp" - username = "" - password = "" - authdb = "admin" -} - -docs { - openapi = true - swagger = false -} - -auth { - handler = "mongo" - apikeylength = 32 - - bearer = true - token = true - basic = true - cache.db = true - - users = ["{}"] - roles = ["{}"] - secret = "secret_key" - expiring.duration = 6h - prefix = "mc_" -} - -file { - handler = "gridfs" - cache.age = "7776000" -} - -plugins { - directory="/opt/mongocamp/plugins" - ignored=[] -} - -http.client.headers = "{}" +} \ No newline at end of file