github.com/pslzym/go-ethereum@v1.8.17-0.20180926104442-4b6824e07b1b/cmd/swarm/swarm-smoke/upload_and_sync.go (about) 1 // Copyright 2018 The go-ethereum Authors 2 // This file is part of go-ethereum. 3 // 4 // go-ethereum is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // go-ethereum is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with go-ethereum. If not, see <http://www.gnu.org/licenses/>. 16 17 package main 18 19 import ( 20 "bytes" 21 "crypto/md5" 22 "crypto/rand" 23 "fmt" 24 "io" 25 "io/ioutil" 26 "net/http" 27 "os" 28 "os/exec" 29 "strings" 30 "sync" 31 "time" 32 33 "github.com/ethereum/go-ethereum/log" 34 "github.com/pborman/uuid" 35 36 cli "gopkg.in/urfave/cli.v1" 37 ) 38 39 func generateEndpoints(scheme string, cluster string, from int, to int) { 40 if cluster == "prod" { 41 cluster = "" 42 } else if cluster == "local" { 43 for port := from; port <= to; port++ { 44 endpoints = append(endpoints, fmt.Sprintf("%s://localhost:%v", scheme, port)) 45 } 46 return 47 } else { 48 cluster = cluster + "." 49 } 50 51 for port := from; port <= to; port++ { 52 endpoints = append(endpoints, fmt.Sprintf("%s://%v.%sswarm-gateways.net", scheme, port, cluster)) 53 } 54 55 if includeLocalhost { 56 endpoints = append(endpoints, "http://localhost:8500") 57 } 58 } 59 60 func cliUploadAndSync(c *cli.Context) error { 61 defer func(now time.Time) { log.Info("total time", "time", time.Since(now), "size (kb)", filesize) }(time.Now()) 62 63 generateEndpoints(scheme, cluster, from, to) 64 65 log.Info("uploading to " + endpoints[0] + " and syncing") 66 67 f, cleanup := generateRandomFile(filesize * 1000) 68 defer cleanup() 69 70 hash, err := upload(f, endpoints[0]) 71 if err != nil { 72 log.Error(err.Error()) 73 return err 74 } 75 76 fhash, err := digest(f) 77 if err != nil { 78 log.Error(err.Error()) 79 return err 80 } 81 82 log.Info("uploaded successfully", "hash", hash, "digest", fmt.Sprintf("%x", fhash)) 83 84 time.Sleep(3 * time.Second) 85 86 wg := sync.WaitGroup{} 87 for _, endpoint := range endpoints { 88 endpoint := endpoint 89 ruid := uuid.New()[:8] 90 wg.Add(1) 91 go func(endpoint string, ruid string) { 92 for { 93 err := fetch(hash, endpoint, fhash, ruid) 94 if err != nil { 95 continue 96 } 97 98 wg.Done() 99 return 100 } 101 }(endpoint, ruid) 102 } 103 wg.Wait() 104 log.Info("all endpoints synced random file successfully") 105 106 return nil 107 } 108 109 // fetch is getting the requested `hash` from the `endpoint` and compares it with the `original` file 110 func fetch(hash string, endpoint string, original []byte, ruid string) error { 111 log.Trace("sleeping", "ruid", ruid) 112 time.Sleep(3 * time.Second) 113 114 log.Trace("http get request", "ruid", ruid, "api", endpoint, "hash", hash) 115 res, err := http.Get(endpoint + "/bzz:/" + hash + "/") 116 if err != nil { 117 log.Warn(err.Error(), "ruid", ruid) 118 return err 119 } 120 log.Trace("http get response", "ruid", ruid, "api", endpoint, "hash", hash, "code", res.StatusCode, "len", res.ContentLength) 121 122 if res.StatusCode != 200 { 123 err := fmt.Errorf("expected status code %d, got %v", 200, res.StatusCode) 124 log.Warn(err.Error(), "ruid", ruid) 125 return err 126 } 127 128 defer res.Body.Close() 129 130 rdigest, err := digest(res.Body) 131 if err != nil { 132 log.Warn(err.Error(), "ruid", ruid) 133 return err 134 } 135 136 if !bytes.Equal(rdigest, original) { 137 err := fmt.Errorf("downloaded imported file md5=%x is not the same as the generated one=%x", rdigest, original) 138 log.Warn(err.Error(), "ruid", ruid) 139 return err 140 } 141 142 log.Trace("downloaded file matches random file", "ruid", ruid, "len", res.ContentLength) 143 144 return nil 145 } 146 147 // upload is uploading a file `f` to `endpoint` via the `swarm up` cmd 148 func upload(f *os.File, endpoint string) (string, error) { 149 var out bytes.Buffer 150 cmd := exec.Command("swarm", "--bzzapi", endpoint, "up", f.Name()) 151 cmd.Stdout = &out 152 err := cmd.Run() 153 if err != nil { 154 return "", err 155 } 156 hash := strings.TrimRight(out.String(), "\r\n") 157 return hash, nil 158 } 159 160 func digest(r io.Reader) ([]byte, error) { 161 h := md5.New() 162 _, err := io.Copy(h, r) 163 if err != nil { 164 return nil, err 165 } 166 return h.Sum(nil), nil 167 } 168 169 // generateRandomFile is creating a temporary file with the requested byte size 170 func generateRandomFile(size int) (f *os.File, teardown func()) { 171 // create a tmp file 172 tmp, err := ioutil.TempFile("", "swarm-test") 173 if err != nil { 174 panic(err) 175 } 176 177 // callback for tmp file cleanup 178 teardown = func() { 179 tmp.Close() 180 os.Remove(tmp.Name()) 181 } 182 183 buf := make([]byte, size) 184 _, err = rand.Read(buf) 185 if err != nil { 186 panic(err) 187 } 188 ioutil.WriteFile(tmp.Name(), buf, 0755) 189 190 return tmp, teardown 191 }