# Conflicts:
#	.gitignore
main
HwangKC 2024-09-14 22:53:36 +08:00
commit 0a14ee1735
107 changed files with 6399 additions and 2082 deletions

View File

@ -223,3 +223,110 @@ bool OpDatabase::queryUser(const std::string& user_id, const std::string& passwd
return false;
}
}
bool OpDatabase::queryInnerDevice(int dev_id, std::string& jsonResult)
{
try
{
#if 0
// 数据库连接配置
std::string server = "tcp://127.0.0.1:3306";
std::string dbuser = "root";
std::string password = "Hj57471000";
std::string database = "hjems";
// 创建连接
sql::mysql::MySQL_Driver* driver;
driver = sql::mysql::get_mysql_driver_instance();
//m_pDbConnection.reset(driver->connect(server, dbuser, password));
sql::Connection* pDbConnection = driver->connect(server, dbuser, password);
if( !pDbConnection )
{
hloge("Failed to connect to database.");
return false;
}
// 设置为使用指定数据库
pDbConnection->setSchema(database);
hloge("%s : %s", user_id.c_str(), passwd_md5.c_str());
#endif
// 准备SQL查询语句
std::string sql = "SELECT uid,uname, upasswd,usalt,email,mobile1,mobile2,memo FROM tbl_user WHERE uid = ?";
// 创建预编译的prepared statement
std::unique_ptr<sql::PreparedStatement> pstmt(m_pDbConnection->prepareStatement(sql));
// 绑定参数
pstmt->setString(1, user_id); // 替换为你要查询的用户名
// 执行查询
std::unique_ptr<sql::ResultSet> res(pstmt->executeQuery());
bool ret = false;
OpenJson json;
auto& nodeRoot = json["user"];
int i = 0;
// 处理结果集
while( res->next() )
{
auto& node = nodeRoot[i++];
node["valid"] = 0;
node["uid"] = res->getString("uid");
// 假设username和password都是字符串类型
std::string pass = res->getString("upasswd");
std::string salt = res->getString("usalt");
//计算passwd和salt之间的关系
//!passwd=md5(passwd_md5+salt+salt)
// passwd_md5 是大写的,需要确保一下
std::string tmp2(passwd_md5);
std::transform(tmp2.begin(), tmp2.end(), tmp2.begin(),
[](unsigned char c)
{
return std::toupper(c);
});
std::string tmp = tmp2 + salt + salt;
std::string smd5 = CalculateMD5(tmp);
if( pass == smd5 )
{
node["valid"] = 1;
node["uname"] = res->getString("uname");
node["email"] = res->getString("email");
node["mobile1"] = res->getString("mobile1");
node["mobile2"] = res->getString("mobile2");
node["memo"] = res->getString("memo");
ret = true;
break;
}
else
{
hloge("upass=[%s],calc=[%s],src=[%s]", pass.c_str(), smd5.c_str(), tmp.c_str());
}
}
jsonResult = json.encode();
//pDbConnection->close();
//delete pDbConnection;
return ret;
}
catch( sql::SQLException& e )
{
std::ostringstream ss;
ss << "SQLException: " << e.what();
ss << " (MySQL error code: " << e.getErrorCode();
ss << ", SQLState: " << e.getSQLState() << " )";
hloge("Failed to connect to database: %s", ss.str().c_str());
return false;
}
}

View File

@ -21,6 +21,9 @@ public:
void InsertMessage(const std::string& ts, const std::string& msg_type, const std::string& fsu, const std::string& content, int topic, int dev_id);
bool queryUser(const std::string& user_id, const std::string& passwd_md5, std::string& jsonResult);
//查询设备,dev_id=0则返回全部
bool queryInnerDevice(int dev_id, std::string& jsonResult);
protected:
//std::unique_ptr<sql::Connection> m_pDbConnection;
sql::Connection* m_pDbConnection;

View File

@ -0,0 +1,74 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
*~
*.autosave
*.a
*.core
*.moc
*.o
*.obj
*.orig
*.rej
*.so
*.so.*
*_pch.h.cpp
*_resource.rc
*.qm
.#*
*.*#
core
!core/
tags
.DS_Store
.directory
*.debug
Makefile*
*.prl
*.app
moc_*.cpp
ui_*.h
qrc_*.cpp
Thumbs.db
*.res
*.rc
/.qmake.cache
/.qmake.stash
# qtcreator generated files
*.pro.user*
CMakeLists.txt.user*
# xemacs temporary files
*.flc
# Vim temporary files
.*.swp
# Visual Studio generated files
*.ib_pdb_index
*.idb
*.ilk
*.pdb
*.sln
*.suo
*.vcproj
*vcproj.*.*.user
*.ncb
*.sdf
*.opensdf
*.vcxproj
*vcxproj.*
# MinGW generated files
*.Debug
*.Release
# Python byte code
*.pyc
# Binaries
# --------
*.dll
*.exe

View File

@ -0,0 +1,254 @@
INSTALLATION INSTRUCTIONS
These instructions refer to the package you are installing as
some-package.tar.gz or some-package.zip. The .zip file is intended for use
on Windows.
The directory you choose for the installation will be referred to as
your-install-dir.
Note to Qt Visual Studio Integration users: In the instructions below,
instead of building from command line with nmake, you can use the menu
command 'Qt->Open Solution from .pro file' on the .pro files in the
example and plugin directories, and then build from within Visual
Studio.
Unpacking and installation
--------------------------
1. Unpacking the archive (if you have not done so already).
On Unix and Mac OS X (in a terminal window):
cd your-install-dir
gunzip some-package.tar.gz
tar xvf some-package.tar
This creates the subdirectory some-package containing the files.
On Windows:
Unpack the .zip archive by right-clicking it in explorer and
choosing "Extract All...". If your version of Windows does not
have zip support, you can use the infozip tools available
from www.info-zip.org.
If you are using the infozip tools (in a command prompt window):
cd your-install-dir
unzip some-package.zip
2. Configuring the package.
The configure script is called "configure" on unix/mac and
"configure.bat" on Windows. It should be run from a command line
after cd'ing to the package directory.
You can choose whether you want to use the component by including
its source code directly into your project, or build the component
as a dynamic shared library (DLL) that is loaded into the
application at run-time. The latter may be preferable for
technical or licensing (LGPL) reasons. If you want to build a DLL,
run the configure script with the argument "-library". Also see
the note about usage below.
(Components that are Qt plugins, e.g. styles and image formats,
are by default built as a plugin DLL.)
The configure script will prompt you in some cases for further
information. Answer these questions and carefully read the license text
before accepting the license conditions. The package cannot be used if
you do not accept the license conditions.
3. Building the component and examples (when required).
If a DLL is to be built, or if you would like to build the
examples, next give the commands
qmake
make [or nmake if your are using Microsoft Visual C++]
The example program(s) can be found in the directory called
"examples" or "example".
Components that are Qt plugins, e.g. styles and image formats, are
ready to be used as soon as they are built, so the rest of this
installation instruction can be skipped.
4. Building the Qt Designer plugin (optional).
Some of the widget components are provided with plugins for Qt
Designer. To build and install the plugin, cd into the
some-package/plugin directory and give the commands
qmake
make [or nmake if your are using Microsoft Visual C++]
Restart Qt Designer to make it load the new widget plugin.
Note: If you are using the built-in Qt Designer from the Qt Visual
Studio Integration, you will need to manually copy the plugin DLL
file, i.e. copy
%QTDIR%\plugins\designer\some-component.dll
to the Qt Visual Studio Integration plugin path, typically:
C:\Program Files\Trolltech\Qt VS Integration\plugins
Note: If you for some reason are using a Qt Designer that is built
in debug mode, you will need to build the plugin in debug mode
also. Edit the file plugin.pro in the plugin directory, changing
'release' to 'debug' in the CONFIG line, before running qmake.
Solutions components are intended to be used directly from the package
directory during development, so there is no 'make install' procedure.
Using a component in your project
---------------------------------
To use this component in your project, add the following line to the
project's .pro file (or do the equivalent in your IDE):
include(your-install-dir/some-package/src/some-package.pri)
This adds the package's sources and headers to the SOURCES and HEADERS
project variables respectively (or, if the component has been
configured as a DLL, it adds that library to the LIBS variable), and
updates INCLUDEPATH to contain the package's src
directory. Additionally, the .pri file may include some dependencies
needed by the package.
To include a header file from the package in your sources, you can now
simply use:
#include <SomeClass>
or alternatively, in pre-Qt 4 style:
#include <some-class.h>
Refer to the documentation to see the classes and headers this
components provides.
Install documentation (optional)
--------------------------------
The HTML documentation for the package's classes is located in the
your-install-dir/some-package/doc/html/index.html. You can open this
file and read the documentation with any web browser.
To install the documentation into Qt Assistant (for Qt version 4.4 and
later):
1. In Assistant, open the Edit->Preferences dialog and choose the
Documentation tab. Click the Add... button and select the file
your-install-dir/some-package/doc/html/some-package.qch
For Qt versions prior to 4.4, do instead the following:
1. The directory your-install-dir/some-package/doc/html contains a
file called some-package.dcf. Execute the following commands in a
shell, command prompt or terminal window:
cd your-install-dir/some-package/doc/html/
assistant -addContentFile some-package.dcf
The next time you start Qt Assistant, you can access the package's
documentation.
Removing the documentation from assistant
-----------------------------------------
If you have installed the documentation into Qt Assistant, and want to uninstall it, do as follows, for Qt version 4.4 and later:
1. In Assistant, open the Edit->Preferences dialog and choose the
Documentation tab. In the list of Registered Documentation, select
the item com.nokia.qtsolutions.some-package_version, and click
the Remove button.
For Qt versions prior to 4.4, do instead the following:
1. The directory your-install-dir/some-package/doc/html contains a
file called some-package.dcf. Execute the following commands in a
shell, command prompt or terminal window:
cd your-install-dir/some-package/doc/html/
assistant -removeContentFile some-package.dcf
Using the component as a DLL
----------------------------
1. Normal components
The shared library (DLL) is built and placed in the
some-package/lib directory. It is intended to be used directly
from there during development. When appropriate, both debug and
release versions are built, since the run-time linker will in some
cases refuse to load a debug-built DLL into a release-built
application or vice versa.
The following steps are taken by default to help the dynamic
linker to locate the DLL at run-time (during development):
Unix: The some-package.pri file will add linker instructions to
add the some-package/lib directory to the rpath of the
executable. (When distributing, or if your system does not support
rpath, you can copy the shared library to another place that is
searched by the dynamic linker, e.g. the "lib" directory of your
Qt installation.)
Mac: The full path to the library is hardcoded into the library
itself, from where it is copied into the executable at link time,
and ready by the dynamic linker at run-time. (When distributing,
you will want to edit these hardcoded paths in the same way as for
the Qt DLLs. Refer to the document "Deploying an Application on
Mac OS X" in the Qt Reference Documentation.)
Windows: the .dll file(s) are copied into the "bin" directory of
your Qt installation. The Qt installation will already have set up
that directory to be searched by the dynamic linker.
2. Plugins
For Qt Solutions plugins (e.g. image formats), both debug and
release versions of the plugin are built by default when
appropriate, since in some cases the release Qt library will not
load a debug plugin, and vice versa. The plugins are automatically
copied into the plugins directory of your Qt installation when
built, so no further setup is required.
Plugins may also be built statically, i.e. as a library that will be
linked into your application executable, and so will not need to
be redistributed as a separate plugin DLL to end users. Static
building is required if Qt itself is built statically. To do it,
just add "static" to the CONFIG variable in the plugin/plugin.pro
file before building. Refer to the "Static Plugins" section in the
chapter "How to Create Qt Plugins" for explanation of how to use a
static plugin in your application. The source code of the example
program(s) will also typically contain the relevant instructions
as comments.
Uninstalling
------------
The following command will remove any fils that have been
automatically placed outside the package directory itself during
installation and building
make distclean [or nmake if your are using Microsoft Visual C++]
If Qt Assistant documentation or Qt Designer plugins have been
installed, they can be uninstalled manually, ref. above.
Enjoy! :)
- The Qt Solutions Team.

View File

@ -0,0 +1 @@
#include "qtlockedfile.h"

View File

@ -0,0 +1,33 @@
Qt Solutions Component: Single Application
The QtSingleApplication component provides support for
applications that can be only started once per user.
Version history:
2.0: - Version 1.3 ported to Qt 4.
2.1: - Fix compilation problem on Mac.
2.2: - Really fix the Mac compilation problem.
- Mac: fix crash due to wrong object releasing.
- Mac: Fix memory leak.
2.3: - Windows: Force creation of internal widget to make it work
with Qt 4.2.
2.4: - Fix the system for automatic window raising on message
reception. NOTE: minor API change.
2.5: - Mac: Fix isRunning() to work and report correctly.
2.6: - - initialize() is now obsolete, no longer necessary to call
it
- - Fixed race condition where multiple instances migth be started
- - QtSingleCoreApplication variant provided for non-GUI (console)
usage
- Complete reimplementation. Visible changes:
- LGPL release.

View File

@ -0,0 +1,205 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtlocalpeer.h"
#include <QCoreApplication>
#include <QTime>
#include <QDataStream>
#include <QRegularExpression>
#if defined(Q_OS_WIN)
#include <QLibrary>
#include <qt_windows.h>
typedef BOOL(WINAPI*PProcessIdToSessionId)(DWORD,DWORD*);
static PProcessIdToSessionId pProcessIdToSessionId = 0;
#endif
#if defined(Q_OS_UNIX)
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#endif
namespace QtLP_Private {
#include "qtlockedfile.cpp"
#if defined(Q_OS_WIN)
#include "qtlockedfile_win.cpp"
#else
#include "qtlockedfile_unix.cpp"
#endif
}
const char* QtLocalPeer::ack = "ack";
QtLocalPeer::QtLocalPeer(QObject* parent, const QString &appId)
: QObject(parent), id(appId)
{
QString prefix = id;
if (id.isEmpty()) {
id = QCoreApplication::applicationFilePath();
#if defined(Q_OS_WIN)
id = id.toLower();
#endif
prefix = id.section(QLatin1Char('/'), -1);
}
prefix.remove(QRegularExpression ("[^a-zA-Z]"));
prefix.truncate(6);
QByteArray idc = id.toUtf8();
quint16 idNum = qChecksum(idc.constData(), idc.size());
socketName = QLatin1String("qtsingleapp-") + prefix
+ QLatin1Char('-') + QString::number(idNum, 16);
#if defined(Q_OS_WIN)
if (!pProcessIdToSessionId) {
QLibrary lib("kernel32");
pProcessIdToSessionId = (PProcessIdToSessionId)lib.resolve("ProcessIdToSessionId");
}
if (pProcessIdToSessionId) {
DWORD sessionId = 0;
pProcessIdToSessionId(GetCurrentProcessId(), &sessionId);
socketName += QLatin1Char('-') + QString::number(sessionId, 16);
}
#else
socketName += QLatin1Char('-') + QString::number(::getuid(), 16);
#endif
server = new QLocalServer(this);
QString lockName = QDir(QDir::tempPath()).absolutePath()
+ QLatin1Char('/') + socketName
+ QLatin1String("-lockfile");
lockFile.setFileName(lockName);
lockFile.open(QIODevice::ReadWrite);
}
bool QtLocalPeer::isClient()
{
if (lockFile.isLocked())
return false;
if (!lockFile.lock(QtLP_Private::QtLockedFile::WriteLock, false))
return true;
bool res = server->listen(socketName);
#if defined(Q_OS_UNIX) && (QT_VERSION >= QT_VERSION_CHECK(4,5,0))
// ### Workaround
if (!res && server->serverError() == QAbstractSocket::AddressInUseError) {
QFile::remove(QDir::cleanPath(QDir::tempPath())+QLatin1Char('/')+socketName);
res = server->listen(socketName);
}
#endif
if (!res)
qWarning("QtSingleCoreApplication: listen on local socket failed, %s", qPrintable(server->errorString()));
QObject::connect(server, SIGNAL(newConnection()), SLOT(receiveConnection()));
return false;
}
bool QtLocalPeer::sendMessage(const QString &message, int timeout)
{
if (!isClient())
return false;
QLocalSocket socket;
bool connOk = false;
for(int i = 0; i < 2; i++) {
// Try twice, in case the other instance is just starting up
socket.connectToServer(socketName);
connOk = socket.waitForConnected(timeout/2);
if (connOk || i)
break;
int ms = 250;
#if defined(Q_OS_WIN)
Sleep(DWORD(ms));
#else
struct timespec ts = { ms / 1000, (ms % 1000) * 1000 * 1000 };
nanosleep(&ts, NULL);
#endif
}
if (!connOk)
return false;
QByteArray uMsg(message.toUtf8());
QDataStream ds(&socket);
ds.writeBytes(uMsg.constData(), uMsg.size());
bool res = socket.waitForBytesWritten(timeout);
if (res) {
res &= socket.waitForReadyRead(timeout); // wait for ack
if (res)
res &= (socket.read(qstrlen(ack)) == ack);
}
return res;
}
void QtLocalPeer::receiveConnection()
{
QLocalSocket* socket = server->nextPendingConnection();
if (!socket)
return;
while (socket->bytesAvailable() < (int)sizeof(quint32))
socket->waitForReadyRead();
QDataStream ds(socket);
QByteArray uMsg;
quint32 remaining;
ds >> remaining;
uMsg.resize(remaining);
int got = 0;
char* uMsgBuf = uMsg.data();
do {
got = ds.readRawData(uMsgBuf, remaining);
remaining -= got;
uMsgBuf += got;
} while (remaining && got >= 0 && socket->waitForReadyRead(2000));
if (got < 0) {
qWarning("QtLocalPeer: Message reception failed %s", socket->errorString().toLatin1().constData());
delete socket;
return;
}
QString message(QString::fromUtf8(uMsg));
socket->write(ack, qstrlen(ack));
socket->waitForBytesWritten(1000);
socket->waitForDisconnected(1000); // make sure client reads ack
delete socket;
emit messageReceived(message); //### (might take a long time to return)
}

View File

@ -0,0 +1,77 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTLOCALPEER_H
#define QTLOCALPEER_H
#include <QLocalServer>
#include <QLocalSocket>
#include <QDir>
#include "qtlockedfile.h"
class QtLocalPeer : public QObject
{
Q_OBJECT
public:
QtLocalPeer(QObject *parent = 0, const QString &appId = QString());
bool isClient();
bool sendMessage(const QString &message, int timeout);
QString applicationId() const
{ return id; }
Q_SIGNALS:
void messageReceived(const QString &message);
protected Q_SLOTS:
void receiveConnection();
protected:
QString id;
QString socketName;
QLocalServer* server;
QtLP_Private::QtLockedFile lockFile;
private:
static const char* ack;
};
#endif // QTLOCALPEER_H

View File

@ -0,0 +1,193 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtlockedfile.h"
/*!
\class QtLockedFile
\brief The QtLockedFile class extends QFile with advisory locking
functions.
A file may be locked in read or write mode. Multiple instances of
\e QtLockedFile, created in multiple processes running on the same
machine, may have a file locked in read mode. Exactly one instance
may have it locked in write mode. A read and a write lock cannot
exist simultaneously on the same file.
The file locks are advisory. This means that nothing prevents
another process from manipulating a locked file using QFile or
file system functions offered by the OS. Serialization is only
guaranteed if all processes that access the file use
QLockedFile. Also, while holding a lock on a file, a process
must not open the same file again (through any API), or locks
can be unexpectedly lost.
The lock provided by an instance of \e QtLockedFile is released
whenever the program terminates. This is true even when the
program crashes and no destructors are called.
*/
/*! \enum QtLockedFile::LockMode
This enum describes the available lock modes.
\value ReadLock A read lock.
\value WriteLock A write lock.
\value NoLock Neither a read lock nor a write lock.
*/
/*!
Constructs an unlocked \e QtLockedFile object. This constructor
behaves in the same way as \e QFile::QFile().
\sa QFile::QFile()
*/
QtLockedFile::QtLockedFile()
: QFile()
{
#ifdef Q_OS_WIN
wmutex = 0;
rmutex = 0;
#endif
m_lock_mode = NoLock;
}
/*!
Constructs an unlocked QtLockedFile object with file \a name. This
constructor behaves in the same way as \e QFile::QFile(const
QString&).
\sa QFile::QFile()
*/
QtLockedFile::QtLockedFile(const QString &name)
: QFile(name)
{
#ifdef Q_OS_WIN
wmutex = 0;
rmutex = 0;
#endif
m_lock_mode = NoLock;
}
/*!
Opens the file in OpenMode \a mode.
This is identical to QFile::open(), with the one exception that the
Truncate mode flag is disallowed. Truncation would conflict with the
advisory file locking, since the file would be modified before the
write lock is obtained. If truncation is required, use resize(0)
after obtaining the write lock.
Returns true if successful; otherwise false.
\sa QFile::open(), QFile::resize()
*/
bool QtLockedFile::open(OpenMode mode)
{
if (mode & QIODevice::Truncate) {
qWarning("QtLockedFile::open(): Truncate mode not allowed.");
return false;
}
return QFile::open(mode);
}
/*!
Returns \e true if this object has a in read or write lock;
otherwise returns \e false.
\sa lockMode()
*/
bool QtLockedFile::isLocked() const
{
return m_lock_mode != NoLock;
}
/*!
Returns the type of lock currently held by this object, or \e
QtLockedFile::NoLock.
\sa isLocked()
*/
QtLockedFile::LockMode QtLockedFile::lockMode() const
{
return m_lock_mode;
}
/*!
\fn bool QtLockedFile::lock(LockMode mode, bool block = true)
Obtains a lock of type \a mode. The file must be opened before it
can be locked.
If \a block is true, this function will block until the lock is
aquired. If \a block is false, this function returns \e false
immediately if the lock cannot be aquired.
If this object already has a lock of type \a mode, this function
returns \e true immediately. If this object has a lock of a
different type than \a mode, the lock is first released and then a
new lock is obtained.
This function returns \e true if, after it executes, the file is
locked by this object, and \e false otherwise.
\sa unlock(), isLocked(), lockMode()
*/
/*!
\fn bool QtLockedFile::unlock()
Releases a lock.
If the object has no lock, this function returns immediately.
This function returns \e true if, after it executes, the file is
not locked by this object, and \e false otherwise.
\sa lock(), isLocked(), lockMode()
*/
/*!
\fn QtLockedFile::~QtLockedFile()
Destroys the \e QtLockedFile object. If any locks were held, they
are released.
*/

View File

@ -0,0 +1,97 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTLOCKEDFILE_H
#define QTLOCKEDFILE_H
#include <QFile>
#ifdef Q_OS_WIN
#include <QVector>
#endif
#if defined(Q_OS_WIN)
# if !defined(QT_QTLOCKEDFILE_EXPORT) && !defined(QT_QTLOCKEDFILE_IMPORT)
# define QT_QTLOCKEDFILE_EXPORT
# elif defined(QT_QTLOCKEDFILE_IMPORT)
# if defined(QT_QTLOCKEDFILE_EXPORT)
# undef QT_QTLOCKEDFILE_EXPORT
# endif
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllimport)
# elif defined(QT_QTLOCKEDFILE_EXPORT)
# undef QT_QTLOCKEDFILE_EXPORT
# define QT_QTLOCKEDFILE_EXPORT __declspec(dllexport)
# endif
#else
# define QT_QTLOCKEDFILE_EXPORT
#endif
namespace QtLP_Private {
class QT_QTLOCKEDFILE_EXPORT QtLockedFile : public QFile
{
public:
enum LockMode { NoLock = 0, ReadLock, WriteLock };
QtLockedFile();
QtLockedFile(const QString &name);
~QtLockedFile();
bool open(OpenMode mode);
bool lock(LockMode mode, bool block = true);
bool unlock();
bool isLocked() const;
LockMode lockMode() const;
private:
#ifdef Q_OS_WIN
Qt::HANDLE wmutex;
Qt::HANDLE rmutex;
QVector<Qt::HANDLE> rmutexes;
QString mutexname;
Qt::HANDLE getMutexHandle(int idx, bool doCreate);
bool waitMutex(Qt::HANDLE mutex, bool doBlock);
#endif
LockMode m_lock_mode;
};
}
#endif

View File

@ -0,0 +1,115 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include "qtlockedfile.h"
bool QtLockedFile::lock(LockMode mode, bool block)
{
if (!isOpen()) {
qWarning("QtLockedFile::lock(): file is not opened");
return false;
}
if (mode == NoLock)
return unlock();
if (mode == m_lock_mode)
return true;
if (m_lock_mode != NoLock)
unlock();
struct flock fl;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = (mode == ReadLock) ? F_RDLCK : F_WRLCK;
int cmd = block ? F_SETLKW : F_SETLK;
int ret = fcntl(handle(), cmd, &fl);
if (ret == -1) {
if (errno != EINTR && errno != EAGAIN)
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
return false;
}
m_lock_mode = mode;
return true;
}
bool QtLockedFile::unlock()
{
if (!isOpen()) {
qWarning("QtLockedFile::unlock(): file is not opened");
return false;
}
if (!isLocked())
return true;
struct flock fl;
fl.l_whence = SEEK_SET;
fl.l_start = 0;
fl.l_len = 0;
fl.l_type = F_UNLCK;
int ret = fcntl(handle(), F_SETLKW, &fl);
if (ret == -1) {
qWarning("QtLockedFile::lock(): fcntl: %s", strerror(errno));
return false;
}
m_lock_mode = NoLock;
return true;
}
QtLockedFile::~QtLockedFile()
{
if (isOpen())
unlock();
}

View File

@ -0,0 +1,211 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtlockedfile.h"
#include <qt_windows.h>
#include <QFileInfo>
#define MUTEX_PREFIX "QtLockedFile mutex "
// Maximum number of concurrent read locks. Must not be greater than MAXIMUM_WAIT_OBJECTS
#define MAX_READERS MAXIMUM_WAIT_OBJECTS
#if QT_VERSION >= 0x050000
#define QT_WA(unicode, ansi) unicode
#endif
Qt::HANDLE QtLockedFile::getMutexHandle(int idx, bool doCreate)
{
if (mutexname.isEmpty()) {
QFileInfo fi(*this);
mutexname = QString::fromLatin1(MUTEX_PREFIX)
+ fi.absoluteFilePath().toLower();
}
QString mname(mutexname);
if (idx >= 0)
mname += QString::number(idx);
Qt::HANDLE mutex;
if (doCreate) {
QT_WA( { mutex = CreateMutexW(NULL, FALSE, (TCHAR*)mname.utf16()); },
{ mutex = CreateMutexA(NULL, FALSE, mname.toLocal8Bit().constData()); } );
if (!mutex) {
qErrnoWarning("QtLockedFile::lock(): CreateMutex failed");
return 0;
}
}
else {
QT_WA( { mutex = OpenMutexW(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, (TCHAR*)mname.utf16()); },
{ mutex = OpenMutexA(SYNCHRONIZE | MUTEX_MODIFY_STATE, FALSE, mname.toLocal8Bit().constData()); } );
if (!mutex) {
if (GetLastError() != ERROR_FILE_NOT_FOUND)
qErrnoWarning("QtLockedFile::lock(): OpenMutex failed");
return 0;
}
}
return mutex;
}
bool QtLockedFile::waitMutex(Qt::HANDLE mutex, bool doBlock)
{
Q_ASSERT(mutex);
DWORD res = WaitForSingleObject(mutex, doBlock ? INFINITE : 0);
switch (res) {
case WAIT_OBJECT_0:
case WAIT_ABANDONED:
return true;
break;
case WAIT_TIMEOUT:
break;
default:
qErrnoWarning("QtLockedFile::lock(): WaitForSingleObject failed");
}
return false;
}
bool QtLockedFile::lock(LockMode mode, bool block)
{
if (!isOpen()) {
qWarning("QtLockedFile::lock(): file is not opened");
return false;
}
if (mode == NoLock)
return unlock();
if (mode == m_lock_mode)
return true;
if (m_lock_mode != NoLock)
unlock();
if (!wmutex && !(wmutex = getMutexHandle(-1, true)))
return false;
if (!waitMutex(wmutex, block))
return false;
if (mode == ReadLock) {
int idx = 0;
for (; idx < MAX_READERS; idx++) {
rmutex = getMutexHandle(idx, false);
if (!rmutex || waitMutex(rmutex, false))
break;
CloseHandle(rmutex);
}
bool ok = true;
if (idx >= MAX_READERS) {
qWarning("QtLockedFile::lock(): too many readers");
rmutex = 0;
ok = false;
}
else if (!rmutex) {
rmutex = getMutexHandle(idx, true);
if (!rmutex || !waitMutex(rmutex, false))
ok = false;
}
if (!ok && rmutex) {
CloseHandle(rmutex);
rmutex = 0;
}
ReleaseMutex(wmutex);
if (!ok)
return false;
}
else {
Q_ASSERT(rmutexes.isEmpty());
for (int i = 0; i < MAX_READERS; i++) {
Qt::HANDLE mutex = getMutexHandle(i, false);
if (mutex)
rmutexes.append(mutex);
}
if (rmutexes.size()) {
DWORD res = WaitForMultipleObjects(rmutexes.size(), rmutexes.constData(),
TRUE, block ? INFINITE : 0);
if (res != WAIT_OBJECT_0 && res != WAIT_ABANDONED) {
if (res != WAIT_TIMEOUT)
qErrnoWarning("QtLockedFile::lock(): WaitForMultipleObjects failed");
m_lock_mode = WriteLock; // trick unlock() to clean up - semiyucky
unlock();
return false;
}
}
}
m_lock_mode = mode;
return true;
}
bool QtLockedFile::unlock()
{
if (!isOpen()) {
qWarning("QtLockedFile::unlock(): file is not opened");
return false;
}
if (!isLocked())
return true;
if (m_lock_mode == ReadLock) {
ReleaseMutex(rmutex);
CloseHandle(rmutex);
rmutex = 0;
}
else {
foreach(Qt::HANDLE mutex, rmutexes) {
ReleaseMutex(mutex);
CloseHandle(mutex);
}
rmutexes.clear();
ReleaseMutex(wmutex);
}
m_lock_mode = QtLockedFile::NoLock;
return true;
}
QtLockedFile::~QtLockedFile()
{
if (isOpen())
unlock();
if (wmutex)
CloseHandle(wmutex);
}

View File

@ -0,0 +1,356 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtsingleapplication.h"
#include "qtlocalpeer.h"
#include <QWidget>
/*!
\class QtSingleApplication qtsingleapplication.h
\brief The QtSingleApplication class provides an API to detect and
communicate with running instances of an application.
This class allows you to create applications where only one
instance should be running at a time. I.e., if the user tries to
launch another instance, the already running instance will be
activated instead. Another usecase is a client-server system,
where the first started instance will assume the role of server,
and the later instances will act as clients of that server.
By default, the full path of the executable file is used to
determine whether two processes are instances of the same
application. You can also provide an explicit identifier string
that will be compared instead.
The application should create the QtSingleApplication object early
in the startup phase, and call isRunning() to find out if another
instance of this application is already running. If isRunning()
returns false, it means that no other instance is running, and
this instance has assumed the role as the running instance. In
this case, the application should continue with the initialization
of the application user interface before entering the event loop
with exec(), as normal.
The messageReceived() signal will be emitted when the running
application receives messages from another instance of the same
application. When a message is received it might be helpful to the
user to raise the application so that it becomes visible. To
facilitate this, QtSingleApplication provides the
setActivationWindow() function and the activateWindow() slot.
If isRunning() returns true, another instance is already
running. It may be alerted to the fact that another instance has
started by using the sendMessage() function. Also data such as
startup parameters (e.g. the name of the file the user wanted this
new instance to open) can be passed to the running instance with
this function. Then, the application should terminate (or enter
client mode).
If isRunning() returns true, but sendMessage() fails, that is an
indication that the running instance is frozen.
Here's an example that shows how to convert an existing
application to use QtSingleApplication. It is very simple and does
not make use of all QtSingleApplication's functionality (see the
examples for that).
\code
// Original
int main(int argc, char **argv)
{
QApplication app(argc, argv);
MyMainWidget mmw;
mmw.show();
return app.exec();
}
// Single instance
int main(int argc, char **argv)
{
QtSingleApplication app(argc, argv);
if (app.isRunning())
return !app.sendMessage(someDataString);
MyMainWidget mmw;
app.setActivationWindow(&mmw);
mmw.show();
return app.exec();
}
\endcode
Once this QtSingleApplication instance is destroyed (normally when
the process exits or crashes), when the user next attempts to run the
application this instance will not, of course, be encountered. The
next instance to call isRunning() or sendMessage() will assume the
role as the new running instance.
For console (non-GUI) applications, QtSingleCoreApplication may be
used instead of this class, to avoid the dependency on the QtGui
library.
\sa QtSingleCoreApplication
*/
void QtSingleApplication::sysInit(const QString &appId)
{
actWin = 0;
peer = new QtLocalPeer(this, appId);
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
}
/*!
Creates a QtSingleApplication object. The application identifier
will be QCoreApplication::applicationFilePath(). \a argc, \a
argv, and \a GUIenabled are passed on to the QAppliation constructor.
If you are creating a console application (i.e. setting \a
GUIenabled to false), you may consider using
QtSingleCoreApplication instead.
*/
QtSingleApplication::QtSingleApplication(int &argc, char **argv, bool GUIenabled)
: QApplication(argc, argv, GUIenabled)
{
sysInit();
}
/*!
Creates a QtSingleApplication object with the application
identifier \a appId. \a argc and \a argv are passed on to the
QAppliation constructor.
*/
QtSingleApplication::QtSingleApplication(const QString &appId, int &argc, char **argv)
: QApplication(argc, argv),
peer(nullptr)
{
sysInit(appId);
}
QtSingleApplication::~QtSingleApplication()
{
if (peer)
{
delete peer;
}
}
#if QT_VERSION < 0x050000
/*!
Creates a QtSingleApplication object. The application identifier
will be QCoreApplication::applicationFilePath(). \a argc, \a
argv, and \a type are passed on to the QAppliation constructor.
*/
QtSingleApplication::QtSingleApplication(int &argc, char **argv, Type type)
: QApplication(argc, argv, type)
{
sysInit();
}
# if defined(Q_WS_X11)
/*!
Special constructor for X11, ref. the documentation of
QApplication's corresponding constructor. The application identifier
will be QCoreApplication::applicationFilePath(). \a dpy, \a visual,
and \a cmap are passed on to the QApplication constructor.
*/
QtSingleApplication::QtSingleApplication(Display* dpy, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, visual, cmap)
{
sysInit();
}
/*!
Special constructor for X11, ref. the documentation of
QApplication's corresponding constructor. The application identifier
will be QCoreApplication::applicationFilePath(). \a dpy, \a argc, \a
argv, \a visual, and \a cmap are passed on to the QApplication
constructor.
*/
QtSingleApplication::QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, argc, argv, visual, cmap)
{
sysInit();
}
/*!
Special constructor for X11, ref. the documentation of
QApplication's corresponding constructor. The application identifier
will be \a appId. \a dpy, \a argc, \a
argv, \a visual, and \a cmap are passed on to the QApplication
constructor.
*/
QtSingleApplication::QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual, Qt::HANDLE cmap)
: QApplication(dpy, argc, argv, visual, cmap)
{
sysInit(appId);
}
# endif // Q_WS_X11
#endif // QT_VERSION < 0x050000
/*!
Returns true if another instance of this application is running;
otherwise false.
This function does not find instances of this application that are
being run by a different user (on Windows: that are running in
another session).
\sa sendMessage()
*/
bool QtSingleApplication::isRunning()
{
return peer->isClient();
}
/*!
Tries to send the text \a message to the currently running
instance. The QtSingleApplication object in the running instance
will emit the messageReceived() signal when it receives the
message.
This function returns true if the message has been sent to, and
processed by, the current instance. If there is no instance
currently running, or if the running instance fails to process the
message within \a timeout milliseconds, this function return false.
\sa isRunning(), messageReceived()
*/
bool QtSingleApplication::sendMessage(const QString &message, int timeout)
{
return peer->sendMessage(message, timeout);
}
/*!
Returns the application identifier. Two processes with the same
identifier will be regarded as instances of the same application.
*/
QString QtSingleApplication::id() const
{
return peer->applicationId();
}
/*!
Sets the activation window of this application to \a aw. The
activation window is the widget that will be activated by
activateWindow(). This is typically the application's main window.
If \a activateOnMessage is true (the default), the window will be
activated automatically every time a message is received, just prior
to the messageReceived() signal being emitted.
\sa activateWindow(), messageReceived()
*/
void QtSingleApplication::setActivationWindow(QWidget* aw, bool activateOnMessage)
{
actWin = aw;
if (activateOnMessage)
connect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));
else
disconnect(peer, SIGNAL(messageReceived(const QString&)), this, SLOT(activateWindow()));
}
/*!
Returns the applications activation window if one has been set by
calling setActivationWindow(), otherwise returns 0.
\sa setActivationWindow()
*/
QWidget* QtSingleApplication::activationWindow() const
{
return actWin;
}
/*!
De-minimizes, raises, and activates this application's activation window.
This function does nothing if no activation window has been set.
This is a convenience function to show the user that this
application instance has been activated when he has tried to start
another instance.
This function should typically be called in response to the
messageReceived() signal. By default, that will happen
automatically, if an activation window has been set.
\sa setActivationWindow(), messageReceived(), initialize()
*/
void QtSingleApplication::activateWindow()
{
if (actWin) {
actWin->setWindowState(actWin->windowState() & ~Qt::WindowMinimized);
actWin->raise();
actWin->activateWindow();
}
}
/*!
\fn void QtSingleApplication::messageReceived(const QString& message)
This signal is emitted when the current instance receives a \a
message from another instance of this application.
\sa sendMessage(), setActivationWindow(), activateWindow()
*/
/*!
\fn void QtSingleApplication::initialize(bool dummy = true)
\obsolete
*/

View File

@ -0,0 +1,107 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTSINGLEAPPLICATION_H
#define QTSINGLEAPPLICATION_H
#include <QApplication>
class QtLocalPeer;
#if defined(Q_OS_WIN)
# if !defined(QT_QTSINGLEAPPLICATION_EXPORT) && !defined(QT_QTSINGLEAPPLICATION_IMPORT)
# define QT_QTSINGLEAPPLICATION_EXPORT
# elif defined(QT_QTSINGLEAPPLICATION_IMPORT)
# if defined(QT_QTSINGLEAPPLICATION_EXPORT)
# undef QT_QTSINGLEAPPLICATION_EXPORT
# endif
# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllimport)
# elif defined(QT_QTSINGLEAPPLICATION_EXPORT)
# undef QT_QTSINGLEAPPLICATION_EXPORT
# define QT_QTSINGLEAPPLICATION_EXPORT __declspec(dllexport)
# endif
#else
# define QT_QTSINGLEAPPLICATION_EXPORT
#endif
class QT_QTSINGLEAPPLICATION_EXPORT QtSingleApplication : public QApplication
{
Q_OBJECT
public:
QtSingleApplication(int &argc, char **argv, bool GUIenabled = true);
QtSingleApplication(const QString &id, int &argc, char **argv);
virtual ~QtSingleApplication();
#if QT_VERSION < 0x050000
QtSingleApplication(int &argc, char **argv, Type type);
# if defined(Q_WS_X11)
QtSingleApplication(Display* dpy, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
QtSingleApplication(Display *dpy, int &argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE cmap= 0);
QtSingleApplication(Display* dpy, const QString &appId, int argc, char **argv, Qt::HANDLE visual = 0, Qt::HANDLE colormap = 0);
# endif // Q_WS_X11
#endif // QT_VERSION < 0x050000
bool isRunning();
QString id() const;
void setActivationWindow(QWidget* aw, bool activateOnMessage = true);
QWidget* activationWindow() const;
// Obsolete:
void initialize(bool dummy = true)
{ isRunning(); Q_UNUSED(dummy) }
public Q_SLOTS:
bool sendMessage(const QString &message, int timeout = 5000);
void activateWindow();
Q_SIGNALS:
void messageReceived(const QString &message);
private:
void sysInit(const QString &appId = QString());
QtLocalPeer *peer;
QWidget *actWin;
};
#endif // QTSINGLEAPPLICATION_H

View File

@ -0,0 +1,17 @@
#include(../common.pri)
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
QT *= network
greaterThan(QT_MAJOR_VERSION, 4): QT *= widgets
qtsingleapplication-uselib:!qtsingleapplication-buildlib {
LIBS += -L$$QTSINGLEAPPLICATION_LIBDIR -l$$QTSINGLEAPPLICATION_LIBNAME
} else {
SOURCES += $$PWD/qtsingleapplication.cpp $$PWD/qtlocalpeer.cpp
HEADERS += $$PWD/qtsingleapplication.h $$PWD/qtlocalpeer.h
}
win32 {
contains(TEMPLATE, lib):contains(CONFIG, shared):DEFINES += QT_QTSINGLEAPPLICATION_EXPORT
else:qtsingleapplication-uselib:DEFINES += QT_QTSINGLEAPPLICATION_IMPORT
}

View File

@ -0,0 +1,149 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qtsinglecoreapplication.h"
#include "qtlocalpeer.h"
/*!
\class QtSingleCoreApplication qtsinglecoreapplication.h
\brief A variant of the QtSingleApplication class for non-GUI applications.
This class is a variant of QtSingleApplication suited for use in
console (non-GUI) applications. It is an extension of
QCoreApplication (instead of QApplication). It does not require
the QtGui library.
The API and usage is identical to QtSingleApplication, except that
functions relating to the "activation window" are not present, for
obvious reasons. Please refer to the QtSingleApplication
documentation for explanation of the usage.
A QtSingleCoreApplication instance can communicate to a
QtSingleApplication instance if they share the same application
id. Hence, this class can be used to create a light-weight
command-line tool that sends commands to a GUI application.
\sa QtSingleApplication
*/
/*!
Creates a QtSingleCoreApplication object. The application identifier
will be QCoreApplication::applicationFilePath(). \a argc and \a
argv are passed on to the QCoreAppliation constructor.
*/
QtSingleCoreApplication::QtSingleCoreApplication(int &argc, char **argv)
: QCoreApplication(argc, argv)
{
peer = new QtLocalPeer(this);
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
}
/*!
Creates a QtSingleCoreApplication object with the application
identifier \a appId. \a argc and \a argv are passed on to the
QCoreAppliation constructor.
*/
QtSingleCoreApplication::QtSingleCoreApplication(const QString &appId, int &argc, char **argv)
: QCoreApplication(argc, argv)
{
peer = new QtLocalPeer(this, appId);
connect(peer, SIGNAL(messageReceived(const QString&)), SIGNAL(messageReceived(const QString&)));
}
/*!
Returns true if another instance of this application is running;
otherwise false.
This function does not find instances of this application that are
being run by a different user (on Windows: that are running in
another session).
\sa sendMessage()
*/
bool QtSingleCoreApplication::isRunning()
{
return peer->isClient();
}
/*!
Tries to send the text \a message to the currently running
instance. The QtSingleCoreApplication object in the running instance
will emit the messageReceived() signal when it receives the
message.
This function returns true if the message has been sent to, and
processed by, the current instance. If there is no instance
currently running, or if the running instance fails to process the
message within \a timeout milliseconds, this function return false.
\sa isRunning(), messageReceived()
*/
bool QtSingleCoreApplication::sendMessage(const QString &message, int timeout)
{
return peer->sendMessage(message, timeout);
}
/*!
Returns the application identifier. Two processes with the same
identifier will be regarded as instances of the same application.
*/
QString QtSingleCoreApplication::id() const
{
return peer->applicationId();
}
/*!
\fn void QtSingleCoreApplication::messageReceived(const QString& message)
This signal is emitted when the current instance receives a \a
message from another instance of this application.
\sa sendMessage()
*/

View File

@ -0,0 +1,71 @@
/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the Qt Solutions component.
**
** $QT_BEGIN_LICENSE:BSD$
** You may use this file under the terms of the BSD license as follows:
**
** "Redistribution and use in source and binary forms, with or without
** modification, are permitted provided that the following conditions are
** met:
** * Redistributions of source code must retain the above copyright
** notice, this list of conditions and the following disclaimer.
** * Redistributions in binary form must reproduce the above copyright
** notice, this list of conditions and the following disclaimer in
** the documentation and/or other materials provided with the
** distribution.
** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
** of its contributors may be used to endorse or promote products derived
** from this software without specific prior written permission.
**
**
** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QTSINGLECOREAPPLICATION_H
#define QTSINGLECOREAPPLICATION_H
#include <QCoreApplication>
class QtLocalPeer;
class QtSingleCoreApplication : public QCoreApplication
{
Q_OBJECT
public:
QtSingleCoreApplication(int &argc, char **argv);
QtSingleCoreApplication(const QString &id, int &argc, char **argv);
bool isRunning();
QString id() const;
public Q_SLOTS:
bool sendMessage(const QString &message, int timeout = 5000);
Q_SIGNALS:
void messageReceived(const QString &message);
private:
QtLocalPeer* peer;
};
#endif // QTSINGLECOREAPPLICATION_H

View File

@ -0,0 +1,10 @@
INCLUDEPATH += $$PWD
DEPENDPATH += $$PWD
HEADERS += $$PWD/qtsinglecoreapplication.h $$PWD/qtlocalpeer.h
SOURCES += $$PWD/qtsinglecoreapplication.cpp $$PWD/qtlocalpeer.cpp
QT *= network
win32:contains(TEMPLATE, lib):contains(CONFIG, shared) {
DEFINES += QT_QTSINGLECOREAPPLICATION_EXPORT=__declspec(dllexport)
}

View File

@ -0,0 +1,22 @@
#include "datafetcher.h"
#include "globalparameters.h"
DataFetcher::DataFetcher()
{
}
DataFetcher::~DataFetcher()
{
}
bool DataFetcher::Fetch(TableData& tbl_data)
{
return true;
}
int DataFetcher::VerifyStatus()
{
return STATUS_NORMAL;
}

View File

@ -0,0 +1,19 @@
#ifndef DATAFETCHER_H
#define DATAFETCHER_H
#include "globalparameters.h"
class DataFetcher
{
public:
DataFetcher();
virtual ~DataFetcher();
public:
virtual bool Fetch(TableData& tbl_data);
protected:
int VerifyStatus();
};
#endif // DATAFETCHER_H

View File

@ -0,0 +1,202 @@
#include "devicepropertypage.h"
#include <QGuiApplication>
#include <QTimer>
#include <QMessageBox>
#include <QTableView>
#include <QVBoxLayout>
#include <QPushButton>
#include <QScrollBar>
#include <QHeaderView>
#include "globalparameters.h"
#include "mytablemodel.h"
DevicePropertyPage::DevicePropertyPage(QWidget *parent) :
QWidget(parent),m_pTableView(nullptr),m_pButton(nullptr)
{
InitializeTable();
m_pTimer = new QTimer(this);
connect(m_pTimer, SIGNAL(timeout()), this, SLOT(handleTimeout()));
//m_pTimer->start(AppData::getInstance()->nTimeOut);
}
DevicePropertyPage::~DevicePropertyPage()
{
}
void DevicePropertyPage::handleTimeout()
{
if(m_pTimer->isActive())
{
m_pTimer->stop();
Refresh();
int nInterval = 5000;
m_pTimer->start(nInterval*1000);
}
}
void DevicePropertyPage::InitializeTableView(MyTableModel *model, QTableView *tableView)
{
//设置tableview的model
model->setHeadData(AppData::getInstance()->lstDataTableHeaderText);
tableView->setModel(model);
QHeaderView* pHeaderView = tableView->horizontalHeader();
//pHeaderView->setStyleSheet("QHeaderView::section {color: black;padding-left: 4px;border: 1px solid #6c6c6c;}");
pHeaderView->setStyleSheet("QHeaderView::section{background:lightgray;}");
// pHeaderView->setSectionResizeMode(QHeaderView::Stretch); //Stretch
pHeaderView->setHidden(false); //false 显示行号列 true Hide
//pHeaderView->setVisible(true);
//pHeaderView->setFixedHeight(40);
//点击表时不对表头行光亮(获取焦点)
pHeaderView->setHighlightSections(false);
// pHeaderView->setDefaultSectionSize(200);
// //设置表头字体加粗
// QFont font = pHeaderView->font();
// font.setBold(true);
// pHeaderView->setFont(font);
//设置表头字体
pHeaderView->setFont(QFont("Arial", 12));
// 设置表头列宽自动调整
for (int i = 0; i < model->columnCount(); ++i)
{
pHeaderView->setSectionResizeMode(i, QHeaderView::Interactive);
}
// 允许用户通过拖动表头边缘调整列宽
//pHeaderView->setSectionResizeMode(QHeaderView::Interactive);
tableView->verticalHeader()->setDefaultSectionSize(30); //行高
tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
tableView->setSelectionMode(QAbstractItemView::SingleSelection);
tableView->setAlternatingRowColors(true);
tableView->setTextElideMode(Qt::ElideMiddle);
//所有单元格的字体 设置成一样
tableView->setFont(QFont("Arial", 9));
//设置表格数据区内的所有单元格都不允许编辑
tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
#if 1
//设置列宽
int base = 120; //w / (model->columnCount()-1);
tableView->setColumnWidth(0,base-30);
tableView->setColumnWidth(1,base*3+40);
tableView->setColumnWidth(2,base);
tableView->setColumnWidth(3,base-40);
tableView->setColumnWidth(4,base+50);
#endif
tableView->show();
}
void DevicePropertyPage::InitializeTable()
{
m_myModel = new MyTableModel(this);
m_myModel->setHeadData(AppData::getInstance()->lstDataTableHeaderText);
m_pTableView = new QTableView(this);
m_pButton = new QPushButton(tr("Refresh"), this);
// 创建主布局
QVBoxLayout *mainLayout = new QVBoxLayout(this);
InitializeTableView(m_myModel,m_pTableView);
mainLayout->addWidget(m_pTableView);
// 创建一个水平布局来包含按钮
QHBoxLayout *buttonLayout = new QHBoxLayout();
buttonLayout->addStretch(); // 让按钮保持在右侧
buttonLayout->addWidget(m_pButton);
buttonLayout->setContentsMargins(0, 0, 0, 0); // 取消按钮的边距
// 将表格视图和按钮布局添加到主布局
mainLayout->addLayout(buttonLayout);
mainLayout->setContentsMargins(0, 0, 0, 0); // 取消主布局的边距
mainLayout->setSpacing(10); // 取消布局间的间距
// 设置固定大小和位置的按钮
m_pButton->setFixedSize(100, 30); // 设置按钮的固定大小
// 连接信号和槽
connect(m_pTableView, &QTableView::doubleClicked, this, &DevicePropertyPage::onTableViewDoubleClicked);
connect(m_pButton, &QPushButton::clicked, this, &DevicePropertyPage::onButtonClicked);
setLayout(mainLayout);
}
void DevicePropertyPage::Refresh()
{
QGuiApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
TableData tbl_data;
if (Fetch(tbl_data))
{
m_myModel->setModelData(tbl_data);
}
QGuiApplication::restoreOverrideCursor();
}
void DevicePropertyPage::setBaseType(unsigned int base, unsigned int mask)
{
filterBaseType = base;
mask_code = mask;
}
void DevicePropertyPage::onButtonClicked()
{
m_pTimer->stop();
Refresh();
}
void DevicePropertyPage::onTableViewDoubleClicked(const QModelIndex &index)
{
//QAbstractItemModel *model=ui->tableView->model();
MyTableModel *model = (MyTableModel *)m_pTableView->model();
QModelIndex mindex = model->index(index.row(),7); //index.row()为算选择的行号。7为所选中行的第8列。。
QVariant datatemp=model->data(mindex);
}
void DevicePropertyPage::resizeEvent(QResizeEvent *event)
{
QWidget::resizeEvent(event);
#if 0
// 获取当前QTableView的总宽度
int currentTotalWidth = m_pTableView->viewport()->width();
// 计算总的初始宽度
int initialTotalWidth = 0;
for (int width : columnWidths) {
initialTotalWidth += width;
}
// 计算比例因子
double scaleFactor = static_cast<double>(currentTotalWidth) / initialTotalWidth;
// 重新设置列宽,按比例调整
for (int i = 0; i < columnWidths.size(); ++i) {
int newWidth = static_cast<int>(columnWidths[i] * scaleFactor);
m_pTableView->setColumnWidth(i, newWidth);
}
#endif
}

View File

@ -0,0 +1,54 @@
#ifndef DEVICEPROPERTYPAGE_H
#define DEVICEPROPERTYPAGE_H
#pragma execution_character_set("utf-8")
#include <QWidget>
#include "datafetcher.h"
class MyTableModel;
class QTimer;
class QTableView;
class QPushButton;
class DevicePropertyPage : public QWidget,public DataFetcher
{
Q_OBJECT
public:
explicit DevicePropertyPage(QWidget *parent = nullptr);
~DevicePropertyPage();
void setBaseType(unsigned int base,unsigned int mask);
void InitializeTable();
public slots:
void handleTimeout(); //超时处理函数
private:
QTimer *m_pTimer;
private:
MyTableModel* m_myModel;
protected:
void Refresh();
void InitializeTableView(MyTableModel *model, QTableView *tableView);
// 重写resizeEvent当QTableView窗口大小变化时按比例调整列宽
void resizeEvent(QResizeEvent *event) override;
private slots:
void onButtonClicked();
void onTableViewDoubleClicked(const QModelIndex &index);
private:
unsigned int filterBaseType;
unsigned int mask_code;
QTableView* m_pTableView;
QPushButton* m_pButton;
QVector<int> columnWidths; // 存储初始列宽
};
#endif // DEVICEPROPERTYPAGE_H

View File

@ -0,0 +1,69 @@
QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
CONFIG += c++17
QMAKE_LFLAGS += /ignore:4099
QMAKE_CXXFLAGS_WARN_ON += -wd4100
include("$$PWD/QtSingleApplication/qtsingleapplication.pri")
DEFINES += HAVE_CONFIG_H
DEFINES += _CRT_SECURE_NO_WARNINGS
INCLUDEPATH += $$PWD/../../SDK/include
CONFIG(debug, debug|debug) {
INCLUDEPATH += "D:/Visual Leak Detector/include"
win32:LIBS += "D:/Visual Leak Detector/lib/Win64/vld.lib"
}
CONFIG(debug, debug|release) {
win32:LIBS += $$PWD/..\..\SDK\lib\libdesd.lib
win32:LIBS += $$PWD/..\..\SDK\lib\OpenSSL_VC\libcrypto64MDd.lib
win32:LIBS += $$PWD/..\..\SDK\lib\OpenSSL_VC\libssl64MDd.lib
win32:LIBS += $$PWD/..\..\SDK\lib\hv.lib
win32:LIBS += Ws2_32.lib
}else{
win32:LIBS += $$PWD/..\..\SDK\lib\libdes.lib
win32:LIBS += $$PWD/..\..\SDK\lib\OpenSSL_VC\libcrypto64MD.lib
win32:LIBS += $$PWD/..\..\SDK\lib\OpenSSL_VC\libssl64MD.lib
win32:LIBS += $$PWD/..\..\SDK\lib\hvd.lib
win32:LIBS += Ws2_32.lib
}
# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
datafetcher.cpp \
devicepropertypage.cpp \
globalparameters.cpp \
main.cpp \
maindialog.cpp \
mainwindow.cpp \
mytablemodel.cpp
HEADERS += \
datafetcher.h \
devicepropertypage.h \
globalparameters.h \
maindialog.h \
mainwindow.h \
mytablemodel.h \
singleton.h
FORMS += \
maindialog.ui \
mainwindow.ui
# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target
RESOURCES += \
emscfgres.qrc

View File

@ -0,0 +1,16 @@
<RCC>
<qresource prefix="/">
<file>images/emscfg-main.ico</file>
<file>images/hj-net.png</file>
<file>images/icon.png</file>
<file>images/PageAir.png</file>
<file>images/PageBattery.png</file>
<file>images/PageFan.png</file>
<file>images/PagePower.png</file>
<file>images/PagePV.png</file>
<file>images/PageSensor.png</file>
<file>images/PageSetting.png</file>
<file>images/PageSwitch.png</file>
<file>images/PageUps.png</file>
</qresource>
</RCC>

View File

@ -0,0 +1,114 @@
#include <QCoreApplication>
#include <QMessageBox>
#include <QString>
#include <QAbstractTableModel>
#include <QTableView>
#include <QHeaderView>
#include <QApplication>
#include <QCursor>
#include "globalparameters.h"
#include "mytablemodel.h"
AppData::~AppData()
{
}
AppData::AppData(token)
{
lstDataTableHeaderText << ("Status")
<< ("Parameter")
<< ("Value")
<< ("Unit")
<< ("Time");
nTimeOut = 5000;
qsDestinationIp = "127.0.0.1";
qsLastErrorString = "OK";
}
AppCommon::AppCommon(token)
{
}
AppCommon::~AppCommon()
{
}
void AppCommon::InitializeTableView(MyTableModel *model, QTableView *tableView)
{
//设置tableview的model
model->setHeadData(AppData::getInstance()->lstDataTableHeaderText);
tableView->setModel(model);
QHeaderView* pHeaderView = tableView->horizontalHeader();
//pHeaderView->setStyleSheet("QHeaderView::section {color: black;padding-left: 4px;border: 1px solid #6c6c6c;}");
pHeaderView->setStyleSheet("QHeaderView::section{background:lightgray;}");
// pHeaderView->setSectionResizeMode(QHeaderView::Stretch); //Stretch
pHeaderView->setHidden(false); //false 显示行号列 true Hide
//pHeaderView->setVisible(true);
//pHeaderView->setFixedHeight(40);
//点击表时不对表头行光亮(获取焦点)
pHeaderView->setHighlightSections(false);
//pHeaderView->setDefaultSectionSize(35);
// //设置表头字体加粗
// QFont font = pHeaderView->font();
// font.setBold(true);
// pHeaderView->setFont(font);
//设置表头字体
pHeaderView->setFont(QFont("Arial", 12));
// 设置表头列宽自动调整
for (int i = 0; i < model->columnCount(); ++i) {
pHeaderView->setSectionResizeMode(i, QHeaderView::Stretch);
}
// 允许用户通过拖动表头边缘调整列宽
pHeaderView->setSectionResizeMode(QHeaderView::Interactive);
tableView->verticalHeader()->setDefaultSectionSize(30); //行高
tableView->setSelectionBehavior(QAbstractItemView::SelectRows);
tableView->setSelectionMode(QAbstractItemView::SingleSelection);
tableView->setAlternatingRowColors(true);
tableView->setTextElideMode(Qt::ElideMiddle);
//所有单元格的字体 设置成一样
tableView->setFont(QFont("Arial", 9));
//设置表格数据区内的所有单元格都不允许编辑
tableView->setEditTriggers(QAbstractItemView::NoEditTriggers);
#if 0
//设置列宽
int w = tableView->width();
int base = w /(AppData::getInstance()->lstDataTableHeaderText.count()-1);
tableView->setColumnWidth(0,base-45);
tableView->setColumnWidth(1,base-20);
tableView->setColumnWidth(2,base+30);
tableView->setColumnWidth(3,base+10);
tableView->setColumnWidth(4,base);
#endif
tableView->show();
}
CWaitorCursor::CWaitorCursor()
{
QApplication::setOverrideCursor(QCursor(Qt::WaitCursor));
}
CWaitorCursor::~CWaitorCursor()
{
QApplication::restoreOverrideCursor();
}

View File

@ -0,0 +1,78 @@
#ifndef GLOBALPARAMETERS_H
#define GLOBALPARAMETERS_H
#pragma execution_character_set("utf-8")
#include <QStringList>
#include "singleton.h"
class QAbstractTableModel;
class QTableView;
class MyTableModel;
//采集设备参数所处的状态
typedef enum _tagSignalStatus
{
STATUS_NORMAL = 0,
STATUS_WARN = 1,
STATUS_ERROR = 2,
STATUS_INFO = 3,
}SignalStatus;
typedef struct _ModelItem
{
SignalStatus status;
std::string ParameterName;
std::string value;
std::string unit;
std::string sampleTime;
}ModelItem;
typedef QList<ModelItem> TableData;
class CWaitorCursor
{
public:
CWaitorCursor();
~CWaitorCursor();
};
//全局变量
class AppData:public Singleton<AppData>
{
public:
AppData(token);
~AppData();
AppData(const AppData &other) = delete;
AppData& operator=(const AppData &other) = delete;
public:
//数据表格的表头
QStringList lstDataTableHeaderText;
//定时刷新间隔
int nTimeOut;
//目标机器IP
QString qsDestinationIp;
//最后的错误信息
QString qsLastErrorString;
};
//全局通用类
class AppCommon:public Singleton<AppCommon>
{
public:
AppCommon(token);
~AppCommon();
AppCommon(const AppCommon&)=delete;
AppCommon& operator =(const AppCommon&)= delete;
public:
void InitializeTableView(MyTableModel* model,QTableView* tableView);
};
#endif // GLOBALPARAMETERS_H

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.7 KiB

View File

@ -0,0 +1,73 @@
#ifdef _DEBUG
#include <vld.h>
#endif
#include "mainwindow.h"
#include "qtsingleapplication.h"
#include <QApplication>
#include <QTranslator>
#include <QMessageBox>
#include <QScreen>
#include <hv/hv.h>
#include <hv/hmain.h>
#include <hv/iniparser.h>
#include <hv/hloop.h>
#include <hv/hsocket.h>
#include <hv/hssl.h>
int main(int argc, char *argv[])
{
QString app_unique_name("emsConfigurer_application_name");
QtSingleApplication app(app_unique_name,argc, argv);
if(app.isRunning())
{
QMessageBox::information(nullptr, "EMS Configurer", "Another instance is already running.");
app.sendMessage("raise_window_noop", 1000); //1s后激活前个实例
return EXIT_SUCCESS;
}
main_ctx_init(argc, argv);
QString appDir = QCoreApplication::applicationDirPath();
std::string logFilePath = (appDir + QString::fromStdString("/emsConfigurer.log")).toStdString();
hlog_set_file(logFilePath.c_str());
hlogi("=========--- Welcome to the Earth ---=========");
hlogi("%s version: %s", argv[0], "1.1.0");
hlog_fsync();
QTranslator translator;
const QStringList uiLanguages = QLocale::system().uiLanguages();
for (const QString &locale : uiLanguages)
{
const QString baseName = "emsConfigurer_" + QLocale(locale).name();
if (translator.load(":/i18n/" + baseName))
{
app.installTranslator(&translator);
break;
}
}
MainWindow w;
//隐藏(不显示)最大化最小化按钮
w.setWindowFlags(w.windowFlags()&~Qt::WindowMinMaxButtonsHint);
//w.setWindowFlags(w.windowFlags() | Qt::WindowStaysOnTopHint);
w.setStyleSheet("{border-radius: 4px;}"); // 定制圆角
// ".QLabel{background: gray;}.QTextEdit{background: white;}");
//获取窗口尺寸并居中
QScreen *scr = app.primaryScreen();
int scr_w = scr->size().width();
int scr_h = scr->size().height();
w.move((scr_w - w.width()) / 2, (scr_h - w.height()) / 2);
w.show();
int ret = app.exec();
hlogi("=========--- I'll be back! ---=========");
return ret;
}

View File

@ -0,0 +1,217 @@
#include "maindialog.h"
#include "ui_maindialog.h"
#include <QToolBar>
#include <QListWidget>
#include <QStackedWidget>
#include <QVBoxLayout>
#include <QIcon>
#include <QSize>
#include <QPushButton>
#include <QSplitter>
#include <QSettings>
#include <QCloseEvent>
#include <QMessageBox>
#include <QTableView>
#include <QStandardItemModel>
#include "devicepropertypage.h"
MainDialog::MainDialog(QWidget *parent) :
QMainWindow (parent),
ui(new Ui::MainDialog)
{
//ui->setupUi(this);
this->setWindowIcon(QIcon(":/images/icon.png"));
InitializeUI();
// Load the window state
loadWindowState();
}
MainDialog::~MainDialog()
{
delete ui;
}
void MainDialog::InitializeUI()
{
// Create central widget and layout
this->takeCentralWidget();
QWidget *centralWidget = new QWidget(this);
QVBoxLayout *mainLayout = new QVBoxLayout(centralWidget);
//Create toolbar
CreateToolbar();
// Set up the QListWidget
m_pDeviceListWidget = new QListWidget(this);
m_pDeviceListWidget->setStyleSheet("background-color:transparent");
m_pDeviceListWidget->setViewMode(QListView::IconMode);
m_pDeviceListWidget->setIconSize(QSize(70, 70));
m_pDeviceListWidget->setGridSize(QSize(145, 100)); // item 的大小
m_pDeviceListWidget->setMovement(QListView::Static);
m_pDeviceListWidget->setMaximumWidth(170);
m_pDeviceListWidget->setMinimumWidth(170); // Set minimum width
m_pDeviceListWidget->setResizeMode(QListView::Fixed);
m_pDeviceListWidget->setSpacing(25);
//m_pDeviceListWidget->setUniformItemSizes(true); // 所有的 item 一样大
m_pDeviceListWidget->setEditTriggers(QAbstractItemView::NoEditTriggers);
CreateIcon(QIcon(":/images/PagePower.png"),tr("Power"));
CreateIcon(QIcon(":/images/PageBattery.png"),tr("Battery"));
CreateIcon(QIcon(":/images/PageSwitch.png"),tr("Switch"));
CreateIcon(QIcon(":/images/PageAir.png"),tr("Air"));
CreateIcon(QIcon(":/images/PageFan.png"),tr("Fan"));
CreateIcon(QIcon(":/images/PageSensor.png"),tr("Sensor"));
// Set up the QStackedWidget
CreateTablePage();
// Set up the QSplitter to manage the resizing of QListWidget and QStackedWidget
QSplitter *splitter = new QSplitter(Qt::Horizontal, this);
splitter->addWidget(m_pDeviceListWidget);
splitter->addWidget(m_pDevicestackedWidget);
splitter->setSizes(QList<int>({200, 600})); // Set initial sizes (200 for QListWidget, 600 for QStackedWidget)
// Disable splitter dragging
splitter->setChildrenCollapsible(false);
// 将工具栏添加到主窗口的顶部
//addToolBar(Qt::TopToolBarArea, m_pMainToolBar);
// Set up layout
mainLayout->addWidget(m_pMainToolBar);
mainLayout->addWidget(splitter);
centralWidget->setLayout(mainLayout);
// Set central widget
setCentralWidget(centralWidget);
// Set initial size of the dialog
setWindowTitle(tr("EMS Configurer "));
//resize(800, 600);
setMinimumSize(1024, 768);
connect(m_pDeviceListWidget, &QListWidget::currentItemChanged, this, &MainDialog::changePage);
}
void MainDialog::CreateToolbar()
{
m_pMainToolBar = new QToolBar(this);
m_pMainToolBar->setIconSize(QSize(48, 48));
// 创建一个水平布局以容纳图标和占位符
QWidget *toolBarWidget = new QWidget(this);
QHBoxLayout *layout = new QHBoxLayout(toolBarWidget);
layout->setContentsMargins(0, 0, 0, 0); // 去除内边距
// 添加一个弹性空间以推送图标到右侧
QSpacerItem *spacer = new QSpacerItem(40, 20, QSizePolicy::Expanding, QSizePolicy::Minimum);
layout->addItem(spacer);
// Create actions for the toolbar
QAction *action1 = new QAction(QIcon(":/images/icon.png"), "Button 1", this);
QAction *action2 = new QAction(QIcon(":/images/icon.png"), "Button 2", this);
QAction *action3 = new QAction(QIcon(":/images/icon.png"), "About...", this);
// Add actions to the toolbar
m_pMainToolBar->addAction(action1);
m_pMainToolBar->addAction(action2);
m_pMainToolBar->addAction(action3);
// 将工具栏的 widget 设置为包含图标和占位符的 widget
m_pMainToolBar->addWidget(toolBarWidget);
// Connect actions to slots
connect(action1, &QAction::triggered, this, &MainDialog::onToolButton1Clicked);
connect(action2, &QAction::triggered, this, &MainDialog::onToolButton1Clicked);
connect(action3, &QAction::triggered, this, &MainDialog::onAboutButtonClicked);
}
void MainDialog::CreateTablePage()
{
m_pDevicestackedWidget = new QStackedWidget(this);
QVBoxLayout *stackedWidgetLayout = new QVBoxLayout(m_pDevicestackedWidget);
#if 1
//m_pDevicestackedWidget->setLayout(stackedWidgetLayout);
stackedWidgetLayout->addWidget(m_pDevicestackedWidget);
DevicePropertyPage *page1 = new DevicePropertyPage(m_pDevicestackedWidget);
DevicePropertyPage *page2 = new DevicePropertyPage(m_pDevicestackedWidget);
m_pDevicestackedWidget->addWidget(page1); // Add QTableView as a page
m_pDevicestackedWidget->addWidget(page2);
m_pDevicestackedWidget->addWidget(new QPushButton("Page 3"));
m_pDevicestackedWidget->addWidget(new QPushButton("Page 4"));
m_pDevicestackedWidget->addWidget(new QPushButton("Page 5"));
m_pDevicestackedWidget->addWidget(new QPushButton("Page 6"));
#endif
// setLayout(stackedWidgetLayout);
}
void MainDialog::CreateIcon(const QIcon& icon,QString text)
{
QListWidgetItem *itemButton = new QListWidgetItem(m_pDeviceListWidget);
itemButton->setIcon(icon);
itemButton->setText(text);
itemButton->setTextAlignment(Qt::AlignHCenter);
itemButton->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
}
void MainDialog::changePage(QListWidgetItem *current, QListWidgetItem *previous)
{
if (!current)
current = previous;
m_pDevicestackedWidget->setCurrentIndex(m_pDeviceListWidget->row(current));
}
void MainDialog::closeEvent(QCloseEvent *event)
{
// Save the window state
saveWindowState();
QMainWindow::closeEvent(event);
}
void MainDialog::saveWindowState()
{
QSettings settings("HJ-NET", "EMSCFG");
settings.setValue("geometry", saveGeometry());
settings.setValue("windowState", saveState());
}
void MainDialog::loadWindowState()
{
QSettings settings("HJ-NET", "EMSCFG");
restoreGeometry(settings.value("geometry").toByteArray());
restoreState(settings.value("windowState").toByteArray());
}
void MainDialog::onToolButton1Clicked()
{
QMessageBox::information(this, "Button Clicked", "Button 1 was clicked!");
}
void MainDialog::onToolButton2Clicked()
{
QMessageBox::information(this, "Button Clicked", "Button 2 was clicked!");
}
void MainDialog::onAboutButtonClicked()
{
QMessageBox::information(this, "Button Clicked", "About");
}

View File

@ -0,0 +1,53 @@
#ifndef MAINDIALOG_H
#define MAINDIALOG_H
#include <QMainWindow>
#include <QListWidget>
#include <QListWidgetItem>
#include <QIcon>
#include <QStackedWidget>
#include <QToolBar>
namespace Ui {
class MainDialog;
}
class MainDialog : public QMainWindow
{
Q_OBJECT
public:
explicit MainDialog(QWidget *parent = nullptr);
~MainDialog();
void InitializeUI();
void loadWindowState();
public slots:
void changePage(QListWidgetItem *current, QListWidgetItem *previous);
private slots:
void onToolButton1Clicked();
void onToolButton2Clicked();
void onAboutButtonClicked();
private:
Ui::MainDialog *ui;
QListWidget *m_pDeviceListWidget;
QStackedWidget *m_pDevicestackedWidget;
QToolBar *m_pMainToolBar;
private:
void CreateToolbar();
void CreateIcon(const QIcon& icon,QString text);
void CreateTablePage();
protected:
void closeEvent(QCloseEvent *event) override;
void saveWindowState();
};
#endif // MAINDIALOG_H

View File

@ -0,0 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainDialog</class>
<widget class="QDialog" name="MainDialog">
<property name="windowModality">
<enum>Qt::NonModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>867</width>
<height>665</height>
</rect>
</property>
<property name="contextMenuPolicy">
<enum>Qt::NoContextMenu</enum>
</property>
<property name="windowTitle">
<string>Dialog</string>
</property>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,53 @@
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QPixmap>
#include <QMessageBox>
#include <QRegularExpression>
#include <QRegularExpressionValidator>
#include "MainDialog.h"
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow)
, m_pMainDialog(nullptr)
{
ui->setupUi(this);
this->setWindowIcon(QIcon(":/images/icon.png"));
QPixmap pixmap(":/images/hj-net.png");
pixmap = pixmap.scaled(250, 75, Qt::KeepAspectRatio, Qt::SmoothTransformation); // 按比例缩放
ui->label_logo->setPixmap(pixmap);
QString qsLineEditStyle("QLineEdit { min-height: 20px; min-width: 120px; }");
ui->userToken->setStyleSheet(qsLineEditStyle);
ui->serverIp->setStyleSheet(qsLineEditStyle);
QRegularExpression rx("^((2[0-4]\\d|25[0-5]|[01]?\\d\\d?)\\.){3}(2[0-4]\\d|25[0-5]|[01]?\\d\\d?)$");
QRegularExpressionValidator* ipValidator = new QRegularExpressionValidator(rx, this);
ui->serverIp->setValidator(ipValidator);
setIp("127.0.0.1");
}
MainWindow::~MainWindow()
{
delete ui;
if (m_pMainDialog)
{
delete m_pMainDialog;
m_pMainDialog = nullptr;
}
}
void MainWindow::setIp(const QString &ip)
{
ui->serverIp->setText(ip);
}
void MainWindow::on_pb_Logon_clicked()
{
m_pMainDialog = new MainDialog();
m_pMainDialog->show();
this->close();
}

View File

@ -0,0 +1,30 @@
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
class MainDialog;
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
protected:
void setIp(const QString &ip);
private slots:
void on_pb_Logon_clicked();
private:
Ui::MainWindow *ui;
MainDialog* m_pMainDialog;
};
#endif // MAINWINDOW_H

View File

@ -0,0 +1,219 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>MainWindow</class>
<widget class="QMainWindow" name="MainWindow">
<property name="windowModality">
<enum>Qt::WindowModal</enum>
</property>
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>551</width>
<height>352</height>
</rect>
</property>
<property name="contextMenuPolicy">
<enum>Qt::NoContextMenu</enum>
</property>
<property name="windowTitle">
<string>EMS Configurer</string>
</property>
<widget class="QWidget" name="centralwidget">
<widget class="QLabel" name="label_4">
<property name="geometry">
<rect>
<x>130</x>
<y>176</y>
<width>61</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Host IP</string>
</property>
</widget>
<widget class="QLabel" name="label">
<property name="geometry">
<rect>
<x>140</x>
<y>60</y>
<width>231</width>
<height>71</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>26</pointsize>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Configurer</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QLineEdit" name="serverIp">
<property name="geometry">
<rect>
<x>220</x>
<y>173</y>
<width>124</width>
<height>23</height>
</rect>
</property>
<property name="inputMask">
<string/>
</property>
</widget>
<widget class="QLabel" name="label_6">
<property name="geometry">
<rect>
<x>370</x>
<y>88</y>
<width>161</width>
<height>41</height>
</rect>
</property>
<property name="font">
<font>
<pointsize>16</pointsize>
</font>
</property>
<property name="text">
<string>for EMU Host</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
<widget class="QPushButton" name="pb_Test">
<property name="geometry">
<rect>
<x>350</x>
<y>173</y>
<width>51</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Test</string>
</property>
</widget>
<widget class="QLabel" name="label_logo">
<property name="geometry">
<rect>
<x>7</x>
<y>7</y>
<width>261</width>
<height>61</height>
</rect>
</property>
<property name="text">
<string>WWW.HJ-NET.COM</string>
</property>
</widget>
<widget class="QWidget" name="layoutWidget">
<property name="geometry">
<rect>
<x>140</x>
<y>280</y>
<width>251</width>
<height>31</height>
</rect>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QPushButton" name="pb_Logon">
<property name="text">
<string>Logon</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="pb_Close">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QLineEdit" name="userToken">
<property name="geometry">
<rect>
<x>220</x>
<y>233</y>
<width>181</width>
<height>23</height>
</rect>
</property>
<property name="contextMenuPolicy">
<enum>Qt::NoContextMenu</enum>
</property>
<property name="acceptDrops">
<bool>false</bool>
</property>
<property name="inputMethodHints">
<set>Qt::ImhHiddenText|Qt::ImhNoAutoUppercase|Qt::ImhNoEditMenu|Qt::ImhNoPredictiveText|Qt::ImhSensitiveData</set>
</property>
<property name="echoMode">
<enum>QLineEdit::Password</enum>
</property>
</widget>
<widget class="QLabel" name="label_2">
<property name="geometry">
<rect>
<x>130</x>
<y>200</y>
<width>68</width>
<height>30</height>
</rect>
</property>
<property name="text">
<string>Login name</string>
</property>
</widget>
<widget class="QLabel" name="label_3">
<property name="geometry">
<rect>
<x>130</x>
<y>233</y>
<width>56</width>
<height>21</height>
</rect>
</property>
<property name="text">
<string>Password</string>
</property>
</widget>
<widget class="QLineEdit" name="userName">
<property name="geometry">
<rect>
<x>220</x>
<y>203</y>
<width>181</width>
<height>23</height>
</rect>
</property>
</widget>
</widget>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,151 @@
#include <QColor>
#include "mytablemodel.h"
MyTableModel::MyTableModel(QObject* parent)
:QAbstractTableModel(parent)
{
for(int i=0;i<100;i++)
{
ModelItem item;
item.status = STATUS_WARN;
item.ParameterName= "Visual Leak Detector detected 1 memory leak (84 bytes)";
item.sampleTime = "2024-9-10 11:22:33.444";
item.unit = "C";
item.value = "100";
m_modelData.append(item);
}
}
int MyTableModel::rowCount(const QModelIndex & /*parent*/) const
{
return m_modelData.size();
}
int MyTableModel::columnCount(const QModelIndex & /*parent*/) const
{
return AppData::getInstance()->lstDataTableHeaderText.count();
}
QVariant MyTableModel::data(const QModelIndex& index, int role) const
{
if (!index.isValid())
return QVariant();
if (role == Qt::DisplayRole || role == Qt::EditRole)
{
const int row = index.row();
switch (index.column())
{
case 0:
{
if (m_modelData.at(row).status == STATUS_NORMAL) return tr("Normal");
if (m_modelData.at(row).status == STATUS_INFO) return tr("INFO");
if (m_modelData.at(row).status == STATUS_WARN) return tr("WARN");
if (m_modelData.at(row).status == STATUS_ERROR) return tr("ERROR");
}
case 1:
{
return m_modelData.at(row).ParameterName.c_str();
}
case 2: return m_modelData.at(row).value.c_str();
case 3: return m_modelData.at(row).unit.c_str();
case 4: return m_modelData.at(row).sampleTime.c_str();
}
}
//对齐处理
if (role == Qt::TextAlignmentRole)
{
//const int row = index.row();
switch (index.column())
{
case 1:
case 2:
case 3:
return QVariant(Qt::AlignLeft|Qt::AlignVCenter);
break;
//case 4:
// return QVariant(Qt::AlignRight|Qt::AlignVCenter);
// break;
default:
return Qt::AlignCenter;
break;
}
}
if (role == Qt::BackgroundRole)
{
const int row = index.row();
switch (index.column())
{
case 0: //状态
case 2: //数值
{
if (m_modelData.at(row).status == STATUS_WARN)
return QVariant(QColor(Qt::yellow));
else if (m_modelData.at(row).status == STATUS_ERROR)
return QVariant(QColor(Qt::red));
}
}
}
return QVariant();
}
QVariant MyTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole && orientation == Qt::Horizontal)
{
if (section < m_headeList.size())
{
return m_headeList[section];
}
}
return QAbstractItemModel::headerData(section, orientation, role);
}
const TableData *MyTableModel::getModelData() const
{
return &m_modelData;
}
bool MyTableModel::setData(const QModelIndex& index, const QVariant& value, int role)
{
//beginResetModel();
if (!index.isValid())
return false;
//endResetModel(); //在结束前添加此函数
return QAbstractTableModel::setData(index, value, role);
}
Qt::ItemFlags MyTableModel::flags(const QModelIndex &index) const
{
return Qt::ItemIsEditable | QAbstractTableModel::flags(index);
}
void MyTableModel::setModelData(TableData data)
{
//修改数据前后用beginResetModel()和endResetModel()
beginResetModel(); //通过这个告诉我要开始修改model了
m_modelData.clear();
for (int i = 0;i < data.count();++i)
{
m_modelData.append(data[i]);
}
endResetModel(); //通过这个告诉我修改model结束了
}
void MyTableModel::clearModelData()
{
m_modelData.clear();
}
void MyTableModel::setHeadData(QStringList i_list)
{
m_headeList=i_list;
}

View File

@ -0,0 +1,37 @@
#pragma execution_character_set("utf-8")
#ifndef MYTABLEMODEL_H
#define MYTABLEMODEL_H
#include <QAbstractTableModel>
#include <QString>
#include "globalparameters.h"
class MyTableModel : public QAbstractTableModel
{
Q_OBJECT
public:
MyTableModel(QObject* parent);
int rowCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE;
int columnCount(const QModelIndex& parent = QModelIndex()) const Q_DECL_OVERRIDE;
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) Q_DECL_OVERRIDE;
Qt::ItemFlags flags(const QModelIndex& index) const Q_DECL_OVERRIDE;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
const TableData *getModelData() const;
private:
TableData m_modelData;
QStringList m_headeList;
public:
void setHeadData(QStringList i_list);
void setModelData(TableData data);
void clearModelData();
};
#endif // MYTABLEMODEL_H

View File

@ -0,0 +1,24 @@
#ifndef SINGLETON_H
#define SINGLETON_H
#include <iostream>
template<typename T>
class Singleton
{
public:
static T* getInstance() noexcept(std::is_nothrow_constructible<T>::value)
{
static T instance{token()};
return &instance;
}
virtual ~Singleton() =default;
Singleton(const Singleton&)=delete;
Singleton& operator =(const Singleton&)=delete;
protected:
struct token{}; // helper class
Singleton() noexcept=default;
};
#endif // SINGLETON_H

View File

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.35130.168
MinimumVisualStudioVersion = 10.0.40219.1
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WinDataHubs", "WinDataHubs.vcxproj", "{2192CF4F-DE56-4896-9EA1-4C61B40590A5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{2192CF4F-DE56-4896-9EA1-4C61B40590A5}.Debug|x64.ActiveCfg = Debug|x64
{2192CF4F-DE56-4896-9EA1-4C61B40590A5}.Debug|x64.Build.0 = Debug|x64
{2192CF4F-DE56-4896-9EA1-4C61B40590A5}.Debug|x86.ActiveCfg = Debug|Win32
{2192CF4F-DE56-4896-9EA1-4C61B40590A5}.Debug|x86.Build.0 = Debug|Win32
{2192CF4F-DE56-4896-9EA1-4C61B40590A5}.Release|x64.ActiveCfg = Release|x64
{2192CF4F-DE56-4896-9EA1-4C61B40590A5}.Release|x64.Build.0 = Release|x64
{2192CF4F-DE56-4896-9EA1-4C61B40590A5}.Release|x86.ActiveCfg = Release|Win32
{2192CF4F-DE56-4896-9EA1-4C61B40590A5}.Release|x86.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {81B0EBA0-C45B-4F9A-B3E8-4780447CB231}
EndGlobalSection
EndGlobal

View File

@ -0,0 +1,167 @@
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Debug|x64">
<Configuration>Debug</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|x64">
<Configuration>Release</Configuration>
<Platform>x64</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<VCProjectVersion>16.0</VCProjectVersion>
<Keyword>Win32Proj</Keyword>
<ProjectGuid>{2192cf4f-de56-4896-9ea1-4c61b40590a5}</ProjectGuid>
<RootNamespace>WinDataHubs</RootNamespace>
<WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<PlatformToolset>v142</PlatformToolset>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="Shared">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(SolutionDir)\..\..\sdk\include;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)\..\..\sdk\lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<LinkIncremental>true</LinkIncremental>
<IncludePath>$(SolutionDir)\..\..\sdk\include;$(IncludePath)</IncludePath>
<LibraryPath>$(SolutionDir)\..\..\sdk\Lib;$(LibraryPath)</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_DEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>hv.lib;zlibd.lib;mysqlcppconn.lib;libiconvD.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="eventhandler.cpp" />
<ClCompile Include="iconv-utils.cpp" />
<ClCompile Include="kutilities.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="openjson.cpp" />
<ClCompile Include="opmysql.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="eventhandler.h" />
<ClInclude Include="frame_define.h" />
<ClInclude Include="iconv-utils.h" />
<ClInclude Include="kdefine.h" />
<ClInclude Include="kutilities.h" />
<ClInclude Include="mqtt_msg.h" />
<ClInclude Include="openjson.h" />
<ClInclude Include="opmysql.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>

View File

@ -8,7 +8,8 @@ log_filesize = 16M
# worker_processes = auto # auto = ncpu
# worker_processes = auto
worker_processed = 0
worker_threads = auto
# worker_threads = auto
worker_threads = 1
host = 0.0.0.0
port = 44242

View File

@ -76,20 +76,27 @@
<ImportGroup Label="PropertySheets" />
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<IncludePath>D:\My Documents\汇珏网络\15. EMS\projects\sdk\include;$(IncludePath)</IncludePath>
<IncludePath>$(SolutionDir)\..\..\sdk\include;$(IncludePath)</IncludePath>
<ProjectPublicIncludePath>-I/usr/local/include</ProjectPublicIncludePath>
<LibraryPath>$(SolutionDir)\..\..\sdk\lib;</LibraryPath>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">
<IncludePath>D:\My Documents\汇珏网络\15. EMS\projects\emsApplication\sdk\include;$(IncludePath)</IncludePath>
<IncludePath>..\..\..\emsApplication\sdk\include;$(IncludePath)</IncludePath>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="eventhandler.cpp" />
<ClCompile Include="iconv-utils.cpp" />
<ClCompile Include="kutilities.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="openjson.cpp" />
<ClCompile Include="opmysql.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="eventhandler.h" />
<ClInclude Include="frame_define.h" />
<ClInclude Include="iconv-utils.h" />
<ClInclude Include="kdefine.h" />
<ClInclude Include="kutilities.h" />
<ClInclude Include="mqtt_msg.h" />
<ClInclude Include="openjson.h" />
<ClInclude Include="opmysql.h" />
@ -103,6 +110,7 @@
<Link>
<AdditionalOptions>-L/usr/local/lib</AdditionalOptions>
<LibraryDependencies>hv;sqlite3;dl</LibraryDependencies>
<AdditionalLibraryDirectories>%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|ARM'">

View File

@ -0,0 +1,249 @@
#include "eventhandler.h"
#include <hv/hv.h>
#include <hv/hmain.h>
#include <hv/iniparser.h>
#include <hv/hloop.h>
#include <hv/hsocket.h>
#include <hv/hssl.h>
#include "kdefine.h"
#include "frame_define.h"
#include "openjson.h"
#include "iconv-utils.h"
#include "kutilities.h"
#include "opmysql.h"
#include "mqtt_msg.h"
EventHandler::EventHandler()
{
}
EventHandler::~EventHandler()
{
}
void EventHandler::onRecvHandler(hio_t* io, void* buf, int readbytes)
{
__USING_NAMESPACE_HJ__;
char localaddrstr[SOCKADDR_STRLEN] = { 0 };
char peeraddrstr[SOCKADDR_STRLEN] = { 0 };
hlogi("### 1 ### on_recv fd=%d readbytes=%d [%s] <==== [%s]", hio_fd(io), readbytes,
SOCKADDR_STR(hio_localaddr(io), localaddrstr),
SOCKADDR_STR(hio_peeraddr(io), peeraddrstr));
MessageFrame respFrame;
if( readbytes > 0xFFFF - 1 )
{
hloge("too large data buffer to process: %d", readbytes);
respFrame.setErrorFrame(ERR_INVALID_BUF_LEN);
hio_write(io, (void*)&respFrame, sizeof respFrame);
return;
}
hlogi("<=== decode OK [\n%s\n]", printHex(buf, readbytes).c_str());
MessageFrame* pReadFrame = (MessageFrame*)buf;
hlogi("on_recv fd=%d frame_len=%d [0x%x] ", hio_fd(io), pReadFrame->frame_len, pReadFrame->frame_len);
if( pReadFrame->frame_len > 0xFFFF - 1 )
{
hloge("too big string buffer to process: %d, it should be less than %d", pReadFrame->frame_len, 0xFFFF);
respFrame.setErrorFrame(ERR_INVALID_LEN);
hio_write(io, (void*)&respFrame, sizeof respFrame);
return;
}
if( Frame_DeviceData_Request == pReadFrame->frame_type )
{
handleGatherData(io, buf, readbytes);
}
else
{
assert(false);
}
}
void EventHandler::handleGatherData(hio_t* io, void* buf, int readbytes)
{
assert(buf);
__USING_NAMESPACE_HJ__;
MessageFrame respFrame;
MessageFrame* pReadFrame = (MessageFrame*)buf;
hlogi("<=== reveive device data request");
OpenJson json;
CODING buf_code = GetCoding((unsigned char*)pReadFrame->frame_content, pReadFrame->frame_len); //判断是否是utf-8
hlogi("<=== recieve buffer coding is [%s]", buf_code == GBK ? "GBK" : (buf_code == UTF8 ? "UTF8" : "UNKNOWN CODING"));
MessageData* pData = (MessageData*)pReadFrame->frame_content;
#ifdef _DEBUG
hlogd("<=== MessageData structure [\n%s\n]", printHex(pData, pReadFrame->frame_len).c_str());
#endif
//这里将帧内帧的内容转换为字符串符合json格式的字符串详见mqtt_msg.h的MessageData结构定义
std::string msg((char*)pReadFrame->frame_content + MSG_HEADER_LENGTH, pReadFrame->frame_len - MSG_HEADER_LENGTH);
#ifdef _DEBUG
hlogd("<=== json content [\n%s\n]", msg.c_str());
#endif
if( buf_code == CODING::GBK
|| buf_code == CODING::UNKOWN )
{
std::string str_result;
//转换为UTF8
if( !GBKToUTF8(msg, str_result) )
{
hloge("Failed to transfer code from GBK to UTF-8");
respFrame.setErrorFrame(ERR_INVALID_UTF8);
hio_write(io, (void*)&respFrame, sizeof respFrame);
return;
}
hlogi("Successfuly transfer code from GBK to UTF-8!");
msg = str_result;
}
#ifdef _DEBUG
hlogd("<=== recieve !!VALID!! mqtt pack len =[%d] data=[%s]", msg.length(), msg.c_str()); //这里还是好的
#endif
unsigned int len = msg.length();
char* pTmp = new char[len];
memcpy(pTmp, msg.c_str(), len);
std::shared_ptr<char> ptr; //放个智能指针省得忘记删除
ptr.reset(pTmp);
//hlogi("<=== decode OK, msg=[%s]", msg.c_str());
#if 0
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 17).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 18).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 19).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 20).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 21).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 22).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 23).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 24).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 25).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 26).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 27).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 28).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 29).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 30).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 31).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 32).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 33).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 34).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 61).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 62).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 63).c_str());
#endif
//hlogd("<=== decode OK [\n%s\n]", printHex(pTmp, len).c_str());
try
{
if( !json.decode(msg) )
{
hloge("Failed to decode json string pack , length=%d", readbytes);
respFrame.setErrorFrame(ERR_INVALID_JSON_FMT);
hio_write(io, (void*)&respFrame, sizeof respFrame);
return;
}
std::string fsucode = json["FsuCode"].s();
std::string msg_type = json["type"].s();
std::string timestamp = get_current_timestamp(); // json["TimeStamp"].s();
if( fsucode.length() == 0 )
{
//delete[] pTmp;
hlogw("!!empty fsucode recieved!");
respFrame.setErrorFrame(ERR_INVALID_FSUCODE);
hio_write(io, (void*)&respFrame, sizeof respFrame);
return;
}
hlogi("<=== decode OK, recieve fsucode=[%s] type=[%s] ts=[%s]", fsucode.c_str(), msg_type.c_str(), timestamp.c_str());
hio_write(io, (void*)&respFrame, sizeof respFrame);
#ifdef _DEBUG
hlogd("<<<<Check Mem after decode here>>>> \n[\n%s\n]\n", printHex(pTmp, len).c_str());
#endif
std::string out_compress;
int zip_ret = 0;
if( (zip_ret = CompressString(pTmp, len, out_compress, Z_DEFAULT_COMPRESSION)) != Z_OK )
{
hloge("Failed to compress source data, zip return value %d", zip_ret);
return;
}
hlogd("<<<<Compress result: string size from original [%d] to [%d]", len, out_compress.size());
#ifdef _DEBUG
hlogd("<<<<Compressed string here>>>> \n[\n%s\n]\n", printHex(out_compress.c_str(), out_compress.size()).c_str());
#endif
//std::string msg2(pTmp, len);
if( msg_type == "gateway-data"
|| msg_type == "gateway-alarmdata"
|| msg_type == "gateway-writedata"
|| msg_type == "gateway-readdata"
|| msg_type == "web-write"
|| msg_type == "web-alarm" )
{
auto& IdCodeContent = json["IdCodeContent"];
if( IdCodeContent.size() <= 0 )
{
//delete[] pTmp;
hloge("invalid IdCodeContent's size: %d", IdCodeContent.size());
return;
}
auto& pNode = IdCodeContent[0]; //这是只解析第一个节点
std::string oid = pNode["OID"].s();
OpDatabase::getInstance()->InsertMessage(timestamp, msg_type, fsucode, out_compress, (int)pData->mqtt_topic, (int)pData->device_id);
}
if( msg_type == "web-read" )
{
auto& IdCodeContent = json["IdCodes"];
if( IdCodeContent.size() <= 0 )
{
hloge("invalid IdCodes's size: %d", IdCodeContent.size());
//delete[] pTmp;
return;
}
auto& pNode = IdCodeContent[0]; //这是只解析第一个节点
std::string oid = pNode.s();
OpDatabase::getInstance()->InsertMessage(timestamp, msg_type, fsucode, out_compress, (int)pData->mqtt_topic, (int)pData->device_id);
}
//delete[] pTmp;
}
catch( const char* errMsg )
{
hloge("Failed to decode json string pack , catch error:%s", errMsg);
respFrame.setErrorFrame(ERR_INVALID_JSON_FMT);
hio_write(io, (void*)&respFrame, sizeof respFrame);
return;
}
}

View File

@ -0,0 +1,18 @@
#pragma once
#include <hv/hloop.h>
class EventHandler
{
public:
EventHandler();
virtual ~EventHandler();
public:
static void onRecvHandler(hio_t* io, void* buf, int readbytes);
protected:
//处理采集程序上传的数据以JSON数据上报
static void handleGatherData(hio_t* io, void* buf, int readbytes);
};

View File

@ -0,0 +1,54 @@
#pragma once
#pragma pack(1)
#include "kdefine.h"
__NAMESPACE_BEGIN__(HJ)
#define FRAME_HEADER_LENGTH (5)
#define FRAME_TAILE_LENGTH (4)
typedef enum tagErrorCode : unsigned char
{
ERR_OK = 0X00,
ERR_INVALID_LEN = 0X01,
ERR_INVALID_UTF8 = 0X02,
ERR_INVALID_BUF_LEN = 0X03,
ERR_INVALID_JSON_FMT = 0X04,
ERR_INVALID_FSUCODE = 0X05,
ERR_UNKOWN = 0XFF
}ErrorCode;
typedef enum tagFrameType : unsigned char
{
Frame_Response = 0x00, //返回帧
Frame_Request = 0x01, //请求帧
Frame_DeviceData_Request = 0x02, //来自采集程序的数据请求包,将数据保存到数据库中
}FrameType;
typedef struct tagFrameTail
{
unsigned char frame_delimiter[4] = { 0xEE,0xFF,0xEE,0xFF };
}FrameTail;
typedef struct tagFrame
{
FrameType frame_type; //帧类型
unsigned int frame_len; //帧数据长度
unsigned char frame_content[1]; //帧的内容实际应为json字符串由json内容自解释
tagFrame()
{
frame_type = Frame_Response;
frame_len = 1;
frame_content[0] = ERR_OK;
}
void setErrorFrame(ErrorCode err = ERR_OK)
{
frame_len = 1;
frame_content[0] = err;
}
}MessageFrame;
__NAMESPACE_END__(HJ)
#pragma pack()

View File

@ -135,8 +135,11 @@ int code_convert(const char* from_charset, const char* to_charset, char* inbuf,
return -1;
}
iconv_close(cd);
#ifndef _WIN32
* pout = '\0';
#else
*pout = (char*)'\0';
#endif
return 0;
}

View File

@ -0,0 +1,41 @@
#ifndef __KDEFINE_INCLUDE__
#define __KDEFINE_INCLUDE__
#define K22_STR_EXP(__A) #__A
#define K22_STR(__A) K22_STR_EXP(__A)
#define K22_STRW_EXP(__A) L ## #__A
#define K22_STRW(__A) K22_STRW_EXP(__A)
#define K22_CMS_VERSION_MAJOR 1
#define K22_CMS_VERSION_MINOR 215
#define K22_CMS_VERSION_REVISION 0
#define K22_VERSION K22_STR(K22_CMS_VERSION_MAJOR) "." K22_STR(K22_CMS_VERSION_MINOR) "." K22_STR(K22_CMS_VERSION_REVISION) ""
#ifdef __cplusplus
# ifndef EXTERN_C
# define EXTERN_C extern "C"
# endif
# ifndef BEGIN_EXTERN_C
# define BEGIN_EXTERN_C extern "C" {
# endif
# ifndef END_EXTERN_C
# define END_EXTERN_C } // extern "C"
# endif
#else
# define EXTERN_C extern
# define BEGIN_EXTERN_C
# define END_EXTERN_C
#endif // __cplusplus
#define __NAMESPACE_BEGIN__(X) namespace X {
#define __NAMESPACE_END__(X) }
#define __USING_NAMESPACE__(X) using namespace X
#define __USING_NAMESPACE_HJ__ using namespace HJ
#endif //__KDEFINE_INCLUDE__

View File

@ -0,0 +1,269 @@
#include "kutilities.h"
#include <iomanip>
#include <string>
#include <memory>
#include <sstream>
#include <chrono>
#define CHUNK 16384
/* Compress from file source to file dest until EOF on source.
def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
allocated for processing, Z_STREAM_ERROR if an invalid compression
level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
version of the library linked do not match, or Z_ERRNO if there is
an error reading or writing the files. */
int CompressString(const char* in_str, size_t in_len, std::string& out_str, int level)
{
if( !in_str )
return Z_DATA_ERROR;
int ret, flush;
unsigned have;
z_stream strm;
unsigned char out[CHUNK];
/* allocate deflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
ret = deflateInit(&strm, level);
if( ret != Z_OK )
return ret;
std::shared_ptr<z_stream> sp_strm(&strm, [](z_stream* strm)
{
(void)deflateEnd(strm);
});
const char* end = in_str + in_len;
//size_t pos_index = 0;
size_t distance = 0;
/* compress until end of file */
do
{
distance = end - in_str;
strm.avail_in = (distance >= CHUNK) ? CHUNK : distance;
strm.next_in = (Bytef*)in_str;
// next pos
in_str += strm.avail_in;
flush = (in_str == end) ? Z_FINISH : Z_NO_FLUSH;
/* run deflate() on input until output buffer not full, finish
compression if all of source has been read in */
do
{
strm.avail_out = CHUNK;
strm.next_out = out;
ret = deflate(&strm, flush); /* no bad return value */
if( ret == Z_STREAM_ERROR )
break;
have = CHUNK - strm.avail_out;
out_str.append((const char*)out, have);
}
while( strm.avail_out == 0 );
if( strm.avail_in != 0 ); /* all input will be used */
break;
/* done when last data in file processed */
}
while( flush != Z_FINISH );
if( ret != Z_STREAM_END ) /* stream will be complete */
return Z_STREAM_ERROR;
/* clean up and return */
return Z_OK;
}
/* Decompress from file source to file dest until stream ends or EOF.
inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
allocated for processing, Z_DATA_ERROR if the deflate data is
invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
the version of the library linked do not match, or Z_ERRNO if there
is an error reading or writing the files. */
int DecompressString(const char* in_str, size_t in_len, std::string& out_str)
{
if( !in_str )
return Z_DATA_ERROR;
int ret;
unsigned have;
z_stream strm;
unsigned char out[CHUNK];
/* allocate inflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit(&strm);
if( ret != Z_OK )
return ret;
std::shared_ptr<z_stream> sp_strm(&strm, [](z_stream* strm)
{
(void)inflateEnd(strm);
});
const char* end = in_str + in_len;
//size_t pos_index = 0;
size_t distance = 0;
int flush = 0;
/* decompress until deflate stream ends or end of file */
do
{
distance = end - in_str;
strm.avail_in = (distance >= CHUNK) ? CHUNK : distance;
strm.next_in = (Bytef*)in_str;
// next pos
in_str += strm.avail_in;
flush = (in_str == end) ? Z_FINISH : Z_NO_FLUSH;
/* run inflate() on input until output buffer not full */
do
{
strm.avail_out = CHUNK;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
if( ret == Z_STREAM_ERROR ) /* state not clobbered */
break;
switch( ret )
{
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
return ret;
}
have = CHUNK - strm.avail_out;
out_str.append((const char*)out, have);
}
while( strm.avail_out == 0 );
/* done when inflate() says it's done */
}
while( flush != Z_FINISH );
/* clean up and return */
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}
// 函数用于将内存块转换为十六进制字符串
std::string printHex(const void* data, size_t size)
{
std::ostringstream oss;
std::ostringstream oss2;
std::ostringstream ossrow;
const size_t lineSize = 16; // 每行输出的字节数
const unsigned char* p = static_cast<const unsigned char*>(data);
int ic = 0;
int row = 0;
ossrow << std::setw(8) << std::setfill('0') << std::hex << row++ << "h : ";
oss << ossrow.str().c_str();
for( size_t i = 0; i < size; ++i )
{
ic++;
// 每个字节之间用空格分隔
oss << std::setw(2) << std::setfill('0') << std::hex << std::uppercase << static_cast<int>(p[i]);
char ch = (isprint(p[i]) != 0) ? p[i] : '.';
oss2 << ch;
// 每lineSize个字节换行
if( (i + 1) % lineSize == 0 )
{
ossrow.clear();
ossrow.str("");
oss << " [" << oss2.str().c_str() << "]" << std::endl;
oss2.clear();
oss2.str("");
ossrow << std::setw(8) << std::setfill('0') << std::hex << row++ << "h : ";
oss << ossrow.str().c_str();
ic = 0;
}
else if( i == size - 1 )
{
if( (i + 1) % lineSize != 0 )
{
if( i % 2 != 0 )
{
for( size_t j = 0; j < (lineSize - ic); j++ )
{
oss << " --";
}
}
else
{
for( size_t j = 0; j < (lineSize - ic); j++ )
{
oss << " --";
}
}
}
oss << " [" << oss2.str().c_str();
if( (i + 1) % lineSize != 0 )
{
for( size_t j = 0; j < (lineSize - ic); j++ )
{
oss << " ";
}
}
oss << "]" << std::endl;
oss2.clear();
oss2.str("");
ic = 0;
}
#if 0
else if( (i + 1) % 8 == 0 )
{
oss << " ";
oss2 << " ";
}
#endif
else
{
oss << " ";
}
}
return oss.str();
}
std::string get_current_timestamp()
{
auto now = std::chrono::system_clock::now();
//通过不同精度获取相差的毫秒数
uint64_t dis_millseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count()
- std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count() * 1000;
time_t tt = std::chrono::system_clock::to_time_t(now);
auto time_tm = localtime(&tt);
char strTime[25] = { 0 };
sprintf(strTime, "%d-%02d-%02d %02d:%02d:%02d.%03d", time_tm->tm_year + 1900,
time_tm->tm_mon + 1, time_tm->tm_mday, time_tm->tm_hour,
time_tm->tm_min, time_tm->tm_sec, (int)dis_millseconds);
return std::string(strTime);
}

View File

@ -0,0 +1,9 @@
#pragma once
#include <string>
#include <zlib/zlib.h>
int CompressString(const char* in_str, size_t in_len, std::string& out_str, int level);
int DecompressString(const char* in_str, size_t in_len, std::string& out_str);
std::string printHex(const void* data, size_t size);
std::string get_current_timestamp();

View File

@ -1,11 +1,10 @@
#include <string>
#include <chrono>
#include <fcntl.h>
#ifndef _WIN32
#include <unistd.h>
#endif
#include <fstream>
#include <memory>
#include <iomanip>
#include <sstream>
#include <hv/hv.h>
#include <hv/hmain.h>
@ -13,180 +12,28 @@
#include <hv/hloop.h>
#include <hv/hsocket.h>
#include <hv/hssl.h>
#include <zlib/zlib.h>
#include "mqtt_msg.h"
#include "openjson.h"
#include "kdefine.h"
#include "opmysql.h"
#include "eventhandler.h"
#include "iconv-utils.h"
#ifndef TEST_UNPACK
#define TEST_UNPACK 1
#define K22_STR_EXP(__A) #__A
#define K22_STR(__A) K22_STR_EXP(__A)
#define K22_CMS_VERSION_MAJOR 1
#define K22_CMS_VERSION_MINOR 215
#define K22_CMS_VERSION_REVISION 0
#define K22_VERSION K22_STR(K22_CMS_VERSION_MAJOR) "." K22_STR(K22_CMS_VERSION_MINOR) "." K22_STR(K22_CMS_VERSION_REVISION) ""
#define CHUNK 16384
/* Compress from file source to file dest until EOF on source.
def() returns Z_OK on success, Z_MEM_ERROR if memory could not be
allocated for processing, Z_STREAM_ERROR if an invalid compression
level is supplied, Z_VERSION_ERROR if the version of zlib.h and the
version of the library linked do not match, or Z_ERRNO if there is
an error reading or writing the files. */
int CompressString(const char* in_str, size_t in_len, std::string& out_str, int level)
{
if (!in_str)
return Z_DATA_ERROR;
int ret, flush;
unsigned have;
z_stream strm;
unsigned char out[CHUNK];
/* allocate deflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
ret = deflateInit(&strm, level);
if (ret != Z_OK)
return ret;
std::shared_ptr<z_stream> sp_strm(&strm, [](z_stream* strm)
{
(void)deflateEnd(strm);
});
const char* end = in_str + in_len;
//size_t pos_index = 0;
size_t distance = 0;
/* compress until end of file */
do
{
distance = end - in_str;
strm.avail_in = (distance >= CHUNK) ? CHUNK : distance;
strm.next_in = (Bytef*)in_str;
// next pos
in_str += strm.avail_in;
flush = (in_str == end) ? Z_FINISH : Z_NO_FLUSH;
/* run deflate() on input until output buffer not full, finish
compression if all of source has been read in */
do
{
strm.avail_out = CHUNK;
strm.next_out = out;
ret = deflate(&strm, flush); /* no bad return value */
if (ret == Z_STREAM_ERROR)
break;
have = CHUNK - strm.avail_out;
out_str.append((const char*)out, have);
} while (strm.avail_out == 0);
if (strm.avail_in != 0); /* all input will be used */
break;
/* done when last data in file processed */
} while (flush != Z_FINISH);
if (ret != Z_STREAM_END) /* stream will be complete */
return Z_STREAM_ERROR;
/* clean up and return */
return Z_OK;
}
/* Decompress from file source to file dest until stream ends or EOF.
inf() returns Z_OK on success, Z_MEM_ERROR if memory could not be
allocated for processing, Z_DATA_ERROR if the deflate data is
invalid or incomplete, Z_VERSION_ERROR if the version of zlib.h and
the version of the library linked do not match, or Z_ERRNO if there
is an error reading or writing the files. */
int DecompressString(const char* in_str, size_t in_len, std::string& out_str)
{
if (!in_str)
return Z_DATA_ERROR;
int ret;
unsigned have;
z_stream strm;
unsigned char out[CHUNK];
/* allocate inflate state */
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
ret = inflateInit(&strm);
if (ret != Z_OK)
return ret;
std::shared_ptr<z_stream> sp_strm(&strm, [](z_stream* strm)
{
(void)inflateEnd(strm);
});
const char* end = in_str + in_len;
//size_t pos_index = 0;
size_t distance = 0;
int flush = 0;
/* decompress until deflate stream ends or end of file */
do
{
distance = end - in_str;
strm.avail_in = (distance >= CHUNK) ? CHUNK : distance;
strm.next_in = (Bytef*)in_str;
// next pos
in_str += strm.avail_in;
flush = (in_str == end) ? Z_FINISH : Z_NO_FLUSH;
/* run inflate() on input until output buffer not full */
do
{
strm.avail_out = CHUNK;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
if (ret == Z_STREAM_ERROR) /* state not clobbered */
break;
switch (ret)
{
case Z_NEED_DICT:
ret = Z_DATA_ERROR; /* and fall through */
case Z_DATA_ERROR:
case Z_MEM_ERROR:
return ret;
}
have = CHUNK - strm.avail_out;
out_str.append((const char*)out, have);
} while (strm.avail_out == 0);
/* done when inflate() says it's done */
} while (flush != Z_FINISH);
/* clean up and return */
return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
}
//static OpDatabase gOpDatabase;
#endif
#if TEST_UNPACK
static unpack_setting_t unpack_setting;
#endif
//连接关闭回调
static void on_close(hio_t* io);
//接入回调
static void on_accept(hio_t* io);
//接收到数据
static void on_recv(hio_t* io, void* buf, int readbytes);
//重载参数回调
static void on_reload(void* userdata);
/*
* @build: make
* @usage: datahubs -h
@ -212,6 +59,7 @@ typedef struct conf_ctx_s
std::string dbuser;
std::string dbname;
} conf_ctx_t;
conf_ctx_t g_conf_ctx;
inline void conf_ctx_init(conf_ctx_t* ctx)
@ -284,6 +132,7 @@ int parse_confile(const char* confile)
strncpy(g_main_ctx.logfile, str.c_str(), sizeof(g_main_ctx.logfile));
}
hlog_set_file(g_main_ctx.logfile);
#if 1
// loglevel
str = g_conf_ctx.parser->GetValue("loglevel");
if (!str.empty())
@ -308,14 +157,26 @@ int parse_confile(const char* confile)
{
logger_enable_fsync(hlog, hv_getboolean(str.c_str()));
}
// first log here
#endif
// first log here
hlogi("=========--- Welcome to the Earth ---=========");
hlogi("%s version: %s", g_main_ctx.program_name, K22_VERSION);
hlog_fsync();
#if 0
g_conf_ctx.worker_processes = 1;
g_conf_ctx.worker_threads = 1;
g_conf_ctx.host = "0.0.0.0";
g_conf_ctx.port = 44242;
g_conf_ctx.dbname = "hjems";
g_conf_ctx.dbuser = "root";
g_conf_ctx.dbserver = "tcp://127.0.0.1:3306";
#endif
// worker_processes
int worker_processes = 0;
#if 1
#ifdef DEBUG
// Disable multi-processes mode for debugging
worker_processes = 0;
@ -351,6 +212,7 @@ int parse_confile(const char* confile)
worker_threads = atoi(str.c_str());
}
}
g_conf_ctx.worker_threads = LIMIT(0, worker_threads, 64);
//host
@ -422,15 +284,10 @@ int parse_confile(const char* confile)
hlogi("dbserver = ('%s')", g_conf_ctx.dbserver.c_str());
hlogi("parse_confile('%s') OK", confile);
#endif
return 0;
}
static void on_reload(void* userdata)
{
hlogi("reload confile [%s]", g_main_ctx.confile);
parse_confile(g_main_ctx.confile);
}
//////1///////////////////////////////
#if 0
#define LOCKFILE "/var/lock/datahub.lock"
@ -537,6 +394,14 @@ int main(int argc, char** argv)
exit(0);
}
// signal
signal_init(on_reload);
const char* signal = get_arg("s");
if( signal )
{
signal_handle(signal);
}
// g_conf_ctx
conf_ctx_init(&g_conf_ctx);
const char* confile = get_arg("c");
@ -553,13 +418,6 @@ int main(int argc, char** argv)
exit(0);
}
// signal
signal_init(on_reload);
const char* signal = get_arg("s");
if (signal)
{
signal_handle(signal);
}
#ifdef OS_UNIX
// daemon
@ -596,294 +454,55 @@ int main(int argc, char** argv)
return 0;
}
void worker_fn(void* userdata)
{
conf_ctx_t* ptrCtx = (conf_ctx_t*)(intptr_t)(userdata);
long port = ptrCtx->port;
//initialize database connection
bool dbok = OpDatabase::getInstance()->OpenDatabase(ptrCtx->dbserver,ptrCtx->dbuser,ptrCtx->dbname);
if (!dbok)
{
hloge("failed to open database, exit now...");
return;
}
hlogi("database connection created!");
hloop_t* loop = hloop_new(0);
const char* host = ptrCtx->host.c_str();
hio_t* listenio = hloop_create_tcp_server(loop, host, port, on_accept);
if (listenio == NULL)
{
hloge("worker process finished");
return;
}
hlogi("port=%ld pid=%ld tid=%ld listenfd=%d", port, hv_getpid(), hv_gettid(), hio_fd(listenio));
hloop_run(loop);
hlogi("database connection close!");
OpDatabase::getInstance()->CloseDatabase();
hloop_free(&loop);
}
/// 各回调函数定义
static void on_reload(void* userdata)
{
hlogi("reload confile [%s]", g_main_ctx.confile);
parse_confile(g_main_ctx.confile);
}
static void on_close(hio_t* io)
{
hlogi("on_close fd=%d error=%d", hio_fd(io), hio_error(io));
}
std::string get_current_timestamp()
{
auto now = std::chrono::system_clock::now();
//通过不同精度获取相差的毫秒数
uint64_t dis_millseconds = std::chrono::duration_cast<std::chrono::milliseconds>(now.time_since_epoch()).count()
- std::chrono::duration_cast<std::chrono::seconds>(now.time_since_epoch()).count() * 1000;
time_t tt = std::chrono::system_clock::to_time_t(now);
auto time_tm = localtime(&tt);
char strTime[25] = { 0 };
sprintf(strTime, "%d-%02d-%02d %02d:%02d:%02d.%03d", time_tm->tm_year + 1900,
time_tm->tm_mon + 1, time_tm->tm_mday, time_tm->tm_hour,
time_tm->tm_min, time_tm->tm_sec, (int)dis_millseconds);
return std::string(strTime);
}
// 函数用于将内存块转换为十六进制字符串
std::string printHex(const void* data, size_t size)
{
std::ostringstream oss;
std::ostringstream oss2;
std::ostringstream ossrow;
const size_t lineSize = 16; // 每行输出的字节数
const unsigned char* p = static_cast<const unsigned char*>(data);
int ic = 0;
int row = 0;
ossrow << std::setw(8) << std::setfill('0') << std::hex << row++ << "h : ";
oss << ossrow.str().c_str();
for (size_t i = 0; i < size; ++i)
{
ic++;
// 每个字节之间用空格分隔
oss << std::setw(2) << std::setfill('0') << std::hex << std::uppercase << static_cast<int>(p[i]);
char ch = (isprint(p[i]) != 0) ? p[i] : '.';
oss2 << ch;
// 每lineSize个字节换行
if ((i + 1) % lineSize == 0)
{
ossrow.clear();
ossrow.str("");
oss << " [" << oss2.str().c_str() << "]" << std::endl;
oss2.clear();
oss2.str("");
ossrow << std::setw(8) << std::setfill('0') << std::hex << row++ << "h : ";
oss << ossrow.str().c_str();
ic = 0;
}
else if (i == size - 1)
{
if ((i + 1) % lineSize != 0)
{
if (i % 2 != 0)
{
for (size_t j = 0; j < (lineSize - ic); j++)
{
oss << " --";
}
}
else
{
for (size_t j = 0; j < (lineSize - ic); j++)
{
oss << " --";
}
}
}
oss << " [" << oss2.str().c_str();
if ((i + 1) % lineSize != 0)
{
for (size_t j = 0; j < (lineSize - ic); j++)
{
oss << " ";
}
}
oss << "]" << std::endl;
oss2.clear();
oss2.str("");
ic = 0;
}
#if 0
else if ((i + 1) % 8 == 0)
{
oss << " ";
oss2 << " ";
}
#endif
else
{
oss << " ";
}
}
return oss.str();
}
//接收到数据
static void on_recv(hio_t* io, void* buf, int readbytes)
{
char localaddrstr[SOCKADDR_STRLEN] = { 0 };
char peeraddrstr[SOCKADDR_STRLEN] = { 0 };
hlogi("### 1 ### on_recv fd=%d readbytes=%d [%s] <==== [%s]", hio_fd(io), readbytes,
SOCKADDR_STR(hio_localaddr(io), localaddrstr),
SOCKADDR_STR(hio_peeraddr(io), peeraddrstr));
char ret[1] = { 0 };
if (readbytes > 0xFFFF - 1)
{
hloge("too large data buffer to process: %d", readbytes);
ret[0] = 1;
hio_write(io, (void*)ret, 1);
return;
}
MessageData* pData = (MessageData*)buf;
OpenJson json;
if (pData->content_len > 0xFFFF - 1)
{
hloge("too big string buffer to process: %d, it should be less than %d", pData->content_len, 0xFFFF);
ret[0] = 1;
hio_write(io, (void*)ret, 1);
return;
}
CODING buf_code = GetCoding((unsigned char*)pData->content_data, pData->content_len); //判断是否是utf-8
hlogi("<=== recieve buffer code is [%d]", buf_code);
std::string msg(pData->content_data, pData->content_len);
if (buf_code == CODING::GBK
|| buf_code == CODING::UNKOWN)
{
std::string str_result;
//转换为UTF8
if (!GBKToUTF8(msg, str_result))
{
hloge("Failed to transfer code from GBK to UTF-8");
ret[0] = 1;
hio_write(io, (void*)ret, 1);
return;
}
hlogi("Successfuly transfer code from GBK to UTF-8!");
msg = str_result;
}
#ifdef _DEBUG
hlogd("<=== recieve !!VALID!! mqtt pack len =[%d] data=[%s]", msg.length(), msg.c_str()); //这里还是好的
#endif
unsigned int len = msg.length();
char* pTmp = new char[len];
memcpy(pTmp, msg.c_str(), len);
std::shared_ptr<char> ptr; //放个智能指针省得忘记删除
ptr.reset(pTmp);
//hlogi("<=== decode OK, msg=[%s]", msg.c_str());
#if 0
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 17).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 18).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 19).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 20).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 21).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 22).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 23).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 24).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 25).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 26).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 27).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 28).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 29).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 30).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 31).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 32).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 33).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 34).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 61).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 62).c_str());
hlogi("<=== decode OK [\n%s\n]", printHex(pTmp, 63).c_str());
#endif
//hlogd("<=== decode OK [\n%s\n]", printHex(pTmp, len).c_str());
if (!json.decode(msg))
{
//delete[] pTmp;
hloge("Failed to decode json string pack , length=%d", readbytes);
ret[0] = 1;
hio_write(io, (void*)ret, 1);
return;
}
hio_write(io, (void*)ret, 1);
std::string fsucode = json["FsuCode"].s();
std::string msg_type = json["type"].s();
std::string timestamp = get_current_timestamp(); // json["TimeStamp"].s();
if (fsucode.length() == 0)
{
//delete[] pTmp;
hlogw("!!empty fsucode recieved!");
return;
}
hlogi("<=== decode OK, recieve fsucode=[%s] type=[%s] ts=[%s]", fsucode.c_str(), msg_type.c_str(), timestamp.c_str());
#ifdef _DEBUG
hlogd("<<<<Check Mem after decode here>>>> \n[\n%s\n]\n", printHex(pTmp, len).c_str());
#endif
std::string out_compress;
int zip_ret = 0;
if ((zip_ret = CompressString(pTmp, len, out_compress, Z_DEFAULT_COMPRESSION)) != Z_OK)
{
hloge("Failed to compress source data, zip return value %d", zip_ret);
return;
}
hlogd("<<<<Compress result: string size from original [%d] to [%d]", len, out_compress.size());
#ifdef _DEBUG
hlogd("<<<<Compress string here>>>> \n[\n%s\n]\n", printHex(out_compress.c_str(), out_compress.size()).c_str());
#endif
//std::string msg2(pTmp, len);
if (msg_type == "gateway-data"
|| msg_type == "gateway-alarmdata"
|| msg_type == "gateway-writedata"
|| msg_type == "gateway-readdata"
|| msg_type == "web-write"
|| msg_type == "web-alarm")
{
auto& IdCodeContent = json["IdCodeContent"];
if (IdCodeContent.size() <= 0)
{
//delete[] pTmp;
hloge("invalid IdCodeContent's size: %d", IdCodeContent.size());
return;
}
auto& pNode = IdCodeContent[0]; //这是只解析第一个节点
std::string oid = pNode["OID"].s();
OpDatabase::getInstance()->InsertMessage(timestamp, msg_type, fsucode, out_compress, (int)pData->mqtt_topic, (int)pData->device_id);
}
if (msg_type == "web-read")
{
auto& IdCodeContent = json["IdCodes"];
if (IdCodeContent.size() <= 0)
{
hloge("invalid IdCodes's size: %d", IdCodeContent.size());
//delete[] pTmp;
return;
}
auto& pNode = IdCodeContent[0]; //这是只解析第一个节点
std::string oid = pNode.s();
OpDatabase::getInstance()->InsertMessage(timestamp, msg_type, fsucode, out_compress, (int)pData->mqtt_topic, (int)pData->device_id);
}
//delete[] pTmp;
}
//接入回调
static void on_accept(hio_t* io)
{
@ -905,37 +524,9 @@ static void on_accept(hio_t* io)
hio_read_start(io);
}
void worker_fn(void* userdata)
//接收到数据
static void on_recv(hio_t* io, void* buf, int readbytes)
{
conf_ctx_t* ptrCtx = (conf_ctx_t*)(intptr_t)(userdata);
long port = ptrCtx->port;
//initialize database connection
bool dbok = OpDatabase::getInstance()->OpenDatabase(ptrCtx->dbserver,ptrCtx->dbuser,ptrCtx->dbname);
if (!dbok)
{
hloge("failed to open database, exit now...");
return;
EventHandler::onRecvHandler(io, buf, readbytes);
}
hlogi("database connection created!");
hloop_t* loop = hloop_new(0);
const char* host = ptrCtx->host.c_str();
hio_t* listenio = hloop_create_tcp_server(loop, host, port, on_accept);
if (listenio == NULL)
{
hlogw("worker process finished");
return;
}
hlogi("port=%ld pid=%ld tid=%ld listenfd=%d", port, hv_getpid(), hv_gettid(), hio_fd(listenio));
hloop_run(loop);
hlogi("database connection close!");
OpDatabase::getInstance()->CloseDatabase();
hloop_free(&loop);
}

View File

@ -1,5 +1,12 @@
#pragma once
#include "kdefine.h"
#pragma pack(1)
__NAMESPACE_BEGIN__(HJ)
#define MSG_HEADER_LENGTH (8)
typedef enum tagTopic : char
{
GateWayPublicTopic_Server = 0,
@ -15,7 +22,9 @@ typedef enum tagDataType : char
DT_GATEWAY_CTRLDATA = 4,
DT_WEB_CTRL = 5,
DT_WEB_WRITE = 6,
DT_GATEWAY_WRITE = 7
DT_GATEWAY_WRITE = 7,
FRAME_REQUEST = 8,
FRAME_RESPONSE = 9,
}MQTT_DataType;
/*
@ -47,4 +56,6 @@ typedef struct tagMsgData
char content_data[1]; //MQTT包字符串的内容
}MessageData;
__NAMESPACE_END__(HJ)
#pragma pack()

View File

@ -20,10 +20,13 @@
#include <stdarg.h>
#include <string>
#include <hv/hlog.h>
#include "openjson.h"
//#define PRINTF printf
#define PRINTF hloge
#define PRINTF printf
#if (defined(_MSC_VER) && (_MSC_VER >= 1400 ))
inline int SNPRINTF(char* buffer, size_t size, const char* format, ...)
{
@ -188,10 +191,10 @@ bool OpenJson::Box::remove(OpenJson* node)
//JsonContext
OpenJson::Context::Context()
:
offset_(0),
data_(0),
root_(0),
size_(0)
size_(0),
offset_(0),
root_(0)
{
}
@ -278,10 +281,10 @@ OpenJson::OpenJson(JsonType type)
:type_(type),
context_(0),
wcontext_(0),
box_(0),
idx_(0),
key_(0),
len_(0),
box_(0),
key_(0),
segment_(0)
{
}
@ -783,12 +786,16 @@ OpenJson& OpenJson::object(const char* key)
{
if (type_ == ARRAY)
{
Log("JsonNode must be OBJECT, not ARRAY");
PRINTF("JsonNode must be OBJECT, not ARRAY");
}
type_ = OBJECT;
}
else
{
if( !box_ )
{
PRINTF("JsonNode must be OBJECT, not NOTHING! key:[%s]", key);
}
assert(box_);
}
if (!box_) box_ = new Box;
@ -828,7 +835,7 @@ void OpenJson::addNode(OpenJson* node)
if (!node) return;
if (type_ != OBJECT && type_ != ARRAY)
{
Log("JsonNode must be OBJECT or ARRAY");
PRINTF("JsonNode must be OBJECT or ARRAY");
type_ = node->key_ ? OBJECT : ARRAY;
}
if (box_ == 0) box_ = new Box;

View File

@ -34,7 +34,8 @@ bool OpDatabase::OpenDatabase(const std::string& server, const std::string& dbus
// 数据库连接配置
//std::string server = "tcp://127.0.0.1:3306";
//std::string dbuser = "root";
std::string password = "Hj57471000";
//std::string password = "Hj57471000";
std::string password = "L2ysc1s1kr";
//std::string database = "hjems";
// 创建连接

View File

@ -1,27 +1,35 @@
/*
Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C++ is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
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 General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
* published by the Free Software Foundation.
*
* This program is also distributed with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an
* additional permission to link the program and your derivative works
* with the separately licensed software that they have included with
* MySQL.
*
* Without limiting anything contained in the foregoing, this file,
* which is part of MySQL Connector/C++, is also subject to the
* Universal FOSS Exception, version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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 General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _SQL_BUILD_CONFIG_H_
#define _SQL_BUILD_CONFIG_H_

View File

@ -1,12 +1,31 @@
/*
Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C++ is licensed under the terms of the GPL
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPL as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
* Copyright (c) 2009, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
* published by the Free Software Foundation.
*
* This program is also distributed with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an
* additional permission to link the program and your derivative works
* with the separately licensed software that they have included with
* MySQL.
*
* Without limiting anything contained in the foregoing, this file,
* which is part of MySQL Connector/C++, is also subject to the
* Universal FOSS Exception, version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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 General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
// libmysql defines HAVE_STRTOUL (on win), so we have to follow different pattern in definitions names
@ -35,27 +54,34 @@
#define HAVE_UINT32_T 1
#define HAVE_INT64_T 1
#define HAVE_UINT64_T 1
/* #undef HAVE_MS_INT8 */
/* #undef HAVE_MS_UINT8 */
/* #undef HAVE_MS_INT16 */
/* #undef HAVE_MS_UINT16 */
/* #undef HAVE_MS_INT32 */
/* #undef HAVE_MS_UINT32 */
/* #undef HAVE_MS_INT64 */
/* #undef HAVE_MS_UINT64 */
#define HAVE_MS_INT8 1
#define HAVE_MS_UINT8 1
#define HAVE_MS_INT16 1
#define HAVE_MS_UINT16 1
#define HAVE_MS_INT32 1
#define HAVE_MS_UINT32 1
#define HAVE_MS_INT64 1
#define HAVE_MS_UINT64 1
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#ifdef HAVE_INTTYPES_H
#if defined(HAVE_INTTYPES_H) && !defined(_WIN32)
#include <inttypes.h>
#endif
#if defined(_WIN32)
#ifndef CPPCONN_DONT_TYPEDEF_MS_TYPES_TO_C99_TYPES
#if _MSC_VER >= 1600
#include <stdint.h>
#else
#if !defined(HAVE_INT8_T) && defined(HAVE_MS_INT8)
typedef __int8 int8_t;
#endif
@ -86,5 +112,6 @@ typedef __int64 int64_t;
typedef unsigned __int64 uint64_t;
#endif
#endif // _MSC_VER >= 1600
#endif // CPPCONN_DONT_TYPEDEF_MS_TYPES_TO_C99_TYPES
#endif // _WIN32

View File

@ -1,42 +1,49 @@
/*
Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C++ is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
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 General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
* published by the Free Software Foundation.
*
* This program is also distributed with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an
* additional permission to link the program and your derivative works
* with the separately licensed software that they have included with
* MySQL.
*
* Without limiting anything contained in the foregoing, this file,
* which is part of MySQL Connector/C++, is also subject to the
* Universal FOSS Exception, version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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 General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _SQL_CONNECTION_H_
#define _SQL_CONNECTION_H_
#include <map>
#include <boost/variant.hpp>
#include "build_config.h"
#include "warning.h"
#include "sqlstring.h"
#include "variant.h"
namespace sql
{
typedef boost::variant<int, double, bool, sql::SQLString > ConnectPropertyVal;
typedef sql::Variant ConnectPropertyVal;
typedef std::map< sql::SQLString, ConnectPropertyVal > ConnectOptionsMap;
@ -54,6 +61,12 @@ typedef enum transaction_isolation
TRANSACTION_SERIALIZABLE
} enum_transaction_isolation;
enum ssl_mode
{
SSL_MODE_DISABLED= 1, SSL_MODE_PREFERRED, SSL_MODE_REQUIRED,
SSL_MODE_VERIFY_CA, SSL_MODE_VERIFY_IDENTITY
};
class Savepoint
{
/* Prevent use of these */
@ -99,6 +112,8 @@ public:
virtual void getClientOption(const sql::SQLString & optionName, void * optionValue) = 0;
virtual sql::SQLString getClientOption(const sql::SQLString & optionName) = 0;
virtual DatabaseMetaData * getMetaData() = 0;
virtual enum_transaction_isolation getTransactionIsolation() = 0;
@ -109,6 +124,10 @@ public:
virtual bool isReadOnly() = 0;
virtual bool isValid() = 0;
virtual bool reconnect() = 0;
virtual sql::SQLString nativeSQL(const sql::SQLString& sql) = 0;
virtual PreparedStatement * prepareStatement(const sql::SQLString& sql) = 0;
@ -137,6 +156,8 @@ public:
virtual sql::Connection * setClientOption(const sql::SQLString & optionName, const void * optionValue) = 0;
virtual sql::Connection * setClientOption(const sql::SQLString & optionName, const sql::SQLString & optionValue) = 0;
virtual void setHoldability(int holdability) = 0;
virtual void setReadOnly(bool readOnly) = 0;

View File

@ -1,27 +1,35 @@
/*
Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C++ is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
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 General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
* published by the Free Software Foundation.
*
* This program is also distributed with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an
* additional permission to link the program and your derivative works
* with the separately licensed software that they have included with
* MySQL.
*
* Without limiting anything contained in the foregoing, this file,
* which is part of MySQL Connector/C++, is also subject to the
* Universal FOSS Exception, version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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 General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _SQL_DATATYPE_H_
#define _SQL_DATATYPE_H_
@ -57,7 +65,8 @@ public:
GEOMETRY,
ENUM,
SET,
SQLNULL
SQLNULL,
JSON
};
};

View File

@ -1,27 +1,35 @@
/*
Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C++ is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
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 General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
* published by the Free Software Foundation.
*
* This program is also distributed with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an
* additional permission to link the program and your derivative works
* with the separately licensed software that they have included with
* MySQL.
*
* Without limiting anything contained in the foregoing, this file,
* which is part of MySQL Connector/C++, is also subject to the
* Universal FOSS Exception, version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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 General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _SQL_DRIVER_H_
#define _SQL_DRIVER_H_

View File

@ -1,27 +1,35 @@
/*
Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C++ is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
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 General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
* published by the Free Software Foundation.
*
* This program is also distributed with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an
* additional permission to link the program and your derivative works
* with the separately licensed software that they have included with
* MySQL.
*
* Without limiting anything contained in the foregoing, this file,
* which is part of MySQL Connector/C++, is also subject to the
* Universal FOSS Exception, version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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 General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _SQL_EXCEPTION_H_
#define _SQL_EXCEPTION_H_
@ -33,6 +41,7 @@
namespace sql
{
#if (__cplusplus < 201103L)
#define MEMORY_ALLOC_OPERATORS(Class) \
void* operator new(size_t size) throw (std::bad_alloc) { return ::operator new(size); } \
void* operator new(size_t, void*) throw(); \
@ -41,7 +50,17 @@ namespace sql
void* operator new[](size_t, void*) throw(); \
void* operator new[](size_t, const std::nothrow_t&) throw(); \
void* operator new(size_t N, std::allocator<Class>&);
#else
#define MEMORY_ALLOC_OPERATORS(Class) \
void* operator new(size_t size){ return ::operator new(size); } \
void* operator new(size_t, void*) noexcept; \
void* operator new(size_t, const std::nothrow_t&) noexcept; \
void* operator new[](size_t); \
void* operator new[](size_t, void*) noexcept; \
void* operator new[](size_t, const std::nothrow_t&) noexcept; \
void* operator new(size_t N, std::allocator<Class>&);
#endif
#ifdef _WIN32
#pragma warning (disable : 4290)
//warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
@ -121,6 +140,29 @@ struct CPPCONN_PUBLIC_FUNC NonScrollableException : public SQLException
NonScrollableException(const std::string& reason) : SQLException(reason, "", 0) {}
};
struct CPPCONN_PUBLIC_FUNC SQLUnsupportedOptionException : public SQLException
{
SQLUnsupportedOptionException(const SQLUnsupportedOptionException& e, const std::string conn_option) :
SQLException(e.what(), e.sql_state, e.errNo),
option(conn_option )
{}
SQLUnsupportedOptionException(const std::string& reason, const std::string conn_option) :
SQLException(reason, "", 0),
option(conn_option )
{}
const char *getConnectionOption() const
{
return option.c_str();
}
~SQLUnsupportedOptionException() throw () {};
protected:
const std::string option;
};
} /* namespace sql */
#endif /* _SQL_EXCEPTION_H_ */

View File

@ -1,27 +1,35 @@
/*
Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C++ is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
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 General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
* published by the Free Software Foundation.
*
* This program is also distributed with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an
* additional permission to link the program and your derivative works
* with the separately licensed software that they have included with
* MySQL.
*
* Without limiting anything contained in the foregoing, this file,
* which is part of MySQL Connector/C++, is also subject to the
* Universal FOSS Exception, version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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 General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _SQL_METADATA_H_
#define _SQL_METADATA_H_
@ -245,6 +253,10 @@ public:
virtual const sql::SQLString& getSchemaTerm() = 0;
virtual ResultSet * getSchemaCollation(const sql::SQLString& catalog, const sql::SQLString& schemaPattern) = 0;
virtual ResultSet * getSchemaCharset(const sql::SQLString& catalog, const sql::SQLString& schemaPattern) = 0;
virtual const sql::SQLString& getSearchStringEscape() = 0;
virtual const sql::SQLString& getSQLKeywords() = 0;
@ -265,6 +277,10 @@ public:
virtual ResultSet * getTableTypes() = 0;
virtual ResultSet * getTableCollation(const sql::SQLString& catalog, const sql::SQLString& schemaPattern, const sql::SQLString& tableNamePattern) = 0;
virtual ResultSet * getTableCharset(const sql::SQLString& catalog, const sql::SQLString& schemaPattern, const sql::SQLString& tableNamePattern) = 0;
virtual const sql::SQLString& getTimeDateFunctions() = 0;
virtual ResultSet * getTypeInfo() = 0;

View File

@ -1,27 +1,35 @@
/*
Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C++ is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
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 General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
* published by the Free Software Foundation.
*
* This program is also distributed with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an
* additional permission to link the program and your derivative works
* with the separately licensed software that they have included with
* MySQL.
*
* Without limiting anything contained in the foregoing, this file,
* which is part of MySQL Connector/C++, is also subject to the
* Universal FOSS Exception, version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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 General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _SQL_PARAMETER_METADATA_H_
#define _SQL_PARAMETER_METADATA_H_

View File

@ -1,28 +1,36 @@
/*
Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C++ is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
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 General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
* published by the Free Software Foundation.
*
* This program is also distributed with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an
* additional permission to link the program and your derivative works
* with the separately licensed software that they have included with
* MySQL.
*
* Without limiting anything contained in the foregoing, this file,
* which is part of MySQL Connector/C++, is also subject to the
* Universal FOSS Exception, version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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 General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _SQL_PREPARED_STATEMENT_H_
#define _SQL_PREPARED_STATEMENT_H_
@ -58,6 +66,8 @@ public:
virtual ParameterMetaData * getParameterMetaData() = 0;
virtual bool getMoreResults() = 0;
virtual void setBigInt(unsigned int parameterIndex, const sql::SQLString& value) = 0;
virtual void setBlob(unsigned int parameterIndex, std::istream * blob) = 0;

View File

@ -1,27 +1,35 @@
/*
Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C++ is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
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 General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
* published by the Free Software Foundation.
*
* This program is also distributed with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an
* additional permission to link the program and your derivative works
* with the separately licensed software that they have included with
* MySQL.
*
* Without limiting anything contained in the foregoing, this file,
* which is part of MySQL Connector/C++, is also subject to the
* Universal FOSS Exception, version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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 General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _SQL_RESULTSET_H_
#define _SQL_RESULTSET_H_

View File

@ -1,27 +1,35 @@
/*
Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C++ is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
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 General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
* published by the Free Software Foundation.
*
* This program is also distributed with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an
* additional permission to link the program and your derivative works
* with the separately licensed software that they have included with
* MySQL.
*
* Without limiting anything contained in the foregoing, this file,
* which is part of MySQL Connector/C++, is also subject to the
* Universal FOSS Exception, version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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 General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _SQL_RESULTSET_METADATA_H_
#define _SQL_RESULTSET_METADATA_H_
@ -55,6 +63,10 @@ public:
virtual SQLString getColumnTypeName(unsigned int column) = 0;
virtual SQLString getColumnCharset(unsigned int columnIndex) = 0;
virtual SQLString getColumnCollation(unsigned int columnIndex) = 0;
virtual unsigned int getPrecision(unsigned int column) = 0;
virtual unsigned int getScale(unsigned int column) = 0;
@ -73,6 +85,8 @@ public:
virtual int isNullable(unsigned int column) = 0;
virtual bool isNumeric(unsigned int column) = 0;
virtual bool isReadOnly(unsigned int column) = 0;
virtual bool isSearchable(unsigned int column) = 0;

View File

@ -1,31 +1,40 @@
/*
Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C++ is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
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 General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
* published by the Free Software Foundation.
*
* This program is also distributed with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an
* additional permission to link the program and your derivative works
* with the separately licensed software that they have included with
* MySQL.
*
* Without limiting anything contained in the foregoing, this file,
* which is part of MySQL Connector/C++, is also subject to the
* Universal FOSS Exception, version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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 General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _SQL_STRING_H_
#define _SQL_STRING_H_
#include <string>
#include <algorithm>
#include "build_config.h"
#include <iostream>
@ -102,6 +111,30 @@ namespace sql
return realStr.compare(pos1, n1, s);
}
int caseCompare(const SQLString &s) const
{
std::string tmp(realStr), str(s);
std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
return tmp.compare(str);
}
int caseCompare(const char * s) const
{
std::string tmp(realStr), str(s);
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
return tmp.compare(str);
}
int caseCompare(size_t pos1, size_t n1, const char * s) const
{
std::string tmp(realStr.c_str() + pos1, n1), str(s);
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
std::transform(tmp.begin(), tmp.end(), tmp.begin(), ::tolower);
return tmp.compare(str);
}
const std::string & asStdString() const
{
return realStr;

View File

@ -1,27 +1,35 @@
/*
Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C++ is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
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 General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
* published by the Free Software Foundation.
*
* This program is also distributed with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an
* additional permission to link the program and your derivative works
* with the separately licensed software that they have included with
* MySQL.
*
* Without limiting anything contained in the foregoing, this file,
* which is part of MySQL Connector/C++, is also subject to the
* Universal FOSS Exception, version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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 General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _SQL_STATEMENT_H_
#define _SQL_STATEMENT_H_

View File

@ -1,27 +1,35 @@
/*
Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
The MySQL Connector/C++ is licensed under the terms of the GPLv2
<http://www.gnu.org/licenses/old-licenses/gpl-2.0.html>, like most
MySQL Connectors. There are special exceptions to the terms and
conditions of the GPLv2 as it is applied to this software, see the
FLOSS License Exception
<http://www.mysql.com/about/legal/licensing/foss-exception.html>.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published
by the Free Software Foundation; version 2 of the License.
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 General Public License
for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
* Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License, version 2.0, as
* published by the Free Software Foundation.
*
* This program is also distributed with certain software (including
* but not limited to OpenSSL) that is licensed under separate terms,
* as designated in a particular file or component or in included license
* documentation. The authors of MySQL hereby grant you an
* additional permission to link the program and your derivative works
* with the separately licensed software that they have included with
* MySQL.
*
* Without limiting anything contained in the foregoing, this file,
* which is part of MySQL Connector/C++, is also subject to the
* Universal FOSS Exception, version 1.0, a copy of which can be found at
* http://oss.oracle.com/licenses/universal-foss-exception.
*
* 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 General Public License, version 2.0, for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef _SQL_WARNING_H_
#define _SQL_WARNING_H_
@ -59,7 +67,7 @@ protected:
virtual ~SQLWarning(){};
SQLWarning(const SQLWarning& e){};
SQLWarning(const SQLWarning&){};
private:
const SQLWarning & operator = (const SQLWarning & rhs);

View File

@ -0,0 +1,164 @@
#ifndef HV_ASYNC_HTTP_CLIENT_H_
#define HV_ASYNC_HTTP_CLIENT_H_
#include <map>
#include <list>
#include "EventLoopThread.h"
#include "Channel.h"
#include "HttpMessage.h"
#include "HttpParser.h"
namespace hv {
template<typename Conn>
class ConnPool {
public:
int size() {
return conns_.size();
}
bool get(Conn& conn) {
if (conns_.empty()) return false;
conn = conns_.front();
conns_.pop_front();
return true;
}
bool add(const Conn& conn) {
conns_.push_back(conn);
return true;
}
bool remove(const Conn& conn) {
auto iter = conns_.begin();
while (iter != conns_.end()) {
if (*iter == conn) {
iter = conns_.erase(iter);
return true;
} else {
++iter;
}
}
return false;
}
private:
std::list<Conn> conns_;
};
struct HttpClientTask {
HttpRequestPtr req;
HttpResponseCallback cb;
uint64_t start_time;
};
typedef std::shared_ptr<HttpClientTask> HttpClientTaskPtr;
struct HttpClientContext {
HttpClientTaskPtr task;
HttpResponsePtr resp;
HttpParserPtr parser;
TimerID timerID;
HttpClientContext() {
timerID = INVALID_TIMER_ID;
}
~HttpClientContext() {
cancelTimer();
}
void cancelTimer() {
if (timerID != INVALID_TIMER_ID) {
killTimer(timerID);
timerID = INVALID_TIMER_ID;
}
}
void cancelTask() {
cancelTimer();
task = NULL;
}
void callback() {
cancelTimer();
if (task && task->cb) {
task->cb(resp);
}
// NOTE: task done
task = NULL;
}
void successCallback() {
callback();
resp = NULL;
}
void errorCallback() {
resp = NULL;
callback();
}
};
class HV_EXPORT AsyncHttpClient : private EventLoopThread {
public:
AsyncHttpClient(EventLoopPtr loop = NULL) : EventLoopThread(loop) {
if (loop == NULL) {
EventLoopThread::start(true);
}
}
~AsyncHttpClient() {
EventLoopThread::stop(true);
}
// thread-safe
int send(const HttpRequestPtr& req, HttpResponseCallback resp_cb);
int send(const HttpClientTaskPtr& task) {
EventLoopThread::loop()->queueInLoop(std::bind(&AsyncHttpClient::sendInLoop, this, task));
return 0;
}
protected:
void sendInLoop(HttpClientTaskPtr task) {
int err = doTask(task);
if (err != 0 && task->cb) {
task->cb(NULL);
}
}
int doTask(const HttpClientTaskPtr& task);
static int sendRequest(const SocketChannelPtr& channel);
// channel
const SocketChannelPtr& getChannel(int fd) {
return channels[fd];
// return fd < channels.capacity() ? channels[fd] : NULL;
}
const SocketChannelPtr& addChannel(hio_t* io) {
auto channel = std::make_shared<SocketChannel>(io);
channel->newContext<HttpClientContext>();
int fd = channel->fd();
channels[fd] = channel;
return channels[fd];
}
void removeChannel(const SocketChannelPtr& channel) {
channel->deleteContext<HttpClientContext>();
int fd = channel->fd();
channels.erase(fd);
}
private:
// NOTE: just one loop thread, no need mutex.
// fd => SocketChannelPtr
std::map<int, SocketChannelPtr> channels;
// peeraddr => ConnPool
std::map<std::string, ConnPool<int>> conn_pools;
};
}
#endif // HV_ASYNC_HTTP_CLIENT_H_

View File

@ -241,7 +241,7 @@ typedef std::shared_ptr<EventLoop> EventLoopPtr;
static inline EventLoop* tlsEventLoop() {
return (EventLoop*)ThreadLocalStorage::get(ThreadLocalStorage::EVENT_LOOP);
}
#define currentThreadEventLoop tlsEventLoop()
#define currentThreadEventLoop ::hv::tlsEventLoop()
static inline TimerID setTimer(int timeout_ms, TimerCallback cb, uint32_t repeat = INFINITE) {
EventLoop* loop = tlsEventLoop();

View File

@ -44,6 +44,7 @@ public:
Functor pre = Functor(),
Functor post = Functor()) {
if (status() >= kStarting && status() < kStopped) return;
if (isRunning()) return;
setStatus(kStarting);
thread_ = std::make_shared<std::thread>(&EventLoopThread::loop_thread, this, pre, post);

View File

@ -8,7 +8,7 @@
/*
#include <stdio.h>
#include "http_client.h"
#include "HttpClient.h"
int main(int argc, char* argv[]) {
HttpRequest req;
@ -30,7 +30,6 @@ int main(int argc, char* argv[]) {
typedef struct http_client_s http_client_t;
HV_EXPORT http_client_t* http_client_new(const char* host = NULL, int port = DEFAULT_HTTP_PORT, int https = 0);
HV_EXPORT int http_client_close(http_client_t* cli);
HV_EXPORT int http_client_del(http_client_t* cli);
HV_EXPORT const char* http_client_strerror(int errcode);
@ -69,6 +68,15 @@ HV_EXPORT int http_client_send(HttpRequest* req, HttpResponse* resp);
// http_client_send_async(&default_async_client, ...)
HV_EXPORT int http_client_send_async(HttpRequestPtr req, HttpResponseCallback resp_cb = NULL);
// low-level api
// @retval >=0 connfd, <0 error
HV_EXPORT int http_client_connect(http_client_t* cli, const char* host, int port, int https, int timeout);
HV_EXPORT int http_client_send_header(http_client_t* cli, HttpRequest* req);
HV_EXPORT int http_client_send_data(http_client_t* cli, const char* data, int size);
HV_EXPORT int http_client_recv_data(http_client_t* cli, char* data, int size);
HV_EXPORT int http_client_recv_response(http_client_t* cli, HttpResponse* resp);
HV_EXPORT int http_client_close(http_client_t* cli);
namespace hv {
class HttpClient {
@ -134,7 +142,22 @@ public:
return http_client_send_async(_client, req, std::move(resp_cb));
}
// close
// low-level api
int connect(const char* host, int port = DEFAULT_HTTP_PORT, int https = 0, int timeout = DEFAULT_HTTP_CONNECT_TIMEOUT) {
return http_client_connect(_client, host, port, https, timeout);
}
int sendHeader(HttpRequest* req) {
return http_client_send_header(_client, req);
}
int sendData(const char* data, int size) {
return http_client_send_data(_client, data, size);
}
int recvData(char* data, int size) {
return http_client_recv_data(_client, data, size);
}
int recvResponse(HttpResponse* resp) {
return http_client_recv_response(_client, resp);
}
int close() {
return http_client_close(_client);
}

View File

@ -46,19 +46,6 @@
#include "httpdef.h"
#include "http_content.h"
namespace hv {
struct NetAddr {
std::string ip;
int port;
std::string ipport() {
return hv::asprintf("%s:%d", ip.c_str(), port);
}
};
}
// https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Set-Cookie
// Cookie: sessionid=1; domain=.example.com; path=/; max-age=86400; secure; httponly
struct HV_EXPORT HttpCookie {
@ -297,6 +284,7 @@ public:
void* Content() {
if (content == NULL && body.size() != 0) {
content = (void*)body.data();
content_length = body.size();
}
return content;
}

View File

@ -3,9 +3,11 @@
#include "hexport.h"
#include "hssl.h"
// #include "EventLoop.h"
#include "HttpService.h"
// #include "WebSocketServer.h"
namespace hv {
class EventLoop;
struct WebSocketService;
}
using hv::HttpService;
@ -72,18 +74,16 @@ int main() {
return 200;
});
HttpServer server;
server.registerHttpService(&service);
server.setPort(8080);
HttpServer server(&service);
server.setThreadNum(4);
server.run();
server.run(":8080");
return 0;
}
*/
namespace hv {
class HttpServer : public http_server_t {
class HV_EXPORT HttpServer : public http_server_t {
public:
HttpServer(HttpService* service = NULL)
: http_server_t()
@ -96,6 +96,8 @@ public:
this->service = service;
}
std::shared_ptr<hv::EventLoop> loop(int idx = -1);
void setHost(const char* host = "0.0.0.0") {
if (host) strcpy(this->host, host);
}
@ -117,6 +119,11 @@ public:
this->worker_threads = num;
}
void setMaxWorkerConnectionNum(uint32_t num) {
this->worker_connections = num;
}
size_t connectionNum();
// SSL/TLS
int setSslCtx(hssl_ctx_t ssl_ctx) {
this->ssl_ctx = ssl_ctx;
@ -130,12 +137,20 @@ public:
return setSslCtx(ssl_ctx);
}
int run(bool wait = true) {
// run(":8080")
// run("0.0.0.0:8080")
// run("[::]:8080")
int run(const char* ip_port = NULL, bool wait = true) {
if (ip_port) {
hv::NetAddr listen_addr(ip_port);
if (listen_addr.ip.size() != 0) setHost(listen_addr.ip.c_str());
if (listen_addr.port != 0) setPort(listen_addr.port);
}
return http_server_run(this, wait);
}
int start() {
return run(false);
int start(const char* ip_port = NULL) {
return run(ip_port, false);
}
int stop() {

View File

@ -32,7 +32,11 @@ public:
}
EventLoopPtr loop(int idx = -1) {
return worker_threads.loop(idx);
EventLoopPtr worker_loop = worker_threads.loop(idx);
if (worker_loop == NULL) {
worker_loop = acceptor_loop;
}
return worker_loop;
}
//@retval >=0 listenfd, <0 error
@ -294,8 +298,10 @@ public:
// start thread-safe
void start(bool wait_threads_started = true) {
TcpServerEventLoopTmpl<TSocketChannel>::start(wait_threads_started);
if (!isRunning()) {
EventLoopThread::start(wait_threads_started);
}
}
// stop thread-safe
void stop(bool wait_threads_stopped = true) {

View File

@ -60,6 +60,7 @@ public:
if (ret != 0) {
perror("bind");
}
hio_set_localaddr(channel->io(), &local_addr.sa, SOCKADDR_LEN(&local_addr));
return ret;
}

View File

@ -36,7 +36,11 @@ HV_INLINE std::string Base64Decode(const char* str, unsigned int len = 0) {
int decoded_size = BASE64_DECODE_OUT_SIZE(len);
std::string decoded_buf(decoded_size + 1, 0);
decoded_size = hv_base64_decode(str, len, (unsigned char*)decoded_buf.data());
if (decoded_size > 0) {
decoded_buf.resize(decoded_size);
} else {
decoded_buf.clear();
}
return decoded_buf;
}

View File

@ -1,105 +0,0 @@
#ifndef HV_DNS_H_
#define HV_DNS_H_
#include "hexport.h"
#include "hplatform.h"
#define DNS_PORT 53
#define DNS_QUERY 0
#define DNS_RESPONSE 1
#define DNS_TYPE_A 1 // ipv4
#define DNS_TYPE_NS 2
#define DNS_TYPE_CNAME 5
#define DNS_TYPE_SOA 6
#define DNS_TYPE_WKS 11
#define DNS_TYPE_PTR 12
#define DNS_TYPE_HINFO 13
#define DNS_TYPE_MX 15
#define DNS_TYPE_AAAA 28 // ipv6
#define DNS_TYPE_AXFR 252
#define DNS_TYPE_ANY 255
#define DNS_CLASS_IN 1
#define DNS_NAME_MAXLEN 256
// sizeof(dnshdr_t) = 12
typedef struct dnshdr_s {
uint16_t transaction_id;
// flags
#if BYTE_ORDER == LITTLE_ENDIAN
uint8_t rd:1;
uint8_t tc:1;
uint8_t aa:1;
uint8_t opcode:4;
uint8_t qr:1;
uint8_t rcode:4;
uint8_t cd:1;
uint8_t ad:1;
uint8_t res:1;
uint8_t ra:1;
#elif BYTE_ORDER == BIG_ENDIAN
uint8_t qr:1; // DNS_QUERY or DNS_RESPONSE
uint8_t opcode:4;
uint8_t aa:1; // authoritative
uint8_t tc:1; // truncated
uint8_t rd:1; // recursion desired
uint8_t ra:1; // recursion available
uint8_t res:1; // reserved
uint8_t ad:1; // authenticated data
uint8_t cd:1; // checking disable
uint8_t rcode:4;
#else
#error "BYTE_ORDER undefined!"
#endif
uint16_t nquestion;
uint16_t nanswer;
uint16_t nauthority;
uint16_t naddtional;
} dnshdr_t;
typedef struct dns_rr_s {
char name[DNS_NAME_MAXLEN]; // original domain, such as www.example.com
uint16_t rtype;
uint16_t rclass;
uint32_t ttl;
uint16_t datalen;
char* data;
} dns_rr_t;
typedef struct dns_s {
dnshdr_t hdr;
dns_rr_t* questions;
dns_rr_t* answers;
dns_rr_t* authorities;
dns_rr_t* addtionals;
} dns_t;
BEGIN_EXTERN_C
// www.example.com => 3www7example3com
HV_EXPORT int dns_name_encode(const char* domain, char* buf);
// 3www7example3com => www.example.com
HV_EXPORT int dns_name_decode(const char* buf, char* domain);
HV_EXPORT int dns_rr_pack(dns_rr_t* rr, char* buf, int len);
HV_EXPORT int dns_rr_unpack(char* buf, int len, dns_rr_t* rr, int is_question);
HV_EXPORT int dns_pack(dns_t* dns, char* buf, int len);
HV_EXPORT int dns_unpack(char* buf, int len, dns_t* dns);
// NOTE: free dns->rrs
HV_EXPORT void dns_free(dns_t* dns);
// dns_pack -> sendto -> recvfrom -> dns_unpack
HV_EXPORT int dns_query(dns_t* query, dns_t* response, const char* nameserver DEFAULT("127.0.1.1"));
// domain -> dns_t query; -> dns_query -> dns_t response; -> addrs
HV_EXPORT int nslookup(const char* domain, uint32_t* addrs, int naddr, const char* nameserver DEFAULT("127.0.1.1"));
END_EXTERN_C
#endif // HV_DNS_H_

View File

@ -1,96 +0,0 @@
#ifndef HV_FTP_H_
#define HV_FTP_H_
#include "hexport.h"
#define FTP_COMMAND_PORT 21
#define FTP_DATA_PORT 20
// ftp_command
// X(name)
#define FTP_COMMAND_MAP(X) \
X(HELP) \
X(USER) \
X(PASS) \
X(PWD) \
X(CWD) \
X(CDUP) \
X(MKD) \
X(RMD) \
X(STAT) \
X(SIZE) \
X(DELE) \
X(RNFR) \
X(RNTO) \
X(PORT) \
X(PASV) \
X(LIST) \
X(NLST) \
X(APPE) \
X(RETR) \
X(STOR) \
X(QUIT) \
enum ftp_command {
#define X(name) FTP_##name,
FTP_COMMAND_MAP(X)
#undef X
};
// ftp_status
// XXX(code, name, string)
#define FTP_STATUS_MAP(XXX) \
XXX(220, READY, Ready) \
XXX(221, BYE, Bye) \
XXX(226, TRANSFER_COMPLETE, Transfer complete) \
XXX(227, PASV, Entering Passive Mode) \
XXX(331, PASS, Password required) \
XXX(230, LOGIN_OK, Login OK) \
XXX(250, OK, OK) \
XXX(500, BAD_SYNTAX, Bad syntax) \
XXX(530, NOT_LOGIN, Not login) \
enum ftp_status {
#define XXX(code, name, string) FTP_STATUS_##name = code,
FTP_STATUS_MAP(XXX)
#undef XXX
};
// more friendly macros
#define FTP_MKDIR FTP_MKD
#define FTP_RMDIR FTP_RMD
#define FTP_APPEND FTP_APPE
#define FTP_REMOVE FTP_DELE
#define FTP_DOWNLOAD FTP_RETR
#define FTP_UPLOAD FTP_STOR
#define FTP_RECV_BUFSIZE 8192
typedef struct ftp_handle_s {
int sockfd;
char recvbuf[FTP_RECV_BUFSIZE];
void* userdata;
} ftp_handle_t;
BEGIN_EXTERN_C
HV_EXPORT const char* ftp_command_str(enum ftp_command cmd);
HV_EXPORT const char* ftp_status_str(enum ftp_status status);
HV_EXPORT int ftp_connect(ftp_handle_t* hftp, const char* host, int port);
HV_EXPORT int ftp_login(ftp_handle_t* hftp, const char* username, const char* password);
HV_EXPORT int ftp_quit(ftp_handle_t* hftp);
HV_EXPORT int ftp_exec(ftp_handle_t* hftp, const char* cmd, const char* param);
// local => remote
HV_EXPORT int ftp_upload(ftp_handle_t* hftp, const char* local_filepath, const char* remote_filepath);
// remote => local
HV_EXPORT int ftp_download(ftp_handle_t* hftp, const char* remote_filepath, const char* local_filepath);
typedef int (*ftp_download_cb)(ftp_handle_t* hftp, char* buf, int len);
HV_EXPORT int ftp_download_with_cb(ftp_handle_t* hftp, const char* filepath, ftp_download_cb cb);
END_EXTERN_C
#endif // HV_FTP_H_

View File

@ -82,6 +82,7 @@ HV_EXPORT char* hv_strncat(char* dest, const char* src, size_t n);
#endif
HV_EXPORT char* hv_strnchr(const char* s, char c, size_t n);
HV_EXPORT char* hv_strnrchr(const char* s, char c, size_t n);
#define hv_strrchr_dot(str) strrchr(str, '.')
HV_EXPORT char* hv_strrchr_dir(const char* filepath);

View File

@ -10,7 +10,7 @@
#endif
#ifndef HAVE_STDATOMIC_H
#define HAVE_STDATOMIC_H 1
#define HAVE_STDATOMIC_H 0
#endif
#ifndef HAVE_SYS_TYPES_H
@ -22,7 +22,7 @@
#endif
#ifndef HAVE_SYS_TIME_H
#define HAVE_SYS_TIME_H 1
#define HAVE_SYS_TIME_H 0
#endif
#ifndef HAVE_FCNTL_H
@ -30,11 +30,11 @@
#endif
#ifndef HAVE_PTHREAD_H
#define HAVE_PTHREAD_H 1
#define HAVE_PTHREAD_H 0
#endif
#ifndef HAVE_ENDIAN_H
#define HAVE_ENDIAN_H 1
#define HAVE_ENDIAN_H 0
#endif
#ifndef HAVE_SYS_ENDIAN_H
@ -54,46 +54,49 @@
#endif
#ifndef HAVE_CLOCK_GETTIME
#define HAVE_CLOCK_GETTIME 1
#define HAVE_CLOCK_GETTIME 0
#endif
#ifndef HAVE_GETTIMEOFDAY
#define HAVE_GETTIMEOFDAY 1
#define HAVE_GETTIMEOFDAY 0
#endif
#ifndef HAVE_PTHREAD_SPIN_LOCK
#define HAVE_PTHREAD_SPIN_LOCK 1
#define HAVE_PTHREAD_SPIN_LOCK 0
#endif
#ifndef HAVE_PTHREAD_MUTEX_TIMEDLOCK
#define HAVE_PTHREAD_MUTEX_TIMEDLOCK 1
#define HAVE_PTHREAD_MUTEX_TIMEDLOCK 0
#endif
#ifndef HAVE_SEM_TIMEDWAIT
#define HAVE_SEM_TIMEDWAIT 1
#define HAVE_SEM_TIMEDWAIT 0
#endif
#ifndef HAVE_PIPE
#define HAVE_PIPE 1
#define HAVE_PIPE 0
#endif
#ifndef HAVE_SOCKETPAIR
#define HAVE_SOCKETPAIR 1
#define HAVE_SOCKETPAIR 0
#endif
#ifndef HAVE_EVENTFD
#define HAVE_EVENTFD 1
#define HAVE_EVENTFD 0
#endif
#ifndef HAVE_SETPROCTITLE
#define HAVE_SETPROCTITLE 0
#endif
/* #undef WITH_OPENSSL */
#define WITH_OPENSSL 1
/* #undef WITH_GNUTLS */
/* #undef WITH_MBEDTLS */
/* #undef ENABLE_UDS */
/* #undef USE_MULTIMAP */
#define WITH_WEPOLL 1
/* #undef WITH_KCP */
#endif // HV_CONFIG_H_

View File

@ -37,32 +37,6 @@
#define HV_UNUSED
#endif
// @param[IN | OUT | INOUT]
#ifndef IN
#define IN
#endif
#ifndef OUT
#define OUT
#endif
#ifndef INOUT
#define INOUT
#endif
// @field[OPTIONAL | REQUIRED | REPEATED]
#ifndef OPTIONAL
#define OPTIONAL
#endif
#ifndef REQUIRED
#define REQUIRED
#endif
#ifndef REPEATED
#define REPEATED
#endif
#ifdef __cplusplus
#ifndef EXTERN_C

View File

@ -11,16 +11,18 @@ typedef struct hevent_s hevent_t;
// NOTE: The following structures are subclasses of hevent_t,
// inheriting hevent_t data members and function members.
typedef struct hio_s hio_t;
typedef struct hidle_s hidle_t;
typedef struct htimer_s htimer_t;
typedef struct htimeout_s htimeout_t;
typedef struct hperiod_s hperiod_t;
typedef struct hio_s hio_t;
typedef struct hevent_s hsignal_t;
typedef void (*hevent_cb) (hevent_t* ev);
typedef void (*hio_cb) (hio_t* io);
typedef void (*hidle_cb) (hidle_t* idle);
typedef void (*htimer_cb) (htimer_t* timer);
typedef void (*hio_cb) (hio_t* io);
typedef void (*hsignal_cb) (hsignal_t* sig);
typedef void (*haccept_cb) (hio_t* io);
typedef void (*hconnect_cb) (hio_t* io);
@ -31,7 +33,8 @@ typedef void (*hclose_cb) (hio_t* io);
typedef enum {
HLOOP_STATUS_STOP,
HLOOP_STATUS_RUNNING,
HLOOP_STATUS_PAUSE
HLOOP_STATUS_PAUSE,
HLOOP_STATUS_DESTROY
} hloop_status_e;
typedef enum {
@ -41,6 +44,7 @@ typedef enum {
HEVENT_TYPE_PERIOD = 0x00000020,
HEVENT_TYPE_TIMER = HEVENT_TYPE_TIMEOUT|HEVENT_TYPE_PERIOD,
HEVENT_TYPE_IDLE = 0x00000100,
HEVENT_TYPE_SIGNAL = 0x00000200,
HEVENT_TYPE_CUSTOM = 0x00000400, // 1024
} hevent_type_e;
@ -93,6 +97,7 @@ typedef enum {
HIO_TYPE_STDIO = 0x0000000F,
HIO_TYPE_FILE = 0x00000010,
HIO_TYPE_PIPE = 0x00000020,
HIO_TYPE_IP = 0x00000100,
HIO_TYPE_SOCK_RAW = 0x00000F00,
@ -182,6 +187,10 @@ HV_EXPORT void* hloop_userdata(hloop_t* loop);
// NOTE: hloop_post_event is thread-safe, used to post event from other thread to loop thread.
HV_EXPORT void hloop_post_event(hloop_t* loop, hevent_t* ev);
// signal
HV_EXPORT hsignal_t* hsignal_add(hloop_t* loop, hsignal_cb cb, int signo);
HV_EXPORT void hsignal_del(hsignal_t* sig);
// idle
HV_EXPORT hidle_t* hidle_add(hloop_t* loop, hidle_cb cb, uint32_t repeat DEFAULT(INFINITE));
HV_EXPORT void hidle_del(hidle_t* idle);
@ -435,6 +444,10 @@ HV_EXPORT hio_t* hloop_create_udp_server (hloop_t* loop, const char* host, int p
// @see examples/nc.c
HV_EXPORT hio_t* hloop_create_udp_client (hloop_t* loop, const char* host, int port);
//-----------------pipe---------------------------------------------
// @see examples/pipe_test.c
HV_EXPORT int hio_create_pipe(hloop_t* loop, hio_t* pipeio[2]);
//-----------------upstream---------------------------------------------
// hio_read(io)
// hio_read(io->upstream_io)

View File

@ -65,6 +65,7 @@ typedef struct option_s {
char short_opt;
const char* long_opt;
int arg_type;
const char* description;
} option_t;
HV_EXPORT int main_ctx_init(int argc, char** argv);
@ -76,7 +77,8 @@ HV_EXPORT void main_ctx_free(void);
// watch -n10 ls
HV_EXPORT int parse_opt(int argc, char** argv, const char* opt);
// gcc -g -Wall -O3 -std=cpp main.c
HV_EXPORT int parse_opt_long(int argc, char** argv, const option_t* long_options, int size);
HV_EXPORT int parse_opt_long(int argc, char** argv, const option_t* long_options, int opt_size);
HV_EXPORT int dump_opt_long(const option_t* long_options, int opt_size, char* out_str, int out_size);
HV_EXPORT const char* get_arg(const char* key);
HV_EXPORT const char* get_env(const char* key);

View File

@ -41,6 +41,7 @@
#undef OS_UNIX
#define OS_WIN
#else
#undef OS_WIN
#define OS_UNIX
#endif
@ -142,6 +143,12 @@
// headers
#ifdef OS_WIN
#ifndef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#elif _WIN32_WINNT < 0x0600
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x0600
#endif
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif

View File

@ -82,9 +82,11 @@ HV_INLINE int nonblocking(int s) {
return fcntl(s, F_SETFL, fcntl(s, F_GETFL) | O_NONBLOCK);
}
#ifndef closesocket
HV_INLINE int closesocket(int sockfd) {
return close(sockfd);
}
#endif
#endif

View File

@ -75,6 +75,18 @@ HV_EXPORT std::string trim_pairs(const std::string& str, const char* pairs = PAI
HV_EXPORT std::string replace(const std::string& str, const std::string& find, const std::string& rep);
HV_EXPORT std::string replaceAll(const std::string& str, const std::string& find, const std::string& rep);
struct HV_EXPORT NetAddr {
std::string ip;
int port;
NetAddr() : port(0) {}
NetAddr(const std::string& _ip, int _port) : ip(_ip), port(_port) {}
NetAddr(const std::string& ipport) { from_string(ipport); }
void from_string(const std::string& ipport);
std::string to_string();
};
} // end namespace hv
#endif // HV_STRING_H_

View File

@ -8,7 +8,7 @@ BEGIN_EXTERN_C
#define HV_VERSION_MAJOR 1
#define HV_VERSION_MINOR 3
#define HV_VERSION_PATCH 2
#define HV_VERSION_PATCH 3
#define HV_VERSION_STRING STRINGIFY(HV_VERSION_MAJOR) "." \
STRINGIFY(HV_VERSION_MINOR) "." \

View File

@ -1,15 +0,0 @@
#ifndef HV_ICMP_H_
#define HV_ICMP_H_
#include "hexport.h"
BEGIN_EXTERN_C
// @param cnt: ping count
// @return: ok count
// @note: printd $CC -DPRINT_DEBUG
HV_EXPORT int ping(const char* host, int cnt DEFAULT(4));
END_EXTERN_C
#endif // HV_ICMP_H_

View File

@ -29,6 +29,7 @@ struct mqtt_client_s {
unsigned char alloced_ssl_ctx: 1; // intern
unsigned char connected : 1;
unsigned short keepalive;
int ping_cnt;
char client_id[64];
// will
mqtt_message_t* will;
@ -47,7 +48,7 @@ struct mqtt_client_s {
// privdata
hloop_t* loop;
hio_t* io;
htimer_t* reconn_timer;
htimer_t* timer;
// SSL/TLS
hssl_ctx_t ssl_ctx;
// thread-safe
@ -101,6 +102,7 @@ HV_EXPORT int mqtt_client_reconnect(mqtt_client_t* cli);
// on_connect -> mqtt_client_login ->
// on_connack
HV_EXPORT void mqtt_client_set_connect_timeout(mqtt_client_t* cli, int ms);
HV_EXPORT void mqtt_client_set_host(mqtt_client_t* cli, const char* host, int port, int ssl);
HV_EXPORT int mqtt_client_connect(mqtt_client_t* cli,
const char* host,
int port DEFAULT(DEFAULT_MQTT_PORT),
@ -125,4 +127,214 @@ HV_EXPORT int mqtt_client_unsubscribe(mqtt_client_t* cli,
END_EXTERN_C
#ifdef __cplusplus
#include <functional>
#include <map>
#include <mutex>
#include <string>
namespace hv {
// @usage examples/mqtt/mqtt_client_test.cpp
class MqttClient {
public:
mqtt_client_t* client;
// callbacks
typedef std::function<void(MqttClient*)> MqttCallback;
typedef std::function<void(MqttClient*, mqtt_message_t*)> MqttMessageCallback;
MqttCallback onConnect;
MqttCallback onClose;
MqttMessageCallback onMessage;
MqttClient(hloop_t* loop = NULL) {
client = mqtt_client_new(loop);
}
~MqttClient() {
if (client) {
mqtt_client_free(client);
client = NULL;
}
}
void run() {
mqtt_client_set_callback(client, on_mqtt);
mqtt_client_set_userdata(client, this);
mqtt_client_run(client);
}
void stop() {
mqtt_client_stop(client);
}
void setID(const char* id) {
mqtt_client_set_id(client, id);
}
void setWill(mqtt_message_t* will) {
mqtt_client_set_will(client, will);
}
void setAuth(const char* username, const char* password) {
mqtt_client_set_auth(client, username, password);
}
void setPingInterval(int sec) {
client->keepalive = sec;
}
int lastError() {
return mqtt_client_get_last_error(client);
}
// SSL/TLS
int setSslCtx(hssl_ctx_t ssl_ctx) {
return mqtt_client_set_ssl_ctx(client, ssl_ctx);
}
int newSslCtx(hssl_ctx_opt_t* opt) {
return mqtt_client_new_ssl_ctx(client, opt);
}
void setReconnect(reconn_setting_t* reconn) {
mqtt_client_set_reconnect(client, reconn);
}
void setConnectTimeout(int ms) {
mqtt_client_set_connect_timeout(client, ms);
}
void setHost(const char* host, int port = DEFAULT_MQTT_PORT, int ssl = 0) {
mqtt_client_set_host(client, host, port, ssl);
}
int connect(const char* host, int port = DEFAULT_MQTT_PORT, int ssl = 0) {
return mqtt_client_connect(client, host, port, ssl);
}
int reconnect() {
return mqtt_client_reconnect(client);
}
int disconnect() {
return mqtt_client_disconnect(client);
}
bool isConnected() {
return mqtt_client_is_connected(client);
}
int publish(mqtt_message_t* msg, MqttCallback ack_cb = NULL) {
int mid = mqtt_client_publish(client, msg);
if (msg->qos > 0 && mid >= 0 && ack_cb) {
setAckCallback(mid, ack_cb);
}
return mid;
}
int publish(const std::string& topic, const std::string& payload, int qos = 0, int retain = 0, MqttCallback ack_cb = NULL) {
mqtt_message_t msg;
memset(&msg, 0, sizeof(msg));
msg.topic_len = topic.size();
msg.topic = topic.c_str();
msg.payload_len = payload.size();
msg.payload = payload.c_str();
msg.qos = qos;
msg.retain = retain;
return publish(&msg, ack_cb);
}
int subscribe(const char* topic, int qos = 0, MqttCallback ack_cb = NULL) {
int mid = mqtt_client_subscribe(client, topic, qos);
if (qos > 0 && mid >= 0 && ack_cb) {
setAckCallback(mid, ack_cb);
}
return mid;
}
int unsubscribe(const char* topic, MqttCallback ack_cb = NULL) {
int mid = mqtt_client_unsubscribe(client, topic);
if (mid >= 0 && ack_cb) {
setAckCallback(mid, ack_cb);
}
return mid;
}
protected:
void setAckCallback(int mid, MqttCallback cb) {
ack_cbs_mutex.lock();
ack_cbs[mid] = std::move(cb);
ack_cbs_mutex.unlock();
}
void invokeAckCallback(int mid) {
MqttCallback ack_cb = NULL;
ack_cbs_mutex.lock();
auto iter = ack_cbs.find(mid);
if (iter != ack_cbs.end()) {
ack_cb = std::move(iter->second);
ack_cbs.erase(iter);
}
ack_cbs_mutex.unlock();
if (ack_cb) ack_cb(this);
}
static void on_mqtt(mqtt_client_t* cli, int type) {
MqttClient* client = (MqttClient*)mqtt_client_get_userdata(cli);
// printf("on_mqtt type=%d\n", type);
switch(type) {
case MQTT_TYPE_CONNECT:
// printf("mqtt connected!\n");
break;
case MQTT_TYPE_DISCONNECT:
// printf("mqtt disconnected!\n");
if (client->onClose) {
client->onClose(client);
}
break;
case MQTT_TYPE_CONNACK:
// printf("mqtt connack!\n");
if (client->onConnect) {
client->onConnect(client);
}
break;
case MQTT_TYPE_PUBLISH:
if (client->onMessage) {
client->onMessage(client, &cli->message);
}
break;
case MQTT_TYPE_PUBACK: /* qos = 1 */
// printf("mqtt puback mid=%d\n", cli->mid);
client->invokeAckCallback(cli->mid);
break;
case MQTT_TYPE_PUBREC: /* qos = 2 */
// printf("mqtt pubrec mid=%d\n", cli->mid);
// wait MQTT_TYPE_PUBCOMP
break;
case MQTT_TYPE_PUBCOMP: /* qos = 2 */
// printf("mqtt pubcomp mid=%d\n", cli->mid);
client->invokeAckCallback(cli->mid);
break;
case MQTT_TYPE_SUBACK:
// printf("mqtt suback mid=%d\n", cli->mid);
client->invokeAckCallback(cli->mid);
break;
case MQTT_TYPE_UNSUBACK:
// printf("mqtt unsuback mid=%d\n", cli->mid);
client->invokeAckCallback(cli->mid);
break;
default:
break;
}
}
private:
// mid => ack callback
std::map<int, MqttCallback> ack_cbs;
std::mutex ack_cbs_mutex;
};
}
#endif
#endif // HV_MQTT_CLIENT_H_

Some files were not shown because too many files have changed in this diff Show More