Allow arbitrary networktables address (#764)

* Allow specifying NT server address by ip.
This commit is contained in:
Doug Wegscheid
2023-05-12 18:01:09 -04:00
committed by GitHub
parent 6bdb158b33
commit 80f479344d
11 changed files with 73 additions and 26 deletions

View File

@@ -81,7 +81,7 @@
</v-list-item-title>
<router-link v-if="!$store.state.settings.networkSettings.runNTServer" to="settings" class="accent--text"
@click="switchToSettingsTab">
Team number is {{ $store.state.settings.networkSettings.teamNumber }}
NT server is {{ $store.state.settings.networkSettings.ntServerAddress }}
</router-link>
</v-list-item-content>
</v-list-item>
@@ -151,7 +151,7 @@ export default {
computed: {
needsTeamNumberSet: {
get() {
return this.$store.state.settings.networkSettings.teamNumber < 1
return this.$store.state.settings.networkSettings.ntServerAddress == ""
&& this.teamNumberDialog && this.$store.state.backendConnected
&& !this.$route.name.toLowerCase().includes("settings");
}

View File

@@ -135,7 +135,7 @@ export default new Vuex.Store({
hardwarePlatform: "Unknown",
},
networkSettings: {
teamNumber: 0,
ntServerAddress: "",
supported: true,
// Below options are only configurable if supported is true

View File

@@ -475,7 +475,7 @@ export default {
},
showNTWarning: {
get() {
return (!this.$store.state.ntConnectionInfo.connected || this.$store.state.settings.networkSettings.runNTServer) && this.$store.state.settings.networkSettings.teamNumber > 0 && this.$store.state.backendConnected && !this.hideNTWarning;
return (!this.$store.state.ntConnectionInfo.connected || this.$store.state.settings.networkSettings.runNTServer) && this.$store.state.settings.networkSettings.ntServerAddress != "" && this.$store.state.backendConnected && !this.hideNTWarning;
}
},
},

View File

@@ -4,21 +4,21 @@
ref="form"
v-model="valid"
>
<CVnumberinput
v-model="teamNumber"
<CVinput
v-model="ntServerAddress"
:input-cols="inputCols"
:disabled="settings.runNTServer"
name="Team Number"
:rules="[v => (v > 0) || 'Team number must be greater than zero', v => (v < 10000) || 'Team number must have fewer than five digits']"
class="mb-4"
:label-cols="$vuetify.breakpoint.mdAndUp ? undefined : 5"
tooltip="enter the team number or the IP address of the robot NetworkTables server"
:rules="[v => isValidTeamNumber(v) || 'Team Number must be non blank and a team number, IP address, or hostname']"
/>
<v-banner
v-show="(teamNumber < 1 || teamNumber > 10000) && !runNTServer"
v-show="!isValidTeamNumber(ntServerAddress) && !runNTServer"
rounded
color="red"
text-color="white"
>
Team number is unset or invalid. NetworkTables will not be able to connect.
Team Number unset or invalid. NetworkTables will not be able to connect.
</v-banner>
<CVradio
v-show="$store.state.settings.networkSettings.shouldManage"
@@ -36,6 +36,7 @@
name="IP"
/>
<CVinput
v-show="$store.state.settings.networkSettings.shouldManage"
v-model="hostname"
:input-cols="inputCols"
:rules="[v => isHostname(v) || 'Invalid hostname']"
@@ -165,7 +166,6 @@
</template>
<script>
import CVnumberinput from '../../components/common/cv-number-input'
import CVradio from '../../components/common/cv-radio'
import CVinput from '../../components/common/cv-input'
import CVSwitch from "@/components/common/cv-switch";
@@ -174,12 +174,13 @@ import CVSwitch from "@/components/common/cv-switch";
const ipv4Regex = /^((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])$/;
// https://stackoverflow.com/a/18494710
const hostnameRegex = /^([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*)+(\.([a-zA-Z0-9]+(-[a-zA-Z0-9]+)*))*$/;
const teamNumberRegex = /^[1-9][0-9]{0,3}$/;
const badTeamNumberRegex = /^[0-9]{5,}$/;
export default {
name: 'Networking',
components: {
CVSwitch,
CVnumberinput,
CVradio,
CVinput
},
@@ -205,12 +206,12 @@ export default {
settings() {
return this.$store.state.settings.networkSettings;
},
teamNumber: {
ntServerAddress: {
get() {
return this.settings.teamNumber
return this.settings.ntServerAddress
},
set(value) {
this.$store.commit('mutateNetworkSettings', {['teamNumber']: value || 0});
this.$store.commit('mutateNetworkSettings', {['ntServerAddress']: value || ""});
}
},
runNTServer: {
@@ -247,6 +248,16 @@ export default {
},
},
methods: {
isValidTeamNumber(v) {
if (teamNumberRegex.test(v)) return true;
if (ipv4Regex.test(v)) return true;
// need to check these before the hostname. "0" and "99999" are valid hostnames,
// but we don't want to allow then
if (v == '0') return false;
if (badTeamNumberRegex.test(v)) return false;
if (hostnameRegex.test(v)) return true;
return false;
},
isIPv4(v) {
return ipv4Regex.test(v);
},

View File

@@ -17,6 +17,7 @@
package org.photonvision.common.configuration;
import com.fasterxml.jackson.annotation.JsonAlias;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonGetter;
import com.fasterxml.jackson.annotation.JsonIgnore;
@@ -30,7 +31,7 @@ import org.photonvision.common.networking.NetworkMode;
import org.photonvision.common.util.file.JacksonUtils;
public class NetworkConfig {
public int teamNumber = 0;
public String ntServerAddress = "0";
public NetworkMode connectionType = NetworkMode.DHCP;
public String staticIp = "";
public String hostname = "photonvision";
@@ -54,7 +55,8 @@ public class NetworkConfig {
@JsonCreator
public NetworkConfig(
@JsonProperty("teamNumber") int teamNumber,
@JsonProperty("ntServerAddress") @JsonAlias({"ntServerAddress", "teamNumber"})
String ntServerAddress,
@JsonProperty("connectionType") NetworkMode connectionType,
@JsonProperty("staticIp") String staticIp,
@JsonProperty("hostname") String hostname,
@@ -64,7 +66,7 @@ public class NetworkConfig {
@JsonProperty("physicalInterface") String physicalInterface,
@JsonProperty("setStaticCommand") String setStaticCommand,
@JsonProperty("setDHCPcommand") String setDHCPcommand) {
this.teamNumber = teamNumber;
this.ntServerAddress = ntServerAddress;
this.connectionType = connectionType;
this.staticIp = staticIp;
this.hostname = hostname;

View File

@@ -66,7 +66,12 @@ public class NetworkTablesManager {
getInstance().broadcastConnectedStatus();
} else if (event.logMessage.message.contains("connected")
&& System.currentTimeMillis() - lastConnectMessageMillis > 125) {
logger.info("NT Connected!");
String connectionDescription = "(unknown)";
var connections = getInstance().ntInstance.getConnections();
if (connections.length > 0) {
connectionDescription = connections[0].remote_ip + ":" + connections[0].remote_port;
}
logger.info("NT Connected to " + connectionDescription + "!");
hasReportedConnectionFailure = false;
lastConnectMessageMillis = System.currentTimeMillis();
ScriptManager.queueEvent(ScriptEventType.kNTConnected);
@@ -107,16 +112,23 @@ public class NetworkTablesManager {
if (config.runNTServer) {
setServerMode();
} else {
setClientMode(config.teamNumber);
setClientMode(config.ntServerAddress);
}
broadcastVersion();
}
private void setClientMode(int teamNumber) {
if (!isRetryingConnection) logger.info("Starting NT Client");
private void setClientMode(String ntServerAddress) {
ntInstance.stopServer();
ntInstance.startClient4("photonvision");
ntInstance.setServerTeam(teamNumber);
try {
Integer t = Integer.parseInt(ntServerAddress);
if (!isRetryingConnection) logger.info("Starting NT Client, server team is " + t);
ntInstance.setServerTeam(t);
} catch (NumberFormatException e) {
if (!isRetryingConnection)
logger.info("Starting NT Client, server IP is \"" + ntServerAddress + "\"");
ntInstance.setServer(ntServerAddress);
}
ntInstance.startDSClient();
broadcastVersion();
}

View File

@@ -46,7 +46,7 @@ public class NetworkManager {
}
var config = ConfigManager.getInstance().getConfig().getNetworkConfig();
logger.info("Setting " + config.connectionType + " with team team " + config.teamNumber);
logger.info("Setting " + config.connectionType + " with team " + config.ntServerAddress);
if (Platform.isLinux()) {
if (!Platform.isRoot()) {
logger.error("Cannot manage hostname without root!");

View File

@@ -33,4 +33,20 @@ public class NetworkConfigTest {
Assertions.assertDoesNotThrow(() -> mapper.readValue(path.toFile(), NetworkConfig.class));
new File("netTest.json").delete();
}
@Test
public void testDeserializeTeamNumberOrNtServerAddress() {
{
ConfigManager configMgr =
new ConfigManager(Path.of("test-resources/network-old-team-number"));
configMgr.load();
Assertions.assertEquals("9999", configMgr.getConfig().getNetworkConfig().ntServerAddress);
}
{
ConfigManager configMgr =
new ConfigManager(Path.of("test-resources/network-new-team-number"));
configMgr.load();
Assertions.assertEquals("9999", configMgr.getConfig().getNetworkConfig().ntServerAddress);
}
}
}

View File

@@ -1 +1 @@
{"teamNumber":0,"connectionType":"DHCP","staticIp":"","hostname":"photonvision","runNTServer":false,"shouldManage":false}
{"ntServerAddress":"","connectionType":"DHCP","staticIp":"","hostname":"photonvision","runNTServer":false,"shouldManage":false}

View File

@@ -0,0 +1,3 @@
{
"ntServerAddress" : "9999"
}

View File

@@ -0,0 +1,3 @@
{
"teamNumber" : 9999
}