Skip to content

Commit

Permalink
feat: 增加go版本的cli,支持server及client
Browse files Browse the repository at this point in the history
  • Loading branch information
Licoy committed Jun 17, 2022
1 parent 9ba6f14 commit ae397fd
Show file tree
Hide file tree
Showing 12 changed files with 372 additions and 40 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Expand Up @@ -2,3 +2,5 @@
hosts.txt
hosts.json
index.php
index.html
output
Empty file removed .htaccess
Empty file.
38 changes: 38 additions & 0 deletions args.go
@@ -0,0 +1,38 @@
package main

import (
"errors"
"fmt"
"github.com/jessevdk/go-flags"
"os"
)

type CmdArgs struct {
Mode string `default:"client" short:"m" long:"mode" description:"启动模式(client或server)"`
FetchInterval int `default:"60" short:"i" long:"interval" description:"获取hosts的间隔时间,单位为分钟"`
Version bool `short:"v" long:"version" description:"查看当前版本"`
}

func ParseBootArgs() *CmdArgs {
args := &CmdArgs{}
_, err := flags.ParseArgs(args, os.Args)
if err != nil {
et, y := err.(*flags.Error)
if y {
if errors.Is(flags.ErrHelp, et.Type) {
os.Exit(0)
}
}
panic(fmt.Sprintf("解析参数错误: %v", err))
}
if args.Version {
fmt.Printf("版本号: V%.1f\n", VERSION)
}
if args.Mode != "client" && args.Mode != "server" {
panic(fmt.Sprintf("无效的启动模式: %s", args.Mode))
}
if args.FetchInterval < 1 {
panic(fmt.Sprintf("获取hosts的间隔时间不可以小于1分钟,当前为%d分钟", args.FetchInterval))
}
return args
}
40 changes: 40 additions & 0 deletions domains.json
@@ -0,0 +1,40 @@
[
"alive.github.com",
"live.github.com",
"github.githubassets.com",
"central.github.com",
"desktop.githubusercontent.com",
"assets-cdn.github.com",
"camo.githubusercontent.com",
"github.map.fastly.net",
"github.global.ssl.fastly.net",
"gist.github.com",
"github.io",
"github.com",
"github.blog",
"api.github.com",
"raw.githubusercontent.com",
"user-images.githubusercontent.com",
"favicons.githubusercontent.com",
"avatars5.githubusercontent.com",
"avatars4.githubusercontent.com",
"avatars3.githubusercontent.com",
"avatars2.githubusercontent.com",
"avatars1.githubusercontent.com",
"avatars0.githubusercontent.com",
"avatars.githubusercontent.com",
"codeload.github.com",
"github-cloud.s3.amazonaws.com",
"github-com.s3.amazonaws.com",
"github-production-release-asset-2e65be.s3.amazonaws.com",
"github-production-user-asset-6210df.s3.amazonaws.com",
"github-production-repository-file-5c1aeb.s3.amazonaws.com",
"githubstatus.com",
"github.hscsec.cnmunity",
"github.dev",
"collector.github.com",
"pipelines.actions.githubusercontent.com",
"media.githubusercontent.com",
"cloud.githubusercontent.com",
"objects.githubusercontent.com"
]
133 changes: 133 additions & 0 deletions fetch_hosts.go
@@ -0,0 +1,133 @@
package main

import (
"bytes"
"encoding/json"
"fmt"
"io/ioutil"
"net"
"net/http"
"os"
"regexp"
"strings"
"time"
)

const (
Windows = "windows"
Linux = "linux"
Darwin = "darwin"
HostUrl = "https://hosts.gitcdn.top/hosts.txt"
)

// ClientFetchHosts 获取最新的host并写入hosts文件
func ClientFetchHosts() (err error) {
hostsPath := GetSystemHostsPath()
hostsBytes, err := ioutil.ReadFile(hostsPath)
if err != nil {
err = ComposeError("读取文件hosts错误", err)
return
}

resp, err := http.Get(HostUrl)
if err != nil || resp.StatusCode != http.StatusOK {
err = ComposeError("获取最新的hosts失败", err)
return
}

fetchHosts, err := ioutil.ReadAll(resp.Body)
if err != nil {
err = ComposeError("读取最新的hosts失败", err)
return
}

hosts := string(hostsBytes)

mth, err := regexp.Compile(`# fetch-github-hosts begin(([\s\S])*.?)# fetch-github-hosts end`)
if err != nil {
err = ComposeError("创建内容正则匹配失败", err)
return
}
findStr := mth.FindStringSubmatch(hosts)
if len(findStr) > 0 {
hosts = strings.Replace(hosts, findStr[0], string(fetchHosts), 1)
} else {
hosts += "\n\n" + string(fetchHosts)
}

if err = ioutil.WriteFile(hostsPath, []byte(hosts), os.ModeType); err != nil {
err = ComposeError("写入hosts文件失败,请用超级管理员身份启动本程序!", err)
return
}

return
}

// ServerFetchHosts 服务端获取github最新的hosts并写入到对应文件及更新首页
func ServerFetchHosts() (err error) {
execDir := AppExecDir()
fileData, err := ioutil.ReadFile(execDir + "/domains.json")
if err != nil {
err = ComposeError("读取文件domains.json错误", err)
return
}

var domains []string
if err = json.Unmarshal(fileData, &domains); err != nil {
err = ComposeError("domain.json解析失败", err)
return
}

hostJson, hostFile, now, err := FetchHosts(domains)
if err != nil {
err = ComposeError("获取Github的Host失败", err)
return
}

if err = ioutil.WriteFile(execDir+"/hosts.json", hostJson, 0775); err != nil {
err = ComposeError("写入数据到hosts.json文件失败", err)
return
}

if err = ioutil.WriteFile(execDir+"/hosts.txt", hostFile, 0775); err != nil {
err = ComposeError("写入数据到hosts.txt文件失败", err)
return
}

var templateFile []byte
templateFile, err = ioutil.ReadFile(execDir + "/index-template.html")
if err != nil {
err = ComposeError("读取首页模板文件失败", err)
return
}

templateData := strings.Replace(string(templateFile), "<!--time-->", now, 1)
if err = ioutil.WriteFile(execDir+"/index.html", []byte(templateData), 0775); err != nil {
err = ComposeError("写入更新信息到首页文件失败", err)
return
}

return
}

func FetchHosts(domains []string) (hostsJson, hostsFile []byte, now string, err error) {
now = time.Now().Format("2006-01-02 15:04:05")
hosts := make([][]string, 0, len(domains))
hostsFileData := bytes.NewBufferString("# fetch-github-hosts begin\n")
for _, domain := range domains {
host, err := net.LookupHost(domain)
if err != nil {
fmt.Println("获取主机记录失败: ", err.Error())
continue
}
item := []string{host[0], domain}
hosts = append(hosts, item)
hostsFileData.WriteString(fmt.Sprintf("%-28s%s\n", item[0], item[1]))
}
hostsFileData.WriteString("# last fetch time: ")
hostsFileData.WriteString(now)
hostsFileData.WriteString("\n# update url: https://hosts.gitcdn.top/hosts.txt\n# fetch-github-hosts end\n\n")
hostsFile = hostsFileData.Bytes()
hostsJson, err = json.Marshal(hosts)
return
}
44 changes: 4 additions & 40 deletions fetch_hosts.php
@@ -1,44 +1,8 @@
<?php

$github_urls = ["alive.github.com",
"live.github.com",
"github.githubassets.com",
"central.github.com",
"desktop.githubusercontent.com",
"assets-cdn.github.com",
"camo.githubusercontent.com",
"github.map.fastly.net",
"github.global.ssl.fastly.net",
"gist.github.com",
"github.io",
"github.com",
"github.blog",
"api.github.com",
"raw.githubusercontent.com",
"user-images.githubusercontent.com",
"favicons.githubusercontent.com",
"avatars5.githubusercontent.com",
"avatars4.githubusercontent.com",
"avatars3.githubusercontent.com",
"avatars2.githubusercontent.com",
"avatars1.githubusercontent.com",
"avatars0.githubusercontent.com",
"avatars.githubusercontent.com",
"codeload.github.com",
"github-cloud.s3.amazonaws.com",
"github-com.s3.amazonaws.com",
"github-production-release-asset-2e65be.s3.amazonaws.com",
"github-production-user-asset-6210df.s3.amazonaws.com",
"github-production-repository-file-5c1aeb.s3.amazonaws.com",
"githubstatus.com",
"github.hscsec.cnmunity",
"github.dev",
"collector.github.com",
"pipelines.actions.githubusercontent.com",
"media.githubusercontent.com",
"cloud.githubusercontent.com",
"objects.githubusercontent.com"
];
// 此文件为旧版本通过PHP获取Github Hosts,只能运用于服务端,不建议使用!

$github_urls = file_get_contents(dirname(__FILE__).'/domains.json');

$github_hosts = [];
$hosts_content = "# fetch-github-hosts begin\n";
Expand All @@ -51,7 +15,7 @@
$hosts_content .= "# last fetch time: $utc_date\n# update url: https://hosts.gitcdn.top/hosts.txt\n# fetch-github-hosts end\n\n";

$template = file_get_contents('index-template.php');
file_put_contents('index.php', str_replace('<!--time-->', $utc_date, $template));
file_put_contents('index.html', str_replace('<!--time-->', $utc_date, $template));
file_put_contents('hosts.txt', $hosts_content);
file_put_contents('hosts.json', json_encode($github_hosts));

Expand Down
7 changes: 7 additions & 0 deletions fetch_hosts_test.go
@@ -0,0 +1,7 @@
package main

import "testing"

func TestClientFetchHosts(t *testing.T) {
ClientFetchHosts()
}
9 changes: 9 additions & 0 deletions go.mod
@@ -0,0 +1,9 @@
module github.com/Licoy/fetch-github-hosts

go 1.18

require github.com/jessevdk/go-flags v1.5.0

require (
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 // indirect
)
8 changes: 8 additions & 0 deletions go.sum
@@ -0,0 +1,8 @@
github.com/akavel/rsrc v0.10.2 h1:Zxm8V5eI1hW4gGaYsJQUhxpjkENuG91ki8B4zCrvEsw=
github.com/akavel/rsrc v0.10.2/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c=
github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc=
github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef h1:UD99BBEz19F21KhOFHLNAI6KodDWUvXaPr4Oqu8yMV8=
github.com/rwtodd/Go.Sed v0.0.0-20210816025313-55464686f9ef/go.mod h1:8AEUvGVi2uQ5b24BIhcr0GCcpd/RNAFWaN2CJFrWIIQ=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4 h1:EZ2mChiOa8udjfp6rRmswTbtZN/QzUQp4ptM4rnjHvc=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
File renamed without changes.
64 changes: 64 additions & 0 deletions main.go
@@ -0,0 +1,64 @@
package main

import (
"fmt"
"runtime"
"time"
)

func main() {
permission, err := PreCheckHasHostsRWPermission()
if err != nil {
fmt.Println("检查hosts读写权限失败", err.Error())
return
}
if !permission {
if runtime.GOOS == Windows {
fmt.Println("请鼠标右键选择【以管理员的身份运行】来执行本程序!")
} else {
fmt.Println("请以root账户或sudo来执行本程序!", err.Error())
}
return
}
args := ParseBootArgs()
ticker := time.NewTicker(time.Minute * time.Duration(args.FetchInterval))
logPrint(fmt.Sprintf("开始程序监听,当前以%d分钟更新一次Github-Hosts!", args.FetchInterval))
logPrint("请不要关闭此窗口以保持再前台运行")
logPrint("可以将此程序注册为服务,具体请参考项目说明:https://github.com/Licoy/fetch-github-hosts")
if args.Mode == "server" {
startServer(ticker)
} else {
startClient(ticker)
}
}

func startServer(ticker *time.Ticker) {
for {
select {
case <-ticker.C:
if err := ServerFetchHosts(); err != nil {
logPrint("执行更新Github-Hosts失败:" + err.Error())
} else {
logPrint("执行更新Github-Hosts成功!")
}
}
}
}

func startClient(ticker *time.Ticker) {
for {
select {
case <-ticker.C:
if err := ClientFetchHosts(); err != nil {
logPrint("更新Github-Hosts失败:" + err.Error())
} else {
logPrint("更新Github-Hosts成功!")
}
}
}
}

func logPrint(msg string) {
now := time.Now().Format("2006-01-02 15:04:05")
fmt.Printf("[%s] %s\n", now, msg)
}

0 comments on commit ae397fd

Please sign in to comment.