Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f4c6f4c57d | ||
|
|
4df60c6955 | ||
|
|
0501e120f6 | ||
|
|
cfa425bb33 | ||
|
|
0613b0022d | ||
|
|
740d15bf79 | ||
|
|
7ace5d04fa | ||
|
|
a38d7bb51d | ||
|
|
61e16f96c5 |
@@ -11,6 +11,8 @@
|
|||||||
<p>Supports <b>monitoring</b> system status, HTTP (SSL certificate change, upcoming expiration, expired), TCP, Ping and supports <b>push alerts</b>, run scheduled tasks and <b>web terminal</b>.</p>
|
<p>Supports <b>monitoring</b> system status, HTTP (SSL certificate change, upcoming expiration, expired), TCP, Ping and supports <b>push alerts</b>, run scheduled tasks and <b>web terminal</b>.</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
\>> Telegram Channel: [哪吒监控(中文通知频道)](https://t.me/nezhanews)
|
||||||
|
|
||||||
\>> Telegram Group: [Nezha Monitoring Global (English Only)](https://t.me/nezhamonitoring_global), [哪吒监控(中文群组)](https://t.me/nezhamonitoring)
|
\>> Telegram Group: [Nezha Monitoring Global (English Only)](https://t.me/nezhamonitoring_global), [哪吒监控(中文群组)](https://t.me/nezhamonitoring)
|
||||||
|
|
||||||
\>> [Use Cases | 我们的用户](https://www.google.com/search?q=%22powered+by+Nezha+Monitoring%22+OR+%22powered+by+%E5%93%AA%E5%90%92%E7%9B%91%E6%8E%A7%22) (Google)
|
\>> [Use Cases | 我们的用户](https://www.google.com/search?q=%22powered+by+Nezha+Monitoring%22+OR+%22powered+by+%E5%93%AA%E5%90%92%E7%9B%91%E6%8E%A7%22) (Google)
|
||||||
@@ -42,13 +44,13 @@ You can change the dashboard language in the settings page (`/setting`) after th
|
|||||||
<a href="https://github.com/AkkiaS7" title="Akkia"><img src="https://avatars.githubusercontent.com/u/68485070?v=4" width="50;" alt="Akkia"/></a>
|
<a href="https://github.com/AkkiaS7" title="Akkia"><img src="https://avatars.githubusercontent.com/u/68485070?v=4" width="50;" alt="Akkia"/></a>
|
||||||
<a href="https://github.com/Erope" title="卖女孩的小火柴"><img src="https://avatars.githubusercontent.com/u/44471469?v=4" width="50;" alt="卖女孩的小火柴"/></a>
|
<a href="https://github.com/Erope" title="卖女孩的小火柴"><img src="https://avatars.githubusercontent.com/u/44471469?v=4" width="50;" alt="卖女孩的小火柴"/></a>
|
||||||
<a href="https://github.com/dysf888" title="黑歌"><img src="https://avatars.githubusercontent.com/u/47450409?v=4" width="50;" alt="黑歌"/></a>
|
<a href="https://github.com/dysf888" title="黑歌"><img src="https://avatars.githubusercontent.com/u/47450409?v=4" width="50;" alt="黑歌"/></a>
|
||||||
<a href="https://github.com/xykt" title="xykt"><img src="https://avatars.githubusercontent.com/u/152045469?v=4" width="50;" alt="xykt"/></a>
|
|
||||||
<a href="https://github.com/uubulb" title="UUBulb"><img src="https://avatars.githubusercontent.com/u/35923940?v=4" width="50;" alt="UUBulb"/></a>
|
<a href="https://github.com/uubulb" title="UUBulb"><img src="https://avatars.githubusercontent.com/u/35923940?v=4" width="50;" alt="UUBulb"/></a>
|
||||||
<a href="https://github.com/MikoyChinese" title="MikoyChinese"><img src="https://avatars.githubusercontent.com/u/22676744?v=4" width="50;" alt="MikoyChinese"/></a>
|
<a href="https://github.com/xykt" title="xykt"><img src="https://avatars.githubusercontent.com/u/152045469?v=4" width="50;" alt="xykt"/></a>
|
||||||
<a href="https://github.com/nap0o" title="nap0o"><img src="https://avatars.githubusercontent.com/u/144927971?v=4" width="50;" alt="nap0o"/></a>
|
<a href="https://github.com/nap0o" title="nap0o"><img src="https://avatars.githubusercontent.com/u/144927971?v=4" width="50;" alt="nap0o"/></a>
|
||||||
|
<a href="https://github.com/MikoyChinese" title="MikoyChinese"><img src="https://avatars.githubusercontent.com/u/22676744?v=4" width="50;" alt="MikoyChinese"/></a>
|
||||||
<a href="https://github.com/JackieSung4ev" title="JackieSung4ev"><img src="https://avatars.githubusercontent.com/u/24974735?v=4" width="50;" alt="JackieSung4ev"/></a>
|
<a href="https://github.com/JackieSung4ev" title="JackieSung4ev"><img src="https://avatars.githubusercontent.com/u/24974735?v=4" width="50;" alt="JackieSung4ev"/></a>
|
||||||
<a href="https://github.com/lemoeo" title="Lemoe"><img src="https://avatars.githubusercontent.com/u/18618627?v=4" width="50;" alt="Lemoe"/></a>
|
|
||||||
<a href="https://github.com/cantoblanco" title="Kris"><img src="https://avatars.githubusercontent.com/u/116849421?v=4" width="50;" alt="Kris"/></a>
|
<a href="https://github.com/cantoblanco" title="Kris"><img src="https://avatars.githubusercontent.com/u/116849421?v=4" width="50;" alt="Kris"/></a>
|
||||||
|
<a href="https://github.com/lemoeo" title="Lemoe"><img src="https://avatars.githubusercontent.com/u/18618627?v=4" width="50;" alt="Lemoe"/></a>
|
||||||
<a href="https://github.com/spiritLHLS" title="spiritlhl"><img src="https://avatars.githubusercontent.com/u/103393591?v=4" width="50;" alt="spiritlhl"/></a>
|
<a href="https://github.com/spiritLHLS" title="spiritlhl"><img src="https://avatars.githubusercontent.com/u/103393591?v=4" width="50;" alt="spiritlhl"/></a>
|
||||||
<a href="https://github.com/liuyanxi975" title="刘颜溪"><img src="https://avatars.githubusercontent.com/u/24417037?v=4" width="50;" alt="刘颜溪"/></a>
|
<a href="https://github.com/liuyanxi975" title="刘颜溪"><img src="https://avatars.githubusercontent.com/u/24417037?v=4" width="50;" alt="刘颜溪"/></a>
|
||||||
<a href="https://github.com/CosmosZ-code" title="CosmosZ-code"><img src="https://avatars.githubusercontent.com/u/81398224?v=4" width="50;" alt="CosmosZ-code"/></a>
|
<a href="https://github.com/CosmosZ-code" title="CosmosZ-code"><img src="https://avatars.githubusercontent.com/u/81398224?v=4" width="50;" alt="CosmosZ-code"/></a>
|
||||||
|
|||||||
+28
-3
@@ -42,6 +42,19 @@ func percentage(used, total uint64) float64 {
|
|||||||
return float64(used) * 100 / float64(total)
|
return float64(used) * 100 / float64(total)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func maxSliceValue(slice []float64) float64 {
|
||||||
|
if len(slice) != 0 {
|
||||||
|
max := slice[0]
|
||||||
|
for _, val := range slice {
|
||||||
|
if max < val {
|
||||||
|
max = val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
// Snapshot 未通过规则返回 struct{}{}, 通过返回 nil
|
// Snapshot 未通过规则返回 struct{}{}, 通过返回 nil
|
||||||
func (u *Rule) Snapshot(cycleTransferStats *CycleTransferStats, server *Server, db *gorm.DB) interface{} {
|
func (u *Rule) Snapshot(cycleTransferStats *CycleTransferStats, server *Server, db *gorm.DB) interface{} {
|
||||||
// 监控全部但是排除了此服务器
|
// 监控全部但是排除了此服务器
|
||||||
@@ -63,6 +76,8 @@ func (u *Rule) Snapshot(cycleTransferStats *CycleTransferStats, server *Server,
|
|||||||
switch u.Type {
|
switch u.Type {
|
||||||
case "cpu":
|
case "cpu":
|
||||||
src = float64(server.State.CPU)
|
src = float64(server.State.CPU)
|
||||||
|
case "gpu":
|
||||||
|
src = float64(server.State.GPU)
|
||||||
case "memory":
|
case "memory":
|
||||||
src = percentage(server.State.MemUsed, server.Host.MemTotal)
|
src = percentage(server.State.MemUsed, server.Host.MemTotal)
|
||||||
case "swap":
|
case "swap":
|
||||||
@@ -91,21 +106,21 @@ func (u *Rule) Snapshot(cycleTransferStats *CycleTransferStats, server *Server,
|
|||||||
src = float64(server.State.NetInTransfer - uint64(server.PrevHourlyTransferIn))
|
src = float64(server.State.NetInTransfer - uint64(server.PrevHourlyTransferIn))
|
||||||
if u.CycleInterval != 0 {
|
if u.CycleInterval != 0 {
|
||||||
var res NResult
|
var res NResult
|
||||||
db.Model(&Transfer{}).Select("SUM(`in`) AS n").Where("created_at > ? AND server_id = ?", u.GetTransferDurationStart(), server.ID).Scan(&res)
|
db.Model(&Transfer{}).Select("SUM(`in`) AS n").Where("datetime(`created_at`) >= datetime(?) AND server_id = ?", u.GetTransferDurationStart().UTC(), server.ID).Scan(&res)
|
||||||
src += float64(res.N)
|
src += float64(res.N)
|
||||||
}
|
}
|
||||||
case "transfer_out_cycle":
|
case "transfer_out_cycle":
|
||||||
src = float64(server.State.NetOutTransfer - uint64(server.PrevHourlyTransferOut))
|
src = float64(server.State.NetOutTransfer - uint64(server.PrevHourlyTransferOut))
|
||||||
if u.CycleInterval != 0 {
|
if u.CycleInterval != 0 {
|
||||||
var res NResult
|
var res NResult
|
||||||
db.Model(&Transfer{}).Select("SUM(`out`) AS n").Where("created_at > ? AND server_id = ?", u.GetTransferDurationStart(), server.ID).Scan(&res)
|
db.Model(&Transfer{}).Select("SUM(`out`) AS n").Where("datetime(`created_at`) >= datetime(?) AND server_id = ?", u.GetTransferDurationStart().UTC(), server.ID).Scan(&res)
|
||||||
src += float64(res.N)
|
src += float64(res.N)
|
||||||
}
|
}
|
||||||
case "transfer_all_cycle":
|
case "transfer_all_cycle":
|
||||||
src = float64(server.State.NetOutTransfer - uint64(server.PrevHourlyTransferOut) + server.State.NetInTransfer - uint64(server.PrevHourlyTransferIn))
|
src = float64(server.State.NetOutTransfer - uint64(server.PrevHourlyTransferOut) + server.State.NetInTransfer - uint64(server.PrevHourlyTransferIn))
|
||||||
if u.CycleInterval != 0 {
|
if u.CycleInterval != 0 {
|
||||||
var res NResult
|
var res NResult
|
||||||
db.Model(&Transfer{}).Select("SUM(`in`+`out`) AS n").Where("created_at > ? AND server_id = ?", u.GetTransferDurationStart(), server.ID).Scan(&res)
|
db.Model(&Transfer{}).Select("SUM(`in`+`out`) AS n").Where("datetime(`created_at`) >= datetime(?) AND server_id = ?", u.GetTransferDurationStart().UTC(), server.ID).Scan(&res)
|
||||||
src += float64(res.N)
|
src += float64(res.N)
|
||||||
}
|
}
|
||||||
case "load1":
|
case "load1":
|
||||||
@@ -120,6 +135,16 @@ func (u *Rule) Snapshot(cycleTransferStats *CycleTransferStats, server *Server,
|
|||||||
src = float64(server.State.UdpConnCount)
|
src = float64(server.State.UdpConnCount)
|
||||||
case "process_count":
|
case "process_count":
|
||||||
src = float64(server.State.ProcessCount)
|
src = float64(server.State.ProcessCount)
|
||||||
|
case "temperature_max":
|
||||||
|
var temp []float64
|
||||||
|
if server.State.Temperatures != nil {
|
||||||
|
for _, tempStat := range server.State.Temperatures {
|
||||||
|
if tempStat.Temperature != 0 {
|
||||||
|
temp = append(temp, tempStat.Temperature)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
src = maxSliceValue(temp)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 循环区间流量检测 · 更新下次需要检测时间
|
// 循环区间流量检测 · 更新下次需要检测时间
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ type ProviderCloudflare struct {
|
|||||||
Secret string
|
Secret string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderCloudflare) UpdateDomain(domainConfig *DomainConfig) bool {
|
func (provider *ProviderCloudflare) UpdateDomain(domainConfig *DomainConfig) bool {
|
||||||
if domainConfig == nil {
|
if domainConfig == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -42,7 +42,7 @@ func (provider ProviderCloudflare) UpdateDomain(domainConfig *DomainConfig) bool
|
|||||||
return resultV4 && resultV6
|
return resultV4 && resultV6
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderCloudflare) addDomainRecord(zoneID string, domainConfig *DomainConfig, isIpv4 bool) bool {
|
func (provider *ProviderCloudflare) addDomainRecord(zoneID string, domainConfig *DomainConfig, isIpv4 bool) bool {
|
||||||
record, err := provider.findDNSRecord(zoneID, domainConfig.FullDomain, isIpv4)
|
record, err := provider.findDNSRecord(zoneID, domainConfig.FullDomain, isIpv4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("查找 DNS 记录时出错: %s\n", err)
|
log.Printf("查找 DNS 记录时出错: %s\n", err)
|
||||||
@@ -58,7 +58,7 @@ func (provider ProviderCloudflare) addDomainRecord(zoneID string, domainConfig *
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderCloudflare) getZoneID(domain string) (string, error) {
|
func (provider *ProviderCloudflare) getZoneID(domain string) (string, error) {
|
||||||
_, realDomain := SplitDomain(domain)
|
_, realDomain := SplitDomain(domain)
|
||||||
url := fmt.Sprintf("https://api.cloudflare.com/client/v4/zones?name=%s", realDomain)
|
url := fmt.Sprintf("https://api.cloudflare.com/client/v4/zones?name=%s", realDomain)
|
||||||
body, err := provider.sendRequest("GET", url, nil)
|
body, err := provider.sendRequest("GET", url, nil)
|
||||||
@@ -81,7 +81,7 @@ func (provider ProviderCloudflare) getZoneID(domain string) (string, error) {
|
|||||||
return "", fmt.Errorf("找不到 Zone ID")
|
return "", fmt.Errorf("找不到 Zone ID")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderCloudflare) findDNSRecord(zoneID string, domain string, isIPv4 bool) (map[string]interface{}, error) {
|
func (provider *ProviderCloudflare) findDNSRecord(zoneID string, domain string, isIPv4 bool) (map[string]interface{}, error) {
|
||||||
var ipType = "A"
|
var ipType = "A"
|
||||||
if !isIPv4 {
|
if !isIPv4 {
|
||||||
ipType = "AAAA"
|
ipType = "AAAA"
|
||||||
@@ -106,7 +106,7 @@ func (provider ProviderCloudflare) findDNSRecord(zoneID string, domain string, i
|
|||||||
return nil, nil // 没有找到 DNS 记录
|
return nil, nil // 没有找到 DNS 记录
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderCloudflare) createDNSRecord(zoneID string, domainConfig *DomainConfig, isIPv4 bool) bool {
|
func (provider *ProviderCloudflare) createDNSRecord(zoneID string, domainConfig *DomainConfig, isIPv4 bool) bool {
|
||||||
var ipType = "A"
|
var ipType = "A"
|
||||||
var ipAddr = domainConfig.Ipv4Addr
|
var ipAddr = domainConfig.Ipv4Addr
|
||||||
if !isIPv4 {
|
if !isIPv4 {
|
||||||
@@ -126,7 +126,7 @@ func (provider ProviderCloudflare) createDNSRecord(zoneID string, domainConfig *
|
|||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderCloudflare) updateDNSRecord(zoneID string, recordID string, domainConfig *DomainConfig, isIPv4 bool) bool {
|
func (provider *ProviderCloudflare) updateDNSRecord(zoneID string, recordID string, domainConfig *DomainConfig, isIPv4 bool) bool {
|
||||||
var ipType = "A"
|
var ipType = "A"
|
||||||
var ipAddr = domainConfig.Ipv4Addr
|
var ipAddr = domainConfig.Ipv4Addr
|
||||||
if !isIPv4 {
|
if !isIPv4 {
|
||||||
@@ -147,7 +147,7 @@ func (provider ProviderCloudflare) updateDNSRecord(zoneID string, recordID strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 以下为辅助方法,如发送 HTTP 请求等
|
// 以下为辅助方法,如发送 HTTP 请求等
|
||||||
func (provider ProviderCloudflare) sendRequest(method string, url string, data []byte) ([]byte, error) {
|
func (provider *ProviderCloudflare) sendRequest(method string, url string, data []byte) ([]byte, error) {
|
||||||
client := &http.Client{}
|
client := &http.Client{}
|
||||||
req, err := http.NewRequest(method, url, bytes.NewBuffer(data))
|
req, err := http.NewRequest(method, url, bytes.NewBuffer(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
+1
-1
@@ -2,6 +2,6 @@ package ddns
|
|||||||
|
|
||||||
type ProviderDummy struct{}
|
type ProviderDummy struct{}
|
||||||
|
|
||||||
func (provider ProviderDummy) UpdateDomain(domainConfig *DomainConfig) bool {
|
func (provider *ProviderDummy) UpdateDomain(domainConfig *DomainConfig) bool {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -23,7 +23,7 @@ type ProviderTencentCloud struct {
|
|||||||
SecretKey string
|
SecretKey string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderTencentCloud) UpdateDomain(domainConfig *DomainConfig) bool {
|
func (provider *ProviderTencentCloud) UpdateDomain(domainConfig *DomainConfig) bool {
|
||||||
if domainConfig == nil {
|
if domainConfig == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -46,7 +46,7 @@ func (provider ProviderTencentCloud) UpdateDomain(domainConfig *DomainConfig) bo
|
|||||||
return resultV4 && resultV6
|
return resultV4 && resultV6
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderTencentCloud) addDomainRecord(domainConfig *DomainConfig, isIpv4 bool) bool {
|
func (provider *ProviderTencentCloud) addDomainRecord(domainConfig *DomainConfig, isIpv4 bool) bool {
|
||||||
record, err := provider.findDNSRecord(domainConfig.FullDomain, isIpv4)
|
record, err := provider.findDNSRecord(domainConfig.FullDomain, isIpv4)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Printf("查找 DNS 记录时出错: %s\n", err)
|
log.Printf("查找 DNS 记录时出错: %s\n", err)
|
||||||
@@ -66,7 +66,7 @@ func (provider ProviderTencentCloud) addDomainRecord(domainConfig *DomainConfig,
|
|||||||
return provider.updateDNSRecord(domainConfig.FullDomain, record["RecordList"].([]interface{})[0].(map[string]interface{})["RecordId"].(float64), domainConfig, isIpv4)
|
return provider.updateDNSRecord(domainConfig.FullDomain, record["RecordList"].([]interface{})[0].(map[string]interface{})["RecordId"].(float64), domainConfig, isIpv4)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderTencentCloud) findDNSRecord(domain string, isIPv4 bool) (map[string]interface{}, error) {
|
func (provider *ProviderTencentCloud) findDNSRecord(domain string, isIPv4 bool) (map[string]interface{}, error) {
|
||||||
var ipType = "A"
|
var ipType = "A"
|
||||||
if !isIPv4 {
|
if !isIPv4 {
|
||||||
ipType = "AAAA"
|
ipType = "AAAA"
|
||||||
@@ -95,7 +95,7 @@ func (provider ProviderTencentCloud) findDNSRecord(domain string, isIPv4 bool) (
|
|||||||
return result, nil
|
return result, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderTencentCloud) createDNSRecord(domain string, domainConfig *DomainConfig, isIPv4 bool) bool {
|
func (provider *ProviderTencentCloud) createDNSRecord(domain string, domainConfig *DomainConfig, isIPv4 bool) bool {
|
||||||
var ipType = "A"
|
var ipType = "A"
|
||||||
var ipAddr = domainConfig.Ipv4Addr
|
var ipAddr = domainConfig.Ipv4Addr
|
||||||
if !isIPv4 {
|
if !isIPv4 {
|
||||||
@@ -117,7 +117,7 @@ func (provider ProviderTencentCloud) createDNSRecord(domain string, domainConfig
|
|||||||
return err == nil
|
return err == nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderTencentCloud) updateDNSRecord(domain string, recordID float64, domainConfig *DomainConfig, isIPv4 bool) bool {
|
func (provider *ProviderTencentCloud) updateDNSRecord(domain string, recordID float64, domainConfig *DomainConfig, isIPv4 bool) bool {
|
||||||
var ipType = "A"
|
var ipType = "A"
|
||||||
var ipAddr = domainConfig.Ipv4Addr
|
var ipAddr = domainConfig.Ipv4Addr
|
||||||
if !isIPv4 {
|
if !isIPv4 {
|
||||||
@@ -141,7 +141,7 @@ func (provider ProviderTencentCloud) updateDNSRecord(domain string, recordID flo
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 以下为辅助方法,如发送 HTTP 请求等
|
// 以下为辅助方法,如发送 HTTP 请求等
|
||||||
func (provider ProviderTencentCloud) sendRequest(action string, data []byte) ([]byte, error) {
|
func (provider *ProviderTencentCloud) sendRequest(action string, data []byte) ([]byte, error) {
|
||||||
client := &http.Client{}
|
client := &http.Client{}
|
||||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(data))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -173,18 +173,18 @@ func (provider ProviderTencentCloud) sendRequest(action string, data []byte) ([]
|
|||||||
|
|
||||||
// https://github.com/jeessy2/ddns-go/blob/master/util/tencent_cloud_signer.go
|
// https://github.com/jeessy2/ddns-go/blob/master/util/tencent_cloud_signer.go
|
||||||
|
|
||||||
func (provider ProviderTencentCloud) sha256hex(s string) string {
|
func (provider *ProviderTencentCloud) sha256hex(s string) string {
|
||||||
b := sha256.Sum256([]byte(s))
|
b := sha256.Sum256([]byte(s))
|
||||||
return hex.EncodeToString(b[:])
|
return hex.EncodeToString(b[:])
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderTencentCloud) hmacsha256(s, key string) string {
|
func (provider *ProviderTencentCloud) hmacsha256(s, key string) string {
|
||||||
hashed := hmac.New(sha256.New, []byte(key))
|
hashed := hmac.New(sha256.New, []byte(key))
|
||||||
hashed.Write([]byte(s))
|
hashed.Write([]byte(s))
|
||||||
return string(hashed.Sum(nil))
|
return string(hashed.Sum(nil))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderTencentCloud) WriteString(strs ...string) string {
|
func (provider *ProviderTencentCloud) WriteString(strs ...string) string {
|
||||||
var b strings.Builder
|
var b strings.Builder
|
||||||
for _, str := range strs {
|
for _, str := range strs {
|
||||||
b.WriteString(str)
|
b.WriteString(str)
|
||||||
@@ -193,7 +193,7 @@ func (provider ProviderTencentCloud) WriteString(strs ...string) string {
|
|||||||
return b.String()
|
return b.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderTencentCloud) signRequest(secretId string, secretKey string, r *http.Request, action string, payload string) {
|
func (provider *ProviderTencentCloud) signRequest(secretId string, secretKey string, r *http.Request, action string, payload string) {
|
||||||
algorithm := "TC3-HMAC-SHA256"
|
algorithm := "TC3-HMAC-SHA256"
|
||||||
service := "dnspod"
|
service := "dnspod"
|
||||||
host := provider.WriteString(service, ".tencentcloudapi.com")
|
host := provider.WriteString(service, ".tencentcloudapi.com")
|
||||||
|
|||||||
+1
-1
@@ -14,7 +14,7 @@ type ProviderWebHook struct {
|
|||||||
RequestHeader string
|
RequestHeader string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (provider ProviderWebHook) UpdateDomain(domainConfig *DomainConfig) bool {
|
func (provider *ProviderWebHook) UpdateDomain(domainConfig *DomainConfig) bool {
|
||||||
if domainConfig == nil {
|
if domainConfig == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-52
@@ -7,6 +7,7 @@ const mixinsVue = {
|
|||||||
showGoTop: false,
|
showGoTop: false,
|
||||||
preferredTemplate: null,
|
preferredTemplate: null,
|
||||||
isMobile: false,
|
isMobile: false,
|
||||||
|
staticUrl: '/static/theme-server-status',
|
||||||
adaptedTemplates: [
|
adaptedTemplates: [
|
||||||
{ key: 'default', name: 'Default', icon: 'th large' },
|
{ key: 'default', name: 'Default', icon: 'th large' },
|
||||||
{ key: 'angel-kanade', name: 'AngelKanade', icon: 'square' },
|
{ key: 'angel-kanade', name: 'AngelKanade', icon: 'square' },
|
||||||
@@ -15,8 +16,8 @@ const mixinsVue = {
|
|||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.isMobile = this.checkIsMobile();
|
this.isMobile = this.checkIsMobile();
|
||||||
this.initTheme();
|
this.theme = this.initTheme();
|
||||||
this.storedShowGroup();
|
this.showGroup = this.initShowGroup();
|
||||||
this.preferredTemplate = this.getCookie('preferred_theme') ? this.getCookie('preferred_theme') : this.$root.defaultTemplate;
|
this.preferredTemplate = this.getCookie('preferred_theme') ? this.getCookie('preferred_theme') : this.$root.defaultTemplate;
|
||||||
window.addEventListener('scroll', this.handleScroll);
|
window.addEventListener('scroll', this.handleScroll);
|
||||||
},
|
},
|
||||||
@@ -24,22 +25,36 @@ const mixinsVue = {
|
|||||||
window.removeEventListener('scroll', this.handleScroll);
|
window.removeEventListener('scroll', this.handleScroll);
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleView() {
|
initTheme() {
|
||||||
this.showGroup = !this.showGroup;
|
const storedTheme = localStorage.getItem("theme");
|
||||||
localStorage.setItem("showGroup", JSON.stringify(this.showGroup));
|
const theme = (storedTheme === 'dark' || storedTheme === 'light') ? storedTheme : (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
|
||||||
return this.showGroup;
|
this.setTheme(theme);
|
||||||
|
return theme;
|
||||||
},
|
},
|
||||||
storedShowGroup() {
|
setTheme(theme) {
|
||||||
const storedShowGroup = localStorage.getItem("showGroup");
|
document.body.setAttribute("theme", theme);
|
||||||
if (storedShowGroup !== null) {
|
this.theme = theme;
|
||||||
this.showGroup = JSON.parse(storedShowGroup);
|
localStorage.setItem("theme", theme);
|
||||||
|
// 重新赋值全局调色
|
||||||
|
this.colors = this.theme == "dark" ? this.colorsDark : this.colorsLight;
|
||||||
|
|
||||||
|
if(this.$root.page == 'index') {
|
||||||
|
this.reloadCharts(); // 重新载入echarts图表
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toggleTemplate(template) {
|
initShowGroup() {
|
||||||
if( template != this.preferredTemplate){
|
const storedShowGroup = localStorage.getItem("showGroup");
|
||||||
this.preferredTemplate = template;
|
const showGroup = storedShowGroup !== null ? JSON.parse(storedShowGroup) : false;
|
||||||
this.updateCookie("preferred_theme", template);
|
if (storedShowGroup === null) {
|
||||||
window.location.reload();
|
localStorage.setItem("showGroup", showGroup);
|
||||||
|
}
|
||||||
|
return showGroup;
|
||||||
|
},
|
||||||
|
toggleShowGroup() {
|
||||||
|
this.showGroup = !this.showGroup;
|
||||||
|
localStorage.setItem("showGroup", this.showGroup);
|
||||||
|
if (this.$root.page == 'service') {
|
||||||
|
this.$root.initTooltip();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
updateCookie(name, value) {
|
updateCookie(name, value) {
|
||||||
@@ -57,43 +72,6 @@ const mixinsVue = {
|
|||||||
}
|
}
|
||||||
return cookieValue;
|
return cookieValue;
|
||||||
},
|
},
|
||||||
setTheme(title, store = false) {
|
|
||||||
this.theme = title;
|
|
||||||
document.body.setAttribute("theme", title);
|
|
||||||
if (store) {
|
|
||||||
localStorage.setItem("theme", title);
|
|
||||||
this.isSystemTheme = false;
|
|
||||||
if(this.$root.page == 'index') {
|
|
||||||
this.$root.reloadCharts(); //重新载入echarts图表
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
setSystemTheme() {
|
|
||||||
localStorage.removeItem("theme");
|
|
||||||
this.initTheme();
|
|
||||||
this.isSystemTheme = true;
|
|
||||||
},
|
|
||||||
initTheme() {
|
|
||||||
const storeTheme = localStorage.getItem("theme");
|
|
||||||
if (storeTheme === 'dark' || storeTheme === 'light') {
|
|
||||||
this.setTheme(storeTheme, true);
|
|
||||||
} else {
|
|
||||||
this.isSystemTheme = true
|
|
||||||
const handleChange = (mediaQueryListEvent) => {
|
|
||||||
if (localStorage.getItem("theme")) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if (mediaQueryListEvent.matches) {
|
|
||||||
this.setTheme('dark');
|
|
||||||
} else {
|
|
||||||
this.setTheme('light');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const mediaQueryListDark = window.matchMedia('(prefers-color-scheme: dark)');
|
|
||||||
this.setTheme(mediaQueryListDark.matches ? 'dark' : 'light');
|
|
||||||
mediaQueryListDark.addEventListener("change", handleChange);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
toFixed2(f) {
|
toFixed2(f) {
|
||||||
return f.toFixed(2)
|
return f.toFixed(2)
|
||||||
},
|
},
|
||||||
|
|||||||
+1277
File diff suppressed because it is too large
Load Diff
+243
File diff suppressed because one or more lines are too long
+242
File diff suppressed because one or more lines are too long
+245
File diff suppressed because one or more lines are too long
+244
File diff suppressed because one or more lines are too long
+1
@@ -180,6 +180,7 @@
|
|||||||
'TC0H', //CPU Heatsink 温度,代表 CPU 散热器的温度
|
'TC0H', //CPU Heatsink 温度,代表 CPU 散热器的温度
|
||||||
'TC0P', //CPU Proximity 温度,代表 CPU 附近的温度
|
'TC0P', //CPU Proximity 温度,代表 CPU 附近的温度
|
||||||
'k10temp', //AMD K10(Phenom、Athlon、Sempron 等)系列处理器的温度监测
|
'k10temp', //AMD K10(Phenom、Athlon、Sempron 等)系列处理器的温度监测
|
||||||
|
'k10temp_tctl', //AMD K10 (Athlon II、Phenom II 等)系列处理器的温度监测
|
||||||
'coretemp_package_id_0', //整个封装处理器温度
|
'coretemp_package_id_0', //整个封装处理器温度
|
||||||
'cpu_thermal_zone', //全志
|
'cpu_thermal_zone', //全志
|
||||||
'cpu-thermal', //树莓派(博通)
|
'cpu-thermal', //树莓派(博通)
|
||||||
|
|||||||
@@ -9,12 +9,12 @@
|
|||||||
<i @click="showMapChart" data-toggle="modal" data-target="#mapChartBox" class="bi bi-geo-alt"></i>
|
<i @click="showMapChart" data-toggle="modal" data-target="#mapChartBox" class="bi bi-geo-alt"></i>
|
||||||
</span>
|
</span>
|
||||||
<span class="toggleView">
|
<span class="toggleView">
|
||||||
<i v-if="showGroup" @click="toggleView" class="show-nogroup bi bi-justify"></i>
|
<i v-if="showGroup" @click="toggleShowGroup" class="show-nogroup bi bi-justify"></i>
|
||||||
<i v-else @click="toggleView" class="show-group bi bi-view-stacked"></i>
|
<i v-else @click="toggleShowGroup" class="show-group bi bi-view-stacked"></i>
|
||||||
</span>
|
</span>
|
||||||
<span class="setTheme">
|
<span class="setTheme">
|
||||||
<i v-if="theme === 'light'" @click="setTheme('dark', true)" class="setTheme-dark bi bi-moon-fill"></i>
|
<i v-if="theme === 'light'" @click="setTheme('dark')" class="setTheme-dark bi bi-moon-fill"></i>
|
||||||
<i v-else @click="setTheme('light', true)" class="setTheme-light bi bi-brightness-high-fill"></i>
|
<i v-else @click="setTheme('light')" class="setTheme-light bi bi-brightness-high-fill"></i>
|
||||||
</span>
|
</span>
|
||||||
<span v-if="showGoTop" class="showGoTop">
|
<span v-if="showGoTop" class="showGoTop">
|
||||||
<i @click="goTop" class="goTop bi bi-arrow-up"></i>
|
<i @click="goTop" class="goTop bi bi-arrow-up"></i>
|
||||||
|
|||||||
+1
-2
@@ -20,8 +20,7 @@
|
|||||||
<script src="https://unpkg.com/[email protected]/dist/js/bootstrap.min.js"></script>
|
<script src="https://unpkg.com/[email protected]/dist/js/bootstrap.min.js"></script>
|
||||||
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
|
<script src="https://unpkg.com/[email protected]/dist/vue.min.js"></script>
|
||||||
<script src="https://unpkg.com/[email protected]/dist/echarts.min.js"></script>
|
<script src="https://unpkg.com/[email protected]/dist/echarts.min.js"></script>
|
||||||
<script src="https://unpkg.com/[email protected]/map/js/world.js"></script>
|
<script src="/static/theme-server-status/js/mixin.js?v20240707"></script>
|
||||||
<script src="/static/theme-server-status/js/mixin.js?v20240302"></script>
|
|
||||||
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
<!-- HTML5 shim and Respond.js IE8 support of HTML5 elements and media queries -->
|
||||||
<!--[if lt IE 9]>
|
<!--[if lt IE 9]>
|
||||||
<script src="/static/theme-server-status/js/html5shiv.js"></script>
|
<script src="/static/theme-server-status/js/html5shiv.js"></script>
|
||||||
|
|||||||
+22
-3
File diff suppressed because one or more lines are too long
+68
-49
@@ -4,18 +4,24 @@
|
|||||||
{{template "theme-server-status/content-nav" .}}
|
{{template "theme-server-status/content-nav" .}}
|
||||||
<!-- showGroup true -->
|
<!-- showGroup true -->
|
||||||
<template v-if="showGroup">
|
<template v-if="showGroup">
|
||||||
<section class="container content" style="max-width: 95vw; min-height: .01%;overflow-x: auto;" v-for="group in servicesTag">
|
<section v-if="servicesTag.length === 0" class="container content" style="max-width: 95vw; min-height: .01%;overflow-x: auto;">
|
||||||
|
<p>No Valid Service Monitor Configuration Entries Found. Please Verify in the <a href="/monitor">Admin Panel</a>.</p>
|
||||||
|
</section>
|
||||||
|
<section v-else class="container content" style="max-width: 95vw; min-height: .01%;overflow-x: auto;" v-for="group in servicesTag">
|
||||||
{{template "theme-server-status/service-group-true" .}}
|
{{template "theme-server-status/service-group-true" .}}
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
<!-- showGroup false -->
|
<!-- showGroup false -->
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<section class="container content" style="max-width: 95vw; min-height: .01%;overflow-x: auto;">
|
<section v-if="servicesNoTag.length === 0" class="container content" style="max-width: 95vw; min-height: .01%;overflow-x: auto;">
|
||||||
|
<p>No Valid Service Monitor Configuration Entries Found. Please Verify in the <a href="/monitor">Admin Panel</a>.</p>
|
||||||
|
</section>
|
||||||
|
<section v-else class="container content" style="max-width: 95vw; min-height: .01%;overflow-x: auto;">
|
||||||
{{template "theme-server-status/service-group-false" .}}
|
{{template "theme-server-status/service-group-false" .}}
|
||||||
</section>
|
</section>
|
||||||
</template>
|
</template>
|
||||||
<section class="container content table-responsive" style="max-width: 95vw">
|
|
||||||
{{if .CycleTransferStats}}
|
{{if .CycleTransferStats}}
|
||||||
|
<section class="container content table-responsive" style="max-width: 95vw">
|
||||||
<table class="table table-striped table-condensed table-hover">
|
<table class="table table-striped table-condensed table-hover">
|
||||||
<thead>
|
<thead>
|
||||||
<tr class="node-group-tag">
|
<tr class="node-group-tag">
|
||||||
@@ -62,16 +68,10 @@
|
|||||||
{{end}}
|
{{end}}
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
{{end}}
|
|
||||||
</section>
|
</section>
|
||||||
|
{{end}}
|
||||||
{{template "theme-server-status/content-footer" .}}
|
{{template "theme-server-status/content-footer" .}}
|
||||||
</div>
|
</div>
|
||||||
<script>
|
|
||||||
// 初始化 Tooltip
|
|
||||||
$(document).ready(function(){
|
|
||||||
$('[data-toggle="tooltip"]').tooltip();
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
<script>
|
<script>
|
||||||
new Vue({
|
new Vue({
|
||||||
el: '#app',
|
el: '#app',
|
||||||
@@ -80,13 +80,16 @@
|
|||||||
page: 'service',
|
page: 'service',
|
||||||
defaultTemplate: {{.Conf.Site.Theme}},
|
defaultTemplate: {{.Conf.Site.Theme}},
|
||||||
templates: {{.Themes}},
|
templates: {{.Themes}},
|
||||||
|
services: {{.Services}},
|
||||||
servicesTag: [],
|
servicesTag: [],
|
||||||
servicesNoTag: [],
|
servicesNoTag: []
|
||||||
},
|
},
|
||||||
created() {
|
created() {
|
||||||
this.initData();
|
this.servicesTag = this.groupingData(this.initData(this.services),"type");
|
||||||
|
this.servicesNoTag = this.initData(this.services);
|
||||||
},
|
},
|
||||||
mounted() {
|
mounted() {
|
||||||
|
this.initTooltip();
|
||||||
},
|
},
|
||||||
mixins: [mixinsVue],
|
mixins: [mixinsVue],
|
||||||
methods: {
|
methods: {
|
||||||
@@ -103,32 +106,36 @@
|
|||||||
}
|
}
|
||||||
return n
|
return n
|
||||||
},
|
},
|
||||||
initData() {
|
initData(services) {
|
||||||
// @formatter:off
|
let nodes = [];
|
||||||
const services = []
|
for (let key in services) {
|
||||||
{{range $service := .Services}}
|
const service = services[key];
|
||||||
services.push({
|
let node = {
|
||||||
type: '{{$service.Monitor.Type}}',
|
type: service.Monitor.Type,
|
||||||
name: '{{$service.Monitor.Name}}',
|
name: service.Monitor.Name,
|
||||||
currentUp: parseInt('{{$service.CurrentUp}}'),
|
currentUp: parseInt(service.CurrentUp),
|
||||||
currentDown: parseInt('{{$service.CurrentDown}}'),
|
currentDown: parseInt(service.CurrentDown),
|
||||||
totalUp: parseInt('{{$service.TotalUp}}'),
|
totalUp: parseInt(service.TotalUp),
|
||||||
totalDown: parseInt('{{$service.TotalDown}}'),
|
totalDown: parseInt(service.TotalDown),
|
||||||
delay: '{{$service.Delay}}'.replaceAll("[","").replaceAll("]","").split(" "),
|
up: service.Up,
|
||||||
up: '{{$service.Up}}'.replaceAll("[","").replaceAll("]","").split(" "),
|
down: service.Down,
|
||||||
down: '{{$service.Down}}'.replaceAll("[","").replaceAll("]","").split(" "),
|
delay: service.Delay,
|
||||||
})
|
avgDelay: parseInt(this.getAvgDelay(service.Delay)) + "ms",
|
||||||
{{end}}
|
health: this.getStateInfo(this.getPercent(service.CurrentUp, service.CurrentDown)),
|
||||||
// @formatter:on
|
totalUpTime: this.getProgressInfo(this.getPercent(service.TotalUp, service.TotalDown))
|
||||||
for (let i = 0; i < services.length; i++) {
|
};
|
||||||
const service = services[i];
|
nodes.push(node);
|
||||||
service.avgDelay = parseInt(service.delay[service.delay.length - 1]) + "ms"
|
};
|
||||||
service.health = this.getStateInfo(this.getPercent(service.currentUp, service.currentDown))
|
for (let i = 0; i < nodes.length; i++) {
|
||||||
service.dayDetail = this.getDayTails(service)
|
const node = nodes[i];
|
||||||
service.totalUpTime = this.getProgressInfo(this.getPercent(service.totalUp, service.totalDown))
|
node.dayDetail = this.getDayTails(node)
|
||||||
}
|
}
|
||||||
this.servicesTag = this.groupingData(services,"type");
|
return nodes
|
||||||
this.servicesNoTag = services;
|
},
|
||||||
|
initTooltip() {
|
||||||
|
$(document).ready(function(){
|
||||||
|
$('[data-toggle="tooltip"]').tooltip();
|
||||||
|
});
|
||||||
},
|
},
|
||||||
getPercent(up, down) {
|
getPercent(up, down) {
|
||||||
if (!up) {
|
if (!up) {
|
||||||
@@ -151,24 +158,24 @@
|
|||||||
return this.toFixed2(currentUp / total * 100)
|
return this.toFixed2(currentUp / total * 100)
|
||||||
},
|
},
|
||||||
getDayTails(service) {
|
getDayTails(service) {
|
||||||
const result = []
|
const result = [];
|
||||||
for (let i = 0; i < service.up.length; i++) {
|
for (let i = 0; i < service.up.length; i++) {
|
||||||
const up = service.up[i]
|
const up = service.up[i];
|
||||||
const down = service.down[i]
|
const down = service.down[i];
|
||||||
const delay = service.delay[i]
|
let delay = Number(service.delay[i]);
|
||||||
let percent = this.getPercent(up, down)
|
let percent = this.getPercent(up, down);
|
||||||
if (percent <= 0) {
|
if (percent <= 0) {
|
||||||
percent = 0;
|
percent = 0;
|
||||||
}
|
}
|
||||||
let className = this.getStateInfo(percent).className
|
let className = this.getStateInfo(percent).className;
|
||||||
let available = '{{tr "Availability"}}'
|
let available = '{{tr "Availability"}}';
|
||||||
let averageLatency = '{{tr "AverageLatency"}}'
|
let averageLatency = '{{tr "AverageLatency"}}';
|
||||||
const text = `${this.beforeDay(service.up.length - i - 1)},${available}:${percent}%,${averageLatency}:${delay}ms`
|
const text = `${this.beforeDay(service.up.length - i - 1)},${available}:${Number(percent).toFixed(3)}%,${averageLatency}:${Number(delay).toFixed(3)}ms`;
|
||||||
result.push({
|
result.push({
|
||||||
text, className
|
text, className
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
return result
|
return result;
|
||||||
},
|
},
|
||||||
beforeDay(days) {
|
beforeDay(days) {
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
@@ -203,8 +210,9 @@
|
|||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
getProgressInfo(percent) {
|
getProgressInfo(percent) {
|
||||||
const result = this.getStateInfo(percent)
|
const result = this.getStateInfo(percent);
|
||||||
result.style = `width: ${parseInt(percent)}%`;
|
result.style = `width: ${parseInt(percent)}%`;
|
||||||
|
result.percent = Number(percent).toFixed(2);
|
||||||
const className = result.className;
|
const className = result.className;
|
||||||
if (className === "good") {
|
if (className === "good") {
|
||||||
result.className = 'progress-bar progress-bar-success'
|
result.className = 'progress-bar progress-bar-success'
|
||||||
@@ -218,6 +226,17 @@
|
|||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
},
|
},
|
||||||
|
getAvgDelay(array) {
|
||||||
|
const { sum, count } = array.reduce((acc, value) => {
|
||||||
|
if (value !== 0) {
|
||||||
|
acc.sum += value;
|
||||||
|
acc.count += 1;
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, { sum: 0, count: 0 });
|
||||||
|
|
||||||
|
return count > 0 ? sum / count : 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
+2
-2
@@ -24,8 +24,8 @@ os_arch=""
|
|||||||
[ -e /etc/os-release ] && grep -i "PRETTY_NAME" /etc/os-release | grep -qi "alpine" && os_alpine='1'
|
[ -e /etc/os-release ] && grep -i "PRETTY_NAME" /etc/os-release | grep -qi "alpine" && os_alpine='1'
|
||||||
|
|
||||||
sudo() {
|
sudo() {
|
||||||
EUID=$(id -ru)
|
myEUID=$(id -ru)
|
||||||
if [ "$EUID" -ne 0 ]; then
|
if [ "$myEUID" -ne 0 ]; then
|
||||||
if command -v sudo > /dev/null 2>&1; then
|
if command -v sudo > /dev/null 2>&1; then
|
||||||
command sudo "$@"
|
command sudo "$@"
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -24,8 +24,8 @@ os_arch=""
|
|||||||
[ -e /etc/os-release ] && grep -i "PRETTY_NAME" /etc/os-release | grep -qi "alpine" && os_alpine='1'
|
[ -e /etc/os-release ] && grep -i "PRETTY_NAME" /etc/os-release | grep -qi "alpine" && os_alpine='1'
|
||||||
|
|
||||||
sudo() {
|
sudo() {
|
||||||
EUID=$(id -ru)
|
myEUID=$(id -ru)
|
||||||
if [ "$EUID" -ne 0 ]; then
|
if [ "$myEUID" -ne 0 ]; then
|
||||||
if command -v sudo > /dev/null 2>&1; then
|
if command -v sudo > /dev/null 2>&1; then
|
||||||
command sudo "$@"
|
command sudo "$@"
|
||||||
else
|
else
|
||||||
|
|||||||
+14
-14
@@ -1,10 +1,10 @@
|
|||||||
package singleton
|
package singleton
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
ddns2 "github.com/naiba/nezha/pkg/ddns"
|
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
ddns2 "github.com/naiba/nezha/pkg/ddns"
|
||||||
)
|
)
|
||||||
|
|
||||||
func RetryableUpdateDomain(provider ddns2.Provider, config *ddns2.DomainConfig, maxRetries int) bool {
|
func RetryableUpdateDomain(provider ddns2.Provider, config *ddns2.DomainConfig, maxRetries int) bool {
|
||||||
@@ -25,54 +25,54 @@ func RetryableUpdateDomain(provider ddns2.Provider, config *ddns2.DomainConfig,
|
|||||||
func GetDDNSProviderFromString(provider string) (ddns2.Provider, error) {
|
func GetDDNSProviderFromString(provider string) (ddns2.Provider, error) {
|
||||||
switch provider {
|
switch provider {
|
||||||
case "webhook":
|
case "webhook":
|
||||||
return ddns2.ProviderWebHook{
|
return &ddns2.ProviderWebHook{
|
||||||
URL: Conf.DDNS.WebhookURL,
|
URL: Conf.DDNS.WebhookURL,
|
||||||
RequestMethod: Conf.DDNS.WebhookMethod,
|
RequestMethod: Conf.DDNS.WebhookMethod,
|
||||||
RequestBody: Conf.DDNS.WebhookRequestBody,
|
RequestBody: Conf.DDNS.WebhookRequestBody,
|
||||||
RequestHeader: Conf.DDNS.WebhookHeaders,
|
RequestHeader: Conf.DDNS.WebhookHeaders,
|
||||||
}, nil
|
}, nil
|
||||||
case "dummy":
|
case "dummy":
|
||||||
return ddns2.ProviderDummy{}, nil
|
return &ddns2.ProviderDummy{}, nil
|
||||||
case "cloudflare":
|
case "cloudflare":
|
||||||
return ddns2.ProviderCloudflare{
|
return &ddns2.ProviderCloudflare{
|
||||||
Secret: Conf.DDNS.AccessSecret,
|
Secret: Conf.DDNS.AccessSecret,
|
||||||
}, nil
|
}, nil
|
||||||
case "tencentcloud":
|
case "tencentcloud":
|
||||||
return ddns2.ProviderTencentCloud{
|
return &ddns2.ProviderTencentCloud{
|
||||||
SecretID: Conf.DDNS.AccessID,
|
SecretID: Conf.DDNS.AccessID,
|
||||||
SecretKey: Conf.DDNS.AccessSecret,
|
SecretKey: Conf.DDNS.AccessSecret,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
return ddns2.ProviderDummy{}, errors.New(fmt.Sprintf("无法找到配置的DDNS提供者%s", Conf.DDNS.Provider))
|
return &ddns2.ProviderDummy{}, fmt.Errorf("无法找到配置的DDNS提供者%s", Conf.DDNS.Provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetDDNSProviderFromProfile(profileName string) (ddns2.Provider, error) {
|
func GetDDNSProviderFromProfile(profileName string) (ddns2.Provider, error) {
|
||||||
profile, ok := Conf.DDNS.Profiles[profileName]
|
profile, ok := Conf.DDNS.Profiles[profileName]
|
||||||
if !ok {
|
if !ok {
|
||||||
return ddns2.ProviderDummy{}, errors.New(fmt.Sprintf("未找到配置项 %s", profileName))
|
return &ddns2.ProviderDummy{}, fmt.Errorf("未找到配置项 %s", profileName)
|
||||||
}
|
}
|
||||||
|
|
||||||
switch profile.Provider {
|
switch profile.Provider {
|
||||||
case "webhook":
|
case "webhook":
|
||||||
return ddns2.ProviderWebHook{
|
return &ddns2.ProviderWebHook{
|
||||||
URL: profile.WebhookURL,
|
URL: profile.WebhookURL,
|
||||||
RequestMethod: profile.WebhookMethod,
|
RequestMethod: profile.WebhookMethod,
|
||||||
RequestBody: profile.WebhookRequestBody,
|
RequestBody: profile.WebhookRequestBody,
|
||||||
RequestHeader: profile.WebhookHeaders,
|
RequestHeader: profile.WebhookHeaders,
|
||||||
}, nil
|
}, nil
|
||||||
case "dummy":
|
case "dummy":
|
||||||
return ddns2.ProviderDummy{}, nil
|
return &ddns2.ProviderDummy{}, nil
|
||||||
case "cloudflare":
|
case "cloudflare":
|
||||||
return ddns2.ProviderCloudflare{
|
return &ddns2.ProviderCloudflare{
|
||||||
Secret: profile.AccessSecret,
|
Secret: profile.AccessSecret,
|
||||||
}, nil
|
}, nil
|
||||||
case "tencentcloud":
|
case "tencentcloud":
|
||||||
return ddns2.ProviderTencentCloud{
|
return &ddns2.ProviderTencentCloud{
|
||||||
SecretID: profile.AccessID,
|
SecretID: profile.AccessID,
|
||||||
SecretKey: profile.AccessSecret,
|
SecretKey: profile.AccessSecret,
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
return ddns2.ProviderDummy{}, errors.New(fmt.Sprintf("无法找到配置的DDNS提供者%s", profile.Provider))
|
return &ddns2.ProviderDummy{}, fmt.Errorf("无法找到配置的DDNS提供者%s", profile.Provider)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ValidateDDNSProvidersFromProfiles() error {
|
func ValidateDDNSProvidersFromProfiles() error {
|
||||||
@@ -80,7 +80,7 @@ func ValidateDDNSProvidersFromProfiles() error {
|
|||||||
providers := make(map[string]string)
|
providers := make(map[string]string)
|
||||||
for profileName, profile := range Conf.DDNS.Profiles {
|
for profileName, profile := range Conf.DDNS.Profiles {
|
||||||
if _, ok := validProviders[profile.Provider]; !ok {
|
if _, ok := validProviders[profile.Provider]; !ok {
|
||||||
return errors.New(fmt.Sprintf("无法找到配置的DDNS提供者%s", profile.Provider))
|
return fmt.Errorf("无法找到配置的DDNS提供者%s", profile.Provider)
|
||||||
}
|
}
|
||||||
providers[profileName] = profile.Provider
|
providers[profileName] = profile.Provider
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ func RecordTransferHourlyUsage() {
|
|||||||
ServerLock.Lock()
|
ServerLock.Lock()
|
||||||
defer ServerLock.Unlock()
|
defer ServerLock.Unlock()
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
nowTrimSeconds := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, Loc)
|
nowTrimSeconds := time.Date(now.Year(), now.Month(), now.Day(), now.Hour(), 0, 0, 0, now.Location())
|
||||||
var txs []model.Transfer
|
var txs []model.Transfer
|
||||||
for id, server := range ServerList {
|
for id, server := range ServerList {
|
||||||
tx := model.Transfer{
|
tx := model.Transfer{
|
||||||
@@ -136,7 +136,7 @@ func CleanMonitorHistory() {
|
|||||||
if !rule.IsTransferDurationRule() {
|
if !rule.IsTransferDurationRule() {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
dataCouldRemoveBefore := rule.GetTransferDurationStart()
|
dataCouldRemoveBefore := rule.GetTransferDurationStart().UTC()
|
||||||
// 判断规则影响的机器范围
|
// 判断规则影响的机器范围
|
||||||
if rule.Cover == model.RuleCoverAll {
|
if rule.Cover == model.RuleCoverAll {
|
||||||
// 更新全局可以清理的数据点
|
// 更新全局可以清理的数据点
|
||||||
@@ -155,12 +155,12 @@ func CleanMonitorHistory() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
for id, couldRemove := range specialServerKeep {
|
for id, couldRemove := range specialServerKeep {
|
||||||
DB.Unscoped().Delete(&model.Transfer{}, "server_id = ? AND created_at < ?", id, couldRemove)
|
DB.Unscoped().Delete(&model.Transfer{}, "server_id = ? AND datetime(`created_at`) < datetime(?)", id, couldRemove)
|
||||||
}
|
}
|
||||||
if allServerKeep.IsZero() {
|
if allServerKeep.IsZero() {
|
||||||
DB.Unscoped().Delete(&model.Transfer{}, "server_id NOT IN (?)", specialServerIDs)
|
DB.Unscoped().Delete(&model.Transfer{}, "server_id NOT IN (?)", specialServerIDs)
|
||||||
} else {
|
} else {
|
||||||
DB.Unscoped().Delete(&model.Transfer{}, "server_id NOT IN (?) AND created_at < ?", specialServerIDs, allServerKeep)
|
DB.Unscoped().Delete(&model.Transfer{}, "server_id NOT IN (?) AND datetime(`created_at`) < datetime(?)", specialServerIDs, allServerKeep)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user