Skip to content

Commit ce54f11

Browse files
authored
Merge pull request #3 from soulteary/chore/tweak-webui
feat: init webui with config api
2 parents 0ad47a8 + 9b90cfa commit ce54f11

File tree

2 files changed

+91
-46
lines changed

2 files changed

+91
-46
lines changed

main.go

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package main
33
import (
44
"embed"
55
"encoding/json"
6+
"flag"
67
"fmt"
78
"log"
89
"net"
@@ -16,6 +17,7 @@ import (
1617
//go:embed public
1718
var EmbedFS embed.FS
1819

20+
// DeviceInfo holds device information from UDP broadcasts
1921
type DeviceInfo struct {
2022
Name string `json:"name"`
2123
IP string `json:"ip"`
@@ -30,30 +32,31 @@ var upgrader = websocket.Upgrader{
3032

3133
var clients = make(map[*websocket.Conn]bool)
3234

33-
func udpListener() {
35+
// udpListener listens for UDP broadcasts from devices
36+
func udpListener(port int) {
3437
addr := net.UDPAddr{
35-
Port: 9999,
38+
Port: port,
3639
IP: net.ParseIP("0.0.0.0"),
3740
}
3841
conn, err := net.ListenUDP("udp4", &addr)
3942
if err != nil {
40-
log.Fatalf("监听UDP失败: %v", err)
43+
log.Fatalf("❌ UDP listener failed to start on port %d: %v", port, err)
4144
}
4245
defer conn.Close()
4346

44-
buf := make([]byte, 1024)
45-
log.Println("开始监听设备广播...")
47+
buffer := make([]byte, 1024)
48+
log.Printf("📡 Listening for device broadcasts on UDP port %d", port)
4649

4750
for {
48-
n, _, err := conn.ReadFromUDP(buf)
51+
n, _, err := conn.ReadFromUDP(buffer)
4952
if err != nil {
50-
log.Printf("接收失败: %v", err)
53+
log.Printf("⚠️ Error receiving UDP broadcast: %v", err)
5154
continue
5255
}
5356

5457
var device DeviceInfo
55-
if err := json.Unmarshal(buf[:n], &device); err != nil {
56-
log.Printf("JSON解析失败: %v", err)
58+
if err := json.Unmarshal(buffer[:n], &device); err != nil {
59+
log.Printf("⚠️ Failed to parse device info: %v", err)
5760
continue
5861
}
5962

@@ -64,10 +67,11 @@ func udpListener() {
6467
}
6568
}
6669

70+
// wsHandler handles WebSocket upgrade requests and client management
6771
func wsHandler(c *gin.Context) {
6872
conn, err := upgrader.Upgrade(c.Writer, c.Request, nil)
6973
if err != nil {
70-
log.Println("升级失败:", err)
74+
log.Printf("⚠️ WebSocket upgrade failed: %v", err)
7175
return
7276
}
7377
defer conn.Close()
@@ -82,23 +86,47 @@ func wsHandler(c *gin.Context) {
8286
}
8387
}
8488

89+
// main initializes and starts the HTTP and UDP services
8590
func main() {
86-
go udpListener()
91+
var httpPort int
92+
var udpPort int
8793

94+
flag.IntVar(&httpPort, "http-port", 6200, "Port for HTTP server")
95+
flag.IntVar(&udpPort, "udp-port", 9999, "Port for UDP listener")
96+
flag.Parse()
97+
98+
log.Printf("🚀 Starting device discovery service")
99+
100+
go udpListener(udpPort)
101+
102+
gin.SetMode(gin.ReleaseMode)
88103
r := gin.Default()
89104

90105
r.GET("/", static.ServeEmbed("public", EmbedFS))
91-
92106
r.GET("/ws", wsHandler)
93107

94108
r.GET("/ping", func(c *gin.Context) {
95-
c.String(200, "test")
109+
c.String(http.StatusOK, "pong")
110+
})
111+
112+
r.GET("/config", func(c *gin.Context) {
113+
callback := c.Query("callback")
114+
host := c.Request.Host
115+
116+
if callback == "" {
117+
c.JSON(http.StatusBadRequest, gin.H{"error": "callback parameter required"})
118+
return
119+
}
120+
121+
data := gin.H{"host": host}
122+
c.JSONP(http.StatusOK, data)
96123
})
97124

98125
r.NoRoute(func(c *gin.Context) {
99-
fmt.Printf("%s doesn't exists, redirect on /\n", c.Request.URL.Path)
126+
log.Printf("🔄 Redirecting unknown route '%s' to '/'", c.Request.URL.Path)
100127
c.Redirect(http.StatusMovedPermanently, "/")
101128
})
102129

103-
r.Run(":18080")
130+
log.Printf("🌐 HTTP server running on port %d", httpPort)
131+
r.Run(fmt.Sprintf(":%d", httpPort))
104132
}

public/index.html

Lines changed: 48 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -27,43 +27,60 @@ <h1>灵心巧手设备列表</h1>
2727
</table>
2828

2929
<script>
30-
const socket = new WebSocket('ws://localhost:18080/ws');
31-
const devices = {};
30+
async function initWebSocket() {
31+
try {
32+
const response = await fetch('/config?callback=init');
33+
const configText = await response.text();
34+
const configJSON = JSON.parse(configText.match(/init\((.*)\)/)[1]);
35+
const wsHost = configJSON.host;
3236

33-
socket.onmessage = function(event) {
34-
const device = JSON.parse(event.data);
35-
const now = new Date().toLocaleString();
36-
const deviceKey = device.mac;
37+
const socket = new WebSocket(`ws://${wsHost}/ws`);
38+
const devices = {};
3739

38-
if (!devices[deviceKey]) {
39-
devices[deviceKey] = {
40-
...device,
41-
firstSeen: now,
42-
lastSeen: now
40+
socket.onmessage = function(event) {
41+
const device = JSON.parse(event.data);
42+
const now = new Date().toLocaleString();
43+
const deviceKey = device.mac;
44+
45+
if (!devices[deviceKey]) {
46+
devices[deviceKey] = {
47+
...device,
48+
firstSeen: now,
49+
lastSeen: now
50+
};
51+
52+
const row = document.createElement('tr');
53+
row.id = `device-${deviceKey}`;
54+
row.innerHTML = `
55+
<td>${device.name}</td>
56+
<td>${device.ip}</td>
57+
<td>${device.mac}</td>
58+
<td>${device.model}</td>
59+
<td>
60+
<a href="https://github.com/linker-bot/can-bridge/releases/tag/v1.2.1/${device.version}" target="_blank">
61+
${device.version}
62+
</a>
63+
</td>
64+
<td>${now}</td>
65+
<td>${now}</td>
66+
`;
67+
document.getElementById('devices').appendChild(row);
68+
} else {
69+
devices[deviceKey].lastSeen = now;
70+
const row = document.getElementById(`device-${deviceKey}`);
71+
row.cells[6].textContent = now;
72+
}
4373
};
4474

45-
const row = document.createElement('tr');
46-
row.id = `device-${deviceKey}`;
47-
row.innerHTML = `
48-
<td>${device.name}</td>
49-
<td>${device.ip}</td>
50-
<td>${device.mac}</td>
51-
<td>${device.model}</td>
52-
<td>${device.version}</td>
53-
<td>${now}</td>
54-
<td>${now}</td>
55-
`;
56-
document.getElementById('devices').appendChild(row);
57-
} else {
58-
devices[deviceKey].lastSeen = now;
59-
const row = document.getElementById(`device-${deviceKey}`);
60-
row.cells[6].textContent = now;
75+
socket.onerror = function(event) {
76+
console.error("WebSocket 错误:", event);
77+
};
78+
} catch (error) {
79+
console.error("配置初始化失败:", error);
6180
}
62-
};
81+
}
6382

64-
socket.onerror = function(event) {
65-
console.error("WebSocket 错误:", event);
66-
};
83+
initWebSocket();
6784
</script>
6885
</body>
6986
</html>

0 commit comments

Comments
 (0)