diff --git a/packages/lib/link/messages.js b/packages/lib/link/messages.js index 5a13f6dd..ea3d0aae 100644 --- a/packages/lib/link/messages.js +++ b/packages/lib/link/messages.js @@ -337,6 +337,7 @@ let slaveProperties = { "name": { type: "string" }, "id": { type: "integer" }, "connected": { type: "boolean" }, + "public_address": { type: ["null", "string"] }, }; messages.listSlaves = new Request({ @@ -372,6 +373,7 @@ let instanceProperties = { "name": { type: "string" }, "id": { type: "integer" }, "assigned_slave": { type: ["null", "integer"] }, + "game_port": { type: ["null", "integer"] }, "status": { enum: [ "unknown", "unassigned", "stopped", "starting", "running", "stopping", "creating_save", "exporting_data", "deleted", @@ -1145,11 +1147,13 @@ messages.instanceInitialized = new Event({ messages.instanceStatusChanged = new Event({ type: "instance_status_changed", links: ["instance-slave", "slave-master"], + eventRequired: ["instance_id", "status"], eventProperties: { "instance_id": { type: "integer" }, "status": { enum: [ "stopped", "starting", "running", "stopping", "creating_save", "exporting_data", ]}, + "game_port": { type: ["null", "integer"] }, }, }); diff --git a/packages/lib/schema.js b/packages/lib/schema.js index da43a843..17157876 100644 --- a/packages/lib/schema.js +++ b/packages/lib/schema.js @@ -178,6 +178,7 @@ const clientHandshake = ajv.compile({ "version": { type: "string" }, "name": { type: "string" }, "id": { type: "integer" }, + "public_address": { type: "string" }, "plugins": { type: "object", additionalProperties: { type: "string" }, diff --git a/packages/master/src/ControlConnection.js b/packages/master/src/ControlConnection.js index 69e1f5e9..7062ce7d 100644 --- a/packages/master/src/ControlConnection.js +++ b/packages/master/src/ControlConnection.js @@ -106,6 +106,7 @@ class ControlConnection extends BaseConnection { version: slave.version, id: slave.id, name: slave.name, + public_address: slave.public_address || null, connected: this._master.wsServer.slaveConnections.has(slave.id), }); } @@ -169,6 +170,7 @@ class ControlConnection extends BaseConnection { id, name: instance.config.get("instance.name"), assigned_slave: instance.config.get("instance.assigned_slave"), + game_port: instance.game_port || null, status: instance.status, }; } @@ -180,6 +182,7 @@ class ControlConnection extends BaseConnection { id: instance.config.get("instance.id"), name: instance.config.get("instance.name"), assigned_slave: instance.config.get("instance.assigned_slave"), + game_port: instance.game_port || null, status: instance.status, }); } @@ -199,6 +202,7 @@ class ControlConnection extends BaseConnection { id: instance.config.get("instance.id"), name: instance.config.get("instance.name"), assigned_slave: instance.config.get("instance.assigned_slave"), + game_port: instance.game_port || null, status: instance.status, }); } diff --git a/packages/master/src/Master.js b/packages/master/src/Master.js index c4f2ee6e..5c7de4f0 100644 --- a/packages/master/src/Master.js +++ b/packages/master/src/Master.js @@ -368,6 +368,7 @@ class Master { version: slave.version, id: slave.id, name: slave.name, + public_address: slave.public_address || null, connected: this.wsServer.slaveConnections.has(slave.id), }; diff --git a/packages/master/src/SlaveConnection.js b/packages/master/src/SlaveConnection.js index 6c2319dd..a8e1e456 100644 --- a/packages/master/src/SlaveConnection.js +++ b/packages/master/src/SlaveConnection.js @@ -28,6 +28,7 @@ class SlaveConnection extends BaseConnection { id: this._id, name: this._name, version: this._version, + public_address: registerData.public_address, plugins: registerData.plugins, }); @@ -87,6 +88,7 @@ class SlaveConnection extends BaseConnection { let prev = instance.status; instance.status = message.data.status; + instance.game_port = message.data.game_port; logger.verbose(`Instance ${instance.config.get("instance.name")} State: ${instance.status}`); this._master.instanceUpdated(instance); await libPlugin.invokeHook(this._master.plugins, "onInstanceStatusChanged", instance, prev); diff --git a/packages/slave/slave.js b/packages/slave/slave.js index ddf0cd32..d1bd56e8 100755 --- a/packages/slave/slave.js +++ b/packages/slave/slave.js @@ -260,7 +260,9 @@ class Instance extends libLink.Link { notifyStatus(status) { this._status = status; libLink.messages.instanceStatusChanged.send(this, { - instance_id: this.id, status, + instance_id: this.id, + status, + game_port: this.server?.gamePort || this.config.get("factorio.game_port") || null, }); } @@ -1004,6 +1006,7 @@ class SlaveConnector extends libLink.WebSocketClientConnector { version, id: this.slaveConfig.get("slave.id"), name: this.slaveConfig.get("slave.name"), + public_address: this.slaveConfig.get("slave.public_address"), plugins, }); } diff --git a/packages/web_ui/src/components/InstanceList.jsx b/packages/web_ui/src/components/InstanceList.jsx index 4a010ffa..7163608a 100644 --- a/packages/web_ui/src/components/InstanceList.jsx +++ b/packages/web_ui/src/components/InstanceList.jsx @@ -1,12 +1,13 @@ import React from "react"; import { useHistory } from "react-router-dom"; -import { Table } from "antd"; +import { message, Button, Table } from "antd"; +import CopyOutlined from "@ant-design/icons/CopyOutlined"; import { useSlaveList } from "../model/slave"; +import InstanceStatusTag from "./InstanceStatusTag"; const strcmp = new Intl.Collator(undefined, { numerice: "true", sensitivity: "base" }).compare; - export default function InstanceList(props) { let history = useHistory(); let [slaveList] = useSlaveList(); @@ -19,6 +20,17 @@ export default function InstanceList(props) { return String(slaveId); } + function instancePublicAddress(instance) { + let slave = slaveList.find(s => s.id === instance.assigned_slave); + if (slave && slave.public_address) { + if (instance.game_port) { + return `${slave.public_address}:${instance.game_port}`; + } + return slave.public_address; + } + return null; + } + let columns = [ { title: "Name", @@ -32,9 +44,30 @@ export default function InstanceList(props) { render: instance => slaveName(instance["assigned_slave"]), sorter: (a, b) => strcmp(slaveName(a["assigned_slave"]), slaveName(b["assigned_slave"])), }, + { + title: "Public address", + key: "public_address", + render: instance => { + let public_address = instancePublicAddress(instance); + return public_address ? <> + {public_address} + + } + /> ; } @@ -116,7 +129,7 @@ export default function InstanceViewPage(props) { buttonContent={assigned ? "Reassign" : "Assign"} />} - {instance["status"]} + { diff --git a/packages/web_ui/src/components/SlaveViewPage.jsx b/packages/web_ui/src/components/SlaveViewPage.jsx index c5a985bd..0b03fb6c 100644 --- a/packages/web_ui/src/components/SlaveViewPage.jsx +++ b/packages/web_ui/src/components/SlaveViewPage.jsx @@ -1,5 +1,5 @@ import React, { useContext, useState } from "react"; -import { Descriptions, PageHeader, Spin, Typography } from "antd"; +import { Descriptions, PageHeader, Spin, Tag, Typography } from "antd"; import { useParams } from "react-router-dom"; import InstanceList from "./InstanceList"; @@ -44,7 +44,11 @@ export default function SlaveViewPage(props) { {slave["name"]} - {slave["connected"] ? "yes" : "no"} + + + {slave["connected"] ? "Connected" : "Disconnected"} + + {slave["agent"]} {slave["version"]} diff --git a/packages/web_ui/src/components/SlavesPage.jsx b/packages/web_ui/src/components/SlavesPage.jsx index 9333752a..24cb17ed 100644 --- a/packages/web_ui/src/components/SlavesPage.jsx +++ b/packages/web_ui/src/components/SlavesPage.jsx @@ -1,6 +1,6 @@ import React, { useContext, useRef, useState } from "react"; import { useHistory } from "react-router-dom"; -import { Button, Form, Input, Modal, PageHeader, Table } from "antd"; +import { Button, Form, Input, Modal, PageHeader, Table, Tag } from "antd"; import { libLink } from "@clusterio/lib"; @@ -104,10 +104,19 @@ export default function SlavesPage() { dataIndex: "version", sorter: (a, b) => strcmp(a["version"], b["version"]), }, + { + title: "Public address", + dataIndex: "public_address", + sorter: (a, b) => strcmp(a["public_address"], b["public_address"]), + }, { title: "Connected", key: "connected", - render: slave => slave["connected"] && "Yes", + render: slave => + {slave["connected"] ? "Connected" : "Disconnected"} + , sorter: (a, b) => a["connected"] - b["connected"], }, ]}