Compare commits

...

2 Commits

Author SHA1 Message Date
9a2e992964 lock cache during ROM move operation
All checks were successful
continuous-integration/drone/push Build is passing
2023-06-04 15:58:16 -06:00
449d48258d Add comments / documentation 2023-06-04 15:52:08 -06:00

46
main.go
View File

@ -15,13 +15,13 @@ import (
// Information for a LineageOS ROM available for download // Information for a LineageOS ROM available for download
type LineageOSROM struct { type LineageOSROM struct {
Datetime int `json:"datetime"` Datetime int `json:"datetime"` // Unix timestamp - i.e. 1685907926
Filename string `json:"filename"` Filename string `json:"filename"` // .zip filename - i.e. lineage-20.0-20230604-UNOFFICIAL-sunfish.zip
ID string `json:"id"` ID string `json:"id"` // A unique identifier such as a SHA256 hash of the .zip - i.e. 603bfc02e403e5fd1bf9ed74383f1d6c9ec7fb228d03c4b37753033d79488e93
Romtype string `json:"romtype"` Romtype string `json:"romtype"` // i.e. nightly
Size int `json:"size"` Size int `json:"size"` // size of .zip file in bytes
URL string `json:"url"` URL string `json:"url"` // public URL where client could download the .zip file
Version string `json:"version"` Version string `json:"version"` // LineageOS version - i.e. 20.0
} }
// The HTTP response JSON should be a JSON array of lineageOSROMS available for download // The HTTP response JSON should be a JSON array of lineageOSROMS available for download
@ -29,26 +29,27 @@ type HTTPResponseJSON struct {
Response []LineageOSROM `json:"response"` Response []LineageOSROM `json:"response"`
} }
// Caches data about available ROMs in memory so we don't need to reference the filesystem for each request
type ROMCache struct { type ROMCache struct {
ROMs []LineageOSROM ROMs []LineageOSROM
Cached map[string]bool // to quickly lookup if a file is already cached Cached map[string]bool // to quickly lookup if a file is already cached
sync.Mutex sync.Mutex // We have multiple goroutines that may be accessing this data simultaneously, so we much lock / unlock it to prevent race conditions
} }
var ( var ( // evil global variable
romCache ROMCache romCache ROMCache
) )
// Preload cached list of files and hashes
func init() { func init() {
romCache = ROMCache{} romCache = ROMCache{}
romCache.Cached = make(map[string]bool) romCache.Cached = make(map[string]bool)
// Check if any new build artifacts and preload the romCache
moveBuildArtifacts("out", "public") moveBuildArtifacts("out", "public")
go updateROMCache("public") go updateROMCache("public")
} }
// HTTP Routing // HTTP Server
func main() { func main() {
//Public static files //Public static files
@ -59,7 +60,6 @@ func main() {
log.Print("Service listening on :8080") log.Print("Service listening on :8080")
log.Fatal(http.ListenAndServe(":8080", nil)) log.Fatal(http.ListenAndServe(":8080", nil))
} }
// Reads the ROM files on the filesystem and populates a slice of linageOSROMs // Reads the ROM files on the filesystem and populates a slice of linageOSROMs
@ -153,7 +153,9 @@ func moveBuildArtifacts(outDirectory, romDirectory string) bool {
newROMs = true newROMs = true
log.Printf("new build found - moving file %s", v.Name()) log.Printf("new build found - moving file %s", v.Name())
romCache.Lock() // lock to prevent multiple concurrent goroutines moving the same file
err := moveBuildFile(fmt.Sprintf("%s/%s", outDirectory, v.Name()), fmt.Sprintf("%s/%s", romDirectory, v.Name())) err := moveBuildFile(fmt.Sprintf("%s/%s", outDirectory, v.Name()), fmt.Sprintf("%s/%s", romDirectory, v.Name()))
romCache.Unlock()
if err != nil { if err != nil {
log.Printf("failed to move file '%s' from out to rom directory: %v", v.Name(), err) log.Printf("failed to move file '%s' from out to rom directory: %v", v.Name(), err)
continue continue
@ -182,11 +184,16 @@ func isLineageROMZip(v fs.DirEntry) (bool, []string) {
// http - GET / // http - GET /
// Writes JSON response for the updater app to know what versions are available to download // Writes JSON response for the updater app to know what versions are available to download
func lineageOSROMListHandler(w http.ResponseWriter, r *http.Request) { func lineageOSROMListHandler(w http.ResponseWriter, r *http.Request) {
romCache.Lock() go func() {
lineageOSROMs := romCache.ROMs newBuilds := moveBuildArtifacts("out", "public")
romCache.Unlock() if newBuilds {
updateROMCache("public")
}
}()
httpResponseJSON := &HTTPResponseJSON{Response: lineageOSROMs} romCache.Lock()
httpResponseJSON := &HTTPResponseJSON{Response: romCache.ROMs}
romCache.Unlock()
b, err := json.Marshal(httpResponseJSON) b, err := json.Marshal(httpResponseJSON)
if err != nil { if err != nil {
@ -196,13 +203,6 @@ func lineageOSROMListHandler(w http.ResponseWriter, r *http.Request) {
} }
w.Write(b) w.Write(b)
go func() {
newBuilds := moveBuildArtifacts("out", "public")
if newBuilds {
updateROMCache("public")
}
}()
} }
// Returns a sha256 hash of a file located at the path provided // Returns a sha256 hash of a file located at the path provided