分类 工作&技术 下的文章

这几天无聊写了一个小小的项目,现在完成度有80%了。
整个项目我基本没有手搓代码,全部都是cursor完成的。我要做的事情就是把项目进行细分以及审核和测试代码(当然,单元测试也是让cursor写甚至直接运行),以及一次次叫cursor修改。
代码写得不算漂亮,但胜在它能运行。虽然bug挺多的,不过慢慢修还是总能修好,即便有时把人气得够呛。
要让AI完全构建一个工程现阶段还是不现实的。只有小白才敢说拿一个项目全部AI自行生成,那些单页应用就别扯了,那不能算项目。不过等AI再继续进化下去的话,看这样也许真就可以小白也能了。
还好我打算退休颐养天年了,以后的程序员们看来是挺难的了。

root@vps:~/test# find . -name "*.go" -type f -exec cat {} + | wc -l
6544

家里路由器,以前用的网件,它自带了noip的支持。 不过呢,可能是太老了,速度上不去,我家800M的宽带只能跑到4-500M。换成小米并刷openwrt的话,可以跑到700多M,算跑满了。不过问题就是ddns不太支持了,虽然有一堆,但我都没号也不想花钱呀,自己搓一个吧。用起来其实挺简单的,在openwrt里面的ddns那里服务商选自定义然后填好参数就可以了。
域名的话是用自己的托管在cloudflare的域名。用户名密码固定写死在代码中了,不是商业的东西,简单防刷就好。
自定义URL格式是标准的,就是 https://ddns服务器域名/updatedns?hostname=[DOMAIN]&myip=[IP]&username=[USERNAME]&password=[PASSWORD]

package main

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"log"
	"net/http"

	"github.com/gin-gonic/gin"
)

var (
	apiKey     = "cloudflare API KEY"
	email      = "cloudflare登录email"
	zoneID     = "域名的zone id"
	username   = "客户端认证的用户名"
	password   = "密码"
	ListenPort = "监听端口"
	ListenAddr = "监听ip"
)

type dnsRecord struct {
	ID      string `json:"id"`
	Type    string `json:"type"`
	Name    string `json:"name"`
	Content string `json:"content"`
}

func updateDNS(ip, hostname string) error {
	client := &http.Client{}

	reqURL := fmt.Sprintf("https://api.cloudflare.com/client/v4/zones/%s/dns_records?type=A&name=%s", zoneID, hostname)

	req, _ := http.NewRequest("GET", reqURL, nil)
	req.Header.Add("X-Auth-Email", email)
	req.Header.Add("X-Auth-Key", apiKey)
	req.Header.Add("Content-Type", "application/json")

	resp, err := client.Do(req)
	if err != nil {
		return fmt.Errorf("request failed: %w", err)
	}
	defer resp.Body.Close()

	body, _ := io.ReadAll(resp.Body)

	var result struct {
		Success bool        `json:"success"`
		Result  []dnsRecord `json:"result"`
		Errors  []struct {
			Code    int    `json:"code"`
			Message string `json:"message"`
		} `json:"errors"`
	}

	if err := json.Unmarshal(body, &result); err != nil {
		return fmt.Errorf("json unmarshal failed: %w", err)
	}

	if !result.Success {
		return fmt.Errorf("API returned success=false, errors: %+v", result.Errors)
	}

	if len(result.Result) == 0 {
		return fmt.Errorf("record not found for %s - the DNS record may not exist yet. Please create it first in Cloudflare Dashboard", hostname)
	}

	rec := result.Result[0]

	if rec.Content == ip {
		log.Printf("No change: %s already -> %s", hostname, ip)
		return nil
	}

	data := map[string]interface{}{
		"type":    "A",
		"name":    hostname,
		"content": ip,
		"ttl":     120,
	}
	j, _ := json.Marshal(data)

	putURL := fmt.Sprintf("https://api.cloudflare.com/client/v4/zones/%s/dns_records/%s", zoneID, rec.ID)

	req2, _ := http.NewRequest("PUT", putURL, bytes.NewBuffer(j))
	req2.Header.Add("X-Auth-Email", email)
	req2.Header.Add("X-Auth-Key", apiKey)
	req2.Header.Add("Content-Type", "application/json")

	resp2, err := client.Do(req2)
	if err != nil {
		return fmt.Errorf("update request failed: %w", err)
	}
	defer resp2.Body.Close()

	io.ReadAll(resp2.Body)
	log.Printf("DNS updated: %s -> %s", hostname, ip)

	return nil
}

func main() {
	r := gin.Default()

	r.GET("/updatedns", func(c *gin.Context) {
		hostname := c.Query("hostname")
		myip := c.Query("myip")
		reqUsername := c.Query("username")
		reqPassword := c.Query("password")

		if hostname == "" || myip == "" || reqUsername == "" || reqPassword == "" {
			c.String(http.StatusBadRequest, "missing required parameters: hostname, myip, username, password")
			return
		}

		if reqUsername != username || reqPassword != password {
			c.String(http.StatusUnauthorized, "invalid username or password")
			return
		}

		log.Printf("Update request: %s -> %s", hostname, myip)

		if err := updateDNS(myip, hostname); err != nil {
			log.Printf("Error: %v", err)
			c.String(http.StatusInternalServerError, err.Error())
			return
		}

		c.String(http.StatusOK, "good %s", myip)
	})

	addr := fmt.Sprintf("%s:%s", ListenAddr, ListenPort)
	log.Printf("DDNS server running on %s", addr)
	r.Run(addr)
}

OVH VPS-x系列对别的商家绝对是降维打击。然后新加坡这机器总是卖断货,放货一天然后断货一周甚至更久。
上周本来入了一个想自用,结果被人高价给收去了。我是贪财之人,只要有溢价,我就忍不住把机器卖了。。。
好吧,现在就只能继续蹲了。让AI写了个小工具来监控一下。我唯一做的有价值的事,只是告诉AI需要监视的API链接。
代码是GO的,运行方法就是 ./checkstock sgp 这样了。只是提供思路了,如果需要,你可以让AI把它改成任何语言以及形式等。

package main

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

const (
        telegramToken  = "Telegram机器人token"
        telegramChatID = "Telegram发送通知的会话ID"
        apiURL         = "https://api.ovh.com/1.0/vps/order/rule/datacenter?ovhSubsidiary=IE&os=Ubuntu+25.04&planCode=vps-2025-model1"
)

type Data struct {
        Datacenters []struct {
                Datacenter    string `json:"datacenter"`
                Status        string `json:"status"`
                LinuxStatus   string `json:"linuxStatus"`
                WindowsStatus string `json:"windowsStatus"`
        } `json:"datacenters"`
}

func isAvailable(s string) bool {
        return s == "available" || s == "out-of-stock-preorder-allowed"
}

func sendTelegram(msg string) {
        endpoint := fmt.Sprintf("https://api.telegram.org/bot%s/sendMessage", telegramToken)
        data := url.Values{}
        data.Set("chat_id", telegramChatID)
        data.Set("text", msg)
        http.PostForm(endpoint, data)
}

func check(target string) (bool, error) {
        resp, err := http.Get(apiURL)
        if err != nil {
                return false, err
        }
        defer resp.Body.Close()

        body, err := io.ReadAll(resp.Body)
        if err != nil {
                return false, err
        }

        var data Data
        if err := json.Unmarshal(body, &data); err != nil {
                return false, err
        }

        fmt.Printf("[%s] 当前各数据中心状态:\n", time.Now().Format("2006-01-02 15:04:05"))
        for _, d := range data.Datacenters {
                fmt.Printf("  %s: status=%s, linux=%s, windows=%s\n",
                        d.Datacenter, d.Status, d.LinuxStatus, d.WindowsStatus)
        }

        for _, d := range data.Datacenters {
                if strings.EqualFold(d.Datacenter, target) {
                        return isAvailable(d.Status) && isAvailable(d.LinuxStatus), nil
                }
        }
        fmt.Printf("%s 不存在\n", target)
        return false, nil
}

func main() {
        if len(os.Args) < 2 {
                fmt.Println("Usage: checkstock <datacenter_code>")
                os.Exit(1)
        }
        target := strings.ToUpper(strings.TrimSpace(os.Args[1]))

        startMsg := fmt.Sprintf("监控启动:正在监控 %s 库存状态", target)
        fmt.Println(startMsg)
        sendTelegram(startMsg)

        for {
                ok, err := check(target)
                if err != nil {
                        fmt.Println("Error:", err)
                } else if ok {
                        msg := fmt.Sprintf("🚀 %s 有货(含预购)!", target)
                        fmt.Println(msg)
                        sendTelegram(msg)
                        os.Exit(0)
                }
                fmt.Printf("[%s] 无货,等待60秒后重试...\n----\n", time.Now().Format("2006-01-02 15:04:05"))
                time.Sleep(60 * time.Second)
        }
}

运行示例:

[2025-10-09 01:54:20] 当前各数据中心状态:
  GRA: status=available, linux=available, windows=available
  DE: status=available, linux=available, windows=available
  BHS: status=available, linux=available, windows=available
  SBG: status=out-of-stock-preorder-allowed, linux=out-of-stock-preorder-allowed, windows=out-of-stock-preorder-allowed
  WAW: status=out-of-stock-preorder-allowed, linux=out-of-stock-preorder-allowed, windows=available
  SGP: status=out-of-stock, linux=out-of-stock, windows=out-of-stock
  UK: status=out-of-stock, linux=out-of-stock, windows=out-of-stock
[2025-10-09 01:54:20] 无货,等待60秒后重试...

国庆无聊,做了一个小测试。
测试符合预期也是我想要证明的结果,同样也很扎心。结论就是:我所有的需求不过就是一台1C1G的服务器而已。我以后不需再买新的服务器了。。。
测试内容就是把我的所有的东西全扔在了netcup的1o机(1C1G30G)上,包含docker,mysql,redis,nginx,npm,hy2,哪吒探针,还有我自己写的东西等。
服务器1G内存是显然不够的,不过swap跑起来,系统感觉不到太明显的卡顿。现在这个博客就在上面,挺流畅的。

mem.jpg

我有个小工具,是来监视ovh的ks产品线变化的。没错,你猜对了,我就是想检测le系列的上线消息,一旦有了,马上准备api上去抢跑。
这代码正常运行几个月了,今天突然发现不能正常获得价格了,所有价格都报告0。ovh的api和数据结构我也忘得差不多了,不想去研究代码和json结构,直接扔给了cursor。
我就告诉cursor,KS-B的价格应该是9.9,结果变0了! 没有其它的prompt了。
cursor去帮我拉回来了api数据瞅了瞅,然后就找到了问题并完美修正了错误。完全自动的过程。
我也恍然大悟了,我以前的代码是提取到的安装费,安装费基本就是一个月月费,所以,我代码运行“正常”。然而,ovh近期取消了安装费,现在全线安装费是0,所以,我代码获得的“价格”也就全0了。

cursor1.png
cursor2.png