📊 别再手动查流量了,让代码替你干活

作为一个经常折腾 VPS 的博主,最怕的不是服务器宕机,而是月底突然收到“流量耗尽”的邮件,尤其是像我这种手头好几台搬瓦工(BandwagonHost)机器的人。虽然后台也能看,但我这人记性差,总是忘记去查。为了治好这个懒癌,我最近写了一个简单的 Go 语言脚本,配置好后,它每天能像个贴身管家一样,准时向我的 Telegram 报告流量使用情况。

这个方案不仅轻量(编译出来就几 MB),而且不需要安装任何繁琐的依赖,非常适合放在低配置的机器或者 NAS 上长期跑。今天就把这个“偷懒”神器分享给大家,顺带讲讲核心代码的逻辑和部署技巧。


🛠️ 准备工作:我们需要哪些钥匙?

Telegram 流量通知效果图

脚本运行后发送到 Telegram 的流量日报截图,直观展示剩余流量和百分比。

在开始写代码之前,我们得先准备好几把“钥匙”,用来解锁搬瓦工的数据和 Telegram 的发送权限。整个过程大概需要 5 分钟。

1. 搬瓦工 API 信息

登录搬瓦工的控制面板(KiwiVM),在左侧菜单栏找到 API 选项。这里你需要记下两个关键参数:

  • VEID:这通常是一串数字,其实就在你浏览器地址栏或者后台首页就有显示。
  • API Key:点击生成或查看,记得复制保存,这个就像是你的高级通行证。

2. Telegram Bot 令牌

  • 在 Telegram 里搜索 @BotFather,发送 /newbot 按提示创建一个新机器人。
  • 创建成功后,BotFather 会发给你一串 Token,格式通常是 123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11,这个非常关键。

3. 你的 Telegram Chat ID

  • 机器人建好了,但机器人不知道要把消息发给谁。
  • 在浏览器访问 https://api.telegram.org/bot<你的Token>/getUpdates(把 bot 后面的 token 换成你刚获取的)。
  • 向你的新机器人发送任意一条消息(比如“你好”)。
  • 刷新浏览器页面,在返回的 JSON 数据里找到 "chat":{"id":123456789,那个 id 数字就是我们要的 Chat ID

💻 核心代码解析:它是怎么工作的?

这里我们直接上 Go 语言的源码。为了让代码更整洁,我把配置项抽离到了 config.json 文件中,这样以后改时间或者换账号都不用重新编译代码。

完整的 main.go

package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"time"
)

// Config 结构体用于映射 json 配置文件
type Config struct {
	VEID        string `json:"veid"`
	APIKey      string `json:"api_key"`
	TGBotToken  string `json:"tg_bot_token"`
	TGChatID    string `json:"tg_chat_id"`
	CheckHour   int    `json:"check_hour"`
	CheckMinute int    `json:"check_minute"`
}

// 全局配置变量
var AppConfig Config

// BwhResponse 搬瓦工 API 返回的部分结构体
type BwhResponse struct {
	PlanDataCounter   int64 `json:"data_counter"`   // 已用流量
	PlanDataNextReset int64 `json:"data_next_reset"` // 流量重置时间
	DataLimit         int64 `json:"plan_monthly_data"` // 总流量限制
}

// loadConfig 从当前目录加载配置文件
func loadConfig() error {
	file, err := os.Open("config.json")
	if err != nil {
		return fmt.Errorf("无法打开配置文件 config.json: %v", err)
	}
	defer file.Close()

bytes, err := io.ReadAll(file)
	if err != nil {
		return fmt.Errorf("无法读取配置文件: %v", err)
	}

if err := json.Unmarshal(bytes, &AppConfig); err != nil {
		return fmt.Errorf("解析配置文件 JSON 失败: %v", err)
	}
	return nil
}

func main() {
	// 启动时先加载配置
	if err := loadConfig(); err != nil {
		fmt.Println("配置加载失败,程序退出:", err)
		return
	}
	fmt.Println("搬瓦工流量监控服务已启动...")

// 启动时先执行一次检查
	checkAndNotify()

// 循环定时任务
	for {
		now := time.Now()
		// 计算下一次执行的时间(从配置中读取小时和分钟)
		next := time.Date(now.Year(), now.Month(), now.Day(), AppConfig.CheckHour, AppConfig.CheckMinute, 0, 0, now.Location())
		if next.Before(now) {
			next = next.Add(24 * time.Hour)
		}
		fmt.Printf("下一次通知时间: %s\n", next.Format("2006-01-02 15:04:05"))

time.Sleep(next.Sub(now))
		checkAndNotify()
	}
}

// 核心逻辑:获取流量并发送通知
func checkAndNotify() {
	fmt.Println("开始获取流量信息...")

// 1. 调用搬瓦工 API(动态使用 AppConfig 中的变量)
	apiURL := fmt.Sprintf("https://api.64clouds.com/v1/getLiveServiceInfo?veid=%s&api_key=%s", AppConfig.VEID, AppConfig.APIKey)
	resp, err := http.Get(apiURL)
	if err != nil {
		fmt.Println("调用搬瓦工 API 失败:", err)
		return
	}
	defer resp.Body.Close()

body, _ := io.ReadAll(resp.Body)
	var bwhData BwhResponse
	if err := json.Unmarshal(body, &bwhData); err != nil {
		fmt.Println("解析 JSON 失败:", err)
		return
	}

// 2. 计算流量数据 (Bytes 转 GB)
	totalGB := float64(bwhData.DataLimit) / 1024 / 1024 / 1024
	usedGB := float64(bwhData.PlanDataCounter) / 1024 / 1024 / 1024
	remainingGB := totalGB - usedGB

// 计算使用百分比
	var usagePercent float64
	if totalGB > 0 {
		usagePercent = (usedGB / totalGB) * 100
	}

resetTime := time.Unix(bwhData.PlanDataNextReset, 0).Format("2006-01-02")

// 3. 组装消息文本
	message := fmt.Sprintf(
		"📊 搬瓦工 VPS 流量日报\n\n"+
			"🔹 总流量: %.2f GB\n"+
			"🔸 已使用: %.2f GB (%.1f%%)\n"+
			"✅ 剩余流量: %.2f GB\n"+
			"📅 重置日期: %s",
		totalGB, usedGB, usagePercent, remainingGB, resetTime,
	)

// 4. 发送 Telegram 通知
	err = sendTGMessage(message)
	if err != nil {
		fmt.Println("发送 TG 通知失败:", err)
	} else {
		fmt.Println("通知发送成功!时间:", time.Now().Format("15:04:05"))
	}
}

// 发送 Telegram 消息的函数
func sendTGMessage(text string) error {
	tgURL := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", AppConfig.TGBotToken)
	formData := url.Values{
		"chat_id":    {AppConfig.TGChatID},
		"text":       {text},
		"parse_mode": {"Markdown"},
	}

resp, err := http.PostForm(tgURL, formData)
	if err != nil {
		return err
	}
	defer resp.Body.Close()

if resp.StatusCode != http.StatusOK {
		body, _ := io.ReadAll(resp.Body)
		return fmt.Errorf("TG API 返回错误码: %d, 原因: %s", resp.StatusCode, string(body))
	}
	return nil
}

代码逻辑简要分析

这段代码的逻辑其实非常清晰,主要分为三个部分:

  1. 配置加载 (loadConfig):程序启动的第一件事,就是去读同目录下的 config.json。如果文件不存在或格式写错了,程序会直接报错退出,避免后面运行出 bug。
  2. 定时循环 (main):这里没有使用复杂的 cron 库,而是利用 Go 原生的 time 包。程序启动时会先立刻跑一次检查(验证配置是否正确),然后进入 for 无限循环。每次循环都会计算下一次触发的时间点(比如配置的是 21:00),然后 time.Sleep 休眠到那个时间点再执行。这样做的好处是资源占用极低,不像每秒轮询那样浪费 CPU。
  3. 数据获取与推送 (checkAndNotify & sendTGMessage):这是心脏部分。它先发 HTTP 请求去搬瓦工 API 拿数据,把 Bytes 转换成 GB,算好百分比,最后拼成一段带 Emoji 的文本,POST 到 Telegram 的接口。

⚙️ 部署实战:五步上线服务

代码有了,接下来就是怎么让它跑起来。我们把上面的代码保存为 main.go,然后在同级目录下创建一个 config.json 文件。

第一步:编写配置文件

新建一个 config.json,把你刚才准备好的信息填进去:

{
  "veid": "你的VEID",
  "api_key": "你的API Key",
  "tg_bot_token": "你的TG Bot Token",
  "tg_chat_id": "你的TG Chat ID",
  "check_hour": 21,
  "check_minute": 0
}

*注意:check_hour 是 24 小时制,如果你想早上 9 点看,就改成 9。`

第二步:本地编译测试

确保你安装了 Go 环境(没安装的去 Go 官网下个安装包)。在终端输入:

go build -o bfw_monitor main.go

这会生成一个名为 bfw_monitor 的可执行文件(Windows 下是 .exe)。直接运行它试试:

./bfw_monitor # Linux/Mac
# 或者
bfw_monitor.exe # Windows

如果一切顺利,你的 Telegram 应该马上就能收到一条日报消息,终端里也会显示“下一次通知时间”。

第三步:后台长期运行(进阶篇)

总不能一直开个终端窗口挂着吧?如果你的机器是 Linux,推荐使用 systemd 来管理这个服务,这样开机自启、崩溃重启都能自动搞定。

创建一个服务文件:

sudo nano /etc/systemd/system/bwg-monitor.service

填入以下内容(注意修改路径):

[Unit]
Description=BandwagonHost Traffic Monitor
After=network.target

[Service]
Type=simple
User=root # 建议使用普通用户,但要注意文件权限
WorkingDirectory=/root/bwg_monitor # 切换到你程序所在的目录
ExecStart=/root/bwg_monitor/bfw_monitor # 程序的绝对路径
Restart=on-failure

[Install]
WantedBy=multi-user.target

保存后重载并启动:

sudo systemctl daemon-reload
sudo systemctl enable bwg-monitor.service
sudo systemctl start bwg-monitor.service

查看日志状态:

sudo systemctl status bwg-monitor.service

第四步(懒人版):直接下载成品

如果你觉得配置 Go 环境或者编译太麻烦,我也已经编译好了常用的版本(Linux 64位),你可以直接下载使用。不过,为了安全起见,建议你在虚拟机里先跑一跑,或者有能力的还是推荐自己源码编译。

(下载链接在文末)


🤔 常见问题与解决方案

Q: 提示“调用搬瓦工 API 失败”?

A: 检查一下你的 VEID 和 API Key 是否复制正确,有没有多余的空格。另外,搬瓦工 API 偶尔会抽风,如果是一次性报错,程序会等到下次时间点重试;如果一直报错,建议手动去浏览器访问一下 API 链接看看返回什么。

Q: Telegram 收不到消息?

A: 最常见的原因是 Chat ID 填错了。请再次确认 getUpdates 返回的 ID 是否正确。此外,确保你已经在 Telegram 里向机器人发送过至少一条消息,否则有些情况下机器人无法主动推送。

Q: 我想监控多个 VPS 怎么办?

A: 目前的代码是单进程的。如果你有多台机器,最简单的方法是复制几份代码和配置文件,放在不同的文件夹里,给每个可执行文件改个名,然后用 systemd 启动多个服务即可。稍微进阶一点的做法是修改 config.json 支持数组,然后遍历查询,但那样改动代码稍微多一点。


💡 总结

这个小小的脚本虽然代码量不大,但实用性非常强。它完美解决了“忘记查流量”这个痛点,而且 Go 语言编译后的二进制文件分发极其方便,不需要担心依赖库缺失的问题。

自动化运维往往就是从解决这些琐碎的小需求开始的。如果你是 VPS 重度用户,希望这个工具能帮你省点心。如果你有更好的想法,比如加上“流量使用率超过 80% 预警”之类的功能,欢迎在代码基础上魔改!

标签: none

AI Skills Smart Station on Nick Launches

评论已关闭