func (sk *SpaceKeeper) GetQuality(ctx context.Context, sid string, challenge pocutil.Hash) ([]*engine.WorkSpaceQuality, error) {
	if !sk.Started() {
		return nil, ErrSpaceKeeperIsNotRunning
	}
	if ws, ok := sk.workSpaceIndex[allState].Items()[sid]; ok && ws.using {
		return sk.getQuality(ws, challenge), nil
	}
	return nil, ErrWorkSpaceDoesNotExist
}
TODO: 1/512 plot filter
package skchia
import (
	"context"
	"path/filepath"
	"sync"
	"sync/atomic"
	"github.com/massnetorg/mass-core/logging"
	"github.com/massnetorg/mass-core/massutil/service"
	"github.com/massnetorg/mass-core/poc"
	"github.com/massnetorg/mass-core/poc/chiapos"
	"github.com/massnetorg/mass-core/poc/pocutil"
	"github.com/panjf2000/ants/v2"
	"github.com/shirou/gopsutil/disk"
	"massnet.org/mass/poc/engine.v2"
)
const (
	plotterMaxChanSize = 1024
	maxPoolWorker      = 32
	allState           = engine.LastState + 1  
)
type PoCWallet interface {
	SignMessage(pubKey *chiapos.G1Element, hash []byte) (*chiapos.G2Element, error)
	Unlock(password []byte) error
	Lock()
	IsLocked() bool
}
type SpaceKeeper struct {
	*service.BaseService
	stateLock             sync.RWMutex
	wg                    sync.WaitGroup
	quit                  chan struct{}
	configuring           int32  
	configured            int32  
	allowGenerateNewSpace bool
	dbDirs                []string
	dbType                string
	workSpaceIndex        []*WorkSpaceMap
	workSpacePaths        map[string]*WorkSpacePath
	workSpaceList         []*WorkSpace
	queue                 *plotterQueue
	newQueuedWorkSpaceCh  chan *queuedWorkSpace
	workerPool            *ants.Pool
	generateInitialIndex  func() error
	fileWatcher           func()
}
func (sk *SpaceKeeper) OnStart() error {
	sk.quit = make(chan struct{})
	go sk.spacePlotter()
	go sk.fileWatcher()
	logging.CPrint(logging.INFO, "spaceKeeper started")
	return nil
}
func (sk *SpaceKeeper) OnStop() error {
	close(sk.quit)
	sk.wg.Wait()
	logging.CPrint(logging.INFO, "spaceKeeper stopped")
	return nil
}
func (sk *SpaceKeeper) Type() string {
	return sk.Name()
}
func (sk *SpaceKeeper) WorkSpaceIDs(flags engine.WorkSpaceStateFlags) ([]string, error) {
	sk.stateLock.RLock()
	defer sk.stateLock.RUnlock()
	if flags.Contains(engine.SFAll) {
		idList := sk.workSpaceList
		result := make([]string, len(idList))
		for i := range result {
			result[i] = idList[i].id.String()
		}
		return result, nil
	}
	items := getWsByFlags(sk.workSpaceList, flags)
	result := make([]string, 0, len(items))
	for _, ws := range items {
		result = append(result, ws.id.String())
	}
	return result, nil
}
func (sk *SpaceKeeper) WorkSpaceInfos(flags engine.WorkSpaceStateFlags) ([]engine.WorkSpaceInfo, error) {
	sk.stateLock.RLock()
	defer sk.stateLock.RUnlock()
	if flags.Contains(engine.SFAll) {
		wsList := sk.workSpaceList
		result := make([]engine.WorkSpaceInfo, len(wsList))
		for i := range result {
			result[i] = wsList[i].Info()
		}
		return result, nil
	}
	items := getWsByFlags(sk.workSpaceList, flags)
	result := make([]engine.WorkSpaceInfo, 0, len(items))
	for _, ws := range items {
		result = append(result, ws.Info())
	}
	return result, nil
}