mirror of
				https://github.com/TeaOSLab/EdgeNode.git
				synced 2025-11-04 16:00:25 +08:00 
			
		
		
		
	
		
			
				
	
	
		
			133 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			133 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
 | 
						||
 | 
						||
package bfs
 | 
						||
 | 
						||
import (
 | 
						||
	"encoding/json"
 | 
						||
	"github.com/TeaOSLab/EdgeNode/internal/utils"
 | 
						||
	"sort"
 | 
						||
)
 | 
						||
 | 
						||
type FileHeader struct {
 | 
						||
	Version         int         `json:"1,omitempty"`
 | 
						||
	ModifiedAt      int64       `json:"2,omitempty"`
 | 
						||
	ExpiresAt       int64       `json:"3,omitempty"`
 | 
						||
	Status          int         `json:"4,omitempty"`
 | 
						||
	HeaderSize      int64       `json:"5,omitempty"`
 | 
						||
	BodySize        int64       `json:"6,omitempty"`
 | 
						||
	ExpiredBodySize int64       `json:"7,omitempty"`
 | 
						||
	HeaderBlocks    []BlockInfo `json:"8,omitempty"`
 | 
						||
	BodyBlocks      []BlockInfo `json:"9,omitempty"`
 | 
						||
	IsCompleted     bool        `json:"10,omitempty"`
 | 
						||
	IsWriting       bool        `json:"11,omitempty"`
 | 
						||
}
 | 
						||
 | 
						||
func (this *FileHeader) BlockAt(offset int64) (blockInfo BlockInfo, ok bool) {
 | 
						||
	var l = len(this.BodyBlocks)
 | 
						||
	if l == 1 {
 | 
						||
		if this.BodyBlocks[0].Contains(offset) {
 | 
						||
			return this.BodyBlocks[0], true
 | 
						||
		}
 | 
						||
		return
 | 
						||
	}
 | 
						||
 | 
						||
	sort.Search(l, func(i int) bool {
 | 
						||
		if this.BodyBlocks[i].Contains(offset) {
 | 
						||
			blockInfo = this.BodyBlocks[i]
 | 
						||
			ok = true
 | 
						||
			return true
 | 
						||
		}
 | 
						||
		return this.BodyBlocks[i].OriginOffsetFrom > offset
 | 
						||
	})
 | 
						||
 | 
						||
	return
 | 
						||
}
 | 
						||
 | 
						||
func (this *FileHeader) MaxOffset() int64 {
 | 
						||
	var l = len(this.BodyBlocks)
 | 
						||
	if l > 0 {
 | 
						||
		return this.BodyBlocks[l-1].OriginOffsetTo
 | 
						||
	}
 | 
						||
	return 0
 | 
						||
}
 | 
						||
 | 
						||
func (this *FileHeader) Compact() {
 | 
						||
	// TODO 合并相邻的headerBlocks和bodyBlocks(必须是对应的BFile offset也要相邻)
 | 
						||
 | 
						||
	if len(this.BodyBlocks) > 0 {
 | 
						||
		sort.Slice(this.BodyBlocks, func(i, j int) bool {
 | 
						||
			var block1 = this.BodyBlocks[i]
 | 
						||
			var block2 = this.BodyBlocks[j]
 | 
						||
			if block1.OriginOffsetFrom == block1.OriginOffsetFrom {
 | 
						||
				return block1.OriginOffsetTo < block2.OriginOffsetTo
 | 
						||
			}
 | 
						||
			return block1.OriginOffsetFrom < block2.OriginOffsetFrom
 | 
						||
		})
 | 
						||
 | 
						||
		var isCompleted = true
 | 
						||
		if this.BodyBlocks[0].OriginOffsetFrom != 0 || this.BodyBlocks[len(this.BodyBlocks)-1].OriginOffsetTo != this.BodySize {
 | 
						||
			isCompleted = false
 | 
						||
		} else {
 | 
						||
			for index, block := range this.BodyBlocks {
 | 
						||
				// 是否有不连续的
 | 
						||
				if index > 0 && block.OriginOffsetFrom > this.BodyBlocks[index-1].OriginOffsetTo {
 | 
						||
					isCompleted = false
 | 
						||
					break
 | 
						||
				}
 | 
						||
			}
 | 
						||
		}
 | 
						||
		this.IsCompleted = isCompleted
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
func (this *FileHeader) Clone() *FileHeader {
 | 
						||
	return &FileHeader{
 | 
						||
		Version:         this.Version,
 | 
						||
		ModifiedAt:      this.ModifiedAt,
 | 
						||
		ExpiresAt:       this.ExpiresAt,
 | 
						||
		Status:          this.Status,
 | 
						||
		HeaderSize:      this.HeaderSize,
 | 
						||
		BodySize:        this.BodySize,
 | 
						||
		ExpiredBodySize: this.ExpiredBodySize,
 | 
						||
		HeaderBlocks:    this.HeaderBlocks,
 | 
						||
		BodyBlocks:      this.BodyBlocks,
 | 
						||
		IsCompleted:     this.IsCompleted,
 | 
						||
		IsWriting:       this.IsWriting,
 | 
						||
	}
 | 
						||
}
 | 
						||
 | 
						||
func (this *FileHeader) Encode(hash string) ([]byte, error) {
 | 
						||
	headerJSON, err := json.Marshal(this)
 | 
						||
	if err != nil {
 | 
						||
		return nil, err
 | 
						||
	}
 | 
						||
 | 
						||
	// we do not compress data which size is less than 100 bytes
 | 
						||
	if len(headerJSON) < 100 {
 | 
						||
		return EncodeMetaBlock(MetaActionNew, hash, append([]byte("json:"), headerJSON...))
 | 
						||
	}
 | 
						||
 | 
						||
	var buf = utils.SharedBufferPool.Get()
 | 
						||
	defer utils.SharedBufferPool.Put(buf)
 | 
						||
 | 
						||
	compressor, err := SharedCompressPool.Get(buf)
 | 
						||
	if err != nil {
 | 
						||
		return nil, err
 | 
						||
	}
 | 
						||
 | 
						||
	_, err = compressor.Write(headerJSON)
 | 
						||
	if err != nil {
 | 
						||
		_ = compressor.Close()
 | 
						||
		SharedCompressPool.Put(compressor)
 | 
						||
		return nil, err
 | 
						||
	}
 | 
						||
 | 
						||
	err = compressor.Close()
 | 
						||
	SharedCompressPool.Put(compressor)
 | 
						||
	if err != nil {
 | 
						||
		return nil, err
 | 
						||
	}
 | 
						||
 | 
						||
	return EncodeMetaBlock(MetaActionNew, hash, buf.Bytes())
 | 
						||
}
 |