|
@@ -0,0 +1,725 @@
|
|
|
+#include <cstring>
|
|
|
+#include <unistd.h>
|
|
|
+#include "utils.h"
|
|
|
+#include "device.h"
|
|
|
+#include "json/parser.h"
|
|
|
+
|
|
|
+// declare of scoped vars and funcs
|
|
|
+namespace hm {
|
|
|
+ const int gWaitTime = 3000;
|
|
|
+ std::map<int, std::string> gOpenTypeMap = { // NOLINT
|
|
|
+ {0, "未知方式"},
|
|
|
+ {1, "密码开锁"},
|
|
|
+ {2, "刷卡开锁"},
|
|
|
+ {3, "先刷卡后密码开锁"},
|
|
|
+ {4, "先密码后刷卡开锁"},
|
|
|
+ {5, "远程开锁,如通过室内机或者平台对门口机开锁"},
|
|
|
+ {6, "开锁按钮进行开锁"},
|
|
|
+ {7, "开锁"},
|
|
|
+ {8, "密码+刷卡+组合开锁"},
|
|
|
+ {10, "密码+组合开锁"},
|
|
|
+ {11, "刷卡+组合开锁"},
|
|
|
+ {12, "多人开锁"},
|
|
|
+ {13, "钥匙开门"},
|
|
|
+ {14, "胁迫密码开门"},
|
|
|
+ {15, "二维码开门"},
|
|
|
+ {16, "目标识别开门"},
|
|
|
+ {18, "人证对比"},
|
|
|
+ {19, "证件+人证比对"},
|
|
|
+ {20, "蓝牙开门"},
|
|
|
+ {21, "个性化密码开门"},
|
|
|
+ {22, "UserID+密码"},
|
|
|
+ {23, "人脸+密码开锁"},
|
|
|
+ {24, "+密码开锁"},
|
|
|
+ {25, "+人脸开锁"},
|
|
|
+ {26, "刷卡+人脸开锁"},
|
|
|
+ {27, "人脸或密码开锁"},
|
|
|
+ {28, "或密码开锁"},
|
|
|
+ {29, "或人脸开锁"},
|
|
|
+ {30, "刷卡或人脸开锁"},
|
|
|
+ {31, "刷卡或开锁"},
|
|
|
+ {32, "+人脸+密码开锁"},
|
|
|
+ {33, "刷卡+人脸+密码开锁"},
|
|
|
+ {34, "刷卡++密码开锁"},
|
|
|
+ {35, "卡++人脸组合开锁"},
|
|
|
+ {36, "或人脸或密码"},
|
|
|
+ {37, "卡或人脸或密码开锁"},
|
|
|
+ {38, "卡或人脸开锁"},
|
|
|
+ {39, "卡++人脸+密码组合开锁"},
|
|
|
+ {40, "卡或人脸或密码开锁"},
|
|
|
+ {41, "(证件+人证比对)或刷卡或人脸"},
|
|
|
+ {42, "人证比对或刷卡(二维码)或人脸"},
|
|
|
+ {43, "DTMF开锁(包括SIPINFO,RFC2833,INBAND)"},
|
|
|
+ {44, "远程二维码开门"},
|
|
|
+ {45, "远程人脸开门"},
|
|
|
+ {46, "人证比对开门()"},
|
|
|
+ {47, "临时密码开门"},
|
|
|
+ {48, "健康码开门"},
|
|
|
+ {49, "目标识别开锁"},
|
|
|
+ {50, "目标+密码组合开锁"},
|
|
|
+ {51, "人脸+目标组合开锁"},
|
|
|
+ {52, "卡+目标组合开锁"},
|
|
|
+ {53, "目标或密码开锁"},
|
|
|
+ {54, "人脸或目标开锁"},
|
|
|
+ {55, "卡或目标开锁"},
|
|
|
+ {56, "人脸+目标+密码组合开锁"},
|
|
|
+ {57, "卡+人脸+目标组合开锁"},
|
|
|
+ {58, "卡+目标+密码组合开锁"},
|
|
|
+ {59, "人脸或目标或密码开锁"},
|
|
|
+ {60, "卡或人脸或目标开锁"},
|
|
|
+ {61, "卡或目标或密码开锁"},
|
|
|
+ {62, "卡+人脸+目标+密码组合开锁"},
|
|
|
+ {63, "卡或人脸或目标或密码开锁"}
|
|
|
+ };
|
|
|
+
|
|
|
+ int onSubscribeData(
|
|
|
+ LLONG handler, DWORD type, void *info, BYTE *imgBuf, DWORD bufSize,
|
|
|
+ LDWORD user, int seq, void *reserved
|
|
|
+ );
|
|
|
+
|
|
|
+ Device *getDeviceBySubId(const LLONG &subId);
|
|
|
+}
|
|
|
+
|
|
|
+// implement of scoped funcs
|
|
|
+namespace hm {
|
|
|
+ int onSubscribeData(
|
|
|
+ LLONG handler, DWORD type, void *info, BYTE *imgBuf, DWORD bufSize,
|
|
|
+ LDWORD user, int seq, void *reserved
|
|
|
+ ) {
|
|
|
+ Device *device = getDeviceBySubId(handler);
|
|
|
+ if (device == nullptr) {
|
|
|
+ Log(Warn, "unrecognized subscribe uid: %ld", handler);
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+ switch (type) {
|
|
|
+ case EVENT_IVS_ACCESS_CTL: // 人脸
|
|
|
+ if (device->isFaceDevice)
|
|
|
+ device->onAccessCtlEvent((DEV_EVENT_ACCESS_CTL_INFO *) info, imgBuf, bufSize);
|
|
|
+ else Log(Warn, "seq[%s] is car device, but got a face event", device->seq.c_str());
|
|
|
+ break;
|
|
|
+ case EVENT_IVS_TRAFFICJUNCTION: // 车辆闸机
|
|
|
+ if (!device->isFaceDevice)
|
|
|
+ device->onTrafficJunctionEvent((DEV_EVENT_TRAFFICJUNCTION_INFO *) info, imgBuf, bufSize);
|
|
|
+ else Log(Warn, "seq[%s] is face device, but got a car event", device->seq.c_str());
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ Log(Warn, "unrecognized event: %u", type);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ Device *getDeviceBySubId(const LLONG &subId) {
|
|
|
+ for (auto &itr : gDevicesVec) if (itr->subId == subId) return itr.get();
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+
|
|
|
+ void Device::init() {
|
|
|
+ NET_IN_INIT_DEVICE_ACCOUNT in;
|
|
|
+ in.dwSize = sizeof in;
|
|
|
+ strcpy(in.szMac, this->mac.c_str());
|
|
|
+ strcpy(in.szUserName, gConfLoginUser.c_str());
|
|
|
+ strcpy(in.szPwd, gConfLoginPass.c_str());
|
|
|
+ in.byPwdResetWay = this->reset;
|
|
|
+
|
|
|
+ NET_OUT_INIT_DEVICE_ACCOUNT out;
|
|
|
+ out.dwSize = sizeof out;
|
|
|
+
|
|
|
+ if (CLIENT_InitDevAccount(&in, &out, gWaitTime, this->local.data())) {
|
|
|
+ Log(Info, "device: seq[%s] init success", this->seq.c_str());
|
|
|
+ this->inited = true;
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Log(
|
|
|
+ Error, "device(ip[%s], mac[%s], seq[%s]) init fail",
|
|
|
+ this->ip.c_str(), this->mac.c_str(), this->seq.c_str()
|
|
|
+ );
|
|
|
+ this->running = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool Device::login() {
|
|
|
+ NET_IN_LOGIN_WITH_HIGHLEVEL_SECURITY in = {0};
|
|
|
+ in.dwSize = sizeof in;
|
|
|
+ strcpy(in.szIP, this->ip.c_str());
|
|
|
+ in.nPort = this->port;
|
|
|
+ strcpy(in.szUserName, gConfLoginUser.c_str());
|
|
|
+ strcpy(in.szPassword, gConfLoginPass.c_str());
|
|
|
+ in.emSpecCap = EM_LOGIN_SPEC_CAP_TCP;
|
|
|
+
|
|
|
+ NET_OUT_LOGIN_WITH_HIGHLEVEL_SECURITY out;
|
|
|
+ out.dwSize = sizeof out;
|
|
|
+
|
|
|
+ for (int i = 0; i < 3; ++i) {
|
|
|
+ this->loginId = CLIENT_LoginWithHighLevelSecurity(&in, &out);
|
|
|
+ if (this->loginId) {
|
|
|
+ Log(Trace, "device seq[%s] login success", this->seq.c_str());
|
|
|
+ usleep(1000000);
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ sleep(1);
|
|
|
+ }
|
|
|
+ Log(
|
|
|
+ Error, "device(ip[%s], mac[%s], seq[%s]) login fail",
|
|
|
+ this->ip.c_str(), this->mac.c_str(), this->seq.c_str()
|
|
|
+ );
|
|
|
+ this->running = false;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ void Device::logout() {
|
|
|
+ if (this->loginId) CLIENT_Logout(this->loginId);
|
|
|
+ this->loginId = 0, this->running = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool Device::subscribe() {
|
|
|
+ if (isFaceDevice) {
|
|
|
+ this->subId = CLIENT_RealLoadPictureEx(
|
|
|
+ this->loginId, 0, EVENT_IVS_ACCESS_CTL, TRUE,
|
|
|
+ onSubscribeData, 0, nullptr
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ this->subId = CLIENT_RealLoadPictureEx(
|
|
|
+ this->loginId, 0, EVENT_IVS_TRAFFICJUNCTION, TRUE,
|
|
|
+ onSubscribeData, 0, nullptr
|
|
|
+ );
|
|
|
+ }
|
|
|
+ if (this->subId) {
|
|
|
+ Log(Trace, "device seq[%s] subscribe success", this->seq.c_str());
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ Log(
|
|
|
+ Error, "device(ip[%s], mac[%s], seq[%s]) face subscribe fail",
|
|
|
+ this->ip.c_str(), this->mac.c_str(), this->seq.c_str()
|
|
|
+ );
|
|
|
+ this->running = false;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ void Device::unsubscribe() {
|
|
|
+ if (this->subId) CLIENT_StopLoadPic(this->subId);
|
|
|
+ this->subId = 0, this->running = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ void Device::varUserInsert(const User &user) {
|
|
|
+ bool have = false;
|
|
|
+ std::lock_guard<std::mutex> lock(uMtx);
|
|
|
+ for (const User &itr : faceUserList) {
|
|
|
+ if (itr.uid == user.uid) {
|
|
|
+ have = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!have) faceUserList.push_back(user);
|
|
|
+ }
|
|
|
+
|
|
|
+ void Device::varUserDelete(const std::string &uid) {
|
|
|
+ std::lock_guard<std::mutex> lock(uMtx);
|
|
|
+ for (auto it = faceUserList.begin(); it != faceUserList.end(); ++it) {
|
|
|
+ if (it->uid == uid) {
|
|
|
+ faceUserList.erase(it);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ bool Device::varUserExists(const std::string &uid) {
|
|
|
+ std::lock_guard<std::mutex> lock(uMtx);
|
|
|
+ for (User &user : faceUserList) if (user.uid == uid) return true;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool Device::addUserFace(const std::string &uid, const std::string &face, std::string &msg) {
|
|
|
+ NET_IN_ADD_FACE_INFO in;
|
|
|
+ in.dwSize = sizeof in;
|
|
|
+ strcpy(in.szUserID, uid.c_str());
|
|
|
+ in.stuFaceInfo.nFacePhoto = 1;
|
|
|
+ in.stuFaceInfo.nFacePhotoLen[0] = imgcpy(in.stuFaceInfo.pszFacePhoto[0], face);
|
|
|
+ // Log(Info, "face-size: %ld, pho-len:%d", face.size(), in.stuFaceInfo.nFacePhotoLen[0]);
|
|
|
+ // imageSave("./java.jpg", in.stuFaceInfo.pszFacePhoto[0], in.stuFaceInfo.nFacePhotoLen[0]);
|
|
|
+
|
|
|
+ NET_OUT_ADD_FACE_INFO out;
|
|
|
+ out.dwSize = sizeof out;
|
|
|
+ bool res = CLIENT_FaceInfoOpreate(loginId, EM_FACEINFO_OPREATE_ADD, &in, &out, gWaitTime);
|
|
|
+ if (!res) msg = "user face add failed";
|
|
|
+ delete[] in.stuFaceInfo.pszFacePhoto[0];
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool Device::removeUserOnly(const std::string &uid, std::string &msg) {
|
|
|
+ NET_IN_ACCESS_USER_SERVICE_REMOVE in;
|
|
|
+ in.dwSize = sizeof in;
|
|
|
+ in.nUserNum = 1;
|
|
|
+ std::strcpy(in.szUserID[0], uid.c_str());
|
|
|
+ in.bUserIDEx = 0;
|
|
|
+ NET_OUT_ACCESS_USER_SERVICE_REMOVE out;
|
|
|
+ out.dwSize = sizeof out;
|
|
|
+ out.nMaxRetNum = 1;
|
|
|
+ out.pFailCode = new NET_EM_FAILCODE;
|
|
|
+
|
|
|
+ bool res = CLIENT_OperateAccessUserService(
|
|
|
+ loginId, NET_EM_ACCESS_CTL_USER_SERVICE_REMOVE, &in, &out, gWaitTime
|
|
|
+ );
|
|
|
+ if (res) varUserDelete(uid);
|
|
|
+ else msg = "user info delete failed";
|
|
|
+ delete out.pFailCode;
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool Device::removeUserFace(const std::string &uid, std::string &msg) {
|
|
|
+ NET_IN_REMOVE_FACE_INFO in;
|
|
|
+ in.dwSize = sizeof in;
|
|
|
+ strcpy(in.szUserID, uid.c_str());
|
|
|
+
|
|
|
+ NET_OUT_REMOVE_FACE_INFO out;
|
|
|
+ out.dwSize = sizeof out;
|
|
|
+ bool res = CLIENT_FaceInfoOpreate(loginId, EM_FACEINFO_OPREATE_REMOVE, &in, &out, gWaitTime);
|
|
|
+ if (!res) msg = "user face remove failed";
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+ void Device::varCarWoBInsert(const bool &isBlack, const Plate &plate) {
|
|
|
+ bool have = false;
|
|
|
+ std::lock_guard<std::mutex> lock(isBlack ? cbMtx : cwMtx);
|
|
|
+ for (const Plate &itr : isBlack ? carBlackList : carWhiteList) {
|
|
|
+ if (itr.cid == plate.cid) {
|
|
|
+ have = true;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!have) isBlack ? carBlackList.push_back(plate) : carWhiteList.push_back(plate);
|
|
|
+ }
|
|
|
+
|
|
|
+ void Device::varCarWoBDelete(const bool &isBlack, const int &cid) {
|
|
|
+ std::lock_guard<std::mutex> lock(isBlack ? cbMtx : cwMtx);
|
|
|
+ for (auto it = (isBlack ? carBlackList : carWhiteList).begin();
|
|
|
+ it != (isBlack ? carBlackList : carWhiteList).end(); ++it) {
|
|
|
+ if (it->cid == cid) {
|
|
|
+ (isBlack ? carBlackList : carWhiteList).erase(it);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ bool Device::varCarWoBExists(const bool &isBlack, const int &cid) {
|
|
|
+ std::lock_guard<std::mutex> lock(isBlack ? cbMtx : cwMtx);
|
|
|
+ for (const Plate &plate : isBlack ? carBlackList : carWhiteList) if (plate.cid == cid) return true;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool Device::varCarWoBExists(const bool &isBlack, const std::string &plate) {
|
|
|
+ std::lock_guard<std::mutex> lock(isBlack ? cbMtx : cwMtx);
|
|
|
+ for (const Plate &itr : isBlack ? carBlackList : carWhiteList) if (itr.plate == plate) return true;
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool Device::insertOneCarWoBList(const bool &isBlack, Plate &plateInfo, std::string &msg) {
|
|
|
+ if (varCarWoBExists(isBlack, plateInfo.plate)) {
|
|
|
+ msg = "exist already";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ NET_IN_OPERATE_TRAFFIC_LIST_RECORD in;
|
|
|
+ in.dwSize = sizeof in;
|
|
|
+ in.emOperateType = NET_TRAFFIC_LIST_INSERT;
|
|
|
+ in.emRecordType = isBlack ? NET_RECORD_TRAFFICBLACKLIST : NET_RECORD_TRAFFICREDLIST;
|
|
|
+ auto *info = new NET_INSERT_RECORD_INFO;
|
|
|
+ info->dwSize = sizeof(NET_INSERT_RECORD_INFO);
|
|
|
+ auto *record = new NET_TRAFFIC_LIST_RECORD;
|
|
|
+ strcpy(record->szMasterOfCar, plateInfo.name.c_str());
|
|
|
+ strcpy(record->szPlateNumber, plateInfo.plate.c_str());
|
|
|
+ time_t tst = plateInfo.timestamp / 1000;
|
|
|
+ struct tm *timeInfo = localtime(&tst);
|
|
|
+ record->stCancelTime.dwYear = timeInfo->tm_year + 1900, record->stCancelTime.dwMonth = timeInfo->tm_mon + 1;
|
|
|
+ record->stCancelTime.dwDay = timeInfo->tm_mday, record->stCancelTime.dwHour = timeInfo->tm_hour;
|
|
|
+ record->stCancelTime.dwMinute = timeInfo->tm_min, record->stCancelTime.dwSecond = timeInfo->tm_sec;
|
|
|
+ record->stBeginTime.dwYear = 2000, record->stBeginTime.dwMonth = 1, record->stBeginTime.dwDay = 1;
|
|
|
+ record->stBeginTime.dwHour = 0, record->stBeginTime.dwMinute = 0, record->stBeginTime.dwSecond = 0;
|
|
|
+ record->nAuthrityNum = 0;
|
|
|
+ info->pRecordInfo = record;
|
|
|
+ in.pstOpreateInfo = info;
|
|
|
+
|
|
|
+ NET_OUT_OPERATE_TRAFFIC_LIST_RECORD out;
|
|
|
+ out.dwSize = sizeof out;
|
|
|
+ bool res = CLIENT_OperateTrafficList(loginId, &in, &out);
|
|
|
+ if (res) {
|
|
|
+ plateInfo.cid = out.nRecordNo;
|
|
|
+ plateInfo.cid_s = std::to_string(out.nRecordNo);
|
|
|
+ varCarWoBInsert(isBlack, plateInfo);
|
|
|
+ } else {
|
|
|
+ msg = "insert failed";
|
|
|
+ plateInfo.cid = 0;
|
|
|
+ }
|
|
|
+ delete record;
|
|
|
+ delete info;
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool Device::removeOneCarWoBList(const bool &isBlack, const int &cid, std::string &msg) {
|
|
|
+ if (!varCarWoBExists(isBlack, cid)) {
|
|
|
+ msg = "no such plate";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ NET_IN_OPERATE_TRAFFIC_LIST_RECORD in;
|
|
|
+ in.dwSize = sizeof in;
|
|
|
+ in.emOperateType = NET_TRAFFIC_LIST_REMOVE;
|
|
|
+ in.emRecordType = isBlack ? NET_RECORD_TRAFFICBLACKLIST : NET_RECORD_TRAFFICREDLIST;
|
|
|
+ auto *info = new NET_REMOVE_RECORD_INFO;
|
|
|
+ info->dwSize = sizeof(NET_REMOVE_RECORD_INFO);
|
|
|
+ info->nRecordNo = cid;
|
|
|
+ in.pstOpreateInfo = info;
|
|
|
+
|
|
|
+ NET_OUT_OPERATE_TRAFFIC_LIST_RECORD out;
|
|
|
+ out.dwSize = sizeof out;
|
|
|
+
|
|
|
+ bool res = CLIENT_OperateTrafficList(loginId, &in, &out);
|
|
|
+ if (res) varCarWoBDelete(isBlack, cid);
|
|
|
+ else msg = "remove failed";
|
|
|
+ delete info;
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+ Plate *Device::getPlateByCNo(const std::string &cno) {
|
|
|
+ for (auto &itr : carWhiteList) if (itr.plate == cno) return &itr;
|
|
|
+ for (auto &itr : carBlackList) if (itr.plate == cno) return &itr;
|
|
|
+ return nullptr;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+namespace hm {
|
|
|
+ Device::Device(DEVICE_NET_INFO_EX2 *info) {
|
|
|
+ this->inited = (info->stuDevInfo.byInitStatus & 3) != 1;
|
|
|
+ this->port = info->stuDevInfo.nPort;
|
|
|
+ this->reset = info->stuDevInfo.byPwdResetWay;
|
|
|
+ this->seq = info->stuDevInfo.szSerialNo;
|
|
|
+ this->mac = info->stuDevInfo.szMac;
|
|
|
+ this->ip = info->stuDevInfo.szIP;
|
|
|
+ this->local = info->szLocalIP;
|
|
|
+ // 108: {szDeviceType: BSC, szDetailType: DH-ASI31A-MW, szNewDetailType: DH-ASI31A-MW}
|
|
|
+ // 109: {szDeviceType: ITC, szDetailType: ITC313-PW2A-LF, szNewDetailType: ITC313-PW2A-LF}
|
|
|
+ this->isFaceDevice = strcmp("DH-ASI31A-MW", info->stuDevInfo.szDetailType) == 0;
|
|
|
+
|
|
|
+ this->online = this->running = false;
|
|
|
+ this->loginId = this->subId = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ Device::~Device() {
|
|
|
+ this->unsubscribe();
|
|
|
+ this->logout();
|
|
|
+ }
|
|
|
+
|
|
|
+ void Device::queryFaceUsers() {
|
|
|
+ NET_IN_USERINFO_START_FIND start_in;
|
|
|
+ start_in.dwSize = sizeof start_in;
|
|
|
+ strcpy(start_in.szUserID, "");
|
|
|
+ NET_OUT_USERINFO_START_FIND start_out;
|
|
|
+ start_out.dwSize = sizeof start_out;
|
|
|
+
|
|
|
+ LLONG handler = CLIENT_StartFindUserInfo(loginId, &start_in, &start_out, gWaitTime);
|
|
|
+ if (handler) {
|
|
|
+ int offset = 0, count = 10;
|
|
|
+ faceUserList.clear();
|
|
|
+ while (offset < start_out.nTotalCount) {
|
|
|
+ NET_IN_USERINFO_DO_FIND find_in;
|
|
|
+ find_in.dwSize = sizeof find_in;
|
|
|
+ find_in.nStartNo = offset;
|
|
|
+ find_in.nCount = count;
|
|
|
+ NET_OUT_USERINFO_DO_FIND find_out;
|
|
|
+ find_out.dwSize = sizeof find_out;
|
|
|
+ find_out.nMaxNum = count;
|
|
|
+ find_out.pstuInfo = new NET_ACCESS_USER_INFO[count];
|
|
|
+ bool res = CLIENT_DoFindUserInfo(handler, &find_in, &find_out, gWaitTime);
|
|
|
+ if (res) {
|
|
|
+ for (int i = 0; i < find_out.nRetNum; ++i) {
|
|
|
+ User one = {
|
|
|
+ .uid=find_out.pstuInfo[i].szUserID, .name=find_out.pstuInfo[i].szName,
|
|
|
+ .password = find_out.pstuInfo[i].szPsw,
|
|
|
+ .timestamp=1000 * toTimestamp(
|
|
|
+ find_out.pstuInfo[i].stuValidEndTime.dwYear,
|
|
|
+ find_out.pstuInfo[i].stuValidEndTime.dwMonth,
|
|
|
+ find_out.pstuInfo[i].stuValidEndTime.dwDay,
|
|
|
+ find_out.pstuInfo[i].stuValidEndTime.dwHour,
|
|
|
+ find_out.pstuInfo[i].stuValidEndTime.dwMinute,
|
|
|
+ find_out.pstuInfo[i].stuValidEndTime.dwSecond
|
|
|
+ )
|
|
|
+ };
|
|
|
+ varUserInsert(one);
|
|
|
+ }
|
|
|
+ offset += find_out.nRetNum;
|
|
|
+ delete[] find_out.pstuInfo;
|
|
|
+ } else break;
|
|
|
+ }
|
|
|
+ CLIENT_StopFindUserInfo(handler);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ void Device::queryCarWoBList(const bool &isBlack) {
|
|
|
+ NET_IN_FIND_RECORD_PARAM find_in;
|
|
|
+ find_in.dwSize = sizeof find_in;
|
|
|
+ find_in.emType = isBlack ? NET_RECORD_TRAFFICBLACKLIST : NET_RECORD_TRAFFICREDLIST;
|
|
|
+ auto *find_cond = new FIND_RECORD_TRAFFICREDLIST_CONDITION;
|
|
|
+ find_cond->dwSize = sizeof(FIND_RECORD_TRAFFICREDLIST_CONDITION);
|
|
|
+ strcpy(find_cond->szPlateNumber, "");
|
|
|
+ strcpy(find_cond->szPlateNumberVague, "");
|
|
|
+ find_cond->nQueryResultBegin = 0;
|
|
|
+ find_cond->bRapidQuery = 0;
|
|
|
+ find_in.pQueryCondition = find_cond;
|
|
|
+ NET_OUT_FIND_RECORD_PARAM find_out;
|
|
|
+ find_out.dwSize = sizeof find_out;
|
|
|
+ bool res = CLIENT_FindRecord(loginId, &find_in, &find_out);
|
|
|
+ if (res) {
|
|
|
+ NET_IN_QUEYT_RECORD_COUNT_PARAM query_in;
|
|
|
+ query_in.dwSize = sizeof query_in;
|
|
|
+ query_in.lFindeHandle = find_out.lFindeHandle;
|
|
|
+ NET_OUT_QUEYT_RECORD_COUNT_PARAM query_out;
|
|
|
+ query_out.dwSize = sizeof query_out;
|
|
|
+ res = CLIENT_QueryRecordCount(&query_in, &query_out);
|
|
|
+ if (res) {
|
|
|
+ int found = 0, batch = 5;
|
|
|
+ while (found < query_out.nRecordCount) {
|
|
|
+ NET_IN_FIND_NEXT_RECORD_PARAM do_in;
|
|
|
+ do_in.dwSize = sizeof do_in;
|
|
|
+ do_in.lFindeHandle = find_out.lFindeHandle;
|
|
|
+ do_in.nFileCount = batch;
|
|
|
+ NET_OUT_FIND_NEXT_RECORD_PARAM do_out;
|
|
|
+ do_out.dwSize = sizeof do_out;
|
|
|
+ do_out.nMaxRecordNum = batch;
|
|
|
+ auto *records = new NET_TRAFFIC_LIST_RECORD[5];
|
|
|
+ do_out.pRecordList = records;
|
|
|
+ for (int i = 0; i < batch; ++i) records[i].dwSize = sizeof(NET_TRAFFIC_LIST_RECORD);
|
|
|
+ res = CLIENT_FindNextRecord(&do_in, &do_out);
|
|
|
+ if (res) {
|
|
|
+ found += do_out.nRetRecordNum;
|
|
|
+ for (int i = 0; i < do_out.nRetRecordNum; ++i) {
|
|
|
+ Plate one = {
|
|
|
+ .name = records[i].szMasterOfCar, .plate = records[i].szPlateNumber,
|
|
|
+ .cid_s = std::to_string(records[i].nRecordNo), .cid = records[i].nRecordNo,
|
|
|
+ .timestamp = 1000 * toTimestamp(
|
|
|
+ records[i].stCancelTime.dwYear, records[i].stCancelTime.dwMonth,
|
|
|
+ records[i].stCancelTime.dwDay, records[i].stCancelTime.dwHour,
|
|
|
+ records[i].stCancelTime.dwMinute, records[i].stCancelTime.dwSecond
|
|
|
+ )
|
|
|
+ };
|
|
|
+ varCarWoBInsert(isBlack, one);
|
|
|
+ }
|
|
|
+ } else break;
|
|
|
+ delete[] records;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ CLIENT_FindRecordClose(find_out.lFindeHandle);
|
|
|
+ }
|
|
|
+ delete find_cond;
|
|
|
+ }
|
|
|
+
|
|
|
+ void Device::Start() {
|
|
|
+ if (this->running) return;
|
|
|
+ this->running = true;
|
|
|
+
|
|
|
+ if (!this->inited) this->init();
|
|
|
+ if (!this->login()) return;
|
|
|
+ this->online = true;
|
|
|
+ if (!this->subscribe()) return;
|
|
|
+ }
|
|
|
+
|
|
|
+ void Device::onAccessCtlEvent(DEV_EVENT_ACCESS_CTL_INFO *info, BYTE *imgBuf, DWORD bufSize) {
|
|
|
+ char status[2] = {info->bStatus ? '1' : '0', 0}, method[64] = {0}, time[32] = {0};
|
|
|
+ strcpy(method, gOpenTypeMap[0].c_str());
|
|
|
+ if (gOpenTypeMap.find(info->emOpenMethod) != gOpenTypeMap.end())
|
|
|
+ strcpy(method, gOpenTypeMap[info->emOpenMethod].c_str());
|
|
|
+ sprintf(
|
|
|
+ time, "%d-%02d-%02d %02d:%02d:%02d", info->UTC.dwYear, info->UTC.dwMonth,
|
|
|
+ info->UTC.dwDay, info->UTC.dwHour + 8, info->UTC.dwMinute, info->UTC.dwSecond
|
|
|
+ );
|
|
|
+ Log(
|
|
|
+ Info,
|
|
|
+ R"({"mac":"%s","seq":"%s","time":"%s","result":%s,"userId":"%s","userName":"%s","method":"%s"})",
|
|
|
+ this->mac.c_str(), this->seq.c_str(), time, status, info->szUserID, info->szCardName, method
|
|
|
+ );
|
|
|
+ // imageSave("./face.jpg", imgBuf, bufSize);
|
|
|
+ std::map<std::string, std::string> data{
|
|
|
+ {"mac", this->mac},
|
|
|
+ {"seq", this->seq},
|
|
|
+ {"time", time},
|
|
|
+ {"result", status},
|
|
|
+ {"userId", info->szUserID},
|
|
|
+ {"userName", info->szCardName},
|
|
|
+ {"method", method}
|
|
|
+ };
|
|
|
+ dataUpload(gConfFaceRemote, data, imgBuf, bufSize);
|
|
|
+ }
|
|
|
+
|
|
|
+ void Device::onTrafficJunctionEvent(DEV_EVENT_TRAFFICJUNCTION_INFO *info, BYTE *imgBuf, DWORD bufSize) {
|
|
|
+ char time[32] = {0}, speed[4] = {0}, status[2] = {info->byOpenStrobeState > 1 ? '1' : '0', 0};
|
|
|
+ sprintf(speed, "%d", info->nSpeed);
|
|
|
+ sprintf(
|
|
|
+ time, "%d-%02d-%02d %02d:%02d:%02d", info->UTC.dwYear, info->UTC.dwMonth,
|
|
|
+ info->UTC.dwDay, info->UTC.dwHour, info->UTC.dwMinute, info->UTC.dwSecond
|
|
|
+ );
|
|
|
+ std::string cno(info->stTrafficCar.szPlateNumber), username, cid;
|
|
|
+ if (!cno.empty()) {
|
|
|
+ Plate *plate = getPlateByCNo(cno);
|
|
|
+ if (plate != nullptr) {
|
|
|
+ username = plate->name;
|
|
|
+ cid = plate->cid_s;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ Log(
|
|
|
+ Info,
|
|
|
+ R"({"mac":"%s","seq":"%s","time":"%s","plateNumber":"%s","username":"%s","cid":"%s","plateType":"%s","plateColor":"%s","carType":"%s","carSubType":"%s","carColor":"%s","speed":"%s","result":"%s"})",
|
|
|
+ this->mac.c_str(), this->seq.c_str(), time, info->stTrafficCar.szPlateNumber,
|
|
|
+ username.c_str(), cid.c_str(), info->stTrafficCar.szPlateType, info->stTrafficCar.szPlateColor,
|
|
|
+ info->stuVehicle.szText, info->stuVehicle.szObjectSubType, info->stTrafficCar.szVehicleColor,
|
|
|
+ speed, status
|
|
|
+ );
|
|
|
+
|
|
|
+ // imageSave("./car.jpg", imgBuf, bufSize);
|
|
|
+ std::map<std::string, std::string> data{
|
|
|
+ {"mac", this->mac},
|
|
|
+ {"seq", this->seq},
|
|
|
+ {"time", time},
|
|
|
+ {"plateNumber", info->stTrafficCar.szPlateNumber},
|
|
|
+ {"username", username},
|
|
|
+ {"cid", cid},
|
|
|
+ {"plateType", info->stTrafficCar.szPlateType},
|
|
|
+ {"plateColor", info->stTrafficCar.szPlateColor},
|
|
|
+ {"carType", info->stuVehicle.szText},
|
|
|
+ {"carSubType", info->stuVehicle.szObjectSubType},
|
|
|
+ {"carColor", info->stTrafficCar.szVehicleColor},
|
|
|
+ {"speed", speed},
|
|
|
+ {"result", status},
|
|
|
+ };
|
|
|
+ dataUpload(gConfCarRemote, data, imgBuf, bufSize);
|
|
|
+ }
|
|
|
+
|
|
|
+ std::string Device::getJsonStr() {
|
|
|
+ /* 1: online: 1 -> true, 0 -> false
|
|
|
+ * 37: {"mac":"","seq":"","ip":"","online":}
|
|
|
+ * */
|
|
|
+ size_t size = mac.size() + seq.size() + ip.size() + 38;
|
|
|
+ std::string res(size, 0);
|
|
|
+ sprintf(
|
|
|
+ res.data(), R"({"mac":"%s","seq":"%s","ip":"%s","online":%d})",
|
|
|
+ mac.c_str(), seq.c_str(), ip.c_str(), online
|
|
|
+ );
|
|
|
+ return res;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool Device::getFaceUsers(std::vector<std::string> &users, std::string &msg) {
|
|
|
+ for (User &user : faceUserList) users.push_back(user.getJsonStr());
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool Device::insertFaceUser(const User &user, std::string &msg) {
|
|
|
+ if (varUserExists(user.uid)) {
|
|
|
+ msg = "user existed already";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ NET_IN_ACCESS_USER_SERVICE_INSERT in;
|
|
|
+ in.dwSize = sizeof in;
|
|
|
+ in.nInfoNum = 1;
|
|
|
+ auto *usr = new NET_ACCESS_USER_INFO;
|
|
|
+ usr->bUserIDEx = 0;
|
|
|
+ strcpy(usr->szUserID, user.uid.c_str());
|
|
|
+ usr->bUseNameEx = 0;
|
|
|
+ strcpy(usr->szName, user.name.c_str());
|
|
|
+ strcpy(usr->szPsw, user.password.c_str());
|
|
|
+ usr->emUserType = NET_ENUM_USER_TYPE_NORMAL;
|
|
|
+ usr->nUserStatus = 0;
|
|
|
+ usr->nDoorNum = 1, usr->nDoors[0] = 0;
|
|
|
+ usr->nTimeSectionNum = 1, usr->nTimeSectionNo[0] = 255;
|
|
|
+ usr->nSpecialDaysScheduleNum = 1, usr->nSpecialDaysSchedule[0] = 255;
|
|
|
+ time_t tst = user.timestamp / 1000;
|
|
|
+ struct tm *timeInfo = localtime(&tst);
|
|
|
+ usr->stuValidEndTime.dwYear = timeInfo->tm_year + 1900;
|
|
|
+ usr->stuValidEndTime.dwMonth = timeInfo->tm_mon + 1;
|
|
|
+ usr->stuValidEndTime.dwDay = timeInfo->tm_mday;
|
|
|
+ usr->stuValidEndTime.dwHour = timeInfo->tm_hour;
|
|
|
+ usr->stuValidEndTime.dwMinute = timeInfo->tm_min;
|
|
|
+ usr->stuValidEndTime.dwSecond = timeInfo->tm_sec;
|
|
|
+ usr->stuValidBeginTime.dwYear = 2000;
|
|
|
+ usr->stuValidBeginTime.dwMonth = 1;
|
|
|
+ usr->stuValidBeginTime.dwDay = 1;
|
|
|
+ usr->stuValidBeginTime.dwHour = 0;
|
|
|
+ usr->stuValidBeginTime.dwMinute = 0;
|
|
|
+ usr->stuValidBeginTime.dwSecond = 0;
|
|
|
+ usr->nFirstEnterDoorsNum = 0;
|
|
|
+ usr->emAuthority = NET_ATTENDANCE_AUTHORITY_CUSTOMER;
|
|
|
+ usr->nFloorNum = 0;
|
|
|
+ usr->nRoom = 0;
|
|
|
+ usr->bFloorNoExValid = 0;
|
|
|
+ usr->nFloorNumEx = 0;
|
|
|
+ usr->bFloorNoEx2Valid = 0;
|
|
|
+ usr->nUserTimeSectionsNum = 0;
|
|
|
+ usr->bUserInfoExValid = 0;
|
|
|
+ usr->bUserInfoEx2Valid = 0;
|
|
|
+ in.pUserInfo = usr;
|
|
|
+
|
|
|
+ NET_OUT_ACCESS_USER_SERVICE_INSERT out;
|
|
|
+ out.dwSize = sizeof out;
|
|
|
+ out.nMaxRetNum = 1;
|
|
|
+ out.pFailCode = new NET_EM_FAILCODE;
|
|
|
+
|
|
|
+ bool ok = true, res = CLIENT_OperateAccessUserService(
|
|
|
+ loginId, NET_EM_ACCESS_CTL_USER_SERVICE_INSERT, &in, &out, gWaitTime
|
|
|
+ );
|
|
|
+ if (res) {
|
|
|
+ res = addUserFace(user.uid, user.face, msg);
|
|
|
+ if (res) varUserInsert(user);
|
|
|
+ else {
|
|
|
+ ok = false;
|
|
|
+ removeUserOnly(user.uid, msg);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ ok = false;
|
|
|
+ msg = "usr info insert failed";
|
|
|
+ }
|
|
|
+ delete usr;
|
|
|
+ delete out.pFailCode;
|
|
|
+ return ok;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool Device::removeFaceUser(const std::string &uid, std::string &msg) {
|
|
|
+ if (!varUserExists(uid)) {
|
|
|
+ msg = "no such user";
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ bool ok1 = removeUserFace(uid, msg), ok2 = removeUserOnly(uid, msg);
|
|
|
+ return ok1 && ok2;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool Device::getCarWoBList(const bool &isBlack, std::vector<std::string> &list, std::string &msg) {
|
|
|
+ for (Plate &plate : isBlack ? carBlackList : carWhiteList) list.push_back(plate.getJsonStr());
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool Device::insertCarWoBList(const bool &isBlack, std::vector<Plate> &list, std::string &msg) {
|
|
|
+ json::Parser parser;
|
|
|
+ json::Value result = parser.parse("[]");
|
|
|
+ for (Plate &info : list) {
|
|
|
+ json::Value one = parser.parse("{}");
|
|
|
+ std::string reason;
|
|
|
+ bool res = insertOneCarWoBList(isBlack, info, reason);
|
|
|
+ one["cid"] = json::Value(info.cid);
|
|
|
+ one["plate"] = json::Value(info.plate);
|
|
|
+ one["success"] = json::Value(res);
|
|
|
+ one["msg"] = json::Value(reason);
|
|
|
+ result.push_back(one);
|
|
|
+ }
|
|
|
+ msg = result.str();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+
|
|
|
+ bool Device::removeCarWoBList(const bool &isBlack, const std::vector<int> &cids, std::string &msg) {
|
|
|
+ json::Parser parser;
|
|
|
+ json::Value result = parser.parse("[]");
|
|
|
+ for (const int &cid : cids) {
|
|
|
+ json::Value one = parser.parse("{}");
|
|
|
+ std::string reason;
|
|
|
+ bool res = removeOneCarWoBList(isBlack, cid, reason);
|
|
|
+ one["cid"] = json::Value(cid);
|
|
|
+ one["success"] = json::Value(res);
|
|
|
+ one["msg"] = json::Value(reason);
|
|
|
+ result.push_back(one);
|
|
|
+ }
|
|
|
+ msg = result.str();
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+}
|