mirror of
https://github.com/Eyre-S/Coeur-Morny-Cono.git
synced 2024-11-28 05:56:50 +08:00
Compare commits
2 Commits
053b789aff
...
2baa249d63
Author | SHA1 | Date | |
---|---|---|---|
2baa249d63 | |||
a62398e0c5 |
2
.gitignore
vendored
2
.gitignore
vendored
@ -1,7 +1,5 @@
|
|||||||
|
|
||||||
# IDE
|
# IDE
|
||||||
.idea/
|
|
||||||
.vscode/
|
|
||||||
.gradle/
|
.gradle/
|
||||||
.settings/
|
.settings/
|
||||||
.metals/
|
.metals/
|
||||||
|
BIN
.idea/icon.png
Normal file
BIN
.idea/icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 258 KiB |
1
.run/.gitignore
vendored
Normal file
1
.run/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
|||||||
|
debug.env
|
16
.run/Morny CLI [pr].run.xml
Normal file
16
.run/Morny CLI [pr].run.xml
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Morny CLI [pr]" type="Application" factoryName="Application">
|
||||||
|
<option name="MAIN_CLASS_NAME" value="cc.sukazyo.cono.morny.MornyCLI" />
|
||||||
|
<module name="Coeur Morny Cono" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$/run" />
|
||||||
|
<extension name="coverage">
|
||||||
|
<pattern>
|
||||||
|
<option name="PATTERN" value=".*" />
|
||||||
|
<option name="ENABLED" value="true" />
|
||||||
|
</pattern>
|
||||||
|
</extension>
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
20
.run/Morny Coeur [t][user_dev(env).u_q_c_r_m] [pr].run.xml
Normal file
20
.run/Morny Coeur [t][user_dev(env).u_q_c_r_m] [pr].run.xml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Morny Coeur [t][user:dev(env).u|q|c|r:m] [pr]" type="Application" factoryName="Application">
|
||||||
|
<option name="envFilePaths">
|
||||||
|
<option value="$PROJECT_DIR$/.run/debug.env" />
|
||||||
|
</option>
|
||||||
|
<option name="MAIN_CLASS_NAME" value="cc.sukazyo.cono.morny.core.ServerMain" />
|
||||||
|
<module name="Coeur Morny Cono" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="--quiet --debug -t --username sukazyo_deving_bot --master 793274677 --trusted-chat -1 --auto-cmd --outdated-block --trusted-reader-dinner 1040613596 --report-to 793274677 -medc 793274677 -medt 0,2,18,19 -medtz 8 --dinner-chat -1001670950261" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$/run" />
|
||||||
|
<extension name="coverage">
|
||||||
|
<pattern>
|
||||||
|
<option name="PATTERN" value=".*" />
|
||||||
|
<option name="ENABLED" value="true" />
|
||||||
|
</pattern>
|
||||||
|
</extension>
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
20
.run/Morny Coeur [user_dev(env).u_q_c] [pr].run.xml
Normal file
20
.run/Morny Coeur [user_dev(env).u_q_c] [pr].run.xml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Morny Coeur [user:dev(env).u|q|c] [pr]" type="Application" factoryName="Application">
|
||||||
|
<option name="envFilePaths">
|
||||||
|
<option value="$PROJECT_DIR$/.run/debug.env" />
|
||||||
|
</option>
|
||||||
|
<option name="MAIN_CLASS_NAME" value="cc.sukazyo.cono.morny.core.ServerMain" />
|
||||||
|
<module name="Coeur Morny Cono" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="--quiet --debug --username sukazyo_deving_bot --master 793274677 --trusted-chat -1 --outdated-block --trusted-reader-dinner 1040613596 -medc 793274677 -medt 0,2,18,19 -medtz 8 --dinner-chat -1001670950261" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$/run" />
|
||||||
|
<extension name="coverage">
|
||||||
|
<pattern>
|
||||||
|
<option name="PATTERN" value=".*" />
|
||||||
|
<option name="ENABLED" value="true" />
|
||||||
|
</pattern>
|
||||||
|
</extension>
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
20
.run/Morny Coeur [user_dev(env).u_q_c_r_m] [pr].run.xml
Normal file
20
.run/Morny Coeur [user_dev(env).u_q_c_r_m] [pr].run.xml
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Morny Coeur [user:dev(env).u|q|c|r:m] [pr]" type="Application" factoryName="Application">
|
||||||
|
<option name="envFilePaths">
|
||||||
|
<option value="$PROJECT_DIR$/.run/debug.env" />
|
||||||
|
</option>
|
||||||
|
<option name="MAIN_CLASS_NAME" value="cc.sukazyo.cono.morny.core.ServerMain" />
|
||||||
|
<module name="Coeur Morny Cono" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="--quiet --debug --username sukazyo_deving_bot --master 793274677 --trusted-chat -1 --auto-cmd --outdated-block --trusted-reader-dinner 1040613596 --report-to 793274677 -medc 793274677 -medt 0,2,18,19 -medtz 8 --dinner-chat -1001670950261" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$/run" />
|
||||||
|
<extension name="coverage">
|
||||||
|
<pattern>
|
||||||
|
<option name="PATTERN" value=".*" />
|
||||||
|
<option name="ENABLED" value="true" />
|
||||||
|
</pattern>
|
||||||
|
</extension>
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
31
.run/MornyTests #ALL.run.xml
Normal file
31
.run/MornyTests #ALL.run.xml
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="MornyTests #ALL" type="ScalaTestRunConfiguration" factoryName="ScalaTest" singleton="false" show_console_on_std_err="false" show_console_on_std_out="false">
|
||||||
|
<module name="Coeur Morny Cono" />
|
||||||
|
<option name="VMParameters" value="" />
|
||||||
|
<option name="allowRunningInParallel" value="true" />
|
||||||
|
<option name="alternativeJrePath" />
|
||||||
|
<option name="alternativeJrePathEnabled" value="false" />
|
||||||
|
<option name="classpathModifications">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="envs">
|
||||||
|
<map />
|
||||||
|
</option>
|
||||||
|
<option name="passParentEnvs" value="true" />
|
||||||
|
<option name="programParameters" value="" />
|
||||||
|
<option name="projectPathOnTarget" />
|
||||||
|
<option name="selectedOptions">
|
||||||
|
<list />
|
||||||
|
</option>
|
||||||
|
<option name="testKind" value="All in package" />
|
||||||
|
<option name="workingDirectory" value="$ProjectFileDir$\run" />
|
||||||
|
<option name="searchTest" value="In single module" />
|
||||||
|
<option name="shortenClasspath" value="NONE" />
|
||||||
|
<option name="testPackagePath" value="cc.sukazyo.cono.morny.test" />
|
||||||
|
<option name="useUiWithSbt" value="true" />
|
||||||
|
<option name="workingDirectory" value="$ProjectFileDir$\run" />
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
17
.run/ServerMain [only-hello].run.xml
Normal file
17
.run/ServerMain [only-hello].run.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="ServerMain [only-hello]" type="Application" factoryName="Application">
|
||||||
|
<option name="MAIN_CLASS_NAME" value="cc.sukazyo.cono.morny.core.ServerMain" />
|
||||||
|
<module name="Coeur Morny Cono" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="--only-hello" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$/run" />
|
||||||
|
<extension name="coverage">
|
||||||
|
<pattern>
|
||||||
|
<option name="PATTERN" value=".*" />
|
||||||
|
<option name="ENABLED" value="true" />
|
||||||
|
</pattern>
|
||||||
|
</extension>
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
17
.run/ServerMain [version].run.xml
Normal file
17
.run/ServerMain [version].run.xml
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="ServerMain [version]" type="Application" factoryName="Application">
|
||||||
|
<option name="MAIN_CLASS_NAME" value="cc.sukazyo.cono.morny.core.ServerMain" />
|
||||||
|
<module name="Coeur Morny Cono" />
|
||||||
|
<option name="PROGRAM_PARAMETERS" value="--version" />
|
||||||
|
<option name="WORKING_DIRECTORY" value="$ProjectFileDir$/run" />
|
||||||
|
<extension name="coverage">
|
||||||
|
<pattern>
|
||||||
|
<option name="PATTERN" value=".*" />
|
||||||
|
<option name="ENABLED" value="true" />
|
||||||
|
</pattern>
|
||||||
|
</extension>
|
||||||
|
<method v="2">
|
||||||
|
<option name="Make" enabled="true" />
|
||||||
|
</method>
|
||||||
|
</configuration>
|
||||||
|
</component>
|
1
.run/debug.env.example
Normal file
1
.run/debug.env.example
Normal file
@ -0,0 +1 @@
|
|||||||
|
MORNY_TG_TOKEN="2001015432:ABCDEFGH01234567890123456790123456"
|
9
.vscode/extensions.json
vendored
Normal file
9
.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"recommendations": [
|
||||||
|
"scalameta.metals",
|
||||||
|
"scala-lang.scala",
|
||||||
|
"scala-lang.scala-snippets",
|
||||||
|
"streetsidesoftware.code-spell-checker",
|
||||||
|
"vscjava.vscode-java-pack"
|
||||||
|
]
|
||||||
|
}
|
57
.vscode/launch.json
vendored
Normal file
57
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
// 使用 IntelliSense 以得知可用的屬性。
|
||||||
|
// 暫留以檢視現有屬性的描述。
|
||||||
|
// 如需詳細資訊,請瀏覽: https://go.microsoft.com/fwlink/?linkid=830387
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Morny Coeur [user:dev|q|d|mm|tc:rm|ac|ob|trd|dc|r:m|med] [pr]",
|
||||||
|
"type": "java",
|
||||||
|
"request": "launch",
|
||||||
|
"projectName": "Coeur Morny Cono",
|
||||||
|
"cwd": "${workspaceFolder}/run",
|
||||||
|
"mainClass": "cc.sukazyo.cono.morny.ServerMain",
|
||||||
|
"vmArgs": ["-Djava.net.useSystemProxies=true"],
|
||||||
|
"envFile": "${workspaceFolder}/.run/debug.env",
|
||||||
|
"args": [
|
||||||
|
"--quiet",
|
||||||
|
"--debug",
|
||||||
|
"--username", "sukazyo_deving_bot",
|
||||||
|
"--master", "793274677",
|
||||||
|
"--trusted-chat", "-1",
|
||||||
|
"--auto-cmd",
|
||||||
|
"--outdated-block",
|
||||||
|
"--trusted-reader-dinner", "1040613596",
|
||||||
|
"--dinner-chat", "-1001670950261",
|
||||||
|
"--report-to", "793274677",
|
||||||
|
"-medc", "793274677", "-medt", "0,2,18,19", "-medtz", "8",
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Morny Test [pr]",
|
||||||
|
"type": "java",
|
||||||
|
"request": "launch",
|
||||||
|
"cwd": "${workspaceFolder}/run",
|
||||||
|
"vmArgs": ["-Djava.net.useSystemProxies=true"],
|
||||||
|
"projectName": "Coeur Morny Cono",
|
||||||
|
"mainClass": "cc.sukazyo.cono.morny.MornyTest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "UniversalTest [pr]",
|
||||||
|
"type": "java",
|
||||||
|
"request": "launch",
|
||||||
|
"cwd": "${workspaceFolder}/run",
|
||||||
|
"vmArgs": ["-Djava.net.useSystemProxies=true"],
|
||||||
|
"projectName": "Coeur Morny Cono",
|
||||||
|
"mainClass": "cc.sukazyo.cono.morny.UniversalTest",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Current File [pr]",
|
||||||
|
"type": "java",
|
||||||
|
"request": "launch",
|
||||||
|
"cwd": "${workspaceFolder}/run",
|
||||||
|
"vmArgs": ["-Djava.net.useSystemProxies=true"],
|
||||||
|
"mainClass": "${file}"
|
||||||
|
},
|
||||||
|
]
|
||||||
|
}
|
14
.vscode/settings.json
vendored
Normal file
14
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
{
|
||||||
|
"java.dependency.packagePresentation": "hierarchical",
|
||||||
|
"java.configuration.updateBuildConfiguration": "disabled",
|
||||||
|
"java.compile.nullAnalysis.mode": "disabled",
|
||||||
|
"files.watcherExclude": {
|
||||||
|
"**/target": true
|
||||||
|
},
|
||||||
|
"cSpell.words": [
|
||||||
|
"Coeur",
|
||||||
|
"Gson",
|
||||||
|
"Morny",
|
||||||
|
"userid"
|
||||||
|
]
|
||||||
|
}
|
@ -4,8 +4,10 @@ import cc.sukazyo.cono.morny.core.internal.logging.{MornyFormatterConsole, Morny
|
|||||||
import cc.sukazyo.messiva.appender.ConsoleAppender
|
import cc.sukazyo.messiva.appender.ConsoleAppender
|
||||||
import cc.sukazyo.messiva.log.LogLevels
|
import cc.sukazyo.messiva.log.LogLevels
|
||||||
|
|
||||||
|
/** Logger controller of Morny Coeur program */
|
||||||
object Log {
|
object Log {
|
||||||
|
|
||||||
|
/** The logger that Morny will use */
|
||||||
val logger: MornyLoggerBase = MornyLoggerBase(
|
val logger: MornyLoggerBase = MornyLoggerBase(
|
||||||
ConsoleAppender(
|
ConsoleAppender(
|
||||||
MornyFormatterConsole()
|
MornyFormatterConsole()
|
||||||
@ -13,8 +15,14 @@ object Log {
|
|||||||
)
|
)
|
||||||
logger.minLevel(LogLevels.INFO)
|
logger.minLevel(LogLevels.INFO)
|
||||||
|
|
||||||
|
/** If the debug level logging is enabled
|
||||||
|
*
|
||||||
|
* @return `true` when the debug logging is enabled, `false` otherwise.
|
||||||
|
*/
|
||||||
def debug: Boolean = logger.levelSetting.minLevel.level <= LogLevels.DEBUG.level
|
def debug: Boolean = logger.levelSetting.minLevel.level <= LogLevels.DEBUG.level
|
||||||
|
|
||||||
|
/** Set if the debug logging should be enabled.
|
||||||
|
*/
|
||||||
def debug (is: Boolean): Unit =
|
def debug (is: Boolean): Unit =
|
||||||
if is then logger.minLevel(LogLevels.ALL)
|
if is then logger.minLevel(LogLevels.ALL)
|
||||||
else logger.minLevel(LogLevels.INFO)
|
else logger.minLevel(LogLevels.INFO)
|
||||||
|
@ -367,7 +367,6 @@ class MornyCoeur (modules: List[MornyModule])(using val config: MornyConfig)(tes
|
|||||||
* }}}
|
* }}}
|
||||||
*/
|
*/
|
||||||
object dsl extends BotExtension {
|
object dsl extends BotExtension {
|
||||||
given coeur: MornyCoeur = MornyCoeur.this
|
|
||||||
given account: TelegramBot = MornyCoeur.this.account
|
given account: TelegramBot = MornyCoeur.this.account
|
||||||
given translations: MornyLangs = MornyCoeur.this.lang
|
given translations: MornyLangs = MornyCoeur.this.lang
|
||||||
}
|
}
|
||||||
|
@ -4,10 +4,44 @@ import cc.sukazyo.cono.morny.core.MornyCoeur.*
|
|||||||
|
|
||||||
trait MornyModule {
|
trait MornyModule {
|
||||||
|
|
||||||
|
/** The unique id of this Morny module.
|
||||||
|
*
|
||||||
|
* Requires to be unique between modules that will loaded, requires only contains ASCII
|
||||||
|
* characters excepts control characters.
|
||||||
|
*
|
||||||
|
* This module id will listed in the module lists as the primary key. Although currently
|
||||||
|
* is no checks to make sure this is unique (and if is legal), it is still highly
|
||||||
|
* recommended making this unique between modules, for forward compatibles and third-party
|
||||||
|
* compatibles.
|
||||||
|
*
|
||||||
|
* Recommended to be named using all lowercased characters and hyphen character (`-`) like
|
||||||
|
* `module-author-or-provider.module-name` . For example, the Morny internal module
|
||||||
|
* `morny_misc` has the id `morny.misc`, and `stickers_get` has the id `morny.stickers-get`.
|
||||||
|
*/
|
||||||
val id: String
|
val id: String
|
||||||
|
/** Human readable name of this Morny module.
|
||||||
|
*
|
||||||
|
* No specific formats requires except do not contains ASCII control characters.
|
||||||
|
*
|
||||||
|
* No special usage except showing in module table.
|
||||||
|
*
|
||||||
|
* Recommended set this to a English name while the i18n for this is not implemented yet.
|
||||||
|
*/
|
||||||
val name: String
|
val name: String
|
||||||
|
/** Version of this module build.
|
||||||
|
*
|
||||||
|
* No special usage except showing in module table.
|
||||||
|
*/
|
||||||
val version: String
|
val version: String
|
||||||
|
|
||||||
|
/** Human readable description of this Morny module.
|
||||||
|
*
|
||||||
|
* Should be a Markdown document.
|
||||||
|
*
|
||||||
|
* No special usage.
|
||||||
|
*
|
||||||
|
* Recommended to use English while the i18n for this is not implemented yet.
|
||||||
|
*/
|
||||||
val description: String | Null
|
val description: String | Null
|
||||||
|
|
||||||
def onInitializingPre (using MornyCoeur)(cxt: OnInitializingPreContext): Unit = {}
|
def onInitializingPre (using MornyCoeur)(cxt: OnInitializingPreContext): Unit = {}
|
||||||
|
@ -13,24 +13,100 @@ import java.security.NoSuchAlgorithmException
|
|||||||
|
|
||||||
object MornySystem {
|
object MornySystem {
|
||||||
|
|
||||||
|
/** The normal version string without extra context (`+000` fields).
|
||||||
|
*
|
||||||
|
* Should contains base version ([[VERSION_BASE]]), with additional [[VERSION_DELTA version delta]]
|
||||||
|
* or snapshot tag if exists.
|
||||||
|
*
|
||||||
|
* For example `1.0.0`, `2.1.1-beta2`, `0.19.2-SNAPSHOT`, `2.0.0-alpha19-SNAPSHOT`
|
||||||
|
*/
|
||||||
@BuildConfigField val VERSION: String = BuildConfig.VERSION
|
@BuildConfigField val VERSION: String = BuildConfig.VERSION
|
||||||
|
/** The full specific version string with extra context (`+000` fields).
|
||||||
|
*
|
||||||
|
* Should contains all the normal version ([[VERSION]]), additional with git commit hash
|
||||||
|
* if exists.
|
||||||
|
*
|
||||||
|
* For example `2.0.0-alpha19-SNAPSHOT+git254ec2a5`
|
||||||
|
*/
|
||||||
@BuildConfigField val VERSION_FULL: String = BuildConfig.VERSION_FULL
|
@BuildConfigField val VERSION_FULL: String = BuildConfig.VERSION_FULL
|
||||||
|
/** The base version string.
|
||||||
|
*
|
||||||
|
* Contains only the main version number (0.0.0) and alpha/beta/RC version (-alpha20). NO
|
||||||
|
* snapshot tag or [[VERSION_DELTA version delta]] is included.
|
||||||
|
*/
|
||||||
@BuildConfigField val VERSION_BASE: String = BuildConfig.VERSION_BASE
|
@BuildConfigField val VERSION_BASE: String = BuildConfig.VERSION_BASE
|
||||||
|
/** The version delta string if exists.
|
||||||
|
*
|
||||||
|
* This delta is for debug purpose when it is designed, it adds a field to the normal
|
||||||
|
* version string to help shows if the code is updated in debug environment.
|
||||||
|
*
|
||||||
|
* The standard version delta is a string starts with `-ð`, attached after the
|
||||||
|
* [[VERSION_BASE base version]].
|
||||||
|
*
|
||||||
|
* It is currently not in used in official environment yet.
|
||||||
|
*/
|
||||||
@BuildConfigField val VERSION_DELTA: Option[String] = BuildConfig.VERSION_DELTA
|
@BuildConfigField val VERSION_DELTA: Option[String] = BuildConfig.VERSION_DELTA
|
||||||
|
/** The full length git commit id that this build is based on.
|
||||||
|
*
|
||||||
|
* Along the workspace is in a checked out git repo, this field will be the currently checked
|
||||||
|
* out git commit, no matter the git repo is clean or not.
|
||||||
|
*
|
||||||
|
* Only exists when this is built with git repo, if there's no git repo, this will only be
|
||||||
|
* [[None]].
|
||||||
|
*/
|
||||||
@BuildConfigField val GIT_COMMIT: Option[String] = Some(BuildConfig.COMMIT)
|
@BuildConfigField val GIT_COMMIT: Option[String] = Some(BuildConfig.COMMIT)
|
||||||
|
/** The build time in [[EpochMillis]].
|
||||||
|
*
|
||||||
|
* If this build is built with a git repo and the git repo is clean, that means the source
|
||||||
|
* code should have no changes with [[GIT_COMMIT the currently checked out git commit]],
|
||||||
|
* then we call this is a **clean build**, and this timestamp will be the [[GIT_COMMIT]]'s
|
||||||
|
* commit timestamp. This can help us to do a *reproducible build*.
|
||||||
|
*
|
||||||
|
* On any other cases, this timestamp will be the [[System.currentTimeMillis]] when the
|
||||||
|
* `sbt compile` is called.
|
||||||
|
*/
|
||||||
@BuildConfigField val CODE_TIMESTAMP: EpochMillis = BuildConfig.CODE_TIMESTAMP
|
@BuildConfigField val CODE_TIMESTAMP: EpochMillis = BuildConfig.CODE_TIMESTAMP
|
||||||
|
/** The codename of this version.
|
||||||
|
*
|
||||||
|
* Usually a city name, and usually updates on and only on the minor version (X.Y.z) level
|
||||||
|
* update.
|
||||||
|
*
|
||||||
|
* Should be a lowercased english only string (maybe contains numbers at some point, at
|
||||||
|
* least not historically).
|
||||||
|
*/
|
||||||
@BuildConfigField val CODENAME: String = BuildConfig.CODENAME
|
@BuildConfigField val CODENAME: String = BuildConfig.CODENAME
|
||||||
|
/** The HTTP url that a git repository of this project can be found.
|
||||||
|
*/
|
||||||
@BuildConfigField val CODE_STORE: String = BuildConfig.CODE_STORE
|
@BuildConfigField val CODE_STORE: String = BuildConfig.CODE_STORE
|
||||||
|
/** The string template that the commit url of this build can be found.
|
||||||
|
*
|
||||||
|
* Should contains one `%s` placeholder, can be interpolated a [[GIT_COMMIT]] to get the
|
||||||
|
* page of commit that current build based on.
|
||||||
|
*/
|
||||||
//noinspection ScalaWeakerAccess
|
//noinspection ScalaWeakerAccess
|
||||||
@BuildConfigField val COMMIT_PATH: String = BuildConfig.COMMIT_PATH
|
@BuildConfigField val COMMIT_PATH: String = BuildConfig.COMMIT_PATH
|
||||||
|
|
||||||
|
/** If this build is built with a clean git repo. */
|
||||||
@BuildConfigField
|
@BuildConfigField
|
||||||
def isCleanBuild: Boolean = BuildConfig.CLEAN_BUILD
|
def isCleanBuild: Boolean = BuildConfig.CLEAN_BUILD
|
||||||
|
|
||||||
|
/** The HTTP url of git commit which this build is based on.
|
||||||
|
*
|
||||||
|
* Based on [[GIT_COMMIT]] and [[COMMIT_PATH]].
|
||||||
|
*/
|
||||||
def currentCodePath: String|Null =
|
def currentCodePath: String|Null =
|
||||||
if ((COMMIT_PATH eq null) || (GIT_COMMIT isEmpty)) null
|
if ((COMMIT_PATH eq null) || (GIT_COMMIT isEmpty)) null
|
||||||
else COMMIT_PATH.formatted(GIT_COMMIT get)
|
else COMMIT_PATH.formatted(GIT_COMMIT get)
|
||||||
|
|
||||||
|
/** The MD5 hash of current running coeur execution jar.
|
||||||
|
*
|
||||||
|
* Only works on the current running coeur is from a jar file.
|
||||||
|
*
|
||||||
|
* If read jar file failed, it possibly means currently is not run from a jar file, then
|
||||||
|
* this will return `"<non-jar-runtime>"`.
|
||||||
|
*
|
||||||
|
* If failed on calculating MD5 hash, it will return `"<calculation-error>"`.
|
||||||
|
*/
|
||||||
def getJarMD5: String = {
|
def getJarMD5: String = {
|
||||||
try {
|
try {
|
||||||
FileUtils.getMD5Three(MornySystem.getClass.getProtectionDomain.getCodeSource.getLocation.toURI.getPath)
|
FileUtils.getMD5Three(MornySystem.getClass.getProtectionDomain.getCodeSource.getLocation.toURI.getPath)
|
||||||
|
@ -13,6 +13,7 @@ object ServerModulesLoader {
|
|||||||
morny.slash_action.ModuleSlashAction(),
|
morny.slash_action.ModuleSlashAction(),
|
||||||
morny.nbnhhsh.ModuleNbnhhsh(),
|
morny.nbnhhsh.ModuleNbnhhsh(),
|
||||||
morny.ip186.ModuleIP186(),
|
morny.ip186.ModuleIP186(),
|
||||||
|
morny.crons.ModuleCRONs(),
|
||||||
morny.encrypt_tool.ModuleEncryptor(),
|
morny.encrypt_tool.ModuleEncryptor(),
|
||||||
morny.call_me.ModuleCallMe(),
|
morny.call_me.ModuleCallMe(),
|
||||||
morny.social_share.ModuleSocialShare(),
|
morny.social_share.ModuleSocialShare(),
|
||||||
|
@ -26,6 +26,19 @@ trait BotExtension {
|
|||||||
|
|
||||||
extension (user: User) {
|
extension (user: User) {
|
||||||
|
|
||||||
|
/** Get this telegram [[User]]'s prefer language.
|
||||||
|
*
|
||||||
|
* It will check the [[User.languageCode]] provided by Telegram API.
|
||||||
|
*
|
||||||
|
* If a language code is provided, it will be [[LangTag.normalizeLangTag normalized]]
|
||||||
|
* to [[LangTag]] and return.
|
||||||
|
*
|
||||||
|
* If cannot find a language code associated with this [[User]], the empty string will
|
||||||
|
* be return.
|
||||||
|
*
|
||||||
|
* @return A [[LangTag.normalizeLangTag normalized]] [[LangTag]] that should be this
|
||||||
|
* [[User]]'s prefer language, or a empty string.
|
||||||
|
*/
|
||||||
def prefer_language: String =
|
def prefer_language: String =
|
||||||
user.languageCode match
|
user.languageCode match
|
||||||
case null => ""
|
case null => ""
|
||||||
|
@ -27,9 +27,28 @@ import com.pengrad.telegrambot.request.AbstractSendRequest
|
|||||||
*/
|
*/
|
||||||
trait ErrorMessage[T1 <: AbstractSendRequest[T1], T2 <: AbstractSendRequest[T2]] {
|
trait ErrorMessage[T1 <: AbstractSendRequest[T1], T2 <: AbstractSendRequest[T2]] {
|
||||||
|
|
||||||
|
/** The simple variant of this error message.
|
||||||
|
*
|
||||||
|
* In Morny, this is usually a sticker that shows the generic type of the error.
|
||||||
|
*
|
||||||
|
* Can be get by using [[getByType]] with variant tag [[ErrorMessage.Types.Simple]]
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
val simple: T1
|
val simple: T1
|
||||||
|
/** The complex variant of this error message.
|
||||||
|
*
|
||||||
|
* In Morny, this should be a text-based message that shows key information of the error
|
||||||
|
* which want to describe.
|
||||||
|
*
|
||||||
|
* Can be get by using [[getByType]] with variant tag [[ErrorMessage.Types.Complex]]
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
val complex: T2
|
val complex: T2
|
||||||
|
|
||||||
|
/** An context that defines where this error message belongs. Will be used to publish this
|
||||||
|
* message (aka. send message).
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
val context: MessagingContext.WithMessage
|
val context: MessagingContext.WithMessage
|
||||||
|
|
||||||
/** Get the simple or complex message by the given [[ErrorMessage.Types]] infer.
|
/** Get the simple or complex message by the given [[ErrorMessage.Types]] infer.
|
||||||
@ -58,12 +77,30 @@ trait ErrorMessage[T1 <: AbstractSendRequest[T1], T2 <: AbstractSendRequest[T2]]
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @see [[ErrorMessage]] */
|
||||||
object ErrorMessage {
|
object ErrorMessage {
|
||||||
|
|
||||||
|
/** An enum that contains the tag of an [[ErrorMessage]]'s variant type.
|
||||||
|
*
|
||||||
|
* Can be used to get the specific type's message of that type using [[ErrorMessage.getByType]].
|
||||||
|
*
|
||||||
|
* @since 2.0.0
|
||||||
|
*/
|
||||||
enum Types:
|
enum Types:
|
||||||
|
/** @see [[ErrorMessage.simple]] */
|
||||||
case Simple
|
case Simple
|
||||||
|
/** @see [[ErrorMessage.complex]] */
|
||||||
case Complex
|
case Complex
|
||||||
|
|
||||||
|
/** A new [[ErrorMessage]].
|
||||||
|
*
|
||||||
|
* @since 2.0.0
|
||||||
|
* @see [[ErrorMessage]]
|
||||||
|
*
|
||||||
|
* @param _simple The [[ErrorMessage.simple]] message of this error message.
|
||||||
|
* @param _complex The [[ErrorMessage.complex]] message of this error message.
|
||||||
|
* @param cxt The context of this error message, defines where the error message belongs.
|
||||||
|
*/
|
||||||
def apply [T1 <: AbstractSendRequest[T1], T2<: AbstractSendRequest[T2]]
|
def apply [T1 <: AbstractSendRequest[T1], T2<: AbstractSendRequest[T2]]
|
||||||
(_simple: T1, _complex: T2)(using cxt: MessagingContext.WithMessage): ErrorMessage[T1, T2] =
|
(_simple: T1, _complex: T2)(using cxt: MessagingContext.WithMessage): ErrorMessage[T1, T2] =
|
||||||
new ErrorMessage[T1, T2]:
|
new ErrorMessage[T1, T2]:
|
||||||
|
@ -6,7 +6,7 @@ import java.lang.annotation.ElementType;
|
|||||||
import java.lang.annotation.Target;
|
import java.lang.annotation.Target;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 这个注解表示当前字段是由 gradle 任务 {@code generateBuildConfig} 自动生成的.
|
* The annotation indicates that the field is generated by the sbt plugin {@code sbtBuildInfo}.
|
||||||
* @since 1.0.0-alpha4
|
* @since 1.0.0-alpha4
|
||||||
*/
|
*/
|
||||||
@Documented
|
@Documented
|
||||||
|
24
src/main/scala/cc/sukazyo/cono/morny/crons/ModuleCRONs.scala
Normal file
24
src/main/scala/cc/sukazyo/cono/morny/crons/ModuleCRONs.scala
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package cc.sukazyo.cono.morny.crons
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.core.internal.MornyInternalModule
|
||||||
|
import cc.sukazyo.cono.morny.core.MornyCoeur
|
||||||
|
import cc.sukazyo.cono.morny.crons.cmd.CommandCreate
|
||||||
|
|
||||||
|
class ModuleCRONs extends MornyInternalModule {
|
||||||
|
|
||||||
|
override val id: String = "morny.cron"
|
||||||
|
override val name: String = "Morny CRON messaging for Users"
|
||||||
|
override val description: String | Null =
|
||||||
|
// language=markdown
|
||||||
|
"""Provides users to set CRON based timer for messaging to themselves.
|
||||||
|
|
|
||||||
|
|Not implemented yet while Morny's database is not implemented yet.""".stripMargin
|
||||||
|
|
||||||
|
override def onInitializing (using MornyCoeur)(cxt: MornyCoeur.OnInitializingContext): Unit = {
|
||||||
|
import cxt.commandManager
|
||||||
|
|
||||||
|
commandManager `register` CommandCreate()
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,81 @@
|
|||||||
|
package cc.sukazyo.cono.morny.crons.cmd
|
||||||
|
|
||||||
|
import cc.sukazyo.cono.morny.core.bot.api.{ICommandAlias, ISimpleCommand}
|
||||||
|
import cc.sukazyo.cono.morny.core.MornyCoeur
|
||||||
|
import cc.sukazyo.cono.morny.core.bot.api.messages.{ErrorMessage, MessagingContext}
|
||||||
|
import cc.sukazyo.cono.morny.data.TelegramStickers
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.InputCommand
|
||||||
|
import cc.sukazyo.cono.morny.util.tgapi.TelegramExtensions.Requests.unsafeExecute
|
||||||
|
import cc.sukazyo.cono.morny.util.UseThrowable.toLogString
|
||||||
|
import com.cronutils.descriptor.CronDescriptor
|
||||||
|
import com.cronutils.model.{Cron, CronType}
|
||||||
|
import com.cronutils.model.definition.CronDefinitionBuilder
|
||||||
|
import com.cronutils.model.time.ExecutionTime
|
||||||
|
import com.cronutils.parser.CronParser
|
||||||
|
import com.pengrad.telegrambot.model.{Message, Update}
|
||||||
|
import com.pengrad.telegrambot.request.{SendMessage, SendSticker}
|
||||||
|
|
||||||
|
import java.time.ZonedDateTime
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
|
class CommandCreate (using coeur: MornyCoeur) extends ISimpleCommand {
|
||||||
|
import coeur.dsl.{*, given}
|
||||||
|
|
||||||
|
override val name: String = "create_cron_message"
|
||||||
|
override val aliases: List[ICommandAlias] = Nil
|
||||||
|
|
||||||
|
override def execute (using command: InputCommand, event: Update): Unit = {
|
||||||
|
given context: MessagingContext.WithUserAndMessage = MessagingContext.extract(using event.message)
|
||||||
|
|
||||||
|
SendMessage(
|
||||||
|
context.bind_chat.id,
|
||||||
|
"Type your CRON expression below:"
|
||||||
|
).replyToMessageId(context.bind_message.messageId)
|
||||||
|
.unsafeExecute
|
||||||
|
|
||||||
|
coeur.messageThreading.doAfter(execute1)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
def execute1 (message: Message, prev: MessagingContext.WithUserAndMessage): Unit = {
|
||||||
|
given context: MessagingContext.WithUserAndMessage = MessagingContext.extract(using message)
|
||||||
|
|
||||||
|
val cron: Cron =
|
||||||
|
try CronParser(CronDefinitionBuilder.instanceDefinitionFor(CronType.UNIX))
|
||||||
|
.parse(message.text())
|
||||||
|
catch case e: IllegalArgumentException =>
|
||||||
|
ErrorMessage(
|
||||||
|
SendSticker(
|
||||||
|
context.bind_chat.id,
|
||||||
|
TelegramStickers.ID_404
|
||||||
|
),
|
||||||
|
SendMessage(
|
||||||
|
context.bind_chat.id,
|
||||||
|
s"""Probably you've entered an invalid CRON expression:
|
||||||
|
|
|
||||||
|
|${e.toLogString}
|
||||||
|
|""".stripMargin
|
||||||
|
)
|
||||||
|
).submit
|
||||||
|
return
|
||||||
|
|
||||||
|
val cron_describe = CronDescriptor.instance().describe(cron)
|
||||||
|
val current = ZonedDateTime.now()
|
||||||
|
val cron_exec_time = ExecutionTime.forCron(cron)
|
||||||
|
val cron_next = cron_exec_time.nextExecution(current)
|
||||||
|
val cron_prev = cron_exec_time.lastExecution(current)
|
||||||
|
SendMessage(
|
||||||
|
context.bind_chat.id,
|
||||||
|
s"""Set CRON task.
|
||||||
|
|
|
||||||
|
|Your cron settings is runs $cron_describe
|
||||||
|
|Previous runs at: ${cron_prev.map(_.format(DateTimeFormatter.ISO_DATE_TIME)).orElse("Will not run before.")}
|
||||||
|
|Next will run at: ${cron_next.map(_.format(DateTimeFormatter.ISO_DATE_TIME)).orElse("Will not run afterwards.")}
|
||||||
|
|
|
||||||
|
|""".stripMargin
|
||||||
|
).replyToMessageId(context.bind_message.messageId)
|
||||||
|
.unsafeExecute
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user