diff --git a/.addonsconfig.json b/.addonsconfig.json
new file mode 100644
index 0000000..5ef49bc
--- /dev/null
+++ b/.addonsconfig.json
@@ -0,0 +1,8 @@
+[
+ {
+ "name": "little-wigs",
+ "filename": "littlewigs",
+ "url": "https://www.curseforge.com/wow/addons/little-wigs",
+ "download_url": "https://www.curseforge.com/wow/addons/little-wigs/download/5693335"
+ }
+]
\ No newline at end of file
diff --git a/.systemsconfig.json b/.systemsconfig.json
new file mode 100644
index 0000000..c0b5ec8
--- /dev/null
+++ b/.systemsconfig.json
@@ -0,0 +1,10 @@
+[
+ {
+ "name": "extract.addon.path",
+ "path": "/home/miso/Games/battlenet/drive_c/Program Files (x86)/World of Warcraft/_retail_/Interface/AddOns"
+ },
+ {
+ "name": "browser.download.dir",
+ "path": "/home/miso/Downloads/goaddons_download"
+ }
+]
diff --git a/FUTURE.md b/FUTURE.md
index 7e6589d..cf61bc6 100644
--- a/FUTURE.md
+++ b/FUTURE.md
@@ -1,13 +1,10 @@
# Future plans for GoAddons
-## Tests
-1. Some tests
-2. aaaand some more test
-3. and after that even more tests
-
-## Make Docker dependency deprecated
-1. Change from MySQL to a simple SQLite database that makes it easier to ship instead of requiring Docker.
-2. Look into possibility of not requiring the Docker Chrome browser when downloading files.
+## Fix the updater
+1. For some reason the downloaded files are owned by ROOT:ROOT. This is not OK, they should be owned by current OS user (perhaps configurable?)
+2. Make it non-parallel - there is no need for concurrency, there is risk for website throttling/blocking us plus extracting is fast enough as is
+3. Make the extracting more simple - anything in the download volume that ends with .zip should be extracted and ultimately removed
+4. Look into possibility of not requiring the Docker Chrome browser when downloading files - the fewer dependencies the better
## Refactoring and generic clean-up
@@ -15,3 +12,12 @@
*. Discuss the possibility of using formatters e.g. gofmt or perhaps Go linters?
2. Refactoring and making code easier to read and follow (the less jumping around the better)
3. Generic Clean-up and whatever that would entail!
+
+## Config
+
+1. Allow more configurations - perhaps look into some config lib that can help
+2. Look into possibly leaving JSON for the config and instead use YAML
+
+## Cli
+
+1. Leave behind the current and basic CLI and look into uses something like ncurses or alternatives for it in Golang
diff --git a/README.md b/README.md
index d5ab65e..3d76d3f 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,11 @@
# GoAddons
-GoAddons is a command-line interface (CLI) application designed to enhance the World of Warcraft (WoW) experience by simplifying the management of game addons. Leveraging the power of a database, GoAddons facilitates the effortless discovery, update, and management of WoW addons.
+GoAddons is a command-line interface (CLI) application designed to enhance the World of Warcraft (WoW) experience by simplifying the management of game addons. GoAddons facilitates the effortless update and management of WoW addons.
## Features
- **Addon Management**: Easily list, search, add, or remove WoW addons to customize your gaming setup.
-- **Updater Menu**: ~~Automatically checks and~~ updates your addons to the latest versions, ensuring you have the latest features and fixes.
+- **Updater Menu**: Updates your addons to the latest versions, ensuring you have the latest features and fixes.
- **About**: Learn more about GoAddons.
## Getting Started
@@ -22,7 +22,7 @@ cd GoAddons
2. **Docker containers**:
Make sure you have Docker/Docker-engine and Docker-compose installed on your system. You will need to edit the docker-compose.yml file to fit your system.
-The "kaasufouji-extract-volume" device path needs to be your systems path to your addons directory. Finally, change any [YOUR_HOST_NAME_HERE] to your actual user's name.
+The "goaddons-extract-volume" device path needs to be your systems path to your addons directory. Finally, change any [YOUR_HOST_NAME_HERE] to your actual user's name.
Now, run the following command:
@@ -86,7 +86,7 @@ In the Addon Management menu, you can:
### Updater Menu
-Start the updater ~~to check for~~ and apply updates to your addons.
+Start the updater and apply updates to your addons.
### About
diff --git a/cli/AddonManagement.go b/cmp/cli/AddonManagement.go
similarity index 60%
rename from cli/AddonManagement.go
rename to cmp/cli/AddonManagement.go
index f51bf1e..9c51ad4 100644
--- a/cli/AddonManagement.go
+++ b/cmp/cli/AddonManagement.go
@@ -16,36 +16,22 @@ package cli
import (
"encoding/json"
"fmt"
- "goaddons/database"
- "goaddons/models"
- "goaddons/utils"
+ "goaddons/cmp/models"
+ "goaddons/cmp/utils"
+ "goaddons/cmp/vault"
"log"
- "strconv"
)
func ListAllAddons() {
utils.ClearScreen()
fmt.Printf(" »»» All Addons «««\n\n")
- addons, err := database.GetAllAddons(db)
+ addonsVault, err := vault.GetInstance()
if err != nil {
- log.Printf("cli.ListAllAddons :: Error while trying to get all addons -> %v\n", err)
- return
- }
-
- if addons == nil || len(addons) == 0 {
- return
- }
-
- b, err := json.MarshalIndent(addons, "", " ")
- if err != nil {
- log.Printf("cli.ListAllAddons :: Failed to marshal -> %v\n", err)
- return
+ log.Fatalf("Error initializing AddonVault: %v", err)
}
- if b != nil && utils.IsValidString(string(b)) {
- fmt.Println(string(b))
- }
+ addonsVault.Print()
}
func SearchForAddonByName() {
@@ -60,24 +46,25 @@ func SearchForAddonByName() {
}
// Search for and list addon, all by the argument 'name'
- addons, err := database.GetAddonsByName(db, name)
+ addonsVault, err := vault.GetInstance()
if err != nil {
- log.Printf("cli.SearchForAddonByName :: Error while getting addon... -> %v\n", err)
- return
+ log.Fatalf("Was unable to get instance of AddonVault")
}
-
- if addons == nil || len(addons) == 0 {
+ if addonsVault.Length() == 0 {
return
}
- b, err := json.MarshalIndent(addons, "", " ")
- if err != nil {
- log.Printf("cli.SearchForAddonByName :: Failed to marshal -> %v\n", err)
- return
- }
+ for _, addon := range addonsVault.Addons {
+ if addon.Name == name {
+ b, err := json.MarshalIndent(addon, "", " ")
+ if err != nil {
+ log.Printf("Error marshalling addon to JSON: %v", err)
+ }
- if b != nil && utils.IsValidString(string(b)) {
- fmt.Println(string(b))
+ if b != nil && len(b) > 0 {
+ fmt.Println(string(b))
+ }
+ }
}
}
@@ -96,16 +83,24 @@ func AddNewAddon() {
fmt.Printf("\n Addon download URL\n > ")
addon.DownloadUrl = userInput("cli.AddNewAddon")
+ fmt.Printf("\n »»» New Addon ««« \n")
+ fmt.Printf(" Name: %s\n Filename: %s\n URL: %s\n DownloadURL: %s\n", addon.Name, addon.Filename,
+ addon.Url, addon.DownloadUrl)
fmt.Printf("\n Do you want to commit? [y/N]\n > ")
input := userInput("cli.AddNewAddon")
switch input {
case "Y", "y":
- r, err := database.InsertAddon(db, addon)
+ addonsVault, err := vault.GetInstance()
if err != nil {
- log.Printf("cli.addNewAddon :: Failed to insert addon(s)! -> %v\n", err)
+ log.Fatalf("Error initializing AddonVault: %v", err)
}
- fmt.Printf(" Inserted total of %d addon(s) into TanukiDB!\n", r)
+
+ if err := addonsVault.Append(&addon); err != nil {
+ log.Printf("Error appending addon to vault: %v", err)
+ return
+ }
+ fmt.Printf(" Successfully inserted addon(s)!")
case "N", "n":
fmt.Println(" Stopped insertion of new addon(s)!")
default:
@@ -116,30 +111,29 @@ func AddNewAddon() {
func RemoveAddon() {
utils.ClearScreen()
- fmt.Printf("\n »»» Remove addon «««\n\n Addon ID\n > ")
- id := userInput("cli.RemoveAddon")
-
- if !utils.IsValidString(id) {
- log.Printf("cli.RemoveAddon :: The 'ID' argument is not valid! -> [%s]\n", id)
- return
- }
+ fmt.Printf("\n »»» Remove addon «««\n\n Addon name\n > ")
+ name := userInput("cli.RemoveAddon")
- idNum, err := strconv.Atoi(id)
- if err != nil {
- log.Printf("cli.RemoveAddon :: Error while trying to convert ID to its decimal equivalent! -> %v\n", err)
+ if !utils.IsValidString(name) {
+ log.Printf("cli.RemoveAddon :: The 'name' argument is not valid! -> [%s]\n", name)
return
}
+ fmt.Printf("\n Will try to remove addon with the name: %s\n", name)
fmt.Printf("\n Do you want to commit? [y/N]\n > ")
input := userInput("cli.RemoveAddon")
-
switch input {
case "Y", "y":
- r, err := database.RemoveAddonByID(db, idNum)
+ addonsVault, err := vault.GetInstance()
if err != nil {
- log.Printf("cli.RemoveAddon :: Failed to remove addon(s)! -> %v\n", err)
+ log.Fatalf("Error initializing AddonVault: %v", err)
+ }
+ beenRemoved, err := addonsVault.Remove(name)
+ if beenRemoved {
+ fmt.Printf(" Successfully removed addon with name: %s", name)
+ } else {
+ fmt.Printf(" Failed to remove addon with name: %s -> %v\n", name, err)
}
- fmt.Printf(" Removed total of %d addon(s) from TanukiDB!", r)
case "N", "n":
fmt.Println(" Stopped deletion of addon(s)!")
default:
diff --git a/cli/core.go b/cmp/cli/core.go
similarity index 86%
rename from cli/core.go
rename to cmp/cli/core.go
index b4f7adb..befe728 100644
--- a/cli/core.go
+++ b/cmp/cli/core.go
@@ -14,21 +14,13 @@
package cli
import (
- "database/sql"
"fmt"
- "goaddons/database"
- "goaddons/updater"
- "goaddons/utils"
- "log"
+ "goaddons/cmp/updater"
+ "goaddons/cmp/utils"
+ "goaddons/cmp/vault"
"os"
)
-const (
- databasePath string = "./bin/acd.db"
-)
-
-var db *sql.DB
-
func StartCli() {
utils.ClearScreen()
fmt.Printf(`
@@ -62,7 +54,7 @@ func StartCli() {
func addonManagement() {
utils.ClearScreen()
- initDatabase() // init database connection if it is not already initialized
+ _, _ = vault.GetInstance()
fmt.Printf(`
»»» Addon Management «««
@@ -101,7 +93,7 @@ func addonManagement() {
func updaterMenu() {
utils.ClearScreen()
- initDatabase() // init database connection if it is not already initialized
+ _, _ = vault.GetInstance()
fmt.Printf(`
»»» Updater Menu «««
@@ -113,7 +105,7 @@ func updaterMenu() {
if len(input) > 0 {
switch input {
case "1":
- updater.StartUpdater(db)
+ updater.StartUpdater()
case "X", "x":
StartCli()
default:
@@ -152,17 +144,6 @@ func about() {
StartCli()
}
-// initDatabase initializes the global database connection.
-func initDatabase() {
- if db == nil {
- var err error
- db, err = database.ConnectToServer(databasePath)
- if err != nil {
- log.Fatalf("cli:core.initDatabase():ConnectToServer(%s) -> %v", databasePath, err)
- }
- }
-}
-
func terminate() {
os.Exit(0)
}
diff --git a/models/DLog.go b/cmp/models/Addon.go
similarity index 67%
rename from models/DLog.go
rename to cmp/models/Addon.go
index 7193178..0023ef9 100644
--- a/models/DLog.go
+++ b/cmp/models/Addon.go
@@ -13,9 +13,16 @@
package models
-type DLog struct {
- Id int
- RunId string
- Url string
- AddedAt []uint8
+type Addon struct {
+ Name string `json:"name"`
+ Filename string `json:"filename"`
+ Url string `json:"url"`
+ DownloadUrl string `json:"download_url"`
+}
+
+func (a *Addon) Validate() bool {
+ if len(a.Name) == 0 || len(a.Filename) == 0 || len(a.Url) == 0 || len(a.DownloadUrl) == 0 {
+ return false
+ }
+ return true
}
diff --git a/models/SystemConfig.go b/cmp/models/SystemConfig.go
similarity index 86%
rename from models/SystemConfig.go
rename to cmp/models/SystemConfig.go
index 705710e..3df5363 100644
--- a/models/SystemConfig.go
+++ b/cmp/models/SystemConfig.go
@@ -17,3 +17,7 @@ type SystemConfig struct {
Name string
Path string
}
+
+func NewSystemConfig(name string, path string) *SystemConfig {
+ return &SystemConfig{Name: name, Path: path}
+}
diff --git a/net/BrowserDownload.go b/cmp/net/BrowserDownload.go
similarity index 81%
rename from net/BrowserDownload.go
rename to cmp/net/BrowserDownload.go
index 30968b7..26f32ae 100644
--- a/net/BrowserDownload.go
+++ b/cmp/net/BrowserDownload.go
@@ -15,10 +15,9 @@ package net
import (
"context"
- "database/sql"
"fmt"
- "goaddons/database"
- "goaddons/models"
+ "goaddons/cmp/models"
+ "goaddons/cmp/vault"
"log"
"math/rand"
"os"
@@ -42,16 +41,14 @@ var userAgents = []string{
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_16_0) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/14.0.2 Safari/605.1.15",
}
-func StartHeadlessAndDownloadAddons(runId string, addons []models.Addon, downloadPath string,
- db *sql.DB) (done bool, err error) {
-
- if addons == nil || downloadPath == "" {
- return false, fmt.Errorf("addons or downloadPath is required\n")
+func StartHeadlessAndDownloadAddons(addonVault *vault.AddonVault, downloadPath string) (done bool, err error) {
+ if addonVault.Length() == 0 || downloadPath == "" {
+ return false, fmt.Errorf("browserDownload -> StartHeadlessAndDownloadAddons(): addons or downloadPath is required\n")
}
ctx, cancel, err := setupContext(downloadPath)
if err != nil {
- return false, err
+ return false, fmt.Errorf("browserDownload -> StartHeadlessAndDownloadAddons(): %w\n", err)
}
defer cancel()
@@ -59,18 +56,18 @@ func StartHeadlessAndDownloadAddons(runId string, addons []models.Addon, downloa
downloadComplete := make(chan string)
setupContextListeners(ctx, downloadPath, downloadComplete)
- for idx, addon := range addons {
- log.Printf("[%d/%d] Will try to navigate to: %s\n", idx+1, len(addons), addon.DownloadUrl)
+ for idx, addon := range addonVault.Addons {
+ log.Printf("[%d/%d] Will try to navigate to: %s\n", idx+1, len(addonVault.Addons), addon.DownloadUrl)
if addon.DownloadUrl == "" {
log.Printf("DownloadURL is not allowed to be empty, will ignore this addon!\n")
} else if strings.HasSuffix(addon.DownloadUrl, ".zip") {
- _, err := handleDirectDownload(addon, downloadPath, db, runId, downloadComplete)
+ _, err := handleDirectDownload(addon, downloadPath, downloadComplete)
if err != nil {
return false, err
}
} else {
- _, err := handleBrowserDownload(ctx, addon, db, runId, downloadComplete)
+ _, err := handleBrowserDownload(ctx, addon, downloadComplete)
if err != nil {
return false, err
}
@@ -84,9 +81,7 @@ func StartHeadlessAndDownloadAddons(runId string, addons []models.Addon, downloa
return true, nil
}
-func handleDirectDownload(addon models.Addon, downloadPath string, db *sql.DB,
- runId string, dcSignal chan string) (bool, error) {
-
+func handleDirectDownload(addon models.Addon, downloadPath string, dcSignal chan string) (bool, error) {
res, err := directDownload(addon, downloadPath)
if err != nil {
log.Printf("Error with direct download! -> %v\n", err)
@@ -96,43 +91,21 @@ func handleDirectDownload(addon models.Addon, downloadPath string, db *sql.DB,
// Wait for the signal that the current download is complete
<-dcSignal
- err = databaseOperations(db, addon, runId)
- if err != nil {
- return false, err
- }
+ log.Printf("Download finished!\n")
return res, nil
}
return false, nil
}
-func handleBrowserDownload(ctx context.Context, addon models.Addon, db *sql.DB,
- runId string, dcSignal chan string) (bool, error) {
-
+func handleBrowserDownload(ctx context.Context, addon models.Addon, dcSignal chan string) (bool, error) {
navigateToAddonDownloadUrl(ctx, addon)
// Wait for the signal that the current download is complete
<-dcSignal
- err := databaseOperations(db, addon, runId)
- if err != nil {
- return false, err
- }
+ log.Printf("Download finished!\n")
return true, nil
}
-func databaseOperations(db *sql.DB, addon models.Addon, runId string) (err error) {
- err = handleDownloadLogging(db, addon, runId)
- if err != nil {
- return err
- }
-
- // Update the column 'last_downloaded'
- _, err = database.UpdateAddon(db, addon)
- if err != nil {
- return err
- }
- return nil
-}
-
func setupContext(downloadPath string) (ctx context.Context, cancelFunc context.CancelFunc, err error) {
allocatorCtx, allocatorCancel := chromedp.NewRemoteAllocator(context.Background(), dockerUrl)
// initialize a controllable Chrome instance
@@ -179,17 +152,6 @@ func directDownload(addon models.Addon, downloadPath string) (done bool, err err
return false, nil
}
-func handleDownloadLogging(db *sql.DB, addon models.Addon, runId string) error {
- dLog, err := database.InsertDLog(db, models.DLog{RunId: runId,
- Url: addon.DownloadUrl})
- if err != nil {
- return fmt.Errorf("failed to store download logging into database for the URL: %s -> %v\n",
- addon.DownloadUrl, err)
- }
- log.Printf("Stored download logging with ID: %d, for the URL: %s\n", dLog, addon.DownloadUrl)
- return nil
-}
-
func navigateToAddonDownloadUrl(ctx context.Context, addon models.Addon) {
if err := chromedp.Run(ctx,
chromedp.Navigate(addon.DownloadUrl),
diff --git a/net/DirectDownload.go b/cmp/net/DirectDownload.go
similarity index 100%
rename from net/DirectDownload.go
rename to cmp/net/DirectDownload.go
diff --git a/cmp/system/ConfigReader.go b/cmp/system/ConfigReader.go
new file mode 100644
index 0000000..0614bf3
--- /dev/null
+++ b/cmp/system/ConfigReader.go
@@ -0,0 +1,82 @@
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+package system
+
+import (
+ "encoding/json"
+ "fmt"
+ "goaddons/cmp/models"
+ "goaddons/cmp/utils"
+ "io"
+ "log"
+ "os"
+)
+
+const (
+ SYSTEM_CONFIG_PATH = "./.systemsconfig.json"
+ ADDONS_CONFIG_PATH_KEY = "./.addonsconfig.json"
+)
+
+func GetSystemsConfig() ([]models.SystemConfig, error) {
+ var config []models.SystemConfig
+ configBytes, err := readConfig(SYSTEM_CONFIG_PATH)
+ if err != nil {
+ return config, err
+ }
+
+ err = json.Unmarshal(configBytes, &config)
+ if err != nil {
+ return nil, fmt.Errorf("configReader -> GetSystemsConfig(): %w\n", err)
+ }
+ return config, nil
+}
+
+func GetAddonsConfig() ([]models.Addon, error) {
+ var addons []models.Addon
+ addonsConfigBytes, err := readConfig(ADDONS_CONFIG_PATH_KEY)
+ if err != nil {
+ return addons, err
+ }
+
+ err = json.Unmarshal(addonsConfigBytes, &addons)
+ if err != nil {
+ return nil, fmt.Errorf("configReader -> GetAddonsConfig(): %w\n", err)
+ }
+ return addons, nil
+}
+
+// ReadConfig will open, read and return a whole file as a []byte
+func readConfig(fp string) ([]byte, error) {
+ if !utils.IsValidString(fp) {
+ return []byte{}, nil
+ }
+
+ f, err := os.OpenFile(fp, os.O_RDONLY, 0666)
+ if err != nil {
+ return []byte{}, fmt.Errorf("configReader -> ReadConfig(): %w\n", err)
+ }
+ defer func(f *os.File) {
+ err := f.Close()
+ if err != nil {
+ log.Printf("configReader -> ReadConfig(): %v\n", err)
+ return
+ }
+ }(f)
+
+ rtnBytes, err := io.ReadAll(f)
+ if err != nil {
+ return []byte{}, fmt.Errorf("configReader -> ReadConfig(): %w\n", err)
+ }
+ return rtnBytes, nil
+}
diff --git a/system/Ziperino.go b/cmp/system/Ziperino.go
similarity index 100%
rename from system/Ziperino.go
rename to cmp/system/Ziperino.go
diff --git a/updater/AddonUpdater.go b/cmp/updater/AddonUpdater.go
similarity index 51%
rename from updater/AddonUpdater.go
rename to cmp/updater/AddonUpdater.go
index d970839..98c5352 100644
--- a/updater/AddonUpdater.go
+++ b/cmp/updater/AddonUpdater.go
@@ -14,80 +14,52 @@
package updater
import (
- "database/sql"
"fmt"
- "goaddons/database"
- "goaddons/models"
- "goaddons/net"
- "goaddons/utils"
+ "goaddons/cmp/models"
+ "goaddons/cmp/net"
+ "goaddons/cmp/system"
+ "goaddons/cmp/utils"
+ "goaddons/cmp/vault"
"log"
- "strings"
"time"
-
- "github.com/google/uuid"
)
const (
- serviceName = "GOADDONS_SERVICE"
- systemsAddonsPathName = "extract.addon.path"
- browserDownloadDirName = "browser.download.dir"
+ SYSTEMS_ADDON_PATH_KEY = "extract.addon.path"
+ BROWSER_DOWNLOAD_PATH_KEY = "browser.download.dir"
)
-func StartUpdater(db *sql.DB) {
+func StartUpdater() {
log.Printf("Addon Updater starting...\n")
- // Connect to MySQL database
- if db == nil {
- var err error
- db, err = database.ConnectToServer("./bin/acd.db")
- if err != nil {
- log.Fatalf("updater:AddonUpdater.StartUpdater():database.ConnectToServer(\"./bin/acd\") -> %v", err)
- }
- defer func(db *sql.DB) {
- err := db.Close()
- if err != nil {
- log.Println("Error occurred while trying to close connection to database -> %w", err)
- }
- }(db)
- }
-
- runId := strings.Replace(uuid.New().String(), "-", "", -1)
-
- // Log that the software is making a "run"
- rLog, err := database.InsertRLog(db, models.RLog{RunId: runId,
- Service: serviceName})
+ // Fetch systems configuration from file
+ config, err := system.GetSystemsConfig()
if err != nil {
- log.Printf("Failed to store run logging into database... -> %v\n", err)
+ log.Fatalf("Failed to fetch system configurations! -> %v\n", err)
}
- log.Printf("Stored run logging with ID: %d\n", rLog)
-
- // Fetch systems configuration from database
- config, err := database.GetSystemConfigurations(db)
- if err != nil {
- log.Fatalf("Failed to fetch system configurations... -> %v\n", err)
+ if config == nil || len(config) == 0 {
+ log.Fatalf("Failed to find any system configurations! -> %v\n", err)
}
// Fetch the addons path & download dir from the system configurations
- addonsPath, downloadPath, err := getDownloadPathAndAddonsPath(config)
+ addonsPath, downloadPath, err := GetSystemPaths(config)
if err != nil {
- log.Fatalf("Failed to fetch system configurations... -> %v\n", err)
+ log.Fatalf("Failed to parse system configurations for addon and download paths! -> %v\n", err)
}
-
- startTime := time.Now().UTC()
-
- // Get all addons from database
- addons, err := database.GetAllAddons(db)
+ addonsVault, err := vault.GetInstance()
if err != nil {
- log.Fatalf("Failed to fetch all addons... -> %v\n", err)
+ log.Fatalf("Error initializing AddonVault: %v", err)
}
- log.Printf("Fetched a total of %d addons!\n", len(addons))
+ startTime := time.Now().UTC()
+
+ log.Printf("Vault has a total of %d addons!\n", addonsVault.Length())
// Creates stop channel and errorChannel and starts the PollingExtractor
stopChannel := make(chan struct{})
errorChannel := make(chan error, 1)
- go PollingExtractor(db, runId, downloadPath, addonsPath, stopChannel, errorChannel)
+ go PollingExtractor(addonsVault, downloadPath, addonsPath, stopChannel, errorChannel)
go func() {
for err := range errorChannel {
@@ -96,7 +68,7 @@ func StartUpdater(db *sql.DB) {
}()
// Starts headless browser and downloads addons. Will return bool for done state
- done, err := net.StartHeadlessAndDownloadAddons(runId, addons, downloadPath, db)
+ done, err := net.StartHeadlessAndDownloadAddons(addonsVault, downloadPath)
if err != nil {
log.Fatalf("Error while navigating... -> %v\n", err)
}
@@ -137,22 +109,33 @@ func handleNotDone(stopChannel chan struct{}, errorChannel chan error) {
close(stopChannel)
}
-func getDownloadPathAndAddonsPath(config []models.SystemConfig) (ap string, dp string, err error) {
- for _, c := range config {
- if c.Name == systemsAddonsPathName {
- if c.Path == "" {
- return "", "", fmt.Errorf("system's addons directory path is empty -> %v\n", err)
+func GetSystemPaths(configs []models.SystemConfig) (addonPath string, downloadPath string, err error) {
+ for _, config := range configs {
+ if config.Name == SYSTEMS_ADDON_PATH_KEY {
+ if !utils.IsValidString(config.Path) {
+ return "", "",
+ fmt.Errorf("AddonUpdater -> GetSystemPaths(): system's addons directory path is empty\n")
+ }
+
+ if !utils.PathExists(config.Path) {
+ return "", "", fmt.Errorf("AddonUpdater -> GetSystemPaths(): " +
+ "system's addons directory path is empty")
}
- ap = c.Path
- log.Printf("Found the host system's addons directory path at: '%s'\n", ap)
- } else if c.Name == browserDownloadDirName {
- if c.Path == "" {
- return "", "", fmt.Errorf("system's download directory path is empty -> %v\n", err)
+ addonPath = config.Path
+ log.Printf("Found the host system's addons directory path at: '%s'\n", addonPath)
+ } else if config.Name == BROWSER_DOWNLOAD_PATH_KEY {
+ if config.Path == "" {
+ return "", "", fmt.Errorf("AddonUpdater -> GetSystemPaths(): " +
+ "browser's download directory path is empty\n")
}
- dp = c.Path
- log.Printf("Found the host system's download directory path at: '%s'\n", dp)
+ if !utils.PathExists(config.Path) {
+ return "", "", fmt.Errorf("AddonUpdater -> GetSystemPaths(): " +
+ "system's addons directory path is empty\n")
+ }
+ downloadPath = config.Path
+ log.Printf("Found the host system's download directory path at: '%s'\n", downloadPath)
}
}
return
diff --git a/models/Addon.go b/cmp/updater/AddonUpdater_test.go
similarity index 50%
rename from models/Addon.go
rename to cmp/updater/AddonUpdater_test.go
index 0062b91..0e201e1 100644
--- a/models/Addon.go
+++ b/cmp/updater/AddonUpdater_test.go
@@ -11,15 +11,34 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-package models
+package updater
-type Addon struct {
- Id int `json:"id,omitempty"`
- Name string `json:"name,omitempty"`
- Filename string `json:"filename,omitempty"`
- Url string `json:"url,omitempty"`
- DownloadUrl string `json:"download_url,omitempty"`
- LastDownloaded []uint8 `json:"last_downloaded,omitempty"`
- LastModifiedAt []uint8 `json:"last_modified_at,omitempty"`
- AddedAt []uint8 `json:"addedAt,omitempty"`
+import (
+ "goaddons/cmp/models"
+ "testing"
+)
+
+const (
+ PATH_EXTRACT = "/home/test/Games/Addons"
+ PATH_DOWNLOAD = "/home/test/Downloads"
+)
+
+var testSystemsConfigData = []models.SystemConfig{
+ *models.NewSystemConfig("extract.addon.path", PATH_EXTRACT),
+ *models.NewSystemConfig("browser.download.dir", PATH_DOWNLOAD),
+}
+
+func TestGetSystemPaths(t *testing.T) {
+ addonPath, downloadPath, err := GetSystemPaths(testSystemsConfigData)
+ if err != nil {
+ t.Error(err)
+ }
+
+ if addonPath != PATH_EXTRACT {
+ t.Error("addonPath does not match")
+ }
+
+ if downloadPath != PATH_DOWNLOAD {
+ t.Error("downloadPath does not match")
+ }
}
diff --git a/updater/Extractor.go b/cmp/updater/Extractor.go
similarity index 58%
rename from updater/Extractor.go
rename to cmp/updater/Extractor.go
index cc4fde5..b3209fb 100644
--- a/updater/Extractor.go
+++ b/cmp/updater/Extractor.go
@@ -14,11 +14,9 @@
package updater
import (
- "database/sql"
"fmt"
- "goaddons/database"
- "goaddons/models"
- "goaddons/system"
+ "goaddons/cmp/system"
+ "goaddons/cmp/vault"
"log"
"os"
"path/filepath"
@@ -30,14 +28,11 @@ const (
sleepDuration = 1000 * time.Millisecond
)
-var db *sql.DB
-var cachedAddons []models.Addon
-
// PollingExtractor continuously polls the specified directory for addons and extracts them if found
-func PollingExtractor(dbConn *sql.DB, runId string, dp string, ap string, stopChannel <-chan struct{}, errorChannel chan<- error) {
- log.Printf("PollingExtractor started -> RunID: [%s]\n", runId)
- db = dbConn
+func PollingExtractor(addonVault *vault.AddonVault, dp string, ap string,
+ stopChannel <-chan struct{}, errorChannel chan<- error) {
+ log.Printf("PollingExtractor started...\n")
for {
select {
case <-stopChannel:
@@ -48,16 +43,14 @@ func PollingExtractor(dbConn *sql.DB, runId string, dp string, ap string, stopCh
fl, found, err := getAddonsAtPath(dp)
if err != nil {
- errorChannel <- fmt.Errorf("updater:Extractor.PollingExtractor():getAddonsAtPath(%s) "+
- "-> %w", dp, err)
+ errorChannel <- fmt.Errorf("extractor -> PollingExtractor(): %w\n", err)
continue
}
if found {
- err = extractFiles(runId, dp, ap, fl)
+ err = extractFiles(addonVault, dp, ap, fl)
if err != nil {
- errorChannel <- fmt.Errorf("updater:Extractor.PollingExtractor():extractFiles(%s, %s, %s) "+
- "-> %w", runId, dp, ap, err)
+ errorChannel <- fmt.Errorf("extractor -> PollingExtractor(): %w\n", err)
}
}
time.Sleep(sleepDuration)
@@ -65,19 +58,12 @@ func PollingExtractor(dbConn *sql.DB, runId string, dp string, ap string, stopCh
}
}
-// filterFilesForAddons filters the directory entries to include only those present in the database
-func filterFilesForAddons(files []os.DirEntry) (filteredAddons []os.DirEntry, err error) {
- if len(cachedAddons) == 0 {
- cachedAddons, err = database.GetAllAddons(db)
- if err != nil {
- return nil, fmt.Errorf("updater:Extractor.filterFilesForAddons():database.GetAllAddons(db) "+
- "-> %w", err)
- }
- }
-
+// filterFilesForAddons filters the directory entries to include only those present from the file
+func filterFilesForAddons(addonVault *vault.AddonVault, files []os.DirEntry) (filteredAddons []os.DirEntry, err error) {
for _, dirEntry := range files {
log.Printf("[DEBUG] DirEntry: %s\n", dirEntry.Name())
- for _, addon := range cachedAddons {
+
+ for _, addon := range addonVault.Addons {
if strings.Contains(dirEntry.Name(), addon.Filename) {
log.Printf("[DEBUG] %s contains %s == true\n", dirEntry.Name(), addon.Filename)
filteredAddons = append(filteredAddons, dirEntry)
@@ -88,10 +74,10 @@ func filterFilesForAddons(files []os.DirEntry) (filteredAddons []os.DirEntry, er
}
// extractFiles processes and extracts the filtered addon files
-func extractFiles(runId string, dp string, ap string, files []os.DirEntry) error {
- filteredFiles, err := filterFilesForAddons(files)
+func extractFiles(addonVault *vault.AddonVault, dp string, ap string, files []os.DirEntry) error {
+ filteredFiles, err := filterFilesForAddons(addonVault, files)
if err != nil {
- return fmt.Errorf("updater:Extractor.extractFiles():filterFilesForAddons(files) -> %w", err)
+ return fmt.Errorf("extractor -> extractFiles(): %w\n", err)
}
log.Printf("Will now commence extraction of a total of %d addons...\n", len(filteredFiles))
@@ -100,20 +86,9 @@ func extractFiles(runId string, dp string, ap string, files []os.DirEntry) error
log.Printf("[%d/%d] System extract of %s!\n", idx+1, len(filteredFiles), file.Name())
err := system.Extract(absPath, ap)
if err != nil {
- return fmt.Errorf("updater:Extractor.extractFiles():system.Extract(%s, %s) "+
- "-> %w", absPath, ap, err)
- }
-
- id, err := database.InsertELog(db, models.ELog{
- RunId: strings.Replace(runId, "-", "", -1),
- File: absPath,
- })
- if err != nil {
- return fmt.Errorf("updater:Extractor.extractFiles():database.InsertELog(db, models.ELog) "+
- "-> %w", err)
+ return fmt.Errorf("extractor -> extractFiles(): %w\n", err)
}
- log.Printf("Stored extract logging with ID: %d, for the file: %s\n", id, file.Name())
err = os.Remove(absPath)
if err != nil {
return fmt.Errorf("updater:Extractor.extractFiles():os.Remove(%s) -> %w", absPath, err)
@@ -126,8 +101,7 @@ func extractFiles(runId string, dp string, ap string, files []os.DirEntry) error
func getAddonsAtPath(path string) (files []os.DirEntry, found bool, err error) {
readFiles, err := os.ReadDir(path)
if err != nil {
- return nil, false, fmt.Errorf("updater:Extractor.getAddonsAtPath():os.ReadDir(%s) "+
- "-> %w", path, err)
+ return nil, false, fmt.Errorf("extractor -> getAddonsAtPath(): %w\n", err)
}
for _, file := range readFiles {
if strings.HasSuffix(file.Name(), ".zip") {
diff --git a/utils/CliUtils.go b/cmp/utils/CliUtils.go
similarity index 100%
rename from utils/CliUtils.go
rename to cmp/utils/CliUtils.go
diff --git a/models/RLog.go b/cmp/utils/OSUtils.go
similarity index 81%
rename from models/RLog.go
rename to cmp/utils/OSUtils.go
index 39a418a..1aa35c6 100644
--- a/models/RLog.go
+++ b/cmp/utils/OSUtils.go
@@ -11,11 +11,14 @@
// You should have received a copy of the GNU General Public License
// along with this program. If not, see .
-package models
+package utils
-type RLog struct {
- Id int
- RunId string
- Service string
- AddedAt []uint8
+import "os"
+
+func PathExists(path string) bool {
+ _, err := os.Stat(path)
+ if os.IsNotExist(err) {
+ return false
+ }
+ return err == nil
}
diff --git a/utils/StringUtils.go b/cmp/utils/StringUtils.go
similarity index 100%
rename from utils/StringUtils.go
rename to cmp/utils/StringUtils.go
diff --git a/cmp/vault/AddonVault.go b/cmp/vault/AddonVault.go
new file mode 100644
index 0000000..9f342bf
--- /dev/null
+++ b/cmp/vault/AddonVault.go
@@ -0,0 +1,205 @@
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program. If not, see .
+
+package vault
+
+import (
+ "encoding/json"
+ "errors"
+ "fmt"
+ "goaddons/cmp/models"
+ "goaddons/cmp/utils"
+ "log"
+ "os"
+ "sync"
+)
+
+const ADDONS_CONFIG_FILENAME = "./.addonsconfig.json"
+
+var (
+ instance *AddonVault
+ once sync.Once
+)
+
+type AddonVault struct {
+ Addons []models.Addon `json:"addons"`
+ structMx sync.RWMutex
+ fileMx sync.Mutex
+}
+
+// GetInstance returns the singleton instance of AddonVault
+func GetInstance() (*AddonVault, error) {
+ once.Do(func() {
+ log.Println("AddonVault instance created")
+ instance = &AddonVault{}
+ err := instance.Load()
+ if err != nil {
+ log.Printf("Failed to load AddonVault: %v", err)
+ instance = nil // reset instance to nil on failure
+ }
+ })
+ if instance == nil {
+ return nil, errors.New("failed to initialize AddonVault")
+ }
+ return instance, nil
+}
+
+func (v *AddonVault) Append(addon *models.Addon) error {
+ if addon == nil {
+ return errors.New("AddonVault -> Append(): argument is nil")
+ }
+
+ if !addon.Validate() {
+ return errors.New("addonVault -> Append(): addon is invalid")
+ }
+
+ v.structMx.Lock()
+ v.Addons = append(v.Addons, *addon)
+ v.structMx.Unlock()
+
+ if err := v.Persist(); err != nil {
+ return fmt.Errorf("AddonVault -> Append(): error persisting data: %v", err)
+ }
+ return nil
+}
+
+func (v *AddonVault) AppendMany(addons []models.Addon) error {
+ if addons == nil {
+ return nil
+ }
+
+ for _, addon := range addons {
+ if !addon.Validate() {
+ return errors.New("addonVault -> AppendMany(): addon is invalid")
+ }
+ }
+
+ v.structMx.Lock()
+ v.Addons = append(v.Addons, addons...)
+ v.structMx.Unlock()
+
+ if err := v.Persist(); err != nil {
+ return fmt.Errorf("AddonVault -> AppendMany(): error persisting data: %v", err)
+ }
+ return nil
+}
+
+func (v *AddonVault) Remove(id string) (bool, error) {
+ if !utils.IsValidString(id) {
+ return false, errors.New("AddonVault -> Remove(): argument is invalid")
+ }
+
+ v.structMx.Lock()
+ var found bool
+
+ // Find and remove the addon
+ for i, addon := range v.Addons {
+ if addon.Name == id {
+ v.Addons = append(v.Addons[:i], v.Addons[i+1:]...)
+ found = true
+ break
+ }
+ }
+ v.structMx.Unlock() // Unlock before calling Persist()
+
+ if !found {
+ return false, fmt.Errorf("AddonVault -> Remove(): addon with id '%s' not found", id)
+ }
+
+ // Persist the updated list outside the lock to avoid deadlock
+ if err := v.Persist(); err != nil {
+ return false, err
+ }
+
+ return true, nil
+}
+
+func (v *AddonVault) Load() error {
+ v.fileMx.Lock()
+ file, err := os.Open(ADDONS_CONFIG_FILENAME)
+ if err != nil {
+ return fmt.Errorf("AddonVault -> Load(): %v", err)
+ }
+ defer func(file *os.File) {
+ if err := file.Close(); err != nil {
+ log.Printf("AddonVault -> Load(): error closing file: %v", err)
+ }
+ }(file)
+ v.fileMx.Unlock()
+
+ var addons []models.Addon
+ decoder := json.NewDecoder(file)
+ if err := decoder.Decode(&addons); err != nil {
+ addons = make([]models.Addon, 0)
+ return nil
+ }
+
+ return v.AppendMany(addons)
+}
+
+func (v *AddonVault) Persist() error {
+ v.fileMx.Lock()
+ defer v.fileMx.Unlock()
+
+ v.structMx.RLock()
+ data, err := json.MarshalIndent(v.Addons, "", " ")
+ v.structMx.RUnlock()
+
+ if err != nil {
+ return fmt.Errorf("AddonVault -> SaveToFile(): error marshaling to JSON: %v", err)
+ }
+
+ // Open the file for writing, with permissions to create or truncate
+ file, err := os.OpenFile(ADDONS_CONFIG_FILENAME, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0644)
+ if err != nil {
+ return fmt.Errorf("AddonVault -> SaveToFile(): error opening file: %v", err)
+ }
+ defer func(file *os.File) {
+ err := file.Close()
+ if err != nil {
+ log.Printf("AddonVault -> SaveToFile(): error closing file: %v", err)
+ }
+ }(file)
+
+ // Write the JSON data to the file
+ _, err = file.Write(data)
+ if err != nil {
+ return fmt.Errorf("AddonVault -> SaveToFile(): error writing to file: %v", err)
+ }
+
+ return nil
+}
+
+func (v *AddonVault) Length() int {
+ v.structMx.RLock()
+ defer v.structMx.RUnlock()
+ return len(v.Addons)
+}
+
+func (v *AddonVault) Print() {
+ v.structMx.RLock()
+ defer v.structMx.RUnlock()
+
+ if v.Addons == nil {
+ return
+ }
+
+ bytes, err := json.MarshalIndent(v.Addons, "", " ")
+ if err != nil {
+ log.Printf("Error marshalling addon to JSON: %v", err)
+ }
+
+ if bytes != nil && len(bytes) > 0 {
+ fmt.Println(string(bytes))
+ }
+}
diff --git a/database/Connection.go b/database/Connection.go
deleted file mode 100644
index eb18ca5..0000000
--- a/database/Connection.go
+++ /dev/null
@@ -1,68 +0,0 @@
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-package database
-
-import (
- "database/sql"
- "fmt"
- "log"
- "time"
-
- _ "modernc.org/sqlite"
-)
-
-const (
- databasePath = "./init.sql"
- databaseType = "sqlite"
- maxConnLifetimeInMinutes = 30
- maxOpenConns = 1
- maxIdleConns = 1
-)
-
-// ConnectToServer opens a connection to the SQLite database and sets up the connection parameters.
-func ConnectToServer(database string) (dbConn *sql.DB, err error) {
- // Open a connection to the SQLite database.
- dbConn, err = sql.Open(databaseType, database)
- if err != nil {
- return nil, fmt.Errorf("database:Connection.ConnectToServer():sql.Open(%s, %s) "+
- "-> %w", databaseType, database, err)
- }
-
- // Set the connection parameters.
- dbConn.SetConnMaxLifetime(time.Minute * maxConnLifetimeInMinutes)
- dbConn.SetMaxOpenConns(maxOpenConns)
- dbConn.SetMaxIdleConns(maxIdleConns)
-
- // Ping the database to ensure the connection is valid.
- err = dbConn.Ping()
- if err != nil {
- return nil, fmt.Errorf("database:Connection.ConnectToServer():dbConn.Ping() "+
- "-> %w", err)
- }
- log.Println("Connected!")
-
- // Log connection statistics.
- stats := dbConn.Stats()
- log.Printf("\n### Statistics ###\nConnections: %d/%d\nNumber of active connections: %d\n"+
- "Number of idle connections: %d\n",
- stats.OpenConnections, stats.MaxOpenConnections, stats.InUse, stats.Idle)
-
- // Execute any initialization SQL.
- err = ExecuteInitSQL(dbConn, databasePath)
- if err != nil {
- return nil, fmt.Errorf("database:Connection.ConnectToServer():ExecuteInitSQL(dbConn) "+
- "-> %w", err)
- }
- return dbConn, nil
-}
diff --git a/database/DatabaseGetter.go b/database/DatabaseGetter.go
deleted file mode 100644
index baec817..0000000
--- a/database/DatabaseGetter.go
+++ /dev/null
@@ -1,109 +0,0 @@
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-package database
-
-import (
- "database/sql"
- "fmt"
- "goaddons/models"
- "log"
-)
-
-func GetSystemConfigurations(db *sql.DB) (systemConfig []models.SystemConfig, err error) {
- rows, err := db.Query("SELECT * FROM system_config_default")
- if err != nil {
- return nil, fmt.Errorf("database.GetSystemConfigurations :: %v\n", err)
- }
-
- defer func(rows *sql.Rows) {
- err := rows.Close()
- if err != nil {
- log.Printf("database.GetSystemConfigurations:rows.Close() :: %v\n", err)
- return
- }
- }(rows)
-
- for rows.Next() {
- var config models.SystemConfig
- if err := rows.Scan(&config.Name, &config.Path); err != nil {
- return nil, fmt.Errorf("database.GetSystemConfigurations :: %v\n", err)
- }
- systemConfig = append(systemConfig, config)
- }
-
- if err := rows.Err(); err != nil {
- return nil, fmt.Errorf("database.GetSystemConfigurations :: %v\n", err)
- }
- return
-}
-
-func GetAllAddons(db *sql.DB) (addons []models.Addon, err error) {
- rows, err := db.Query("SELECT id, name, filename, url, download_url, last_downloaded, last_modified_at, added_at " +
- "FROM addon WHERE download_url IS NOT NULL AND download_url != '';")
- if err != nil {
- return nil, fmt.Errorf("database.GetAllAddons :: %v\n", err)
- }
-
- defer func(rows *sql.Rows) {
- err := rows.Close()
- if err != nil {
- log.Printf("GetAllAddons.GetAllAddons:rows.Close() :: %v\n", err)
- return
- }
- }(rows)
-
- for rows.Next() {
- var addon models.Addon
- if err := rows.Scan(&addon.Id, &addon.Name, &addon.Filename, &addon.Url, &addon.DownloadUrl,
- &addon.LastDownloaded, &addon.LastModifiedAt, &addon.AddedAt); err != nil {
- return nil, fmt.Errorf("database.GetAllAddons :: %v\n", err)
- }
- addons = append(addons, addon)
- }
-
- if err := rows.Err(); err != nil {
- return nil, fmt.Errorf("database.GetAllAddons :: %v\n", err)
- }
- return
-}
-
-func GetAddonsByName(db *sql.DB, name string) (addons []models.Addon, err error) {
- rows, err := db.Query("SELECT id, name, filename, url, download_url, last_downloaded, last_modified_at, added_at " +
- "FROM addon WHERE name LIKE '%" + name + "%'")
- if err != nil {
- return nil, fmt.Errorf("database.GetAddonsByName :: Error while searching for addon! -> %v\n", err)
- }
-
- defer func(rows *sql.Rows) {
- rowsErr := rows.Close()
- if rowsErr != nil {
- log.Printf("database.GetAddonsByName:rows.Close() :: Error while trying to close rows! -> %v\n", rowsErr)
- return
- }
- }(rows)
-
- for rows.Next() {
- var addon models.Addon
- if err = rows.Scan(&addon.Id, &addon.Name, &addon.Filename, &addon.Url, &addon.DownloadUrl,
- &addon.LastDownloaded, &addon.LastModifiedAt, &addon.AddedAt); err != nil {
- return nil, fmt.Errorf("database.GetAddonsByName :: %v\n", err)
- }
- addons = append(addons, addon)
- }
-
- if err := rows.Err(); err != nil {
- return nil, fmt.Errorf("database.GetAddonsByName :: %v\n", err)
- }
- return
-}
diff --git a/database/DatabaseGetter_test.go b/database/DatabaseGetter_test.go
deleted file mode 100644
index 30f36a8..0000000
--- a/database/DatabaseGetter_test.go
+++ /dev/null
@@ -1,165 +0,0 @@
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-package database
-
-import (
- "encoding/json"
- "goaddons/models"
- "testing"
-
- "github.com/DATA-DOG/go-sqlmock"
- "github.com/stretchr/testify/assert"
-)
-
-var (
- expectedTestAddon1 = models.Addon{
- Id: 1,
- Name: "TestName1",
- Filename: "TestFilename1",
- Url: "www.TestUrl1.io",
- DownloadUrl: "www.TestDownloadUrl1.io/download",
- LastDownloaded: nil,
- LastModifiedAt: nil,
- AddedAt: nil,
- }
- expectedTestAddon2 = models.Addon{
- Id: 2,
- Name: "TestName2",
- Filename: "TestFilename2",
- Url: "www.TestUrl2.io",
- DownloadUrl: "www.TestDownloadUrl2.io/download",
- LastDownloaded: nil,
- LastModifiedAt: nil,
- AddedAt: nil,
- }
- expectedSystemConfig1 = models.SystemConfig{
- Name: "TestConfig1",
- Path: "TestPath1",
- }
- expectedSystemConfig2 = models.SystemConfig{
- Name: "TestConfig2",
- Path: "TestPath2",
- }
-)
-
-func TestGetSystemConfigurations(t *testing.T) {
- db, mock, err := sqlmock.New()
- if err != nil {
- t.Fatalf("database.TestGetSystemConfigurations :: An error was not expected when opening "+
- "a stub database connection -> %v\n", err)
- }
-
- rows := sqlmock.NewRows([]string{"Name", "Path"}).
- AddRow("TestConfig1", "TestPath1").
- AddRow("TestConfig2", "TestPath2")
-
- mock.ExpectQuery("SELECT \\* FROM system_config_default").WillReturnRows(rows)
-
- configs, err := GetSystemConfigurations(db)
- assert.NoError(t, err)
- assert.Len(t, configs, 2)
-
- expectedSystemConfig1Json, err := json.Marshal(expectedSystemConfig1)
- assert.NoError(t, err)
-
- expectedSystemConfig2Json, err := json.Marshal(expectedSystemConfig2)
- assert.NoError(t, err)
-
- actualSystemConfig1Json, err := json.Marshal(configs[0])
- assert.NoError(t, err)
-
- actualSystemConfig2Json, err := json.Marshal(configs[1])
- assert.NoError(t, err)
-
- assert.EqualValues(t, string(expectedSystemConfig1Json), string(actualSystemConfig1Json))
- assert.EqualValues(t, string(expectedSystemConfig2Json), string(actualSystemConfig2Json))
-
- // Ensure all expectations were met
- if err := mock.ExpectationsWereMet(); err != nil {
- t.Errorf("database.TestGetSystemConfigurations :: There were unfulfilled expectations: %s\n", err)
- }
-}
-
-func TestGetAllAddons(t *testing.T) {
- db, mock, err := sqlmock.New()
- if err != nil {
- t.Fatalf("database.TestGetAllAddons :: An error was not expected when opening "+
- "a stub database connection -> %v\n", err)
- }
-
- rows := sqlmock.NewRows([]string{"Id", "Name", "Filename", "Url", "DownloadUrl", "LastDownloaded", "LastModifiedAt", "AddedAt"}).
- AddRow(1, "TestName1", "TestFilename1", "www.TestUrl1.io", "www.TestDownloadUrl1.io/download", nil, nil, nil).
- AddRow(2, "TestName2", "TestFilename2", "www.TestUrl2.io", "www.TestDownloadUrl2.io/download", nil, nil, nil)
-
- mock.ExpectQuery("SELECT id, name, filename, url, download_url, last_downloaded, last_modified_at, " +
- "added_at FROM addon WHERE download_url IS NOT NULL AND download_url != '';").
- WillReturnRows(rows)
- addons, err := GetAllAddons(db)
-
- assert.NoError(t, err)
- assert.Len(t, addons, 2)
-
- actualTestAddon1, err := json.Marshal(addons[0])
- assert.NoError(t, err)
-
- actualTestAddon2, err := json.Marshal(addons[1])
- assert.NoError(t, err)
-
- expectedTestAddon1Json, err := json.Marshal(expectedTestAddon1)
- assert.NoError(t, err)
-
- expectedTestAddon2Json, err := json.Marshal(expectedTestAddon2)
- assert.NoError(t, err)
-
- assert.EqualValues(t, string(expectedTestAddon1Json), string(actualTestAddon1))
- assert.EqualValues(t, string(expectedTestAddon2Json), string(actualTestAddon2))
-
- // Ensure all expectations were met
- if err := mock.ExpectationsWereMet(); err != nil {
- t.Errorf("database.TestGetAllAddons :: There were unfulfilled expectations: %s\n", err)
- }
-}
-
-func TestGetAddonsByName(t *testing.T) {
- db, mock, err := sqlmock.New()
- if err != nil {
- t.Fatalf("database.TestGetAddonsByName :: An error was not expected when opening "+
- "a stub database connection -> %v\n", err)
- return
- }
-
- rows := sqlmock.NewRows([]string{"Id", "Name", "Filename", "Url", "DownloadUrl", "LastDownloaded", "LastModifiedAt", "AddedAt"}).
- AddRow(1, "TestName2", "TestFilename2", "www.TestUrl2.io", "www.TestDownloadUrl2.io/download", nil, nil, nil)
-
- mock.ExpectQuery("SELECT id, name, filename, url, download_url, last_downloaded, last_modified_at, added_at " +
- "FROM addon WHERE name LIKE '%" + expectedTestAddon2.Name + "%'").
- WillReturnRows(rows)
- addon, err := GetAddonsByName(db, expectedTestAddon2.Name)
- assert.NoError(t, err)
- assert.Len(t, addon, 1)
-
- actualTestAddon2, err := json.Marshal(addon[0])
- assert.NoError(t, err)
-
- expectedTestAddon2.Id = 1
- expectedTestAddon2Json, err := json.Marshal(expectedTestAddon2)
- assert.NoError(t, err)
-
- assert.EqualValues(t, string(expectedTestAddon2Json), string(actualTestAddon2))
-
- // Ensure all expectations were met
- if err := mock.ExpectationsWereMet(); err != nil {
- t.Errorf("database.TestGetAddonsByName :: There were unfulfilled expectations: %s\n", err)
- }
-}
diff --git a/database/DatabaseInitializerIT_test.go b/database/DatabaseInitializerIT_test.go
deleted file mode 100644
index f488355..0000000
--- a/database/DatabaseInitializerIT_test.go
+++ /dev/null
@@ -1,36 +0,0 @@
-package database
-
-import (
- "database/sql"
- "log"
- "testing"
-
- "github.com/stretchr/testify/assert"
-)
-
-const (
- sqliteInMemoryOption = "file::memory:?cache=shared"
-)
-
-func TestInitDatabase(t *testing.T) {
- dbConn, err := ConnectToServer(sqliteInMemoryOption)
- assert.NotNil(t, dbConn)
- assert.NoError(t, err)
-
- defer func(db *sql.DB) {
- err := db.Close()
- if err != nil {
- log.Fatalf("TestInitDatabase: Problem occurred while trying to close database -> %v", err)
- }
- }(dbConn)
-
- err = ExecuteInitSQL(dbConn, "./init.sql")
- assert.NoError(t, err)
-
- tables := [5]string{"system_config_default", "addon", "run_log", "download_log", "extract_log"}
-
- for _, table := range tables {
- sqliteTableCheck := "SELECT name FROM sqlite_master WHERE type='table' AND name='" + table + "'"
- assert.NotNil(t, sqliteTableCheck)
- }
-}
diff --git a/database/DatabaseLogger.go b/database/DatabaseLogger.go
deleted file mode 100644
index fd6c0bd..0000000
--- a/database/DatabaseLogger.go
+++ /dev/null
@@ -1,65 +0,0 @@
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-package database
-
-import (
- "database/sql"
- "fmt"
- "goaddons/models"
-)
-
-func InsertRLog(db *sql.DB, rlog models.RLog) (int64, error) {
- result, err := db.Exec("INSERT OR IGNORE INTO run_log (run_id, service) VALUES (?, ?)",
- rlog.RunId, rlog.Service)
- if err != nil {
- return 0, fmt.Errorf("InsertRLog: %v\n", err)
- }
-
- id, err := result.LastInsertId()
- if err != nil {
- return 0, fmt.Errorf("InsertRLog: %v\n", err)
- }
-
- return id, nil
-}
-
-func InsertDLog(db *sql.DB, dlog models.DLog) (int64, error) {
- result, err := db.Exec("INSERT OR IGNORE INTO download_log (run_id, url) VALUES (?, ?)",
- dlog.RunId, dlog.Url)
- if err != nil {
- return 0, fmt.Errorf("InsertDLog: %v\n", err)
- }
-
- id, err := result.LastInsertId()
- if err != nil {
- return 0, fmt.Errorf("InsertDLog: %v\n", err)
- }
-
- return id, nil
-}
-
-func InsertELog(db *sql.DB, elog models.ELog) (int64, error) {
- result, err := db.Exec("INSERT OR IGNORE INTO extract_log (run_id, file) VALUES (?, ?)",
- elog.RunId, elog.File)
- if err != nil {
- return 0, fmt.Errorf("InsertELog: %v\n", err)
- }
-
- id, err := result.LastInsertId()
- if err != nil {
- return 0, fmt.Errorf("InsertELog: %v\n", err)
- }
-
- return id, nil
-}
diff --git a/database/DatabaseLogger_test.go b/database/DatabaseLogger_test.go
deleted file mode 100644
index 8a8ec66..0000000
--- a/database/DatabaseLogger_test.go
+++ /dev/null
@@ -1,112 +0,0 @@
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-package database
-
-import (
- "goaddons/models"
- "testing"
-
- "github.com/DATA-DOG/go-sqlmock"
- "github.com/google/uuid"
- "github.com/stretchr/testify/assert"
-)
-
-var testUUID, _ = uuid.NewUUID()
-
-var (
- expectedRLog1 = models.RLog{
- Id: 1,
- RunId: testUUID.String(),
- Service: "TestService1",
- AddedAt: nil,
- }
- expectedDLog1 = models.DLog{
- Id: 1,
- RunId: testUUID.String(),
- Url: "TestURL1",
- AddedAt: nil,
- }
- expectedELog1 = models.ELog{
- Id: 1,
- RunId: testUUID.String(),
- File: "TestFile1",
- AddedAt: nil,
- }
-)
-
-func TestInsertRLog(t *testing.T) {
- db, mock, err := sqlmock.New()
- if err != nil {
- t.Fatalf("database.TestInsertRLog :: Failed to create SQL mock! -> %v\n", err)
- }
-
- result := sqlmock.NewResult(1, 1)
-
- mock.ExpectExec("INSERT OR IGNORE INTO run_log \\(run_id, service\\) VALUES \\(\\?, \\?\\)").
- WithArgs(testUUID.String(), "TestService1").
- WillReturnResult(result)
-
- ra, err := InsertRLog(db, expectedRLog1)
- assert.NoError(t, err)
- assert.Equal(t, int64(1), ra)
-
- // Ensure all expectations were met
- if err := mock.ExpectationsWereMet(); err != nil {
- t.Errorf("database.TestInsertRLog :: there were unfulfilled expectations: %v\n", err)
- }
-}
-
-func TestInsertDLog(t *testing.T) {
- db, mock, err := sqlmock.New()
- if err != nil {
- t.Fatalf("database.TestInsertDLog :: Failed to create SQL mock! -> %v\n", err)
- }
-
- result := sqlmock.NewResult(1, 1)
-
- mock.ExpectExec("INSERT OR IGNORE INTO download_log \\(run_id, url\\) VALUES \\(\\?, \\?\\)").
- WithArgs(testUUID.String(), "TestURL1").
- WillReturnResult(result)
-
- ra, err := InsertDLog(db, expectedDLog1)
- assert.NoError(t, err)
- assert.Equal(t, int64(1), ra)
-
- // Ensure all expectations were met
- if err := mock.ExpectationsWereMet(); err != nil {
- t.Errorf("database.TestInsertDLog :: there were unfulfilled expectations! -> %v\n", err)
- }
-}
-
-func TestInsertELog(t *testing.T) {
- db, mock, err := sqlmock.New()
- if err != nil {
- t.Fatalf("database.TestInsertELog :: Failed to create SQL mock! -> %v\n", err)
- }
-
- result := sqlmock.NewResult(1, 1)
-
- mock.ExpectExec("INSERT OR IGNORE INTO extract_log \\(run_id, file\\) VALUES \\(\\?, \\?\\)").
- WithArgs(testUUID.String(), "TestFile1").
- WillReturnResult(result)
-
- ra, err := InsertELog(db, expectedELog1)
- assert.NoError(t, err)
- assert.Equal(t, int64(1), ra)
-
- // Ensure all expectations were met
- if err := mock.ExpectationsWereMet(); err != nil {
- t.Errorf("database.TestInsertELog :: there were unfulfilled expectations: %v\n", err)
- }
-}
diff --git a/database/DatabaseUpdater.go b/database/DatabaseUpdater.go
deleted file mode 100644
index ed5d3a0..0000000
--- a/database/DatabaseUpdater.go
+++ /dev/null
@@ -1,65 +0,0 @@
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-package database
-
-import (
- "database/sql"
- "fmt"
- "goaddons/models"
- "time"
-)
-
-func UpdateAddon(db *sql.DB, addon models.Addon) (r int64, err error) {
- result, err := db.Exec("UPDATE addon SET last_downloaded = ? WHERE name = ?",
- time.Now().UTC(), addon.Name)
- if err != nil {
- return 0, fmt.Errorf("database.UpdateAddon: %v\n", err)
- }
-
- r, err = result.RowsAffected()
- if err != nil {
- return 0, fmt.Errorf("database.UpdateAddon: %v\n", err)
- }
-
- return
-}
-
-func InsertAddon(db *sql.DB, addon models.Addon) (r int64, err error) {
- result, err := db.Exec("INSERT OR IGNORE INTO addon (name, filename, url, download_url) VALUES (?, ?, ?, ?);",
- addon.Name, addon.Filename, addon.Url, addon.DownloadUrl)
- if err != nil {
- return 0, fmt.Errorf("database.InsertAddon :: %v\n", err)
- }
-
- r, err = result.RowsAffected()
- if err != nil {
- return 0, fmt.Errorf("database.InsertAddon :: %v\n", err)
- }
- return
-}
-
-func RemoveAddonByID(db *sql.DB, id int) (r int64, err error) {
- result, err := db.Exec("DELETE FROM addon WHERE id = ?;", id)
- if err != nil {
- return 0, fmt.Errorf("database.RemoveAddonByID :: Error while trying to delete addon by ID [%d] -> %v\n",
- id, err)
- }
-
- r, err = result.RowsAffected()
- if err != nil {
- return 0, fmt.Errorf("database.RemoveAddonByID :: Error while trying to delete addon by ID [%d] -> %v\n",
- id, err)
- }
- return
-}
diff --git a/database/DatabaseUpdater_test.go b/database/DatabaseUpdater_test.go
deleted file mode 100644
index 5cf96f0..0000000
--- a/database/DatabaseUpdater_test.go
+++ /dev/null
@@ -1,88 +0,0 @@
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-package database
-
-import (
- "goaddons/models"
- "testing"
-
- "github.com/DATA-DOG/go-sqlmock"
- "github.com/stretchr/testify/assert"
-)
-
-func TestUpdateAddon(t *testing.T) {
- // Expected: "UPDATE kaasufouji.addons SET last_downloaded = ? WHERE name = ?", time.Now().UTC(), addon.Name
- db, mock, err := sqlmock.New()
- if err != nil {
- t.Fatalf("An error '%s' was not expected when opening a stub database connection", err)
- }
-
- addon := models.Addon{Name: "TestAddon"}
-
- mock.ExpectExec("UPDATE addon SET last_downloaded = \\? WHERE name = \\?").
- WithArgs(sqlmock.AnyArg(), addon.Name).
- WillReturnResult(sqlmock.NewResult(0, 1)) // Assuming the update affects 1 row
-
- r, err := UpdateAddon(db, addon)
- assert.NoError(t, err)
- assert.Equal(t, int64(1), r)
-
- if err := mock.ExpectationsWereMet(); err != nil {
- t.Errorf("There were unfulfilled expectations: %s", err)
- }
-}
-
-func TestInsertAddon(t *testing.T) {
- // Expected: "INSERT IGNORE INTO kaasufouji.addons (name, filename, url, download_url) VALUES (?, ?, ?, ?);"
- db, mock, err := sqlmock.New()
- if err != nil {
- t.Fatalf("An error '%s' was not expected when opening a stub database connection", err)
- }
-
- addon := models.Addon{Name: "TestAddon", Filename: "testfile.zip", Url: "http://example.com/test", DownloadUrl: "http://example.com/download/testfile.zip"}
-
- mock.ExpectExec("INSERT OR IGNORE INTO addon \\(name, filename, url, download_url\\) VALUES \\(\\?, \\?, \\?, \\?\\);").
- WithArgs(addon.Name, addon.Filename, addon.Url, addon.DownloadUrl).
- WillReturnResult(sqlmock.NewResult(1, 1)) // Assuming the insert results in 1 row affected
-
- r, err := InsertAddon(db, addon)
- assert.NoError(t, err)
- assert.Equal(t, int64(1), r)
-
- if err := mock.ExpectationsWereMet(); err != nil {
- t.Errorf("There were unfulfilled expectations: %s", err)
- }
-}
-
-func TestRemoveAddonByID(t *testing.T) {
- // Expected: "DELETE FROM kaasufouji.addons WHERE id = ?;", id
- db, mock, err := sqlmock.New()
- if err != nil {
- t.Fatalf("An error '%s' was not expected when opening a stub database connection", err)
- }
-
- addonID := 1
-
- mock.ExpectExec("DELETE FROM addon WHERE id = \\?;").
- WithArgs(addonID).
- WillReturnResult(sqlmock.NewResult(0, 1)) // Assuming the delete affects 1 row
-
- r, err := RemoveAddonByID(db, addonID)
- assert.NoError(t, err)
- assert.Equal(t, int64(1), r)
-
- if err := mock.ExpectationsWereMet(); err != nil {
- t.Errorf("There were unfulfilled expectations: %s", err)
- }
-}
diff --git a/database/Initializer.go b/database/Initializer.go
deleted file mode 100644
index 9342dfb..0000000
--- a/database/Initializer.go
+++ /dev/null
@@ -1,45 +0,0 @@
-package database
-
-import (
- "database/sql"
- "os"
- "strings"
-)
-
-func ExecuteInitSQL(dbConn *sql.DB, dbPath string) error {
- sqlFileContent, err := os.ReadFile(dbPath)
- if err != nil {
- return err
- }
-
- // Convert the file content to a string and split into individual statements.
- sqlCommands := strings.Split(string(sqlFileContent), ";")
-
- // Begin a transaction.
- trans, err := dbConn.Begin()
- if err != nil {
- return err
- }
-
- // Execute each statement.
- for _, command := range sqlCommands {
- command = strings.TrimSpace(command)
- if command == "" {
- continue // skip empty commands
- }
-
- _, err := trans.Exec(command)
- if err != nil {
- // If an error occurs, rollback the transaction and return the error.
- _ = trans.Rollback() // Ignore rollback error, focus on the original error.
- return err
- }
- }
-
- // Commit the transaction.
- if err := trans.Commit(); err != nil {
- return err
- }
-
- return nil
-}
diff --git a/database/init.sql b/database/init.sql
deleted file mode 100644
index 01dc09b..0000000
--- a/database/init.sql
+++ /dev/null
@@ -1,49 +0,0 @@
--- This file is part of GoAddons, which is licensed under the GNU General Public License v3.0.
--- You should have received a copy of the GNU General Public License along with this program.
--- If not, see .
-
-CREATE TABLE IF NOT EXISTS `system_config_default` (
- `name` VARCHAR(255),
- `path` VARCHAR(255),
- PRIMARY KEY (`name`)
-);
-
-INSERT OR IGNORE INTO `system_config_default` (`name`, `path`)
- VALUES ('browser.download.dir', '/home/[YOUR_HOST_NAME_HERE]/Downloads/goaddons_download'),
- ('extract.addon.path', '/home/[YOUR_HOST_NAME_HERE]/ssd/Games/battlenet/drive_c/Program Files (x86)/World of Warcraft/_retail_/Interface/AddOns');
-
-CREATE TABLE IF NOT EXISTS `addon` (
- `id` INT AUTO_INCREMENT,
- `name` VARCHAR(128) NOT NULL UNIQUE,
- `filename` varchar(128) DEFAULT NULL,
- `url` VARCHAR(255) NULL DEFAULT NULL,
- `download_url` VARCHAR(255) NULL DEFAULT NULL,
- `last_downloaded` TIMESTAMP NULL DEFAULT NULL,
- `last_modified_at` TIMESTAMP DEFAULT (CURRENT_TIMESTAMP),
- `added_at` TIMESTAMP DEFAULT (CURRENT_TIMESTAMP),
- PRIMARY KEY (`id`)
-);
-
-CREATE TABLE IF NOT EXISTS `run_log` (
- `id` INT AUTO_INCREMENT,
- `run_id` VARCHAR(255) NOT NULL,
- `service` VARCHAR(128) NOT NULL,
- `added_at` TIMESTAMP DEFAULT (CURRENT_TIMESTAMP),
- PRIMARY KEY (`id`)
-);
-
-CREATE TABLE IF NOT EXISTS `download_log` (
- `id` INT AUTO_INCREMENT,
- `run_id` VARCHAR(255) NOT NULL,
- `url` VARCHAR(255) NOT NULL,
- `added_at` TIMESTAMP DEFAULT (CURRENT_TIMESTAMP),
- PRIMARY KEY (`id`)
-);
-
-CREATE TABLE IF NOT EXISTS `extract_log` (
- `id` INT AUTO_INCREMENT,
- `run_id` VARCHAR(255) NOT NULL,
- `file` TEXT NOT NULL,
- `added_at` TIMESTAMP DEFAULT (CURRENT_TIMESTAMP),
- PRIMARY KEY (`id`)
-);
diff --git a/docker-compose.yml b/docker-compose.yml
index 65dea28..93d7457 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -2,8 +2,6 @@
# You should have received a copy of the GNU General Public License along with this program.
# If not, see .
-version: '3.1'
-
services:
goaddons_cdp:
image: chromedp/headless-shell
@@ -11,19 +9,19 @@ services:
ports:
- "9222:9222"
volumes:
- - goaddons-addons-volume:/home/[YOUR_HOST_NAME_HERE]/Downloads/goaddons_download
- - goaddons-extract-volume:/home/[YOUR_HOST_NAME_HERE]/Downloads/goaddons_extract
+ - goaddons-addons-volume:/home/miso/Downloads/goaddons_download
+ - goaddons-extract-volume:/home/miso/Downloads/goaddons_extract
volumes:
- kaasufouji-addons-volume:
+ goaddons-addons-volume:
driver: local
driver_opts:
type: none
- device: /home/[YOUR_HOST_NAME_HERE]/Downloads/goaddons_download
+ device: /home/miso/Downloads/goaddons_download
o: bind
- kaasufouji-extract-volume:
+ goaddons-extract-volume:
driver: local
driver_opts:
type: none
- device: "/home/[YOUR_HOST_NAME_HERE]/ssd/Games/battlenet/drive_c/Program Files (x86)/World of Warcraft/_retail_/Interface/AddOns"
+ device: "/home/miso/Games/battlenet/drive_c/Program Files (x86)/World of Warcraft/_retail_/Interface/AddOns"
o: bind
diff --git a/go.mod b/go.mod
index 5c7d355..d68f246 100644
--- a/go.mod
+++ b/go.mod
@@ -13,37 +13,19 @@
module goaddons
-go 1.22.0
+go 1.23.0
require (
- github.com/DATA-DOG/go-sqlmock v1.5.2
- github.com/chromedp/cdproto v0.0.0-20240328024531-fe04f09ede24
- github.com/chromedp/chromedp v0.9.5
- github.com/google/uuid v1.6.0
- github.com/stretchr/testify v1.9.0
- modernc.org/sqlite v1.30.0
+ github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476
+ github.com/chromedp/chromedp v0.10.0
)
require (
github.com/chromedp/sysutil v1.0.0 // indirect
- github.com/davecgh/go-spew v1.1.1 // indirect
- github.com/dustin/go-humanize v1.0.1 // indirect
github.com/gobwas/httphead v0.1.0 // indirect
github.com/gobwas/pool v0.2.1 // indirect
- github.com/gobwas/ws v1.3.2 // indirect
- github.com/hashicorp/golang-lru/v2 v2.0.7 // indirect
+ github.com/gobwas/ws v1.4.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/mailru/easyjson v0.7.7 // indirect
- github.com/mattn/go-isatty v0.0.20 // indirect
- github.com/ncruces/go-strftime v0.1.9 // indirect
- github.com/pmezard/go-difflib v1.0.0 // indirect
- github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
- golang.org/x/sys v0.19.0 // indirect
- gopkg.in/yaml.v3 v3.0.1 // indirect
- modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b // indirect
- modernc.org/libc v1.50.9 // indirect
- modernc.org/mathutil v1.6.0 // indirect
- modernc.org/memory v1.8.0 // indirect
- modernc.org/strutil v1.2.0 // indirect
- modernc.org/token v1.1.0 // indirect
+ golang.org/x/sys v0.25.0 // indirect
)
diff --git a/go.sum b/go.sum
index 7090e50..f9db289 100644
--- a/go.sum
+++ b/go.sum
@@ -1,82 +1,25 @@
-github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
-github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
-github.com/chromedp/cdproto v0.0.0-20240202021202-6d0b6a386732/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
-github.com/chromedp/cdproto v0.0.0-20240328024531-fe04f09ede24 h1:XLG3KlHtG6Wg75ed/daLltJtcj8VXjw7F9mzYenzFL0=
-github.com/chromedp/cdproto v0.0.0-20240328024531-fe04f09ede24/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
-github.com/chromedp/chromedp v0.9.5 h1:viASzruPJOiThk7c5bueOUY91jGLJVximoEMGoH93rg=
-github.com/chromedp/chromedp v0.9.5/go.mod h1:D4I2qONslauw/C7INoCir1BJkSwBYMyZgx8X276z3+Y=
+github.com/chromedp/cdproto v0.0.0-20240801214329-3f85d328b335/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
+github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476 h1:VnjHsRXCRti7Av7E+j4DCha3kf68echfDzQ+wD11SBU=
+github.com/chromedp/cdproto v0.0.0-20240810084448-b931b754e476/go.mod h1:GKljq0VrfU4D5yc+2qA6OVr8pmO/MBbPEWqWQ/oqGEs=
+github.com/chromedp/chromedp v0.10.0 h1:bRclRYVpMm/UVD76+1HcRW9eV3l58rFfy7AdBvKab1E=
+github.com/chromedp/chromedp v0.10.0/go.mod h1:ei/1ncZIqXX1YnAYDkxhD4gzBgavMEUu7JCKvztdomE=
github.com/chromedp/sysutil v1.0.0 h1:+ZxhTpfpZlmchB58ih/LBHX52ky7w2VhQVKQMucy3Ic=
github.com/chromedp/sysutil v1.0.0/go.mod h1:kgWmDdq8fTzXYcKIBqIYvRRTnYb9aNS9moAV0xufSww=
-github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
-github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
-github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/gobwas/httphead v0.1.0 h1:exrUm0f4YX0L7EBwZHuCF4GDp8aJfVeBrlLQrs6NqWU=
github.com/gobwas/httphead v0.1.0/go.mod h1:O/RXo79gxV8G+RqlR/otEwx4Q36zl9rqC5u12GKvMCM=
github.com/gobwas/pool v0.2.1 h1:xfeeEhW7pwmX8nuLVlqbzVc7udMDrwetjEv+TZIz1og=
github.com/gobwas/pool v0.2.1/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw=
-github.com/gobwas/ws v1.3.2 h1:zlnbNHxumkRvfPWgfXu8RBwyNR1x8wh9cf5PTOCqs9Q=
-github.com/gobwas/ws v1.3.2/go.mod h1:hRKAFb8wOxFROYNsT1bqfWnhX+b5MFeJM9r2ZSwg/KY=
-github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd h1:gbpYu9NMq8jhDVbvlGkMFWCjLFlqqEZjEmObmhUy6Vo=
-github.com/google/pprof v0.0.0-20240409012703-83162a5b38cd/go.mod h1:kf6iHlnVGwgKolg33glAes7Yg/8iWP8ukqeldJSO7jw=
-github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
-github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k=
-github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM=
+github.com/gobwas/ws v1.4.0 h1:CTaoG1tojrh4ucGPcoJFiAQUAsEWekEWvLy7GsVNqGs=
+github.com/gobwas/ws v1.4.0/go.mod h1:G3gNqMNtPppf5XUz7O4shetPpcZ1VJ7zt18dlUeakrc=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
-github.com/kisielk/sqlstruct v0.0.0-20201105191214-5f3e10d3ab46/go.mod h1:yyMNCyc/Ib3bDTKd379tNMpB/7/H5TjM2Y9QJ5THLbE=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80 h1:6Yzfa6GP0rIo/kULo2bwGEkFvCePZ3qHDDTC3/J9Swo=
github.com/ledongthuc/pdf v0.0.0-20220302134840-0c2507a12d80/go.mod h1:imJHygn/1yfhB7XSJJKlFZKl/J+dCPAknuiaGOshXAs=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
-github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
-github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
-github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4=
-github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde h1:x0TT0RDC7UhAVbbWWBzr41ElhJx5tXPWkIHA2HWPRuw=
github.com/orisano/pixelmatch v0.0.0-20220722002657-fb0b55479cde/go.mod h1:nZgzbfBr3hhjoZnS66nKrHmduYNpc34ny7RK4z5/HM0=
-github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
-github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
-github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
-github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
-github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
-golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
-golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
-golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
-golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
-golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
-gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
-gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-modernc.org/cc/v4 v4.21.2 h1:dycHFB/jDc3IyacKipCNSDrjIC0Lm1hyoWOZTRR20Lk=
-modernc.org/cc/v4 v4.21.2/go.mod h1:HM7VJTZbUCR3rV8EYBi9wxnJ0ZBRiGE5OeGXNA0IsLQ=
-modernc.org/ccgo/v4 v4.17.8 h1:yyWBf2ipA0Y9GGz/MmCmi3EFpKgeS7ICrAFes+suEbs=
-modernc.org/ccgo/v4 v4.17.8/go.mod h1:buJnJ6Fn0tyAdP/dqePbrrvLyr6qslFfTbFrCuaYvtA=
-modernc.org/fileutil v1.3.0 h1:gQ5SIzK3H9kdfai/5x41oQiKValumqNTDXMvKo62HvE=
-modernc.org/fileutil v1.3.0/go.mod h1:XatxS8fZi3pS8/hKG2GH/ArUogfxjpEKs3Ku3aK4JyQ=
-modernc.org/gc/v2 v2.4.1 h1:9cNzOqPyMJBvrUipmynX0ZohMhcxPtMccYgGOJdOiBw=
-modernc.org/gc/v2 v2.4.1/go.mod h1:wzN5dK1AzVGoH6XOzc3YZ+ey/jPgYHLuVckd62P0GYU=
-modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b h1:BnN1t+pb1cy61zbvSUV7SeI0PwosMhlAEi/vBY4qxp8=
-modernc.org/gc/v3 v3.0.0-20240304020402-f0dba7c97c2b/go.mod h1:Qz0X07sNOR1jWYCrJMEnbW/X55x206Q7Vt4mz6/wHp4=
-modernc.org/libc v1.50.9 h1:hIWf1uz55lorXQhfoEoezdUHjxzuO6ceshET/yWjSjk=
-modernc.org/libc v1.50.9/go.mod h1:15P6ublJ9FJR8YQCGy8DeQ2Uwur7iW9Hserr/T3OFZE=
-modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
-modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
-modernc.org/memory v1.8.0 h1:IqGTL6eFMaDZZhEWwcREgeMXYwmW83LYW8cROZYkg+E=
-modernc.org/memory v1.8.0/go.mod h1:XPZ936zp5OMKGWPqbD3JShgd/ZoQ7899TUuQqxY+peU=
-modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
-modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
-modernc.org/sortutil v1.2.0 h1:jQiD3PfS2REGJNzNCMMaLSp/wdMNieTbKX920Cqdgqc=
-modernc.org/sortutil v1.2.0/go.mod h1:TKU2s7kJMf1AE84OoiGppNHJwvB753OYfNl2WRb++Ss=
-modernc.org/sqlite v1.30.0 h1:8YhPUs/HTnlEgErn/jSYQTwHN/ex8CjHHjg+K9iG7LM=
-modernc.org/sqlite v1.30.0/go.mod h1:cgkTARJ9ugeXSNaLBPK3CqbOe7Ec7ZhWPoMFGldEYEw=
-modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
-modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
-modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
-modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
+golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
+golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
diff --git a/main.go b/main.go
index c0c3ee0..2b19874 100644
--- a/main.go
+++ b/main.go
@@ -14,22 +14,19 @@
package main
import (
- "database/sql"
"fmt"
- "goaddons/cli"
- "goaddons/updater"
+ "goaddons/cmp/cli"
+ "goaddons/cmp/updater"
"goaddons/version"
"log"
"os"
)
-var db *sql.DB
-
func main() {
if len(os.Args) >= 2 {
switch os.Args[1] {
case "--updater", "-u":
- updater.StartUpdater(db)
+ updater.StartUpdater()
case "--cli", "c":
cli.StartCli()
case "--version", "-v":
diff --git a/models/ELog.go b/models/ELog.go
deleted file mode 100644
index 2ecfe35..0000000
--- a/models/ELog.go
+++ /dev/null
@@ -1,21 +0,0 @@
-// This program is free software: you can redistribute it and/or modify
-// it under the terms of the GNU General Public License as published by
-// the Free Software Foundation, either version 3 of the License, or
-// (at your option) any later version.
-//
-// This program is distributed in the hope that it will be useful,
-// but WITHOUT ANY WARRANTY; without even the implied warranty of
-// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-// GNU General Public License for more details.
-//
-// You should have received a copy of the GNU General Public License
-// along with this program. If not, see .
-
-package models
-
-type ELog struct {
- Id int
- RunId string
- File string
- AddedAt []uint8
-}