Skip to content

Commit a97b844

Browse files
Init commit
1 parent fed35fe commit a97b844

File tree

13 files changed

+2052
-0
lines changed

13 files changed

+2052
-0
lines changed

.github/workflows/release.yml

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
name: Release
2+
on:
3+
push:
4+
tags:
5+
- 'v*.*.*'
6+
7+
jobs:
8+
release:
9+
name: Release
10+
runs-on: ubuntu-latest
11+
env:
12+
ACTIONS_ALLOW_UNSECURE_COMMANDS: true
13+
steps:
14+
- name: Check out the repo
15+
uses: actions/checkout@v2
16+
17+
- name: Set up enviroment
18+
run: echo ::set-env name=RELEASE_VERSION::${GITHUB_REF#refs/*/}
19+
20+
- name: Publish GitHub release
21+
uses: "marvinpinto/action-automatic-releases@latest"
22+
with:
23+
repo_token: "${{ secrets.GITHUB_TOKEN }}"
24+
prerelease: false

.github/workflows/test.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Tests
2+
on: push
3+
4+
permissions:
5+
contents: read
6+
7+
jobs:
8+
lint:
9+
name: lint
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/setup-go@v3
13+
with:
14+
go-version: '1.20'
15+
- uses: actions/checkout@v3
16+
- name: golangci-lint
17+
uses: golangci/golangci-lint-action@v3
18+
with:
19+
version: v1.51.2
20+
args: --timeout=4m
21+
test:
22+
runs-on: ubuntu-latest
23+
steps:
24+
- name: install Go
25+
uses: actions/setup-go@v2
26+
with:
27+
go-version: 1.20.x
28+
- name: checkout code
29+
uses: actions/checkout@v2
30+
- uses: actions/cache@v2
31+
with:
32+
path: ~/go/pkg/mod
33+
key: ${{ runner.os }}-go-${{ hashFiles('**/go.sum') }}
34+
restore-keys: |
35+
${{ runner.os }}-go-
36+
- name: golang tests
37+
env:
38+
GO111MODULE: on
39+
run: |
40+
go mod download
41+
go test ./...

.gitignore

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Binaries for programs and plugins
2+
*.exe
3+
*.exe~
4+
*.dll
5+
*.so
6+
*.dylib
7+
.env
8+
.idea
9+
.DS_Store
10+
11+
# Test binary, built with `go test -c`
12+
*.test
13+
14+
# Output of the go coverage tool, specifically when used with LiteIDE
15+
*.out
16+
17+
# Dependency directories (remove the comment below to include it)
18+
vendor/

.golangci.yml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
linters:
2+
enable:
3+
- goconst
4+
- gocritic
5+
- gofmt
6+
- govet
7+
- prealloc
8+
- unconvert
9+
- unused
10+
- errcheck
11+
- ineffassign
12+
- containedctx
13+
- tenv
14+
- musttag

Makefile

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
lint:
2+
golangci-lint run
3+
4+
test:
5+
go test ./...

data.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package main
2+
3+
// Data -
4+
type Data struct {
5+
Raw []byte
6+
Node string
7+
ResponseTime int64
8+
}
9+
10+
// Provider -
11+
type Provider struct {
12+
ID string `yaml:"id" validate:"required"`
13+
Address string `yaml:"addr" validate:"required"`
14+
}

errors.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package main
2+
3+
import "errors"
4+
5+
// Errors
6+
var (
7+
ErrInvalidURI = errors.New("invalid URI")
8+
ErrEmptyIPFSGatewayList = errors.New("empty IPFS gateway list")
9+
ErrHTTPRequest = errors.New("HTTP request error")
10+
ErrJSONDecoding = errors.New("JSON decoding error")
11+
ErrNoIPFSResponse = errors.New("can't load document from IPFS")
12+
ErrInvalidCID = errors.New("invalid CID")
13+
)

functions.go

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"math/rand"
6+
"net/url"
7+
"regexp"
8+
"strings"
9+
10+
"github.com/ipfs/go-cid"
11+
"github.com/pkg/errors"
12+
)
13+
14+
// Hash - separate IPFS hash from link
15+
func Hash(link string) (string, error) {
16+
hash := FindAllLinks([]byte(link))
17+
if len(hash) != 1 {
18+
return "", errors.Errorf("invalid IPFS link: %s", link)
19+
}
20+
_, err := cid.Decode(hash[0])
21+
return hash[0], err
22+
}
23+
24+
// Link - get gateway link
25+
func Link(gateway, hash string) string {
26+
return fmt.Sprintf("%s/ipfs/%s", gateway, hash)
27+
}
28+
29+
// Path - get path without protocol
30+
func Path(link string) string {
31+
return strings.TrimPrefix(link, "ipfs://")
32+
}
33+
34+
var ipfsURL = regexp.MustCompile(`ipfs:\/\/(?P<hash>(baf[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{56})|Qm[123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz]{44})`)
35+
36+
// FindAllLinks -
37+
func FindAllLinks(data []byte) []string {
38+
matches := ipfsURL.FindAllSubmatch(data, -1)
39+
if len(matches) == 0 {
40+
return nil
41+
}
42+
43+
res := make([]string, 0)
44+
for i := range matches {
45+
if len(matches[i]) != 2 {
46+
continue
47+
}
48+
res = append(res, string(matches[i][1]))
49+
}
50+
return res
51+
}
52+
53+
// ShuffleGateways - shuffle gateways for different request order for different files
54+
func ShuffleGateways(gateways []string) []string {
55+
if len(gateways) < 2 {
56+
return gateways
57+
}
58+
59+
shuffled := make([]string, len(gateways))
60+
copy(shuffled, gateways)
61+
rand.Shuffle(len(shuffled), func(i, j int) { shuffled[i], shuffled[j] = shuffled[j], shuffled[i] })
62+
return shuffled
63+
}
64+
65+
// Is -
66+
func Is(link string) bool {
67+
u, err := url.Parse(link)
68+
if err != nil {
69+
return false
70+
}
71+
_, err = cid.Decode(u.Host)
72+
return err == nil
73+
}

functions_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package main
2+
3+
import "testing"
4+
5+
func TestIs(t *testing.T) {
6+
tests := []struct {
7+
name string
8+
link string
9+
want bool
10+
}{
11+
{
12+
name: "ipfs://QmWYTUjkRusrhz4BCmoMKfSA8DBXk5pH2oAN83S9mABE3w",
13+
link: "ipfs://QmWYTUjkRusrhz4BCmoMKfSA8DBXk5pH2oAN83S9mABE3w",
14+
want: true,
15+
}, {
16+
name: "ipfs://zdj7WkPvrxL7VxiWbjBP5rfshPtAzXwZ77uvZhfSAoHDeb3iw/1",
17+
link: "ipfs://zdj7WkPvrxL7VxiWbjBP5rfshPtAzXwZ77uvZhfSAoHDeb3iw/1",
18+
want: true,
19+
}, {
20+
name: "ipfs://bafkreie7cvrfe6cgiat6nrffmtlf5al4fkae6hxtoy7lfebbz62v32lyvi",
21+
link: "ipfs://bafkreie7cvrfe6cgiat6nrffmtlf5al4fkae6hxtoy7lfebbz62v32lyvi",
22+
want: true,
23+
}, {
24+
name: "invalid",
25+
link: "ipfs://invalid",
26+
},
27+
}
28+
for _, tt := range tests {
29+
t.Run(tt.name, func(t *testing.T) {
30+
if got := Is(tt.link); got != tt.want {
31+
t.Errorf("Is() = %v, want %v", got, tt.want)
32+
}
33+
})
34+
}
35+
}

0 commit comments

Comments
 (0)