package com.xiaopeng.map.service.serviceimpl; import com.xiaopeng.map.config.VinSaltProperties; import com.xiaopeng.map.dto.AreaInput; import com.xiaopeng.map.service.AdcOssHandleService; import com.xiaopeng.map.service.RobotaxiOssService; import com.xiaopeng.map.utils.MapAreaVersionProtoWriter; import com.xiaopeng.map.utils.VehicleCodec; import com.xiaopeng.map.utils.XngpAreaRTreeFbsUtil; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; import org.springframework.stereotype.Service; import org.springframework.util.CollectionUtils; import org.springframework.util.StringUtils; import java.util.List; /** * ADC OSS 处理服务实现,根据坐标点生成 RTree fbs 并上传至 OSS。 */ @Slf4j @Service @RequiredArgsConstructor @ConditionalOnBean(RobotaxiOssService.class) public class AdcOssHandleServiceImpl implements AdcOssHandleService { private final RobotaxiOssService robotaxiOssService; private final VinSaltProperties vinSaltProperties; @Override public String uploadOddLayerFile(List areas, String vin, long version) { log.info("[ADC-OSS] uploadOddLayerFile 开始, vin={}, version={}, areasCount={}", vin, version, areas == null ? 0 : areas.size()); if (areas != null) { for (int i = 0; i < areas.size(); i++) { AreaInput a = areas.get(i); log.info("[ADC-OSS] area[{}]: areaId={}, isBlacklist={}, pointsCount={}", i, a.getAreaId(), a.isBlacklist(), a.getPoints() == null ? 0 : a.getPoints().size()); } } validateParams(areas, vin); String vehicleUuid = VehicleCodec.vinToUUID(vin, vinSaltProperties.getSalt1(), vinSaltProperties.getSalt2()); log.info("[ADC-OSS] VIN={} -> UUID={}", vin, vehicleUuid); byte[] fbsBytes = XngpAreaRTreeFbsUtil.buildRTreeBytesFromMultiAreas(areas); if (fbsBytes == null || fbsBytes.length == 0) { log.info("[ADC-OSS] buildRTreeBytesFromMultiAreas 返回空, vin={}", vin); throw new IllegalStateException("Failed to build RTree fbs from areas"); } log.info("[ADC-OSS] FBS构建成功, vin={}, fbsSize={}bytes", vin, fbsBytes.length); String binFileName = version + "_xngp_area_data.bin"; String objectKey = robotaxiOssService.uploadOddLayerFile(fbsBytes, binFileName, vehicleUuid); log.info("[ADC-OSS] bin文件上传成功, vin={}, objectKey={}", vin, objectKey); byte[] pbBytes = MapAreaVersionProtoWriter.toByteArray((int) version, fbsBytes.length); robotaxiOssService.uploadOddLayerFile(pbBytes, "xngp_area_version.pb", vehicleUuid); log.info("[ADC-OSS] pb版本文件上传成功, vin={}, version={}", vin, version); return objectKey; } @Override public String uploadEmptyFence(String vin, long version) { log.info("[ADC-OSS] uploadEmptyFence 开始, vin={}, version={}", vin, version); if (!StringUtils.hasText(vin)) { throw new IllegalArgumentException("vin cannot be empty"); } String vehicleUuid = VehicleCodec.vinToUUID(vin, vinSaltProperties.getSalt1(), vinSaltProperties.getSalt2()); log.info("[ADC-OSS] VIN={} -> UUID={}", vin, vehicleUuid); byte[] fbsBytes = XngpAreaRTreeFbsUtil.buildEmptyRTreeBytes(); if (fbsBytes == null || fbsBytes.length == 0) { log.info("[ADC-OSS] buildEmptyRTreeBytes 返回空, vin={}", vin); throw new IllegalStateException("Failed to build empty RTree fbs"); } log.info("[ADC-OSS] 空FBS构建成功, vin={}, fbsSize={}bytes", vin, fbsBytes.length); String binFileName = version + "_xngp_area_data.bin"; String objectKey = robotaxiOssService.uploadOddLayerFile(fbsBytes, binFileName, vehicleUuid); log.info("[ADC-OSS] 空FBS bin文件上传成功, vin={}, objectKey={}", vin, objectKey); byte[] pbBytes = MapAreaVersionProtoWriter.toByteArray((int) version, fbsBytes.length); robotaxiOssService.uploadOddLayerFile(pbBytes, "xngp_area_version.pb", vehicleUuid); log.info("[ADC-OSS] 空FBS pb版本文件上传成功, vin={}, version={}", vin, version); return objectKey; } private void validateParams(List areas, String vin) { if (CollectionUtils.isEmpty(areas)) { log.info("[ADC-OSS] validateParams失败: areas为空, vin={}", vin); throw new IllegalArgumentException("areas cannot be empty"); } for (int i = 0; i < areas.size(); i++) { AreaInput area = areas.get(i); if (CollectionUtils.isEmpty(area.getPoints())) { log.info("[ADC-OSS] validateParams失败: area[{}] areaId={} points为空, vin={}", i, area.getAreaId(), vin); throw new IllegalArgumentException("each area must have non-empty points, areaId=" + area.getAreaId()); } } if (!StringUtils.hasText(vin)) { log.info("[ADC-OSS] validateParams失败: vin为空"); throw new IllegalArgumentException("vin cannot be empty"); } } }