feat: 更新时间同步逻辑,使用K780时间API替代中国时间API
- 修改时间同步服务,使用K780时间API获取北京时间,增强了API请求的错误处理和日志记录。 - 更新响应结构,解析新的时间戳格式,确保时间同步的准确性和稳定性。
This commit is contained in:
@@ -21,10 +21,17 @@ type TimeSync struct {
|
|||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
}
|
}
|
||||||
|
|
||||||
// ChinaTimeAPIResponse 中国时间API响应结构(type=1返回时间戳)
|
// K780TimeAPIResponse K780时间API响应结构
|
||||||
type ChinaTimeAPIResponse struct {
|
type K780TimeAPIResponse struct {
|
||||||
Code int `json:"code"`
|
Success string `json:"success"`
|
||||||
Msg string `json:"msg"` // 时间戳字符串(秒)
|
Msgid string `json:"msgid"`
|
||||||
|
Msg string `json:"msg"`
|
||||||
|
Result struct {
|
||||||
|
Timestamp string `json:"timestamp"` // 时间戳(秒)
|
||||||
|
TimestampMs string `json:"timestamp_ms"` // 时间戳(毫秒)
|
||||||
|
Datetime1 string `json:"datetime_1"` // 日期时间格式1
|
||||||
|
Datetime2 string `json:"datetime_2"` // 日期时间格式2
|
||||||
|
} `json:"result"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewTimeSync 创建时间同步器
|
// NewTimeSync 创建时间同步器
|
||||||
@@ -44,66 +51,97 @@ func NewTimeSync(logger *zap.Logger) (*TimeSync, error) {
|
|||||||
|
|
||||||
// syncTime 同步时间(从HTTP API获取北京时间)
|
// syncTime 同步时间(从HTTP API获取北京时间)
|
||||||
func (ts *TimeSync) syncTime() error {
|
func (ts *TimeSync) syncTime() error {
|
||||||
// 使用中国时间API(必须使用,大陆无法访问海外API)
|
// 使用K780时间API
|
||||||
chinaAPIs := []string{
|
apiURL := "https://sapi.k780.com/?app=life.time&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json"
|
||||||
"http://101.35.2.25/api/time/getapi.php",
|
|
||||||
"http://124.222.204.22/api/time/getapi.php",
|
|
||||||
"http://81.68.149.132/api/time/getapi.php",
|
|
||||||
"https://cn.apihz.cn/api/time/getapi.php",
|
|
||||||
}
|
|
||||||
|
|
||||||
var lastErr error
|
|
||||||
|
|
||||||
// 尝试所有中国时间API
|
|
||||||
for _, baseURL := range chinaAPIs {
|
|
||||||
apiURL := baseURL + "?id=88888888&key=88888888&type=1"
|
|
||||||
|
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
Timeout: 5 * time.Second,
|
Timeout: 5 * time.Second,
|
||||||
}
|
}
|
||||||
|
|
||||||
resp, err := client.Get(apiURL)
|
// 创建请求,添加浏览器请求头
|
||||||
|
req, err := http.NewRequest("GET", apiURL, nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lastErr = err
|
ts.mu.Lock()
|
||||||
ts.logger.Debug("API请求失败", zap.String("api", baseURL), zap.Error(err))
|
ts.lastSyncError = err
|
||||||
continue
|
ts.mu.Unlock()
|
||||||
|
return fmt.Errorf("创建请求失败: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 添加浏览器请求头,模拟浏览器访问
|
||||||
|
req.Header.Set("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7")
|
||||||
|
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.9")
|
||||||
|
req.Header.Set("Cache-Control", "max-age=0")
|
||||||
|
req.Header.Set("Connection", "keep-alive")
|
||||||
|
req.Header.Set("Referer", "https://www.nowapi.com/")
|
||||||
|
req.Header.Set("Sec-Fetch-Dest", "document")
|
||||||
|
req.Header.Set("Sec-Fetch-Mode", "navigate")
|
||||||
|
req.Header.Set("Sec-Fetch-Site", "cross-site")
|
||||||
|
req.Header.Set("Sec-Fetch-User", "?1")
|
||||||
|
req.Header.Set("Upgrade-Insecure-Requests", "1")
|
||||||
|
req.Header.Set("User-Agent", "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/143.0.0.0 Safari/537.36")
|
||||||
|
req.Header.Set("sec-ch-ua", `"Google Chrome";v="143", "Chromium";v="143", "Not A(Brand";v="24"`)
|
||||||
|
req.Header.Set("sec-ch-ua-mobile", "?0")
|
||||||
|
req.Header.Set("sec-ch-ua-platform", `"macOS"`)
|
||||||
|
|
||||||
|
resp, err := client.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
ts.mu.Lock()
|
||||||
|
ts.lastSyncError = err
|
||||||
|
ts.mu.Unlock()
|
||||||
|
return fmt.Errorf("API请求失败: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
resp.Body.Close()
|
err := fmt.Errorf("API返回状态码: %d", resp.StatusCode)
|
||||||
lastErr = fmt.Errorf("API返回状态码: %d", resp.StatusCode)
|
ts.mu.Lock()
|
||||||
ts.logger.Debug("API返回错误状态码", zap.String("api", baseURL), zap.Int("status", resp.StatusCode))
|
ts.lastSyncError = err
|
||||||
continue
|
ts.mu.Unlock()
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
var result ChinaTimeAPIResponse
|
var result K780TimeAPIResponse
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||||
resp.Body.Close()
|
ts.mu.Lock()
|
||||||
lastErr = err
|
ts.lastSyncError = err
|
||||||
ts.logger.Debug("解析API响应失败", zap.String("api", baseURL), zap.Error(err))
|
ts.mu.Unlock()
|
||||||
continue
|
return fmt.Errorf("解析API响应失败: %w", err)
|
||||||
}
|
|
||||||
resp.Body.Close()
|
|
||||||
|
|
||||||
// 检查返回码
|
|
||||||
if result.Code != 200 {
|
|
||||||
lastErr = fmt.Errorf("API返回错误: %s", result.Msg)
|
|
||||||
ts.logger.Debug("API返回错误码", zap.String("api", baseURL), zap.Int("code", result.Code), zap.String("msg", result.Msg))
|
|
||||||
continue
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 从msg字段解析时间戳字符串
|
// 检查返回状态
|
||||||
if result.Msg == "" {
|
if result.Success != "1" {
|
||||||
lastErr = fmt.Errorf("API返回的时间戳为空")
|
errMsg := fmt.Sprintf("API返回失败状态: success=%s", result.Success)
|
||||||
continue
|
if result.Msg != "" {
|
||||||
|
errMsg += fmt.Sprintf(", msg=%s", result.Msg)
|
||||||
|
}
|
||||||
|
if result.Msgid != "" {
|
||||||
|
errMsg += fmt.Sprintf(", msgid=%s", result.Msgid)
|
||||||
|
}
|
||||||
|
err := fmt.Errorf(errMsg)
|
||||||
|
ts.mu.Lock()
|
||||||
|
ts.lastSyncError = err
|
||||||
|
ts.mu.Unlock()
|
||||||
|
ts.logger.Warn("时间API返回失败", zap.String("success", result.Success), zap.String("msgid", result.Msgid), zap.String("msg", result.Msg))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// 从result.timestamp字段解析时间戳字符串
|
||||||
|
if result.Result.Timestamp == "" {
|
||||||
|
err := fmt.Errorf("API返回的时间戳为空")
|
||||||
|
ts.mu.Lock()
|
||||||
|
ts.lastSyncError = err
|
||||||
|
ts.mu.Unlock()
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 解析时间戳字符串为int64
|
// 解析时间戳字符串为int64
|
||||||
var timestamp int64
|
var timestamp int64
|
||||||
if _, err := fmt.Sscanf(result.Msg, "%d", ×tamp); err != nil {
|
if _, err := fmt.Sscanf(result.Result.Timestamp, "%d", ×tamp); err != nil {
|
||||||
lastErr = fmt.Errorf("解析时间戳失败: %w", err)
|
err := fmt.Errorf("解析时间戳失败: %w", err)
|
||||||
ts.logger.Debug("解析时间戳失败", zap.String("api", baseURL), zap.String("msg", result.Msg), zap.Error(err))
|
ts.mu.Lock()
|
||||||
continue
|
ts.lastSyncError = err
|
||||||
|
ts.mu.Unlock()
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 使用时间戳转换为北京时间
|
// 使用时间戳转换为北京时间
|
||||||
@@ -119,7 +157,7 @@ func (ts *TimeSync) syncTime() error {
|
|||||||
ts.mu.Unlock()
|
ts.mu.Unlock()
|
||||||
|
|
||||||
ts.logger.Info("时间同步成功",
|
ts.logger.Info("时间同步成功",
|
||||||
zap.String("api", baseURL),
|
zap.String("api", apiURL),
|
||||||
zap.String("remote_time", beijingTime.Format("2006-01-02 15:04:05")),
|
zap.String("remote_time", beijingTime.Format("2006-01-02 15:04:05")),
|
||||||
zap.String("local_time", localTime.Format("2006-01-02 15:04:05")),
|
zap.String("local_time", localTime.Format("2006-01-02 15:04:05")),
|
||||||
zap.Duration("time_diff", timeDiff),
|
zap.Duration("time_diff", timeDiff),
|
||||||
@@ -128,13 +166,6 @@ func (ts *TimeSync) syncTime() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
ts.mu.Lock()
|
|
||||||
ts.lastSyncError = lastErr
|
|
||||||
ts.mu.Unlock()
|
|
||||||
|
|
||||||
return fmt.Errorf("所有中国时间API同步失败: %w", lastErr)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start 启动定期时间同步
|
// Start 启动定期时间同步
|
||||||
func (ts *TimeSync) Start(ctx context.Context, interval time.Duration) {
|
func (ts *TimeSync) Start(ctx context.Context, interval time.Duration) {
|
||||||
// 立即同步一次
|
// 立即同步一次
|
||||||
|
|||||||
Reference in New Issue
Block a user