256 lines
6.3 KiB
Go
256 lines
6.3 KiB
Go
|
|
// myList provides functions to create and manage user string lists
|
|
// Lists are concurrency safe, and are stored in-memory and on disk.
|
|
// Examples of lists include matches, viewed hosts, and viewed moderators
|
|
|
|
package myList
|
|
|
|
import "seekia/internal/appMemory"
|
|
import "seekia/internal/helpers"
|
|
import "seekia/internal/localFilesystem"
|
|
|
|
import "encoding/json"
|
|
import "path/filepath"
|
|
import "errors"
|
|
import "sync"
|
|
import "slices"
|
|
|
|
//TODO: We might want to create a new file, rename, delete old file, and rename new file, so we can better protect against losing power or computer crashing and data being lost?
|
|
|
|
func InitializeMyListsFolder()error{
|
|
|
|
userDirectory, err := localFilesystem.GetAppUserFolderPath()
|
|
if (err != nil) { return err }
|
|
|
|
myListsFolderpath := filepath.Join(userDirectory, "MyLists")
|
|
|
|
_, err = localFilesystem.CreateFolder(myListsFolderpath)
|
|
if (err != nil) { return err }
|
|
|
|
return nil
|
|
}
|
|
|
|
type MyList struct{
|
|
|
|
// Name of list. Name of file is derived from this name
|
|
listName string
|
|
|
|
// Folderpath of the list file.
|
|
listFolderpath string
|
|
|
|
// We lock this whenever we are updating the memory list and list file
|
|
updatingListMutex sync.Mutex
|
|
|
|
// We lock this when we edit the memoryList
|
|
// memoryMutex only needs to be RLock/RUnlocked by GetList, because updatingListMutex is locked for all other reads
|
|
memoryMutex sync.RWMutex
|
|
|
|
// The list stored in memory
|
|
memoryList []string
|
|
}
|
|
|
|
func CreateNewList(newListName string)(*MyList, error){
|
|
|
|
if (newListName == ""){
|
|
return nil, errors.New("CreateNewList called with empty myList name.")
|
|
}
|
|
|
|
var newList MyList
|
|
|
|
newList.listName = newListName
|
|
|
|
userDirectory, err := localFilesystem.GetAppUserFolderPath()
|
|
if (err != nil) { return nil, err }
|
|
|
|
listFolderpath := filepath.Join(userDirectory, "MyLists")
|
|
|
|
newList.listFolderpath = listFolderpath
|
|
|
|
getListFromFile := func()([]string, error){
|
|
|
|
listFilepath := filepath.Join(listFolderpath, newListName + "List.json")
|
|
|
|
fileExists, fileBytes, err := localFilesystem.GetFileContents(listFilepath)
|
|
if (err != nil) { return nil, err }
|
|
if (fileExists == false || len(fileBytes) == 0){
|
|
emptyList := make([]string, 0)
|
|
return emptyList, nil
|
|
}
|
|
|
|
var currentList []string
|
|
|
|
err = json.Unmarshal(fileBytes, ¤tList)
|
|
if (err != nil){ return nil, err }
|
|
|
|
return currentList, nil
|
|
}
|
|
|
|
listFromFile, err := getListFromFile()
|
|
if (err != nil) { return nil, err }
|
|
|
|
newList.memoryList = listFromFile
|
|
|
|
return &newList, nil
|
|
}
|
|
|
|
func (listObject *MyList) GetList()([]string, error){
|
|
|
|
if (listObject == nil){
|
|
return nil, errors.New("GetList called when MyList is not initialized.")
|
|
}
|
|
|
|
exists, _ := appMemory.GetMemoryEntry("AppUser")
|
|
if (exists == false){
|
|
return nil, errors.New("GetList called when no user is signed in.")
|
|
}
|
|
|
|
listObject.memoryMutex.RLock()
|
|
|
|
currentList := listObject.memoryList
|
|
listCopy := slices.Clone(currentList)
|
|
|
|
listObject.memoryMutex.RUnlock()
|
|
|
|
return listCopy, nil
|
|
}
|
|
|
|
func (listObject *MyList) AddListItem(newItem string)error{
|
|
|
|
if (listObject == nil){
|
|
return errors.New("AddListItem called when MyList is not initialized.")
|
|
}
|
|
|
|
exists, _ := appMemory.GetMemoryEntry("AppUser")
|
|
if (exists == false){
|
|
return errors.New("AddListItem called when no user is signed in.")
|
|
}
|
|
|
|
listObject.updatingListMutex.Lock()
|
|
defer listObject.updatingListMutex.Unlock()
|
|
|
|
listObject.memoryMutex.Lock()
|
|
|
|
currentList := listObject.memoryList
|
|
currentList = append(currentList, newItem)
|
|
listObject.memoryList = currentList
|
|
|
|
listObject.memoryMutex.Unlock()
|
|
|
|
listFolderpath := listObject.listFolderpath
|
|
listName := listObject.listName
|
|
|
|
err := overwriteListFileWithList(listFolderpath, listName, currentList)
|
|
if (err != nil) { return err }
|
|
|
|
return nil
|
|
}
|
|
|
|
func (listObject *MyList) DeleteListItem(item string)error{
|
|
|
|
if (listObject == nil){
|
|
return errors.New("DeleteListItem called when MyList is not initialized.")
|
|
}
|
|
|
|
exists, _ := appMemory.GetMemoryEntry("AppUser")
|
|
if (exists == false){
|
|
return errors.New("DeleteListItem called when no user is signed in.")
|
|
}
|
|
|
|
listObject.updatingListMutex.Lock()
|
|
defer listObject.updatingListMutex.Unlock()
|
|
|
|
listObject.memoryMutex.Lock()
|
|
|
|
currentList := listObject.memoryList
|
|
|
|
newList, anyDeleted := helpers.DeleteAllMatchingItemsFromList(currentList, item)
|
|
if (anyDeleted == false){
|
|
listObject.memoryMutex.Unlock()
|
|
return nil
|
|
}
|
|
|
|
listObject.memoryList = newList
|
|
listObject.memoryMutex.Unlock()
|
|
|
|
listFolderpath := listObject.listFolderpath
|
|
listName := listObject.listName
|
|
|
|
err := overwriteListFileWithList(listFolderpath, listName, newList)
|
|
if (err != nil) { return err }
|
|
|
|
return nil
|
|
}
|
|
|
|
func (listObject *MyList) DeleteList()error{
|
|
|
|
if (listObject == nil){
|
|
return errors.New("DeleteList called when MyList is not initialized.")
|
|
}
|
|
|
|
exists, _ := appMemory.GetMemoryEntry("AppUser")
|
|
if (exists == false){
|
|
return errors.New("DeleteList called when no user is signed in.")
|
|
}
|
|
|
|
listObject.updatingListMutex.Lock()
|
|
defer listObject.updatingListMutex.Unlock()
|
|
|
|
emptyList := make([]string, 0)
|
|
|
|
listObject.memoryMutex.Lock()
|
|
listObject.memoryList = emptyList
|
|
listObject.memoryMutex.Unlock()
|
|
|
|
listFolderpath := listObject.listFolderpath
|
|
listName := listObject.listName
|
|
|
|
err := overwriteListFileWithList(listFolderpath, listName, emptyList)
|
|
if (err != nil) { return err }
|
|
|
|
return nil
|
|
}
|
|
|
|
// Note: Input list is not copied
|
|
func (listObject *MyList) OverwriteList(newList []string) error{
|
|
|
|
if (listObject == nil){
|
|
return errors.New("OverwriteList called when MyList is not initialized.")
|
|
}
|
|
|
|
exists, _ := appMemory.GetMemoryEntry("AppUser")
|
|
if (exists == false){
|
|
return errors.New("OverwriteList called when no user is signed in.")
|
|
}
|
|
|
|
listObject.updatingListMutex.Lock()
|
|
defer listObject.updatingListMutex.Unlock()
|
|
|
|
listObject.memoryMutex.Lock()
|
|
listObject.memoryList = newList
|
|
listObject.memoryMutex.Unlock()
|
|
|
|
listFolderpath := listObject.listFolderpath
|
|
listName := listObject.listName
|
|
|
|
err := overwriteListFileWithList(listFolderpath, listName, newList)
|
|
if (err != nil) { return err }
|
|
|
|
return nil
|
|
}
|
|
|
|
|
|
func overwriteListFileWithList(listFolderpath string, listName string, inputList []string)error{
|
|
|
|
newFileBytes, err := json.MarshalIndent(inputList, "", "\t")
|
|
if (err != nil) { return err }
|
|
|
|
listFileName := listName + "List.json"
|
|
|
|
err = localFilesystem.CreateOrOverwriteFile(newFileBytes, listFolderpath, listFileName)
|
|
if (err != nil) { return err }
|
|
|
|
return nil
|
|
}
|
|
|
|
|
|
|