2022-11-13 12:41:21 +00:00
|
|
|
package frameserver
|
|
|
|
|
|
|
|
import (
|
|
|
|
"git.gammaspectra.live/S.O.N.G/Ignite/frame"
|
|
|
|
"os"
|
2023-08-11 02:01:35 +00:00
|
|
|
"path"
|
2022-11-13 12:41:21 +00:00
|
|
|
"runtime"
|
|
|
|
"sync"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Pool automatically grows and shrinks as-needed based on how many frame requests come in.
|
|
|
|
type Pool struct {
|
|
|
|
cachedFrameSeekTable []int64
|
|
|
|
seekTableLock sync.RWMutex
|
|
|
|
sourcePath string
|
|
|
|
pool sync.Pool
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewPool(sourcePath string, cachedFrameSeekTable []int64) *Pool {
|
|
|
|
p := &Pool{
|
|
|
|
sourcePath: sourcePath,
|
|
|
|
cachedFrameSeekTable: cachedFrameSeekTable,
|
|
|
|
}
|
|
|
|
p.pool.New = func() any {
|
|
|
|
if f, err := os.Open(p.sourcePath); err != nil {
|
|
|
|
return nil
|
|
|
|
} else {
|
|
|
|
p.seekTableLock.RLock()
|
|
|
|
defer p.seekTableLock.RUnlock()
|
2023-08-11 02:01:35 +00:00
|
|
|
|
|
|
|
if path.Ext(p.sourcePath) == ".xz" {
|
|
|
|
if s := NewXZCompressed(f, p.cachedFrameSeekTable); s != nil {
|
|
|
|
runtime.SetFinalizer(s, func(s *FrameServer) {
|
|
|
|
f.Close()
|
|
|
|
})
|
|
|
|
return s
|
|
|
|
} else {
|
|
|
|
return nil
|
|
|
|
}
|
2022-11-13 12:41:21 +00:00
|
|
|
} else {
|
2023-08-11 02:01:35 +00:00
|
|
|
if s := New(f, p.cachedFrameSeekTable); s != nil {
|
|
|
|
runtime.SetFinalizer(s, func(s *FrameServer) {
|
|
|
|
f.Close()
|
|
|
|
})
|
|
|
|
return s
|
|
|
|
} else {
|
|
|
|
return nil
|
|
|
|
}
|
2022-11-13 12:41:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return p
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Pool) getServer() *FrameServer {
|
|
|
|
if a := p.pool.Get(); a == nil {
|
|
|
|
return nil
|
|
|
|
} else {
|
|
|
|
return a.(*FrameServer)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Pool) GetFrameSeekTable() []int64 {
|
|
|
|
p.seekTableLock.RLock()
|
|
|
|
defer p.seekTableLock.RUnlock()
|
|
|
|
return p.cachedFrameSeekTable
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Pool) putServer(s *FrameServer) {
|
|
|
|
if func() bool {
|
|
|
|
p.seekTableLock.RLock()
|
|
|
|
defer p.seekTableLock.RUnlock()
|
|
|
|
|
|
|
|
return len(p.cachedFrameSeekTable) < len(s.GetFrameSeekTable())
|
|
|
|
}() {
|
|
|
|
//cache longer table
|
|
|
|
p.seekTableLock.Lock()
|
|
|
|
defer p.seekTableLock.Unlock()
|
|
|
|
//avoid races overwriting things
|
|
|
|
if len(p.cachedFrameSeekTable) < len(s.GetFrameSeekTable()) {
|
|
|
|
p.cachedFrameSeekTable = s.GetFrameSeekTable()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
p.pool.Put(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Pool) GetAllFrames() *frame.Stream {
|
|
|
|
if s := p.getServer(); s == nil {
|
|
|
|
return nil
|
|
|
|
} else {
|
|
|
|
defer p.putServer(s)
|
|
|
|
return s.GetAllFramesLock()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *Pool) GetFrames(startFrameNumber, endFrameNumber int) *frame.Stream {
|
|
|
|
if s := p.getServer(); s == nil {
|
|
|
|
return nil
|
|
|
|
} else {
|
|
|
|
defer p.putServer(s)
|
|
|
|
return s.GetFramesLock(startFrameNumber, endFrameNumber)
|
|
|
|
}
|
|
|
|
}
|