github.com/micro/go-micro/v2@v2.9.1/util/file/client.go (about) 1 package file 2 3 import ( 4 "bufio" 5 "context" 6 "errors" 7 "fmt" 8 "io" 9 "log" 10 "os" 11 12 "github.com/micro/go-micro/v2/client" 13 proto "github.com/micro/go-micro/v2/util/file/proto" 14 ) 15 16 // Client is the client interface to access files 17 type File interface { 18 Open(filename string, truncate bool) (int64, error) 19 Stat(filename string) (*proto.StatResponse, error) 20 GetBlock(sessionId, blockId int64) ([]byte, error) 21 ReadAt(sessionId, offset, size int64) ([]byte, error) 22 Read(sessionId int64, buf []byte) (int, error) 23 Write(sessionId, offset int64, data []byte) error 24 Close(sessionId int64) error 25 Download(filename, saveFile string) error 26 Upload(filename, localFile string) error 27 DownloadAt(filename, saveFile string, blockId int) error 28 } 29 30 // NewClient returns a new Client which uses a micro Client 31 func New(service string, c client.Client) File { 32 return &fc{proto.NewFileService(service, c)} 33 } 34 35 const ( 36 blockSize = 512 * 1024 37 ) 38 39 type fc struct { 40 c proto.FileService 41 } 42 43 func (c *fc) Open(filename string, truncate bool) (int64, error) { 44 rsp, err := c.c.Open(context.TODO(), &proto.OpenRequest{ 45 Filename: filename, 46 Truncate: truncate, 47 }) 48 if err != nil { 49 return 0, err 50 } 51 return rsp.Id, nil 52 } 53 54 func (c *fc) Stat(filename string) (*proto.StatResponse, error) { 55 return c.c.Stat(context.TODO(), &proto.StatRequest{Filename: filename}) 56 } 57 58 func (c *fc) GetBlock(sessionId, blockId int64) ([]byte, error) { 59 return c.ReadAt(sessionId, blockId*blockSize, blockSize) 60 } 61 62 func (c *fc) ReadAt(sessionId, offset, size int64) ([]byte, error) { 63 rsp, err := c.c.Read(context.TODO(), &proto.ReadRequest{Id: sessionId, Size: size, Offset: offset}) 64 if err != nil { 65 return nil, err 66 } 67 68 if rsp.Eof { 69 err = io.EOF 70 } 71 72 if rsp.Data == nil { 73 rsp.Data = make([]byte, size) 74 } 75 76 if size != rsp.Size { 77 return rsp.Data[:rsp.Size], err 78 } 79 80 return rsp.Data, nil 81 } 82 83 func (c *fc) Read(sessionId int64, buf []byte) (int, error) { 84 b, err := c.ReadAt(sessionId, 0, int64(cap(buf))) 85 if err != nil { 86 return 0, err 87 } 88 copy(buf, b) 89 return len(b), nil 90 } 91 92 func (c *fc) Write(sessionId, offset int64, data []byte) error { 93 _, err := c.c.Write(context.TODO(), &proto.WriteRequest{ 94 Id: sessionId, 95 Offset: offset, 96 Data: data}) 97 return err 98 } 99 100 func (c *fc) Close(sessionId int64) error { 101 _, err := c.c.Close(context.TODO(), &proto.CloseRequest{Id: sessionId}) 102 return err 103 } 104 105 func (c *fc) Download(filename, saveFile string) error { 106 return c.DownloadAt(filename, saveFile, 0) 107 } 108 109 func (c *fc) Upload(filename, localFile string) error { 110 file, err := os.Open(localFile) 111 if err != nil { 112 return err 113 } 114 defer file.Close() 115 116 offset := 0 117 sessionId, err := c.Open(filename, true) 118 defer c.Close(sessionId) 119 if err != nil { 120 return err 121 } 122 reader := bufio.NewReader(file) 123 part := make([]byte, blockSize) 124 125 for { 126 count, err := reader.Read(part) 127 if err != nil { 128 break 129 } 130 err = c.Write(sessionId, int64(offset), part) 131 if err != nil { 132 return err 133 } 134 offset += count 135 } 136 if err != nil && err != io.EOF { 137 return fmt.Errorf("Error reading %v: %v", localFile, err) 138 } 139 return nil 140 } 141 142 func (c *fc) DownloadAt(filename, saveFile string, blockId int) error { 143 stat, err := c.Stat(filename) 144 if err != nil { 145 return err 146 } 147 if stat.Type == "Directory" { 148 return errors.New(fmt.Sprintf("%s is directory.", filename)) 149 } 150 151 blocks := int(stat.Size / blockSize) 152 if stat.Size%blockSize != 0 { 153 blocks += 1 154 } 155 156 log.Printf("Download %s in %d blocks\n", filename, blocks-blockId) 157 158 file, err := os.OpenFile(saveFile, os.O_CREATE|os.O_WRONLY, 0666) 159 if err != nil { 160 return err 161 } 162 defer file.Close() 163 164 sessionId, err := c.Open(filename, false) 165 if err != nil { 166 return err 167 } 168 169 for i := blockId; i < blocks; i++ { 170 buf, rerr := c.GetBlock(sessionId, int64(i)) 171 if rerr != nil && rerr != io.EOF { 172 return rerr 173 } 174 if _, werr := file.WriteAt(buf, int64(i)*blockSize); werr != nil { 175 return werr 176 } 177 178 if i%((blocks-blockId)/100+1) == 0 { 179 log.Printf("Downloading %s [%d/%d] blocks", filename, i-blockId+1, blocks-blockId) 180 } 181 182 if rerr == io.EOF { 183 break 184 } 185 } 186 log.Printf("Download %s completed", filename) 187 188 c.Close(sessionId) 189 190 return nil 191 }