commit 2ced72c94da4c9259c40353c375319d9d28a78f3 Author: 世界 Date: Tue Jul 5 12:18:20 2022 +0800 Init commit diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..85210f8 --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,37 @@ +name: Build +on: + push: + branches: + - main +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Get latest go version + id: version + run: | + echo ::set-output name=go_version::$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g') + - name: Setup Go + uses: actions/setup-go@v2 + with: + go-version: ${{ steps.version.outputs.go_version }} + - name: Build geoip + id: build + env: + NO_SKIP: true + run: go run -v . + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: geoip.db + path: geoip.db + - name: Upload artifacts + uses: actions/upload-artifact@v2 + with: + name: geoip-cn.db + path: geoip-cn.db \ No newline at end of file diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..8c949b1 --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,81 @@ +name: Release +on: + workflow_dispatch: + schedule: + - cron: "0 8 12 * *" +jobs: + build: + name: Build + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + with: + fetch-depth: 0 + - name: Get latest go version + id: version + run: | + echo ::set-output name=go_version::$(curl -s https://raw.githubusercontent.com/actions/go-versions/main/versions-manifest.json | grep -oE '"version": "[0-9]{1}.[0-9]{1,}(.[0-9]{1,})?"' | head -1 | cut -d':' -f2 | sed 's/ //g; s/"//g') + - name: Setup Go + uses: actions/setup-go@v2 + with: + go-version: ${{ steps.version.outputs.go_version }} + - name: Build geoip + id: build + run: go run -v . + - name: Generate sha256 hash + if: steps.build.outputs.skip != 'true' + run: | + sha256sum geoip.db > geoip.db.sha256sum + sha256sum geoip-cn.db > geoip-cn.db.sha256sum + - name: Create a release + if: steps.build.outputs.skip != 'true' + id: create_release + uses: actions/create-release@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ steps.build.outputs.tag }} + release_name: ${{ steps.build.outputs.tag }} + draft: false + prerelease: false + - name: Release geoip.db + if: steps.build.outputs.skip != 'true' + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./geoip.db + asset_name: geoip.db + asset_content_type: application/octet-stream + - name: Release geoip.db sha256sum + if: steps.build.outputs.skip != 'true' + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./geoip.db.sha256sum + asset_name: geoip.db.sha256sum + asset_content_type: text/plain + - name: Release geoip-cn.db + if: steps.build.outputs.skip != 'true' + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./geoip-cn.db + asset_name: geoip-cn.db + asset_content_type: application/octet-stream + - name: Release geoip.db sha256sum + if: steps.build.outputs.skip != 'true' + uses: actions/upload-release-asset@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./geoip-cn.db.sha256sum + asset_name: geoip-cn.db.sha256sum + asset_content_type: text/plain \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..be5143c --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +/.idea/ +/vendor/ +/*.db +*.mmdb \ No newline at end of file diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 0000000..948fcc4 --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,54 @@ +run: + timeout: 5m + +linters: + enable-all: true + disable: + - errcheck + - wrapcheck + - varnamelen + - stylecheck + - nonamedreturns + - nlreturn + - ireturn + - gomnd + - exhaustivestruct + - ifshort + - goerr113 + - gochecknoglobals + - forcetypeassert + - exhaustruct + - exhaustive + - cyclop + - containedctx + - wsl + - nestif + - lll + - funlen + - goconst + - godot + - gocognit + - golint + - goimports + - gochecknoinits + - maligned + - tagliatelle + - gocyclo + - maintidx + - gocritic + - nakedret + +linters-settings: + revive: + rules: + - name: var-naming + disabled: true + govet: + enable-all: true + disable: + - composites + - fieldalignment + - shadow + gosec: + excludes: + - G404 \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..3e3e29e --- /dev/null +++ b/LICENSE @@ -0,0 +1,14 @@ +Copyright (C) 2022 by nekohasekai + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . \ No newline at end of file diff --git a/format.go b/format.go new file mode 100644 index 0000000..37faa45 --- /dev/null +++ b/format.go @@ -0,0 +1,7 @@ +package main + +//go:generate go install -v mvdan.cc/gofumpt@latest +//go:generate go install -v github.com/daixiang0/gci@latest +//go:generate gofumpt -l -w . +//go:generate gofmt -s -w . +//go:generate gci write . diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..821a25d --- /dev/null +++ b/go.mod @@ -0,0 +1,21 @@ +module sing-geoip + +go 1.18 + +require ( + github.com/google/go-github/v45 v45.2.0 + github.com/maxmind/mmdbwriter v0.0.0-20220629155728-aaafab1a32b0 + github.com/oschwald/geoip2-golang v1.7.0 + github.com/oschwald/maxminddb-golang v1.9.0 + github.com/sagernet/sing v0.0.0-20220627234642-a817f7084d9c + github.com/sirupsen/logrus v1.8.1 +) + +require ( + github.com/google/go-querystring v1.1.0 // indirect + go4.org/intern v0.0.0-20220617035311-6925f38cc365 // indirect + go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 // indirect + golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 // indirect + golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c // indirect + inet.af/netaddr v0.0.0-20220617031823-097006376321 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..a5e8fd5 --- /dev/null +++ b/go.sum @@ -0,0 +1,60 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dvyukov/go-fuzz v0.0.0-20210103155950-6a8e9d1f2415/go.mod h1:11Gm+ccJnvAhCNLlf5+cS9KjtbaD5I5zaZpFMsTHWTw= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg= +github.com/google/go-github/v45 v45.2.0 h1:5oRLszbrkvxDDqBCNj2hjDZMKmvexaZ1xw/FCD+K3FI= +github.com/google/go-github/v45 v45.2.0/go.mod h1:FObaZJEDSTa/WGCzZ2Z3eoCDXWJKMenWWTrd8jrta28= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= +github.com/maxmind/mmdbwriter v0.0.0-20220629155728-aaafab1a32b0 h1:OkGyxTsNr1xGezC/A3zSgvGJbvaxfXxAy+aCEveWUSw= +github.com/maxmind/mmdbwriter v0.0.0-20220629155728-aaafab1a32b0/go.mod h1:hcQEc0iII9Rd1pIPQKWWChWewb3sk6B6kfcxXX3+Uvc= +github.com/oschwald/geoip2-golang v1.7.0 h1:JW1r5AKi+vv2ujSxjKthySK3jo8w8oKWPyXsw+Qs/S8= +github.com/oschwald/geoip2-golang v1.7.0/go.mod h1:mdI/C7iK7NVMcIDDtf4bCKMJ7r0o7UwGeCo9eiitCMQ= +github.com/oschwald/maxminddb-golang v1.9.0 h1:tIk4nv6VT9OiPyrnDAfJS1s1xKDQMZOsGojab6EjC1Y= +github.com/oschwald/maxminddb-golang v1.9.0/go.mod h1:TK+s/Z2oZq0rSl4PSeAEoP0bgm82Cp5HyvYbt8K3zLY= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/sagernet/sing v0.0.0-20220627234642-a817f7084d9c h1:98QC0wtaD648MFPw82KaT1O9LloQgR4ZyIDtNtsno8Y= +github.com/sagernet/sing v0.0.0-20220627234642-a817f7084d9c/go.mod h1:I67R/q5f67xDExL2kL3RLIP7kGJBOPkYXkpRAykgC+E= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= +go4.org/intern v0.0.0-20211027215823-ae77deb06f29/go.mod h1:cS2ma+47FKrLPdXFpr7CuxiTW3eyJbWew4qx0qtQWDA= +go4.org/intern v0.0.0-20220617035311-6925f38cc365 h1:t9hFvR102YlOqU0fQn1wgwhNvSbHGBbbJxX9JKfU3l0= +go4.org/intern v0.0.0-20220617035311-6925f38cc365/go.mod h1:WXRv3p7T6gzt0CcJm43AAKdKVZmcQbwwC7EwquU5BZU= +go4.org/unsafe/assume-no-moving-gc v0.0.0-20211027215541-db492cf91b37/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= +go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760 h1:FyBZqvoA/jbNzuAWLQE2kG820zMAkcilx6BMjGbL/E4= +go4.org/unsafe/assume-no-moving-gc v0.0.0-20220617031537-928513b29760/go.mod h1:FftLjUGFEDu5k8lt0ddY+HcrH/qU/0qk+H8j9/nTl3E= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 h1:HWj/xjIHfjYU5nVXpTM0s39J9CbLn7Cc5a7IC5rwsMQ= +golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c h1:aFV+BgZ4svzjfabn8ERpuB4JI4N6/rdy1iusx77G3oU= +golang.org/x/sys v0.0.0-20220615213510-4f61da869c0c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +inet.af/netaddr v0.0.0-20220617031823-097006376321 h1:B4dC8ySKTQXasnjDTMsoCMf1sQG4WsMej0WXaHxunmU= +inet.af/netaddr v0.0.0-20220617031823-097006376321/go.mod h1:OIezDfdzOgFhuw4HuWapWq2e9l0H9tK4F1j+ETRtF3k= diff --git a/main.go b/main.go new file mode 100644 index 0000000..3382d32 --- /dev/null +++ b/main.go @@ -0,0 +1,247 @@ +package main + +import ( + "context" + "io" + "net" + "net/http" + "os" + "sort" + "strings" + + "github.com/google/go-github/v45/github" + "github.com/maxmind/mmdbwriter" + "github.com/maxmind/mmdbwriter/inserter" + "github.com/maxmind/mmdbwriter/mmdbtype" + "github.com/oschwald/geoip2-golang" + "github.com/oschwald/maxminddb-golang" + "github.com/sagernet/sing/common" + E "github.com/sagernet/sing/common/exceptions" + "github.com/sagernet/sing/common/rw" + "github.com/sirupsen/logrus" +) + +var githubClient *github.Client + +func init() { + accessToken, loaded := os.LookupEnv("ACCESS_TOKEN") + if !loaded { + githubClient = github.NewClient(nil) + return + } + transport := &github.BasicAuthTransport{ + Username: accessToken, + } + githubClient = github.NewClient(transport.Client()) +} + +func fetch(from string) (*github.RepositoryRelease, error) { + names := strings.SplitN(from, "/", 2) + latestRelease, _, err := githubClient.Repositories.GetLatestRelease(context.Background(), names[0], names[1]) + if err != nil { + return nil, err + } + return latestRelease, err +} + +func get(downloadURL *string) ([]byte, error) { + logrus.Info("download ", *downloadURL) + response, err := http.Get(*downloadURL) + if err != nil { + return nil, err + } + defer response.Body.Close() + return io.ReadAll(response.Body) +} + +func download(release *github.RepositoryRelease) ([]byte, error) { + geoipAsset := common.Find(release.Assets, func(it *github.ReleaseAsset) bool { + return *it.Name == "Country.mmdb" + }) + if geoipAsset == nil { + return nil, E.New("Country.mmdb not found in upstream release ", release.Name) + } + return get(geoipAsset.BrowserDownloadURL) +} + +func parse(binary []byte) (metadata maxminddb.Metadata, countryMap map[string][]*net.IPNet, err error) { + database, err := maxminddb.FromBytes(binary) + if err != nil { + return + } + metadata = database.Metadata + networks := database.Networks(maxminddb.SkipAliasedNetworks) + countryMap = make(map[string][]*net.IPNet) + var country geoip2.Enterprise + var ipNet *net.IPNet + for networks.Next() { + ipNet, err = networks.Network(&country) + if err != nil { + return + } + var code string + if country.Country.IsoCode != "" { + code = strings.ToLower(country.Country.IsoCode) + } else if country.RegisteredCountry.IsoCode != "" { + code = strings.ToLower(country.RegisteredCountry.IsoCode) + } else if country.RepresentedCountry.IsoCode != "" { + code = strings.ToLower(country.RepresentedCountry.IsoCode) + } else if country.Continent.Code != "" { + code = strings.ToLower(country.Continent.Code) + } else { + continue + } + countryMap[code] = append(countryMap[code], ipNet) + } + err = networks.Err() + return +} + +func newWriter(metadata maxminddb.Metadata, codes []string) (*mmdbwriter.Tree, error) { + return mmdbwriter.New(mmdbwriter.Options{ + DatabaseType: "sing-geoip", + Languages: codes, + IPVersion: int(metadata.IPVersion), + RecordSize: int(metadata.RecordSize), + Inserter: inserter.ReplaceWith, + DisableIPv4Aliasing: true, + IncludeReservedNetworks: true, + }) +} + +func open(path string, codes []string) (*mmdbwriter.Tree, error) { + reader, err := maxminddb.Open(path) + if err != nil { + return nil, err + } + if reader.Metadata.DatabaseType != "sing-geoip" { + return nil, E.New("invalid sing-geoip database") + } + reader.Close() + + return mmdbwriter.Load(path, mmdbwriter.Options{ + Languages: append(reader.Metadata.Languages, common.Filter(codes, func(it string) bool { + return !common.Contains(reader.Metadata.Languages, it) + })...), + Inserter: inserter.ReplaceWith, + }) +} + +func write(writer *mmdbwriter.Tree, dataMap map[string][]*net.IPNet, output string, codes []string) error { + if len(codes) == 0 { + codes = make([]string, 0, len(dataMap)) + for code := range dataMap { + codes = append(codes, code) + } + } + sort.Strings(codes) + codeMap := make(map[string]bool) + for _, code := range codes { + codeMap[code] = true + } + for code, data := range dataMap { + if !codeMap[code] { + continue + } + for _, item := range data { + err := writer.Insert(item, mmdbtype.String(code)) + if err != nil { + return err + } + } + } + outputFile, err := os.Create(output) + if err != nil { + return err + } + defer outputFile.Close() + _, err = writer.WriteTo(outputFile) + return err +} + +func local(input string, output string, codes []string) error { + binary, err := os.ReadFile(input) + if err != nil { + return err + } + metadata, countryMap, err := parse(binary) + if err != nil { + return err + } + var writer *mmdbwriter.Tree + if rw.FileExists(output) { + writer, err = open(output, codes) + } else { + writer, err = newWriter(metadata, codes) + } + if err != nil { + return err + } + return write(writer, countryMap, output, codes) +} + +func release(source string, destination string) error { + sourceRelease, err := fetch(source) + if err != nil { + return err + } + destinationRelease, err := fetch(destination) + if err != nil { + logrus.Warn("missing destination latest release") + } else { + if os.Getenv("NO_SKIP") != "true" && strings.Contains(*destinationRelease.Name, *sourceRelease.Name) { + logrus.Info("already latest") + setActionOutput("skip", "true") + return nil + } + } + binary, err := download(sourceRelease) + if err != nil { + return err + } + metadata, countryMap, err := parse(binary) + if err != nil { + return err + } + allCodes := make([]string, 0, len(countryMap)) + for code := range countryMap { + allCodes = append(allCodes, code) + } + writer, err := newWriter(metadata, allCodes) + if err != nil { + return err + } + err = write(writer, countryMap, "geoip.db", nil) + if err != nil { + return err + } + writer, err = newWriter(metadata, []string{"cn"}) + if err != nil { + return err + } + err = write(writer, countryMap, "geoip-cn.db", []string{"cn"}) + if err != nil { + return err + } + if err != nil { + return err + } + setActionOutput("tag", *sourceRelease.Name) + return nil +} + +func setActionOutput(name string, content string) { + os.Stdout.WriteString("::set-output name=" + name + "::" + content + "\n") +} + +func main() { + var err error + if len(os.Args) >= 3 { + err = local(os.Args[1], os.Args[2], os.Args[2:]) + } else { + err = release("Dreamacro/maxmind-geoip", "sagernet/sing-geoip") + } + if err != nil { + logrus.Fatal(err) + } +}