feat: 天地图瓦片缓存(tile-cache)、拓扑标注助手与文档更新
- tile-cache: 瓦片缓存服务(vec/cva)、启动探针、详细日志、上游超时可配置(UPSTREAM_TIMEOUT_MS) - central: docker-compose 集成 tile-cache,env.example 增加 TILE_CACHE_* / TIANDITU_TK - topology-editor: 天地图/缓存加载、GPS 安全来源错误提示、TIANDITU 文档(403/白名单、localhost 测试说明) - doc: README 部署步骤与 GPS 安全来源说明,TIANDITU_CONFIG 完善 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -31,13 +31,14 @@ ONVIF_TEMP=$(mktemp)
|
||||
PING_TEMP=$(mktemp)
|
||||
|
||||
# 处理CSV文件(跳过注释行和标题行)
|
||||
tail -n +2 "$CSV_FILE" | grep -v '^#' | while IFS=',' read -r type ip device group network device_type model location username password onvif_port lat lon; do
|
||||
# 列顺序: type,ip,name,role,parent,uplink_type,network,device_type,model,location,username,password,onvif_port,lat,lon
|
||||
tail -n +2 "$CSV_FILE" | grep -v '^#' | while IFS=',' read -r type ip name role parent uplink_type network device_type model location username password onvif_port lat lon; do
|
||||
# 去除空格
|
||||
type=$(echo "$type" | xargs)
|
||||
ip=$(echo "$ip" | xargs)
|
||||
|
||||
# 跳过空行
|
||||
if [ -z "$type" ] || [ -z "$ip" ]; then
|
||||
if [ -z "$type" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
@@ -84,22 +85,34 @@ tail -n +2 "$CSV_FILE" | grep -v '^#' | while IFS=',' read -r type ip device gro
|
||||
|
||||
elif [ "$type" = "ping" ]; then
|
||||
# 处理 Ping 目标
|
||||
device=$(echo "$device" | xargs)
|
||||
group=$(echo "$group" | xargs)
|
||||
device=$(echo "$name" | xargs) # name 作为 device 标签
|
||||
role=$(echo "$role" | xargs)
|
||||
parent=$(echo "$parent" | xargs)
|
||||
uplink_type=$(echo "$uplink_type" | xargs)
|
||||
network=$(echo "$network" | xargs)
|
||||
|
||||
labels="{
|
||||
\"device\": \"$device\""
|
||||
|
||||
if [ -n "$group" ]; then
|
||||
if [ -n "$uplink_type" ]; then
|
||||
labels="$labels,
|
||||
\"group\": \"$group\""
|
||||
\"uplink_type\": \"$uplink_type\""
|
||||
fi
|
||||
|
||||
if [ -n "$network" ]; then
|
||||
labels="$labels,
|
||||
\"network\": \"$network\""
|
||||
fi
|
||||
|
||||
if [ -n "$role" ]; then
|
||||
labels="$labels,
|
||||
\"role\": \"$role\""
|
||||
fi
|
||||
|
||||
if [ -n "$parent" ]; then
|
||||
labels="$labels,
|
||||
\"parent\": \"$parent\""
|
||||
fi
|
||||
|
||||
labels="$labels
|
||||
}"
|
||||
|
||||
100
edge-agent/config/csv-to-topology-geojson.sh
Executable file
100
edge-agent/config/csv-to-topology-geojson.sh
Executable file
@@ -0,0 +1,100 @@
|
||||
#!/bin/bash
|
||||
|
||||
# 从 targets.csv 生成拓扑 GeoJSON(用于 Grafana Geomap)
|
||||
# - 支持 type: ping / onvif / topology
|
||||
# - 使用列: name, role, parent, lat, lon
|
||||
# - 输出: topology.geojson(FeatureCollection,含 Point 和 LineString)
|
||||
|
||||
set -e
|
||||
|
||||
CSV_FILE=${1:-"targets.csv"}
|
||||
OUTPUT_FILE=${2:-"topology.geojson"}
|
||||
|
||||
if ! command -v jq &> /dev/null; then
|
||||
echo "❌ jq 未安装,请先安装 jq"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [ ! -f "$CSV_FILE" ]; then
|
||||
echo "❌ CSV 文件 $CSV_FILE 不存在"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TMP_JSON=$(mktemp)
|
||||
|
||||
echo "🔄 正在从 $CSV_FILE 生成拓扑 GeoJSON 到 $OUTPUT_FILE ..."
|
||||
|
||||
# 列顺序: type,ip,name,role,parent,uplink_type,network,device_type,model,location,username,password,onvif_port,lat,lon
|
||||
tail -n +2 "$CSV_FILE" | grep -v '^#' | while IFS=',' read -r type ip name role parent uplink_type network device_type model location username password onvif_port lat lon; do
|
||||
type=$(echo "$type" | xargs)
|
||||
name=$(echo "$name" | xargs)
|
||||
|
||||
# 空行跳过
|
||||
if [ -z "$type" ] || [ -z "$name" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
cat >> "$TMP_JSON" <<EOF
|
||||
{"type":"$type","ip":"$ip","name":"$name","role":"$role","parent":"$parent","uplink_type":"$uplink_type","network":"$network","device_type":"$device_type","model":"$model","location":"$location","lat":"$lat","lon":"$lon"}
|
||||
EOF
|
||||
done
|
||||
|
||||
# 用 jq 生成 FeatureCollection
|
||||
jq -s '
|
||||
def toPoint:
|
||||
select(.lat != "" and .lon != "") |
|
||||
{
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "Point",
|
||||
coordinates: [ (.lon|tonumber), (.lat|tonumber) ]
|
||||
},
|
||||
properties: {
|
||||
kind: .type,
|
||||
name: .name,
|
||||
role: .role,
|
||||
parent: .parent,
|
||||
ip: .ip,
|
||||
uplink_type: .uplink_type,
|
||||
network: .network,
|
||||
device_type: .device_type,
|
||||
model: .model,
|
||||
location: .location
|
||||
}
|
||||
};
|
||||
|
||||
def toLine(all):
|
||||
select(.parent != "" and .lat != "" and .lon != "") as $child
|
||||
| (all[] | select(.name == $child.parent and .lat != "" and .lon != "")) as $parent
|
||||
| {
|
||||
type: "Feature",
|
||||
geometry: {
|
||||
type: "LineString",
|
||||
coordinates: [
|
||||
[ ($parent.lon|tonumber), ($parent.lat|tonumber) ],
|
||||
[ ($child.lon|tonumber), ($child.lat|tonumber) ]
|
||||
]
|
||||
},
|
||||
properties: {
|
||||
type: "link",
|
||||
from: $parent.name,
|
||||
to: $child.name,
|
||||
from_role: $parent.role,
|
||||
to_role: $child.role
|
||||
}
|
||||
};
|
||||
|
||||
. as $all
|
||||
| {
|
||||
type: "FeatureCollection",
|
||||
features: (
|
||||
[ $all[] | toPoint ] +
|
||||
[ $all[] | toLine($all) ]
|
||||
)
|
||||
}
|
||||
' "$TMP_JSON" > "$OUTPUT_FILE"
|
||||
|
||||
rm -f "$TMP_JSON"
|
||||
|
||||
echo "✅ 已生成 $OUTPUT_FILE"
|
||||
|
||||
@@ -1,14 +1,25 @@
|
||||
# 统一监控目标配置文件
|
||||
# 格式: type,ip,device,group,network,device_type,model,location,username,password,onvif_port,lat,lon
|
||||
# type: onvif 或 ping
|
||||
# 对于 onvif 类型,需要填写: ip,device_type,model,location,username,password,onvif_port,lat,lon
|
||||
# - lat / lon 为摄像头地理位置坐标(十进制度数),用于在 Geomap 上打点
|
||||
# 对于 ping 类型,需要填写: ip,device,group,network(lat / lon 可选)
|
||||
type,ip,device,group,network,device_type,model,location,username,password,onvif_port,lat,lon
|
||||
ping,192.168.2.1,main_router,network,internal,,,,,,,,
|
||||
ping,8.8.8.8,google_dns,external,external,,,,,,,,
|
||||
# 统一监控 + 拓扑目标配置文件
|
||||
# 格式: type,ip,name,role,parent,uplink_type,network,device_type,model,location,username,password,onvif_port,lat,lon
|
||||
# type: ping / onvif / topology
|
||||
# - ping: 有 IP,可做网络探测
|
||||
# - onvif: 有 IP,走 ONVIF Exporter
|
||||
# - topology: 纯拓扑节点(无 IP 也可),只用于在 Geomap 上画点和连线
|
||||
# role: core_switch / access_switch / camera / wireless_bridge / media_converter ...
|
||||
# parent: 上联设备的 name,用于生成拓扑连线
|
||||
# uplink_type: 与上联 parent 之间的链路类型(fiber / copper / wireless 等)
|
||||
# lat / lon: 地理坐标(十进制度数),用于在 Geomap 上打点
|
||||
type,ip,name,role,parent,uplink_type,network,device_type,model,location,username,password,onvif_port,lat,lon
|
||||
|
||||
# 核心交换机(有 IP,可 ping,暂无上联,uplink_type 留空)
|
||||
ping,192.168.2.1,core_sw_1,core_switch,, ,internal,,,,,,,22.5431,113.9876
|
||||
|
||||
# 互联网 DNS(示例,链路类型为 fiber / copper / wireless 之一)
|
||||
ping,8.8.8.8,google_dns,dns,core_sw_1,fiber,external,,,,,,,22.5500,113.9900
|
||||
|
||||
# 哑设备示例:傻瓜交换机、光收发器(无 IP,只画拓扑)
|
||||
# topology,,dumb_sw_1,access_switch,core_sw_1,copper,internal,switch,Unmanaged_8P,building_A_3F,,,,22.5438,113.9882
|
||||
# topology,,optic_1,media_converter,dumb_sw_1,fiber,internal,media_conv,MC-1000,basement_1F,,,,22.5436,113.9880
|
||||
|
||||
# ONVIF 设备示例(取消注释并填写实际信息)
|
||||
# onvif,192.168.1.100,,,front_door,camera,HIKVISION_DS-2CD2342WD-I,front_door,admin,password1,80,22.1234,113.5678
|
||||
# onvif,192.168.1.101,,,back_yard,camera,DAHUA_IPC-HFW1230S,back_yard,admin,password2,80,22.2234,113.6678
|
||||
# onvif,192.168.1.102,,,living_room,camera,UNIVIEW_IPC3120SR,living_room,admin,password3,8080,22.3234,113.7678
|
||||
# onvif,192.168.1.50,,,server_rack,nvr,HIKVISION_DS-7608NI-I2,server_rack,admin,password4,80,22.4234,113.8678
|
||||
# onvif,192.168.1.100,camera_front,camera,dumb_sw_1,copper,onvif_cameras,internal,camera,HIKVISION_DS-2CD2342WD-I,front_door,admin,password1,80,22.1234,113.5678
|
||||
# onvif,192.168.1.101,camera_back,camera,bridge_1,wireless,onvif_cameras,internal,camera,DAHUA_IPC-HFW1230S,back_yard,admin,password2,80,22.2234,113.6678
|
||||
|
||||
|
Reference in New Issue
Block a user