package quant.rich.emoney.entity.config; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.Random; import java.util.regex.Matcher; import java.util.regex.Pattern; import com.fasterxml.jackson.annotation.JsonView; import lombok.Data; import lombok.experimental.Accessors; import lombok.extern.slf4j.Slf4j; import quant.rich.emoney.interfaces.ConfigInfo; import quant.rich.emoney.interfaces.IConfig; @Data @Accessors(chain = true) @Slf4j @ConfigInfo( field = "deviceInfo", name = "设备信息设置", initDefault = true, managed = false) public class DeviceInfoConfig implements IConfig { private static final Random RANDOM = new Random(); @JsonView(IConfig.Views.Persistence.class) List deviceInfos; public DeviceInfoConfig() { deviceInfos = new ArrayList<>(); } /** * 获取随机设备信息 * @return */ public DeviceInfo getRandomDeviceInfo() { if (deviceInfos.isEmpty()) return null; return deviceInfos.get(RANDOM.nextInt(deviceInfos.size())); } @Data @Accessors(chain=true) @Slf4j public static class DeviceInfo { // 持久化在本地的 DeviceInfo 只有三个字段: // model、deviceType 和 fingerprint // 其中除 model 和 deviceType 外,其他字段全部从 fingerprint 派生 // 也就是说只要提供 model、deviceType 和 fingerprint 就能创建一个 DeviceInfo 实例 @JsonView(IConfig.Views.Persistence.class) private String model; private String brand; private String product; private String device; @JsonView(IConfig.Views.Persistence.class) private String deviceType; private String versionRelease; private String buildId; private String buildNumber; private String buildType; private String buildTags; /** * 用以匹配 fingerprint 的正则表达式 */ public static final Pattern PATTERN = Pattern.compile("^(?.*?)/(?.*?)/(?.*?):(?.*?)/(?.*?)/(?.*?):(?.*?)/(?.*?)$"); private DeviceInfo() {} public DeviceInfo setFingerprint(String fingerprint) { Matcher m = PATTERN.matcher(fingerprint); if (!m.matches()) { throw new IllegalArgumentException("Fingerprint not match the pattern: " + fingerprint); } this.setBrand(m.group("brand")); this.setBuildId(m.group("buildId")); this.setBuildNumber(m.group("buildNumber")); this.setBuildTags(m.group("buildTags")); this.setBuildType(m.group("buildType")); this.setProduct(m.group("product")); this.setVersionRelease(m.group("versionRelease")); this.setDevice(m.group("device")); return this; } public DeviceInfo setDeviceType(String deviceType) { if (!"Mobile".equals(deviceType) && !"Pad".equals(deviceType)) { throw new IllegalArgumentException("DeviceType must be \"Mobile\" or \"Pad\", but got \"" + deviceType + "\""); } this.deviceType = deviceType; return this; } /** * 根据指定 model、fingerprint 和 deviceType 返回 DeviceInfo * @param model * @param fingerprint * @param deviceType * @return */ public static DeviceInfo from(String model, String fingerprint, String deviceType) { DeviceInfo deviceInfo = new DeviceInfo(); deviceInfo.setModel(model); deviceInfo.setFingerprint(fingerprint); deviceInfo.setDeviceType(deviceType); return deviceInfo; } public static DeviceInfo from(String model, String fingerprint) { return from(model, fingerprint, "Mobile"); } /** * 从设备信息中还原 fingerprint * @return */ @JsonView(IConfig.Views.Persistence.class) public String getFingerprint() { return String.format("%s/%s/%s:%s/%s/%s:%s/%s", getBrand(), getProduct(), getDevice(), getVersionRelease(), getBuildId(), getBuildNumber(), getBuildType(), getBuildTags() ); } public final String toString() { return String.format("Model: %s, DeviceType: %s, Fingerprint: %s", getModel(), getDeviceType(), getFingerprint() ); } public boolean equals(Object obj) { if (this == obj) return true; if (obj == null || getClass() != obj.getClass()) return false; DeviceInfo other = (DeviceInfo)obj; return hashCode() == other.hashCode(); } public int hashCode() { return Objects.hash(getModel(), getDeviceType(), getFingerprint()); } } }