github.com/0chain/gosdk@v1.17.11/core/sys/util.go (about)

     1  package sys
     2  
     3  import (
     4  	"bytes"
     5  	"io"
     6  	"io/fs"
     7  	"os"
     8  	"time"
     9  
    10  	"github.com/0chain/gosdk/core/common"
    11  	"github.com/valyala/bytebufferpool"
    12  )
    13  
    14  // MemFile represents a file totally loaded in memory
    15  // Aware of the file size, so it can seek and truncate.
    16  type MemFile struct {
    17  	Name    string
    18  	Buffer  []byte      // file content
    19  	Mode    fs.FileMode // FileInfo.Mode
    20  	ModTime time.Time   // FileInfo.ModTime
    21  	Sys     interface{} // FileInfo.Sys
    22  	reader  io.Reader
    23  }
    24  
    25  // Stat returns the file information
    26  func (f *MemFile) Stat() (fs.FileInfo, error) {
    27  	return &MemFileInfo{name: f.Name, f: f}, nil
    28  }
    29  
    30  // Read reads data from the file
    31  func (f *MemFile) Read(p []byte) (int, error) {
    32  	if f.reader == nil {
    33  		f.reader = bytes.NewReader(f.Buffer)
    34  	}
    35  	return f.reader.Read(p)
    36  
    37  }
    38  
    39  // Write writes data to the file
    40  func (f *MemFile) Write(p []byte) (n int, err error) {
    41  	f.Buffer = append(f.Buffer, p...)
    42  	return len(p), nil
    43  }
    44  
    45  // WriteAt writes data to the file at a specific offset
    46  func (f *MemFile) WriteAt(p []byte, offset int64) (n int, err error) {
    47  	if offset < 0 || offset > int64(len(f.Buffer)) || len(p) > len(f.Buffer)-int(offset) {
    48  		return 0, io.ErrShortWrite
    49  	}
    50  
    51  	copy(f.Buffer[offset:], p)
    52  
    53  	return len(p), nil
    54  }
    55  
    56  // InitBuffer initializes the buffer with a specific size
    57  func (f *MemFile) InitBuffer(size int) {
    58  	buff := common.MemPool.Get()
    59  	if cap(buff.B) < size {
    60  		buff.B = make([]byte, size)
    61  	}
    62  	f.Buffer = buff.B[:size]
    63  }
    64  
    65  // Sync not implemented
    66  func (f *MemFile) Sync() error {
    67  	return nil
    68  }
    69  func (f *MemFile) Seek(offset int64, whence int) (ret int64, err error) {
    70  
    71  	if whence != io.SeekStart {
    72  		return 0, os.ErrInvalid
    73  	}
    74  	switch {
    75  	case offset < 0:
    76  		return 0, os.ErrInvalid
    77  	case offset > int64(len(f.Buffer)):
    78  		return 0, io.EOF
    79  	default:
    80  		f.reader = bytes.NewReader(f.Buffer[offset:])
    81  		return offset, nil
    82  	}
    83  }
    84  
    85  func (f *MemFile) Close() error {
    86  	f.reader = nil
    87  	return nil
    88  }
    89  
    90  // MemFileInfo represents file information
    91  type MemFileInfo struct {
    92  	name string
    93  	f    *MemFile
    94  }
    95  
    96  // Name returns the base name of the file
    97  func (i *MemFileInfo) Name() string {
    98  	return i.name
    99  }
   100  
   101  // Size returns the size of the file
   102  func (i *MemFileInfo) Size() int64 {
   103  	return int64(len(i.f.Buffer))
   104  }
   105  
   106  // Mode returns the file mode bits
   107  func (i *MemFileInfo) Mode() fs.FileMode {
   108  	return i.f.Mode
   109  }
   110  
   111  // Type returns the file mode type
   112  func (i *MemFileInfo) Type() fs.FileMode {
   113  	return i.f.Mode.Type()
   114  }
   115  
   116  // ModTime returns the modification time of the file
   117  func (i *MemFileInfo) ModTime() time.Time {
   118  	return i.f.ModTime
   119  }
   120  
   121  // IsDir returns true if the file is a directory
   122  func (i *MemFileInfo) IsDir() bool {
   123  	return i.f.Mode&fs.ModeDir != 0
   124  }
   125  
   126  // Sys returns the underlying data source (can return nil)
   127  func (i *MemFileInfo) Sys() interface{} {
   128  	return i.f.Sys
   129  }
   130  
   131  // Info returns the file information
   132  func (i *MemFileInfo) Info() (fs.FileInfo, error) {
   133  	return i, nil
   134  }
   135  
   136  // MemChanFile used to read or write file content sequentially through a buffer channel.
   137  // Not aware of the file size, so it can't seek or truncate.
   138  type MemChanFile struct {
   139  	Name           string
   140  	Buffer         chan []byte // file content
   141  	Mode           fs.FileMode // FileInfo.Mode
   142  	ModTime        time.Time   // FileInfo.ModTime
   143  	ChunkWriteSize int         //  0 value means no limit
   144  	Sys            interface{} // FileInfo.Sys
   145  	ErrChan        chan error
   146  	data           []byte
   147  }
   148  
   149  // Stat returns the file information
   150  func (f *MemChanFile) Stat() (fs.FileInfo, error) {
   151  	return &MemFileChanInfo{name: f.Name, f: f}, nil
   152  }
   153  
   154  // Read reads data from the file through the buffer channel
   155  // It returns io.EOF when the buffer channel is closed.
   156  //   - p: file in bytes loaded from the buffer channel
   157  func (f *MemChanFile) Read(p []byte) (int, error) {
   158  	select {
   159  	case err := <-f.ErrChan:
   160  		return 0, err
   161  	case recieveData, ok := <-f.Buffer:
   162  		if !ok {
   163  			return 0, io.EOF
   164  		}
   165  		if len(recieveData) > len(p) {
   166  			return 0, io.ErrShortBuffer
   167  		}
   168  		n := copy(p, recieveData)
   169  		return n, nil
   170  	}
   171  }
   172  
   173  // Write writes data to the file through the buffer channel
   174  // It writes the data to the buffer channel in chunks of ChunkWriteSize.
   175  // If ChunkWriteSize is 0, it writes the data as a whole.
   176  //   - p: file in bytes to write to the buffer channel
   177  func (f *MemChanFile) Write(p []byte) (n int, err error) {
   178  	if f.ChunkWriteSize == 0 {
   179  		data := make([]byte, len(p))
   180  		copy(data, p)
   181  		f.Buffer <- data
   182  	} else {
   183  		if cap(f.data) == 0 {
   184  			bbuf := common.MemPool.Get()
   185  			if cap(bbuf.B) < len(p) {
   186  				bbuf.B = make([]byte, 0, len(p))
   187  			}
   188  			f.data = bbuf.B
   189  		}
   190  		f.data = append(f.data, p...)
   191  	}
   192  	return len(p), nil
   193  }
   194  
   195  // Sync write the data chunk to the buffer channel
   196  // It writes the data to the buffer channel in chunks of ChunkWriteSize.
   197  // If ChunkWriteSize is 0, it writes the data as a whole.
   198  func (f *MemChanFile) Sync() error {
   199  	current := 0
   200  	for ; current < len(f.data); current += f.ChunkWriteSize {
   201  		end := current + f.ChunkWriteSize
   202  		if end > len(f.data) {
   203  			end = len(f.data)
   204  		}
   205  		f.Buffer <- f.data[current:end]
   206  	}
   207  	f.data = f.data[:0]
   208  	return nil
   209  }
   210  
   211  // Seek not implemented
   212  func (f *MemChanFile) Seek(offset int64, whence int) (ret int64, err error) {
   213  	return 0, nil
   214  }
   215  
   216  // Close closes the buffer channel
   217  func (f *MemChanFile) Close() error {
   218  	close(f.Buffer)
   219  	if cap(f.data) > 0 {
   220  		bbuf := &bytebufferpool.ByteBuffer{
   221  			B: f.data,
   222  		}
   223  		common.MemPool.Put(bbuf)
   224  	}
   225  	return nil
   226  }
   227  
   228  // MemFileChanInfo represents file information
   229  type MemFileChanInfo struct {
   230  	name string
   231  	f    *MemChanFile
   232  }
   233  
   234  // Name returns the base name of the file
   235  func (i *MemFileChanInfo) Name() string {
   236  	return i.name
   237  }
   238  
   239  // Size not implemented
   240  func (i *MemFileChanInfo) Size() int64 {
   241  	return 0
   242  }
   243  
   244  // Mode returns the file mode bits
   245  func (i *MemFileChanInfo) Mode() fs.FileMode {
   246  	return i.f.Mode
   247  }
   248  
   249  // Type returns the file mode type
   250  func (i *MemFileChanInfo) Type() fs.FileMode {
   251  	return i.f.Mode.Type()
   252  }
   253  
   254  // ModTime returns the modification time of the file
   255  func (i *MemFileChanInfo) ModTime() time.Time {
   256  	return i.f.ModTime
   257  }
   258  
   259  // IsDir returns true if the file is a directory
   260  func (i *MemFileChanInfo) IsDir() bool {
   261  	return i.f.Mode&fs.ModeDir != 0
   262  }
   263  
   264  // Sys returns the underlying data source (can return nil)
   265  func (i *MemFileChanInfo) Sys() interface{} {
   266  	return i.f.Sys
   267  }
   268  
   269  // Info returns the file information
   270  func (i *MemFileChanInfo) Info() (fs.FileInfo, error) {
   271  	return i, nil
   272  }