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 }