Some checks failed
SonarQube / SonarQube (push) Failing after 5m28s
E2e test on main branch push / server and client test (map[name:admin port:8080]) (push) Failing after 3m33s
Server and lib tests / Library test (js) (push) Failing after 1m36s
Server and lib tests / Library test (vue) (push) Successful in 2m24s
Server and lib tests / Web client test (admin) (push) Successful in 2m52s
Server and lib tests / Web client test (compose) (push) Successful in 3m23s
Server and lib tests / Web client test (discovery) (push) Successful in 2m49s
Server and lib tests / Web client test (one) (push) Successful in 2m52s
Server and lib tests / Web client test (privacy) (push) Successful in 2m44s
Server and lib tests / Web client test (reporter) (push) Successful in 2m56s
Server and lib tests / Web client test (workflow) (push) Successful in 3m0s
Server and lib tests / Server tests (push) Failing after 4m55s
E2e test on main branch push / notify-failure (push) Failing after 9s
Server and lib tests / Send matrix testing notification (push) Successful in 2s
Mark stale issues and pull requests / stale (push) Successful in 40s
144 lines
3.3 KiB
Go
144 lines
3.3 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/cortezaproject/corteza/server/pkg/auth"
|
|
)
|
|
|
|
const (
|
|
exportSessionTTL = time.Hour
|
|
)
|
|
|
|
type (
|
|
RecordExportSession struct {
|
|
SessionID uint64 `json:"sessionID,string"`
|
|
UserID uint64 `json:"userID,string"`
|
|
|
|
NamespaceID uint64 `json:"namespaceID,string"`
|
|
ModuleID uint64 `json:"moduleID,string"`
|
|
|
|
Filename string `json:"filename"`
|
|
Ext string `json:"ext"`
|
|
|
|
Filter string `json:"filter"`
|
|
Fields []string `json:"fields"`
|
|
Timezone string `json:"timezone"`
|
|
MultiValueDelimiter string `json:"multiValueDelimiter"`
|
|
WrapMultiValue string `json:"wrapMultiValue"`
|
|
ResolveRefs bool `json:"resolveRefs"`
|
|
IncludeRefID bool `json:"includeRefID"`
|
|
|
|
CreatedAt time.Time `json:"createdAt"`
|
|
UpdatedAt time.Time `json:"updatedAt"`
|
|
}
|
|
|
|
exportSessionSet []*RecordExportSession
|
|
|
|
exportSession struct {
|
|
l sync.Mutex
|
|
sessions exportSessionSet
|
|
}
|
|
|
|
ExportSessionService interface {
|
|
Create(ctx context.Context, s *RecordExportSession) (*RecordExportSession, error)
|
|
FindByID(ctx context.Context, sessionID uint64) (*RecordExportSession, error)
|
|
DeleteByID(ctx context.Context, sessionID uint64) error
|
|
}
|
|
)
|
|
|
|
func ExportSession() *exportSession {
|
|
svc := &exportSession{
|
|
sessions: exportSessionSet{},
|
|
}
|
|
|
|
go svc.cleanupLoop(context.Background())
|
|
|
|
return svc
|
|
}
|
|
|
|
func (svc *exportSession) indexOf(userID, sessionID uint64) int {
|
|
for i, r := range svc.sessions {
|
|
if r.SessionID == sessionID && r.UserID == userID {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
func (svc *exportSession) Create(ctx context.Context, s *RecordExportSession) (*RecordExportSession, error) {
|
|
svc.l.Lock()
|
|
defer svc.l.Unlock()
|
|
|
|
s.SessionID = nextID()
|
|
s.UserID = auth.GetIdentityFromContext(ctx).Identity()
|
|
s.CreatedAt = time.Now()
|
|
s.UpdatedAt = s.CreatedAt
|
|
|
|
svc.sessions = append(svc.sessions, s)
|
|
return s, nil
|
|
}
|
|
|
|
func (svc *exportSession) FindByID(ctx context.Context, sessionID uint64) (*RecordExportSession, error) {
|
|
svc.l.Lock()
|
|
defer svc.l.Unlock()
|
|
|
|
userID := auth.GetIdentityFromContext(ctx).Identity()
|
|
i := svc.indexOf(userID, sessionID)
|
|
if i < 0 {
|
|
return nil, fmt.Errorf("compose.service.RecordExportSessionNotFound")
|
|
}
|
|
|
|
s := svc.sessions[i]
|
|
if time.Since(s.UpdatedAt) > exportSessionTTL {
|
|
svc.sessions = removeExportSession(svc.sessions, i)
|
|
return nil, fmt.Errorf("compose.service.RecordExportSessionNotFound")
|
|
}
|
|
|
|
return s, nil
|
|
}
|
|
|
|
func (svc *exportSession) DeleteByID(ctx context.Context, sessionID uint64) error {
|
|
svc.l.Lock()
|
|
defer svc.l.Unlock()
|
|
|
|
userID := auth.GetIdentityFromContext(ctx).Identity()
|
|
i := svc.indexOf(userID, sessionID)
|
|
if i >= 0 {
|
|
svc.sessions = removeExportSession(svc.sessions, i)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func removeExportSession(s exportSessionSet, i int) exportSessionSet {
|
|
s[len(s)-1], s[i] = s[i], s[len(s)-1]
|
|
return s[:len(s)-1]
|
|
}
|
|
|
|
func (svc *exportSession) cleanupLoop(ctx context.Context) {
|
|
t := time.NewTicker(10 * time.Minute)
|
|
defer t.Stop()
|
|
for {
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-t.C:
|
|
svc.clean()
|
|
}
|
|
}
|
|
}
|
|
|
|
func (svc *exportSession) clean() {
|
|
svc.l.Lock()
|
|
defer svc.l.Unlock()
|
|
|
|
for i := len(svc.sessions) - 1; i >= 0; i-- {
|
|
if time.Since(svc.sessions[i].UpdatedAt) > exportSessionTTL {
|
|
svc.sessions = removeExportSession(svc.sessions, i)
|
|
}
|
|
}
|
|
}
|