2022-10-08 22:47:18 +08:00
// This file is generated automatically by amalgamate;
// GitHub repo https://github.com/edlund/amalgamate
// When contributing to this repository, please DO NOT edit this file.
// Copyright (C) 2020-2021 Eritque arcus and contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or any later version(in your opinion).
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
# ifndef MIRAICP_PRO_PLUGINCONFIG_H
# define MIRAICP_PRO_PLUGINCONFIG_H
2022-10-20 13:15:42 +08:00
# if defined(_WIN32)
# include <windows.h>
# if defined(_MSC_VER)
# pragma warning(disable: 4474)
# pragma warning(disable: 4615)
# pragma warning(disable: 4819)
# pragma warning(disable: 6031)
# endif
# elif defined(__linux__) || defined(unix) || defined(__unix__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__)
# include <dlfcn.h>
# include <unistd.h>
# elif defined(__APPLE__) || defined(__MACH__)
# include <mach-o/dyld.h>
# endif
2022-10-08 22:47:18 +08:00
# include <json.hpp>
namespace MiraiCP {
const std : : string MiraiCPVersion = " v2.12.0-RC2 " ;
struct PluginConfig {
/// @brief 插件id, 要与别人不一样否则报错无法加载(建议用类包格式,如: io.github.nambers)
const char * id ;
/// @brief 插件名称
const char * name ;
/// @brief 插件版本
const char * version ;
/// @brief 插件作者(及联系方式)
const char * author ;
/// @brief [optional]插件描述
const char * description ;
/// @brief [optional]构建时间, 默认为__DATE__宏
const char * time = __DATE__ ;
const char * mversion = MiraiCPVersion . c_str ( ) ;
std : : string getId ( ) const {
return { id } ;
}
std : : string getName ( ) const {
return { name } ;
}
std : : string getVersion ( ) const {
return { version } ;
}
std : : string getAuthor ( ) const {
return { author } ;
}
std : : string getDescription ( ) const {
return { description } ;
}
std : : string getTime ( ) const {
return { time } ;
}
std : : string getMVersion ( ) const {
return { mversion } ;
}
nlohmann : : json serialize ( ) ;
std : : string serialize2string ( ) ;
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_PLUGINCONFIG_H
// Copyright (c) 2022. Eritque arcus and contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or any later version(in your opinion).
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
# ifndef MIRAICP_PRO_COMMONTOOLS_H
# define MIRAICP_PRO_COMMONTOOLS_H
# include <functional>
# define MiraiCP_defer(code) \
auto __defered_statement_wrapper__ = [ & ] ( ) { code } ; \
CommonTools : : MiraiCPDefer < void > __defered_object__ ( __defered_statement_wrapper__ )
# define MiraiCP_defer_lambda(lambda) \
auto __defered_statement_wrapper__ = lambda ; \
CommonTools : : MiraiCPDefer < void > __defered_object__ ( __defered_statement_wrapper__ )
namespace CommonTools {
/// defer class
/// @see MiraiCP_defer
template < typename RT_TYPE >
class MiraiCPDefer {
public :
std : : function < RT_TYPE ( ) > defer_func ;
template < class F >
MiraiCPDefer ( F & & func ) : defer_func ( std : : forward < F > ( func ) ) {
}
virtual ~ MiraiCPDefer ( ) {
defer_func ( ) ;
}
} ;
} // namespace CommonTools
# endif //MIRAICP_PRO_COMMONTOOLS_H
// Copyright (c) 2022. Eritque arcus and contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or any later version(in your opinion).
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
# ifndef MIRAICP_PRO_COMMONTYPES_H
# define MIRAICP_PRO_COMMONTYPES_H
// don't create cpp for this header
// #include "PluginConfig.h"
// #include "loaderApiInternal.h"
// Copyright (c) 2022. Eritque arcus and contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or any later version(in your opinion).
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
# ifndef MIRAICP_PRO_LOADERAPIINTERNAL_H
# define MIRAICP_PRO_LOADERAPIINTERNAL_H
// #include "miraicpString.h"
// Copyright (c) 2022. Eritque arcus and contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or any later version(in your opinion).
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
# ifndef MIRAICP_PRO_MIRAICPSTRING_H
# define MIRAICP_PRO_MIRAICPSTRING_H
# include <cassert>
# include <string>
namespace MiraiCP {
// this class is used to ensure data consistency between dynamic libs
// note: do not use this directly;
// always convert to const char* or std::string before using.
class MiraiCPString {
using string = std : : string ;
friend void swap ( MiraiCPString & , MiraiCPString & ) noexcept ;
private :
static constexpr decltype ( & : : std : : free ) std_free_ptr = & : : std : : free ;
private :
// to keep integration and safe for empty construction/deconstruction, always initialize here
char * str = nullptr ;
size_t _size = 0 ;
decltype ( & : : std : : free ) free_this = std_free_ptr ; // specify which free() to use; ensure deconstruction is paired to construction
public :
bool isEmpty ( ) const {
return _size = = 0 ;
}
MiraiCPString ( ) : str ( nullptr ) , _size ( 0 ) , free_this ( std_free_ptr ) { }
// call if _size is set to non-zero
// allocate memory for str
void construction ( ) ;
~ MiraiCPString ( ) ;
MiraiCPString ( const MiraiCPString & other ) ;
MiraiCPString ( MiraiCPString & & temp ) noexcept ;
MiraiCPString ( const char * char_str ) ;
MiraiCPString ( const std : : string & string_str ) ;
std : : string toString ( ) const {
if ( str = = nullptr | | _size = = 0 ) return { } ;
return { str } ;
}
operator std : : string ( ) const {
return toString ( ) ;
}
// for safe destruction, DO NOT provide move convert to char*
// the return value of this method can always be deleted by delete[] and is never nullptr
const char * copyToCharPtr ( ) const ;
bool operator = = ( const MiraiCPString & another ) const ;
MiraiCPString & operator = ( const MiraiCPString & another ) ;
MiraiCPString & operator = ( MiraiCPString & & another ) noexcept ;
} ;
static_assert ( sizeof ( char ) = = 1 , " Please make sure the size of char type is 1 " ) ;
static_assert ( sizeof ( MiraiCPString ) = = 3 * 8 , " Please make sure MiraiCP is compiled under 64-bit mode. " ) ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_MIRAICPSTRING_H
# ifdef MIRAICP_LIB_LOADER
constexpr int LOADERAPI_H_COUNTER_BASE = __COUNTER__ + 1 ;
# define LOADERAPI_H_NOTHING(X)
# define LOADERAPI_H_LOADER_API_INNER(X) LOADERAPI_H_NOTHING(X)
# define LOADER_API_COUNT LOADERAPI_H_LOADER_API_INNER(__COUNTER__)
# define LOADERAPI_H_GET_COUNTER (__COUNTER__ - LOADERAPI_H_COUNTER_BASE)
# else
# define LOADER_API_COUNT
# endif
// the API defs to be exposed
namespace LibLoader : : LoaderApi {
using MiraiCP : : MiraiCPString ;
LOADER_API_COUNT
MiraiCPString pluginOperation ( const MiraiCPString & ) ;
LOADER_API_COUNT
void loggerInterface ( const MiraiCPString & content , const MiraiCPString & name , long long id , int level ) ;
LOADER_API_COUNT
MiraiCPString showAllPluginId ( ) ;
LOADER_API_COUNT
void enablePluginById ( const MiraiCPString & ) ;
LOADER_API_COUNT
void disablePluginById ( const MiraiCPString & ) ;
LOADER_API_COUNT
void enableAllPlugins ( ) ;
LOADER_API_COUNT
void disableAllPlugins ( ) ;
LOADER_API_COUNT
void loadNewPlugin ( const MiraiCPString & , bool ) ;
LOADER_API_COUNT
void unloadPluginById ( const MiraiCPString & ) ;
LOADER_API_COUNT
void reloadPluginById ( const MiraiCPString & ) ;
struct interface_funcs {
decltype ( & pluginOperation ) _pluginOperation ;
decltype ( & loggerInterface ) _loggerInterface ;
decltype ( & showAllPluginId ) _showAllPluginId ;
// function below can only be called by admin plugins
decltype ( & enablePluginById ) _enablePluginById = nullptr ;
decltype ( & disablePluginById ) _disablePluginById = nullptr ;
decltype ( & enableAllPlugins ) _enableAllPlugins = nullptr ;
decltype ( & disableAllPlugins ) _disableAllPlugins = nullptr ;
decltype ( & loadNewPlugin ) _loadNewPlugin = nullptr ;
decltype ( & unloadPluginById ) _unloadPluginById = nullptr ;
decltype ( & reloadPluginById ) _reloadPluginById = nullptr ;
} ;
# ifdef MIRAICP_LIB_LOADER
constexpr inline interface_funcs collect_interface_functions ( bool admin ) {
constexpr int counter = LOADERAPI_H_GET_COUNTER ;
static_assert ( sizeof ( interface_funcs ) = = sizeof ( void * ) * counter ) ;
if ( admin ) {
constexpr int line0 = __LINE__ ;
interface_funcs t = {
pluginOperation ,
loggerInterface ,
showAllPluginId ,
enablePluginById ,
disablePluginById ,
enableAllPlugins ,
disableAllPlugins ,
loadNewPlugin ,
unloadPluginById ,
reloadPluginById ,
} ;
constexpr int line1 = __LINE__ ;
static_assert ( line1 - line0 = = counter + 3 ) ;
return t ;
} else {
interface_funcs t2 = {
pluginOperation ,
loggerInterface ,
showAllPluginId ,
} ; // no admin functions
return t2 ;
}
}
# endif
} // namespace LibLoader::LoaderApi
# endif //MIRAICP_PRO_LOADERAPIINTERNAL_H
# define FUNC_ENTRANCE FUNC_ENTRANCE
# define FUNC_EVENT FUNC_EVENT
# define FUNC_EXIT FUNC_EXIT
# define PLUGIN_INFO PLUGIN_INFO
namespace LibLoader {
typedef void * plugin_handle ;
/// @see @macro FUNC_ENTRANCE
typedef void ( * plugin_entrance_func_ptr ) ( const LoaderApi : : interface_funcs & ) ;
/// @see @macro FUNC_EVENT
typedef void ( * plugin_event_func_ptr ) ( const char * ) ;
/// @see @macro FUNC_EXIT
typedef void ( * plugin_func_ptr ) ( ) ;
/// @see @macro PLUGIN_INFO
typedef const MiraiCP : : PluginConfig & ( * plugin_info_func_ptr ) ( ) ;
} // namespace LibLoader
# endif //MIRAICP_PRO_COMMONTYPES_H
// Copyright (c) 2022. Eritque arcus and contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or any later version(in your opinion).
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
# ifndef MIRAICP_PRO_LOADERAPIINTERNAL_H
# define MIRAICP_PRO_LOADERAPIINTERNAL_H
// #include "miraicpString.h"
# ifdef MIRAICP_LIB_LOADER
constexpr int LOADERAPI_H_COUNTER_BASE = __COUNTER__ + 1 ;
# define LOADERAPI_H_NOTHING(X)
# define LOADERAPI_H_LOADER_API_INNER(X) LOADERAPI_H_NOTHING(X)
# define LOADER_API_COUNT LOADERAPI_H_LOADER_API_INNER(__COUNTER__)
# define LOADERAPI_H_GET_COUNTER (__COUNTER__ - LOADERAPI_H_COUNTER_BASE)
# else
# define LOADER_API_COUNT
# endif
// the API defs to be exposed
namespace LibLoader : : LoaderApi {
using MiraiCP : : MiraiCPString ;
LOADER_API_COUNT
MiraiCPString pluginOperation ( const MiraiCPString & ) ;
LOADER_API_COUNT
void loggerInterface ( const MiraiCPString & content , const MiraiCPString & name , long long id , int level ) ;
LOADER_API_COUNT
MiraiCPString showAllPluginId ( ) ;
LOADER_API_COUNT
void enablePluginById ( const MiraiCPString & ) ;
LOADER_API_COUNT
void disablePluginById ( const MiraiCPString & ) ;
LOADER_API_COUNT
void enableAllPlugins ( ) ;
LOADER_API_COUNT
void disableAllPlugins ( ) ;
LOADER_API_COUNT
void loadNewPlugin ( const MiraiCPString & , bool ) ;
LOADER_API_COUNT
void unloadPluginById ( const MiraiCPString & ) ;
LOADER_API_COUNT
void reloadPluginById ( const MiraiCPString & ) ;
struct interface_funcs {
decltype ( & pluginOperation ) _pluginOperation ;
decltype ( & loggerInterface ) _loggerInterface ;
decltype ( & showAllPluginId ) _showAllPluginId ;
// function below can only be called by admin plugins
decltype ( & enablePluginById ) _enablePluginById = nullptr ;
decltype ( & disablePluginById ) _disablePluginById = nullptr ;
decltype ( & enableAllPlugins ) _enableAllPlugins = nullptr ;
decltype ( & disableAllPlugins ) _disableAllPlugins = nullptr ;
decltype ( & loadNewPlugin ) _loadNewPlugin = nullptr ;
decltype ( & unloadPluginById ) _unloadPluginById = nullptr ;
decltype ( & reloadPluginById ) _reloadPluginById = nullptr ;
} ;
# ifdef MIRAICP_LIB_LOADER
constexpr inline interface_funcs collect_interface_functions ( bool admin ) {
constexpr int counter = LOADERAPI_H_GET_COUNTER ;
static_assert ( sizeof ( interface_funcs ) = = sizeof ( void * ) * counter ) ;
if ( admin ) {
constexpr int line0 = __LINE__ ;
interface_funcs t = {
pluginOperation ,
loggerInterface ,
showAllPluginId ,
enablePluginById ,
disablePluginById ,
enableAllPlugins ,
disableAllPlugins ,
loadNewPlugin ,
unloadPluginById ,
reloadPluginById ,
} ;
constexpr int line1 = __LINE__ ;
static_assert ( line1 - line0 = = counter + 3 ) ;
return t ;
} else {
interface_funcs t2 = {
pluginOperation ,
loggerInterface ,
showAllPluginId ,
} ; // no admin functions
return t2 ;
}
}
# endif
} // namespace LibLoader::LoaderApi
# endif //MIRAICP_PRO_LOADERAPIINTERNAL_H
// Copyright (c) 2022. Eritque arcus and contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or any later version(in your opinion).
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
# ifndef MIRAICP_PRO_MIRAICPSTRING_H
# define MIRAICP_PRO_MIRAICPSTRING_H
# include <cassert>
# include <string>
namespace MiraiCP {
// this class is used to ensure data consistency between dynamic libs
// note: do not use this directly;
// always convert to const char* or std::string before using.
class MiraiCPString {
using string = std : : string ;
friend void swap ( MiraiCPString & , MiraiCPString & ) noexcept ;
private :
static constexpr decltype ( & : : std : : free ) std_free_ptr = & : : std : : free ;
private :
// to keep integration and safe for empty construction/deconstruction, always initialize here
char * str = nullptr ;
size_t _size = 0 ;
decltype ( & : : std : : free ) free_this = std_free_ptr ; // specify which free() to use; ensure deconstruction is paired to construction
public :
bool isEmpty ( ) const {
return _size = = 0 ;
}
MiraiCPString ( ) : str ( nullptr ) , _size ( 0 ) , free_this ( std_free_ptr ) { }
// call if _size is set to non-zero
// allocate memory for str
void construction ( ) ;
~ MiraiCPString ( ) ;
MiraiCPString ( const MiraiCPString & other ) ;
MiraiCPString ( MiraiCPString & & temp ) noexcept ;
MiraiCPString ( const char * char_str ) ;
MiraiCPString ( const std : : string & string_str ) ;
std : : string toString ( ) const {
if ( str = = nullptr | | _size = = 0 ) return { } ;
return { str } ;
}
operator std : : string ( ) const {
return toString ( ) ;
}
// for safe destruction, DO NOT provide move convert to char*
// the return value of this method can always be deleted by delete[] and is never nullptr
const char * copyToCharPtr ( ) const ;
bool operator = = ( const MiraiCPString & another ) const ;
MiraiCPString & operator = ( const MiraiCPString & another ) ;
MiraiCPString & operator = ( MiraiCPString & & another ) noexcept ;
} ;
static_assert ( sizeof ( char ) = = 1 , " Please make sure the size of char type is 1 " ) ;
static_assert ( sizeof ( MiraiCPString ) = = 3 * 8 , " Please make sure MiraiCP is compiled under 64-bit mode. " ) ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_MIRAICPSTRING_H
# ifndef MIRAICP_PRO_BOT_H
# define MIRAICP_PRO_BOT_H
# include <string>
# include <vector>
// #include "MiraiDefs.h"
# ifndef MIRAICP_PRO_MIRAIDEFS_H
# define MIRAICP_PRO_MIRAIDEFS_H
// #define MiraiCPThrow(x) throw x.append(__FILE__, __LINE__)
# define ErrorHandle(x, y) ErrorHandle0(__FILE__, __LINE__, (x), (y))
# define MIRAICP_EXCEPTION_WHERE __FILE__, __LINE__
# if defined(_MSC_VER)
# define ShouldNotUse(msg) _Pragma("warning(error:4996)") [[deprecated(msg)]] _Pragma("warning(warning:4996)")
# else // MSVC
# if defined(__GNUC__)
# define ShouldNotUse(msg) [[deprecated(msg)]] __attribute__((error(msg)))
# else // GUNC
# define ShouldNotUse(msg)
# endif // ShouldNotUse
# endif
# include <string>
namespace MiraiCP {
using QQID = unsigned long long ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_MIRAIDEFS_H
namespace MiraiCP {
class Friend ; // forward declaration
class Group ; // forward declaration
class Contact ; // forward declaration
/// 当前bot账号信息
class Bot {
private :
bool inited = false ;
std : : string _nick ;
std : : string _avatarUrl ;
public :
/// 该botid
QQID id ;
private :
void check ( ) {
if ( ! this - > inited ) {
refreshInfo ( ) ;
this - > inited = true ;
}
}
public :
/*!
* @ brief 刷 新 bot信息
* @ param env
*/
void refreshInfo ( ) ;
/// 用id构建机器人
explicit Bot ( QQID i ) : id ( i ) { }
/// 取好友
Friend getFriend ( QQID i ) const ;
/// 取群聊
Group getGroup ( QQID groupid ) const ;
/// 昵称
std : : string nick ( ) {
check ( ) ;
return this - > _nick ;
}
/// 头像下载链接
std : : string avatarUrl ( ) {
check ( ) ;
return this - > _avatarUrl ;
}
/// 取好友列表
std : : vector < QQID > getFriendList ( ) const ;
/// 好友列表string形式返回, 利于保存
std : : string FriendListToString ( ) ;
/// 取群列表
std : : vector < QQID > getGroupList ( ) const ;
/// 群列表string形式返回, 利于保存
std : : string GroupListToString ( ) const ;
bool operator = = ( const Contact & c ) const ;
bool operator = = ( const Bot & b ) const {
return this - > id = = b . id ;
}
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_BOT_H
# ifndef MIRAICP_PRO_CPPPLUGIN_H
# define MIRAICP_PRO_CPPPLUGIN_H
# include <utility>
// #include "Logger.h"
# ifndef MIRAICP_PRO_LOGGER_H
# define MIRAICP_PRO_LOGGER_H
// #include "MiraiCode.h"
# ifndef MIRAICP_PRO_MIRAICODE_H
# define MIRAICP_PRO_MIRAICODE_H
# include <string>
namespace MiraiCP {
/// MiraiCode父类, 指可以被转换成miraicode的类型
class MiraiCodeable {
public :
/// 返回MiraiCode
virtual std : : string toMiraiCode ( ) const = 0 ;
} ;
/// @brief miraicode字符串
/// @attention MiraiCode会把非miraicode组成部分(非[mirai:])转码, 输出转码前的文本用toString, 参考: https://github.com/mamoe/mirai/blob/dev/docs/Messages.md#%E8%BD%AC%E4%B9%89%E8%A7%84%E5%88%99
/// @detail 为了便捷使用, 构造函数不以explicit注释
class MiraiCode : public MiraiCodeable {
private :
std : : string content ;
public :
/// 输出当前内容, 会自动转码
std : : string toString ( ) ;
/// 和toString作用一样, 不过不会自动转码
std : : string toMiraiCode ( ) const override {
return content ;
}
/// 从MiraiCodeable类型初始化一个miraicode字符串
MiraiCode ( MiraiCodeable * a ) { // NOLINT(google-explicit-constructor)
content = a - > toMiraiCode ( ) ;
}
/// 从文本初始化一个miraicode字符串, 根据第二个参数决定是否转码, 默认不转码
/// @attention 如果是传入文本MiraiCode, 请勿转码, 转码只是为了[mirai:xxx:<应该转码的部分>], 如果<应该转码>的部分里面含有'[]:,'内容, 请调用Tools::escapeToMiraiCode转码
MiraiCode ( const std : : string & a , bool convert = false ) ;
MiraiCode operator + ( MiraiCodeable * a ) {
return { content + a - > toMiraiCode ( ) } ;
}
MiraiCode operator + ( const std : : string & a ) {
return { content + a } ;
}
MiraiCode operator + ( const MiraiCode & a ) {
return { content + a . content } ;
}
MiraiCode operator + ( MiraiCode * a ) {
return { content + a - > content } ;
}
MiraiCode & operator = ( const std : : string & a ) {
this - > content = a ;
return * this ;
}
MiraiCode plus ( MiraiCodeable * a ) {
return { content + a - > toMiraiCode ( ) } ;
}
MiraiCode plus ( const std : : string & a ) {
return MiraiCode ( a ) + this ;
}
/// 不执行转义, 适用于已经被MiraiCode转义过的字符串
static MiraiCode MiraiCodeWithoutEscape ( const std : : string & a ) {
return { a , false } ;
}
/// 不执行转义, 因为MiraiCodeable的toMiraiCode已经转义过了
static MiraiCode MiraiCodeWithoutEscape ( MiraiCodeable * a ) {
return { a - > toMiraiCode ( ) , false } ;
}
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_MIRAICODE_H
// #include "MiraiDefs.h"
# include <functional>
# include <sstream>
namespace MiraiCP {
class MiraiCodeable ; // forward declaration
/*!
* @ class Logger
* @ brief 以 MiraiCP的名义发送日志 , 日 志 表 现 格 式 是 : 2021 - 06 - 28 09 : 37 : 22 [ log level ] / MiraiCP : [ log content ] , 为 最 底 层 的 logger
* 发 送 消 息 级 日 志
* @ code Logger : : logger . info ( string ) @ endcode
* 发 送 警 告 级 日 志
* @ code Logger : : logger . warning ( string ) @ endcode
* 发 送 错 误 级 日 志
* @ code Logger : : logger . error ( string ) @ endcode
* @ doxygenEg { 1011 , logger . cpp , 自 定 义 日 志 handle }
*/
class Logger_interface {
using string = std : : string ;
public :
/// @brief 封装lambda类型
/// @param string 日志内容
/// @param 日志级别
/// - 0 info
/// - 1 warning
/// - 2 error
typedef std : : function < void ( string , int ) > Action ;
/// @brief loggerhandler会在每次log执行前执行一遍, 可用于执行自定义的保存操作等
struct Handler {
/// @brief 是否启用
bool enable = true ;
/// @brief 执行的操作, 格式为lambda
Action action = [ ] ( const string & content , int level ) { } ;
} ;
Handler loggerhandler ;
private :
static std : : string constructString ( ) {
return " " ;
}
template < class T , class . . . T1 >
static std : : string constructString ( T val , T1 . . . val1 ) {
std : : stringstream sstream ;
sstream < < val ;
return sstream . str ( ) + constructString ( val1 . . . ) ;
}
template < class . . . T >
static std : : string constructString ( std : : string a , T . . . val1 ) {
return a + constructString ( val1 . . . ) ;
}
template < class . . . T >
static std : : string constructString ( MiraiCodeable & val , T . . . val1 ) {
return val . toMiraiCode ( ) + constructString ( val1 . . . ) ;
}
protected :
/// @brief 日志底层实现封装
/// @param log 日志内容
/// @param level 日志等级
virtual void log_interface ( const string & log , int level ) = 0 ;
public :
///发送普通(info级日志)
template < class . . . T >
void info ( T . . . val ) {
this - > log_interface ( constructString ( val . . . ) , 0 ) ;
}
///发送警告(warning级日志)
template < class . . . T >
void warning ( T . . . val ) {
this - > log_interface ( constructString ( val . . . ) , 1 ) ;
}
///发送错误(error级日志)
template < class . . . T >
void error ( T . . . val ) {
this - > log_interface ( constructString ( val . . . ) , 2 ) ;
}
/// @brief 设置loggerhandler的action
/// @param action 执行的操作
/// @see Logger::handler
void registerHandle ( Action action ) {
this - > loggerhandler . action = std : : move ( action ) ;
}
/// @brief 设置handler的启用状态
/// @param state 状态,启用或者关闭
/// @doxygenEg{1012, logger.cpp, 启用或关闭日志}
void setHandleState ( bool state ) {
this - > loggerhandler . enable = state ;
}
} ;
class Logger : public Logger_interface {
private :
Logger ( ) = default ;
protected :
/// @brief 日志底层实现封装
/// @param content 日志内容
/// @param level 日志等级
void log_interface ( const std : : string & content , int level ) override ;
public :
static Logger logger ;
} ;
/// 带id(一般为bot账号)的logger
class IdLogger : public Logger_interface {
public :
QQID id ;
protected :
void log_interface ( const std : : string & content , int level ) override ;
public :
IdLogger ( QQID id , Logger * l ) : id ( id ) {
this - > loggerhandler = l - > loggerhandler ;
}
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_LOGGER_H
// #include "PluginConfig.h"
namespace MiraiCP {
/// 插件父类
class CPPPlugin {
public :
// for api-compatible
ShouldNotUse ( " 请改为初始化静态常量 CPPPlugin::config " ) explicit CPPPlugin ( const PluginConfig & c ) {
// 不可覆盖原本的config, 这里什么都不做
}
explicit CPPPlugin ( ) = default ;
virtual ~ CPPPlugin ( ) = default ;
public :
/// @brief 插件信息,一个插件中该内容不应变化
const static PluginConfig config ;
/// @brief 插件级logger
/// @deprecated use Logger::logger instead
[[deprecated("Use Logger::logger instead")]] static Logger * pluginLogger ;
static std : : unique_ptr < CPPPlugin > plugin ;
public :
/// 插件启用时调用一次
virtual void onEnable ( ) { }
virtual void onDisable ( ) { }
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_CPPPLUGIN_H
# ifndef MIRAICP_PRO_COMMAND_H
# define MIRAICP_PRO_COMMAND_H
// #include "CPPPlugin.h"
// #include "Exception.h"
# ifndef MIRAICP_PRO_EXCEPTION_H
# define MIRAICP_PRO_EXCEPTION_H
// #include "CPPPlugin.h"
# include <exception>
# include <string>
# include <thread>
namespace MiraiCP {
/// @brief 总异常抽象类,用于一般捕获,不要直接抛出该类,不知道抛出什么的时候请抛出 MiraiCPException
/// @interface MiraiCPExceptionBase
class MiraiCPExceptionBase : public : : std : : exception {
protected :
using string = std : : string ;
protected :
/// @brief 异常内容
string re ;
public :
/// @brief 发生异常的文件名
string filename ;
/// @brief 发生异常的行号
int lineNum = 0 ;
protected :
/// 受保护构造函数,供子类调用
MiraiCPExceptionBase ( string info , string _filename , int _lineNum ) : re ( std : : move ( info ) ) , filename ( std : : move ( _filename ) ) , lineNum ( _lineNum ) { }
public :
~ MiraiCPExceptionBase ( ) override = default ;
public :
/// 异常信息
const char * what ( ) const noexcept override { return re . c_str ( ) ; }
/// 返回std::string的异常信息
string getError ( ) const { return re ; }
/// 实际抛出方法
void raise ( ) const ;
public : // 暴露的接口
/// basicRaise 基本抛出方法,子类重写该方法
virtual void basicRaise ( ) const ;
// CRTP实现一次, 调用静态的exceptionType
/// 获取异常类型,通用接口
virtual string getExceptionType ( ) const = 0 ;
// 每个子类需要单独实现该静态方法
/// 返回异常的类型,该静态方法无法正确实现多态,请使用 getExceptionType
/// @see getExceptionType
static string exceptionType ( ) { return " MiraiCPException " ; }
} ;
/// @brief 总异常CRTP抽象类, 不要直接抛出该类, 不知道抛出什么的时候请抛出 MiraiCPException。
/// 该类是用于继承的基类,需要新的异常类型时,继承该类并以子类作为模板参数。
/// 子类需要实现的方法:
/// 1. 构造函数, 要求必须委托MiraiCPExceptionCRTP构造, 其他成员需要在MiraiCPException构造前完成构造。
/// 2. `static std::string exceptionType()` 返回一个字符串表示异常类型。
/// 继承该类后异常类能正确实现多态。
/// @interface MiraiCPExceptionCRTP
/// @note 请勿给该类增加新的属性。如果要增加属性应在 MiraiCPExceptionBase 中增加
template < class T >
class MiraiCPExceptionCRTP : public MiraiCPExceptionBase {
public :
/// 委托构造函数
explicit MiraiCPExceptionCRTP ( std : : string _re , string _filename , int _lineNum ) : MiraiCPExceptionBase ( std : : move ( _re ) , std : : move ( _filename ) , _lineNum ) {
}
public :
// CRTP类型获取实现
string getExceptionType ( ) const override { return T : : exceptionType ( ) ; }
} ;
/// @brief 通用MiraiCP异常
/// @param const string &description, string _filename, int _lineNum
/// @see MiraiCPExceptionBase
typedef MiraiCPExceptionCRTP < MiraiCPExceptionBase > MiraiCPException ;
/// 文件读取异常.
/// @see MiraiCPExceptionBase
class UploadException : public MiraiCPExceptionCRTP < UploadException > {
public :
explicit UploadException ( const std : : string & text , string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 上传(图片/文件)异常 " + text , std : : move ( _filename ) , _lineNum ) { }
static std : : string exceptionType ( ) { return " UploadException " ; }
} ;
/// 通常为Mirai返回
/// @see MiraiCPExceptionBase
class IllegalStateException : public MiraiCPExceptionCRTP < IllegalStateException > {
public :
explicit IllegalStateException ( const std : : string & text , string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 状态异常: " + text , std : : move ( _filename ) , _lineNum ) { }
static std : : string exceptionType ( ) { return " IllegalStateException " ; }
} ;
/// 内部异常, 通常为json读写问题
/// @see MiraiCPExceptionBase
class APIException : public MiraiCPExceptionCRTP < APIException > {
public :
explicit APIException ( const std : : string & text , string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " MiraiCP内部无法预料的错误: " + text , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " APIException " ; }
} ;
/// 机器人操作异常
/// @see MiraiCPExceptionBase
class BotException : public MiraiCPExceptionCRTP < BotException > {
public :
explicit BotException ( string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 没有权限执行该操作 " , std : : move ( _filename ) , _lineNum ) { }
explicit BotException ( const string & d , string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( d , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " BotException " ; }
} ;
/// 被禁言异常, 通常发生于发送信息
class BotIsBeingMutedException : public MiraiCPExceptionCRTP < BotIsBeingMutedException > {
public :
/// 剩余禁言时间, 单位秒
int timeRemain ;
public :
explicit BotIsBeingMutedException ( int t , string _filename , int _lineNum ) : timeRemain ( t ) , MiraiCPExceptionCRTP ( " 发送信息失败, bot已被禁言, 剩余时间 " + std : : to_string ( t ) , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " BotIsBeingMutedException " ; }
} ;
/// 禁言异常
/// @see MiraiCPExceptionBase
class MuteException : public MiraiCPExceptionCRTP < MuteException > {
public :
/*
* 禁 言 时 间 超 出 0 s ~ 30 d
*/
MuteException ( string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 禁言时长不在0s~30d中间 " , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " MuteException " ; }
} ;
/// 获取群成员错误
/// @see MiraiCPExceptionBase
class MemberException : public MiraiCPExceptionCRTP < MemberException > {
public :
enum MemberExceptionType : int {
OtherType ,
NoSuchGroup ,
NoSuchMember
} ;
MemberExceptionType type = OtherType ;
/*
* " 1 " - 找 不 到 群
* " 2 " - 找 不 到 群 成 员
*/
explicit MemberException ( int _type , string _filename , int _lineNum ) : MiraiCPExceptionCRTP (
[ & ] ( ) - > string {
type = MemberExceptionType ( _type ) ;
switch ( type ) {
case NoSuchGroup :
return " 找不到群 " ;
case NoSuchMember :
return " 找不到群成员 " ;
default :
return " " ;
}
} ( ) ,
std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " MemberException " ; }
} ;
/// 获取群成员错误
/// @see MiraiCPExceptionBase
class FriendException : public MiraiCPExceptionCRTP < FriendException > {
public :
/*
* 找 不 到 好 友
*/
FriendException ( string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 找不到好友 " , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " FriendException " ; }
} ;
/// 获取群错误
/// @see MiraiCPExceptionBase
class GroupException : public MiraiCPExceptionCRTP < GroupException > {
public :
GroupException ( string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 找不到群 " , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " GroupException " ; }
} ;
/// 撤回异常
/// @see MiraiCPExceptionBase
class RecallException : public MiraiCPExceptionCRTP < RecallException > {
public :
RecallException ( string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 该消息已经被撤回 " , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " RecallException " ; }
} ;
/// 远程资源出现问题
/// @see MiraiCPExceptionBase
class RemoteAssetException : public MiraiCPExceptionCRTP < RemoteAssetException > {
public :
explicit RemoteAssetException ( const string & e , string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( e , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " RemoteAssetException " ; }
} ;
/// 参数错误
/// @see MiraiCPExceptionBase
class IllegalArgumentException : public MiraiCPExceptionCRTP < IllegalArgumentException > {
public :
explicit IllegalArgumentException ( const string & e , string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( e , std : : move ( _filename ) , _lineNum ) {
}
static string exceptionType ( ) { return " IllegalArgumentException " ; }
} ;
/// 超时
/// @see MiraiCPExceptionBase
class TimeOutException : public MiraiCPExceptionCRTP < TimeOutException > {
public :
explicit TimeOutException ( const std : : string & e , string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( e , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " TimeOutException " ; }
} ;
/// 事件被取消, 一般出现在发送消息时在preSendMessageEvent取消的时候抛出
/// @see MiraiCPExceptionBase
class EventCancelledException : public MiraiCPExceptionCRTP < EventCancelledException > {
public :
explicit EventCancelledException ( const string & msg , string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( msg , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " EventCancelledException " ; }
} ;
/// 插件没有权限时抛出该异常
/// 该异常仅可能在插件尝试调用libLoader 高级权限的Api接口时抛出
/// 如插件尝试重载、加载、卸载插件等操作,但配置文件中并没有赋予该插件权限时
/// @see MiraiCPExceptionBase
class PluginNotAuthorizedException : public MiraiCPExceptionCRTP < PluginNotAuthorizedException > {
public :
explicit PluginNotAuthorizedException ( string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 插件 " + CPPPlugin : : config . getId ( ) + " 没有管理权限 " , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " PluginNotAuthorizedException " ; }
} ;
/// 插件未加载抛出该异常
/// 在插件能正常运行时不会抛出, 出现该异常事件时请不要再次尝试收发消息等Mirai操作,
/// 否则可能导致异常处理时再次抛出异常
/// @see MiraiCPExceptionBase
class PluginNotEnabledException : public MiraiCPExceptionCRTP < PluginNotEnabledException > {
public :
explicit PluginNotEnabledException ( string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 插件 " + CPPPlugin : : config . getId ( ) + " 未加载 " , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " PluginNotEnabledException " ; }
} ;
/// 如果在 MiraiCPNewThread 中捕获到了非 MiraiCP 之外的异常抛出
/// @see MiraiCPNewThread
class MiraiCPThreadException : public MiraiCPExceptionCRTP < MiraiCPThreadException > {
public :
/// 抛出异常的线程 ID
std : : thread : : id threadId ;
public :
explicit MiraiCPThreadException ( const std : : string & exception_content , std : : thread : : id threadId , string _filename , int _lineNum )
: MiraiCPExceptionCRTP ( exception_content + " at threadId: " + getThreadIdStr ( threadId ) , std : : move ( _filename ) , _lineNum ) ,
threadId ( threadId ) { }
public :
std : : string getThreadIdStr ( ) const { return getThreadIdStr ( threadId ) ; }
public :
static string exceptionType ( ) { return " MiraiCPThreadException " ; }
private :
static std : : string getThreadIdStr ( const std : : thread : : id & id ) {
std : : stringstream ss ;
ss < < id ;
return ss . str ( ) ;
}
} ;
inline void ErrorHandle0 ( const std : : string & name , int line , const std : : string & re , const std : : string & ErrorMsg = " " ) {
if ( re = = " EF " )
throw FriendException ( name , line ) ;
if ( re = = " EG " )
throw GroupException ( name , line ) ;
if ( re = = " EM " )
throw MemberException ( 1 , name , line ) ;
if ( re = = " EMM " )
throw MemberException ( 2 , name , line ) ;
if ( re = = " EB " )
throw BotException ( " 找不到bot: " + re , name , line ) ;
if ( re = = " EA " )
throw APIException ( ErrorMsg , name , line ) ;
if ( re = = " EC " )
throw EventCancelledException ( " 发送信息被取消 " , name , line ) ;
if ( re = = " ET " )
throw TimeOutException ( " 发送信息超时 " , name , line ) ;
if ( re = = " EP " )
throw BotException ( name , line ) ;
// equal to Tools::start_with
if ( re . rfind ( " EBM " , 0 ) = = 0 )
throw BotIsBeingMutedException ( std : : stoi ( re . substr ( 3 ) ) , name , line ) ;
}
} // namespace MiraiCP
# endif //MIRAICP_PRO_EXCEPTION_H
// #include "KtOperation.h"
# ifndef MIRAICP_PRO_KTOPERATION_H
# define MIRAICP_PRO_KTOPERATION_H
# include <json.hpp>
/// @brief 配置类声明, MiraiCP内部使用, 不需要更改或其他操作
/// @internal 一般为MiraiCP内部调用jni接口使用
/// @namespace KtOperation
namespace MiraiCP : : KtOperation {
/// 操作id
enum operation_set {
/// 撤回信息
Recall ,
/// 发送信息
Send ,
/// 查询信息接口
RefreshInfo ,
/// 上传图片
UploadImg ,
/// 取好友列表
QueryBFL ,
/// 取群组列表
QueryBGL ,
/// 上传文件
SendFile ,
/// 查询文件信息
RemoteFileInfo ,
/// 查询图片下载地址
QueryImgInfo ,
/// 禁言
MuteM ,
/// 查询权限
QueryM ,
/// 踢出
KickM ,
/// 取群主
QueryOwner ,
/// 语音
Voice ,
/// 查询群成员列表
QueryML ,
/// 群设置
GroupSetting ,
/// 构建转发信息
Buildforward ,
/// 好友申请事件
Nfroperation ,
/// 群聊邀请事件
Gioperation ,
/// 回复(引用并发送)
SendWithQuote ,
/// 群公告操作
Announcement ,
/// 定时任务
TimeOut ,
/// 发送戳一戳
SendNudge ,
/// 下一条信息
NextMsg ,
/// 更改权限
ModifyAdmin ,
/// 群成员申请入群
MemberJoinRequest ,
/// 图片是否已经上传
ImageUploaded ,
/// 注册指令
CommandReg ,
/// 改名称
ChangeNameCard ,
} ;
/**
* @ brief 调 用 mirai操作
* @ param type 操 作 id
* @ param data 传 入 数 据
* @ return 返 回 数 据
*/
std : : string ktOperation (
operation_set type ,
nlohmann : : json data ,
bool catchErr = true ,
const std : : string & errorInfo = " " ) ;
} // namespace MiraiCP::KtOperation
# endif //MIRAICP_PRO_KTOPERATION_H
// #include "Logger.h"
# include <optional>
namespace MiraiCP {
class MessageChain ;
class Bot ;
class Contact ;
/*!
* @ brief 指 令 Interface
* @ doxygenEg { 1001 , command . cpp , 新 建 自 定 义 命 令 }
* @ attention loader端的命令只支持从console传入 , plugin端是对接mirai的RawCommand
*/
class IRawCommand {
using string = std : : string ;
public :
struct Config {
public :
/// 指令名不能为空
string primaryName ;
/// 可以为空
std : : vector < string > secondNames ;
/// 用法
string usage = " null " ;
/// 描述
string description = " null " ;
/// 覆盖已有命令
bool overrideOrigin = false ;
/// 前缀`/`可省略
bool preFixOption = false ;
} ;
virtual IRawCommand : : Config config ( ) = 0 ;
virtual void onCommand ( std : : optional < Contact > , const Bot & , const MessageChain & ) = 0 ;
IRawCommand ( ) = default ;
virtual ~ IRawCommand ( ) = default ;
} ;
class CommandManager {
private :
CommandManager ( ) = default ;
std : : vector < std : : shared_ptr < IRawCommand > > commandList ;
public :
std : : shared_ptr < IRawCommand > & operator [ ] ( const int & index ) { return commandList [ index ] ; }
/*!
* @ brief 注 册 一 条 指 令
* @ param command 指 令
* @ return 是 否 注 册 成 功
*/
template < class T >
bool registerCommand ( T command ) {
static_assert ( std : : is_base_of_v < IRawCommand , T > , " 只支持IRawCommand的派生类 " ) ;
nlohmann : : json j ;
j [ " pluginId " ] = CPPPlugin : : config . id ;
j [ " usage " ] = command . config ( ) . usage ;
j [ " primaryName " ] = command . config ( ) . primaryName ;
j [ " secondName " ] = command . config ( ) . secondNames ;
j [ " description " ] = command . config ( ) . description ;
j [ " override " ] = command . config ( ) . overrideOrigin ;
j [ " preFixOption " ] = command . config ( ) . preFixOption ;
size_t before = commandList . size ( ) ;
std : : shared_ptr < IRawCommand > c ;
c . reset ( new T ( command ) ) ;
commandList . push_back ( c ) ;
size_t now = commandList . size ( ) ;
if ( now - before = = 1 )
j [ " bindId " ] = now - 1 ;
else {
auto i = std : : find ( commandList . begin ( ) , commandList . end ( ) , c ) ;
if ( i ! = commandList . end ( ) )
j [ " bindId " ] = i - commandList . begin ( ) ;
else
throw IllegalArgumentException ( " 找不到合适的bindId " , MIRAICP_EXCEPTION_WHERE ) ;
}
nlohmann : : json rej ;
rej [ " command " ] = j . dump ( ) ;
std : : string re = KtOperation : : ktOperation ( KtOperation : : CommandReg , rej ) ;
return re = = " true " ;
}
static CommandManager commandManager ;
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_COMMAND_H
# ifndef MIRAICP_PRO_CONTACT_H
# define MIRAICP_PRO_CONTACT_H
// #include "MessageChain.h"
# ifndef MIRAICP_PRO_MESSAGECHAIN_H
# define MIRAICP_PRO_MESSAGECHAIN_H
// #include "Exception.h"
// #include "SingleMessage.h"
# ifndef MIRAICP_PRO_SINGLEMESSAGE_H
# define MIRAICP_PRO_SINGLEMESSAGE_H
# include <array>
# include <json.hpp>
# include <optional>
# include <sstream>
// #include "MessageSource.h"
# ifndef MIRAICP_PRO_MESSAGESOURCE_H
# define MIRAICP_PRO_MESSAGESOURCE_H
# include <string>
// #include "MiraiDefs.h"
namespace MiraiCP {
class MiraiCodeable ; // forward declaration
/*! 消息源声明
* @ doxygenEg { 1014 , message . cpp , 回 复 信 息 }
*/
class MessageSource {
public :
/// 消息的ids
std : : string ids ;
/// 消息的internalids
std : : string internalids ;
/// 消息源序列化
std : : string source ;
MessageSource ( ) = default ;
/// @deprecated 用Contact.quoteAndSendMessage, since v2.8.1
ShouldNotUse ( " Use Contact.quoteAndSendMessage " ) MessageSource
quoteAndSendMiraiCode ( MiraiCodeable * msg , QQID groupid = 0 ,
void * env = nullptr ) const = delete ;
/// @deprecated use Contact.quoteAndSendMessage, since v2.8.1
ShouldNotUse ( " Use Contact.quoteAndSendMessage " ) MessageSource
quoteAndSendMsg ( const std : : string & c , QQID groupid = 0 ,
void * = nullptr ) const = delete ;
/// @deprecated use Contact.quoteAndSendMessage, since v2.8.1
ShouldNotUse ( " Use Contact.quoteAndSendMessage " ) MessageSource
quoteAndSendMiraiCode ( const std : : string & c , QQID groupid = 0 ,
void * = nullptr ) const = delete ;
/*!
* @ brief 构 建 消 息 源
* @ param ids
* @ param internalids
* @ param source
*/
MessageSource ( std : : string ids , std : : string internalids , std : : string source ) ;
/*!
* @ brief 从 json字符串反序列化到MessageSource对象
* @ note json应该为以下格式
* @ code
* { " ids " : " " , " internalids " : " " }
* @ endcode
*/
static MessageSource deserializeFromString ( const std : : string & source ) ;
std : : string serializeToString ( ) const ;
/// @brief 撤回该信息
void recall ( ) const ;
bool operator = = ( const MessageSource & ms ) const {
return this - > ids = = ms . ids & & this - > internalids = = ms . internalids ;
}
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_MESSAGESOURCE_H
// #include "MiraiCode.h"
namespace MiraiCP {
/// 用serviceMessage的分享信息
struct URLSharer {
/// 简介 没点进来看见的样子
std : : string brief = " 简介 没点进来看见的样子 " ;
/// 目标url
std : : string url = " 目标url " ;
/// 图标地址
std : : string cover = " 图标地址 " ;
/// 标题
std : : string title = " 标题 " ;
/// 描述文字
std : : string summary = " 描述文字 " ;
} ;
/// MessageChain的组成部分
class SingleMessage : public MiraiCodeable {
public :
/// MiraiCode类别
/// @see SingleMessage::messageType
int type ;
std : : string content ;
std : : string prefix ;
public :
static std : : unordered_map < int , std : : string > messageType ;
public :
/// @brief 构建单条
/// @param type 消息类型 @see messageType
/// @param content 内容
/// @param prefix 前缀, 默认为`:`, 第二个冒号部分的内容, 目前在serviceMesage有使用
SingleMessage ( int type , std : : string content , std : : string prefix = " : " ) : type ( type ) ,
content ( std : : move ( content ) ) ,
prefix ( std : : move ( prefix ) ) { }
virtual ~ SingleMessage ( ) = default ;
public :
/// @brief 找对应类型的index key
/// @param value 类型名
/// @return 如果没找到返回-1
static int getKey ( const std : : string & value ) ;
public :
virtual nlohmann : : json toJson ( ) const {
nlohmann : : json re ;
re [ " key " ] = " miraicode " ;
re [ " content " ] = this - > toMiraiCode ( ) ;
return re ;
}
std : : string toMiraiCode ( ) const override ;
public :
bool operator = = ( const SingleMessage & m ) const {
return this - > type = = m . type & & this - > toMiraiCode ( ) = = m . toMiraiCode ( ) ;
}
bool operator = = ( SingleMessage * m ) const {
return this - > type = = m - > type & & this - > toMiraiCode ( ) = = m - > toMiraiCode ( ) ;
}
} ;
/// 纯文本信息
class PlainText : public SingleMessage {
public :
explicit PlainText ( const SingleMessage & sg ) ;
template < typename T >
explicit PlainText ( const T & a ) : SingleMessage ( PlainText : : type ( ) , ( [ & a ] ( ) - > std : : string {
std : : stringstream sst ;
sst < < a ;
return sst . str ( ) ;
} ) ( ) ) { }
PlainText ( PlainText & & _o ) noexcept : SingleMessage ( PlainText : : type ( ) , std : : move ( _o . content ) ) { }
PlainText ( const PlainText & _o ) : SingleMessage ( PlainText : : type ( ) , _o . content ) { }
public :
static int type ( ) { return 0 ; }
public :
std : : string toMiraiCode ( ) const override {
return content ;
}
nlohmann : : json toJson ( ) const override ;
bool operator = = ( const PlainText & p ) const {
return this - > content = = p . content ;
}
} ;
/// @
class At : public SingleMessage {
public :
static int type ( ) { return 1 ; }
QQID target ;
nlohmann : : json toJson ( ) const override ;
explicit At ( const SingleMessage & sg ) ;
explicit At ( QQID a ) : SingleMessage ( At : : type ( ) , std : : to_string ( a ) ) , target ( a ) { } ;
std : : string toMiraiCode ( ) const override {
return " [mirai:at: " + std : : to_string ( this - > target ) + " ] " ; // 后面有个空格
}
bool operator = = ( const At & a ) const {
return this - > target = = a . target ;
}
} ;
/// @brief \@全体
class AtAll : public SingleMessage {
public :
static int type ( ) { return 2 ; }
std : : string toMiraiCode ( ) const override {
return " [mirai:atall] " ;
}
nlohmann : : json toJson ( ) const override ;
AtAll ( ) : SingleMessage ( AtAll : : type ( ) , " " , " " ) { }
} ;
/// 图像类声明
class Image : public SingleMessage {
public :
static int type ( ) { return 3 ; }
//图片id, 样式:` {xxx}.xx `
std : : string id ;
/// 可为空, 用`refreshInfo`获取
std : : optional < std : : string > md5 ;
/// 可为0, 来源:用`refreshInfo`可能可以获取或者自己填充, 是isUploaded的必须条件, 默认0
size_t size ;
/// 可为空, 用`refreshInfo`获取
std : : optional < std : : string > url ;
/// 宽度, 默认0, 单位px
int width ;
/// 长度, 默认0, 单位px
int height ;
/*!
* @ brief 图 片 类 型
* - 0 png
* - 1 bmp
* - 2 jpg
* - 3 gif
* - 4 apng
* - 5 unknown
* 默 认 5
*/
int imageType ;
/*!
* @ brief 图 片 是 否 已 经 上 传 ( 如 果 已 经 上 传 即 表 明 可 以 直 接 用 ImageId发送 , 如 果 没 有 需 要 手 动 上 传 )
* @ param md5 在 kotlin端会用 . toByteArray ( ) 转 换
* @ param size 图 片 大 小 , 不 能 为 0
* @ param botid 所 属 Botid
* @ return 是 否 已 上 传
*/
bool isUploaded ( QQID botid ) ;
/*!
* @ brief 从 图 片 builder构造 , 适 用 于 服 务 器 上 已 经 有 的 图 片 , 即 接 收 到 的
* @ param imageId 图 片 id , 必 须
* @ param size isUploaded的必要条件 , 单 纯 用 ImageId可能取不到图片size , 需 要 自 己 上 传
* @ param width 宽 度
* @ param height 长 度
* @ param type 图 片 类 型
* @ detail 图 片 miraiCode格式例子 , ` [ mirai : image : { 图 片 id } . jpg ] `
* 可 以 用 这 个 正 则 表 达 式 找 出 id ` \ \ [ mirai : image : ( . * ? ) \ \ ] `
*/
explicit Image ( const std : : string & imageId , size_t size = 0 , int width = 0 , int height = 0 , int type = 5 ) : SingleMessage ( Image : : type ( ) , imageId ) {
this - > id = imageId ;
this - > size = size ;
this - > width = width ;
this - > height = height ;
this - > imageType = type ;
}
explicit Image ( const SingleMessage & sg ) ;
/// 刷新信息(获取图片下载Url,md5, size)
void refreshInfo ( ) ;
/// 取图片Mirai码
std : : string toMiraiCode ( ) const override {
return " [mirai:image: " + this - > id + " ] " ;
}
nlohmann : : json toJson ( ) const override ;
static Image deserialize ( const std : : string & ) ;
bool operator = = ( const Image & i ) const {
return this - > id = = i . id ;
}
} ;
/// 闪照, 和Image属性类似
class FlashImage : public Image {
public :
static int type ( ) { return 8 ; }
std : : string toMiraiCode ( ) const override {
return " [mirai:flash: " + this - > id + " ] " ;
}
explicit FlashImage ( const std : : string & imageId , size_t size = 0 , int width = 0 , int height = 0 , int type = 0 ) : Image ( imageId , size , width , height , type ) {
this - > SingleMessage : : type = 8 ;
}
explicit FlashImage ( const SingleMessage & sg ) : Image ( sg ) { }
explicit FlashImage ( const Image & img ) : Image ( img ) { }
nlohmann : : json toJson ( ) const override ;
static FlashImage deserialize ( const std : : string & ) ;
bool operator = = ( const FlashImage & i ) const {
return this - > id = = i . id ;
}
/// 转换到普通图片
Image toImage ( ) { return Image ( id , size , width , height , imageType ) ; }
} ;
/*!
* @ brief 小 程 序 卡 片
* @ attention 自 带 的 模 板 不 稳 定 , 可 能 发 出 现 没 有 效 果
* @ doxygenEg { 1015 , lightApp . cpp , 从 文 本 构 建 LightApp }
*/
class LightApp : public SingleMessage {
public :
static int type ( ) { return 4 ; }
/// @brief 使用纯文本构造,推荐使用其他结构体方法构造
/// @param content 构造文本
explicit LightApp ( std : : string content ) : SingleMessage ( LightApp : : type ( ) , std : : move ( content ) ) { }
explicit LightApp ( const SingleMessage & sg ) ;
nlohmann : : json toJson ( ) const override ;
/// 返回miraicode
std : : string toMiraiCode ( ) const override ;
bool operator = = ( const LightApp & la ) const {
return this - > content = = la . content ;
}
} ;
/// xml格式的超文本信息
/// @attention 自带的模板不稳定,可能发出现没有效果
class ServiceMessage : public SingleMessage {
public :
static int type ( ) { return 5 ; }
nlohmann : : json toJson ( ) const override ;
std : : string toMiraiCode ( ) const override ;
int id ;
/// @brief ServiceMessage
/// @param id 在xml内容前面的id (不包括逗号)
/// @param a xml内容 (不需要事先转码到miraiCode)
explicit ServiceMessage ( int id , std : : string a ) : SingleMessage ( ServiceMessage : : type ( ) , std : : move ( a ) ,
" : " + std : : to_string ( id ) + ' , ' ) ,
id ( id ) { }
explicit ServiceMessage ( const SingleMessage & sg ) ;
explicit ServiceMessage ( const URLSharer & a ) : SingleMessage ( 5 ,
" <?xml version= \" 1.0 \" encoding= \" utf-8 \" ?><msg templateID= \" 12345 \" action= \" web \" brief= \" " +
a . brief + " \" serviceID= \" 1 \" url= \" " + a . url +
" \" ><item layout= \" 2 \" ><picture cover= \" " +
a . cover + " \" /><title> " + a . title +
" </title><summary> " + a . summary +
" </summary></item><source/></msg> " ,
" :1, " ) ,
id ( 1 ) { }
bool operator = = ( const ServiceMessage & s ) const {
return this - > content = = s . content ;
}
} ;
/// 引用信息
class QuoteReply : public SingleMessage {
public :
static int type ( ) { return - 2 ; }
// 不可直接发送, 发送引用信息用MessageChain.quoteAndSendMessage
ShouldNotUse ( " don't have MiraiCode, use MessageChain.quote instead " ) std : : string toMiraiCode ( ) const override {
return " " ;
}
/// 引用信息的MessageSource
MessageSource source ;
explicit QuoteReply ( const SingleMessage & m ) ;
explicit QuoteReply ( MessageSource source ) : SingleMessage ( QuoteReply : : type ( ) , source . serializeToString ( ) ) , source ( std : : move ( source ) ) { } ;
bool operator = = ( const QuoteReply & qr ) const {
return this - > source = = qr . source ;
}
} ;
/// 接收到的音频文件, 发送用`Contact.sendAudio`
class OnlineAudio : public SingleMessage {
public :
static int type ( ) { return - 3 ; }
/// 文件名
std : : string filename ;
/// 下载地址
std : : string url ;
/// 文件大小
int size ;
/// 编码方式
int codec ;
/// 时长(单位s)
int length ;
/// 16位md5
std : : array < uint8_t , 16 > md5 ;
/// 不支持直接发送, 用Contact.sendAudio
ShouldNotUse ( " cannot use, use Contact.sendAudio " ) std : : string toMiraiCode ( ) const override {
return " " ;
}
explicit OnlineAudio ( std : : string f , std : : array < uint8_t , 16 > md5 , int size , int codec , int length ,
std : : string url ) : SingleMessage ( OnlineAudio : : type ( ) , " " ) ,
filename ( std : : move ( f ) ) , md5 ( md5 ) , size ( size ) , codec ( codec ) ,
length ( length ) , url ( std : : move ( url ) ) { } ;
bool operator = = ( const OnlineAudio & oa ) const {
return this - > md5 = = oa . md5 ;
}
} ;
/// @brief 远程(群)文件类型
class RemoteFile : public SingleMessage {
public :
static int type ( ) { return 6 ; }
/// @brief 下载信息
/// @see RemoteFile
struct Dinfo {
/// 下载地址, 可能会是 `null` 当文件不存在
std : : string url ;
/// md5 可用于校验
std : : string md5 ;
/// sha1 可用于校验
std : : string sha1 ;
} ;
/// @brief 文件信息
/// @see RemoteFile
struct Finfo {
/// 文件大小
QQID size ;
/// 上传者id
QQID uploaderid ;
/// 过期时间
long expirytime ;
/// 上传时间, 时间戳格式
QQID uploadtime ;
/// 上次更改时间, 时间戳格式
QQID lastmodifytime ;
} ;
/// 文件唯一id, 用于识别
std : : string id ;
/// 文件内部id, 用于构造miraiCode发送
unsigned int internalid ;
/// 文件名
std : : string name ;
/// 文件大小
long long size ;
/// 文件在群文件的路径
/// @attention 可能为空(通常出现于MessageChain从MiraiCode反序列化), 需要从Group重新获取文件
/// @see Group::getFileByFile
std : : optional < std : : string > path ;
/// 文件下载信息
/// @attention 可能为空(常出现于MessageChain从MiraiCode反序列化), 如果为空需要从Group重新获取
/// @see MiraiCP::Dinfo, Group::getFileByFile
std : : optional < Dinfo > dinfo ;
/// 文件信息
/// @attention 可能为空(常出现于MessageChain从MiraiCode反序列化), 如果为空需要从Group重新获取
/// @see MiraiCP::Finfo, Group::getFileByFile
std : : optional < Finfo > finfo ;
std : : string serializeToString ( ) ;
RemoteFile plus ( unsigned int ii ) ;
static RemoteFile deserializeFromString ( const std : : string & source ) ;
/*!
* @ brief 构 造 远 程 ( 群 ) 文 件
* @ param i ids
* @ param ii internalids
* @ param n name
* @ param s size
* @ param p path
* @ param d dinfo
* @ param f finfo
*/
explicit RemoteFile ( const std : : string & i , unsigned int ii , std : : string n , long long s , std : : string p , struct Dinfo d , struct Finfo f ) ;
/*!
* @ brief 构 造 远 程 ( 群 ) 文 件
* @ param i ids
* @ param ii internalids
* @ param n name
* @ param s size
* @ param p path
* @ param d dinfo
* @ param f finfo
*/
explicit RemoteFile ( const std : : string & i , unsigned int ii , std : : string n , long long s ) ;
/// 上传后会自动发送
ShouldNotUse ( " Cannot send manually, use Group.sendFile " ) std : : string toMiraiCode ( ) const override {
return " " ;
}
bool operator = = ( const RemoteFile & rf ) const {
return this - > id = = rf . id ;
}
} ;
/// 自带表情
/// @attention 有些表情会变成PlainText类型和\\xxx 的格式
class Face : public SingleMessage {
public :
static int type ( ) { return 7 ; }
int id ;
nlohmann : : json toJson ( ) const override ;
std : : string toMiraiCode ( ) const override {
return " [mirai:face: " + std : : to_string ( id ) + " ] " ;
}
explicit Face ( int id ) : SingleMessage ( Face : : type ( ) , std : : to_string ( id ) ) , id ( id ) { }
bool operator = = ( const Face & f ) const {
return this - > id = = f . id ;
}
} ;
/// 一些可以被mirai识别的音乐卡片, 如果不能被mirai识别, 那应该被表现成lightApp类型(可能收费/vip歌曲用lightApp, 免费用MusicShare)
class MusicShare : public SingleMessage {
public :
static int type ( ) { return 9 ; }
/// 应用名称, 如NeteaseCloudMusic
std : : string appName ;
/// 歌名
std : : string title ;
/// 卡片第二行的文字内容
std : : string summary ;
/// 点击跳转到的链接
std : : string jumpUrl ;
/// 图片链接
std : : string picUrl ;
/// 音乐文件链接
std : : string musicUrl ;
/// 简介, 点进聊天节目前显示的小文字, 一般是`分享`
std : : string brief ;
std : : string toMiraiCode ( ) const override {
return " [mirai:musicshare: " + appName + " , " + title + " , " + summary + " , " + jumpUrl + " , " + picUrl + " , " + musicUrl + " , " + brief + " ] " ;
}
MusicShare ( const std : : string & appName , const std : : string & title , const std : : string & summary , const std : : string & jumpUrl , const std : : string & picUrl , const std : : string & musicUrl , const std : : string & brief ) : SingleMessage ( MusicShare : : type ( ) , " " ) , appName ( appName ) , title ( title ) , summary ( summary ) , jumpUrl ( jumpUrl ) , picUrl ( picUrl ) , musicUrl ( musicUrl ) , brief ( brief ) { }
} ;
class MarketFace : public SingleMessage {
public :
static int type ( ) { return - 5 ; }
/// 目前无法直接发送MarketFace, 可以转发
ShouldNotUse ( " 暂不支持直接发送 " ) std : : string toMiraiCode ( ) const override {
return " " ;
}
std : : array < uint8_t , 16 > faceId ;
explicit MarketFace ( std : : array < uint8_t , 16 > id ) : SingleMessage ( MarketFace : : type ( ) , " " ) , faceId ( id ) { }
bool operator = = ( const MarketFace & mf ) const {
return this - > faceId = = mf . faceId ;
}
} ;
/// @brief 目前不支持的消息类型, 不支持发送
class UnSupportMessage : public SingleMessage {
public :
static int type ( ) { return - 1 ; }
nlohmann : : json toJson ( ) const override ;
/// 不支持发送
ShouldNotUse ( " 不支持直接发送UnSupportMessage " ) std : : string toMiraiCode ( ) const override {
return " " ;
}
explicit UnSupportMessage ( const SingleMessage & s ) : SingleMessage ( s ) { } ;
explicit UnSupportMessage ( const std : : string & content ) : SingleMessage ( UnSupportMessage : : type ( ) , content ) { }
bool operator = = ( const UnSupportMessage & m ) const {
return this - > content = = m . content ;
}
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_SINGLEMESSAGE_H
namespace MiraiCP {
class MessageSource ; // forward declaration
namespace internal {
class Message : public std : : shared_ptr < SingleMessage > {
private :
// std::shared_ptr<SingleMessage> content;
public : // constructor
template < class T >
explicit Message ( const T & _singleMessage ) {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只支持SingleMessage的子类 " ) ;
reset ( new T ( _singleMessage ) ) ;
}
explicit Message ( std : : shared_ptr < SingleMessage > msgptr ) : std : : shared_ptr < SingleMessage > ( std : : move ( msgptr ) ) { }
public :
/// 代表的子类
/// @see MessageChain::messageType
int type ( ) const {
return ( * this ) - > type ;
} ;
/// 取指定类型
/// @throw IllegalArgumentException
template < class T >
T get ( ) const {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只支持SingleMessage的派生类 " ) ;
if ( T : : type ( ) ! = this - > type ( ) )
throw IllegalArgumentException ( " cannot convert from " + SingleMessage : : messageType [ this - > type ( ) ] + " to " + SingleMessage : : messageType [ T : : type ( ) ] , MIRAICP_EXCEPTION_WHERE ) ;
T * re = static_cast < T * > ( std : : shared_ptr < SingleMessage > : : get ( ) ) ;
if ( re = = nullptr )
throw IllegalArgumentException ( " cannot convert from " + SingleMessage : : messageType [ this - > type ( ) ] + " to " + SingleMessage : : messageType [ T : : type ( ) ] , MIRAICP_EXCEPTION_WHERE ) ;
return * re ;
}
std : : string toMiraiCode ( ) const {
return ( * this ) - > toMiraiCode ( ) ;
}
bool operator = = ( const Message & m ) const {
return ( * this ) - > type = = m - > type & & ( * this ) - > toMiraiCode ( ) = = m - > toMiraiCode ( ) ;
}
bool operator ! = ( const Message & m ) const {
return ( * this ) - > type ! = m - > type | | ( * this ) - > toMiraiCode ( ) ! = m - > toMiraiCode ( ) ;
}
} ;
} // namespace internal
/// 消息链, 一般由SingleMessage组成
class MessageChain : public std : : vector < internal : : Message > , public MiraiCodeable {
public : // typedefs
using Message = internal : : Message ;
public :
/// 如果由MiraiCP构造(incoming)就会存在,否则则不存在
std : : optional < MessageSource > source = std : : nullopt ;
public :
MessageChain ( const MessageChain & _o ) = default ;
MessageChain ( MessageChain & & _o ) = default ;
/// incoming构造器
template < class . . . T >
explicit MessageChain ( MessageSource ms , T . . . args ) : source ( std : : move ( ms ) ) {
this - > constructMessages ( args . . . ) ;
} ;
/*!
* @ brief 从 多 个 参 数 构 建 MessageChain
* @ tparam T 多 个 传 入 参 数 的 类 型
* 支 持 以 下 类 型 :
* - std : : string / const char * 相 当 于 传 入 PlainText
* - SingleMessage的派生类
* @ param args 参 数 本 身
*/
template < class . . . T >
explicit MessageChain ( T . . . args ) {
constructMessages ( args . . . ) ;
} ;
/// outcoming 构造器
template < class T >
explicit MessageChain ( const T & msg ) {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只支持SingleMessage子类 " ) ;
emplace_back ( msg ) ;
} ;
public :
[[deprecated("MessageChain继承自std::vector<Message>, 无需获取内部vector")]] const std : : vector < Message > & vector ( ) const {
return * static_cast < const std : : vector < Message > * > ( this ) ;
}
std : : string toMiraiCode ( ) const override ;
std : : vector < std : : string > toMiraiCodeVector ( ) const {
std : : vector < std : : string > tmp ;
for ( auto & & a : * this )
tmp . emplace_back ( a - > toMiraiCode ( ) ) ;
return tmp ;
}
/// @brief 添加元素
/// @tparam T 任意的SingleMessage的子类
/// @param a 添加的值
template < class T >
void add ( const T & a ) {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只接受SingleMessage的子类 " ) ;
emplace_back ( a ) ;
}
void add ( const MessageSource & val ) {
source = val ;
}
/// 筛选出某种类型的消息
template < class T >
std : : vector < T > filter ( ) {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只支持SingleMessage的子类 " ) ;
std : : vector < T > re ;
for ( auto & & a : * this ) {
if ( a . type ( ) = = T : : type ( ) )
re . emplace_back ( a . get < T > ( ) ) ;
}
return re ;
}
/// 自定义筛选器
template < class T >
std : : vector < T > filter ( const std : : function < bool ( Message ) > & func ) {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只支持SingleMessage的子类 " ) ;
std : : vector < T > re ;
for ( auto & & a : * this ) {
if ( func ( a ) )
re . push_back ( a . get < T > ( ) ) ;
}
return re ;
}
/// 找出第一个指定的type的消息, 消息可能不存在
template < class T >
std : : optional < T > first ( ) {
for ( auto & & a : * this )
if ( a . type ( ) = = T : : type ( ) )
return a . get < T > ( ) ;
return std : : nullopt ;
}
template < class T >
[[nodiscard]] MessageChain plus ( const T & a ) const {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只支持SingleMessage的子类 " ) ;
MessageChain tmp ( * this ) ;
tmp . emplace_back ( a ) ;
return tmp ;
}
[[nodiscard]] MessageChain plus ( const MessageChain & mc ) const {
MessageChain tmp ( * this ) ;
tmp . insert ( tmp . end ( ) , mc . begin ( ) , mc . end ( ) ) ;
return tmp ;
}
[[nodiscard]] MessageChain plus ( const MessageSource & ms ) const {
MessageChain tmp ( * this ) ;
tmp . source = ms ;
return tmp ;
}
template < class T >
MessageChain operator + ( const T & msg ) const {
return this - > plus ( msg ) ;
}
bool operator = = ( const MessageChain & mc ) const {
if ( size ( ) ! = mc . size ( ) )
return false ;
for ( size_t i = 0 ; i < size ( ) ; i + + ) {
if ( ( * this ) [ i ] ! = mc [ i ] )
return false ;
}
return true ;
}
bool operator ! = ( const MessageChain & mc ) const {
return ! ( * this = = mc ) ;
}
bool empty ( ) const {
return std : : vector < Message > : : empty ( ) | | toMiraiCode ( ) . empty ( ) ;
}
/// @brief 回复并发送
/// @param s 内容
/// @param groupid 如果是来源于TempGroupMessage就要提供(因为要找到那个Member)
/// @note 可以改MessageSource里的内容, 客户端在发送的时候并不会校验MessageSource的内容正确性(比如改originalMessage来改引用的文本的内容, 或者改id来定位到其他信息)
/// @detail 支持以下类型传入
/// - std::string / const char* 相当于传入PlainText(str)
/// - SingleMessage的各种派生类
/// - MessageChain
/// @deprecated use Contact.quoteAndSend or `this->quoteAndSend1(s, groupid, env)`, since v2.8.1
template < class T >
ShouldNotUse ( " use Contact.quoteAndSend " ) MessageSource
quoteAndSendMessage ( T s , QQID groupid = - 1 , void * env = nullptr ) = delete ;
public : // static functions
/// @brief 找到miraiCode结尾的`]`
/// @param s 文本
/// @param start 开始位置
/// @return 如果不存在返回-1, 存在则返回index
static size_t findEnd ( const std : : string & s , size_t start ) {
size_t pos = start ;
while ( pos < s . length ( ) ) {
switch ( s [ pos ] ) {
case ' \\ ' :
pos + = 2 ;
continue ;
case ' ] ' :
return pos ;
}
pos + + ;
}
return - 1 ;
}
/// 从miraicode string构建MessageChain
static MessageChain deserializationFromMiraiCode ( const std : : string & m ) ;
static MessageChain deserializationFromMessageSourceJson ( const std : : string & msg , bool origin = true ) {
return deserializationFromMessageSourceJson ( nlohmann : : json : : parse ( msg ) , origin ) ;
}
/// 从MessageSource json中构建MessageChain, 常用于Incoming message
/// @attention 本方法并不会自动附加MessageSource到MessageChain, 需要用.plus方法自行附加
static MessageChain deserializationFromMessageSourceJson ( const nlohmann : : json & j , bool origin = true ) ;
private : // private methods
void constructMessages ( ) { }
template < class T1 , class . . . T2 >
void constructMessages ( T1 h , T2 . . . args ) {
static_assert ( std : : is_base_of_v < SingleMessage , T1 > , " 只支持SingleMessage子类 " ) ;
emplace_back ( h ) ;
constructMessages ( args . . . ) ;
}
template < class . . . T2 >
void constructMessages ( const std : : string & h , T2 . . . args ) {
emplace_back ( PlainText ( h ) ) ;
constructMessages ( args . . . ) ;
}
template < class . . . T2 >
void constructMessages ( const char * h , T2 . . . args ) {
emplace_back ( PlainText ( h ) ) ;
constructMessages ( args . . . ) ;
}
template < class . . . T >
void constructMessages ( const MessageChain & mc , T . . . args ) {
insert ( end ( ) , mc . begin ( ) , mc . end ( ) ) ;
constructMessages ( args . . . ) ;
}
MessageSource quoteAndSend0 ( std : : string msg , QQID groupid = - 1 ) ;
template < class T >
MessageSource quoteAndSend1 ( T s , QQID groupid = - 1 ) {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只支持SingleMessage的派生类 " ) ;
return this - > quoteAndSend0 ( s . toMiraiCode ( ) , groupid ) ;
}
MessageSource quoteAndSend1 ( std : : string s , QQID groupid ) {
return this - > quoteAndSend0 ( std : : move ( s ) , groupid ) ;
}
MessageSource quoteAndSend1 ( const MessageChain & mc , QQID groupid ) {
return this - > quoteAndSend0 ( mc . toMiraiCode ( ) , groupid ) ;
}
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_MESSAGECHAIN_H
# include <json.hpp>
# include <string>
namespace MiraiCP {
enum contactType {
MIRAI_CONTACT = 0 ,
MIRAI_FRIEND = 1 ,
MIRAI_GROUP = 2 ,
MIRAI_MEMBER = 3 ,
MIRAI_OTHERTYPE = 4 ,
} ;
/*!
* @ brief group , friend , member的父类
* @ doxygenEg { 1002 , message . cpp , 发 送 以 及 回 复 群 消 息 }
*/
class Contact {
protected : // attrs
contactType _type ;
QQID _id ;
QQID _groupid ;
std : : string _nickOrNameCard ;
std : : string _avatarUrl ;
QQID _botid ;
bool _anonymous = false ;
protected :
/// 发送语音
MessageSource sendVoice0 ( const std : : string & path ) ;
public :
// constructors
/*!
* @ brief 无 参 初 始 化 Contact类型
* @ internal 一 般 在 MiraiCp内部构造
*/
Contact ( ) {
this - > _type = MIRAI_CONTACT ;
this - > _id = 0 ;
this - > _groupid = 0 ;
this - > _nickOrNameCard = " " ;
this - > _botid = 0 ;
}
/*!
* @ brief 构 造 contact类型
* @ param type 类 型
* @ see Contact : : type ( )
* @ param id ID
* @ see Contact : : id ( )
* @ param gid 是 member的时候是群id , 否 则 为 0
* @ see Contact : : groupid
* @ param name 群 名 片 或 昵 称 或 群 名
* @ see Contact : : name ( )
* @ param botid 对 应 的 botid
*/
explicit Contact ( int type , QQID id , QQID gid , const std : : string & name , QQID botid , bool anonymous = false ) {
if ( type < 0 | | type > 4 ) throw APIException ( " Contact::type incorrect " , MIRAICP_EXCEPTION_WHERE ) ;
this - > _type = static_cast < contactType > ( type ) ;
this - > _id = id ;
this - > _groupid = gid ;
this - > _nickOrNameCard = name ;
this - > _botid = botid ;
this - > _anonymous = anonymous ;
} ;
// Contact(Contact &&c) : _type(c._type), _id(c._id), _groupid(c._groupid), _botid(c._botid), _anonymous(c._anonymous), _nickOrNameCard(std::move(c._nickOrNameCard)), _avatarUrl(std::move(c._avatarUrl)) {
// }
// destructor
virtual ~ Contact ( ) = default ;
bool operator = = ( const Contact & c ) const {
return this - > id ( ) = = c . id ( ) ;
}
/// @brief 当前对象类型
/// @see contactType
/// - 1 Friend 好友
/// - 2 Group 群聊
/// - 3 Member 群成员
contactType type ( ) const { return this - > _type ; }
/// @brief id在全部情况存在
/// - 当当前type为1(Friend)时, 为好友id
/// - 当当前type为2(Group)时, 为群id
/// - 当当前type为3(Member)时, 为群成员id
QQID id ( ) const { return this - > _id ; }
/// @brief 当type为3的时候存在, 否则为0, 可以看作补充id
/// - 当当前type为1(Friend)时, 为0
/// - 当当前type为2(Group)时, 为0
/// - 当当前type为3(Member)时,为群号
/// @attention 当当前type为2(Group)时, 为0, 不为群号, id才是群号
QQID groupid ( ) const { return this - > _groupid ; }
/// 群名称,群成员群名片,或好友昵称
std : : string nickOrNameCard ( ) const { return this - > _nickOrNameCard ; } ;
/// 头像url地址
std : : string avatarUrl ( ) const { return this - > _avatarUrl ; } ;
/// 所属bot
QQID botid ( ) const { return this - > _botid ; } ;
public : // serialization
/// 序列化到json对象
nlohmann : : json toJson ( ) const {
nlohmann : : json j ;
j [ " type " ] = type ( ) ;
j [ " id " ] = id ( ) ;
j [ " groupid " ] = groupid ( ) ;
j [ " nickornamecard " ] = nickOrNameCard ( ) ;
j [ " botid " ] = botid ( ) ;
return j ;
}
/// @deprecated since v2.8.1, use `this->toJson()`
ShouldNotUse ( " use toJson " ) nlohmann : : json serialization ( ) const = delete ;
/// 序列化成文本, 可以通过deserializationFromString反序列化, 利于保存
/// @see Contact::fromString()
std : : string toString ( ) const {
return this - > toJson ( ) . dump ( ) ;
}
/// @deprecated since v2.8.1, use `this->toString()`
ShouldNotUse ( " use toString " ) std : : string serializationToString ( ) const = delete ;
/// 反序列化成bot, 可以通过serializationToString序列化, 利于保存
/// @see Contact::serializationToString()
/// @param source 序列化后的文本
/// @throw APIException
static Contact deserialize ( const std : : string & source ) ;
static Contact deserialize ( nlohmann : : json source ) ;
public :
/// @deprecated since v2.8.1, use `Contact::deserialize(source)`
ShouldNotUse ( " use deserialize " ) static Contact deserializationFromString ( const std : : string & source ) = delete ;
/// @deprecated since v2.8.1, use `sendMessage(MiraiCode)` or `sendMsg0(msg.toMiraiCode(), retryTime, true, env)`
ShouldNotUse ( " Use sendMessage " ) MessageSource sendMiraiCode ( const MiraiCode & msg , int retryTime = 3 , void * env = nullptr ) const = delete ;
/*!
* @ brief 回 复 并 发 送
* @ param s 内 容
* @ detail 支 持 以 下 类 型 传 入
* - std : : string / const char * 相 当 于 传 入 PlainText ( str )
* - SingleMessage的各种派生类
* - MessageChain
* @ param ms 回 复 的 信 息 的 MessageSource
* @ note 可 以 改 MessageSource里的内容 , 客 户 端 在 发 送 的 时 候 并 不 会 校 验 MessageSource的内容正确性 ( 比 如 改 originalMessage来改引用的文本的内容 , 或 者 改 id来定位到其他信息 )
*/
template < class T >
MessageSource quoteAndSendMessage ( T s , MessageSource ms ) {
return this - > quoteAndSend1 ( s , ms ) ;
}
/*!
* @ brief 回 复 并 发 送
* @ param s 内 容
* @ param groupid 如 果 是 来 源 于 TempGroupMessage就要提供 ( 因 为 要 找 到 那 个 Member )
* @ note 可 以 改 MessageSource里的内容 , 客 户 端 在 发 送 的 时 候 并 不 会 校 验 MessageSource的内容正确性 ( 比 如 改 originalMessage来改引用的文本的内容 , 或 者 改 id来定位到其他信息 )
* @ detail 支 持 以 下 类 型 传 入
* - std : : string / const char * 相 当 于 传 入 PlainText ( str )
* - SingleMessage的各种派生类
* - MessageChain
*/
template < class . . . T >
MessageSource quoteAndSendMessage ( MessageSource ms , T . . . val ) {
return this - > quoteAndSendMessage ( MessageChain ( val . . . ) , std : : move ( ms ) ) ;
}
/*!
* @ brief 发 送 信 息
* @ tparam T 类 型
* 支 持 :
* - SingleMessage的派生类
* - MessageChain
* - std : : string / const char * 相 当 于 发 送 PlainText ( )
* @ param msg 内 容
* @ return MessageSource
*/
template < class . . . T >
MessageSource sendMessage ( T . . . msg ) {
return this - > sendMessage ( MessageChain ( msg . . . ) ) ;
}
/// @brief 发送一条Message
/// @detail 支持
/// - std::string: 相当于发送PlainText(str)
/// - MiraiCode 相当于发送反序列化MiraiCode后的
/// - 各种SingleMessage的派生类
/// - MessageChain
/// @param msg Message
/// @param retryTime 重试次数
/// @return MessageSource
template < class T >
MessageSource sendMessage ( T msg , int retryTime = 3 ) {
return this - > send1 ( msg , retryTime ) ;
}
/// @deprecated since v2.8.1, use `sendMessage(msg)` or `sendMsg0(msg, retryTime, false, env)`
ShouldNotUse ( " Use sendMessage " ) MessageSource sendMsg ( const std : : string & msg , int retryTime = 3 , void * env = nullptr ) = delete ;
/// @deprecated since v2.8.1, use `sendMessage(MiraiCode)` or `sendMsg0(msg.toMiraiCode(), retryTime, false, env);`
ShouldNotUse ( " Use sendMessage " ) MessageSource sendMsg ( const MiraiCode & msg , int retryTime = 3 , void * env = nullptr ) = delete ;
/// @deprecated since v2.8.1, use `sendMessage(Tools::VectorToString(std::move(msg)))` or `sendMsg0(Tools::VectorToString(std::move(msg)), retryTime, false, env);`
ShouldNotUse ( " Use sendMessage " ) MessageSource sendMsg ( std : : vector < std : : string > msg , int retryTime = 3 , void * env = nullptr ) = delete ;
/*!
* @ brief 上 传 本 地 图 片 , 务 必 要 用 绝 对 路 径
* 由 于 mirai要区分图片发送对象 , 所 以 使 用 本 函 数 上 传 的 图 片 只 能 发 到 群
* @ attention 最 大 支 持 图 片 大 小 为 30 MB
* @ throws
* - 可 能 抛 出 UploadException异常代表路径无效或大小大于30MB
* - 可 能 抛 出 MemberException找不到群或群成员
*/
Image uploadImg ( const std : : string & path ) const ;
FlashImage uploadFlashImg ( const std : : string & path ) const ;
template < class T >
T to ( ) {
static_assert ( std : : is_base_of_v < Contact , T > ) ;
return T ( * this ) ;
}
private : // private methods
/// 发送纯文本信息
/// @throw IllegalArgumentException, TimeOutException, BotIsBeingMutedException
MessageSource sendMsg0 ( const std : : string & msg , int retryTime , bool miraicode = false ) const ;
template < class T >
MessageSource send1 ( T msg , int retryTime ) {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只支持SingleMessage的派生类 " ) ;
return sendMsg0 ( msg . toMiraiCode ( ) , retryTime , true ) ;
}
MessageSource send1 ( MessageChain msg , int retryTime ) {
return sendMsg0 ( msg . toMiraiCode ( ) , retryTime , true ) ;
}
MessageSource send1 ( MiraiCode msg , int retryTime ) {
return sendMsg0 ( msg . toMiraiCode ( ) , retryTime , true ) ;
}
MessageSource send1 ( std : : string msg , int retryTime ) {
return sendMsg0 ( msg , retryTime , false ) ;
}
MessageSource send1 ( const char * msg , int retryTime ) {
return sendMsg0 ( std : : string ( msg ) , retryTime , false ) ;
}
MessageSource quoteAndSend0 ( const std : : string & msg , MessageSource ms ) ;
template < class T >
MessageSource quoteAndSend1 ( T s , MessageSource ms ) {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只支持SingleMessage的派生类 " ) ;
return this - > quoteAndSend0 ( s . toMiraiCode ( ) , ms ) ;
}
MessageSource quoteAndSend1 ( std : : string s , MessageSource ms ) {
return this - > quoteAndSend0 ( s , ms ) ;
}
MessageSource quoteAndSend1 ( MessageChain mc , MessageSource ms ) {
return this - > quoteAndSend0 ( mc . toMiraiCode ( ) , ms ) ;
}
} ;
class INudgeSupport {
public :
/*!
* @ brief 发 送 戳 一 戳
* @ warning 仅 限 Friend , Member类调用
* @ see MiraiCP : : Friend : : sendNudge , MiraiCP : : Member : : sendNudge
* @ throw MiraiCP : : BotException , MiraiCP : : IllegalStateException
*/
virtual void sendNudge ( ) = 0 ;
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_CONTACT_H
# ifndef MIRAICP_PRO_EVENT_H
# define MIRAICP_PRO_EVENT_H
// #include "Bot.h"
// #include "Friend.h"
# ifndef MIRAICP_PRO_FRIEND_H
# define MIRAICP_PRO_FRIEND_H
// #include "Contact.h"
namespace MiraiCP {
/// 好友类声明
class Friend : public Contact , INudgeSupport {
public :
/// 删除好友(delete是C++关键字)
void deleteFriend ( ) ;
void refreshInfo ( ) ;
/*!
* @ brief 发 送 戳 一 戳
* @ warning 发 送 戳 一 戳 的 前 提 是 登 录 该 bot的协议是android_phone / ipad , 否 则 抛 出 IllegalStateException
* @ throw MiraiCP : : BotException , MiraiCP : : IllegalStateException
*/
void sendNudge ( ) override ;
/*!
* @ brief 构 建 好 友 对 象
* @ param friendid q号
* @ param botid 对 应 机 器 人 id
*/
explicit Friend ( QQID friendid , QQID botid ) ;
explicit Friend ( const Contact & c ) : Contact ( c ) {
if ( c . type ( ) ! = 1 )
throw IllegalArgumentException ( " 无法从 type== " + std : : to_string ( c . type ( ) ) + " 转为 type == 1(friend) " , MIRAICP_EXCEPTION_WHERE ) ;
refreshInfo ( ) ;
} ;
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_FRIEND_H
// #include "Group.h"
# ifndef MIRAICP_PRO_GROUP_H
# define MIRAICP_PRO_GROUP_H
// #include "Contact.h"
# include "json.hpp"
namespace MiraiCP {
class Member ; // forward declaration
/*!
* @ detail 群 聊 类 声 明
*/
class Group : public Contact {
public : // member classes and structs
/// 群公告参数
class AnnouncementParams {
public :
/// 发送给新成员
bool send2new ;
/// 需要确认
bool requireConfirm ;
/// 置顶
bool pinned ;
/// 引导群成员修改群名片
bool showEditCard ;
/// 显示弹窗
bool showPopup ;
/// 序列化到文本
nlohmann : : json serializeToJson ( ) ;
explicit AnnouncementParams ( bool send2New = false , bool requireConfirm = false , bool pinned = false ,
bool showEditCard = false , bool showPopup = false ) : send2new ( send2New ) ,
requireConfirm (
requireConfirm ) ,
pinned ( pinned ) ,
showEditCard ( showEditCard ) ,
showPopup ( showPopup ) { }
} ;
/// 在线群公告
class OnlineAnnouncement {
public :
/// 内容
std : : string content ;
/// 所属bot
QQID botid ;
/// 公告属性
AnnouncementParams params ;
/// 所在群id
QQID groupid ;
/// 发送者id
QQID senderid ;
/// 发送时间戳
long long publicationTime ;
/// 唯一识别属性
std : : string fid ;
/// 如果需要确认,即为确认的人数
int confirmNum ;
/// 图片id, 如果不存在即为空
std : : string imageid ;
/// 删除当前群公告
/// @throw BotException
void deleteThis ( ) ;
/// 反序列化
static OnlineAnnouncement deserializeFromJson ( const nlohmann : : json & ) ;
OnlineAnnouncement ( const std : : string & content , AnnouncementParams & params ,
QQID groupid , QQID senderid , QQID botid ,
long long int publicationTime , const std : : string & fid , int confirmNum ,
const std : : string & imageid ) : content ( content ) , params ( params ) , groupid ( groupid ) ,
senderid ( senderid ) , botid ( botid ) ,
publicationTime ( publicationTime ) ,
fid ( fid ) , confirmNum ( confirmNum ) , imageid ( imageid ) { }
} ;
/// 本地(未发送)群公告
class OfflineAnnouncement {
public :
/// 内容
std : : string content ;
/// 公告属性
AnnouncementParams params ;
/// 发布群公告
Group : : OnlineAnnouncement publishTo ( const Group & ) ;
OfflineAnnouncement ( const std : : string & content , AnnouncementParams params ) : content ( content ) ,
params ( params ) { }
} ;
/**
* @ brief 群 设 置
* @ details 使 用 uploadSetting上传设置 , 使 用 refreshInfo同步服务器设定 , 后 面 两 项 由 于 https : //github.com/mamoe/mirai/issues/1307 还不能改
*/
struct GroupSetting {
/// 群名称
std : : string name ;
/// 禁言全部
bool isMuteAll { } ;
/// 允许群成员邀请
bool isAllowMemberInvite { } ;
/// 自动同意进群
bool isAutoApproveEnabled { } ;
/// 允许匿名聊天
bool isAnonymousChatEnabled { } ;
} ;
/// 群文件的简短描述
struct file_short_info {
// 路径带文件名
std : : string path ;
// 唯一id
std : : string id ;
} ;
public : // attrs
/// 群设置
GroupSetting setting ;
public : // constructors
/// @brief 构建以群号构建群对象
/// @param groupid 群号
/// @param botid 机器人id
/// @doxygenEg{1007, group.cpp, 从群号构建群对象}
Group ( QQID groupid , QQID botid ) ;
explicit Group ( const Contact & c ) : Contact ( c ) {
if ( c . type ( ) ! = 2 )
throw IllegalArgumentException ( " 无法从 type== " + std : : to_string ( c . type ( ) ) + " 转为 type == 2(group) " , MIRAICP_EXCEPTION_WHERE ) ;
refreshInfo ( ) ;
}
public : // methods
/**
* @ brief 更 新 群 设 置 , 即 覆 盖 服 务 器 上 的 群 设 置
* @ details 从 服 务 器 拉 去 群 设 置 用 refreshInfo
* @ see Group : : refreshInfo ( )
*/
void updateSetting ( ) ;
/// 取群成员列表
/// @return vector<long>
std : : vector < unsigned long long > getMemberList ( ) ;
/*!
* 以 string格式取群成员列表
* @ note 格 式 :
* 每 个 群 成 员 id间用逗号分隔
*/
std : : string MemberListToString ( ) ;
/// 取群主
Member getOwner ( ) ;
/// 取群成员
Member getMember ( QQID memberid ) ;
Member operator [ ] ( QQID id ) ;
/// 取群公告列表
std : : vector < OnlineAnnouncement > getAnnouncementsList ( ) ;
/// 刷新群聊信息
void refreshInfo ( ) ;
void quit ( ) ;
/*!
@ brief 上 传 并 发 送 远 程 ( 群 ) 文 件
@ param path - 群 文 件 路 径 ( 带 文 件 名 ) , 根 目 录 为 /
@ param filepath - 本 地 文 件 路 径
@ attention 路 径 分 隔 符 是 ` / `
@ doxygenEg { 1008 , group . cpp , 发 送 群 文 件 }
*/
RemoteFile sendFile ( const std : : string & path , const std : : string & filepath ) ;
/// 发送语音
MessageSource sendVoice ( const std : : string & path ) {
return Contact : : sendVoice0 ( path ) ;
}
/*!
取 群 文 件 信 息 , 会 自 动 搜 索 子 目 录
@ param path - 群 文 件 路 径 ( 不 带 文 件 名 )
@ param id - 文 件 id , 可 空 , 空 则 为 用 路 径 查 找 ( 此 时 路 径 要 带 文 件 名 )
@ attention 因 为 群 文 件 允 许 重 名 文 件 存 在 的 特 性 , 如 果 没 有 id该查找并不可靠 , 只 能 返 回 重 名 文 件 中 的 其 中 一 个 文 件
@ see RemoteFile
@ doxygenEg { 1009 , group . cpp , 获 取 群 文 件 }
*/
RemoteFile getFile ( const std : : string & path , const std : : string & id = " " ) ;
/*!
* @ brief 取 文 件 信 息 ( 根 据 id )
* @ param id 文 件 id
* @ return 文 件
* @ detail 相 当 于 从 根 目 录 开 始 遍 历 查 找 文 件 , 相 当 于 getFile ( " / " , id ) ;
*/
RemoteFile getFileById ( const std : : string & id ) ;
RemoteFile getFileByFile ( const RemoteFile & file ) {
return getFileById ( file . id ) ;
}
/*!
* 获 取 path路径下全部文件信息
* @ param path - 远 程 路 径
* @ return 返 回 值 为 一 个 vector容器 , 每 一 项 为 short_info
* @ doxygenEg { 1010 , group . cpp , 获 取 群 文 件 列 表 }
*/
std : : vector < file_short_info > getFileList ( const std : : string & path ) ;
/// 取文件列表以字符串形式返回
/// @param path 文件夹路径
std : : string getFileListString ( const std : : string & path ) ;
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_GROUP_H
// #include "Logger.h"
// #include "Member.h"
# ifndef MIRAICP_PRO_MEMBER_H
# define MIRAICP_PRO_MEMBER_H
// #include "Contact.h"
namespace MiraiCP {
/*!
* @ brief 群 成 员 类 声 明
* @ doxygenEg { 1013 , member . cpp , 群 成 员 操 作 }
*/
class Member : public Contact , INudgeSupport {
public :
/// @brief 权限等级
/// - OWNER群主 为 2
/// - ADMINISTRATOR管理员 为 1
/// - MEMBER群成员 为 0
/// @note 上面那些变量在constants.h中有定义
unsigned int permission = 0 ;
/// @brief 更改群成员权限
/// @param admin 如果为true为更改到管理员
/// @param env
void modifyAdmin ( bool admin ) ;
/// @brief 构建群成员对象
/// @param qqid 该成员q号
/// @param groupid 所在群号
/// @param botid 机器人id
explicit Member ( QQID qqid , QQID groupid , QQID botid ) ;
explicit Member ( const Contact & c ) : Contact ( c ) {
if ( c . type ( ) ! = 3 )
throw IllegalArgumentException ( " 无法从 type== " + std : : to_string ( c . type ( ) ) + " 转为 type == 3(member) " , MIRAICP_EXCEPTION_WHERE ) ;
this - > isAnonymous = this - > _anonymous ;
refreshInfo ( ) ;
} ;
/// 是否是匿名群成员, 如果是匿名群成员一些功能会受限
bool isAnonymous = false ;
/// 重新获取(刷新)群成员信息
void refreshInfo ( ) ;
/// 发送语音
MessageSource sendVoice ( const std : : string & path ) {
return Contact : : sendVoice0 ( path ) ;
}
/// 获取权限, 会在构造时调用, 请使用permission缓存变量
/// @see Member::permission
unsigned int getPermission ( ) const ;
/*!
* 禁 言 当 前 对 象 , 单 位 是 秒 , 最 少 0 秒 最 大 30 天 , 如 果 为 0 或 者 为 负 则 unmute
* @ throws BotException , MuteException
*/
void mute ( int time ) ;
/// 取消禁言
/// @throws BotException, MuteException
void unMute ( ) {
mute ( 0 ) ;
}
/*! 踢出这个群成员
* @ param reason - 原 因
*/
void kick ( const std : : string & reason ) ;
/// At一个群成员
At at ( ) {
return At ( this - > id ( ) ) ;
}
/// 更改群名片
/// @throw MiraiCP::BotException 如果没权限时
void changeNameCard ( std : : string_view newName ) ;
/*!
* @ brief 发 送 戳 一 戳
* @ warning 发 送 戳 一 戳 的 前 提 是 登 录 该 bot的协议是android_phone / ipad , 否 则 抛 出 IllegalStateException
* @ throw MiraiCP : : BotException , MiraiCP : : IllegalStateException
*/
void sendNudge ( ) override ;
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_MEMBER_H
namespace MiraiCP {
/// Event 工厂
namespace eventTypes {
enum Types {
BaseEvent [[maybe_unused]] , // 0
GroupMessageEvent , // 1
PrivateMessageEvent , // 2
GroupInviteEvent , // 3
NewFriendRequestEvent , // 4
MemberJoinEvent , // 5
MemberLeaveEvent , // 6
RecallEvent , // 7
BotJoinGroupEvent , // 8
GroupTempMessageEvent , // 9
TimeOutEvent , // 10
BotOnlineEvent , // 11
NudgeEvent , // 12
BotLeaveEvent , // 13
MemberJoinRequestEvent , // 14
MessagePreSendEvent , // 15
MiraiCPExceptionEvent , // 16
Command , // 17
count , // 事件在此位置前定义, 此时count为事件种类数
error // 出现问题时使用此enum
} ;
}
/// Event抽象父类
class MiraiCPEvent {
public :
MiraiCPEvent ( ) = default ;
virtual ~ MiraiCPEvent ( ) = default ;
public :
static eventTypes : : Types get_event_type ( ) { return eventTypes : : Types : : error ; }
virtual eventTypes : : Types getEventType ( ) const = 0 ;
} ;
/// 所有事件处理timeoutevent都是机器人事件, 指都有机器人实例
template < class T >
class BotEvent : public MiraiCPEvent {
public :
eventTypes : : Types getEventType ( ) const override { return T : : get_event_type ( ) ; }
// TODO: 考虑设置一个Bot全局变量, 此处存储一个Bot指针, 减少无用构造.
/// 该事件接受的机器人
Bot bot ;
/// 以该机器人的名义发送日志
/// @see BotLogger
IdLogger botlogger ;
explicit BotEvent ( QQID botid ) : bot ( botid ) , botlogger ( botid , & Logger : : logger ) { }
} ;
/// MessageEvent类型的抽象接口, 用于Message类型多态实现
class MessageEvent {
public :
/// 获取当前聊天,可能是群,私聊,或群临时回话
virtual Contact * chat ( ) = 0 ;
/// 获取当前聊天,可能是群,私聊,或群临时回话
virtual Contact * from ( ) = 0 ;
virtual MessageChain * getMessageChain ( ) = 0 ;
virtual const Contact * chat ( ) const = 0 ;
virtual const Contact * from ( ) const = 0 ;
virtual const MessageChain * getMessageChain ( ) const = 0 ;
} ;
/*!
* @ brief 群 消 息 事 件 声 明
* @ doxygenEg { 1003 , group . cpp , 取 群 聊 下 一 条 消 息 }
*/
class GroupMessageEvent : public BotEvent < GroupMessageEvent > , public MessageEvent {
public :
static eventTypes : : Types get_event_type ( ) {
return eventTypes : : Types : : GroupMessageEvent ;
}
public :
///来源群
Group group ;
///发送人
Member sender ;
/// 信息
MessageChain message ;
GroupMessageEvent ( QQID botid , const Group & group , const Member & sender ,
MessageChain mc ) : BotEvent ( botid ) , group ( group ) ,
sender ( sender ) , message ( std : : move ( mc ) ) { } ;
/*!
* @ brief 取 群 聊 下 一 个 消 息 ( 群 聊 与 本 事 件 一 样 )
* @ param time 超 时 时 间 限 制 , 单 位 为 ms , 超 时 后 抛 出 TimeOutException
* @ param halt 是 否 拦 截 该 事 件 ( 不 让 这 个 消 息 被 注 册 的 其 他 监 听 器 收 到 处 理 )
* @ return 消 息 链
*/
MessageChain nextMessage ( long time = - 1 , bool halt = true ) const ;
/*!
* @ brief 取 群 聊 中 同 群 成 员 的 下 一 个 消 息 ( 发 送 人 和 群 与 本 事 件 一 样 )
* @ param time 超 时 时 间 限 制 , 单 位 为 ms , 超 时 后 抛 出 TimeOutException
* @ param halt 是 否 拦 截 该 事 件 ( 不 让 消 息 被 注 册 的 其 他 监 听 器 收 到 处 理 )
* @ return 消 息 链
*/
MessageChain senderNextMessage ( long time = - 1 , bool halt = true ) const ;
public :
Contact * chat ( ) override {
return & group ;
}
const Contact * chat ( ) const override {
return & group ;
}
Contact * from ( ) override {
return & sender ;
}
const Contact * from ( ) const override {
return & sender ;
}
MessageChain * getMessageChain ( ) override {
return & message ;
}
const MessageChain * getMessageChain ( ) const override {
return & message ;
}
} ;
/*!
* @ detail 私 聊 消 息 事 件 类 声 明
* @ doxygenEg { 1004 , group . cpp , 取 好 友 下 一 条 信 息 }
*/
class PrivateMessageEvent : public BotEvent < PrivateMessageEvent > , public MessageEvent {
public :
static eventTypes : : Types get_event_type ( ) {
return eventTypes : : Types : : PrivateMessageEvent ;
}
public :
/// 发起人
Friend sender ;
/// 信息
MessageChain message { } ;
/*!
* @ brief 构 建 私 聊 信 息
* @ param botid 对 应 botid
* @ param sender 发 送 者
* @ param message 消 息
* @ param messageSource 消 息 源
*/
PrivateMessageEvent ( QQID botid , Friend sender , MessageChain mc ) : BotEvent ( botid ) , sender ( std : : move ( sender ) ) ,
message ( std : : move ( mc ) ) { } ;
/*!
* @ brief 取 下 一 个 消 息 ( 发 送 人 和 接 收 人 和 本 事 件 一 样 )
* @ warning 如 果 两 次 发 送 信 息 间 隔 过 短 可 能 会 漏 过 信 息
* @ param time 超 时 时 间 限 制 , 单 位 为 ms , 超 时 后 抛 出 TimeOutException
* @ param halt 是 否 拦 截 该 事 件 ( 不 被 注 册 的 监 听 器 收 到 处 理 )
* @ return 消 息 链
*/
MessageChain nextMessage ( long time = - 1 , bool halt = true ) const ;
public :
Contact * chat ( ) override {
return & sender ;
}
const Contact * chat ( ) const override {
return & sender ;
}
Contact * from ( ) override {
return & sender ;
}
const Contact * from ( ) const override {
return & sender ;
}
MessageChain * getMessageChain ( ) override {
return & message ;
}
const MessageChain * getMessageChain ( ) const override {
return & message ;
}
} ;
/// 群聊邀请事件类声明
class GroupInviteEvent : public BotEvent < GroupInviteEvent > {
public :
static eventTypes : : Types get_event_type ( ) {
return eventTypes : : Types : : GroupInviteEvent ;
}
public :
/// 事件序列化文本
std : : string source ;
/// 发起人昵称
std : : string inviterNick ;
/// 发起人id
QQID inviterid = 0 ;
/// 被邀请进的组
std : : string groupName ;
/// 群号
QQID groupid = 0 ;
static void operation0 ( const std : : string & source , QQID botid , bool accept ) ;
void reject ( ) {
GroupInviteEvent : : operation0 ( this - > source , this - > bot . id , false ) ;
}
void accept ( ) {
GroupInviteEvent : : operation0 ( this - > source , this - > bot . id , true ) ;
}
/*!
* @ brief 群 邀 请 事 件
* @ param botid 当 前 botid
* @ param source 序 列 化 后 字 符 串
* @ param inviterNick 邀 请 人 昵 称
* @ param inviterid 邀 请 人 id
* @ param groupName 群 聊 名 称
* @ param groupid 群 号
*/
GroupInviteEvent ( QQID botid , const std : : string & source , const std : : string & inviterNick ,
QQID inviterid , const std : : string & groupName , QQID groupid )
: BotEvent ( botid ) , source ( source ) , inviterNick ( inviterNick ) , inviterid ( inviterid ) , groupName ( groupName ) ,
groupid ( groupid ) { }
} ;
/// 好友申请事件声明
class NewFriendRequestEvent : public BotEvent < NewFriendRequestEvent > {
public :
static eventTypes : : Types get_event_type ( ) {
return eventTypes : : Types : : NewFriendRequestEvent ;
}
public :
/// @brief 序列化的事件信息
std : : string source ;
/// @brief 对方id
QQID fromid ;
QQID fromgroupid ;
/// @brief 对方昵称
std : : string nick ;
/// @brief 申请理由
std : : string message ;
/// @brief 接受好友申请
/// @param source 事件序列化信息
static void operation0 ( const std : : string & source , QQID botid , bool accept , bool ban = false ) ;
/// @brief 拒绝好友申请
/// @param ban - 是否加入黑名单
void reject ( bool ban = false ) {
NewFriendRequestEvent : : operation0 ( this - > source , this - > bot . id , false , ban ) ;
}
/// @brief 接受申请
void accept ( ) {
NewFriendRequestEvent : : operation0 ( this - > source , this - > bot . id , true ) ;
}
/*!
* @ brief 好 友 申 请 事 件
* @ param botid 对 应 botid
* @ param source 序 列 化 后 信 息
* @ param fromid 对 方 id
* @ param fromgroupid 从 哪 个 群 申 请 的 , 否 则 为 0
* @ param nick 对 方 昵 称
* @ param message 申 请 理 由
*/
NewFriendRequestEvent ( QQID botid , const std : : string & source ,
QQID fromid ,
QQID fromgroupid , const std : : string & nick ,
const std : : string & message )
: BotEvent ( botid ) , source ( source ) , fromid ( fromid ) , fromgroupid ( fromgroupid ) , nick ( nick ) ,
message ( message ) { }
} ;
/// 新群成员加入
class MemberJoinEvent : public BotEvent < MemberJoinEvent > {
public :
static eventTypes : : Types get_event_type ( ) {
return eventTypes : : Types : : MemberJoinEvent ;
}
public :
enum joinType {
error = 0 ,
invited = 1 ,
applied = 2 ,
rehab = 3
} ;
/*!
* @ brief 事 件 类 型
* 1 - 被 邀 请 进 来
* 2 - 主 动 加 入
* 3 - 原 群 主 通 过 https : //huifu.qq.com/ 恢复原来群主身份并入群
*/
joinType type = joinType : : error ;
///新进入的成员
Member member ;
///目标群
Group group ;
///邀请人, 当type = 1时存在, 否则则和member变量相同
QQID inviterid ;
/*!
* @ brief 新 群 成 员 入 群 事 件
* @ param botid botid
* @ param type 类 别 @ see MemberJoinEvent : : type
* @ param member 入 群 群 成 员
* @ param group 群 组
* @ param inviterid 邀 请 群 成 员 id , 如 果 不 存 在 和 member id参数一致
*/
MemberJoinEvent ( QQID botid , int type , const Member & member , const Group & group ,
QQID inviterid ) : BotEvent ( botid ) , type ( joinType ( type ) ) , member ( member ) ,
group ( group ) ,
inviterid ( inviterid ) { }
} ;
/// 群成员离开
class MemberLeaveEvent : public BotEvent < MemberLeaveEvent > {
public :
static eventTypes : : Types get_event_type ( ) {
return eventTypes : : Types : : MemberLeaveEvent ;
}
public :
/*!
* @ brief 事 件 类 型
* 1 - 被 踢 出
* 2 - 主 动 退 出
*/
int type = 0 ;
/// 退出的成员q号
QQID memberid ;
/// 目标群
Group group ;
/// 操作人, 主动退出时与member相同, 该成员可能是当前bot, 名称为operater以与系统operator区分
QQID operaterid ;
/*!
* @ brief 群 成 员 离 开
* @ param botid
* @ param type
* @ param memberid 退 出 的 群 成 员
* @ param group 群
* @ param operaterid 操 作 人 id , 主 动 退 出 时 与 member相同 , 该 成 员 可 能 是 当 前 bot , 名 称 为 operater以与系统operator区分
*/
MemberLeaveEvent ( QQID botid , int type , QQID memberid ,
Group group ,
QQID operaterid ) : BotEvent ( botid ) , type ( type ) , memberid ( memberid ) ,
group ( std : : move ( group ) ) ,
operaterid ( operaterid ) { }
} ;
/// 撤回信息
class RecallEvent : public BotEvent < RecallEvent > {
public :
static eventTypes : : Types get_event_type ( ) {
return eventTypes : : Types : : RecallEvent ;
}
public :
/// 为1时是好友私聊中撤回, 为2时为群聊内撤回
int type = 0 ;
/// 时间戳
int time = 0 ;
/// 原发送者
QQID authorid = 0 ;
/// 撤回者
QQID operatorid = 0 ;
/// 信息id
std : : string ids ;
//内部ids
std : : string internalids ;
//当type是2的时候存在, 否则为0
QQID groupid = 0 ;
/*!
* @ brief 撤 回 事 件
* @ param botid 对 应 bot
* @ param type 类 型
* @ param time 时 间
* @ param authorid 发 送 者 id
* @ param operatorid 撤 回 者 id
* @ param ids 消 息 源 ids
* @ param internalids 消 息 源 internalids
* @ param groupid
*/
RecallEvent ( QQID botid , int type , int time , QQID authorid ,
QQID operatorid , std : : string ids , std : : string internalids ,
QQID groupid ) : BotEvent ( botid ) , type ( type ) , time ( time ) , authorid ( authorid ) ,
operatorid ( operatorid ) , ids ( std : : move ( ids ) ) ,
internalids ( std : : move ( internalids ) ) ,
groupid ( groupid ) { }
} ;
/// 机器人进入某群
class BotJoinGroupEvent : public BotEvent < BotJoinGroupEvent > {
public :
static eventTypes : : Types get_event_type ( ) {
return eventTypes : : Types : : BotJoinGroupEvent ;
}
public :
/// 1-主动加入,2-被邀请加入,3-提供恢复群主身份加入
int type ;
/// 进入的群
Group group ;
/// 当type=2时存在, 为邀请人, 否则为空, 调用可能会报错
QQID inviterid ;
/*!
* @ brief bot加入群
* @ param botid 对 应 bot
* @ param type 类 别
* @ param group 加 入 的 群
* @ param inviter 邀 请 人
*/
BotJoinGroupEvent ( QQID botid , int type , Group group ,
QQID inviter )
: BotEvent ( botid ) , type ( type ) , group ( std : : move ( group ) ) , inviterid ( inviter ) { }
} ;
/// 群临时会话
class GroupTempMessageEvent : public BotEvent < GroupTempMessageEvent > , public MessageEvent {
public :
static eventTypes : : Types get_event_type ( ) {
return eventTypes : : Types : : GroupTempMessageEvent ;
}
public :
/// 来源群
Group group ;
/// 发送人
Member sender ;
/// 信息
MessageChain message ;
/*!
* @ brief 群 临 时 会 话 消 息 事 件
* @ param botid 对 应 bot
* @ param group 发 起 的 群
* @ param sender 发 送 消 息 对 象
* @ param message 消 息
* @ param messageSource 消 息 源
*/
GroupTempMessageEvent ( QQID botid , Group group , Member sender ,
MessageChain message ) : BotEvent ( botid ) ,
group ( std : : move ( group ) ) ,
sender ( std : : move ( sender ) ) ,
message ( std : : move ( message ) ) { }
public :
Contact * chat ( ) override {
return & sender ;
}
const Contact * chat ( ) const override {
return & sender ;
}
Contact * from ( ) override {
return & sender ;
}
const Contact * from ( ) const override {
return & sender ;
}
MessageChain * getMessageChain ( ) override {
return & message ;
}
const MessageChain * getMessageChain ( ) const override {
return & message ;
}
} ;
/// 定时任务结束
class TimeOutEvent : public MiraiCPEvent {
public :
/// 事件所附信息
std : : string msg ;
public :
explicit TimeOutEvent ( std : : string msg ) : msg ( std : : move ( msg ) ) { }
public :
static eventTypes : : Types get_event_type ( ) {
return eventTypes : : Types : : TimeOutEvent ;
}
eventTypes : : Types getEventType ( ) const override { return this - > get_event_type ( ) ; }
} ;
/// 机器人上线事件
class BotOnlineEvent : public BotEvent < BotOnlineEvent > {
public :
static eventTypes : : Types get_event_type ( ) {
return eventTypes : : Types : : BotOnlineEvent ;
}
public :
explicit BotOnlineEvent ( QQID botid ) : BotEvent ( botid ) { }
} ;
/*! 戳一戳事件
/* @warning nudgeEvent事件也会被bot自己发的Nudge触发, 可能会造成无限循环
*/
class NudgeEvent : public BotEvent < NudgeEvent > {
public :
static eventTypes : : Types get_event_type ( ) {
return eventTypes : : Types : : NudgeEvent ;
}
public :
///发送人
Contact from ;
/// 目标
Contact target ;
/// 发送的环境, 可能为Group / Friend
Contact subject ;
NudgeEvent ( const Contact & c , const Contact & target , const Contact & subject , QQID botid ) : BotEvent ( botid ) , from ( c ) ,
target ( target ) , subject ( subject ) { }
} ;
/// 机器人退群事件
/// 可能有3种类型, 主动退/被踢/解散
/// 目前mirai的botLeave事件还不稳定暂时不支持类型
class BotLeaveEvent : public BotEvent < BotLeaveEvent > {
public :
static eventTypes : : Types get_event_type ( ) {
return eventTypes : : Types : : BotLeaveEvent ;
}
public :
/// 退出的群
/// @attension 收到这个事件时已经退出该群, 可能取不到相关信息
QQID groupid ;
BotLeaveEvent ( QQID g , QQID botid ) : BotEvent ( botid ) , groupid ( g ) { }
} ;
/// 申请加群事件, bot需为管理员或者群主
class MemberJoinRequestEvent : public BotEvent < MemberJoinRequestEvent > {
private :
std : : string source ;
public :
/**
* @ brief 底 层 通 过 MemberJoinRequest
* @ param s 序 列 化 后 的 文 本
*/
static void operate ( std : : string_view s ,
QQID botid ,
bool sign ,
const std : : string & msg = " " ) ;
public :
static eventTypes : : Types get_event_type ( ) {
return eventTypes : : Types : : MemberJoinRequestEvent ;
}
public :
/// 申请的群, 如果不存在就表明广播这个事件的时候机器人已经退出该群
std : : optional < Group > group ;
/// 邀请人, 如果不存在表明这个邀请人退出了群或没有邀请人为主动进群
std : : optional < Member > inviter ;
/// 申请人id
QQID requesterId ;
public :
MemberJoinRequestEvent ( std : : optional < Group > g , std : : optional < Member > i , QQID botid , QQID requesterId , std : : string source )
: BotEvent ( botid ) , group ( std : : move ( g ) ) , inviter ( std : : move ( i ) ) , source ( std : : move ( source ) ) , requesterId ( requesterId ) { } ;
/// 通过
void accept ( ) {
operate ( this - > source , this - > bot . id , true ) ;
}
/// 拒绝
void reject ( const std : : string & msg ) {
operate ( this - > source , this - > bot . id , false , msg ) ;
}
} ;
/*! 每条消息发送前的事件, 总是在消息实际上被发送和广播MessagePostSendEvent前广播
* @ see MessagePostSendEvent
* @ warning 在 这 个 事 件 里 小 心 使 用 sendMessage , 可 能 会 触 发 无 限 递 归 preSend - > sendMessage - > preSend - > . . .
* */
class MessagePreSendEvent : public BotEvent < MessagePreSendEvent > {
public :
static eventTypes : : Types get_event_type ( ) {
return eventTypes : : Types : : MessagePreSendEvent ;
}
public :
/// 发送目标
Contact target ;
/// 消息
MessageChain message ;
explicit MessagePreSendEvent ( Contact c , MessageChain mc , QQID botid ) : BotEvent ( botid ) , target ( std : : move ( c ) ) , message ( std : : move ( mc ) ) { }
} ;
class MiraiCPExceptionBase ; // forward declaration
/// @brief 异常抛出事件
class MiraiCPExceptionEvent : public MiraiCPEvent {
private :
MiraiCPExceptionBase * exceptionPtr ;
public :
explicit MiraiCPExceptionEvent ( MiraiCPExceptionBase * err ) {
exceptionPtr = err ;
}
public :
static eventTypes : : Types get_event_type ( ) {
return eventTypes : : Types : : MiraiCPExceptionEvent ;
}
eventTypes : : Types getEventType ( ) const override { return this - > get_event_type ( ) ; }
const MiraiCPExceptionBase * getException ( ) const {
return exceptionPtr ;
}
} ;
/// 事件监听操控, 可用于stop停止监听和resume继续监听
class NodeHandle {
private :
bool _enable ;
public :
explicit NodeHandle ( bool a ) : _enable ( a ) { }
bool isEnable ( ) const { return _enable ; }
void stop ( ) { _enable = false ; }
void resume ( ) { _enable = true ; }
} ;
class Event {
private : // typedefs
class eventNode {
private :
/// 回调的handle, 用于管理
std : : shared_ptr < NodeHandle > _handle ;
public :
std : : function < bool ( MiraiCPEvent * ) > func ;
explicit eventNode ( std : : function < bool ( MiraiCPEvent * ) > f ) : _handle ( new NodeHandle ( true ) ) , func ( std : : move ( f ) ) { }
eventNode ( eventNode & & _o ) noexcept : _handle ( std : : move ( _o . _handle ) ) , func ( std : : move ( _o . func ) ) { }
public :
/// 返回true代表block之后的回调
bool run ( MiraiCPEvent * a ) const {
return _handle - > isEnable ( ) & & func ( a ) ;
}
std : : shared_ptr < NodeHandle > getHandle ( ) {
return _handle ;
}
} ;
using priority_level = unsigned char ;
using event_vector = std : : vector < eventNode > ;
using eventNodeTable = std : : vector < std : : map < priority_level , event_vector > > ;
private : // member
eventNodeTable _all_events_ ;
private :
Event ( ) : _all_events_ ( int ( eventTypes : : Types : : count ) ) { } ;
public : // singleton mode
static Event processor ;
private :
template < typename EventClass >
constexpr static int id ( ) {
static_assert ( std : : is_base_of_v < MiraiCPEvent , EventClass > , " 只支持广播继承MiraiCPEvent的事件 " ) ;
return static_cast < int > ( EventClass : : get_event_type ( ) ) ;
}
public :
static bool noRegistered ( int index ) {
return processor . _all_events_ [ index ] . empty ( ) ;
}
/// 清空全部配置
static void clear ( ) {
for ( auto & a : processor . _all_events_ ) a . clear ( ) ;
}
static void incomingEvent ( nlohmann : : json j , int type ) ;
/// 广播一个事件, 必须为MiraiCPEvent的派生类
template < typename EventClass >
static void broadcast ( EventClass & & val ) {
static_assert ( std : : is_base_of_v < MiraiCPEvent , EventClass > , " 只支持广播MiraiCPEvent的派生类 " ) ;
MiraiCPEvent * p = & val ;
for ( auto & & [ k , v ] : processor . _all_events_ [ id < EventClass > ( ) ] ) {
for ( auto & & a : v ) {
if ( a . run ( p ) ) return ;
}
}
}
/**
* @ brief 注 册 一 个 事 件 的 回 调
* @ param T 事 件 类 型
* @ param callback 要 注 册 的 回 调 函 数 , 忽 略 返 回 值
* @ param priority_level 优 先 级 , 范 围 : 0 - 255 , 越 低 的 优 先 级 越 先 执 行 , 默 认 100
* @ doxygenEg { 1018 , callbackHandle . cpp , NodeHandle使用 }
*/
template < typename EventClass >
static std : : shared_ptr < NodeHandle > registerEvent ( std : : function < void ( EventClass ) > callback , priority_level level = 100 ) {
static_assert ( std : : is_base_of_v < MiraiCPEvent , EventClass > , " 只支持注册MiraiCPEvent的派生类事件 " ) ;
std : : function < bool ( MiraiCPEvent * ) > tmp = [ = ] ( MiraiCPEvent * p ) {
callback ( * dynamic_cast < EventClass * > ( p ) ) ;
return false ;
} ;
auto t = eventNode ( tmp ) ;
auto ans = t . getHandle ( ) ;
// 先获得shared_ptr才可以emplace_back
processor . _all_events_ [ id < EventClass > ( ) ] [ level ] . emplace_back ( std : : move ( t ) ) ;
return ans ;
}
/**
* @ brief 注 册 一 个 可 以 阻 塞 后 续 回 调 函 数 的 回 调 。
* 回 调 返 回 true时 , 将 会 忽 略 所 有 优 先 级 低 于 当 前 回 调 , 以 及 注 册 顺 序 晚 于 当 前 回 调 且 优 先 级 等 于 当 前 回 调 的 所 有 其 他 回 调 函 数
* @ param T 事 件 类 型
* @ param callback 要 注 册 的 回 调 函 数 , 必 须 返 回 bool值
* @ param priority_level 优 先 级 , 范 围 : 0 - 255 , 越 低 的 优 先 级 越 先 执 行 , 默 认 100
* @ doxygenEg { 1019 , callbackHandle . cpp , NodeHandle使用 }
*/
template < typename EventClass >
static std : : shared_ptr < NodeHandle > registerBlockingEvent ( std : : function < bool ( EventClass ) > callback , priority_level level = 100 ) {
static_assert ( std : : is_base_of_v < MiraiCPEvent , EventClass > , " 只支持注册MiraiCPEvent的派生类事件 " ) ;
std : : function < bool ( MiraiCPEvent * ) > tmp = [ = ] ( MiraiCPEvent * p ) {
return callback ( * dynamic_cast < EventClass * > ( p ) ) ;
} ;
auto t = eventNode ( tmp ) ;
auto ans = t . getHandle ( ) ;
// 先获得shared_ptr才可以emplace_back
processor . _all_events_ [ id < EventClass > ( ) ] [ level ] . emplace_back ( std : : move ( t ) ) ;
return ans ;
}
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_EVENT_H
# ifndef MIRAICP_PRO_EXCEPTION_H
# define MIRAICP_PRO_EXCEPTION_H
// #include "CPPPlugin.h"
# include <exception>
# include <string>
# include <thread>
namespace MiraiCP {
/// @brief 总异常抽象类,用于一般捕获,不要直接抛出该类,不知道抛出什么的时候请抛出 MiraiCPException
/// @interface MiraiCPExceptionBase
class MiraiCPExceptionBase : public : : std : : exception {
protected :
using string = std : : string ;
protected :
/// @brief 异常内容
string re ;
public :
/// @brief 发生异常的文件名
string filename ;
/// @brief 发生异常的行号
int lineNum = 0 ;
protected :
/// 受保护构造函数,供子类调用
MiraiCPExceptionBase ( string info , string _filename , int _lineNum ) : re ( std : : move ( info ) ) , filename ( std : : move ( _filename ) ) , lineNum ( _lineNum ) { }
public :
~ MiraiCPExceptionBase ( ) override = default ;
public :
/// 异常信息
const char * what ( ) const noexcept override { return re . c_str ( ) ; }
/// 返回std::string的异常信息
string getError ( ) const { return re ; }
/// 实际抛出方法
void raise ( ) const ;
public : // 暴露的接口
/// basicRaise 基本抛出方法,子类重写该方法
virtual void basicRaise ( ) const ;
// CRTP实现一次, 调用静态的exceptionType
/// 获取异常类型,通用接口
virtual string getExceptionType ( ) const = 0 ;
// 每个子类需要单独实现该静态方法
/// 返回异常的类型,该静态方法无法正确实现多态,请使用 getExceptionType
/// @see getExceptionType
static string exceptionType ( ) { return " MiraiCPException " ; }
} ;
/// @brief 总异常CRTP抽象类, 不要直接抛出该类, 不知道抛出什么的时候请抛出 MiraiCPException。
/// 该类是用于继承的基类,需要新的异常类型时,继承该类并以子类作为模板参数。
/// 子类需要实现的方法:
/// 1. 构造函数, 要求必须委托MiraiCPExceptionCRTP构造, 其他成员需要在MiraiCPException构造前完成构造。
/// 2. `static std::string exceptionType()` 返回一个字符串表示异常类型。
/// 继承该类后异常类能正确实现多态。
/// @interface MiraiCPExceptionCRTP
/// @note 请勿给该类增加新的属性。如果要增加属性应在 MiraiCPExceptionBase 中增加
template < class T >
class MiraiCPExceptionCRTP : public MiraiCPExceptionBase {
public :
/// 委托构造函数
explicit MiraiCPExceptionCRTP ( std : : string _re , string _filename , int _lineNum ) : MiraiCPExceptionBase ( std : : move ( _re ) , std : : move ( _filename ) , _lineNum ) {
}
public :
// CRTP类型获取实现
string getExceptionType ( ) const override { return T : : exceptionType ( ) ; }
} ;
/// @brief 通用MiraiCP异常
/// @param const string &description, string _filename, int _lineNum
/// @see MiraiCPExceptionBase
typedef MiraiCPExceptionCRTP < MiraiCPExceptionBase > MiraiCPException ;
/// 文件读取异常.
/// @see MiraiCPExceptionBase
class UploadException : public MiraiCPExceptionCRTP < UploadException > {
public :
explicit UploadException ( const std : : string & text , string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 上传(图片/文件)异常 " + text , std : : move ( _filename ) , _lineNum ) { }
static std : : string exceptionType ( ) { return " UploadException " ; }
} ;
/// 通常为Mirai返回
/// @see MiraiCPExceptionBase
class IllegalStateException : public MiraiCPExceptionCRTP < IllegalStateException > {
public :
explicit IllegalStateException ( const std : : string & text , string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 状态异常: " + text , std : : move ( _filename ) , _lineNum ) { }
static std : : string exceptionType ( ) { return " IllegalStateException " ; }
} ;
/// 内部异常, 通常为json读写问题
/// @see MiraiCPExceptionBase
class APIException : public MiraiCPExceptionCRTP < APIException > {
public :
explicit APIException ( const std : : string & text , string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " MiraiCP内部无法预料的错误: " + text , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " APIException " ; }
} ;
/// 机器人操作异常
/// @see MiraiCPExceptionBase
class BotException : public MiraiCPExceptionCRTP < BotException > {
public :
explicit BotException ( string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 没有权限执行该操作 " , std : : move ( _filename ) , _lineNum ) { }
explicit BotException ( const string & d , string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( d , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " BotException " ; }
} ;
/// 被禁言异常, 通常发生于发送信息
class BotIsBeingMutedException : public MiraiCPExceptionCRTP < BotIsBeingMutedException > {
public :
/// 剩余禁言时间, 单位秒
int timeRemain ;
public :
explicit BotIsBeingMutedException ( int t , string _filename , int _lineNum ) : timeRemain ( t ) , MiraiCPExceptionCRTP ( " 发送信息失败, bot已被禁言, 剩余时间 " + std : : to_string ( t ) , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " BotIsBeingMutedException " ; }
} ;
/// 禁言异常
/// @see MiraiCPExceptionBase
class MuteException : public MiraiCPExceptionCRTP < MuteException > {
public :
/*
* 禁 言 时 间 超 出 0 s ~ 30 d
*/
MuteException ( string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 禁言时长不在0s~30d中间 " , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " MuteException " ; }
} ;
/// 获取群成员错误
/// @see MiraiCPExceptionBase
class MemberException : public MiraiCPExceptionCRTP < MemberException > {
public :
enum MemberExceptionType : int {
OtherType ,
NoSuchGroup ,
NoSuchMember
} ;
MemberExceptionType type = OtherType ;
/*
* " 1 " - 找 不 到 群
* " 2 " - 找 不 到 群 成 员
*/
explicit MemberException ( int _type , string _filename , int _lineNum ) : MiraiCPExceptionCRTP (
[ & ] ( ) - > string {
type = MemberExceptionType ( _type ) ;
switch ( type ) {
case NoSuchGroup :
return " 找不到群 " ;
case NoSuchMember :
return " 找不到群成员 " ;
default :
return " " ;
}
} ( ) ,
std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " MemberException " ; }
} ;
/// 获取群成员错误
/// @see MiraiCPExceptionBase
class FriendException : public MiraiCPExceptionCRTP < FriendException > {
public :
/*
* 找 不 到 好 友
*/
FriendException ( string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 找不到好友 " , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " FriendException " ; }
} ;
/// 获取群错误
/// @see MiraiCPExceptionBase
class GroupException : public MiraiCPExceptionCRTP < GroupException > {
public :
GroupException ( string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 找不到群 " , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " GroupException " ; }
} ;
/// 撤回异常
/// @see MiraiCPExceptionBase
class RecallException : public MiraiCPExceptionCRTP < RecallException > {
public :
RecallException ( string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 该消息已经被撤回 " , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " RecallException " ; }
} ;
/// 远程资源出现问题
/// @see MiraiCPExceptionBase
class RemoteAssetException : public MiraiCPExceptionCRTP < RemoteAssetException > {
public :
explicit RemoteAssetException ( const string & e , string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( e , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " RemoteAssetException " ; }
} ;
/// 参数错误
/// @see MiraiCPExceptionBase
class IllegalArgumentException : public MiraiCPExceptionCRTP < IllegalArgumentException > {
public :
explicit IllegalArgumentException ( const string & e , string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( e , std : : move ( _filename ) , _lineNum ) {
}
static string exceptionType ( ) { return " IllegalArgumentException " ; }
} ;
/// 超时
/// @see MiraiCPExceptionBase
class TimeOutException : public MiraiCPExceptionCRTP < TimeOutException > {
public :
explicit TimeOutException ( const std : : string & e , string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( e , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " TimeOutException " ; }
} ;
/// 事件被取消, 一般出现在发送消息时在preSendMessageEvent取消的时候抛出
/// @see MiraiCPExceptionBase
class EventCancelledException : public MiraiCPExceptionCRTP < EventCancelledException > {
public :
explicit EventCancelledException ( const string & msg , string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( msg , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " EventCancelledException " ; }
} ;
/// 插件没有权限时抛出该异常
/// 该异常仅可能在插件尝试调用libLoader 高级权限的Api接口时抛出
/// 如插件尝试重载、加载、卸载插件等操作,但配置文件中并没有赋予该插件权限时
/// @see MiraiCPExceptionBase
class PluginNotAuthorizedException : public MiraiCPExceptionCRTP < PluginNotAuthorizedException > {
public :
explicit PluginNotAuthorizedException ( string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 插件 " + CPPPlugin : : config . getId ( ) + " 没有管理权限 " , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " PluginNotAuthorizedException " ; }
} ;
/// 插件未加载抛出该异常
/// 在插件能正常运行时不会抛出, 出现该异常事件时请不要再次尝试收发消息等Mirai操作,
/// 否则可能导致异常处理时再次抛出异常
/// @see MiraiCPExceptionBase
class PluginNotEnabledException : public MiraiCPExceptionCRTP < PluginNotEnabledException > {
public :
explicit PluginNotEnabledException ( string _filename , int _lineNum ) : MiraiCPExceptionCRTP ( " 插件 " + CPPPlugin : : config . getId ( ) + " 未加载 " , std : : move ( _filename ) , _lineNum ) { }
static string exceptionType ( ) { return " PluginNotEnabledException " ; }
} ;
/// 如果在 MiraiCPNewThread 中捕获到了非 MiraiCP 之外的异常抛出
/// @see MiraiCPNewThread
class MiraiCPThreadException : public MiraiCPExceptionCRTP < MiraiCPThreadException > {
public :
/// 抛出异常的线程 ID
std : : thread : : id threadId ;
public :
explicit MiraiCPThreadException ( const std : : string & exception_content , std : : thread : : id threadId , string _filename , int _lineNum )
: MiraiCPExceptionCRTP ( exception_content + " at threadId: " + getThreadIdStr ( threadId ) , std : : move ( _filename ) , _lineNum ) ,
threadId ( threadId ) { }
public :
std : : string getThreadIdStr ( ) const { return getThreadIdStr ( threadId ) ; }
public :
static string exceptionType ( ) { return " MiraiCPThreadException " ; }
private :
static std : : string getThreadIdStr ( const std : : thread : : id & id ) {
std : : stringstream ss ;
ss < < id ;
return ss . str ( ) ;
}
} ;
inline void ErrorHandle0 ( const std : : string & name , int line , const std : : string & re , const std : : string & ErrorMsg = " " ) {
if ( re = = " EF " )
throw FriendException ( name , line ) ;
if ( re = = " EG " )
throw GroupException ( name , line ) ;
if ( re = = " EM " )
throw MemberException ( 1 , name , line ) ;
if ( re = = " EMM " )
throw MemberException ( 2 , name , line ) ;
if ( re = = " EB " )
throw BotException ( " 找不到bot: " + re , name , line ) ;
if ( re = = " EA " )
throw APIException ( ErrorMsg , name , line ) ;
if ( re = = " EC " )
throw EventCancelledException ( " 发送信息被取消 " , name , line ) ;
if ( re = = " ET " )
throw TimeOutException ( " 发送信息超时 " , name , line ) ;
if ( re = = " EP " )
throw BotException ( name , line ) ;
// equal to Tools::start_with
if ( re . rfind ( " EBM " , 0 ) = = 0 )
throw BotIsBeingMutedException ( std : : stoi ( re . substr ( 3 ) ) , name , line ) ;
}
} // namespace MiraiCP
# endif //MIRAICP_PRO_EXCEPTION_H
# ifndef MIRAICP_PRO_FORWARDEDMESSAGE_H
# define MIRAICP_PRO_FORWARDEDMESSAGE_H
// #include "MessageChain.h"
// #include "MiraiDefs.h"
# include <utility>
# include <variant>
namespace MiraiCP {
class Contact ;
class ForwardedMessage ;
/// 转发信息显示策略, 目前好像只在转发信息内的转发信息生效
class ForwardedMessageDisplayStrategy {
using string = std : : string ;
public :
string title = " 群聊的聊天记录 " ;
string brief = " [聊天记录] " ;
string source = " 聊天记录 " ;
string summary = " 查看1条转发信息 " ;
std : : vector < string > preview { " Name: message " } ;
public :
static std : : optional < ForwardedMessageDisplayStrategy > defaultStrategy ( ) { return std : : nullopt ; }
public :
ForwardedMessageDisplayStrategy ( ) = default ;
ForwardedMessageDisplayStrategy ( std : : string title , std : : string brief , std : : string source , std : : string summary , std : : vector < std : : string > preview ) : title ( std : : move ( title ) ) , brief ( std : : move ( brief ) ) , source ( std : : move ( source ) ) , summary ( std : : move ( summary ) ) , preview ( std : : move ( preview ) ) { }
public :
nlohmann : : json toJson ( ) {
nlohmann : : json j ;
j [ " title " ] = title ;
j [ " brief " ] = brief ;
j [ " source " ] = source ;
j [ " summary " ] = summary ;
j [ " preview " ] = preview ;
return j ;
}
} ;
///聊天记录里每个消息
/// todo 传入头像
class ForwardedNode {
public :
///发送者id
QQID id = 0 ;
///发送者昵称
std : : string name ;
///发送信息
std : : variant < MessageChain , std : : shared_ptr < ForwardedMessage > > message ;
///发送时间(时间戳)
int time = 0 ;
private :
bool isForwardedMessage ;
std : : optional < ForwardedMessageDisplayStrategy > display = std : : nullopt ;
public :
/// @brief 聊天记录里的每条信息
/// @param id - 发送者id
/// @param name - 发送者昵称
/// @param message - 发送的信息
/// @param time - 发送时间,以时间戳记
ForwardedNode ( QQID id , std : : string name , MessageChain message ,
int time )
: id ( id ) , name ( std : : move ( name ) ) , message ( std : : move ( message ) ) , time ( time ) , isForwardedMessage ( false ) { }
/// @brief 构造聊天记录里每条信息
/// @param c - 发送者的contact指针
/// @param message - 发送的信息
/// @param t - 发送时间,时间戳格式
ForwardedNode ( QQID id , std : : string name , ForwardedMessage message , int t , std : : optional < ForwardedMessageDisplayStrategy > display = ForwardedMessageDisplayStrategy : : defaultStrategy ( ) ) ;
/*
ForwardedNode ( Contact * c , MessageChain message , int t ) ;
ForwardedNode ( QQID id , std : : string name , ForwardedMessage & message , int t ) ;
*/
public :
bool isForwarded ( ) const { return isForwardedMessage ; }
} ;
/*!转发消息, 由ForwardNode组成
* @ see class ForwardedNode
* @ doxygenEg { 1005 , forwardMessage . cpp , 构 建 聊 天 记 录 }
*/
class ForwardedMessage {
private :
/// json except value
nlohmann : : json sendmsg ;
public :
/// 每条信息
std : : vector < ForwardedNode > nodes ;
/// 显示策略
std : : optional < ForwardedMessageDisplayStrategy > display = std : : nullopt ;
public :
/*!
* @ brief 构 建 一 条 聊 天 记 录
* @ details 第 一 个 参 数 是 聊 天 记 录 发 生 的 地 方 , 然 后 是 每 条 信 息
*/
ForwardedMessage ( std : : initializer_list < ForwardedNode > nodes , std : : optional < ForwardedMessageDisplayStrategy > display = ForwardedMessageDisplayStrategy : : defaultStrategy ( ) ) : ForwardedMessage ( std : : vector ( nodes ) , std : : move ( display ) ) { }
ForwardedMessage ( std : : vector < ForwardedNode > nodes , std : : optional < ForwardedMessageDisplayStrategy > display = ForwardedMessageDisplayStrategy : : defaultStrategy ( ) ) : nodes ( std : : move ( nodes ) ) , display ( std : : move ( display ) ) { }
public :
void add ( const ForwardedNode & a ) { this - > nodes . push_back ( a ) ; }
/// 发送给群或好友或群成员
MessageSource sendTo ( Contact * c ) ;
nlohmann : : json nodesToJson ( ) ;
ForwardedMessage plus ( const ForwardedNode & a ) {
ForwardedMessage tmp ( * this ) ;
tmp . nodes . push_back ( a ) ;
return tmp ;
}
public :
ForwardedNode & operator [ ] ( int index ) { return nodes [ index ] ; }
const ForwardedNode & operator [ ] ( int index ) const { return nodes [ index ] ; }
ForwardedMessage operator + ( const ForwardedNode & a ) { return this - > plus ( a ) ; }
public :
static ForwardedMessage deserializationFromMessageSourceJson ( const nlohmann : : json & j ) ;
} ;
/// 接收到的转发消息, 发送用 MiraiCP::ForwardedMessage
class OnlineForwardedMessage : public SingleMessage {
public :
/// 里面每条信息
std : : vector < ForwardedNode > nodelist ;
/// 用展示出来ServiceMessage
ServiceMessage origin ;
// unknown 用途, 有一些情况下没有
// std::optional<std::string> resourceId;
public :
explicit OnlineForwardedMessage ( nlohmann : : json o , /*std::optional<std::string> rid,*/ std : : vector < ForwardedNode > nodes ) : SingleMessage ( OnlineForwardedMessage : : type ( ) , " " ) , nodelist ( std : : move ( nodes ) ) , /*resourceId(std::move(rid)),*/ origin ( ServiceMessage ( o [ " serviceId " ] , o [ " content " ] ) ) { }
public :
/// 转ForwardedMessage
/// @param c 发生的环境, 比如群聊或者好友
ForwardedMessage toForwardedMessage ( std : : optional < ForwardedMessageDisplayStrategy > display = ForwardedMessageDisplayStrategy : : defaultStrategy ( ) ) const ;
/// 不支持直接发送OnlineForwardMessage, ForwardedMessage发送
ShouldNotUse ( " use MiraiCP::ForwardedMessage to send " ) std : : string toMiraiCode ( ) const override {
return " " ;
}
public :
ForwardedNode & operator [ ] ( int i ) {
return nodelist [ i ] ;
}
const ForwardedNode & operator [ ] ( int i ) const {
return nodelist [ i ] ;
}
bool operator = = ( const OnlineForwardedMessage & m ) const ;
public :
static int type ( ) { return - 4 ; }
static OnlineForwardedMessage deserializationFromMessageSourceJson ( const nlohmann : : json & j ) ;
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_FORWARDEDMESSAGE_H
# ifndef MIRAICP_PRO_FRIEND_H
# define MIRAICP_PRO_FRIEND_H
// #include "Contact.h"
namespace MiraiCP {
/// 好友类声明
class Friend : public Contact , INudgeSupport {
public :
/// 删除好友(delete是C++关键字)
void deleteFriend ( ) ;
void refreshInfo ( ) ;
/*!
* @ brief 发 送 戳 一 戳
* @ warning 发 送 戳 一 戳 的 前 提 是 登 录 该 bot的协议是android_phone / ipad , 否 则 抛 出 IllegalStateException
* @ throw MiraiCP : : BotException , MiraiCP : : IllegalStateException
*/
void sendNudge ( ) override ;
/*!
* @ brief 构 建 好 友 对 象
* @ param friendid q号
* @ param botid 对 应 机 器 人 id
*/
explicit Friend ( QQID friendid , QQID botid ) ;
explicit Friend ( const Contact & c ) : Contact ( c ) {
if ( c . type ( ) ! = 1 )
throw IllegalArgumentException ( " 无法从 type== " + std : : to_string ( c . type ( ) ) + " 转为 type == 1(friend) " , MIRAICP_EXCEPTION_WHERE ) ;
refreshInfo ( ) ;
} ;
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_FRIEND_H
# ifndef MIRAICP_PRO_GROUP_H
# define MIRAICP_PRO_GROUP_H
// #include "Contact.h"
# include "json.hpp"
namespace MiraiCP {
class Member ; // forward declaration
/*!
* @ detail 群 聊 类 声 明
*/
class Group : public Contact {
public : // member classes and structs
/// 群公告参数
class AnnouncementParams {
public :
/// 发送给新成员
bool send2new ;
/// 需要确认
bool requireConfirm ;
/// 置顶
bool pinned ;
/// 引导群成员修改群名片
bool showEditCard ;
/// 显示弹窗
bool showPopup ;
/// 序列化到文本
nlohmann : : json serializeToJson ( ) ;
explicit AnnouncementParams ( bool send2New = false , bool requireConfirm = false , bool pinned = false ,
bool showEditCard = false , bool showPopup = false ) : send2new ( send2New ) ,
requireConfirm (
requireConfirm ) ,
pinned ( pinned ) ,
showEditCard ( showEditCard ) ,
showPopup ( showPopup ) { }
} ;
/// 在线群公告
class OnlineAnnouncement {
public :
/// 内容
std : : string content ;
/// 所属bot
QQID botid ;
/// 公告属性
AnnouncementParams params ;
/// 所在群id
QQID groupid ;
/// 发送者id
QQID senderid ;
/// 发送时间戳
long long publicationTime ;
/// 唯一识别属性
std : : string fid ;
/// 如果需要确认,即为确认的人数
int confirmNum ;
/// 图片id, 如果不存在即为空
std : : string imageid ;
/// 删除当前群公告
/// @throw BotException
void deleteThis ( ) ;
/// 反序列化
static OnlineAnnouncement deserializeFromJson ( const nlohmann : : json & ) ;
OnlineAnnouncement ( const std : : string & content , AnnouncementParams & params ,
QQID groupid , QQID senderid , QQID botid ,
long long int publicationTime , const std : : string & fid , int confirmNum ,
const std : : string & imageid ) : content ( content ) , params ( params ) , groupid ( groupid ) ,
senderid ( senderid ) , botid ( botid ) ,
publicationTime ( publicationTime ) ,
fid ( fid ) , confirmNum ( confirmNum ) , imageid ( imageid ) { }
} ;
/// 本地(未发送)群公告
class OfflineAnnouncement {
public :
/// 内容
std : : string content ;
/// 公告属性
AnnouncementParams params ;
/// 发布群公告
Group : : OnlineAnnouncement publishTo ( const Group & ) ;
OfflineAnnouncement ( const std : : string & content , AnnouncementParams params ) : content ( content ) ,
params ( params ) { }
} ;
/**
* @ brief 群 设 置
* @ details 使 用 uploadSetting上传设置 , 使 用 refreshInfo同步服务器设定 , 后 面 两 项 由 于 https : //github.com/mamoe/mirai/issues/1307 还不能改
*/
struct GroupSetting {
/// 群名称
std : : string name ;
/// 禁言全部
bool isMuteAll { } ;
/// 允许群成员邀请
bool isAllowMemberInvite { } ;
/// 自动同意进群
bool isAutoApproveEnabled { } ;
/// 允许匿名聊天
bool isAnonymousChatEnabled { } ;
} ;
/// 群文件的简短描述
struct file_short_info {
// 路径带文件名
std : : string path ;
// 唯一id
std : : string id ;
} ;
public : // attrs
/// 群设置
GroupSetting setting ;
public : // constructors
/// @brief 构建以群号构建群对象
/// @param groupid 群号
/// @param botid 机器人id
/// @doxygenEg{1007, group.cpp, 从群号构建群对象}
Group ( QQID groupid , QQID botid ) ;
explicit Group ( const Contact & c ) : Contact ( c ) {
if ( c . type ( ) ! = 2 )
throw IllegalArgumentException ( " 无法从 type== " + std : : to_string ( c . type ( ) ) + " 转为 type == 2(group) " , MIRAICP_EXCEPTION_WHERE ) ;
refreshInfo ( ) ;
}
public : // methods
/**
* @ brief 更 新 群 设 置 , 即 覆 盖 服 务 器 上 的 群 设 置
* @ details 从 服 务 器 拉 去 群 设 置 用 refreshInfo
* @ see Group : : refreshInfo ( )
*/
void updateSetting ( ) ;
/// 取群成员列表
/// @return vector<long>
std : : vector < unsigned long long > getMemberList ( ) ;
/*!
* 以 string格式取群成员列表
* @ note 格 式 :
* 每 个 群 成 员 id间用逗号分隔
*/
std : : string MemberListToString ( ) ;
/// 取群主
Member getOwner ( ) ;
/// 取群成员
Member getMember ( QQID memberid ) ;
Member operator [ ] ( QQID id ) ;
/// 取群公告列表
std : : vector < OnlineAnnouncement > getAnnouncementsList ( ) ;
/// 刷新群聊信息
void refreshInfo ( ) ;
void quit ( ) ;
/*!
@ brief 上 传 并 发 送 远 程 ( 群 ) 文 件
@ param path - 群 文 件 路 径 ( 带 文 件 名 ) , 根 目 录 为 /
@ param filepath - 本 地 文 件 路 径
@ attention 路 径 分 隔 符 是 ` / `
@ doxygenEg { 1008 , group . cpp , 发 送 群 文 件 }
*/
RemoteFile sendFile ( const std : : string & path , const std : : string & filepath ) ;
/// 发送语音
MessageSource sendVoice ( const std : : string & path ) {
return Contact : : sendVoice0 ( path ) ;
}
/*!
取 群 文 件 信 息 , 会 自 动 搜 索 子 目 录
@ param path - 群 文 件 路 径 ( 不 带 文 件 名 )
@ param id - 文 件 id , 可 空 , 空 则 为 用 路 径 查 找 ( 此 时 路 径 要 带 文 件 名 )
@ attention 因 为 群 文 件 允 许 重 名 文 件 存 在 的 特 性 , 如 果 没 有 id该查找并不可靠 , 只 能 返 回 重 名 文 件 中 的 其 中 一 个 文 件
@ see RemoteFile
@ doxygenEg { 1009 , group . cpp , 获 取 群 文 件 }
*/
RemoteFile getFile ( const std : : string & path , const std : : string & id = " " ) ;
/*!
* @ brief 取 文 件 信 息 ( 根 据 id )
* @ param id 文 件 id
* @ return 文 件
* @ detail 相 当 于 从 根 目 录 开 始 遍 历 查 找 文 件 , 相 当 于 getFile ( " / " , id ) ;
*/
RemoteFile getFileById ( const std : : string & id ) ;
RemoteFile getFileByFile ( const RemoteFile & file ) {
return getFileById ( file . id ) ;
}
/*!
* 获 取 path路径下全部文件信息
* @ param path - 远 程 路 径
* @ return 返 回 值 为 一 个 vector容器 , 每 一 项 为 short_info
* @ doxygenEg { 1010 , group . cpp , 获 取 群 文 件 列 表 }
*/
std : : vector < file_short_info > getFileList ( const std : : string & path ) ;
/// 取文件列表以字符串形式返回
/// @param path 文件夹路径
std : : string getFileListString ( const std : : string & path ) ;
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_GROUP_H
# ifndef MIRAICP_PRO_KTOPERATION_H
# define MIRAICP_PRO_KTOPERATION_H
# include <json.hpp>
/// @brief 配置类声明, MiraiCP内部使用, 不需要更改或其他操作
/// @internal 一般为MiraiCP内部调用jni接口使用
/// @namespace KtOperation
namespace MiraiCP : : KtOperation {
/// 操作id
enum operation_set {
/// 撤回信息
Recall ,
/// 发送信息
Send ,
/// 查询信息接口
RefreshInfo ,
/// 上传图片
UploadImg ,
/// 取好友列表
QueryBFL ,
/// 取群组列表
QueryBGL ,
/// 上传文件
SendFile ,
/// 查询文件信息
RemoteFileInfo ,
/// 查询图片下载地址
QueryImgInfo ,
/// 禁言
MuteM ,
/// 查询权限
QueryM ,
/// 踢出
KickM ,
/// 取群主
QueryOwner ,
/// 语音
Voice ,
/// 查询群成员列表
QueryML ,
/// 群设置
GroupSetting ,
/// 构建转发信息
Buildforward ,
/// 好友申请事件
Nfroperation ,
/// 群聊邀请事件
Gioperation ,
/// 回复(引用并发送)
SendWithQuote ,
/// 群公告操作
Announcement ,
/// 定时任务
TimeOut ,
/// 发送戳一戳
SendNudge ,
/// 下一条信息
NextMsg ,
/// 更改权限
ModifyAdmin ,
/// 群成员申请入群
MemberJoinRequest ,
/// 图片是否已经上传
ImageUploaded ,
/// 注册指令
CommandReg ,
/// 改名称
ChangeNameCard ,
} ;
/**
* @ brief 调 用 mirai操作
* @ param type 操 作 id
* @ param data 传 入 数 据
* @ return 返 回 数 据
*/
std : : string ktOperation (
operation_set type ,
nlohmann : : json data ,
bool catchErr = true ,
const std : : string & errorInfo = " " ) ;
} // namespace MiraiCP::KtOperation
# endif //MIRAICP_PRO_KTOPERATION_H
# ifndef MIRAICP_PRO_LOGGER_H
# define MIRAICP_PRO_LOGGER_H
// #include "MiraiCode.h"
// #include "MiraiDefs.h"
# include <functional>
# include <sstream>
namespace MiraiCP {
class MiraiCodeable ; // forward declaration
/*!
* @ class Logger
* @ brief 以 MiraiCP的名义发送日志 , 日 志 表 现 格 式 是 : 2021 - 06 - 28 09 : 37 : 22 [ log level ] / MiraiCP : [ log content ] , 为 最 底 层 的 logger
* 发 送 消 息 级 日 志
* @ code Logger : : logger . info ( string ) @ endcode
* 发 送 警 告 级 日 志
* @ code Logger : : logger . warning ( string ) @ endcode
* 发 送 错 误 级 日 志
* @ code Logger : : logger . error ( string ) @ endcode
* @ doxygenEg { 1011 , logger . cpp , 自 定 义 日 志 handle }
*/
class Logger_interface {
using string = std : : string ;
public :
/// @brief 封装lambda类型
/// @param string 日志内容
/// @param 日志级别
/// - 0 info
/// - 1 warning
/// - 2 error
typedef std : : function < void ( string , int ) > Action ;
/// @brief loggerhandler会在每次log执行前执行一遍, 可用于执行自定义的保存操作等
struct Handler {
/// @brief 是否启用
bool enable = true ;
/// @brief 执行的操作, 格式为lambda
Action action = [ ] ( const string & content , int level ) { } ;
} ;
Handler loggerhandler ;
private :
static std : : string constructString ( ) {
return " " ;
}
template < class T , class . . . T1 >
static std : : string constructString ( T val , T1 . . . val1 ) {
std : : stringstream sstream ;
sstream < < val ;
return sstream . str ( ) + constructString ( val1 . . . ) ;
}
template < class . . . T >
static std : : string constructString ( std : : string a , T . . . val1 ) {
return a + constructString ( val1 . . . ) ;
}
template < class . . . T >
static std : : string constructString ( MiraiCodeable & val , T . . . val1 ) {
return val . toMiraiCode ( ) + constructString ( val1 . . . ) ;
}
protected :
/// @brief 日志底层实现封装
/// @param log 日志内容
/// @param level 日志等级
virtual void log_interface ( const string & log , int level ) = 0 ;
public :
///发送普通(info级日志)
template < class . . . T >
void info ( T . . . val ) {
this - > log_interface ( constructString ( val . . . ) , 0 ) ;
}
///发送警告(warning级日志)
template < class . . . T >
void warning ( T . . . val ) {
this - > log_interface ( constructString ( val . . . ) , 1 ) ;
}
///发送错误(error级日志)
template < class . . . T >
void error ( T . . . val ) {
this - > log_interface ( constructString ( val . . . ) , 2 ) ;
}
/// @brief 设置loggerhandler的action
/// @param action 执行的操作
/// @see Logger::handler
void registerHandle ( Action action ) {
this - > loggerhandler . action = std : : move ( action ) ;
}
/// @brief 设置handler的启用状态
/// @param state 状态,启用或者关闭
/// @doxygenEg{1012, logger.cpp, 启用或关闭日志}
void setHandleState ( bool state ) {
this - > loggerhandler . enable = state ;
}
} ;
class Logger : public Logger_interface {
private :
Logger ( ) = default ;
protected :
/// @brief 日志底层实现封装
/// @param content 日志内容
/// @param level 日志等级
void log_interface ( const std : : string & content , int level ) override ;
public :
static Logger logger ;
} ;
/// 带id(一般为bot账号)的logger
class IdLogger : public Logger_interface {
public :
QQID id ;
protected :
void log_interface ( const std : : string & content , int level ) override ;
public :
IdLogger ( QQID id , Logger * l ) : id ( id ) {
this - > loggerhandler = l - > loggerhandler ;
}
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_LOGGER_H
# ifndef MIRAICP_PRO_LOWLEVELAPI_H
# define MIRAICP_PRO_LOWLEVELAPI_H
# include <json.hpp>
namespace MiraiCP {
/// 较底层api
class LowLevelAPI {
public :
/// @brief 抽象封装底层发送信息接口
/// @param content 信息字符串
/// @param c 目标Contact->serialization()
/// @param miraicode 是否为miraicode格式
/// @return
static std : : string send0 ( const std : : string & content , nlohmann : : json c , int retryTime , bool miraicode ,
const std : : string & errorInfo = " " ) ;
/// @brief 取该联系人的一些信息
/// @param c 该联系人Contact->serializationToString()
/// @return json格式字符串, 待解析
static std : : string getInfoSource ( const std : : string & ) ;
/*!
* @ brief 上 传 图 片
* @ param path 本 地 地 址
* @ param c 上 传 的 对 象 , Contact - > serializationToString ( )
* @ return string 待 解 析 json
*/
static std : : string uploadImg0 ( const std : : string & , const std : : string & ) ;
/// 每个对象的必有信息
struct info {
std : : string nickornamecard ;
std : : string avatarUrl ;
} ;
/// 获取每个对象必有信息
/// @see LowLevelAPI::info
static info info0 ( const std : : string & source ) ;
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_LOWLEVELAPI_H
# ifndef MIRAICP_PRO_MEMBER_H
# define MIRAICP_PRO_MEMBER_H
// #include "Contact.h"
namespace MiraiCP {
/*!
* @ brief 群 成 员 类 声 明
* @ doxygenEg { 1013 , member . cpp , 群 成 员 操 作 }
*/
class Member : public Contact , INudgeSupport {
public :
/// @brief 权限等级
/// - OWNER群主 为 2
/// - ADMINISTRATOR管理员 为 1
/// - MEMBER群成员 为 0
/// @note 上面那些变量在constants.h中有定义
unsigned int permission = 0 ;
/// @brief 更改群成员权限
/// @param admin 如果为true为更改到管理员
/// @param env
void modifyAdmin ( bool admin ) ;
/// @brief 构建群成员对象
/// @param qqid 该成员q号
/// @param groupid 所在群号
/// @param botid 机器人id
explicit Member ( QQID qqid , QQID groupid , QQID botid ) ;
explicit Member ( const Contact & c ) : Contact ( c ) {
if ( c . type ( ) ! = 3 )
throw IllegalArgumentException ( " 无法从 type== " + std : : to_string ( c . type ( ) ) + " 转为 type == 3(member) " , MIRAICP_EXCEPTION_WHERE ) ;
this - > isAnonymous = this - > _anonymous ;
refreshInfo ( ) ;
} ;
/// 是否是匿名群成员, 如果是匿名群成员一些功能会受限
bool isAnonymous = false ;
/// 重新获取(刷新)群成员信息
void refreshInfo ( ) ;
/// 发送语音
MessageSource sendVoice ( const std : : string & path ) {
return Contact : : sendVoice0 ( path ) ;
}
/// 获取权限, 会在构造时调用, 请使用permission缓存变量
/// @see Member::permission
unsigned int getPermission ( ) const ;
/*!
* 禁 言 当 前 对 象 , 单 位 是 秒 , 最 少 0 秒 最 大 30 天 , 如 果 为 0 或 者 为 负 则 unmute
* @ throws BotException , MuteException
*/
void mute ( int time ) ;
/// 取消禁言
/// @throws BotException, MuteException
void unMute ( ) {
mute ( 0 ) ;
}
/*! 踢出这个群成员
* @ param reason - 原 因
*/
void kick ( const std : : string & reason ) ;
/// At一个群成员
At at ( ) {
return At ( this - > id ( ) ) ;
}
/// 更改群名片
/// @throw MiraiCP::BotException 如果没权限时
void changeNameCard ( std : : string_view newName ) ;
/*!
* @ brief 发 送 戳 一 戳
* @ warning 发 送 戳 一 戳 的 前 提 是 登 录 该 bot的协议是android_phone / ipad , 否 则 抛 出 IllegalStateException
* @ throw MiraiCP : : BotException , MiraiCP : : IllegalStateException
*/
void sendNudge ( ) override ;
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_MEMBER_H
# ifndef MIRAICP_PRO_MESSAGECHAIN_H
# define MIRAICP_PRO_MESSAGECHAIN_H
// #include "Exception.h"
// #include "SingleMessage.h"
namespace MiraiCP {
class MessageSource ; // forward declaration
namespace internal {
class Message : public std : : shared_ptr < SingleMessage > {
private :
// std::shared_ptr<SingleMessage> content;
public : // constructor
template < class T >
explicit Message ( const T & _singleMessage ) {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只支持SingleMessage的子类 " ) ;
reset ( new T ( _singleMessage ) ) ;
}
explicit Message ( std : : shared_ptr < SingleMessage > msgptr ) : std : : shared_ptr < SingleMessage > ( std : : move ( msgptr ) ) { }
public :
/// 代表的子类
/// @see MessageChain::messageType
int type ( ) const {
return ( * this ) - > type ;
} ;
/// 取指定类型
/// @throw IllegalArgumentException
template < class T >
T get ( ) const {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只支持SingleMessage的派生类 " ) ;
if ( T : : type ( ) ! = this - > type ( ) )
throw IllegalArgumentException ( " cannot convert from " + SingleMessage : : messageType [ this - > type ( ) ] + " to " + SingleMessage : : messageType [ T : : type ( ) ] , MIRAICP_EXCEPTION_WHERE ) ;
T * re = static_cast < T * > ( std : : shared_ptr < SingleMessage > : : get ( ) ) ;
if ( re = = nullptr )
throw IllegalArgumentException ( " cannot convert from " + SingleMessage : : messageType [ this - > type ( ) ] + " to " + SingleMessage : : messageType [ T : : type ( ) ] , MIRAICP_EXCEPTION_WHERE ) ;
return * re ;
}
std : : string toMiraiCode ( ) const {
return ( * this ) - > toMiraiCode ( ) ;
}
bool operator = = ( const Message & m ) const {
return ( * this ) - > type = = m - > type & & ( * this ) - > toMiraiCode ( ) = = m - > toMiraiCode ( ) ;
}
bool operator ! = ( const Message & m ) const {
return ( * this ) - > type ! = m - > type | | ( * this ) - > toMiraiCode ( ) ! = m - > toMiraiCode ( ) ;
}
} ;
} // namespace internal
/// 消息链, 一般由SingleMessage组成
class MessageChain : public std : : vector < internal : : Message > , public MiraiCodeable {
public : // typedefs
using Message = internal : : Message ;
public :
/// 如果由MiraiCP构造(incoming)就会存在,否则则不存在
std : : optional < MessageSource > source = std : : nullopt ;
public :
MessageChain ( const MessageChain & _o ) = default ;
MessageChain ( MessageChain & & _o ) = default ;
/// incoming构造器
template < class . . . T >
explicit MessageChain ( MessageSource ms , T . . . args ) : source ( std : : move ( ms ) ) {
this - > constructMessages ( args . . . ) ;
} ;
/*!
* @ brief 从 多 个 参 数 构 建 MessageChain
* @ tparam T 多 个 传 入 参 数 的 类 型
* 支 持 以 下 类 型 :
* - std : : string / const char * 相 当 于 传 入 PlainText
* - SingleMessage的派生类
* @ param args 参 数 本 身
*/
template < class . . . T >
explicit MessageChain ( T . . . args ) {
constructMessages ( args . . . ) ;
} ;
/// outcoming 构造器
template < class T >
explicit MessageChain ( const T & msg ) {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只支持SingleMessage子类 " ) ;
emplace_back ( msg ) ;
} ;
public :
[[deprecated("MessageChain继承自std::vector<Message>, 无需获取内部vector")]] const std : : vector < Message > & vector ( ) const {
return * static_cast < const std : : vector < Message > * > ( this ) ;
}
std : : string toMiraiCode ( ) const override ;
std : : vector < std : : string > toMiraiCodeVector ( ) const {
std : : vector < std : : string > tmp ;
for ( auto & & a : * this )
tmp . emplace_back ( a - > toMiraiCode ( ) ) ;
return tmp ;
}
/// @brief 添加元素
/// @tparam T 任意的SingleMessage的子类
/// @param a 添加的值
template < class T >
void add ( const T & a ) {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只接受SingleMessage的子类 " ) ;
emplace_back ( a ) ;
}
void add ( const MessageSource & val ) {
source = val ;
}
/// 筛选出某种类型的消息
template < class T >
std : : vector < T > filter ( ) {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只支持SingleMessage的子类 " ) ;
std : : vector < T > re ;
for ( auto & & a : * this ) {
if ( a . type ( ) = = T : : type ( ) )
re . emplace_back ( a . get < T > ( ) ) ;
}
return re ;
}
/// 自定义筛选器
template < class T >
std : : vector < T > filter ( const std : : function < bool ( Message ) > & func ) {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只支持SingleMessage的子类 " ) ;
std : : vector < T > re ;
for ( auto & & a : * this ) {
if ( func ( a ) )
re . push_back ( a . get < T > ( ) ) ;
}
return re ;
}
/// 找出第一个指定的type的消息, 消息可能不存在
template < class T >
std : : optional < T > first ( ) {
for ( auto & & a : * this )
if ( a . type ( ) = = T : : type ( ) )
return a . get < T > ( ) ;
return std : : nullopt ;
}
template < class T >
[[nodiscard]] MessageChain plus ( const T & a ) const {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只支持SingleMessage的子类 " ) ;
MessageChain tmp ( * this ) ;
tmp . emplace_back ( a ) ;
return tmp ;
}
[[nodiscard]] MessageChain plus ( const MessageChain & mc ) const {
MessageChain tmp ( * this ) ;
tmp . insert ( tmp . end ( ) , mc . begin ( ) , mc . end ( ) ) ;
return tmp ;
}
[[nodiscard]] MessageChain plus ( const MessageSource & ms ) const {
MessageChain tmp ( * this ) ;
tmp . source = ms ;
return tmp ;
}
template < class T >
MessageChain operator + ( const T & msg ) const {
return this - > plus ( msg ) ;
}
bool operator = = ( const MessageChain & mc ) const {
if ( size ( ) ! = mc . size ( ) )
return false ;
for ( size_t i = 0 ; i < size ( ) ; i + + ) {
if ( ( * this ) [ i ] ! = mc [ i ] )
return false ;
}
return true ;
}
bool operator ! = ( const MessageChain & mc ) const {
return ! ( * this = = mc ) ;
}
bool empty ( ) const {
return std : : vector < Message > : : empty ( ) | | toMiraiCode ( ) . empty ( ) ;
}
/// @brief 回复并发送
/// @param s 内容
/// @param groupid 如果是来源于TempGroupMessage就要提供(因为要找到那个Member)
/// @note 可以改MessageSource里的内容, 客户端在发送的时候并不会校验MessageSource的内容正确性(比如改originalMessage来改引用的文本的内容, 或者改id来定位到其他信息)
/// @detail 支持以下类型传入
/// - std::string / const char* 相当于传入PlainText(str)
/// - SingleMessage的各种派生类
/// - MessageChain
/// @deprecated use Contact.quoteAndSend or `this->quoteAndSend1(s, groupid, env)`, since v2.8.1
template < class T >
ShouldNotUse ( " use Contact.quoteAndSend " ) MessageSource
quoteAndSendMessage ( T s , QQID groupid = - 1 , void * env = nullptr ) = delete ;
public : // static functions
/// @brief 找到miraiCode结尾的`]`
/// @param s 文本
/// @param start 开始位置
/// @return 如果不存在返回-1, 存在则返回index
static size_t findEnd ( const std : : string & s , size_t start ) {
size_t pos = start ;
while ( pos < s . length ( ) ) {
switch ( s [ pos ] ) {
case ' \\ ' :
pos + = 2 ;
continue ;
case ' ] ' :
return pos ;
}
pos + + ;
}
return - 1 ;
}
/// 从miraicode string构建MessageChain
static MessageChain deserializationFromMiraiCode ( const std : : string & m ) ;
static MessageChain deserializationFromMessageSourceJson ( const std : : string & msg , bool origin = true ) {
return deserializationFromMessageSourceJson ( nlohmann : : json : : parse ( msg ) , origin ) ;
}
/// 从MessageSource json中构建MessageChain, 常用于Incoming message
/// @attention 本方法并不会自动附加MessageSource到MessageChain, 需要用.plus方法自行附加
static MessageChain deserializationFromMessageSourceJson ( const nlohmann : : json & j , bool origin = true ) ;
private : // private methods
void constructMessages ( ) { }
template < class T1 , class . . . T2 >
void constructMessages ( T1 h , T2 . . . args ) {
static_assert ( std : : is_base_of_v < SingleMessage , T1 > , " 只支持SingleMessage子类 " ) ;
emplace_back ( h ) ;
constructMessages ( args . . . ) ;
}
template < class . . . T2 >
void constructMessages ( const std : : string & h , T2 . . . args ) {
emplace_back ( PlainText ( h ) ) ;
constructMessages ( args . . . ) ;
}
template < class . . . T2 >
void constructMessages ( const char * h , T2 . . . args ) {
emplace_back ( PlainText ( h ) ) ;
constructMessages ( args . . . ) ;
}
template < class . . . T >
void constructMessages ( const MessageChain & mc , T . . . args ) {
insert ( end ( ) , mc . begin ( ) , mc . end ( ) ) ;
constructMessages ( args . . . ) ;
}
MessageSource quoteAndSend0 ( std : : string msg , QQID groupid = - 1 ) ;
template < class T >
MessageSource quoteAndSend1 ( T s , QQID groupid = - 1 ) {
static_assert ( std : : is_base_of_v < SingleMessage , T > , " 只支持SingleMessage的派生类 " ) ;
return this - > quoteAndSend0 ( s . toMiraiCode ( ) , groupid ) ;
}
MessageSource quoteAndSend1 ( std : : string s , QQID groupid ) {
return this - > quoteAndSend0 ( std : : move ( s ) , groupid ) ;
}
MessageSource quoteAndSend1 ( const MessageChain & mc , QQID groupid ) {
return this - > quoteAndSend0 ( mc . toMiraiCode ( ) , groupid ) ;
}
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_MESSAGECHAIN_H
# ifndef MIRAICP_PRO_MESSAGESOURCE_H
# define MIRAICP_PRO_MESSAGESOURCE_H
# include <string>
// #include "MiraiDefs.h"
namespace MiraiCP {
class MiraiCodeable ; // forward declaration
/*! 消息源声明
* @ doxygenEg { 1014 , message . cpp , 回 复 信 息 }
*/
class MessageSource {
public :
/// 消息的ids
std : : string ids ;
/// 消息的internalids
std : : string internalids ;
/// 消息源序列化
std : : string source ;
MessageSource ( ) = default ;
/// @deprecated 用Contact.quoteAndSendMessage, since v2.8.1
ShouldNotUse ( " Use Contact.quoteAndSendMessage " ) MessageSource
quoteAndSendMiraiCode ( MiraiCodeable * msg , QQID groupid = 0 ,
void * env = nullptr ) const = delete ;
/// @deprecated use Contact.quoteAndSendMessage, since v2.8.1
ShouldNotUse ( " Use Contact.quoteAndSendMessage " ) MessageSource
quoteAndSendMsg ( const std : : string & c , QQID groupid = 0 ,
void * = nullptr ) const = delete ;
/// @deprecated use Contact.quoteAndSendMessage, since v2.8.1
ShouldNotUse ( " Use Contact.quoteAndSendMessage " ) MessageSource
quoteAndSendMiraiCode ( const std : : string & c , QQID groupid = 0 ,
void * = nullptr ) const = delete ;
/*!
* @ brief 构 建 消 息 源
* @ param ids
* @ param internalids
* @ param source
*/
MessageSource ( std : : string ids , std : : string internalids , std : : string source ) ;
/*!
* @ brief 从 json字符串反序列化到MessageSource对象
* @ note json应该为以下格式
* @ code
* { " ids " : " " , " internalids " : " " }
* @ endcode
*/
static MessageSource deserializeFromString ( const std : : string & source ) ;
std : : string serializeToString ( ) const ;
/// @brief 撤回该信息
void recall ( ) const ;
bool operator = = ( const MessageSource & ms ) const {
return this - > ids = = ms . ids & & this - > internalids = = ms . internalids ;
}
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_MESSAGESOURCE_H
// Copyright (c) 2022 - 2022. Eritque arcus and contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or any later version(in your opinion).
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
# ifndef MIRAICP_PRO_MIRAICPNEWTHREAD_H
# define MIRAICP_PRO_MIRAICPNEWTHREAD_H
// #include "Event.h"
// #include "Exception.h"
# include <ostream>
# include <thread>
namespace MiraiCP {
/// MiraiCP 对 std::thread 的封装
class MiraiCPNewThread : public std : : thread {
public :
MiraiCPNewThread ( ) noexcept = default ;
template < typename Callable , typename . . . Args >
explicit MiraiCPNewThread ( Callable & & func , Args & & . . . args )
: std : : thread (
[ lambda_func = std : : forward < Callable > ( func ) ] ( auto & & . . . argss ) {
try {
lambda_func ( std : : forward < decltype ( argss ) > ( argss ) . . . ) ;
} catch ( MiraiCPExceptionBase & e ) {
e . raise ( ) ;
Event : : broadcast ( MiraiCPExceptionEvent ( & e ) ) ;
} catch ( const std : : exception & e ) {
MiraiCPThreadException exNew ( std : : string ( e . what ( ) ) , std : : this_thread : : get_id ( ) , MIRAICP_EXCEPTION_WHERE ) ;
exNew . raise ( ) ;
Event : : broadcast ( MiraiCPExceptionEvent ( & exNew ) ) ;
} catch ( . . . ) {
MiraiCPThreadException exNew ( " unknown exception type " , std : : this_thread : : get_id ( ) , MIRAICP_EXCEPTION_WHERE ) ;
exNew . raise ( ) ;
Event : : broadcast ( MiraiCPExceptionEvent ( & exNew ) ) ;
}
} ,
std : : forward < Args > ( args ) . . . ) { }
MiraiCPNewThread & operator = ( const std : : thread & ) = delete ;
MiraiCPNewThread & operator = ( const MiraiCPNewThread & ) = delete ;
MiraiCPNewThread & operator = ( std : : thread & & other ) {
* static_cast < std : : thread * > ( this ) = std : : move ( other ) ;
return * this ;
}
MiraiCPNewThread & operator = ( MiraiCPNewThread & & other ) noexcept {
* static_cast < std : : thread * > ( this ) = std : : move ( * static_cast < std : : thread * > ( & other ) ) ;
return * this ;
}
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_MIRAICPNEWTHREAD_H
# ifndef MIRAICP_PRO_MIRAICODE_H
# define MIRAICP_PRO_MIRAICODE_H
# include <string>
namespace MiraiCP {
/// MiraiCode父类, 指可以被转换成miraicode的类型
class MiraiCodeable {
public :
/// 返回MiraiCode
virtual std : : string toMiraiCode ( ) const = 0 ;
} ;
/// @brief miraicode字符串
/// @attention MiraiCode会把非miraicode组成部分(非[mirai:])转码, 输出转码前的文本用toString, 参考: https://github.com/mamoe/mirai/blob/dev/docs/Messages.md#%E8%BD%AC%E4%B9%89%E8%A7%84%E5%88%99
/// @detail 为了便捷使用, 构造函数不以explicit注释
class MiraiCode : public MiraiCodeable {
private :
std : : string content ;
public :
/// 输出当前内容, 会自动转码
std : : string toString ( ) ;
/// 和toString作用一样, 不过不会自动转码
std : : string toMiraiCode ( ) const override {
return content ;
}
/// 从MiraiCodeable类型初始化一个miraicode字符串
MiraiCode ( MiraiCodeable * a ) { // NOLINT(google-explicit-constructor)
content = a - > toMiraiCode ( ) ;
}
/// 从文本初始化一个miraicode字符串, 根据第二个参数决定是否转码, 默认不转码
/// @attention 如果是传入文本MiraiCode, 请勿转码, 转码只是为了[mirai:xxx:<应该转码的部分>], 如果<应该转码>的部分里面含有'[]:,'内容, 请调用Tools::escapeToMiraiCode转码
MiraiCode ( const std : : string & a , bool convert = false ) ;
MiraiCode operator + ( MiraiCodeable * a ) {
return { content + a - > toMiraiCode ( ) } ;
}
MiraiCode operator + ( const std : : string & a ) {
return { content + a } ;
}
MiraiCode operator + ( const MiraiCode & a ) {
return { content + a . content } ;
}
MiraiCode operator + ( MiraiCode * a ) {
return { content + a - > content } ;
}
MiraiCode & operator = ( const std : : string & a ) {
this - > content = a ;
return * this ;
}
MiraiCode plus ( MiraiCodeable * a ) {
return { content + a - > toMiraiCode ( ) } ;
}
MiraiCode plus ( const std : : string & a ) {
return MiraiCode ( a ) + this ;
}
/// 不执行转义, 适用于已经被MiraiCode转义过的字符串
static MiraiCode MiraiCodeWithoutEscape ( const std : : string & a ) {
return { a , false } ;
}
/// 不执行转义, 因为MiraiCodeable的toMiraiCode已经转义过了
static MiraiCode MiraiCodeWithoutEscape ( MiraiCodeable * a ) {
return { a - > toMiraiCode ( ) , false } ;
}
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_MIRAICODE_H
# ifndef MIRAICP_PRO_MIRAIDEFS_H
# define MIRAICP_PRO_MIRAIDEFS_H
// #define MiraiCPThrow(x) throw x.append(__FILE__, __LINE__)
# define ErrorHandle(x, y) ErrorHandle0(__FILE__, __LINE__, (x), (y))
# define MIRAICP_EXCEPTION_WHERE __FILE__, __LINE__
# if defined(_MSC_VER)
# define ShouldNotUse(msg) _Pragma("warning(error:4996)") [[deprecated(msg)]] _Pragma("warning(warning:4996)")
# else // MSVC
# if defined(__GNUC__)
# define ShouldNotUse(msg) [[deprecated(msg)]] __attribute__((error(msg)))
# else // GUNC
# define ShouldNotUse(msg)
# endif // ShouldNotUse
# endif
# include <string>
namespace MiraiCP {
using QQID = unsigned long long ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_MIRAIDEFS_H
# ifndef MIRAICP_PRO_SINGLEMESSAGE_H
# define MIRAICP_PRO_SINGLEMESSAGE_H
# include <array>
# include <json.hpp>
# include <optional>
# include <sstream>
// #include "MessageSource.h"
// #include "MiraiCode.h"
namespace MiraiCP {
/// 用serviceMessage的分享信息
struct URLSharer {
/// 简介 没点进来看见的样子
std : : string brief = " 简介 没点进来看见的样子 " ;
/// 目标url
std : : string url = " 目标url " ;
/// 图标地址
std : : string cover = " 图标地址 " ;
/// 标题
std : : string title = " 标题 " ;
/// 描述文字
std : : string summary = " 描述文字 " ;
} ;
/// MessageChain的组成部分
class SingleMessage : public MiraiCodeable {
public :
/// MiraiCode类别
/// @see SingleMessage::messageType
int type ;
std : : string content ;
std : : string prefix ;
public :
static std : : unordered_map < int , std : : string > messageType ;
public :
/// @brief 构建单条
/// @param type 消息类型 @see messageType
/// @param content 内容
/// @param prefix 前缀, 默认为`:`, 第二个冒号部分的内容, 目前在serviceMesage有使用
SingleMessage ( int type , std : : string content , std : : string prefix = " : " ) : type ( type ) ,
content ( std : : move ( content ) ) ,
prefix ( std : : move ( prefix ) ) { }
virtual ~ SingleMessage ( ) = default ;
public :
/// @brief 找对应类型的index key
/// @param value 类型名
/// @return 如果没找到返回-1
static int getKey ( const std : : string & value ) ;
public :
virtual nlohmann : : json toJson ( ) const {
nlohmann : : json re ;
re [ " key " ] = " miraicode " ;
re [ " content " ] = this - > toMiraiCode ( ) ;
return re ;
}
std : : string toMiraiCode ( ) const override ;
public :
bool operator = = ( const SingleMessage & m ) const {
return this - > type = = m . type & & this - > toMiraiCode ( ) = = m . toMiraiCode ( ) ;
}
bool operator = = ( SingleMessage * m ) const {
return this - > type = = m - > type & & this - > toMiraiCode ( ) = = m - > toMiraiCode ( ) ;
}
} ;
/// 纯文本信息
class PlainText : public SingleMessage {
public :
explicit PlainText ( const SingleMessage & sg ) ;
template < typename T >
explicit PlainText ( const T & a ) : SingleMessage ( PlainText : : type ( ) , ( [ & a ] ( ) - > std : : string {
std : : stringstream sst ;
sst < < a ;
return sst . str ( ) ;
} ) ( ) ) { }
PlainText ( PlainText & & _o ) noexcept : SingleMessage ( PlainText : : type ( ) , std : : move ( _o . content ) ) { }
PlainText ( const PlainText & _o ) : SingleMessage ( PlainText : : type ( ) , _o . content ) { }
public :
static int type ( ) { return 0 ; }
public :
std : : string toMiraiCode ( ) const override {
return content ;
}
nlohmann : : json toJson ( ) const override ;
bool operator = = ( const PlainText & p ) const {
return this - > content = = p . content ;
}
} ;
/// @
class At : public SingleMessage {
public :
static int type ( ) { return 1 ; }
QQID target ;
nlohmann : : json toJson ( ) const override ;
explicit At ( const SingleMessage & sg ) ;
explicit At ( QQID a ) : SingleMessage ( At : : type ( ) , std : : to_string ( a ) ) , target ( a ) { } ;
std : : string toMiraiCode ( ) const override {
return " [mirai:at: " + std : : to_string ( this - > target ) + " ] " ; // 后面有个空格
}
bool operator = = ( const At & a ) const {
return this - > target = = a . target ;
}
} ;
/// @brief \@全体
class AtAll : public SingleMessage {
public :
static int type ( ) { return 2 ; }
std : : string toMiraiCode ( ) const override {
return " [mirai:atall] " ;
}
nlohmann : : json toJson ( ) const override ;
AtAll ( ) : SingleMessage ( AtAll : : type ( ) , " " , " " ) { }
} ;
/// 图像类声明
class Image : public SingleMessage {
public :
static int type ( ) { return 3 ; }
//图片id, 样式:` {xxx}.xx `
std : : string id ;
/// 可为空, 用`refreshInfo`获取
std : : optional < std : : string > md5 ;
/// 可为0, 来源:用`refreshInfo`可能可以获取或者自己填充, 是isUploaded的必须条件, 默认0
size_t size ;
/// 可为空, 用`refreshInfo`获取
std : : optional < std : : string > url ;
/// 宽度, 默认0, 单位px
int width ;
/// 长度, 默认0, 单位px
int height ;
/*!
* @ brief 图 片 类 型
* - 0 png
* - 1 bmp
* - 2 jpg
* - 3 gif
* - 4 apng
* - 5 unknown
* 默 认 5
*/
int imageType ;
/*!
* @ brief 图 片 是 否 已 经 上 传 ( 如 果 已 经 上 传 即 表 明 可 以 直 接 用 ImageId发送 , 如 果 没 有 需 要 手 动 上 传 )
* @ param md5 在 kotlin端会用 . toByteArray ( ) 转 换
* @ param size 图 片 大 小 , 不 能 为 0
* @ param botid 所 属 Botid
* @ return 是 否 已 上 传
*/
bool isUploaded ( QQID botid ) ;
/*!
* @ brief 从 图 片 builder构造 , 适 用 于 服 务 器 上 已 经 有 的 图 片 , 即 接 收 到 的
* @ param imageId 图 片 id , 必 须
* @ param size isUploaded的必要条件 , 单 纯 用 ImageId可能取不到图片size , 需 要 自 己 上 传
* @ param width 宽 度
* @ param height 长 度
* @ param type 图 片 类 型
* @ detail 图 片 miraiCode格式例子 , ` [ mirai : image : { 图 片 id } . jpg ] `
* 可 以 用 这 个 正 则 表 达 式 找 出 id ` \ \ [ mirai : image : ( . * ? ) \ \ ] `
*/
explicit Image ( const std : : string & imageId , size_t size = 0 , int width = 0 , int height = 0 , int type = 5 ) : SingleMessage ( Image : : type ( ) , imageId ) {
this - > id = imageId ;
this - > size = size ;
this - > width = width ;
this - > height = height ;
this - > imageType = type ;
}
explicit Image ( const SingleMessage & sg ) ;
/// 刷新信息(获取图片下载Url,md5, size)
void refreshInfo ( ) ;
/// 取图片Mirai码
std : : string toMiraiCode ( ) const override {
return " [mirai:image: " + this - > id + " ] " ;
}
nlohmann : : json toJson ( ) const override ;
static Image deserialize ( const std : : string & ) ;
bool operator = = ( const Image & i ) const {
return this - > id = = i . id ;
}
} ;
/// 闪照, 和Image属性类似
class FlashImage : public Image {
public :
static int type ( ) { return 8 ; }
std : : string toMiraiCode ( ) const override {
return " [mirai:flash: " + this - > id + " ] " ;
}
explicit FlashImage ( const std : : string & imageId , size_t size = 0 , int width = 0 , int height = 0 , int type = 0 ) : Image ( imageId , size , width , height , type ) {
this - > SingleMessage : : type = 8 ;
}
explicit FlashImage ( const SingleMessage & sg ) : Image ( sg ) { }
explicit FlashImage ( const Image & img ) : Image ( img ) { }
nlohmann : : json toJson ( ) const override ;
static FlashImage deserialize ( const std : : string & ) ;
bool operator = = ( const FlashImage & i ) const {
return this - > id = = i . id ;
}
/// 转换到普通图片
Image toImage ( ) { return Image ( id , size , width , height , imageType ) ; }
} ;
/*!
* @ brief 小 程 序 卡 片
* @ attention 自 带 的 模 板 不 稳 定 , 可 能 发 出 现 没 有 效 果
* @ doxygenEg { 1015 , lightApp . cpp , 从 文 本 构 建 LightApp }
*/
class LightApp : public SingleMessage {
public :
static int type ( ) { return 4 ; }
/// @brief 使用纯文本构造,推荐使用其他结构体方法构造
/// @param content 构造文本
explicit LightApp ( std : : string content ) : SingleMessage ( LightApp : : type ( ) , std : : move ( content ) ) { }
explicit LightApp ( const SingleMessage & sg ) ;
nlohmann : : json toJson ( ) const override ;
/// 返回miraicode
std : : string toMiraiCode ( ) const override ;
bool operator = = ( const LightApp & la ) const {
return this - > content = = la . content ;
}
} ;
/// xml格式的超文本信息
/// @attention 自带的模板不稳定,可能发出现没有效果
class ServiceMessage : public SingleMessage {
public :
static int type ( ) { return 5 ; }
nlohmann : : json toJson ( ) const override ;
std : : string toMiraiCode ( ) const override ;
int id ;
/// @brief ServiceMessage
/// @param id 在xml内容前面的id (不包括逗号)
/// @param a xml内容 (不需要事先转码到miraiCode)
explicit ServiceMessage ( int id , std : : string a ) : SingleMessage ( ServiceMessage : : type ( ) , std : : move ( a ) ,
" : " + std : : to_string ( id ) + ' , ' ) ,
id ( id ) { }
explicit ServiceMessage ( const SingleMessage & sg ) ;
explicit ServiceMessage ( const URLSharer & a ) : SingleMessage ( 5 ,
" <?xml version= \" 1.0 \" encoding= \" utf-8 \" ?><msg templateID= \" 12345 \" action= \" web \" brief= \" " +
a . brief + " \" serviceID= \" 1 \" url= \" " + a . url +
" \" ><item layout= \" 2 \" ><picture cover= \" " +
a . cover + " \" /><title> " + a . title +
" </title><summary> " + a . summary +
" </summary></item><source/></msg> " ,
" :1, " ) ,
id ( 1 ) { }
bool operator = = ( const ServiceMessage & s ) const {
return this - > content = = s . content ;
}
} ;
/// 引用信息
class QuoteReply : public SingleMessage {
public :
static int type ( ) { return - 2 ; }
// 不可直接发送, 发送引用信息用MessageChain.quoteAndSendMessage
ShouldNotUse ( " don't have MiraiCode, use MessageChain.quote instead " ) std : : string toMiraiCode ( ) const override {
return " " ;
}
/// 引用信息的MessageSource
MessageSource source ;
explicit QuoteReply ( const SingleMessage & m ) ;
explicit QuoteReply ( MessageSource source ) : SingleMessage ( QuoteReply : : type ( ) , source . serializeToString ( ) ) , source ( std : : move ( source ) ) { } ;
bool operator = = ( const QuoteReply & qr ) const {
return this - > source = = qr . source ;
}
} ;
/// 接收到的音频文件, 发送用`Contact.sendAudio`
class OnlineAudio : public SingleMessage {
public :
static int type ( ) { return - 3 ; }
/// 文件名
std : : string filename ;
/// 下载地址
std : : string url ;
/// 文件大小
int size ;
/// 编码方式
int codec ;
/// 时长(单位s)
int length ;
/// 16位md5
std : : array < uint8_t , 16 > md5 ;
/// 不支持直接发送, 用Contact.sendAudio
ShouldNotUse ( " cannot use, use Contact.sendAudio " ) std : : string toMiraiCode ( ) const override {
return " " ;
}
explicit OnlineAudio ( std : : string f , std : : array < uint8_t , 16 > md5 , int size , int codec , int length ,
std : : string url ) : SingleMessage ( OnlineAudio : : type ( ) , " " ) ,
filename ( std : : move ( f ) ) , md5 ( md5 ) , size ( size ) , codec ( codec ) ,
length ( length ) , url ( std : : move ( url ) ) { } ;
bool operator = = ( const OnlineAudio & oa ) const {
return this - > md5 = = oa . md5 ;
}
} ;
/// @brief 远程(群)文件类型
class RemoteFile : public SingleMessage {
public :
static int type ( ) { return 6 ; }
/// @brief 下载信息
/// @see RemoteFile
struct Dinfo {
/// 下载地址, 可能会是 `null` 当文件不存在
std : : string url ;
/// md5 可用于校验
std : : string md5 ;
/// sha1 可用于校验
std : : string sha1 ;
} ;
/// @brief 文件信息
/// @see RemoteFile
struct Finfo {
/// 文件大小
QQID size ;
/// 上传者id
QQID uploaderid ;
/// 过期时间
long expirytime ;
/// 上传时间, 时间戳格式
QQID uploadtime ;
/// 上次更改时间, 时间戳格式
QQID lastmodifytime ;
} ;
/// 文件唯一id, 用于识别
std : : string id ;
/// 文件内部id, 用于构造miraiCode发送
unsigned int internalid ;
/// 文件名
std : : string name ;
/// 文件大小
long long size ;
/// 文件在群文件的路径
/// @attention 可能为空(通常出现于MessageChain从MiraiCode反序列化), 需要从Group重新获取文件
/// @see Group::getFileByFile
std : : optional < std : : string > path ;
/// 文件下载信息
/// @attention 可能为空(常出现于MessageChain从MiraiCode反序列化), 如果为空需要从Group重新获取
/// @see MiraiCP::Dinfo, Group::getFileByFile
std : : optional < Dinfo > dinfo ;
/// 文件信息
/// @attention 可能为空(常出现于MessageChain从MiraiCode反序列化), 如果为空需要从Group重新获取
/// @see MiraiCP::Finfo, Group::getFileByFile
std : : optional < Finfo > finfo ;
std : : string serializeToString ( ) ;
RemoteFile plus ( unsigned int ii ) ;
static RemoteFile deserializeFromString ( const std : : string & source ) ;
/*!
* @ brief 构 造 远 程 ( 群 ) 文 件
* @ param i ids
* @ param ii internalids
* @ param n name
* @ param s size
* @ param p path
* @ param d dinfo
* @ param f finfo
*/
explicit RemoteFile ( const std : : string & i , unsigned int ii , std : : string n , long long s , std : : string p , struct Dinfo d , struct Finfo f ) ;
/*!
* @ brief 构 造 远 程 ( 群 ) 文 件
* @ param i ids
* @ param ii internalids
* @ param n name
* @ param s size
* @ param p path
* @ param d dinfo
* @ param f finfo
*/
explicit RemoteFile ( const std : : string & i , unsigned int ii , std : : string n , long long s ) ;
/// 上传后会自动发送
ShouldNotUse ( " Cannot send manually, use Group.sendFile " ) std : : string toMiraiCode ( ) const override {
return " " ;
}
bool operator = = ( const RemoteFile & rf ) const {
return this - > id = = rf . id ;
}
} ;
/// 自带表情
/// @attention 有些表情会变成PlainText类型和\\xxx 的格式
class Face : public SingleMessage {
public :
static int type ( ) { return 7 ; }
int id ;
nlohmann : : json toJson ( ) const override ;
std : : string toMiraiCode ( ) const override {
return " [mirai:face: " + std : : to_string ( id ) + " ] " ;
}
explicit Face ( int id ) : SingleMessage ( Face : : type ( ) , std : : to_string ( id ) ) , id ( id ) { }
bool operator = = ( const Face & f ) const {
return this - > id = = f . id ;
}
} ;
/// 一些可以被mirai识别的音乐卡片, 如果不能被mirai识别, 那应该被表现成lightApp类型(可能收费/vip歌曲用lightApp, 免费用MusicShare)
class MusicShare : public SingleMessage {
public :
static int type ( ) { return 9 ; }
/// 应用名称, 如NeteaseCloudMusic
std : : string appName ;
/// 歌名
std : : string title ;
/// 卡片第二行的文字内容
std : : string summary ;
/// 点击跳转到的链接
std : : string jumpUrl ;
/// 图片链接
std : : string picUrl ;
/// 音乐文件链接
std : : string musicUrl ;
/// 简介, 点进聊天节目前显示的小文字, 一般是`分享`
std : : string brief ;
std : : string toMiraiCode ( ) const override {
return " [mirai:musicshare: " + appName + " , " + title + " , " + summary + " , " + jumpUrl + " , " + picUrl + " , " + musicUrl + " , " + brief + " ] " ;
}
MusicShare ( const std : : string & appName , const std : : string & title , const std : : string & summary , const std : : string & jumpUrl , const std : : string & picUrl , const std : : string & musicUrl , const std : : string & brief ) : SingleMessage ( MusicShare : : type ( ) , " " ) , appName ( appName ) , title ( title ) , summary ( summary ) , jumpUrl ( jumpUrl ) , picUrl ( picUrl ) , musicUrl ( musicUrl ) , brief ( brief ) { }
} ;
class MarketFace : public SingleMessage {
public :
static int type ( ) { return - 5 ; }
/// 目前无法直接发送MarketFace, 可以转发
ShouldNotUse ( " 暂不支持直接发送 " ) std : : string toMiraiCode ( ) const override {
return " " ;
}
std : : array < uint8_t , 16 > faceId ;
explicit MarketFace ( std : : array < uint8_t , 16 > id ) : SingleMessage ( MarketFace : : type ( ) , " " ) , faceId ( id ) { }
bool operator = = ( const MarketFace & mf ) const {
return this - > faceId = = mf . faceId ;
}
} ;
/// @brief 目前不支持的消息类型, 不支持发送
class UnSupportMessage : public SingleMessage {
public :
static int type ( ) { return - 1 ; }
nlohmann : : json toJson ( ) const override ;
/// 不支持发送
ShouldNotUse ( " 不支持直接发送UnSupportMessage " ) std : : string toMiraiCode ( ) const override {
return " " ;
}
explicit UnSupportMessage ( const SingleMessage & s ) : SingleMessage ( s ) { } ;
explicit UnSupportMessage ( const std : : string & content ) : SingleMessage ( UnSupportMessage : : type ( ) , content ) { }
bool operator = = ( const UnSupportMessage & m ) const {
return this - > content = = m . content ;
}
} ;
} // namespace MiraiCP
# endif //MIRAICP_PRO_SINGLEMESSAGE_H
# ifndef MIRAICP_PRO_TOOLS_H
# define MIRAICP_PRO_TOOLS_H
// #include "MiraiDefs.h"
# include <sstream>
# include <string>
# include <vector>
# if defined(__clang__) || defined(__GNUC__)
# define MIRAICP_CPP_STANDARD __cplusplus
# elif defined(_MSC_VER)
# define MIRAICP_CPP_STANDARD _MSVC_LANG
# endif
//#if MIRAICP_CPP_STANDARD >= 201703L
//#define get_return_type std::invoke_result_t
//#else
//#define get_return_type std::result_of_t
//#endif
namespace MiraiCP {
/// @brief 工具类声明, 常用的一些转换工具, 如需转码使用std::filesystem
/// @class Tools
namespace Tools {
/*!
* @ brief 替 换 全 部 在 一 个 字 符 串 中 .
* @ param str 原 字 符 串 .
* @ param from 需 要 被 替 换 的 字 符 .
* @ param to 替 换 到 的 字 符 .
* @ return 返 回 替 换 后 的 字 符 串 .
* @ note 来 源 : https : //stackoverflow.com/a/24315631/14646226
*/
std : : string replace ( std : : string str , std : : string_view from , std : : string_view to ) ;
/// @brief long long 类型的vector格式化输出
/// @param a vector
/// @return string
template < typename T >
std : : string VectorToString ( const std : : vector < T > & a , const std : : string & separator = " , " ) {
std : : stringstream ss ;
for ( size_t i = 0 ; i < a . size ( ) ; + + i ) {
if ( i ! = 0 )
ss < < separator ;
ss < < a [ i ] ;
}
std : : string s = ss . str ( ) ;
return s ;
}
/// @brief 从string格式化到vector
/// @param temp string
/// @return vector
std : : vector < QQID > StringToVector ( std : : string temp ) ;
/// @brief 从miraicode转义到正常
/// @param s 经过miraicode转义的字符串
/// @return 原字符串
std : : string escapeFromMiraiCode ( const std : : string & s ) ;
/// @brief 转义miraicode格式
std : : string escapeToMiraiCode ( const std : : string & s ) ;
/// starts_with, from <https://stackoverflow.com/questions/1878001/how-do-i-check-if-a-c-stdstring-starts-with-a-certain-string-and-convert-a>
bool starts_with ( std : : string_view f , std : : string_view s ) ;
/// compare char with case-insensitive
bool icompareChar ( const char & c1 , const char & c2 ) ;
/// case insensitive string compare from https://thispointer.com/c-case-insensitive-string-comparison-using-stl-c11-boost-library/
bool iequal ( std : : string_view str1 , std : : string_view str2 ) ;
/// from https://www.zhihu.com/question/36642771, delim is regex(ignore last `+`)
std : : vector < std : : string > split ( const std : : string & text , const std : : string & delim ) ;
} ; // namespace Tools
} // namespace MiraiCP
// #undef get_return_type
# endif //MIRAICP_PRO_TOOLS_H
// Copyright (c) 2022 - 2022. Antares, Eritque arcus and contributors.
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or any later version(in your opinion).
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
# ifndef MIRAICP_PRO_LOADERAPI_H
# define MIRAICP_PRO_LOADERAPI_H
// #include "loaderApiInternal.h"
namespace LibLoader : : LoaderApi {
} // namespace LibLoader::LoaderApi
# endif //MIRAICP_PRO_LOADERAPI_H
# ifndef MIRAICP_PRO_UTILS_H
# define MIRAICP_PRO_UTILS_H
// #include "CPPPlugin.h"
// #include "KtOperation.h"
// #include "PluginConfig.h"
// #include "commonTypes.h"
namespace MiraiCP {
/*!
* @ brief 定 时 任 务 , 在 一 定 时 间 后 广 播 * * 一 次 * * TimeOutEvent
* @ param time 在 多 少 毫 秒 后 执 行
* @ param msg 附 加 的 string类型信息
* @ doxygenEg { 1017 , schedule . cpp , 定 时 任 务 }
*/
inline void schedule ( long time , const std : : string & msg ) {
nlohmann : : json j ;
j [ " time " ] = time ;
j [ " msg " ] = msg ;
KtOperation : : ktOperation ( KtOperation : : TimeOut , j ) ;
}
/// 注册插件函数, 需要被实现, 类似onStart();
void enrollPlugin ( ) ;
/// 用指针绑定插件
inline void enrollPlugin ( CPPPlugin * p ) {
CPPPlugin : : plugin . reset ( p ) ;
}
[[deprecated("use enrollPlugin instead")]] inline void enrollPlugin0 ( CPPPlugin * p ) {
enrollPlugin ( p ) ;
}
} // namespace MiraiCP
# ifndef MIRAICP_EXPORT
# if _WIN32 || _WIN64 || WIN32
# define MIRAICP_EXPORT __declspec(dllexport)
# else
# define MIRAICP_EXPORT
# endif
# endif
extern " C " {
MIRAICP_EXPORT void FUNC_ENTRANCE ( const LibLoader : : LoaderApi : : interface_funcs & ) ;
MIRAICP_EXPORT void FUNC_EVENT ( const char * content ) ;
MIRAICP_EXPORT void FUNC_EXIT ( ) ;
MIRAICP_EXPORT const MiraiCP : : PluginConfig & PLUGIN_INFO ( ) ;
}
# endif //MIRAICP_PRO_UTILS_H