mirror of
https://github.com/caozhiyi/CppNet.git
synced 2026-01-12 00:19:01 +08:00
[FIX] 1. add clang-tidy, 2. warning fix
This commit is contained in:
273
.clang-tidy
Normal file
273
.clang-tidy
Normal file
@@ -0,0 +1,273 @@
|
||||
Checks: "
|
||||
android-cloexec-accept,\
|
||||
android-cloexec-accept4,\
|
||||
android-cloexec-creat,\
|
||||
android-cloexec-dup,\
|
||||
android-cloexec-epoll-create,\
|
||||
android-cloexec-epoll-create1,\
|
||||
android-cloexec-fopen,\
|
||||
android-cloexec-inotify-init,\
|
||||
android-cloexec-inotify-init1,\
|
||||
android-cloexec-memfd-create,\
|
||||
android-cloexec-open,\
|
||||
android-cloexec-pipe,\
|
||||
android-cloexec-pipe2,\
|
||||
android-cloexec-socket,\
|
||||
android-comparison-in-temp-failure-retry,\
|
||||
bugprone-argument-comment,\
|
||||
bugprone-assert-side-effect,\
|
||||
bugprone-bad-signal-to-kill-thread,\
|
||||
bugprone-bool-pointer-implicit-conversion,\
|
||||
bugprone-copy-constructor-init,\
|
||||
bugprone-dangling-handle,\
|
||||
bugprone-dynamic-static-initializers,\
|
||||
bugprone-easily-swappable-parameters,\
|
||||
bugprone-exception-escape,\
|
||||
bugprone-fold-init-type,\
|
||||
bugprone-forward-declaration-namespace,\
|
||||
bugprone-forwarding-reference-overload,\
|
||||
bugprone-implicit-widening-of-multiplication-result,\
|
||||
bugprone-inaccurate-erase,\
|
||||
bugprone-incorrect-roundings,\
|
||||
bugprone-infinite-loop,\
|
||||
bugprone-integer-division,\
|
||||
bugprone-lambda-function-name,\
|
||||
bugprone-macro-parentheses,\
|
||||
bugprone-macro-repeated-side-effects,\
|
||||
bugprone-misplaced-operator-in-strlen-in-alloc,\
|
||||
bugprone-misplaced-widening-cast,\
|
||||
bugprone-move-forwarding-reference,\
|
||||
bugprone-multiple-statement-macro,\
|
||||
bugprone-no-escape,\
|
||||
bugprone-not-null-terminated-result,\
|
||||
bugprone-parent-virtual-call,\
|
||||
bugprone-posix-return,\
|
||||
bugprone-redundant-branch-condition,\
|
||||
bugprone-signal-handler,\
|
||||
bugprone-signed-char-misuse,\
|
||||
bugprone-sizeof-container,\
|
||||
bugprone-sizeof-expression,\
|
||||
bugprone-spuriously-wake-up-functions,\
|
||||
bugprone-string-constructor,\
|
||||
bugprone-string-integer-assignment,\
|
||||
bugprone-string-literal-with-embedded-nul,\
|
||||
bugprone-suspicious-enum-usage,\
|
||||
bugprone-suspicious-include,\
|
||||
bugprone-suspicious-memset-usage,\
|
||||
bugprone-suspicious-missing-comma,\
|
||||
bugprone-suspicious-semicolon,\
|
||||
bugprone-suspicious-string-compare,\
|
||||
bugprone-swapped-arguments,\
|
||||
bugprone-terminating-continue,\
|
||||
bugprone-throw-keyword-missing,\
|
||||
bugprone-too-small-loop-variable,\
|
||||
bugprone-undefined-memory-manipulation,\
|
||||
bugprone-undelegated-constructor,\
|
||||
bugprone-unhandled-exception-at-new,\
|
||||
bugprone-unhandled-self-assignment,\
|
||||
bugprone-unused-raii,\
|
||||
bugprone-unused-return-value,\
|
||||
bugprone-use-after-move,\
|
||||
bugprone-virtual-near-miss,\
|
||||
cert-dcl21-cpp,\
|
||||
cert-dcl50-cpp,\
|
||||
cert-dcl58-cpp,\
|
||||
cert-env33-c,\
|
||||
cert-err34-c,\
|
||||
cert-err52-cpp,\
|
||||
cert-err58-cpp,\
|
||||
cert-err60-cpp,\
|
||||
cert-flp30-c,\
|
||||
cert-mem57-cpp,\
|
||||
cert-msc50-cpp,\
|
||||
cert-msc51-cpp,\
|
||||
cert-oop57-cpp,\
|
||||
cert-oop58-cpp,\
|
||||
clang-analyzer-core.DynamicTypePropagation,\
|
||||
clang-analyzer-core.uninitialized.CapturedBlockVariable,\
|
||||
clang-analyzer-cplusplus.InnerPointer,\
|
||||
clang-analyzer-cplusplus.NewDelete,\
|
||||
clang-analyzer-cplusplus.NewDeleteLeaks,\
|
||||
clang-analyzer-cplusplus.PlacementNewChecker,\
|
||||
clang-analyzer-cplusplus.SelfAssignment,\
|
||||
clang-analyzer-nullability.NullableReturnedFromNonnull,\
|
||||
clang-analyzer-optin.osx.OSObjectCStyleCast,\
|
||||
clang-analyzer-optin.performance.GCDAntipattern,\
|
||||
clang-analyzer-optin.performance.Padding,\
|
||||
clang-analyzer-optin.portability.UnixAPI,\
|
||||
clang-analyzer-osx.MIG,\
|
||||
clang-analyzer-osx.NumberObjectConversion,\
|
||||
clang-analyzer-osx.OSObjectRetainCount,\
|
||||
clang-analyzer-osx.ObjCProperty,\
|
||||
clang-analyzer-osx.cocoa.AutoreleaseWrite,\
|
||||
clang-analyzer-osx.cocoa.Loops,\
|
||||
clang-analyzer-osx.cocoa.MissingSuperCall,\
|
||||
clang-analyzer-osx.cocoa.NonNilReturnValue,\
|
||||
clang-analyzer-osx.cocoa.RunLoopAutoreleaseLeak,\
|
||||
clang-analyzer-valist.CopyToSelf,\
|
||||
clang-analyzer-valist.Uninitialized,\
|
||||
clang-analyzer-valist.Unterminated,\
|
||||
concurrency-mt-unsafe,\
|
||||
concurrency-thread-canceltype-asynchronous,\
|
||||
cppcoreguidelines-avoid-goto,\
|
||||
cppcoreguidelines-avoid-non-const-global-variables,\
|
||||
cppcoreguidelines-init-variables,\
|
||||
cppcoreguidelines-interfaces-global-init,\
|
||||
cppcoreguidelines-macro-usage,\
|
||||
cppcoreguidelines-narrowing-conversions,\
|
||||
cppcoreguidelines-no-malloc,\
|
||||
cppcoreguidelines-prefer-member-initializer,\
|
||||
cppcoreguidelines-pro-type-const-cast,\
|
||||
cppcoreguidelines-pro-type-cstyle-cast,\
|
||||
cppcoreguidelines-pro-type-member-init,\
|
||||
cppcoreguidelines-pro-type-static-cast-downcast,\
|
||||
cppcoreguidelines-pro-type-union-access,\
|
||||
cppcoreguidelines-slicing,\
|
||||
cppcoreguidelines-special-member-functions,\
|
||||
darwin-avoid-spinlock,\
|
||||
darwin-dispatch-once-nonstatic,\
|
||||
google-build-explicit-make-pair,\
|
||||
google-build-namespaces,\
|
||||
google-build-using-namespace,\
|
||||
google-default-arguments,\
|
||||
google-explicit-constructor,\
|
||||
google-global-names-in-headers,\
|
||||
google-objc-avoid-nsobject-new,\
|
||||
google-objc-avoid-throwing-exception,\
|
||||
google-objc-function-naming,\
|
||||
google-objc-global-variable-declaration,\
|
||||
google-readability-avoid-underscore-in-googletest-name,\
|
||||
google-readability-casting,\
|
||||
google-readability-todo,\
|
||||
google-runtime-int,\
|
||||
google-runtime-operator,\
|
||||
hicpp-avoid-goto,\
|
||||
hicpp-exception-baseclass,\
|
||||
hicpp-multiway-paths-covered,\
|
||||
hicpp-no-assembler,\
|
||||
hicpp-signed-bitwise,\
|
||||
linuxkernel-must-use-errs,\
|
||||
llvm-header-guard,\
|
||||
llvm-include-order,\
|
||||
llvm-namespace-comment,\
|
||||
llvm-prefer-isa-or-dyn-cast-in-conditionals,\
|
||||
llvm-prefer-register-over-unsigned,\
|
||||
llvm-twine-local,\
|
||||
misc-definitions-in-headers,\
|
||||
misc-misplaced-const,\
|
||||
misc-new-delete-overloads,\
|
||||
misc-no-recursion,\
|
||||
misc-non-copyable-objects,\
|
||||
misc-redundant-expression,\
|
||||
misc-static-assert,\
|
||||
misc-throw-by-value-catch-by-reference,\
|
||||
misc-unconventional-assign-operator,\
|
||||
misc-uniqueptr-reset-release,\
|
||||
misc-unused-alias-decls,\
|
||||
misc-unused-parameters,\
|
||||
misc-unused-using-decls,\
|
||||
modernize-avoid-bind,\
|
||||
modernize-concat-nested-namespaces,\
|
||||
modernize-deprecated-headers,\
|
||||
modernize-deprecated-ios-base-aliases,\
|
||||
modernize-loop-convert,\
|
||||
modernize-make-shared,\
|
||||
modernize-make-unique,\
|
||||
modernize-pass-by-value,\
|
||||
modernize-raw-string-literal,\
|
||||
modernize-redundant-void-arg,\
|
||||
modernize-replace-auto-ptr,\
|
||||
modernize-replace-disallow-copy-and-assign-macro,\
|
||||
modernize-replace-random-shuffle,\
|
||||
modernize-return-braced-init-list,\
|
||||
modernize-shrink-to-fit,\
|
||||
modernize-unary-static-assert,\
|
||||
modernize-use-auto,\
|
||||
modernize-use-bool-literals,\
|
||||
modernize-use-default-member-init,\
|
||||
modernize-use-emplace,\
|
||||
modernize-use-equals-default,\
|
||||
modernize-use-equals-delete,\
|
||||
modernize-use-nodiscard,\
|
||||
modernize-use-noexcept,\
|
||||
modernize-use-nullptr,\
|
||||
modernize-use-override,\
|
||||
modernize-use-transparent-functors,\
|
||||
modernize-use-uncaught-exceptions,\
|
||||
modernize-use-using,\
|
||||
mpi-buffer-deref,\
|
||||
mpi-type-mismatch,\
|
||||
objc-avoid-nserror-init,\
|
||||
objc-dealloc-in-category,\
|
||||
objc-forbidden-subclassing,\
|
||||
objc-missing-hash,\
|
||||
objc-nsinvocation-argument-lifetime,\
|
||||
objc-property-declaration,\
|
||||
objc-super-self,\
|
||||
openmp-exception-escape,\
|
||||
openmp-use-default-none,\
|
||||
performance-faster-string-find,\
|
||||
performance-for-range-copy,\
|
||||
performance-implicit-conversion-in-loop,\
|
||||
performance-inefficient-algorithm,\
|
||||
performance-inefficient-string-concatenation,\
|
||||
performance-inefficient-vector-operation,\
|
||||
performance-move-const-arg,\
|
||||
performance-move-constructor-init,\
|
||||
performance-no-automatic-move,\
|
||||
performance-no-int-to-ptr,\
|
||||
performance-noexcept-move-constructor,\
|
||||
performance-trivially-destructible,\
|
||||
performance-type-promotion-in-math-fn,\
|
||||
performance-unnecessary-copy-initialization,\
|
||||
performance-unnecessary-value-param,\
|
||||
portability-restrict-system-includes,\
|
||||
portability-simd-intrinsics,\
|
||||
readability-avoid-const-params-in-decls,\
|
||||
readability-braces-around-statements,\
|
||||
readability-const-return-type,\
|
||||
readability-container-size-empty,\
|
||||
readability-convert-member-functions-to-static,\
|
||||
readability-delete-null-pointer,\
|
||||
readability-else-after-return,\
|
||||
readability-function-cognitive-complexity,\
|
||||
readability-function-size,\
|
||||
readability-identifier-naming,\
|
||||
readability-implicit-bool-conversion,\
|
||||
readability-inconsistent-declaration-parameter-name,\
|
||||
readability-isolate-declaration,\
|
||||
readability-make-member-function-const,\
|
||||
readability-misleading-indentation,\
|
||||
readability-misplaced-array-index,\
|
||||
readability-non-const-parameter,\
|
||||
readability-qualified-auto,\
|
||||
readability-redundant-access-specifiers,\
|
||||
readability-redundant-control-flow,\
|
||||
readability-redundant-declaration,\
|
||||
readability-redundant-function-ptr-dereference,\
|
||||
readability-redundant-member-init,\
|
||||
readability-redundant-preprocessor,\
|
||||
readability-redundant-smartptr-get,\
|
||||
readability-redundant-string-cstr,\
|
||||
readability-redundant-string-init,\
|
||||
readability-simplify-boolean-expr,\
|
||||
readability-simplify-subscript-expr,\
|
||||
readability-static-accessed-through-instance,\
|
||||
readability-static-definition-in-anonymous-namespace,\
|
||||
readability-string-compare,\
|
||||
readability-uniqueptr-delete-release,\
|
||||
readability-use-anyofallof,\
|
||||
zircon-temporary-objects"
|
||||
CheckOptions:
|
||||
- key: cppcoreguidelines-pro-type-member-init.IgnoreArrays
|
||||
value: '0'
|
||||
- key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions
|
||||
value: '1'
|
||||
- key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor
|
||||
value: '1'
|
||||
- key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctionsWhenCopyIsDeleted
|
||||
value: '1'
|
||||
- key: readability-braces-around-statements.ShortStatementLines
|
||||
value: '1'
|
||||
- key: modernize-use-default-member-init.IgnoreMacros
|
||||
value: '1'
|
||||
@@ -13,7 +13,7 @@ set(CXX_FLAGS
|
||||
-fPIC
|
||||
-lstdc++
|
||||
-pipe
|
||||
)
|
||||
)
|
||||
|
||||
if(CMAKE_BUILD_BITS EQUAL 32)
|
||||
list(APPEND CXX_FLAGS "-m32")
|
||||
|
||||
@@ -8,15 +8,13 @@
|
||||
#include "cppnet_base.h"
|
||||
#include "cppnet/cppnet_config.h"
|
||||
|
||||
#include "common/util/random.h"
|
||||
#include "common/log/log.h"
|
||||
#include "common/log/file_logger.h"
|
||||
#include "common/log/stdout_logger.h"
|
||||
|
||||
namespace cppnet {
|
||||
|
||||
CppNet::CppNet() {
|
||||
|
||||
}
|
||||
|
||||
CppNet::~CppNet() {
|
||||
if (_cppnet_base) {
|
||||
@@ -52,44 +50,44 @@ void CppNet::Join() {
|
||||
_cppnet_base->Join();
|
||||
}
|
||||
|
||||
void CppNet::SetReadCallback(const read_call_back& cb) {
|
||||
_cppnet_base->SetReadCallback(cb);
|
||||
void CppNet::SetReadCallback(read_call_back&& cb) {
|
||||
_cppnet_base->SetReadCallback(std::move(cb));
|
||||
}
|
||||
|
||||
void CppNet::SetWriteCallback(const write_call_back& cb) {
|
||||
_cppnet_base->SetWriteCallback(cb);
|
||||
void CppNet::SetWriteCallback(write_call_back&& cb) {
|
||||
_cppnet_base->SetWriteCallback(std::move(cb));
|
||||
}
|
||||
|
||||
void CppNet::SetDisconnectionCallback(const connect_call_back& cb) {
|
||||
_cppnet_base->SetDisconnectionCallback(cb);
|
||||
void CppNet::SetDisconnectionCallback(connect_call_back&& cb) {
|
||||
_cppnet_base->SetDisconnectionCallback(std::move(cb));
|
||||
}
|
||||
|
||||
void CppNet::SetTimerCallback(const timer_call_back& cb) {
|
||||
_cppnet_base->SetTimerCallback(cb);
|
||||
void CppNet::SetTimerCallback(timer_call_back&& cb) {
|
||||
_cppnet_base->SetTimerCallback(std::move(cb));
|
||||
}
|
||||
|
||||
uint64_t CppNet::AddTimer(int32_t interval, const user_timer_call_back& cb, void* param, bool always) {
|
||||
return _cppnet_base->AddTimer(interval, cb, param, always);
|
||||
uint64_t CppNet::AddTimer(int32_t interval, user_timer_call_back&& cb, void* param, bool always) {
|
||||
return _cppnet_base->AddTimer(interval, std::move(cb), param, always);
|
||||
}
|
||||
|
||||
void CppNet::RemoveTimer(uint64_t timer_id) {
|
||||
_cppnet_base->RemoveTimer(timer_id);
|
||||
}
|
||||
|
||||
void CppNet::SetAcceptCallback(const connect_call_back& cb) {
|
||||
_cppnet_base->SetAcceptCallback(cb);
|
||||
void CppNet::SetAcceptCallback(connect_call_back&& cb) {
|
||||
_cppnet_base->SetAcceptCallback(std::move(cb));
|
||||
}
|
||||
|
||||
bool CppNet::ListenAndAccept(const std::string& ip, uint16_t port) {
|
||||
return _cppnet_base->ListenAndAccept(ip, port);
|
||||
}
|
||||
|
||||
void CppNet::SetConnectionCallback(const connect_call_back& cb) {
|
||||
_cppnet_base->SetConnectionCallback(cb);
|
||||
void CppNet::SetConnectionCallback(connect_call_back&& cb) {
|
||||
_cppnet_base->SetConnectionCallback(std::move(cb));
|
||||
}
|
||||
|
||||
bool CppNet::Connection(const std::string& ip, uint16_t port) {
|
||||
return _cppnet_base->Connection(ip, port);
|
||||
}
|
||||
|
||||
}
|
||||
} // namespace cppnet
|
||||
|
||||
@@ -31,14 +31,6 @@ union TimerId {
|
||||
};
|
||||
|
||||
|
||||
CppNetBase::CppNetBase() {
|
||||
|
||||
}
|
||||
|
||||
CppNetBase::~CppNetBase() {
|
||||
|
||||
}
|
||||
|
||||
void CppNetBase::Init(uint32_t thread_num) {
|
||||
uint32_t cpus = GetCpuNum();
|
||||
if (thread_num == 0 || thread_num >= cpus * 2) {
|
||||
@@ -72,7 +64,7 @@ void CppNetBase::Join() {
|
||||
}
|
||||
}
|
||||
|
||||
uint64_t CppNetBase::AddTimer(uint32_t interval, const user_timer_call_back& cb, void* param, bool always) {
|
||||
uint64_t CppNetBase::AddTimer(uint32_t interval, user_timer_call_back&& cb, void* param, bool always) {
|
||||
uint32_t index = _random->Random();
|
||||
uint32_t id = _dispatchers[index]->AddTimer(cb, param, interval, always);
|
||||
TimerId tid;
|
||||
|
||||
@@ -23,29 +23,29 @@ class CppNetBase:
|
||||
public std::enable_shared_from_this<CppNetBase> {
|
||||
|
||||
public:
|
||||
CppNetBase();
|
||||
~CppNetBase();
|
||||
CppNetBase() = default;
|
||||
~CppNetBase() = default;
|
||||
// common
|
||||
void Init(uint32_t thread_num);
|
||||
void Dealloc();
|
||||
void Join();
|
||||
|
||||
// set call back
|
||||
void SetReadCallback(const read_call_back& cb) { _read_cb = cb; }
|
||||
void SetWriteCallback(const write_call_back& cb) { _write_cb = cb; }
|
||||
void SetDisconnectionCallback(const connect_call_back& cb) { _disconnect_cb = cb; }
|
||||
void SetTimerCallback(const timer_call_back& cb) { _timer_cb = cb; }
|
||||
void SetReadCallback(read_call_back&& cb) { _read_cb = std::move(cb); }
|
||||
void SetWriteCallback(write_call_back&& cb) { _write_cb = std::move(cb); }
|
||||
void SetDisconnectionCallback(connect_call_back&& cb) { _disconnect_cb = std::move(cb); }
|
||||
void SetTimerCallback(timer_call_back&& cb) { _timer_cb = std::move(cb); }
|
||||
|
||||
// about timer
|
||||
uint64_t AddTimer(uint32_t interval, const user_timer_call_back& cb, void* param = nullptr, bool always = false);
|
||||
uint64_t AddTimer(uint32_t interval, user_timer_call_back&& cb, void* param = nullptr, bool always = false);
|
||||
void RemoveTimer(uint64_t timer_id);
|
||||
|
||||
//server
|
||||
void SetAcceptCallback(const connect_call_back& cb) { _accept_cb = cb; }
|
||||
void SetAcceptCallback(connect_call_back&& cb) { _accept_cb = std::move(cb); }
|
||||
bool ListenAndAccept(const std::string& ip, uint16_t port);
|
||||
|
||||
//client
|
||||
void SetConnectionCallback(const connect_call_back& cb) { _connect_cb = cb; }
|
||||
void SetConnectionCallback(connect_call_back&& cb) { _connect_cb = std::move(cb); }
|
||||
bool Connection(const std::string& ip, uint16_t port);
|
||||
|
||||
// call back
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
namespace cppnet {
|
||||
|
||||
typedef std::function<void()> Task;
|
||||
using Task = std::function<void()>;
|
||||
|
||||
class Timer;
|
||||
class RWSocket;
|
||||
@@ -30,12 +30,12 @@ class Dispatcher:
|
||||
|
||||
public:
|
||||
Dispatcher(std::shared_ptr<CppNetBase> base, uint32_t thread_num, uint32_t base_id);
|
||||
Dispatcher(std::shared_ptr<CppNetBase> base, uint32_t base_id = 0);
|
||||
~Dispatcher();
|
||||
explicit Dispatcher(std::shared_ptr<CppNetBase> base, uint32_t base_id = 0);
|
||||
~Dispatcher() override;
|
||||
|
||||
void Run();
|
||||
void Run() override;
|
||||
|
||||
void Stop();
|
||||
void Stop() override;
|
||||
|
||||
void Listen(uint64_t sock, const std::string& ip, uint16_t port);
|
||||
|
||||
@@ -53,7 +53,6 @@ private:
|
||||
void DoTask();
|
||||
uint32_t MakeTimerID();
|
||||
|
||||
private:
|
||||
uint64_t _cur_utc_time;
|
||||
|
||||
std::mutex _timer_id_mutex;
|
||||
|
||||
@@ -19,7 +19,7 @@ class CppNetBase;
|
||||
// cppnet instance
|
||||
class CppNet {
|
||||
public:
|
||||
CppNet();
|
||||
CppNet() = default;
|
||||
~CppNet();
|
||||
// common
|
||||
// init cppnet library.
|
||||
@@ -31,23 +31,23 @@ public:
|
||||
void Join();
|
||||
|
||||
// must set callback before listen
|
||||
void SetReadCallback(const read_call_back& cb);
|
||||
void SetWriteCallback(const write_call_back& cb);
|
||||
void SetDisconnectionCallback(const connect_call_back& cb);
|
||||
void SetReadCallback(read_call_back&& cb);
|
||||
void SetWriteCallback(write_call_back&& cb);
|
||||
void SetDisconnectionCallback(connect_call_back&& cb);
|
||||
|
||||
// if use socket timer, set it
|
||||
void SetTimerCallback(const timer_call_back& cb);
|
||||
void SetTimerCallback(timer_call_back&& cb);
|
||||
|
||||
// return timer id
|
||||
uint64_t AddTimer(int32_t interval, const user_timer_call_back& cb, void* param = nullptr, bool always = false);
|
||||
uint64_t AddTimer(int32_t interval, user_timer_call_back&& cb, void* param = nullptr, bool always = false);
|
||||
void RemoveTimer(uint64_t timer_id);
|
||||
|
||||
//server
|
||||
void SetAcceptCallback(const connect_call_back& cb);
|
||||
void SetAcceptCallback(connect_call_back&& cb);
|
||||
bool ListenAndAccept(const std::string& ip, uint16_t port);
|
||||
|
||||
//client
|
||||
void SetConnectionCallback(const connect_call_back& cb);
|
||||
void SetConnectionCallback(connect_call_back&& cb);
|
||||
bool Connection(const std::string& ip, uint16_t port);
|
||||
|
||||
private:
|
||||
|
||||
Reference in New Issue
Block a user