mirror of
https://github.com/Theodor-Springmann-Stiftung/kgpz_web.git
synced 2025-10-29 17:15:31 +00:00
Some sync changes, graceful shutdwn
This commit is contained in:
@@ -3,5 +3,5 @@
|
|||||||
"git_branch": "main",
|
"git_branch": "main",
|
||||||
"webhook_endpoint": "/webhook",
|
"webhook_endpoint": "/webhook",
|
||||||
"webhook_secret": "secret",
|
"webhook_secret": "secret",
|
||||||
"debug": false
|
"debug": true
|
||||||
}
|
}
|
||||||
|
|||||||
98
kgpz_web.go
98
kgpz_web.go
@@ -3,8 +3,10 @@ package main
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
|
"os/signal"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"sync"
|
"sync"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
"githib.com/Theodor-Springmann-Stiftung/kgpz_web/helpers"
|
"githib.com/Theodor-Springmann-Stiftung/kgpz_web/helpers"
|
||||||
"githib.com/Theodor-Springmann-Stiftung/kgpz_web/providers"
|
"githib.com/Theodor-Springmann-Stiftung/kgpz_web/providers"
|
||||||
@@ -32,7 +34,6 @@ const (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type Library struct {
|
type Library struct {
|
||||||
smu sync.Mutex
|
|
||||||
Agents *providers.AgentProvider
|
Agents *providers.AgentProvider
|
||||||
Places *providers.PlaceProvider
|
Places *providers.PlaceProvider
|
||||||
Works *providers.WorkProvider
|
Works *providers.WorkProvider
|
||||||
@@ -42,6 +43,7 @@ type Library struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type KGPZ struct {
|
type KGPZ struct {
|
||||||
|
lmu sync.Mutex
|
||||||
Config *providers.ConfigProvider
|
Config *providers.ConfigProvider
|
||||||
Repo *providers.GitProvider
|
Repo *providers.GitProvider
|
||||||
Library
|
Library
|
||||||
@@ -64,6 +66,8 @@ func (k *KGPZ) IsDebug() bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (k *KGPZ) Pull() {
|
func (k *KGPZ) Pull() {
|
||||||
|
// TODO: what happens if the application quits mid-pull?
|
||||||
|
// We need to make sure to exit gracefully
|
||||||
go func(k *KGPZ) {
|
go func(k *KGPZ) {
|
||||||
if k.Repo == nil {
|
if k.Repo == nil {
|
||||||
return
|
return
|
||||||
@@ -102,63 +106,102 @@ func (k *KGPZ) InitRepo() {
|
|||||||
|
|
||||||
// This panics if the data cant be read, and there is no data read
|
// This panics if the data cant be read, and there is no data read
|
||||||
func (k *KGPZ) Serialize() {
|
func (k *KGPZ) Serialize() {
|
||||||
k.smu.Lock()
|
|
||||||
defer k.smu.Unlock()
|
|
||||||
// TODO: maybe dont panic if a webhook can be setup, we need to check the requirements only when starting the server
|
// TODO: maybe dont panic if a webhook can be setup, we need to check the requirements only when starting the server
|
||||||
// TODO: do this in parallel goroutines using a waitgroup
|
|
||||||
|
new := Library{}
|
||||||
|
|
||||||
|
wg := sync.WaitGroup{}
|
||||||
|
wg.Add(6)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
agents := k.InitAgents()
|
agents := k.InitAgents()
|
||||||
if agents == nil && k.Agents != nil {
|
if agents == nil && k.Agents != nil {
|
||||||
helpers.LogOnErr(&k.Agents, nil, "Error initializing agents, keeping old state")
|
helpers.LogOnErr(&k.Agents, nil, "Error initializing agents, keeping old state")
|
||||||
|
new.Agents = k.Agents
|
||||||
|
return
|
||||||
} else if agents == nil {
|
} else if agents == nil {
|
||||||
helpers.Panic(nil, "Error initializing agents")
|
helpers.Panic(nil, "Error initializing agents")
|
||||||
} else {
|
return
|
||||||
k.Agents = agents
|
|
||||||
}
|
}
|
||||||
|
new.Agents = agents
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
places := k.InitPlaces()
|
places := k.InitPlaces()
|
||||||
if places == nil && k.Places != nil {
|
if places == nil && k.Places != nil {
|
||||||
helpers.LogOnErr(&k.Places, nil, "Error initializing places, keeping old state")
|
helpers.LogOnErr(&k.Places, nil, "Error initializing places, keeping old state")
|
||||||
|
new.Places = k.Places
|
||||||
|
return
|
||||||
} else if places == nil {
|
} else if places == nil {
|
||||||
helpers.Panic(nil, "Error initializing places")
|
helpers.Panic(nil, "Error initializing places")
|
||||||
} else {
|
return
|
||||||
k.Places = places
|
|
||||||
}
|
}
|
||||||
|
new.Places = places
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
works := k.InitWorks()
|
works := k.InitWorks()
|
||||||
if works == nil && k.Works != nil {
|
if works == nil && k.Works != nil {
|
||||||
helpers.LogOnErr(&k.Works, nil, "Error initializing works, keeping old state")
|
helpers.LogOnErr(&k.Works, nil, "Error initializing works, keeping old state")
|
||||||
|
new.Works = k.Works
|
||||||
|
return
|
||||||
} else if works == nil {
|
} else if works == nil {
|
||||||
helpers.Panic(nil, "Error initializing works")
|
helpers.Panic(nil, "Error initializing works")
|
||||||
} else {
|
return
|
||||||
k.Works = works
|
|
||||||
}
|
}
|
||||||
|
new.Works = works
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
categories := k.InitCategories()
|
categories := k.InitCategories()
|
||||||
if categories == nil && k.Categories != nil {
|
if categories == nil && k.Categories != nil {
|
||||||
helpers.LogOnErr(&k.Categories, nil, "Error initializing categories, keeping old state")
|
helpers.LogOnErr(&k.Categories, nil, "Error initializing categories, keeping old state")
|
||||||
|
new.Categories = k.Categories
|
||||||
|
return
|
||||||
} else if categories == nil {
|
} else if categories == nil {
|
||||||
helpers.Panic(nil, "Error initializing categories")
|
helpers.Panic(nil, "Error initializing categories")
|
||||||
} else {
|
return
|
||||||
k.Categories = categories
|
|
||||||
}
|
}
|
||||||
|
new.Categories = categories
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
issues := k.InitIssues()
|
issues := k.InitIssues()
|
||||||
if issues == nil && k.Issues != nil {
|
if issues == nil && k.Issues != nil {
|
||||||
helpers.LogOnErr(&k.Issues, nil, "Error initializing issues, keeping old state")
|
helpers.LogOnErr(&k.Issues, nil, "Error initializing issues, keeping old state")
|
||||||
|
new.Issues = k.Issues
|
||||||
|
return
|
||||||
} else if issues == nil {
|
} else if issues == nil {
|
||||||
helpers.Panic(nil, "Error initializing issues")
|
helpers.Panic(nil, "Error initializing issues")
|
||||||
} else {
|
return
|
||||||
k.Issues = issues
|
|
||||||
}
|
}
|
||||||
|
new.Issues = issues
|
||||||
|
}()
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
defer wg.Done()
|
||||||
pieces := k.InitPieces()
|
pieces := k.InitPieces()
|
||||||
if pieces == nil && k.Pieces != nil {
|
if pieces == nil && k.Pieces != nil {
|
||||||
helpers.LogOnErr(&k.Pieces, nil, "Error initializing pieces, keeping old state")
|
helpers.LogOnErr(&k.Pieces, nil, "Error initializing pieces, keeping old state")
|
||||||
|
new.Pieces = k.Pieces
|
||||||
|
return
|
||||||
} else if pieces == nil {
|
} else if pieces == nil {
|
||||||
helpers.Panic(nil, "Error initializing pieces")
|
helpers.Panic(nil, "Error initializing pieces")
|
||||||
} else {
|
return
|
||||||
k.Pieces = pieces
|
|
||||||
}
|
}
|
||||||
|
new.Pieces = pieces
|
||||||
|
}()
|
||||||
|
|
||||||
|
wg.Wait()
|
||||||
|
|
||||||
|
k.lmu.Lock()
|
||||||
|
k.Library = new
|
||||||
|
k.lmu.Unlock()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (k *KGPZ) InitAgents() *providers.AgentProvider {
|
func (k *KGPZ) InitAgents() *providers.AgentProvider {
|
||||||
@@ -257,6 +300,10 @@ func (k *KGPZ) InitPieces() *providers.PieceProvider {
|
|||||||
return cp
|
return cp
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (k *KGPZ) Shutdown() {
|
||||||
|
k.Repo.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
func getXMLFiles(path string) (*[]string, error) {
|
func getXMLFiles(path string) (*[]string, error) {
|
||||||
if _, err := os.Stat(path); os.IsNotExist(err) {
|
if _, err := os.Stat(path); os.IsNotExist(err) {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -276,4 +323,23 @@ func main() {
|
|||||||
kgpz := NewKGPZ(cfg)
|
kgpz := NewKGPZ(cfg)
|
||||||
kgpz.InitRepo()
|
kgpz.InitRepo()
|
||||||
kgpz.Serialize()
|
kgpz.Serialize()
|
||||||
|
|
||||||
|
Cleanup(kgpz)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Cleanup(k *KGPZ) {
|
||||||
|
sigs := make(chan os.Signal, 1)
|
||||||
|
done := make(chan bool, 1)
|
||||||
|
|
||||||
|
signal.Notify(sigs, syscall.SIGINT, syscall.SIGTERM)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
_ = <-sigs
|
||||||
|
// INFO: here we can add a cleanup functions
|
||||||
|
k.Shutdown()
|
||||||
|
done <- true
|
||||||
|
}()
|
||||||
|
|
||||||
|
<-done
|
||||||
|
fmt.Println("Cleanup finished. Exiting.")
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ type Agent struct {
|
|||||||
SortName string `xml:"sortiername"`
|
SortName string `xml:"sortiername"`
|
||||||
Life string `xml:"lebensdaten"`
|
Life string `xml:"lebensdaten"`
|
||||||
GND string `xml:"gnd"`
|
GND string `xml:"gnd"`
|
||||||
|
Org bool `xml:"org,attr"`
|
||||||
Identifier
|
Identifier
|
||||||
AnnotationNote
|
AnnotationNote
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,25 +88,28 @@ func (g *GitProvider) Pull() (error, bool) {
|
|||||||
return err, false
|
return err, false
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := wt.Checkout(&git.CheckoutOptions{
|
|
||||||
Branch: branch,
|
|
||||||
Force: true,
|
|
||||||
}); err != nil {
|
|
||||||
return err, false
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := wt.Pull(&git.PullOptions{
|
if err := wt.Pull(&git.PullOptions{
|
||||||
RemoteName: "origin",
|
RemoteName: "origin",
|
||||||
ReferenceName: branch,
|
ReferenceName: branch,
|
||||||
Progress: os.Stdout,
|
Progress: os.Stdout,
|
||||||
}); err != nil && err != git.NoErrAlreadyUpToDate {
|
}); err != nil {
|
||||||
return err, false
|
if err == git.NoErrAlreadyUpToDate {
|
||||||
} else if err == git.NoErrAlreadyUpToDate {
|
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
return err, false
|
||||||
|
}
|
||||||
defer wt.Clean(&git.CleanOptions{Dir: true})
|
defer wt.Clean(&git.CleanOptions{Dir: true})
|
||||||
|
|
||||||
return g.setValues(repo), true
|
oldCommit := g.Commit
|
||||||
|
if err := g.setValues(repo); err != nil {
|
||||||
|
return err, false
|
||||||
|
}
|
||||||
|
|
||||||
|
if oldCommit == g.Commit {
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (g *GitProvider) Clone() error {
|
func (g *GitProvider) Clone() error {
|
||||||
@@ -233,6 +236,11 @@ func (g *GitProvider) ValidateBranch(repo *git.Repository) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (g *GitProvider) Wait() {
|
||||||
|
g.mu.Lock()
|
||||||
|
defer g.mu.Unlock()
|
||||||
|
}
|
||||||
|
|
||||||
func (g *GitProvider) ValidateCommit() error {
|
func (g *GitProvider) ValidateCommit() error {
|
||||||
if g.Commit == "" || g.Date.IsZero() {
|
if g.Commit == "" || g.Date.IsZero() {
|
||||||
return InvalidStateError
|
return InvalidStateError
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ type Piece struct {
|
|||||||
WorkRefs []WorkRef `xml:"werk"`
|
WorkRefs []WorkRef `xml:"werk"`
|
||||||
PieceRefs []PieceRef `xml:"beitrag"`
|
PieceRefs []PieceRef `xml:"beitrag"`
|
||||||
AdditionalRef []AdditionalRef `xml:"beilage"`
|
AdditionalRef []AdditionalRef `xml:"beilage"`
|
||||||
|
Datum []KGPZDate `xml:"datum"`
|
||||||
Incipit []string `xml:"incipit"`
|
Incipit []string `xml:"incipit"`
|
||||||
Title []string `xml:"titel"`
|
Title []string `xml:"titel"`
|
||||||
Identifier
|
Identifier
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ type AdditionalRef struct {
|
|||||||
Reference
|
Reference
|
||||||
Datum string `xml:"datum,attr"`
|
Datum string `xml:"datum,attr"`
|
||||||
Nr string `xml:"nr,attr"`
|
Nr string `xml:"nr,attr"`
|
||||||
|
AdditionalNo string `xml:"beilage,attr"`
|
||||||
Von string `xml:"von,attr"`
|
Von string `xml:"von,attr"`
|
||||||
Bis string `xml:"bis,attr"`
|
Bis string `xml:"bis,attr"`
|
||||||
}
|
}
|
||||||
@@ -49,6 +50,7 @@ type WorkRef struct {
|
|||||||
|
|
||||||
type PieceRef struct {
|
type PieceRef struct {
|
||||||
XMLName xml.Name `xml:"beitrag"`
|
XMLName xml.Name `xml:"beitrag"`
|
||||||
|
Page string `xml:"s,attr"`
|
||||||
Reference
|
Reference
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -20,22 +20,16 @@ type XMLProvider[T KGPZXML[T]] struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (p *XMLProvider[T]) Load() error {
|
func (p *XMLProvider[T]) Load() error {
|
||||||
var wg sync.WaitGroup
|
|
||||||
for _, path := range p.paths {
|
for _, path := range p.paths {
|
||||||
wg.Add(1)
|
|
||||||
go func(path string) {
|
|
||||||
defer wg.Done()
|
|
||||||
var data T
|
var data T
|
||||||
if err := UnmarshalFile(path, &data); err != nil {
|
if err := UnmarshalFile(path, &data); err != nil {
|
||||||
fmt.Println(err)
|
fmt.Println(err)
|
||||||
return
|
return err
|
||||||
}
|
}
|
||||||
p.mu.Lock()
|
p.mu.Lock()
|
||||||
p.Items = p.Items.Append(data)
|
p.Items = p.Items.Append(data)
|
||||||
p.mu.Unlock()
|
p.mu.Unlock()
|
||||||
}(path)
|
|
||||||
}
|
}
|
||||||
wg.Wait()
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user