github.com/annwntech/go-micro/v2@v2.9.5/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/annwntech/go-micro/v2/client"
    13  	proto "github.com/annwntech/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  }