new release management
This commit is contained in:
@@ -75,7 +75,7 @@
|
||||
- `parseMeta()` - Metadatok feldolgozása (de `FileRepository.ReadMetaFromFile()` segítségével)
|
||||
|
||||
#### ✅ 3.2 Environment Variables - Centralizált konfiguráció
|
||||
- `GAMES_DIR` és `GAMES_DIR` továbbra is `os.Getenv()`-el hívódnak
|
||||
- `FILE_CONTAINER_PATH` és `FILE_CONTAINER_PATH` továbbra is `os.Getenv()`-el hívódnak
|
||||
- MEGLÉPÉS: Az env vars a Domain inicializációban továbbra is szétszórva vannak
|
||||
- TODO: Config struct még nem készült (de nem kritikus)
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
```
|
||||
|
||||
#### ✅ 3.6 Erőforrás nevek megtisztítása
|
||||
- `GAMES_DIR` → `GAMES_DIR` (nem "game" szó)
|
||||
- `FILE_CONTAINER_PATH` → `FILE_CONTAINER_PATH` (nem "game" szó)
|
||||
- Összes referencia frissítve
|
||||
|
||||
---
|
||||
|
||||
+1
-1
@@ -97,7 +97,7 @@ services:
|
||||
- DB_PORT=3306
|
||||
- DB_NAME=softwares
|
||||
- UPDATE_SECRET=${UPDATE_SECRET}
|
||||
- GAMES_DIR=/softwares
|
||||
- FILE_CONTAINER_PATH=/softwares
|
||||
depends_on:
|
||||
mysql:
|
||||
condition: service_healthy
|
||||
|
||||
+8
-7
@@ -5,12 +5,13 @@ import (
|
||||
)
|
||||
|
||||
type Domain struct {
|
||||
SoftwareRepository SoftwareRepositoryInterface
|
||||
ReleaseRepository ReleaseRepositoryInterface
|
||||
FileRepository FileRepositoryInterface
|
||||
DownloadService DownloadServiceInterface
|
||||
SoftwareUpdaterService SoftwareUpdaterServiceInterface
|
||||
SoftwareService SoftwareServiceInterface
|
||||
SoftwareRepository SoftwareRepositoryInterface
|
||||
ReleaseRepository ReleaseRepositoryInterface
|
||||
FileRepository FileRepositoryInterface
|
||||
DownloadService DownloadServiceInterface
|
||||
SoftwareUpdaterService SoftwareUpdaterServiceInterface
|
||||
SoftwareService SoftwareServiceInterface
|
||||
FileService FileServiceInterface
|
||||
}
|
||||
|
||||
func NewDomain() Domain {
|
||||
@@ -22,7 +23,7 @@ func NewDomain() Domain {
|
||||
fileRepository := NewFileRepository()
|
||||
|
||||
softwareService := NewSoftwareService(softwareRepository)
|
||||
|
||||
|
||||
tic80Updater := NewSoftwareUpdaterTIC80Service(
|
||||
softwareRepository,
|
||||
releaseRepository,
|
||||
|
||||
@@ -4,9 +4,9 @@ import "gorm.io/gorm"
|
||||
|
||||
type Release struct {
|
||||
gorm.Model
|
||||
SoftwareID uint `gorm:"index" json:"software_id"`
|
||||
Version string `gorm:"size:64" json:"version"`
|
||||
CartridgePath string `gorm:"size:255" json:"-"`
|
||||
SourcePath string `gorm:"size:255" json:"-"`
|
||||
WebPlayable bool `gorm:"default:false" json:"web_playable"`
|
||||
SoftwareID uint `gorm:"index" json:"software_id"`
|
||||
Version string `gorm:"size:64" json:"version"`
|
||||
CartridgePath string `gorm:"size:255" json:"-"`
|
||||
SourcePath string `gorm:"size:255" json:"-"`
|
||||
HTMLFolderPath string `gorm:"size:255" json:"-"`
|
||||
}
|
||||
|
||||
+67
-146
@@ -2,7 +2,6 @@ package domain
|
||||
|
||||
import (
|
||||
"archive/zip"
|
||||
"bufio"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
@@ -11,185 +10,107 @@ import (
|
||||
)
|
||||
|
||||
type FileRepositoryInterface interface {
|
||||
FileExists(fileName, basePath string) bool
|
||||
CreateDir(dirPath string) error
|
||||
DeleteFile(fileName, basePath string) error
|
||||
MoveFile(srcFileName, destPath, basePath string) error
|
||||
UnzipHTMLContent(zipFilePath, softwareName, version, basePath string) error
|
||||
GetSoftwareDir(softwareName, basePath string) string
|
||||
GetSoftwareVersionDir(softwareName, version, basePath string) string
|
||||
GetFileInSoftwareVersionDir(softwareName, version, fileName, basePath string) string
|
||||
GetHTMLContentDir(softwareName, version, basePath string) string
|
||||
GetCartridgePath(softwareName, version, basePath string) string
|
||||
GetSourcePath(softwareName, version, basePath string) string
|
||||
ReadMetaFromFile(filePath string, basePath string) (map[string]string, error)
|
||||
GetPath(path string) string
|
||||
FileExists(path string) bool
|
||||
CreateDir(path string) error
|
||||
DeleteFile(path string) error
|
||||
MoveFile(srcPath, destPath string) error
|
||||
UnzipFile(path, destPath string) error
|
||||
}
|
||||
|
||||
type FileRepository struct{}
|
||||
type FileRepository struct {
|
||||
fileContainerPath string
|
||||
}
|
||||
|
||||
func NewFileRepository() *FileRepository {
|
||||
return &FileRepository{}
|
||||
fileContainerPath, _ := os.LookupEnv("FILE_CONTAINER_PATH")
|
||||
return &FileRepository{
|
||||
fileContainerPath: fileContainerPath,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *FileRepository) FileExists(fileName, basePath string) bool {
|
||||
var filePath string
|
||||
if filepath.IsAbs(fileName) {
|
||||
filePath = fileName
|
||||
} else if basePath != "" {
|
||||
filePath = filepath.Join(basePath, fileName)
|
||||
} else {
|
||||
filePath = fileName // Assume it's relative to current working dir or absolute
|
||||
}
|
||||
func (fr *FileRepository) GetPath(path string) string {
|
||||
return filepath.Join(fr.fileContainerPath, path)
|
||||
}
|
||||
|
||||
_, err := os.Stat(filePath)
|
||||
func (fr *FileRepository) FileExists(path string) bool {
|
||||
fullPath := fr.GetPath(path)
|
||||
_, err := os.Stat(fullPath)
|
||||
return err == nil
|
||||
}
|
||||
|
||||
func (r *FileRepository) CreateDir(dirPath string) error {
|
||||
return os.MkdirAll(dirPath, os.ModePerm)
|
||||
func (fr *FileRepository) CreateDir(path string) error {
|
||||
fullPath := fr.GetPath(path)
|
||||
return os.MkdirAll(fullPath, 0755)
|
||||
}
|
||||
|
||||
func (r *FileRepository) DeleteFile(fileName, basePath string) error {
|
||||
var filePath string
|
||||
if filepath.IsAbs(fileName) {
|
||||
filePath = fileName
|
||||
} else if basePath != "" {
|
||||
filePath = filepath.Join(basePath, fileName)
|
||||
} else {
|
||||
filePath = fileName
|
||||
func (fr *FileRepository) DeleteFile(path string) error {
|
||||
fullPath := fr.GetPath(path)
|
||||
return os.RemoveAll(fullPath)
|
||||
}
|
||||
|
||||
func (fr *FileRepository) MoveFile(srcPath, destPath string) error {
|
||||
fullSrcPath := fr.GetPath(srcPath)
|
||||
fullDestPath := fr.GetPath(destPath)
|
||||
|
||||
destDir := filepath.Dir(fullDestPath)
|
||||
if err := os.MkdirAll(destDir, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create destination directory: %w", err)
|
||||
}
|
||||
return os.Remove(filePath)
|
||||
|
||||
return os.Rename(fullSrcPath, fullDestPath)
|
||||
}
|
||||
|
||||
func (r *FileRepository) MoveFile(srcFileName, destPath, basePath string) error {
|
||||
var srcPath string
|
||||
if filepath.IsAbs(srcFileName) {
|
||||
srcPath = srcFileName
|
||||
} else if basePath != "" {
|
||||
srcPath = filepath.Join(basePath, srcFileName)
|
||||
} else {
|
||||
srcPath = srcFileName
|
||||
}
|
||||
return os.Rename(srcPath, destPath)
|
||||
}
|
||||
func (fr *FileRepository) UnzipFile(path, destPath string) error {
|
||||
fullPath := fr.GetPath(path)
|
||||
fullDestPath := fr.GetPath(destPath)
|
||||
|
||||
func (r *FileRepository) UnzipHTMLContent(zipFilePath, softwareName, version, basePath string) error {
|
||||
destDir := r.GetHTMLContentDir(softwareName, version, basePath)
|
||||
|
||||
fmt.Printf("FileRepository: Unzipping %s to %s\n", zipFilePath, destDir)
|
||||
|
||||
reader, err := zip.OpenReader(zipFilePath)
|
||||
reader, err := zip.OpenReader(fullPath)
|
||||
if err != nil {
|
||||
return err
|
||||
return fmt.Errorf("failed to open zip file: %w", err)
|
||||
}
|
||||
defer reader.Close()
|
||||
|
||||
destDir, err = filepath.Abs(destDir)
|
||||
if err != nil {
|
||||
return err
|
||||
if err := os.MkdirAll(fullDestPath, 0755); err != nil {
|
||||
return fmt.Errorf("failed to create destination directory: %w", err)
|
||||
}
|
||||
|
||||
for _, f := range reader.File {
|
||||
fpath := filepath.Join(destDir, f.Name)
|
||||
|
||||
if !strings.HasPrefix(fpath, destDir) {
|
||||
return fmt.Errorf("%s: illegal file path", fpath)
|
||||
}
|
||||
|
||||
if f.FileInfo().IsDir() {
|
||||
os.MkdirAll(fpath, os.ModePerm)
|
||||
continue
|
||||
}
|
||||
|
||||
if err = os.MkdirAll(filepath.Dir(fpath), os.ModePerm); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
outFile, err := os.OpenFile(fpath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
||||
if err != nil {
|
||||
outFile.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
rc, err := f.Open()
|
||||
if err != nil {
|
||||
outFile.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = io.Copy(outFile, rc)
|
||||
outFile.Close()
|
||||
rc.Close()
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
for _, file := range reader.File {
|
||||
if err := extractZipFile(file, fullDestPath); err != nil {
|
||||
return fmt.Errorf("failed to extract %s: %w", file.Name, err)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *FileRepository) GetSoftwareDir(softwareName, basePath string) string {
|
||||
return filepath.Join(basePath, softwareName)
|
||||
}
|
||||
func extractZipFile(file *zip.File, destPath string) error {
|
||||
filePath := filepath.Join(destPath, file.Name)
|
||||
|
||||
func (r *FileRepository) GetSoftwareVersionDir(softwareName, version, basePath string) string {
|
||||
return filepath.Join(r.GetSoftwareDir(softwareName, basePath), version)
|
||||
}
|
||||
|
||||
func (r *FileRepository) GetFileInSoftwareVersionDir(softwareName, version, fileName, basePath string) string {
|
||||
return filepath.Join(r.GetSoftwareVersionDir(softwareName, version, basePath), fileName)
|
||||
}
|
||||
|
||||
func (r *FileRepository) GetHTMLContentDir(softwareName, version, basePath string) string {
|
||||
return filepath.Join(r.GetSoftwareVersionDir(softwareName, version, basePath), "html")
|
||||
}
|
||||
|
||||
func (r *FileRepository) GetCartridgePath(softwareName, version, basePath string) string {
|
||||
return filepath.Join(r.GetSoftwareVersionDir(softwareName, version, basePath), fmt.Sprintf("%s.tic", softwareName))
|
||||
}
|
||||
|
||||
func (r *FileRepository) GetSourcePath(softwareName, version, basePath string) string {
|
||||
return filepath.Join(r.GetSoftwareVersionDir(softwareName, version, basePath), fmt.Sprintf("%s.lua", softwareName))
|
||||
}
|
||||
|
||||
func (r *FileRepository) ReadMetaFromFile(filePath string, basePath string) (map[string]string, error) {
|
||||
var fullPath string
|
||||
if filepath.IsAbs(filePath) {
|
||||
fullPath = filePath
|
||||
} else if basePath != "" {
|
||||
fullPath = filepath.Join(basePath, filePath)
|
||||
} else {
|
||||
fullPath = filePath
|
||||
if !strings.HasPrefix(filePath, filepath.Clean(destPath)+string(os.PathSeparator)) {
|
||||
return fmt.Errorf("invalid file path: %s", file.Name)
|
||||
}
|
||||
|
||||
file, err := os.Open(fullPath)
|
||||
if file.FileInfo().IsDir() {
|
||||
return os.MkdirAll(filePath, file.Mode())
|
||||
}
|
||||
|
||||
if err := os.MkdirAll(filepath.Dir(filePath), 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
srcFile, err := file.Open()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return err
|
||||
}
|
||||
defer file.Close()
|
||||
defer srcFile.Close()
|
||||
|
||||
metaData := make(map[string]string)
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.HasPrefix(line, "--") {
|
||||
parts := strings.SplitN(strings.TrimPrefix(line, "--"), ":", 2)
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
key := strings.TrimSpace(parts[0])
|
||||
val := strings.TrimSpace(parts[1])
|
||||
metaData[strings.ToLower(key)] = val
|
||||
} else {
|
||||
break
|
||||
}
|
||||
destFile, err := os.OpenFile(filePath, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, file.Mode())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer destFile.Close()
|
||||
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return metaData, nil
|
||||
_, err = io.Copy(destFile, srcFile)
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
package domain
|
||||
|
||||
type FileServiceInterface interface {
|
||||
GetPath(path string) string
|
||||
}
|
||||
|
||||
type FileService struct {
|
||||
FileRepository FileRepositoryInterface
|
||||
}
|
||||
|
||||
func NewFileService() *FileService {
|
||||
return &FileService{
|
||||
FileRepository: NewFileRepository(),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *FileService) GetPath(path string) string {
|
||||
return s.FileRepository.GetPath(path)
|
||||
}
|
||||
@@ -1,8 +1,10 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type SoftwareUpdaterTIC80ServiceInterface interface {
|
||||
@@ -29,131 +31,86 @@ func NewSoftwareUpdaterTIC80Service(
|
||||
|
||||
func (s *SoftwareUpdaterTIC80Service) Update(name, version string) error {
|
||||
fmt.Printf("TIC80 Updater: Starting update for name: %s, version: %s\n", name, version)
|
||||
contentsPath, _ := os.LookupEnv("GAMES_DIR")
|
||||
|
||||
if err := s.handleHTMLContent(name, version, contentsPath); err == nil {
|
||||
fmt.Printf("TIC80 Updater: Successfully processed HTML content: %s\n", name)
|
||||
}
|
||||
cartridgePath := s.fileRepository.GetPath(name + "-" + version + ".tic")
|
||||
sourcePath := s.fileRepository.GetPath(name + "-" + version + ".lua")
|
||||
zipPath := s.fileRepository.GetPath(name + "-" + version + ".html.zip")
|
||||
htmlFolderPath := s.fileRepository.GetPath(name + "-" + version)
|
||||
|
||||
if err := s.handleLuaCartridge(name, version, contentsPath); err != nil {
|
||||
s.fileRepository.CreateDir(htmlFolderPath)
|
||||
s.fileRepository.UnzipFile(zipPath, htmlFolderPath)
|
||||
|
||||
var err error
|
||||
|
||||
metaData, err := s.GetMetadata(sourcePath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
software := s.BuildSoftware(metaData)
|
||||
|
||||
err = s.softwareRepository.UpdateOrCreate(software)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
release := Release{
|
||||
SoftwareID: software.ID,
|
||||
Version: version,
|
||||
CartridgePath: cartridgePath,
|
||||
SourcePath: sourcePath,
|
||||
HTMLFolderPath: htmlFolderPath,
|
||||
}
|
||||
|
||||
s.releaseRepository.Create(&release)
|
||||
|
||||
fmt.Printf("TIC80 Updater: Successfully processed Lua cartridge: %s\n", name)
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SoftwareUpdaterTIC80Service) handleHTMLContent(name, version, contentsPath string) error {
|
||||
zipFileName := fmt.Sprintf("%s.html.zip", name)
|
||||
// The zip file is now in the versioned folder
|
||||
zipFilePathInVersionDir := s.fileRepository.GetFileInSoftwareVersionDir(name, version, zipFileName, contentsPath)
|
||||
|
||||
if err := s.fileRepository.UnzipHTMLContent(zipFilePathInVersionDir, name, version, contentsPath); err != nil {
|
||||
return err
|
||||
func (s *SoftwareUpdaterTIC80Service) BuildSoftware(metadata map[string]string) *Software {
|
||||
software := &Software{
|
||||
Name: metadata["name"],
|
||||
Title: metadata["title"],
|
||||
Author: metadata["author"],
|
||||
Desc: metadata["desc"],
|
||||
Site: metadata["site"],
|
||||
License: metadata["license"],
|
||||
Platform: "tic80",
|
||||
}
|
||||
|
||||
return s.fileRepository.DeleteFile(zipFilePathInVersionDir, contentsPath)
|
||||
return software
|
||||
}
|
||||
|
||||
func (s *SoftwareUpdaterTIC80Service) handleLuaCartridge(name, version, contentsPath string) error {
|
||||
// The lua and tic files are now in the versioned folder.
|
||||
luaFileName := s.fileRepository.GetFileInSoftwareVersionDir(name, version, fmt.Sprintf("%s.lua", name), contentsPath)
|
||||
cartridgeFileName := s.fileRepository.GetFileInSoftwareVersionDir(name, version, fmt.Sprintf("%s.tic", name), contentsPath)
|
||||
func (s *SoftwareUpdaterTIC80Service) GetMetadata(sourcePath string) (map[string]string, error) {
|
||||
|
||||
|
||||
if !s.fileRepository.FileExists(luaFileName, "") { // basePath is already included in luaFileName
|
||||
return fmt.Errorf("no recognizable content file found for '%s' in '%s'", name, contentsPath)
|
||||
}
|
||||
|
||||
if !s.fileRepository.FileExists(cartridgeFileName, "") { // basePath is already included in cartridgeFileName
|
||||
return fmt.Errorf("missing cartridge file '%s' for '%s'", cartridgeFileName, luaFileName)
|
||||
}
|
||||
|
||||
software, parsedVersion, err := s.parseMeta(luaFileName, name, contentsPath)
|
||||
file, err := os.Open(sourcePath)
|
||||
if err != nil {
|
||||
return err
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
// Use the version from the webhook for consistency
|
||||
if version != parsedVersion {
|
||||
fmt.Printf("TIC80 Updater: Warning - parsed version '%s' from Lua file differs from provided version '%s'\n", parsedVersion, version)
|
||||
}
|
||||
|
||||
if version == "" {
|
||||
return fmt.Errorf("missing version info (webhook or parsed) for '%s'", luaFileName)
|
||||
}
|
||||
metaData := make(map[string]string)
|
||||
scanner := bufio.NewScanner(file)
|
||||
|
||||
if err := s.softwareRepository.UpdateOrCreate(&software); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := s.moveCartridgeFiles(name, software, version, luaFileName, cartridgeFileName, contentsPath); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
release := &Release{
|
||||
SoftwareID: software.ID,
|
||||
Version: version,
|
||||
CartridgePath: s.fileRepository.GetCartridgePath(software.Name, version, contentsPath),
|
||||
SourcePath: s.fileRepository.GetSourcePath(software.Name, version, contentsPath),
|
||||
WebPlayable: true,
|
||||
}
|
||||
|
||||
return s.releaseRepository.Create(release)
|
||||
}
|
||||
|
||||
func (s *SoftwareUpdaterTIC80Service) moveCartridgeFiles(name string, software Software, version, luaSrcPath, cartridgeSrcPath, contentsPath string) error {
|
||||
softwareVersionDir := s.fileRepository.GetSoftwareVersionDir(software.Name, version, contentsPath)
|
||||
|
||||
fmt.Printf("TIC80 Updater: Creating software version directory: %s\n", softwareVersionDir)
|
||||
if err := s.fileRepository.CreateDir(softwareVersionDir); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newCartridgePath := s.fileRepository.GetCartridgePath(software.Name, version, contentsPath)
|
||||
newSourcePath := s.fileRepository.GetSourcePath(software.Name, version, contentsPath)
|
||||
|
||||
fmt.Printf("TIC80 Updater: Moving cartridge from %s to %s\n", cartridgeSrcPath, newCartridgePath)
|
||||
if err := s.fileRepository.MoveFile(cartridgeSrcPath, newCartridgePath, ""); err != nil { // srcPath includes basePath
|
||||
return err
|
||||
}
|
||||
|
||||
fmt.Printf("TIC80 Updater: Moving Lua source from %s to %s\n", luaSrcPath, newSourcePath)
|
||||
if err := s.fileRepository.MoveFile(luaSrcPath, newSourcePath, ""); err != nil { // srcPath includes basePath
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SoftwareUpdaterTIC80Service) parseMeta(luaFileName, name, contentsPath string) (Software, string, error) {
|
||||
var software Software
|
||||
var version string
|
||||
|
||||
metaData, err := s.fileRepository.ReadMetaFromFile(luaFileName, "") // luaFileName already contains basePath
|
||||
if err != nil {
|
||||
return software, "", err
|
||||
}
|
||||
|
||||
software.Name = name
|
||||
software.Platform = "tic80"
|
||||
|
||||
for key, val := range metaData {
|
||||
switch key {
|
||||
case "title":
|
||||
software.Title = val
|
||||
case "author":
|
||||
software.Author = val
|
||||
case "desc":
|
||||
software.Desc = val
|
||||
case "site":
|
||||
software.Site = val
|
||||
case "license":
|
||||
software.License = val
|
||||
case "version":
|
||||
version = val
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
if strings.HasPrefix(line, "--") {
|
||||
parts := strings.SplitN(strings.TrimPrefix(line, "--"), ":", 2)
|
||||
if len(parts) != 2 {
|
||||
continue
|
||||
}
|
||||
key := strings.TrimSpace(parts[0])
|
||||
val := strings.TrimSpace(parts[1])
|
||||
metaData[strings.ToLower(key)] = val
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return software, version, nil
|
||||
if err := scanner.Err(); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return metaData, nil
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ func (c *DownloadController) serve(w http.ResponseWriter, r *http.Request, relea
|
||||
return
|
||||
}
|
||||
|
||||
absContentsDir, err := filepath.Abs(os.Getenv("GAMES_DIR"))
|
||||
absContentsDir, err := filepath.Abs(os.Getenv("FILE_CONTAINER_PATH"))
|
||||
if err != nil {
|
||||
http.Error(w, "Invalid contents directory path", http.StatusInternalServerError)
|
||||
return
|
||||
|
||||
+7
-99
@@ -4,7 +4,6 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"teletype_softwares/domain"
|
||||
"teletype_softwares/lib/template_utils"
|
||||
|
||||
@@ -13,59 +12,19 @@ import (
|
||||
|
||||
type PlayController struct {
|
||||
softwareService domain.SoftwareServiceInterface
|
||||
fileService domain.FileServiceInterface
|
||||
}
|
||||
|
||||
func NewPlayController(softwareService domain.SoftwareServiceInterface) *PlayController {
|
||||
func NewPlayController(softwareService domain.SoftwareServiceInterface, fileService domain.FileServiceInterface) *PlayController {
|
||||
return &PlayController{
|
||||
softwareService: softwareService,
|
||||
fileService: fileService,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *PlayController) PlayV1(w http.ResponseWriter, r *http.Request) {
|
||||
name := chi.URLParam(r, "name")
|
||||
if name == "" {
|
||||
http.Error(w, "Name not provided", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
software, err := c.softwareService.GetByNameWithReleases(name)
|
||||
if err != nil {
|
||||
if err == domain.ErrSoftwareNotFound {
|
||||
http.Error(w, "Software not found", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
var webPlayableRelease *domain.Release
|
||||
for _, release := range software.Releases {
|
||||
if release.WebPlayable {
|
||||
webPlayableRelease = &release
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if webPlayableRelease == nil {
|
||||
http.Error(w, "No web-playable version found for this software", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
http.Redirect(w, r, fmt.Sprintf("/play/%s/%s", name, webPlayableRelease.Version), http.StatusFound)
|
||||
}
|
||||
|
||||
func (c *PlayController) Play(w http.ResponseWriter, r *http.Request) {
|
||||
name := chi.URLParam(r, "name")
|
||||
if name == "" {
|
||||
http.Error(w, "Name not provided", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
version := chi.URLParam(r, "version")
|
||||
if version == "" {
|
||||
http.Error(w, "Version not provided", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
software, err := c.softwareService.GetByNameWithReleases(name)
|
||||
if err != nil {
|
||||
@@ -79,7 +38,7 @@ func (c *PlayController) Play(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
var webPlayableRelease *domain.Release
|
||||
for _, release := range software.Releases {
|
||||
if release.Version == version && release.WebPlayable {
|
||||
if release.Version == version && release.HTMLFolderPath != "" {
|
||||
webPlayableRelease = &release
|
||||
break
|
||||
}
|
||||
@@ -102,64 +61,13 @@ func (c *PlayController) Play(w http.ResponseWriter, r *http.Request) {
|
||||
})
|
||||
}
|
||||
|
||||
func (c *PlayController) ServeContentV1(w http.ResponseWriter, r *http.Request) {
|
||||
contentsPath := os.Getenv("GAMES_DIR")
|
||||
name := chi.URLParam(r, "name")
|
||||
if name == "" {
|
||||
http.Error(w, "Name not provided", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
software, err := c.softwareService.GetByNameWithReleases(name)
|
||||
if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Content for '%s' not found.", name), http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
var webPlayableRelease *domain.Release
|
||||
for _, release := range software.Releases {
|
||||
if release.WebPlayable {
|
||||
webPlayableRelease = &release
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if webPlayableRelease == nil {
|
||||
http.Error(w, "No web-playable version found for this software", http.StatusNotFound)
|
||||
return
|
||||
}
|
||||
|
||||
htmlBaseDir := filepath.Join(contentsPath, "html", name, webPlayableRelease.Version)
|
||||
|
||||
if _, err := os.Stat(htmlBaseDir); os.IsNotExist(err) {
|
||||
http.Error(w, fmt.Sprintf("Content for '%s' not found.", name), http.StatusNotFound)
|
||||
return
|
||||
} else if err != nil {
|
||||
http.Error(w, fmt.Sprintf("Error accessing content for '%s': %v", name, err), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
|
||||
fs := http.StripPrefix(fmt.Sprintf("/play/%s/content", name), http.FileServer(http.Dir(htmlBaseDir)))
|
||||
fs.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
func (c *PlayController) ServeContent(w http.ResponseWriter, r *http.Request) {
|
||||
contentsPath := os.Getenv("GAMES_DIR")
|
||||
name := chi.URLParam(r, "name")
|
||||
if name == "" {
|
||||
http.Error(w, "Name not provided", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
version := chi.URLParam(r, "version")
|
||||
if version == "" {
|
||||
http.Error(w, "Version not provided", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
htmlBaseDir := filepath.Join(contentsPath, name, version, "html")
|
||||
html_base_dir := c.fileService.GetPath(name + "-" + version)
|
||||
|
||||
if _, err := os.Stat(htmlBaseDir); os.IsNotExist(err) {
|
||||
if _, err := os.Stat(html_base_dir); os.IsNotExist(err) {
|
||||
http.Error(w, fmt.Sprintf("Content for '%s' not found.", name), http.StatusNotFound)
|
||||
return
|
||||
} else if err != nil {
|
||||
@@ -167,6 +75,6 @@ func (c *PlayController) ServeContent(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
fs := http.StripPrefix(fmt.Sprintf("/play/%s/%s/content", name, version), http.FileServer(http.Dir(htmlBaseDir)))
|
||||
fs := http.StripPrefix(fmt.Sprintf("/play/%s/%s/content", name, version), http.FileServer(http.Dir(html_base_dir)))
|
||||
fs.ServeHTTP(w, r)
|
||||
}
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ func StartHttpServer(domainInstance domain.Domain) {
|
||||
NewSoftwareController(domainInstance.SoftwareService),
|
||||
NewSoftwareUpdaterController(domainInstance.SoftwareUpdaterService),
|
||||
NewDownloadController(domainInstance.DownloadService),
|
||||
NewPlayController(domainInstance.SoftwareService),
|
||||
NewPlayController(domainInstance.SoftwareService, domainInstance.FileService),
|
||||
NewRootController(),
|
||||
).Init()
|
||||
|
||||
|
||||
+2
-3
@@ -1,8 +1,9 @@
|
||||
package http
|
||||
|
||||
import (
|
||||
"github.com/go-chi/chi/v5"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
)
|
||||
|
||||
type Router struct {
|
||||
@@ -40,8 +41,6 @@ func (r *Router) Init() *chi.Mux {
|
||||
router.Get("/download/{name}/cartridge", r.downloadController.GetLatestCartridge)
|
||||
router.Get("/download/{name}/{version}/source", r.downloadController.GetSource)
|
||||
router.Get("/download/{name}/{version}/cartridge", r.downloadController.GetCartridge)
|
||||
router.Get("/play/{name}", r.playController.PlayV1)
|
||||
router.Get("/play/{name}/content*", r.playController.ServeContentV1)
|
||||
router.Get("/play/{name}/{version}", r.playController.Play)
|
||||
router.Get("/play/{name}/{version}/content*", r.playController.ServeContent)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user