diff --git a/FILE_STRUCTURE.md b/FILE_STRUCTURE.md index 0ba0e3d..4659fab 100644 --- a/FILE_STRUCTURE.md +++ b/FILE_STRUCTURE.md @@ -4,11 +4,15 @@ File structure of pmcenter's source code: |- pmcenter - Source code main directory |- BotCommands - Every bot command's processing logic | |- ... + |- BotProcess - Bot's message routing logics + | |- ... + |- CallbackActions - Every inline keyboard command's processing logic + | |- ... |- CommandLines - Every commandline's processing logic | |- ... |- Configurations - Configurations' processing logics | |- ... - |- Enums - pmcenter's self-defined enums + |- EventHandlers - Global error handler and Ctrl-C handler | |- ... |- Interfaces - pmcenter's self-defined interfaces | |- ... @@ -18,15 +22,17 @@ File structure of pmcenter's source code: | | | |- ... | | |- Writing - For writing things to database | | | |- ... + | |- H2Helper - http/2 helper + | | |- ... + | |- Logging - Logging module + | | |- ... | |- NetworkTest - Testing network quality, used by some commands | | |- ... | |- Threads - Threads' logics | | |- ... + | |- UpdateHelper - pmcenter updates helper + | | |- ... | |- ... - |- BotProcess.cs - Bot's master logic - |- CommandLineRouter.cs - Commandlines' router - |- CommandLines.cs - Loading commandlines to memory - |- CommandManager.cs - Bot commands' router |- Program.cs - Main entry of pmcenter |- Setup.cs - Setup wizard's processing logic |- Template.cs - As its name diff --git a/README.md b/README.md index e089dcd..b69ca62 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # pmcenter -[![build status](https://ci.appveyor.com/api/projects/status/gmbdiackw0563980?svg=true)](https://ci.appveyor.com/project/Elepover/pmcenter) [![CodeFactor](https://www.codefactor.io/repository/github/elepover/pmcenter/badge)](https://www.codefactor.io/repository/github/elepover/pmcenter) [![telegram channel](https://img.shields.io/badge/telegram-channel-blue.svg)](https://t.me/pmcenter_devlog) ![license](https://img.shields.io/github/license/elepover/pmcenter.svg) ![language rank](https://img.shields.io/github/languages/top/elepover/pmcenter.svg?color=brightgreen) ![repo size in bytes](https://img.shields.io/github/repo-size/elepover/pmcenter.svg) ![environment](https://img.shields.io/badge/dotnet-v2.1-blue.svg) ![last commit](https://img.shields.io/github/last-commit/elepover/pmcenter.svg) ![status](https://img.shields.io/badge/status-maintaining-success.svg) +[![build status](https://ci.appveyor.com/api/projects/status/gmbdiackw0563980?svg=true)](https://ci.appveyor.com/project/Elepover/pmcenter) [![CodeFactor](https://www.codefactor.io/repository/github/elepover/pmcenter/badge)](https://www.codefactor.io/repository/github/elepover/pmcenter) [![telegram channel](https://img.shields.io/badge/telegram-channel-blue.svg)](https://t.me/pmcenter_devlog) ![license](https://img.shields.io/github/license/elepover/pmcenter.svg) ![language rank](https://img.shields.io/github/languages/top/elepover/pmcenter.svg?color=brightgreen) ![repo size in bytes](https://img.shields.io/github/repo-size/elepover/pmcenter.svg) ![environment](https://img.shields.io/badge/dotnet-v3.1-blueviolet.svg) ![last commit](https://img.shields.io/github/last-commit/elepover/pmcenter.svg) ![status](https://img.shields.io/badge/status-maintaining-success.svg) A telegram bot helping you process private messages. @@ -142,6 +142,7 @@ Or, use setup wizard: | Key | Type | User Editable | Description | | :---- | :---- | :---- | ----:| +| `Minify` | `Boolean`| ✓ | To minify pmcenter configurations or not. | | `APIKey` | `String`| ✓ | Your Telegram bot's API key. | | `OwnerID` | `Long` | ✓ | The owner's Telegram user ID. | | `EnableCc` | `Boolean` | ✓ | Decides whether cc feature is enabled or not. | @@ -176,7 +177,13 @@ Or, use setup wizard: | `UpdateChannel` | `String` | ✓ | Choose which update channel you prefer to. | | `IgnoreKeyboardInterrupt` | `Boolean` | ✓ | Choose whether pmcenter should ignore Ctrl-C interrupts or not. | | `DisableNetCore3Check` | `Boolean` | ✓ | Turn this on to hide .NET Core Runtime version warnings. | +| `DisableMessageLinkTip` | `Boolean` | ✓ | Turn this on to hide message link tip prompts. | +| `AnalyzeStartupTime` | `Boolean` | ✓ | Turn this on to show detailed analysis of startup time. | +| `SkipAPIKeyVerification` | `Boolean` | ✓ | Turn this on to skip API Key verification on startup. | +| `EnableActions` | `Boolean` | ✓ | Turn this on to enable message actions. | +| `CheckLangVersionMismatch` | `Boolean` | ✓ | Check language version and send alert on startup. | | `Statistics` | `Stats` | ✕ | Statistics data. | +| `IgnoredLogModules` | `Array` | ✓ | List of ignored log modules. Selected modules will not generate output to console. | | `Socks5Proxies` | `Array` | ✓ | List of SOCKS5 proxies. | | `BannedKeywords` | `Array` | ✓ | Storage of banned keywords. | | `Banned` | `Array` | ✓ | Storage of banned users. | @@ -199,7 +206,8 @@ Tip: After upgrades, you can send `/saveconf` command to the bot to fix missing - **Emojis** are supported, and were used by default. - Currently the response of the `/info` command is unchangeable. - Familiar with another language? Pull requests are welcome! -- Please think twice before turning on `EnableMsgLink`, it makes it possible for you to reply to messages that are forwarded anonymously or from channels, however, it will cost more and more of your storage space and memory as the storage grows and makes it slower for pmcenter to process configuration files. +- ~~Please think twice before turning on `EnableMsgLink`, it makes it possible for you to reply to messages that are forwarded anonymously or from channels, however, it will cost more and more of your storage space and memory as the storage grows and makes it slower for pmcenter to process configuration files.~~ +- Now Message Links play an important role in pmcenter's basic functions. Turning it off is NOT recommended. #### Changing File Location @@ -246,6 +254,7 @@ You can write a `systemd service` to keep it running, even after the host machin | `/backup` | Owner | Backup configurations. | | `/editconf ` | Owner | Manually edit configurations and translations w/ JSON-formatted text. | | `/saveconf` | Owner | Manually save configurations and translations. Useful after upgrades. | +| `/autosave [off/interval]` | Owner | Enable/Disable autosave. Intervals are in milliseconds (1/1000 of a second). | | `/readconf` | Owner | Reload configurations without restarting bot. | | `/resetconf` | Owner | Reset configurations. | | `/uptime` | Owner | Get system uptime info. | @@ -301,6 +310,8 @@ pmcenter is planning to move to .NET Core 3.1, see [issue #25](https://github.co Please enable the `EnableMsgLink` option in pmcenter's configurations file. Only messages forwarded when `EnableMsgLink` option is turned on can be replied. +You can NOT reply to the messages that were forwarded when `EnableMsgLink` option was disabled since their corresponding message links were missing. + For more information, refer to the [configurations](#pmcenter-settings) part. ### Why pmcenter.json is too large? diff --git a/README_zh.md b/README_zh.md index ce485d5..91c0c36 100644 --- a/README_zh.md +++ b/README_zh.md @@ -1,6 +1,6 @@ # pmcenter -[![build status](https://ci.appveyor.com/api/projects/status/gmbdiackw0563980?svg=true)](https://ci.appveyor.com/project/Elepover/pmcenter) [![CodeFactor](https://www.codefactor.io/repository/github/elepover/pmcenter/badge)](https://www.codefactor.io/repository/github/elepover/pmcenter) [![telegram channel](https://img.shields.io/badge/telegram-channel-blue.svg)](https://t.me/pmcenter_devlog) ![license](https://img.shields.io/github/license/elepover/pmcenter.svg) ![language rank](https://img.shields.io/github/languages/top/elepover/pmcenter.svg?color=brightgreen) ![repo size in bytes](https://img.shields.io/github/repo-size/elepover/pmcenter.svg) ![environment](https://img.shields.io/badge/dotnet-v2.1-blue.svg) ![last commit](https://img.shields.io/github/last-commit/elepover/pmcenter.svg) ![status](https://img.shields.io/badge/status-maintaining-success.svg) +[![build status](https://ci.appveyor.com/api/projects/status/gmbdiackw0563980?svg=true)](https://ci.appveyor.com/project/Elepover/pmcenter) [![CodeFactor](https://www.codefactor.io/repository/github/elepover/pmcenter/badge)](https://www.codefactor.io/repository/github/elepover/pmcenter) [![telegram channel](https://img.shields.io/badge/telegram-channel-blue.svg)](https://t.me/pmcenter_devlog) ![license](https://img.shields.io/github/license/elepover/pmcenter.svg) ![language rank](https://img.shields.io/github/languages/top/elepover/pmcenter.svg?color=brightgreen) ![repo size in bytes](https://img.shields.io/github/repo-size/elepover/pmcenter.svg) ![environment](https://img.shields.io/badge/dotnet-v3.1-blueviolet.svg) ![last commit](https://img.shields.io/github/last-commit/elepover/pmcenter.svg) ![status](https://img.shields.io/badge/status-maintaining-success.svg) 一个帮你处理私人聊天消息的 Telegram 机器人。 @@ -144,6 +144,7 @@ docker run -d -v $(pwd)/pmcenter.json:/opt/pmcenter/pmcenter.json --restart alwa | 项目 | 类型 | 用户可编辑 | 描述 | | :---- | :---- | :---- | ----:| +| `Minify` | `Boolean`| ✓ | 是否精简化 pmcenter 配置 | | `APIKey` | `String` | ✓ | 你的 Telegram 机器人 API 密钥 | | `OwnerID` | `Long` | ✓ | 使用者的 Telegram ID | | `EnableCc` | `Boolean` | ✓ | 是否启用 Cc 功能 | @@ -178,7 +179,13 @@ docker run -d -v $(pwd)/pmcenter.json:/opt/pmcenter/pmcenter.json --restart alwa | `UpdateChannel` | `String` | ✓ | 选择更新频道 | | `IgnoreKeyboardInterrupt` | `Boolean` | ✓ | 是否忽略 Ctrl-C 中断 | | `DisableNetCore3Check` | `Boolean` | ✓ | 启用以忽略 .NET Core 运行时版本检查 | +| `DisableMessageLinkTip` | `Boolean` | ✓ | 启用以忽略消息链接提示 | +| `AnalyzeStartupTime` | `Boolean` | ✓ | 启用以显示细化的启动时间分析 | +| `SkipAPIKeyVerification` | `Boolean` | ✓ | 启用以跳过启动时的 API 密钥校验 | +| `EnableActions` | `Boolean` | ✓ | 启动以启用消息操作面版 | +| `CheckLangVersionMismatch` | `Boolean` | ✓ | 在启动时检测语言文件版本 | | `Statistics` | `Stats` | ✕ | 统计数据 | +| `IgnoredLogModules` | `Array` | ✓ | 忽略的日志模块列表,这些模块将不会输出信息到控制台 | | `Socks5Proxies` | `Array` | ✓ | SOCKS5 代理列表 | | `BannedKeywords` | `Array` | ✓ | 屏蔽的关键字存储 | | `Banned` | `Array` | ✓ | 封禁用户存储 | @@ -202,7 +209,8 @@ docker run -d -v $(pwd)/pmcenter.json:/opt/pmcenter/pmcenter.json --restart alwa - 目前 `/info` 命令的回复尚且无法更改。 - 欢迎 Pull Requests. - 切换中文语言包,只需发送 `/switchlang https://raw.githubusercontent.com/Elepover/pmcenter/master/locales/pmcenter_locale_zh.json` -- 在启用 `EnableMsgLink` 前请三思:虽然此功能允许您回复匿名转发消息及频道消息,但 pmcenter 的存储和内存占用将随消息量增长而增加,并将拖慢 pmcenter 操作配置文件时的速度。 +- ~~在启用 `EnableMsgLink` 前请三思:虽然此功能允许您回复匿名转发消息及频道消息,但 pmcenter 的存储和内存占用将随消息量增长而增加,并将拖慢 pmcenter 操作配置文件时的速度。~~ +- 现在消息链接在 pmcenter 正常功能中起着重要作用,我们不推荐将其禁用。 #### 改变文件位置 @@ -249,6 +257,7 @@ pmcenter_lang: pmcenter 语言文件路径。 | `/backup` | 所有者 | 备份配置文件 | | `/editconf ` | 所有者 | 手动保存 JSON 格式的配置及翻译 | | `/saveconf` | 所有者 | 手动保存配置及翻译,可用于更新后补齐缺少的配置项 | +| `/autosave [off/时间间隔]` | 所有者 | 启用或停用自动保存,时间间隔单位为毫秒(1/1000 秒) | | `/readconf` | 所有者 | 在不重启机器人的情况下,重新载入配置 | | `/resetconf` | 所有者 | 重置配置文件 | | `/uptime` | 所有者 | 获取系统在线时间信息 | @@ -304,6 +313,8 @@ pmcenter 正在准备转向 .NET Core 3.1,请参考 [issue #25](https://github 请在 pmcenter 设置文件中启用 `EnableMsgLink` 选项。只有在 `EnableMsgLink` 选项启用后的转发的消息可以被回复。 +您无法回复在此选项处于禁用状态时被转发的消息,因为对应的消息链接不存在。 + 如需更多信息,请参见[配置](#pmcenter-设置)部分。 ### 为什么 pmcenter.json 这么大? diff --git a/locales/pmcenter_locale_en.json b/locales/pmcenter_locale_en.json index 5974282..b95649e 100644 --- a/locales/pmcenter_locale_en.json +++ b/locales/pmcenter_locale_en.json @@ -1,5 +1,5 @@ { - "TargetVersion": "1.9.280.15", + "TargetVersion": "2.0.2.0", "LangCode": "en.imported", "LanguageNameInEnglish": "English", "LanguageNameInNative": "English", @@ -7,7 +7,7 @@ "Message_UserStartDefault": "📨 *Hi!* To send anything to my owner, just send it here.\n⚠ To be informed: I'll *automatically* ban flooding users.", "Message_ReplySuccessful": "✅ Successfully replied to user $1!", "Message_ForwardedToOwner": "✅ Your message has been forwarded to my owner!", - "Message_Help": "❓ `pmcenter` *Bot Help*\n/start - Display welcome message.\n/info - Display the message's info.\n/ban - Restrict the user from contacting you.\n/banid - Restrict a user from contacting you with his/her ID.\n/pardon - Pardon the user.\n/pardonid - Pardon a user with his/her ID.\n/ping - Test if the bot is working.\n/switchfw - Pause/Resume message forwarding.\n/switchbw - Enable/Disable keyword banning.\n/switchnf - Enable/Disable notifications.\n/switchlang - Switch language file.\n/switchlangcode [Code] - Switch language with language code.\n/detectperm - Detect permissions.\n/backup - Backup configurations.\n/editconf - Manually edit settings w/ JSON-formatted text.\n/saveconf - Manually save all settings and translations. Especially useful after upgrades.\n/readconf - Reload configurations without restarting bot.\n/resetconf - Reset configurations.\n/uptime - Check system uptime information.\n/update - Check for updates and update bot.\n/chkupdate - Only check for updates.\n/catconf - Get your current configurations.\n/restart - Restart bot.\n/status - Get host device's status information.\n/perform - Run performance test.\n/testnetwork - Test latency to servers used by pmcenter.\n/chat - Enter Continued Conversation mode.\n/stopchat - Leave Continued Conversation mode.\n/retract - Retract a message.\n/clearmessagelinks - Clear message links.\n/getstats - Get statistics data.\n/help - Display this message.\n\nThank you for using `pmcenter`!", + "Message_Help": "❓ `pmcenter` *Bot Help*\n/start - Display welcome message.\n/info - Display the message's info.\n/ban - Restrict the user from contacting you.\n/banid - Restrict a user from contacting you with his/her ID.\n/pardon - Pardon the user.\n/pardonid - Pardon a user with his/her ID.\n/ping - Test if the bot is working.\n/switchfw - Pause/Resume message forwarding.\n/switchbw - Enable/Disable keyword banning.\n/switchnf - Enable/Disable notifications.\n/switchlang - Switch language file.\n/switchlangcode [Code] - Switch language with language code.\n/detectperm - Detect permissions.\n/backup - Backup configurations.\n/editconf - Manually edit settings w/ JSON-formatted text.\n/saveconf - Manually save all settings and translations. Especially useful after upgrades.\n/readconf - Reload configurations without restarting bot.\n/resetconf - Reset configurations.\n/uptime - Check system uptime information.\n/update - Check for updates and update bot.\n/chkupdate - Only check for updates.\n/catconf - Get your current configurations.\n/restart - Restart bot.\n/status - Get host device's status information.\n/perform - Run performance test.\n/testnetwork - Test latency to servers used by pmcenter.\n/chat - Enter Continued Conversation mode.\n/stopchat - Leave Continued Conversation mode.\n/retract - Retract a message.\n/clearmessagelinks - Clear message links.\n/getstats - Get statistics data.\n/autosave [off/interval] - Switch autosave status.\n/help - Display this message.\n\nThank you for using `pmcenter`!", "Message_UserBanned": "🚫 The user has been banned permanently.", "Message_UserPardoned": "✅ You've pardoned the user.", "Message_CommandNotReplying": "😶 Don't talk to me, spend time chatting with those who love you.", @@ -70,5 +70,21 @@ "Message_Retracted": "✅ This message has been retracted.", "Message_MsgLinksCleared": "✅ All message links have been cleared.", "Message_AvailableLang": "ℹ *Available languages*\n\n`$1`", - "Message_NetCore31Required": "⚠ You need `.NET Core 3.1` (runtime) installed in order to receive pmcenter v2 and further updates.\n\nLatest .NET Core runtime version detected on your device: `$1`\n\nThis warning will only show once." + "Message_NetCore31Required": "⚠ You need `.NET Core 3.1` (runtime) installed in order to receive pmcenter v2 and further updates.\n\nLatest .NET Core runtime version detected on your device: `$1`\n\nThis warning will only show once.", + "Message_MsgLinkTip": "ℹ Tip: You need to set `EnableMsgLink` option to `true` in pmcenter configurations in order to reply to anonymously forwarded messages.\nThis also happens when the message link for the message couldn't be found.\nDue to Telegram API's restrictions, it's impossible now to reply to that message.\nAfter you set `EnableMsgLink` to `true`, you'll be able to reply to this kind of messages.\n\nThis tip will only prompt once.", + "Message_AutoSaveEnabled": "✅ Autosave *enabled*, interval: `$1s`.", + "Message_AutoSaveIntervalTooShort": "⚠ The current autosave interval (`$1ms`) is *too short*! It may cause high CPU and disk usage as a result. *Disable it if you didn't intend to do that!*", + "Message_AutoSaveDisabled": "✅ Autosave *disabled*.", + "Message_Action_Banned": "✅ User $1 has been banned!", + "Message_Action_Pardoned": "✅ User $1 has been pardoned!", + "Message_Action_ContChatEnabled": "✅ You're now chatting with $1!", + "Message_Action_ContChatDisabled": "✅ Continued chat disabled!", + "Message_Action_Error": "✖ Action failed. Check logs.", + "Message_Action_ErrorWithDetails": "✖ Action failed: $1", + "Message_Action_ChooseAction": "❓ *What do you want to do with this message?*", + "Message_Action_Ban": "✖ Ban the user", + "Message_Action_Pardon": "✅ Pardon the user", + "Message_Action_Chat": "💬 Enter continued conversation", + "Message_Action_StopChat": "💬 Stop continued conversation", + "Message_Action_LinkNotFound": "✖ Cannot find the corresponding message link, did you just clear the message links, or was the message links feature disabled?" } \ No newline at end of file diff --git a/locales/pmcenter_locale_zh.json b/locales/pmcenter_locale_zh.json index 4c5085c..23df2fc 100644 --- a/locales/pmcenter_locale_zh.json +++ b/locales/pmcenter_locale_zh.json @@ -1,5 +1,5 @@ { - "TargetVersion": "1.9.280.15", + "TargetVersion": "2.0.2.0", "LangCode": "zh.simplified", "LanguageNameInEnglish": "Chinese (Simplified)", "LanguageNameInNative": "简体中文", @@ -70,5 +70,21 @@ "Message_Retracted": "✅ 消息已撤回。", "Message_MsgLinksCleared": "✅ 所有消息链接已清空。", "Message_AvailableLang": "ℹ *可用语言*\n\n`$1`", - "Message_NetCore31Required": "⚠ 您的设备上需要安装 `.NET Core 3.1` (运行时) 以获取 pmcenter v2 或未来版本的更新。\n\n在您设备上检测到的最新 .NET Core 运行时版本为: `$1`\n\n此警告只会出现一次。" + "Message_NetCore31Required": "⚠ 您的设备上需要安装 `.NET Core 3.1` (运行时) 以获取 pmcenter v2 或未来版本的更新。\n\n在您设备上检测到的最新 .NET Core 运行时版本为: `$1`\n\n此警告只会出现一次。", + "Message_MsgLinkTip": "ℹ 提示: 您需要在 pmcenter 配置中设置 `EnableMsgLink` 选项为 `true` 以回复匿名转发的消息。\n此情况也会在无法找到对应的消息链接时发生。\n由于 Telegram API 限制,这条消息已经无法回复了。\n在您设置 `EnableMsgLink` 为 `true` 后,您就可以回复后续的匿名转发消息了。\n\n此提示只会出现一次。", + "Message_AutoSaveEnabled": "✅ 自动保存 *已启用*, 时间间隔: `$1s`", + "Message_AutoSaveIntervalTooShort": "⚠ 当前自动保存时间间隔 (`$1ms`) *太短了*! 这可能导致高 CPU 和硬盘占用, *如果您不是刻意为之,请尽快停用!*", + "Message_AutoSaveDisabled": "✅ 自动保存 *已停用*", + "Message_Action_Banned": "✅ 已封禁用户 $1!", + "Message_Action_Pardoned": "✅ 已解封用户 $1!", + "Message_Action_ContChatEnabled": "✅ 已进入与 $1 的持续对话!", + "Message_Action_ContChatDisabled": "✅ 持续对话模式已停用!", + "Message_Action_Error": "✖ 操作失败,请检查日志", + "Message_Action_ErrorWithDetails": "✖ 操作失败: $1", + "Message_Action_ChooseAction": "❓ *你想对这条消息做什么?*", + "Message_Action_Ban": "✖ 封禁该用户", + "Message_Action_Pardon": "✅ 解封该用户", + "Message_Action_Chat": "💬 进入持续对话模式", + "Message_Action_StopChat": "💬 退出持续对话模式", + "Message_Action_LinkNotFound": "✖ 无法找到对应的消息链接, 您是否刚刚清除或者禁用了消息链接?" } \ No newline at end of file diff --git a/locales/pmcenter_locale_zh.meow.json b/locales/pmcenter_locale_zh.meow.json index 421f4ae..5f8d39d 100644 --- a/locales/pmcenter_locale_zh.meow.json +++ b/locales/pmcenter_locale_zh.meow.json @@ -1,5 +1,5 @@ { - "TargetVersion": "1.9.280.15", + "TargetVersion": "2.0.2.0", "LangCode": "zh.meow", "LanguageNameInEnglish": "Chinese (Meow)", "LanguageNameInNative": "喵体中文", @@ -70,5 +70,21 @@ "Message_Retracted": "✅ 消息已经从主人那边撤回啦~", "Message_MsgLinksCleared": "✅ 所有消息链接都清理掉啦~", "Message_AvailableLang": "ℹ *可用语言*\n\n`$1`", - "Message_NetCore31Required": "⚠ 您的设备上需要安装 `.NET Core 3.1` (运行时) 以获取 pmcenter v2 或未来版本的更新。\n\n在您设备上检测到的最新 .NET Core 运行时版本为: `$1`\n\n此警告只会出现一次。" + "Message_NetCore31Required": "⚠ 您的设备上需要安装 `.NET Core 3.1` (运行时) 以获取 pmcenter v2 或未来版本的更新。\n\n在您设备上检测到的最新 .NET Core 运行时版本为: `$1`\n\n此警告只会出现一次。", + "Message_MsgLinkTip": "ℹ 提示: 您需要在 pmcenter 配置中设置 `EnableMsgLink` 选项为 `true` 以回复匿名转发的消息。\n此情况也会在无法找到对应的消息链接时发生。\n由于 Telegram API 限制,这条消息已经回复不了惹。\n设置 `EnableMsgLink` 为 `true` 后,就可以回复后续的匿名转发消息啦。\n\n咱只骚扰咱家主人一次的喵!。", + "Message_AutoSaveEnabled": "✅ 自动保存 *已启用*, 时间间隔: `$1s`", + "Message_AutoSaveIntervalTooShort": "⚠ 现在的自动保存时间间隔 (`$1ms`) *太短了*! 这可能导致高 CPU 和硬盘占用, 主人是手滑了吗(挠", + "Message_AutoSaveDisabled": "✅ 自动保存 *已停用*", + "Message_Action_Banned": "✅ 已搞定用户 $1!", + "Message_Action_Pardoned": "✅ 已解封用户 $1!", + "Message_Action_ContChatEnabled": "✅ 已进入与 $1 的持续对话!", + "Message_Action_ContChatDisabled": "✅ 持续对话模式已停用!", + "Message_Action_Error": "✖ 操作失败啦OAO,看一下日志吧", + "Message_Action_ErrorWithDetails": "✖ 操作失败: $1", + "Message_Action_ChooseAction": "❓ *想做什么呢(盯*", + "Message_Action_Ban": "✖ 拍扁该用户", + "Message_Action_Pardon": "✅ 解封该用户", + "Message_Action_Chat": "💬 进入持续对话模式", + "Message_Action_StopChat": "💬 退出持续对话模式", + "Message_Action_LinkNotFound": "✖ 咱找不到对应的消息链接耶, 主人是不是刚刚清除或者禁用了消息链接?" } \ No newline at end of file diff --git a/locales/pmcenter_locale_zh.tw.json b/locales/pmcenter_locale_zh.tw.json index 0f4e478..ecda77e 100644 --- a/locales/pmcenter_locale_zh.tw.json +++ b/locales/pmcenter_locale_zh.tw.json @@ -1,5 +1,5 @@ { - "TargetVersion": "1.9.280.15", + "TargetVersion": "2.0.2.0", "LangCode": "zh.tw", "LanguageNameInEnglish": "Chinese (Traditional, Taiwan)", "LanguageNameInNative": "繁體中文(台灣)", @@ -70,5 +70,21 @@ "Message_Retracted": "✅ 訊息已撤銷。", "Message_MsgLinksCleared": "✅ 所有訊息鏈接已清空。", "Message_AvailableLang": "ℹ *可用語言*\n\n`$1`", - "Message_NetCore31Required": "⚠ 您的設備上需要安裝 `.NET Core 3.1` (運行時) 以獲取 pmcenter v2 或更新版本更新。\n\n在您的設備上識別到的最新 .NET Core 運行時版本為: `$1`\n\n此警告僅會出現一次。" + "Message_NetCore31Required": "⚠ 您的設備上需要安裝 `.NET Core 3.1` (運行時) 以獲取 pmcenter v2 或更新版本更新。\n\n在您的設備上識別到的最新 .NET Core 運行時版本為: `$1`\n\n此警告僅會出現一次。", + "Message_MsgLinkTip": "ℹ 提示: 您需要於 pmcenter 設定中設定 `EnableMsgLink` 選項爲 `true` 以回覆匿名轉傳的訊息。\n此情況也會於無法搜尋到對應的訊息連結時發生。\n由於 Telegram API 限制,這條訊息已經無法回覆了。\n在您設定 `EnableMsgLink` 爲 `true` 後,您即可回覆後續的匿名轉傳訊息了。\n\n此提示僅會出現一次。", + "Message_AutoSaveEnabled": "✅ 自動儲存 *已啓用*, 時間間隔: `$1s`", + "Message_AutoSaveIntervalTooShort": "⚠ 目前自動儲存時間間隔 (`$1ms`) *過短*! 這可能導致高 CPU 和硬碟佔用, *若您非刻意爲之,請儘快停用!*", + "Message_AutoSaveDisabled": "✅ 自動儲存 *已停用*", + "Message_Action_Banned": "✅ 已封鎖用戶 $1!", + "Message_Action_Pardoned": "✅ 已解除封鎖用戶 $1!", + "Message_Action_ContChatEnabled": "✅ 已進入與 $1 的持續對話!", + "Message_Action_ContChatDisabled": "✅ 持續對話模式已停用!", + "Message_Action_Error": "✖ 操作失敗,請檢查日誌", + "Message_Action_ErrorWithDetails": "✖ 操作失敗: $1", + "Message_Action_ChooseAction": "❓ *你想對這條訊息做甚麼?*", + "Message_Action_Ban": "✖ 封鎖该用戶", + "Message_Action_Pardon": "✅ 解除封鎖该用戶", + "Message_Action_Chat": "💬 進入持續對話模式", + "Message_Action_StopChat": "💬 退出持續對話模式", + "Message_Action_LinkNotFound": "✖ 無法找到對應的訊息連結, 您是否剛剛清除或停用了訊息連結?" } \ No newline at end of file diff --git a/pmcenter/.editorconfig b/pmcenter/.editorconfig index 6f1602b..96e4170 100644 --- a/pmcenter/.editorconfig +++ b/pmcenter/.editorconfig @@ -1,13 +1,13 @@ [*.cs] # CA1303: Do not pass literals as localized parameters -dotnet_diagnostic.CA1303.severity = suggestion +dotnet_diagnostic.CA1303.severity = none # CA1031: Do not catch general exception types -dotnet_diagnostic.CA1031.severity = suggestion +dotnet_diagnostic.CA1031.severity = none # CA1307: Specify StringComparison -dotnet_diagnostic.CA1307.severity = suggestion +dotnet_diagnostic.CA1307.severity = none # CA1304: Specify CultureInfo dotnet_diagnostic.CA1304.severity = suggestion @@ -25,7 +25,7 @@ dotnet_diagnostic.CA1052.severity = suggestion dotnet_diagnostic.CA1056.severity = suggestion # CA1062: Validate arguments of public methods -dotnet_diagnostic.CA1062.severity = suggestion +dotnet_diagnostic.CA1062.severity = none # CA1707: Identifiers should not contain underscores dotnet_diagnostic.CA1707.severity = suggestion diff --git a/pmcenter/BotCommands/AutoSaveCommand.cs b/pmcenter/BotCommands/AutoSaveCommand.cs new file mode 100644 index 0000000..170be68 --- /dev/null +++ b/pmcenter/BotCommands/AutoSaveCommand.cs @@ -0,0 +1,74 @@ +using System; +using System.Threading; +using System.Threading.Tasks; +using Telegram.Bot; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; +using static pmcenter.Methods.Logging; + +namespace pmcenter.Commands +{ + internal class AutoSaveCommand : IBotCommand + { + public bool OwnerOnly => true; + + public string Prefix => "autosave"; + + public async Task ExecuteAsync(TelegramBotClient botClient, Update update) + { + try + { + var text = update.Message.Text; + var interval = 30000; + if (text.Contains(" ")) + { + var command = text.Split(' ', 2)[1]; + if (command.ToLower() == "off") + { + Vars.CurrentConf.ConfSyncInterval = 0; + _ = await botClient.SendTextMessageAsync(update.Message.From.Id, + Vars.CurrentLang.Message_AutoSaveDisabled, + ParseMode.Markdown, + false, + Vars.CurrentConf.DisableNotifications, + update.Message.MessageId).ConfigureAwait(false); + if (Vars.SyncConf != null) Vars.SyncConf.Interrupt(); + return true; + } + interval = int.Parse(command); + } + Vars.CurrentConf.ConfSyncInterval = interval; + _ = await botClient.SendTextMessageAsync(update.Message.From.Id, + Vars.CurrentLang.Message_AutoSaveEnabled.Replace("$1", (interval / 1000).ToString()), + ParseMode.Markdown, + false, + Vars.CurrentConf.DisableNotifications, + update.Message.MessageId).ConfigureAwait(false); + if (interval < 5000) + _ = await botClient.SendTextMessageAsync(update.Message.From.Id, + Vars.CurrentLang.Message_AutoSaveIntervalTooShort.Replace("$1", interval.ToString()), + ParseMode.Markdown, + false, + Vars.CurrentConf.DisableNotifications, + update.Message.MessageId).ConfigureAwait(false); + if ((Vars.SyncConf == null) || !Vars.SyncConf.IsAlive) + { + Vars.SyncConf = new Thread(() => Methods.ThrSyncConf()); + Vars.SyncConf.Start(); + } + return true; + } + catch (Exception ex) + { + Log($"Failed to process autosave command: {ex}", "BOT", LogLevel.Error); + _ = await botClient.SendTextMessageAsync(update.Message.From.Id, + Vars.CurrentLang.Message_GeneralFailure.Replace("$1", ex.ToString()), + ParseMode.Default, + false, + Vars.CurrentConf.DisableNotifications, + update.Message.MessageId).ConfigureAwait(false); + return true; + } + } + } +} diff --git a/pmcenter/BotCommands/BackupConfCommand.cs b/pmcenter/BotCommands/BackupConfCommand.cs index 5520b7b..1faa7f1 100644 --- a/pmcenter/BotCommands/BackupConfCommand.cs +++ b/pmcenter/BotCommands/BackupConfCommand.cs @@ -5,10 +5,11 @@ using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; using static pmcenter.Methods; +using static pmcenter.Methods.Logging; namespace pmcenter.Commands { - internal class BackupConfCommand : ICommand + internal class BackupConfCommand : IBotCommand { public bool OwnerOnly => true; @@ -16,12 +17,12 @@ internal class BackupConfCommand : ICommand public async Task ExecuteAsync(TelegramBotClient botClient, Update update) { - var RandomFilename = $"pmcenter.{DateTime.Now.ToString("yyyy-dd-M-HH-mm-ss")}#{GetRandomString(6)}.json"; - Log($"Backing up configurations, filename: {Path.Combine(Vars.AppDirectory, RandomFilename)}", "BOT"); - System.IO.File.Copy(Vars.ConfFile, RandomFilename); + var randomFilename = $"pmcenter.{DateTime.Now:yyyy-dd-M-HH-mm-ss}#{GetRandomString(6)}.json"; + Log($"Backing up configurations, filename: {Path.Combine(Vars.AppDirectory, randomFilename)}", "BOT"); + System.IO.File.Copy(Vars.ConfFile, randomFilename); _ = await botClient.SendTextMessageAsync( update.Message.From.Id, - Vars.CurrentLang.Message_BackupComplete.Replace("$1", RandomFilename), + Vars.CurrentLang.Message_BackupComplete.Replace("$1", randomFilename), ParseMode.Markdown, false, Vars.CurrentConf.DisableNotifications, diff --git a/pmcenter/BotCommands/BanCommand.cs b/pmcenter/BotCommands/BanCommand.cs index 66e1acb..57828df 100644 --- a/pmcenter/BotCommands/BanCommand.cs +++ b/pmcenter/BotCommands/BanCommand.cs @@ -6,7 +6,7 @@ namespace pmcenter.Commands { - internal class BanCommand : ICommand + internal class BanCommand : IBotCommand { public bool OwnerOnly => true; diff --git a/pmcenter/BotCommands/BanIdCommand.cs b/pmcenter/BotCommands/BanIdCommand.cs index 2b3a4e5..61b0b5a 100644 --- a/pmcenter/BotCommands/BanIdCommand.cs +++ b/pmcenter/BotCommands/BanIdCommand.cs @@ -7,7 +7,7 @@ namespace pmcenter.Commands { - internal class BanIdCommand : ICommand + internal class BanIdCommand : IBotCommand { public bool OwnerOnly => true; diff --git a/pmcenter/BotCommands/CatConfigCommand.cs b/pmcenter/BotCommands/CatConfigCommand.cs index 617dce0..5698e67 100644 --- a/pmcenter/BotCommands/CatConfigCommand.cs +++ b/pmcenter/BotCommands/CatConfigCommand.cs @@ -6,7 +6,7 @@ namespace pmcenter.Commands { - internal class CatConfigCommand : ICommand + internal class CatConfigCommand : IBotCommand { public bool OwnerOnly => true; diff --git a/pmcenter/BotCommands/Chat.cs b/pmcenter/BotCommands/ChatCommand.cs similarity index 70% rename from pmcenter/BotCommands/Chat.cs rename to pmcenter/BotCommands/ChatCommand.cs index eba0ff9..bca7e8d 100644 --- a/pmcenter/BotCommands/Chat.cs +++ b/pmcenter/BotCommands/ChatCommand.cs @@ -3,11 +3,11 @@ using Telegram.Bot; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; -using static pmcenter.Methods; +using static pmcenter.Methods.Logging; namespace pmcenter.Commands { - internal class ChatCommand : ICommand + internal class ChatCommand : IBotCommand { public bool OwnerOnly => true; @@ -19,42 +19,42 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) { Log("Enabling Continued Conversation...", "BOT"); - long RealTarget; - bool IsArgumentMode; + long realTarget; + bool isArgumentMode; // try to use argument if (update.Message.Text.Contains(" ")) { - IsArgumentMode = true; + isArgumentMode = true; Log("Resolving arguments...", "BOT"); - RealTarget = long.Parse(update.Message.Text.Split(" ", 2)[1]); + realTarget = long.Parse(update.Message.Text.Split(" ", 2)[1]); } else { - IsArgumentMode = false; + isArgumentMode = false; // no argument detected / use reply message instead if (update.Message.ReplyToMessage.ForwardFrom == null) { throw (new ArgumentException("Cannot initiate Continued Conversation by channel posts.")); } - RealTarget = update.Message.ReplyToMessage.ForwardFrom.Id; + realTarget = update.Message.ReplyToMessage.ForwardFrom.Id; } - Log($"Continued Conversation enabled, target: {RealTarget}", "BOT"); - Vars.CurrentConf.ContChatTarget = RealTarget; + Log($"Continued Conversation enabled, target: {realTarget}", "BOT"); + Vars.CurrentConf.ContChatTarget = realTarget; _ = await Conf.SaveConf(false, true).ConfigureAwait(false); - string ReplaceText; - if (IsArgumentMode) + string replacementText; + if (isArgumentMode) { - ReplaceText = $"[{RealTarget}](tg://user?id={RealTarget})"; + replacementText = $"[{realTarget}](tg://user?id={realTarget})"; } else { - ReplaceText = $"[{update.Message.ReplyToMessage.ForwardFrom.FirstName} (@{update.Message.ReplyToMessage.ForwardFrom.Username})](tg://user?id={RealTarget})"; + replacementText = $"[{update.Message.ReplyToMessage.ForwardFrom.FirstName} (@{update.Message.ReplyToMessage.ForwardFrom.Username})](tg://user?id={realTarget})"; } _ = await botClient.SendTextMessageAsync(update.Message.From.Id, - Vars.CurrentLang.Message_ContinuedChatEnabled.Replace("$1", ReplaceText), + Vars.CurrentLang.Message_ContinuedChatEnabled.Replace("$1", replacementText), ParseMode.Markdown, false, Vars.CurrentConf.DisableNotifications, @@ -63,7 +63,7 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) } catch (Exception ex) { - Log($"Failed to enable Continued Conversation: {ex.ToString()}", "BOT", LogLevel.ERROR); + Log($"Failed to enable Continued Conversation: {ex}", "BOT", LogLevel.Error); _ = await botClient.SendTextMessageAsync(update.Message.From.Id, Vars.CurrentLang.Message_GeneralFailure.Replace("$1", ex.ToString()), ParseMode.Default, diff --git a/pmcenter/BotCommands/CheckUpdateCommand.cs b/pmcenter/BotCommands/CheckUpdateCommand.cs index df8617f..35da615 100644 --- a/pmcenter/BotCommands/CheckUpdateCommand.cs +++ b/pmcenter/BotCommands/CheckUpdateCommand.cs @@ -1,35 +1,35 @@ using System; using System.Threading.Tasks; using Telegram.Bot; -using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; +using static pmcenter.Methods.UpdateHelper; namespace pmcenter.Commands { - internal class CheckUpdateCommand : ICommand + internal class CheckUpdateCommand : IBotCommand { public bool OwnerOnly => true; public string Prefix => "chkupdate"; - public async Task ExecuteAsync(TelegramBotClient botClient, Update update) + public async Task ExecuteAsync(TelegramBotClient botClient, Telegram.Bot.Types.Update update) { try { - var Latest = Conf.CheckForUpdates(); - var CurrentLocalizedIndex = Conf.GetUpdateInfoIndexByLocale(Latest, Vars.CurrentLang.LangCode); - if (Conf.IsNewerVersionAvailable(Latest)) + var latest = await CheckForUpdatesAsync().ConfigureAwait(false); + var currentLocalizedIndex = GetUpdateInfoIndexByLocale(latest, Vars.CurrentLang.LangCode); + if (IsNewerVersionAvailable(latest)) { Vars.UpdatePending = true; - Vars.UpdateVersion = new Version(Latest.Latest); - Vars.UpdateLevel = Latest.UpdateLevel; - var UpdateString = Vars.CurrentLang.Message_UpdateAvailable - .Replace("$1", Latest.Latest) - .Replace("$2", Latest.UpdateCollection[CurrentLocalizedIndex].Details) - .Replace("$3", Methods.GetUpdateLevel(Latest.UpdateLevel)); + Vars.UpdateVersion = new Version(latest.Latest); + Vars.UpdateLevel = latest.UpdateLevel; + var updateString = Vars.CurrentLang.Message_UpdateAvailable + .Replace("$1", latest.Latest) + .Replace("$2", latest.UpdateCollection[currentLocalizedIndex].Details) + .Replace("$3", Methods.GetUpdateLevel(latest.UpdateLevel)); _ = await botClient.SendTextMessageAsync( update.Message.From.Id, - UpdateString, + updateString, ParseMode.Markdown, false, Vars.CurrentConf.DisableNotifications, @@ -41,9 +41,9 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) _ = await botClient.SendTextMessageAsync( update.Message.From.Id, Vars.CurrentLang.Message_AlreadyUpToDate - .Replace("$1", Latest.Latest) + .Replace("$1", latest.Latest) .Replace("$2", Vars.AppVer.ToString()) - .Replace("$3", Latest.UpdateCollection[CurrentLocalizedIndex].Details), + .Replace("$3", latest.UpdateCollection[currentLocalizedIndex].Details), ParseMode.Markdown, false, Vars.CurrentConf.DisableNotifications, @@ -53,10 +53,11 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) } catch (Exception ex) { - var ErrorString = Vars.CurrentLang.Message_UpdateCheckFailed.Replace("$1", ex.Message); + var errorString = Vars.CurrentLang.Message_UpdateCheckFailed.Replace("$1", ex.Message); _ = await botClient.SendTextMessageAsync( update.Message.From.Id, - ErrorString, ParseMode.Markdown, + errorString, + ParseMode.Markdown, false, Vars.CurrentConf.DisableNotifications, update.Message.MessageId).ConfigureAwait(false); diff --git a/pmcenter/BotCommands/ClearMessageLinksCommand.cs b/pmcenter/BotCommands/ClearMessageLinksCommand.cs index b1c7616..d4a363c 100644 --- a/pmcenter/BotCommands/ClearMessageLinksCommand.cs +++ b/pmcenter/BotCommands/ClearMessageLinksCommand.cs @@ -1,12 +1,13 @@ +using System.Collections.Generic; using System.Threading.Tasks; using Telegram.Bot; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; -using static pmcenter.Methods; +using static pmcenter.Methods.Logging; namespace pmcenter.Commands { - internal class ClearMessageLinksCommand : ICommand + internal class ClearMessageLinksCommand : IBotCommand { public bool OwnerOnly => true; @@ -15,7 +16,7 @@ internal class ClearMessageLinksCommand : ICommand public async Task ExecuteAsync(TelegramBotClient botClient, Update update) { Log("Clearing message links...", "BOT"); - Vars.CurrentConf.MessageLinks = new System.Collections.Generic.List(); + Vars.CurrentConf.MessageLinks = new List(); _ = await botClient.SendTextMessageAsync( update.Message.From.Id, Vars.CurrentLang.Message_MsgLinksCleared, diff --git a/pmcenter/BotCommands/DetectPermissionCommand.cs b/pmcenter/BotCommands/DetectPermissionCommand.cs index ebbed12..9dab011 100644 --- a/pmcenter/BotCommands/DetectPermissionCommand.cs +++ b/pmcenter/BotCommands/DetectPermissionCommand.cs @@ -8,7 +8,7 @@ namespace pmcenter.Commands { - internal class DetectPermissionCommand : ICommand + internal class DetectPermissionCommand : IBotCommand { public bool OwnerOnly => true; @@ -16,13 +16,13 @@ internal class DetectPermissionCommand : ICommand public async Task ExecuteAsync(TelegramBotClient botClient, Update update) { - var ConfWritable = FlipBool((new FileInfo(Vars.ConfFile)).IsReadOnly); - var LangWritable = FlipBool((new FileInfo(Vars.LangFile)).IsReadOnly); + var confWritable = !(new FileInfo(Vars.ConfFile)).IsReadOnly; + var langWritable = !(new FileInfo(Vars.LangFile)).IsReadOnly; _ = await botClient.SendTextMessageAsync( update.Message.From.Id, Vars.CurrentLang.Message_ConfAccess - .Replace("$1", BoolStr(ConfWritable)) - .Replace("$2", BoolStr(LangWritable)) + .Replace("$1", confWritable.ToString()) + .Replace("$2", langWritable.ToString()) , ParseMode.Markdown, false, diff --git a/pmcenter/BotCommands/DonateCommand.cs b/pmcenter/BotCommands/DonateCommand.cs index 54f8de7..9fd8022 100644 --- a/pmcenter/BotCommands/DonateCommand.cs +++ b/pmcenter/BotCommands/DonateCommand.cs @@ -1,13 +1,11 @@ -using System; -using System.Threading.Tasks; +using System.Threading.Tasks; using Telegram.Bot; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; -using static pmcenter.Methods; namespace pmcenter.Commands { - internal class DonateCommand : ICommand + internal class DonateCommand : IBotCommand { public bool OwnerOnly => false; diff --git a/pmcenter/BotCommands/EditConfCommand.cs b/pmcenter/BotCommands/EditConfCommand.cs index 6351961..1675385 100644 --- a/pmcenter/BotCommands/EditConfCommand.cs +++ b/pmcenter/BotCommands/EditConfCommand.cs @@ -1,15 +1,16 @@ +using Newtonsoft.Json; using System; using System.Threading; using System.Threading.Tasks; -using Newtonsoft.Json; using Telegram.Bot; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; using static pmcenter.Methods; +using static pmcenter.Methods.Logging; namespace pmcenter.Commands { - internal class EditConfCommand : ICommand + internal class EditConfCommand : IBotCommand { public bool OwnerOnly => true; @@ -19,12 +20,12 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) { try { - Log("Configurations received, applying...", "BOT", LogLevel.INFO); - var ConfStr = update.Message.Text.Split(" ", 2)[1]; - var Temp = JsonConvert.DeserializeObject(ConfStr); - if (Temp.APIKey != Vars.CurrentConf.APIKey) + Log("Configurations received, applying...", "BOT", LogLevel.Info); + var confStr = update.Message.Text.Split(" ", 2)[1]; + var temp = JsonConvert.DeserializeObject(confStr); + if (temp.APIKey != Vars.CurrentConf.APIKey) { - Log("API Key has changed! Please restart pmcenter to apply the change.", "BOT", LogLevel.WARN); + Log("API Key has changed! Please restart pmcenter to apply the change.", "BOT", LogLevel.Warning); _ = await botClient.SendTextMessageAsync( update.Message.From.Id, Vars.CurrentLang.Message_APIKeyChanged, @@ -34,9 +35,9 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) update.Message.MessageId).ConfigureAwait(false); Vars.RestartRequired = true; } - if (Temp.ConfSyncInterval == 0) + if (temp.ConfSyncInterval == 0) { - Log("ConfSync has been disabled, the worker thread will exit soon.", "BOT", LogLevel.WARN); + Log("ConfSync has been disabled, the worker thread will exit soon.", "BOT", LogLevel.Warning); } else if (Vars.CurrentConf.ConfSyncInterval == 0) { @@ -45,8 +46,8 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) Vars.SyncConf = new Thread(() => ThrSyncConf()); Vars.SyncConf.Start(); } - Vars.CurrentConf = Temp; - Log("Applied! Saving to local disk...", "BOT", LogLevel.INFO); + Vars.CurrentConf = temp; + Log("Applied! Saving to local disk...", "BOT", LogLevel.Info); _ = await Conf.SaveConf(false, true).ConfigureAwait(false); _ = await botClient.SendTextMessageAsync( update.Message.From.Id, diff --git a/pmcenter/BotCommands/GetStatsCommand.cs b/pmcenter/BotCommands/GetStatsCommand.cs index 0003558..ddb21af 100644 --- a/pmcenter/BotCommands/GetStatsCommand.cs +++ b/pmcenter/BotCommands/GetStatsCommand.cs @@ -5,7 +5,7 @@ namespace pmcenter.Commands { - internal class GetStatsCommand : ICommand + internal class GetStatsCommand : IBotCommand { public bool OwnerOnly => true; diff --git a/pmcenter/BotCommands/HelpCommand.cs b/pmcenter/BotCommands/HelpCommand.cs index 7371283..37228c7 100644 --- a/pmcenter/BotCommands/HelpCommand.cs +++ b/pmcenter/BotCommands/HelpCommand.cs @@ -5,7 +5,7 @@ namespace pmcenter.Commands { - internal class HelpCommand : ICommand + internal class HelpCommand : IBotCommand { public bool OwnerOnly => true; diff --git a/pmcenter/BotCommands/InfoCommand.cs b/pmcenter/BotCommands/InfoCommand.cs index 5c54720..2bf0457 100644 --- a/pmcenter/BotCommands/InfoCommand.cs +++ b/pmcenter/BotCommands/InfoCommand.cs @@ -6,7 +6,7 @@ namespace pmcenter.Commands { - internal class InfoCommand : ICommand + internal class InfoCommand : IBotCommand { public bool OwnerOnly => true; @@ -18,80 +18,87 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) { return false; } + var targetMessage = update.Message.ReplyToMessage; var sb = new StringBuilder("ℹ *Message Info*\n📩 *Sender*: ["); if (Vars.CurrentConf.UseUsernameInMsgInfo) { - sb.Append(update.Message.ReplyToMessage.ForwardFrom.FirstName); + sb.Append(targetMessage.ForwardFrom.FirstName); sb.Append(" "); - sb.Append(update.Message.ReplyToMessage.ForwardFrom.LastName); + sb.Append(targetMessage.ForwardFrom.LastName); } else { sb.Append("Here"); } sb.Append("](tg://user?id="); - sb.Append(update.Message.ReplyToMessage.ForwardFrom.Id); + sb.Append(targetMessage.ForwardFrom.Id); sb.Append(")\n👤 User ID: `"); - sb.Append(update.Message.ReplyToMessage.ForwardFrom.Id); + sb.Append(targetMessage.ForwardFrom.Id); sb.Append("`\n🌐 Language: `"); - sb.Append(update.Message.ReplyToMessage.ForwardFrom.LanguageCode); + sb.Append(targetMessage.ForwardFrom.LanguageCode); sb.Append("`\n⌚ Forward Time: `"); - sb.Append(update.Message.ReplyToMessage.ForwardDate.ToString()); + sb.Append(targetMessage.ForwardDate.ToString()); sb.Append("`\n🆔 Message ID: `"); - sb.Append(update.Message.ReplyToMessage.MessageId); + sb.Append(targetMessage.MessageId); sb.Append("`"); sb.Append("\n\n➕ *Additional Info*"); - sb.Append("\n📼 Message Type: " + update.Message.ReplyToMessage.Type.ToString()); - if (update.Message.ReplyToMessage.Document != null) + sb.Append("\n📼 Message Type: " + targetMessage.Type.ToString()); + if (targetMessage.Document != null) { sb.Append("\n📛 File Name: `"); - sb.Append(update.Message.ReplyToMessage.Document.FileName); + sb.Append(targetMessage.Document.FileName); sb.Append("`\n📄 File ID: `"); - sb.Append(update.Message.ReplyToMessage.Document.FileId); + sb.Append(targetMessage.Document.FileId); sb.Append("`\n🗜 File Size: `"); - sb.Append(update.Message.ReplyToMessage.Document.FileSize); + sb.Append(targetMessage.Document.FileSize); sb.Append("`\n📖 MIME Type: `"); - sb.Append(update.Message.ReplyToMessage.Document.MimeType); + sb.Append(targetMessage.Document.MimeType); sb.Append("`"); } - else if (update.Message.ReplyToMessage.Location != null) + else if (targetMessage.Location != null) { sb.Append("\n🌐 Latitude: `"); - sb.Append(update.Message.ReplyToMessage.Location.Latitude); + sb.Append(targetMessage.Location.Latitude); sb.Append("`\n🌐 Longitude: `"); - sb.Append(update.Message.ReplyToMessage.Location.Longitude); + sb.Append(targetMessage.Location.Longitude); sb.Append("`"); } - else if (update.Message.ReplyToMessage.Sticker != null) + else if (targetMessage.Sticker != null) { sb.Append("\n😶 Emoji: `"); - sb.Append(update.Message.ReplyToMessage.Sticker.Emoji); + sb.Append(targetMessage.Sticker.Emoji); sb.Append("`\n📄 File ID: `"); - sb.Append(update.Message.ReplyToMessage.Sticker.FileId); + sb.Append(targetMessage.Sticker.FileId); sb.Append("`"); } - else if (update.Message.ReplyToMessage.Audio != null) + else if (targetMessage.Audio != null) { sb.Append("\n📄 File ID: `"); - sb.Append(update.Message.ReplyToMessage.Audio.FileId); + sb.Append(targetMessage.Audio.FileId); sb.Append("`\n🗜 File Size: `"); - sb.Append(update.Message.ReplyToMessage.Audio.FileSize); + sb.Append(targetMessage.Audio.FileSize); sb.Append("`\n📖 MIME Type: `"); - sb.Append(update.Message.ReplyToMessage.Audio.MimeType); + sb.Append(targetMessage.Audio.MimeType); sb.Append("`\n⏳ Duration(secs): `"); - sb.Append(update.Message.ReplyToMessage.Audio.Duration); + sb.Append(targetMessage.Audio.Duration); sb.Append("`"); } - else if (update.Message.ReplyToMessage.Photo != null) + else if (targetMessage.Photo != null) { sb.Append("\n📄 File ID: `"); - sb.Append(update.Message.ReplyToMessage.Photo[0].FileId); + sb.Append(targetMessage.Photo[0].FileId); sb.Append("`\n🗜 File Size: `"); - sb.Append(update.Message.ReplyToMessage.Photo[0].FileSize); + sb.Append(targetMessage.Photo[0].FileSize); sb.Append("`"); } - sb.Append("\n\n_Additional information is available for a limited set of message types, including: Audios, Documents(Files), Locations, Photos and Stickers._"); + else if (targetMessage.Dice != null) + { + sb.Append("\n🎲 Dice/Dart: `"); + sb.Append(targetMessage.Dice.Value); + sb.Append("`"); + } + sb.Append("\n\n_Additional information is available for a limited set of message types, including: Audios, Documents(Files), Dices, Locations, Photos and Stickers._"); _ = await botClient.SendTextMessageAsync( update.Message.From.Id, diff --git a/pmcenter/BotCommands/PardonCommand.cs b/pmcenter/BotCommands/PardonCommand.cs index 93a4a05..0b0d55b 100644 --- a/pmcenter/BotCommands/PardonCommand.cs +++ b/pmcenter/BotCommands/PardonCommand.cs @@ -6,7 +6,7 @@ namespace pmcenter.Commands { - internal class PardonCommand : ICommand + internal class PardonCommand : IBotCommand { public bool OwnerOnly => true; diff --git a/pmcenter/BotCommands/PardonIdCommand.cs b/pmcenter/BotCommands/PardonIdCommand.cs index 52a13d4..c5639d0 100644 --- a/pmcenter/BotCommands/PardonIdCommand.cs +++ b/pmcenter/BotCommands/PardonIdCommand.cs @@ -7,7 +7,7 @@ namespace pmcenter.Commands { - internal class PardonIdCommand : ICommand + internal class PardonIdCommand : IBotCommand { public bool OwnerOnly => true; diff --git a/pmcenter/BotCommands/PerformCommand.cs b/pmcenter/BotCommands/PerformCommand.cs index da867e9..bd1fc9a 100644 --- a/pmcenter/BotCommands/PerformCommand.cs +++ b/pmcenter/BotCommands/PerformCommand.cs @@ -1,5 +1,4 @@ -using System; -using System.Threading; +using System.Threading; using System.Threading.Tasks; using Telegram.Bot; using Telegram.Bot.Types; @@ -7,7 +6,7 @@ namespace pmcenter.Commands { - internal class PerformCommand : ICommand + internal class PerformCommand : IBotCommand { public bool OwnerOnly => true; @@ -22,8 +21,8 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) false, Vars.CurrentConf.DisableNotifications, update.Message.MessageId).ConfigureAwait(false); - var PerformanceChecker = new Thread(() => Methods.ThrPerform()); - PerformanceChecker.Start(); + var performanceChecker = new Thread(() => Methods.ThrPerform()); + performanceChecker.Start(); Thread.Sleep(1000); Vars.IsPerformanceTestEndRequested = true; while (Vars.IsPerformanceTestExecuting) diff --git a/pmcenter/BotCommands/PingCommand.cs b/pmcenter/BotCommands/PingCommand.cs index 4031c99..e665982 100644 --- a/pmcenter/BotCommands/PingCommand.cs +++ b/pmcenter/BotCommands/PingCommand.cs @@ -5,7 +5,7 @@ namespace pmcenter.Commands { - internal class PingCommand : ICommand + internal class PingCommand : IBotCommand { public bool OwnerOnly => true; diff --git a/pmcenter/BotCommands/ReadConfigCommand.cs b/pmcenter/BotCommands/ReadConfigCommand.cs index a2d1e9d..3b1746b 100644 --- a/pmcenter/BotCommands/ReadConfigCommand.cs +++ b/pmcenter/BotCommands/ReadConfigCommand.cs @@ -2,10 +2,11 @@ using Telegram.Bot; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; +using static pmcenter.Methods.Logging; namespace pmcenter.Commands { - internal class ReadConfigCommand : ICommand + internal class ReadConfigCommand : IBotCommand { public bool OwnerOnly => true; @@ -15,6 +16,7 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) { _ = await Conf.ReadConf().ConfigureAwait(false); _ = await Lang.ReadLang().ConfigureAwait(false); + Log("Configurations and locale files have been reloaded from disk", "BOT"); _ = await botClient.SendTextMessageAsync( update.Message.From.Id, Vars.CurrentLang.Message_ConfigReloaded, diff --git a/pmcenter/BotCommands/ResetConfCommand.cs b/pmcenter/BotCommands/ResetConfCommand.cs index d8ed91c..f668342 100644 --- a/pmcenter/BotCommands/ResetConfCommand.cs +++ b/pmcenter/BotCommands/ResetConfCommand.cs @@ -1,5 +1,4 @@ -using System; -using System.Threading; +using System.Threading; using System.Threading.Tasks; using Telegram.Bot; using Telegram.Bot.Types; @@ -7,7 +6,7 @@ namespace pmcenter.Commands { - internal class ResetConfCommand : ICommand + internal class ResetConfCommand : IBotCommand { public bool OwnerOnly => true; @@ -24,11 +23,13 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) false, Vars.CurrentConf.DisableNotifications, update.Message.MessageId).ConfigureAwait(false); - var OwnerID = Vars.CurrentConf.OwnerUID; - var APIKey = Vars.CurrentConf.APIKey; - Vars.CurrentConf = new Conf.ConfObj(); - Vars.CurrentConf.OwnerUID = OwnerID; - Vars.CurrentConf.APIKey = APIKey; + var ownerId = Vars.CurrentConf.OwnerUID; + var apiKey = Vars.CurrentConf.APIKey; + Vars.CurrentConf = new Conf.ConfObj + { + OwnerUID = ownerId, + APIKey = apiKey + }; _ = await Conf.SaveConf(false, true).ConfigureAwait(false); Vars.CurrentLang = new Lang.Language(); _ = await Lang.SaveLang().ConfigureAwait(false); @@ -39,7 +40,7 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) false, Vars.CurrentConf.DisableNotifications, update.Message.MessageId).ConfigureAwait(false); - Methods.ExitApp(0); + await Methods.ExitApp(0); return true; } else diff --git a/pmcenter/BotCommands/RestartCommand.cs b/pmcenter/BotCommands/RestartCommand.cs index 9ee97a5..3005a3c 100644 --- a/pmcenter/BotCommands/RestartCommand.cs +++ b/pmcenter/BotCommands/RestartCommand.cs @@ -1,5 +1,4 @@ -using System; -using System.Threading; +using System.Threading; using System.Threading.Tasks; using Telegram.Bot; using Telegram.Bot.Types; @@ -7,7 +6,7 @@ namespace pmcenter.Commands { - internal class RestartCommand : ICommand + internal class RestartCommand : IBotCommand { public bool OwnerOnly => true; @@ -23,7 +22,7 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) Vars.CurrentConf.DisableNotifications, update.Message.MessageId).ConfigureAwait(false); Thread.Sleep(5000); - Methods.ExitApp(0); + await Methods.ExitApp(0); return true; } } diff --git a/pmcenter/BotCommands/RetractCommand.cs b/pmcenter/BotCommands/RetractCommand.cs index b746b44..6394dcf 100644 --- a/pmcenter/BotCommands/RetractCommand.cs +++ b/pmcenter/BotCommands/RetractCommand.cs @@ -2,10 +2,12 @@ using Telegram.Bot; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; +using static pmcenter.Methods; +using static pmcenter.Methods.Logging; namespace pmcenter.Commands { - internal class RetractCommand : ICommand + internal class RetractCommand : IBotCommand { public bool OwnerOnly => false; @@ -17,13 +19,15 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) { return false; } - var SelectedMsgID = update.Message.ReplyToMessage.MessageId; + var selectedMsgId = update.Message.ReplyToMessage.MessageId; + Log($"Retracting message for user {update.Message.From.Id}", "BOT"); if (update.Message.From.Id == Vars.CurrentConf.OwnerUID) { // owner retracting - if (Methods.IsOwnerRetractionAvailable(SelectedMsgID)) + if (IsOwnerRetractionAvailable(selectedMsgId)) { - Conf.MessageIDLink Link = Methods.GetLinkByOwnerMsgID(SelectedMsgID); - await botClient.DeleteMessageAsync(Link.TGUser.Id, Link.UserSessionMessageID).ConfigureAwait(false); + var link = GetLinkByOwnerMsgID(selectedMsgId); + await botClient.DeleteMessageAsync(link.TGUser.Id, link.UserSessionMessageID).ConfigureAwait(false); + Log($"Successfully retracted message from {GetComposedUsername(link.TGUser, true, true)}.", "BOT"); } else { @@ -38,10 +42,13 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) } else // user retracting { - if (Methods.IsUserRetractionAvailable(SelectedMsgID)) + if (IsUserRetractionAvailable(selectedMsgId)) { - Conf.MessageIDLink Link = Methods.GetLinkByUserMsgID(SelectedMsgID); - await botClient.DeleteMessageAsync(Vars.CurrentConf.OwnerUID, Link.OwnerSessionMessageID).ConfigureAwait(false); + var link = GetLinkByUserMsgID(selectedMsgId); + await botClient.DeleteMessageAsync(Vars.CurrentConf.OwnerUID, link.OwnerSessionMessageID).ConfigureAwait(false); + Log($"Successfully retracted message from owner.", "BOT"); + if (Vars.CurrentConf.EnableActions && link.OwnerSessionActionMessageID != -1) + await botClient.DeleteMessageAsync(Vars.CurrentConf.OwnerUID, link.OwnerSessionActionMessageID).ConfigureAwait(false); } else { diff --git a/pmcenter/BotCommands/SaveConfigCommand.cs b/pmcenter/BotCommands/SaveConfigCommand.cs index 9277cc3..3e059f5 100644 --- a/pmcenter/BotCommands/SaveConfigCommand.cs +++ b/pmcenter/BotCommands/SaveConfigCommand.cs @@ -5,7 +5,7 @@ namespace pmcenter.Commands { - internal class SaveConfigCommand : ICommand + internal class SaveConfigCommand : IBotCommand { public bool OwnerOnly => true; diff --git a/pmcenter/BotCommands/StartCommand.cs b/pmcenter/BotCommands/StartCommand.cs index 715cbb6..d5ef96f 100644 --- a/pmcenter/BotCommands/StartCommand.cs +++ b/pmcenter/BotCommands/StartCommand.cs @@ -5,7 +5,7 @@ namespace pmcenter.Commands { - internal class StartCommand : ICommand + internal class StartCommand : IBotCommand { public bool OwnerOnly => false; diff --git a/pmcenter/BotCommands/StatusCommand.cs b/pmcenter/BotCommands/StatusCommand.cs index 8d2462d..aa8b3a9 100644 --- a/pmcenter/BotCommands/StatusCommand.cs +++ b/pmcenter/BotCommands/StatusCommand.cs @@ -8,7 +8,7 @@ namespace pmcenter.Commands { - internal class StatusCommand : ICommand + internal class StatusCommand : IBotCommand { public bool OwnerOnly => true; @@ -16,27 +16,27 @@ internal class StatusCommand : ICommand public async Task ExecuteAsync(TelegramBotClient botClient, Update update) { - var MessageStr = Vars.CurrentLang.Message_SysStatus_Header + "\n\n"; + var messageStr = Vars.CurrentLang.Message_SysStatus_Header + "\n\n"; // process other headers - var NoActionRequired = true; + var noActionRequired = true; if (Vars.UpdatePending) { - MessageStr += Vars.CurrentLang.Message_SysStatus_PendingUpdate.Replace("$1", Vars.UpdateVersion.ToString()) + "\n"; - MessageStr += GetUpdateLevel(Vars.UpdateLevel) + "\n"; - NoActionRequired = false; + messageStr += Vars.CurrentLang.Message_SysStatus_PendingUpdate.Replace("$1", Vars.UpdateVersion.ToString()) + "\n"; + messageStr += GetUpdateLevel(Vars.UpdateLevel) + "\n"; + noActionRequired = false; } if (Vars.NonEmergRestartRequired) { - MessageStr += Vars.CurrentLang.Message_SysStatus_RestartRequired + "\n"; - NoActionRequired = false; + messageStr += Vars.CurrentLang.Message_SysStatus_RestartRequired + "\n"; + noActionRequired = false; } - if (NoActionRequired) + if (noActionRequired) { - MessageStr += Vars.CurrentLang.Message_SysStatus_NoOperationRequired + "\n"; + messageStr += Vars.CurrentLang.Message_SysStatus_NoOperationRequired + "\n"; } - MessageStr += "\n"; + messageStr += "\n"; // process summary - MessageStr += Vars.CurrentLang.Message_SysStatus_Summary + messageStr += Vars.CurrentLang.Message_SysStatus_Summary .Replace("$1", Environment.MachineName) .Replace("$2", Environment.OSVersion.ToString()) .Replace("$3", RuntimeInformation.OSDescription) @@ -56,7 +56,7 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) _ = await botClient.SendTextMessageAsync( update.Message.From.Id, - MessageStr, + messageStr, ParseMode.Markdown, false, Vars.CurrentConf.DisableNotifications, diff --git a/pmcenter/BotCommands/StopChat.cs b/pmcenter/BotCommands/StopChat.cs index a7c19e3..63b7df6 100644 --- a/pmcenter/BotCommands/StopChat.cs +++ b/pmcenter/BotCommands/StopChat.cs @@ -2,11 +2,11 @@ using Telegram.Bot; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; -using static pmcenter.Methods; +using static pmcenter.Methods.Logging; namespace pmcenter.Commands { - internal class StopChatCommand : ICommand + internal class StopChatCommand : IBotCommand { public bool OwnerOnly => true; diff --git a/pmcenter/BotCommands/SwitchBwCommand.cs b/pmcenter/BotCommands/SwitchBwCommand.cs index e0b306f..07d8397 100644 --- a/pmcenter/BotCommands/SwitchBwCommand.cs +++ b/pmcenter/BotCommands/SwitchBwCommand.cs @@ -5,7 +5,7 @@ namespace pmcenter.Commands { - internal class SwitchBwCommand : ICommand + internal class SwitchBwCommand : IBotCommand { public bool OwnerOnly => true; @@ -13,11 +13,11 @@ internal class SwitchBwCommand : ICommand public async Task ExecuteAsync(TelegramBotClient botClient, Update update) { - var IsEnabledNow = Conf.SwitchBlocking(); + var isEnabledNow = Conf.SwitchBlocking(); _ = await Conf.SaveConf(false, true).ConfigureAwait(false); _ = await botClient.SendTextMessageAsync( update.Message.From.Id, - IsEnabledNow ? + isEnabledNow ? Vars.CurrentLang.Message_MessageBlockEnabled : Vars.CurrentLang.Message_MessageBlockDisabled, ParseMode.Markdown, diff --git a/pmcenter/BotCommands/SwitchFwCommand.cs b/pmcenter/BotCommands/SwitchFwCommand.cs index e9e34ba..e71254c 100644 --- a/pmcenter/BotCommands/SwitchFwCommand.cs +++ b/pmcenter/BotCommands/SwitchFwCommand.cs @@ -5,7 +5,7 @@ namespace pmcenter.Commands { - internal class SwitchFwCommand : ICommand + internal class SwitchFwCommand : IBotCommand { public bool OwnerOnly => true; @@ -13,10 +13,10 @@ internal class SwitchFwCommand : ICommand public async Task ExecuteAsync(TelegramBotClient botClient, Update update) { - var IsPausedNow = Conf.SwitchPaused(); + var isPausedNow = Conf.SwitchPaused(); _ = await Conf.SaveConf(false, true).ConfigureAwait(false); _ = await botClient.SendTextMessageAsync(update.Message.From.Id, - IsPausedNow ? + isPausedNow ? Vars.CurrentLang.Message_ServicePaused : Vars.CurrentLang.Message_ServiceResumed, ParseMode.Markdown, diff --git a/pmcenter/BotCommands/SwitchLangCodeCommand.cs b/pmcenter/BotCommands/SwitchLangCodeCommand.cs index 1859df8..3814dd2 100644 --- a/pmcenter/BotCommands/SwitchLangCodeCommand.cs +++ b/pmcenter/BotCommands/SwitchLangCodeCommand.cs @@ -1,15 +1,15 @@ using Newtonsoft.Json; using System; using System.IO; -using System.Net; using System.Threading.Tasks; using Telegram.Bot; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; +using static pmcenter.Methods.H2Helper; namespace pmcenter.Commands { - internal class SwitchLangCodeCommand : ICommand + internal class SwitchLangCodeCommand : IBotCommand { public bool OwnerOnly => true; @@ -17,45 +17,43 @@ internal class SwitchLangCodeCommand : ICommand public async Task ExecuteAsync(TelegramBotClient botClient, Update update) { - string Reply; - string ListJSONString; + string reply; + string listJsonString; + Conf.LocaleList localeList; // try to get locale list - using (var ListDownloader = new WebClient()) - { - ListJSONString = await ListDownloader.DownloadStringTaskAsync(Vars.LocaleMapURL.Replace("$channel", Vars.CurrentConf.UpdateChannel)).ConfigureAwait(false); - } - Conf.LocaleList LocaleList = JsonConvert.DeserializeObject(ListJSONString); + listJsonString = await GetStringAsync(new Uri(Vars.LocaleMapURL.Replace("$channel", Vars.CurrentConf.UpdateChannel))).ConfigureAwait(false); + localeList = JsonConvert.DeserializeObject(listJsonString); if (!update.Message.Text.Contains(" ")) { - var ListString = ""; - foreach (Conf.LocaleMirror Mirror in LocaleList.Locales) + var listString = ""; + foreach (var mirror in localeList.Locales) { - ListString += $"{Mirror.LocaleCode} - {Mirror.LocaleNameNative} ({Mirror.LocaleNameEng})\n"; + listString += $"{mirror.LocaleCode} - {mirror.LocaleNameNative} ({mirror.LocaleNameEng})\n"; } - Reply = Vars.CurrentLang.Message_AvailableLang.Replace("$1", ListString); + reply = Vars.CurrentLang.Message_AvailableLang.Replace("$1", listString); } else { - var TargetCode = update.Message.Text.Split(" ")[1]; - foreach (Conf.LocaleMirror Mirror in LocaleList.Locales) + var targetCode = update.Message.Text.Split(" ")[1]; + foreach (var mirror in localeList.Locales) { - if (Mirror.LocaleCode == TargetCode) + if (mirror.LocaleCode == targetCode) { // update configurations - Vars.CurrentConf.LangURL = Mirror.LocaleFileURL.Replace("$channel", Vars.CompileChannel); + Vars.CurrentConf.LangURL = mirror.LocaleFileURL.Replace("$channel", Vars.CompileChannel); // start downloading - using (var Downloader = new WebClient()) - { - _ = await Conf.SaveConf(IsAutoSave: true).ConfigureAwait(false); - await Downloader.DownloadFileTaskAsync( - new Uri(Vars.CurrentConf.LangURL), - Path.Combine(Vars.AppDirectory, "pmcenter_locale.json") - ).ConfigureAwait(false); - } + _ = await Conf.SaveConf(isAutoSave: true).ConfigureAwait(false); + await DownloadFileAsync( + new Uri(Vars.CurrentConf.LangURL), + Path.Combine( + Vars.AppDirectory, + "pmcenter_locale.json" + ) + ).ConfigureAwait(false); // reload configurations _ = await Conf.ReadConf().ConfigureAwait(false); _ = await Lang.ReadLang().ConfigureAwait(false); - Reply = Vars.CurrentLang.Message_LangSwitched; + reply = Vars.CurrentLang.Message_LangSwitched; goto SendMsg; } } @@ -64,7 +62,7 @@ await Downloader.DownloadFileTaskAsync( SendMsg: _ = await botClient.SendTextMessageAsync( update.Message.From.Id, - Reply, + reply, ParseMode.Markdown, false, Vars.CurrentConf.DisableNotifications, diff --git a/pmcenter/BotCommands/SwitchLangCommand.cs b/pmcenter/BotCommands/SwitchLangCommand.cs index 860a582..0bd525b 100644 --- a/pmcenter/BotCommands/SwitchLangCommand.cs +++ b/pmcenter/BotCommands/SwitchLangCommand.cs @@ -1,15 +1,14 @@ using System; using System.IO; -using System.Net; using System.Threading.Tasks; using Telegram.Bot; using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; -using static pmcenter.Methods; +using static pmcenter.Methods.H2Helper; namespace pmcenter.Commands { - internal class SwitchLangCommand : ICommand + internal class SwitchLangCommand : IBotCommand { public bool OwnerOnly => true; @@ -28,17 +27,14 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) update.Message.MessageId).ConfigureAwait(false); // download file - var LangURL = update.Message.Text.Split(" ")[1]; - Vars.CurrentConf.LangURL = LangURL; + var langUrl = update.Message.Text.Split(" ")[1]; + Vars.CurrentConf.LangURL = langUrl; // save conf - _ = await Conf.SaveConf(IsAutoSave: true); - using (var Downloader = new WebClient()) - { - await Downloader.DownloadFileTaskAsync( - new Uri(LangURL), + _ = await Conf.SaveConf(isAutoSave: true); + await DownloadFileAsync( + new Uri(langUrl), Path.Combine(Vars.AppDirectory, "pmcenter_locale.json") - ).ConfigureAwait(false); - } + ).ConfigureAwait(false); // reload configurations _ = await Conf.ReadConf().ConfigureAwait(false); diff --git a/pmcenter/BotCommands/SwitchNotificationCommand.cs b/pmcenter/BotCommands/SwitchNotificationCommand.cs index 7a42d62..c5b4fc0 100644 --- a/pmcenter/BotCommands/SwitchNotificationCommand.cs +++ b/pmcenter/BotCommands/SwitchNotificationCommand.cs @@ -5,7 +5,7 @@ namespace pmcenter.Commands { - internal class SwitchNotificationCommand : ICommand + internal class SwitchNotificationCommand : IBotCommand { public bool OwnerOnly => true; @@ -13,10 +13,10 @@ internal class SwitchNotificationCommand : ICommand public async Task ExecuteAsync(TelegramBotClient botClient, Update update) { - var IsDisabledNow = Conf.SwitchNotifications(); + var isDisabledNow = Conf.SwitchNotifications(); _ = await Conf.SaveConf(false, true).ConfigureAwait(false); _ = await botClient.SendTextMessageAsync(update.Message.From.Id, - IsDisabledNow ? + isDisabledNow ? Vars.CurrentLang.Message_NotificationsOff : Vars.CurrentLang.Message_NotificationsOn, ParseMode.Markdown, diff --git a/pmcenter/BotCommands/TestNetwork.cs b/pmcenter/BotCommands/TestNetwork.cs index db68663..bcd6931 100644 --- a/pmcenter/BotCommands/TestNetwork.cs +++ b/pmcenter/BotCommands/TestNetwork.cs @@ -4,10 +4,11 @@ using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; using static pmcenter.Methods; +using static pmcenter.Methods.Logging; namespace pmcenter.Commands { - internal class TestNetworkCommand : ICommand + internal class TestNetworkCommand : IBotCommand { public bool OwnerOnly => true; @@ -16,14 +17,14 @@ internal class TestNetworkCommand : ICommand public async Task ExecuteAsync(TelegramBotClient botClient, Update update) { Log("Starting network test...", "BOT"); - var LatencyToGH = Math.Round((await TestLatency("https://github.com").ConfigureAwait(false)).TotalMilliseconds, 2); - var LatencyToTG = Math.Round((await TestLatency("https://api.telegram.org/bot").ConfigureAwait(false)).TotalMilliseconds, 2); - var LatencyToCI = Math.Round((await TestLatency("https://ci.appveyor.com").ConfigureAwait(false)).TotalMilliseconds, 2); + var latencyToGh = Math.Round((await TestLatency("https://github.com").ConfigureAwait(false)).TotalMilliseconds, 2); + var latencyToTg = Math.Round((await TestLatency("https://api.telegram.org/bot").ConfigureAwait(false)).TotalMilliseconds, 2); + var latencyToCi = Math.Round((await TestLatency("https://ci.appveyor.com").ConfigureAwait(false)).TotalMilliseconds, 2); _ = await botClient.SendTextMessageAsync(update.Message.From.Id, Vars.CurrentLang.Message_Connectivity - .Replace("$1", LatencyToGH + "ms") - .Replace("$2", LatencyToTG + "ms") - .Replace("$3", LatencyToCI + "ms"), + .Replace("$1", latencyToGh + "ms") + .Replace("$2", latencyToTg + "ms") + .Replace("$3", latencyToCi + "ms"), ParseMode.Markdown, false, Vars.CurrentConf.DisableNotifications, diff --git a/pmcenter/BotCommands/UpdateCommand.cs b/pmcenter/BotCommands/UpdateCommand.cs index d9a5f12..357c2db 100644 --- a/pmcenter/BotCommands/UpdateCommand.cs +++ b/pmcenter/BotCommands/UpdateCommand.cs @@ -1,40 +1,39 @@ using System; -using System.IO; -using System.IO.Compression; -using System.Net; using System.Threading.Tasks; using Telegram.Bot; -using Telegram.Bot.Types; using Telegram.Bot.Types.Enums; using static pmcenter.Methods; +using static pmcenter.Methods.Logging; +using static pmcenter.Methods.UpdateHelper; namespace pmcenter.Commands { - internal class UpdateCommand : ICommand + internal class UpdateCommand : IBotCommand { public bool OwnerOnly => true; public string Prefix => "update"; - public async Task ExecuteAsync(TelegramBotClient botClient, Update update) + public async Task ExecuteAsync(TelegramBotClient botClient, Telegram.Bot.Types.Update update) { try { - var Latest = Conf.CheckForUpdates(); - var CurrentLocalizedIndex = Conf.GetUpdateInfoIndexByLocale(Latest, Vars.CurrentLang.LangCode); - if (Conf.IsNewerVersionAvailable(Latest)) + var latest = await CheckForUpdatesAsync().ConfigureAwait(false); + var currentLocalizedIndex = GetUpdateInfoIndexByLocale(latest, Vars.CurrentLang.LangCode); + if (IsNewerVersionAvailable(latest)) { - var UpdateString = Vars.CurrentLang.Message_UpdateAvailable - .Replace("$1", Latest.Latest) - .Replace("$2", Latest.UpdateCollection[CurrentLocalizedIndex].Details) - .Replace("$3", Methods.GetUpdateLevel(Latest.UpdateLevel)); + var updateString = Vars.CurrentLang.Message_UpdateAvailable + .Replace("$1", latest.Latest) + .Replace("$2", latest.UpdateCollection[currentLocalizedIndex].Details) + .Replace("$3", GetUpdateLevel(latest.UpdateLevel)); + // \ update available! / _ = await botClient.SendTextMessageAsync( update.Message.From.Id, - UpdateString, ParseMode.Markdown, + updateString, ParseMode.Markdown, false, Vars.CurrentConf.DisableNotifications, update.Message.MessageId).ConfigureAwait(false); - // where difference begins + // \ updating! / _ = await botClient.SendTextMessageAsync( update.Message.From.Id, Vars.CurrentLang.Message_UpdateProcessing, @@ -43,33 +42,11 @@ public async Task ExecuteAsync(TelegramBotClient botClient, Update update) Vars.CurrentConf.DisableNotifications, update.Message.MessageId).ConfigureAwait(false); // download compiled package - Log("Starting update download... (pmcenter_update.zip)", "BOT"); - Log($"From address: {Latest.UpdateCollection[CurrentLocalizedIndex].UpdateArchiveAddress}", "BOT"); - using (var Downloader = new WebClient()) - { - await Downloader.DownloadFileTaskAsync( - new Uri(Latest.UpdateCollection[CurrentLocalizedIndex].UpdateArchiveAddress), - Path.Combine(Vars.AppDirectory, "pmcenter_update.zip")).ConfigureAwait(false); - Log("Download complete. Extracting...", "BOT"); - using (ZipArchive Zip = ZipFile.OpenRead(Path.Combine(Vars.AppDirectory, "pmcenter_update.zip"))) - { - foreach (ZipArchiveEntry Entry in Zip.Entries) - { - Log($"Extracting: {Path.Combine(Vars.AppDirectory, Entry.FullName)}", "BOT"); - Entry.ExtractToFile(Path.Combine(Vars.AppDirectory, Entry.FullName), true); - } - } - if (Vars.CurrentConf.AutoLangUpdate) - { - Log("Starting automatic language file update...", "BOT"); - await Downloader.DownloadFileTaskAsync( - new Uri(Vars.CurrentConf.LangURL), - Path.Combine(Vars.AppDirectory, "pmcenter_locale.json") - ).ConfigureAwait(false); - } - } - Log("Cleaning up temporary files...", "BOT"); - System.IO.File.Delete(Path.Combine(Vars.AppDirectory, "pmcenter_update.zip")); + await DownloadUpdatesAsync(latest, currentLocalizedIndex).ConfigureAwait(false); + // update languages + if (Vars.CurrentConf.AutoLangUpdate) await DownloadLangAsync().ConfigureAwait(false); + + // \ see you! / _ = await botClient.SendTextMessageAsync( update.Message.From.Id, Vars.CurrentLang.Message_UpdateFinalizing, @@ -78,7 +55,7 @@ await Downloader.DownloadFileTaskAsync( Vars.CurrentConf.DisableNotifications, update.Message.MessageId).ConfigureAwait(false); Log("Exiting program... (Let the daemon do the restart job)", "BOT"); - ExitApp(0); + await ExitApp(0); return true; // end of difference } @@ -87,9 +64,9 @@ await Downloader.DownloadFileTaskAsync( _ = await botClient.SendTextMessageAsync( update.Message.From.Id, Vars.CurrentLang.Message_AlreadyUpToDate - .Replace("$1", Latest.Latest) + .Replace("$1", latest.Latest) .Replace("$2", Vars.AppVer.ToString()) - .Replace("$3", Latest.UpdateCollection[CurrentLocalizedIndex].Details), + .Replace("$3", latest.UpdateCollection[currentLocalizedIndex].Details), ParseMode.Markdown, false, Vars.CurrentConf.DisableNotifications, @@ -99,10 +76,10 @@ await Downloader.DownloadFileTaskAsync( } catch (Exception ex) { - string ErrorString = Vars.CurrentLang.Message_UpdateCheckFailed.Replace("$1", ex.ToString()); + string errorString = Vars.CurrentLang.Message_UpdateCheckFailed.Replace("$1", ex.ToString()); _ = await botClient.SendTextMessageAsync( update.Message.From.Id, - ErrorString, + errorString, ParseMode.Markdown, false, Vars.CurrentConf.DisableNotifications, diff --git a/pmcenter/BotCommands/UptimeCommand.cs b/pmcenter/BotCommands/UptimeCommand.cs index dd4aa67..9281da0 100644 --- a/pmcenter/BotCommands/UptimeCommand.cs +++ b/pmcenter/BotCommands/UptimeCommand.cs @@ -6,7 +6,7 @@ namespace pmcenter.Commands { - internal class UptimeCommand : ICommand + internal class UptimeCommand : IBotCommand { public bool OwnerOnly => true; @@ -14,13 +14,13 @@ internal class UptimeCommand : ICommand public async Task ExecuteAsync(TelegramBotClient botClient, Update update) { - var UptimeString = + var uptimeString = Vars.CurrentLang.Message_UptimeInfo .Replace("$1", (new TimeSpan(0, 0, 0, 0, Environment.TickCount)).ToString()) .Replace("$2", Vars.StartSW.Elapsed.ToString()); _ = await botClient.SendTextMessageAsync( update.Message.From.Id, - UptimeString, + uptimeString, ParseMode.Markdown, false, Vars.CurrentConf.DisableNotifications, diff --git a/pmcenter/BotProcess.cs b/pmcenter/BotProcess.cs deleted file mode 100644 index b335840..0000000 --- a/pmcenter/BotProcess.cs +++ /dev/null @@ -1,370 +0,0 @@ -/* -// BotProcess.cs / pmcenter project / https://github.com/Elepover/pmcenter -// Main processing logic of pmcenter. -// Copyright (C) The pmcenter authors. Licensed under the Apache License (Version 2.0). -*/ - -using pmcenter.Commands; -using System; -using System.Threading.Tasks; -using Telegram.Bot.Args; -using Telegram.Bot.Types; -using Telegram.Bot.Types.Enums; -using static pmcenter.Methods; - -namespace pmcenter -{ - public static class BotProcess - { - private static readonly CommandRouter commandManager = new CommandRouter(); - - static BotProcess() - { - commandManager.RegisterCommand(new StartCommand()); - commandManager.RegisterCommand(new HelpCommand()); - - commandManager.RegisterCommand(new InfoCommand()); - commandManager.RegisterCommand(new BanCommand()); - commandManager.RegisterCommand(new PardonCommand()); - - commandManager.RegisterCommand(new BackupConfCommand()); - commandManager.RegisterCommand(new BanIdCommand()); - commandManager.RegisterCommand(new CatConfigCommand()); - commandManager.RegisterCommand(new ChatCommand()); - commandManager.RegisterCommand(new CheckUpdateCommand()); - commandManager.RegisterCommand(new ClearMessageLinksCommand()); - commandManager.RegisterCommand(new DetectPermissionCommand()); - commandManager.RegisterCommand(new DonateCommand()); - commandManager.RegisterCommand(new EditConfCommand()); - commandManager.RegisterCommand(new GetStatsCommand()); - commandManager.RegisterCommand(new PardonIdCommand()); - commandManager.RegisterCommand(new PerformCommand()); - commandManager.RegisterCommand(new PingCommand()); - commandManager.RegisterCommand(new ReadConfigCommand()); - commandManager.RegisterCommand(new ResetConfCommand()); - commandManager.RegisterCommand(new RestartCommand()); - commandManager.RegisterCommand(new RetractCommand()); - commandManager.RegisterCommand(new SaveConfigCommand()); - commandManager.RegisterCommand(new StatusCommand()); - commandManager.RegisterCommand(new StopChatCommand()); - commandManager.RegisterCommand(new SwitchBwCommand()); - commandManager.RegisterCommand(new SwitchFwCommand()); - commandManager.RegisterCommand(new SwitchLangCodeCommand()); - commandManager.RegisterCommand(new SwitchLangCommand()); - commandManager.RegisterCommand(new SwitchNotificationCommand()); - commandManager.RegisterCommand(new TestNetworkCommand()); - commandManager.RegisterCommand(new UpdateCommand()); - commandManager.RegisterCommand(new UptimeCommand()); - } - - public static async void OnUpdate(object sender, UpdateEventArgs e) - { - try - { - if (e == null) return; - if (Vars.CurrentConf.DetailedMsgLogging) - { - Log($"OnUpdate() triggered: UpdType: {e.Update.Type.ToString()} UpdID: {e.Update.Id} ChatId: {e.Update.Message.Chat.Id} Username: {e.Update.Message.Chat.Username} FromID: {e.Update.Message.From.Id} FromUsername: {e.Update.Message.From.Username}", "BOT-DETAILED", LogLevel.INFO); - } - var update = e.Update; - if (update.Type != UpdateType.Message) return; - if (update.Message.From.IsBot) return; - if (update.Message.Chat.Type != ChatType.Private) return; - - if (IsBanned(update.Message.From.Id)) - { - Log($"Restricting banned user from sending messages: {update.Message.From.FirstName} (@{update.Message.From.Username} / {(long)update.Message.From.Id})", "BOT"); - return; - } - - Vars.CurrentConf.Statistics.TotalMessagesReceived += 1; - if (update.Message.From.Id == Vars.CurrentConf.OwnerUID) - { - await OwnerLogic(update).ConfigureAwait(false); - } - else - { - await UserLogic(update).ConfigureAwait(false); - } - } - catch (Exception ex) - { - Log($"General error while processing incoming update: {ex.ToString()}", "BOT", LogLevel.ERROR); - if (Vars.CurrentConf.CatchAllExceptions) - { - try - { - _ = await Vars.Bot.SendTextMessageAsync(Vars.CurrentConf.OwnerUID, - Vars.CurrentLang.Message_GeneralFailure.Replace("$1", ex.ToString()), - ParseMode.Default, - false, - Vars.CurrentConf.DisableNotifications).ConfigureAwait(false); - } - catch (Exception iEx) - { - Log($"Failed to catch exception to owner: {iEx.ToString()}", "BOT", LogLevel.ERROR); - } - } - } - } - - private static async Task UserLogic(Update update) - { - // is user - - if (await commandManager.Execute(Vars.Bot, update).ConfigureAwait(false)) - { - return; - } - - Log($"Received message from \"{update.Message.From.FirstName}\" (@{update.Message.From.Username} / {update.Message.From.Id}), forwarding...", "BOT"); - - if (Vars.CurrentConf.ForwardingPaused) - { - Log("Stopped: forwarding is currently paused.", "BOT", LogLevel.INFO); - _ = await Vars.Bot.SendTextMessageAsync(update.Message.From.Id, - Vars.CurrentLang.Message_UserServicePaused, - ParseMode.Markdown, - false, - false, - update.Message.MessageId).ConfigureAwait(false); - return; - } - - // test text blacklist - if (!string.IsNullOrEmpty(update.Message.Text) && IsKeywordBanned(update.Message.Text)) - { - Log("Stopped: sentence contains blocked words.", "BOT", LogLevel.INFO); - if (Vars.CurrentConf.KeywordAutoBan) - { - BanUser(update.Message.From.Id); - } - return; - } - - // process owner - Log("Forwarding message to owner...", "BOT"); - var ForwardedMessage = await Vars.Bot.ForwardMessageAsync(Vars.CurrentConf.OwnerUID, - update.Message.From.Id, - update.Message.MessageId, - Vars.CurrentConf.DisableNotifications).ConfigureAwait(false); - Vars.CurrentConf.Statistics.TotalForwardedToOwner += 1; - if (Vars.CurrentConf.EnableMsgLink) - { - Log($"Recording message link: owner {ForwardedMessage.MessageId} <-> user {update.Message.MessageId} user: {update.Message.From.Id}", "BOT"); - Vars.CurrentConf.MessageLinks.Add( - new Conf.MessageIDLink() - { OwnerSessionMessageID = ForwardedMessage.MessageId, UserSessionMessageID = update.Message.MessageId, TGUser = update.Message.From, IsFromOwner = false } - ); - // Conf.SaveConf(false, true); - } - // check for real message sender - // check if forwarded from channels - if (update.Message.ForwardFrom == null && update.Message.ForwardFromChat != null) - { - // is forwarded from channel - _ = await Vars.Bot.SendTextMessageAsync(Vars.CurrentConf.OwnerUID, - Vars.CurrentLang.Message_ForwarderNotReal - .Replace("$2", update.Message.From.Id.ToString()) - .Replace("$1", "[" + update.Message.From.FirstName + " " + update.Message.From.LastName + "](tg://user?id=" + update.Message.From.Id + ")"), - ParseMode.Markdown, - false, - Vars.CurrentConf.DisableNotifications, - ForwardedMessage.MessageId).ConfigureAwait(false); - } - if (update.Message.ForwardFrom != null && update.Message.ForwardFromChat == null) - { - // is forwarded from chats - if (update.Message.ForwardFrom.Id != update.Message.From.Id) - { - _ = await Vars.Bot.SendTextMessageAsync(Vars.CurrentConf.OwnerUID, - Vars.CurrentLang.Message_ForwarderNotReal - .Replace("$2", update.Message.From.Id.ToString()) - .Replace("$1", "[" + update.Message.From.FirstName + " " + update.Message.From.LastName + "](tg://user?id=" + update.Message.From.Id + ")"), - ParseMode.Markdown, - false, - Vars.CurrentConf.DisableNotifications, - ForwardedMessage.MessageId).ConfigureAwait(false); - } - } - - // process cc - if (Vars.CurrentConf.EnableCc) - { - await RunCC(update).ConfigureAwait(false); - } - if (Vars.CurrentConf.EnableForwardedConfirmation) - { - _ = await Vars.Bot.SendTextMessageAsync(update.Message.From.Id, - Vars.CurrentLang.Message_ForwardedToOwner, - ParseMode.Markdown, - false, - false, - update.Message.MessageId).ConfigureAwait(false); - } - AddRateLimit(update.Message.From.Id); - } - - private static async Task RunCC(Update update) - { - Log("Cc enabled, forwarding...", "BOT"); - foreach (long Id in Vars.CurrentConf.Cc) - { - Log($"Forwarding message to cc: {Id}", "BOT"); - try - { - var ForwardedMessageCc = await Vars.Bot.ForwardMessageAsync(Id, - update.Message.From.Id, - update.Message.MessageId, - Vars.CurrentConf.DisableNotifications).ConfigureAwait(false); - // check if forwarded from channels - if (update.Message.ForwardFrom == null && update.Message.ForwardFromChat != null) - { - // is forwarded from channel - _ = await Vars.Bot.SendTextMessageAsync(Id, - Vars.CurrentLang.Message_ForwarderNotReal - .Replace("$2", update.Message.From.Id.ToString()) - .Replace("$1", "[" + update.Message.From.FirstName + " " + update.Message.From.LastName + "](tg://user?id=" + update.Message.From.Id + ")"), - ParseMode.Markdown, - false, - Vars.CurrentConf.DisableNotifications, - ForwardedMessageCc.MessageId).ConfigureAwait(false); - } - if (update.Message.ForwardFrom != null && update.Message.ForwardFromChat == null) - { - // is forwarded from chats - // check real message sender - if (update.Message.ForwardFrom.Id != update.Message.From.Id) - { - _ = await Vars.Bot.SendTextMessageAsync(Id, - Vars.CurrentLang.Message_ForwarderNotReal - .Replace("$2", update.Message.From.Id.ToString()) - .Replace("$1", "[" + update.Message.From.FirstName + " " + update.Message.From.LastName + "](tg://user?id=" + update.Message.From.Id + ")"), - ParseMode.Markdown, - false, - Vars.CurrentConf.DisableNotifications, - ForwardedMessageCc.MessageId).ConfigureAwait(false); - } - } - } - catch (Exception ex) - { - Log($"Unable to forward message to cc: {Id}, reason: {ex.Message}", "BOT", LogLevel.ERROR); - } - } - } - - private static async Task OwnerLogic(Update update) - { - if (update.Message.ReplyToMessage != null) - { - await OwnerReplying(update).ConfigureAwait(false); - } - else - { - await OwnerCommand(update).ConfigureAwait(false); - } - } - - private static async Task OwnerCommand(Update update) - { - // The owner is not even replying. - // start or help command? - if (await commandManager.Execute(Vars.Bot, update).ConfigureAwait(false)) - { - Vars.CurrentConf.Statistics.TotalCommandsReceived += 1; - return; - } - // command mismatch - if (Vars.CurrentConf.ContChatTarget != -1) - { - // Is replying, replying to forwarded message AND not command. - var Forwarded = await Vars.Bot.ForwardMessageAsync( - Vars.CurrentConf.ContChatTarget, - update.Message.Chat.Id, - update.Message.MessageId, - Vars.CurrentConf.DisableNotifications).ConfigureAwait(false); - if (Vars.CurrentConf.EnableMsgLink) - { - Log($"Recording message link: {Forwarded.MessageId} -> {update.Message.MessageId} in {update.Message.From.Id}", "BOT"); - Vars.CurrentConf.MessageLinks.Add( - new Conf.MessageIDLink() - { OwnerSessionMessageID = Forwarded.MessageId, UserSessionMessageID = update.Message.MessageId, TGUser = update.Message.From, IsFromOwner = true } - ); - // Conf.SaveConf(false, true); - } - // Process locale. - if (Vars.CurrentConf.EnableRepliedConfirmation) - { - var ReplyToMessage = Vars.CurrentLang.Message_ReplySuccessful; - ReplyToMessage = ReplyToMessage.Replace("$1", $"[{Vars.CurrentConf.ContChatTarget}](tg://user?id={Vars.CurrentConf.ContChatTarget})"); - _ = await Vars.Bot.SendTextMessageAsync(update.Message.From.Id, ReplyToMessage, ParseMode.Markdown, false, false, update.Message.MessageId).ConfigureAwait(false); - } - Log($"Successfully passed owner's reply to UID: {Vars.CurrentConf.ContChatTarget}", "BOT"); - return; - } - - _ = await Vars.Bot.SendTextMessageAsync( - update.Message.From.Id, - Vars.CurrentLang.Message_CommandNotReplying, - ParseMode.Markdown, - false, - Vars.CurrentConf.DisableNotifications, - update.Message.MessageId).ConfigureAwait(false); - } - - private static async Task OwnerReplying(Update update) - { - // check anonymous forward (5.5.0 new feature compatibility fix) - var Link = GetLinkByOwnerMsgID(update.Message.ReplyToMessage.MessageId); - if (Link != null && !Link.IsFromOwner) - { - Log($"Selected message is forwarded anonymously from {Link.TGUser.Id}, fixing user information from database.", "BOT"); - update.Message.ReplyToMessage.ForwardFrom = Link.TGUser; - } - if (update.Message.ReplyToMessage.ForwardFrom == null && update.Message.Text.ToLower() != "/retract") - { - // The owner is replying to bot messages. (no forwardfrom) - _ = await Vars.Bot.SendTextMessageAsync( - update.Message.From.Id, - Vars.CurrentLang.Message_CommandNotReplyingValidMessage, - ParseMode.Markdown, - false, - Vars.CurrentConf.DisableNotifications, - update.Message.MessageId).ConfigureAwait(false); - return; - } - - if (await commandManager.Execute(Vars.Bot, update).ConfigureAwait(false)) - { - Vars.CurrentConf.Statistics.TotalCommandsReceived += 1; - return; - } - - // Is replying, replying to forwarded message AND not command. - var Forwarded = await Vars.Bot.ForwardMessageAsync( - update.Message.ReplyToMessage.ForwardFrom.Id, - update.Message.Chat.Id, - update.Message.MessageId, - Vars.CurrentConf.DisableNotifications).ConfigureAwait(false); - if (Vars.CurrentConf.EnableMsgLink) - { - Log($"Recording message link: user {Forwarded.MessageId} <-> owner {update.Message.MessageId}, user: {update.Message.ReplyToMessage.ForwardFrom.Id}", "BOT"); - Vars.CurrentConf.MessageLinks.Add( - new Conf.MessageIDLink() - { OwnerSessionMessageID = update.Message.MessageId, UserSessionMessageID = Forwarded.MessageId, TGUser = update.Message.ReplyToMessage.ForwardFrom, IsFromOwner = true } - ); - // Conf.SaveConf(false, true); - } - Vars.CurrentConf.Statistics.TotalForwardedFromOwner += 1; - // Process locale. - if (Vars.CurrentConf.EnableRepliedConfirmation) - { - var ReplyToMessage = Vars.CurrentLang.Message_ReplySuccessful; - ReplyToMessage = ReplyToMessage.Replace("$1", $"[{update.Message.ReplyToMessage.ForwardFrom.FirstName} (@{update.Message.ReplyToMessage.ForwardFrom.Username})](tg://user?id={update.Message.ReplyToMessage.ForwardFrom.Id})"); - _ = await Vars.Bot.SendTextMessageAsync(update.Message.From.Id, ReplyToMessage, ParseMode.Markdown, false, false, update.Message.MessageId).ConfigureAwait(false); - } - Log($"Successfully passed owner's reply to {update.Message.ReplyToMessage.ForwardFrom.FirstName} (@{update.Message.ReplyToMessage.ForwardFrom.Username} / {update.Message.ReplyToMessage.ForwardFrom.Id})", "BOT"); - } - } -} diff --git a/pmcenter/BotProcess/BotProcess.CallbackQueryRoute.cs b/pmcenter/BotProcess/BotProcess.CallbackQueryRoute.cs new file mode 100644 index 0000000..8a7a2ea --- /dev/null +++ b/pmcenter/BotProcess/BotProcess.CallbackQueryRoute.cs @@ -0,0 +1,44 @@ +using pmcenter.CallbackActions; +using System; +using System.Threading.Tasks; +using Telegram.Bot.Args; +using Telegram.Bot.Types.ReplyMarkups; +using static pmcenter.Methods; +using static pmcenter.Methods.Logging; + +namespace pmcenter +{ + public static partial class BotProcess + { + private static async Task CallbackQueryRoute(object sender, UpdateEventArgs e) + { + var update = e.Update; + if (update.CallbackQuery == null) return; + if (update.CallbackQuery.From.IsBot) return; + try + { + var link = GetLinkByOwnerMsgID(update.CallbackQuery.Message.ReplyToMessage.MessageId); + if (link == null) throw new NullReferenceException(Vars.CurrentLang.Message_Action_LinkNotFound); + var result = await CallbackProcess.DoCallback(update.CallbackQuery.Data, link.TGUser, update.CallbackQuery.Message); + // prompt result + await Vars.Bot.AnswerCallbackQueryAsync(update.CallbackQuery.Id, result.Status, result.ShowAsAlert); + // update existing buttons + if (result.Succeeded) + _ = await Vars.Bot.EditMessageReplyMarkupAsync( + update.CallbackQuery.Message.Chat.Id, + update.CallbackQuery.Message.MessageId, + new InlineKeyboardMarkup(CallbackProcess.GetAvailableButtons(update))); + } + catch (Exception ex) + { + Log($"Unable to process action {update.CallbackQuery.Data}: {ex}", "BOT", LogLevel.Error); + await Vars.Bot.AnswerCallbackQueryAsync + ( + update.CallbackQuery.Id, + Vars.CurrentLang.Message_Action_ErrorWithDetails.Replace("$1", ex.Message), + true + ); + } + } + } +} diff --git a/pmcenter/BotProcess/BotProcess.MessageRoute.cs b/pmcenter/BotProcess/BotProcess.MessageRoute.cs new file mode 100644 index 0000000..c5d2373 --- /dev/null +++ b/pmcenter/BotProcess/BotProcess.MessageRoute.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using Telegram.Bot.Args; +using Telegram.Bot.Types.Enums; + +namespace pmcenter +{ + public static partial class BotProcess + { + private static async Task MessageRoute(object sender, UpdateEventArgs e) + { + var update = e.Update; + if (update.Message == null) return; + if (update.Message.From.IsBot) return; + if (update.Message.Chat.Type != ChatType.Private) return; + + Vars.CurrentConf.Statistics.TotalMessagesReceived += 1; + if (update.Message.From.Id == Vars.CurrentConf.OwnerUID) + { + await OwnerLogic(update).ConfigureAwait(false); + } + else + { + await UserLogic(update).ConfigureAwait(false); + } + } + } +} diff --git a/pmcenter/BotProcess/BotProcess.OwnerCommand.cs b/pmcenter/BotProcess/BotProcess.OwnerCommand.cs new file mode 100644 index 0000000..73e72ed --- /dev/null +++ b/pmcenter/BotProcess/BotProcess.OwnerCommand.cs @@ -0,0 +1,57 @@ +using System.Threading.Tasks; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; +using static pmcenter.Methods.Logging; + +namespace pmcenter +{ + public static partial class BotProcess + { + private static async Task OwnerCommand(Update update) + { + // The owner is not even replying. + // start or help command? + if (await commandManager.Execute(Vars.Bot, update).ConfigureAwait(false)) + { + Vars.CurrentConf.Statistics.TotalCommandsReceived += 1; + return; + } + // command mismatch + if (Vars.CurrentConf.ContChatTarget != -1) + { + // Is replying, replying to forwarded message AND not command. + var forwarded = await Vars.Bot.ForwardMessageAsync( + Vars.CurrentConf.ContChatTarget, + update.Message.Chat.Id, + update.Message.MessageId, + Vars.CurrentConf.DisableNotifications).ConfigureAwait(false); + if (Vars.CurrentConf.EnableMsgLink) + { + Log($"Recording message link: {forwarded.MessageId} -> {update.Message.MessageId} in {update.Message.From.Id}", "BOT"); + Vars.CurrentConf.MessageLinks.Add( + new Conf.MessageIDLink() + { OwnerSessionMessageID = forwarded.MessageId, UserSessionMessageID = update.Message.MessageId, TGUser = update.Message.From, IsFromOwner = true } + ); + // Conf.SaveConf(false, true); + } + // Process locale. + if (Vars.CurrentConf.EnableRepliedConfirmation) + { + var replyToMessage = Vars.CurrentLang.Message_ReplySuccessful; + replyToMessage = replyToMessage.Replace("$1", $"[{Vars.CurrentConf.ContChatTarget}](tg://user?id={Vars.CurrentConf.ContChatTarget})"); + _ = await Vars.Bot.SendTextMessageAsync(update.Message.From.Id, replyToMessage, ParseMode.Markdown, false, false, update.Message.MessageId).ConfigureAwait(false); + } + Log($"Successfully passed owner's reply to UID: {Vars.CurrentConf.ContChatTarget}", "BOT"); + return; + } + + _ = await Vars.Bot.SendTextMessageAsync( + update.Message.From.Id, + Vars.CurrentLang.Message_CommandNotReplying, + ParseMode.Markdown, + false, + Vars.CurrentConf.DisableNotifications, + update.Message.MessageId).ConfigureAwait(false); + } + } +} diff --git a/pmcenter/BotProcess/BotProcess.OwnerLogic.cs b/pmcenter/BotProcess/BotProcess.OwnerLogic.cs new file mode 100644 index 0000000..2d10cc0 --- /dev/null +++ b/pmcenter/BotProcess/BotProcess.OwnerLogic.cs @@ -0,0 +1,20 @@ +using System.Threading.Tasks; +using Telegram.Bot.Types; + +namespace pmcenter +{ + public static partial class BotProcess + { + private static async Task OwnerLogic(Update update) + { + if (update.Message.ReplyToMessage != null) + { + await OwnerReplying(update).ConfigureAwait(false); + } + else + { + await OwnerCommand(update).ConfigureAwait(false); + } + } + } +} diff --git a/pmcenter/BotProcess/BotProcess.OwnerReplying.cs b/pmcenter/BotProcess/BotProcess.OwnerReplying.cs new file mode 100644 index 0000000..4910dee --- /dev/null +++ b/pmcenter/BotProcess/BotProcess.OwnerReplying.cs @@ -0,0 +1,76 @@ +using System.Threading.Tasks; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; +using static pmcenter.Methods.Logging; + +namespace pmcenter +{ + public static partial class BotProcess + { + private static async Task OwnerReplying(Update update) + { + // check anonymous forward (5.5.0 new feature compatibility fix) + var link = Methods.GetLinkByOwnerMsgID(update.Message.ReplyToMessage.MessageId); + if (link != null && !link.IsFromOwner) + { + Log($"Found corresponding message link for message #{update.Message.ReplyToMessage.MessageId}, which was actually forwarded from {link.TGUser.Id}, patching user information from database...", "BOT"); + update.Message.ReplyToMessage.ForwardFrom = link.TGUser; + } + if ((update.Message.ReplyToMessage.ForwardFrom == null) && (update.Message.Text.ToLowerInvariant() != "/retract")) + { + // The owner is replying to bot messages. (no forwardfrom) + _ = await Vars.Bot.SendTextMessageAsync( + update.Message.From.Id, + Vars.CurrentLang.Message_CommandNotReplyingValidMessage, + ParseMode.Markdown, + false, + Vars.CurrentConf.DisableNotifications, + update.Message.MessageId).ConfigureAwait(false); + // The message is forwarded anonymously + if (!string.IsNullOrEmpty(update.Message.ReplyToMessage.ForwardSenderName) && !Vars.CurrentConf.DisableMessageLinkTip) + { + _ = await Vars.Bot.SendTextMessageAsync( + update.Message.From.Id, + Vars.CurrentLang.Message_MsgLinkTip, + ParseMode.Markdown, + false, + Vars.CurrentConf.DisableNotifications, + update.Message.MessageId).ConfigureAwait(false); + Vars.CurrentConf.DisableMessageLinkTip = true; + } + return; + } + + if (await commandManager.Execute(Vars.Bot, update).ConfigureAwait(false)) + { + Vars.CurrentConf.Statistics.TotalCommandsReceived += 1; + return; + } + + // Is replying, replying to forwarded message AND not command. + var forwarded = await Vars.Bot.ForwardMessageAsync( + update.Message.ReplyToMessage.ForwardFrom.Id, + update.Message.Chat.Id, + update.Message.MessageId, + Vars.CurrentConf.DisableNotifications).ConfigureAwait(false); + if (Vars.CurrentConf.EnableMsgLink) + { + Log($"Recording message link: user {forwarded.MessageId} <-> owner {update.Message.MessageId}, user: {update.Message.ReplyToMessage.ForwardFrom.Id}", "BOT"); + Vars.CurrentConf.MessageLinks.Add( + new Conf.MessageIDLink() + { OwnerSessionMessageID = update.Message.MessageId, UserSessionMessageID = forwarded.MessageId, TGUser = update.Message.ReplyToMessage.ForwardFrom, IsFromOwner = true } + ); + // Conf.SaveConf(false, true); + } + Vars.CurrentConf.Statistics.TotalForwardedFromOwner += 1; + // Process locale. + if (Vars.CurrentConf.EnableRepliedConfirmation) + { + var replyToMessage = Vars.CurrentLang.Message_ReplySuccessful; + replyToMessage = replyToMessage.Replace("$1", $"[{Methods.GetComposedUsername(update.Message.ReplyToMessage.ForwardFrom)}](tg://user?id={update.Message.ReplyToMessage.ForwardFrom.Id})"); + _ = await Vars.Bot.SendTextMessageAsync(update.Message.From.Id, replyToMessage, ParseMode.Markdown, false, false, update.Message.MessageId).ConfigureAwait(false); + } + Log($"Successfully passed owner's reply to {Methods.GetComposedUsername(update.Message.ReplyToMessage.ForwardFrom, true, true)}", "BOT"); + } + } +} diff --git a/pmcenter/BotProcess/BotProcess.RunCc.cs b/pmcenter/BotProcess/BotProcess.RunCc.cs new file mode 100644 index 0000000..3c39441 --- /dev/null +++ b/pmcenter/BotProcess/BotProcess.RunCc.cs @@ -0,0 +1,60 @@ +using System; +using System.Threading.Tasks; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; +using static pmcenter.Methods.Logging; + +namespace pmcenter +{ + public static partial class BotProcess + { + private static async Task RunCc(Update update) + { + Log("Cc enabled, forwarding...", "BOT"); + foreach (var id in Vars.CurrentConf.Cc) + { + Log($"Forwarding message to cc: {id}", "BOT"); + try + { + var forwardedMessageCc = await Vars.Bot.ForwardMessageAsync(id, + update.Message.From.Id, + update.Message.MessageId, + Vars.CurrentConf.DisableNotifications).ConfigureAwait(false); + // check if forwarded from channels + if (update.Message.ForwardFrom == null && update.Message.ForwardFromChat != null) + { + // is forwarded from channel + _ = await Vars.Bot.SendTextMessageAsync(id, + Vars.CurrentLang.Message_ForwarderNotReal + .Replace("$2", update.Message.From.Id.ToString()) + .Replace("$1", "[" + update.Message.From.FirstName + " " + update.Message.From.LastName + "](tg://user?id=" + update.Message.From.Id + ")"), + ParseMode.Markdown, + false, + Vars.CurrentConf.DisableNotifications, + forwardedMessageCc.MessageId).ConfigureAwait(false); + } + if (update.Message.ForwardFrom != null && update.Message.ForwardFromChat == null) + { + // is forwarded from chats + // check real message sender + if (update.Message.ForwardFrom.Id != update.Message.From.Id) + { + _ = await Vars.Bot.SendTextMessageAsync(id, + Vars.CurrentLang.Message_ForwarderNotReal + .Replace("$2", update.Message.From.Id.ToString()) + .Replace("$1", "[" + update.Message.From.FirstName + " " + update.Message.From.LastName + "](tg://user?id=" + update.Message.From.Id + ")"), + ParseMode.Markdown, + false, + Vars.CurrentConf.DisableNotifications, + forwardedMessageCc.MessageId).ConfigureAwait(false); + } + } + } + catch (Exception ex) + { + Log($"Unable to forward message to cc: {id}, reason: {ex.Message}", "BOT", LogLevel.Error); + } + } + } + } +} diff --git a/pmcenter/BotProcess/BotProcess.UserLogic.cs b/pmcenter/BotProcess/BotProcess.UserLogic.cs new file mode 100644 index 0000000..10bb554 --- /dev/null +++ b/pmcenter/BotProcess/BotProcess.UserLogic.cs @@ -0,0 +1,129 @@ +using pmcenter.CallbackActions; +using System.Threading.Tasks; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; +using Telegram.Bot.Types.ReplyMarkups; +using static pmcenter.Methods; +using static pmcenter.Methods.Logging; + +namespace pmcenter +{ + public static partial class BotProcess + { + private static async Task UserLogic(Update update) + { + // is user + + if (await commandManager.Execute(Vars.Bot, update).ConfigureAwait(false)) return; + + Log($"Received message from \"{update.Message.From.FirstName}\" (@{update.Message.From.Username} / {update.Message.From.Id}), forwarding...", "BOT"); + + if (Vars.CurrentConf.ForwardingPaused) + { + Log("Stopped: forwarding is currently paused.", "BOT", LogLevel.Info); + _ = await Vars.Bot.SendTextMessageAsync(update.Message.From.Id, + Vars.CurrentLang.Message_UserServicePaused, + ParseMode.Markdown, + false, + false, + update.Message.MessageId).ConfigureAwait(false); + return; + } + + if (Methods.IsBanned(update.Message.From.Id)) + { + Log($"Restricting banned user from sending messages: {update.Message.From.FirstName} (@{update.Message.From.Username} / {(long)update.Message.From.Id})", "BOT"); + return; + } + + // test text blacklist + if (!string.IsNullOrEmpty(update.Message.Text) && IsKeywordBanned(update.Message.Text)) + { + Log("Stopped: sentence contains blocked words.", "BOT", LogLevel.Info); + if (Vars.CurrentConf.KeywordAutoBan) + { + BanUser(update.Message.From.Id); + } + return; + } + + // process owner + Log("Forwarding message to owner...", "BOT"); + var forwardedMessage = await Vars.Bot.ForwardMessageAsync(Vars.CurrentConf.OwnerUID, + update.Message.From.Id, + update.Message.MessageId, + Vars.CurrentConf.DisableNotifications).ConfigureAwait(false); + Vars.CurrentConf.Statistics.TotalForwardedToOwner += 1; + // preprocess message link + var link = new Conf.MessageIDLink() + { + OwnerSessionMessageID = forwardedMessage.MessageId, + UserSessionMessageID = update.Message.MessageId, + TGUser = update.Message.From, + IsFromOwner = false + }; + // process actions + if (Vars.CurrentConf.EnableActions && Vars.CurrentConf.EnableMsgLink) + { + var markup = new InlineKeyboardMarkup(CallbackProcess.GetAvailableButtons(update)); + link.OwnerSessionActionMessageID = (await Vars.Bot.SendTextMessageAsync( + Vars.CurrentConf.OwnerUID, + Vars.CurrentLang.Message_Action_ChooseAction, + ParseMode.Markdown, + false, + true, + forwardedMessage.MessageId, + markup + ).ConfigureAwait(false)).MessageId; + } + // process message links + if (Vars.CurrentConf.EnableMsgLink) + { + Log($"Recording message link: owner {forwardedMessage.MessageId} <-> user {update.Message.MessageId} user: {update.Message.From.Id}", "BOT"); + Vars.CurrentConf.MessageLinks.Add(link); + // Conf.SaveConf(false, true); + } + // check for real message sender + // check if forwarded from channels + bool forwarderNotReal = false; + if (update.Message.ForwardFrom == null && update.Message.ForwardFromChat != null) + // is forwarded from channel + forwarderNotReal = true; + + if (update.Message.ForwardFrom != null && update.Message.ForwardFromChat == null) + // is forwarded from chats, but the forwarder is not the message sender + if (update.Message.ForwardFrom.Id != update.Message.From.Id) + forwarderNotReal = true; + + if (!string.IsNullOrEmpty(update.Message.ForwardSenderName) || !string.IsNullOrEmpty(forwardedMessage.ForwardSenderName)) + // is anonymously forwarded + forwarderNotReal = true; + + if (forwarderNotReal) + _ = await Vars.Bot.SendTextMessageAsync(Vars.CurrentConf.OwnerUID, + Vars.CurrentLang.Message_ForwarderNotReal + .Replace("$2", update.Message.From.Id.ToString()) + .Replace("$1", $"[{GetComposedUsername(update.Message.From)}](tg://user?id={update.Message.From.Id})"), + ParseMode.Markdown, + false, + Vars.CurrentConf.DisableNotifications, + forwardedMessage.MessageId).ConfigureAwait(false); + + // process cc + if (Vars.CurrentConf.EnableCc) + { + await RunCc(update).ConfigureAwait(false); + } + if (Vars.CurrentConf.EnableForwardedConfirmation) + { + _ = await Vars.Bot.SendTextMessageAsync(update.Message.From.Id, + Vars.CurrentLang.Message_ForwardedToOwner, + ParseMode.Markdown, + false, + false, + update.Message.MessageId).ConfigureAwait(false); + } + AddRateLimit(update.Message.From.Id); + } + } +} diff --git a/pmcenter/BotProcess/BotProcess.cs b/pmcenter/BotProcess/BotProcess.cs new file mode 100644 index 0000000..b3bf1df --- /dev/null +++ b/pmcenter/BotProcess/BotProcess.cs @@ -0,0 +1,98 @@ +/* +// BotProcess.cs / pmcenter project / https://github.com/Elepover/pmcenter +// Main processing logic of pmcenter. +// Copyright (C) The pmcenter authors. Licensed under the Apache License (Version 2.0). +*/ + +using pmcenter.Commands; +using System; +using Telegram.Bot.Args; +using Telegram.Bot.Types.Enums; +using static pmcenter.Methods.Logging; + +namespace pmcenter +{ + public static partial class BotProcess + { + private static readonly CommandRouter commandManager = new CommandRouter(); + + static BotProcess() + { + commandManager.RegisterCommand(new StartCommand()); + commandManager.RegisterCommand(new HelpCommand()); + + commandManager.RegisterCommand(new InfoCommand()); + commandManager.RegisterCommand(new BanCommand()); + commandManager.RegisterCommand(new PardonCommand()); + + commandManager.RegisterCommand(new AutoSaveCommand()); + commandManager.RegisterCommand(new BackupConfCommand()); + commandManager.RegisterCommand(new BanIdCommand()); + commandManager.RegisterCommand(new CatConfigCommand()); + commandManager.RegisterCommand(new ChatCommand()); + commandManager.RegisterCommand(new CheckUpdateCommand()); + commandManager.RegisterCommand(new ClearMessageLinksCommand()); + commandManager.RegisterCommand(new DetectPermissionCommand()); + commandManager.RegisterCommand(new DonateCommand()); + commandManager.RegisterCommand(new EditConfCommand()); + commandManager.RegisterCommand(new GetStatsCommand()); + commandManager.RegisterCommand(new PardonIdCommand()); + commandManager.RegisterCommand(new PerformCommand()); + commandManager.RegisterCommand(new PingCommand()); + commandManager.RegisterCommand(new ReadConfigCommand()); + commandManager.RegisterCommand(new ResetConfCommand()); + commandManager.RegisterCommand(new RestartCommand()); + commandManager.RegisterCommand(new RetractCommand()); + commandManager.RegisterCommand(new SaveConfigCommand()); + commandManager.RegisterCommand(new StatusCommand()); + commandManager.RegisterCommand(new StopChatCommand()); + commandManager.RegisterCommand(new SwitchBwCommand()); + commandManager.RegisterCommand(new SwitchFwCommand()); + commandManager.RegisterCommand(new SwitchLangCodeCommand()); + commandManager.RegisterCommand(new SwitchLangCommand()); + commandManager.RegisterCommand(new SwitchNotificationCommand()); + commandManager.RegisterCommand(new TestNetworkCommand()); + commandManager.RegisterCommand(new UpdateCommand()); + commandManager.RegisterCommand(new UptimeCommand()); + } + + public static async void OnUpdate(object sender, UpdateEventArgs e) + { + try + { + if (e == null) return; + if (Vars.CurrentConf.DetailedMsgLogging && e.Update.Type == UpdateType.Message) + Log($"OnUpdate() triggered: UpdType: {e.Update.Type}, UpdID: {e.Update.Id}, ChatId: {e.Update.Message.Chat.Id}, Username: {e.Update.Message.Chat.Username}, FromID: {e.Update.Message.From.Id}, FromUsername: {e.Update.Message.From.Username}", "BOT-DETAILED", LogLevel.Info); + + switch (e.Update.Type) + { + case UpdateType.Message: await MessageRoute(sender, e); break; + case UpdateType.CallbackQuery: await CallbackQueryRoute(sender, e); break; + default: + if (Vars.CurrentConf.DetailedMsgLogging) + Log($"Ditching unknown update type ({e.Update.Type})...", "BOT-DETAILED"); + return; + } + } + catch (Exception ex) + { + Log($"General error while processing incoming update: {ex}", "BOT", LogLevel.Error); + if (Vars.CurrentConf.CatchAllExceptions) + { + try + { + _ = await Vars.Bot.SendTextMessageAsync(Vars.CurrentConf.OwnerUID, + Vars.CurrentLang.Message_GeneralFailure.Replace("$1", ex.ToString()), + ParseMode.Default, + false, + Vars.CurrentConf.DisableNotifications).ConfigureAwait(false); + } + catch (Exception iEx) + { + Log($"Failed to catch exception to owner: {iEx}", "BOT", LogLevel.Error); + } + } + } + } + } +} diff --git a/pmcenter/CommandRouter.cs b/pmcenter/BotProcess/CommandRouter.cs similarity index 84% rename from pmcenter/CommandRouter.cs rename to pmcenter/BotProcess/CommandRouter.cs index cdcf9dd..07800a7 100644 --- a/pmcenter/CommandRouter.cs +++ b/pmcenter/BotProcess/CommandRouter.cs @@ -18,13 +18,13 @@ internal class CommandRouter { private const char globalPrefix = '/'; - private readonly List commands = new List(); + private readonly List commands = new List(); public CommandRouter() { } - public ICommand this[string prefix] => commands.FirstOrDefault(command => command.Prefix == prefix); + public IBotCommand this[string prefix] => commands.FirstOrDefault(command => command.Prefix == prefix); /// /// Add a command to manager. @@ -32,7 +32,7 @@ public CommandRouter() /// /// the command /// - public void RegisterCommand(ICommand command) + public void RegisterCommand(IBotCommand command) { if (commands.Any(x => x.Prefix == command.Prefix)) { throw new ArgumentException($"A command with prefix \"{ command.Prefix }\" already exists.", nameof(command)); } @@ -48,8 +48,8 @@ public void RegisterCommand(ICommand command) /// processed by one command public async Task Execute(TelegramBotClient botClient, Update update) { - if (update.Message.Type != MessageType.Text) { return false; } - if (!update.Message.Text.StartsWith(globalPrefix)) { return false; } + if (update.Message.Type != MessageType.Text) return false; + if (!update.Message.Text.StartsWith(globalPrefix)) return false; var command = commands.FirstOrDefault(cmd => { diff --git a/pmcenter/CallbackActions/BanAction.cs b/pmcenter/CallbackActions/BanAction.cs new file mode 100644 index 0000000..ecd0c17 --- /dev/null +++ b/pmcenter/CallbackActions/BanAction.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using Telegram.Bot.Types; +using static pmcenter.Methods; +using static pmcenter.Methods.Logging; + +namespace pmcenter.CallbackActions +{ + internal class BanAction : ICallbackAction + { + public string Name => "ban"; + public string ButtonName => Vars.CurrentLang.Message_Action_Ban; + public ICallbackAction Replacement => new PardonAction(); + +#pragma warning disable CS1998 + public async Task Action(User user, Message msg) +#pragma warning restore CS1998 + { + // attempt to ban the user + Log($"Attempting to ban user {user.Id} via callback actions...", "BOT"); + BanUser(user.Id); + Log($"User {user.Id} banned via callback actions...", "BOT"); + return Vars.CurrentLang.Message_Action_Banned.Replace("$1", GetComposedUsername(user, false)); + } + + public bool IsAvailable(Update update) => !IsBanned(update); + } +} diff --git a/pmcenter/CallbackActions/CallbackActionResult.cs b/pmcenter/CallbackActions/CallbackActionResult.cs new file mode 100644 index 0000000..37ab725 --- /dev/null +++ b/pmcenter/CallbackActions/CallbackActionResult.cs @@ -0,0 +1,15 @@ +namespace pmcenter.CallbackActions +{ + public class CallbackActionResult + { + public CallbackActionResult(string status, bool showAsAlert = false, bool succeeded = true) + { + Status = status; + Succeeded = succeeded; + ShowAsAlert = showAsAlert; + } + public string Status; + public bool Succeeded; + public bool ShowAsAlert; + } +} diff --git a/pmcenter/CallbackActions/CallbackManager.cs b/pmcenter/CallbackActions/CallbackManager.cs new file mode 100644 index 0000000..2d613f7 --- /dev/null +++ b/pmcenter/CallbackActions/CallbackManager.cs @@ -0,0 +1,57 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Threading.Tasks; +using Telegram.Bot.Types; +using Telegram.Bot.Types.ReplyMarkups; + +namespace pmcenter.CallbackActions +{ + internal class CallbackManager + { + private readonly List callbacks = new List(); + + public CallbackManager() + { } + + public ICallbackAction this[string prefix] => callbacks.FirstOrDefault(x => x.Name.StartsWith(prefix)); + + public void RegisterAction(ICallbackAction action) + { + if (callbacks.Any(x => x.Name == action.Name)) + throw new ArgumentException($"An action named \"{action.Name}\" is already registered.", nameof(action)); + callbacks.Add(action); + } + + public async Task Execute(string actionName, User user, Message msg) + { + foreach (var action in callbacks) + { + if (action.Name == actionName) + { + return await action.Action(user, msg); + } + } + return null; + } + + public List> GetAvailableButtons(Update update) + { + var result = new List>(); + foreach (var action in callbacks) + if (action.IsAvailable(update)) + { + var oneLineKeyboard = new List + { + new InlineKeyboardButton() + { + CallbackData = action.Name, + Text = action.ButtonName + } + }; + result.Add(oneLineKeyboard); + } + return result; + } + } +} diff --git a/pmcenter/CallbackActions/CallbackProcess.cs b/pmcenter/CallbackActions/CallbackProcess.cs new file mode 100644 index 0000000..932f2ff --- /dev/null +++ b/pmcenter/CallbackActions/CallbackProcess.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Threading.Tasks; +using Telegram.Bot.Types; +using Telegram.Bot.Types.ReplyMarkups; +using static pmcenter.Methods.Logging; + +namespace pmcenter.CallbackActions +{ + public static class CallbackProcess + { + private static readonly int callbackOutputThreshold = 50; + private static readonly CallbackManager callbackManager = new CallbackManager(); + + static CallbackProcess() + { + callbackManager.RegisterAction(new BanAction()); + callbackManager.RegisterAction(new PardonAction()); + callbackManager.RegisterAction(new ContinuedChatAction()); + callbackManager.RegisterAction(new DisableContinuedChatAction()); + } + + /// + /// Do callback with given arguments + /// + /// The name of the action + /// The user who initiated the action + /// The corresponding message + /// + public static async Task DoCallback(string actionName, User user, Message msg) + { + try + { + var result = await callbackManager.Execute(actionName, user, msg); + if (result == null) + { + Log($"Callback {actionName} from user {user.Id} cannot be found.", "BOT", LogLevel.Warning); + result = Vars.CurrentLang.Message_Action_Error; + } + var useAlert = result.Length > callbackOutputThreshold; + if (useAlert) + Log($"Callback query result length {result.Length} exceeded limit ({callbackOutputThreshold}), using alert instead.", "BOT"); + return new CallbackActionResult + ( + result, + useAlert, + result != null + ); + } + catch (Exception ex) + { + Log($"Callback {actionName} could not be executed: {ex}", "BOT", LogLevel.Error); + return new CallbackActionResult(Vars.CurrentLang.Message_Action_Error, true, false); + } + } + + public static List> GetAvailableButtons(Update update) => callbackManager.GetAvailableButtons(update); + } +} diff --git a/pmcenter/CallbackActions/ContinuedChatAction.cs b/pmcenter/CallbackActions/ContinuedChatAction.cs new file mode 100644 index 0000000..39124a9 --- /dev/null +++ b/pmcenter/CallbackActions/ContinuedChatAction.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using Telegram.Bot.Types; +using static pmcenter.Methods; +using static pmcenter.Methods.Logging; + +namespace pmcenter.CallbackActions +{ + internal class ContinuedChatAction : ICallbackAction + { + public string Name => "chat"; + public string ButtonName => Vars.CurrentLang.Message_Action_Chat; + public ICallbackAction Replacement => new DisableContinuedChatAction(); + +#pragma warning disable CS1998 + public async Task Action(User user, Message msg) +#pragma warning restore CS1998 + { + Log("Enabling continued conversation via actions...", "BOT"); + Vars.CurrentConf.ContChatTarget = user.Id; + _ = await Conf.SaveConf(false, true).ConfigureAwait(false); + Log($"Continued conversation to {user.Id} enabled via actions.", "BOT"); + return Vars.CurrentLang.Message_Action_ContChatEnabled.Replace("$1", GetComposedUsername(user, false)); + } + + public bool IsAvailable(Update update) => Vars.CurrentConf.ContChatTarget == -1; + } +} diff --git a/pmcenter/CallbackActions/DisableContinuedChatAction.cs b/pmcenter/CallbackActions/DisableContinuedChatAction.cs new file mode 100644 index 0000000..9c1c8e1 --- /dev/null +++ b/pmcenter/CallbackActions/DisableContinuedChatAction.cs @@ -0,0 +1,26 @@ +using System.Threading.Tasks; +using Telegram.Bot.Types; +using static pmcenter.Methods.Logging; + +namespace pmcenter.CallbackActions +{ + internal class DisableContinuedChatAction : ICallbackAction + { + public string Name => "disablechat"; + public string ButtonName => Vars.CurrentLang.Message_Action_StopChat; + public ICallbackAction Replacement => new ContinuedChatAction(); + +#pragma warning disable CS1998 + public async Task Action(User user, Message msg) +#pragma warning restore CS1998 + { + Log("Disabling continued conversation via actions...", "BOT"); + Vars.CurrentConf.ContChatTarget = -1; + _ = await Conf.SaveConf(false, true).ConfigureAwait(false); + Log("Continued conversation disabled via actions.", "BOT"); + return Vars.CurrentLang.Message_Action_ContChatDisabled; + } + + public bool IsAvailable(Update update) => Vars.CurrentConf.ContChatTarget != -1; + } +} diff --git a/pmcenter/CallbackActions/PardonAction.cs b/pmcenter/CallbackActions/PardonAction.cs new file mode 100644 index 0000000..322d483 --- /dev/null +++ b/pmcenter/CallbackActions/PardonAction.cs @@ -0,0 +1,27 @@ +using System.Threading.Tasks; +using Telegram.Bot.Types; +using static pmcenter.Methods; +using static pmcenter.Methods.Logging; + +namespace pmcenter.CallbackActions +{ + internal class PardonAction : ICallbackAction + { + public string Name => "pardon"; + public string ButtonName => Vars.CurrentLang.Message_Action_Pardon; + public ICallbackAction Replacement => new BanAction(); + +#pragma warning disable CS1998 + public async Task Action(User user, Message msg) +#pragma warning restore CS1998 + { + // attempt to pardon the user + Log($"Attempting to pardon {user.Id} via callback actions...", "BOT"); + UnbanUser(user.Id); + Log($"User {user.Id} pardoned via callback actions...", "BOT"); + return Vars.CurrentLang.Message_Action_Pardoned.Replace("$1", GetComposedUsername(user, false)); + } + + public bool IsAvailable(Update update) => IsBanned(update); + } +} diff --git a/pmcenter/CommandLines/BackupCmdLine.cs b/pmcenter/CommandLines/BackupCmdLine.cs index 55c8948..4918674 100644 --- a/pmcenter/CommandLines/BackupCmdLine.cs +++ b/pmcenter/CommandLines/BackupCmdLine.cs @@ -1,24 +1,23 @@ using System; using System.IO; -using System.Runtime.InteropServices; using System.Threading.Tasks; - using static pmcenter.Methods; +using static pmcenter.Methods.Logging; namespace pmcenter.CommandLines { - internal class BackupCmdLine : ICmdLine + internal class BackupCmdLine : ICommandLine { public string Prefix => "backup"; public bool ExitAfterExecution => true; public Task Process() { Log("Backing up...", "CMD"); - var RandomFilename = $"pmcenter.{DateTime.Now.ToString("yyyy-dd-M-HH-mm-ss")}#{GetRandomString(6)}.json"; - RandomFilename = Path.Combine(Vars.AppDirectory, RandomFilename); - File.Copy(Vars.ConfFile, RandomFilename); - Log($"Backup complete. Filename: {RandomFilename}", "CMD"); + var randomFilename = $"pmcenter.{DateTime.Now:yyyy-dd-M-HH-mm-ss}#{GetRandomString(6)}.json"; + randomFilename = Path.Combine(Vars.AppDirectory, randomFilename); + File.Copy(Vars.ConfFile, randomFilename); + Log($"Backup complete. Filename: {randomFilename}", "CMD"); return Task.FromResult(true); } } -} \ No newline at end of file +} diff --git a/pmcenter/CommandLineProcess.cs b/pmcenter/CommandLines/CommandLineProcess.cs similarity index 50% rename from pmcenter/CommandLineProcess.cs rename to pmcenter/CommandLines/CommandLineProcess.cs index b9b8d0e..d384f6b 100644 --- a/pmcenter/CommandLineProcess.cs +++ b/pmcenter/CommandLines/CommandLineProcess.cs @@ -10,22 +10,22 @@ namespace pmcenter { public static class CmdLineProcess { - private static readonly CommandLineRouter CmdLineRouter = new CommandLineRouter(); + private static readonly CommandLineRouter cmdLineRouter = new CommandLineRouter(); static CmdLineProcess() { - CmdLineRouter.RegisterCommand(new CommandLines.HelpCmdLine()); - CmdLineRouter.RegisterCommand(new CommandLines.InfoCmdLine()); - CmdLineRouter.RegisterCommand(new CommandLines.NonServiceModeCmdLine()); - CmdLineRouter.RegisterCommand(new CommandLines.SetupWizardCmdLine()); - CmdLineRouter.RegisterCommand(new CommandLines.ResetCmdLine()); - CmdLineRouter.RegisterCommand(new CommandLines.BackupCmdLine()); - CmdLineRouter.RegisterCommand(new CommandLines.UpdateCmdLine()); + cmdLineRouter.RegisterCommand(new CommandLines.HelpCmdLine()); + cmdLineRouter.RegisterCommand(new CommandLines.InfoCmdLine()); + cmdLineRouter.RegisterCommand(new CommandLines.NonServiceModeCmdLine()); + cmdLineRouter.RegisterCommand(new CommandLines.SetupWizardCmdLine()); + cmdLineRouter.RegisterCommand(new CommandLines.ResetCmdLine()); + cmdLineRouter.RegisterCommand(new CommandLines.BackupCmdLine()); + cmdLineRouter.RegisterCommand(new CommandLines.UpdateCmdLine()); } public static async Task RunCommand(string CommandLine) { - _ = await CmdLineRouter.Execute(CommandLine).ConfigureAwait(false); + _ = await cmdLineRouter.Execute(CommandLine).ConfigureAwait(false); } } -} \ No newline at end of file +} diff --git a/pmcenter/CommandLineRouter.cs b/pmcenter/CommandLines/CommandLineRouter.cs similarity index 85% rename from pmcenter/CommandLineRouter.cs rename to pmcenter/CommandLines/CommandLineRouter.cs index 9e9fd18..b0ad819 100644 --- a/pmcenter/CommandLineRouter.cs +++ b/pmcenter/CommandLines/CommandLineRouter.cs @@ -8,8 +8,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; - -using static pmcenter.Methods; +using static pmcenter.Methods.Logging; namespace pmcenter { @@ -17,13 +16,13 @@ internal class CommandLineRouter { private const string globalPrefix = "--"; - private readonly List commands = new List(); + private readonly List commands = new List(); public CommandLineRouter() { } - public ICmdLine this[string prefix] => commands.FirstOrDefault(command => command.Prefix == prefix); + public ICommandLine this[string prefix] => commands.FirstOrDefault(command => command.Prefix == prefix); /// /// Add a command to manager. @@ -31,7 +30,7 @@ public CommandLineRouter() /// /// the command /// - public void RegisterCommand(ICmdLine command) + public void RegisterCommand(ICommandLine command) { if (commands.Any(x => x.Prefix == command.Prefix)) { throw new ArgumentException($"A commandline with prefix \"{command.Prefix}\" already exists.", nameof(command)); } @@ -47,7 +46,7 @@ public void RegisterCommand(ICmdLine command) public async Task Execute(string cmdLine) { Log("Processing commandlines...", "CMD"); - foreach (ICmdLine cmdProcess in commands) + foreach (var cmdProcess in commands) { if (cmdLine.Contains(globalPrefix + cmdProcess.Prefix)) { @@ -58,7 +57,7 @@ public async Task Execute(string cmdLine) } catch (Exception ex) { - Log($"Exception while executing commandline: {ex.ToString()}", "CMD", LogLevel.ERROR); + Log($"Exception while executing commandline: {ex}", "CMD", LogLevel.Error); Environment.Exit(1); } Log("Command finished.", "CMD"); @@ -74,4 +73,4 @@ public async Task Execute(string cmdLine) return false; } } -} \ No newline at end of file +} diff --git a/pmcenter/CommandLines/HelpCmdLine.cs b/pmcenter/CommandLines/HelpCmdLine.cs index 8556fec..747bc1e 100644 --- a/pmcenter/CommandLines/HelpCmdLine.cs +++ b/pmcenter/CommandLines/HelpCmdLine.cs @@ -1,11 +1,9 @@ -using System; -using System.Threading.Tasks; - -using static pmcenter.Methods; +using System.Threading.Tasks; +using static pmcenter.Methods.Logging; namespace pmcenter.CommandLines { - internal class HelpCmdLine : ICmdLine + internal class HelpCmdLine : ICommandLine { public string Prefix => "help"; public bool ExitAfterExecution => true; @@ -17,4 +15,4 @@ public Task Process() return Task.FromResult(true); } } -} \ No newline at end of file +} diff --git a/pmcenter/CommandLines/InfoCmdLine.cs b/pmcenter/CommandLines/InfoCmdLine.cs index 3e39395..09be9ff 100644 --- a/pmcenter/CommandLines/InfoCmdLine.cs +++ b/pmcenter/CommandLines/InfoCmdLine.cs @@ -1,32 +1,32 @@ using System; using System.Runtime.InteropServices; using System.Threading.Tasks; - using static pmcenter.Methods; +using static pmcenter.Methods.Logging; namespace pmcenter.CommandLines { - internal class InfoCmdLine : ICmdLine + internal class InfoCmdLine : ICommandLine { public string Prefix => "info"; public bool ExitAfterExecution => true; public async Task Process() { Log("Gathering application information... This may take a while for there's some network activities.", "CMD"); - var IsTelegramAPIAccessible = await TestConnectivity("https://api.telegram.org/bot/", true).ConfigureAwait(false); - var IsGitHubAccessible = await TestConnectivity("https://raw.githubusercontent.com/", true).ConfigureAwait(false); - var IsCIAvailable = await TestConnectivity("https://ci.appveyor.com/", true).ConfigureAwait(false); + var isTelegramApiAccessible = await TestConnectivity("https://api.telegram.org/bot/", true).ConfigureAwait(false); + var isGitHubAccessible = await TestConnectivity("https://raw.githubusercontent.com/", true).ConfigureAwait(false); + var isCiAvailable = await TestConnectivity("https://ci.appveyor.com/", true).ConfigureAwait(false); Log("Application information", "CMD"); - Log($"CLR version: {Environment.Version.ToString()}", "CMD"); + Log($"CLR version: {Environment.Version}", "CMD"); Log($"Framework description: {RuntimeInformation.FrameworkDescription}", "CMD"); - Log($"Application version: {Vars.AppVer.ToString()}", "CMD"); + Log($"Application version: {Vars.AppVer}", "CMD"); Log($"Configurations filename: {Vars.ConfFile}", "CMD"); Log($"Language filename: {Vars.LangFile}", "CMD"); - Log($"Is Telegram API accessible? {(IsTelegramAPIAccessible ? "yes" : "no")}", "CMD"); - Log($"Is GitHub accessible? {(IsGitHubAccessible ? "yes" : "no")}", "CMD"); - Log($"Is CI accessible? {(IsCIAvailable ? "yes" : "no")}", "CMD"); + Log($"Is Telegram API accessible? {(isTelegramApiAccessible ? "yes" : "no")}", "CMD"); + Log($"Is GitHub accessible? {(isGitHubAccessible ? "yes" : "no")}", "CMD"); + Log($"Is CI accessible? {(isCiAvailable ? "yes" : "no")}", "CMD"); return true; } } -} \ No newline at end of file +} diff --git a/pmcenter/CommandLines/NonServiceModeCmdLine.cs b/pmcenter/CommandLines/NonServiceModeCmdLine.cs index 1da71da..66ea314 100644 --- a/pmcenter/CommandLines/NonServiceModeCmdLine.cs +++ b/pmcenter/CommandLines/NonServiceModeCmdLine.cs @@ -1,20 +1,19 @@ -using System; -using System.Runtime.InteropServices; -using System.Threading.Tasks; - -using static pmcenter.Methods; +using System.Threading.Tasks; +using static pmcenter.Methods.Logging; namespace pmcenter.CommandLines { - internal class NonServiceModeCmdLine : ICmdLine + internal class NonServiceModeCmdLine : ICommandLine { public string Prefix => "noservice"; public bool ExitAfterExecution => false; +#pragma warning disable CS1998 public async Task Process() +#pragma warning restore CS1998 { Vars.ServiceMode = false; Log("Service mode disabled."); return true; } } -} \ No newline at end of file +} diff --git a/pmcenter/CommandLines/ResetCmdLine.cs b/pmcenter/CommandLines/ResetCmdLine.cs index 5907369..d5873f1 100644 --- a/pmcenter/CommandLines/ResetCmdLine.cs +++ b/pmcenter/CommandLines/ResetCmdLine.cs @@ -1,12 +1,9 @@ -using System; -using System.Runtime.InteropServices; -using System.Threading.Tasks; - -using static pmcenter.Methods; +using System.Threading.Tasks; +using static pmcenter.Methods.Logging; namespace pmcenter.CommandLines { - internal class ResetCmdLine : ICmdLine + internal class ResetCmdLine : ICommandLine { public string Prefix => "reset"; public bool ExitAfterExecution => true; @@ -21,4 +18,4 @@ public async Task Process() return true; } } -} \ No newline at end of file +} diff --git a/pmcenter/CommandLines/SetupWizardCmdLine.cs b/pmcenter/CommandLines/SetupWizardCmdLine.cs index 7c64d18..993c13d 100644 --- a/pmcenter/CommandLines/SetupWizardCmdLine.cs +++ b/pmcenter/CommandLines/SetupWizardCmdLine.cs @@ -1,12 +1,9 @@ -using System; -using System.Runtime.InteropServices; -using System.Threading.Tasks; - -using static pmcenter.Methods; +using System.Threading.Tasks; +using static pmcenter.Methods.Logging; namespace pmcenter.CommandLines { - internal class SetupWizardCmdLine : ICmdLine + internal class SetupWizardCmdLine : ICommandLine { public string Prefix => "setup"; public bool ExitAfterExecution => true; @@ -18,4 +15,4 @@ public async Task Process() return true; } } -} \ No newline at end of file +} diff --git a/pmcenter/CommandLines/UpdateCmdLine.cs b/pmcenter/CommandLines/UpdateCmdLine.cs index f390e9f..fd73875 100644 --- a/pmcenter/CommandLines/UpdateCmdLine.cs +++ b/pmcenter/CommandLines/UpdateCmdLine.cs @@ -1,57 +1,32 @@ -using System; -using System.IO; -using System.IO.Compression; -using System.Net; -using System.Threading.Tasks; - -using static pmcenter.Methods; +using System.Threading.Tasks; +using static pmcenter.Methods.Logging; +using static pmcenter.Methods.UpdateHelper; namespace pmcenter.CommandLines { - internal class UpdateCmdLine : ICmdLine + internal class UpdateCmdLine : ICommandLine { public string Prefix => "update"; public bool ExitAfterExecution => true; public async Task Process() { - Log($"Application version: {Vars.AppVer.ToString()}", "CMD"); + Log($"Application version: {Vars.AppVer}", "CMD"); Log("Checking for updates...", "CMD"); Log("Custom update channels and languages are currently unsupported in command line mode, will use \"master\" channel with English.", "CMD"); - var Latest = Conf.CheckForUpdates(); - if (Conf.IsNewerVersionAvailable(Latest)) + var latest = await CheckForUpdatesAsync().ConfigureAwait(false); + if (IsNewerVersionAvailable(latest)) { - Log($"Newer version found: {Latest.Latest}, main changes:\n{Latest.UpdateCollection[0].Details}", "CMD"); + Log($"Newer version found: {latest.Latest}, main changes:\n{latest.UpdateCollection[0].Details}", "CMD"); Log("Updating...", "CMD"); - Log("Starting update download... (pmcenter_update.zip)", "CMD"); - using (var Downloader = new WebClient()) - { - await Downloader.DownloadFileTaskAsync( - new Uri(Vars.UpdateArchiveURL), - Path.Combine(Vars.AppDirectory, "pmcenter_update.zip")).ConfigureAwait(false); - Log("Download complete. Extracting...", "CMD"); - using (ZipArchive Zip = ZipFile.OpenRead(Path.Combine(Vars.AppDirectory, "pmcenter_update.zip"))) - { - foreach (ZipArchiveEntry Entry in Zip.Entries) - { - Log($"Extracting: {Path.Combine(Vars.AppDirectory, Entry.FullName)}", "CMD"); - Entry.ExtractToFile(Path.Combine(Vars.AppDirectory, Entry.FullName), true); - } - } - Log("Starting language file update...", "CMD"); - await Downloader.DownloadFileTaskAsync( - new Uri(Vars.CurrentConf.LangURL), - Path.Combine(Vars.AppDirectory, "pmcenter_locale.json") - ).ConfigureAwait(false); - } - Log("Cleaning up temporary files...", "CMD"); - File.Delete(Path.Combine(Vars.AppDirectory, "pmcenter_update.zip")); + await DownloadUpdatesAsync(latest).ConfigureAwait(false); + await DownloadLangAsync().ConfigureAwait(false); Log("Update complete.", "CMD"); } else { - Log($"No newer version found.\nCurrently installed version: {Vars.AppVer.ToString()}\nThe latest version is: {Latest.Latest}", "CMD"); + Log($"No newer version found.\nCurrently installed version: {Vars.AppVer}\nThe latest version is: {latest.Latest}", "CMD"); } return true; } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/CheckPoint.cs b/pmcenter/Configurations/CheckPoint.cs new file mode 100644 index 0000000..ca8caef --- /dev/null +++ b/pmcenter/Configurations/CheckPoint.cs @@ -0,0 +1,13 @@ +namespace pmcenter +{ + public class CheckPoint + { + public CheckPoint(long tick = 0, string name = "Unspecified") + { + Tick = tick; + Name = name; + } + public long Tick; + public string Name; + } +} diff --git a/pmcenter/Configurations/Conf.BanObj.cs b/pmcenter/Configurations/Conf.BanObj.cs index 21c837e..e6507ae 100644 --- a/pmcenter/Configurations/Conf.BanObj.cs +++ b/pmcenter/Configurations/Conf.BanObj.cs @@ -1,6 +1,6 @@ namespace pmcenter { - public partial class Conf + public static partial class Conf { public class BanObj { @@ -11,4 +11,4 @@ public BanObj() public long UID { get; set; } } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Conf.CheckForUpdates.cs b/pmcenter/Configurations/Conf.CheckForUpdates.cs deleted file mode 100644 index 59607c0..0000000 --- a/pmcenter/Configurations/Conf.CheckForUpdates.cs +++ /dev/null @@ -1,18 +0,0 @@ -using System; -using System.Net; -using Newtonsoft.Json; - -namespace pmcenter -{ - public partial class Conf - { - public static Update2 CheckForUpdates() - { - using (var Downloader = new WebClient()) - { - var Response = Downloader.DownloadString(new Uri(Vars.UpdateInfo2URL.Replace("$channel", Vars.CurrentConf == null ? "master" : Vars.CurrentConf.UpdateChannel))); - return JsonConvert.DeserializeObject(Response); - } - } - } -} \ No newline at end of file diff --git a/pmcenter/Configurations/Conf.ConfObj.New.cs b/pmcenter/Configurations/Conf.ConfObj.New.cs index 78048a2..3cc02ef 100644 --- a/pmcenter/Configurations/Conf.ConfObj.New.cs +++ b/pmcenter/Configurations/Conf.ConfObj.New.cs @@ -2,12 +2,13 @@ namespace pmcenter { - public partial class Conf + public static partial class Conf { - public partial class ConfObj + public sealed partial class ConfObj { public ConfObj() { + Minify = false; APIKey = ""; OwnerUID = -1; EnableCc = false; @@ -33,7 +34,7 @@ public ConfObj() CatchAllExceptions = false; NoStartupMessage = false; ContChatTarget = -1; - EnableMsgLink = false; + EnableMsgLink = true; AllowUserRetraction = false; ConfSyncInterval = 30000; AdvancedLogging = false; @@ -41,7 +42,13 @@ public ConfObj() UpdateChannel = "master"; IgnoreKeyboardInterrupt = false; DisableNetCore3Check = false; + DisableMessageLinkTip = false; + AnalyzeStartupTime = false; + SkipAPIKeyVerification = false; + EnableActions = false; + CheckLangVersionMismatch = true; Statistics = new Stats(); + IgnoredLogModules = new List(); Socks5Proxies = new List(); BannedKeywords = new List(); Banned = new List(); @@ -49,4 +56,4 @@ public ConfObj() } } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Conf.ConfObj.cs b/pmcenter/Configurations/Conf.ConfObj.cs index 46578cf..2cae1e0 100644 --- a/pmcenter/Configurations/Conf.ConfObj.cs +++ b/pmcenter/Configurations/Conf.ConfObj.cs @@ -2,48 +2,55 @@ namespace pmcenter { - public partial class Conf + public static partial class Conf { - public partial class ConfObj + public sealed partial class ConfObj { - public string APIKey; - public long OwnerUID; - public bool EnableCc; - public List Cc; - public bool AutoBan; - public int AutoBanThreshold; - public bool ForwardingPaused; - public bool KeywordBanning; - public bool KeywordAutoBan; - public bool EnableRegex; - public bool AutoLangUpdate; - public string LangURL; - public bool DisableNotifications; - public bool EnableRepliedConfirmation; - public bool EnableForwardedConfirmation; - public bool EnableAutoUpdateCheck; - public bool UseUsernameInMsgInfo; - public string DonateString; - public bool LowPerformanceMode; - public bool DetailedMsgLogging; - public bool UseProxy; - public bool ResolveHostnamesLocally; - public bool CatchAllExceptions; - public bool NoStartupMessage; - public long ContChatTarget; - public bool EnableMsgLink; - public bool AllowUserRetraction; - public int ConfSyncInterval; - public bool AdvancedLogging; - public bool DisableTimeDisplay; - public string UpdateChannel; - public bool IgnoreKeyboardInterrupt; - public bool DisableNetCore3Check; - public Stats Statistics; - public List Socks5Proxies; - public List BannedKeywords; - public List Banned; - public List MessageLinks; + public bool Minify { get; set; } + public string APIKey { get; set; } + public long OwnerUID { get; set; } + public bool EnableCc { get; set; } + public List Cc { get; set; } + public bool AutoBan { get; set; } + public int AutoBanThreshold { get; set; } + public bool ForwardingPaused { get; set; } + public bool KeywordBanning { get; set; } + public bool KeywordAutoBan { get; set; } + public bool EnableRegex { get; set; } + public bool AutoLangUpdate { get; set; } + public string LangURL { get; set; } + public bool DisableNotifications { get; set; } + public bool EnableRepliedConfirmation { get; set; } + public bool EnableForwardedConfirmation { get; set; } + public bool EnableAutoUpdateCheck { get; set; } + public bool UseUsernameInMsgInfo { get; set; } + public string DonateString { get; set; } + public bool LowPerformanceMode { get; set; } + public bool DetailedMsgLogging { get; set; } + public bool UseProxy { get; set; } + public bool ResolveHostnamesLocally { get; set; } + public bool CatchAllExceptions { get; set; } + public bool NoStartupMessage { get; set; } + public long ContChatTarget { get; set; } + public bool EnableMsgLink { get; set; } + public bool AllowUserRetraction { get; set; } + public int ConfSyncInterval { get; set; } + public bool AdvancedLogging { get; set; } + public bool DisableTimeDisplay { get; set; } + public string UpdateChannel { get; set; } + public bool IgnoreKeyboardInterrupt { get; set; } + public bool DisableNetCore3Check { get; set; } + public bool DisableMessageLinkTip { get; set; } + public bool AnalyzeStartupTime { get; set; } + public bool SkipAPIKeyVerification { get; set; } + public bool EnableActions { get; set; } + public bool CheckLangVersionMismatch { get; set; } + public Stats Statistics { get; set; } + public List IgnoredLogModules { get; set; } + public List Socks5Proxies { get; set; } + public List BannedKeywords { get; set; } + public List Banned { get; set; } + public List MessageLinks { get; set; } } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Conf.GetConf.cs b/pmcenter/Configurations/Conf.GetConf.cs index f6f5aba..985c356 100644 --- a/pmcenter/Configurations/Conf.GetConf.cs +++ b/pmcenter/Configurations/Conf.GetConf.cs @@ -1,14 +1,15 @@ -using System.Threading.Tasks; using Newtonsoft.Json; +using System.IO; +using System.Threading.Tasks; namespace pmcenter { - public partial class Conf + public static partial class Conf { - public static async Task GetConf(string Filename) + public static async Task GetConf(string filename) { - var SettingsText = await System.IO.File.ReadAllTextAsync(Filename).ConfigureAwait(false); - return JsonConvert.DeserializeObject(SettingsText); + var settingsText = await File.ReadAllTextAsync(filename).ConfigureAwait(false); + return JsonConvert.DeserializeObject(settingsText); } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Conf.GetUpdateInfoIndexByLocale.cs b/pmcenter/Configurations/Conf.GetUpdateInfoIndexByLocale.cs deleted file mode 100644 index 6a6f304..0000000 --- a/pmcenter/Configurations/Conf.GetUpdateInfoIndexByLocale.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; - -namespace pmcenter -{ - public partial class Conf - { - public static int GetUpdateInfoIndexByLocale(Update2 Update, string Locale) - { - List indexes = new List(); - for (int i = 0; i < Update.UpdateCollection.Count; i++) - { - if (Update.UpdateCollection[i].LangCode.Contains(Locale)) indexes.Add(i); - } - if (indexes.Count == 0) return 0; - foreach (int i in indexes) - { - if (Update.UpdateCollection[i].UpdateChannel == Vars.CurrentConf.UpdateChannel) return i; - } - return indexes[0]; - } - } -} \ No newline at end of file diff --git a/pmcenter/Configurations/Conf.InitConf.cs b/pmcenter/Configurations/Conf.InitConf.cs index c5cf80a..55d6d33 100644 --- a/pmcenter/Configurations/Conf.InitConf.cs +++ b/pmcenter/Configurations/Conf.InitConf.cs @@ -1,17 +1,18 @@ using System; +using System.IO; using System.Threading.Tasks; -using static pmcenter.Methods; +using static pmcenter.Methods.Logging; namespace pmcenter { - public partial class Conf + public static partial class Conf { public static async Task InitConf() { Log("Checking configurations file's integrity...", "CONF"); - if (!System.IO.File.Exists(Vars.ConfFile)) + if (!File.Exists(Vars.ConfFile)) { // STEP 1, DETECT EXISTENCE. - Log("Configurations file not found. Creating...", "CONF", LogLevel.WARN); + Log("Configurations file not found. Creating...", "CONF", LogLevel.Warning); Vars.CurrentConf = new ConfObj(); _ = await SaveConf(true).ConfigureAwait(false); // Then the app will exit, do nothing. } @@ -23,9 +24,9 @@ public static async Task InitConf() } catch (Exception ex) { - Log($"Error! {ex.ToString()}", "CONF", LogLevel.ERROR); - Log("Moving old configurations file to \"pmcenter.json.bak\"...", "CONF", LogLevel.WARN); - System.IO.File.Move(Vars.ConfFile, Vars.ConfFile + ".bak"); + Log($"Error! {ex}", "CONF", LogLevel.Error); + Log("Moving old configurations file to \"pmcenter.json.bak\"...", "CONF", LogLevel.Warning); + File.Move(Vars.ConfFile, Vars.ConfFile + ".bak"); Vars.CurrentConf = new ConfObj(); _ = await SaveConf(true).ConfigureAwait(false); // Then the app will exit, do nothing. } @@ -33,4 +34,4 @@ public static async Task InitConf() Log("Integrity test finished!", "CONF"); } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Conf.IsNewerVersionAvailable.cs b/pmcenter/Configurations/Conf.IsNewerVersionAvailable.cs deleted file mode 100644 index c1fa933..0000000 --- a/pmcenter/Configurations/Conf.IsNewerVersionAvailable.cs +++ /dev/null @@ -1,21 +0,0 @@ -using System; - -namespace pmcenter -{ - public partial class Conf - { - public static bool IsNewerVersionAvailable(Update2 CurrentUpdate) - { - var CurrentVersion = Vars.AppVer; - var CurrentLatest = new Version(CurrentUpdate.Latest); - if (CurrentLatest > CurrentVersion) - { - return true; - } - else - { - return false; - } - } - } -} \ No newline at end of file diff --git a/pmcenter/Configurations/Conf.KillIllegalChars.cs b/pmcenter/Configurations/Conf.KillIllegalChars.cs index b053fc5..8c437c4 100644 --- a/pmcenter/Configurations/Conf.KillIllegalChars.cs +++ b/pmcenter/Configurations/Conf.KillIllegalChars.cs @@ -1,10 +1,10 @@ namespace pmcenter { - public partial class Conf + public static partial class Conf { - public static string KillIllegalChars(string Input) + public static string KillIllegalChars(string input) { - return Input.Replace("/", "-").Replace("<", "-").Replace(">", "-").Replace(":", "-").Replace("\"", "-").Replace("/", "-").Replace("\\", "-").Replace("|", "-").Replace("?", "-").Replace("*", "-"); + return input.Replace("/", "-").Replace("<", "-").Replace(">", "-").Replace(":", "-").Replace("\"", "-").Replace("/", "-").Replace("\\", "-").Replace("|", "-").Replace("?", "-").Replace("*", "-"); } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Conf.LocaleList.cs b/pmcenter/Configurations/Conf.LocaleList.cs index 96a47b0..4b94735 100644 --- a/pmcenter/Configurations/Conf.LocaleList.cs +++ b/pmcenter/Configurations/Conf.LocaleList.cs @@ -2,7 +2,7 @@ namespace pmcenter { - public partial class Conf + public static partial class Conf { public class LocaleList { @@ -13,4 +13,4 @@ public LocaleList() public List Locales { get; set; } } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Conf.LocaleMirror.cs b/pmcenter/Configurations/Conf.LocaleMirror.cs index a85ae9f..bda44f4 100644 --- a/pmcenter/Configurations/Conf.LocaleMirror.cs +++ b/pmcenter/Configurations/Conf.LocaleMirror.cs @@ -1,6 +1,6 @@ namespace pmcenter { - public partial class Conf + public static partial class Conf { public class LocaleMirror { @@ -17,4 +17,4 @@ public LocaleMirror() public string LocaleNameNative { get; set; } } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Conf.MessageIDLink.cs b/pmcenter/Configurations/Conf.MessageIDLink.cs index 0d5980d..47208a7 100644 --- a/pmcenter/Configurations/Conf.MessageIDLink.cs +++ b/pmcenter/Configurations/Conf.MessageIDLink.cs @@ -2,7 +2,7 @@ namespace pmcenter { - public partial class Conf + public static partial class Conf { public class MessageIDLink { @@ -10,6 +10,7 @@ public MessageIDLink() { TGUser = null; OwnerSessionMessageID = -1; + OwnerSessionActionMessageID = -1; UserSessionMessageID = -1; IsFromOwner = false; } @@ -18,8 +19,9 @@ public MessageIDLink() /// Message ID of the message in owner's session /// public int OwnerSessionMessageID { get; set; } + public int OwnerSessionActionMessageID { get; set; } public int UserSessionMessageID { get; set; } public bool IsFromOwner { get; set; } } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Conf.RateData.cs b/pmcenter/Configurations/Conf.RateData.cs index 6866ae3..42f77dd 100644 --- a/pmcenter/Configurations/Conf.RateData.cs +++ b/pmcenter/Configurations/Conf.RateData.cs @@ -1,6 +1,6 @@ namespace pmcenter { - public partial class Conf + public static partial class Conf { public class RateData { @@ -13,4 +13,4 @@ public RateData() public int MessageCount { get; set; } } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Conf.ReadConf.cs b/pmcenter/Configurations/Conf.ReadConf.cs index 6d702f8..36ab75f 100644 --- a/pmcenter/Configurations/Conf.ReadConf.cs +++ b/pmcenter/Configurations/Conf.ReadConf.cs @@ -2,13 +2,13 @@ namespace pmcenter { - public partial class Conf + public static partial class Conf { - public static async Task ReadConf(bool Apply = true) + public static async Task ReadConf(bool apply = true) { // DO NOT HANDLE ERRORS HERE. THE CALLING METHOD WILL HANDLE THEM. - var Temp = await GetConf(Vars.ConfFile).ConfigureAwait(false); - if (Apply) { Vars.CurrentConf = Temp; } + var temp = await GetConf(Vars.ConfFile).ConfigureAwait(false); + if (apply) { Vars.CurrentConf = temp; } return true; } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Conf.SaveConf.cs b/pmcenter/Configurations/Conf.SaveConf.cs index a5d39c6..1a35dbc 100644 --- a/pmcenter/Configurations/Conf.SaveConf.cs +++ b/pmcenter/Configurations/Conf.SaveConf.cs @@ -1,27 +1,27 @@ -using System.Collections.Generic; -using System.Threading.Tasks; using Newtonsoft.Json; -using static pmcenter.Methods; +using System.IO; +using System.Threading.Tasks; +using static pmcenter.Methods.Logging; namespace pmcenter { - public partial class Conf + public static partial class Conf { - public static async Task SaveConf(bool IsInvalid = false, bool IsAutoSave = false) + public static async Task SaveConf(bool isInvalid = false, bool isAutoSave = false) { // DO NOT HANDLE ERRORS HERE. - string Text = JsonConvert.SerializeObject(Vars.CurrentConf, Formatting.Indented); - await System.IO.File.WriteAllTextAsync(Vars.ConfFile, Text).ConfigureAwait(false); - if (IsAutoSave) + string text = JsonConvert.SerializeObject(Vars.CurrentConf, Vars.CurrentConf.Minify ? Formatting.None : Formatting.Indented); + await File.WriteAllTextAsync(Vars.ConfFile, text).ConfigureAwait(false); + if (isAutoSave) { Log("Autosave complete.", "CONF"); } - if (IsInvalid) + if (isInvalid) { - Log("We've detected an invalid configurations file and have reset it.", "CONF", LogLevel.WARN); - Log("Please reconfigure it and try to start pmcenter again.", "CONF", LogLevel.WARN); + Log("We've detected an invalid configurations file and have reset it.", "CONF", LogLevel.Warning); + Log("Please reconfigure it and try to start pmcenter again.", "CONF", LogLevel.Warning); Vars.RestartRequired = true; } return true; } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Conf.Socks5Proxy.cs b/pmcenter/Configurations/Conf.Socks5Proxy.cs index 3004474..0bb3491 100644 --- a/pmcenter/Configurations/Conf.Socks5Proxy.cs +++ b/pmcenter/Configurations/Conf.Socks5Proxy.cs @@ -1,6 +1,6 @@ namespace pmcenter { - public partial class Conf + public static partial class Conf { public class Socks5Proxy { @@ -17,4 +17,4 @@ public Socks5Proxy() public string ProxyPass { get; set; } } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Conf.Stats.cs b/pmcenter/Configurations/Conf.Stats.cs index 5332159..f0134dd 100644 --- a/pmcenter/Configurations/Conf.Stats.cs +++ b/pmcenter/Configurations/Conf.Stats.cs @@ -1,6 +1,6 @@ namespace pmcenter { - public partial class Conf + public static partial class Conf { public class Stats { @@ -17,4 +17,4 @@ public Stats() public int TotalForwardedFromOwner { get; set; } } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Conf.SwitchBlocking.cs b/pmcenter/Configurations/Conf.SwitchBlocking.cs index 4790685..423f9a3 100644 --- a/pmcenter/Configurations/Conf.SwitchBlocking.cs +++ b/pmcenter/Configurations/Conf.SwitchBlocking.cs @@ -1,6 +1,6 @@ namespace pmcenter { - public partial class Conf + public static partial class Conf { /// /// Switch 'blocking' status, returning current status. @@ -20,4 +20,4 @@ public static bool SwitchBlocking() } } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Conf.SwitchNotifications.cs b/pmcenter/Configurations/Conf.SwitchNotifications.cs index d2bd8e3..f859f1d 100644 --- a/pmcenter/Configurations/Conf.SwitchNotifications.cs +++ b/pmcenter/Configurations/Conf.SwitchNotifications.cs @@ -1,6 +1,6 @@ namespace pmcenter { - public partial class Conf + public static partial class Conf { /// /// Switch 'disablenotifications' status, returning current status. @@ -20,4 +20,4 @@ public static bool SwitchNotifications() } } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Conf.SwitchPaused.cs b/pmcenter/Configurations/Conf.SwitchPaused.cs index f36c618..a39b4f4 100644 --- a/pmcenter/Configurations/Conf.SwitchPaused.cs +++ b/pmcenter/Configurations/Conf.SwitchPaused.cs @@ -1,6 +1,6 @@ namespace pmcenter { - public partial class Conf + public static partial class Conf { /// /// Switch 'forwarding' status, returning current status. @@ -20,4 +20,4 @@ public static bool SwitchPaused() } } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Conf.Update.cs b/pmcenter/Configurations/Conf.Update.cs deleted file mode 100644 index ba5e310..0000000 --- a/pmcenter/Configurations/Conf.Update.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System.Collections.Generic; - -namespace pmcenter -{ - public partial class Conf - { - public class Update - { - public Update() - { - Details = "(Load failed.)"; - LangCode = new List() { "en.integrated" }; - UpdateChannel = "master"; - UpdateArchiveAddress = "https://see.wtf/pmcenter-update"; - } - public string Details; - public List LangCode; - public string UpdateChannel; - public string UpdateArchiveAddress; - } - } -} \ No newline at end of file diff --git a/pmcenter/Configurations/Conf.Update2.cs b/pmcenter/Configurations/Conf.Update2.cs deleted file mode 100644 index 490df5c..0000000 --- a/pmcenter/Configurations/Conf.Update2.cs +++ /dev/null @@ -1,20 +0,0 @@ -using System.Collections.Generic; - -namespace pmcenter -{ - public partial class Conf - { - public class Update2 - { - public Update2() - { - Latest = "0.0.0.0"; - UpdateLevel = UpdateLevel.Optional; - UpdateCollection = new List(); - } - public string Latest; - public UpdateLevel UpdateLevel; - public List UpdateCollection; - } - } -} \ No newline at end of file diff --git a/pmcenter/Configurations/Conf.UpdateLevel.cs b/pmcenter/Configurations/Conf.UpdateLevel.cs deleted file mode 100644 index ad07b0e..0000000 --- a/pmcenter/Configurations/Conf.UpdateLevel.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace pmcenter -{ - public partial class Conf - { - public enum UpdateLevel - { - Optional = 0, - Recommended = 1, - Important = 2, - Urgent = 3, - } - } -} \ No newline at end of file diff --git a/pmcenter/Configurations/Lang.InitLang.cs b/pmcenter/Configurations/Lang.InitLang.cs index 64f9c19..8c56fe8 100644 --- a/pmcenter/Configurations/Lang.InitLang.cs +++ b/pmcenter/Configurations/Lang.InitLang.cs @@ -1,18 +1,18 @@ using System; using System.IO; using System.Threading.Tasks; -using static pmcenter.Methods; +using static pmcenter.Methods.Logging; namespace pmcenter { - public partial class Lang + public static partial class Lang { public static async Task InitLang() { Log("Checking language file's integrity...", "LANG"); if (!File.Exists(Vars.LangFile)) { // STEP 1, DETECT EXISTENCE. - Log("Language file not found. Creating...", "LANG", LogLevel.WARN); + Log("Language file not found. Creating...", "LANG", LogLevel.Warning); Vars.CurrentLang = new Language(); _ = await SaveLang(true).ConfigureAwait(false); // Then the app will exit, do nothing. } @@ -24,8 +24,8 @@ public static async Task InitLang() } catch (Exception ex) { - Log($"Error! {ex.ToString()}", "LANG", LogLevel.ERROR); - Log("Moving old language file to \"pmcenter_locale.json.bak\"...", "LANG", LogLevel.WARN); + Log($"Error! {ex}", "LANG", LogLevel.Error); + Log("Moving old language file to \"pmcenter_locale.json.bak\"...", "LANG", LogLevel.Warning); File.Move(Vars.LangFile, Vars.LangFile + ".bak"); Vars.CurrentLang = new Language(); _ = await SaveLang(true).ConfigureAwait(false); // Then the app will exit, do nothing. @@ -34,4 +34,4 @@ public static async Task InitLang() Log("Integrity test finished!", "LANG"); } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Lang.Language.New.cs b/pmcenter/Configurations/Lang.Language.New.cs index c4616ff..8514592 100644 --- a/pmcenter/Configurations/Lang.Language.New.cs +++ b/pmcenter/Configurations/Lang.Language.New.cs @@ -1,8 +1,8 @@ namespace pmcenter { - public partial class Lang + public static partial class Lang { - public partial class Language + public sealed partial class Language { public Language() { @@ -12,7 +12,7 @@ public Language() LanguageNameInNative = "English"; Message_CommandNotReplying = "😶 Don't talk to me, spend time chatting with those who love you."; Message_CommandNotReplyingValidMessage = "😐 Speaking to me makes no sense."; - Message_Help = "❓ `pmcenter` *Bot Help*\n/start - Display welcome message.\n/info - Display the message's info.\n/ban - Restrict the user from contacting you.\n/banid - Restrict a user from contacting you with his/her ID.\n/pardon - Pardon the user.\n/pardonid - Pardon a user with his/her ID.\n/ping - Test if the bot is working.\n/switchfw - Pause/Resume message forwarding.\n/switchbw - Enable/Disable keyword banning.\n/switchnf - Enable/Disable notifications.\n/switchlang - Switch language file.\n/switchlangcode [Code] - Switch language with language code.\n/detectperm - Detect permissions.\n/backup - Backup configurations.\n/editconf - Manually edit settings w/ JSON-formatted text.\n/saveconf - Manually save all settings and translations. Especially useful after upgrades.\n/readconf - Reload configurations without restarting bot.\n/resetconf - Reset configurations.\n/uptime - Check system uptime information.\n/update - Check for updates and update bot.\n/chkupdate - Only check for updates.\n/catconf - Get your current configurations.\n/restart - Restart bot.\n/status - Get host device's status information.\n/perform - Run performance test.\n/testnetwork - Test latency to servers used by pmcenter.\n/chat - Enter Continued Conversation mode.\n/stopchat - Leave Continued Conversation mode.\n/retract - Retract a message.\n/clearmessagelinks - Clear message links.\n/getstats - Get statistics data.\n/help - Display this message.\n\nThank you for using `pmcenter`!"; + Message_Help = "❓ `pmcenter` *Bot Help*\n/start - Display welcome message.\n/info - Display the message's info.\n/ban - Restrict the user from contacting you.\n/banid - Restrict a user from contacting you with his/her ID.\n/pardon - Pardon the user.\n/pardonid - Pardon a user with his/her ID.\n/ping - Test if the bot is working.\n/switchfw - Pause/Resume message forwarding.\n/switchbw - Enable/Disable keyword banning.\n/switchnf - Enable/Disable notifications.\n/switchlang - Switch language file.\n/switchlangcode [Code] - Switch language with language code.\n/detectperm - Detect permissions.\n/backup - Backup configurations.\n/editconf - Manually edit settings w/ JSON-formatted text.\n/saveconf - Manually save all settings and translations. Especially useful after upgrades.\n/readconf - Reload configurations without restarting bot.\n/resetconf - Reset configurations.\n/uptime - Check system uptime information.\n/update - Check for updates and update bot.\n/chkupdate - Only check for updates.\n/catconf - Get your current configurations.\n/restart - Restart bot.\n/status - Get host device's status information.\n/perform - Run performance test.\n/testnetwork - Test latency to servers used by pmcenter.\n/chat - Enter Continued Conversation mode.\n/stopchat - Leave Continued Conversation mode.\n/retract - Retract a message.\n/clearmessagelinks - Clear message links.\n/getstats - Get statistics data.\n/autosave [off/interval] - Switch autosave status.\n/help - Display this message.\n\nThank you for using `pmcenter`!"; Message_OwnerStart = "😊 *Hi!* I'm your `pmcenter` bot, and I work just for you.\nThis message means that you've set up the bot successfully.\nTo reply to any forwarded messages, just directly reply to them here.\n\nThank you for using the `pmcenter` bot!"; Message_ReplySuccessful = "✅ Successfully replied to user $1!"; Message_ForwardedToOwner = "✅ Your message has been forwarded to my owner!"; @@ -78,7 +78,23 @@ public Language() Message_MsgLinksCleared = "✅ All message links have been cleared."; Message_AvailableLang = "ℹ *Available languages*\n\n`$1`"; Message_NetCore31Required = "⚠ You need `.NET Core 3.1` (runtime) installed in order to receive pmcenter v2 and further updates.\n\nLatest .NET Core runtime version detected on your device: `$1`\n\nThis warning will only show once."; + Message_MsgLinkTip = "ℹ Tip: You need to set `EnableMsgLink` option to `true` in pmcenter configurations in order to reply to anonymously forwarded messages.\nThis also happens when the message link for the message couldn't be found.\nDue to Telegram API's restrictions, it's impossible now to reply to that message.\nAfter you set `EnableMsgLink` to `true`, you'll be able to reply to this kind of messages.\n\nThis tip will only prompt once."; + Message_AutoSaveEnabled = "✅ Autosave *enabled*, interval: `$1s`."; + Message_AutoSaveIntervalTooShort = "⚠ The current autosave interval (`$1ms`) is *too short*! It may cause high CPU and disk usage as a result. *Disable it if you didn't intend to do that!*"; + Message_AutoSaveDisabled = "✅ Autosave *disabled*."; + Message_Action_Banned = "✅ User $1 has been banned!"; + Message_Action_Pardoned = "✅ User $1 has been pardoned!"; + Message_Action_ContChatEnabled = "✅ You're now chatting with $1!"; + Message_Action_ContChatDisabled = "✅ Continued chat disabled!"; + Message_Action_Error = "✖ Action failed. Check logs."; + Message_Action_ErrorWithDetails = "✖ Action failed: $1"; + Message_Action_ChooseAction = "❓ *What do you want to do with this message?*"; + Message_Action_Ban = "✖ Ban the user"; + Message_Action_Pardon = "✅ Pardon the user"; + Message_Action_Chat = "💬 Enter continued conversation"; + Message_Action_StopChat = "💬 Stop continued conversation"; + Message_Action_LinkNotFound = "✖ Cannot find the corresponding message link, did you just clear the message links, or was the message links feature disabled?"; } } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Lang.Language.cs b/pmcenter/Configurations/Lang.Language.cs index 20dee04..8349cd0 100644 --- a/pmcenter/Configurations/Lang.Language.cs +++ b/pmcenter/Configurations/Lang.Language.cs @@ -1,81 +1,97 @@ namespace pmcenter { - public partial class Lang + public static partial class Lang { - public partial class Language + public sealed partial class Language { - public string TargetVersion; - public string LangCode; - public string LanguageNameInEnglish; - public string LanguageNameInNative; - public string Message_OwnerStart; - public string Message_UserStartDefault; - public string Message_ReplySuccessful; - public string Message_ForwardedToOwner; - public string Message_Help; - public string Message_UserBanned; - public string Message_UserPardoned; - public string Message_CommandNotReplying; - public string Message_CommandNotReplyingValidMessage; - public string Message_PingReply; - public string Message_ServicePaused; - public string Message_ServiceResumed; - public string Message_UserServicePaused; - public string Message_BotStarted; - public string Message_MessageBlockEnabled; - public string Message_MessageBlockDisabled; - public string Message_ConfigUpdated; - public string Message_ConfigReloaded; - public string Message_UptimeInfo; - public string Message_UpdateAvailable; - public string Message_UpdateProcessing; - public string Message_UpdateCheckFailed; - public string Message_AlreadyUpToDate; - public string Message_UpdateExtracting; - public string Message_UpdateFinalizing; - public string Message_CurrentConf; - public string Message_SysStatus_Header; - public string Message_SysStatus_RestartRequired; - public string Message_SysStatus_PendingUpdate; - public string Message_SysStatus_UpdateLevel_Template; - public string Message_SysStatus_UpdateLevel_Optional; - public string Message_SysStatus_UpdateLevel_Recommended; - public string Message_SysStatus_UpdateLevel_Important; - public string Message_SysStatus_UpdateLevel_Urgent; - public string Message_SysStatus_UpdateLevel_Unknown; - public string Message_SysStatus_NoOperationRequired; - public string Message_SysStatus_Summary; - public string Message_Restarting; - public string Message_NotificationsOff; - public string Message_NotificationsOn; - public string Message_SupportTextMessagesOnly; - public string Message_ForwarderNotReal; - public string Message_GeneralFailure; - public string Message_LangVerMismatch; - public string Message_SwitchingLang; - public string Message_LangSwitched; - public string Message_ThreadStatus_Unknown; - public string Message_ThreadStatus_Standby; - public string Message_ThreadStatus_Working; - public string Message_ThreadStatus_Stopped; - public string Message_ThreadStatus_Error; - public string Message_ConfReset_Inited; - public string Message_ConfReset_Started; - public string Message_ConfReset_Done; - public string Message_Performance_Inited; - public string Message_Performance_Results; - public string Message_BackupComplete; - public string Message_ConfAccess; - public string Message_APIKeyChanged; - public string Message_Connectivity; - public string Message_ContinuedChatEnabled; - public string Message_ContinuedChatDisabled; - public string Message_FeatureNotAvailable; - public string Message_Stats; - public string Message_Retracted; - public string Message_MsgLinksCleared; - public string Message_AvailableLang; - public string Message_NetCore31Required; + public string TargetVersion { get; set; } + public string LangCode { get; set; } + public string LanguageNameInEnglish { get; set; } + public string LanguageNameInNative { get; set; } + public string Message_OwnerStart { get; set; } + public string Message_UserStartDefault { get; set; } + public string Message_ReplySuccessful { get; set; } + public string Message_ForwardedToOwner { get; set; } + public string Message_Help { get; set; } + public string Message_UserBanned { get; set; } + public string Message_UserPardoned { get; set; } + public string Message_CommandNotReplying { get; set; } + public string Message_CommandNotReplyingValidMessage { get; set; } + public string Message_PingReply { get; set; } + public string Message_ServicePaused { get; set; } + public string Message_ServiceResumed { get; set; } + public string Message_UserServicePaused { get; set; } + public string Message_BotStarted { get; set; } + public string Message_MessageBlockEnabled { get; set; } + public string Message_MessageBlockDisabled { get; set; } + public string Message_ConfigUpdated { get; set; } + public string Message_ConfigReloaded { get; set; } + public string Message_UptimeInfo { get; set; } + public string Message_UpdateAvailable { get; set; } + public string Message_UpdateProcessing { get; set; } + public string Message_UpdateCheckFailed { get; set; } + public string Message_AlreadyUpToDate { get; set; } + public string Message_UpdateExtracting { get; set; } + public string Message_UpdateFinalizing { get; set; } + public string Message_CurrentConf { get; set; } + public string Message_SysStatus_Header { get; set; } + public string Message_SysStatus_RestartRequired { get; set; } + public string Message_SysStatus_PendingUpdate { get; set; } + public string Message_SysStatus_UpdateLevel_Template { get; set; } + public string Message_SysStatus_UpdateLevel_Optional { get; set; } + public string Message_SysStatus_UpdateLevel_Recommended { get; set; } + public string Message_SysStatus_UpdateLevel_Important { get; set; } + public string Message_SysStatus_UpdateLevel_Urgent { get; set; } + public string Message_SysStatus_UpdateLevel_Unknown { get; set; } + public string Message_SysStatus_NoOperationRequired { get; set; } + public string Message_SysStatus_Summary { get; set; } + public string Message_Restarting { get; set; } + public string Message_NotificationsOff { get; set; } + public string Message_NotificationsOn { get; set; } + public string Message_SupportTextMessagesOnly { get; set; } + public string Message_ForwarderNotReal { get; set; } + public string Message_GeneralFailure { get; set; } + public string Message_LangVerMismatch { get; set; } + public string Message_SwitchingLang { get; set; } + public string Message_LangSwitched { get; set; } + public string Message_ThreadStatus_Unknown { get; set; } + public string Message_ThreadStatus_Standby { get; set; } + public string Message_ThreadStatus_Working { get; set; } + public string Message_ThreadStatus_Stopped { get; set; } + public string Message_ThreadStatus_Error { get; set; } + public string Message_ConfReset_Inited { get; set; } + public string Message_ConfReset_Started { get; set; } + public string Message_ConfReset_Done { get; set; } + public string Message_Performance_Inited { get; set; } + public string Message_Performance_Results { get; set; } + public string Message_BackupComplete { get; set; } + public string Message_ConfAccess { get; set; } + public string Message_APIKeyChanged { get; set; } + public string Message_Connectivity { get; set; } + public string Message_ContinuedChatEnabled { get; set; } + public string Message_ContinuedChatDisabled { get; set; } + public string Message_FeatureNotAvailable { get; set; } + public string Message_Stats { get; set; } + public string Message_Retracted { get; set; } + public string Message_MsgLinksCleared { get; set; } + public string Message_AvailableLang { get; set; } + public string Message_NetCore31Required { get; set; } + public string Message_MsgLinkTip { get; set; } + public string Message_AutoSaveEnabled { get; set; } + public string Message_AutoSaveIntervalTooShort { get; set; } + public string Message_AutoSaveDisabled { get; set; } + public string Message_Action_Banned { get; set; } + public string Message_Action_Pardoned { get; set; } + public string Message_Action_ContChatEnabled { get; set; } + public string Message_Action_ContChatDisabled { get; set; } + public string Message_Action_Error { get; set; } + public string Message_Action_ErrorWithDetails { get; set; } + public string Message_Action_ChooseAction { get; set; } + public string Message_Action_Ban { get; set; } + public string Message_Action_Pardon { get; set; } + public string Message_Action_Chat { get; set; } + public string Message_Action_StopChat { get; set; } + public string Message_Action_LinkNotFound { get; set; } } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Lang.ReadLang.cs b/pmcenter/Configurations/Lang.ReadLang.cs index a1969d8..a9f5bfb 100644 --- a/pmcenter/Configurations/Lang.ReadLang.cs +++ b/pmcenter/Configurations/Lang.ReadLang.cs @@ -1,17 +1,17 @@ +using Newtonsoft.Json; using System.IO; using System.Threading.Tasks; -using Newtonsoft.Json; namespace pmcenter { - public partial class Lang + public static partial class Lang { - public static async Task ReadLang(bool Apply = true) + public static async Task ReadLang(bool apply = true) { // DO NOT HANDLE ERRORS HERE. THE CALLING METHOD WILL HANDLE THEM. - var SettingsText = await File.ReadAllTextAsync(Vars.LangFile).ConfigureAwait(false); - var Temp = JsonConvert.DeserializeObject(SettingsText); - if (Apply) { Vars.CurrentLang = Temp; } + var langText = await File.ReadAllTextAsync(Vars.LangFile).ConfigureAwait(false); + var temp = JsonConvert.DeserializeObject(langText); + if (apply) { Vars.CurrentLang = temp; } return true; } } -} \ No newline at end of file +} diff --git a/pmcenter/Configurations/Lang.SaveLang.cs b/pmcenter/Configurations/Lang.SaveLang.cs index 8d16717..30d95ba 100644 --- a/pmcenter/Configurations/Lang.SaveLang.cs +++ b/pmcenter/Configurations/Lang.SaveLang.cs @@ -1,26 +1,26 @@ +using Newtonsoft.Json; using System.IO; using System.Threading.Tasks; -using Newtonsoft.Json; -using static pmcenter.Methods; +using static pmcenter.Methods.Logging; namespace pmcenter { - public partial class Lang + public static partial class Lang { - public static async Task SaveLang(bool IsInvalid = false) + public static async Task SaveLang(bool isInvalid = false) { // DO NOT HANDLE ERRORS HERE. - var Text = JsonConvert.SerializeObject(Vars.CurrentLang, Formatting.Indented); - var Writer = new StreamWriter(File.Create(Vars.LangFile), System.Text.Encoding.UTF8); - await Writer.WriteAsync(Text).ConfigureAwait(false); - await Writer.FlushAsync().ConfigureAwait(false); - Writer.Close(); - if (IsInvalid) + var text = JsonConvert.SerializeObject(Vars.CurrentLang, Formatting.Indented); + var writer = new StreamWriter(File.Create(Vars.LangFile), System.Text.Encoding.UTF8); + await writer.WriteAsync(text).ConfigureAwait(false); + await writer.FlushAsync().ConfigureAwait(false); + writer.Close(); + if (isInvalid) { - Log("We've detected an invalid language file and have reset it.", "LANG", LogLevel.WARN); - Log("Please reconfigure it and try to start pmcenter again.", "LANG", LogLevel.WARN); + Log("We've detected an invalid language file and have reset it.", "LANG", LogLevel.Warning); + Log("Please reconfigure it and try to start pmcenter again.", "LANG", LogLevel.Warning); Vars.RestartRequired = true; } return true; } } -} \ No newline at end of file +} diff --git a/pmcenter/EventHandlers/CtrlCHandler.cs b/pmcenter/EventHandlers/CtrlCHandler.cs index ecefddd..8c9dd63 100644 --- a/pmcenter/EventHandlers/CtrlCHandler.cs +++ b/pmcenter/EventHandlers/CtrlCHandler.cs @@ -1,29 +1,30 @@ using System; using static pmcenter.Methods; +using static pmcenter.Methods.Logging; namespace pmcenter { - public partial class EventHandlers + public static partial class EventHandlers { - public static void CtrlCHandler(object sender, ConsoleCancelEventArgs e) + public static async void CtrlCHandler(object sender, ConsoleCancelEventArgs e) { + if (e != null) e.Cancel = true; Vars.CtrlCCounter++; if (Vars.CtrlCCounter > 3) { - Log("More than 3 interrupts has received, terminating...", Type: LogLevel.WARN); + Log("More than 3 interrupts has received, terminating...", LogLevel.Warning); Environment.Exit(137); } if (Vars.IsCtrlCHandled) return; if (Vars.CurrentConf.IgnoreKeyboardInterrupt) { - Log("Keyboard interrupt is currently being ignored. To change this behavior, set \"IgnoreKeyboardInterrupt\" key to \"false\" in pmcenter configurations.", Type: LogLevel.WARN); - e.Cancel = true; + Log("Keyboard interrupt is currently being ignored. To change this behavior, set \"IgnoreKeyboardInterrupt\" key to \"false\" in pmcenter configurations.", LogLevel.Warning); return; } Vars.IsCtrlCHandled = true; - Log("Interrupt! pmcenter is exiting..."); + Log("Interrupt! pmcenter is exiting...", LogLevel.Warning); Log("If pmcenter was unresponsive, press Ctrl-C 3 more times."); - ExitApp(130); + await ExitApp(130); } } -} \ No newline at end of file +} diff --git a/pmcenter/EventHandlers/GlobalErrorHandler.cs b/pmcenter/EventHandlers/GlobalErrorHandler.cs index 6811a26..6bd05f4 100644 --- a/pmcenter/EventHandlers/GlobalErrorHandler.cs +++ b/pmcenter/EventHandlers/GlobalErrorHandler.cs @@ -6,7 +6,7 @@ namespace pmcenter { - public partial class EventHandlers + public static partial class EventHandlers { public static void GlobalErrorHandler(object sender, UnhandledExceptionEventArgs e) { @@ -14,10 +14,9 @@ public static void GlobalErrorHandler(object sender, UnhandledExceptionEventArgs L("pmcenter's global error handler has captured a critical error."); L("If you believe that this is a bug, feel free to open an issue with the details below on pmcenter's GitHub repository at:"); L("https://github.com/Elepover/pmcenter"); - L(e.IsTerminating ? "" : "This is not a catastrophic. pmcenter will keep running.\nIf you encounter more errors, please consider restarting pmcenter."); - var exception = (Exception) e.ExceptionObject; + var exception = e != null ? (Exception)e.ExceptionObject : new Exception("unknown error"); var fileName = Path.Combine(Environment.CurrentDirectory, $"pmcenter-error-{GetDateTimeString(true)}.log"); - L($"Exception details: {exception.ToString()}"); + L($"Exception details: {exception}"); L($"Attempting to write to {fileName}"); try { @@ -25,19 +24,15 @@ public static void GlobalErrorHandler(object sender, UnhandledExceptionEventArgs writer.WriteLine($"pmcenter critical error log @{GetDateTimeString()} (local time)"); writer.WriteLine($"Framework: {RuntimeInformation.FrameworkDescription}\nSystem: {RuntimeInformation.OSDescription}"); writer.WriteLine("If you believe that this is a bug, feel free to open an issue with the details below on pmcenter's GitHub repository at https://github.com/Elepover/pmcenter"); - writer.WriteLine($"==> HRESULT 0x{exception.HResult.ToString("x")} error details:"); + writer.WriteLine($"==> HRESULT 0x{exception.HResult:x} error details:"); writer.WriteLine(exception.ToString()); writer.Close(); } catch (Exception ex) { - L($"Unable to save error logs: {ex.ToString()}"); - } - if (e.IsTerminating) - { - L("Since it's a catastrophic error, pmcenter will exit now."); - Environment.Exit(Marshal.GetHRForException(exception)); + L($"Unable to save error logs: {ex}"); } + Environment.Exit(Marshal.GetHRForException(exception)); } private static void L(string log) @@ -46,4 +41,4 @@ private static void L(string log) Console.Error.WriteLine(log); } } -} \ No newline at end of file +} diff --git a/pmcenter/Interfaces/ICommand.cs b/pmcenter/Interfaces/IBotCommand.cs similarity index 92% rename from pmcenter/Interfaces/ICommand.cs rename to pmcenter/Interfaces/IBotCommand.cs index 8b47096..b58ab18 100644 --- a/pmcenter/Interfaces/ICommand.cs +++ b/pmcenter/Interfaces/IBotCommand.cs @@ -10,7 +10,7 @@ namespace pmcenter { - internal interface ICommand + internal interface IBotCommand { bool OwnerOnly { get; } string Prefix { get; } diff --git a/pmcenter/Interfaces/ICallbackAction.cs b/pmcenter/Interfaces/ICallbackAction.cs new file mode 100644 index 0000000..da7bcaa --- /dev/null +++ b/pmcenter/Interfaces/ICallbackAction.cs @@ -0,0 +1,14 @@ +using System.Threading.Tasks; +using Telegram.Bot.Types; + +namespace pmcenter +{ + internal interface ICallbackAction + { + string Name { get; } + string ButtonName { get; } + ICallbackAction Replacement { get; } + Task Action(User user, Message msg); + bool IsAvailable(Update update); + } +} diff --git a/pmcenter/Interfaces/ICmdLine.cs b/pmcenter/Interfaces/ICommandLine.cs similarity index 82% rename from pmcenter/Interfaces/ICmdLine.cs rename to pmcenter/Interfaces/ICommandLine.cs index d283075..2d54e87 100644 --- a/pmcenter/Interfaces/ICmdLine.cs +++ b/pmcenter/Interfaces/ICommandLine.cs @@ -5,12 +5,10 @@ */ using System.Threading.Tasks; -using Telegram.Bot; -using Telegram.Bot.Types; namespace pmcenter { - internal interface ICmdLine + internal interface ICommandLine { string Prefix { get; } bool ExitAfterExecution { get; } diff --git a/pmcenter/Methods/Database/Checking/Methods.GetBanObjByID.cs b/pmcenter/Methods/Database/Checking/Methods.GetBanObjByID.cs index 4573e5a..fc59a82 100644 --- a/pmcenter/Methods/Database/Checking/Methods.GetBanObjByID.cs +++ b/pmcenter/Methods/Database/Checking/Methods.GetBanObjByID.cs @@ -2,15 +2,15 @@ namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static BanObj GetBanObjByID(long UID) + public static BanObj GetBanObjByID(long uid) { - foreach (BanObj Banned in Vars.CurrentConf.Banned) + foreach (var banned in Vars.CurrentConf.Banned) { - if (Banned.UID == UID) { return Banned; } + if (banned.UID == uid) return banned; } return null; } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Database/Checking/Methods.GetLinkByOwnerMsgID.cs b/pmcenter/Methods/Database/Checking/Methods.GetLinkByOwnerMsgID.cs index e92474b..35920c2 100644 --- a/pmcenter/Methods/Database/Checking/Methods.GetLinkByOwnerMsgID.cs +++ b/pmcenter/Methods/Database/Checking/Methods.GetLinkByOwnerMsgID.cs @@ -2,18 +2,18 @@ namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static MessageIDLink GetLinkByOwnerMsgID(long OwnerSessionMsgID) + public static MessageIDLink GetLinkByOwnerMsgID(long ownerSessionMsgId) { lock (Vars.CurrentConf.MessageLinks) { - foreach (MessageIDLink Link in Vars.CurrentConf.MessageLinks) + foreach (var link in Vars.CurrentConf.MessageLinks) { - if (Link.OwnerSessionMessageID == OwnerSessionMsgID) { return Link; } + if (link.OwnerSessionMessageID == ownerSessionMsgId) return link; } } return null; } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Database/Checking/Methods.GetLinkByUserMsgID.cs b/pmcenter/Methods/Database/Checking/Methods.GetLinkByUserMsgID.cs index 19a76cf..2ede789 100644 --- a/pmcenter/Methods/Database/Checking/Methods.GetLinkByUserMsgID.cs +++ b/pmcenter/Methods/Database/Checking/Methods.GetLinkByUserMsgID.cs @@ -2,18 +2,18 @@ namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static MessageIDLink GetLinkByUserMsgID(long UserSessionMsgID) + public static MessageIDLink GetLinkByUserMsgID(long userSessionMsgId) { lock (Vars.CurrentConf.MessageLinks) { - foreach (MessageIDLink Link in Vars.CurrentConf.MessageLinks) + foreach (var link in Vars.CurrentConf.MessageLinks) { - if (Link.UserSessionMessageID == UserSessionMsgID) { return Link; } + if (link.UserSessionMessageID == userSessionMsgId) { return link; } } } return null; } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Database/Checking/Methods.GetRateDataIndexByID.cs b/pmcenter/Methods/Database/Checking/Methods.GetRateDataIndexByID.cs index b7cba41..0edb11c 100644 --- a/pmcenter/Methods/Database/Checking/Methods.GetRateDataIndexByID.cs +++ b/pmcenter/Methods/Database/Checking/Methods.GetRateDataIndexByID.cs @@ -1,16 +1,14 @@ -using static pmcenter.Conf; - namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static int GetRateDataIndexByID(long UID) + public static int GetRateDataIndexByID(long uid) { - foreach (RateData Data in Vars.RateLimits) + foreach (var data in Vars.RateLimits) { - if (Data.UID == UID) { return Vars.RateLimits.IndexOf(Data); } + if (data.UID == uid) { return Vars.RateLimits.IndexOf(data); } } return -1; } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Database/Checking/Methods.IsBanned.cs b/pmcenter/Methods/Database/Checking/Methods.IsBanned.cs index d2450a0..29bd75d 100644 --- a/pmcenter/Methods/Database/Checking/Methods.IsBanned.cs +++ b/pmcenter/Methods/Database/Checking/Methods.IsBanned.cs @@ -1,16 +1,25 @@ -using static pmcenter.Conf; +using Telegram.Bot.Types; +using Telegram.Bot.Types.Enums; namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static bool IsBanned(long UID) + public static bool IsBanned(long uid) { - foreach (BanObj Banned in Vars.CurrentConf.Banned) + foreach (var banned in Vars.CurrentConf.Banned) { - if (Banned.UID == UID) { return true; } + if (banned.UID == uid) return true; } return false; } + + public static bool IsBanned(Update update) + { + bool isBanned = true; + if (update.Type == UpdateType.CallbackQuery) isBanned = IsBanned(GetLinkByOwnerMsgID(update.CallbackQuery.Message.ReplyToMessage.MessageId).TGUser.Id); + if (update.Type == UpdateType.Message) isBanned = IsBanned(update.Message.From.Id); + return isBanned; + } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Database/Checking/Methods.IsKeywordBanned.cs b/pmcenter/Methods/Database/Checking/Methods.IsKeywordBanned.cs index 96d0b04..1088b10 100644 --- a/pmcenter/Methods/Database/Checking/Methods.IsKeywordBanned.cs +++ b/pmcenter/Methods/Database/Checking/Methods.IsKeywordBanned.cs @@ -1,23 +1,23 @@ namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static bool IsKeywordBanned(string Sentence) + public static bool IsKeywordBanned(string sentence) { - if (!Vars.CurrentConf.KeywordBanning) { return false; } + if (!Vars.CurrentConf.KeywordBanning) return false; - foreach (string Blocked in Vars.CurrentConf.BannedKeywords) + foreach (var blocked in Vars.CurrentConf.BannedKeywords) { if (Vars.CurrentConf.EnableRegex) { - if (IsRegexMatch(Sentence, Blocked)) { return true; } + if (IsRegexMatch(sentence, blocked)) return true; } else { - if (Sentence.Contains(Blocked)) { return true; } + if (sentence.Contains(blocked)) return true; } } return false; } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Database/Checking/Methods.IsOwnerRetractionAvailable.cs b/pmcenter/Methods/Database/Checking/Methods.IsOwnerRetractionAvailable.cs index 7025a23..a274430 100644 --- a/pmcenter/Methods/Database/Checking/Methods.IsOwnerRetractionAvailable.cs +++ b/pmcenter/Methods/Database/Checking/Methods.IsOwnerRetractionAvailable.cs @@ -1,20 +1,18 @@ -using static pmcenter.Conf; - namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static bool IsOwnerRetractionAvailable(int OwnerSessionMsgID) + public static bool IsOwnerRetractionAvailable(int ownerSessionMsgId) { - if (!Vars.CurrentConf.EnableMsgLink) { return false; } + if (!Vars.CurrentConf.EnableMsgLink) return false; lock (Vars.CurrentConf.MessageLinks) { - foreach (MessageIDLink Link in Vars.CurrentConf.MessageLinks) + foreach (var link in Vars.CurrentConf.MessageLinks) { - if (Link.OwnerSessionMessageID == OwnerSessionMsgID) { return true; } + if (link.OwnerSessionMessageID == ownerSessionMsgId) return true; } } return false; } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Database/Checking/Methods.IsRateDataTracking.cs b/pmcenter/Methods/Database/Checking/Methods.IsRateDataTracking.cs index 15f1bff..d89f5ea 100644 --- a/pmcenter/Methods/Database/Checking/Methods.IsRateDataTracking.cs +++ b/pmcenter/Methods/Database/Checking/Methods.IsRateDataTracking.cs @@ -1,16 +1,14 @@ -using static pmcenter.Conf; - namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static bool IsRateDataTracking(long UID) + public static bool IsRateDataTracking(long uid) { - foreach (RateData Data in Vars.RateLimits) + foreach (var data in Vars.RateLimits) { - if (Data.UID == UID) { return true; } + if (data.UID == uid) return true; } return false; } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Database/Checking/Methods.IsUserRetractionAvailable.cs b/pmcenter/Methods/Database/Checking/Methods.IsUserRetractionAvailable.cs index fc9265a..bc9b2d3 100644 --- a/pmcenter/Methods/Database/Checking/Methods.IsUserRetractionAvailable.cs +++ b/pmcenter/Methods/Database/Checking/Methods.IsUserRetractionAvailable.cs @@ -2,19 +2,19 @@ namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static bool IsUserRetractionAvailable(int UserSessionMsgID) + public static bool IsUserRetractionAvailable(int userSessionMsgId) { - if (!Vars.CurrentConf.EnableMsgLink) { return false; } + if (!Vars.CurrentConf.EnableMsgLink) return false; lock (Vars.CurrentConf.MessageLinks) { - foreach (MessageIDLink Link in Vars.CurrentConf.MessageLinks) + foreach (var link in Vars.CurrentConf.MessageLinks) { - if (Link.UserSessionMessageID == UserSessionMsgID) { return true; } + if (link.UserSessionMessageID == userSessionMsgId) return true; } } return false; } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Database/Writing/Methods.AddRateLimit.cs b/pmcenter/Methods/Database/Writing/Methods.AddRateLimit.cs index 691d495..79d03c6 100644 --- a/pmcenter/Methods/Database/Writing/Methods.AddRateLimit.cs +++ b/pmcenter/Methods/Database/Writing/Methods.AddRateLimit.cs @@ -2,24 +2,24 @@ namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static void AddRateLimit(long UID) + public static void AddRateLimit(long uid) { - if (IsRateDataTracking(UID)) + if (IsRateDataTracking(uid)) { - var DataID = GetRateDataIndexByID(UID); - Vars.RateLimits[DataID].MessageCount += 1; + var dataId = GetRateDataIndexByID(uid); + Vars.RateLimits[dataId].MessageCount += 1; } else { - var Data = new RateData + var data = new RateData { - UID = UID, + UID = uid, MessageCount = 1 }; - Vars.RateLimits.Add(Data); + Vars.RateLimits.Add(data); } } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Database/Writing/Methods.BanUser.cs b/pmcenter/Methods/Database/Writing/Methods.BanUser.cs index 02b09af..f940d90 100644 --- a/pmcenter/Methods/Database/Writing/Methods.BanUser.cs +++ b/pmcenter/Methods/Database/Writing/Methods.BanUser.cs @@ -2,18 +2,18 @@ namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static void BanUser(long UID) + public static void BanUser(long uid) { - if (!IsBanned(UID)) + if (!IsBanned(uid)) { - var Banned = new BanObj + var banned = new BanObj { - UID = UID + UID = uid }; - Vars.CurrentConf.Banned.Add(Banned); + Vars.CurrentConf.Banned.Add(banned); } } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Database/Writing/Methods.UnbanUser.cs b/pmcenter/Methods/Database/Writing/Methods.UnbanUser.cs index 07a237a..7db6bbd 100644 --- a/pmcenter/Methods/Database/Writing/Methods.UnbanUser.cs +++ b/pmcenter/Methods/Database/Writing/Methods.UnbanUser.cs @@ -1,13 +1,13 @@ namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static void UnbanUser(long UID) + public static void UnbanUser(long uid) { - if (IsBanned(UID)) + if (IsBanned(uid)) { - _ = Vars.CurrentConf.Banned.Remove(GetBanObjByID(UID)); + _ = Vars.CurrentConf.Banned.Remove(GetBanObjByID(uid)); } } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/H2Helper/Methods.H2Helper.DownloadFileAsync.cs b/pmcenter/Methods/H2Helper/Methods.H2Helper.DownloadFileAsync.cs new file mode 100644 index 0000000..51d59c7 --- /dev/null +++ b/pmcenter/Methods/H2Helper/Methods.H2Helper.DownloadFileAsync.cs @@ -0,0 +1,21 @@ +using System; +using System.IO; +using System.Threading.Tasks; + +namespace pmcenter +{ + public static partial class Methods + { + public static partial class H2Helper + { + public static async Task DownloadFileAsync(Uri uri, string filename) + { + var bytes = await GetBytesAsync(uri).ConfigureAwait(false); + var fileStream = File.Create(filename); + await fileStream.WriteAsync(bytes).ConfigureAwait(false); + await fileStream.FlushAsync(); + fileStream.Close(); + } + } + } +} diff --git a/pmcenter/Methods/H2Helper/Methods.H2Helper.GetBytesAsync.cs b/pmcenter/Methods/H2Helper/Methods.H2Helper.GetBytesAsync.cs new file mode 100644 index 0000000..61a074d --- /dev/null +++ b/pmcenter/Methods/H2Helper/Methods.H2Helper.GetBytesAsync.cs @@ -0,0 +1,17 @@ +using System; +using System.Threading.Tasks; + +namespace pmcenter +{ + public static partial class Methods + { + public static partial class H2Helper + { + public static async Task GetBytesAsync(Uri uri) + { + using var content = await GetHttpContentAsync(uri).ConfigureAwait(false); + return await content.ReadAsByteArrayAsync().ConfigureAwait(false); + } + } + } +} diff --git a/pmcenter/Methods/H2Helper/Methods.H2Helper.GetHttpContentAsync.cs b/pmcenter/Methods/H2Helper/Methods.H2Helper.GetHttpContentAsync.cs new file mode 100644 index 0000000..33979f6 --- /dev/null +++ b/pmcenter/Methods/H2Helper/Methods.H2Helper.GetHttpContentAsync.cs @@ -0,0 +1,19 @@ +using System; +using System.Net.Http; +using System.Threading.Tasks; + +namespace pmcenter +{ + public static partial class Methods + { + public static partial class H2Helper + { + private static async Task GetHttpContentAsync(Uri uri) + { + var client = new HttpClient() { DefaultRequestVersion = new Version(2, 0) }; + var response = await client.GetAsync(uri).ConfigureAwait(false); + return response.Content; + } + } + } +} diff --git a/pmcenter/Methods/H2Helper/Methods.H2Helper.GetStringAsync.cs b/pmcenter/Methods/H2Helper/Methods.H2Helper.GetStringAsync.cs new file mode 100644 index 0000000..a0f3163 --- /dev/null +++ b/pmcenter/Methods/H2Helper/Methods.H2Helper.GetStringAsync.cs @@ -0,0 +1,17 @@ +using System; +using System.Threading.Tasks; + +namespace pmcenter +{ + public static partial class Methods + { + public static partial class H2Helper + { + public static async Task GetStringAsync(Uri uri) + { + using var content = await GetHttpContentAsync(uri).ConfigureAwait(false); + return await content.ReadAsStringAsync().ConfigureAwait(false); + } + } + } +} diff --git a/pmcenter/Methods/Logging/Methods.Log.cs b/pmcenter/Methods/Logging/Methods.Log.cs new file mode 100644 index 0000000..9e16b94 --- /dev/null +++ b/pmcenter/Methods/Logging/Methods.Log.cs @@ -0,0 +1,40 @@ +using System; +using System.Globalization; +using System.IO; +using System.Runtime.CompilerServices; + +namespace pmcenter +{ + public static partial class Methods + { + public static partial class Logging + { + public static void Log(string text, LogLevel type) + { + Log(text, "CORE", type); + } + public static void Log(string text, + string module = "CORE", + LogLevel type = LogLevel.Info, + [CallerFilePath] string filePath = "file?", + [CallerMemberName] string callerName = "method?", + [CallerLineNumber] int lineNumber = 0) + { + if (Vars.CurrentConf?.IgnoredLogModules.Contains(module) == true) return; + if (Vars.CurrentConf?.LowPerformanceMode == true) return; + + var file = $"/{(Path.GetFileName((Environment.OSVersion.Platform == PlatformID.Unix) ? filePath.Replace(@"\", "/") : filePath))}/{callerName}()@L{lineNumber}"; + var output = Vars.CurrentConf?.DisableTimeDisplay != true + ? $"[{DateTime.Now.ToString("o", CultureInfo.InvariantCulture)}]" + : ""; + output += $"[{module}{(Vars.CurrentConf?.AdvancedLogging == true ? file : "")}]"; + output += LogTable[type].Prefix; + output += text; + Console.BackgroundColor = ConsoleColor.Black; + Console.ForegroundColor = LogTable[type].Color; + LogTable[type].Func(output); + Console.ForegroundColor = ConsoleColor.White; + } + } + } +} diff --git a/pmcenter/Methods/Logging/Methods.LogLevel.cs b/pmcenter/Methods/Logging/Methods.LogLevel.cs new file mode 100644 index 0000000..35ec806 --- /dev/null +++ b/pmcenter/Methods/Logging/Methods.LogLevel.cs @@ -0,0 +1,15 @@ +namespace pmcenter +{ + public static partial class Methods + { + public static partial class Logging + { + public enum LogLevel + { + Info = 0, + Warning = 1, + Error = 2, + } + } + } +} diff --git a/pmcenter/Methods/Logging/Methods.LogMode.cs b/pmcenter/Methods/Logging/Methods.LogMode.cs new file mode 100644 index 0000000..ac7d2f7 --- /dev/null +++ b/pmcenter/Methods/Logging/Methods.LogMode.cs @@ -0,0 +1,17 @@ +using System; + +namespace pmcenter +{ + public static partial class Methods + { + public static partial class Logging + { + public class LogMode + { + public ConsoleColor Color; + public string Prefix; + public Action Func; + } + } + } +} diff --git a/pmcenter/Methods/Logging/Methods.LogTable.cs b/pmcenter/Methods/Logging/Methods.LogTable.cs new file mode 100644 index 0000000..52ab9f2 --- /dev/null +++ b/pmcenter/Methods/Logging/Methods.LogTable.cs @@ -0,0 +1,18 @@ +using System; +using System.Collections.Generic; + +namespace pmcenter +{ + public static partial class Methods + { + public static partial class Logging + { + public static Dictionary LogTable = new Dictionary() + { + {LogLevel.Info, new LogMode() {Color = ConsoleColor.White, Prefix = "[INFO] ", Func = Console.WriteLine}}, + {LogLevel.Warning, new LogMode() {Color = ConsoleColor.Yellow, Prefix = "[WARN] ", Func = Console.WriteLine}}, + {LogLevel.Error, new LogMode() {Color = ConsoleColor.Red, Prefix = "[ERROR] ", Func = Console.Error.WriteLine}} + }; + } + } +} diff --git a/pmcenter/Methods/Methods.BoolStr.cs b/pmcenter/Methods/Methods.BoolStr.cs deleted file mode 100644 index 3b22502..0000000 --- a/pmcenter/Methods/Methods.BoolStr.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace pmcenter -{ - public partial class Methods - { - public static string BoolStr(bool Input) - { - return Input ? "true" : "false"; - } - } -} \ No newline at end of file diff --git a/pmcenter/Methods/Methods.CheckNetCoreVersion.cs b/pmcenter/Methods/Methods.CheckNetCoreVersion.cs index b698aab..5623d50 100644 --- a/pmcenter/Methods/Methods.CheckNetCoreVersion.cs +++ b/pmcenter/Methods/Methods.CheckNetCoreVersion.cs @@ -1,19 +1,20 @@ using System; +using static pmcenter.Methods.Logging; namespace pmcenter { - public partial class Methods + public static partial class Methods { public static bool CheckNetCoreVersion(Version version) { if (version.Major != 3 || version.Minor != 1) { - Log("pmcenter v2 or up wouldn't run on devices without .NET Core 3.1 (runtime) installed.", Type: LogLevel.WARN); - Log($"pmcenter has detected that the latest version installed on your device is .NET Core runtime {version.ToString()}.", Type: LogLevel.WARN); - Log("Consider updating your .NET Core runtime in order to run pmcenter v2 and receive further updates.", Type: LogLevel.WARN); + Log("pmcenter v2 or up wouldn't run on devices without .NET Core 3.1 (runtime) installed.", LogLevel.Warning); + Log($"pmcenter has detected that the latest version installed on your device is .NET Core runtime {version}.", LogLevel.Warning); + Log("Consider updating your .NET Core runtime in order to run pmcenter v2 and receive further updates.", LogLevel.Warning); return false; } return true; } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Methods.CheckOpenSSLComp.cs b/pmcenter/Methods/Methods.CheckOpenSSLComp.cs index 0771924..5b5f8f0 100644 --- a/pmcenter/Methods/Methods.CheckOpenSSLComp.cs +++ b/pmcenter/Methods/Methods.CheckOpenSSLComp.cs @@ -1,13 +1,15 @@ using System; using System.Net.Http; using System.Security.Authentication; +using static pmcenter.Methods.Logging; namespace pmcenter { - public partial class Methods + public static partial class Methods { public static void CheckOpenSSLComp(Exception ex) { + if (ex == null) return; try { if (ex.GetType() == typeof(HttpRequestException)) @@ -16,7 +18,7 @@ public static void CheckOpenSSLComp(Exception ex) { if (ex.InnerException?.InnerException?.GetType() == typeof(TypeInitializationException)) { - Log("\n\n[!] pmcenter has detected a known issue.\n\nIt appears that your version of .NET Core runtime is incompatible with OpenSSL 1.1+ and therefore pmcenter will not be able to make TLS connections to necessary servers.\n\nTo learn more, open:\nhttps://github.com/Elepover/pmcenter#openssl-compatibility-problem\n\npmcenter will now quit.", "CORE", LogLevel.ERROR); + Log("\n\n[!] pmcenter has detected a known issue.\n\nIt appears that your version of .NET Core runtime is incompatible with OpenSSL 1.1+ and therefore pmcenter will not be able to make TLS connections to necessary servers.\n\nTo learn more, open:\nhttps://github.com/Elepover/pmcenter#openssl-compatibility-problem\n\npmcenter will now quit.", "CORE", LogLevel.Error); Environment.Exit(1); } } @@ -25,4 +27,4 @@ public static void CheckOpenSSLComp(Exception ex) catch {} } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Methods.ExitApp.cs b/pmcenter/Methods/Methods.ExitApp.cs index f8aab50..7d9e25c 100644 --- a/pmcenter/Methods/Methods.ExitApp.cs +++ b/pmcenter/Methods/Methods.ExitApp.cs @@ -1,12 +1,14 @@ using System; using System.Diagnostics; using System.Threading; +using System.Threading.Tasks; +using static pmcenter.Methods.Logging; namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static void ExitApp(int code) + public static async Task ExitApp(int code) { Log("Attempting to exit gracefully..."); Log("Stopping bot message receiving..."); @@ -16,13 +18,12 @@ public static void ExitApp(int code) sw.Start(); Vars.IsShuttingDown = true; - if (Vars.IsPerformanceTestExecuting) + Log("Saving configurations..."); + await Conf.SaveConf(); + while (Vars.IsPerformanceTestExecuting) { - while (!Vars.IsPerformanceTestExecuting) - { - if (sw.ElapsedMilliseconds >= 10000) Environment.Exit(16); - Thread.Sleep(50); - } + if (sw.ElapsedMilliseconds >= 10000) Environment.Exit(16); + Thread.Sleep(50); } Log("[OK] Shut down performance tester."); @@ -31,7 +32,7 @@ public static void ExitApp(int code) Vars.ConfValidator, Vars.UpdateChecker, Vars.RateLimiter, - Vars.BannedSweepper, + Vars.BannedSweeper, Vars.SyncConf }; diff --git a/pmcenter/Methods/Methods.FlipBool.cs b/pmcenter/Methods/Methods.FlipBool.cs deleted file mode 100644 index 7b9f9d6..0000000 --- a/pmcenter/Methods/Methods.FlipBool.cs +++ /dev/null @@ -1,10 +0,0 @@ -namespace pmcenter -{ - public partial class Methods - { - public static bool FlipBool(bool Input) - { - return Input ? false : true; - } - } -} \ No newline at end of file diff --git a/pmcenter/Methods/Methods.GetComposedUsername.cs b/pmcenter/Methods/Methods.GetComposedUsername.cs new file mode 100644 index 0000000..301cfee --- /dev/null +++ b/pmcenter/Methods/Methods.GetComposedUsername.cs @@ -0,0 +1,23 @@ +using System.Text; +using Telegram.Bot.Types; + +namespace pmcenter +{ + public static partial class Methods + { + public static string GetComposedUsername(User user, bool includeUsername = true, bool includeId = false) + { + var sb = new StringBuilder(user.FirstName); + if (!(string.IsNullOrEmpty(user.LastName) || string.IsNullOrWhiteSpace(user.LastName))) + sb.Append($" {user.LastName}"); + if (!includeUsername && !includeId) return sb.ToString(); + if (includeUsername && !includeId && string.IsNullOrEmpty(user.Username)) return sb.ToString(); + sb.Append('('); + if (includeUsername && !string.IsNullOrEmpty(user.Username)) + sb.Append($"@{user.Username}"); + if (includeId) sb.Append($", {user.Id}"); + sb.Append(')'); + return sb.ToString(); + } + } +} diff --git a/pmcenter/Methods/Methods.GetDateTimeString.cs b/pmcenter/Methods/Methods.GetDateTimeString.cs index 21c0398..e3b957a 100644 --- a/pmcenter/Methods/Methods.GetDateTimeString.cs +++ b/pmcenter/Methods/Methods.GetDateTimeString.cs @@ -3,7 +3,7 @@ namespace pmcenter { - public partial class Methods + public static partial class Methods { public static string GetDateTimeString(bool removeInvalidChar = false) { diff --git a/pmcenter/Methods/Methods.GetNetCoreVersion.cs b/pmcenter/Methods/Methods.GetNetCoreVersion.cs index 160cee1..a4231c6 100644 --- a/pmcenter/Methods/Methods.GetNetCoreVersion.cs +++ b/pmcenter/Methods/Methods.GetNetCoreVersion.cs @@ -1,10 +1,10 @@ using System; using System.Diagnostics; -using System.Text; +using static pmcenter.Methods.Logging; namespace pmcenter { - public partial class Methods + public static partial class Methods { public static Version GetNetCoreVersion() { @@ -37,9 +37,9 @@ public static Version GetNetCoreVersion() } catch (Exception ex) { - Log($"pmcenter is unable to detect your .NET Core installation: {ex.Message}, you need to have .NET Core 3.1 (runtime) installed in order to run pmcenter v2 or up.", Type: LogLevel.WARN); + Log($"pmcenter is unable to detect your .NET Core installation: {ex.Message}, you need to have .NET Core 3.1 (runtime) installed in order to run pmcenter v2 or up.", LogLevel.Warning); return new Version("0.0.0.0"); } } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Methods.GetRandomString.cs b/pmcenter/Methods/Methods.GetRandomString.cs index 0aad597..d1cf971 100644 --- a/pmcenter/Methods/Methods.GetRandomString.cs +++ b/pmcenter/Methods/Methods.GetRandomString.cs @@ -3,12 +3,12 @@ namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static string GetRandomString(int Length = 8) + public static string GetRandomString(int length = 8) { - const string Chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - return new string(Enumerable.Repeat(Chars, Length).Select(s => s[(new Random()).Next(s.Length)]).ToArray()); + const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; + return new string(Enumerable.Repeat(chars, length).Select(s => s[(new Random()).Next(s.Length)]).ToArray()); } } } diff --git a/pmcenter/Methods/Methods.GetThreadStatus.cs b/pmcenter/Methods/Methods.GetThreadStatus.cs index 51d6aab..c1473d0 100644 --- a/pmcenter/Methods/Methods.GetThreadStatus.cs +++ b/pmcenter/Methods/Methods.GetThreadStatus.cs @@ -2,13 +2,13 @@ namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static ThreadStatus GetThreadStatus(Thread Thread) + public static ThreadStatus GetThreadStatus(Thread thread) { try { - return Thread.IsAlive ? ThreadStatus.Standby : ThreadStatus.Stopped; + return thread.IsAlive ? ThreadStatus.Standby : ThreadStatus.Stopped; } catch { @@ -16,4 +16,4 @@ public static ThreadStatus GetThreadStatus(Thread Thread) } } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Methods.GetThreadStatusString.cs b/pmcenter/Methods/Methods.GetThreadStatusString.cs index 118881b..55b36c6 100644 --- a/pmcenter/Methods/Methods.GetThreadStatusString.cs +++ b/pmcenter/Methods/Methods.GetThreadStatusString.cs @@ -1,22 +1,17 @@ namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static string GetThreadStatusString(ThreadStatus Status) + public static string GetThreadStatusString(ThreadStatus status) { - switch (Status) + return status switch { - case ThreadStatus.Working: - return Vars.CurrentLang.Message_ThreadStatus_Working; - case ThreadStatus.Standby: - return Vars.CurrentLang.Message_ThreadStatus_Standby; - case ThreadStatus.Stopped: - return Vars.CurrentLang.Message_ThreadStatus_Stopped; - case ThreadStatus.Error: - return Vars.CurrentLang.Message_ThreadStatus_Error; - default: - return Vars.CurrentLang.Message_ThreadStatus_Unknown; - } + ThreadStatus.Working => Vars.CurrentLang.Message_ThreadStatus_Working, + ThreadStatus.Standby => Vars.CurrentLang.Message_ThreadStatus_Standby, + ThreadStatus.Stopped => Vars.CurrentLang.Message_ThreadStatus_Stopped, + ThreadStatus.Error => Vars.CurrentLang.Message_ThreadStatus_Error, + _ => Vars.CurrentLang.Message_ThreadStatus_Unknown, + }; } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Methods.GetUpdateLevel.cs b/pmcenter/Methods/Methods.GetUpdateLevel.cs index 2724262..846daa8 100644 --- a/pmcenter/Methods/Methods.GetUpdateLevel.cs +++ b/pmcenter/Methods/Methods.GetUpdateLevel.cs @@ -1,25 +1,20 @@ -using static pmcenter.Conf; +using static pmcenter.Methods.UpdateHelper; namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static string GetUpdateLevel(UpdateLevel Level) + public static string GetUpdateLevel(UpdateLevel level) { - string Processed = Vars.CurrentLang.Message_SysStatus_UpdateLevel_Template; - switch (Level) + string processed = Vars.CurrentLang.Message_SysStatus_UpdateLevel_Template; + return level switch { - case UpdateLevel.Optional: - return Processed.Replace("$1", Vars.CurrentLang.Message_SysStatus_UpdateLevel_Optional); - case UpdateLevel.Recommended: - return Processed.Replace("$1", Vars.CurrentLang.Message_SysStatus_UpdateLevel_Recommended); - case UpdateLevel.Important: - return Processed.Replace("$1", Vars.CurrentLang.Message_SysStatus_UpdateLevel_Important); - case UpdateLevel.Urgent: - return Processed.Replace("$1", Vars.CurrentLang.Message_SysStatus_UpdateLevel_Urgent); - default: - return Processed.Replace("$1", Vars.CurrentLang.Message_SysStatus_UpdateLevel_Unknown); - } + UpdateLevel.Optional => processed.Replace("$1", Vars.CurrentLang.Message_SysStatus_UpdateLevel_Optional), + UpdateLevel.Recommended => processed.Replace("$1", Vars.CurrentLang.Message_SysStatus_UpdateLevel_Recommended), + UpdateLevel.Important => processed.Replace("$1", Vars.CurrentLang.Message_SysStatus_UpdateLevel_Important), + UpdateLevel.Urgent => processed.Replace("$1", Vars.CurrentLang.Message_SysStatus_UpdateLevel_Urgent), + _ => processed.Replace("$1", Vars.CurrentLang.Message_SysStatus_UpdateLevel_Unknown), + }; } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Methods.IsRegexMatch.cs b/pmcenter/Methods/Methods.IsRegexMatch.cs index 750d12e..28b4160 100644 --- a/pmcenter/Methods/Methods.IsRegexMatch.cs +++ b/pmcenter/Methods/Methods.IsRegexMatch.cs @@ -1,28 +1,23 @@ using System; using System.Text.RegularExpressions; +using static pmcenter.Methods.Logging; namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static bool IsRegexMatch(string Source, string Expression) + public static bool IsRegexMatch(string source, string expression) { try { - if (Regex.IsMatch(Source, Expression, RegexOptions.None)) - { - return true; - } - else - { - return false; - } + if (Regex.IsMatch(source, expression, RegexOptions.None)) return true; + return false; } catch (Exception ex) { - Log($"Regex match failed: {ex.Message}, did you use a wrong regex?", "BOT", LogLevel.ERROR); + Log($"Regex match failed: {ex.Message}, did you use a wrong regex?", "BOT", LogLevel.Error); return false; } } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Methods.Log.cs b/pmcenter/Methods/Methods.Log.cs deleted file mode 100644 index 2dcc9b0..0000000 --- a/pmcenter/Methods/Methods.Log.cs +++ /dev/null @@ -1,66 +0,0 @@ -using System; -using System.Globalization; -using System.IO; -using System.Runtime.CompilerServices; - -namespace pmcenter -{ - public partial class Methods - { - public static void Log(string Text, - string Module = "CORE", - LogLevel Type = LogLevel.INFO, - [CallerFilePath] string filePath = "file?", - [CallerMemberName] string callerName = "method?", - [CallerLineNumber] int lineNumber = 0) - { - if (Vars.CurrentConf?.LowPerformanceMode == true) return; - string file = $"/{((Environment.OSVersion.Platform == PlatformID.Unix) ? Path.GetFileName(filePath.Replace(@"\", "/")) : Path.GetFileName(filePath))}/{callerName}()@L{lineNumber}"; - var Output = - (Vars.CurrentConf?.DisableTimeDisplay != true ? - $"[{DateTime.Now.ToString("o", CultureInfo.InvariantCulture)}]" - : - "" - ) - + "[" - + Module - + - (Vars.CurrentConf?.AdvancedLogging == true ? - file - : - "" - ) - + "]"; - Console.BackgroundColor = ConsoleColor.Black; - switch (Type) - { - case LogLevel.INFO: - Console.ForegroundColor = ConsoleColor.White; - Output += "[INFO] "; // Spacebars between prefixes and contents were already added here. - break; - case LogLevel.WARN: - Console.ForegroundColor = ConsoleColor.Yellow; - Output += "[WARN] "; - break; - case LogLevel.ERROR: - Console.ForegroundColor = ConsoleColor.Red; - Output += "[ERROR] "; - break; - default: - Console.ForegroundColor = ConsoleColor.Gray; - Output += "[UKNN] "; - break; - } - Output += Text; - if (Type == LogLevel.ERROR) - { - Console.Error.WriteLine(Output); - } - else - { - Console.WriteLine(Output); - } - Console.ForegroundColor = ConsoleColor.White; - } - } -} \ No newline at end of file diff --git a/pmcenter/Methods/Methods.LogLevel.cs b/pmcenter/Methods/Methods.LogLevel.cs deleted file mode 100644 index a0495e9..0000000 --- a/pmcenter/Methods/Methods.LogLevel.cs +++ /dev/null @@ -1,12 +0,0 @@ -namespace pmcenter -{ - public partial class Methods - { - public enum LogLevel - { - INFO = 0, - WARN = 1, - ERROR = 2, - } - } -} \ No newline at end of file diff --git a/pmcenter/Methods/Methods.SerializeCurrentConf.cs b/pmcenter/Methods/Methods.SerializeCurrentConf.cs index 6f05e20..90830a9 100644 --- a/pmcenter/Methods/Methods.SerializeCurrentConf.cs +++ b/pmcenter/Methods/Methods.SerializeCurrentConf.cs @@ -2,11 +2,11 @@ namespace pmcenter { - public partial class Methods + public static partial class Methods { public static string SerializeCurrentConf() { return JsonConvert.SerializeObject(Vars.CurrentConf, Formatting.Indented); } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Methods.StrChunk.cs b/pmcenter/Methods/Methods.StrChunk.cs index 430b6b9..a4eeedf 100644 --- a/pmcenter/Methods/Methods.StrChunk.cs +++ b/pmcenter/Methods/Methods.StrChunk.cs @@ -3,11 +3,11 @@ namespace pmcenter { - public partial class Methods + public static partial class Methods { public static List StrChunk(string str, int chunkSize) { return Enumerable.Range(0, str.Length / chunkSize).Select(i => str.Substring(i * chunkSize, chunkSize)).ToList(); } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Methods.ThreadStatus.cs b/pmcenter/Methods/Methods.ThreadStatus.cs index 6c732fb..0f27882 100644 --- a/pmcenter/Methods/Methods.ThreadStatus.cs +++ b/pmcenter/Methods/Methods.ThreadStatus.cs @@ -1,6 +1,6 @@ namespace pmcenter { - public partial class Methods + public static partial class Methods { public enum ThreadStatus { @@ -11,4 +11,4 @@ public enum ThreadStatus Error = 4, } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/NetworkTest/Methods.TestConnectivity.cs b/pmcenter/Methods/NetworkTest/Methods.TestConnectivity.cs index 942c485..82b82d6 100644 --- a/pmcenter/Methods/NetworkTest/Methods.TestConnectivity.cs +++ b/pmcenter/Methods/NetworkTest/Methods.TestConnectivity.cs @@ -1,24 +1,26 @@ using System; using System.Net; using System.Threading.Tasks; +using static pmcenter.Methods.Logging; namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static async Task TestConnectivity(string Target, bool Ignore45 = false) + public static async Task TestConnectivity(string target, bool ignore45 = false) { try { - var Req = WebRequest.CreateHttp(Target); - Req.Timeout = 10000; - _ = await Req.GetResponseAsync().ConfigureAwait(false); + var req = WebRequest.CreateHttp(target); + req.ProtocolVersion = new Version(2, 0); + req.Timeout = 10000; + _ = await req.GetResponseAsync().ConfigureAwait(false); return true; } catch (WebException ex) { - if (ex.Status == WebExceptionStatus.ProtocolError && Ignore45) { return true; } - Log($"Connectivity to {Target} is unavailable: {ex.Message}"); + if (ex.Status == WebExceptionStatus.ProtocolError && ignore45) return true; + Log($"Connectivity to {target} is unavailable: {ex.Message}"); return false; } catch (Exception ex) diff --git a/pmcenter/Methods/NetworkTest/Methods.TestLatency.cs b/pmcenter/Methods/NetworkTest/Methods.TestLatency.cs index 8f99b9a..8d309b3 100644 --- a/pmcenter/Methods/NetworkTest/Methods.TestLatency.cs +++ b/pmcenter/Methods/NetworkTest/Methods.TestLatency.cs @@ -2,32 +2,34 @@ using System.Diagnostics; using System.Net; using System.Threading.Tasks; +using static pmcenter.Methods.Logging; namespace pmcenter { - public partial class Methods + public static partial class Methods { - public static async Task TestLatency(string Target) + public static async Task TestLatency(string target) { - var ReqSW = new Stopwatch(); + var reqSw = new Stopwatch(); try { - var Req = WebRequest.CreateHttp(Target); - ReqSW.Start(); - _ = await Req.GetResponseAsync().ConfigureAwait(false); - ReqSW.Stop(); - return ReqSW.Elapsed; + var req = WebRequest.CreateHttp(target); + reqSw.Start(); + _ = await req.GetResponseAsync().ConfigureAwait(false); + reqSw.Stop(); + return reqSw.Elapsed; } catch (WebException) { - ReqSW.Stop(); - return ReqSW.Elapsed; + reqSw.Stop(); + return reqSw.Elapsed; } catch (Exception ex) { Log($"Latency test failed: {ex.Message}"); + reqSw.Reset(); return new TimeSpan(0); } } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Threads/Methods.ThrDoResetConfCount.cs b/pmcenter/Methods/Threads/Methods.ThrDoResetConfCount.cs index 5fef90d..2aae84a 100644 --- a/pmcenter/Methods/Threads/Methods.ThrDoResetConfCount.cs +++ b/pmcenter/Methods/Threads/Methods.ThrDoResetConfCount.cs @@ -2,16 +2,16 @@ namespace pmcenter { - public partial class Methods + public static partial class Methods { public static void ThrDoResetConfCount() { Vars.ConfResetTimerStatus = ThreadStatus.Working; - if (Vars.IsResetConfAvailable) { return; } + if (Vars.IsResetConfAvailable) return; Vars.IsResetConfAvailable = true; Thread.Sleep(30000); Vars.IsResetConfAvailable = false; Vars.ConfResetTimerStatus = ThreadStatus.Stopped; } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Threads/Methods.ThrPerform.cs b/pmcenter/Methods/Threads/Methods.ThrPerform.cs index f56a94d..a8f2a1b 100644 --- a/pmcenter/Methods/Threads/Methods.ThrPerform.cs +++ b/pmcenter/Methods/Threads/Methods.ThrPerform.cs @@ -1,10 +1,10 @@ namespace pmcenter { - public partial class Methods + public static partial class Methods { public static void ThrPerform() { - if (Vars.IsPerformanceTestExecuting) { return; } + if (Vars.IsPerformanceTestExecuting) return; Vars.IsPerformanceTestExecuting = true; Vars.PerformanceScore = 0; while (!(Vars.IsPerformanceTestEndRequested || Vars.IsShuttingDown)) @@ -15,4 +15,4 @@ public static void ThrPerform() Vars.IsPerformanceTestEndRequested = false; } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Threads/Methods.ThrRateLimiter.cs b/pmcenter/Methods/Threads/Methods.ThrRateLimiter.cs index 6ad14e9..f9d27e5 100644 --- a/pmcenter/Methods/Threads/Methods.ThrRateLimiter.cs +++ b/pmcenter/Methods/Threads/Methods.ThrRateLimiter.cs @@ -1,9 +1,10 @@ using System.Threading; using static pmcenter.Conf; +using static pmcenter.Methods.Logging; namespace pmcenter { - public partial class Methods + public static partial class Methods { public static async void ThrRateLimiter() { @@ -11,19 +12,19 @@ public static async void ThrRateLimiter() while (!Vars.IsShuttingDown) { Vars.RateLimiterStatus = ThreadStatus.Working; - foreach (RateData Data in Vars.RateLimits) + foreach (var data in Vars.RateLimits) { - if (Data.MessageCount > Vars.CurrentConf.AutoBanThreshold && Vars.CurrentConf.AutoBan) + if (data.MessageCount > Vars.CurrentConf.AutoBanThreshold && Vars.CurrentConf.AutoBan) { - BanUser(Data.UID); + BanUser(data.UID); _ = await SaveConf(false, true).ConfigureAwait(false); - Log($"Banning user: {Data.UID}", "RATELIMIT"); + Log($"Banning user: {data.UID}", "RATELIMIT"); } - Data.MessageCount = 0; + data.MessageCount = 0; } Vars.RateLimiterStatus = ThreadStatus.Standby; try { Thread.Sleep(30000); } catch { } } } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Threads/Methods.ThrSyncConf.cs b/pmcenter/Methods/Threads/Methods.ThrSyncConf.cs index 1c83150..11f4b1f 100644 --- a/pmcenter/Methods/Threads/Methods.ThrSyncConf.cs +++ b/pmcenter/Methods/Threads/Methods.ThrSyncConf.cs @@ -1,12 +1,14 @@ using System; using System.Threading; +using static pmcenter.Methods.Logging; namespace pmcenter { - public partial class Methods + public static partial class Methods { public static async void ThrSyncConf() { + Log("Autosave thread online!", "CONFSYNC"); while (!Vars.IsShuttingDown) { try @@ -16,15 +18,15 @@ public static async void ThrSyncConf() } catch (Exception ex) { - Log($"Failed to write configurations to local disk: {ex.Message}", "CONFSYNC", LogLevel.ERROR); + Log($"Failed to write configurations to local disk: {ex.Message}", "CONFSYNC", LogLevel.Error); } if (Vars.CurrentConf.ConfSyncInterval == 0) { - Log("ConfSync disabled, stopping...", "CONFSYNC", LogLevel.WARN); + Log("ConfSync disabled, stopping...", "CONFSYNC", LogLevel.Warning); return; } try { Thread.Sleep(Vars.CurrentConf.ConfSyncInterval); } catch { } } } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/Threads/Methods.ThrUpdateChecker.cs b/pmcenter/Methods/Threads/Methods.ThrUpdateChecker.cs index c6ba315..572b9a0 100644 --- a/pmcenter/Methods/Threads/Methods.ThrUpdateChecker.cs +++ b/pmcenter/Methods/Threads/Methods.ThrUpdateChecker.cs @@ -1,11 +1,12 @@ using System; using System.Threading; using Telegram.Bot.Types.Enums; -using static pmcenter.Conf; +using static pmcenter.Methods.Logging; +using static pmcenter.Methods.UpdateHelper; namespace pmcenter { - public partial class Methods + public static partial class Methods { public static async void ThrUpdateChecker() { @@ -15,24 +16,24 @@ public static async void ThrUpdateChecker() Vars.UpdateCheckerStatus = ThreadStatus.Working; try { - var Latest = Conf.CheckForUpdates(); - var CurrentLocalizedIndex = GetUpdateInfoIndexByLocale(Latest, Vars.CurrentLang.LangCode); - var DisNotif = Vars.CurrentConf.DisableNotifications; + var latest = await CheckForUpdatesAsync().ConfigureAwait(false); + var currentLocalizedIndex = GetUpdateInfoIndexByLocale(latest, Vars.CurrentLang.LangCode); + var isNotificationDisabled = Vars.CurrentConf.DisableNotifications; // Identical with BotProcess.cs, L206. - if (Conf.IsNewerVersionAvailable(Latest)) + if (IsNewerVersionAvailable(latest)) { Vars.UpdatePending = true; - Vars.UpdateVersion = new Version(Latest.Latest); - Vars.UpdateLevel = Latest.UpdateLevel; - var UpdateString = Vars.CurrentLang.Message_UpdateAvailable - .Replace("$1", Latest.Latest) - .Replace("$2", Latest.UpdateCollection[CurrentLocalizedIndex].Details) - .Replace("$3", GetUpdateLevel(Latest.UpdateLevel)); + Vars.UpdateVersion = new Version(latest.Latest); + Vars.UpdateLevel = latest.UpdateLevel; + var updateString = Vars.CurrentLang.Message_UpdateAvailable + .Replace("$1", latest.Latest) + .Replace("$2", latest.UpdateCollection[currentLocalizedIndex].Details) + .Replace("$3", GetUpdateLevel(latest.UpdateLevel)); _ = await Vars.Bot.SendTextMessageAsync(Vars.CurrentConf.OwnerUID, - UpdateString, + updateString, ParseMode.Markdown, false, - DisNotif).ConfigureAwait(false); + isNotificationDisabled).ConfigureAwait(false); return; // Since this thread wouldn't be useful any longer, exit. } else @@ -43,11 +44,11 @@ public static async void ThrUpdateChecker() } catch (Exception ex) { - Log($"Error during update check: {ex.ToString()}", "UPDATER", LogLevel.ERROR); + Log($"Error during update check: {ex}", "UPDATER", LogLevel.Error); } Vars.UpdateCheckerStatus = ThreadStatus.Standby; try { Thread.Sleep(60000); } catch { } } } } -} \ No newline at end of file +} diff --git a/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.CheckForUpdatesAsync.cs b/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.CheckForUpdatesAsync.cs new file mode 100644 index 0000000..e954cda --- /dev/null +++ b/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.CheckForUpdatesAsync.cs @@ -0,0 +1,23 @@ +using Newtonsoft.Json; +using System; +using System.Threading.Tasks; +using static pmcenter.Methods.H2Helper; + +namespace pmcenter +{ + public static partial class Methods + { + public static partial class UpdateHelper + { + public static async Task CheckForUpdatesAsync() + { + var response = await GetStringAsync( + new Uri( + Vars.UpdateInfo2URL.Replace("$channel", Vars.CurrentConf == null ? "master" : Vars.CurrentConf.UpdateChannel) + ) + ); + return JsonConvert.DeserializeObject(response); + } + } + } +} diff --git a/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.DownloadLangAsync.cs b/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.DownloadLangAsync.cs new file mode 100644 index 0000000..1c7b5f8 --- /dev/null +++ b/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.DownloadLangAsync.cs @@ -0,0 +1,23 @@ +using System; +using System.IO; +using System.Threading.Tasks; +using static pmcenter.Methods.H2Helper; +using static pmcenter.Methods.Logging; + +namespace pmcenter +{ + public static partial class Methods + { + public static partial class UpdateHelper + { + public static async Task DownloadLangAsync() + { + Log("Starting automatic language file update...", "BOT"); + await DownloadFileAsync( + new Uri(Vars.CurrentConf.LangURL), + Path.Combine(Vars.AppDirectory, "pmcenter_locale.json") + ).ConfigureAwait(false); + } + } + } +} diff --git a/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.DownloadUpdateAsync.cs b/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.DownloadUpdateAsync.cs new file mode 100644 index 0000000..d063559 --- /dev/null +++ b/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.DownloadUpdateAsync.cs @@ -0,0 +1,45 @@ +using System; +using System.IO; +using System.IO.Compression; +using System.Threading.Tasks; +using static pmcenter.Methods.H2Helper; +using static pmcenter.Methods.Logging; + +namespace pmcenter +{ + public static partial class Methods + { + public static partial class UpdateHelper + { + /// + /// Download update to filesystem and extract. + /// You must run Conf.CheckForUpdatesAsync() in order to pass the latestUpdate argument. + /// + /// The information of the latest update + /// The target localization's index + /// + public static async Task DownloadUpdatesAsync(Update2 latestUpdate, int localizationIndex = 0) + { + Log("Starting update download... (pmcenter_update.zip)"); +#pragma warning disable CA1062 // Validate arguments of public methods + Log($"From address: {latestUpdate.UpdateCollection[localizationIndex].UpdateArchiveAddress}"); +#pragma warning restore CA1062 + await DownloadFileAsync( + new Uri(latestUpdate.UpdateCollection[localizationIndex].UpdateArchiveAddress), + Path.Combine(Vars.AppDirectory, "pmcenter_update.zip") + ).ConfigureAwait(false); + Log("Download complete. Extracting..."); + using (var zip = ZipFile.OpenRead(Path.Combine(Vars.AppDirectory, "pmcenter_update.zip"))) + { + foreach (var entry in zip.Entries) + { + Log($"Extracting: {Path.Combine(Vars.AppDirectory, entry.FullName)}"); + entry.ExtractToFile(Path.Combine(Vars.AppDirectory, entry.FullName), true); + } + } + Log("Cleaning up temporary files..."); + File.Delete(Path.Combine(Vars.AppDirectory, "pmcenter_update.zip")); + } + } + } +} diff --git a/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.GetUpdateInfoIndexByLocale.cs b/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.GetUpdateInfoIndexByLocale.cs new file mode 100644 index 0000000..b5925bc --- /dev/null +++ b/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.GetUpdateInfoIndexByLocale.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace pmcenter +{ + public static partial class Methods + { + public static partial class UpdateHelper + { + public static int GetUpdateInfoIndexByLocale(Update2 Update, string Locale) + { + var indexes = new List(); + for (int i = 0; i < Update.UpdateCollection.Count; i++) + { + if (Update.UpdateCollection[i].LangCode.Contains(Locale)) indexes.Add(i); + } + if (indexes.Count == 0) return 0; + foreach (var i in indexes) + { + if (Update.UpdateCollection[i].UpdateChannel == Vars.CurrentConf.UpdateChannel) return i; + } + return indexes[0]; + } + } + } +} diff --git a/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.IsNewerVersionAvailable.cs b/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.IsNewerVersionAvailable.cs new file mode 100644 index 0000000..b92e133 --- /dev/null +++ b/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.IsNewerVersionAvailable.cs @@ -0,0 +1,30 @@ +using System; +using static pmcenter.Methods.Logging; + +namespace pmcenter +{ + public static partial class Methods + { + public static partial class UpdateHelper + { + public static bool IsNewerVersionAvailable(Update2 CurrentUpdate) + { + if (Vars.GitHubReleases) + { + Log("This distribution of pmcenter is released via GitHub releases. Automatic updates are not supported yet.", LogLevel.Warning); + return false; + } + var currentVersion = Vars.AppVer; + var currentLatest = new Version(CurrentUpdate.Latest); + if (currentLatest > currentVersion) + { + return true; + } + else + { + return false; + } + } + } + } +} diff --git a/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.Update.cs b/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.Update.cs new file mode 100644 index 0000000..04ba884 --- /dev/null +++ b/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.Update.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace pmcenter +{ + public static partial class Methods + { + public static partial class UpdateHelper + { + public class Update + { + public Update() + { + Details = "(Load failed.)"; + LangCode = new List() { "en.integrated" }; + UpdateChannel = "master"; + UpdateArchiveAddress = "https://see.wtf/pmcenter-update"; + } + public string Details; + public List LangCode; + public string UpdateChannel; + public string UpdateArchiveAddress; + } + } + } +} diff --git a/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.Update2.cs b/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.Update2.cs new file mode 100644 index 0000000..b367afb --- /dev/null +++ b/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.Update2.cs @@ -0,0 +1,23 @@ +using System.Collections.Generic; + +namespace pmcenter +{ + public static partial class Methods + { + public static partial class UpdateHelper + { + public class Update2 + { + public Update2() + { + Latest = "0.0.0.0"; + UpdateLevel = UpdateLevel.Optional; + UpdateCollection = new List(); + } + public string Latest; + public UpdateLevel UpdateLevel; + public List UpdateCollection; + } + } + } +} diff --git a/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.UpdateLevel.cs b/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.UpdateLevel.cs new file mode 100644 index 0000000..8b5b11e --- /dev/null +++ b/pmcenter/Methods/UpdateHelper/Methods.UpdateHelper.UpdateLevel.cs @@ -0,0 +1,16 @@ +namespace pmcenter +{ + public static partial class Methods + { + public static partial class UpdateHelper + { + public enum UpdateLevel + { + Optional = 0, + Recommended = 1, + Important = 2, + Urgent = 3, + } + } + } +} diff --git a/pmcenter/Program.cs b/pmcenter/Program.cs index 78f98dd..974fdec 100644 --- a/pmcenter/Program.cs +++ b/pmcenter/Program.cs @@ -4,81 +4,99 @@ // Copyright (C) The pmcenter authors. Licensed under the Apache License (Version 2.0). */ +using MihaZupan; using System; using System.Collections.Generic; using System.IO; using System.Threading; using System.Threading.Tasks; -using MihaZupan; using Telegram.Bot; using Telegram.Bot.Types.Enums; using static pmcenter.Conf; using static pmcenter.EventHandlers; using static pmcenter.Lang; using static pmcenter.Methods; +using static pmcenter.Methods.Logging; namespace pmcenter { - public partial class Program + public sealed partial class Program { + private static readonly List _checkPoints = new List(); + private static void Check(string name) => _checkPoints.Add(new CheckPoint(Vars.StartSW.ElapsedTicks, name)); + private static void PrintCheckPoints() + { + Log("Check points recorded during startup:"); + for (int i = 1; i < _checkPoints.Count; i++) + Log($"#{i}: {new TimeSpan(_checkPoints[i].Tick - _checkPoints[i - 1].Tick).TotalMilliseconds}ms: {_checkPoints[i].Name} at {new TimeSpan(_checkPoints[i].Tick).TotalMilliseconds}ms"); + } + public static void Main(string[] args) { Vars.StartSW.Start(); - Console.WriteLine(Vars.ASCII); + Console.WriteLine(Vars.AsciiArt); Log("Main delegator activated!", "DELEGATOR"); - Log($"Starting pmcenter, version {Vars.AppVer.ToString()}. Channel: \"{Vars.CompileChannel}\"", "DELEGATOR"); - var MainAsyncTask = MainAsync(args); - MainAsyncTask.Wait(); - Log("Main worker accidentally exited. Stopping...", "DELEGATOR", LogLevel.ERROR); + Log($"Starting pmcenter, version {Vars.AppVer}. Channel: \"{Vars.CompileChannel}\"", "DELEGATOR"); + if (Vars.GitHubReleases) + Log("This image of pmcenter is built for GitHub releases. Will use a different updating mechanism.", "DELEGATOR"); + var mainAsyncTask = MainAsync(args); + mainAsyncTask.Wait(); + Log("Main worker accidentally exited. Stopping...", "DELEGATOR", LogLevel.Error); Environment.Exit(1); } public static async Task MainAsync(string[] args) { try { + Check("Initial checkpoint"); // mark initial checkpoint Log("==> Running pre-start operations..."); // hook global errors (final failsafe) AppDomain.CurrentDomain.UnhandledException += GlobalErrorHandler; Log("Global error handler is armed and ready!"); // hook ctrl-c events Console.CancelKeyPress += CtrlCHandler; + Check("Event handlers armed"); // process commandlines await CmdLineProcess.RunCommand(Environment.CommandLine).ConfigureAwait(false); + Check("Command line arguments processed"); // everything (exits and/or errors) are handled above, please do not process. // detect environment variables - // including: $pmcenter_conf, $pmcenter_lang + // including: + // $pmcenter_conf + // $pmcenter_lang try { - var ConfByEnviVar = Environment.GetEnvironmentVariable("pmcenter_conf"); - var LangByEnviVar = Environment.GetEnvironmentVariable("pmcenter_lang"); - if (ConfByEnviVar != null) + var confByEnvironmentVar = Environment.GetEnvironmentVariable("pmcenter_conf"); + var langByEnvironmentVar = Environment.GetEnvironmentVariable("pmcenter_lang"); + if (confByEnvironmentVar != null) { - if (File.Exists(ConfByEnviVar)) + if (File.Exists(confByEnvironmentVar)) { - Vars.ConfFile = ConfByEnviVar; + Vars.ConfFile = confByEnvironmentVar; } else { - Log($"==> The following file was not found: {ConfByEnviVar}", "CORE", LogLevel.INFO); + Log($"==> The following file was not found: {confByEnvironmentVar}", "CORE", LogLevel.Info); } } - if (LangByEnviVar != null) + if (langByEnvironmentVar != null) { - if (File.Exists(LangByEnviVar)) + if (File.Exists(langByEnvironmentVar)) { - Vars.LangFile = LangByEnviVar; + Vars.LangFile = langByEnvironmentVar; } else { - Log($"==> The following file was not found: {LangByEnviVar}", "CORE", LogLevel.INFO); + Log($"==> The following file was not found: {langByEnvironmentVar}", "CORE", LogLevel.Info); } } } catch (Exception ex) { - Log($"Failed to read environment variables: {ex.ToString()}", "CORE", LogLevel.WARN); + Log($"Failed to read environment variables: {ex}", "CORE", LogLevel.Warning); } - + Check("Environment variables processed"); + Log($"==> Using configurations file: {Vars.ConfFile}"); Log($"==> Using language file: {Vars.LangFile}"); @@ -86,23 +104,36 @@ public static async Task MainAsync(string[] args) Log("==> Initializing module - CONF"); // BY DEFAULT CONF & LANG ARE NULL! PROCEED BEFORE DOING ANYTHING. <- well anyway we have default values await InitConf().ConfigureAwait(false); _ = await ReadConf().ConfigureAwait(false); + Check("Configurations loaded"); await InitLang().ConfigureAwait(false); _ = await ReadLang().ConfigureAwait(false); + Check("Custom locale loaded"); if (Vars.CurrentLang == null) - { throw new InvalidOperationException("Language file is empty."); - } if (Vars.RestartRequired) { Log("This may be the first time that you use the pmcenter bot.", "CORE"); Log("Configuration guide could be found at https://see.wtf/feEJJ", "CORE"); - Log("Received restart requirement from settings system. Exiting...", "CORE", LogLevel.ERROR); - Log("You may need to check your settings and try again.", "CORE", LogLevel.INFO); + Log("Received restart requirement from settings system. Exiting...", "CORE", LogLevel.Error); + Log("You may need to check your settings and try again.", "CORE", LogLevel.Info); Environment.Exit(1); } + // check if logs are being omitted + if (Vars.CurrentConf.IgnoredLogModules.Count > 0) + { + var tmp = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Yellow; + Console.WriteLine("!!!!!!!!!! SOME LOG ENTRIES ARE HIDDEN ACCORDING TO CURRENT SETTINGS !!!!!!!!!!"); + Console.WriteLine("To revert this, clear the \"IgnoredLogModules\" field in pmcenter.json."); + Console.WriteLine("To disable all log output, turn on \"LowPerformanceMode\"."); + Console.WriteLine("This warning will appear every time pmcenter starts up with \"IgnoredLogModules\" set."); + Console.ForegroundColor = tmp; + } + Check("Warnings displayed"); + Log("==> Initializing module - THREADS"); Log("Starting RateLimiter..."); Vars.RateLimiter = new Thread(() => ThrRateLimiter()); @@ -112,6 +143,8 @@ public static async Task MainAsync(string[] args) { Thread.Sleep(100); } + Check("Rate limiter online"); + Log("Starting UpdateChecker..."); if (Vars.CurrentConf.EnableAutoUpdateCheck) { @@ -128,6 +161,8 @@ public static async Task MainAsync(string[] args) Vars.UpdateCheckerStatus = ThreadStatus.Stopped; Log("Skipped."); } + Check("Update checker ready"); + Log("Starting SyncConf..."); Vars.SyncConf = new Thread(() => ThrSyncConf()); Vars.SyncConf.Start(); @@ -136,47 +171,62 @@ public static async Task MainAsync(string[] args) { Thread.Sleep(100); } + Check("Configurations autosaver online"); Log("==> Initializing module - BOT"); Log("Initializing bot instance..."); if (Vars.CurrentConf.UseProxy) { Log("Activating SOCKS5 proxy..."); - List ProxyInfoList = new List(); - foreach (Socks5Proxy Info in Vars.CurrentConf.Socks5Proxies) + List proxyInfoList = new List(); + foreach (var proxyInfo in Vars.CurrentConf.Socks5Proxies) { - ProxyInfo ProxyInfo = new ProxyInfo(Info.ServerName, - Info.ServerPort, - Info.Username, - Info.ProxyPass); - ProxyInfoList.Add(ProxyInfo); + var newProxyInfo = new ProxyInfo(proxyInfo.ServerName, + proxyInfo.ServerPort, + proxyInfo.Username, + proxyInfo.ProxyPass); + proxyInfoList.Add(newProxyInfo); } - HttpToSocks5Proxy Proxy = new HttpToSocks5Proxy(ProxyInfoList.ToArray()) + var proxy = new HttpToSocks5Proxy(proxyInfoList.ToArray()) { ResolveHostnamesLocally = Vars.CurrentConf.ResolveHostnamesLocally }; Log("SOCKS5 proxy is enabled."); - Vars.Bot = new TelegramBotClient(Vars.CurrentConf.APIKey, Proxy); + Vars.Bot = new TelegramBotClient(Vars.CurrentConf.APIKey, proxy); } else { Vars.Bot = new TelegramBotClient(Vars.CurrentConf.APIKey); } + Check("Bot initialized"); + Log("Validating API Key..."); - _ = await Vars.Bot.TestApiAsync().ConfigureAwait(false); - Log("Hooking event processors..."); + if (Vars.CurrentConf.SkipAPIKeyVerification) + Log("API Key validation skipped", LogLevel.Warning); + else + _ = await Vars.Bot.TestApiAsync().ConfigureAwait(false); + Check("API Key test passed"); + + Log("Hooking message processors..."); Vars.Bot.OnUpdate += BotProcess.OnUpdate; Log("Starting receiving..."); - Vars.Bot.StartReceiving(new[] { UpdateType.Message }); + Vars.Bot.StartReceiving(new[] + { + UpdateType.Message, + UpdateType.CallbackQuery + }); + Check("Update receiving started"); + Log("==> Startup complete!"); Log("==> Running post-start operations..."); try { + // prompt startup success if (!Vars.CurrentConf.NoStartupMessage) { _ = await Vars.Bot.SendTextMessageAsync(Vars.CurrentConf.OwnerUID, Vars.CurrentLang.Message_BotStarted - .Replace("$1", Math.Round(Vars.StartSW.Elapsed.TotalSeconds, 2) + "s"), + .Replace("$1", $"{Math.Round(Vars.StartSW.Elapsed.TotalSeconds, 2)}s"), ParseMode.Markdown, false, false).ConfigureAwait(false); @@ -184,10 +234,13 @@ public static async Task MainAsync(string[] args) } catch (Exception ex) { - Log($"Failed to send startup message to owner.\nDid you set the \"OwnerID\" key correctly? Otherwise pmcenter could not work properly.\nYou can try to use setup wizard to update/get your OwnerID automatically, just run \"dotnet pmcenter.dll --setup\".\n\nError details: {ex.ToString()}", "BOT", LogLevel.WARN); + Log($"Failed to send startup message to owner.\nDid you set the \"OwnerID\" key correctly? Otherwise pmcenter could not work properly.\nYou can try to use setup wizard to update/get your OwnerID automatically, just run \"dotnet pmcenter.dll --setup\".\n\nError details: {ex}", "BOT", LogLevel.Warning); } + Check("Startup message sent"); + try { + // check .net core runtime version var netCoreVersion = GetNetCoreVersion(); if (!CheckNetCoreVersion(netCoreVersion) && !Vars.CurrentConf.DisableNetCore3Check) { @@ -198,44 +251,49 @@ public static async Task MainAsync(string[] args) false, false).ConfigureAwait(false); Vars.CurrentConf.DisableNetCore3Check = true; + _ = await SaveConf(false, true); } } catch (Exception ex) { - Log($".NET Core runtime version warning wasn't delivered to the owner: {ex.Message}, did you set the \"OwnerID\" key correctly?", "BOT", LogLevel.WARN); + Log($".NET Core runtime version warning wasn't delivered to the owner: {ex.Message}, did you set the \"OwnerID\" key correctly?", "BOT", LogLevel.Warning); } + Check(".NET Core runtime version check complete"); + + // check language mismatch if (Vars.CurrentLang.TargetVersion != Vars.AppVer.ToString()) { - Log("Language version mismatch detected.", "CORE", LogLevel.WARN); - _ = await Vars.Bot.SendTextMessageAsync(Vars.CurrentConf.OwnerUID, - Vars.CurrentLang.Message_LangVerMismatch - .Replace("$1", Vars.CurrentLang.TargetVersion) - .Replace("$2", Vars.AppVer.ToString()), - ParseMode.Markdown, - false, - false).ConfigureAwait(false); + Log("Language version mismatch detected", "CORE", LogLevel.Warning); + if (Vars.CurrentConf.CheckLangVersionMismatch) + _ = await Vars.Bot.SendTextMessageAsync(Vars.CurrentConf.OwnerUID, + Vars.CurrentLang.Message_LangVerMismatch + .Replace("$1", Vars.CurrentLang.TargetVersion) + .Replace("$2", Vars.AppVer.ToString()), + ParseMode.Markdown, + false, + false).ConfigureAwait(false); } + Check("Language version mismatch checked"); + Check("Complete"); + if (Vars.CurrentConf.AnalyzeStartupTime) + { + Log("Advanced startup time analysis is on, printing startup checkpoints..."); + PrintCheckPoints(); + _checkPoints.Clear(); + } + Log("==> All finished!"); if (Vars.ServiceMode) - { while (true) - { Thread.Sleep(int.MaxValue); - } - } else - { while (true) - { Console.ReadKey(true); - } - } - } catch (Exception ex) { CheckOpenSSLComp(ex); - Log($"Unexpected error during startup: {ex.ToString()}", "CORE", LogLevel.ERROR); + Log($"Unexpected error during startup: {ex}", "CORE", LogLevel.Error); Environment.Exit(1); } } diff --git a/pmcenter/Setup.cs b/pmcenter/Setup.cs index a2252a5..37058af 100644 --- a/pmcenter/Setup.cs +++ b/pmcenter/Setup.cs @@ -14,39 +14,39 @@ namespace pmcenter { - public class Setup + public static class Setup { - private static Conf.ConfObj NewConf = new Conf.ConfObj(); - private static TelegramBotClient TestBot; - private static bool IsUIDReceived = false; - private static long ReceivedUID = -1; - private static string Nickname = ""; + private static readonly Conf.ConfObj newConf = new Conf.ConfObj(); + private static TelegramBotClient testBot; + private static bool isUidReceived = false; + private static long receivedUid = -1; + private static string nickname = ""; private static void OnUpdate(object sender, UpdateEventArgs e) { Say("Update received."); Say(".. Processing..."); - if (!IsUIDReceived) + if (!isUidReceived) { - IsUIDReceived = true; - ReceivedUID = e.Update.Message.From.Id; - Nickname = string.IsNullOrEmpty(e.Update.Message.From.LastName) ? e.Update.Message.From.FirstName : $"{e.Update.Message.From.FirstName} {e.Update.Message.From.LastName}"; - TestBot.StopReceiving(); + isUidReceived = true; + receivedUid = e.Update.Message.From.Id; + nickname = string.IsNullOrEmpty(e.Update.Message.From.LastName) ? e.Update.Message.From.FirstName : $"{e.Update.Message.From.FirstName} {e.Update.Message.From.LastName}"; + testBot.StopReceiving(); } } - private static void Say(string Input) + private static void Say(string input) { - Console.WriteLine(Input); + Console.WriteLine(input); } - private static void SIn(string Input) + private static void SIn(string input) { - Console.Write(Input); + Console.Write(input); } public static async Task SetupWizard() { Say(":) Welcome!"); Say(" This is the pmcenter setup wizard."); - Say($" App version: {Vars.AppVer.ToString()}"); + Say($" App version: {Vars.AppVer}"); Say(" Here to guide you through some *important* configurations of pmcenter."); SIn("=> Continue? [y/N]: "); if (Console.ReadLine().ToLower() != "y") @@ -71,8 +71,8 @@ public static async Task SetupWizard() Say(" All major configurations have been set!"); Say(""); SIn("=> Save configurations? [Y/n]: "); - string Choice = Console.ReadLine(); - if (Choice.ToLower() != "n") + var choice = Console.ReadLine(); + if (choice.ToLower() != "n") { if (File.Exists(Vars.ConfFile)) { @@ -87,7 +87,7 @@ public static async Task SetupWizard() Say(" Done!"); } SIn($"Saving configurations to {Vars.ConfFile}..."); - Vars.CurrentConf = NewConf; + Vars.CurrentConf = newConf; _ = await Conf.SaveConf().ConfigureAwait(false); Say(" Done!"); if (File.Exists(Vars.LangFile)) @@ -131,12 +131,12 @@ private static async Task SetAPIKey() Say(""); EnterKey: SIn("=> Enter your API Key: "); - string Key = Console.ReadLine(); - SIn($".. Testing API Key: {Key}..."); + string key = Console.ReadLine(); + SIn($".. Testing API Key: {key}..."); try { - TestBot = new TelegramBotClient(Key); - if (!await TestBot.TestApiAsync().ConfigureAwait(false)) + testBot = new TelegramBotClient(key); + if (!await testBot.TestApiAsync().ConfigureAwait(false)) { throw (new ArgumentException("API Key is not valid.")); } @@ -147,7 +147,7 @@ private static async Task SetAPIKey() Say($" Invalid API Key: {ex.Message}"); goto EnterKey; } - NewConf.APIKey = Key; + newConf.APIKey = key; Say(" Done!"); } private static async Task SetUID() @@ -158,30 +158,30 @@ private static async Task SetUID() Say(""); EnterUID: SIn("=> Enter your UID, or \"auto\" for automatic setup: "); - string UID = Console.ReadLine(); - if (UID.ToLower() == "auto") + string uid = Console.ReadLine(); + if (uid.ToLower() == "auto") { Say(".. Preparing for automatic UID detection..."); - TestBot.OnUpdate += OnUpdate; - TestBot.StartReceiving(new UpdateType[] { UpdateType.Message }); + testBot.OnUpdate += OnUpdate; + testBot.StartReceiving(new UpdateType[] { UpdateType.Message }); Say("Say something to your bot on Telegram. We'll detect your UID automatically."); - while (!IsUIDReceived) + while (!isUidReceived) { Thread.Sleep(200); } - _ = await TestBot.SendTextMessageAsync(ReceivedUID, $"👋 *Hello my owner!* Your UID `{ReceivedUID}` is now being saved.", ParseMode.Markdown); - Say($"Hello, [{Nickname}]! Your UID has been detected as {ReceivedUID}."); - SIn($".. Saving UID: {ReceivedUID}..."); - NewConf.OwnerUID = ReceivedUID; + _ = await testBot.SendTextMessageAsync(receivedUid, $"👋 *Hello my owner!* Your UID `{receivedUid}` is now being saved.", ParseMode.Markdown); + Say($"Hello, [{nickname}]! Your UID has been detected as {receivedUid}."); + SIn($".. Saving UID: {receivedUid}..."); + newConf.OwnerUID = receivedUid; Say(" Done!"); } else { try { - long NewUID = long.Parse(UID); - SIn($".. Saving UID: {NewUID}..."); - NewConf.OwnerUID = NewUID; + long newUid = long.Parse(uid); + SIn($".. Saving UID: {newUid}..."); + newConf.OwnerUID = newUid; Say(" Done!"); } catch (Exception ex) @@ -199,7 +199,7 @@ private static void SetNotifPrefs() SIn("=> Mute notifications? [y/N]: "); string muteNotif = Console.ReadLine(); SIn(".. Saving..."); - NewConf.DisableNotifications = muteNotif.ToLower() != "y" ? true : false; + newConf.DisableNotifications = muteNotif.ToLower() != "y" ? true : false; Say(" Done!"); } private static void SetAutoBanPrefs() @@ -210,7 +210,7 @@ private static void SetAutoBanPrefs() SIn("=> Automatically ban flooding users? [Y/n]: "); string autoBan = Console.ReadLine(); SIn(".. Saving..."); - NewConf.AutoBan = autoBan.ToLower() != "n" ? true : false; + newConf.AutoBan = autoBan.ToLower() != "n" ? true : false; Say(" Done!"); } private static void SetMessageLinks() @@ -223,8 +223,8 @@ private static void SetMessageLinks() SIn("=> Enable message links? [Y/n]: "); string enableMsgLinks = Console.ReadLine(); SIn(".. Saving..."); - NewConf.EnableMsgLink = enableMsgLinks.ToLower() != "n" ? true : false; + newConf.EnableMsgLink = enableMsgLinks.ToLower() != "n" ? true : false; Say(" Done!"); } } -} \ No newline at end of file +} diff --git a/pmcenter/Template.cs b/pmcenter/Template.cs index a8728c6..9f581f5 100644 --- a/pmcenter/Template.cs +++ b/pmcenter/Template.cs @@ -4,11 +4,9 @@ // Copyright (C) The pmcenter authors. Licensed under the Apache License (Version 2.0). */ -using System; - namespace pmcenter { public class Template { } -} \ No newline at end of file +} diff --git a/pmcenter/Vars.cs b/pmcenter/Vars.cs index 06706c2..e461b47 100644 --- a/pmcenter/Vars.cs +++ b/pmcenter/Vars.cs @@ -4,6 +4,9 @@ // Copyright (C) The pmcenter authors. Licensed under the Apache License (Version 2.0). */ +//#define BUILT_FOR_GITHUB_RELEASES +//#define SELFCONTAINED + using System; using System.Collections.Generic; using System.Diagnostics; @@ -16,10 +19,10 @@ namespace pmcenter { public static class Vars { - public readonly static string ASCII = " __ \n ____ ____ ___ ________ ____ / /____ _____\n / __ \\/ __ `__ \\/ ___/ _ \\/ __ \\/ __/ _ \\/ ___/\n / /_/ / / / / / / /__/ __/ / / / /_/ __/ / \n / .___/_/ /_/ /_/\\___/\\___/_/ /_/\\__/\\___/_/ \n/_/ "; - public readonly static Version AppVer = new Version("1.9.280.15"); + public readonly static string AsciiArt = " __ \n ____ ____ ___ ________ ____ / /____ _____\n / __ \\/ __ `__ \\/ ___/ _ \\/ __ \\/ __/ _ \\/ ___/\n / /_/ / / / / / / /__/ __/ / / / /_/ __/ / \n / .___/_/ /_/ /_/\\___/\\___/_/ /_/\\__/\\___/_/ \n/_/ "; + public readonly static Version AppVer = new Version("2.0.2.0"); public readonly static string AppExecutable = Assembly.GetExecutingAssembly().Location; - public readonly static string AppDirectory = (new FileInfo(AppExecutable)).DirectoryName; + public readonly static string AppDirectory = Path.GetDirectoryName(AppExecutable); public static string ConfFile = Path.Combine(AppDirectory, "pmcenter.json"); public static string LangFile = Path.Combine(AppDirectory, "pmcenter_locale.json"); public readonly static string UpdateArchiveURL = "https://see.wtf/pmcenter-update"; @@ -31,7 +34,17 @@ public static class Vars #else public readonly static string CompileChannel = "pmcenter-lazer"; #endif - // public readonly static long AnonymousChannelID = -1001228946795; +#if BUILT_FOR_GITHUB_RELEASES + public readonly static bool GitHubReleases = true; +#else + public readonly static bool GitHubReleases = false; +#endif +#if SELFCONTAINED + public readonly static bool SelfContained = true; +#else + public readonly static bool SelfContained = false; +#endif + // public readonly static long AnonymousChannelId = -1001228946795; // public readonly static string AnonymousChannelTitle = "a user"; // public readonly static string AnonymousChannelUsername = "HiddenSender"; @@ -43,7 +56,7 @@ public static class Vars public static int CtrlCCounter = 0; public static bool IsShuttingDown = false; public static bool ServiceMode = true; - public static Conf.UpdateLevel UpdateLevel; + public static Methods.UpdateHelper.UpdateLevel UpdateLevel; public static Version UpdateVersion; public static Stopwatch StartSW = new Stopwatch(); public static List RateLimits = new List(); @@ -56,7 +69,7 @@ public static class Vars public static bool IsPerformanceTestEndRequested = false; public static double PerformanceScore = 0; - public static Thread BannedSweepper; + public static Thread BannedSweeper; public static Thread ConfValidator; public static Methods.ThreadStatus ConfResetTimerStatus = Methods.ThreadStatus.Stopped; public static Thread RateLimiter; @@ -65,4 +78,4 @@ public static class Vars public static Methods.ThreadStatus UpdateCheckerStatus = Methods.ThreadStatus.Stopped; public static Thread SyncConf; } -} \ No newline at end of file +} diff --git a/pmcenter/pmcenter.csproj b/pmcenter/pmcenter.csproj index 0267928..bc377f6 100644 --- a/pmcenter/pmcenter.csproj +++ b/pmcenter/pmcenter.csproj @@ -2,14 +2,15 @@ Exe - netcoreapp2.1 + netcoreapp3.1 pmcenter.Program + - + diff --git a/updateinfo.json b/updateinfo.json index 7f5e4ee..9bf363e 100644 --- a/updateinfo.json +++ b/updateinfo.json @@ -1,5 +1,5 @@ { - "Latest": "1.9.1.271", + "Latest": "2.0.2.0", "Details": "`If you're using pmcenter `1.7.93.230` or older, you would only see this update message in the future but you could still upgrade to the latest version at any time.`", "UpdateLevel": 1 } \ No newline at end of file diff --git a/updateinfo2.json b/updateinfo2.json index 3402047..fdd52a3 100644 --- a/updateinfo2.json +++ b/updateinfo2.json @@ -1,9 +1,9 @@ { - "Latest": "1.9.280.15", + "Latest": "2.0.2.0", "UpdateLevel": 1, "UpdateCollection": [ { - "Details": "[i] This is the final update before pmcenter v2 arrives.\n[+] Added .NET Core Runtime version check.\n[+] Added Ctrl-C event handler.\n[/] Updated Setup Wizard.\n[+] Updated exiting mechanism.", + "Details": "Welcome to pmcenter 2.0!\n\npmcenter now depends on .NET Core 3.1, with these enhancements and new features:\n[/] Backend code refactor\n[/] Now pmcenter turns on Message Links by default\n[+] NuGet package updates\n[+] HTTP/2 protocol support\n[+] Dices & darts support\n[+] Inline keyboard actions support\n[+] R2R + AOT packages available via GitHub releases\n[+] Startup time analysis\n[+] Toggleable autosave\n[+] Better forwarding logics\n[+] JSON configuration files can be minified\n[+] Language version mismatch check is now toggleable", "LangCode": [ "en.imported", "en.integrated" @@ -12,7 +12,7 @@ "UpdateArchiveAddress": "https://see.wtf/pmcenter-update" }, { - "Details": "[i] 这是 pmcenter v2 更新前的最后一次更新。\n[+] 添加 .NET Core 运行时版本检查。\n[+] 添加 Ctrl-C 事件处理器。\n[/] 更新了设置向导。\n[+] 全新的退出机制。", + "Details": "欢迎使用 pmcenter 2.0!\n\npmcenter 现依赖于 .NET Core 3.1,伴有以下更新内容:\n[/] 后端代码重构\n[/] 现在 pmcenter 默认启用消息链接\n[+] NuGet 包更新\n[+] HTTP/2 协议支持\n[+] 骰子 & 飞镖支持\n[+] 内联键盘操作支持\n[+] R2R + AOT 包现可通过 GitHub releases 获取\n[+] 启动时间分析\n[+] 自动保存命令\n[+] 优化的转发逻辑\n[+] JSON 配置文件现可最小化\n[+] 可开关语言文件版本匹配警告", "LangCode": [ "zh.simplified" ], @@ -20,7 +20,7 @@ "UpdateArchiveAddress": "https://see.wtf/pmcenter-update" }, { - "Details": "[i] 这是 pmcenter v2 更新前的最后一次更新。\n[+] 添加 .NET Core 运行时版本检查。\n[+] 添加 Ctrl-C 事件处理器。\n[/] 更新了设置向导。\n[+] 全新的退出机制。", + "Details": "欢迎使用 pmcenter 2.0!\n\npmcenter 现依赖于 .NET Core 3.1,伴有以下更新内容:\n[/] 后端代码重构\n[/] 现在 pmcenter 默认启用消息链接\n[+] NuGet 包更新\n[+] HTTP/2 协议支持\n[+] 骰子 & 飞镖支持\n[+] 内联键盘操作支持\n[+] R2R + AOT 包现可通过 GitHub releases 获取\n[+] 启动时间分析\n[+] 自动保存命令\n[+] 优化的转发逻辑\n[+] JSON 配置文件现可最小化\n[+] 可开关语言文件版本匹配警告", "LangCode": [ "zh.meow" ], @@ -28,7 +28,7 @@ "UpdateArchiveAddress": "https://see.wtf/pmcenter-update" }, { - "Details": "[i] 這是 pmcenter v2 更新前的最後一次更新。\n[+] 新增 .NET Core 運行時版本檢查。\n[+] 新增 Ctrl-C 事件處理器。\n[/] 更新了設置向導。\n[+] 全新的退出機制。", + "Details": "歡迎使用 pmcenter 2.0!\n\npmcenter 現依賴於 .NET Core 3.1,隨附以下更新內容:\n[/] 後端程式碼重構\n[/] 默認啟用訊息連結\n[+] NuGet 軟件包更新\n[+] HTTP/2 協議支援\n[+] 骰子 & 飛鏢支援\n[+] 內聯鍵盤操作支援\n[+] R2R + AOT 包可透過 GitHub releases 獲取\n[+] 啟動時間分析\n[+] 自動儲存命令\n[+] 優化的轉發邏輯\n[+] JSON 配置文件現可最小化\n[+] 可開關語言文件版本匹配警告", "LangCode": [ "zh.tw" ], @@ -36,7 +36,7 @@ "UpdateArchiveAddress": "https://see.wtf/pmcenter-update" }, { - "Details": "[i] This is the final update before pmcenter v2 arrives.\n[+] Added .NET Core Runtime version check.\n[+] Added Ctrl-C event handler.\n[/] Updated Setup Wizard.\n[+] Updated exiting mechanism.", + "Details": "Welcome to pmcenter 2.0!\n\npmcenter now depends on .NET Core 3.1, with these enhancements and new features:\n[/] Backend code refactor\n[/] Now pmcenter turns on Message Links by default\n[+] NuGet package updates\n[+] HTTP/2 protocol support\n[+] Dices & darts support\n[+] Inline keyboard actions support\n[+] R2R + AOT packages available via GitHub releases\n[+] Startup time analysis\n[+] Toggleable autosave\n[+] Better forwarding logics\n[+] JSON configuration files can be minified\n[+] Language version mismatch check is now toggleable", "LangCode": [ "en.imported", "en.integrated" @@ -45,7 +45,7 @@ "UpdateArchiveAddress": "https://see.wtf/pmcenter-lazer-update" }, { - "Details": "[i] 这是 pmcenter v2 更新前的最后一次更新。\n[+] 添加 .NET Core 运行时版本检查。\n[+] 添加 Ctrl-C 事件处理器。\n[/] 更新了设置向导。\n[+] 全新的退出机制。", + "Details": "欢迎使用 pmcenter 2.0!\n\npmcenter 现依赖于 .NET Core 3.1,伴有以下更新内容:\n[/] 后端代码重构\n[/] 现在 pmcenter 默认启用消息链接\n[+] NuGet 包更新\n[+] HTTP/2 协议支持\n[+] 骰子 & 飞镖支持\n[+] 内联键盘操作支持\n[+] R2R + AOT 包现可通过 GitHub releases 获取\n[+] 启动时间分析\n[+] 自动保存命令\n[+] 优化的转发逻辑\n[+] JSON 配置文件现可最小化\n[+] 可开关语言文件版本匹配警告", "LangCode": [ "zh.simplified" ], @@ -53,7 +53,7 @@ "UpdateArchiveAddress": "https://see.wtf/pmcenter-lazer-update" }, { - "Details": "[i] 这是 pmcenter v2 更新前的最后一次更新。\n[+] 添加 .NET Core 运行时版本检查。\n[+] 添加 Ctrl-C 事件处理器。\n[/] 更新了设置向导。\n[+] 全新的退出机制。", + "Details": "欢迎使用 pmcenter 2.0!\n\npmcenter 现依赖于 .NET Core 3.1,伴有以下更新内容:\n[/] 后端代码重构\n[/] 现在 pmcenter 默认启用消息链接\n[+] NuGet 包更新\n[+] HTTP/2 协议支持\n[+] 骰子 & 飞镖支持\n[+] 内联键盘操作支持\n[+] R2R + AOT 包现可通过 GitHub releases 获取\n[+] 启动时间分析\n[+] 自动保存命令\n[+] 优化的转发逻辑\n[+] JSON 配置文件现可最小化\n[+] 可开关语言文件版本匹配警告", "LangCode": [ "zh.meow" ], @@ -61,7 +61,7 @@ "UpdateArchiveAddress": "https://see.wtf/pmcenter-lazer-update" }, { - "Details": "[i] 這是 pmcenter v2 更新前的最後一次更新。\n[+] 新增 .NET Core 運行時版本檢查。\n[+] 新增 Ctrl-C 事件處理器。\n[/] 更新了設置向導。\n[+] 全新的退出機制。", + "Details": "歡迎使用 pmcenter 2.0!\n\npmcenter 現依賴於 .NET Core 3.1,隨附以下更新內容:\n[/] 後端程式碼重構\n[/] 默認啟用訊息連結\n[+] NuGet 軟件包更新\n[+] HTTP/2 協議支援\n[+] 骰子 & 飛鏢支援\n[+] 內聯鍵盤操作支援\n[+] R2R + AOT 包可透過 GitHub releases 獲取\n[+] 啟動時間分析\n[+] 自動儲存命令\n[+] 優化的轉發邏輯\n[+] JSON 配置文件現可最小化\n[+] 可開關語言文件版本匹配警告", "LangCode": [ "zh.tw" ],