package com.ruoyi.web.integration.dahua;
|
|
import com.ruoyi.common.config.RuoYiConfig;
|
import com.ruoyi.system.utils.DoorDeviceCredentialCrypto;
|
|
import javax.imageio.ImageIO;
|
import java.awt.image.BufferedImage;
|
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayOutputStream;
|
import java.nio.file.Files;
|
import java.nio.file.Path;
|
import java.nio.file.Paths;
|
import java.util.Date;
|
|
/**
|
* 仅用于实体门禁联调:临时下发测试人员和人脸,并在 finally 中立即撤权。
|
*/
|
public final class DahuaGrantProbe {
|
|
private static final String TEST_USER_ID = "CODEX_TEST_20260810";
|
private static final String TEST_USER_NAME = "门禁联调测试";
|
private static final long ONE_MINUTE_MILLIS = 60_000L;
|
private static final int DEVICE_FACE_IMAGE_LIMIT = 200 * 1024;
|
|
private DahuaGrantProbe() {
|
}
|
|
public static void main(String[] args) throws Exception {
|
if (args.length != 5) {
|
throw new IllegalArgumentException("参数:原生库目录、设备地址、用户名、profile目录、人脸图片地址");
|
}
|
|
String passwordCipher = System.getenv("DAHUA_DEVICE_PASSWORD_CIPHER");
|
if (passwordCipher == null || passwordCipher.trim().isEmpty()) {
|
throw new IllegalArgumentException("缺少 DAHUA_DEVICE_PASSWORD_CIPHER");
|
}
|
String password = DoorDeviceCredentialCrypto.decrypt(passwordCipher);
|
|
new RuoYiConfig().setProfile(args[3]);
|
byte[] faceImage = new DahuaFaceImageLoader().load(args[4]);
|
DahuaAccessProperties properties = createProperties(args[0], args[2], password);
|
DahuaAccessControlClient client = new DahuaAccessControlClient(properties);
|
DahuaDeviceCredential device = new DahuaDeviceCredential(
|
args[1], 37777, args[2], password, 0, 255, "GBK");
|
|
long now = System.currentTimeMillis();
|
DahuaAccessControlClient.VisitorCredential visitor =
|
new DahuaAccessControlClient.VisitorCredential(
|
TEST_USER_ID,
|
TEST_USER_NAME,
|
null,
|
new Date(now - ONE_MINUTE_MILLIS),
|
new Date(now + 5 * ONE_MINUTE_MILLIS),
|
faceImage);
|
|
RuntimeException grantFailure = null;
|
try {
|
client.grant(device, visitor);
|
System.out.println("grantSuccess=true");
|
} catch (RuntimeException e) {
|
grantFailure = e;
|
throw e;
|
} finally {
|
try {
|
client.revoke(device, TEST_USER_ID);
|
System.out.println("revokeSuccess=true");
|
} catch (RuntimeException revokeFailure) {
|
if (grantFailure != null) {
|
grantFailure.addSuppressed(revokeFailure);
|
} else {
|
throw revokeFailure;
|
}
|
} finally {
|
client.cleanup();
|
}
|
}
|
}
|
|
private static DahuaAccessProperties createProperties(String nativeLibraryPath,
|
String username,
|
String password) {
|
DahuaAccessProperties properties = new DahuaAccessProperties();
|
properties.setNativeLibraryPath(nativeLibraryPath);
|
properties.setConnectTimeout(5000);
|
properties.setTimeout(10000);
|
return properties;
|
}
|
|
private static byte[] loadFaceImage(Path path) throws Exception {
|
byte[] image = Files.readAllBytes(path);
|
if (image.length == 0 || image.length > DahuaSdkLayout.MAX_FACE_IMAGE_BYTES) {
|
throw new IllegalArgumentException("人脸图片必须大于0且不超过200KB");
|
}
|
if (!isJpeg(image) && !isPng(image)) {
|
throw new IllegalArgumentException("人脸图片必须是有效的JPEG或PNG文件");
|
}
|
if (image.length <= DEVICE_FACE_IMAGE_LIMIT && isJpeg(image)) {
|
return image;
|
}
|
|
BufferedImage source = ImageIO.read(new ByteArrayInputStream(image));
|
if (source == null) {
|
throw new IllegalArgumentException("无法解码人脸图片");
|
}
|
ByteArrayOutputStream output = new ByteArrayOutputStream();
|
if (!ImageIO.write(source, "jpg", output)) {
|
throw new IllegalArgumentException("无法将人脸图片转换为JPEG");
|
}
|
byte[] normalized = output.toByteArray();
|
if (normalized.length > DEVICE_FACE_IMAGE_LIMIT) {
|
throw new IllegalArgumentException("人脸图片转换后仍超过120KB");
|
}
|
System.out.println("normalizedFaceBytes=" + normalized.length);
|
return normalized;
|
}
|
|
private static boolean isJpeg(byte[] image) {
|
return image.length >= 3
|
&& (image[0] & 0xFF) == 0xFF
|
&& (image[1] & 0xFF) == 0xD8
|
&& (image[2] & 0xFF) == 0xFF;
|
}
|
|
private static boolean isPng(byte[] image) {
|
return image.length >= 8
|
&& (image[0] & 0xFF) == 0x89
|
&& image[1] == 0x50
|
&& image[2] == 0x4E
|
&& image[3] == 0x47
|
&& image[4] == 0x0D
|
&& image[5] == 0x0A
|
&& image[6] == 0x1A
|
&& image[7] == 0x0A;
|
}
|
}
|