Browse Source

支持网络配置

master
zhaohe 1 month ago
parent
commit
afb1b9bb7a
  1. 5
      src/main/java/a8k/BoditechA800Application.java
  2. 106
      src/main/java/a8k/OS.java
  3. 3
      src/main/java/a8k/app/channel/iflytophald/type/protocol/A8kEcode.java
  4. 4
      src/main/java/a8k/app/controler/api/v1/app/setting/DeviceInfoControler.java
  5. 6
      src/main/java/a8k/app/controler/api/v1/app/setting/DeviceSettingController.java
  6. 7
      src/main/java/a8k/app/controler/api/v1/app/setting/NetworkSettingController.java
  7. 3
      src/main/java/a8k/app/dao/type/db/NetworkSetting.java
  8. 2
      src/main/java/a8k/app/i18n/Internationalization.java
  9. 103
      src/main/java/a8k/app/service/os/OSNetworkMgrService.java
  10. 2
      src/main/java/a8k/app/service/os/OSTimeMgrService.java
  11. 33
      src/main/java/a8k/app/service/setting/AppNetworkSettingService.java
  12. 9
      src/main/java/a8k/app/service/statemgr/GStateMgrService.java
  13. 2
      src/main/java/a8k/app/type/GState.java
  14. 4
      src/main/java/a8k/iflyutils/netplan/NetplanConfigFactory.java

5
src/main/java/a8k/BoditechA800Application.java

@ -10,6 +10,9 @@ import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.core.env.Environment;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@Slf4j
@SpringBootApplication
public class BoditechA800Application implements ApplicationListener<ContextRefreshedEvent> {
@ -19,8 +22,6 @@ public class BoditechA800Application implements ApplicationListener<ContextRefre
public static void main(String[] args) {
SpringApplication.run(BoditechA800Application.class, args);
}
@Override

106
src/main/java/a8k/OS.java

@ -1,7 +1,36 @@
package a8k;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.util.Enumeration;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@Slf4j
@Component
public class OS {
@Data
public static class LinuxCommandResult {
private final int exitCode;
private final String output;
public LinuxCommandResult(int exitCode, String output) {
this.exitCode = exitCode;
this.output = output;
}
}
public static void hsleep(int ms) {
forceSleep(ms);
}
@ -26,4 +55,81 @@ public class OS {
String os = System.getProperty("os.name").toLowerCase();
return os.contains("windows");
}
public static LinuxCommandResult executeLinuxCommand(String command, long timeout, TimeUnit unit)
throws IOException, InterruptedException {
if (isRunOnWindows()) {
log.info("当前操作系统为Windows,无法执行Linux命令: {}", command);
return new LinuxCommandResult(-1, "当前操作系统为Windows,无法执行Linux命令: " + command);
}
ProcessBuilder builder = new ProcessBuilder("/bin/bash", "-c", command);
builder.redirectErrorStream(true);
Process process = builder.start();
// 读取输出
StringBuilder output = new StringBuilder();
try (InputStream inputStream = process.getInputStream();
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))) {
String line;
while ((line = reader.readLine()) != null) {
output.append(line).append("\n");
}
}
// 等待命令完成带超时
boolean completed = process.waitFor(timeout, unit);
if (!completed) {
process.destroyForcibly();
throw new InterruptedException("命令执行超时");
}
return new LinuxCommandResult(process.exitValue(), output.toString());
}
static public String getEthName() {
return "eth1";
}
static public String getLocalIp() {
if (isRunOnWindows()) {
return "W:0.0.0.0";
}
NetworkInterface networkInterface = null;
try {
networkInterface = NetworkInterface.getByName(getEthName());
} catch (SocketException e) {
log.error("获取网卡 {} 时发生错误: {}", getEthName(), e.getMessage());
return "";
}
if (networkInterface == null) {
log.warn("未找到网卡: {}", getEthName());
return "";
}
try {
if (!networkInterface.isUp()) {
log.warn("网卡 {} 未启用", getEthName());
return "";
}
} catch (SocketException e) {
log.error("检查网卡 {} 状态时发生错误: {}", getEthName(), e.getMessage());
return "";
}
Enumeration<InetAddress> inetAddresses = networkInterface.getInetAddresses();
while (inetAddresses.hasMoreElements()) {
InetAddress inetAddress = inetAddresses.nextElement();
if (!inetAddress.isLoopbackAddress() && inetAddress instanceof Inet4Address) {
return inetAddress.getHostAddress();
}
}
log.warn("网卡 {} 没有找到有效的IPv4地址", getEthName());
return "";
}
public static void main(String[] args) {
System.out.println("LOCAL IP: " + OS.getLocalIp());
}
}

3
src/main/java/a8k/app/channel/iflytophald/type/protocol/A8kEcode.java

@ -32,6 +32,9 @@ public enum A8kEcode {
APPE_PAUSE_OPERATION_NOT_SUPPORT_IN_ENGINEER_TASK(20), //
APPE_CONTINUE_OPERATION_NOT_SUPPORT_IN_ENGINEER_TASK(21), //
APPE_WAST_BIN_IS_FULL(22), //废料箱已满
SYS_CMD_EXEC_OVERTIME(23), //Linux命令执行超时
NETWORK_PARAMETER_ERROR(24), //网络参数错误
//
// 参数错误

4
src/main/java/a8k/app/controler/api/v1/app/setting/DeviceInfoControler.java

@ -37,7 +37,7 @@ public class DeviceInfoControler {
info.mcuVersion = gstate.getMcuVersion();
info.sn = gstate.getSn();
info.factorySN = gstate.getFactorySn();
info.ip = "192.168.8.10";
info.ip = gstate.getLocalIp();
return ApiRet.success(info);
}
@ -57,7 +57,7 @@ public class DeviceInfoControler {
@PostMapping("/getIp")
public ApiRet<String> readdeviceip() {
//TODO:
return ApiRet.success("192.168.8.10");
return ApiRet.success(gstate.getLocalIp());
}
}

6
src/main/java/a8k/app/controler/api/v1/app/setting/DeviceSettingController.java

@ -1,6 +1,6 @@
package a8k.app.controler.api.v1.app.setting;
import a8k.app.service.os.OSSettingService;
import a8k.app.service.os.OSTimeMgrService;
import a8k.app.type.exception.AppException;
import a8k.app.type.ui.ApiRet;
import a8k.app.dao.type.db.DeviceSetting;
@ -26,7 +26,7 @@ import java.util.List;
@RequiredArgsConstructor
public class DeviceSettingController {
private final AppSettingsMgrService appSettingsMgrService;
private final OSSettingService osSettingService;
private final OSTimeMgrService osTimeMgrService;
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// EXT FUNC
@ -119,7 +119,7 @@ public class DeviceSettingController {
@Operation(summary = "设置时间")
@PostMapping("/setDateAndTime")
public void setDateAndTime(String datetime) {
osSettingService.setDateAndTime(datetime);
osTimeMgrService.setDateAndTime(datetime);
}
}

7
src/main/java/a8k/app/controler/api/v1/app/setting/NetworkSettingController.java

@ -1,7 +1,8 @@
package a8k.app.controler.api.v1.app.setting;
import a8k.app.dao.type.db.NetworkSetting;
import a8k.app.service.setting.AppNetworkSettingService;
import a8k.app.service.os.OSNetworkMgrService;
import a8k.app.type.exception.AppException;
import a8k.app.type.ui.ApiRet;
import a8k.app.utils.ZJsonHelper;
import io.swagger.v3.oas.annotations.Operation;
@ -22,7 +23,7 @@ import org.springframework.web.bind.annotation.ResponseBody;
@ResponseBody
public class NetworkSettingController {
@Resource
AppNetworkSettingService appNetworkService;
OSNetworkMgrService appNetworkService;
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
// EXT FUNC
// ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
@ -36,7 +37,7 @@ public class NetworkSettingController {
@Operation(summary = "设置系统设置")
@PostMapping("/setNetworkSetting")
public ApiRet<Void> setNetworkSetting(@RequestBody NetworkSetting setting) {
public ApiRet<Void> setNetworkSetting(@RequestBody NetworkSetting setting) throws AppException {
log.info("设置LIS配置 {}", ZJsonHelper.objToPrettyJson(setting));
appNetworkService.setNetworkSetting(setting);
return ApiRet.success();

3
src/main/java/a8k/app/dao/type/db/NetworkSetting.java

@ -15,7 +15,7 @@ public class NetworkSetting implements Serializable {
public String ip = "192.168.8.10";
public String netmask = "255.255.255.0";
public String gateway = "192.168.8.1";
public List<String> dnsList = ZList.of("223.5.5.5", "223.6.6.6");
public List<String> dnsList = ZList.of("192.168.8.1");
}
static public class DynamicIpConfig {
@ -23,6 +23,7 @@ public class NetworkSetting implements Serializable {
public List<String> dnsList = ZList.of("223.5.5.5", "223.6.6.6");
}
public Boolean firstRun = true; // 是否第一次运行第一次运行需要初始化网络配置
public NetworkMode networkMode = NetworkMode.STATIC_IP;
public StaticIPConfig staticIPConfig = new StaticIPConfig();
public DynamicIpConfig dynamicIpConfig = new DynamicIpConfig();

2
src/main/java/a8k/app/i18n/Internationalization.java

@ -81,6 +81,8 @@ public class Internationalization {
case APPE_PAUSE_OPERATION_NOT_SUPPORT_IN_ENGINEER_TASK -> "工程师任务,不支持暂停操作";
case APPE_CONTINUE_OPERATION_NOT_SUPPORT_IN_ENGINEER_TASK -> "工程师任务,不支持继续操作";
case APPE_WAST_BIN_IS_FULL -> "废料箱已满";
case SYS_CMD_EXEC_OVERTIME -> "系统指令超时";
case NETWORK_PARAMETER_ERROR -> "网络参数错误";
default -> ecode.toString();
};
}

103
src/main/java/a8k/app/service/os/OSNetworkMgrService.java

@ -0,0 +1,103 @@
package a8k.app.service.os;
import a8k.OS;
import a8k.app.channel.iflytophald.type.protocol.A8kEcode;
import a8k.app.dao.NetworkSettingDao;
import a8k.app.dao.type.db.NetworkSetting;
import a8k.app.service.statemgr.GStateMgrService;
import a8k.app.type.exception.AppException;
import a8k.iflyutils.netplan.NetplanConfigFactory;
import a8k.iflyutils.netplan.exception.NetSettingIllegalException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.io.FileWriter;
import java.io.IOException;
import java.util.concurrent.TimeUnit;
@Component
@Slf4j
@RequiredArgsConstructor
@EnableScheduling
public class OSNetworkMgrService implements ApplicationListener<ContextRefreshedEvent> {
private final NetworkSettingDao networkSettingDao;
private final GStateMgrService gStateMgrService;
public NetworkSetting getNetworkSetting() {
return networkSettingDao.get();
}
public void setNetworkSetting(NetworkSetting setting) throws AppException {
try {
doSetNetworkSetting(setting);
} catch (NetSettingIllegalException e) {
throw AppException.of(A8kEcode.NETWORK_PARAMETER_ERROR, e.getMessage());
} catch (IOException e) {
throw AppException.of(A8kEcode.CODEERROR, e.getMessage());
}
networkSettingDao.update(setting);
log.info("Network configuration updated: {}", setting);
}
public void doSetNetworkSetting(NetworkSetting setting) throws NetSettingIllegalException, IOException, AppException {
if (OS.isRunOnWindows()) {
return;
}
NetplanConfigFactory netplanConfigFactory = new NetplanConfigFactory();
String netplanConfigContent = "";
switch (setting.networkMode) {
case STATIC_IP -> netplanConfigContent = netplanConfigFactory.newStaticEthernetConfig(
OS.getEthName(),
setting.staticIPConfig.ip,
setting.staticIPConfig.netmask,
setting.staticIPConfig.gateway,
setting.staticIPConfig.dnsList);
case DYNAMIC_IP -> netplanConfigContent = netplanConfigFactory.newDynamicEthernetConfig(
OS.getEthName(), setting.dynamicIpConfig.autoDns, setting.dynamicIpConfig.dnsList);
}
//参考规范 https://iflytop1.feishu.cn/wiki/I2v5whcqEitWeRkFZtKcuC08nxe
try (FileWriter writer = new FileWriter("/etc/netplan/00_netplan_config.yaml")) {
///etc/netplan/00_netplan_config.yaml写入配置文件
writer.write(netplanConfigContent);
}
try {
OS.executeLinuxCommand("netplan apply", 5, TimeUnit.SECONDS);
} catch (InterruptedException e) {
throw new AppException(A8kEcode.SYS_CMD_EXEC_OVERTIME);
}
log.info("Network configuration applied successfully: {}", setting);
}
@Scheduled(fixedDelay = 1000)
void updateLocalIp() {
gStateMgrService.updateLocalIp(OS.getLocalIp());
}
/**
* 在应用启动时设置网络配置
*/
@Override public void onApplicationEvent(ContextRefreshedEvent event) {
if (OS.isRunOnWindows()) {
return;
}
NetworkSetting setting = networkSettingDao.get();
try {
doSetNetworkSetting(setting);
setting.firstRun = false;
networkSettingDao.update(setting);
log.info("Network setting applied on startup: {}", setting);
} catch (Exception e) {
log.error("setting network failed: {}", e.getMessage());
}
}
}

2
src/main/java/a8k/app/service/os/OSSettingService.java → src/main/java/a8k/app/service/os/OSTimeMgrService.java

@ -10,7 +10,7 @@ import java.io.InputStreamReader;
@Component
@Slf4j
@RequiredArgsConstructor
public class OSSettingService {
public class OSTimeMgrService {
/**
* Set the system date and time.

33
src/main/java/a8k/app/service/setting/AppNetworkSettingService.java

@ -1,33 +0,0 @@
package a8k.app.service.setting;
import a8k.app.dao.NetworkSettingDao;
import a8k.app.dao.type.db.NetworkSetting;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
@Component
@Slf4j
@RequiredArgsConstructor
public class AppNetworkSettingService {
private final NetworkSettingDao networkSettingDao;
public NetworkSetting getNetworkSetting() {
return networkSettingDao.get();
}
public void setNetworkSetting(NetworkSetting setting) {
networkSettingDao.update(setting);
log.info("Network configuration updated: {}", setting);
}
}

9
src/main/java/a8k/app/service/statemgr/GStateMgrService.java

@ -132,6 +132,15 @@ public class GStateMgrService {
this.gState.fatalErrorInfo = null;
}
synchronized public void updateLocalIp(String localIp) {
this.gState.localIP = localIp;
}
synchronized public String getLocalIp() {
return this.gState.localIP;
}
@PostConstruct
public void init() {
log.info("GStateMgrService init {}", this.gState.deviceRunMode);

2
src/main/java/a8k/app/type/GState.java

@ -30,6 +30,8 @@ public class GState {
public Boolean fatalError = false;
//
public AppError fatalErrorInfo = null;
//
public String localIP = "";//设备IP
public SensorState sensorState = new SensorState();
}

4
src/main/java/a8k/iflyutils/netplan/NetplanConfigFactory.java

@ -25,8 +25,8 @@ public class NetplanConfigFactory {
* cat /run/systemd/resolve/resolv.conf
* 应用配置
* netplan apply
*
*
* 配置说明参考:
* https://wiki.t-firefly.com/zh_CN/Firefly-Linux-Guide/first_use.html#shi-yong-netplan-guan-li-wang-luo
*/
RendererType renderer = RendererType.NetworkManager;

Loading…
Cancel
Save