Initial commit

This commit is contained in:
2026-04-23 14:23:42 +08:00
commit 9ceba6f9e3
141 changed files with 2886 additions and 0 deletions

View File

@@ -0,0 +1,13 @@
package com.noblelift.ota.common.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Log {
String value() default "";
}

View File

@@ -0,0 +1,61 @@
package com.noblelift.ota.common.aspect;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.noblelift.ota.common.annotation.Log;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import java.util.Arrays;
@Aspect
@Component
@Slf4j
@RequiredArgsConstructor
public class LogAspect {
private final ObjectMapper objectMapper;
@Around("@annotation(logAnnotation)")
public Object around(ProceedingJoinPoint joinPoint, Log logAnnotation) throws Throwable {
long start = System.currentTimeMillis();
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
HttpServletRequest request = requestAttributes instanceof ServletRequestAttributes servletRequestAttributes
? servletRequestAttributes.getRequest()
: null;
String requestUri = request == null ? "N/A" : request.getRequestURI();
String requestMethod = request == null ? "N/A" : request.getMethod();
String params = serializeArgs(joinPoint.getArgs());
String operation = logAnnotation.value().isBlank() ? signature.getMethod().getName() : logAnnotation.value();
log.info("[API-REQUEST] operation={}, method={}, uri={}, params={}", operation, requestMethod, requestUri, params);
try {
Object result = joinPoint.proceed();
log.info("[API-RESPONSE] operation={}, duration={}ms", operation, System.currentTimeMillis() - start);
return result;
} catch (Throwable ex) {
log.error("[API-ERROR] operation={}, duration={}ms, message={}", operation, System.currentTimeMillis() - start, ex.getMessage(), ex);
throw ex;
}
}
private String serializeArgs(Object[] args) {
Object[] filtered = Arrays.stream(args)
.filter(arg -> !(arg instanceof HttpServletRequest))
.toArray();
try {
return objectMapper.writeValueAsString(filtered);
} catch (JsonProcessingException e) {
return Arrays.toString(filtered);
}
}
}

View File

@@ -0,0 +1,19 @@
package com.noblelift.ota.common.dto;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.Instant;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ApiMessage {
private String code;
private String message;
private Instant timestamp;
}

View File

@@ -0,0 +1,24 @@
package com.noblelift.ota.common.model;
import com.noblelift.ota.domain.UpgradeMode;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.Instant;
import java.util.Map;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class ReleaseManifest {
private String releaseVersion;
private String releaseNotes;
private UpgradeMode upgradeMode;
private Instant publishedAt;
private Boolean parkingRequired;
private Map<String, Object> components;
}

View File

@@ -0,0 +1,26 @@
package com.noblelift.ota.common.model;
import com.noblelift.ota.domain.TaskStatus;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.Instant;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class VehicleAssignment {
private String vehicleId;
private String releaseVersion;
private TaskStatus taskStatus;
private Instant promptedAt;
private Instant confirmedAt;
private Instant startedAt;
private Instant finishedAt;
private Integer postponeCount;
private String lastMessage;
}

View File

@@ -0,0 +1,31 @@
package com.noblelift.ota.common.model;
import com.noblelift.ota.domain.AgentStatus;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.Instant;
import java.util.Map;
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class VehicleInfo {
private String vehicleId;
private String vin;
private String currentRelease;
private String currentBackendVersion;
private String currentFrontendVersion;
private String currentRosVersion;
private Instant lastSeenAt;
private AgentStatus agentStatus;
private String targetRelease;
private String lastResult;
private Map<String, String> images;
private String backupFile;
private Boolean online;
}

View File

@@ -0,0 +1,42 @@
package com.noblelift.ota.common.util;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public final class ReleaseVersionComparator {
private static final Pattern TOKEN_PATTERN = Pattern.compile("\\d+");
private ReleaseVersionComparator() {
}
public static int compare(String left, String right) {
List<String> leftTokens = tokenize(left);
List<String> rightTokens = tokenize(right);
int size = Math.max(leftTokens.size(), rightTokens.size());
for (int i = 0; i < size; i++) {
String leftToken = i < leftTokens.size() ? leftTokens.get(i) : "0";
String rightToken = i < rightTokens.size() ? rightTokens.get(i) : "0";
int result = new BigInteger(leftToken).compareTo(new BigInteger(rightToken));
if (result != 0) {
return result;
}
}
return 0;
}
private static List<String> tokenize(String value) {
List<String> tokens = new ArrayList<>();
if (value == null || value.isBlank()) {
return tokens;
}
Matcher matcher = TOKEN_PATTERN.matcher(value);
while (matcher.find()) {
tokens.add(matcher.group());
}
return tokens;
}
}