add file-based module loader and update resource-tools to 0.3.0
@ -19,7 +19,7 @@ object MornyConfiguration {
|
||||
"com.github.spotbugs" % "spotbugs-annotations" % "4.8.4" % Compile,
|
||||
|
||||
"cc.sukazyo" % "messiva" % "0.2.0",
|
||||
"cc.sukazyo" % "resource-tools" % "0.2.2",
|
||||
"cc.sukazyo" % "resource-tools" % "0.3.0",
|
||||
|
||||
"com.github.pengrad" % "java-telegram-bot-api" % "6.2.0",
|
||||
"org.http4s" %% "http4s-dsl" % "0.23.27",
|
||||
|
Before Width: | Height: | Size: 286 KiB After Width: | Height: | Size: 286 KiB |
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 82 KiB After Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 73 KiB After Width: | Height: | Size: 73 KiB |
Before Width: | Height: | Size: 90 KiB After Width: | Height: | Size: 90 KiB |
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
14
src/main/resources/morny-modules.list
Normal file
@ -0,0 +1,14 @@
|
||||
cc.sukazyo.cono.morny.tele_utils.ModuleTeleUtils
|
||||
cc.sukazyo.cono.morny.randomize_somthing.ModuleRandomize
|
||||
cc.sukazyo.cono.morny.slash_action.ModuleSlashAction
|
||||
cc.sukazyo.cono.morny.nbnhhsh.ModuleNbnhhsh
|
||||
cc.sukazyo.cono.morny.ip186.ModuleIP186
|
||||
cc.sukazyo.cono.morny.crons.ModuleCRONs
|
||||
cc.sukazyo.cono.morny.encrypt_tool.ModuleEncryptor
|
||||
cc.sukazyo.cono.morny.call_me.ModuleCallMe
|
||||
cc.sukazyo.cono.morny.social_share.ModuleSocialShare
|
||||
cc.sukazyo.cono.morny.medication_timer.ModuleMedicationTimer
|
||||
cc.sukazyo.cono.morny.morny_misc.ModuleMornyMisc
|
||||
cc.sukazyo.cono.morny.uni_meow.ModuleUniMeow
|
||||
cc.sukazyo.cono.morny.reporter.Module
|
||||
cc.sukazyo.cono.morny.stickers_get.Module
|
@ -7,7 +7,7 @@ import java.io.IOException
|
||||
object MornyAbout {
|
||||
|
||||
val MORNY_PREVIEW_IMAGE_ASCII: String =
|
||||
try { MornyAssets.pack `getResource` "texts/server-hello.txt" readAsString }
|
||||
try { MornyAssets.assets.getFile("texts/server-hello.txt").readString }
|
||||
catch case e: IOException =>
|
||||
throw RuntimeException("Cannot read MORNY_PREVIEW_IMAGE_ASCII from assets pack", e)
|
||||
|
||||
|
@ -8,6 +8,7 @@ import cc.sukazyo.cono.morny.core.bot.event.{MornyOnInlineQuery, MornyOnTelegram
|
||||
import cc.sukazyo.cono.morny.core.bot.internal.{ErrorMessageManager, ThreadingManagerImpl}
|
||||
import cc.sukazyo.cono.morny.core.http.api.{HttpServer, MornyHttpServerContext}
|
||||
import cc.sukazyo.cono.morny.core.http.internal.MornyHttpServerContextImpl
|
||||
import cc.sukazyo.cono.morny.core.module.ModuleHelper
|
||||
import cc.sukazyo.cono.morny.reporter.MornyReport
|
||||
import cc.sukazyo.cono.morny.util.schedule.Scheduler
|
||||
import cc.sukazyo.cono.morny.util.EpochDateTime.EpochMillis
|
||||
@ -15,6 +16,7 @@ import cc.sukazyo.cono.morny.util.time.WatchDog
|
||||
import cc.sukazyo.cono.morny.util.GivenContext
|
||||
import cc.sukazyo.cono.morny.util.UseString.MString
|
||||
import cc.sukazyo.cono.morny.util.UseThrowable.toLogString
|
||||
import cc.sukazyo.cono.morny.util.dataview.Table
|
||||
import com.pengrad.telegrambot.TelegramBot
|
||||
import com.pengrad.telegrambot.request.GetMe
|
||||
|
||||
@ -118,13 +120,9 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
|
||||
given MornyCoeur = this
|
||||
|
||||
val externalContext: GivenContext = GivenContext()
|
||||
import cc.sukazyo.cono.morny.util.dataview.Table.format as fmtTable
|
||||
logger `info`
|
||||
m"""The following Modules have been added to current Morny:
|
||||
|${fmtTable(
|
||||
"Module ID" :: "Module Name" :: "Module Version" :: Nil,
|
||||
modules.map(f => f.id :: f.name :: f.version :: Nil)*
|
||||
)}
|
||||
|${ModuleHelper.drawTable(modules)}
|
||||
|"""
|
||||
|
||||
///>>> BLOCK START local storage / data configuration
|
||||
|
@ -22,8 +22,8 @@ object MornyLangs {
|
||||
|
||||
val (lang_dir, lang_index_content) = try {
|
||||
(
|
||||
MornyAssets.pack.getResDir("langs"),
|
||||
MornyAssets.pack.getResource("langs/_index.hyl").readAsString()
|
||||
MornyAssets.assets.getDirectory("langs"),
|
||||
MornyAssets.assets.getFile("langs/_index.hyl").readString
|
||||
)
|
||||
} catch case e: IOException =>
|
||||
throw Exception("Cannot read Morny's translations file.", e)
|
||||
@ -37,11 +37,10 @@ object MornyLangs {
|
||||
|
||||
val language_translations = mutable.HashMap.empty[String, Definitions]
|
||||
|
||||
for (file <- lang_dir.listFiles().filter(_.isFile)) yield {
|
||||
for (file <- lang_dir.listFiles()) yield {
|
||||
boundary {
|
||||
import file.getPath as raw_path
|
||||
if !(raw_path.endsWith(".hyt") || raw_path.endsWith(".hytrans")) then break()
|
||||
val file_name = file.getPath.reverse.takeWhile(c => (c != '/') && (c != '\\')).reverse
|
||||
val file_name = file.getPath.last
|
||||
if !(file_name.endsWith(".hyt") || file_name.endsWith(".hytrans")) then break()
|
||||
val file_basename = file_name.dropRight(
|
||||
if file_name.endsWith(".hyt") then ".hyt".length
|
||||
else ".hytrans".length
|
||||
@ -51,7 +50,7 @@ object MornyLangs {
|
||||
logger `warn` s"translation file \"$file_name\" is not in language index, so it got ignored (normalized lang name is \"$normalized\")."
|
||||
break()
|
||||
val lang_def = try {
|
||||
val content = file.readAsString()
|
||||
val content = file.readString
|
||||
Parser.parse(content)
|
||||
} catch case e: IOException =>
|
||||
logger `error`
|
||||
|
@ -1,7 +1,8 @@
|
||||
package cc.sukazyo.cono.morny.core
|
||||
|
||||
import cc.sukazyo.cono.morny.core.Log.logger
|
||||
import cc.sukazyo.cono.morny.core.MornyConfig.CheckFailure
|
||||
import cc.sukazyo.cono.morny.core.MornyConfig.{CheckFailure, PROP_TOKEN_KEY}
|
||||
import cc.sukazyo.cono.morny.core.module.{ModuleHelper, ModuleLoader}
|
||||
import cc.sukazyo.cono.morny.util.CommonFormat
|
||||
|
||||
import java.time.ZoneOffset
|
||||
@ -19,6 +20,7 @@ object ServerMain {
|
||||
|
||||
val config = new MornyConfig.Prototype()
|
||||
var mode_echoVersion = false
|
||||
var mode_echoModules = false
|
||||
var mode_echoHello = false
|
||||
var mode_testRun = false
|
||||
var showHello = true
|
||||
@ -45,6 +47,7 @@ object ServerMain {
|
||||
case "--no-hello" | "-hf" | "--quiet" | "-q" => showHello = false
|
||||
case "--only-hello" | "-ho" | "-o" | "-hi" => mode_echoHello = true
|
||||
case "--version" | "-v" => mode_echoVersion = true
|
||||
case "--modules" | "-mod" => mode_echoModules = true
|
||||
|
||||
// deprecated: use --outdated-ignore instead
|
||||
// case "--outdated-block" | "-ob" =>
|
||||
@ -167,6 +170,8 @@ object ServerMain {
|
||||
s"""The Skip Login feature is not implemented yet!
|
||||
|""".stripMargin
|
||||
|
||||
val loadedModules = ModuleLoader.loadCoreModules()
|
||||
|
||||
if (mode_echoVersion) {
|
||||
|
||||
logger `info`
|
||||
@ -195,10 +200,18 @@ object ServerMain {
|
||||
| ${MornySystem.CODE_TIMESTAMP}
|
||||
| ${CommonFormat.formatDate(MornySystem.CODE_TIMESTAMP, 0)} [UTC]"""
|
||||
.stripMargin
|
||||
return
|
||||
|
||||
}
|
||||
|
||||
if (mode_echoModules) {
|
||||
|
||||
logger `info` s"Loaded modules ::: \n${ModuleHelper.drawTable(loadedModules)}"
|
||||
|
||||
}
|
||||
|
||||
if mode_echoVersion | mode_echoModules then
|
||||
return
|
||||
|
||||
logger `info`
|
||||
s"""ServerMain.java Loaded >>>
|
||||
|- version ${MornySystem.VERSION_FULL}
|
||||
@ -222,7 +235,7 @@ object ServerMain {
|
||||
|
||||
try
|
||||
MornyCoeur(
|
||||
ServerModulesLoader.load()
|
||||
loadedModules
|
||||
)(using config build)(
|
||||
testRun = mode_testRun
|
||||
)
|
||||
|
@ -1,30 +0,0 @@
|
||||
package cc.sukazyo.cono.morny.core
|
||||
|
||||
import cc.sukazyo.cono.morny
|
||||
|
||||
object ServerModulesLoader {
|
||||
|
||||
def load (): List[MornyModule] = {
|
||||
|
||||
List(
|
||||
|
||||
morny.tele_utils.ModuleTeleUtils(),
|
||||
morny.randomize_somthing.ModuleRandomize(),
|
||||
morny.slash_action.ModuleSlashAction(),
|
||||
morny.nbnhhsh.ModuleNbnhhsh(),
|
||||
morny.ip186.ModuleIP186(),
|
||||
morny.crons.ModuleCRONs(),
|
||||
morny.encrypt_tool.ModuleEncryptor(),
|
||||
morny.call_me.ModuleCallMe(),
|
||||
morny.social_share.ModuleSocialShare(),
|
||||
morny.medication_timer.ModuleMedicationTimer(),
|
||||
morny.morny_misc.ModuleMornyMisc(),
|
||||
morny.uni_meow.ModuleUniMeow(),
|
||||
morny.reporter.Module(),
|
||||
morny.stickers_get.Module(),
|
||||
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
package cc.sukazyo.cono.morny.core.module
|
||||
|
||||
import cc.sukazyo.cono.morny.core.MornyModule
|
||||
import cc.sukazyo.cono.morny.util.dataview.Table
|
||||
|
||||
object ModuleHelper {
|
||||
|
||||
def drawTable (modules: List[MornyModule]): String = {
|
||||
Table.format(
|
||||
"Module ID" :: "Module Name" :: "Module Version" :: Nil,
|
||||
modules.map(f => f.id :: f.name :: f.version :: Nil) *
|
||||
)
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,51 @@
|
||||
package cc.sukazyo.cono.morny.core.module
|
||||
|
||||
import cc.sukazyo.cono.morny.core.{MornyCoeur, MornyModule}
|
||||
import cc.sukazyo.cono.morny.core.Log.logger
|
||||
import cc.sukazyo.cono.morny.util.UseThrowable.toLogString
|
||||
|
||||
import java.nio.charset.StandardCharsets
|
||||
import scala.collection.mutable.ListBuffer
|
||||
|
||||
object ModuleLoader {
|
||||
|
||||
def loadCoreModules (): List[MornyModule] = {
|
||||
loadFromJar(classOf[MornyCoeur])
|
||||
}
|
||||
|
||||
def loadFromJar (packageClazz: Class[?]): List[MornyModule] = {
|
||||
val list = ListBuffer[MornyModule]()
|
||||
|
||||
val moduleListFile = packageClazz.getResourceAsStream("/morny-modules.list")
|
||||
.readAllBytes()
|
||||
val modules = String(moduleListFile, StandardCharsets.UTF_8)
|
||||
.split("\n")
|
||||
.map(_.strip)
|
||||
.filter(_.nonEmpty)
|
||||
|
||||
modules.foreach { (clazzName: String) =>
|
||||
try {
|
||||
val clazz = Class.forName(clazzName)
|
||||
val instance = clazz.getConstructor().newInstance()
|
||||
instance match
|
||||
case module: MornyModule =>
|
||||
list += module
|
||||
case _ =>
|
||||
logger `error`
|
||||
s"""Module is not a Morny Module :
|
||||
| - in package : ${packageClazz.getName}
|
||||
| - declared class name : $clazzName
|
||||
|You need to implement a MornyModule trait to make it a REAL morny module!""".stripMargin
|
||||
} catch case e: Exception =>
|
||||
logger `error`
|
||||
s"""Failed to create a module instance :
|
||||
| - in package : ${packageClazz.getName}
|
||||
| - declared class name : $clazzName
|
||||
|${e.toLogString}
|
||||
|Is this a typo or packaging error? You need to add morny-modules.list and your code to the same jar.""".stripMargin
|
||||
}
|
||||
|
||||
list.toList
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,9 @@
|
||||
package cc.sukazyo.cono.morny.core.module
|
||||
|
||||
object ModulesJarLoader {
|
||||
|
||||
def load (): Unit = {
|
||||
// TODO
|
||||
}
|
||||
|
||||
}
|
@ -1,11 +1,14 @@
|
||||
package cc.sukazyo.cono.morny.data
|
||||
|
||||
import cc.sukazyo.restools.ResourcesPackage
|
||||
import cc.sukazyo.restools.{ResourceDirectory, ResourcePackage}
|
||||
|
||||
object MornyAssets {
|
||||
|
||||
class AssetsException (caused: Throwable) extends Exception("Cannot read assets file.", caused)
|
||||
|
||||
val pack: ResourcesPackage = ResourcesPackage(MornyAssets.getClass, "assets_morny")
|
||||
val assetsLocation: List[String] = "assets" :: "morny-coeur" :: Nil
|
||||
|
||||
val pack: ResourcePackage = ResourcePackage.get(assetsLocation :+ "morny-coeur.identifier" *)
|
||||
val assets: ResourceDirectory = pack.getDirectory(assetsLocation*)
|
||||
|
||||
}
|
||||
|
@ -37,7 +37,7 @@ object MornyInformation {
|
||||
catch case _: UnknownHostException => None
|
||||
}
|
||||
|
||||
def getAboutPic: Array[Byte] = TelegramImages.IMG_ABOUT get
|
||||
def getAboutPic: Array[Byte] = TelegramImages.IMG_ABOUT.get
|
||||
|
||||
def getMornyAboutLinksVars: List[Var] =
|
||||
List(
|
||||
|
@ -8,7 +8,7 @@ import scala.util.Using
|
||||
|
||||
object TelegramImages {
|
||||
|
||||
class AssetsFileImage (assetsPath: String) {
|
||||
class AssetsFileImage (assetsPath: List[String]) {
|
||||
|
||||
private var cache: Option[Array[Byte]] = None
|
||||
|
||||
@ -19,7 +19,7 @@ object TelegramImages {
|
||||
|
||||
@throws[AssetsException]
|
||||
private def read (): Unit = {
|
||||
Using ((MornyAssets.pack `getResource` assetsPath)read) { stream =>
|
||||
Using (MornyAssets.assets.getFile(assetsPath*).read()) { stream =>
|
||||
try { this.cache = Some(stream.readAllBytes()) }
|
||||
catch case e: IOException => {
|
||||
throw AssetsException(e)
|
||||
@ -29,11 +29,18 @@ object TelegramImages {
|
||||
|
||||
}
|
||||
|
||||
val IMG_ABOUT: AssetsFileImage = AssetsFileImage("images/featured-image@0.5x.jpg")
|
||||
val IMG_400: AssetsFileImage = AssetsFileImage("images/http-sekai-400.png")
|
||||
val IMG_404: AssetsFileImage = AssetsFileImage("images/http-sekai-404.png")
|
||||
val IMG_500: AssetsFileImage = AssetsFileImage("images/http-sekai-500.png")
|
||||
val IMG_501: AssetsFileImage = AssetsFileImage("images/http-sekai-501.png")
|
||||
val IMG_523: AssetsFileImage = AssetsFileImage("images/http-sekai-523.png")
|
||||
object AssetsFileImage {
|
||||
def byId (id: String): AssetsFileImage =
|
||||
byId(id, "png")
|
||||
def byId (id: String, ty: String): AssetsFileImage =
|
||||
AssetsFileImage("images" :: s"$id.$ty" :: Nil);
|
||||
}
|
||||
|
||||
val IMG_ABOUT: AssetsFileImage = AssetsFileImage.byId("featured-image@0.5x", "jpg")
|
||||
val IMG_400: AssetsFileImage = AssetsFileImage.byId("http-sekai-400")
|
||||
val IMG_404: AssetsFileImage = AssetsFileImage.byId("http-sekai-404")
|
||||
val IMG_500: AssetsFileImage = AssetsFileImage.byId("http-sekai-500")
|
||||
val IMG_501: AssetsFileImage = AssetsFileImage.byId("http-sekai-501")
|
||||
val IMG_523: AssetsFileImage = AssetsFileImage.byId("http-sekai-523")
|
||||
|
||||
}
|
||||
|
@ -1,13 +1,13 @@
|
||||
package cc.sukazyo.cono.morny.test
|
||||
|
||||
import cc.sukazyo.restools.ResourcesPackage
|
||||
import cc.sukazyo.restools.{ResourceDirectory, ResourcePackage}
|
||||
import org.scalatest.freespec.AnyFreeSpec
|
||||
import org.scalatest.matchers.should
|
||||
|
||||
abstract class MornyTests extends AnyFreeSpec with should.Matchers {
|
||||
|
||||
val assets: ResourcesPackage =
|
||||
ResourcesPackage(classOf[MornyTests], "assets_morny_tests")
|
||||
val pack: ResourcePackage = ResourcePackage.get("assets_morny_tests")
|
||||
val assets: ResourceDirectory = pack.getDirectory("assets_morny_tests")
|
||||
|
||||
val pending_val = "[not-implemented]"
|
||||
|
||||
|
@ -83,7 +83,7 @@ class CommonEncryptTest extends MornyTests with TableDrivenPropertyChecks {
|
||||
if file == null then
|
||||
Array.empty[Byte]
|
||||
else
|
||||
assets.getResource(file).read.readAllBytes
|
||||
assets.getFile(file).read.readAllBytes
|
||||
|
||||
s"while hashing binary $_name :" - {
|
||||
|
||||
|